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.

381 lines
9.4 KiB

  1. // BinHex.cpp: implementation of the CBinHex class.
  2. //
  3. //////////////////////////////////////////////////////////////////////
  4. #include "stdafx.h"
  5. #include "BinHex.h"
  6. #include "BstrDebug.h"
  7. // These characters are the legal digits, in order, that are
  8. // used in Base64 encoding
  9. //
  10. const WCHAR rgwchBase64[] =
  11. L"ABCDEFGHIJKLMNOPQ"
  12. L"RSTUVWXYZabcdefgh"
  13. L"ijklmnopqrstuvwxy"
  14. L"z0123456789!*";
  15. const char rgwchBase64ASCII[] =
  16. "ABCDEFGHIJKLMNOPQ"
  17. "RSTUVWXYZabcdefgh"
  18. "ijklmnopqrstuvwxy"
  19. "z0123456789!*";
  20. CBinHex::CBinHex()
  21. {
  22. unsigned char i;
  23. //
  24. // Initialize our decoding array
  25. //
  26. memset(m_decodeArray, BBAD, 256);
  27. for (i = 0; i < 64; i++)
  28. {
  29. WCHAR wch = rgwchBase64[i];
  30. m_decodeArray[wch] = i;
  31. }
  32. }
  33. // This function takes IN a single-char buffer, and puts the binhex
  34. // output into a bstr -- in the bstr, it's ASCII string
  35. //
  36. // Function name : ToBase64
  37. // Description :
  38. // Return type : HRESULT
  39. // Argument : LPVOID pv
  40. // Argument : ULONG cbSize
  41. // Argument : char prepend
  42. // Argument : BSTR* pbstr
  43. //
  44. HRESULT CBinHex::ToBase64ASCII(LPVOID pv, UINT cbSize, char prepend, char ivecnpad[9], BSTR* pbstr)
  45. //
  46. // Encode and return the bytes in base 64
  47. //
  48. {
  49. UINT cb = cbSize, cbSafe, cchNeeded, cbNeeded, i;
  50. HRESULT hr = S_OK;
  51. *pbstr = NULL;
  52. if (cb % 3)
  53. cbSafe = cb + 3 - (cb % 3); // For padding
  54. else
  55. cbSafe = cb;
  56. // cbSafe is now a multiple of 3
  57. cchNeeded = (cbSafe*4/3); // 3 normal bytes --> 4 chars
  58. cbNeeded = cchNeeded;
  59. if (prepend != 0)
  60. {
  61. if (ivecnpad != NULL)
  62. *pbstr = ALLOC_BSTR_BYTE_LEN(NULL, cbNeeded+2+18); // ivec & kv
  63. else
  64. *pbstr = ALLOC_BSTR_BYTE_LEN(NULL, cbNeeded+2); // just kv
  65. }
  66. else
  67. *pbstr = ALLOC_BSTR_BYTE_LEN(NULL, cbNeeded);
  68. if (*pbstr)
  69. {
  70. BYTE* pb = (BYTE*)pv;
  71. char* pch = (char*)*pbstr;
  72. int cchLine = 0;
  73. if (prepend != 0)
  74. {
  75. *pch++ = (char) prepend;
  76. if (ivecnpad != NULL)
  77. {
  78. for (i = 0; i < 9; i++)
  79. *pch++ = (char) ivecnpad[i];
  80. }
  81. }
  82. //
  83. // Main encoding loop
  84. //
  85. while (cb >= 3)
  86. {
  87. BYTE b0 = ((pb[0]>>2) & 0x3F);
  88. BYTE b1 = ((pb[0]&0x03)<<4) | ((pb[1]>>4) & 0x0F);
  89. BYTE b2 = ((pb[1]&0x0F)<<2) | ((pb[2]>>6) & 0x03);
  90. BYTE b3 = ((pb[2]&0x3F));
  91. *pch++ = rgwchBase64ASCII[b0];
  92. *pch++ = rgwchBase64ASCII[b1];
  93. *pch++ = rgwchBase64ASCII[b2];
  94. *pch++ = rgwchBase64ASCII[b3];
  95. pb += 3;
  96. cb -= 3;
  97. }
  98. if (cb==0)
  99. {
  100. // nothing to do
  101. }
  102. else if (cb==1)
  103. {
  104. BYTE b0 = ((pb[0]>>2) & 0x3F);
  105. BYTE b1 = ((pb[0]&0x03)<<4) | 0;
  106. *pch++ = rgwchBase64ASCII[b0];
  107. *pch++ = rgwchBase64ASCII[b1];
  108. *pch++ = '$';
  109. *pch++ = '$';
  110. }
  111. else if (cb==2)
  112. {
  113. BYTE b0 = ((pb[0]>>2) & 0x3F);
  114. BYTE b1 = ((pb[0]&0x03)<<4) | ((pb[1]>>4) & 0x0F);
  115. BYTE b2 = ((pb[1]&0x0F)<<2) | 0;
  116. *pch++ = rgwchBase64ASCII[b0];
  117. *pch++ = rgwchBase64ASCII[b1];
  118. *pch++ = rgwchBase64ASCII[b2];
  119. *pch++ = '$';
  120. }
  121. }
  122. else
  123. hr = E_OUTOFMEMORY;
  124. GIVEAWAY_BSTR(*pbstr);
  125. return hr;
  126. }
  127. // This function takes IN a single-char buffer, and puts the binhex
  128. // output into a bstr, but using only ASCII chars
  129. //
  130. // Function name : ToBase64
  131. // Description :
  132. // Return type : HRESULT
  133. // Argument : LPVOID pv
  134. // Argument : ULONG cbSize
  135. // Argument : char prepend
  136. // Argument : BSTR* pbstr
  137. //
  138. HRESULT CBinHex::ToBase64(LPVOID pv, UINT cbSize, char prepend, char ivecnpad[9], BSTR* pbstr)
  139. //
  140. // Encode and return the bytes in base 64
  141. //
  142. {
  143. UINT cb = cbSize, cbSafe, cchNeeded, cbNeeded, i;
  144. HRESULT hr = S_OK;
  145. *pbstr = NULL;
  146. if (cb % 3)
  147. cbSafe = cb + 3 - (cb % 3); // For padding
  148. else
  149. cbSafe = cb;
  150. // cbSafe is now a multiple of 3
  151. cchNeeded = (cbSafe*4/3); // 3 normal bytes --> 4 chars
  152. cbNeeded = cchNeeded * sizeof(WCHAR);
  153. if (prepend != 0)
  154. {
  155. if (ivecnpad != NULL)
  156. *pbstr = ALLOC_BSTR_BYTE_LEN(NULL, cbNeeded+2+18); // ivec & kv
  157. else
  158. *pbstr = ALLOC_BSTR_BYTE_LEN(NULL, cbNeeded+2); // just kv
  159. }
  160. else
  161. *pbstr = ALLOC_BSTR_BYTE_LEN(NULL, cbNeeded);
  162. if (*pbstr)
  163. {
  164. BYTE* pb = (BYTE*)pv;
  165. WCHAR* pch = *pbstr;
  166. int cchLine = 0;
  167. if (prepend != 0)
  168. {
  169. *pch++ = (WCHAR) prepend;
  170. if (ivecnpad != NULL)
  171. {
  172. for (i = 0; i < 9; i++)
  173. *pch++ = (WCHAR) ivecnpad[i];
  174. }
  175. }
  176. //
  177. // Main encoding loop
  178. //
  179. while (cb >= 3)
  180. {
  181. BYTE b0 = ((pb[0]>>2) & 0x3F);
  182. BYTE b1 = ((pb[0]&0x03)<<4) | ((pb[1]>>4) & 0x0F);
  183. BYTE b2 = ((pb[1]&0x0F)<<2) | ((pb[2]>>6) & 0x03);
  184. BYTE b3 = ((pb[2]&0x3F));
  185. *pch++ = rgwchBase64[b0];
  186. *pch++ = rgwchBase64[b1];
  187. *pch++ = rgwchBase64[b2];
  188. *pch++ = rgwchBase64[b3];
  189. pb += 3;
  190. cb -= 3;
  191. }
  192. if (cb==0)
  193. {
  194. // nothing to do
  195. }
  196. else if (cb==1)
  197. {
  198. BYTE b0 = ((pb[0]>>2) & 0x3F);
  199. BYTE b1 = ((pb[0]&0x03)<<4) | 0;
  200. *pch++ = rgwchBase64[b0];
  201. *pch++ = rgwchBase64[b1];
  202. *pch++ = L'$';
  203. *pch++ = L'$';
  204. }
  205. else if (cb==2)
  206. {
  207. BYTE b0 = ((pb[0]>>2) & 0x3F);
  208. BYTE b1 = ((pb[0]&0x03)<<4) | ((pb[1]>>4) & 0x0F);
  209. BYTE b2 = ((pb[1]&0x0F)<<2) | 0;
  210. *pch++ = rgwchBase64[b0];
  211. *pch++ = rgwchBase64[b1];
  212. *pch++ = rgwchBase64[b2];
  213. *pch++ = L'$';
  214. }
  215. }
  216. else
  217. hr = E_OUTOFMEMORY;
  218. GIVEAWAY_BSTR(*pbstr);
  219. return hr;
  220. }
  221. HRESULT CBinHex::PartFromBase64(LPSTR lpStr, BYTE *output, ULONG *numOutBytes)
  222. {
  223. HRESULT hr = S_OK;
  224. if (!output) return E_INVALIDARG;
  225. //
  226. // Loop over the input buffer until we get numOutBytes in output
  227. //
  228. ULONG bCurrent = 0; // what we're in the process of filling up
  229. int cbitFilled = 0; // how many bits in it we've filled
  230. ULONG numOut = 0;
  231. BYTE* pb = (BYTE*) output; // current destination (not filled)
  232. for (CHAR* pch=lpStr; *pch && numOut < *numOutBytes; pch++)
  233. {
  234. CHAR ch = *pch;
  235. //
  236. // Have we reached the end?
  237. //
  238. if (ch=='$')
  239. break;
  240. //
  241. // How much is this character worth?
  242. //
  243. BYTE bDigit = m_decodeArray[ch];
  244. if (bDigit==BBAD)
  245. {
  246. hr = E_INVALIDARG;
  247. break;
  248. }
  249. //
  250. // Add in its contribution
  251. //
  252. bCurrent <<= 6;
  253. bCurrent |= bDigit;
  254. cbitFilled += 6;
  255. //
  256. // If we've got enough, output a byte
  257. //
  258. if (cbitFilled >= 8)
  259. {
  260. ULONG b = (bCurrent >> (cbitFilled-8)); // get's top eight valid bits
  261. *pb++ = (BYTE)(b&0xFF); // store the byte away
  262. cbitFilled -= 8;
  263. numOut++;
  264. }
  265. } // for
  266. _ASSERT(numOut <= *numOutBytes);
  267. if (hr!=S_OK)
  268. {
  269. *numOutBytes = 0;
  270. }
  271. else
  272. {
  273. if (numOut < *numOutBytes)
  274. *numOutBytes = numOut;
  275. }
  276. return hr;
  277. }
  278. HRESULT CBinHex::PartFromWideBase64(LPWSTR bStr, BYTE *output, ULONG *numOutBytes)
  279. {
  280. HRESULT hr = S_OK;
  281. if (!output) return E_INVALIDARG;
  282. //
  283. // Loop over the input buffer until we get numOutBytes in output
  284. //
  285. ULONG bCurrent = 0; // what we're in the process of filling up
  286. int cbitFilled = 0; // how many bits in it we've filled
  287. ULONG numOut = 0;
  288. BYTE* pb = (BYTE*) output; // current destination (not filled)
  289. for (WCHAR* pwch=bStr; *pwch && numOut < *numOutBytes; pwch++)
  290. {
  291. WCHAR wch = *pwch;
  292. //
  293. // Have we reached the end?
  294. //
  295. if (wch==L'$')
  296. break;
  297. //
  298. // How much is this character worth?
  299. //
  300. if (wch > 255)
  301. {
  302. hr = E_INVALIDARG;
  303. break;
  304. }
  305. BYTE bDigit = m_decodeArray[wch];
  306. if (bDigit==BBAD)
  307. {
  308. hr = E_INVALIDARG;
  309. break;
  310. }
  311. //
  312. // Add in its contribution
  313. //
  314. bCurrent <<= 6;
  315. bCurrent |= bDigit;
  316. cbitFilled += 6;
  317. //
  318. // If we've got enough, output a byte
  319. //
  320. if (cbitFilled >= 8)
  321. {
  322. ULONG b = (bCurrent >> (cbitFilled-8)); // get's top eight valid bits
  323. *pb++ = (BYTE)(b&0xFF); // store the byte away
  324. cbitFilled -= 8;
  325. numOut++;
  326. }
  327. } // for
  328. _ASSERT(numOut <= *numOutBytes);
  329. if (hr!=S_OK)
  330. {
  331. *numOutBytes = 0;
  332. }
  333. else if (numOut < *numOutBytes)
  334. {
  335. *numOutBytes = numOut;
  336. }
  337. return hr;
  338. }