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.

1647 lines
33 KiB

  1. /*++
  2. Copyright (C) Microsoft Corporation, 1996 - 1999
  3. Module Name:
  4. misc
  5. Abstract:
  6. This module contains an interesting collection of routines that are
  7. generally useful in the Calais context, but don't seem to fit anywhere else.
  8. Author:
  9. Doug Barlow (dbarlow) 11/14/1996
  10. Environment:
  11. Win32, C++ w/ Exceptions
  12. Notes:
  13. ?Notes?
  14. --*/
  15. #ifndef WIN32_LEAN_AND_MEAN
  16. #define WIN32_LEAN_AND_MEAN
  17. #endif
  18. #include <Windows.h>
  19. #include <SCardLib.h>
  20. #include <stdio.h>
  21. #include <stdarg.h>
  22. #include <tchar.h>
  23. /*++
  24. MemCompare:
  25. This routine compares memory sections.
  26. Arguments:
  27. pbOne supplies the address of the first block of memory
  28. pbTwo supplies the address of the second block of memory
  29. cbLength supplies the length of the two memory segments.
  30. Return Value:
  31. the difference between the first two differing bytes, or zero if they're the
  32. identical.
  33. Throws:
  34. None
  35. Author:
  36. Doug Barlow (dbarlow) 11/26/1996
  37. --*/
  38. int
  39. MemCompare(
  40. IN LPCBYTE pbOne,
  41. IN LPCBYTE pbTwo,
  42. IN DWORD cbLength)
  43. {
  44. for (DWORD index = 0; index < cbLength; index += 1)
  45. {
  46. if (*pbOne++ != *pbTwo++)
  47. return (int)*(--pbOne) - (int)*(--pbTwo);
  48. }
  49. return 0;
  50. }
  51. /*++
  52. MStrAdd:
  53. This method adds a string to the end of a multistring contained in a
  54. CBuffer. The CBuffer may be empty, in which case its value becomes a
  55. multistring with the single string element.
  56. Arguments:
  57. bfMsz supplies the multistring to be modified.
  58. szAdd supplies the string to append.
  59. Return Value:
  60. the number of strings in the resulting multistring.
  61. Throws:
  62. None
  63. Author:
  64. Doug Barlow (dbarlow) 1/29/1997
  65. --*/
  66. DWORD
  67. MStrAdd(
  68. IN OUT CBuffer &bfMsz,
  69. IN LPCSTR szAdd)
  70. {
  71. DWORD dwLen, dwAddLen;
  72. CBuffer bfTmp;
  73. dwLen = bfMsz.Length();
  74. if (0 < dwLen)
  75. {
  76. ASSERT(2 * sizeof(TCHAR) <= dwLen);
  77. ASSERT(0 == *(LPCTSTR)(bfMsz.Access(dwLen - sizeof(TCHAR))));
  78. ASSERT(0 == *(LPCTSTR)(bfMsz.Access(dwLen - 2 * sizeof(TCHAR))));
  79. dwLen -= sizeof(TCHAR);
  80. }
  81. dwAddLen = MoveString(bfTmp, szAdd);
  82. bfMsz.Presize((dwLen + dwAddLen + 1) * sizeof(TCHAR), TRUE);
  83. bfMsz.Resize(dwLen, TRUE); // Trim one trailing NULL, if any.
  84. bfMsz.Append(bfTmp.Access(), dwAddLen * sizeof(TCHAR));
  85. bfMsz.Append((LPBYTE)TEXT("\000"), sizeof(TCHAR));
  86. return MStrLen(bfMsz);
  87. }
  88. DWORD
  89. MStrAdd(
  90. IN OUT CBuffer &bfMsz,
  91. IN LPCWSTR szAdd)
  92. {
  93. DWORD dwLen, dwAddLen;
  94. CBuffer bfTmp;
  95. dwLen = bfMsz.Length();
  96. if (0 < dwLen)
  97. {
  98. ASSERT(2 * sizeof(TCHAR) <= dwLen);
  99. ASSERT(0 == *(LPCTSTR)(bfMsz.Access(dwLen - sizeof(TCHAR))));
  100. ASSERT(0 == *(LPCTSTR)(bfMsz.Access(dwLen - 2 * sizeof(TCHAR))));
  101. dwLen -= sizeof(TCHAR);
  102. }
  103. dwAddLen = MoveString(bfTmp, szAdd);
  104. bfMsz.Presize((dwLen + dwAddLen + 2) * sizeof(TCHAR), TRUE);
  105. bfMsz.Resize(dwLen, TRUE); // Trim one trailing NULL, if any.
  106. bfMsz.Append(bfTmp.Access(), dwAddLen * sizeof(TCHAR));
  107. bfMsz.Append((LPBYTE)TEXT("\000"), sizeof(TCHAR));
  108. return MStrLen(bfMsz);
  109. }
  110. /*++
  111. MStrLen:
  112. This routine determines the length of a Multi-string, in characters.
  113. Arguments:
  114. mszString supplies the string to compute the length of.
  115. Return Value:
  116. The length of the string, in characters, including trailing zeroes.
  117. Author:
  118. Doug Barlow (dbarlow) 11/14/1996
  119. --*/
  120. DWORD
  121. MStrLen(
  122. LPCSTR mszString)
  123. {
  124. DWORD dwLen, dwTotLen = 0;
  125. for (;;)
  126. {
  127. dwLen = lstrlenA(&mszString[dwTotLen]);
  128. dwTotLen += dwLen + 1;
  129. if (0 == dwLen)
  130. break;
  131. }
  132. if (2 > dwTotLen)
  133. dwTotLen = 2; // Include the second trailing null character.
  134. return dwTotLen;
  135. }
  136. DWORD
  137. MStrLen(
  138. LPCWSTR mszString)
  139. {
  140. DWORD dwLen, dwTotLen = 0;
  141. for (;;)
  142. {
  143. dwLen = lstrlenW(&mszString[dwTotLen]);
  144. dwTotLen += dwLen + 1;
  145. if (0 == dwLen)
  146. break;
  147. }
  148. if (2 > dwTotLen)
  149. dwTotLen = 2; // Include the second trailing null character.
  150. return dwTotLen;
  151. }
  152. /*++
  153. FirstString:
  154. This routine returns a pointer to the first string in a multistring, or NULL
  155. if there aren't any.
  156. Arguments:
  157. szMultiString - This supplies the address of the current position within a
  158. Multi-string structure.
  159. Return Value:
  160. The address of the first null-terminated string in the structure, or NULL if
  161. there are no strings.
  162. Author:
  163. Doug Barlow (dbarlow) 11/25/1996
  164. --*/
  165. LPCTSTR
  166. FirstString(
  167. IN LPCTSTR szMultiString)
  168. {
  169. LPCTSTR szFirst = NULL;
  170. try
  171. {
  172. if (0 != *szMultiString)
  173. szFirst = szMultiString;
  174. }
  175. catch (...) {}
  176. return szFirst;
  177. }
  178. /*++
  179. NextString:
  180. In some cases, the Smartcard API returns multiple strings, separated by Null
  181. characters, and terminated by two null characters in a row. This routine
  182. simplifies access to such structures. Given the current string in a
  183. multi-string structure, it returns the next string, or NULL if no other
  184. strings follow the current string.
  185. Arguments:
  186. szMultiString - This supplies the address of the current position within a
  187. Multi-string structure.
  188. Return Value:
  189. The address of the next Null-terminated string in the structure, or NULL if
  190. no more strings follow.
  191. Author:
  192. Doug Barlow (dbarlow) 8/12/1996
  193. --*/
  194. LPCTSTR
  195. NextString(
  196. IN LPCTSTR szMultiString)
  197. {
  198. LPCTSTR szNext;
  199. try
  200. {
  201. DWORD cchLen = lstrlen(szMultiString);
  202. if (0 == cchLen)
  203. szNext = NULL;
  204. else
  205. {
  206. szNext = szMultiString + cchLen + 1;
  207. if (0 == *szNext)
  208. szNext = NULL;
  209. }
  210. }
  211. catch (...)
  212. {
  213. szNext = NULL;
  214. }
  215. return szNext;
  216. }
  217. /*++
  218. StringIndex:
  219. In some cases, the Smartcard API returns multiple strings, separated by Null
  220. characters, and terminated by two null characters in a row. This routine
  221. simplifies access to such structures. Given the starting address of a
  222. multi-string structure, it returns the nth string in the structure, where n
  223. is a zero-based index. If the supplied value for n exceeds the number of
  224. strings in the structure, NULL is returned.
  225. Arguments:
  226. szMultiString - This supplies the address of the Multi-string structure.
  227. dwIndex - This supplies the index value into the structure.
  228. Return Value:
  229. The address of the specified Null-terminated string in the structure, or
  230. NULL if dwIndex indexes beyond the end of the structure.
  231. Author:
  232. Doug Barlow (dbarlow) 8/12/1996
  233. --*/
  234. LPCTSTR
  235. StringIndex(
  236. IN LPCTSTR szMultiString,
  237. IN DWORD dwIndex)
  238. {
  239. LPCTSTR szCurrent = szMultiString;
  240. try
  241. {
  242. DWORD index;
  243. for (index = 0; (index < dwIndex) && (NULL != szCurrent); index += 1)
  244. szCurrent = NextString(szCurrent);
  245. }
  246. catch (...)
  247. {
  248. szCurrent = NULL;
  249. }
  250. return szCurrent;
  251. }
  252. /*++
  253. MStringCount:
  254. This routine returns the count of the number of strings in a multistring
  255. Arguments:
  256. mszInString supplies the input string to be sorted.
  257. Return Value:
  258. The count of strings
  259. Throws:
  260. None
  261. Author:
  262. Ross Garmoe (v-rossg) 12/05/1996
  263. --*/
  264. DWORD
  265. MStringCount(
  266. LPCTSTR mszInString)
  267. {
  268. LPCTSTR szCurrent;
  269. DWORD cStr = 0;
  270. //
  271. // Count the strings
  272. //
  273. for (szCurrent = FirstString(mszInString);
  274. NULL != szCurrent;
  275. szCurrent = NextString(szCurrent))
  276. cStr++;
  277. return (cStr);
  278. }
  279. /*++
  280. MStringSort:
  281. This routine rearranges a multistring so that the elements are sorted and
  282. duplicates are eliminated.
  283. Arguments:
  284. mszInString supplies the input string to be sorted.
  285. bfOutString receives the sorted string.
  286. Return Value:
  287. Count of strings in the multistring
  288. Throws:
  289. None
  290. Author:
  291. Doug Barlow (dbarlow) 11/25/1996
  292. --*/
  293. DWORD
  294. MStringSort(
  295. LPCTSTR mszInString,
  296. CBuffer &bfOutString)
  297. {
  298. LPCTSTR szCurrent;
  299. LPCTSTR szTmp;
  300. CDynamicArray<const TCHAR> rgszElements;
  301. DWORD ix, jx, kx, nMax;
  302. int nDiff;
  303. //
  304. // Set up for the sort.
  305. //
  306. for (szCurrent = FirstString(mszInString);
  307. NULL != szCurrent;
  308. szCurrent = NextString(szCurrent))
  309. rgszElements.Add(szCurrent);
  310. //
  311. // Do a simple bubble sort, eliminating duplicates. (We don't use qsort
  312. // here, to ensure that the Run-time library doesn't get pulled in.)
  313. //
  314. nMax = rgszElements.Count();
  315. if (0 == nMax)
  316. {
  317. bfOutString.Set((LPCBYTE)TEXT("\000"), 2 * sizeof(TCHAR));
  318. return (nMax); // No elements implies nothing to do.
  319. }
  320. for (ix = 0; ix < nMax; ix += 1)
  321. {
  322. for (jx = nMax - 1; ix < jx; jx -= 1)
  323. {
  324. nDiff = lstrcmpi(rgszElements[jx - 1], rgszElements[jx]);
  325. if (0 < nDiff)
  326. {
  327. szTmp = rgszElements.Get(jx - 1);
  328. rgszElements.Set(jx - 1, rgszElements.Get(jx));
  329. rgszElements.Set(jx, szTmp);
  330. }
  331. else if (0 == nDiff)
  332. {
  333. for (kx = jx; kx < nMax - 1; kx += 1)
  334. rgszElements.Set(kx, rgszElements.Get(kx + 1));
  335. rgszElements.Set(nMax -1, NULL);
  336. nMax -= 1;
  337. }
  338. // else 0 > nDiff, which is what we want.
  339. }
  340. }
  341. //
  342. // Write the sorted strings to the output buffer.
  343. //
  344. jx = 0;
  345. for (ix = 0; ix < nMax; ix += 1)
  346. jx += lstrlen(rgszElements[ix]) + 1;
  347. bfOutString.Presize((jx + 2) * sizeof(TCHAR));
  348. bfOutString.Reset();
  349. for (ix = 0; ix < nMax; ix += 1)
  350. {
  351. szTmp = rgszElements[ix];
  352. bfOutString.Append(
  353. (LPCBYTE)szTmp,
  354. (lstrlen(szTmp) + 1) * sizeof(TCHAR));
  355. }
  356. bfOutString.Append((LPCBYTE)TEXT("\000"), sizeof(TCHAR));
  357. return (nMax);
  358. }
  359. /*++
  360. MStringMerge:
  361. This routine merges two Multistrings into a single multistring without
  362. duplicate entries.
  363. Arguments:
  364. mszOne supplies the first multistring.
  365. mszTwo supplies the secong multistring.
  366. bfOutString receives the combined strings.
  367. Return Value:
  368. Count of strings in the multistring
  369. Throws:
  370. None
  371. Author:
  372. Doug Barlow (dbarlow) 11/25/1996
  373. --*/
  374. DWORD
  375. MStringMerge(
  376. LPCTSTR mszOne,
  377. LPCTSTR mszTwo,
  378. CBuffer &bfOutString)
  379. {
  380. DWORD dwLenOne = (MStrLen(mszOne) - 1) * sizeof(TCHAR);
  381. DWORD dwLenTwo = MStrLen(mszTwo) * sizeof(TCHAR);
  382. CBuffer bfTmp;
  383. bfTmp.Presize((dwLenOne + dwLenTwo) * sizeof(TCHAR));
  384. bfTmp.Set((LPCBYTE)mszOne, dwLenOne);
  385. bfTmp.Append((LPCBYTE)mszTwo, dwLenTwo);
  386. return MStringSort((LPCTSTR)bfTmp.Access(), bfOutString);
  387. }
  388. /*++
  389. MStringCommon:
  390. This routine finds strings which are common to both supplied multistrings,
  391. and returns the list of commonalities.
  392. Arguments:
  393. mszOne supplies the first multistring.
  394. mszTwo supplies the secong multistring.
  395. bfOutString receives the intersection of the strings.
  396. Return Value:
  397. Count of strings in the multistring
  398. Throws:
  399. None
  400. Author:
  401. Doug Barlow (dbarlow) 11/25/1996
  402. --*/
  403. DWORD
  404. MStringCommon(
  405. LPCTSTR mszOne,
  406. LPCTSTR mszTwo,
  407. CBuffer &bfOutString)
  408. {
  409. CBuffer bfOne, bfTwo;
  410. LPCTSTR szOne, szTwo;
  411. DWORD dwStrings = 0;
  412. int nDiff;
  413. bfOutString.Reset();
  414. MStringSort(mszOne, bfOne);
  415. MStringSort(mszTwo, bfTwo);
  416. szOne = FirstString(bfOne);
  417. szTwo = FirstString(bfTwo);
  418. while ((NULL != szOne) && (NULL != szTwo))
  419. {
  420. nDiff = lstrcmpi(szOne, szTwo);
  421. if (0 > nDiff)
  422. szOne = NextString(szOne);
  423. else if (0 < nDiff)
  424. szTwo = NextString(szTwo);
  425. else // a match!
  426. {
  427. bfOutString.Append(
  428. (LPCBYTE)szOne,
  429. (lstrlen(szOne) + 1) * sizeof(TCHAR));
  430. szOne = NextString(szOne);
  431. szTwo = NextString(szTwo);
  432. dwStrings += 1;
  433. }
  434. }
  435. if (0 == dwStrings)
  436. bfOutString.Append((LPCBYTE)TEXT("\000"), 2 * sizeof(TCHAR));
  437. else
  438. bfOutString.Append((LPCBYTE)TEXT("\000"), sizeof(TCHAR));
  439. return dwStrings;
  440. }
  441. /*++
  442. MStringRemove:
  443. This routine scans the first supplied multistring, removing any entries that
  444. exist in the second string.
  445. Arguments:
  446. mszOne supplies the first multistring.
  447. mszTwo supplies the secong multistring.
  448. bfOutString receives the value of the first string without the second
  449. string.
  450. Return Value:
  451. Number of strings in output buffer
  452. Throws:
  453. None
  454. Author:
  455. Doug Barlow (dbarlow) 11/25/1996
  456. --*/
  457. DWORD
  458. MStringRemove(
  459. LPCTSTR mszOne,
  460. LPCTSTR mszTwo,
  461. CBuffer &bfOutString)
  462. {
  463. CBuffer bfOne, bfTwo;
  464. LPCTSTR szOne, szTwo;
  465. int nDiff;
  466. DWORD cStr = 0;
  467. bfOutString.Reset();
  468. MStringSort(mszOne, bfOne);
  469. MStringSort(mszTwo, bfTwo);
  470. szOne = FirstString(bfOne);
  471. szTwo = FirstString(bfTwo);
  472. while ((NULL != szOne) && (NULL != szTwo))
  473. {
  474. nDiff = lstrcmpi(szOne, szTwo);
  475. if (0 > nDiff)
  476. {
  477. bfOutString.Append(
  478. (LPCBYTE)szOne,
  479. (lstrlen(szOne) + 1) * sizeof(TCHAR));
  480. szOne = NextString(szOne);
  481. cStr++;
  482. }
  483. else if (0 < nDiff)
  484. {
  485. szTwo = NextString(szTwo);
  486. }
  487. else // a match!
  488. {
  489. szOne = NextString(szOne);
  490. szTwo = NextString(szTwo);
  491. }
  492. }
  493. while (NULL != szOne)
  494. {
  495. bfOutString.Append(
  496. (LPCBYTE)szOne,
  497. (lstrlen(szOne) + 1) * sizeof(TCHAR));
  498. szOne = NextString(szOne);
  499. cStr++;
  500. }
  501. bfOutString.Append(
  502. (LPCBYTE)TEXT("\000"),
  503. (DWORD)(0 == cStr ? 2 * sizeof(TCHAR) :sizeof(TCHAR)));
  504. return cStr;
  505. }
  506. /*++
  507. ParseAtr:
  508. This routine parses an ATR string.
  509. Arguments:
  510. pbAtr supplies the ATR string.
  511. pdwAtrLen receives the length of the ATR string. This is an optional
  512. parameter, and may be NULL.
  513. pdwHistOffset receives the offset into the ATR string at which the history
  514. string starts; i.e., the history string is at pbAtr[*pdwOffset].
  515. pcbHisory receives the length of the history string, in bytes.
  516. cbMaxLen supplies the maximum length of this ATR string. Typically this is
  517. 33, but you can restrict it to less by setting this parameter.
  518. Return Value:
  519. TRUE - Valid ATR
  520. FALSE - Invalid ATR
  521. Author:
  522. Doug Barlow (dbarlow) 11/14/1996
  523. --*/
  524. BOOL
  525. ParseAtr(
  526. LPCBYTE pbAtr,
  527. LPDWORD pdwAtrLen,
  528. LPDWORD pdwHistOffset,
  529. LPDWORD pcbHistory,
  530. DWORD cbMaxLen)
  531. {
  532. static const BYTE rgbYMap[] = {
  533. 0, // 0000
  534. 1, // 0001
  535. 1, // 0010
  536. 2, // 0011
  537. 1, // 0100
  538. 2, // 0101
  539. 2, // 0110
  540. 3, // 0111
  541. 1, // 1000
  542. 2, // 1001
  543. 2, // 1010
  544. 3, // 1011
  545. 2, // 1100
  546. 3, // 1101
  547. 3, // 1110
  548. 4 }; // 1111
  549. DWORD dwHistLen, dwHistOffset, dwTDLen, dwIndex, dwAtrLen;
  550. BOOL fTck = FALSE;
  551. ASSERT(33 >= cbMaxLen);
  552. try
  553. {
  554. //
  555. // Get the ATR string, if any.
  556. //
  557. if ((0x3b != pbAtr[0]) && (0x3f != pbAtr[0]))
  558. throw (DWORD)ERROR_NOT_SUPPORTED;
  559. dwHistLen = pbAtr[1] & 0x0f;
  560. dwIndex = 1;
  561. dwTDLen = 0;
  562. for (;;)
  563. {
  564. dwIndex += dwTDLen;
  565. dwTDLen = rgbYMap[(pbAtr[dwIndex] >> 4) & 0x0f];
  566. if (cbMaxLen < dwIndex + dwTDLen + dwHistLen)
  567. throw (DWORD)ERROR_INVALID_DATA;
  568. if (0 == dwTDLen)
  569. break;
  570. if (0 != (pbAtr[dwIndex] & 0x80))
  571. {
  572. if (0 != (pbAtr[dwIndex + dwTDLen] & 0x0f))
  573. fTck = TRUE;
  574. }
  575. else
  576. break;
  577. }
  578. dwIndex += dwTDLen + 1;
  579. dwHistOffset = dwIndex;
  580. dwAtrLen = dwIndex + dwHistLen + (fTck ? 1 : 0);
  581. if (cbMaxLen < dwAtrLen)
  582. throw (DWORD)ERROR_INVALID_DATA;
  583. if (fTck)
  584. {
  585. BYTE bXor = 0;
  586. for (dwIndex = 1; dwIndex < dwAtrLen; dwIndex += 1)
  587. bXor ^= pbAtr[dwIndex];
  588. if (0 != bXor)
  589. throw (DWORD)ERROR_INVALID_DATA;
  590. }
  591. }
  592. catch (...)
  593. {
  594. return FALSE;
  595. }
  596. //
  597. // Let the caller in on what we know.
  598. //
  599. if (NULL != pdwAtrLen)
  600. *pdwAtrLen = dwAtrLen;
  601. if (NULL != pdwHistOffset)
  602. *pdwHistOffset = dwHistOffset;
  603. if (NULL != pcbHistory)
  604. *pcbHistory = dwHistLen;
  605. return TRUE;
  606. }
  607. /*++
  608. AtrCompare:
  609. This routine compares two ATRs for equality, given an optional ATR mask. If
  610. the mask is supplied, ATR1 XORed against the mask must match ATR2.
  611. Arguments:
  612. pbAtr1 supplies the first ATR.
  613. pbAtr2 supplies the second ATR,
  614. pbMask supplies the ATR mask associated with the 2nd ATR. If this
  615. parameter is NULL, no mask is used.
  616. cbAtr2 supplies the length of ATR2 and it's mask. This value may be zero
  617. if the length should be derived from ATR2.
  618. Return Value:
  619. TRUE - They are identical
  620. FALSE - They differ.
  621. Author:
  622. Doug Barlow (dbarlow) 11/25/1996
  623. --*/
  624. BOOL
  625. AtrCompare(
  626. LPCBYTE pbAtr1,
  627. LPCBYTE pbAtr2,
  628. LPCBYTE pbMask,
  629. DWORD cbAtr2)
  630. {
  631. DWORD dwAtr1Len = 0;
  632. DWORD dwAtr2Len = 0;
  633. //
  634. // Trivial checks.
  635. //
  636. if (!ParseAtr(pbAtr1, &dwAtr1Len))
  637. return FALSE; // Invalid ATR.
  638. if ((NULL == pbMask) || (0 == cbAtr2))
  639. {
  640. if (!ParseAtr(pbAtr2, &dwAtr2Len))
  641. return FALSE; // Invalid ATR.
  642. if ((0 != cbAtr2) && (dwAtr2Len != cbAtr2))
  643. return FALSE; // Lengths don't match.
  644. if (dwAtr1Len != dwAtr2Len)
  645. return FALSE; // Different lengths.
  646. }
  647. else
  648. {
  649. dwAtr2Len = cbAtr2;
  650. if (dwAtr1Len != dwAtr2Len)
  651. return FALSE; // Different lengths.
  652. }
  653. //
  654. // Apply the mask, if any.
  655. //
  656. if (NULL != pbMask)
  657. {
  658. for (DWORD index = 0; index < dwAtr2Len; index += 1)
  659. {
  660. if ((pbAtr1[index] & pbMask[index]) != pbAtr2[index])
  661. return FALSE; // Byte mismatch.
  662. }
  663. }
  664. else
  665. {
  666. for (DWORD index = 0; index < dwAtr2Len; index += 1)
  667. {
  668. if (pbAtr1[index] != pbAtr2[index])
  669. return FALSE; // Byte mismatch.
  670. }
  671. }
  672. //
  673. // If we get here, they match.
  674. //
  675. return TRUE;
  676. }
  677. /*++
  678. MoveString:
  679. This routine moves an ASCII or UNICODE string into a buffer, converting to
  680. the character set in use.
  681. Arguments:
  682. bfDst receives the string, converted to TCHARs, and NULL terminated.
  683. szSrc supplies the original string.
  684. dwLength supplies the length of the string, with or without trailing
  685. nulls, in characters. A -1 value implies the length should be
  686. computed based on a trailing null.
  687. Return Value:
  688. The actual number of characters in the resultant string, including the
  689. trailing null.
  690. Throws:
  691. Errors encountered, as DWORDS.
  692. Author:
  693. Doug Barlow (dbarlow) 2/12/1997
  694. --*/
  695. DWORD
  696. MoveString(
  697. CBuffer &bfDst,
  698. LPCSTR szSrc,
  699. DWORD dwLength)
  700. {
  701. if ((DWORD)(-1) == dwLength)
  702. dwLength = lstrlenA(szSrc);
  703. else
  704. {
  705. while ((0 < dwLength) && (0 == szSrc[dwLength - 1]))
  706. dwLength -= 1;
  707. }
  708. #ifdef UNICODE
  709. DWORD dwResultLength;
  710. dwResultLength =
  711. MultiByteToWideChar(
  712. GetACP(),
  713. MB_PRECOMPOSED | MB_USEGLYPHCHARS,
  714. szSrc,
  715. dwLength,
  716. NULL,
  717. 0);
  718. if (0 == dwLength)
  719. throw GetLastError();
  720. bfDst.Presize((dwResultLength + 1) * sizeof(TCHAR));
  721. dwResultLength =
  722. MultiByteToWideChar(
  723. GetACP(),
  724. MB_PRECOMPOSED | MB_USEGLYPHCHARS,
  725. szSrc,
  726. dwLength,
  727. (LPTSTR)bfDst.Access(),
  728. bfDst.Space()/sizeof(TCHAR) - 1);
  729. if (0 == dwLength)
  730. throw GetLastError();
  731. bfDst.Resize(dwResultLength * sizeof(TCHAR), TRUE);
  732. dwLength = dwResultLength;
  733. #else
  734. bfDst.Presize((dwLength + 1) * sizeof(TCHAR));
  735. bfDst.Set((LPCBYTE)szSrc, dwLength * sizeof(TCHAR));
  736. #endif
  737. bfDst.Append((LPCBYTE)(TEXT("\000")), sizeof(TCHAR));
  738. dwLength += 1;
  739. return dwLength;
  740. }
  741. DWORD
  742. MoveString(
  743. CBuffer &bfDst,
  744. LPCWSTR szSrc,
  745. DWORD dwLength)
  746. {
  747. if ((DWORD)(-1) == dwLength)
  748. dwLength = lstrlenW(szSrc);
  749. else
  750. {
  751. while ((0 < dwLength) && (0 == szSrc[dwLength - 1]))
  752. dwLength -= 1;
  753. }
  754. #ifndef UNICODE
  755. DWORD dwResultLength =
  756. WideCharToMultiByte(
  757. GetACP(),
  758. WC_COMPOSITECHECK,
  759. szSrc,
  760. dwLength,
  761. NULL,
  762. 0,
  763. NULL,
  764. NULL);
  765. if (0 == dwResultLength)
  766. throw GetLastError();
  767. bfDst.Presize((dwResultLength + 1) * sizeof(TCHAR));
  768. dwResultLength =
  769. WideCharToMultiByte(
  770. GetACP(),
  771. WC_COMPOSITECHECK,
  772. szSrc,
  773. dwLength,
  774. (LPSTR)bfDst.Access(),
  775. bfDst.Space()/sizeof(TCHAR) - 1,
  776. NULL,
  777. NULL);
  778. if (0 == dwResultLength)
  779. throw GetLastError();
  780. bfDst.Resize(dwResultLength * sizeof(TCHAR), TRUE);
  781. dwLength = dwResultLength;
  782. #else
  783. bfDst.Presize((dwLength + 1) * sizeof(TCHAR));
  784. bfDst.Set((LPCBYTE)szSrc, dwLength * sizeof(TCHAR));
  785. #endif
  786. bfDst.Append((LPCBYTE)(TEXT("\000")), sizeof(TCHAR));
  787. dwLength += 1;
  788. return dwLength;
  789. }
  790. /*++
  791. MoveToAnsiString:
  792. This routine moves the internal string representation to an ANSI output
  793. buffer.
  794. Arguments:
  795. szDst receives the output string. It must be sufficiently large enough to
  796. handle the string. If this parameter is NULL, then the number of
  797. characters required to hold the result is returned.
  798. szSrc supplies the input string.
  799. cchLength supplies the length of the input string, with or without trailing
  800. nulls. A -1 value implies the length should be computed based on a
  801. trailing null.
  802. Return Value:
  803. The length of the resultant string, in characters, including the trailing
  804. null.
  805. Throws:
  806. Errors as DWORD status codes.
  807. Author:
  808. Doug Barlow (dbarlow) 2/14/1997
  809. --*/
  810. DWORD
  811. MoveToAnsiString(
  812. LPSTR szDst,
  813. LPCTSTR szSrc,
  814. DWORD cchLength)
  815. {
  816. if ((DWORD)(-1) == cchLength)
  817. cchLength = lstrlen(szSrc);
  818. else
  819. {
  820. while ((0 < cchLength) && (0 == szSrc[cchLength - 1]))
  821. cchLength -= 1;
  822. }
  823. #ifdef UNICODE
  824. if (0 == *szSrc)
  825. cchLength = 1;
  826. else if (NULL == szDst)
  827. {
  828. cchLength =
  829. WideCharToMultiByte(
  830. GetACP(),
  831. WC_COMPOSITECHECK,
  832. szSrc,
  833. cchLength,
  834. NULL,
  835. 0,
  836. NULL,
  837. NULL);
  838. if (0 == cchLength)
  839. throw GetLastError();
  840. cchLength += 1;
  841. }
  842. else
  843. {
  844. cchLength =
  845. WideCharToMultiByte(
  846. GetACP(),
  847. WC_COMPOSITECHECK,
  848. szSrc,
  849. cchLength,
  850. szDst,
  851. cchLength,
  852. NULL,
  853. NULL);
  854. if (0 == cchLength)
  855. throw GetLastError();
  856. szDst[cchLength++] = 0;
  857. }
  858. #else
  859. if (0 < cchLength)
  860. {
  861. cchLength += 1;
  862. if (NULL != szDst)
  863. CopyMemory(szDst, szSrc, cchLength * sizeof(TCHAR));
  864. }
  865. #endif
  866. return cchLength;
  867. }
  868. /*++
  869. MoveToUnicodeString:
  870. This routine moves the internal string representation to a UNICODE output
  871. buffer.
  872. Arguments:
  873. szDst receives the output string. It must be sufficiently large enough to
  874. handle the string. If this parameter is NULL, then the number of
  875. characters required to hold the result is returned.
  876. szSrc supplies the input string.
  877. cchLength supplies the length of the input string, with or without trailing
  878. nulls. A -1 value implies the length should be computed based on a
  879. trailing null.
  880. Return Value:
  881. The length of the resultant string, in characters, including the trailing
  882. null.
  883. Throws:
  884. Errors as DWORD status codes.
  885. Author:
  886. Doug Barlow (dbarlow) 2/14/1997
  887. --*/
  888. DWORD
  889. MoveToUnicodeString(
  890. LPWSTR szDst,
  891. LPCTSTR szSrc,
  892. DWORD cchLength)
  893. {
  894. if ((DWORD)(-1) == cchLength)
  895. cchLength = lstrlen(szSrc);
  896. else
  897. {
  898. while ((0 < cchLength) && (0 == szSrc[cchLength - 1]))
  899. cchLength -= 1;
  900. }
  901. #ifndef UNICODE
  902. if (0 == *szSrc)
  903. cchLength = 1;
  904. else if (NULL == szDst)
  905. {
  906. cchLength =
  907. MultiByteToWideChar(
  908. GetACP(),
  909. MB_PRECOMPOSED | MB_USEGLYPHCHARS,
  910. szSrc,
  911. cchLength,
  912. NULL,
  913. 0);
  914. if (0 == cchLength)
  915. throw GetLastError();
  916. cchLength += 1;
  917. }
  918. else
  919. {
  920. cchLength =
  921. MultiByteToWideChar(
  922. GetACP(),
  923. MB_PRECOMPOSED | MB_USEGLYPHCHARS,
  924. szSrc,
  925. cchLength,
  926. szDst,
  927. cchLength);
  928. if (0 == cchLength)
  929. throw GetLastError();
  930. szDst[cchLength++] = 0;
  931. }
  932. #else
  933. cchLength += 1;
  934. if (NULL != szDst)
  935. CopyMemory(szDst, szSrc, cchLength * sizeof(TCHAR));
  936. #endif
  937. return cchLength;
  938. }
  939. /*++
  940. MoveToAnsiMultistring:
  941. This routine moves the internal multistring representation to an ANSI output
  942. buffer.
  943. Arguments:
  944. szDst receives the output string. It must be sufficiently large enough to
  945. handle the multistring. If this parameter is NULL, then the number of
  946. characters required to hold the result is returned.
  947. szSrc supplies the input multistring.
  948. cchLength supplies the length of the input string, in characters, with or
  949. without trailing nulls. A -1 value implies the length should be
  950. computed based on a double trailing null.
  951. Return Value:
  952. The length of the resultant string, in characters, including the trailing
  953. nulls.
  954. Throws:
  955. Errors as DWORD status codes.
  956. Author:
  957. Doug Barlow (dbarlow) 2/17/1997
  958. --*/
  959. DWORD
  960. MoveToAnsiMultiString(
  961. LPSTR mszDst,
  962. LPCTSTR mszSrc,
  963. DWORD cchLength)
  964. {
  965. DWORD dwLen;
  966. if ((DWORD)(-1) == cchLength)
  967. cchLength = MStrLen(mszSrc);
  968. dwLen = MoveToAnsiString(mszDst, mszSrc, cchLength);
  969. if (0 == dwLen)
  970. {
  971. if (NULL != mszDst)
  972. mszDst[0] = mszDst[1] = 0;
  973. dwLen = 2;
  974. }
  975. else
  976. {
  977. if (NULL != mszDst)
  978. mszDst[dwLen] = 0;
  979. dwLen += 1;
  980. }
  981. return dwLen;
  982. }
  983. /*++
  984. MoveToUnicodeMultistring:
  985. This routine moves the internal multistring representation to a
  986. Unicode output buffer.
  987. Arguments:
  988. szDst receives the output string. It must be sufficiently large enough to
  989. handle the multistring. If this parameter is NULL, then the number of
  990. characters required to hold the result is returned.
  991. szSrc supplies the input multistring.
  992. cchLength supplies the length of the input string, in characters, with or
  993. without trailing nulls. A -1 value implies the length should be
  994. computed based on a double trailing null.
  995. Return Value:
  996. The length of the resultant string, in characters, including the trailing
  997. nulls.
  998. Throws:
  999. Errors as DWORD status codes.
  1000. Author:
  1001. Doug Barlow (dbarlow) 2/17/1997
  1002. --*/
  1003. DWORD
  1004. MoveToUnicodeMultiString(
  1005. LPWSTR mszDst,
  1006. LPCTSTR mszSrc,
  1007. DWORD cchLength)
  1008. {
  1009. DWORD dwLen;
  1010. if ((DWORD)(-1) == cchLength)
  1011. cchLength = MStrLen(mszSrc);
  1012. dwLen = MoveToUnicodeString(mszDst, mszSrc, cchLength);
  1013. if (NULL != mszDst)
  1014. mszDst[dwLen] = 0;
  1015. dwLen += 1;
  1016. return dwLen;
  1017. }
  1018. /*++
  1019. ErrorString:
  1020. This routine does it's very best to translate a given error code into a
  1021. text message. Any trailing non-printable characters are striped from the
  1022. end of the text message, such as carriage returns and line feeds.
  1023. Arguments:
  1024. dwErrorCode supplies the error code to be translated.
  1025. Return Value:
  1026. The address of a freshly allocated text string. Use FreeErrorString to
  1027. dispose of it.
  1028. Throws:
  1029. Errors are thrown as DWORD status codes.
  1030. Remarks:
  1031. Author:
  1032. Doug Barlow (dbarlow) 8/27/1998
  1033. --*/
  1034. LPCTSTR
  1035. ErrorString(
  1036. DWORD dwErrorCode)
  1037. {
  1038. LPTSTR szErrorString = NULL;
  1039. try
  1040. {
  1041. DWORD dwLen;
  1042. LPTSTR szLast;
  1043. dwLen = FormatMessage(
  1044. FORMAT_MESSAGE_ALLOCATE_BUFFER
  1045. | FORMAT_MESSAGE_FROM_SYSTEM,
  1046. NULL,
  1047. dwErrorCode,
  1048. LANG_NEUTRAL,
  1049. (LPTSTR)&szErrorString,
  1050. 0,
  1051. NULL);
  1052. if (0 == dwLen)
  1053. {
  1054. ASSERT(NULL == szErrorString);
  1055. dwLen = FormatMessage(
  1056. FORMAT_MESSAGE_ALLOCATE_BUFFER
  1057. | FORMAT_MESSAGE_FROM_HMODULE,
  1058. GetModuleHandle(NULL),
  1059. dwErrorCode,
  1060. LANG_NEUTRAL,
  1061. (LPTSTR)&szErrorString,
  1062. 0,
  1063. NULL);
  1064. if (0 == dwLen)
  1065. {
  1066. ASSERT(NULL == szErrorString);
  1067. szErrorString = (LPTSTR)LocalAlloc(
  1068. LMEM_FIXED,
  1069. 32 * sizeof(TCHAR));
  1070. if (NULL == szErrorString)
  1071. throw (DWORD)SCARD_E_NO_MEMORY;
  1072. _stprintf(szErrorString, TEXT("0x%08x"), dwErrorCode);
  1073. }
  1074. }
  1075. ASSERT(NULL != szErrorString);
  1076. for (szLast = szErrorString + lstrlen(szErrorString) - 1;
  1077. szLast > szErrorString;
  1078. szLast -= 1)
  1079. {
  1080. if (_istgraph(*szLast))
  1081. break;
  1082. *szLast = 0;
  1083. }
  1084. }
  1085. catch (...)
  1086. {
  1087. FreeErrorString(szErrorString);
  1088. throw;
  1089. }
  1090. return szErrorString;
  1091. }
  1092. /*++
  1093. FreeErrorString:
  1094. This routine frees the Error String allocated by the ErrorString service.
  1095. Arguments:
  1096. szErrorString supplies the error string to be deallocated.
  1097. Return Value:
  1098. None
  1099. Throws:
  1100. None
  1101. Remarks:
  1102. Author:
  1103. Doug Barlow (dbarlow) 8/27/1998
  1104. --*/
  1105. void
  1106. FreeErrorString(
  1107. LPCTSTR szErrorString)
  1108. {
  1109. if (NULL != szErrorString)
  1110. LocalFree((LPVOID)szErrorString);
  1111. }
  1112. /*++
  1113. SelectString:
  1114. This routine compares a given string to a list of possible strings, and
  1115. returns the index of the string that matches. The comparison is done case
  1116. insensitive, and abbreviations are allowed, as long as they're unique.
  1117. Arguments:
  1118. szSource supplies the string to be compared against all other strings.
  1119. Following strings supply a list of strings against which the source string
  1120. can be compared. The last parameter must be NULL.
  1121. Return Value:
  1122. 0 - No match, or ambiguous match.
  1123. 1-n - The source string matches the indexed template string.
  1124. Throws:
  1125. None
  1126. Remarks:
  1127. Author:
  1128. Doug Barlow (dbarlow) 8/27/1998
  1129. --*/
  1130. DWORD
  1131. SelectString(
  1132. LPCTSTR szSource,
  1133. ...)
  1134. {
  1135. va_list vaArgs;
  1136. DWORD cchSourceLen;
  1137. DWORD dwReturn = 0;
  1138. DWORD dwIndex = 1;
  1139. LPCTSTR szTpl;
  1140. va_start(vaArgs, szSource);
  1141. //
  1142. // Step through each input parameter until we find an exact match.
  1143. //
  1144. cchSourceLen = lstrlen(szSource);
  1145. if (0 == cchSourceLen)
  1146. return 0; // Empty strings don't match anything.
  1147. szTpl = va_arg(vaArgs, LPCTSTR);
  1148. while (NULL != szTpl)
  1149. {
  1150. if (0 == _tcsncicmp(szTpl, szSource, cchSourceLen))
  1151. {
  1152. if (0 != dwReturn)
  1153. {
  1154. dwReturn = 0;
  1155. break;
  1156. }
  1157. dwReturn = dwIndex;
  1158. }
  1159. szTpl = va_arg(vaArgs, LPCTSTR);
  1160. dwIndex += 1;
  1161. }
  1162. va_end(vaArgs);
  1163. return dwReturn;
  1164. }
  1165. /*++
  1166. StringFromGuid:
  1167. This routine converts a GUID into its corresponding string representation.
  1168. It's here so that it's not necessary to link all of OleBase into WinSCard.
  1169. Otherwise, we'd just use StringFromCLSID.
  1170. Arguments:
  1171. pguidSource supplies the GUID to convert.
  1172. szGuid receives the GUID as a string. This string is assumed to be at
  1173. least 39 characters long.
  1174. Return Value:
  1175. None
  1176. Throws:
  1177. Errors are thrown as DWORD status codes.
  1178. Author:
  1179. Doug Barlow (dbarlow) 1/20/1998
  1180. --*/
  1181. void
  1182. StringFromGuid(
  1183. IN LPCGUID pguidResult,
  1184. OUT LPTSTR szGuid)
  1185. {
  1186. //
  1187. // The following placement assumes Little Endianness.
  1188. // {1D92589A-91E4-11d1-93AA-00C04FD91402}
  1189. // 0123456789012345678901234567890123456789
  1190. // 1 2 3
  1191. //
  1192. static const WORD wPlace[sizeof(GUID)]
  1193. = { 8, 6, 4, 2, 13, 11, 18, 16, 21, 23, 26, 28, 30, 32, 34, 36 };
  1194. static const WORD wPunct[]
  1195. = { 0, 9, 14, 19, 24, 37, 38 };
  1196. static const TCHAR chPunct[]
  1197. = { TEXT('{'), TEXT('-'), TEXT('-'), TEXT('-'), TEXT('-'), TEXT('}'), TEXT('\000') };
  1198. DWORD dwI, dwJ;
  1199. TCHAR ch;
  1200. LPTSTR pch;
  1201. LPBYTE pbGuid = (LPBYTE)pguidResult;
  1202. BYTE bVal;
  1203. for (dwI = 0; dwI < sizeof(GUID); dwI += 1)
  1204. {
  1205. bVal = pbGuid[dwI];
  1206. pch = &szGuid[wPlace[dwI]];
  1207. for (dwJ = 0; dwJ < 2; dwJ += 1)
  1208. {
  1209. ch = bVal & 0x0f;
  1210. ch += TEXT('0');
  1211. if (ch > TEXT('9'))
  1212. ch += TEXT('A') - (TEXT('9') + 1);
  1213. *pch-- = ch;
  1214. bVal >>= 4;
  1215. }
  1216. }
  1217. dwI = 0;
  1218. do
  1219. {
  1220. szGuid[wPunct[dwI]] = chPunct[dwI];
  1221. } while (0 != chPunct[dwI++]);
  1222. }