3 * Copyright (C) 2004 ReactOS Team
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
20 * @brief National Language Support.
21 * @author Filip Navara
24 /* INCLUDES *******************************************************************/
28 #include "../include/debug.h"
30 /* GLOBAL VARIABLES ***********************************************************/
32 typedef struct _CODEPAGE_ENTRY
38 CPTABLEINFO CodePageTable
;
39 } CODEPAGE_ENTRY
, *PCODEPAGE_ENTRY
;
41 /* Sequence length based on the first character. */
42 static const char UTF8Length
[128] =
44 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x80 - 0x8F */
45 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x90 - 0x9F */
46 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0xA0 - 0xAF */
47 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0xB0 - 0xBF */
48 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 0xC0 - 0xCF */
49 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 0xD0 - 0xDF */
50 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, /* 0xE0 - 0xEF */
51 3, 3, 3, 3, 3, 3, 3, 3, 4, 4, 4, 4, 5, 5, 0, 0 /* 0xF0 - 0xFF */
54 /* First byte mask depending on UTF-8 sequence length. */
55 static const unsigned char UTF8Mask
[6] = {0x7f, 0x1f, 0x0f, 0x07, 0x03, 0x01};
57 /* FIXME: Change to HASH table or linear array. */
58 static LIST_ENTRY CodePageListHead
;
59 static CODEPAGE_ENTRY AnsiCodePage
;
60 static CODEPAGE_ENTRY OemCodePage
;
61 static RTL_CRITICAL_SECTION CodePageListLock
;
63 /* FORWARD DECLARATIONS *******************************************************/
66 GetNlsSectionName(UINT CodePage
, UINT Base
, ULONG Unknown
,
67 LPSTR BaseName
, LPSTR Result
, ULONG ResultSize
);
70 GetCPFileNameFromRegistry(UINT CodePage
, LPWSTR FileName
, ULONG FileNameSize
);
72 /* PRIVATE FUNCTIONS **********************************************************/
77 * Internal NLS related stuff initialization.
83 UNICODE_STRING DirName
;
84 OBJECT_ATTRIBUTES ObjectAttributes
;
87 InitializeListHead(&CodePageListHead
);
88 RtlInitializeCriticalSection(&CodePageListLock
);
91 * FIXME: Eventually this should be done only for the NLS Server
92 * process, but since we don't have anything like that (yet?) we
93 * always try to create the "\Nls" directory here.
95 RtlInitUnicodeString(&DirName
, L
"\\Nls");
96 InitializeObjectAttributes(&ObjectAttributes
, &DirName
,
97 OBJ_CASE_INSENSITIVE
| OBJ_PERMANENT
,
99 if (NT_SUCCESS(NtCreateDirectoryObject(&Handle
, DIRECTORY_ALL_ACCESS
, &ObjectAttributes
)))
104 /* Setup ANSI code page. */
105 AnsiCodePage
.CodePage
= CP_ACP
;
106 AnsiCodePage
.SectionHandle
= NULL
;
107 AnsiCodePage
.SectionMapping
= NtCurrentTeb()->ProcessEnvironmentBlock
->AnsiCodePageData
;
108 RtlInitCodePageTable((PUSHORT
)AnsiCodePage
.SectionMapping
,
109 &AnsiCodePage
.CodePageTable
);
110 InsertTailList(&CodePageListHead
, &AnsiCodePage
.Entry
);
112 /* Setup OEM code page. */
113 OemCodePage
.CodePage
= CP_OEMCP
;
114 OemCodePage
.SectionHandle
= NULL
;
115 OemCodePage
.SectionMapping
= NtCurrentTeb()->ProcessEnvironmentBlock
->OemCodePageData
;
116 RtlInitCodePageTable((PUSHORT
)OemCodePage
.SectionMapping
,
117 &OemCodePage
.CodePageTable
);
118 InsertTailList(&CodePageListHead
, &OemCodePage
.Entry
);
126 * Internal NLS related stuff uninitialization.
132 PCODEPAGE_ENTRY Current
;
134 /* Delete the code page list. */
135 while (!IsListEmpty(&CodePageListHead
))
137 Current
= CONTAINING_RECORD(CodePageListHead
.Flink
, CODEPAGE_ENTRY
, Entry
);
138 if (Current
->SectionHandle
!= NULL
)
140 UnmapViewOfFile(Current
->SectionMapping
);
141 NtClose(Current
->SectionHandle
);
143 RemoveHeadList(&CodePageListHead
);
145 RtlDeleteCriticalSection(&CodePageListLock
);
149 * @name IntGetLoadedCodePageEntry
151 * Internal function to get structure containing a code page information
152 * of code page that is already loaded.
155 * Number of the code page. Special values like CP_OEMCP, CP_ACP
156 * or CP_UTF8 aren't allowed.
158 * @return Code page entry or NULL if the specified code page hasn't
162 PCODEPAGE_ENTRY FASTCALL
163 IntGetLoadedCodePageEntry(UINT CodePage
)
165 LIST_ENTRY
*CurrentEntry
;
166 PCODEPAGE_ENTRY Current
;
168 RtlEnterCriticalSection(&CodePageListLock
);
169 for (CurrentEntry
= CodePageListHead
.Flink
;
170 CurrentEntry
!= &CodePageListHead
;
171 CurrentEntry
= CurrentEntry
->Flink
)
173 Current
= CONTAINING_RECORD(CurrentEntry
, CODEPAGE_ENTRY
, Entry
);
174 if (Current
->CodePage
== CodePage
)
176 RtlLeaveCriticalSection(&CodePageListLock
);
180 RtlLeaveCriticalSection(&CodePageListLock
);
186 * @name IntGetCodePageEntry
188 * Internal function to get structure containing a code page information.
191 * Number of the code page. Special values like CP_OEMCP, CP_ACP
192 * or CP_THREAD_ACP are allowed, but CP_UTF[7/8] isn't.
194 * @return Code page entry.
197 static PCODEPAGE_ENTRY FASTCALL
198 IntGetCodePageEntry(UINT CodePage
)
200 CHAR SectionName
[40];
202 HANDLE SectionHandle
= INVALID_HANDLE_VALUE
, FileHandle
;
203 PBYTE SectionMapping
;
204 OBJECT_ATTRIBUTES ObjectAttributes
;
205 ANSI_STRING AnsiName
;
206 UNICODE_STRING UnicodeName
;
207 WCHAR FileName
[MAX_PATH
+ 1];
209 PCODEPAGE_ENTRY CodePageEntry
;
211 if (CodePage
== CP_THREAD_ACP
)
213 if (!GetLocaleInfoW(GetThreadLocale(), LOCALE_IDEFAULTANSICODEPAGE
|
214 LOCALE_RETURN_NUMBER
, (WCHAR
*)&CodePage
,
215 sizeof(CodePage
) / sizeof(WCHAR
)))
217 /* Last error is set by GetLocaleInfoW. */
221 else if (CodePage
== CP_MACCP
)
223 if (!GetLocaleInfoW(LOCALE_SYSTEM_DEFAULT
, LOCALE_IDEFAULTMACCODEPAGE
|
224 LOCALE_RETURN_NUMBER
, (WCHAR
*)&CodePage
,
225 sizeof(CodePage
) / sizeof(WCHAR
)))
227 /* Last error is set by GetLocaleInfoW. */
232 /* Try searching for loaded page first. */
233 CodePageEntry
= IntGetLoadedCodePageEntry(CodePage
);
234 if (CodePageEntry
!= NULL
)
236 return CodePageEntry
;
240 * Yes, we really want to lock here. Otherwise it can happen that
241 * two parallel requests will try to get the entry for the same
242 * code page and we would load it twice.
244 RtlEnterCriticalSection(&CodePageListLock
);
246 /* Generate the section name. */
247 if (!GetNlsSectionName(CodePage
, 10, 0, "\\Nls\\NlsSectionCP",
248 SectionName
, sizeof(SectionName
)))
250 RtlLeaveCriticalSection(&CodePageListLock
);
253 RtlInitAnsiString(&AnsiName
, SectionName
);
254 RtlAnsiStringToUnicodeString(&UnicodeName
, &AnsiName
, TRUE
);
255 InitializeObjectAttributes(&ObjectAttributes
, &UnicodeName
, 0,
258 /* Try to open the section first */
259 Status
= NtOpenSection(&SectionHandle
, SECTION_MAP_READ
, &ObjectAttributes
);
261 /* If the section doesn't exist, try to create it. */
262 if (Status
== STATUS_UNSUCCESSFUL
||
263 Status
== STATUS_OBJECT_NAME_NOT_FOUND
||
264 Status
== STATUS_OBJECT_PATH_NOT_FOUND
)
266 FileNamePos
= GetSystemDirectoryW(FileName
, MAX_PATH
);
267 if (GetCPFileNameFromRegistry(CodePage
, FileName
+ FileNamePos
+ 1,
268 MAX_PATH
- FileNamePos
- 1))
270 FileName
[FileNamePos
] = L
'\\';
271 FileName
[MAX_PATH
] = 0;
272 FileHandle
= CreateFileW(FileName
, FILE_GENERIC_READ
, FILE_SHARE_READ
,
273 NULL
, OPEN_EXISTING
, 0, NULL
);
274 Status
= NtCreateSection(&SectionHandle
, SECTION_MAP_READ
,
275 &ObjectAttributes
, NULL
, PAGE_READONLY
,
276 SEC_FILE
, FileHandle
);
279 RtlFreeUnicodeString(&UnicodeName
);
281 if (!NT_SUCCESS(Status
))
283 RtlLeaveCriticalSection(&CodePageListLock
);
287 SectionMapping
= MapViewOfFile(SectionHandle
, FILE_MAP_READ
, 0, 0, 0);
288 if (SectionMapping
== NULL
)
290 NtClose(SectionHandle
);
291 RtlLeaveCriticalSection(&CodePageListLock
);
295 CodePageEntry
= HeapAlloc(GetProcessHeap(), 0, sizeof(CODEPAGE_ENTRY
));
296 if (CodePageEntry
== NULL
)
298 NtClose(SectionHandle
);
299 RtlLeaveCriticalSection(&CodePageListLock
);
303 CodePageEntry
->CodePage
= CodePage
;
304 CodePageEntry
->SectionHandle
= SectionHandle
;
305 CodePageEntry
->SectionMapping
= SectionMapping
;
306 RtlInitCodePageTable((PUSHORT
)SectionMapping
, &CodePageEntry
->CodePageTable
);
308 /* Insert the new entry to list and unlock. Uff. */
309 InsertTailList(&CodePageListHead
, &CodePageEntry
->Entry
);
310 RtlLeaveCriticalSection(&CodePageListLock
);
312 return CodePageEntry
;
316 * @name IntMultiByteToWideCharUTF8
318 * Internal version of MultiByteToWideChar for UTF8.
320 * @see MultiByteToWideChar
321 * @todo Add UTF8 validity checks.
325 IntMultiByteToWideCharUTF8(DWORD Flags
,
326 LPCSTR MultiByteString
, INT MultiByteCount
,
327 LPWSTR WideCharString
, INT WideCharCount
)
336 SetLastError(ERROR_INVALID_FLAGS
);
340 /* Does caller query for output buffer size? */
341 if (WideCharCount
== 0)
343 MbsEnd
= MultiByteString
+ MultiByteCount
;
344 for (; MultiByteString
< MbsEnd
; WideCharCount
++)
346 Char
= *MultiByteString
++;
349 MultiByteString
+= UTF8Length
[Char
- 0x80];
351 return WideCharCount
;
354 MbsEnd
= MultiByteString
+ MultiByteCount
;
355 for (Count
= 0; Count
< WideCharCount
&& MultiByteString
< MbsEnd
; Count
++)
357 Char
= *MultiByteString
++;
360 *WideCharString
++ = Char
;
363 Length
= UTF8Length
[Char
- 0x80];
364 WideChar
= Char
& UTF8Mask
[Length
];
365 while (Length
&& MultiByteString
< MbsEnd
)
367 WideChar
= (WideChar
<< 6) | *MultiByteString
++;
370 *WideCharString
++ = WideChar
;
373 if (MultiByteString
< MbsEnd
)
374 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
380 * @name IntMultiByteToWideCharCP
382 * Internal version of MultiByteToWideChar for code page tables.
384 * @see MultiByteToWideChar
385 * @todo Handle MB_PRECOMPOSED, MB_COMPOSITE, MB_USEGLYPHCHARS and
390 IntMultiByteToWideCharCP(UINT CodePage
, DWORD Flags
,
391 LPCSTR MultiByteString
, INT MultiByteCount
,
392 LPWSTR WideCharString
, INT WideCharCount
)
394 PCODEPAGE_ENTRY CodePageEntry
;
395 PCPTABLEINFO CodePageTable
;
399 /* Get code page table. */
400 CodePageEntry
= IntGetCodePageEntry(CodePage
);
401 if (CodePageEntry
== NULL
)
403 SetLastError(ERROR_INVALID_PARAMETER
);
406 CodePageTable
= &CodePageEntry
->CodePageTable
;
408 /* Different handling for DBCS code pages. */
409 if (CodePageTable
->MaximumCharacterSize
> 1)
416 /* Check for invalid characters. */
417 if (Flags
& MB_ERR_INVALID_CHARS
)
419 for (TempString
= MultiByteString
, TempLength
= MultiByteCount
;
421 TempString
++, TempLength
--)
423 if (CodePageTable
->MultiByteTable
[(UCHAR
)*TempString
] ==
424 CodePageTable
->UniDefaultChar
&&
425 *TempString
!= CodePageEntry
->CodePageTable
.DefaultChar
)
427 SetLastError(ERROR_NO_UNICODE_TRANSLATION
);
433 /* Does caller query for output buffer size? */
434 if (WideCharCount
== 0)
435 return MultiByteCount
;
437 /* Adjust buffer size. Wine trick ;-) */
438 if (WideCharCount
< MultiByteCount
)
440 MultiByteCount
= WideCharCount
;
441 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
444 for (TempLength
= MultiByteCount
;
446 MultiByteString
++, TempLength
--)
448 *WideCharString
++ = CodePageTable
->MultiByteTable
[(UCHAR
)*MultiByteString
];
451 return MultiByteCount
;
456 * @name IntWideCharToMultiByteUTF8
458 * Internal version of WideCharToMultiByte for UTF8.
460 * @see WideCharToMultiByte
464 IntWideCharToMultiByteUTF8(UINT CodePage
, DWORD Flags
,
465 LPCWSTR WideCharString
, INT WideCharCount
,
466 LPSTR MultiByteString
, INT MultiByteCount
,
467 LPCSTR DefaultChar
, LPBOOL UsedDefaultChar
)
472 /* Does caller query for output buffer size? */
473 if (MultiByteCount
== 0)
475 for (TempLength
= 0; WideCharCount
;
476 WideCharCount
--, WideCharString
++)
479 if (*WideCharString
>= 0x80)
482 if (*WideCharString
>= 0x800)
489 for (TempLength
= MultiByteCount
; WideCharCount
;
490 WideCharCount
--, WideCharString
++)
492 Char
= *WideCharString
;
497 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
501 *MultiByteString
++ = Char
;
505 if (Char
< 0x800) /* 0x80-0x7ff: 2 bytes */
509 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
512 MultiByteString
[1] = 0x80 | (Char
& 0x3f); Char
>>= 6;
513 MultiByteString
[0] = 0xc0 | Char
;
514 MultiByteString
+= 2;
519 /* 0x800-0xffff: 3 bytes */
522 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
525 MultiByteString
[2] = 0x80 | (Char
& 0x3f); Char
>>= 6;
526 MultiByteString
[1] = 0x80 | (Char
& 0x3f); Char
>>= 6;
527 MultiByteString
[0] = 0xe0 | Char
;
528 MultiByteString
+= 3;
532 return MultiByteCount
- TempLength
;
536 * @name IntWideCharToMultiByteCP
538 * Internal version of WideCharToMultiByte for code page tables.
540 * @see WideCharToMultiByte
541 * @todo Handle default characters and flags.
545 IntWideCharToMultiByteCP(UINT CodePage
, DWORD Flags
,
546 LPCWSTR WideCharString
, INT WideCharCount
,
547 LPSTR MultiByteString
, INT MultiByteCount
,
548 LPCSTR DefaultChar
, LPBOOL UsedDefaultChar
)
550 PCODEPAGE_ENTRY CodePageEntry
;
551 PCPTABLEINFO CodePageTable
;
554 /* Get code page table. */
555 CodePageEntry
= IntGetCodePageEntry(CodePage
);
556 if (CodePageEntry
== NULL
)
558 SetLastError(ERROR_INVALID_PARAMETER
);
561 CodePageTable
= &CodePageEntry
->CodePageTable
;
563 /* Different handling for DBCS code pages. */
564 if (CodePageTable
->MaximumCharacterSize
> 1)
566 DPRINT1("WideCharToMultiByte for DBCS codepages is not implemented!\n");
571 /* Does caller query for output buffer size? */
572 if (MultiByteCount
== 0)
573 return WideCharCount
;
575 /* Adjust buffer size. Wine trick ;-) */
576 if (MultiByteCount
< WideCharCount
)
578 WideCharCount
= MultiByteCount
;
579 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
582 for (TempLength
= WideCharCount
;
584 WideCharString
++, TempLength
--)
586 *MultiByteString
++ = ((PCHAR
)CodePageTable
->WideCharTable
)[*WideCharString
];
590 if (UsedDefaultChar
!= NULL
)
591 *UsedDefaultChar
= FALSE
;
593 return WideCharCount
;
598 * @name IntIsLeadByte
600 * Internal function to detect if byte is lead byte in specific character
605 IntIsLeadByte(PCPTABLEINFO TableInfo
, BYTE Byte
)
609 if (TableInfo
->MaximumCharacterSize
== 2)
611 for (LeadByteNo
= 0; LeadByteNo
< MAXIMUM_LEADBYTES
; LeadByteNo
++)
613 if (TableInfo
->LeadByte
[LeadByteNo
] == Byte
)
621 /* PUBLIC FUNCTIONS ***********************************************************/
624 * @name GetNlsSectionName
626 * Construct a name of NLS section.
631 * Integer base used for converting to string. Usually set to 10.
633 * As the name suggests the meaning of this parameter is unknown.
634 * The native version of Kernel32 passes it as the third parameter
635 * to NlsConvertIntegerToString function, which is used for the
636 * actual conversion of the code page number.
638 * Base name of the section. (ex. "\\Nls\\NlsSectionCP")
640 * Buffer that will hold the constructed name.
642 * Size of the buffer for the result.
644 * @return TRUE if the buffer was large enough and was filled with
645 * the requested information, FALSE otherwise.
651 GetNlsSectionName(UINT CodePage
, UINT Base
, ULONG Unknown
,
652 LPSTR BaseName
, LPSTR Result
, ULONG ResultSize
)
656 if (!NT_SUCCESS(RtlIntegerToChar(CodePage
, Base
, sizeof(Integer
), Integer
)))
660 * If the name including the terminating NULL character doesn't
661 * fit in the output buffer then fail.
663 if (strlen(Integer
) + strlen(BaseName
) >= ResultSize
)
666 lstrcpyA(Result
, BaseName
);
667 lstrcatA(Result
, Integer
);
673 * @name GetCPFileNameFromRegistry
675 * Get file name of code page definition file.
678 * Code page number to get file name of.
680 * Buffer that is filled with file name of successful return. Can
682 * @param FileNameSize
683 * Size of the buffer to hold file name in WCHARs.
685 * @return TRUE if the file name was retrieved, FALSE otherwise.
691 GetCPFileNameFromRegistry(UINT CodePage
, LPWSTR FileName
, ULONG FileNameSize
)
693 WCHAR ValueNameBuffer
[11];
694 UNICODE_STRING KeyName
, ValueName
;
695 OBJECT_ATTRIBUTES ObjectAttributes
;
698 PKEY_VALUE_PARTIAL_INFORMATION Kvpi
;
701 /* Convert the codepage number to string. */
702 ValueName
.Buffer
= ValueNameBuffer
;
703 ValueName
.MaximumLength
= sizeof(ValueNameBuffer
);
704 if (!NT_SUCCESS(RtlIntegerToUnicodeString(CodePage
, 10, &ValueName
)))
707 /* Open the registry key containing file name mappings. */
708 RtlInitUnicodeString(&KeyName
, L
"\\Registry\\Machine\\System\\"
709 L
"CurrentControlSet\\Control\\Nls\\CodePage");
710 InitializeObjectAttributes(&ObjectAttributes
, &KeyName
, OBJ_CASE_INSENSITIVE
,
712 Status
= NtOpenKey(&KeyHandle
, KEY_READ
, &ObjectAttributes
);
713 if (!NT_SUCCESS(Status
))
718 /* Allocate buffer that will be used to query the value data. */
719 KvpiSize
= sizeof(KEY_VALUE_PARTIAL_INFORMATION
) +
720 (MAX_PATH
* sizeof(WCHAR
));
721 Kvpi
= HeapAlloc(GetProcessHeap(), 0, KvpiSize
);
728 /* Query the file name for our code page. */
729 Status
= NtQueryValueKey(KeyHandle
, &ValueName
, KeyValuePartialInformation
,
730 Kvpi
, KvpiSize
, &KvpiSize
);
734 /* Check if we succeded and the value is non-empty string. */
735 if (NT_SUCCESS(Status
) && Kvpi
->Type
== REG_SZ
&&
736 Kvpi
->DataLength
> sizeof(WCHAR
))
738 if (FileName
!= NULL
)
740 lstrcpynW(FileName
, (WCHAR
*)Kvpi
->Data
,
741 min(Kvpi
->DataLength
/ sizeof(WCHAR
), FileNameSize
));
750 * @name IsValidCodePage
752 * Detect if specified code page is valid and present in the system.
755 * Code page number to query.
757 * @return TRUE if code page is present.
761 IsValidCodePage(UINT CodePage
)
763 if (CodePage
== CP_UTF8
|| CodePage
== CP_UTF7
)
765 if (IntGetLoadedCodePageEntry(CodePage
))
767 return GetCPFileNameFromRegistry(CodePage
, NULL
, 0);
771 * @name MultiByteToWideChar
773 * Convert a multi-byte string to wide-charater equivalent.
776 * Code page to be used to perform the conversion. It can be also
777 * one of the special values (CP_ACP for ANSI code page, CP_MACCP
778 * for Macintosh code page, CP_OEMCP for OEM code page, CP_THREAD_ACP
779 * for thread active code page, CP_UTF7 or CP_UTF8).
781 * Additional conversion flags (MB_PRECOMPOSED, MB_COMPOSITE,
782 * MB_ERR_INVALID_CHARS, MB_USEGLYPHCHARS).
783 * @param MultiByteString
785 * @param MultiByteCount
786 * Size of MultiByteString, or -1 if MultiByteString is NULL
788 * @param WideCharString
790 * @param WideCharCount
791 * Size in WCHARs of WideCharString, or 0 if the caller just wants
792 * to know how large WideCharString should be for a successful
795 * @return Zero on error, otherwise the number of WCHARs written
796 * in the WideCharString buffer.
802 MultiByteToWideChar(UINT CodePage
, DWORD Flags
,
803 LPCSTR MultiByteString
, INT MultiByteCount
,
804 LPWSTR WideCharString
, INT WideCharCount
)
806 /* Check the parameters. */
807 if (MultiByteString
== NULL
||
808 (WideCharString
== NULL
&& WideCharCount
> 0) ||
809 (PVOID
)MultiByteString
== (PVOID
)WideCharString
)
811 SetLastError(ERROR_INVALID_PARAMETER
);
815 /* Determine the input string length. */
816 if (MultiByteCount
< 0)
818 MultiByteCount
= lstrlenA(MultiByteString
) + 1;
824 return IntMultiByteToWideCharUTF8(
825 Flags
, MultiByteString
, MultiByteCount
,
826 WideCharString
, WideCharCount
);
829 DPRINT1("MultiByteToWideChar for CP_UTF7 is not implemented!\n");
833 DPRINT1("MultiByteToWideChar for CP_SYMBOL is not implemented!\n");
837 return IntMultiByteToWideCharCP(
838 CodePage
, Flags
, MultiByteString
, MultiByteCount
,
839 WideCharString
, WideCharCount
);
844 * @name WideCharToMultiByte
846 * Convert a wide-charater string to closest multi-byte equivalent.
849 * Code page to be used to perform the conversion. It can be also
850 * one of the special values (CP_ACP for ANSI code page, CP_MACCP
851 * for Macintosh code page, CP_OEMCP for OEM code page, CP_THREAD_ACP
852 * for thread active code page, CP_UTF7 or CP_UTF8).
854 * Additional conversion flags (WC_NO_BEST_FIT_CHARS, WC_COMPOSITECHECK,
855 * WC_DISCARDNS, WC_SEPCHARS, WC_DEFAULTCHAR).
856 * @param WideCharString
857 * Points to the wide-character string to be converted.
858 * @param WideCharCount
859 * Size in WCHARs of WideCharStr, or 0 if the caller just wants to
860 * know how large WideCharString should be for a successful conversion.
861 * @param MultiByteString
862 * Points to the buffer to receive the translated string.
863 * @param MultiByteCount
864 * Specifies the size in bytes of the buffer pointed to by the
865 * MultiByteString parameter. If this value is zero, the function
866 * returns the number of bytes required for the buffer.
868 * Points to the character used if a wide character cannot be
869 * represented in the specified code page. If this parameter is
870 * NULL, a system default value is used.
871 * @param UsedDefaultChar
872 * Points to a flag that indicates whether a default character was
873 * used. This parameter can be NULL.
875 * @return Zero on error, otherwise the number of bytes written in the
876 * MultiByteString buffer. Or the number of bytes needed for
877 * the MultiByteString buffer if MultiByteCount is zero.
883 WideCharToMultiByte(UINT CodePage
, DWORD Flags
,
884 LPCWSTR WideCharString
, INT WideCharCount
,
885 LPSTR MultiByteString
, INT MultiByteCount
,
886 LPCSTR DefaultChar
, LPBOOL UsedDefaultChar
)
888 /* Check the parameters. */
889 if (WideCharString
== NULL
||
890 (MultiByteString
== NULL
&& MultiByteCount
> 0) ||
891 (PVOID
)WideCharString
== (PVOID
)MultiByteString
)
893 SetLastError(ERROR_INVALID_PARAMETER
);
897 /* Determine the input string length. */
898 if (WideCharCount
< 0)
900 WideCharCount
= lstrlenW(WideCharString
) + 1;
906 return IntWideCharToMultiByteUTF8(
907 CodePage
, Flags
, WideCharString
, WideCharCount
,
908 MultiByteString
, MultiByteCount
, DefaultChar
,
912 DPRINT1("WideCharToMultiByte for CP_UTF7 is not implemented!\n");
916 DPRINT1("WideCharToMultiByte for CP_SYMBOL is not implemented!\n");
920 return IntWideCharToMultiByteCP(
921 CodePage
, Flags
, WideCharString
, WideCharCount
,
922 MultiByteString
, MultiByteCount
, DefaultChar
,
930 * Get active ANSI code page number.
938 return AnsiCodePage
.CodePageTable
.CodePage
;
944 * Get active OEM code page number.
952 return OemCodePage
.CodePageTable
.CodePage
;
956 * @name IsDBCSLeadByteEx
958 * Determine if passed byte is lead byte in specified code page.
964 IsDBCSLeadByteEx(UINT CodePage
, BYTE TestByte
)
966 PCODEPAGE_ENTRY CodePageEntry
;
968 CodePageEntry
= IntGetCodePageEntry(CodePage
);
969 if (CodePageEntry
!= NULL
)
970 return IntIsLeadByte(&CodePageEntry
->CodePageTable
, TestByte
);
972 SetLastError(ERROR_INVALID_PARAMETER
);
977 * @name IsDBCSLeadByteEx
979 * Determine if passed byte is lead byte in current ANSI code page.
985 IsDBCSLeadByte(BYTE TestByte
)
987 return IntIsLeadByte(&AnsiCodePage
.CodePageTable
, TestByte
);
992 NlsGetCacheUpdateCount(VOID
)