Source code of Windows XP (NT5)
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.

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