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.

239 lines
6.0 KiB

  1. //+----------------------------------------------------------------------------
  2. // File: mime64.cxx
  3. //
  4. // Synopsis:
  5. //
  6. //-----------------------------------------------------------------------------
  7. // Includes -------------------------------------------------------------------
  8. #include <core.hxx>
  9. // Constants ------------------------------------------------------------------
  10. const LARGE_INTEGER LIB_ZERO = { 0, 0 };
  11. const ULONG BUFFER_SIZE = 256;
  12. const UCHAR INVALID_CHAR = (UCHAR)-2;
  13. const UCHAR IGNORE_CHAR = (UCHAR)-1;
  14. const UCHAR CH_TERMINATION = '=';
  15. const char achAlpha[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
  16. "abcdefghijklmnopqrstuvwxyz"
  17. "0123456789+/";
  18. // Globals --------------------------------------------------------------------
  19. UCHAR g_anBinary[256];
  20. // Prototypes -----------------------------------------------------------------
  21. inline ULONG BinaryFromASCII(UCHAR ch) { return g_anBinary[ch]; }
  22. //+----------------------------------------------------------------------------
  23. // Function: ProcessAttachMIME64
  24. //
  25. // Synopsis:
  26. //
  27. //-----------------------------------------------------------------------------
  28. HRESULT
  29. ProcessAttachMIME64()
  30. {
  31. UCHAR ubin;
  32. UCHAR ch;
  33. int i;
  34. // BUGBUG: Hard code this table
  35. for (i=0; i < ARRAY_SIZE(g_anBinary); i++)
  36. {
  37. ch = (UCHAR)i;
  38. switch (ch)
  39. {
  40. case ' ' :
  41. case '\t':
  42. case '\n':
  43. case '\r':
  44. ubin = IGNORE_CHAR;
  45. break;
  46. default:
  47. if ((ch >= 'A') && (ch <= 'Z'))
  48. ubin = (UCHAR)(ch - 'A');
  49. else if ((ch >= 'a') && (ch <= 'z'))
  50. ubin = (UCHAR)(26 + (ch - 'a'));
  51. else if ((ch >= '0') && (ch <= '9'))
  52. ubin = (UCHAR)(52 + (ch - '0'));
  53. else
  54. ubin = INVALID_CHAR;
  55. break;
  56. case '+':
  57. ubin = 62;
  58. break;
  59. case '/':
  60. ubin = 63;
  61. break;
  62. }
  63. g_anBinary[i] = ubin;
  64. }
  65. return S_OK;
  66. }
  67. //+----------------------------------------------------------------------------
  68. // Function: EncodeMIME64
  69. //
  70. // Synopsis:
  71. //
  72. //-----------------------------------------------------------------------------
  73. HRESULT
  74. EncodeMIME64(
  75. BYTE * pbSrc,
  76. UINT cbSrc,
  77. IStream * pstmDest,
  78. ULONG * pcbWritten)
  79. {
  80. UCHAR achOut[(2 * sizeof(UCHAR)) + CB_NEWLINE];
  81. ULONG ichOut = 0;
  82. ULONG cbWritten;
  83. ULONG cbTotalWritten;
  84. ULONG bAccum = 0;
  85. ULONG cShift = 0;
  86. HRESULT hr = S_OK;
  87. Assert(pbSrc);
  88. Assert(pstmDest);
  89. if (!pcbWritten)
  90. {
  91. pcbWritten = &cbTotalWritten;
  92. }
  93. // Convert the source string, 6-bits at a time, to ASCII characters
  94. while (cbSrc)
  95. {
  96. bAccum <<= 8;
  97. cShift += 8;
  98. bAccum |= *pbSrc++;
  99. cbSrc--;
  100. while (cShift >= 6)
  101. {
  102. cShift -= 6;
  103. hr = pstmDest->Write(&achAlpha[(bAccum >> cShift) & 0x3FL], 1, &cbWritten);
  104. *pcbWritten += cbWritten;
  105. if (hr)
  106. goto Cleanup;
  107. }
  108. }
  109. // If there are bits not yet written, pad with zeros and write the resulting character
  110. if (cShift)
  111. {
  112. bAccum <<= 6 - cShift;
  113. achOut[ichOut++] = achAlpha[(bAccum >> cShift) & 0x3FL];
  114. }
  115. // Add a termination character and newline
  116. achOut[ichOut++] = CH_TERMINATION;
  117. ::memcpy(achOut+ichOut, SZ_NEWLINE, CB_NEWLINE);
  118. ichOut += CB_NEWLINE;
  119. hr = pstmDest->Write(achOut, ichOut, &cbWritten);
  120. *pcbWritten += cbWritten;
  121. if (hr)
  122. goto Cleanup;
  123. Cleanup:
  124. return hr;
  125. }
  126. //+----------------------------------------------------------------------------
  127. // Function: DecodeMIME64
  128. //
  129. // Synopsis:
  130. //
  131. //-----------------------------------------------------------------------------
  132. HRESULT
  133. DecodeMIME64(
  134. IStream * pstmSrc,
  135. IStream * pstmDest,
  136. ULONG * pcbWritten)
  137. {
  138. UCHAR ch;
  139. UCHAR achOut[BUFFER_SIZE];
  140. ULONG ichOut = 0;
  141. ULONG cbRead;
  142. ULONG cbWritten;
  143. ULONG cbTotalWritten = 0;
  144. ULONG bAccum = 0;
  145. ULONG cShift = 0;
  146. ULONG bValue;
  147. HRESULT hr;
  148. if (!pcbWritten)
  149. {
  150. pcbWritten = &cbTotalWritten;
  151. }
  152. // As long as characters remain, convert them to binary
  153. // (This loop skips "whitespace" and stops when it encounters an out-of-range value)
  154. for (;;)
  155. {
  156. hr = pstmSrc->Read(&ch, sizeof(ch), &cbRead);
  157. if (hr)
  158. goto Cleanup;
  159. // Stop when no more characters remain
  160. if (!cbRead)
  161. break;
  162. bValue = BinaryFromASCII(ch);
  163. // Convert known characters back to binary
  164. if (bValue < 64)
  165. {
  166. bAccum <<= 6;
  167. cShift += 6;
  168. bAccum |= bValue;
  169. if (cShift >= 8)
  170. {
  171. cShift -= 8;
  172. achOut[ichOut++] = (UCHAR)((bAccum >> cShift) & 0xFF);
  173. if (ichOut >= ARRAY_SIZE(achOut))
  174. {
  175. hr = pstmDest->Write(achOut, ichOut, &cbWritten);
  176. *pcbWritten += cbWritten;
  177. if (hr)
  178. goto Cleanup;
  179. ichOut = 0;
  180. }
  181. }
  182. }
  183. // Skip "whitespace"
  184. else if (bValue == IGNORE_CHAR)
  185. ;
  186. // Stop if anything else is encountered
  187. else
  188. break;
  189. }
  190. // If characters remain to be written, write them now
  191. if (ichOut)
  192. {
  193. hr = pstmDest->Write(achOut, ichOut, &cbWritten);
  194. *pcbWritten += cbWritten;
  195. if (hr)
  196. goto Cleanup;
  197. }
  198. Cleanup:
  199. return hr;
  200. }