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.

1154 lines
27 KiB

  1. ////////////////////////////////////////////////////////////////////////////////////
  2. //
  3. // File: globals.cpp
  4. //
  5. // History: 16-Nov-00 markder Created.
  6. //
  7. // Desc: This file contains miscellaneous helper functions.
  8. //
  9. ////////////////////////////////////////////////////////////////////////////////////
  10. #include "StdAfx.h"
  11. #include <errno.h>
  12. ////////////////////////////////////////////////////////////////////////////////////
  13. //
  14. // Func: PrintError, PrintErrorStack, Print
  15. //
  16. // Desc: Helper functions for console output
  17. //
  18. ////////////////////////////////////////////////////////////////////////////////////
  19. TCHAR gszT[1024]; // Global buffer for console output
  20. void _cdecl PrintError(
  21. LPCTSTR pszFmt,
  22. ...)
  23. {
  24. va_list arglist;
  25. va_start(arglist, pszFmt);
  26. StringCchVPrintf(gszT, ARRAYSIZE(gszT), pszFmt, arglist);
  27. gszT[1023] = _T('\0'); // ensure null termination
  28. va_end(arglist);
  29. _tprintf(_T("\nNMAKE : U8604: 'ShimDBC': %s"), gszT);
  30. }
  31. void PrintErrorStack()
  32. {
  33. CString csError;
  34. INT_PTR i, j;
  35. Print(_T("\n\nErrors were encountered during compilation:\n"));
  36. for (i = g_rgErrors.GetSize() - 1; i >= 0; i--) {
  37. csError.Empty();
  38. j = g_rgErrors.GetSize() - i;
  39. while(--j) {
  40. csError += _T(" ");
  41. }
  42. csError += g_rgErrors[i];
  43. csError += _T("\n");
  44. PrintError(csError);
  45. }
  46. }
  47. void _cdecl Print(
  48. LPCTSTR pszFmt,
  49. ...)
  50. {
  51. va_list arglist;
  52. if (g_bQuiet)
  53. return;
  54. va_start(arglist, pszFmt);
  55. StringCchVPrintf(gszT, ARRAYSIZE(gszT), pszFmt, arglist);
  56. gszT[1023] = _T('\0'); // ensure null termination
  57. va_end(arglist);
  58. _tprintf(_T("%s"), gszT);
  59. }
  60. ////////////////////////////////////////////////////////////////////////////////////
  61. //
  62. // Func: StringToDword
  63. //
  64. // Desc: Converts a string to a DWORD. Handles the 0x prefix for hex strings.
  65. //
  66. DWORD StringToDword(
  67. CString cs)
  68. {
  69. DWORD dwRet;
  70. cs.MakeLower();
  71. if (cs.Left(2) == _T("0x")) {
  72. _stscanf(cs, _T("0x%x"), &dwRet);
  73. } else {
  74. dwRet = _ttol(cs);
  75. }
  76. return dwRet;
  77. }
  78. ////////////////////////////////////////////////////////////////////////////////////
  79. //
  80. // Func: StringToULong
  81. //
  82. // Desc: Converts a string to a unsigned long.
  83. //
  84. ULONG StringToULong(
  85. LPCTSTR lpszVal)
  86. {
  87. TCHAR* pEnd;
  88. return _tcstoul(lpszVal, &pEnd, 0);
  89. }
  90. ////////////////////////////////////////////////////////////////////////////////////
  91. //
  92. // Func: StringToMask
  93. //
  94. // Desc: Converts a string to a mask, with some checking
  95. //
  96. BOOL
  97. StringToMask(
  98. LPDWORD pdwMask,
  99. LPCTSTR lpszVal
  100. )
  101. {
  102. DWORD dwMask = 0;
  103. LPCTSTR pVal;
  104. BOOL bSuccess;
  105. TCHAR* pEnd = NULL;
  106. pVal = lpszVal + _tcsspn(lpszVal, _T(" \t"));
  107. dwMask = (DWORD)_tcstoul(pVal, &pEnd, 0);
  108. if (dwMask == 0) { // suspicious, possibly check errno
  109. if (errno != 0) {
  110. goto errHandle;
  111. }
  112. }
  113. //
  114. // if a mask is ending with some garbage -- it's an error
  115. //
  116. if (pEnd && *pEnd != _T('\0') && !_istspace(*pEnd)) {
  117. goto errHandle;
  118. }
  119. if (pdwMask) {
  120. *pdwMask = dwMask;
  121. }
  122. return TRUE;
  123. errHandle:
  124. SDBERROR_FORMAT((_T("Failed to parse \"%s\"\n"), lpszVal));
  125. return FALSE;
  126. }
  127. ////////////////////////////////////////////////////////////////////////////////////
  128. //
  129. // Func: StringToQword
  130. //
  131. // Desc: Converts a string to a 64-bit ULONGLONG (aka QWORD). Handles the 0x
  132. // prefix for hex strings.
  133. //
  134. ULONGLONG StringToQword(
  135. CString cs)
  136. {
  137. ULONGLONG ullRet;
  138. cs.MakeLower();
  139. if (cs.Left(2) == _T("0x")) {
  140. _stscanf(cs, _T("0x%I64x"), &ullRet);
  141. } else {
  142. ullRet = _ttoi64(cs);
  143. }
  144. return ullRet;
  145. }
  146. ////////////////////////////////////////////////////////////////////////////////////
  147. //
  148. // Func: VersionToQword
  149. //
  150. // Desc: Converts a version string to a 64-bit ULONGLONG (aka QWORD).
  151. // Version strings are of the form xx.xx.xx.xx, where each of
  152. // numbers is turned into a word and combined into a single
  153. // quad word. If a portion of the version string is a * or is
  154. // missing, it is stored as 0xFFFF.
  155. //
  156. BOOL VersionToQword(
  157. LPCTSTR lpszVersion,
  158. ULONGLONG* pullRet
  159. )
  160. {
  161. BOOL bSuccess = FALSE;
  162. ULONG ulPart;
  163. LPTSTR pEnd = NULL;
  164. int i;
  165. *pullRet = 0;
  166. for (i = 0; i < 4; i++) {
  167. ulPart = (WORD)0xFFFF;
  168. //
  169. // skip whitespace
  170. //
  171. lpszVersion += _tcsspn(lpszVersion, _T(" \t"));
  172. if (*lpszVersion == _T('*')) {
  173. //
  174. // we expect to see either *\0 or *.xxx
  175. // so move past *
  176. //
  177. pEnd = (LPTSTR)(lpszVersion + 1);
  178. }
  179. else {
  180. //
  181. // not a wildcard - if we have not reached the end of the string,
  182. // keep parsing numbers
  183. //
  184. if (*lpszVersion) {
  185. pEnd = NULL;
  186. ulPart = _tcstol(lpszVersion, &pEnd, 0);
  187. //
  188. // check to see that the part was converted properly
  189. //
  190. if (pEnd == NULL) {
  191. SDBERROR_FORMAT((_T("Internal error, failed to parse \"%s\"\n"), lpszVersion));
  192. goto eh;
  193. }
  194. }
  195. }
  196. if (pEnd == NULL) {
  197. break;
  198. }
  199. //
  200. // skip whitespace first
  201. //
  202. pEnd += _tcsspn(pEnd, _T(" \t"));
  203. //
  204. // at this point we should be at the end of
  205. // the string OR at the '.'
  206. //
  207. if (*pEnd && *pEnd != _T('.')) {
  208. SDBERROR_FORMAT((_T("Bad version specification, parsing stopped at \"%s\"\n"), pEnd));
  209. goto eh;
  210. }
  211. lpszVersion = (*pEnd == _T('.') ? pEnd + 1 : pEnd);
  212. *pullRet = (*pullRet << 16) | ((WORD)ulPart);
  213. }
  214. bSuccess = TRUE;
  215. eh:
  216. return bSuccess;
  217. }
  218. BOOL VersionQwordToString(
  219. OUT CString& rString,
  220. ULONGLONG ullVersion
  221. )
  222. {
  223. // we do conversion to string
  224. int i;
  225. WORD wPart;
  226. CString csPart;
  227. ULONGLONG ullMask = (((ULONGLONG)0xFFFF) << 48);
  228. ULONGLONG ullPart;
  229. rString.Empty();
  230. for (i = 0; i < 4; ++i) {
  231. ullPart = ullVersion & ullMask;
  232. ullVersion = (ullVersion << 16) | (WORD)0xFFFF;
  233. //
  234. // get the part into the lower portion
  235. //
  236. wPart = (WORD)(ullPart >> 48);
  237. if (wPart == (WORD)0xFFFF) {
  238. csPart = _T('*');
  239. } else {
  240. csPart.Format(_T("%hu"), wPart);
  241. }
  242. if (i > 0) {
  243. rString += _T('.');
  244. }
  245. rString += csPart;
  246. if (ullVersion == (ULONGLONG)-1) {
  247. break;
  248. }
  249. }
  250. return TRUE;
  251. }
  252. ////////////////////////////////////////////////////////////////////////////////////
  253. //
  254. // Func: TrimParagraph
  255. //
  256. // Desc: Trims extra whitespace from a string
  257. //
  258. //
  259. CString TrimParagraph(CString csInput)
  260. {
  261. CString csOutput;
  262. long i;
  263. // Expand CString's buffer to size of input
  264. csOutput.GetBuffer(csInput.GetLength());
  265. csOutput.ReleaseBuffer();
  266. for (i = 0; i < csInput.GetLength(); i++) {
  267. TCHAR c = csInput.GetAt(i);
  268. if (_istspace(c)) {
  269. if (csOutput.GetLength() == 0)
  270. continue;
  271. if (csOutput.Mid(csOutput.GetLength() - 1) == _T(' ') ||
  272. csOutput.Mid(csOutput.GetLength() - 4, 4) == _T("BR/>") ||
  273. csOutput.Mid(csOutput.GetLength() - 3, 3) == _T("P/>"))
  274. continue;
  275. csOutput += _T(' ');
  276. continue;
  277. }
  278. if (csInput.Left(3) == _T("<BR") ||
  279. csInput.Left(2) == _T("<P")) {
  280. //
  281. // Get rid of spaces preceding a <BR/> tag
  282. //
  283. csOutput.TrimRight();
  284. }
  285. csOutput += c;
  286. }
  287. csOutput.TrimLeft();
  288. csOutput.TrimRight();
  289. return csOutput;
  290. }
  291. ////////////////////////////////////////////////////////////////////////////////////
  292. //
  293. // Func: ReplaceStringNoCase
  294. //
  295. // Desc: Replaces all instances of lpszFindThis with lpszReplaceWithThis
  296. // within csText (case insensitive).
  297. //
  298. VOID ReplaceStringNoCase(CString& csText, LPCTSTR lpszFindThis, LPCTSTR lpszReplaceWithThis)
  299. {
  300. LPTSTR lpszBuffer;
  301. LPTSTR lpszFind;
  302. if (0 == csText.GetLength()) {
  303. return;
  304. }
  305. CString strFindNoCase(lpszFindThis);
  306. lpszBuffer = csText.GetBuffer(csText.GetLength());
  307. strFindNoCase.MakeUpper();
  308. do {
  309. lpszFind = StrStrI(lpszBuffer, strFindNoCase);
  310. if (NULL != lpszFind) {
  311. memcpy(lpszFind, (LPCTSTR)strFindNoCase, strFindNoCase.GetLength() * sizeof(*lpszFind));
  312. lpszBuffer = lpszFind + strFindNoCase.GetLength();
  313. }
  314. } while (NULL != lpszFind);
  315. // now that all the instances of the lpszFindThis had been replaced with
  316. // the upper-cased version... do a regular replace
  317. csText.ReleaseBuffer();
  318. csText.Replace(strFindNoCase, lpszReplaceWithThis);
  319. }
  320. ////////////////////////////////////////////////////////////////////////////////////
  321. //
  322. // Func: MakeFullPath
  323. //
  324. // Desc: Creates a full path from a (possible) relative one. Uses
  325. // GetCurrentDirectory to prepend the passed in string.
  326. //
  327. CString MakeFullPath(CString cs)
  328. {
  329. CString csNewPath;
  330. DWORD dwCurDirSize;
  331. LPTSTR lpszCurDir;
  332. return cs;
  333. #if 0
  334. //
  335. // Check if it's already a full path
  336. //
  337. if (cs.Mid(1, 1) == _T(":") ||
  338. cs.Left(2) == _T("\\\\")) {
  339. //
  340. // This is either a UNC full path or a DOS full path.
  341. // Drop out.
  342. //
  343. return cs;
  344. }
  345. dwCurDirSize = GetCurrentDirectory(0, NULL);
  346. lpszCurDir = csNewPath.GetBuffer(dwCurDirSize);
  347. if (0 == GetCurrentDirectory(dwCurDirSize, lpszCurDir)) {
  348. //
  349. // Something really weird happened. Not sure how to error out.
  350. //
  351. return cs;
  352. }
  353. csNewPath.ReleaseBuffer();
  354. if (csNewPath.Right(1) != _T("\\")) {
  355. csNewPath += _T("\\");
  356. }
  357. csNewPath += cs;
  358. return csNewPath;
  359. #endif
  360. }
  361. ////////////////////////////////////////////////////////////////////////////////////
  362. //
  363. // Func: GetByteStringSize
  364. //
  365. // Desc: Parses a 'byte string' (used in <PATCH> declarations) to determine
  366. // how many bytes it contains.
  367. //
  368. DWORD GetByteStringSize(
  369. CString csBytes)
  370. {
  371. DWORD dwByteCount = 0;
  372. BOOL bOnByte = FALSE;
  373. csBytes.MakeUpper();
  374. for (long i = 0; i < csBytes.GetLength(); i++) {
  375. if (_istxdigit(csBytes.GetAt(i))) {
  376. if (!bOnByte) {
  377. dwByteCount++;
  378. bOnByte = TRUE;
  379. }
  380. } else if (_istspace(csBytes.GetAt(i))) {
  381. bOnByte = FALSE;
  382. } else {
  383. SDBERROR_FORMAT((_T("Unrecognized byte character '%c' in <PATCH> block:\n%s\n"),
  384. csBytes.GetAt(i), ((LPCTSTR)csBytes)+i));
  385. return 0xFFFFFFFF;
  386. }
  387. }
  388. return dwByteCount;
  389. }
  390. ////////////////////////////////////////////////////////////////////////////////////
  391. //
  392. // Func: GetBytesFromString
  393. //
  394. // Desc: Parses a 'byte string' (used in <PATCH> declarations) into an actual
  395. // memory block.
  396. //
  397. DWORD GetBytesFromString(
  398. CString csBytes,
  399. BYTE* pBuffer,
  400. DWORD dwBufferSize)
  401. {
  402. csBytes.MakeUpper();
  403. CString csByte;
  404. DWORD dwRequiredBufferSize;
  405. LONG nFirstByteChar = -1;
  406. DWORD dwBufferCursor = 0;
  407. DWORD dwByte;
  408. dwRequiredBufferSize = GetByteStringSize(csBytes);
  409. if (dwRequiredBufferSize < dwBufferSize || dwRequiredBufferSize == 0xFFFFFFFF) {
  410. return dwRequiredBufferSize;
  411. }
  412. for (long i = 0; i < csBytes.GetLength() + 1; i++) {
  413. if (_istxdigit(csBytes.GetAt(i))) {
  414. if (nFirstByteChar == -1) {
  415. nFirstByteChar = i;
  416. }
  417. } else if (_istspace(csBytes.GetAt(i)) ||
  418. csBytes.GetAt(i) == _T('\0')) {
  419. if (nFirstByteChar != -1) {
  420. csByte = csBytes.Mid(nFirstByteChar, i - nFirstByteChar);
  421. _stscanf(csByte, _T("%x"), &dwByte);
  422. memcpy(pBuffer + dwBufferCursor++, &dwByte, sizeof(BYTE));
  423. }
  424. nFirstByteChar = -1;
  425. } else {
  426. SDBERROR_FORMAT((_T("Unrecognized byte character '%c' in <PATCH> block:\n%s\n"),
  427. csBytes.GetAt(i), ((LPCTSTR)csBytes)+i));
  428. return 0xFFFFFFFF;
  429. }
  430. }
  431. return dwRequiredBufferSize;
  432. }
  433. ////////////////////////////////////////////////////////////////////////////////////
  434. //
  435. // Func: DecodeString
  436. //
  437. // Desc: Decodes a list of strings with flags
  438. //
  439. // [00] [00] [00] [00]
  440. // ^ Arch1 Arch2 Arch3
  441. // |- flags
  442. //
  443. // syntax for the runtime platform:
  444. // [!] ( [!] STR1 [; STR2 ] ... )
  445. // example:
  446. // !STR1 - will evaluate to TRUE when the the string is NOT STR1
  447. // !(STR1; STR2) - will evaluate to TRUE when the string doesn't contain STR1 or STR2
  448. //
  449. BOOL DecodeString(LPCTSTR pszStr, LPDWORD pdwMask, PFNGETSTRINGMASK pfnGetStringMask)
  450. {
  451. BOOL bNot = FALSE;
  452. BOOL bBracket = FALSE;
  453. LPTSTR pEnd;
  454. TCHAR chSave;
  455. DWORD dwElement;
  456. BOOL bNotElement;
  457. DWORD dwMask = 0;
  458. INT nElement = 0;
  459. BOOL bSuccess = FALSE;
  460. pszStr += _tcsspn(pszStr, _T(" \t"));
  461. //
  462. // Got the first char
  463. //
  464. if (*pszStr == _T('!')) {
  465. //
  466. // Peek ahead and see whether we have a bracket
  467. //
  468. pEnd = (LPTSTR)(pszStr + 1);
  469. pEnd += _tcsspn(pEnd, _T(" \t"));
  470. if (*pEnd == '(') {
  471. // global not
  472. bNot = TRUE;
  473. pszStr = pEnd;
  474. } else {
  475. // local NOT -- so jump to parsing it
  476. goto ParseStart;
  477. }
  478. }
  479. if (*pszStr == _T('(')) {
  480. // bracket, we need to find closing one too
  481. ++pszStr;
  482. bBracket = TRUE;
  483. }
  484. ParseStart:
  485. do {
  486. dwElement = 0;
  487. pszStr += _tcsspn(pszStr, _T(" ;,\t"));
  488. if (*pszStr == _T('\0') || *pszStr == _T(')')) {
  489. break;
  490. }
  491. bNotElement = (*pszStr == _T('!'));
  492. if (bNotElement) {
  493. pszStr++;
  494. }
  495. // find the end of this token
  496. pEnd = _tcspbrk(pszStr, _T(" \t;,)"));
  497. if (pEnd != NULL) {
  498. chSave = *pEnd;
  499. *pEnd = _T('\0');
  500. }
  501. dwElement = (*pfnGetStringMask)(pszStr);
  502. if (pEnd) {
  503. *pEnd = chSave;
  504. }
  505. if (dwElement == OS_SKU_NONE) {
  506. goto HandleError;
  507. }
  508. if (bNotElement) {
  509. dwElement ^= 0xFFFFFFFF;
  510. }
  511. dwMask |= dwElement;
  512. pszStr = pEnd;
  513. } while (pEnd); // when pEnd == NULL -- it was the last token
  514. if (bBracket && (!pszStr || *pszStr != ')')) {
  515. // we expected a bracket here
  516. goto HandleError;
  517. }
  518. if (bNot) {
  519. dwMask ^= 0xFFFFFFFF;
  520. }
  521. *pdwMask = dwMask;
  522. bSuccess = TRUE;
  523. HandleError:
  524. if (!bSuccess) {
  525. SDBERROR_FORMAT((_T("Failed to decode \"%s\"\n"), pszStr));
  526. }
  527. return bSuccess;
  528. }
  529. ////////////////////////////////////////////////////////////////////////////////////
  530. //
  531. // Func: DecodeRuntimePlatformString
  532. //
  533. // Desc: Decodes a list of Platform Strings with flags
  534. //
  535. // [00] [00] [00] [00]
  536. // ^ Arch1 Arch2 Arch3
  537. // |- flags
  538. //
  539. // syntax for the runtime platform:
  540. // [!] ( [!] Platform1 [; Platform2 ] ... )
  541. // example:
  542. // !(IA64; !X86) - will evaluate to TRUE when it's NOT IA64 (native) and X86
  543. // (IA3264; X86) - will evaluate to TRUE when it's running on X86 or 32-bit subsystem on IA64
  544. // (AMD64; IA3264) - will evaluate to TRUE when it's running on AMD64 or 32-bit subsystem on ia64
  545. //
  546. BOOL DecodeRuntimePlatformString(LPCTSTR pszPlatform, LPDWORD pdwRuntimePlatform)
  547. {
  548. BOOL bNot = FALSE;
  549. BOOL bBracket = FALSE;
  550. LPTSTR pEnd;
  551. TCHAR chSave;
  552. DWORD dwElement;
  553. DWORD dwNotElementFlag;
  554. DWORD dwRuntimePlatform = 0;
  555. INT nElement = 0;
  556. BOOL bSuccess = FALSE;
  557. pszPlatform += _tcsspn(pszPlatform, _T(" \t"));
  558. // got the first char
  559. if (*pszPlatform == _T('!')) {
  560. // peek ahead and see whether we have a bracket
  561. pEnd = (LPTSTR)(pszPlatform + 1);
  562. pEnd += _tcsspn(pEnd, _T(" \t"));
  563. if (*pEnd == '(') {
  564. // global not
  565. bNot = TRUE;
  566. pszPlatform = pEnd;
  567. } else {
  568. // local NOT -- so jump to parsing it
  569. goto ParseStart;
  570. }
  571. }
  572. if (*pszPlatform == _T('(')) {
  573. // bracket, we need to find closing one too
  574. ++pszPlatform;
  575. bBracket = TRUE;
  576. }
  577. ParseStart:
  578. do {
  579. dwElement = 0;
  580. pszPlatform += _tcsspn(pszPlatform, _T(" ;,\t"));
  581. if (*pszPlatform == _T('\0') || *pszPlatform == _T(')')) {
  582. break;
  583. }
  584. dwNotElementFlag = (*pszPlatform == _T('!')) ? RUNTIME_PLATFORM_FLAG_NOT_ELEMENT : 0;
  585. // find the end of this token
  586. pEnd = _tcspbrk(pszPlatform, _T(" \t;,)"));
  587. if (pEnd != NULL) {
  588. chSave = *pEnd;
  589. *pEnd = _T('\0');
  590. }
  591. dwElement = GetRuntimePlatformType(pszPlatform);
  592. if (pEnd) {
  593. *pEnd = chSave;
  594. }
  595. if (dwElement == PROCESSOR_ARCHITECTURE_UNKNOWN) {
  596. goto HandleError;
  597. }
  598. dwElement |= dwNotElementFlag | RUNTIME_PLATFORM_FLAG_VALID;
  599. if (nElement >= 3) {
  600. goto HandleError;
  601. }
  602. // now shift
  603. dwElement <<= (nElement * 8);
  604. ++nElement; // on to the next element
  605. dwRuntimePlatform |= dwElement;
  606. pszPlatform = pEnd;
  607. } while(pEnd); // when pEnd == NULL -- it was the last token
  608. if (bBracket && (!pszPlatform || *pszPlatform != ')')) {
  609. // we expected a bracket here
  610. goto HandleError;
  611. }
  612. if (bNot && nElement > 1) {
  613. dwRuntimePlatform |= RUNTIME_PLATFORM_FLAG_NOT;
  614. }
  615. *pdwRuntimePlatform = dwRuntimePlatform;
  616. bSuccess = TRUE;
  617. HandleError:
  618. return bSuccess;
  619. }
  620. ////////////////////////////////////////////////////////////////////////////////////
  621. //
  622. // Func: ReadName
  623. //
  624. // Desc: Wrapper to read the name attribute from an XML node.
  625. //
  626. BOOL ReadName( IXMLDOMNode* pNode, CString* pcsName)
  627. {
  628. BOOL bSuccess = FALSE;
  629. if (!GetAttribute(_T("NAME"), pNode, pcsName)) {
  630. SDBERROR_FORMAT((_T("NAME attribute required:\n%s\n\n"),
  631. GetXML(pNode)));
  632. goto eh;
  633. }
  634. bSuccess = TRUE;
  635. eh:
  636. return TRUE;
  637. }
  638. BOOL ReadLangID(IXMLDOMNode* pNode, SdbDatabase* pDB, CString* pcsLangID)
  639. {
  640. if (!GetAttribute(_T("LANGID"), pNode, pcsLangID)) {
  641. if (!pDB->m_csCurrentLangID.GetLength())
  642. {
  643. SDBERROR_FORMAT((
  644. _T("Tag requires LANGID attribute if there is no LANGID on the DATABASE node\n%s\n"),
  645. GetXML(pNode)));
  646. return FALSE;
  647. }
  648. *pcsLangID = pDB->m_csCurrentLangID;
  649. }
  650. return TRUE;
  651. }
  652. BOOL FilterOSVersion(DOUBLE flOSVersion, CString csOSVersionSpec, LPDWORD lpdwSPMask)
  653. {
  654. DOUBLE flVerXML;
  655. CString csTemp;
  656. long nBeg, i, nIndSP;
  657. int nSPVersion;
  658. TCHAR chSP;
  659. BOOL bFilter = TRUE;
  660. DWORD dwSPMask;
  661. if (flOSVersion == 0.0 || csOSVersionSpec.IsEmpty()) {
  662. *lpdwSPMask = 0xFFFFFFFF;
  663. return FALSE;
  664. }
  665. *lpdwSPMask = 0;
  666. nBeg = 0;
  667. for (i = 0; i <= csOSVersionSpec.GetLength(); i++) {
  668. if (csOSVersionSpec.GetAt(i) == _T('\0') || csOSVersionSpec.GetAt(i) == _T(';')) {
  669. csTemp = csOSVersionSpec.Mid(nBeg, i - nBeg);
  670. nBeg = i + 1;
  671. if (csTemp.GetLength() == 0) {
  672. continue;
  673. }
  674. dwSPMask = 0xFFFFFFFF;
  675. nSPVersion = -1;
  676. nIndSP = -1;
  677. if ((nIndSP = csTemp.Find('.')) != -1) {
  678. if ((nIndSP = csTemp.Find('.', nIndSP + 1)) != -1) {
  679. CString csSP = csTemp.Right(csTemp.GetLength() - nIndSP - 1);
  680. chSP = csTemp.GetAt(nIndSP);
  681. csTemp.SetAt(nIndSP, 0);
  682. nSPVersion = _ttoi(csSP);
  683. }
  684. }
  685. if (csTemp.Left(2) == _T("gt")) {
  686. if (csTemp.Left(3) == _T("gte")) {
  687. flVerXML = _tcstod(csTemp.Right(csTemp.GetLength() - 3), NULL);
  688. if (flOSVersion >= flVerXML) {
  689. bFilter = FALSE;
  690. }
  691. if (nSPVersion != -1 && flOSVersion == flVerXML) {
  692. dwSPMask = 0xFFFFFFFF - (1 << nSPVersion) + 1;
  693. }
  694. } else {
  695. flVerXML = _tcstod(csTemp.Right(csTemp.GetLength() - 2), NULL);
  696. if (flOSVersion > flVerXML) {
  697. bFilter = FALSE;
  698. }
  699. if (nSPVersion != -1 && flOSVersion == flVerXML) {
  700. bFilter = FALSE;
  701. dwSPMask = 0xFFFFFFFF - (1 << (nSPVersion + 1)) + 1;
  702. }
  703. }
  704. } else if (csTemp.Left(2) == _T("lt")) {
  705. if (csTemp.Left(3) == _T("lte")) {
  706. flVerXML = _tcstod(csTemp.Right(csTemp.GetLength() - 3), NULL);
  707. if (flOSVersion <= flVerXML) {
  708. bFilter = FALSE;
  709. }
  710. if (nSPVersion != -1 && flOSVersion == flVerXML) {
  711. dwSPMask = 0xFFFFFFFF - (1 << (nSPVersion + 1)) + 1;
  712. dwSPMask ^= 0xFFFFFFFF;
  713. }
  714. } else {
  715. flVerXML = _tcstod(csTemp.Right(csTemp.GetLength() - 2), NULL);
  716. if (flOSVersion < flVerXML) {
  717. bFilter = FALSE;
  718. }
  719. if (nSPVersion != -1 && flOSVersion == flVerXML) {
  720. bFilter = FALSE;
  721. dwSPMask = 0xFFFFFFFF - (1 << nSPVersion) + 1;
  722. dwSPMask ^= 0xFFFFFFFF;
  723. }
  724. }
  725. } else {
  726. if (flOSVersion == _tcstod(csTemp, NULL)) {
  727. bFilter = FALSE;
  728. if (nSPVersion != -1) {
  729. dwSPMask = (1 << nSPVersion);
  730. }
  731. }
  732. }
  733. if (nIndSP != -1) {
  734. csTemp.SetAt(nIndSP, chSP);
  735. *lpdwSPMask |= dwSPMask;
  736. }
  737. }
  738. }
  739. if (*lpdwSPMask == 0) {
  740. *lpdwSPMask = 0xFFFFFFFF;
  741. }
  742. return bFilter;
  743. }
  744. VOID ExpandEnvStrings(CString* pcs)
  745. {
  746. LPTSTR lpszBuf;
  747. DWORD cchReqBufSize;
  748. CString cs(*pcs);
  749. cchReqBufSize = ExpandEnvironmentStrings(cs, NULL, 0);
  750. lpszBuf = pcs->GetBuffer(cchReqBufSize);
  751. ExpandEnvironmentStrings(cs, lpszBuf, cchReqBufSize);
  752. pcs->ReleaseBuffer();
  753. }
  754. BOOL MakeUTCTime(CString& cs, time_t* pt)
  755. {
  756. BOOL bSuccess = FALSE;
  757. CString csTZ;
  758. //
  759. // Set TZ environment variable to override locale
  760. // settings so that date/time conversion routines
  761. // never do any localizations.
  762. //
  763. csTZ = _tgetenv(_T("TZ"));
  764. csTZ = _T("TZ=") + csTZ;
  765. _tputenv(_T("TZ=UTC0"));
  766. _tzset();
  767. COleDateTime odt;
  768. SYSTEMTIME st;
  769. CTime time;
  770. if (!odt.ParseDateTime(cs)) {
  771. goto eh;
  772. }
  773. if (!odt.GetAsSystemTime(st)) {
  774. goto eh;
  775. }
  776. time = st;
  777. *pt = time.GetTime();
  778. bSuccess = TRUE;
  779. eh:
  780. _tputenv(csTZ);
  781. _tzset();
  782. return bSuccess;
  783. }
  784. BOOL ParseLanguageID(LPCTSTR pszLanguage, DWORD* pdwLanguageID)
  785. {
  786. LPCTSTR pch;
  787. LPTSTR pend = NULL;
  788. BOOL bSuccess = FALSE;
  789. BOOL bBracket = FALSE;
  790. DWORD dwLangID = 0;
  791. pch = _tcschr(pszLanguage, TEXT('['));
  792. if (NULL != pch) {
  793. bBracket = TRUE;
  794. ++pch;
  795. } else {
  796. pch = pszLanguage;
  797. }
  798. while (_istspace(*pch)) {
  799. ++pch;
  800. }
  801. dwLangID = _tcstoul(pch, &pend, 0);
  802. if (dwLangID == 0) {
  803. goto cleanup;
  804. }
  805. if (pend != NULL) {
  806. bSuccess = bBracket ? (_istspace(*pend) || *pend == TEXT(']')) :
  807. (_istspace(*pend) || *pend == TEXT('\0'));
  808. }
  809. cleanup:
  810. if (bSuccess) {
  811. *pdwLanguageID = dwLangID;
  812. }
  813. return bSuccess;
  814. }
  815. BOOL ParseLanguagesString(CString csLanguages, CStringArray* prgLanguages)
  816. {
  817. BOOL bSuccess = FALSE, bExistsAlready = FALSE;
  818. int nLastSemicolon = -1, i, j;
  819. CString csLangID;
  820. for (i = 0; i <= csLanguages.GetLength(); i++)
  821. {
  822. if (csLanguages[i] == _T(';') || csLanguages[i] == _T('\0')) {
  823. csLangID = csLanguages.Mid(nLastSemicolon + 1, i - nLastSemicolon - 1);
  824. csLangID.TrimLeft();
  825. csLangID.TrimRight();
  826. csLangID.MakeUpper();
  827. bExistsAlready = FALSE;
  828. for (j = 0; j < prgLanguages->GetSize(); j++)
  829. {
  830. if (prgLanguages->GetAt(j) == csLangID)
  831. {
  832. bExistsAlready = TRUE;
  833. break;
  834. }
  835. }
  836. if (!bExistsAlready)
  837. {
  838. prgLanguages->Add(csLangID);
  839. }
  840. nLastSemicolon = i;
  841. }
  842. }
  843. bSuccess = TRUE;
  844. return bSuccess;
  845. }
  846. CString GetGUID(REFGUID guid)
  847. {
  848. CString csRet;
  849. LPOLESTR lpszGUID = NULL;
  850. StringFromCLSID(guid, &lpszGUID);
  851. csRet = lpszGUID;
  852. CoTaskMemFree(lpszGUID);
  853. return csRet;
  854. }
  855. CString ProcessShimCmdLine(
  856. CString& csCommandLine,
  857. GUID& guidDB,
  858. TAGID tiShimRef
  859. )
  860. {
  861. //
  862. // find whether we have anything to expand in csCommandLine
  863. //
  864. LPCTSTR pch;
  865. int nIndex;
  866. CString csNewCmdLine = csCommandLine;
  867. CString csToken;
  868. int nIndexStart = 0;
  869. int nIndexEnd;
  870. while (nIndexStart < csNewCmdLine.GetLength()) {
  871. nIndex = csNewCmdLine.Find(_T('%'), nIndexStart);
  872. if (nIndex < 0) {
  873. goto Done;
  874. }
  875. nIndexEnd = csNewCmdLine.Find(_T('%'), nIndex + 1);
  876. if (nIndexEnd < 0) {
  877. goto Done;
  878. }
  879. //
  880. // we matched a token, see whether it's something we're interested in
  881. //
  882. csToken = csNewCmdLine.Mid(nIndex + 1, nIndexEnd - nIndex - 1);
  883. if (0 == csToken.CompareNoCase(_T("DBINFO"))) {
  884. csToken.Format(_T("-d%ls -t0x%lx"), (LPCTSTR)GetGUID(guidDB), tiShimRef);
  885. //
  886. // replace the token with csToken
  887. //
  888. csNewCmdLine.Delete(nIndex, nIndexEnd - nIndex + 1);
  889. csNewCmdLine.Insert(nIndex, csToken);
  890. //
  891. // adjust our position for scanning
  892. //
  893. nIndexEnd = nIndex + csToken.GetLength() - 1; // one char before the end of this token
  894. }
  895. nIndexStart = nIndexEnd + 1;
  896. }
  897. Done:
  898. return csNewCmdLine;
  899. }