2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS system libraries
4 * FILE: dll/win32/kernel32/misc/nls.c
5 * PURPOSE: National Language Support
6 * PROGRAMMER: Filip Navara
14 /* INCLUDES *******************************************************************/
21 /* GLOBAL VARIABLES ***********************************************************/
23 /* Sequence length based on the first character. */
24 static const char UTF8Length
[128] =
26 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x80 - 0x8F */
27 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x90 - 0x9F */
28 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0xA0 - 0xAF */
29 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0xB0 - 0xBF */
30 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 0xC0 - 0xCF */
31 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 0xD0 - 0xDF */
32 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, /* 0xE0 - 0xEF */
33 3, 3, 3, 3, 3, 3, 3, 3, 4, 4, 4, 4, 5, 5, 0, 0 /* 0xF0 - 0xFF */
36 /* First byte mask depending on UTF-8 sequence length. */
37 static const unsigned char UTF8Mask
[6] = {0x7f, 0x1f, 0x0f, 0x07, 0x03, 0x01};
39 /* FIXME: Change to HASH table or linear array. */
40 static LIST_ENTRY CodePageListHead
;
41 static CODEPAGE_ENTRY AnsiCodePage
;
42 static CODEPAGE_ENTRY OemCodePage
;
43 static RTL_CRITICAL_SECTION CodePageListLock
;
45 /* FORWARD DECLARATIONS *******************************************************/
48 GetNlsSectionName(UINT CodePage
, UINT Base
, ULONG Unknown
,
49 LPSTR BaseName
, LPSTR Result
, ULONG ResultSize
);
52 GetCPFileNameFromRegistry(UINT CodePage
, LPWSTR FileName
, ULONG FileNameSize
);
54 /* PRIVATE FUNCTIONS **********************************************************/
59 * Internal NLS related stuff initialization.
66 UNICODE_STRING DirName
;
67 OBJECT_ATTRIBUTES ObjectAttributes
;
70 InitializeListHead(&CodePageListHead
);
71 RtlInitializeCriticalSection(&CodePageListLock
);
74 * FIXME: Eventually this should be done only for the NLS Server
75 * process, but since we don't have anything like that (yet?) we
76 * always try to create the "\Nls" directory here.
78 RtlInitUnicodeString(&DirName
, L
"\\Nls");
80 InitializeObjectAttributes(&ObjectAttributes
,
82 OBJ_CASE_INSENSITIVE
| OBJ_PERMANENT
,
86 if (NT_SUCCESS(NtCreateDirectoryObject(&Handle
, DIRECTORY_ALL_ACCESS
, &ObjectAttributes
)))
91 /* Setup ANSI code page. */
92 AnsiCodePage
.SectionHandle
= NULL
;
93 AnsiCodePage
.SectionMapping
= NtCurrentTeb()->ProcessEnvironmentBlock
->AnsiCodePageData
;
95 RtlInitCodePageTable((PUSHORT
)AnsiCodePage
.SectionMapping
,
96 &AnsiCodePage
.CodePageTable
);
97 AnsiCodePage
.CodePage
= AnsiCodePage
.CodePageTable
.CodePage
;
99 InsertTailList(&CodePageListHead
, &AnsiCodePage
.Entry
);
101 /* Setup OEM code page. */
102 OemCodePage
.SectionHandle
= NULL
;
103 OemCodePage
.SectionMapping
= NtCurrentTeb()->ProcessEnvironmentBlock
->OemCodePageData
;
105 RtlInitCodePageTable((PUSHORT
)OemCodePage
.SectionMapping
,
106 &OemCodePage
.CodePageTable
);
107 OemCodePage
.CodePage
= OemCodePage
.CodePageTable
.CodePage
;
108 InsertTailList(&CodePageListHead
, &OemCodePage
.Entry
);
116 * Internal NLS related stuff uninitialization.
123 PCODEPAGE_ENTRY Current
;
125 /* Delete the code page list. */
126 while (!IsListEmpty(&CodePageListHead
))
128 Current
= CONTAINING_RECORD(CodePageListHead
.Flink
, CODEPAGE_ENTRY
, Entry
);
129 if (Current
->SectionHandle
!= NULL
)
131 UnmapViewOfFile(Current
->SectionMapping
);
132 NtClose(Current
->SectionHandle
);
134 RemoveHeadList(&CodePageListHead
);
136 RtlDeleteCriticalSection(&CodePageListLock
);
140 * @name IntGetLoadedCodePageEntry
142 * Internal function to get structure containing a code page information
143 * of code page that is already loaded.
146 * Number of the code page. Special values like CP_OEMCP, CP_ACP
147 * or CP_UTF8 aren't allowed.
149 * @return Code page entry or NULL if the specified code page hasn't
155 IntGetLoadedCodePageEntry(UINT CodePage
)
157 LIST_ENTRY
*CurrentEntry
;
158 PCODEPAGE_ENTRY Current
;
160 RtlEnterCriticalSection(&CodePageListLock
);
161 for (CurrentEntry
= CodePageListHead
.Flink
;
162 CurrentEntry
!= &CodePageListHead
;
163 CurrentEntry
= CurrentEntry
->Flink
)
165 Current
= CONTAINING_RECORD(CurrentEntry
, CODEPAGE_ENTRY
, Entry
);
166 if (Current
->CodePage
== CodePage
)
168 RtlLeaveCriticalSection(&CodePageListLock
);
172 RtlLeaveCriticalSection(&CodePageListLock
);
178 * @name IntGetCodePageEntry
180 * Internal function to get structure containing a code page information.
183 * Number of the code page. Special values like CP_OEMCP, CP_ACP
184 * or CP_THREAD_ACP are allowed, but CP_UTF[7/8] isn't.
186 * @return Code page entry.
191 IntGetCodePageEntry(UINT CodePage
)
193 CHAR SectionName
[40];
195 HANDLE SectionHandle
= INVALID_HANDLE_VALUE
, FileHandle
;
196 PBYTE SectionMapping
;
197 OBJECT_ATTRIBUTES ObjectAttributes
;
198 ANSI_STRING AnsiName
;
199 UNICODE_STRING UnicodeName
;
200 WCHAR FileName
[MAX_PATH
+ 1];
202 PCODEPAGE_ENTRY CodePageEntry
;
203 if (CodePage
== CP_ACP
)
205 return &AnsiCodePage
;
207 else if (CodePage
== CP_OEMCP
)
211 else if (CodePage
== CP_THREAD_ACP
)
213 if (!GetLocaleInfoW(GetThreadLocale(),
214 LOCALE_IDEFAULTANSICODEPAGE
| LOCALE_RETURN_NUMBER
,
216 sizeof(CodePage
) / sizeof(WCHAR
)))
218 /* Last error is set by GetLocaleInfoW. */
222 else if (CodePage
== CP_MACCP
)
224 if (!GetLocaleInfoW(LOCALE_SYSTEM_DEFAULT
,
225 LOCALE_IDEFAULTMACCODEPAGE
| LOCALE_RETURN_NUMBER
,
227 sizeof(CodePage
) / sizeof(WCHAR
)))
229 /* Last error is set by GetLocaleInfoW. */
234 /* Try searching for loaded page first. */
235 CodePageEntry
= IntGetLoadedCodePageEntry(CodePage
);
236 if (CodePageEntry
!= NULL
)
238 return CodePageEntry
;
242 * Yes, we really want to lock here. Otherwise it can happen that
243 * two parallel requests will try to get the entry for the same
244 * code page and we would load it twice.
246 RtlEnterCriticalSection(&CodePageListLock
);
248 /* Generate the section name. */
249 if (!GetNlsSectionName(CodePage
,
252 "\\Nls\\NlsSectionCP",
254 sizeof(SectionName
)))
256 RtlLeaveCriticalSection(&CodePageListLock
);
260 RtlInitAnsiString(&AnsiName
, SectionName
);
261 RtlAnsiStringToUnicodeString(&UnicodeName
, &AnsiName
, TRUE
);
263 InitializeObjectAttributes(&ObjectAttributes
, &UnicodeName
, 0, NULL
, NULL
);
265 /* Try to open the section first */
266 Status
= NtOpenSection(&SectionHandle
, SECTION_MAP_READ
, &ObjectAttributes
);
268 /* If the section doesn't exist, try to create it. */
269 if (Status
== STATUS_UNSUCCESSFUL
||
270 Status
== STATUS_OBJECT_NAME_NOT_FOUND
||
271 Status
== STATUS_OBJECT_PATH_NOT_FOUND
)
273 FileNamePos
= GetSystemDirectoryW(FileName
, MAX_PATH
);
274 if (GetCPFileNameFromRegistry(CodePage
,
275 FileName
+ FileNamePos
+ 1,
276 MAX_PATH
- FileNamePos
- 1))
278 FileName
[FileNamePos
] = L
'\\';
279 FileName
[MAX_PATH
] = 0;
280 FileHandle
= CreateFileW(FileName
,
288 Status
= NtCreateSection(&SectionHandle
,
296 /* HACK: Check if another process was faster
297 * and already created this section. See bug 3626 for details */
298 if (Status
== STATUS_OBJECT_NAME_COLLISION
)
300 /* Close the file then */
303 /* And open the section */
304 Status
= NtOpenSection(&SectionHandle
,
310 RtlFreeUnicodeString(&UnicodeName
);
312 if (!NT_SUCCESS(Status
))
314 RtlLeaveCriticalSection(&CodePageListLock
);
318 SectionMapping
= MapViewOfFile(SectionHandle
, FILE_MAP_READ
, 0, 0, 0);
319 if (SectionMapping
== NULL
)
321 NtClose(SectionHandle
);
322 RtlLeaveCriticalSection(&CodePageListLock
);
326 CodePageEntry
= HeapAlloc(GetProcessHeap(), 0, sizeof(CODEPAGE_ENTRY
));
327 if (CodePageEntry
== NULL
)
329 NtClose(SectionHandle
);
330 RtlLeaveCriticalSection(&CodePageListLock
);
334 CodePageEntry
->CodePage
= CodePage
;
335 CodePageEntry
->SectionHandle
= SectionHandle
;
336 CodePageEntry
->SectionMapping
= SectionMapping
;
338 RtlInitCodePageTable((PUSHORT
)SectionMapping
, &CodePageEntry
->CodePageTable
);
340 /* Insert the new entry to list and unlock. Uff. */
341 InsertTailList(&CodePageListHead
, &CodePageEntry
->Entry
);
342 RtlLeaveCriticalSection(&CodePageListLock
);
344 return CodePageEntry
;
348 * @name IntMultiByteToWideCharUTF8
350 * Internal version of MultiByteToWideChar for UTF8.
352 * @see MultiByteToWideChar
353 * @todo Add UTF8 validity checks.
359 IntMultiByteToWideCharUTF8(DWORD Flags
,
360 LPCSTR MultiByteString
,
362 LPWSTR WideCharString
,
370 if (Flags
!= 0 && Flags
!= MB_ERR_INVALID_CHARS
)
372 SetLastError(ERROR_INVALID_FLAGS
);
376 /* Does caller query for output buffer size? */
377 if (WideCharCount
== 0)
379 MbsEnd
= MultiByteString
+ MultiByteCount
;
380 for (; MultiByteString
< MbsEnd
; WideCharCount
++)
382 Char
= *MultiByteString
++;
385 MultiByteString
+= UTF8Length
[Char
- 0x80];
387 return WideCharCount
;
390 MbsEnd
= MultiByteString
+ MultiByteCount
;
391 for (Count
= 0; Count
< WideCharCount
&& MultiByteString
< MbsEnd
; Count
++)
393 Char
= *MultiByteString
++;
396 *WideCharString
++ = Char
;
399 Length
= UTF8Length
[Char
- 0x80];
400 WideChar
= Char
& UTF8Mask
[Length
];
401 while (Length
&& MultiByteString
< MbsEnd
)
403 WideChar
= (WideChar
<< 6) | (*MultiByteString
++ & 0x7f);
406 *WideCharString
++ = WideChar
;
409 if (MultiByteString
< MbsEnd
)
410 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
416 * @name IntMultiByteToWideCharCP
418 * Internal version of MultiByteToWideChar for code page tables.
420 * @see MultiByteToWideChar
421 * @todo Handle MB_PRECOMPOSED, MB_COMPOSITE, MB_USEGLYPHCHARS and
428 IntMultiByteToWideCharCP(UINT CodePage
,
430 LPCSTR MultiByteString
,
432 LPWSTR WideCharString
,
435 PCODEPAGE_ENTRY CodePageEntry
;
436 PCPTABLEINFO CodePageTable
;
440 /* Get code page table. */
441 CodePageEntry
= IntGetCodePageEntry(CodePage
);
442 if (CodePageEntry
== NULL
)
444 SetLastError(ERROR_INVALID_PARAMETER
);
447 CodePageTable
= &CodePageEntry
->CodePageTable
;
449 /* Different handling for DBCS code pages. */
450 if (CodePageTable
->MaximumCharacterSize
> 1)
456 LPCSTR MbsEnd
= MultiByteString
+ MultiByteCount
;
459 /* Does caller query for output buffer size? */
460 if (WideCharCount
== 0)
462 for (; MultiByteString
< MbsEnd
; WideCharCount
++)
464 Char
= *MultiByteString
++;
469 DBCSOffset
= CodePageTable
->DBCSOffsets
[Char
];
474 if (MultiByteString
< MbsEnd
)
478 return WideCharCount
;
481 for (Count
= 0; Count
< WideCharCount
&& MultiByteString
< MbsEnd
; Count
++)
483 Char
= *MultiByteString
++;
487 *WideCharString
++ = Char
;
491 DBCSOffset
= CodePageTable
->DBCSOffsets
[Char
];
495 *WideCharString
++ = CodePageTable
->MultiByteTable
[Char
];
499 if (MultiByteString
< MbsEnd
)
500 *WideCharString
++ = CodePageTable
->DBCSOffsets
[DBCSOffset
+ *(PUCHAR
)MultiByteString
++];
503 if (MultiByteString
< MbsEnd
)
505 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
511 else /* Not DBCS code page */
513 /* Check for invalid characters. */
514 if (Flags
& MB_ERR_INVALID_CHARS
)
516 for (TempString
= MultiByteString
, TempLength
= MultiByteCount
;
518 TempString
++, TempLength
--)
520 if (CodePageTable
->MultiByteTable
[(UCHAR
)*TempString
] ==
521 CodePageTable
->UniDefaultChar
&&
522 *TempString
!= CodePageEntry
->CodePageTable
.DefaultChar
)
524 SetLastError(ERROR_NO_UNICODE_TRANSLATION
);
530 /* Does caller query for output buffer size? */
531 if (WideCharCount
== 0)
532 return MultiByteCount
;
534 /* Fill the WideCharString buffer with what will fit: Verified on WinXP */
535 for (TempLength
= (WideCharCount
< MultiByteCount
) ? WideCharCount
: MultiByteCount
;
537 MultiByteString
++, TempLength
--)
539 *WideCharString
++ = CodePageTable
->MultiByteTable
[(UCHAR
)*MultiByteString
];
542 /* Adjust buffer size. Wine trick ;-) */
543 if (WideCharCount
< MultiByteCount
)
545 MultiByteCount
= WideCharCount
;
546 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
549 return MultiByteCount
;
554 * @name IntMultiByteToWideCharSYMBOL
556 * Internal version of MultiByteToWideChar for SYMBOL.
558 * @see MultiByteToWideChar
564 IntMultiByteToWideCharSYMBOL(DWORD Flags
,
565 LPCSTR MultiByteString
,
567 LPWSTR WideCharString
,
577 SetLastError(ERROR_INVALID_FLAGS
);
581 if (WideCharCount
== 0)
583 return MultiByteCount
;
586 WideCharMaxLen
= WideCharCount
> MultiByteCount
? MultiByteCount
: WideCharCount
;
588 for (Count
= 0; Count
< WideCharMaxLen
; Count
++)
590 Char
= MultiByteString
[Count
];
593 WideCharString
[Count
] = Char
;
597 WideCharString
[Count
] = Char
+ 0xf000;
600 if (MultiByteCount
> WideCharMaxLen
)
602 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
606 return WideCharMaxLen
;
610 * @name IntWideCharToMultiByteSYMBOL
612 * Internal version of WideCharToMultiByte for SYMBOL.
614 * @see WideCharToMultiByte
619 IntWideCharToMultiByteSYMBOL(DWORD Flags
,
620 LPCWSTR WideCharString
,
622 LPSTR MultiByteString
,
631 SetLastError(ERROR_INVALID_PARAMETER
);
636 if (MultiByteCount
== 0)
638 return WideCharCount
;
641 MaxLen
= MultiByteCount
> WideCharCount
? WideCharCount
: MultiByteCount
;
642 for (Count
= 0; Count
< MaxLen
; Count
++)
644 Char
= WideCharString
[Count
];
647 MultiByteString
[Count
] = (CHAR
)Char
;
651 if ((Char
>= 0xf020) && (Char
< 0xf100))
653 MultiByteString
[Count
] = Char
- 0xf000;
657 SetLastError(ERROR_NO_UNICODE_TRANSLATION
);
663 if (WideCharCount
> MaxLen
)
665 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
672 * @name IntWideCharToMultiByteUTF8
674 * Internal version of WideCharToMultiByte for UTF8.
676 * @see WideCharToMultiByte
681 IntWideCharToMultiByteUTF8(UINT CodePage
,
683 LPCWSTR WideCharString
,
685 LPSTR MultiByteString
,
688 LPBOOL UsedDefaultChar
)
693 /* Does caller query for output buffer size? */
694 if (MultiByteCount
== 0)
696 for (TempLength
= 0; WideCharCount
;
697 WideCharCount
--, WideCharString
++)
700 if (*WideCharString
>= 0x80)
703 if (*WideCharString
>= 0x800)
710 for (TempLength
= MultiByteCount
; WideCharCount
; WideCharCount
--, WideCharString
++)
712 Char
= *WideCharString
;
717 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
721 *MultiByteString
++ = (CHAR
)Char
;
725 if (Char
< 0x800) /* 0x80-0x7ff: 2 bytes */
729 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
732 MultiByteString
[1] = 0x80 | (Char
& 0x3f); Char
>>= 6;
733 MultiByteString
[0] = 0xc0 | Char
;
734 MultiByteString
+= 2;
739 /* 0x800-0xffff: 3 bytes */
742 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
745 MultiByteString
[2] = 0x80 | (Char
& 0x3f); Char
>>= 6;
746 MultiByteString
[1] = 0x80 | (Char
& 0x3f); Char
>>= 6;
747 MultiByteString
[0] = 0xe0 | Char
;
748 MultiByteString
+= 3;
752 return MultiByteCount
- TempLength
;
756 * @name IsValidSBCSMapping
758 * Checks if ch (single-byte character) is a valid mapping for wch
760 * @see IntWideCharToMultiByteCP
765 IntIsValidSBCSMapping(PCPTABLEINFO CodePageTable
, DWORD Flags
, WCHAR wch
, UCHAR ch
)
767 /* If the WC_NO_BEST_FIT_CHARS flag has been specified, the characters need to match exactly. */
768 if (Flags
& WC_NO_BEST_FIT_CHARS
)
769 return (CodePageTable
->MultiByteTable
[ch
] == wch
);
771 /* By default, all characters except TransDefaultChar apply as a valid mapping
772 for ch (so also "nearest" characters) */
773 if (ch
!= CodePageTable
->TransDefaultChar
)
776 /* The only possible left valid mapping is the default character itself */
777 return (wch
== CodePageTable
->TransUniDefaultChar
);
781 * @name IsValidDBCSMapping
783 * Checks if ch (double-byte character) is a valid mapping for wch
785 * @see IntWideCharToMultiByteCP
788 IntIsValidDBCSMapping(PCPTABLEINFO CodePageTable
, DWORD Flags
, WCHAR wch
, USHORT ch
)
790 /* If ch is the default character, but the wch is not, it can't be a valid mapping */
791 if (ch
== CodePageTable
->TransDefaultChar
&& wch
!= CodePageTable
->TransUniDefaultChar
)
794 /* If the WC_NO_BEST_FIT_CHARS flag has been specified, the characters need to match exactly. */
795 if (Flags
& WC_NO_BEST_FIT_CHARS
)
799 USHORT uOffset
= CodePageTable
->DBCSOffsets
[ch
>> 8];
800 /* if (!uOffset) return (CodePageTable->MultiByteTable[ch] == wch); */
801 return (CodePageTable
->DBCSOffsets
[uOffset
+ (ch
& 0xff)] == wch
);
804 return (CodePageTable
->MultiByteTable
[ch
] == wch
);
807 /* If we're still here, we have a valid mapping */
812 * @name IntWideCharToMultiByteCP
814 * Internal version of WideCharToMultiByte for code page tables.
816 * @see WideCharToMultiByte
817 * @todo Handle WC_COMPOSITECHECK
822 IntWideCharToMultiByteCP(UINT CodePage
,
824 LPCWSTR WideCharString
,
826 LPSTR MultiByteString
,
829 LPBOOL UsedDefaultChar
)
831 PCODEPAGE_ENTRY CodePageEntry
;
832 PCPTABLEINFO CodePageTable
;
835 /* Get code page table. */
836 CodePageEntry
= IntGetCodePageEntry(CodePage
);
837 if (CodePageEntry
== NULL
)
839 SetLastError(ERROR_INVALID_PARAMETER
);
842 CodePageTable
= &CodePageEntry
->CodePageTable
;
845 /* Different handling for DBCS code pages. */
846 if (CodePageTable
->MaximumCharacterSize
> 1)
848 /* If Flags, DefaultChar or UsedDefaultChar were given, we have to do some more work */
849 if(Flags
|| DefaultChar
|| UsedDefaultChar
)
851 BOOL TempUsedDefaultChar
;
854 /* If UsedDefaultChar is not set, set it to a temporary value, so we don't have
855 to check on every character */
857 UsedDefaultChar
= &TempUsedDefaultChar
;
859 *UsedDefaultChar
= FALSE
;
861 /* Use the CodePage's TransDefaultChar if none was given. Don't modify the DefaultChar pointer here. */
863 DefChar
= DefaultChar
[1] ? ((DefaultChar
[0] << 8) | DefaultChar
[1]) : DefaultChar
[0];
865 DefChar
= CodePageTable
->TransDefaultChar
;
867 /* Does caller query for output buffer size? */
870 for(TempLength
= 0; WideCharCount
; WideCharCount
--, WideCharString
++, TempLength
++)
874 if ((Flags
& WC_COMPOSITECHECK
) && WideCharCount
> 1)
876 /* FIXME: Handle WC_COMPOSITECHECK */
879 uChar
= ((PUSHORT
) CodePageTable
->WideCharTable
)[*WideCharString
];
881 /* Verify if the mapping is valid for handling DefaultChar and UsedDefaultChar */
882 if (!IntIsValidDBCSMapping(CodePageTable
, Flags
, *WideCharString
, uChar
))
885 *UsedDefaultChar
= TRUE
;
888 /* Increment TempLength again if this is a double-byte character */
896 /* Convert the WideCharString to the MultiByteString and verify if the mapping is valid */
897 for(TempLength
= MultiByteCount
;
898 WideCharCount
&& TempLength
;
899 TempLength
--, WideCharString
++, WideCharCount
--)
903 if ((Flags
& WC_COMPOSITECHECK
) && WideCharCount
> 1)
905 /* FIXME: Handle WC_COMPOSITECHECK */
908 uChar
= ((PUSHORT
)CodePageTable
->WideCharTable
)[*WideCharString
];
910 /* Verify if the mapping is valid for handling DefaultChar and UsedDefaultChar */
911 if (!IntIsValidDBCSMapping(CodePageTable
, Flags
, *WideCharString
, uChar
))
914 *UsedDefaultChar
= TRUE
;
917 /* Handle double-byte characters */
920 /* Don't output a partial character */
925 *MultiByteString
++ = uChar
>> 8;
928 *MultiByteString
++ = (char)uChar
;
931 /* WideCharCount should be 0 if all characters were converted */
934 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
938 return MultiByteCount
- TempLength
;
941 /* Does caller query for output buffer size? */
944 for (TempLength
= 0; WideCharCount
; WideCharCount
--, WideCharString
++, TempLength
++)
946 /* Increment TempLength again if this is a double-byte character */
947 if (((PWCHAR
)CodePageTable
->WideCharTable
)[*WideCharString
] & 0xff00)
954 /* Convert the WideCharString to the MultiByteString */
955 for (TempLength
= MultiByteCount
;
956 WideCharCount
&& TempLength
;
957 TempLength
--, WideCharString
++, WideCharCount
--)
959 USHORT uChar
= ((PUSHORT
) CodePageTable
->WideCharTable
)[*WideCharString
];
961 /* Is this a double-byte character? */
964 /* Don't output a partial character */
969 *MultiByteString
++ = uChar
>> 8;
972 *MultiByteString
++ = (char)uChar
;
975 /* WideCharCount should be 0 if all characters were converted */
978 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
982 return MultiByteCount
- TempLength
;
984 else /* Not DBCS code page */
988 /* If Flags, DefaultChar or UsedDefaultChar were given, we have to do some more work */
989 if (Flags
|| DefaultChar
|| UsedDefaultChar
)
991 BOOL TempUsedDefaultChar
;
994 /* If UsedDefaultChar is not set, set it to a temporary value, so we don't have
995 to check on every character */
996 if (!UsedDefaultChar
)
997 UsedDefaultChar
= &TempUsedDefaultChar
;
999 *UsedDefaultChar
= FALSE
;
1001 /* Does caller query for output buffer size? */
1002 if (!MultiByteCount
)
1004 /* Loop through the whole WideCharString and check if we can get a valid mapping for each character */
1005 for (TempLength
= 0; WideCharCount
; TempLength
++, WideCharString
++, WideCharCount
--)
1007 if ((Flags
& WC_COMPOSITECHECK
) && WideCharCount
> 1)
1009 /* FIXME: Handle WC_COMPOSITECHECK */
1012 if (!*UsedDefaultChar
)
1013 *UsedDefaultChar
= !IntIsValidSBCSMapping(CodePageTable
,
1016 ((PCHAR
)CodePageTable
->WideCharTable
)[*WideCharString
]);
1022 /* Use the CodePage's TransDefaultChar if none was given. Don't modify the DefaultChar pointer here. */
1024 DefChar
= *DefaultChar
;
1026 DefChar
= (CHAR
)CodePageTable
->TransDefaultChar
;
1028 /* Convert the WideCharString to the MultiByteString and verify if the mapping is valid */
1029 for (TempLength
= MultiByteCount
;
1030 WideCharCount
&& TempLength
;
1031 MultiByteString
++, TempLength
--, WideCharString
++, WideCharCount
--)
1033 if ((Flags
& WC_COMPOSITECHECK
) && WideCharCount
> 1)
1035 /* FIXME: Handle WC_COMPOSITECHECK */
1038 *MultiByteString
= ((PCHAR
)CodePageTable
->WideCharTable
)[*WideCharString
];
1040 if (!IntIsValidSBCSMapping(CodePageTable
, Flags
, *WideCharString
, *MultiByteString
))
1042 *MultiByteString
= DefChar
;
1043 *UsedDefaultChar
= TRUE
;
1047 /* WideCharCount should be 0 if all characters were converted */
1050 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
1054 return MultiByteCount
- TempLength
;
1057 /* Does caller query for output buffer size? */
1058 if (!MultiByteCount
)
1059 return WideCharCount
;
1061 /* Is the buffer large enough? */
1062 if (MultiByteCount
< WideCharCount
)
1064 /* Convert the string up to MultiByteCount and return 0 */
1065 WideCharCount
= MultiByteCount
;
1066 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
1071 /* Otherwise WideCharCount will be the number of converted characters */
1072 nReturn
= WideCharCount
;
1075 /* Convert the WideCharString to the MultiByteString */
1076 for (TempLength
= WideCharCount
; --TempLength
>= 0; WideCharString
++, MultiByteString
++)
1078 *MultiByteString
= ((PCHAR
)CodePageTable
->WideCharTable
)[*WideCharString
];
1086 * @name IntIsLeadByte
1088 * Internal function to detect if byte is lead byte in specific character
1094 IntIsLeadByte(PCPTABLEINFO TableInfo
, BYTE Byte
)
1098 if (TableInfo
->MaximumCharacterSize
== 2)
1100 for (i
= 0; i
< MAXIMUM_LEADBYTES
&& TableInfo
->LeadByte
[i
]; i
+= 2)
1102 if (Byte
>= TableInfo
->LeadByte
[i
] && Byte
<= TableInfo
->LeadByte
[i
+1])
1110 /* PUBLIC FUNCTIONS ***********************************************************/
1113 * @name GetNlsSectionName
1115 * Construct a name of NLS section.
1120 * Integer base used for converting to string. Usually set to 10.
1122 * As the name suggests the meaning of this parameter is unknown.
1123 * The native version of Kernel32 passes it as the third parameter
1124 * to NlsConvertIntegerToString function, which is used for the
1125 * actual conversion of the code page number.
1127 * Base name of the section. (ex. "\\Nls\\NlsSectionCP")
1129 * Buffer that will hold the constructed name.
1131 * Size of the buffer for the result.
1133 * @return TRUE if the buffer was large enough and was filled with
1134 * the requested information, FALSE otherwise.
1141 GetNlsSectionName(UINT CodePage
,
1150 if (!NT_SUCCESS(RtlIntegerToChar(CodePage
, Base
, sizeof(Integer
), Integer
)))
1154 * If the name including the terminating NULL character doesn't
1155 * fit in the output buffer then fail.
1157 if (strlen(Integer
) + strlen(BaseName
) >= ResultSize
)
1160 lstrcpyA(Result
, BaseName
);
1161 lstrcatA(Result
, Integer
);
1167 * @name GetCPFileNameFromRegistry
1169 * Get file name of code page definition file.
1172 * Code page number to get file name of.
1174 * Buffer that is filled with file name of successful return. Can
1176 * @param FileNameSize
1177 * Size of the buffer to hold file name in WCHARs.
1179 * @return TRUE if the file name was retrieved, FALSE otherwise.
1186 GetCPFileNameFromRegistry(UINT CodePage
, LPWSTR FileName
, ULONG FileNameSize
)
1188 WCHAR ValueNameBuffer
[11];
1189 UNICODE_STRING KeyName
, ValueName
;
1190 OBJECT_ATTRIBUTES ObjectAttributes
;
1193 PKEY_VALUE_PARTIAL_INFORMATION Kvpi
;
1199 /* Convert the codepage number to string. */
1200 ValueName
.Buffer
= ValueNameBuffer
;
1201 ValueName
.MaximumLength
= sizeof(ValueNameBuffer
);
1203 if (!NT_SUCCESS(RtlIntegerToUnicodeString(CodePage
, 10, &ValueName
)))
1206 /* Open the registry key containing file name mappings. */
1207 RtlInitUnicodeString(&KeyName
, L
"\\Registry\\Machine\\System\\"
1208 L
"CurrentControlSet\\Control\\Nls\\CodePage");
1209 InitializeObjectAttributes(&ObjectAttributes
, &KeyName
, OBJ_CASE_INSENSITIVE
,
1211 Status
= NtOpenKey(&KeyHandle
, KEY_READ
, &ObjectAttributes
);
1212 if (!NT_SUCCESS(Status
))
1217 /* Allocate buffer that will be used to query the value data. */
1218 KvpiSize
= sizeof(KEY_VALUE_PARTIAL_INFORMATION
) + (MAX_PATH
* sizeof(WCHAR
));
1219 Kvpi
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, KvpiSize
);
1226 /* Query the file name for our code page. */
1227 Status
= NtQueryValueKey(KeyHandle
, &ValueName
, KeyValuePartialInformation
,
1228 Kvpi
, KvpiSize
, &KvpiSize
);
1232 /* Check if we succeded and the value is non-empty string. */
1233 if (NT_SUCCESS(Status
) && Kvpi
->Type
== REG_SZ
&&
1234 Kvpi
->DataLength
> sizeof(WCHAR
))
1237 if (FileName
!= NULL
)
1239 lstrcpynW(FileName
, (WCHAR
*)Kvpi
->Data
,
1240 min(Kvpi
->DataLength
/ sizeof(WCHAR
), FileNameSize
));
1244 /* free temporary buffer */
1245 HeapFree(GetProcessHeap(),0,Kvpi
);
1250 * @name IsValidCodePage
1252 * Detect if specified code page is valid and present in the system.
1255 * Code page number to query.
1257 * @return TRUE if code page is present.
1262 IsValidCodePage(UINT CodePage
)
1264 if (CodePage
== 0) return FALSE
;
1265 if (CodePage
== CP_UTF8
|| CodePage
== CP_UTF7
)
1267 if (IntGetLoadedCodePageEntry(CodePage
))
1269 return GetCPFileNameFromRegistry(CodePage
, NULL
, 0);
1272 static const signed char
1275 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
1276 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
1277 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 62, -1, -1, -1, 63,
1278 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, -1, -1, -1, -1, -1, -1,
1279 -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14,
1280 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, -1, -1, -1, -1, -1,
1281 -1, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40,
1282 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, -1, -1, -1, -1, -1
1285 static VOID
Utf7Base64Decode(BYTE
*pbDest
, LPCSTR pszSrc
, INT cchSrc
)
1290 for(i
= 0; i
< cchSrc
/ 4 * 4; i
+= 4)
1292 for(j
= n
= 0; j
< 4; )
1294 b
= (BYTE
) base64inv
[(BYTE
) *pszSrc
++];
1295 n
|= (((INT
) b
) << ((3 - j
) * 6));
1298 for(j
= 0; j
< 3; j
++)
1299 *pbDest
++ = (BYTE
) ((n
>> (8 * (2 - j
))) & 0xFF);
1301 for(j
= n
= 0; j
< cchSrc
% 4; )
1303 b
= (BYTE
) base64inv
[(BYTE
) *pszSrc
++];
1304 n
|= (((INT
) b
) << ((3 - j
) * 6));
1307 for(j
= 0; j
< ((cchSrc
% 4) * 6 / 8); j
++)
1308 *pbDest
++ = (BYTE
) ((n
>> (8 * (2 - j
))) & 0xFF);
1311 static VOID
myswab(LPVOID pv
, INT cw
)
1313 LPBYTE pb
= (LPBYTE
) pv
;
1325 static INT
Utf7ToWideCharSize(LPCSTR pszUtf7
, INT cchUtf7
)
1347 while(cchUtf7
> 0 && (BYTE
) *pszUtf7
< 0x80 &&
1348 base64inv
[*pszUtf7
] >= 0)
1353 cch
= pszUtf7
- pch
;
1356 if (cchUtf7
> 0 && *pszUtf7
== '-')
1372 static INT
Utf7ToWideChar(LPCSTR pszUtf7
, INT cchUtf7
, LPWSTR pszWide
, INT cchWide
)
1379 c
= Utf7ToWideCharSize(pszUtf7
, cchUtf7
);
1385 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
1394 if (*pszUtf7
== '-')
1403 while(cchUtf7
> 0 && (BYTE
) *pszUtf7
< 0x80 &&
1404 base64inv
[*pszUtf7
] >= 0)
1409 cch
= pszUtf7
- pch
;
1411 pwsz
= (WORD
*) HeapAlloc(GetProcessHeap(), 0, (n
+ 1) * sizeof(WORD
));
1414 ZeroMemory(pwsz
, n
* sizeof(WORD
));
1415 Utf7Base64Decode((BYTE
*) pwsz
, pch
, cch
);
1417 CopyMemory(pszWide
, pwsz
, n
* sizeof(WORD
));
1418 HeapFree(GetProcessHeap(), 0, pwsz
);
1420 if (cchUtf7
> 0 && *pszUtf7
== '-')
1428 *pszWide
++ = (WCHAR
) ch
;
1437 * @name MultiByteToWideChar
1439 * Convert a multi-byte string to wide-charater equivalent.
1442 * Code page to be used to perform the conversion. It can be also
1443 * one of the special values (CP_ACP for ANSI code page, CP_MACCP
1444 * for Macintosh code page, CP_OEMCP for OEM code page, CP_THREAD_ACP
1445 * for thread active code page, CP_UTF7 or CP_UTF8).
1447 * Additional conversion flags (MB_PRECOMPOSED, MB_COMPOSITE,
1448 * MB_ERR_INVALID_CHARS, MB_USEGLYPHCHARS).
1449 * @param MultiByteString
1451 * @param MultiByteCount
1452 * Size of MultiByteString, or -1 if MultiByteString is NULL
1454 * @param WideCharString
1456 * @param WideCharCount
1457 * Size in WCHARs of WideCharString, or 0 if the caller just wants
1458 * to know how large WideCharString should be for a successful
1461 * @return Zero on error, otherwise the number of WCHARs written
1462 * in the WideCharString buffer.
1469 MultiByteToWideChar(UINT CodePage
,
1471 LPCSTR MultiByteString
,
1473 LPWSTR WideCharString
,
1476 /* Check the parameters. */
1477 if (MultiByteString
== NULL
||
1478 MultiByteCount
== 0 ||
1479 (WideCharString
== NULL
&& WideCharCount
> 0) ||
1480 (PVOID
)MultiByteString
== (PVOID
)WideCharString
)
1482 SetLastError(ERROR_INVALID_PARAMETER
);
1486 /* Determine the input string length. */
1487 if (MultiByteCount
< 0)
1489 MultiByteCount
= lstrlenA(MultiByteString
) + 1;
1495 return IntMultiByteToWideCharUTF8(Flags
,
1504 SetLastError(ERROR_INVALID_FLAGS
);
1507 return Utf7ToWideChar(MultiByteString
, MultiByteCount
,
1508 WideCharString
, WideCharCount
);
1511 return IntMultiByteToWideCharSYMBOL(Flags
,
1517 return IntMultiByteToWideCharCP(CodePage
,
1526 static const char mustshift
[] =
1528 0, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 1, 1, 0, 1, 1,
1529 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1530 0, 1, 1, 1, 1, 1, 1, 0, 0, 0, 1, 1, 0, 0, 0, 0,
1531 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0,
1532 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
1533 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1,
1534 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
1535 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1
1538 static const char base64
[] =
1539 "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
1541 static INT
WideCharToUtf7Size(LPCWSTR pszWide
, INT cchWide
)
1545 BOOL fShift
= FALSE
;
1550 if (wch
< 0x80 && !mustshift
[wch
])
1574 if (cchWide
> 0 && (*pszWide
>= 0x80 || mustshift
[*pszWide
]))
1579 if (cchWide
> 0 && (*pszWide
>= 0x80 || mustshift
[*pszWide
]))
1586 if (cchWide
> 0 && *pszWide
< 0x80 && !mustshift
[*pszWide
])
1599 static INT
WideCharToUtf7(LPCWSTR pszWide
, INT cchWide
, LPSTR pszUtf7
, INT cchUtf7
)
1604 BOOL fShift
= FALSE
;
1606 c
= WideCharToUtf7Size(pszWide
, cchWide
);
1612 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
1619 if (wch
< 0x80 && !mustshift
[wch
])
1621 *pszUtf7
++ = (CHAR
) wch
;
1640 wsz
[0] = *pszWide
++;
1643 if (cchWide
> 0 && (*pszWide
>= 0x80 || mustshift
[*pszWide
]))
1645 wsz
[1] = *pszWide
++;
1648 if (cchWide
> 0 && (*pszWide
>= 0x80 || mustshift
[*pszWide
]))
1650 wsz
[2] = *pszWide
++;
1655 *pszUtf7
++ = base64
[wsz
[0] >> 10];
1656 *pszUtf7
++ = base64
[(wsz
[0] >> 4) & 0x3F];
1657 *pszUtf7
++ = base64
[(wsz
[0] << 2 | wsz
[1] >> 14) & 0x3F];
1660 *pszUtf7
++ = base64
[(wsz
[1] >> 8) & 0x3F];
1661 *pszUtf7
++ = base64
[(wsz
[1] >> 2) & 0x3F];
1662 *pszUtf7
++ = base64
[(wsz
[1] << 4 | wsz
[2] >> 12) & 0x3F];
1665 *pszUtf7
++ = base64
[(wsz
[2] >> 6) & 0x3F];
1666 *pszUtf7
++ = base64
[wsz
[2] & 0x3F];
1669 if (cchWide
> 0 && *pszWide
< 0x80 && !mustshift
[*pszWide
])
1683 GetLocalisedText(DWORD dwResId
, WCHAR
*lpszDest
, DWORD dwDestSize
)
1691 dwId
= dwResId
* 100;
1695 lcid
= GetUserDefaultLCID();
1696 lcid
= ConvertDefaultLocale(lcid
);
1698 langId
= LANGIDFROMLCID(lcid
);
1700 if (PRIMARYLANGID(langId
) == LANG_NEUTRAL
)
1701 langId
= MAKELANGID(LANG_ENGLISH
, SUBLANG_ENGLISH_US
);
1703 hrsrc
= FindResourceExW(hCurrentModule
,
1705 MAKEINTRESOURCEW((dwId
>> 4) + 1),
1708 /* english fallback */
1711 hrsrc
= FindResourceExW(hCurrentModule
,
1713 MAKEINTRESOURCEW((dwId
>> 4) + 1),
1714 MAKELANGID(LANG_ENGLISH
, SUBLANG_ENGLISH_US
));
1719 HGLOBAL hmem
= LoadResource(hCurrentModule
, hrsrc
);
1727 p
= LockResource(hmem
);
1729 for (i
= 0; i
< (dwId
& 0x0f); i
++) p
+= *p
+ 1;
1734 len
= *p
* sizeof(WCHAR
);
1736 if(len
+ sizeof(WCHAR
) > dwDestSize
)
1738 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
1742 memcpy(lpszDest
, p
+ 1, len
);
1743 lpszDest
[*p
] = '\0';
1749 DPRINT1("Resource not found: dwResId = %lu\n", dwResId
);
1750 SetLastError(ERROR_INVALID_PARAMETER
);
1759 GetCPInfo(UINT CodePage
,
1760 LPCPINFO CodePageInfo
)
1762 PCODEPAGE_ENTRY CodePageEntry
;
1766 SetLastError(ERROR_INVALID_PARAMETER
);
1770 CodePageEntry
= IntGetCodePageEntry(CodePage
);
1771 if (CodePageEntry
== NULL
)
1777 CodePageInfo
->DefaultChar
[0] = 0x3f;
1778 CodePageInfo
->DefaultChar
[1] = 0;
1779 CodePageInfo
->LeadByte
[0] = CodePageInfo
->LeadByte
[1] = 0;
1780 CodePageInfo
->MaxCharSize
= (CodePage
== CP_UTF7
) ? 5 : 4;
1784 DPRINT1("Invalid CP!: %lx\n", CodePage
);
1785 SetLastError( ERROR_INVALID_PARAMETER
);
1789 if (CodePageEntry
->CodePageTable
.DefaultChar
& 0xff00)
1791 CodePageInfo
->DefaultChar
[0] = (CodePageEntry
->CodePageTable
.DefaultChar
& 0xff00) >> 8;
1792 CodePageInfo
->DefaultChar
[1] = CodePageEntry
->CodePageTable
.DefaultChar
& 0x00ff;
1796 CodePageInfo
->DefaultChar
[0] = CodePageEntry
->CodePageTable
.DefaultChar
& 0xff;
1797 CodePageInfo
->DefaultChar
[1] = 0;
1800 if ((CodePageInfo
->MaxCharSize
= CodePageEntry
->CodePageTable
.MaximumCharacterSize
) == 2)
1801 memcpy(CodePageInfo
->LeadByte
, CodePageEntry
->CodePageTable
.LeadByte
, sizeof(CodePageInfo
->LeadByte
));
1803 CodePageInfo
->LeadByte
[0] = CodePageInfo
->LeadByte
[1] = 0;
1813 GetCPInfoExW(UINT CodePage
,
1815 LPCPINFOEXW lpCPInfoEx
)
1817 if (!GetCPInfo(CodePage
, (LPCPINFO
) lpCPInfoEx
))
1824 lpCPInfoEx
->CodePage
= CP_UTF7
;
1825 lpCPInfoEx
->UnicodeDefaultChar
= 0x3f;
1826 return GetLocalisedText((DWORD
)CodePage
, lpCPInfoEx
->CodePageName
, sizeof(lpCPInfoEx
->CodePageName
)) != 0;
1832 lpCPInfoEx
->CodePage
= CP_UTF8
;
1833 lpCPInfoEx
->UnicodeDefaultChar
= 0x3f;
1834 return GetLocalisedText((DWORD
)CodePage
, lpCPInfoEx
->CodePageName
, sizeof(lpCPInfoEx
->CodePageName
)) != 0;
1839 PCODEPAGE_ENTRY CodePageEntry
;
1841 CodePageEntry
= IntGetCodePageEntry(CodePage
);
1842 if (CodePageEntry
== NULL
)
1844 DPRINT1("Could not get CodePage Entry! CodePageEntry = 0\n");
1845 SetLastError(ERROR_INVALID_PARAMETER
);
1849 lpCPInfoEx
->CodePage
= CodePageEntry
->CodePageTable
.CodePage
;
1850 lpCPInfoEx
->UnicodeDefaultChar
= CodePageEntry
->CodePageTable
.UniDefaultChar
;
1851 return GetLocalisedText(CodePageEntry
->CodePageTable
.CodePage
, lpCPInfoEx
->CodePageName
, sizeof(lpCPInfoEx
->CodePageName
)) != 0;
1863 GetCPInfoExA(UINT CodePage
,
1865 LPCPINFOEXA lpCPInfoEx
)
1869 if (!GetCPInfoExW(CodePage
, dwFlags
, &CPInfo
))
1872 /* the layout is the same except for CodePageName */
1873 memcpy(lpCPInfoEx
, &CPInfo
, sizeof(CPINFOEXA
));
1875 WideCharToMultiByte(CP_ACP
,
1877 CPInfo
.CodePageName
,
1879 lpCPInfoEx
->CodePageName
,
1880 sizeof(lpCPInfoEx
->CodePageName
),
1887 * @name WideCharToMultiByte
1889 * Convert a wide-charater string to closest multi-byte equivalent.
1892 * Code page to be used to perform the conversion. It can be also
1893 * one of the special values (CP_ACP for ANSI code page, CP_MACCP
1894 * for Macintosh code page, CP_OEMCP for OEM code page, CP_THREAD_ACP
1895 * for thread active code page, CP_UTF7 or CP_UTF8).
1897 * Additional conversion flags (WC_NO_BEST_FIT_CHARS, WC_COMPOSITECHECK,
1898 * WC_DISCARDNS, WC_SEPCHARS, WC_DEFAULTCHAR).
1899 * @param WideCharString
1900 * Points to the wide-character string to be converted.
1901 * @param WideCharCount
1902 * Size in WCHARs of WideCharStr, or 0 if the caller just wants to
1903 * know how large WideCharString should be for a successful conversion.
1904 * @param MultiByteString
1905 * Points to the buffer to receive the translated string.
1906 * @param MultiByteCount
1907 * Specifies the size in bytes of the buffer pointed to by the
1908 * MultiByteString parameter. If this value is zero, the function
1909 * returns the number of bytes required for the buffer.
1910 * @param DefaultChar
1911 * Points to the character used if a wide character cannot be
1912 * represented in the specified code page. If this parameter is
1913 * NULL, a system default value is used.
1914 * @param UsedDefaultChar
1915 * Points to a flag that indicates whether a default character was
1916 * used. This parameter can be NULL.
1918 * @return Zero on error, otherwise the number of bytes written in the
1919 * MultiByteString buffer. Or the number of bytes needed for
1920 * the MultiByteString buffer if MultiByteCount is zero.
1927 WideCharToMultiByte(UINT CodePage
,
1929 LPCWSTR WideCharString
,
1931 LPSTR MultiByteString
,
1934 LPBOOL UsedDefaultChar
)
1936 /* Check the parameters. */
1937 if (WideCharString
== NULL
||
1938 WideCharCount
== 0 ||
1939 (MultiByteString
== NULL
&& MultiByteCount
> 0) ||
1940 (PVOID
)WideCharString
== (PVOID
)MultiByteString
||
1943 SetLastError(ERROR_INVALID_PARAMETER
);
1947 /* Determine the input string length. */
1948 if (WideCharCount
< 0)
1950 WideCharCount
= lstrlenW(WideCharString
) + 1;
1956 if (DefaultChar
!= NULL
|| UsedDefaultChar
!= NULL
)
1958 SetLastError(ERROR_INVALID_PARAMETER
);
1961 return IntWideCharToMultiByteUTF8(CodePage
,
1971 if (DefaultChar
!= NULL
|| UsedDefaultChar
!= NULL
)
1973 SetLastError(ERROR_INVALID_PARAMETER
);
1978 SetLastError(ERROR_INVALID_FLAGS
);
1981 return WideCharToUtf7(WideCharString
, WideCharCount
,
1982 MultiByteString
, MultiByteCount
);
1985 if ((DefaultChar
!=NULL
) || (UsedDefaultChar
!=NULL
))
1987 SetLastError(ERROR_INVALID_PARAMETER
);
1990 return IntWideCharToMultiByteSYMBOL(Flags
,
1997 return IntWideCharToMultiByteCP(CodePage
,
2011 * Get active ANSI code page number.
2020 return AnsiCodePage
.CodePageTable
.CodePage
;
2026 * Get active OEM code page number.
2035 return OemCodePage
.CodePageTable
.CodePage
;
2039 * @name IsDBCSLeadByteEx
2041 * Determine if passed byte is lead byte in specified code page.
2048 IsDBCSLeadByteEx(UINT CodePage
, BYTE TestByte
)
2050 PCODEPAGE_ENTRY CodePageEntry
;
2052 CodePageEntry
= IntGetCodePageEntry(CodePage
);
2053 if (CodePageEntry
!= NULL
)
2054 return IntIsLeadByte(&CodePageEntry
->CodePageTable
, TestByte
);
2056 SetLastError(ERROR_INVALID_PARAMETER
);
2061 * @name IsDBCSLeadByteEx
2063 * Determine if passed byte is lead byte in current ANSI code page.
2070 IsDBCSLeadByte(BYTE TestByte
)
2072 return IntIsLeadByte(&AnsiCodePage
.CodePageTable
, TestByte
);
2078 NTSTATUS WINAPI
CreateNlsSecurityDescriptor(PSECURITY_DESCRIPTOR SecurityDescriptor
,ULONG Size
,ULONG AccessMask
)
2087 BOOL WINAPI
IsValidUILanguage(LANGID langid
)
2096 VOID WINAPI
NlsConvertIntegerToString(ULONG Value
,ULONG Base
,ULONG strsize
, LPWSTR str
, ULONG strsize2
)
2104 UINT WINAPI
SetCPGlobal(UINT CodePage
)
2115 ValidateLCType(int a1
, unsigned int a2
, int a3
, int a4
)
2126 NlsResetProcessLocale(VOID
)
2137 GetDefaultSortkeySize(LPVOID lpUnknown
)
2148 GetLinguistLangSize(LPVOID lpUnknown
)
2159 ValidateLocale(IN ULONG LocaleId
)
2170 NlsGetCacheUpdateCount(VOID
)
2181 IsNLSDefinedString(IN NLS_FUNCTION Function
,
2183 IN LPNLSVERSIONINFO lpVersionInformation
,
2184 IN LPCWSTR lpString
,
2196 GetNLSVersion(IN NLS_FUNCTION Function
,
2198 IN OUT LPNLSVERSIONINFO lpVersionInformation
)