2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS system libraries
4 * FILE: dll/win32/kernel32/winnls/string/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 return &AnsiCodePage
;
224 else if (CodePage
== CP_MACCP
)
226 if (!GetLocaleInfoW(LOCALE_SYSTEM_DEFAULT
,
227 LOCALE_IDEFAULTMACCODEPAGE
| LOCALE_RETURN_NUMBER
,
229 sizeof(CodePage
) / sizeof(WCHAR
)))
231 /* Last error is set by GetLocaleInfoW. */
236 /* Try searching for loaded page first. */
237 CodePageEntry
= IntGetLoadedCodePageEntry(CodePage
);
238 if (CodePageEntry
!= NULL
)
240 return CodePageEntry
;
244 * Yes, we really want to lock here. Otherwise it can happen that
245 * two parallel requests will try to get the entry for the same
246 * code page and we would load it twice.
248 RtlEnterCriticalSection(&CodePageListLock
);
250 /* Generate the section name. */
251 if (!GetNlsSectionName(CodePage
,
254 "\\Nls\\NlsSectionCP",
256 sizeof(SectionName
)))
258 RtlLeaveCriticalSection(&CodePageListLock
);
262 RtlInitAnsiString(&AnsiName
, SectionName
);
263 RtlAnsiStringToUnicodeString(&UnicodeName
, &AnsiName
, TRUE
);
265 InitializeObjectAttributes(&ObjectAttributes
, &UnicodeName
, 0, NULL
, NULL
);
267 /* Try to open the section first */
268 Status
= NtOpenSection(&SectionHandle
, SECTION_MAP_READ
, &ObjectAttributes
);
270 /* If the section doesn't exist, try to create it. */
271 if (Status
== STATUS_UNSUCCESSFUL
||
272 Status
== STATUS_OBJECT_NAME_NOT_FOUND
||
273 Status
== STATUS_OBJECT_PATH_NOT_FOUND
)
275 FileNamePos
= GetSystemDirectoryW(FileName
, MAX_PATH
);
276 if (GetCPFileNameFromRegistry(CodePage
,
277 FileName
+ FileNamePos
+ 1,
278 MAX_PATH
- FileNamePos
- 1))
280 FileName
[FileNamePos
] = L
'\\';
281 FileName
[MAX_PATH
] = 0;
282 FileHandle
= CreateFileW(FileName
,
290 Status
= NtCreateSection(&SectionHandle
,
298 /* HACK: Check if another process was faster
299 * and already created this section. See bug 3626 for details */
300 if (Status
== STATUS_OBJECT_NAME_COLLISION
)
302 /* Close the file then */
305 /* And open the section */
306 Status
= NtOpenSection(&SectionHandle
,
312 RtlFreeUnicodeString(&UnicodeName
);
314 if (!NT_SUCCESS(Status
))
316 RtlLeaveCriticalSection(&CodePageListLock
);
320 SectionMapping
= MapViewOfFile(SectionHandle
, FILE_MAP_READ
, 0, 0, 0);
321 if (SectionMapping
== NULL
)
323 NtClose(SectionHandle
);
324 RtlLeaveCriticalSection(&CodePageListLock
);
328 CodePageEntry
= HeapAlloc(GetProcessHeap(), 0, sizeof(CODEPAGE_ENTRY
));
329 if (CodePageEntry
== NULL
)
331 NtClose(SectionHandle
);
332 RtlLeaveCriticalSection(&CodePageListLock
);
336 CodePageEntry
->CodePage
= CodePage
;
337 CodePageEntry
->SectionHandle
= SectionHandle
;
338 CodePageEntry
->SectionMapping
= SectionMapping
;
340 RtlInitCodePageTable((PUSHORT
)SectionMapping
, &CodePageEntry
->CodePageTable
);
342 /* Insert the new entry to list and unlock. Uff. */
343 InsertTailList(&CodePageListHead
, &CodePageEntry
->Entry
);
344 RtlLeaveCriticalSection(&CodePageListLock
);
346 return CodePageEntry
;
350 * @name IntMultiByteToWideCharUTF8
352 * Internal version of MultiByteToWideChar for UTF8.
354 * @see MultiByteToWideChar
355 * @todo Add UTF8 validity checks.
361 IntMultiByteToWideCharUTF8(DWORD Flags
,
362 LPCSTR MultiByteString
,
364 LPWSTR WideCharString
,
372 if (Flags
!= 0 && Flags
!= MB_ERR_INVALID_CHARS
)
374 SetLastError(ERROR_INVALID_FLAGS
);
378 /* Does caller query for output buffer size? */
379 if (WideCharCount
== 0)
381 MbsEnd
= MultiByteString
+ MultiByteCount
;
382 for (; MultiByteString
< MbsEnd
; WideCharCount
++)
384 Char
= *MultiByteString
++;
387 MultiByteString
+= UTF8Length
[Char
- 0x80];
389 return WideCharCount
;
392 MbsEnd
= MultiByteString
+ MultiByteCount
;
393 for (Count
= 0; Count
< WideCharCount
&& MultiByteString
< MbsEnd
; Count
++)
395 Char
= *MultiByteString
++;
398 *WideCharString
++ = Char
;
401 Length
= UTF8Length
[Char
- 0x80];
402 WideChar
= Char
& UTF8Mask
[Length
];
403 while (Length
&& MultiByteString
< MbsEnd
)
405 WideChar
= (WideChar
<< 6) | (*MultiByteString
++ & 0x7f);
408 *WideCharString
++ = WideChar
;
411 if (MultiByteString
< MbsEnd
)
412 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
418 * @name IntMultiByteToWideCharCP
420 * Internal version of MultiByteToWideChar for code page tables.
422 * @see MultiByteToWideChar
423 * @todo Handle MB_PRECOMPOSED, MB_COMPOSITE, MB_USEGLYPHCHARS and
430 IntMultiByteToWideCharCP(UINT CodePage
,
432 LPCSTR MultiByteString
,
434 LPWSTR WideCharString
,
437 PCODEPAGE_ENTRY CodePageEntry
;
438 PCPTABLEINFO CodePageTable
;
439 PUSHORT MultiByteTable
;
444 /* Get code page table. */
445 CodePageEntry
= IntGetCodePageEntry(CodePage
);
446 if (CodePageEntry
== NULL
)
448 SetLastError(ERROR_INVALID_PARAMETER
);
452 CodePageTable
= &CodePageEntry
->CodePageTable
;
454 /* If MB_USEGLYPHCHARS flag present and glyph table present */
455 if ((Flags
& MB_USEGLYPHCHARS
) && CodePageTable
->MultiByteTable
[256])
457 /* Use glyph table */
458 MultiByteTable
= CodePageTable
->MultiByteTable
+ 256 + 1;
462 MultiByteTable
= CodePageTable
->MultiByteTable
;
465 /* Different handling for DBCS code pages. */
466 if (CodePageTable
->DBCSCodePage
)
470 LPCSTR MbsEnd
= MultiByteString
+ MultiByteCount
;
473 if (Flags
& MB_ERR_INVALID_CHARS
)
475 TempString
= MultiByteString
;
477 while (TempString
< MbsEnd
)
479 DBCSOffset
= CodePageTable
->DBCSOffsets
[(UCHAR
)*TempString
];
483 /* If lead byte is presented, but behind it there is no symbol */
484 if (((TempString
+ 1) == MbsEnd
) || (*(TempString
+ 1) == 0))
486 SetLastError(ERROR_NO_UNICODE_TRANSLATION
);
490 WideChar
= CodePageTable
->DBCSOffsets
[DBCSOffset
+ *(TempString
+ 1)];
492 if (WideChar
== CodePageTable
->UniDefaultChar
&&
493 MAKEWORD(*(TempString
+ 1), *TempString
) != CodePageTable
->TransUniDefaultChar
)
495 SetLastError(ERROR_NO_UNICODE_TRANSLATION
);
503 WideChar
= MultiByteTable
[(UCHAR
)*TempString
];
505 if ((WideChar
== CodePageTable
->UniDefaultChar
&&
506 *TempString
!= CodePageTable
->TransUniDefaultChar
) ||
507 /* "Private Use" characters */
508 (WideChar
>= 0xE000 && WideChar
<= 0xF8FF))
510 SetLastError(ERROR_NO_UNICODE_TRANSLATION
);
519 /* Does caller query for output buffer size? */
520 if (WideCharCount
== 0)
522 for (; MultiByteString
< MbsEnd
; WideCharCount
++)
524 Char
= *MultiByteString
++;
529 DBCSOffset
= CodePageTable
->DBCSOffsets
[Char
];
534 if (MultiByteString
< MbsEnd
)
538 return WideCharCount
;
541 for (Count
= 0; Count
< WideCharCount
&& MultiByteString
< MbsEnd
; Count
++)
543 Char
= *MultiByteString
++;
547 *WideCharString
++ = Char
;
551 DBCSOffset
= CodePageTable
->DBCSOffsets
[Char
];
555 *WideCharString
++ = MultiByteTable
[Char
];
559 if (MultiByteString
< MbsEnd
)
560 *WideCharString
++ = CodePageTable
->DBCSOffsets
[DBCSOffset
+ *(PUCHAR
)MultiByteString
++];
563 if (MultiByteString
< MbsEnd
)
565 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
571 else /* SBCS code page */
573 /* Check for invalid characters. */
574 if (Flags
& MB_ERR_INVALID_CHARS
)
576 for (TempString
= MultiByteString
, TempLength
= MultiByteCount
;
578 TempString
++, TempLength
--)
580 WideChar
= MultiByteTable
[(UCHAR
)*TempString
];
582 if ((WideChar
== CodePageTable
->UniDefaultChar
&&
583 *TempString
!= CodePageTable
->TransUniDefaultChar
) ||
584 /* "Private Use" characters */
585 (WideChar
>= 0xE000 && WideChar
<= 0xF8FF))
587 SetLastError(ERROR_NO_UNICODE_TRANSLATION
);
593 /* Does caller query for output buffer size? */
594 if (WideCharCount
== 0)
595 return MultiByteCount
;
597 /* Fill the WideCharString buffer with what will fit: Verified on WinXP */
598 for (TempLength
= (WideCharCount
< MultiByteCount
) ? WideCharCount
: MultiByteCount
;
600 MultiByteString
++, TempLength
--)
602 *WideCharString
++ = MultiByteTable
[(UCHAR
)*MultiByteString
];
605 /* Adjust buffer size. Wine trick ;-) */
606 if (WideCharCount
< MultiByteCount
)
608 MultiByteCount
= WideCharCount
;
609 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
612 return MultiByteCount
;
617 * @name IntMultiByteToWideCharSYMBOL
619 * Internal version of MultiByteToWideChar for SYMBOL.
621 * @see MultiByteToWideChar
627 IntMultiByteToWideCharSYMBOL(DWORD Flags
,
628 LPCSTR MultiByteString
,
630 LPWSTR WideCharString
,
640 SetLastError(ERROR_INVALID_FLAGS
);
644 if (WideCharCount
== 0)
646 return MultiByteCount
;
649 WideCharMaxLen
= WideCharCount
> MultiByteCount
? MultiByteCount
: WideCharCount
;
651 for (Count
= 0; Count
< WideCharMaxLen
; Count
++)
653 Char
= MultiByteString
[Count
];
656 WideCharString
[Count
] = Char
;
660 WideCharString
[Count
] = Char
+ 0xf000;
663 if (MultiByteCount
> WideCharMaxLen
)
665 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
669 return WideCharMaxLen
;
673 * @name IntWideCharToMultiByteSYMBOL
675 * Internal version of WideCharToMultiByte for SYMBOL.
677 * @see WideCharToMultiByte
682 IntWideCharToMultiByteSYMBOL(DWORD Flags
,
683 LPCWSTR WideCharString
,
685 LPSTR MultiByteString
,
694 SetLastError(ERROR_INVALID_PARAMETER
);
699 if (MultiByteCount
== 0)
701 return WideCharCount
;
704 MaxLen
= MultiByteCount
> WideCharCount
? WideCharCount
: MultiByteCount
;
705 for (Count
= 0; Count
< MaxLen
; Count
++)
707 Char
= WideCharString
[Count
];
710 MultiByteString
[Count
] = (CHAR
)Char
;
714 if ((Char
>= 0xf020) && (Char
< 0xf100))
716 MultiByteString
[Count
] = Char
- 0xf000;
720 SetLastError(ERROR_NO_UNICODE_TRANSLATION
);
726 if (WideCharCount
> MaxLen
)
728 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
735 * @name IntWideCharToMultiByteUTF8
737 * Internal version of WideCharToMultiByte for UTF8.
739 * @see WideCharToMultiByte
744 IntWideCharToMultiByteUTF8(UINT CodePage
,
746 LPCWSTR WideCharString
,
748 LPSTR MultiByteString
,
751 LPBOOL UsedDefaultChar
)
756 /* Does caller query for output buffer size? */
757 if (MultiByteCount
== 0)
759 for (TempLength
= 0; WideCharCount
;
760 WideCharCount
--, WideCharString
++)
763 if (*WideCharString
>= 0x80)
766 if (*WideCharString
>= 0x800)
773 for (TempLength
= MultiByteCount
; WideCharCount
; WideCharCount
--, WideCharString
++)
775 Char
= *WideCharString
;
780 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
784 *MultiByteString
++ = (CHAR
)Char
;
788 if (Char
< 0x800) /* 0x80-0x7ff: 2 bytes */
792 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
795 MultiByteString
[1] = 0x80 | (Char
& 0x3f); Char
>>= 6;
796 MultiByteString
[0] = 0xc0 | Char
;
797 MultiByteString
+= 2;
802 /* 0x800-0xffff: 3 bytes */
805 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
808 MultiByteString
[2] = 0x80 | (Char
& 0x3f); Char
>>= 6;
809 MultiByteString
[1] = 0x80 | (Char
& 0x3f); Char
>>= 6;
810 MultiByteString
[0] = 0xe0 | Char
;
811 MultiByteString
+= 3;
815 return MultiByteCount
- TempLength
;
819 * @name IsValidSBCSMapping
821 * Checks if ch (single-byte character) is a valid mapping for wch
823 * @see IntWideCharToMultiByteCP
828 IntIsValidSBCSMapping(PCPTABLEINFO CodePageTable
, DWORD Flags
, WCHAR wch
, UCHAR ch
)
830 /* If the WC_NO_BEST_FIT_CHARS flag has been specified, the characters need to match exactly. */
831 if (Flags
& WC_NO_BEST_FIT_CHARS
)
832 return (CodePageTable
->MultiByteTable
[ch
] == wch
);
834 /* By default, all characters except TransDefaultChar apply as a valid mapping
835 for ch (so also "nearest" characters) */
836 if (ch
!= CodePageTable
->TransDefaultChar
)
839 /* The only possible left valid mapping is the default character itself */
840 return (wch
== CodePageTable
->TransUniDefaultChar
);
844 * @name IsValidDBCSMapping
846 * Checks if ch (double-byte character) is a valid mapping for wch
848 * @see IntWideCharToMultiByteCP
851 IntIsValidDBCSMapping(PCPTABLEINFO CodePageTable
, DWORD Flags
, WCHAR wch
, USHORT ch
)
853 /* If ch is the default character, but the wch is not, it can't be a valid mapping */
854 if (ch
== CodePageTable
->TransDefaultChar
&& wch
!= CodePageTable
->TransUniDefaultChar
)
857 /* If the WC_NO_BEST_FIT_CHARS flag has been specified, the characters need to match exactly. */
858 if (Flags
& WC_NO_BEST_FIT_CHARS
)
862 USHORT uOffset
= CodePageTable
->DBCSOffsets
[ch
>> 8];
863 /* if (!uOffset) return (CodePageTable->MultiByteTable[ch] == wch); */
864 return (CodePageTable
->DBCSOffsets
[uOffset
+ (ch
& 0xff)] == wch
);
867 return (CodePageTable
->MultiByteTable
[ch
] == wch
);
870 /* If we're still here, we have a valid mapping */
875 * @name IntWideCharToMultiByteCP
877 * Internal version of WideCharToMultiByte for code page tables.
879 * @see WideCharToMultiByte
880 * @todo Handle WC_COMPOSITECHECK
885 IntWideCharToMultiByteCP(UINT CodePage
,
887 LPCWSTR WideCharString
,
889 LPSTR MultiByteString
,
892 LPBOOL UsedDefaultChar
)
894 PCODEPAGE_ENTRY CodePageEntry
;
895 PCPTABLEINFO CodePageTable
;
898 /* Get code page table. */
899 CodePageEntry
= IntGetCodePageEntry(CodePage
);
900 if (CodePageEntry
== NULL
)
902 SetLastError(ERROR_INVALID_PARAMETER
);
905 CodePageTable
= &CodePageEntry
->CodePageTable
;
908 /* Different handling for DBCS code pages. */
909 if (CodePageTable
->MaximumCharacterSize
> 1)
911 /* If Flags, DefaultChar or UsedDefaultChar were given, we have to do some more work */
912 if(Flags
|| DefaultChar
|| UsedDefaultChar
)
914 BOOL TempUsedDefaultChar
;
917 /* If UsedDefaultChar is not set, set it to a temporary value, so we don't have
918 to check on every character */
920 UsedDefaultChar
= &TempUsedDefaultChar
;
922 *UsedDefaultChar
= FALSE
;
924 /* Use the CodePage's TransDefaultChar if none was given. Don't modify the DefaultChar pointer here. */
926 DefChar
= DefaultChar
[1] ? ((DefaultChar
[0] << 8) | DefaultChar
[1]) : DefaultChar
[0];
928 DefChar
= CodePageTable
->TransDefaultChar
;
930 /* Does caller query for output buffer size? */
933 for(TempLength
= 0; WideCharCount
; WideCharCount
--, WideCharString
++, TempLength
++)
937 if ((Flags
& WC_COMPOSITECHECK
) && WideCharCount
> 1)
939 /* FIXME: Handle WC_COMPOSITECHECK */
942 uChar
= ((PUSHORT
) CodePageTable
->WideCharTable
)[*WideCharString
];
944 /* Verify if the mapping is valid for handling DefaultChar and UsedDefaultChar */
945 if (!IntIsValidDBCSMapping(CodePageTable
, Flags
, *WideCharString
, uChar
))
948 *UsedDefaultChar
= TRUE
;
951 /* Increment TempLength again if this is a double-byte character */
959 /* Convert the WideCharString to the MultiByteString and verify if the mapping is valid */
960 for(TempLength
= MultiByteCount
;
961 WideCharCount
&& TempLength
;
962 TempLength
--, WideCharString
++, WideCharCount
--)
966 if ((Flags
& WC_COMPOSITECHECK
) && WideCharCount
> 1)
968 /* FIXME: Handle WC_COMPOSITECHECK */
971 uChar
= ((PUSHORT
)CodePageTable
->WideCharTable
)[*WideCharString
];
973 /* Verify if the mapping is valid for handling DefaultChar and UsedDefaultChar */
974 if (!IntIsValidDBCSMapping(CodePageTable
, Flags
, *WideCharString
, uChar
))
977 *UsedDefaultChar
= TRUE
;
980 /* Handle double-byte characters */
983 /* Don't output a partial character */
988 *MultiByteString
++ = uChar
>> 8;
991 *MultiByteString
++ = (char)uChar
;
994 /* WideCharCount should be 0 if all characters were converted */
997 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
1001 return MultiByteCount
- TempLength
;
1004 /* Does caller query for output buffer size? */
1005 if (!MultiByteCount
)
1007 for (TempLength
= 0; WideCharCount
; WideCharCount
--, WideCharString
++, TempLength
++)
1009 /* Increment TempLength again if this is a double-byte character */
1010 if (((PWCHAR
)CodePageTable
->WideCharTable
)[*WideCharString
] & 0xff00)
1017 /* Convert the WideCharString to the MultiByteString */
1018 for (TempLength
= MultiByteCount
;
1019 WideCharCount
&& TempLength
;
1020 TempLength
--, WideCharString
++, WideCharCount
--)
1022 USHORT uChar
= ((PUSHORT
) CodePageTable
->WideCharTable
)[*WideCharString
];
1024 /* Is this a double-byte character? */
1027 /* Don't output a partial character */
1028 if (TempLength
== 1)
1032 *MultiByteString
++ = uChar
>> 8;
1035 *MultiByteString
++ = (char)uChar
;
1038 /* WideCharCount should be 0 if all characters were converted */
1041 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
1045 return MultiByteCount
- TempLength
;
1047 else /* Not DBCS code page */
1051 /* If Flags, DefaultChar or UsedDefaultChar were given, we have to do some more work */
1052 if (Flags
|| DefaultChar
|| UsedDefaultChar
)
1054 BOOL TempUsedDefaultChar
;
1057 /* If UsedDefaultChar is not set, set it to a temporary value, so we don't have
1058 to check on every character */
1059 if (!UsedDefaultChar
)
1060 UsedDefaultChar
= &TempUsedDefaultChar
;
1062 *UsedDefaultChar
= FALSE
;
1064 /* Does caller query for output buffer size? */
1065 if (!MultiByteCount
)
1067 /* Loop through the whole WideCharString and check if we can get a valid mapping for each character */
1068 for (TempLength
= 0; WideCharCount
; TempLength
++, WideCharString
++, WideCharCount
--)
1070 if ((Flags
& WC_COMPOSITECHECK
) && WideCharCount
> 1)
1072 /* FIXME: Handle WC_COMPOSITECHECK */
1075 if (!*UsedDefaultChar
)
1076 *UsedDefaultChar
= !IntIsValidSBCSMapping(CodePageTable
,
1079 ((PCHAR
)CodePageTable
->WideCharTable
)[*WideCharString
]);
1085 /* Use the CodePage's TransDefaultChar if none was given. Don't modify the DefaultChar pointer here. */
1087 DefChar
= *DefaultChar
;
1089 DefChar
= (CHAR
)CodePageTable
->TransDefaultChar
;
1091 /* Convert the WideCharString to the MultiByteString and verify if the mapping is valid */
1092 for (TempLength
= MultiByteCount
;
1093 WideCharCount
&& TempLength
;
1094 MultiByteString
++, TempLength
--, WideCharString
++, WideCharCount
--)
1096 if ((Flags
& WC_COMPOSITECHECK
) && WideCharCount
> 1)
1098 /* FIXME: Handle WC_COMPOSITECHECK */
1101 *MultiByteString
= ((PCHAR
)CodePageTable
->WideCharTable
)[*WideCharString
];
1103 if (!IntIsValidSBCSMapping(CodePageTable
, Flags
, *WideCharString
, *MultiByteString
))
1105 *MultiByteString
= DefChar
;
1106 *UsedDefaultChar
= TRUE
;
1110 /* WideCharCount should be 0 if all characters were converted */
1113 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
1117 return MultiByteCount
- TempLength
;
1120 /* Does caller query for output buffer size? */
1121 if (!MultiByteCount
)
1122 return WideCharCount
;
1124 /* Is the buffer large enough? */
1125 if (MultiByteCount
< WideCharCount
)
1127 /* Convert the string up to MultiByteCount and return 0 */
1128 WideCharCount
= MultiByteCount
;
1129 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
1134 /* Otherwise WideCharCount will be the number of converted characters */
1135 nReturn
= WideCharCount
;
1138 /* Convert the WideCharString to the MultiByteString */
1139 for (TempLength
= WideCharCount
; --TempLength
>= 0; WideCharString
++, MultiByteString
++)
1141 *MultiByteString
= ((PCHAR
)CodePageTable
->WideCharTable
)[*WideCharString
];
1149 * @name IntIsLeadByte
1151 * Internal function to detect if byte is lead byte in specific character
1157 IntIsLeadByte(PCPTABLEINFO TableInfo
, BYTE Byte
)
1161 if (TableInfo
->MaximumCharacterSize
== 2)
1163 for (i
= 0; i
< MAXIMUM_LEADBYTES
&& TableInfo
->LeadByte
[i
]; i
+= 2)
1165 if (Byte
>= TableInfo
->LeadByte
[i
] && Byte
<= TableInfo
->LeadByte
[i
+1])
1173 /* PUBLIC FUNCTIONS ***********************************************************/
1176 * @name GetNlsSectionName
1178 * Construct a name of NLS section.
1183 * Integer base used for converting to string. Usually set to 10.
1185 * As the name suggests the meaning of this parameter is unknown.
1186 * The native version of Kernel32 passes it as the third parameter
1187 * to NlsConvertIntegerToString function, which is used for the
1188 * actual conversion of the code page number.
1190 * Base name of the section. (ex. "\\Nls\\NlsSectionCP")
1192 * Buffer that will hold the constructed name.
1194 * Size of the buffer for the result.
1196 * @return TRUE if the buffer was large enough and was filled with
1197 * the requested information, FALSE otherwise.
1204 GetNlsSectionName(UINT CodePage
,
1213 if (!NT_SUCCESS(RtlIntegerToChar(CodePage
, Base
, sizeof(Integer
), Integer
)))
1217 * If the name including the terminating NULL character doesn't
1218 * fit in the output buffer then fail.
1220 if (strlen(Integer
) + strlen(BaseName
) >= ResultSize
)
1223 lstrcpyA(Result
, BaseName
);
1224 lstrcatA(Result
, Integer
);
1230 * @name GetCPFileNameFromRegistry
1232 * Get file name of code page definition file.
1235 * Code page number to get file name of.
1237 * Buffer that is filled with file name of successful return. Can
1239 * @param FileNameSize
1240 * Size of the buffer to hold file name in WCHARs.
1242 * @return TRUE if the file name was retrieved, FALSE otherwise.
1249 GetCPFileNameFromRegistry(UINT CodePage
, LPWSTR FileName
, ULONG FileNameSize
)
1251 WCHAR ValueNameBuffer
[11];
1252 UNICODE_STRING KeyName
, ValueName
;
1253 OBJECT_ATTRIBUTES ObjectAttributes
;
1256 PKEY_VALUE_PARTIAL_INFORMATION Kvpi
;
1262 /* Convert the codepage number to string. */
1263 ValueName
.Buffer
= ValueNameBuffer
;
1264 ValueName
.MaximumLength
= sizeof(ValueNameBuffer
);
1266 if (!NT_SUCCESS(RtlIntegerToUnicodeString(CodePage
, 10, &ValueName
)))
1269 /* Open the registry key containing file name mappings. */
1270 RtlInitUnicodeString(&KeyName
, L
"\\Registry\\Machine\\System\\"
1271 L
"CurrentControlSet\\Control\\Nls\\CodePage");
1272 InitializeObjectAttributes(&ObjectAttributes
, &KeyName
, OBJ_CASE_INSENSITIVE
,
1274 Status
= NtOpenKey(&KeyHandle
, KEY_READ
, &ObjectAttributes
);
1275 if (!NT_SUCCESS(Status
))
1280 /* Allocate buffer that will be used to query the value data. */
1281 KvpiSize
= sizeof(KEY_VALUE_PARTIAL_INFORMATION
) + (MAX_PATH
* sizeof(WCHAR
));
1282 Kvpi
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, KvpiSize
);
1289 /* Query the file name for our code page. */
1290 Status
= NtQueryValueKey(KeyHandle
, &ValueName
, KeyValuePartialInformation
,
1291 Kvpi
, KvpiSize
, &KvpiSize
);
1295 /* Check if we succeded and the value is non-empty string. */
1296 if (NT_SUCCESS(Status
) && Kvpi
->Type
== REG_SZ
&&
1297 Kvpi
->DataLength
> sizeof(WCHAR
))
1300 if (FileName
!= NULL
)
1302 lstrcpynW(FileName
, (WCHAR
*)Kvpi
->Data
,
1303 min(Kvpi
->DataLength
/ sizeof(WCHAR
), FileNameSize
));
1307 /* free temporary buffer */
1308 HeapFree(GetProcessHeap(),0,Kvpi
);
1313 * @name IsValidCodePage
1315 * Detect if specified code page is valid and present in the system.
1318 * Code page number to query.
1320 * @return TRUE if code page is present.
1325 IsValidCodePage(UINT CodePage
)
1327 if (CodePage
== 0) return FALSE
;
1328 if (CodePage
== CP_UTF8
|| CodePage
== CP_UTF7
)
1330 if (IntGetLoadedCodePageEntry(CodePage
))
1332 return GetCPFileNameFromRegistry(CodePage
, NULL
, 0);
1335 static inline BOOL
utf7_write_w(WCHAR
*dst
, int dstlen
, int *index
, WCHAR character
)
1339 if (*index
>= dstlen
)
1342 dst
[*index
] = character
;
1350 static INT
Utf7ToWideChar(const char *src
, int srclen
, WCHAR
*dst
, int dstlen
)
1352 static const signed char base64_decoding_table
[] =
1354 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 0x00-0x0F */
1355 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 0x10-0x1F */
1356 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 62, -1, -1, -1, 63, /* 0x20-0x2F */
1357 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, -1, -1, -1, -1, -1, -1, /* 0x30-0x3F */
1358 -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, /* 0x40-0x4F */
1359 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, -1, -1, -1, -1, -1, /* 0x50-0x5F */
1360 -1, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, /* 0x60-0x6F */
1361 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, -1, -1, -1, -1, -1 /* 0x70-0x7F */
1364 const char *source_end
= src
+ srclen
;
1367 DWORD byte_pair
= 0;
1370 while (src
< source_end
)
1375 if (src
>= source_end
)
1380 /* just a plus sign escaped as +- */
1381 if (!utf7_write_w(dst
, dstlen
, &dest_index
, '+'))
1383 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
1392 signed char sextet
= *src
;
1395 /* skip over the dash and end base64 decoding
1396 * the current, unfinished byte pair is discarded */
1403 /* the next character of src is < 0 and therefore not part of a base64 sequence
1404 * the current, unfinished byte pair is NOT discarded in this case
1405 * this is probably a bug in Windows */
1409 sextet
= base64_decoding_table
[sextet
];
1412 /* -1 means that the next character of src is not part of a base64 sequence
1413 * in other words, all sextets in this base64 sequence have been processed
1414 * the current, unfinished byte pair is discarded */
1419 byte_pair
= (byte_pair
<< 6) | sextet
;
1424 /* this byte pair is done */
1425 if (!utf7_write_w(dst
, dstlen
, &dest_index
, (byte_pair
>> (offset
- 16)) & 0xFFFF))
1427 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
1435 while (src
< source_end
);
1439 /* we have to convert to unsigned char in case *src < 0 */
1440 if (!utf7_write_w(dst
, dstlen
, &dest_index
, (unsigned char)*src
))
1442 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
1453 * @name MultiByteToWideChar
1455 * Convert a multi-byte string to wide-charater equivalent.
1458 * Code page to be used to perform the conversion. It can be also
1459 * one of the special values (CP_ACP for ANSI code page, CP_MACCP
1460 * for Macintosh code page, CP_OEMCP for OEM code page, CP_THREAD_ACP
1461 * for thread active code page, CP_UTF7 or CP_UTF8).
1463 * Additional conversion flags (MB_PRECOMPOSED, MB_COMPOSITE,
1464 * MB_ERR_INVALID_CHARS, MB_USEGLYPHCHARS).
1465 * @param MultiByteString
1467 * @param MultiByteCount
1468 * Size of MultiByteString, or -1 if MultiByteString is NULL
1470 * @param WideCharString
1472 * @param WideCharCount
1473 * Size in WCHARs of WideCharString, or 0 if the caller just wants
1474 * to know how large WideCharString should be for a successful
1477 * @return Zero on error, otherwise the number of WCHARs written
1478 * in the WideCharString buffer.
1485 MultiByteToWideChar(UINT CodePage
,
1487 LPCSTR MultiByteString
,
1489 LPWSTR WideCharString
,
1492 /* Check the parameters. */
1493 if (MultiByteString
== NULL
||
1494 MultiByteCount
== 0 || WideCharCount
< 0 ||
1495 (WideCharCount
&& (WideCharString
== NULL
||
1496 (PVOID
)MultiByteString
== (PVOID
)WideCharString
)))
1498 SetLastError(ERROR_INVALID_PARAMETER
);
1502 /* Determine the input string length. */
1503 if (MultiByteCount
< 0)
1505 MultiByteCount
= lstrlenA(MultiByteString
) + 1;
1511 return IntMultiByteToWideCharUTF8(Flags
,
1520 SetLastError(ERROR_INVALID_FLAGS
);
1523 return Utf7ToWideChar(MultiByteString
, MultiByteCount
,
1524 WideCharString
, WideCharCount
);
1527 return IntMultiByteToWideCharSYMBOL(Flags
,
1533 return IntMultiByteToWideCharCP(CodePage
,
1542 static inline BOOL
utf7_can_directly_encode(WCHAR codepoint
)
1544 static const BOOL directly_encodable_table
[] =
1546 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 1, 0, 0, /* 0x00 - 0x0F */
1547 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x10 - 0x1F */
1548 1, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 1, 1, 1, 1, 1, /* 0x20 - 0x2F */
1549 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 1, /* 0x30 - 0x3F */
1550 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 0x40 - 0x4F */
1551 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, /* 0x50 - 0x5F */
1552 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 0x60 - 0x6F */
1553 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 /* 0x70 - 0x7A */
1556 return codepoint
<= 0x7A ? directly_encodable_table
[codepoint
] : FALSE
;
1559 static inline BOOL
utf7_write_c(char *dst
, int dstlen
, int *index
, char character
)
1563 if (*index
>= dstlen
)
1566 dst
[*index
] = character
;
1574 static INT
WideCharToUtf7(const WCHAR
*src
, int srclen
, char *dst
, int dstlen
)
1576 static const char base64_encoding_table
[] =
1577 "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
1579 const WCHAR
*source_end
= src
+ srclen
;
1582 while (src
< source_end
)
1586 if (!utf7_write_c(dst
, dstlen
, &dest_index
, '+'))
1588 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
1591 if (!utf7_write_c(dst
, dstlen
, &dest_index
, '-'))
1593 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
1598 else if (utf7_can_directly_encode(*src
))
1600 if (!utf7_write_c(dst
, dstlen
, &dest_index
, *src
))
1602 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
1609 unsigned int offset
= 0;
1610 DWORD byte_pair
= 0;
1612 if (!utf7_write_c(dst
, dstlen
, &dest_index
, '+'))
1614 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
1618 while (src
< source_end
&& !utf7_can_directly_encode(*src
))
1620 byte_pair
= (byte_pair
<< 16) | *src
;
1624 if (!utf7_write_c(dst
, dstlen
, &dest_index
, base64_encoding_table
[(byte_pair
>> (offset
- 6)) & 0x3F]))
1626 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
1636 /* Windows won't create a padded base64 character if there's no room for the - sign
1637 * as well ; this is probably a bug in Windows */
1638 if (dstlen
> 0 && dest_index
+ 1 >= dstlen
)
1640 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
1644 byte_pair
<<= (6 - offset
);
1645 if (!utf7_write_c(dst
, dstlen
, &dest_index
, base64_encoding_table
[byte_pair
& 0x3F]))
1647 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
1652 /* Windows always explicitly terminates the base64 sequence
1653 even though RFC 2152 (page 3, rule 2) does not require this */
1654 if (!utf7_write_c(dst
, dstlen
, &dest_index
, '-'))
1656 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
1666 GetLocalisedText(DWORD dwResId
, WCHAR
*lpszDest
, DWORD dwDestSize
)
1674 dwId
= dwResId
* 100;
1678 lcid
= GetUserDefaultLCID();
1679 lcid
= ConvertDefaultLocale(lcid
);
1681 langId
= LANGIDFROMLCID(lcid
);
1683 if (PRIMARYLANGID(langId
) == LANG_NEUTRAL
)
1684 langId
= MAKELANGID(LANG_ENGLISH
, SUBLANG_ENGLISH_US
);
1686 hrsrc
= FindResourceExW(hCurrentModule
,
1688 MAKEINTRESOURCEW((dwId
>> 4) + 1),
1691 /* english fallback */
1694 hrsrc
= FindResourceExW(hCurrentModule
,
1696 MAKEINTRESOURCEW((dwId
>> 4) + 1),
1697 MAKELANGID(LANG_ENGLISH
, SUBLANG_ENGLISH_US
));
1702 HGLOBAL hmem
= LoadResource(hCurrentModule
, hrsrc
);
1710 p
= LockResource(hmem
);
1712 for (i
= 0; i
< (dwId
& 0x0f); i
++) p
+= *p
+ 1;
1717 len
= *p
* sizeof(WCHAR
);
1719 if(len
+ sizeof(WCHAR
) > dwDestSize
)
1721 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
1725 memcpy(lpszDest
, p
+ 1, len
);
1726 lpszDest
[*p
] = '\0';
1732 DPRINT1("Resource not found: dwResId = %lu\n", dwResId
);
1733 SetLastError(ERROR_INVALID_PARAMETER
);
1742 GetCPInfo(UINT CodePage
,
1743 LPCPINFO CodePageInfo
)
1745 PCODEPAGE_ENTRY CodePageEntry
;
1749 SetLastError(ERROR_INVALID_PARAMETER
);
1753 CodePageEntry
= IntGetCodePageEntry(CodePage
);
1754 if (CodePageEntry
== NULL
)
1760 CodePageInfo
->DefaultChar
[0] = 0x3f;
1761 CodePageInfo
->DefaultChar
[1] = 0;
1762 CodePageInfo
->LeadByte
[0] = CodePageInfo
->LeadByte
[1] = 0;
1763 CodePageInfo
->MaxCharSize
= (CodePage
== CP_UTF7
) ? 5 : 4;
1767 DPRINT1("Invalid CP!: %lx\n", CodePage
);
1768 SetLastError( ERROR_INVALID_PARAMETER
);
1772 if (CodePageEntry
->CodePageTable
.DefaultChar
& 0xff00)
1774 CodePageInfo
->DefaultChar
[0] = (CodePageEntry
->CodePageTable
.DefaultChar
& 0xff00) >> 8;
1775 CodePageInfo
->DefaultChar
[1] = CodePageEntry
->CodePageTable
.DefaultChar
& 0x00ff;
1779 CodePageInfo
->DefaultChar
[0] = CodePageEntry
->CodePageTable
.DefaultChar
& 0xff;
1780 CodePageInfo
->DefaultChar
[1] = 0;
1783 if ((CodePageInfo
->MaxCharSize
= CodePageEntry
->CodePageTable
.MaximumCharacterSize
) == 2)
1784 memcpy(CodePageInfo
->LeadByte
, CodePageEntry
->CodePageTable
.LeadByte
, sizeof(CodePageInfo
->LeadByte
));
1786 CodePageInfo
->LeadByte
[0] = CodePageInfo
->LeadByte
[1] = 0;
1796 GetCPInfoExW(UINT CodePage
,
1798 LPCPINFOEXW lpCPInfoEx
)
1800 if (!GetCPInfo(CodePage
, (LPCPINFO
) lpCPInfoEx
))
1807 lpCPInfoEx
->CodePage
= CP_UTF7
;
1808 lpCPInfoEx
->UnicodeDefaultChar
= 0x3f;
1809 return GetLocalisedText((DWORD
)CodePage
, lpCPInfoEx
->CodePageName
, sizeof(lpCPInfoEx
->CodePageName
)) != 0;
1815 lpCPInfoEx
->CodePage
= CP_UTF8
;
1816 lpCPInfoEx
->UnicodeDefaultChar
= 0x3f;
1817 return GetLocalisedText((DWORD
)CodePage
, lpCPInfoEx
->CodePageName
, sizeof(lpCPInfoEx
->CodePageName
)) != 0;
1822 PCODEPAGE_ENTRY CodePageEntry
;
1824 CodePageEntry
= IntGetCodePageEntry(CodePage
);
1825 if (CodePageEntry
== NULL
)
1827 DPRINT1("Could not get CodePage Entry! CodePageEntry = 0\n");
1828 SetLastError(ERROR_INVALID_PARAMETER
);
1832 lpCPInfoEx
->CodePage
= CodePageEntry
->CodePageTable
.CodePage
;
1833 lpCPInfoEx
->UnicodeDefaultChar
= CodePageEntry
->CodePageTable
.UniDefaultChar
;
1834 return GetLocalisedText(CodePageEntry
->CodePageTable
.CodePage
, lpCPInfoEx
->CodePageName
, sizeof(lpCPInfoEx
->CodePageName
)) != 0;
1846 GetCPInfoExA(UINT CodePage
,
1848 LPCPINFOEXA lpCPInfoEx
)
1852 if (!GetCPInfoExW(CodePage
, dwFlags
, &CPInfo
))
1855 /* the layout is the same except for CodePageName */
1856 memcpy(lpCPInfoEx
, &CPInfo
, sizeof(CPINFOEXA
));
1858 WideCharToMultiByte(CP_ACP
,
1860 CPInfo
.CodePageName
,
1862 lpCPInfoEx
->CodePageName
,
1863 sizeof(lpCPInfoEx
->CodePageName
),
1870 * @name WideCharToMultiByte
1872 * Convert a wide-charater string to closest multi-byte equivalent.
1875 * Code page to be used to perform the conversion. It can be also
1876 * one of the special values (CP_ACP for ANSI code page, CP_MACCP
1877 * for Macintosh code page, CP_OEMCP for OEM code page, CP_THREAD_ACP
1878 * for thread active code page, CP_UTF7 or CP_UTF8).
1880 * Additional conversion flags (WC_NO_BEST_FIT_CHARS, WC_COMPOSITECHECK,
1881 * WC_DISCARDNS, WC_SEPCHARS, WC_DEFAULTCHAR).
1882 * @param WideCharString
1883 * Points to the wide-character string to be converted.
1884 * @param WideCharCount
1885 * Size in WCHARs of WideCharStr, or 0 if the caller just wants to
1886 * know how large WideCharString should be for a successful conversion.
1887 * @param MultiByteString
1888 * Points to the buffer to receive the translated string.
1889 * @param MultiByteCount
1890 * Specifies the size in bytes of the buffer pointed to by the
1891 * MultiByteString parameter. If this value is zero, the function
1892 * returns the number of bytes required for the buffer.
1893 * @param DefaultChar
1894 * Points to the character used if a wide character cannot be
1895 * represented in the specified code page. If this parameter is
1896 * NULL, a system default value is used.
1897 * @param UsedDefaultChar
1898 * Points to a flag that indicates whether a default character was
1899 * used. This parameter can be NULL.
1901 * @return Zero on error, otherwise the number of bytes written in the
1902 * MultiByteString buffer. Or the number of bytes needed for
1903 * the MultiByteString buffer if MultiByteCount is zero.
1910 WideCharToMultiByte(UINT CodePage
,
1912 LPCWSTR WideCharString
,
1914 LPSTR MultiByteString
,
1917 LPBOOL UsedDefaultChar
)
1919 /* Check the parameters. */
1920 if (WideCharString
== NULL
||
1921 WideCharCount
== 0 ||
1922 (MultiByteString
== NULL
&& MultiByteCount
> 0) ||
1923 (PVOID
)WideCharString
== (PVOID
)MultiByteString
||
1926 SetLastError(ERROR_INVALID_PARAMETER
);
1930 /* Determine the input string length. */
1931 if (WideCharCount
< 0)
1933 WideCharCount
= lstrlenW(WideCharString
) + 1;
1939 if (DefaultChar
!= NULL
|| UsedDefaultChar
!= NULL
)
1941 SetLastError(ERROR_INVALID_PARAMETER
);
1944 return IntWideCharToMultiByteUTF8(CodePage
,
1954 if (DefaultChar
!= NULL
|| UsedDefaultChar
!= NULL
)
1956 SetLastError(ERROR_INVALID_PARAMETER
);
1961 SetLastError(ERROR_INVALID_FLAGS
);
1964 return WideCharToUtf7(WideCharString
, WideCharCount
,
1965 MultiByteString
, MultiByteCount
);
1968 if ((DefaultChar
!=NULL
) || (UsedDefaultChar
!=NULL
))
1970 SetLastError(ERROR_INVALID_PARAMETER
);
1973 return IntWideCharToMultiByteSYMBOL(Flags
,
1980 return IntWideCharToMultiByteCP(CodePage
,
1994 * Get active ANSI code page number.
2003 return AnsiCodePage
.CodePageTable
.CodePage
;
2009 * Get active OEM code page number.
2018 return OemCodePage
.CodePageTable
.CodePage
;
2022 * @name IsDBCSLeadByteEx
2024 * Determine if passed byte is lead byte in specified code page.
2031 IsDBCSLeadByteEx(UINT CodePage
, BYTE TestByte
)
2033 PCODEPAGE_ENTRY CodePageEntry
;
2035 CodePageEntry
= IntGetCodePageEntry(CodePage
);
2036 if (CodePageEntry
!= NULL
)
2037 return IntIsLeadByte(&CodePageEntry
->CodePageTable
, TestByte
);
2039 SetLastError(ERROR_INVALID_PARAMETER
);
2044 * @name IsDBCSLeadByteEx
2046 * Determine if passed byte is lead byte in current ANSI code page.
2053 IsDBCSLeadByte(BYTE TestByte
)
2055 return IntIsLeadByte(&AnsiCodePage
.CodePageTable
, TestByte
);
2061 NTSTATUS WINAPI
CreateNlsSecurityDescriptor(PSECURITY_DESCRIPTOR SecurityDescriptor
,ULONG Size
,ULONG AccessMask
)
2070 BOOL WINAPI
IsValidUILanguage(LANGID langid
)
2079 VOID WINAPI
NlsConvertIntegerToString(ULONG Value
,ULONG Base
,ULONG strsize
, LPWSTR str
, ULONG strsize2
)
2087 UINT WINAPI
SetCPGlobal(UINT CodePage
)
2098 ValidateLCType(int a1
, unsigned int a2
, int a3
, int a4
)
2109 NlsResetProcessLocale(VOID
)
2120 GetDefaultSortkeySize(LPVOID lpUnknown
)
2131 GetLinguistLangSize(LPVOID lpUnknown
)
2142 ValidateLocale(IN ULONG LocaleId
)
2153 NlsGetCacheUpdateCount(VOID
)
2164 IsNLSDefinedString(IN NLS_FUNCTION Function
,
2166 IN LPNLSVERSIONINFO lpVersionInformation
,
2167 IN LPCWSTR lpString
,
2179 GetNLSVersion(IN NLS_FUNCTION Function
,
2181 IN OUT LPNLSVERSIONINFO lpVersionInformation
)