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.

1708 lines
36 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. GetPlatform:
  679. This routine determines, to the best of its ability, the underlying
  680. operating system.
  681. Arguments:
  682. None
  683. Return Value:
  684. A DWORD, formatted as follows:
  685. +-------------------------------------------------------------------+
  686. | OpSys Id | Major Version | Minor Version |
  687. +-------------------------------------------------------------------+
  688. Bit 31 16 15 8 7 0
  689. Predefined values are:
  690. PLATFORM_UNKNOWN - The platform cannot be determined
  691. PLATFORM_WIN95 - The platform is Windows 95
  692. PLATFORM_WIN97 - The platform is Windows 97
  693. PLATFORM_WINNT40 - The platform is Windows NT V4.0
  694. PLATFORM_WINNT50 - The platform is Windows NT V5.0
  695. Throws:
  696. None
  697. Author:
  698. Doug Barlow (dbarlow) 1/16/1997
  699. Taken from a collection of common routines with no authorship
  700. information.
  701. --*/
  702. DWORD
  703. GetPlatform(
  704. void)
  705. {
  706. static DWORD dwPlatform = PLATFORM_UNKNOWN;
  707. if (PLATFORM_UNKNOWN == dwPlatform)
  708. {
  709. OSVERSIONINFO osVer;
  710. memset(&osVer, 0, sizeof(OSVERSIONINFO));
  711. osVer.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
  712. if (GetVersionEx(&osVer))
  713. dwPlatform =
  714. (osVer.dwPlatformId << 16)
  715. + (osVer.dwMajorVersion << 8)
  716. + osVer.dwMinorVersion;
  717. }
  718. return dwPlatform;
  719. }
  720. /*++
  721. MoveString:
  722. This routine moves an ASCII or UNICODE string into a buffer, converting to
  723. the character set in use.
  724. Arguments:
  725. bfDst receives the string, converted to TCHARs, and NULL terminated.
  726. szSrc supplies the original string.
  727. dwLength supplies the length of the string, with or without trailing
  728. nulls, in characters. A -1 value implies the length should be
  729. computed based on a trailing null.
  730. Return Value:
  731. The actual number of characters in the resultant string, including the
  732. trailing null.
  733. Throws:
  734. Errors encountered, as DWORDS.
  735. Author:
  736. Doug Barlow (dbarlow) 2/12/1997
  737. --*/
  738. DWORD
  739. MoveString(
  740. CBuffer &bfDst,
  741. LPCSTR szSrc,
  742. DWORD dwLength)
  743. {
  744. if ((DWORD)(-1) == dwLength)
  745. dwLength = lstrlenA(szSrc);
  746. else
  747. {
  748. while ((0 < dwLength) && (0 == szSrc[dwLength - 1]))
  749. dwLength -= 1;
  750. }
  751. #ifdef UNICODE
  752. DWORD dwResultLength;
  753. dwResultLength =
  754. MultiByteToWideChar(
  755. GetACP(),
  756. MB_PRECOMPOSED | MB_USEGLYPHCHARS,
  757. szSrc,
  758. dwLength,
  759. NULL,
  760. 0);
  761. if (0 == dwLength)
  762. throw GetLastError();
  763. bfDst.Presize((dwResultLength + 1) * sizeof(TCHAR));
  764. dwResultLength =
  765. MultiByteToWideChar(
  766. GetACP(),
  767. MB_PRECOMPOSED | MB_USEGLYPHCHARS,
  768. szSrc,
  769. dwLength,
  770. (LPTSTR)bfDst.Access(),
  771. bfDst.Space()/sizeof(TCHAR) - 1);
  772. if (0 == dwLength)
  773. throw GetLastError();
  774. bfDst.Resize(dwResultLength * sizeof(TCHAR), TRUE);
  775. dwLength = dwResultLength;
  776. #else
  777. bfDst.Presize((dwLength + 1) * sizeof(TCHAR));
  778. bfDst.Set((LPCBYTE)szSrc, dwLength * sizeof(TCHAR));
  779. #endif
  780. bfDst.Append((LPCBYTE)(TEXT("\000")), sizeof(TCHAR));
  781. dwLength += 1;
  782. return dwLength;
  783. }
  784. DWORD
  785. MoveString(
  786. CBuffer &bfDst,
  787. LPCWSTR szSrc,
  788. DWORD dwLength)
  789. {
  790. if ((DWORD)(-1) == dwLength)
  791. dwLength = lstrlenW(szSrc);
  792. else
  793. {
  794. while ((0 < dwLength) && (0 == szSrc[dwLength - 1]))
  795. dwLength -= 1;
  796. }
  797. #ifndef UNICODE
  798. DWORD dwResultLength =
  799. WideCharToMultiByte(
  800. GetACP(),
  801. WC_COMPOSITECHECK,
  802. szSrc,
  803. dwLength,
  804. NULL,
  805. 0,
  806. NULL,
  807. NULL);
  808. if (0 == dwResultLength)
  809. throw GetLastError();
  810. bfDst.Presize((dwResultLength + 1) * sizeof(TCHAR));
  811. dwResultLength =
  812. WideCharToMultiByte(
  813. GetACP(),
  814. WC_COMPOSITECHECK,
  815. szSrc,
  816. dwLength,
  817. (LPSTR)bfDst.Access(),
  818. bfDst.Space()/sizeof(TCHAR) - 1,
  819. NULL,
  820. NULL);
  821. if (0 == dwResultLength)
  822. throw GetLastError();
  823. bfDst.Resize(dwResultLength * sizeof(TCHAR), TRUE);
  824. dwLength = dwResultLength;
  825. #else
  826. bfDst.Presize((dwLength + 1) * sizeof(TCHAR));
  827. bfDst.Set((LPCBYTE)szSrc, dwLength * sizeof(TCHAR));
  828. #endif
  829. bfDst.Append((LPCBYTE)(TEXT("\000")), sizeof(TCHAR));
  830. dwLength += 1;
  831. return dwLength;
  832. }
  833. /*++
  834. MoveToAnsiString:
  835. This routine moves the internal string representation to an ANSI output
  836. buffer.
  837. Arguments:
  838. szDst receives the output string. It must be sufficiently large enough to
  839. handle the string. If this parameter is NULL, then the number of
  840. characters required to hold the result is returned.
  841. szSrc supplies the input string.
  842. cchLength supplies the length of the input string, with or without trailing
  843. nulls. A -1 value implies the length should be computed based on a
  844. trailing null.
  845. Return Value:
  846. The length of the resultant string, in characters, including the trailing
  847. null.
  848. Throws:
  849. Errors as DWORD status codes.
  850. Author:
  851. Doug Barlow (dbarlow) 2/14/1997
  852. --*/
  853. DWORD
  854. MoveToAnsiString(
  855. LPSTR szDst,
  856. LPCTSTR szSrc,
  857. DWORD cchLength)
  858. {
  859. if ((DWORD)(-1) == cchLength)
  860. cchLength = lstrlen(szSrc);
  861. else
  862. {
  863. while ((0 < cchLength) && (0 == szSrc[cchLength - 1]))
  864. cchLength -= 1;
  865. }
  866. #ifdef UNICODE
  867. if (0 == *szSrc)
  868. cchLength = 1;
  869. else if (NULL == szDst)
  870. {
  871. cchLength =
  872. WideCharToMultiByte(
  873. GetACP(),
  874. WC_COMPOSITECHECK,
  875. szSrc,
  876. cchLength,
  877. NULL,
  878. 0,
  879. NULL,
  880. NULL);
  881. if (0 == cchLength)
  882. throw GetLastError();
  883. cchLength += 1;
  884. }
  885. else
  886. {
  887. cchLength =
  888. WideCharToMultiByte(
  889. GetACP(),
  890. WC_COMPOSITECHECK,
  891. szSrc,
  892. cchLength,
  893. szDst,
  894. cchLength,
  895. NULL,
  896. NULL);
  897. if (0 == cchLength)
  898. throw GetLastError();
  899. szDst[cchLength++] = 0;
  900. }
  901. #else
  902. if (0 < cchLength)
  903. {
  904. cchLength += 1;
  905. if (NULL != szDst)
  906. CopyMemory(szDst, szSrc, cchLength * sizeof(TCHAR));
  907. }
  908. #endif
  909. return cchLength;
  910. }
  911. /*++
  912. MoveToUnicodeString:
  913. This routine moves the internal string representation to a UNICODE output
  914. buffer.
  915. Arguments:
  916. szDst receives the output string. It must be sufficiently large enough to
  917. handle the string. If this parameter is NULL, then the number of
  918. characters required to hold the result is returned.
  919. szSrc supplies the input string.
  920. cchLength supplies the length of the input string, with or without trailing
  921. nulls. A -1 value implies the length should be computed based on a
  922. trailing null.
  923. Return Value:
  924. The length of the resultant string, in characters, including the trailing
  925. null.
  926. Throws:
  927. Errors as DWORD status codes.
  928. Author:
  929. Doug Barlow (dbarlow) 2/14/1997
  930. --*/
  931. DWORD
  932. MoveToUnicodeString(
  933. LPWSTR szDst,
  934. LPCTSTR szSrc,
  935. DWORD cchLength)
  936. {
  937. if ((DWORD)(-1) == cchLength)
  938. cchLength = lstrlen(szSrc);
  939. else
  940. {
  941. while ((0 < cchLength) && (0 == szSrc[cchLength - 1]))
  942. cchLength -= 1;
  943. }
  944. #ifndef UNICODE
  945. if (0 == *szSrc)
  946. cchLength = 1;
  947. else if (NULL == szDst)
  948. {
  949. cchLength =
  950. MultiByteToWideChar(
  951. GetACP(),
  952. MB_PRECOMPOSED | MB_USEGLYPHCHARS,
  953. szSrc,
  954. cchLength,
  955. NULL,
  956. 0);
  957. if (0 == cchLength)
  958. throw GetLastError();
  959. cchLength += 1;
  960. }
  961. else
  962. {
  963. cchLength =
  964. MultiByteToWideChar(
  965. GetACP(),
  966. MB_PRECOMPOSED | MB_USEGLYPHCHARS,
  967. szSrc,
  968. cchLength,
  969. szDst,
  970. cchLength);
  971. if (0 == cchLength)
  972. throw GetLastError();
  973. szDst[cchLength++] = 0;
  974. }
  975. #else
  976. cchLength += 1;
  977. if (NULL != szDst)
  978. CopyMemory(szDst, szSrc, cchLength * sizeof(TCHAR));
  979. #endif
  980. return cchLength;
  981. }
  982. /*++
  983. MoveToAnsiMultistring:
  984. This routine moves the internal multistring representation to an ANSI output
  985. buffer.
  986. Arguments:
  987. szDst receives the output string. It must be sufficiently large enough to
  988. handle the multistring. If this parameter is NULL, then the number of
  989. characters required to hold the result is returned.
  990. szSrc supplies the input multistring.
  991. cchLength supplies the length of the input string, in characters, with or
  992. without trailing nulls. A -1 value implies the length should be
  993. computed based on a double trailing null.
  994. Return Value:
  995. The length of the resultant string, in characters, including the trailing
  996. nulls.
  997. Throws:
  998. Errors as DWORD status codes.
  999. Author:
  1000. Doug Barlow (dbarlow) 2/17/1997
  1001. --*/
  1002. DWORD
  1003. MoveToAnsiMultiString(
  1004. LPSTR mszDst,
  1005. LPCTSTR mszSrc,
  1006. DWORD cchLength)
  1007. {
  1008. DWORD dwLen;
  1009. if ((DWORD)(-1) == cchLength)
  1010. cchLength = MStrLen(mszSrc);
  1011. dwLen = MoveToAnsiString(mszDst, mszSrc, cchLength);
  1012. if (0 == dwLen)
  1013. {
  1014. if (NULL != mszDst)
  1015. mszDst[0] = mszDst[1] = 0;
  1016. dwLen = 2;
  1017. }
  1018. else
  1019. {
  1020. if (NULL != mszDst)
  1021. mszDst[dwLen] = 0;
  1022. dwLen += 1;
  1023. }
  1024. return dwLen;
  1025. }
  1026. /*++
  1027. MoveToUnicodeMultistring:
  1028. This routine moves the internal multistring representation to a
  1029. Unicode output buffer.
  1030. Arguments:
  1031. szDst receives the output string. It must be sufficiently large enough to
  1032. handle the multistring. If this parameter is NULL, then the number of
  1033. characters required to hold the result is returned.
  1034. szSrc supplies the input multistring.
  1035. cchLength supplies the length of the input string, in characters, with or
  1036. without trailing nulls. A -1 value implies the length should be
  1037. computed based on a double trailing null.
  1038. Return Value:
  1039. The length of the resultant string, in characters, including the trailing
  1040. nulls.
  1041. Throws:
  1042. Errors as DWORD status codes.
  1043. Author:
  1044. Doug Barlow (dbarlow) 2/17/1997
  1045. --*/
  1046. DWORD
  1047. MoveToUnicodeMultiString(
  1048. LPWSTR mszDst,
  1049. LPCTSTR mszSrc,
  1050. DWORD cchLength)
  1051. {
  1052. DWORD dwLen;
  1053. if ((DWORD)(-1) == cchLength)
  1054. cchLength = MStrLen(mszSrc);
  1055. dwLen = MoveToUnicodeString(mszDst, mszSrc, cchLength);
  1056. if (NULL != mszDst)
  1057. mszDst[dwLen] = 0;
  1058. dwLen += 1;
  1059. return dwLen;
  1060. }
  1061. /*++
  1062. ErrorString:
  1063. This routine does it's very best to translate a given error code into a
  1064. text message. Any trailing non-printable characters are striped from the
  1065. end of the text message, such as carriage returns and line feeds.
  1066. Arguments:
  1067. dwErrorCode supplies the error code to be translated.
  1068. Return Value:
  1069. The address of a freshly allocated text string. Use FreeErrorString to
  1070. dispose of it.
  1071. Throws:
  1072. Errors are thrown as DWORD status codes.
  1073. Remarks:
  1074. Author:
  1075. Doug Barlow (dbarlow) 8/27/1998
  1076. --*/
  1077. LPCTSTR
  1078. ErrorString(
  1079. DWORD dwErrorCode)
  1080. {
  1081. LPTSTR szErrorString = NULL;
  1082. try
  1083. {
  1084. DWORD dwLen;
  1085. LPTSTR szLast;
  1086. dwLen = FormatMessage(
  1087. FORMAT_MESSAGE_ALLOCATE_BUFFER
  1088. | FORMAT_MESSAGE_FROM_SYSTEM,
  1089. NULL,
  1090. dwErrorCode,
  1091. LANG_NEUTRAL,
  1092. (LPTSTR)&szErrorString,
  1093. 0,
  1094. NULL);
  1095. if (0 == dwLen)
  1096. {
  1097. ASSERT(NULL == szErrorString);
  1098. dwLen = FormatMessage(
  1099. FORMAT_MESSAGE_ALLOCATE_BUFFER
  1100. | FORMAT_MESSAGE_FROM_HMODULE,
  1101. GetModuleHandle(NULL),
  1102. dwErrorCode,
  1103. LANG_NEUTRAL,
  1104. (LPTSTR)&szErrorString,
  1105. 0,
  1106. NULL);
  1107. if (0 == dwLen)
  1108. {
  1109. ASSERT(NULL == szErrorString);
  1110. szErrorString = (LPTSTR)LocalAlloc(
  1111. LMEM_FIXED,
  1112. 32 * sizeof(TCHAR));
  1113. if (NULL == szErrorString)
  1114. throw (DWORD)SCARD_E_NO_MEMORY;
  1115. _stprintf(szErrorString, TEXT("0x%08x"), dwErrorCode);
  1116. }
  1117. }
  1118. ASSERT(NULL != szErrorString);
  1119. for (szLast = szErrorString + lstrlen(szErrorString) - 1;
  1120. szLast > szErrorString;
  1121. szLast -= 1)
  1122. {
  1123. if (_istgraph(*szLast))
  1124. break;
  1125. *szLast = 0;
  1126. }
  1127. }
  1128. catch (...)
  1129. {
  1130. FreeErrorString(szErrorString);
  1131. throw;
  1132. }
  1133. return szErrorString;
  1134. }
  1135. /*++
  1136. FreeErrorString:
  1137. This routine frees the Error String allocated by the ErrorString service.
  1138. Arguments:
  1139. szErrorString supplies the error string to be deallocated.
  1140. Return Value:
  1141. None
  1142. Throws:
  1143. None
  1144. Remarks:
  1145. Author:
  1146. Doug Barlow (dbarlow) 8/27/1998
  1147. --*/
  1148. void
  1149. FreeErrorString(
  1150. LPCTSTR szErrorString)
  1151. {
  1152. if (NULL != szErrorString)
  1153. LocalFree((LPVOID)szErrorString);
  1154. }
  1155. /*++
  1156. SelectString:
  1157. This routine compares a given string to a list of possible strings, and
  1158. returns the index of the string that matches. The comparison is done case
  1159. insensitive, and abbreviations are allowed, as long as they're unique.
  1160. Arguments:
  1161. szSource supplies the string to be compared against all other strings.
  1162. Following strings supply a list of strings against which the source string
  1163. can be compared. The last parameter must be NULL.
  1164. Return Value:
  1165. 0 - No match, or ambiguous match.
  1166. 1-n - The source string matches the indexed template string.
  1167. Throws:
  1168. None
  1169. Remarks:
  1170. Author:
  1171. Doug Barlow (dbarlow) 8/27/1998
  1172. --*/
  1173. DWORD
  1174. SelectString(
  1175. LPCTSTR szSource,
  1176. ...)
  1177. {
  1178. va_list vaArgs;
  1179. DWORD cchSourceLen;
  1180. DWORD dwReturn = 0;
  1181. DWORD dwIndex = 1;
  1182. LPCTSTR szTpl;
  1183. va_start(vaArgs, szSource);
  1184. //
  1185. // Step through each input parameter until we find an exact match.
  1186. //
  1187. cchSourceLen = lstrlen(szSource);
  1188. if (0 == cchSourceLen)
  1189. return 0; // Empty strings don't match anything.
  1190. szTpl = va_arg(vaArgs, LPCTSTR);
  1191. while (NULL != szTpl)
  1192. {
  1193. if (0 == _tcsncicmp(szTpl, szSource, cchSourceLen))
  1194. {
  1195. if (0 != dwReturn)
  1196. {
  1197. dwReturn = 0;
  1198. break;
  1199. }
  1200. dwReturn = dwIndex;
  1201. }
  1202. szTpl = va_arg(vaArgs, LPCTSTR);
  1203. dwIndex += 1;
  1204. }
  1205. va_end(vaArgs);
  1206. return dwReturn;
  1207. }
  1208. /*++
  1209. StringFromGuid:
  1210. This routine converts a GUID into its corresponding string representation.
  1211. It's here so that it's not necessary to link all of OleBase into WinSCard.
  1212. Otherwise, we'd just use StringFromCLSID.
  1213. Arguments:
  1214. pguidSource supplies the GUID to convert.
  1215. szGuid receives the GUID as a string. This string is assumed to be at
  1216. least 39 characters long.
  1217. Return Value:
  1218. None
  1219. Throws:
  1220. Errors are thrown as DWORD status codes.
  1221. Author:
  1222. Doug Barlow (dbarlow) 1/20/1998
  1223. --*/
  1224. void
  1225. StringFromGuid(
  1226. IN LPCGUID pguidResult,
  1227. OUT LPTSTR szGuid)
  1228. {
  1229. //
  1230. // The following placement assumes Little Endianness.
  1231. // {1D92589A-91E4-11d1-93AA-00C04FD91402}
  1232. // 0123456789012345678901234567890123456789
  1233. // 1 2 3
  1234. //
  1235. static const WORD wPlace[sizeof(GUID)]
  1236. = { 8, 6, 4, 2, 13, 11, 18, 16, 21, 23, 26, 28, 30, 32, 34, 36 };
  1237. static const WORD wPunct[]
  1238. = { 0, 9, 14, 19, 24, 37, 38 };
  1239. static const TCHAR chPunct[]
  1240. = { TEXT('{'), TEXT('-'), TEXT('-'), TEXT('-'), TEXT('-'), TEXT('}'), TEXT('\000') };
  1241. DWORD dwI, dwJ;
  1242. TCHAR ch;
  1243. LPTSTR pch;
  1244. LPBYTE pbGuid = (LPBYTE)pguidResult;
  1245. BYTE bVal;
  1246. for (dwI = 0; dwI < sizeof(GUID); dwI += 1)
  1247. {
  1248. bVal = pbGuid[dwI];
  1249. pch = &szGuid[wPlace[dwI]];
  1250. for (dwJ = 0; dwJ < 2; dwJ += 1)
  1251. {
  1252. ch = bVal & 0x0f;
  1253. ch += TEXT('0');
  1254. if (ch > TEXT('9'))
  1255. ch += TEXT('A') - (TEXT('9') + 1);
  1256. *pch-- = ch;
  1257. bVal >>= 4;
  1258. }
  1259. }
  1260. dwI = 0;
  1261. do
  1262. {
  1263. szGuid[wPunct[dwI]] = chPunct[dwI];
  1264. } while (0 != chPunct[dwI++]);
  1265. }