⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 nls.c

📁 winNT技术操作系统,国外开放的原代码和LIUX一样
💻 C
📖 第 1 页 / 共 2 页
字号:
/* $Id: nls.c 24244 2006-09-24 07:30:43Z greatlrd $
 *
 * COPYRIGHT:       See COPYING in the top level directory
 * PROJECT:         ReactOS system libraries
 * FILE:            dll/win32/kernel32/misc/nls.c
 * PURPOSE:         National Language Support
 * PROGRAMMER:      Filip Navara
 *                  Hartmut Birr
 *                  Gunnar Andre Dalsnes
 *                  Thomas Weidenmueller
 * UPDATE HISTORY:
 *                  Created 24/08/2004
 */

/* INCLUDES *******************************************************************/

#include <k32.h>
#define NDEBUG
#include "../include/debug.h"

/* GLOBAL VARIABLES ***********************************************************/

typedef struct _CODEPAGE_ENTRY
{
   LIST_ENTRY Entry;
   UINT CodePage;
   HANDLE SectionHandle;
   PBYTE SectionMapping;
   CPTABLEINFO CodePageTable;
} CODEPAGE_ENTRY, *PCODEPAGE_ENTRY;

/* Sequence length based on the first character. */
static const char UTF8Length[128] =
{
   0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x80 - 0x8F */
   0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x90 - 0x9F */
   0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0xA0 - 0xAF */
   0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0xB0 - 0xBF */
   1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 0xC0 - 0xCF */
   1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 0xD0 - 0xDF */
   2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, /* 0xE0 - 0xEF */
   3, 3, 3, 3, 3, 3, 3, 3, 4, 4, 4, 4, 5, 5, 0, 0  /* 0xF0 - 0xFF */
};

/* First byte mask depending on UTF-8 sequence length. */
static const unsigned char UTF8Mask[6] = {0x7f, 0x1f, 0x0f, 0x07, 0x03, 0x01};

/* FIXME: Change to HASH table or linear array. */
static LIST_ENTRY CodePageListHead;
static CODEPAGE_ENTRY AnsiCodePage;
static CODEPAGE_ENTRY OemCodePage;
static RTL_CRITICAL_SECTION CodePageListLock;

/* FORWARD DECLARATIONS *******************************************************/

BOOL STDCALL
GetNlsSectionName(UINT CodePage, UINT Base, ULONG Unknown,
                  LPSTR BaseName, LPSTR Result, ULONG ResultSize);

BOOL STDCALL
GetCPFileNameFromRegistry(UINT CodePage, LPWSTR FileName, ULONG FileNameSize);

/* PRIVATE FUNCTIONS **********************************************************/

/**
 * @name NlsInit
 *
 * Internal NLS related stuff initialization.
 */

BOOL FASTCALL
NlsInit()
{
   UNICODE_STRING DirName;
   OBJECT_ATTRIBUTES ObjectAttributes;
   HANDLE Handle;

   InitializeListHead(&CodePageListHead);
   RtlInitializeCriticalSection(&CodePageListLock);

   /*
    * FIXME: Eventually this should be done only for the NLS Server
    * process, but since we don't have anything like that (yet?) we
    * always try to create the "\Nls" directory here.
    */
   RtlInitUnicodeString(&DirName, L"\\Nls");
   InitializeObjectAttributes(&ObjectAttributes, &DirName,
                              OBJ_CASE_INSENSITIVE | OBJ_PERMANENT,
                              NULL, NULL);
   if (NT_SUCCESS(NtCreateDirectoryObject(&Handle, DIRECTORY_ALL_ACCESS, &ObjectAttributes)))
   {
      NtClose(Handle);
   }

   /* Setup ANSI code page. */
   AnsiCodePage.CodePage = CP_ACP;
   AnsiCodePage.SectionHandle = NULL;
   AnsiCodePage.SectionMapping = NtCurrentTeb()->ProcessEnvironmentBlock->AnsiCodePageData;
   RtlInitCodePageTable((PUSHORT)AnsiCodePage.SectionMapping,
                        &AnsiCodePage.CodePageTable);
   InsertTailList(&CodePageListHead, &AnsiCodePage.Entry);

   /* Setup OEM code page. */
   OemCodePage.CodePage = CP_OEMCP;
   OemCodePage.SectionHandle = NULL;
   OemCodePage.SectionMapping = NtCurrentTeb()->ProcessEnvironmentBlock->OemCodePageData;
   RtlInitCodePageTable((PUSHORT)OemCodePage.SectionMapping,
                        &OemCodePage.CodePageTable);
   InsertTailList(&CodePageListHead, &OemCodePage.Entry);

   return TRUE;
}

