Home | Info | Community | Development | myReactOS | Contact Us
ReactOS Development > Doxygennls.c
Go to the documentation of this file.
00001 /* $Id: nls.c 52854 2011-07-24 23:42:09Z ion $ 00002 * 00003 * COPYRIGHT: See COPYING in the top level directory 00004 * PROJECT: ReactOS system libraries 00005 * FILE: dll/win32/kernel32/misc/nls.c 00006 * PURPOSE: National Language Support 00007 * PROGRAMMER: Filip Navara 00008 * Hartmut Birr 00009 * Gunnar Andre Dalsnes 00010 * Thomas Weidenmueller 00011 * UPDATE HISTORY: 00012 * Created 24/08/2004 00013 */ 00014 00015 /* INCLUDES *******************************************************************/ 00016 00017 #include <k32.h> 00018 #define NDEBUG 00019 #include <debug.h> 00020 00021 /* GLOBAL VARIABLES ***********************************************************/ 00022 00023 /* Sequence length based on the first character. */ 00024 static const char UTF8Length[128] = 00025 { 00026 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x80 - 0x8F */ 00027 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x90 - 0x9F */ 00028 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0xA0 - 0xAF */ 00029 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0xB0 - 0xBF */ 00030 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 0xC0 - 0xCF */ 00031 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 0xD0 - 0xDF */ 00032 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, /* 0xE0 - 0xEF */ 00033 3, 3, 3, 3, 3, 3, 3, 3, 4, 4, 4, 4, 5, 5, 0, 0 /* 0xF0 - 0xFF */ 00034 }; 00035 00036 /* First byte mask depending on UTF-8 sequence length. */ 00037 static const unsigned char UTF8Mask[6] = {0x7f, 0x1f, 0x0f, 0x07, 0x03, 0x01}; 00038 00039 /* FIXME: Change to HASH table or linear array. */ 00040 static LIST_ENTRY CodePageListHead; 00041 static CODEPAGE_ENTRY AnsiCodePage; 00042 static CODEPAGE_ENTRY OemCodePage; 00043 static RTL_CRITICAL_SECTION CodePageListLock; 00044 00045 /* FORWARD DECLARATIONS *******************************************************/ 00046 00047 BOOL WINAPI 00048 GetNlsSectionName(UINT CodePage, UINT Base, ULONG Unknown, 00049 LPSTR BaseName, LPSTR Result, ULONG ResultSize); 00050 00051 BOOL WINAPI 00052 GetCPFileNameFromRegistry(UINT CodePage, LPWSTR FileName, ULONG FileNameSize); 00053 00054 /* PRIVATE FUNCTIONS **********************************************************/ 00055 00062 BOOL 00063 FASTCALL 00064 NlsInit(VOID) 00065 { 00066 UNICODE_STRING DirName; 00067 OBJECT_ATTRIBUTES ObjectAttributes; 00068 HANDLE Handle; 00069 00070 InitializeListHead(&CodePageListHead); 00071 RtlInitializeCriticalSection(&CodePageListLock); 00072 00073 /* 00074 * FIXME: Eventually this should be done only for the NLS Server 00075 * process, but since we don't have anything like that (yet?) we 00076 * always try to create the "\Nls" directory here. 00077 */ 00078 RtlInitUnicodeString(&DirName, L"\\Nls"); 00079 00080 InitializeObjectAttributes(&ObjectAttributes, 00081 &DirName, 00082 OBJ_CASE_INSENSITIVE | OBJ_PERMANENT, 00083 NULL, 00084 NULL); 00085 00086 if (NT_SUCCESS(NtCreateDirectoryObject(&Handle, DIRECTORY_ALL_ACCESS, &ObjectAttributes))) 00087 { 00088 NtClose(Handle); 00089 } 00090 00091 /* Setup ANSI code page. */ 00092 AnsiCodePage.CodePage = CP_ACP; 00093 AnsiCodePage.SectionHandle = NULL; 00094 AnsiCodePage.SectionMapping = NtCurrentTeb()->ProcessEnvironmentBlock->AnsiCodePageData; 00095 00096 RtlInitCodePageTable((PUSHORT)AnsiCodePage.SectionMapping, 00097 &AnsiCodePage.CodePageTable); 00098 InsertTailList(&CodePageListHead, &AnsiCodePage.Entry); 00099 00100 /* Setup OEM code page. */ 00101 OemCodePage.CodePage = CP_OEMCP; 00102 OemCodePage.SectionHandle = NULL; 00103 OemCodePage.SectionMapping = NtCurrentTeb()->ProcessEnvironmentBlock->OemCodePageData; 00104 00105 RtlInitCodePageTable((PUSHORT)OemCodePage.SectionMapping, 00106 &OemCodePage.CodePageTable); 00107 InsertTailList(&CodePageListHead, &OemCodePage.Entry); 00108 00109 return TRUE; 00110 } 00111 00118 VOID 00119 FASTCALL 00120 NlsUninit(VOID) 00121 { 00122 PCODEPAGE_ENTRY Current; 00123 00124 /* Delete the code page list. */ 00125 while (!IsListEmpty(&CodePageListHead)) 00126 { 00127 Current = CONTAINING_RECORD(CodePageListHead.Flink, CODEPAGE_ENTRY, Entry); 00128 if (Current->SectionHandle != NULL) 00129 { 00130 UnmapViewOfFile(Current->SectionMapping); 00131 NtClose(Current->SectionHandle); 00132 } 00133 RemoveHeadList(&CodePageListHead); 00134 } 00135 RtlDeleteCriticalSection(&CodePageListLock); 00136 } 00137 00152 PCODEPAGE_ENTRY 00153 FASTCALL 00154 IntGetLoadedCodePageEntry(UINT CodePage) 00155 { 00156 LIST_ENTRY *CurrentEntry; 00157 PCODEPAGE_ENTRY Current; 00158 00159 RtlEnterCriticalSection(&CodePageListLock); 00160 for (CurrentEntry = CodePageListHead.Flink; 00161 CurrentEntry != &CodePageListHead; 00162 CurrentEntry = CurrentEntry->Flink) 00163 { 00164 Current = CONTAINING_RECORD(CurrentEntry, CODEPAGE_ENTRY, Entry); 00165 if (Current->CodePage == CodePage) 00166 { 00167 RtlLeaveCriticalSection(&CodePageListLock); 00168 return Current; 00169 } 00170 } 00171 RtlLeaveCriticalSection(&CodePageListLock); 00172 00173 return NULL; 00174 } 00175 00188 PCODEPAGE_ENTRY 00189 FASTCALL 00190 IntGetCodePageEntry(UINT CodePage) 00191 { 00192 CHAR SectionName[40]; 00193 NTSTATUS Status; 00194 HANDLE SectionHandle = INVALID_HANDLE_VALUE, FileHandle; 00195 PBYTE SectionMapping; 00196 OBJECT_ATTRIBUTES ObjectAttributes; 00197 ANSI_STRING AnsiName; 00198 UNICODE_STRING UnicodeName; 00199 WCHAR FileName[MAX_PATH + 1]; 00200 UINT FileNamePos; 00201 PCODEPAGE_ENTRY CodePageEntry; 00202 00203 if (CodePage == CP_THREAD_ACP) 00204 { 00205 if (!GetLocaleInfoW(GetThreadLocale(), 00206 LOCALE_IDEFAULTANSICODEPAGE | LOCALE_RETURN_NUMBER, 00207 (WCHAR *)&CodePage, 00208 sizeof(CodePage) / sizeof(WCHAR))) 00209 { 00210 /* Last error is set by GetLocaleInfoW. */ 00211 return NULL; 00212 } 00213 } 00214 else if (CodePage == CP_MACCP) 00215 { 00216 if (!GetLocaleInfoW(LOCALE_SYSTEM_DEFAULT, 00217 LOCALE_IDEFAULTMACCODEPAGE | LOCALE_RETURN_NUMBER, 00218 (WCHAR *)&CodePage, 00219 sizeof(CodePage) / sizeof(WCHAR))) 00220 { 00221 /* Last error is set by GetLocaleInfoW. */ 00222 return NULL; 00223 } 00224 } 00225 00226 /* Try searching for loaded page first. */ 00227 CodePageEntry = IntGetLoadedCodePageEntry(CodePage); 00228 if (CodePageEntry != NULL) 00229 { 00230 return CodePageEntry; 00231 } 00232 00233 /* 00234 * Yes, we really want to lock here. Otherwise it can happen that 00235 * two parallel requests will try to get the entry for the same 00236 * code page and we would load it twice. 00237 */ 00238 RtlEnterCriticalSection(&CodePageListLock); 00239 00240 /* Generate the section name. */ 00241 if (!GetNlsSectionName(CodePage, 00242 10, 00243 0, 00244 "\\Nls\\NlsSectionCP", 00245 SectionName, 00246 sizeof(SectionName))) 00247 { 00248 RtlLeaveCriticalSection(&CodePageListLock); 00249 return NULL; 00250 } 00251 00252 RtlInitAnsiString(&AnsiName, SectionName); 00253 RtlAnsiStringToUnicodeString(&UnicodeName, &AnsiName, TRUE); 00254 00255 InitializeObjectAttributes(&ObjectAttributes, &UnicodeName, 0, NULL, NULL); 00256 00257 /* Try to open the section first */ 00258 Status = NtOpenSection(&SectionHandle, SECTION_MAP_READ, &ObjectAttributes); 00259 00260 /* If the section doesn't exist, try to create it. */ 00261 if (Status == STATUS_UNSUCCESSFUL || 00262 Status == STATUS_OBJECT_NAME_NOT_FOUND || 00263 Status == STATUS_OBJECT_PATH_NOT_FOUND) 00264 { 00265 FileNamePos = GetSystemDirectoryW(FileName, MAX_PATH); 00266 if (GetCPFileNameFromRegistry(CodePage, 00267 FileName + FileNamePos + 1, 00268 MAX_PATH - FileNamePos - 1)) 00269 { 00270 FileName[FileNamePos] = L'\\'; 00271 FileName[MAX_PATH] = 0; 00272 FileHandle = CreateFileW(FileName, 00273 FILE_GENERIC_READ, 00274 FILE_SHARE_READ, 00275 NULL, 00276 OPEN_EXISTING, 00277 0, 00278 NULL); 00279 00280 Status = NtCreateSection(&SectionHandle, 00281 SECTION_MAP_READ, 00282 &ObjectAttributes, 00283 NULL, 00284 PAGE_READONLY, 00285 SEC_COMMIT, 00286 FileHandle); 00287 00288 /* HACK: Check if another process was faster 00289 * and already created this section. See bug 3626 for details */ 00290 if (Status == STATUS_OBJECT_NAME_COLLISION) 00291 { 00292 /* Close the file then */ 00293 NtClose(FileHandle); 00294 00295 /* And open the section */ 00296 Status = NtOpenSection(&SectionHandle, 00297 SECTION_MAP_READ, 00298 &ObjectAttributes); 00299 } 00300 } 00301 } 00302 RtlFreeUnicodeString(&UnicodeName); 00303 00304 if (!NT_SUCCESS(Status)) 00305 { 00306 RtlLeaveCriticalSection(&CodePageListLock); 00307 return NULL; 00308 } 00309 00310 SectionMapping = MapViewOfFile(SectionHandle, FILE_MAP_READ, 0, 0, 0); 00311 if (SectionMapping == NULL) 00312 { 00313 NtClose(SectionHandle); 00314 RtlLeaveCriticalSection(&CodePageListLock); 00315 return NULL; 00316 } 00317 00318 CodePageEntry = HeapAlloc(GetProcessHeap(), 0, sizeof(CODEPAGE_ENTRY)); 00319 if (CodePageEntry == NULL) 00320 { 00321 NtClose(SectionHandle); 00322 RtlLeaveCriticalSection(&CodePageListLock); 00323 return NULL; 00324 } 00325 00326 CodePageEntry->CodePage = CodePage; 00327 CodePageEntry->SectionHandle = SectionHandle; 00328 CodePageEntry->SectionMapping = SectionMapping; 00329 00330 RtlInitCodePageTable((PUSHORT)SectionMapping, &CodePageEntry->CodePageTable); 00331 00332 /* Insert the new entry to list and unlock. Uff. */ 00333 InsertTailList(&CodePageListHead, &CodePageEntry->Entry); 00334 RtlLeaveCriticalSection(&CodePageListLock); 00335 00336 return CodePageEntry; 00337 } 00338 00348 static 00349 INT 00350 WINAPI 00351 IntMultiByteToWideCharUTF8(DWORD Flags, 00352 LPCSTR MultiByteString, 00353 INT MultiByteCount, 00354 LPWSTR WideCharString, 00355 INT WideCharCount) 00356 { 00357 LPCSTR MbsEnd; 00358 UCHAR Char, Length; 00359 WCHAR WideChar; 00360 LONG Count; 00361 00362 if (Flags != 0) 00363 { 00364 SetLastError(ERROR_INVALID_FLAGS); 00365 return 0; 00366 } 00367 00368 /* Does caller query for output buffer size? */ 00369 if (WideCharCount == 0) 00370 { 00371 MbsEnd = MultiByteString + MultiByteCount; 00372 for (; MultiByteString < MbsEnd; WideCharCount++) 00373 { 00374 Char = *MultiByteString++; 00375 if (Char < 0xC0) 00376 continue; 00377 MultiByteString += UTF8Length[Char - 0x80]; 00378 } 00379 return WideCharCount; 00380 } 00381 00382 MbsEnd = MultiByteString + MultiByteCount; 00383 for (Count = 0; Count < WideCharCount && MultiByteString < MbsEnd; Count++) 00384 { 00385 Char = *MultiByteString++; 00386 if (Char < 0x80) 00387 { 00388 *WideCharString++ = Char; 00389 continue; 00390 } 00391 Length = UTF8Length[Char - 0x80]; 00392 WideChar = Char & UTF8Mask[Length]; 00393 while (Length && MultiByteString < MbsEnd) 00394 { 00395 WideChar = (WideChar << 6) | (*MultiByteString++ & 0x7f); 00396 Length--; 00397 } 00398 *WideCharString++ = WideChar; 00399 } 00400 00401 if (MultiByteString < MbsEnd) 00402 SetLastError(ERROR_INSUFFICIENT_BUFFER); 00403 00404 return Count; 00405 } 00406 00417 static 00418 INT 00419 WINAPI 00420 IntMultiByteToWideCharCP(UINT CodePage, 00421 DWORD Flags, 00422 LPCSTR MultiByteString, 00423 INT MultiByteCount, 00424 LPWSTR WideCharString, 00425 INT WideCharCount) 00426 { 00427 PCODEPAGE_ENTRY CodePageEntry; 00428 PCPTABLEINFO CodePageTable; 00429 LPCSTR TempString; 00430 INT TempLength; 00431 00432 /* Get code page table. */ 00433 CodePageEntry = IntGetCodePageEntry(CodePage); 00434 if (CodePageEntry == NULL) 00435 { 00436 SetLastError(ERROR_INVALID_PARAMETER); 00437 return 0; 00438 } 00439 CodePageTable = &CodePageEntry->CodePageTable; 00440 00441 /* Different handling for DBCS code pages. */ 00442 if (CodePageTable->MaximumCharacterSize > 1) 00443 { 00444 /* FIXME */ 00445 00446 UCHAR Char; 00447 USHORT DBCSOffset; 00448 LPCSTR MbsEnd = MultiByteString + MultiByteCount; 00449 INT Count; 00450 00451 /* Does caller query for output buffer size? */ 00452 if (WideCharCount == 0) 00453 { 00454 for (; MultiByteString < MbsEnd; WideCharCount++) 00455 { 00456 Char = *MultiByteString++; 00457 00458 if (Char < 0x80) 00459 continue; 00460 00461 DBCSOffset = CodePageTable->DBCSOffsets[Char]; 00462 00463 if (!DBCSOffset) 00464 continue; 00465 00466 if (MultiByteString < MbsEnd) 00467 MultiByteString++; 00468 } 00469 00470 return WideCharCount; 00471 } 00472 00473 for (Count = 0; Count < WideCharCount && MultiByteString < MbsEnd; Count++) 00474 { 00475 Char = *MultiByteString++; 00476 00477 if (Char < 0x80) 00478 { 00479 *WideCharString++ = Char; 00480 continue; 00481 } 00482 00483 DBCSOffset = CodePageTable->DBCSOffsets[Char]; 00484 00485 if (!DBCSOffset) 00486 { 00487 *WideCharString++ = CodePageTable->MultiByteTable[Char]; 00488 continue; 00489 } 00490 00491 if (MultiByteString < MbsEnd) 00492 *WideCharString++ = CodePageTable->DBCSOffsets[DBCSOffset + *(PUCHAR)MultiByteString++]; 00493 } 00494 00495 if (MultiByteString < MbsEnd) 00496 { 00497 SetLastError(ERROR_INSUFFICIENT_BUFFER); 00498 return 0; 00499 } 00500 00501 return Count; 00502 } 00503 else /* Not DBCS code page */ 00504 { 00505 /* Check for invalid characters. */ 00506 if (Flags & MB_ERR_INVALID_CHARS) 00507 { 00508 for (TempString = MultiByteString, TempLength = MultiByteCount; 00509 TempLength > 0; 00510 TempString++, TempLength--) 00511 { 00512 if (CodePageTable->MultiByteTable[(UCHAR)*TempString] == 00513 CodePageTable->UniDefaultChar && 00514 *TempString != CodePageEntry->CodePageTable.DefaultChar) 00515 { 00516 SetLastError(ERROR_NO_UNICODE_TRANSLATION); 00517 return 0; 00518 } 00519 } 00520 } 00521 00522 /* Does caller query for output buffer size? */ 00523 if (WideCharCount == 0) 00524 return MultiByteCount; 00525 00526 /* Fill the WideCharString buffer with what will fit: Verified on WinXP */ 00527 for (TempLength = (WideCharCount < MultiByteCount) ? WideCharCount : MultiByteCount; 00528 TempLength > 0; 00529 MultiByteString++, TempLength--) 00530 { 00531 *WideCharString++ = CodePageTable->MultiByteTable[(UCHAR)*MultiByteString]; 00532 } 00533 00534 /* Adjust buffer size. Wine trick ;-) */ 00535 if (WideCharCount < MultiByteCount) 00536 { 00537 MultiByteCount = WideCharCount; 00538 SetLastError(ERROR_INSUFFICIENT_BUFFER); 00539 return 0; 00540 } 00541 return MultiByteCount; 00542 } 00543 } 00544 00553 static 00554 INT 00555 WINAPI 00556 IntMultiByteToWideCharSYMBOL(DWORD Flags, 00557 LPCSTR MultiByteString, 00558 INT MultiByteCount, 00559 LPWSTR WideCharString, 00560 INT WideCharCount) 00561 { 00562 LONG Count; 00563 UCHAR Char; 00564 INT WideCharMaxLen; 00565 00566 00567 if (Flags != 0) 00568 { 00569 SetLastError(ERROR_INVALID_FLAGS); 00570 return 0; 00571 } 00572 00573 if (WideCharCount == 0) 00574 { 00575 return MultiByteCount; 00576 } 00577 00578 WideCharMaxLen = WideCharCount > MultiByteCount ? MultiByteCount : WideCharCount; 00579 00580 for (Count = 0; Count < WideCharMaxLen; Count++) 00581 { 00582 Char = MultiByteString[Count]; 00583 if ( Char < 0x20 ) 00584 { 00585 WideCharString[Count] = Char; 00586 } 00587 else 00588 { 00589 WideCharString[Count] = Char + 0xf000; 00590 } 00591 } 00592 if (MultiByteCount > WideCharMaxLen) 00593 { 00594 SetLastError(ERROR_INSUFFICIENT_BUFFER); 00595 return 0; 00596 } 00597 00598 return WideCharMaxLen; 00599 } 00600 00609 static INT 00610 WINAPI 00611 IntWideCharToMultiByteSYMBOL(DWORD Flags, 00612 LPCWSTR WideCharString, 00613 INT WideCharCount, 00614 LPSTR MultiByteString, 00615 INT MultiByteCount) 00616 { 00617 LONG Count; 00618 INT MaxLen; 00619 WCHAR Char; 00620 00621 if (Flags!=0) 00622 { 00623 SetLastError(ERROR_INVALID_PARAMETER); 00624 return 0; 00625 } 00626 00627 00628 if (MultiByteCount == 0) 00629 { 00630 return WideCharCount; 00631 } 00632 00633 MaxLen = MultiByteCount > WideCharCount ? WideCharCount : MultiByteCount; 00634 for (Count = 0; Count < MaxLen; Count++) 00635 { 00636 Char = WideCharString[Count]; 00637 if (Char < 0x20) 00638 { 00639 MultiByteString[Count] = Char; 00640 } 00641 else 00642 { 00643 if ((Char>=0xf020)&&(Char<0xf100)) 00644 { 00645 MultiByteString[Count] = Char - 0xf000; 00646 } 00647 else 00648 { 00649 SetLastError(ERROR_NO_UNICODE_TRANSLATION); 00650 return 0; 00651 } 00652 } 00653 } 00654 if (WideCharCount > MaxLen) 00655 { 00656 SetLastError(ERROR_INSUFFICIENT_BUFFER); 00657 return 0; 00658 } 00659 return MaxLen; 00660 } 00661 00670 static INT 00671 WINAPI 00672 IntWideCharToMultiByteUTF8(UINT CodePage, 00673 DWORD Flags, 00674 LPCWSTR WideCharString, 00675 INT WideCharCount, 00676 LPSTR MultiByteString, 00677 INT MultiByteCount, 00678 LPCSTR DefaultChar, 00679 LPBOOL UsedDefaultChar) 00680 { 00681 INT TempLength; 00682 WCHAR Char; 00683 00684 /* Does caller query for output buffer size? */ 00685 if (MultiByteCount == 0) 00686 { 00687 for (TempLength = 0; WideCharCount; 00688 WideCharCount--, WideCharString++) 00689 { 00690 TempLength++; 00691 if (*WideCharString >= 0x80) 00692 { 00693 TempLength++; 00694 if (*WideCharString >= 0x800) 00695 TempLength++; 00696 } 00697 } 00698 return TempLength; 00699 } 00700 00701 for (TempLength = MultiByteCount; WideCharCount; WideCharCount--, WideCharString++) 00702 { 00703 Char = *WideCharString; 00704 if (Char < 0x80) 00705 { 00706 if (!TempLength) 00707 { 00708 SetLastError(ERROR_INSUFFICIENT_BUFFER); 00709 break; 00710 } 00711 TempLength--; 00712 *MultiByteString++ = (CHAR)Char; 00713 continue; 00714 } 00715 00716 if (Char < 0x800) /* 0x80-0x7ff: 2 bytes */ 00717 { 00718 if (TempLength < 2) 00719 { 00720 SetLastError(ERROR_INSUFFICIENT_BUFFER); 00721 break; 00722 } 00723 MultiByteString[1] = 0x80 | (Char & 0x3f); Char >>= 6; 00724 MultiByteString[0] = 0xc0 | Char; 00725 MultiByteString += 2; 00726 TempLength -= 2; 00727 continue; 00728 } 00729 00730 /* 0x800-0xffff: 3 bytes */ 00731 if (TempLength < 3) 00732 { 00733 SetLastError(ERROR_INSUFFICIENT_BUFFER); 00734 break; 00735 } 00736 MultiByteString[2] = 0x80 | (Char & 0x3f); Char >>= 6; 00737 MultiByteString[1] = 0x80 | (Char & 0x3f); Char >>= 6; 00738 MultiByteString[0] = 0xe0 | Char; 00739 MultiByteString += 3; 00740 TempLength -= 3; 00741 } 00742 00743 return MultiByteCount - TempLength; 00744 } 00745 00753 static 00754 inline 00755 BOOL 00756 IntIsValidSBCSMapping(PCPTABLEINFO CodePageTable, DWORD Flags, WCHAR wch, UCHAR ch) 00757 { 00758 /* If the WC_NO_BEST_FIT_CHARS flag has been specified, the characters need to match exactly. */ 00759 if (Flags & WC_NO_BEST_FIT_CHARS) 00760 return (CodePageTable->MultiByteTable[ch] == wch); 00761 00762 /* By default, all characters except TransDefaultChar apply as a valid mapping 00763 for ch (so also "nearest" characters) */ 00764 if (ch != CodePageTable->TransDefaultChar) 00765 return TRUE; 00766 00767 /* The only possible left valid mapping is the default character itself */ 00768 return (wch == CodePageTable->TransUniDefaultChar); 00769 } 00770 00778 static inline BOOL 00779 IntIsValidDBCSMapping(PCPTABLEINFO CodePageTable, DWORD Flags, WCHAR wch, USHORT ch) 00780 { 00781 /* If ch is the default character, but the wch is not, it can't be a valid mapping */ 00782 if (ch == CodePageTable->TransDefaultChar && wch != CodePageTable->TransUniDefaultChar) 00783 return FALSE; 00784 00785 /* If the WC_NO_BEST_FIT_CHARS flag has been specified, the characters need to match exactly. */ 00786 if (Flags & WC_NO_BEST_FIT_CHARS) 00787 { 00788 if(ch & 0xff00) 00789 { 00790 USHORT uOffset = CodePageTable->DBCSOffsets[ch >> 8]; 00791 /* if (!uOffset) return (CodePageTable->MultiByteTable[ch] == wch); */ 00792 return (CodePageTable->DBCSOffsets[uOffset + (ch & 0xff)] == wch); 00793 } 00794 00795 return (CodePageTable->MultiByteTable[ch] == wch); 00796 } 00797 00798 /* If we're still here, we have a valid mapping */ 00799 return TRUE; 00800 } 00801 00810 static 00811 INT 00812 WINAPI 00813 IntWideCharToMultiByteCP(UINT CodePage, 00814 DWORD Flags, 00815 LPCWSTR WideCharString, 00816 INT WideCharCount, 00817 LPSTR MultiByteString, 00818 INT MultiByteCount, 00819 LPCSTR DefaultChar, 00820 LPBOOL UsedDefaultChar) 00821 { 00822 PCODEPAGE_ENTRY CodePageEntry; 00823 PCPTABLEINFO CodePageTable; 00824 INT TempLength; 00825 00826 /* Get code page table. */ 00827 CodePageEntry = IntGetCodePageEntry(CodePage); 00828 if (CodePageEntry == NULL) 00829 { 00830 SetLastError(ERROR_INVALID_PARAMETER); 00831 return 0; 00832 } 00833 CodePageTable = &CodePageEntry->CodePageTable; 00834 00835 00836 /* Different handling for DBCS code pages. */ 00837 if (CodePageTable->MaximumCharacterSize > 1) 00838 { 00839 /* If Flags, DefaultChar or UsedDefaultChar were given, we have to do some more work */ 00840 if(Flags || DefaultChar || UsedDefaultChar) 00841 { 00842 BOOL TempUsedDefaultChar; 00843 USHORT DefChar; 00844 00845 /* If UsedDefaultChar is not set, set it to a temporary value, so we don't have 00846 to check on every character */ 00847 if(!UsedDefaultChar) 00848 UsedDefaultChar = &TempUsedDefaultChar; 00849 00850 *UsedDefaultChar = FALSE; 00851 00852 /* Use the CodePage's TransDefaultChar if none was given. Don't modify the DefaultChar pointer here. */ 00853 if(DefaultChar) 00854 DefChar = DefaultChar[1] ? ((DefaultChar[0] << 8) | DefaultChar[1]) : DefaultChar[0]; 00855 else 00856 DefChar = CodePageTable->TransDefaultChar; 00857 00858 /* Does caller query for output buffer size? */ 00859 if(!MultiByteCount) 00860 { 00861 for(TempLength = 0; WideCharCount; WideCharCount--, WideCharString++, TempLength++) 00862 { 00863 USHORT uChar; 00864 00865 if ((Flags & WC_COMPOSITECHECK) && WideCharCount > 1) 00866 { 00867 /* FIXME: Handle WC_COMPOSITECHECK */ 00868 } 00869 00870 uChar = ((PUSHORT) CodePageTable->WideCharTable)[*WideCharString]; 00871 00872 /* Verify if the mapping is valid for handling DefaultChar and UsedDefaultChar */ 00873 if (!IntIsValidDBCSMapping(CodePageTable, Flags, *WideCharString, uChar)) 00874 { 00875 uChar = DefChar; 00876 *UsedDefaultChar = TRUE; 00877 } 00878 00879 /* Increment TempLength again if this is a double-byte character */ 00880 if (uChar & 0xff00) 00881 TempLength++; 00882 } 00883 00884 return TempLength; 00885 } 00886 00887 /* Convert the WideCharString to the MultiByteString and verify if the mapping is valid */ 00888 for(TempLength = MultiByteCount; 00889 WideCharCount && TempLength; 00890 TempLength--, WideCharString++, WideCharCount--) 00891 { 00892 USHORT uChar; 00893 00894 if ((Flags & WC_COMPOSITECHECK) && WideCharCount > 1) 00895 { 00896 /* FIXME: Handle WC_COMPOSITECHECK */ 00897 } 00898 00899 uChar = ((PUSHORT)CodePageTable->WideCharTable)[*WideCharString]; 00900 00901 /* Verify if the mapping is valid for handling DefaultChar and UsedDefaultChar */ 00902 if (!IntIsValidDBCSMapping(CodePageTable, Flags, *WideCharString, uChar)) 00903 { 00904 uChar = DefChar; 00905 *UsedDefaultChar = TRUE; 00906 } 00907 00908 /* Handle double-byte characters */ 00909 if (uChar & 0xff00) 00910 { 00911 /* Don't output a partial character */ 00912 if (TempLength == 1) 00913 break; 00914 00915 TempLength--; 00916 *MultiByteString++ = uChar >> 8; 00917 } 00918 00919 *MultiByteString++ = (char)uChar; 00920 } 00921 00922 /* WideCharCount should be 0 if all characters were converted */ 00923 if (WideCharCount) 00924 { 00925 SetLastError(ERROR_INSUFFICIENT_BUFFER); 00926 return 0; 00927 } 00928 00929 return MultiByteCount - TempLength; 00930 } 00931 00932 /* Does caller query for output buffer size? */ 00933 if (!MultiByteCount) 00934 { 00935 for (TempLength = 0; WideCharCount; WideCharCount--, WideCharString++, TempLength++) 00936 { 00937 /* Increment TempLength again if this is a double-byte character */ 00938 if (((PWCHAR)CodePageTable->WideCharTable)[*WideCharString] & 0xff00) 00939 TempLength++; 00940 } 00941 00942 return TempLength; 00943 } 00944 00945 /* Convert the WideCharString to the MultiByteString */ 00946 for (TempLength = MultiByteCount; 00947 WideCharCount && TempLength; 00948 TempLength--, WideCharString++, WideCharCount--) 00949 { 00950 USHORT uChar = ((PUSHORT) CodePageTable->WideCharTable)[*WideCharString]; 00951 00952 /* Is this a double-byte character? */ 00953 if (uChar & 0xff00) 00954 { 00955 /* Don't output a partial character */ 00956 if (TempLength == 1) 00957 break; 00958 00959 TempLength--; 00960 *MultiByteString++ = uChar >> 8; 00961 } 00962 00963 *MultiByteString++ = (char)uChar; 00964 } 00965 00966 /* WideCharCount should be 0 if all characters were converted */ 00967 if (WideCharCount) 00968 { 00969 SetLastError(ERROR_INSUFFICIENT_BUFFER); 00970 return 0; 00971 } 00972 00973 return MultiByteCount - TempLength; 00974 } 00975 else /* Not DBCS code page */ 00976 { 00977 INT nReturn; 00978 00979 /* If Flags, DefaultChar or UsedDefaultChar were given, we have to do some more work */ 00980 if (Flags || DefaultChar || UsedDefaultChar) 00981 { 00982 BOOL TempUsedDefaultChar; 00983 CHAR DefChar; 00984 00985 /* If UsedDefaultChar is not set, set it to a temporary value, so we don't have 00986 to check on every character */ 00987 if (!UsedDefaultChar) 00988 UsedDefaultChar = &TempUsedDefaultChar; 00989 00990 *UsedDefaultChar = FALSE; 00991 00992 /* Does caller query for output buffer size? */ 00993 if (!MultiByteCount) 00994 { 00995 /* Loop through the whole WideCharString and check if we can get a valid mapping for each character */ 00996 for (TempLength = 0; WideCharCount; TempLength++, WideCharString++, WideCharCount--) 00997 { 00998 if ((Flags & WC_COMPOSITECHECK) && WideCharCount > 1) 00999 { 01000 /* FIXME: Handle WC_COMPOSITECHECK */ 01001 } 01002 01003 if (!*UsedDefaultChar) 01004 *UsedDefaultChar = !IntIsValidSBCSMapping(CodePageTable, 01005 Flags, 01006 *WideCharString, 01007 ((PCHAR)CodePageTable->WideCharTable)[*WideCharString]); 01008 } 01009 01010 return TempLength; 01011 } 01012 01013 /* Use the CodePage's TransDefaultChar if none was given. Don't modify the DefaultChar pointer here. */ 01014 if (DefaultChar) 01015 DefChar = *DefaultChar; 01016 else 01017 DefChar = CodePageTable->TransDefaultChar; 01018 01019 /* Convert the WideCharString to the MultiByteString and verify if the mapping is valid */ 01020 for (TempLength = MultiByteCount; 01021 WideCharCount && TempLength; 01022 MultiByteString++, TempLength--, WideCharString++, WideCharCount--) 01023 { 01024 if ((Flags & WC_COMPOSITECHECK) && WideCharCount > 1) 01025 { 01026 /* FIXME: Handle WC_COMPOSITECHECK */ 01027 } 01028 01029 *MultiByteString = ((PCHAR)CodePageTable->WideCharTable)[*WideCharString]; 01030 01031 if (!IntIsValidSBCSMapping(CodePageTable, Flags, *WideCharString, *MultiByteString)) 01032 { 01033 *MultiByteString = DefChar; 01034 *UsedDefaultChar = TRUE; 01035 } 01036 } 01037 01038 /* WideCharCount should be 0 if all characters were converted */ 01039 if (WideCharCount) 01040 { 01041 SetLastError(ERROR_INSUFFICIENT_BUFFER); 01042 return 0; 01043 } 01044 01045 return MultiByteCount - TempLength; 01046 } 01047 01048 /* Does caller query for output buffer size? */ 01049 if (!MultiByteCount) 01050 return WideCharCount; 01051 01052 /* Is the buffer large enough? */ 01053 if (MultiByteCount < WideCharCount) 01054 { 01055 /* Convert the string up to MultiByteCount and return 0 */ 01056 WideCharCount = MultiByteCount; 01057 SetLastError(ERROR_INSUFFICIENT_BUFFER); 01058 nReturn = 0; 01059 } 01060 else 01061 { 01062 /* Otherwise WideCharCount will be the number of converted characters */ 01063 nReturn = WideCharCount; 01064 } 01065 01066 /* Convert the WideCharString to the MultiByteString */ 01067 for (TempLength = WideCharCount; --TempLength >= 0; WideCharString++, MultiByteString++) 01068 { 01069 *MultiByteString = ((PCHAR)CodePageTable->WideCharTable)[*WideCharString]; 01070 } 01071 01072 return nReturn; 01073 } 01074 } 01075 01083 static BOOL 01084 WINAPI 01085 IntIsLeadByte(PCPTABLEINFO TableInfo, BYTE Byte) 01086 { 01087 UINT i; 01088 01089 if (TableInfo->MaximumCharacterSize == 2) 01090 { 01091 for (i = 0; i < MAXIMUM_LEADBYTES && TableInfo->LeadByte[i]; i += 2) 01092 { 01093 if (Byte >= TableInfo->LeadByte[i] && Byte <= TableInfo->LeadByte[i+1]) 01094 return TRUE; 01095 } 01096 } 01097 01098 return FALSE; 01099 } 01100 01101 /* PUBLIC FUNCTIONS ***********************************************************/ 01102 01130 BOOL 01131 WINAPI 01132 GetNlsSectionName(UINT CodePage, 01133 UINT Base, 01134 ULONG Unknown, 01135 LPSTR BaseName, 01136 LPSTR Result, 01137 ULONG ResultSize) 01138 { 01139 CHAR Integer[11]; 01140 01141 if (!NT_SUCCESS(RtlIntegerToChar(CodePage, Base, sizeof(Integer), Integer))) 01142 return FALSE; 01143 01144 /* 01145 * If the name including the terminating NULL character doesn't 01146 * fit in the output buffer then fail. 01147 */ 01148 if (strlen(Integer) + strlen(BaseName) >= ResultSize) 01149 return FALSE; 01150 01151 lstrcpyA(Result, BaseName); 01152 lstrcatA(Result, Integer); 01153 01154 return TRUE; 01155 } 01156 01175 BOOL 01176 WINAPI 01177 GetCPFileNameFromRegistry(UINT CodePage, LPWSTR FileName, ULONG FileNameSize) 01178 { 01179 WCHAR ValueNameBuffer[11]; 01180 UNICODE_STRING KeyName, ValueName; 01181 OBJECT_ATTRIBUTES ObjectAttributes; 01182 NTSTATUS Status; 01183 HANDLE KeyHandle; 01184 PKEY_VALUE_PARTIAL_INFORMATION Kvpi; 01185 DWORD KvpiSize; 01186 BOOL bRetValue; 01187 01188 bRetValue = FALSE; 01189 01190 /* Convert the codepage number to string. */ 01191 ValueName.Buffer = ValueNameBuffer; 01192 ValueName.MaximumLength = sizeof(ValueNameBuffer); 01193 01194 if (!NT_SUCCESS(RtlIntegerToUnicodeString(CodePage, 10, &ValueName))) 01195 return bRetValue; 01196 01197 /* Open the registry key containing file name mappings. */ 01198 RtlInitUnicodeString(&KeyName, L"\\Registry\\Machine\\System\\" 01199 L"CurrentControlSet\\Control\\Nls\\CodePage"); 01200 InitializeObjectAttributes(&ObjectAttributes, &KeyName, OBJ_CASE_INSENSITIVE, 01201 NULL, NULL); 01202 Status = NtOpenKey(&KeyHandle, KEY_READ, &ObjectAttributes); 01203 if (!NT_SUCCESS(Status)) 01204 { 01205 return bRetValue; 01206 } 01207 01208 /* Allocate buffer that will be used to query the value data. */ 01209 KvpiSize = sizeof(KEY_VALUE_PARTIAL_INFORMATION) + (MAX_PATH * sizeof(WCHAR)); 01210 Kvpi = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, KvpiSize); 01211 if (Kvpi == NULL) 01212 { 01213 NtClose(KeyHandle); 01214 return bRetValue; 01215 } 01216 01217 /* Query the file name for our code page. */ 01218 Status = NtQueryValueKey(KeyHandle, &ValueName, KeyValuePartialInformation, 01219 Kvpi, KvpiSize, &KvpiSize); 01220 01221 NtClose(KeyHandle); 01222 01223 /* Check if we succeded and the value is non-empty string. */ 01224 if (NT_SUCCESS(Status) && Kvpi->Type == REG_SZ && 01225 Kvpi->DataLength > sizeof(WCHAR)) 01226 { 01227 bRetValue = TRUE; 01228 if (FileName != NULL) 01229 { 01230 lstrcpynW(FileName, (WCHAR*)Kvpi->Data, 01231 min(Kvpi->DataLength / sizeof(WCHAR), FileNameSize)); 01232 } 01233 } 01234 01235 /* free temporary buffer */ 01236 HeapFree(GetProcessHeap(),0,Kvpi); 01237 return bRetValue; 01238 } 01239 01251 BOOL 01252 WINAPI 01253 IsValidCodePage(UINT CodePage) 01254 { 01255 if (CodePage == 0) return FALSE; 01256 if (CodePage == CP_UTF8 || CodePage == CP_UTF7) 01257 return TRUE; 01258 if (IntGetLoadedCodePageEntry(CodePage)) 01259 return TRUE; 01260 return GetCPFileNameFromRegistry(CodePage, NULL, 0); 01261 } 01262 01263 static const signed char 01264 base64inv[] = 01265 { 01266 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 01267 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 01268 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 62, -1, -1, -1, 63, 01269 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, -1, -1, -1, -1, -1, -1, 01270 -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 01271 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, -1, -1, -1, -1, -1, 01272 -1, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 01273 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, -1, -1, -1, -1, -1 01274 }; 01275 01276 static VOID Utf7Base64Decode(BYTE *pbDest, LPCSTR pszSrc, INT cchSrc) 01277 { 01278 INT i, j, n; 01279 BYTE b; 01280 01281 for(i = 0; i < cchSrc / 4 * 4; i += 4) 01282 { 01283 for(j = n = 0; j < 4; ) 01284 { 01285 b = (BYTE) base64inv[(BYTE) *pszSrc++]; 01286 n |= (((INT) b) << ((3 - j) * 6)); 01287 j++; 01288 } 01289 for(j = 0; j < 3; j++) 01290 *pbDest++ = (BYTE) ((n >> (8 * (2 - j))) & 0xFF); 01291 } 01292 for(j = n = 0; j < cchSrc % 4; ) 01293 { 01294 b = (BYTE) base64inv[(BYTE) *pszSrc++]; 01295 n |= (((INT) b) << ((3 - j) * 6)); 01296 j++; 01297 } 01298 for(j = 0; j < ((cchSrc % 4) * 6 / 8); j++) 01299 *pbDest++ = (BYTE) ((n >> (8 * (2 - j))) & 0xFF); 01300 } 01301 01302 static VOID myswab(LPVOID pv, INT cw) 01303 { 01304 LPBYTE pb = (LPBYTE) pv; 01305 BYTE b; 01306 while(cw > 0) 01307 { 01308 b = *pb; 01309 *pb = pb[1]; 01310 pb[1] = b; 01311 pb += 2; 01312 cw--; 01313 } 01314 } 01315 01316 static INT Utf7ToWideCharSize(LPCSTR pszUtf7, INT cchUtf7) 01317 { 01318 INT n, c, cch; 01319 CHAR ch; 01320 LPCSTR pch; 01321 01322 c = 0; 01323 while(cchUtf7 > 0) 01324 { 01325 ch = *pszUtf7++; 01326 if (ch == '+') 01327 { 01328 ch = *pszUtf7; 01329 if (ch == '-') 01330 { 01331 c++; 01332 pszUtf7++; 01333 cchUtf7 -= 2; 01334 continue; 01335 } 01336 cchUtf7--; 01337 pch = pszUtf7; 01338 while(cchUtf7 > 0 && (BYTE) *pszUtf7 < 0x80 && 01339 base64inv[*pszUtf7] >= 0) 01340 { 01341 cchUtf7--; 01342 pszUtf7++; 01343 } 01344 cch = pszUtf7 - pch; 01345 n = (cch * 3) / 8; 01346 c += n; 01347 if (cchUtf7 > 0 && *pszUtf7 == '-') 01348 { 01349 pszUtf7++; 01350 cchUtf7--; 01351 } 01352 } 01353 else 01354 { 01355 c++; 01356 cchUtf7--; 01357 } 01358 } 01359 01360 return c; 01361 } 01362 01363 static INT Utf7ToWideChar(LPCSTR pszUtf7, INT cchUtf7, LPWSTR pszWide, INT cchWide) 01364 { 01365 INT n, c, cch; 01366 CHAR ch; 01367 LPCSTR pch; 01368 WORD *pwsz; 01369 01370 c = Utf7ToWideCharSize(pszUtf7, cchUtf7); 01371 if (cchWide == 0) 01372 return c; 01373 01374 if (cchWide < c) 01375 { 01376 SetLastError(ERROR_INSUFFICIENT_BUFFER); 01377 return 0; 01378 } 01379 01380 while(cchUtf7 > 0) 01381 { 01382 ch = *pszUtf7++; 01383 if (ch == '+') 01384 { 01385 if (*pszUtf7 == '-') 01386 { 01387 *pszWide++ = L'+'; 01388 pszUtf7++; 01389 cchUtf7 -= 2; 01390 continue; 01391 } 01392 cchUtf7--; 01393 pch = pszUtf7; 01394 while(cchUtf7 > 0 && (BYTE) *pszUtf7 < 0x80 && 01395 base64inv[*pszUtf7] >= 0) 01396 { 01397 cchUtf7--; 01398 pszUtf7++; 01399 } 01400 cch = pszUtf7 - pch; 01401 n = (cch * 3) / 8; 01402 pwsz = (WORD *) HeapAlloc(GetProcessHeap(), 0, (n + 1) * sizeof(WORD)); 01403 if (pwsz == NULL) 01404 return 0; 01405 ZeroMemory(pwsz, n * sizeof(WORD)); 01406 Utf7Base64Decode((BYTE *) pwsz, pch, cch); 01407 myswab(pwsz, n); 01408 CopyMemory(pszWide, pwsz, n * sizeof(WORD)); 01409 HeapFree(GetProcessHeap(), 0, pwsz); 01410 pszWide += n; 01411 if (cchUtf7 > 0 && *pszUtf7 == '-') 01412 { 01413 pszUtf7++; 01414 cchUtf7--; 01415 } 01416 } 01417 else 01418 { 01419 *pszWide++ = (WCHAR) ch; 01420 cchUtf7--; 01421 } 01422 } 01423 01424 return c; 01425 } 01426 01458 INT 01459 WINAPI 01460 MultiByteToWideChar(UINT CodePage, 01461 DWORD Flags, 01462 LPCSTR MultiByteString, 01463 INT MultiByteCount, 01464 LPWSTR WideCharString, 01465 INT WideCharCount) 01466 { 01467 /* Check the parameters. */ 01468 if (MultiByteString == NULL || 01469 (WideCharString == NULL && WideCharCount > 0) || 01470 (PVOID)MultiByteString == (PVOID)WideCharString) 01471 { 01472 SetLastError(ERROR_INVALID_PARAMETER); 01473 return 0; 01474 } 01475 01476 /* Determine the input string length. */ 01477 if (MultiByteCount < 0) 01478 { 01479 MultiByteCount = lstrlenA(MultiByteString) + 1; 01480 } 01481 01482 switch (CodePage) 01483 { 01484 case CP_UTF8: 01485 return IntMultiByteToWideCharUTF8(Flags, 01486 MultiByteString, 01487 MultiByteCount, 01488 WideCharString, 01489 WideCharCount); 01490 01491 case CP_UTF7: 01492 if (Flags) 01493 { 01494 SetLastError(ERROR_INVALID_FLAGS); 01495 return 0; 01496 } 01497 return Utf7ToWideChar(MultiByteString, MultiByteCount, 01498 WideCharString, WideCharCount); 01499 01500 case CP_SYMBOL: 01501 return IntMultiByteToWideCharSYMBOL(Flags, 01502 MultiByteString, 01503 MultiByteCount, 01504 WideCharString, 01505 WideCharCount); 01506 default: 01507 return IntMultiByteToWideCharCP(CodePage, 01508 Flags, 01509 MultiByteString, 01510 MultiByteCount, 01511 WideCharString, 01512 WideCharCount); 01513 } 01514 } 01515 01516 static const char mustshift[] = 01517 { 01518 0, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 1, 1, 0, 1, 1, 01519 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 01520 0, 1, 1, 1, 1, 1, 1, 0, 0, 0, 1, 1, 0, 0, 0, 0, 01521 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 01522 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 01523 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 01524 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 01525 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1 01526 }; 01527 01528 static const char base64[] = 01529 "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; 01530 01531 static INT WideCharToUtf7Size(LPCWSTR pszWide, INT cchWide) 01532 { 01533 WCHAR wch; 01534 INT c = 0; 01535 BOOL fShift = FALSE; 01536 01537 while(cchWide > 0) 01538 { 01539 wch = *pszWide; 01540 if (wch < 0x80 && !mustshift[wch]) 01541 { 01542 c++; 01543 cchWide--; 01544 pszWide++; 01545 } 01546 else 01547 { 01548 if (wch == L'+') 01549 { 01550 c++; 01551 c++; 01552 cchWide--; 01553 pszWide++; 01554 continue; 01555 } 01556 if (!fShift) 01557 { 01558 c++; 01559 fShift = TRUE; 01560 } 01561 pszWide++; 01562 cchWide--; 01563 c += 3; 01564 if (cchWide > 0 && (*pszWide >= 0x80 || mustshift[*pszWide])) 01565 { 01566 pszWide++; 01567 cchWide--; 01568 c += 3; 01569 if (cchWide > 0 && (*pszWide >= 0x80 || mustshift[*pszWide])) 01570 { 01571 pszWide++; 01572 cchWide--; 01573 c += 2; 01574 } 01575 } 01576 if (cchWide > 0 && *pszWide < 0x80 && !mustshift[*pszWide]) 01577 { 01578 c++; 01579 fShift = FALSE; 01580 } 01581 } 01582 } 01583 if (fShift) 01584 c++; 01585 01586 return c; 01587 } 01588 01589 static INT WideCharToUtf7(LPCWSTR pszWide, INT cchWide, LPSTR pszUtf7, INT cchUtf7) 01590 { 01591 WCHAR wch; 01592 INT c, n; 01593 WCHAR wsz[3]; 01594 BOOL fShift = FALSE; 01595 01596 c = WideCharToUtf7Size(pszWide, cchWide); 01597 if (cchUtf7 == 0) 01598 return c; 01599 01600 if (cchUtf7 < c) 01601 { 01602 SetLastError(ERROR_INSUFFICIENT_BUFFER); 01603 return 0; 01604 } 01605 01606 while(cchWide > 0) 01607 { 01608 wch = *pszWide; 01609 if (wch < 0x80 && !mustshift[wch]) 01610 { 01611 *pszUtf7++ = (CHAR) wch; 01612 cchWide--; 01613 pszWide++; 01614 } 01615 else 01616 { 01617 if (wch == L'+') 01618 { 01619 *pszUtf7++ = '+'; 01620 *pszUtf7++ = '-'; 01621 cchWide--; 01622 pszWide++; 01623 continue; 01624 } 01625 if (!fShift) 01626 { 01627 *pszUtf7++ = '+'; 01628 fShift = TRUE; 01629 } 01630 wsz[0] = *pszWide++; 01631 cchWide--; 01632 n = 1; 01633 if (cchWide > 0 && (*pszWide >= 0x80 || mustshift[*pszWide])) 01634 { 01635 wsz[1] = *pszWide++; 01636 cchWide--; 01637 n++; 01638 if (cchWide > 0 && (*pszWide >= 0x80 || mustshift[*pszWide])) 01639 { 01640 wsz[2] = *pszWide++; 01641 cchWide--; 01642 n++; 01643 } 01644 } 01645 *pszUtf7++ = base64[wsz[0] >> 10]; 01646 *pszUtf7++ = base64[(wsz[0] >> 4) & 0x3F]; 01647 *pszUtf7++ = base64[(wsz[0] << 2 | wsz[1] >> 14) & 0x3F]; 01648 if (n >= 2) 01649 { 01650 *pszUtf7++ = base64[(wsz[1] >> 8) & 0x3F]; 01651 *pszUtf7++ = base64[(wsz[1] >> 2) & 0x3F]; 01652 *pszUtf7++ = base64[(wsz[1] << 4 | wsz[2] >> 12) & 0x3F]; 01653 if (n >= 3) 01654 { 01655 *pszUtf7++ = base64[(wsz[2] >> 6) & 0x3F]; 01656 *pszUtf7++ = base64[wsz[2] & 0x3F]; 01657 } 01658 } 01659 if (cchWide > 0 && *pszWide < 0x80 && !mustshift[*pszWide]) 01660 { 01661 *pszUtf7++ = '-'; 01662 fShift = FALSE; 01663 } 01664 } 01665 } 01666 if (fShift) 01667 *pszUtf7 = '-'; 01668 01669 return c; 01670 } 01671 01672 static BOOL 01673 GetLocalisedText(DWORD dwResId, WCHAR *lpszDest) 01674 { 01675 HRSRC hrsrc; 01676 LCID lcid; 01677 LANGID langId; 01678 DWORD dwId; 01679 01680 if (dwResId == 37) 01681 dwId = dwResId * 100; 01682 else 01683 dwId = dwResId; 01684 01685 lcid = GetUserDefaultLCID(); 01686 lcid = ConvertDefaultLocale(lcid); 01687 01688 langId = LANGIDFROMLCID(lcid); 01689 01690 if (PRIMARYLANGID(langId) == LANG_NEUTRAL) 01691 langId = MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US); 01692 01693 hrsrc = FindResourceExW(hCurrentModule, 01694 (LPWSTR)RT_STRING, 01695 MAKEINTRESOURCEW((dwId >> 4) + 1), 01696 langId); 01697 if (hrsrc) 01698 { 01699 HGLOBAL hmem = LoadResource(hCurrentModule, hrsrc); 01700 01701 if (hmem) 01702 { 01703 const WCHAR *p; 01704 unsigned int i; 01705 01706 p = LockResource(hmem); 01707 for (i = 0; i < (dwId & 0x0f); i++) p += *p + 1; 01708 01709 memcpy(lpszDest, p + 1, *p * sizeof(WCHAR)); 01710 lpszDest[*p] = '\0'; 01711 01712 return TRUE; 01713 } 01714 } 01715 01716 DPRINT1("Could not get codepage name. dwResId = %ld\n", dwResId); 01717 return FALSE; 01718 } 01719 01720 /* 01721 * @implemented 01722 */ 01723 BOOL 01724 WINAPI 01725 GetCPInfo(UINT CodePage, 01726 LPCPINFO CodePageInfo) 01727 { 01728 PCODEPAGE_ENTRY CodePageEntry; 01729 01730 if (!CodePageInfo) 01731 { 01732 SetLastError(ERROR_INVALID_PARAMETER); 01733 return FALSE; 01734 } 01735 01736 CodePageEntry = IntGetCodePageEntry(CodePage); 01737 if (CodePageEntry == NULL) 01738 { 01739 switch(CodePage) 01740 { 01741 case CP_UTF7: 01742 case CP_UTF8: 01743 CodePageInfo->DefaultChar[0] = 0x3f; 01744 CodePageInfo->DefaultChar[1] = 0; 01745 CodePageInfo->LeadByte[0] = CodePageInfo->LeadByte[1] = 0; 01746 CodePageInfo->MaxCharSize = (CodePage == CP_UTF7) ? 5 : 4; 01747 return TRUE; 01748 } 01749 01750 SetLastError( ERROR_INVALID_PARAMETER ); 01751 return FALSE; 01752 } 01753 01754 if (CodePageEntry->CodePageTable.DefaultChar & 0xff00) 01755 { 01756 CodePageInfo->DefaultChar[0] = (CodePageEntry->CodePageTable.DefaultChar & 0xff00) >> 8; 01757 CodePageInfo->DefaultChar[1] = CodePageEntry->CodePageTable.DefaultChar & 0x00ff; 01758 } 01759 else 01760 { 01761 CodePageInfo->DefaultChar[0] = CodePageEntry->CodePageTable.DefaultChar & 0xff; 01762 CodePageInfo->DefaultChar[1] = 0; 01763 } 01764 01765 if ((CodePageInfo->MaxCharSize = CodePageEntry->CodePageTable.MaximumCharacterSize) == 2) 01766 memcpy(CodePageInfo->LeadByte, CodePageEntry->CodePageTable.LeadByte, sizeof(CodePageInfo->LeadByte)); 01767 else 01768 CodePageInfo->LeadByte[0] = CodePageInfo->LeadByte[1] = 0; 01769 01770 return TRUE; 01771 } 01772 01773 /* 01774 * @implemented 01775 */ 01776 BOOL 01777 WINAPI 01778 GetCPInfoExW(UINT CodePage, 01779 DWORD dwFlags, 01780 LPCPINFOEXW lpCPInfoEx) 01781 { 01782 if (!GetCPInfo(CodePage, (LPCPINFO) lpCPInfoEx)) 01783 return FALSE; 01784 01785 switch(CodePage) 01786 { 01787 case CP_UTF7: 01788 { 01789 lpCPInfoEx->CodePage = CP_UTF7; 01790 lpCPInfoEx->UnicodeDefaultChar = 0x3f; 01791 return GetLocalisedText((DWORD)CodePage, lpCPInfoEx->CodePageName); 01792 } 01793 break; 01794 01795 case CP_UTF8: 01796 { 01797 lpCPInfoEx->CodePage = CP_UTF8; 01798 lpCPInfoEx->UnicodeDefaultChar = 0x3f; 01799 return GetLocalisedText((DWORD)CodePage, lpCPInfoEx->CodePageName); 01800 } 01801 01802 default: 01803 { 01804 PCODEPAGE_ENTRY CodePageEntry; 01805 01806 CodePageEntry = IntGetCodePageEntry(CodePage); 01807 if (CodePageEntry == NULL) 01808 { 01809 DPRINT1("Could not get CodePage Entry! CodePageEntry = 0\n"); 01810 SetLastError(ERROR_INVALID_PARAMETER); 01811 return FALSE; 01812 } 01813 01814 lpCPInfoEx->CodePage = CodePageEntry->CodePageTable.CodePage; 01815 lpCPInfoEx->UnicodeDefaultChar = CodePageEntry->CodePageTable.UniDefaultChar; 01816 return GetLocalisedText((DWORD)CodePage, lpCPInfoEx->CodePageName); 01817 } 01818 break; 01819 } 01820 } 01821 01822 01823 /* 01824 * @implemented 01825 */ 01826 BOOL 01827 WINAPI 01828 GetCPInfoExA(UINT CodePage, 01829 DWORD dwFlags, 01830 LPCPINFOEXA lpCPInfoEx) 01831 { 01832 CPINFOEXW CPInfo; 01833 01834 if (!GetCPInfoExW(CodePage, dwFlags, &CPInfo)) 01835 return FALSE; 01836 01837 /* the layout is the same except for CodePageName */ 01838 memcpy(lpCPInfoEx, &CPInfo, sizeof(CPINFOEXA)); 01839 01840 WideCharToMultiByte(CP_ACP, 01841 0, 01842 CPInfo.CodePageName, 01843 -1, 01844 lpCPInfoEx->CodePageName, 01845 sizeof(lpCPInfoEx->CodePageName), 01846 NULL, 01847 NULL); 01848 return TRUE; 01849 } 01850 01890 INT 01891 WINAPI 01892 WideCharToMultiByte(UINT CodePage, 01893 DWORD Flags, 01894 LPCWSTR WideCharString, 01895 INT WideCharCount, 01896 LPSTR MultiByteString, 01897 INT MultiByteCount, 01898 LPCSTR DefaultChar, 01899 LPBOOL UsedDefaultChar) 01900 { 01901 /* Check the parameters. */ 01902 if (WideCharString == NULL || 01903 (MultiByteString == NULL && MultiByteCount > 0) || 01904 (PVOID)WideCharString == (PVOID)MultiByteString || 01905 MultiByteCount < 0) 01906 { 01907 SetLastError(ERROR_INVALID_PARAMETER); 01908 return 0; 01909 } 01910 01911 /* Determine the input string length. */ 01912 if (WideCharCount < 0) 01913 { 01914 WideCharCount = lstrlenW(WideCharString) + 1; 01915 } 01916 01917 switch (CodePage) 01918 { 01919 case CP_UTF8: 01920 return IntWideCharToMultiByteUTF8(CodePage, 01921 Flags, 01922 WideCharString, 01923 WideCharCount, 01924 MultiByteString, 01925 MultiByteCount, 01926 DefaultChar, 01927 UsedDefaultChar); 01928 01929 case CP_UTF7: 01930 if (DefaultChar != NULL || UsedDefaultChar != NULL) 01931 { 01932 SetLastError(ERROR_INVALID_PARAMETER); 01933 return 0; 01934 } 01935 if (Flags) 01936 { 01937 SetLastError(ERROR_INVALID_FLAGS); 01938 return 0; 01939 } 01940 return WideCharToUtf7(WideCharString, WideCharCount, 01941 MultiByteString, MultiByteCount); 01942 01943 case CP_SYMBOL: 01944 if ((DefaultChar!=NULL) || (UsedDefaultChar!=NULL)) 01945 { 01946 SetLastError(ERROR_INVALID_PARAMETER); 01947 return 0; 01948 } 01949 return IntWideCharToMultiByteSYMBOL(Flags, 01950 WideCharString, 01951 WideCharCount, 01952 MultiByteString, 01953 MultiByteCount); 01954 01955 default: 01956 return IntWideCharToMultiByteCP(CodePage, 01957 Flags, 01958 WideCharString, 01959 WideCharCount, 01960 MultiByteString, 01961 MultiByteCount, 01962 DefaultChar, 01963 UsedDefaultChar); 01964 } 01965 } 01966 01975 UINT 01976 WINAPI 01977 GetACP(VOID) 01978 { 01979 return AnsiCodePage.CodePageTable.CodePage; 01980 } 01981 01990 UINT 01991 WINAPI 01992 GetOEMCP(VOID) 01993 { 01994 return OemCodePage.CodePageTable.CodePage; 01995 } 01996 02005 BOOL 02006 WINAPI 02007 IsDBCSLeadByteEx(UINT CodePage, BYTE TestByte) 02008 { 02009 PCODEPAGE_ENTRY CodePageEntry; 02010 02011 CodePageEntry = IntGetCodePageEntry(CodePage); 02012 if (CodePageEntry != NULL) 02013 return IntIsLeadByte(&CodePageEntry->CodePageTable, TestByte); 02014 02015 SetLastError(ERROR_INVALID_PARAMETER); 02016 return FALSE; 02017 } 02018 02027 BOOL 02028 WINAPI 02029 IsDBCSLeadByte(BYTE TestByte) 02030 { 02031 return IntIsLeadByte(&AnsiCodePage.CodePageTable, TestByte); 02032 } 02033 02034 /* 02035 * @unimplemented 02036 */ 02037 NTSTATUS WINAPI CreateNlsSecurityDescriptor(PSECURITY_DESCRIPTOR SecurityDescriptor,ULONG Size,ULONG AccessMask) 02038 { 02039 STUB; 02040 return 0; 02041 } 02042 02043 /* 02044 * @unimplemented 02045 */ 02046 BOOL WINAPI IsValidUILanguage(LANGID langid) 02047 { 02048 STUB; 02049 return 0; 02050 } 02051 02052 /* 02053 * @unimplemented 02054 */ 02055 VOID WINAPI NlsConvertIntegerToString(ULONG Value,ULONG Base,ULONG strsize, LPWSTR str, ULONG strsize2) 02056 { 02057 STUB; 02058 } 02059 02060 /* 02061 * @unimplemented 02062 */ 02063 UINT WINAPI SetCPGlobal(UINT CodePage) 02064 { 02065 STUB; 02066 return 0; 02067 } 02068 02069 /* 02070 * @unimplemented 02071 */ 02072 BOOL 02073 WINAPI 02074 ValidateLCType(int a1, unsigned int a2, int a3, int a4) 02075 { 02076 STUB; 02077 return FALSE; 02078 } 02079 02080 /* 02081 * @unimplemented 02082 */ 02083 BOOL 02084 WINAPI 02085 NlsResetProcessLocale(VOID) 02086 { 02087 STUB; 02088 return TRUE; 02089 } 02090 02091 /* 02092 * @unimplemented 02093 */ 02094 VOID 02095 WINAPI 02096 GetDefaultSortkeySize(LPVOID lpUnknown) 02097 { 02098 STUB; 02099 lpUnknown = NULL; 02100 } 02101 02102 /* 02103 * @unimplemented 02104 */ 02105 VOID 02106 WINAPI 02107 GetLinguistLangSize(LPVOID lpUnknown) 02108 { 02109 STUB; 02110 lpUnknown = NULL; 02111 } 02112 02113 /* 02114 * @unimplemented 02115 */ 02116 BOOL 02117 WINAPI 02118 ValidateLocale(IN ULONG LocaleId) 02119 { 02120 STUB; 02121 return TRUE; 02122 } 02123 02124 /* 02125 * @unimplemented 02126 */ 02127 ULONG 02128 WINAPI 02129 NlsGetCacheUpdateCount(VOID) 02130 { 02131 STUB; 02132 return 0; 02133 } 02134 02135 /* 02136 * @unimplemented 02137 */ 02138 BOOL 02139 WINAPI 02140 IsNLSDefinedString(IN NLS_FUNCTION Function, 02141 IN DWORD dwFlags, 02142 IN LPNLSVERSIONINFO lpVersionInformation, 02143 IN LPCWSTR lpString, 02144 IN INT cchStr) 02145 { 02146 STUB; 02147 return TRUE; 02148 } 02149 02150 /* 02151 * @unimplemented 02152 */ 02153 BOOL 02154 WINAPI 02155 GetNLSVersion(IN NLS_FUNCTION Function, 02156 IN LCID Locale, 02157 IN OUT LPNLSVERSIONINFO lpVersionInformation) 02158 { 02159 STUB; 02160 return TRUE; 02161 } 02162 02163 /* EOF */ Generated on Fri May 25 2012 04:22:35 for ReactOS by
1.7.6.1
|