3 * Copyright (C) 2004 ReactOS Team
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
20 * @brief National Language Support.
21 * @author Filip Navara
24 /* INCLUDES *******************************************************************/
28 #include "../include/debug.h"
30 /* GLOBAL VARIABLES ***********************************************************/
32 typedef struct _CODEPAGE_ENTRY
38 CPTABLEINFO CodePageTable
;
39 } CODEPAGE_ENTRY
, *PCODEPAGE_ENTRY
;
41 /* Sequence length based on the first character. */
42 static const char UTF8Length
[128] =
44 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x80 - 0x8F */
45 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x90 - 0x9F */
46 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0xA0 - 0xAF */
47 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0xB0 - 0xBF */
48 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 0xC0 - 0xCF */
49 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 0xD0 - 0xDF */
50 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, /* 0xE0 - 0xEF */
51 3, 3, 3, 3, 3, 3, 3, 3, 4, 4, 4, 4, 5, 5, 0, 0 /* 0xF0 - 0xFF */
54 /* First byte mask depending on UTF-8 sequence length. */
55 static const unsigned char UTF8Mask
[6] = {0x7f, 0x1f, 0x0f, 0x07, 0x03, 0x01};
57 /* FIXME: Change to HASH table or linear array. */
58 static LIST_ENTRY CodePageListHead
;
59 static CODEPAGE_ENTRY AnsiCodePage
;
60 static CODEPAGE_ENTRY OemCodePage
;
61 static RTL_CRITICAL_SECTION CodePageListLock
;
63 /* FORWARD DECLARATIONS *******************************************************/
66 GetNlsSectionName(UINT CodePage
, UINT Base
, ULONG Unknown
,
67 LPSTR BaseName
, LPSTR Result
, ULONG ResultSize
);
70 GetCPFileNameFromRegistry(UINT CodePage
, LPWSTR FileName
, ULONG FileNameSize
);
72 /* PRIVATE FUNCTIONS **********************************************************/
75 * Internal NLS related stuff initialization.
80 UNICODE_STRING DirName
;
81 OBJECT_ATTRIBUTES ObjectAttributes
;
84 InitializeListHead(&CodePageListHead
);
85 RtlInitializeCriticalSection(&CodePageListLock
);
88 * FIXME: Eventually this should be done only for the NLS Server
89 * process, but since we don't have anything like that (yet?) we
90 * always try to create the "\Nls" directory here.
92 RtlInitUnicodeString(&DirName
, L
"\\Nls");
93 InitializeObjectAttributes(&ObjectAttributes
, &DirName
,
94 OBJ_CASE_INSENSITIVE
| OBJ_PERMANENT
,
96 if (NT_SUCCESS(NtCreateDirectoryObject(&Handle
, DIRECTORY_ALL_ACCESS
, &ObjectAttributes
)))
101 /* Setup ANSI code page. */
102 AnsiCodePage
.CodePage
= CP_ACP
;
103 AnsiCodePage
.SectionHandle
= NULL
;
104 AnsiCodePage
.SectionMapping
= NtCurrentTeb()->ProcessEnvironmentBlock
->AnsiCodePageData
;
105 RtlInitCodePageTable((PUSHORT
)AnsiCodePage
.SectionMapping
,
106 &AnsiCodePage
.CodePageTable
);
107 InsertTailList(&CodePageListHead
, &AnsiCodePage
.Entry
);
109 /* Setup OEM code page. */
110 OemCodePage
.CodePage
= CP_OEMCP
;
111 OemCodePage
.SectionHandle
= NULL
;
112 OemCodePage
.SectionMapping
= NtCurrentTeb()->ProcessEnvironmentBlock
->OemCodePageData
;
113 RtlInitCodePageTable((PUSHORT
)OemCodePage
.SectionMapping
,
114 &OemCodePage
.CodePageTable
);
115 InsertTailList(&CodePageListHead
, &OemCodePage
.Entry
);
121 * Internal NLS related stuff uninitialization.
126 PCODEPAGE_ENTRY Current
;
128 /* Delete the code page list. */
129 while (!IsListEmpty(&CodePageListHead
))
131 Current
= CONTAINING_RECORD(CodePageListHead
.Flink
, CODEPAGE_ENTRY
, Entry
);
132 if (Current
->SectionHandle
!= NULL
)
134 UnmapViewOfFile(Current
->SectionMapping
);
135 NtClose(Current
->SectionHandle
);
137 RemoveHeadList(&CodePageListHead
);
139 RtlDeleteCriticalSection(&CodePageListLock
);
143 * Internal function to get structure containing a code page information
144 * of code page that is already loaded.
147 * Number of the code page. Special values like CP_OEMCP, CP_ACP
148 * or CP_UTF8 aren't allowed.
150 * @return Code page entry or NULL if the specified code page hasn't
153 PCODEPAGE_ENTRY FASTCALL
154 IntGetLoadedCodePageEntry(UINT CodePage
)
156 LIST_ENTRY
*CurrentEntry
;
157 PCODEPAGE_ENTRY Current
;
159 RtlEnterCriticalSection(&CodePageListLock
);
160 for (CurrentEntry
= CodePageListHead
.Flink
;
161 CurrentEntry
!= &CodePageListHead
;
162 CurrentEntry
= CurrentEntry
->Flink
)
164 Current
= CONTAINING_RECORD(CurrentEntry
, CODEPAGE_ENTRY
, Entry
);
165 if (Current
->CodePage
== CodePage
)
167 RtlLeaveCriticalSection(&CodePageListLock
);
171 RtlLeaveCriticalSection(&CodePageListLock
);
177 * Internal function to get structure containing a code page information.
180 * Number of the code page. Special values like CP_OEMCP, CP_ACP
181 * or CP_THREAD_ACP are allowed, but CP_UTF[7/8] isn't.
183 * @return Code page entry.
185 PCODEPAGE_ENTRY FASTCALL
186 IntGetCodePageEntry(UINT CodePage
)
188 CHAR SectionName
[40];
190 HANDLE SectionHandle
= INVALID_HANDLE_VALUE
, FileHandle
;
191 PBYTE SectionMapping
;
192 OBJECT_ATTRIBUTES ObjectAttributes
;
193 ANSI_STRING AnsiName
;
194 UNICODE_STRING UnicodeName
;
195 WCHAR FileName
[MAX_PATH
+ 1];
197 PCODEPAGE_ENTRY CodePageEntry
;
199 if (CodePage
== CP_THREAD_ACP
)
201 if (!GetLocaleInfoW(GetThreadLocale(), LOCALE_IDEFAULTANSICODEPAGE
|
202 LOCALE_RETURN_NUMBER
, (WCHAR
*)&CodePage
,
203 sizeof(CodePage
) / sizeof(WCHAR
)))
205 /* Last error is set by GetLocaleInfoW. */
209 else if (CodePage
== CP_MACCP
)
211 if (!GetLocaleInfoW(LOCALE_SYSTEM_DEFAULT
, LOCALE_IDEFAULTMACCODEPAGE
|
212 LOCALE_RETURN_NUMBER
, (WCHAR
*)&CodePage
,
213 sizeof(CodePage
) / sizeof(WCHAR
)))
215 /* Last error is set by GetLocaleInfoW. */
220 /* Try searching for loaded page first. */
221 CodePageEntry
= IntGetLoadedCodePageEntry(CodePage
);
222 if (CodePageEntry
!= NULL
)
224 return CodePageEntry
;
228 * Yes, we really want to lock here. Otherwise it can happen that
229 * two parallel requests will try to get the entry for the same
230 * code page and we would load it twice.
232 RtlEnterCriticalSection(&CodePageListLock
);
234 /* Generate the section name. */
235 if (!GetNlsSectionName(CodePage
, 10, 0, "\\Nls\\NlsSectionCP",
236 SectionName
, sizeof(SectionName
)))
238 RtlLeaveCriticalSection(&CodePageListLock
);
241 RtlInitAnsiString(&AnsiName
, SectionName
);
242 RtlAnsiStringToUnicodeString(&UnicodeName
, &AnsiName
, TRUE
);
243 InitializeObjectAttributes(&ObjectAttributes
, &UnicodeName
, 0,
246 /* Try to open the section first */
247 Status
= NtOpenSection(&SectionHandle
, SECTION_MAP_READ
, &ObjectAttributes
);
249 /* If the section doesn't exist, try to create it. */
250 if (Status
== STATUS_UNSUCCESSFUL
||
251 Status
== STATUS_OBJECT_NAME_NOT_FOUND
||
252 Status
== STATUS_OBJECT_PATH_NOT_FOUND
)
254 FileNamePos
= GetSystemDirectoryW(FileName
, MAX_PATH
);
255 if (GetCPFileNameFromRegistry(CodePage
, FileName
+ FileNamePos
+ 1,
256 MAX_PATH
- FileNamePos
- 1))
258 FileName
[FileNamePos
] = L
'\\';
259 FileName
[MAX_PATH
] = 0;
260 FileHandle
= CreateFileW(FileName
, FILE_GENERIC_READ
, FILE_SHARE_READ
,
261 NULL
, OPEN_EXISTING
, 0, NULL
);
262 Status
= NtCreateSection(&SectionHandle
, SECTION_MAP_READ
,
263 &ObjectAttributes
, NULL
, PAGE_READONLY
,
264 SEC_FILE
, FileHandle
);
267 RtlFreeUnicodeString(&UnicodeName
);
269 if (!NT_SUCCESS(Status
))
271 RtlLeaveCriticalSection(&CodePageListLock
);
275 SectionMapping
= MapViewOfFile(SectionHandle
, FILE_MAP_READ
, 0, 0, 0);
276 if (SectionMapping
== NULL
)
278 NtClose(SectionHandle
);
279 RtlLeaveCriticalSection(&CodePageListLock
);
283 CodePageEntry
= HeapAlloc(GetProcessHeap(), 0, sizeof(CODEPAGE_ENTRY
));
284 if (CodePageEntry
== NULL
)
286 NtClose(SectionHandle
);
287 RtlLeaveCriticalSection(&CodePageListLock
);
291 CodePageEntry
->CodePage
= CodePage
;
292 CodePageEntry
->SectionHandle
= SectionHandle
;
293 CodePageEntry
->SectionMapping
= SectionMapping
;
294 RtlInitCodePageTable((PUSHORT
)SectionMapping
, &CodePageEntry
->CodePageTable
);
296 /* Insert the new entry to list and unlock. Uff. */
297 InsertTailList(&CodePageListHead
, &CodePageEntry
->Entry
);
298 RtlLeaveCriticalSection(&CodePageListLock
);
300 return CodePageEntry
;
304 * Internal version of MultiByteToWideChar for UTF8.
306 * @see MultiByteToWideChar
307 * @todo Add UTF8 validity checks.
310 IntMultiByteToWideCharUTF8(DWORD Flags
,
311 LPCSTR MultiByteString
, INT MultiByteCount
,
312 LPWSTR WideCharString
, INT WideCharCount
)
321 SetLastError(ERROR_INVALID_FLAGS
);
325 /* Does caller query for output buffer size? */
326 if (WideCharCount
== 0)
328 MbsEnd
= MultiByteString
+ MultiByteCount
;
329 for (; MultiByteString
< MbsEnd
; WideCharCount
++)
331 Char
= *MultiByteString
++;
334 MultiByteString
+= UTF8Length
[Char
- 0x80];
336 return WideCharCount
;
339 MbsEnd
= MultiByteString
+ MultiByteCount
;
340 for (Count
= 0; Count
< WideCharCount
&& MultiByteString
< MbsEnd
; Count
++)
342 Char
= *MultiByteString
++;
345 *WideCharString
++ = Char
;
348 Length
= UTF8Length
[Char
- 0x80];
349 WideChar
= Char
& UTF8Mask
[Length
];
350 while (Length
&& MultiByteString
< MbsEnd
)
352 WideChar
= (WideChar
<< 6) | *MultiByteString
++;
355 *WideCharString
++ = WideChar
;
358 if (MultiByteString
< MbsEnd
)
359 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
365 * Internal version of MultiByteToWideChar for code page tables.
367 * @see MultiByteToWideChar
368 * @todo Handle MB_PRECOMPOSED, MB_COMPOSITE, MB_USEGLYPHCHARS and
372 IntMultiByteToWideCharCP(UINT CodePage
, DWORD Flags
,
373 LPCSTR MultiByteString
, INT MultiByteCount
,
374 LPWSTR WideCharString
, INT WideCharCount
)
376 PCODEPAGE_ENTRY CodePageEntry
;
377 PCPTABLEINFO CodePageTable
;
381 /* Get code page table. */
382 CodePageEntry
= IntGetCodePageEntry(CodePage
);
383 if (CodePageEntry
== NULL
)
385 SetLastError(ERROR_INVALID_PARAMETER
);
388 CodePageTable
= &CodePageEntry
->CodePageTable
;
390 /* Different handling for DBCS code pages. */
391 if (CodePageTable
->MaximumCharacterSize
> 1)
398 /* Check for invalid characters. */
399 if (Flags
& MB_ERR_INVALID_CHARS
)
401 for (TempString
= MultiByteString
, TempLength
= MultiByteCount
;
403 TempString
++, TempLength
--)
405 if (CodePageTable
->MultiByteTable
[(UCHAR
)*TempString
] ==
406 CodePageTable
->UniDefaultChar
&&
407 *TempString
!= CodePageEntry
->CodePageTable
.DefaultChar
)
409 SetLastError(ERROR_NO_UNICODE_TRANSLATION
);
415 /* Does caller query for output buffer size? */
416 if (WideCharCount
== 0)
417 return MultiByteCount
;
419 /* Adjust buffer size. Wine trick ;-) */
420 if (WideCharCount
< MultiByteCount
)
422 MultiByteCount
= WideCharCount
;
423 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
426 for (TempLength
= MultiByteCount
;
428 MultiByteString
++, TempLength
--)
430 *WideCharString
++ = CodePageTable
->MultiByteTable
[(UCHAR
)*MultiByteString
];
433 return MultiByteCount
;
438 * Internal version of WideCharToMultiByte for UTF8.
440 * @see WideCharToMultiByte
443 IntWideCharToMultiByteUTF8(UINT CodePage
, DWORD Flags
,
444 LPCWSTR WideCharString
, INT WideCharCount
,
445 LPSTR MultiByteString
, INT MultiByteCount
,
446 LPCSTR DefaultChar
, LPBOOL UsedDefaultChar
)
451 /* Does caller query for output buffer size? */
452 if (MultiByteCount
== 0)
454 for (TempLength
= 0; WideCharCount
;
455 WideCharCount
--, WideCharString
++)
458 if (*WideCharString
>= 0x80)
461 if (*WideCharString
>= 0x800)
468 for (TempLength
= MultiByteCount
; WideCharCount
;
469 WideCharCount
--, WideCharString
++)
471 Char
= *WideCharString
;
476 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
480 *MultiByteString
++ = Char
;
484 if (Char
< 0x800) /* 0x80-0x7ff: 2 bytes */
488 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
491 MultiByteString
[1] = 0x80 | (Char
& 0x3f); Char
>>= 6;
492 MultiByteString
[0] = 0xc0 | Char
;
493 MultiByteString
+= 2;
498 /* 0x800-0xffff: 3 bytes */
501 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
504 MultiByteString
[2] = 0x80 | (Char
& 0x3f); Char
>>= 6;
505 MultiByteString
[1] = 0x80 | (Char
& 0x3f); Char
>>= 6;
506 MultiByteString
[0] = 0xe0 | Char
;
507 MultiByteString
+= 3;
511 return MultiByteCount
- TempLength
;
515 * Internal version of WideCharToMultiByte for code page tables.
517 * @see WideCharToMultiByte
518 * @todo Handle default characters and flags.
521 IntWideCharToMultiByteCP(UINT CodePage
, DWORD Flags
,
522 LPCWSTR WideCharString
, INT WideCharCount
,
523 LPSTR MultiByteString
, INT MultiByteCount
,
524 LPCSTR DefaultChar
, LPBOOL UsedDefaultChar
)
526 PCODEPAGE_ENTRY CodePageEntry
;
527 PCPTABLEINFO CodePageTable
;
530 /* Get code page table. */
531 CodePageEntry
= IntGetCodePageEntry(CodePage
);
532 if (CodePageEntry
== NULL
)
534 SetLastError(ERROR_INVALID_PARAMETER
);
537 CodePageTable
= &CodePageEntry
->CodePageTable
;
539 /* Different handling for DBCS code pages. */
540 if (CodePageTable
->MaximumCharacterSize
> 1)
542 DPRINT1("WideCharToMultiByte for DBCS codepages is not implemented!\n");
547 /* Does caller query for output buffer size? */
548 if (MultiByteCount
== 0)
549 return WideCharCount
;
551 /* Adjust buffer size. Wine trick ;-) */
552 if (MultiByteCount
< WideCharCount
)
554 WideCharCount
= MultiByteCount
;
555 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
558 for (TempLength
= WideCharCount
;
560 WideCharString
++, TempLength
--)
562 *MultiByteString
++ = ((PCHAR
)CodePageTable
->WideCharTable
)[*WideCharString
];
566 if (UsedDefaultChar
!= NULL
)
567 *UsedDefaultChar
= FALSE
;
569 return WideCharCount
;
573 /* PUBLIC FUNCTIONS ***********************************************************/
576 * Construct a name of NLS section.
581 * Integer base used for converting to string. Usually set to 10.
583 * As the name suggests the meaning of this parameter is unknown.
584 * The native version of Kernel32 passes it as the third parameter
585 * to NlsConvertIntegerToString function, which is used for the
586 * actual conversion of the code page number.
588 * Base name of the section. (ex. "\\Nls\\NlsSectionCP")
590 * Buffer that will hold the constructed name.
592 * Size of the buffer for the result.
594 * @return TRUE if the buffer was large enough and was filled with
595 * the requested information, FALSE otherwise.
600 GetNlsSectionName(UINT CodePage
, UINT Base
, ULONG Unknown
,
601 LPSTR BaseName
, LPSTR Result
, ULONG ResultSize
)
605 if (!NT_SUCCESS(RtlIntegerToChar(CodePage
, Base
, sizeof(Integer
), Integer
)))
609 * If the name including the terminating NULL character doesn't
610 * fit in the output buffer then fail.
612 if (strlen(Integer
) + strlen(BaseName
) >= ResultSize
)
615 lstrcpyA(Result
, BaseName
);
616 lstrcatA(Result
, Integer
);
622 * Get file name of code page definition file.
625 * Code page number to get file name of.
627 * Buffer that is filled with file name of successful return. Can
629 * @param FileNameSize
630 * Size of the buffer to hold file name in WCHARs.
632 * @return TRUE if the file name was retrieved, FALSE otherwise.
637 GetCPFileNameFromRegistry(UINT CodePage
, LPWSTR FileName
, ULONG FileNameSize
)
639 WCHAR ValueNameBuffer
[11];
640 UNICODE_STRING KeyName
, ValueName
;
641 OBJECT_ATTRIBUTES ObjectAttributes
;
644 PKEY_VALUE_PARTIAL_INFORMATION Kvpi
;
647 /* Convert the codepage number to string. */
648 ValueName
.Buffer
= ValueNameBuffer
;
649 ValueName
.MaximumLength
= sizeof(ValueNameBuffer
);
650 if (!NT_SUCCESS(RtlIntegerToUnicodeString(CodePage
, 10, &ValueName
)))
653 /* Open the registry key containing file name mappings. */
654 RtlInitUnicodeString(&KeyName
, L
"\\Registry\\Machine\\System\\"
655 L
"CurrentControlSet\\Control\\Nls\\CodePage");
656 InitializeObjectAttributes(&ObjectAttributes
, &KeyName
, OBJ_CASE_INSENSITIVE
,
658 Status
= NtOpenKey(&KeyHandle
, KEY_READ
, &ObjectAttributes
);
659 if (!NT_SUCCESS(Status
))
664 /* Allocate buffer that will be used to query the value data. */
665 KvpiSize
= sizeof(KEY_VALUE_PARTIAL_INFORMATION
) +
666 (MAX_PATH
* sizeof(WCHAR
));
667 Kvpi
= HeapAlloc(GetProcessHeap(), 0, KvpiSize
);
674 /* Query the file name for our code page. */
675 Status
= NtQueryValueKey(KeyHandle
, &ValueName
, KeyValuePartialInformation
,
676 Kvpi
, KvpiSize
, &KvpiSize
);
680 /* Check if we succeded and the value is non-empty string. */
681 if (NT_SUCCESS(Status
) && Kvpi
->Type
== REG_SZ
&&
682 Kvpi
->DataLength
> sizeof(WCHAR
))
684 if (FileName
!= NULL
)
686 lstrcpynW(FileName
, (WCHAR
*)Kvpi
->Data
,
687 min(Kvpi
->DataLength
/ sizeof(WCHAR
), FileNameSize
));
696 * Detect if specified code page is valid and present in the system.
699 * Code page number to query.
701 * @return TRUE if code page is present.
704 IsValidCodePage(UINT CodePage
)
706 if (CodePage
== CP_UTF8
|| CodePage
== CP_UTF7
)
708 if (IntGetLoadedCodePageEntry(CodePage
))
710 return GetCPFileNameFromRegistry(CodePage
, NULL
, 0);
714 * Convert a multi-byte string to wide-charater equivalent.
717 * Code page to be used to perform the conversion. It can be also
718 * one of the special values (CP_ACP for ANSI code page, CP_MACCP
719 * for Macintosh code page, CP_OEMCP for OEM code page, CP_THREAD_ACP
720 * for thread active code page, CP_UTF7 or CP_UTF8).
722 * Additional conversion flags (MB_PRECOMPOSED, MB_COMPOSITE,
723 * MB_ERR_INVALID_CHARS, MB_USEGLYPHCHARS).
724 * @param MultiByteString
726 * @param MultiByteCount
727 * Size of MultiByteString, or -1 if MultiByteString is NULL
729 * @param WideCharString
731 * @param WideCharCount
732 * Size in WCHARs of WideCharString, or 0 if the caller just wants
733 * to know how large WideCharString should be for a successful
736 * @return Zero on error, otherwise the number of WCHARs written
737 * in the WideCharString buffer.
742 MultiByteToWideChar(UINT CodePage
, DWORD Flags
,
743 LPCSTR MultiByteString
, INT MultiByteCount
,
744 LPWSTR WideCharString
, INT WideCharCount
)
746 /* Check the parameters. */
747 if (MultiByteString
== NULL
||
748 (WideCharString
== NULL
&& WideCharCount
> 0))
750 SetLastError(ERROR_INVALID_PARAMETER
);
754 /* Determine the input string length. */
755 if (MultiByteCount
< 0)
757 MultiByteCount
= lstrlenA(MultiByteString
) + 1;
763 return IntMultiByteToWideCharUTF8(
764 Flags
, MultiByteString
, MultiByteCount
,
765 WideCharString
, WideCharCount
);
768 DPRINT1("MultiByteToWideChar for CP_UTF7 is not implemented!\n");
772 DPRINT1("MultiByteToWideChar for CP_SYMBOL is not implemented!\n");
776 return IntMultiByteToWideCharCP(
777 CodePage
, Flags
, MultiByteString
, MultiByteCount
,
778 WideCharString
, WideCharCount
);
783 * Convert a wide-charater string to closest multi-byte equivalent.
786 * Code page to be used to perform the conversion. It can be also
787 * one of the special values (CP_ACP for ANSI code page, CP_MACCP
788 * for Macintosh code page, CP_OEMCP for OEM code page, CP_THREAD_ACP
789 * for thread active code page, CP_UTF7 or CP_UTF8).
791 * Additional conversion flags (WC_NO_BEST_FIT_CHARS, WC_COMPOSITECHECK,
792 * WC_DISCARDNS, WC_SEPCHARS, WC_DEFAULTCHAR).
793 * @param WideCharString
794 * Points to the wide-character string to be converted.
795 * @param WideCharCount
796 * Size in WCHARs of WideCharStr, or 0 if the caller just wants to
797 * know how large WideCharString should be for a successful conversion.
798 * @param MultiByteString
799 * Points to the buffer to receive the translated string.
800 * @param MultiByteCount
801 * Specifies the size in bytes of the buffer pointed to by the
802 * MultiByteString parameter. If this value is zero, the function
803 * returns the number of bytes required for the buffer.
805 * Points to the character used if a wide character cannot be
806 * represented in the specified code page. If this parameter is
807 * NULL, a system default value is used.
808 * @param UsedDefaultChar
809 * Points to a flag that indicates whether a default character was
810 * used. This parameter can be NULL.
812 * @return Zero on error, otherwise the number of bytes written in the
813 * MultiByteString buffer. Or the number of bytes needed for
814 * the MultiByteString buffer if MultiByteCount is zero.
819 WideCharToMultiByte(UINT CodePage
, DWORD Flags
,
820 LPCWSTR WideCharString
, INT WideCharCount
,
821 LPSTR MultiByteString
, INT MultiByteCount
,
822 LPCSTR DefaultChar
, LPBOOL UsedDefaultChar
)
824 /* Check the parameters. */
825 if (WideCharString
== NULL
||
826 (MultiByteString
== NULL
&& MultiByteCount
> 0))
828 SetLastError(ERROR_INVALID_PARAMETER
);
832 /* Determine the input string length. */
833 if (WideCharCount
< 0)
835 WideCharCount
= lstrlenW(WideCharString
) + 1;
841 return IntWideCharToMultiByteUTF8(
842 CodePage
, Flags
, WideCharString
, WideCharCount
,
843 MultiByteString
, MultiByteCount
, DefaultChar
,
847 DPRINT1("WideCharToMultiByte for CP_UTF7 is not implemented!\n");
851 DPRINT1("WideCharToMultiByte for CP_SYMBOL is not implemented!\n");
855 return IntWideCharToMultiByteCP(
856 CodePage
, Flags
, WideCharString
, WideCharCount
,
857 MultiByteString
, MultiByteCount
, DefaultChar
,
869 return AnsiCodePage
.CodePageTable
.CodePage
;
879 return OemCodePage
.CodePageTable
.CodePage
;
883 IntIsLeadByte(PCPTABLEINFO TableInfo
, UCHAR Ch
)
885 if(TableInfo
->MaximumCharacterSize
== 2)
888 for(i
= 0; i
< MAXIMUM_LEADBYTES
; i
++)
890 if(TableInfo
->LeadByte
[i
] == Ch
)
908 return IntIsLeadByte(&AnsiCodePage
.CodePageTable
, (UCHAR
)TestChar
);
922 PCODEPAGE_ENTRY CodePageEntry
;
924 CodePageEntry
= IntGetCodePageEntry(CodePage
);
925 if(CodePageEntry
!= NULL
)
927 return IntIsLeadByte(&CodePageEntry
->CodePageTable
, (UCHAR
)TestChar
);
930 SetLastError(ERROR_INVALID_PARAMETER
);