/**
 * @name NlsUninit
 *
 * Internal NLS related stuff uninitialization.
 */

VOID FASTCALL
NlsUninit()
{
   PCODEPAGE_ENTRY Current;

   /* Delete the code page list. */
   while (!IsListEmpty(&CodePageListHead))
   {
      Current = CONTAINING_RECORD(CodePageListHead.Flink, CODEPAGE_ENTRY, Entry);
      if (Current->SectionHandle != NULL)
      {
         UnmapViewOfFile(Current->SectionMapping);
         NtClose(Current->SectionHandle);
      }
      RemoveHeadList(&CodePageListHead);
   }
   RtlDeleteCriticalSection(&CodePageListLock);
}

/**
 * @name IntGetLoadedCodePageEntry
 *
 * Internal function to get structure containing a code page information
 * of code page that is already loaded.
 *
 * @param CodePage
 *        Number of the code page. Special values like CP_OEMCP, CP_ACP
 *        or CP_UTF8 aren't allowed.
 *
 * @return Code page entry or NULL if the specified code page hasn't
 *         been loaded yet.
 */

PCODEPAGE_ENTRY FASTCALL
IntGetLoadedCodePageEntry(UINT CodePage)
{
   LIST_ENTRY *CurrentEntry;
   PCODEPAGE_ENTRY Current;

   RtlEnterCriticalSection(&CodePageListLock);
   for (CurrentEntry = CodePageListHead.Flink;
        CurrentEntry != &CodePageListHead;
        CurrentEntry = CurrentEntry->Flink)
   {
      Current = CONTAINING_RECORD(CurrentEntry, CODEPAGE_ENTRY, Entry);
      if (Current->CodePage == CodePage)
      {
         RtlLeaveCriticalSection(&CodePageListLock);
         return Current;
      }
   }
   RtlLeaveCriticalSection(&CodePageListLock);

   return NULL;
}

/**
 * @name IntGetCodePageEntry
 *
 * Internal function to get structure containing a code page information.
 *
 * @param CodePage
 *        Number of the code page. Special values like CP_OEMCP, CP_ACP
 *        or CP_THREAD_ACP are allowed, but CP_UTF[7/8] isn't.
 *
 * @return Code page entry.
 */

