trifilter.cpp
Upload User: caisha3
Upload Date: 2013-09-21
Package Size: 208739k
Code Size: 28k
Category:

Windows Develop

Development Platform:

Visual C++

  1. // Copyright (c)1997-1999 Microsoft Corporation, All Rights Reserved
  2. #include "stdafx.h"
  3. #include "DHTMLEd.h"
  4. #include "DHTMLEdit.h"
  5. #include "site.h"
  6. #include "proxyframe.h"
  7. #define AGENT_SIGNATURE (TEXT("Mozilla/4.0 (compatible; MSIE 5.01; DHTML Editing Control)"))
  8. // Check to see if a buffer starts with a byte order Unicode character.
  9. // This implementation is processor byte-order independant.
  10. //
  11. static BOOL StartsWithByteOrderMark ( LPVOID pvData )
  12. {
  13. CHAR *pchData = (CHAR*)pvData;
  14. #pragma warning(disable: 4310) // cast truncates constant value
  15. if ( ( (char)0xff == pchData[0] ) && ( (char)0xfe == pchData[1] ) )
  16. #pragma warning(default: 4310) // cast truncates constant value
  17. {
  18. return TRUE;
  19. }
  20. return FALSE;
  21. }
  22. // Given a pointer to a buffer assumed to hold at least two bytes,
  23. // write a Unicode byte order mark to it.
  24. // This implementation is processor byte-order independant.
  25. //
  26. static void InsertByteOrderMark ( LPVOID pvData )
  27. {
  28. CHAR *pchData = (CHAR*)pvData;
  29. #pragma warning(disable: 4310) // cast truncates constant value
  30. pchData[0] = (CHAR)0xff;
  31. pchData[1] = (CHAR)0xfe;
  32. #pragma warning(default: 4310) // cast truncates constant value
  33. }
  34. HRESULT
  35. CSite::HrFileToStream(LPCTSTR fileName, LPSTREAM* ppiStream)
  36. {
  37. HRESULT hr = S_OK;
  38. HANDLE hFile = NULL;
  39. HGLOBAL hMem = NULL;
  40. DWORD cbData = 0;
  41. LPVOID pbData = NULL;
  42. BOOL memLocked = FALSE;
  43. DWORD bytesRead = 0;
  44. BOOL bResult = FALSE;
  45. BOOL  bfUnicode = FALSE;
  46. hFile = CreateFile(
  47. fileName,
  48. GENERIC_READ,
  49. FILE_SHARE_READ,
  50. NULL,
  51. OPEN_EXISTING,
  52. 0,
  53. NULL);
  54. if(INVALID_HANDLE_VALUE == hFile)
  55. {
  56. DWORD ec = ::GetLastError();
  57. if ( ERROR_BAD_NETPATH == ec ) ec = ERROR_PATH_NOT_FOUND;
  58. hr = HRESULT_FROM_WIN32(ec);
  59. return hr;
  60. }
  61. cbData = GetFileSize(hFile, NULL);
  62. if (0xFFFFFFFF == cbData)
  63. {
  64. hr = HRESULT_FROM_WIN32(::GetLastError());
  65. goto cleanup;
  66. }
  67. // If the file is empty, create a zero length stream, but the global block must be non-zero in size.
  68. // VID98BUG 23121
  69. hMem = GlobalAlloc(GMEM_MOVEABLE|GMEM_ZEROINIT, ( 0 == cbData ) ? 2 : cbData );
  70. #if _DEBUG
  71. size = GlobalSize(hMem);
  72. #endif
  73. if (NULL == hMem)
  74. {
  75. _ASSERTE(hMem);
  76. hr = E_OUTOFMEMORY;
  77. goto cleanup;
  78. }
  79. pbData = GlobalLock(hMem);
  80. _ASSERTE(pbData);
  81. if (NULL == pbData)
  82. {
  83. hr = E_OUTOFMEMORY;
  84. goto cleanup;
  85. }
  86. bResult = ReadFile(hFile, pbData, cbData, &bytesRead, NULL) ; 
  87. _ASSERTE(bResult);
  88. if (FALSE == bResult)
  89. {
  90. hr = HRESULT_FROM_WIN32(::GetLastError());
  91. goto cleanup;
  92. }
  93. _ASSERTE(bytesRead == cbData);
  94. BfFlipBytesIfBigEndianUnicode ( (CHAR*)pbData, bytesRead );
  95. if ( IsUnicode ( pbData, (int)cbData ) )
  96. {
  97. bfUnicode = TRUE;
  98. }
  99. else
  100. {
  101. bfUnicode = FALSE;
  102. }
  103. cleanup:
  104. ::CloseHandle((HANDLE) hFile);
  105. if (hr != E_OUTOFMEMORY)
  106. memLocked = GlobalUnlock(hMem);
  107. _ASSERTE(FALSE == memLocked);
  108. if (SUCCEEDED(hr))
  109. {
  110. if (SUCCEEDED(hr = CreateStreamOnHGlobal(hMem, TRUE, ppiStream)))
  111. {
  112. ULARGE_INTEGER ui = {0};
  113. _ASSERTE(ppiStream);
  114. ui.LowPart = cbData;
  115. ui.HighPart = 0x00;
  116. hr = (*ppiStream)->SetSize(ui);
  117. _ASSERTE(SUCCEEDED(hr));
  118. }
  119. if ( SUCCEEDED ( hr ) )
  120. {
  121. SetSaveAsUnicode ( bfUnicode );
  122. if ( !bfUnicode )
  123. {
  124. hr = HrConvertStreamToUnicode ( *ppiStream );
  125. _ASSERTE(SUCCEEDED(hr));
  126. }
  127. }
  128. }
  129. else // if failed
  130. {
  131. hMem = GlobalFree(hMem);
  132. _ASSERTE(NULL == hMem);
  133. }
  134. return hr;
  135. }
  136. // Determine which method of URL fetch to use.  We have one for https, and another for other protocols.
  137. //
  138. HRESULT
  139. CSite::HrURLToStream(LPCTSTR szURL, LPSTREAM* ppiStream)
  140. {
  141. HRESULT hr = S_OK;
  142. URL_COMPONENTS urlc;
  143. _ASSERTE ( szURL );
  144. _ASSERTE ( ppiStream );
  145. memset ( &urlc, 0, sizeof ( urlc ) );
  146. urlc.dwStructSize = sizeof ( urlc );
  147. hr = InternetCrackUrl ( szURL, 0, 0, &urlc );
  148. if ( SUCCEEDED ( hr ) )
  149. {
  150. if ( INTERNET_SCHEME_HTTPS == urlc.nScheme )
  151. {
  152. hr = HrSecureURLToStream ( szURL, ppiStream );
  153. }
  154. else
  155. {
  156. hr = HrNonSecureURLToStream ( szURL, ppiStream );
  157. }
  158. }
  159. return hr;
  160. }
  161. // This version utilizes WinINet, which does not create cache files so is usable with https.
  162. // However, pluggable protocols cannot be stacked on the WinINet fucntions.
  163. //
  164. #define BUFFLEN 4096
  165. HRESULT
  166. CSite::HrSecureURLToStream(LPCTSTR szURL, LPSTREAM* ppiStream)
  167. {
  168. HRESULT hr = S_OK;
  169. _ASSERTE ( szURL );
  170. _ASSERTE ( ppiStream );
  171. *ppiStream = NULL;
  172. // Create a new read/write stream:
  173. hr = CreateStreamOnHGlobal ( NULL, TRUE, ppiStream );
  174. if ( SUCCEEDED ( hr ) && *ppiStream )
  175. {
  176. CHAR *pBuff = NULL;
  177. DWORD dwRead = 0;
  178. ULONG ulStreamLen = 0;
  179. ULONG ulStreamWrite = 0;
  180. ULARGE_INTEGER ui = {0};
  181. BOOL bfUnicode = FALSE;
  182. pBuff = new CHAR[BUFFLEN];
  183. if ( NULL == pBuff )
  184. {
  185. hr = E_OUTOFMEMORY;
  186. }
  187. else
  188. {
  189. HINTERNET hSession = InternetOpen ( AGENT_SIGNATURE, INTERNET_OPEN_TYPE_PRECONFIG, NULL, NULL, 0 );
  190. if ( NULL == hSession )
  191. {
  192. // InternetOpen failed
  193. hr = HRESULT_FROM_WIN32 ( GetLastError () );
  194. _ASSERTE ( FAILED ( hr ) ); // Make sure error returned wasn't NO_ERR
  195. }
  196. else
  197. {
  198. // Do not allow redirects in the SFS control.
  199. DWORD dwFlags = m_pFR->GetControl()->IsSafeForScripting () ? INTERNET_FLAG_NO_AUTO_REDIRECT : 0;
  200. HINTERNET hFile = InternetOpenUrl ( hSession, szURL, NULL, 0, dwFlags, 0 );
  201. if ( NULL == hFile )
  202. {
  203. // InternetOpenURL failed
  204. hr = HRESULT_FROM_WIN32 ( GetLastError () );
  205. _ASSERTE ( FAILED ( hr ) ); // Make sure error returned wasn't NO_ERR
  206. }
  207. else
  208. {
  209. // Read in data and write it to the stream to return.
  210. while ( InternetReadFile ( hFile, pBuff, BUFFLEN, &dwRead ) )
  211. {
  212. if ( 0 == dwRead )
  213. {
  214. break;
  215. }
  216. hr = (*ppiStream)->Write ( pBuff, dwRead, &ulStreamWrite );
  217. _ASSERTE ( dwRead == ulStreamWrite );
  218. if ( SUCCEEDED ( hr ) )
  219. {
  220. ulStreamLen += ulStreamWrite;
  221. }
  222. else
  223. {
  224. // Failed to read the data.  Make sure the error is not overwritten.
  225. goto READFILE_BAILOUT;
  226. }
  227. }
  228. ui.LowPart = ulStreamLen;
  229. ui.HighPart = 0x00;
  230. hr = (*ppiStream)->SetSize(ui);
  231. hr = HrConvertStreamToUnicode ( *ppiStream );
  232. bfUnicode = ( S_FALSE == hr );
  233. if ( SUCCEEDED ( hr ) )
  234. {
  235. hr = S_OK; // the S_FALSE result wouldn't make much sense to caller of this function.
  236. }
  237. SetSaveAsUnicode ( bfUnicode );
  238. READFILE_BAILOUT:
  239. InternetCloseHandle ( hFile );
  240. }
  241. InternetCloseHandle ( hSession );
  242. }
  243. delete [] pBuff;
  244. }
  245. }
  246. // If an error is being returned, cleat the stream here.
  247. if ( FAILED ( hr ) && ( NULL != *ppiStream ) )
  248. {
  249. (*ppiStream)->Release();
  250. *ppiStream = NULL;
  251. }
  252. return hr;
  253. }
  254. //  This version utilizes URLMon, which makes stacking pluggable protocols possible.
  255. // However, it cannot be used with https because it creates a cache file.
  256. //
  257. HRESULT
  258. CSite::HrNonSecureURLToStream(LPCTSTR szURL, LPSTREAM* ppiStream)
  259. {
  260. HRESULT hr = S_OK;
  261. IStream* piStreamOrig = NULL;
  262. *ppiStream = NULL;
  263. // Use the degenerate IBindStatusCallback implemented on the proxyframe exclusively
  264. // to provide IAuthenticate.
  265. IBindStatusCallback* piBSCB = NULL;
  266. m_pFR->QueryInterface ( IID_IBindStatusCallback, (void**)&piBSCB );
  267. m_pFR->ClearSFSRedirect ();
  268. #ifdef LATE_BIND_URLMON_WININET
  269. PFNURLOpenBlockingStream pfnURLOpenBlockingStream = m_pFR->m_pfnURLOpenBlockingStream;
  270. _ASSERTE ( pfnURLOpenBlockingStream );
  271. hr = (*pfnURLOpenBlockingStream)( NULL, szURL, &piStreamOrig, 0, piBSCB );
  272. #else
  273. hr = URLOpenBlockingStream ( NULL, szURL, &piStreamOrig, 0, piBSCB );
  274. #endif // LATE_BIND_URLMON_WININET
  275. if ( NULL != piBSCB )
  276. {
  277. piBSCB->Release ();
  278. piBSCB = NULL;
  279. }
  280. // If SFSRedirect got set, this is the SFS control and a redirect was detected.  Abort for security!
  281. if ( m_pFR->GetSFSRedirect () )
  282. {
  283. if ( NULL != piStreamOrig )
  284. {
  285. piStreamOrig->Release ();
  286. piStreamOrig = NULL;
  287. }
  288. hr = DE_E_ACCESS_DENIED;
  289. }
  290. if ( SUCCEEDED ( hr ) )
  291. {
  292. ULONG cbStreamSize = 0;
  293. HGLOBAL hGlob = NULL;
  294. STATSTG stat;
  295. // TriEdit will call GetHGlobalFromStream on the stream, which will fail.
  296. // We need to recopy it into this process.
  297. if ((hr = piStreamOrig->Stat(&stat, STATFLAG_NONAME)) == S_OK)
  298. {
  299. cbStreamSize = stat.cbSize.LowPart;
  300. // If the file is empty, create a zero length stream, but the global block must be non-zero in size.
  301. hGlob = GlobalAlloc ( GHND, ( 0 == cbStreamSize ) ? 2 : cbStreamSize );
  302. if ( NULL == hGlob )
  303. {
  304. DWORD ec = ::GetLastError();
  305. hr = HRESULT_FROM_WIN32(ec);
  306. }
  307. else
  308. {
  309. void* pBuff = GlobalLock ( hGlob );
  310. if ( NULL == pBuff )
  311. {
  312. DWORD ec = ::GetLastError();
  313. hr = HRESULT_FROM_WIN32(ec);
  314. }
  315. else
  316. {
  317. ULONG cbBytesRead = 0;
  318. hr = piStreamOrig->Read ( pBuff, cbStreamSize, &cbBytesRead );
  319. _ASSERTE ( SUCCEEDED ( hr ) );
  320. _ASSERTE ( cbBytesRead == cbStreamSize );
  321. if ( SUCCEEDED ( hr ) )
  322. {
  323. // We now have a global to creat a NEW stream from, locally.
  324. hr = CreateStreamOnHGlobal ( hGlob, TRUE, ppiStream );
  325. if ( SUCCEEDED ( hr ) )
  326. {
  327. // Convert it to Unicode if necessary.  Set SaveAsUnicode so it can be saved properly.
  328. hr = HrConvertStreamToUnicode ( *ppiStream );
  329. BOOL bfUnicode = ( S_FALSE == hr );
  330. if ( SUCCEEDED ( hr ) )
  331. {
  332. hr = S_OK; // the S_FALSE result wouldn't make much sense to caller of this function.
  333. }
  334. SetSaveAsUnicode ( bfUnicode );
  335. }
  336. }
  337. }
  338. GlobalUnlock ( hGlob );
  339. }
  340. if ( FAILED ( hr ) )
  341. {
  342. GlobalFree ( hGlob );
  343. }
  344. piStreamOrig->Release();
  345. }
  346. }
  347. return hr;
  348. }
  349. // Post V1.0 change:
  350. // The stream will now always be Unicode.
  351. // We should save the file as Unicode only if it was loaded as Unicode from File or URL,
  352. // otherwise convert to MBCS string.
  353. //
  354. HRESULT
  355. CSite::HrStreamToFile(LPSTREAM pStream, LPCTSTR fileName)
  356. {
  357. HRESULT hr = S_OK;
  358. HANDLE hFile = NULL;
  359. HGLOBAL hMem = NULL;
  360. WCHAR *pwcData = NULL;
  361. DWORD bytesWritten = 0;
  362. BOOL bResult = FALSE;
  363. STATSTG statStg = {0};
  364.             
  365. hFile = CreateFile(fileName,
  366. GENERIC_WRITE,
  367. FILE_SHARE_WRITE, 
  368. NULL,
  369. CREATE_ALWAYS,
  370. FILE_ATTRIBUTE_NORMAL,
  371. NULL);
  372.     if (INVALID_HANDLE_VALUE == hFile)
  373. {
  374. DWORD ec = ::GetLastError();
  375. if ( ERROR_BAD_NETPATH == ec ) ec = ERROR_PATH_NOT_FOUND;
  376. hr = HRESULT_FROM_WIN32(ec);
  377. return hr;
  378.     }
  379. if (FAILED(hr = pStream->Stat(&statStg, STATFLAG_NONAME)))
  380. {
  381. _ASSERTE(SUCCEEDED(hr));
  382. return hr;
  383. }
  384. if (FAILED(hr = GetHGlobalFromStream(pStream, &hMem)))
  385. {
  386. _ASSERTE(SUCCEEDED(hr));
  387. return hr;
  388. }
  389. pwcData = (WCHAR*)GlobalLock(hMem);
  390. if (NULL == pwcData)
  391. {
  392. hr = HRESULT_FROM_WIN32(::GetLastError());
  393. _ASSERTE(pwcData);
  394. return hr;
  395. }
  396. _ASSERTE ( IsUnicode ( pwcData, statStg.cbSize.LowPart ) );
  397. // Should it be converted to MBCS?
  398. if ( GetSaveAsUnicode () )
  399. {
  400. bResult = WriteFile(hFile, pwcData, statStg.cbSize.LowPart, &bytesWritten, NULL);
  401. _ASSERTE(bytesWritten == statStg.cbSize.LowPart);
  402. }
  403. else
  404. {
  405. UINT cbOrigSize = statStg.cbSize.LowPart / sizeof ( WCHAR );
  406. UINT cbNewSize = 0;
  407. char *pchTemp = NULL;
  408. // Substract one for the byte order mark if it begins the stream.  (It should.)
  409. if ( StartsWithByteOrderMark ( pwcData ) )
  410. {
  411. pwcData++; // Skip the byte order mark WCHAR
  412. cbOrigSize--;
  413. }
  414. if ( NULL != m_piMLang )
  415. {
  416. DWORD dwMode = 0;
  417. hr = m_piMLang->ConvertStringFromUnicode ( &dwMode, GetCurrentCodePage (), pwcData, &cbOrigSize, NULL, &cbNewSize );
  418. if ( S_FALSE == hr )
  419. {
  420. // This indicates that a conversion was not available.  Happens for default CP_ACP if test is typed into new page!
  421. hr = S_OK;
  422. goto fallback;
  423. }
  424. _ASSERTE ( 0 != cbNewSize );
  425. if ( SUCCEEDED ( hr ) )
  426. {
  427. pchTemp = new char [cbNewSize];
  428. _ASSERTE ( pchTemp );
  429. if ( NULL != pchTemp )
  430. {
  431. hr = m_piMLang->ConvertStringFromUnicode ( &dwMode, GetCurrentCodePage (), pwcData, &cbOrigSize, pchTemp, &cbNewSize );
  432. bResult = WriteFile(hFile, pchTemp, cbNewSize, &bytesWritten, NULL);
  433. _ASSERTE(bytesWritten == cbNewSize);
  434. delete [] pchTemp;
  435. }
  436. }
  437. }
  438. else
  439. {
  440. fallback:
  441. cbNewSize = ::WideCharToMultiByte ( GetCurrentCodePage (), 0, pwcData, cbOrigSize, NULL, 0, NULL, NULL );
  442. _ASSERTE ( 0 != cbNewSize );
  443. pchTemp = new char [cbNewSize];
  444. _ASSERTE ( pchTemp );
  445. if ( NULL != pchTemp )
  446. {
  447. ::WideCharToMultiByte ( GetCurrentCodePage (), 0, pwcData, cbOrigSize, pchTemp, cbNewSize, NULL, NULL );
  448. bResult = WriteFile(hFile, pchTemp, cbNewSize, &bytesWritten, NULL);
  449. _ASSERTE(bytesWritten == cbNewSize);
  450. delete [] pchTemp;
  451. }
  452. }
  453. }
  454. if (FALSE == bResult)
  455. {
  456. hr = HRESULT_FROM_WIN32(::GetLastError());
  457. goto cleanup;
  458. }
  459. cleanup:
  460. ::CloseHandle(hFile);
  461. // Reference count of hMem not checked here
  462. // since we can't assume how many times the
  463. // Stream has locked it
  464. GlobalUnlock(hMem); 
  465. return hr;
  466. }
  467. // Post V1.0 change:
  468. // The stream is always Unicode now.
  469. //
  470. HRESULT
  471. CSite::HrBstrToStream(BSTR bstrSrc, LPSTREAM* ppStream)
  472. {
  473. HRESULT hr = S_OK;
  474. HGLOBAL hMem = NULL;
  475. ULONG cbMBStr = 0;
  476. ULONG cbBuff = 0;
  477. LPVOID pStrDest = NULL;
  478. LPVOID pCopyPos = NULL;
  479. ULARGE_INTEGER ui = {0};
  480. _ASSERTE(bstrSrc);
  481. _ASSERTE(ppStream);
  482. cbMBStr = SysStringLen ( bstrSrc ) * sizeof (OLECHAR);
  483. cbBuff  = cbMBStr;
  484. // If the Unicode string does not contain a byte order mark at the beginning, it is
  485. // misinterpreted by Trident.  When DocumentHTML was set with Japanese text, the
  486. // BSTR was fed in without the byte order mark and was misinterpreted. (Possibly as UTF-8?)
  487. // Now, the byte-order mark is prepended to all non-empty strings.
  488. if ( 2 <= cbMBStr )
  489. {
  490. if ( !StartsWithByteOrderMark ( bstrSrc ) )
  491. {
  492. cbBuff += 2; // Reserve space for the byte order mark we'll add.
  493. }
  494. }
  495. // If the file is empty, create a zero length stream, but the global block must be non-zero in size.
  496. hMem = GlobalAlloc ( GMEM_MOVEABLE|GMEM_ZEROINIT, ( 0 == cbBuff ) ? 2 : cbBuff );
  497. _ASSERTE(hMem);
  498. if (NULL == hMem)
  499. {
  500. hr = E_OUTOFMEMORY;
  501. goto cleanup;
  502. }
  503. pStrDest = GlobalLock(hMem);
  504. _ASSERTE(pStrDest);
  505. if (NULL == pStrDest)
  506. {
  507. hr = HRESULT_FROM_WIN32(::GetLastError());
  508. GlobalFree(hMem);
  509. goto cleanup;
  510. }
  511. // Insert the byte order mark if it is not already there
  512. pCopyPos = pStrDest;
  513. if ( cbMBStr != cbBuff )
  514. {
  515. InsertByteOrderMark ( pStrDest );
  516. pCopyPos = &((char*)pCopyPos)[2]; // Advance copy target two bytes.
  517. }
  518. memcpy ( pCopyPos, bstrSrc, cbMBStr );
  519. GlobalUnlock(hMem);
  520. if (FAILED(hr = CreateStreamOnHGlobal(hMem, TRUE, ppStream)))
  521. {
  522. _ASSERTE(SUCCEEDED(hr));
  523. goto cleanup;
  524. }
  525. _ASSERTE(ppStream);
  526. ui.LowPart = cbBuff;
  527. ui.HighPart = 0x00;
  528. hr = (*ppStream)->SetSize(ui);
  529. _ASSERTE((*ppStream));
  530. cleanup:
  531. return hr;
  532. }
  533. // Post V1.0 change:
  534. // The stream is expected to be in Unicode now.
  535. // Just copy the contents to a BSTR.
  536. // Exception: the stream can begin with FFFE (or theoretically FEFF, but then I think we'd be broken.)
  537. // If the byte order mark begins the stream, don't copy it to the BSTR UNLESS bfRetainByteOrderMark
  538. // is set.  This should be retained in the case where we're loading an interal BSTR to be returned
  539. // to the pluggable protocol.  If the byte order mark is missing in that case, IE5 does not properly
  540. // convert the string.
  541. //
  542. HRESULT
  543. CSite::HrStreamToBstr(LPSTREAM pStream, BSTR* pBstr, BOOL bfRetainByteOrderMark)
  544. {
  545. HRESULT hr = S_OK;
  546. HGLOBAL hMem = NULL;
  547. WCHAR *pwcData = NULL;
  548. STATSTG statStg = {0};
  549. _ASSERTE(pStream);
  550. _ASSERTE(pBstr);
  551. *pBstr = NULL;
  552. if (FAILED(hr = GetHGlobalFromStream(pStream, &hMem)))
  553. {
  554. _ASSERTE(SUCCEEDED(hr));
  555. return hr;
  556. }
  557. hr = pStream->Stat(&statStg, STATFLAG_NONAME);
  558. _ASSERTE(SUCCEEDED(hr));
  559. pwcData = (WCHAR*)GlobalLock(hMem);
  560. _ASSERTE(pwcData);
  561. if (NULL == pwcData)
  562. {
  563. hr = HRESULT_FROM_WIN32(::GetLastError());
  564. return hr;
  565. }
  566. _ASSERTE ( IsUnicode ( pwcData, statStg.cbSize.LowPart ) );
  567. if ( !bfRetainByteOrderMark && StartsWithByteOrderMark ( pwcData ) )
  568. {
  569. pwcData++; // Skip the first WCHAR
  570. statStg.cbSize.LowPart -= sizeof(WCHAR); // This is a byte count rather than a WCHAR count.
  571. }
  572. *pBstr = SysAllocStringLen ( pwcData, statStg.cbSize.LowPart / sizeof(WCHAR) );
  573. GlobalUnlock(hMem); 
  574. return hr;
  575. }
  576. #ifdef _DEBUG_HELPER
  577. static void ExamineStream ( IStream* piStream, char* pchNameOfStream )
  578. {
  579. HGLOBAL hMem = NULL;
  580. LPVOID pvData = NULL;
  581. HRESULT hr = S_OK;
  582. _ASSERTE ( pchNameOfStream );
  583. hr = GetHGlobalFromStream(piStream, &hMem);
  584. pvData = GlobalLock ( hMem );
  585. // Examine *(char*)pvData
  586. GlobalUnlock ( hMem );
  587. }
  588. #endif
  589. HRESULT
  590. CSite::HrFilter(BOOL bDirection, LPSTREAM pSrcStream, LPSTREAM* ppFilteredStream, DWORD dwFilterFlags)
  591. {
  592. _ASSERTE(m_pObj);
  593. _ASSERTE(pSrcStream);
  594. _ASSERTE(ppFilteredStream);
  595. HRESULT hr = S_OK;
  596. STATSTG statStg = {0};
  597. // Test for the exceptional case of an empty stream.  Opening an empyt file can cause this.
  598. hr = pSrcStream->Stat(&statStg, STATFLAG_NONAME);
  599. _ASSERTE(SUCCEEDED(hr));
  600. if ( 0 == statStg.cbSize.HighPart && 0 == statStg.cbSize.LowPart )
  601. {
  602. *ppFilteredStream = pSrcStream;
  603. pSrcStream->AddRef ();
  604. return S_OK;
  605. }
  606. CComQIPtr<ITriEditDocument, &IID_ITriEditDocument> piTriEditDoc(m_pObj);
  607. CComQIPtr<IStream, &IID_IStream> piFilteredStream;
  608. DWORD dwTriEditFlags = 0;
  609. #ifdef _DEBUG_HELPER
  610. ExamineStream ( pSrcStream, "pSrcStream" );
  611. #endif
  612. if (dwFilterFlags == filterNone)
  613. {
  614. pSrcStream->AddRef();
  615. *ppFilteredStream = pSrcStream;
  616. return hr;
  617. }
  618. // dwTriEditFlags |= dwFilterMultiByteStream; // loading an ANSI Stream NOT ANY MORE.  The stream is ALWAYS Unicode now.
  619. if (dwFilterFlags & filterDTCs)
  620. dwTriEditFlags |= dwFilterDTCs;
  621. if (dwFilterFlags & filterASP)
  622. dwTriEditFlags |= dwFilterServerSideScripts;
  623. if (dwFilterFlags & preserveSourceCode)
  624. dwTriEditFlags |= dwPreserveSourceCode;
  625. if (dwFilterFlags & filterSourceCode)
  626. dwTriEditFlags |= filterSourceCode;
  627. if (!piTriEditDoc)
  628. return E_NOINTERFACE;
  629. CComBSTR bstrBaseURL;
  630. m_pFR->GetBaseURL ( bstrBaseURL );
  631. if (TRUE == bDirection)
  632. {
  633. if (FAILED(hr = piTriEditDoc->FilterIn(pSrcStream, (LPUNKNOWN*) &piFilteredStream, dwTriEditFlags, bstrBaseURL)))
  634. {
  635. goto cleanup;
  636. }
  637. }
  638. else
  639. {
  640. if (FAILED(hr = piTriEditDoc->FilterOut(pSrcStream, (LPUNKNOWN*) &piFilteredStream, dwTriEditFlags, bstrBaseURL)))
  641. {
  642. _ASSERTE(SUCCEEDED(hr));
  643. goto cleanup;
  644. }
  645. }
  646. *ppFilteredStream = piFilteredStream;
  647. #ifdef _DEBUG_HELPER
  648. ExamineStream ( *ppFilteredStream, "*ppFilteredStream" );
  649. #endif
  650. _ASSERTE((*ppFilteredStream));
  651. if (!(*ppFilteredStream))
  652. {
  653. hr = E_NOINTERFACE;
  654. goto cleanup;
  655. }
  656. (*ppFilteredStream)->AddRef();
  657. cleanup:
  658. return hr;
  659. }
  660. // Attempts to open the file specified by the UNC path
  661. // This method is a crude way of seeing if a given file
  662. // is available and current permissions allow for opening
  663. // Returns:
  664. // S_OK is file is available and it can be opened for reading
  665. // else
  666. // HRESULT containing Win32 facility and error code from ::GetLastError()
  667. HRESULT
  668. CSite::HrTestFileOpen(BSTR path)
  669. {
  670. USES_CONVERSION;
  671. HRESULT hr = S_OK;
  672. LPTSTR pFileName = NULL;
  673. HANDLE hFile = NULL;
  674. pFileName = OLE2T(path);
  675. _ASSERTE(pFileName);
  676. hFile = CreateFile(
  677. pFileName,
  678. GENERIC_READ,
  679. FILE_SHARE_READ,
  680. NULL,
  681. OPEN_EXISTING,
  682. 0,
  683. NULL);
  684. if(INVALID_HANDLE_VALUE == hFile)
  685. {
  686. DWORD ec = ::GetLastError();
  687. if ( ERROR_BAD_NETPATH == ec ) ec = ERROR_PATH_NOT_FOUND;
  688. hr = HRESULT_FROM_WIN32(ec);
  689. }
  690. ::CloseHandle(hFile);
  691. return hr;
  692. }
  693. //******************************************************************************************
  694. //
  695. // Unicode Utilities
  696. //
  697. // Post V1.0, we changed the internal data format from (unchecked, assumed) MBCS to Unicode.
  698. // The Stream and associated Trident is always Unicode.
  699. //
  700. //******************************************************************************************
  701. // This can be called without knowing if the stream is already Unicode or not.
  702. // Convert stream in place.  Assume the stream is created with CreateStreamOnHGlobal.
  703. // Convert without using ATL macros.  They give out at about 200KB.
  704. // If the stream was already Unicode, return S_FALSE.
  705. //
  706. HRESULT CSite::HrConvertStreamToUnicode ( IStream* piStream )
  707. {
  708. HRESULT hr = S_OK;
  709. HGLOBAL hMem = NULL;
  710. LPVOID pbData = NULL;
  711. STATSTG statStg = {0};
  712. UINT cwcNewStr = 0;
  713. WCHAR *pwcUnicode = NULL;
  714. _ASSERTE(piStream);
  715. // The stream MUST be created on a global
  716. if (FAILED(hr = GetHGlobalFromStream(piStream, &hMem)))
  717. {
  718. _ASSERTE(SUCCEEDED(hr));
  719. return hr;
  720. }
  721. hr = piStream->Stat(&statStg, STATFLAG_NONAME);
  722. _ASSERTE(SUCCEEDED(hr));
  723. if ( 0 == statStg.cbSize.HighPart && 4 > statStg.cbSize.LowPart )
  724. {
  725. return S_FALSE; // If it's not even four bytes long, leave as is.
  726. }
  727. pbData = GlobalLock(hMem);
  728. _ASSERTE(pbData);
  729. if (NULL == pbData)
  730. {
  731. hr = HRESULT_FROM_WIN32(::GetLastError());
  732. return hr;
  733. }
  734. // If the stream was already Unicode, do nothing!
  735. if ( IsUnicode ( pbData, statStg.cbSize.LowPart ) )
  736. {
  737. hr = S_FALSE;
  738. goto exit;
  739. }
  740. // If IMultilanguage2 is available, try to determine its code page.
  741. if ( NULL != m_piMLang )
  742. {
  743. DetectEncodingInfo rdei[8];
  744. int nScores = 8;
  745. DWORD dwMode = 0;
  746. UINT uiInSize = statStg.cbSize.LowPart;
  747. HRESULT hrCharset = E_FAIL;
  748. // Check to see if there's an embedded META charset tag.
  749. // Only if the appropriate TriEdit is installed will this work.
  750. // We need access to MLang to make sense out of the result, too.
  751. _ASSERTE ( m_pObj );
  752. CComQIPtr<ITriEditExtendedAccess, &IID_ITriEditExtendedAccess> pItex ( m_pObj );
  753. if ( pItex )
  754. {
  755. CComBSTR bstrCodePage;
  756. hrCharset = pItex->GetCharsetFromStream ( piStream, &bstrCodePage );
  757. // If "Unicode" is returned, it's got to be bogus.
  758. // We would have mangled Unicode in the initial translation.
  759. // This turns out to be a not-so-rare special case.  Outlook produced such files.
  760. if ( S_OK == hrCharset )
  761. {
  762. MIMECSETINFO mcsi;
  763. if ( 0 == _wcsicmp ( L"unicode", bstrCodePage ) )
  764. {
  765. hrCharset = S_FALSE;
  766. }
  767. else
  768. {
  769. hrCharset = m_piMLang->GetCharsetInfo ( bstrCodePage, &mcsi );
  770. if ( SUCCEEDED ( hrCharset ) )
  771. {
  772. m_cpCodePage = mcsi.uiInternetEncoding;
  773. }
  774. }
  775. }
  776. }
  777. // If we found the charset via GetCharsetFromStream, don't use MLang.
  778. if ( S_OK != hrCharset )
  779. {
  780. hr = m_piMLang->DetectCodepageInIStream ( MLDETECTCP_HTML, 0, piStream, rdei, &nScores );
  781. if ( FAILED ( hr ) )
  782. {
  783. goto fallback; // Use default ANSI code page
  784. }
  785. m_cpCodePage = rdei[0].nCodePage;
  786. }
  787. hr = m_piMLang->ConvertStringToUnicode ( &dwMode, m_cpCodePage, (char*)pbData, &uiInSize, NULL, &cwcNewStr );
  788. _ASSERTE ( SUCCEEDED ( hr ) );
  789. if ( S_OK != hr ) // S_FALSE for conversion not supported (no such language pack), E_FAIL for internal error.
  790. {
  791. goto fallback; // Use default ANSI code page
  792. }
  793. // Create the buffer to convert to.
  794. pwcUnicode = new WCHAR[cwcNewStr+1]; // One extra character for the byte order mark.
  795. _ASSERTE ( pwcUnicode );
  796. if ( NULL == pwcUnicode )
  797. {
  798. hr = E_OUTOFMEMORY;
  799. goto exit;
  800. }
  801. InsertByteOrderMark ( pwcUnicode );
  802. hr = m_piMLang->ConvertStringToUnicode ( &dwMode, m_cpCodePage, (char*)pbData, &uiInSize, &pwcUnicode[1], &cwcNewStr );
  803. _ASSERTE ( SUCCEEDED ( hr ) );
  804. if ( S_OK != hr ) // S_FALSE for conversion not supported (no such language pack), E_FAIL for internal error.
  805. {
  806. delete [] pwcUnicode; // This will be reallocated.
  807. pwcUnicode = NULL;
  808. goto fallback; // Use default ANSI code page
  809. }
  810. }
  811. else
  812. {
  813. fallback: // If we attempt to use MLang but fail, we must STILL convert to Unicode...
  814. // Set code page to default:
  815. m_cpCodePage = CP_ACP;
  816. // Count how many wide characters are required:
  817. cwcNewStr = ::MultiByteToWideChar(GetCurrentCodePage (), 0, (char*)pbData, statStg.cbSize.LowPart, NULL, 0);
  818. _ASSERTE ( 0 != cwcNewStr );
  819. if ( 0 == cwcNewStr )
  820. {
  821. #ifdef _DEBUG
  822. DWORD dwError = GetLastError ();
  823. _ASSERTE ( 0 == dwError );
  824. #endif
  825. goto exit;
  826. }
  827. // Create the buffer to convert to.
  828. pwcUnicode = new WCHAR[cwcNewStr+1]; // One extra character for the byte order mark.
  829. _ASSERTE ( pwcUnicode );
  830. if ( NULL == pwcUnicode )
  831. {
  832. hr = E_OUTOFMEMORY;
  833. goto exit;
  834. }
  835. InsertByteOrderMark ( pwcUnicode );
  836. // Create the wide string.  Write starting at position [1], preserving the byte order character.
  837. cwcNewStr = ::MultiByteToWideChar(GetCurrentCodePage (), 0, (char*)pbData, statStg.cbSize.LowPart, &pwcUnicode[1], cwcNewStr);
  838. if ( 0 == cwcNewStr )
  839. {
  840. #ifdef _DEBUG
  841. DWORD dwError = GetLastError ();
  842. _ASSERTE ( 0 == dwError );
  843. #endif
  844. goto exit1;
  845. }
  846. }
  847. // We've successfully read the data in, now replace the stream.  pwcUnicode contains the data.
  848. ULARGE_INTEGER ui;
  849. ui.LowPart = (cwcNewStr+1) * 2; // + 1 for the byte order mark at the beginning.
  850. ui.HighPart = 0x00;
  851. hr = piStream->SetSize ( ui );
  852. _ASSERTE ( SUCCEEDED ( hr ) );
  853. if ( SUCCEEDED ( hr ) )
  854. {
  855. GlobalUnlock(hMem);
  856. pbData = GlobalLock(hMem);
  857. memcpy ( pbData, pwcUnicode, (cwcNewStr+1) * 2 ); // Copy string + byte order mark
  858. // Reposition the mark to the beginning of the stream
  859. LARGE_INTEGER liIn = {0};
  860. ULARGE_INTEGER uliOut = {0};
  861. piStream->Seek ( liIn, STREAM_SEEK_SET, &uliOut );
  862. }
  863. exit1:
  864. delete [] pwcUnicode;
  865. exit:
  866. GlobalUnlock(hMem);
  867. return hr;
  868. }
  869. // Test the buffer to see if it contains a Unicode string.  It's assumed to if:
  870. // It starts with the byte order marker FFFE or
  871. // It contains NULL bytes before the last four bytes.
  872. // If it's less than or equal to four bytes, do not consider it Unicode.
  873. //
  874. BOOL CSite::IsUnicode ( void* pData, int cbSize )
  875. {
  876. BOOL bfUnicode = FALSE;
  877. CHAR *pchData = (CHAR*)pData;
  878. if ( 4 < cbSize )
  879. {
  880. #pragma warning(disable: 4310) // cast truncates constant value
  881. if ( ( (char)0xff == pchData[0] ) && ( (char)0xfe == pchData[1] ) )
  882. bfUnicode = TRUE;
  883. if ( ( (char)0xfe == pchData[0] ) && ( (char)0xff == pchData[1] ) )
  884. #pragma warning(default: 4310) // cast truncates constant value
  885. {
  886. // Reverse order Unicode?  Will this be encountered?
  887. _ASSERTE ( ! ( (char)0xfe == pchData[0] ) && ( (char)0xff == pchData[1] ) );
  888. bfUnicode = FALSE;
  889. }
  890. if ( ! bfUnicode )
  891. {
  892. bfUnicode = FALSE;
  893. for ( int i = 0; i < cbSize - 4; i++ )
  894. {
  895. if ( 0 == pchData[i] )
  896. {
  897. bfUnicode = TRUE;
  898. break;
  899. }
  900. }
  901. }
  902. }
  903. return bfUnicode;
  904. }
  905. // Given a buffer of characters, detect whether its a BigEndian Unicode stream by the first word (FEFF).
  906. // If not, return FALSE.
  907. // If so, flip all words to LittleEndian order (FFFE) and return true.
  908. // Note: this is a storage convention, not an encoding.  This may be encountered in disk files, not in downloads.
  909. // A Unicode stream should contain an even number of bytes!  If not, we'll assert, but continue.
  910. //
  911. BOOL CSite::BfFlipBytesIfBigEndianUnicode ( CHAR* pchData, int cbSize )
  912. {
  913. _ASSERTE ( pchData );
  914. // See if it's Unicode stored in reverse order.
  915. #pragma warning(disable: 4310) // cast truncates constant value
  916. if ( ( (CHAR)0xFE == pchData[0] ) && ( (CHAR)0xFF == pchData[1] ) )
  917. #pragma warning(default: 4310) // cast truncates constant value
  918. {
  919. // A Unicode stream must contain an even number of characters.
  920. _ASSERTE ( 0 != ( cbSize & 1 ) );
  921. // This stream is populated with reversed Unicode.  Flip it in place.
  922. // Subtract 1 from initial byte count to avoid overrunning odd length buffer.
  923. CHAR chTemp = '';
  924. for ( int iPos = 0; iPos < cbSize - 1; iPos += 2 )
  925. {
  926. chTemp = pchData[iPos];
  927. pchData[iPos] = pchData[iPos+1];
  928. pchData[iPos+1] = chTemp;
  929. }
  930. return TRUE;
  931. }
  932. return FALSE;
  933. }