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 *******************************************************************/
20 /* GLOBAL VARIABLES ***********************************************************/
22 /* Sequence length based on the first character. */
23 static const char UTF8Length
[128] =
25 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x80 - 0x8F */
26 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x90 - 0x9F */
27 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0xA0 - 0xAF */
28 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0xB0 - 0xBF */
29 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 0xC0 - 0xCF */
30 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 0xD0 - 0xDF */
31 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, /* 0xE0 - 0xEF */
32 3, 3, 3, 3, 3, 3, 3, 3, 4, 4, 4, 4, 5, 5, 0, 0 /* 0xF0 - 0xFF */
35 /* First byte mask depending on UTF-8 sequence length. */
36 static const unsigned char UTF8Mask
[6] = {0x7f, 0x1f, 0x0f, 0x07, 0x03, 0x01};
38 /* FIXME: Change to HASH table or linear array. */
39 static LIST_ENTRY CodePageListHead
;
40 static CODEPAGE_ENTRY AnsiCodePage
;
41 static CODEPAGE_ENTRY OemCodePage
;
42 static RTL_CRITICAL_SECTION CodePageListLock
;
44 /* FORWARD DECLARATIONS *******************************************************/
47 GetNlsSectionName(UINT CodePage
, UINT Base
, ULONG Unknown
,
48 LPSTR BaseName
, LPSTR Result
, ULONG ResultSize
);
51 GetCPFileNameFromRegistry(UINT CodePage
, LPWSTR FileName
, ULONG FileNameSize
);
53 /* PRIVATE FUNCTIONS **********************************************************/
58 * Internal NLS related stuff initialization.
65 UNICODE_STRING DirName
;
66 OBJECT_ATTRIBUTES ObjectAttributes
;
69 InitializeListHead(&CodePageListHead
);
70 RtlInitializeCriticalSection(&CodePageListLock
);
73 * FIXME: Eventually this should be done only for the NLS Server
74 * process, but since we don't have anything like that (yet?) we
75 * always try to create the "\Nls" directory here.
77 RtlInitUnicodeString(&DirName
, L
"\\Nls");
79 InitializeObjectAttributes(&ObjectAttributes
,
81 OBJ_CASE_INSENSITIVE
| OBJ_PERMANENT
,
85 if (NT_SUCCESS(NtCreateDirectoryObject(&Handle
, DIRECTORY_ALL_ACCESS
, &ObjectAttributes
)))
90 /* Setup ANSI code page. */
91 AnsiCodePage
.CodePage
= CP_ACP
;
92 AnsiCodePage
.SectionHandle
= NULL
;
93 AnsiCodePage
.SectionMapping
= NtCurrentTeb()->ProcessEnvironmentBlock
->AnsiCodePageData
;
95 RtlInitCodePageTable((PUSHORT
)AnsiCodePage
.SectionMapping
,
96 &AnsiCodePage
.CodePageTable
);
97 InsertTailList(&CodePageListHead
, &AnsiCodePage
.Entry
);
99 /* Setup OEM code page. */
100 OemCodePage
.CodePage
= CP_OEMCP
;
101 OemCodePage
.SectionHandle
= NULL
;
102 OemCodePage
.SectionMapping
= NtCurrentTeb()->ProcessEnvironmentBlock
->OemCodePageData
;
104 RtlInitCodePageTable((PUSHORT
)OemCodePage
.SectionMapping
,
105 &OemCodePage
.CodePageTable
);
106 InsertTailList(&CodePageListHead
, &OemCodePage
.Entry
);
114 * Internal NLS related stuff uninitialization.
121 PCODEPAGE_ENTRY Current
;
123 /* Delete the code page list. */
124 while (!IsListEmpty(&CodePageListHead
))
126 Current
= CONTAINING_RECORD(CodePageListHead
.Flink
, CODEPAGE_ENTRY
, Entry
);
127 if (Current
->SectionHandle
!= NULL
)
129 UnmapViewOfFile(Current
->SectionMapping
);
130 NtClose(Current
->SectionHandle
);
132 RemoveHeadList(&CodePageListHead
);
134 RtlDeleteCriticalSection(&CodePageListLock
);
138 * @name IntGetLoadedCodePageEntry
140 * Internal function to get structure containing a code page information
141 * of code page that is already loaded.
144 * Number of the code page. Special values like CP_OEMCP, CP_ACP
145 * or CP_UTF8 aren't allowed.
147 * @return Code page entry or NULL if the specified code page hasn't
153 IntGetLoadedCodePageEntry(UINT CodePage
)
155 LIST_ENTRY
*CurrentEntry
;
156 PCODEPAGE_ENTRY Current
;
158 RtlEnterCriticalSection(&CodePageListLock
);
159 for (CurrentEntry
= CodePageListHead
.Flink
;
160 CurrentEntry
!= &CodePageListHead
;
161 CurrentEntry
= CurrentEntry
->Flink
)
163 Current
= CONTAINING_RECORD(CurrentEntry
, CODEPAGE_ENTRY
, Entry
);
164 if (Current
->CodePage
== CodePage
)
166 RtlLeaveCriticalSection(&CodePageListLock
);
170 RtlLeaveCriticalSection(&CodePageListLock
);
176 * @name IntGetCodePageEntry
178 * Internal function to get structure containing a code page information.
181 * Number of the code page. Special values like CP_OEMCP, CP_ACP
182 * or CP_THREAD_ACP are allowed, but CP_UTF[7/8] isn't.
184 * @return Code page entry.
189 IntGetCodePageEntry(UINT CodePage
)
191 CHAR SectionName
[40];
193 HANDLE SectionHandle
= INVALID_HANDLE_VALUE
, FileHandle
;
194 PBYTE SectionMapping
;
195 OBJECT_ATTRIBUTES ObjectAttributes
;
196 ANSI_STRING AnsiName
;
197 UNICODE_STRING UnicodeName
;
198 WCHAR FileName
[MAX_PATH
+ 1];
200 PCODEPAGE_ENTRY CodePageEntry
;
202 if (CodePage
== CP_THREAD_ACP
)
204 if (!GetLocaleInfoW(GetThreadLocale(),
205 LOCALE_IDEFAULTANSICODEPAGE
| LOCALE_RETURN_NUMBER
,
207 sizeof(CodePage
) / sizeof(WCHAR
)))
209 /* Last error is set by GetLocaleInfoW. */
213 else if (CodePage
== CP_MACCP
)
215 if (!GetLocaleInfoW(LOCALE_SYSTEM_DEFAULT
,
216 LOCALE_IDEFAULTMACCODEPAGE
| LOCALE_RETURN_NUMBER
,
218 sizeof(CodePage
) / sizeof(WCHAR
)))
220 /* Last error is set by GetLocaleInfoW. */
225 /* Try searching for loaded page first. */
226 CodePageEntry
= IntGetLoadedCodePageEntry(CodePage
);
227 if (CodePageEntry
!= NULL
)
229 return CodePageEntry
;
233 * Yes, we really want to lock here. Otherwise it can happen that
234 * two parallel requests will try to get the entry for the same
235 * code page and we would load it twice.
237 RtlEnterCriticalSection(&CodePageListLock
);
239 /* Generate the section name. */
240 if (!GetNlsSectionName(CodePage
,
243 "\\Nls\\NlsSectionCP",
245 sizeof(SectionName
)))
247 RtlLeaveCriticalSection(&CodePageListLock
);
251 RtlInitAnsiString(&AnsiName
, SectionName
);
252 RtlAnsiStringToUnicodeString(&UnicodeName
, &AnsiName
, TRUE
);
254 InitializeObjectAttributes(&ObjectAttributes
, &UnicodeName
, 0, NULL
, NULL
);
256 /* Try to open the section first */
257 Status
= NtOpenSection(&SectionHandle
, SECTION_MAP_READ
, &ObjectAttributes
);
259 /* If the section doesn't exist, try to create it. */
260 if (Status
== STATUS_UNSUCCESSFUL
||
261 Status
== STATUS_OBJECT_NAME_NOT_FOUND
||
262 Status
== STATUS_OBJECT_PATH_NOT_FOUND
)
264 FileNamePos
= GetSystemDirectoryW(FileName
, MAX_PATH
);
265 if (GetCPFileNameFromRegistry(CodePage
,
266 FileName
+ FileNamePos
+ 1,
267 MAX_PATH
- FileNamePos
- 1))
269 FileName
[FileNamePos
] = L
'\\';
270 FileName
[MAX_PATH
] = 0;
271 FileHandle
= CreateFileW(FileName
,
279 Status
= NtCreateSection(&SectionHandle
,
287 /* HACK: Check if another process was faster
288 * and already created this section. See bug 3626 for details */
289 if (Status
== STATUS_OBJECT_NAME_COLLISION
)
291 /* Close the file then */
294 /* And open the section */
295 Status
= NtOpenSection(&SectionHandle
,
301 RtlFreeUnicodeString(&UnicodeName
);
303 if (!NT_SUCCESS(Status
))
305 RtlLeaveCriticalSection(&CodePageListLock
);
309 SectionMapping
= MapViewOfFile(SectionHandle
, FILE_MAP_READ
, 0, 0, 0);
310 if (SectionMapping
== NULL
)
312 NtClose(SectionHandle
);
313 RtlLeaveCriticalSection(&CodePageListLock
);
317 CodePageEntry
= HeapAlloc(GetProcessHeap(), 0, sizeof(CODEPAGE_ENTRY
));
318 if (CodePageEntry
== NULL
)
320 NtClose(SectionHandle
);
321 RtlLeaveCriticalSection(&CodePageListLock
);
325 CodePageEntry
->CodePage
= CodePage
;
326 CodePageEntry
->SectionHandle
= SectionHandle
;
327 CodePageEntry
->SectionMapping
= SectionMapping
;
329 RtlInitCodePageTable((PUSHORT
)SectionMapping
, &CodePageEntry
->CodePageTable
);
331 /* Insert the new entry to list and unlock. Uff. */
332 InsertTailList(&CodePageListHead
, &CodePageEntry
->Entry
);
333 RtlLeaveCriticalSection(&CodePageListLock
);
335 return CodePageEntry
;
339 * @name IntMultiByteToWideCharUTF8
341 * Internal version of MultiByteToWideChar for UTF8.
343 * @see MultiByteToWideChar
344 * @todo Add UTF8 validity checks.
350 IntMultiByteToWideCharUTF8(DWORD Flags
,
351 LPCSTR MultiByteString
,
353 LPWSTR WideCharString
,
361 if (Flags
!= 0 && Flags
!= MB_ERR_INVALID_CHARS
)
363 SetLastError(ERROR_INVALID_FLAGS
);
367 /* Does caller query for output buffer size? */
368 if (WideCharCount
== 0)
370 MbsEnd
= MultiByteString
+ MultiByteCount
;
371 for (; MultiByteString
< MbsEnd
; WideCharCount
++)
373 Char
= *MultiByteString
++;
376 MultiByteString
+= UTF8Length
[Char
- 0x80];
378 return WideCharCount
;
381 MbsEnd
= MultiByteString
+ MultiByteCount
;
382 for (Count
= 0; Count
< WideCharCount
&& MultiByteString
< MbsEnd
; Count
++)
384 Char
= *MultiByteString
++;
387 *WideCharString
++ = Char
;
390 Length
= UTF8Length
[Char
- 0x80];
391 WideChar
= Char
& UTF8Mask
[Length
];
392 while (Length
&& MultiByteString
< MbsEnd
)
394 WideChar
= (WideChar
<< 6) | (*MultiByteString
++ & 0x7f);
397 *WideCharString
++ = WideChar
;
400 if (MultiByteString
< MbsEnd
)
401 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
407 * @name IntMultiByteToWideCharCP
409 * Internal version of MultiByteToWideChar for code page tables.
411 * @see MultiByteToWideChar
412 * @todo Handle MB_PRECOMPOSED, MB_COMPOSITE, MB_USEGLYPHCHARS and
419 IntMultiByteToWideCharCP(UINT CodePage
,
421 LPCSTR MultiByteString
,
423 LPWSTR WideCharString
,
426 PCODEPAGE_ENTRY CodePageEntry
;
427 PCPTABLEINFO CodePageTable
;
431 /* Get code page table. */
432 CodePageEntry
= IntGetCodePageEntry(CodePage
);
433 if (CodePageEntry
== NULL
)
435 SetLastError(ERROR_INVALID_PARAMETER
);
438 CodePageTable
= &CodePageEntry
->CodePageTable
;
440 /* Different handling for DBCS code pages. */
441 if (CodePageTable
->MaximumCharacterSize
> 1)
447 LPCSTR MbsEnd
= MultiByteString
+ MultiByteCount
;
450 /* Does caller query for output buffer size? */
451 if (WideCharCount
== 0)
453 for (; MultiByteString
< MbsEnd
; WideCharCount
++)
455 Char
= *MultiByteString
++;
460 DBCSOffset
= CodePageTable
->DBCSOffsets
[Char
];
465 if (MultiByteString
< MbsEnd
)
469 return WideCharCount
;
472 for (Count
= 0; Count
< WideCharCount
&& MultiByteString
< MbsEnd
; Count
++)
474 Char
= *MultiByteString
++;
478 *WideCharString
++ = Char
;
482 DBCSOffset
= CodePageTable
->DBCSOffsets
[Char
];
486 *WideCharString
++ = CodePageTable
->MultiByteTable
[Char
];
490 if (MultiByteString
< MbsEnd
)
491 *WideCharString
++ = CodePageTable
->DBCSOffsets
[DBCSOffset
+ *(PUCHAR
)MultiByteString
++];
494 if (MultiByteString
< MbsEnd
)
496 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
502 else /* Not DBCS code page */
504 /* Check for invalid characters. */
505 if (Flags
& MB_ERR_INVALID_CHARS
)
507 for (TempString
= MultiByteString
, TempLength
= MultiByteCount
;
509 TempString
++, TempLength
--)
511 if (CodePageTable
->MultiByteTable
[(UCHAR
)*TempString
] ==
512 CodePageTable
->UniDefaultChar
&&
513 *TempString
!= CodePageEntry
->CodePageTable
.DefaultChar
)
515 SetLastError(ERROR_NO_UNICODE_TRANSLATION
);
521 /* Does caller query for output buffer size? */
522 if (WideCharCount
== 0)
523 return MultiByteCount
;
525 /* Fill the WideCharString buffer with what will fit: Verified on WinXP */
526 for (TempLength
= (WideCharCount
< MultiByteCount
) ? WideCharCount
: MultiByteCount
;
528 MultiByteString
++, TempLength
--)
530 *WideCharString
++ = CodePageTable
->MultiByteTable
[(UCHAR
)*MultiByteString
];
533 /* Adjust buffer size. Wine trick ;-) */
534 if (WideCharCount
< MultiByteCount
)
536 MultiByteCount
= WideCharCount
;
537 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
540 return MultiByteCount
;
545 * @name IntMultiByteToWideCharSYMBOL
547 * Internal version of MultiByteToWideChar for SYMBOL.
549 * @see MultiByteToWideChar
555 IntMultiByteToWideCharSYMBOL(DWORD Flags
,
556 LPCSTR MultiByteString
,
558 LPWSTR WideCharString
,
568 SetLastError(ERROR_INVALID_FLAGS
);
572 if (WideCharCount
== 0)
574 return MultiByteCount
;
577 WideCharMaxLen
= WideCharCount
> MultiByteCount
? MultiByteCount
: WideCharCount
;
579 for (Count
= 0; Count
< WideCharMaxLen
; Count
++)
581 Char
= MultiByteString
[Count
];
584 WideCharString
[Count
] = Char
;
588 WideCharString
[Count
] = Char
+ 0xf000;
591 if (MultiByteCount
> WideCharMaxLen
)
593 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
597 return WideCharMaxLen
;
601 * @name IntWideCharToMultiByteSYMBOL
603 * Internal version of WideCharToMultiByte for SYMBOL.
605 * @see WideCharToMultiByte
610 IntWideCharToMultiByteSYMBOL(DWORD Flags
,
611 LPCWSTR WideCharString
,
613 LPSTR MultiByteString
,
622 SetLastError(ERROR_INVALID_PARAMETER
);
627 if (MultiByteCount
== 0)
629 return WideCharCount
;
632 MaxLen
= MultiByteCount
> WideCharCount
? WideCharCount
: MultiByteCount
;
633 for (Count
= 0; Count
< MaxLen
; Count
++)
635 Char
= WideCharString
[Count
];
638 MultiByteString
[Count
] = Char
;
642 if ((Char
>=0xf020)&&(Char
<0xf100))
644 MultiByteString
[Count
] = Char
- 0xf000;
648 SetLastError(ERROR_NO_UNICODE_TRANSLATION
);
653 if (WideCharCount
> MaxLen
)
655 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
662 * @name IntWideCharToMultiByteUTF8
664 * Internal version of WideCharToMultiByte for UTF8.
666 * @see WideCharToMultiByte
671 IntWideCharToMultiByteUTF8(UINT CodePage
,
673 LPCWSTR WideCharString
,
675 LPSTR MultiByteString
,
678 LPBOOL UsedDefaultChar
)
683 /* Does caller query for output buffer size? */
684 if (MultiByteCount
== 0)
686 for (TempLength
= 0; WideCharCount
;
687 WideCharCount
--, WideCharString
++)
690 if (*WideCharString
>= 0x80)
693 if (*WideCharString
>= 0x800)
700 for (TempLength
= MultiByteCount
; WideCharCount
; WideCharCount
--, WideCharString
++)
702 Char
= *WideCharString
;
707 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
711 *MultiByteString
++ = (CHAR
)Char
;
715 if (Char
< 0x800) /* 0x80-0x7ff: 2 bytes */
719 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
722 MultiByteString
[1] = 0x80 | (Char
& 0x3f); Char
>>= 6;
723 MultiByteString
[0] = 0xc0 | Char
;
724 MultiByteString
+= 2;
729 /* 0x800-0xffff: 3 bytes */
732 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
735 MultiByteString
[2] = 0x80 | (Char
& 0x3f); Char
>>= 6;
736 MultiByteString
[1] = 0x80 | (Char
& 0x3f); Char
>>= 6;
737 MultiByteString
[0] = 0xe0 | Char
;
738 MultiByteString
+= 3;
742 return MultiByteCount
- TempLength
;
746 * @name IsValidSBCSMapping
748 * Checks if ch (single-byte character) is a valid mapping for wch
750 * @see IntWideCharToMultiByteCP
755 IntIsValidSBCSMapping(PCPTABLEINFO CodePageTable
, DWORD Flags
, WCHAR wch
, UCHAR ch
)
757 /* If the WC_NO_BEST_FIT_CHARS flag has been specified, the characters need to match exactly. */
758 if (Flags
& WC_NO_BEST_FIT_CHARS
)
759 return (CodePageTable
->MultiByteTable
[ch
] == wch
);
761 /* By default, all characters except TransDefaultChar apply as a valid mapping
762 for ch (so also "nearest" characters) */
763 if (ch
!= CodePageTable
->TransDefaultChar
)
766 /* The only possible left valid mapping is the default character itself */
767 return (wch
== CodePageTable
->TransUniDefaultChar
);
771 * @name IsValidDBCSMapping
773 * Checks if ch (double-byte character) is a valid mapping for wch
775 * @see IntWideCharToMultiByteCP
778 IntIsValidDBCSMapping(PCPTABLEINFO CodePageTable
, DWORD Flags
, WCHAR wch
, USHORT ch
)
780 /* If ch is the default character, but the wch is not, it can't be a valid mapping */
781 if (ch
== CodePageTable
->TransDefaultChar
&& wch
!= CodePageTable
->TransUniDefaultChar
)
784 /* If the WC_NO_BEST_FIT_CHARS flag has been specified, the characters need to match exactly. */
785 if (Flags
& WC_NO_BEST_FIT_CHARS
)
789 USHORT uOffset
= CodePageTable
->DBCSOffsets
[ch
>> 8];
790 /* if (!uOffset) return (CodePageTable->MultiByteTable[ch] == wch); */
791 return (CodePageTable
->DBCSOffsets
[uOffset
+ (ch
& 0xff)] == wch
);
794 return (CodePageTable
->MultiByteTable
[ch
] == wch
);
797 /* If we're still here, we have a valid mapping */
802 * @name IntWideCharToMultiByteCP
804 * Internal version of WideCharToMultiByte for code page tables.
806 * @see WideCharToMultiByte
807 * @todo Handle WC_COMPOSITECHECK
812 IntWideCharToMultiByteCP(UINT CodePage
,
814 LPCWSTR WideCharString
,
816 LPSTR MultiByteString
,
819 LPBOOL UsedDefaultChar
)
821 PCODEPAGE_ENTRY CodePageEntry
;
822 PCPTABLEINFO CodePageTable
;
825 /* Get code page table. */
826 CodePageEntry
= IntGetCodePageEntry(CodePage
);
827 if (CodePageEntry
== NULL
)
829 SetLastError(ERROR_INVALID_PARAMETER
);
832 CodePageTable
= &CodePageEntry
->CodePageTable
;
835 /* Different handling for DBCS code pages. */
836 if (CodePageTable
->MaximumCharacterSize
> 1)
838 /* If Flags, DefaultChar or UsedDefaultChar were given, we have to do some more work */
839 if(Flags
|| DefaultChar
|| UsedDefaultChar
)
841 BOOL TempUsedDefaultChar
;
844 /* If UsedDefaultChar is not set, set it to a temporary value, so we don't have
845 to check on every character */
847 UsedDefaultChar
= &TempUsedDefaultChar
;
849 *UsedDefaultChar
= FALSE
;
851 /* Use the CodePage's TransDefaultChar if none was given. Don't modify the DefaultChar pointer here. */
853 DefChar
= DefaultChar
[1] ? ((DefaultChar
[0] << 8) | DefaultChar
[1]) : DefaultChar
[0];
855 DefChar
= CodePageTable
->TransDefaultChar
;
857 /* Does caller query for output buffer size? */
860 for(TempLength
= 0; WideCharCount
; WideCharCount
--, WideCharString
++, TempLength
++)
864 if ((Flags
& WC_COMPOSITECHECK
) && WideCharCount
> 1)
866 /* FIXME: Handle WC_COMPOSITECHECK */
869 uChar
= ((PUSHORT
) CodePageTable
->WideCharTable
)[*WideCharString
];
871 /* Verify if the mapping is valid for handling DefaultChar and UsedDefaultChar */
872 if (!IntIsValidDBCSMapping(CodePageTable
, Flags
, *WideCharString
, uChar
))
875 *UsedDefaultChar
= TRUE
;
878 /* Increment TempLength again if this is a double-byte character */
886 /* Convert the WideCharString to the MultiByteString and verify if the mapping is valid */
887 for(TempLength
= MultiByteCount
;
888 WideCharCount
&& TempLength
;
889 TempLength
--, WideCharString
++, WideCharCount
--)
893 if ((Flags
& WC_COMPOSITECHECK
) && WideCharCount
> 1)
895 /* FIXME: Handle WC_COMPOSITECHECK */
898 uChar
= ((PUSHORT
)CodePageTable
->WideCharTable
)[*WideCharString
];
900 /* Verify if the mapping is valid for handling DefaultChar and UsedDefaultChar */
901 if (!IntIsValidDBCSMapping(CodePageTable
, Flags
, *WideCharString
, uChar
))
904 *UsedDefaultChar
= TRUE
;
907 /* Handle double-byte characters */
910 /* Don't output a partial character */
915 *MultiByteString
++ = uChar
>> 8;
918 *MultiByteString
++ = (char)uChar
;
921 /* WideCharCount should be 0 if all characters were converted */
924 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
928 return MultiByteCount
- TempLength
;
931 /* Does caller query for output buffer size? */
934 for (TempLength
= 0; WideCharCount
; WideCharCount
--, WideCharString
++, TempLength
++)
936 /* Increment TempLength again if this is a double-byte character */
937 if (((PWCHAR
)CodePageTable
->WideCharTable
)[*WideCharString
] & 0xff00)
944 /* Convert the WideCharString to the MultiByteString */
945 for (TempLength
= MultiByteCount
;
946 WideCharCount
&& TempLength
;
947 TempLength
--, WideCharString
++, WideCharCount
--)
949 USHORT uChar
= ((PUSHORT
) CodePageTable
->WideCharTable
)[*WideCharString
];
951 /* Is this a double-byte character? */
954 /* Don't output a partial character */
959 *MultiByteString
++ = uChar
>> 8;
962 *MultiByteString
++ = (char)uChar
;
965 /* WideCharCount should be 0 if all characters were converted */
968 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
972 return MultiByteCount
- TempLength
;
974 else /* Not DBCS code page */
978 /* If Flags, DefaultChar or UsedDefaultChar were given, we have to do some more work */
979 if (Flags
|| DefaultChar
|| UsedDefaultChar
)
981 BOOL TempUsedDefaultChar
;
984 /* If UsedDefaultChar is not set, set it to a temporary value, so we don't have
985 to check on every character */
986 if (!UsedDefaultChar
)
987 UsedDefaultChar
= &TempUsedDefaultChar
;
989 *UsedDefaultChar
= FALSE
;
991 /* Does caller query for output buffer size? */
994 /* Loop through the whole WideCharString and check if we can get a valid mapping for each character */
995 for (TempLength
= 0; WideCharCount
; TempLength
++, WideCharString
++, WideCharCount
--)
997 if ((Flags
& WC_COMPOSITECHECK
) && WideCharCount
> 1)
999 /* FIXME: Handle WC_COMPOSITECHECK */
1002 if (!*UsedDefaultChar
)
1003 *UsedDefaultChar
= !IntIsValidSBCSMapping(CodePageTable
,
1006 ((PCHAR
)CodePageTable
->WideCharTable
)[*WideCharString
]);
1012 /* Use the CodePage's TransDefaultChar if none was given. Don't modify the DefaultChar pointer here. */
1014 DefChar
= *DefaultChar
;
1016 DefChar
= CodePageTable
->TransDefaultChar
;
1018 /* Convert the WideCharString to the MultiByteString and verify if the mapping is valid */
1019 for (TempLength
= MultiByteCount
;
1020 WideCharCount
&& TempLength
;
1021 MultiByteString
++, TempLength
--, WideCharString
++, WideCharCount
--)
1023 if ((Flags
& WC_COMPOSITECHECK
) && WideCharCount
> 1)
1025 /* FIXME: Handle WC_COMPOSITECHECK */
1028 *MultiByteString
= ((PCHAR
)CodePageTable
->WideCharTable
)[*WideCharString
];
1030 if (!IntIsValidSBCSMapping(CodePageTable
, Flags
, *WideCharString
, *MultiByteString
))
1032 *MultiByteString
= DefChar
;
1033 *UsedDefaultChar
= TRUE
;
1037 /* WideCharCount should be 0 if all characters were converted */
1040 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
1044 return MultiByteCount
- TempLength
;
1047 /* Does caller query for output buffer size? */
1048 if (!MultiByteCount
)
1049 return WideCharCount
;
1051 /* Is the buffer large enough? */
1052 if (MultiByteCount
< WideCharCount
)
1054 /* Convert the string up to MultiByteCount and return 0 */
1055 WideCharCount
= MultiByteCount
;
1056 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
1061 /* Otherwise WideCharCount will be the number of converted characters */
1062 nReturn
= WideCharCount
;
1065 /* Convert the WideCharString to the MultiByteString */
1066 for (TempLength
= WideCharCount
; --TempLength
>= 0; WideCharString
++, MultiByteString
++)
1068 *MultiByteString
= ((PCHAR
)CodePageTable
->WideCharTable
)[*WideCharString
];
1076 * @name IntIsLeadByte
1078 * Internal function to detect if byte is lead byte in specific character
1084 IntIsLeadByte(PCPTABLEINFO TableInfo
, BYTE Byte
)
1088 if (TableInfo
->MaximumCharacterSize
== 2)
1090 for (i
= 0; i
< MAXIMUM_LEADBYTES
&& TableInfo
->LeadByte
[i
]; i
+= 2)
1092 if (Byte
>= TableInfo
->LeadByte
[i
] && Byte
<= TableInfo
->LeadByte
[i
+1])
1100 /* PUBLIC FUNCTIONS ***********************************************************/
1103 * @name GetNlsSectionName
1105 * Construct a name of NLS section.
1110 * Integer base used for converting to string. Usually set to 10.
1112 * As the name suggests the meaning of this parameter is unknown.
1113 * The native version of Kernel32 passes it as the third parameter
1114 * to NlsConvertIntegerToString function, which is used for the
1115 * actual conversion of the code page number.
1117 * Base name of the section. (ex. "\\Nls\\NlsSectionCP")
1119 * Buffer that will hold the constructed name.
1121 * Size of the buffer for the result.
1123 * @return TRUE if the buffer was large enough and was filled with
1124 * the requested information, FALSE otherwise.
1131 GetNlsSectionName(UINT CodePage
,
1140 if (!NT_SUCCESS(RtlIntegerToChar(CodePage
, Base
, sizeof(Integer
), Integer
)))
1144 * If the name including the terminating NULL character doesn't
1145 * fit in the output buffer then fail.
1147 if (strlen(Integer
) + strlen(BaseName
) >= ResultSize
)
1150 lstrcpyA(Result
, BaseName
);
1151 lstrcatA(Result
, Integer
);
1157 * @name GetCPFileNameFromRegistry
1159 * Get file name of code page definition file.
1162 * Code page number to get file name of.
1164 * Buffer that is filled with file name of successful return. Can
1166 * @param FileNameSize
1167 * Size of the buffer to hold file name in WCHARs.
1169 * @return TRUE if the file name was retrieved, FALSE otherwise.
1176 GetCPFileNameFromRegistry(UINT CodePage
, LPWSTR FileName
, ULONG FileNameSize
)
1178 WCHAR ValueNameBuffer
[11];
1179 UNICODE_STRING KeyName
, ValueName
;
1180 OBJECT_ATTRIBUTES ObjectAttributes
;
1183 PKEY_VALUE_PARTIAL_INFORMATION Kvpi
;
1189 /* Convert the codepage number to string. */
1190 ValueName
.Buffer
= ValueNameBuffer
;
1191 ValueName
.MaximumLength
= sizeof(ValueNameBuffer
);
1193 if (!NT_SUCCESS(RtlIntegerToUnicodeString(CodePage
, 10, &ValueName
)))
1196 /* Open the registry key containing file name mappings. */
1197 RtlInitUnicodeString(&KeyName
, L
"\\Registry\\Machine\\System\\"
1198 L
"CurrentControlSet\\Control\\Nls\\CodePage");
1199 InitializeObjectAttributes(&ObjectAttributes
, &KeyName
, OBJ_CASE_INSENSITIVE
,
1201 Status
= NtOpenKey(&KeyHandle
, KEY_READ
, &ObjectAttributes
);
1202 if (!NT_SUCCESS(Status
))
1207 /* Allocate buffer that will be used to query the value data. */
1208 KvpiSize
= sizeof(KEY_VALUE_PARTIAL_INFORMATION
) + (MAX_PATH
* sizeof(WCHAR
));
1209 Kvpi
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, KvpiSize
);
1216 /* Query the file name for our code page. */
1217 Status
= NtQueryValueKey(KeyHandle
, &ValueName
, KeyValuePartialInformation
,
1218 Kvpi
, KvpiSize
, &KvpiSize
);
1222 /* Check if we succeded and the value is non-empty string. */
1223 if (NT_SUCCESS(Status
) && Kvpi
->Type
== REG_SZ
&&
1224 Kvpi
->DataLength
> sizeof(WCHAR
))
1227 if (FileName
!= NULL
)
1229 lstrcpynW(FileName
, (WCHAR
*)Kvpi
->Data
,
1230 min(Kvpi
->DataLength
/ sizeof(WCHAR
), FileNameSize
));
1234 /* free temporary buffer */
1235 HeapFree(GetProcessHeap(),0,Kvpi
);
1240 * @name IsValidCodePage
1242 * Detect if specified code page is valid and present in the system.
1245 * Code page number to query.
1247 * @return TRUE if code page is present.
1252 IsValidCodePage(UINT CodePage
)
1254 if (CodePage
== 0) return FALSE
;
1255 if (CodePage
== CP_UTF8
|| CodePage
== CP_UTF7
)
1257 if (IntGetLoadedCodePageEntry(CodePage
))
1259 return GetCPFileNameFromRegistry(CodePage
, NULL
, 0);
1262 static const signed char
1265 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
1266 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
1267 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 62, -1, -1, -1, 63,
1268 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, -1, -1, -1, -1, -1, -1,
1269 -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14,
1270 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, -1, -1, -1, -1, -1,
1271 -1, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40,
1272 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, -1, -1, -1, -1, -1
1275 static VOID
Utf7Base64Decode(BYTE
*pbDest
, LPCSTR pszSrc
, INT cchSrc
)
1280 for(i
= 0; i
< cchSrc
/ 4 * 4; i
+= 4)
1282 for(j
= n
= 0; j
< 4; )
1284 b
= (BYTE
) base64inv
[(BYTE
) *pszSrc
++];
1285 n
|= (((INT
) b
) << ((3 - j
) * 6));
1288 for(j
= 0; j
< 3; j
++)
1289 *pbDest
++ = (BYTE
) ((n
>> (8 * (2 - j
))) & 0xFF);
1291 for(j
= n
= 0; j
< cchSrc
% 4; )
1293 b
= (BYTE
) base64inv
[(BYTE
) *pszSrc
++];
1294 n
|= (((INT
) b
) << ((3 - j
) * 6));
1297 for(j
= 0; j
< ((cchSrc
% 4) * 6 / 8); j
++)
1298 *pbDest
++ = (BYTE
) ((n
>> (8 * (2 - j
))) & 0xFF);
1301 static VOID
myswab(LPVOID pv
, INT cw
)
1303 LPBYTE pb
= (LPBYTE
) pv
;
1315 static INT
Utf7ToWideCharSize(LPCSTR pszUtf7
, INT cchUtf7
)
1337 while(cchUtf7
> 0 && (BYTE
) *pszUtf7
< 0x80 &&
1338 base64inv
[*pszUtf7
] >= 0)
1343 cch
= pszUtf7
- pch
;
1346 if (cchUtf7
> 0 && *pszUtf7
== '-')
1362 static INT
Utf7ToWideChar(LPCSTR pszUtf7
, INT cchUtf7
, LPWSTR pszWide
, INT cchWide
)
1369 c
= Utf7ToWideCharSize(pszUtf7
, cchUtf7
);
1375 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
1384 if (*pszUtf7
== '-')
1393 while(cchUtf7
> 0 && (BYTE
) *pszUtf7
< 0x80 &&
1394 base64inv
[*pszUtf7
] >= 0)
1399 cch
= pszUtf7
- pch
;
1401 pwsz
= (WORD
*) HeapAlloc(GetProcessHeap(), 0, (n
+ 1) * sizeof(WORD
));
1404 ZeroMemory(pwsz
, n
* sizeof(WORD
));
1405 Utf7Base64Decode((BYTE
*) pwsz
, pch
, cch
);
1407 CopyMemory(pszWide
, pwsz
, n
* sizeof(WORD
));
1408 HeapFree(GetProcessHeap(), 0, pwsz
);
1410 if (cchUtf7
> 0 && *pszUtf7
== '-')
1418 *pszWide
++ = (WCHAR
) ch
;
1427 * @name MultiByteToWideChar
1429 * Convert a multi-byte string to wide-charater equivalent.
1432 * Code page to be used to perform the conversion. It can be also
1433 * one of the special values (CP_ACP for ANSI code page, CP_MACCP
1434 * for Macintosh code page, CP_OEMCP for OEM code page, CP_THREAD_ACP
1435 * for thread active code page, CP_UTF7 or CP_UTF8).
1437 * Additional conversion flags (MB_PRECOMPOSED, MB_COMPOSITE,
1438 * MB_ERR_INVALID_CHARS, MB_USEGLYPHCHARS).
1439 * @param MultiByteString
1441 * @param MultiByteCount
1442 * Size of MultiByteString, or -1 if MultiByteString is NULL
1444 * @param WideCharString
1446 * @param WideCharCount
1447 * Size in WCHARs of WideCharString, or 0 if the caller just wants
1448 * to know how large WideCharString should be for a successful
1451 * @return Zero on error, otherwise the number of WCHARs written
1452 * in the WideCharString buffer.
1459 MultiByteToWideChar(UINT CodePage
,
1461 LPCSTR MultiByteString
,
1463 LPWSTR WideCharString
,
1466 /* Check the parameters. */
1467 if (MultiByteString
== NULL
||
1468 MultiByteCount
== 0 ||
1469 (WideCharString
== NULL
&& WideCharCount
> 0) ||
1470 (PVOID
)MultiByteString
== (PVOID
)WideCharString
)
1472 SetLastError(ERROR_INVALID_PARAMETER
);
1476 /* Determine the input string length. */
1477 if (MultiByteCount
< 0)
1479 MultiByteCount
= lstrlenA(MultiByteString
) + 1;
1485 return IntMultiByteToWideCharUTF8(Flags
,
1494 SetLastError(ERROR_INVALID_FLAGS
);
1497 return Utf7ToWideChar(MultiByteString
, MultiByteCount
,
1498 WideCharString
, WideCharCount
);
1501 return IntMultiByteToWideCharSYMBOL(Flags
,
1507 return IntMultiByteToWideCharCP(CodePage
,
1516 static const char mustshift
[] =
1518 0, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 1, 1, 0, 1, 1,
1519 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1520 0, 1, 1, 1, 1, 1, 1, 0, 0, 0, 1, 1, 0, 0, 0, 0,
1521 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0,
1522 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
1523 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1,
1524 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
1525 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1
1528 static const char base64
[] =
1529 "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
1531 static INT
WideCharToUtf7Size(LPCWSTR pszWide
, INT cchWide
)
1535 BOOL fShift
= FALSE
;
1540 if (wch
< 0x80 && !mustshift
[wch
])
1564 if (cchWide
> 0 && (*pszWide
>= 0x80 || mustshift
[*pszWide
]))
1569 if (cchWide
> 0 && (*pszWide
>= 0x80 || mustshift
[*pszWide
]))
1576 if (cchWide
> 0 && *pszWide
< 0x80 && !mustshift
[*pszWide
])
1589 static INT
WideCharToUtf7(LPCWSTR pszWide
, INT cchWide
, LPSTR pszUtf7
, INT cchUtf7
)
1594 BOOL fShift
= FALSE
;
1596 c
= WideCharToUtf7Size(pszWide
, cchWide
);
1602 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
1609 if (wch
< 0x80 && !mustshift
[wch
])
1611 *pszUtf7
++ = (CHAR
) wch
;
1630 wsz
[0] = *pszWide
++;
1633 if (cchWide
> 0 && (*pszWide
>= 0x80 || mustshift
[*pszWide
]))
1635 wsz
[1] = *pszWide
++;
1638 if (cchWide
> 0 && (*pszWide
>= 0x80 || mustshift
[*pszWide
]))
1640 wsz
[2] = *pszWide
++;
1645 *pszUtf7
++ = base64
[wsz
[0] >> 10];
1646 *pszUtf7
++ = base64
[(wsz
[0] >> 4) & 0x3F];
1647 *pszUtf7
++ = base64
[(wsz
[0] << 2 | wsz
[1] >> 14) & 0x3F];
1650 *pszUtf7
++ = base64
[(wsz
[1] >> 8) & 0x3F];
1651 *pszUtf7
++ = base64
[(wsz
[1] >> 2) & 0x3F];
1652 *pszUtf7
++ = base64
[(wsz
[1] << 4 | wsz
[2] >> 12) & 0x3F];
1655 *pszUtf7
++ = base64
[(wsz
[2] >> 6) & 0x3F];
1656 *pszUtf7
++ = base64
[wsz
[2] & 0x3F];
1659 if (cchWide
> 0 && *pszWide
< 0x80 && !mustshift
[*pszWide
])
1673 GetLocalisedText(DWORD dwResId
, WCHAR
*lpszDest
)
1681 dwId
= dwResId
* 100;
1685 lcid
= GetUserDefaultLCID();
1686 lcid
= ConvertDefaultLocale(lcid
);
1688 langId
= LANGIDFROMLCID(lcid
);
1690 if (PRIMARYLANGID(langId
) == LANG_NEUTRAL
)
1691 langId
= MAKELANGID(LANG_ENGLISH
, SUBLANG_ENGLISH_US
);
1693 hrsrc
= FindResourceExW(hCurrentModule
,
1695 MAKEINTRESOURCEW((dwId
>> 4) + 1),
1699 HGLOBAL hmem
= LoadResource(hCurrentModule
, hrsrc
);
1706 p
= LockResource(hmem
);
1707 for (i
= 0; i
< (dwId
& 0x0f); i
++) p
+= *p
+ 1;
1709 memcpy(lpszDest
, p
+ 1, *p
* sizeof(WCHAR
));
1710 lpszDest
[*p
] = '\0';
1716 DPRINT1("Could not get codepage name. dwResId = %ld\n", dwResId
);
1725 GetCPInfo(UINT CodePage
,
1726 LPCPINFO CodePageInfo
)
1728 PCODEPAGE_ENTRY CodePageEntry
;
1732 SetLastError(ERROR_INVALID_PARAMETER
);
1736 CodePageEntry
= IntGetCodePageEntry(CodePage
);
1737 if (CodePageEntry
== NULL
)
1743 CodePageInfo
->DefaultChar
[0] = 0x3f;
1744 CodePageInfo
->DefaultChar
[1] = 0;
1745 CodePageInfo
->LeadByte
[0] = CodePageInfo
->LeadByte
[1] = 0;
1746 CodePageInfo
->MaxCharSize
= (CodePage
== CP_UTF7
) ? 5 : 4;
1750 SetLastError( ERROR_INVALID_PARAMETER
);
1754 if (CodePageEntry
->CodePageTable
.DefaultChar
& 0xff00)
1756 CodePageInfo
->DefaultChar
[0] = (CodePageEntry
->CodePageTable
.DefaultChar
& 0xff00) >> 8;
1757 CodePageInfo
->DefaultChar
[1] = CodePageEntry
->CodePageTable
.DefaultChar
& 0x00ff;
1761 CodePageInfo
->DefaultChar
[0] = CodePageEntry
->CodePageTable
.DefaultChar
& 0xff;
1762 CodePageInfo
->DefaultChar
[1] = 0;
1765 if ((CodePageInfo
->MaxCharSize
= CodePageEntry
->CodePageTable
.MaximumCharacterSize
) == 2)
1766 memcpy(CodePageInfo
->LeadByte
, CodePageEntry
->CodePageTable
.LeadByte
, sizeof(CodePageInfo
->LeadByte
));
1768 CodePageInfo
->LeadByte
[0] = CodePageInfo
->LeadByte
[1] = 0;
1778 GetCPInfoExW(UINT CodePage
,
1780 LPCPINFOEXW lpCPInfoEx
)
1782 if (!GetCPInfo(CodePage
, (LPCPINFO
) lpCPInfoEx
))
1789 lpCPInfoEx
->CodePage
= CP_UTF7
;
1790 lpCPInfoEx
->UnicodeDefaultChar
= 0x3f;
1791 return GetLocalisedText((DWORD
)CodePage
, lpCPInfoEx
->CodePageName
);
1797 lpCPInfoEx
->CodePage
= CP_UTF8
;
1798 lpCPInfoEx
->UnicodeDefaultChar
= 0x3f;
1799 return GetLocalisedText((DWORD
)CodePage
, lpCPInfoEx
->CodePageName
);
1804 PCODEPAGE_ENTRY CodePageEntry
;
1806 CodePageEntry
= IntGetCodePageEntry(CodePage
);
1807 if (CodePageEntry
== NULL
)
1809 DPRINT1("Could not get CodePage Entry! CodePageEntry = 0\n");
1810 SetLastError(ERROR_INVALID_PARAMETER
);
1814 lpCPInfoEx
->CodePage
= CodePageEntry
->CodePageTable
.CodePage
;
1815 lpCPInfoEx
->UnicodeDefaultChar
= CodePageEntry
->CodePageTable
.UniDefaultChar
;
1816 return GetLocalisedText((DWORD
)CodePage
, lpCPInfoEx
->CodePageName
);
1828 GetCPInfoExA(UINT CodePage
,
1830 LPCPINFOEXA lpCPInfoEx
)
1834 if (!GetCPInfoExW(CodePage
, dwFlags
, &CPInfo
))
1837 /* the layout is the same except for CodePageName */
1838 memcpy(lpCPInfoEx
, &CPInfo
, sizeof(CPINFOEXA
));
1840 WideCharToMultiByte(CP_ACP
,
1842 CPInfo
.CodePageName
,
1844 lpCPInfoEx
->CodePageName
,
1845 sizeof(lpCPInfoEx
->CodePageName
),
1852 * @name WideCharToMultiByte
1854 * Convert a wide-charater string to closest multi-byte equivalent.
1857 * Code page to be used to perform the conversion. It can be also
1858 * one of the special values (CP_ACP for ANSI code page, CP_MACCP
1859 * for Macintosh code page, CP_OEMCP for OEM code page, CP_THREAD_ACP
1860 * for thread active code page, CP_UTF7 or CP_UTF8).
1862 * Additional conversion flags (WC_NO_BEST_FIT_CHARS, WC_COMPOSITECHECK,
1863 * WC_DISCARDNS, WC_SEPCHARS, WC_DEFAULTCHAR).
1864 * @param WideCharString
1865 * Points to the wide-character string to be converted.
1866 * @param WideCharCount
1867 * Size in WCHARs of WideCharStr, or 0 if the caller just wants to
1868 * know how large WideCharString should be for a successful conversion.
1869 * @param MultiByteString
1870 * Points to the buffer to receive the translated string.
1871 * @param MultiByteCount
1872 * Specifies the size in bytes of the buffer pointed to by the
1873 * MultiByteString parameter. If this value is zero, the function
1874 * returns the number of bytes required for the buffer.
1875 * @param DefaultChar
1876 * Points to the character used if a wide character cannot be
1877 * represented in the specified code page. If this parameter is
1878 * NULL, a system default value is used.
1879 * @param UsedDefaultChar
1880 * Points to a flag that indicates whether a default character was
1881 * used. This parameter can be NULL.
1883 * @return Zero on error, otherwise the number of bytes written in the
1884 * MultiByteString buffer. Or the number of bytes needed for
1885 * the MultiByteString buffer if MultiByteCount is zero.
1892 WideCharToMultiByte(UINT CodePage
,
1894 LPCWSTR WideCharString
,
1896 LPSTR MultiByteString
,
1899 LPBOOL UsedDefaultChar
)
1901 /* Check the parameters. */
1902 if (WideCharString
== NULL
||
1903 WideCharCount
== 0 ||
1904 (MultiByteString
== NULL
&& MultiByteCount
> 0) ||
1905 (PVOID
)WideCharString
== (PVOID
)MultiByteString
||
1908 SetLastError(ERROR_INVALID_PARAMETER
);
1912 /* Determine the input string length. */
1913 if (WideCharCount
< 0)
1915 WideCharCount
= lstrlenW(WideCharString
) + 1;
1921 if (DefaultChar
!= NULL
|| UsedDefaultChar
!= NULL
)
1923 SetLastError(ERROR_INVALID_PARAMETER
);
1926 return IntWideCharToMultiByteUTF8(CodePage
,
1936 if (DefaultChar
!= NULL
|| UsedDefaultChar
!= NULL
)
1938 SetLastError(ERROR_INVALID_PARAMETER
);
1943 SetLastError(ERROR_INVALID_FLAGS
);
1946 return WideCharToUtf7(WideCharString
, WideCharCount
,
1947 MultiByteString
, MultiByteCount
);
1950 if ((DefaultChar
!=NULL
) || (UsedDefaultChar
!=NULL
))
1952 SetLastError(ERROR_INVALID_PARAMETER
);
1955 return IntWideCharToMultiByteSYMBOL(Flags
,
1962 return IntWideCharToMultiByteCP(CodePage
,
1976 * Get active ANSI code page number.
1985 return AnsiCodePage
.CodePageTable
.CodePage
;
1991 * Get active OEM code page number.
2000 return OemCodePage
.CodePageTable
.CodePage
;
2004 * @name IsDBCSLeadByteEx
2006 * Determine if passed byte is lead byte in specified code page.
2013 IsDBCSLeadByteEx(UINT CodePage
, BYTE TestByte
)
2015 PCODEPAGE_ENTRY CodePageEntry
;
2017 CodePageEntry
= IntGetCodePageEntry(CodePage
);
2018 if (CodePageEntry
!= NULL
)
2019 return IntIsLeadByte(&CodePageEntry
->CodePageTable
, TestByte
);
2021 SetLastError(ERROR_INVALID_PARAMETER
);
2026 * @name IsDBCSLeadByteEx
2028 * Determine if passed byte is lead byte in current ANSI code page.
2035 IsDBCSLeadByte(BYTE TestByte
)
2037 return IntIsLeadByte(&AnsiCodePage
.CodePageTable
, TestByte
);
2043 NTSTATUS WINAPI
CreateNlsSecurityDescriptor(PSECURITY_DESCRIPTOR SecurityDescriptor
,ULONG Size
,ULONG AccessMask
)
2052 BOOL WINAPI
IsValidUILanguage(LANGID langid
)
2061 VOID WINAPI
NlsConvertIntegerToString(ULONG Value
,ULONG Base
,ULONG strsize
, LPWSTR str
, ULONG strsize2
)
2069 UINT WINAPI
SetCPGlobal(UINT CodePage
)
2080 ValidateLCType(int a1
, unsigned int a2
, int a3
, int a4
)
2091 NlsResetProcessLocale(VOID
)
2102 GetDefaultSortkeySize(LPVOID lpUnknown
)
2113 GetLinguistLangSize(LPVOID lpUnknown
)
2124 ValidateLocale(IN ULONG LocaleId
)
2135 NlsGetCacheUpdateCount(VOID
)
2146 IsNLSDefinedString(IN NLS_FUNCTION Function
,
2148 IN LPNLSVERSIONINFO lpVersionInformation
,
2149 IN LPCWSTR lpString
,
2161 GetNLSVersion(IN NLS_FUNCTION Function
,
2163 IN OUT LPNLSVERSIONINFO lpVersionInformation
)