static PCODEPAGE_ENTRY FASTCALL
IntGetCodePageEntry(UINT CodePage)
{
   CHAR SectionName[40];
   NTSTATUS Status;
   HANDLE SectionHandle = INVALID_HANDLE_VALUE, FileHandle;
   PBYTE SectionMapping;
   OBJECT_ATTRIBUTES ObjectAttributes;
   ANSI_STRING AnsiName;
   UNICODE_STRING UnicodeName;
   WCHAR FileName[MAX_PATH + 1];
   UINT FileNamePos;
   PCODEPAGE_ENTRY CodePageEntry;

   if (CodePage == CP_THREAD_ACP)
   {
      if (!GetLocaleInfoW(GetThreadLocale(), LOCALE_IDEFAULTANSICODEPAGE |
                          LOCALE_RETURN_NUMBER, (WCHAR *)&CodePage,
                          sizeof(CodePage) / sizeof(WCHAR)))
      {
         /* Last error is set by GetLocaleInfoW. */
         return 0;
      }
   }
   else if (CodePage == CP_MACCP)
   {
      if (!GetLocaleInfoW(LOCALE_SYSTEM_DEFAULT, LOCALE_IDEFAULTMACCODEPAGE |
                          LOCALE_RETURN_NUMBER, (WCHAR *)&CodePage,
                          sizeof(CodePage) / sizeof(WCHAR)))
      {
         /* Last error is set by GetLocaleInfoW. */
         return 0;
      }
   }

   /* Try searching for loaded page first. */
   CodePageEntry = IntGetLoadedCodePageEntry(CodePage);
   if (CodePageEntry != NULL)
   {
      return CodePageEntry;
   }

   /*
    * Yes, we really want to lock here. Otherwise it can happen that
    * two parallel requests will try to get the entry for the same
    * code page and we would load it twice.
    */
   RtlEnterCriticalSection(&CodePageListLock);

   /* Generate the section name. */
   if (!GetNlsSectionName(CodePage, 10, 0, "\\Nls\\NlsSectionCP",
                          SectionName, sizeof(SectionName)))
   {
      RtlLeaveCriticalSection(&CodePageListLock);
      return NULL;
   }
   RtlInitAnsiString(&AnsiName, SectionName);
   RtlAnsiStringToUnicodeString(&UnicodeName, &AnsiName, TRUE);
   InitializeObjectAttributes(&ObjectAttributes, &UnicodeName, 0,
                              NULL, NULL);

   /* Try to open the section first */
   Status = NtOpenSection(&SectionHandle, SECTION_MAP_READ, &ObjectAttributes);

   /* If the section doesn't exist, try to create it. */
   if (Status == STATUS_UNSUCCESSFUL ||
       Status == STATUS_OBJECT_NAME_NOT_FOUND ||
       Status == STATUS_OBJECT_PATH_NOT_FOUND)
   {
      FileNamePos = GetSystemDirectoryW(FileName, MAX_PATH);
      if (GetCPFileNameFromRegistry(CodePage, FileName + FileNamePos + 1,
                                    MAX_PATH - FileNamePos - 1))
      {
         FileName[FileNamePos] = L'\\';
         FileName[MAX_PATH] = 0;
         FileHandle = CreateFileW(FileName, FILE_GENERIC_READ, FILE_SHARE_READ,
                                  NULL, OPEN_EXISTING, 0, NULL);
         Status = NtCreateSection(&SectionHandle, SECTION_MAP_READ,
                                  &ObjectAttributes, NULL, PAGE_READONLY,
                                  SEC_FILE, FileHandle);
      }
   }
   RtlFreeUnicodeString(&UnicodeName);

   if (!NT_SUCCESS(Status))
   {
      RtlLeaveCriticalSection(&CodePageListLock);
      return NULL;
   }

   SectionMapping = MapViewOfFile(SectionHandle, FILE_MAP_READ, 0, 0, 0);
   if (SectionMapping == NULL)
   {
      NtClose(SectionHandle);
      RtlLeaveCriticalSection(&CodePageListLock);
      return NULL;
   }

   CodePageEntry = HeapAlloc(GetProcessHeap(), 0, sizeof(CODEPAGE_ENTRY));
   if (CodePageEntry == NULL)
   {
      NtClose(SectionHandle);
      RtlLeaveCriticalSection(&CodePageListLock);
      return NULL;
   }

   CodePageEntry->CodePage = CodePage;
   CodePageEntry->SectionHandle = SectionHandle;
   CodePageEntry->SectionMapping = SectionMapping;
   RtlInitCodePageTable((PUSHORT)SectionMapping, &CodePageEntry->CodePageTable);

   /* Insert the new entry to list and unlock. Uff. */
   InsertTailList(&CodePageListHead, &CodePageEntry->Entry);
   RtlLeaveCriticalSection(&CodePageListLock);

   return CodePageEntry;
}

/**
 * @name IntMultiByteToWideCharUTF8
 *
 * Internal version of MultiByteToWideChar for UTF8.
 *
 * @see MultiByteToWideChar
 * @todo Add UTF8 validity checks.
 */

static INT STDCALL
IntMultiByteToWideCharUTF8(DWORD Flags,
                           LPCSTR MultiByteString, INT MultiByteCount,
                           LPWSTR WideCharString, INT WideCharCount)
{
   LPCSTR MbsEnd;
   UCHAR Char, Length;
   WCHAR WideChar;
   LONG Count;

   if (Flags != 0)
   {
      SetLastError(ERROR_INVALID_FLAGS);
      return 0;
   }

   /* Does caller query for output buffer size? */
   if (WideCharCount == 0)
   {
      MbsEnd = MultiByteString + MultiByteCount;
      for (; MultiByteString < MbsEnd; WideCharCount++)
      {
         Char = *MultiByteString++;
         if (Char < 0xC0)
            continue;
         MultiByteString += UTF8Length[Char - 0x80];
      }
      return WideCharCount;
   }

   MbsEnd = MultiByteString + MultiByteCount;
   for (Count = 0; Count < WideCharCount && MultiByteString < MbsEnd; Count++)
   {
      Char = *MultiByteString++;
      if (Char < 0x80)
      {
         *WideCharString++ = Char;
         continue;
      }
      Length = UTF8Length[Char - 0x80];
      WideChar = Char & UTF8Mask[Length];
      while (Length && MultiByteString < MbsEnd)
      {
         WideChar = (WideChar << 6) | *MultiByteString++;
         Length--;
      }
      *WideCharString++ = WideChar;
   }

   if (MultiByteString < MbsEnd)
      SetLastError(ERROR_INSUFFICIENT_BUFFER);

   return Count;
}

