4049 lines
110 KiB
C++
4049 lines
110 KiB
C++
//+---------------------------------------------------------------------------
|
|
//
|
|
// Microsoft Windows
|
|
// Copyright (C) Microsoft Corporation, 1994
|
|
//
|
|
// File: persist.cxx
|
|
//
|
|
// Contents: Implmentation of Office9 Thicket Save API
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
|
|
#include "priv.h"
|
|
#include <mshtml.h>
|
|
#include <winineti.h>
|
|
#include <mlang.h>
|
|
// fake out mimeole.h's dll linkage directives for our delay load stuff in dllload.c
|
|
#define _MIMEOLE_
|
|
#define DEFINE_STRCONST
|
|
#include <mimeole.h>
|
|
#include "resource.h"
|
|
#include "packager.h"
|
|
#include "reload.h"
|
|
|
|
#include <mluisupp.h>
|
|
|
|
#define DEFINE_STRING_CONSTANTS
|
|
#pragma warning( disable : 4207 )
|
|
#include "htmlstr.h"
|
|
#pragma warning( default : 4207 )
|
|
|
|
const GUID CLSID_IMimeInternational =
|
|
{0xfd853cd9, 0x7f86, 0x11d0, {0x82, 0x52, 0x0, 0xc0, 0x4f, 0xd8, 0x5a, 0xb4}};
|
|
|
|
const GUID IID_IMimeInternational =
|
|
{0xc5588349, 0x7f86, 0x11d0, {0x82, 0x52, 0x0, 0xc0, 0x4f, 0xd8, 0x5a, 0xb4}};
|
|
|
|
const GUID IID_IMimeBody =
|
|
{0xc558834c, 0x7f86, 0x11d0, {0x82, 0x52, 0x0, 0xc0, 0x4f, 0xd8, 0x5a, 0xb4}};
|
|
|
|
// Trident legacy defines...
|
|
|
|
#define RRETURN(hr) return hr;
|
|
#define ReleaseInterface(punk) { if (punk) punk->Release(); punk = NULL; }
|
|
|
|
// Local prototypes
|
|
|
|
void RemoveBookMark(WCHAR *pwzURL, WCHAR **ppwzBookMark);
|
|
void RestoreBookMark(WCHAR *pwzBookMark);
|
|
|
|
HRESULT HrGetElement(IHTMLDocument2 *pDoc, LPCSTR pszName, IHTMLElement **ppElem);
|
|
HRESULT HrGetBodyElement(IHTMLDocument2 *pDoc, IHTMLBodyElement **ppBody);
|
|
HRESULT HrSetMember(LPUNKNOWN pUnk, BSTR bstrMember, BSTR bstrValue);
|
|
HRESULT HrGetCollectionOf(IHTMLDocument2 *pDoc, BSTR bstrTagName, IHTMLElementCollection **ppCollect);
|
|
HRESULT HrGetCollectionItem(IHTMLElementCollection *pCollect, ULONG uIndex, REFIID riid, LPVOID *ppvObj);
|
|
ULONG UlGetCollectionCount(IHTMLElementCollection *pCollect);
|
|
HRESULT HrGetMember(LPUNKNOWN pUnk, BSTR bstrMember,LONG lFlags, BSTR *pbstr);
|
|
HRESULT HrLPSZToBSTR(LPCSTR lpsz, BSTR *pbstr);
|
|
HRESULT HrBSTRToLPSZ(BSTR bstr, LPSTR *lplpsz);
|
|
HRESULT HrGetCombinedURL( IHTMLElementCollection *pCollBase,
|
|
LONG cBase,
|
|
LONG lElemPos,
|
|
BSTR bstrRelURL,
|
|
BSTR bstrDocURL,
|
|
BSTR *pbstrBaseURL);
|
|
|
|
class CHashEntry {
|
|
public:
|
|
CHashEntry(void) : m_bstrKey(NULL), m_bstrValue(NULL), m_pheNext(NULL) {};
|
|
~CHashEntry(void)
|
|
{
|
|
if (m_bstrKey)
|
|
SysFreeString(m_bstrKey);
|
|
if (m_bstrValue)
|
|
SysFreeString(m_bstrValue);
|
|
}
|
|
|
|
BOOL SetKey(BSTR bstrKey)
|
|
{
|
|
ASSERT(m_bstrKey==NULL);
|
|
m_bstrKey = SysAllocString(bstrKey);
|
|
return m_bstrKey != NULL;
|
|
}
|
|
|
|
BOOL SetValue(BSTR bstrValue)
|
|
{
|
|
ASSERT(m_bstrValue==NULL || !StrCmpIW(m_bstrValue, c_bstr_BLANK) ||
|
|
!StrCmpIW(m_bstrValue, bstrValue));
|
|
m_bstrValue = SysAllocString(bstrValue);
|
|
return m_bstrValue != NULL;
|
|
}
|
|
|
|
BSTR m_bstrKey;
|
|
BSTR m_bstrValue;
|
|
CHashEntry *m_pheNext;
|
|
};
|
|
|
|
|
|
class CWebArchive
|
|
{
|
|
public:
|
|
|
|
CWebArchive(CThicketProgress* ptp=NULL);
|
|
~CWebArchive(void);
|
|
|
|
virtual HRESULT Init( LPCTSTR lpstrDoc, DWORD dwHashSize );
|
|
|
|
virtual HRESULT AddURL( BSTR bstrURL, CHashEntry **pphe ) = 0;
|
|
virtual HRESULT AddFrameOrStyleEntry( BSTR bstrURL, CHashEntry **pphe, LPTSTR lpstrFrameDoc ) = 0;
|
|
virtual HRESULT Find(BSTR bstrF, CHashEntry **pphe);
|
|
|
|
virtual HRESULT Commit(void);
|
|
virtual HRESULT Revert(void);
|
|
|
|
virtual HRESULT ArchiveDocumentText(IHTMLDocument2 *pDoc, UINT cpDoc, BOOL fFrameDoc) = 0;
|
|
virtual HRESULT ArchiveCSSText( BSTR bstrCSSUrl, LPCSTR lpszSSText, LPCTSTR lpszStyleDoc ) = 0;
|
|
|
|
protected:
|
|
|
|
LPTSTR m_lpstrDoc; // Desintation file for thicket document
|
|
LPTSTR m_lpstrSafeDoc; // Temp name of original file, which we delete on Commit()
|
|
|
|
CThicketProgress* m_ptp;
|
|
|
|
enum ThURLType {
|
|
thurlMisc,
|
|
thurlHttp,
|
|
thurlFile
|
|
};
|
|
|
|
ThURLType _GetURLType( BSTR bstrURL );
|
|
|
|
HRESULT _BackupOldFile(void);
|
|
|
|
// hash table stuff stolen from MIMEEDIT
|
|
HRESULT _Insert(BSTR bstrI, BSTR bstrThicket, CHashEntry **pphe);
|
|
inline DWORD Hash(LPWSTR psz);
|
|
|
|
DWORD m_cBins;
|
|
CHashEntry *m_rgBins;
|
|
};
|
|
|
|
|
|
class CThicketArchive : public CWebArchive
|
|
{
|
|
public:
|
|
|
|
CThicketArchive(CThicketProgress* ptp=NULL);
|
|
~CThicketArchive(void);
|
|
|
|
virtual HRESULT Init( LPCTSTR lpstrDoc, DWORD dwHashSize );
|
|
|
|
virtual HRESULT AddURL( BSTR bstrURL, CHashEntry **pphe );
|
|
virtual HRESULT AddFrameOrStyleEntry( BSTR bstrURL, CHashEntry **pphe, LPTSTR lpstrFrameDoc );
|
|
|
|
virtual HRESULT Commit(void);
|
|
virtual HRESULT Revert(void);
|
|
|
|
virtual HRESULT ArchiveDocumentText(IHTMLDocument2 *pDoc, UINT cpDoc, BOOL fFrameDoc);
|
|
virtual HRESULT ArchiveCSSText( BSTR bstrCSSUrl, LPCSTR lpszSSText, LPCTSTR lpszStyleDoc );
|
|
|
|
protected:
|
|
|
|
LPTSTR m_lpstrFilesDir; // directory for document's supporting files.
|
|
LPTSTR m_lpstrFilesDirName; // suffix of m_lpstrFilesDir
|
|
LPTSTR m_lpstrSafeDir; // Temp name of original files directory, which we delete on Commit()
|
|
BOOL m_fFilesDir; // TRUE if m_lpstrFilesDir has been created.
|
|
|
|
|
|
HRESULT _ApplyMarkOfTheWeb( IHTMLDocument2 *pDoc, LPSTREAM pstm, BOOL fUnicode );
|
|
|
|
HRESULT _AddHttpEntry( BSTR bstrURL, CHashEntry **pphe, LPTSTR lpstrDstFile, LPTSTR lpstrSrcFile=NULL );
|
|
HRESULT _AddFileEntry( BSTR bstrURL, CHashEntry **pphe, LPTSTR lpstrDstFile, LPTSTR lpstrSrcFile=NULL );
|
|
HRESULT _AddMiscEntry( BSTR bstrURL, CHashEntry **pphe, LPTSTR lpstrDstFile, int cchDstFile );
|
|
|
|
HRESULT _PersistHttpURL( BSTR bstrURL, CHashEntry **pphe );
|
|
HRESULT _PersistFileURL( BSTR bstrURL, CHashEntry **pphe );
|
|
HRESULT _PersistMiscURL( BSTR bstrURL, CHashEntry **pphe );
|
|
|
|
HRESULT _BackupOldDirectory(void);
|
|
HRESULT _RemoveOldDirectoryAndChildren( LPCWSTR pszDir );
|
|
|
|
HRESULT _Insert(BSTR bstrI, LPTSTR lpszFile, int cchFile, CHashEntry **pphe);
|
|
};
|
|
|
|
class CMHTMLArchive : public CWebArchive
|
|
{
|
|
public:
|
|
|
|
CMHTMLArchive(CThicketProgress* ptp=NULL);
|
|
~CMHTMLArchive(void);
|
|
|
|
virtual HRESULT Init( LPCTSTR lpstrDoc, DWORD dwHashSize );
|
|
|
|
virtual HRESULT AddURL( BSTR bstrURL, CHashEntry **pphe );
|
|
virtual HRESULT AddFrameOrStyleEntry( BSTR bstrURL, CHashEntry **pphe, LPTSTR lpstrFrameDoc );
|
|
|
|
virtual HRESULT ArchiveDocumentText(IHTMLDocument2 *pDoc, UINT cpDoc, BOOL fFrameDoc);
|
|
virtual HRESULT ArchiveCSSText( BSTR bstrCSSUrl, LPCSTR lpszSSText, LPCTSTR lpszStyleDoc );
|
|
|
|
virtual HRESULT SetCharset(UINT uiCharset, CSETAPPLYTYPE csat, IMimeBody *pBody);
|
|
|
|
protected:
|
|
|
|
HBODY m_hBodyAlt;
|
|
IMimeMessage *m_pimm;
|
|
};
|
|
|
|
/*
|
|
* The following classes implement extended Save As MTHML functionality.
|
|
* Access to the extended functionality is controlled by new MECD_ flags
|
|
* defined in mimeole.h. Clients of the C API in this module should notice
|
|
* mimimal change in its behavior. ( limited to the additional inclusion
|
|
* table and table cell background images ).
|
|
*
|
|
* The root idea is that of a collection packager, which takes a subset
|
|
* of the document.all collection, filters the elements of that subcollection,
|
|
* and marshall's the element data into the MIMEOle document This is patterned
|
|
* after the existing PackageImageData routine, and relies heavily on
|
|
* HrAddImageToMessage, which is much more general than its name implies.
|
|
*
|
|
*
|
|
* Stylesheets introduce some repetition, as the stylesheet OM is similar,
|
|
* but not similar enough, to support common base classes specialized via
|
|
* templates.
|
|
*
|
|
* The process of adding new packagers is pretty straight-forward.
|
|
* [1] (a) if the packaged attribute is a complete URL, derive from CCollectionPackager
|
|
* (b) if the attribute is a relative URL, derive from CRelativeURLPackager
|
|
* [2] Implement InitFromCollection. Have it call _InitSubCollection() with the tag name.
|
|
* See CImagePackager::InitFromCollection() as a simple example.
|
|
* [3] Implement _GetTargetAttribute() to return the attribute you want to package.
|
|
* You may want to add the string constants for [2] and [3] to htmlstr.h
|
|
* [4] Define an MECD_ control flag, if the thing you're packaging is new.
|
|
* [5] Add a local var of your packager type to CDocumentPackager::PackageDocument.
|
|
* [6] Follow the pattern of the other packagers in CDocumentPackager::PackageDocument
|
|
*
|
|
* For elements with multiple persisted attributes, it's dealer's choice as to how
|
|
* to approach it. Write seperate, simpler packagers for each attribute or write
|
|
* one packager that deals with all of the target element's attributes.
|
|
*/
|
|
|
|
|
|
|
|
/*
|
|
* CCollectionPackager - abstract base class for HTML element packagers.
|
|
* Implements subsampling from the all collection, iteration over the
|
|
* collection, and basic packaging functionality.
|
|
*
|
|
* Derived classes must implement InitFromCollection and _GetTargetAttribute.
|
|
* InitFromCollection - derived class should store the desired subset of the
|
|
* input collection into the m_pColl data member. _InitSubCollection is
|
|
* a useful method for this purpose.
|
|
* _GetTargetAttribute - derived class should return a BSTR naming the attribute
|
|
* of the element to be packaged.
|
|
*
|
|
*/
|
|
class CCollectionPackager
|
|
{
|
|
public:
|
|
virtual ~CCollectionPackager(void);
|
|
virtual HRESULT InitFromCollection(IHTMLElementCollection *pColl,
|
|
ULONG *pcElems = NULL) = 0;
|
|
virtual HRESULT PackageData(CWebArchive *pwa, BOOL *pfCancel = NULL,
|
|
CThicketProgress *ptp = NULL, ULONG progLow = 0, ULONG progHigh = 100)
|
|
{
|
|
return _PackageData( pwa, m_pColl, pfCancel, ptp, progLow, progHigh );
|
|
}
|
|
|
|
protected:
|
|
|
|
CCollectionPackager(void) : m_pColl(NULL), m_fAddCntLoc(FALSE) {};
|
|
|
|
HRESULT _InitSubCollection(IHTMLElementCollection *pAll,
|
|
BSTR bstrTagName,
|
|
IHTMLElementCollection **ppSub,
|
|
ULONG *pcElems = NULL);
|
|
|
|
virtual BSTR _GetTargetAttribute(void) = 0;
|
|
|
|
virtual HRESULT _GetElementURL(IHTMLElement *pElem, BSTR *pbstrURL);
|
|
virtual HRESULT _PackageData(CWebArchive *pwa,
|
|
IHTMLElementCollection *pColl,
|
|
BOOL *pfCancel = NULL,
|
|
CThicketProgress *ptp = NULL, ULONG progLow = 0, ULONG progHigh = 100);
|
|
virtual HRESULT _PackageElement(CWebArchive *pwa,
|
|
IHTMLElement *pElem);
|
|
|
|
IHTMLElementCollection *m_pColl;
|
|
BOOL m_fAddCntLoc;
|
|
};
|
|
|
|
/*
|
|
* CImagePackager - packages the src's of IMG tags.
|
|
*/
|
|
class CImagePackager : public CCollectionPackager
|
|
{
|
|
public:
|
|
CImagePackager(void) {};
|
|
virtual ~CImagePackager(void) {};
|
|
|
|
virtual HRESULT InitFromCollection(IHTMLElementCollection *pColl,
|
|
ULONG *pcElems = NULL);
|
|
protected:
|
|
|
|
virtual BSTR _GetTargetAttribute(void);
|
|
|
|
};
|
|
|
|
/*
|
|
* CInputImgPackager - packages INPUT type="image"
|
|
*/
|
|
|
|
class CInputImgPackager : public CImagePackager
|
|
{
|
|
public:
|
|
CInputImgPackager() {}
|
|
virtual ~CInputImgPackager() {}
|
|
|
|
virtual HRESULT InitFromCollection(IHTMLElementCollection *pColl,
|
|
ULONG *pcElems = NULL);
|
|
|
|
};
|
|
|
|
/*
|
|
* CBGSoundsPackager - packages background sounds
|
|
*/
|
|
|
|
class CBGSoundsPackager : public CCollectionPackager
|
|
{
|
|
public:
|
|
CBGSoundsPackager() {};
|
|
virtual ~CBGSoundsPackager() {};
|
|
|
|
virtual HRESULT InitFromCollection(IHTMLElementCollection *pColl,
|
|
ULONG *pcElems = NULL);
|
|
protected:
|
|
|
|
virtual BSTR _GetTargetAttribute(void);
|
|
|
|
};
|
|
|
|
/*
|
|
* CAnchorAdjustor - modifies anchor hrefs.
|
|
*
|
|
* Makes them absolute if they point out of the collection.
|
|
*/
|
|
|
|
class CAnchorAdjustor : public CCollectionPackager
|
|
{
|
|
public:
|
|
CAnchorAdjustor(void) {};
|
|
virtual ~CAnchorAdjustor(void) {};
|
|
|
|
virtual HRESULT InitFromCollection(IHTMLElementCollection *pColl,
|
|
ULONG *pcElems = NULL);
|
|
protected:
|
|
|
|
virtual BSTR _GetTargetAttribute(void);
|
|
virtual HRESULT _PackageElement(CWebArchive *pwa,
|
|
IHTMLElement *pElem);
|
|
};
|
|
|
|
/*
|
|
* CAreaAdjustor - modifies AREA hrefs.
|
|
*
|
|
* Makes them absolute if they point out of the collection. Same filter
|
|
* as the anchor adjustor, but different tag.
|
|
*/
|
|
|
|
class CAreaAdjustor : public CAnchorAdjustor
|
|
{
|
|
public:
|
|
CAreaAdjustor(void) {};
|
|
virtual ~CAreaAdjustor(void) {};
|
|
|
|
virtual HRESULT InitFromCollection(IHTMLElementCollection *pColl,
|
|
ULONG *pcElems = NULL);
|
|
};
|
|
|
|
/*
|
|
* CBaseNeutralizer - resets any and all <BASE> tags to the d.
|
|
*
|
|
* No actual packaging goes on here, but we do remap the
|
|
* <BASE> href.
|
|
*/
|
|
|
|
class CBaseNeutralizer : public CCollectionPackager
|
|
{
|
|
public:
|
|
CBaseNeutralizer(void) : m_bstrLocal(NULL), m_pTree(NULL) {};
|
|
virtual ~CBaseNeutralizer(void);
|
|
|
|
virtual HRESULT InitFromCollection(IHTMLElementCollection *pColl,
|
|
ULONG *pcElems = NULL )
|
|
{ return InitFromCollection( pColl, pcElems, NULL ); };
|
|
HRESULT InitFromCollection(IHTMLElementCollection *pColl,
|
|
ULONG *pcElems = NULL,
|
|
IHTMLDocument2 *pDoc = NULL);
|
|
virtual HRESULT PackageData(CWebArchive *pwa, BOOL *pfCancel = NULL,
|
|
CThicketProgress *ptp = NULL, ULONG progLow = 0, ULONG progHigh = 100);
|
|
|
|
protected:
|
|
|
|
virtual BSTR _GetTargetAttribute(void);
|
|
virtual HRESULT _PackageElement(CWebArchive *pwa,
|
|
IHTMLElement *pElem);
|
|
|
|
BSTR m_bstrLocal;
|
|
IMarkupServices *m_pTree;
|
|
};
|
|
|
|
/*
|
|
* CRelativeURLPackager - abstract base class for packagers
|
|
* whose element's source attribute returns a relative URL.
|
|
* This class implements triutils.pp's GetBackgroundImageUrl's
|
|
* process of attempting to combine the (relative) element URL
|
|
* with the nearest <BASE> URL. If no <BASE> is availaible, it
|
|
* uses the document URL.
|
|
*
|
|
* This class is an abstract base because it does not implement
|
|
* _GetTargetAttribute. It's implementation of InitFromCollection
|
|
* isn't very useful and will probably be overridden by derived
|
|
* classes.
|
|
*/
|
|
|
|
class CRelativeURLPackager : public CCollectionPackager
|
|
{
|
|
public:
|
|
CRelativeURLPackager(void) : m_pCollBase(NULL), m_cBase(0), m_bstrDocURL(NULL) {};
|
|
virtual ~CRelativeURLPackager(void);
|
|
|
|
virtual HRESULT InitFromCollection(IHTMLElementCollection *pColl,
|
|
ULONG *pcElems = NULL)
|
|
{
|
|
return Init( pColl, pcElems, NULL );
|
|
}
|
|
|
|
virtual HRESULT Init(IHTMLElementCollection *pColl,
|
|
ULONG *pcElems,
|
|
IHTMLDocument2 *pDoc);
|
|
|
|
protected:
|
|
|
|
virtual HRESULT _GetElementURL(IHTMLElement *pElem, BSTR *pbstrURL);
|
|
|
|
IHTMLElementCollection *m_pCollBase; // collection of BASE tags used to complete URLs
|
|
ULONG m_cBase;
|
|
BSTR m_bstrDocURL;
|
|
};
|
|
|
|
/*
|
|
* CBackgroundPackager - packages the background of BODY, TABLE, TD, and TH.
|
|
*
|
|
* These three tags have a common target attribute.
|
|
*/
|
|
|
|
class CBackgroundPackager : public CRelativeURLPackager
|
|
{
|
|
public:
|
|
CBackgroundPackager(void) {};
|
|
~CBackgroundPackager(void) {};
|
|
|
|
virtual HRESULT PackageData(CWebArchive *pwa, BOOL *pfCancel,
|
|
CThicketProgress *ptp = NULL, ULONG progLow = 0, ULONG progHigh = 100);
|
|
protected:
|
|
|
|
virtual BSTR _GetTargetAttribute(void);
|
|
};
|
|
|
|
/*
|
|
* CDynSrcPackager - packages the dynsrc of IMG and INPUT.
|
|
*
|
|
* These two tags have a common target attribute.
|
|
*/
|
|
|
|
class CDynSrcPackager : public CRelativeURLPackager
|
|
{
|
|
public:
|
|
CDynSrcPackager(void) {};
|
|
~CDynSrcPackager(void) {};
|
|
|
|
virtual HRESULT PackageData(CWebArchive *pwa, BOOL *pfCancel,
|
|
CThicketProgress *ptp = NULL, ULONG progLow = 0, ULONG progHigh = 100);
|
|
protected:
|
|
|
|
virtual BSTR _GetTargetAttribute(void);
|
|
};
|
|
|
|
|
|
/*
|
|
* CScriptPackager - packages the dynsrc of IMG and INPUT.
|
|
*
|
|
* These two tags have a common target attribute.
|
|
*/
|
|
|
|
class CScriptPackager : public CRelativeURLPackager
|
|
{
|
|
public:
|
|
CScriptPackager(void) : m_pCollScripts(NULL) {};
|
|
~CScriptPackager(void) { if (m_pCollScripts) m_pCollScripts->Release(); };
|
|
|
|
virtual HRESULT PackageData(CWebArchive *pwa, BOOL *pfCancel = NULL,
|
|
CThicketProgress *ptp = NULL, ULONG progLow = 0, ULONG progHigh = 100)
|
|
{
|
|
return _PackageData( pwa, m_pCollScripts, pfCancel, ptp, progLow, progHigh );
|
|
}
|
|
|
|
virtual HRESULT Init(IHTMLElementCollection *pColl,
|
|
ULONG *pcElems = NULL,
|
|
IHTMLDocument2 *pDoc = NULL);
|
|
protected:
|
|
|
|
virtual BSTR _GetTargetAttribute(void);
|
|
|
|
IHTMLElementCollection *m_pCollScripts;
|
|
|
|
};
|
|
|
|
|
|
/*
|
|
* CFramesPackager - packages the <FRAME> and <IFRAME> sub-documents.
|
|
*
|
|
* This process is recursive, so all nested frames will be packaged.
|
|
*/
|
|
|
|
class CFramesPackager : public CRelativeURLPackager
|
|
{
|
|
public:
|
|
CFramesPackager(void) :
|
|
m_pCollFrames(NULL),
|
|
m_pframes2(NULL),
|
|
m_cFrames(0),
|
|
m_iFrameCur(0),
|
|
m_pfCancel(0),
|
|
m_ptp(NULL),
|
|
m_uLow(0),
|
|
m_uHigh(0),
|
|
m_uRangeDoc(0) {};
|
|
|
|
virtual ~CFramesPackager(void)
|
|
{
|
|
if (m_pCollFrames) m_pCollFrames->Release();
|
|
if (m_pframes2) m_pframes2->Release();
|
|
};
|
|
|
|
virtual HRESULT InitFromCollection(IHTMLElementCollection *pColl,
|
|
ULONG *pcElems = NULL)
|
|
{
|
|
return CRelativeURLPackager::Init( pColl, pcElems, NULL );
|
|
}
|
|
|
|
virtual HRESULT Init(IHTMLElementCollection *pColl,
|
|
ULONG *pcElems,
|
|
IHTMLDocument2 *pDoc,
|
|
IHTMLDocument2 *pDocDesign,
|
|
CDocumentPackager *pdp);
|
|
|
|
virtual HRESULT PackageData(CWebArchive *pwa, BOOL *pfCancel,
|
|
CThicketProgress *ptp = NULL, ULONG progLow = 0, ULONG progHigh = 100);
|
|
|
|
protected:
|
|
|
|
virtual BSTR _GetTargetAttribute(void);
|
|
virtual HRESULT _PackageElement(CWebArchive *pwa,
|
|
IHTMLElement *pElem);
|
|
|
|
IHTMLElementCollection *m_pCollFrames;
|
|
IHTMLFramesCollection2 *m_pframes2;
|
|
ULONG m_cFrames;
|
|
ULONG m_iFrameCur;
|
|
BOOL *m_pfCancel;
|
|
CThicketProgress* m_ptp;
|
|
ULONG m_uLow;
|
|
ULONG m_uHigh;
|
|
ULONG m_uRangeDoc;
|
|
CDocumentPackager *m_pdp;
|
|
};
|
|
|
|
/*
|
|
* CSSPackager - packages imported stylesheets.
|
|
*
|
|
* Stylesheets have a different OM than document elements, so
|
|
* we have a packager that looks similar, but works differently
|
|
* than the other element packagers.
|
|
*
|
|
* We derive from CRelativeURLPackager for the convenience of
|
|
* its Init method and <BASE> collection functionality, which
|
|
* we also need because the hrefs in style sheets can be relative.
|
|
*
|
|
* Since we aren't actually packaging elments, the _GetTargetAttribute()
|
|
* implementation is a formality to satisfy the abstract base class.
|
|
*/
|
|
|
|
class CSSPackager : public CRelativeURLPackager
|
|
{
|
|
public:
|
|
CSSPackager(void) : m_pDoc(NULL) {};
|
|
~CSSPackager(void) {};
|
|
|
|
HRESULT Init( IHTMLElementCollection *pColl,
|
|
ULONG *pcElems = NULL,
|
|
IHTMLDocument2 *pDoc = NULL);
|
|
|
|
HRESULT PackageStyleSheets(IHTMLDocument2 *pDoc2, CWebArchive *pwa);
|
|
|
|
protected:
|
|
|
|
BSTR _GetTargetAttribute(void) { ASSERT(FALSE); return NULL; };
|
|
|
|
HRESULT _PackageSSCollection(IHTMLStyleSheetsCollection *pssc,
|
|
CWebArchive *pwa);
|
|
HRESULT _PackageSS(IHTMLStyleSheet *pss, CWebArchive *pwa);
|
|
|
|
IHTMLDocument2 *m_pDoc;
|
|
};
|
|
|
|
|
|
// possible hash-table sizes, chosen from primes not close to powers of 2
|
|
static const DWORD s_rgPrimes[] = { 29, 53, 97, 193, 389, 769, 1543, 3079, 6151, 12289, 24593 };
|
|
|
|
/*
|
|
* class implementation
|
|
*/
|
|
|
|
/*
|
|
* CWebArchive ##################################################
|
|
*/
|
|
|
|
CWebArchive::CWebArchive(CThicketProgress *ptp)
|
|
{
|
|
m_lpstrDoc = NULL;
|
|
m_lpstrSafeDoc = NULL;
|
|
|
|
m_cBins = 0;
|
|
m_rgBins = NULL;
|
|
|
|
m_ptp = ptp;
|
|
}
|
|
|
|
|
|
CWebArchive::~CWebArchive(void)
|
|
{
|
|
CHashEntry *phe, *pheTemp;
|
|
|
|
if (m_lpstrDoc != NULL)
|
|
{
|
|
LocalFree( m_lpstrDoc );
|
|
m_lpstrDoc = NULL;
|
|
}
|
|
|
|
if (m_lpstrSafeDoc != NULL)
|
|
{
|
|
LocalFree( m_lpstrSafeDoc );
|
|
m_lpstrSafeDoc = NULL;
|
|
}
|
|
|
|
// m_ptp is on loan to us, don't delete it
|
|
|
|
for (DWORD dw = 0; dw < m_cBins; dw++)
|
|
{
|
|
if (m_rgBins[dw].m_pheNext)
|
|
{
|
|
phe = m_rgBins[dw].m_pheNext;
|
|
while (phe)
|
|
{
|
|
pheTemp = phe;
|
|
phe = phe->m_pheNext;
|
|
delete pheTemp;
|
|
}
|
|
}
|
|
}
|
|
delete[] m_rgBins;
|
|
}
|
|
|
|
|
|
HRESULT
|
|
CWebArchive::Init( LPCTSTR lpstrDoc, DWORD dwHashSize )
|
|
{
|
|
HRESULT hr = S_OK;
|
|
int i = 0;
|
|
|
|
m_lpstrDoc = StrDup(lpstrDoc);
|
|
|
|
// check for replacement of old file
|
|
if (PathFileExists(m_lpstrDoc))
|
|
hr = _BackupOldFile();
|
|
if (FAILED(hr))
|
|
goto error;
|
|
|
|
// Initialize the hash table.
|
|
for (i = 0; i < (ARRAYSIZE(s_rgPrimes) - 1) && s_rgPrimes[i] < dwHashSize; i++);
|
|
ASSERT(s_rgPrimes[i] >= dwHashSize || i == (ARRAYSIZE(s_rgPrimes)-1));
|
|
m_cBins = s_rgPrimes[i];
|
|
|
|
m_rgBins = new CHashEntry[m_cBins];
|
|
if (m_rgBins==NULL)
|
|
hr = E_OUTOFMEMORY;
|
|
|
|
error:
|
|
|
|
RRETURN(hr);
|
|
}
|
|
|
|
|
|
HRESULT
|
|
CWebArchive::Commit()
|
|
{
|
|
// clean up old version of file
|
|
if (m_lpstrSafeDoc)
|
|
DeleteFile(m_lpstrSafeDoc);
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
HRESULT
|
|
CWebArchive::Revert()
|
|
{
|
|
if (m_lpstrSafeDoc)
|
|
{
|
|
// we used to use MoveFileEx with MOVEFILE_REPLACE_EXISTING, but MoveFileEx
|
|
// doesn't work on Win9x... so we have to DeleteFile/MoveFile instead...
|
|
|
|
DeleteFile(m_lpstrDoc);
|
|
BOOL fMoved = MoveFile(m_lpstrSafeDoc, m_lpstrDoc);
|
|
|
|
if (!fMoved)
|
|
{
|
|
ASSERT(FALSE);
|
|
// We shouldn't get into this situtation because we've pre-checked that
|
|
// the original file is not read-only.
|
|
DeleteFile(m_lpstrSafeDoc);
|
|
}
|
|
}
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
CWebArchive::ThURLType
|
|
CWebArchive::_GetURLType( BSTR bstrURL )
|
|
{
|
|
// _tcsncmpi(bstrURL, 4, _T("http",4)
|
|
if ( bstrURL[0] == TEXT('h') &&
|
|
bstrURL[1] == TEXT('t') &&
|
|
bstrURL[2] == TEXT('t') &&
|
|
bstrURL[3] == TEXT('p') )
|
|
return thurlHttp;
|
|
else if ( bstrURL[0] == TEXT('f') &&
|
|
bstrURL[1] == TEXT('i') &&
|
|
bstrURL[2] == TEXT('l') &&
|
|
bstrURL[3] == TEXT('e') )
|
|
return thurlFile;
|
|
else
|
|
return thurlMisc;
|
|
}
|
|
|
|
|
|
|
|
HRESULT
|
|
CWebArchive::_Insert(BSTR bstrI, BSTR bstrThicket, CHashEntry **pphe )
|
|
{
|
|
HRESULT hr = S_OK;
|
|
|
|
CHashEntry *phe = &m_rgBins[Hash(bstrI)];
|
|
|
|
ASSERT(pphe != NULL);
|
|
|
|
*pphe = NULL;
|
|
|
|
|
|
if (phe->m_bstrKey)
|
|
{
|
|
CHashEntry *pheNew = new CHashEntry;
|
|
|
|
if (pheNew==NULL)
|
|
return E_OUTOFMEMORY;
|
|
|
|
if (pheNew->SetKey(bstrI) && pheNew->SetValue(bstrThicket))
|
|
*pphe = pheNew;
|
|
else
|
|
{
|
|
delete pheNew;
|
|
hr = E_OUTOFMEMORY;
|
|
goto Cleanup;
|
|
}
|
|
|
|
pheNew->m_pheNext = phe->m_pheNext;
|
|
phe->m_pheNext = pheNew;
|
|
phe = pheNew;
|
|
}
|
|
else if (phe->SetKey(bstrI) && phe->SetValue(bstrThicket))
|
|
*pphe = phe;
|
|
else
|
|
hr = E_OUTOFMEMORY;
|
|
|
|
Cleanup:
|
|
|
|
return hr;
|
|
}
|
|
|
|
HRESULT
|
|
CWebArchive::Find(BSTR bstrF, CHashEntry **pphe)
|
|
{
|
|
CHashEntry *phe = &m_rgBins[Hash(bstrF)];
|
|
|
|
if (!pphe)
|
|
return E_POINTER;
|
|
|
|
*pphe = NULL;
|
|
|
|
if (phe->m_bstrKey)
|
|
{
|
|
do
|
|
{
|
|
if (!StrCmpW(phe->m_bstrKey, bstrF))
|
|
{
|
|
ASSERT(phe->m_bstrValue!=NULL);
|
|
*pphe = phe;
|
|
return NOERROR;
|
|
}
|
|
phe = phe->m_pheNext;
|
|
}
|
|
while (phe);
|
|
}
|
|
return E_INVALIDARG;
|
|
}
|
|
|
|
|
|
DWORD
|
|
CWebArchive::Hash(BSTR bstr)
|
|
{
|
|
DWORD h = 0;
|
|
WCHAR *pwch = bstr;
|
|
|
|
while (*pwch)
|
|
h = ((h << 4) + *pwch++ + (h >> 28));
|
|
return (h % m_cBins);
|
|
}
|
|
|
|
HRESULT
|
|
CWebArchive::_BackupOldFile()
|
|
{
|
|
HRESULT hr = S_OK;
|
|
TCHAR chT;
|
|
LPTSTR lpstrT;
|
|
TCHAR szT[MAX_PATH];
|
|
DWORD dwAttrib = GetFileAttributes(m_lpstrDoc);
|
|
|
|
if (dwAttrib & FILE_ATTRIBUTE_READONLY)
|
|
return E_ACCESSDENIED;
|
|
|
|
lpstrT = PathFindFileName(m_lpstrDoc);
|
|
ASSERT(lpstrT);
|
|
|
|
lpstrT--; // back up to the slash
|
|
chT = *lpstrT;
|
|
*lpstrT = 0;
|
|
if (GetTempFileName( m_lpstrDoc, &lpstrT[1], 0,szT ))
|
|
{
|
|
*lpstrT = chT;
|
|
if (CopyFile(m_lpstrDoc, szT, FALSE))
|
|
{
|
|
int cchSafeDoc = lstrlen(szT) + 1;
|
|
m_lpstrSafeDoc = (LPTSTR)LocalAlloc( LMEM_FIXED, sizeof(TCHAR) * cchSafeDoc);
|
|
if (m_lpstrSafeDoc)
|
|
StrCpyN(m_lpstrSafeDoc, szT, cchSafeDoc);
|
|
else
|
|
{
|
|
hr = E_OUTOFMEMORY;
|
|
DeleteFile(szT);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
hr = HRESULT_FROM_WIN32(GetLastError());
|
|
goto error;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
|
|
hr = HRESULT_FROM_WIN32(GetLastError());
|
|
goto error;
|
|
}
|
|
|
|
error:
|
|
*lpstrT = chT;
|
|
RRETURN(hr);
|
|
}
|
|
|
|
/*
|
|
* CThicketArchive ##################################################
|
|
*/
|
|
|
|
CThicketArchive::CThicketArchive(CThicketProgress *ptp) : CWebArchive(ptp)
|
|
{
|
|
m_lpstrFilesDir = NULL;
|
|
m_lpstrFilesDirName = NULL;
|
|
m_lpstrSafeDir = NULL;
|
|
m_fFilesDir = FALSE; // TRUE when m_lpstrFilesDir has been created
|
|
}
|
|
|
|
|
|
CThicketArchive::~CThicketArchive(void)
|
|
{
|
|
if (m_lpstrFilesDir != NULL)
|
|
{
|
|
LocalFree( m_lpstrFilesDir );
|
|
m_lpstrFilesDir = NULL;
|
|
}
|
|
|
|
if (m_lpstrSafeDir != NULL)
|
|
{
|
|
LocalFree( m_lpstrSafeDir );
|
|
m_lpstrSafeDir = NULL;
|
|
}
|
|
|
|
// m_lpstrFilesDirName points into m_lpstrFilesDir
|
|
}
|
|
|
|
|
|
HRESULT
|
|
CThicketArchive::Init( LPCTSTR lpstrDoc, DWORD dwHashSize )
|
|
{
|
|
HRESULT hr = CWebArchive::Init( lpstrDoc, dwHashSize );
|
|
int i = 0;
|
|
TCHAR chT;
|
|
LPTSTR lpstrT;
|
|
TCHAR szFmt[MAX_PATH];
|
|
int cch;
|
|
|
|
if (FAILED(hr))
|
|
goto error;
|
|
|
|
// Build the path to the directory for stored files, like 'Document1 files'.
|
|
lpstrT = PathFindExtension(m_lpstrDoc);
|
|
chT = *lpstrT;
|
|
*lpstrT = 0;
|
|
MLLoadString(IDS_THICKETDIRFMT, szFmt, ARRAYSIZE(szFmt));
|
|
cch = lstrlen(m_lpstrDoc) + lstrlen(szFmt) + 1;
|
|
m_lpstrFilesDir = (LPTSTR)LocalAlloc( LMEM_FIXED, sizeof(TCHAR) * cch );
|
|
if (m_lpstrFilesDir==NULL)
|
|
{
|
|
hr = E_OUTOFMEMORY;
|
|
goto error;
|
|
}
|
|
|
|
StrCpyN( m_lpstrFilesDir, m_lpstrDoc, cch);
|
|
StrCatBuff( m_lpstrFilesDir, szFmt, cch );
|
|
|
|
*lpstrT = chT;
|
|
|
|
// make m_lpstrFilesDirName point to the last component of m_lpstrFilesDir
|
|
for ( i = lstrlen(m_lpstrFilesDir) - 1; i > 0 && m_lpstrFilesDirName == NULL; i-- )
|
|
{
|
|
if ( m_lpstrFilesDir[i-1] == FILENAME_SEPARATOR )
|
|
m_lpstrFilesDirName = &m_lpstrFilesDir[i];
|
|
}
|
|
|
|
// check to see if the files dir already exists. If it does, rename the original.
|
|
if (PathFileExists(m_lpstrFilesDir))
|
|
hr = _BackupOldDirectory();
|
|
if (FAILED(hr))
|
|
goto error;
|
|
|
|
error:
|
|
|
|
RRETURN(hr);
|
|
}
|
|
|
|
|
|
HRESULT
|
|
CThicketArchive::AddURL( BSTR bstrURL, CHashEntry **pphe )
|
|
{
|
|
HRESULT hr;
|
|
|
|
hr = THR(Find(bstrURL, pphe));
|
|
|
|
if (FAILED(hr))
|
|
{
|
|
// first, lets put our document dir in place, if it isn't already
|
|
if (!m_fFilesDir)
|
|
m_fFilesDir = (SHCreateDirectory(NULL, m_lpstrFilesDir) == ERROR_SUCCESS);
|
|
|
|
if (m_fFilesDir)
|
|
{
|
|
switch (_GetURLType(bstrURL))
|
|
{
|
|
case thurlMisc:
|
|
hr = _PersistMiscURL(bstrURL, pphe);
|
|
break;
|
|
|
|
case thurlHttp:
|
|
hr = _PersistHttpURL(bstrURL, pphe);
|
|
break;
|
|
|
|
case thurlFile:
|
|
hr = _PersistFileURL(bstrURL, pphe);
|
|
break;
|
|
}
|
|
}
|
|
else
|
|
hr = E_FAIL;
|
|
}
|
|
|
|
RRETURN(hr);
|
|
}
|
|
|
|
HRESULT
|
|
CThicketArchive::AddFrameOrStyleEntry( BSTR bstrURL, CHashEntry **pphe, LPTSTR lpstrFrameDoc )
|
|
{
|
|
HRESULT hr;
|
|
|
|
hr = THR(Find(bstrURL, pphe)); // there's always a slim chance we're reusing a frame.
|
|
|
|
if (FAILED(hr))
|
|
{
|
|
// first, lets put our document dir in place, if it isn't already
|
|
if (!m_fFilesDir)
|
|
m_fFilesDir = (SHCreateDirectory(NULL, m_lpstrFilesDir) == ERROR_SUCCESS);
|
|
|
|
if (m_fFilesDir)
|
|
{
|
|
switch (_GetURLType(bstrURL))
|
|
{
|
|
case thurlMisc:
|
|
//hr = _AddMiscEntry(bstrURL, pphe, lpstrFrameDoc);
|
|
// It would be nice if we could just _AddMiscEntry, but if set a frame src
|
|
// to one of the temp files that this produces, we get a 'Do you want to open'
|
|
// prompt, so instead, we'll just keep this funky protocol URL.
|
|
hr = CWebArchive::_Insert( bstrURL, bstrURL, pphe );
|
|
lpstrFrameDoc[0] = 0; // shouldn't be used, anyway
|
|
hr = S_FALSE; // I told him we all-reddy got one! <snicker>
|
|
break;
|
|
|
|
case thurlHttp:
|
|
hr = _AddHttpEntry(bstrURL, pphe, lpstrFrameDoc);
|
|
break;
|
|
|
|
case thurlFile:
|
|
hr = _AddFileEntry(bstrURL, pphe, lpstrFrameDoc);
|
|
break;
|
|
}
|
|
|
|
if (m_ptp)
|
|
m_ptp->SetSaving( PathFindFileName(lpstrFrameDoc), m_lpstrFilesDir );
|
|
|
|
}
|
|
else
|
|
{
|
|
hr = (GetLastError() == ERROR_DISK_FULL) ? (HRESULT_FROM_WIN32(ERROR_DISK_FULL))
|
|
: (E_FAIL);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
LPTSTR lpszThicket;
|
|
lpszThicket = (*pphe)->m_bstrValue;
|
|
PathCombine( lpstrFrameDoc, m_lpstrFilesDir, lpszThicket );
|
|
hr = S_FALSE;
|
|
}
|
|
|
|
return hr; // no RRETURN - may return S_FALSE
|
|
}
|
|
|
|
HRESULT
|
|
CThicketArchive::Commit()
|
|
{
|
|
CWebArchive::Commit();
|
|
|
|
// clean up obsolete files dir.
|
|
if (m_lpstrSafeDir)
|
|
{
|
|
_RemoveOldDirectoryAndChildren(m_lpstrSafeDir);
|
|
}
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
HRESULT
|
|
CThicketArchive::Revert()
|
|
{
|
|
// clean up file dir
|
|
|
|
_RemoveOldDirectoryAndChildren(m_lpstrFilesDir);
|
|
|
|
// restore old files dir.
|
|
if (m_lpstrSafeDir)
|
|
MoveFile(m_lpstrSafeDir,m_lpstrFilesDir);
|
|
|
|
return CWebArchive::Revert();;
|
|
}
|
|
|
|
HRESULT CThicketArchive::ArchiveDocumentText(IHTMLDocument2 *pDoc, UINT cpDoc, BOOL fFrameDoc)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
IPersistStreamInit* ppsi = NULL;
|
|
IStream* pstm = NULL;
|
|
|
|
hr = SHCreateStreamOnFile(m_lpstrDoc, STGM_WRITE | STGM_CREATE, &pstm);
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
hr = pDoc->QueryInterface(IID_IPersistStreamInit, (void**)&ppsi);
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
hr = _ApplyMarkOfTheWeb( pDoc, pstm, cpDoc == CP_UNICODE );
|
|
|
|
if ( SUCCEEDED(hr) )
|
|
hr = ppsi->Save(pstm, FALSE);
|
|
}
|
|
}
|
|
|
|
ReleaseInterface(ppsi);
|
|
ReleaseInterface(pstm);
|
|
|
|
RRETURN(hr);
|
|
}
|
|
|
|
HRESULT CThicketArchive::ArchiveCSSText( BSTR bstrCSSUrl, LPCSTR lpszSSText, LPCTSTR lpszStyleDoc )
|
|
{
|
|
HRESULT hr = S_OK;
|
|
HANDLE hfile;
|
|
|
|
hfile = CreateFile( lpszStyleDoc, GENERIC_WRITE, FILE_SHARE_READ, NULL,
|
|
CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
|
|
|
|
if (hfile!=INVALID_HANDLE_VALUE)
|
|
{
|
|
ULONG cbWrite, cbWritten;
|
|
|
|
cbWrite = lstrlenA(lpszSSText);
|
|
if (!WriteFile( hfile, lpszSSText, cbWrite, &cbWritten, NULL ))
|
|
hr = HRESULT_FROM_WIN32(GetLastError());
|
|
|
|
CloseHandle(hfile);
|
|
}
|
|
else
|
|
hr = HRESULT_FROM_WIN32(hr);
|
|
|
|
return hr;
|
|
}
|
|
|
|
EXTERN_C HRESULT GetMarkOfTheWeb( LPCSTR, LPCSTR, DWORD, LPSTR *);
|
|
|
|
HRESULT CThicketArchive::_ApplyMarkOfTheWeb( IHTMLDocument2 *pDoc, LPSTREAM pstm, BOOL fUnicode )
|
|
{
|
|
HRESULT hr;
|
|
IInternetSecurityManager *pism = NULL;
|
|
DWORD dwZone;
|
|
BSTR bstrURL = NULL;
|
|
|
|
hr = pDoc->get_URL( &bstrURL );
|
|
if (FAILED(hr))
|
|
return hr;
|
|
|
|
// We only want to mark the document if it isn't already coming from the local
|
|
// file system. If ( minus the mark ) the file is in the local machine zone,
|
|
// then it was made here, saved with a mark, or created outside our control.
|
|
// If it was saved with a mark, then we want to leave that in place, rather
|
|
// than mark it with the local copy's file: URL.
|
|
|
|
hr = CoInternetCreateSecurityManager( NULL, &pism, 0 );
|
|
if (SUCCEEDED(hr) &&
|
|
SUCCEEDED(pism->MapUrlToZone( bstrURL, &dwZone, MUTZ_NOSAVEDFILECHECK)) &&
|
|
dwZone != URLZONE_LOCAL_MACHINE )
|
|
{
|
|
LPSTR pszMark;
|
|
DWORD cchURL = WideCharToMultiByte(CP_ACP, 0, bstrURL, -1, NULL, 0, NULL, NULL);
|
|
LPSTR pszURL = new CHAR[cchURL];
|
|
|
|
if (pszURL)
|
|
{
|
|
if (WideCharToMultiByte(CP_ACP, 0, bstrURL, -1, pszURL, cchURL, NULL, NULL))
|
|
{
|
|
int cch = lstrlen(m_lpstrDoc) + 1;
|
|
LPSTR psz = new char[cch];
|
|
|
|
if (psz)
|
|
{
|
|
SHUnicodeToAnsi(m_lpstrDoc, psz, cch);
|
|
|
|
hr = GetMarkOfTheWeb( pszURL, psz, 0, &pszMark);
|
|
|
|
delete [] psz;
|
|
}
|
|
else
|
|
{
|
|
hr = E_OUTOFMEMORY;
|
|
}
|
|
|
|
|
|
IMarkupServices *pims = NULL;
|
|
IMarkupPointer *pimp = NULL;
|
|
IMarkupContainer *pimc = NULL;
|
|
IHTMLElement *pihe = NULL;
|
|
IHTMLElement *piheBody = NULL;
|
|
IDispatch *pidDocument = NULL;
|
|
IHTMLCommentElement *pihce = NULL;
|
|
LPWSTR pwszMark = NULL;
|
|
BSTR bstrMark = NULL;
|
|
|
|
hr = pDoc->QueryInterface(IID_IMarkupServices, (void **)&pims);
|
|
|
|
if (SUCCEEDED(hr)) {
|
|
hr = pims->CreateElement(TAGID_COMMENT, NULL, &pihe);
|
|
|
|
if (SUCCEEDED(hr)) {
|
|
hr = pihe->QueryInterface(IID_IHTMLCommentElement, (void **)&pihce);
|
|
}
|
|
|
|
if (SUCCEEDED(hr)) {
|
|
int cbWrite = 0;
|
|
int cchMark = MultiByteToWideChar(CP_ACP, 0, pszMark, -1, NULL, 0);
|
|
|
|
// cchMark includes the null terminator.
|
|
|
|
pwszMark = new WCHAR[cchMark];
|
|
if ( pwszMark != NULL )
|
|
{
|
|
MultiByteToWideChar( CP_ACP, 0, pszMark, -1, pwszMark, cchMark);
|
|
cbWrite = (cchMark - 1) * sizeof(WCHAR);
|
|
}
|
|
else
|
|
{
|
|
hr = E_OUTOFMEMORY;
|
|
}
|
|
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
// force <!-- ... --> style comment
|
|
hr = pihce->put_atomic(1);
|
|
}
|
|
|
|
}
|
|
|
|
if (SUCCEEDED(hr)) {
|
|
bstrMark = SysAllocString(pwszMark);
|
|
if (NULL != bstrMark)
|
|
{
|
|
hr = pihce->put_text(bstrMark);
|
|
}
|
|
else
|
|
{
|
|
hr = E_OUTOFMEMORY;
|
|
}
|
|
|
|
}
|
|
|
|
if (SUCCEEDED(hr)) {
|
|
hr = pims->CreateMarkupPointer(&pimp);
|
|
}
|
|
|
|
if (SUCCEEDED(hr)) {
|
|
hr = pDoc->get_body(&piheBody);
|
|
}
|
|
|
|
if (SUCCEEDED(hr)) {
|
|
hr = piheBody->get_document(&pidDocument);
|
|
}
|
|
|
|
if (SUCCEEDED(hr)) {
|
|
hr = pidDocument->QueryInterface(IID_IMarkupContainer, (void **)&pimc);
|
|
}
|
|
|
|
if (SUCCEEDED(hr)) {
|
|
// Move to beginning of doc and insert it
|
|
hr = pimp->MoveToContainer(pimc, TRUE);
|
|
|
|
if (SUCCEEDED(hr)) {
|
|
hr = pims->InsertElement(pihe, pimp, pimp);
|
|
}
|
|
}
|
|
}
|
|
|
|
SAFERELEASE(pims);
|
|
SAFERELEASE(pimc);
|
|
SAFERELEASE(pihe);
|
|
SAFERELEASE(pimp);
|
|
SAFERELEASE(piheBody);
|
|
SAFERELEASE(pidDocument);
|
|
SAFERELEASE(pihce);
|
|
|
|
if (bstrMark)
|
|
{
|
|
SysFreeString(bstrMark);
|
|
}
|
|
|
|
if (pwszMark)
|
|
{
|
|
delete[] pwszMark;
|
|
}
|
|
}
|
|
else
|
|
hr = HRESULT_FROM_WIN32(GetLastError());
|
|
|
|
delete[] pszURL;
|
|
}
|
|
else
|
|
hr = E_OUTOFMEMORY;
|
|
}
|
|
|
|
|
|
|
|
ReleaseInterface(pism);
|
|
if (bstrURL)
|
|
SysFreeString(bstrURL);
|
|
|
|
return hr;
|
|
}
|
|
|
|
HRESULT
|
|
CThicketArchive::_AddHttpEntry( BSTR bstrURL, CHashEntry **pphe, LPTSTR lpstrDstFile, LPTSTR lpstrSrcFile )
|
|
{
|
|
HRESULT hr;
|
|
TCHAR szCacheFile[MAX_PATH];
|
|
LPTSTR lpszDst;
|
|
LPTSTR lpszFile;
|
|
int cchFile;
|
|
LPTSTR lpszURL;
|
|
|
|
lpszURL = bstrURL;
|
|
|
|
hr = URLDownloadToCacheFile(NULL, lpszURL, szCacheFile,
|
|
ARRAYSIZE(szCacheFile), BINDF_FWD_BACK,
|
|
NULL);
|
|
if (FAILED(hr))
|
|
goto Cleanup;
|
|
|
|
if (lpstrSrcFile)
|
|
StrCpyN(lpstrSrcFile, szCacheFile, MAX_PATH);
|
|
|
|
PathUndecorate( szCacheFile );
|
|
|
|
lpszFile = PathFindFileName( szCacheFile );
|
|
ASSERT(lpszFile != NULL);
|
|
|
|
cchFile = ARRAYSIZE(szCacheFile) - (int)(lpszFile-szCacheFile);
|
|
|
|
hr = _Insert( bstrURL, lpszFile, cchFile, pphe );
|
|
|
|
lpszDst = PathCombine( lpstrDstFile, m_lpstrFilesDir, lpszFile );
|
|
ASSERT( lpszDst );
|
|
|
|
Cleanup:
|
|
|
|
RRETURN(hr);
|
|
}
|
|
|
|
|
|
HRESULT
|
|
CThicketArchive::_AddFileEntry( BSTR bstrURL, CHashEntry **pphe, LPTSTR lpstrDstFile, LPTSTR lpstrSrcFile )
|
|
{
|
|
HRESULT hr;
|
|
LPTSTR lpszDst;
|
|
LPTSTR lpszFile;
|
|
int cchFile;
|
|
LPTSTR lpszPath;
|
|
WCHAR rgchUrlPath[MAX_PATH];
|
|
DWORD dwLen;
|
|
|
|
dwLen = ARRAYSIZE(rgchUrlPath);
|
|
|
|
hr = PathCreateFromUrlW(bstrURL, rgchUrlPath, &dwLen, 0);
|
|
if (FAILED(hr))
|
|
return E_FAIL;
|
|
|
|
lpszPath = rgchUrlPath;
|
|
|
|
if (lpstrSrcFile)
|
|
StrCpyN( lpstrSrcFile, lpszPath, MAX_PATH );
|
|
|
|
lpszFile = PathFindFileName( lpszPath );
|
|
ASSERT(lpszFile != NULL);
|
|
cchFile = ARRAYSIZE(rgchUrlPath) - (int)(lpszFile-rgchUrlPath);
|
|
|
|
hr = THR(_Insert( bstrURL, lpszFile, cchFile, pphe ));
|
|
|
|
lpszDst = PathCombine( lpstrDstFile, m_lpstrFilesDir, lpszFile );
|
|
ASSERT( lpszDst );
|
|
|
|
RRETURN(hr);
|
|
}
|
|
|
|
HRESULT
|
|
CThicketArchive::_AddMiscEntry( BSTR bstrURL, CHashEntry **pphe, LPTSTR lpstrDstFile, int cchDstFile )
|
|
{
|
|
HRESULT hr;
|
|
TCHAR szT[MAX_PATH];
|
|
LPTSTR lpszPrefix;
|
|
LPTSTR lpszDst;
|
|
|
|
lpszPrefix = bstrURL;
|
|
|
|
if (GetTempFileName( m_lpstrFilesDir, lpszPrefix, 0,szT ))
|
|
{
|
|
lpszDst = PathCombine( lpstrDstFile, m_lpstrFilesDir, szT );
|
|
ASSERT(lpszDst);
|
|
|
|
LPTSTR pszFile = PathFindFileName(lpstrDstFile);
|
|
hr = THR(_Insert( bstrURL, pszFile, cchDstFile - (int)(pszFile-lpstrDstFile), pphe ));
|
|
}
|
|
else
|
|
hr = HRESULT_FROM_WIN32(GetLastError());
|
|
|
|
RRETURN(hr);
|
|
}
|
|
|
|
HRESULT
|
|
CThicketArchive::_PersistHttpURL( BSTR bstrURL, CHashEntry **pphe )
|
|
{
|
|
HRESULT hr;
|
|
TCHAR szDst[MAX_PATH];
|
|
TCHAR szSrc[MAX_PATH];
|
|
|
|
hr = THR(_AddHttpEntry( bstrURL, pphe, szDst, szSrc ));
|
|
if (FAILED(hr))
|
|
goto Error;
|
|
|
|
if (m_ptp)
|
|
m_ptp->SetSaving( PathFindFileName(szSrc), m_lpstrFilesDir );
|
|
|
|
if (!CopyFile(szSrc,szDst, FALSE))
|
|
hr = HRESULT_FROM_WIN32(GetLastError());
|
|
|
|
Error:
|
|
RRETURN(hr);
|
|
}
|
|
|
|
HRESULT
|
|
CThicketArchive::_PersistFileURL( BSTR bstrURL, CHashEntry **pphe )
|
|
{
|
|
HRESULT hr;
|
|
TCHAR szDst[MAX_PATH];
|
|
TCHAR szSrc[MAX_PATH];
|
|
|
|
hr = THR(_AddFileEntry( bstrURL, pphe, szDst, szSrc ));
|
|
if (FAILED(hr))
|
|
goto Error;
|
|
|
|
if (m_ptp)
|
|
m_ptp->SetSaving( PathFindFileName(szSrc), m_lpstrFilesDir );
|
|
|
|
if (!CopyFile(szSrc,szDst, FALSE))
|
|
hr = HRESULT_FROM_WIN32(GetLastError());
|
|
|
|
Error:
|
|
RRETURN(hr);
|
|
}
|
|
|
|
HRESULT
|
|
CThicketArchive::_PersistMiscURL( BSTR bstrURL, CHashEntry **pphe )
|
|
{
|
|
HRESULT hr;
|
|
TCHAR szDst[MAX_PATH];
|
|
LPTSTR lpszURL;
|
|
|
|
lpszURL = bstrURL;
|
|
|
|
hr = THR(_AddMiscEntry( bstrURL, pphe, szDst, ARRAYSIZE(szDst) ));
|
|
if (FAILED(hr))
|
|
goto Error;
|
|
|
|
if (m_ptp)
|
|
m_ptp->SetSaving( PathFindFileName(szDst), m_lpstrFilesDir );
|
|
|
|
hr = URLDownloadToFile(NULL, lpszURL, szDst,0, NULL);
|
|
|
|
Error:
|
|
RRETURN(hr);
|
|
}
|
|
|
|
|
|
HRESULT
|
|
CThicketArchive::_Insert(BSTR bstrI, LPTSTR lpszFile, int cchFile, CHashEntry **pphe )
|
|
{
|
|
HRESULT hr = S_OK;
|
|
BSTR bstrThicket = NULL;
|
|
TCHAR buf[MAX_PATH];
|
|
int i = 0;
|
|
|
|
CHashEntry *phe = &m_rgBins[Hash(bstrI)];
|
|
|
|
ASSERT(pphe != NULL);
|
|
|
|
*pphe = NULL;
|
|
|
|
if (lstrlen(m_lpstrFilesDir) + lstrlen(lpszFile) + 1 < MAX_PATH)
|
|
wnsprintf( buf, ARRAYSIZE(buf), TEXT("%s") TEXT(FILENAME_SEPARATOR_STR) TEXT("%s"), m_lpstrFilesDir, lpszFile );
|
|
else
|
|
{
|
|
hr = E_FAIL;
|
|
goto Cleanup;
|
|
}
|
|
|
|
// Defend against bug 18160 - collision of file names in the thicket.
|
|
if ( PathFileExists(buf) )
|
|
{
|
|
TCHAR *pszExt = PathFindExtension(lpszFile);
|
|
int i = 0;
|
|
|
|
// chop the file name into name and extenstion
|
|
if ( pszExt )
|
|
{
|
|
*pszExt = 0;
|
|
pszExt++;
|
|
}
|
|
|
|
do
|
|
{
|
|
i++;
|
|
|
|
if ( pszExt )
|
|
wnsprintf( buf, ARRAYSIZE(buf), TEXT("%s") TEXT(FILENAME_SEPARATOR_STR) TEXT("%s(%d).%s"), m_lpstrFilesDir, lpszFile, i, pszExt );
|
|
else
|
|
wnsprintf( buf, ARRAYSIZE(buf), TEXT("%s") TEXT(FILENAME_SEPARATOR_STR) TEXT("%s(%d)"), m_lpstrFilesDir, lpszFile, i );
|
|
|
|
} while ( PathFileExists(buf) && i < 1000 );
|
|
|
|
|
|
// deviously rewrite the file name for the caller
|
|
StrCpyN( lpszFile, PathFindFileName(buf), cchFile );
|
|
}
|
|
else
|
|
wnsprintf( buf, ARRAYSIZE(buf), TEXT("%s/%s"), m_lpstrFilesDirName, lpszFile );
|
|
|
|
bstrThicket = SysAllocString(buf);
|
|
if (bstrThicket == NULL)
|
|
{
|
|
hr = E_OUTOFMEMORY;
|
|
goto Cleanup;
|
|
}
|
|
|
|
if (phe->m_bstrKey)
|
|
{
|
|
CHashEntry *pheNew = new CHashEntry;
|
|
|
|
if (pheNew==NULL)
|
|
return E_OUTOFMEMORY;
|
|
|
|
if (pheNew->SetKey(bstrI) && pheNew->SetValue(bstrThicket))
|
|
*pphe = pheNew;
|
|
else
|
|
{
|
|
delete pheNew;
|
|
hr = E_OUTOFMEMORY;
|
|
goto Cleanup;
|
|
}
|
|
|
|
pheNew->m_pheNext = phe->m_pheNext;
|
|
phe->m_pheNext = pheNew;
|
|
phe = pheNew;
|
|
}
|
|
else if (phe->SetKey(bstrI) && phe->SetValue(bstrThicket))
|
|
*pphe = phe;
|
|
else
|
|
hr = E_OUTOFMEMORY;
|
|
|
|
Cleanup:
|
|
if (bstrThicket)
|
|
SysFreeString(bstrThicket);
|
|
|
|
return hr;
|
|
}
|
|
|
|
|
|
HRESULT
|
|
CThicketArchive::_BackupOldDirectory()
|
|
{
|
|
int n = 1;
|
|
HRESULT hr = S_OK;
|
|
TCHAR szFmt[MAX_PATH];
|
|
|
|
// Do we need to do this under critical section?
|
|
MLLoadString(IDS_THICKETTEMPFMT, szFmt, ARRAYSIZE(szFmt));
|
|
|
|
do {
|
|
if (m_lpstrSafeDir)
|
|
{
|
|
LocalFree( m_lpstrSafeDir );
|
|
m_lpstrSafeDir = NULL;
|
|
}
|
|
|
|
if (n > 100) // avoid infinite loop!
|
|
break;
|
|
|
|
DWORD cchSafeDir = lstrlen(m_lpstrFilesDir) + lstrlen(szFmt) + 1;
|
|
m_lpstrSafeDir = (LPTSTR)LocalAlloc( LMEM_FIXED, sizeof(TCHAR) * cchSafeDir );
|
|
if (m_lpstrSafeDir!=NULL)
|
|
{
|
|
wnsprintf( m_lpstrSafeDir, cchSafeDir, szFmt, m_lpstrFilesDir, n++ );
|
|
}
|
|
else
|
|
hr = E_OUTOFMEMORY;
|
|
|
|
} while (SUCCEEDED(hr) && GetFileAttributes(m_lpstrSafeDir) != -1 && n < 1000);
|
|
|
|
// rename the old version of the supporting files directory
|
|
if (SUCCEEDED(hr) && !MoveFile(m_lpstrFilesDir, m_lpstrSafeDir))
|
|
{
|
|
LocalFree( m_lpstrSafeDir );
|
|
m_lpstrSafeDir = NULL;
|
|
|
|
hr = HRESULT_FROM_WIN32(GetLastError());
|
|
}
|
|
|
|
RRETURN(hr);
|
|
}
|
|
|
|
HRESULT
|
|
CThicketArchive::_RemoveOldDirectoryAndChildren( LPCWSTR pwzDir )
|
|
{
|
|
HRESULT hr = S_OK;
|
|
HANDLE hf = INVALID_HANDLE_VALUE;
|
|
WCHAR wzBuf[MAX_PATH];
|
|
WIN32_FIND_DATAW fd;
|
|
|
|
if (!pwzDir)
|
|
goto Exit;
|
|
|
|
if (RemoveDirectoryW(pwzDir))
|
|
goto Exit;
|
|
|
|
// FindNextFile returns 120, not implemented on OSR2, so we'll have to do all
|
|
// this stuff multibyte
|
|
|
|
StrCpyNW(wzBuf, pwzDir, ARRAYSIZE(wzBuf));
|
|
StrCatBuffW(wzBuf, FILENAME_SEPARATOR_STR_W L"*", ARRAYSIZE(wzBuf));
|
|
|
|
if ((hf = FindFirstFileW(wzBuf, &fd)) == INVALID_HANDLE_VALUE) {
|
|
hr = HRESULT_FROM_WIN32(GetLastError());
|
|
goto Exit;
|
|
}
|
|
|
|
do {
|
|
|
|
if ( (StrCmpW(fd.cFileName, L".") == 0) ||
|
|
(StrCmpW(fd.cFileName, L"..") == 0))
|
|
continue;
|
|
|
|
wnsprintfW(wzBuf, ARRAYSIZE(wzBuf), L"%s" FILENAME_SEPARATOR_STR_W L"%s", pwzDir, fd.cFileName);
|
|
|
|
if (fd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
|
|
|
|
SetFileAttributesW(wzBuf,
|
|
FILE_ATTRIBUTE_DIRECTORY|FILE_ATTRIBUTE_NORMAL);
|
|
|
|
if (FAILED((hr=_RemoveOldDirectoryAndChildren(wzBuf)))) {
|
|
goto Exit;
|
|
}
|
|
|
|
} else {
|
|
|
|
SetFileAttributesW(wzBuf, FILE_ATTRIBUTE_NORMAL);
|
|
if (!DeleteFileW(wzBuf)) {
|
|
hr = HRESULT_FROM_WIN32(GetLastError());
|
|
goto Exit;
|
|
}
|
|
}
|
|
|
|
|
|
} while (FindNextFileW(hf, &fd));
|
|
|
|
|
|
if (GetLastError() != ERROR_NO_MORE_FILES) {
|
|
|
|
hr = HRESULT_FROM_WIN32(GetLastError());
|
|
goto Exit;
|
|
}
|
|
|
|
if (hf != INVALID_HANDLE_VALUE) {
|
|
FindClose(hf);
|
|
hf = INVALID_HANDLE_VALUE;
|
|
}
|
|
|
|
// here if all subdirs/children removed
|
|
/// re-attempt to remove the main dir
|
|
if (!RemoveDirectoryW(pwzDir)) {
|
|
hr = HRESULT_FROM_WIN32(GetLastError());
|
|
goto Exit;
|
|
}
|
|
|
|
Exit:
|
|
|
|
if (hf != INVALID_HANDLE_VALUE)
|
|
FindClose(hf);
|
|
|
|
RRETURN(hr);
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
* CMHTMLArchive ##################################################
|
|
*/
|
|
|
|
CMHTMLArchive::CMHTMLArchive(CThicketProgress *ptp) :
|
|
CWebArchive(ptp),
|
|
m_hBodyAlt(NULL),
|
|
m_pimm(NULL)
|
|
{
|
|
}
|
|
|
|
|
|
CMHTMLArchive::~CMHTMLArchive(void)
|
|
{
|
|
ReleaseInterface(m_pimm);
|
|
}
|
|
|
|
|
|
HRESULT
|
|
CMHTMLArchive::Init( LPCTSTR lpstrDoc, DWORD dwHashSize )
|
|
{
|
|
HRESULT hr = S_OK;
|
|
|
|
MimeOleSetCompatMode(MIMEOLE_COMPAT_MLANG2);
|
|
|
|
if ( m_pimm == NULL )
|
|
{
|
|
hr = CWebArchive::Init( lpstrDoc, dwHashSize );
|
|
if (SUCCEEDED(hr))
|
|
hr = MimeOleCreateMessage(NULL, &m_pimm);
|
|
}
|
|
|
|
RRETURN(hr);
|
|
}
|
|
|
|
|
|
HRESULT
|
|
CMHTMLArchive::AddURL( BSTR bstrURL, CHashEntry **pphe )
|
|
{
|
|
HRESULT hr;
|
|
|
|
hr = THR(Find(bstrURL, pphe));
|
|
|
|
if (FAILED(hr))
|
|
{
|
|
IStream *pstm = NULL;
|
|
CHAR szUrl[INTERNET_MAX_URL_LENGTH];
|
|
WCHAR wzArchiveText[MAX_SAVING_STATUS_TEXT + 1];
|
|
WCHAR wzBuf[INTERNET_MAX_URL_LENGTH + MAX_SAVING_STATUS_TEXT + 1];
|
|
LPSTR lpszCID=0;
|
|
DWORD dwAttach = URL_ATTACH_SET_CNTTYPE;
|
|
|
|
SHUnicodeToAnsi(bstrURL, szUrl, ARRAYSIZE(szUrl));
|
|
|
|
// hack: if it's an MHTML: url then we have to fixup to get the cid:
|
|
if (StrCmpNIA(szUrl, "mhtml:", 6)==0)
|
|
{
|
|
LPSTR lpszBody;
|
|
|
|
if (SUCCEEDED(MimeOleParseMhtmlUrl(szUrl, NULL, &lpszBody)))
|
|
{
|
|
StrCpyNA(szUrl, lpszBody, INTERNET_MAX_URL_LENGTH);
|
|
CoTaskMemFree(lpszBody);
|
|
}
|
|
}
|
|
|
|
MLLoadStringW(IDS_SAVING_STATUS_TEXT, wzArchiveText,
|
|
ARRAYSIZE(wzArchiveText));
|
|
|
|
wnsprintfW(wzBuf, ARRAYSIZE(wzBuf), L"%ws: %ws", wzArchiveText, bstrURL);
|
|
m_ptp->SetSaveText(wzBuf);
|
|
|
|
#ifndef WIN16 //RUN16_BLOCK - NOT YET AVAILABLE
|
|
hr = URLOpenBlockingStreamW(NULL, bstrURL, &pstm, 0, NULL);
|
|
#else
|
|
hr = MIME_E_URL_NOTFOUND;
|
|
#endif
|
|
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
HBODY hBody;
|
|
|
|
hr = m_pimm->AttachURL(NULL, szUrl, dwAttach, pstm, &lpszCID, &hBody);
|
|
|
|
if (SUCCEEDED(hr))
|
|
hr = _Insert( bstrURL, bstrURL, pphe );
|
|
}
|
|
|
|
ReleaseInterface(pstm);
|
|
}
|
|
|
|
RRETURN(hr);
|
|
}
|
|
|
|
HRESULT
|
|
CMHTMLArchive::AddFrameOrStyleEntry( BSTR bstrURL, CHashEntry **pphe, LPTSTR lpstrFrameDoc )
|
|
{
|
|
HRESULT hr;
|
|
|
|
hr = THR(Find(bstrURL, pphe)); // there's always a slim chance we're reusing a frame.
|
|
|
|
if (FAILED(hr))
|
|
{
|
|
// insert place-holder
|
|
hr = _Insert(bstrURL, c_bstr_BLANK, pphe);
|
|
}
|
|
|
|
return hr; // no RRETURN - may return S_FALSE
|
|
}
|
|
|
|
|
|
|
|
HRESULT
|
|
CMHTMLArchive::ArchiveDocumentText(IHTMLDocument2 *pDoc, UINT cpDoc, BOOL fFrameDoc)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
IPersistStreamInit* ppsi = NULL;
|
|
PROPVARIANT variant;
|
|
FILETIME filetime;
|
|
WCHAR wzBuffer[MAX_BUFFER_LEN];
|
|
WCHAR wzArchiveText[MAX_SAVING_STATUS_TEXT + 1];
|
|
WCHAR wzBuf[INTERNET_MAX_URL_LENGTH + MAX_SAVING_STATUS_TEXT + 1];
|
|
|
|
// Set the MIME subject header
|
|
|
|
PropVariantClear(&variant);
|
|
variant.vt = VT_LPWSTR;
|
|
hr = pDoc->get_title(&variant.pwszVal);
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
hr = m_pimm->SetBodyProp(HBODY_ROOT, PIDTOSTR(PID_HDR_SUBJECT), 0,
|
|
&variant);
|
|
SAFEFREEBSTR(variant.pwszVal);
|
|
}
|
|
|
|
// Set the MIME date header
|
|
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
hr = CoFileTimeNow(&filetime);
|
|
}
|
|
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
PropVariantClear(&variant);
|
|
variant.vt = VT_FILETIME;
|
|
variant.filetime = filetime;
|
|
hr = m_pimm->SetBodyProp(HBODY_ROOT, PIDTOSTR(PID_HDR_DATE), 0,
|
|
&variant);
|
|
}
|
|
|
|
// Set the MIME from header
|
|
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
MLLoadStringW(IDS_MIME_SAVEAS_HEADER_FROM, wzBuffer,
|
|
ARRAYSIZE(wzBuffer));
|
|
|
|
PropVariantClear(&variant);
|
|
variant.vt = VT_LPWSTR;
|
|
variant.pwszVal = wzBuffer;
|
|
hr = m_pimm->SetBodyProp(HBODY_ROOT, PIDTOSTR(PID_HDR_FROM), 0,
|
|
&variant);
|
|
}
|
|
|
|
hr = pDoc->QueryInterface(IID_IPersistStreamInit, (void**)&ppsi);
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
IStream *pstm = NULL;
|
|
|
|
hr = MimeOleCreateVirtualStream( &pstm );
|
|
if ( SUCCEEDED(hr) )
|
|
{
|
|
HBODY hBody;
|
|
hr = ppsi->Save(pstm, FALSE);
|
|
|
|
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
BSTR bstrDocURL = NULL;
|
|
WCHAR *pwzBookMark = NULL;
|
|
|
|
pDoc->get_URL(&bstrDocURL);
|
|
RemoveBookMark(bstrDocURL, &pwzBookMark);
|
|
|
|
if (!StrCmpIW(bstrDocURL, URL_ABOUT_BLANK))
|
|
{
|
|
// We got about:blank as the URL (because the doc has
|
|
// document.write's etc in it). We can't save this!
|
|
hr = E_FAIL;
|
|
goto Exit;
|
|
}
|
|
|
|
MLLoadStringW(IDS_SAVING_STATUS_TEXT, wzArchiveText,
|
|
ARRAYSIZE(wzArchiveText));
|
|
|
|
wnsprintfW(wzBuf, ARRAYSIZE(wzBuf), L"%ws: %ws", wzArchiveText, bstrDocURL);
|
|
m_ptp->SetSaveText(wzBuf);
|
|
|
|
|
|
if (fFrameDoc)
|
|
{
|
|
CHAR szURL[INTERNET_MAX_URL_LENGTH];
|
|
LPSTR lpszCID = NULL;
|
|
DWORD dwAttach = URL_ATTACH_SET_CNTTYPE;
|
|
|
|
szURL[0] = 0;
|
|
|
|
|
|
if (WideCharToMultiByte(CP_ACP, 0, bstrDocURL, -1, szURL, INTERNET_MAX_URL_LENGTH, NULL, NULL))
|
|
{
|
|
|
|
hr = m_pimm->AttachURL(NULL, szURL, dwAttach,
|
|
pstm, &lpszCID, &hBody);
|
|
|
|
if (SUCCEEDED(hr) && cpDoc)
|
|
{
|
|
IMimeBody *pBody = NULL;
|
|
|
|
hr = m_pimm->BindToObject(hBody, IID_IMimeBody,
|
|
(LPVOID *)&pBody);
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
hr = SetCharset(cpDoc, CSET_APPLY_TAG_ALL, pBody);
|
|
}
|
|
pBody->Release();
|
|
}
|
|
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
CHashEntry *phe;
|
|
|
|
LPWSTR pwz = NULL;
|
|
int iLen = 0;
|
|
|
|
// If it is ASP, it is actually HTML
|
|
|
|
iLen = lstrlenW(bstrDocURL);
|
|
|
|
if (iLen) {
|
|
pwz = StrRChrW(bstrDocURL, bstrDocURL + iLen, L'.');
|
|
}
|
|
|
|
|
|
if (pwz && !StrCmpIW(pwz, TEXT(".asp")))
|
|
{
|
|
PROPVARIANT propvar;
|
|
|
|
PropVariantClear(&propvar);
|
|
propvar.vt = VT_LPSTR;
|
|
propvar.pszVal = "text/html";
|
|
hr = m_pimm->SetBodyProp(hBody,
|
|
PIDTOSTR(PID_HDR_CNTTYPE),
|
|
0, &propvar);
|
|
}
|
|
|
|
if ( m_hBodyAlt == NULL )
|
|
m_hBodyAlt = hBody;
|
|
|
|
// update the place-holder hash entry
|
|
hr = Find( bstrDocURL, &phe);
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
ASSERT(phe != NULL);
|
|
phe->SetValue( bstrDocURL );
|
|
}
|
|
}
|
|
}
|
|
else
|
|
hr = HRESULT_FROM_WIN32(GetLastError());
|
|
|
|
}
|
|
else
|
|
{
|
|
hr = m_pimm->SetTextBody( TXT_HTML, IET_INETCSET, m_hBodyAlt, pstm, &hBody);
|
|
// The main text was the last thing we were waiting for
|
|
if (SUCCEEDED(hr) && cpDoc)
|
|
{
|
|
IMimeBody *pBody = NULL;
|
|
|
|
hr = m_pimm->BindToObject(hBody, IID_IMimeBody,
|
|
(LPVOID *)&pBody);
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
hr = SetCharset(cpDoc, CSET_APPLY_TAG_ALL, pBody);
|
|
}
|
|
pBody->Release();
|
|
}
|
|
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
IPersistFile *pipf = NULL;
|
|
// Initialzie PropVariant
|
|
PROPVARIANT rVariant;
|
|
rVariant.vt = VT_LPWSTR;
|
|
rVariant.pwszVal = (LPWSTR)bstrDocURL;
|
|
// Add a content location, so we can use it for security later.
|
|
hr = m_pimm->SetBodyProp( hBody, STR_HDR_CNTLOC, 0, &rVariant );
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
hr = m_pimm->QueryInterface(IID_IPersistFile, (LPVOID *)&pipf);
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
LPWSTR lpwszFile;
|
|
lpwszFile = m_lpstrDoc;
|
|
hr = pipf->Save(lpwszFile, FALSE);
|
|
|
|
SAFERELEASE(pipf);
|
|
}
|
|
}
|
|
|
|
ReleaseInterface(pstm);
|
|
}
|
|
}
|
|
|
|
if ( bstrDocURL )
|
|
{
|
|
// Restore Bookmark
|
|
RestoreBookMark(pwzBookMark);
|
|
SysFreeString(bstrDocURL);
|
|
}
|
|
}
|
|
|
|
ReleaseInterface(pstm);
|
|
}
|
|
}
|
|
|
|
ReleaseInterface(ppsi);
|
|
|
|
Exit:
|
|
|
|
RRETURN(hr);
|
|
}
|
|
|
|
HRESULT
|
|
CMHTMLArchive::ArchiveCSSText( BSTR bstrCSSUrl, LPCSTR lpszSSText, LPCTSTR lpszStyleDoc )
|
|
{
|
|
HRESULT hr;
|
|
BSTR bstrDocURL = NULL;
|
|
CHAR szURL[INTERNET_MAX_URL_LENGTH];
|
|
LPSTR lpszCID = NULL;
|
|
DWORD dwAttach = URL_ATTACH_SET_CNTTYPE;
|
|
HBODY hBody;
|
|
IStream *pstm = NULL;
|
|
ULONG cbWrite, cbWritten;
|
|
|
|
hr = MimeOleCreateVirtualStream( &pstm );
|
|
if (FAILED(hr))
|
|
return hr;
|
|
|
|
cbWrite = lstrlenA(lpszSSText);
|
|
pstm->Write(lpszSSText, cbWrite, &cbWritten);
|
|
ASSERT(cbWritten==cbWrite);
|
|
|
|
//if (dwFlags & MECD_CNTLOCATIONS)
|
|
// dwAttach |= URL_ATTACH_SET_CNTLOCATION;
|
|
|
|
szURL[0] = 0;
|
|
|
|
if (WideCharToMultiByte(CP_ACP, 0, bstrCSSUrl, -1, szURL, INTERNET_MAX_URL_LENGTH, NULL, NULL))
|
|
{
|
|
|
|
hr = m_pimm->AttachURL(NULL, szURL, dwAttach,
|
|
pstm, &lpszCID, &hBody);
|
|
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
CHashEntry *phe;
|
|
|
|
// update the place-holder hash entry
|
|
hr = Find(bstrCSSUrl, &phe);
|
|
|
|
ASSERT(SUCCEEDED(hr) && phe != NULL);
|
|
|
|
phe->SetValue( bstrCSSUrl );
|
|
}
|
|
}
|
|
else
|
|
hr = HRESULT_FROM_WIN32(GetLastError());
|
|
|
|
ReleaseInterface(pstm);
|
|
|
|
return hr;
|
|
}
|
|
|
|
HRESULT CMHTMLArchive::SetCharset(UINT uiCharset, CSETAPPLYTYPE csat,
|
|
IMimeBody *pBody)
|
|
{
|
|
HRESULT hr = E_FAIL;
|
|
HCHARSET hCharset;
|
|
IMimeInternational *pimi = NULL;
|
|
|
|
hr = CoCreateInstance(CLSID_IMimeInternational,
|
|
NULL, CLSCTX_INPROC_SERVER,
|
|
IID_IMimeInternational, (LPVOID*)&pimi);
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
hr = pimi->GetCodePageCharset(uiCharset, CHARSET_WEB, &hCharset);
|
|
}
|
|
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
hr = pBody->SetCharset(hCharset, csat);
|
|
}
|
|
|
|
if (pimi)
|
|
{
|
|
pimi->Release();
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
/*
|
|
* CThicketProgress ##################################################
|
|
*/
|
|
|
|
CThicketProgress::CThicketProgress( HWND hDlg )
|
|
{
|
|
TCHAR szFmt[MAX_PATH];
|
|
int cchPctFmt;
|
|
|
|
m_hDlg = hDlg;
|
|
m_hwndProg = GetDlgItem(hDlg, IDC_THICKETPROGRESS);
|
|
|
|
MLLoadString(IDS_THICKETSAVINGFMT, szFmt, ARRAYSIZE(szFmt) );
|
|
m_cchSavingFmt = lstrlen(szFmt);
|
|
m_pszSavingFmt = new TCHAR[m_cchSavingFmt+1];
|
|
if (m_pszSavingFmt != NULL)
|
|
{
|
|
StrCpyN( m_pszSavingFmt, szFmt, m_cchSavingFmt+1 );
|
|
}
|
|
|
|
MLLoadString(IDS_THICKETPCTFMT, szFmt, ARRAYSIZE(szFmt));
|
|
cchPctFmt = lstrlen(szFmt);
|
|
m_pszPctFmt = new TCHAR[cchPctFmt+1];
|
|
if (m_pszPctFmt != NULL)
|
|
{
|
|
StrCpyN( m_pszPctFmt, szFmt, cchPctFmt+1 );
|
|
}
|
|
|
|
m_ulPct = 0;
|
|
}
|
|
|
|
CThicketProgress::~CThicketProgress(void)
|
|
{
|
|
if (m_pszSavingFmt)
|
|
delete[] m_pszSavingFmt;
|
|
|
|
if (m_pszPctFmt)
|
|
delete[] m_pszPctFmt;
|
|
|
|
}
|
|
|
|
void CThicketProgress::SetPercent( ULONG ulPct )
|
|
{
|
|
TCHAR szBuf[MAX_PATH];
|
|
|
|
szBuf[0] = TEXT('\0');
|
|
|
|
if ( ulPct > 100 )
|
|
ulPct = 100;
|
|
|
|
if ( ulPct > m_ulPct ) // prevent retrograde motion.
|
|
{
|
|
m_ulPct = ulPct;
|
|
if (m_pszPctFmt != NULL)
|
|
{
|
|
wnsprintf( szBuf, ARRAYSIZE(szBuf), m_pszPctFmt, m_ulPct );
|
|
}
|
|
SetDlgItemText(m_hDlg, IDC_THICKETPCT, szBuf);
|
|
SendMessage(m_hwndProg, PBM_SETPOS, m_ulPct, 0);
|
|
}
|
|
}
|
|
|
|
void CThicketProgress::SetSaving( LPCTSTR szFile, LPCTSTR szDst )
|
|
{
|
|
TCHAR szPath[30];
|
|
TCHAR szBuf[MAX_PATH*2];
|
|
LPCTSTR psz;
|
|
|
|
szBuf[0] = TEXT('\0');
|
|
|
|
if (PathCompactPathEx( szPath, szDst, 30, 0 ))
|
|
{
|
|
psz = szPath;
|
|
}
|
|
else
|
|
{
|
|
psz = szDst;
|
|
}
|
|
|
|
if (m_pszSavingFmt != NULL)
|
|
{
|
|
wnsprintf( szBuf, ARRAYSIZE(szBuf), m_pszSavingFmt, szFile, psz );
|
|
}
|
|
|
|
SetDlgItemText(m_hDlg, IDC_THICKETSAVING, szBuf);
|
|
}
|
|
|
|
void CThicketProgress::SetSaveText(LPCTSTR szText)
|
|
{
|
|
if (szText)
|
|
{
|
|
SetDlgItemText(m_hDlg, IDC_THICKETSAVING, szText);
|
|
}
|
|
}
|
|
|
|
/*
|
|
* CCollectionPackager ##################################################
|
|
*/
|
|
|
|
CCollectionPackager::~CCollectionPackager(void)
|
|
{
|
|
if (m_pColl)
|
|
m_pColl->Release();
|
|
}
|
|
|
|
|
|
HRESULT CCollectionPackager::_GetElementURL(IHTMLElement *pElem, BSTR *pbstrURL)
|
|
{
|
|
HRESULT hr;
|
|
VARIANT rVar;
|
|
|
|
ASSERT (pElem);
|
|
|
|
rVar.vt = VT_BSTR;
|
|
|
|
// Note that _GetTargetAttribute is a virtual method, so the derived class
|
|
// specifies what attribute to fetch.
|
|
|
|
hr = THR(pElem->getAttribute(_GetTargetAttribute(), VARIANT_FALSE, &rVar));
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
if (rVar.vt == VT_BSTR && rVar.bstrVal != NULL)
|
|
*pbstrURL = rVar.bstrVal;
|
|
else
|
|
hr = S_FALSE;
|
|
}
|
|
|
|
return hr; // no RRETURN - may return S_FALSE
|
|
}
|
|
|
|
|
|
HRESULT CCollectionPackager::_PackageData(CWebArchive *pwa,
|
|
IHTMLElementCollection *pColl,
|
|
BOOL *pfCancel,
|
|
CThicketProgress *ptp, ULONG progLow, ULONG progHigh)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
ULONG uElem,
|
|
cElems,
|
|
uRange = progHigh - progLow;
|
|
IHTMLElement *pElem;
|
|
|
|
cElems = UlGetCollectionCount(pColl);
|
|
|
|
// Iterate over the collection, packaging each element in turn.
|
|
|
|
for (uElem=0; uElem<cElems && SUCCEEDED(hr) ; uElem++)
|
|
{
|
|
hr = THR(HrGetCollectionItem(pColl, uElem, IID_IHTMLElement, (LPVOID *)&pElem));
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
hr = _PackageElement(pwa, pElem ); // no THR - may return S_FALSE
|
|
pElem->Release();
|
|
}
|
|
|
|
if (pfCancel && *pfCancel)
|
|
hr = E_ABORT;
|
|
|
|
if (ptp && uRange)
|
|
ptp->SetPercent( progLow + (uRange * uElem) / cElems );
|
|
}
|
|
|
|
return hr; // no RRETURN - may return S_FALSE
|
|
}
|
|
|
|
HRESULT CCollectionPackager::_PackageElement(CWebArchive *pwa,
|
|
IHTMLElement *pElem)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
BSTR bstrURL = NULL;
|
|
BOOL fBadLinks=FALSE;
|
|
CHashEntry *phe;
|
|
|
|
hr = _GetElementURL(pElem, &bstrURL);
|
|
if (hr == S_OK && bstrURL && bstrURL[0])
|
|
{
|
|
// PTH hr = HrAddImageToMessage(pMsgSrc, pMsgDst, pHash, bstrURL, &bstrURLThicket, m_fAddCntLoc);
|
|
hr = pwa->AddURL( bstrURL, &phe );
|
|
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
hr = THR(HrSetMember(pElem, _GetTargetAttribute(), phe->m_bstrValue));
|
|
}
|
|
else
|
|
hr = THR(HrSetMember(pElem, _GetTargetAttribute(), c_bstr_EMPTY));
|
|
}
|
|
|
|
if (bstrURL)
|
|
SysFreeString(bstrURL);
|
|
|
|
|
|
return hr;
|
|
}
|
|
|
|
|
|
HRESULT CCollectionPackager::_InitSubCollection(IHTMLElementCollection *pAll,
|
|
BSTR bstrTagName,
|
|
IHTMLElementCollection **ppSub,
|
|
ULONG *pcElems)
|
|
{
|
|
IDispatch *pDisp=NULL;
|
|
VARIANT TagName;
|
|
HRESULT hr = S_FALSE;
|
|
|
|
ASSERT (ppSub);
|
|
ASSERT(pAll);
|
|
|
|
*ppSub = NULL;
|
|
|
|
TagName.vt = VT_BSTR;
|
|
TagName.bstrVal = bstrTagName;
|
|
if (NULL == TagName.bstrVal)
|
|
hr = E_INVALIDARG;
|
|
else
|
|
{
|
|
hr = pAll->tags(TagName, &pDisp);
|
|
}
|
|
|
|
if (pDisp)
|
|
{
|
|
hr = pDisp->QueryInterface(IID_IHTMLElementCollection,
|
|
(void **)ppSub);
|
|
pDisp->Release();
|
|
}
|
|
|
|
if (pcElems)
|
|
{
|
|
if (hr == S_OK)
|
|
*pcElems = UlGetCollectionCount(*ppSub);
|
|
else
|
|
*pcElems = 0;
|
|
}
|
|
|
|
RRETURN(hr);
|
|
}
|
|
|
|
/*
|
|
* CImagePackager ##################################################
|
|
*/
|
|
|
|
|
|
HRESULT CImagePackager::InitFromCollection(IHTMLElementCollection *pColl,
|
|
ULONG *pcElems)
|
|
{
|
|
return _InitSubCollection(pColl, (BSTR)c_bstr_IMG, &m_pColl, pcElems);
|
|
}
|
|
|
|
BSTR CImagePackager::_GetTargetAttribute(void)
|
|
{
|
|
return (BSTR)c_bstr_SRC;
|
|
}
|
|
|
|
/*
|
|
* CInputImgPackager ##################################################
|
|
*/
|
|
|
|
HRESULT CInputImgPackager::InitFromCollection(IHTMLElementCollection *pColl,
|
|
ULONG *pcElems)
|
|
{
|
|
return _InitSubCollection(pColl, (BSTR)c_bstr_INPUT, &m_pColl, pcElems);
|
|
}
|
|
|
|
/*
|
|
* CBGSoundsPackager ##################################################
|
|
*/
|
|
|
|
HRESULT CBGSoundsPackager::InitFromCollection(IHTMLElementCollection *pColl,
|
|
ULONG *pcElems)
|
|
{
|
|
return _InitSubCollection(pColl, (BSTR)c_bstr_BGSOUND, &m_pColl, pcElems);
|
|
}
|
|
|
|
BSTR CBGSoundsPackager::_GetTargetAttribute(void)
|
|
{
|
|
return (BSTR)c_bstr_SRC;
|
|
}
|
|
|
|
/*
|
|
* CAnchorAdjustor ##################################################
|
|
*/
|
|
|
|
|
|
HRESULT CAnchorAdjustor::InitFromCollection(IHTMLElementCollection *pColl,
|
|
ULONG *pcElems)
|
|
{
|
|
return _InitSubCollection(pColl, (BSTR)c_bstr_ANCHOR, &m_pColl, pcElems);
|
|
}
|
|
|
|
BSTR CAnchorAdjustor::_GetTargetAttribute(void)
|
|
{
|
|
return (BSTR)c_bstr_HREF;
|
|
}
|
|
|
|
HRESULT CAnchorAdjustor::_PackageElement(CWebArchive *pwa,
|
|
IHTMLElement *pElem)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
BSTR bstrURL = NULL;
|
|
BSTR bstrThicket = NULL;
|
|
BOOL fBadLinks=FALSE;
|
|
CHashEntry *phe;
|
|
|
|
// leave intra-doc urls and <A name=> alone
|
|
// seanf(2/11/98) : haven't seen a local # link come through here yet.
|
|
hr = _GetElementURL(pElem, &bstrURL);
|
|
if (hr != S_OK || bstrURL == NULL || bstrURL[0] == '#' || bstrURL[0] == 0)
|
|
goto error;
|
|
|
|
// See if the target is something we have in the thicket, like an <A> in frame A
|
|
// targetting the page saved for frame B.
|
|
ASSERT(pwa);
|
|
|
|
hr = pwa->Find(bstrURL, &phe);
|
|
if (SUCCEEDED(hr))
|
|
bstrThicket = phe->m_bstrValue;
|
|
else
|
|
{
|
|
// not in the thicket, so make both URLs the same.
|
|
bstrThicket = bstrURL;
|
|
hr = S_OK;
|
|
}
|
|
|
|
if (hr == S_OK)
|
|
hr = THR(HrSetMember(pElem, _GetTargetAttribute(), bstrThicket));
|
|
|
|
error:
|
|
|
|
if (bstrURL)
|
|
SysFreeString(bstrURL);
|
|
|
|
// don't free bstrThicket, its either bstrURL, or belongs to the thicket hash table.
|
|
|
|
return hr;
|
|
}
|
|
|
|
/*
|
|
* CAreaAdjustor ##################################################
|
|
*/
|
|
|
|
|
|
HRESULT CAreaAdjustor::InitFromCollection(IHTMLElementCollection *pColl,
|
|
ULONG *pcElems)
|
|
{
|
|
return _InitSubCollection(pColl, (BSTR)c_bstr_AREA, &m_pColl, pcElems);
|
|
}
|
|
|
|
/*
|
|
* CBaseNeutralizer ##################################################
|
|
*/
|
|
|
|
CBaseNeutralizer::~CBaseNeutralizer(void)
|
|
{
|
|
if (m_bstrLocal)
|
|
SysFreeString(m_bstrLocal);
|
|
|
|
if (m_pTree)
|
|
m_pTree->Release();
|
|
}
|
|
|
|
HRESULT CBaseNeutralizer::InitFromCollection(IHTMLElementCollection *pColl,
|
|
ULONG *pcElems,
|
|
IHTMLDocument2 *pDoc )
|
|
{
|
|
if ( pDoc != NULL )
|
|
{
|
|
if ( m_pTree )
|
|
{
|
|
m_pTree->Release();
|
|
m_pTree = NULL;
|
|
}
|
|
pDoc->QueryInterface(IID_IMarkupServices, (void**)&m_pTree);
|
|
}
|
|
|
|
return _InitSubCollection(pColl, (BSTR)c_bstr_BASE, &m_pColl, pcElems);
|
|
}
|
|
|
|
|
|
BSTR CBaseNeutralizer::_GetTargetAttribute(void)
|
|
{
|
|
return (BSTR)c_bstr_HREF;
|
|
}
|
|
|
|
HRESULT CBaseNeutralizer::PackageData(CWebArchive *pwa, BOOL *pfCancel,
|
|
CThicketProgress *ptp,
|
|
ULONG progLow, ULONG progHigh)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
ULONG uElem,
|
|
cElems,
|
|
uRange = progHigh - progLow;
|
|
IHTMLElement *pElem;
|
|
|
|
cElems = UlGetCollectionCount(m_pColl);
|
|
|
|
// Iterate over the collection, packaging each element in turn.
|
|
|
|
for (uElem=0; uElem<cElems && SUCCEEDED(hr) ; uElem++)
|
|
{
|
|
hr = THR(HrGetCollectionItem(m_pColl, 0, IID_IHTMLElement, (LPVOID *)&pElem));
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
hr = _PackageElement(pwa, pElem ); // no THR - may return S_FALSE
|
|
pElem->Release();
|
|
}
|
|
|
|
if (pfCancel && *pfCancel)
|
|
hr = E_ABORT;
|
|
|
|
if (ptp && uRange)
|
|
ptp->SetPercent( progLow + (uRange * uElem) / cElems );
|
|
}
|
|
|
|
return hr; // no RRETURN - may return S_FALSE
|
|
}
|
|
|
|
HRESULT CBaseNeutralizer::_PackageElement(CWebArchive *pwa,
|
|
IHTMLElement *pElem)
|
|
{
|
|
HRESULT hr = S_FALSE;
|
|
|
|
// NOTE: There's seems to be no retouching that will make this work.
|
|
// Tried setting BASE to ".", ".\", "". It has to be absolute,
|
|
// which would anchor the thicket to one location in the file
|
|
// system. The solution here is to use the base to fix the
|
|
// other rel URLs in the doc, then whack the base tags.
|
|
if ( m_pTree )
|
|
{
|
|
//OLD NOTE: Tree Services can't remove a head element yet, so
|
|
// wait to enable this pending Joe Beda/EricVas work.
|
|
hr = m_pTree->RemoveElement( pElem );
|
|
}
|
|
|
|
return hr; // no RRETURN - may return S_FALSE
|
|
}
|
|
|
|
/*
|
|
* CRelativeURLPackager ##################################################
|
|
*/
|
|
|
|
|
|
CRelativeURLPackager::~CRelativeURLPackager(void)
|
|
{
|
|
if (m_pCollBase)
|
|
m_pCollBase->Release();
|
|
|
|
if (m_bstrDocURL)
|
|
SysFreeString(m_bstrDocURL);
|
|
}
|
|
|
|
|
|
HRESULT CRelativeURLPackager::Init(IHTMLElementCollection *pColl,
|
|
ULONG *pcElems,
|
|
IHTMLDocument2 *pDoc)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
|
|
// Hold on to the outer collection, we'll subsample it later.
|
|
m_pColl = pColl;
|
|
|
|
if (m_pColl)
|
|
{
|
|
m_pColl->AddRef();
|
|
hr = _InitSubCollection( m_pColl, (BSTR)c_bstr_BASE, &m_pCollBase, &m_cBase );
|
|
}
|
|
|
|
if (SUCCEEDED(hr) && pDoc)
|
|
{
|
|
hr = pDoc->get_URL( &m_bstrDocURL );
|
|
}
|
|
|
|
RRETURN(hr);
|
|
}
|
|
|
|
HRESULT CRelativeURLPackager::_GetElementURL(IHTMLElement *pElem, BSTR *pbstrURL)
|
|
{
|
|
HRESULT hr = S_FALSE;
|
|
LONG lElemPos;
|
|
BSTR bstr = NULL;
|
|
|
|
|
|
ASSERT (pbstrURL);
|
|
*pbstrURL = 0;
|
|
|
|
hr = CCollectionPackager::_GetElementURL(pElem, &bstr);
|
|
if (hr==S_OK)
|
|
{
|
|
if (bstr==NULL)
|
|
hr = S_FALSE;
|
|
else
|
|
{
|
|
hr = pElem->get_sourceIndex(&lElemPos);
|
|
ASSERT(SUCCEEDED(hr));
|
|
hr = HrGetCombinedURL(m_pCollBase, m_cBase, lElemPos, bstr, m_bstrDocURL, pbstrURL);
|
|
SysFreeString(bstr);
|
|
}
|
|
}
|
|
|
|
return hr; // no RRETURN - may return S_FALSE
|
|
}
|
|
|
|
/*
|
|
* CBackgroundPackager ##################################################
|
|
*/
|
|
|
|
|
|
HRESULT CBackgroundPackager::PackageData(CWebArchive *pwa,
|
|
BOOL *pfCancel,
|
|
CThicketProgress *ptp, ULONG progLow, ULONG progHigh)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
IHTMLElementCollection *pColl = NULL;
|
|
|
|
hr = _InitSubCollection(m_pColl, (BSTR)c_bstr_BODY, &pColl);
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
if (hr==S_OK)
|
|
hr = _PackageData( pwa, pColl, pfCancel );
|
|
if (FAILED(hr))
|
|
goto error;
|
|
pColl->Release();
|
|
pColl = NULL;
|
|
}
|
|
|
|
hr = _InitSubCollection(m_pColl, (BSTR)c_bstr_TABLE, &pColl);
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
if (hr==S_OK)
|
|
hr = _PackageData( pwa, pColl, pfCancel);
|
|
if (FAILED(hr))
|
|
goto error;
|
|
pColl->Release();
|
|
pColl = NULL;
|
|
}
|
|
|
|
hr = _InitSubCollection(m_pColl, (BSTR)c_bstr_TD, &pColl);
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
if (hr==S_OK)
|
|
hr = _PackageData( pwa, pColl, pfCancel );
|
|
if (FAILED(hr))
|
|
goto error;
|
|
pColl->Release();
|
|
pColl = NULL;
|
|
}
|
|
|
|
hr = _InitSubCollection(m_pColl, (BSTR)c_bstr_TH, &pColl);
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
if (hr==S_OK)
|
|
hr = _PackageData( pwa, pColl, pfCancel );
|
|
if (FAILED(hr))
|
|
goto error;
|
|
pColl->Release();
|
|
pColl = NULL;
|
|
}
|
|
|
|
error:
|
|
|
|
if (pColl)
|
|
pColl->Release();
|
|
|
|
return hr; // no RRETURN - may return S_FALSE
|
|
}
|
|
|
|
|
|
BSTR CBackgroundPackager::_GetTargetAttribute(void)
|
|
{
|
|
return (BSTR)c_bstr_BACKGROUND;
|
|
}
|
|
|
|
|
|
/*
|
|
* CDynSrcPackager ##################################################
|
|
*/
|
|
|
|
|
|
HRESULT CDynSrcPackager::PackageData(CWebArchive *pwa,
|
|
BOOL *pfCancel,
|
|
CThicketProgress *ptp, ULONG progLow, ULONG progHigh)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
IHTMLElementCollection *pColl = NULL;
|
|
|
|
hr = _InitSubCollection(m_pColl, (BSTR)c_bstr_IMG, &pColl);
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
if (hr==S_OK)
|
|
hr = _PackageData( pwa, pColl, pfCancel );
|
|
if (FAILED(hr))
|
|
goto error;
|
|
pColl->Release();
|
|
pColl = NULL;
|
|
}
|
|
|
|
hr = _InitSubCollection(m_pColl, (BSTR)c_bstr_INPUT, &pColl);
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
if (hr==S_OK)
|
|
hr = _PackageData( pwa, pColl, pfCancel );
|
|
if (FAILED(hr))
|
|
goto error;
|
|
pColl->Release();
|
|
pColl = NULL;
|
|
}
|
|
|
|
|
|
error:
|
|
|
|
if (pColl)
|
|
pColl->Release();
|
|
|
|
return hr; // no RRETURN - may return S_FALSE
|
|
}
|
|
|
|
|
|
BSTR CDynSrcPackager::_GetTargetAttribute(void)
|
|
{
|
|
return (BSTR)c_bstr_DYNSRC;
|
|
}
|
|
|
|
|
|
/*
|
|
* CScriptPackager ##################################################
|
|
*/
|
|
|
|
|
|
HRESULT CScriptPackager::Init(IHTMLElementCollection *pColl,
|
|
ULONG *pcElems,
|
|
IHTMLDocument2 *pDoc)
|
|
{
|
|
HRESULT hr = CRelativeURLPackager::Init(pColl, NULL, pDoc);
|
|
|
|
if (SUCCEEDED(hr))
|
|
hr = _InitSubCollection(m_pColl, (BSTR)c_bstr_SCRIPT, &m_pCollScripts, pcElems );
|
|
|
|
return hr;
|
|
}
|
|
|
|
|
|
BSTR CScriptPackager::_GetTargetAttribute(void)
|
|
{
|
|
return (BSTR)c_bstr_SRC;
|
|
}
|
|
|
|
/*
|
|
* CFramesPackager ##################################################
|
|
*/
|
|
|
|
HRESULT CFramesPackager::Init(IHTMLElementCollection *pColl,
|
|
ULONG *pcElems,
|
|
IHTMLDocument2 *pDoc,
|
|
IHTMLDocument2 *pDocDesign,
|
|
CDocumentPackager *pdp)
|
|
{
|
|
HRESULT hr = CRelativeURLPackager::Init(pColl, NULL, pDocDesign);
|
|
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
m_pdp = pdp;
|
|
// Get the element collection for the frames.
|
|
// Note: If documents have frames, they are either all
|
|
// <FRAME>s _OR_ all <IFRAME>s.
|
|
hr = _InitSubCollection(m_pColl, (BSTR)c_bstr_FRAME, &m_pCollFrames, &m_cFrames);
|
|
if (FAILED(hr) || m_cFrames == 0)
|
|
{
|
|
if (m_pCollFrames)
|
|
m_pCollFrames->Release();
|
|
hr = _InitSubCollection(m_pColl, (BSTR)c_bstr_IFRAME, &m_pCollFrames, &m_cFrames);
|
|
}
|
|
|
|
if (pcElems)
|
|
*pcElems = m_cFrames;
|
|
|
|
// To traverse a framseset that spans multiple domains, we need to approach it
|
|
// via the "unsecured" window object, which is only accessible via Invoke.
|
|
if (SUCCEEDED(hr) && m_cFrames > 0)
|
|
{
|
|
DISPPARAMS dispparams;
|
|
VARIANT VarResult;
|
|
VariantInit(&VarResult);
|
|
ZeroMemory(&dispparams, sizeof(dispparams));
|
|
|
|
hr = pDoc->Invoke(DISPID_WINDOWOBJECT,
|
|
IID_NULL,
|
|
0,
|
|
DISPATCH_PROPERTYGET,
|
|
&dispparams,
|
|
&VarResult,
|
|
NULL,
|
|
NULL );
|
|
|
|
if( SUCCEEDED(hr) )
|
|
{
|
|
// Code in iedisp.cpp's GetDelegateOnIDispatch was really paranoid about this,
|
|
// so we'll be similarly cautious.
|
|
if( (VarResult.vt == VT_DISPATCH || VarResult.vt == VT_UNKNOWN)
|
|
&& VarResult.pdispVal )
|
|
{
|
|
IHTMLWindow2 *pwin2 = NULL;
|
|
|
|
hr = VarResult.pdispVal->QueryInterface( IID_IHTMLWindow2, (LPVOID*)&pwin2);
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
hr = pwin2->get_frames(&m_pframes2);
|
|
pwin2->Release();
|
|
}
|
|
} // if we really got an interface
|
|
else
|
|
hr = E_FAIL;
|
|
|
|
VariantClearLazy( &VarResult );
|
|
} // if we can get the un-secured window object
|
|
} // if we have frames
|
|
} // if base initialization succeeded
|
|
|
|
return hr;
|
|
}
|
|
|
|
|
|
HRESULT CFramesPackager::PackageData(CWebArchive *pwa,
|
|
BOOL *pfCancel,
|
|
CThicketProgress *ptp, ULONG progLow, ULONG progHigh)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
//ULONG cColl = 0;
|
|
|
|
if (m_cFrames == 0)
|
|
return S_OK; // Trident will get confused if we return a non-S_OK success code
|
|
|
|
m_iFrameCur = 0; // index of frame in window.frames and all.tags("FRAME");
|
|
m_pfCancel = pfCancel;
|
|
m_ptp = ptp;
|
|
m_uLow = progLow;
|
|
m_uHigh = progHigh;
|
|
|
|
m_uRangeDoc = (progHigh - progLow) / m_cFrames;
|
|
hr = _PackageData( pwa, m_pCollFrames, pfCancel );
|
|
|
|
return hr; // no RRETURN - may return S_FALSE
|
|
}
|
|
|
|
|
|
BSTR CFramesPackager::_GetTargetAttribute(void)
|
|
{
|
|
return (BSTR)c_bstr_SRC;
|
|
}
|
|
|
|
HRESULT CFramesPackager::_PackageElement(CWebArchive *pwa,
|
|
IHTMLElement *pElem)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
BSTR bstrURL = NULL;
|
|
BOOL fBadLinks=FALSE;
|
|
IHTMLDocument2 *pDocFrame = NULL;
|
|
//IWebBrowser *pwb = NULL;
|
|
IDispatch *pDisp = NULL;
|
|
IHTMLWindow2 *pwin2 = NULL;
|
|
VARIANT varIndex;
|
|
VARIANT varFrame;
|
|
WCHAR *pwzBookMark = NULL;
|
|
|
|
ASSERT(pElem);
|
|
ASSERT(pwa);
|
|
|
|
varIndex.vt = VT_I4;
|
|
varIndex.lVal = m_iFrameCur;
|
|
hr = m_pframes2->item( &varIndex, &varFrame );
|
|
if (FAILED(hr))
|
|
goto error;
|
|
// The variant should give us an IHTMLWindow2, but we'll treat it as a Disp anyway
|
|
ASSERT(varFrame.vt & VT_DISPATCH);
|
|
pDisp = varFrame.pdispVal;
|
|
hr = pDisp->QueryInterface(IID_IHTMLWindow2, (LPVOID*)&pwin2 );
|
|
if (FAILED(hr))
|
|
goto error;
|
|
|
|
hr = pwin2->get_document(&pDocFrame);
|
|
|
|
#ifdef OLD_THICKET
|
|
|
|
hr = pElem->QueryInterface(IID_IWebBrowser, (void**)&pwb);
|
|
if (FAILED(hr))
|
|
goto error;
|
|
|
|
hr = pwb->get_Document( &pDisp );
|
|
if (FAILED(hr))
|
|
goto error;
|
|
else if ( pDisp == NULL )
|
|
{
|
|
hr = S_FALSE;
|
|
goto error;
|
|
}
|
|
|
|
hr = pDisp->QueryInterface(IID_IHTMLDocument2, (void**)&pDocFrame);
|
|
if (FAILED(hr))
|
|
goto error;
|
|
|
|
#endif // OLD_THICKET
|
|
|
|
if (SUCCEEDED(hr) && SUCCEEDED(pDocFrame->get_URL(&bstrURL)) && bstrURL && bstrURL[0])
|
|
{
|
|
TCHAR szFrameDoc[MAX_PATH];
|
|
CHashEntry *phe;
|
|
|
|
RemoveBookMark(bstrURL, &pwzBookMark);
|
|
|
|
hr = pwa->AddFrameOrStyleEntry( bstrURL, &phe, szFrameDoc );
|
|
if (hr==S_OK)
|
|
{
|
|
ULONG uLowDoc = m_uLow + m_iFrameCur * m_uRangeDoc;
|
|
ULONG uHighDoc = uLowDoc + m_uRangeDoc;
|
|
CWebArchive *pwaFrame = m_pdp->GetFrameDocArchive( pwa );
|
|
|
|
if ( pwaFrame != NULL )
|
|
{
|
|
BSTR bstrCharSetSrc = NULL;
|
|
MIMECSETINFO csetInfo;
|
|
IMultiLanguage2 *pMultiLanguage = NULL;
|
|
|
|
hr = pDocFrame->get_charset(&bstrCharSetSrc);
|
|
if (FAILED(hr))
|
|
goto error;
|
|
|
|
hr = CoCreateInstance(CLSID_CMultiLanguage, NULL, CLSCTX_INPROC_SERVER,
|
|
IID_IMultiLanguage2, (void**)&pMultiLanguage);
|
|
if (FAILED(hr))
|
|
{
|
|
goto error;
|
|
}
|
|
|
|
hr = pMultiLanguage->GetCharsetInfo(bstrCharSetSrc, &csetInfo);
|
|
pMultiLanguage->Release();
|
|
|
|
if (FAILED(hr))
|
|
{
|
|
goto error;
|
|
}
|
|
|
|
hr = m_pdp->_PackageDocument(pDocFrame, szFrameDoc, m_pfCancel, m_ptp,
|
|
uLowDoc, uHighDoc, csetInfo.uiInternetEncoding,
|
|
pwaFrame, m_pdp, TRUE );
|
|
if (SUCCEEDED(hr))
|
|
hr = THR(HrSetMember(pElem, _GetTargetAttribute(), phe->m_bstrValue));
|
|
else
|
|
fBadLinks = TRUE;
|
|
|
|
if ( pwaFrame != pwa ) // only delete if new one was made (thicket)
|
|
delete pwaFrame;
|
|
}
|
|
else
|
|
hr = E_OUTOFMEMORY;
|
|
} // if the location matched the element URL
|
|
else if (hr==S_FALSE)
|
|
{
|
|
// This is a repeat - we don't need to do most of the work, but we
|
|
// do need to record the element for remapping.
|
|
hr = THR(HrSetMember(pElem, _GetTargetAttribute(), phe->m_bstrValue));
|
|
}
|
|
} // if we got the frame's doc's URL
|
|
else // if ( hr == DISP_E_MEMBERNOTFOUND ) // frame is non-trident docobj
|
|
{
|
|
IHTMLLocation *ploc = NULL;
|
|
|
|
// For a non-trident doc-obj, get the file, if possible, and put it in the thicket.
|
|
|
|
hr = pwin2->get_location( &ploc );
|
|
if (SUCCEEDED(hr) &&
|
|
SUCCEEDED(hr = ploc->get_href( &bstrURL )))
|
|
{
|
|
if (bstrURL && bstrURL[0])
|
|
{
|
|
CHashEntry *phe;
|
|
// PTH hr = HrAddImageToMessage(pMsgSrc, pMsgDst, pHash, bstrURL, &bstrURLThicket, m_fAddCntLoc);
|
|
hr = pwa->AddURL( bstrURL, &phe );
|
|
if (!FAILED(hr))
|
|
{
|
|
hr = THR(HrSetMember(pElem, _GetTargetAttribute(), phe->m_bstrValue));
|
|
}
|
|
}
|
|
else
|
|
hr = S_FALSE;
|
|
}
|
|
ReleaseInterface(ploc);
|
|
}
|
|
|
|
error:
|
|
//ReleaseInterface(pwb);
|
|
ReleaseInterface(pwin2);
|
|
ReleaseInterface(pDisp);
|
|
ReleaseInterface(pDocFrame);
|
|
|
|
if (bstrURL) {
|
|
RestoreBookMark(pwzBookMark);
|
|
SysFreeString(bstrURL); // bstrFrameURL);
|
|
}
|
|
|
|
m_iFrameCur++;
|
|
|
|
return hr;
|
|
}
|
|
|
|
/*
|
|
* CDocumentPackager ##################################################
|
|
*/
|
|
|
|
HRESULT CDocumentPackager::PackageDocument(IHTMLDocument2 *pDoc,
|
|
LPCTSTR lpstrDoc,
|
|
BOOL *pfCancel, CThicketProgress *ptp,
|
|
ULONG progLow, ULONG progHigh,
|
|
UINT cpDst,
|
|
CWebArchive *pwa)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
|
|
m_ptp = ptp;
|
|
|
|
switch (m_iPackageStyle)
|
|
{
|
|
case PACKAGE_THICKET:
|
|
{
|
|
CThicketArchive thicket(ptp);
|
|
|
|
hr = _PackageDocument( pDoc, lpstrDoc, pfCancel, ptp, progLow, progHigh, cpDst, &thicket, this, FALSE );
|
|
}
|
|
break;
|
|
|
|
case PACKAGE_MHTML:
|
|
{
|
|
CMHTMLArchive *pmhtmla = (CMHTMLArchive *)pwa; // sleazy downcast
|
|
|
|
if (pwa == NULL)
|
|
pmhtmla = new CMHTMLArchive(ptp);
|
|
|
|
if (pmhtmla != NULL)
|
|
{
|
|
hr = _PackageDocument( pDoc, lpstrDoc, pfCancel, ptp, progLow, progHigh, cpDst,
|
|
pmhtmla, this, FALSE );
|
|
|
|
// if pwa is NULL, then we created a CMHTMLArchive for
|
|
// use in _PackageDocument which we now need to clean up
|
|
if (pwa == NULL)
|
|
delete pmhtmla;
|
|
}
|
|
else
|
|
{
|
|
hr = E_OUTOFMEMORY;
|
|
}
|
|
}
|
|
break;
|
|
|
|
case PACKAGE_HTML:
|
|
// fall through - Trident will do the right thing by sniffing the
|
|
// extension.
|
|
case PACKAGE_TEXT:
|
|
{
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
IHTMLDocument2 *pDocDesign = NULL;
|
|
IHTMLDocument2 *pDocSave = NULL;
|
|
IPersistFile *ppf = NULL;
|
|
|
|
if (cpDst == CP_ACP)
|
|
{
|
|
// No encoding change, use the browse doc
|
|
pDocSave = pDoc;
|
|
}
|
|
else
|
|
{
|
|
hr = _GetDesignDoc( pDoc, &pDocDesign, pfCancel, ptp, cpDst);
|
|
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
pDocSave = pDocDesign;
|
|
}
|
|
else
|
|
{
|
|
return E_FAIL;
|
|
}
|
|
}
|
|
|
|
// Trident IPersistFile::Save looks at the extension to determine if it's
|
|
// an HTML or text save.
|
|
|
|
hr = pDocSave->QueryInterface(IID_IPersistFile, (void**)&ppf);
|
|
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
LPCWSTR lpwszFile;
|
|
lpwszFile = lpstrDoc;
|
|
BSTR bstrURL = NULL;
|
|
WCHAR wzSavingText[MAX_SAVING_STATUS_TEXT + 1];
|
|
WCHAR wzBuf[INTERNET_MAX_URL_LENGTH + MAX_SAVING_STATUS_TEXT + 1];
|
|
|
|
hr = pDocSave->get_URL(&bstrURL);
|
|
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
|
|
MLLoadStringW(IDS_SAVING_STATUS_TEXT, wzSavingText,
|
|
ARRAYSIZE(wzSavingText));
|
|
|
|
wnsprintfW(wzBuf, ARRAYSIZE(wzBuf),
|
|
L"%ws: %ws", wzSavingText, bstrURL);
|
|
ptp->SetSaveText(wzBuf);
|
|
|
|
if (bstrURL)
|
|
{
|
|
SysFreeString(bstrURL);
|
|
}
|
|
}
|
|
|
|
hr = ppf->Save( lpwszFile, FALSE );
|
|
ppf->SaveCompleted(lpwszFile);
|
|
|
|
ppf->Release();
|
|
}
|
|
|
|
if (cpDst != CP_ACP)
|
|
{
|
|
pDocSave->Release();
|
|
}
|
|
|
|
// If we used the browse-time pDoc, we don't need to release
|
|
// it because it is released by CThicketUI::ThicketUIThreadProc
|
|
}
|
|
}
|
|
break;
|
|
|
|
default:
|
|
ASSERT(FALSE);
|
|
break;
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
HRESULT CDocumentPackager::_PackageDocument(IHTMLDocument2 *pDoc,
|
|
LPCTSTR lpstrDoc,
|
|
BOOL *pfCancel, CThicketProgress *ptp,
|
|
ULONG progLow, ULONG progHigh,
|
|
UINT cpDst,
|
|
CWebArchive *pwa,
|
|
CDocumentPackager *pdpFrames,
|
|
BOOL fFrameDoc)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
ULONG cImages;
|
|
ULONG cInputImgs;
|
|
ULONG cBGSounds;
|
|
ULONG cFrames;
|
|
ULONG uRange = progHigh - progLow;
|
|
ULONG uRangeThis;
|
|
ULONG uLow, uHigh;
|
|
IHTMLElementCollection *pCollect = NULL;
|
|
CImagePackager imgPkgr;
|
|
CInputImgPackager inputimgPkgr;
|
|
CBGSoundsPackager bgsPkgr;
|
|
CBackgroundPackager bkgndPkgr;
|
|
CBaseNeutralizer baseNeut;
|
|
CAnchorAdjustor anchorAdj;
|
|
CAreaAdjustor areaAdj;
|
|
CFramesPackager framesPkgr;
|
|
CSSPackager stylesheetPkgr;
|
|
CDynSrcPackager dynsrcPkgr;
|
|
CScriptPackager scriptPkgr;
|
|
IHTMLDocument2 *pDocDesign = NULL;
|
|
BYTE abBuffer[MAX_BUFFER_LEN];
|
|
DWORD dwType = 0;
|
|
DWORD dwSize = 0;
|
|
BOOL bDLImages = TRUE;
|
|
HKEY hkey = 0;
|
|
IOleCommandTarget *pIOCT = NULL;
|
|
|
|
if (pDoc==NULL)
|
|
return E_INVALIDARG;
|
|
|
|
hr = _GetDesignDoc( pDoc, &pDocDesign, pfCancel, ptp, cpDst );
|
|
if (FAILED(hr))
|
|
goto error;
|
|
|
|
// HACK! If you have a unicode character in the filename, when we
|
|
// call put_href on the CSS, trident tries to download this. The
|
|
// invalid character is sent to the server, who sends badddddd
|
|
// stuff, which the CSS parser doesn't understand. The result is
|
|
// that trident falls on the floor. This tells trident not to download
|
|
// the CSS hence avoiding the problem.
|
|
|
|
hr = pDocDesign->QueryInterface(IID_IOleCommandTarget, (void **)&pIOCT);
|
|
|
|
if (SUCCEEDED(hr) && pIOCT)
|
|
{
|
|
pIOCT->Exec(NULL, OLECMDID_DONTDOWNLOADCSS, OLECMDID_DONTDOWNLOADCSS,
|
|
NULL, NULL);
|
|
pIOCT->Release();
|
|
}
|
|
|
|
hr = pDocDesign->get_all(&pCollect);
|
|
if (FAILED(hr))
|
|
RRETURN(hr);
|
|
|
|
dwSize = MAX_BUFFER_LEN;
|
|
if (RegOpenKey(HKEY_CURRENT_USER, REGPATH_MSIE_MAIN, &hkey) == ERROR_SUCCESS)
|
|
{
|
|
if (SHQueryValueExA(hkey, REGVALUE_DOWNLOAD_IMAGES, 0, &dwType,
|
|
abBuffer, &dwSize) == NO_ERROR)
|
|
{
|
|
bDLImages = !StrCmpIA((char *)abBuffer, "yes");
|
|
}
|
|
|
|
RegCloseKey(hkey);
|
|
}
|
|
|
|
if (bDLImages)
|
|
{
|
|
// pack all the images into the message and remember the Thicket mappings
|
|
hr = imgPkgr.InitFromCollection(pCollect, &cImages);
|
|
if (FAILED(hr))
|
|
goto error;
|
|
|
|
hr = inputimgPkgr.InitFromCollection(pCollect, &cInputImgs);
|
|
if (FAILED(hr))
|
|
goto error;
|
|
|
|
}
|
|
|
|
hr = bgsPkgr.InitFromCollection(pCollect, &cBGSounds);
|
|
if (FAILED(hr))
|
|
goto error;
|
|
|
|
hr = bkgndPkgr.Init(pCollect, NULL, pDocDesign);
|
|
if (FAILED(hr))
|
|
goto error;
|
|
|
|
hr = dynsrcPkgr.Init(pCollect, NULL, pDocDesign);
|
|
if (FAILED(hr))
|
|
goto error;
|
|
|
|
hr = stylesheetPkgr.Init(pCollect, NULL, pDocDesign);
|
|
if (FAILED(hr))
|
|
goto error;
|
|
|
|
hr = framesPkgr.Init(pCollect, &cFrames, pDoc, pDocDesign, this);
|
|
if (FAILED(hr))
|
|
goto error;
|
|
|
|
hr = scriptPkgr.Init(pCollect, NULL, pDocDesign);
|
|
if (FAILED(hr))
|
|
goto error;
|
|
|
|
hr = pwa->Init(lpstrDoc, cImages + cInputImgs + cFrames);
|
|
if (FAILED(hr))
|
|
goto error;
|
|
|
|
// herewith commences the hackery to drive the progess bar.
|
|
// If we have frames we devide the progress range among all the docs involved.
|
|
// We'll neglect style sheets and devote the range for the immediate
|
|
// document to the image collection.
|
|
uRangeThis = uRange / (cFrames + 1);
|
|
|
|
uLow = progLow;
|
|
uHigh = progLow + uRangeThis;
|
|
|
|
if (bDLImages)
|
|
{
|
|
hr = imgPkgr.PackageData(pwa, pfCancel, ptp, uLow, uHigh);
|
|
if (FAILED(hr))
|
|
goto error;
|
|
|
|
hr = inputimgPkgr.PackageData(pwa, pfCancel, ptp, uLow, uHigh);
|
|
if (FAILED(hr))
|
|
goto error;
|
|
}
|
|
|
|
hr = bgsPkgr.PackageData(pwa, pfCancel, ptp, uLow, uHigh);
|
|
if (FAILED(hr))
|
|
goto error;
|
|
|
|
hr = bkgndPkgr.PackageData(pwa, pfCancel);
|
|
if (FAILED(hr))
|
|
goto error;
|
|
|
|
hr = dynsrcPkgr.PackageData(pwa, pfCancel);
|
|
if (FAILED(hr))
|
|
goto error;
|
|
|
|
hr = stylesheetPkgr.PackageStyleSheets(pDocDesign, pwa);
|
|
if (FAILED(hr))
|
|
goto error;
|
|
|
|
uLow = progHigh - uRangeThis;
|
|
uHigh = progHigh;
|
|
|
|
hr = framesPkgr.PackageData(pwa, pfCancel, ptp, uLow, uHigh);
|
|
if (FAILED(hr))
|
|
goto error;
|
|
|
|
hr = scriptPkgr.PackageData(pwa, pfCancel);
|
|
if (FAILED(hr))
|
|
goto error;
|
|
|
|
// we want to do this after frames s.t. the frame docs will be in the thicket
|
|
// and we can correctly direct a targetted hyperlink from frame A to frame B
|
|
// if the href is in the thicket vs. still out on the Web.
|
|
hr = anchorAdj.InitFromCollection(pCollect);
|
|
if (FAILED(hr))
|
|
goto error;
|
|
|
|
hr = anchorAdj.PackageData(pwa, pfCancel); // not that we need the thicket...
|
|
if (FAILED(hr))
|
|
goto error;
|
|
|
|
hr = areaAdj.InitFromCollection(pCollect);
|
|
if (FAILED(hr))
|
|
goto error;
|
|
|
|
hr = areaAdj.PackageData(pwa, pfCancel); // not that we need the thicket...
|
|
if (FAILED(hr))
|
|
goto error;
|
|
|
|
|
|
// Now that we've got everybody remapped, short-circuit the base tags
|
|
// and redirect to the current directory.
|
|
hr = baseNeut.InitFromCollection(pCollect, NULL, pDocDesign );
|
|
if (FAILED(hr))
|
|
goto error;
|
|
|
|
hr = baseNeut.PackageData(pwa, pfCancel);
|
|
if (FAILED(hr))
|
|
goto error;
|
|
|
|
//if(dwFlags & MECD_HTML || dwFlags & MECD_PLAINTEXT)
|
|
{
|
|
hr = pwa->ArchiveDocumentText( pDocDesign, cpDst, fFrameDoc );
|
|
if (FAILED(hr))
|
|
goto error;
|
|
}
|
|
|
|
|
|
error:
|
|
|
|
if (pCollect)
|
|
pCollect->Release();
|
|
|
|
if (pDocDesign)
|
|
pDocDesign->Release();
|
|
|
|
if (pfCancel && *pfCancel)
|
|
hr = E_ABORT;
|
|
|
|
if (SUCCEEDED(hr))
|
|
pwa->Commit();
|
|
else
|
|
pwa->Revert();
|
|
|
|
return hr;
|
|
}
|
|
|
|
CWebArchive *CDocumentPackager::GetFrameDocArchive(CWebArchive *pwaSrc)
|
|
{
|
|
CWebArchive *pwa = NULL;
|
|
|
|
if (m_iPackageStyle == PACKAGE_THICKET)
|
|
pwa = new CThicketArchive(m_ptp);
|
|
else if (m_iPackageStyle == PACKAGE_MHTML)
|
|
pwa = pwaSrc;
|
|
else
|
|
ASSERT(FALSE);
|
|
|
|
return pwa;
|
|
}
|
|
|
|
HRESULT CDocumentPackager::_GetDesignDoc( IHTMLDocument2 *pDocSrc, IHTMLDocument2 **ppDocDesign,
|
|
BOOL *pfCancel, CThicketProgress *ptp, UINT cpDst )
|
|
{
|
|
HRESULT hr;
|
|
DWORD dwFlags;
|
|
BSTR bstrURL = NULL;
|
|
BSTR bstrCharSetSrc = NULL;
|
|
MIMECSETINFO csetInfo;
|
|
IMultiLanguage2 *pMultiLanguage = NULL;
|
|
CUrlDownload *pud = NULL;
|
|
ULONG cRef = 0;
|
|
DWORD dwUrlEncodingDisableUTF8;
|
|
DWORD dwSize = SIZEOF(dwUrlEncodingDisableUTF8);
|
|
BOOL fDefault = FALSE;
|
|
|
|
hr = pDocSrc->get_charset(&bstrCharSetSrc);
|
|
if (FAILED(hr))
|
|
goto Cleanup;
|
|
|
|
hr = CoCreateInstance(CLSID_CMultiLanguage, NULL, CLSCTX_INPROC_SERVER,
|
|
IID_IMultiLanguage2, (void**)&pMultiLanguage);
|
|
if (FAILED(hr))
|
|
{
|
|
goto Cleanup;
|
|
}
|
|
|
|
hr = pMultiLanguage->GetCharsetInfo(bstrCharSetSrc, &csetInfo);
|
|
if (FAILED(hr))
|
|
{
|
|
goto Cleanup;
|
|
}
|
|
|
|
if (FAILED(pDocSrc->get_URL( &bstrURL )))
|
|
goto Cleanup;
|
|
|
|
pud = new CUrlDownload( ptp, &hr, csetInfo.uiInternetEncoding );
|
|
|
|
if (pud == NULL)
|
|
{
|
|
hr = E_OUTOFMEMORY;
|
|
goto Cleanup;
|
|
}
|
|
|
|
*ppDocDesign = NULL;
|
|
|
|
// seanf(2/6/98): Review DLCTL_ flags.
|
|
dwFlags = DLCTL_NO_SCRIPTS | DLCTL_NO_JAVA | DLCTL_NO_RUNACTIVEXCTLS | DLCTL_NO_FRAMEDOWNLOAD |
|
|
DLCTL_SILENT | DLCTL_OFFLINE;
|
|
|
|
SHRegGetUSValue(REGSTR_PATH_INTERNET_SETTINGS,
|
|
TEXT("UrlEncoding"), NULL, (LPBYTE) &dwUrlEncodingDisableUTF8, &dwSize, FALSE, (LPVOID) &fDefault, SIZEOF(fDefault));
|
|
|
|
if (dwUrlEncodingDisableUTF8)
|
|
{
|
|
dwFlags |= DLCTL_URL_ENCODING_DISABLE_UTF8;
|
|
}
|
|
else
|
|
{
|
|
dwFlags |= DLCTL_URL_ENCODING_ENABLE_UTF8;
|
|
}
|
|
|
|
hr = pud->SetDLCTL(dwFlags);
|
|
if (SUCCEEDED(hr))
|
|
hr = pud->BeginDownloadURL2( bstrURL, BDU2_BROWSER, BDU2_NONE, NULL, 0xF0000000 );
|
|
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
MSG msg;
|
|
|
|
hr = S_FALSE;
|
|
|
|
while (hr==S_FALSE)
|
|
{
|
|
GetMessage(&msg, NULL, 0, 0);
|
|
TranslateMessage(&msg);
|
|
DispatchMessage(&msg);
|
|
if (*pfCancel)
|
|
{
|
|
pud->AbortDownload();
|
|
hr = E_ABORT;
|
|
}
|
|
}
|
|
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
hr = pud->GetDocument( ppDocDesign );
|
|
|
|
// Set the document to the codepage the user has selected.
|
|
// Don't bother if it's no specific page has been directed, as is the case
|
|
// with frame documents and in cases where the user kept the default
|
|
// code page selected in the Save As... dialog.
|
|
if (SUCCEEDED(hr) && cpDst != CP_ACP)
|
|
{
|
|
MIMECPINFO cpInfo;
|
|
BSTR bstrCharSet = NULL;
|
|
LANGID langid;
|
|
|
|
langid = MLGetUILanguage();
|
|
|
|
if ( SUCCEEDED(pMultiLanguage->GetCodePageInfo(cpDst, langid, &cpInfo)) &&
|
|
(bstrCharSet = SysAllocString(cpInfo.wszWebCharset)) != NULL )
|
|
hr = (*ppDocDesign)->put_charset(bstrCharSet);
|
|
|
|
ASSERT(SUCCEEDED(hr));
|
|
|
|
if (bstrCharSet)
|
|
SysFreeString(bstrCharSet);
|
|
}
|
|
}
|
|
}
|
|
|
|
pud->DoneDownloading();
|
|
|
|
cRef = pud->Release();
|
|
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
IOleCommandTarget *pioct;
|
|
|
|
hr = pDocSrc->QueryInterface(IID_IOleCommandTarget, (LPVOID*)&pioct);
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
VARIANTARG v;
|
|
|
|
v.vt = VT_UNKNOWN;
|
|
v.punkVal = *ppDocDesign;
|
|
|
|
hr = pioct->Exec( &CGID_ShortCut, CMDID_SAVEASTHICKET, OLECMDEXECOPT_DODEFAULT, &v, NULL );
|
|
|
|
pioct->Release();
|
|
}
|
|
}
|
|
|
|
Cleanup:
|
|
|
|
SAFERELEASE(pMultiLanguage);
|
|
|
|
if (bstrURL)
|
|
SysFreeString(bstrURL);
|
|
|
|
if (bstrCharSetSrc)
|
|
SysFreeString(bstrCharSetSrc);
|
|
|
|
if (FAILED(hr))
|
|
{
|
|
if (ppDocDesign != NULL)
|
|
{
|
|
ReleaseInterface((*ppDocDesign));
|
|
}
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
/*
|
|
* CSSPackager ##################################################
|
|
*/
|
|
|
|
HRESULT CSSPackager::Init(IHTMLElementCollection *pColl,
|
|
ULONG *pcElems,
|
|
IHTMLDocument2 *pDoc)
|
|
{
|
|
HRESULT hr = CRelativeURLPackager::Init( pColl, pcElems, pDoc );
|
|
|
|
m_pDoc = pDoc;
|
|
|
|
RRETURN(hr);
|
|
}
|
|
|
|
|
|
HRESULT CSSPackager::PackageStyleSheets(IHTMLDocument2 *pDoc2,
|
|
CWebArchive *pwa)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
IHTMLStyleSheetsCollection *pssc = NULL;
|
|
|
|
ASSERT(pDoc2);
|
|
ASSERT(pwa);
|
|
|
|
// process the inline style sheets
|
|
hr = pDoc2->get_styleSheets( &pssc );
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
hr = _PackageSSCollection(pssc, pwa);
|
|
pssc->Release();
|
|
}
|
|
|
|
return hr; // no RRETURN - may return S_FALSE
|
|
}
|
|
|
|
|
|
HRESULT CSSPackager::_PackageSSCollection(IHTMLStyleSheetsCollection *pssc,
|
|
CWebArchive *pwa)
|
|
{
|
|
HRESULT hr;
|
|
LONG cSS;
|
|
|
|
hr = pssc->get_length( &cSS );
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
LONG iSS;
|
|
|
|
for (iSS = 0; iSS < cSS && SUCCEEDED(hr); iSS++ )
|
|
{
|
|
VARIANT varIndex;
|
|
VARIANT varSS;
|
|
|
|
varIndex.vt = VT_I4;
|
|
varIndex.lVal = iSS;
|
|
varSS.vt = VT_EMPTY;
|
|
hr = pssc->item( &varIndex, &varSS );
|
|
if (SUCCEEDED(hr) && varSS.vt == VT_DISPATCH && varSS.pdispVal != NULL)
|
|
{
|
|
IHTMLStyleSheet *pss = NULL;
|
|
if(SUCCEEDED(varSS.pdispVal->QueryInterface(IID_IHTMLStyleSheet, (void**)&pss)))
|
|
{
|
|
hr = _PackageSS(pss, pwa);
|
|
pss->Release();
|
|
}
|
|
varSS.pdispVal->Release();
|
|
}
|
|
}
|
|
}
|
|
return hr; // no RRETURN - may return S_FALSE
|
|
}
|
|
|
|
|
|
HRESULT CSSPackager::_PackageSS(IHTMLStyleSheet *pss,
|
|
CWebArchive *pwa)
|
|
{
|
|
HRESULT hr;
|
|
BSTR bstrRelURL = NULL;
|
|
BSTR bstrAbsURL = NULL;
|
|
LONG lElemPos;
|
|
IHTMLElement *pElemOwner = NULL;
|
|
IHTMLStyleSheetsCollection *pssc = NULL;
|
|
BOOL fStyleTag = FALSE;
|
|
|
|
if (pss == NULL || pwa == NULL)
|
|
return E_INVALIDARG;
|
|
|
|
hr = pss->get_href(&bstrRelURL);
|
|
if (FAILED(hr))
|
|
goto error;
|
|
fStyleTag = bstrRelURL == NULL || *bstrRelURL == 0;
|
|
|
|
hr = pss->get_owningElement(&pElemOwner);
|
|
if (FAILED(hr))
|
|
goto error;
|
|
|
|
hr = pElemOwner->get_sourceIndex(&lElemPos);
|
|
if (FAILED(hr))
|
|
goto error;
|
|
|
|
hr = HrGetCombinedURL(m_pCollBase, m_cBase, lElemPos, bstrRelURL, m_bstrDocURL, &bstrAbsURL);
|
|
if (FAILED(hr))
|
|
goto error;
|
|
|
|
// First we do the defualt processing, gathering the imports into _our_
|
|
|
|
// process the inline style sheets
|
|
hr = pss->get_imports( &pssc );
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
long cSS;
|
|
|
|
hr = pssc->get_length( &cSS );
|
|
if (SUCCEEDED(hr) && cSS > 0)
|
|
{
|
|
CSSPackager importPkgr;
|
|
|
|
hr = importPkgr.Init(m_pCollBase, NULL, m_pDoc);
|
|
|
|
hr = importPkgr._PackageSSCollection(pssc, pwa);
|
|
}
|
|
pssc->Release();
|
|
}
|
|
|
|
// oh, yeah, if we want to do background-image and list-style-image, we'd enumerate this ss's rule styles
|
|
// here, find the ones with these attributes, and build a list of IHTML rule style, maybe using some sub-obj
|
|
// like an image packager.
|
|
|
|
if (SUCCEEDED(hr) && !fStyleTag)
|
|
{
|
|
BSTR bstrSSText;
|
|
|
|
// Now we grab our modified text and add it to the document.
|
|
hr = pss->get_cssText(&bstrSSText);
|
|
if (SUCCEEDED(hr) && bstrSSText != NULL)
|
|
{
|
|
LPSTR lpszSSText;
|
|
|
|
// This text needs to be ANSI before we put it into the stream.
|
|
hr = HrBSTRToLPSZ( bstrSSText, &lpszSSText );
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
// PTH hr = MimeOleCreateVirtualStream(&pstm);
|
|
TCHAR szStyleDoc[MAX_PATH];
|
|
CHashEntry *phe;
|
|
|
|
hr = pwa->AddFrameOrStyleEntry( bstrAbsURL, &phe, szStyleDoc );
|
|
|
|
if (hr==S_OK)
|
|
{
|
|
hr = pwa->ArchiveCSSText( bstrAbsURL, lpszSSText, szStyleDoc );
|
|
|
|
if ( SUCCEEDED(hr) )
|
|
hr = pss->put_href(phe->m_bstrValue);
|
|
}
|
|
else if (hr==S_FALSE)
|
|
{
|
|
// repeated style sheet, don't need to do all the work, but do need to note
|
|
// the ss for remapping
|
|
hr = pss->put_href( phe->m_bstrValue);
|
|
}
|
|
delete lpszSSText;
|
|
}
|
|
SysFreeString(bstrSSText);
|
|
}
|
|
}
|
|
|
|
error:
|
|
if (pElemOwner)
|
|
pElemOwner->Release();
|
|
if (bstrRelURL)
|
|
SysFreeString(bstrRelURL);
|
|
if (bstrAbsURL)
|
|
SysFreeString(bstrAbsURL);
|
|
|
|
return hr; // no RRETURN - may return S_FALSE
|
|
}
|
|
|
|
//
|
|
// Functions ##############################################################
|
|
//
|
|
|
|
HRESULT HrGetElement(IHTMLDocument2 *pDoc, LPCSTR pszName, IHTMLElement **ppElem)
|
|
{
|
|
HRESULT hr = E_FAIL;
|
|
IHTMLElementCollection *pCollect = NULL;
|
|
IDispatch *pDisp = NULL;
|
|
VARIANTARG va1, va2;
|
|
|
|
if (pDoc)
|
|
{
|
|
pDoc->get_all(&pCollect);
|
|
if (pCollect)
|
|
{
|
|
if (SUCCEEDED(HrLPSZToBSTR(pszName, &va1.bstrVal)))
|
|
{
|
|
va1.vt = VT_BSTR;
|
|
va2.vt = VT_EMPTY;
|
|
pCollect->item(va1, va2, &pDisp);
|
|
if (pDisp)
|
|
{
|
|
hr = pDisp->QueryInterface(IID_IHTMLElement, (LPVOID*)ppElem);
|
|
pDisp->Release();
|
|
}
|
|
SysFreeString(va1.bstrVal);
|
|
}
|
|
pCollect->Release();
|
|
}
|
|
}
|
|
return hr; // no RRETURN - may return S_FALSE
|
|
|
|
}
|
|
|
|
|
|
HRESULT HrGetBodyElement(IHTMLDocument2 *pDoc, IHTMLBodyElement **ppBody)
|
|
{
|
|
HRESULT hr=E_FAIL;
|
|
IHTMLElement *pElem=0;
|
|
|
|
if (ppBody == NULL)
|
|
return E_INVALIDARG;
|
|
|
|
*ppBody = 0;
|
|
if (pDoc)
|
|
{
|
|
pDoc->get_body(&pElem);
|
|
if (pElem)
|
|
{
|
|
hr = pElem->QueryInterface(IID_IHTMLBodyElement, (LPVOID *)ppBody);
|
|
pElem->Release();
|
|
}
|
|
}
|
|
return hr; // no RRETURN - may return S_FALSE
|
|
}
|
|
|
|
HRESULT HrGetMember(LPUNKNOWN pUnk, BSTR bstrMember,LONG lFlags, BSTR *pbstr)
|
|
{
|
|
IHTMLElement *pObj;
|
|
HRESULT hr;
|
|
VARIANT rVar;
|
|
|
|
hr = pUnk->QueryInterface(IID_IHTMLElement, (LPVOID *)&pObj);
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
ASSERT (pObj);
|
|
|
|
rVar.vt = VT_BSTR;
|
|
hr = pObj->getAttribute(bstrMember, lFlags, &rVar);
|
|
if (SUCCEEDED(hr) && rVar.vt == VT_BSTR && rVar.bstrVal != NULL)
|
|
{
|
|
*pbstr = rVar.bstrVal;
|
|
}
|
|
pObj->Release();
|
|
}
|
|
return hr; // no RRETURN - may return S_FALSE
|
|
}
|
|
|
|
|
|
|
|
ULONG UlGetCollectionCount(IHTMLElementCollection *pCollect)
|
|
{
|
|
ULONG ulCount=0;
|
|
|
|
if (pCollect)
|
|
pCollect->get_length((LONG *)&ulCount);
|
|
|
|
return ulCount;
|
|
}
|
|
|
|
HRESULT HrGetCollectionItem(IHTMLElementCollection *pCollect, ULONG uIndex, REFIID riid, LPVOID *ppvObj)
|
|
{
|
|
HRESULT hr=E_FAIL;
|
|
IDispatch *pDisp=0;
|
|
VARIANTARG va1,
|
|
va2;
|
|
|
|
va1.vt = VT_I4;
|
|
va2.vt = VT_EMPTY;
|
|
va1.lVal = (LONG)uIndex;
|
|
|
|
pCollect->item(va1, va2, &pDisp);
|
|
if (pDisp)
|
|
{
|
|
hr = pDisp->QueryInterface(riid, ppvObj);
|
|
pDisp->Release();
|
|
}
|
|
return hr; // no RRETURN - may return S_FALSE
|
|
}
|
|
|
|
HRESULT HrGetCollectionOf(IHTMLDocument2 *pDoc, BSTR bstrTagName, IHTMLElementCollection **ppCollect)
|
|
{
|
|
VARIANT v;
|
|
IDispatch *pDisp=0;
|
|
IHTMLElementCollection *pCollect=0;
|
|
HRESULT hr;
|
|
|
|
ASSERT(ppCollect);
|
|
ASSERT(bstrTagName);
|
|
ASSERT(pDoc);
|
|
|
|
*ppCollect = NULL;
|
|
|
|
hr = pDoc->get_all(&pCollect);
|
|
if (pCollect)
|
|
{
|
|
v.vt = VT_BSTR;
|
|
v.bstrVal = bstrTagName;
|
|
pCollect->tags(v, &pDisp);
|
|
if (pDisp)
|
|
{
|
|
hr = pDisp->QueryInterface(IID_IHTMLElementCollection, (LPVOID *)ppCollect);
|
|
pDisp->Release();
|
|
}
|
|
pCollect->Release();
|
|
}
|
|
else if (S_OK == hr)
|
|
hr = E_FAIL;
|
|
|
|
return hr; // no RRETURN - may return S_FALSE
|
|
}
|
|
|
|
HRESULT HrSetMember(LPUNKNOWN pUnk, BSTR bstrMember, BSTR bstrValue)
|
|
{
|
|
IHTMLElement *pObj;
|
|
HRESULT hr;
|
|
VARIANT rVar;
|
|
|
|
ASSERT(pUnk);
|
|
|
|
hr = pUnk->QueryInterface(IID_IHTMLElement, (LPVOID *)&pObj);
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
ASSERT (pObj);
|
|
rVar.vt = VT_BSTR;
|
|
rVar.bstrVal = bstrValue;
|
|
hr = pObj->setAttribute(bstrMember, rVar, FALSE);
|
|
pObj->Release();
|
|
}
|
|
return hr; // no RRETURN - may return S_FALSE
|
|
}
|
|
|
|
|
|
/*
|
|
* HrGetCombinedURL does some of the things that GetBackgroundImageUrl
|
|
* does, but in a more general way. It relies on the caller to have
|
|
* isolated the <BASE> collection and to supply the root document URL.
|
|
* While a trifle awkward, it is more efficient if the caller is going
|
|
* to combine many URLS.
|
|
*/
|
|
|
|
HRESULT HrGetCombinedURL( IHTMLElementCollection *pCollBase,
|
|
LONG cBase,
|
|
LONG lElemPos,
|
|
BSTR bstrRelURL,
|
|
BSTR bstrDocURL,
|
|
BSTR *pbstrBaseURL)
|
|
{
|
|
HRESULT hr = S_FALSE;
|
|
IHTMLElement *pElemBase;
|
|
IHTMLBaseElement *pBase;
|
|
LONG lBasePos=0,
|
|
lBasePosSoFar=0;
|
|
BSTR bstr = NULL;
|
|
LPWSTR pszUrlW=0;
|
|
WCHAR szBaseW[INTERNET_MAX_URL_LENGTH];
|
|
WCHAR szUrlW[INTERNET_MAX_URL_LENGTH];
|
|
DWORD cch=INTERNET_MAX_URL_LENGTH;
|
|
LONG i;
|
|
|
|
*pbstrBaseURL = 0;
|
|
*szBaseW = 0;
|
|
|
|
for (i=0; i<cBase; i++)
|
|
{
|
|
if (SUCCEEDED(HrGetCollectionItem(pCollBase, i, IID_IHTMLElement, (LPVOID *)&pElemBase)))
|
|
{
|
|
pElemBase->get_sourceIndex(&lBasePos);
|
|
if (lBasePos < lElemPos &&
|
|
lBasePos >= lBasePosSoFar)
|
|
{
|
|
if (SUCCEEDED(pElemBase->QueryInterface(IID_IHTMLBaseElement, (LPVOID *)&pBase)))
|
|
{
|
|
bstr = NULL;
|
|
if (pBase->get_href(&bstr)==S_OK && bstr != NULL)
|
|
{
|
|
ASSERT (bstr);
|
|
if (*bstr)
|
|
{
|
|
StrCpyNW(szBaseW, bstr, ARRAYSIZE(szBaseW));
|
|
lBasePosSoFar = lBasePos;
|
|
}
|
|
SysFreeString(bstr);
|
|
}
|
|
pBase->Release();
|
|
}
|
|
}
|
|
pElemBase->Release();
|
|
}
|
|
}
|
|
|
|
if (szBaseW[0] == 0 && bstrDocURL)
|
|
{
|
|
// We didn't find a <BASE> tag before our element, so fall back to using
|
|
// the document's location as basis for the base
|
|
StrCpyNW( szBaseW, bstrDocURL, ARRAYSIZE(szBaseW) );
|
|
}
|
|
|
|
#ifndef WIN16 //RUN16_BLOCK - UrlCombineW is not available
|
|
// if there's a <BASE> then do the combine
|
|
if (*szBaseW &&
|
|
SUCCEEDED(UrlCombineW(szBaseW, bstrRelURL, szUrlW, &cch, 0)))
|
|
pszUrlW = szUrlW;
|
|
#endif //!WIN16
|
|
|
|
// pszUrlW contains the combined <BODY> and <BASE> tag, return this.
|
|
if (pszUrlW)
|
|
*pbstrBaseURL = SysAllocString(pszUrlW);
|
|
|
|
return (*pbstrBaseURL == NULL ? S_FALSE : S_OK);
|
|
}
|
|
|
|
HRESULT HrLPSZToBSTR(LPCSTR lpsz, BSTR *pbstr)
|
|
{
|
|
HRESULT hr = NOERROR;
|
|
BSTR bstr=0;
|
|
ULONG cch = 0, ccb,
|
|
cchRet;
|
|
UINT cp = GetACP();
|
|
|
|
// get byte count
|
|
ccb = lstrlenA(lpsz);
|
|
|
|
// get character count - DBCS string ccb may not equal to cch
|
|
cch=MultiByteToWideChar(cp, 0, lpsz, ccb, NULL, 0);
|
|
if(cch==0 && ccb!=0)
|
|
{
|
|
ASSERT(FALSE);
|
|
hr=E_FAIL;
|
|
goto error;
|
|
}
|
|
|
|
// allocate a wide-string with enough character to hold string - use character count
|
|
bstr=SysAllocStringLen(NULL, cch);
|
|
if (!bstr)
|
|
{
|
|
hr=E_OUTOFMEMORY;
|
|
goto error;
|
|
}
|
|
|
|
cchRet=MultiByteToWideChar(cp, 0, lpsz, ccb, (LPWSTR)bstr, cch);
|
|
if (cchRet==0 && ccb!=0)
|
|
{
|
|
hr=E_FAIL;
|
|
goto error;
|
|
}
|
|
|
|
*pbstr = bstr;
|
|
bstr=0; // freed by caller
|
|
|
|
error:
|
|
if (bstr)
|
|
SysFreeString(bstr);
|
|
RRETURN(hr);
|
|
|
|
}
|
|
|
|
HRESULT HrBSTRToLPSZ(BSTR bstr, LPSTR *lplpsz)
|
|
{
|
|
ULONG cch = 0;
|
|
|
|
ASSERT (bstr && lplpsz);
|
|
|
|
cch = WideCharToMultiByte(CP_ACP, 0, bstr, -1, NULL, 0, NULL, NULL);
|
|
|
|
if (!cch)
|
|
{
|
|
return HRESULT_FROM_WIN32(GetLastError());
|
|
}
|
|
|
|
*lplpsz = new char[cch + 1];
|
|
|
|
if (!*lplpsz)
|
|
{
|
|
return E_OUTOFMEMORY;
|
|
}
|
|
|
|
if (WideCharToMultiByte(CP_ACP, 0, bstr, -1, *lplpsz, cch+1, NULL, NULL))
|
|
return S_OK;
|
|
else
|
|
return HRESULT_FROM_WIN32(GetLastError());
|
|
}
|
|
|
|
void RemoveBookMark(WCHAR *pwzURL, WCHAR **ppwzBookMark)
|
|
{
|
|
if (pwzURL && ppwzBookMark)
|
|
{
|
|
*ppwzBookMark = pwzURL;
|
|
|
|
while (**ppwzBookMark)
|
|
{
|
|
if (**ppwzBookMark == L'#')
|
|
{
|
|
**ppwzBookMark = L'\0';
|
|
break;
|
|
}
|
|
|
|
(*ppwzBookMark)++;
|
|
}
|
|
}
|
|
}
|
|
|
|
void RestoreBookMark(WCHAR *pwzBookMark)
|
|
{
|
|
if (pwzBookMark)
|
|
{
|
|
*pwzBookMark = L'#';
|
|
}
|
|
}
|
|
|