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
;
442 /* Get code page table. */
443 CodePageEntry
= IntGetCodePageEntry(CodePage
);
444 if (CodePageEntry
== NULL
)
446 SetLastError(ERROR_INVALID_PARAMETER
);
449 CodePageTable
= &CodePageEntry
->CodePageTable
;
451 /* Different handling for DBCS code pages. */
452 if (CodePageTable
->MaximumCharacterSize
> 1)
456 LPCSTR MbsEnd
= MultiByteString
+ MultiByteCount
;
459 if (Flags
& MB_ERR_INVALID_CHARS
)
462 DPRINT1("IntMultiByteToWideCharCP: MB_ERR_INVALID_CHARS case not implemented!\n");
465 /* Does caller query for output buffer size? */
466 if (WideCharCount
== 0)
468 for (; MultiByteString
< MbsEnd
; WideCharCount
++)
470 Char
= *MultiByteString
++;
475 DBCSOffset
= CodePageTable
->DBCSOffsets
[Char
];
480 if (MultiByteString
< MbsEnd
)
484 return WideCharCount
;
487 for (Count
= 0; Count
< WideCharCount
&& MultiByteString
< MbsEnd
; Count
++)
489 Char
= *MultiByteString
++;
493 *WideCharString
++ = Char
;
497 DBCSOffset
= CodePageTable
->DBCSOffsets
[Char
];
501 *WideCharString
++ = CodePageTable
->MultiByteTable
[Char
];
505 if (MultiByteString
< MbsEnd
)
506 *WideCharString
++ = CodePageTable
->DBCSOffsets
[DBCSOffset
+ *(PUCHAR
)MultiByteString
++];
509 if (MultiByteString
< MbsEnd
)
511 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
517 else /* Not DBCS code page */
519 /* Check for invalid characters. */
520 if (Flags
& MB_ERR_INVALID_CHARS
)
522 for (TempString
= MultiByteString
, TempLength
= MultiByteCount
;
524 TempString
++, TempLength
--)
526 if (CodePageTable
->MultiByteTable
[(UCHAR
)*TempString
] ==
527 CodePageTable
->UniDefaultChar
&&
528 *TempString
!= CodePageEntry
->CodePageTable
.DefaultChar
)
530 SetLastError(ERROR_NO_UNICODE_TRANSLATION
);
536 /* Does caller query for output buffer size? */
537 if (WideCharCount
== 0)
538 return MultiByteCount
;
540 /* Fill the WideCharString buffer with what will fit: Verified on WinXP */
541 for (TempLength
= (WideCharCount
< MultiByteCount
) ? WideCharCount
: MultiByteCount
;
543 MultiByteString
++, TempLength
--)
545 *WideCharString
++ = CodePageTable
->MultiByteTable
[(UCHAR
)*MultiByteString
];
548 /* Adjust buffer size. Wine trick ;-) */
549 if (WideCharCount
< MultiByteCount
)
551 MultiByteCount
= WideCharCount
;
552 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
555 return MultiByteCount
;
560 * @name IntMultiByteToWideCharSYMBOL
562 * Internal version of MultiByteToWideChar for SYMBOL.
564 * @see MultiByteToWideChar
570 IntMultiByteToWideCharSYMBOL(DWORD Flags
,
571 LPCSTR MultiByteString
,
573 LPWSTR WideCharString
,
583 SetLastError(ERROR_INVALID_FLAGS
);
587 if (WideCharCount
== 0)
589 return MultiByteCount
;
592 WideCharMaxLen
= WideCharCount
> MultiByteCount
? MultiByteCount
: WideCharCount
;
594 for (Count
= 0; Count
< WideCharMaxLen
; Count
++)
596 Char
= MultiByteString
[Count
];
599 WideCharString
[Count
] = Char
;
603 WideCharString
[Count
] = Char
+ 0xf000;
606 if (MultiByteCount
> WideCharMaxLen
)
608 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
612 return WideCharMaxLen
;
616 * @name IntWideCharToMultiByteSYMBOL
618 * Internal version of WideCharToMultiByte for SYMBOL.
620 * @see WideCharToMultiByte
625 IntWideCharToMultiByteSYMBOL(DWORD Flags
,
626 LPCWSTR WideCharString
,
628 LPSTR MultiByteString
,
637 SetLastError(ERROR_INVALID_PARAMETER
);
642 if (MultiByteCount
== 0)
644 return WideCharCount
;
647 MaxLen
= MultiByteCount
> WideCharCount
? WideCharCount
: MultiByteCount
;
648 for (Count
= 0; Count
< MaxLen
; Count
++)
650 Char
= WideCharString
[Count
];
653 MultiByteString
[Count
] = (CHAR
)Char
;
657 if ((Char
>= 0xf020) && (Char
< 0xf100))
659 MultiByteString
[Count
] = Char
- 0xf000;
663 SetLastError(ERROR_NO_UNICODE_TRANSLATION
);
669 if (WideCharCount
> MaxLen
)
671 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
678 * @name IntWideCharToMultiByteUTF8
680 * Internal version of WideCharToMultiByte for UTF8.
682 * @see WideCharToMultiByte
687 IntWideCharToMultiByteUTF8(UINT CodePage
,
689 LPCWSTR WideCharString
,
691 LPSTR MultiByteString
,
694 LPBOOL UsedDefaultChar
)
699 /* Does caller query for output buffer size? */
700 if (MultiByteCount
== 0)
702 for (TempLength
= 0; WideCharCount
;
703 WideCharCount
--, WideCharString
++)
706 if (*WideCharString
>= 0x80)
709 if (*WideCharString
>= 0x800)
716 for (TempLength
= MultiByteCount
; WideCharCount
; WideCharCount
--, WideCharString
++)
718 Char
= *WideCharString
;
723 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
727 *MultiByteString
++ = (CHAR
)Char
;
731 if (Char
< 0x800) /* 0x80-0x7ff: 2 bytes */
735 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
738 MultiByteString
[1] = 0x80 | (Char
& 0x3f); Char
>>= 6;
739 MultiByteString
[0] = 0xc0 | Char
;
740 MultiByteString
+= 2;
745 /* 0x800-0xffff: 3 bytes */
748 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
751 MultiByteString
[2] = 0x80 | (Char
& 0x3f); Char
>>= 6;
752 MultiByteString
[1] = 0x80 | (Char
& 0x3f); Char
>>= 6;
753 MultiByteString
[0] = 0xe0 | Char
;
754 MultiByteString
+= 3;
758 return MultiByteCount
- TempLength
;
762 * @name IsValidSBCSMapping
764 * Checks if ch (single-byte character) is a valid mapping for wch
766 * @see IntWideCharToMultiByteCP
771 IntIsValidSBCSMapping(PCPTABLEINFO CodePageTable
, DWORD Flags
, WCHAR wch
, UCHAR ch
)
773 /* If the WC_NO_BEST_FIT_CHARS flag has been specified, the characters need to match exactly. */
774 if (Flags
& WC_NO_BEST_FIT_CHARS
)
775 return (CodePageTable
->MultiByteTable
[ch
] == wch
);
777 /* By default, all characters except TransDefaultChar apply as a valid mapping
778 for ch (so also "nearest" characters) */
779 if (ch
!= CodePageTable
->TransDefaultChar
)
782 /* The only possible left valid mapping is the default character itself */
783 return (wch
== CodePageTable
->TransUniDefaultChar
);
787 * @name IsValidDBCSMapping
789 * Checks if ch (double-byte character) is a valid mapping for wch
791 * @see IntWideCharToMultiByteCP
794 IntIsValidDBCSMapping(PCPTABLEINFO CodePageTable
, DWORD Flags
, WCHAR wch
, USHORT ch
)
796 /* If ch is the default character, but the wch is not, it can't be a valid mapping */
797 if (ch
== CodePageTable
->TransDefaultChar
&& wch
!= CodePageTable
->TransUniDefaultChar
)
800 /* If the WC_NO_BEST_FIT_CHARS flag has been specified, the characters need to match exactly. */
801 if (Flags
& WC_NO_BEST_FIT_CHARS
)
805 USHORT uOffset
= CodePageTable
->DBCSOffsets
[ch
>> 8];
806 /* if (!uOffset) return (CodePageTable->MultiByteTable[ch] == wch); */
807 return (CodePageTable
->DBCSOffsets
[uOffset
+ (ch
& 0xff)] == wch
);
810 return (CodePageTable
->MultiByteTable
[ch
] == wch
);
813 /* If we're still here, we have a valid mapping */
818 * @name IntWideCharToMultiByteCP
820 * Internal version of WideCharToMultiByte for code page tables.
822 * @see WideCharToMultiByte
823 * @todo Handle WC_COMPOSITECHECK
828 IntWideCharToMultiByteCP(UINT CodePage
,
830 LPCWSTR WideCharString
,
832 LPSTR MultiByteString
,
835 LPBOOL UsedDefaultChar
)
837 PCODEPAGE_ENTRY CodePageEntry
;
838 PCPTABLEINFO CodePageTable
;
841 /* Get code page table. */
842 CodePageEntry
= IntGetCodePageEntry(CodePage
);
843 if (CodePageEntry
== NULL
)
845 SetLastError(ERROR_INVALID_PARAMETER
);
848 CodePageTable
= &CodePageEntry
->CodePageTable
;
851 /* Different handling for DBCS code pages. */
852 if (CodePageTable
->MaximumCharacterSize
> 1)
854 /* If Flags, DefaultChar or UsedDefaultChar were given, we have to do some more work */
855 if(Flags
|| DefaultChar
|| UsedDefaultChar
)
857 BOOL TempUsedDefaultChar
;
860 /* If UsedDefaultChar is not set, set it to a temporary value, so we don't have
861 to check on every character */
863 UsedDefaultChar
= &TempUsedDefaultChar
;
865 *UsedDefaultChar
= FALSE
;
867 /* Use the CodePage's TransDefaultChar if none was given. Don't modify the DefaultChar pointer here. */
869 DefChar
= DefaultChar
[1] ? ((DefaultChar
[0] << 8) | DefaultChar
[1]) : DefaultChar
[0];
871 DefChar
= CodePageTable
->TransDefaultChar
;
873 /* Does caller query for output buffer size? */
876 for(TempLength
= 0; WideCharCount
; WideCharCount
--, WideCharString
++, TempLength
++)
880 if ((Flags
& WC_COMPOSITECHECK
) && WideCharCount
> 1)
882 /* FIXME: Handle WC_COMPOSITECHECK */
885 uChar
= ((PUSHORT
) CodePageTable
->WideCharTable
)[*WideCharString
];
887 /* Verify if the mapping is valid for handling DefaultChar and UsedDefaultChar */
888 if (!IntIsValidDBCSMapping(CodePageTable
, Flags
, *WideCharString
, uChar
))
891 *UsedDefaultChar
= TRUE
;
894 /* Increment TempLength again if this is a double-byte character */
902 /* Convert the WideCharString to the MultiByteString and verify if the mapping is valid */
903 for(TempLength
= MultiByteCount
;
904 WideCharCount
&& TempLength
;
905 TempLength
--, WideCharString
++, WideCharCount
--)
909 if ((Flags
& WC_COMPOSITECHECK
) && WideCharCount
> 1)
911 /* FIXME: Handle WC_COMPOSITECHECK */
914 uChar
= ((PUSHORT
)CodePageTable
->WideCharTable
)[*WideCharString
];
916 /* Verify if the mapping is valid for handling DefaultChar and UsedDefaultChar */
917 if (!IntIsValidDBCSMapping(CodePageTable
, Flags
, *WideCharString
, uChar
))
920 *UsedDefaultChar
= TRUE
;
923 /* Handle double-byte characters */
926 /* Don't output a partial character */
931 *MultiByteString
++ = uChar
>> 8;
934 *MultiByteString
++ = (char)uChar
;
937 /* WideCharCount should be 0 if all characters were converted */
940 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
944 return MultiByteCount
- TempLength
;
947 /* Does caller query for output buffer size? */
950 for (TempLength
= 0; WideCharCount
; WideCharCount
--, WideCharString
++, TempLength
++)
952 /* Increment TempLength again if this is a double-byte character */
953 if (((PWCHAR
)CodePageTable
->WideCharTable
)[*WideCharString
] & 0xff00)
960 /* Convert the WideCharString to the MultiByteString */
961 for (TempLength
= MultiByteCount
;
962 WideCharCount
&& TempLength
;
963 TempLength
--, WideCharString
++, WideCharCount
--)
965 USHORT uChar
= ((PUSHORT
) CodePageTable
->WideCharTable
)[*WideCharString
];
967 /* Is this a double-byte character? */
970 /* Don't output a partial character */
975 *MultiByteString
++ = uChar
>> 8;
978 *MultiByteString
++ = (char)uChar
;
981 /* WideCharCount should be 0 if all characters were converted */
984 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
988 return MultiByteCount
- TempLength
;
990 else /* Not DBCS code page */
994 /* If Flags, DefaultChar or UsedDefaultChar were given, we have to do some more work */
995 if (Flags
|| DefaultChar
|| UsedDefaultChar
)
997 BOOL TempUsedDefaultChar
;
1000 /* If UsedDefaultChar is not set, set it to a temporary value, so we don't have
1001 to check on every character */
1002 if (!UsedDefaultChar
)
1003 UsedDefaultChar
= &TempUsedDefaultChar
;
1005 *UsedDefaultChar
= FALSE
;
1007 /* Does caller query for output buffer size? */
1008 if (!MultiByteCount
)
1010 /* Loop through the whole WideCharString and check if we can get a valid mapping for each character */
1011 for (TempLength
= 0; WideCharCount
; TempLength
++, WideCharString
++, WideCharCount
--)
1013 if ((Flags
& WC_COMPOSITECHECK
) && WideCharCount
> 1)
1015 /* FIXME: Handle WC_COMPOSITECHECK */
1018 if (!*UsedDefaultChar
)
1019 *UsedDefaultChar
= !IntIsValidSBCSMapping(CodePageTable
,
1022 ((PCHAR
)CodePageTable
->WideCharTable
)[*WideCharString
]);
1028 /* Use the CodePage's TransDefaultChar if none was given. Don't modify the DefaultChar pointer here. */
1030 DefChar
= *DefaultChar
;
1032 DefChar
= (CHAR
)CodePageTable
->TransDefaultChar
;
1034 /* Convert the WideCharString to the MultiByteString and verify if the mapping is valid */
1035 for (TempLength
= MultiByteCount
;
1036 WideCharCount
&& TempLength
;
1037 MultiByteString
++, TempLength
--, WideCharString
++, WideCharCount
--)
1039 if ((Flags
& WC_COMPOSITECHECK
) && WideCharCount
> 1)
1041 /* FIXME: Handle WC_COMPOSITECHECK */
1044 *MultiByteString
= ((PCHAR
)CodePageTable
->WideCharTable
)[*WideCharString
];
1046 if (!IntIsValidSBCSMapping(CodePageTable
, Flags
, *WideCharString
, *MultiByteString
))
1048 *MultiByteString
= DefChar
;
1049 *UsedDefaultChar
= TRUE
;
1053 /* WideCharCount should be 0 if all characters were converted */
1056 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
1060 return MultiByteCount
- TempLength
;
1063 /* Does caller query for output buffer size? */
1064 if (!MultiByteCount
)
1065 return WideCharCount
;
1067 /* Is the buffer large enough? */
1068 if (MultiByteCount
< WideCharCount
)
1070 /* Convert the string up to MultiByteCount and return 0 */
1071 WideCharCount
= MultiByteCount
;
1072 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
1077 /* Otherwise WideCharCount will be the number of converted characters */
1078 nReturn
= WideCharCount
;
1081 /* Convert the WideCharString to the MultiByteString */
1082 for (TempLength
= WideCharCount
; --TempLength
>= 0; WideCharString
++, MultiByteString
++)
1084 *MultiByteString
= ((PCHAR
)CodePageTable
->WideCharTable
)[*WideCharString
];
1092 * @name IntIsLeadByte
1094 * Internal function to detect if byte is lead byte in specific character
1100 IntIsLeadByte(PCPTABLEINFO TableInfo
, BYTE Byte
)
1104 if (TableInfo
->MaximumCharacterSize
== 2)
1106 for (i
= 0; i
< MAXIMUM_LEADBYTES
&& TableInfo
->LeadByte
[i
]; i
+= 2)
1108 if (Byte
>= TableInfo
->LeadByte
[i
] && Byte
<= TableInfo
->LeadByte
[i
+1])
1116 /* PUBLIC FUNCTIONS ***********************************************************/
1119 * @name GetNlsSectionName
1121 * Construct a name of NLS section.
1126 * Integer base used for converting to string. Usually set to 10.
1128 * As the name suggests the meaning of this parameter is unknown.
1129 * The native version of Kernel32 passes it as the third parameter
1130 * to NlsConvertIntegerToString function, which is used for the
1131 * actual conversion of the code page number.
1133 * Base name of the section. (ex. "\\Nls\\NlsSectionCP")
1135 * Buffer that will hold the constructed name.
1137 * Size of the buffer for the result.
1139 * @return TRUE if the buffer was large enough and was filled with
1140 * the requested information, FALSE otherwise.
1147 GetNlsSectionName(UINT CodePage
,
1156 if (!NT_SUCCESS(RtlIntegerToChar(CodePage
, Base
, sizeof(Integer
), Integer
)))
1160 * If the name including the terminating NULL character doesn't
1161 * fit in the output buffer then fail.
1163 if (strlen(Integer
) + strlen(BaseName
) >= ResultSize
)
1166 lstrcpyA(Result
, BaseName
);
1167 lstrcatA(Result
, Integer
);
1173 * @name GetCPFileNameFromRegistry
1175 * Get file name of code page definition file.
1178 * Code page number to get file name of.
1180 * Buffer that is filled with file name of successful return. Can
1182 * @param FileNameSize
1183 * Size of the buffer to hold file name in WCHARs.
1185 * @return TRUE if the file name was retrieved, FALSE otherwise.
1192 GetCPFileNameFromRegistry(UINT CodePage
, LPWSTR FileName
, ULONG FileNameSize
)
1194 WCHAR ValueNameBuffer
[11];
1195 UNICODE_STRING KeyName
, ValueName
;
1196 OBJECT_ATTRIBUTES ObjectAttributes
;
1199 PKEY_VALUE_PARTIAL_INFORMATION Kvpi
;
1205 /* Convert the codepage number to string. */
1206 ValueName
.Buffer
= ValueNameBuffer
;
1207 ValueName
.MaximumLength
= sizeof(ValueNameBuffer
);
1209 if (!NT_SUCCESS(RtlIntegerToUnicodeString(CodePage
, 10, &ValueName
)))
1212 /* Open the registry key containing file name mappings. */
1213 RtlInitUnicodeString(&KeyName
, L
"\\Registry\\Machine\\System\\"
1214 L
"CurrentControlSet\\Control\\Nls\\CodePage");
1215 InitializeObjectAttributes(&ObjectAttributes
, &KeyName
, OBJ_CASE_INSENSITIVE
,
1217 Status
= NtOpenKey(&KeyHandle
, KEY_READ
, &ObjectAttributes
);
1218 if (!NT_SUCCESS(Status
))
1223 /* Allocate buffer that will be used to query the value data. */
1224 KvpiSize
= sizeof(KEY_VALUE_PARTIAL_INFORMATION
) + (MAX_PATH
* sizeof(WCHAR
));
1225 Kvpi
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, KvpiSize
);
1232 /* Query the file name for our code page. */
1233 Status
= NtQueryValueKey(KeyHandle
, &ValueName
, KeyValuePartialInformation
,
1234 Kvpi
, KvpiSize
, &KvpiSize
);
1238 /* Check if we succeded and the value is non-empty string. */
1239 if (NT_SUCCESS(Status
) && Kvpi
->Type
== REG_SZ
&&
1240 Kvpi
->DataLength
> sizeof(WCHAR
))
1243 if (FileName
!= NULL
)
1245 lstrcpynW(FileName
, (WCHAR
*)Kvpi
->Data
,
1246 min(Kvpi
->DataLength
/ sizeof(WCHAR
), FileNameSize
));
1250 /* free temporary buffer */
1251 HeapFree(GetProcessHeap(),0,Kvpi
);
1256 * @name IsValidCodePage
1258 * Detect if specified code page is valid and present in the system.
1261 * Code page number to query.
1263 * @return TRUE if code page is present.
1268 IsValidCodePage(UINT CodePage
)
1270 if (CodePage
== 0) return FALSE
;
1271 if (CodePage
== CP_UTF8
|| CodePage
== CP_UTF7
)
1273 if (IntGetLoadedCodePageEntry(CodePage
))
1275 return GetCPFileNameFromRegistry(CodePage
, NULL
, 0);
1278 static inline BOOL
utf7_write_w(WCHAR
*dst
, int dstlen
, int *index
, WCHAR character
)
1282 if (*index
>= dstlen
)
1285 dst
[*index
] = character
;
1293 static INT
Utf7ToWideChar(const char *src
, int srclen
, WCHAR
*dst
, int dstlen
)
1295 static const signed char base64_decoding_table
[] =
1297 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 0x00-0x0F */
1298 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 0x10-0x1F */
1299 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 62, -1, -1, -1, 63, /* 0x20-0x2F */
1300 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, -1, -1, -1, -1, -1, -1, /* 0x30-0x3F */
1301 -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, /* 0x40-0x4F */
1302 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, -1, -1, -1, -1, -1, /* 0x50-0x5F */
1303 -1, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, /* 0x60-0x6F */
1304 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, -1, -1, -1, -1, -1 /* 0x70-0x7F */
1307 const char *source_end
= src
+ srclen
;
1310 DWORD byte_pair
= 0;
1313 while (src
< source_end
)
1318 if (src
>= source_end
)
1323 /* just a plus sign escaped as +- */
1324 if (!utf7_write_w(dst
, dstlen
, &dest_index
, '+'))
1326 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
1335 signed char sextet
= *src
;
1338 /* skip over the dash and end base64 decoding
1339 * the current, unfinished byte pair is discarded */
1346 /* the next character of src is < 0 and therefore not part of a base64 sequence
1347 * the current, unfinished byte pair is NOT discarded in this case
1348 * this is probably a bug in Windows */
1352 sextet
= base64_decoding_table
[sextet
];
1355 /* -1 means that the next character of src is not part of a base64 sequence
1356 * in other words, all sextets in this base64 sequence have been processed
1357 * the current, unfinished byte pair is discarded */
1362 byte_pair
= (byte_pair
<< 6) | sextet
;
1367 /* this byte pair is done */
1368 if (!utf7_write_w(dst
, dstlen
, &dest_index
, (byte_pair
>> (offset
- 16)) & 0xFFFF))
1370 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
1378 while (src
< source_end
);
1382 /* we have to convert to unsigned char in case *src < 0 */
1383 if (!utf7_write_w(dst
, dstlen
, &dest_index
, (unsigned char)*src
))
1385 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
1396 * @name MultiByteToWideChar
1398 * Convert a multi-byte string to wide-charater equivalent.
1401 * Code page to be used to perform the conversion. It can be also
1402 * one of the special values (CP_ACP for ANSI code page, CP_MACCP
1403 * for Macintosh code page, CP_OEMCP for OEM code page, CP_THREAD_ACP
1404 * for thread active code page, CP_UTF7 or CP_UTF8).
1406 * Additional conversion flags (MB_PRECOMPOSED, MB_COMPOSITE,
1407 * MB_ERR_INVALID_CHARS, MB_USEGLYPHCHARS).
1408 * @param MultiByteString
1410 * @param MultiByteCount
1411 * Size of MultiByteString, or -1 if MultiByteString is NULL
1413 * @param WideCharString
1415 * @param WideCharCount
1416 * Size in WCHARs of WideCharString, or 0 if the caller just wants
1417 * to know how large WideCharString should be for a successful
1420 * @return Zero on error, otherwise the number of WCHARs written
1421 * in the WideCharString buffer.
1428 MultiByteToWideChar(UINT CodePage
,
1430 LPCSTR MultiByteString
,
1432 LPWSTR WideCharString
,
1435 /* Check the parameters. */
1436 if (MultiByteString
== NULL
||
1437 MultiByteCount
== 0 ||
1438 (WideCharString
== NULL
&& WideCharCount
> 0) ||
1439 (PVOID
)MultiByteString
== (PVOID
)WideCharString
)
1441 SetLastError(ERROR_INVALID_PARAMETER
);
1445 /* Determine the input string length. */
1446 if (MultiByteCount
< 0)
1448 MultiByteCount
= lstrlenA(MultiByteString
) + 1;
1454 return IntMultiByteToWideCharUTF8(Flags
,
1463 SetLastError(ERROR_INVALID_FLAGS
);
1466 return Utf7ToWideChar(MultiByteString
, MultiByteCount
,
1467 WideCharString
, WideCharCount
);
1470 return IntMultiByteToWideCharSYMBOL(Flags
,
1476 return IntMultiByteToWideCharCP(CodePage
,
1485 static inline BOOL
utf7_can_directly_encode(WCHAR codepoint
)
1487 static const BOOL directly_encodable_table
[] =
1489 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 1, 0, 0, /* 0x00 - 0x0F */
1490 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x10 - 0x1F */
1491 1, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 1, 1, 1, 1, 1, /* 0x20 - 0x2F */
1492 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 1, /* 0x30 - 0x3F */
1493 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 0x40 - 0x4F */
1494 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, /* 0x50 - 0x5F */
1495 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 0x60 - 0x6F */
1496 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 /* 0x70 - 0x7A */
1499 return codepoint
<= 0x7A ? directly_encodable_table
[codepoint
] : FALSE
;
1502 static inline BOOL
utf7_write_c(char *dst
, int dstlen
, int *index
, char character
)
1506 if (*index
>= dstlen
)
1509 dst
[*index
] = character
;
1517 static INT
WideCharToUtf7(const WCHAR
*src
, int srclen
, char *dst
, int dstlen
)
1519 static const char base64_encoding_table
[] =
1520 "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
1522 const WCHAR
*source_end
= src
+ srclen
;
1525 while (src
< source_end
)
1529 if (!utf7_write_c(dst
, dstlen
, &dest_index
, '+'))
1531 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
1534 if (!utf7_write_c(dst
, dstlen
, &dest_index
, '-'))
1536 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
1541 else if (utf7_can_directly_encode(*src
))
1543 if (!utf7_write_c(dst
, dstlen
, &dest_index
, *src
))
1545 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
1552 unsigned int offset
= 0;
1553 DWORD byte_pair
= 0;
1555 if (!utf7_write_c(dst
, dstlen
, &dest_index
, '+'))
1557 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
1561 while (src
< source_end
&& !utf7_can_directly_encode(*src
))
1563 byte_pair
= (byte_pair
<< 16) | *src
;
1567 if (!utf7_write_c(dst
, dstlen
, &dest_index
, base64_encoding_table
[(byte_pair
>> (offset
- 6)) & 0x3F]))
1569 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
1579 /* Windows won't create a padded base64 character if there's no room for the - sign
1580 * as well ; this is probably a bug in Windows */
1581 if (dstlen
> 0 && dest_index
+ 1 >= dstlen
)
1583 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
1587 byte_pair
<<= (6 - offset
);
1588 if (!utf7_write_c(dst
, dstlen
, &dest_index
, base64_encoding_table
[byte_pair
& 0x3F]))
1590 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
1595 /* Windows always explicitly terminates the base64 sequence
1596 even though RFC 2152 (page 3, rule 2) does not require this */
1597 if (!utf7_write_c(dst
, dstlen
, &dest_index
, '-'))
1599 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
1609 GetLocalisedText(DWORD dwResId
, WCHAR
*lpszDest
, DWORD dwDestSize
)
1617 dwId
= dwResId
* 100;
1621 lcid
= GetUserDefaultLCID();
1622 lcid
= ConvertDefaultLocale(lcid
);
1624 langId
= LANGIDFROMLCID(lcid
);
1626 if (PRIMARYLANGID(langId
) == LANG_NEUTRAL
)
1627 langId
= MAKELANGID(LANG_ENGLISH
, SUBLANG_ENGLISH_US
);
1629 hrsrc
= FindResourceExW(hCurrentModule
,
1631 MAKEINTRESOURCEW((dwId
>> 4) + 1),
1634 /* english fallback */
1637 hrsrc
= FindResourceExW(hCurrentModule
,
1639 MAKEINTRESOURCEW((dwId
>> 4) + 1),
1640 MAKELANGID(LANG_ENGLISH
, SUBLANG_ENGLISH_US
));
1645 HGLOBAL hmem
= LoadResource(hCurrentModule
, hrsrc
);
1653 p
= LockResource(hmem
);
1655 for (i
= 0; i
< (dwId
& 0x0f); i
++) p
+= *p
+ 1;
1660 len
= *p
* sizeof(WCHAR
);
1662 if(len
+ sizeof(WCHAR
) > dwDestSize
)
1664 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
1668 memcpy(lpszDest
, p
+ 1, len
);
1669 lpszDest
[*p
] = '\0';
1675 DPRINT1("Resource not found: dwResId = %lu\n", dwResId
);
1676 SetLastError(ERROR_INVALID_PARAMETER
);
1685 GetCPInfo(UINT CodePage
,
1686 LPCPINFO CodePageInfo
)
1688 PCODEPAGE_ENTRY CodePageEntry
;
1692 SetLastError(ERROR_INVALID_PARAMETER
);
1696 CodePageEntry
= IntGetCodePageEntry(CodePage
);
1697 if (CodePageEntry
== NULL
)
1703 CodePageInfo
->DefaultChar
[0] = 0x3f;
1704 CodePageInfo
->DefaultChar
[1] = 0;
1705 CodePageInfo
->LeadByte
[0] = CodePageInfo
->LeadByte
[1] = 0;
1706 CodePageInfo
->MaxCharSize
= (CodePage
== CP_UTF7
) ? 5 : 4;
1710 DPRINT1("Invalid CP!: %lx\n", CodePage
);
1711 SetLastError( ERROR_INVALID_PARAMETER
);
1715 if (CodePageEntry
->CodePageTable
.DefaultChar
& 0xff00)
1717 CodePageInfo
->DefaultChar
[0] = (CodePageEntry
->CodePageTable
.DefaultChar
& 0xff00) >> 8;
1718 CodePageInfo
->DefaultChar
[1] = CodePageEntry
->CodePageTable
.DefaultChar
& 0x00ff;
1722 CodePageInfo
->DefaultChar
[0] = CodePageEntry
->CodePageTable
.DefaultChar
& 0xff;
1723 CodePageInfo
->DefaultChar
[1] = 0;
1726 if ((CodePageInfo
->MaxCharSize
= CodePageEntry
->CodePageTable
.MaximumCharacterSize
) == 2)
1727 memcpy(CodePageInfo
->LeadByte
, CodePageEntry
->CodePageTable
.LeadByte
, sizeof(CodePageInfo
->LeadByte
));
1729 CodePageInfo
->LeadByte
[0] = CodePageInfo
->LeadByte
[1] = 0;
1739 GetCPInfoExW(UINT CodePage
,
1741 LPCPINFOEXW lpCPInfoEx
)
1743 if (!GetCPInfo(CodePage
, (LPCPINFO
) lpCPInfoEx
))
1750 lpCPInfoEx
->CodePage
= CP_UTF7
;
1751 lpCPInfoEx
->UnicodeDefaultChar
= 0x3f;
1752 return GetLocalisedText((DWORD
)CodePage
, lpCPInfoEx
->CodePageName
, sizeof(lpCPInfoEx
->CodePageName
)) != 0;
1758 lpCPInfoEx
->CodePage
= CP_UTF8
;
1759 lpCPInfoEx
->UnicodeDefaultChar
= 0x3f;
1760 return GetLocalisedText((DWORD
)CodePage
, lpCPInfoEx
->CodePageName
, sizeof(lpCPInfoEx
->CodePageName
)) != 0;
1765 PCODEPAGE_ENTRY CodePageEntry
;
1767 CodePageEntry
= IntGetCodePageEntry(CodePage
);
1768 if (CodePageEntry
== NULL
)
1770 DPRINT1("Could not get CodePage Entry! CodePageEntry = 0\n");
1771 SetLastError(ERROR_INVALID_PARAMETER
);
1775 lpCPInfoEx
->CodePage
= CodePageEntry
->CodePageTable
.CodePage
;
1776 lpCPInfoEx
->UnicodeDefaultChar
= CodePageEntry
->CodePageTable
.UniDefaultChar
;
1777 return GetLocalisedText(CodePageEntry
->CodePageTable
.CodePage
, lpCPInfoEx
->CodePageName
, sizeof(lpCPInfoEx
->CodePageName
)) != 0;
1789 GetCPInfoExA(UINT CodePage
,
1791 LPCPINFOEXA lpCPInfoEx
)
1795 if (!GetCPInfoExW(CodePage
, dwFlags
, &CPInfo
))
1798 /* the layout is the same except for CodePageName */
1799 memcpy(lpCPInfoEx
, &CPInfo
, sizeof(CPINFOEXA
));
1801 WideCharToMultiByte(CP_ACP
,
1803 CPInfo
.CodePageName
,
1805 lpCPInfoEx
->CodePageName
,
1806 sizeof(lpCPInfoEx
->CodePageName
),
1813 * @name WideCharToMultiByte
1815 * Convert a wide-charater string to closest multi-byte equivalent.
1818 * Code page to be used to perform the conversion. It can be also
1819 * one of the special values (CP_ACP for ANSI code page, CP_MACCP
1820 * for Macintosh code page, CP_OEMCP for OEM code page, CP_THREAD_ACP
1821 * for thread active code page, CP_UTF7 or CP_UTF8).
1823 * Additional conversion flags (WC_NO_BEST_FIT_CHARS, WC_COMPOSITECHECK,
1824 * WC_DISCARDNS, WC_SEPCHARS, WC_DEFAULTCHAR).
1825 * @param WideCharString
1826 * Points to the wide-character string to be converted.
1827 * @param WideCharCount
1828 * Size in WCHARs of WideCharStr, or 0 if the caller just wants to
1829 * know how large WideCharString should be for a successful conversion.
1830 * @param MultiByteString
1831 * Points to the buffer to receive the translated string.
1832 * @param MultiByteCount
1833 * Specifies the size in bytes of the buffer pointed to by the
1834 * MultiByteString parameter. If this value is zero, the function
1835 * returns the number of bytes required for the buffer.
1836 * @param DefaultChar
1837 * Points to the character used if a wide character cannot be
1838 * represented in the specified code page. If this parameter is
1839 * NULL, a system default value is used.
1840 * @param UsedDefaultChar
1841 * Points to a flag that indicates whether a default character was
1842 * used. This parameter can be NULL.
1844 * @return Zero on error, otherwise the number of bytes written in the
1845 * MultiByteString buffer. Or the number of bytes needed for
1846 * the MultiByteString buffer if MultiByteCount is zero.
1853 WideCharToMultiByte(UINT CodePage
,
1855 LPCWSTR WideCharString
,
1857 LPSTR MultiByteString
,
1860 LPBOOL UsedDefaultChar
)
1862 /* Check the parameters. */
1863 if (WideCharString
== NULL
||
1864 WideCharCount
== 0 ||
1865 (MultiByteString
== NULL
&& MultiByteCount
> 0) ||
1866 (PVOID
)WideCharString
== (PVOID
)MultiByteString
||
1869 SetLastError(ERROR_INVALID_PARAMETER
);
1873 /* Determine the input string length. */
1874 if (WideCharCount
< 0)
1876 WideCharCount
= lstrlenW(WideCharString
) + 1;
1882 if (DefaultChar
!= NULL
|| UsedDefaultChar
!= NULL
)
1884 SetLastError(ERROR_INVALID_PARAMETER
);
1887 return IntWideCharToMultiByteUTF8(CodePage
,
1897 if (DefaultChar
!= NULL
|| UsedDefaultChar
!= NULL
)
1899 SetLastError(ERROR_INVALID_PARAMETER
);
1904 SetLastError(ERROR_INVALID_FLAGS
);
1907 return WideCharToUtf7(WideCharString
, WideCharCount
,
1908 MultiByteString
, MultiByteCount
);
1911 if ((DefaultChar
!=NULL
) || (UsedDefaultChar
!=NULL
))
1913 SetLastError(ERROR_INVALID_PARAMETER
);
1916 return IntWideCharToMultiByteSYMBOL(Flags
,
1923 return IntWideCharToMultiByteCP(CodePage
,
1937 * Get active ANSI code page number.
1946 return AnsiCodePage
.CodePageTable
.CodePage
;
1952 * Get active OEM code page number.
1961 return OemCodePage
.CodePageTable
.CodePage
;
1965 * @name IsDBCSLeadByteEx
1967 * Determine if passed byte is lead byte in specified code page.
1974 IsDBCSLeadByteEx(UINT CodePage
, BYTE TestByte
)
1976 PCODEPAGE_ENTRY CodePageEntry
;
1978 CodePageEntry
= IntGetCodePageEntry(CodePage
);
1979 if (CodePageEntry
!= NULL
)
1980 return IntIsLeadByte(&CodePageEntry
->CodePageTable
, TestByte
);
1982 SetLastError(ERROR_INVALID_PARAMETER
);
1987 * @name IsDBCSLeadByteEx
1989 * Determine if passed byte is lead byte in current ANSI code page.
1996 IsDBCSLeadByte(BYTE TestByte
)
1998 return IntIsLeadByte(&AnsiCodePage
.CodePageTable
, TestByte
);
2004 NTSTATUS WINAPI
CreateNlsSecurityDescriptor(PSECURITY_DESCRIPTOR SecurityDescriptor
,ULONG Size
,ULONG AccessMask
)
2013 BOOL WINAPI
IsValidUILanguage(LANGID langid
)
2022 VOID WINAPI
NlsConvertIntegerToString(ULONG Value
,ULONG Base
,ULONG strsize
, LPWSTR str
, ULONG strsize2
)
2030 UINT WINAPI
SetCPGlobal(UINT CodePage
)
2041 ValidateLCType(int a1
, unsigned int a2
, int a3
, int a4
)
2052 NlsResetProcessLocale(VOID
)
2063 GetDefaultSortkeySize(LPVOID lpUnknown
)
2074 GetLinguistLangSize(LPVOID lpUnknown
)
2085 ValidateLocale(IN ULONG LocaleId
)
2096 NlsGetCacheUpdateCount(VOID
)
2107 IsNLSDefinedString(IN NLS_FUNCTION Function
,
2109 IN LPNLSVERSIONINFO lpVersionInformation
,
2110 IN LPCWSTR lpString
,
2122 GetNLSVersion(IN NLS_FUNCTION Function
,
2124 IN OUT LPNLSVERSIONINFO lpVersionInformation
)