📄 nls.c
字号:
/* $Id: nls.c 26836 2007-05-19 10:11:48Z dgorbachev $
*
* COPYRIGHT: See COPYING in the top level directory
* PROJECT: ReactOS system libraries
* FILE: dll/win32/kernel32/misc/nls.c
* PURPOSE: National Language Support
* PROGRAMMER: Filip Navara
* Hartmut Birr
* Gunnar Andre Dalsnes
* Thomas Weidenmueller
* UPDATE HISTORY:
* Created 24/08/2004
*/
/* INCLUDES *******************************************************************/
#include <k32.h>
#define NDEBUG
#include "../include/debug.h"
/* GLOBAL VARIABLES ***********************************************************/
typedef struct _CODEPAGE_ENTRY
{
LIST_ENTRY Entry;
UINT CodePage;
HANDLE SectionHandle;
PBYTE SectionMapping;
CPTABLEINFO CodePageTable;
} CODEPAGE_ENTRY, *PCODEPAGE_ENTRY;
/* Sequence length based on the first character. */
static const char UTF8Length[128] =
{
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x80 - 0x8F */
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x90 - 0x9F */
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0xA0 - 0xAF */
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0xB0 - 0xBF */
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 0xC0 - 0xCF */
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 0xD0 - 0xDF */
2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, /* 0xE0 - 0xEF */
3, 3, 3, 3, 3, 3, 3, 3, 4, 4, 4, 4, 5, 5, 0, 0 /* 0xF0 - 0xFF */
};
/* First byte mask depending on UTF-8 sequence length. */
static const unsigned char UTF8Mask[6] = {0x7f, 0x1f, 0x0f, 0x07, 0x03, 0x01};
/* FIXME: Change to HASH table or linear array. */
static LIST_ENTRY CodePageListHead;
static CODEPAGE_ENTRY AnsiCodePage;
static CODEPAGE_ENTRY OemCodePage;
static RTL_CRITICAL_SECTION CodePageListLock;
/* FORWARD DECLARATIONS *******************************************************/
BOOL STDCALL
GetNlsSectionName(UINT CodePage, UINT Base, ULONG Unknown,
LPSTR BaseName, LPSTR Result, ULONG ResultSize);
BOOL STDCALL
GetCPFileNameFromRegistry(UINT CodePage, LPWSTR FileName, ULONG FileNameSize);
/* PRIVATE FUNCTIONS **********************************************************/
/**
* @name NlsInit
*
* Internal NLS related stuff initialization.
*/
BOOL FASTCALL
NlsInit()
{
UNICODE_STRING DirName;
OBJECT_ATTRIBUTES ObjectAttributes;
HANDLE Handle;
InitializeListHead(&CodePageListHead);
RtlInitializeCriticalSection(&CodePageListLock);
/*
* FIXME: Eventually this should be done only for the NLS Server
* process, but since we don't have anything like that (yet?) we
* always try to create the "\Nls" directory here.
*/
RtlInitUnicodeString(&DirName, L"\\Nls");
InitializeObjectAttributes(&ObjectAttributes, &DirName,
OBJ_CASE_INSENSITIVE | OBJ_PERMANENT,
NULL, NULL);
if (NT_SUCCESS(NtCreateDirectoryObject(&Handle, DIRECTORY_ALL_ACCESS, &ObjectAttributes)))
{
NtClose(Handle);
}
/* Setup ANSI code page. */
AnsiCodePage.CodePage = CP_ACP;
AnsiCodePage.SectionHandle = NULL;
AnsiCodePage.SectionMapping = NtCurrentTeb()->ProcessEnvironmentBlock->AnsiCodePageData;
RtlInitCodePageTable((PUSHORT)AnsiCodePage.SectionMapping,
&AnsiCodePage.CodePageTable);
InsertTailList(&CodePageListHead, &AnsiCodePage.Entry);
/* Setup OEM code page. */
OemCodePage.CodePage = CP_OEMCP;
OemCodePage.SectionHandle = NULL;
OemCodePage.SectionMapping = NtCurrentTeb()->ProcessEnvironmentBlock->OemCodePageData;
RtlInitCodePageTable((PUSHORT)OemCodePage.SectionMapping,
&OemCodePage.CodePageTable);
InsertTailList(&CodePageListHead, &OemCodePage.Entry);
return TRUE;
}
/**
* @name NlsUninit
*
* Internal NLS related stuff uninitialization.
*/
VOID FASTCALL
NlsUninit()
{
PCODEPAGE_ENTRY Current;
/* Delete the code page list. */
while (!IsListEmpty(&CodePageListHead))
{
Current = CONTAINING_RECORD(CodePageListHead.Flink, CODEPAGE_ENTRY, Entry);
if (Current->SectionHandle != NULL)
{
UnmapViewOfFile(Current->SectionMapping);
NtClose(Current->SectionHandle);
}
RemoveHeadList(&CodePageListHead);
}
RtlDeleteCriticalSection(&CodePageListLock);
}
/**
* @name IntGetLoadedCodePageEntry
*
* Internal function to get structure containing a code page information
* of code page that is already loaded.
*
* @param CodePage
* Number of the code page. Special values like CP_OEMCP, CP_ACP
* or CP_UTF8 aren't allowed.
*
* @return Code page entry or NULL if the specified code page hasn't
* been loaded yet.
*/
PCODEPAGE_ENTRY FASTCALL
IntGetLoadedCodePageEntry(UINT CodePage)
{
LIST_ENTRY *CurrentEntry;
PCODEPAGE_ENTRY Current;
RtlEnterCriticalSection(&CodePageListLock);
for (CurrentEntry = CodePageListHead.Flink;
CurrentEntry != &CodePageListHead;
CurrentEntry = CurrentEntry->Flink)
{
Current = CONTAINING_RECORD(CurrentEntry, CODEPAGE_ENTRY, Entry);
if (Current->CodePage == CodePage)
{
RtlLeaveCriticalSection(&CodePageListLock);
return Current;
}
}
RtlLeaveCriticalSection(&CodePageListLock);
return NULL;
}
/**
* @name IntGetCodePageEntry
*
* Internal function to get structure containing a code page information.
*
* @param CodePage
* Number of the code page. Special values like CP_OEMCP, CP_ACP
* or CP_THREAD_ACP are allowed, but CP_UTF[7/8] isn't.
*
* @return Code page entry.
*/
static PCODEPAGE_ENTRY FASTCALL
IntGetCodePageEntry(UINT CodePage)
{
CHAR SectionName[40];
NTSTATUS Status;
HANDLE SectionHandle = INVALID_HANDLE_VALUE, FileHandle;
PBYTE SectionMapping;
OBJECT_ATTRIBUTES ObjectAttributes;
ANSI_STRING AnsiName;
UNICODE_STRING UnicodeName;
WCHAR FileName[MAX_PATH + 1];
UINT FileNamePos;
PCODEPAGE_ENTRY CodePageEntry;
if (CodePage == CP_THREAD_ACP)
{
if (!GetLocaleInfoW(GetThreadLocale(), LOCALE_IDEFAULTANSICODEPAGE |
LOCALE_RETURN_NUMBER, (WCHAR *)&CodePage,
sizeof(CodePage) / sizeof(WCHAR)))
{
/* Last error is set by GetLocaleInfoW. */
return 0;
}
}
else if (CodePage == CP_MACCP)
{
if (!GetLocaleInfoW(LOCALE_SYSTEM_DEFAULT, LOCALE_IDEFAULTMACCODEPAGE |
LOCALE_RETURN_NUMBER, (WCHAR *)&CodePage,
sizeof(CodePage) / sizeof(WCHAR)))
{
/* Last error is set by GetLocaleInfoW. */
return 0;
}
}
/* Try searching for loaded page first. */
CodePageEntry = IntGetLoadedCodePageEntry(CodePage);
if (CodePageEntry != NULL)
{
return CodePageEntry;
}
/*
* Yes, we really want to lock here. Otherwise it can happen that
* two parallel requests will try to get the entry for the same
* code page and we would load it twice.
*/
RtlEnterCriticalSection(&CodePageListLock);
/* Generate the section name. */
if (!GetNlsSectionName(CodePage, 10, 0, "\\Nls\\NlsSectionCP",
SectionName, sizeof(SectionName)))
{
RtlLeaveCriticalSection(&CodePageListLock);
return NULL;
}
RtlInitAnsiString(&AnsiName, SectionName);
RtlAnsiStringToUnicodeString(&UnicodeName, &AnsiName, TRUE);
InitializeObjectAttributes(&ObjectAttributes, &UnicodeName, 0,
NULL, NULL);
/* Try to open the section first */
Status = NtOpenSection(&SectionHandle, SECTION_MAP_READ, &ObjectAttributes);
/* If the section doesn't exist, try to create it. */
if (Status == STATUS_UNSUCCESSFUL ||
Status == STATUS_OBJECT_NAME_NOT_FOUND ||
Status == STATUS_OBJECT_PATH_NOT_FOUND)
{
FileNamePos = GetSystemDirectoryW(FileName, MAX_PATH);
if (GetCPFileNameFromRegistry(CodePage, FileName + FileNamePos + 1,
MAX_PATH - FileNamePos - 1))
{
FileName[FileNamePos] = L'\\';
FileName[MAX_PATH] = 0;
FileHandle = CreateFileW(FileName, FILE_GENERIC_READ, FILE_SHARE_READ,
NULL, OPEN_EXISTING, 0, NULL);
Status = NtCreateSection(&SectionHandle, SECTION_MAP_READ,
&ObjectAttributes, NULL, PAGE_READONLY,
SEC_FILE, FileHandle);
}
}
RtlFreeUnicodeString(&UnicodeName);
if (!NT_SUCCESS(Status))
{
RtlLeaveCriticalSection(&CodePageListLock);
return NULL;
}
SectionMapping = MapViewOfFile(SectionHandle, FILE_MAP_READ, 0, 0, 0);
if (SectionMapping == NULL)
{
NtClose(SectionHandle);
RtlLeaveCriticalSection(&CodePageListLock);
return NULL;
}
CodePageEntry = HeapAlloc(GetProcessHeap(), 0, sizeof(CODEPAGE_ENTRY));
if (CodePageEntry == NULL)
{
NtClose(SectionHandle);
RtlLeaveCriticalSection(&CodePageListLock);
return NULL;
}
CodePageEntry->CodePage = CodePage;
CodePageEntry->SectionHandle = SectionHandle;
CodePageEntry->SectionMapping = SectionMapping;
RtlInitCodePageTable((PUSHORT)SectionMapping, &CodePageEntry->CodePageTable);
/* Insert the new entry to list and unlock. Uff. */
InsertTailList(&CodePageListHead, &CodePageEntry->Entry);
RtlLeaveCriticalSection(&CodePageListLock);
return CodePageEntry;
}
/**
* @name IntMultiByteToWideCharUTF8
*
* Internal version of MultiByteToWideChar for UTF8.
*
* @see MultiByteToWideChar
* @todo Add UTF8 validity checks.
*/
static INT STDCALL
IntMultiByteToWideCharUTF8(DWORD Flags,
LPCSTR MultiByteString, INT MultiByteCount,
LPWSTR WideCharString, INT WideCharCount)
{
LPCSTR MbsEnd;
UCHAR Char, Length;
WCHAR WideChar;
LONG Count;
if (Flags != 0)
{
SetLastError(ERROR_INVALID_FLAGS);
return 0;
}
/* Does caller query for output buffer size? */
if (WideCharCount == 0)
{
MbsEnd = MultiByteString + MultiByteCount;
for (; MultiByteString < MbsEnd; WideCharCount++)
{
Char = *MultiByteString++;
if (Char < 0xC0)
continue;
MultiByteString += UTF8Length[Char - 0x80];
}
return WideCharCount;
}
MbsEnd = MultiByteString + MultiByteCount;
for (Count = 0; Count < WideCharCount && MultiByteString < MbsEnd; Count++)
{
Char = *MultiByteString++;
if (Char < 0x80)
{
*WideCharString++ = Char;
continue;
}
Length = UTF8Length[Char - 0x80];
WideChar = Char & UTF8Mask[Length];
while (Length && MultiByteString < MbsEnd)
{
WideChar = (WideChar << 6) | *MultiByteString++;
Length--;
}
*WideCharString++ = WideChar;
}
if (MultiByteString < MbsEnd)
SetLastError(ERROR_INSUFFICIENT_BUFFER);
return Count;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -