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.

2014 lines
55 KiB

  1. /*++
  2. Copyright (c) 1991-2000, Microsoft Corporation All rights reserved.
  3. Module Name:
  4. util.c
  5. Abstract:
  6. This file contains utility functions that are shared across NLS's code
  7. modules, but are not necessarily part of any of the existing code
  8. modules.
  9. Private APIs found in this file:
  10. NlsGetCacheUpdateCount
  11. External Routines found in this file:
  12. IsValidSeparatorString
  13. IsValidGroupingString
  14. IsValidCalendarType
  15. IsValidCalendarTypeStr
  16. GetUserInfo
  17. GetPreComposedChar
  18. GetCompositeChars
  19. InsertPreComposedForm
  20. InsertFullWidthPreComposedForm
  21. InsertCompositeForm
  22. NlsConvertIntegerToString
  23. NlsConvertIntegerToHexStringW
  24. NlsConvertStringToIntegerW
  25. NlsStrCpyW
  26. NlsStrCatW
  27. NlsStrLenW
  28. NlsStrNCatW
  29. NlsStrEqualW
  30. NlsStrNEqualW
  31. GetStringTableEntry
  32. NlsIsDll
  33. Revision History:
  34. 05-31-91 JulieB Created.
  35. --*/
  36. //
  37. // Include Files.
  38. //
  39. #include "nls.h"
  40. //-------------------------------------------------------------------------//
  41. // PRIVATE API ROUTINES //
  42. //-------------------------------------------------------------------------//
  43. ////////////////////////////////////////////////////////////////////////////
  44. //
  45. // NlsGetCacheUpdateCount
  46. //
  47. // Returns the current cache update count. The cache update count is
  48. // updated whenever the HKCU\Control Panel\International settings are
  49. // modified. This count allows the caller to see if the cache has been
  50. // updated since the last time this function was called.
  51. //
  52. // This private api is needed by the Complex Script Language Pack
  53. // (CSLPK) to enable it to quickly see if the international section of
  54. // the registry has been modified.
  55. //
  56. ////////////////////////////////////////////////////////////////////////////
  57. ULONG WINAPI NlsGetCacheUpdateCount(void)
  58. {
  59. return (pNlsUserInfo->ulCacheUpdateCount);
  60. }
  61. //-------------------------------------------------------------------------//
  62. // EXTERNAL ROUTINES //
  63. //-------------------------------------------------------------------------//
  64. ////////////////////////////////////////////////////////////////////////////
  65. //
  66. // IsValidSeparatorString
  67. //
  68. // Returns TRUE if the given string is valid. Otherwise, it returns FALSE.
  69. //
  70. // A valid string is one that does NOT contain any code points between
  71. // L'0' and L'9', and does NOT have a length greater than the maximum.
  72. //
  73. // NOTE: The string must be a null terminated string.
  74. //
  75. // 10-12-93 JulieB Created.
  76. ////////////////////////////////////////////////////////////////////////////
  77. BOOL IsValidSeparatorString(
  78. LPCWSTR pString,
  79. ULONG MaxLength,
  80. BOOL fCheckZeroLen)
  81. {
  82. ULONG Length; // string length
  83. LPWSTR pCur; // ptr to current position in string
  84. //
  85. // Search down the string to see if the chars are valid.
  86. // Save the length of the string.
  87. //
  88. pCur = (LPWSTR)pString;
  89. while (*pCur)
  90. {
  91. if ((*pCur >= NLS_CHAR_ZERO) && (*pCur <= NLS_CHAR_NINE))
  92. {
  93. //
  94. // String is NOT valid.
  95. //
  96. return (FALSE);
  97. }
  98. pCur++;
  99. }
  100. Length = (ULONG)(pCur - (LPWSTR)pString);
  101. //
  102. // Make sure the length is not greater than the maximum allowed.
  103. // Also, check for 0 length string (if appropriate).
  104. //
  105. if ((Length >= MaxLength) ||
  106. ((fCheckZeroLen) && (Length == 0)))
  107. {
  108. //
  109. // String is NOT valid.
  110. //
  111. return (FALSE);
  112. }
  113. //
  114. // String is valid.
  115. //
  116. return (TRUE);
  117. }
  118. ////////////////////////////////////////////////////////////////////////////
  119. //
  120. // IsValidGroupingString
  121. //
  122. // Returns TRUE if the given string is valid. Otherwise, it returns FALSE.
  123. //
  124. // A valid string is one that begins and ends with a number between
  125. // L'0' and L'9', alternates between a number and a semicolon, and does
  126. // NOT have a length greater than the maximum.
  127. // (eg. 3;2;0 or 3;0 or 0 or 3)
  128. //
  129. // NOTE: The string must be a null terminated string.
  130. //
  131. // 01-05-98 JulieB Created.
  132. ////////////////////////////////////////////////////////////////////////////
  133. BOOL IsValidGroupingString(
  134. LPCWSTR pString,
  135. ULONG MaxLength,
  136. BOOL fCheckZeroLen)
  137. {
  138. ULONG Length; // string length
  139. LPWSTR pCur; // ptr to current position in string
  140. //
  141. // Search down the string to see if the chars are valid.
  142. // Save the length of the string.
  143. //
  144. pCur = (LPWSTR)pString;
  145. while (*pCur)
  146. {
  147. if ((*pCur < NLS_CHAR_ZERO) || (*pCur > NLS_CHAR_NINE))
  148. {
  149. //
  150. // String is NOT valid.
  151. //
  152. return (FALSE);
  153. }
  154. pCur++;
  155. if (*pCur)
  156. {
  157. if ((*pCur != NLS_CHAR_SEMICOLON) || (*(pCur + 1) == 0))
  158. {
  159. //
  160. // String is NOT valid.
  161. //
  162. return (FALSE);
  163. }
  164. pCur++;
  165. }
  166. }
  167. Length = (ULONG)(pCur - (LPWSTR)pString);
  168. //
  169. // Make sure the length is not greater than the maximum allowed.
  170. // Also, check for 0 length string (if appropriate).
  171. //
  172. if ((Length >= MaxLength) ||
  173. ((fCheckZeroLen) && (Length == 0)))
  174. {
  175. //
  176. // String is NOT valid.
  177. //
  178. return (FALSE);
  179. }
  180. //
  181. // String is valid.
  182. //
  183. return (TRUE);
  184. }
  185. ////////////////////////////////////////////////////////////////////////////
  186. //
  187. // IsValidCalendarType
  188. //
  189. // Returns the pointer to the optional calendar structure if the given
  190. // calendar type is valid for the given locale. Otherwise, it returns
  191. // NULL.
  192. //
  193. // 10-12-93 JulieB Created.
  194. ////////////////////////////////////////////////////////////////////////////
  195. LPWORD IsValidCalendarType(
  196. PLOC_HASH pHashN,
  197. CALID CalId)
  198. {
  199. LPWORD pOptCal; // ptr to list of optional calendars
  200. LPWORD pEndOptCal; // ptr to end of list of optional calendars
  201. //
  202. // Make sure the Cal Id is not zero, since that may be in the
  203. // optional calendar section (meaning no optional calendars).
  204. //
  205. if (CalId == 0)
  206. {
  207. return (NULL);
  208. }
  209. //
  210. // Search down the list of optional calendars.
  211. //
  212. pOptCal = (LPWORD)(pHashN->pLocaleHdr) + pHashN->pLocaleHdr->IOptionalCal;
  213. pEndOptCal = (LPWORD)(pHashN->pLocaleHdr) + pHashN->pLocaleHdr->SDayName1;
  214. while (pOptCal < pEndOptCal)
  215. {
  216. //
  217. // Check the calendar ids.
  218. //
  219. if (CalId == ((POPT_CAL)pOptCal)->CalId)
  220. {
  221. //
  222. // Calendar id is valid for the given locale.
  223. //
  224. return (pOptCal);
  225. }
  226. //
  227. // Increment to the next optional calendar.
  228. //
  229. pOptCal += ((POPT_CAL)pOptCal)->Offset;
  230. }
  231. //
  232. // Calendar id is NOT valid if this point is reached.
  233. //
  234. return (NULL);
  235. }
  236. ////////////////////////////////////////////////////////////////////////////
  237. //
  238. // IsValidCalendarTypeStr
  239. //
  240. // Converts the calendar string to an integer and validates the calendar
  241. // id for the given locale. It return a pointer to the optional calendar
  242. // structure, or null if the calendar id was invalid.
  243. //
  244. // 10-19-93 JulieB Created.
  245. ////////////////////////////////////////////////////////////////////////////
  246. LPWORD IsValidCalendarTypeStr(
  247. PLOC_HASH pHashN,
  248. LPCWSTR pCalStr)
  249. {
  250. UNICODE_STRING ObUnicodeStr; // value string
  251. CALID CalNum; // calendar id
  252. //
  253. // Convert the string to an integer value.
  254. //
  255. RtlInitUnicodeString(&ObUnicodeStr, pCalStr);
  256. if (RtlUnicodeStringToInteger(&ObUnicodeStr, 10, &CalNum))
  257. {
  258. return (NULL);
  259. }
  260. //
  261. // Validate the calendar id and return the pointer to the
  262. // optional calendar structure.
  263. //
  264. return (IsValidCalendarType(pHashN, CalNum));
  265. }
  266. ////////////////////////////////////////////////////////////////////////////
  267. //
  268. // GetCPFileNameFromRegistry
  269. //
  270. // Gets the name of the code page file from the registry. If pResultBuf
  271. // or Size == 0, then just return true if it exists in the registry, but
  272. // don't return the actual value.
  273. //
  274. // 05-31-2002 ShawnSte Created.
  275. ////////////////////////////////////////////////////////////////////////////
  276. BOOL GetCPFileNameFromRegistry(
  277. UINT CodePage,
  278. LPWSTR pResultBuf,
  279. UINT Size)
  280. {
  281. // Working things.
  282. WCHAR pTmpBuf[MAX_SMALL_BUF_LEN]; // temp buffer
  283. PKEY_VALUE_FULL_INFORMATION pKeyValueFull; // ptr to query info
  284. BYTE pStatic[MAX_KEY_VALUE_FULLINFO]; // ptr to static buffer
  285. //
  286. // Convert value to unicode string.
  287. //
  288. if (!NT_SUCCESS(NlsConvertIntegerToString( CodePage,
  289. 10,
  290. 0,
  291. pTmpBuf,
  292. MAX_SMALL_BUF_LEN )))
  293. {
  294. // Didn't work. (Don't bother closing key though, its used globally)
  295. return (FALSE);
  296. }
  297. // Open hCodePageKey, return false if it fails
  298. OPEN_CODEPAGE_KEY(FALSE);
  299. //
  300. // Query the registry value for that code page.
  301. //
  302. pKeyValueFull = (PKEY_VALUE_FULL_INFORMATION)pStatic;
  303. if ( NO_ERROR != QueryRegValue( hCodePageKey,
  304. pTmpBuf,
  305. &pKeyValueFull,
  306. MAX_KEY_VALUE_FULLINFO,
  307. NULL ) )
  308. {
  309. // Didn't work. (Don't bother closing key though, its used globally)
  310. return (FALSE);
  311. }
  312. //
  313. // Make sure there is data with this value.
  314. //
  315. if (GET_VALUE_DATA_PTR(pKeyValueFull)[0] == 0)
  316. {
  317. // Nope, no file name for this code page. (Not installed).
  318. return (FALSE);
  319. }
  320. // It worked, see if that's all they wanted.
  321. if (!pResultBuf || Size == 0)
  322. {
  323. // Caller didn't want the name, just to know if it was there
  324. return (TRUE);
  325. }
  326. // Now we have to copy the name to their buffer for them.
  327. NlsStrCpyW(pResultBuf, GET_VALUE_DATA_PTR(pKeyValueFull));
  328. // Yea, it worked
  329. return (TRUE);
  330. }
  331. ////////////////////////////////////////////////////////////////////////////
  332. //
  333. // GetUserInfoFromRegistry
  334. //
  335. // Gets the information from the registry for the given value entry.
  336. //
  337. // 06-11-98 JulieB Created.
  338. ////////////////////////////////////////////////////////////////////////////
  339. BOOL GetUserInfoFromRegistry(
  340. LPWSTR pValue,
  341. LPWSTR pOutput,
  342. LCID Locale)
  343. {
  344. PKEY_VALUE_FULL_INFORMATION pKeyValueFull; // ptr to query info
  345. BYTE pStatic[MAX_KEY_VALUE_FULLINFO]; // ptr to static buffer
  346. HANDLE hKey = NULL; // handle to intl key
  347. ULONG rc = 0L; // return code
  348. //
  349. // Open the Control Panel International registry key.
  350. //
  351. OPEN_CPANEL_INTL_KEY(hKey, FALSE, KEY_READ);
  352. //
  353. // Initialize the output string.
  354. //
  355. *pOutput = 0;
  356. pKeyValueFull = (PKEY_VALUE_FULL_INFORMATION)pStatic;
  357. //
  358. // Check to be sure the current user is running in the given locale.
  359. //
  360. if (Locale)
  361. {
  362. if (NO_ERROR == QueryRegValue( hKey,
  363. L"Locale",
  364. &pKeyValueFull,
  365. MAX_KEY_VALUE_FULLINFO,
  366. NULL ))
  367. {
  368. UINT uiLocale;
  369. if (NlsConvertStringToIntegerW(GET_VALUE_DATA_PTR(pKeyValueFull), 16, -1, &uiLocale) &&
  370. uiLocale != Locale)
  371. {
  372. CLOSE_REG_KEY(hKey);
  373. return FALSE;
  374. }
  375. }
  376. }
  377. //
  378. // Query the registry value.
  379. //
  380. rc = QueryRegValue( hKey,
  381. pValue,
  382. &pKeyValueFull,
  383. MAX_KEY_VALUE_FULLINFO,
  384. NULL );
  385. //
  386. // Close the registry key.
  387. //
  388. CLOSE_REG_KEY(hKey);
  389. //
  390. // If the query failed or if the output buffer is not large enough,
  391. // then return failure.
  392. //
  393. if ((rc != NO_ERROR) ||
  394. (pKeyValueFull->DataLength > (MAX_REG_VAL_SIZE * sizeof(WCHAR))))
  395. {
  396. return (FALSE);
  397. }
  398. //
  399. // Save the string in pOutput.
  400. //
  401. NlsStrCpyW(pOutput, GET_VALUE_DATA_PTR(pKeyValueFull));
  402. //
  403. // Return success.
  404. //
  405. return (TRUE);
  406. }
  407. ////////////////////////////////////////////////////////////////////////////
  408. //
  409. // GetUserInfo
  410. //
  411. // Gets the information from the registry for the given locale and user
  412. // value entry.
  413. //
  414. // 05-31-91 JulieB Created.
  415. ////////////////////////////////////////////////////////////////////////////
  416. BOOL GetUserInfo(
  417. LCID Locale,
  418. LCTYPE LCType,
  419. SIZE_T CacheOffset,
  420. LPWSTR pValue,
  421. LPWSTR pOutput,
  422. size_t cchOutput,
  423. BOOL fCheckNull)
  424. {
  425. LCID UserLocale;
  426. HRESULT hr; // return val for string copy
  427. //
  428. // Check if the current thread/process is impersonating
  429. // or running in the context of a user other than the
  430. // interactive one.
  431. //
  432. if (NT_SUCCESS( NlsGetCurrentUserNlsInfo( Locale,
  433. LCType,
  434. pValue,
  435. pOutput,
  436. FALSE )))
  437. {
  438. //
  439. // See if we need to check for a null string.
  440. //
  441. if ((fCheckNull) && (*pOutput == 0))
  442. {
  443. return (FALSE);
  444. }
  445. return (TRUE);
  446. }
  447. //
  448. // Running in the same security context as the logged-on user.
  449. //
  450. // Go to server side (csrss.exe) by calling CsrBasepNlsGetUserInfo(). The server side will enter a critical section to
  451. // protect the cache reading, and Copy the data to the output buffer.
  452. // NOTENOTE: CsrBasepNlsGetUserInfo takes the buffer size in BYTE, so
  453. // we have to multiply cchOutput by sizeof(WCHAR)
  454. if (!NT_SUCCESS(CsrBasepNlsGetUserInfo(Locale, CacheOffset, pOutput, cchOutput * sizeof(WCHAR))))
  455. {
  456. //
  457. // Make sure the cache is valid.
  458. //
  459. // Also, check for an invalid entry. An invalid entry is marked
  460. // with NLS_INVALID_INFO_CHAR in the first position of the string
  461. // array.
  462. //
  463. //
  464. // The cache is invalid, so try getting the information directly
  465. // from the registry.
  466. //
  467. if (GetUserInfoFromRegistry(pValue, pOutput, Locale) == FALSE)
  468. {
  469. return (FALSE);
  470. }
  471. }
  472. //
  473. // See if we need to check for a null string.
  474. //
  475. if ((fCheckNull) && (*pOutput == 0))
  476. {
  477. return (FALSE);
  478. }
  479. //
  480. // Return success.
  481. //
  482. return (TRUE);
  483. }
  484. ////////////////////////////////////////////////////////////////////////////
  485. //
  486. // GetPreComposedChar
  487. //
  488. // Gets the precomposed character form of a given base character and
  489. // nonspacing character. If there is no precomposed form for the given
  490. // character, it returns 0.
  491. //
  492. // 05-31-91 JulieB Created.
  493. ////////////////////////////////////////////////////////////////////////////
  494. WCHAR FASTCALL GetPreComposedChar(
  495. WCHAR wcNonSp,
  496. WCHAR wcBase)
  497. {
  498. PCOMP_INFO pComp; // ptr to composite information
  499. WORD BSOff = 0; // offset of base char in grid
  500. WORD NSOff = 0; // offset of nonspace char in grid
  501. int Index; // index into grid
  502. //
  503. // Store the ptr to the composite information. No need to check if
  504. // it's a NULL pointer since all tables in the Unicode file are
  505. // constructed during initialization.
  506. //
  507. pComp = pTblPtrs->pComposite;
  508. //
  509. // Traverse 8:4:4 table for Base character offset.
  510. //
  511. BSOff = TRAVERSE_844_W(pComp->pBase, wcBase);
  512. if (!BSOff)
  513. {
  514. return (0);
  515. }
  516. //
  517. // Traverse 8:4:4 table for NonSpace character offset.
  518. //
  519. NSOff = TRAVERSE_844_W(pComp->pNonSp, wcNonSp);
  520. if (!NSOff)
  521. {
  522. return (0);
  523. }
  524. //
  525. // Get wide character value out of 2D grid.
  526. // If there is no precomposed character at the location in the
  527. // grid, it will return 0.
  528. //
  529. Index = (BSOff - 1) * pComp->NumNonSp + (NSOff - 1);
  530. return ((pComp->pGrid)[Index]);
  531. }
  532. ////////////////////////////////////////////////////////////////////////////
  533. //
  534. // GetCompositeChars
  535. //
  536. // Gets the composite characters of a given wide character. If the
  537. // composite form is found, it returns TRUE. Otherwise, it returns
  538. // FALSE.
  539. //
  540. // 05-31-91 JulieB Created.
  541. ////////////////////////////////////////////////////////////////////////////
  542. BOOL FASTCALL GetCompositeChars(
  543. WCHAR wch,
  544. WCHAR *pNonSp,
  545. WCHAR *pBase)
  546. {
  547. PPRECOMP pPreComp; // ptr to precomposed information
  548. //
  549. // Store the ptr to the precomposed information. No need to check if
  550. // it's a NULL pointer since all tables in the Unicode file are
  551. // constructed during initialization.
  552. //
  553. pPreComp = pTblPtrs->pPreComposed;
  554. //
  555. // Traverse 8:4:4 table for base and nonspace character translation.
  556. //
  557. TRAVERSE_844_D(pPreComp, wch, *pNonSp, *pBase);
  558. //
  559. // Return success if found. Otherwise, error.
  560. //
  561. return ((*pNonSp) && (*pBase));
  562. }
  563. ////////////////////////////////////////////////////////////////////////////
  564. //
  565. // InsertPreComposedForm
  566. //
  567. // Gets the precomposed form of a given wide character string, places it in
  568. // the given wide character, and returns the number of composite characters
  569. // used to form the precomposed form. If there is no precomposed form for
  570. // the given character, nothing is written into pPreComp and it returns 1
  571. // for the number of characters used.
  572. //
  573. // 05-31-91 JulieB Created.
  574. ////////////////////////////////////////////////////////////////////////////
  575. int FASTCALL InsertPreComposedForm(
  576. LPCWSTR pWCStr,
  577. LPWSTR pEndWCStr,
  578. LPWSTR pPreComp)
  579. {
  580. WCHAR wch; // precomposed character
  581. LPWSTR pPos; // ptr to position in string
  582. //
  583. // If no precomposed form can be found, return 1 character used
  584. // (base character).
  585. //
  586. if (((pWCStr + 1) >= pEndWCStr) ||
  587. (!(wch = GetPreComposedChar(*(pWCStr + 1), *pWCStr))))
  588. {
  589. return (1);
  590. }
  591. //
  592. // Get the precomposed character from the given wide character string.
  593. // Must check for multiple nonspacing characters for the same
  594. // precomposed character.
  595. //
  596. *pPreComp = wch;
  597. pPos = (LPWSTR)pWCStr + 2;
  598. while ((pPos < pEndWCStr) &&
  599. (wch = GetPreComposedChar(*pPos, *pPreComp)))
  600. {
  601. *pPreComp = wch;
  602. pPos++;
  603. }
  604. //
  605. // Return the number of characters used to form the precomposed
  606. // character.
  607. //
  608. return ((int)(pPos - (LPWSTR)pWCStr));
  609. }
  610. ////////////////////////////////////////////////////////////////////////////
  611. //
  612. // InsertFullWidthPreComposedForm
  613. //
  614. // Gets the full width precomposed form of a given wide character string,
  615. // places it in the given wide character, and returns the number of
  616. // composite characters used to form the precomposed form. If there is
  617. // no precomposed form for the given character, only the full width conversion
  618. // of the first code point is written into pPreComp and it returns 1 for
  619. // the number of characters used.
  620. //
  621. // 11-04-93 JulieB Created.
  622. ////////////////////////////////////////////////////////////////////////////
  623. int FASTCALL InsertFullWidthPreComposedForm(
  624. LPCWSTR pWCStr,
  625. LPWSTR pEndWCStr,
  626. LPWSTR pPreComp,
  627. PCASE pCase)
  628. {
  629. WCHAR wch; // nonspace character
  630. LPWSTR pPos; // ptr to position in string
  631. //
  632. // Get the case (if necessary).
  633. //
  634. *pPreComp = (pCase) ? GET_LOWER_UPPER_CASE(pCase, *pWCStr) : *pWCStr;
  635. //
  636. // Get the full width.
  637. //
  638. *pPreComp = GET_FULL_WIDTH(pTblPtrs->pFullWidth, *pPreComp);
  639. if ((pPos = ((LPWSTR)pWCStr + 1)) >= pEndWCStr)
  640. {
  641. return (1);
  642. }
  643. while (pPos < pEndWCStr)
  644. {
  645. wch = (pCase) ? GET_LOWER_UPPER_CASE(pCase, *pPos) : *pPos;
  646. wch = GET_FULL_WIDTH(pTblPtrs->pFullWidth, wch);
  647. if (wch = GetPreComposedChar(wch, *pPreComp))
  648. {
  649. *pPreComp = wch;
  650. pPos++;
  651. }
  652. else
  653. {
  654. break;
  655. }
  656. }
  657. //
  658. // Return the number of characters used to form the precomposed
  659. // character.
  660. //
  661. return ((int)(pPos - (LPWSTR)pWCStr));
  662. }
  663. ////////////////////////////////////////////////////////////////////////////
  664. //
  665. // InsertCompositeForm
  666. //
  667. // Gets the composite form of a given wide character, places it in the
  668. // wide character string, and returns the number of characters written.
  669. // If there is no composite form for the given character, the wide character
  670. // string is not touched. It will return 1 for the number of characters
  671. // written, since the base character was already written.
  672. //
  673. // 05-31-91 JulieB Created.
  674. ////////////////////////////////////////////////////////////////////////////
  675. int FASTCALL InsertCompositeForm(
  676. LPWSTR pWCStr,
  677. LPWSTR pEndWCStr)
  678. {
  679. WCHAR Base; // base character
  680. WCHAR NonSp; // non space character
  681. int wcCount = 0; // number of wide characters written
  682. LPWSTR pEndComp; // ptr to end of composite form
  683. int ctr; // loop counter
  684. //
  685. // If no composite form can be found, return 1 for the base
  686. // character that was already written.
  687. //
  688. if (!GetCompositeChars(*pWCStr, &NonSp, &Base))
  689. {
  690. return (1);
  691. }
  692. //
  693. // Get the composite characters and write them to the pWCStr
  694. // buffer. Must check for multiple breakdowns of the precomposed
  695. // character into more than 2 characters (multiple nonspacing
  696. // characters).
  697. //
  698. pEndComp = pWCStr;
  699. do
  700. {
  701. //
  702. // Make sure pWCStr is big enough to hold the nonspacing
  703. // character.
  704. //
  705. if (pEndComp < (pEndWCStr - 1))
  706. {
  707. //
  708. // Addition of next breakdown of nonspacing characters
  709. // are to be added right after the base character. So,
  710. // move all nonspacing characters ahead one position
  711. // to make room for the next nonspacing character.
  712. //
  713. pEndComp++;
  714. for (ctr = 0; ctr < wcCount; ctr++)
  715. {
  716. *(pEndComp - ctr) = *(pEndComp - (ctr + 1));
  717. }
  718. //
  719. // Fill in the new base form and the new nonspacing character.
  720. //
  721. *pWCStr = Base;
  722. *(pWCStr + 1) = NonSp;
  723. wcCount++;
  724. }
  725. else
  726. {
  727. //
  728. // Make sure we don't get into an infinite loop if the
  729. // destination buffer isn't large enough.
  730. //
  731. break;
  732. }
  733. } while (GetCompositeChars(*pWCStr, &NonSp, &Base));
  734. //
  735. // Return number of wide characters written. Add 1 to include the
  736. // base character.
  737. //
  738. return (wcCount + 1);
  739. }
  740. ////////////////////////////////////////////////////////////////////////////
  741. //
  742. // NlsConvertIntegerToString
  743. //
  744. // This routine converts an integer to a Unicode string.
  745. //
  746. // 11-15-96 JulieB Created.
  747. ////////////////////////////////////////////////////////////////////////////
  748. ULONG NlsConvertIntegerToString(
  749. UINT Value,
  750. UINT Base,
  751. UINT Padding,
  752. LPWSTR pResultBuf,
  753. UINT Size)
  754. {
  755. UNICODE_STRING ObString; // value string
  756. UINT ctr; // loop counter
  757. LPWSTR pBufPtr; // ptr to result buffer
  758. WCHAR pTmpBuf[MAX_PATH_LEN]; // ptr to temp buffer
  759. ULONG rc = 0L; // return code
  760. //
  761. // Set up the Unicode string structure.
  762. //
  763. ObString.Length = (USHORT)(Size * sizeof(WCHAR));
  764. ObString.MaximumLength = (USHORT)(Size * sizeof(WCHAR));
  765. ObString.Buffer = pTmpBuf;
  766. //
  767. // Get the value as a string.
  768. //
  769. if (rc = RtlIntegerToUnicodeString(Value, Base, &ObString))
  770. {
  771. return (rc);
  772. }
  773. //
  774. // Pad the string with the appropriate number of zeros.
  775. //
  776. pBufPtr = pResultBuf;
  777. for (ctr = GET_WC_COUNT(ObString.Length);
  778. ctr < Padding;
  779. ctr++, pBufPtr++)
  780. {
  781. *pBufPtr = NLS_CHAR_ZERO;
  782. }
  783. NlsStrCpyW(pBufPtr, ObString.Buffer);
  784. //
  785. // Return success.
  786. //
  787. return (NO_ERROR);
  788. }
  789. ////////////////////////////////////////////////////////////////////////////
  790. //
  791. // NlsConvertIntegerToHexStringW
  792. // Convert an integer value to an Unicode null-terminated string WITH
  793. // leading zeros. E.g. 0x409 with Width 5 will be converted to L"0409".
  794. // This function is faster than NlsConvertIntegerToString(), but it
  795. // only supports hex numbers.
  796. //
  797. // Parameters:
  798. // Value The number to be converted.
  799. // UpperCase If TRUE, the hex digit will be uppercase.
  800. // Str The buffer for the converted Unicode string.
  801. // Width The character count of the buffer. The value should be the total
  802. // heximal digit number plus one for null-terminiated.
  803. // E.g. if the value is from 0x0000 - 0xffff, the Width should be 5.
  804. //
  805. // Return:
  806. // TRUE if successful. FALSE if the width is not big enough to hold the converted string.
  807. //
  808. ////////////////////////////////////////////////////////////////////////////
  809. BOOL FASTCALL NlsConvertIntegerToHexStringW(UINT Value, BOOL UpperCase, PWSTR Str, UINT CharCount)
  810. {
  811. int Digit;
  812. PWSTR p;
  813. if(Str == NULL)
  814. {
  815. return (FALSE);
  816. }
  817. p = Str + CharCount - 1;
  818. *p-- = L'\0';
  819. while (p >= Str)
  820. {
  821. Digit = Value & 0xf;
  822. if (Digit < 10)
  823. {
  824. Digit = Digit + L'0';
  825. }
  826. else
  827. {
  828. Digit = Digit - 10 + (UpperCase ? L'A' : L'a');
  829. }
  830. *p-- = (WCHAR)Digit;
  831. Value >>= 4;
  832. }
  833. if (Value > 0)
  834. {
  835. //
  836. // There are still digit remaining.
  837. //
  838. return (FALSE);
  839. }
  840. return (TRUE);
  841. }
  842. ////////////////////////////////////////////////////////////////////////////
  843. //
  844. // NlsConvertStringToIntegerW
  845. //
  846. // Parameters:
  847. // Str the hex string to be converted.
  848. // Base base
  849. // CharCount
  850. // the character count of the string (excluding the terminiated-null, if any).
  851. // If the value is -1, this function assumes that
  852. // Str is a null-terminated string.
  853. // Result the pointer to the result.
  854. //
  855. // Result:
  856. // TRUE if the operation is successful. FALSE if there is non-hex
  857. // character in the string.
  858. //
  859. ////////////////////////////////////////////////////////////////////////////
  860. BOOL FASTCALL NlsConvertStringToIntegerW(PWSTR Str, UINT Base, int CharCount, UINT* Result)
  861. {
  862. int i;
  863. WCHAR Digit;
  864. WCHAR c;
  865. if (Str == NULL || Result == NULL)
  866. {
  867. return (FALSE);
  868. }
  869. *Result = 0;
  870. if (CharCount == -1)
  871. {
  872. while (c = *Str)
  873. {
  874. c = *Str;
  875. if (c >= L'0' && c <= L'9')
  876. {
  877. Digit = c - L'0';
  878. }
  879. else if(Base == 16)
  880. {
  881. if (c >= L'A' && c <= L'F')
  882. {
  883. Digit = c - L'A' + 10;
  884. }
  885. else if (c >= L'a' && c <= L'f')
  886. {
  887. Digit = c - L'a' + 10;
  888. }
  889. else
  890. {
  891. return (FALSE);
  892. }
  893. }
  894. else
  895. {
  896. return (FALSE);
  897. }
  898. if (Base == 16)
  899. {
  900. *Result = (*Result << 4) | Digit;
  901. }
  902. else
  903. {
  904. *Result = *Result*10 + Digit;
  905. }
  906. Str++;
  907. }
  908. } else
  909. {
  910. for (i=0; i< CharCount; i++) {
  911. c = *Str++;
  912. if (c >= L'0' && c <= L'9')
  913. {
  914. Digit = c - L'0';
  915. }
  916. else if(Base == 16)
  917. {
  918. if (c >= L'A' && c <= L'F')
  919. {
  920. Digit = c - L'A' + 10;
  921. }
  922. else if (c >= L'a' && c <= L'f')
  923. {
  924. Digit = c - L'a' + 10;
  925. }
  926. else
  927. {
  928. return (FALSE);
  929. }
  930. }
  931. else
  932. {
  933. return (FALSE);
  934. }
  935. if (Base == 16)
  936. {
  937. *Result = (*Result << 4) | Digit;
  938. }
  939. else
  940. {
  941. *Result = *Result*10 + Digit;
  942. }
  943. }
  944. }
  945. return (TRUE);
  946. }
  947. ////////////////////////////////////////////////////////////////////////////
  948. //
  949. // NlsStrCpyW
  950. //
  951. // This routine copies the source wide character string to the destination
  952. // wide character string buffer.
  953. //
  954. // NOTE: This routine is here to avoid any dependencies on other DLLs
  955. // during initialization.
  956. //
  957. // 05-31-91 JulieB Created.
  958. ////////////////////////////////////////////////////////////////////////////
  959. LPWSTR FASTCALL NlsStrCpyW(
  960. LPWSTR pwszDest,
  961. LPCWSTR pwszSrc)
  962. {
  963. LPWSTR pwszRet = pwszDest; // ptr to beginning of string
  964. loop:
  965. if (!(pwszDest[0x0] = pwszSrc[0x0])) goto done;
  966. if (!(pwszDest[0x1] = pwszSrc[0x1])) goto done;
  967. if (!(pwszDest[0x2] = pwszSrc[0x2])) goto done;
  968. if (!(pwszDest[0x3] = pwszSrc[0x3])) goto done;
  969. if (!(pwszDest[0x4] = pwszSrc[0x4])) goto done;
  970. if (!(pwszDest[0x5] = pwszSrc[0x5])) goto done;
  971. if (!(pwszDest[0x6] = pwszSrc[0x6])) goto done;
  972. if (!(pwszDest[0x7] = pwszSrc[0x7])) goto done;
  973. if (!(pwszDest[0x8] = pwszSrc[0x8])) goto done;
  974. if (!(pwszDest[0x9] = pwszSrc[0x9])) goto done;
  975. if (!(pwszDest[0xA] = pwszSrc[0xA])) goto done;
  976. if (!(pwszDest[0xB] = pwszSrc[0xB])) goto done;
  977. if (!(pwszDest[0xC] = pwszSrc[0xC])) goto done;
  978. if (!(pwszDest[0xD] = pwszSrc[0xD])) goto done;
  979. if (!(pwszDest[0xE] = pwszSrc[0xE])) goto done;
  980. if (!(pwszDest[0xF] = pwszSrc[0xF])) goto done;
  981. pwszDest+= 0x10;
  982. pwszSrc+= 0x10;
  983. goto loop;
  984. done:
  985. return (pwszRet);
  986. }
  987. ////////////////////////////////////////////////////////////////////////////
  988. //
  989. // NlsStrCatW
  990. //
  991. // This routine attaches the second string to the first string.
  992. //
  993. // NOTE: This routine is here to avoid any dependencies on other DLLs
  994. // during initialization.
  995. //
  996. // 05-31-91 JulieB Created.
  997. ////////////////////////////////////////////////////////////////////////////
  998. LPWSTR FASTCALL NlsStrCatW(
  999. LPWSTR pwsz1,
  1000. LPCWSTR pwsz2)
  1001. {
  1002. LPWSTR pwszRet = pwsz1; // ptr to beginning of string
  1003. strlen_loop:
  1004. if (*pwsz1) pwsz1++; else goto cat_loop;
  1005. if (*pwsz1) pwsz1++; else goto cat_loop;
  1006. if (*pwsz1) pwsz1++; else goto cat_loop;
  1007. if (*pwsz1) pwsz1++; else goto cat_loop;
  1008. if (*pwsz1) pwsz1++; else goto cat_loop;
  1009. if (*pwsz1) pwsz1++; else goto cat_loop;
  1010. if (*pwsz1) pwsz1++; else goto cat_loop;
  1011. if (*pwsz1) pwsz1++; else goto cat_loop;
  1012. if (*pwsz1) pwsz1++; else goto cat_loop;
  1013. if (*pwsz1) pwsz1++; else goto cat_loop;
  1014. if (*pwsz1) pwsz1++; else goto cat_loop;
  1015. if (*pwsz1) pwsz1++; else goto cat_loop;
  1016. if (*pwsz1) pwsz1++; else goto cat_loop;
  1017. if (*pwsz1) pwsz1++; else goto cat_loop;
  1018. if (*pwsz1) pwsz1++; else goto cat_loop;
  1019. if (*pwsz1) pwsz1++; else goto cat_loop;
  1020. goto strlen_loop;
  1021. cat_loop:
  1022. if (!(pwsz1[0x00] = pwsz2[0x00])) goto done;
  1023. if (!(pwsz1[0x01] = pwsz2[0x01])) goto done;
  1024. if (!(pwsz1[0x02] = pwsz2[0x02])) goto done;
  1025. if (!(pwsz1[0x03] = pwsz2[0x03])) goto done;
  1026. if (!(pwsz1[0x04] = pwsz2[0x04])) goto done;
  1027. if (!(pwsz1[0x05] = pwsz2[0x05])) goto done;
  1028. if (!(pwsz1[0x06] = pwsz2[0x06])) goto done;
  1029. if (!(pwsz1[0x07] = pwsz2[0x07])) goto done;
  1030. if (!(pwsz1[0x08] = pwsz2[0x08])) goto done;
  1031. if (!(pwsz1[0x09] = pwsz2[0x09])) goto done;
  1032. if (!(pwsz1[0x0A] = pwsz2[0x0A])) goto done;
  1033. if (!(pwsz1[0x0B] = pwsz2[0x0B])) goto done;
  1034. if (!(pwsz1[0x0C] = pwsz2[0x0C])) goto done;
  1035. if (!(pwsz1[0x0D] = pwsz2[0x0D])) goto done;
  1036. if (!(pwsz1[0x0E] = pwsz2[0x0E])) goto done;
  1037. if (!(pwsz1[0x0F] = pwsz2[0x0F])) goto done;
  1038. pwsz1 += 0x10;
  1039. pwsz2 += 0x10;
  1040. goto cat_loop;
  1041. done:
  1042. return (pwszRet);
  1043. }
  1044. ////////////////////////////////////////////////////////////////////////////
  1045. //
  1046. // NlsStrLenW
  1047. //
  1048. // This routine returns the length of the given wide character string.
  1049. // The length does NOT include the null terminator.
  1050. //
  1051. // NOTE: This routine is here to avoid any dependencies on other DLLs
  1052. // during initialization.
  1053. //
  1054. // 05-31-91 JulieB Created.
  1055. ////////////////////////////////////////////////////////////////////////////
  1056. int FASTCALL NlsStrLenW(
  1057. LPCWSTR pwsz)
  1058. {
  1059. LPCWSTR pwszStart = pwsz; // ptr to beginning of string
  1060. loop:
  1061. if (*pwsz) pwsz++; else goto done;
  1062. if (*pwsz) pwsz++; else goto done;
  1063. if (*pwsz) pwsz++; else goto done;
  1064. if (*pwsz) pwsz++; else goto done;
  1065. if (*pwsz) pwsz++; else goto done;
  1066. if (*pwsz) pwsz++; else goto done;
  1067. if (*pwsz) pwsz++; else goto done;
  1068. if (*pwsz) pwsz++; else goto done;
  1069. if (*pwsz) pwsz++; else goto done;
  1070. if (*pwsz) pwsz++; else goto done;
  1071. if (*pwsz) pwsz++; else goto done;
  1072. if (*pwsz) pwsz++; else goto done;
  1073. if (*pwsz) pwsz++; else goto done;
  1074. if (*pwsz) pwsz++; else goto done;
  1075. if (*pwsz) pwsz++; else goto done;
  1076. if (*pwsz) pwsz++; else goto done;
  1077. goto loop;
  1078. done:
  1079. return ((int)(pwsz - pwszStart));
  1080. }
  1081. ////////////////////////////////////////////////////////////////////////////
  1082. //
  1083. // NlsStrNCatW
  1084. //
  1085. // This routine concatenates two wide character strings for the count of
  1086. // characters given. It copies "Count" characters from the back string to
  1087. // the end of the "front" string.
  1088. //
  1089. // NOTE: This routine is here to avoid any dependencies on other DLLs
  1090. // during initialization.
  1091. //
  1092. // 05-31-91 JulieB Created.
  1093. ////////////////////////////////////////////////////////////////////////////
  1094. LPWSTR FASTCALL NlsStrNCatW(
  1095. LPWSTR pwszFront,
  1096. LPCWSTR pwszBack,
  1097. int Count)
  1098. {
  1099. LPWSTR pwszStart = pwszFront; // ptr to beginning of string
  1100. strlen_loop:
  1101. if (*pwszFront) pwszFront++; goto cat_loop;
  1102. if (*pwszFront) pwszFront++; goto cat_loop;
  1103. if (*pwszFront) pwszFront++; goto cat_loop;
  1104. if (*pwszFront) pwszFront++; goto cat_loop;
  1105. if (*pwszFront) pwszFront++; goto cat_loop;
  1106. if (*pwszFront) pwszFront++; goto cat_loop;
  1107. if (*pwszFront) pwszFront++; goto cat_loop;
  1108. if (*pwszFront) pwszFront++; goto cat_loop;
  1109. goto strlen_loop;
  1110. cat_loop:
  1111. if (Count == 0 || !(*pwszFront = *pwszBack)) goto done;
  1112. pwszFront++; pwszBack++; Count--;
  1113. if (Count == 0 || !(*pwszFront = *pwszBack)) goto done;
  1114. pwszFront++; pwszBack++; Count--;
  1115. if (Count == 0 || !(*pwszFront = *pwszBack)) goto done;
  1116. pwszFront++; pwszBack++; Count--;
  1117. if (Count == 0 || !(*pwszFront = *pwszBack)) goto done;
  1118. pwszFront++; pwszBack++; Count--;
  1119. if (Count == 0 || !(*pwszFront = *pwszBack)) goto done;
  1120. pwszFront++; pwszBack++; Count--;
  1121. if (Count == 0 || !(*pwszFront = *pwszBack)) goto done;
  1122. pwszFront++; pwszBack++; Count--;
  1123. if (Count == 0 || !(*pwszFront = *pwszBack)) goto done;
  1124. pwszFront++; pwszBack++; Count--;
  1125. if (Count == 0 || !(*pwszFront = *pwszBack)) goto done;
  1126. pwszFront++; pwszBack++; Count--;
  1127. goto cat_loop;
  1128. done:
  1129. *pwszFront = (WCHAR)0;
  1130. return (pwszStart);
  1131. }
  1132. ////////////////////////////////////////////////////////////////////////////
  1133. //
  1134. // NlsStrEqualW
  1135. //
  1136. // This routine compares two strings to see if they are exactly identical.
  1137. // It returns 1 if they are identical, 0 if they are different.
  1138. //
  1139. // NOTE: This routine is here to avoid any dependencies on other DLLs
  1140. // during initialization.
  1141. //
  1142. // 05-31-91 JulieB Created.
  1143. ////////////////////////////////////////////////////////////////////////////
  1144. int FASTCALL NlsStrEqualW(
  1145. LPCWSTR pwszFirst,
  1146. LPCWSTR pwszSecond)
  1147. {
  1148. loop:
  1149. if (*pwszFirst != *pwszSecond) goto error;
  1150. if (!*pwszFirst) return (1);
  1151. pwszFirst++;
  1152. pwszSecond++;
  1153. if (*pwszFirst != *pwszSecond) goto error;
  1154. if (!*pwszFirst) return (1);
  1155. pwszFirst++;
  1156. pwszSecond++;
  1157. if (*pwszFirst != *pwszSecond) goto error;
  1158. if (!*pwszFirst) return (1);
  1159. pwszFirst++;
  1160. pwszSecond++;
  1161. if (*pwszFirst != *pwszSecond) goto error;
  1162. if (!*pwszFirst) return (1);
  1163. pwszFirst++;
  1164. pwszSecond++;
  1165. if (*pwszFirst != *pwszSecond) goto error;
  1166. if (!*pwszFirst) return (1);
  1167. pwszFirst++;
  1168. pwszSecond++;
  1169. if (*pwszFirst != *pwszSecond) goto error;
  1170. if (!*pwszFirst) return (1);
  1171. pwszFirst++;
  1172. pwszSecond++;
  1173. if (*pwszFirst != *pwszSecond) goto error;
  1174. if (!*pwszFirst) return (1);
  1175. pwszFirst++;
  1176. pwszSecond++;
  1177. if (*pwszFirst != *pwszSecond) goto error;
  1178. if (!*pwszFirst) return (1);
  1179. pwszFirst++;
  1180. pwszSecond++;
  1181. goto loop;
  1182. error:
  1183. //
  1184. // Return error.
  1185. //
  1186. return (0);
  1187. }
  1188. ////////////////////////////////////////////////////////////////////////////
  1189. //
  1190. // NlsStrNEqualW
  1191. //
  1192. // This routine compares two strings to see if they are exactly identical
  1193. // for the count of characters given.
  1194. // It returns 1 if they are identical, 0 if they are different.
  1195. //
  1196. // NOTE: This routine is here to avoid any dependencies on other DLLs
  1197. // during initialization.
  1198. //
  1199. // 05-31-91 JulieB Created.
  1200. ////////////////////////////////////////////////////////////////////////////
  1201. int FASTCALL NlsStrNEqualW(
  1202. LPCWSTR pwszFirst,
  1203. LPCWSTR pwszSecond,
  1204. int Count)
  1205. {
  1206. loop:
  1207. if (Count == 0) return (1);
  1208. if (*pwszFirst != *pwszSecond) goto error;
  1209. if (!*pwszFirst) return (1);
  1210. pwszFirst++;
  1211. pwszSecond++;
  1212. Count--;
  1213. if (Count == 0) return (1);
  1214. if (*pwszFirst != *pwszSecond) goto error;
  1215. if (!*pwszFirst) return (1);
  1216. pwszFirst++;
  1217. pwszSecond++;
  1218. Count--;
  1219. if (Count == 0) return (1);
  1220. if (*pwszFirst != *pwszSecond) goto error;
  1221. if (!*pwszFirst) return (1);
  1222. pwszFirst++;
  1223. pwszSecond++;
  1224. Count--;
  1225. if (Count == 0) return (1);
  1226. if (*pwszFirst != *pwszSecond) goto error;
  1227. if (!*pwszFirst) return (1);
  1228. pwszFirst++;
  1229. pwszSecond++;
  1230. Count--;
  1231. if (Count == 0) return (1);
  1232. if (*pwszFirst != *pwszSecond) goto error;
  1233. if (!*pwszFirst) return (1);
  1234. pwszFirst++;
  1235. pwszSecond++;
  1236. Count--;
  1237. if (Count == 0) return (1);
  1238. if (*pwszFirst != *pwszSecond) goto error;
  1239. if (!*pwszFirst) return (1);
  1240. pwszFirst++;
  1241. pwszSecond++;
  1242. Count--;
  1243. if (Count == 0) return (1);
  1244. if (*pwszFirst != *pwszSecond) goto error;
  1245. if (!*pwszFirst) return (1);
  1246. pwszFirst++;
  1247. pwszSecond++;
  1248. Count--;
  1249. if (Count == 0) return (1);
  1250. if (*pwszFirst != *pwszSecond) goto error;
  1251. if (!*pwszFirst) return (1);
  1252. pwszFirst++;
  1253. pwszSecond++;
  1254. Count--;
  1255. goto loop;
  1256. error:
  1257. //
  1258. // Return error.
  1259. //
  1260. return (0);
  1261. }
  1262. ////////////////////////////////////////////////////////////////////////////
  1263. //
  1264. // GetDefaultSortkeySize
  1265. //
  1266. ////////////////////////////////////////////////////////////////////////////
  1267. ULONG GetDefaultSortkeySize(
  1268. PLARGE_INTEGER pSize)
  1269. {
  1270. *pSize = pTblPtrs->DefaultSortkeySize;
  1271. return (STATUS_SUCCESS);
  1272. }
  1273. ////////////////////////////////////////////////////////////////////////////
  1274. //
  1275. // GetLinguistLangSize
  1276. //
  1277. ////////////////////////////////////////////////////////////////////////////
  1278. ULONG GetLinguistLangSize(
  1279. PLARGE_INTEGER pSize)
  1280. {
  1281. *pSize = pTblPtrs->LinguistLangSize;
  1282. return (STATUS_SUCCESS);
  1283. }
  1284. ////////////////////////////////////////////////////////////////////////////
  1285. //
  1286. // ValidateLocale
  1287. //
  1288. // Internal routine, called from server. Validates that a locale is
  1289. // present in the registry. This code comes from IsValidLocale, but
  1290. // does not check the internal data to prevent recursive calls to the
  1291. // server.
  1292. //
  1293. ////////////////////////////////////////////////////////////////////////////
  1294. BOOL ValidateLocale(
  1295. LCID Locale)
  1296. {
  1297. PKEY_VALUE_FULL_INFORMATION pKeyValueFull;
  1298. BYTE pStatic1[MAX_KEY_VALUE_FULLINFO];
  1299. BYTE pStatic2[MAX_KEY_VALUE_FULLINFO];
  1300. WCHAR pTmpBuf[MAX_PATH]; // temp buffer
  1301. UNICODE_STRING ObUnicodeStr; // registry data value string
  1302. DWORD Data; // registry data value
  1303. LPWSTR pData; // ptr to registry data
  1304. BOOL bResult = FALSE; // result value
  1305. //
  1306. // Invalid Locale Check.
  1307. //
  1308. if (IS_INVALID_LOCALE(Locale))
  1309. {
  1310. return (FALSE);
  1311. }
  1312. //
  1313. // Open the Locale, the Alternate Sorts, and the Language Groups
  1314. // registry keys.
  1315. //
  1316. OPEN_LOCALE_KEY(FALSE);
  1317. OPEN_ALT_SORTS_KEY(FALSE);
  1318. OPEN_LANG_GROUPS_KEY(FALSE);
  1319. //
  1320. // Convert locale value to Unicode string.
  1321. //
  1322. if (NlsConvertIntegerToString(Locale, 16, 8, pTmpBuf, MAX_PATH))
  1323. {
  1324. return (FALSE);
  1325. }
  1326. //
  1327. // Query the registry for the value.
  1328. //
  1329. pKeyValueFull = (PKEY_VALUE_FULL_INFORMATION)pStatic1;
  1330. if (((QueryRegValue( hLocaleKey,
  1331. pTmpBuf,
  1332. &pKeyValueFull,
  1333. MAX_KEY_VALUE_FULLINFO,
  1334. NULL ) == NO_ERROR) ||
  1335. (QueryRegValue( hAltSortsKey,
  1336. pTmpBuf,
  1337. &pKeyValueFull,
  1338. MAX_KEY_VALUE_FULLINFO,
  1339. NULL ) == NO_ERROR)) &&
  1340. (pKeyValueFull->DataLength > 2))
  1341. {
  1342. RtlInitUnicodeString(&ObUnicodeStr, GET_VALUE_DATA_PTR(pKeyValueFull));
  1343. if ((RtlUnicodeStringToInteger(&ObUnicodeStr, 16, &Data) == NO_ERROR) &&
  1344. (Data != 0))
  1345. {
  1346. pKeyValueFull = (PKEY_VALUE_FULL_INFORMATION)pStatic2;
  1347. if ((QueryRegValue( hLangGroupsKey,
  1348. ObUnicodeStr.Buffer,
  1349. &pKeyValueFull,
  1350. MAX_KEY_VALUE_FULLINFO,
  1351. NULL ) == NO_ERROR) &&
  1352. (pKeyValueFull->DataLength > 2))
  1353. {
  1354. pData = GET_VALUE_DATA_PTR(pKeyValueFull);
  1355. if ((pData[0] == L'1') && (pData[1] == 0))
  1356. {
  1357. bResult = TRUE;
  1358. }
  1359. }
  1360. }
  1361. }
  1362. //
  1363. // Return the result.
  1364. //
  1365. return (TRUE);
  1366. }
  1367. ////////////////////////////////////////////////////////////////////////////
  1368. //
  1369. // ValidateLCType
  1370. //
  1371. // This routine is called from the server (and also from locale.c) in
  1372. // order to get a Registry key name and a field pointer in the NlsInfo
  1373. // structure given an LCType.
  1374. //
  1375. ////////////////////////////////////////////////////////////////////////////
  1376. BOOL ValidateLCType(
  1377. PNLS_USER_INFO pInfo,
  1378. LCTYPE LCType,
  1379. LPWSTR *ppwReg,
  1380. LPWSTR *ppwCache)
  1381. {
  1382. switch (LCType)
  1383. {
  1384. case ( LOCALE_IFIRSTWEEKOFYEAR ) :
  1385. {
  1386. *ppwReg = NLS_VALUE_IFIRSTWEEKOFYEAR;
  1387. *ppwCache = pInfo->iFirstWeek;
  1388. break;
  1389. }
  1390. case ( LOCALE_IFIRSTDAYOFWEEK ) :
  1391. {
  1392. *ppwReg = NLS_VALUE_IFIRSTDAYOFWEEK;
  1393. *ppwCache = pInfo->iFirstDay;
  1394. break;
  1395. }
  1396. case ( LOCALE_ICALENDARTYPE ) :
  1397. {
  1398. *ppwReg = NLS_VALUE_ICALENDARTYPE;
  1399. *ppwCache = pInfo->iCalType;
  1400. break;
  1401. }
  1402. case ( LOCALE_SLONGDATE ) :
  1403. {
  1404. *ppwReg = NLS_VALUE_SLONGDATE;
  1405. *ppwCache = pInfo->sLongDate;
  1406. break;
  1407. }
  1408. case ( LOCALE_SYEARMONTH ) :
  1409. {
  1410. *ppwReg = NLS_VALUE_SYEARMONTH;
  1411. *ppwCache = pInfo->sYearMonth;
  1412. break;
  1413. }
  1414. case ( LOCALE_S1159 ) :
  1415. {
  1416. *ppwReg = NLS_VALUE_S1159;
  1417. *ppwCache = pInfo->s1159;
  1418. break;
  1419. }
  1420. case ( LOCALE_SNEGATIVESIGN ) :
  1421. {
  1422. *ppwReg = NLS_VALUE_SNEGATIVESIGN;
  1423. *ppwCache = pInfo->sNegSign;
  1424. break;
  1425. }
  1426. case ( LOCALE_SPOSITIVESIGN ) :
  1427. {
  1428. *ppwReg = NLS_VALUE_SPOSITIVESIGN;
  1429. *ppwCache = pInfo->sPosSign;
  1430. break;
  1431. }
  1432. case ( LOCALE_INEGCURR ) :
  1433. {
  1434. *ppwReg = NLS_VALUE_INEGCURR;
  1435. *ppwCache = pInfo->iNegCurr;
  1436. break;
  1437. }
  1438. case ( LOCALE_ICURRENCY ) :
  1439. {
  1440. *ppwReg = NLS_VALUE_ICURRENCY;
  1441. *ppwCache = pInfo->iCurrency;
  1442. break;
  1443. }
  1444. case ( LOCALE_ICURRDIGITS ) :
  1445. {
  1446. *ppwReg = NLS_VALUE_ICURRDIGITS;
  1447. *ppwCache = pInfo->iCurrDigits;
  1448. break;
  1449. }
  1450. case ( LOCALE_SMONGROUPING ) :
  1451. {
  1452. *ppwReg = NLS_VALUE_SMONGROUPING;
  1453. *ppwCache = pInfo->sMonGrouping;
  1454. break;
  1455. }
  1456. case ( LOCALE_SMONTHOUSANDSEP ) :
  1457. {
  1458. *ppwReg = NLS_VALUE_SMONTHOUSANDSEP;
  1459. *ppwCache = pInfo->sMonThouSep;
  1460. break;
  1461. }
  1462. case ( LOCALE_SMONDECIMALSEP ) :
  1463. {
  1464. *ppwReg = NLS_VALUE_SMONDECIMALSEP;
  1465. *ppwCache = pInfo->sMonDecSep;
  1466. break;
  1467. }
  1468. case ( LOCALE_SCURRENCY ) :
  1469. {
  1470. *ppwReg = NLS_VALUE_SCURRENCY;
  1471. *ppwCache = pInfo->sCurrency;
  1472. break;
  1473. }
  1474. case ( LOCALE_IDIGITSUBSTITUTION ) :
  1475. {
  1476. *ppwReg = NLS_VALUE_IDIGITSUBST;
  1477. *ppwCache = pInfo->iDigitSubstitution;
  1478. break;
  1479. }
  1480. case ( LOCALE_SNATIVEDIGITS ) :
  1481. {
  1482. *ppwReg = NLS_VALUE_SNATIVEDIGITS;
  1483. *ppwCache = pInfo->sNativeDigits;
  1484. break;
  1485. }
  1486. case ( LOCALE_INEGNUMBER ) :
  1487. {
  1488. *ppwReg = NLS_VALUE_INEGNUMBER;
  1489. *ppwCache = pInfo->iNegNumber;
  1490. break;
  1491. }
  1492. case ( LOCALE_ILZERO ) :
  1493. {
  1494. *ppwReg = NLS_VALUE_ILZERO;
  1495. *ppwCache = pInfo->iLZero;
  1496. break;
  1497. }
  1498. case ( LOCALE_IDIGITS ) :
  1499. {
  1500. *ppwReg = NLS_VALUE_IDIGITS;
  1501. *ppwCache = pInfo->iDigits;
  1502. break;
  1503. }
  1504. case ( LOCALE_SGROUPING ) :
  1505. {
  1506. *ppwReg = NLS_VALUE_SGROUPING;
  1507. *ppwCache = pInfo->sGrouping;
  1508. break;
  1509. }
  1510. case ( LOCALE_STHOUSAND ) :
  1511. {
  1512. *ppwReg = NLS_VALUE_STHOUSAND;
  1513. *ppwCache = pInfo->sThousand;
  1514. break;
  1515. }
  1516. case ( LOCALE_SDECIMAL ) :
  1517. {
  1518. *ppwReg = NLS_VALUE_SDECIMAL;
  1519. *ppwCache = pInfo->sDecimal;
  1520. break;
  1521. }
  1522. case ( LOCALE_IPAPERSIZE ) :
  1523. {
  1524. *ppwReg = NLS_VALUE_IPAPERSIZE;
  1525. *ppwCache = pInfo->iPaperSize;
  1526. break;
  1527. }
  1528. case ( LOCALE_IMEASURE ) :
  1529. {
  1530. *ppwReg = NLS_VALUE_IMEASURE;
  1531. *ppwCache = pInfo->iMeasure;
  1532. break;
  1533. }
  1534. case ( LOCALE_SLIST ) :
  1535. {
  1536. *ppwReg = NLS_VALUE_SLIST;
  1537. *ppwCache = pInfo->sList;
  1538. break;
  1539. }
  1540. case ( LOCALE_S2359 ) :
  1541. {
  1542. *ppwReg = NLS_VALUE_S2359;
  1543. *ppwCache = pInfo->s2359;
  1544. break;
  1545. }
  1546. default :
  1547. {
  1548. return (FALSE);
  1549. }
  1550. }
  1551. return (TRUE);
  1552. }
  1553. ////////////////////////////////////////////////////////////////////////////
  1554. //
  1555. // GetStringTableEntry
  1556. //
  1557. // Returns the localized version of the strings for the given resource
  1558. // id. It gets the information from the resource file in the language that
  1559. // the current user is using.
  1560. //
  1561. // The string table contains a series of strings in the following order:
  1562. // Language Name
  1563. // Country Name
  1564. // Language Group Name
  1565. // Code Page Name (decimal values converted to hex values)
  1566. // Region (Geo) Friendly Name (decimal values converted to hex values)
  1567. // Region (Geo) Official Name (decimal values converted to hex values)
  1568. // Sorting Names (in order starting with 0, separated by $)
  1569. //
  1570. // Each string is separated by $. The final string is terminated with
  1571. // a null.
  1572. //
  1573. // The sorting names are in order of the sort ids, starting with 0.
  1574. //
  1575. // For example,
  1576. // "Language$Country$LangGrp$CodePage$Geo1$Geo2$Sort0$Sort1" or
  1577. // "Language$Country" or
  1578. // "$$LangGrp$CodePage" or
  1579. // "$$$CodePage" or
  1580. // "$$$$Geo1$Geo2"
  1581. //
  1582. // 11-17-00 JulieB Created.
  1583. ////////////////////////////////////////////////////////////////////////////
  1584. int GetStringTableEntry(
  1585. UINT ResourceID,
  1586. LANGID UILangId,
  1587. LPWSTR pBuffer,
  1588. int cchBuffer,
  1589. int WhichString)
  1590. {
  1591. HANDLE hFindRes; // handle from find resource
  1592. HANDLE hLoadRes; // handle from load resource
  1593. LPWSTR pSearch, pSearchEnd; // ptrs to search for correct string
  1594. LPWSTR pString; // ptr to final string
  1595. int cchCount = 0; // count of characters
  1596. //
  1597. // Make sure the buffer is ok.
  1598. //
  1599. if ((pBuffer == NULL) || (cchBuffer == 0))
  1600. {
  1601. return (0);
  1602. }
  1603. //
  1604. // Make sure we're not hitting the GEO ID that is out of bounds.
  1605. //
  1606. // !!! NOTE !!! This is needed because the East Timor Geo Id
  1607. // is out of bounds and wraps to 0x60e7.
  1608. //
  1609. if (ResourceID == 0x60e7)
  1610. {
  1611. return (0);
  1612. }
  1613. //
  1614. // Set the UI Language Id.
  1615. //
  1616. if (UILangId == 0)
  1617. {
  1618. UILangId = GetUserDefaultUILanguage();
  1619. }
  1620. //
  1621. // String Tables are broken up into 16 string segments. Find the
  1622. // resource containing the string we want.
  1623. //
  1624. if ((!(hFindRes = FindResourceExW( hModule,
  1625. RT_STRING,
  1626. (LPWSTR)UlongToPtr((ULONG)(((USHORT)ResourceID >> 4) + 1)),
  1627. (WORD)UILangId ))))
  1628. {
  1629. //
  1630. // Could not find resource. Try NEUTRAL language id.
  1631. //
  1632. if ((!(hFindRes = FindResourceExW( hModule,
  1633. RT_STRING,
  1634. (LPWSTR)UlongToPtr((ULONG)(((USHORT)ResourceID >> 4) + 1)),
  1635. (WORD)0 ))))
  1636. {
  1637. //
  1638. // Could not find resource. Return 0.
  1639. //
  1640. return (0);
  1641. }
  1642. }
  1643. //
  1644. // Load the resource.
  1645. //
  1646. if (hLoadRes = LoadResource(hModule, hFindRes))
  1647. {
  1648. //
  1649. // Lock the resource. Store the found pointer in the given
  1650. // pointer.
  1651. //
  1652. if (pSearch = (LPWSTR)LockResource(hLoadRes))
  1653. {
  1654. //
  1655. // Move past the other strings in this segment.
  1656. // (16 strings in a segment -> & 0x0F)
  1657. //
  1658. ResourceID &= 0x0F;
  1659. //
  1660. // Find the correct string in this segment.
  1661. //
  1662. while (TRUE)
  1663. {
  1664. cchCount = *((WORD *)pSearch++);
  1665. if (ResourceID-- == 0)
  1666. {
  1667. break;
  1668. }
  1669. pSearch += cchCount;
  1670. }
  1671. //
  1672. // Mark the end of the resource string since it is not
  1673. // NULL terminated.
  1674. //
  1675. pSearchEnd = pSearch + cchCount;
  1676. //
  1677. // Get to the appropriate string.
  1678. //
  1679. while ((WhichString > 0) && (pSearch < pSearchEnd))
  1680. {
  1681. do
  1682. {
  1683. if (*pSearch == RC_STRING_SEPARATOR)
  1684. {
  1685. pSearch++;
  1686. break;
  1687. }
  1688. pSearch++;
  1689. } while (pSearch < pSearchEnd);
  1690. WhichString--;
  1691. }
  1692. //
  1693. // Count the number of characters for this string.
  1694. //
  1695. pString = pSearch;
  1696. cchCount = 0;
  1697. while ((pSearch < pSearchEnd) && (*pSearch != RC_STRING_SEPARATOR))
  1698. {
  1699. pSearch++;
  1700. cchCount++;
  1701. }
  1702. //
  1703. // See if there is anything to copy.
  1704. //
  1705. if (cchCount > 0)
  1706. {
  1707. //
  1708. // Don't copy more than the max allowed.
  1709. //
  1710. if (cchCount >= cchBuffer)
  1711. {
  1712. cchCount = cchBuffer - 1;
  1713. }
  1714. //
  1715. // Copy the string into the buffer and NULL terminate it.
  1716. //
  1717. CopyMemory(pBuffer, pString, cchCount * sizeof(WCHAR));
  1718. pBuffer[cchCount] = 0;
  1719. //
  1720. // Return the number of characters in the string, not
  1721. // including the NULL terminator.
  1722. //
  1723. return (cchCount);
  1724. }
  1725. }
  1726. }
  1727. //
  1728. // Return failure.
  1729. //
  1730. return (0);
  1731. }
  1732. ////////////////////////////////////////////////////////////////////////////
  1733. //
  1734. // NlsIsDll
  1735. //
  1736. // Check if file extension is DLL
  1737. //
  1738. ////////////////////////////////////////////////////////////////////////////
  1739. BOOL FASTCALL NlsIsDll(
  1740. LPCWSTR pFileName
  1741. )
  1742. {
  1743. BOOL bIsDll = FALSE;
  1744. if (pFileName)
  1745. {
  1746. int iLen = NlsStrLenW(pFileName);
  1747. //
  1748. // Check DLL extension, save the trouble of calling lstrcmp
  1749. //
  1750. if (iLen > 4)
  1751. {
  1752. pFileName += iLen-4;
  1753. if ((*pFileName++ == L'.') &&
  1754. (*pFileName == L'D' || *pFileName++ == L'd') &&
  1755. (*pFileName == L'L' || *pFileName++ == L'l') &&
  1756. (*pFileName == L'L' || *pFileName++ == L'l'))
  1757. {
  1758. bIsDll = TRUE;
  1759. }
  1760. }
  1761. }
  1762. return bIsDll;
  1763. }