2013-03-16 20:48:10 +00:00
|
|
|
/*
|
2006-05-25 19:50:19 +00:00
|
|
|
* COPYRIGHT: See COPYING in the top level directory
|
|
|
|
* PROJECT: ReactOS system libraries
|
2015-11-14 14:57:11 +00:00
|
|
|
* FILE: dll/win32/kernel32/winnls/string/nls.c
|
2006-05-25 19:50:19 +00:00
|
|
|
* PURPOSE: National Language Support
|
|
|
|
* PROGRAMMER: Filip Navara
|
|
|
|
* Hartmut Birr
|
|
|
|
* Gunnar Andre Dalsnes
|
|
|
|
* Thomas Weidenmueller
|
|
|
|
* UPDATE HISTORY:
|
|
|
|
* Created 24/08/2004
|
2004-08-24 17:21:12 +00:00
|
|
|
*/
|
|
|
|
|
|
|
|
/* INCLUDES *******************************************************************/
|
|
|
|
|
|
|
|
#include <k32.h>
|
2013-12-22 18:10:41 +00:00
|
|
|
|
2004-08-24 17:21:12 +00:00
|
|
|
#define NDEBUG
|
2007-09-02 19:42:22 +00:00
|
|
|
#include <debug.h>
|
2004-08-24 17:21:12 +00:00
|
|
|
|
|
|
|
/* GLOBAL VARIABLES ***********************************************************/
|
|
|
|
|
|
|
|
/* 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;
|
2005-01-03 23:02:15 +00:00
|
|
|
static RTL_CRITICAL_SECTION CodePageListLock;
|
2004-08-24 17:21:12 +00:00
|
|
|
|
|
|
|
/* FORWARD DECLARATIONS *******************************************************/
|
|
|
|
|
2008-11-30 11:42:05 +00:00
|
|
|
BOOL WINAPI
|
2004-08-24 17:21:12 +00:00
|
|
|
GetNlsSectionName(UINT CodePage, UINT Base, ULONG Unknown,
|
|
|
|
LPSTR BaseName, LPSTR Result, ULONG ResultSize);
|
|
|
|
|
2008-11-30 11:42:05 +00:00
|
|
|
BOOL WINAPI
|
2004-08-24 17:21:12 +00:00
|
|
|
GetCPFileNameFromRegistry(UINT CodePage, LPWSTR FileName, ULONG FileNameSize);
|
|
|
|
|
|
|
|
/* PRIVATE FUNCTIONS **********************************************************/
|
|
|
|
|
|
|
|
/**
|
2005-08-29 21:06:07 +00:00
|
|
|
* @name NlsInit
|
|
|
|
*
|
2004-08-24 17:21:12 +00:00
|
|
|
* Internal NLS related stuff initialization.
|
|
|
|
*/
|
2005-08-29 21:06:07 +00:00
|
|
|
|
2008-11-23 11:15:52 +00:00
|
|
|
BOOL
|
|
|
|
FASTCALL
|
2009-08-24 20:10:05 +00:00
|
|
|
NlsInit(VOID)
|
2004-08-24 17:21:12 +00:00
|
|
|
{
|
2008-11-23 11:15:52 +00:00
|
|
|
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.SectionHandle = NULL;
|
|
|
|
AnsiCodePage.SectionMapping = NtCurrentTeb()->ProcessEnvironmentBlock->AnsiCodePageData;
|
|
|
|
|
|
|
|
RtlInitCodePageTable((PUSHORT)AnsiCodePage.SectionMapping,
|
|
|
|
&AnsiCodePage.CodePageTable);
|
2014-06-24 19:36:22 +00:00
|
|
|
AnsiCodePage.CodePage = AnsiCodePage.CodePageTable.CodePage;
|
2016-09-26 10:12:58 +00:00
|
|
|
|
2008-11-23 11:15:52 +00:00
|
|
|
InsertTailList(&CodePageListHead, &AnsiCodePage.Entry);
|
|
|
|
|
|
|
|
/* Setup OEM code page. */
|
|
|
|
OemCodePage.SectionHandle = NULL;
|
|
|
|
OemCodePage.SectionMapping = NtCurrentTeb()->ProcessEnvironmentBlock->OemCodePageData;
|
|
|
|
|
|
|
|
RtlInitCodePageTable((PUSHORT)OemCodePage.SectionMapping,
|
|
|
|
&OemCodePage.CodePageTable);
|
2014-06-24 19:36:22 +00:00
|
|
|
OemCodePage.CodePage = OemCodePage.CodePageTable.CodePage;
|
2008-11-23 11:15:52 +00:00
|
|
|
InsertTailList(&CodePageListHead, &OemCodePage.Entry);
|
|
|
|
|
|
|
|
return TRUE;
|
2004-08-24 17:21:12 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
2005-08-29 21:06:07 +00:00
|
|
|
* @name NlsUninit
|
|
|
|
*
|
2004-08-24 17:21:12 +00:00
|
|
|
* Internal NLS related stuff uninitialization.
|
|
|
|
*/
|
2005-08-29 21:06:07 +00:00
|
|
|
|
2008-11-23 11:15:52 +00:00
|
|
|
VOID
|
|
|
|
FASTCALL
|
2009-08-24 20:10:05 +00:00
|
|
|
NlsUninit(VOID)
|
2004-08-24 17:21:12 +00:00
|
|
|
{
|
2008-11-23 11:15:52 +00:00
|
|
|
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);
|
2004-08-24 17:21:12 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
2005-08-29 21:06:07 +00:00
|
|
|
* @name IntGetLoadedCodePageEntry
|
|
|
|
*
|
2004-08-24 17:21:12 +00:00
|
|
|
* 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.
|
|
|
|
*/
|
2005-08-29 21:06:07 +00:00
|
|
|
|
2008-11-23 11:15:52 +00:00
|
|
|
PCODEPAGE_ENTRY
|
|
|
|
FASTCALL
|
2004-08-24 17:21:12 +00:00
|
|
|
IntGetLoadedCodePageEntry(UINT CodePage)
|
|
|
|
{
|
2008-11-23 11:15:52 +00:00
|
|
|
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;
|
2004-08-24 17:21:12 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
2005-08-29 21:06:07 +00:00
|
|
|
* @name IntGetCodePageEntry
|
|
|
|
*
|
2004-08-24 17:21:12 +00:00
|
|
|
* 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.
|
|
|
|
*/
|
2005-08-29 21:06:07 +00:00
|
|
|
|
2008-11-23 11:15:52 +00:00
|
|
|
PCODEPAGE_ENTRY
|
|
|
|
FASTCALL
|
2004-08-24 17:21:12 +00:00
|
|
|
IntGetCodePageEntry(UINT CodePage)
|
|
|
|
{
|
2008-11-23 11:15:52 +00:00
|
|
|
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;
|
2014-06-24 19:36:22 +00:00
|
|
|
if (CodePage == CP_ACP)
|
|
|
|
{
|
|
|
|
return &AnsiCodePage;
|
|
|
|
}
|
|
|
|
else if (CodePage == CP_OEMCP)
|
|
|
|
{
|
|
|
|
return &OemCodePage;
|
|
|
|
}
|
|
|
|
else if (CodePage == CP_THREAD_ACP)
|
2008-11-23 11:15:52 +00:00
|
|
|
{
|
|
|
|
if (!GetLocaleInfoW(GetThreadLocale(),
|
|
|
|
LOCALE_IDEFAULTANSICODEPAGE | LOCALE_RETURN_NUMBER,
|
|
|
|
(WCHAR *)&CodePage,
|
|
|
|
sizeof(CodePage) / sizeof(WCHAR)))
|
|
|
|
{
|
|
|
|
/* Last error is set by GetLocaleInfoW. */
|
2009-01-03 15:50:55 +00:00
|
|
|
return NULL;
|
2008-11-23 11:15:52 +00:00
|
|
|
}
|
2015-06-28 12:34:01 +00:00
|
|
|
if (CodePage == 0)
|
|
|
|
return &AnsiCodePage;
|
2008-11-23 11:15:52 +00:00
|
|
|
}
|
|
|
|
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. */
|
2009-01-03 15:50:55 +00:00
|
|
|
return NULL;
|
2008-11-23 11:15:52 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* 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,
|
2010-10-02 01:12:53 +00:00
|
|
|
SEC_COMMIT,
|
2008-11-23 11:15:52 +00:00
|
|
|
FileHandle);
|
2009-01-02 17:38:01 +00:00
|
|
|
|
|
|
|
/* HACK: Check if another process was faster
|
|
|
|
* and already created this section. See bug 3626 for details */
|
|
|
|
if (Status == STATUS_OBJECT_NAME_COLLISION)
|
|
|
|
{
|
|
|
|
/* Close the file then */
|
|
|
|
NtClose(FileHandle);
|
|
|
|
|
|
|
|
/* And open the section */
|
|
|
|
Status = NtOpenSection(&SectionHandle,
|
|
|
|
SECTION_MAP_READ,
|
|
|
|
&ObjectAttributes);
|
|
|
|
}
|
2008-11-23 11:15:52 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
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;
|
2004-08-24 17:21:12 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
2005-08-29 21:06:07 +00:00
|
|
|
* @name IntMultiByteToWideCharUTF8
|
|
|
|
*
|
2004-08-24 17:21:12 +00:00
|
|
|
* Internal version of MultiByteToWideChar for UTF8.
|
|
|
|
*
|
|
|
|
* @see MultiByteToWideChar
|
|
|
|
* @todo Add UTF8 validity checks.
|
|
|
|
*/
|
2005-08-29 21:06:07 +00:00
|
|
|
|
2008-11-23 11:15:52 +00:00
|
|
|
static
|
|
|
|
INT
|
2008-11-30 11:42:05 +00:00
|
|
|
WINAPI
|
2004-08-24 17:21:12 +00:00
|
|
|
IntMultiByteToWideCharUTF8(DWORD Flags,
|
2008-11-23 11:15:52 +00:00
|
|
|
LPCSTR MultiByteString,
|
|
|
|
INT MultiByteCount,
|
|
|
|
LPWSTR WideCharString,
|
|
|
|
INT WideCharCount)
|
2004-08-24 17:21:12 +00:00
|
|
|
{
|
2008-11-23 11:15:52 +00:00
|
|
|
LPCSTR MbsEnd;
|
|
|
|
UCHAR Char, Length;
|
|
|
|
WCHAR WideChar;
|
|
|
|
LONG Count;
|
|
|
|
|
2012-10-10 20:33:45 +00:00
|
|
|
if (Flags != 0 && Flags != MB_ERR_INVALID_CHARS)
|
2008-11-23 11:15:52 +00:00
|
|
|
{
|
|
|
|
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;
|
2004-08-24 17:21:12 +00:00
|
|
|
continue;
|
2008-11-23 11:15:52 +00:00
|
|
|
}
|
|
|
|
Length = UTF8Length[Char - 0x80];
|
|
|
|
WideChar = Char & UTF8Mask[Length];
|
|
|
|
while (Length && MultiByteString < MbsEnd)
|
|
|
|
{
|
2008-12-29 20:16:22 +00:00
|
|
|
WideChar = (WideChar << 6) | (*MultiByteString++ & 0x7f);
|
2008-11-23 11:15:52 +00:00
|
|
|
Length--;
|
|
|
|
}
|
|
|
|
*WideCharString++ = WideChar;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (MultiByteString < MbsEnd)
|
|
|
|
SetLastError(ERROR_INSUFFICIENT_BUFFER);
|
|
|
|
|
|
|
|
return Count;
|
2004-08-24 17:21:12 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
2005-08-29 21:06:07 +00:00
|
|
|
* @name IntMultiByteToWideCharCP
|
|
|
|
*
|
2004-08-24 17:21:12 +00:00
|
|
|
* Internal version of MultiByteToWideChar for code page tables.
|
|
|
|
*
|
|
|
|
* @see MultiByteToWideChar
|
|
|
|
* @todo Handle MB_PRECOMPOSED, MB_COMPOSITE, MB_USEGLYPHCHARS and
|
|
|
|
* DBCS codepages.
|
|
|
|
*/
|
2005-08-29 21:06:07 +00:00
|
|
|
|
2008-11-23 11:15:52 +00:00
|
|
|
static
|
|
|
|
INT
|
2008-11-30 11:42:05 +00:00
|
|
|
WINAPI
|
2008-11-23 11:15:52 +00:00
|
|
|
IntMultiByteToWideCharCP(UINT CodePage,
|
|
|
|
DWORD Flags,
|
|
|
|
LPCSTR MultiByteString,
|
|
|
|
INT MultiByteCount,
|
|
|
|
LPWSTR WideCharString,
|
|
|
|
INT WideCharCount)
|
2004-08-24 17:21:12 +00:00
|
|
|
{
|
2008-11-23 11:15:52 +00:00
|
|
|
PCODEPAGE_ENTRY CodePageEntry;
|
|
|
|
PCPTABLEINFO CodePageTable;
|
2016-09-18 17:26:59 +00:00
|
|
|
PUSHORT MultiByteTable;
|
2008-11-23 11:15:52 +00:00
|
|
|
LPCSTR TempString;
|
|
|
|
INT TempLength;
|
2016-09-18 18:21:30 +00:00
|
|
|
USHORT WideChar;
|
2008-11-23 11:15:52 +00:00
|
|
|
|
|
|
|
/* Get code page table. */
|
|
|
|
CodePageEntry = IntGetCodePageEntry(CodePage);
|
|
|
|
if (CodePageEntry == NULL)
|
|
|
|
{
|
|
|
|
SetLastError(ERROR_INVALID_PARAMETER);
|
|
|
|
return 0;
|
|
|
|
}
|
2016-09-18 17:26:59 +00:00
|
|
|
|
2008-11-23 11:15:52 +00:00
|
|
|
CodePageTable = &CodePageEntry->CodePageTable;
|
|
|
|
|
2016-09-18 17:26:59 +00:00
|
|
|
/* If MB_USEGLYPHCHARS flag present and glyph table present */
|
|
|
|
if ((Flags & MB_USEGLYPHCHARS) && CodePageTable->MultiByteTable[256])
|
|
|
|
{
|
|
|
|
/* Use glyph table */
|
|
|
|
MultiByteTable = CodePageTable->MultiByteTable + 256 + 1;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
MultiByteTable = CodePageTable->MultiByteTable;
|
|
|
|
}
|
|
|
|
|
2008-11-23 11:15:52 +00:00
|
|
|
/* Different handling for DBCS code pages. */
|
2016-09-18 17:26:59 +00:00
|
|
|
if (CodePageTable->DBCSCodePage)
|
2008-11-23 11:15:52 +00:00
|
|
|
{
|
|
|
|
UCHAR Char;
|
|
|
|
USHORT DBCSOffset;
|
|
|
|
LPCSTR MbsEnd = MultiByteString + MultiByteCount;
|
2008-12-03 17:40:49 +00:00
|
|
|
INT Count;
|
2008-11-23 11:15:52 +00:00
|
|
|
|
2015-06-28 13:06:43 +00:00
|
|
|
if (Flags & MB_ERR_INVALID_CHARS)
|
|
|
|
{
|
2016-09-18 18:21:30 +00:00
|
|
|
TempString = MultiByteString;
|
|
|
|
|
|
|
|
while (TempString < MbsEnd)
|
|
|
|
{
|
2016-09-18 20:11:05 +00:00
|
|
|
DBCSOffset = CodePageTable->DBCSOffsets[(UCHAR)*TempString];
|
2016-09-18 18:21:30 +00:00
|
|
|
|
|
|
|
if (DBCSOffset)
|
|
|
|
{
|
|
|
|
/* If lead byte is presented, but behind it there is no symbol */
|
|
|
|
if (((TempString + 1) == MbsEnd) || (*(TempString + 1) == 0))
|
|
|
|
{
|
|
|
|
SetLastError(ERROR_NO_UNICODE_TRANSLATION);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2016-09-18 20:11:05 +00:00
|
|
|
WideChar = CodePageTable->DBCSOffsets[DBCSOffset + *(TempString + 1)];
|
2016-09-18 18:21:30 +00:00
|
|
|
|
|
|
|
if (WideChar == CodePageTable->UniDefaultChar &&
|
|
|
|
MAKEWORD(*(TempString + 1), *TempString) != CodePageTable->TransUniDefaultChar)
|
|
|
|
{
|
|
|
|
SetLastError(ERROR_NO_UNICODE_TRANSLATION);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
TempString++;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2016-09-18 20:11:05 +00:00
|
|
|
WideChar = MultiByteTable[(UCHAR)*TempString];
|
2016-09-18 18:21:30 +00:00
|
|
|
|
|
|
|
if ((WideChar == CodePageTable->UniDefaultChar &&
|
|
|
|
*TempString != CodePageTable->TransUniDefaultChar) ||
|
|
|
|
/* "Private Use" characters */
|
|
|
|
(WideChar >= 0xE000 && WideChar <= 0xF8FF))
|
|
|
|
{
|
|
|
|
SetLastError(ERROR_NO_UNICODE_TRANSLATION);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
TempString++;
|
|
|
|
}
|
2015-06-28 13:06:43 +00:00
|
|
|
}
|
2016-09-26 10:12:58 +00:00
|
|
|
|
2008-11-23 11:15:52 +00:00
|
|
|
/* Does caller query for output buffer size? */
|
|
|
|
if (WideCharCount == 0)
|
|
|
|
{
|
|
|
|
for (; MultiByteString < MbsEnd; WideCharCount++)
|
|
|
|
{
|
|
|
|
Char = *MultiByteString++;
|
|
|
|
|
|
|
|
DBCSOffset = CodePageTable->DBCSOffsets[Char];
|
|
|
|
|
|
|
|
if (!DBCSOffset)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
if (MultiByteString < MbsEnd)
|
|
|
|
MultiByteString++;
|
|
|
|
}
|
|
|
|
|
|
|
|
return WideCharCount;
|
|
|
|
}
|
|
|
|
|
|
|
|
for (Count = 0; Count < WideCharCount && MultiByteString < MbsEnd; Count++)
|
|
|
|
{
|
2007-05-19 10:11:48 +00:00
|
|
|
Char = *MultiByteString++;
|
|
|
|
|
|
|
|
DBCSOffset = CodePageTable->DBCSOffsets[Char];
|
|
|
|
|
|
|
|
if (!DBCSOffset)
|
2008-11-23 11:15:52 +00:00
|
|
|
{
|
2016-09-18 17:26:59 +00:00
|
|
|
*WideCharString++ = MultiByteTable[Char];
|
2008-11-23 11:15:52 +00:00
|
|
|
continue;
|
|
|
|
}
|
2007-05-19 10:11:48 +00:00
|
|
|
|
2016-09-18 21:10:07 +00:00
|
|
|
if (MultiByteString == MbsEnd)
|
|
|
|
{
|
|
|
|
*WideCharString++ = UNICODE_NULL;
|
|
|
|
}
|
|
|
|
else if (*MultiByteString == 0)
|
|
|
|
{
|
|
|
|
*WideCharString++ = UNICODE_NULL;
|
|
|
|
MultiByteString++;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
*WideCharString++ = CodePageTable->DBCSOffsets[DBCSOffset + (UCHAR)*MultiByteString++];
|
|
|
|
}
|
2008-11-23 11:15:52 +00:00
|
|
|
}
|
2007-05-19 10:11:48 +00:00
|
|
|
|
2008-11-23 11:15:52 +00:00
|
|
|
if (MultiByteString < MbsEnd)
|
2009-01-20 16:27:05 +00:00
|
|
|
{
|
2008-11-23 11:15:52 +00:00
|
|
|
SetLastError(ERROR_INSUFFICIENT_BUFFER);
|
2009-01-20 16:27:05 +00:00
|
|
|
return 0;
|
|
|
|
}
|
2007-05-19 10:11:48 +00:00
|
|
|
|
2008-11-23 11:15:52 +00:00
|
|
|
return Count;
|
|
|
|
}
|
2016-09-18 20:11:05 +00:00
|
|
|
else /* SBCS code page */
|
2008-11-23 11:15:52 +00:00
|
|
|
{
|
|
|
|
/* Check for invalid characters. */
|
|
|
|
if (Flags & MB_ERR_INVALID_CHARS)
|
|
|
|
{
|
|
|
|
for (TempString = MultiByteString, TempLength = MultiByteCount;
|
|
|
|
TempLength > 0;
|
|
|
|
TempString++, TempLength--)
|
|
|
|
{
|
2016-09-18 18:21:30 +00:00
|
|
|
WideChar = MultiByteTable[(UCHAR)*TempString];
|
2016-09-18 17:26:59 +00:00
|
|
|
|
|
|
|
if ((WideChar == CodePageTable->UniDefaultChar &&
|
2016-09-18 18:21:30 +00:00
|
|
|
*TempString != CodePageTable->TransUniDefaultChar) ||
|
2016-09-18 17:26:59 +00:00
|
|
|
/* "Private Use" characters */
|
|
|
|
(WideChar >= 0xE000 && WideChar <= 0xF8FF))
|
2008-11-23 11:15:52 +00:00
|
|
|
{
|
|
|
|
SetLastError(ERROR_NO_UNICODE_TRANSLATION);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2007-05-19 10:11:48 +00:00
|
|
|
|
2008-11-23 11:15:52 +00:00
|
|
|
/* Does caller query for output buffer size? */
|
|
|
|
if (WideCharCount == 0)
|
|
|
|
return MultiByteCount;
|
2007-05-19 10:11:48 +00:00
|
|
|
|
2009-02-03 09:09:06 +00:00
|
|
|
/* Fill the WideCharString buffer with what will fit: Verified on WinXP */
|
|
|
|
for (TempLength = (WideCharCount < MultiByteCount) ? WideCharCount : MultiByteCount;
|
|
|
|
TempLength > 0;
|
|
|
|
MultiByteString++, TempLength--)
|
|
|
|
{
|
2016-09-18 17:26:59 +00:00
|
|
|
*WideCharString++ = MultiByteTable[(UCHAR)*MultiByteString];
|
2009-02-03 09:09:06 +00:00
|
|
|
}
|
|
|
|
|
2008-11-23 11:15:52 +00:00
|
|
|
/* Adjust buffer size. Wine trick ;-) */
|
|
|
|
if (WideCharCount < MultiByteCount)
|
|
|
|
{
|
|
|
|
MultiByteCount = WideCharCount;
|
|
|
|
SetLastError(ERROR_INSUFFICIENT_BUFFER);
|
2009-01-20 16:27:05 +00:00
|
|
|
return 0;
|
2008-11-23 11:15:52 +00:00
|
|
|
}
|
2016-09-18 20:11:05 +00:00
|
|
|
return MultiByteCount;
|
2008-11-23 11:15:52 +00:00
|
|
|
}
|
2004-08-24 17:21:12 +00:00
|
|
|
}
|
|
|
|
|
2007-12-19 10:56:29 +00:00
|
|
|
/**
|
|
|
|
* @name IntMultiByteToWideCharSYMBOL
|
|
|
|
*
|
|
|
|
* Internal version of MultiByteToWideChar for SYMBOL.
|
|
|
|
*
|
|
|
|
* @see MultiByteToWideChar
|
|
|
|
*/
|
|
|
|
|
2008-11-23 11:15:52 +00:00
|
|
|
static
|
|
|
|
INT
|
2013-09-14 10:20:11 +00:00
|
|
|
WINAPI
|
|
|
|
IntMultiByteToWideCharSYMBOL(DWORD Flags,
|
2008-11-23 11:15:52 +00:00
|
|
|
LPCSTR MultiByteString,
|
2013-09-14 10:20:11 +00:00
|
|
|
INT MultiByteCount,
|
2008-11-23 11:15:52 +00:00
|
|
|
LPWSTR WideCharString,
|
|
|
|
INT WideCharCount)
|
2007-12-19 10:56:29 +00:00
|
|
|
{
|
2008-11-23 11:15:52 +00:00
|
|
|
LONG Count;
|
|
|
|
UCHAR Char;
|
|
|
|
INT WideCharMaxLen;
|
|
|
|
|
|
|
|
|
|
|
|
if (Flags != 0)
|
|
|
|
{
|
|
|
|
SetLastError(ERROR_INVALID_FLAGS);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2013-09-14 10:20:11 +00:00
|
|
|
if (WideCharCount == 0)
|
2008-11-23 11:15:52 +00:00
|
|
|
{
|
|
|
|
return MultiByteCount;
|
|
|
|
}
|
|
|
|
|
|
|
|
WideCharMaxLen = WideCharCount > MultiByteCount ? MultiByteCount : WideCharCount;
|
|
|
|
|
|
|
|
for (Count = 0; Count < WideCharMaxLen; Count++)
|
|
|
|
{
|
|
|
|
Char = MultiByteString[Count];
|
|
|
|
if ( Char < 0x20 )
|
|
|
|
{
|
|
|
|
WideCharString[Count] = Char;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
WideCharString[Count] = Char + 0xf000;
|
|
|
|
}
|
|
|
|
}
|
2013-09-14 10:20:11 +00:00
|
|
|
if (MultiByteCount > WideCharMaxLen)
|
2008-11-23 11:15:52 +00:00
|
|
|
{
|
|
|
|
SetLastError(ERROR_INSUFFICIENT_BUFFER);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
return WideCharMaxLen;
|
2007-12-19 10:56:29 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @name IntWideCharToMultiByteSYMBOL
|
|
|
|
*
|
|
|
|
* Internal version of WideCharToMultiByte for SYMBOL.
|
|
|
|
*
|
|
|
|
* @see WideCharToMultiByte
|
|
|
|
*/
|
|
|
|
|
2008-11-23 11:15:52 +00:00
|
|
|
static INT
|
2008-11-30 11:42:05 +00:00
|
|
|
WINAPI
|
2007-12-19 10:56:29 +00:00
|
|
|
IntWideCharToMultiByteSYMBOL(DWORD Flags,
|
2008-11-23 11:15:52 +00:00
|
|
|
LPCWSTR WideCharString,
|
|
|
|
INT WideCharCount,
|
|
|
|
LPSTR MultiByteString,
|
|
|
|
INT MultiByteCount)
|
2007-12-19 10:56:29 +00:00
|
|
|
{
|
2008-11-23 11:15:52 +00:00
|
|
|
LONG Count;
|
|
|
|
INT MaxLen;
|
|
|
|
WCHAR Char;
|
|
|
|
|
|
|
|
if (Flags!=0)
|
|
|
|
{
|
|
|
|
SetLastError(ERROR_INVALID_PARAMETER);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2013-09-14 10:20:11 +00:00
|
|
|
if (MultiByteCount == 0)
|
2008-11-23 11:15:52 +00:00
|
|
|
{
|
|
|
|
return WideCharCount;
|
|
|
|
}
|
|
|
|
|
|
|
|
MaxLen = MultiByteCount > WideCharCount ? WideCharCount : MultiByteCount;
|
|
|
|
for (Count = 0; Count < MaxLen; Count++)
|
|
|
|
{
|
|
|
|
Char = WideCharString[Count];
|
|
|
|
if (Char < 0x20)
|
|
|
|
{
|
2013-09-14 10:20:11 +00:00
|
|
|
MultiByteString[Count] = (CHAR)Char;
|
2008-11-23 11:15:52 +00:00
|
|
|
}
|
2013-09-14 10:20:11 +00:00
|
|
|
else
|
2008-11-23 11:15:52 +00:00
|
|
|
{
|
2013-09-14 10:20:11 +00:00
|
|
|
if ((Char >= 0xf020) && (Char < 0xf100))
|
2008-11-23 11:15:52 +00:00
|
|
|
{
|
|
|
|
MultiByteString[Count] = Char - 0xf000;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
SetLastError(ERROR_NO_UNICODE_TRANSLATION);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2013-09-14 10:20:11 +00:00
|
|
|
|
|
|
|
if (WideCharCount > MaxLen)
|
2008-11-23 11:15:52 +00:00
|
|
|
{
|
|
|
|
SetLastError(ERROR_INSUFFICIENT_BUFFER);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
return MaxLen;
|
2007-12-19 10:56:29 +00:00
|
|
|
}
|
|
|
|
|
2004-08-24 17:21:12 +00:00
|
|
|
/**
|
2005-08-29 21:06:07 +00:00
|
|
|
* @name IntWideCharToMultiByteUTF8
|
|
|
|
*
|
2004-08-24 17:21:12 +00:00
|
|
|
* Internal version of WideCharToMultiByte for UTF8.
|
|
|
|
*
|
|
|
|
* @see WideCharToMultiByte
|
|
|
|
*/
|
2005-08-29 21:06:07 +00:00
|
|
|
|
2008-11-23 11:15:52 +00:00
|
|
|
static INT
|
2008-11-30 11:42:05 +00:00
|
|
|
WINAPI
|
2008-11-23 11:15:52 +00:00
|
|
|
IntWideCharToMultiByteUTF8(UINT CodePage,
|
|
|
|
DWORD Flags,
|
|
|
|
LPCWSTR WideCharString,
|
|
|
|
INT WideCharCount,
|
|
|
|
LPSTR MultiByteString,
|
|
|
|
INT MultiByteCount,
|
|
|
|
LPCSTR DefaultChar,
|
|
|
|
LPBOOL UsedDefaultChar)
|
2004-08-24 17:21:12 +00:00
|
|
|
{
|
2008-11-23 11:15:52 +00:00
|
|
|
INT TempLength;
|
2016-09-26 10:12:58 +00:00
|
|
|
DWORD Char;
|
2008-11-23 11:15:52 +00:00
|
|
|
|
2016-09-28 19:53:43 +00:00
|
|
|
if (Flags)
|
|
|
|
{
|
|
|
|
SetLastError(ERROR_INVALID_FLAGS);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2008-11-23 11:15:52 +00:00
|
|
|
/* Does caller query for output buffer size? */
|
|
|
|
if (MultiByteCount == 0)
|
|
|
|
{
|
|
|
|
for (TempLength = 0; WideCharCount;
|
|
|
|
WideCharCount--, WideCharString++)
|
|
|
|
{
|
2004-08-31 07:01:43 +00:00
|
|
|
TempLength++;
|
2008-11-23 11:15:52 +00:00
|
|
|
if (*WideCharString >= 0x80)
|
|
|
|
{
|
|
|
|
TempLength++;
|
|
|
|
if (*WideCharString >= 0x800)
|
2016-09-26 10:12:58 +00:00
|
|
|
{
|
2008-11-23 11:15:52 +00:00
|
|
|
TempLength++;
|
2016-09-26 10:12:58 +00:00
|
|
|
if (*WideCharString >= 0xd800 && *WideCharString < 0xdc00 &&
|
|
|
|
WideCharCount >= 1 &&
|
|
|
|
WideCharString[1] >= 0xdc00 && WideCharString[1] <= 0xe000)
|
|
|
|
{
|
|
|
|
WideCharCount--;
|
|
|
|
WideCharString++;
|
|
|
|
TempLength++;
|
|
|
|
}
|
|
|
|
}
|
2008-11-23 11:15:52 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
return TempLength;
|
|
|
|
}
|
|
|
|
|
|
|
|
for (TempLength = MultiByteCount; WideCharCount; WideCharCount--, WideCharString++)
|
|
|
|
{
|
|
|
|
Char = *WideCharString;
|
|
|
|
if (Char < 0x80)
|
|
|
|
{
|
|
|
|
if (!TempLength)
|
|
|
|
{
|
|
|
|
SetLastError(ERROR_INSUFFICIENT_BUFFER);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
TempLength--;
|
|
|
|
*MultiByteString++ = (CHAR)Char;
|
|
|
|
continue;
|
|
|
|
}
|
2004-08-31 07:01:43 +00:00
|
|
|
|
2008-11-23 11:15:52 +00:00
|
|
|
if (Char < 0x800) /* 0x80-0x7ff: 2 bytes */
|
|
|
|
{
|
|
|
|
if (TempLength < 2)
|
|
|
|
{
|
|
|
|
SetLastError(ERROR_INSUFFICIENT_BUFFER);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
MultiByteString[1] = 0x80 | (Char & 0x3f); Char >>= 6;
|
|
|
|
MultiByteString[0] = 0xc0 | Char;
|
|
|
|
MultiByteString += 2;
|
|
|
|
TempLength -= 2;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2016-09-26 10:12:58 +00:00
|
|
|
/* surrogate pair 0x10000-0x10ffff: 4 bytes */
|
|
|
|
if (Char >= 0xd800 && Char < 0xdc00 &&
|
|
|
|
WideCharCount >= 1 &&
|
|
|
|
WideCharString[1] >= 0xdc00 && WideCharString[1] < 0xe000)
|
|
|
|
{
|
|
|
|
WideCharCount--;
|
|
|
|
WideCharString++;
|
|
|
|
|
|
|
|
if (TempLength < 4)
|
|
|
|
{
|
|
|
|
SetLastError(ERROR_INSUFFICIENT_BUFFER);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
Char = (Char - 0xd800) << 10;
|
|
|
|
Char |= *WideCharString - 0xdc00;
|
|
|
|
ASSERT(Char <= 0xfffff);
|
|
|
|
Char += 0x10000;
|
|
|
|
ASSERT(Char <= 0x10ffff);
|
|
|
|
|
|
|
|
MultiByteString[3] = 0x80 | (Char & 0x3f); Char >>= 6;
|
|
|
|
MultiByteString[2] = 0x80 | (Char & 0x3f); Char >>= 6;
|
|
|
|
MultiByteString[1] = 0x80 | (Char & 0x3f); Char >>= 6;
|
|
|
|
MultiByteString[0] = 0xf0 | Char;
|
|
|
|
MultiByteString += 4;
|
|
|
|
TempLength -= 4;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2008-11-23 11:15:52 +00:00
|
|
|
/* 0x800-0xffff: 3 bytes */
|
|
|
|
if (TempLength < 3)
|
|
|
|
{
|
2004-08-31 07:01:43 +00:00
|
|
|
SetLastError(ERROR_INSUFFICIENT_BUFFER);
|
|
|
|
break;
|
2008-11-23 11:15:52 +00:00
|
|
|
}
|
|
|
|
MultiByteString[2] = 0x80 | (Char & 0x3f); Char >>= 6;
|
|
|
|
MultiByteString[1] = 0x80 | (Char & 0x3f); Char >>= 6;
|
|
|
|
MultiByteString[0] = 0xe0 | Char;
|
|
|
|
MultiByteString += 3;
|
|
|
|
TempLength -= 3;
|
|
|
|
}
|
|
|
|
|
|
|
|
return MultiByteCount - TempLength;
|
2004-08-24 17:21:12 +00:00
|
|
|
}
|
|
|
|
|
2008-07-11 19:11:06 +00:00
|
|
|
/**
|
|
|
|
* @name IsValidSBCSMapping
|
|
|
|
*
|
|
|
|
* Checks if ch (single-byte character) is a valid mapping for wch
|
|
|
|
*
|
|
|
|
* @see IntWideCharToMultiByteCP
|
|
|
|
*/
|
2008-11-23 11:15:52 +00:00
|
|
|
static
|
|
|
|
inline
|
|
|
|
BOOL
|
2008-07-11 19:11:06 +00:00
|
|
|
IntIsValidSBCSMapping(PCPTABLEINFO CodePageTable, DWORD Flags, WCHAR wch, UCHAR ch)
|
|
|
|
{
|
2008-11-23 11:15:52 +00:00
|
|
|
/* If the WC_NO_BEST_FIT_CHARS flag has been specified, the characters need to match exactly. */
|
|
|
|
if (Flags & WC_NO_BEST_FIT_CHARS)
|
2008-12-09 16:13:51 +00:00
|
|
|
return (CodePageTable->MultiByteTable[ch] == wch);
|
2008-07-11 19:11:06 +00:00
|
|
|
|
2008-11-23 11:15:52 +00:00
|
|
|
/* By default, all characters except TransDefaultChar apply as a valid mapping
|
|
|
|
for ch (so also "nearest" characters) */
|
|
|
|
if (ch != CodePageTable->TransDefaultChar)
|
|
|
|
return TRUE;
|
2008-07-11 19:11:06 +00:00
|
|
|
|
2008-11-23 11:15:52 +00:00
|
|
|
/* The only possible left valid mapping is the default character itself */
|
|
|
|
return (wch == CodePageTable->TransUniDefaultChar);
|
2008-07-11 19:11:06 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @name IsValidDBCSMapping
|
|
|
|
*
|
|
|
|
* Checks if ch (double-byte character) is a valid mapping for wch
|
|
|
|
*
|
|
|
|
* @see IntWideCharToMultiByteCP
|
|
|
|
*/
|
|
|
|
static inline BOOL
|
|
|
|
IntIsValidDBCSMapping(PCPTABLEINFO CodePageTable, DWORD Flags, WCHAR wch, USHORT ch)
|
|
|
|
{
|
2008-11-23 11:15:52 +00:00
|
|
|
/* If ch is the default character, but the wch is not, it can't be a valid mapping */
|
|
|
|
if (ch == CodePageTable->TransDefaultChar && wch != CodePageTable->TransUniDefaultChar)
|
|
|
|
return FALSE;
|
|
|
|
|
|
|
|
/* If the WC_NO_BEST_FIT_CHARS flag has been specified, the characters need to match exactly. */
|
|
|
|
if (Flags & WC_NO_BEST_FIT_CHARS)
|
|
|
|
{
|
|
|
|
if(ch & 0xff00)
|
|
|
|
{
|
2008-12-03 17:40:49 +00:00
|
|
|
USHORT uOffset = CodePageTable->DBCSOffsets[ch >> 8];
|
|
|
|
/* if (!uOffset) return (CodePageTable->MultiByteTable[ch] == wch); */
|
|
|
|
return (CodePageTable->DBCSOffsets[uOffset + (ch & 0xff)] == wch);
|
2008-11-23 11:15:52 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
return (CodePageTable->MultiByteTable[ch] == wch);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* If we're still here, we have a valid mapping */
|
|
|
|
return TRUE;
|
2008-07-11 19:11:06 +00:00
|
|
|
}
|
|
|
|
|
2004-08-24 17:21:12 +00:00
|
|
|
/**
|
2005-08-29 21:06:07 +00:00
|
|
|
* @name IntWideCharToMultiByteCP
|
|
|
|
*
|
2004-08-24 17:21:12 +00:00
|
|
|
* Internal version of WideCharToMultiByte for code page tables.
|
|
|
|
*
|
|
|
|
* @see WideCharToMultiByte
|
2008-07-11 19:11:06 +00:00
|
|
|
* @todo Handle WC_COMPOSITECHECK
|
2004-08-24 17:21:12 +00:00
|
|
|
*/
|
2008-11-23 11:15:52 +00:00
|
|
|
static
|
|
|
|
INT
|
2008-11-30 11:42:05 +00:00
|
|
|
WINAPI
|
2008-11-23 11:15:52 +00:00
|
|
|
IntWideCharToMultiByteCP(UINT CodePage,
|
|
|
|
DWORD Flags,
|
|
|
|
LPCWSTR WideCharString,
|
|
|
|
INT WideCharCount,
|
|
|
|
LPSTR MultiByteString,
|
|
|
|
INT MultiByteCount,
|
|
|
|
LPCSTR DefaultChar,
|
|
|
|
LPBOOL UsedDefaultChar)
|
2004-08-24 17:21:12 +00:00
|
|
|
{
|
2008-11-23 11:15:52 +00:00
|
|
|
PCODEPAGE_ENTRY CodePageEntry;
|
|
|
|
PCPTABLEINFO CodePageTable;
|
|
|
|
INT TempLength;
|
|
|
|
|
|
|
|
/* Get code page table. */
|
|
|
|
CodePageEntry = IntGetCodePageEntry(CodePage);
|
|
|
|
if (CodePageEntry == NULL)
|
|
|
|
{
|
|
|
|
SetLastError(ERROR_INVALID_PARAMETER);
|
|
|
|
return 0;
|
|
|
|
}
|
2016-09-18 21:10:07 +00:00
|
|
|
|
2008-11-23 11:15:52 +00:00
|
|
|
CodePageTable = &CodePageEntry->CodePageTable;
|
|
|
|
|
|
|
|
|
|
|
|
/* Different handling for DBCS code pages. */
|
2016-09-18 21:10:07 +00:00
|
|
|
if (CodePageTable->DBCSCodePage)
|
2008-11-23 11:15:52 +00:00
|
|
|
{
|
|
|
|
/* If Flags, DefaultChar or UsedDefaultChar were given, we have to do some more work */
|
2016-09-18 21:10:07 +00:00
|
|
|
if (Flags || DefaultChar || UsedDefaultChar)
|
2008-11-23 11:15:52 +00:00
|
|
|
{
|
|
|
|
BOOL TempUsedDefaultChar;
|
|
|
|
USHORT DefChar;
|
|
|
|
|
|
|
|
/* If UsedDefaultChar is not set, set it to a temporary value, so we don't have
|
|
|
|
to check on every character */
|
2016-09-18 21:10:07 +00:00
|
|
|
if (!UsedDefaultChar)
|
2008-11-23 11:15:52 +00:00
|
|
|
UsedDefaultChar = &TempUsedDefaultChar;
|
|
|
|
|
|
|
|
*UsedDefaultChar = FALSE;
|
|
|
|
|
|
|
|
/* Use the CodePage's TransDefaultChar if none was given. Don't modify the DefaultChar pointer here. */
|
2016-09-18 21:10:07 +00:00
|
|
|
if (DefaultChar)
|
2008-11-23 11:15:52 +00:00
|
|
|
DefChar = DefaultChar[1] ? ((DefaultChar[0] << 8) | DefaultChar[1]) : DefaultChar[0];
|
|
|
|
else
|
|
|
|
DefChar = CodePageTable->TransDefaultChar;
|
|
|
|
|
|
|
|
/* Does caller query for output buffer size? */
|
2016-09-18 21:10:07 +00:00
|
|
|
if (!MultiByteCount)
|
2008-07-11 19:11:06 +00:00
|
|
|
{
|
2016-09-18 21:10:07 +00:00
|
|
|
for (TempLength = 0; WideCharCount; WideCharCount--, WideCharString++, TempLength++)
|
2008-11-23 11:15:52 +00:00
|
|
|
{
|
|
|
|
USHORT uChar;
|
|
|
|
|
|
|
|
if ((Flags & WC_COMPOSITECHECK) && WideCharCount > 1)
|
|
|
|
{
|
|
|
|
/* FIXME: Handle WC_COMPOSITECHECK */
|
2016-09-28 17:33:36 +00:00
|
|
|
DPRINT("WC_COMPOSITECHECK flag UNIMPLEMENTED\n");
|
2008-11-23 11:15:52 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
uChar = ((PUSHORT) CodePageTable->WideCharTable)[*WideCharString];
|
|
|
|
|
|
|
|
/* Verify if the mapping is valid for handling DefaultChar and UsedDefaultChar */
|
|
|
|
if (!IntIsValidDBCSMapping(CodePageTable, Flags, *WideCharString, uChar))
|
|
|
|
{
|
|
|
|
uChar = DefChar;
|
|
|
|
*UsedDefaultChar = TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Increment TempLength again if this is a double-byte character */
|
|
|
|
if (uChar & 0xff00)
|
|
|
|
TempLength++;
|
|
|
|
}
|
|
|
|
|
|
|
|
return TempLength;
|
2008-07-11 19:11:06 +00:00
|
|
|
}
|
|
|
|
|
2008-11-23 11:15:52 +00:00
|
|
|
/* Convert the WideCharString to the MultiByteString and verify if the mapping is valid */
|
2016-09-18 21:10:07 +00:00
|
|
|
for (TempLength = MultiByteCount;
|
|
|
|
WideCharCount && TempLength;
|
|
|
|
TempLength--, WideCharString++, WideCharCount--)
|
2008-11-23 11:15:52 +00:00
|
|
|
{
|
|
|
|
USHORT uChar;
|
|
|
|
|
|
|
|
if ((Flags & WC_COMPOSITECHECK) && WideCharCount > 1)
|
|
|
|
{
|
|
|
|
/* FIXME: Handle WC_COMPOSITECHECK */
|
2016-09-28 17:33:36 +00:00
|
|
|
DPRINT("WC_COMPOSITECHECK flag UNIMPLEMENTED\n");
|
2008-11-23 11:15:52 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
uChar = ((PUSHORT)CodePageTable->WideCharTable)[*WideCharString];
|
|
|
|
|
|
|
|
/* Verify if the mapping is valid for handling DefaultChar and UsedDefaultChar */
|
|
|
|
if (!IntIsValidDBCSMapping(CodePageTable, Flags, *WideCharString, uChar))
|
|
|
|
{
|
|
|
|
uChar = DefChar;
|
|
|
|
*UsedDefaultChar = TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Handle double-byte characters */
|
|
|
|
if (uChar & 0xff00)
|
|
|
|
{
|
|
|
|
/* Don't output a partial character */
|
|
|
|
if (TempLength == 1)
|
|
|
|
break;
|
|
|
|
|
|
|
|
TempLength--;
|
|
|
|
*MultiByteString++ = uChar >> 8;
|
|
|
|
}
|
|
|
|
|
|
|
|
*MultiByteString++ = (char)uChar;
|
|
|
|
}
|
2008-07-11 19:11:06 +00:00
|
|
|
|
2008-11-23 11:15:52 +00:00
|
|
|
/* WideCharCount should be 0 if all characters were converted */
|
|
|
|
if (WideCharCount)
|
2008-07-11 19:11:06 +00:00
|
|
|
{
|
2008-11-23 11:15:52 +00:00
|
|
|
SetLastError(ERROR_INSUFFICIENT_BUFFER);
|
|
|
|
return 0;
|
2008-07-11 19:11:06 +00:00
|
|
|
}
|
|
|
|
|
2008-11-23 11:15:52 +00:00
|
|
|
return MultiByteCount - TempLength;
|
|
|
|
}
|
2008-07-11 19:11:06 +00:00
|
|
|
|
2008-11-23 11:15:52 +00:00
|
|
|
/* Does caller query for output buffer size? */
|
|
|
|
if (!MultiByteCount)
|
|
|
|
{
|
|
|
|
for (TempLength = 0; WideCharCount; WideCharCount--, WideCharString++, TempLength++)
|
2008-07-11 19:11:06 +00:00
|
|
|
{
|
2008-11-23 11:15:52 +00:00
|
|
|
/* Increment TempLength again if this is a double-byte character */
|
|
|
|
if (((PWCHAR)CodePageTable->WideCharTable)[*WideCharString] & 0xff00)
|
|
|
|
TempLength++;
|
2008-07-11 19:11:06 +00:00
|
|
|
}
|
|
|
|
|
2008-11-23 11:15:52 +00:00
|
|
|
return TempLength;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Convert the WideCharString to the MultiByteString */
|
|
|
|
for (TempLength = MultiByteCount;
|
|
|
|
WideCharCount && TempLength;
|
|
|
|
TempLength--, WideCharString++, WideCharCount--)
|
|
|
|
{
|
|
|
|
USHORT uChar = ((PUSHORT) CodePageTable->WideCharTable)[*WideCharString];
|
|
|
|
|
|
|
|
/* Is this a double-byte character? */
|
|
|
|
if (uChar & 0xff00)
|
2008-07-11 19:11:06 +00:00
|
|
|
{
|
2008-11-23 11:15:52 +00:00
|
|
|
/* Don't output a partial character */
|
|
|
|
if (TempLength == 1)
|
|
|
|
break;
|
2008-07-11 19:11:06 +00:00
|
|
|
|
2008-11-23 11:15:52 +00:00
|
|
|
TempLength--;
|
|
|
|
*MultiByteString++ = uChar >> 8;
|
2008-07-11 19:11:06 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
*MultiByteString++ = (char)uChar;
|
2008-11-23 11:15:52 +00:00
|
|
|
}
|
2008-07-11 19:11:06 +00:00
|
|
|
|
2008-11-23 11:15:52 +00:00
|
|
|
/* WideCharCount should be 0 if all characters were converted */
|
|
|
|
if (WideCharCount)
|
|
|
|
{
|
2008-07-11 19:11:06 +00:00
|
|
|
SetLastError(ERROR_INSUFFICIENT_BUFFER);
|
|
|
|
return 0;
|
2008-11-23 11:15:52 +00:00
|
|
|
}
|
2007-05-19 10:11:48 +00:00
|
|
|
|
2008-11-23 11:15:52 +00:00
|
|
|
return MultiByteCount - TempLength;
|
|
|
|
}
|
2016-09-18 21:10:07 +00:00
|
|
|
else /* SBCS code page */
|
2008-11-23 11:15:52 +00:00
|
|
|
{
|
|
|
|
INT nReturn;
|
2007-05-19 10:11:48 +00:00
|
|
|
|
2008-11-23 11:15:52 +00:00
|
|
|
/* If Flags, DefaultChar or UsedDefaultChar were given, we have to do some more work */
|
|
|
|
if (Flags || DefaultChar || UsedDefaultChar)
|
|
|
|
{
|
|
|
|
BOOL TempUsedDefaultChar;
|
|
|
|
CHAR DefChar;
|
2008-07-11 19:11:06 +00:00
|
|
|
|
2008-11-23 11:15:52 +00:00
|
|
|
/* If UsedDefaultChar is not set, set it to a temporary value, so we don't have
|
|
|
|
to check on every character */
|
|
|
|
if (!UsedDefaultChar)
|
|
|
|
UsedDefaultChar = &TempUsedDefaultChar;
|
2008-07-11 19:11:06 +00:00
|
|
|
|
2008-11-23 11:15:52 +00:00
|
|
|
*UsedDefaultChar = FALSE;
|
2008-07-11 19:11:06 +00:00
|
|
|
|
2008-11-23 11:15:52 +00:00
|
|
|
/* Does caller query for output buffer size? */
|
|
|
|
if (!MultiByteCount)
|
|
|
|
{
|
|
|
|
/* Loop through the whole WideCharString and check if we can get a valid mapping for each character */
|
|
|
|
for (TempLength = 0; WideCharCount; TempLength++, WideCharString++, WideCharCount--)
|
|
|
|
{
|
|
|
|
if ((Flags & WC_COMPOSITECHECK) && WideCharCount > 1)
|
|
|
|
{
|
|
|
|
/* FIXME: Handle WC_COMPOSITECHECK */
|
2016-09-28 17:33:36 +00:00
|
|
|
DPRINT("WC_COMPOSITECHECK flag UNIMPLEMENTED\n");
|
2008-11-23 11:15:52 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if (!*UsedDefaultChar)
|
|
|
|
*UsedDefaultChar = !IntIsValidSBCSMapping(CodePageTable,
|
|
|
|
Flags,
|
|
|
|
*WideCharString,
|
|
|
|
((PCHAR)CodePageTable->WideCharTable)[*WideCharString]);
|
|
|
|
}
|
|
|
|
|
|
|
|
return TempLength;
|
2007-05-19 10:11:48 +00:00
|
|
|
}
|
|
|
|
|
2008-11-23 11:15:52 +00:00
|
|
|
/* Use the CodePage's TransDefaultChar if none was given. Don't modify the DefaultChar pointer here. */
|
|
|
|
if (DefaultChar)
|
|
|
|
DefChar = *DefaultChar;
|
|
|
|
else
|
2013-09-14 10:20:11 +00:00
|
|
|
DefChar = (CHAR)CodePageTable->TransDefaultChar;
|
2008-11-23 11:15:52 +00:00
|
|
|
|
|
|
|
/* Convert the WideCharString to the MultiByteString and verify if the mapping is valid */
|
|
|
|
for (TempLength = MultiByteCount;
|
|
|
|
WideCharCount && TempLength;
|
|
|
|
MultiByteString++, TempLength--, WideCharString++, WideCharCount--)
|
2008-07-11 19:11:06 +00:00
|
|
|
{
|
2008-11-23 11:15:52 +00:00
|
|
|
if ((Flags & WC_COMPOSITECHECK) && WideCharCount > 1)
|
|
|
|
{
|
|
|
|
/* FIXME: Handle WC_COMPOSITECHECK */
|
2016-09-28 17:33:36 +00:00
|
|
|
DPRINT("WC_COMPOSITECHECK flag UNIMPLEMENTED\n");
|
2008-11-23 11:15:52 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
*MultiByteString = ((PCHAR)CodePageTable->WideCharTable)[*WideCharString];
|
|
|
|
|
|
|
|
if (!IntIsValidSBCSMapping(CodePageTable, Flags, *WideCharString, *MultiByteString))
|
|
|
|
{
|
|
|
|
*MultiByteString = DefChar;
|
|
|
|
*UsedDefaultChar = TRUE;
|
|
|
|
}
|
2008-07-11 19:11:06 +00:00
|
|
|
}
|
|
|
|
|
2008-11-23 11:15:52 +00:00
|
|
|
/* WideCharCount should be 0 if all characters were converted */
|
|
|
|
if (WideCharCount)
|
2008-07-11 19:11:06 +00:00
|
|
|
{
|
2008-11-23 11:15:52 +00:00
|
|
|
SetLastError(ERROR_INSUFFICIENT_BUFFER);
|
|
|
|
return 0;
|
2008-07-11 19:11:06 +00:00
|
|
|
}
|
|
|
|
|
2008-11-23 11:15:52 +00:00
|
|
|
return MultiByteCount - TempLength;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Does caller query for output buffer size? */
|
|
|
|
if (!MultiByteCount)
|
|
|
|
return WideCharCount;
|
|
|
|
|
|
|
|
/* Is the buffer large enough? */
|
|
|
|
if (MultiByteCount < WideCharCount)
|
|
|
|
{
|
|
|
|
/* Convert the string up to MultiByteCount and return 0 */
|
|
|
|
WideCharCount = MultiByteCount;
|
2007-05-19 10:11:48 +00:00
|
|
|
SetLastError(ERROR_INSUFFICIENT_BUFFER);
|
2008-11-23 11:15:52 +00:00
|
|
|
nReturn = 0;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
/* Otherwise WideCharCount will be the number of converted characters */
|
|
|
|
nReturn = WideCharCount;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Convert the WideCharString to the MultiByteString */
|
|
|
|
for (TempLength = WideCharCount; --TempLength >= 0; WideCharString++, MultiByteString++)
|
|
|
|
{
|
|
|
|
*MultiByteString = ((PCHAR)CodePageTable->WideCharTable)[*WideCharString];
|
|
|
|
}
|
|
|
|
|
|
|
|
return nReturn;
|
|
|
|
}
|
2004-08-24 17:21:12 +00:00
|
|
|
}
|
|
|
|
|
2007-10-19 23:21:45 +00:00
|
|
|
/**
|
2005-08-29 21:06:07 +00:00
|
|
|
* @name IntIsLeadByte
|
|
|
|
*
|
|
|
|
* Internal function to detect if byte is lead byte in specific character
|
|
|
|
* table.
|
|
|
|
*/
|
|
|
|
|
2008-11-23 11:15:52 +00:00
|
|
|
static BOOL
|
2008-11-30 11:42:05 +00:00
|
|
|
WINAPI
|
2005-08-29 21:06:07 +00:00
|
|
|
IntIsLeadByte(PCPTABLEINFO TableInfo, BYTE Byte)
|
|
|
|
{
|
2008-12-13 15:42:56 +00:00
|
|
|
UINT i;
|
2008-11-23 11:15:52 +00:00
|
|
|
|
|
|
|
if (TableInfo->MaximumCharacterSize == 2)
|
|
|
|
{
|
2008-12-13 15:42:56 +00:00
|
|
|
for (i = 0; i < MAXIMUM_LEADBYTES && TableInfo->LeadByte[i]; i += 2)
|
2008-11-23 11:15:52 +00:00
|
|
|
{
|
2008-12-13 15:42:56 +00:00
|
|
|
if (Byte >= TableInfo->LeadByte[i] && Byte <= TableInfo->LeadByte[i+1])
|
2008-11-23 11:15:52 +00:00
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return FALSE;
|
2005-08-29 21:06:07 +00:00
|
|
|
}
|
|
|
|
|
2004-08-24 17:21:12 +00:00
|
|
|
/* PUBLIC FUNCTIONS ***********************************************************/
|
|
|
|
|
|
|
|
/**
|
2005-08-29 21:06:07 +00:00
|
|
|
* @name GetNlsSectionName
|
|
|
|
*
|
2004-08-24 17:21:12 +00:00
|
|
|
* Construct a name of NLS section.
|
|
|
|
*
|
|
|
|
* @param CodePage
|
|
|
|
* Code page number.
|
|
|
|
* @param Base
|
|
|
|
* Integer base used for converting to string. Usually set to 10.
|
|
|
|
* @param Unknown
|
|
|
|
* As the name suggests the meaning of this parameter is unknown.
|
|
|
|
* The native version of Kernel32 passes it as the third parameter
|
|
|
|
* to NlsConvertIntegerToString function, which is used for the
|
|
|
|
* actual conversion of the code page number.
|
|
|
|
* @param BaseName
|
|
|
|
* Base name of the section. (ex. "\\Nls\\NlsSectionCP")
|
|
|
|
* @param Result
|
|
|
|
* Buffer that will hold the constructed name.
|
|
|
|
* @param ResultSize
|
|
|
|
* Size of the buffer for the result.
|
|
|
|
*
|
|
|
|
* @return TRUE if the buffer was large enough and was filled with
|
|
|
|
* the requested information, FALSE otherwise.
|
|
|
|
*
|
|
|
|
* @implemented
|
|
|
|
*/
|
2005-08-29 21:06:07 +00:00
|
|
|
|
2008-11-23 11:15:52 +00:00
|
|
|
BOOL
|
2008-11-30 11:42:05 +00:00
|
|
|
WINAPI
|
2008-11-23 11:15:52 +00:00
|
|
|
GetNlsSectionName(UINT CodePage,
|
|
|
|
UINT Base,
|
|
|
|
ULONG Unknown,
|
|
|
|
LPSTR BaseName,
|
|
|
|
LPSTR Result,
|
|
|
|
ULONG ResultSize)
|
2004-08-24 17:21:12 +00:00
|
|
|
{
|
2008-11-23 11:15:52 +00:00
|
|
|
CHAR Integer[11];
|
2004-08-24 17:21:12 +00:00
|
|
|
|
2008-11-23 11:15:52 +00:00
|
|
|
if (!NT_SUCCESS(RtlIntegerToChar(CodePage, Base, sizeof(Integer), Integer)))
|
|
|
|
return FALSE;
|
2004-08-24 17:21:12 +00:00
|
|
|
|
2008-11-23 11:15:52 +00:00
|
|
|
/*
|
|
|
|
* If the name including the terminating NULL character doesn't
|
|
|
|
* fit in the output buffer then fail.
|
|
|
|
*/
|
|
|
|
if (strlen(Integer) + strlen(BaseName) >= ResultSize)
|
|
|
|
return FALSE;
|
2004-08-24 17:21:12 +00:00
|
|
|
|
2008-11-23 11:15:52 +00:00
|
|
|
lstrcpyA(Result, BaseName);
|
|
|
|
lstrcatA(Result, Integer);
|
2004-08-24 17:21:12 +00:00
|
|
|
|
2008-11-23 11:15:52 +00:00
|
|
|
return TRUE;
|
2004-08-24 17:21:12 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
2005-08-29 21:06:07 +00:00
|
|
|
* @name GetCPFileNameFromRegistry
|
|
|
|
*
|
2004-08-24 17:21:12 +00:00
|
|
|
* Get file name of code page definition file.
|
|
|
|
*
|
|
|
|
* @param CodePage
|
|
|
|
* Code page number to get file name of.
|
|
|
|
* @param FileName
|
2005-05-09 01:46:57 +00:00
|
|
|
* Buffer that is filled with file name of successful return. Can
|
2004-08-24 17:21:12 +00:00
|
|
|
* be set to NULL.
|
|
|
|
* @param FileNameSize
|
|
|
|
* Size of the buffer to hold file name in WCHARs.
|
|
|
|
*
|
|
|
|
* @return TRUE if the file name was retrieved, FALSE otherwise.
|
|
|
|
*
|
|
|
|
* @implemented
|
|
|
|
*/
|
2005-08-29 21:06:07 +00:00
|
|
|
|
2008-11-23 11:15:52 +00:00
|
|
|
BOOL
|
2008-11-30 11:42:05 +00:00
|
|
|
WINAPI
|
2004-08-24 17:21:12 +00:00
|
|
|
GetCPFileNameFromRegistry(UINT CodePage, LPWSTR FileName, ULONG FileNameSize)
|
|
|
|
{
|
2008-11-23 11:15:52 +00:00
|
|
|
WCHAR ValueNameBuffer[11];
|
|
|
|
UNICODE_STRING KeyName, ValueName;
|
|
|
|
OBJECT_ATTRIBUTES ObjectAttributes;
|
|
|
|
NTSTATUS Status;
|
|
|
|
HANDLE KeyHandle;
|
|
|
|
PKEY_VALUE_PARTIAL_INFORMATION Kvpi;
|
|
|
|
DWORD KvpiSize;
|
|
|
|
BOOL bRetValue;
|
|
|
|
|
|
|
|
bRetValue = FALSE;
|
|
|
|
|
|
|
|
/* Convert the codepage number to string. */
|
|
|
|
ValueName.Buffer = ValueNameBuffer;
|
|
|
|
ValueName.MaximumLength = sizeof(ValueNameBuffer);
|
|
|
|
|
|
|
|
if (!NT_SUCCESS(RtlIntegerToUnicodeString(CodePage, 10, &ValueName)))
|
|
|
|
return bRetValue;
|
|
|
|
|
|
|
|
/* Open the registry key containing file name mappings. */
|
|
|
|
RtlInitUnicodeString(&KeyName, L"\\Registry\\Machine\\System\\"
|
|
|
|
L"CurrentControlSet\\Control\\Nls\\CodePage");
|
|
|
|
InitializeObjectAttributes(&ObjectAttributes, &KeyName, OBJ_CASE_INSENSITIVE,
|
|
|
|
NULL, NULL);
|
|
|
|
Status = NtOpenKey(&KeyHandle, KEY_READ, &ObjectAttributes);
|
|
|
|
if (!NT_SUCCESS(Status))
|
|
|
|
{
|
|
|
|
return bRetValue;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Allocate buffer that will be used to query the value data. */
|
|
|
|
KvpiSize = sizeof(KEY_VALUE_PARTIAL_INFORMATION) + (MAX_PATH * sizeof(WCHAR));
|
|
|
|
Kvpi = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, KvpiSize);
|
|
|
|
if (Kvpi == NULL)
|
|
|
|
{
|
|
|
|
NtClose(KeyHandle);
|
|
|
|
return bRetValue;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Query the file name for our code page. */
|
|
|
|
Status = NtQueryValueKey(KeyHandle, &ValueName, KeyValuePartialInformation,
|
|
|
|
Kvpi, KvpiSize, &KvpiSize);
|
|
|
|
|
|
|
|
NtClose(KeyHandle);
|
|
|
|
|
|
|
|
/* Check if we succeded and the value is non-empty string. */
|
|
|
|
if (NT_SUCCESS(Status) && Kvpi->Type == REG_SZ &&
|
|
|
|
Kvpi->DataLength > sizeof(WCHAR))
|
|
|
|
{
|
|
|
|
bRetValue = TRUE;
|
|
|
|
if (FileName != NULL)
|
|
|
|
{
|
|
|
|
lstrcpynW(FileName, (WCHAR*)Kvpi->Data,
|
|
|
|
min(Kvpi->DataLength / sizeof(WCHAR), FileNameSize));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* free temporary buffer */
|
|
|
|
HeapFree(GetProcessHeap(),0,Kvpi);
|
|
|
|
return bRetValue;
|
2004-08-24 17:21:12 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
2005-08-29 21:06:07 +00:00
|
|
|
* @name IsValidCodePage
|
|
|
|
*
|
2004-08-24 17:21:12 +00:00
|
|
|
* Detect if specified code page is valid and present in the system.
|
|
|
|
*
|
|
|
|
* @param CodePage
|
|
|
|
* Code page number to query.
|
|
|
|
*
|
|
|
|
* @return TRUE if code page is present.
|
|
|
|
*/
|
2005-08-29 21:06:07 +00:00
|
|
|
|
2008-11-23 11:15:52 +00:00
|
|
|
BOOL
|
2008-11-30 11:42:05 +00:00
|
|
|
WINAPI
|
2004-08-24 17:21:12 +00:00
|
|
|
IsValidCodePage(UINT CodePage)
|
|
|
|
{
|
2009-04-13 17:13:35 +00:00
|
|
|
if (CodePage == 0) return FALSE;
|
2008-11-23 11:15:52 +00:00
|
|
|
if (CodePage == CP_UTF8 || CodePage == CP_UTF7)
|
|
|
|
return TRUE;
|
|
|
|
if (IntGetLoadedCodePageEntry(CodePage))
|
|
|
|
return TRUE;
|
|
|
|
return GetCPFileNameFromRegistry(CodePage, NULL, 0);
|
2004-08-24 17:21:12 +00:00
|
|
|
}
|
|
|
|
|
2015-06-28 09:00:03 +00:00
|
|
|
static inline BOOL utf7_write_w(WCHAR *dst, int dstlen, int *index, WCHAR character)
|
2010-05-18 06:34:48 +00:00
|
|
|
{
|
2015-06-28 09:00:03 +00:00
|
|
|
if (dstlen > 0)
|
2010-05-18 06:34:48 +00:00
|
|
|
{
|
2015-06-28 09:00:03 +00:00
|
|
|
if (*index >= dstlen)
|
|
|
|
return FALSE;
|
2010-05-18 06:34:48 +00:00
|
|
|
|
2015-06-28 09:00:03 +00:00
|
|
|
dst[*index] = character;
|
2010-05-18 06:34:48 +00:00
|
|
|
}
|
2015-06-28 09:00:03 +00:00
|
|
|
|
|
|
|
(*index)++;
|
|
|
|
|
|
|
|
return TRUE;
|
2010-05-18 06:34:48 +00:00
|
|
|
}
|
|
|
|
|
2015-06-28 09:00:03 +00:00
|
|
|
static INT Utf7ToWideChar(const char *src, int srclen, WCHAR *dst, int dstlen)
|
2010-05-18 06:34:48 +00:00
|
|
|
{
|
2015-06-28 09:00:03 +00:00
|
|
|
static const signed char base64_decoding_table[] =
|
2010-05-18 06:34:48 +00:00
|
|
|
{
|
2015-06-28 09:00:03 +00:00
|
|
|
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 0x00-0x0F */
|
|
|
|
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 0x10-0x1F */
|
|
|
|
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 62, -1, -1, -1, 63, /* 0x20-0x2F */
|
|
|
|
52, 53, 54, 55, 56, 57, 58, 59, 60, 61, -1, -1, -1, -1, -1, -1, /* 0x30-0x3F */
|
|
|
|
-1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, /* 0x40-0x4F */
|
|
|
|
15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, -1, -1, -1, -1, -1, /* 0x50-0x5F */
|
|
|
|
-1, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, /* 0x60-0x6F */
|
|
|
|
41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, -1, -1, -1, -1, -1 /* 0x70-0x7F */
|
|
|
|
};
|
|
|
|
|
|
|
|
const char *source_end = src + srclen;
|
|
|
|
int dest_index = 0;
|
|
|
|
|
|
|
|
DWORD byte_pair = 0;
|
|
|
|
short offset = 0;
|
|
|
|
|
|
|
|
while (src < source_end)
|
|
|
|
{
|
|
|
|
if (*src == '+')
|
2010-05-18 06:34:48 +00:00
|
|
|
{
|
2015-06-28 09:00:03 +00:00
|
|
|
src++;
|
|
|
|
if (src >= source_end)
|
|
|
|
break;
|
|
|
|
|
|
|
|
if (*src == '-')
|
2010-05-18 06:34:48 +00:00
|
|
|
{
|
2015-06-28 09:00:03 +00:00
|
|
|
/* just a plus sign escaped as +- */
|
|
|
|
if (!utf7_write_w(dst, dstlen, &dest_index, '+'))
|
|
|
|
{
|
|
|
|
SetLastError(ERROR_INSUFFICIENT_BUFFER);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
src++;
|
2010-05-18 06:34:48 +00:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2015-06-28 09:00:03 +00:00
|
|
|
do
|
|
|
|
{
|
|
|
|
signed char sextet = *src;
|
|
|
|
if (sextet == '-')
|
|
|
|
{
|
|
|
|
/* skip over the dash and end base64 decoding
|
|
|
|
* the current, unfinished byte pair is discarded */
|
|
|
|
src++;
|
|
|
|
offset = 0;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
if (sextet < 0)
|
|
|
|
{
|
|
|
|
/* the next character of src is < 0 and therefore not part of a base64 sequence
|
|
|
|
* the current, unfinished byte pair is NOT discarded in this case
|
|
|
|
* this is probably a bug in Windows */
|
|
|
|
break;
|
|
|
|
}
|
2010-05-18 06:34:48 +00:00
|
|
|
|
2015-06-28 09:00:03 +00:00
|
|
|
sextet = base64_decoding_table[sextet];
|
|
|
|
if (sextet == -1)
|
|
|
|
{
|
|
|
|
/* -1 means that the next character of src is not part of a base64 sequence
|
|
|
|
* in other words, all sextets in this base64 sequence have been processed
|
|
|
|
* the current, unfinished byte pair is discarded */
|
|
|
|
offset = 0;
|
|
|
|
break;
|
|
|
|
}
|
2010-05-18 06:34:48 +00:00
|
|
|
|
2015-06-28 09:00:03 +00:00
|
|
|
byte_pair = (byte_pair << 6) | sextet;
|
|
|
|
offset += 6;
|
2010-05-18 06:34:48 +00:00
|
|
|
|
2015-06-28 09:00:03 +00:00
|
|
|
if (offset >= 16)
|
|
|
|
{
|
|
|
|
/* this byte pair is done */
|
|
|
|
if (!utf7_write_w(dst, dstlen, &dest_index, (byte_pair >> (offset - 16)) & 0xFFFF))
|
|
|
|
{
|
|
|
|
SetLastError(ERROR_INSUFFICIENT_BUFFER);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
offset -= 16;
|
|
|
|
}
|
2010-05-18 06:34:48 +00:00
|
|
|
|
2015-06-28 09:00:03 +00:00
|
|
|
src++;
|
2010-05-18 06:34:48 +00:00
|
|
|
}
|
2015-06-28 09:00:03 +00:00
|
|
|
while (src < source_end);
|
2010-05-18 06:34:48 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2015-06-28 09:00:03 +00:00
|
|
|
/* we have to convert to unsigned char in case *src < 0 */
|
|
|
|
if (!utf7_write_w(dst, dstlen, &dest_index, (unsigned char)*src))
|
|
|
|
{
|
|
|
|
SetLastError(ERROR_INSUFFICIENT_BUFFER);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
src++;
|
2010-05-18 06:34:48 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-06-28 09:00:03 +00:00
|
|
|
return dest_index;
|
2010-05-18 06:34:48 +00:00
|
|
|
}
|
|
|
|
|
2004-08-24 17:21:12 +00:00
|
|
|
/**
|
2005-08-29 21:06:07 +00:00
|
|
|
* @name MultiByteToWideChar
|
|
|
|
*
|
2004-08-24 17:21:12 +00:00
|
|
|
* Convert a multi-byte string to wide-charater equivalent.
|
|
|
|
*
|
|
|
|
* @param CodePage
|
|
|
|
* Code page to be used to perform the conversion. It can be also
|
|
|
|
* one of the special values (CP_ACP for ANSI code page, CP_MACCP
|
|
|
|
* for Macintosh code page, CP_OEMCP for OEM code page, CP_THREAD_ACP
|
|
|
|
* for thread active code page, CP_UTF7 or CP_UTF8).
|
|
|
|
* @param Flags
|
|
|
|
* Additional conversion flags (MB_PRECOMPOSED, MB_COMPOSITE,
|
|
|
|
* MB_ERR_INVALID_CHARS, MB_USEGLYPHCHARS).
|
|
|
|
* @param MultiByteString
|
|
|
|
* Input buffer.
|
|
|
|
* @param MultiByteCount
|
|
|
|
* Size of MultiByteString, or -1 if MultiByteString is NULL
|
|
|
|
* terminated.
|
|
|
|
* @param WideCharString
|
|
|
|
* Output buffer.
|
|
|
|
* @param WideCharCount
|
|
|
|
* Size in WCHARs of WideCharString, or 0 if the caller just wants
|
|
|
|
* to know how large WideCharString should be for a successful
|
|
|
|
* conversion.
|
|
|
|
*
|
|
|
|
* @return Zero on error, otherwise the number of WCHARs written
|
|
|
|
* in the WideCharString buffer.
|
|
|
|
*
|
|
|
|
* @implemented
|
|
|
|
*/
|
2005-08-29 21:06:07 +00:00
|
|
|
|
2008-11-23 11:15:52 +00:00
|
|
|
INT
|
2008-11-30 11:42:05 +00:00
|
|
|
WINAPI
|
2008-11-23 11:15:52 +00:00
|
|
|
MultiByteToWideChar(UINT CodePage,
|
|
|
|
DWORD Flags,
|
|
|
|
LPCSTR MultiByteString,
|
|
|
|
INT MultiByteCount,
|
|
|
|
LPWSTR WideCharString,
|
|
|
|
INT WideCharCount)
|
2004-08-24 17:21:12 +00:00
|
|
|
{
|
2008-11-23 11:15:52 +00:00
|
|
|
/* Check the parameters. */
|
|
|
|
if (MultiByteString == NULL ||
|
2016-09-18 17:26:59 +00:00
|
|
|
MultiByteCount == 0 || WideCharCount < 0 ||
|
|
|
|
(WideCharCount && (WideCharString == NULL ||
|
|
|
|
(PVOID)MultiByteString == (PVOID)WideCharString)))
|
2008-11-23 11:15:52 +00:00
|
|
|
{
|
|
|
|
SetLastError(ERROR_INVALID_PARAMETER);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Determine the input string length. */
|
|
|
|
if (MultiByteCount < 0)
|
|
|
|
{
|
|
|
|
MultiByteCount = lstrlenA(MultiByteString) + 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
switch (CodePage)
|
|
|
|
{
|
|
|
|
case CP_UTF8:
|
|
|
|
return IntMultiByteToWideCharUTF8(Flags,
|
|
|
|
MultiByteString,
|
|
|
|
MultiByteCount,
|
|
|
|
WideCharString,
|
|
|
|
WideCharCount);
|
|
|
|
|
|
|
|
case CP_UTF7:
|
2010-05-18 06:34:48 +00:00
|
|
|
if (Flags)
|
|
|
|
{
|
|
|
|
SetLastError(ERROR_INVALID_FLAGS);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
return Utf7ToWideChar(MultiByteString, MultiByteCount,
|
|
|
|
WideCharString, WideCharCount);
|
2004-08-24 17:21:12 +00:00
|
|
|
|
2008-11-23 11:15:52 +00:00
|
|
|
case CP_SYMBOL:
|
|
|
|
return IntMultiByteToWideCharSYMBOL(Flags,
|
|
|
|
MultiByteString,
|
|
|
|
MultiByteCount,
|
|
|
|
WideCharString,
|
|
|
|
WideCharCount);
|
|
|
|
default:
|
|
|
|
return IntMultiByteToWideCharCP(CodePage,
|
|
|
|
Flags,
|
|
|
|
MultiByteString,
|
|
|
|
MultiByteCount,
|
|
|
|
WideCharString,
|
|
|
|
WideCharCount);
|
|
|
|
}
|
2004-08-24 17:21:12 +00:00
|
|
|
}
|
|
|
|
|
2015-06-28 10:21:52 +00:00
|
|
|
static inline BOOL utf7_can_directly_encode(WCHAR codepoint)
|
2010-05-18 06:34:48 +00:00
|
|
|
{
|
2015-06-28 10:21:52 +00:00
|
|
|
static const BOOL directly_encodable_table[] =
|
|
|
|
{
|
|
|
|
1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 1, 0, 0, /* 0x00 - 0x0F */
|
|
|
|
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x10 - 0x1F */
|
|
|
|
1, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 1, 1, 1, 1, 1, /* 0x20 - 0x2F */
|
|
|
|
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 1, /* 0x30 - 0x3F */
|
|
|
|
0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 0x40 - 0x4F */
|
|
|
|
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, /* 0x50 - 0x5F */
|
|
|
|
0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 0x60 - 0x6F */
|
|
|
|
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 /* 0x70 - 0x7A */
|
|
|
|
};
|
2010-05-18 06:34:48 +00:00
|
|
|
|
2015-06-28 10:21:52 +00:00
|
|
|
return codepoint <= 0x7A ? directly_encodable_table[codepoint] : FALSE;
|
|
|
|
}
|
2010-05-18 06:34:48 +00:00
|
|
|
|
2015-06-28 10:21:52 +00:00
|
|
|
static inline BOOL utf7_write_c(char *dst, int dstlen, int *index, char character)
|
2010-05-18 06:34:48 +00:00
|
|
|
{
|
2015-06-28 10:21:52 +00:00
|
|
|
if (dstlen > 0)
|
2010-05-18 06:34:48 +00:00
|
|
|
{
|
2015-06-28 10:21:52 +00:00
|
|
|
if (*index >= dstlen)
|
|
|
|
return FALSE;
|
|
|
|
|
|
|
|
dst[*index] = character;
|
2010-05-18 06:34:48 +00:00
|
|
|
}
|
|
|
|
|
2015-06-28 10:21:52 +00:00
|
|
|
(*index)++;
|
|
|
|
|
|
|
|
return TRUE;
|
2010-05-18 06:34:48 +00:00
|
|
|
}
|
|
|
|
|
2015-06-28 10:21:52 +00:00
|
|
|
static INT WideCharToUtf7(const WCHAR *src, int srclen, char *dst, int dstlen)
|
2010-05-18 06:34:48 +00:00
|
|
|
{
|
2015-06-28 10:21:52 +00:00
|
|
|
static const char base64_encoding_table[] =
|
|
|
|
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
|
2010-05-18 06:34:48 +00:00
|
|
|
|
2015-06-28 10:21:52 +00:00
|
|
|
const WCHAR *source_end = src + srclen;
|
|
|
|
int dest_index = 0;
|
2010-05-18 06:34:48 +00:00
|
|
|
|
2015-06-28 10:21:52 +00:00
|
|
|
while (src < source_end)
|
2010-05-18 06:34:48 +00:00
|
|
|
{
|
2015-06-28 10:21:52 +00:00
|
|
|
if (*src == '+')
|
2010-05-18 06:34:48 +00:00
|
|
|
{
|
2015-06-28 10:21:52 +00:00
|
|
|
if (!utf7_write_c(dst, dstlen, &dest_index, '+'))
|
|
|
|
{
|
|
|
|
SetLastError(ERROR_INSUFFICIENT_BUFFER);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
if (!utf7_write_c(dst, dstlen, &dest_index, '-'))
|
|
|
|
{
|
|
|
|
SetLastError(ERROR_INSUFFICIENT_BUFFER);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
src++;
|
2010-05-18 06:34:48 +00:00
|
|
|
}
|
2015-06-28 10:21:52 +00:00
|
|
|
else if (utf7_can_directly_encode(*src))
|
2010-05-18 06:34:48 +00:00
|
|
|
{
|
2015-06-28 10:21:52 +00:00
|
|
|
if (!utf7_write_c(dst, dstlen, &dest_index, *src))
|
2010-05-18 06:34:48 +00:00
|
|
|
{
|
2015-06-28 10:21:52 +00:00
|
|
|
SetLastError(ERROR_INSUFFICIENT_BUFFER);
|
|
|
|
return 0;
|
2010-05-18 06:34:48 +00:00
|
|
|
}
|
2015-06-28 10:21:52 +00:00
|
|
|
src++;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
unsigned int offset = 0;
|
|
|
|
DWORD byte_pair = 0;
|
|
|
|
|
|
|
|
if (!utf7_write_c(dst, dstlen, &dest_index, '+'))
|
2010-05-18 06:34:48 +00:00
|
|
|
{
|
2015-06-28 10:21:52 +00:00
|
|
|
SetLastError(ERROR_INSUFFICIENT_BUFFER);
|
|
|
|
return 0;
|
2010-05-18 06:34:48 +00:00
|
|
|
}
|
2015-06-28 10:21:52 +00:00
|
|
|
|
|
|
|
while (src < source_end && !utf7_can_directly_encode(*src))
|
2010-05-18 06:34:48 +00:00
|
|
|
{
|
2015-06-28 10:21:52 +00:00
|
|
|
byte_pair = (byte_pair << 16) | *src;
|
|
|
|
offset += 16;
|
|
|
|
while (offset >= 6)
|
2010-05-18 06:34:48 +00:00
|
|
|
{
|
2015-06-28 10:21:52 +00:00
|
|
|
if (!utf7_write_c(dst, dstlen, &dest_index, base64_encoding_table[(byte_pair >> (offset - 6)) & 0x3F]))
|
|
|
|
{
|
|
|
|
SetLastError(ERROR_INSUFFICIENT_BUFFER);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
offset -= 6;
|
2010-05-18 06:34:48 +00:00
|
|
|
}
|
2015-06-28 10:21:52 +00:00
|
|
|
src++;
|
2010-05-18 06:34:48 +00:00
|
|
|
}
|
2015-06-28 10:21:52 +00:00
|
|
|
|
|
|
|
if (offset)
|
2010-05-18 06:34:48 +00:00
|
|
|
{
|
2015-06-28 10:21:52 +00:00
|
|
|
/* Windows won't create a padded base64 character if there's no room for the - sign
|
|
|
|
* as well ; this is probably a bug in Windows */
|
|
|
|
if (dstlen > 0 && dest_index + 1 >= dstlen)
|
|
|
|
{
|
|
|
|
SetLastError(ERROR_INSUFFICIENT_BUFFER);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
byte_pair <<= (6 - offset);
|
|
|
|
if (!utf7_write_c(dst, dstlen, &dest_index, base64_encoding_table[byte_pair & 0x3F]))
|
2010-05-18 06:34:48 +00:00
|
|
|
{
|
2015-06-28 10:21:52 +00:00
|
|
|
SetLastError(ERROR_INSUFFICIENT_BUFFER);
|
|
|
|
return 0;
|
2010-05-18 06:34:48 +00:00
|
|
|
}
|
|
|
|
}
|
2015-06-28 10:21:52 +00:00
|
|
|
|
|
|
|
/* Windows always explicitly terminates the base64 sequence
|
|
|
|
even though RFC 2152 (page 3, rule 2) does not require this */
|
|
|
|
if (!utf7_write_c(dst, dstlen, &dest_index, '-'))
|
2010-05-18 06:34:48 +00:00
|
|
|
{
|
2015-06-28 10:21:52 +00:00
|
|
|
SetLastError(ERROR_INSUFFICIENT_BUFFER);
|
|
|
|
return 0;
|
2010-05-18 06:34:48 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-06-28 10:21:52 +00:00
|
|
|
return dest_index;
|
2010-05-18 06:34:48 +00:00
|
|
|
}
|
|
|
|
|
2017-04-26 17:38:57 +00:00
|
|
|
/*
|
|
|
|
* A function similar to LoadStringW, but adapted for usage by GetCPInfoExW
|
|
|
|
* and GetGeoInfoW. It uses the current user localization, otherwise falls back
|
|
|
|
* to English (US). Contrary to LoadStringW which always saves the loaded string
|
|
|
|
* into the user-given buffer, truncating the string if needed, this function
|
|
|
|
* returns instead an ERROR_INSUFFICIENT_BUFFER error code if the user buffer
|
|
|
|
* is not large enough.
|
|
|
|
*/
|
|
|
|
UINT
|
|
|
|
GetLocalisedText(
|
|
|
|
IN UINT uID,
|
|
|
|
IN LPWSTR lpszDest,
|
|
|
|
IN UINT cchDest)
|
[KERNEL32]: Winesync all there is to Winesync in ReactOS' kernel32. This mainly affects LZ*, Comm*, *ProfileString* (INI), and *Resource* APIs, however the changes in there are relatively minor. More substantial changes affect the locale/NLS/language functions, many which were bitrotting for 6+ years.
In theory, this code is "better" than before, and it is closer to Wine (which arguably has better compatibility). It also resets things in sync with Wine however, and may lose and "fixes" ReactOS may have added over the years. But this is a good thing, since these fixes have been "lost" (they obviously never made it into Wine), and if regressions are now found due to this, actual upstream patches can be sent and picked up on the next sync. This avoids maintaining duplicate code, at the expenses of some potential short-term regressions in i18n.
Finally, note that much of /string seems to be taken from Wine's Unicode library (which a host "unicode" already exists in ReactOS' tools/. It may be better (for someone with more experience as to these wine-isms) to simply just pull-in whatever winelib files are not currently present in ReactOS, and have kernel32 and tools/unicode use winelib, instead of having 2 or 3 copies of the code.
svn path=/trunk/; revision=52754
2011-07-21 05:24:59 +00:00
|
|
|
{
|
|
|
|
HRSRC hrsrc;
|
2017-04-26 17:38:57 +00:00
|
|
|
HGLOBAL hmem;
|
[KERNEL32]: Winesync all there is to Winesync in ReactOS' kernel32. This mainly affects LZ*, Comm*, *ProfileString* (INI), and *Resource* APIs, however the changes in there are relatively minor. More substantial changes affect the locale/NLS/language functions, many which were bitrotting for 6+ years.
In theory, this code is "better" than before, and it is closer to Wine (which arguably has better compatibility). It also resets things in sync with Wine however, and may lose and "fixes" ReactOS may have added over the years. But this is a good thing, since these fixes have been "lost" (they obviously never made it into Wine), and if regressions are now found due to this, actual upstream patches can be sent and picked up on the next sync. This avoids maintaining duplicate code, at the expenses of some potential short-term regressions in i18n.
Finally, note that much of /string seems to be taken from Wine's Unicode library (which a host "unicode" already exists in ReactOS' tools/. It may be better (for someone with more experience as to these wine-isms) to simply just pull-in whatever winelib files are not currently present in ReactOS, and have kernel32 and tools/unicode use winelib, instead of having 2 or 3 copies of the code.
svn path=/trunk/; revision=52754
2011-07-21 05:24:59 +00:00
|
|
|
LCID lcid;
|
|
|
|
LANGID langId;
|
2017-04-26 17:38:57 +00:00
|
|
|
const WCHAR *p;
|
|
|
|
UINT i;
|
[KERNEL32]: Winesync all there is to Winesync in ReactOS' kernel32. This mainly affects LZ*, Comm*, *ProfileString* (INI), and *Resource* APIs, however the changes in there are relatively minor. More substantial changes affect the locale/NLS/language functions, many which were bitrotting for 6+ years.
In theory, this code is "better" than before, and it is closer to Wine (which arguably has better compatibility). It also resets things in sync with Wine however, and may lose and "fixes" ReactOS may have added over the years. But this is a good thing, since these fixes have been "lost" (they obviously never made it into Wine), and if regressions are now found due to this, actual upstream patches can be sent and picked up on the next sync. This avoids maintaining duplicate code, at the expenses of some potential short-term regressions in i18n.
Finally, note that much of /string seems to be taken from Wine's Unicode library (which a host "unicode" already exists in ReactOS' tools/. It may be better (for someone with more experience as to these wine-isms) to simply just pull-in whatever winelib files are not currently present in ReactOS, and have kernel32 and tools/unicode use winelib, instead of having 2 or 3 copies of the code.
svn path=/trunk/; revision=52754
2011-07-21 05:24:59 +00:00
|
|
|
|
2017-04-26 17:38:57 +00:00
|
|
|
/* See HACK in winnls/lang/xx-XX.rc files */
|
|
|
|
if (uID == 37)
|
|
|
|
uID = uID * 100;
|
[KERNEL32]: Winesync all there is to Winesync in ReactOS' kernel32. This mainly affects LZ*, Comm*, *ProfileString* (INI), and *Resource* APIs, however the changes in there are relatively minor. More substantial changes affect the locale/NLS/language functions, many which were bitrotting for 6+ years.
In theory, this code is "better" than before, and it is closer to Wine (which arguably has better compatibility). It also resets things in sync with Wine however, and may lose and "fixes" ReactOS may have added over the years. But this is a good thing, since these fixes have been "lost" (they obviously never made it into Wine), and if regressions are now found due to this, actual upstream patches can be sent and picked up on the next sync. This avoids maintaining duplicate code, at the expenses of some potential short-term regressions in i18n.
Finally, note that much of /string seems to be taken from Wine's Unicode library (which a host "unicode" already exists in ReactOS' tools/. It may be better (for someone with more experience as to these wine-isms) to simply just pull-in whatever winelib files are not currently present in ReactOS, and have kernel32 and tools/unicode use winelib, instead of having 2 or 3 copies of the code.
svn path=/trunk/; revision=52754
2011-07-21 05:24:59 +00:00
|
|
|
|
|
|
|
lcid = GetUserDefaultLCID();
|
|
|
|
lcid = ConvertDefaultLocale(lcid);
|
|
|
|
|
|
|
|
langId = LANGIDFROMLCID(lcid);
|
|
|
|
|
|
|
|
if (PRIMARYLANGID(langId) == LANG_NEUTRAL)
|
|
|
|
langId = MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US);
|
|
|
|
|
|
|
|
hrsrc = FindResourceExW(hCurrentModule,
|
|
|
|
(LPWSTR)RT_STRING,
|
2017-04-26 17:38:57 +00:00
|
|
|
MAKEINTRESOURCEW((uID >> 4) + 1),
|
[KERNEL32]: Winesync all there is to Winesync in ReactOS' kernel32. This mainly affects LZ*, Comm*, *ProfileString* (INI), and *Resource* APIs, however the changes in there are relatively minor. More substantial changes affect the locale/NLS/language functions, many which were bitrotting for 6+ years.
In theory, this code is "better" than before, and it is closer to Wine (which arguably has better compatibility). It also resets things in sync with Wine however, and may lose and "fixes" ReactOS may have added over the years. But this is a good thing, since these fixes have been "lost" (they obviously never made it into Wine), and if regressions are now found due to this, actual upstream patches can be sent and picked up on the next sync. This avoids maintaining duplicate code, at the expenses of some potential short-term regressions in i18n.
Finally, note that much of /string seems to be taken from Wine's Unicode library (which a host "unicode" already exists in ReactOS' tools/. It may be better (for someone with more experience as to these wine-isms) to simply just pull-in whatever winelib files are not currently present in ReactOS, and have kernel32 and tools/unicode use winelib, instead of having 2 or 3 copies of the code.
svn path=/trunk/; revision=52754
2011-07-21 05:24:59 +00:00
|
|
|
langId);
|
2014-10-31 16:32:23 +00:00
|
|
|
|
2017-04-26 17:38:57 +00:00
|
|
|
/* English fallback */
|
|
|
|
if (!hrsrc)
|
2014-10-31 16:32:23 +00:00
|
|
|
{
|
|
|
|
hrsrc = FindResourceExW(hCurrentModule,
|
2017-04-26 17:38:57 +00:00
|
|
|
(LPWSTR)RT_STRING,
|
|
|
|
MAKEINTRESOURCEW((uID >> 4) + 1),
|
|
|
|
MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US));
|
2014-10-31 16:32:23 +00:00
|
|
|
}
|
|
|
|
|
2017-04-26 17:38:57 +00:00
|
|
|
if (!hrsrc)
|
|
|
|
goto NotFound;
|
2014-10-31 18:13:36 +00:00
|
|
|
|
2017-04-26 17:38:57 +00:00
|
|
|
hmem = LoadResource(hCurrentModule, hrsrc);
|
|
|
|
if (!hmem)
|
|
|
|
goto NotFound;
|
[KERNEL32]: Winesync all there is to Winesync in ReactOS' kernel32. This mainly affects LZ*, Comm*, *ProfileString* (INI), and *Resource* APIs, however the changes in there are relatively minor. More substantial changes affect the locale/NLS/language functions, many which were bitrotting for 6+ years.
In theory, this code is "better" than before, and it is closer to Wine (which arguably has better compatibility). It also resets things in sync with Wine however, and may lose and "fixes" ReactOS may have added over the years. But this is a good thing, since these fixes have been "lost" (they obviously never made it into Wine), and if regressions are now found due to this, actual upstream patches can be sent and picked up on the next sync. This avoids maintaining duplicate code, at the expenses of some potential short-term regressions in i18n.
Finally, note that much of /string seems to be taken from Wine's Unicode library (which a host "unicode" already exists in ReactOS' tools/. It may be better (for someone with more experience as to these wine-isms) to simply just pull-in whatever winelib files are not currently present in ReactOS, and have kernel32 and tools/unicode use winelib, instead of having 2 or 3 copies of the code.
svn path=/trunk/; revision=52754
2011-07-21 05:24:59 +00:00
|
|
|
|
2017-04-26 17:38:57 +00:00
|
|
|
p = LockResource(hmem);
|
2014-10-31 18:13:36 +00:00
|
|
|
|
2017-04-26 17:38:57 +00:00
|
|
|
for (i = 0; i < (uID & 0x0F); i++)
|
|
|
|
p += *p + 1;
|
2014-10-31 18:13:36 +00:00
|
|
|
|
2017-04-26 17:38:57 +00:00
|
|
|
/* Needed for GetGeoInfo(): return the needed string size including the NULL terminator */
|
|
|
|
if (cchDest == 0)
|
|
|
|
return *p + 1;
|
|
|
|
/* Needed for GetGeoInfo(): bail out if the user buffer is not large enough */
|
|
|
|
if (*p + 1 > cchDest)
|
|
|
|
{
|
|
|
|
SetLastError(ERROR_INSUFFICIENT_BUFFER);
|
|
|
|
return 0;
|
|
|
|
}
|
[KERNEL32]: Winesync all there is to Winesync in ReactOS' kernel32. This mainly affects LZ*, Comm*, *ProfileString* (INI), and *Resource* APIs, however the changes in there are relatively minor. More substantial changes affect the locale/NLS/language functions, many which were bitrotting for 6+ years.
In theory, this code is "better" than before, and it is closer to Wine (which arguably has better compatibility). It also resets things in sync with Wine however, and may lose and "fixes" ReactOS may have added over the years. But this is a good thing, since these fixes have been "lost" (they obviously never made it into Wine), and if regressions are now found due to this, actual upstream patches can be sent and picked up on the next sync. This avoids maintaining duplicate code, at the expenses of some potential short-term regressions in i18n.
Finally, note that much of /string seems to be taken from Wine's Unicode library (which a host "unicode" already exists in ReactOS' tools/. It may be better (for someone with more experience as to these wine-isms) to simply just pull-in whatever winelib files are not currently present in ReactOS, and have kernel32 and tools/unicode use winelib, instead of having 2 or 3 copies of the code.
svn path=/trunk/; revision=52754
2011-07-21 05:24:59 +00:00
|
|
|
|
2017-04-26 17:38:57 +00:00
|
|
|
i = *p;
|
|
|
|
if (i > 0)
|
|
|
|
{
|
|
|
|
memcpy(lpszDest, p + 1, i * sizeof(WCHAR));
|
|
|
|
lpszDest[i] = L'\0';
|
|
|
|
return i;
|
|
|
|
}
|
|
|
|
#if 0
|
|
|
|
else
|
|
|
|
{
|
|
|
|
if (cchDest >= 1)
|
|
|
|
lpszDest[0] = L'\0';
|
|
|
|
/* Fall-back */
|
[KERNEL32]: Winesync all there is to Winesync in ReactOS' kernel32. This mainly affects LZ*, Comm*, *ProfileString* (INI), and *Resource* APIs, however the changes in there are relatively minor. More substantial changes affect the locale/NLS/language functions, many which were bitrotting for 6+ years.
In theory, this code is "better" than before, and it is closer to Wine (which arguably has better compatibility). It also resets things in sync with Wine however, and may lose and "fixes" ReactOS may have added over the years. But this is a good thing, since these fixes have been "lost" (they obviously never made it into Wine), and if regressions are now found due to this, actual upstream patches can be sent and picked up on the next sync. This avoids maintaining duplicate code, at the expenses of some potential short-term regressions in i18n.
Finally, note that much of /string seems to be taken from Wine's Unicode library (which a host "unicode" already exists in ReactOS' tools/. It may be better (for someone with more experience as to these wine-isms) to simply just pull-in whatever winelib files are not currently present in ReactOS, and have kernel32 and tools/unicode use winelib, instead of having 2 or 3 copies of the code.
svn path=/trunk/; revision=52754
2011-07-21 05:24:59 +00:00
|
|
|
}
|
2017-04-26 17:38:57 +00:00
|
|
|
#endif
|
[KERNEL32]: Winesync all there is to Winesync in ReactOS' kernel32. This mainly affects LZ*, Comm*, *ProfileString* (INI), and *Resource* APIs, however the changes in there are relatively minor. More substantial changes affect the locale/NLS/language functions, many which were bitrotting for 6+ years.
In theory, this code is "better" than before, and it is closer to Wine (which arguably has better compatibility). It also resets things in sync with Wine however, and may lose and "fixes" ReactOS may have added over the years. But this is a good thing, since these fixes have been "lost" (they obviously never made it into Wine), and if regressions are now found due to this, actual upstream patches can be sent and picked up on the next sync. This avoids maintaining duplicate code, at the expenses of some potential short-term regressions in i18n.
Finally, note that much of /string seems to be taken from Wine's Unicode library (which a host "unicode" already exists in ReactOS' tools/. It may be better (for someone with more experience as to these wine-isms) to simply just pull-in whatever winelib files are not currently present in ReactOS, and have kernel32 and tools/unicode use winelib, instead of having 2 or 3 copies of the code.
svn path=/trunk/; revision=52754
2011-07-21 05:24:59 +00:00
|
|
|
|
2017-04-26 17:38:57 +00:00
|
|
|
NotFound:
|
|
|
|
DPRINT1("Resource not found: uID = %lu\n", uID);
|
2014-10-31 18:13:36 +00:00
|
|
|
SetLastError(ERROR_INVALID_PARAMETER);
|
2017-04-26 17:38:57 +00:00
|
|
|
return 0;
|
[KERNEL32]: Winesync all there is to Winesync in ReactOS' kernel32. This mainly affects LZ*, Comm*, *ProfileString* (INI), and *Resource* APIs, however the changes in there are relatively minor. More substantial changes affect the locale/NLS/language functions, many which were bitrotting for 6+ years.
In theory, this code is "better" than before, and it is closer to Wine (which arguably has better compatibility). It also resets things in sync with Wine however, and may lose and "fixes" ReactOS may have added over the years. But this is a good thing, since these fixes have been "lost" (they obviously never made it into Wine), and if regressions are now found due to this, actual upstream patches can be sent and picked up on the next sync. This avoids maintaining duplicate code, at the expenses of some potential short-term regressions in i18n.
Finally, note that much of /string seems to be taken from Wine's Unicode library (which a host "unicode" already exists in ReactOS' tools/. It may be better (for someone with more experience as to these wine-isms) to simply just pull-in whatever winelib files are not currently present in ReactOS, and have kernel32 and tools/unicode use winelib, instead of having 2 or 3 copies of the code.
svn path=/trunk/; revision=52754
2011-07-21 05:24:59 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* @implemented
|
|
|
|
*/
|
|
|
|
BOOL
|
|
|
|
WINAPI
|
|
|
|
GetCPInfo(UINT CodePage,
|
|
|
|
LPCPINFO CodePageInfo)
|
|
|
|
{
|
|
|
|
PCODEPAGE_ENTRY CodePageEntry;
|
|
|
|
|
|
|
|
if (!CodePageInfo)
|
|
|
|
{
|
|
|
|
SetLastError(ERROR_INVALID_PARAMETER);
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
CodePageEntry = IntGetCodePageEntry(CodePage);
|
|
|
|
if (CodePageEntry == NULL)
|
|
|
|
{
|
|
|
|
switch(CodePage)
|
|
|
|
{
|
|
|
|
case CP_UTF7:
|
|
|
|
case CP_UTF8:
|
|
|
|
CodePageInfo->DefaultChar[0] = 0x3f;
|
|
|
|
CodePageInfo->DefaultChar[1] = 0;
|
|
|
|
CodePageInfo->LeadByte[0] = CodePageInfo->LeadByte[1] = 0;
|
|
|
|
CodePageInfo->MaxCharSize = (CodePage == CP_UTF7) ? 5 : 4;
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
|
2013-08-31 19:24:54 +00:00
|
|
|
DPRINT1("Invalid CP!: %lx\n", CodePage);
|
[KERNEL32]: Winesync all there is to Winesync in ReactOS' kernel32. This mainly affects LZ*, Comm*, *ProfileString* (INI), and *Resource* APIs, however the changes in there are relatively minor. More substantial changes affect the locale/NLS/language functions, many which were bitrotting for 6+ years.
In theory, this code is "better" than before, and it is closer to Wine (which arguably has better compatibility). It also resets things in sync with Wine however, and may lose and "fixes" ReactOS may have added over the years. But this is a good thing, since these fixes have been "lost" (they obviously never made it into Wine), and if regressions are now found due to this, actual upstream patches can be sent and picked up on the next sync. This avoids maintaining duplicate code, at the expenses of some potential short-term regressions in i18n.
Finally, note that much of /string seems to be taken from Wine's Unicode library (which a host "unicode" already exists in ReactOS' tools/. It may be better (for someone with more experience as to these wine-isms) to simply just pull-in whatever winelib files are not currently present in ReactOS, and have kernel32 and tools/unicode use winelib, instead of having 2 or 3 copies of the code.
svn path=/trunk/; revision=52754
2011-07-21 05:24:59 +00:00
|
|
|
SetLastError( ERROR_INVALID_PARAMETER );
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (CodePageEntry->CodePageTable.DefaultChar & 0xff00)
|
|
|
|
{
|
|
|
|
CodePageInfo->DefaultChar[0] = (CodePageEntry->CodePageTable.DefaultChar & 0xff00) >> 8;
|
|
|
|
CodePageInfo->DefaultChar[1] = CodePageEntry->CodePageTable.DefaultChar & 0x00ff;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
CodePageInfo->DefaultChar[0] = CodePageEntry->CodePageTable.DefaultChar & 0xff;
|
|
|
|
CodePageInfo->DefaultChar[1] = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
if ((CodePageInfo->MaxCharSize = CodePageEntry->CodePageTable.MaximumCharacterSize) == 2)
|
|
|
|
memcpy(CodePageInfo->LeadByte, CodePageEntry->CodePageTable.LeadByte, sizeof(CodePageInfo->LeadByte));
|
|
|
|
else
|
|
|
|
CodePageInfo->LeadByte[0] = CodePageInfo->LeadByte[1] = 0;
|
|
|
|
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* @implemented
|
|
|
|
*/
|
|
|
|
BOOL
|
|
|
|
WINAPI
|
|
|
|
GetCPInfoExW(UINT CodePage,
|
|
|
|
DWORD dwFlags,
|
|
|
|
LPCPINFOEXW lpCPInfoEx)
|
|
|
|
{
|
2017-04-26 17:38:57 +00:00
|
|
|
if (!GetCPInfo(CodePage, (LPCPINFO)lpCPInfoEx))
|
[KERNEL32]: Winesync all there is to Winesync in ReactOS' kernel32. This mainly affects LZ*, Comm*, *ProfileString* (INI), and *Resource* APIs, however the changes in there are relatively minor. More substantial changes affect the locale/NLS/language functions, many which were bitrotting for 6+ years.
In theory, this code is "better" than before, and it is closer to Wine (which arguably has better compatibility). It also resets things in sync with Wine however, and may lose and "fixes" ReactOS may have added over the years. But this is a good thing, since these fixes have been "lost" (they obviously never made it into Wine), and if regressions are now found due to this, actual upstream patches can be sent and picked up on the next sync. This avoids maintaining duplicate code, at the expenses of some potential short-term regressions in i18n.
Finally, note that much of /string seems to be taken from Wine's Unicode library (which a host "unicode" already exists in ReactOS' tools/. It may be better (for someone with more experience as to these wine-isms) to simply just pull-in whatever winelib files are not currently present in ReactOS, and have kernel32 and tools/unicode use winelib, instead of having 2 or 3 copies of the code.
svn path=/trunk/; revision=52754
2011-07-21 05:24:59 +00:00
|
|
|
return FALSE;
|
|
|
|
|
|
|
|
switch(CodePage)
|
|
|
|
{
|
|
|
|
case CP_UTF7:
|
|
|
|
{
|
|
|
|
lpCPInfoEx->CodePage = CP_UTF7;
|
|
|
|
lpCPInfoEx->UnicodeDefaultChar = 0x3f;
|
2017-04-26 17:38:57 +00:00
|
|
|
return GetLocalisedText(lpCPInfoEx->CodePage,
|
|
|
|
lpCPInfoEx->CodePageName,
|
|
|
|
ARRAYSIZE(lpCPInfoEx->CodePageName)) != 0;
|
[KERNEL32]: Winesync all there is to Winesync in ReactOS' kernel32. This mainly affects LZ*, Comm*, *ProfileString* (INI), and *Resource* APIs, however the changes in there are relatively minor. More substantial changes affect the locale/NLS/language functions, many which were bitrotting for 6+ years.
In theory, this code is "better" than before, and it is closer to Wine (which arguably has better compatibility). It also resets things in sync with Wine however, and may lose and "fixes" ReactOS may have added over the years. But this is a good thing, since these fixes have been "lost" (they obviously never made it into Wine), and if regressions are now found due to this, actual upstream patches can be sent and picked up on the next sync. This avoids maintaining duplicate code, at the expenses of some potential short-term regressions in i18n.
Finally, note that much of /string seems to be taken from Wine's Unicode library (which a host "unicode" already exists in ReactOS' tools/. It may be better (for someone with more experience as to these wine-isms) to simply just pull-in whatever winelib files are not currently present in ReactOS, and have kernel32 and tools/unicode use winelib, instead of having 2 or 3 copies of the code.
svn path=/trunk/; revision=52754
2011-07-21 05:24:59 +00:00
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case CP_UTF8:
|
|
|
|
{
|
|
|
|
lpCPInfoEx->CodePage = CP_UTF8;
|
|
|
|
lpCPInfoEx->UnicodeDefaultChar = 0x3f;
|
2017-04-26 17:38:57 +00:00
|
|
|
return GetLocalisedText(lpCPInfoEx->CodePage,
|
|
|
|
lpCPInfoEx->CodePageName,
|
|
|
|
ARRAYSIZE(lpCPInfoEx->CodePageName)) != 0;
|
[KERNEL32]: Winesync all there is to Winesync in ReactOS' kernel32. This mainly affects LZ*, Comm*, *ProfileString* (INI), and *Resource* APIs, however the changes in there are relatively minor. More substantial changes affect the locale/NLS/language functions, many which were bitrotting for 6+ years.
In theory, this code is "better" than before, and it is closer to Wine (which arguably has better compatibility). It also resets things in sync with Wine however, and may lose and "fixes" ReactOS may have added over the years. But this is a good thing, since these fixes have been "lost" (they obviously never made it into Wine), and if regressions are now found due to this, actual upstream patches can be sent and picked up on the next sync. This avoids maintaining duplicate code, at the expenses of some potential short-term regressions in i18n.
Finally, note that much of /string seems to be taken from Wine's Unicode library (which a host "unicode" already exists in ReactOS' tools/. It may be better (for someone with more experience as to these wine-isms) to simply just pull-in whatever winelib files are not currently present in ReactOS, and have kernel32 and tools/unicode use winelib, instead of having 2 or 3 copies of the code.
svn path=/trunk/; revision=52754
2011-07-21 05:24:59 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
default:
|
|
|
|
{
|
|
|
|
PCODEPAGE_ENTRY CodePageEntry;
|
|
|
|
|
|
|
|
CodePageEntry = IntGetCodePageEntry(CodePage);
|
|
|
|
if (CodePageEntry == NULL)
|
|
|
|
{
|
2017-04-26 17:38:57 +00:00
|
|
|
DPRINT1("Could not get CodePage Entry! CodePageEntry = NULL\n");
|
[KERNEL32]: Winesync all there is to Winesync in ReactOS' kernel32. This mainly affects LZ*, Comm*, *ProfileString* (INI), and *Resource* APIs, however the changes in there are relatively minor. More substantial changes affect the locale/NLS/language functions, many which were bitrotting for 6+ years.
In theory, this code is "better" than before, and it is closer to Wine (which arguably has better compatibility). It also resets things in sync with Wine however, and may lose and "fixes" ReactOS may have added over the years. But this is a good thing, since these fixes have been "lost" (they obviously never made it into Wine), and if regressions are now found due to this, actual upstream patches can be sent and picked up on the next sync. This avoids maintaining duplicate code, at the expenses of some potential short-term regressions in i18n.
Finally, note that much of /string seems to be taken from Wine's Unicode library (which a host "unicode" already exists in ReactOS' tools/. It may be better (for someone with more experience as to these wine-isms) to simply just pull-in whatever winelib files are not currently present in ReactOS, and have kernel32 and tools/unicode use winelib, instead of having 2 or 3 copies of the code.
svn path=/trunk/; revision=52754
2011-07-21 05:24:59 +00:00
|
|
|
SetLastError(ERROR_INVALID_PARAMETER);
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
lpCPInfoEx->CodePage = CodePageEntry->CodePageTable.CodePage;
|
|
|
|
lpCPInfoEx->UnicodeDefaultChar = CodePageEntry->CodePageTable.UniDefaultChar;
|
2017-04-26 17:38:57 +00:00
|
|
|
return GetLocalisedText(lpCPInfoEx->CodePage,
|
|
|
|
lpCPInfoEx->CodePageName,
|
|
|
|
ARRAYSIZE(lpCPInfoEx->CodePageName)) != 0;
|
[KERNEL32]: Winesync all there is to Winesync in ReactOS' kernel32. This mainly affects LZ*, Comm*, *ProfileString* (INI), and *Resource* APIs, however the changes in there are relatively minor. More substantial changes affect the locale/NLS/language functions, many which were bitrotting for 6+ years.
In theory, this code is "better" than before, and it is closer to Wine (which arguably has better compatibility). It also resets things in sync with Wine however, and may lose and "fixes" ReactOS may have added over the years. But this is a good thing, since these fixes have been "lost" (they obviously never made it into Wine), and if regressions are now found due to this, actual upstream patches can be sent and picked up on the next sync. This avoids maintaining duplicate code, at the expenses of some potential short-term regressions in i18n.
Finally, note that much of /string seems to be taken from Wine's Unicode library (which a host "unicode" already exists in ReactOS' tools/. It may be better (for someone with more experience as to these wine-isms) to simply just pull-in whatever winelib files are not currently present in ReactOS, and have kernel32 and tools/unicode use winelib, instead of having 2 or 3 copies of the code.
svn path=/trunk/; revision=52754
2011-07-21 05:24:59 +00:00
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
* @implemented
|
|
|
|
*/
|
|
|
|
BOOL
|
|
|
|
WINAPI
|
|
|
|
GetCPInfoExA(UINT CodePage,
|
|
|
|
DWORD dwFlags,
|
|
|
|
LPCPINFOEXA lpCPInfoEx)
|
|
|
|
{
|
|
|
|
CPINFOEXW CPInfo;
|
|
|
|
|
|
|
|
if (!GetCPInfoExW(CodePage, dwFlags, &CPInfo))
|
|
|
|
return FALSE;
|
|
|
|
|
|
|
|
/* the layout is the same except for CodePageName */
|
|
|
|
memcpy(lpCPInfoEx, &CPInfo, sizeof(CPINFOEXA));
|
|
|
|
|
|
|
|
WideCharToMultiByte(CP_ACP,
|
|
|
|
0,
|
|
|
|
CPInfo.CodePageName,
|
|
|
|
-1,
|
|
|
|
lpCPInfoEx->CodePageName,
|
|
|
|
sizeof(lpCPInfoEx->CodePageName),
|
|
|
|
NULL,
|
|
|
|
NULL);
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
|
2004-08-24 17:21:12 +00:00
|
|
|
/**
|
2005-08-29 21:06:07 +00:00
|
|
|
* @name WideCharToMultiByte
|
|
|
|
*
|
2004-08-24 17:21:12 +00:00
|
|
|
* Convert a wide-charater string to closest multi-byte equivalent.
|
2005-05-09 01:46:57 +00:00
|
|
|
*
|
2004-08-24 17:21:12 +00:00
|
|
|
* @param CodePage
|
|
|
|
* Code page to be used to perform the conversion. It can be also
|
|
|
|
* one of the special values (CP_ACP for ANSI code page, CP_MACCP
|
|
|
|
* for Macintosh code page, CP_OEMCP for OEM code page, CP_THREAD_ACP
|
|
|
|
* for thread active code page, CP_UTF7 or CP_UTF8).
|
|
|
|
* @param Flags
|
|
|
|
* Additional conversion flags (WC_NO_BEST_FIT_CHARS, WC_COMPOSITECHECK,
|
|
|
|
* WC_DISCARDNS, WC_SEPCHARS, WC_DEFAULTCHAR).
|
|
|
|
* @param WideCharString
|
2005-05-09 01:46:57 +00:00
|
|
|
* Points to the wide-character string to be converted.
|
2004-08-24 17:21:12 +00:00
|
|
|
* @param WideCharCount
|
|
|
|
* Size in WCHARs of WideCharStr, or 0 if the caller just wants to
|
|
|
|
* know how large WideCharString should be for a successful conversion.
|
|
|
|
* @param MultiByteString
|
2005-05-09 01:46:57 +00:00
|
|
|
* Points to the buffer to receive the translated string.
|
2004-08-24 17:21:12 +00:00
|
|
|
* @param MultiByteCount
|
2005-05-09 01:46:57 +00:00
|
|
|
* Specifies the size in bytes of the buffer pointed to by the
|
|
|
|
* MultiByteString parameter. If this value is zero, the function
|
|
|
|
* returns the number of bytes required for the buffer.
|
|
|
|
* @param DefaultChar
|
|
|
|
* Points to the character used if a wide character cannot be
|
|
|
|
* represented in the specified code page. If this parameter is
|
|
|
|
* NULL, a system default value is used.
|
|
|
|
* @param UsedDefaultChar
|
2004-08-24 17:21:12 +00:00
|
|
|
* Points to a flag that indicates whether a default character was
|
2005-05-09 01:46:57 +00:00
|
|
|
* used. This parameter can be NULL.
|
2004-08-24 17:21:12 +00:00
|
|
|
*
|
|
|
|
* @return Zero on error, otherwise the number of bytes written in the
|
|
|
|
* MultiByteString buffer. Or the number of bytes needed for
|
|
|
|
* the MultiByteString buffer if MultiByteCount is zero.
|
|
|
|
*
|
|
|
|
* @implemented
|
|
|
|
*/
|
2005-08-29 21:06:07 +00:00
|
|
|
|
2008-11-23 11:15:52 +00:00
|
|
|
INT
|
2008-11-30 11:42:05 +00:00
|
|
|
WINAPI
|
2008-11-23 11:15:52 +00:00
|
|
|
WideCharToMultiByte(UINT CodePage,
|
|
|
|
DWORD Flags,
|
|
|
|
LPCWSTR WideCharString,
|
|
|
|
INT WideCharCount,
|
|
|
|
LPSTR MultiByteString,
|
|
|
|
INT MultiByteCount,
|
|
|
|
LPCSTR DefaultChar,
|
|
|
|
LPBOOL UsedDefaultChar)
|
2004-08-24 17:21:12 +00:00
|
|
|
{
|
2008-11-23 11:15:52 +00:00
|
|
|
/* Check the parameters. */
|
|
|
|
if (WideCharString == NULL ||
|
2013-08-26 21:36:16 +00:00
|
|
|
WideCharCount == 0 ||
|
2008-11-23 11:15:52 +00:00
|
|
|
(MultiByteString == NULL && MultiByteCount > 0) ||
|
|
|
|
(PVOID)WideCharString == (PVOID)MultiByteString ||
|
|
|
|
MultiByteCount < 0)
|
|
|
|
{
|
|
|
|
SetLastError(ERROR_INVALID_PARAMETER);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Determine the input string length. */
|
|
|
|
if (WideCharCount < 0)
|
|
|
|
{
|
|
|
|
WideCharCount = lstrlenW(WideCharString) + 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
switch (CodePage)
|
|
|
|
{
|
|
|
|
case CP_UTF8:
|
2013-08-26 21:36:16 +00:00
|
|
|
if (DefaultChar != NULL || UsedDefaultChar != NULL)
|
|
|
|
{
|
|
|
|
SetLastError(ERROR_INVALID_PARAMETER);
|
|
|
|
return 0;
|
|
|
|
}
|
2008-11-23 11:15:52 +00:00
|
|
|
return IntWideCharToMultiByteUTF8(CodePage,
|
|
|
|
Flags,
|
|
|
|
WideCharString,
|
|
|
|
WideCharCount,
|
|
|
|
MultiByteString,
|
|
|
|
MultiByteCount,
|
|
|
|
DefaultChar,
|
|
|
|
UsedDefaultChar);
|
|
|
|
|
|
|
|
case CP_UTF7:
|
2010-05-18 06:34:48 +00:00
|
|
|
if (DefaultChar != NULL || UsedDefaultChar != NULL)
|
|
|
|
{
|
|
|
|
SetLastError(ERROR_INVALID_PARAMETER);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
if (Flags)
|
|
|
|
{
|
|
|
|
SetLastError(ERROR_INVALID_FLAGS);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
return WideCharToUtf7(WideCharString, WideCharCount,
|
|
|
|
MultiByteString, MultiByteCount);
|
2008-11-23 11:15:52 +00:00
|
|
|
|
|
|
|
case CP_SYMBOL:
|
|
|
|
if ((DefaultChar!=NULL) || (UsedDefaultChar!=NULL))
|
|
|
|
{
|
|
|
|
SetLastError(ERROR_INVALID_PARAMETER);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
return IntWideCharToMultiByteSYMBOL(Flags,
|
|
|
|
WideCharString,
|
|
|
|
WideCharCount,
|
|
|
|
MultiByteString,
|
|
|
|
MultiByteCount);
|
|
|
|
|
|
|
|
default:
|
|
|
|
return IntWideCharToMultiByteCP(CodePage,
|
|
|
|
Flags,
|
|
|
|
WideCharString,
|
|
|
|
WideCharCount,
|
|
|
|
MultiByteString,
|
|
|
|
MultiByteCount,
|
|
|
|
DefaultChar,
|
|
|
|
UsedDefaultChar);
|
2004-08-24 17:21:12 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2005-08-29 21:06:07 +00:00
|
|
|
/**
|
|
|
|
* @name GetACP
|
|
|
|
*
|
|
|
|
* Get active ANSI code page number.
|
|
|
|
*
|
2004-08-26 16:03:09 +00:00
|
|
|
* @implemented
|
|
|
|
*/
|
2005-08-29 21:06:07 +00:00
|
|
|
|
2008-11-23 11:15:52 +00:00
|
|
|
UINT
|
2008-11-30 11:42:05 +00:00
|
|
|
WINAPI
|
2005-08-29 21:06:07 +00:00
|
|
|
GetACP(VOID)
|
2004-08-26 16:03:09 +00:00
|
|
|
{
|
2008-11-23 11:15:52 +00:00
|
|
|
return AnsiCodePage.CodePageTable.CodePage;
|
2004-08-26 16:03:09 +00:00
|
|
|
}
|
|
|
|
|
2005-08-29 21:06:07 +00:00
|
|
|
/**
|
|
|
|
* @name GetOEMCP
|
|
|
|
*
|
|
|
|
* Get active OEM code page number.
|
2007-10-19 23:21:45 +00:00
|
|
|
*
|
2004-08-26 16:03:09 +00:00
|
|
|
* @implemented
|
|
|
|
*/
|
|
|
|
|
2008-11-23 11:15:52 +00:00
|
|
|
UINT
|
2008-11-30 11:42:05 +00:00
|
|
|
WINAPI
|
2005-08-29 21:06:07 +00:00
|
|
|
GetOEMCP(VOID)
|
2004-09-21 17:41:24 +00:00
|
|
|
{
|
2008-11-23 11:15:52 +00:00
|
|
|
return OemCodePage.CodePageTable.CodePage;
|
2004-09-21 17:41:24 +00:00
|
|
|
}
|
|
|
|
|
2005-08-29 21:06:07 +00:00
|
|
|
/**
|
|
|
|
* @name IsDBCSLeadByteEx
|
|
|
|
*
|
|
|
|
* Determine if passed byte is lead byte in specified code page.
|
|
|
|
*
|
2004-09-21 17:41:24 +00:00
|
|
|
* @implemented
|
|
|
|
*/
|
2005-08-29 21:06:07 +00:00
|
|
|
|
2008-11-23 11:15:52 +00:00
|
|
|
BOOL
|
2008-11-30 11:42:05 +00:00
|
|
|
WINAPI
|
2005-08-29 21:06:07 +00:00
|
|
|
IsDBCSLeadByteEx(UINT CodePage, BYTE TestByte)
|
2004-09-21 17:41:24 +00:00
|
|
|
{
|
2008-11-23 11:15:52 +00:00
|
|
|
PCODEPAGE_ENTRY CodePageEntry;
|
2004-09-21 17:41:24 +00:00
|
|
|
|
2008-11-23 11:15:52 +00:00
|
|
|
CodePageEntry = IntGetCodePageEntry(CodePage);
|
|
|
|
if (CodePageEntry != NULL)
|
|
|
|
return IntIsLeadByte(&CodePageEntry->CodePageTable, TestByte);
|
2004-09-21 17:41:24 +00:00
|
|
|
|
2008-11-23 11:15:52 +00:00
|
|
|
SetLastError(ERROR_INVALID_PARAMETER);
|
|
|
|
return FALSE;
|
2005-08-29 21:06:07 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @name IsDBCSLeadByteEx
|
|
|
|
*
|
|
|
|
* Determine if passed byte is lead byte in current ANSI code page.
|
|
|
|
*
|
2004-09-21 17:41:24 +00:00
|
|
|
* @implemented
|
|
|
|
*/
|
2005-05-09 01:46:57 +00:00
|
|
|
|
2008-11-23 11:15:52 +00:00
|
|
|
BOOL
|
2008-11-30 11:42:05 +00:00
|
|
|
WINAPI
|
2005-08-29 21:06:07 +00:00
|
|
|
IsDBCSLeadByte(BYTE TestByte)
|
|
|
|
{
|
2008-11-23 11:15:52 +00:00
|
|
|
return IntIsLeadByte(&AnsiCodePage.CodePageTable, TestByte);
|
2004-09-21 17:41:24 +00:00
|
|
|
}
|
|
|
|
|
2011-07-22 02:13:57 +00:00
|
|
|
/*
|
|
|
|
* @unimplemented
|
|
|
|
*/
|
|
|
|
NTSTATUS WINAPI CreateNlsSecurityDescriptor(PSECURITY_DESCRIPTOR SecurityDescriptor,ULONG Size,ULONG AccessMask)
|
|
|
|
{
|
|
|
|
STUB;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* @unimplemented
|
|
|
|
*/
|
|
|
|
BOOL WINAPI IsValidUILanguage(LANGID langid)
|
|
|
|
{
|
|
|
|
STUB;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* @unimplemented
|
|
|
|
*/
|
|
|
|
VOID WINAPI NlsConvertIntegerToString(ULONG Value,ULONG Base,ULONG strsize, LPWSTR str, ULONG strsize2)
|
|
|
|
{
|
|
|
|
STUB;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* @unimplemented
|
|
|
|
*/
|
|
|
|
UINT WINAPI SetCPGlobal(UINT CodePage)
|
|
|
|
{
|
|
|
|
STUB;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2011-07-24 23:42:09 +00:00
|
|
|
/*
|
|
|
|
* @unimplemented
|
|
|
|
*/
|
|
|
|
BOOL
|
|
|
|
WINAPI
|
|
|
|
ValidateLCType(int a1, unsigned int a2, int a3, int a4)
|
|
|
|
{
|
|
|
|
STUB;
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* @unimplemented
|
|
|
|
*/
|
2011-07-22 02:13:57 +00:00
|
|
|
BOOL
|
|
|
|
WINAPI
|
|
|
|
NlsResetProcessLocale(VOID)
|
|
|
|
{
|
|
|
|
STUB;
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
|
2011-07-24 23:42:09 +00:00
|
|
|
/*
|
|
|
|
* @unimplemented
|
|
|
|
*/
|
2011-07-22 02:13:57 +00:00
|
|
|
VOID
|
|
|
|
WINAPI
|
|
|
|
GetDefaultSortkeySize(LPVOID lpUnknown)
|
|
|
|
{
|
|
|
|
STUB;
|
|
|
|
lpUnknown = NULL;
|
|
|
|
}
|
|
|
|
|
2011-07-24 23:42:09 +00:00
|
|
|
/*
|
|
|
|
* @unimplemented
|
|
|
|
*/
|
2011-07-22 02:13:57 +00:00
|
|
|
VOID
|
|
|
|
WINAPI
|
|
|
|
GetLinguistLangSize(LPVOID lpUnknown)
|
|
|
|
{
|
|
|
|
STUB;
|
|
|
|
lpUnknown = NULL;
|
|
|
|
}
|
|
|
|
|
2011-07-24 23:42:09 +00:00
|
|
|
/*
|
|
|
|
* @unimplemented
|
|
|
|
*/
|
|
|
|
BOOL
|
|
|
|
WINAPI
|
|
|
|
ValidateLocale(IN ULONG LocaleId)
|
|
|
|
{
|
|
|
|
STUB;
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* @unimplemented
|
|
|
|
*/
|
2011-07-22 02:13:57 +00:00
|
|
|
ULONG
|
|
|
|
WINAPI
|
|
|
|
NlsGetCacheUpdateCount(VOID)
|
|
|
|
{
|
|
|
|
STUB;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2011-07-24 23:42:09 +00:00
|
|
|
/*
|
|
|
|
* @unimplemented
|
|
|
|
*/
|
|
|
|
BOOL
|
|
|
|
WINAPI
|
|
|
|
IsNLSDefinedString(IN NLS_FUNCTION Function,
|
|
|
|
IN DWORD dwFlags,
|
|
|
|
IN LPNLSVERSIONINFO lpVersionInformation,
|
|
|
|
IN LPCWSTR lpString,
|
|
|
|
IN INT cchStr)
|
|
|
|
{
|
|
|
|
STUB;
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* @unimplemented
|
|
|
|
*/
|
|
|
|
BOOL
|
|
|
|
WINAPI
|
|
|
|
GetNLSVersion(IN NLS_FUNCTION Function,
|
|
|
|
IN LCID Locale,
|
|
|
|
IN OUT LPNLSVERSIONINFO lpVersionInformation)
|
|
|
|
{
|
|
|
|
STUB;
|
|
|
|
return TRUE;
|
|
|
|
}
|
2013-09-14 10:20:11 +00:00
|
|
|
|
2004-08-24 17:21:12 +00:00
|
|
|
/* EOF */
|