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.

1150 lines
39 KiB

  1. // --------------------------------------------------------------------------------
  2. // Ibdystm.cpp
  3. // Copyright (c)1993-1995 Microsoft Corporation, All Rights Reserved
  4. // Steven J. Bailey
  5. // --------------------------------------------------------------------------------
  6. #include "pch.hxx"
  7. #include "ibdystm.h"
  8. #include "dllmain.h"
  9. #include "inetconv.h"
  10. #include "internat.h"
  11. #include "symcache.h"
  12. #include "bookbody.h"
  13. #include "strconst.h"
  14. #include "demand.h"
  15. // --------------------------------------------------------------------------------
  16. // Encoding Type Names
  17. // --------------------------------------------------------------------------------
  18. const ENCODINGMAP g_rgEncodingMap[IET_LAST] = {
  19. { IET_BINARY, STR_ENC_BINARY, TRUE },
  20. { IET_BASE64, STR_ENC_BASE64, TRUE },
  21. { IET_UUENCODE, STR_ENC_UUENCODE, TRUE },
  22. { IET_QP, STR_ENC_QP, TRUE },
  23. { IET_7BIT, STR_ENC_7BIT, TRUE },
  24. { IET_8BIT, STR_ENC_8BIT, TRUE },
  25. { IET_INETCSET, NULL, FALSE },
  26. { IET_UNICODE, NULL, FALSE },
  27. { IET_RFC1522, NULL, FALSE },
  28. { IET_ENCODED, NULL, FALSE },
  29. { IET_CURRENT, NULL, FALSE },
  30. { IET_UNKNOWN, NULL, FALSE },
  31. { IET_BINHEX40, STR_ENC_BINHEX40, TRUE }
  32. };
  33. // --------------------------------------------------------------------------------
  34. // Document Covnert Map
  35. // --------------------------------------------------------------------------------
  36. const CONVERSIONMAP g_rgConversionMap[IET_LAST] = {
  37. { DCT_NONE, DCT_ENCODE, DCT_ENCODE, DCT_ENCODE, DCT_ENCODE, DCT_ENCODE, DCT_NONE, DCT_NONE, DCT_NONE, DCT_NONE, DCT_NONE, DCT_NONE, DCT_ENCODE }, // IET_BINARY
  38. { DCT_DECODE, DCT_NONE, DCT_DECENC, DCT_DECENC, DCT_DECENC, DCT_DECENC, DCT_NONE, DCT_NONE, DCT_NONE, DCT_NONE, DCT_NONE, DCT_NONE, DCT_DECENC }, // IET_BASE64
  39. { DCT_DECODE, DCT_DECENC, DCT_NONE, DCT_DECENC, DCT_DECENC, DCT_DECENC, DCT_NONE, DCT_NONE, DCT_NONE, DCT_NONE, DCT_NONE, DCT_NONE, DCT_DECENC }, // IET_UUENCODE
  40. { DCT_DECODE, DCT_DECENC, DCT_DECENC, DCT_NONE, DCT_DECENC, DCT_DECENC, DCT_NONE, DCT_NONE, DCT_NONE, DCT_NONE, DCT_NONE, DCT_NONE, DCT_DECENC }, // IET_QP
  41. { DCT_DECODE, DCT_DECENC, DCT_DECENC, DCT_DECENC, DCT_NONE, DCT_NONE, DCT_NONE, DCT_NONE, DCT_NONE, DCT_NONE, DCT_NONE, DCT_NONE, DCT_DECENC }, // IET_7BIT
  42. { DCT_DECODE, DCT_DECENC, DCT_DECENC, DCT_DECENC, DCT_NONE, DCT_NONE, DCT_NONE, DCT_NONE, DCT_NONE, DCT_NONE, DCT_NONE, DCT_NONE, DCT_DECENC }, // IET_8BIT
  43. { DCT_NONE, DCT_NONE, DCT_NONE, DCT_NONE, DCT_NONE, DCT_NONE, DCT_NONE, DCT_NONE, DCT_NONE, DCT_NONE, DCT_NONE, DCT_NONE, DCT_NONE }, // IET_INETCSET
  44. { DCT_NONE, DCT_NONE, DCT_NONE, DCT_NONE, DCT_NONE, DCT_NONE, DCT_NONE, DCT_NONE, DCT_NONE, DCT_NONE, DCT_NONE, DCT_NONE, DCT_NONE }, // IET_UNICODE
  45. { DCT_NONE, DCT_NONE, DCT_NONE, DCT_NONE, DCT_NONE, DCT_NONE, DCT_NONE, DCT_NONE, DCT_NONE, DCT_NONE, DCT_NONE, DCT_NONE, DCT_NONE }, // IET_RFC1522
  46. { DCT_NONE, DCT_NONE, DCT_NONE, DCT_NONE, DCT_NONE, DCT_NONE, DCT_NONE, DCT_NONE, DCT_NONE, DCT_NONE, DCT_NONE, DCT_NONE, DCT_NONE }, // IET_ENCODED
  47. { DCT_NONE, DCT_NONE, DCT_NONE, DCT_NONE, DCT_NONE, DCT_NONE, DCT_NONE, DCT_NONE, DCT_NONE, DCT_NONE, DCT_NONE, DCT_NONE, DCT_NONE }, // IET_CURRENT
  48. { DCT_NONE, DCT_NONE, DCT_NONE, DCT_NONE, DCT_NONE, DCT_NONE, DCT_NONE, DCT_NONE, DCT_NONE, DCT_NONE, DCT_NONE, DCT_NONE, DCT_NONE }, // IET_UNKNOWN
  49. { DCT_DECODE, DCT_DECENC, DCT_DECENC, DCT_DECENC, DCT_DECENC, DCT_DECENC, DCT_NONE, DCT_NONE, DCT_NONE, DCT_NONE, DCT_NONE, DCT_NONE, DCT_NONE }, // IET_BINHEX40
  50. // BINARY BASE64 UUENCODE QP 7BIT 8BIT INETCSET UNICODE RFC1522 ENCODED CURRENT UNKNOWN BINHEX40
  51. };
  52. // --------------------------------------------------------------------------------
  53. // FIsValidBodyEncoding
  54. // --------------------------------------------------------------------------------
  55. BOOL FIsValidBodyEncoding(ENCODINGTYPE ietEncoding)
  56. {
  57. // Try to find the correct body encoding
  58. for (ULONG i=0; i<IET_LAST; i++)
  59. {
  60. // Is this it?
  61. if (ietEncoding == g_rgEncodingMap[i].ietEncoding)
  62. return g_rgEncodingMap[i].fValidBodyEncoding;
  63. }
  64. // Failure
  65. return FALSE;
  66. }
  67. // --------------------------------------------------------------------------------
  68. // CBodyStream::CBodyStream
  69. // --------------------------------------------------------------------------------
  70. CBodyStream::CBodyStream(void)
  71. {
  72. DllAddRef();
  73. m_cRef = 1;
  74. m_pszFileName = NULL;
  75. m_uliIntOffset.QuadPart = 0;
  76. m_uliIntSize.QuadPart = 0;
  77. m_liLastWrite.QuadPart = 0;
  78. m_pLockBytes = NULL;
  79. m_dctConvert = DCT_NONE;
  80. m_pEncoder = NULL;
  81. m_pDecoder = NULL;
  82. InitializeCriticalSection(&m_cs);
  83. }
  84. // --------------------------------------------------------------------------------
  85. // CBodyStream::~CBodyStream
  86. // --------------------------------------------------------------------------------
  87. CBodyStream::~CBodyStream(void)
  88. {
  89. SafeMemFree(m_pszFileName);
  90. SafeRelease(m_pLockBytes);
  91. SafeRelease(m_pEncoder);
  92. SafeRelease(m_pDecoder);
  93. DeleteCriticalSection(&m_cs);
  94. DllRelease();
  95. }
  96. // --------------------------------------------------------------------------------
  97. // CBodyStream::QueryInterface
  98. // --------------------------------------------------------------------------------
  99. STDMETHODIMP CBodyStream::QueryInterface(REFIID riid, LPVOID *ppv)
  100. {
  101. // check params
  102. if (ppv == NULL)
  103. return TrapError(E_INVALIDARG);
  104. // Init
  105. *ppv = NULL;
  106. // Find IID
  107. if (IID_IUnknown == riid)
  108. *ppv = (IUnknown *)this;
  109. else if (IID_IStream == riid)
  110. *ppv = (IStream *)this;
  111. else if (IID_CBodyStream == riid)
  112. *ppv = (CBodyStream *)this;
  113. else
  114. {
  115. *ppv = NULL;
  116. return TrapError(E_NOINTERFACE);
  117. }
  118. // AddRef It
  119. ((IUnknown *)*ppv)->AddRef();
  120. // Done
  121. return S_OK;
  122. }
  123. // --------------------------------------------------------------------------------
  124. // CBodyStream::AddRef
  125. // --------------------------------------------------------------------------------
  126. STDMETHODIMP_(ULONG) CBodyStream::AddRef(void)
  127. {
  128. return (ULONG)InterlockedIncrement(&m_cRef);
  129. }
  130. // --------------------------------------------------------------------------------
  131. // CBodyStream::Release
  132. // --------------------------------------------------------------------------------
  133. STDMETHODIMP_(ULONG) CBodyStream::Release(void)
  134. {
  135. LONG cRef = InterlockedDecrement(&m_cRef);
  136. if (0 == cRef)
  137. delete this;
  138. return (ULONG)cRef;
  139. }
  140. // --------------------------------------------------------------------------------
  141. // CBodyStream::GetEncodeWrapInfo
  142. // --------------------------------------------------------------------------------
  143. void CBodyStream::GetEncodeWrapInfo(LPCONVINITINFO pInitInfo, LPMESSAGEBODY pBody)
  144. {
  145. // Locals
  146. PROPVARIANT rOption;
  147. // Export 7bit or 8bit
  148. if (IET_7BIT != pInitInfo->ietEncoding && IET_8BIT != pInitInfo->ietEncoding)
  149. return;
  150. // OID_WRAP_BODY_TEXT
  151. if (FAILED(pBody->GetOption(OID_WRAP_BODY_TEXT, &rOption)) || FALSE == rOption.boolVal)
  152. return;
  153. // Get Wrapping Width
  154. if (FAILED(pBody->GetOption(OID_CBMAX_BODY_LINE, &rOption)))
  155. rOption.ulVal = DEF_CBMAX_BODY_LINE;
  156. // We are wrapping
  157. pInitInfo->dwFlags |= ICF_WRAPTEXT;
  158. // Max Line
  159. pInitInfo->cchMaxLine = rOption.ulVal;
  160. // Done
  161. return;
  162. }
  163. // --------------------------------------------------------------------------------
  164. // CBodyStream::GetCodePageInfo
  165. // --------------------------------------------------------------------------------
  166. void CBodyStream::GetCodePageInfo(LPCONVINITINFO pInitInfo, BOOL fDoCharset, CODEPAGEID cpiSource, CODEPAGEID cpiDest)
  167. {
  168. // Decide if we should do a code page conversion
  169. if (TRUE == fDoCharset && cpiSource != cpiDest)
  170. {
  171. // No Conversions between 28591 and 1252
  172. if ((1252 == cpiSource || 28591 == cpiSource) && (1252 == cpiDest || 28591 == cpiDest))
  173. {
  174. // Do a code page conversion
  175. FLAGCLEAR(pInitInfo->dwFlags, ICF_CODEPAGE);
  176. }
  177. // Can the conversion between the internal and external code pages be performed ?
  178. else if (g_pInternat->CanConvertCodePages(cpiSource, cpiDest) == S_OK)
  179. {
  180. // Do a code page conversion
  181. FLAGSET(pInitInfo->dwFlags, ICF_CODEPAGE);
  182. }
  183. // Otherwise...
  184. else
  185. {
  186. // Time to Whine
  187. DOUTL(4, "MLANG.DLL Can't Convert CodePage %d to CodePage %d\n", cpiSource, cpiDest);
  188. // If cpiSource is unicode and cpiDest is not unicode, we need to set cpiDest to a legal multibyte code page
  189. if (CP_UNICODE == cpiSource && CP_UNICODE != cpiDest)
  190. {
  191. // Default to system acp
  192. cpiDest = GetACP();
  193. // We better be able to do this conversion...
  194. Assert(g_pInternat->CanConvertCodePages(cpiSource, cpiDest) == S_OK);
  195. // Do the conversion...
  196. FLAGSET(pInitInfo->dwFlags, ICF_CODEPAGE);
  197. // Whine some more
  198. DOUTL(4, "Modified: CODEPAGE(%d -> %d, 0x%0X -> 0x%0X)\n", cpiSource, cpiDest, cpiSource, cpiDest);
  199. }
  200. // multibyte to unicode
  201. else if (CP_UNICODE != cpiSource && CP_UNICODE == cpiDest)
  202. {
  203. // Default to system acp
  204. cpiSource = GetACP();
  205. // We better be able to do this conversion...
  206. Assert(g_pInternat->CanConvertCodePages(cpiSource, cpiDest) == S_OK);
  207. // Do the conversion...
  208. FLAGSET(pInitInfo->dwFlags, ICF_CODEPAGE);
  209. // Whine some more
  210. DOUTL(4, "Modified: CODEPAGE(%d -> %d, 0x%0X -> 0x%0X)\n", cpiSource, cpiDest, cpiSource, cpiDest);
  211. }
  212. }
  213. }
  214. // Set Source Code Page
  215. pInitInfo->cpiSource = cpiSource;
  216. // Set Destination Code Page
  217. pInitInfo->cpiDest = cpiDest;
  218. // Done
  219. return;
  220. }
  221. // --------------------------------------------------------------------------------
  222. // CBodyStream::ComputeCodePageMapping
  223. // --------------------------------------------------------------------------------
  224. void CBodyStream::ComputeCodePageMapping(LPBODYSTREAMINIT pInitInfo)
  225. {
  226. // We should always have a charset...
  227. Assert(pInitInfo->pCharset && g_pInternat);
  228. // External is IET_UNICODE
  229. if (IET_UNICODE == pInitInfo->ietExternal)
  230. {
  231. pInitInfo->cpiExternal = CP_UNICODE;
  232. pInitInfo->ietExternal = IET_BINARY;
  233. }
  234. // External is in Windows CodePage
  235. else if (IET_BINARY == pInitInfo->ietExternal)
  236. {
  237. // RAID-32777: User does not want unicode, so make sure we return multibyte
  238. pInitInfo->cpiExternal = (CP_UNICODE == pInitInfo->pCharset->cpiWindows) ? GetACP() : pInitInfo->pCharset->cpiWindows;
  239. // Map outof autodetect
  240. if (CP_JAUTODETECT == pInitInfo->cpiExternal)
  241. pInitInfo->cpiExternal = 932;
  242. }
  243. // External is in Internet CodePage
  244. else
  245. {
  246. // RAID-25300 - FE-J:Athena: Newsgroup article and mail sent with charset=_autodetect
  247. pInitInfo->cpiExternal = (CP_JAUTODETECT == pInitInfo->pCharset->cpiInternet) ? 50220 : pInitInfo->pCharset->cpiInternet;
  248. // Better not be unicode - Removed because of Raid 40228
  249. /// Assert(CP_UNICODE != pInitInfo->cpiExternal);
  250. // Adjust ietExternal
  251. if (FALSE == FIsValidBodyEncoding((ENCODINGTYPE)pInitInfo->ietExternal))
  252. pInitInfo->ietExternal = IET_BINARY;
  253. }
  254. // Internal is IET_UNICODE
  255. if (IET_UNICODE == pInitInfo->ietInternal)
  256. {
  257. pInitInfo->cpiInternal = CP_UNICODE;
  258. pInitInfo->ietInternal = IET_BINARY;
  259. }
  260. // Internal is in Windows CodePage
  261. else if (IET_BINARY == pInitInfo->ietInternal)
  262. {
  263. // The internal data is not unicode so make sure we don't say its unicode
  264. pInitInfo->cpiInternal = (CP_UNICODE == pInitInfo->pCharset->cpiWindows) ? GetACP() : pInitInfo->pCharset->cpiWindows;
  265. }
  266. // Internal is in Internet CodePage
  267. else
  268. {
  269. // Internet CodePage
  270. pInitInfo->cpiInternal = pInitInfo->pCharset->cpiInternet;
  271. // Adjust ietExternal
  272. if (FALSE == FIsValidBodyEncoding((ENCODINGTYPE)pInitInfo->ietInternal))
  273. pInitInfo->ietInternal = IET_BINARY;
  274. }
  275. }
  276. // --------------------------------------------------------------------------------
  277. // CBodyStream::GenerateDefaultMacBinaryHeader
  278. // --------------------------------------------------------------------------------
  279. void CBodyStream::GenerateDefaultMacBinaryHeader(LPMACBINARY pMacBinary)
  280. {
  281. // ZeroInit
  282. ZeroMemory(pMacBinary, sizeof(MACBINARY));
  283. }
  284. // --------------------------------------------------------------------------------
  285. // CBodyStream::HrInitialize
  286. // --------------------------------------------------------------------------------
  287. HRESULT CBodyStream::HrInitialize(LPBODYSTREAMINIT pInitInfo, LPMESSAGEBODY pBody)
  288. {
  289. // Locals
  290. HRESULT hr=S_OK;
  291. STATSTG rStat;
  292. BOOL fDoCharset=FALSE;
  293. BOOL fIsText;
  294. CONVINITINFO rEncodeInit;
  295. CONVINITINFO rDecodeInit;
  296. PROPVARIANT rVariant;
  297. // Parameters
  298. Assert(pBody);
  299. // Thread Safety
  300. EnterCriticalSection(&m_cs);
  301. // Get Code Page Mappings
  302. ComputeCodePageMapping(pInitInfo);
  303. // Debug
  304. //DebugTrace("IBodyStream: ENCODING(%s -> %s) CODEPAGE(%d -> %d)\n", g_rgEncodingMap[pInitInfo->ietInternal].pszName,g_rgEncodingMap[pInitInfo->ietExternal].pszName, pInitInfo->cpiInternal, pInitInfo->cpiExternal);
  305. // Initialize Convert Init Structs
  306. ZeroMemory(&rEncodeInit, sizeof(CONVINITINFO));
  307. rEncodeInit.fEncoder = TRUE;
  308. ZeroMemory(&rDecodeInit, sizeof(CONVINITINFO));
  309. rDecodeInit.fEncoder = FALSE;
  310. // Get the class id of this stream
  311. rVariant.vt = VT_LPSTR;
  312. if (SUCCEEDED(pBody->GetProp(PIDTOSTR(PID_ATT_GENFNAME), 0, &rVariant)))
  313. m_pszFileName = rVariant.pszVal;
  314. // Lets test my IBodyStream::Stat function
  315. #ifdef DEBUG
  316. Stat(&rStat, STATFLAG_NONAME);
  317. #endif
  318. // Get LockBytes from the body
  319. hr = pBody->HrGetLockBytes(&m_pLockBytes);
  320. if (FAILED(hr) && MIME_E_NO_DATA != hr)
  321. {
  322. TrapError(hr);
  323. goto exit;
  324. }
  325. // Else, ok
  326. hr = S_OK;
  327. // Otherwise, query the size
  328. if (m_pLockBytes)
  329. {
  330. // Get the size of the lockbytes object...
  331. CHECKHR(hr = m_pLockBytes->Stat(&rStat, STATFLAG_NONAME));
  332. m_uliIntSize.QuadPart = rStat.cbSize.QuadPart;
  333. }
  334. // Special Case for IET_CURRENT
  335. if (IET_CURRENT == pInitInfo->ietExternal)
  336. {
  337. // No Conversion
  338. m_dctConvert = DCT_NONE;
  339. // Done
  340. goto exit;
  341. }
  342. // Otheriwse, lookup conversion type
  343. Assert(FIsValidBodyEncoding(pInitInfo->ietInternal) && FIsValidBodyEncoding(pInitInfo->ietExternal));
  344. m_dctConvert = (DOCCONVTYPE)(g_rgConversionMap[pInitInfo->ietInternal].rgDestType[pInitInfo->ietExternal]);
  345. // If we have data...
  346. if (m_uliIntSize.QuadPart > 0)
  347. {
  348. // Is Text
  349. fIsText = (pBody->IsContentType(STR_CNT_TEXT, NULL) == S_OK) ? TRUE : FALSE;
  350. // Get the character set for this body...
  351. if (fIsText)
  352. {
  353. // Raid-6832: Mail : We fail to display Plain Text messages when they have a name parameter in the Content Type header
  354. // If multibyte to unicode or unicode to multibyte, then we must do a charset translation
  355. if ((CP_UNICODE == pInitInfo->cpiInternal && CP_UNICODE != pInitInfo->cpiExternal) ||
  356. (CP_UNICODE != pInitInfo->cpiInternal && CP_UNICODE == pInitInfo->cpiExternal))
  357. fDoCharset = TRUE;
  358. // If Tagged with a Character Set, then always apply charset dencode/encode
  359. else if (pBody->IsType(IBT_CSETTAGGED) == S_OK)
  360. fDoCharset = TRUE;
  361. // Otherwise, if its not an attachment, then always apply charset dencode/encode
  362. else if (pBody->IsType(IBT_AUTOATTACH) == S_OK || pBody->IsType(IBT_ATTACHMENT) == S_FALSE)
  363. fDoCharset = TRUE;
  364. }
  365. // If currently no conversion, see if we are translating between code pages
  366. if (fDoCharset && DCT_NONE == m_dctConvert && pInitInfo->cpiInternal != pInitInfo->cpiExternal)
  367. m_dctConvert = DCT_DECODE;
  368. // Encode
  369. if (DCT_ENCODE == m_dctConvert)
  370. {
  371. // Do Code Page Convsion
  372. GetCodePageInfo(&rEncodeInit, fDoCharset, pInitInfo->cpiInternal, pInitInfo->cpiExternal);
  373. // Remove NBSPs
  374. if ((TRUE == fIsText) && (CP_UNICODE == pInitInfo->cpiInternal) && (TRUE == pInitInfo->fRemoveNBSP))
  375. rEncodeInit.dwFlags |= ICF_KILLNBSP;
  376. // Set Encoding Type
  377. rEncodeInit.ietEncoding = pInitInfo->ietExternal;
  378. // BinHex Encoding...
  379. if (IET_BINHEX40 == rEncodeInit.ietEncoding)
  380. {
  381. // Locals
  382. PROPVARIANT rOption;
  383. // Init rOption
  384. rOption.vt = VT_BLOB;
  385. rOption.blob.cbSize = sizeof(MACBINARY);
  386. rOption.blob.pBlobData = (LPBYTE)&rEncodeInit.rMacBinary;
  387. GenerateDefaultMacBinaryHeader(&rEncodeInit.rMacBinary);
  388. }
  389. // GetEncodeWrapInfo
  390. if (fIsText)
  391. GetEncodeWrapInfo(&rEncodeInit, pBody);
  392. // Create Internet Encoder
  393. CHECKHR(hr = HrCreateInternetConverter(&rEncodeInit, &m_pEncoder));
  394. }
  395. // Decode
  396. else if (DCT_DECODE == m_dctConvert)
  397. {
  398. // Do Code Page Convsion
  399. GetCodePageInfo(&rDecodeInit, fDoCharset, pInitInfo->cpiInternal, pInitInfo->cpiExternal);
  400. // Remove NBSPs
  401. if ((TRUE == fIsText) && (CP_UNICODE == pInitInfo->cpiInternal) && (TRUE == pInitInfo->fRemoveNBSP))
  402. rDecodeInit.dwFlags |= ICF_KILLNBSP;
  403. // Set Encoding Type
  404. rDecodeInit.ietEncoding = pInitInfo->ietInternal;
  405. // BinHex Dencoding...
  406. if (IET_BINHEX40 == rDecodeInit.ietEncoding)
  407. {
  408. // Locals
  409. PROPVARIANT rOption;
  410. // OID_SHOW_MACBINARY
  411. if (SUCCEEDED(pBody->GetOption(OID_SHOW_MACBINARY, &rOption)))
  412. {
  413. rDecodeInit.fShowMacBinary = rOption.boolVal;
  414. }
  415. }
  416. // Create Internet DeCoder
  417. CHECKHR(hr = HrCreateInternetConverter(&rDecodeInit, &m_pDecoder));
  418. }
  419. // Decode -> Encode
  420. else if (DCT_DECENC == m_dctConvert)
  421. {
  422. // Do Code Page Convsion
  423. if (pInitInfo->cpiInternal != pInitInfo->cpiExternal)
  424. {
  425. // Internal -> Unicode
  426. GetCodePageInfo(&rDecodeInit, fDoCharset, pInitInfo->cpiInternal, CP_UNICODE);
  427. // Unicode -> Extnernal
  428. GetCodePageInfo(&rEncodeInit, fDoCharset, CP_UNICODE, pInitInfo->cpiExternal);
  429. }
  430. // Set Encoding Type
  431. rDecodeInit.ietEncoding = pInitInfo->ietInternal;
  432. // Create Internet Decoder
  433. CHECKHR(hr = HrCreateInternetConverter(&rDecodeInit, &m_pDecoder));
  434. // Set Encoding Type
  435. rEncodeInit.ietEncoding = pInitInfo->ietExternal;
  436. // GetEncodeWrapInfo
  437. if (fIsText)
  438. GetEncodeWrapInfo(&rEncodeInit, pBody);
  439. // Create Internet Encoder
  440. CHECKHR(hr = HrCreateInternetConverter(&rEncodeInit, &m_pEncoder));
  441. }
  442. // No Conversion
  443. else
  444. Assert(DCT_NONE == m_dctConvert);
  445. }
  446. // Otherwise, handle zero length data
  447. else
  448. {
  449. // Converting to IET_UUENCODE
  450. if (IET_UUENCODE == pInitInfo->ietExternal)
  451. {
  452. // Save Size
  453. m_uliIntOffset.QuadPart = m_uliIntSize.QuadPart = lstrlen(c_szUUEncodeZeroLength);
  454. // Single byte
  455. CHECKHR(hr = m_cVirtualStream.Write(c_szUUEncodeZeroLength, lstrlen(c_szUUEncodeZeroLength), NULL));
  456. // Rewind that stream
  457. HrRewindStream(&m_cVirtualStream);
  458. // Change the DC type to any other type
  459. m_dctConvert = DCT_ENCODE;
  460. }
  461. }
  462. exit:
  463. // Thread Safety
  464. LeaveCriticalSection(&m_cs);
  465. // Done
  466. return hr;
  467. }
  468. // --------------------------------------------------------------------------------
  469. // CBodyStream::HrConvertDataLast
  470. // --------------------------------------------------------------------------------
  471. HRESULT CBodyStream::HrConvertDataLast(void)
  472. {
  473. // Locals
  474. HRESULT hr=S_OK;
  475. HRESULT hrWarnings=S_OK;
  476. // Handle Conversion type
  477. switch(m_dctConvert)
  478. {
  479. // ----------------------------------------------------------------------------
  480. case DCT_ENCODE:
  481. // Encode
  482. CHECKHR(hr = m_pEncoder->HrInternetEncode(TRUE));
  483. if ( S_OK != hr )
  484. hrWarnings = TrapError(hr);
  485. // Write
  486. CHECKHR(hr = m_pEncoder->HrWriteConverted(&m_cVirtualStream));
  487. break;
  488. // ----------------------------------------------------------------------------
  489. case DCT_DECODE:
  490. // Convert
  491. CHECKHR(hr = m_pDecoder->HrInternetDecode(TRUE));
  492. if ( S_OK != hr )
  493. hrWarnings = TrapError(hr);
  494. // Write
  495. CHECKHR(hr = m_pDecoder->HrWriteConverted(&m_cVirtualStream));
  496. break;
  497. // ----------------------------------------------------------------------------
  498. case DCT_DECENC:
  499. // Convert
  500. CHECKHR(hr = m_pDecoder->HrInternetDecode(TRUE));
  501. if ( S_OK != hr )
  502. hrWarnings = TrapError(hr);
  503. // Fill Buffer
  504. CHECKHR(hr = m_pDecoder->HrWriteConverted(m_pEncoder));
  505. // Convert
  506. CHECKHR(hr = m_pEncoder->HrInternetEncode(TRUE));
  507. if ( S_OK != hr )
  508. hrWarnings = TrapError(hr);
  509. // Write
  510. CHECKHR(hr = m_pEncoder->HrWriteConverted(&m_cVirtualStream));
  511. break;
  512. // ----------------------------------------------------------------------------
  513. default:
  514. AssertSz(FALSE, "I should be fired and shot if this line of code executes.");
  515. break;
  516. }
  517. exit:
  518. // Done
  519. return (hr == S_OK) ? hrWarnings : hr;
  520. }
  521. // --------------------------------------------------------------------------------
  522. // CBodyStream::HrConvertData
  523. // --------------------------------------------------------------------------------
  524. HRESULT CBodyStream::HrConvertData(LPBLOB pConvert)
  525. {
  526. // Locals
  527. HRESULT hr=S_OK;
  528. HRESULT hrWarnings=S_OK;
  529. // Handle Conversion type
  530. switch(m_dctConvert)
  531. {
  532. // ----------------------------------------------------------------------------
  533. case DCT_ENCODE:
  534. // Fill Buffer
  535. CHECKHR(hr = m_pEncoder->HrFillAppend(pConvert));
  536. // Encode
  537. CHECKHR(hr = m_pEncoder->HrInternetEncode(FALSE));
  538. if ( S_OK != hr )
  539. hrWarnings = TrapError(hr);
  540. // Write
  541. CHECKHR(hr = m_pEncoder->HrWriteConverted(&m_cVirtualStream));
  542. break;
  543. // ----------------------------------------------------------------------------
  544. case DCT_DECODE:
  545. // Fill Buffer
  546. CHECKHR(hr = m_pDecoder->HrFillAppend(pConvert));
  547. // Convert
  548. CHECKHR(hr = m_pDecoder->HrInternetDecode(FALSE));
  549. if ( S_OK != hr )
  550. hrWarnings = TrapError(hr);
  551. // Write
  552. CHECKHR(hr = m_pDecoder->HrWriteConverted(&m_cVirtualStream));
  553. break;
  554. // ----------------------------------------------------------------------------
  555. case DCT_DECENC:
  556. // Fill Buffer
  557. CHECKHR(hr = m_pDecoder->HrFillAppend(pConvert));
  558. // Convert
  559. CHECKHR(hr = m_pDecoder->HrInternetDecode(FALSE));
  560. if ( S_OK != hr )
  561. hrWarnings = TrapError(hr);
  562. // Fill Buffer
  563. CHECKHR(hr = m_pDecoder->HrWriteConverted(m_pEncoder));
  564. // Convert
  565. CHECKHR(hr = m_pEncoder->HrInternetEncode(FALSE));
  566. if ( S_OK != hr )
  567. hrWarnings = TrapError(hr);
  568. // Write
  569. CHECKHR(hr = m_pEncoder->HrWriteConverted(&m_cVirtualStream));
  570. break;
  571. // ----------------------------------------------------------------------------
  572. default:
  573. AssertSz(FALSE, "I should be fired and shot if this line of code executes.");
  574. break;
  575. }
  576. exit:
  577. // Done
  578. return (hr == S_OK) ? hrWarnings : hr;
  579. }
  580. // --------------------------------------------------------------------------------
  581. // CBodyStream::HrConvertToOffset
  582. // --------------------------------------------------------------------------------
  583. HRESULT CBodyStream::HrConvertToOffset(ULARGE_INTEGER uliOffset)
  584. {
  585. // Locals
  586. HRESULT hr=S_OK;
  587. HRESULT hrWarnings=S_OK;
  588. BYTE rgbBuffer[4096];
  589. ULONG cbBuffer=0;
  590. ULONG cb;
  591. ULARGE_INTEGER uliCur, uliSize;
  592. LARGE_INTEGER liStart;
  593. BLOB rConvert;
  594. DWORD dwSize = 0;
  595. // Big Problems...
  596. Assert(m_pLockBytes);
  597. // Fatal Error: This can happen if we are persisting an IMimeMessage back into its original source.
  598. if (NULL == m_pLockBytes)
  599. {
  600. hr = TrapError(E_FAIL);
  601. goto exit;
  602. }
  603. // Query Current position and uliSize
  604. m_cVirtualStream.QueryStat(&uliCur, &uliSize);
  605. liStart.QuadPart = uliCur.QuadPart;
  606. Assert(m_liLastWrite.QuadPart == liStart.QuadPart);
  607. dwSize = m_uliIntSize.LowPart - m_uliIntOffset.LowPart;
  608. // Convert until no more to read or virtual offset is correct
  609. while(dwSize)
  610. {
  611. // Done
  612. if (uliCur.QuadPart >= uliOffset.QuadPart)
  613. break;
  614. // Read a buffer
  615. Assert(m_uliIntOffset.QuadPart <= m_uliIntSize.QuadPart);
  616. CHECKHR(hr = m_pLockBytes->ReadAt(m_uliIntOffset, rgbBuffer, sizeof(rgbBuffer), &cbBuffer));
  617. // Done
  618. if (0 == cbBuffer)
  619. break;
  620. dwSize = dwSize - cbBuffer;
  621. // Last Buffer ?
  622. Assert(m_uliIntOffset.QuadPart + cbBuffer <= m_uliIntSize.QuadPart);
  623. // Setup Blob to Convert
  624. rConvert.cbSize = cbBuffer;
  625. rConvert.pBlobData = rgbBuffer;
  626. // Convert the buffer
  627. CHECKHR(hr = HrConvertData(&rConvert));
  628. if ( S_OK != hr )
  629. hrWarnings = TrapError(hr);
  630. // Increment internal offset...
  631. m_uliIntOffset.QuadPart += cbBuffer;
  632. // Get current virtual offset
  633. m_cVirtualStream.QueryStat(&uliCur, &uliSize);
  634. // Save position as last write position...
  635. m_liLastWrite.QuadPart = uliCur.QuadPart;
  636. }
  637. // Done ?
  638. if (0 == cbBuffer || m_uliIntOffset.QuadPart == m_uliIntSize.QuadPart)
  639. {
  640. // Well we don't need m_pLockBytes anymore, its all in m_cVirtualStream
  641. Assert(m_uliIntOffset.QuadPart == m_uliIntSize.QuadPart);
  642. // Do the last one
  643. CHECKHR(hr = HrConvertDataLast());
  644. if ( S_OK != hr )
  645. hrWarnings = TrapError(hr);
  646. // Get current virtual offset
  647. m_cVirtualStream.QueryStat(&uliCur, &uliSize);
  648. // Save position as last write position...
  649. m_liLastWrite.QuadPart = uliCur.QuadPart;
  650. // Release objects
  651. SafeRelease(m_pLockBytes);
  652. SafeRelease(m_pEncoder);
  653. SafeRelease(m_pDecoder);
  654. }
  655. // Rewind virtual stream back to
  656. CHECKHR(hr = m_cVirtualStream.Seek(liStart, STREAM_SEEK_SET, NULL));
  657. exit:
  658. // Done
  659. return (hr == S_OK) ? hrWarnings : hr;
  660. }
  661. // --------------------------------------------------------------------------------
  662. // CBodyStream::HrConvertToEnd
  663. // --------------------------------------------------------------------------------
  664. HRESULT CBodyStream::HrConvertToEnd(void)
  665. {
  666. // Locals
  667. HRESULT hr=S_OK;
  668. BYTE rgbBuffer[4096];
  669. ULONG cbRead;
  670. // Thread Safety
  671. EnterCriticalSection(&m_cs);
  672. // Move virtual stream to last write position
  673. CHECKHR(hr = m_cVirtualStream.Seek(m_liLastWrite, STREAM_SEEK_SET, NULL));
  674. // Copy m_pLockBytes to pstmTemp
  675. while(1)
  676. {
  677. // Read
  678. CHECKHR(hr = Read(rgbBuffer, sizeof(rgbBuffer), &cbRead));
  679. // Done
  680. if (0 == cbRead)
  681. {
  682. // Well we don't need m_pLockBytes anymore, its all in m_cVirtualStream
  683. Assert(m_uliIntOffset.QuadPart == m_uliIntSize.QuadPart);
  684. break;
  685. }
  686. }
  687. exit:
  688. // Thread Safety
  689. LeaveCriticalSection(&m_cs);
  690. // Done
  691. return hr;
  692. }
  693. // --------------------------------------------------------------------------------
  694. // CBodyStream::Read
  695. // --------------------------------------------------------------------------------
  696. #ifndef WIN16
  697. STDMETHODIMP CBodyStream::Read(LPVOID pv, ULONG cb, ULONG *pcbRead)
  698. #else
  699. STDMETHODIMP CBodyStream::Read(VOID HUGEP *pv, ULONG cb, ULONG *pcbRead)
  700. #endif // !WIN16
  701. {
  702. // Locals
  703. HRESULT hr=S_OK;
  704. HRESULT hrWarnings=S_OK;
  705. ULARGE_INTEGER uliCur,
  706. uliSize;
  707. ULONG cbRead=0,
  708. cbLeft=0,
  709. cbGet;
  710. // Thread Safety
  711. EnterCriticalSection(&m_cs);
  712. // No Convert Case
  713. if (DCT_NONE == m_dctConvert)
  714. {
  715. // Do I Have data
  716. if (m_pLockBytes)
  717. {
  718. // Read Buffer
  719. CHECKHR(hr = m_pLockBytes->ReadAt(m_uliIntOffset, pv, cb, &cbRead));
  720. // Done
  721. m_uliIntOffset.QuadPart += cbRead;
  722. }
  723. }
  724. // Otherwise
  725. else
  726. {
  727. // Read until we have cb
  728. cbLeft = cb;
  729. while(cbLeft)
  730. {
  731. // Query Current position and uliSize
  732. m_cVirtualStream.QueryStat(&uliCur, &uliSize);
  733. // Convert more into the virtual stream
  734. if (uliCur.QuadPart == uliSize.QuadPart)
  735. {
  736. // Done
  737. if (m_uliIntOffset.QuadPart == m_uliIntSize.QuadPart)
  738. break;
  739. // Grow
  740. uliCur.QuadPart += g_dwSysPageSize;
  741. // Convert to offset...
  742. CHECKHR(hr = HrConvertToOffset(uliCur));
  743. if ( S_OK != hr )
  744. hrWarnings = TrapError(hr);
  745. }
  746. // Compute amount that can be read from the current cache
  747. CHECKHR(hr = m_cVirtualStream.Read((LPVOID)((LPBYTE)pv + cbRead), cbLeft, &cbGet));
  748. // Increment cbRead
  749. cbRead+=cbGet;
  750. cbLeft-=cbGet;
  751. }
  752. }
  753. // Return amount read
  754. if (pcbRead)
  755. *pcbRead = cbRead;
  756. exit:
  757. // Thread Safety
  758. LeaveCriticalSection(&m_cs);
  759. // Done
  760. return (hr == S_OK) ? hrWarnings : hr;
  761. }
  762. // --------------------------------------------------------------------------------
  763. // CBodyStream::Seek
  764. // --------------------------------------------------------------------------------
  765. STDMETHODIMP CBodyStream::Seek(LARGE_INTEGER dlibMove, DWORD dwOrigin, ULARGE_INTEGER *plibNewPosition)
  766. {
  767. // Locals
  768. HRESULT hr=S_OK;
  769. HRESULT hrWarnings=S_OK;
  770. ULARGE_INTEGER uliNew;
  771. // Thread Safety
  772. EnterCriticalSection(&m_cs);
  773. // No Convert Case
  774. if (DCT_NONE == m_dctConvert)
  775. {
  776. // Seek the file pointer
  777. switch (dwOrigin)
  778. {
  779. // --------------------------------------------------------
  780. case STREAM_SEEK_SET:
  781. uliNew.QuadPart = (DWORDLONG)dlibMove.QuadPart;
  782. break;
  783. // --------------------------------------------------------
  784. case STREAM_SEEK_CUR:
  785. if (dlibMove.QuadPart < 0)
  786. {
  787. if ((DWORDLONG)(0 - dlibMove.QuadPart) > m_uliIntOffset.QuadPart)
  788. {
  789. hr = TrapError(E_FAIL);
  790. goto exit;
  791. }
  792. }
  793. uliNew.QuadPart = m_uliIntOffset.QuadPart + dlibMove.QuadPart;
  794. break;
  795. // --------------------------------------------------------
  796. case STREAM_SEEK_END:
  797. if (dlibMove.QuadPart < 0 || (DWORDLONG)dlibMove.QuadPart > m_uliIntSize.QuadPart)
  798. {
  799. hr = TrapError(E_FAIL);
  800. goto exit;
  801. }
  802. uliNew.QuadPart = m_uliIntSize.QuadPart - dlibMove.QuadPart;
  803. break;
  804. // --------------------------------------------------------
  805. default:
  806. hr = TrapError(STG_E_INVALIDFUNCTION);
  807. goto exit;
  808. }
  809. // New offset greater than size...
  810. m_uliIntOffset.QuadPart = min(uliNew.QuadPart, m_uliIntSize.QuadPart);
  811. // Return Position
  812. if (plibNewPosition)
  813. plibNewPosition->QuadPart = (LONGLONG)m_uliIntOffset.QuadPart;
  814. }
  815. // Otherwise
  816. else
  817. {
  818. // Locals
  819. ULARGE_INTEGER uliCur, uliSize;
  820. LARGE_INTEGER liNew;
  821. // Query Current position and uliSize
  822. m_cVirtualStream.QueryStat(&uliCur, &uliSize);
  823. // Seek the file pointer
  824. switch (dwOrigin)
  825. {
  826. // --------------------------------------------------------
  827. case STREAM_SEEK_SET:
  828. // Assume new position
  829. uliNew.QuadPart = (DWORDLONG)dlibMove.QuadPart;
  830. break;
  831. // --------------------------------------------------------
  832. case STREAM_SEEK_CUR:
  833. if (dlibMove.QuadPart < 0)
  834. {
  835. if ((DWORDLONG)(0 - dlibMove.QuadPart) > uliCur.QuadPart)
  836. {
  837. hr = TrapError(E_FAIL);
  838. goto exit;
  839. }
  840. }
  841. uliNew.QuadPart = uliCur.QuadPart + dlibMove.QuadPart;
  842. break;
  843. // --------------------------------------------------------
  844. case STREAM_SEEK_END:
  845. // Do I need to convert any more ?
  846. if (m_uliIntOffset.QuadPart < m_uliIntSize.QuadPart)
  847. {
  848. // Then Convert to the end
  849. CHECKHR(hr = HrConvertToEnd());
  850. // Better be done...
  851. Assert(m_uliIntOffset.QuadPart == m_uliIntSize.QuadPart && NULL == m_pLockBytes);
  852. }
  853. // Query Current Position
  854. m_cVirtualStream.QueryStat(&uliCur, &uliSize);
  855. // Can I really move there
  856. if (dlibMove.QuadPart < 0 || (DWORDLONG)dlibMove.QuadPart > uliSize.QuadPart)
  857. {
  858. hr = TrapError(E_FAIL);
  859. goto exit;
  860. }
  861. // Assume new position
  862. uliNew.QuadPart = uliSize.QuadPart - dlibMove.QuadPart;
  863. break;
  864. // --------------------------------------------------------
  865. default:
  866. hr = TrapError(STG_E_INVALIDFUNCTION);
  867. goto exit;
  868. }
  869. // New offset greater than size...
  870. if (uliNew.QuadPart > uliSize.QuadPart)
  871. {
  872. // Do I need to convert any more ?
  873. if (m_uliIntOffset.QuadPart < m_uliIntSize.QuadPart)
  874. {
  875. // Seek m_cVirtualStream to m_uliIntOffset
  876. CHECKHR(hr = m_cVirtualStream.Seek(m_liLastWrite, STREAM_SEEK_SET, NULL));
  877. // Convert to offset
  878. CHECKHR(hr = HrConvertToOffset(uliNew));
  879. if ( S_OK != hr )
  880. hrWarnings = TrapError(hr);
  881. }
  882. // Query Current position and uliSize
  883. m_cVirtualStream.QueryStat(&uliCur, &uliSize);
  884. // Reposition uliNew.QuadPart
  885. uliNew.QuadPart = (uliNew.QuadPart > uliSize.QuadPart) ? uliSize.QuadPart : uliNew.QuadPart;
  886. }
  887. // Otherwise, seek m_cVirtualStream to new location
  888. liNew.QuadPart = uliNew.QuadPart;
  889. CHECKHR(hr = m_cVirtualStream.Seek(liNew, STREAM_SEEK_SET, NULL));
  890. // Return Position
  891. if (plibNewPosition)
  892. plibNewPosition->QuadPart = (LONGLONG)uliNew.QuadPart;
  893. }
  894. exit:
  895. // Thread Safety
  896. LeaveCriticalSection(&m_cs);
  897. // Done
  898. return (hr == S_OK) ? hrWarnings : hr;
  899. }
  900. // --------------------------------------------------------------------------------
  901. // CBodyStream::CopyTo
  902. // --------------------------------------------------------------------------------
  903. STDMETHODIMP CBodyStream::CopyTo(IStream *pstmDest, ULARGE_INTEGER cb, ULARGE_INTEGER *puliRead, ULARGE_INTEGER *puliWritten)
  904. {
  905. return HrCopyStreamCB((IStream *)this, pstmDest, cb, puliRead, puliWritten);
  906. }
  907. // --------------------------------------------------------------------------------
  908. // CBodyStream::Stat
  909. // --------------------------------------------------------------------------------
  910. STDMETHODIMP CBodyStream::Stat(STATSTG *pStat, DWORD grfStatFlag)
  911. {
  912. // Locals
  913. HRESULT hr=S_OK;
  914. LARGE_INTEGER liSeek;
  915. ULARGE_INTEGER uliCurrent;
  916. // Invalid Arg
  917. if (NULL == pStat)
  918. return TrapError(E_INVALIDARG);
  919. // Init
  920. ZeroMemory(pStat, sizeof(STATSTG));
  921. // Set Storage Type
  922. pStat->type = STGTY_STREAM;
  923. // Set the name ?
  924. if (m_pszFileName && !(grfStatFlag & STATFLAG_NONAME))
  925. pStat->pwcsName = PszToUnicode(CP_ACP, m_pszFileName);
  926. // Seek current position
  927. liSeek.QuadPart = 0;
  928. CHECKHR(hr = Seek(liSeek, STREAM_SEEK_CUR, &uliCurrent));
  929. // Seek to the end
  930. liSeek.QuadPart = 0;
  931. CHECKHR(hr = Seek(liSeek, STREAM_SEEK_END, &pStat->cbSize));
  932. // Seek back to current position
  933. liSeek.QuadPart = uliCurrent.QuadPart;
  934. CHECKHR(hr = Seek(liSeek, STREAM_SEEK_SET, &uliCurrent));
  935. Assert(uliCurrent.QuadPart == (DWORDLONG)liSeek.QuadPart);
  936. // init clsid
  937. pStat->clsid = CLSID_NULL;
  938. // If we have a filename, get the class id...
  939. if (m_pszFileName)
  940. {
  941. // Locals
  942. CHAR szExt[MAX_PATH];
  943. // Split the filename
  944. if (SUCCEEDED(MimeOleGetFileExtension(m_pszFileName, szExt, ARRAYSIZE(szExt))))
  945. MimeOleGetExtClassId(szExt, &pStat->clsid);
  946. }
  947. exit:
  948. // Done
  949. return hr;
  950. }