Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

895 lines
25 KiB

  1. // CLSID_CWebViewMimeFilter
  2. //
  3. // Mime filter for Web View (.htt) content. Does substitutions on:
  4. //
  5. // %TEMPLATEDIR%
  6. // %THISDIRPATH%
  7. // %THISDIRNAME%
  8. //
  9. #include "stdafx.h"
  10. #pragma hdrstop
  11. #define MAX_VARIABLE_NAME_SIZE 15 // see _Expand
  12. // urlmon uses a 2K buffer size, so match that in retail. To force
  13. // extra iterations and reallocations, use a smaller buffer size
  14. // in debug. To further save on reallocations, we don't read the
  15. // entire buffer to leave room for growth.
  16. #ifdef DEBUG
  17. #define BUFFER_SIZE 512
  18. #define BUFFER_ALLOC_SIZE BUFFER_SIZE
  19. #else
  20. #define BUFFER_SIZE 0x2000
  21. #define BUFFER_ALLOC_SIZE (BUFFER_SIZE+2*MAX_PATH)
  22. #endif
  23. #define BUFFER_SIZE_INC MAX_VARIABLE_NAME_SIZE*2 // must be > MAX_VARIABLE_NAME_SIZE
  24. #define TF_EXPAND 0 // show strings as they are expanded in our mime filter?
  25. #define MAX_HTML_ESCAPE_SEQUENCE 8 // longest string representation of a 16 bit integer is 65535. So, entire composite escape string has:
  26. // 2 for "&#" + maximum of 5 digits + 1 for ";" = 8 characters
  27. class CWebViewMimeFilter : public IInternetProtocol
  28. , public IInternetProtocolSink
  29. , public IServiceProvider
  30. {
  31. public:
  32. virtual STDMETHODIMP QueryInterface(REFIID riid, void **ppvObj);
  33. virtual STDMETHODIMP_(ULONG) AddRef(void);
  34. virtual STDMETHODIMP_(ULONG) Release(void);
  35. // IInternetProtocol methods
  36. STDMETHOD(Start)(
  37. LPCWSTR szUrl,
  38. IInternetProtocolSink *pProtSink,
  39. IInternetBindInfo *pOIBindInfo,
  40. DWORD grfSTI,
  41. HANDLE_PTR dwReserved);
  42. STDMETHOD(Continue)(PROTOCOLDATA *pStateInfo);
  43. STDMETHOD(Abort)(HRESULT hrReason,DWORD dwOptions);
  44. STDMETHOD(Terminate)(DWORD dwOptions);
  45. STDMETHOD(Suspend)();
  46. STDMETHOD(Resume)();
  47. STDMETHOD(Read)(void *pv,ULONG cb,ULONG *pcbRead);
  48. STDMETHOD(Seek)(
  49. LARGE_INTEGER dlibMove,
  50. DWORD dwOrigin,
  51. ULARGE_INTEGER *plibNewPosition);
  52. STDMETHOD(LockRequest)(DWORD dwOptions);
  53. STDMETHOD(UnlockRequest)();
  54. // IInternetProtocolSink methods
  55. STDMETHOD(Switch)(PROTOCOLDATA * pProtocolData);
  56. STDMETHOD(ReportProgress)(ULONG ulStatusCode, LPCWSTR pwszStatusText);
  57. STDMETHOD(ReportData)(DWORD grfBSCF, ULONG ulProgress, ULONG ulProgressMax);
  58. STDMETHOD(ReportResult)(HRESULT hrResult, DWORD dwError, LPCWSTR pwszResult);
  59. // IServiceProvider methods
  60. STDMETHOD(QueryService)(REFGUID rsid, REFIID riid, void ** ppvObj);
  61. private:
  62. CWebViewMimeFilter();
  63. ~CWebViewMimeFilter();
  64. friend HRESULT CWebViewMimeFilter_CreateInstance(LPUNKNOWN punkOuter, REFIID riid, void **ppvOut);
  65. int _StrCmp(LPBYTE pSrc, LPCSTR pAnsi, LPWSTR pUnicode);
  66. LPBYTE _StrChr(LPBYTE pSrc, char chA, WCHAR chW);
  67. int _StrLen(LPBYTE pStr);
  68. void _QueryForDVCMDID(int dvcmdid, LPBYTE pDst, int cbDst);
  69. void _EncodeHtml(LPBYTE psz, size_t cbByte);
  70. HRESULT _IncreaseBuffer(ULONG cbIncrement, LPBYTE * pp1, LPBYTE * pp2);
  71. int _Expand(LPBYTE pszVar, LPBYTE * ppszExp);
  72. HRESULT _ReadAndExpandBuffer();
  73. int _cRef;
  74. LPBYTE _pBuf; // our buffer
  75. ULONG _cbBufSize; // size of the buffer
  76. ULONG _nCharSize; // sizeof(char) or sizeof(WCHAR) depending on data type
  77. ULONG _cbBuf; // count of bytes read into the buffer
  78. ULONG _cbSeek; // offset to seek position
  79. BYTE _szTemplateDirPath[2*MAX_PATH];
  80. BYTE _szThisDirPath[MAX_HTML_ESCAPE_SEQUENCE*MAX_PATH];
  81. BYTE _szThisDirName[MAX_HTML_ESCAPE_SEQUENCE*MAX_PATH];
  82. BYTE _szExpansion[2*MAX_PATH];
  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. HANDLE_PTR 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. hr = S_OK;
  170. }
  171. return hr;
  172. }
  173. HRESULT CWebViewMimeFilter::Continue(PROTOCOLDATA *pStateInfo)
  174. {
  175. ASSERT(_pProt);
  176. return _pProt->Continue(pStateInfo);
  177. }
  178. HRESULT CWebViewMimeFilter::Abort(HRESULT hrReason,DWORD dwOptions)
  179. {
  180. ATOMICRELEASE(_pProtSink); // probably to remove ref cycle
  181. ASSERT(_pProt);
  182. return _pProt->Abort(hrReason, dwOptions);
  183. }
  184. HRESULT CWebViewMimeFilter::Terminate(DWORD dwOptions)
  185. {
  186. ATOMICRELEASE(_pProtSink); // probably to remove ref cycle
  187. return _pProt->Terminate(dwOptions);
  188. }
  189. HRESULT CWebViewMimeFilter::Suspend()
  190. {
  191. return _pProt->Suspend();
  192. }
  193. HRESULT CWebViewMimeFilter::Resume()
  194. {
  195. return _pProt->Resume();
  196. }
  197. int CWebViewMimeFilter::_StrCmp(LPBYTE pSrc, LPCSTR pAnsi, LPWSTR pUnicode)
  198. {
  199. if (SIZEOF(char) == _nCharSize)
  200. {
  201. return lstrcmpA(pAnsi, (LPSTR)pSrc);
  202. }
  203. else
  204. {
  205. ASSERT(_nCharSize == SIZEOF(WCHAR));
  206. return StrCmpW(pUnicode, (LPWSTR)pSrc);
  207. }
  208. }
  209. LPBYTE CWebViewMimeFilter::_StrChr(LPBYTE pSrc, char chA, WCHAR chW)
  210. {
  211. if (SIZEOF(char) == _nCharSize)
  212. {
  213. return (LPBYTE)StrChrA((LPSTR)pSrc, chA);
  214. }
  215. else
  216. {
  217. return (LPBYTE)StrChrW((LPWSTR)pSrc, chW);
  218. }
  219. }
  220. int CWebViewMimeFilter::_StrLen(LPBYTE pStr)
  221. {
  222. if (SIZEOF(char) == _nCharSize)
  223. {
  224. return lstrlenA((LPSTR)pStr);
  225. }
  226. else
  227. {
  228. return lstrlenW((LPWSTR)pStr);
  229. }
  230. }
  231. /*
  232. * UnicodeToHTMLEscapeStringAnsi
  233. *
  234. * Takes a unicode string as the input source and translates it into an ansi string that mshtml can process. Characters > 127 will be
  235. * translated into an html escape sequence that has the following syntax: "&#xxxxx;" where xxxxx is the string representation of the decimal
  236. * integer which is the value for the unicode character. In this manner we are able to generate HTML text which represent UNICODE characters.
  237. */
  238. void UnicodeToHTMLEscapeStringAnsi(LPWSTR pstrSrc, LPSTR pstrDest, int cbDest)
  239. {
  240. while (*pstrSrc && (cbDest > MAX_HTML_ESCAPE_SEQUENCE))
  241. {
  242. int iLen;
  243. ULONG ul = MAKELONG(*pstrSrc, 0);
  244. // We can optimize the common ansi characters to avoid generating the long escape sequence. This allows us to fit
  245. // longer paths in the buffer.
  246. if (ul < 128)
  247. {
  248. *pstrDest = (CHAR)*pstrSrc;
  249. iLen = 1;
  250. }
  251. else
  252. {
  253. iLen = wsprintfA(pstrDest, "&#%lu;", ul);
  254. }
  255. pstrDest += iLen;
  256. cbDest -= iLen;
  257. pstrSrc++;
  258. }
  259. *pstrDest = 0;
  260. }
  261. void CWebViewMimeFilter::_QueryForDVCMDID(int dvcmdid, LPBYTE pDst, int cbDst)
  262. {
  263. IOleCommandTarget * pct;
  264. if (SUCCEEDED(QueryService(SID_DefView, IID_IOleCommandTarget, (LPVOID*)&pct)))
  265. {
  266. VARIANT v = {0};
  267. if (S_OK == pct->Exec(&CGID_DefView, dvcmdid, 0, NULL, &v))
  268. {
  269. if (v.vt == VT_BSTR)
  270. {
  271. if (SIZEOF(char) == _nCharSize)
  272. {
  273. UnicodeToHTMLEscapeStringAnsi(v.bstrVal, (LPSTR)pDst, cbDst);
  274. }
  275. else
  276. {
  277. ASSERT(_nCharSize == SIZEOF(WCHAR));
  278. StrCpyNW((LPWSTR)pDst, v.bstrVal, cbDst/sizeof(WCHAR));
  279. }
  280. }
  281. VariantClear(&v);
  282. }
  283. pct->Release();
  284. }
  285. }
  286. void ConvertTCharToBytes(LPCTSTR psz, UINT nCharSize, LPBYTE pBuf, int nBytes)
  287. {
  288. if (SIZEOF(char) == nCharSize)
  289. {
  290. SHTCharToAnsi(psz, (LPSTR)pBuf, nBytes/nCharSize);
  291. }
  292. else
  293. {
  294. ASSERT(nCharSize == SIZEOF(WCHAR));
  295. SHTCharToUnicode(psz, (LPWSTR)pBuf, nBytes/nCharSize);
  296. }
  297. }
  298. void GetMachineTemplateDir(LPBYTE pszTemplateDirPath, int nBytes, UINT nCharSize)
  299. {
  300. TCHAR szTemplateDir[MAX_PATH];
  301. szTemplateDir[0] = TEXT('\0');
  302. SHGetWebFolderFilePath(TEXT(""), szTemplateDir, ARRAYSIZE(szTemplateDir));
  303. // Remove the trailing back slash, if any
  304. int len = lstrlen(szTemplateDir);
  305. if ((len > 0) && (szTemplateDir[len - 1] == TEXT('\\')))
  306. {
  307. szTemplateDir[len - 1] = TEXT('\0');
  308. }
  309. ConvertTCharToBytes(szTemplateDir, nCharSize, pszTemplateDirPath, nBytes);
  310. }
  311. #define REG_WEBVIEW_TEMPLATE_MACROS TEXT("Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\WebView\\TemplateMacros")
  312. void ConvertBytesToTChar(LPCBYTE pBuf, UINT nCharSize, LPTSTR psz, int cch)
  313. {
  314. if (SIZEOF(char) == nCharSize)
  315. {
  316. SHAnsiToTChar((LPCSTR)pBuf, psz, cch);
  317. }
  318. else
  319. {
  320. ASSERT(nCharSize == SIZEOF(WCHAR));
  321. SHUnicodeToTChar((LPCWSTR)pBuf, psz, cch);
  322. }
  323. }
  324. void ExpandMacro(LPBYTE pszMacro, LPBYTE pszExpansion, int nBytes, UINT nCharSize)
  325. {
  326. TCHAR szExpansion[MAX_PATH];
  327. szExpansion[0] = TEXT('\0');
  328. TCHAR szTCharMacro[MAX_PATH];
  329. ConvertBytesToTChar(pszMacro, nCharSize, szTCharMacro, ARRAYSIZE(szTCharMacro));
  330. TCHAR szKey[MAX_PATH];
  331. lstrcpyn(szKey, REG_WEBVIEW_TEMPLATE_MACROS, ARRAYSIZE(szKey));
  332. StrCatBuff(szKey, TEXT("\\"), ARRAYSIZE(szKey));
  333. StrCatBuff(szKey, szTCharMacro, ARRAYSIZE(szKey));
  334. HKEY hkMacros;
  335. if (RegOpenKey(HKEY_CURRENT_USER, szKey, &hkMacros) == ERROR_SUCCESS
  336. || RegOpenKey(HKEY_LOCAL_MACHINE, szKey, &hkMacros) == ERROR_SUCCESS)
  337. {
  338. DWORD dwType;
  339. DWORD cbData = SIZEOF(szExpansion);
  340. SHQueryValueEx(hkMacros, NULL, NULL, &dwType, (LPBYTE)szExpansion, &cbData);
  341. RegCloseKey(hkMacros);
  342. }
  343. ConvertTCharToBytes(szExpansion, nCharSize, pszExpansion, nBytes);
  344. }
  345. // Replace the first character of pszDst with the string pszIns.
  346. //
  347. HRESULT StringCchReplaceFirstCharWithStringA(LPSTR psz, size_t cch, LPCSTR pszIns)
  348. {
  349. HRESULT hr;
  350. size_t cchIns = lstrlenA(pszIns);
  351. if (cchIns < cch )
  352. {
  353. MoveMemory(psz + cchIns, psz + 1, cch - cchIns);
  354. *(psz + cch - 1) = '\0';
  355. MoveMemory(psz, pszIns, cchIns);
  356. hr = S_OK;
  357. }
  358. else
  359. {
  360. hr = HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER);
  361. }
  362. return hr;
  363. }
  364. HRESULT StringCchReplaceFirstCharWithStringW(LPWSTR psz, size_t cch, LPCWSTR pszIns)
  365. {
  366. HRESULT hr;
  367. size_t cchIns = lstrlenW(pszIns);
  368. if (cchIns < cch)
  369. {
  370. MoveMemory(psz + cchIns, psz + 1, (cch - cchIns) * sizeof(WCHAR));
  371. *(psz + cch - 1) = L'\0';
  372. MoveMemory(psz, pszIns, cchIns * sizeof(WCHAR));
  373. hr = S_OK;
  374. }
  375. else
  376. {
  377. hr = HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER);
  378. }
  379. return hr;
  380. }
  381. void CWebViewMimeFilter::_EncodeHtml(LPBYTE psz, size_t cb)
  382. {
  383. HRESULT hr;
  384. size_t length;
  385. if (SIZEOF(char) == _nCharSize)
  386. {
  387. while (*psz)
  388. {
  389. switch (*psz)
  390. {
  391. case '<':
  392. hr = StringCchReplaceFirstCharWithStringA((LPSTR)psz, cb, "&lt");
  393. length = 3;
  394. break;
  395. case '>':
  396. hr = StringCchReplaceFirstCharWithStringA((LPSTR)psz, cb, "&gt");
  397. length = 3;
  398. break;
  399. case '"':
  400. hr = StringCchReplaceFirstCharWithStringA((LPSTR)psz, cb, "&quot");
  401. length = 5;
  402. break;
  403. default:
  404. hr = S_OK;
  405. length = 1;
  406. break;
  407. }
  408. if (SUCCEEDED(hr))
  409. {
  410. psz += length;
  411. cb -= length;
  412. }
  413. else
  414. {
  415. *psz = '\0';
  416. }
  417. }
  418. }
  419. else
  420. {
  421. ASSERT(sizeof(WCHAR) == _nCharSize);
  422. WCHAR* pszW = (WCHAR*)psz;
  423. size_t cchW = cb / sizeof(WCHAR);
  424. while (*pszW)
  425. {
  426. switch (*pszW)
  427. {
  428. case L'<':
  429. hr = StringCchReplaceFirstCharWithStringW(pszW, cchW, L"&lt");
  430. length = 3;
  431. break;
  432. case L'>':
  433. hr = StringCchReplaceFirstCharWithStringW(pszW, cchW, L"&gt");
  434. length = 3;
  435. break;
  436. case L'"':
  437. hr = StringCchReplaceFirstCharWithStringW(pszW, cchW, L"&quot");
  438. length = 5;
  439. break;
  440. default:
  441. hr = S_OK;
  442. length = 1;
  443. break;
  444. }
  445. if (SUCCEEDED(hr))
  446. {
  447. pszW += length;
  448. cchW -= length;
  449. }
  450. else
  451. {
  452. *pszW = L'\0';
  453. }
  454. }
  455. }
  456. }
  457. int CWebViewMimeFilter::_Expand(LPBYTE pszVar, LPBYTE * ppszExp)
  458. {
  459. if (!_StrCmp(pszVar, "TEMPLATEDIR", L"TEMPLATEDIR"))
  460. {
  461. if (!_szTemplateDirPath[0])
  462. {
  463. GetMachineTemplateDir(_szTemplateDirPath, SIZEOF(_szTemplateDirPath), _nCharSize);
  464. _EncodeHtml(_szTemplateDirPath, SIZEOF(_szTemplateDirPath));
  465. }
  466. *ppszExp = _szTemplateDirPath;
  467. }
  468. else if (!_StrCmp(pszVar, "THISDIRPATH", L"THISDIRPATH"))
  469. {
  470. if (!_szThisDirPath[0])
  471. {
  472. _QueryForDVCMDID(DVCMDID_GETTHISDIRPATH, _szThisDirPath, SIZEOF(_szThisDirPath));
  473. _EncodeHtml(_szThisDirPath, SIZEOF(_szThisDirPath));
  474. }
  475. *ppszExp = _szThisDirPath;
  476. }
  477. else if (!_StrCmp(pszVar, "THISDIRNAME", L"THISDIRNAME"))
  478. {
  479. if (!_szThisDirName[0])
  480. {
  481. _QueryForDVCMDID(DVCMDID_GETTHISDIRNAME, _szThisDirName, SIZEOF(_szThisDirName));
  482. _EncodeHtml(_szThisDirName, SIZEOF(_szThisDirName));
  483. }
  484. *ppszExp = _szThisDirName;
  485. }
  486. else
  487. {
  488. ExpandMacro(pszVar, _szExpansion, SIZEOF(_szExpansion), _nCharSize);
  489. _EncodeHtml(_szExpansion, SIZEOF(_szExpansion));
  490. *ppszExp = _szExpansion;
  491. }
  492. return _StrLen(*ppszExp);
  493. }
  494. //
  495. // Ensure room for at least cbIncrement more bytes at the end of the buffer.
  496. // If the memory gets moved or realloced, *pp1 and *pp2 are adjusted to
  497. // point to the corresponding bytes at their new location(s).
  498. //
  499. HRESULT CWebViewMimeFilter::_IncreaseBuffer(ULONG cbIncrement, LPBYTE * pp1, LPBYTE * pp2)
  500. {
  501. HRESULT hr = S_OK;
  502. // first check if there's room at the beginning of the buffer
  503. if (_cbSeek >= cbIncrement)
  504. {
  505. MoveMemory(_pBuf, _pBuf + _cbSeek, _cbBuf - _cbSeek);
  506. _cbBuf -= _cbSeek;
  507. if (pp1)
  508. *pp1 = *pp1 - _cbSeek;
  509. if (pp2)
  510. *pp2 = *pp2 - _cbSeek;
  511. _cbSeek = 0;
  512. }
  513. else
  514. {
  515. // not enough room, so allocate more memory
  516. LPBYTE p = (LPBYTE)LocalReAlloc(_pBuf, _cbBufSize + cbIncrement, LMEM_MOVEABLE);
  517. if (!p)
  518. {
  519. hr = E_OUTOFMEMORY;
  520. }
  521. else
  522. {
  523. if (pp1)
  524. *pp1 = p + (int)(*pp1 - _pBuf);
  525. if (pp2)
  526. *pp2 = p + (int)(*pp2 - _pBuf);
  527. _pBuf = p;
  528. _cbBufSize += cbIncrement;
  529. }
  530. }
  531. return hr;
  532. }
  533. HRESULT CWebViewMimeFilter::_ReadAndExpandBuffer()
  534. {
  535. HRESULT hr;
  536. _cbBuf = 0;
  537. _cbSeek = 0;
  538. if (!_pBuf)
  539. {
  540. _pBuf = (LPBYTE)LocalAlloc(LPTR, BUFFER_ALLOC_SIZE);
  541. if (!_pBuf)
  542. return E_OUTOFMEMORY;
  543. _cbBufSize = BUFFER_ALLOC_SIZE;
  544. }
  545. // As strings expand, our buffer grows. If we keep reading in the
  546. // max amount, we'll keep reallocating the more variable expansions
  547. // we do. By only reading in BUFFER_SIZE, our _pBuf will grow only
  548. // a few times and then all the variable expansions should fit
  549. // in the extra room generated. NOTE: for debug builds, always
  550. // read the most we can, so we reallocate more often.
  551. #ifdef DEBUG
  552. #define BUFFER_READ_SIZE (_cbBufSize)
  553. #else
  554. #define BUFFER_READ_SIZE BUFFER_SIZE
  555. #endif
  556. hr = _pProt->Read(_pBuf, BUFFER_READ_SIZE-SIZEOF(WCHAR), &_cbBuf); // make sure we have room for NULL
  557. if (SUCCEEDED(hr) && _cbBuf > 0)
  558. {
  559. LPBYTE pchSeek = _pBuf;
  560. LPBYTE pchEnd;
  561. if (!_nCharSize)
  562. {
  563. // scan buffer and figure out if it's unicode or ansi
  564. //
  565. // since we'll always be looking at html and the html header
  566. // is standard ansi chars, every other byte will be null if
  567. // we have a unicode buffer. i'm sure 3 checks are enough,
  568. // so we'll require 8 characters...
  569. if (_cbBuf > 6 &&
  570. 0 == _pBuf[1] &&
  571. 0 == _pBuf[3] &&
  572. 0 == _pBuf[5])
  573. {
  574. TraceMsg(TF_EXPAND, "WebView MIME filter - buffer is UNICODE");
  575. _nCharSize = SIZEOF(WCHAR);
  576. }
  577. else
  578. {
  579. TraceMsg(TF_EXPAND, "WebView MIME filter - buffer is ANSI");
  580. _nCharSize = SIZEOF(char);
  581. }
  582. }
  583. // The string had better be null-terminated, for not only are we
  584. // going to do a StrChr, but our loop control relies on it!
  585. // The buffer might have leftover goo from a previous go-round, so
  586. // ensure that the nulls are there.
  587. _pBuf[_cbBuf] = _pBuf[_cbBuf+1] = 0;
  588. #ifdef DEBUG
  589. if (SIZEOF(char)==_nCharSize)
  590. TraceMsg(TF_EXPAND, "Read A[%hs]", _pBuf);
  591. else
  592. TraceMsg(TF_EXPAND, "Read W[%ls]", _pBuf);
  593. #endif
  594. do {
  595. LPBYTE pchStart = pchSeek;
  596. // Assert that the string is still properly null-terminated
  597. // because we're going to be doing StrChr soon.
  598. ASSERT(_pBuf[_cbBuf] == 0);
  599. ASSERT(_pBuf[_cbBuf+1] == 0);
  600. pchSeek = _StrChr(pchSeek, '%', L'%');
  601. if (!pchSeek)
  602. break;
  603. pchEnd = _StrChr(pchSeek+_nCharSize, '%', L'%');
  604. if (!pchEnd)
  605. {
  606. // no terminator. if there's plenty of space to the end of
  607. // this buffer then there can't be a clipped variable
  608. // name to expand.
  609. if (_cbBuf - (pchSeek - _pBuf) > MAX_VARIABLE_NAME_SIZE*_nCharSize)
  610. break;
  611. // there may be a real variable here we need to expand,
  612. // so increase our buffer size and read some more data.
  613. //
  614. // we may get re-allocated, so update pchStart!
  615. hr = _IncreaseBuffer(BUFFER_SIZE_INC, &pchStart, NULL);
  616. if (FAILED(hr))
  617. break;
  618. pchSeek = pchStart;
  619. // read in more info -- this will be enough to complete
  620. // any partial variable name expansions
  621. DWORD dwTmp;
  622. ASSERT(_cbBufSize - _cbBuf - SIZEOF(WCHAR) > 0);
  623. hr = _pProt->Read(_pBuf + _cbBuf, _cbBufSize-_cbBuf-SIZEOF(WCHAR), &dwTmp);
  624. if (FAILED(hr) || dwTmp == 0)
  625. break;
  626. _cbBuf += dwTmp;
  627. // Ensure proper null termination
  628. _pBuf[_cbBuf] = _pBuf[_cbBuf+1] = 0;
  629. continue;
  630. }
  631. // figure out what to expand to
  632. LPBYTE pszExp;
  633. BYTE b[2];
  634. b[0] = pchEnd[0];
  635. b[1] = pchEnd[1];
  636. pchEnd[0] = 0;
  637. pchEnd[1] = 0;
  638. int cbExp = _Expand(pchSeek + _nCharSize, &pszExp);
  639. pchEnd[0] = b[0];
  640. pchEnd[1] = b[1];
  641. if (!cbExp)
  642. {
  643. // if it's not a recognized variable, use the bytes as they are
  644. pchSeek = pchEnd;
  645. continue;
  646. }
  647. // cbVar = number of bytes being replaced (sizeof("%VARNAME%"))
  648. // pchSeek points to the starting percent sign and pchEnd to
  649. // the trailing percent sign, so we need to add one more
  650. // _nCharSize to include the trailing percent sign itself.
  651. int cbVar = (int)(pchEnd - pchSeek) + _nCharSize;
  652. if (_cbBuf - cbVar + cbExp > _cbBufSize - SIZEOF(WCHAR))
  653. {
  654. hr = _IncreaseBuffer((_cbBuf - cbVar + cbExp) - (_cbBufSize - SIZEOF(WCHAR)), &pchSeek, &pchEnd);
  655. if (FAILED(hr))
  656. break;
  657. }
  658. // move the bytes around!
  659. // cbSeek = the number of bytes before the first percent sign
  660. int cbSeek = (int)(pchSeek - _pBuf);
  661. ASSERT(_cbBuf - cbVar + cbExp <= _cbBufSize - SIZEOF(WCHAR));
  662. // Move the stuff after the %VARNAME% to its final home
  663. // Don't forget to move the artificial trailing NULLs too!
  664. MoveMemory(pchSeek + cbExp, pchEnd + _nCharSize, _cbBuf - cbSeek - cbVar + SIZEOF(WCHAR));
  665. // Insert the expansion
  666. MoveMemory(pchSeek, pszExp, cbExp);
  667. // on to the rest of the buffer...
  668. pchSeek = pchEnd + _nCharSize;
  669. _cbBuf = _cbBuf - cbVar + cbExp;
  670. } while (*pchSeek);
  671. #ifdef DEBUG
  672. if (SIZEOF(char)==_nCharSize)
  673. TraceMsg(TF_EXPAND, "---> A[%s]", _pBuf);
  674. else
  675. TraceMsg(TF_EXPAND, "---> W[%hs]", _pBuf);
  676. #endif
  677. }
  678. else
  679. {
  680. // we're at end of stream
  681. hr = S_FALSE;
  682. }
  683. return hr;
  684. }
  685. HRESULT CWebViewMimeFilter::Read(void *pv,ULONG cb,ULONG *pcbRead)
  686. {
  687. HRESULT hr = S_OK;
  688. if (!_pProt)
  689. {
  690. hr = E_FAIL;
  691. }
  692. else
  693. {
  694. *pcbRead = 0;
  695. while (cb)
  696. {
  697. // if our buffer is empty, fill it
  698. if (_cbSeek == _cbBuf)
  699. {
  700. hr = _ReadAndExpandBuffer();
  701. }
  702. // do we have any data to copy?
  703. int cbLeft = _cbBuf - _cbSeek;
  704. if (SUCCEEDED(hr) && cbLeft > 0)
  705. {
  706. ULONG cbCopy = min(cb, (ULONG)cbLeft);
  707. memcpy(pv, &_pBuf[_cbSeek], cbCopy);
  708. pv = (LPVOID)(((LPBYTE)pv) + cbCopy);
  709. cb -= cbCopy;
  710. *pcbRead += cbCopy;
  711. _cbSeek += cbCopy;
  712. // do not return S_FALSE if some bytes were left unread
  713. if (cbCopy < (ULONG)cbLeft)
  714. hr = S_OK;
  715. }
  716. else
  717. {
  718. ASSERT(FAILED(hr) || hr == S_FALSE);
  719. // nothing left to copy
  720. break;
  721. }
  722. }
  723. }
  724. return hr;
  725. }
  726. HRESULT CWebViewMimeFilter::Seek(
  727. LARGE_INTEGER dlibMove,
  728. DWORD dwOrigin,
  729. ULARGE_INTEGER *plibNewPosition)
  730. {
  731. return E_NOTIMPL;
  732. }
  733. HRESULT CWebViewMimeFilter::LockRequest(DWORD dwOptions)
  734. {
  735. return S_OK;
  736. }
  737. HRESULT CWebViewMimeFilter::UnlockRequest()
  738. {
  739. return S_OK;
  740. }
  741. // IInternetProtocolSink methods
  742. HRESULT CWebViewMimeFilter::Switch(PROTOCOLDATA * pProtocolData)
  743. {
  744. if (_pProtSink)
  745. return _pProtSink->Switch(pProtocolData);
  746. return E_FAIL;
  747. }
  748. HRESULT CWebViewMimeFilter::ReportProgress(ULONG ulStatusCode, LPCWSTR pwszStatusText)
  749. {
  750. if (_pProtSink)
  751. return _pProtSink->ReportProgress(ulStatusCode, pwszStatusText);
  752. return E_FAIL;
  753. }
  754. HRESULT CWebViewMimeFilter::ReportData(DWORD grfBSCF, ULONG ulProgress, ULONG ulProgressMax)
  755. {
  756. if (_pProtSink)
  757. return _pProtSink->ReportData(grfBSCF, ulProgress, ulProgressMax);
  758. return E_FAIL;
  759. }
  760. HRESULT CWebViewMimeFilter::ReportResult(HRESULT hrResult, DWORD dwError, LPCWSTR pwszResult)
  761. {
  762. if (_pProtSink)
  763. return _pProtSink->ReportResult(hrResult, dwError, pwszResult);
  764. return E_FAIL;
  765. }
  766. //IServiceProvider methods
  767. HRESULT CWebViewMimeFilter::QueryService(REFGUID rsid, REFIID riid, void ** ppvObj)
  768. {
  769. return IUnknown_QueryService(_pProtSink, rsid, riid, ppvObj);
  770. }