|
|
// CLSID_CWebViewMimeFilter
//
// Mime filter for Web View (.htt) content. Does substitutions on:
//
// %TEMPLATEDIR%
// %THISDIRPATH%
// %THISDIRNAME%
//
#include "stdafx.h"
#pragma hdrstop
#define MAX_VARIABLE_NAME_SIZE 15 // see _Expand
// urlmon uses a 2K buffer size, so match that in retail. To force
// extra iterations and reallocations, use a smaller buffer size
// in debug. To further save on reallocations, we don't read the
// entire buffer to leave room for growth.
#ifdef DEBUG
#define BUFFER_SIZE 512
#define BUFFER_ALLOC_SIZE BUFFER_SIZE
#else
#define BUFFER_SIZE 0x2000
#define BUFFER_ALLOC_SIZE (BUFFER_SIZE+2*MAX_PATH)
#endif
#define BUFFER_SIZE_INC MAX_VARIABLE_NAME_SIZE*2 // must be > MAX_VARIABLE_NAME_SIZE
#define TF_EXPAND 0 // show strings as they are expanded in our mime filter?
#define MAX_HTML_ESCAPE_SEQUENCE 8 // longest string representation of a 16 bit integer is 65535. So, entire composite escape string has:
// 2 for "&#" + maximum of 5 digits + 1 for ";" = 8 characters
class CWebViewMimeFilter : public IInternetProtocol , public IInternetProtocolSink , public IServiceProvider { public: virtual STDMETHODIMP QueryInterface(REFIID riid, void **ppvObj); virtual STDMETHODIMP_(ULONG) AddRef(void); virtual STDMETHODIMP_(ULONG) Release(void);
// IInternetProtocol methods
STDMETHOD(Start)( LPCWSTR szUrl, IInternetProtocolSink *pProtSink, IInternetBindInfo *pOIBindInfo, DWORD grfSTI, HANDLE_PTR dwReserved); STDMETHOD(Continue)(PROTOCOLDATA *pStateInfo); STDMETHOD(Abort)(HRESULT hrReason,DWORD dwOptions); STDMETHOD(Terminate)(DWORD dwOptions); STDMETHOD(Suspend)(); STDMETHOD(Resume)(); STDMETHOD(Read)(void *pv,ULONG cb,ULONG *pcbRead); STDMETHOD(Seek)( LARGE_INTEGER dlibMove, DWORD dwOrigin, ULARGE_INTEGER *plibNewPosition); STDMETHOD(LockRequest)(DWORD dwOptions); STDMETHOD(UnlockRequest)();
// IInternetProtocolSink methods
STDMETHOD(Switch)(PROTOCOLDATA * pProtocolData); STDMETHOD(ReportProgress)(ULONG ulStatusCode, LPCWSTR pwszStatusText); STDMETHOD(ReportData)(DWORD grfBSCF, ULONG ulProgress, ULONG ulProgressMax); STDMETHOD(ReportResult)(HRESULT hrResult, DWORD dwError, LPCWSTR pwszResult);
// IServiceProvider methods
STDMETHOD(QueryService)(REFGUID rsid, REFIID riid, void ** ppvObj);
private: CWebViewMimeFilter(); ~CWebViewMimeFilter(); friend HRESULT CWebViewMimeFilter_CreateInstance(LPUNKNOWN punkOuter, REFIID riid, void **ppvOut);
int _StrCmp(LPBYTE pSrc, LPCSTR pAnsi, LPWSTR pUnicode); LPBYTE _StrChr(LPBYTE pSrc, char chA, WCHAR chW); int _StrLen(LPBYTE pStr);
void _QueryForDVCMDID(int dvcmdid, LPBYTE pDst, int cbDst); void _EncodeHtml(LPBYTE psz, size_t cbByte); HRESULT _IncreaseBuffer(ULONG cbIncrement, LPBYTE * pp1, LPBYTE * pp2); int _Expand(LPBYTE pszVar, LPBYTE * ppszExp); HRESULT _ReadAndExpandBuffer();
int _cRef;
LPBYTE _pBuf; // our buffer
ULONG _cbBufSize; // size of the buffer
ULONG _nCharSize; // sizeof(char) or sizeof(WCHAR) depending on data type
ULONG _cbBuf; // count of bytes read into the buffer
ULONG _cbSeek; // offset to seek position
BYTE _szTemplateDirPath[2*MAX_PATH]; BYTE _szThisDirPath[MAX_HTML_ESCAPE_SEQUENCE*MAX_PATH]; BYTE _szThisDirName[MAX_HTML_ESCAPE_SEQUENCE*MAX_PATH]; BYTE _szExpansion[2*MAX_PATH];
IInternetProtocol* _pProt; // incoming
IInternetProtocolSink* _pProtSink; // outgoing
};
CWebViewMimeFilter::CWebViewMimeFilter() { _cRef = 1; }
CWebViewMimeFilter::~CWebViewMimeFilter() { ATOMICRELEASE(_pProt);
if (_pBuf) { LocalFree(_pBuf); _pBuf = NULL; _cbBufSize = 0; }
ASSERT(NULL == _pProtSink); }
HRESULT CWebViewMimeFilter_CreateInstance(LPUNKNOWN punkOuter, REFIID riid, void **ppvOut) { // aggregation checking is handled in class factory
HRESULT hres; CWebViewMimeFilter* pObj;
pObj = new CWebViewMimeFilter(); if (pObj) { hres = pObj->QueryInterface(riid, ppvOut); pObj->Release(); } else { *ppvOut = NULL; hres = E_OUTOFMEMORY; }
return hres; }
ULONG CWebViewMimeFilter::AddRef(void) { _cRef++; return _cRef; }
ULONG CWebViewMimeFilter::Release(void) { _cRef--;
if (_cRef > 0) return _cRef;
delete this;
return 0; }
HRESULT CWebViewMimeFilter::QueryInterface(REFIID riid, void **ppvObj) { static const QITAB qit[] = { QITABENT(CWebViewMimeFilter, IInternetProtocol), QITABENTMULTI(CWebViewMimeFilter, IInternetProtocolRoot, IInternetProtocol), QITABENT(CWebViewMimeFilter, IInternetProtocolSink), QITABENT(CWebViewMimeFilter, IServiceProvider), { 0 }, };
return QISearch(this, qit, riid, ppvObj); }
// IInternetProtocol methods
HRESULT CWebViewMimeFilter::Start( LPCWSTR szUrl, IInternetProtocolSink *pProtSink, IInternetBindInfo *pOIBindInfo, DWORD grfSTI, HANDLE_PTR dwReserved) { HRESULT hr;
if (!(EVAL(grfSTI & PI_FILTER_MODE))) { hr = E_INVALIDARG; } else { // get the Prot pointer here
PROTOCOLFILTERDATA* FiltData = (PROTOCOLFILTERDATA*) dwReserved; ASSERT(NULL == _pProt); _pProt = FiltData->pProtocol; _pProt->AddRef();
// hold onto the sink as well
ASSERT(NULL == _pProtSink); _pProtSink = pProtSink; _pProtSink->AddRef();
// this filter converts text/webviewhtml to text/html
_pProtSink->ReportProgress(BINDSTATUS_FILTERREPORTMIMETYPE, L"text/html");
hr = S_OK; }
return hr; } HRESULT CWebViewMimeFilter::Continue(PROTOCOLDATA *pStateInfo) { ASSERT(_pProt); return _pProt->Continue(pStateInfo); } HRESULT CWebViewMimeFilter::Abort(HRESULT hrReason,DWORD dwOptions) { ATOMICRELEASE(_pProtSink); // probably to remove ref cycle
ASSERT(_pProt); return _pProt->Abort(hrReason, dwOptions); } HRESULT CWebViewMimeFilter::Terminate(DWORD dwOptions) { ATOMICRELEASE(_pProtSink); // probably to remove ref cycle
return _pProt->Terminate(dwOptions); } HRESULT CWebViewMimeFilter::Suspend() { return _pProt->Suspend(); } HRESULT CWebViewMimeFilter::Resume() { return _pProt->Resume(); }
int CWebViewMimeFilter::_StrCmp(LPBYTE pSrc, LPCSTR pAnsi, LPWSTR pUnicode) { if (sizeof(char) == _nCharSize) { return lstrcmpA(pAnsi, (LPSTR)pSrc); } else { ASSERT(_nCharSize == sizeof(WCHAR));
return StrCmpW(pUnicode, (LPWSTR)pSrc); } }
LPBYTE CWebViewMimeFilter::_StrChr(LPBYTE pSrc, char chA, WCHAR chW) { if (sizeof(char) == _nCharSize) { return (LPBYTE)StrChrA((LPSTR)pSrc, chA); } else { return (LPBYTE)StrChrW((LPWSTR)pSrc, chW); } }
int CWebViewMimeFilter::_StrLen(LPBYTE pStr) { if (sizeof(char) == _nCharSize) { return lstrlenA((LPSTR)pStr); } else { return lstrlenW((LPWSTR)pStr); } }
/*
* UnicodeToHTMLEscapeStringAnsi * * Takes a unicode string as the input source and translates it into an ansi string that mshtml can process. Characters > 127 will be * translated into an html escape sequence that has the following syntax: "&#xxxxx;" where xxxxx is the string representation of the decimal * integer which is the value for the unicode character. In this manner we are able to generate HTML text which represent UNICODE characters. */ void UnicodeToHTMLEscapeStringAnsi(LPWSTR pstrSrc, LPSTR pstrDest, int cbDest) { LPSTR pstrDestOriginal = pstrDest;
while (*pstrSrc && (cbDest > MAX_HTML_ESCAPE_SEQUENCE)) { int iLen; ULONG ul = MAKELONG(*pstrSrc, 0);
// We can optimize the common ansi characters to avoid generating the long escape sequence. This allows us to fit
// longer paths in the buffer.
if (ul < 128) { *pstrDest = (CHAR)*pstrSrc; iLen = 1; } else { HRESULT hr = StringCchPrintfA(pstrDest, cbDest, "&#%lu;", ul); if (FAILED(hr)) { *pstrDestOriginal = '\0'; return; } iLen = lstrlenA(pstrDest); } pstrDest += iLen; cbDest -= iLen; pstrSrc++; } *pstrDest = 0; }
void CWebViewMimeFilter::_QueryForDVCMDID(int dvcmdid, LPBYTE pDst, int cbDst) { IOleCommandTarget * pct; if (SUCCEEDED(QueryService(SID_DefView, IID_IOleCommandTarget, (LPVOID*)&pct))) { VARIANT v = {0};
if (S_OK == pct->Exec(&CGID_DefView, dvcmdid, 0, NULL, &v)) { if (v.vt == VT_BSTR) { if (sizeof(char) == _nCharSize) { UnicodeToHTMLEscapeStringAnsi(v.bstrVal, (LPSTR)pDst, cbDst); } else { ASSERT(_nCharSize == sizeof(WCHAR)); HRESULT hr = StringCbCopy((LPWSTR)pDst, cbDst, v.bstrVal); if (FAILED(hr)) { *((LPWSTR)pDst) = L'\0'; } } }
VariantClear(&v); } pct->Release(); } }
void ConvertTCharToBytes(LPCTSTR psz, UINT nCharSize, LPBYTE pBuf, int nBytes) { if (sizeof(char) == nCharSize) { SHTCharToAnsi(psz, (LPSTR)pBuf, nBytes/nCharSize); } else { ASSERT(nCharSize == sizeof(WCHAR)); SHTCharToUnicode(psz, (LPWSTR)pBuf, nBytes/nCharSize); } }
void GetMachineTemplateDir(LPBYTE pszTemplateDirPath, int nBytes, UINT nCharSize) { TCHAR szTemplateDir[MAX_PATH]; szTemplateDir[0] = TEXT('\0'); SHGetWebFolderFilePath(TEXT(""), szTemplateDir, ARRAYSIZE(szTemplateDir)); // Remove the trailing back slash, if any
int len = lstrlen(szTemplateDir); if ((len > 0) && (szTemplateDir[len - 1] == TEXT('\\'))) { szTemplateDir[len - 1] = TEXT('\0'); }
ConvertTCharToBytes(szTemplateDir, nCharSize, pszTemplateDirPath, nBytes); }
#define REG_WEBVIEW_TEMPLATE_MACROS TEXT("Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\WebView\\TemplateMacros")
void ConvertBytesToTChar(LPCBYTE pBuf, UINT nCharSize, LPTSTR psz, int cch) { if (sizeof(char) == nCharSize) { SHAnsiToTChar((LPCSTR)pBuf, psz, cch); } else { ASSERT(nCharSize == sizeof(WCHAR)); SHUnicodeToTChar((LPCWSTR)pBuf, psz, cch); } }
void ExpandMacro(LPBYTE pszMacro, LPBYTE pszExpansion, int nBytes, UINT nCharSize) { TCHAR szExpansion[MAX_PATH]; szExpansion[0] = TEXT('\0'); TCHAR szTCharMacro[MAX_PATH]; ConvertBytesToTChar(pszMacro, nCharSize, szTCharMacro, ARRAYSIZE(szTCharMacro)); TCHAR szKey[MAX_PATH]; HRESULT hr = StringCchPrintf(szKey, ARRAYSIZE(szKey), TEXT("%s\\%s"), REG_WEBVIEW_TEMPLATE_MACROS, szTCharMacro); if (SUCCEEDED(hr)) { HKEY hkMacros; if (RegOpenKeyEx(HKEY_CURRENT_USER, szKey, 0, KEY_QUERY_VALUE, &hkMacros) == ERROR_SUCCESS || RegOpenKeyEx(HKEY_LOCAL_MACHINE, szKey, 0, KEY_QUERY_VALUE, &hkMacros) == ERROR_SUCCESS) { DWORD dwType; DWORD cbData = sizeof(szExpansion); SHQueryValueEx(hkMacros, NULL, NULL, &dwType, (LPBYTE)szExpansion, &cbData); RegCloseKey(hkMacros); } } ConvertTCharToBytes(szExpansion, nCharSize, pszExpansion, nBytes); }
// Replace the first character of pszDst with the string pszIns.
//
HRESULT StringCchReplaceFirstCharWithStringA(LPSTR psz, size_t cch, LPCSTR pszIns) { HRESULT hr;
size_t cchIns = lstrlenA(pszIns);
if (cchIns < cch ) { MoveMemory(psz + cchIns, psz + 1, cch - cchIns); *(psz + cch - 1) = '\0'; MoveMemory(psz, pszIns, cchIns); hr = S_OK; } else { hr = HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER); }
return hr; }
HRESULT StringCchReplaceFirstCharWithStringW(LPWSTR psz, size_t cch, LPCWSTR pszIns) { HRESULT hr;
size_t cchIns = lstrlenW(pszIns);
if (cchIns < cch) { MoveMemory(psz + cchIns, psz + 1, (cch - cchIns) * sizeof(WCHAR)); *(psz + cch - 1) = L'\0'; MoveMemory(psz, pszIns, cchIns * sizeof(WCHAR)); hr = S_OK; } else { hr = HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER); }
return hr; }
void CWebViewMimeFilter::_EncodeHtml(LPBYTE psz, size_t cb) { HRESULT hr; size_t length;
if (sizeof(char) == _nCharSize) { while (*psz) { switch (*psz) { case '<': hr = StringCchReplaceFirstCharWithStringA((LPSTR)psz, cb, "<"); length = 3; break;
case '>': hr = StringCchReplaceFirstCharWithStringA((LPSTR)psz, cb, ">"); length = 3; break;
case '"': hr = StringCchReplaceFirstCharWithStringA((LPSTR)psz, cb, """); length = 5; break;
default: hr = S_OK; length = 1; break; }
if (SUCCEEDED(hr)) { psz += length; cb -= length; } else { *psz = '\0'; } } } else { ASSERT(sizeof(WCHAR) == _nCharSize);
WCHAR* pszW = (WCHAR*)psz; size_t cchW = cb / sizeof(WCHAR);
while (*pszW) { switch (*pszW) { case L'<': hr = StringCchReplaceFirstCharWithStringW(pszW, cchW, L"<"); length = 3; break;
case L'>': hr = StringCchReplaceFirstCharWithStringW(pszW, cchW, L">"); length = 3; break;
case L'"': hr = StringCchReplaceFirstCharWithStringW(pszW, cchW, L"""); length = 5; break;
default: hr = S_OK; length = 1; break; }
if (SUCCEEDED(hr)) { pszW += length; cchW -= length; } else { *pszW = L'\0'; } } } }
int CWebViewMimeFilter::_Expand(LPBYTE pszVar, LPBYTE * ppszExp) { if (!_StrCmp(pszVar, "TEMPLATEDIR", L"TEMPLATEDIR")) { if (!_szTemplateDirPath[0]) { GetMachineTemplateDir(_szTemplateDirPath, sizeof(_szTemplateDirPath), _nCharSize); _EncodeHtml(_szTemplateDirPath, sizeof(_szTemplateDirPath)); } *ppszExp = _szTemplateDirPath; } else if (!_StrCmp(pszVar, "THISDIRPATH", L"THISDIRPATH")) { if (!_szThisDirPath[0]) { _QueryForDVCMDID(DVCMDID_GETTHISDIRPATH, _szThisDirPath, sizeof(_szThisDirPath)); _EncodeHtml(_szThisDirPath, sizeof(_szThisDirPath)); } *ppszExp = _szThisDirPath; } else if (!_StrCmp(pszVar, "THISDIRNAME", L"THISDIRNAME")) { if (!_szThisDirName[0]) { _QueryForDVCMDID(DVCMDID_GETTHISDIRNAME, _szThisDirName, sizeof(_szThisDirName)); _EncodeHtml(_szThisDirName, sizeof(_szThisDirName)); } *ppszExp = _szThisDirName; } else { ExpandMacro(pszVar, _szExpansion, sizeof(_szExpansion), _nCharSize); _EncodeHtml(_szExpansion, sizeof(_szExpansion)); *ppszExp = _szExpansion; }
return _StrLen(*ppszExp); }
//
// Ensure room for at least cbIncrement more bytes at the end of the buffer.
// If the memory gets moved or realloced, *pp1 and *pp2 are adjusted to
// point to the corresponding bytes at their new location(s).
//
HRESULT CWebViewMimeFilter::_IncreaseBuffer(ULONG cbIncrement, LPBYTE * pp1, LPBYTE * pp2) { HRESULT hr = S_OK;
// first check if there's room at the beginning of the buffer
if (_cbSeek >= cbIncrement) { MoveMemory(_pBuf, _pBuf + _cbSeek, _cbBuf - _cbSeek); _cbBuf -= _cbSeek;
if (pp1) *pp1 = *pp1 - _cbSeek; if (pp2) *pp2 = *pp2 - _cbSeek;
_cbSeek = 0; } else { // not enough room, so allocate more memory
LPBYTE p = (LPBYTE)LocalReAlloc(_pBuf, _cbBufSize + cbIncrement, LMEM_MOVEABLE); if (!p) { hr = E_OUTOFMEMORY; } else { if (pp1) *pp1 = p + (int)(*pp1 - _pBuf); if (pp2) *pp2 = p + (int)(*pp2 - _pBuf); _pBuf = p; _cbBufSize += cbIncrement; } }
return hr; }
HRESULT CWebViewMimeFilter::_ReadAndExpandBuffer() { HRESULT hr;
_cbBuf = 0; _cbSeek = 0;
if (!_pBuf) { _pBuf = (LPBYTE)LocalAlloc(LPTR, BUFFER_ALLOC_SIZE); if (!_pBuf) return E_OUTOFMEMORY;
_cbBufSize = BUFFER_ALLOC_SIZE; }
// As strings expand, our buffer grows. If we keep reading in the
// max amount, we'll keep reallocating the more variable expansions
// we do. By only reading in BUFFER_SIZE, our _pBuf will grow only
// a few times and then all the variable expansions should fit
// in the extra room generated. NOTE: for debug builds, always
// read the most we can, so we reallocate more often.
#ifdef DEBUG
#define BUFFER_READ_SIZE (_cbBufSize)
#else
#define BUFFER_READ_SIZE BUFFER_SIZE
#endif
hr = _pProt->Read(_pBuf, BUFFER_READ_SIZE - sizeof(WCHAR), &_cbBuf); // make sure we have room for NULL
if (SUCCEEDED(hr) && _cbBuf > 0) { LPBYTE pchSeek = _pBuf; LPBYTE pchEnd;
if (!_nCharSize) { // scan buffer and figure out if it's unicode or ansi
//
// since we'll always be looking at html and the html header
// is standard ansi chars, every other byte will be null if
// we have a unicode buffer. i'm sure 3 checks are enough,
// so we'll require 8 characters...
if (_cbBuf > 6 && 0 == _pBuf[1] && 0 == _pBuf[3] && 0 == _pBuf[5]) { TraceMsg(TF_EXPAND, "WebView MIME filter - buffer is UNICODE"); _nCharSize = sizeof(WCHAR); } else { TraceMsg(TF_EXPAND, "WebView MIME filter - buffer is ANSI"); _nCharSize = sizeof(char); } }
// The string had better be null-terminated, for not only are we
// going to do a StrChr, but our loop control relies on it!
// The buffer might have leftover goo from a previous go-round, so
// ensure that the nulls are there.
_pBuf[_cbBuf] = _pBuf[_cbBuf+1] = 0;
#ifdef DEBUG
if (sizeof(char)==_nCharSize) TraceMsg(TF_EXPAND, "Read A[%hs]", _pBuf); else TraceMsg(TF_EXPAND, "Read W[%ls]", _pBuf); #endif
do { LPBYTE pchStart = pchSeek;
// Assert that the string is still properly null-terminated
// because we're going to be doing StrChr soon.
ASSERT(_pBuf[_cbBuf] == 0); ASSERT(_pBuf[_cbBuf+1] == 0);
pchSeek = _StrChr(pchSeek, '%', L'%'); if (!pchSeek) break;
pchEnd = _StrChr(pchSeek+_nCharSize, '%', L'%'); if (!pchEnd) { // no terminator. if there's plenty of space to the end of
// this buffer then there can't be a clipped variable
// name to expand.
if (_cbBuf - (pchSeek - _pBuf) > MAX_VARIABLE_NAME_SIZE*_nCharSize) break;
// there may be a real variable here we need to expand,
// so increase our buffer size and read some more data.
//
// we may get re-allocated, so update pchStart!
hr = _IncreaseBuffer(BUFFER_SIZE_INC, &pchStart, NULL); if (FAILED(hr)) break; pchSeek = pchStart;
// read in more info -- this will be enough to complete
// any partial variable name expansions
DWORD dwTmp; ASSERT(_cbBufSize - _cbBuf - sizeof(WCHAR) > 0); hr = _pProt->Read(_pBuf + _cbBuf, _cbBufSize- _cbBuf - sizeof(WCHAR), &dwTmp); if (FAILED(hr) || dwTmp == 0) break; _cbBuf += dwTmp; // Ensure proper null termination
_pBuf[_cbBuf] = _pBuf[_cbBuf+1] = 0; continue; }
// figure out what to expand to
LPBYTE pszExp; BYTE b[2];
b[0] = pchEnd[0]; b[1] = pchEnd[1]; pchEnd[0] = 0; pchEnd[1] = 0; int cbExp = _Expand(pchSeek + _nCharSize, &pszExp); pchEnd[0] = b[0]; pchEnd[1] = b[1];
if (!cbExp) { // if it's not a recognized variable, use the bytes as they are
pchSeek = pchEnd; continue; }
// cbVar = number of bytes being replaced (sizeof("%VARNAME%"))
// pchSeek points to the starting percent sign and pchEnd to
// the trailing percent sign, so we need to add one more
// _nCharSize to include the trailing percent sign itself.
int cbVar = (int)(pchEnd - pchSeek) + _nCharSize;
if (_cbBuf - cbVar + cbExp > _cbBufSize - sizeof(WCHAR)) { hr = _IncreaseBuffer((_cbBuf - cbVar + cbExp) - (_cbBufSize - sizeof(WCHAR)), &pchSeek, &pchEnd); if (FAILED(hr)) break; }
// move the bytes around!
// cbSeek = the number of bytes before the first percent sign
int cbSeek = (int)(pchSeek - _pBuf); ASSERT(_cbBuf - cbVar + cbExp <= _cbBufSize - sizeof(WCHAR)); // Move the stuff after the %VARNAME% to its final home
// Don't forget to move the artificial trailing NULLs too!
MoveMemory(pchSeek + cbExp, pchEnd + _nCharSize, _cbBuf - cbSeek - cbVar + sizeof(WCHAR));
// Insert the expansion
MoveMemory(pchSeek, pszExp, cbExp);
// on to the rest of the buffer...
pchSeek = pchEnd + _nCharSize; _cbBuf = _cbBuf - cbVar + cbExp;
} while (*pchSeek);
#ifdef DEBUG
if (sizeof(char)==_nCharSize) TraceMsg(TF_EXPAND, "---> A[%s]", _pBuf); else TraceMsg(TF_EXPAND, "---> W[%hs]", _pBuf); #endif
} else { // we're at end of stream
hr = S_FALSE; }
return hr; }
HRESULT CWebViewMimeFilter::Read(void *pv,ULONG cb,ULONG *pcbRead) { HRESULT hr = S_OK;
if (!_pProt) { hr = E_FAIL; } else { *pcbRead = 0;
while (cb) { // if our buffer is empty, fill it
if (_cbSeek == _cbBuf) { hr = _ReadAndExpandBuffer(); }
// do we have any data to copy?
int cbLeft = _cbBuf - _cbSeek; if (SUCCEEDED(hr) && cbLeft > 0) { ULONG cbCopy = min(cb, (ULONG)cbLeft);
memcpy(pv, &_pBuf[_cbSeek], cbCopy);
pv = (LPVOID)(((LPBYTE)pv) + cbCopy); cb -= cbCopy; *pcbRead += cbCopy; _cbSeek += cbCopy;
// do not return S_FALSE if some bytes were left unread
if (cbCopy < (ULONG)cbLeft) hr = S_OK; } else { ASSERT(FAILED(hr) || hr == S_FALSE);
// nothing left to copy
break; } } } return hr; } HRESULT CWebViewMimeFilter::Seek( LARGE_INTEGER dlibMove, DWORD dwOrigin, ULARGE_INTEGER *plibNewPosition) { return E_NOTIMPL; } HRESULT CWebViewMimeFilter::LockRequest(DWORD dwOptions) { return S_OK; } HRESULT CWebViewMimeFilter::UnlockRequest() { return S_OK; }
// IInternetProtocolSink methods
HRESULT CWebViewMimeFilter::Switch(PROTOCOLDATA * pProtocolData) { if (_pProtSink) return _pProtSink->Switch(pProtocolData); return E_FAIL; } HRESULT CWebViewMimeFilter::ReportProgress(ULONG ulStatusCode, LPCWSTR pwszStatusText) { if (_pProtSink) return _pProtSink->ReportProgress(ulStatusCode, pwszStatusText); return E_FAIL; } HRESULT CWebViewMimeFilter::ReportData(DWORD grfBSCF, ULONG ulProgress, ULONG ulProgressMax) { if (_pProtSink) return _pProtSink->ReportData(grfBSCF, ulProgress, ulProgressMax); return E_FAIL; } HRESULT CWebViewMimeFilter::ReportResult(HRESULT hrResult, DWORD dwError, LPCWSTR pwszResult) { if (_pProtSink) return _pProtSink->ReportResult(hrResult, dwError, pwszResult); return E_FAIL; }
//IServiceProvider methods
HRESULT CWebViewMimeFilter::QueryService(REFGUID rsid, REFIID riid, void ** ppvObj) { return IUnknown_QueryService(_pProtSink, rsid, riid, ppvObj); }
|