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.

2601 lines
80 KiB

  1. // --------------------------------------------------------------------------------
  2. // Inetconv.cpp
  3. // Copyright (c)1993-1995 Microsoft Corporation, All Rights Reserved
  4. // Steven J. Bailey
  5. // --------------------------------------------------------------------------------
  6. #include "pch.hxx"
  7. #include "dllmain.h"
  8. #include "inetconv.h"
  9. #include "internat.h"
  10. #ifndef MAC
  11. #include <shlwapi.h>
  12. #include <mlang.h>
  13. #endif // !MAC
  14. #include "mimeapi.h"
  15. #include "icoint.h"
  16. #include "demand.h"
  17. // --------------------------------------------------------------------------------
  18. // FGROWBUFFER
  19. // --------------------------------------------------------------------------------
  20. #define FGROWBUFFER(_pBuffer, _cb) ((_pBuffer)->cb + _cb >= (_pBuffer)->cbAlloc)
  21. // --------------------------------------------------------------------------------
  22. // QP Encoder
  23. // --------------------------------------------------------------------------------
  24. const CHAR g_rgchHex[] = "0123456789ABCDEF";
  25. // --------------------------------------------------------------------------------
  26. // Base64 Decoding Table
  27. // ---------------------
  28. // Decodes one Base64 character into a numeric value
  29. //
  30. // 0 1 2 3 4 5 6
  31. // 0123456789012345678901234567890123456789012345678901234567890123
  32. // ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/
  33. // --------------------------------------------------------------------------------
  34. const char g_rgchDecodeBase64[256] = {
  35. 64, 64, 64, 64, 64, 64, 64, 64, // 0x00
  36. 64, 64, 64, 64, 64, 64, 64, 64,
  37. 64, 64, 64, 64, 64, 64, 64, 64, // 0x10
  38. 64, 64, 64, 64, 64, 64, 64, 64,
  39. 64, 64, 64, 64, 64, 64, 64, 64, // 0x20
  40. 64, 64, 64, 62, 64, 64, 64, 63,
  41. 52, 53, 54, 55, 56, 57, 58, 59, // 0x30
  42. 60, 61, 64, 64, 64, 0, 64, 64,
  43. 64, 0, 1, 2, 3, 4, 5, 6, // 0x40
  44. 7, 8, 9, 10, 11, 12, 13, 14,
  45. 15, 16, 17, 18, 19, 20, 21, 22, // 0x50
  46. 23, 24, 25, 64, 64, 64, 64, 64,
  47. 64, 26, 27, 28, 29, 30, 31, 32, // 0x60
  48. 33, 34, 35, 36, 37, 38, 39, 40,
  49. 41, 42, 43, 44, 45, 46, 47, 48, // 0x70
  50. 49, 50, 51, 64, 64, 64, 64, 64,
  51. 64, 64, 64, 64, 64, 64, 64, 64, // 0x80
  52. 64, 64, 64, 64, 64, 64, 64, 64,
  53. 64, 64, 64, 64, 64, 64, 64, 64, // 0x90
  54. 64, 64, 64, 64, 64, 64, 64, 64,
  55. 64, 64, 64, 64, 64, 64, 64, 64, // 0xA0
  56. 64, 64, 64, 64, 64, 64, 64, 64,
  57. 64, 64, 64, 64, 64, 64, 64, 64, // 0xB0
  58. 64, 64, 64, 64, 64, 64, 64, 64,
  59. 64, 64, 64, 64, 64, 64, 64, 64, // 0xC0
  60. 64, 64, 64, 64, 64, 64, 64, 64,
  61. 64, 64, 64, 64, 64, 64, 64, 64, // 0xD0
  62. 64, 64, 64, 64, 64, 64, 64, 64,
  63. 64, 64, 64, 64, 64, 64, 64, 64, // 0xE0
  64. 64, 64, 64, 64, 64, 64, 64, 64,
  65. 64, 64, 64, 64, 64, 64, 64, 64, // 0xF0
  66. 64, 64, 64, 64, 64, 64, 64, 64,
  67. };
  68. // --------------------------------------------------------------------------------
  69. // Base64 Encoder
  70. // --------------------------------------------------------------------------------
  71. extern const CHAR g_rgchEncodeBase64[] =
  72. "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/ ";
  73. // --------------------------------------------------------------------------------
  74. // BinHex Decoding Table
  75. // ---------------------
  76. // Decodes one BinHex character into a numeric value
  77. //
  78. // 0 1 2 3 4 5 6
  79. // 0123456789012345678901234567890123456789012345678901234567890123
  80. // !"#$%&'()*+,-012345689@ABCDEFGHIJKLMNPQRSTUVXYZ[`abcdefhijklmpqr
  81. // --------------------------------------------------------------------------------
  82. #undef BINHEX_INVALID
  83. #undef BINHEX_REPEAT
  84. #undef XXXX
  85. const UCHAR BINHEX_INVALID = 0x40;
  86. const UCHAR BINHEX_REPEAT = 0x90;
  87. const UCHAR BINHEX_TERM = ':';
  88. const UCHAR XXXX = BINHEX_INVALID;
  89. const ULONG cbMinBinHexHeader = 22;
  90. const WORD wBinHexZero = 0;
  91. const UCHAR g_rgchDecodeBinHex[256] = {
  92. XXXX, XXXX, XXXX, XXXX, XXXX, XXXX, XXXX, XXXX, // 0x00
  93. XXXX, XXXX, XXXX, XXXX, XXXX, XXXX, XXXX, XXXX,
  94. XXXX, XXXX, XXXX, XXXX, XXXX, XXXX, XXXX, XXXX, // 0x10
  95. XXXX, XXXX, XXXX, XXXX, XXXX, XXXX, XXXX, XXXX,
  96. XXXX, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, // 0x20
  97. 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, XXXX, XXXX,
  98. 0x0D, 0x0E, 0x0F, 0x10, 0x11, 0x12, 0x13, XXXX, // 0x30
  99. 0x14, 0x15, 0x16, XXXX, XXXX, XXXX, XXXX, XXXX,
  100. 0x16, 0x17, 0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, // 0x40
  101. 0x1E, 0x1F, 0x20, 0x21, 0x22, 0x23, 0x24, XXXX,
  102. 0x25, 0x26, 0x27, 0x28, 0x29, 0x2A, 0x2B, XXXX, // 0x50
  103. 0x2C, 0x2D, 0x2E, 0x2F, XXXX, XXXX, XXXX, XXXX,
  104. 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, XXXX, // 0x60
  105. 0x37, 0x38, 0x39, 0x3A, 0x3B, 0x3C, XXXX, XXXX,
  106. 0x3D, 0x3E, 0x3F, XXXX, XXXX, XXXX, XXXX, XXXX, // 0x70
  107. XXXX, XXXX, XXXX, XXXX, XXXX, XXXX, XXXX, XXXX,
  108. XXXX, XXXX, XXXX, XXXX, XXXX, XXXX, XXXX, XXXX, // 0x80
  109. XXXX, XXXX, XXXX, XXXX, XXXX, XXXX, XXXX, XXXX,
  110. XXXX, XXXX, XXXX, XXXX, XXXX, XXXX, XXXX, XXXX, // 0x90
  111. XXXX, XXXX, XXXX, XXXX, XXXX, XXXX, XXXX, XXXX,
  112. XXXX, XXXX, XXXX, XXXX, XXXX, XXXX, XXXX, XXXX, // 0xA0
  113. XXXX, XXXX, XXXX, XXXX, XXXX, XXXX, XXXX, XXXX,
  114. XXXX, XXXX, XXXX, XXXX, XXXX, XXXX, XXXX, XXXX, // 0xB0
  115. XXXX, XXXX, XXXX, XXXX, XXXX, XXXX, XXXX, XXXX,
  116. XXXX, XXXX, XXXX, XXXX, XXXX, XXXX, XXXX, XXXX, // 0xC0
  117. XXXX, XXXX, XXXX, XXXX, XXXX, XXXX, XXXX, XXXX,
  118. XXXX, XXXX, XXXX, XXXX, XXXX, XXXX, XXXX, XXXX, // 0xD0
  119. XXXX, XXXX, XXXX, XXXX, XXXX, XXXX, XXXX, XXXX,
  120. XXXX, XXXX, XXXX, XXXX, XXXX, XXXX, XXXX, XXXX, // 0xE0
  121. XXXX, XXXX, XXXX, XXXX, XXXX, XXXX, XXXX, XXXX,
  122. XXXX, XXXX, XXXX, XXXX, XXXX, XXXX, XXXX, XXXX, // 0xF0
  123. XXXX, XXXX, XXXX, XXXX, XXXX, XXXX, XXXX, XXXX,
  124. };
  125. // --------------------------------------------------------------------------------
  126. // HrCreateLineBreaker
  127. // --------------------------------------------------------------------------------
  128. HRESULT HrCreateLineBreaker(IMLangLineBreakConsole **ppLineBreak)
  129. {
  130. // Locals
  131. HRESULT hr=S_OK;
  132. PFNGETCLASSOBJECT pfnDllGetClassObject=NULL;
  133. IClassFactory *pFactory=NULL;
  134. // Invalid Args
  135. Assert(ppLineBreak);
  136. // Init
  137. *ppLineBreak = NULL;
  138. // Thread Safety
  139. EnterCriticalSection(&g_csMLANG);
  140. // If not loaded yet
  141. if (NULL == g_hinstMLANG)
  142. {
  143. // Load MLANG - This should be fast most of the time because MLANG is usually loaded
  144. g_hinstMLANG = LoadLibrary("MLANG.DLL");
  145. if (NULL == g_hinstMLANG)
  146. {
  147. hr = TrapError(E_FAIL);
  148. goto exit;
  149. }
  150. }
  151. // Get DllClassObject
  152. pfnDllGetClassObject = (PFNGETCLASSOBJECT)GetProcAddress(g_hinstMLANG, "DllGetClassObject");
  153. if (NULL == pfnDllGetClassObject)
  154. {
  155. hr = TrapError(E_FAIL);
  156. goto exit;
  157. }
  158. // Get the MLANG Class Factory
  159. CHECKHR(hr = (*pfnDllGetClassObject)(CLSID_CMultiLanguage, IID_IClassFactory, (LPVOID *)&pFactory));
  160. // Finally, create the object that I actually wanted
  161. CHECKHR(hr = pFactory->CreateInstance(NULL, IID_IMLangLineBreakConsole, (LPVOID *)ppLineBreak));
  162. exit:
  163. // Thread Safety
  164. LeaveCriticalSection(&g_csMLANG);
  165. // Cleanup
  166. SafeRelease(pFactory);
  167. // Done
  168. return hr;
  169. }
  170. // --------------------------------------------------------------------------------
  171. // HrCreateInternetConverter
  172. // --------------------------------------------------------------------------------
  173. HRESULT HrCreateInternetConverter(LPCONVINITINFO pInitInfo, CInternetConverter **ppConverter)
  174. {
  175. // Allocate It
  176. *ppConverter = new CInternetConverter();
  177. if (NULL == *ppConverter)
  178. return TrapError(E_OUTOFMEMORY);
  179. // Initialize
  180. return TrapError((*ppConverter)->HrInit(pInitInfo));
  181. }
  182. // --------------------------------------------------------------------------------
  183. // BinHexCalcCRC16
  184. // --------------------------------------------------------------------------------
  185. void BinHexCalcCRC16( LPBYTE lpbBuff, ULONG cBuff, WORD * wCRC )
  186. {
  187. LPBYTE lpb;
  188. BYTE b;
  189. WORD uCRC;
  190. WORD fWrap;
  191. ULONG i;
  192. uCRC = *wCRC;
  193. for ( lpb = lpbBuff; lpb < lpbBuff + cBuff; lpb++ )
  194. {
  195. b = *lpb;
  196. for ( i = 0; i < 8; i++ )
  197. {
  198. fWrap = uCRC & 0x8000;
  199. uCRC = (uCRC << 1) | (b >> 7);
  200. if ( fWrap )
  201. {
  202. uCRC = uCRC ^ 0x1021;
  203. }
  204. b = b << 1;
  205. }
  206. }
  207. *wCRC = uCRC;
  208. }
  209. // --------------------------------------------------------------------------------
  210. // HrCreateMacBinaryHeader
  211. // --------------------------------------------------------------------------------
  212. HRESULT HrCreateMacBinaryHeader(LPCONVERTBUFFER prBinHexHeader, LPCONVERTBUFFER prMacBinaryHeader)
  213. {
  214. HRESULT hr = S_OK;
  215. LPMACBINARY pmacbin;
  216. LPBYTE pbBinHex;
  217. #ifndef _MAC
  218. WORD wCRC = 0;
  219. #endif // _MAC
  220. if ((NULL == prBinHexHeader) || (NULL == prMacBinaryHeader))
  221. {
  222. hr = ERROR_INVALID_PARAMETER;
  223. goto exit;
  224. }
  225. pmacbin = (LPMACBINARY)(prMacBinaryHeader->pb);
  226. pbBinHex = (LPBYTE)(prBinHexHeader->pb);
  227. // Zero it out first
  228. ZeroMemory(pmacbin, sizeof(MACBINARY));
  229. // Write in the filename length
  230. pmacbin->cchFileName = (BYTE)min(pbBinHex[0], sizeof(pmacbin->rgchFileName)-1);
  231. pbBinHex += 1;
  232. // Copy over the filename
  233. CopyMemory(pmacbin->rgchFileName, pbBinHex, pmacbin->cchFileName);
  234. pmacbin->rgchFileName[pmacbin->cchFileName] = '\0';
  235. pbBinHex += pmacbin->cchFileName + 1;
  236. // Copy over the type and creator
  237. CopyMemory(&(pmacbin->dwType), pbBinHex, sizeof(pmacbin->dwType));
  238. pbBinHex += 4;
  239. CopyMemory(&(pmacbin->dwCreator), pbBinHex, sizeof(pmacbin->dwCreator));
  240. pbBinHex += 4;
  241. // Copy over the finder flags
  242. pmacbin->bFinderFlags = *pbBinHex;
  243. pbBinHex++;
  244. pmacbin->bFinderFlags2 = *pbBinHex;
  245. pbBinHex++;
  246. // Copy over the data fork length
  247. CopyMemory(&(pmacbin->lcbDataFork), pbBinHex, sizeof(pmacbin->lcbDataFork));
  248. pbBinHex += 4;
  249. // Copy over the resource fork length
  250. CopyMemory(&(pmacbin->lcbResourceFork), pbBinHex, sizeof(pmacbin->lcbResourceFork));
  251. pbBinHex += 4;
  252. // Drop on the version stamps
  253. pmacbin->bVerMacBin2 = 129;
  254. pmacbin->bMinVerMacBin2 = 129;
  255. // Calculate the CRC
  256. #ifdef _MAC
  257. BinHexCalcCRC16((LPBYTE) pmacbin, 124, &(pmacbin->wCRC));
  258. BinHexCalcCRC16((LPBYTE) &wBinHexZero, sizeof(wBinHexZero), &(pmacbin->wCRC));
  259. #else // !_MAC
  260. BinHexCalcCRC16((LPBYTE) pmacbin, 124, &(wCRC));
  261. BinHexCalcCRC16((LPBYTE) &wBinHexZero, sizeof(wBinHexZero), &(wCRC));
  262. // Need to keep it in Mac order
  263. pmacbin->wCRC = HIBYTE(wCRC);
  264. pmacbin->wCRC |= (LOBYTE(wCRC) << 8);
  265. #endif // _MAC
  266. prMacBinaryHeader->cb += sizeof(MACBINARY);
  267. exit:
  268. return hr;
  269. }
  270. // --------------------------------------------------------------------------------
  271. // CInternetConverter
  272. // --------------------------------------------------------------------------------
  273. CInternetConverter::CInternetConverter(void)
  274. {
  275. m_cRef = 1;
  276. m_dwFlags = 0;
  277. m_cbConvert = 0;
  278. m_ietEncoding = IET_BINARY;
  279. m_cpiSource = CP_ACP;
  280. m_cpiDest = CP_ACP;
  281. m_fLastBuffer = FALSE;
  282. m_fEncoder = FALSE;
  283. m_uchPrev = '\0';
  284. m_pAppend = NULL;
  285. m_pWrite = NULL;
  286. m_convtype = ICT_UNKNOWN;
  287. m_cchMaxLine = 0;
  288. m_pBinhexEncode = NULL;
  289. m_eBinHexStateDec = sSTARTING;
  290. m_fRepeating = FALSE;
  291. m_cAccum = 0;
  292. m_prBinhexOutput = &m_rOut;
  293. m_cbToProcess = 0;
  294. m_cbDataFork = 0;
  295. m_cbResourceFork = 0;
  296. m_wCRC = 0;
  297. m_wCRCForFork = 0;
  298. m_fDataForkOnly = FALSE;
  299. m_pLineBreak = NULL;
  300. ZeroMemory(&m_rIn, sizeof(CONVERTBUFFER));
  301. ZeroMemory(&m_rOut, sizeof(CONVERTBUFFER));
  302. ZeroMemory(&m_rCset, sizeof(CONVERTBUFFER));
  303. ZeroMemory(&m_rBinhexHeader, sizeof(CONVERTBUFFER));
  304. }
  305. // --------------------------------------------------------------------------------
  306. // CInternetConverter::~CInternetConverter
  307. // --------------------------------------------------------------------------------
  308. CInternetConverter::~CInternetConverter(void)
  309. {
  310. if (m_pBinhexEncode)
  311. delete m_pBinhexEncode;
  312. SafeMemFree(m_rIn.pb);
  313. SafeMemFree(m_rOut.pb);
  314. SafeMemFree(m_rCset.pb);
  315. SafeMemFree(m_rBinhexHeader.pb);
  316. SafeRelease(m_pLineBreak);
  317. }
  318. // --------------------------------------------------------------------------------
  319. // CInternetConverter::QueryInterface
  320. // --------------------------------------------------------------------------------
  321. STDMETHODIMP CInternetConverter::QueryInterface(REFIID riid, LPVOID *ppv)
  322. {
  323. return E_NOTIMPL;
  324. }
  325. // --------------------------------------------------------------------------------
  326. // CInternetConverter::AddRef
  327. // --------------------------------------------------------------------------------
  328. STDMETHODIMP_(ULONG) CInternetConverter::AddRef(void)
  329. {
  330. return ++m_cRef;
  331. }
  332. // --------------------------------------------------------------------------------
  333. // CInternetConverter::Release
  334. // --------------------------------------------------------------------------------
  335. STDMETHODIMP_(ULONG) CInternetConverter::Release(void)
  336. {
  337. if (0 != --m_cRef)
  338. return m_cRef;
  339. delete this;
  340. return 0;
  341. }
  342. // --------------------------------------------------------------------------------
  343. // CInternetConverter::HrInit
  344. // --------------------------------------------------------------------------------
  345. HRESULT CInternetConverter::HrInit(LPCONVINITINFO pInitInfo)
  346. {
  347. // Locals
  348. HRESULT hr=S_OK;
  349. // Save Flags
  350. m_dwFlags = pInitInfo->dwFlags;
  351. // Save Format
  352. m_ietEncoding = pInitInfo->ietEncoding;
  353. // Save Source Code Page
  354. m_cpiSource = pInitInfo->cpiSource;
  355. // Save Dest Code Page
  356. m_cpiDest = pInitInfo->cpiDest;
  357. // Are we an encoder..
  358. m_fEncoder = pInitInfo->fEncoder;
  359. // Save Wrap Info
  360. m_cchMaxLine = pInitInfo->cchMaxLine;
  361. // Save MacBinary state
  362. m_fDataForkOnly = !pInitInfo->fShowMacBinary;
  363. // InitConvertType
  364. CHECKHR(hr = HrInitConvertType(pInitInfo));
  365. // DoubleCheck
  366. Assert(m_pWrite && m_pAppend && ICT_UNKNOWN != m_convtype);
  367. exit:
  368. // Done
  369. return hr;
  370. }
  371. // --------------------------------------------------------------------------------
  372. // CInternetConverter::HrInitConvertType
  373. // --------------------------------------------------------------------------------
  374. HRESULT CInternetConverter::HrInitConvertType(LPCONVINITINFO pInitInfo)
  375. {
  376. // Locals
  377. HRESULT hr=S_OK;
  378. CODEPAGEINFO CodePage;
  379. CODEPAGEID cpiLCID;
  380. // Time to compute m_pAppend and m_pDump...
  381. if (ICF_WRAPTEXT & m_dwFlags)
  382. {
  383. // Check Assumptions
  384. Assert((IET_7BIT == m_ietEncoding || IET_8BIT == m_ietEncoding) && TRUE == m_fEncoder);
  385. // Code Page Conversion...
  386. if (ICF_CODEPAGE & m_dwFlags)
  387. m_convtype = ICT_WRAPTEXT_CODEPAGE;
  388. else
  389. m_convtype = ICT_WRAPTEXT;
  390. // Load MLANG
  391. CHECKHR(hr = HrCreateLineBreaker(&m_pLineBreak));
  392. // Set cpiLCID
  393. cpiLCID = m_cpiSource;
  394. // Unicode ?
  395. if (CP_UNICODE == m_cpiSource)
  396. {
  397. // Get Destination Code Page Info
  398. if (SUCCEEDED(g_pInternat->GetCodePageInfo(m_cpiDest, &CodePage)))
  399. {
  400. // Set cpiLCID
  401. cpiLCID = CodePage.cpiFamily;
  402. }
  403. }
  404. // Map m_cpiSource to lcid
  405. switch(cpiLCID)
  406. {
  407. case 874: m_lcid = 0x041E; break;
  408. case 932: m_lcid = 0x0411; break;
  409. case 936: m_lcid = 0x0804; break;
  410. case 949: m_lcid = 0x0412; break;
  411. case 950: m_lcid = 0x0404; break;
  412. case 1250: m_lcid = 0x040e; break;
  413. case 1251: m_lcid = 0x0419; break;
  414. case 1252: m_lcid = 0x0409; break;
  415. case 1253: m_lcid = 0x0408; break;
  416. case 1254: m_lcid = 0x041f; break;
  417. case 1255: m_lcid = 0x040d; break;
  418. case 1256: m_lcid = 0x0401; break;
  419. case 1257: m_lcid = 0x0426; break;
  420. default: m_lcid = GetSystemDefaultLCID(); break;
  421. }
  422. }
  423. // Otherwise, if encoding
  424. else if (TRUE == m_fEncoder)
  425. {
  426. // If CodePage Conversion
  427. if (ICF_CODEPAGE & m_dwFlags)
  428. m_convtype = ICT_CODEPAGE_ENCODE;
  429. else
  430. m_convtype = ICT_ENCODE;
  431. // Need binhex encoder
  432. if (IET_BINHEX40 == m_ietEncoding)
  433. {
  434. // Create me an encoder
  435. CHECKALLOC(m_pBinhexEncode = new CBinhexEncoder);
  436. // Initialize
  437. CHECKHR(hr = m_pBinhexEncode->HrConfig(0, 0, &pInitInfo->rMacBinary));
  438. }
  439. }
  440. // Otherwise, if not encoding
  441. else
  442. {
  443. // If CodePage Conversion
  444. if (ICF_CODEPAGE & m_dwFlags)
  445. m_convtype = ICT_DECODE_CODEPAGE;
  446. else
  447. m_convtype = ICT_DECODE;
  448. }
  449. // Map Write and Append Buffers from Conversion Type
  450. switch(m_convtype)
  451. {
  452. // m_rIn --> m_rCset
  453. case ICT_WRAPTEXT_CODEPAGE:
  454. case ICT_DECODE_CODEPAGE:
  455. m_pAppend = &m_rIn;
  456. m_pWrite = &m_rCset;
  457. break;
  458. // m_rIn --> m_rOut
  459. case ICT_WRAPTEXT:
  460. case ICT_ENCODE:
  461. case ICT_DECODE:
  462. m_pAppend = &m_rIn;
  463. m_pWrite = &m_rOut;
  464. break;
  465. // m_rCset --> m_rOut
  466. case ICT_CODEPAGE_ENCODE:
  467. m_pAppend = &m_rCset;
  468. m_pWrite = &m_rOut;
  469. break;
  470. // Error
  471. default:
  472. AssertSz(FALSE, "INVALID INETCONVTYPE");
  473. break;
  474. }
  475. exit:
  476. // Done
  477. return hr;
  478. }
  479. // --------------------------------------------------------------------------------
  480. // CInternetConverter::HrConvBuffAppendBlock
  481. // --------------------------------------------------------------------------------
  482. inline HRESULT CInternetConverter::HrConvBuffAppendBlock(LPBYTE pb, ULONG cb)
  483. {
  484. // Locals
  485. HRESULT hr=S_OK;
  486. // Do I need to grow
  487. if (FGROWBUFFER(&m_rOut, cb))
  488. {
  489. // Grow the buffer
  490. CHECKHR(hr = HrGrowBuffer(&m_rOut, cb));
  491. }
  492. // Copy the buffer
  493. CopyMemory(m_rOut.pb + m_rOut.cb, pb, cb);
  494. // Increment Size
  495. m_rOut.cb += cb;
  496. exit:
  497. // Done
  498. return hr;
  499. }
  500. // --------------------------------------------------------------------------------
  501. // CInternetConverter::PszConvBuffGetNextLine
  502. // --------------------------------------------------------------------------------
  503. inline LPSTR CInternetConverter::PszConvBuffGetNextLine(ULONG *pcbLine, ULONG *pcbRead, BOOL *pfFound)
  504. {
  505. // Locals
  506. UCHAR uchThis, uchPrev;
  507. ULONG cbLine=0;
  508. // Invalid Arg
  509. Assert(pcbLine && pcbRead && pfFound);
  510. // Init
  511. *pfFound = FALSE;
  512. // Read to next \n
  513. while(m_rIn.i + cbLine < m_rIn.cb)
  514. {
  515. // Get a character...
  516. uchThis = m_rIn.pb[m_rIn.i + cbLine];
  517. // Better not be null
  518. Assert(uchThis);
  519. // Increment Line Length
  520. cbLine++;
  521. // Done
  522. if (chLF == uchThis)
  523. {
  524. *pfFound = TRUE;
  525. break;
  526. }
  527. // Remember Previous Char
  528. uchPrev = uchThis;
  529. }
  530. // Set Next Line
  531. *pcbRead = cbLine;
  532. // Fixup cbLine
  533. if (chLF == uchThis)
  534. cbLine--;
  535. if (chCR == uchPrev)
  536. cbLine--;
  537. // Set Length
  538. *pcbLine = cbLine;
  539. // Done
  540. return (LPSTR)(m_rIn.pb + m_rIn.i);
  541. }
  542. // --------------------------------------------------------------------------------
  543. // CInternetConverter::CopyMemoryRemoveNBSP
  544. // --------------------------------------------------------------------------------
  545. void CInternetConverter::CopyMemoryRemoveNBSP(LPBYTE pbDest, LPBYTE pbSource, ULONG cbSource)
  546. {
  547. // Locals
  548. ULONG iDest=0;
  549. ULONG iSource=0;
  550. // Invalid ARg
  551. Assert(pbDest && pbSource && CP_UNICODE == m_cpiSource);
  552. // Do It
  553. while(1)
  554. {
  555. // If not a null lead, copy next two bytes...
  556. if (iSource + 1 < cbSource)
  557. {
  558. // Better not be 0x00A0 - insert space
  559. Assert(iSource % 2 == 0);
  560. if (0xA0 == pbSource[iSource] && 0x00 == pbSource[iSource + 1])
  561. {
  562. // 0x0020 = Space
  563. pbDest[iDest++] = 0x20;
  564. pbDest[iDest++] = 0x00;
  565. // Step Over this character...
  566. iSource+=2;
  567. }
  568. // Otherwise, copy the character
  569. else
  570. {
  571. // Copy This Char
  572. pbDest[iDest++] = pbSource[iSource++];
  573. // Copy Next Char
  574. if (iSource < cbSource)
  575. pbDest[iDest++] = pbSource[iSource++];
  576. }
  577. }
  578. // Otherwise, just copy this once character and stop
  579. else
  580. {
  581. // Copy It
  582. if (iSource < cbSource)
  583. pbDest[iDest++] = pbSource[iSource++];
  584. // Done
  585. break;
  586. }
  587. }
  588. }
  589. // --------------------------------------------------------------------------------
  590. // CInternetConverter::HrFillAppend
  591. // --------------------------------------------------------------------------------
  592. HRESULT CInternetConverter::HrFillAppend(LPBLOB pData)
  593. {
  594. // Locals
  595. HRESULT hr=S_OK;
  596. // Invlaid ARg
  597. Assert(pData && m_pAppend);
  598. // Call Internal Function
  599. CHECKHR(hr = HrAppendBuffer(m_pAppend, pData, (m_dwFlags & ICF_KILLNBSP)));
  600. exit:
  601. // Done
  602. return hr;
  603. }
  604. // --------------------------------------------------------------------------------
  605. // CInternetConverter::HrAppendBuffer
  606. // --------------------------------------------------------------------------------
  607. HRESULT CInternetConverter::HrAppendBuffer(LPCONVERTBUFFER pBuffer, LPBLOB pData, BOOL fKillNBSP)
  608. {
  609. // Locals
  610. HRESULT hr=S_OK;
  611. // Collapse Current Buffer
  612. if (pBuffer->i != 0)
  613. {
  614. // Move Memory
  615. MoveMemory(pBuffer->pb, pBuffer->pb + pBuffer->i, pBuffer->cb - pBuffer->i);
  616. // Decrease Size
  617. pBuffer->cb -= pBuffer->i;
  618. // Reset Start
  619. pBuffer->i = 0;
  620. }
  621. // Enought Space ?
  622. // Do I need to grow
  623. if (FGROWBUFFER(pBuffer, pData->cbSize))
  624. {
  625. // Grow the buffer
  626. CHECKHR(hr = HrGrowBuffer(pBuffer, pData->cbSize));
  627. }
  628. // Append the buffer...
  629. if (fKillNBSP)
  630. CopyMemoryRemoveNBSP(pBuffer->pb + pBuffer->cb, pData->pBlobData, pData->cbSize);
  631. // Otherwise, this is a simple copy
  632. else
  633. CopyMemory(pBuffer->pb + pBuffer->cb, pData->pBlobData, pData->cbSize);
  634. // Increment Amount of Data
  635. pBuffer->cb += pData->cbSize;
  636. exit:
  637. // Done
  638. return hr;
  639. }
  640. // --------------------------------------------------------------------------------
  641. // CInternetConverter::HrGrowBuffer
  642. // --------------------------------------------------------------------------------
  643. HRESULT CInternetConverter::HrGrowBuffer(LPCONVERTBUFFER pBuffer, ULONG cbAppend)
  644. {
  645. // Locals
  646. HRESULT hr=S_OK;
  647. ULONG cbGrow;
  648. // Better need a grow
  649. Assert(FGROWBUFFER(pBuffer, cbAppend));
  650. // Compute Grow By
  651. cbGrow = (cbAppend - (pBuffer->cbAlloc - pBuffer->cb)) + 256;
  652. // Realloc the buffer
  653. CHECKHR(hr = HrRealloc((LPVOID *)&pBuffer->pb, pBuffer->cbAlloc + cbGrow));
  654. // Adjust cbAlloc
  655. pBuffer->cbAlloc += cbGrow;
  656. exit:
  657. // Done
  658. return hr;
  659. }
  660. // --------------------------------------------------------------------------------
  661. // CInternetConverter::HrWriteConverted
  662. // --------------------------------------------------------------------------------
  663. HRESULT CInternetConverter::HrWriteConverted(IStream *pStream)
  664. {
  665. // Locals
  666. HRESULT hr=S_OK;
  667. // Anything to write
  668. if (m_pWrite->cb)
  669. {
  670. // Write the current block
  671. CHECKHR(hr = pStream->Write(m_pWrite->pb, m_pWrite->cb, NULL));
  672. // Nothing in m_rOut
  673. m_pWrite->cb = 0;
  674. }
  675. exit:
  676. // Done
  677. return hr;
  678. }
  679. // --------------------------------------------------------------------------------
  680. // CInternetConverter::HrWriteConverted
  681. // --------------------------------------------------------------------------------
  682. HRESULT CInternetConverter::HrWriteConverted(CInternetConverter *pConverter)
  683. {
  684. // Locals
  685. HRESULT hr=S_OK;
  686. BLOB rData;
  687. // Anything to write
  688. if (m_pWrite->cb)
  689. {
  690. // Setup Blob
  691. rData.pBlobData = m_pWrite->pb;
  692. rData.cbSize = m_pWrite->cb;
  693. // Write the current block
  694. CHECKHR(hr = pConverter->HrFillAppend(&rData));
  695. // Nothing in m_rOut
  696. m_pWrite->cb = 0;
  697. }
  698. exit:
  699. // Done
  700. return hr;
  701. }
  702. // --------------------------------------------------------------------------------
  703. // CInternetConverter::HrInternetEncode
  704. // --------------------------------------------------------------------------------
  705. HRESULT CInternetConverter::HrInternetEncode(BOOL fLastBuffer)
  706. {
  707. // Locals
  708. HRESULT hr=S_OK;
  709. HRESULT hrWarnings=S_OK;
  710. BLOB rData;
  711. // We Better be an encoder
  712. Assert(m_fEncoder);
  713. // Set Last Buffer
  714. m_fLastBuffer = fLastBuffer;
  715. // Text Wrapping ?
  716. if (ICF_WRAPTEXT & m_dwFlags)
  717. {
  718. // Wrap It: m_rIn -> m_rOut
  719. if (CP_UNICODE == m_cpiSource)
  720. CHECKHR(hr = HrWrapInternetTextW());
  721. else
  722. CHECKHR(hr = HrWrapInternetTextA());
  723. // Character Set Encoding: m_rOut -> m_rCset
  724. if (ICF_CODEPAGE & m_dwFlags)
  725. {
  726. // Charset Encode
  727. CHECKHR(hr = HrCodePageFromOutToCset());
  728. if ( S_OK != hr )
  729. hrWarnings = TrapError(hr);
  730. }
  731. }
  732. // Otherwise
  733. else
  734. {
  735. // Character Set Encoding: m_rCset -> m_rIn
  736. if (ICF_CODEPAGE & m_dwFlags)
  737. {
  738. // Charset Encode
  739. CHECKHR(hr = HrCodePageFromCsetToIn());
  740. if ( S_OK != hr )
  741. hrWarnings = TrapError(hr);
  742. }
  743. // Handle Conversion type
  744. switch(m_ietEncoding)
  745. {
  746. // Binary
  747. case IET_BINARY:
  748. case IET_7BIT:
  749. case IET_8BIT:
  750. // Better be at zero
  751. Assert(m_rIn.i == 0);
  752. // Initialize Blob to copy
  753. rData.pBlobData = m_rIn.pb;
  754. rData.cbSize = m_rIn.cb;
  755. // Append to outbound buffer
  756. CHECKHR(hr = HrAppendBuffer(&m_rOut, &rData, FALSE));
  757. // Increment offset
  758. m_rIn.i = m_rIn.cb = 0;
  759. break;
  760. // Quoted-Printable
  761. case IET_QP:
  762. CHECKHR(hr = HrEncodeQP());
  763. break;
  764. // Bas 64
  765. case IET_BASE64:
  766. CHECKHR(hr = HrEncode64());
  767. break;
  768. // UUENCODE
  769. case IET_UUENCODE:
  770. CHECKHR(hr = HrEncodeUU());
  771. break;
  772. // BINHEX
  773. case IET_BINHEX40:
  774. #ifdef NEVER
  775. CHECKHR(hr = HrEncodeBinhex());
  776. #endif // NEVER
  777. // IE v. 5.0:33596 HrEncodeBinhex returns E_FAIL if body size is too small
  778. // Binhex encoding doesn't currently work. I believe that it should work (or almost work)
  779. // if the header CBinhexEncoder::m_lpmacbinHdr is initialized properly. However, this
  780. // requires understanding the Mac file format and parsing the body stream contents into
  781. // data and resource forks.
  782. // - sethco 8/19/1998
  783. CHECKHR(hr = MIME_E_INVALID_ENCODINGTYPE);
  784. break;
  785. // Bummer
  786. default:
  787. AssertSz(FALSE, "MIME_E_INVALID_ENCODINGTYPE");
  788. break;
  789. }
  790. }
  791. exit:
  792. // If Last Buffer, we better be done
  793. Assert(m_fLastBuffer ? m_rIn.i == m_rIn.cb : TRUE);
  794. // Done
  795. return (hr == S_OK) ? hrWarnings : hr;
  796. }
  797. // --------------------------------------------------------------------------------
  798. // CInternetConverter::HrInternetDecode
  799. // --------------------------------------------------------------------------------
  800. HRESULT CInternetConverter::HrInternetDecode(BOOL fLastBuffer)
  801. {
  802. // Locals
  803. HRESULT hr=S_OK;
  804. HRESULT hrWarnings=S_OK;
  805. BLOB rData;
  806. // We Better not be an encoder
  807. Assert(!m_fEncoder);
  808. // Set Last Buffer
  809. m_fLastBuffer = fLastBuffer;
  810. // Handle Format
  811. switch(m_ietEncoding)
  812. {
  813. // Binary
  814. case IET_BINARY:
  815. case IET_7BIT:
  816. case IET_8BIT:
  817. // Better be at zero
  818. Assert(m_rIn.i == 0);
  819. // Initialize Blob to copy
  820. rData.pBlobData = m_rIn.pb;
  821. rData.cbSize = m_rIn.cb;
  822. // Append to outbound buffer
  823. CHECKHR(hr = HrAppendBuffer(&m_rOut, &rData, FALSE));
  824. // Increment offset
  825. m_rIn.i = m_rIn.cb = 0;
  826. break;
  827. // Quoted-Printable
  828. case IET_QP:
  829. CHECKHR(hr = HrDecodeQP());
  830. break;
  831. // Bas64
  832. case IET_BASE64:
  833. CHECKHR(hr = HrDecode64());
  834. break;
  835. // UUENCODE
  836. case IET_UUENCODE:
  837. CHECKHR(hr = HrDecodeUU());
  838. break;
  839. // BINHEX
  840. case IET_BINHEX40:
  841. CHECKHR(hr = HrDecodeBinHex());
  842. break;
  843. // Bummer
  844. default:
  845. AssertSz(FALSE, "MIME_E_INVALID_ENCODINGTYPE");
  846. break;
  847. }
  848. // Character Set Decoding ?
  849. if (ICF_CODEPAGE & m_dwFlags)
  850. {
  851. // Charset Decoder
  852. CHECKHR(hr = HrCodePageFromOutToCset());
  853. if ( S_OK != hr )
  854. hrWarnings = TrapError(hr);
  855. }
  856. exit:
  857. // If Last Buffer, we better be done
  858. Assert(m_fLastBuffer ? m_rIn.i == m_rIn.cb : TRUE);
  859. // Done
  860. return (hr == S_OK) ? hrWarnings : hr;
  861. }
  862. // --------------------------------------------------------------------------------
  863. // CInternetConverter::HrCodePageFromOutToCset
  864. // --------------------------------------------------------------------------------
  865. HRESULT CInternetConverter::HrCodePageFromOutToCset(void)
  866. {
  867. // Locals
  868. HRESULT hr=S_OK;
  869. HRESULT hrWarnings=S_OK;
  870. BLOB rData;
  871. BLOB rDecoded={0};
  872. ULONG cbRead;
  873. // Nothing to convert...
  874. if (0 == m_rOut.cb)
  875. return S_OK;
  876. // Setup Convert Blob
  877. rData.pBlobData = m_rOut.pb;
  878. rData.cbSize = m_rOut.cb;
  879. // Decode text from m_intformat
  880. hr = g_pInternat->ConvertBuffer(m_cpiSource, m_cpiDest, &rData, &rDecoded, &cbRead);
  881. if (SUCCEEDED(hr) )
  882. {
  883. // save HRESULT from charset conversion
  884. if ( S_OK != hr )
  885. hrWarnings = TrapError(hr);
  886. // Fill m_rIn...
  887. CHECKHR(hr = HrAppendBuffer(&m_rCset, &rDecoded, FALSE));
  888. }
  889. // Otherwise, just put m_rCset as the inbound buffer
  890. else
  891. {
  892. // SBAILEY: Raid-74506: MIMEOLE: error decoding text body in q-p encoded iso-2022-jp message
  893. // CHECKHR(hr = HrAppendBuffer(&m_rCset, &rData, FALSE));
  894. hr = S_OK;
  895. // We read all of it
  896. cbRead = rData.cbSize;
  897. }
  898. // Adjust m_rOut if cbRead != m_rOut.cb
  899. if (cbRead != m_rOut.cb)
  900. {
  901. // Move Memory
  902. MoveMemory(m_rOut.pb, m_rOut.pb + cbRead, m_rOut.cb - cbRead);
  903. }
  904. // Decrease Size
  905. Assert(cbRead <= m_rOut.cb);
  906. m_rOut.cb -= cbRead;
  907. exit:
  908. // Cleanup
  909. SafeMemFree(rDecoded.pBlobData);
  910. // Done
  911. return (hr == S_OK) ? hrWarnings : hr;
  912. }
  913. // --------------------------------------------------------------------------------
  914. // CInternetConverter::HrCodePageFromCsetToIn
  915. // --------------------------------------------------------------------------------
  916. HRESULT CInternetConverter::HrCodePageFromCsetToIn(void)
  917. {
  918. // Locals
  919. HRESULT hr=S_OK;
  920. HRESULT hrWarnings=S_OK;
  921. BLOB rData;
  922. BLOB rEncoded={0};
  923. ULONG cbRead;
  924. // Check State
  925. Assert(m_rCset.i == 0);
  926. // Nothing to convert
  927. if (0 == m_rCset.cb)
  928. return S_OK;
  929. // Setup Convert Blob
  930. rData.pBlobData = m_rCset.pb;
  931. rData.cbSize = m_rCset.cb;
  932. // Decode text from m_intformat
  933. hr = g_pInternat->ConvertBuffer(m_cpiSource, m_cpiDest, &rData, &rEncoded, &cbRead);
  934. if (SUCCEEDED(hr) )
  935. {
  936. // save HRESULT from charset conversion
  937. if ( S_OK != hr )
  938. hrWarnings = TrapError(hr);
  939. // Fill m_rIn...
  940. CHECKHR(hr = HrAppendBuffer(&m_rIn, &rEncoded, FALSE));
  941. }
  942. // Otherwise, just put m_rCset as the inbound buffer
  943. else
  944. {
  945. // SBAILEY: Raid-74506: MIMEOLE: error decoding text body in q-p encoded iso-2022-jp message
  946. // CHECKHR(hr = HrAppendBuffer(&m_rIn, &rData, FALSE));
  947. hr = S_OK;
  948. // Set Read
  949. cbRead = m_rCset.cb;
  950. }
  951. // Adjust m_rOut if cbRead != m_rOut.cb
  952. if (cbRead != m_rCset.cb)
  953. {
  954. // Move Memory
  955. MoveMemory(m_rCset.pb, m_rCset.pb + cbRead, m_rCset.cb - cbRead);
  956. }
  957. // Decrease Size
  958. Assert(cbRead <= m_rCset.cb);
  959. m_rCset.cb -= cbRead;
  960. m_rCset.i = 0;
  961. exit:
  962. // Cleanup
  963. SafeMemFree(rEncoded.pBlobData);
  964. // Done
  965. return (hr == S_OK) ? hrWarnings : hr;
  966. }
  967. // --------------------------------------------------------------------------------
  968. // CInternetConverter::HrEncode64
  969. // --------------------------------------------------------------------------------
  970. HRESULT CInternetConverter::HrEncode64(void)
  971. {
  972. // Locals
  973. HRESULT hr=S_OK;
  974. ULONG cbRead;
  975. ULONG i;
  976. UCHAR uch[3];
  977. UCHAR *pbuf;
  978. // Read lines and stuff dots
  979. while(1)
  980. {
  981. // Compute encode buffer length
  982. cbRead = min(CCHMAX_ENCODE64_IN, m_rIn.cb - m_rIn.i);
  983. // Should we encode this buffer ?
  984. if (0 == cbRead || (cbRead < CCHMAX_ENCODE64_IN && FALSE == m_fLastBuffer))
  985. goto exit;
  986. // Do I need to grow
  987. if (FGROWBUFFER(&m_rOut, CCHMAX_ENCODE64_OUT))
  988. {
  989. // Grow the buffer
  990. CHECKHR(hr = HrGrowBuffer(&m_rOut, CCHMAX_ENCODE64_OUT));
  991. }
  992. // Set Buffer Pointer
  993. pbuf = (m_rIn.pb + m_rIn.i);
  994. // Encodes 3 characters at a time
  995. for (i=0; i<cbRead; i+=3)
  996. {
  997. // Setup Buffer
  998. uch[0] = pbuf[i];
  999. uch[1] = (i+1 < cbRead) ? pbuf[i+1] : '\0';
  1000. uch[2] = (i+2 < cbRead) ? pbuf[i+2] : '\0';
  1001. // Encode first tow
  1002. ConvBuffAppend(g_rgchEncodeBase64[(uch[0] >> 2) & 0x3F]);
  1003. ConvBuffAppend(g_rgchEncodeBase64[(uch[0] << 4 | uch[1] >> 4) & 0x3F]);
  1004. // Encode Next
  1005. if (i+1 < cbRead)
  1006. ConvBuffAppend(g_rgchEncodeBase64[(uch[1] << 2 | uch[2] >> 6) & 0x3F]);
  1007. else
  1008. ConvBuffAppend('=');
  1009. // Encode Net
  1010. if (i+2 < cbRead)
  1011. ConvBuffAppend(g_rgchEncodeBase64[(uch[2] ) & 0x3F]);
  1012. else
  1013. ConvBuffAppend('=');
  1014. }
  1015. // Increment iIn
  1016. m_rIn.i += cbRead;
  1017. // Ends encoded line and writes to storage
  1018. ConvBuffAppend(chCR);
  1019. ConvBuffAppend(chLF);
  1020. }
  1021. exit:
  1022. // Done
  1023. return hr;
  1024. }
  1025. // --------------------------------------------------------------------------------
  1026. // CInternetConverter::HrDecode64
  1027. // --------------------------------------------------------------------------------
  1028. HRESULT CInternetConverter::HrDecode64(void)
  1029. {
  1030. // Locals
  1031. HRESULT hr=S_OK;
  1032. UCHAR uchThis;
  1033. ULONG i;
  1034. ULONG cPad=0;
  1035. ULONG cbRead=0;
  1036. ULONG cbLine;
  1037. BOOL fFound;
  1038. LPSTR pszLine;
  1039. // Read lines and stuff dots
  1040. while(1)
  1041. {
  1042. // Increment Index
  1043. m_rIn.i += cbRead;
  1044. // Get Next Line
  1045. pszLine = PszConvBuffGetNextLine(&cbLine, &cbRead, &fFound);
  1046. if (0 == cbRead || (FALSE == fFound && FALSE == m_fLastBuffer))
  1047. goto exit;
  1048. // Do I need to grow - decoded line will always be smaller than cbLine
  1049. if (FGROWBUFFER(&m_rOut, cbLine))
  1050. {
  1051. // Grow the buffer
  1052. CHECKHR(hr = HrGrowBuffer(&m_rOut, cbLine));
  1053. }
  1054. // Decodes characters in line buffer
  1055. for (i=0; i<cbLine; i++)
  1056. {
  1057. // Gets 4 legal Base64 characters, ignores if illegal
  1058. uchThis = pszLine[i];
  1059. // Decode It
  1060. m_uchConvert[m_cbConvert] = DECODE64(uchThis);
  1061. // Test for valid non-pad
  1062. if ((m_uchConvert[m_cbConvert] < 64) || ((uchThis == '=') && (m_cbConvert > 1)))
  1063. m_cbConvert++;
  1064. // Test for pad
  1065. if ((uchThis == '=') && (m_cbConvert > 1))
  1066. cPad++;
  1067. // Outputs when 4 legal Base64 characters are in the buffer
  1068. if (4 == m_cbConvert)
  1069. {
  1070. // Validate Buffer
  1071. Assert(m_rOut.cb + 4 <= m_rOut.cbAlloc);
  1072. // Convert
  1073. if (cPad < 3)
  1074. ConvBuffAppend((m_uchConvert[0] << 2 | m_uchConvert[1] >> 4));
  1075. if (cPad < 2)
  1076. ConvBuffAppend((m_uchConvert[1] << 4 | m_uchConvert[2] >> 2));
  1077. if (cPad < 1)
  1078. ConvBuffAppend((m_uchConvert[2] << 6 | m_uchConvert[3]));
  1079. // Reset
  1080. m_cbConvert = 0;
  1081. }
  1082. }
  1083. }
  1084. exit:
  1085. // Done
  1086. return hr;
  1087. }
  1088. // --------------------------------------------------------------------------------
  1089. // CInternetConverter::HrEncodeUU
  1090. // --------------------------------------------------------------------------------
  1091. HRESULT CInternetConverter::HrEncodeUU(void)
  1092. {
  1093. // Locals
  1094. HRESULT hr=S_OK;
  1095. ULONG cbRead, i;
  1096. UCHAR buf[CCHMAX_ENCODEUU_IN];
  1097. // Read lines and stuff dots
  1098. while(1)
  1099. {
  1100. // Compute encode buffer length
  1101. cbRead = min(CCHMAX_ENCODEUU_IN, m_rIn.cb - m_rIn.i);
  1102. if (0 == cbRead || (cbRead < CCHMAX_ENCODEUU_IN && FALSE == m_fLastBuffer))
  1103. goto exit;
  1104. // Copy the bytes
  1105. CopyMemory(buf, m_rIn.pb + m_rIn.i, cbRead);
  1106. // Zero the Rest
  1107. ZeroMemory(buf + cbRead, sizeof(buf) - cbRead);
  1108. // Do I need to grow
  1109. if (FGROWBUFFER(&m_rOut, CCHMAX_ENCODEUU_OUT))
  1110. {
  1111. // Grow the buffer
  1112. CHECKHR(hr = HrGrowBuffer(&m_rOut, CCHMAX_ENCODEUU_OUT));
  1113. }
  1114. // Encode Line length
  1115. ConvBuffAppend(UUENCODE((UCHAR)cbRead));
  1116. // Encodes 3 characters at a time
  1117. for (i=0; i<cbRead; i+=3)
  1118. {
  1119. ConvBuffAppend(UUENCODE((buf[i] >> 2)));
  1120. ConvBuffAppend(UUENCODE((buf[i] << 4) | (buf[i+1] >> 4)));
  1121. ConvBuffAppend(UUENCODE((buf[i+1] << 2) | (buf[i+2] >> 6)));
  1122. ConvBuffAppend(UUENCODE((buf[i+2])));
  1123. }
  1124. // Increment i
  1125. m_rIn.i += cbRead;
  1126. // Ends encoded line and writes to storage
  1127. ConvBuffAppend(chCR);
  1128. ConvBuffAppend(chLF);
  1129. }
  1130. exit:
  1131. // If last buffer and we can't read anymore
  1132. if (TRUE == m_fLastBuffer && FALSE == FConvBuffCanRead(m_rIn))
  1133. {
  1134. // RAID-21179: ZeroLength uuencoded attachments m_rOut may not have been allocated
  1135. // Do I need to grow
  1136. if (FGROWBUFFER(&m_rOut, CCHMAX_ENCODEUU_OUT))
  1137. {
  1138. // Grow the buffer
  1139. CHECKHR(hr = HrGrowBuffer(&m_rOut, CCHMAX_ENCODEUU_OUT));
  1140. }
  1141. // Better have space
  1142. Assert(m_rOut.cb + 3 < m_rOut.cbAlloc);
  1143. // End
  1144. ConvBuffAppend(UUENCODE(0));
  1145. ConvBuffAppend(chCR);
  1146. ConvBuffAppend(chLF);
  1147. }
  1148. // Done
  1149. return hr;
  1150. }
  1151. // --------------------------------------------------------------------------------
  1152. // CInternetConverter::FUUEncodeThrowAway
  1153. // --------------------------------------------------------------------------------
  1154. BOOL CInternetConverter::FUUEncodeThrowAway(LPSTR pszLine, ULONG cbLine, ULONG *pcbActual, ULONG *pcbLine)
  1155. {
  1156. // Locals
  1157. CHAR ch;
  1158. ULONG cchOffset, cbEncoded, cbTolerance=0, cbExpected;
  1159. // RAID-25953: "BEGIN --- CUT HERE --- Cut Here --- cut here ---" - WinVN post
  1160. // partial messages that have the following line at the beginning of
  1161. // each partial. B = 66 and the length of this line is 48, so the following
  1162. // code thinks that this line is a valid UUENCODED line, so, to fix this,
  1163. // we will throw out all lines that start with BEGIN since this is not valid
  1164. // to be in uuencode.
  1165. if (StrCmpNI("BEGIN", pszLine, 5) == 0)
  1166. return TRUE;
  1167. // END Line
  1168. else if (StrCmpNI("END", pszLine, 3) == 0)
  1169. return TRUE;
  1170. // Checks line length
  1171. ch = *pszLine;
  1172. *pcbLine = cbEncoded = UUDECODE(ch);
  1173. // Comput tolerance and offset for non-conforming even line lengths
  1174. cchOffset = (cbEncoded % 3);
  1175. if (cchOffset != 0)
  1176. {
  1177. cchOffset++;
  1178. cbTolerance = 4 - cchOffset;
  1179. }
  1180. // Compute expected line length
  1181. cbExpected = 4 * (cbEncoded / 3) + cchOffset;
  1182. // Always check for '-'
  1183. if (cbLine < cbExpected)
  1184. return TRUE;
  1185. // Wack off trailing spaces
  1186. while(pszLine[cbLine-1] == ' ' && cbLine > 0 && cbLine != cbExpected)
  1187. --cbLine;
  1188. // Checksum character and encoders which include the count char in the line count
  1189. if (cbExpected != cbLine && cbExpected + cbTolerance != cbLine &&
  1190. cbExpected + 1 != cbLine && cbExpected + cbTolerance + 1 != cbLine &&
  1191. cbExpected - 1 != cbLine && cbExpected + cbTolerance - 1 != cbLine)
  1192. return TRUE;
  1193. // Set actual line length
  1194. *pcbActual = cbLine;
  1195. // Done
  1196. return FALSE;
  1197. }
  1198. // --------------------------------------------------------------------------------
  1199. // CInternetConverter::HrDecodeUU
  1200. // --------------------------------------------------------------------------------
  1201. HRESULT CInternetConverter::HrDecodeUU(void)
  1202. {
  1203. // Locals
  1204. HRESULT hr=S_OK;
  1205. ULONG cbLine;
  1206. LPSTR pszLine;
  1207. ULONG cbRead=0;
  1208. ULONG cbLineLength;
  1209. BOOL fFound;
  1210. ULONG cbConvert;
  1211. ULONG cbScan;
  1212. ULONG i;
  1213. UCHAR uchConvert[4];
  1214. UCHAR uchThis;
  1215. // Read lines and stuff dots
  1216. while(1)
  1217. {
  1218. // Increment Index
  1219. m_rIn.i += cbRead;
  1220. // Get Next Line
  1221. pszLine = PszConvBuffGetNextLine(&cbLine, &cbRead, &fFound);
  1222. if (0 == cbRead || (FALSE == fFound && FALSE == m_fLastBuffer))
  1223. goto exit;
  1224. // UUENCODE ThrowAway
  1225. if (FUUEncodeThrowAway(pszLine, cbLine, &cbLine, &cbLineLength))
  1226. continue;
  1227. // Do I need to grow
  1228. if (FGROWBUFFER(&m_rOut, cbLineLength + 20))
  1229. {
  1230. // Grow the buffer
  1231. CHECKHR(hr = HrGrowBuffer(&m_rOut, cbLineLength + 20));
  1232. }
  1233. // Decodes 4 characters at a time
  1234. for (cbConvert=0, cbScan=0, i=1; cbScan < cbLineLength; i++)
  1235. {
  1236. // Gets 4 characters, pads with blank if necessary
  1237. uchThis = (i < cbLine) ? pszLine[i] : ' ';
  1238. // Decode
  1239. uchConvert[cbConvert++] = UUDECODE(uchThis);
  1240. // Outputs decoded characters
  1241. if (cbConvert == 4)
  1242. {
  1243. // Covnert
  1244. if (cbScan++ < cbLineLength)
  1245. ConvBuffAppend((uchConvert[0] << 2) | (uchConvert[1] >> 4));
  1246. if (cbScan++ < cbLineLength)
  1247. ConvBuffAppend((uchConvert[1] << 4) | (uchConvert[2] >> 2));
  1248. if (cbScan++ < cbLineLength)
  1249. ConvBuffAppend((uchConvert[2] << 6) | (uchConvert[3]));
  1250. // Reset
  1251. cbConvert = 0;
  1252. }
  1253. }
  1254. }
  1255. exit:
  1256. // Done
  1257. return hr;
  1258. }
  1259. // --------------------------------------------------------------------------------
  1260. // CInternetConverter::HrEncodeQP
  1261. // --------------------------------------------------------------------------------
  1262. HRESULT CInternetConverter::HrEncodeQP(void)
  1263. {
  1264. // Locals
  1265. HRESULT hr=S_OK;
  1266. UCHAR uchThis;
  1267. ULONG cbLine=0;
  1268. ULONG iCurrent;
  1269. LONG iLastWhite=-1;
  1270. LONG iLineWhite=-1;
  1271. UCHAR szLine[CCHMAX_QPLINE+30];
  1272. // Set iCurrent
  1273. iCurrent = m_rIn.i;
  1274. // Read lines and stuff dots
  1275. while (iCurrent < m_rIn.cb)
  1276. {
  1277. // Gets the next character
  1278. uchThis = m_rIn.pb[iCurrent];
  1279. // End of line...
  1280. if (chLF == uchThis || cbLine > CCHMAX_QPLINE)
  1281. {
  1282. // Soft Line break
  1283. if (chLF != uchThis)
  1284. {
  1285. // Lets back track to last white
  1286. if (iLastWhite != -1)
  1287. {
  1288. cbLine = iLineWhite + 1;
  1289. iCurrent = iLastWhite + 1;
  1290. }
  1291. // Hex encode the 8bit octet
  1292. Assert(cbLine + 3 <= sizeof(szLine));
  1293. szLine[cbLine++] = '=';
  1294. szLine[cbLine++] = chCR;
  1295. szLine[cbLine++] = chLF;
  1296. }
  1297. // Otherwise, we may need to encode the last space
  1298. else
  1299. {
  1300. // Encode Straggling '\n'
  1301. if (chCR != m_uchPrev)
  1302. {
  1303. Assert(cbLine + 4 <= sizeof(szLine));
  1304. szLine[cbLine++] = '=';
  1305. szLine[cbLine++] = g_rgchHex[uchThis >> 4];
  1306. szLine[cbLine++] = g_rgchHex[uchThis & 0x0F];
  1307. szLine[cbLine++] = '=';
  1308. }
  1309. // Detect preceding whitespace ...
  1310. if (cbLine && (' ' == szLine[cbLine - 1] || '\t' == szLine[cbLine - 1]))
  1311. {
  1312. // Hex encode the 8bit octet
  1313. UCHAR chWhite = szLine[cbLine - 1];
  1314. cbLine--;
  1315. Assert(cbLine + 3 <= sizeof(szLine));
  1316. szLine[cbLine++] = '=';
  1317. szLine[cbLine++] = g_rgchHex[chWhite >> 4];
  1318. szLine[cbLine++] = g_rgchHex[chWhite & 0x0F];
  1319. }
  1320. // Otherwise, hard line break
  1321. Assert(cbLine + 2 <= sizeof(szLine));
  1322. szLine[cbLine++] = chCR;
  1323. szLine[cbLine++] = chLF;
  1324. iCurrent++;
  1325. }
  1326. // Copy the line
  1327. CHECKHR(hr = HrConvBuffAppendBlock(szLine, cbLine));
  1328. // Reset
  1329. iLastWhite = -1;
  1330. iLineWhite = -1;
  1331. cbLine = 0;
  1332. *szLine = '\0';
  1333. // We processed this buffer
  1334. m_rIn.i = iCurrent;
  1335. }
  1336. // Encode empty '\r'
  1337. else if (chCR == uchThis)
  1338. {
  1339. // Overflow detection
  1340. if (iCurrent + 1 < m_rIn.cb && m_rIn.pb[iCurrent + 1] != chLF || iCurrent + 1 >= m_rIn.cb)
  1341. {
  1342. Assert(cbLine + 3 <= sizeof(szLine));
  1343. szLine[cbLine++] = '=';
  1344. szLine[cbLine++] = g_rgchHex[uchThis >> 4];
  1345. szLine[cbLine++] = g_rgchHex[uchThis & 0x0F];
  1346. }
  1347. // Next Character
  1348. iCurrent++;
  1349. }
  1350. // Rule #1: Replace 8-bit and equal signs
  1351. else if (('\t' != uchThis) && (uchThis < 32 || uchThis == 61 || uchThis > 126 || '=' == uchThis))
  1352. {
  1353. // Hex encode the 8bit octet
  1354. Assert(chLF != uchThis);
  1355. Assert(cbLine + 3 <= sizeof(szLine));
  1356. szLine[cbLine++] = '=';
  1357. szLine[cbLine++] = g_rgchHex[uchThis >> 4];
  1358. szLine[cbLine++] = g_rgchHex[uchThis & 0x0F];
  1359. iCurrent++;
  1360. }
  1361. // Otherwise, write the character
  1362. else
  1363. {
  1364. // Save position of last white space
  1365. if (' ' == uchThis || '\t' == uchThis)
  1366. {
  1367. iLastWhite = iCurrent;
  1368. iLineWhite = cbLine;
  1369. }
  1370. // Rule #2: Printable literals
  1371. Assert(cbLine + 1 <= sizeof(szLine));
  1372. szLine[cbLine++] = uchThis;
  1373. iCurrent++;
  1374. }
  1375. // Save Previous Char
  1376. m_uchPrev = uchThis;
  1377. }
  1378. // Last line
  1379. if (cbLine && m_fLastBuffer)
  1380. {
  1381. // Append the Line
  1382. CHECKHR(hr = HrConvBuffAppendBlock(szLine, cbLine));
  1383. // Set i
  1384. m_rIn.i = m_rIn.cb;
  1385. }
  1386. exit:
  1387. // Done
  1388. return hr;
  1389. }
  1390. // --------------------------------------------------------------------------------
  1391. // CInternetConverter::HrDecodeQP
  1392. // --------------------------------------------------------------------------------
  1393. HRESULT CInternetConverter::HrDecodeQP(void)
  1394. {
  1395. // Locals
  1396. HRESULT hr=S_OK;
  1397. UCHAR uchThis;
  1398. UCHAR uchNext1;
  1399. UCHAR uchNext2;
  1400. UCHAR uch1;
  1401. UCHAR uch2;
  1402. // Read lines and stuff dots
  1403. while (FConvBuffCanRead(m_rIn))
  1404. {
  1405. // bug #35230 - display trash in trident
  1406. // Can I read 2 more characters
  1407. if (FALSE == m_fLastBuffer && m_rIn.i + 2 >= m_rIn.cb)
  1408. break;
  1409. // Do I need to grow
  1410. if (FGROWBUFFER(&m_rOut, 3))
  1411. {
  1412. // Grow the buffer
  1413. CHECKHR(hr = HrGrowBuffer(&m_rOut, 3));
  1414. }
  1415. // Gets the next character
  1416. uchThis = m_rIn.pb[m_rIn.i];
  1417. // Determine next couple of characers for end of line detection...
  1418. uchNext1 = (m_rIn.i + 1 < m_rIn.cb) ? m_rIn.pb[m_rIn.i + 1] : '\0';
  1419. uchNext2 = (m_rIn.i + 2 < m_rIn.cb) ? m_rIn.pb[m_rIn.i + 2] : '\0';
  1420. // Dont break on \r\n
  1421. if (chCR == uchNext1 && chLF == uchNext2 && m_rIn.i + 3 >= m_rIn.cb)
  1422. {
  1423. // If last buffer, then save characters
  1424. if (m_fLastBuffer)
  1425. {
  1426. // If not a soft line break
  1427. if ('=' != uchThis)
  1428. {
  1429. ConvBuffAppend(uchThis);
  1430. ConvBuffAppend(chCR);
  1431. ConvBuffAppend(chLF);
  1432. }
  1433. // Done
  1434. m_rIn.i += 3;
  1435. }
  1436. // Done
  1437. goto exit;
  1438. }
  1439. // If not end of line...
  1440. if ('=' == uchThis)
  1441. {
  1442. // Soft NL
  1443. if (chCR == uchNext1 && chLF == uchNext2)
  1444. {
  1445. // Step over =\r\n
  1446. m_rIn.i += 3;
  1447. }
  1448. // If not end of line...
  1449. else if (m_rIn.i + 2 < m_rIn.cb)
  1450. {
  1451. // Step Over Equal Sign
  1452. m_rIn.i++;
  1453. // Convert Hex Characters
  1454. uch1 = ChConvertFromHex(m_rIn.pb[m_rIn.i++]);
  1455. uch2 = ChConvertFromHex(m_rIn.pb[m_rIn.i++]);
  1456. // Store Hex characters
  1457. if (uch1 == 255 || uch2 == 255)
  1458. ConvBuffAppend('=');
  1459. else
  1460. ConvBuffAppend((uch1 << 4) | uch2);
  1461. }
  1462. else
  1463. {
  1464. // Last Buffer ?
  1465. ConvBuffAppend(uchThis);
  1466. m_rIn.i++;
  1467. }
  1468. }
  1469. // Otherwise store the character
  1470. else if (chCR == uchThis && chLF == uchNext1)
  1471. {
  1472. // Stuff CRLF
  1473. ConvBuffAppend(chCR);
  1474. ConvBuffAppend(chLF);
  1475. // Increment i
  1476. m_rIn.i += 2;
  1477. }
  1478. // Otherwise, store the character
  1479. else
  1480. {
  1481. ConvBuffAppend(uchThis);
  1482. m_rIn.i++;
  1483. }
  1484. // Set Previous
  1485. m_uchPrev = uchThis;
  1486. }
  1487. exit:
  1488. // Done
  1489. return hr;
  1490. }
  1491. // --------------------------------------------------------------------------------
  1492. // CInternetConverter::HrWrapInternetTextA
  1493. // --------------------------------------------------------------------------------
  1494. HRESULT CInternetConverter::HrWrapInternetTextA(void)
  1495. {
  1496. // Locals
  1497. HRESULT hr=S_OK;
  1498. LONG cchLine;
  1499. LONG cchSkip;
  1500. // Read lines and stuff dots
  1501. while(FConvBuffCanRead(m_rIn))
  1502. {
  1503. // Not enough to encode a full line and not the last buffer
  1504. if ((FALSE == m_fLastBuffer) && ((LONG)(m_rIn.cb - m_rIn.i) < m_cchMaxLine))
  1505. goto exit;
  1506. // Call LineBreaker
  1507. if (*((CHAR*)(m_rIn.pb + m_rIn.i)) == '\0')
  1508. {
  1509. // This is to prevent the endless loop in case of malformed data stream
  1510. hr = TrapError(MIME_E_BAD_TEXT_DATA);
  1511. goto exit;
  1512. }
  1513. CHECKHR(hr = m_pLineBreak->BreakLineA(m_lcid, m_cpiSource, (LPCSTR)(m_rIn.pb + m_rIn.i), (m_rIn.cb - m_rIn.i), m_cchMaxLine, &cchLine, &cchSkip));
  1514. // Do I need to grow
  1515. if (FGROWBUFFER(&m_rOut, cchLine + 5))
  1516. {
  1517. // Grow the buffer
  1518. CHECKHR(hr = HrGrowBuffer(&m_rOut, cchLine + 5));
  1519. }
  1520. // Have some data ?
  1521. if (cchLine)
  1522. {
  1523. // Write the line
  1524. CHECKHR(hr = HrConvBuffAppendBlock(m_rIn.pb + m_rIn.i, cchLine));
  1525. }
  1526. // Write CRLF
  1527. Assert(m_rOut.cb + 2 < m_rOut.cbAlloc);
  1528. ConvBuffAppend(chCR);
  1529. ConvBuffAppend(chLF);
  1530. // Increment iText
  1531. m_rIn.i += (cchLine + cchSkip);
  1532. }
  1533. exit:
  1534. // Done
  1535. return hr;
  1536. }
  1537. HRESULT CInternetConverter::_GetEndOfURL(IN LPCWSTR pszLine, DWORD cchSize, DWORD * pdwMax)
  1538. {
  1539. HRESULT hr = S_OK;
  1540. DWORD cchCurrent = 0;
  1541. for (cchCurrent = 0; cchCurrent < cchSize; cchCurrent++)
  1542. {
  1543. if ((L' ' == pszLine[cchCurrent]) ||
  1544. (L'\r' == pszLine[cchCurrent]))
  1545. {
  1546. (*pdwMax) = (cchCurrent + 2);
  1547. break;
  1548. }
  1549. }
  1550. return hr;
  1551. }
  1552. HRESULT CInternetConverter::_FixLineBreakingProblems(
  1553. IN LCID locale, IN const WCHAR* pszSrc,
  1554. IN long cchSrc, IN long cMaxColumns,
  1555. OUT long* pcchLine, OUT long* pcchSkip,
  1556. BOOL * pfDoURLFix)
  1557. {
  1558. HRESULT hr = S_OK;
  1559. // There was a bug where a signature marker, which is '-- '
  1560. // (dash, dash, space, end-of-line) would get stripped out.
  1561. // This happens in ILineBreak::BreakLineW(). It will strip off
  1562. // the extra space thinking it is just extra white space.
  1563. if ((3 <= cchSrc) &&
  1564. (m_rIn.cb >= 10) &&
  1565. (2 <= *pcchLine) &&
  1566. (1 <= *pcchSkip) &&
  1567. (L'-' == pszSrc[*pcchLine - 2]) &&
  1568. (L'-' == pszSrc[*pcchLine - 1]) &&
  1569. (L' ' == pszSrc[*pcchLine - 0]))
  1570. {
  1571. (*pcchLine)++;
  1572. (*pcchSkip)--;
  1573. // DebugTrace("MimeOLE - Sig Delimiter: Preserved.\n");
  1574. }
  1575. // We do not want to wrap if that causes a break in URLs.
  1576. // This is bad because when the receiver's newsgroup reader
  1577. // turns the URL into a hyperlink, it will no longer point
  1578. // to the right location because part of the URL is missing.
  1579. // This happens often with urls that contain '=' or '/', like:
  1580. // http://www.amazon.com/exec/obidos/ASIN/B0000633EM/qid=1027792220/sr=8-3/ref=sr_8_3/104-5930498-2421552
  1581. // http://www.amazon.com/exec/obidos/tg/stores/detail/-/electronics/B0000633EM/reviews/ref=e_wlt1_de_a_er/104-5930498-2421552#
  1582. if ((5 <= *pcchLine) &&
  1583. (cchSrc > *pcchLine) && // Make sure this isn't the end of the line.
  1584. (L' ' != pszSrc[*pcchLine]) &&
  1585. (L'\r' != pszSrc[*pcchLine])) // We worry if the char after this break isn't a space.
  1586. {
  1587. WCHAR szUrl[50]; // We only need the first part.
  1588. WCHAR szScheme[30];
  1589. DWORD cchScheme = ARRAYSIZE(szScheme);
  1590. StrCpyNW(szUrl, pszSrc, (int) min(ARRAYSIZE(szUrl), *pcchLine));
  1591. HRESULT hrUrlPart = UrlGetPartW(szUrl, szScheme, &cchScheme, URL_PART_SCHEME, 0);
  1592. if ((S_OK == hrUrlPart) &&
  1593. szScheme[0] &&
  1594. (!StrCmpIW(szScheme, L"http") ||
  1595. !StrCmpIW(szScheme, L"https") ||
  1596. !StrCmpIW(szScheme, L"mailto") ||
  1597. !StrCmpIW(szScheme, L"file") ||
  1598. !StrCmpIW(szScheme, L"news") ||
  1599. !StrCmpIW(szScheme, L"nntp") ||
  1600. !StrCmpIW(szScheme, L"telnet") ||
  1601. !StrCmpIW(szScheme, L"ftp")))
  1602. {
  1603. *pfDoURLFix = TRUE;
  1604. }
  1605. }
  1606. return hr;
  1607. }
  1608. // --------------------------------------------------------------------------------
  1609. // CInternetConverter::HrWrapInternetTextW
  1610. // --------------------------------------------------------------------------------
  1611. HRESULT CInternetConverter::HrWrapInternetTextW(void)
  1612. {
  1613. // Locals
  1614. HRESULT hr=S_OK;
  1615. LONG cchLine;
  1616. LONG cchSkip;
  1617. LPCWSTR pszNext = NULL;
  1618. BOOL fFollowingURLFix = FALSE;
  1619. // Invalid State
  1620. Assert(m_pLineBreak);
  1621. // Read lines and stuff dots
  1622. while(FConvBuffCanRead(m_rIn))
  1623. {
  1624. DWORD cchCurrentLineLen = ((m_rIn.cb - m_rIn.i) / sizeof(WCHAR));
  1625. pszNext = (LPCWSTR)(m_rIn.pb + m_rIn.i);
  1626. // Not enough to encode a full line and not the last buffer
  1627. if ((FALSE == m_fLastBuffer) && ((LONG)cchCurrentLineLen < m_cchMaxLine))
  1628. goto exit;
  1629. // Call LineBreaker
  1630. if (pszNext[0] == L'\0')
  1631. {
  1632. // This is to prevent the endless loop in case of malformed data stream
  1633. hr = TrapError(MIME_E_BAD_TEXT_DATA);
  1634. goto exit;
  1635. }
  1636. DWORD cchMax = m_cchMaxLine;
  1637. if (fFollowingURLFix)
  1638. {
  1639. _GetEndOfURL(pszNext, cchCurrentLineLen, &cchMax);
  1640. fFollowingURLFix = FALSE;
  1641. }
  1642. CHECKHR(hr = m_pLineBreak->BreakLineW(m_lcid, pszNext, cchCurrentLineLen, cchMax, &cchLine, &cchSkip));
  1643. BOOL fDoURLFix = FALSE;
  1644. _FixLineBreakingProblems(m_lcid, pszNext, cchCurrentLineLen, m_cchMaxLine, &cchLine, &cchSkip, &fDoURLFix);
  1645. // Do I need to grow
  1646. if (FGROWBUFFER(&m_rOut, ((cchLine + 5) * sizeof(WCHAR))))
  1647. {
  1648. // Grow the buffer
  1649. CHECKHR(hr = HrGrowBuffer(&m_rOut, ((cchLine + 5) * sizeof(WCHAR))));
  1650. }
  1651. // Have some data
  1652. if (cchLine)
  1653. {
  1654. // Write the line
  1655. CHECKHR(hr = HrConvBuffAppendBlock((BYTE *) pszNext, (cchLine * sizeof(WCHAR))));
  1656. }
  1657. // Write CRLF
  1658. Assert(m_rOut.cb + (2 * sizeof(WCHAR)) < m_rOut.cbAlloc);
  1659. if (!fDoURLFix)
  1660. {
  1661. ConvBuffAppendW(wchCR);
  1662. ConvBuffAppendW(wchLF);
  1663. }
  1664. else
  1665. {
  1666. fFollowingURLFix = TRUE;
  1667. }
  1668. // Increment iText
  1669. m_rIn.i += ((cchLine + cchSkip) * sizeof(WCHAR));
  1670. }
  1671. exit:
  1672. // Done
  1673. return hr;
  1674. }
  1675. // --------------------------------------------------------------------------------
  1676. // CInternetConverter::HrEncodeDecodeBinhex
  1677. // --------------------------------------------------------------------------------
  1678. const CHAR szBINHEXSTART[] = "(This file must be converted with BinHex";
  1679. const ULONG cbBINHEXSTART = ARRAYSIZE(szBINHEXSTART)-1;
  1680. HRESULT CInternetConverter::HrEncodeBinhex(void)
  1681. {
  1682. // Locals
  1683. HRESULT hr=S_OK;
  1684. HRESULT hrError;
  1685. ULONG cbLeft;
  1686. ULONG cbRead;
  1687. ULONG cbMaxEncode;
  1688. ULONG cbWrite;
  1689. // cbLeft
  1690. cbLeft = m_rIn.cb - m_rIn.i;
  1691. // cbMaxEncode - this should always insure enough room
  1692. cbMaxEncode = cbLeft * 2;
  1693. // Do I need to grow
  1694. if (FGROWBUFFER(&m_rOut, cbMaxEncode))
  1695. {
  1696. // Grow the buffer
  1697. CHECKHR(hr = HrGrowBuffer(&m_rOut, cbMaxEncode));
  1698. }
  1699. // Set max amount to read
  1700. cbRead = cbLeft;
  1701. // Set max amount to write
  1702. cbWrite = cbLeft;
  1703. // We better want to read some
  1704. Assert(cbRead && cbWrite);
  1705. // Encode/Decode some data
  1706. if (m_fEncoder)
  1707. {
  1708. // Encode
  1709. if (ERROR_SUCCESS != m_pBinhexEncode->HrEmit(m_rIn.pb + m_rIn.i, &cbRead, m_rOut.pb + m_rOut.cb, &cbWrite))
  1710. {
  1711. hr = TrapError(E_FAIL);
  1712. goto exit;
  1713. }
  1714. }
  1715. // Increment Amount Read
  1716. m_rIn.i += cbRead;
  1717. // Increment Amount Wrote
  1718. m_rOut.cb += cbWrite;
  1719. exit:
  1720. // Done
  1721. return hr;
  1722. }
  1723. // --------------------------------------------------------------------------------
  1724. // CInternetConverter::HrBinhexThrowAway
  1725. // --------------------------------------------------------------------------------
  1726. HRESULT CInternetConverter::HrBinhexDecodeBuffAppend(UCHAR uchIn, ULONG cchIn, ULONG cchLeft, ULONG * pcbProduced)
  1727. {
  1728. HRESULT hr = S_FALSE;
  1729. ULONG cbPad = 0;
  1730. LPBYTE pbBinHex = NULL;
  1731. if (m_eBinHexStateDec == sHDRFILESIZE)
  1732. {
  1733. // First incoming character is always the size of the stream.
  1734. Assert(cchIn == 1);
  1735. if ((uchIn < 1) || (uchIn > 63))
  1736. {
  1737. hr = E_FAIL; // ERROR_INVALID_DATA
  1738. m_eBinHexStateDec = sENDED;
  1739. goto exit;
  1740. }
  1741. // Allocate the binhex header
  1742. if (FGROWBUFFER(&m_rBinhexHeader, cbMinBinHexHeader + uchIn))
  1743. {
  1744. // Grow the buffer
  1745. CHECKHR(hr = HrGrowBuffer(&m_rBinhexHeader, cbMinBinHexHeader + uchIn));
  1746. }
  1747. // Mark how many characters are left to process
  1748. m_cbToProcess = cbMinBinHexHeader + uchIn;
  1749. // Switch to filling the header sHEADER
  1750. m_prBinhexOutput = &m_rBinhexHeader;
  1751. m_eBinHexStateDec = sHEADER;
  1752. }
  1753. if (1 == cchIn)
  1754. {
  1755. m_prBinhexOutput->pb[m_prBinhexOutput->cb++] = uchIn;
  1756. }
  1757. else
  1758. {
  1759. // Check output buffer for space
  1760. if (FGROWBUFFER(m_prBinhexOutput, cchLeft + cchIn))
  1761. {
  1762. // Grow the buffer
  1763. CHECKHR(hr = HrGrowBuffer(m_prBinhexOutput, cchLeft + cchIn));
  1764. }
  1765. // Fill output buffer
  1766. FillMemory((m_prBinhexOutput->pb + m_prBinhexOutput->cb), cchIn, uchIn);
  1767. m_prBinhexOutput->cb += cchIn;
  1768. }
  1769. // Are we done processing this fork?
  1770. if (m_cbToProcess <= (LONG) cchIn)
  1771. {
  1772. switch (m_eBinHexStateDec)
  1773. {
  1774. case sHEADER:
  1775. // Verify that we have the correct CRC
  1776. m_wCRC = 0;
  1777. BinHexCalcCRC16((LPBYTE) m_rBinhexHeader.pb, cbMinBinHexHeader + *(m_rBinhexHeader.pb) - 2, &(m_wCRC));
  1778. BinHexCalcCRC16((LPBYTE) &wBinHexZero, sizeof(wBinHexZero), &(m_wCRC));
  1779. if ( HIBYTE( m_wCRC ) != m_rBinhexHeader.pb[cbMinBinHexHeader + *(m_rBinhexHeader.pb) - 2]
  1780. || LOBYTE( m_wCRC ) != m_rBinhexHeader.pb[cbMinBinHexHeader + *(m_rBinhexHeader.pb) - 1] )
  1781. {
  1782. hr = E_FAIL; // ERROR_INVALID_DATA
  1783. goto exit;
  1784. }
  1785. m_wCRC = 0;
  1786. *pcbProduced = 0;
  1787. // Switch to using the correct buffer
  1788. m_prBinhexOutput = &m_rOut;
  1789. cchIn -= m_cbToProcess;
  1790. // Save off the size of the two forks
  1791. pbBinHex = m_rBinhexHeader.pb + m_rBinhexHeader.pb[0] + cbMinBinHexHeader - 10;
  1792. m_cbDataFork = NATIVE_LONG_FROM_BIG(pbBinHex);
  1793. m_cbResourceFork =NATIVE_LONG_FROM_BIG(pbBinHex + 4);
  1794. if (FALSE == m_fDataForkOnly)
  1795. {
  1796. // Copy extra data into new buffer
  1797. if (FGROWBUFFER(m_prBinhexOutput, cchLeft + cchIn + sizeof(MACBINARY)))
  1798. {
  1799. // Grow the buffer
  1800. CHECKHR(hr = HrGrowBuffer(m_prBinhexOutput, cchLeft + cchIn + sizeof(MACBINARY)));
  1801. }
  1802. // Write out the MacBinary header
  1803. CHECKHR(hr = HrCreateMacBinaryHeader(&m_rBinhexHeader, m_prBinhexOutput));
  1804. }
  1805. if (m_cbDataFork > 0)
  1806. {
  1807. // Fill output buffer
  1808. FillMemory((m_prBinhexOutput->pb + m_prBinhexOutput->cb), cchIn, uchIn);
  1809. m_prBinhexOutput->cb += cchIn;
  1810. // delete binhex header buffer
  1811. SafeMemFree(m_rBinhexHeader.pb);
  1812. ZeroMemory(&m_rBinhexHeader, sizeof(CONVERTBUFFER));
  1813. m_cbToProcess = m_cbDataFork;
  1814. // Switch to doing the data fork.
  1815. m_eBinHexStateDec = sDATA;
  1816. }
  1817. else
  1818. {
  1819. BinHexCalcCRC16((LPBYTE) &wBinHexZero, sizeof(wBinHexZero), &(m_wCRC));
  1820. // Save off the CRC until we can get the CRC from the fork.
  1821. m_wCRCForFork = m_wCRC;
  1822. m_prBinhexOutput = &m_rBinhexHeader;
  1823. // Remove the HEADER from the buffer
  1824. FillMemory(m_prBinhexOutput->pb, cchIn, uchIn);
  1825. m_prBinhexOutput->cb = cchIn;
  1826. // Switch to filling the data CRC
  1827. m_cbToProcess = 2;
  1828. m_eBinHexStateDec = sDATACRC;
  1829. }
  1830. break;
  1831. case sDATA:
  1832. // Verify that we have the correct CRC
  1833. BinHexCalcCRC16((LPBYTE) m_prBinhexOutput->pb + m_prBinhexOutput->cb - cchIn - *pcbProduced,
  1834. m_cbToProcess + *pcbProduced, &(m_wCRC));
  1835. BinHexCalcCRC16((LPBYTE) &wBinHexZero, sizeof(wBinHexZero), &(m_wCRC));
  1836. // Save off the CRC until we can get the CRC from the fork.
  1837. m_wCRCForFork = m_wCRC;
  1838. m_wCRC = 0;
  1839. *pcbProduced = 0;
  1840. cchIn -= m_cbToProcess;
  1841. // Switch to the proper buffer for CRC calculations
  1842. if (FGROWBUFFER(&m_rBinhexHeader, cchLeft + cchIn))
  1843. {
  1844. // Grow the buffer
  1845. CHECKHR(hr = HrGrowBuffer(&m_rBinhexHeader, cchLeft + cchIn));
  1846. }
  1847. // Move any current bytes so we don't overwrite anything
  1848. CopyMemory((m_rBinhexHeader.pb + m_rBinhexHeader.cb),
  1849. (m_prBinhexOutput->pb + m_prBinhexOutput->cb), cchIn);
  1850. m_rBinhexHeader.cb += cchIn;
  1851. // We only need to pad for a real Mac file...
  1852. if (FALSE == m_fDataForkOnly)
  1853. {
  1854. // Check to see if the size of the fork is a multiple of 128?
  1855. cbPad = 128 - (m_cbDataFork % 128);
  1856. if (cbPad != 0)
  1857. {
  1858. uchIn = '\0';
  1859. // Check output buffer for space
  1860. if (FGROWBUFFER(m_prBinhexOutput, cchLeft + cbPad - cchIn))
  1861. {
  1862. // Grow the buffer
  1863. CHECKHR(hr = HrGrowBuffer(m_prBinhexOutput, cchLeft + cbPad - cchIn));
  1864. }
  1865. // Fill output buffer
  1866. FillMemory((m_prBinhexOutput->pb + m_prBinhexOutput->cb - cchIn), cbPad, uchIn);
  1867. m_prBinhexOutput->cb += cbPad - cchIn;
  1868. }
  1869. }
  1870. // Switch to filling the data fork CRC
  1871. m_prBinhexOutput = &m_rBinhexHeader;
  1872. m_cbToProcess = 2;
  1873. m_eBinHexStateDec = sDATACRC;
  1874. break;
  1875. case sDATACRC:
  1876. if ( HIBYTE( m_wCRCForFork ) != m_prBinhexOutput->pb[0]
  1877. || LOBYTE( m_wCRCForFork ) != m_prBinhexOutput->pb[1] )
  1878. {
  1879. hr = E_FAIL; // ERROR_INVALID_DATA
  1880. goto exit;
  1881. }
  1882. m_wCRC = 0;
  1883. cchIn -= m_cbToProcess;
  1884. *pcbProduced = 0;
  1885. if (m_cbResourceFork > 0)
  1886. {
  1887. m_prBinhexOutput = &m_rOut;
  1888. // Switch to the proper buffer for CRC calculations
  1889. if (FGROWBUFFER(m_prBinhexOutput, cchLeft + cchIn))
  1890. {
  1891. // Grow the buffer
  1892. CHECKHR(hr = HrGrowBuffer(m_prBinhexOutput, cchLeft + cchIn));
  1893. }
  1894. // Move any current bytes so we don't overwrite anything
  1895. CopyMemory((m_prBinhexOutput->pb + m_prBinhexOutput->cb),
  1896. (m_rBinhexHeader.pb + m_rBinhexHeader.cb), cchIn);
  1897. m_prBinhexOutput->cb += cchIn;
  1898. // delete binhex header buffer
  1899. SafeMemFree(m_rBinhexHeader.pb);
  1900. ZeroMemory(&m_rBinhexHeader, sizeof(CONVERTBUFFER));
  1901. // Switch to filling the resource fork
  1902. if (FALSE == m_fDataForkOnly)
  1903. {
  1904. m_cbToProcess = m_cbResourceFork;
  1905. m_eBinHexStateDec = sRESOURCE;
  1906. }
  1907. else
  1908. {
  1909. m_cbToProcess = 0x0;
  1910. m_eBinHexStateDec = sENDING;
  1911. }
  1912. }
  1913. else
  1914. {
  1915. // Set the CRC for the data fork.
  1916. BinHexCalcCRC16((LPBYTE) &wBinHexZero, sizeof(wBinHexZero), &(m_wCRC));
  1917. // Save off the CRC until we can get the CRC from the fork.
  1918. m_wCRCForFork = m_wCRC;
  1919. // Remove the DATA CRC from the buffer
  1920. MoveMemory(m_prBinhexOutput->pb, m_prBinhexOutput->pb + 2, m_prBinhexOutput->cb - 2);
  1921. m_prBinhexOutput->cb -= 2;
  1922. // Switch to filling the resource CRC
  1923. m_cbToProcess = 2;
  1924. m_eBinHexStateDec = sRESOURCECRC;
  1925. }
  1926. break;
  1927. case sRESOURCE:
  1928. // Verify that we have the correct CRC
  1929. BinHexCalcCRC16((LPBYTE) m_prBinhexOutput->pb + m_prBinhexOutput->cb - cchIn - *pcbProduced,
  1930. m_cbToProcess + *pcbProduced, &(m_wCRC));
  1931. BinHexCalcCRC16((LPBYTE) &wBinHexZero, sizeof(wBinHexZero), &(m_wCRC));
  1932. // Save off the CRC until we can get the CRC from the fork.
  1933. m_wCRCForFork = m_wCRC;
  1934. m_wCRC = 0;
  1935. *pcbProduced = 0;
  1936. cchIn -= m_cbToProcess;
  1937. // Switch to the proper buffer for CRC calculations
  1938. if (FGROWBUFFER(&m_rBinhexHeader, cchLeft + cchIn))
  1939. {
  1940. // Grow the buffer
  1941. CHECKHR(hr = HrGrowBuffer(&m_rBinhexHeader, cchLeft + cchIn));
  1942. }
  1943. // Move any current bytes so we don't overwrite anything
  1944. CopyMemory((m_rBinhexHeader.pb + m_rBinhexHeader.cb),
  1945. (m_prBinhexOutput->pb + m_prBinhexOutput->cb), cchIn);
  1946. m_rBinhexHeader.cb += cchIn;
  1947. // Check to see if the size of the fork is a multiple of 128?
  1948. cbPad = 128 - (m_cbResourceFork % 128);
  1949. if (cbPad != 0)
  1950. {
  1951. uchIn = '\0';
  1952. // Check output buffer for space
  1953. if (FGROWBUFFER(m_prBinhexOutput, cchLeft + cbPad - cchIn))
  1954. {
  1955. // Grow the buffer
  1956. CHECKHR(hr = HrGrowBuffer(m_prBinhexOutput, cchLeft + cbPad - cchIn));
  1957. }
  1958. // Fill output buffer
  1959. FillMemory((m_prBinhexOutput->pb + m_prBinhexOutput->cb - cchIn), cbPad, uchIn);
  1960. m_prBinhexOutput->cb += cbPad - cchIn;
  1961. }
  1962. // Switch to filling the resource fork CRC
  1963. m_prBinhexOutput = &m_rBinhexHeader;
  1964. m_cbToProcess = 2;
  1965. m_eBinHexStateDec = sRESOURCECRC;
  1966. break;
  1967. case sRESOURCECRC:
  1968. if ( HIBYTE( m_wCRCForFork ) != m_prBinhexOutput->pb[0]
  1969. || LOBYTE( m_wCRCForFork ) != m_prBinhexOutput->pb[1] )
  1970. {
  1971. hr = E_FAIL; // ERROR_INVALID_DATA
  1972. goto exit;
  1973. }
  1974. m_wCRC = 0;
  1975. cchIn -= m_cbToProcess;
  1976. m_prBinhexOutput = &m_rOut;
  1977. *pcbProduced = 0;
  1978. // Switch to the proper buffer for CRC calculations
  1979. if (FGROWBUFFER(m_prBinhexOutput, cchLeft + cchIn))
  1980. {
  1981. // Grow the buffer
  1982. CHECKHR(hr = HrGrowBuffer(m_prBinhexOutput, cchLeft + cchIn));
  1983. }
  1984. // Move any current bytes so we don't overwrite anything
  1985. CopyMemory((m_prBinhexOutput->pb + m_prBinhexOutput->cb),
  1986. (m_rBinhexHeader.pb + m_rBinhexHeader.cb), cchIn);
  1987. m_prBinhexOutput->cb += cchIn;
  1988. // delete binhex header buffer
  1989. SafeMemFree(m_rBinhexHeader.pb);
  1990. ZeroMemory(&m_rBinhexHeader, sizeof(CONVERTBUFFER));
  1991. // Switch to filling the resource fork
  1992. m_cbToProcess = 0x0;
  1993. m_eBinHexStateDec = sENDING;
  1994. break;
  1995. default:
  1996. Assert(FALSE);
  1997. break;
  1998. }
  1999. }
  2000. m_cbToProcess -= cchIn;
  2001. *pcbProduced += cchIn;
  2002. hr = S_OK;
  2003. exit:
  2004. // Done
  2005. return hr;
  2006. }
  2007. // --------------------------------------------------------------------------------
  2008. // CInternetConverter::HrBinhexThrowAway
  2009. // --------------------------------------------------------------------------------
  2010. HRESULT CInternetConverter::HrBinhexThrowAway(LPSTR pszLine, ULONG cbLine)
  2011. {
  2012. HRESULT hr = S_FALSE;
  2013. if (m_eBinHexStateDec == sSTARTING)
  2014. {
  2015. // Ingore all lines before we start that only have whitespace characters
  2016. // or the start tag.
  2017. hr = S_OK;
  2018. for (LPSTR pszEnd = pszLine + cbLine; pszLine < pszEnd; pszLine++)
  2019. {
  2020. if (!FBINHEXRETURN(*pszLine))
  2021. {
  2022. // Need to ignore lines that start with the tag
  2023. if (((ULONG)(pszEnd - pszLine) >= cbBINHEXSTART) && (StrCmpNI(szBINHEXSTART, pszLine, cbBINHEXSTART) == 0))
  2024. {
  2025. m_eBinHexStateDec = sSTARTED;
  2026. break;
  2027. }
  2028. // We must have gotten bad data
  2029. hr = E_FAIL; // ERROR_INVALID_DATA
  2030. m_eBinHexStateDec = sENDED;
  2031. goto exit;
  2032. }
  2033. }
  2034. }
  2035. else if (m_eBinHexStateDec == sENDED)
  2036. {
  2037. // We can ignore any lines after we are done.
  2038. hr = S_OK;
  2039. }
  2040. exit:
  2041. // Done
  2042. return hr;
  2043. }
  2044. // --------------------------------------------------------------------------------
  2045. // CInternetConverter::HrDecodeBinHex
  2046. // --------------------------------------------------------------------------------
  2047. HRESULT CInternetConverter::HrDecodeBinHex(void)
  2048. {
  2049. // Locals
  2050. HRESULT hr=S_OK;
  2051. ULONG cbLine;
  2052. LPSTR pszLine;
  2053. ULONG cbRead=0;
  2054. ULONG cbLineLength;
  2055. BOOL fFound;
  2056. ULONG cbConvert;
  2057. ULONG cbScan;
  2058. ULONG i;
  2059. UCHAR uchConvert[4];
  2060. UCHAR uchThis;
  2061. UCHAR uchDecoded;
  2062. UCHAR cuchWrite;
  2063. UCHAR rgbShift[] = {0, 4, 2, 0};
  2064. ULONG cbProduced = 0;
  2065. // Read lines and stuff dots
  2066. while(1)
  2067. {
  2068. // Increment Index
  2069. m_rIn.i += cbRead;
  2070. // Get Next Line
  2071. pszLine = PszConvBuffGetNextLine(&cbLine, &cbRead, &fFound);
  2072. if (0 == cbRead || (FALSE == fFound && FALSE == m_fLastBuffer))
  2073. {
  2074. goto exit;
  2075. }
  2076. // UUENCODE ThrowAway
  2077. hr = HrBinhexThrowAway(pszLine, cbLine);
  2078. if (FAILED(hr))
  2079. {
  2080. goto exit;
  2081. }
  2082. else if (S_OK == hr)
  2083. {
  2084. continue;
  2085. }
  2086. hr = S_OK;
  2087. // Do I need to grow
  2088. if (FGROWBUFFER(m_prBinhexOutput, cbLine + 20))
  2089. {
  2090. // Grow the buffer
  2091. CHECKHR(hr = HrGrowBuffer(m_prBinhexOutput, cbLine + 20));
  2092. }
  2093. AssertSz((m_eBinHexStateDec != sSTARTING) && (m_eBinHexStateDec != sENDED),
  2094. "Why haven't we found the start of the stream yet??\n");
  2095. // Decodes characters in line buffer
  2096. for (i=0; i<cbLine; i++)
  2097. {
  2098. uchThis = pszLine[i];
  2099. // Check for valid white space
  2100. if (FBINHEXRETURN(uchThis))
  2101. continue;
  2102. // Check for start or end of stream
  2103. if (BINHEX_TERM == uchThis)
  2104. {
  2105. if (m_eBinHexStateDec == sSTARTED)
  2106. {
  2107. m_eBinHexStateDec = sHDRFILESIZE;
  2108. continue;
  2109. }
  2110. else if (m_eBinHexStateDec == sENDING)
  2111. {
  2112. m_eBinHexStateDec = sENDED;
  2113. break;
  2114. }
  2115. }
  2116. if (m_eBinHexStateDec == sENDING)
  2117. {
  2118. if (('!' == uchThis) || (TRUE == m_fDataForkOnly))
  2119. {
  2120. continue;
  2121. }
  2122. else
  2123. {
  2124. // ensure that we're not in an invalid state. If we made it to sENDING and we got
  2125. // valid CRCs and everything is hunky dory, just ignore the terminating stuff.
  2126. continue;
  2127. }
  2128. }
  2129. // Decode It
  2130. uchDecoded = DECODEBINHEX(uchThis);
  2131. // Test for valid char
  2132. if (uchDecoded == BINHEX_INVALID)
  2133. {
  2134. hr = E_FAIL; // ERROR_INVALID_DATA
  2135. goto exit;
  2136. }
  2137. if ( m_cAccum == 0 )
  2138. {
  2139. m_ulAccum = uchDecoded;
  2140. ++m_cAccum;
  2141. continue;
  2142. }
  2143. else
  2144. {
  2145. m_ulAccum = ( m_ulAccum << 6 ) | uchDecoded;
  2146. uchDecoded = (BYTE)(m_ulAccum >> rgbShift[m_cAccum]) & 0xff;
  2147. m_cAccum++;
  2148. m_cAccum %= sizeof(m_ulAccum);
  2149. }
  2150. // If we are repeating then fill the buffer with char
  2151. if (m_fRepeating)
  2152. {
  2153. m_fRepeating = FALSE;
  2154. // Check to see if it's just a literal 0x90
  2155. if (0x00 == uchDecoded)
  2156. {
  2157. // Just write out one BINHEX_REPEAT char
  2158. m_uchPrev = BINHEX_REPEAT;
  2159. cuchWrite = 1;
  2160. }
  2161. else
  2162. {
  2163. cuchWrite = uchDecoded - 1;
  2164. }
  2165. }
  2166. // Check for repeat character
  2167. else if (BINHEX_REPEAT == uchDecoded)
  2168. {
  2169. m_fRepeating = TRUE;
  2170. continue;
  2171. }
  2172. // Else it's just a normal character.
  2173. else
  2174. {
  2175. m_uchPrev = uchDecoded;
  2176. cuchWrite = 1;
  2177. }
  2178. CHECKHR(HrBinhexDecodeBuffAppend(m_uchPrev, cuchWrite, cbLine - i, &cbProduced));
  2179. }
  2180. BinHexCalcCRC16((LPBYTE) m_prBinhexOutput->pb + m_prBinhexOutput->cb - cbProduced, cbProduced, &(m_wCRC));
  2181. cbProduced = 0;
  2182. }
  2183. hr = S_OK;
  2184. exit:
  2185. // Done
  2186. return hr;
  2187. }