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 (WideCharString
== NULL
&& WideCharCount
> 0) ||
1469 (PVOID
)MultiByteString
== (PVOID
)WideCharString
)
1471 SetLastError(ERROR_INVALID_PARAMETER
);
1475 /* Determine the input string length. */
1476 if (MultiByteCount
< 0)
1478 MultiByteCount
= lstrlenA(MultiByteString
) + 1;
1484 return IntMultiByteToWideCharUTF8(Flags
,
1493 SetLastError(ERROR_INVALID_FLAGS
);
1496 return Utf7ToWideChar(MultiByteString
, MultiByteCount
,
1497 WideCharString
, WideCharCount
);
1500 return IntMultiByteToWideCharSYMBOL(Flags
,
1506 return IntMultiByteToWideCharCP(CodePage
,
1515 static const char mustshift
[] =
1517 0, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 1, 1, 0, 1, 1,
1518 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1519 0, 1, 1, 1, 1, 1, 1, 0, 0, 0, 1, 1, 0, 0, 0, 0,
1520 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0,
1521 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
1522 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1,
1523 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
1524 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1
1527 static const char base64
[] =
1528 "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
1530 static INT
WideCharToUtf7Size(LPCWSTR pszWide
, INT cchWide
)
1534 BOOL fShift
= FALSE
;
1539 if (wch
< 0x80 && !mustshift
[wch
])
1563 if (cchWide
> 0 && (*pszWide
>= 0x80 || mustshift
[*pszWide
]))
1568 if (cchWide
> 0 && (*pszWide
>= 0x80 || mustshift
[*pszWide
]))
1575 if (cchWide
> 0 && *pszWide
< 0x80 && !mustshift
[*pszWide
])
1588 static INT
WideCharToUtf7(LPCWSTR pszWide
, INT cchWide
, LPSTR pszUtf7
, INT cchUtf7
)
1593 BOOL fShift
= FALSE
;
1595 c
= WideCharToUtf7Size(pszWide
, cchWide
);
1601 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
1608 if (wch
< 0x80 && !mustshift
[wch
])
1610 *pszUtf7
++ = (CHAR
) wch
;
1629 wsz
[0] = *pszWide
++;
1632 if (cchWide
> 0 && (*pszWide
>= 0x80 || mustshift
[*pszWide
]))
1634 wsz
[1] = *pszWide
++;
1637 if (cchWide
> 0 && (*pszWide
>= 0x80 || mustshift
[*pszWide
]))
1639 wsz
[2] = *pszWide
++;
1644 *pszUtf7
++ = base64
[wsz
[0] >> 10];
1645 *pszUtf7
++ = base64
[(wsz
[0] >> 4) & 0x3F];
1646 *pszUtf7
++ = base64
[(wsz
[0] << 2 | wsz
[1] >> 14) & 0x3F];
1649 *pszUtf7
++ = base64
[(wsz
[1] >> 8) & 0x3F];
1650 *pszUtf7
++ = base64
[(wsz
[1] >> 2) & 0x3F];
1651 *pszUtf7
++ = base64
[(wsz
[1] << 4 | wsz
[2] >> 12) & 0x3F];
1654 *pszUtf7
++ = base64
[(wsz
[2] >> 6) & 0x3F];
1655 *pszUtf7
++ = base64
[wsz
[2] & 0x3F];
1658 if (cchWide
> 0 && *pszWide
< 0x80 && !mustshift
[*pszWide
])
1672 GetLocalisedText(DWORD dwResId
, WCHAR
*lpszDest
)
1680 dwId
= dwResId
* 100;
1684 lcid
= GetUserDefaultLCID();
1685 lcid
= ConvertDefaultLocale(lcid
);
1687 langId
= LANGIDFROMLCID(lcid
);
1689 if (PRIMARYLANGID(langId
) == LANG_NEUTRAL
)
1690 langId
= MAKELANGID(LANG_ENGLISH
, SUBLANG_ENGLISH_US
);
1692 hrsrc
= FindResourceExW(hCurrentModule
,
1694 MAKEINTRESOURCEW((dwId
>> 4) + 1),
1698 HGLOBAL hmem
= LoadResource(hCurrentModule
, hrsrc
);
1705 p
= LockResource(hmem
);
1706 for (i
= 0; i
< (dwId
& 0x0f); i
++) p
+= *p
+ 1;
1708 memcpy(lpszDest
, p
+ 1, *p
* sizeof(WCHAR
));
1709 lpszDest
[*p
] = '\0';
1715 DPRINT1("Could not get codepage name. dwResId = %ld\n", dwResId
);
1724 GetCPInfo(UINT CodePage
,
1725 LPCPINFO CodePageInfo
)
1727 PCODEPAGE_ENTRY CodePageEntry
;
1731 SetLastError(ERROR_INVALID_PARAMETER
);
1735 CodePageEntry
= IntGetCodePageEntry(CodePage
);
1736 if (CodePageEntry
== NULL
)
1742 CodePageInfo
->DefaultChar
[0] = 0x3f;
1743 CodePageInfo
->DefaultChar
[1] = 0;
1744 CodePageInfo
->LeadByte
[0] = CodePageInfo
->LeadByte
[1] = 0;
1745 CodePageInfo
->MaxCharSize
= (CodePage
== CP_UTF7
) ? 5 : 4;
1749 SetLastError( ERROR_INVALID_PARAMETER
);
1753 if (CodePageEntry
->CodePageTable
.DefaultChar
& 0xff00)
1755 CodePageInfo
->DefaultChar
[0] = (CodePageEntry
->CodePageTable
.DefaultChar
& 0xff00) >> 8;
1756 CodePageInfo
->DefaultChar
[1] = CodePageEntry
->CodePageTable
.DefaultChar
& 0x00ff;
1760 CodePageInfo
->DefaultChar
[0] = CodePageEntry
->CodePageTable
.DefaultChar
& 0xff;
1761 CodePageInfo
->DefaultChar
[1] = 0;
1764 if ((CodePageInfo
->MaxCharSize
= CodePageEntry
->CodePageTable
.MaximumCharacterSize
) == 2)
1765 memcpy(CodePageInfo
->LeadByte
, CodePageEntry
->CodePageTable
.LeadByte
, sizeof(CodePageInfo
->LeadByte
));
1767 CodePageInfo
->LeadByte
[0] = CodePageInfo
->LeadByte
[1] = 0;
1777 GetCPInfoExW(UINT CodePage
,
1779 LPCPINFOEXW lpCPInfoEx
)
1781 if (!GetCPInfo(CodePage
, (LPCPINFO
) lpCPInfoEx
))
1788 lpCPInfoEx
->CodePage
= CP_UTF7
;
1789 lpCPInfoEx
->UnicodeDefaultChar
= 0x3f;
1790 return GetLocalisedText((DWORD
)CodePage
, lpCPInfoEx
->CodePageName
);
1796 lpCPInfoEx
->CodePage
= CP_UTF8
;
1797 lpCPInfoEx
->UnicodeDefaultChar
= 0x3f;
1798 return GetLocalisedText((DWORD
)CodePage
, lpCPInfoEx
->CodePageName
);
1803 PCODEPAGE_ENTRY CodePageEntry
;
1805 CodePageEntry
= IntGetCodePageEntry(CodePage
);
1806 if (CodePageEntry
== NULL
)
1808 DPRINT1("Could not get CodePage Entry! CodePageEntry = 0\n");
1809 SetLastError(ERROR_INVALID_PARAMETER
);
1813 lpCPInfoEx
->CodePage
= CodePageEntry
->CodePageTable
.CodePage
;
1814 lpCPInfoEx
->UnicodeDefaultChar
= CodePageEntry
->CodePageTable
.UniDefaultChar
;
1815 return GetLocalisedText((DWORD
)CodePage
, lpCPInfoEx
->CodePageName
);
1827 GetCPInfoExA(UINT CodePage
,
1829 LPCPINFOEXA lpCPInfoEx
)
1833 if (!GetCPInfoExW(CodePage
, dwFlags
, &CPInfo
))
1836 /* the layout is the same except for CodePageName */
1837 memcpy(lpCPInfoEx
, &CPInfo
, sizeof(CPINFOEXA
));
1839 WideCharToMultiByte(CP_ACP
,
1841 CPInfo
.CodePageName
,
1843 lpCPInfoEx
->CodePageName
,
1844 sizeof(lpCPInfoEx
->CodePageName
),
1851 * @name WideCharToMultiByte
1853 * Convert a wide-charater string to closest multi-byte equivalent.
1856 * Code page to be used to perform the conversion. It can be also
1857 * one of the special values (CP_ACP for ANSI code page, CP_MACCP
1858 * for Macintosh code page, CP_OEMCP for OEM code page, CP_THREAD_ACP
1859 * for thread active code page, CP_UTF7 or CP_UTF8).
1861 * Additional conversion flags (WC_NO_BEST_FIT_CHARS, WC_COMPOSITECHECK,
1862 * WC_DISCARDNS, WC_SEPCHARS, WC_DEFAULTCHAR).
1863 * @param WideCharString
1864 * Points to the wide-character string to be converted.
1865 * @param WideCharCount
1866 * Size in WCHARs of WideCharStr, or 0 if the caller just wants to
1867 * know how large WideCharString should be for a successful conversion.
1868 * @param MultiByteString
1869 * Points to the buffer to receive the translated string.
1870 * @param MultiByteCount
1871 * Specifies the size in bytes of the buffer pointed to by the
1872 * MultiByteString parameter. If this value is zero, the function
1873 * returns the number of bytes required for the buffer.
1874 * @param DefaultChar
1875 * Points to the character used if a wide character cannot be
1876 * represented in the specified code page. If this parameter is
1877 * NULL, a system default value is used.
1878 * @param UsedDefaultChar
1879 * Points to a flag that indicates whether a default character was
1880 * used. This parameter can be NULL.
1882 * @return Zero on error, otherwise the number of bytes written in the
1883 * MultiByteString buffer. Or the number of bytes needed for
1884 * the MultiByteString buffer if MultiByteCount is zero.
1891 WideCharToMultiByte(UINT CodePage
,
1893 LPCWSTR WideCharString
,
1895 LPSTR MultiByteString
,
1898 LPBOOL UsedDefaultChar
)
1900 /* Check the parameters. */
1901 if (WideCharString
== NULL
||
1902 (MultiByteString
== NULL
&& MultiByteCount
> 0) ||
1903 (PVOID
)WideCharString
== (PVOID
)MultiByteString
||
1906 SetLastError(ERROR_INVALID_PARAMETER
);
1910 /* Determine the input string length. */
1911 if (WideCharCount
< 0)
1913 WideCharCount
= lstrlenW(WideCharString
) + 1;
1919 return IntWideCharToMultiByteUTF8(CodePage
,
1929 if (DefaultChar
!= NULL
|| UsedDefaultChar
!= NULL
)
1931 SetLastError(ERROR_INVALID_PARAMETER
);
1936 SetLastError(ERROR_INVALID_FLAGS
);
1939 return WideCharToUtf7(WideCharString
, WideCharCount
,
1940 MultiByteString
, MultiByteCount
);
1943 if ((DefaultChar
!=NULL
) || (UsedDefaultChar
!=NULL
))
1945 SetLastError(ERROR_INVALID_PARAMETER
);
1948 return IntWideCharToMultiByteSYMBOL(Flags
,
1955 return IntWideCharToMultiByteCP(CodePage
,
1969 * Get active ANSI code page number.
1978 return AnsiCodePage
.CodePageTable
.CodePage
;
1984 * Get active OEM code page number.
1993 return OemCodePage
.CodePageTable
.CodePage
;
1997 * @name IsDBCSLeadByteEx
1999 * Determine if passed byte is lead byte in specified code page.
2006 IsDBCSLeadByteEx(UINT CodePage
, BYTE TestByte
)
2008 PCODEPAGE_ENTRY CodePageEntry
;
2010 CodePageEntry
= IntGetCodePageEntry(CodePage
);
2011 if (CodePageEntry
!= NULL
)
2012 return IntIsLeadByte(&CodePageEntry
->CodePageTable
, TestByte
);
2014 SetLastError(ERROR_INVALID_PARAMETER
);
2019 * @name IsDBCSLeadByteEx
2021 * Determine if passed byte is lead byte in current ANSI code page.
2028 IsDBCSLeadByte(BYTE TestByte
)
2030 return IntIsLeadByte(&AnsiCodePage
.CodePageTable
, TestByte
);
2036 NTSTATUS WINAPI
CreateNlsSecurityDescriptor(PSECURITY_DESCRIPTOR SecurityDescriptor
,ULONG Size
,ULONG AccessMask
)
2045 BOOL WINAPI
IsValidUILanguage(LANGID langid
)
2054 VOID WINAPI
NlsConvertIntegerToString(ULONG Value
,ULONG Base
,ULONG strsize
, LPWSTR str
, ULONG strsize2
)
2062 UINT WINAPI
SetCPGlobal(UINT CodePage
)
2073 ValidateLCType(int a1
, unsigned int a2
, int a3
, int a4
)
2084 NlsResetProcessLocale(VOID
)
2095 GetDefaultSortkeySize(LPVOID lpUnknown
)
2106 GetLinguistLangSize(LPVOID lpUnknown
)
2117 ValidateLocale(IN ULONG LocaleId
)
2128 NlsGetCacheUpdateCount(VOID
)
2139 IsNLSDefinedString(IN NLS_FUNCTION Function
,
2141 IN LPNLSVERSIONINFO lpVersionInformation
,
2142 IN LPCWSTR lpString
,
2154 GetNLSVersion(IN NLS_FUNCTION Function
,
2156 IN OUT LPNLSVERSIONINFO lpVersionInformation
)