/**
 * @name IntMultiByteToWideCharCP
 *
 * Internal version of MultiByteToWideChar for code page tables.
 *
 * @see MultiByteToWideChar
 * @todo Handle MB_PRECOMPOSED, MB_COMPOSITE, MB_USEGLYPHCHARS and
 *       DBCS codepages.
 */

static INT STDCALL
IntMultiByteToWideCharCP(UINT CodePage, DWORD Flags,
                         LPCSTR MultiByteString, INT MultiByteCount,
                         LPWSTR WideCharString, INT WideCharCount)
{
   PCODEPAGE_ENTRY CodePageEntry;
   PCPTABLEINFO CodePageTable;
   LPCSTR TempString;
   INT TempLength;

   /* Get code page table. */
   CodePageEntry = IntGetCodePageEntry(CodePage);
   if (CodePageEntry == NULL)
   {
      SetLastError(ERROR_INVALID_PARAMETER);
      return 0;
   }
   CodePageTable = &CodePageEntry->CodePageTable;

   /* Different handling for DBCS code pages. */
   if (CodePageTable->MaximumCharacterSize > 1)
   {
      /* UNIMPLEMENTED */
      return 0;
   }
   else
   {
      /* Check for invalid characters. */
      if (Flags & MB_ERR_INVALID_CHARS)
      {
         for (TempString = MultiByteString, TempLength = MultiByteCount;
              TempLength > 0;
              TempString++, TempLength--)
         {
            if (CodePageTable->MultiByteTable[(UCHAR)*TempString] ==
                CodePageTable->UniDefaultChar &&
                *TempString != CodePageEntry->CodePageTable.DefaultChar)
            {
               SetLastError(ERROR_NO_UNICODE_TRANSLATION);
               return 0;
            }
         }
      }

      /* Does caller query for output buffer size? */
      if (WideCharCount == 0)
         return MultiByteCount;

      /* Adjust buffer size. Wine trick ;-) */
      if (WideCharCount < MultiByteCount)
      {
         MultiByteCount = WideCharCount;
         SetLastError(ERROR_INSUFFICIENT_BUFFER);
      }

      for (TempLength = MultiByteCount;
           TempLength > 0;
           MultiByteString++, TempLength--)
      {
         *WideCharString++ = CodePageTable->MultiByteTable[(UCHAR)*MultiByteString];
      }

      return MultiByteCount;
   }
}

/**
 * @name IntWideCharToMultiByteUTF8
 *
 * Internal version of WideCharToMultiByte for UTF8.
 *
 * @see WideCharToMultiByte
 */

static INT STDCALL
IntWideCharToMultiByteUTF8(UINT CodePage, DWORD Flags,
                           LPCWSTR WideCharString, INT WideCharCount,
                           LPSTR MultiByteString, INT MultiByteCount,
                           LPCSTR DefaultChar, LPBOOL UsedDefaultChar)
{
   INT TempLength;
   WCHAR Char;

   /* Does caller query for output buffer size? */
   if (MultiByteCount == 0)
   {
      for (TempLength = 0; WideCharCount;
           WideCharCount--, WideCharString++)
      {
         TempLength++;
         if (*WideCharString >= 0x80)
         {
            TempLength++;
            if (*WideCharString >= 0x800)
               TempLength++;
         }
      }
      return TempLength;
   }

   for (TempLength = MultiByteCount; WideCharCount;
        WideCharCount--, WideCharString++)
   {
      Char = *WideCharString;
      if (Char < 0x80)
      {
         if (!TempLength)
         {
            SetLastError(ERROR_INSUFFICIENT_BUFFER);
            break;
         }
         TempLength--;

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -