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.

737 lines
15 KiB

  1. #include "stdinc.h"
  2. #include "debmacro.h"
  3. #include "ntdef.h"
  4. #include "fusionparser.h"
  5. #include "shlwapi.h"
  6. #if !defined(NUMBER_OF)
  7. #define NUMBER_OF(x) (sizeof(x) / sizeof((x)[0]))
  8. #endif
  9. BOOL
  10. CFusionParser::ParseVersion(
  11. ASSEMBLY_VERSION &rav,
  12. PCWSTR sz,
  13. SIZE_T cch,
  14. bool &rfSyntaxValid
  15. )
  16. {
  17. BOOL fSuccess = FALSE;
  18. FN_TRACE_WIN32(fSuccess);
  19. ULONG cDots = 0;
  20. PCWSTR pszTemp;
  21. SIZE_T cchLeft;
  22. ULONG ulTemp;
  23. ASSEMBLY_VERSION avTemp;
  24. PCWSTR pszLast;
  25. bool fSyntaxValid = true;
  26. rfSyntaxValid = false;
  27. PARAMETER_CHECK((sz != NULL) || (cch == 0));
  28. avTemp.Major = 0;
  29. avTemp.Minor = 0;
  30. avTemp.Revision = 0;
  31. avTemp.Build = 0;
  32. while ((cch != 0) && (sz[cch - 1] == L'\0'))
  33. cch--;
  34. // Unfortunately there isn't a StrChrN(), so we'll look for the dots ourselves...
  35. pszTemp = sz;
  36. cchLeft = cch;
  37. while (cchLeft-- != 0)
  38. {
  39. WCHAR wch = *pszTemp++;
  40. if (wch == L'.')
  41. {
  42. cDots++;
  43. if (cDots >= 4)
  44. {
  45. fSyntaxValid = false;
  46. break;
  47. }
  48. }
  49. else if ((wch < L'0') || (wch > L'9'))
  50. {
  51. fSyntaxValid = false;
  52. break;
  53. }
  54. }
  55. if (fSyntaxValid && (cDots < 3))
  56. fSyntaxValid = false;
  57. if (fSyntaxValid)
  58. {
  59. pszTemp = sz;
  60. pszLast = sz + cch;
  61. ulTemp = 0;
  62. for (;;)
  63. {
  64. WCHAR wch = *pszTemp++;
  65. if (wch == L'.')
  66. break;
  67. ulTemp = (ulTemp * 10) + (wch - L'0');
  68. if (ulTemp > 65535)
  69. {
  70. fSuccess = true;
  71. // rfSyntaxValid implicitly false
  72. ASSERT(!rfSyntaxValid);
  73. goto Exit;
  74. }
  75. }
  76. avTemp.Major = (USHORT) ulTemp;
  77. ulTemp = 0;
  78. for (;;)
  79. {
  80. WCHAR wch = *pszTemp++;
  81. if (wch == L'.')
  82. break;
  83. ulTemp = (ulTemp * 10) + (wch - L'0');
  84. if (ulTemp > 65535)
  85. {
  86. fSuccess = true;
  87. // rfSyntaxValid implicitly false
  88. ASSERT(!rfSyntaxValid);
  89. goto Exit;
  90. }
  91. }
  92. avTemp.Minor = (USHORT) ulTemp;
  93. ulTemp = 0;
  94. for (;;)
  95. {
  96. WCHAR wch = *pszTemp++;
  97. if (wch == L'.')
  98. break;
  99. ulTemp = (ulTemp * 10) + (wch - L'0');
  100. if (ulTemp > 65535)
  101. {
  102. fSuccess = true;
  103. // rfSyntaxValid implicitly false
  104. ASSERT(!rfSyntaxValid);
  105. goto Exit;
  106. }
  107. }
  108. avTemp.Revision = (USHORT) ulTemp;
  109. // Now the tricky bit. We aren't necessarily null-terminated, so we
  110. // have to just look for hitting the end.
  111. ulTemp = 0;
  112. while (pszTemp < pszLast)
  113. {
  114. WCHAR wch = *pszTemp++;
  115. ulTemp = (ulTemp * 10) + (wch - L'0');
  116. if (ulTemp > 65535)
  117. {
  118. fSuccess = true;
  119. // rfSyntaxValid implicitly false
  120. ASSERT(!rfSyntaxValid);
  121. goto Exit;
  122. }
  123. }
  124. avTemp.Build = (USHORT) ulTemp;
  125. rav = avTemp;
  126. }
  127. rfSyntaxValid = fSyntaxValid;
  128. fSuccess = TRUE;
  129. Exit:
  130. return fSuccess;
  131. }
  132. #if FUSION_DISABLED_CODE
  133. HRESULT CFusionParser::ParseThreadingModel(ULONG &threadingModel, PCWSTR sz, SIZE_T cch)
  134. {
  135. HRESULT hr = NOERROR;
  136. #define FUSIONPARSER_PARSETHREADINGMODELENTRY(x, y) \
  137. { x, NUMBER_OF(x) - 1, y },
  138. static const struct
  139. {
  140. PCWSTR m_psz;
  141. SIZE_T m_cch;
  142. ULONG m_threadingModel;
  143. } s_rgmap[] =
  144. {
  145. FUSIONPARSER_PARSETHREADINGMODELENTRY(L"Free", COMCLASS_THREADINGMODEL_FREE)
  146. FUSIONPARSER_PARSETHREADINGMODELENTRY(L"Apartment", COMCLASS_THREADINGMODEL_APARTMENT)
  147. FUSIONPARSER_PARSETHREADINGMODELENTRY(L"Both", COMCLASS_THREADINGMODEL_BOTH)
  148. };
  149. ULONG i;
  150. // If the caller included the terminating null character, back up one.
  151. while ((cch != 0) && (sz[cch - 1] == L'\0'))
  152. cch--;
  153. for (i=0; i<NUMBER_OF(s_rgmap); i++)
  154. {
  155. if ((s_rgmap[i].m_cch == cch) &&
  156. (StrCmpNI(s_rgmap[i].m_psz, sz, cch) == 0))
  157. break;
  158. }
  159. if (i == NUMBER_OF(s_rgmap))
  160. {
  161. // ParseError
  162. hr = E_FAIL;
  163. goto Exit;
  164. }
  165. threadingModel = s_rgmap[i].m_threadingModel;
  166. hr = NOERROR;
  167. Exit:
  168. return hr;
  169. }
  170. HRESULT CFusionParser::ParseBoolean(BOOLEAN &rfValue, PCWSTR sz, SIZE_T cch)
  171. {
  172. HRESULT hr = NOERROR;
  173. static const struct
  174. {
  175. PCWSTR m_psz;
  176. SIZE_T m_cch;
  177. BOOLEAN m_fValue;
  178. } s_rgmap[] =
  179. {
  180. { L"yes", 3, TRUE },
  181. { L"no", 2, FALSE },
  182. };
  183. ULONG i;
  184. if (cch < 0)
  185. cch = ::wcslen(sz);
  186. // Some callers may erroneously include the null character in the length...
  187. while ((cch != 0) && (sz[cch - 1] == L'\0'))
  188. cch--;
  189. for (i=0; i<NUMBER_OF(s_rgmap); i++)
  190. {
  191. if ((cch == s_rgmap[i].m_cch) &&
  192. (StrCmpNIW(s_rgmap[i].m_psz, sz, cch) == 0))
  193. break;
  194. }
  195. if (i == NUMBER_OF(s_rgmap))
  196. {
  197. // ParseError
  198. hr = E_FAIL;
  199. goto Exit;
  200. }
  201. rfValue = s_rgmap[i].m_fValue;
  202. hr = NOERROR;
  203. Exit:
  204. return hr;
  205. }
  206. HRESULT CFusionParser::ParseBLOB(BLOB &rblob, PCWSTR szIn, SSIZE_T cch)
  207. {
  208. HRESULT hr = NOERROR;
  209. PCWSTR psz;
  210. WCHAR wch;
  211. SIZE_T cchLeft;
  212. BYTE *pBlobData = NULL;
  213. ULONG cbSize = 0;
  214. psz = szIn;
  215. if (cch < 0)
  216. cch = ::wcslen(szIn);
  217. if ((cch != 0) && (szIn[cch - 1] == L'\0'))
  218. cch--;
  219. cchLeft = cch;
  220. // Run through the string twice; once to count bytes and the second time to
  221. // parse them.
  222. while (cchLeft-- != 0)
  223. {
  224. wch = *psz++;
  225. // Space and dash are nice separators; just ignore them.
  226. if ((wch == L' ') ||
  227. (wch == L'-'))
  228. continue;
  229. if (!SxspIsHexDigit(wch))
  230. {
  231. // Bad character; punt.
  232. // ParseError
  233. hr = E_FAIL;
  234. goto Exit;
  235. }
  236. // First character was good; look for the 2nd nibble
  237. wch = *psz++;
  238. if ((wch == L'\0') ||
  239. (wch == L'-') ||
  240. (wch == L' '))
  241. {
  242. cbSize++;
  243. if (wch == L'\0')
  244. break;
  245. }
  246. else if (!SxspIsHexDigit(wch))
  247. {
  248. // ParseError
  249. hr = E_FAIL;
  250. goto Exit;
  251. }
  252. else
  253. {
  254. cbSize++;
  255. }
  256. }
  257. if (cbSize != 0)
  258. {
  259. BYTE *pb = NULL;
  260. // Allocate the buffer and parse the string for real this time.
  261. pBlobData = NEW(BYTE[cbSize]);
  262. if (pBlobData == NULL)
  263. {
  264. hr = E_OUTOFMEMORY;
  265. goto Exit;
  266. }
  267. // We do not attempt to clean up pBlobData in the exit path, so
  268. // if you add code here that can fail, be sure to clean up pBlobData
  269. // if you do fail.
  270. psz = szIn;
  271. cchLeft = cch;
  272. pb = pBlobData;
  273. while (cchLeft-- != 0)
  274. {
  275. wch = *psz++;
  276. // Space and dash are nice separators; just ignore them.
  277. if ((wch == L' ') ||
  278. (wch == L'-'))
  279. continue;
  280. bTemp = SxspHexDigitToValue(wch);
  281. wch = *psz++;
  282. if ((wch == L'\0') ||
  283. (wch == L'-') ||
  284. (wch == L' '))
  285. {
  286. *pb++ = bTemp;
  287. if (wch == L'\0')
  288. break;
  289. }
  290. *pb++ = (bTemp << 4) | SxspHexDigitToValue(wch);
  291. }
  292. }
  293. rblob.pBlobData = pBlobData;
  294. rblob.cbSize = cbSize;
  295. hr = NOERROR;
  296. Exit:
  297. // No need to clean up pBlobData; we don't fail after its attempted allocation.
  298. return hr;
  299. }
  300. #endif // FUSION_DISABLED_CODE
  301. BOOL
  302. CFusionParser::ParseULONG(
  303. ULONG &rul,
  304. PCWSTR sz,
  305. SIZE_T cch,
  306. ULONG Radix
  307. )
  308. {
  309. BOOL fSuccess = FALSE;
  310. FN_TRACE_WIN32(fSuccess);
  311. ULONG ulTemp = 0;
  312. PARAMETER_CHECK((Radix >= 2) && (Radix <= 36));
  313. while (cch != 0)
  314. {
  315. const WCHAR wch = *sz++;
  316. ULONG Digit = 0;
  317. cch--;
  318. if ((wch >= L'0') && (wch <= L'9'))
  319. Digit = (wch - L'0');
  320. else if ((wch >= L'a') && (wch <= L'z'))
  321. Digit = (10 + wch - L'a');
  322. else if ((wch >= L'A') && (wch <= L'Z'))
  323. Digit = (10 + wch - L'A');
  324. else
  325. ORIGINATE_WIN32_FAILURE_AND_EXIT(InvalidDigit, ERROR_SXS_MANIFEST_PARSE_ERROR);
  326. if (Digit >= Radix)
  327. ORIGINATE_WIN32_FAILURE_AND_EXIT(InvalidDigitForRadix, ERROR_SXS_MANIFEST_PARSE_ERROR);
  328. ulTemp = (ulTemp * Radix) + Digit;
  329. }
  330. rul = ulTemp;
  331. fSuccess = TRUE;
  332. Exit:
  333. return fSuccess;
  334. }
  335. BOOL
  336. CFusionParser::ParseIETFDate(
  337. FILETIME &rft,
  338. PCWSTR sz,
  339. SIZE_T cch
  340. )
  341. {
  342. BOOL fSuccess = FALSE;
  343. FN_TRACE_WIN32(fSuccess);
  344. SYSTEMTIME st;
  345. ULONG ulTemp;
  346. //
  347. // Our format is:
  348. //
  349. // DD/MM/YYYY
  350. // 0123456789
  351. //
  352. // Strip off extra \0's from the end of sz, adjusting the cch
  353. //
  354. while ( ( cch != 0 ) && ( sz[cch - 1] == L'\0' ) )
  355. cch--;
  356. PARAMETER_CHECK(cch == 10);
  357. PARAMETER_CHECK(sz[2] == L'/');
  358. PARAMETER_CHECK(sz[5] == L'/');
  359. ZeroMemory( &st, sizeof( st ) );
  360. IFW32FALSE_EXIT(CFusionParser::ParseULONG(ulTemp, sz, 2, 10));
  361. st.wDay = (WORD)ulTemp;
  362. IFW32FALSE_EXIT(CFusionParser::ParseULONG(ulTemp, sz + 3, 2, 10));
  363. st.wMonth = (WORD)ulTemp;
  364. IFW32FALSE_EXIT(CFusionParser::ParseULONG(ulTemp, sz + 6, 4, 10));
  365. st.wYear = (WORD)ulTemp;
  366. IFW32FALSE_ORIGINATE_AND_EXIT(::SystemTimeToFileTime(&st, &rft));
  367. fSuccess = TRUE;
  368. Exit:
  369. return fSuccess;
  370. }
  371. BOOL
  372. CFusionParser::ParseFILETIME(
  373. FILETIME &rft,
  374. PCWSTR sz,
  375. SIZE_T cch
  376. )
  377. {
  378. BOOL fSuccess = FALSE;
  379. FN_TRACE_WIN32(fSuccess);
  380. SYSTEMTIME st;
  381. ULONG ulTemp;
  382. while ((cch != 0) && (sz[cch - 1] == L'\0'))
  383. cch--;
  384. // MM/DD/YYYY HH:MM:SS.CCC
  385. // 01234567890123456789012
  386. if (cch != 23) // 23 is the exact length of a filetime that we require
  387. ORIGINATE_WIN32_FAILURE_AND_EXIT(BadFiletimeLength, ERROR_SXS_MANIFEST_PARSE_ERROR);
  388. st.wMonth = 0;
  389. st.wDay = 0;
  390. st.wYear = 0;
  391. st.wHour = 0;
  392. st.wMinute = 0;
  393. st.wSecond = 0;
  394. st.wMilliseconds = 0;
  395. if ((sz[2] != L'/') ||
  396. (sz[5] != L'/') ||
  397. (sz[10] != L' ') ||
  398. (sz[13] != L':') ||
  399. (sz[16] != L':') ||
  400. (sz[19] != L'.'))
  401. {
  402. ::SetLastError(ERROR_SXS_MANIFEST_PARSE_ERROR);
  403. goto Exit;
  404. }
  405. #define PARSE_FIELD(_field, _index, _length) \
  406. do \
  407. { \
  408. if (!CFusionParser::ParseULONG(ulTemp, &sz[(_index)], (_length))) \
  409. goto Exit; \
  410. st._field = (WORD) ulTemp; \
  411. } while (0)
  412. PARSE_FIELD(wMonth, 0, 2);
  413. PARSE_FIELD(wDay, 3, 2);
  414. PARSE_FIELD(wYear, 6, 4);
  415. PARSE_FIELD(wHour, 11, 2);
  416. PARSE_FIELD(wMinute, 14, 2);
  417. PARSE_FIELD(wSecond, 17, 2);
  418. PARSE_FIELD(wMilliseconds, 20, 3);
  419. IFW32FALSE_ORIGINATE_AND_EXIT(::SystemTimeToFileTime(&st, &rft));
  420. fSuccess = TRUE;
  421. Exit:
  422. return fSuccess;
  423. }
  424. BOOL
  425. FusionDupString(
  426. LPWSTR *ppszOut,
  427. PCWSTR szIn,
  428. SIZE_T cchIn
  429. )
  430. {
  431. BOOL fSuccess = FALSE;
  432. FN_TRACE_WIN32(fSuccess);
  433. if (ppszOut != NULL)
  434. *ppszOut = NULL;
  435. PARAMETER_CHECK((cchIn == 0) || (szIn != NULL));
  436. PARAMETER_CHECK(ppszOut != NULL);
  437. IFALLOCFAILED_EXIT(*ppszOut = FUSION_NEW_ARRAY(WCHAR, cchIn + 1));
  438. if (cchIn != 0)
  439. memcpy(*ppszOut, szIn, cchIn * sizeof(WCHAR));
  440. (*ppszOut)[cchIn] = L'\0';
  441. fSuccess = TRUE;
  442. Exit:
  443. return fSuccess;
  444. }
  445. int SxspHexDigitToValue(WCHAR wch)
  446. {
  447. if ((wch >= L'a') && (wch <= L'f'))
  448. return 10 + (wch - L'a');
  449. else if ((wch >= L'A') && (wch <= 'F'))
  450. return 10 + (wch - L'A');
  451. else if (wch >= '0' && wch <= '9')
  452. return (wch - L'0');
  453. else
  454. return -1;
  455. }
  456. bool SxspIsHexDigit(WCHAR wch)
  457. {
  458. return (((wch >= L'0') && (wch <= L'9')) ||
  459. ((wch >= L'a') && (wch <= L'f')) ||
  460. ((wch >= L'A') && (wch <= L'F')));
  461. }
  462. #if FUSION_DISABLED_CODE
  463. HRESULT CFusionParser::ParseULARGE_INTEGER(ULARGE_INTEGER &ruli, PCWSTR sz, SIZE_T cch)
  464. {
  465. HRESULT hr = NOERROR;
  466. ULONGLONG ullTemp = 0;
  467. if (cch < 0)
  468. cch = ::wcslen(sz);
  469. while ((cch != 0) && (sz[cch - 1] == L'\0'))
  470. cch--;
  471. while (cch-- != 0)
  472. {
  473. WCHAR wch = *sz++;
  474. // If we see anything other than a digit, we fail. We're not
  475. // atoi(); we're hard core.
  476. if ((wch < L'0') ||
  477. (wch > L'9'))
  478. {
  479. hr = E_FAIL;
  480. goto Exit;
  481. }
  482. // I don't know if I really need all these casts, but I don't know what the
  483. // compiler's documented behavior for expressions of mixed unsigned __int64, int and
  484. // unsigned short types will be. Instead we'll explicitly cast everything to
  485. // unsigned __int64 (e.g. ULONGLONG) and hopefully the right stuff will happen.
  486. ullTemp = (ullTemp * static_cast<ULONGLONG>(10)) + static_cast<ULONGLONG>(wch - L'\0');
  487. }
  488. ruli.QuadPart = ullTemp;
  489. hr = NOERROR;
  490. Exit:
  491. return hr;
  492. }
  493. HRESULT CFusionParser::ParseHexString(PCWSTR sz, SIZE_T cch, DWORD &rdwOut, PCWSTR &rszOut)
  494. {
  495. HRESULT hr = NOERROR;
  496. FN_TRACE_HR(hr);
  497. DWORD dw = 0;
  498. if (cch < 0)
  499. cch = ::wcslen(sz);
  500. while ((cch != 0) && (sz[cch - 1] == L'\0'))
  501. cch--;
  502. while (cch-- != 0)
  503. {
  504. int i = ::SxspHexDigitToValue(*sz++);
  505. INTERNAL_ERROR_CHECK(i >= 0);
  506. dw = (dw << 4) | i;
  507. }
  508. rdwOut = dw;
  509. rszOut = sz;
  510. hr = NOERROR;
  511. Exit:
  512. return hr;
  513. }
  514. HRESULT
  515. FusionCopyString(
  516. WCHAR *prgchBuffer,
  517. SIZE_T *pcchBuffer,
  518. PCWSTR szIn,
  519. SIZE_T cchIn)
  520. {
  521. HRESULT hr = NOERROR;
  522. FN_TRACE_HR(hr);
  523. SIZE_T cch;
  524. PARAMETER_CHECK(pcchBuffer != NULL);
  525. PARAMETER_CHECK((pcchBuffer == NULL) || ((*pcchBuffer == 0) || (prgchBuffer != NULL)));
  526. PARAMETER_CHECK((szIn != NULL) || (cchIn == 0));
  527. if (cchIn < 0)
  528. cchIn = ::wcslen(szIn);
  529. if ((*pcchBuffer) < ((SIZE_T) (cchIn + 1)))
  530. {
  531. *pcchBuffer = cchIn + 1;
  532. ORIGINATE_WIN32_FAILURE_AND_EXIT(NoRoom, ERROR_INSUFFICIENT_BUFFER);
  533. }
  534. memcpy(prgchBuffer, szIn, cchIn * sizeof(WCHAR));
  535. prgchBuffer[cchIn] = L'\0';
  536. *pcchBuffer = (cchIn + 1);
  537. hr = NOERROR;
  538. Exit:
  539. return hr;
  540. }
  541. HRESULT FusionCopyBlob(BLOB *pblobOut, const BLOB &rblobIn)
  542. {
  543. HRESULT hr = NOERROR;
  544. if (pblobOut != NULL)
  545. {
  546. pblobOut->cbSize = 0;
  547. pblobOut->pBlobData = NULL;
  548. }
  549. if (pblobOut == NULL)
  550. {
  551. hr = E_POINTER;
  552. goto Exit;
  553. }
  554. if (rblobIn.cbSize != 0)
  555. {
  556. pblobOut->pBlobData = NEW(BYTE[rblobIn.cbSize]);
  557. if (pblobOut->pBlobData == NULL)
  558. {
  559. hr = E_OUTOFMEMORY;
  560. goto Exit;
  561. }
  562. memcpy(pblobOut->pBlobData, rblobIn.pBlobData, rblobIn.cbSize);
  563. pblobOut->cbSize = rblobIn.cbSize;
  564. }
  565. hr = NOERROR;
  566. Exit:
  567. return hr;
  568. }
  569. VOID FusionFreeBlob(BLOB *pblob)
  570. {
  571. if (pblob != NULL)
  572. {
  573. if (pblob->pBlobData != NULL)
  574. {
  575. CSxsPreserveLastError ple;
  576. delete []pblob->pBlobData;
  577. pblob->pBlobData = NULL;
  578. ple.Restore();
  579. }
  580. pblob->cbSize = 0;
  581. }
  582. }
  583. #endif // FUSION_DISABLED_CODE