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