mimeflt.cpp
Upload User: xhy777
Upload Date: 2007-02-14
Package Size: 24088k
Code Size: 21k
Category:

Windows Kernel

Development Platform:

Visual C++

  1. // CLSID_CWebViewMimeFilter
  2. //
  3. // Mime filter for Web View (.htx) content. Does substitutions on:
  4. //
  5. //   %TEMPLATEDIR%
  6. //   %THISDIRPATH%
  7. //   %THISDIRNAME%
  8. //
  9. #include "stdafx.h"
  10. #pragma hdrstop
  11. //#include "clsobj.h"
  12. #define MAX_VARIABLE_NAME_SIZE 15 // see _Expand
  13. // urlmon uses a 2K buffer size, so match that in retail. To force
  14. // extra iterations and reallocations, use a smaller buffer size
  15. // in debug. To further save on reallocations, we don't read the
  16. // entire buffer to leave room for growth.
  17. #ifdef DEBUG
  18. #define BUFFER_SIZE 512
  19. #define BUFFER_ALLOC_SIZE BUFFER_SIZE
  20. #else
  21. #define BUFFER_SIZE 0x2000
  22. #define BUFFER_ALLOC_SIZE (BUFFER_SIZE+2*MAX_PATH)
  23. #endif
  24. #define BUFFER_SIZE_INC MAX_VARIABLE_NAME_SIZE*2 // must be > MAX_VARIABLE_NAME_SIZE
  25. #define TF_EXPAND 0 // show strings as they are expanded in our mime filter?
  26. class CWebViewMimeFilter : public IInternetProtocol
  27.                          , public IInternetProtocolSink
  28.                          , public IServiceProvider
  29. {
  30. public:
  31.     virtual STDMETHODIMP QueryInterface(REFIID riid, void **ppvObj);
  32.     virtual STDMETHODIMP_(ULONG) AddRef(void);
  33.     virtual STDMETHODIMP_(ULONG) Release(void);
  34.     // IInternetProtocol methods
  35.     STDMETHOD(Start)(
  36.             LPCWSTR szUrl,
  37.             IInternetProtocolSink *pProtSink,
  38.             IInternetBindInfo *pOIBindInfo,
  39.             DWORD grfSTI,
  40.             DWORD dwReserved);
  41.     STDMETHOD(Continue)(PROTOCOLDATA *pStateInfo);
  42.     STDMETHOD(Abort)(HRESULT hrReason,DWORD dwOptions);
  43.     STDMETHOD(Terminate)(DWORD dwOptions);
  44.     STDMETHOD(Suspend)();
  45.     STDMETHOD(Resume)();
  46.     STDMETHOD(Read)(void *pv,ULONG cb,ULONG *pcbRead);
  47.     STDMETHOD(Seek)(
  48.             LARGE_INTEGER dlibMove,
  49.             DWORD dwOrigin,
  50.             ULARGE_INTEGER *plibNewPosition);
  51.     STDMETHOD(LockRequest)(DWORD dwOptions);
  52.     STDMETHOD(UnlockRequest)();
  53.     // IInternetProtocolSink methods
  54.     STDMETHOD(Switch)(PROTOCOLDATA * pProtocolData);
  55.     STDMETHOD(ReportProgress)(ULONG ulStatusCode, LPCWSTR pwszStatusText);
  56.     STDMETHOD(ReportData)(DWORD grfBSCF, ULONG ulProgress, ULONG ulProgressMax);
  57.     STDMETHOD(ReportResult)(HRESULT hrResult, DWORD dwError, LPCWSTR pwszResult);
  58.     // IServiceProvider methods
  59.     STDMETHOD(QueryService)(REFGUID rsid, REFIID riid, void ** ppvObj);
  60. private:
  61.     CWebViewMimeFilter();
  62.     ~CWebViewMimeFilter();
  63.     friend HRESULT CWebViewMimeFilter_CreateInstance(LPUNKNOWN punkOuter, REFIID riid, void **ppvOut);
  64.     LPBYTE _StrCmp(LPBYTE pSrc, LPCSTR pAnsi, LPWSTR pUnicode);
  65.     LPBYTE _StrChr(LPBYTE pSrc, char chA, WCHAR chW);
  66.     int    _StrLen(LPBYTE pStr);
  67.     void _QueryForDVCMDID(int dvcmdid, LPBYTE pDst, int cbDst);
  68.     HRESULT _IncreaseBuffer(ULONG cbIncrement, LPBYTE * pp1, LPBYTE * pp2);
  69.     int _Expand(LPBYTE pszVar, LPBYTE * ppszExp);
  70.     HRESULT _ReadAndExpandBuffer();
  71.     int _cRef;
  72.     LPBYTE _pBuf;       // our buffer
  73.     ULONG _cbBufSize;   // size of the buffer
  74.     ULONG _nCharSize;   // sizeof(char) or sizeof(WCHAR) depending on data type
  75.     ULONG _cbBuf;       // count of bytes read into the buffer
  76.     ULONG _cbSeek;      // offset to seek position
  77.     BYTE  _szTemplateDirPath[MAX_PATH];
  78.     ULONG _cbTemplateDirPath;
  79.     BYTE  _szThisDirPath[MAX_PATH];
  80.     ULONG _cbThisDirPath;
  81.     BYTE  _szThisDirName[MAX_PATH];
  82.     ULONG _cbThisDirname;
  83.     IInternetProtocol*         _pProt;             // incoming
  84.     IInternetProtocolSink*     _pProtSink;         // outgoing
  85. };
  86. CWebViewMimeFilter::CWebViewMimeFilter()
  87. {
  88.     _cRef = 1;
  89. }
  90. CWebViewMimeFilter::~CWebViewMimeFilter()
  91. {
  92.     ATOMICRELEASE(_pProt);
  93.     if (_pBuf)
  94.     {
  95.         LocalFree(_pBuf);
  96.         _pBuf = NULL;
  97.         _cbBufSize = 0;
  98.     }
  99.     ASSERT(NULL == _pProtSink);
  100. }
  101. HRESULT CWebViewMimeFilter_CreateInstance(LPUNKNOWN punkOuter, REFIID riid, void **ppvOut)
  102. {
  103.     // aggregation checking is handled in class factory
  104.     HRESULT hres;
  105.     CWebViewMimeFilter* pObj;
  106.     pObj = new CWebViewMimeFilter();
  107.     if (pObj)
  108.     {
  109.         hres = pObj->QueryInterface(riid, ppvOut);
  110.         pObj->Release();
  111.     }
  112.     else
  113.     {
  114.         *ppvOut = NULL;
  115.         hres = E_OUTOFMEMORY;
  116.     }
  117.     return hres;
  118. }
  119. ULONG CWebViewMimeFilter::AddRef(void)
  120. {
  121.     _cRef++;
  122.     return _cRef;
  123. }
  124. ULONG CWebViewMimeFilter::Release(void)
  125. {
  126.     _cRef--;
  127.     if (_cRef > 0)
  128.         return _cRef;
  129.     delete this;
  130.     return 0;
  131. }
  132. HRESULT CWebViewMimeFilter::QueryInterface(REFIID riid, void **ppvObj)
  133. {
  134.     static const QITAB qit[] = {
  135.         QITABENT(CWebViewMimeFilter, IInternetProtocol),
  136.         QITABENTMULTI(CWebViewMimeFilter, IInternetProtocolRoot, IInternetProtocol),
  137.         QITABENT(CWebViewMimeFilter, IInternetProtocolSink),
  138.         QITABENT(CWebViewMimeFilter, IServiceProvider),
  139.         { 0 },
  140.     };
  141.     return QISearch(this, qit, riid, ppvObj);
  142. }
  143. // IInternetProtocol methods
  144. HRESULT CWebViewMimeFilter::Start(
  145.         LPCWSTR szUrl,
  146.         IInternetProtocolSink *pProtSink,
  147.         IInternetBindInfo *pOIBindInfo,
  148.         DWORD grfSTI,
  149.         DWORD dwReserved)
  150. {
  151.     HRESULT hr;
  152.     if (!(EVAL(grfSTI & PI_FILTER_MODE)))
  153.     {
  154.         hr = E_INVALIDARG;
  155.     }
  156.     else
  157.     {
  158.         // get the Prot pointer here
  159.         PROTOCOLFILTERDATA* FiltData = (PROTOCOLFILTERDATA*) dwReserved;
  160.         ASSERT(NULL == _pProt);
  161.         _pProt = FiltData->pProtocol;
  162.         _pProt->AddRef();
  163.         // hold onto the sink as well
  164.         ASSERT(NULL == _pProtSink);
  165.         _pProtSink = pProtSink;
  166.         _pProtSink->AddRef();
  167.         // this filter converts text/webviewhtml to text/html
  168.         _pProtSink->ReportProgress(BINDSTATUS_FILTERREPORTMIMETYPE, L"text/html");
  169.         
  170.         hr = S_OK;
  171.     }
  172.     return hr;
  173. }
  174. HRESULT CWebViewMimeFilter::Continue(PROTOCOLDATA *pStateInfo)
  175. {
  176.     ASSERT(_pProt);
  177.     return _pProt->Continue(pStateInfo);
  178. }
  179. HRESULT CWebViewMimeFilter::Abort(HRESULT hrReason,DWORD dwOptions)
  180. {
  181.     ATOMICRELEASE(_pProtSink); // probably to remove ref cycle
  182.     ASSERT(_pProt);
  183.     return _pProt->Abort(hrReason, dwOptions);
  184. }
  185. HRESULT CWebViewMimeFilter::Terminate(DWORD dwOptions)
  186. {
  187.     ATOMICRELEASE(_pProtSink); // probably to remove ref cycle
  188.     return _pProt->Terminate(dwOptions);
  189. }
  190. HRESULT CWebViewMimeFilter::Suspend()
  191. {
  192.     return _pProt->Suspend();
  193. }
  194. HRESULT CWebViewMimeFilter::Resume()
  195. {
  196.     return _pProt->Resume();
  197. }
  198. LPBYTE CWebViewMimeFilter::_StrCmp(LPBYTE pSrc, LPCSTR pAnsi, LPWSTR pUnicode)
  199. {
  200.     if (SIZEOF(char) == _nCharSize)
  201.     {
  202.         return (LPBYTE)lstrcmpA(pAnsi, (LPSTR)pSrc);
  203.     }
  204.     else
  205.     {
  206.         ASSERT(_nCharSize == SIZEOF(WCHAR));
  207.         return (LPBYTE)StrCmpW(pUnicode, (LPWSTR)pSrc);
  208.     }
  209. }
  210. LPBYTE CWebViewMimeFilter::_StrChr(LPBYTE pSrc, char chA, WCHAR chW)
  211. {
  212.     if (SIZEOF(char) == _nCharSize)
  213.     {
  214.         return (LPBYTE)StrChrA((LPSTR)pSrc, chA);
  215.     }
  216.     else
  217.     {
  218.         return (LPBYTE)StrChrW((LPWSTR)pSrc, chW);
  219.     }
  220. }
  221. int CWebViewMimeFilter::_StrLen(LPBYTE pStr)
  222. {
  223.     if (SIZEOF(char) == _nCharSize)
  224.     {
  225.         return lstrlenA((LPSTR)pStr);
  226.     }
  227.     else
  228.     {
  229.         return lstrlenW((LPWSTR)pStr);
  230.     }
  231. }
  232. /*
  233.  * UnicodeToHTMLEscapeStringAnsi
  234.  *
  235.  * Takes a unicode string as the input source and translates it into an ansi string that mshtml can process.  Characters > 127 will be
  236.  * translated into an html escape sequence that has the following syntax:  "&#xxxxx;" where xxxxx is the string representation of the decimal
  237.  * integer which is the value for the unicode character.  In this manner we are able to generate HTML text which represent UNICODE characters.
  238.  */
  239. #define MAX_HTML_ESCAPE_SEQUENCE 9  // longest string representation of a 16 bit integer is 65535.  So, entire composite escape string has:
  240.                                     // 2 for "&#" + maximum of 5 digits + 1 for ";" + 1 for NULL terminator = 9 characters
  241. void UnicodeToHTMLEscapeStringAnsi(LPWSTR pstrSrc, LPSTR pstrDest, int cbDest)
  242. {
  243.     while (*pstrSrc && (cbDest >= MAX_HTML_ESCAPE_SEQUENCE))
  244.     {
  245.         int iLen;
  246.         ULONG ul = MAKELONG(*pstrSrc, 0);
  247.         // We can optimize the common ansi characters to avoid generating the long escape sequence.  This allows us to fit
  248.         // longer paths in the buffer.
  249.         if (ul < 128)
  250.         {
  251.             *pstrDest = (CHAR)*pstrSrc;
  252.             iLen = 1;
  253.         }
  254.         else
  255.         {
  256.             iLen = wsprintfA(pstrDest, "&#%lu;", ul);
  257.         }
  258.         pstrDest += iLen;
  259.         cbDest -= iLen;
  260.         pstrSrc++;
  261.     }
  262.     *pstrDest = 0;
  263. }
  264. void CWebViewMimeFilter::_QueryForDVCMDID(int dvcmdid, LPBYTE pDst, int cbDst)
  265. {
  266.     IOleCommandTarget * pct;
  267.     if (SUCCEEDED(QueryService(SID_DefView, IID_IOleCommandTarget, (LPVOID*)&pct)))
  268.     {
  269.         VARIANT v = {0};
  270.         if (S_OK == pct->Exec(&CGID_DefView, dvcmdid, 0, NULL, &v))
  271.         {
  272.             if (v.vt == VT_BSTR)
  273.             {
  274.                 if (SIZEOF(char) == _nCharSize)
  275.                 {
  276.                     UnicodeToHTMLEscapeStringAnsi(v.bstrVal, (LPSTR)pDst, cbDst);
  277.                 }
  278.                 else
  279.                 {
  280.                     ASSERT(_nCharSize == SIZEOF(WCHAR));
  281.             
  282.                     StrCpyNW((LPWSTR)pDst, v.bstrVal, cbDst/sizeof(WCHAR));
  283.                 }
  284.             }
  285.             VariantClear(&v);
  286.         }
  287.         pct->Release();
  288.     }
  289. }
  290. int CWebViewMimeFilter::_Expand(LPBYTE pszVar, LPBYTE * ppszExp)
  291. {
  292.     if (!_StrCmp(pszVar, "TEMPLATEDIR", L"TEMPLATEDIR"))
  293.     {
  294.         if (!_szTemplateDirPath[0])
  295.         {
  296. #ifdef UNICODE
  297.             WCHAR wszBuf[MAX_PATH];
  298.             GetWindowsDirectory(wszBuf, ARRAYSIZE(wszBuf));
  299.             WideCharToMultiByte(CP_ACP, 0, wszBuf, -1, (LPSTR)_szTemplateDirPath, sizeof(_szTemplateDirPath)/sizeof(WCHAR), NULL, NULL);
  300. #else
  301.             GetWindowsDirectory((LPSTR)_szTemplateDirPath, sizeof(_szTemplateDirPath)/sizeof(char));
  302. #endif
  303.             StrNCatA((LPSTR)_szTemplateDirPath, "\WEB", sizeof(_szTemplateDirPath)/sizeof(char));
  304.             if (SIZEOF(WCHAR)==_nCharSize)
  305.             {
  306.                 char szBuf[MAX_PATH];
  307.                 lstrcpyA(szBuf, (LPSTR)_szTemplateDirPath);
  308.                 _cbTemplateDirPath = MultiByteToWideChar(CP_ACP, 0, szBuf, -1,
  309.                         (LPWSTR)_szTemplateDirPath, sizeof(_szTemplateDirPath)/sizeof(WCHAR));
  310.             }
  311.         }
  312.         *ppszExp = _szTemplateDirPath;
  313.     }
  314.     else if (!_StrCmp(pszVar, "THISDIRPATH", L"THISDIRPATH"))
  315.     {
  316.         if (!_szThisDirPath[0])
  317.         {
  318.             _QueryForDVCMDID(DVCMDID_GETTHISDIRPATH, _szThisDirPath, SIZEOF(_szThisDirPath));
  319.         }
  320.         *ppszExp = _szThisDirPath;
  321.     }
  322.     else if (!_StrCmp(pszVar, "THISDIRNAME", L"THISDIRNAME"))
  323.     {
  324.         if (!_szThisDirName[0])
  325.         {
  326.             _QueryForDVCMDID(DVCMDID_GETTHISDIRNAME, _szThisDirName, SIZEOF(_szThisDirName));
  327.         }
  328.         *ppszExp = _szThisDirName;
  329.     }
  330.     else
  331.     {
  332.         *ppszExp = (LPBYTE)(L""); // just in case memcpy doesn't like a null pointer
  333.     }
  334.     return _StrLen(*ppszExp);
  335. }
  336. //
  337. //  Ensure room for at least cbIncrement more bytes at the end of the buffer.
  338. //  If the memory gets moved or realloced, *pp1 and *pp2 are adjusted to
  339. //  point to the corresponding bytes at their new location(s).
  340. //
  341. HRESULT CWebViewMimeFilter::_IncreaseBuffer(ULONG cbIncrement, LPBYTE * pp1, LPBYTE * pp2)
  342. {
  343.     HRESULT hr = S_OK;
  344.     // first check if there's room at the beginning of the buffer
  345.     if (_cbSeek >= cbIncrement)
  346.     {
  347.         MoveMemory(_pBuf, _pBuf + _cbSeek, _cbBuf - _cbSeek);
  348.         _cbBuf -= _cbSeek;
  349.         if (pp1)
  350.             *pp1 = *pp1 - _cbSeek;
  351.         if (pp2)
  352.             *pp2 = *pp2 - _cbSeek;
  353.         _cbSeek = 0;
  354.     }
  355.     else
  356.     {
  357.         // not enough room, so allocate more memory
  358.         LPBYTE p = (LPBYTE)LocalReAlloc(_pBuf, _cbBufSize + cbIncrement, LMEM_MOVEABLE);
  359.         if (!p)
  360.         {
  361.             hr = E_OUTOFMEMORY;
  362.         }
  363.         else
  364.         {
  365.             if (pp1)
  366.                 *pp1 = p + (int)(*pp1 - _pBuf);
  367.             if (pp2)
  368.                 *pp2 = p + (int)(*pp2 - _pBuf);
  369.     
  370.             _pBuf = p;
  371.             _cbBufSize += cbIncrement;
  372.         }
  373.     }
  374.     return hr;
  375. }
  376. HRESULT CWebViewMimeFilter::_ReadAndExpandBuffer()
  377. {
  378.     HRESULT hr;
  379.     _cbBuf = 0;
  380.     _cbSeek = 0;
  381.     if (!_pBuf)
  382.     {
  383.         _pBuf = (LPBYTE)LocalAlloc(LPTR, BUFFER_ALLOC_SIZE);
  384.         if (!_pBuf)
  385.             return E_OUTOFMEMORY;
  386.         _cbBufSize = BUFFER_ALLOC_SIZE;
  387.     }
  388.     // As strings expand, our buffer grows. If we keep reading in the
  389.     // max amount, we'll keep reallocating the more variable expansions
  390.     // we do. By only reading in BUFFER_SIZE, our _pBuf will grow only
  391.     // a few times and then all the variable expansions should fit
  392.     // in the extra room generated. NOTE: for debug builds, always
  393.     // read the most we can, so we reallocate more often.
  394. #ifdef DEBUG
  395.     #define BUFFER_READ_SIZE (_cbBufSize)
  396. #else
  397.     #define BUFFER_READ_SIZE BUFFER_SIZE
  398. #endif
  399.     hr = _pProt->Read(_pBuf, BUFFER_READ_SIZE-SIZEOF(WCHAR), &_cbBuf); // make sure we have room for NULL
  400.     if (SUCCEEDED(hr) && _cbBuf > 0)
  401.     {
  402.         LPBYTE pchSeek = _pBuf;
  403.         LPBYTE pchEnd;
  404.         if (!_nCharSize)
  405.         {
  406.             // scan buffer and figure out if it's unicode or ansi
  407.             //
  408.             // since we'll always be looking at html and the html header
  409.             // is standard ansi chars, every other byte will be null if
  410.             // we have a unicode buffer. i'm sure 3 checks are enough,
  411.             // so we'll require 8 characters...
  412.             if (_cbBuf > 6 &&
  413.                 0 == _pBuf[1] &&
  414.                 0 == _pBuf[3] &&
  415.                 0 == _pBuf[5])
  416.             {
  417.                 TraceMsg(TF_EXPAND, "WebView MIME filter - buffer is UNICODE");
  418.                 _nCharSize = SIZEOF(WCHAR);
  419.             }
  420.             else
  421.             {
  422.                 TraceMsg(TF_EXPAND, "WebView MIME filter - buffer is ANSI");
  423.                 _nCharSize = SIZEOF(char);
  424.             }
  425.         }
  426.         // The string had better be null-terminated, for not only are we
  427.         // going to do a StrChr, but our loop control relies on it!
  428.         // The buffer might have leftover goo from a previous go-round, so
  429.         // ensure that the nulls are there.
  430.         _pBuf[_cbBuf] = _pBuf[_cbBuf+1] = 0;
  431. #ifdef DEBUG
  432.         if (SIZEOF(char)==_nCharSize)
  433.             TraceMsg(TF_EXPAND, "Read A[%hs]", _pBuf);
  434.         else
  435.             TraceMsg(TF_EXPAND, "Read W[%ls]", _pBuf);
  436. #endif
  437.         do {
  438.             LPBYTE pchStart = pchSeek;
  439.             // Assert that the string is still properly null-terminated
  440.             // because we're going to be doing StrChr soon.
  441.             ASSERT(_pBuf[_cbBuf] == 0);
  442.             ASSERT(_pBuf[_cbBuf+1] == 0);
  443.             pchSeek = _StrChr(pchSeek, '%', L'%');
  444.             if (!pchSeek)
  445.                 break;
  446.             pchEnd = _StrChr(pchSeek+_nCharSize, '%', L'%');
  447.             if (!pchEnd)
  448.             {
  449.                 // no terminator. if there's plenty of space to the end of
  450.                 // this buffer then there can't be a clipped variable
  451.                 // name to expand.
  452.                 if (_cbBuf - (pchSeek - _pBuf) > MAX_VARIABLE_NAME_SIZE*_nCharSize)
  453.                     break;
  454.                 // there may be a real variable here we need to expand,
  455.                 // so increase our buffer size and read some more data.
  456.                 //
  457.                 // we may get re-allocated, so update pchStart!
  458.                 hr = _IncreaseBuffer(BUFFER_SIZE_INC, &pchStart, NULL);
  459.                 if (FAILED(hr))
  460.                     break;
  461.                 pchSeek = pchStart;
  462.                 // read in more info -- this will be enough to complete
  463.                 // any partial variable name expansions
  464.                 DWORD dwTmp;
  465.                 ASSERT(_cbBufSize - _cbBuf - SIZEOF(WCHAR) > 0);
  466.                 hr = _pProt->Read(_pBuf + _cbBuf, _cbBufSize-_cbBuf-SIZEOF(WCHAR), &dwTmp);
  467.                 if (FAILED(hr) || dwTmp == 0)
  468.                     break;
  469.                 _cbBuf += dwTmp;
  470.                 // Ensure proper null termination
  471.                 _pBuf[_cbBuf] = _pBuf[_cbBuf+1] = 0;
  472.                 continue;
  473.             }
  474.             // figure out what to expand to
  475.             LPBYTE pszExp;
  476.             BYTE b[2];
  477.             b[0] = pchEnd[0];
  478.             b[1] = pchEnd[1];
  479.             pchEnd[0] = 0;
  480.             pchEnd[1] = 0;
  481.             int cbExp = _Expand(pchSeek + _nCharSize, &pszExp);
  482.             pchEnd[0] = b[0];
  483.             pchEnd[1] = b[1];
  484.             if (!cbExp)
  485.             {
  486.                 // if it's not a recognized variable, use the bytes as they are
  487.                 pchSeek = pchEnd;
  488.                 continue;
  489.             }
  490.             // cbVar = number of bytes being replaced (sizeof("%VARNAME%"))
  491.             // pchSeek points to the starting percent sign and pchEnd to
  492.             // the trailing percent sign, so we need to add one more
  493.             // _nCharSize to include the trailing percent sign itself.
  494.             int cbVar = (int)(pchEnd - pchSeek) + _nCharSize;
  495.             if (_cbBuf - cbVar + cbExp  > _cbBufSize - SIZEOF(WCHAR))
  496.             {
  497.                 hr = _IncreaseBuffer((_cbBuf - cbVar + cbExp) - (_cbBufSize - SIZEOF(WCHAR)), &pchSeek, &pchEnd);
  498.                 if (FAILED(hr))
  499.                     break;
  500.             }
  501.             // move the bytes around!
  502.             // cbSeek = the number of bytes before the first percent sign
  503.             int cbSeek = (int)(pchSeek - _pBuf);
  504.             ASSERT(_cbBuf - cbVar + cbExp <= _cbBufSize - SIZEOF(WCHAR));
  505.             // Move the stuff after the %VARNAME% to its final home
  506.             // Don't forget to move the artificial trailing NULLs too!
  507.             MoveMemory(pchSeek + cbExp, pchEnd + _nCharSize, _cbBuf - cbSeek - cbVar + SIZEOF(WCHAR));
  508.             // Insert the expansion
  509.             MoveMemory(pchSeek, pszExp, cbExp);
  510.             // on to the rest of the buffer...
  511.             pchSeek = pchEnd + _nCharSize;
  512.             _cbBuf = _cbBuf - cbVar + cbExp;
  513.         } while (*pchSeek);
  514. #ifdef DEBUG
  515.         if (SIZEOF(char)==_nCharSize)
  516.             TraceMsg(TF_EXPAND, "---> A[%s]", _pBuf);
  517.         else
  518.             TraceMsg(TF_EXPAND, "---> W[%hs]", _pBuf);
  519. #endif
  520.     }
  521.     else
  522.     {
  523.         // we're at end of stream
  524.         hr = S_FALSE;
  525.     }
  526.     return hr;
  527. }
  528. HRESULT CWebViewMimeFilter::Read(void *pv,ULONG cb,ULONG *pcbRead)
  529. {
  530.     HRESULT hr = S_OK;
  531.     if (!_pProt)
  532.     {
  533.         hr = E_FAIL;
  534.     }
  535.     else
  536.     {
  537.         *pcbRead = 0;
  538.         while (cb)
  539.         {
  540.             // if our buffer is empty, fill it
  541.             if (_cbSeek == _cbBuf)
  542.             {
  543.                 hr = _ReadAndExpandBuffer();
  544.             }
  545.             // do we have any data to copy?
  546.             int cbLeft = _cbBuf - _cbSeek;
  547.             if (SUCCEEDED(hr) && cbLeft > 0)
  548.             {
  549.                 ULONG cbCopy = min(cb, (ULONG)cbLeft);
  550.                 memcpy(pv, &_pBuf[_cbSeek], cbCopy);
  551.                 pv = (LPVOID)(((LPBYTE)pv) + cbCopy);
  552.                 cb -= cbCopy;
  553.                 *pcbRead += cbCopy;
  554.                 _cbSeek += cbCopy;
  555.                 // do not return S_FALSE if some bytes were left unread
  556.                 if (cbCopy < (ULONG)cbLeft)
  557.                     hr = S_OK;
  558.             }
  559.             else
  560.             {
  561.                 ASSERT(FAILED(hr) || hr == S_FALSE);
  562.                 // nothing left to copy
  563.                 break;
  564.             }
  565.         }
  566.     }
  567.     return hr;
  568. }
  569. HRESULT CWebViewMimeFilter::Seek(
  570.         LARGE_INTEGER dlibMove,
  571.         DWORD dwOrigin,
  572.         ULARGE_INTEGER *plibNewPosition)
  573. {
  574.     return E_NOTIMPL;
  575. }
  576. HRESULT CWebViewMimeFilter::LockRequest(DWORD dwOptions)
  577. {
  578.     return S_OK;
  579. }
  580. HRESULT CWebViewMimeFilter::UnlockRequest()
  581. {
  582.     return S_OK;
  583. }
  584. // IInternetProtocolSink methods
  585. HRESULT CWebViewMimeFilter::Switch(PROTOCOLDATA * pProtocolData)
  586. {
  587.     if (_pProtSink)
  588.         return _pProtSink->Switch(pProtocolData);
  589.     return E_FAIL;
  590. }
  591. HRESULT CWebViewMimeFilter::ReportProgress(ULONG ulStatusCode, LPCWSTR pwszStatusText)
  592. {
  593.     if (_pProtSink)
  594.         return _pProtSink->ReportProgress(ulStatusCode, pwszStatusText);
  595.     return E_FAIL;
  596. }
  597. HRESULT CWebViewMimeFilter::ReportData(DWORD grfBSCF, ULONG ulProgress, ULONG ulProgressMax)
  598. {
  599.     if (_pProtSink)
  600.         return _pProtSink->ReportData(grfBSCF, ulProgress, ulProgressMax);
  601.     return E_FAIL;
  602. }
  603. HRESULT CWebViewMimeFilter::ReportResult(HRESULT hrResult, DWORD dwError, LPCWSTR pwszResult)
  604. {
  605.     if (_pProtSink)
  606.         return _pProtSink->ReportResult(hrResult, dwError, pwszResult);
  607.     return E_FAIL;
  608. }
  609. //IServiceProvider methods
  610. HRESULT CWebViewMimeFilter::QueryService(REFGUID rsid, REFIID riid, void ** ppvObj)
  611. {
  612.     HRESULT             hr;
  613.     IServiceProvider *  pSP;
  614.     *ppvObj = NULL;
  615.     hr = _pProtSink->QueryInterface(IID_IServiceProvider, (void **)&pSP);
  616.     if (SUCCEEDED(hr))
  617.     {
  618.         hr = pSP->QueryService(rsid, riid, ppvObj);
  619.         pSP->Release();
  620.     }
  621.     return hr;
  622. }