Source code of Windows XP (NT5)
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.

315 lines
7.9 KiB

  1. //////////////////////////////////////////////////////////////////////////////
  2. //
  3. // Copyright (c) 1999 Microsoft Corporation
  4. //
  5. // Module Name:
  6. //
  7. // base64tool.cpp
  8. //
  9. // Abstract:
  10. //
  11. // base64 encoding and decoding functions
  12. //
  13. // Revision History:
  14. //
  15. // Comes from SimpleLogObj.cpp (provided as part of the Microsoft
  16. // Transaction Server Software Development Kit
  17. // Copyright (C) 1997 Microsoft Corporation, All rights reserved
  18. //
  19. // Thierry Perraut 04/02/1999 (many minor changes)
  20. // 10/19/1999 Change CoTaskMemAlloc(0) into CoTaskMemAlloc(sizeof(BSTR*))
  21. // fix the bug 416872 (memory used after the free). This bug
  22. // became visible after fixing the first one, on checked builds.
  23. //
  24. //////////////////////////////////////////////////////////////////////////////
  25. #include "stdafx.h"
  26. #include "base64tool.h"
  27. // These characters are the legal digits, in order, that are
  28. // used in Base64 encoding
  29. //
  30. namespace
  31. {
  32. const WCHAR rgwchBase64[] =
  33. L"ABCDEFGHIJKLMNOPQ"
  34. L"RSTUVWXYZabcdefgh"
  35. L"ijklmnopqrstuvwxy"
  36. L"z0123456789+/";
  37. }
  38. //////////////////////////////////////////////////////////////////////////////
  39. //
  40. // Encode and return the bytes in base 64
  41. //
  42. //////////////////////////////////////////////////////////////////////////////
  43. HRESULT ToBase64(LPVOID pv, ULONG cByteLength, BSTR* pbstr)
  44. {
  45. if ( !pbstr )
  46. {
  47. return E_OUTOFMEMORY;
  48. }
  49. ULONG cb = cByteLength;
  50. int cchPerLine = 72;
  51. // conservative, must be mult of 4 for us
  52. int cbPerLine = cchPerLine / 4 * 3;
  53. LONG cbSafe = cb + 3; // allow for padding
  54. LONG cLine = cbSafe / cbPerLine + 2; // conservative
  55. LONG cchNeeded = cLine * (cchPerLine + 4 /*CRLF*/) + 1 /*slash NULL*/;
  56. LONG cbNeeded = cchNeeded * sizeof(WCHAR);
  57. HRESULT hr = S_OK;
  58. LPWSTR wsz = static_cast<LPWSTR>(CoTaskMemAlloc(cbNeeded));
  59. if ( !wsz )
  60. {
  61. return E_OUTOFMEMORY;
  62. }
  63. BYTE* pb = (BYTE*)pv;
  64. WCHAR* pch = wsz ;
  65. int cchLine = 0;
  66. //
  67. // Main encoding loop
  68. //
  69. while (cb >= 3)
  70. {
  71. BYTE b0 = ((pb[0]>>2) & 0x3F);
  72. BYTE b1 = ((pb[0]&0x03)<<4) | ((pb[1]>>4) & 0x0F);
  73. BYTE b2 = ((pb[1]&0x0F)<<2) | ((pb[2]>>6) & 0x03);
  74. BYTE b3 = ((pb[2]&0x3F));
  75. *pch++ = rgwchBase64[b0];
  76. *pch++ = rgwchBase64[b1];
  77. *pch++ = rgwchBase64[b2];
  78. *pch++ = rgwchBase64[b3];
  79. pb += 3;
  80. cb -= 3;
  81. // put in line breaks
  82. cchLine += 4;
  83. if (cchLine >= cchPerLine)
  84. {
  85. *pch++ = L'\\';
  86. *pch++ = L'\r';
  87. cchLine = 0;
  88. }
  89. }
  90. //
  91. // Account for gunk at the end
  92. //
  93. *pch++ = L'\\';
  94. *pch++ = L'\r'; // easier than keeping track
  95. if (cb==0)
  96. {
  97. // nothing to do
  98. }
  99. else if (cb==1)
  100. {
  101. BYTE b0 = ((pb[0]>>2) & 0x3F);
  102. BYTE b1 = ((pb[0]&0x03)<<4) | 0;
  103. *pch++ = rgwchBase64[b0];
  104. *pch++ = rgwchBase64[b1];
  105. }
  106. else if (cb==2)
  107. {
  108. BYTE b0 = ((pb[0]>>2) & 0x3F);
  109. BYTE b1 = ((pb[0]&0x03)<<4) | ((pb[1]>>4) & 0x0F);
  110. BYTE b2 = ((pb[1]&0x0F)<<2) | 0;
  111. *pch++ = rgwchBase64[b0];
  112. *pch++ = rgwchBase64[b1];
  113. *pch++ = rgwchBase64[b2];
  114. }
  115. else
  116. {
  117. // should never go there
  118. }
  119. //
  120. // NULL terminate the string
  121. //
  122. *pch++ = L'\\';
  123. *pch++ = L'\r'; // easier than keeping track
  124. *pch++ = NULL;
  125. //
  126. // Allocate our final output
  127. //
  128. *pbstr = SysAllocString(wsz);
  129. if ( !*pbstr )
  130. {
  131. return E_OUTOFMEMORY;
  132. }
  133. CoTaskMemFree(wsz);
  134. wsz = NULL;
  135. #ifdef _DEBUG
  136. if (hr==S_OK)
  137. {
  138. BLOB b;
  139. FromBase64(*pbstr, &b);
  140. _ASSERTE(b.cbSize == cByteLength);
  141. _ASSERTE(memcmp(b.pBlobData, pv, cByteLength) == 0);
  142. CoTaskMemFree(b.pBlobData);
  143. }
  144. #endif
  145. return hr;
  146. }
  147. //////////////////////////////////////////////////////////////////////////////
  148. //
  149. // Decode and return the Base64 encoded bytes
  150. //
  151. // Allocates the memory for the blob.
  152. //
  153. //////////////////////////////////////////////////////////////////////////////
  154. HRESULT FromBase64(BSTR bstr, BLOB* pblob, int Index)
  155. {
  156. ASSERT(Index >= 0);
  157. ASSERT(pblob);
  158. if (bstr == NULL)
  159. {
  160. #ifdef DEBUG
  161. wprintf(L"FromBase64 (bstr == NULL)\n");
  162. #endif //DEBUG
  163. return E_FAIL;
  164. }
  165. HRESULT hr = S_OK;
  166. ULONG cbNeeded = wcslen(bstr); // an upper bound
  167. BYTE* rgb = static_cast<BYTE*>(CoTaskMemAlloc(cbNeeded));
  168. if ( !rgb )
  169. {
  170. return E_OUTOFMEMORY;
  171. }
  172. memset(rgb, 0, cbNeeded);
  173. BYTE mpwchb[256];
  174. BYTE bBad = (BYTE)-1;
  175. //
  176. // Initialize our decoding array
  177. //
  178. memset(&mpwchb[0], bBad, 256);
  179. for ( BYTE i = 0; i < 64; ++i )
  180. {
  181. WCHAR wch = rgwchBase64[i];
  182. mpwchb[wch] = i;
  183. }
  184. //
  185. // Loop over the entire input buffer
  186. //
  187. // what we're in the process of filling up
  188. ULONG bCurrent = 0;
  189. // how many bits in it we've filled
  190. int cbitFilled = 0;
  191. // current destination (not filled)
  192. BYTE* pb = rgb;
  193. // SysStringLen doesn't include the termination NULL character
  194. LONG LoopCounter = static_cast<LONG>(SysStringLen(bstr) + 1);
  195. for ( WCHAR* pwch = bstr; *pwch; ++pwch )
  196. {
  197. WCHAR wch = *pwch;
  198. //
  199. // Ignore white space
  200. //
  201. if ( wch==0x0A || wch==0x0D || wch==0x20 || wch==0x09 )
  202. {
  203. continue;
  204. }
  205. if ( Index > 0 )
  206. {
  207. LoopCounter--;
  208. ////////////////////////////////////////////
  209. // At least one section needs to be skipped
  210. ////////////////////////////////////////////
  211. if ( wch != L'*' )
  212. {
  213. //////////////////////////////////
  214. // Not the end of the section yet
  215. //////////////////////////////////
  216. continue;
  217. }
  218. else
  219. {
  220. ///////////////////////////////
  221. // End of section marker found
  222. // decrease index and loop
  223. ///////////////////////////////
  224. Index --;
  225. continue;
  226. }
  227. }
  228. else if ( wch == L'*' )
  229. {
  230. ////////////////////////////////
  231. // End of the section to decode
  232. ////////////////////////////////
  233. break;
  234. }
  235. //
  236. // Have we reached the end?
  237. //
  238. if ( LoopCounter-- <= 0 )
  239. {
  240. break;
  241. }
  242. //
  243. // How much is this character worth?
  244. //
  245. BYTE bDigit = mpwchb[wch];
  246. if ( bDigit == bBad )
  247. {
  248. hr = E_INVALIDARG;
  249. break;
  250. }
  251. //
  252. // Add in its contribution
  253. //
  254. bCurrent <<= 6;
  255. bCurrent |= bDigit;
  256. cbitFilled += 6;
  257. //
  258. // If we've got enough, output a byte
  259. //
  260. if ( cbitFilled >= 8 )
  261. {
  262. // get's top eight valid bits
  263. ULONG b = (bCurrent >> (cbitFilled-8));
  264. *pb++ = (BYTE)(b&0xFF);// store the byte away
  265. cbitFilled -= 8;
  266. }
  267. }
  268. if ( hr == S_OK )
  269. {
  270. pblob->pBlobData = rgb;
  271. pblob->cbSize = (ULONG) (pb - rgb);
  272. }
  273. else
  274. {
  275. CoTaskMemFree(rgb);
  276. pblob->pBlobData = NULL;
  277. }
  278. return hr;
  279. }