ReactOS Fundraising Campaign 2012
 
€ 4,410 / € 30,000

Information | Donate

Home | Info | Community | Development | myReactOS | Contact Us

  1. Home
  2. Community
  3. Development
  4. myReactOS
  5. Fundraiser 2012

  1. Main Page
  2. Alphabetical List
  3. Data Structures
  4. Directories
  5. File List
  6. Data Fields
  7. Globals
  8. Related Pages

ReactOS Development > Doxygen

nls.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 doxygen 1.7.6.1

ReactOS is a registered trademark or a trademark of ReactOS Foundation in the United States and other countries.