Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

3371 lines
108 KiB

  1. /*++
  2. Copyright (c) 1991-2000, Microsoft Corporation All rights reserved.
  3. Module Name:
  4. tables.c
  5. Abstract:
  6. This file contains functions that manipulate or return information
  7. about the different tables used by the NLS API.
  8. External Routines found in this file:
  9. AllocTables
  10. GetUnicodeFileInfo
  11. GetGeoFileInfo
  12. GetCTypeFileInfo
  13. GetDefaultSortkeyFileInfo
  14. GetDefaultSortTablesFileInfo
  15. GetSortkeyFileInfo
  16. GetSortTablesFileInfo
  17. GetCodePageFileInfo
  18. GetLanguageFileInfo
  19. GetLocaleFileInfo
  20. MakeCPHashNode
  21. MakeLangHashNode
  22. MakeLocHashNode
  23. GetCPHashNode
  24. GetLangHashNode
  25. GetLocHashNode
  26. GetCalendar
  27. Revision History:
  28. 05-31-91 JulieB Created.
  29. --*/
  30. //
  31. // Include Files.
  32. //
  33. #include "nls.h"
  34. #include "nlssafe.h"
  35. //
  36. // Constant Declarations.
  37. //
  38. #define SEM_NOERROR (SEM_FAILCRITICALERRORS | \
  39. SEM_NOGPFAULTERRORBOX | \
  40. SEM_NOOPENFILEERRORBOX)
  41. //
  42. // Global Variables.
  43. //
  44. PTBL_PTRS pTblPtrs; // ptr to structure of table ptrs
  45. //
  46. // Forward Declarations.
  47. //
  48. BOOL
  49. IsValidSortId(
  50. LCID Locale);
  51. ULONG
  52. GetLanguageExceptionInfo(void);
  53. LPWORD
  54. GetLinguisticLanguageInfo(
  55. LCID Locale);
  56. ULONG
  57. CreateAndCopyLanguageExceptions(
  58. LCID Locale,
  59. LPWORD *ppBaseAddr);
  60. BOOL FASTCALL
  61. FindLanguageExceptionPointers(
  62. LCID Locale,
  63. PL_EXCEPT_HDR *ppExceptHdr,
  64. PL_EXCEPT *ppExceptTbl);
  65. void FASTCALL
  66. CopyLanguageExceptionInfo(
  67. LPWORD pBaseAddr,
  68. PL_EXCEPT_HDR pExceptHdr,
  69. PL_EXCEPT pExceptTbl);
  70. BOOL FASTCALL
  71. FindExceptionPointers(
  72. LCID Locale,
  73. PEXCEPT_HDR *ppExceptHdr,
  74. PEXCEPT *ppExceptTbl,
  75. PVOID *ppIdeograph,
  76. PULONG pReturn);
  77. void FASTCALL
  78. CopyExceptionInfo(
  79. PSORTKEY pSortkey,
  80. PEXCEPT_HDR pExceptHdr,
  81. PEXCEPT pExceptTbl,
  82. PVOID pIdeograph);
  83. ULONG
  84. WaitOnEvent(
  85. LPWORD pSem);
  86. //-------------------------------------------------------------------------//
  87. // INTERNAL MACROS //
  88. //-------------------------------------------------------------------------//
  89. ////////////////////////////////////////////////////////////////////////////
  90. //
  91. // GET_HASH_VALUE
  92. //
  93. // Returns the hash value for given value and the given table size.
  94. //
  95. // DEFINED AS A MACRO.
  96. //
  97. // 05-31-91 JulieB Created.
  98. ////////////////////////////////////////////////////////////////////////////
  99. #define GET_HASH_VALUE(Value, TblSize) (Value % TblSize)
  100. ////////////////////////////////////////////////////////////////////////////
  101. //
  102. // CREATE_CODEPAGE_HASH_NODE
  103. //
  104. // Creates a code page hash node and stores the pointer to it in pHashN.
  105. //
  106. // NOTE: This macro may return if an error is encountered.
  107. //
  108. // DEFINED AS A MACRO.
  109. //
  110. // 05-31-91 JulieB Created.
  111. ////////////////////////////////////////////////////////////////////////////
  112. #define CREATE_CODEPAGE_HASH_NODE( CodePage, \
  113. pHashN ) \
  114. { \
  115. /* \
  116. * Allocate CP_HASH structure. \
  117. */ \
  118. if ((pHashN = (PCP_HASH)NLS_ALLOC_MEM(sizeof(CP_HASH))) == NULL) \
  119. { \
  120. return (ERROR_OUTOFMEMORY); \
  121. } \
  122. \
  123. /* \
  124. * Fill in the CodePage value. \
  125. */ \
  126. pHashN->CodePage = CodePage; \
  127. \
  128. /* \
  129. * Make sure the pfnCPProc value is NULL for now. \
  130. */ \
  131. pHashN->pfnCPProc = NULL; \
  132. }
  133. ////////////////////////////////////////////////////////////////////////////
  134. //
  135. // CREATE_LOCALE_HASH_NODE
  136. //
  137. // Creates a locale hash node and stores the pointer to it in pHashN.
  138. //
  139. // NOTE: This macro may return if an error is encountered.
  140. //
  141. // DEFINED AS A MACRO.
  142. //
  143. // 05-31-91 JulieB Created.
  144. ////////////////////////////////////////////////////////////////////////////
  145. #define CREATE_LOCALE_HASH_NODE( Locale, \
  146. pHashN ) \
  147. { \
  148. /* \
  149. * Allocate LOC_HASH structure. \
  150. */ \
  151. if ((pHashN = (PLOC_HASH)NLS_ALLOC_MEM(sizeof(LOC_HASH))) == NULL) \
  152. { \
  153. return (ERROR_OUTOFMEMORY); \
  154. } \
  155. \
  156. /* \
  157. * Fill in the Locale value. \
  158. */ \
  159. pHashN->Locale = Locale; \
  160. }
  161. ////////////////////////////////////////////////////////////////////////////
  162. //
  163. // FIND_CP_HASH_NODE
  164. //
  165. // Searches for the cp hash node for the given locale. The result is
  166. // put in pHashN. If no node exists, pHashN will be NULL.
  167. //
  168. // DEFINED AS A MACRO.
  169. //
  170. // 05-31-91 JulieB Created.
  171. ////////////////////////////////////////////////////////////////////////////
  172. #define FIND_CP_HASH_NODE( CodePage, \
  173. pHashN ) \
  174. { \
  175. UINT Index; /* hash value */ \
  176. \
  177. /* \
  178. * Get hash value. \
  179. */ \
  180. Index = GET_HASH_VALUE(CodePage, CP_TBL_SIZE); \
  181. \
  182. /* \
  183. * Make sure the hash node still doesn't exist in the table. \
  184. */ \
  185. pHashN = (pTblPtrs->pCPHashTbl)[Index]; \
  186. while ((pHashN != NULL) && (pHashN->CodePage != CodePage)) \
  187. { \
  188. pHashN = pHashN->pNext; \
  189. } \
  190. }
  191. ////////////////////////////////////////////////////////////////////////////
  192. //
  193. // IsCPHashNodeLoaded
  194. //
  195. // Wrapper for the FIND_CP_HASH_NODE macro so that we can call this from
  196. // mbcs.c. Return TRUE if the node already exists, otherwise false. False
  197. // could still indicate a valid code page, just not one already loaded.
  198. //
  199. // 05-31-02 ShawnSte Created.
  200. ////////////////////////////////////////////////////////////////////////////
  201. BOOL IsCPHashNodeLoaded( UINT CodePage )
  202. {
  203. PCP_HASH pHashN; // ptr to CP hash node
  204. //
  205. // Get hash node.
  206. //
  207. FIND_CP_HASH_NODE(CodePage, pHashN);
  208. return (pHashN != NULL);
  209. }
  210. ////////////////////////////////////////////////////////////////////////////
  211. //
  212. // FIND_LOCALE_HASH_NODE
  213. //
  214. // Searches for the locale hash node for the given locale. The result is
  215. // put in pHashN. If no node exists, pHashN will be NULL.
  216. //
  217. // DEFINED AS A MACRO.
  218. //
  219. // 05-31-91 JulieB Created.
  220. ////////////////////////////////////////////////////////////////////////////
  221. #define FIND_LOCALE_HASH_NODE( Locale, \
  222. pHashN ) \
  223. { \
  224. UINT Index; /* hash value */ \
  225. \
  226. \
  227. /* \
  228. * Get hash value. \
  229. */ \
  230. Index = GET_HASH_VALUE(Locale, LOC_TBL_SIZE); \
  231. \
  232. /* \
  233. * Get hash node. \
  234. */ \
  235. pHashN = (pTblPtrs->pLocHashTbl)[Index]; \
  236. while ((pHashN != NULL) && (pHashN->Locale != Locale)) \
  237. { \
  238. pHashN = pHashN->pNext; \
  239. } \
  240. }
  241. ////////////////////////////////////////////////////////////////////////////
  242. //
  243. // EXIST_LANGUAGE_INFO
  244. //
  245. // Checks to see if the casing tables have been added to the locale
  246. // hash node.
  247. //
  248. // Must check the LOWER CASE pointer, since that value is set last in
  249. // the hash node.
  250. //
  251. // DEFINED AS A MACRO.
  252. //
  253. // 05-31-91 JulieB Created.
  254. ////////////////////////////////////////////////////////////////////////////
  255. #define EXIST_LANGUAGE_INFO(pHashN) (pHashN->pLowerCase)
  256. ////////////////////////////////////////////////////////////////////////////
  257. //
  258. // EXIST_LINGUIST_LANGUAGE_INFO
  259. //
  260. // Checks to see if the linguistic casing tables have been added to the locale
  261. // hash node.
  262. //
  263. // Must check the LOWER CASE pointer, since that value is set last in
  264. // the hash node.
  265. //
  266. // DEFINED AS A MACRO.
  267. //
  268. // 08-30-95 JulieB Created.
  269. ////////////////////////////////////////////////////////////////////////////
  270. #define EXIST_LINGUIST_LANGUAGE_INFO(pHashN) (pHashN->pLowerLinguist)
  271. ////////////////////////////////////////////////////////////////////////////
  272. //
  273. // EXIST_LOCALE_INFO
  274. //
  275. // Checks to see if the locale tables have been added to the locale
  276. // hash node.
  277. //
  278. // Must check the FIXED locale pointer, since that value is set last in
  279. // the hash node.
  280. //
  281. // DEFINED AS A MACRO.
  282. //
  283. // 05-31-91 JulieB Created.
  284. ////////////////////////////////////////////////////////////////////////////
  285. #define EXIST_LOCALE_INFO(pHashN) (pHashN->pLocaleFixed)
  286. ////////////////////////////////////////////////////////////////////////////
  287. //
  288. // INSERT_CP_HASH_NODE
  289. //
  290. // Inserts a CP hash node into the global CP hash table. It assumes that
  291. // all unused hash values in the table are pointing to NULL. If there is
  292. // a collision, the new node will be added FIRST in the list.
  293. //
  294. // DEFINED AS A MACRO.
  295. //
  296. // 05-31-91 JulieB Created.
  297. ////////////////////////////////////////////////////////////////////////////
  298. #define INSERT_CP_HASH_NODE( pHashN, \
  299. pBaseAddr ) \
  300. { \
  301. UINT Index; /* hash value */ \
  302. PCP_HASH pSearch; /* ptr to CP hash node for search */ \
  303. \
  304. \
  305. /* \
  306. * Get hash value. \
  307. */ \
  308. Index = GET_HASH_VALUE(pHashN->CodePage, CP_TBL_SIZE); \
  309. \
  310. /* \
  311. * Enter table pointers critical section. \
  312. */ \
  313. RtlEnterCriticalSection(&gcsTblPtrs); \
  314. \
  315. /* \
  316. * Make sure the hash node still doesn't exist in the table. \
  317. */ \
  318. pSearch = (pTblPtrs->pCPHashTbl)[Index]; \
  319. while ((pSearch != NULL) && (pSearch->CodePage != pHashN->CodePage)) \
  320. { \
  321. pSearch = pSearch->pNext; \
  322. } \
  323. \
  324. /* \
  325. * If the hash node does not exist, insert the new one. \
  326. * Otherwise, free it. \
  327. */ \
  328. if (pSearch == NULL) \
  329. { \
  330. /* \
  331. * Insert hash node into hash table. \
  332. */ \
  333. pHashN->pNext = (pTblPtrs->pCPHashTbl)[Index]; \
  334. (pTblPtrs->pCPHashTbl)[Index] = pHashN; \
  335. } \
  336. else \
  337. { \
  338. /* \
  339. * Free the resources allocated. \
  340. */ \
  341. if (pBaseAddr) \
  342. { \
  343. UnMapSection(pBaseAddr); \
  344. } \
  345. NLS_FREE_MEM(pHashN); \
  346. } \
  347. \
  348. /* \
  349. * Leave table pointers critical section. \
  350. */ \
  351. RtlLeaveCriticalSection(&gcsTblPtrs); \
  352. }
  353. ////////////////////////////////////////////////////////////////////////////
  354. //
  355. // INSERT_LOC_HASH_NODE
  356. //
  357. // Inserts a LOC hash node into the global LOC hash table. It assumes
  358. // that all unused hash values in the table are pointing to NULL. If
  359. // there is a collision, the new node will be added FIRST in the list.
  360. //
  361. // DEFINED AS A MACRO.
  362. //
  363. // 05-31-91 JulieB Created.
  364. ////////////////////////////////////////////////////////////////////////////
  365. #define INSERT_LOC_HASH_NODE( pHashN, \
  366. pBaseAddr ) \
  367. { \
  368. UINT Index; /* hash value */ \
  369. PLOC_HASH pSearch; /* ptr to LOC hash node for search */ \
  370. \
  371. \
  372. /* \
  373. * Get hash value. \
  374. */ \
  375. Index = GET_HASH_VALUE(pHashN->Locale, LOC_TBL_SIZE); \
  376. \
  377. /* \
  378. * Enter table pointers critical section. \
  379. */ \
  380. RtlEnterCriticalSection(&gcsTblPtrs); \
  381. \
  382. /* \
  383. * Make sure the hash node still doesn't exist in the table. \
  384. */ \
  385. pSearch = (pTblPtrs->pLocHashTbl)[Index]; \
  386. while ((pSearch != NULL) && (pSearch->Locale != pHashN->Locale)) \
  387. { \
  388. pSearch = pSearch->pNext; \
  389. } \
  390. \
  391. /* \
  392. * If the hash node does not exist, insert the new one. \
  393. * Otherwise, free it. \
  394. */ \
  395. if (pSearch == NULL) \
  396. { \
  397. /* \
  398. * Insert hash node into hash table. \
  399. */ \
  400. pHashN->pNext = (pTblPtrs->pLocHashTbl)[Index]; \
  401. (pTblPtrs->pLocHashTbl)[Index] = pHashN; \
  402. } \
  403. else \
  404. { \
  405. /* \
  406. * Free the resources allocated. \
  407. */ \
  408. if (pBaseAddr) \
  409. { \
  410. UnMapSection(pBaseAddr); \
  411. } \
  412. if ((pHashN->pSortkey != pTblPtrs->pDefaultSortkey) && \
  413. (pHashN->pSortkey != NULL)) \
  414. { \
  415. UnMapSection(((LPWORD)(pHashN->pSortkey)) - SORTKEY_HEADER); \
  416. } \
  417. NLS_FREE_MEM(pHashN); \
  418. } \
  419. \
  420. /* \
  421. * Leave table pointers critical section. \
  422. */ \
  423. RtlLeaveCriticalSection(&gcsTblPtrs); \
  424. }
  425. ////////////////////////////////////////////////////////////////////////////
  426. //
  427. // GET_CP_SECTION_NAME
  428. //
  429. // Gets the section name for a given code page.
  430. //
  431. // NOTE: This macro may return if an error is encountered.
  432. //
  433. // DEFINED AS A MACRO.
  434. //
  435. // 05-31-91 JulieB Created.
  436. ////////////////////////////////////////////////////////////////////////////
  437. #define GET_CP_SECTION_NAME( CodePage, \
  438. pwszSecName, \
  439. cchSecName, \
  440. pObSecName ) \
  441. { \
  442. if (rc = GetNlsSectionName( CodePage, \
  443. 10, \
  444. 0, \
  445. NLS_SECTION_CPPREFIX, \
  446. pwszSecName, \
  447. cchSecName)) \
  448. { \
  449. return (rc); \
  450. } \
  451. RtlInitUnicodeString(pObSecName, pwszSecName); \
  452. }
  453. ////////////////////////////////////////////////////////////////////////////
  454. //
  455. // GET_SORTKEY_SECTION_NAME
  456. //
  457. // Gets the sortkey section name for a given locale.
  458. //
  459. // NOTE: This macro may return if an error is encountered.
  460. //
  461. // DEFINED AS A MACRO.
  462. //
  463. // 05-31-91 JulieB Created.
  464. ////////////////////////////////////////////////////////////////////////////
  465. #define GET_SORTKEY_SECTION_NAME( Locale, \
  466. pwszSecName, \
  467. cchSecName, \
  468. pObSecName ) \
  469. { \
  470. if (rc = GetNlsSectionName( Locale, \
  471. 16, \
  472. 8, \
  473. NLS_SECTION_SORTKEY, \
  474. pwszSecName, \
  475. cchSecName)) \
  476. { \
  477. return (rc); \
  478. } \
  479. RtlInitUnicodeString(pObSecName, pwszSecName); \
  480. }
  481. ////////////////////////////////////////////////////////////////////////////
  482. //
  483. // GET_LANG_SECTION_NAME
  484. //
  485. // Gets the section name for a given language.
  486. //
  487. // NOTE: This macro may return if an error is encountered.
  488. //
  489. // DEFINED AS A MACRO.
  490. //
  491. // 05-31-91 JulieB Created.
  492. ////////////////////////////////////////////////////////////////////////////
  493. #define GET_LANG_SECTION_NAME( Locale, \
  494. pwszSecName, \
  495. cchSecName, \
  496. pObSecName ) \
  497. { \
  498. if (rc = GetNlsSectionName( Locale, \
  499. 16, \
  500. 8, \
  501. NLS_SECTION_LANGPREFIX, \
  502. pwszSecName, \
  503. cchSecName)) \
  504. { \
  505. return (rc); \
  506. } \
  507. RtlInitUnicodeString(pObSecName, pwszSecName); \
  508. }
  509. //-------------------------------------------------------------------------//
  510. // EXTERNAL ROUTINES //
  511. //-------------------------------------------------------------------------//
  512. ////////////////////////////////////////////////////////////////////////////
  513. //
  514. // AllocTables
  515. //
  516. // Allocates the global table pointers structure. It then allocates the
  517. // code page and locale hash tables and saves the pointers to the tables
  518. // in the global table pointers structure.
  519. //
  520. // 05-31-91 JulieB Created.
  521. ////////////////////////////////////////////////////////////////////////////
  522. ULONG AllocTables()
  523. {
  524. //
  525. // Allocate global table pointers structure.
  526. //
  527. if ((pTblPtrs = (PTBL_PTRS)NLS_ALLOC_MEM(sizeof(TBL_PTRS))) == NULL)
  528. {
  529. KdPrint(("NLSAPI: Allocation for TABLE PTRS structure FAILED.\n"));
  530. return (ERROR_OUTOFMEMORY);
  531. }
  532. //
  533. // Allocate code page hash table.
  534. //
  535. if ((pTblPtrs->pCPHashTbl =
  536. (PCP_HASH_TBL)NLS_ALLOC_MEM(sizeof(PCP_HASH) * CP_TBL_SIZE)) == NULL)
  537. {
  538. KdPrint(("NLSAPI: Allocation for CODE PAGE hash table FAILED.\n"));
  539. return (ERROR_OUTOFMEMORY);
  540. }
  541. //
  542. // Allocate locale hash table.
  543. //
  544. if ((pTblPtrs->pLocHashTbl =
  545. (PLOC_HASH_TBL)NLS_ALLOC_MEM(sizeof(PLOC_HASH) * LOC_TBL_SIZE)) == NULL)
  546. {
  547. KdPrint(("NLSAPI: Allocation for LOCALE hash table FAILED.\n"));
  548. return (ERROR_OUTOFMEMORY);
  549. }
  550. //
  551. // Return success.
  552. //
  553. return (NO_ERROR);
  554. }
  555. ////////////////////////////////////////////////////////////////////////////
  556. //
  557. // GetUnicodeFileInfo
  558. //
  559. // Opens and Maps a view of the section for the unicode file. It then
  560. // fills in the appropriate fields of the global table pointers structure.
  561. //
  562. // 05-31-91 JulieB Created.
  563. ////////////////////////////////////////////////////////////////////////////
  564. ULONG GetUnicodeFileInfo()
  565. {
  566. HANDLE hSec = (HANDLE)0; // section handle
  567. UNICODE_STRING ObSecName; // section name
  568. LPWORD pBaseAddr; // ptr to base address of section
  569. ULONG rc = 0L; // return code
  570. WORD offCZ; // offset to FOLDCZONE table
  571. WORD offHG; // offset to HIRAGANA table
  572. WORD offKK; // offset to KATAKANA table
  573. WORD offHW; // offset to HALFWIDTH table
  574. WORD offFW; // offset to FULLWIDTH table
  575. WORD offTR; // offset to TRADITIONAL table
  576. WORD offSP; // offset to SIMPLIFIED table
  577. WORD offPre; // offset to PRECOMPOSED table
  578. WORD offComp; // offset to COMPOSITE table
  579. PCOMP_INFO pComp; // ptr to COMP_INFO structure
  580. //
  581. // Make sure we're in the critical section when entering this call.
  582. //
  583. ASSERT(NtCurrentTeb()->ClientId.UniqueThread == gcsTblPtrs.OwningThread);
  584. //
  585. // Make sure the unicode information is not already there.
  586. // If it is, return success.
  587. //
  588. // Since we're already in the critical section here, there is no
  589. // need to check ALL of the pointers set in this routine. Just
  590. // check one of them.
  591. //
  592. if (pTblPtrs->pADigit != NULL)
  593. {
  594. return (NO_ERROR);
  595. }
  596. //
  597. // Open and Map a view of the section.
  598. //
  599. ObSecName.Buffer = NLS_SECTION_UNICODE;
  600. ObSecName.Length = sizeof (NLS_SECTION_UNICODE) - sizeof (WCHAR);
  601. ObSecName.MaximumLength = ObSecName.Length;
  602. if (rc = OpenSection( &hSec,
  603. &ObSecName,
  604. (PVOID *)&pBaseAddr,
  605. SECTION_MAP_READ,
  606. TRUE ))
  607. {
  608. return (rc);
  609. }
  610. //
  611. // Get the offsets.
  612. //
  613. offCZ = pBaseAddr[0];
  614. offHG = offCZ + pBaseAddr[offCZ];
  615. offKK = offHG + pBaseAddr[offHG];
  616. offHW = offKK + pBaseAddr[offKK];
  617. offFW = offHW + pBaseAddr[offHW];
  618. offTR = offFW + pBaseAddr[offFW];
  619. offSP = offTR + pBaseAddr[offTR];
  620. offPre = offSP + pBaseAddr[offSP];
  621. offComp = offPre + pBaseAddr[offPre];
  622. //
  623. // Allocate COMP_INFO structure.
  624. //
  625. if ((pComp = (PCOMP_INFO)NLS_ALLOC_MEM(sizeof(COMP_INFO))) == NULL)
  626. {
  627. return (ERROR_OUTOFMEMORY);
  628. }
  629. //
  630. // Fill in the COMPOSITE information.
  631. //
  632. pComp->NumBase = LOBYTE((pBaseAddr + offComp)[2]);
  633. pComp->NumNonSp = HIBYTE((pBaseAddr + offComp)[2]);
  634. pComp->pBase = pBaseAddr + offComp + CO_HEADER;
  635. pComp->pNonSp = pComp->pBase + ((pBaseAddr + offComp)[0]);
  636. pComp->pGrid = pComp->pNonSp + ((pBaseAddr + offComp)[1]);
  637. //
  638. // Attach ASCIIDIGITS table to tbl ptrs structure.
  639. //
  640. pTblPtrs->pADigit = pBaseAddr + AD_HEADER;
  641. //
  642. // Attach FOLDCZONE table to tbl ptrs structure.
  643. //
  644. pTblPtrs->pCZone = pBaseAddr + offCZ + CZ_HEADER;
  645. //
  646. // Attach HIRAGANA table to tbl ptrs structure.
  647. //
  648. pTblPtrs->pHiragana = pBaseAddr + offHG + HG_HEADER;
  649. //
  650. // Attach KATAKANA table to tbl ptrs structure.
  651. //
  652. pTblPtrs->pKatakana = pBaseAddr + offKK + KK_HEADER;
  653. //
  654. // Attach HALFWIDTH table to tbl ptrs structure.
  655. //
  656. pTblPtrs->pHalfWidth = pBaseAddr + offHW + HW_HEADER;
  657. //
  658. // Attach FULLWIDTH table to tbl ptrs structure.
  659. //
  660. pTblPtrs->pFullWidth = pBaseAddr + offFW + FW_HEADER;
  661. //
  662. // Attach TRADITIONAL table to tbl ptrs structure.
  663. //
  664. pTblPtrs->pTraditional = pBaseAddr + offTR + TR_HEADER;
  665. //
  666. // Attach SIMPLIFIED table to tbl ptrs structure.
  667. //
  668. pTblPtrs->pSimplified = pBaseAddr + offSP + SP_HEADER;
  669. //
  670. // Attach PRECOMPOSED table to tbl ptrs structure.
  671. //
  672. pTblPtrs->pPreComposed = pBaseAddr + offPre + PC_HEADER;
  673. //
  674. // Attach COMP_INFO to tbl ptrs structure.
  675. //
  676. pTblPtrs->pComposite = pComp;
  677. //
  678. // Return success.
  679. //
  680. return (NO_ERROR);
  681. }
  682. ////////////////////////////////////////////////////////////////////////////
  683. //
  684. // GetGeoFileInfo
  685. //
  686. // Opens and Maps a view of the section for the geo file. It then
  687. // fills in the appropriate field of the global table pointers structure.
  688. // Before calling this function you should check pGeoInfo member.
  689. //
  690. ////////////////////////////////////////////////////////////////////////////
  691. ULONG GetGeoFileInfo()
  692. {
  693. HANDLE hSec = (HANDLE)0; // section handle
  694. UNICODE_STRING ObSecName; // section name
  695. LPWORD pBaseAddr; // ptr to base address of section
  696. ULONG rc = NO_ERROR; // return code
  697. //
  698. // Enter the critical section to set up the GEO tables.
  699. //
  700. RtlEnterCriticalSection(&gcsTblPtrs);
  701. //
  702. // Make sure the Geographical Information table is
  703. // not already there. If it is, return TRUE.
  704. //
  705. // Since we're already in the critical section here, there is no
  706. // need to check ALL of the pointers set in this routine. Just
  707. // check one of them.
  708. //
  709. if (pTblPtrs->pGeoInfo != NULL)
  710. {
  711. RtlLeaveCriticalSection(&gcsTblPtrs);
  712. return (NO_ERROR);
  713. }
  714. //
  715. // Create and map the section, and then save the pointer.
  716. //
  717. if ((rc = CsrBasepNlsCreateSection(NLS_CREATE_SECTION_GEO, 0, &hSec)) == NO_ERROR)
  718. {
  719. //
  720. // Map a View of the Section.
  721. //
  722. if ((rc = MapSection( hSec,
  723. &pBaseAddr,
  724. PAGE_READONLY,
  725. TRUE )) != NO_ERROR)
  726. {
  727. RtlLeaveCriticalSection(&gcsTblPtrs);
  728. return (rc);
  729. }
  730. }
  731. else
  732. {
  733. RtlLeaveCriticalSection(&gcsTblPtrs);
  734. return (rc);
  735. }
  736. //
  737. // Attach GeoInfo mapping table, GEO/LCID mapping table and
  738. // GEO/ISO639 name mapping table to the tbl ptrs structure. We initialize
  739. // the pGeoinfo member at the end so we don't get a race condition.
  740. //
  741. pTblPtrs->nGeoLCID = ((PGEOTABLEHDR)pBaseAddr)->nGeoLCID;
  742. pTblPtrs->pGeoLCID = (PGEOLCID)((PBYTE)pBaseAddr + ((PGEOTABLEHDR)pBaseAddr)->dwOffsetGeoLCID);
  743. pTblPtrs->nGeoInfo = ((PGEOTABLEHDR)pBaseAddr)->nGeoInfo;
  744. pTblPtrs->pGeoInfo = (PGEOINFO)((PBYTE)pBaseAddr + ((PGEOTABLEHDR)pBaseAddr)->dwOffsetGeoInfo);
  745. //
  746. // Leave table pointers critical section.
  747. //
  748. RtlLeaveCriticalSection(&gcsTblPtrs);
  749. //
  750. // Return success.
  751. //
  752. return (NO_ERROR);
  753. }
  754. ////////////////////////////////////////////////////////////////////////////
  755. //
  756. // GetCTypeFileInfo
  757. //
  758. // Opens and Maps a view of the section for the given ctype. It then
  759. // fills in the appropriate field of the global table pointers structure.
  760. //
  761. // 05-31-91 JulieB Created.
  762. ////////////////////////////////////////////////////////////////////////////
  763. ULONG GetCTypeFileInfo()
  764. {
  765. HANDLE hSec = (HANDLE)0; // section handle
  766. UNICODE_STRING ObSecName; // section name
  767. LPWORD pBaseAddr; // ptr to base address of section
  768. ULONG rc = 0L; // return code
  769. //
  770. // Make sure the ctype information is not already there.
  771. // If it is, return success.
  772. //
  773. // Must check the 844 table rather than the mapping table, since
  774. // the 844 table is set AFTER the mapping table below. Otherwise,
  775. // there is a race condition, since we're not in a critical section.
  776. //
  777. if (pTblPtrs->pCType844 != NULL)
  778. {
  779. return (NO_ERROR);
  780. }
  781. //
  782. // Enter table pointers critical section.
  783. //
  784. RtlEnterCriticalSection(&gcsTblPtrs);
  785. if (pTblPtrs->pCType844 != NULL)
  786. {
  787. RtlLeaveCriticalSection(&gcsTblPtrs);
  788. return (NO_ERROR);
  789. }
  790. //
  791. // Open and Map a view of the section.
  792. //
  793. RtlInitUnicodeString(&ObSecName, NLS_SECTION_CTYPE);
  794. if (rc = OpenSection( &hSec,
  795. &ObSecName,
  796. (PVOID *)&pBaseAddr,
  797. SECTION_MAP_READ,
  798. TRUE ))
  799. {
  800. RtlLeaveCriticalSection(&gcsTblPtrs);
  801. return (rc);
  802. }
  803. //
  804. // Attach CTYPE mapping table and 8:4:4 table to tbl ptrs structure.
  805. //
  806. // The pCType844 value must be set LAST, since this is the pointer
  807. // that is checked to see that the ctype information has been
  808. // initialized.
  809. //
  810. pTblPtrs->pCTypeMap = (PCT_VALUES)(pBaseAddr + CT_HEADER);
  811. pTblPtrs->pCType844 = (PCTYPE)((LPBYTE)(pBaseAddr + 1) +
  812. ((PCTYPE_HDR)pBaseAddr)->MapSize);
  813. //
  814. // Leave table pointers critical section.
  815. //
  816. RtlLeaveCriticalSection(&gcsTblPtrs);
  817. //
  818. // Return success.
  819. //
  820. return (NO_ERROR);
  821. }
  822. ////////////////////////////////////////////////////////////////////////////
  823. //
  824. // GetDefaultSortkeyFileInfo
  825. //
  826. // Opens and Maps a view of the section for the default sortkey table. It
  827. // then stores the pointer to the table in the global pointer table.
  828. //
  829. // NOTE: THIS ROUTINE SHOULD ONLY BE CALLED AT PROCESS STARTUP. If it is
  830. // called from other than process startup, a critical section must
  831. // be placed around the assigning of the pointers to pTblPtrs.
  832. //
  833. // 05-31-91 JulieB Created.
  834. ////////////////////////////////////////////////////////////////////////////
  835. ULONG GetDefaultSortkeyFileInfo()
  836. {
  837. HANDLE hSec = (HANDLE)0; // section handle
  838. UNICODE_STRING ObSecName; // section name
  839. LPWORD pBaseAddr; // ptr to base address of section
  840. ULONG rc = 0L; // return code
  841. SECTION_BASIC_INFORMATION SecInfo; // section information - query
  842. //
  843. // Make sure we're in the critical section when entering this call.
  844. //
  845. ASSERT(NtCurrentTeb()->ClientId.UniqueThread == gcsTblPtrs.OwningThread);
  846. //
  847. // Open and Map a view of the section if it hasn't been done yet.
  848. //
  849. if (pTblPtrs->pDefaultSortkey != NULL)
  850. {
  851. return (NO_ERROR);
  852. }
  853. ObSecName.Buffer = NLS_SECTION_SORTKEY;
  854. ObSecName.Length = sizeof (NLS_SECTION_SORTKEY) - sizeof (WCHAR);
  855. ObSecName.MaximumLength = ObSecName.Length;
  856. if (rc = OpenSection( &hSec,
  857. &ObSecName,
  858. (PVOID *)&pBaseAddr,
  859. SECTION_MAP_READ | SECTION_QUERY,
  860. FALSE ))
  861. {
  862. KdPrint(("NLSAPI: Could NOT Open Section %wZ - %lx.\n", &ObSecName, rc));
  863. return (rc);
  864. }
  865. //
  866. // Query size of default section.
  867. //
  868. rc = NtQuerySection( hSec,
  869. SectionBasicInformation,
  870. &SecInfo,
  871. sizeof(SecInfo),
  872. NULL );
  873. //
  874. // Close the section handle.
  875. //
  876. NtClose(hSec);
  877. //
  878. // Check for error from NtQuerySection.
  879. //
  880. if (!NT_SUCCESS(rc))
  881. {
  882. KdPrint(("NLSAPI: Could NOT Query Section %wZ - %lx.\n", &ObSecName, rc));
  883. return (rc);
  884. }
  885. //
  886. // Get Default Sortkey Information.
  887. //
  888. pTblPtrs->pDefaultSortkey = (PSORTKEY)(pBaseAddr + SORTKEY_HEADER);
  889. pTblPtrs->DefaultSortkeySize = SecInfo.MaximumSize;
  890. //
  891. // Return success.
  892. //
  893. return (NO_ERROR);
  894. }
  895. ////////////////////////////////////////////////////////////////////////////
  896. //
  897. // GetDefaultSortTablesFileInfo
  898. //
  899. // Opens and Maps a view of the section for the sort tables. It then
  900. // stores the pointers to the various tables in the global pointer table.
  901. //
  902. // NOTE: THIS ROUTINE SHOULD ONLY BE CALLED AT PROCESS STARTUP. If it is
  903. // called from other than process startup, a critical section must
  904. // be placed around the assigning of the pointers to pTblPtrs.
  905. //
  906. // 05-31-91 JulieB Created.
  907. ////////////////////////////////////////////////////////////////////////////
  908. ULONG GetDefaultSortTablesFileInfo()
  909. {
  910. HANDLE hSec = (HANDLE)0; // section handle
  911. UNICODE_STRING ObSecName; // section name
  912. LPWORD pBaseAddr; // word ptr to base address of section
  913. DWORD Num; // number of entries in table
  914. PCOMPRESS_HDR pCompressHdr; // ptr to compression header
  915. PEXCEPT_HDR pExceptHdr; // ptr to exception header
  916. ULONG rc = 0L; // return code
  917. //
  918. // Make sure we're in the critical section when entering this call.
  919. //
  920. ASSERT(NtCurrentTeb()->ClientId.UniqueThread == gcsTblPtrs.OwningThread);
  921. //
  922. // Open and Map a view of the section if it hasn't been done yet.
  923. //
  924. // Since we're already in the critical section here, there is no
  925. // need to check ALL of the pointers set in this routine. Just
  926. // check one of them.
  927. //
  928. if (pTblPtrs->pReverseDW != NULL)
  929. {
  930. return (NO_ERROR);
  931. }
  932. ObSecName.Buffer = NLS_SECTION_SORTTBLS;
  933. ObSecName.Length = sizeof (NLS_SECTION_SORTTBLS) - sizeof (WCHAR);
  934. ObSecName.MaximumLength = ObSecName.Length;
  935. if (rc = OpenSection( &hSec,
  936. &ObSecName,
  937. (PVOID *)&pBaseAddr,
  938. SECTION_MAP_READ,
  939. TRUE ))
  940. {
  941. return (rc);
  942. }
  943. pTblPtrs->pSortingTableFileBase = pBaseAddr;
  944. //
  945. // Get Defined Code Point version Information.
  946. //
  947. pTblPtrs->NumDefinedVersion = Num = *((LPDWORD)pBaseAddr);
  948. pBaseAddr += NLSDEFINED_HEADER;
  949. if (Num > 0)
  950. {
  951. pTblPtrs->pDefinedVersion = (PDEFVERINFO)pBaseAddr;
  952. pBaseAddr += Num * sizeof(DEFVERINFO)/sizeof(WORD);
  953. }
  954. else
  955. {
  956. KdPrint(("NLSAPI: Appropriate Defined Code Point Table Not Loaded.\n"));
  957. pTblPtrs->pDefinedVersion = NULL;
  958. }
  959. //
  960. // Get Sorting Version Information.
  961. //
  962. if ((pTblPtrs->NumSortVersion = *((LPDWORD)pBaseAddr)) > 0)
  963. {
  964. pTblPtrs->pSortVersion = (PSORTVERINFO)(pBaseAddr + SORTVERINFO_HEADER);
  965. } else
  966. {
  967. pTblPtrs->pSortVersion = NULL;
  968. }
  969. pBaseAddr += SORTVERINFO_HEADER + (pTblPtrs->NumSortVersion * (sizeof(SORTVERINFO) / sizeof(WORD)));
  970. //
  971. // Get Reverse Diacritic Information.
  972. //
  973. Num = *((LPDWORD)pBaseAddr);
  974. if (Num > 0)
  975. {
  976. pTblPtrs->NumReverseDW = Num;
  977. pTblPtrs->pReverseDW = (PREVERSE_DW)(pBaseAddr + REV_DW_HEADER);
  978. }
  979. pBaseAddr += REV_DW_HEADER + (Num * (sizeof(REVERSE_DW) / sizeof(WORD)));
  980. //
  981. // Get Double Compression Information.
  982. //
  983. Num = *((LPDWORD)pBaseAddr);
  984. if (Num > 0)
  985. {
  986. pTblPtrs->NumDblCompression = Num;
  987. pTblPtrs->pDblCompression = (PDBL_COMPRESS)(pBaseAddr + DBL_COMP_HEADER);
  988. }
  989. pBaseAddr += DBL_COMP_HEADER + (Num * (sizeof(DBL_COMPRESS) / sizeof(WORD)));
  990. //
  991. // Get Ideograph Lcid Exception Information.
  992. //
  993. Num = *((LPDWORD)pBaseAddr);
  994. if (Num > 0)
  995. {
  996. pTblPtrs->NumIdeographLcid = Num;
  997. pTblPtrs->pIdeographLcid = (PIDEOGRAPH_LCID)(pBaseAddr + IDEO_LCID_HEADER);
  998. }
  999. pBaseAddr += IDEO_LCID_HEADER + (Num * (sizeof(IDEOGRAPH_LCID) / sizeof(WORD)));
  1000. //
  1001. // Get Expansion Information.
  1002. //
  1003. Num = *((LPDWORD)pBaseAddr);
  1004. if (Num > 0)
  1005. {
  1006. pTblPtrs->NumExpansion = Num;
  1007. pTblPtrs->pExpansion = (PEXPAND)(pBaseAddr + EXPAND_HEADER);
  1008. }
  1009. pBaseAddr += EXPAND_HEADER + (Num * (sizeof(EXPAND) / sizeof(WORD)));
  1010. //
  1011. // Get Compression Information.
  1012. //
  1013. Num = *((LPDWORD)pBaseAddr);
  1014. if (Num > 0)
  1015. {
  1016. pTblPtrs->NumCompression = Num;
  1017. pTblPtrs->pCompressHdr = (PCOMPRESS_HDR)(pBaseAddr + COMPRESS_HDR_OFFSET);
  1018. pTblPtrs->pCompression = (PCOMPRESS)(pBaseAddr + COMPRESS_HDR_OFFSET +
  1019. (Num * (sizeof(COMPRESS_HDR) /
  1020. sizeof(WORD))));
  1021. }
  1022. pCompressHdr = pTblPtrs->pCompressHdr;
  1023. pBaseAddr = (LPWORD)(pTblPtrs->pCompression) +
  1024. (pCompressHdr[Num - 1]).Offset;
  1025. pBaseAddr += (((pCompressHdr[Num - 1]).Num2) *
  1026. (sizeof(COMPRESS_2) / sizeof(WORD)));
  1027. pBaseAddr += (((pCompressHdr[Num - 1]).Num3) *
  1028. (sizeof(COMPRESS_3) / sizeof(WORD)));
  1029. //
  1030. // Get Exception Information.
  1031. //
  1032. Num = *((LPDWORD)pBaseAddr);
  1033. if (Num > 0)
  1034. {
  1035. pTblPtrs->NumException = Num;
  1036. pTblPtrs->pExceptHdr = (PEXCEPT_HDR)(pBaseAddr + EXCEPT_HDR_OFFSET);
  1037. pTblPtrs->pException = (PEXCEPT)(pBaseAddr + EXCEPT_HDR_OFFSET +
  1038. (Num * (sizeof(EXCEPT_HDR) /
  1039. sizeof(WORD))));
  1040. }
  1041. pExceptHdr = pTblPtrs->pExceptHdr;
  1042. pBaseAddr = (LPWORD)(pTblPtrs->pException) +
  1043. (pExceptHdr[Num - 1]).Offset;
  1044. pBaseAddr += (((pExceptHdr[Num - 1]).NumEntries) *
  1045. (sizeof(EXCEPT) / sizeof(WORD)));
  1046. //
  1047. // Get Multiple Weights Information.
  1048. //
  1049. Num = (DWORD)(*pBaseAddr);
  1050. if (Num > 0)
  1051. {
  1052. pTblPtrs->NumMultiWeight = Num;
  1053. pTblPtrs->pMultiWeight = (PMULTI_WT)(pBaseAddr + MULTI_WT_HEADER);
  1054. }
  1055. pBaseAddr += MULTI_WT_HEADER + (Num * (sizeof(MULTI_WT) / sizeof(WORD)));
  1056. //
  1057. // Get Jamo Index Table.
  1058. //
  1059. Num = (DWORD)(*pBaseAddr);
  1060. if (Num > 0)
  1061. {
  1062. //
  1063. // The Jamo Index table size is (Num) bytes.
  1064. //
  1065. pTblPtrs->NumJamoIndex = Num;
  1066. pTblPtrs->pJamoIndex = (PJAMO_TABLE)(pBaseAddr + JAMO_INDEX_HEADER);
  1067. }
  1068. pBaseAddr += JAMO_INDEX_HEADER + (Num * (sizeof(JAMO_TABLE) / sizeof(WORD)));
  1069. //
  1070. // Get Jamo Composition State Machine Table.
  1071. //
  1072. Num = (DWORD)(*pBaseAddr);
  1073. if (Num > 0)
  1074. {
  1075. pTblPtrs->NumJamoComposition = Num;
  1076. pTblPtrs->pJamoComposition = (PJAMO_COMPOSE_STATE)(pBaseAddr + JAMO_COMPOSITION_HEADER);
  1077. }
  1078. //
  1079. // The following line is used to move pBaseAddr to the next field.
  1080. // Uncomment it if you are adding more fields.
  1081. //
  1082. // pBaseAddr += JAMO_COMPOSITION_HEADER + (Num * (sizeof(JAMO_COMPOSE_STATE) / sizeof(WORD)));
  1083. //
  1084. // Return success.
  1085. //
  1086. return (NO_ERROR);
  1087. }
  1088. ////////////////////////////////////////////////////////////////////////////
  1089. //
  1090. // GetSortkeyFileInfo
  1091. //
  1092. // Opens and Maps a view of the section for the sortkey file. It then
  1093. // fills in the appropriate field of the global table pointers structure.
  1094. //
  1095. // 05-31-91 JulieB Created.
  1096. ////////////////////////////////////////////////////////////////////////////
  1097. ULONG GetSortkeyFileInfo(
  1098. LCID Locale,
  1099. PLOC_HASH pHashN)
  1100. {
  1101. HANDLE hSec = (HANDLE)0; // section handle
  1102. UNICODE_STRING ObSecName; // section name
  1103. LPWORD pBaseAddr; // ptr to base address of section
  1104. ULONG rc = 0L; // return code
  1105. PEXCEPT_HDR pExceptHdr; // ptr to exception header
  1106. PEXCEPT pExceptTbl; // ptr to exception table
  1107. PVOID pIdeograph; // ptr to ideograph exception table
  1108. WCHAR wszSecName[MAX_SMALL_BUF_LEN]; // Place for the section name string \
  1109. NTSTATUS Status;
  1110. //
  1111. // Make sure we're in the critical section when entering this call.
  1112. //
  1113. ASSERT(NtCurrentTeb()->ClientId.UniqueThread == gcsTblPtrs.OwningThread);
  1114. //
  1115. // Make sure the default sortkey table is loaded. If it's not, then
  1116. // we shouldn't bother to continue here since the sorting table won't
  1117. // be created properly. pHashN->pSortkey will already be NULL, so
  1118. // we don't need to set it. Return NO_ERROR here to allow kernel32
  1119. // to initialize in case this is winlogon.
  1120. //
  1121. if (pTblPtrs->pDefaultSortkey == NULL)
  1122. {
  1123. KdPrint(("NLSAPI: No Default Sorting Table Loaded.\n"));
  1124. return (NO_ERROR);
  1125. }
  1126. //
  1127. // Try to Open and Map a view of the section (read only).
  1128. //
  1129. GET_SORTKEY_SECTION_NAME(Locale, wszSecName, MAX_SMALL_BUF_LEN, &ObSecName);
  1130. if (rc = OpenSection( &hSec,
  1131. &ObSecName,
  1132. (PVOID *)&pBaseAddr,
  1133. SECTION_MAP_READ,
  1134. FALSE ))
  1135. {
  1136. //
  1137. // Open failed.
  1138. // See if any exceptions exist for given Locale ID.
  1139. //
  1140. rc = NO_ERROR;
  1141. if (!FindExceptionPointers( Locale,
  1142. &pExceptHdr,
  1143. &pExceptTbl,
  1144. &pIdeograph,
  1145. &rc ))
  1146. {
  1147. //
  1148. // No exceptions for locale, so attach the default sortkey
  1149. // table pointer to the hash node and return success.
  1150. //
  1151. pHashN->pSortkey = pTblPtrs->pDefaultSortkey;
  1152. return (NO_ERROR);
  1153. }
  1154. else
  1155. {
  1156. //
  1157. // See if an error occurred.
  1158. //
  1159. if (rc != NO_ERROR)
  1160. {
  1161. //
  1162. // This occurs if the ideograph exception file could not be
  1163. // created or mapped. Return an error in this case.
  1164. //
  1165. // return (rc);
  1166. //
  1167. // On second thought, don't return an error. Returning an
  1168. // error can cause kernel32 to not initialize (which, if this
  1169. // is winlogon, leads to an unbootable system). Let's just
  1170. // patch things up and move on.
  1171. //
  1172. // LATER -- log an error in the logfile.
  1173. //
  1174. pHashN->IfIdeographFailure = TRUE;
  1175. pHashN->pSortkey = pTblPtrs->pDefaultSortkey;
  1176. return (NO_ERROR);
  1177. }
  1178. //
  1179. // Exceptions from default sortkey table exist for the given
  1180. // locale. Need to get the correct sortkey table.
  1181. // Create a section and call the server to lock it in.
  1182. //
  1183. Status = CsrBasepNlsCreateSection( NLS_CREATE_SORT_SECTION,
  1184. Locale,
  1185. &hSec );
  1186. //
  1187. // Check return from server call.
  1188. //
  1189. rc = (ULONG)Status;
  1190. if (!NT_SUCCESS(rc))
  1191. {
  1192. if (hSec != NULL)
  1193. {
  1194. NtClose(hSec);
  1195. }
  1196. return (rc);
  1197. }
  1198. //
  1199. // Map the section for ReadWrite.
  1200. //
  1201. if (rc = MapSection( hSec,
  1202. (PVOID *)&pBaseAddr,
  1203. PAGE_READWRITE,
  1204. FALSE ))
  1205. {
  1206. NtClose(hSec);
  1207. return (rc);
  1208. }
  1209. //
  1210. // Copy the Default Sortkey Table to the New Section.
  1211. //
  1212. RtlMoveMemory( (PVOID)pBaseAddr,
  1213. (PVOID)((LPWORD)(pTblPtrs->pDefaultSortkey) -
  1214. SORTKEY_HEADER),
  1215. (ULONG)(pTblPtrs->DefaultSortkeySize.LowPart) );
  1216. //
  1217. // Copy exception information to the table.
  1218. //
  1219. CopyExceptionInfo( (PSORTKEY)(pBaseAddr + SORTKEY_HEADER),
  1220. pExceptHdr,
  1221. pExceptTbl,
  1222. pIdeograph);
  1223. //
  1224. // Write a 1 to the WORD semaphore (table may now be read).
  1225. //
  1226. *pBaseAddr = 1;
  1227. //
  1228. // Unmap the section for Write and remap it for Read.
  1229. //
  1230. if ((rc = UnMapSection(pBaseAddr)) ||
  1231. (rc = MapSection( hSec,
  1232. (PVOID *)&pBaseAddr,
  1233. PAGE_READONLY,
  1234. FALSE )))
  1235. {
  1236. NtClose(hSec);
  1237. return (rc);
  1238. }
  1239. }
  1240. }
  1241. //
  1242. // Close the section handle.
  1243. //
  1244. NtClose(hSec);
  1245. //
  1246. // Check semaphore bit in file. Make sure that the open
  1247. // succeeded AFTER all exceptions were added to the memory
  1248. // mapped section.
  1249. //
  1250. if (*pBaseAddr == 0)
  1251. {
  1252. //
  1253. // Another process is still adding the appropriate exception
  1254. // information. Must wait for its completion.
  1255. //
  1256. if (rc = WaitOnEvent(pBaseAddr))
  1257. {
  1258. UnMapSection(pBaseAddr);
  1259. return (rc);
  1260. }
  1261. }
  1262. //
  1263. // Save pointer in hash node.
  1264. //
  1265. pHashN->pSortkey = (PSORTKEY)(pBaseAddr + SORTKEY_HEADER);
  1266. //
  1267. // Return success.
  1268. //
  1269. return (NO_ERROR);
  1270. }
  1271. ////////////////////////////////////////////////////////////////////////////
  1272. //
  1273. // GetSortTablesFileInfo
  1274. //
  1275. // Stores the appropriate sort table pointers for the given locale in
  1276. // the given locale hash node.
  1277. //
  1278. // 05-31-91 JulieB Created.
  1279. ////////////////////////////////////////////////////////////////////////////
  1280. void GetSortTablesFileInfo(
  1281. LCID Locale,
  1282. PLOC_HASH pHashN)
  1283. {
  1284. DWORD ctr; // loop counter
  1285. PREVERSE_DW pRevDW; // ptr to reverse diacritic table
  1286. PDBL_COMPRESS pDblComp; // ptr to double compression table
  1287. PCOMPRESS_HDR pCompHdr; // ptr to compression header
  1288. //
  1289. // Make sure we're in the critical section when entering this call.
  1290. //
  1291. ASSERT(NtCurrentTeb()->ClientId.UniqueThread == gcsTblPtrs.OwningThread);
  1292. //
  1293. // Check for Reverse Diacritic Locale.
  1294. //
  1295. pRevDW = pTblPtrs->pReverseDW;
  1296. for (ctr = pTblPtrs->NumReverseDW; ctr > 0; ctr--, pRevDW++)
  1297. {
  1298. if (*pRevDW == (DWORD)Locale)
  1299. {
  1300. pHashN->IfReverseDW = TRUE;
  1301. break;
  1302. }
  1303. }
  1304. //
  1305. // Check for Compression.
  1306. //
  1307. pCompHdr = pTblPtrs->pCompressHdr;
  1308. for (ctr = pTblPtrs->NumCompression; ctr > 0; ctr--, pCompHdr++)
  1309. {
  1310. if (pCompHdr->Locale == (DWORD)Locale)
  1311. {
  1312. pHashN->IfCompression = TRUE;
  1313. pHashN->pCompHdr = pCompHdr;
  1314. if (pCompHdr->Num2 > 0)
  1315. {
  1316. pHashN->pCompress2 = (PCOMPRESS_2)
  1317. (((LPWORD)(pTblPtrs->pCompression)) +
  1318. (pCompHdr->Offset));
  1319. }
  1320. if (pCompHdr->Num3 > 0)
  1321. {
  1322. pHashN->pCompress3 = (PCOMPRESS_3)
  1323. (((LPWORD)(pTblPtrs->pCompression)) +
  1324. (pCompHdr->Offset) +
  1325. (pCompHdr->Num2 *
  1326. (sizeof(COMPRESS_2) / sizeof(WORD))));
  1327. }
  1328. break;
  1329. }
  1330. }
  1331. //
  1332. // Check for Double Compression.
  1333. //
  1334. if (pHashN->IfCompression)
  1335. {
  1336. pDblComp = pTblPtrs->pDblCompression;
  1337. for (ctr = pTblPtrs->NumDblCompression; ctr > 0; ctr--, pDblComp++)
  1338. {
  1339. if (*pDblComp == (DWORD)Locale)
  1340. {
  1341. pHashN->IfDblCompression = TRUE;
  1342. break;
  1343. }
  1344. }
  1345. }
  1346. }
  1347. ////////////////////////////////////////////////////////////////////////////
  1348. //
  1349. // LoadCodePageAsDLL
  1350. //
  1351. // Try to load a code page as a DLL. If succeeded, the CodePage procedure
  1352. // is set.
  1353. //
  1354. // 05-27-99 SamerA Created.
  1355. ////////////////////////////////////////////////////////////////////////////
  1356. ULONG LoadCodePageAsDLL(
  1357. UINT CodePage,
  1358. LPFN_CP_PROC *ppfnCPProc)
  1359. {
  1360. WCHAR pDllName[MAX_PATH_LEN]; // ptr to DLL name
  1361. HANDLE hModCPDll; // module handle of code page DLL
  1362. ULONG rc = ERROR_INVALID_PARAMETER; // return code
  1363. UINT ErrorMode; // error mode
  1364. //
  1365. // Get the DLL name to load.
  1366. //
  1367. pDllName[0] = 0;
  1368. *ppfnCPProc = NULL;
  1369. if (NO_ERROR == GetCodePageDLLPathName(CodePage, pDllName, MAX_PATH_LEN) &&
  1370. NlsIsDll(pDllName))
  1371. {
  1372. //
  1373. // Load the DLL and get the procedure address.
  1374. // Turn off hard error popups.
  1375. //
  1376. ErrorMode = SetErrorMode(SEM_NOERROR);
  1377. SetErrorMode(SEM_NOERROR | ErrorMode);
  1378. hModCPDll = LoadLibrary(pDllName);
  1379. SetErrorMode(ErrorMode);
  1380. if (hModCPDll)
  1381. {
  1382. *ppfnCPProc =
  1383. (LPFN_CP_PROC)GetProcAddress( hModCPDll,
  1384. NLS_CP_DLL_PROC_NAME );
  1385. }
  1386. if (*ppfnCPProc == NULL)
  1387. {
  1388. if (hModCPDll)
  1389. {
  1390. rc = TYPE_E_DLLFUNCTIONNOTFOUND;
  1391. FreeLibrary(hModCPDll);
  1392. }
  1393. else
  1394. {
  1395. rc = TYPE_E_CANTLOADLIBRARY;
  1396. }
  1397. }
  1398. else
  1399. {
  1400. rc = NO_ERROR;
  1401. }
  1402. }
  1403. return (rc);
  1404. }
  1405. ////////////////////////////////////////////////////////////////////////////
  1406. //
  1407. // GetCodePageFileInfo
  1408. //
  1409. // Opens and Maps a view of the section for the given code page. It then
  1410. // creates and inserts a hash node into the global CP hash table.
  1411. //
  1412. // If the section cannot be opened, it then queries the registry to see if
  1413. // the information has been added since the initialization of the DLL. If
  1414. // so, then it creates the section and then opens and maps a view of it.
  1415. //
  1416. // 05-31-91 JulieB Created.
  1417. ////////////////////////////////////////////////////////////////////////////
  1418. ULONG GetCodePageFileInfo(
  1419. UINT CodePage,
  1420. PCP_HASH *ppNode)
  1421. {
  1422. HANDLE hSec = (HANDLE)0; // section handle
  1423. UNICODE_STRING ObSecName; // section name
  1424. LPWORD pBaseAddr = NULL; // ptr to base address of section
  1425. ULONG rc = 0L; // return code
  1426. BOOL IsDLL; // true if dll instead of data file
  1427. LPFN_CP_PROC pfnCPProc; // Code Page DLL Procedure
  1428. WCHAR wszSecName[MAX_SMALL_BUF_LEN]; // Place for the section name string \
  1429. //
  1430. // Make sure we're in the critical section when entering this call.
  1431. //
  1432. ASSERT(NtCurrentTeb()->ClientId.UniqueThread == gcsTblPtrs.OwningThread);
  1433. //
  1434. // See if we're dealing with a DLL or an NLS data file.
  1435. //
  1436. IsDLL = ((CodePage >= NLS_CP_DLL_RANGE) &&
  1437. (CodePage < NLS_CP_ALGORITHM_RANGE));
  1438. if (IsDLL)
  1439. {
  1440. //
  1441. // Try loading the codepage DLL
  1442. //
  1443. ULONG _rc = LoadCodePageAsDLL(CodePage, &pfnCPProc);
  1444. if (_rc)
  1445. {
  1446. if (ERROR_INVALID_PARAMETER == _rc)
  1447. {
  1448. //
  1449. // Not a valid DLL, try loading it as a normal data file
  1450. //
  1451. IsDLL = FALSE;
  1452. }
  1453. else
  1454. {
  1455. //
  1456. // Failed to load the DLL or can't find the function entry
  1457. // Return the error code
  1458. //
  1459. return (rc);
  1460. }
  1461. }
  1462. }
  1463. if (!IsDLL)
  1464. {
  1465. //
  1466. // Open and Map a view of the section.
  1467. //
  1468. GET_CP_SECTION_NAME(CodePage, wszSecName, MAX_SMALL_BUF_LEN, &ObSecName);
  1469. rc = OpenSection( &hSec,
  1470. &ObSecName,
  1471. (PVOID *)&pBaseAddr,
  1472. SECTION_MAP_READ,
  1473. TRUE );
  1474. if (!NT_SUCCESS(rc))
  1475. {
  1476. //
  1477. // Open failed, so try to create the section.
  1478. // If the creation is successful, the section will be mapped
  1479. // to the current process.
  1480. //
  1481. rc = CsrBasepNlsCreateSection(NLS_CREATE_CODEPAGE_SECTION, CodePage,
  1482. &hSec );
  1483. if (NT_SUCCESS(rc))
  1484. {
  1485. rc = MapSection( hSec,
  1486. &pBaseAddr,
  1487. PAGE_READONLY,
  1488. TRUE ); // Close handle (even if fail)
  1489. }
  1490. if (!NT_SUCCESS(rc))
  1491. {
  1492. //
  1493. // Allow the default ACP and default OEMCP to work if
  1494. // it's only the registry that is corrupt. If there is
  1495. // still an error, return the error code that was returned
  1496. // from the OpenSection call.
  1497. //
  1498. if (CodePage == NLS_DEFAULT_ACP)
  1499. {
  1500. //
  1501. // Create the default ACP section.
  1502. //
  1503. if (!NT_SUCCESS(CsrBasepNlsCreateSection(NLS_CREATE_SECTION_DEFAULT_ACP, 0,
  1504. &hSec )))
  1505. {
  1506. return (rc);
  1507. }
  1508. else
  1509. {
  1510. //
  1511. // Map the section.
  1512. //
  1513. if (!NT_SUCCESS(MapSection( hSec,
  1514. (PVOID *)&pBaseAddr,
  1515. PAGE_READONLY,
  1516. TRUE )))
  1517. {
  1518. return (rc);
  1519. }
  1520. KdPrint(("NLSAPI: Registry is corrupt - Default ACP.\n"));
  1521. }
  1522. }
  1523. else if (CodePage == NLS_DEFAULT_OEMCP)
  1524. {
  1525. //
  1526. // Create the default OEMCP section.
  1527. //
  1528. if (!NT_SUCCESS(CsrBasepNlsCreateSection( NLS_CREATE_SECTION_DEFAULT_OEMCP, 0,
  1529. &hSec )))
  1530. {
  1531. return (rc);
  1532. }
  1533. else
  1534. {
  1535. //
  1536. // Map the section.
  1537. //
  1538. if (!NT_SUCCESS(MapSection( hSec,
  1539. (PVOID *)&pBaseAddr,
  1540. PAGE_READONLY,
  1541. TRUE )))
  1542. {
  1543. return (rc);
  1544. }
  1545. KdPrint(("NLSAPI: Registry is corrupt - Default OEMCP.\n"));
  1546. }
  1547. }
  1548. else
  1549. {
  1550. //
  1551. // Return the error code that was returned from the
  1552. // OpenSection call.
  1553. //
  1554. return (rc);
  1555. }
  1556. }
  1557. }
  1558. }
  1559. //
  1560. // Make the hash node and return the result.
  1561. //
  1562. return (MakeCPHashNode( CodePage,
  1563. pBaseAddr,
  1564. ppNode,
  1565. IsDLL,
  1566. pfnCPProc ));
  1567. }
  1568. ////////////////////////////////////////////////////////////////////////////
  1569. //
  1570. // GetLanguageFileInfo
  1571. //
  1572. // Opens and Maps a view of the section for the casing tables and sorting
  1573. // tables for the given locale.
  1574. //
  1575. // If the section cannot be opened, it then queries the registry to see if
  1576. // the information has been added since the initialization of the DLL. If
  1577. // so, then it creates the section and then opens and maps a view of it.
  1578. //
  1579. // 05-31-91 JulieB Created.
  1580. ////////////////////////////////////////////////////////////////////////////
  1581. ULONG GetLanguageFileInfo(
  1582. LCID Locale,
  1583. PLOC_HASH *ppNode,
  1584. BOOLEAN fCreateNode,
  1585. DWORD dwFlags)
  1586. {
  1587. LPWORD pBaseAddr = NULL; // ptr to base address of section
  1588. MEMORY_BASIC_INFORMATION MemoryBasicInfo;
  1589. //
  1590. // Make sure we're in the critical section when entering this call.
  1591. //
  1592. ASSERT(NtCurrentTeb()->ClientId.UniqueThread == gcsTblPtrs.OwningThread);
  1593. //
  1594. // See if the default language table has been stored yet.
  1595. //
  1596. if (pTblPtrs->pDefaultLanguage == NULL)
  1597. {
  1598. //
  1599. // Save the default language table and its size in the
  1600. // table pointers structure.
  1601. //
  1602. pTblPtrs->pDefaultLanguage = NtCurrentPeb()->UnicodeCaseTableData;
  1603. NtQueryVirtualMemory( NtCurrentProcess(),
  1604. pTblPtrs->pDefaultLanguage,
  1605. MemoryBasicInformation,
  1606. &MemoryBasicInfo,
  1607. sizeof(MEMORY_BASIC_INFORMATION),
  1608. NULL );
  1609. pTblPtrs->LinguistLangSize.QuadPart = MemoryBasicInfo.RegionSize;
  1610. ASSERT(MemoryBasicInfo.RegionSize > 0);
  1611. }
  1612. //
  1613. // See if we should load the culturally correct language table.
  1614. //
  1615. if (dwFlags)
  1616. {
  1617. if (pTblPtrs->pLangException == NULL)
  1618. {
  1619. GetLanguageExceptionInfo();
  1620. }
  1621. //
  1622. // Get the default linguistic language table for the given locale.
  1623. //
  1624. pBaseAddr = GetLinguisticLanguageInfo(Locale);
  1625. }
  1626. //
  1627. // Get the casing table and sorting table pointers.
  1628. //
  1629. return (MakeLangHashNode( Locale,
  1630. pBaseAddr,
  1631. ppNode,
  1632. fCreateNode ));
  1633. }
  1634. ////////////////////////////////////////////////////////////////////////////
  1635. //
  1636. // GetLocaleFileInfo
  1637. //
  1638. // Opens and Maps a view of the section for the given locale. It then
  1639. // creates and inserts a hash node into the global LOCALE hash table.
  1640. //
  1641. // If the section cannot be opened, it then queries the registry to see if
  1642. // the information has been added since the initialization of the DLL. If
  1643. // so, then it creates the section and then opens and maps a view of it.
  1644. //
  1645. // 05-31-91 JulieB Created.
  1646. ////////////////////////////////////////////////////////////////////////////
  1647. ULONG GetLocaleFileInfo(
  1648. LCID Locale,
  1649. PLOC_HASH *ppNode,
  1650. BOOLEAN fCreateNode)
  1651. {
  1652. HANDLE hSec = (HANDLE)0; // section handle
  1653. UNICODE_STRING ObSecName; // section name
  1654. LPWORD pBaseAddr; // ptr to base address of section
  1655. ULONG rc = 0L; // return code
  1656. //
  1657. // Make sure we're in the critical section when entering this call.
  1658. //
  1659. ASSERT(NtCurrentTeb()->ClientId.UniqueThread == gcsTblPtrs.OwningThread);
  1660. //
  1661. // Open and Map a view of the section if it hasn't been done yet.
  1662. //
  1663. if ((pBaseAddr = pTblPtrs->pLocaleInfo) == NULL)
  1664. {
  1665. //
  1666. // Get the locale file section pointer.
  1667. //
  1668. ObSecName.Buffer = NLS_SECTION_LOCALE;
  1669. ObSecName.Length = sizeof (NLS_SECTION_LOCALE) - sizeof (WCHAR);
  1670. ObSecName.MaximumLength = ObSecName.Length;
  1671. if (rc = OpenSection( &hSec,
  1672. &ObSecName,
  1673. (PVOID *)&pBaseAddr,
  1674. SECTION_MAP_READ,
  1675. TRUE ))
  1676. {
  1677. return (rc);
  1678. }
  1679. //
  1680. // Store pointer to locale file and calendar info in table
  1681. // structure.
  1682. //
  1683. pTblPtrs->pLocaleInfo = pBaseAddr;
  1684. pTblPtrs->NumCalendars = ((PLOC_CAL_HDR)pBaseAddr)->NumCalendars;
  1685. pTblPtrs->pCalendarInfo = pBaseAddr +
  1686. ((PLOC_CAL_HDR)pBaseAddr)->CalOffset;
  1687. }
  1688. //
  1689. // Make the hash node and return the result.
  1690. //
  1691. return (MakeLocHashNode( Locale,
  1692. pBaseAddr,
  1693. ppNode,
  1694. fCreateNode ));
  1695. }
  1696. ////////////////////////////////////////////////////////////////////////////
  1697. //
  1698. // MakeCPHashNode
  1699. //
  1700. // Creates the hash node for the code page and assigns the fields of the
  1701. // hash node to point at the appropriate places in the file.
  1702. //
  1703. // 05-31-91 JulieB Created.
  1704. ////////////////////////////////////////////////////////////////////////////
  1705. ULONG MakeCPHashNode(
  1706. UINT CodePage,
  1707. LPWORD pBaseAddr,
  1708. PCP_HASH *ppNode,
  1709. BOOL IsDLL,
  1710. LPFN_CP_PROC pfnCPProc)
  1711. {
  1712. PCP_HASH pHashN; // ptr to CP hash node
  1713. WORD offMB; // offset to MB table
  1714. WORD offWC; // offset to WC table
  1715. PGLYPH_TABLE pGlyph; // ptr to glyph table info
  1716. PDBCS_RANGE pRange; // ptr to DBCS range
  1717. //
  1718. // Allocate CP_HASH structure and fill in the CodePage value.
  1719. //
  1720. CREATE_CODEPAGE_HASH_NODE(CodePage, pHashN);
  1721. //
  1722. // See if we're dealing with a DLL or an NLS data file.
  1723. //
  1724. if (IsDLL)
  1725. {
  1726. if (pfnCPProc == NULL)
  1727. {
  1728. NLS_FREE_MEM(pHashN);
  1729. return (ERROR_INVALID_PARAMETER);
  1730. }
  1731. pHashN->pfnCPProc = pfnCPProc;
  1732. }
  1733. else
  1734. {
  1735. //
  1736. // Get the offsets.
  1737. //
  1738. offMB = pBaseAddr[0];
  1739. offWC = offMB + pBaseAddr[offMB];
  1740. //
  1741. // Attach CP Info to CP hash node.
  1742. //
  1743. pHashN->pCPInfo = (PCP_TABLE)(pBaseAddr + CP_HEADER);
  1744. //
  1745. // Attach MB table to CP hash node.
  1746. //
  1747. pHashN->pMBTbl = pBaseAddr + offMB + MB_HEADER;
  1748. //
  1749. // Attach Glyph table to CP hash node (if it exists).
  1750. // Also, set the pointer to the DBCS ranges based on whether or
  1751. // not the GLYPH table is present.
  1752. //
  1753. pGlyph = pHashN->pMBTbl + MB_TBL_SIZE;
  1754. if (pGlyph[0] != 0)
  1755. {
  1756. pHashN->pGlyphTbl = pGlyph + GLYPH_HEADER;
  1757. pRange = pHashN->pDBCSRanges = pHashN->pGlyphTbl + GLYPH_TBL_SIZE;
  1758. }
  1759. else
  1760. {
  1761. pRange = pHashN->pDBCSRanges = pGlyph + GLYPH_HEADER;
  1762. }
  1763. //
  1764. // Attach DBCS information to CP hash node.
  1765. //
  1766. if (pRange[0] > 0)
  1767. {
  1768. //
  1769. // Set the pointer to the offsets section.
  1770. //
  1771. pHashN->pDBCSOffsets = pRange + DBCS_HEADER;
  1772. }
  1773. //
  1774. // Attach WC table to CP hash node.
  1775. //
  1776. pHashN->pWC = pBaseAddr + offWC + WC_HEADER;
  1777. }
  1778. //
  1779. // Insert hash node into hash table.
  1780. //
  1781. INSERT_CP_HASH_NODE(pHashN, pBaseAddr);
  1782. //
  1783. // Save the pointer to the hash node.
  1784. //
  1785. if (ppNode != NULL)
  1786. {
  1787. *ppNode = pHashN;
  1788. }
  1789. //
  1790. // Return success.
  1791. //
  1792. return (NO_ERROR);
  1793. }
  1794. ////////////////////////////////////////////////////////////////////////////
  1795. //
  1796. // MakeLangHashNode
  1797. //
  1798. // Gets the pointers to the casing tables and the sorting tables and
  1799. // stores them in the locale hash node given.
  1800. //
  1801. // If fCreateNode is FALSE, then *ppNode should contain a valid pointer
  1802. // to a LOC hash node. Also, the table critical section must be entered
  1803. // before calling this routine.
  1804. //
  1805. // 05-31-91 JulieB Created.
  1806. ////////////////////////////////////////////////////////////////////////////
  1807. ULONG MakeLangHashNode(
  1808. LCID Locale,
  1809. LPWORD pBaseAddr,
  1810. PLOC_HASH *ppNode,
  1811. BOOLEAN fCreateNode)
  1812. {
  1813. LPWORD pBaseDefault; // ptr to default language section
  1814. PLOC_HASH pHashN; // ptr to LOC hash node
  1815. ULONG rc = 0L; // return code
  1816. //
  1817. // If fCreateNode is TRUE, then allocate LOC_HASH structure.
  1818. //
  1819. if (fCreateNode)
  1820. {
  1821. CREATE_LOCALE_HASH_NODE(Locale, pHashN);
  1822. }
  1823. else
  1824. {
  1825. pHashN = *ppNode;
  1826. }
  1827. //
  1828. // See if the sorting tables still need to be attached.
  1829. //
  1830. if (pHashN->pSortkey == NULL)
  1831. {
  1832. //
  1833. // Get the sortkey table and attach it to the hash node.
  1834. //
  1835. if (rc = GetSortkeyFileInfo(Locale, pHashN))
  1836. {
  1837. if (fCreateNode)
  1838. {
  1839. NLS_FREE_MEM(pHashN);
  1840. }
  1841. return (rc);
  1842. }
  1843. //
  1844. // Get the appropriate sorting tables for the locale.
  1845. //
  1846. GetSortTablesFileInfo(Locale, pHashN);
  1847. }
  1848. //
  1849. // See if the default casing tables still need to be attached.
  1850. //
  1851. if (!EXIST_LANGUAGE_INFO(pHashN))
  1852. {
  1853. //
  1854. // Get the pointer to the base of the default table.
  1855. //
  1856. pBaseDefault = pTblPtrs->pDefaultLanguage;
  1857. //
  1858. // Attach the UPPERCASE table to the hash node.
  1859. //
  1860. pHashN->pUpperCase = pBaseDefault + LANG_HEADER + UP_HEADER;
  1861. //
  1862. // Attach the LOWERCASE table to the hash node.
  1863. //
  1864. // This value must be set LAST, since this is the pointer that
  1865. // is checked to see that the language information has been
  1866. // initialized.
  1867. //
  1868. pHashN->pLowerCase = pBaseDefault + LANG_HEADER +
  1869. pBaseDefault[LANG_HEADER] + LO_HEADER;
  1870. }
  1871. //
  1872. // See if there is a linguistic table to attach.
  1873. //
  1874. if (pBaseAddr)
  1875. {
  1876. //
  1877. // Attach the UPPERCASE Linguistic table to the hash node.
  1878. //
  1879. pHashN->pUpperLinguist = pBaseAddr + LANG_HEADER + UP_HEADER;
  1880. //
  1881. // Attach the LOWERCASE Linguistic table to the hash node.
  1882. //
  1883. // This value must be set LAST, since this is the pointer that
  1884. // is checked to see that the language information has been
  1885. // initialized.
  1886. //
  1887. pHashN->pLowerLinguist = pBaseAddr + LANG_HEADER +
  1888. pBaseAddr[LANG_HEADER] + LO_HEADER;
  1889. }
  1890. //
  1891. // If fCreateNode is TRUE, then insert hash node and save pointer.
  1892. //
  1893. if (fCreateNode)
  1894. {
  1895. //
  1896. // Insert LOC hash node into hash table.
  1897. //
  1898. INSERT_LOC_HASH_NODE(pHashN, pBaseAddr);
  1899. //
  1900. // Save the pointer to the hash node.
  1901. //
  1902. if (ppNode != NULL)
  1903. {
  1904. *ppNode = pHashN;
  1905. }
  1906. }
  1907. //
  1908. // Return success.
  1909. //
  1910. return (NO_ERROR);
  1911. }
  1912. ////////////////////////////////////////////////////////////////////////////
  1913. //
  1914. // MakeLocHashNode
  1915. //
  1916. // Gets the pointers to the locale tables and stores them in the locale
  1917. // hash node given.
  1918. //
  1919. // NOTE: If a critical section is needed to touch pHashN, then the
  1920. // critical section must be entered before calling this routine.
  1921. //
  1922. // 05-31-91 JulieB Created.
  1923. ////////////////////////////////////////////////////////////////////////////
  1924. ULONG MakeLocHashNode(
  1925. LCID Locale,
  1926. LPWORD pBaseAddr,
  1927. PLOC_HASH *ppNode,
  1928. BOOLEAN fCreateNode)
  1929. {
  1930. LANGID Language; // language id
  1931. PLOC_HASH pHashN; // ptr to LOC hash node
  1932. DWORD Num; // total number of locales
  1933. PLOCALE_HDR pFileHdr; // ptr to locale header entry
  1934. ULONG rc = 0L; // return code
  1935. //
  1936. // Save the language id.
  1937. //
  1938. Language = LANGIDFROMLCID(Locale);
  1939. //
  1940. // Search for the right locale id information.
  1941. //
  1942. Num = ((PLOC_CAL_HDR)pBaseAddr)->NumLocales;
  1943. pFileHdr = (PLOCALE_HDR)(pBaseAddr + LOCALE_HDR_OFFSET);
  1944. for (; (Num != 0) && (pFileHdr->Locale != Language); Num--, pFileHdr++)
  1945. ;
  1946. //
  1947. // See if the locale was found in the file.
  1948. //
  1949. if (Num != 0)
  1950. {
  1951. //
  1952. // Locale id was found, so increment the pointer to point at
  1953. // the beginning of the locale information.
  1954. //
  1955. pBaseAddr += pFileHdr->Offset;
  1956. }
  1957. else
  1958. {
  1959. //
  1960. // Return an error. The given locale is not supported.
  1961. //
  1962. return (ERROR_INVALID_PARAMETER);
  1963. }
  1964. //
  1965. // If fCreateNode is TRUE, then allocate LOC_HASH structure.
  1966. //
  1967. if (fCreateNode)
  1968. {
  1969. CREATE_LOCALE_HASH_NODE(Locale, pHashN);
  1970. }
  1971. else
  1972. {
  1973. pHashN = *ppNode;
  1974. }
  1975. //
  1976. // Attach Information to structure.
  1977. //
  1978. // The pLocaleFixed value must be set LAST, since this is the pointer
  1979. // that is checked to see that the locale information has been
  1980. // initialized.
  1981. //
  1982. pHashN->pLocaleHdr = (PLOCALE_VAR)pBaseAddr;
  1983. pHashN->pLocaleFixed = (PLOCALE_FIXED)(pBaseAddr +
  1984. (sizeof(LOCALE_VAR) / sizeof(WORD)));
  1985. //
  1986. // If fCreateNode is TRUE, then insert hash node and save pointer.
  1987. //
  1988. if (fCreateNode)
  1989. {
  1990. //
  1991. // Insert LOC hash node into hash table.
  1992. //
  1993. INSERT_LOC_HASH_NODE(pHashN, pBaseAddr);
  1994. //
  1995. // Save the pointer to the hash node.
  1996. //
  1997. if (ppNode != NULL)
  1998. {
  1999. *ppNode = pHashN;
  2000. }
  2001. }
  2002. //
  2003. // Return success.
  2004. //
  2005. return (NO_ERROR);
  2006. }
  2007. ////////////////////////////////////////////////////////////////////////////
  2008. //
  2009. // GetCPHashNode
  2010. //
  2011. // Returns a pointer to the appropriate CP hash node given the codepage.
  2012. // If no table could be found for the given codepage, NULL is returned.
  2013. //
  2014. // 05-31-91 JulieB Created.
  2015. ////////////////////////////////////////////////////////////////////////////
  2016. PCP_HASH FASTCALL GetCPHashNode(
  2017. UINT CodePage)
  2018. {
  2019. PCP_HASH pHashN; // ptr to CP hash node
  2020. //
  2021. // Get hash node.
  2022. //
  2023. FIND_CP_HASH_NODE(CodePage, pHashN);
  2024. //
  2025. // If the hash node does not exist, try to get the tables
  2026. // from the appropriate data file.
  2027. //
  2028. // NOTE: No need to check error code from GetCodePageFileInfo,
  2029. // because pHashN is not touched if there was an
  2030. // error. Thus, pHashN will still be NULL, and an
  2031. // "error" will be returned from this routine.
  2032. //
  2033. if (pHashN == NULL)
  2034. {
  2035. //
  2036. // Hash node does NOT exist.
  2037. //
  2038. RtlEnterCriticalSection(&gcsTblPtrs);
  2039. FIND_CP_HASH_NODE(CodePage, pHashN);
  2040. if (pHashN == NULL)
  2041. {
  2042. GetCodePageFileInfo(CodePage, &pHashN);
  2043. }
  2044. RtlLeaveCriticalSection(&gcsTblPtrs);
  2045. }
  2046. //
  2047. // Return pointer to hash node.
  2048. //
  2049. return (pHashN);
  2050. }
  2051. ////////////////////////////////////////////////////////////////////////////
  2052. //
  2053. // GetLangHashNode
  2054. //
  2055. // Returns a pointer to the appropriate LOC hash node given the locale.
  2056. // If no table could be found for the given locale, NULL is returned.
  2057. //
  2058. // 05-31-91 JulieB Created.
  2059. ////////////////////////////////////////////////////////////////////////////
  2060. PLOC_HASH FASTCALL GetLangHashNode(
  2061. LCID Locale,
  2062. DWORD dwFlags)
  2063. {
  2064. PLOC_HASH pHashN; // ptr to LOC hash node
  2065. //
  2066. // Get hash node.
  2067. //
  2068. FIND_LOCALE_HASH_NODE(Locale, pHashN);
  2069. //
  2070. // If the hash node does not exist, try to get the tables
  2071. // from the appropriate data file.
  2072. //
  2073. // NOTE: No need to check error code from GetLanguageFileInfo,
  2074. // because pHashN is not touched if there was an
  2075. // error. Thus, pHashN will still be NULL, and an
  2076. // "error" will be returned from this routine.
  2077. //
  2078. if (pHashN == NULL)
  2079. {
  2080. //
  2081. // If a sort id exists, make sure it's valid.
  2082. //
  2083. if (SORTIDFROMLCID(Locale))
  2084. {
  2085. if (!IsValidSortId(Locale))
  2086. {
  2087. return (NULL);
  2088. }
  2089. }
  2090. //
  2091. // Hash node does NOT exist.
  2092. //
  2093. RtlEnterCriticalSection(&gcsTblPtrs);
  2094. FIND_LOCALE_HASH_NODE(Locale, pHashN);
  2095. if (pHashN == NULL)
  2096. {
  2097. //
  2098. // Hash node still does NOT exist.
  2099. //
  2100. GetLanguageFileInfo(Locale, &pHashN, TRUE, dwFlags);
  2101. RtlLeaveCriticalSection(&gcsTblPtrs);
  2102. return (pHashN);
  2103. }
  2104. RtlLeaveCriticalSection(&gcsTblPtrs);
  2105. }
  2106. //
  2107. // Hash node DOES exist.
  2108. //
  2109. if (!EXIST_LANGUAGE_INFO(pHashN) ||
  2110. ((dwFlags != 0) && !EXIST_LINGUIST_LANGUAGE_INFO(pHashN)))
  2111. {
  2112. //
  2113. // Casing tables and sorting tables not yet stored in
  2114. // hash node.
  2115. //
  2116. RtlEnterCriticalSection(&gcsTblPtrs);
  2117. if (!EXIST_LANGUAGE_INFO(pHashN) ||
  2118. ((dwFlags != 0) && !EXIST_LINGUIST_LANGUAGE_INFO(pHashN)))
  2119. {
  2120. if (GetLanguageFileInfo(Locale, &pHashN, FALSE, dwFlags))
  2121. {
  2122. RtlLeaveCriticalSection(&gcsTblPtrs);
  2123. return (NULL);
  2124. }
  2125. }
  2126. RtlLeaveCriticalSection(&gcsTblPtrs);
  2127. }
  2128. //
  2129. // Return pointer to hash node.
  2130. //
  2131. return (pHashN);
  2132. }
  2133. ////////////////////////////////////////////////////////////////////////////
  2134. //
  2135. // GetLocHashNode
  2136. //
  2137. // Returns a pointer to the appropriate LOC hash node given the locale.
  2138. // If no table could be found for the given locale, NULL is returned.
  2139. //
  2140. // 05-31-91 JulieB Created.
  2141. ////////////////////////////////////////////////////////////////////////////
  2142. PLOC_HASH FASTCALL GetLocHashNode(
  2143. LCID Locale)
  2144. {
  2145. PLOC_HASH pHashN; // ptr to LOC hash node
  2146. //
  2147. // Get hash node.
  2148. //
  2149. FIND_LOCALE_HASH_NODE(Locale, pHashN);
  2150. //
  2151. // If the hash node does not exist, try to get the table
  2152. // from locale.nls.
  2153. //
  2154. // NOTE: No need to check error code from GetLocaleFileInfo,
  2155. // because pHashN is not touched if there was an
  2156. // error. Thus, pHashN will still be NULL, and an
  2157. // "error" will be returned from this routine.
  2158. //
  2159. if (pHashN == NULL)
  2160. {
  2161. //
  2162. // If a sort id exists, make sure it's valid.
  2163. //
  2164. if (SORTIDFROMLCID(Locale))
  2165. {
  2166. if (!IsValidSortId(Locale))
  2167. {
  2168. return (NULL);
  2169. }
  2170. }
  2171. //
  2172. // Hash node does NOT exist.
  2173. //
  2174. RtlEnterCriticalSection(&gcsTblPtrs);
  2175. FIND_LOCALE_HASH_NODE(Locale, pHashN);
  2176. if (pHashN == NULL)
  2177. {
  2178. //
  2179. // Hash node still does NOT exist.
  2180. //
  2181. GetLocaleFileInfo(Locale, &pHashN, TRUE);
  2182. RtlLeaveCriticalSection(&gcsTblPtrs);
  2183. return (pHashN);
  2184. }
  2185. RtlLeaveCriticalSection(&gcsTblPtrs);
  2186. }
  2187. //
  2188. // Hash node DOES exist.
  2189. //
  2190. if (!EXIST_LOCALE_INFO(pHashN))
  2191. {
  2192. //
  2193. // Locale tables not yet stored in hash node.
  2194. //
  2195. RtlEnterCriticalSection(&gcsTblPtrs);
  2196. if (!EXIST_LOCALE_INFO(pHashN))
  2197. {
  2198. if (GetLocaleFileInfo(Locale, &pHashN, FALSE))
  2199. {
  2200. RtlLeaveCriticalSection(&gcsTblPtrs);
  2201. return (NULL);
  2202. }
  2203. }
  2204. RtlLeaveCriticalSection(&gcsTblPtrs);
  2205. }
  2206. //
  2207. // Return pointer to hash node.
  2208. //
  2209. return (pHashN);
  2210. }
  2211. ////////////////////////////////////////////////////////////////////////////
  2212. //
  2213. // GetCalendar
  2214. //
  2215. // Gets the pointer to the specific calendar table. It stores it in the
  2216. // calendar information array in the global table pointers structure if it
  2217. // was not done yet.
  2218. //
  2219. // 05-31-91 JulieB Created.
  2220. ////////////////////////////////////////////////////////////////////////////
  2221. ULONG GetCalendar(
  2222. CALID Calendar,
  2223. PCAL_INFO *ppCalInfo)
  2224. {
  2225. PCALENDAR_HDR pCalHdr; // ptr to beginning of calendar header
  2226. DWORD Num; // total number of calendars
  2227. //
  2228. // Get number of calendars.
  2229. //
  2230. Num = pTblPtrs->NumCalendars;
  2231. //
  2232. // Make sure calendar id is within the appropriate range.
  2233. //
  2234. if (Calendar > Num)
  2235. {
  2236. return (ERROR_INVALID_PARAMETER);
  2237. }
  2238. //
  2239. // Check to see if calendar info has already been found.
  2240. //
  2241. if ((*ppCalInfo = (pTblPtrs->pCalTbl)[Calendar]) != NULL)
  2242. {
  2243. //
  2244. // Return success. Calendar info was found.
  2245. //
  2246. return (NO_ERROR);
  2247. }
  2248. RtlEnterCriticalSection(&gcsTblPtrs);
  2249. if ((*ppCalInfo = (pTblPtrs->pCalTbl)[Calendar]) != NULL)
  2250. {
  2251. //
  2252. // Return success. Calendar info was found.
  2253. //
  2254. RtlLeaveCriticalSection(&gcsTblPtrs);
  2255. return (NO_ERROR);
  2256. }
  2257. //
  2258. // Search for the appropriate calendar id information.
  2259. //
  2260. pCalHdr = (PCALENDAR_HDR)(pTblPtrs->pCalendarInfo);
  2261. while ((Num != 0) && (pCalHdr->Calendar != Calendar))
  2262. {
  2263. Num--;
  2264. pCalHdr++;
  2265. }
  2266. //
  2267. // See if the calendar was found in the file.
  2268. //
  2269. if (Num != 0)
  2270. {
  2271. //
  2272. // Calendar id was found.
  2273. //
  2274. // Store the pointer to the beginning of the calendar info
  2275. // in the calendar table array.
  2276. //
  2277. *ppCalInfo = (PCAL_INFO)((LPWORD)(pTblPtrs->pCalendarInfo) +
  2278. pCalHdr->Offset);
  2279. (pTblPtrs->pCalTbl)[Calendar] = *ppCalInfo;
  2280. //
  2281. // Return success. Calendar info was found.
  2282. //
  2283. RtlLeaveCriticalSection(&gcsTblPtrs);
  2284. return (NO_ERROR);
  2285. }
  2286. RtlLeaveCriticalSection(&gcsTblPtrs);
  2287. //
  2288. // Calendar id was not found in the locale.nls file.
  2289. // Return an error. The given calendar is not supported.
  2290. //
  2291. return (ERROR_INVALID_PARAMETER);
  2292. }
  2293. //-------------------------------------------------------------------------//
  2294. // INTERNAL ROUTINES //
  2295. //-------------------------------------------------------------------------//
  2296. ////////////////////////////////////////////////////////////////////////////
  2297. //
  2298. // IsValidSortId
  2299. //
  2300. // Checks to see if the given locale has a valid sort id.
  2301. //
  2302. // 11-15-96 JulieB Created.
  2303. ////////////////////////////////////////////////////////////////////////////
  2304. BOOL IsValidSortId(
  2305. LCID Locale)
  2306. {
  2307. WCHAR pTmpBuf[MAX_PATH]; // temp buffer
  2308. PKEY_VALUE_FULL_INFORMATION pKeyValueFull; // ptr to query info
  2309. BYTE pStatic[MAX_KEY_VALUE_FULLINFO]; // ptr to static buffer
  2310. BOOL IfAlloc = FALSE; // if buffer was allocated
  2311. ULONG rc = 0L; // return code
  2312. //
  2313. // Make sure there is a sort id.
  2314. //
  2315. if (!SORTIDFROMLCID(Locale))
  2316. {
  2317. return (TRUE);
  2318. }
  2319. //
  2320. // Open the Alternate Sorts registry key.
  2321. //
  2322. OPEN_ALT_SORTS_KEY(FALSE);
  2323. //
  2324. // Convert locale value to Unicode string.
  2325. //
  2326. if (NlsConvertIntegerToString(Locale, 16, 8, pTmpBuf, MAX_PATH))
  2327. {
  2328. return (FALSE);
  2329. }
  2330. //
  2331. // Query the registry for the value.
  2332. //
  2333. pKeyValueFull = (PKEY_VALUE_FULL_INFORMATION)pStatic;
  2334. if (rc = QueryRegValue( hAltSortsKey,
  2335. pTmpBuf,
  2336. &pKeyValueFull,
  2337. MAX_KEY_VALUE_FULLINFO,
  2338. &IfAlloc ))
  2339. {
  2340. return (FALSE);
  2341. }
  2342. //
  2343. // Free the buffer used for the query.
  2344. //
  2345. if (IfAlloc)
  2346. {
  2347. NLS_FREE_MEM(pKeyValueFull);
  2348. }
  2349. //
  2350. // Return success.
  2351. //
  2352. return (TRUE);
  2353. }
  2354. ////////////////////////////////////////////////////////////////////////////
  2355. //
  2356. // GetLanguageExceptionInfo
  2357. //
  2358. // Opens and Maps a view of the section for the language exception file.
  2359. // It then fills in the appropriate fields of the global table pointers
  2360. // structure.
  2361. //
  2362. // 08-30-95 JulieB Created.
  2363. ////////////////////////////////////////////////////////////////////////////
  2364. ULONG GetLanguageExceptionInfo()
  2365. {
  2366. HANDLE hSec = (HANDLE)0; // section handle
  2367. LPWORD pBaseAddr; // ptr to base address of section
  2368. DWORD Num; // number of entries in table
  2369. ULONG rc = 0L; // return code
  2370. //
  2371. // Make sure we're in the critical section when entering this call.
  2372. //
  2373. ASSERT(NtCurrentTeb()->ClientId.UniqueThread == gcsTblPtrs.OwningThread);
  2374. //
  2375. // Make sure the table isn't already there.
  2376. //
  2377. if (pTblPtrs->pLangException != NULL)
  2378. {
  2379. return (NO_ERROR);
  2380. }
  2381. //
  2382. // Create and map the section, and then save the pointer.
  2383. //
  2384. if ((rc = CsrBasepNlsCreateSection( NLS_CREATE_SECTION_LANG_EXCEPT, 0,
  2385. &hSec )) == NO_ERROR)
  2386. {
  2387. //
  2388. // Map a View of the Section.
  2389. //
  2390. if ((rc = MapSection( hSec,
  2391. &pBaseAddr,
  2392. PAGE_READONLY,
  2393. TRUE )) != NO_ERROR)
  2394. {
  2395. return (rc);
  2396. }
  2397. }
  2398. else
  2399. {
  2400. return (rc);
  2401. }
  2402. //
  2403. // Save the pointers to the exception information.
  2404. //
  2405. Num = *((LPDWORD)pBaseAddr);
  2406. if (Num > 0)
  2407. {
  2408. pTblPtrs->NumLangException = Num;
  2409. pTblPtrs->pLangExceptHdr = (PL_EXCEPT_HDR)(pBaseAddr +
  2410. L_EXCEPT_HDR_OFFSET);
  2411. pTblPtrs->pLangException = (PL_EXCEPT)(pBaseAddr +
  2412. L_EXCEPT_HDR_OFFSET +
  2413. (Num * (sizeof(L_EXCEPT_HDR) /
  2414. sizeof(WORD))));
  2415. }
  2416. //
  2417. // Return success.
  2418. //
  2419. return (NO_ERROR);
  2420. }
  2421. ////////////////////////////////////////////////////////////////////////////
  2422. //
  2423. // GetLinguisticLanguageInfo
  2424. //
  2425. // Opens and Maps a view of the section for the default linguistic language
  2426. // table. It then stores the pointer to the table in the global pointer
  2427. // table.
  2428. //
  2429. // 08-30-95 JulieB Created.
  2430. ////////////////////////////////////////////////////////////////////////////
  2431. LPWORD GetLinguisticLanguageInfo(
  2432. LCID Locale)
  2433. {
  2434. HANDLE hSec = (HANDLE)0; // section handle
  2435. UNICODE_STRING ObSecName; // section name
  2436. LPWORD pBaseAddr; // ptr to base address of section
  2437. ULONG rc = 0L; // return code
  2438. SECTION_BASIC_INFORMATION SecInfo; // section information - query
  2439. //
  2440. // Make sure we're in the critical section when entering this call.
  2441. //
  2442. ASSERT(NtCurrentTeb()->ClientId.UniqueThread == gcsTblPtrs.OwningThread);
  2443. //
  2444. // Create/Open and Map a view of the section if it hasn't been done yet.
  2445. //
  2446. if (pTblPtrs->pLinguistLanguage == NULL)
  2447. {
  2448. //
  2449. // See if we can simply open the section.
  2450. //
  2451. RtlInitUnicodeString(&ObSecName, NLS_SECTION_LANG_INTL);
  2452. if (rc = OpenSection( &hSec,
  2453. &ObSecName,
  2454. (PVOID *)&pBaseAddr,
  2455. SECTION_MAP_READ,
  2456. TRUE ))
  2457. {
  2458. //
  2459. // Need to create the default linguistic language section.
  2460. //
  2461. if (CreateAndCopyLanguageExceptions(0L, &pBaseAddr))
  2462. {
  2463. return (NULL);
  2464. }
  2465. }
  2466. //
  2467. // Get Default Linguistic Language Information.
  2468. //
  2469. pTblPtrs->pLinguistLanguage = (P844_TABLE)(pBaseAddr);
  2470. }
  2471. //
  2472. // Now see if there are any exceptions for the given locale.
  2473. //
  2474. if (CreateAndCopyLanguageExceptions(Locale, &pBaseAddr))
  2475. {
  2476. return (pTblPtrs->pLinguistLanguage);
  2477. }
  2478. //
  2479. // Return success.
  2480. //
  2481. return (pBaseAddr);
  2482. }
  2483. ////////////////////////////////////////////////////////////////////////////
  2484. //
  2485. // CreateAndCopyLanguageExceptions
  2486. //
  2487. // Creates the section for the new language table (if necessary) and then
  2488. // copies the exceptions to the table.
  2489. //
  2490. // 08-30-95 JulieB Created.
  2491. ////////////////////////////////////////////////////////////////////////////
  2492. ULONG CreateAndCopyLanguageExceptions(
  2493. LCID Locale,
  2494. LPWORD *ppBaseAddr)
  2495. {
  2496. HANDLE hSec = (HANDLE)0; // section handle
  2497. UNICODE_STRING ObSecName; // section name
  2498. LPWORD pBaseAddr; // ptr to base address of section
  2499. P844_TABLE pLangDefault; // ptr to default table to copy from
  2500. ULONG rc = 0L; // return code
  2501. PL_EXCEPT_HDR pExceptHdr; // ptr to exception header
  2502. PL_EXCEPT pExceptTbl; // ptr to exception table
  2503. WCHAR wszSecName[MAX_SMALL_BUF_LEN]; // Place for the section name string \
  2504. NTSTATUS Status;
  2505. //
  2506. // Make sure we're in the critical section when entering this call.
  2507. //
  2508. ASSERT(NtCurrentTeb()->ClientId.UniqueThread == gcsTblPtrs.OwningThread);
  2509. if (Locale == 0)
  2510. {
  2511. //
  2512. // Creating the default section.
  2513. //
  2514. RtlInitUnicodeString(&ObSecName, NLS_SECTION_LANG_INTL);
  2515. pLangDefault = pTblPtrs->pDefaultLanguage;
  2516. }
  2517. else
  2518. {
  2519. GET_LANG_SECTION_NAME(Locale, wszSecName, MAX_SMALL_BUF_LEN, &ObSecName);
  2520. pLangDefault = pTblPtrs->pLinguistLanguage;
  2521. }
  2522. //
  2523. // Try to Open and Map a view of the section (read only).
  2524. //
  2525. if (rc = OpenSection( &hSec,
  2526. &ObSecName,
  2527. (PVOID *)&pBaseAddr,
  2528. SECTION_MAP_READ,
  2529. FALSE ))
  2530. {
  2531. //
  2532. // Open failed.
  2533. // See if any exceptions exist for given Locale ID.
  2534. //
  2535. if (!FindLanguageExceptionPointers( Locale,
  2536. &pExceptHdr,
  2537. &pExceptTbl ) &&
  2538. (Locale != 0))
  2539. {
  2540. //
  2541. // No exceptions for locale and we're not trying to create
  2542. // the default table, so return the pointer to the default
  2543. // table (which should always be created at this point).
  2544. //
  2545. *ppBaseAddr = pTblPtrs->pLinguistLanguage;
  2546. return (NO_ERROR);
  2547. }
  2548. else
  2549. {
  2550. //
  2551. // Exceptions exist for the given locale. Need to create the
  2552. // new section (and call the server to make it permanent).
  2553. //
  2554. Status = CsrBasepNlsCreateSection( NLS_CREATE_LANG_EXCEPTION_SECTION,
  2555. Locale,
  2556. &hSec );
  2557. //
  2558. // Check return from server call.
  2559. //
  2560. rc = (ULONG)Status;
  2561. if (!NT_SUCCESS(rc))
  2562. {
  2563. if (hSec != NULL)
  2564. {
  2565. NtClose(hSec);
  2566. }
  2567. return (rc);
  2568. }
  2569. //
  2570. // Map the section for ReadWrite.
  2571. //
  2572. if (rc = MapSection( hSec,
  2573. (PVOID *)&pBaseAddr,
  2574. PAGE_READWRITE,
  2575. FALSE ))
  2576. {
  2577. NtClose(hSec);
  2578. return (rc);
  2579. }
  2580. //
  2581. // Put a 0 in the semaphore part to denote that the file
  2582. // is not ready yet.
  2583. //
  2584. *pBaseAddr = 0;
  2585. //
  2586. // Copy the Default Language Table to the New Section.
  2587. //
  2588. RtlMoveMemory( (PVOID)((LPWORD)pBaseAddr + LANG_HEADER),
  2589. (PVOID)((LPWORD)(pLangDefault) + LANG_HEADER),
  2590. (ULONG)(pTblPtrs->LinguistLangSize.LowPart -
  2591. (LANG_HEADER * sizeof(WORD))) );
  2592. //
  2593. // Copy exception information to the table.
  2594. //
  2595. CopyLanguageExceptionInfo( pBaseAddr,
  2596. pExceptHdr,
  2597. pExceptTbl );
  2598. //
  2599. // Write a 1 to the WORD semaphore (table may now be read).
  2600. //
  2601. *pBaseAddr = 1;
  2602. //
  2603. // Unmap the section for Write and remap it for Read.
  2604. //
  2605. if ((rc = UnMapSection(pBaseAddr)) ||
  2606. (rc = MapSection( hSec,
  2607. (PVOID *)&pBaseAddr,
  2608. PAGE_READONLY,
  2609. FALSE )))
  2610. {
  2611. NtClose(hSec);
  2612. return (rc);
  2613. }
  2614. }
  2615. }
  2616. //
  2617. // Close the section handle.
  2618. //
  2619. NtClose(hSec);
  2620. //
  2621. // Check semaphore bit in file. Make sure that the open
  2622. // succeeded AFTER all exceptions were added to the memory
  2623. // mapped section.
  2624. //
  2625. if (*pBaseAddr == 0)
  2626. {
  2627. //
  2628. // Another process is still adding the appropriate exception
  2629. // information. Must wait for its completion.
  2630. //
  2631. if (rc = WaitOnEvent(pBaseAddr))
  2632. {
  2633. UnMapSection(pBaseAddr);
  2634. return (rc);
  2635. }
  2636. }
  2637. //
  2638. // Return the pointer to the section.
  2639. //
  2640. *ppBaseAddr = pBaseAddr;
  2641. //
  2642. // Return success.
  2643. //
  2644. return (NO_ERROR);
  2645. }
  2646. ////////////////////////////////////////////////////////////////////////////
  2647. //
  2648. // FindLanguageExceptionPointers
  2649. //
  2650. // Checks to see if any exceptions exist for the given locale id. If
  2651. // exceptions exist, then TRUE is returned and the pointer to the exception
  2652. // header and the pointer to the exception table are stored in the given
  2653. // parameters.
  2654. //
  2655. // 08-30-95 JulieB Created.
  2656. ////////////////////////////////////////////////////////////////////////////
  2657. BOOL FASTCALL FindLanguageExceptionPointers(
  2658. LCID Locale,
  2659. PL_EXCEPT_HDR *ppExceptHdr,
  2660. PL_EXCEPT *ppExceptTbl)
  2661. {
  2662. DWORD ctr; // loop counter
  2663. PL_EXCEPT_HDR pHdr; // ptr to exception header
  2664. BOOL rc = FALSE; // return value
  2665. //
  2666. // Make sure we're in the critical section when entering this call.
  2667. //
  2668. ASSERT(NtCurrentTeb()->ClientId.UniqueThread == gcsTblPtrs.OwningThread);
  2669. //
  2670. // Initialize pointers.
  2671. //
  2672. *ppExceptHdr = NULL;
  2673. *ppExceptTbl = NULL;
  2674. //
  2675. // Need to search down the exception header for the given locale.
  2676. //
  2677. pHdr = pTblPtrs->pLangExceptHdr;
  2678. for (ctr = pTblPtrs->NumLangException; ctr > 0; ctr--, pHdr++)
  2679. {
  2680. if (pHdr->Locale == (DWORD)Locale)
  2681. {
  2682. //
  2683. // Found the locale id, so set the pointers.
  2684. //
  2685. *ppExceptHdr = pHdr;
  2686. *ppExceptTbl = (PL_EXCEPT)(((LPWORD)(pTblPtrs->pLangException)) +
  2687. pHdr->Offset);
  2688. //
  2689. // Set the return code for success.
  2690. //
  2691. rc = TRUE;
  2692. break;
  2693. }
  2694. }
  2695. //
  2696. // Return the value in rc.
  2697. //
  2698. return (rc);
  2699. }
  2700. ////////////////////////////////////////////////////////////////////////////
  2701. //
  2702. // CopyLanguageExceptionInfo
  2703. //
  2704. // Copies the language exception information to the given language table.
  2705. //
  2706. // 08-30-95 JulieB Created.
  2707. ////////////////////////////////////////////////////////////////////////////
  2708. void FASTCALL CopyLanguageExceptionInfo(
  2709. LPWORD pBaseAddr,
  2710. PL_EXCEPT_HDR pExceptHdr,
  2711. PL_EXCEPT pExceptTbl)
  2712. {
  2713. DWORD ctr; // loop counter
  2714. P844_TABLE pUpCase; // ptr to upper case table
  2715. P844_TABLE pLoCase; // ptr to lower case table
  2716. //
  2717. // Make sure we're in the critical section when entering this call.
  2718. //
  2719. ASSERT(NtCurrentTeb()->ClientId.UniqueThread == gcsTblPtrs.OwningThread);
  2720. if (pExceptTbl)
  2721. {
  2722. //
  2723. // Get the pointers to the upper and lower case table.
  2724. //
  2725. pUpCase = pBaseAddr + LANG_HEADER + UP_HEADER;
  2726. pLoCase = pBaseAddr + LANG_HEADER + pBaseAddr[LANG_HEADER] + LO_HEADER;
  2727. //
  2728. // For each entry in the exception table, copy the information to the
  2729. // sortkey table.
  2730. //
  2731. for (ctr = pExceptHdr->NumUpEntries; ctr > 0; ctr--, pExceptTbl++)
  2732. {
  2733. TRAVERSE_844_W(pUpCase, pExceptTbl->UCP) = pExceptTbl->AddAmount;
  2734. }
  2735. for (ctr = pExceptHdr->NumLoEntries; ctr > 0; ctr--, pExceptTbl++)
  2736. {
  2737. TRAVERSE_844_W(pLoCase, pExceptTbl->UCP) = pExceptTbl->AddAmount;
  2738. }
  2739. }
  2740. }
  2741. ////////////////////////////////////////////////////////////////////////////
  2742. //
  2743. // FindExceptionPointers
  2744. //
  2745. // Checks to see if any exceptions exist for the given locale id. If
  2746. // exceptions exist, then TRUE is returned and the pointer to the exception
  2747. // header and the pointer to the exception table are stored in the given
  2748. // parameters.
  2749. //
  2750. // 05-31-91 JulieB Created.
  2751. ////////////////////////////////////////////////////////////////////////////
  2752. BOOL FASTCALL FindExceptionPointers(
  2753. LCID Locale,
  2754. PEXCEPT_HDR *ppExceptHdr,
  2755. PEXCEPT *ppExceptTbl,
  2756. PVOID *ppIdeograph,
  2757. PULONG pReturn)
  2758. {
  2759. HANDLE hSec = (HANDLE)0; // section handle
  2760. DWORD ctr; // loop counter
  2761. PEXCEPT_HDR pHdr; // ptr to exception header
  2762. BOOL bFound = FALSE; // if an exception is found
  2763. PIDEOGRAPH_LCID pIdeoLcid; // ptr to ideograph lcid entry
  2764. PVOID pBaseAddr; // ptr to base address of section
  2765. //
  2766. // Make sure we're in the critical section when entering this call.
  2767. //
  2768. ASSERT(NtCurrentTeb()->ClientId.UniqueThread == gcsTblPtrs.OwningThread);
  2769. //
  2770. // Initialize pointers.
  2771. //
  2772. *ppExceptHdr = NULL;
  2773. *ppExceptTbl = NULL;
  2774. *ppIdeograph = NULL;
  2775. *pReturn = NO_ERROR;
  2776. //
  2777. // Need to search down the exception header for the given locale.
  2778. //
  2779. pHdr = pTblPtrs->pExceptHdr;
  2780. for (ctr = pTblPtrs->NumException; ctr > 0; ctr--, pHdr++)
  2781. {
  2782. if (pHdr->Locale == (DWORD)Locale)
  2783. {
  2784. //
  2785. // Found the locale id, so set the pointers.
  2786. //
  2787. *ppExceptHdr = pHdr;
  2788. *ppExceptTbl = (PEXCEPT)(((LPWORD)(pTblPtrs->pException)) +
  2789. pHdr->Offset);
  2790. //
  2791. // Set the return code to show that an exception has been
  2792. // found.
  2793. //
  2794. bFound = TRUE;
  2795. break;
  2796. }
  2797. }
  2798. //
  2799. // Need to search down the ideograph lcid exception list for the
  2800. // given locale.
  2801. //
  2802. pIdeoLcid = pTblPtrs->pIdeographLcid;
  2803. for (ctr = pTblPtrs->NumIdeographLcid; ctr > 0; ctr--, pIdeoLcid++)
  2804. {
  2805. if (pIdeoLcid->Locale == (DWORD)Locale)
  2806. {
  2807. //
  2808. // Found the locale id, so create/open and map the section
  2809. // for the appropriate file.
  2810. //
  2811. if (*pReturn = CreateSectionTemp(&hSec, pIdeoLcid->pFileName))
  2812. {
  2813. //
  2814. // Ideograph file section could not be created, so return
  2815. // the error.
  2816. //
  2817. return (TRUE);
  2818. }
  2819. if (*pReturn = MapSection(hSec, &pBaseAddr, PAGE_READONLY, TRUE))
  2820. {
  2821. //
  2822. // Ideograph file section could not be mapped, so close
  2823. // the created section and return the error.
  2824. //
  2825. NtClose(hSec);
  2826. return (TRUE);
  2827. }
  2828. //
  2829. // Set the pointer to the ideograph information.
  2830. //
  2831. *ppIdeograph = pBaseAddr;
  2832. //
  2833. // Set the return code to show that an exception has been
  2834. // found.
  2835. //
  2836. bFound = TRUE;
  2837. break;
  2838. }
  2839. }
  2840. //
  2841. // Return the appropriate value.
  2842. //
  2843. return (bFound);
  2844. }
  2845. ////////////////////////////////////////////////////////////////////////////
  2846. //
  2847. // CopyExceptionInfo
  2848. //
  2849. // Copies the exception information to the given sortkey table.
  2850. //
  2851. // 05-31-91 JulieB Created.
  2852. ////////////////////////////////////////////////////////////////////////////
  2853. void FASTCALL CopyExceptionInfo(
  2854. PSORTKEY pSortkey,
  2855. PEXCEPT_HDR pExceptHdr,
  2856. PEXCEPT pExceptTbl,
  2857. PVOID pIdeograph)
  2858. {
  2859. DWORD ctr; // loop counter
  2860. PIDEOGRAPH_EXCEPT_HDR pHdrIG; // ptr to ideograph exception header
  2861. PIDEOGRAPH_EXCEPT pEntryIG; // ptr to ideograph exception entry
  2862. PEXCEPT pEntryIGEx; // ptr to ideograph exception entry ex
  2863. //
  2864. // Make sure we're in the critical section when entering this call.
  2865. //
  2866. ASSERT(NtCurrentTeb()->ClientId.UniqueThread == gcsTblPtrs.OwningThread);
  2867. //
  2868. // For each entry in the exception table, copy the information to the
  2869. // sortkey table.
  2870. //
  2871. if (pExceptTbl)
  2872. {
  2873. for (ctr = pExceptHdr->NumEntries; ctr > 0; ctr--, pExceptTbl++)
  2874. {
  2875. (pSortkey[pExceptTbl->UCP]).UW.Unicode = pExceptTbl->Unicode;
  2876. (pSortkey[pExceptTbl->UCP]).Diacritic = pExceptTbl->Diacritic;
  2877. (pSortkey[pExceptTbl->UCP]).Case = pExceptTbl->Case;
  2878. }
  2879. }
  2880. //
  2881. // For each entry in the ideograph exception table, copy the
  2882. // information to the sortkey table.
  2883. //
  2884. if (pIdeograph)
  2885. {
  2886. pHdrIG = (PIDEOGRAPH_EXCEPT_HDR)pIdeograph;
  2887. ctr = pHdrIG->NumEntries;
  2888. if (pHdrIG->NumColumns == 2)
  2889. {
  2890. pEntryIG = (PIDEOGRAPH_EXCEPT)( ((LPBYTE)pIdeograph) +
  2891. sizeof(IDEOGRAPH_EXCEPT_HDR) );
  2892. for (; ctr > 0; ctr--, pEntryIG++)
  2893. {
  2894. (pSortkey[pEntryIG->UCP]).UW.Unicode = pEntryIG->Unicode;
  2895. }
  2896. }
  2897. else
  2898. {
  2899. pEntryIGEx = (PEXCEPT)( ((LPBYTE)pIdeograph) +
  2900. sizeof(IDEOGRAPH_EXCEPT_HDR) );
  2901. for (; ctr > 0; ctr--, pEntryIGEx++)
  2902. {
  2903. (pSortkey[pEntryIGEx->UCP]).UW.Unicode = pEntryIGEx->Unicode;
  2904. (pSortkey[pEntryIGEx->UCP]).Diacritic = pEntryIGEx->Diacritic;
  2905. (pSortkey[pEntryIGEx->UCP]).Case = pEntryIGEx->Case;
  2906. }
  2907. }
  2908. //
  2909. // Unmap and Close the ideograph section.
  2910. //
  2911. UnMapSection(pIdeograph);
  2912. }
  2913. }
  2914. ////////////////////////////////////////////////////////////////////////////
  2915. //
  2916. // WaitOnEvent
  2917. //
  2918. // Waits (via timeout) for the semaphore dword to be set to a non-zero
  2919. // value.
  2920. //
  2921. // 05-31-91 JulieB Created.
  2922. ////////////////////////////////////////////////////////////////////////////
  2923. ULONG WaitOnEvent(
  2924. LPWORD pSem)
  2925. {
  2926. TIME TimeOut; // ptr to timeout
  2927. //
  2928. // Set up the TIME structure.
  2929. //
  2930. TimeOut.QuadPart = -100000;
  2931. //
  2932. // Wait on the event until the semaphore is set to non-zero.
  2933. // Use a timeout on the wait.
  2934. //
  2935. do
  2936. {
  2937. NtDelayExecution(FALSE, &TimeOut);
  2938. } while (*pSem == 0);
  2939. //
  2940. // Return success.
  2941. //
  2942. return (NO_ERROR);
  2943. }