Leaked source code of windows server 2003
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.

907 lines
26 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. LPSTR pstrDestOriginal = pstrDest;
  241. while (*pstrSrc && (cbDest > MAX_HTML_ESCAPE_SEQUENCE))
  242. {
  243. int iLen;
  244. ULONG ul = MAKELONG(*pstrSrc, 0);
  245. // We can optimize the common ansi characters to avoid generating the long escape sequence. This allows us to fit
  246. // longer paths in the buffer.
  247. if (ul < 128)
  248. {
  249. *pstrDest = (CHAR)*pstrSrc;
  250. iLen = 1;
  251. }
  252. else
  253. {
  254. HRESULT hr = StringCchPrintfA(pstrDest, cbDest, "&#%lu;", ul);
  255. if (FAILED(hr))
  256. {
  257. *pstrDestOriginal = '\0';
  258. return;
  259. }
  260. iLen = lstrlenA(pstrDest);
  261. }
  262. pstrDest += iLen;
  263. cbDest -= iLen;
  264. pstrSrc++;
  265. }
  266. *pstrDest = 0;
  267. }
  268. void CWebViewMimeFilter::_QueryForDVCMDID(int dvcmdid, LPBYTE pDst, int cbDst)
  269. {
  270. IOleCommandTarget * pct;
  271. if (SUCCEEDED(QueryService(SID_DefView, IID_IOleCommandTarget, (LPVOID*)&pct)))
  272. {
  273. VARIANT v = {0};
  274. if (S_OK == pct->Exec(&CGID_DefView, dvcmdid, 0, NULL, &v))
  275. {
  276. if (v.vt == VT_BSTR)
  277. {
  278. if (sizeof(char) == _nCharSize)
  279. {
  280. UnicodeToHTMLEscapeStringAnsi(v.bstrVal, (LPSTR)pDst, cbDst);
  281. }
  282. else
  283. {
  284. ASSERT(_nCharSize == sizeof(WCHAR));
  285. HRESULT hr = StringCbCopy((LPWSTR)pDst, cbDst, v.bstrVal);
  286. if (FAILED(hr))
  287. {
  288. *((LPWSTR)pDst) = L'\0';
  289. }
  290. }
  291. }
  292. VariantClear(&v);
  293. }
  294. pct->Release();
  295. }
  296. }
  297. void ConvertTCharToBytes(LPCTSTR psz, UINT nCharSize, LPBYTE pBuf, int nBytes)
  298. {
  299. if (sizeof(char) == nCharSize)
  300. {
  301. SHTCharToAnsi(psz, (LPSTR)pBuf, nBytes/nCharSize);
  302. }
  303. else
  304. {
  305. ASSERT(nCharSize == sizeof(WCHAR));
  306. SHTCharToUnicode(psz, (LPWSTR)pBuf, nBytes/nCharSize);
  307. }
  308. }
  309. void GetMachineTemplateDir(LPBYTE pszTemplateDirPath, int nBytes, UINT nCharSize)
  310. {
  311. TCHAR szTemplateDir[MAX_PATH];
  312. szTemplateDir[0] = TEXT('\0');
  313. SHGetWebFolderFilePath(TEXT(""), szTemplateDir, ARRAYSIZE(szTemplateDir));
  314. // Remove the trailing back slash, if any
  315. int len = lstrlen(szTemplateDir);
  316. if ((len > 0) && (szTemplateDir[len - 1] == TEXT('\\')))
  317. {
  318. szTemplateDir[len - 1] = TEXT('\0');
  319. }
  320. ConvertTCharToBytes(szTemplateDir, nCharSize, pszTemplateDirPath, nBytes);
  321. }
  322. #define REG_WEBVIEW_TEMPLATE_MACROS TEXT("Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\WebView\\TemplateMacros")
  323. void ConvertBytesToTChar(LPCBYTE pBuf, UINT nCharSize, LPTSTR psz, int cch)
  324. {
  325. if (sizeof(char) == nCharSize)
  326. {
  327. SHAnsiToTChar((LPCSTR)pBuf, psz, cch);
  328. }
  329. else
  330. {
  331. ASSERT(nCharSize == sizeof(WCHAR));
  332. SHUnicodeToTChar((LPCWSTR)pBuf, psz, cch);
  333. }
  334. }
  335. void ExpandMacro(LPBYTE pszMacro, LPBYTE pszExpansion, int nBytes, UINT nCharSize)
  336. {
  337. TCHAR szExpansion[MAX_PATH];
  338. szExpansion[0] = TEXT('\0');
  339. TCHAR szTCharMacro[MAX_PATH];
  340. ConvertBytesToTChar(pszMacro, nCharSize, szTCharMacro, ARRAYSIZE(szTCharMacro));
  341. TCHAR szKey[MAX_PATH];
  342. HRESULT hr = StringCchPrintf(szKey, ARRAYSIZE(szKey), TEXT("%s\\%s"), REG_WEBVIEW_TEMPLATE_MACROS, szTCharMacro);
  343. if (SUCCEEDED(hr))
  344. {
  345. HKEY hkMacros;
  346. if (RegOpenKeyEx(HKEY_CURRENT_USER, szKey, 0, KEY_QUERY_VALUE, &hkMacros) == ERROR_SUCCESS
  347. || RegOpenKeyEx(HKEY_LOCAL_MACHINE, szKey, 0, KEY_QUERY_VALUE, &hkMacros) == ERROR_SUCCESS)
  348. {
  349. DWORD dwType;
  350. DWORD cbData = sizeof(szExpansion);
  351. SHQueryValueEx(hkMacros, NULL, NULL, &dwType, (LPBYTE)szExpansion, &cbData);
  352. RegCloseKey(hkMacros);
  353. }
  354. }
  355. ConvertTCharToBytes(szExpansion, nCharSize, pszExpansion, nBytes);
  356. }
  357. // Replace the first character of pszDst with the string pszIns.
  358. //
  359. HRESULT StringCchReplaceFirstCharWithStringA(LPSTR psz, size_t cch, LPCSTR pszIns)
  360. {
  361. HRESULT hr;
  362. size_t cchIns = lstrlenA(pszIns);
  363. if (cchIns < cch )
  364. {
  365. MoveMemory(psz + cchIns, psz + 1, cch - cchIns);
  366. *(psz + cch - 1) = '\0';
  367. MoveMemory(psz, pszIns, cchIns);
  368. hr = S_OK;
  369. }
  370. else
  371. {
  372. hr = HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER);
  373. }
  374. return hr;
  375. }
  376. HRESULT StringCchReplaceFirstCharWithStringW(LPWSTR psz, size_t cch, LPCWSTR pszIns)
  377. {
  378. HRESULT hr;
  379. size_t cchIns = lstrlenW(pszIns);
  380. if (cchIns < cch)
  381. {
  382. MoveMemory(psz + cchIns, psz + 1, (cch - cchIns) * sizeof(WCHAR));
  383. *(psz + cch - 1) = L'\0';
  384. MoveMemory(psz, pszIns, cchIns * sizeof(WCHAR));
  385. hr = S_OK;
  386. }
  387. else
  388. {
  389. hr = HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER);
  390. }
  391. return hr;
  392. }
  393. void CWebViewMimeFilter::_EncodeHtml(LPBYTE psz, size_t cb)
  394. {
  395. HRESULT hr;
  396. size_t length;
  397. if (sizeof(char) == _nCharSize)
  398. {
  399. while (*psz)
  400. {
  401. switch (*psz)
  402. {
  403. case '<':
  404. hr = StringCchReplaceFirstCharWithStringA((LPSTR)psz, cb, "&lt");
  405. length = 3;
  406. break;
  407. case '>':
  408. hr = StringCchReplaceFirstCharWithStringA((LPSTR)psz, cb, "&gt");
  409. length = 3;
  410. break;
  411. case '"':
  412. hr = StringCchReplaceFirstCharWithStringA((LPSTR)psz, cb, "&quot");
  413. length = 5;
  414. break;
  415. default:
  416. hr = S_OK;
  417. length = 1;
  418. break;
  419. }
  420. if (SUCCEEDED(hr))
  421. {
  422. psz += length;
  423. cb -= length;
  424. }
  425. else
  426. {
  427. *psz = '\0';
  428. }
  429. }
  430. }
  431. else
  432. {
  433. ASSERT(sizeof(WCHAR) == _nCharSize);
  434. WCHAR* pszW = (WCHAR*)psz;
  435. size_t cchW = cb / sizeof(WCHAR);
  436. while (*pszW)
  437. {
  438. switch (*pszW)
  439. {
  440. case L'<':
  441. hr = StringCchReplaceFirstCharWithStringW(pszW, cchW, L"&lt");
  442. length = 3;
  443. break;
  444. case L'>':
  445. hr = StringCchReplaceFirstCharWithStringW(pszW, cchW, L"&gt");
  446. length = 3;
  447. break;
  448. case L'"':
  449. hr = StringCchReplaceFirstCharWithStringW(pszW, cchW, L"&quot");
  450. length = 5;
  451. break;
  452. default:
  453. hr = S_OK;
  454. length = 1;
  455. break;
  456. }
  457. if (SUCCEEDED(hr))
  458. {
  459. pszW += length;
  460. cchW -= length;
  461. }
  462. else
  463. {
  464. *pszW = L'\0';
  465. }
  466. }
  467. }
  468. }
  469. int CWebViewMimeFilter::_Expand(LPBYTE pszVar, LPBYTE * ppszExp)
  470. {
  471. if (!_StrCmp(pszVar, "TEMPLATEDIR", L"TEMPLATEDIR"))
  472. {
  473. if (!_szTemplateDirPath[0])
  474. {
  475. GetMachineTemplateDir(_szTemplateDirPath, sizeof(_szTemplateDirPath), _nCharSize);
  476. _EncodeHtml(_szTemplateDirPath, sizeof(_szTemplateDirPath));
  477. }
  478. *ppszExp = _szTemplateDirPath;
  479. }
  480. else if (!_StrCmp(pszVar, "THISDIRPATH", L"THISDIRPATH"))
  481. {
  482. if (!_szThisDirPath[0])
  483. {
  484. _QueryForDVCMDID(DVCMDID_GETTHISDIRPATH, _szThisDirPath, sizeof(_szThisDirPath));
  485. _EncodeHtml(_szThisDirPath, sizeof(_szThisDirPath));
  486. }
  487. *ppszExp = _szThisDirPath;
  488. }
  489. else if (!_StrCmp(pszVar, "THISDIRNAME", L"THISDIRNAME"))
  490. {
  491. if (!_szThisDirName[0])
  492. {
  493. _QueryForDVCMDID(DVCMDID_GETTHISDIRNAME, _szThisDirName, sizeof(_szThisDirName));
  494. _EncodeHtml(_szThisDirName, sizeof(_szThisDirName));
  495. }
  496. *ppszExp = _szThisDirName;
  497. }
  498. else
  499. {
  500. ExpandMacro(pszVar, _szExpansion, sizeof(_szExpansion), _nCharSize);
  501. _EncodeHtml(_szExpansion, sizeof(_szExpansion));
  502. *ppszExp = _szExpansion;
  503. }
  504. return _StrLen(*ppszExp);
  505. }
  506. //
  507. // Ensure room for at least cbIncrement more bytes at the end of the buffer.
  508. // If the memory gets moved or realloced, *pp1 and *pp2 are adjusted to
  509. // point to the corresponding bytes at their new location(s).
  510. //
  511. HRESULT CWebViewMimeFilter::_IncreaseBuffer(ULONG cbIncrement, LPBYTE * pp1, LPBYTE * pp2)
  512. {
  513. HRESULT hr = S_OK;
  514. // first check if there's room at the beginning of the buffer
  515. if (_cbSeek >= cbIncrement)
  516. {
  517. MoveMemory(_pBuf, _pBuf + _cbSeek, _cbBuf - _cbSeek);
  518. _cbBuf -= _cbSeek;
  519. if (pp1)
  520. *pp1 = *pp1 - _cbSeek;
  521. if (pp2)
  522. *pp2 = *pp2 - _cbSeek;
  523. _cbSeek = 0;
  524. }
  525. else
  526. {
  527. // not enough room, so allocate more memory
  528. LPBYTE p = (LPBYTE)LocalReAlloc(_pBuf, _cbBufSize + cbIncrement, LMEM_MOVEABLE);
  529. if (!p)
  530. {
  531. hr = E_OUTOFMEMORY;
  532. }
  533. else
  534. {
  535. if (pp1)
  536. *pp1 = p + (int)(*pp1 - _pBuf);
  537. if (pp2)
  538. *pp2 = p + (int)(*pp2 - _pBuf);
  539. _pBuf = p;
  540. _cbBufSize += cbIncrement;
  541. }
  542. }
  543. return hr;
  544. }
  545. HRESULT CWebViewMimeFilter::_ReadAndExpandBuffer()
  546. {
  547. HRESULT hr;
  548. _cbBuf = 0;
  549. _cbSeek = 0;
  550. if (!_pBuf)
  551. {
  552. _pBuf = (LPBYTE)LocalAlloc(LPTR, BUFFER_ALLOC_SIZE);
  553. if (!_pBuf)
  554. return E_OUTOFMEMORY;
  555. _cbBufSize = BUFFER_ALLOC_SIZE;
  556. }
  557. // As strings expand, our buffer grows. If we keep reading in the
  558. // max amount, we'll keep reallocating the more variable expansions
  559. // we do. By only reading in BUFFER_SIZE, our _pBuf will grow only
  560. // a few times and then all the variable expansions should fit
  561. // in the extra room generated. NOTE: for debug builds, always
  562. // read the most we can, so we reallocate more often.
  563. #ifdef DEBUG
  564. #define BUFFER_READ_SIZE (_cbBufSize)
  565. #else
  566. #define BUFFER_READ_SIZE BUFFER_SIZE
  567. #endif
  568. hr = _pProt->Read(_pBuf, BUFFER_READ_SIZE - sizeof(WCHAR), &_cbBuf); // make sure we have room for NULL
  569. if (SUCCEEDED(hr) && _cbBuf > 0)
  570. {
  571. LPBYTE pchSeek = _pBuf;
  572. LPBYTE pchEnd;
  573. if (!_nCharSize)
  574. {
  575. // scan buffer and figure out if it's unicode or ansi
  576. //
  577. // since we'll always be looking at html and the html header
  578. // is standard ansi chars, every other byte will be null if
  579. // we have a unicode buffer. i'm sure 3 checks are enough,
  580. // so we'll require 8 characters...
  581. if (_cbBuf > 6 &&
  582. 0 == _pBuf[1] &&
  583. 0 == _pBuf[3] &&
  584. 0 == _pBuf[5])
  585. {
  586. TraceMsg(TF_EXPAND, "WebView MIME filter - buffer is UNICODE");
  587. _nCharSize = sizeof(WCHAR);
  588. }
  589. else
  590. {
  591. TraceMsg(TF_EXPAND, "WebView MIME filter - buffer is ANSI");
  592. _nCharSize = sizeof(char);
  593. }
  594. }
  595. // The string had better be null-terminated, for not only are we
  596. // going to do a StrChr, but our loop control relies on it!
  597. // The buffer might have leftover goo from a previous go-round, so
  598. // ensure that the nulls are there.
  599. _pBuf[_cbBuf] = _pBuf[_cbBuf+1] = 0;
  600. #ifdef DEBUG
  601. if (sizeof(char)==_nCharSize)
  602. TraceMsg(TF_EXPAND, "Read A[%hs]", _pBuf);
  603. else
  604. TraceMsg(TF_EXPAND, "Read W[%ls]", _pBuf);
  605. #endif
  606. do {
  607. LPBYTE pchStart = pchSeek;
  608. // Assert that the string is still properly null-terminated
  609. // because we're going to be doing StrChr soon.
  610. ASSERT(_pBuf[_cbBuf] == 0);
  611. ASSERT(_pBuf[_cbBuf+1] == 0);
  612. pchSeek = _StrChr(pchSeek, '%', L'%');
  613. if (!pchSeek)
  614. break;
  615. pchEnd = _StrChr(pchSeek+_nCharSize, '%', L'%');
  616. if (!pchEnd)
  617. {
  618. // no terminator. if there's plenty of space to the end of
  619. // this buffer then there can't be a clipped variable
  620. // name to expand.
  621. if (_cbBuf - (pchSeek - _pBuf) > MAX_VARIABLE_NAME_SIZE*_nCharSize)
  622. break;
  623. // there may be a real variable here we need to expand,
  624. // so increase our buffer size and read some more data.
  625. //
  626. // we may get re-allocated, so update pchStart!
  627. hr = _IncreaseBuffer(BUFFER_SIZE_INC, &pchStart, NULL);
  628. if (FAILED(hr))
  629. break;
  630. pchSeek = pchStart;
  631. // read in more info -- this will be enough to complete
  632. // any partial variable name expansions
  633. DWORD dwTmp;
  634. ASSERT(_cbBufSize - _cbBuf - sizeof(WCHAR) > 0);
  635. hr = _pProt->Read(_pBuf + _cbBuf, _cbBufSize- _cbBuf - sizeof(WCHAR), &dwTmp);
  636. if (FAILED(hr) || dwTmp == 0)
  637. break;
  638. _cbBuf += dwTmp;
  639. // Ensure proper null termination
  640. _pBuf[_cbBuf] = _pBuf[_cbBuf+1] = 0;
  641. continue;
  642. }
  643. // figure out what to expand to
  644. LPBYTE pszExp;
  645. BYTE b[2];
  646. b[0] = pchEnd[0];
  647. b[1] = pchEnd[1];
  648. pchEnd[0] = 0;
  649. pchEnd[1] = 0;
  650. int cbExp = _Expand(pchSeek + _nCharSize, &pszExp);
  651. pchEnd[0] = b[0];
  652. pchEnd[1] = b[1];
  653. if (!cbExp)
  654. {
  655. // if it's not a recognized variable, use the bytes as they are
  656. pchSeek = pchEnd;
  657. continue;
  658. }
  659. // cbVar = number of bytes being replaced (sizeof("%VARNAME%"))
  660. // pchSeek points to the starting percent sign and pchEnd to
  661. // the trailing percent sign, so we need to add one more
  662. // _nCharSize to include the trailing percent sign itself.
  663. int cbVar = (int)(pchEnd - pchSeek) + _nCharSize;
  664. if (_cbBuf - cbVar + cbExp > _cbBufSize - sizeof(WCHAR))
  665. {
  666. hr = _IncreaseBuffer((_cbBuf - cbVar + cbExp) - (_cbBufSize - sizeof(WCHAR)), &pchSeek, &pchEnd);
  667. if (FAILED(hr))
  668. break;
  669. }
  670. // move the bytes around!
  671. // cbSeek = the number of bytes before the first percent sign
  672. int cbSeek = (int)(pchSeek - _pBuf);
  673. ASSERT(_cbBuf - cbVar + cbExp <= _cbBufSize - sizeof(WCHAR));
  674. // Move the stuff after the %VARNAME% to its final home
  675. // Don't forget to move the artificial trailing NULLs too!
  676. MoveMemory(pchSeek + cbExp, pchEnd + _nCharSize, _cbBuf - cbSeek - cbVar + sizeof(WCHAR));
  677. // Insert the expansion
  678. MoveMemory(pchSeek, pszExp, cbExp);
  679. // on to the rest of the buffer...
  680. pchSeek = pchEnd + _nCharSize;
  681. _cbBuf = _cbBuf - cbVar + cbExp;
  682. } while (*pchSeek);
  683. #ifdef DEBUG
  684. if (sizeof(char)==_nCharSize)
  685. TraceMsg(TF_EXPAND, "---> A[%s]", _pBuf);
  686. else
  687. TraceMsg(TF_EXPAND, "---> W[%hs]", _pBuf);
  688. #endif
  689. }
  690. else
  691. {
  692. // we're at end of stream
  693. hr = S_FALSE;
  694. }
  695. return hr;
  696. }
  697. HRESULT CWebViewMimeFilter::Read(void *pv,ULONG cb,ULONG *pcbRead)
  698. {
  699. HRESULT hr = S_OK;
  700. if (!_pProt)
  701. {
  702. hr = E_FAIL;
  703. }
  704. else
  705. {
  706. *pcbRead = 0;
  707. while (cb)
  708. {
  709. // if our buffer is empty, fill it
  710. if (_cbSeek == _cbBuf)
  711. {
  712. hr = _ReadAndExpandBuffer();
  713. }
  714. // do we have any data to copy?
  715. int cbLeft = _cbBuf - _cbSeek;
  716. if (SUCCEEDED(hr) && cbLeft > 0)
  717. {
  718. ULONG cbCopy = min(cb, (ULONG)cbLeft);
  719. memcpy(pv, &_pBuf[_cbSeek], cbCopy);
  720. pv = (LPVOID)(((LPBYTE)pv) + cbCopy);
  721. cb -= cbCopy;
  722. *pcbRead += cbCopy;
  723. _cbSeek += cbCopy;
  724. // do not return S_FALSE if some bytes were left unread
  725. if (cbCopy < (ULONG)cbLeft)
  726. hr = S_OK;
  727. }
  728. else
  729. {
  730. ASSERT(FAILED(hr) || hr == S_FALSE);
  731. // nothing left to copy
  732. break;
  733. }
  734. }
  735. }
  736. return hr;
  737. }
  738. HRESULT CWebViewMimeFilter::Seek(
  739. LARGE_INTEGER dlibMove,
  740. DWORD dwOrigin,
  741. ULARGE_INTEGER *plibNewPosition)
  742. {
  743. return E_NOTIMPL;
  744. }
  745. HRESULT CWebViewMimeFilter::LockRequest(DWORD dwOptions)
  746. {
  747. return S_OK;
  748. }
  749. HRESULT CWebViewMimeFilter::UnlockRequest()
  750. {
  751. return S_OK;
  752. }
  753. // IInternetProtocolSink methods
  754. HRESULT CWebViewMimeFilter::Switch(PROTOCOLDATA * pProtocolData)
  755. {
  756. if (_pProtSink)
  757. return _pProtSink->Switch(pProtocolData);
  758. return E_FAIL;
  759. }
  760. HRESULT CWebViewMimeFilter::ReportProgress(ULONG ulStatusCode, LPCWSTR pwszStatusText)
  761. {
  762. if (_pProtSink)
  763. return _pProtSink->ReportProgress(ulStatusCode, pwszStatusText);
  764. return E_FAIL;
  765. }
  766. HRESULT CWebViewMimeFilter::ReportData(DWORD grfBSCF, ULONG ulProgress, ULONG ulProgressMax)
  767. {
  768. if (_pProtSink)
  769. return _pProtSink->ReportData(grfBSCF, ulProgress, ulProgressMax);
  770. return E_FAIL;
  771. }
  772. HRESULT CWebViewMimeFilter::ReportResult(HRESULT hrResult, DWORD dwError, LPCWSTR pwszResult)
  773. {
  774. if (_pProtSink)
  775. return _pProtSink->ReportResult(hrResult, dwError, pwszResult);
  776. return E_FAIL;
  777. }
  778. //IServiceProvider methods
  779. HRESULT CWebViewMimeFilter::QueryService(REFGUID rsid, REFIID riid, void ** ppvObj)
  780. {
  781. return IUnknown_QueryService(_pProtSink, rsid, riid, ppvObj);
  782. }