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.

264 lines
8.7 KiB

  1. //-----------------------------------------------------------------------------
  2. //
  3. //
  4. // File: b64octet.cpp
  5. //
  6. // Description: Implementation of Base64 encoding stream designed for use
  7. // with UTF7 encoding.
  8. //
  9. // Author: Mike Swafford (MikeSwa)
  10. //
  11. // History:
  12. // 10/21/98 - MikeSwa Created
  13. //
  14. // Copyright (C) 1998 Microsoft Corporation
  15. //
  16. //-----------------------------------------------------------------------------
  17. #include "precomp.h"
  18. //Alphabet for BASE64 encoding as defined in RFC1421 and RFC1521
  19. CHAR g_rgchBase64[64] =
  20. {
  21. 'A','B','C','D','E','F','G','H','I','J','K','L','M',
  22. 'N','O','P','Q','R','S','T','U','V','W','X','Y','Z',
  23. 'a','b','c','d','e','f','g','h','i','j','k','l','m',
  24. 'n','o','p','q','r','s','t','u','v','w','x','y','z',
  25. '0','1','2','3','4','5','6','7','8','9','+','/'
  26. };
  27. const DWORD BASE64_OCTET_STATE_0_BITS = 0;
  28. const DWORD BASE64_OCTET_STATE_2_BITS = 1;
  29. const DWORD BASE64_OCTET_STATE_4_BITS = 2;
  30. const DWORD BASE64_NUM_STATES = 3;
  31. //---[ CBase64OctetStream::CBase64OctetStream ]--------------------------------
  32. //
  33. //
  34. // Description:
  35. // Default contructor for CBase64OctetStream
  36. // Parameters:
  37. // -
  38. // Returns:
  39. // -
  40. // History:
  41. // 10/21/98 - MikeSwa Created
  42. //
  43. //-----------------------------------------------------------------------------
  44. CBase64OctetStream::CBase64OctetStream()
  45. {
  46. m_dwSignature = BASE64_OCTET_SIG;
  47. m_dwCurrentState = BASE64_OCTET_STATE_0_BITS;
  48. m_bCurrentLeftOver = 0;
  49. }
  50. //---[ CBase64OctetStream::NextState ]------------------------------------------
  51. //
  52. //
  53. // Description:
  54. // Moves the internal state machine to the next state
  55. // Parameters:
  56. // -
  57. // Returns:
  58. // -
  59. // History:
  60. // 10/21/98 - MikeSwa Created
  61. //
  62. //-----------------------------------------------------------------------------
  63. void CBase64OctetStream::NextState()
  64. {
  65. m_dwCurrentState++;
  66. if (BASE64_NUM_STATES == m_dwCurrentState)
  67. {
  68. m_dwCurrentState = BASE64_OCTET_STATE_0_BITS;
  69. m_bCurrentLeftOver = 0;
  70. }
  71. }
  72. //---[ CBase64OctetStream::ResetState ]----------------------------------------
  73. //
  74. //
  75. // Description:
  76. // Resets the internal state machine
  77. // Parameters:
  78. // -
  79. // Returns:
  80. // -
  81. // History:
  82. // 10/21/98 - MikeSwa Created
  83. //
  84. //-----------------------------------------------------------------------------
  85. void CBase64OctetStream::ResetState()
  86. {
  87. m_dwCurrentState = BASE64_OCTET_STATE_0_BITS;
  88. m_bCurrentLeftOver = 0;
  89. }
  90. //---[ CBase64OctetStream::fProcessWideChar ]----------------------------------
  91. //
  92. //
  93. // Description:
  94. // Processes a single wide character and stores the results in its
  95. // buffer. It will also ensure that there is always enough room to
  96. // safely calll TerminateStream.
  97. // Parameters:
  98. // IN wch UNICODE character to process
  99. // Returns:
  100. // TRUE if there is enough room in the buffer to convert this char
  101. // FALSE if there is not enough room to conver this char safely
  102. // History:
  103. // 10/21/98 - MikeSwa Created
  104. //
  105. //-----------------------------------------------------------------------------
  106. BOOL CBase64OctetStream::fProcessWideChar(WCHAR wch)
  107. {
  108. BYTE bHigh = HIBYTE(wch);
  109. BYTE bLow = LOBYTE(wch);
  110. //At most... a single WCHAR will generate 3 base64 characters evenly or 2
  111. //base64 characters plus a remainder which can be expanded to
  112. //3 more characters (with trailing "==")
  113. if (m_CharBuffer.cSpaceLeft() < 5)
  114. return FALSE;
  115. //We know we have enough room to safely convert this character.... we
  116. //will _VERIFY all PushChar's.
  117. //Loop through bytes in WCHAR
  118. _VERIFY(fProcessSingleByte(bHigh));
  119. _VERIFY(fProcessSingleByte(bLow));
  120. return TRUE;
  121. }
  122. //---[ CBase64OctetStream::fProcessSingleByte ]--------------------------------
  123. //
  124. //
  125. // Description:
  126. // Does the actual work of converting a single byte to the appropriate
  127. // base64 char(s). Also keeps track of state.
  128. // Parameters:
  129. // IN b BYTE to convert
  130. // Returns:
  131. // TRUE if there is enough room for the conversion
  132. // FALSE otherwise
  133. // History:
  134. // 10/21/98 - MikeSwa Created
  135. //
  136. //-----------------------------------------------------------------------------
  137. BOOL CBase64OctetStream::fProcessSingleByte(BYTE b)
  138. {
  139. const BYTE BASE64_MASK = 0x3F; //can only use 6 bits in Base64
  140. BOOL fRet = TRUE;
  141. if (m_CharBuffer.fIsFull())
  142. return FALSE;
  143. switch (m_dwCurrentState)
  144. {
  145. case BASE64_OCTET_STATE_0_BITS:
  146. //There were no bits left from previous state
  147. m_bCurrentLeftOver = b & 0x03; //there will now be 2 bits left over
  148. m_bCurrentLeftOver <<= 4; //shift to MSB in six bits
  149. _VERIFY(m_CharBuffer.fPushChar(g_rgchBase64[BASE64_MASK & (b >> 2)]));
  150. NextState();
  151. break;
  152. case BASE64_OCTET_STATE_2_BITS:
  153. //There were 2 bits left from previous state..
  154. m_bCurrentLeftOver += (0x0F & (b >> 4));
  155. _VERIFY(m_CharBuffer.fPushChar(g_rgchBase64[BASE64_MASK & m_bCurrentLeftOver]));
  156. //we will leave 4 low bits over
  157. m_bCurrentLeftOver = 0x0F & b;
  158. m_bCurrentLeftOver <<= 2; //shift to MSB is six bit grouping
  159. NextState();
  160. break;
  161. case BASE64_OCTET_STATE_4_BITS:
  162. //There were 4 bits left over
  163. if (m_CharBuffer.cSpaceLeft() < 2)
  164. {
  165. //There is not enough room for both characters we would push...
  166. //so don't process byte at all.
  167. //Do not move to the next state... do not collection $200.
  168. fRet = FALSE;
  169. }
  170. else
  171. {
  172. m_bCurrentLeftOver += (0x03 & (b >> 6));
  173. _VERIFY(m_CharBuffer.fPushChar(g_rgchBase64[BASE64_MASK & m_bCurrentLeftOver]));
  174. m_bCurrentLeftOver = 0;
  175. _VERIFY(m_CharBuffer.fPushChar(g_rgchBase64[BASE64_MASK & b]));
  176. NextState();
  177. }
  178. break;
  179. default:
  180. _ASSERT(0 && "Invalid State");
  181. }
  182. return fRet;
  183. }
  184. //---[ CBase64OctetStream::cTerminateStream ]----------------------------------
  185. //
  186. //
  187. // Description:
  188. // Used to signal the termination of the current stream. Resets the
  189. // state as performs any padding necessary
  190. // Parameters:
  191. // IN fUTF7Encoded TRUE if the stream is UTF7 encoded (does not
  192. // require '=' padding).
  193. // Returns:
  194. // TRUE if there is anything left in the buffer.
  195. // FALSE if there are no characters left to convert
  196. // History:
  197. // 10/21/98 - MikeSwa Created
  198. //
  199. //-----------------------------------------------------------------------------
  200. BOOL CBase64OctetStream::fTerminateStream(BOOL fUTF7Encoded)
  201. {
  202. if (BASE64_OCTET_STATE_0_BITS != m_dwCurrentState)
  203. {
  204. //There should always be space left to do this
  205. _VERIFY(m_CharBuffer.fPushChar(g_rgchBase64[m_bCurrentLeftOver]));
  206. if (!fUTF7Encoded)
  207. {
  208. switch(m_dwCurrentState)
  209. {
  210. case BASE64_OCTET_STATE_2_BITS:
  211. //There are 2 bits in this byte we did not use... which
  212. //means that there are 2 more base64 chars to fill 24 bits
  213. //+ => Used bits
  214. //- => Unused (but parsed) bits
  215. //? => Unseed bits to fill out to 24 bits
  216. //++++ ++-- ???? ???? ???? ????
  217. _VERIFY(m_CharBuffer.fPushChar('='));
  218. _VERIFY(m_CharBuffer.fPushChar('='));
  219. break;
  220. case BASE64_OCTET_STATE_4_BITS:
  221. //In these chase there is only 1 extra base64 char needed
  222. //++++ ++++ ++++ ---- ???? ????
  223. _VERIFY(m_CharBuffer.fPushChar('='));
  224. break;
  225. }
  226. }
  227. }
  228. ResetState();
  229. return (!m_CharBuffer.fIsEmpty());
  230. }
  231. //---[ CBase64OctetStream::fNextValidChar ]------------------------------------
  232. //
  233. //
  234. // Description:
  235. // Iterates over buffered converted characters
  236. // Parameters:
  237. // OUT pch Next buffer char
  238. // Returns:
  239. // TRUE If there is a character to get
  240. // FALSE If there were no characters to get
  241. // History:
  242. // 10/21/98 - MikeSwa Created
  243. //
  244. //-----------------------------------------------------------------------------
  245. BOOL CBase64OctetStream::fNextValidChar(CHAR *pch)
  246. {
  247. _ASSERT(pch);
  248. return m_CharBuffer.fPopChar(pch);
  249. }