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.

617 lines
14 KiB

  1. //+--------------------------------------------------------------------------
  2. //
  3. // Microsoft Windows
  4. // Copyright (C) Microsoft Corporation, 1996 - 1999
  5. //
  6. // File: hex.cpp
  7. //
  8. // Contents: hex encode/decode implementation
  9. //
  10. //---------------------------------------------------------------------------
  11. #include <windows.h>
  12. #include <assert.h>
  13. #include <stdio.h>
  14. #include <dbgdef.h>
  15. #include "pkifmt.h"
  16. #include <tchar.h> // must be included after dbgdef.h
  17. __inline BOOL
  18. _IsWhiteSpaceChar(
  19. TCHAR ch)
  20. {
  21. return(
  22. TEXT(' ') == ch ||
  23. TEXT('\t') == ch ||
  24. TEXT('\r') == ch);
  25. }
  26. DWORD
  27. _DigToHex(
  28. IN TCHAR ch,
  29. OUT BYTE *pb)
  30. {
  31. BYTE b;
  32. DWORD dwErr = ERROR_SUCCESS;
  33. if (!_istxdigit(ch))
  34. {
  35. dwErr = ERROR_INVALID_DATA;
  36. #if DBG
  37. DbgPrintf(DBG_SS_TRACE, "bad hex data: %02x\n", ch);
  38. #endif //DBG
  39. goto BadHexDataError;
  40. }
  41. if (_istdigit(ch))
  42. {
  43. b = ch - TEXT('0');
  44. }
  45. else
  46. if (_istupper(ch))
  47. {
  48. b = ch - TEXT('A') + 10;
  49. }
  50. else
  51. {
  52. b = ch - TEXT('a') + 10;
  53. }
  54. *pb = b;
  55. ErrorReturn:
  56. return (dwErr);
  57. SET_ERROR(BadHexDataError, dwErr)
  58. }
  59. __inline BOOL
  60. _IsSkipChar(
  61. TCHAR ch)
  62. {
  63. return(
  64. TEXT(' ') == ch ||
  65. TEXT('\t') == ch ||
  66. TEXT('\r') == ch ||
  67. TEXT('\n') == ch ||
  68. TEXT(',') == ch ||
  69. TEXT('-') == ch);
  70. }
  71. DWORD
  72. _HexDecodeSimple(
  73. IN TCHAR const *pchIn,
  74. IN DWORD cchIn,
  75. OPTIONAL OUT BYTE *pbOut,
  76. IN OUT DWORD *pcbOut)
  77. {
  78. DWORD dwErr = ERROR_SUCCESS;
  79. TCHAR const *pch = pchIn;
  80. TCHAR const *pchEnd;
  81. DWORD cb = 0;
  82. BOOL fOverFlow = FALSE;
  83. pchEnd = &pchIn[cchIn];
  84. while (pch < pchEnd)
  85. {
  86. BYTE blo;
  87. BYTE bhi;
  88. if (_IsSkipChar(*pch))
  89. {
  90. pch++;
  91. continue;
  92. }
  93. dwErr = _DigToHex(*pch, &bhi);
  94. if (ERROR_SUCCESS != dwErr)
  95. {
  96. goto _DigToHexError;
  97. }
  98. pch++;
  99. if (pch >= pchEnd)
  100. {
  101. dwErr = ERROR_INVALID_DATA;
  102. goto BadHexDataError;
  103. }
  104. dwErr = _DigToHex(*pch, &blo);
  105. if (ERROR_SUCCESS != dwErr)
  106. {
  107. goto _DigToHexError;
  108. }
  109. pch++;
  110. if (NULL != pbOut)
  111. {
  112. if (cb >= *pcbOut)
  113. {
  114. fOverFlow = TRUE;
  115. pbOut = NULL;
  116. }
  117. else
  118. {
  119. *pbOut++ = blo | (bhi << 4);
  120. }
  121. }
  122. cb++;
  123. }
  124. *pcbOut = cb;
  125. if (fOverFlow)
  126. {
  127. dwErr = ERROR_MORE_DATA;
  128. goto MoreDataError;
  129. }
  130. ErrorReturn:
  131. return (dwErr);
  132. SET_ERROR(MoreDataError, dwErr)
  133. SET_ERROR(BadHexDataError, dwErr)
  134. TRACE_ERROR(_DigToHexError)
  135. }
  136. DWORD
  137. _HexParse(
  138. IN OUT TCHAR const **ppch,
  139. IN TCHAR const *pchEnd,
  140. IN DWORD cDigitMin,
  141. IN DWORD cDigitMax,
  142. OUT DWORD *pdwValue)
  143. {
  144. DWORD dwErr = ERROR_SUCCESS;
  145. TCHAR const *pch = *ppch;
  146. DWORD Value = 0;
  147. DWORD cDigit = 0;
  148. BYTE b;
  149. *pdwValue = 0;
  150. while (pch < pchEnd && cDigit <= cDigitMax)
  151. {
  152. //printf("HexParse %u/%u-%u, ch=%02x\n", cDigit, cDigitMin, cDigitMax, *pch);
  153. dwErr = _DigToHex(*pch, &b);
  154. if (ERROR_SUCCESS != dwErr)
  155. {
  156. break;
  157. }
  158. Value = b | (Value << 4);
  159. pch++;
  160. cDigit++;
  161. }
  162. //printf("HexParse %u/%u-%u, val=%x\n", cDigit, cDigitMin, cDigitMax, Value);
  163. if (cDigit < cDigitMin || cDigit > cDigitMax)
  164. {
  165. dwErr = ERROR_INVALID_DATA;
  166. goto BadHexDataError;
  167. }
  168. *pdwValue = Value;
  169. *ppch = pch;
  170. dwErr = ERROR_SUCCESS;
  171. ErrorReturn:
  172. return (dwErr);
  173. SET_ERROR(BadHexDataError, dwErr)
  174. }
  175. #define HS_ADDRESS 0
  176. #define HS_HEXDATA 1
  177. #define HS_ASCIIDATA 2
  178. #define HS_NEWLINE 3
  179. DWORD
  180. _HexDecodeComplex(
  181. IN TCHAR const *pchIn,
  182. IN DWORD cchIn,
  183. IN DWORD Flags,
  184. OPTIONAL OUT BYTE *pbOut,
  185. IN OUT DWORD *pcbOut)
  186. {
  187. TCHAR const *pch = pchIn;
  188. TCHAR const *pchEnd;
  189. DWORD cb = 0;
  190. DWORD dwErr;
  191. DWORD LastAddress = 0;
  192. DWORD Address;
  193. DWORD i;
  194. BOOL fOverFlow = FALSE;
  195. BOOL fPartialLastLine = FALSE;
  196. int *pStateBase;
  197. int *pState;
  198. int s_aASCIIADDRState[] = { HS_ADDRESS, HS_HEXDATA, HS_ASCIIDATA, HS_NEWLINE };
  199. int s_aASCIIState[] = { HS_HEXDATA, HS_ASCIIDATA, HS_NEWLINE };
  200. int s_aADDRState[] = { HS_ADDRESS, HS_HEXDATA, HS_NEWLINE };
  201. switch (Flags)
  202. {
  203. case CRYPT_STRING_HEXASCII: // 5
  204. pStateBase = s_aASCIIState;
  205. break;
  206. case CRYPT_STRING_HEXADDR: // 0xa
  207. pStateBase = s_aADDRState;
  208. break;
  209. case CRYPT_STRING_HEXASCIIADDR: // 0xb
  210. pStateBase = s_aASCIIADDRState;
  211. break;
  212. default:
  213. dwErr = ERROR_INVALID_DATA; //hr = E_INVALIDARG;
  214. goto FlagsError;
  215. }
  216. pState = pStateBase;
  217. pchEnd = &pchIn[cchIn];
  218. while (pch < pchEnd)
  219. {
  220. //printf("f=%x: *pState: %u ch=%02x\n", Flags, *pState, *pch);
  221. switch (*pState++)
  222. {
  223. case HS_ADDRESS:
  224. // decode 4 to 8 digit address:
  225. while (pch < pchEnd && _IsWhiteSpaceChar(*pch))
  226. {
  227. pch++;
  228. }
  229. if (pch >= pchEnd)
  230. {
  231. continue; // Done: no more data
  232. }
  233. dwErr = _HexParse(&pch, pchEnd, 4, 8, &Address);
  234. if (ERROR_SUCCESS != dwErr)
  235. {
  236. goto _HexParseError;
  237. }
  238. //printf("f=%x: Address: %x\n", Flags, Address);
  239. if (!fPartialLastLine &&
  240. 0 != LastAddress &&
  241. LastAddress + 16 != Address)
  242. {
  243. dwErr = ERROR_INVALID_DATA;
  244. goto BadHexDataError;
  245. }
  246. LastAddress = Address;
  247. break;
  248. case HS_HEXDATA:
  249. // decode up to 16 bytes of hex data
  250. for (i = 0; i < 16; i++)
  251. {
  252. DWORD Data;
  253. // decode 2 digit byte value:
  254. while (pch < pchEnd && _IsSkipChar(*pch))
  255. {
  256. pch++;
  257. }
  258. if (pch >= pchEnd)
  259. {
  260. break; // Done: no more data
  261. }
  262. if (fPartialLastLine)
  263. {
  264. //printf("f=%x: fPartialLastLine extra data: %02x\n", Flags, *pch);
  265. dwErr = ERROR_INVALID_DATA;
  266. goto DataAfterEndError;
  267. }
  268. dwErr = _HexParse(&pch, pchEnd, 2, 2, &Data);
  269. if (ERROR_SUCCESS != dwErr)
  270. {
  271. // Must be a partial last line. The only additional
  272. // data should be an optional partial ascii display on
  273. // the right, a newline, and possibly one more address
  274. // line.
  275. //printf("f=%x: fPartialLastLine = TRUE: %02x\n", Flags, *pch);
  276. fPartialLastLine = TRUE;
  277. break;
  278. }
  279. //printf("f=%x: Data[%u]: %02x\n", Flags, i, Data);
  280. if (NULL != pbOut)
  281. {
  282. if (cb >= *pcbOut)
  283. {
  284. fOverFlow = TRUE;
  285. pbOut = NULL;
  286. }
  287. else
  288. {
  289. *pbOut++ = (BYTE) Data;
  290. }
  291. }
  292. cb++;
  293. }
  294. break;
  295. case HS_ASCIIDATA:
  296. // skip up to 16 non-whitespace characters
  297. while (pch < pchEnd && _IsWhiteSpaceChar(*pch))
  298. {
  299. pch++;
  300. }
  301. for (i = 0; i < 16; i++)
  302. {
  303. if (pch >= pchEnd || TEXT(' ') > *pch || TEXT('~') < *pch)
  304. {
  305. break;
  306. }
  307. //printf("f=%x: Ascii[%u]: %c\n", Flags, i, *pch);
  308. pch++;
  309. }
  310. break;
  311. case HS_NEWLINE:
  312. // skip whitespace characters and a newline
  313. while (pch < pchEnd && _IsWhiteSpaceChar(*pch))
  314. {
  315. //printf("f=%x: NL skip: %02x\n", Flags, *pch);
  316. pch++;
  317. }
  318. //printf("f=%x: NL: %02x\n", Flags, *pch);
  319. if (pch >= pchEnd)
  320. {
  321. continue; // Done: no more data
  322. }
  323. if (TEXT('\n') != *pch)
  324. {
  325. //printf("f=%x: Extra Data: %02x\n", Flags, *pch);
  326. dwErr = ERROR_INVALID_DATA;
  327. goto ExtraDataOnLineError;
  328. }
  329. //printf("f=%x: NewLine\n", Flags);
  330. pch++;
  331. pState = pStateBase;
  332. break;
  333. default:
  334. assert(!"Bad *pState");
  335. }
  336. }
  337. *pcbOut = cb;
  338. if (fOverFlow)
  339. {
  340. dwErr = ERROR_MORE_DATA;
  341. goto MoreDataError;
  342. }
  343. dwErr = ERROR_SUCCESS;
  344. ErrorReturn:
  345. return(dwErr);
  346. SET_ERROR(MoreDataError, dwErr)
  347. SET_ERROR(ExtraDataOnLineError, dwErr)
  348. SET_ERROR(BadHexDataError, dwErr)
  349. TRACE_ERROR(_HexParseError)
  350. SET_ERROR(DataAfterEndError, dwErr)
  351. SET_ERROR(FlagsError, dwErr)
  352. }
  353. DWORD
  354. HexDecode(
  355. IN TCHAR const *pchIn,
  356. IN DWORD cchIn,
  357. IN DWORD Flags,
  358. OPTIONAL OUT BYTE *pbOut,
  359. IN OUT DWORD *pcbOut)
  360. {
  361. DWORD dwErr;
  362. if (CRYPT_STRING_HEX == Flags)
  363. {
  364. dwErr = _HexDecodeSimple(pchIn, cchIn, pbOut, pcbOut);
  365. if (ERROR_SUCCESS != dwErr)
  366. {
  367. #if DBG
  368. //skip ERROR_INVALID_DATA dbg print
  369. if (ERROR_INVALID_DATA == dwErr)
  370. {
  371. SetLastError(dwErr);
  372. goto ErrorReturn;
  373. }
  374. #endif
  375. goto _HexDecodeSimpleError;
  376. }
  377. }
  378. else
  379. {
  380. dwErr = _HexDecodeComplex(pchIn, cchIn, Flags, pbOut, pcbOut);
  381. if (ERROR_SUCCESS != dwErr)
  382. {
  383. #if DBG
  384. //skip ERROR_INVALID_DATA dbg print
  385. if (ERROR_INVALID_DATA == dwErr)
  386. {
  387. SetLastError(dwErr);
  388. goto ErrorReturn;
  389. }
  390. #endif
  391. goto _HexDecodeComplexError;
  392. }
  393. }
  394. ErrorReturn:
  395. return(dwErr);
  396. TRACE_ERROR(_HexDecodeSimpleError)
  397. TRACE_ERROR(_HexDecodeComplexError)
  398. }
  399. TCHAR
  400. _IsPrintableChar(TCHAR ch)
  401. {
  402. if (ch < TEXT(' ') || ch > TEXT('~'))
  403. {
  404. ch = TEXT('.');
  405. }
  406. return(ch);
  407. }
  408. // Encode a BYTE array into text as a hex dump.
  409. // Use CR-LF pairs for line breaks, unless CRYPT_STRING_NOCR is set.
  410. // Do not '\0' terminate the text string -- that's handled by the caller.
  411. DWORD
  412. HexEncode(
  413. IN BYTE const *pbIn,
  414. IN DWORD cbIn,
  415. IN DWORD Flags,
  416. OPTIONAL OUT TCHAR *pchOut,
  417. IN OUT DWORD *pcchOut)
  418. {
  419. TCHAR const *pszsep;
  420. TCHAR const *psznl;
  421. DWORD r;
  422. DWORD i;
  423. DWORD cbremain;
  424. DWORD cchOut = 0;
  425. DWORD cch;
  426. TCHAR *pch = pchOut;
  427. DWORD dwErr = ERROR_MORE_DATA;
  428. BOOL fAscii = FALSE;
  429. BOOL fAddress = FALSE;
  430. TCHAR szAddress[32];
  431. BOOL fNoCR = 0 != (CRYPT_STRING_NOCR & Flags);
  432. switch (~CRYPT_STRING_NOCR & Flags)
  433. {
  434. case CRYPT_STRING_HEX:
  435. break;
  436. case CRYPT_STRING_HEXASCII:
  437. fAscii = TRUE;
  438. break;
  439. case CRYPT_STRING_HEXADDR:
  440. fAddress = TRUE;
  441. break;
  442. case CRYPT_STRING_HEXASCIIADDR:
  443. fAscii = TRUE;
  444. fAddress = TRUE;
  445. break;
  446. default:
  447. dwErr = ERROR_INVALID_DATA; //hr = E_INVALIDARG;
  448. goto FlagsError;
  449. }
  450. for (r = 0; r < cbIn; r += 16)
  451. {
  452. DWORD iEnd;
  453. cbremain = cbIn - r;
  454. iEnd = min(cbremain, 16);
  455. for (i = 0; i < iEnd; i++)
  456. {
  457. psznl = TEXT("");
  458. szAddress[0] = TEXT('\0');
  459. pszsep = TEXT(" ");
  460. if ((i % 8) == 0) // 0 or 8
  461. {
  462. pszsep = TEXT(" ");
  463. if (i == 0) // 0
  464. {
  465. if (fAddress)
  466. {
  467. _stprintf(szAddress, TEXT("%04x"), r);
  468. }
  469. pszsep = TEXT("\t");
  470. if (r != 0) // starting new line
  471. {
  472. psznl = fNoCR? TEXT("\n") : TEXT("\r\n");
  473. pszsep = TEXT("\t");
  474. }
  475. }
  476. }
  477. cch = _tcslen(psznl) + _tcslen(szAddress) + _tcslen(pszsep) + 2;
  478. if (NULL != pchOut)
  479. {
  480. if (cchOut + cch + 1 > *pcchOut)
  481. {
  482. goto MoreDataError;
  483. }
  484. _stprintf(
  485. pch,
  486. TEXT("%s%s%s%02x"),
  487. psznl,
  488. szAddress,
  489. pszsep,
  490. pbIn[r + i]);
  491. pch += cch;
  492. assert(TEXT('\0') == *pch);
  493. assert(pch == &pchOut[cchOut + cch]);
  494. }
  495. cchOut += cch;
  496. }
  497. if (fAscii && 0 != i)
  498. {
  499. cch = 3 + (16 - i)*3 + ((i <= 8)? 1 : 0);
  500. if (NULL != pchOut)
  501. {
  502. if (cchOut + cch + iEnd + 1 > *pcchOut)
  503. {
  504. goto MoreDataError;
  505. }
  506. _stprintf(pch, TEXT("%*s"), cch, TEXT(""));
  507. pch += cch;
  508. assert(TEXT('\0') == *pch);
  509. assert(pch == &pchOut[cchOut + cch]);
  510. for (i = 0; i < iEnd; i++)
  511. {
  512. *pch++ = _IsPrintableChar(pbIn[r + i]);
  513. assert(pch == &pchOut[cchOut + cch + i + 1]);
  514. }
  515. }
  516. cchOut += cch + iEnd;
  517. }
  518. }
  519. if (r != 0)
  520. {
  521. DWORD cchnl = fNoCR? 1 : 2;
  522. if (NULL != pchOut)
  523. {
  524. if (cchOut + cchnl > *pcchOut)
  525. {
  526. goto MoreDataError;
  527. }
  528. if (!fNoCR)
  529. {
  530. *pch++ = TEXT('\r');
  531. }
  532. *pch++ = TEXT('\n');
  533. assert(pch == &pchOut[cchOut + cchnl]);
  534. }
  535. cchOut += cchnl;
  536. }
  537. *pcchOut = cchOut;
  538. dwErr = ERROR_SUCCESS;
  539. ErrorReturn:
  540. return(dwErr);
  541. SET_ERROR(MoreDataError, dwErr)
  542. SET_ERROR(FlagsError, dwErr)
  543. }