78574c6b4362327f14d6b96f344aadb34b495599
[reactos.git] / dll / win32 / kernel32 / winnls / string / nls.c
1 /*
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
7 * Hartmut Birr
8 * Gunnar Andre Dalsnes
9 * Thomas Weidenmueller
10 * Katayama Hirofumi MZ
11 * UPDATE HISTORY:
12 * Created 24/08/2004
13 */
14
15 /* INCLUDES *******************************************************************/
16
17 #include <k32.h>
18
19 #define NDEBUG
20 #include <debug.h>
21
22 /* GLOBAL VARIABLES ***********************************************************/
23
24 /* Sequence length based on the first character. */
25 static const char UTF8Length[128] =
26 {
27 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x80 - 0x8F */
28 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x90 - 0x9F */
29 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0xA0 - 0xAF */
30 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0xB0 - 0xBF */
31 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 0xC0 - 0xCF */
32 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 0xD0 - 0xDF */
33 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, /* 0xE0 - 0xEF */
34 3, 3, 3, 3, 3, 3, 3, 3, 4, 4, 4, 4, 5, 5, 0, 0 /* 0xF0 - 0xFF */
35 };
36
37 /* First byte mask depending on UTF-8 sequence length. */
38 static const unsigned char UTF8Mask[6] = {0x7f, 0x1f, 0x0f, 0x07, 0x03, 0x01};
39
40 /* UTF-8 length to lower bound */
41 static const unsigned long UTF8LBound[] =
42 {0, 0x80, 0x800, 0x10000, 0x200000, 0x2000000, 0xFFFFFFFF};
43
44 /* FIXME: Change to HASH table or linear array. */
45 static LIST_ENTRY CodePageListHead;
46 static CODEPAGE_ENTRY AnsiCodePage;
47 static CODEPAGE_ENTRY OemCodePage;
48 static RTL_CRITICAL_SECTION CodePageListLock;
49
50 /* FORWARD DECLARATIONS *******************************************************/
51
52 BOOL WINAPI
53 GetNlsSectionName(UINT CodePage, UINT Base, ULONG Unknown,
54 LPSTR BaseName, LPSTR Result, ULONG ResultSize);
55
56 BOOL WINAPI
57 GetCPFileNameFromRegistry(UINT CodePage, LPWSTR FileName, ULONG FileNameSize);
58
59 /* PRIVATE FUNCTIONS **********************************************************/
60
61 /**
62 * @name NlsInit
63 *
64 * Internal NLS related stuff initialization.
65 */
66
67 BOOL
68 FASTCALL
69 NlsInit(VOID)
70 {
71 UNICODE_STRING DirName;
72 OBJECT_ATTRIBUTES ObjectAttributes;
73 HANDLE Handle;
74
75 InitializeListHead(&CodePageListHead);
76 RtlInitializeCriticalSection(&CodePageListLock);
77
78 /*
79 * FIXME: Eventually this should be done only for the NLS Server
80 * process, but since we don't have anything like that (yet?) we
81 * always try to create the "\Nls" directory here.
82 */
83 RtlInitUnicodeString(&DirName, L"\\Nls");
84
85 InitializeObjectAttributes(&ObjectAttributes,
86 &DirName,
87 OBJ_CASE_INSENSITIVE | OBJ_PERMANENT,
88 NULL,
89 NULL);
90
91 if (NT_SUCCESS(NtCreateDirectoryObject(&Handle, DIRECTORY_ALL_ACCESS, &ObjectAttributes)))
92 {
93 NtClose(Handle);
94 }
95
96 /* Setup ANSI code page. */
97 AnsiCodePage.SectionHandle = NULL;
98 AnsiCodePage.SectionMapping = NtCurrentTeb()->ProcessEnvironmentBlock->AnsiCodePageData;
99
100 RtlInitCodePageTable((PUSHORT)AnsiCodePage.SectionMapping,
101 &AnsiCodePage.CodePageTable);
102 AnsiCodePage.CodePage = AnsiCodePage.CodePageTable.CodePage;
103
104 InsertTailList(&CodePageListHead, &AnsiCodePage.Entry);
105
106 /* Setup OEM code page. */
107 OemCodePage.SectionHandle = NULL;
108 OemCodePage.SectionMapping = NtCurrentTeb()->ProcessEnvironmentBlock->OemCodePageData;
109
110 RtlInitCodePageTable((PUSHORT)OemCodePage.SectionMapping,
111 &OemCodePage.CodePageTable);
112 OemCodePage.CodePage = OemCodePage.CodePageTable.CodePage;
113 InsertTailList(&CodePageListHead, &OemCodePage.Entry);
114
115 return TRUE;
116 }
117
118 /**
119 * @name NlsUninit
120 *
121 * Internal NLS related stuff uninitialization.
122 */
123
124 VOID
125 FASTCALL
126 NlsUninit(VOID)
127 {
128 PCODEPAGE_ENTRY Current;
129
130 /* Delete the code page list. */
131 while (!IsListEmpty(&CodePageListHead))
132 {
133 Current = CONTAINING_RECORD(CodePageListHead.Flink, CODEPAGE_ENTRY, Entry);
134 if (Current->SectionHandle != NULL)
135 {
136 UnmapViewOfFile(Current->SectionMapping);
137 NtClose(Current->SectionHandle);
138 }
139 RemoveHeadList(&CodePageListHead);
140 }
141 RtlDeleteCriticalSection(&CodePageListLock);
142 }
143
144 /**
145 * @name IntGetLoadedCodePageEntry
146 *
147 * Internal function to get structure containing a code page information
148 * of code page that is already loaded.
149 *
150 * @param CodePage
151 * Number of the code page. Special values like CP_OEMCP, CP_ACP
152 * or CP_UTF8 aren't allowed.
153 *
154 * @return Code page entry or NULL if the specified code page hasn't
155 * been loaded yet.
156 */
157
158 PCODEPAGE_ENTRY
159 FASTCALL
160 IntGetLoadedCodePageEntry(UINT CodePage)
161 {
162 LIST_ENTRY *CurrentEntry;
163 PCODEPAGE_ENTRY Current;
164
165 RtlEnterCriticalSection(&CodePageListLock);
166 for (CurrentEntry = CodePageListHead.Flink;
167 CurrentEntry != &CodePageListHead;
168 CurrentEntry = CurrentEntry->Flink)
169 {
170 Current = CONTAINING_RECORD(CurrentEntry, CODEPAGE_ENTRY, Entry);
171 if (Current->CodePage == CodePage)
172 {
173 RtlLeaveCriticalSection(&CodePageListLock);
174 return Current;
175 }
176 }
177 RtlLeaveCriticalSection(&CodePageListLock);
178
179 return NULL;
180 }
181
182 /**
183 * @name IntGetCodePageEntry
184 *
185 * Internal function to get structure containing a code page information.
186 *
187 * @param CodePage
188 * Number of the code page. Special values like CP_OEMCP, CP_ACP
189 * or CP_THREAD_ACP are allowed, but CP_UTF[7/8] isn't.
190 *
191 * @return Code page entry.
192 */
193
194 PCODEPAGE_ENTRY
195 FASTCALL
196 IntGetCodePageEntry(UINT CodePage)
197 {
198 CHAR SectionName[40];
199 NTSTATUS Status;
200 HANDLE SectionHandle = INVALID_HANDLE_VALUE, FileHandle;
201 PBYTE SectionMapping;
202 OBJECT_ATTRIBUTES ObjectAttributes;
203 ANSI_STRING AnsiName;
204 UNICODE_STRING UnicodeName;
205 WCHAR FileName[MAX_PATH + 1];
206 UINT FileNamePos;
207 PCODEPAGE_ENTRY CodePageEntry;
208 if (CodePage == CP_ACP)
209 {
210 return &AnsiCodePage;
211 }
212 else if (CodePage == CP_OEMCP)
213 {
214 return &OemCodePage;
215 }
216 else if (CodePage == CP_THREAD_ACP)
217 {
218 if (!GetLocaleInfoW(GetThreadLocale(),
219 LOCALE_IDEFAULTANSICODEPAGE | LOCALE_RETURN_NUMBER,
220 (WCHAR *)&CodePage,
221 sizeof(CodePage) / sizeof(WCHAR)))
222 {
223 /* Last error is set by GetLocaleInfoW. */
224 return NULL;
225 }
226 if (CodePage == 0)
227 return &AnsiCodePage;
228 }
229 else if (CodePage == CP_MACCP)
230 {
231 if (!GetLocaleInfoW(LOCALE_SYSTEM_DEFAULT,
232 LOCALE_IDEFAULTMACCODEPAGE | LOCALE_RETURN_NUMBER,
233 (WCHAR *)&CodePage,
234 sizeof(CodePage) / sizeof(WCHAR)))
235 {
236 /* Last error is set by GetLocaleInfoW. */
237 return NULL;
238 }
239 }
240
241 /* Try searching for loaded page first. */
242 CodePageEntry = IntGetLoadedCodePageEntry(CodePage);
243 if (CodePageEntry != NULL)
244 {
245 return CodePageEntry;
246 }
247
248 /*
249 * Yes, we really want to lock here. Otherwise it can happen that
250 * two parallel requests will try to get the entry for the same
251 * code page and we would load it twice.
252 */
253 RtlEnterCriticalSection(&CodePageListLock);
254
255 /* Generate the section name. */
256 if (!GetNlsSectionName(CodePage,
257 10,
258 0,
259 "\\Nls\\NlsSectionCP",
260 SectionName,
261 sizeof(SectionName)))
262 {
263 RtlLeaveCriticalSection(&CodePageListLock);
264 return NULL;
265 }
266
267 RtlInitAnsiString(&AnsiName, SectionName);
268 RtlAnsiStringToUnicodeString(&UnicodeName, &AnsiName, TRUE);
269
270 InitializeObjectAttributes(&ObjectAttributes, &UnicodeName, 0, NULL, NULL);
271
272 /* Try to open the section first */
273 Status = NtOpenSection(&SectionHandle, SECTION_MAP_READ, &ObjectAttributes);
274
275 /* If the section doesn't exist, try to create it. */
276 if (Status == STATUS_UNSUCCESSFUL ||
277 Status == STATUS_OBJECT_NAME_NOT_FOUND ||
278 Status == STATUS_OBJECT_PATH_NOT_FOUND)
279 {
280 FileNamePos = GetSystemDirectoryW(FileName, MAX_PATH);
281 if (GetCPFileNameFromRegistry(CodePage,
282 FileName + FileNamePos + 1,
283 MAX_PATH - FileNamePos - 1))
284 {
285 FileName[FileNamePos] = L'\\';
286 FileName[MAX_PATH] = 0;
287 FileHandle = CreateFileW(FileName,
288 FILE_GENERIC_READ,
289 FILE_SHARE_READ,
290 NULL,
291 OPEN_EXISTING,
292 0,
293 NULL);
294
295 Status = NtCreateSection(&SectionHandle,
296 SECTION_MAP_READ,
297 &ObjectAttributes,
298 NULL,
299 PAGE_READONLY,
300 SEC_COMMIT,
301 FileHandle);
302
303 /* HACK: Check if another process was faster
304 * and already created this section. See bug 3626 for details */
305 if (Status == STATUS_OBJECT_NAME_COLLISION)
306 {
307 /* Close the file then */
308 NtClose(FileHandle);
309
310 /* And open the section */
311 Status = NtOpenSection(&SectionHandle,
312 SECTION_MAP_READ,
313 &ObjectAttributes);
314 }
315 }
316 }
317 RtlFreeUnicodeString(&UnicodeName);
318
319 if (!NT_SUCCESS(Status))
320 {
321 RtlLeaveCriticalSection(&CodePageListLock);
322 return NULL;
323 }
324
325 SectionMapping = MapViewOfFile(SectionHandle, FILE_MAP_READ, 0, 0, 0);
326 if (SectionMapping == NULL)
327 {
328 NtClose(SectionHandle);
329 RtlLeaveCriticalSection(&CodePageListLock);
330 return NULL;
331 }
332
333 CodePageEntry = HeapAlloc(GetProcessHeap(), 0, sizeof(CODEPAGE_ENTRY));
334 if (CodePageEntry == NULL)
335 {
336 NtClose(SectionHandle);
337 RtlLeaveCriticalSection(&CodePageListLock);
338 return NULL;
339 }
340
341 CodePageEntry->CodePage = CodePage;
342 CodePageEntry->SectionHandle = SectionHandle;
343 CodePageEntry->SectionMapping = SectionMapping;
344
345 RtlInitCodePageTable((PUSHORT)SectionMapping, &CodePageEntry->CodePageTable);
346
347 /* Insert the new entry to list and unlock. Uff. */
348 InsertTailList(&CodePageListHead, &CodePageEntry->Entry);
349 RtlLeaveCriticalSection(&CodePageListLock);
350
351 return CodePageEntry;
352 }
353
354 /**
355 * @name IntMultiByteToWideCharUTF8
356 *
357 * Internal version of MultiByteToWideChar for UTF8.
358 *
359 * @see MultiByteToWideChar
360 */
361
362 static
363 INT
364 WINAPI
365 IntMultiByteToWideCharUTF8(DWORD Flags,
366 LPCSTR MultiByteString,
367 INT MultiByteCount,
368 LPWSTR WideCharString,
369 INT WideCharCount)
370 {
371 LPCSTR MbsEnd, MbsPtrSave;
372 UCHAR Char, TrailLength;
373 WCHAR WideChar;
374 LONG Count;
375 BOOL CharIsValid, StringIsValid = TRUE;
376 const WCHAR InvalidChar = 0xFFFD;
377
378 if (Flags != 0 && Flags != MB_ERR_INVALID_CHARS)
379 {
380 SetLastError(ERROR_INVALID_FLAGS);
381 return 0;
382 }
383
384 /* Does caller query for output buffer size? */
385 if (WideCharCount == 0)
386 {
387 /* validate and count the wide characters */
388 MbsEnd = MultiByteString + MultiByteCount;
389 for (; MultiByteString < MbsEnd; WideCharCount++)
390 {
391 Char = *MultiByteString++;
392 if (Char < 0xC0)
393 {
394 TrailLength = 0;
395 continue;
396 }
397 if (Char >= 0xF8 || (Char & 0xC0) == 0x80)
398 {
399 TrailLength = 0;
400 StringIsValid = FALSE;
401 continue;
402 }
403
404 CharIsValid = TRUE;
405 MbsPtrSave = MultiByteString;
406 TrailLength = UTF8Length[Char - 0x80];
407 WideChar = Char & UTF8Mask[TrailLength];
408
409 while (TrailLength && MultiByteString < MbsEnd)
410 {
411 if ((*MultiByteString & 0xC0) != 0x80)
412 {
413 CharIsValid = StringIsValid = FALSE;
414 break;
415 }
416
417 WideChar = (WideChar << 6) | (*MultiByteString++ & 0x7f);
418 TrailLength--;
419 }
420
421 if (!CharIsValid || WideChar < UTF8LBound[UTF8Length[Char - 0x80]])
422 {
423 MultiByteString = MbsPtrSave;
424 }
425 }
426
427 if (TrailLength)
428 {
429 WideCharCount++;
430 }
431
432 if (Flags == MB_ERR_INVALID_CHARS && (!StringIsValid || TrailLength))
433 {
434 SetLastError(ERROR_NO_UNICODE_TRANSLATION);
435 return 0;
436 }
437
438 return WideCharCount;
439 }
440
441 /* convert */
442 MbsEnd = MultiByteString + MultiByteCount;
443 for (Count = 0; Count < WideCharCount && MultiByteString < MbsEnd; Count++)
444 {
445 Char = *MultiByteString++;
446 if (Char < 0x80)
447 {
448 *WideCharString++ = Char;
449 TrailLength = 0;
450 continue;
451 }
452 if (Char >= 0xF8 || Char == 0x80 || (Char & 0xC0) == 0x80)
453 {
454 *WideCharString++ = InvalidChar;
455 TrailLength = 0;
456 continue;
457 }
458
459 CharIsValid = TRUE;
460 MbsPtrSave = MultiByteString;
461 TrailLength = UTF8Length[Char - 0x80];
462 WideChar = Char & UTF8Mask[TrailLength];
463
464 while (TrailLength && MultiByteString < MbsEnd)
465 {
466 if ((*MultiByteString & 0xC0) != 0x80)
467 {
468 CharIsValid = StringIsValid = FALSE;
469 break;
470 }
471
472 WideChar = (WideChar << 6) | (*MultiByteString++ & 0x7f);
473 TrailLength--;
474 }
475
476 if (CharIsValid && UTF8LBound[UTF8Length[Char - 0x80]] <= WideChar)
477 {
478 *WideCharString++ = WideChar;
479 }
480 else
481 {
482 *WideCharString++ = InvalidChar;
483 MultiByteString = MbsPtrSave;
484 }
485 }
486
487 if (TrailLength && Count < WideCharCount && MultiByteString < MbsEnd)
488 {
489 *WideCharString = InvalidChar;
490 WideCharCount++;
491 }
492
493 if (MultiByteString < MbsEnd)
494 {
495 SetLastError(ERROR_INSUFFICIENT_BUFFER);
496 return 0;
497 }
498
499 if (Flags == MB_ERR_INVALID_CHARS && (!StringIsValid || TrailLength))
500 {
501 SetLastError(ERROR_NO_UNICODE_TRANSLATION);
502 return 0;
503 }
504
505 return Count;
506 }
507
508 /**
509 * @name IntMultiByteToWideCharCP
510 *
511 * Internal version of MultiByteToWideChar for code page tables.
512 *
513 * @see MultiByteToWideChar
514 * @todo Handle MB_PRECOMPOSED, MB_COMPOSITE, MB_USEGLYPHCHARS and
515 * DBCS codepages.
516 */
517
518 static
519 INT
520 WINAPI
521 IntMultiByteToWideCharCP(UINT CodePage,
522 DWORD Flags,
523 LPCSTR MultiByteString,
524 INT MultiByteCount,
525 LPWSTR WideCharString,
526 INT WideCharCount)
527 {
528 PCODEPAGE_ENTRY CodePageEntry;
529 PCPTABLEINFO CodePageTable;
530 PUSHORT MultiByteTable;
531 LPCSTR TempString;
532 INT TempLength;
533 USHORT WideChar;
534
535 /* Get code page table. */
536 CodePageEntry = IntGetCodePageEntry(CodePage);
537 if (CodePageEntry == NULL)
538 {
539 SetLastError(ERROR_INVALID_PARAMETER);
540 return 0;
541 }
542
543 CodePageTable = &CodePageEntry->CodePageTable;
544
545 /* If MB_USEGLYPHCHARS flag present and glyph table present */
546 if ((Flags & MB_USEGLYPHCHARS) && CodePageTable->MultiByteTable[256])
547 {
548 /* Use glyph table */
549 MultiByteTable = CodePageTable->MultiByteTable + 256 + 1;
550 }
551 else
552 {
553 MultiByteTable = CodePageTable->MultiByteTable;
554 }
555
556 /* Different handling for DBCS code pages. */
557 if (CodePageTable->DBCSCodePage)
558 {
559 UCHAR Char;
560 USHORT DBCSOffset;
561 LPCSTR MbsEnd = MultiByteString + MultiByteCount;
562 INT Count;
563
564 if (Flags & MB_ERR_INVALID_CHARS)
565 {
566 TempString = MultiByteString;
567
568 while (TempString < MbsEnd)
569 {
570 DBCSOffset = CodePageTable->DBCSOffsets[(UCHAR)*TempString];
571
572 if (DBCSOffset)
573 {
574 /* If lead byte is presented, but behind it there is no symbol */
575 if (((TempString + 1) == MbsEnd) || (*(TempString + 1) == 0))
576 {
577 SetLastError(ERROR_NO_UNICODE_TRANSLATION);
578 return 0;
579 }
580
581 WideChar = CodePageTable->DBCSOffsets[DBCSOffset + *(TempString + 1)];
582
583 if (WideChar == CodePageTable->UniDefaultChar &&
584 MAKEWORD(*(TempString + 1), *TempString) != CodePageTable->TransUniDefaultChar)
585 {
586 SetLastError(ERROR_NO_UNICODE_TRANSLATION);
587 return 0;
588 }
589
590 TempString++;
591 }
592 else
593 {
594 WideChar = MultiByteTable[(UCHAR)*TempString];
595
596 if ((WideChar == CodePageTable->UniDefaultChar &&
597 *TempString != CodePageTable->TransUniDefaultChar) ||
598 /* "Private Use" characters */
599 (WideChar >= 0xE000 && WideChar <= 0xF8FF))
600 {
601 SetLastError(ERROR_NO_UNICODE_TRANSLATION);
602 return 0;
603 }
604 }
605
606 TempString++;
607 }
608 }
609
610 /* Does caller query for output buffer size? */
611 if (WideCharCount == 0)
612 {
613 for (; MultiByteString < MbsEnd; WideCharCount++)
614 {
615 Char = *MultiByteString++;
616
617 DBCSOffset = CodePageTable->DBCSOffsets[Char];
618
619 if (!DBCSOffset)
620 continue;
621
622 if (MultiByteString < MbsEnd)
623 MultiByteString++;
624 }
625
626 return WideCharCount;
627 }
628
629 for (Count = 0; Count < WideCharCount && MultiByteString < MbsEnd; Count++)
630 {
631 Char = *MultiByteString++;
632
633 DBCSOffset = CodePageTable->DBCSOffsets[Char];
634
635 if (!DBCSOffset)
636 {
637 *WideCharString++ = MultiByteTable[Char];
638 continue;
639 }
640
641 if (MultiByteString == MbsEnd)
642 {
643 *WideCharString++ = MultiByteTable[Char];
644 }
645 else if (*MultiByteString == 0)
646 {
647 *WideCharString++ = UNICODE_NULL;
648 MultiByteString++;
649 }
650 else
651 {
652 *WideCharString++ = CodePageTable->DBCSOffsets[DBCSOffset + (UCHAR)*MultiByteString++];
653 }
654 }
655
656 if (MultiByteString < MbsEnd)
657 {
658 SetLastError(ERROR_INSUFFICIENT_BUFFER);
659 return 0;
660 }
661
662 return Count;
663 }
664 else /* SBCS code page */
665 {
666 /* Check for invalid characters. */
667 if (Flags & MB_ERR_INVALID_CHARS)
668 {
669 for (TempString = MultiByteString, TempLength = MultiByteCount;
670 TempLength > 0;
671 TempString++, TempLength--)
672 {
673 WideChar = MultiByteTable[(UCHAR)*TempString];
674
675 if ((WideChar == CodePageTable->UniDefaultChar &&
676 *TempString != CodePageTable->TransUniDefaultChar) ||
677 /* "Private Use" characters */
678 (WideChar >= 0xE000 && WideChar <= 0xF8FF))
679 {
680 SetLastError(ERROR_NO_UNICODE_TRANSLATION);
681 return 0;
682 }
683 }
684 }
685
686 /* Does caller query for output buffer size? */
687 if (WideCharCount == 0)
688 return MultiByteCount;
689
690 /* Fill the WideCharString buffer with what will fit: Verified on WinXP */
691 for (TempLength = (WideCharCount < MultiByteCount) ? WideCharCount : MultiByteCount;
692 TempLength > 0;
693 MultiByteString++, TempLength--)
694 {
695 *WideCharString++ = MultiByteTable[(UCHAR)*MultiByteString];
696 }
697
698 /* Adjust buffer size. Wine trick ;-) */
699 if (WideCharCount < MultiByteCount)
700 {
701 MultiByteCount = WideCharCount;
702 SetLastError(ERROR_INSUFFICIENT_BUFFER);
703 return 0;
704 }
705 return MultiByteCount;
706 }
707 }
708
709 /**
710 * @name IntMultiByteToWideCharSYMBOL
711 *
712 * Internal version of MultiByteToWideChar for SYMBOL.
713 *
714 * @see MultiByteToWideChar
715 */
716
717 static
718 INT
719 WINAPI
720 IntMultiByteToWideCharSYMBOL(DWORD Flags,
721 LPCSTR MultiByteString,
722 INT MultiByteCount,
723 LPWSTR WideCharString,
724 INT WideCharCount)
725 {
726 LONG Count;
727 UCHAR Char;
728 INT WideCharMaxLen;
729
730
731 if (Flags != 0)
732 {
733 SetLastError(ERROR_INVALID_FLAGS);
734 return 0;
735 }
736
737 if (WideCharCount == 0)
738 {
739 return MultiByteCount;
740 }
741
742 WideCharMaxLen = WideCharCount > MultiByteCount ? MultiByteCount : WideCharCount;
743
744 for (Count = 0; Count < WideCharMaxLen; Count++)
745 {
746 Char = MultiByteString[Count];
747 if ( Char < 0x20 )
748 {
749 WideCharString[Count] = Char;
750 }
751 else
752 {
753 WideCharString[Count] = Char + 0xf000;
754 }
755 }
756 if (MultiByteCount > WideCharMaxLen)
757 {
758 SetLastError(ERROR_INSUFFICIENT_BUFFER);
759 return 0;
760 }
761
762 return WideCharMaxLen;
763 }
764
765 /**
766 * @name IntWideCharToMultiByteSYMBOL
767 *
768 * Internal version of WideCharToMultiByte for SYMBOL.
769 *
770 * @see WideCharToMultiByte
771 */
772
773 static INT
774 WINAPI
775 IntWideCharToMultiByteSYMBOL(DWORD Flags,
776 LPCWSTR WideCharString,
777 INT WideCharCount,
778 LPSTR MultiByteString,
779 INT MultiByteCount)
780 {
781 LONG Count;
782 INT MaxLen;
783 WCHAR Char;
784
785 if (Flags!=0)
786 {
787 SetLastError(ERROR_INVALID_PARAMETER);
788 return 0;
789 }
790
791
792 if (MultiByteCount == 0)
793 {
794 return WideCharCount;
795 }
796
797 MaxLen = MultiByteCount > WideCharCount ? WideCharCount : MultiByteCount;
798 for (Count = 0; Count < MaxLen; Count++)
799 {
800 Char = WideCharString[Count];
801 if (Char < 0x20)
802 {
803 MultiByteString[Count] = (CHAR)Char;
804 }
805 else
806 {
807 if ((Char >= 0xf020) && (Char < 0xf100))
808 {
809 MultiByteString[Count] = Char - 0xf000;
810 }
811 else
812 {
813 SetLastError(ERROR_NO_UNICODE_TRANSLATION);
814 return 0;
815 }
816 }
817 }
818
819 if (WideCharCount > MaxLen)
820 {
821 SetLastError(ERROR_INSUFFICIENT_BUFFER);
822 return 0;
823 }
824 return MaxLen;
825 }
826
827 /**
828 * @name IntWideCharToMultiByteUTF8
829 *
830 * Internal version of WideCharToMultiByte for UTF8.
831 *
832 * @see WideCharToMultiByte
833 */
834
835 static INT
836 WINAPI
837 IntWideCharToMultiByteUTF8(UINT CodePage,
838 DWORD Flags,
839 LPCWSTR WideCharString,
840 INT WideCharCount,
841 LPSTR MultiByteString,
842 INT MultiByteCount,
843 LPCSTR DefaultChar,
844 LPBOOL UsedDefaultChar)
845 {
846 INT TempLength;
847 DWORD Char;
848
849 if (Flags)
850 {
851 SetLastError(ERROR_INVALID_FLAGS);
852 return 0;
853 }
854
855 /* Does caller query for output buffer size? */
856 if (MultiByteCount == 0)
857 {
858 for (TempLength = 0; WideCharCount;
859 WideCharCount--, WideCharString++)
860 {
861 TempLength++;
862 if (*WideCharString >= 0x80)
863 {
864 TempLength++;
865 if (*WideCharString >= 0x800)
866 {
867 TempLength++;
868 if (*WideCharString >= 0xd800 && *WideCharString < 0xdc00 &&
869 WideCharCount >= 1 &&
870 WideCharString[1] >= 0xdc00 && WideCharString[1] <= 0xe000)
871 {
872 WideCharCount--;
873 WideCharString++;
874 TempLength++;
875 }
876 }
877 }
878 }
879 return TempLength;
880 }
881
882 for (TempLength = MultiByteCount; WideCharCount; WideCharCount--, WideCharString++)
883 {
884 Char = *WideCharString;
885 if (Char < 0x80)
886 {
887 if (!TempLength)
888 {
889 SetLastError(ERROR_INSUFFICIENT_BUFFER);
890 break;
891 }
892 TempLength--;
893 *MultiByteString++ = (CHAR)Char;
894 continue;
895 }
896
897 if (Char < 0x800) /* 0x80-0x7ff: 2 bytes */
898 {
899 if (TempLength < 2)
900 {
901 SetLastError(ERROR_INSUFFICIENT_BUFFER);
902 break;
903 }
904 MultiByteString[1] = 0x80 | (Char & 0x3f); Char >>= 6;
905 MultiByteString[0] = 0xc0 | Char;
906 MultiByteString += 2;
907 TempLength -= 2;
908 continue;
909 }
910
911 /* surrogate pair 0x10000-0x10ffff: 4 bytes */
912 if (Char >= 0xd800 && Char < 0xdc00 &&
913 WideCharCount >= 1 &&
914 WideCharString[1] >= 0xdc00 && WideCharString[1] < 0xe000)
915 {
916 WideCharCount--;
917 WideCharString++;
918
919 if (TempLength < 4)
920 {
921 SetLastError(ERROR_INSUFFICIENT_BUFFER);
922 break;
923 }
924
925 Char = (Char - 0xd800) << 10;
926 Char |= *WideCharString - 0xdc00;
927 ASSERT(Char <= 0xfffff);
928 Char += 0x10000;
929 ASSERT(Char <= 0x10ffff);
930
931 MultiByteString[3] = 0x80 | (Char & 0x3f); Char >>= 6;
932 MultiByteString[2] = 0x80 | (Char & 0x3f); Char >>= 6;
933 MultiByteString[1] = 0x80 | (Char & 0x3f); Char >>= 6;
934 MultiByteString[0] = 0xf0 | Char;
935 MultiByteString += 4;
936 TempLength -= 4;
937 continue;
938 }
939
940 /* 0x800-0xffff: 3 bytes */
941 if (TempLength < 3)
942 {
943 SetLastError(ERROR_INSUFFICIENT_BUFFER);
944 break;
945 }
946 MultiByteString[2] = 0x80 | (Char & 0x3f); Char >>= 6;
947 MultiByteString[1] = 0x80 | (Char & 0x3f); Char >>= 6;
948 MultiByteString[0] = 0xe0 | Char;
949 MultiByteString += 3;
950 TempLength -= 3;
951 }
952
953 return MultiByteCount - TempLength;
954 }
955
956 /**
957 * @name IsValidSBCSMapping
958 *
959 * Checks if ch (single-byte character) is a valid mapping for wch
960 *
961 * @see IntWideCharToMultiByteCP
962 */
963 static
964 inline
965 BOOL
966 IntIsValidSBCSMapping(PCPTABLEINFO CodePageTable, DWORD Flags, WCHAR wch, UCHAR ch)
967 {
968 /* If the WC_NO_BEST_FIT_CHARS flag has been specified, the characters need to match exactly. */
969 if (Flags & WC_NO_BEST_FIT_CHARS)
970 return (CodePageTable->MultiByteTable[ch] == wch);
971
972 /* By default, all characters except TransDefaultChar apply as a valid mapping
973 for ch (so also "nearest" characters) */
974 if (ch != CodePageTable->TransDefaultChar)
975 return TRUE;
976
977 /* The only possible left valid mapping is the default character itself */
978 return (wch == CodePageTable->TransUniDefaultChar);
979 }
980
981 /**
982 * @name IsValidDBCSMapping
983 *
984 * Checks if ch (double-byte character) is a valid mapping for wch
985 *
986 * @see IntWideCharToMultiByteCP
987 */
988 static inline BOOL
989 IntIsValidDBCSMapping(PCPTABLEINFO CodePageTable, DWORD Flags, WCHAR wch, USHORT ch)
990 {
991 /* If ch is the default character, but the wch is not, it can't be a valid mapping */
992 if (ch == CodePageTable->TransDefaultChar && wch != CodePageTable->TransUniDefaultChar)
993 return FALSE;
994
995 /* If the WC_NO_BEST_FIT_CHARS flag has been specified, the characters need to match exactly. */
996 if (Flags & WC_NO_BEST_FIT_CHARS)
997 {
998 if(ch & 0xff00)
999 {
1000 USHORT uOffset = CodePageTable->DBCSOffsets[ch >> 8];
1001 /* if (!uOffset) return (CodePageTable->MultiByteTable[ch] == wch); */
1002 return (CodePageTable->DBCSOffsets[uOffset + (ch & 0xff)] == wch);
1003 }
1004
1005 return (CodePageTable->MultiByteTable[ch] == wch);
1006 }
1007
1008 /* If we're still here, we have a valid mapping */
1009 return TRUE;
1010 }
1011
1012 /**
1013 * @name IntWideCharToMultiByteCP
1014 *
1015 * Internal version of WideCharToMultiByte for code page tables.
1016 *
1017 * @see WideCharToMultiByte
1018 * @todo Handle WC_COMPOSITECHECK
1019 */
1020 static
1021 INT
1022 WINAPI
1023 IntWideCharToMultiByteCP(UINT CodePage,
1024 DWORD Flags,
1025 LPCWSTR WideCharString,
1026 INT WideCharCount,
1027 LPSTR MultiByteString,
1028 INT MultiByteCount,
1029 LPCSTR DefaultChar,
1030 LPBOOL UsedDefaultChar)
1031 {
1032 PCODEPAGE_ENTRY CodePageEntry;
1033 PCPTABLEINFO CodePageTable;
1034 INT TempLength;
1035
1036 /* Get code page table. */
1037 CodePageEntry = IntGetCodePageEntry(CodePage);
1038 if (CodePageEntry == NULL)
1039 {
1040 SetLastError(ERROR_INVALID_PARAMETER);
1041 return 0;
1042 }
1043
1044 CodePageTable = &CodePageEntry->CodePageTable;
1045
1046
1047 /* Different handling for DBCS code pages. */
1048 if (CodePageTable->DBCSCodePage)
1049 {
1050 /* If Flags, DefaultChar or UsedDefaultChar were given, we have to do some more work */
1051 if (Flags || DefaultChar || UsedDefaultChar)
1052 {
1053 BOOL TempUsedDefaultChar;
1054 USHORT DefChar;
1055
1056 /* If UsedDefaultChar is not set, set it to a temporary value, so we don't have
1057 to check on every character */
1058 if (!UsedDefaultChar)
1059 UsedDefaultChar = &TempUsedDefaultChar;
1060
1061 *UsedDefaultChar = FALSE;
1062
1063 /* Use the CodePage's TransDefaultChar if none was given. Don't modify the DefaultChar pointer here. */
1064 if (DefaultChar)
1065 DefChar = DefaultChar[1] ? ((DefaultChar[0] << 8) | DefaultChar[1]) : DefaultChar[0];
1066 else
1067 DefChar = CodePageTable->TransDefaultChar;
1068
1069 /* Does caller query for output buffer size? */
1070 if (!MultiByteCount)
1071 {
1072 for (TempLength = 0; WideCharCount; WideCharCount--, WideCharString++, TempLength++)
1073 {
1074 USHORT uChar;
1075
1076 if ((Flags & WC_COMPOSITECHECK) && WideCharCount > 1)
1077 {
1078 /* FIXME: Handle WC_COMPOSITECHECK */
1079 DPRINT("WC_COMPOSITECHECK flag UNIMPLEMENTED\n");
1080 }
1081
1082 uChar = ((PUSHORT) CodePageTable->WideCharTable)[*WideCharString];
1083
1084 /* Verify if the mapping is valid for handling DefaultChar and UsedDefaultChar */
1085 if (!IntIsValidDBCSMapping(CodePageTable, Flags, *WideCharString, uChar))
1086 {
1087 uChar = DefChar;
1088 *UsedDefaultChar = TRUE;
1089 }
1090
1091 /* Increment TempLength again if this is a double-byte character */
1092 if (uChar & 0xff00)
1093 TempLength++;
1094 }
1095
1096 return TempLength;
1097 }
1098
1099 /* Convert the WideCharString to the MultiByteString and verify if the mapping is valid */
1100 for (TempLength = MultiByteCount;
1101 WideCharCount && TempLength;
1102 TempLength--, WideCharString++, WideCharCount--)
1103 {
1104 USHORT uChar;
1105
1106 if ((Flags & WC_COMPOSITECHECK) && WideCharCount > 1)
1107 {
1108 /* FIXME: Handle WC_COMPOSITECHECK */
1109 DPRINT("WC_COMPOSITECHECK flag UNIMPLEMENTED\n");
1110 }
1111
1112 uChar = ((PUSHORT)CodePageTable->WideCharTable)[*WideCharString];
1113
1114 /* Verify if the mapping is valid for handling DefaultChar and UsedDefaultChar */
1115 if (!IntIsValidDBCSMapping(CodePageTable, Flags, *WideCharString, uChar))
1116 {
1117 uChar = DefChar;
1118 *UsedDefaultChar = TRUE;
1119 }
1120
1121 /* Handle double-byte characters */
1122 if (uChar & 0xff00)
1123 {
1124 /* Don't output a partial character */
1125 if (TempLength == 1)
1126 break;
1127
1128 TempLength--;
1129 *MultiByteString++ = uChar >> 8;
1130 }
1131
1132 *MultiByteString++ = (char)uChar;
1133 }
1134
1135 /* WideCharCount should be 0 if all characters were converted */
1136 if (WideCharCount)
1137 {
1138 SetLastError(ERROR_INSUFFICIENT_BUFFER);
1139 return 0;
1140 }
1141
1142 return MultiByteCount - TempLength;
1143 }
1144
1145 /* Does caller query for output buffer size? */
1146 if (!MultiByteCount)
1147 {
1148 for (TempLength = 0; WideCharCount; WideCharCount--, WideCharString++, TempLength++)
1149 {
1150 /* Increment TempLength again if this is a double-byte character */
1151 if (((PWCHAR)CodePageTable->WideCharTable)[*WideCharString] & 0xff00)
1152 TempLength++;
1153 }
1154
1155 return TempLength;
1156 }
1157
1158 /* Convert the WideCharString to the MultiByteString */
1159 for (TempLength = MultiByteCount;
1160 WideCharCount && TempLength;
1161 TempLength--, WideCharString++, WideCharCount--)
1162 {
1163 USHORT uChar = ((PUSHORT) CodePageTable->WideCharTable)[*WideCharString];
1164
1165 /* Is this a double-byte character? */
1166 if (uChar & 0xff00)
1167 {
1168 /* Don't output a partial character */
1169 if (TempLength == 1)
1170 break;
1171
1172 TempLength--;
1173 *MultiByteString++ = uChar >> 8;
1174 }
1175
1176 *MultiByteString++ = (char)uChar;
1177 }
1178
1179 /* WideCharCount should be 0 if all characters were converted */
1180 if (WideCharCount)
1181 {
1182 SetLastError(ERROR_INSUFFICIENT_BUFFER);
1183 return 0;
1184 }
1185
1186 return MultiByteCount - TempLength;
1187 }
1188 else /* SBCS code page */
1189 {
1190 INT nReturn;
1191
1192 /* If Flags, DefaultChar or UsedDefaultChar were given, we have to do some more work */
1193 if (Flags || DefaultChar || UsedDefaultChar)
1194 {
1195 BOOL TempUsedDefaultChar;
1196 CHAR DefChar;
1197
1198 /* If UsedDefaultChar is not set, set it to a temporary value, so we don't have
1199 to check on every character */
1200 if (!UsedDefaultChar)
1201 UsedDefaultChar = &TempUsedDefaultChar;
1202
1203 *UsedDefaultChar = FALSE;
1204
1205 /* Does caller query for output buffer size? */
1206 if (!MultiByteCount)
1207 {
1208 /* Loop through the whole WideCharString and check if we can get a valid mapping for each character */
1209 for (TempLength = 0; WideCharCount; TempLength++, WideCharString++, WideCharCount--)
1210 {
1211 if ((Flags & WC_COMPOSITECHECK) && WideCharCount > 1)
1212 {
1213 /* FIXME: Handle WC_COMPOSITECHECK */
1214 DPRINT("WC_COMPOSITECHECK flag UNIMPLEMENTED\n");
1215 }
1216
1217 if (!*UsedDefaultChar)
1218 *UsedDefaultChar = !IntIsValidSBCSMapping(CodePageTable,
1219 Flags,
1220 *WideCharString,
1221 ((PCHAR)CodePageTable->WideCharTable)[*WideCharString]);
1222 }
1223
1224 return TempLength;
1225 }
1226
1227 /* Use the CodePage's TransDefaultChar if none was given. Don't modify the DefaultChar pointer here. */
1228 if (DefaultChar)
1229 DefChar = *DefaultChar;
1230 else
1231 DefChar = (CHAR)CodePageTable->TransDefaultChar;
1232
1233 /* Convert the WideCharString to the MultiByteString and verify if the mapping is valid */
1234 for (TempLength = MultiByteCount;
1235 WideCharCount && TempLength;
1236 MultiByteString++, TempLength--, WideCharString++, WideCharCount--)
1237 {
1238 if ((Flags & WC_COMPOSITECHECK) && WideCharCount > 1)
1239 {
1240 /* FIXME: Handle WC_COMPOSITECHECK */
1241 DPRINT("WC_COMPOSITECHECK flag UNIMPLEMENTED\n");
1242 }
1243
1244 *MultiByteString = ((PCHAR)CodePageTable->WideCharTable)[*WideCharString];
1245
1246 if (!IntIsValidSBCSMapping(CodePageTable, Flags, *WideCharString, *MultiByteString))
1247 {
1248 *MultiByteString = DefChar;
1249 *UsedDefaultChar = TRUE;
1250 }
1251 }
1252
1253 /* WideCharCount should be 0 if all characters were converted */
1254 if (WideCharCount)
1255 {
1256 SetLastError(ERROR_INSUFFICIENT_BUFFER);
1257 return 0;
1258 }
1259
1260 return MultiByteCount - TempLength;
1261 }
1262
1263 /* Does caller query for output buffer size? */
1264 if (!MultiByteCount)
1265 return WideCharCount;
1266
1267 /* Is the buffer large enough? */
1268 if (MultiByteCount < WideCharCount)
1269 {
1270 /* Convert the string up to MultiByteCount and return 0 */
1271 WideCharCount = MultiByteCount;
1272 SetLastError(ERROR_INSUFFICIENT_BUFFER);
1273 nReturn = 0;
1274 }
1275 else
1276 {
1277 /* Otherwise WideCharCount will be the number of converted characters */
1278 nReturn = WideCharCount;
1279 }
1280
1281 /* Convert the WideCharString to the MultiByteString */
1282 for (TempLength = WideCharCount; --TempLength >= 0; WideCharString++, MultiByteString++)
1283 {
1284 *MultiByteString = ((PCHAR)CodePageTable->WideCharTable)[*WideCharString];
1285 }
1286
1287 return nReturn;
1288 }
1289 }
1290
1291 /**
1292 * @name IntIsLeadByte
1293 *
1294 * Internal function to detect if byte is lead byte in specific character
1295 * table.
1296 */
1297
1298 static BOOL
1299 WINAPI
1300 IntIsLeadByte(PCPTABLEINFO TableInfo, BYTE Byte)
1301 {
1302 UINT i;
1303
1304 if (TableInfo->MaximumCharacterSize == 2)
1305 {
1306 for (i = 0; i < MAXIMUM_LEADBYTES && TableInfo->LeadByte[i]; i += 2)
1307 {
1308 if (Byte >= TableInfo->LeadByte[i] && Byte <= TableInfo->LeadByte[i+1])
1309 return TRUE;
1310 }
1311 }
1312
1313 return FALSE;
1314 }
1315
1316 /* PUBLIC FUNCTIONS ***********************************************************/
1317
1318 /**
1319 * @name GetNlsSectionName
1320 *
1321 * Construct a name of NLS section.
1322 *
1323 * @param CodePage
1324 * Code page number.
1325 * @param Base
1326 * Integer base used for converting to string. Usually set to 10.
1327 * @param Unknown
1328 * As the name suggests the meaning of this parameter is unknown.
1329 * The native version of Kernel32 passes it as the third parameter
1330 * to NlsConvertIntegerToString function, which is used for the
1331 * actual conversion of the code page number.
1332 * @param BaseName
1333 * Base name of the section. (ex. "\\Nls\\NlsSectionCP")
1334 * @param Result
1335 * Buffer that will hold the constructed name.
1336 * @param ResultSize
1337 * Size of the buffer for the result.
1338 *
1339 * @return TRUE if the buffer was large enough and was filled with
1340 * the requested information, FALSE otherwise.
1341 *
1342 * @implemented
1343 */
1344
1345 BOOL
1346 WINAPI
1347 GetNlsSectionName(UINT CodePage,
1348 UINT Base,
1349 ULONG Unknown,
1350 LPSTR BaseName,
1351 LPSTR Result,
1352 ULONG ResultSize)
1353 {
1354 CHAR Integer[11];
1355
1356 if (!NT_SUCCESS(RtlIntegerToChar(CodePage, Base, sizeof(Integer), Integer)))
1357 return FALSE;
1358
1359 /*
1360 * If the name including the terminating NULL character doesn't
1361 * fit in the output buffer then fail.
1362 */
1363 if (strlen(Integer) + strlen(BaseName) >= ResultSize)
1364 return FALSE;
1365
1366 lstrcpyA(Result, BaseName);
1367 lstrcatA(Result, Integer);
1368
1369 return TRUE;
1370 }
1371
1372 /**
1373 * @name GetCPFileNameFromRegistry
1374 *
1375 * Get file name of code page definition file.
1376 *
1377 * @param CodePage
1378 * Code page number to get file name of.
1379 * @param FileName
1380 * Buffer that is filled with file name of successful return. Can
1381 * be set to NULL.
1382 * @param FileNameSize
1383 * Size of the buffer to hold file name in WCHARs.
1384 *
1385 * @return TRUE if the file name was retrieved, FALSE otherwise.
1386 *
1387 * @implemented
1388 */
1389
1390 BOOL
1391 WINAPI
1392 GetCPFileNameFromRegistry(UINT CodePage, LPWSTR FileName, ULONG FileNameSize)
1393 {
1394 WCHAR ValueNameBuffer[11];
1395 UNICODE_STRING KeyName, ValueName;
1396 OBJECT_ATTRIBUTES ObjectAttributes;
1397 NTSTATUS Status;
1398 HANDLE KeyHandle;
1399 PKEY_VALUE_PARTIAL_INFORMATION Kvpi;
1400 DWORD KvpiSize;
1401 BOOL bRetValue;
1402
1403 bRetValue = FALSE;
1404
1405 /* Convert the codepage number to string. */
1406 ValueName.Buffer = ValueNameBuffer;
1407 ValueName.MaximumLength = sizeof(ValueNameBuffer);
1408
1409 if (!NT_SUCCESS(RtlIntegerToUnicodeString(CodePage, 10, &ValueName)))
1410 return bRetValue;
1411
1412 /* Open the registry key containing file name mappings. */
1413 RtlInitUnicodeString(&KeyName, L"\\Registry\\Machine\\System\\"
1414 L"CurrentControlSet\\Control\\Nls\\CodePage");
1415 InitializeObjectAttributes(&ObjectAttributes, &KeyName, OBJ_CASE_INSENSITIVE,
1416 NULL, NULL);
1417 Status = NtOpenKey(&KeyHandle, KEY_READ, &ObjectAttributes);
1418 if (!NT_SUCCESS(Status))
1419 {
1420 return bRetValue;
1421 }
1422
1423 /* Allocate buffer that will be used to query the value data. */
1424 KvpiSize = sizeof(KEY_VALUE_PARTIAL_INFORMATION) + (MAX_PATH * sizeof(WCHAR));
1425 Kvpi = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, KvpiSize);
1426 if (Kvpi == NULL)
1427 {
1428 NtClose(KeyHandle);
1429 return bRetValue;
1430 }
1431
1432 /* Query the file name for our code page. */
1433 Status = NtQueryValueKey(KeyHandle, &ValueName, KeyValuePartialInformation,
1434 Kvpi, KvpiSize, &KvpiSize);
1435
1436 NtClose(KeyHandle);
1437
1438 /* Check if we succeded and the value is non-empty string. */
1439 if (NT_SUCCESS(Status) && Kvpi->Type == REG_SZ &&
1440 Kvpi->DataLength > sizeof(WCHAR))
1441 {
1442 bRetValue = TRUE;
1443 if (FileName != NULL)
1444 {
1445 lstrcpynW(FileName, (WCHAR*)Kvpi->Data,
1446 min(Kvpi->DataLength / sizeof(WCHAR), FileNameSize));
1447 }
1448 }
1449
1450 /* free temporary buffer */
1451 HeapFree(GetProcessHeap(),0,Kvpi);
1452 return bRetValue;
1453 }
1454
1455 /**
1456 * @name IsValidCodePage
1457 *
1458 * Detect if specified code page is valid and present in the system.
1459 *
1460 * @param CodePage
1461 * Code page number to query.
1462 *
1463 * @return TRUE if code page is present.
1464 */
1465
1466 BOOL
1467 WINAPI
1468 IsValidCodePage(UINT CodePage)
1469 {
1470 if (CodePage == 0) return FALSE;
1471 if (CodePage == CP_UTF8 || CodePage == CP_UTF7)
1472 return TRUE;
1473 if (IntGetLoadedCodePageEntry(CodePage))
1474 return TRUE;
1475 return GetCPFileNameFromRegistry(CodePage, NULL, 0);
1476 }
1477
1478 static inline BOOL utf7_write_w(WCHAR *dst, int dstlen, int *index, WCHAR character)
1479 {
1480 if (dstlen > 0)
1481 {
1482 if (*index >= dstlen)
1483 return FALSE;
1484
1485 dst[*index] = character;
1486 }
1487
1488 (*index)++;
1489
1490 return TRUE;
1491 }
1492
1493 static INT Utf7ToWideChar(const char *src, int srclen, WCHAR *dst, int dstlen)
1494 {
1495 static const signed char base64_decoding_table[] =
1496 {
1497 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 0x00-0x0F */
1498 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 0x10-0x1F */
1499 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 62, -1, -1, -1, 63, /* 0x20-0x2F */
1500 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, -1, -1, -1, -1, -1, -1, /* 0x30-0x3F */
1501 -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, /* 0x40-0x4F */
1502 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, -1, -1, -1, -1, -1, /* 0x50-0x5F */
1503 -1, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, /* 0x60-0x6F */
1504 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, -1, -1, -1, -1, -1 /* 0x70-0x7F */
1505 };
1506
1507 const char *source_end = src + srclen;
1508 int dest_index = 0;
1509
1510 DWORD byte_pair = 0;
1511 short offset = 0;
1512
1513 while (src < source_end)
1514 {
1515 if (*src == '+')
1516 {
1517 src++;
1518 if (src >= source_end)
1519 break;
1520
1521 if (*src == '-')
1522 {
1523 /* just a plus sign escaped as +- */
1524 if (!utf7_write_w(dst, dstlen, &dest_index, '+'))
1525 {
1526 SetLastError(ERROR_INSUFFICIENT_BUFFER);
1527 return 0;
1528 }
1529 src++;
1530 continue;
1531 }
1532
1533 do
1534 {
1535 signed char sextet = *src;
1536 if (sextet == '-')
1537 {
1538 /* skip over the dash and end base64 decoding
1539 * the current, unfinished byte pair is discarded */
1540 src++;
1541 offset = 0;
1542 break;
1543 }
1544 if (sextet < 0)
1545 {
1546 /* the next character of src is < 0 and therefore not part of a base64 sequence
1547 * the current, unfinished byte pair is NOT discarded in this case
1548 * this is probably a bug in Windows */
1549 break;
1550 }
1551
1552 sextet = base64_decoding_table[sextet];
1553 if (sextet == -1)
1554 {
1555 /* -1 means that the next character of src is not part of a base64 sequence
1556 * in other words, all sextets in this base64 sequence have been processed
1557 * the current, unfinished byte pair is discarded */
1558 offset = 0;
1559 break;
1560 }
1561
1562 byte_pair = (byte_pair << 6) | sextet;
1563 offset += 6;
1564
1565 if (offset >= 16)
1566 {
1567 /* this byte pair is done */
1568 if (!utf7_write_w(dst, dstlen, &dest_index, (byte_pair >> (offset - 16)) & 0xFFFF))
1569 {
1570 SetLastError(ERROR_INSUFFICIENT_BUFFER);
1571 return 0;
1572 }
1573 offset -= 16;
1574 }
1575
1576 src++;
1577 }
1578 while (src < source_end);
1579 }
1580 else
1581 {
1582 /* we have to convert to unsigned char in case *src < 0 */
1583 if (!utf7_write_w(dst, dstlen, &dest_index, (unsigned char)*src))
1584 {
1585 SetLastError(ERROR_INSUFFICIENT_BUFFER);
1586 return 0;
1587 }
1588 src++;
1589 }
1590 }
1591
1592 return dest_index;
1593 }
1594
1595 /**
1596 * @name MultiByteToWideChar
1597 *
1598 * Convert a multi-byte string to wide-charater equivalent.
1599 *
1600 * @param CodePage
1601 * Code page to be used to perform the conversion. It can be also
1602 * one of the special values (CP_ACP for ANSI code page, CP_MACCP
1603 * for Macintosh code page, CP_OEMCP for OEM code page, CP_THREAD_ACP
1604 * for thread active code page, CP_UTF7 or CP_UTF8).
1605 * @param Flags
1606 * Additional conversion flags (MB_PRECOMPOSED, MB_COMPOSITE,
1607 * MB_ERR_INVALID_CHARS, MB_USEGLYPHCHARS).
1608 * @param MultiByteString
1609 * Input buffer.
1610 * @param MultiByteCount
1611 * Size of MultiByteString, or -1 if MultiByteString is NULL
1612 * terminated.
1613 * @param WideCharString
1614 * Output buffer.
1615 * @param WideCharCount
1616 * Size in WCHARs of WideCharString, or 0 if the caller just wants
1617 * to know how large WideCharString should be for a successful
1618 * conversion.
1619 *
1620 * @return Zero on error, otherwise the number of WCHARs written
1621 * in the WideCharString buffer.
1622 *
1623 * @implemented
1624 */
1625
1626 INT
1627 WINAPI
1628 MultiByteToWideChar(UINT CodePage,
1629 DWORD Flags,
1630 LPCSTR MultiByteString,
1631 INT MultiByteCount,
1632 LPWSTR WideCharString,
1633 INT WideCharCount)
1634 {
1635 /* Check the parameters. */
1636 if (MultiByteString == NULL ||
1637 MultiByteCount == 0 || WideCharCount < 0 ||
1638 (WideCharCount && (WideCharString == NULL ||
1639 (PVOID)MultiByteString == (PVOID)WideCharString)))
1640 {
1641 SetLastError(ERROR_INVALID_PARAMETER);
1642 return 0;
1643 }
1644
1645 /* Determine the input string length. */
1646 if (MultiByteCount < 0)
1647 {
1648 MultiByteCount = lstrlenA(MultiByteString) + 1;
1649 }
1650
1651 switch (CodePage)
1652 {
1653 case CP_UTF8:
1654 return IntMultiByteToWideCharUTF8(Flags,
1655 MultiByteString,
1656 MultiByteCount,
1657 WideCharString,
1658 WideCharCount);
1659
1660 case CP_UTF7:
1661 if (Flags)
1662 {
1663 SetLastError(ERROR_INVALID_FLAGS);
1664 return 0;
1665 }
1666 return Utf7ToWideChar(MultiByteString, MultiByteCount,
1667 WideCharString, WideCharCount);
1668
1669 case CP_SYMBOL:
1670 return IntMultiByteToWideCharSYMBOL(Flags,
1671 MultiByteString,
1672 MultiByteCount,
1673 WideCharString,
1674 WideCharCount);
1675 default:
1676 return IntMultiByteToWideCharCP(CodePage,
1677 Flags,
1678 MultiByteString,
1679 MultiByteCount,
1680 WideCharString,
1681 WideCharCount);
1682 }
1683 }
1684
1685 static inline BOOL utf7_can_directly_encode(WCHAR codepoint)
1686 {
1687 static const BOOL directly_encodable_table[] =
1688 {
1689 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 1, 0, 0, /* 0x00 - 0x0F */
1690 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x10 - 0x1F */
1691 1, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 1, 1, 1, 1, 1, /* 0x20 - 0x2F */
1692 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 1, /* 0x30 - 0x3F */
1693 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 0x40 - 0x4F */
1694 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, /* 0x50 - 0x5F */
1695 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 0x60 - 0x6F */
1696 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 /* 0x70 - 0x7A */
1697 };
1698
1699 return codepoint <= 0x7A ? directly_encodable_table[codepoint] : FALSE;
1700 }
1701
1702 static inline BOOL utf7_write_c(char *dst, int dstlen, int *index, char character)
1703 {
1704 if (dstlen > 0)
1705 {
1706 if (*index >= dstlen)
1707 return FALSE;
1708
1709 dst[*index] = character;
1710 }
1711
1712 (*index)++;
1713
1714 return TRUE;
1715 }
1716
1717 static INT WideCharToUtf7(const WCHAR *src, int srclen, char *dst, int dstlen)
1718 {
1719 static const char base64_encoding_table[] =
1720 "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
1721
1722 const WCHAR *source_end = src + srclen;
1723 int dest_index = 0;
1724
1725 while (src < source_end)
1726 {
1727 if (*src == '+')
1728 {
1729 if (!utf7_write_c(dst, dstlen, &dest_index, '+'))
1730 {
1731 SetLastError(ERROR_INSUFFICIENT_BUFFER);
1732 return 0;
1733 }
1734 if (!utf7_write_c(dst, dstlen, &dest_index, '-'))
1735 {
1736 SetLastError(ERROR_INSUFFICIENT_BUFFER);
1737 return 0;
1738 }
1739 src++;
1740 }
1741 else if (utf7_can_directly_encode(*src))
1742 {
1743 if (!utf7_write_c(dst, dstlen, &dest_index, *src))
1744 {
1745 SetLastError(ERROR_INSUFFICIENT_BUFFER);
1746 return 0;
1747 }
1748 src++;
1749 }
1750 else
1751 {
1752 unsigned int offset = 0;
1753 DWORD byte_pair = 0;
1754
1755 if (!utf7_write_c(dst, dstlen, &dest_index, '+'))
1756 {
1757 SetLastError(ERROR_INSUFFICIENT_BUFFER);
1758 return 0;
1759 }
1760
1761 while (src < source_end && !utf7_can_directly_encode(*src))
1762 {
1763 byte_pair = (byte_pair << 16) | *src;
1764 offset += 16;
1765 while (offset >= 6)
1766 {
1767 if (!utf7_write_c(dst, dstlen, &dest_index, base64_encoding_table[(byte_pair >> (offset - 6)) & 0x3F]))
1768 {
1769 SetLastError(ERROR_INSUFFICIENT_BUFFER);
1770 return 0;
1771 }
1772 offset -= 6;
1773 }
1774 src++;
1775 }
1776
1777 if (offset)
1778 {
1779 /* Windows won't create a padded base64 character if there's no room for the - sign
1780 * as well ; this is probably a bug in Windows */
1781 if (dstlen > 0 && dest_index + 1 >= dstlen)
1782 {
1783 SetLastError(ERROR_INSUFFICIENT_BUFFER);
1784 return 0;
1785 }
1786
1787 byte_pair <<= (6 - offset);
1788 if (!utf7_write_c(dst, dstlen, &dest_index, base64_encoding_table[byte_pair & 0x3F]))
1789 {
1790 SetLastError(ERROR_INSUFFICIENT_BUFFER);
1791 return 0;
1792 }
1793 }
1794
1795 /* Windows always explicitly terminates the base64 sequence
1796 even though RFC 2152 (page 3, rule 2) does not require this */
1797 if (!utf7_write_c(dst, dstlen, &dest_index, '-'))
1798 {
1799 SetLastError(ERROR_INSUFFICIENT_BUFFER);
1800 return 0;
1801 }
1802 }
1803 }
1804
1805 return dest_index;
1806 }
1807
1808 /*
1809 * A function similar to LoadStringW, but adapted for usage by GetCPInfoExW
1810 * and GetGeoInfoW. It uses the current user localization, otherwise falls back
1811 * to English (US). Contrary to LoadStringW which always saves the loaded string
1812 * into the user-given buffer, truncating the string if needed, this function
1813 * returns instead an ERROR_INSUFFICIENT_BUFFER error code if the user buffer
1814 * is not large enough.
1815 */
1816 UINT
1817 GetLocalisedText(
1818 IN UINT uID,
1819 IN LPWSTR lpszDest,
1820 IN UINT cchDest)
1821 {
1822 HRSRC hrsrc;
1823 HGLOBAL hmem;
1824 LCID lcid;
1825 LANGID langId;
1826 const WCHAR *p;
1827 UINT i;
1828
1829 /* See HACK in winnls/lang/xx-XX.rc files */
1830 if (uID == 37)
1831 uID = uID * 100;
1832
1833 lcid = GetUserDefaultLCID();
1834 lcid = ConvertDefaultLocale(lcid);
1835
1836 langId = LANGIDFROMLCID(lcid);
1837
1838 if (PRIMARYLANGID(langId) == LANG_NEUTRAL)
1839 langId = MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US);
1840
1841 hrsrc = FindResourceExW(hCurrentModule,
1842 (LPWSTR)RT_STRING,
1843 MAKEINTRESOURCEW((uID >> 4) + 1),
1844 langId);
1845
1846 /* English fallback */
1847 if (!hrsrc)
1848 {
1849 hrsrc = FindResourceExW(hCurrentModule,
1850 (LPWSTR)RT_STRING,
1851 MAKEINTRESOURCEW((uID >> 4) + 1),
1852 MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US));
1853 }
1854
1855 if (!hrsrc)
1856 goto NotFound;
1857
1858 hmem = LoadResource(hCurrentModule, hrsrc);
1859 if (!hmem)
1860 goto NotFound;
1861
1862 p = LockResource(hmem);
1863
1864 for (i = 0; i < (uID & 0x0F); i++)
1865 p += *p + 1;
1866
1867 /* Needed for GetGeoInfo(): return the needed string size including the NULL terminator */
1868 if (cchDest == 0)
1869 return *p + 1;
1870 /* Needed for GetGeoInfo(): bail out if the user buffer is not large enough */
1871 if (*p + 1 > cchDest)
1872 {
1873 SetLastError(ERROR_INSUFFICIENT_BUFFER);
1874 return 0;
1875 }
1876
1877 i = *p;
1878 if (i > 0)
1879 {
1880 memcpy(lpszDest, p + 1, i * sizeof(WCHAR));
1881 lpszDest[i] = L'\0';
1882 return i;
1883 }
1884 #if 0
1885 else
1886 {
1887 if (cchDest >= 1)
1888 lpszDest[0] = L'\0';
1889 /* Fall-back */
1890 }
1891 #endif
1892
1893 NotFound:
1894 DPRINT1("Resource not found: uID = %lu\n", uID);
1895 SetLastError(ERROR_INVALID_PARAMETER);
1896 return 0;
1897 }
1898
1899 /*
1900 * @implemented
1901 */
1902 BOOL
1903 WINAPI
1904 GetCPInfo(UINT CodePage,
1905 LPCPINFO CodePageInfo)
1906 {
1907 PCODEPAGE_ENTRY CodePageEntry;
1908
1909 if (!CodePageInfo)
1910 {
1911 SetLastError(ERROR_INVALID_PARAMETER);
1912 return FALSE;
1913 }
1914
1915 CodePageEntry = IntGetCodePageEntry(CodePage);
1916 if (CodePageEntry == NULL)
1917 {
1918 switch(CodePage)
1919 {
1920 case CP_UTF7:
1921 case CP_UTF8:
1922 CodePageInfo->DefaultChar[0] = 0x3f;
1923 CodePageInfo->DefaultChar[1] = 0;
1924 CodePageInfo->LeadByte[0] = CodePageInfo->LeadByte[1] = 0;
1925 CodePageInfo->MaxCharSize = (CodePage == CP_UTF7) ? 5 : 4;
1926 return TRUE;
1927 }
1928
1929 DPRINT1("Invalid CP!: %lx\n", CodePage);
1930 SetLastError( ERROR_INVALID_PARAMETER );
1931 return FALSE;
1932 }
1933
1934 if (CodePageEntry->CodePageTable.DefaultChar & 0xff00)
1935 {
1936 CodePageInfo->DefaultChar[0] = (CodePageEntry->CodePageTable.DefaultChar & 0xff00) >> 8;
1937 CodePageInfo->DefaultChar[1] = CodePageEntry->CodePageTable.DefaultChar & 0x00ff;
1938 }
1939 else
1940 {
1941 CodePageInfo->DefaultChar[0] = CodePageEntry->CodePageTable.DefaultChar & 0xff;
1942 CodePageInfo->DefaultChar[1] = 0;
1943 }
1944
1945 if ((CodePageInfo->MaxCharSize = CodePageEntry->CodePageTable.MaximumCharacterSize) == 2)
1946 memcpy(CodePageInfo->LeadByte, CodePageEntry->CodePageTable.LeadByte, sizeof(CodePageInfo->LeadByte));
1947 else
1948 CodePageInfo->LeadByte[0] = CodePageInfo->LeadByte[1] = 0;
1949
1950 return TRUE;
1951 }
1952
1953 /*
1954 * @implemented
1955 */
1956 BOOL
1957 WINAPI
1958 GetCPInfoExW(UINT CodePage,
1959 DWORD dwFlags,
1960 LPCPINFOEXW lpCPInfoEx)
1961 {
1962 if (!GetCPInfo(CodePage, (LPCPINFO)lpCPInfoEx))
1963 return FALSE;
1964
1965 switch(CodePage)
1966 {
1967 case CP_UTF7:
1968 {
1969 lpCPInfoEx->CodePage = CP_UTF7;
1970 lpCPInfoEx->UnicodeDefaultChar = 0x3f;
1971 return GetLocalisedText(lpCPInfoEx->CodePage,
1972 lpCPInfoEx->CodePageName,
1973 ARRAYSIZE(lpCPInfoEx->CodePageName)) != 0;
1974 }
1975 break;
1976
1977 case CP_UTF8:
1978 {
1979 lpCPInfoEx->CodePage = CP_UTF8;
1980 lpCPInfoEx->UnicodeDefaultChar = 0x3f;
1981 return GetLocalisedText(lpCPInfoEx->CodePage,
1982 lpCPInfoEx->CodePageName,
1983 ARRAYSIZE(lpCPInfoEx->CodePageName)) != 0;
1984 }
1985
1986 default:
1987 {
1988 PCODEPAGE_ENTRY CodePageEntry;
1989
1990 CodePageEntry = IntGetCodePageEntry(CodePage);
1991 if (CodePageEntry == NULL)
1992 {
1993 DPRINT1("Could not get CodePage Entry! CodePageEntry = NULL\n");
1994 SetLastError(ERROR_INVALID_PARAMETER);
1995 return FALSE;
1996 }
1997
1998 lpCPInfoEx->CodePage = CodePageEntry->CodePageTable.CodePage;
1999 lpCPInfoEx->UnicodeDefaultChar = CodePageEntry->CodePageTable.UniDefaultChar;
2000 return GetLocalisedText(lpCPInfoEx->CodePage,
2001 lpCPInfoEx->CodePageName,
2002 ARRAYSIZE(lpCPInfoEx->CodePageName)) != 0;
2003 }
2004 break;
2005 }
2006 }
2007
2008
2009 /*
2010 * @implemented
2011 */
2012 BOOL
2013 WINAPI
2014 GetCPInfoExA(UINT CodePage,
2015 DWORD dwFlags,
2016 LPCPINFOEXA lpCPInfoEx)
2017 {
2018 CPINFOEXW CPInfo;
2019
2020 if (!GetCPInfoExW(CodePage, dwFlags, &CPInfo))
2021 return FALSE;
2022
2023 /* the layout is the same except for CodePageName */
2024 memcpy(lpCPInfoEx, &CPInfo, sizeof(CPINFOEXA));
2025
2026 WideCharToMultiByte(CP_ACP,
2027 0,
2028 CPInfo.CodePageName,
2029 -1,
2030 lpCPInfoEx->CodePageName,
2031 sizeof(lpCPInfoEx->CodePageName),
2032 NULL,
2033 NULL);
2034 return TRUE;
2035 }
2036
2037 /**
2038 * @name WideCharToMultiByte
2039 *
2040 * Convert a wide-charater string to closest multi-byte equivalent.
2041 *
2042 * @param CodePage
2043 * Code page to be used to perform the conversion. It can be also
2044 * one of the special values (CP_ACP for ANSI code page, CP_MACCP
2045 * for Macintosh code page, CP_OEMCP for OEM code page, CP_THREAD_ACP
2046 * for thread active code page, CP_UTF7 or CP_UTF8).
2047 * @param Flags
2048 * Additional conversion flags (WC_NO_BEST_FIT_CHARS, WC_COMPOSITECHECK,
2049 * WC_DISCARDNS, WC_SEPCHARS, WC_DEFAULTCHAR).
2050 * @param WideCharString
2051 * Points to the wide-character string to be converted.
2052 * @param WideCharCount
2053 * Size in WCHARs of WideCharStr, or 0 if the caller just wants to
2054 * know how large WideCharString should be for a successful conversion.
2055 * @param MultiByteString
2056 * Points to the buffer to receive the translated string.
2057 * @param MultiByteCount
2058 * Specifies the size in bytes of the buffer pointed to by the
2059 * MultiByteString parameter. If this value is zero, the function
2060 * returns the number of bytes required for the buffer.
2061 * @param DefaultChar
2062 * Points to the character used if a wide character cannot be
2063 * represented in the specified code page. If this parameter is
2064 * NULL, a system default value is used.
2065 * @param UsedDefaultChar
2066 * Points to a flag that indicates whether a default character was
2067 * used. This parameter can be NULL.
2068 *
2069 * @return Zero on error, otherwise the number of bytes written in the
2070 * MultiByteString buffer. Or the number of bytes needed for
2071 * the MultiByteString buffer if MultiByteCount is zero.
2072 *
2073 * @implemented
2074 */
2075
2076 INT
2077 WINAPI
2078 WideCharToMultiByte(UINT CodePage,
2079 DWORD Flags,
2080 LPCWSTR WideCharString,
2081 INT WideCharCount,
2082 LPSTR MultiByteString,
2083 INT MultiByteCount,
2084 LPCSTR DefaultChar,
2085 LPBOOL UsedDefaultChar)
2086 {
2087 /* Check the parameters. */
2088 if (WideCharString == NULL ||
2089 WideCharCount == 0 ||
2090 (MultiByteString == NULL && MultiByteCount > 0) ||
2091 (PVOID)WideCharString == (PVOID)MultiByteString ||
2092 MultiByteCount < 0)
2093 {
2094 SetLastError(ERROR_INVALID_PARAMETER);
2095 return 0;
2096 }
2097
2098 /* Determine the input string length. */
2099 if (WideCharCount < 0)
2100 {
2101 WideCharCount = lstrlenW(WideCharString) + 1;
2102 }
2103
2104 switch (CodePage)
2105 {
2106 case CP_UTF8:
2107 if (DefaultChar != NULL || UsedDefaultChar != NULL)
2108 {
2109 SetLastError(ERROR_INVALID_PARAMETER);
2110 return 0;
2111 }
2112 return IntWideCharToMultiByteUTF8(CodePage,
2113 Flags,
2114 WideCharString,
2115 WideCharCount,
2116 MultiByteString,
2117 MultiByteCount,
2118 DefaultChar,
2119 UsedDefaultChar);
2120
2121 case CP_UTF7:
2122 if (DefaultChar != NULL || UsedDefaultChar != NULL)
2123 {
2124 SetLastError(ERROR_INVALID_PARAMETER);
2125 return 0;
2126 }
2127 if (Flags)
2128 {
2129 SetLastError(ERROR_INVALID_FLAGS);
2130 return 0;
2131 }
2132 return WideCharToUtf7(WideCharString, WideCharCount,
2133 MultiByteString, MultiByteCount);
2134
2135 case CP_SYMBOL:
2136 if ((DefaultChar!=NULL) || (UsedDefaultChar!=NULL))
2137 {
2138 SetLastError(ERROR_INVALID_PARAMETER);
2139 return 0;
2140 }
2141 return IntWideCharToMultiByteSYMBOL(Flags,
2142 WideCharString,
2143 WideCharCount,
2144 MultiByteString,
2145 MultiByteCount);
2146
2147 default:
2148 return IntWideCharToMultiByteCP(CodePage,
2149 Flags,
2150 WideCharString,
2151 WideCharCount,
2152 MultiByteString,
2153 MultiByteCount,
2154 DefaultChar,
2155 UsedDefaultChar);
2156 }
2157 }
2158
2159 /**
2160 * @name GetACP
2161 *
2162 * Get active ANSI code page number.
2163 *
2164 * @implemented
2165 */
2166
2167 UINT
2168 WINAPI
2169 GetACP(VOID)
2170 {
2171 return AnsiCodePage.CodePageTable.CodePage;
2172 }
2173
2174 /**
2175 * @name GetOEMCP
2176 *
2177 * Get active OEM code page number.
2178 *
2179 * @implemented
2180 */
2181
2182 UINT
2183 WINAPI
2184 GetOEMCP(VOID)
2185 {
2186 return OemCodePage.CodePageTable.CodePage;
2187 }
2188
2189 /**
2190 * @name IsDBCSLeadByteEx
2191 *
2192 * Determine if passed byte is lead byte in specified code page.
2193 *
2194 * @implemented
2195 */
2196
2197 BOOL
2198 WINAPI
2199 IsDBCSLeadByteEx(UINT CodePage, BYTE TestByte)
2200 {
2201 PCODEPAGE_ENTRY CodePageEntry;
2202
2203 CodePageEntry = IntGetCodePageEntry(CodePage);
2204 if (CodePageEntry != NULL)
2205 return IntIsLeadByte(&CodePageEntry->CodePageTable, TestByte);
2206
2207 SetLastError(ERROR_INVALID_PARAMETER);
2208 return FALSE;
2209 }
2210
2211 /**
2212 * @name IsDBCSLeadByteEx
2213 *
2214 * Determine if passed byte is lead byte in current ANSI code page.
2215 *
2216 * @implemented
2217 */
2218
2219 BOOL
2220 WINAPI
2221 IsDBCSLeadByte(BYTE TestByte)
2222 {
2223 return IntIsLeadByte(&AnsiCodePage.CodePageTable, TestByte);
2224 }
2225
2226 /*
2227 * @unimplemented
2228 */
2229 NTSTATUS WINAPI CreateNlsSecurityDescriptor(PSECURITY_DESCRIPTOR SecurityDescriptor,ULONG Size,ULONG AccessMask)
2230 {
2231 STUB;
2232 return 0;
2233 }
2234
2235 /*
2236 * @unimplemented
2237 */
2238 BOOL WINAPI IsValidUILanguage(LANGID langid)
2239 {
2240 STUB;
2241 return 0;
2242 }
2243
2244 /*
2245 * @unimplemented
2246 */
2247 VOID WINAPI NlsConvertIntegerToString(ULONG Value,ULONG Base,ULONG strsize, LPWSTR str, ULONG strsize2)
2248 {
2249 STUB;
2250 }
2251
2252 /*
2253 * @unimplemented
2254 */
2255 UINT WINAPI SetCPGlobal(UINT CodePage)
2256 {
2257 STUB;
2258 return 0;
2259 }
2260
2261 /*
2262 * @unimplemented
2263 */
2264 BOOL
2265 WINAPI
2266 ValidateLCType(int a1, unsigned int a2, int a3, int a4)
2267 {
2268 STUB;
2269 return FALSE;
2270 }
2271
2272 /*
2273 * @unimplemented
2274 */
2275 BOOL
2276 WINAPI
2277 NlsResetProcessLocale(VOID)
2278 {
2279 STUB;
2280 return TRUE;
2281 }
2282
2283 /*
2284 * @unimplemented
2285 */
2286 VOID
2287 WINAPI
2288 GetDefaultSortkeySize(LPVOID lpUnknown)
2289 {
2290 STUB;
2291 lpUnknown = NULL;
2292 }
2293
2294 /*
2295 * @unimplemented
2296 */
2297 VOID
2298 WINAPI
2299 GetLinguistLangSize(LPVOID lpUnknown)
2300 {
2301 STUB;
2302 lpUnknown = NULL;
2303 }
2304
2305 /*
2306 * @unimplemented
2307 */
2308 BOOL
2309 WINAPI
2310 ValidateLocale(IN ULONG LocaleId)
2311 {
2312 STUB;
2313 return TRUE;
2314 }
2315
2316 /*
2317 * @unimplemented
2318 */
2319 ULONG
2320 WINAPI
2321 NlsGetCacheUpdateCount(VOID)
2322 {
2323 STUB;
2324 return 0;
2325 }
2326
2327 /*
2328 * @unimplemented
2329 */
2330 BOOL
2331 WINAPI
2332 IsNLSDefinedString(IN NLS_FUNCTION Function,
2333 IN DWORD dwFlags,
2334 IN LPNLSVERSIONINFO lpVersionInformation,
2335 IN LPCWSTR lpString,
2336 IN INT cchStr)
2337 {
2338 STUB;
2339 return TRUE;
2340 }
2341
2342 /*
2343 * @unimplemented
2344 */
2345 BOOL
2346 WINAPI
2347 GetNLSVersion(IN NLS_FUNCTION Function,
2348 IN LCID Locale,
2349 IN OUT LPNLSVERSIONINFO lpVersionInformation)
2350 {
2351 STUB;
2352 return TRUE;
2353 }
2354
2355 /*
2356 * @unimplemented
2357 */
2358 BOOL
2359 WINAPI
2360 GetNLSVersionEx(IN NLS_FUNCTION function,
2361 IN LPCWSTR lpLocaleName,
2362 IN OUT LPNLSVERSIONINFOEX lpVersionInformation)
2363 {
2364 STUB;
2365 return TRUE;
2366 }
2367
2368 /* EOF */