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
)
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),
1709 HGLOBAL hmem
= LoadResource(hCurrentModule
, hrsrc
);
1716 p
= LockResource(hmem
);
1717 for (i
= 0; i
< (dwId
& 0x0f); i
++) p
+= *p
+ 1;
1719 memcpy(lpszDest
, p
+ 1, *p
* sizeof(WCHAR
));
1720 lpszDest
[*p
] = '\0';
1726 DPRINT1("Could not get codepage name. dwResId = %lu\n", dwResId
);
1735 GetCPInfo(UINT CodePage
,
1736 LPCPINFO CodePageInfo
)
1738 PCODEPAGE_ENTRY CodePageEntry
;
1742 SetLastError(ERROR_INVALID_PARAMETER
);
1746 CodePageEntry
= IntGetCodePageEntry(CodePage
);
1747 if (CodePageEntry
== NULL
)
1753 CodePageInfo
->DefaultChar
[0] = 0x3f;
1754 CodePageInfo
->DefaultChar
[1] = 0;
1755 CodePageInfo
->LeadByte
[0] = CodePageInfo
->LeadByte
[1] = 0;
1756 CodePageInfo
->MaxCharSize
= (CodePage
== CP_UTF7
) ? 5 : 4;
1760 DPRINT1("Invalid CP!: %lx\n", CodePage
);
1761 SetLastError( ERROR_INVALID_PARAMETER
);
1765 if (CodePageEntry
->CodePageTable
.DefaultChar
& 0xff00)
1767 CodePageInfo
->DefaultChar
[0] = (CodePageEntry
->CodePageTable
.DefaultChar
& 0xff00) >> 8;
1768 CodePageInfo
->DefaultChar
[1] = CodePageEntry
->CodePageTable
.DefaultChar
& 0x00ff;
1772 CodePageInfo
->DefaultChar
[0] = CodePageEntry
->CodePageTable
.DefaultChar
& 0xff;
1773 CodePageInfo
->DefaultChar
[1] = 0;
1776 if ((CodePageInfo
->MaxCharSize
= CodePageEntry
->CodePageTable
.MaximumCharacterSize
) == 2)
1777 memcpy(CodePageInfo
->LeadByte
, CodePageEntry
->CodePageTable
.LeadByte
, sizeof(CodePageInfo
->LeadByte
));
1779 CodePageInfo
->LeadByte
[0] = CodePageInfo
->LeadByte
[1] = 0;
1789 GetCPInfoExW(UINT CodePage
,
1791 LPCPINFOEXW lpCPInfoEx
)
1793 if (!GetCPInfo(CodePage
, (LPCPINFO
) lpCPInfoEx
))
1800 lpCPInfoEx
->CodePage
= CP_UTF7
;
1801 lpCPInfoEx
->UnicodeDefaultChar
= 0x3f;
1802 return GetLocalisedText((DWORD
)CodePage
, lpCPInfoEx
->CodePageName
);
1808 lpCPInfoEx
->CodePage
= CP_UTF8
;
1809 lpCPInfoEx
->UnicodeDefaultChar
= 0x3f;
1810 return GetLocalisedText((DWORD
)CodePage
, lpCPInfoEx
->CodePageName
);
1815 PCODEPAGE_ENTRY CodePageEntry
;
1817 CodePageEntry
= IntGetCodePageEntry(CodePage
);
1818 if (CodePageEntry
== NULL
)
1820 DPRINT1("Could not get CodePage Entry! CodePageEntry = 0\n");
1821 SetLastError(ERROR_INVALID_PARAMETER
);
1825 lpCPInfoEx
->CodePage
= CodePageEntry
->CodePageTable
.CodePage
;
1826 lpCPInfoEx
->UnicodeDefaultChar
= CodePageEntry
->CodePageTable
.UniDefaultChar
;
1827 return GetLocalisedText(CodePageEntry
->CodePageTable
.CodePage
, lpCPInfoEx
->CodePageName
);
1839 GetCPInfoExA(UINT CodePage
,
1841 LPCPINFOEXA lpCPInfoEx
)
1845 if (!GetCPInfoExW(CodePage
, dwFlags
, &CPInfo
))
1848 /* the layout is the same except for CodePageName */
1849 memcpy(lpCPInfoEx
, &CPInfo
, sizeof(CPINFOEXA
));
1851 WideCharToMultiByte(CP_ACP
,
1853 CPInfo
.CodePageName
,
1855 lpCPInfoEx
->CodePageName
,
1856 sizeof(lpCPInfoEx
->CodePageName
),
1863 * @name WideCharToMultiByte
1865 * Convert a wide-charater string to closest multi-byte equivalent.
1868 * Code page to be used to perform the conversion. It can be also
1869 * one of the special values (CP_ACP for ANSI code page, CP_MACCP
1870 * for Macintosh code page, CP_OEMCP for OEM code page, CP_THREAD_ACP
1871 * for thread active code page, CP_UTF7 or CP_UTF8).
1873 * Additional conversion flags (WC_NO_BEST_FIT_CHARS, WC_COMPOSITECHECK,
1874 * WC_DISCARDNS, WC_SEPCHARS, WC_DEFAULTCHAR).
1875 * @param WideCharString
1876 * Points to the wide-character string to be converted.
1877 * @param WideCharCount
1878 * Size in WCHARs of WideCharStr, or 0 if the caller just wants to
1879 * know how large WideCharString should be for a successful conversion.
1880 * @param MultiByteString
1881 * Points to the buffer to receive the translated string.
1882 * @param MultiByteCount
1883 * Specifies the size in bytes of the buffer pointed to by the
1884 * MultiByteString parameter. If this value is zero, the function
1885 * returns the number of bytes required for the buffer.
1886 * @param DefaultChar
1887 * Points to the character used if a wide character cannot be
1888 * represented in the specified code page. If this parameter is
1889 * NULL, a system default value is used.
1890 * @param UsedDefaultChar
1891 * Points to a flag that indicates whether a default character was
1892 * used. This parameter can be NULL.
1894 * @return Zero on error, otherwise the number of bytes written in the
1895 * MultiByteString buffer. Or the number of bytes needed for
1896 * the MultiByteString buffer if MultiByteCount is zero.
1903 WideCharToMultiByte(UINT CodePage
,
1905 LPCWSTR WideCharString
,
1907 LPSTR MultiByteString
,
1910 LPBOOL UsedDefaultChar
)
1912 /* Check the parameters. */
1913 if (WideCharString
== NULL
||
1914 WideCharCount
== 0 ||
1915 (MultiByteString
== NULL
&& MultiByteCount
> 0) ||
1916 (PVOID
)WideCharString
== (PVOID
)MultiByteString
||
1919 SetLastError(ERROR_INVALID_PARAMETER
);
1923 /* Determine the input string length. */
1924 if (WideCharCount
< 0)
1926 WideCharCount
= lstrlenW(WideCharString
) + 1;
1932 if (DefaultChar
!= NULL
|| UsedDefaultChar
!= NULL
)
1934 SetLastError(ERROR_INVALID_PARAMETER
);
1937 return IntWideCharToMultiByteUTF8(CodePage
,
1947 if (DefaultChar
!= NULL
|| UsedDefaultChar
!= NULL
)
1949 SetLastError(ERROR_INVALID_PARAMETER
);
1954 SetLastError(ERROR_INVALID_FLAGS
);
1957 return WideCharToUtf7(WideCharString
, WideCharCount
,
1958 MultiByteString
, MultiByteCount
);
1961 if ((DefaultChar
!=NULL
) || (UsedDefaultChar
!=NULL
))
1963 SetLastError(ERROR_INVALID_PARAMETER
);
1966 return IntWideCharToMultiByteSYMBOL(Flags
,
1973 return IntWideCharToMultiByteCP(CodePage
,
1987 * Get active ANSI code page number.
1996 return AnsiCodePage
.CodePageTable
.CodePage
;
2002 * Get active OEM code page number.
2011 return OemCodePage
.CodePageTable
.CodePage
;
2015 * @name IsDBCSLeadByteEx
2017 * Determine if passed byte is lead byte in specified code page.
2024 IsDBCSLeadByteEx(UINT CodePage
, BYTE TestByte
)
2026 PCODEPAGE_ENTRY CodePageEntry
;
2028 CodePageEntry
= IntGetCodePageEntry(CodePage
);
2029 if (CodePageEntry
!= NULL
)
2030 return IntIsLeadByte(&CodePageEntry
->CodePageTable
, TestByte
);
2032 SetLastError(ERROR_INVALID_PARAMETER
);
2037 * @name IsDBCSLeadByteEx
2039 * Determine if passed byte is lead byte in current ANSI code page.
2046 IsDBCSLeadByte(BYTE TestByte
)
2048 return IntIsLeadByte(&AnsiCodePage
.CodePageTable
, TestByte
);
2054 NTSTATUS WINAPI
CreateNlsSecurityDescriptor(PSECURITY_DESCRIPTOR SecurityDescriptor
,ULONG Size
,ULONG AccessMask
)
2063 BOOL WINAPI
IsValidUILanguage(LANGID langid
)
2072 VOID WINAPI
NlsConvertIntegerToString(ULONG Value
,ULONG Base
,ULONG strsize
, LPWSTR str
, ULONG strsize2
)
2080 UINT WINAPI
SetCPGlobal(UINT CodePage
)
2091 ValidateLCType(int a1
, unsigned int a2
, int a3
, int a4
)
2102 NlsResetProcessLocale(VOID
)
2113 GetDefaultSortkeySize(LPVOID lpUnknown
)
2124 GetLinguistLangSize(LPVOID lpUnknown
)
2135 ValidateLocale(IN ULONG LocaleId
)
2146 NlsGetCacheUpdateCount(VOID
)
2157 IsNLSDefinedString(IN NLS_FUNCTION Function
,
2159 IN LPNLSVERSIONINFO lpVersionInformation
,
2160 IN LPCWSTR lpString
,
2172 GetNLSVersion(IN NLS_FUNCTION Function
,
2174 IN OUT LPNLSVERSIONINFO lpVersionInformation
)