mirror of
https://github.com/reactos/reactos.git
synced 2025-07-30 16:42:03 +00:00
- Implementation of GetCPFileNameFromRegistry, GetNlsSectionName and IsValidCodePage.
- Partial implementation of MultiByteToWideChar and WideCharToMultiByte. - Cleanup buffer allocation in some console functions. svn path=/trunk/; revision=10668
This commit is contained in:
parent
29fc781674
commit
5e458f6f4e
8 changed files with 842 additions and 353 deletions
|
@ -280,7 +280,7 @@ GetAtomNameW@12
|
||||||
GetBinaryType@8
|
GetBinaryType@8
|
||||||
GetBinaryTypeA@8
|
GetBinaryTypeA@8
|
||||||
GetBinaryTypeW@8
|
GetBinaryTypeW@8
|
||||||
;GetCPFileNameFromRegistry
|
GetCPFileNameFromRegistry@12
|
||||||
GetCPInfo@8
|
GetCPInfo@8
|
||||||
GetCPInfoExA@12
|
GetCPInfoExA@12
|
||||||
GetCPInfoExW@12
|
GetCPInfoExW@12
|
||||||
|
@ -409,7 +409,7 @@ GetNamedPipeHandleStateW@28
|
||||||
GetNamedPipeInfo@20
|
GetNamedPipeInfo@20
|
||||||
GetNativeSystemInfo@4
|
GetNativeSystemInfo@4
|
||||||
GetNextVDMCommand@4
|
GetNextVDMCommand@4
|
||||||
;GetNlsSectionName
|
GetNlsSectionName@24
|
||||||
GetNumaHighestNodeNumber@4
|
GetNumaHighestNodeNumber@4
|
||||||
GetNumaNodeProcessorMask@8
|
GetNumaNodeProcessorMask@8
|
||||||
;GetNumaProcessorMap
|
;GetNumaProcessorMap
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
; $Id: kernel32.edf,v 1.32 2004/05/13 20:42:28 navaraf Exp $
|
; $Id: kernel32.edf,v 1.33 2004/08/24 17:21:10 navaraf Exp $
|
||||||
;
|
;
|
||||||
; kernel32.edf
|
; kernel32.edf
|
||||||
;
|
;
|
||||||
|
@ -284,7 +284,7 @@ GetAtomNameW=GetAtomNameW@12
|
||||||
GetBinaryType=GetBinaryTypeA@8
|
GetBinaryType=GetBinaryTypeA@8
|
||||||
GetBinaryTypeA=GetBinaryTypeA@8
|
GetBinaryTypeA=GetBinaryTypeA@8
|
||||||
GetBinaryTypeW=GetBinaryTypeW@8
|
GetBinaryTypeW=GetBinaryTypeW@8
|
||||||
;GetCPFileNameFromRegistry
|
GetCPFileNameFromRegistry=GetCPFileNameFromRegistry@12
|
||||||
GetCPInfo=GetCPInfo@8
|
GetCPInfo=GetCPInfo@8
|
||||||
GetCPInfoExA=GetCPInfoExA@12
|
GetCPInfoExA=GetCPInfoExA@12
|
||||||
GetCPInfoExW=GetCPInfoExW@12
|
GetCPInfoExW=GetCPInfoExW@12
|
||||||
|
@ -414,7 +414,7 @@ GetNamedPipeHandleStateW=GetNamedPipeHandleStateW@28
|
||||||
GetNamedPipeInfo=GetNamedPipeInfo@20
|
GetNamedPipeInfo=GetNamedPipeInfo@20
|
||||||
GetNativeSystemInfo=GetNativeSystemInfo@4
|
GetNativeSystemInfo=GetNativeSystemInfo@4
|
||||||
GetNextVDMCommand=GetNextVDMCommand@4
|
GetNextVDMCommand=GetNextVDMCommand@4
|
||||||
;GetNlsSectionName
|
GetNlsSectionName=GetNlsSectionName@24
|
||||||
GetNumaHighestNodeNumber=GetNumaHighestNodeNumber@4
|
GetNumaHighestNodeNumber=GetNumaHighestNodeNumber@4
|
||||||
GetNumaNodeProcessorMask=GetNumaNodeProcessorMask@8
|
GetNumaNodeProcessorMask=GetNumaNodeProcessorMask@8
|
||||||
;GetNumaProcessorMap
|
;GetNumaProcessorMap
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
# $Id: makefile,v 1.83 2004/08/01 23:27:55 navaraf Exp $
|
# $Id: makefile,v 1.84 2004/08/24 17:21:10 navaraf Exp $
|
||||||
|
|
||||||
PATH_TO_TOP = ../..
|
PATH_TO_TOP = ../..
|
||||||
|
|
||||||
|
@ -33,8 +33,9 @@ MISC_OBJECTS = misc/error.o misc/atom.o misc/handle.o misc/env.o \
|
||||||
misc/console.o misc/time.o misc/timerqueue.o misc/toolhelp.o \
|
misc/console.o misc/time.o misc/timerqueue.o misc/toolhelp.o \
|
||||||
misc/stubs.o misc/lang.o misc/ldr.o misc/res.o \
|
misc/stubs.o misc/lang.o misc/ldr.o misc/res.o \
|
||||||
misc/sysinfo.o misc/profile.o \
|
misc/sysinfo.o misc/profile.o \
|
||||||
misc/mbchars.o misc/muldiv.o misc/computername.o \
|
misc/muldiv.o misc/nls.o misc/computername.o \
|
||||||
misc/perfcnt.o misc/lzexpand_main.o misc/lcformat.o
|
misc/perfcnt.o misc/lzexpand_main.o misc/lcformat.o
|
||||||
|
|
||||||
|
|
||||||
FILE_OBJECTS = file/file.o file/curdir.o file/lfile.o file/dir.o \
|
FILE_OBJECTS = file/file.o file/curdir.o file/lfile.o file/dir.o \
|
||||||
file/iocompl.o file/volume.o file/deviceio.o file/dosdev.o \
|
file/iocompl.o file/volume.o file/deviceio.o file/dosdev.o \
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
/* $Id: console.c,v 1.77 2004/08/22 20:52:28 navaraf Exp $
|
/* $Id: console.c,v 1.78 2004/08/24 17:21:11 navaraf Exp $
|
||||||
*
|
*
|
||||||
* COPYRIGHT: See COPYING in the top level directory
|
* COPYRIGHT: See COPYING in the top level directory
|
||||||
* PROJECT: ReactOS system libraries
|
* PROJECT: ReactOS system libraries
|
||||||
|
@ -1073,10 +1073,10 @@ WriteConsoleA(HANDLE hConsoleOutput,
|
||||||
USHORT Size;
|
USHORT Size;
|
||||||
ULONG MessageSize;
|
ULONG MessageSize;
|
||||||
|
|
||||||
Request = RtlAllocateHeap(GetProcessHeap(),
|
Request = RtlAllocateHeap(GetProcessHeap(), 0,
|
||||||
HEAP_ZERO_MEMORY,
|
sizeof(CSRSS_API_REQUEST) +
|
||||||
sizeof(CSRSS_API_REQUEST) +
|
min(nNumberOfCharsToWrite,
|
||||||
CSRSS_MAX_WRITE_CONSOLE_REQUEST);
|
CSRSS_MAX_WRITE_CONSOLE_REQUEST));
|
||||||
if (Request == NULL)
|
if (Request == NULL)
|
||||||
{
|
{
|
||||||
SetLastError(ERROR_OUTOFMEMORY);
|
SetLastError(ERROR_OUTOFMEMORY);
|
||||||
|
@ -1140,9 +1140,8 @@ BOOL STDCALL ReadConsoleA(HANDLE hConsoleInput,
|
||||||
NTSTATUS Status;
|
NTSTATUS Status;
|
||||||
ULONG CharsRead = 0;
|
ULONG CharsRead = 0;
|
||||||
|
|
||||||
Reply = RtlAllocateHeap(GetProcessHeap(),
|
Reply = RtlAllocateHeap(GetProcessHeap(), 0,
|
||||||
HEAP_ZERO_MEMORY,
|
sizeof(CSRSS_API_REPLY) + nNumberOfCharsToRead);
|
||||||
sizeof(CSRSS_API_REPLY) + nNumberOfCharsToRead);
|
|
||||||
if (Reply == NULL)
|
if (Reply == NULL)
|
||||||
{
|
{
|
||||||
SetLastError(ERROR_OUTOFMEMORY);
|
SetLastError(ERROR_OUTOFMEMORY);
|
||||||
|
@ -1946,9 +1945,9 @@ ReadConsoleOutputCharacterA(
|
||||||
NTSTATUS Status;
|
NTSTATUS Status;
|
||||||
DWORD Size;
|
DWORD Size;
|
||||||
|
|
||||||
Reply = RtlAllocateHeap(GetProcessHeap(),
|
Reply = RtlAllocateHeap(GetProcessHeap(), 0,
|
||||||
HEAP_ZERO_MEMORY,
|
sizeof(CSRSS_API_REPLY) +
|
||||||
sizeof(CSRSS_API_REPLY) + CSRSS_MAX_READ_CONSOLE_OUTPUT_CHAR);
|
min(nLength, CSRSS_MAX_READ_CONSOLE_OUTPUT_CHAR));
|
||||||
if (Reply == NULL)
|
if (Reply == NULL)
|
||||||
{
|
{
|
||||||
SetLastError(ERROR_OUTOFMEMORY);
|
SetLastError(ERROR_OUTOFMEMORY);
|
||||||
|
@ -2035,9 +2034,9 @@ ReadConsoleOutputAttribute(
|
||||||
NTSTATUS Status;
|
NTSTATUS Status;
|
||||||
DWORD Size, i;
|
DWORD Size, i;
|
||||||
|
|
||||||
Reply = RtlAllocateHeap(GetProcessHeap(),
|
Reply = RtlAllocateHeap(GetProcessHeap(), 0,
|
||||||
HEAP_ZERO_MEMORY,
|
sizeof(CSRSS_API_REPLY) +
|
||||||
sizeof(CSRSS_API_REPLY) + CSRSS_MAX_READ_CONSOLE_OUTPUT_ATTRIB);
|
min(nLength, CSRSS_MAX_READ_CONSOLE_OUTPUT_ATTRIB));
|
||||||
if (Reply == NULL)
|
if (Reply == NULL)
|
||||||
{
|
{
|
||||||
SetLastError(ERROR_OUTOFMEMORY);
|
SetLastError(ERROR_OUTOFMEMORY);
|
||||||
|
@ -2101,10 +2100,10 @@ WriteConsoleOutputCharacterA(HANDLE hConsoleOutput,
|
||||||
CSRSS_API_REPLY Reply;
|
CSRSS_API_REPLY Reply;
|
||||||
NTSTATUS Status;
|
NTSTATUS Status;
|
||||||
WORD Size;
|
WORD Size;
|
||||||
|
|
||||||
Request = RtlAllocateHeap(GetProcessHeap(),
|
Request = RtlAllocateHeap(GetProcessHeap(), 0,
|
||||||
HEAP_ZERO_MEMORY,
|
sizeof(CSRSS_API_REQUEST) +
|
||||||
sizeof(CSRSS_API_REQUEST) + CSRSS_MAX_WRITE_CONSOLE_OUTPUT_CHAR);
|
min(nLength, CSRSS_MAX_WRITE_CONSOLE_OUTPUT_CHAR));
|
||||||
if( !Request )
|
if( !Request )
|
||||||
{
|
{
|
||||||
SetLastError( ERROR_OUTOFMEMORY );
|
SetLastError( ERROR_OUTOFMEMORY );
|
||||||
|
@ -2156,9 +2155,9 @@ WriteConsoleOutputCharacterW(HANDLE hConsoleOutput,
|
||||||
NTSTATUS Status;
|
NTSTATUS Status;
|
||||||
WORD Size;
|
WORD Size;
|
||||||
|
|
||||||
Request = RtlAllocateHeap(GetProcessHeap(),
|
Request = RtlAllocateHeap(GetProcessHeap(), 0,
|
||||||
HEAP_ZERO_MEMORY,
|
sizeof(CSRSS_API_REQUEST) +
|
||||||
sizeof(CSRSS_API_REQUEST) + CSRSS_MAX_WRITE_CONSOLE_OUTPUT_CHAR);
|
min(nLength, CSRSS_MAX_WRITE_CONSOLE_OUTPUT_CHAR));
|
||||||
if( !Request )
|
if( !Request )
|
||||||
{
|
{
|
||||||
SetLastError( ERROR_OUTOFMEMORY );
|
SetLastError( ERROR_OUTOFMEMORY );
|
||||||
|
@ -2223,9 +2222,9 @@ WriteConsoleOutputAttribute(
|
||||||
WORD Size;
|
WORD Size;
|
||||||
int c;
|
int c;
|
||||||
|
|
||||||
Request = RtlAllocateHeap(GetProcessHeap(),
|
Request = RtlAllocateHeap(GetProcessHeap(), 0,
|
||||||
HEAP_ZERO_MEMORY,
|
sizeof(CSRSS_API_REQUEST) +
|
||||||
sizeof(CSRSS_API_REQUEST) + CSRSS_MAX_WRITE_CONSOLE_OUTPUT_ATTRIB);
|
min(nLength, CSRSS_MAX_WRITE_CONSOLE_OUTPUT_ATTRIB));
|
||||||
if( !Request )
|
if( !Request )
|
||||||
{
|
{
|
||||||
SetLastError( ERROR_OUTOFMEMORY );
|
SetLastError( ERROR_OUTOFMEMORY );
|
||||||
|
@ -3136,7 +3135,7 @@ GetConsoleCP( VOID )
|
||||||
/*--------------------------------------------------------------
|
/*--------------------------------------------------------------
|
||||||
* SetConsoleCP
|
* SetConsoleCP
|
||||||
*
|
*
|
||||||
* @unimplemented
|
* @implemented
|
||||||
*/
|
*/
|
||||||
BOOL
|
BOOL
|
||||||
WINAPI
|
WINAPI
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
/* $Id: dllmain.c,v 1.35 2004/06/26 20:07:40 gdalsnes Exp $
|
/* $Id: dllmain.c,v 1.36 2004/08/24 17:21:11 navaraf Exp $
|
||||||
*
|
*
|
||||||
* COPYRIGHT: See COPYING in the top level directory
|
* COPYRIGHT: See COPYING in the top level directory
|
||||||
* PROJECT: ReactOS system libraries
|
* PROJECT: ReactOS system libraries
|
||||||
|
@ -40,6 +40,9 @@ CRITICAL_SECTION ConsoleLock;
|
||||||
extern BOOL WINAPI DefaultConsoleCtrlHandler(DWORD Event);
|
extern BOOL WINAPI DefaultConsoleCtrlHandler(DWORD Event);
|
||||||
extern BOOL FASTCALL PROFILE_Init();
|
extern BOOL FASTCALL PROFILE_Init();
|
||||||
|
|
||||||
|
extern BOOL FASTCALL NlsInit();
|
||||||
|
extern VOID FASTCALL NlsUninit();
|
||||||
|
|
||||||
/* FUNCTIONS *****************************************************************/
|
/* FUNCTIONS *****************************************************************/
|
||||||
|
|
||||||
static NTSTATUS
|
static NTSTATUS
|
||||||
|
@ -153,6 +156,12 @@ DllMain(HANDLE hDll,
|
||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Initialize the National Language Support routines */
|
||||||
|
if (! NlsInit())
|
||||||
|
{
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
/* Initialize console ctrl handler */
|
/* Initialize console ctrl handler */
|
||||||
RtlInitializeCriticalSection(&ConsoleLock);
|
RtlInitializeCriticalSection(&ConsoleLock);
|
||||||
SetConsoleCtrlHandler(DefaultConsoleCtrlHandler, TRUE);
|
SetConsoleCtrlHandler(DefaultConsoleCtrlHandler, TRUE);
|
||||||
|
@ -168,6 +177,8 @@ DllMain(HANDLE hDll,
|
||||||
{
|
{
|
||||||
/* Insert more dll detach stuff here! */
|
/* Insert more dll detach stuff here! */
|
||||||
|
|
||||||
|
NlsUninit();
|
||||||
|
|
||||||
/* Delete DLL critical section */
|
/* Delete DLL critical section */
|
||||||
RtlDeleteCriticalSection (&ConsoleLock);
|
RtlDeleteCriticalSection (&ConsoleLock);
|
||||||
RtlDeleteCriticalSection (&DllLock);
|
RtlDeleteCriticalSection (&DllLock);
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
/* $Id: lang.c,v 1.20 2004/06/26 20:10:50 gdalsnes Exp $
|
/* $Id: lang.c,v 1.21 2004/08/24 17:21:11 navaraf Exp $
|
||||||
*
|
*
|
||||||
* COPYRIGHT: See COPYING in the top level directory
|
* COPYRIGHT: See COPYING in the top level directory
|
||||||
* PROJECT : ReactOS user mode libraries
|
* PROJECT : ReactOS user mode libraries
|
||||||
|
@ -907,20 +907,6 @@ GetUserGeoID(
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/*
|
|
||||||
* @unimplemented
|
|
||||||
*/
|
|
||||||
BOOL
|
|
||||||
STDCALL
|
|
||||||
IsValidCodePage (
|
|
||||||
UINT CodePage
|
|
||||||
)
|
|
||||||
{
|
|
||||||
SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
|
|
||||||
return FALSE;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* @unimplemented
|
* @unimplemented
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -1,305 +0,0 @@
|
||||||
/* $Id: mbchars.c,v 1.5 2004/04/04 17:59:23 gvg Exp $
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
#include <windows.h>
|
|
||||||
|
|
||||||
|
|
||||||
/**********************************************************************
|
|
||||||
* NAME PRIVATE
|
|
||||||
* IsInstalledCP@4
|
|
||||||
*
|
|
||||||
* RETURN VALUE
|
|
||||||
* TRUE if CodePage is installed in the system.
|
|
||||||
*/
|
|
||||||
static
|
|
||||||
BOOL
|
|
||||||
STDCALL
|
|
||||||
IsInstalledCP(UINT CodePage)
|
|
||||||
{
|
|
||||||
/* FIXME */
|
|
||||||
return TRUE;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**********************************************************************
|
|
||||||
* NAME EXPORTED
|
|
||||||
* MultiByteToWideChar@24
|
|
||||||
*
|
|
||||||
* ARGUMENTS
|
|
||||||
* CodePage
|
|
||||||
* CP_ACP ANSI code page
|
|
||||||
* CP_MACCP Macintosh code page
|
|
||||||
* CP_OEMCP OEM code page
|
|
||||||
* (UINT) Any installed code page
|
|
||||||
*
|
|
||||||
* dwFlags
|
|
||||||
* MB_PRECOMPOSED
|
|
||||||
* MB_COMPOSITE
|
|
||||||
* MB_ERR_INVALID_CHARS
|
|
||||||
* MB_USEGLYPHCHARS
|
|
||||||
*
|
|
||||||
* lpMultiByteStr
|
|
||||||
* Input buffer;
|
|
||||||
*
|
|
||||||
* cchMultiByte
|
|
||||||
* Size of MultiByteStr, or -1 if MultiByteStr is
|
|
||||||
* NULL terminated;
|
|
||||||
*
|
|
||||||
* lpWideCharStr
|
|
||||||
* Output buffer;
|
|
||||||
*
|
|
||||||
* cchWideChar
|
|
||||||
* Size (in WCHAR unit) of WideCharStr, or 0
|
|
||||||
* if the caller just wants to know how large
|
|
||||||
* WideCharStr should be for a successful
|
|
||||||
* conversion.
|
|
||||||
*
|
|
||||||
* RETURN VALUE
|
|
||||||
* 0 on error; otherwise the number of WCHAR written
|
|
||||||
* in the WideCharStr buffer.
|
|
||||||
*
|
|
||||||
* NOTE
|
|
||||||
* A raw converter for now. It assumes lpMultiByteStr is
|
|
||||||
* NEVER multi-byte (that is each input character is
|
|
||||||
* 8-bit ASCII) and is ALWAYS NULL terminated.
|
|
||||||
* FIXME-FIXME-FIXME-FIXME
|
|
||||||
*
|
|
||||||
* @implemented
|
|
||||||
*/
|
|
||||||
INT
|
|
||||||
STDCALL
|
|
||||||
MultiByteToWideChar(
|
|
||||||
UINT CodePage,
|
|
||||||
DWORD dwFlags,
|
|
||||||
LPCSTR lpMultiByteStr,
|
|
||||||
int cchMultiByte,
|
|
||||||
LPWSTR lpWideCharStr,
|
|
||||||
int cchWideChar)
|
|
||||||
{
|
|
||||||
int InStringLength = 0;
|
|
||||||
PCHAR r;
|
|
||||||
PWCHAR w;
|
|
||||||
int cchConverted;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Check the parameters.
|
|
||||||
*/
|
|
||||||
if (/* --- CODE PAGE --- */
|
|
||||||
( (CP_ACP != CodePage)
|
|
||||||
&& (CP_MACCP != CodePage)
|
|
||||||
&& (CP_OEMCP != CodePage)
|
|
||||||
&& (FALSE == IsInstalledCP(CodePage)) )
|
|
||||||
/* --- FLAGS --- */
|
|
||||||
|| (dwFlags & ~(MB_PRECOMPOSED | MB_COMPOSITE |
|
|
||||||
MB_ERR_INVALID_CHARS | MB_USEGLYPHCHARS))
|
|
||||||
/* --- INPUT BUFFER --- */
|
|
||||||
|| (NULL == lpMultiByteStr) )
|
|
||||||
{
|
|
||||||
SetLastError (ERROR_INVALID_PARAMETER);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
/*
|
|
||||||
* Compute the input buffer length.
|
|
||||||
*/
|
|
||||||
//if (-1 == cchMultiByte)
|
|
||||||
if (cchMultiByte < 0)
|
|
||||||
{
|
|
||||||
InStringLength = lstrlenA(lpMultiByteStr) + 1;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
InStringLength = cchMultiByte;
|
|
||||||
}
|
|
||||||
/*
|
|
||||||
* Does caller query for output
|
|
||||||
* buffer size?
|
|
||||||
*/
|
|
||||||
if (0 == cchWideChar)
|
|
||||||
{
|
|
||||||
//SetLastError(ERROR_SUCCESS); /* according to wine tests this shouldn't be touched on success.
|
|
||||||
return InStringLength;
|
|
||||||
}
|
|
||||||
/*
|
|
||||||
* Is space provided for the translated
|
|
||||||
* string enough?
|
|
||||||
*/
|
|
||||||
if (cchWideChar < InStringLength)
|
|
||||||
{
|
|
||||||
SetLastError(ERROR_INSUFFICIENT_BUFFER);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
/*
|
|
||||||
* Raw 8- to 16-bit conversion.
|
|
||||||
*/
|
|
||||||
for (cchConverted = 0,
|
|
||||||
r = (PCHAR)lpMultiByteStr,
|
|
||||||
w = (PWCHAR)lpWideCharStr;
|
|
||||||
|
|
||||||
cchConverted < InStringLength;
|
|
||||||
|
|
||||||
r++,
|
|
||||||
w++,
|
|
||||||
cchConverted++)
|
|
||||||
{
|
|
||||||
*w = (WCHAR)(unsigned char) *r;
|
|
||||||
}
|
|
||||||
/*
|
|
||||||
* Return how many characters we
|
|
||||||
* wrote in the output buffer.
|
|
||||||
*/
|
|
||||||
//SetLastError(ERROR_SUCCESS); /* according to wine tests this shouldn't be touched on success.
|
|
||||||
return cchConverted;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**********************************************************************
|
|
||||||
* NAME EXPORTED
|
|
||||||
* WideCharToMultiByte@32
|
|
||||||
*
|
|
||||||
* Not yet implemented complete (without NLS so far)
|
|
||||||
*
|
|
||||||
* ARGUMENTS
|
|
||||||
* CodePage
|
|
||||||
* CP_ACP ANSI code page
|
|
||||||
* CP_MACCP Macintosh code page
|
|
||||||
* CP_OEMCP OEM code page
|
|
||||||
* CP_SYMBOL Symbol code page (42)
|
|
||||||
* CP_THREAD_ACP Current thread's ANSI code page
|
|
||||||
* CP_UTF7 Translate using UTF-7
|
|
||||||
* CP_UTF8 Translate using UTF-8
|
|
||||||
* (UINT) Any installed code page
|
|
||||||
*
|
|
||||||
* dwFlags
|
|
||||||
* WC_NO_BEST_FIT_CHARS
|
|
||||||
* WC_COMPOSITECHECK Convert composite characters to precomposed characters.
|
|
||||||
* WC_DISCARDNS Discard nonspacing characters during conversion.
|
|
||||||
* WC_SEPCHARS Generate separate characters during conversion. This is the default conversion behavior.
|
|
||||||
* WC_DEFAULTCHAR Replace exceptions with the default character during conversion.
|
|
||||||
*
|
|
||||||
* lpWideCharStr
|
|
||||||
* Points to the wide-character string to be converted.
|
|
||||||
*
|
|
||||||
* cchWideChar
|
|
||||||
* Size (in WCHAR unit) of WideCharStr, or 0
|
|
||||||
* if the caller just wants to know how large
|
|
||||||
* WideCharStr should be for a successful
|
|
||||||
* conversion.
|
|
||||||
* lpMultiByteStr
|
|
||||||
* Points to the buffer to receive the translated string.
|
|
||||||
* cchMultiByte
|
|
||||||
* Specifies the size in bytes of the buffer pointed to by the
|
|
||||||
* lpMultiByteStr parameter. If this value is zero, the function
|
|
||||||
* returns the number of bytes required for the buffer.
|
|
||||||
* lpDefaultChar
|
|
||||||
* 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.
|
|
||||||
FIXME: ignored
|
|
||||||
* lpUsedDefaultChar
|
|
||||||
* Points to a flag that indicates whether a default character was used.
|
|
||||||
* This parameter may be NULL.
|
|
||||||
FIXME: allways set to FALSE.
|
|
||||||
*
|
|
||||||
*
|
|
||||||
*
|
|
||||||
* RETURN VALUE
|
|
||||||
* 0 on error; otherwise the number of bytes written
|
|
||||||
* in the lpMultiByteStr buffer. Or the number of
|
|
||||||
* bytes needed for the lpMultiByteStr buffer if cchMultiByte is zero.
|
|
||||||
*
|
|
||||||
* NOTE
|
|
||||||
* A raw converter for now. It just cuts off the upper 9 Bit.
|
|
||||||
* So the MBCS-string does not contain any LeadCharacters
|
|
||||||
* FIXME - FIXME - FIXME - FIXME
|
|
||||||
*
|
|
||||||
* @implemented
|
|
||||||
*/
|
|
||||||
int
|
|
||||||
STDCALL
|
|
||||||
WideCharToMultiByte(
|
|
||||||
UINT CodePage,
|
|
||||||
DWORD dwFlags,
|
|
||||||
LPCWSTR lpWideCharStr,
|
|
||||||
int cchWideChar,
|
|
||||||
LPSTR lpMultiByteStr,
|
|
||||||
int cchMultiByte,
|
|
||||||
LPCSTR lpDefaultChar,
|
|
||||||
LPBOOL lpUsedDefaultChar
|
|
||||||
)
|
|
||||||
{
|
|
||||||
int wi, di; // wide counter, dbcs byte count
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Check the parameters.
|
|
||||||
*/
|
|
||||||
if ( /* --- CODE PAGE --- */
|
|
||||||
( (CP_ACP != CodePage)
|
|
||||||
&& (CP_MACCP != CodePage)
|
|
||||||
&& (CP_OEMCP != CodePage)
|
|
||||||
&& (CP_SYMBOL != CodePage)
|
|
||||||
&& (CP_THREAD_ACP != CodePage)
|
|
||||||
&& (CP_UTF7 != CodePage)
|
|
||||||
&& (CP_UTF8 != CodePage)
|
|
||||||
&& (FALSE == IsInstalledCP (CodePage))
|
|
||||||
)
|
|
||||||
/* --- FLAGS --- */
|
|
||||||
|| (dwFlags & ~(/*WC_NO_BEST_FIT_CHARS
|
|
||||||
|*/ WC_COMPOSITECHECK
|
|
||||||
| WC_DISCARDNS
|
|
||||||
| WC_SEPCHARS
|
|
||||||
| WC_DEFAULTCHAR
|
|
||||||
)
|
|
||||||
)
|
|
||||||
/* --- INPUT BUFFER --- */
|
|
||||||
|| (NULL == lpWideCharStr)
|
|
||||||
)
|
|
||||||
{
|
|
||||||
SetLastError(ERROR_INVALID_PARAMETER);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
// for now, make no difference but only convert cut the characters to 7Bit
|
|
||||||
//if (cchWideChar == -1) // assume its a 0-terminated str
|
|
||||||
if (cchWideChar < 0) // assume its a 0-terminated str
|
|
||||||
{ // and determine its length
|
|
||||||
// for (cchWideChar=0; lpWideCharStr[cchWideChar]!=0; cchWideChar++)
|
|
||||||
// cchWideChar++;
|
|
||||||
for (cchWideChar = 0; lpWideCharStr[cchWideChar] != 0; cchWideChar++) {
|
|
||||||
}
|
|
||||||
cchWideChar++; // length includes the null terminator
|
|
||||||
}
|
|
||||||
|
|
||||||
// user wants to determine needed space
|
|
||||||
if (cchMultiByte == 0)
|
|
||||||
{
|
|
||||||
//SetLastError(ERROR_SUCCESS); /* according to wine tests this shouldn't be touched on success.
|
|
||||||
return cchWideChar; // FIXME: determine correct.
|
|
||||||
}
|
|
||||||
// the lpWideCharStr is cchWideChar characters long.
|
|
||||||
for (wi=0, di=0; wi<cchWideChar && di<cchMultiByte; ++wi, ++di)
|
|
||||||
{
|
|
||||||
// Flag and a not displayable char FIXME
|
|
||||||
/*if( (dwFlags&WC_NO_BEST_FIT_CHARS) && (lpWideCharStr[wi] >127) )
|
|
||||||
{
|
|
||||||
lpMultiByteStr[di]=
|
|
||||||
*lpUsedDefaultChar = TRUE;
|
|
||||||
|
|
||||||
}*/
|
|
||||||
// FIXME
|
|
||||||
// just cut off the upper 9 Bit, since vals>=128 mean LeadByte.
|
|
||||||
lpMultiByteStr[di] = lpWideCharStr[wi] & 0x007F;
|
|
||||||
}
|
|
||||||
// has MultiByte exceeded but Wide is still in the string?
|
|
||||||
if (wi < cchWideChar && di >= cchMultiByte)
|
|
||||||
{
|
|
||||||
SetLastError(ERROR_INSUFFICIENT_BUFFER);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
// else return # of bytes wirtten to MBCSbuffer (di)
|
|
||||||
//SetLastError(ERROR_SUCCESS); /* according to wine tests this shouldn't be touched on success.
|
|
||||||
// FIXME: move that elsewhere
|
|
||||||
if (lpUsedDefaultChar != NULL) *lpUsedDefaultChar = FALSE;
|
|
||||||
return di;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* EOF */
|
|
797
reactos/lib/kernel32/misc/nls.c
Executable file
797
reactos/lib/kernel32/misc/nls.c
Executable file
|
@ -0,0 +1,797 @@
|
||||||
|
/*
|
||||||
|
* ReactOS Kernel
|
||||||
|
* Copyright (C) 2004 ReactOS Team
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation; either version 2 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||||
|
*/
|
||||||
|
/**
|
||||||
|
* @brief National Language Support.
|
||||||
|
* @author Filip Navara
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* INCLUDES *******************************************************************/
|
||||||
|
|
||||||
|
#include <k32.h>
|
||||||
|
#define NDEBUG
|
||||||
|
#include "../include/debug.h"
|
||||||
|
|
||||||
|
/* GLOBAL VARIABLES ***********************************************************/
|
||||||
|
|
||||||
|
typedef struct _CODEPAGE_ENTRY
|
||||||
|
{
|
||||||
|
LIST_ENTRY Entry;
|
||||||
|
UINT CodePage;
|
||||||
|
HANDLE SectionHandle;
|
||||||
|
PBYTE SectionMapping;
|
||||||
|
CPTABLEINFO CodePageTable;
|
||||||
|
} CODEPAGE_ENTRY, *PCODEPAGE_ENTRY;
|
||||||
|
|
||||||
|
/* Sequence length based on the first character. */
|
||||||
|
static const char UTF8Length[128] =
|
||||||
|
{
|
||||||
|
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x80 - 0x8F */
|
||||||
|
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x90 - 0x9F */
|
||||||
|
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0xA0 - 0xAF */
|
||||||
|
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0xB0 - 0xBF */
|
||||||
|
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 0xC0 - 0xCF */
|
||||||
|
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 0xD0 - 0xDF */
|
||||||
|
2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, /* 0xE0 - 0xEF */
|
||||||
|
3, 3, 3, 3, 3, 3, 3, 3, 4, 4, 4, 4, 5, 5, 0, 0 /* 0xF0 - 0xFF */
|
||||||
|
};
|
||||||
|
|
||||||
|
/* First byte mask depending on UTF-8 sequence length. */
|
||||||
|
static const unsigned char UTF8Mask[6] = {0x7f, 0x1f, 0x0f, 0x07, 0x03, 0x01};
|
||||||
|
|
||||||
|
/* FIXME: Change to HASH table or linear array. */
|
||||||
|
static LIST_ENTRY CodePageListHead;
|
||||||
|
static CODEPAGE_ENTRY AnsiCodePage;
|
||||||
|
static CODEPAGE_ENTRY OemCodePage;
|
||||||
|
static CRITICAL_SECTION CodePageListLock;
|
||||||
|
|
||||||
|
/* FORWARD DECLARATIONS *******************************************************/
|
||||||
|
|
||||||
|
BOOL STDCALL
|
||||||
|
GetNlsSectionName(UINT CodePage, UINT Base, ULONG Unknown,
|
||||||
|
LPSTR BaseName, LPSTR Result, ULONG ResultSize);
|
||||||
|
|
||||||
|
BOOL STDCALL
|
||||||
|
GetCPFileNameFromRegistry(UINT CodePage, LPWSTR FileName, ULONG FileNameSize);
|
||||||
|
|
||||||
|
/* PRIVATE FUNCTIONS **********************************************************/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Internal NLS related stuff initialization.
|
||||||
|
*/
|
||||||
|
BOOL FASTCALL
|
||||||
|
NlsInit()
|
||||||
|
{
|
||||||
|
UNICODE_STRING DirName;
|
||||||
|
OBJECT_ATTRIBUTES ObjectAttributes;
|
||||||
|
HANDLE Handle;
|
||||||
|
|
||||||
|
InitializeListHead(&CodePageListHead);
|
||||||
|
RtlInitializeCriticalSection(&CodePageListLock);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* FIXME: Eventually this should be done only for the NLS Server
|
||||||
|
* process, but since we don't have anything like that (yet?) we
|
||||||
|
* always try to create the "\Nls" directory here.
|
||||||
|
*/
|
||||||
|
RtlInitUnicodeString(&DirName, L"\\Nls");
|
||||||
|
InitializeObjectAttributes(&ObjectAttributes, &DirName,
|
||||||
|
OBJ_CASE_INSENSITIVE | OBJ_PERMANENT,
|
||||||
|
NULL, NULL);
|
||||||
|
NtCreateDirectoryObject(&Handle, DIRECTORY_ALL_ACCESS, &ObjectAttributes);
|
||||||
|
NtClose(Handle);
|
||||||
|
|
||||||
|
/* Setup ANSI code page. */
|
||||||
|
AnsiCodePage.CodePage = CP_ACP;
|
||||||
|
AnsiCodePage.SectionHandle = NULL;
|
||||||
|
AnsiCodePage.SectionMapping = NtCurrentTeb()->Peb->AnsiCodePageData;
|
||||||
|
RtlInitCodePageTable((PUSHORT)AnsiCodePage.SectionMapping,
|
||||||
|
&AnsiCodePage.CodePageTable);
|
||||||
|
InsertTailList(&CodePageListHead, &AnsiCodePage.Entry);
|
||||||
|
|
||||||
|
/* Setup OEM code page. */
|
||||||
|
OemCodePage.CodePage = CP_OEMCP;
|
||||||
|
OemCodePage.SectionHandle = NULL;
|
||||||
|
OemCodePage.SectionMapping = NtCurrentTeb()->Peb->OemCodePageData;
|
||||||
|
RtlInitCodePageTable((PUSHORT)OemCodePage.SectionMapping,
|
||||||
|
&OemCodePage.CodePageTable);
|
||||||
|
InsertTailList(&CodePageListHead, &OemCodePage.Entry);
|
||||||
|
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Internal NLS related stuff uninitialization.
|
||||||
|
*/
|
||||||
|
VOID FASTCALL
|
||||||
|
NlsUninit()
|
||||||
|
{
|
||||||
|
PCODEPAGE_ENTRY Current;
|
||||||
|
|
||||||
|
/* Delete the code page list. */
|
||||||
|
while (!IsListEmpty(&CodePageListHead))
|
||||||
|
{
|
||||||
|
Current = CONTAINING_RECORD(CodePageListHead.Flink, CODEPAGE_ENTRY, Entry);
|
||||||
|
if (Current->SectionHandle != NULL)
|
||||||
|
{
|
||||||
|
UnmapViewOfFile(Current->SectionMapping);
|
||||||
|
NtClose(Current->SectionHandle);
|
||||||
|
}
|
||||||
|
RemoveHeadList(&CodePageListHead);
|
||||||
|
}
|
||||||
|
RtlDeleteCriticalSection(&CodePageListLock);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Internal function to get structure containing a code page information
|
||||||
|
* of code page that is already loaded.
|
||||||
|
*
|
||||||
|
* @param CodePage
|
||||||
|
* Number of the code page. Special values like CP_OEMCP, CP_ACP
|
||||||
|
* or CP_UTF8 aren't allowed.
|
||||||
|
*
|
||||||
|
* @return Code page entry or NULL if the specified code page hasn't
|
||||||
|
* been loaded yet.
|
||||||
|
*/
|
||||||
|
PCODEPAGE_ENTRY FASTCALL
|
||||||
|
IntGetLoadedCodePageEntry(UINT CodePage)
|
||||||
|
{
|
||||||
|
LIST_ENTRY *CurrentEntry;
|
||||||
|
PCODEPAGE_ENTRY Current;
|
||||||
|
|
||||||
|
RtlEnterCriticalSection(&CodePageListLock);
|
||||||
|
for (CurrentEntry = CodePageListHead.Flink;
|
||||||
|
CurrentEntry != &CodePageListHead;
|
||||||
|
CurrentEntry = CurrentEntry->Flink)
|
||||||
|
{
|
||||||
|
Current = CONTAINING_RECORD(CurrentEntry, CODEPAGE_ENTRY, Entry);
|
||||||
|
if (Current->CodePage == CodePage)
|
||||||
|
{
|
||||||
|
RtlLeaveCriticalSection(&CodePageListLock);
|
||||||
|
return Current;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
RtlLeaveCriticalSection(&CodePageListLock);
|
||||||
|
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
PCODEPAGE_ENTRY FASTCALL
|
||||||
|
IntGetCodePageEntry(UINT CodePage)
|
||||||
|
{
|
||||||
|
CHAR SectionName[40];
|
||||||
|
NTSTATUS Status;
|
||||||
|
HANDLE SectionHandle = INVALID_HANDLE_VALUE, FileHandle;
|
||||||
|
PBYTE SectionMapping;
|
||||||
|
OBJECT_ATTRIBUTES ObjectAttributes;
|
||||||
|
ANSI_STRING AnsiName;
|
||||||
|
UNICODE_STRING UnicodeName;
|
||||||
|
WCHAR FileName[MAX_PATH + 1];
|
||||||
|
UINT FileNamePos;
|
||||||
|
PCODEPAGE_ENTRY CodePageEntry;
|
||||||
|
|
||||||
|
if (CodePage == CP_THREAD_ACP)
|
||||||
|
{
|
||||||
|
if (!GetLocaleInfoW(GetThreadLocale(), LOCALE_IDEFAULTANSICODEPAGE |
|
||||||
|
LOCALE_RETURN_NUMBER, (WCHAR *)&CodePage,
|
||||||
|
sizeof(CodePage) / sizeof(WCHAR)))
|
||||||
|
{
|
||||||
|
/* Last error is set by GetLocaleInfoW. */
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (CodePage == CP_MACCP)
|
||||||
|
{
|
||||||
|
if (!GetLocaleInfoW(LOCALE_SYSTEM_DEFAULT, LOCALE_IDEFAULTMACCODEPAGE |
|
||||||
|
LOCALE_RETURN_NUMBER, (WCHAR *)&CodePage,
|
||||||
|
sizeof(CodePage) / sizeof(WCHAR)))
|
||||||
|
{
|
||||||
|
/* Last error is set by GetLocaleInfoW. */
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Try searching for loaded page first. */
|
||||||
|
CodePageEntry = IntGetLoadedCodePageEntry(CodePage);
|
||||||
|
if (CodePageEntry != NULL)
|
||||||
|
{
|
||||||
|
return CodePageEntry;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Yes, we really want to lock here. Otherwise it can happen that
|
||||||
|
* two parallel requests will try to get the entry for the same
|
||||||
|
* code page and we would load it twice.
|
||||||
|
*/
|
||||||
|
RtlEnterCriticalSection(&CodePageListLock);
|
||||||
|
|
||||||
|
/* Generate the section name. */
|
||||||
|
if (!GetNlsSectionName(CodePage, 10, 0, "\\Nls\\NlsSectionCP",
|
||||||
|
SectionName, sizeof(SectionName)))
|
||||||
|
{
|
||||||
|
RtlLeaveCriticalSection(&CodePageListLock);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
RtlInitAnsiString(&AnsiName, SectionName);
|
||||||
|
RtlAnsiStringToUnicodeString(&UnicodeName, &AnsiName, TRUE);
|
||||||
|
InitializeObjectAttributes(&ObjectAttributes, &UnicodeName, 0,
|
||||||
|
NULL, NULL);
|
||||||
|
|
||||||
|
/* Try to open the section first */
|
||||||
|
Status = NtOpenSection(&SectionHandle, SECTION_MAP_READ, &ObjectAttributes);
|
||||||
|
|
||||||
|
/* If the section doesn't exist, try to create it. */
|
||||||
|
if (Status == STATUS_UNSUCCESSFUL ||
|
||||||
|
Status == STATUS_OBJECT_NAME_NOT_FOUND ||
|
||||||
|
Status == STATUS_OBJECT_PATH_NOT_FOUND)
|
||||||
|
{
|
||||||
|
FileNamePos = GetSystemDirectoryW(FileName, MAX_PATH);
|
||||||
|
if (GetCPFileNameFromRegistry(CodePage, FileName + FileNamePos + 1,
|
||||||
|
MAX_PATH - FileNamePos - 1))
|
||||||
|
{
|
||||||
|
FileName[FileNamePos] = L'\\';
|
||||||
|
FileName[MAX_PATH] = 0;
|
||||||
|
FileHandle = CreateFileW(FileName, FILE_GENERIC_READ, FILE_SHARE_READ,
|
||||||
|
NULL, OPEN_EXISTING, 0, NULL);
|
||||||
|
Status = NtCreateSection(&SectionHandle, SECTION_MAP_READ,
|
||||||
|
&ObjectAttributes, NULL, PAGE_READONLY,
|
||||||
|
SEC_FILE, FileHandle);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
RtlFreeUnicodeString(&UnicodeName);
|
||||||
|
|
||||||
|
if (!NT_SUCCESS(Status))
|
||||||
|
{
|
||||||
|
RtlLeaveCriticalSection(&CodePageListLock);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
SectionMapping = MapViewOfFile(SectionHandle, FILE_MAP_READ, 0, 0, 0);
|
||||||
|
if (SectionMapping == NULL)
|
||||||
|
{
|
||||||
|
NtClose(SectionHandle);
|
||||||
|
RtlLeaveCriticalSection(&CodePageListLock);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
CodePageEntry = HeapAlloc(GetProcessHeap(), 0, sizeof(CODEPAGE_ENTRY));
|
||||||
|
if (CodePageEntry == NULL)
|
||||||
|
{
|
||||||
|
NtClose(SectionHandle);
|
||||||
|
RtlLeaveCriticalSection(&CodePageListLock);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
CodePageEntry->CodePage = CodePage;
|
||||||
|
CodePageEntry->SectionHandle = SectionHandle;
|
||||||
|
CodePageEntry->SectionMapping = SectionMapping;
|
||||||
|
RtlInitCodePageTable((PUSHORT)SectionMapping, &CodePageEntry->CodePageTable);
|
||||||
|
|
||||||
|
/* Insert the new entry to list and unlock. Uff. */
|
||||||
|
InsertTailList(&CodePageListHead, &CodePageEntry->Entry);
|
||||||
|
RtlLeaveCriticalSection(&CodePageListLock);
|
||||||
|
|
||||||
|
return CodePageEntry;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Internal version of MultiByteToWideChar for UTF8.
|
||||||
|
*
|
||||||
|
* @see MultiByteToWideChar
|
||||||
|
* @todo Add UTF8 validity checks.
|
||||||
|
*/
|
||||||
|
INT STDCALL
|
||||||
|
IntMultiByteToWideCharUTF8(DWORD Flags,
|
||||||
|
LPCSTR MultiByteString, INT MultiByteCount,
|
||||||
|
LPWSTR WideCharString, INT WideCharCount)
|
||||||
|
{
|
||||||
|
LPCSTR MbsEnd;
|
||||||
|
UCHAR Char, Length;
|
||||||
|
WCHAR WideChar;
|
||||||
|
ULONG Count;
|
||||||
|
|
||||||
|
if (Flags != 0)
|
||||||
|
{
|
||||||
|
SetLastError(ERROR_INVALID_FLAGS);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Does caller query for output buffer size? */
|
||||||
|
if (WideCharCount == 0)
|
||||||
|
{
|
||||||
|
MbsEnd = MultiByteString + MultiByteCount;
|
||||||
|
for (; MultiByteString < MbsEnd; WideCharCount++)
|
||||||
|
{
|
||||||
|
Char = *MultiByteString++;
|
||||||
|
if (Char < 0xC0)
|
||||||
|
continue;
|
||||||
|
MultiByteString += UTF8Length[Char - 0x80];
|
||||||
|
}
|
||||||
|
return WideCharCount;
|
||||||
|
}
|
||||||
|
|
||||||
|
MbsEnd = MultiByteString + MultiByteCount;
|
||||||
|
for (Count = 0; Count < WideCharCount && MultiByteString < MbsEnd; Count++)
|
||||||
|
{
|
||||||
|
Char = *MultiByteString++;
|
||||||
|
if (Char < 0x80)
|
||||||
|
{
|
||||||
|
*WideCharString++ = Char;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
Length = UTF8Length[Char - 0x80];
|
||||||
|
WideChar = UTF8Mask[Length];
|
||||||
|
while (Length && MultiByteString < MbsEnd)
|
||||||
|
WideChar = (WideChar << 6) | *MultiByteString++;
|
||||||
|
*WideCharString++ = WideChar;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (MultiByteString < MbsEnd)
|
||||||
|
SetLastError(ERROR_INSUFFICIENT_BUFFER);
|
||||||
|
|
||||||
|
return Count;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Internal version of MultiByteToWideChar for code page tables.
|
||||||
|
*
|
||||||
|
* @see MultiByteToWideChar
|
||||||
|
* @todo Handle MB_PRECOMPOSED, MB_COMPOSITE, MB_USEGLYPHCHARS and
|
||||||
|
* DBCS codepages.
|
||||||
|
*/
|
||||||
|
INT STDCALL
|
||||||
|
IntMultiByteToWideCharCP(UINT CodePage, DWORD Flags,
|
||||||
|
LPCSTR MultiByteString, INT MultiByteCount,
|
||||||
|
LPWSTR WideCharString, INT WideCharCount)
|
||||||
|
{
|
||||||
|
PCODEPAGE_ENTRY CodePageEntry;
|
||||||
|
PCPTABLEINFO CodePageTable;
|
||||||
|
LPCSTR TempString;
|
||||||
|
INT TempLength;
|
||||||
|
|
||||||
|
/* Get code page table. */
|
||||||
|
CodePageEntry = IntGetCodePageEntry(CodePage);
|
||||||
|
if (CodePageEntry == NULL)
|
||||||
|
{
|
||||||
|
SetLastError(ERROR_INVALID_PARAMETER);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
CodePageTable = &CodePageEntry->CodePageTable;
|
||||||
|
|
||||||
|
/* Different handling for DBCS code pages. */
|
||||||
|
if (CodePageTable->MaximumCharacterSize > 1)
|
||||||
|
{
|
||||||
|
/* UNIMPLEMENTED */
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
/* Check for invalid characters. */
|
||||||
|
if (Flags & MB_ERR_INVALID_CHARS)
|
||||||
|
{
|
||||||
|
for (TempString = MultiByteString, TempLength = MultiByteCount;
|
||||||
|
TempLength > 0;
|
||||||
|
TempString++, TempLength--)
|
||||||
|
{
|
||||||
|
if (CodePageTable->MultiByteTable[(UCHAR)*TempString] ==
|
||||||
|
CodePageTable->UniDefaultChar &&
|
||||||
|
*TempString != CodePageEntry->CodePageTable.DefaultChar)
|
||||||
|
{
|
||||||
|
SetLastError(ERROR_NO_UNICODE_TRANSLATION);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Does caller query for output buffer size? */
|
||||||
|
if (WideCharCount == 0)
|
||||||
|
return MultiByteCount;
|
||||||
|
|
||||||
|
/* Adjust buffer size. Wine trick ;-) */
|
||||||
|
if (WideCharCount < MultiByteCount)
|
||||||
|
{
|
||||||
|
MultiByteCount = WideCharCount;
|
||||||
|
SetLastError(ERROR_INSUFFICIENT_BUFFER);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (TempLength = MultiByteCount;
|
||||||
|
TempLength > 0;
|
||||||
|
MultiByteString++, TempLength--)
|
||||||
|
{
|
||||||
|
*WideCharString++ = CodePageTable->MultiByteTable[(UCHAR)*MultiByteString];
|
||||||
|
}
|
||||||
|
|
||||||
|
return MultiByteCount;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Internal version of WideCharToMultiByte for UTF8.
|
||||||
|
*
|
||||||
|
* @see WideCharToMultiByte
|
||||||
|
*/
|
||||||
|
INT STDCALL
|
||||||
|
IntWideCharToMultiByteUTF8(UINT CodePage, DWORD Flags,
|
||||||
|
LPCWSTR WideCharString, INT WideCharCount,
|
||||||
|
LPSTR MultiByteString, INT MultiByteCount,
|
||||||
|
LPCSTR DefaultChar, LPBOOL UsedDefaultChar)
|
||||||
|
{
|
||||||
|
DPRINT1("WideCharToMultiByte for CP_UTF8 is not implemented!\n");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Internal version of WideCharToMultiByte for code page tables.
|
||||||
|
*
|
||||||
|
* @see WideCharToMultiByte
|
||||||
|
* @todo Handle default characters and flags.
|
||||||
|
*/
|
||||||
|
INT STDCALL
|
||||||
|
IntWideCharToMultiByteCP(UINT CodePage, DWORD Flags,
|
||||||
|
LPCWSTR WideCharString, INT WideCharCount,
|
||||||
|
LPSTR MultiByteString, INT MultiByteCount,
|
||||||
|
LPCSTR DefaultChar, LPBOOL UsedDefaultChar)
|
||||||
|
{
|
||||||
|
PCODEPAGE_ENTRY CodePageEntry;
|
||||||
|
PCPTABLEINFO CodePageTable;
|
||||||
|
INT TempLength;
|
||||||
|
|
||||||
|
/* Get code page table. */
|
||||||
|
CodePageEntry = IntGetCodePageEntry(CodePage);
|
||||||
|
if (CodePageEntry == NULL)
|
||||||
|
{
|
||||||
|
SetLastError(ERROR_INVALID_PARAMETER);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
CodePageTable = &CodePageEntry->CodePageTable;
|
||||||
|
|
||||||
|
/* Different handling for DBCS code pages. */
|
||||||
|
if (CodePageTable->MaximumCharacterSize > 1)
|
||||||
|
{
|
||||||
|
DPRINT1("WideCharToMultiByte for DBCS codepages is not implemented!\n");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
/* Does caller query for output buffer size? */
|
||||||
|
if (MultiByteCount == 0)
|
||||||
|
return WideCharCount;
|
||||||
|
|
||||||
|
/* Adjust buffer size. Wine trick ;-) */
|
||||||
|
if (MultiByteCount < WideCharCount)
|
||||||
|
{
|
||||||
|
WideCharCount = MultiByteCount;
|
||||||
|
SetLastError(ERROR_INSUFFICIENT_BUFFER);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (TempLength = WideCharCount;
|
||||||
|
TempLength > 0;
|
||||||
|
WideCharString++, TempLength--)
|
||||||
|
{
|
||||||
|
*MultiByteString++ = ((PCHAR)CodePageTable->WideCharTable)[*WideCharString];
|
||||||
|
}
|
||||||
|
|
||||||
|
/* FIXME */
|
||||||
|
if (UsedDefaultChar != NULL)
|
||||||
|
*UsedDefaultChar = FALSE;
|
||||||
|
|
||||||
|
return WideCharCount;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* PUBLIC FUNCTIONS ***********************************************************/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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
|
||||||
|
*/
|
||||||
|
BOOL STDCALL
|
||||||
|
GetNlsSectionName(UINT CodePage, UINT Base, ULONG Unknown,
|
||||||
|
LPSTR BaseName, LPSTR Result, ULONG ResultSize)
|
||||||
|
{
|
||||||
|
CHAR Integer[11];
|
||||||
|
|
||||||
|
if (!NT_SUCCESS(RtlIntegerToChar(CodePage, Base, sizeof(Integer), Integer)))
|
||||||
|
return FALSE;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* 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;
|
||||||
|
|
||||||
|
lstrcpyA(Result, BaseName);
|
||||||
|
lstrcatA(Result, Integer);
|
||||||
|
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get file name of code page definition file.
|
||||||
|
*
|
||||||
|
* @param CodePage
|
||||||
|
* Code page number to get file name of.
|
||||||
|
* @param FileName
|
||||||
|
* Buffer that is filled with file name of successful return. Can
|
||||||
|
* 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
|
||||||
|
*/
|
||||||
|
BOOL STDCALL
|
||||||
|
GetCPFileNameFromRegistry(UINT CodePage, LPWSTR FileName, ULONG FileNameSize)
|
||||||
|
{
|
||||||
|
WCHAR ValueNameBuffer[11];
|
||||||
|
UNICODE_STRING KeyName, ValueName;
|
||||||
|
OBJECT_ATTRIBUTES ObjectAttributes;
|
||||||
|
NTSTATUS Status;
|
||||||
|
HANDLE KeyHandle;
|
||||||
|
PKEY_VALUE_PARTIAL_INFORMATION Kvpi;
|
||||||
|
DWORD KvpiSize;
|
||||||
|
|
||||||
|
/* Convert the codepage number to string. */
|
||||||
|
ValueName.Buffer = ValueNameBuffer;
|
||||||
|
ValueName.MaximumLength = sizeof(ValueNameBuffer);
|
||||||
|
if (!NT_SUCCESS(RtlIntegerToUnicodeString(CodePage, 10, &ValueName)))
|
||||||
|
return FALSE;
|
||||||
|
|
||||||
|
/* 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))
|
||||||
|
{
|
||||||
|
RtlFreeUnicodeString(&ValueName);
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Allocate buffer that will be used to query the value data. */
|
||||||
|
KvpiSize = sizeof(KEY_VALUE_PARTIAL_INFORMATION) +
|
||||||
|
(MAX_PATH * sizeof(WCHAR));
|
||||||
|
Kvpi = HeapAlloc(GetProcessHeap(), 0, KvpiSize);
|
||||||
|
if (Kvpi == NULL)
|
||||||
|
{
|
||||||
|
NtClose(KeyHandle);
|
||||||
|
RtlFreeUnicodeString(&ValueName);
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Query the file name for our code page. */
|
||||||
|
Status = NtQueryValueKey(KeyHandle, &ValueName, KeyValuePartialInformation,
|
||||||
|
Kvpi, KvpiSize, &KvpiSize);
|
||||||
|
RtlFreeUnicodeString(&ValueName);
|
||||||
|
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))
|
||||||
|
{
|
||||||
|
if (FileName != NULL)
|
||||||
|
{
|
||||||
|
lstrcpynW(FileName, (WCHAR*)Kvpi->Data,
|
||||||
|
min(Kvpi->DataLength / sizeof(WCHAR), FileNameSize));
|
||||||
|
}
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
BOOL STDCALL
|
||||||
|
IsValidCodePage(UINT CodePage)
|
||||||
|
{
|
||||||
|
if (CodePage == CP_UTF8 || CodePage == CP_UTF7)
|
||||||
|
return TRUE;
|
||||||
|
if (IntGetLoadedCodePageEntry(CodePage))
|
||||||
|
return TRUE;
|
||||||
|
return GetCPFileNameFromRegistry(CodePage, NULL, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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
|
||||||
|
*/
|
||||||
|
INT STDCALL
|
||||||
|
MultiByteToWideChar(UINT CodePage, DWORD Flags,
|
||||||
|
LPCSTR MultiByteString, INT MultiByteCount,
|
||||||
|
LPWSTR WideCharString, INT WideCharCount)
|
||||||
|
{
|
||||||
|
/* Check the parameters. */
|
||||||
|
if (MultiByteString == NULL ||
|
||||||
|
(WideCharString == NULL && WideCharCount > 0))
|
||||||
|
{
|
||||||
|
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:
|
||||||
|
DPRINT1("MultiByteToWideChar for CP_UTF7 is not implemented!\n");
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
case CP_SYMBOL:
|
||||||
|
DPRINT1("MultiByteToWideChar for CP_SYMBOL is not implemented!\n");
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
default:
|
||||||
|
return IntMultiByteToWideCharCP(
|
||||||
|
CodePage, Flags, MultiByteString, MultiByteCount,
|
||||||
|
WideCharString, WideCharCount);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Convert a wide-charater string to closest multi-byte 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 (WC_NO_BEST_FIT_CHARS, WC_COMPOSITECHECK,
|
||||||
|
* WC_DISCARDNS, WC_SEPCHARS, WC_DEFAULTCHAR).
|
||||||
|
* @param WideCharString
|
||||||
|
* Points to the wide-character string to be converted.
|
||||||
|
* @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
|
||||||
|
* Points to the buffer to receive the translated string.
|
||||||
|
* @param MultiByteCount
|
||||||
|
* 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
|
||||||
|
* Points to a flag that indicates whether a default character was
|
||||||
|
* used. This parameter can be NULL.
|
||||||
|
*
|
||||||
|
* @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
|
||||||
|
*/
|
||||||
|
INT STDCALL
|
||||||
|
WideCharToMultiByte(UINT CodePage, DWORD Flags,
|
||||||
|
LPCWSTR WideCharString, INT WideCharCount,
|
||||||
|
LPSTR MultiByteString, INT MultiByteCount,
|
||||||
|
LPCSTR DefaultChar, LPBOOL UsedDefaultChar)
|
||||||
|
{
|
||||||
|
/* Check the parameters. */
|
||||||
|
if (WideCharString == NULL ||
|
||||||
|
(MultiByteString == NULL && 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:
|
||||||
|
return IntWideCharToMultiByteUTF8(
|
||||||
|
CodePage, Flags, WideCharString, WideCharCount,
|
||||||
|
MultiByteString, MultiByteCount, DefaultChar,
|
||||||
|
UsedDefaultChar);
|
||||||
|
|
||||||
|
case CP_UTF7:
|
||||||
|
DPRINT1("WideCharToMultiByte for CP_UTF7 is not implemented!\n");
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
case CP_SYMBOL:
|
||||||
|
DPRINT1("WideCharToMultiByte for CP_SYMBOL is not implemented!\n");
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
default:
|
||||||
|
return IntWideCharToMultiByteCP(
|
||||||
|
CodePage, Flags, WideCharString, WideCharCount,
|
||||||
|
MultiByteString, MultiByteCount, DefaultChar,
|
||||||
|
UsedDefaultChar);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* EOF */
|
Loading…
Add table
Add a link
Reference in a new issue