Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

3891 lines
110 KiB

  1. //+---------------------------------------------------------------------------
  2. //
  3. // Microsoft Windows
  4. // Copyright (C) Microsoft Corporation, 1994
  5. //
  6. // File: persist.cxx
  7. //
  8. // Contents: Implmentation of Office9 Thicket Save API
  9. //
  10. //----------------------------------------------------------------------------
  11. #include "priv.h"
  12. #include <mshtml.h>
  13. #include <winineti.h>
  14. #include <mlang.h>
  15. // fake out mimeole.h's dll linkage directives for our delay load stuff in dllload.c
  16. #define _MIMEOLE_
  17. #define DEFINE_STRCONST
  18. #include <mimeole.h>
  19. #include "resource.h"
  20. #include "packager.h"
  21. #include "reload.h"
  22. #include <mluisupp.h>
  23. #define DEFINE_STRING_CONSTANTS
  24. #pragma warning( disable : 4207 )
  25. #include "htmlstr.h"
  26. #pragma warning( default : 4207 )
  27. const GUID CLSID_IMimeInternational =
  28. {0xfd853cd9, 0x7f86, 0x11d0, {0x82, 0x52, 0x0, 0xc0, 0x4f, 0xd8, 0x5a, 0xb4}};
  29. const GUID IID_IMimeInternational =
  30. {0xc5588349, 0x7f86, 0x11d0, {0x82, 0x52, 0x0, 0xc0, 0x4f, 0xd8, 0x5a, 0xb4}};
  31. const GUID IID_IMimeBody =
  32. {0xc558834c, 0x7f86, 0x11d0, {0x82, 0x52, 0x0, 0xc0, 0x4f, 0xd8, 0x5a, 0xb4}};
  33. // Trident legacy defines...
  34. #define RRETURN(hr) return hr;
  35. #define ReleaseInterface(punk) { if (punk) punk->Release(); punk = NULL; }
  36. // Local prototypes
  37. void RemoveBookMark(WCHAR *pwzURL, WCHAR **ppwzBookMark);
  38. void RestoreBookMark(WCHAR *pwzBookMark);
  39. HRESULT HrSetMember(LPUNKNOWN pUnk, BSTR bstrMember, BSTR bstrValue);
  40. HRESULT HrGetCollectionItem(IHTMLElementCollection *pCollect, ULONG uIndex, REFIID riid, LPVOID *ppvObj);
  41. ULONG UlGetCollectionCount(IHTMLElementCollection *pCollect);
  42. HRESULT HrBSTRToLPSZ(BSTR bstr, LPSTR *lplpsz);
  43. HRESULT HrGetCombinedURL( IHTMLElementCollection *pCollBase,
  44. LONG cBase,
  45. LONG lElemPos,
  46. BSTR bstrRelURL,
  47. BSTR bstrDocURL,
  48. BSTR *pbstrBaseURL);
  49. class CHashEntry {
  50. public:
  51. CHashEntry(void) : m_bstrKey(NULL), m_bstrValue(NULL), m_pheNext(NULL) {};
  52. ~CHashEntry(void)
  53. {
  54. if (m_bstrKey)
  55. SysFreeString(m_bstrKey);
  56. if (m_bstrValue)
  57. SysFreeString(m_bstrValue);
  58. }
  59. BOOL SetKey(BSTR bstrKey)
  60. {
  61. ASSERT(m_bstrKey==NULL);
  62. m_bstrKey = SysAllocString(bstrKey);
  63. return m_bstrKey != NULL;
  64. }
  65. BOOL SetValue(BSTR bstrValue)
  66. {
  67. ASSERT(m_bstrValue==NULL || !StrCmpIW(m_bstrValue, c_bstr_BLANK) ||
  68. !StrCmpIW(m_bstrValue, bstrValue));
  69. m_bstrValue = SysAllocString(bstrValue);
  70. return m_bstrValue != NULL;
  71. }
  72. BSTR m_bstrKey;
  73. BSTR m_bstrValue;
  74. CHashEntry *m_pheNext;
  75. };
  76. class CWebArchive
  77. {
  78. public:
  79. CWebArchive(CThicketProgress* ptp=NULL);
  80. ~CWebArchive(void);
  81. virtual HRESULT Init( LPCTSTR lpstrDoc, DWORD dwHashSize );
  82. virtual HRESULT AddURL( BSTR bstrURL, CHashEntry **pphe ) = 0;
  83. virtual HRESULT AddFrameOrStyleEntry( BSTR bstrURL, CHashEntry **pphe, LPTSTR lpstrFrameDoc ) = 0;
  84. virtual HRESULT Find(BSTR bstrF, CHashEntry **pphe);
  85. virtual HRESULT Commit(void);
  86. virtual HRESULT Revert(void);
  87. virtual HRESULT ArchiveDocumentText(IHTMLDocument2 *pDoc, UINT cpDoc, BOOL fFrameDoc) = 0;
  88. virtual HRESULT ArchiveCSSText( BSTR bstrCSSUrl, LPCSTR lpszSSText, LPCTSTR lpszStyleDoc ) = 0;
  89. protected:
  90. LPTSTR m_lpstrDoc; // Desintation file for thicket document
  91. LPTSTR m_lpstrSafeDoc; // Temp name of original file, which we delete on Commit()
  92. CThicketProgress* m_ptp;
  93. enum ThURLType {
  94. thurlMisc,
  95. thurlHttp,
  96. thurlFile
  97. };
  98. ThURLType _GetURLType( BSTR bstrURL );
  99. HRESULT _BackupOldFile(void);
  100. // hash table stuff stolen from MIMEEDIT
  101. HRESULT _Insert(BSTR bstrI, BSTR bstrThicket, CHashEntry **pphe);
  102. inline DWORD Hash(LPWSTR psz);
  103. DWORD m_cBins;
  104. CHashEntry *m_rgBins;
  105. };
  106. class CThicketArchive : public CWebArchive
  107. {
  108. public:
  109. CThicketArchive(CThicketProgress* ptp=NULL);
  110. ~CThicketArchive(void);
  111. virtual HRESULT Init( LPCTSTR lpstrDoc, DWORD dwHashSize );
  112. virtual HRESULT AddURL( BSTR bstrURL, CHashEntry **pphe );
  113. virtual HRESULT AddFrameOrStyleEntry( BSTR bstrURL, CHashEntry **pphe, LPTSTR lpstrFrameDoc );
  114. virtual HRESULT Commit(void);
  115. virtual HRESULT Revert(void);
  116. virtual HRESULT ArchiveDocumentText(IHTMLDocument2 *pDoc, UINT cpDoc, BOOL fFrameDoc);
  117. virtual HRESULT ArchiveCSSText( BSTR bstrCSSUrl, LPCSTR lpszSSText, LPCTSTR lpszStyleDoc );
  118. protected:
  119. LPTSTR m_lpstrFilesDir; // directory for document's supporting files.
  120. LPTSTR m_lpstrFilesDirName; // suffix of m_lpstrFilesDir
  121. LPTSTR m_lpstrSafeDir; // Temp name of original files directory, which we delete on Commit()
  122. BOOL m_fFilesDir; // TRUE if m_lpstrFilesDir has been created.
  123. HRESULT _ApplyMarkOfTheWeb( IHTMLDocument2 *pDoc, LPSTREAM pstm, BOOL fUnicode );
  124. HRESULT _AddHttpEntry( BSTR bstrURL, CHashEntry **pphe, LPTSTR lpstrDstFile, LPTSTR lpstrSrcFile=NULL );
  125. HRESULT _AddFileEntry( BSTR bstrURL, CHashEntry **pphe, LPTSTR lpstrDstFile, LPTSTR lpstrSrcFile=NULL );
  126. HRESULT _AddMiscEntry( BSTR bstrURL, CHashEntry **pphe, LPTSTR lpstrDstFile, int cchDstFile );
  127. HRESULT _PersistHttpURL( BSTR bstrURL, CHashEntry **pphe );
  128. HRESULT _PersistFileURL( BSTR bstrURL, CHashEntry **pphe );
  129. HRESULT _PersistMiscURL( BSTR bstrURL, CHashEntry **pphe );
  130. HRESULT _BackupOldDirectory(void);
  131. HRESULT _RemoveOldDirectoryAndChildren( LPCWSTR pszDir );
  132. HRESULT _Insert(BSTR bstrI, LPTSTR lpszFile, int cchFile, CHashEntry **pphe);
  133. };
  134. class CMHTMLArchive : public CWebArchive
  135. {
  136. public:
  137. CMHTMLArchive(CThicketProgress* ptp=NULL);
  138. ~CMHTMLArchive(void);
  139. virtual HRESULT Init( LPCTSTR lpstrDoc, DWORD dwHashSize );
  140. virtual HRESULT AddURL( BSTR bstrURL, CHashEntry **pphe );
  141. virtual HRESULT AddFrameOrStyleEntry( BSTR bstrURL, CHashEntry **pphe, LPTSTR lpstrFrameDoc );
  142. virtual HRESULT ArchiveDocumentText(IHTMLDocument2 *pDoc, UINT cpDoc, BOOL fFrameDoc);
  143. virtual HRESULT ArchiveCSSText( BSTR bstrCSSUrl, LPCSTR lpszSSText, LPCTSTR lpszStyleDoc );
  144. virtual HRESULT SetCharset(UINT uiCharset, CSETAPPLYTYPE csat, IMimeBody *pBody);
  145. protected:
  146. HBODY m_hBodyAlt;
  147. IMimeMessage *m_pimm;
  148. };
  149. /*
  150. * The following classes implement extended Save As MTHML functionality.
  151. * Access to the extended functionality is controlled by new MECD_ flags
  152. * defined in mimeole.h. Clients of the C API in this module should notice
  153. * mimimal change in its behavior. ( limited to the additional inclusion
  154. * table and table cell background images ).
  155. *
  156. * The root idea is that of a collection packager, which takes a subset
  157. * of the document.all collection, filters the elements of that subcollection,
  158. * and marshall's the element data into the MIMEOle document This is patterned
  159. * after the existing PackageImageData routine, and relies heavily on
  160. * HrAddImageToMessage, which is much more general than its name implies.
  161. *
  162. *
  163. * Stylesheets introduce some repetition, as the stylesheet OM is similar,
  164. * but not similar enough, to support common base classes specialized via
  165. * templates.
  166. *
  167. * The process of adding new packagers is pretty straight-forward.
  168. * [1] (a) if the packaged attribute is a complete URL, derive from CCollectionPackager
  169. * (b) if the attribute is a relative URL, derive from CRelativeURLPackager
  170. * [2] Implement InitFromCollection. Have it call _InitSubCollection() with the tag name.
  171. * See CImagePackager::InitFromCollection() as a simple example.
  172. * [3] Implement _GetTargetAttribute() to return the attribute you want to package.
  173. * You may want to add the string constants for [2] and [3] to htmlstr.h
  174. * [4] Define an MECD_ control flag, if the thing you're packaging is new.
  175. * [5] Add a local var of your packager type to CDocumentPackager::PackageDocument.
  176. * [6] Follow the pattern of the other packagers in CDocumentPackager::PackageDocument
  177. *
  178. * For elements with multiple persisted attributes, it's dealer's choice as to how
  179. * to approach it. Write seperate, simpler packagers for each attribute or write
  180. * one packager that deals with all of the target element's attributes.
  181. */
  182. /*
  183. * CCollectionPackager - abstract base class for HTML element packagers.
  184. * Implements subsampling from the all collection, iteration over the
  185. * collection, and basic packaging functionality.
  186. *
  187. * Derived classes must implement InitFromCollection and _GetTargetAttribute.
  188. * InitFromCollection - derived class should store the desired subset of the
  189. * input collection into the m_pColl data member. _InitSubCollection is
  190. * a useful method for this purpose.
  191. * _GetTargetAttribute - derived class should return a BSTR naming the attribute
  192. * of the element to be packaged.
  193. *
  194. */
  195. class CCollectionPackager
  196. {
  197. public:
  198. virtual ~CCollectionPackager(void);
  199. virtual HRESULT InitFromCollection(IHTMLElementCollection *pColl,
  200. ULONG *pcElems = NULL) = 0;
  201. virtual HRESULT PackageData(CWebArchive *pwa, BOOL *pfCancel = NULL,
  202. CThicketProgress *ptp = NULL, ULONG progLow = 0, ULONG progHigh = 100)
  203. {
  204. return _PackageData( pwa, m_pColl, pfCancel, ptp, progLow, progHigh );
  205. }
  206. protected:
  207. CCollectionPackager(void) : m_pColl(NULL), m_fAddCntLoc(FALSE) {};
  208. HRESULT _InitSubCollection(IHTMLElementCollection *pAll,
  209. BSTR bstrTagName,
  210. IHTMLElementCollection **ppSub,
  211. ULONG *pcElems = NULL);
  212. virtual BSTR _GetTargetAttribute(void) = 0;
  213. virtual HRESULT _GetElementURL(IHTMLElement *pElem, BSTR *pbstrURL);
  214. virtual HRESULT _PackageData(CWebArchive *pwa,
  215. IHTMLElementCollection *pColl,
  216. BOOL *pfCancel = NULL,
  217. CThicketProgress *ptp = NULL, ULONG progLow = 0, ULONG progHigh = 100);
  218. virtual HRESULT _PackageElement(CWebArchive *pwa,
  219. IHTMLElement *pElem);
  220. IHTMLElementCollection *m_pColl;
  221. BOOL m_fAddCntLoc;
  222. };
  223. /*
  224. * CImagePackager - packages the src's of IMG tags.
  225. */
  226. class CImagePackager : public CCollectionPackager
  227. {
  228. public:
  229. CImagePackager(void) {};
  230. virtual ~CImagePackager(void) {};
  231. virtual HRESULT InitFromCollection(IHTMLElementCollection *pColl,
  232. ULONG *pcElems = NULL);
  233. protected:
  234. virtual BSTR _GetTargetAttribute(void);
  235. };
  236. /*
  237. * CInputImgPackager - packages INPUT type="image"
  238. */
  239. class CInputImgPackager : public CImagePackager
  240. {
  241. public:
  242. CInputImgPackager() {}
  243. virtual ~CInputImgPackager() {}
  244. virtual HRESULT InitFromCollection(IHTMLElementCollection *pColl,
  245. ULONG *pcElems = NULL);
  246. };
  247. /*
  248. * CBGSoundsPackager - packages background sounds
  249. */
  250. class CBGSoundsPackager : public CCollectionPackager
  251. {
  252. public:
  253. CBGSoundsPackager() {};
  254. virtual ~CBGSoundsPackager() {};
  255. virtual HRESULT InitFromCollection(IHTMLElementCollection *pColl,
  256. ULONG *pcElems = NULL);
  257. protected:
  258. virtual BSTR _GetTargetAttribute(void);
  259. };
  260. /*
  261. * CAnchorAdjustor - modifies anchor hrefs.
  262. *
  263. * Makes them absolute if they point out of the collection.
  264. */
  265. class CAnchorAdjustor : public CCollectionPackager
  266. {
  267. public:
  268. CAnchorAdjustor(void) {};
  269. virtual ~CAnchorAdjustor(void) {};
  270. virtual HRESULT InitFromCollection(IHTMLElementCollection *pColl,
  271. ULONG *pcElems = NULL);
  272. protected:
  273. virtual BSTR _GetTargetAttribute(void);
  274. virtual HRESULT _PackageElement(CWebArchive *pwa,
  275. IHTMLElement *pElem);
  276. };
  277. /*
  278. * CAreaAdjustor - modifies AREA hrefs.
  279. *
  280. * Makes them absolute if they point out of the collection. Same filter
  281. * as the anchor adjustor, but different tag.
  282. */
  283. class CAreaAdjustor : public CAnchorAdjustor
  284. {
  285. public:
  286. CAreaAdjustor(void) {};
  287. virtual ~CAreaAdjustor(void) {};
  288. virtual HRESULT InitFromCollection(IHTMLElementCollection *pColl,
  289. ULONG *pcElems = NULL);
  290. };
  291. /*
  292. * CBaseNeutralizer - resets any and all <BASE> tags to the d.
  293. *
  294. * No actual packaging goes on here, but we do remap the
  295. * <BASE> href.
  296. */
  297. class CBaseNeutralizer : public CCollectionPackager
  298. {
  299. public:
  300. CBaseNeutralizer(void) : m_bstrLocal(NULL), m_pTree(NULL) {};
  301. virtual ~CBaseNeutralizer(void);
  302. virtual HRESULT InitFromCollection(IHTMLElementCollection *pColl,
  303. ULONG *pcElems = NULL )
  304. { return InitFromCollection( pColl, pcElems, NULL ); };
  305. HRESULT InitFromCollection(IHTMLElementCollection *pColl,
  306. ULONG *pcElems = NULL,
  307. IHTMLDocument2 *pDoc = NULL);
  308. virtual HRESULT PackageData(CWebArchive *pwa, BOOL *pfCancel = NULL,
  309. CThicketProgress *ptp = NULL, ULONG progLow = 0, ULONG progHigh = 100);
  310. protected:
  311. virtual BSTR _GetTargetAttribute(void);
  312. virtual HRESULT _PackageElement(CWebArchive *pwa,
  313. IHTMLElement *pElem);
  314. BSTR m_bstrLocal;
  315. IMarkupServices *m_pTree;
  316. };
  317. /*
  318. * CRelativeURLPackager - abstract base class for packagers
  319. * whose element's source attribute returns a relative URL.
  320. * This class implements triutils.pp's GetBackgroundImageUrl's
  321. * process of attempting to combine the (relative) element URL
  322. * with the nearest <BASE> URL. If no <BASE> is availaible, it
  323. * uses the document URL.
  324. *
  325. * This class is an abstract base because it does not implement
  326. * _GetTargetAttribute. It's implementation of InitFromCollection
  327. * isn't very useful and will probably be overridden by derived
  328. * classes.
  329. */
  330. class CRelativeURLPackager : public CCollectionPackager
  331. {
  332. public:
  333. CRelativeURLPackager(void) : m_pCollBase(NULL), m_cBase(0), m_bstrDocURL(NULL) {};
  334. virtual ~CRelativeURLPackager(void);
  335. virtual HRESULT InitFromCollection(IHTMLElementCollection *pColl,
  336. ULONG *pcElems = NULL)
  337. {
  338. return Init( pColl, pcElems, NULL );
  339. }
  340. virtual HRESULT Init(IHTMLElementCollection *pColl,
  341. ULONG *pcElems,
  342. IHTMLDocument2 *pDoc);
  343. protected:
  344. virtual HRESULT _GetElementURL(IHTMLElement *pElem, BSTR *pbstrURL);
  345. IHTMLElementCollection *m_pCollBase; // collection of BASE tags used to complete URLs
  346. ULONG m_cBase;
  347. BSTR m_bstrDocURL;
  348. };
  349. /*
  350. * CBackgroundPackager - packages the background of BODY, TABLE, TD, and TH.
  351. *
  352. * These three tags have a common target attribute.
  353. */
  354. class CBackgroundPackager : public CRelativeURLPackager
  355. {
  356. public:
  357. CBackgroundPackager(void) {};
  358. ~CBackgroundPackager(void) {};
  359. virtual HRESULT PackageData(CWebArchive *pwa, BOOL *pfCancel,
  360. CThicketProgress *ptp = NULL, ULONG progLow = 0, ULONG progHigh = 100);
  361. protected:
  362. virtual BSTR _GetTargetAttribute(void);
  363. };
  364. /*
  365. * CDynSrcPackager - packages the dynsrc of IMG and INPUT.
  366. *
  367. * These two tags have a common target attribute.
  368. */
  369. class CDynSrcPackager : public CRelativeURLPackager
  370. {
  371. public:
  372. CDynSrcPackager(void) {};
  373. ~CDynSrcPackager(void) {};
  374. virtual HRESULT PackageData(CWebArchive *pwa, BOOL *pfCancel,
  375. CThicketProgress *ptp = NULL, ULONG progLow = 0, ULONG progHigh = 100);
  376. protected:
  377. virtual BSTR _GetTargetAttribute(void);
  378. };
  379. /*
  380. * CScriptPackager - packages the dynsrc of IMG and INPUT.
  381. *
  382. * These two tags have a common target attribute.
  383. */
  384. class CScriptPackager : public CRelativeURLPackager
  385. {
  386. public:
  387. CScriptPackager(void) : m_pCollScripts(NULL) {};
  388. ~CScriptPackager(void) { if (m_pCollScripts) m_pCollScripts->Release(); };
  389. virtual HRESULT PackageData(CWebArchive *pwa, BOOL *pfCancel = NULL,
  390. CThicketProgress *ptp = NULL, ULONG progLow = 0, ULONG progHigh = 100)
  391. {
  392. return _PackageData( pwa, m_pCollScripts, pfCancel, ptp, progLow, progHigh );
  393. }
  394. virtual HRESULT Init(IHTMLElementCollection *pColl,
  395. ULONG *pcElems = NULL,
  396. IHTMLDocument2 *pDoc = NULL);
  397. protected:
  398. virtual BSTR _GetTargetAttribute(void);
  399. IHTMLElementCollection *m_pCollScripts;
  400. };
  401. /*
  402. * CFramesPackager - packages the <FRAME> and <IFRAME> sub-documents.
  403. *
  404. * This process is recursive, so all nested frames will be packaged.
  405. */
  406. class CFramesPackager : public CRelativeURLPackager
  407. {
  408. public:
  409. CFramesPackager(void) :
  410. m_pCollFrames(NULL),
  411. m_pframes2(NULL),
  412. m_cFrames(0),
  413. m_iFrameCur(0),
  414. m_pfCancel(0),
  415. m_ptp(NULL),
  416. m_uLow(0),
  417. m_uHigh(0),
  418. m_uRangeDoc(0) {};
  419. virtual ~CFramesPackager(void)
  420. {
  421. if (m_pCollFrames) m_pCollFrames->Release();
  422. if (m_pframes2) m_pframes2->Release();
  423. };
  424. virtual HRESULT InitFromCollection(IHTMLElementCollection *pColl,
  425. ULONG *pcElems = NULL)
  426. {
  427. return CRelativeURLPackager::Init( pColl, pcElems, NULL );
  428. }
  429. virtual HRESULT Init(IHTMLElementCollection *pColl,
  430. ULONG *pcElems,
  431. IHTMLDocument2 *pDoc,
  432. IHTMLDocument2 *pDocDesign,
  433. CDocumentPackager *pdp);
  434. virtual HRESULT PackageData(CWebArchive *pwa, BOOL *pfCancel,
  435. CThicketProgress *ptp = NULL, ULONG progLow = 0, ULONG progHigh = 100);
  436. protected:
  437. virtual BSTR _GetTargetAttribute(void);
  438. virtual HRESULT _PackageElement(CWebArchive *pwa,
  439. IHTMLElement *pElem);
  440. IHTMLElementCollection *m_pCollFrames;
  441. IHTMLFramesCollection2 *m_pframes2;
  442. ULONG m_cFrames;
  443. ULONG m_iFrameCur;
  444. BOOL *m_pfCancel;
  445. CThicketProgress* m_ptp;
  446. ULONG m_uLow;
  447. ULONG m_uHigh;
  448. ULONG m_uRangeDoc;
  449. CDocumentPackager *m_pdp;
  450. };
  451. /*
  452. * CSSPackager - packages imported stylesheets.
  453. *
  454. * Stylesheets have a different OM than document elements, so
  455. * we have a packager that looks similar, but works differently
  456. * than the other element packagers.
  457. *
  458. * We derive from CRelativeURLPackager for the convenience of
  459. * its Init method and <BASE> collection functionality, which
  460. * we also need because the hrefs in style sheets can be relative.
  461. *
  462. * Since we aren't actually packaging elments, the _GetTargetAttribute()
  463. * implementation is a formality to satisfy the abstract base class.
  464. */
  465. class CSSPackager : public CRelativeURLPackager
  466. {
  467. public:
  468. CSSPackager(void) : m_pDoc(NULL) {};
  469. ~CSSPackager(void) {};
  470. HRESULT Init( IHTMLElementCollection *pColl,
  471. ULONG *pcElems = NULL,
  472. IHTMLDocument2 *pDoc = NULL);
  473. HRESULT PackageStyleSheets(IHTMLDocument2 *pDoc2, CWebArchive *pwa);
  474. protected:
  475. BSTR _GetTargetAttribute(void) { ASSERT(FALSE); return NULL; };
  476. HRESULT _PackageSSCollection(IHTMLStyleSheetsCollection *pssc,
  477. CWebArchive *pwa);
  478. HRESULT _PackageSS(IHTMLStyleSheet *pss, CWebArchive *pwa);
  479. IHTMLDocument2 *m_pDoc;
  480. };
  481. // possible hash-table sizes, chosen from primes not close to powers of 2
  482. static const DWORD s_rgPrimes[] = { 29, 53, 97, 193, 389, 769, 1543, 3079, 6151, 12289, 24593 };
  483. /*
  484. * class implementation
  485. */
  486. /*
  487. * CWebArchive ##################################################
  488. */
  489. CWebArchive::CWebArchive(CThicketProgress *ptp)
  490. {
  491. m_lpstrDoc = NULL;
  492. m_lpstrSafeDoc = NULL;
  493. m_cBins = 0;
  494. m_rgBins = NULL;
  495. m_ptp = ptp;
  496. }
  497. CWebArchive::~CWebArchive(void)
  498. {
  499. CHashEntry *phe, *pheTemp;
  500. if (m_lpstrDoc != NULL)
  501. {
  502. LocalFree( m_lpstrDoc );
  503. m_lpstrDoc = NULL;
  504. }
  505. if (m_lpstrSafeDoc != NULL)
  506. {
  507. LocalFree( m_lpstrSafeDoc );
  508. m_lpstrSafeDoc = NULL;
  509. }
  510. // m_ptp is on loan to us, don't delete it
  511. for (DWORD dw = 0; dw < m_cBins; dw++)
  512. {
  513. if (m_rgBins[dw].m_pheNext)
  514. {
  515. phe = m_rgBins[dw].m_pheNext;
  516. while (phe)
  517. {
  518. pheTemp = phe;
  519. phe = phe->m_pheNext;
  520. delete pheTemp;
  521. }
  522. }
  523. }
  524. delete[] m_rgBins;
  525. }
  526. HRESULT
  527. CWebArchive::Init( LPCTSTR lpstrDoc, DWORD dwHashSize )
  528. {
  529. HRESULT hr = S_OK;
  530. int i = 0;
  531. m_lpstrDoc = StrDup(lpstrDoc);
  532. // check for replacement of old file
  533. if (PathFileExists(m_lpstrDoc))
  534. hr = _BackupOldFile();
  535. if (FAILED(hr))
  536. goto error;
  537. // Initialize the hash table.
  538. for (i = 0; i < (ARRAYSIZE(s_rgPrimes) - 1) && s_rgPrimes[i] < dwHashSize; i++);
  539. ASSERT(s_rgPrimes[i] >= dwHashSize || i == (ARRAYSIZE(s_rgPrimes)-1));
  540. m_cBins = s_rgPrimes[i];
  541. m_rgBins = new CHashEntry[m_cBins];
  542. if (m_rgBins==NULL)
  543. hr = E_OUTOFMEMORY;
  544. error:
  545. RRETURN(hr);
  546. }
  547. HRESULT
  548. CWebArchive::Commit()
  549. {
  550. // clean up old version of file
  551. if (m_lpstrSafeDoc)
  552. DeleteFile(m_lpstrSafeDoc);
  553. return S_OK;
  554. }
  555. HRESULT
  556. CWebArchive::Revert()
  557. {
  558. if (m_lpstrSafeDoc)
  559. {
  560. // we used to use MoveFileEx with MOVEFILE_REPLACE_EXISTING, but MoveFileEx
  561. // doesn't work on Win9x... so we have to DeleteFile/MoveFile instead...
  562. DeleteFile(m_lpstrDoc);
  563. BOOL fMoved = MoveFile(m_lpstrSafeDoc, m_lpstrDoc);
  564. if (!fMoved)
  565. {
  566. ASSERT(FALSE);
  567. // We shouldn't get into this situtation because we've pre-checked that
  568. // the original file is not read-only.
  569. DeleteFile(m_lpstrSafeDoc);
  570. }
  571. }
  572. return S_OK;
  573. }
  574. CWebArchive::ThURLType
  575. CWebArchive::_GetURLType( BSTR bstrURL )
  576. {
  577. // _tcsncmpi(bstrURL, 4, _T("http",4)
  578. if ( bstrURL[0] == TEXT('h') &&
  579. bstrURL[1] == TEXT('t') &&
  580. bstrURL[2] == TEXT('t') &&
  581. bstrURL[3] == TEXT('p') )
  582. return thurlHttp;
  583. else if ( bstrURL[0] == TEXT('f') &&
  584. bstrURL[1] == TEXT('i') &&
  585. bstrURL[2] == TEXT('l') &&
  586. bstrURL[3] == TEXT('e') )
  587. return thurlFile;
  588. else
  589. return thurlMisc;
  590. }
  591. HRESULT
  592. CWebArchive::_Insert(BSTR bstrI, BSTR bstrThicket, CHashEntry **pphe )
  593. {
  594. HRESULT hr = S_OK;
  595. CHashEntry *phe = &m_rgBins[Hash(bstrI)];
  596. ASSERT(pphe != NULL);
  597. *pphe = NULL;
  598. if (phe->m_bstrKey)
  599. {
  600. CHashEntry *pheNew = new CHashEntry;
  601. if (pheNew==NULL)
  602. return E_OUTOFMEMORY;
  603. if (pheNew->SetKey(bstrI) && pheNew->SetValue(bstrThicket))
  604. *pphe = pheNew;
  605. else
  606. {
  607. delete pheNew;
  608. hr = E_OUTOFMEMORY;
  609. goto Cleanup;
  610. }
  611. pheNew->m_pheNext = phe->m_pheNext;
  612. phe->m_pheNext = pheNew;
  613. phe = pheNew;
  614. }
  615. else if (phe->SetKey(bstrI) && phe->SetValue(bstrThicket))
  616. *pphe = phe;
  617. else
  618. hr = E_OUTOFMEMORY;
  619. Cleanup:
  620. return hr;
  621. }
  622. HRESULT
  623. CWebArchive::Find(BSTR bstrF, CHashEntry **pphe)
  624. {
  625. CHashEntry *phe = &m_rgBins[Hash(bstrF)];
  626. if (!pphe)
  627. return E_POINTER;
  628. *pphe = NULL;
  629. if (phe->m_bstrKey)
  630. {
  631. do
  632. {
  633. if (!StrCmpW(phe->m_bstrKey, bstrF))
  634. {
  635. ASSERT(phe->m_bstrValue!=NULL);
  636. *pphe = phe;
  637. return NOERROR;
  638. }
  639. phe = phe->m_pheNext;
  640. }
  641. while (phe);
  642. }
  643. return E_INVALIDARG;
  644. }
  645. DWORD
  646. CWebArchive::Hash(BSTR bstr)
  647. {
  648. DWORD h = 0;
  649. WCHAR *pwch = bstr;
  650. while (*pwch)
  651. h = ((h << 4) + *pwch++ + (h >> 28));
  652. return (h % m_cBins);
  653. }
  654. HRESULT
  655. CWebArchive::_BackupOldFile()
  656. {
  657. HRESULT hr = S_OK;
  658. TCHAR chT;
  659. LPTSTR lpstrT;
  660. TCHAR szT[MAX_PATH];
  661. DWORD dwAttrib = GetFileAttributes(m_lpstrDoc);
  662. if (dwAttrib & FILE_ATTRIBUTE_READONLY)
  663. return E_ACCESSDENIED;
  664. lpstrT = PathFindFileName(m_lpstrDoc);
  665. ASSERT(lpstrT);
  666. lpstrT--; // back up to the slash
  667. chT = *lpstrT;
  668. *lpstrT = 0;
  669. if (GetTempFileName( m_lpstrDoc, &lpstrT[1], 0,szT ))
  670. {
  671. *lpstrT = chT;
  672. if (CopyFile(m_lpstrDoc, szT, FALSE))
  673. {
  674. int cchSafeDoc = lstrlen(szT) + 1;
  675. m_lpstrSafeDoc = (LPTSTR)LocalAlloc( LMEM_FIXED, sizeof(TCHAR) * cchSafeDoc);
  676. if (m_lpstrSafeDoc)
  677. StringCchCopy(m_lpstrSafeDoc, cchSafeDoc, szT);
  678. else
  679. {
  680. hr = E_OUTOFMEMORY;
  681. DeleteFile(szT);
  682. }
  683. }
  684. else
  685. {
  686. hr = HRESULT_FROM_WIN32(GetLastError());
  687. goto error;
  688. }
  689. }
  690. else
  691. {
  692. hr = HRESULT_FROM_WIN32(GetLastError());
  693. goto error;
  694. }
  695. error:
  696. *lpstrT = chT;
  697. RRETURN(hr);
  698. }
  699. /*
  700. * CThicketArchive ##################################################
  701. */
  702. CThicketArchive::CThicketArchive(CThicketProgress *ptp) : CWebArchive(ptp)
  703. {
  704. m_lpstrFilesDir = NULL;
  705. m_lpstrFilesDirName = NULL;
  706. m_lpstrSafeDir = NULL;
  707. m_fFilesDir = FALSE; // TRUE when m_lpstrFilesDir has been created
  708. }
  709. CThicketArchive::~CThicketArchive(void)
  710. {
  711. if (m_lpstrFilesDir != NULL)
  712. {
  713. LocalFree( m_lpstrFilesDir );
  714. m_lpstrFilesDir = NULL;
  715. }
  716. if (m_lpstrSafeDir != NULL)
  717. {
  718. LocalFree( m_lpstrSafeDir );
  719. m_lpstrSafeDir = NULL;
  720. }
  721. // m_lpstrFilesDirName points into m_lpstrFilesDir
  722. }
  723. HRESULT
  724. CThicketArchive::Init( LPCTSTR lpstrDoc, DWORD dwHashSize )
  725. {
  726. HRESULT hr = CWebArchive::Init( lpstrDoc, dwHashSize );
  727. int i = 0;
  728. TCHAR chT;
  729. LPTSTR lpstrT;
  730. TCHAR szFmt[MAX_PATH];
  731. int cch;
  732. if (FAILED(hr))
  733. goto error;
  734. // Build the path to the directory for stored files, like 'Document1 files'.
  735. lpstrT = PathFindExtension(m_lpstrDoc);
  736. chT = *lpstrT;
  737. *lpstrT = 0;
  738. MLLoadString(IDS_THICKETDIRFMT, szFmt, ARRAYSIZE(szFmt));
  739. cch = lstrlen(m_lpstrDoc) + lstrlen(szFmt) + 1;
  740. m_lpstrFilesDir = (LPTSTR)LocalAlloc( LMEM_FIXED, sizeof(TCHAR) * cch );
  741. if (m_lpstrFilesDir==NULL)
  742. {
  743. hr = E_OUTOFMEMORY;
  744. goto error;
  745. }
  746. StringCchCopy( m_lpstrFilesDir, cch, m_lpstrDoc);
  747. StringCchCat( m_lpstrFilesDir, cch, szFmt);
  748. *lpstrT = chT;
  749. // make m_lpstrFilesDirName point to the last component of m_lpstrFilesDir
  750. for ( i = lstrlen(m_lpstrFilesDir) - 1; i > 0 && m_lpstrFilesDirName == NULL; i-- )
  751. {
  752. if ( m_lpstrFilesDir[i-1] == FILENAME_SEPARATOR )
  753. m_lpstrFilesDirName = &m_lpstrFilesDir[i];
  754. }
  755. // check to see if the files dir already exists. If it does, rename the original.
  756. if (PathFileExists(m_lpstrFilesDir))
  757. hr = _BackupOldDirectory();
  758. if (FAILED(hr))
  759. goto error;
  760. error:
  761. RRETURN(hr);
  762. }
  763. HRESULT
  764. CThicketArchive::AddURL( BSTR bstrURL, CHashEntry **pphe )
  765. {
  766. HRESULT hr;
  767. hr = THR(Find(bstrURL, pphe));
  768. if (FAILED(hr))
  769. {
  770. // first, lets put our document dir in place, if it isn't already
  771. if (!m_fFilesDir)
  772. m_fFilesDir = (SHCreateDirectory(NULL, m_lpstrFilesDir) == ERROR_SUCCESS);
  773. if (m_fFilesDir)
  774. {
  775. switch (_GetURLType(bstrURL))
  776. {
  777. case thurlMisc:
  778. hr = _PersistMiscURL(bstrURL, pphe);
  779. break;
  780. case thurlHttp:
  781. hr = _PersistHttpURL(bstrURL, pphe);
  782. break;
  783. case thurlFile:
  784. hr = _PersistFileURL(bstrURL, pphe);
  785. break;
  786. }
  787. }
  788. else
  789. hr = E_FAIL;
  790. }
  791. RRETURN(hr);
  792. }
  793. HRESULT
  794. CThicketArchive::AddFrameOrStyleEntry( BSTR bstrURL, CHashEntry **pphe, LPTSTR lpstrFrameDoc )
  795. {
  796. HRESULT hr;
  797. hr = THR(Find(bstrURL, pphe)); // there's always a slim chance we're reusing a frame.
  798. if (FAILED(hr))
  799. {
  800. // first, lets put our document dir in place, if it isn't already
  801. if (!m_fFilesDir)
  802. m_fFilesDir = (SHCreateDirectory(NULL, m_lpstrFilesDir) == ERROR_SUCCESS);
  803. if (m_fFilesDir)
  804. {
  805. switch (_GetURLType(bstrURL))
  806. {
  807. case thurlMisc:
  808. //hr = _AddMiscEntry(bstrURL, pphe, lpstrFrameDoc);
  809. // It would be nice if we could just _AddMiscEntry, but if set a frame src
  810. // to one of the temp files that this produces, we get a 'Do you want to open'
  811. // prompt, so instead, we'll just keep this funky protocol URL.
  812. hr = CWebArchive::_Insert( bstrURL, bstrURL, pphe );
  813. lpstrFrameDoc[0] = 0; // shouldn't be used, anyway
  814. hr = S_FALSE; // I told him we all-reddy got one! <snicker>
  815. break;
  816. case thurlHttp:
  817. hr = _AddHttpEntry(bstrURL, pphe, lpstrFrameDoc);
  818. break;
  819. case thurlFile:
  820. hr = _AddFileEntry(bstrURL, pphe, lpstrFrameDoc);
  821. break;
  822. }
  823. if (m_ptp)
  824. m_ptp->SetSaving( PathFindFileName(lpstrFrameDoc), m_lpstrFilesDir );
  825. }
  826. else
  827. {
  828. hr = (GetLastError() == ERROR_DISK_FULL) ? (HRESULT_FROM_WIN32(ERROR_DISK_FULL))
  829. : (E_FAIL);
  830. }
  831. }
  832. else
  833. {
  834. LPTSTR lpszThicket;
  835. lpszThicket = (*pphe)->m_bstrValue;
  836. PathCombine( lpstrFrameDoc, m_lpstrFilesDir, lpszThicket );
  837. hr = S_FALSE;
  838. }
  839. return hr; // no RRETURN - may return S_FALSE
  840. }
  841. HRESULT
  842. CThicketArchive::Commit()
  843. {
  844. CWebArchive::Commit();
  845. // clean up obsolete files dir.
  846. if (m_lpstrSafeDir)
  847. {
  848. _RemoveOldDirectoryAndChildren(m_lpstrSafeDir);
  849. }
  850. return S_OK;
  851. }
  852. HRESULT
  853. CThicketArchive::Revert()
  854. {
  855. // clean up file dir
  856. _RemoveOldDirectoryAndChildren(m_lpstrFilesDir);
  857. // restore old files dir.
  858. if (m_lpstrSafeDir)
  859. MoveFile(m_lpstrSafeDir,m_lpstrFilesDir);
  860. return CWebArchive::Revert();;
  861. }
  862. HRESULT CThicketArchive::ArchiveDocumentText(IHTMLDocument2 *pDoc, UINT cpDoc, BOOL fFrameDoc)
  863. {
  864. HRESULT hr = S_OK;
  865. IPersistStreamInit* ppsi = NULL;
  866. IStream* pstm = NULL;
  867. hr = SHCreateStreamOnFile(m_lpstrDoc, STGM_WRITE | STGM_CREATE, &pstm);
  868. if (SUCCEEDED(hr))
  869. {
  870. hr = pDoc->QueryInterface(IID_IPersistStreamInit, (void**)&ppsi);
  871. if (SUCCEEDED(hr))
  872. {
  873. hr = _ApplyMarkOfTheWeb( pDoc, pstm, cpDoc == CP_UNICODE );
  874. if ( SUCCEEDED(hr) )
  875. hr = ppsi->Save(pstm, FALSE);
  876. }
  877. }
  878. ReleaseInterface(ppsi);
  879. ReleaseInterface(pstm);
  880. RRETURN(hr);
  881. }
  882. HRESULT CThicketArchive::ArchiveCSSText( BSTR bstrCSSUrl, LPCSTR lpszSSText, LPCTSTR lpszStyleDoc )
  883. {
  884. HRESULT hr = S_OK;
  885. HANDLE hfile;
  886. hfile = CreateFile( lpszStyleDoc, GENERIC_WRITE, FILE_SHARE_READ, NULL,
  887. CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
  888. if (hfile!=INVALID_HANDLE_VALUE)
  889. {
  890. ULONG cbWrite, cbWritten;
  891. cbWrite = lstrlenA(lpszSSText);
  892. if (!WriteFile( hfile, lpszSSText, cbWrite, &cbWritten, NULL ))
  893. hr = HRESULT_FROM_WIN32(GetLastError());
  894. CloseHandle(hfile);
  895. }
  896. else
  897. hr = HRESULT_FROM_WIN32(hr);
  898. return hr;
  899. }
  900. EXTERN_C HRESULT GetMarkOfTheWeb( LPCSTR, LPCSTR, DWORD, LPSTR *);
  901. HRESULT CThicketArchive::_ApplyMarkOfTheWeb( IHTMLDocument2 *pDoc, LPSTREAM pstm, BOOL fUnicode )
  902. {
  903. HRESULT hr;
  904. IInternetSecurityManager *pism = NULL;
  905. DWORD dwZone;
  906. BSTR bstrURL = NULL;
  907. hr = pDoc->get_URL( &bstrURL );
  908. if (FAILED(hr))
  909. return hr;
  910. // We only want to mark the document if it isn't already coming from the local
  911. // file system. If ( minus the mark ) the file is in the local machine zone,
  912. // then it was made here, saved with a mark, or created outside our control.
  913. // If it was saved with a mark, then we want to leave that in place, rather
  914. // than mark it with the local copy's file: URL.
  915. hr = CoInternetCreateSecurityManager( NULL, &pism, 0 );
  916. if (SUCCEEDED(hr) &&
  917. SUCCEEDED(pism->MapUrlToZone( bstrURL, &dwZone, MUTZ_NOSAVEDFILECHECK)) &&
  918. dwZone != URLZONE_LOCAL_MACHINE )
  919. {
  920. LPSTR pszMark;
  921. DWORD cchURL = WideCharToMultiByte(CP_ACP, 0, bstrURL, -1, NULL, 0, NULL, NULL);
  922. LPSTR pszURL = new CHAR[cchURL];
  923. if (pszURL)
  924. {
  925. if (WideCharToMultiByte(CP_ACP, 0, bstrURL, -1, pszURL, cchURL, NULL, NULL))
  926. {
  927. int cch = lstrlen(m_lpstrDoc) + 1;
  928. LPSTR psz = new char[cch];
  929. if (psz)
  930. {
  931. SHUnicodeToAnsi(m_lpstrDoc, psz, cch);
  932. hr = GetMarkOfTheWeb( pszURL, psz, 0, &pszMark);
  933. delete [] psz;
  934. }
  935. else
  936. {
  937. hr = E_OUTOFMEMORY;
  938. }
  939. IMarkupServices *pims = NULL;
  940. IMarkupPointer *pimp = NULL;
  941. IMarkupContainer *pimc = NULL;
  942. IHTMLElement *pihe = NULL;
  943. IHTMLElement *piheBody = NULL;
  944. IDispatch *pidDocument = NULL;
  945. IHTMLCommentElement *pihce = NULL;
  946. LPWSTR pwszMark = NULL;
  947. BSTR bstrMark = NULL;
  948. hr = pDoc->QueryInterface(IID_IMarkupServices, (void **)&pims);
  949. if (SUCCEEDED(hr)) {
  950. hr = pims->CreateElement(TAGID_COMMENT, NULL, &pihe);
  951. if (SUCCEEDED(hr)) {
  952. hr = pihe->QueryInterface(IID_IHTMLCommentElement, (void **)&pihce);
  953. }
  954. if (SUCCEEDED(hr)) {
  955. int cbWrite = 0;
  956. int cchMark = MultiByteToWideChar(CP_ACP, 0, pszMark, -1, NULL, 0);
  957. // cchMark includes the null terminator.
  958. pwszMark = new WCHAR[cchMark];
  959. if ( pwszMark != NULL )
  960. {
  961. MultiByteToWideChar( CP_ACP, 0, pszMark, -1, pwszMark, cchMark);
  962. cbWrite = (cchMark - 1) * sizeof(WCHAR);
  963. }
  964. else
  965. {
  966. hr = E_OUTOFMEMORY;
  967. }
  968. if (SUCCEEDED(hr))
  969. {
  970. // force <!-- ... --> style comment
  971. hr = pihce->put_atomic(1);
  972. }
  973. }
  974. if (SUCCEEDED(hr)) {
  975. bstrMark = SysAllocString(pwszMark);
  976. if (NULL != bstrMark)
  977. {
  978. hr = pihce->put_text(bstrMark);
  979. }
  980. else
  981. {
  982. hr = E_OUTOFMEMORY;
  983. }
  984. }
  985. if (SUCCEEDED(hr)) {
  986. hr = pims->CreateMarkupPointer(&pimp);
  987. }
  988. if (SUCCEEDED(hr)) {
  989. hr = pDoc->get_body(&piheBody);
  990. }
  991. if (SUCCEEDED(hr)) {
  992. hr = piheBody->get_document(&pidDocument);
  993. }
  994. if (SUCCEEDED(hr)) {
  995. hr = pidDocument->QueryInterface(IID_IMarkupContainer, (void **)&pimc);
  996. }
  997. if (SUCCEEDED(hr)) {
  998. // Move to beginning of doc and insert it
  999. hr = pimp->MoveToContainer(pimc, TRUE);
  1000. if (SUCCEEDED(hr)) {
  1001. hr = pims->InsertElement(pihe, pimp, pimp);
  1002. }
  1003. }
  1004. }
  1005. SAFERELEASE(pims);
  1006. SAFERELEASE(pimc);
  1007. SAFERELEASE(pihe);
  1008. SAFERELEASE(pimp);
  1009. SAFERELEASE(piheBody);
  1010. SAFERELEASE(pidDocument);
  1011. SAFERELEASE(pihce);
  1012. if (bstrMark)
  1013. {
  1014. SysFreeString(bstrMark);
  1015. }
  1016. if (pwszMark)
  1017. {
  1018. delete[] pwszMark;
  1019. }
  1020. }
  1021. else
  1022. hr = HRESULT_FROM_WIN32(GetLastError());
  1023. delete[] pszURL;
  1024. }
  1025. else
  1026. hr = E_OUTOFMEMORY;
  1027. }
  1028. ReleaseInterface(pism);
  1029. if (bstrURL)
  1030. SysFreeString(bstrURL);
  1031. return hr;
  1032. }
  1033. HRESULT
  1034. CThicketArchive::_AddHttpEntry( BSTR bstrURL, CHashEntry **pphe, LPTSTR lpstrDstFile, LPTSTR lpstrSrcFile )
  1035. {
  1036. HRESULT hr;
  1037. TCHAR szCacheFile[MAX_PATH];
  1038. LPTSTR lpszDst;
  1039. LPTSTR lpszFile;
  1040. int cchFile;
  1041. LPTSTR lpszURL;
  1042. lpszURL = bstrURL;
  1043. hr = URLDownloadToCacheFile(NULL, lpszURL, szCacheFile,
  1044. ARRAYSIZE(szCacheFile), BINDF_FWD_BACK,
  1045. NULL);
  1046. if (FAILED(hr))
  1047. goto Cleanup;
  1048. if (lpstrSrcFile)
  1049. StringCchCopy(lpstrSrcFile, MAX_PATH, szCacheFile);
  1050. PathUndecorate( szCacheFile );
  1051. lpszFile = PathFindFileName( szCacheFile );
  1052. ASSERT(lpszFile != NULL);
  1053. cchFile = ARRAYSIZE(szCacheFile) - (int)(lpszFile-szCacheFile);
  1054. hr = _Insert( bstrURL, lpszFile, cchFile, pphe );
  1055. lpszDst = PathCombine( lpstrDstFile, m_lpstrFilesDir, lpszFile );
  1056. ASSERT( lpszDst );
  1057. Cleanup:
  1058. RRETURN(hr);
  1059. }
  1060. HRESULT
  1061. CThicketArchive::_AddFileEntry( BSTR bstrURL, CHashEntry **pphe, LPTSTR lpstrDstFile, LPTSTR lpstrSrcFile )
  1062. {
  1063. HRESULT hr;
  1064. LPTSTR lpszDst;
  1065. LPTSTR lpszFile;
  1066. int cchFile;
  1067. LPTSTR lpszPath;
  1068. WCHAR rgchUrlPath[MAX_PATH];
  1069. DWORD dwLen;
  1070. dwLen = ARRAYSIZE(rgchUrlPath);
  1071. hr = PathCreateFromUrlW(bstrURL, rgchUrlPath, &dwLen, 0);
  1072. if (FAILED(hr))
  1073. return E_FAIL;
  1074. lpszPath = rgchUrlPath;
  1075. if (lpstrSrcFile)
  1076. StringCchCopy( lpstrSrcFile, MAX_PATH, lpszPath);
  1077. lpszFile = PathFindFileName( lpszPath );
  1078. ASSERT(lpszFile != NULL);
  1079. cchFile = ARRAYSIZE(rgchUrlPath) - (int)(lpszFile-rgchUrlPath);
  1080. hr = THR(_Insert( bstrURL, lpszFile, cchFile, pphe ));
  1081. lpszDst = PathCombine( lpstrDstFile, m_lpstrFilesDir, lpszFile );
  1082. ASSERT( lpszDst );
  1083. RRETURN(hr);
  1084. }
  1085. HRESULT
  1086. CThicketArchive::_AddMiscEntry( BSTR bstrURL, CHashEntry **pphe, LPTSTR lpstrDstFile, int cchDstFile )
  1087. {
  1088. HRESULT hr;
  1089. TCHAR szT[MAX_PATH];
  1090. LPTSTR lpszPrefix;
  1091. LPTSTR lpszDst;
  1092. lpszPrefix = bstrURL;
  1093. if (GetTempFileName( m_lpstrFilesDir, lpszPrefix, 0,szT ))
  1094. {
  1095. lpszDst = PathCombine( lpstrDstFile, m_lpstrFilesDir, szT );
  1096. ASSERT(lpszDst);
  1097. LPTSTR pszFile = PathFindFileName(lpstrDstFile);
  1098. hr = THR(_Insert( bstrURL, pszFile, cchDstFile - (int)(pszFile-lpstrDstFile), pphe ));
  1099. }
  1100. else
  1101. hr = HRESULT_FROM_WIN32(GetLastError());
  1102. RRETURN(hr);
  1103. }
  1104. HRESULT
  1105. CThicketArchive::_PersistHttpURL( BSTR bstrURL, CHashEntry **pphe )
  1106. {
  1107. HRESULT hr;
  1108. TCHAR szDst[MAX_PATH];
  1109. TCHAR szSrc[MAX_PATH];
  1110. hr = THR(_AddHttpEntry( bstrURL, pphe, szDst, szSrc ));
  1111. if (FAILED(hr))
  1112. goto Error;
  1113. if (m_ptp)
  1114. m_ptp->SetSaving( PathFindFileName(szSrc), m_lpstrFilesDir );
  1115. if (!CopyFile(szSrc,szDst, FALSE))
  1116. hr = HRESULT_FROM_WIN32(GetLastError());
  1117. Error:
  1118. RRETURN(hr);
  1119. }
  1120. HRESULT
  1121. CThicketArchive::_PersistFileURL( BSTR bstrURL, CHashEntry **pphe )
  1122. {
  1123. HRESULT hr;
  1124. TCHAR szDst[MAX_PATH];
  1125. TCHAR szSrc[MAX_PATH];
  1126. hr = THR(_AddFileEntry( bstrURL, pphe, szDst, szSrc ));
  1127. if (FAILED(hr))
  1128. goto Error;
  1129. if (m_ptp)
  1130. m_ptp->SetSaving( PathFindFileName(szSrc), m_lpstrFilesDir );
  1131. if (!CopyFile(szSrc,szDst, FALSE))
  1132. hr = HRESULT_FROM_WIN32(GetLastError());
  1133. Error:
  1134. RRETURN(hr);
  1135. }
  1136. HRESULT
  1137. CThicketArchive::_PersistMiscURL( BSTR bstrURL, CHashEntry **pphe )
  1138. {
  1139. HRESULT hr;
  1140. TCHAR szDst[MAX_PATH];
  1141. LPTSTR lpszURL;
  1142. lpszURL = bstrURL;
  1143. hr = THR(_AddMiscEntry( bstrURL, pphe, szDst, ARRAYSIZE(szDst) ));
  1144. if (FAILED(hr))
  1145. goto Error;
  1146. if (m_ptp)
  1147. m_ptp->SetSaving( PathFindFileName(szDst), m_lpstrFilesDir );
  1148. hr = URLDownloadToFile(NULL, lpszURL, szDst,0, NULL);
  1149. Error:
  1150. RRETURN(hr);
  1151. }
  1152. HRESULT
  1153. CThicketArchive::_Insert(BSTR bstrI, LPTSTR lpszFile, int cchFile, CHashEntry **pphe )
  1154. {
  1155. HRESULT hr = S_OK;
  1156. BSTR bstrThicket = NULL;
  1157. TCHAR buf[MAX_PATH];
  1158. int i = 0;
  1159. CHashEntry *phe = &m_rgBins[Hash(bstrI)];
  1160. ASSERT(pphe != NULL);
  1161. *pphe = NULL;
  1162. if (lstrlen(m_lpstrFilesDir) + lstrlen(lpszFile) + 1 < MAX_PATH)
  1163. StringCchPrintf( buf, ARRAYSIZE(buf), TEXT("%s") TEXT(FILENAME_SEPARATOR_STR) TEXT("%s"), m_lpstrFilesDir, lpszFile );
  1164. else
  1165. {
  1166. hr = E_FAIL;
  1167. goto Cleanup;
  1168. }
  1169. // Defend against bug 18160 - collision of file names in the thicket.
  1170. if ( PathFileExists(buf) )
  1171. {
  1172. TCHAR *pszExt = PathFindExtension(lpszFile);
  1173. int i = 0;
  1174. // chop the file name into name and extenstion
  1175. if ( pszExt )
  1176. {
  1177. *pszExt = 0;
  1178. pszExt++;
  1179. }
  1180. do
  1181. {
  1182. i++;
  1183. if ( pszExt )
  1184. StringCchPrintf( buf, ARRAYSIZE(buf), TEXT("%s") TEXT(FILENAME_SEPARATOR_STR) TEXT("%s(%d).%s"), m_lpstrFilesDir, lpszFile, i, pszExt );
  1185. else
  1186. StringCchPrintf( buf, ARRAYSIZE(buf), TEXT("%s") TEXT(FILENAME_SEPARATOR_STR) TEXT("%s(%d)"), m_lpstrFilesDir, lpszFile, i );
  1187. } while ( PathFileExists(buf) && i < 1000 );
  1188. // deviously rewrite the file name for the caller
  1189. StringCchCopy(lpszFile, cchFile, PathFindFileName(buf));
  1190. }
  1191. else
  1192. StringCchPrintf( buf, ARRAYSIZE(buf), TEXT("%s/%s"), m_lpstrFilesDirName, lpszFile );
  1193. bstrThicket = SysAllocString(buf);
  1194. if (bstrThicket == NULL)
  1195. {
  1196. hr = E_OUTOFMEMORY;
  1197. goto Cleanup;
  1198. }
  1199. if (phe->m_bstrKey)
  1200. {
  1201. CHashEntry *pheNew = new CHashEntry;
  1202. if (pheNew==NULL)
  1203. return E_OUTOFMEMORY;
  1204. if (pheNew->SetKey(bstrI) && pheNew->SetValue(bstrThicket))
  1205. *pphe = pheNew;
  1206. else
  1207. {
  1208. delete pheNew;
  1209. hr = E_OUTOFMEMORY;
  1210. goto Cleanup;
  1211. }
  1212. pheNew->m_pheNext = phe->m_pheNext;
  1213. phe->m_pheNext = pheNew;
  1214. phe = pheNew;
  1215. }
  1216. else if (phe->SetKey(bstrI) && phe->SetValue(bstrThicket))
  1217. *pphe = phe;
  1218. else
  1219. hr = E_OUTOFMEMORY;
  1220. Cleanup:
  1221. if (bstrThicket)
  1222. SysFreeString(bstrThicket);
  1223. return hr;
  1224. }
  1225. HRESULT
  1226. CThicketArchive::_BackupOldDirectory()
  1227. {
  1228. int n = 1;
  1229. HRESULT hr = S_OK;
  1230. TCHAR szFmt[MAX_PATH];
  1231. // Do we need to do this under critical section?
  1232. MLLoadString(IDS_THICKETTEMPFMT, szFmt, ARRAYSIZE(szFmt));
  1233. do {
  1234. if (m_lpstrSafeDir)
  1235. {
  1236. LocalFree( m_lpstrSafeDir );
  1237. m_lpstrSafeDir = NULL;
  1238. }
  1239. if (n > 100) // avoid infinite loop!
  1240. break;
  1241. DWORD cchSafeDir = lstrlen(m_lpstrFilesDir) + lstrlen(szFmt) + 1;
  1242. m_lpstrSafeDir = (LPTSTR)LocalAlloc( LMEM_FIXED, sizeof(TCHAR) * cchSafeDir );
  1243. if (m_lpstrSafeDir!=NULL)
  1244. {
  1245. StringCchPrintf( m_lpstrSafeDir, cchSafeDir, szFmt, m_lpstrFilesDir, n++ );
  1246. }
  1247. else
  1248. hr = E_OUTOFMEMORY;
  1249. } while (SUCCEEDED(hr) && GetFileAttributes(m_lpstrSafeDir) != -1 && n < 1000);
  1250. // rename the old version of the supporting files directory
  1251. if (SUCCEEDED(hr) && !MoveFile(m_lpstrFilesDir, m_lpstrSafeDir))
  1252. {
  1253. LocalFree( m_lpstrSafeDir );
  1254. m_lpstrSafeDir = NULL;
  1255. hr = HRESULT_FROM_WIN32(GetLastError());
  1256. }
  1257. RRETURN(hr);
  1258. }
  1259. HRESULT
  1260. CThicketArchive::_RemoveOldDirectoryAndChildren( LPCWSTR pwzDir )
  1261. {
  1262. HRESULT hr = S_OK;
  1263. HANDLE hf = INVALID_HANDLE_VALUE;
  1264. WCHAR wzBuf[MAX_PATH];
  1265. WIN32_FIND_DATAW fd;
  1266. if (!pwzDir)
  1267. goto Exit;
  1268. if (RemoveDirectoryW(pwzDir))
  1269. goto Exit;
  1270. // FindNextFile returns 120, not implemented on OSR2, so we'll have to do all
  1271. // this stuff multibyte
  1272. StringCchCopy(wzBuf, ARRAYSIZE(wzBuf), pwzDir);
  1273. StringCchCat(wzBuf, ARRAYSIZE(wzBuf), FILENAME_SEPARATOR_STR_W L"*");
  1274. if ((hf = FindFirstFileW(wzBuf, &fd)) == INVALID_HANDLE_VALUE) {
  1275. hr = HRESULT_FROM_WIN32(GetLastError());
  1276. goto Exit;
  1277. }
  1278. do {
  1279. if ( (StrCmpW(fd.cFileName, L".") == 0) ||
  1280. (StrCmpW(fd.cFileName, L"..") == 0))
  1281. continue;
  1282. StringCchPrintf(wzBuf, ARRAYSIZE(wzBuf), L"%s" FILENAME_SEPARATOR_STR_W L"%s", pwzDir, fd.cFileName);
  1283. if (fd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
  1284. SetFileAttributesW(wzBuf,
  1285. FILE_ATTRIBUTE_DIRECTORY|FILE_ATTRIBUTE_NORMAL);
  1286. if (FAILED((hr=_RemoveOldDirectoryAndChildren(wzBuf)))) {
  1287. goto Exit;
  1288. }
  1289. } else {
  1290. SetFileAttributesW(wzBuf, FILE_ATTRIBUTE_NORMAL);
  1291. if (!DeleteFileW(wzBuf)) {
  1292. hr = HRESULT_FROM_WIN32(GetLastError());
  1293. goto Exit;
  1294. }
  1295. }
  1296. } while (FindNextFileW(hf, &fd));
  1297. if (GetLastError() != ERROR_NO_MORE_FILES) {
  1298. hr = HRESULT_FROM_WIN32(GetLastError());
  1299. goto Exit;
  1300. }
  1301. if (hf != INVALID_HANDLE_VALUE) {
  1302. FindClose(hf);
  1303. hf = INVALID_HANDLE_VALUE;
  1304. }
  1305. // here if all subdirs/children removed
  1306. /// re-attempt to remove the main dir
  1307. if (!RemoveDirectoryW(pwzDir)) {
  1308. hr = HRESULT_FROM_WIN32(GetLastError());
  1309. goto Exit;
  1310. }
  1311. Exit:
  1312. if (hf != INVALID_HANDLE_VALUE)
  1313. FindClose(hf);
  1314. RRETURN(hr);
  1315. }
  1316. /*
  1317. * CMHTMLArchive ##################################################
  1318. */
  1319. CMHTMLArchive::CMHTMLArchive(CThicketProgress *ptp) :
  1320. CWebArchive(ptp),
  1321. m_hBodyAlt(NULL),
  1322. m_pimm(NULL)
  1323. {
  1324. }
  1325. CMHTMLArchive::~CMHTMLArchive(void)
  1326. {
  1327. ReleaseInterface(m_pimm);
  1328. }
  1329. HRESULT
  1330. CMHTMLArchive::Init( LPCTSTR lpstrDoc, DWORD dwHashSize )
  1331. {
  1332. HRESULT hr = S_OK;
  1333. MimeOleSetCompatMode(MIMEOLE_COMPAT_MLANG2);
  1334. if ( m_pimm == NULL )
  1335. {
  1336. hr = CWebArchive::Init( lpstrDoc, dwHashSize );
  1337. if (SUCCEEDED(hr))
  1338. hr = MimeOleCreateMessage(NULL, &m_pimm);
  1339. }
  1340. RRETURN(hr);
  1341. }
  1342. HRESULT
  1343. CMHTMLArchive::AddURL( BSTR bstrURL, CHashEntry **pphe )
  1344. {
  1345. HRESULT hr;
  1346. hr = THR(Find(bstrURL, pphe));
  1347. if (FAILED(hr))
  1348. {
  1349. IStream *pstm = NULL;
  1350. CHAR szUrl[INTERNET_MAX_URL_LENGTH];
  1351. WCHAR wzArchiveText[MAX_SAVING_STATUS_TEXT + 1];
  1352. WCHAR wzBuf[INTERNET_MAX_URL_LENGTH + MAX_SAVING_STATUS_TEXT + 1];
  1353. LPSTR lpszCID=0;
  1354. DWORD dwAttach = URL_ATTACH_SET_CNTTYPE;
  1355. SHUnicodeToAnsi(bstrURL, szUrl, ARRAYSIZE(szUrl));
  1356. // hack: if it's an MHTML: url then we have to fixup to get the cid:
  1357. if (StrCmpNIA(szUrl, "mhtml:", 6)==0)
  1358. {
  1359. LPSTR lpszBody;
  1360. if (SUCCEEDED(MimeOleParseMhtmlUrl(szUrl, NULL, &lpszBody)))
  1361. {
  1362. StringCchCopyA(szUrl, INTERNET_MAX_URL_LENGTH, lpszBody);
  1363. CoTaskMemFree(lpszBody);
  1364. }
  1365. }
  1366. MLLoadStringW(IDS_SAVING_STATUS_TEXT, wzArchiveText,
  1367. ARRAYSIZE(wzArchiveText));
  1368. StringCchPrintf(wzBuf, ARRAYSIZE(wzBuf), L"%ws: %ws", wzArchiveText, bstrURL);
  1369. m_ptp->SetSaveText(wzBuf);
  1370. #ifndef WIN16 //RUN16_BLOCK - NOT YET AVAILABLE
  1371. hr = URLOpenBlockingStreamW(NULL, bstrURL, &pstm, 0, NULL);
  1372. #else
  1373. hr = MIME_E_URL_NOTFOUND;
  1374. #endif
  1375. if (SUCCEEDED(hr))
  1376. {
  1377. HBODY hBody;
  1378. hr = m_pimm->AttachURL(NULL, szUrl, dwAttach, pstm, &lpszCID, &hBody);
  1379. if (SUCCEEDED(hr))
  1380. hr = _Insert( bstrURL, bstrURL, pphe );
  1381. }
  1382. ReleaseInterface(pstm);
  1383. }
  1384. RRETURN(hr);
  1385. }
  1386. HRESULT
  1387. CMHTMLArchive::AddFrameOrStyleEntry( BSTR bstrURL, CHashEntry **pphe, LPTSTR lpstrFrameDoc )
  1388. {
  1389. HRESULT hr;
  1390. hr = THR(Find(bstrURL, pphe)); // there's always a slim chance we're reusing a frame.
  1391. if (FAILED(hr))
  1392. {
  1393. // insert place-holder
  1394. hr = _Insert(bstrURL, c_bstr_BLANK, pphe);
  1395. }
  1396. return hr; // no RRETURN - may return S_FALSE
  1397. }
  1398. HRESULT
  1399. CMHTMLArchive::ArchiveDocumentText(IHTMLDocument2 *pDoc, UINT cpDoc, BOOL fFrameDoc)
  1400. {
  1401. HRESULT hr = S_OK;
  1402. IPersistStreamInit* ppsi = NULL;
  1403. PROPVARIANT variant;
  1404. FILETIME filetime;
  1405. WCHAR wzBuffer[MAX_BUFFER_LEN];
  1406. WCHAR wzArchiveText[MAX_SAVING_STATUS_TEXT + 1];
  1407. WCHAR wzBuf[INTERNET_MAX_URL_LENGTH + MAX_SAVING_STATUS_TEXT + 1];
  1408. // Set the MIME subject header
  1409. PropVariantClear(&variant);
  1410. variant.vt = VT_LPWSTR;
  1411. hr = pDoc->get_title(&variant.pwszVal);
  1412. if (SUCCEEDED(hr))
  1413. {
  1414. hr = m_pimm->SetBodyProp(HBODY_ROOT, PIDTOSTR(PID_HDR_SUBJECT), 0,
  1415. &variant);
  1416. SAFEFREEBSTR(variant.pwszVal);
  1417. }
  1418. // Set the MIME date header
  1419. if (SUCCEEDED(hr))
  1420. {
  1421. hr = CoFileTimeNow(&filetime);
  1422. }
  1423. if (SUCCEEDED(hr))
  1424. {
  1425. PropVariantClear(&variant);
  1426. variant.vt = VT_FILETIME;
  1427. variant.filetime = filetime;
  1428. hr = m_pimm->SetBodyProp(HBODY_ROOT, PIDTOSTR(PID_HDR_DATE), 0,
  1429. &variant);
  1430. }
  1431. // Set the MIME from header
  1432. if (SUCCEEDED(hr))
  1433. {
  1434. MLLoadStringW(IDS_MIME_SAVEAS_HEADER_FROM, wzBuffer,
  1435. ARRAYSIZE(wzBuffer));
  1436. PropVariantClear(&variant);
  1437. variant.vt = VT_LPWSTR;
  1438. variant.pwszVal = wzBuffer;
  1439. hr = m_pimm->SetBodyProp(HBODY_ROOT, PIDTOSTR(PID_HDR_FROM), 0,
  1440. &variant);
  1441. }
  1442. hr = pDoc->QueryInterface(IID_IPersistStreamInit, (void**)&ppsi);
  1443. if (SUCCEEDED(hr))
  1444. {
  1445. IStream *pstm = NULL;
  1446. hr = MimeOleCreateVirtualStream( &pstm );
  1447. if ( SUCCEEDED(hr) )
  1448. {
  1449. HBODY hBody;
  1450. hr = ppsi->Save(pstm, FALSE);
  1451. if (SUCCEEDED(hr))
  1452. {
  1453. BSTR bstrDocURL = NULL;
  1454. WCHAR *pwzBookMark = NULL;
  1455. pDoc->get_URL(&bstrDocURL);
  1456. RemoveBookMark(bstrDocURL, &pwzBookMark);
  1457. if (!StrCmpIW(bstrDocURL, URL_ABOUT_BLANK))
  1458. {
  1459. // We got about:blank as the URL (because the doc has
  1460. // document.write's etc in it). We can't save this!
  1461. hr = E_FAIL;
  1462. goto Exit;
  1463. }
  1464. MLLoadStringW(IDS_SAVING_STATUS_TEXT, wzArchiveText,
  1465. ARRAYSIZE(wzArchiveText));
  1466. StringCchPrintf(wzBuf, ARRAYSIZE(wzBuf), L"%ws: %ws", wzArchiveText, bstrDocURL);
  1467. m_ptp->SetSaveText(wzBuf);
  1468. if (fFrameDoc)
  1469. {
  1470. CHAR szURL[INTERNET_MAX_URL_LENGTH];
  1471. LPSTR lpszCID = NULL;
  1472. DWORD dwAttach = URL_ATTACH_SET_CNTTYPE;
  1473. szURL[0] = 0;
  1474. if (WideCharToMultiByte(CP_ACP, 0, bstrDocURL, -1, szURL, INTERNET_MAX_URL_LENGTH, NULL, NULL))
  1475. {
  1476. hr = m_pimm->AttachURL(NULL, szURL, dwAttach,
  1477. pstm, &lpszCID, &hBody);
  1478. if (SUCCEEDED(hr) && cpDoc)
  1479. {
  1480. IMimeBody *pBody = NULL;
  1481. hr = m_pimm->BindToObject(hBody, IID_IMimeBody,
  1482. (LPVOID *)&pBody);
  1483. if (SUCCEEDED(hr))
  1484. {
  1485. hr = SetCharset(cpDoc, CSET_APPLY_TAG_ALL, pBody);
  1486. }
  1487. pBody->Release();
  1488. }
  1489. if (SUCCEEDED(hr))
  1490. {
  1491. CHashEntry *phe;
  1492. LPWSTR pwz = NULL;
  1493. int iLen = 0;
  1494. // If it is ASP, it is actually HTML
  1495. iLen = lstrlenW(bstrDocURL);
  1496. if (iLen) {
  1497. pwz = StrRChrW(bstrDocURL, bstrDocURL + iLen, L'.');
  1498. }
  1499. if (pwz && !StrCmpIW(pwz, TEXT(".asp")))
  1500. {
  1501. PROPVARIANT propvar;
  1502. PropVariantClear(&propvar);
  1503. propvar.vt = VT_LPSTR;
  1504. propvar.pszVal = "text/html";
  1505. hr = m_pimm->SetBodyProp(hBody,
  1506. PIDTOSTR(PID_HDR_CNTTYPE),
  1507. 0, &propvar);
  1508. }
  1509. if ( m_hBodyAlt == NULL )
  1510. m_hBodyAlt = hBody;
  1511. // update the place-holder hash entry
  1512. hr = Find( bstrDocURL, &phe);
  1513. if (SUCCEEDED(hr))
  1514. {
  1515. ASSERT(phe != NULL);
  1516. phe->SetValue( bstrDocURL );
  1517. }
  1518. }
  1519. }
  1520. else
  1521. hr = HRESULT_FROM_WIN32(GetLastError());
  1522. }
  1523. else
  1524. {
  1525. hr = m_pimm->SetTextBody( TXT_HTML, IET_INETCSET, m_hBodyAlt, pstm, &hBody);
  1526. // The main text was the last thing we were waiting for
  1527. if (SUCCEEDED(hr) && cpDoc)
  1528. {
  1529. IMimeBody *pBody = NULL;
  1530. hr = m_pimm->BindToObject(hBody, IID_IMimeBody,
  1531. (LPVOID *)&pBody);
  1532. if (SUCCEEDED(hr))
  1533. {
  1534. hr = SetCharset(cpDoc, CSET_APPLY_TAG_ALL, pBody);
  1535. }
  1536. pBody->Release();
  1537. }
  1538. if (SUCCEEDED(hr))
  1539. {
  1540. IPersistFile *pipf = NULL;
  1541. // Initialzie PropVariant
  1542. PROPVARIANT rVariant;
  1543. rVariant.vt = VT_LPWSTR;
  1544. rVariant.pwszVal = (LPWSTR)bstrDocURL;
  1545. // Add a content location, so we can use it for security later.
  1546. hr = m_pimm->SetBodyProp( hBody, STR_HDR_CNTLOC, 0, &rVariant );
  1547. if (SUCCEEDED(hr))
  1548. {
  1549. hr = m_pimm->QueryInterface(IID_IPersistFile, (LPVOID *)&pipf);
  1550. if (SUCCEEDED(hr))
  1551. {
  1552. LPWSTR lpwszFile;
  1553. lpwszFile = m_lpstrDoc;
  1554. hr = pipf->Save(lpwszFile, FALSE);
  1555. SAFERELEASE(pipf);
  1556. }
  1557. }
  1558. ReleaseInterface(pstm);
  1559. }
  1560. }
  1561. if ( bstrDocURL )
  1562. {
  1563. // Restore Bookmark
  1564. RestoreBookMark(pwzBookMark);
  1565. SysFreeString(bstrDocURL);
  1566. }
  1567. }
  1568. ReleaseInterface(pstm);
  1569. }
  1570. }
  1571. ReleaseInterface(ppsi);
  1572. Exit:
  1573. RRETURN(hr);
  1574. }
  1575. HRESULT
  1576. CMHTMLArchive::ArchiveCSSText( BSTR bstrCSSUrl, LPCSTR lpszSSText, LPCTSTR lpszStyleDoc )
  1577. {
  1578. HRESULT hr;
  1579. BSTR bstrDocURL = NULL;
  1580. CHAR szURL[INTERNET_MAX_URL_LENGTH];
  1581. LPSTR lpszCID = NULL;
  1582. DWORD dwAttach = URL_ATTACH_SET_CNTTYPE;
  1583. HBODY hBody;
  1584. IStream *pstm = NULL;
  1585. ULONG cbWrite, cbWritten;
  1586. hr = MimeOleCreateVirtualStream( &pstm );
  1587. if (FAILED(hr))
  1588. return hr;
  1589. cbWrite = lstrlenA(lpszSSText);
  1590. pstm->Write(lpszSSText, cbWrite, &cbWritten);
  1591. ASSERT(cbWritten==cbWrite);
  1592. //if (dwFlags & MECD_CNTLOCATIONS)
  1593. // dwAttach |= URL_ATTACH_SET_CNTLOCATION;
  1594. szURL[0] = 0;
  1595. if (WideCharToMultiByte(CP_ACP, 0, bstrCSSUrl, -1, szURL, INTERNET_MAX_URL_LENGTH, NULL, NULL))
  1596. {
  1597. hr = m_pimm->AttachURL(NULL, szURL, dwAttach,
  1598. pstm, &lpszCID, &hBody);
  1599. if (SUCCEEDED(hr))
  1600. {
  1601. CHashEntry *phe;
  1602. // update the place-holder hash entry
  1603. hr = Find(bstrCSSUrl, &phe);
  1604. ASSERT(SUCCEEDED(hr) && phe != NULL);
  1605. phe->SetValue( bstrCSSUrl );
  1606. }
  1607. }
  1608. else
  1609. hr = HRESULT_FROM_WIN32(GetLastError());
  1610. ReleaseInterface(pstm);
  1611. return hr;
  1612. }
  1613. HRESULT CMHTMLArchive::SetCharset(UINT uiCharset, CSETAPPLYTYPE csat,
  1614. IMimeBody *pBody)
  1615. {
  1616. HRESULT hr = E_FAIL;
  1617. HCHARSET hCharset;
  1618. IMimeInternational *pimi = NULL;
  1619. hr = CoCreateInstance(CLSID_IMimeInternational,
  1620. NULL, CLSCTX_INPROC_SERVER,
  1621. IID_IMimeInternational, (LPVOID*)&pimi);
  1622. if (SUCCEEDED(hr))
  1623. {
  1624. hr = pimi->GetCodePageCharset(uiCharset, CHARSET_WEB, &hCharset);
  1625. }
  1626. if (SUCCEEDED(hr))
  1627. {
  1628. hr = pBody->SetCharset(hCharset, csat);
  1629. }
  1630. if (pimi)
  1631. {
  1632. pimi->Release();
  1633. }
  1634. return hr;
  1635. }
  1636. /*
  1637. * CThicketProgress ##################################################
  1638. */
  1639. CThicketProgress::CThicketProgress( HWND hDlg )
  1640. {
  1641. TCHAR szFmt[MAX_PATH];
  1642. int cchPctFmt;
  1643. m_hDlg = hDlg;
  1644. m_hwndProg = GetDlgItem(hDlg, IDC_THICKETPROGRESS);
  1645. MLLoadString(IDS_THICKETSAVINGFMT, szFmt, ARRAYSIZE(szFmt) );
  1646. m_cchSavingFmt = lstrlen(szFmt);
  1647. m_pszSavingFmt = new TCHAR[m_cchSavingFmt+1];
  1648. if (m_pszSavingFmt != NULL)
  1649. {
  1650. StringCchCopy( m_pszSavingFmt, m_cchSavingFmt+1, szFmt);
  1651. }
  1652. MLLoadString(IDS_THICKETPCTFMT, szFmt, ARRAYSIZE(szFmt));
  1653. cchPctFmt = lstrlen(szFmt);
  1654. m_pszPctFmt = new TCHAR[cchPctFmt+1];
  1655. if (m_pszPctFmt != NULL)
  1656. {
  1657. StringCchCopy(m_pszPctFmt, cchPctFmt+1, szFmt);
  1658. }
  1659. m_ulPct = 0;
  1660. }
  1661. CThicketProgress::~CThicketProgress(void)
  1662. {
  1663. if (m_pszSavingFmt)
  1664. delete[] m_pszSavingFmt;
  1665. if (m_pszPctFmt)
  1666. delete[] m_pszPctFmt;
  1667. }
  1668. void CThicketProgress::SetPercent( ULONG ulPct )
  1669. {
  1670. TCHAR szBuf[MAX_PATH];
  1671. szBuf[0] = TEXT('\0');
  1672. if ( ulPct > 100 )
  1673. ulPct = 100;
  1674. if ( ulPct > m_ulPct ) // prevent retrograde motion.
  1675. {
  1676. m_ulPct = ulPct;
  1677. if (m_pszPctFmt != NULL)
  1678. {
  1679. StringCchPrintf( szBuf, ARRAYSIZE(szBuf), m_pszPctFmt, m_ulPct );
  1680. }
  1681. SetDlgItemText(m_hDlg, IDC_THICKETPCT, szBuf);
  1682. SendMessage(m_hwndProg, PBM_SETPOS, m_ulPct, 0);
  1683. }
  1684. }
  1685. void CThicketProgress::SetSaving( LPCTSTR szFile, LPCTSTR szDst )
  1686. {
  1687. TCHAR szPath[30];
  1688. TCHAR szBuf[MAX_PATH*2];
  1689. LPCTSTR psz;
  1690. szBuf[0] = TEXT('\0');
  1691. if (PathCompactPathEx( szPath, szDst, 30, 0 ))
  1692. {
  1693. psz = szPath;
  1694. }
  1695. else
  1696. {
  1697. psz = szDst;
  1698. }
  1699. if (m_pszSavingFmt != NULL)
  1700. {
  1701. StringCchPrintf( szBuf, ARRAYSIZE(szBuf), m_pszSavingFmt, szFile, psz );
  1702. }
  1703. SetDlgItemText(m_hDlg, IDC_THICKETSAVING, szBuf);
  1704. }
  1705. void CThicketProgress::SetSaveText(LPCTSTR szText)
  1706. {
  1707. if (szText)
  1708. {
  1709. SetDlgItemText(m_hDlg, IDC_THICKETSAVING, szText);
  1710. }
  1711. }
  1712. /*
  1713. * CCollectionPackager ##################################################
  1714. */
  1715. CCollectionPackager::~CCollectionPackager(void)
  1716. {
  1717. if (m_pColl)
  1718. m_pColl->Release();
  1719. }
  1720. HRESULT CCollectionPackager::_GetElementURL(IHTMLElement *pElem, BSTR *pbstrURL)
  1721. {
  1722. HRESULT hr;
  1723. VARIANT rVar;
  1724. ASSERT (pElem);
  1725. rVar.vt = VT_BSTR;
  1726. // Note that _GetTargetAttribute is a virtual method, so the derived class
  1727. // specifies what attribute to fetch.
  1728. hr = THR(pElem->getAttribute(_GetTargetAttribute(), VARIANT_FALSE, &rVar));
  1729. if (SUCCEEDED(hr))
  1730. {
  1731. if (rVar.vt == VT_BSTR && rVar.bstrVal != NULL)
  1732. *pbstrURL = rVar.bstrVal;
  1733. else
  1734. hr = S_FALSE;
  1735. }
  1736. return hr; // no RRETURN - may return S_FALSE
  1737. }
  1738. HRESULT CCollectionPackager::_PackageData(CWebArchive *pwa,
  1739. IHTMLElementCollection *pColl,
  1740. BOOL *pfCancel,
  1741. CThicketProgress *ptp, ULONG progLow, ULONG progHigh)
  1742. {
  1743. HRESULT hr = S_OK;
  1744. ULONG uElem,
  1745. cElems,
  1746. uRange = progHigh - progLow;
  1747. IHTMLElement *pElem;
  1748. cElems = UlGetCollectionCount(pColl);
  1749. // Iterate over the collection, packaging each element in turn.
  1750. for (uElem=0; uElem<cElems && SUCCEEDED(hr) ; uElem++)
  1751. {
  1752. hr = THR(HrGetCollectionItem(pColl, uElem, IID_IHTMLElement, (LPVOID *)&pElem));
  1753. if (SUCCEEDED(hr))
  1754. {
  1755. hr = _PackageElement(pwa, pElem ); // no THR - may return S_FALSE
  1756. pElem->Release();
  1757. }
  1758. if (pfCancel && *pfCancel)
  1759. hr = E_ABORT;
  1760. if (ptp && uRange)
  1761. ptp->SetPercent( progLow + (uRange * uElem) / cElems );
  1762. }
  1763. return hr; // no RRETURN - may return S_FALSE
  1764. }
  1765. HRESULT CCollectionPackager::_PackageElement(CWebArchive *pwa,
  1766. IHTMLElement *pElem)
  1767. {
  1768. HRESULT hr = S_OK;
  1769. BSTR bstrURL = NULL;
  1770. BOOL fBadLinks=FALSE;
  1771. CHashEntry *phe;
  1772. hr = _GetElementURL(pElem, &bstrURL);
  1773. if (hr == S_OK && bstrURL && bstrURL[0])
  1774. {
  1775. // PTH hr = HrAddImageToMessage(pMsgSrc, pMsgDst, pHash, bstrURL, &bstrURLThicket, m_fAddCntLoc);
  1776. hr = pwa->AddURL( bstrURL, &phe );
  1777. if (SUCCEEDED(hr))
  1778. {
  1779. hr = THR(HrSetMember(pElem, _GetTargetAttribute(), phe->m_bstrValue));
  1780. }
  1781. else
  1782. hr = THR(HrSetMember(pElem, _GetTargetAttribute(), c_bstr_EMPTY));
  1783. }
  1784. if (bstrURL)
  1785. SysFreeString(bstrURL);
  1786. return hr;
  1787. }
  1788. HRESULT CCollectionPackager::_InitSubCollection(IHTMLElementCollection *pAll,
  1789. BSTR bstrTagName,
  1790. IHTMLElementCollection **ppSub,
  1791. ULONG *pcElems)
  1792. {
  1793. IDispatch *pDisp=NULL;
  1794. VARIANT TagName;
  1795. HRESULT hr = S_FALSE;
  1796. ASSERT (ppSub);
  1797. ASSERT(pAll);
  1798. *ppSub = NULL;
  1799. TagName.vt = VT_BSTR;
  1800. TagName.bstrVal = bstrTagName;
  1801. if (NULL == TagName.bstrVal)
  1802. hr = E_INVALIDARG;
  1803. else
  1804. {
  1805. hr = pAll->tags(TagName, &pDisp);
  1806. }
  1807. if (pDisp)
  1808. {
  1809. hr = pDisp->QueryInterface(IID_IHTMLElementCollection,
  1810. (void **)ppSub);
  1811. pDisp->Release();
  1812. }
  1813. if (pcElems)
  1814. {
  1815. if (hr == S_OK)
  1816. *pcElems = UlGetCollectionCount(*ppSub);
  1817. else
  1818. *pcElems = 0;
  1819. }
  1820. RRETURN(hr);
  1821. }
  1822. /*
  1823. * CImagePackager ##################################################
  1824. */
  1825. HRESULT CImagePackager::InitFromCollection(IHTMLElementCollection *pColl,
  1826. ULONG *pcElems)
  1827. {
  1828. return _InitSubCollection(pColl, (BSTR)c_bstr_IMG, &m_pColl, pcElems);
  1829. }
  1830. BSTR CImagePackager::_GetTargetAttribute(void)
  1831. {
  1832. return (BSTR)c_bstr_SRC;
  1833. }
  1834. /*
  1835. * CInputImgPackager ##################################################
  1836. */
  1837. HRESULT CInputImgPackager::InitFromCollection(IHTMLElementCollection *pColl,
  1838. ULONG *pcElems)
  1839. {
  1840. return _InitSubCollection(pColl, (BSTR)c_bstr_INPUT, &m_pColl, pcElems);
  1841. }
  1842. /*
  1843. * CBGSoundsPackager ##################################################
  1844. */
  1845. HRESULT CBGSoundsPackager::InitFromCollection(IHTMLElementCollection *pColl,
  1846. ULONG *pcElems)
  1847. {
  1848. return _InitSubCollection(pColl, (BSTR)c_bstr_BGSOUND, &m_pColl, pcElems);
  1849. }
  1850. BSTR CBGSoundsPackager::_GetTargetAttribute(void)
  1851. {
  1852. return (BSTR)c_bstr_SRC;
  1853. }
  1854. /*
  1855. * CAnchorAdjustor ##################################################
  1856. */
  1857. HRESULT CAnchorAdjustor::InitFromCollection(IHTMLElementCollection *pColl,
  1858. ULONG *pcElems)
  1859. {
  1860. return _InitSubCollection(pColl, (BSTR)c_bstr_ANCHOR, &m_pColl, pcElems);
  1861. }
  1862. BSTR CAnchorAdjustor::_GetTargetAttribute(void)
  1863. {
  1864. return (BSTR)c_bstr_HREF;
  1865. }
  1866. HRESULT CAnchorAdjustor::_PackageElement(CWebArchive *pwa,
  1867. IHTMLElement *pElem)
  1868. {
  1869. HRESULT hr = S_OK;
  1870. BSTR bstrURL = NULL;
  1871. BSTR bstrThicket = NULL;
  1872. BOOL fBadLinks=FALSE;
  1873. CHashEntry *phe;
  1874. // leave intra-doc urls and <A name=> alone
  1875. // seanf(2/11/98) : haven't seen a local # link come through here yet.
  1876. hr = _GetElementURL(pElem, &bstrURL);
  1877. if (hr != S_OK || bstrURL == NULL || bstrURL[0] == '#' || bstrURL[0] == 0)
  1878. goto error;
  1879. // See if the target is something we have in the thicket, like an <A> in frame A
  1880. // targetting the page saved for frame B.
  1881. ASSERT(pwa);
  1882. hr = pwa->Find(bstrURL, &phe);
  1883. if (SUCCEEDED(hr))
  1884. bstrThicket = phe->m_bstrValue;
  1885. else
  1886. {
  1887. // not in the thicket, so make both URLs the same.
  1888. bstrThicket = bstrURL;
  1889. hr = S_OK;
  1890. }
  1891. if (hr == S_OK)
  1892. hr = THR(HrSetMember(pElem, _GetTargetAttribute(), bstrThicket));
  1893. error:
  1894. if (bstrURL)
  1895. SysFreeString(bstrURL);
  1896. // don't free bstrThicket, its either bstrURL, or belongs to the thicket hash table.
  1897. return hr;
  1898. }
  1899. /*
  1900. * CAreaAdjustor ##################################################
  1901. */
  1902. HRESULT CAreaAdjustor::InitFromCollection(IHTMLElementCollection *pColl,
  1903. ULONG *pcElems)
  1904. {
  1905. return _InitSubCollection(pColl, (BSTR)c_bstr_AREA, &m_pColl, pcElems);
  1906. }
  1907. /*
  1908. * CBaseNeutralizer ##################################################
  1909. */
  1910. CBaseNeutralizer::~CBaseNeutralizer(void)
  1911. {
  1912. if (m_bstrLocal)
  1913. SysFreeString(m_bstrLocal);
  1914. if (m_pTree)
  1915. m_pTree->Release();
  1916. }
  1917. HRESULT CBaseNeutralizer::InitFromCollection(IHTMLElementCollection *pColl,
  1918. ULONG *pcElems,
  1919. IHTMLDocument2 *pDoc )
  1920. {
  1921. if ( pDoc != NULL )
  1922. {
  1923. if ( m_pTree )
  1924. {
  1925. m_pTree->Release();
  1926. m_pTree = NULL;
  1927. }
  1928. pDoc->QueryInterface(IID_IMarkupServices, (void**)&m_pTree);
  1929. }
  1930. return _InitSubCollection(pColl, (BSTR)c_bstr_BASE, &m_pColl, pcElems);
  1931. }
  1932. BSTR CBaseNeutralizer::_GetTargetAttribute(void)
  1933. {
  1934. return (BSTR)c_bstr_HREF;
  1935. }
  1936. HRESULT CBaseNeutralizer::PackageData(CWebArchive *pwa, BOOL *pfCancel,
  1937. CThicketProgress *ptp,
  1938. ULONG progLow, ULONG progHigh)
  1939. {
  1940. HRESULT hr = S_OK;
  1941. ULONG uElem,
  1942. cElems,
  1943. uRange = progHigh - progLow;
  1944. IHTMLElement *pElem;
  1945. cElems = UlGetCollectionCount(m_pColl);
  1946. // Iterate over the collection, packaging each element in turn.
  1947. for (uElem=0; uElem<cElems && SUCCEEDED(hr) ; uElem++)
  1948. {
  1949. hr = THR(HrGetCollectionItem(m_pColl, 0, IID_IHTMLElement, (LPVOID *)&pElem));
  1950. if (SUCCEEDED(hr))
  1951. {
  1952. hr = _PackageElement(pwa, pElem ); // no THR - may return S_FALSE
  1953. pElem->Release();
  1954. }
  1955. if (pfCancel && *pfCancel)
  1956. hr = E_ABORT;
  1957. if (ptp && uRange)
  1958. ptp->SetPercent( progLow + (uRange * uElem) / cElems );
  1959. }
  1960. return hr; // no RRETURN - may return S_FALSE
  1961. }
  1962. HRESULT CBaseNeutralizer::_PackageElement(CWebArchive *pwa,
  1963. IHTMLElement *pElem)
  1964. {
  1965. HRESULT hr = S_FALSE;
  1966. // NOTE: There's seems to be no retouching that will make this work.
  1967. // Tried setting BASE to ".", ".\", "". It has to be absolute,
  1968. // which would anchor the thicket to one location in the file
  1969. // system. The solution here is to use the base to fix the
  1970. // other rel URLs in the doc, then whack the base tags.
  1971. if ( m_pTree )
  1972. {
  1973. //OLD NOTE: Tree Services can't remove a head element yet, so
  1974. // wait to enable this pending Joe Beda/EricVas work.
  1975. hr = m_pTree->RemoveElement( pElem );
  1976. }
  1977. return hr; // no RRETURN - may return S_FALSE
  1978. }
  1979. /*
  1980. * CRelativeURLPackager ##################################################
  1981. */
  1982. CRelativeURLPackager::~CRelativeURLPackager(void)
  1983. {
  1984. if (m_pCollBase)
  1985. m_pCollBase->Release();
  1986. if (m_bstrDocURL)
  1987. SysFreeString(m_bstrDocURL);
  1988. }
  1989. HRESULT CRelativeURLPackager::Init(IHTMLElementCollection *pColl,
  1990. ULONG *pcElems,
  1991. IHTMLDocument2 *pDoc)
  1992. {
  1993. HRESULT hr = S_OK;
  1994. // Hold on to the outer collection, we'll subsample it later.
  1995. m_pColl = pColl;
  1996. if (m_pColl)
  1997. {
  1998. m_pColl->AddRef();
  1999. hr = _InitSubCollection( m_pColl, (BSTR)c_bstr_BASE, &m_pCollBase, &m_cBase );
  2000. }
  2001. if (SUCCEEDED(hr) && pDoc)
  2002. {
  2003. hr = pDoc->get_URL( &m_bstrDocURL );
  2004. }
  2005. RRETURN(hr);
  2006. }
  2007. HRESULT CRelativeURLPackager::_GetElementURL(IHTMLElement *pElem, BSTR *pbstrURL)
  2008. {
  2009. HRESULT hr = S_FALSE;
  2010. LONG lElemPos;
  2011. BSTR bstr = NULL;
  2012. ASSERT (pbstrURL);
  2013. *pbstrURL = 0;
  2014. hr = CCollectionPackager::_GetElementURL(pElem, &bstr);
  2015. if (hr==S_OK)
  2016. {
  2017. if (bstr==NULL)
  2018. hr = S_FALSE;
  2019. else
  2020. {
  2021. hr = pElem->get_sourceIndex(&lElemPos);
  2022. ASSERT(SUCCEEDED(hr));
  2023. hr = HrGetCombinedURL(m_pCollBase, m_cBase, lElemPos, bstr, m_bstrDocURL, pbstrURL);
  2024. SysFreeString(bstr);
  2025. }
  2026. }
  2027. return hr; // no RRETURN - may return S_FALSE
  2028. }
  2029. /*
  2030. * CBackgroundPackager ##################################################
  2031. */
  2032. HRESULT CBackgroundPackager::PackageData(CWebArchive *pwa,
  2033. BOOL *pfCancel,
  2034. CThicketProgress *ptp, ULONG progLow, ULONG progHigh)
  2035. {
  2036. HRESULT hr = S_OK;
  2037. IHTMLElementCollection *pColl = NULL;
  2038. hr = _InitSubCollection(m_pColl, (BSTR)c_bstr_BODY, &pColl);
  2039. if (SUCCEEDED(hr))
  2040. {
  2041. if (hr==S_OK)
  2042. hr = _PackageData( pwa, pColl, pfCancel );
  2043. if (FAILED(hr))
  2044. goto error;
  2045. pColl->Release();
  2046. pColl = NULL;
  2047. }
  2048. hr = _InitSubCollection(m_pColl, (BSTR)c_bstr_TABLE, &pColl);
  2049. if (SUCCEEDED(hr))
  2050. {
  2051. if (hr==S_OK)
  2052. hr = _PackageData( pwa, pColl, pfCancel);
  2053. if (FAILED(hr))
  2054. goto error;
  2055. pColl->Release();
  2056. pColl = NULL;
  2057. }
  2058. hr = _InitSubCollection(m_pColl, (BSTR)c_bstr_TD, &pColl);
  2059. if (SUCCEEDED(hr))
  2060. {
  2061. if (hr==S_OK)
  2062. hr = _PackageData( pwa, pColl, pfCancel );
  2063. if (FAILED(hr))
  2064. goto error;
  2065. pColl->Release();
  2066. pColl = NULL;
  2067. }
  2068. hr = _InitSubCollection(m_pColl, (BSTR)c_bstr_TH, &pColl);
  2069. if (SUCCEEDED(hr))
  2070. {
  2071. if (hr==S_OK)
  2072. hr = _PackageData( pwa, pColl, pfCancel );
  2073. if (FAILED(hr))
  2074. goto error;
  2075. pColl->Release();
  2076. pColl = NULL;
  2077. }
  2078. error:
  2079. if (pColl)
  2080. pColl->Release();
  2081. return hr; // no RRETURN - may return S_FALSE
  2082. }
  2083. BSTR CBackgroundPackager::_GetTargetAttribute(void)
  2084. {
  2085. return (BSTR)c_bstr_BACKGROUND;
  2086. }
  2087. /*
  2088. * CDynSrcPackager ##################################################
  2089. */
  2090. HRESULT CDynSrcPackager::PackageData(CWebArchive *pwa,
  2091. BOOL *pfCancel,
  2092. CThicketProgress *ptp, ULONG progLow, ULONG progHigh)
  2093. {
  2094. HRESULT hr = S_OK;
  2095. IHTMLElementCollection *pColl = NULL;
  2096. hr = _InitSubCollection(m_pColl, (BSTR)c_bstr_IMG, &pColl);
  2097. if (SUCCEEDED(hr))
  2098. {
  2099. if (hr==S_OK)
  2100. hr = _PackageData( pwa, pColl, pfCancel );
  2101. if (FAILED(hr))
  2102. goto error;
  2103. pColl->Release();
  2104. pColl = NULL;
  2105. }
  2106. hr = _InitSubCollection(m_pColl, (BSTR)c_bstr_INPUT, &pColl);
  2107. if (SUCCEEDED(hr))
  2108. {
  2109. if (hr==S_OK)
  2110. hr = _PackageData( pwa, pColl, pfCancel );
  2111. if (FAILED(hr))
  2112. goto error;
  2113. pColl->Release();
  2114. pColl = NULL;
  2115. }
  2116. error:
  2117. if (pColl)
  2118. pColl->Release();
  2119. return hr; // no RRETURN - may return S_FALSE
  2120. }
  2121. BSTR CDynSrcPackager::_GetTargetAttribute(void)
  2122. {
  2123. return (BSTR)c_bstr_DYNSRC;
  2124. }
  2125. /*
  2126. * CScriptPackager ##################################################
  2127. */
  2128. HRESULT CScriptPackager::Init(IHTMLElementCollection *pColl,
  2129. ULONG *pcElems,
  2130. IHTMLDocument2 *pDoc)
  2131. {
  2132. HRESULT hr = CRelativeURLPackager::Init(pColl, NULL, pDoc);
  2133. if (SUCCEEDED(hr))
  2134. hr = _InitSubCollection(m_pColl, (BSTR)c_bstr_SCRIPT, &m_pCollScripts, pcElems );
  2135. return hr;
  2136. }
  2137. BSTR CScriptPackager::_GetTargetAttribute(void)
  2138. {
  2139. return (BSTR)c_bstr_SRC;
  2140. }
  2141. /*
  2142. * CFramesPackager ##################################################
  2143. */
  2144. HRESULT CFramesPackager::Init(IHTMLElementCollection *pColl,
  2145. ULONG *pcElems,
  2146. IHTMLDocument2 *pDoc,
  2147. IHTMLDocument2 *pDocDesign,
  2148. CDocumentPackager *pdp)
  2149. {
  2150. HRESULT hr = CRelativeURLPackager::Init(pColl, NULL, pDocDesign);
  2151. if (SUCCEEDED(hr))
  2152. {
  2153. m_pdp = pdp;
  2154. // Get the element collection for the frames.
  2155. // Note: If documents have frames, they are either all
  2156. // <FRAME>s _OR_ all <IFRAME>s.
  2157. hr = _InitSubCollection(m_pColl, (BSTR)c_bstr_FRAME, &m_pCollFrames, &m_cFrames);
  2158. if (FAILED(hr) || m_cFrames == 0)
  2159. {
  2160. if (m_pCollFrames)
  2161. m_pCollFrames->Release();
  2162. hr = _InitSubCollection(m_pColl, (BSTR)c_bstr_IFRAME, &m_pCollFrames, &m_cFrames);
  2163. }
  2164. if (pcElems)
  2165. *pcElems = m_cFrames;
  2166. // To traverse a framseset that spans multiple domains, we need to approach it
  2167. // via the "unsecured" window object, which is only accessible via Invoke.
  2168. if (SUCCEEDED(hr) && m_cFrames > 0)
  2169. {
  2170. DISPPARAMS dispparams;
  2171. VARIANT VarResult;
  2172. VariantInit(&VarResult);
  2173. ZeroMemory(&dispparams, sizeof(dispparams));
  2174. hr = pDoc->Invoke(DISPID_WINDOWOBJECT,
  2175. IID_NULL,
  2176. 0,
  2177. DISPATCH_PROPERTYGET,
  2178. &dispparams,
  2179. &VarResult,
  2180. NULL,
  2181. NULL );
  2182. if( SUCCEEDED(hr) )
  2183. {
  2184. // Code in iedisp.cpp's GetDelegateOnIDispatch was really paranoid about this,
  2185. // so we'll be similarly cautious.
  2186. if( (VarResult.vt == VT_DISPATCH || VarResult.vt == VT_UNKNOWN)
  2187. && VarResult.pdispVal )
  2188. {
  2189. IHTMLWindow2 *pwin2 = NULL;
  2190. hr = VarResult.pdispVal->QueryInterface( IID_IHTMLWindow2, (LPVOID*)&pwin2);
  2191. if (SUCCEEDED(hr))
  2192. {
  2193. hr = pwin2->get_frames(&m_pframes2);
  2194. pwin2->Release();
  2195. }
  2196. } // if we really got an interface
  2197. else
  2198. hr = E_FAIL;
  2199. VariantClearLazy( &VarResult );
  2200. } // if we can get the un-secured window object
  2201. } // if we have frames
  2202. } // if base initialization succeeded
  2203. return hr;
  2204. }
  2205. HRESULT CFramesPackager::PackageData(CWebArchive *pwa,
  2206. BOOL *pfCancel,
  2207. CThicketProgress *ptp, ULONG progLow, ULONG progHigh)
  2208. {
  2209. HRESULT hr = S_OK;
  2210. //ULONG cColl = 0;
  2211. if (m_cFrames == 0)
  2212. return S_OK; // Trident will get confused if we return a non-S_OK success code
  2213. m_iFrameCur = 0; // index of frame in window.frames and all.tags("FRAME");
  2214. m_pfCancel = pfCancel;
  2215. m_ptp = ptp;
  2216. m_uLow = progLow;
  2217. m_uHigh = progHigh;
  2218. m_uRangeDoc = (progHigh - progLow) / m_cFrames;
  2219. hr = _PackageData( pwa, m_pCollFrames, pfCancel );
  2220. return hr; // no RRETURN - may return S_FALSE
  2221. }
  2222. BSTR CFramesPackager::_GetTargetAttribute(void)
  2223. {
  2224. return (BSTR)c_bstr_SRC;
  2225. }
  2226. HRESULT CFramesPackager::_PackageElement(CWebArchive *pwa,
  2227. IHTMLElement *pElem)
  2228. {
  2229. HRESULT hr = S_OK;
  2230. BSTR bstrURL = NULL;
  2231. BOOL fBadLinks=FALSE;
  2232. IHTMLDocument2 *pDocFrame = NULL;
  2233. //IWebBrowser *pwb = NULL;
  2234. IDispatch *pDisp = NULL;
  2235. IHTMLWindow2 *pwin2 = NULL;
  2236. VARIANT varIndex;
  2237. VARIANT varFrame;
  2238. WCHAR *pwzBookMark = NULL;
  2239. ASSERT(pElem);
  2240. ASSERT(pwa);
  2241. varIndex.vt = VT_I4;
  2242. varIndex.lVal = m_iFrameCur;
  2243. hr = m_pframes2->item( &varIndex, &varFrame );
  2244. if (FAILED(hr))
  2245. goto error;
  2246. // The variant should give us an IHTMLWindow2, but we'll treat it as a Disp anyway
  2247. ASSERT(varFrame.vt & VT_DISPATCH);
  2248. pDisp = varFrame.pdispVal;
  2249. hr = pDisp->QueryInterface(IID_IHTMLWindow2, (LPVOID*)&pwin2 );
  2250. if (FAILED(hr))
  2251. goto error;
  2252. hr = pwin2->get_document(&pDocFrame);
  2253. #ifdef OLD_THICKET
  2254. hr = pElem->QueryInterface(IID_IWebBrowser, (void**)&pwb);
  2255. if (FAILED(hr))
  2256. goto error;
  2257. hr = pwb->get_Document( &pDisp );
  2258. if (FAILED(hr))
  2259. goto error;
  2260. else if ( pDisp == NULL )
  2261. {
  2262. hr = S_FALSE;
  2263. goto error;
  2264. }
  2265. hr = pDisp->QueryInterface(IID_IHTMLDocument2, (void**)&pDocFrame);
  2266. if (FAILED(hr))
  2267. goto error;
  2268. #endif // OLD_THICKET
  2269. if (SUCCEEDED(hr) && SUCCEEDED(pDocFrame->get_URL(&bstrURL)) && bstrURL && bstrURL[0])
  2270. {
  2271. TCHAR szFrameDoc[MAX_PATH];
  2272. CHashEntry *phe;
  2273. RemoveBookMark(bstrURL, &pwzBookMark);
  2274. hr = pwa->AddFrameOrStyleEntry( bstrURL, &phe, szFrameDoc );
  2275. if (hr==S_OK)
  2276. {
  2277. ULONG uLowDoc = m_uLow + m_iFrameCur * m_uRangeDoc;
  2278. ULONG uHighDoc = uLowDoc + m_uRangeDoc;
  2279. CWebArchive *pwaFrame = m_pdp->GetFrameDocArchive( pwa );
  2280. if ( pwaFrame != NULL )
  2281. {
  2282. BSTR bstrCharSetSrc = NULL;
  2283. MIMECSETINFO csetInfo;
  2284. IMultiLanguage2 *pMultiLanguage = NULL;
  2285. hr = pDocFrame->get_charset(&bstrCharSetSrc);
  2286. if (FAILED(hr))
  2287. goto error;
  2288. hr = CoCreateInstance(CLSID_CMultiLanguage, NULL, CLSCTX_INPROC_SERVER,
  2289. IID_IMultiLanguage2, (void**)&pMultiLanguage);
  2290. if (FAILED(hr))
  2291. {
  2292. goto error;
  2293. }
  2294. hr = pMultiLanguage->GetCharsetInfo(bstrCharSetSrc, &csetInfo);
  2295. pMultiLanguage->Release();
  2296. if (FAILED(hr))
  2297. {
  2298. goto error;
  2299. }
  2300. hr = m_pdp->_PackageDocument(pDocFrame, szFrameDoc, m_pfCancel, m_ptp,
  2301. uLowDoc, uHighDoc, csetInfo.uiInternetEncoding,
  2302. pwaFrame, m_pdp, TRUE );
  2303. if (SUCCEEDED(hr))
  2304. hr = THR(HrSetMember(pElem, _GetTargetAttribute(), phe->m_bstrValue));
  2305. else
  2306. fBadLinks = TRUE;
  2307. if ( pwaFrame != pwa ) // only delete if new one was made (thicket)
  2308. delete pwaFrame;
  2309. }
  2310. else
  2311. hr = E_OUTOFMEMORY;
  2312. } // if the location matched the element URL
  2313. else if (hr==S_FALSE)
  2314. {
  2315. // This is a repeat - we don't need to do most of the work, but we
  2316. // do need to record the element for remapping.
  2317. hr = THR(HrSetMember(pElem, _GetTargetAttribute(), phe->m_bstrValue));
  2318. }
  2319. } // if we got the frame's doc's URL
  2320. else // if ( hr == DISP_E_MEMBERNOTFOUND ) // frame is non-trident docobj
  2321. {
  2322. IHTMLLocation *ploc = NULL;
  2323. // For a non-trident doc-obj, get the file, if possible, and put it in the thicket.
  2324. hr = pwin2->get_location( &ploc );
  2325. if (SUCCEEDED(hr) &&
  2326. SUCCEEDED(hr = ploc->get_href( &bstrURL )))
  2327. {
  2328. if (bstrURL && bstrURL[0])
  2329. {
  2330. CHashEntry *phe;
  2331. // PTH hr = HrAddImageToMessage(pMsgSrc, pMsgDst, pHash, bstrURL, &bstrURLThicket, m_fAddCntLoc);
  2332. hr = pwa->AddURL( bstrURL, &phe );
  2333. if (!FAILED(hr))
  2334. {
  2335. hr = THR(HrSetMember(pElem, _GetTargetAttribute(), phe->m_bstrValue));
  2336. }
  2337. }
  2338. else
  2339. hr = S_FALSE;
  2340. }
  2341. ReleaseInterface(ploc);
  2342. }
  2343. error:
  2344. //ReleaseInterface(pwb);
  2345. ReleaseInterface(pwin2);
  2346. ReleaseInterface(pDisp);
  2347. ReleaseInterface(pDocFrame);
  2348. if (bstrURL) {
  2349. RestoreBookMark(pwzBookMark);
  2350. SysFreeString(bstrURL); // bstrFrameURL);
  2351. }
  2352. m_iFrameCur++;
  2353. return hr;
  2354. }
  2355. /*
  2356. * CDocumentPackager ##################################################
  2357. */
  2358. HRESULT CDocumentPackager::PackageDocument(IHTMLDocument2 *pDoc,
  2359. LPCTSTR lpstrDoc,
  2360. BOOL *pfCancel, CThicketProgress *ptp,
  2361. ULONG progLow, ULONG progHigh,
  2362. UINT cpDst,
  2363. CWebArchive *pwa)
  2364. {
  2365. HRESULT hr = S_OK;
  2366. m_ptp = ptp;
  2367. switch (m_iPackageStyle)
  2368. {
  2369. case PACKAGE_THICKET:
  2370. {
  2371. CThicketArchive thicket(ptp);
  2372. hr = _PackageDocument( pDoc, lpstrDoc, pfCancel, ptp, progLow, progHigh, cpDst, &thicket, this, FALSE );
  2373. }
  2374. break;
  2375. case PACKAGE_MHTML:
  2376. {
  2377. CMHTMLArchive *pmhtmla = (CMHTMLArchive *)pwa; // sleazy downcast
  2378. if (pwa == NULL)
  2379. pmhtmla = new CMHTMLArchive(ptp);
  2380. if (pmhtmla != NULL)
  2381. {
  2382. hr = _PackageDocument( pDoc, lpstrDoc, pfCancel, ptp, progLow, progHigh, cpDst,
  2383. pmhtmla, this, FALSE );
  2384. // if pwa is NULL, then we created a CMHTMLArchive for
  2385. // use in _PackageDocument which we now need to clean up
  2386. if (pwa == NULL)
  2387. delete pmhtmla;
  2388. }
  2389. else
  2390. {
  2391. hr = E_OUTOFMEMORY;
  2392. }
  2393. }
  2394. break;
  2395. case PACKAGE_HTML:
  2396. // fall through - Trident will do the right thing by sniffing the
  2397. // extension.
  2398. case PACKAGE_TEXT:
  2399. {
  2400. if (SUCCEEDED(hr))
  2401. {
  2402. IHTMLDocument2 *pDocDesign = NULL;
  2403. IHTMLDocument2 *pDocSave = NULL;
  2404. IPersistFile *ppf = NULL;
  2405. if (cpDst == CP_ACP)
  2406. {
  2407. // No encoding change, use the browse doc
  2408. pDocSave = pDoc;
  2409. }
  2410. else
  2411. {
  2412. hr = _GetDesignDoc( pDoc, &pDocDesign, pfCancel, ptp, cpDst);
  2413. if (SUCCEEDED(hr))
  2414. {
  2415. pDocSave = pDocDesign;
  2416. }
  2417. else
  2418. {
  2419. return E_FAIL;
  2420. }
  2421. }
  2422. // Trident IPersistFile::Save looks at the extension to determine if it's
  2423. // an HTML or text save.
  2424. hr = pDocSave->QueryInterface(IID_IPersistFile, (void**)&ppf);
  2425. if (SUCCEEDED(hr))
  2426. {
  2427. LPCWSTR lpwszFile;
  2428. lpwszFile = lpstrDoc;
  2429. BSTR bstrURL = NULL;
  2430. WCHAR wzSavingText[MAX_SAVING_STATUS_TEXT + 1];
  2431. WCHAR wzBuf[INTERNET_MAX_URL_LENGTH + MAX_SAVING_STATUS_TEXT + 1];
  2432. hr = pDocSave->get_URL(&bstrURL);
  2433. if (SUCCEEDED(hr))
  2434. {
  2435. MLLoadStringW(IDS_SAVING_STATUS_TEXT, wzSavingText,
  2436. ARRAYSIZE(wzSavingText));
  2437. StringCchPrintf(wzBuf, ARRAYSIZE(wzBuf),
  2438. L"%ws: %ws", wzSavingText, bstrURL);
  2439. ptp->SetSaveText(wzBuf);
  2440. if (bstrURL)
  2441. {
  2442. SysFreeString(bstrURL);
  2443. }
  2444. }
  2445. hr = ppf->Save( lpwszFile, FALSE );
  2446. ppf->SaveCompleted(lpwszFile);
  2447. ppf->Release();
  2448. }
  2449. if (cpDst != CP_ACP)
  2450. {
  2451. pDocSave->Release();
  2452. }
  2453. // If we used the browse-time pDoc, we don't need to release
  2454. // it because it is released by CThicketUI::ThicketUIThreadProc
  2455. }
  2456. }
  2457. break;
  2458. default:
  2459. ASSERT(FALSE);
  2460. break;
  2461. }
  2462. return hr;
  2463. }
  2464. HRESULT CDocumentPackager::_PackageDocument(IHTMLDocument2 *pDoc,
  2465. LPCTSTR lpstrDoc,
  2466. BOOL *pfCancel, CThicketProgress *ptp,
  2467. ULONG progLow, ULONG progHigh,
  2468. UINT cpDst,
  2469. CWebArchive *pwa,
  2470. CDocumentPackager *pdpFrames,
  2471. BOOL fFrameDoc)
  2472. {
  2473. HRESULT hr = S_OK;
  2474. ULONG cImages;
  2475. ULONG cInputImgs;
  2476. ULONG cBGSounds;
  2477. ULONG cFrames;
  2478. ULONG uRange = progHigh - progLow;
  2479. ULONG uRangeThis;
  2480. ULONG uLow, uHigh;
  2481. IHTMLElementCollection *pCollect = NULL;
  2482. CImagePackager imgPkgr;
  2483. CInputImgPackager inputimgPkgr;
  2484. CBGSoundsPackager bgsPkgr;
  2485. CBackgroundPackager bkgndPkgr;
  2486. CBaseNeutralizer baseNeut;
  2487. CAnchorAdjustor anchorAdj;
  2488. CAreaAdjustor areaAdj;
  2489. CFramesPackager framesPkgr;
  2490. CSSPackager stylesheetPkgr;
  2491. CDynSrcPackager dynsrcPkgr;
  2492. CScriptPackager scriptPkgr;
  2493. IHTMLDocument2 *pDocDesign = NULL;
  2494. BYTE abBuffer[MAX_BUFFER_LEN];
  2495. DWORD dwType = 0;
  2496. DWORD dwSize = 0;
  2497. BOOL bDLImages = TRUE;
  2498. HKEY hkey = 0;
  2499. IOleCommandTarget *pIOCT = NULL;
  2500. if (pDoc==NULL)
  2501. return E_INVALIDARG;
  2502. hr = _GetDesignDoc( pDoc, &pDocDesign, pfCancel, ptp, cpDst );
  2503. if (FAILED(hr))
  2504. goto error;
  2505. // HACK! If you have a unicode character in the filename, when we
  2506. // call put_href on the CSS, trident tries to download this. The
  2507. // invalid character is sent to the server, who sends badddddd
  2508. // stuff, which the CSS parser doesn't understand. The result is
  2509. // that trident falls on the floor. This tells trident not to download
  2510. // the CSS hence avoiding the problem.
  2511. hr = pDocDesign->QueryInterface(IID_IOleCommandTarget, (void **)&pIOCT);
  2512. if (SUCCEEDED(hr) && pIOCT)
  2513. {
  2514. pIOCT->Exec(NULL, OLECMDID_DONTDOWNLOADCSS, OLECMDID_DONTDOWNLOADCSS,
  2515. NULL, NULL);
  2516. pIOCT->Release();
  2517. }
  2518. hr = pDocDesign->get_all(&pCollect);
  2519. if (FAILED(hr))
  2520. RRETURN(hr);
  2521. dwSize = MAX_BUFFER_LEN;
  2522. if (RegOpenKeyEx(HKEY_CURRENT_USER, REGPATH_MSIE_MAIN, 0, KEY_READ ,&hkey) == ERROR_SUCCESS)
  2523. {
  2524. if (SHQueryValueExA(hkey, REGVALUE_DOWNLOAD_IMAGES, 0, &dwType,
  2525. abBuffer, &dwSize) == NO_ERROR)
  2526. {
  2527. bDLImages = !StrCmpIA((char *)abBuffer, "yes");
  2528. }
  2529. RegCloseKey(hkey);
  2530. }
  2531. if (bDLImages)
  2532. {
  2533. // pack all the images into the message and remember the Thicket mappings
  2534. hr = imgPkgr.InitFromCollection(pCollect, &cImages);
  2535. if (FAILED(hr))
  2536. goto error;
  2537. hr = inputimgPkgr.InitFromCollection(pCollect, &cInputImgs);
  2538. if (FAILED(hr))
  2539. goto error;
  2540. }
  2541. hr = bgsPkgr.InitFromCollection(pCollect, &cBGSounds);
  2542. if (FAILED(hr))
  2543. goto error;
  2544. hr = bkgndPkgr.Init(pCollect, NULL, pDocDesign);
  2545. if (FAILED(hr))
  2546. goto error;
  2547. hr = dynsrcPkgr.Init(pCollect, NULL, pDocDesign);
  2548. if (FAILED(hr))
  2549. goto error;
  2550. hr = stylesheetPkgr.Init(pCollect, NULL, pDocDesign);
  2551. if (FAILED(hr))
  2552. goto error;
  2553. hr = framesPkgr.Init(pCollect, &cFrames, pDoc, pDocDesign, this);
  2554. if (FAILED(hr))
  2555. goto error;
  2556. hr = scriptPkgr.Init(pCollect, NULL, pDocDesign);
  2557. if (FAILED(hr))
  2558. goto error;
  2559. hr = pwa->Init(lpstrDoc, cImages + cInputImgs + cFrames);
  2560. if (FAILED(hr))
  2561. goto error;
  2562. // herewith commences the hackery to drive the progess bar.
  2563. // If we have frames we devide the progress range among all the docs involved.
  2564. // We'll neglect style sheets and devote the range for the immediate
  2565. // document to the image collection.
  2566. uRangeThis = uRange / (cFrames + 1);
  2567. uLow = progLow;
  2568. uHigh = progLow + uRangeThis;
  2569. if (bDLImages)
  2570. {
  2571. hr = imgPkgr.PackageData(pwa, pfCancel, ptp, uLow, uHigh);
  2572. if (FAILED(hr))
  2573. goto error;
  2574. hr = inputimgPkgr.PackageData(pwa, pfCancel, ptp, uLow, uHigh);
  2575. if (FAILED(hr))
  2576. goto error;
  2577. }
  2578. hr = bgsPkgr.PackageData(pwa, pfCancel, ptp, uLow, uHigh);
  2579. if (FAILED(hr))
  2580. goto error;
  2581. hr = bkgndPkgr.PackageData(pwa, pfCancel);
  2582. if (FAILED(hr))
  2583. goto error;
  2584. hr = dynsrcPkgr.PackageData(pwa, pfCancel);
  2585. if (FAILED(hr))
  2586. goto error;
  2587. hr = stylesheetPkgr.PackageStyleSheets(pDocDesign, pwa);
  2588. if (FAILED(hr))
  2589. goto error;
  2590. uLow = progHigh - uRangeThis;
  2591. uHigh = progHigh;
  2592. hr = framesPkgr.PackageData(pwa, pfCancel, ptp, uLow, uHigh);
  2593. if (FAILED(hr))
  2594. goto error;
  2595. hr = scriptPkgr.PackageData(pwa, pfCancel);
  2596. if (FAILED(hr))
  2597. goto error;
  2598. // we want to do this after frames s.t. the frame docs will be in the thicket
  2599. // and we can correctly direct a targetted hyperlink from frame A to frame B
  2600. // if the href is in the thicket vs. still out on the Web.
  2601. hr = anchorAdj.InitFromCollection(pCollect);
  2602. if (FAILED(hr))
  2603. goto error;
  2604. hr = anchorAdj.PackageData(pwa, pfCancel); // not that we need the thicket...
  2605. if (FAILED(hr))
  2606. goto error;
  2607. hr = areaAdj.InitFromCollection(pCollect);
  2608. if (FAILED(hr))
  2609. goto error;
  2610. hr = areaAdj.PackageData(pwa, pfCancel); // not that we need the thicket...
  2611. if (FAILED(hr))
  2612. goto error;
  2613. // Now that we've got everybody remapped, short-circuit the base tags
  2614. // and redirect to the current directory.
  2615. hr = baseNeut.InitFromCollection(pCollect, NULL, pDocDesign );
  2616. if (FAILED(hr))
  2617. goto error;
  2618. hr = baseNeut.PackageData(pwa, pfCancel);
  2619. if (FAILED(hr))
  2620. goto error;
  2621. //if(dwFlags & MECD_HTML || dwFlags & MECD_PLAINTEXT)
  2622. {
  2623. hr = pwa->ArchiveDocumentText( pDocDesign, cpDst, fFrameDoc );
  2624. if (FAILED(hr))
  2625. goto error;
  2626. }
  2627. error:
  2628. if (pCollect)
  2629. pCollect->Release();
  2630. if (pDocDesign)
  2631. pDocDesign->Release();
  2632. if (pfCancel && *pfCancel)
  2633. hr = E_ABORT;
  2634. if (SUCCEEDED(hr))
  2635. pwa->Commit();
  2636. else
  2637. pwa->Revert();
  2638. return hr;
  2639. }
  2640. CWebArchive *CDocumentPackager::GetFrameDocArchive(CWebArchive *pwaSrc)
  2641. {
  2642. CWebArchive *pwa = NULL;
  2643. if (m_iPackageStyle == PACKAGE_THICKET)
  2644. pwa = new CThicketArchive(m_ptp);
  2645. else if (m_iPackageStyle == PACKAGE_MHTML)
  2646. pwa = pwaSrc;
  2647. else
  2648. ASSERT(FALSE);
  2649. return pwa;
  2650. }
  2651. HRESULT CDocumentPackager::_GetDesignDoc( IHTMLDocument2 *pDocSrc, IHTMLDocument2 **ppDocDesign,
  2652. BOOL *pfCancel, CThicketProgress *ptp, UINT cpDst )
  2653. {
  2654. HRESULT hr;
  2655. DWORD dwFlags;
  2656. BSTR bstrURL = NULL;
  2657. BSTR bstrCharSetSrc = NULL;
  2658. MIMECSETINFO csetInfo;
  2659. IMultiLanguage2 *pMultiLanguage = NULL;
  2660. CUrlDownload *pud = NULL;
  2661. ULONG cRef = 0;
  2662. DWORD dwUrlEncodingDisableUTF8;
  2663. DWORD dwSize = SIZEOF(dwUrlEncodingDisableUTF8);
  2664. BOOL fDefault = FALSE;
  2665. hr = pDocSrc->get_charset(&bstrCharSetSrc);
  2666. if (FAILED(hr))
  2667. goto Cleanup;
  2668. hr = CoCreateInstance(CLSID_CMultiLanguage, NULL, CLSCTX_INPROC_SERVER,
  2669. IID_IMultiLanguage2, (void**)&pMultiLanguage);
  2670. if (FAILED(hr))
  2671. {
  2672. goto Cleanup;
  2673. }
  2674. hr = pMultiLanguage->GetCharsetInfo(bstrCharSetSrc, &csetInfo);
  2675. if (FAILED(hr))
  2676. {
  2677. goto Cleanup;
  2678. }
  2679. if (FAILED(pDocSrc->get_URL( &bstrURL )))
  2680. goto Cleanup;
  2681. pud = new CUrlDownload( ptp, &hr, csetInfo.uiInternetEncoding );
  2682. if (pud == NULL)
  2683. {
  2684. hr = E_OUTOFMEMORY;
  2685. goto Cleanup;
  2686. }
  2687. *ppDocDesign = NULL;
  2688. // seanf(2/6/98): Review DLCTL_ flags.
  2689. dwFlags = DLCTL_NO_SCRIPTS | DLCTL_NO_JAVA | DLCTL_NO_RUNACTIVEXCTLS | DLCTL_NO_FRAMEDOWNLOAD |
  2690. DLCTL_SILENT | DLCTL_OFFLINE;
  2691. SHRegGetUSValue(REGSTR_PATH_INTERNET_SETTINGS,
  2692. TEXT("UrlEncoding"), NULL, (LPBYTE) &dwUrlEncodingDisableUTF8, &dwSize, FALSE, (LPVOID) &fDefault, SIZEOF(fDefault));
  2693. if (dwUrlEncodingDisableUTF8)
  2694. {
  2695. dwFlags |= DLCTL_URL_ENCODING_DISABLE_UTF8;
  2696. }
  2697. else
  2698. {
  2699. dwFlags |= DLCTL_URL_ENCODING_ENABLE_UTF8;
  2700. }
  2701. hr = pud->SetDLCTL(dwFlags);
  2702. if (SUCCEEDED(hr))
  2703. hr = pud->BeginDownloadURL2( bstrURL, BDU2_BROWSER, BDU2_NONE, NULL, 0xF0000000 );
  2704. if (SUCCEEDED(hr))
  2705. {
  2706. MSG msg;
  2707. hr = S_FALSE;
  2708. while (hr==S_FALSE)
  2709. {
  2710. GetMessage(&msg, NULL, 0, 0);
  2711. TranslateMessage(&msg);
  2712. DispatchMessage(&msg);
  2713. if (*pfCancel)
  2714. {
  2715. pud->AbortDownload();
  2716. hr = E_ABORT;
  2717. }
  2718. }
  2719. if (SUCCEEDED(hr))
  2720. {
  2721. hr = pud->GetDocument( ppDocDesign );
  2722. // Set the document to the codepage the user has selected.
  2723. // Don't bother if it's no specific page has been directed, as is the case
  2724. // with frame documents and in cases where the user kept the default
  2725. // code page selected in the Save As... dialog.
  2726. if (SUCCEEDED(hr) && cpDst != CP_ACP)
  2727. {
  2728. MIMECPINFO cpInfo;
  2729. BSTR bstrCharSet = NULL;
  2730. LANGID langid;
  2731. langid = MLGetUILanguage();
  2732. if ( SUCCEEDED(pMultiLanguage->GetCodePageInfo(cpDst, langid, &cpInfo)) &&
  2733. (bstrCharSet = SysAllocString(cpInfo.wszWebCharset)) != NULL )
  2734. hr = (*ppDocDesign)->put_charset(bstrCharSet);
  2735. ASSERT(SUCCEEDED(hr));
  2736. if (bstrCharSet)
  2737. SysFreeString(bstrCharSet);
  2738. }
  2739. }
  2740. }
  2741. pud->DoneDownloading();
  2742. cRef = pud->Release();
  2743. if (SUCCEEDED(hr))
  2744. {
  2745. IOleCommandTarget *pioct;
  2746. hr = pDocSrc->QueryInterface(IID_IOleCommandTarget, (LPVOID*)&pioct);
  2747. if (SUCCEEDED(hr))
  2748. {
  2749. VARIANTARG v;
  2750. v.vt = VT_UNKNOWN;
  2751. v.punkVal = *ppDocDesign;
  2752. hr = pioct->Exec( &CGID_ShortCut, CMDID_SAVEASTHICKET, OLECMDEXECOPT_DODEFAULT, &v, NULL );
  2753. pioct->Release();
  2754. }
  2755. }
  2756. Cleanup:
  2757. SAFERELEASE(pMultiLanguage);
  2758. if (bstrURL)
  2759. SysFreeString(bstrURL);
  2760. if (bstrCharSetSrc)
  2761. SysFreeString(bstrCharSetSrc);
  2762. if (FAILED(hr))
  2763. {
  2764. if (ppDocDesign != NULL)
  2765. {
  2766. ReleaseInterface((*ppDocDesign));
  2767. }
  2768. }
  2769. return hr;
  2770. }
  2771. /*
  2772. * CSSPackager ##################################################
  2773. */
  2774. HRESULT CSSPackager::Init(IHTMLElementCollection *pColl,
  2775. ULONG *pcElems,
  2776. IHTMLDocument2 *pDoc)
  2777. {
  2778. HRESULT hr = CRelativeURLPackager::Init( pColl, pcElems, pDoc );
  2779. m_pDoc = pDoc;
  2780. RRETURN(hr);
  2781. }
  2782. HRESULT CSSPackager::PackageStyleSheets(IHTMLDocument2 *pDoc2,
  2783. CWebArchive *pwa)
  2784. {
  2785. HRESULT hr = S_OK;
  2786. IHTMLStyleSheetsCollection *pssc = NULL;
  2787. ASSERT(pDoc2);
  2788. ASSERT(pwa);
  2789. // process the inline style sheets
  2790. hr = pDoc2->get_styleSheets( &pssc );
  2791. if (SUCCEEDED(hr))
  2792. {
  2793. hr = _PackageSSCollection(pssc, pwa);
  2794. pssc->Release();
  2795. }
  2796. return hr; // no RRETURN - may return S_FALSE
  2797. }
  2798. HRESULT CSSPackager::_PackageSSCollection(IHTMLStyleSheetsCollection *pssc,
  2799. CWebArchive *pwa)
  2800. {
  2801. HRESULT hr;
  2802. LONG cSS;
  2803. hr = pssc->get_length( &cSS );
  2804. if (SUCCEEDED(hr))
  2805. {
  2806. LONG iSS;
  2807. for (iSS = 0; iSS < cSS && SUCCEEDED(hr); iSS++ )
  2808. {
  2809. VARIANT varIndex;
  2810. VARIANT varSS;
  2811. varIndex.vt = VT_I4;
  2812. varIndex.lVal = iSS;
  2813. varSS.vt = VT_EMPTY;
  2814. hr = pssc->item( &varIndex, &varSS );
  2815. if (SUCCEEDED(hr) && varSS.vt == VT_DISPATCH && varSS.pdispVal != NULL)
  2816. {
  2817. IHTMLStyleSheet *pss = NULL;
  2818. if(SUCCEEDED(varSS.pdispVal->QueryInterface(IID_IHTMLStyleSheet, (void**)&pss)))
  2819. {
  2820. hr = _PackageSS(pss, pwa);
  2821. pss->Release();
  2822. }
  2823. varSS.pdispVal->Release();
  2824. }
  2825. }
  2826. }
  2827. return hr; // no RRETURN - may return S_FALSE
  2828. }
  2829. HRESULT CSSPackager::_PackageSS(IHTMLStyleSheet *pss,
  2830. CWebArchive *pwa)
  2831. {
  2832. HRESULT hr;
  2833. BSTR bstrRelURL = NULL;
  2834. BSTR bstrAbsURL = NULL;
  2835. LONG lElemPos;
  2836. IHTMLElement *pElemOwner = NULL;
  2837. IHTMLStyleSheetsCollection *pssc = NULL;
  2838. BOOL fStyleTag = FALSE;
  2839. if (pss == NULL || pwa == NULL)
  2840. return E_INVALIDARG;
  2841. hr = pss->get_href(&bstrRelURL);
  2842. if (FAILED(hr))
  2843. goto error;
  2844. fStyleTag = bstrRelURL == NULL || *bstrRelURL == 0;
  2845. hr = pss->get_owningElement(&pElemOwner);
  2846. if (FAILED(hr))
  2847. goto error;
  2848. hr = pElemOwner->get_sourceIndex(&lElemPos);
  2849. if (FAILED(hr))
  2850. goto error;
  2851. hr = HrGetCombinedURL(m_pCollBase, m_cBase, lElemPos, bstrRelURL, m_bstrDocURL, &bstrAbsURL);
  2852. if (FAILED(hr))
  2853. goto error;
  2854. // First we do the defualt processing, gathering the imports into _our_
  2855. // process the inline style sheets
  2856. hr = pss->get_imports( &pssc );
  2857. if (SUCCEEDED(hr))
  2858. {
  2859. long cSS;
  2860. hr = pssc->get_length( &cSS );
  2861. if (SUCCEEDED(hr) && cSS > 0)
  2862. {
  2863. CSSPackager importPkgr;
  2864. hr = importPkgr.Init(m_pCollBase, NULL, m_pDoc);
  2865. hr = importPkgr._PackageSSCollection(pssc, pwa);
  2866. }
  2867. pssc->Release();
  2868. }
  2869. // oh, yeah, if we want to do background-image and list-style-image, we'd enumerate this ss's rule styles
  2870. // here, find the ones with these attributes, and build a list of IHTML rule style, maybe using some sub-obj
  2871. // like an image packager.
  2872. if (SUCCEEDED(hr) && !fStyleTag)
  2873. {
  2874. BSTR bstrSSText;
  2875. // Now we grab our modified text and add it to the document.
  2876. hr = pss->get_cssText(&bstrSSText);
  2877. if (SUCCEEDED(hr) && bstrSSText != NULL)
  2878. {
  2879. LPSTR lpszSSText;
  2880. // This text needs to be ANSI before we put it into the stream.
  2881. hr = HrBSTRToLPSZ( bstrSSText, &lpszSSText );
  2882. if (SUCCEEDED(hr))
  2883. {
  2884. // PTH hr = MimeOleCreateVirtualStream(&pstm);
  2885. TCHAR szStyleDoc[MAX_PATH];
  2886. CHashEntry *phe;
  2887. hr = pwa->AddFrameOrStyleEntry( bstrAbsURL, &phe, szStyleDoc );
  2888. if (hr==S_OK)
  2889. {
  2890. hr = pwa->ArchiveCSSText( bstrAbsURL, lpszSSText, szStyleDoc );
  2891. if ( SUCCEEDED(hr) )
  2892. hr = pss->put_href(phe->m_bstrValue);
  2893. }
  2894. else if (hr==S_FALSE)
  2895. {
  2896. // repeated style sheet, don't need to do all the work, but do need to note
  2897. // the ss for remapping
  2898. hr = pss->put_href( phe->m_bstrValue);
  2899. }
  2900. delete lpszSSText;
  2901. }
  2902. SysFreeString(bstrSSText);
  2903. }
  2904. }
  2905. error:
  2906. if (pElemOwner)
  2907. pElemOwner->Release();
  2908. if (bstrRelURL)
  2909. SysFreeString(bstrRelURL);
  2910. if (bstrAbsURL)
  2911. SysFreeString(bstrAbsURL);
  2912. return hr; // no RRETURN - may return S_FALSE
  2913. }
  2914. //
  2915. // Functions ##############################################################
  2916. //
  2917. ULONG UlGetCollectionCount(IHTMLElementCollection *pCollect)
  2918. {
  2919. ULONG ulCount=0;
  2920. if (pCollect)
  2921. pCollect->get_length((LONG *)&ulCount);
  2922. return ulCount;
  2923. }
  2924. HRESULT HrGetCollectionItem(IHTMLElementCollection *pCollect, ULONG uIndex, REFIID riid, LPVOID *ppvObj)
  2925. {
  2926. HRESULT hr=E_FAIL;
  2927. IDispatch *pDisp=0;
  2928. VARIANTARG va1,
  2929. va2;
  2930. va1.vt = VT_I4;
  2931. va2.vt = VT_EMPTY;
  2932. va1.lVal = (LONG)uIndex;
  2933. pCollect->item(va1, va2, &pDisp);
  2934. if (pDisp)
  2935. {
  2936. hr = pDisp->QueryInterface(riid, ppvObj);
  2937. pDisp->Release();
  2938. }
  2939. return hr; // no RRETURN - may return S_FALSE
  2940. }
  2941. HRESULT HrSetMember(LPUNKNOWN pUnk, BSTR bstrMember, BSTR bstrValue)
  2942. {
  2943. IHTMLElement *pObj;
  2944. HRESULT hr;
  2945. VARIANT rVar;
  2946. ASSERT(pUnk);
  2947. hr = pUnk->QueryInterface(IID_IHTMLElement, (LPVOID *)&pObj);
  2948. if (SUCCEEDED(hr))
  2949. {
  2950. ASSERT (pObj);
  2951. rVar.vt = VT_BSTR;
  2952. rVar.bstrVal = bstrValue;
  2953. hr = pObj->setAttribute(bstrMember, rVar, FALSE);
  2954. pObj->Release();
  2955. }
  2956. return hr; // no RRETURN - may return S_FALSE
  2957. }
  2958. /*
  2959. * HrGetCombinedURL does some of the things that GetBackgroundImageUrl
  2960. * does, but in a more general way. It relies on the caller to have
  2961. * isolated the <BASE> collection and to supply the root document URL.
  2962. * While a trifle awkward, it is more efficient if the caller is going
  2963. * to combine many URLS.
  2964. */
  2965. HRESULT HrGetCombinedURL( IHTMLElementCollection *pCollBase,
  2966. LONG cBase,
  2967. LONG lElemPos,
  2968. BSTR bstrRelURL,
  2969. BSTR bstrDocURL,
  2970. BSTR *pbstrBaseURL)
  2971. {
  2972. HRESULT hr = S_FALSE;
  2973. IHTMLElement *pElemBase;
  2974. IHTMLBaseElement *pBase;
  2975. LONG lBasePos=0,
  2976. lBasePosSoFar=0;
  2977. BSTR bstr = NULL;
  2978. LPWSTR pszUrlW=0;
  2979. WCHAR szBaseW[INTERNET_MAX_URL_LENGTH];
  2980. WCHAR szUrlW[INTERNET_MAX_URL_LENGTH];
  2981. DWORD cch=INTERNET_MAX_URL_LENGTH;
  2982. LONG i;
  2983. *pbstrBaseURL = 0;
  2984. *szBaseW = 0;
  2985. for (i=0; i<cBase; i++)
  2986. {
  2987. if (SUCCEEDED(HrGetCollectionItem(pCollBase, i, IID_IHTMLElement, (LPVOID *)&pElemBase)))
  2988. {
  2989. pElemBase->get_sourceIndex(&lBasePos);
  2990. if (lBasePos < lElemPos &&
  2991. lBasePos >= lBasePosSoFar)
  2992. {
  2993. if (SUCCEEDED(pElemBase->QueryInterface(IID_IHTMLBaseElement, (LPVOID *)&pBase)))
  2994. {
  2995. bstr = NULL;
  2996. if (pBase->get_href(&bstr)==S_OK && bstr != NULL)
  2997. {
  2998. ASSERT (bstr);
  2999. if (*bstr)
  3000. {
  3001. StringCchCopy(szBaseW, ARRAYSIZE(szBaseW), bstr);
  3002. lBasePosSoFar = lBasePos;
  3003. }
  3004. SysFreeString(bstr);
  3005. }
  3006. pBase->Release();
  3007. }
  3008. }
  3009. pElemBase->Release();
  3010. }
  3011. }
  3012. if (szBaseW[0] == 0 && bstrDocURL)
  3013. {
  3014. // We didn't find a <BASE> tag before our element, so fall back to using
  3015. // the document's location as basis for the base
  3016. StringCchCopy( szBaseW, ARRAYSIZE(szBaseW), bstrDocURL );
  3017. }
  3018. #ifndef WIN16 //RUN16_BLOCK - UrlCombineW is not available
  3019. // if there's a <BASE> then do the combine
  3020. if (*szBaseW &&
  3021. SUCCEEDED(UrlCombineW(szBaseW, bstrRelURL, szUrlW, &cch, 0)))
  3022. pszUrlW = szUrlW;
  3023. #endif //!WIN16
  3024. // pszUrlW contains the combined <BODY> and <BASE> tag, return this.
  3025. if (pszUrlW)
  3026. *pbstrBaseURL = SysAllocString(pszUrlW);
  3027. return (*pbstrBaseURL == NULL ? S_FALSE : S_OK);
  3028. }
  3029. HRESULT HrBSTRToLPSZ(BSTR bstr, LPSTR *lplpsz)
  3030. {
  3031. ULONG cch = 0;
  3032. ASSERT (bstr && lplpsz);
  3033. cch = WideCharToMultiByte(CP_ACP, 0, bstr, -1, NULL, 0, NULL, NULL);
  3034. if (!cch)
  3035. {
  3036. return HRESULT_FROM_WIN32(GetLastError());
  3037. }
  3038. *lplpsz = new char[cch + 1];
  3039. if (!*lplpsz)
  3040. {
  3041. return E_OUTOFMEMORY;
  3042. }
  3043. if (WideCharToMultiByte(CP_ACP, 0, bstr, -1, *lplpsz, cch+1, NULL, NULL))
  3044. return S_OK;
  3045. else
  3046. return HRESULT_FROM_WIN32(GetLastError());
  3047. }
  3048. void RemoveBookMark(WCHAR *pwzURL, WCHAR **ppwzBookMark)
  3049. {
  3050. if (pwzURL && ppwzBookMark)
  3051. {
  3052. *ppwzBookMark = pwzURL;
  3053. while (**ppwzBookMark)
  3054. {
  3055. if (**ppwzBookMark == L'#')
  3056. {
  3057. **ppwzBookMark = L'\0';
  3058. break;
  3059. }
  3060. (*ppwzBookMark)++;
  3061. }
  3062. }
  3063. }
  3064. void RestoreBookMark(WCHAR *pwzBookMark)
  3065. {
  3066. if (pwzBookMark)
  3067. {
  3068. *pwzBookMark = L'#';
  3069. }
  3070. }