|
|
/*++
Copyright (c) 1991-2000, Microsoft Corporation All rights reserved.
Module Name:
tables.c
Abstract:
This file contains functions that manipulate or return information about the different tables used by the NLS API.
External Routines found in this file: AllocTables GetUnicodeFileInfo GetGeoFileInfo GetCTypeFileInfo GetDefaultSortkeyFileInfo GetDefaultSortTablesFileInfo GetSortkeyFileInfo GetSortTablesFileInfo GetCodePageFileInfo GetLanguageFileInfo GetLocaleFileInfo MakeCPHashNode MakeLangHashNode MakeLocHashNode GetCPHashNode GetLangHashNode GetLocHashNode GetCalendar
Revision History:
05-31-91 JulieB Created.
--*/
//
// Include Files.
//
#include "nls.h"
#include "nlssafe.h"
//
// Constant Declarations.
//
#define SEM_NOERROR (SEM_FAILCRITICALERRORS | \
SEM_NOGPFAULTERRORBOX | \ SEM_NOOPENFILEERRORBOX)
//
// Global Variables.
//
PTBL_PTRS pTblPtrs; // ptr to structure of table ptrs
//
// Forward Declarations.
//
BOOL IsValidSortId( LCID Locale);
ULONG GetLanguageExceptionInfo(void);
LPWORD GetLinguisticLanguageInfo( LCID Locale);
ULONG CreateAndCopyLanguageExceptions( LCID Locale, LPWORD *ppBaseAddr);
BOOL FASTCALL FindLanguageExceptionPointers( LCID Locale, PL_EXCEPT_HDR *ppExceptHdr, PL_EXCEPT *ppExceptTbl);
void FASTCALL CopyLanguageExceptionInfo( LPWORD pBaseAddr, PL_EXCEPT_HDR pExceptHdr, PL_EXCEPT pExceptTbl);
BOOL FASTCALL FindExceptionPointers( LCID Locale, PEXCEPT_HDR *ppExceptHdr, PEXCEPT *ppExceptTbl, PVOID *ppIdeograph, PULONG pReturn);
void FASTCALL CopyExceptionInfo( PSORTKEY pSortkey, PEXCEPT_HDR pExceptHdr, PEXCEPT pExceptTbl, PVOID pIdeograph);
ULONG WaitOnEvent( LPWORD pSem);
//-------------------------------------------------------------------------//
// INTERNAL MACROS //
//-------------------------------------------------------------------------//
////////////////////////////////////////////////////////////////////////////
//
// GET_HASH_VALUE
//
// Returns the hash value for given value and the given table size.
//
// DEFINED AS A MACRO.
//
// 05-31-91 JulieB Created.
////////////////////////////////////////////////////////////////////////////
#define GET_HASH_VALUE(Value, TblSize) (Value % TblSize)
////////////////////////////////////////////////////////////////////////////
//
// CREATE_CODEPAGE_HASH_NODE
//
// Creates a code page hash node and stores the pointer to it in pHashN.
//
// NOTE: This macro may return if an error is encountered.
//
// DEFINED AS A MACRO.
//
// 05-31-91 JulieB Created.
////////////////////////////////////////////////////////////////////////////
#define CREATE_CODEPAGE_HASH_NODE( CodePage, \
pHashN ) \ { \ /* \
* Allocate CP_HASH structure. \ */ \ if ((pHashN = (PCP_HASH)NLS_ALLOC_MEM(sizeof(CP_HASH))) == NULL) \ { \ return (ERROR_OUTOFMEMORY); \ } \ \ /* \
* Fill in the CodePage value. \ */ \ pHashN->CodePage = CodePage; \ \ /* \
* Make sure the pfnCPProc value is NULL for now. \ */ \ pHashN->pfnCPProc = NULL; \ }
////////////////////////////////////////////////////////////////////////////
//
// CREATE_LOCALE_HASH_NODE
//
// Creates a locale hash node and stores the pointer to it in pHashN.
//
// NOTE: This macro may return if an error is encountered.
//
// DEFINED AS A MACRO.
//
// 05-31-91 JulieB Created.
////////////////////////////////////////////////////////////////////////////
#define CREATE_LOCALE_HASH_NODE( Locale, \
pHashN ) \ { \ /* \
* Allocate LOC_HASH structure. \ */ \ if ((pHashN = (PLOC_HASH)NLS_ALLOC_MEM(sizeof(LOC_HASH))) == NULL) \ { \ return (ERROR_OUTOFMEMORY); \ } \ \ /* \
* Fill in the Locale value. \ */ \ pHashN->Locale = Locale; \ }
////////////////////////////////////////////////////////////////////////////
//
// FIND_CP_HASH_NODE
//
// Searches for the cp hash node for the given locale. The result is
// put in pHashN. If no node exists, pHashN will be NULL.
//
// DEFINED AS A MACRO.
//
// 05-31-91 JulieB Created.
////////////////////////////////////////////////////////////////////////////
#define FIND_CP_HASH_NODE( CodePage, \
pHashN ) \ { \ UINT Index; /* hash value */ \ \ /* \
* Get hash value. \ */ \ Index = GET_HASH_VALUE(CodePage, CP_TBL_SIZE); \ \ /* \
* Make sure the hash node still doesn't exist in the table. \ */ \ pHashN = (pTblPtrs->pCPHashTbl)[Index]; \ while ((pHashN != NULL) && (pHashN->CodePage != CodePage)) \ { \ pHashN = pHashN->pNext; \ } \ }
////////////////////////////////////////////////////////////////////////////
//
// IsCPHashNodeLoaded
//
// Wrapper for the FIND_CP_HASH_NODE macro so that we can call this from
// mbcs.c. Return TRUE if the node already exists, otherwise false. False
// could still indicate a valid code page, just not one already loaded.
//
// 05-31-02 ShawnSte Created.
////////////////////////////////////////////////////////////////////////////
BOOL IsCPHashNodeLoaded( UINT CodePage ) { PCP_HASH pHashN; // ptr to CP hash node
//
// Get hash node.
//
FIND_CP_HASH_NODE(CodePage, pHashN);
return (pHashN != NULL); }
////////////////////////////////////////////////////////////////////////////
//
// FIND_LOCALE_HASH_NODE
//
// Searches for the locale hash node for the given locale. The result is
// put in pHashN. If no node exists, pHashN will be NULL.
//
// DEFINED AS A MACRO.
//
// 05-31-91 JulieB Created.
////////////////////////////////////////////////////////////////////////////
#define FIND_LOCALE_HASH_NODE( Locale, \
pHashN ) \ { \ UINT Index; /* hash value */ \ \ \ /* \
* Get hash value. \ */ \ Index = GET_HASH_VALUE(Locale, LOC_TBL_SIZE); \ \ /* \
* Get hash node. \ */ \ pHashN = (pTblPtrs->pLocHashTbl)[Index]; \ while ((pHashN != NULL) && (pHashN->Locale != Locale)) \ { \ pHashN = pHashN->pNext; \ } \ }
////////////////////////////////////////////////////////////////////////////
//
// EXIST_LANGUAGE_INFO
//
// Checks to see if the casing tables have been added to the locale
// hash node.
//
// Must check the LOWER CASE pointer, since that value is set last in
// the hash node.
//
// DEFINED AS A MACRO.
//
// 05-31-91 JulieB Created.
////////////////////////////////////////////////////////////////////////////
#define EXIST_LANGUAGE_INFO(pHashN) (pHashN->pLowerCase)
////////////////////////////////////////////////////////////////////////////
//
// EXIST_LINGUIST_LANGUAGE_INFO
//
// Checks to see if the linguistic casing tables have been added to the locale
// hash node.
//
// Must check the LOWER CASE pointer, since that value is set last in
// the hash node.
//
// DEFINED AS A MACRO.
//
// 08-30-95 JulieB Created.
////////////////////////////////////////////////////////////////////////////
#define EXIST_LINGUIST_LANGUAGE_INFO(pHashN) (pHashN->pLowerLinguist)
////////////////////////////////////////////////////////////////////////////
//
// EXIST_LOCALE_INFO
//
// Checks to see if the locale tables have been added to the locale
// hash node.
//
// Must check the FIXED locale pointer, since that value is set last in
// the hash node.
//
// DEFINED AS A MACRO.
//
// 05-31-91 JulieB Created.
////////////////////////////////////////////////////////////////////////////
#define EXIST_LOCALE_INFO(pHashN) (pHashN->pLocaleFixed)
////////////////////////////////////////////////////////////////////////////
//
// INSERT_CP_HASH_NODE
//
// Inserts a CP hash node into the global CP hash table. It assumes that
// all unused hash values in the table are pointing to NULL. If there is
// a collision, the new node will be added FIRST in the list.
//
// DEFINED AS A MACRO.
//
// 05-31-91 JulieB Created.
////////////////////////////////////////////////////////////////////////////
#define INSERT_CP_HASH_NODE( pHashN, \
pBaseAddr ) \ { \ UINT Index; /* hash value */ \ PCP_HASH pSearch; /* ptr to CP hash node for search */ \ \ \ /* \
* Get hash value. \ */ \ Index = GET_HASH_VALUE(pHashN->CodePage, CP_TBL_SIZE); \ \ /* \
* Enter table pointers critical section. \ */ \ RtlEnterCriticalSection(&gcsTblPtrs); \ \ /* \
* Make sure the hash node still doesn't exist in the table. \ */ \ pSearch = (pTblPtrs->pCPHashTbl)[Index]; \ while ((pSearch != NULL) && (pSearch->CodePage != pHashN->CodePage)) \ { \ pSearch = pSearch->pNext; \ } \ \ /* \
* If the hash node does not exist, insert the new one. \ * Otherwise, free it. \ */ \ if (pSearch == NULL) \ { \ /* \
* Insert hash node into hash table. \ */ \ pHashN->pNext = (pTblPtrs->pCPHashTbl)[Index]; \ (pTblPtrs->pCPHashTbl)[Index] = pHashN; \ } \ else \ { \ /* \
* Free the resources allocated. \ */ \ if (pBaseAddr) \ { \ UnMapSection(pBaseAddr); \ } \ NLS_FREE_MEM(pHashN); \ } \ \ /* \
* Leave table pointers critical section. \ */ \ RtlLeaveCriticalSection(&gcsTblPtrs); \ }
////////////////////////////////////////////////////////////////////////////
//
// INSERT_LOC_HASH_NODE
//
// Inserts a LOC hash node into the global LOC hash table. It assumes
// that all unused hash values in the table are pointing to NULL. If
// there is a collision, the new node will be added FIRST in the list.
//
// DEFINED AS A MACRO.
//
// 05-31-91 JulieB Created.
////////////////////////////////////////////////////////////////////////////
#define INSERT_LOC_HASH_NODE( pHashN, \
pBaseAddr ) \ { \ UINT Index; /* hash value */ \ PLOC_HASH pSearch; /* ptr to LOC hash node for search */ \ \ \ /* \
* Get hash value. \ */ \ Index = GET_HASH_VALUE(pHashN->Locale, LOC_TBL_SIZE); \ \ /* \
* Enter table pointers critical section. \ */ \ RtlEnterCriticalSection(&gcsTblPtrs); \ \ /* \
* Make sure the hash node still doesn't exist in the table. \ */ \ pSearch = (pTblPtrs->pLocHashTbl)[Index]; \ while ((pSearch != NULL) && (pSearch->Locale != pHashN->Locale)) \ { \ pSearch = pSearch->pNext; \ } \ \ /* \
* If the hash node does not exist, insert the new one. \ * Otherwise, free it. \ */ \ if (pSearch == NULL) \ { \ /* \
* Insert hash node into hash table. \ */ \ pHashN->pNext = (pTblPtrs->pLocHashTbl)[Index]; \ (pTblPtrs->pLocHashTbl)[Index] = pHashN; \ } \ else \ { \ /* \
* Free the resources allocated. \ */ \ if (pBaseAddr) \ { \ UnMapSection(pBaseAddr); \ } \ if ((pHashN->pSortkey != pTblPtrs->pDefaultSortkey) && \ (pHashN->pSortkey != NULL)) \ { \ UnMapSection(((LPWORD)(pHashN->pSortkey)) - SORTKEY_HEADER); \ } \ NLS_FREE_MEM(pHashN); \ } \ \ /* \
* Leave table pointers critical section. \ */ \ RtlLeaveCriticalSection(&gcsTblPtrs); \ }
////////////////////////////////////////////////////////////////////////////
//
// GET_CP_SECTION_NAME
//
// Gets the section name for a given code page.
//
// NOTE: This macro may return if an error is encountered.
//
// DEFINED AS A MACRO.
//
// 05-31-91 JulieB Created.
////////////////////////////////////////////////////////////////////////////
#define GET_CP_SECTION_NAME( CodePage, \
pwszSecName, \ cchSecName, \ pObSecName ) \ { \ if (rc = GetNlsSectionName( CodePage, \ 10, \ 0, \ NLS_SECTION_CPPREFIX, \ pwszSecName, \ cchSecName)) \ { \ return (rc); \ } \ RtlInitUnicodeString(pObSecName, pwszSecName); \ }
////////////////////////////////////////////////////////////////////////////
//
// GET_SORTKEY_SECTION_NAME
//
// Gets the sortkey section name for a given locale.
//
// NOTE: This macro may return if an error is encountered.
//
// DEFINED AS A MACRO.
//
// 05-31-91 JulieB Created.
////////////////////////////////////////////////////////////////////////////
#define GET_SORTKEY_SECTION_NAME( Locale, \
pwszSecName, \ cchSecName, \ pObSecName ) \ { \ if (rc = GetNlsSectionName( Locale, \ 16, \ 8, \ NLS_SECTION_SORTKEY, \ pwszSecName, \ cchSecName)) \ { \ return (rc); \ } \ RtlInitUnicodeString(pObSecName, pwszSecName); \ }
////////////////////////////////////////////////////////////////////////////
//
// GET_LANG_SECTION_NAME
//
// Gets the section name for a given language.
//
// NOTE: This macro may return if an error is encountered.
//
// DEFINED AS A MACRO.
//
// 05-31-91 JulieB Created.
////////////////////////////////////////////////////////////////////////////
#define GET_LANG_SECTION_NAME( Locale, \
pwszSecName, \ cchSecName, \ pObSecName ) \ { \ if (rc = GetNlsSectionName( Locale, \ 16, \ 8, \ NLS_SECTION_LANGPREFIX, \ pwszSecName, \ cchSecName)) \ { \ return (rc); \ } \ RtlInitUnicodeString(pObSecName, pwszSecName); \ }
//-------------------------------------------------------------------------//
// EXTERNAL ROUTINES //
//-------------------------------------------------------------------------//
////////////////////////////////////////////////////////////////////////////
//
// AllocTables
//
// Allocates the global table pointers structure. It then allocates the
// code page and locale hash tables and saves the pointers to the tables
// in the global table pointers structure.
//
// 05-31-91 JulieB Created.
////////////////////////////////////////////////////////////////////////////
ULONG AllocTables() { //
// Allocate global table pointers structure.
//
if ((pTblPtrs = (PTBL_PTRS)NLS_ALLOC_MEM(sizeof(TBL_PTRS))) == NULL) { KdPrint(("NLSAPI: Allocation for TABLE PTRS structure FAILED.\n")); return (ERROR_OUTOFMEMORY); }
//
// Allocate code page hash table.
//
if ((pTblPtrs->pCPHashTbl = (PCP_HASH_TBL)NLS_ALLOC_MEM(sizeof(PCP_HASH) * CP_TBL_SIZE)) == NULL) { KdPrint(("NLSAPI: Allocation for CODE PAGE hash table FAILED.\n")); return (ERROR_OUTOFMEMORY); }
//
// Allocate locale hash table.
//
if ((pTblPtrs->pLocHashTbl = (PLOC_HASH_TBL)NLS_ALLOC_MEM(sizeof(PLOC_HASH) * LOC_TBL_SIZE)) == NULL) { KdPrint(("NLSAPI: Allocation for LOCALE hash table FAILED.\n")); return (ERROR_OUTOFMEMORY); }
//
// Return success.
//
return (NO_ERROR); }
////////////////////////////////////////////////////////////////////////////
//
// GetUnicodeFileInfo
//
// Opens and Maps a view of the section for the unicode file. It then
// fills in the appropriate fields of the global table pointers structure.
//
// 05-31-91 JulieB Created.
////////////////////////////////////////////////////////////////////////////
ULONG GetUnicodeFileInfo() { HANDLE hSec = (HANDLE)0; // section handle
UNICODE_STRING ObSecName; // section name
LPWORD pBaseAddr; // ptr to base address of section
ULONG rc = 0L; // return code
WORD offCZ; // offset to FOLDCZONE table
WORD offHG; // offset to HIRAGANA table
WORD offKK; // offset to KATAKANA table
WORD offHW; // offset to HALFWIDTH table
WORD offFW; // offset to FULLWIDTH table
WORD offTR; // offset to TRADITIONAL table
WORD offSP; // offset to SIMPLIFIED table
WORD offPre; // offset to PRECOMPOSED table
WORD offComp; // offset to COMPOSITE table
PCOMP_INFO pComp; // ptr to COMP_INFO structure
//
// Make sure we're in the critical section when entering this call.
//
ASSERT(NtCurrentTeb()->ClientId.UniqueThread == gcsTblPtrs.OwningThread);
//
// Make sure the unicode information is not already there.
// If it is, return success.
//
// Since we're already in the critical section here, there is no
// need to check ALL of the pointers set in this routine. Just
// check one of them.
//
if (pTblPtrs->pADigit != NULL) { return (NO_ERROR); }
//
// Open and Map a view of the section.
//
ObSecName.Buffer = NLS_SECTION_UNICODE; ObSecName.Length = sizeof (NLS_SECTION_UNICODE) - sizeof (WCHAR); ObSecName.MaximumLength = ObSecName.Length; if (rc = OpenSection( &hSec, &ObSecName, (PVOID *)&pBaseAddr, SECTION_MAP_READ, TRUE )) { return (rc); }
//
// Get the offsets.
//
offCZ = pBaseAddr[0]; offHG = offCZ + pBaseAddr[offCZ]; offKK = offHG + pBaseAddr[offHG]; offHW = offKK + pBaseAddr[offKK]; offFW = offHW + pBaseAddr[offHW]; offTR = offFW + pBaseAddr[offFW]; offSP = offTR + pBaseAddr[offTR]; offPre = offSP + pBaseAddr[offSP]; offComp = offPre + pBaseAddr[offPre];
//
// Allocate COMP_INFO structure.
//
if ((pComp = (PCOMP_INFO)NLS_ALLOC_MEM(sizeof(COMP_INFO))) == NULL) { return (ERROR_OUTOFMEMORY); }
//
// Fill in the COMPOSITE information.
//
pComp->NumBase = LOBYTE((pBaseAddr + offComp)[2]); pComp->NumNonSp = HIBYTE((pBaseAddr + offComp)[2]); pComp->pBase = pBaseAddr + offComp + CO_HEADER; pComp->pNonSp = pComp->pBase + ((pBaseAddr + offComp)[0]); pComp->pGrid = pComp->pNonSp + ((pBaseAddr + offComp)[1]);
//
// Attach ASCIIDIGITS table to tbl ptrs structure.
//
pTblPtrs->pADigit = pBaseAddr + AD_HEADER;
//
// Attach FOLDCZONE table to tbl ptrs structure.
//
pTblPtrs->pCZone = pBaseAddr + offCZ + CZ_HEADER;
//
// Attach HIRAGANA table to tbl ptrs structure.
//
pTblPtrs->pHiragana = pBaseAddr + offHG + HG_HEADER;
//
// Attach KATAKANA table to tbl ptrs structure.
//
pTblPtrs->pKatakana = pBaseAddr + offKK + KK_HEADER;
//
// Attach HALFWIDTH table to tbl ptrs structure.
//
pTblPtrs->pHalfWidth = pBaseAddr + offHW + HW_HEADER;
//
// Attach FULLWIDTH table to tbl ptrs structure.
//
pTblPtrs->pFullWidth = pBaseAddr + offFW + FW_HEADER;
//
// Attach TRADITIONAL table to tbl ptrs structure.
//
pTblPtrs->pTraditional = pBaseAddr + offTR + TR_HEADER;
//
// Attach SIMPLIFIED table to tbl ptrs structure.
//
pTblPtrs->pSimplified = pBaseAddr + offSP + SP_HEADER;
//
// Attach PRECOMPOSED table to tbl ptrs structure.
//
pTblPtrs->pPreComposed = pBaseAddr + offPre + PC_HEADER;
//
// Attach COMP_INFO to tbl ptrs structure.
//
pTblPtrs->pComposite = pComp;
//
// Return success.
//
return (NO_ERROR); }
////////////////////////////////////////////////////////////////////////////
//
// GetGeoFileInfo
//
// Opens and Maps a view of the section for the geo file. It then
// fills in the appropriate field of the global table pointers structure.
// Before calling this function you should check pGeoInfo member.
//
////////////////////////////////////////////////////////////////////////////
ULONG GetGeoFileInfo() { HANDLE hSec = (HANDLE)0; // section handle
UNICODE_STRING ObSecName; // section name
LPWORD pBaseAddr; // ptr to base address of section
ULONG rc = NO_ERROR; // return code
//
// Enter the critical section to set up the GEO tables.
//
RtlEnterCriticalSection(&gcsTblPtrs);
//
// Make sure the Geographical Information table is
// not already there. If it is, return TRUE.
//
// Since we're already in the critical section here, there is no
// need to check ALL of the pointers set in this routine. Just
// check one of them.
//
if (pTblPtrs->pGeoInfo != NULL) { RtlLeaveCriticalSection(&gcsTblPtrs); return (NO_ERROR); }
//
// Create and map the section, and then save the pointer.
//
if ((rc = CsrBasepNlsCreateSection(NLS_CREATE_SECTION_GEO, 0, &hSec)) == NO_ERROR) { //
// Map a View of the Section.
//
if ((rc = MapSection( hSec, &pBaseAddr, PAGE_READONLY, TRUE )) != NO_ERROR) { RtlLeaveCriticalSection(&gcsTblPtrs); return (rc); } } else { RtlLeaveCriticalSection(&gcsTblPtrs); return (rc); }
//
// Attach GeoInfo mapping table, GEO/LCID mapping table and
// GEO/ISO639 name mapping table to the tbl ptrs structure. We initialize
// the pGeoinfo member at the end so we don't get a race condition.
//
pTblPtrs->nGeoLCID = ((PGEOTABLEHDR)pBaseAddr)->nGeoLCID; pTblPtrs->pGeoLCID = (PGEOLCID)((PBYTE)pBaseAddr + ((PGEOTABLEHDR)pBaseAddr)->dwOffsetGeoLCID); pTblPtrs->nGeoInfo = ((PGEOTABLEHDR)pBaseAddr)->nGeoInfo; pTblPtrs->pGeoInfo = (PGEOINFO)((PBYTE)pBaseAddr + ((PGEOTABLEHDR)pBaseAddr)->dwOffsetGeoInfo);
//
// Leave table pointers critical section.
//
RtlLeaveCriticalSection(&gcsTblPtrs);
//
// Return success.
//
return (NO_ERROR); }
////////////////////////////////////////////////////////////////////////////
//
// GetCTypeFileInfo
//
// Opens and Maps a view of the section for the given ctype. It then
// fills in the appropriate field of the global table pointers structure.
//
// 05-31-91 JulieB Created.
////////////////////////////////////////////////////////////////////////////
ULONG GetCTypeFileInfo() { HANDLE hSec = (HANDLE)0; // section handle
UNICODE_STRING ObSecName; // section name
LPWORD pBaseAddr; // ptr to base address of section
ULONG rc = 0L; // return code
//
// Make sure the ctype information is not already there.
// If it is, return success.
//
// Must check the 844 table rather than the mapping table, since
// the 844 table is set AFTER the mapping table below. Otherwise,
// there is a race condition, since we're not in a critical section.
//
if (pTblPtrs->pCType844 != NULL) { return (NO_ERROR); }
//
// Enter table pointers critical section.
//
RtlEnterCriticalSection(&gcsTblPtrs); if (pTblPtrs->pCType844 != NULL) { RtlLeaveCriticalSection(&gcsTblPtrs); return (NO_ERROR); }
//
// Open and Map a view of the section.
//
RtlInitUnicodeString(&ObSecName, NLS_SECTION_CTYPE); if (rc = OpenSection( &hSec, &ObSecName, (PVOID *)&pBaseAddr, SECTION_MAP_READ, TRUE )) { RtlLeaveCriticalSection(&gcsTblPtrs); return (rc); }
//
// Attach CTYPE mapping table and 8:4:4 table to tbl ptrs structure.
//
// The pCType844 value must be set LAST, since this is the pointer
// that is checked to see that the ctype information has been
// initialized.
//
pTblPtrs->pCTypeMap = (PCT_VALUES)(pBaseAddr + CT_HEADER); pTblPtrs->pCType844 = (PCTYPE)((LPBYTE)(pBaseAddr + 1) + ((PCTYPE_HDR)pBaseAddr)->MapSize);
//
// Leave table pointers critical section.
//
RtlLeaveCriticalSection(&gcsTblPtrs);
//
// Return success.
//
return (NO_ERROR); }
////////////////////////////////////////////////////////////////////////////
//
// GetDefaultSortkeyFileInfo
//
// Opens and Maps a view of the section for the default sortkey table. It
// then stores the pointer to the table in the global pointer table.
//
// NOTE: THIS ROUTINE SHOULD ONLY BE CALLED AT PROCESS STARTUP. If it is
// called from other than process startup, a critical section must
// be placed around the assigning of the pointers to pTblPtrs.
//
// 05-31-91 JulieB Created.
////////////////////////////////////////////////////////////////////////////
ULONG GetDefaultSortkeyFileInfo() { HANDLE hSec = (HANDLE)0; // section handle
UNICODE_STRING ObSecName; // section name
LPWORD pBaseAddr; // ptr to base address of section
ULONG rc = 0L; // return code
SECTION_BASIC_INFORMATION SecInfo; // section information - query
//
// Make sure we're in the critical section when entering this call.
//
ASSERT(NtCurrentTeb()->ClientId.UniqueThread == gcsTblPtrs.OwningThread);
//
// Open and Map a view of the section if it hasn't been done yet.
//
if (pTblPtrs->pDefaultSortkey != NULL) { return (NO_ERROR); }
ObSecName.Buffer = NLS_SECTION_SORTKEY; ObSecName.Length = sizeof (NLS_SECTION_SORTKEY) - sizeof (WCHAR); ObSecName.MaximumLength = ObSecName.Length; if (rc = OpenSection( &hSec, &ObSecName, (PVOID *)&pBaseAddr, SECTION_MAP_READ | SECTION_QUERY, FALSE )) { KdPrint(("NLSAPI: Could NOT Open Section %wZ - %lx.\n", &ObSecName, rc)); return (rc); }
//
// Query size of default section.
//
rc = NtQuerySection( hSec, SectionBasicInformation, &SecInfo, sizeof(SecInfo), NULL );
//
// Close the section handle.
//
NtClose(hSec);
//
// Check for error from NtQuerySection.
//
if (!NT_SUCCESS(rc)) { KdPrint(("NLSAPI: Could NOT Query Section %wZ - %lx.\n", &ObSecName, rc)); return (rc); }
//
// Get Default Sortkey Information.
//
pTblPtrs->pDefaultSortkey = (PSORTKEY)(pBaseAddr + SORTKEY_HEADER); pTblPtrs->DefaultSortkeySize = SecInfo.MaximumSize;
//
// Return success.
//
return (NO_ERROR); }
////////////////////////////////////////////////////////////////////////////
//
// GetDefaultSortTablesFileInfo
//
// Opens and Maps a view of the section for the sort tables. It then
// stores the pointers to the various tables in the global pointer table.
//
// NOTE: THIS ROUTINE SHOULD ONLY BE CALLED AT PROCESS STARTUP. If it is
// called from other than process startup, a critical section must
// be placed around the assigning of the pointers to pTblPtrs.
//
// 05-31-91 JulieB Created.
////////////////////////////////////////////////////////////////////////////
ULONG GetDefaultSortTablesFileInfo() { HANDLE hSec = (HANDLE)0; // section handle
UNICODE_STRING ObSecName; // section name
LPWORD pBaseAddr; // word ptr to base address of section
DWORD Num; // number of entries in table
PCOMPRESS_HDR pCompressHdr; // ptr to compression header
PEXCEPT_HDR pExceptHdr; // ptr to exception header
ULONG rc = 0L; // return code
//
// Make sure we're in the critical section when entering this call.
//
ASSERT(NtCurrentTeb()->ClientId.UniqueThread == gcsTblPtrs.OwningThread);
//
// Open and Map a view of the section if it hasn't been done yet.
//
// Since we're already in the critical section here, there is no
// need to check ALL of the pointers set in this routine. Just
// check one of them.
//
if (pTblPtrs->pReverseDW != NULL) { return (NO_ERROR); }
ObSecName.Buffer = NLS_SECTION_SORTTBLS; ObSecName.Length = sizeof (NLS_SECTION_SORTTBLS) - sizeof (WCHAR); ObSecName.MaximumLength = ObSecName.Length;
if (rc = OpenSection( &hSec, &ObSecName, (PVOID *)&pBaseAddr, SECTION_MAP_READ, TRUE )) { return (rc); }
pTblPtrs->pSortingTableFileBase = pBaseAddr; //
// Get Defined Code Point version Information.
//
pTblPtrs->NumDefinedVersion = Num = *((LPDWORD)pBaseAddr); pBaseAddr += NLSDEFINED_HEADER; if (Num > 0) { pTblPtrs->pDefinedVersion = (PDEFVERINFO)pBaseAddr; pBaseAddr += Num * sizeof(DEFVERINFO)/sizeof(WORD); } else { KdPrint(("NLSAPI: Appropriate Defined Code Point Table Not Loaded.\n")); pTblPtrs->pDefinedVersion = NULL; } //
// Get Sorting Version Information.
//
if ((pTblPtrs->NumSortVersion = *((LPDWORD)pBaseAddr)) > 0) { pTblPtrs->pSortVersion = (PSORTVERINFO)(pBaseAddr + SORTVERINFO_HEADER); } else { pTblPtrs->pSortVersion = NULL; } pBaseAddr += SORTVERINFO_HEADER + (pTblPtrs->NumSortVersion * (sizeof(SORTVERINFO) / sizeof(WORD)));
//
// Get Reverse Diacritic Information.
//
Num = *((LPDWORD)pBaseAddr); if (Num > 0) { pTblPtrs->NumReverseDW = Num; pTblPtrs->pReverseDW = (PREVERSE_DW)(pBaseAddr + REV_DW_HEADER); } pBaseAddr += REV_DW_HEADER + (Num * (sizeof(REVERSE_DW) / sizeof(WORD)));
//
// Get Double Compression Information.
//
Num = *((LPDWORD)pBaseAddr); if (Num > 0) { pTblPtrs->NumDblCompression = Num; pTblPtrs->pDblCompression = (PDBL_COMPRESS)(pBaseAddr + DBL_COMP_HEADER); } pBaseAddr += DBL_COMP_HEADER + (Num * (sizeof(DBL_COMPRESS) / sizeof(WORD)));
//
// Get Ideograph Lcid Exception Information.
//
Num = *((LPDWORD)pBaseAddr); if (Num > 0) { pTblPtrs->NumIdeographLcid = Num; pTblPtrs->pIdeographLcid = (PIDEOGRAPH_LCID)(pBaseAddr + IDEO_LCID_HEADER); } pBaseAddr += IDEO_LCID_HEADER + (Num * (sizeof(IDEOGRAPH_LCID) / sizeof(WORD)));
//
// Get Expansion Information.
//
Num = *((LPDWORD)pBaseAddr); if (Num > 0) { pTblPtrs->NumExpansion = Num; pTblPtrs->pExpansion = (PEXPAND)(pBaseAddr + EXPAND_HEADER); } pBaseAddr += EXPAND_HEADER + (Num * (sizeof(EXPAND) / sizeof(WORD)));
//
// Get Compression Information.
//
Num = *((LPDWORD)pBaseAddr); if (Num > 0) { pTblPtrs->NumCompression = Num; pTblPtrs->pCompressHdr = (PCOMPRESS_HDR)(pBaseAddr + COMPRESS_HDR_OFFSET); pTblPtrs->pCompression = (PCOMPRESS)(pBaseAddr + COMPRESS_HDR_OFFSET + (Num * (sizeof(COMPRESS_HDR) / sizeof(WORD)))); } pCompressHdr = pTblPtrs->pCompressHdr; pBaseAddr = (LPWORD)(pTblPtrs->pCompression) + (pCompressHdr[Num - 1]).Offset;
pBaseAddr += (((pCompressHdr[Num - 1]).Num2) * (sizeof(COMPRESS_2) / sizeof(WORD)));
pBaseAddr += (((pCompressHdr[Num - 1]).Num3) * (sizeof(COMPRESS_3) / sizeof(WORD)));
//
// Get Exception Information.
//
Num = *((LPDWORD)pBaseAddr); if (Num > 0) { pTblPtrs->NumException = Num; pTblPtrs->pExceptHdr = (PEXCEPT_HDR)(pBaseAddr + EXCEPT_HDR_OFFSET); pTblPtrs->pException = (PEXCEPT)(pBaseAddr + EXCEPT_HDR_OFFSET + (Num * (sizeof(EXCEPT_HDR) / sizeof(WORD)))); } pExceptHdr = pTblPtrs->pExceptHdr; pBaseAddr = (LPWORD)(pTblPtrs->pException) + (pExceptHdr[Num - 1]).Offset; pBaseAddr += (((pExceptHdr[Num - 1]).NumEntries) * (sizeof(EXCEPT) / sizeof(WORD)));
//
// Get Multiple Weights Information.
//
Num = (DWORD)(*pBaseAddr); if (Num > 0) { pTblPtrs->NumMultiWeight = Num; pTblPtrs->pMultiWeight = (PMULTI_WT)(pBaseAddr + MULTI_WT_HEADER); } pBaseAddr += MULTI_WT_HEADER + (Num * (sizeof(MULTI_WT) / sizeof(WORD)));
//
// Get Jamo Index Table.
//
Num = (DWORD)(*pBaseAddr); if (Num > 0) { //
// The Jamo Index table size is (Num) bytes.
//
pTblPtrs->NumJamoIndex = Num; pTblPtrs->pJamoIndex = (PJAMO_TABLE)(pBaseAddr + JAMO_INDEX_HEADER); } pBaseAddr += JAMO_INDEX_HEADER + (Num * (sizeof(JAMO_TABLE) / sizeof(WORD)));
//
// Get Jamo Composition State Machine Table.
//
Num = (DWORD)(*pBaseAddr); if (Num > 0) { pTblPtrs->NumJamoComposition = Num; pTblPtrs->pJamoComposition = (PJAMO_COMPOSE_STATE)(pBaseAddr + JAMO_COMPOSITION_HEADER); } //
// The following line is used to move pBaseAddr to the next field.
// Uncomment it if you are adding more fields.
//
// pBaseAddr += JAMO_COMPOSITION_HEADER + (Num * (sizeof(JAMO_COMPOSE_STATE) / sizeof(WORD)));
//
// Return success.
//
return (NO_ERROR); }
////////////////////////////////////////////////////////////////////////////
//
// GetSortkeyFileInfo
//
// Opens and Maps a view of the section for the sortkey file. It then
// fills in the appropriate field of the global table pointers structure.
//
// 05-31-91 JulieB Created.
////////////////////////////////////////////////////////////////////////////
ULONG GetSortkeyFileInfo( LCID Locale, PLOC_HASH pHashN) { HANDLE hSec = (HANDLE)0; // section handle
UNICODE_STRING ObSecName; // section name
LPWORD pBaseAddr; // ptr to base address of section
ULONG rc = 0L; // return code
PEXCEPT_HDR pExceptHdr; // ptr to exception header
PEXCEPT pExceptTbl; // ptr to exception table
PVOID pIdeograph; // ptr to ideograph exception table
WCHAR wszSecName[MAX_SMALL_BUF_LEN]; // Place for the section name string \
NTSTATUS Status;
//
// Make sure we're in the critical section when entering this call.
//
ASSERT(NtCurrentTeb()->ClientId.UniqueThread == gcsTblPtrs.OwningThread);
//
// Make sure the default sortkey table is loaded. If it's not, then
// we shouldn't bother to continue here since the sorting table won't
// be created properly. pHashN->pSortkey will already be NULL, so
// we don't need to set it. Return NO_ERROR here to allow kernel32
// to initialize in case this is winlogon.
//
if (pTblPtrs->pDefaultSortkey == NULL) { KdPrint(("NLSAPI: No Default Sorting Table Loaded.\n")); return (NO_ERROR); }
//
// Try to Open and Map a view of the section (read only).
//
GET_SORTKEY_SECTION_NAME(Locale, wszSecName, MAX_SMALL_BUF_LEN, &ObSecName);
if (rc = OpenSection( &hSec, &ObSecName, (PVOID *)&pBaseAddr, SECTION_MAP_READ, FALSE )) { //
// Open failed.
// See if any exceptions exist for given Locale ID.
//
rc = NO_ERROR; if (!FindExceptionPointers( Locale, &pExceptHdr, &pExceptTbl, &pIdeograph, &rc )) { //
// No exceptions for locale, so attach the default sortkey
// table pointer to the hash node and return success.
//
pHashN->pSortkey = pTblPtrs->pDefaultSortkey; return (NO_ERROR); } else { //
// See if an error occurred.
//
if (rc != NO_ERROR) { //
// This occurs if the ideograph exception file could not be
// created or mapped. Return an error in this case.
//
// return (rc);
//
// On second thought, don't return an error. Returning an
// error can cause kernel32 to not initialize (which, if this
// is winlogon, leads to an unbootable system). Let's just
// patch things up and move on.
//
// LATER -- log an error in the logfile.
//
pHashN->IfIdeographFailure = TRUE; pHashN->pSortkey = pTblPtrs->pDefaultSortkey; return (NO_ERROR); }
//
// Exceptions from default sortkey table exist for the given
// locale. Need to get the correct sortkey table.
// Create a section and call the server to lock it in.
//
Status = CsrBasepNlsCreateSection( NLS_CREATE_SORT_SECTION, Locale, &hSec );
//
// Check return from server call.
//
rc = (ULONG)Status;
if (!NT_SUCCESS(rc)) { if (hSec != NULL) { NtClose(hSec); } return (rc); }
//
// Map the section for ReadWrite.
//
if (rc = MapSection( hSec, (PVOID *)&pBaseAddr, PAGE_READWRITE, FALSE )) { NtClose(hSec); return (rc); }
//
// Copy the Default Sortkey Table to the New Section.
//
RtlMoveMemory( (PVOID)pBaseAddr, (PVOID)((LPWORD)(pTblPtrs->pDefaultSortkey) - SORTKEY_HEADER), (ULONG)(pTblPtrs->DefaultSortkeySize.LowPart) );
//
// Copy exception information to the table.
//
CopyExceptionInfo( (PSORTKEY)(pBaseAddr + SORTKEY_HEADER), pExceptHdr, pExceptTbl, pIdeograph);
//
// Write a 1 to the WORD semaphore (table may now be read).
//
*pBaseAddr = 1;
//
// Unmap the section for Write and remap it for Read.
//
if ((rc = UnMapSection(pBaseAddr)) || (rc = MapSection( hSec, (PVOID *)&pBaseAddr, PAGE_READONLY, FALSE ))) { NtClose(hSec); return (rc); } } }
//
// Close the section handle.
//
NtClose(hSec);
//
// Check semaphore bit in file. Make sure that the open
// succeeded AFTER all exceptions were added to the memory
// mapped section.
//
if (*pBaseAddr == 0) { //
// Another process is still adding the appropriate exception
// information. Must wait for its completion.
//
if (rc = WaitOnEvent(pBaseAddr)) { UnMapSection(pBaseAddr); return (rc); } }
//
// Save pointer in hash node.
//
pHashN->pSortkey = (PSORTKEY)(pBaseAddr + SORTKEY_HEADER);
//
// Return success.
//
return (NO_ERROR); }
////////////////////////////////////////////////////////////////////////////
//
// GetSortTablesFileInfo
//
// Stores the appropriate sort table pointers for the given locale in
// the given locale hash node.
//
// 05-31-91 JulieB Created.
////////////////////////////////////////////////////////////////////////////
void GetSortTablesFileInfo( LCID Locale, PLOC_HASH pHashN) { DWORD ctr; // loop counter
PREVERSE_DW pRevDW; // ptr to reverse diacritic table
PDBL_COMPRESS pDblComp; // ptr to double compression table
PCOMPRESS_HDR pCompHdr; // ptr to compression header
//
// Make sure we're in the critical section when entering this call.
//
ASSERT(NtCurrentTeb()->ClientId.UniqueThread == gcsTblPtrs.OwningThread);
//
// Check for Reverse Diacritic Locale.
//
pRevDW = pTblPtrs->pReverseDW; for (ctr = pTblPtrs->NumReverseDW; ctr > 0; ctr--, pRevDW++) { if (*pRevDW == (DWORD)Locale) { pHashN->IfReverseDW = TRUE; break; } }
//
// Check for Compression.
//
pCompHdr = pTblPtrs->pCompressHdr; for (ctr = pTblPtrs->NumCompression; ctr > 0; ctr--, pCompHdr++) { if (pCompHdr->Locale == (DWORD)Locale) { pHashN->IfCompression = TRUE; pHashN->pCompHdr = pCompHdr; if (pCompHdr->Num2 > 0) { pHashN->pCompress2 = (PCOMPRESS_2) (((LPWORD)(pTblPtrs->pCompression)) + (pCompHdr->Offset)); } if (pCompHdr->Num3 > 0) { pHashN->pCompress3 = (PCOMPRESS_3) (((LPWORD)(pTblPtrs->pCompression)) + (pCompHdr->Offset) + (pCompHdr->Num2 * (sizeof(COMPRESS_2) / sizeof(WORD)))); } break; } }
//
// Check for Double Compression.
//
if (pHashN->IfCompression) { pDblComp = pTblPtrs->pDblCompression; for (ctr = pTblPtrs->NumDblCompression; ctr > 0; ctr--, pDblComp++) { if (*pDblComp == (DWORD)Locale) { pHashN->IfDblCompression = TRUE; break; } } } }
////////////////////////////////////////////////////////////////////////////
//
// LoadCodePageAsDLL
//
// Try to load a code page as a DLL. If succeeded, the CodePage procedure
// is set.
//
// 05-27-99 SamerA Created.
////////////////////////////////////////////////////////////////////////////
ULONG LoadCodePageAsDLL( UINT CodePage, LPFN_CP_PROC *ppfnCPProc) { WCHAR pDllName[MAX_PATH_LEN]; // ptr to DLL name
HANDLE hModCPDll; // module handle of code page DLL
ULONG rc = ERROR_INVALID_PARAMETER; // return code
UINT ErrorMode; // error mode
//
// Get the DLL name to load.
//
pDllName[0] = 0; *ppfnCPProc = NULL; if (NO_ERROR == GetCodePageDLLPathName(CodePage, pDllName, MAX_PATH_LEN) && NlsIsDll(pDllName)) { //
// Load the DLL and get the procedure address.
// Turn off hard error popups.
//
ErrorMode = SetErrorMode(SEM_NOERROR); SetErrorMode(SEM_NOERROR | ErrorMode);
hModCPDll = LoadLibrary(pDllName);
SetErrorMode(ErrorMode);
if (hModCPDll) { *ppfnCPProc = (LPFN_CP_PROC)GetProcAddress( hModCPDll, NLS_CP_DLL_PROC_NAME ); }
if (*ppfnCPProc == NULL) { if (hModCPDll) { rc = TYPE_E_DLLFUNCTIONNOTFOUND; FreeLibrary(hModCPDll); } else { rc = TYPE_E_CANTLOADLIBRARY; } } else { rc = NO_ERROR; } }
return (rc); }
////////////////////////////////////////////////////////////////////////////
//
// GetCodePageFileInfo
//
// Opens and Maps a view of the section for the given code page. It then
// creates and inserts a hash node into the global CP hash table.
//
// If the section cannot be opened, it then queries the registry to see if
// the information has been added since the initialization of the DLL. If
// so, then it creates the section and then opens and maps a view of it.
//
// 05-31-91 JulieB Created.
////////////////////////////////////////////////////////////////////////////
ULONG GetCodePageFileInfo( UINT CodePage, PCP_HASH *ppNode) { HANDLE hSec = (HANDLE)0; // section handle
UNICODE_STRING ObSecName; // section name
LPWORD pBaseAddr = NULL; // ptr to base address of section
ULONG rc = 0L; // return code
BOOL IsDLL; // true if dll instead of data file
LPFN_CP_PROC pfnCPProc; // Code Page DLL Procedure
WCHAR wszSecName[MAX_SMALL_BUF_LEN]; // Place for the section name string \
//
// Make sure we're in the critical section when entering this call.
//
ASSERT(NtCurrentTeb()->ClientId.UniqueThread == gcsTblPtrs.OwningThread);
//
// See if we're dealing with a DLL or an NLS data file.
//
IsDLL = ((CodePage >= NLS_CP_DLL_RANGE) && (CodePage < NLS_CP_ALGORITHM_RANGE));
if (IsDLL) { //
// Try loading the codepage DLL
//
ULONG _rc = LoadCodePageAsDLL(CodePage, &pfnCPProc);
if (_rc) { if (ERROR_INVALID_PARAMETER == _rc) { //
// Not a valid DLL, try loading it as a normal data file
//
IsDLL = FALSE; } else { //
// Failed to load the DLL or can't find the function entry
// Return the error code
//
return (rc); } } }
if (!IsDLL) { //
// Open and Map a view of the section.
//
GET_CP_SECTION_NAME(CodePage, wszSecName, MAX_SMALL_BUF_LEN, &ObSecName);
rc = OpenSection( &hSec, &ObSecName, (PVOID *)&pBaseAddr, SECTION_MAP_READ, TRUE ); if (!NT_SUCCESS(rc)) { //
// Open failed, so try to create the section.
// If the creation is successful, the section will be mapped
// to the current process.
//
rc = CsrBasepNlsCreateSection(NLS_CREATE_CODEPAGE_SECTION, CodePage, &hSec );
if (NT_SUCCESS(rc)) { rc = MapSection( hSec, &pBaseAddr, PAGE_READONLY, TRUE ); // Close handle (even if fail)
}
if (!NT_SUCCESS(rc)) { //
// Allow the default ACP and default OEMCP to work if
// it's only the registry that is corrupt. If there is
// still an error, return the error code that was returned
// from the OpenSection call.
//
if (CodePage == NLS_DEFAULT_ACP) { //
// Create the default ACP section.
//
if (!NT_SUCCESS(CsrBasepNlsCreateSection(NLS_CREATE_SECTION_DEFAULT_ACP, 0, &hSec ))) { return (rc); } else { //
// Map the section.
//
if (!NT_SUCCESS(MapSection( hSec, (PVOID *)&pBaseAddr, PAGE_READONLY, TRUE ))) { return (rc); } KdPrint(("NLSAPI: Registry is corrupt - Default ACP.\n")); } } else if (CodePage == NLS_DEFAULT_OEMCP) { //
// Create the default OEMCP section.
//
if (!NT_SUCCESS(CsrBasepNlsCreateSection( NLS_CREATE_SECTION_DEFAULT_OEMCP, 0, &hSec ))) { return (rc); } else { //
// Map the section.
//
if (!NT_SUCCESS(MapSection( hSec, (PVOID *)&pBaseAddr, PAGE_READONLY, TRUE ))) { return (rc); } KdPrint(("NLSAPI: Registry is corrupt - Default OEMCP.\n")); } } else { //
// Return the error code that was returned from the
// OpenSection call.
//
return (rc); } } } }
//
// Make the hash node and return the result.
//
return (MakeCPHashNode( CodePage, pBaseAddr, ppNode, IsDLL, pfnCPProc )); }
////////////////////////////////////////////////////////////////////////////
//
// GetLanguageFileInfo
//
// Opens and Maps a view of the section for the casing tables and sorting
// tables for the given locale.
//
// If the section cannot be opened, it then queries the registry to see if
// the information has been added since the initialization of the DLL. If
// so, then it creates the section and then opens and maps a view of it.
//
// 05-31-91 JulieB Created.
////////////////////////////////////////////////////////////////////////////
ULONG GetLanguageFileInfo( LCID Locale, PLOC_HASH *ppNode, BOOLEAN fCreateNode, DWORD dwFlags) { LPWORD pBaseAddr = NULL; // ptr to base address of section
MEMORY_BASIC_INFORMATION MemoryBasicInfo;
//
// Make sure we're in the critical section when entering this call.
//
ASSERT(NtCurrentTeb()->ClientId.UniqueThread == gcsTblPtrs.OwningThread);
//
// See if the default language table has been stored yet.
//
if (pTblPtrs->pDefaultLanguage == NULL) { //
// Save the default language table and its size in the
// table pointers structure.
//
pTblPtrs->pDefaultLanguage = NtCurrentPeb()->UnicodeCaseTableData;
NtQueryVirtualMemory( NtCurrentProcess(), pTblPtrs->pDefaultLanguage, MemoryBasicInformation, &MemoryBasicInfo, sizeof(MEMORY_BASIC_INFORMATION), NULL ); pTblPtrs->LinguistLangSize.QuadPart = MemoryBasicInfo.RegionSize; ASSERT(MemoryBasicInfo.RegionSize > 0); }
//
// See if we should load the culturally correct language table.
//
if (dwFlags) { if (pTblPtrs->pLangException == NULL) { GetLanguageExceptionInfo(); }
//
// Get the default linguistic language table for the given locale.
//
pBaseAddr = GetLinguisticLanguageInfo(Locale); }
//
// Get the casing table and sorting table pointers.
//
return (MakeLangHashNode( Locale, pBaseAddr, ppNode, fCreateNode )); }
////////////////////////////////////////////////////////////////////////////
//
// GetLocaleFileInfo
//
// Opens and Maps a view of the section for the given locale. It then
// creates and inserts a hash node into the global LOCALE hash table.
//
// If the section cannot be opened, it then queries the registry to see if
// the information has been added since the initialization of the DLL. If
// so, then it creates the section and then opens and maps a view of it.
//
// 05-31-91 JulieB Created.
////////////////////////////////////////////////////////////////////////////
ULONG GetLocaleFileInfo( LCID Locale, PLOC_HASH *ppNode, BOOLEAN fCreateNode) { HANDLE hSec = (HANDLE)0; // section handle
UNICODE_STRING ObSecName; // section name
LPWORD pBaseAddr; // ptr to base address of section
ULONG rc = 0L; // return code
//
// Make sure we're in the critical section when entering this call.
//
ASSERT(NtCurrentTeb()->ClientId.UniqueThread == gcsTblPtrs.OwningThread);
//
// Open and Map a view of the section if it hasn't been done yet.
//
if ((pBaseAddr = pTblPtrs->pLocaleInfo) == NULL) { //
// Get the locale file section pointer.
//
ObSecName.Buffer = NLS_SECTION_LOCALE; ObSecName.Length = sizeof (NLS_SECTION_LOCALE) - sizeof (WCHAR); ObSecName.MaximumLength = ObSecName.Length;
if (rc = OpenSection( &hSec, &ObSecName, (PVOID *)&pBaseAddr, SECTION_MAP_READ, TRUE )) { return (rc); }
//
// Store pointer to locale file and calendar info in table
// structure.
//
pTblPtrs->pLocaleInfo = pBaseAddr;
pTblPtrs->NumCalendars = ((PLOC_CAL_HDR)pBaseAddr)->NumCalendars; pTblPtrs->pCalendarInfo = pBaseAddr + ((PLOC_CAL_HDR)pBaseAddr)->CalOffset; }
//
// Make the hash node and return the result.
//
return (MakeLocHashNode( Locale, pBaseAddr, ppNode, fCreateNode )); }
////////////////////////////////////////////////////////////////////////////
//
// MakeCPHashNode
//
// Creates the hash node for the code page and assigns the fields of the
// hash node to point at the appropriate places in the file.
//
// 05-31-91 JulieB Created.
////////////////////////////////////////////////////////////////////////////
ULONG MakeCPHashNode( UINT CodePage, LPWORD pBaseAddr, PCP_HASH *ppNode, BOOL IsDLL, LPFN_CP_PROC pfnCPProc) { PCP_HASH pHashN; // ptr to CP hash node
WORD offMB; // offset to MB table
WORD offWC; // offset to WC table
PGLYPH_TABLE pGlyph; // ptr to glyph table info
PDBCS_RANGE pRange; // ptr to DBCS range
//
// Allocate CP_HASH structure and fill in the CodePage value.
//
CREATE_CODEPAGE_HASH_NODE(CodePage, pHashN);
//
// See if we're dealing with a DLL or an NLS data file.
//
if (IsDLL) { if (pfnCPProc == NULL) { NLS_FREE_MEM(pHashN); return (ERROR_INVALID_PARAMETER); }
pHashN->pfnCPProc = pfnCPProc; } else { //
// Get the offsets.
//
offMB = pBaseAddr[0]; offWC = offMB + pBaseAddr[offMB];
//
// Attach CP Info to CP hash node.
//
pHashN->pCPInfo = (PCP_TABLE)(pBaseAddr + CP_HEADER);
//
// Attach MB table to CP hash node.
//
pHashN->pMBTbl = pBaseAddr + offMB + MB_HEADER;
//
// Attach Glyph table to CP hash node (if it exists).
// Also, set the pointer to the DBCS ranges based on whether or
// not the GLYPH table is present.
//
pGlyph = pHashN->pMBTbl + MB_TBL_SIZE; if (pGlyph[0] != 0) { pHashN->pGlyphTbl = pGlyph + GLYPH_HEADER; pRange = pHashN->pDBCSRanges = pHashN->pGlyphTbl + GLYPH_TBL_SIZE; } else { pRange = pHashN->pDBCSRanges = pGlyph + GLYPH_HEADER; }
//
// Attach DBCS information to CP hash node.
//
if (pRange[0] > 0) { //
// Set the pointer to the offsets section.
//
pHashN->pDBCSOffsets = pRange + DBCS_HEADER; }
//
// Attach WC table to CP hash node.
//
pHashN->pWC = pBaseAddr + offWC + WC_HEADER; }
//
// Insert hash node into hash table.
//
INSERT_CP_HASH_NODE(pHashN, pBaseAddr);
//
// Save the pointer to the hash node.
//
if (ppNode != NULL) { *ppNode = pHashN; }
//
// Return success.
//
return (NO_ERROR); }
////////////////////////////////////////////////////////////////////////////
//
// MakeLangHashNode
//
// Gets the pointers to the casing tables and the sorting tables and
// stores them in the locale hash node given.
//
// If fCreateNode is FALSE, then *ppNode should contain a valid pointer
// to a LOC hash node. Also, the table critical section must be entered
// before calling this routine.
//
// 05-31-91 JulieB Created.
////////////////////////////////////////////////////////////////////////////
ULONG MakeLangHashNode( LCID Locale, LPWORD pBaseAddr, PLOC_HASH *ppNode, BOOLEAN fCreateNode) { LPWORD pBaseDefault; // ptr to default language section
PLOC_HASH pHashN; // ptr to LOC hash node
ULONG rc = 0L; // return code
//
// If fCreateNode is TRUE, then allocate LOC_HASH structure.
//
if (fCreateNode) { CREATE_LOCALE_HASH_NODE(Locale, pHashN); } else { pHashN = *ppNode; }
//
// See if the sorting tables still need to be attached.
//
if (pHashN->pSortkey == NULL) { //
// Get the sortkey table and attach it to the hash node.
//
if (rc = GetSortkeyFileInfo(Locale, pHashN)) { if (fCreateNode) { NLS_FREE_MEM(pHashN); } return (rc); }
//
// Get the appropriate sorting tables for the locale.
//
GetSortTablesFileInfo(Locale, pHashN); }
//
// See if the default casing tables still need to be attached.
//
if (!EXIST_LANGUAGE_INFO(pHashN)) { //
// Get the pointer to the base of the default table.
//
pBaseDefault = pTblPtrs->pDefaultLanguage;
//
// Attach the UPPERCASE table to the hash node.
//
pHashN->pUpperCase = pBaseDefault + LANG_HEADER + UP_HEADER;
//
// Attach the LOWERCASE table to the hash node.
//
// This value must be set LAST, since this is the pointer that
// is checked to see that the language information has been
// initialized.
//
pHashN->pLowerCase = pBaseDefault + LANG_HEADER + pBaseDefault[LANG_HEADER] + LO_HEADER; }
//
// See if there is a linguistic table to attach.
//
if (pBaseAddr) { //
// Attach the UPPERCASE Linguistic table to the hash node.
//
pHashN->pUpperLinguist = pBaseAddr + LANG_HEADER + UP_HEADER;
//
// Attach the LOWERCASE Linguistic table to the hash node.
//
// This value must be set LAST, since this is the pointer that
// is checked to see that the language information has been
// initialized.
//
pHashN->pLowerLinguist = pBaseAddr + LANG_HEADER + pBaseAddr[LANG_HEADER] + LO_HEADER; }
//
// If fCreateNode is TRUE, then insert hash node and save pointer.
//
if (fCreateNode) { //
// Insert LOC hash node into hash table.
//
INSERT_LOC_HASH_NODE(pHashN, pBaseAddr);
//
// Save the pointer to the hash node.
//
if (ppNode != NULL) { *ppNode = pHashN; } }
//
// Return success.
//
return (NO_ERROR); }
////////////////////////////////////////////////////////////////////////////
//
// MakeLocHashNode
//
// Gets the pointers to the locale tables and stores them in the locale
// hash node given.
//
// NOTE: If a critical section is needed to touch pHashN, then the
// critical section must be entered before calling this routine.
//
// 05-31-91 JulieB Created.
////////////////////////////////////////////////////////////////////////////
ULONG MakeLocHashNode( LCID Locale, LPWORD pBaseAddr, PLOC_HASH *ppNode, BOOLEAN fCreateNode) { LANGID Language; // language id
PLOC_HASH pHashN; // ptr to LOC hash node
DWORD Num; // total number of locales
PLOCALE_HDR pFileHdr; // ptr to locale header entry
ULONG rc = 0L; // return code
//
// Save the language id.
//
Language = LANGIDFROMLCID(Locale);
//
// Search for the right locale id information.
//
Num = ((PLOC_CAL_HDR)pBaseAddr)->NumLocales; pFileHdr = (PLOCALE_HDR)(pBaseAddr + LOCALE_HDR_OFFSET); for (; (Num != 0) && (pFileHdr->Locale != Language); Num--, pFileHdr++) ;
//
// See if the locale was found in the file.
//
if (Num != 0) { //
// Locale id was found, so increment the pointer to point at
// the beginning of the locale information.
//
pBaseAddr += pFileHdr->Offset; } else { //
// Return an error. The given locale is not supported.
//
return (ERROR_INVALID_PARAMETER); }
//
// If fCreateNode is TRUE, then allocate LOC_HASH structure.
//
if (fCreateNode) { CREATE_LOCALE_HASH_NODE(Locale, pHashN); } else { pHashN = *ppNode; }
//
// Attach Information to structure.
//
// The pLocaleFixed value must be set LAST, since this is the pointer
// that is checked to see that the locale information has been
// initialized.
//
pHashN->pLocaleHdr = (PLOCALE_VAR)pBaseAddr; pHashN->pLocaleFixed = (PLOCALE_FIXED)(pBaseAddr + (sizeof(LOCALE_VAR) / sizeof(WORD)));
//
// If fCreateNode is TRUE, then insert hash node and save pointer.
//
if (fCreateNode) { //
// Insert LOC hash node into hash table.
//
INSERT_LOC_HASH_NODE(pHashN, pBaseAddr);
//
// Save the pointer to the hash node.
//
if (ppNode != NULL) { *ppNode = pHashN; } }
//
// Return success.
//
return (NO_ERROR); }
////////////////////////////////////////////////////////////////////////////
//
// GetCPHashNode
//
// Returns a pointer to the appropriate CP hash node given the codepage.
// If no table could be found for the given codepage, NULL is returned.
//
// 05-31-91 JulieB Created.
////////////////////////////////////////////////////////////////////////////
PCP_HASH FASTCALL GetCPHashNode( UINT CodePage) { PCP_HASH pHashN; // ptr to CP hash node
//
// Get hash node.
//
FIND_CP_HASH_NODE(CodePage, pHashN);
//
// If the hash node does not exist, try to get the tables
// from the appropriate data file.
//
// NOTE: No need to check error code from GetCodePageFileInfo,
// because pHashN is not touched if there was an
// error. Thus, pHashN will still be NULL, and an
// "error" will be returned from this routine.
//
if (pHashN == NULL) { //
// Hash node does NOT exist.
//
RtlEnterCriticalSection(&gcsTblPtrs); FIND_CP_HASH_NODE(CodePage, pHashN); if (pHashN == NULL) { GetCodePageFileInfo(CodePage, &pHashN); } RtlLeaveCriticalSection(&gcsTblPtrs); }
//
// Return pointer to hash node.
//
return (pHashN); }
////////////////////////////////////////////////////////////////////////////
//
// GetLangHashNode
//
// Returns a pointer to the appropriate LOC hash node given the locale.
// If no table could be found for the given locale, NULL is returned.
//
// 05-31-91 JulieB Created.
////////////////////////////////////////////////////////////////////////////
PLOC_HASH FASTCALL GetLangHashNode( LCID Locale, DWORD dwFlags) { PLOC_HASH pHashN; // ptr to LOC hash node
//
// Get hash node.
//
FIND_LOCALE_HASH_NODE(Locale, pHashN);
//
// If the hash node does not exist, try to get the tables
// from the appropriate data file.
//
// NOTE: No need to check error code from GetLanguageFileInfo,
// because pHashN is not touched if there was an
// error. Thus, pHashN will still be NULL, and an
// "error" will be returned from this routine.
//
if (pHashN == NULL) { //
// If a sort id exists, make sure it's valid.
//
if (SORTIDFROMLCID(Locale)) { if (!IsValidSortId(Locale)) { return (NULL); } }
//
// Hash node does NOT exist.
//
RtlEnterCriticalSection(&gcsTblPtrs); FIND_LOCALE_HASH_NODE(Locale, pHashN); if (pHashN == NULL) { //
// Hash node still does NOT exist.
//
GetLanguageFileInfo(Locale, &pHashN, TRUE, dwFlags); RtlLeaveCriticalSection(&gcsTblPtrs); return (pHashN); } RtlLeaveCriticalSection(&gcsTblPtrs); }
//
// Hash node DOES exist.
//
if (!EXIST_LANGUAGE_INFO(pHashN) || ((dwFlags != 0) && !EXIST_LINGUIST_LANGUAGE_INFO(pHashN))) { //
// Casing tables and sorting tables not yet stored in
// hash node.
//
RtlEnterCriticalSection(&gcsTblPtrs); if (!EXIST_LANGUAGE_INFO(pHashN) || ((dwFlags != 0) && !EXIST_LINGUIST_LANGUAGE_INFO(pHashN))) { if (GetLanguageFileInfo(Locale, &pHashN, FALSE, dwFlags)) { RtlLeaveCriticalSection(&gcsTblPtrs); return (NULL); } } RtlLeaveCriticalSection(&gcsTblPtrs); }
//
// Return pointer to hash node.
//
return (pHashN); }
////////////////////////////////////////////////////////////////////////////
//
// GetLocHashNode
//
// Returns a pointer to the appropriate LOC hash node given the locale.
// If no table could be found for the given locale, NULL is returned.
//
// 05-31-91 JulieB Created.
////////////////////////////////////////////////////////////////////////////
PLOC_HASH FASTCALL GetLocHashNode( LCID Locale) { PLOC_HASH pHashN; // ptr to LOC hash node
//
// Get hash node.
//
FIND_LOCALE_HASH_NODE(Locale, pHashN);
//
// If the hash node does not exist, try to get the table
// from locale.nls.
//
// NOTE: No need to check error code from GetLocaleFileInfo,
// because pHashN is not touched if there was an
// error. Thus, pHashN will still be NULL, and an
// "error" will be returned from this routine.
//
if (pHashN == NULL) { //
// If a sort id exists, make sure it's valid.
//
if (SORTIDFROMLCID(Locale)) { if (!IsValidSortId(Locale)) { return (NULL); } }
//
// Hash node does NOT exist.
//
RtlEnterCriticalSection(&gcsTblPtrs); FIND_LOCALE_HASH_NODE(Locale, pHashN); if (pHashN == NULL) { //
// Hash node still does NOT exist.
//
GetLocaleFileInfo(Locale, &pHashN, TRUE); RtlLeaveCriticalSection(&gcsTblPtrs); return (pHashN); } RtlLeaveCriticalSection(&gcsTblPtrs); }
//
// Hash node DOES exist.
//
if (!EXIST_LOCALE_INFO(pHashN)) { //
// Locale tables not yet stored in hash node.
//
RtlEnterCriticalSection(&gcsTblPtrs); if (!EXIST_LOCALE_INFO(pHashN)) { if (GetLocaleFileInfo(Locale, &pHashN, FALSE)) { RtlLeaveCriticalSection(&gcsTblPtrs); return (NULL); } } RtlLeaveCriticalSection(&gcsTblPtrs); }
//
// Return pointer to hash node.
//
return (pHashN); }
////////////////////////////////////////////////////////////////////////////
//
// GetCalendar
//
// Gets the pointer to the specific calendar table. It stores it in the
// calendar information array in the global table pointers structure if it
// was not done yet.
//
// 05-31-91 JulieB Created.
////////////////////////////////////////////////////////////////////////////
ULONG GetCalendar( CALID Calendar, PCAL_INFO *ppCalInfo) { PCALENDAR_HDR pCalHdr; // ptr to beginning of calendar header
DWORD Num; // total number of calendars
//
// Get number of calendars.
//
Num = pTblPtrs->NumCalendars;
//
// Make sure calendar id is within the appropriate range.
//
if (Calendar > Num) { return (ERROR_INVALID_PARAMETER); }
//
// Check to see if calendar info has already been found.
//
if ((*ppCalInfo = (pTblPtrs->pCalTbl)[Calendar]) != NULL) { //
// Return success. Calendar info was found.
//
return (NO_ERROR); }
RtlEnterCriticalSection(&gcsTblPtrs);
if ((*ppCalInfo = (pTblPtrs->pCalTbl)[Calendar]) != NULL) { //
// Return success. Calendar info was found.
//
RtlLeaveCriticalSection(&gcsTblPtrs); return (NO_ERROR); }
//
// Search for the appropriate calendar id information.
//
pCalHdr = (PCALENDAR_HDR)(pTblPtrs->pCalendarInfo); while ((Num != 0) && (pCalHdr->Calendar != Calendar)) { Num--; pCalHdr++; }
//
// See if the calendar was found in the file.
//
if (Num != 0) { //
// Calendar id was found.
//
// Store the pointer to the beginning of the calendar info
// in the calendar table array.
//
*ppCalInfo = (PCAL_INFO)((LPWORD)(pTblPtrs->pCalendarInfo) + pCalHdr->Offset); (pTblPtrs->pCalTbl)[Calendar] = *ppCalInfo;
//
// Return success. Calendar info was found.
//
RtlLeaveCriticalSection(&gcsTblPtrs); return (NO_ERROR); }
RtlLeaveCriticalSection(&gcsTblPtrs);
//
// Calendar id was not found in the locale.nls file.
// Return an error. The given calendar is not supported.
//
return (ERROR_INVALID_PARAMETER); }
//-------------------------------------------------------------------------//
// INTERNAL ROUTINES //
//-------------------------------------------------------------------------//
////////////////////////////////////////////////////////////////////////////
//
// IsValidSortId
//
// Checks to see if the given locale has a valid sort id.
//
// 11-15-96 JulieB Created.
////////////////////////////////////////////////////////////////////////////
BOOL IsValidSortId( LCID Locale) { WCHAR pTmpBuf[MAX_PATH]; // temp buffer
PKEY_VALUE_FULL_INFORMATION pKeyValueFull; // ptr to query info
BYTE pStatic[MAX_KEY_VALUE_FULLINFO]; // ptr to static buffer
BOOL IfAlloc = FALSE; // if buffer was allocated
ULONG rc = 0L; // return code
//
// Make sure there is a sort id.
//
if (!SORTIDFROMLCID(Locale)) { return (TRUE); }
//
// Open the Alternate Sorts registry key.
//
OPEN_ALT_SORTS_KEY(FALSE);
//
// Convert locale value to Unicode string.
//
if (NlsConvertIntegerToString(Locale, 16, 8, pTmpBuf, MAX_PATH)) { return (FALSE); }
//
// Query the registry for the value.
//
pKeyValueFull = (PKEY_VALUE_FULL_INFORMATION)pStatic; if (rc = QueryRegValue( hAltSortsKey, pTmpBuf, &pKeyValueFull, MAX_KEY_VALUE_FULLINFO, &IfAlloc )) { return (FALSE); }
//
// Free the buffer used for the query.
//
if (IfAlloc) { NLS_FREE_MEM(pKeyValueFull); }
//
// Return success.
//
return (TRUE); }
////////////////////////////////////////////////////////////////////////////
//
// GetLanguageExceptionInfo
//
// Opens and Maps a view of the section for the language exception file.
// It then fills in the appropriate fields of the global table pointers
// structure.
//
// 08-30-95 JulieB Created.
////////////////////////////////////////////////////////////////////////////
ULONG GetLanguageExceptionInfo() { HANDLE hSec = (HANDLE)0; // section handle
LPWORD pBaseAddr; // ptr to base address of section
DWORD Num; // number of entries in table
ULONG rc = 0L; // return code
//
// Make sure we're in the critical section when entering this call.
//
ASSERT(NtCurrentTeb()->ClientId.UniqueThread == gcsTblPtrs.OwningThread);
//
// Make sure the table isn't already there.
//
if (pTblPtrs->pLangException != NULL) { return (NO_ERROR); }
//
// Create and map the section, and then save the pointer.
//
if ((rc = CsrBasepNlsCreateSection( NLS_CREATE_SECTION_LANG_EXCEPT, 0, &hSec )) == NO_ERROR) { //
// Map a View of the Section.
//
if ((rc = MapSection( hSec, &pBaseAddr, PAGE_READONLY, TRUE )) != NO_ERROR) { return (rc); } } else { return (rc); }
//
// Save the pointers to the exception information.
//
Num = *((LPDWORD)pBaseAddr); if (Num > 0) { pTblPtrs->NumLangException = Num; pTblPtrs->pLangExceptHdr = (PL_EXCEPT_HDR)(pBaseAddr + L_EXCEPT_HDR_OFFSET); pTblPtrs->pLangException = (PL_EXCEPT)(pBaseAddr + L_EXCEPT_HDR_OFFSET + (Num * (sizeof(L_EXCEPT_HDR) / sizeof(WORD)))); }
//
// Return success.
//
return (NO_ERROR); }
////////////////////////////////////////////////////////////////////////////
//
// GetLinguisticLanguageInfo
//
// Opens and Maps a view of the section for the default linguistic language
// table. It then stores the pointer to the table in the global pointer
// table.
//
// 08-30-95 JulieB Created.
////////////////////////////////////////////////////////////////////////////
LPWORD GetLinguisticLanguageInfo( LCID Locale) { HANDLE hSec = (HANDLE)0; // section handle
UNICODE_STRING ObSecName; // section name
LPWORD pBaseAddr; // ptr to base address of section
ULONG rc = 0L; // return code
SECTION_BASIC_INFORMATION SecInfo; // section information - query
//
// Make sure we're in the critical section when entering this call.
//
ASSERT(NtCurrentTeb()->ClientId.UniqueThread == gcsTblPtrs.OwningThread);
//
// Create/Open and Map a view of the section if it hasn't been done yet.
//
if (pTblPtrs->pLinguistLanguage == NULL) { //
// See if we can simply open the section.
//
RtlInitUnicodeString(&ObSecName, NLS_SECTION_LANG_INTL); if (rc = OpenSection( &hSec, &ObSecName, (PVOID *)&pBaseAddr, SECTION_MAP_READ, TRUE )) { //
// Need to create the default linguistic language section.
//
if (CreateAndCopyLanguageExceptions(0L, &pBaseAddr)) { return (NULL); } }
//
// Get Default Linguistic Language Information.
//
pTblPtrs->pLinguistLanguage = (P844_TABLE)(pBaseAddr); }
//
// Now see if there are any exceptions for the given locale.
//
if (CreateAndCopyLanguageExceptions(Locale, &pBaseAddr)) { return (pTblPtrs->pLinguistLanguage); }
//
// Return success.
//
return (pBaseAddr); }
////////////////////////////////////////////////////////////////////////////
//
// CreateAndCopyLanguageExceptions
//
// Creates the section for the new language table (if necessary) and then
// copies the exceptions to the table.
//
// 08-30-95 JulieB Created.
////////////////////////////////////////////////////////////////////////////
ULONG CreateAndCopyLanguageExceptions( LCID Locale, LPWORD *ppBaseAddr)
{ HANDLE hSec = (HANDLE)0; // section handle
UNICODE_STRING ObSecName; // section name
LPWORD pBaseAddr; // ptr to base address of section
P844_TABLE pLangDefault; // ptr to default table to copy from
ULONG rc = 0L; // return code
PL_EXCEPT_HDR pExceptHdr; // ptr to exception header
PL_EXCEPT pExceptTbl; // ptr to exception table
WCHAR wszSecName[MAX_SMALL_BUF_LEN]; // Place for the section name string \
NTSTATUS Status;
//
// Make sure we're in the critical section when entering this call.
//
ASSERT(NtCurrentTeb()->ClientId.UniqueThread == gcsTblPtrs.OwningThread);
if (Locale == 0) { //
// Creating the default section.
//
RtlInitUnicodeString(&ObSecName, NLS_SECTION_LANG_INTL); pLangDefault = pTblPtrs->pDefaultLanguage;
} else { GET_LANG_SECTION_NAME(Locale, wszSecName, MAX_SMALL_BUF_LEN, &ObSecName); pLangDefault = pTblPtrs->pLinguistLanguage; }
//
// Try to Open and Map a view of the section (read only).
//
if (rc = OpenSection( &hSec, &ObSecName, (PVOID *)&pBaseAddr, SECTION_MAP_READ, FALSE )) { //
// Open failed.
// See if any exceptions exist for given Locale ID.
//
if (!FindLanguageExceptionPointers( Locale, &pExceptHdr, &pExceptTbl ) && (Locale != 0)) { //
// No exceptions for locale and we're not trying to create
// the default table, so return the pointer to the default
// table (which should always be created at this point).
//
*ppBaseAddr = pTblPtrs->pLinguistLanguage; return (NO_ERROR); } else { //
// Exceptions exist for the given locale. Need to create the
// new section (and call the server to make it permanent).
//
Status = CsrBasepNlsCreateSection( NLS_CREATE_LANG_EXCEPTION_SECTION, Locale, &hSec ); //
// Check return from server call.
//
rc = (ULONG)Status;
if (!NT_SUCCESS(rc)) { if (hSec != NULL) { NtClose(hSec); } return (rc); }
//
// Map the section for ReadWrite.
//
if (rc = MapSection( hSec, (PVOID *)&pBaseAddr, PAGE_READWRITE, FALSE )) { NtClose(hSec); return (rc); }
//
// Put a 0 in the semaphore part to denote that the file
// is not ready yet.
//
*pBaseAddr = 0;
//
// Copy the Default Language Table to the New Section.
//
RtlMoveMemory( (PVOID)((LPWORD)pBaseAddr + LANG_HEADER), (PVOID)((LPWORD)(pLangDefault) + LANG_HEADER), (ULONG)(pTblPtrs->LinguistLangSize.LowPart - (LANG_HEADER * sizeof(WORD))) );
//
// Copy exception information to the table.
//
CopyLanguageExceptionInfo( pBaseAddr, pExceptHdr, pExceptTbl );
//
// Write a 1 to the WORD semaphore (table may now be read).
//
*pBaseAddr = 1;
//
// Unmap the section for Write and remap it for Read.
//
if ((rc = UnMapSection(pBaseAddr)) || (rc = MapSection( hSec, (PVOID *)&pBaseAddr, PAGE_READONLY, FALSE ))) { NtClose(hSec); return (rc); } } }
//
// Close the section handle.
//
NtClose(hSec);
//
// Check semaphore bit in file. Make sure that the open
// succeeded AFTER all exceptions were added to the memory
// mapped section.
//
if (*pBaseAddr == 0) { //
// Another process is still adding the appropriate exception
// information. Must wait for its completion.
//
if (rc = WaitOnEvent(pBaseAddr)) { UnMapSection(pBaseAddr); return (rc); } }
//
// Return the pointer to the section.
//
*ppBaseAddr = pBaseAddr;
//
// Return success.
//
return (NO_ERROR); }
////////////////////////////////////////////////////////////////////////////
//
// FindLanguageExceptionPointers
//
// Checks to see if any exceptions exist for the given locale id. If
// exceptions exist, then TRUE is returned and the pointer to the exception
// header and the pointer to the exception table are stored in the given
// parameters.
//
// 08-30-95 JulieB Created.
////////////////////////////////////////////////////////////////////////////
BOOL FASTCALL FindLanguageExceptionPointers( LCID Locale, PL_EXCEPT_HDR *ppExceptHdr, PL_EXCEPT *ppExceptTbl) { DWORD ctr; // loop counter
PL_EXCEPT_HDR pHdr; // ptr to exception header
BOOL rc = FALSE; // return value
//
// Make sure we're in the critical section when entering this call.
//
ASSERT(NtCurrentTeb()->ClientId.UniqueThread == gcsTblPtrs.OwningThread);
//
// Initialize pointers.
//
*ppExceptHdr = NULL; *ppExceptTbl = NULL;
//
// Need to search down the exception header for the given locale.
//
pHdr = pTblPtrs->pLangExceptHdr; for (ctr = pTblPtrs->NumLangException; ctr > 0; ctr--, pHdr++) { if (pHdr->Locale == (DWORD)Locale) { //
// Found the locale id, so set the pointers.
//
*ppExceptHdr = pHdr; *ppExceptTbl = (PL_EXCEPT)(((LPWORD)(pTblPtrs->pLangException)) + pHdr->Offset);
//
// Set the return code for success.
//
rc = TRUE; break; } }
//
// Return the value in rc.
//
return (rc); }
////////////////////////////////////////////////////////////////////////////
//
// CopyLanguageExceptionInfo
//
// Copies the language exception information to the given language table.
//
// 08-30-95 JulieB Created.
////////////////////////////////////////////////////////////////////////////
void FASTCALL CopyLanguageExceptionInfo( LPWORD pBaseAddr, PL_EXCEPT_HDR pExceptHdr, PL_EXCEPT pExceptTbl) { DWORD ctr; // loop counter
P844_TABLE pUpCase; // ptr to upper case table
P844_TABLE pLoCase; // ptr to lower case table
//
// Make sure we're in the critical section when entering this call.
//
ASSERT(NtCurrentTeb()->ClientId.UniqueThread == gcsTblPtrs.OwningThread);
if (pExceptTbl) { //
// Get the pointers to the upper and lower case table.
//
pUpCase = pBaseAddr + LANG_HEADER + UP_HEADER; pLoCase = pBaseAddr + LANG_HEADER + pBaseAddr[LANG_HEADER] + LO_HEADER;
//
// For each entry in the exception table, copy the information to the
// sortkey table.
//
for (ctr = pExceptHdr->NumUpEntries; ctr > 0; ctr--, pExceptTbl++) { TRAVERSE_844_W(pUpCase, pExceptTbl->UCP) = pExceptTbl->AddAmount; } for (ctr = pExceptHdr->NumLoEntries; ctr > 0; ctr--, pExceptTbl++) { TRAVERSE_844_W(pLoCase, pExceptTbl->UCP) = pExceptTbl->AddAmount; } } }
////////////////////////////////////////////////////////////////////////////
//
// FindExceptionPointers
//
// Checks to see if any exceptions exist for the given locale id. If
// exceptions exist, then TRUE is returned and the pointer to the exception
// header and the pointer to the exception table are stored in the given
// parameters.
//
// 05-31-91 JulieB Created.
////////////////////////////////////////////////////////////////////////////
BOOL FASTCALL FindExceptionPointers( LCID Locale, PEXCEPT_HDR *ppExceptHdr, PEXCEPT *ppExceptTbl, PVOID *ppIdeograph, PULONG pReturn) { HANDLE hSec = (HANDLE)0; // section handle
DWORD ctr; // loop counter
PEXCEPT_HDR pHdr; // ptr to exception header
BOOL bFound = FALSE; // if an exception is found
PIDEOGRAPH_LCID pIdeoLcid; // ptr to ideograph lcid entry
PVOID pBaseAddr; // ptr to base address of section
//
// Make sure we're in the critical section when entering this call.
//
ASSERT(NtCurrentTeb()->ClientId.UniqueThread == gcsTblPtrs.OwningThread);
//
// Initialize pointers.
//
*ppExceptHdr = NULL; *ppExceptTbl = NULL; *ppIdeograph = NULL; *pReturn = NO_ERROR;
//
// Need to search down the exception header for the given locale.
//
pHdr = pTblPtrs->pExceptHdr; for (ctr = pTblPtrs->NumException; ctr > 0; ctr--, pHdr++) { if (pHdr->Locale == (DWORD)Locale) { //
// Found the locale id, so set the pointers.
//
*ppExceptHdr = pHdr; *ppExceptTbl = (PEXCEPT)(((LPWORD)(pTblPtrs->pException)) + pHdr->Offset);
//
// Set the return code to show that an exception has been
// found.
//
bFound = TRUE; break; } }
//
// Need to search down the ideograph lcid exception list for the
// given locale.
//
pIdeoLcid = pTblPtrs->pIdeographLcid; for (ctr = pTblPtrs->NumIdeographLcid; ctr > 0; ctr--, pIdeoLcid++) { if (pIdeoLcid->Locale == (DWORD)Locale) { //
// Found the locale id, so create/open and map the section
// for the appropriate file.
//
if (*pReturn = CreateSectionTemp(&hSec, pIdeoLcid->pFileName)) { //
// Ideograph file section could not be created, so return
// the error.
//
return (TRUE); } if (*pReturn = MapSection(hSec, &pBaseAddr, PAGE_READONLY, TRUE)) { //
// Ideograph file section could not be mapped, so close
// the created section and return the error.
//
NtClose(hSec); return (TRUE); }
//
// Set the pointer to the ideograph information.
//
*ppIdeograph = pBaseAddr;
//
// Set the return code to show that an exception has been
// found.
//
bFound = TRUE; break; } }
//
// Return the appropriate value.
//
return (bFound); }
////////////////////////////////////////////////////////////////////////////
//
// CopyExceptionInfo
//
// Copies the exception information to the given sortkey table.
//
// 05-31-91 JulieB Created.
////////////////////////////////////////////////////////////////////////////
void FASTCALL CopyExceptionInfo( PSORTKEY pSortkey, PEXCEPT_HDR pExceptHdr, PEXCEPT pExceptTbl, PVOID pIdeograph) { DWORD ctr; // loop counter
PIDEOGRAPH_EXCEPT_HDR pHdrIG; // ptr to ideograph exception header
PIDEOGRAPH_EXCEPT pEntryIG; // ptr to ideograph exception entry
PEXCEPT pEntryIGEx; // ptr to ideograph exception entry ex
//
// Make sure we're in the critical section when entering this call.
//
ASSERT(NtCurrentTeb()->ClientId.UniqueThread == gcsTblPtrs.OwningThread);
//
// For each entry in the exception table, copy the information to the
// sortkey table.
//
if (pExceptTbl) { for (ctr = pExceptHdr->NumEntries; ctr > 0; ctr--, pExceptTbl++) { (pSortkey[pExceptTbl->UCP]).UW.Unicode = pExceptTbl->Unicode; (pSortkey[pExceptTbl->UCP]).Diacritic = pExceptTbl->Diacritic; (pSortkey[pExceptTbl->UCP]).Case = pExceptTbl->Case; } }
//
// For each entry in the ideograph exception table, copy the
// information to the sortkey table.
//
if (pIdeograph) { pHdrIG = (PIDEOGRAPH_EXCEPT_HDR)pIdeograph; ctr = pHdrIG->NumEntries;
if (pHdrIG->NumColumns == 2) { pEntryIG = (PIDEOGRAPH_EXCEPT)( ((LPBYTE)pIdeograph) + sizeof(IDEOGRAPH_EXCEPT_HDR) ); for (; ctr > 0; ctr--, pEntryIG++) { (pSortkey[pEntryIG->UCP]).UW.Unicode = pEntryIG->Unicode; } } else { pEntryIGEx = (PEXCEPT)( ((LPBYTE)pIdeograph) + sizeof(IDEOGRAPH_EXCEPT_HDR) ); for (; ctr > 0; ctr--, pEntryIGEx++) { (pSortkey[pEntryIGEx->UCP]).UW.Unicode = pEntryIGEx->Unicode; (pSortkey[pEntryIGEx->UCP]).Diacritic = pEntryIGEx->Diacritic; (pSortkey[pEntryIGEx->UCP]).Case = pEntryIGEx->Case; } }
//
// Unmap and Close the ideograph section.
//
UnMapSection(pIdeograph); } }
////////////////////////////////////////////////////////////////////////////
//
// WaitOnEvent
//
// Waits (via timeout) for the semaphore dword to be set to a non-zero
// value.
//
// 05-31-91 JulieB Created.
////////////////////////////////////////////////////////////////////////////
ULONG WaitOnEvent( LPWORD pSem) { TIME TimeOut; // ptr to timeout
//
// Set up the TIME structure.
//
TimeOut.QuadPart = -100000;
//
// Wait on the event until the semaphore is set to non-zero.
// Use a timeout on the wait.
//
do { NtDelayExecution(FALSE, &TimeOut);
} while (*pSem == 0);
//
// Return success.
//
return (NO_ERROR); }
|