update for HEAD-2003091401
[reactos.git] / ntoskrnl / rtl / nls.c
index 5a3460b..6d010bc 100644 (file)
  *                  20/08/99 Created by Emanuele Aliberti
  *                  10/11/99 Added translation functions.
  *
- * NOTE:
- *   Multi-byte code pages are not supported yet. Even single-byte code
- *   pages are not supported properly. Only stupid CHAR->WCHAR and
- *   WCHAR->CHAR (Attention: data loss!!!) translation is done.
- *
  * TODO:
- *   1) Implement code to initialize the translation tables.
- *   2) Use fixed translation table for translation.
- *   3) Add loading of translation tables (NLS files).
- *   4) Add multi-byte translation code.
+ *   1) Add multi-byte translation code.
  */
 
-#ifdef WIN32_REGDBG
-#include "cm_win32.h"
-#else
-
 #include <ddk/ntddk.h>
-//#include <internal/nls.h>
+#include <internal/mm.h>
+#include <internal/nls.h>
 
 #define NDEBUG
 #include <internal/debug.h>
 
-#endif
 
 /* GLOBALS *******************************************************************/
 
-BOOLEAN NlsMbCodePageTag = FALSE;
-BOOLEAN NlsMbOemCodePageTag = FALSE;
+USHORT NlsAnsiCodePage = 0; /* exported */
+BOOLEAN NlsMbCodePageTag = FALSE; /* exported */
+PWCHAR NlsAnsiToUnicodeTable = NULL;
+PCHAR NlsUnicodeToAnsiTable = NULL;
+PWCHAR NlsDbcsUnicodeToAnsiTable = NULL;
+PUSHORT NlsLeadByteInfo = NULL; /* exported */
 
-BYTE NlsLeadByteInfo = 0; /* ? */
 
-USHORT NlsOemLeadByteInfo = 0;
+USHORT NlsOemCodePage = 0;
+BOOLEAN NlsMbOemCodePageTag = FALSE; /* exported */
+PWCHAR NlsOemToUnicodeTable = NULL;
+PCHAR NlsUnicodeToOemTable =NULL;
+PWCHAR NlsDbcsUnicodeToOemTable = NULL;
+PUSHORT NlsOemLeadByteInfo = NULL; /* exported */
 
-USHORT NlsAnsiCodePage = 0;
-USHORT NlsOemCodePage = 0; /* not exported */
 
-PWCHAR AnsiToUnicodeTable = NULL; /* size: 256*sizeof(WCHAR) */
-PWCHAR OemToUnicodeTable = NULL; /* size: 256*sizeof(WCHAR) */
+PUSHORT NlsUnicodeUpcaseTable = NULL;
+PUSHORT NlsUnicodeLowercaseTable = NULL;
 
-PCHAR UnicodeToAnsiTable = NULL; /* size: 65536*sizeof(CHAR) */
-PCHAR UnicodeToOemTable =NULL; /* size: 65536*sizeof(CHAR) */
 
-PWCHAR UnicodeUpcaseTable = NULL; /* size: 65536*sizeof(WCHAR) */
-PWCHAR UnicodeLowercaseTable = NULL; /* size: 65536*sizeof(WCHAR) */
+static PUSHORT NlsAnsiCodePageTable = NULL;
+static ULONG NlsAnsiCodePageTableSize = 0;
 
+static PUSHORT NlsOemCodePageTable = NULL;
+static ULONG NlsOemCodePageTableSize = 0;
 
-/* FUNCTIONS *****************************************************************/
-
-VOID
-RtlpInitNlsTables(VOID)
-{
-  INT i;
-  PCHAR pc;
-  PWCHAR pwc;
+static PUSHORT NlsUnicodeCasemapTable = NULL;
+static ULONG NlsUnicodeCasemapTableSize = 0;
 
-  /* allocate and initialize ansi->unicode table */
-  AnsiToUnicodeTable = ExAllocatePool(NonPagedPool, 256 * sizeof(WCHAR));
-  if (AnsiToUnicodeTable == NULL)
-    {
-      DbgPrint("Allocation of 'AnsiToUnicodeTable' failed\n");
-      KeBugCheck(0);
-    }
+PVOID NlsSectionObject = NULL;
+static PVOID NlsSectionBase = NULL;
+static ULONG NlsSectionViewSize = 0;
 
-  pwc = AnsiToUnicodeTable;
-  for (i = 0; i < 256; i++, pwc++)
-    *pwc = (WCHAR)i;
+ULONG NlsAnsiTableOffset = 0;
+ULONG NlsOemTableOffset = 0;
+ULONG NlsUnicodeTableOffset = 0;
 
-  /* allocate and initialize oem->unicode table */
-  OemToUnicodeTable = ExAllocatePool(NonPagedPool, 256 * sizeof(WCHAR));
-  if (OemToUnicodeTable == NULL)
-    {
-      DbgPrint("Allocation of 'OemToUnicodeTable' failed\n");
-      KeBugCheck(0);
-    }
 
-  pwc = OemToUnicodeTable;
-  for (i = 0; i < 256; i++, pwc++)
-    *pwc = (WCHAR)i;
+/* FUNCTIONS *****************************************************************/
 
-  /* allocate and initialize unicode->ansi table */
-  UnicodeToAnsiTable = ExAllocatePool(NonPagedPool, 65536 * sizeof(CHAR));
-  if (UnicodeToAnsiTable == NULL)
-    {
-      DbgPrint("Allocation of 'UnicodeToAnsiTable' failed\n");
-      KeBugCheck(0);
-    }
+VOID
+RtlpImportAnsiCodePage(PUSHORT TableBase,
+                      ULONG Size)
+{
+  NlsAnsiCodePageTable = TableBase;
+  NlsAnsiCodePageTableSize = Size;
+}
 
-  pc = UnicodeToAnsiTable;
-  for (i = 0; i < 256; i++, pc++)
-    *pc = (CHAR)i;
-  for (; i < 65536; i++, pc++)
-    *pc = 0;
 
-  /* allocate and initialize unicode->oem table */
-  UnicodeToOemTable = ExAllocatePool(NonPagedPool, 65536 * sizeof(CHAR));
-  if (UnicodeToOemTable == NULL)
-    {
-      DbgPrint("Allocation of 'UnicodeToOemTable' failed\n");
-      KeBugCheck(0);
-    }
+VOID
+RtlpImportOemCodePage(PUSHORT TableBase,
+                     ULONG Size)
+{
+  NlsOemCodePageTable = TableBase;
+  NlsOemCodePageTableSize = Size;
+}
 
-  pc = UnicodeToOemTable;
-  for (i = 0; i < 256; i++, pc++)
-    *pc = (CHAR)i;
-  for (; i < 65536; i++, pc++)
-    *pc = 0;
 
-  /* allocate and initialize unicode upcase table */
-  UnicodeUpcaseTable = ExAllocatePool(NonPagedPool, 65536 * sizeof(WCHAR));
-  if (UnicodeUpcaseTable == NULL)
-    {
-      DbgPrint("Allocation of 'UnicodeUpcaseTable' failed\n");
-      KeBugCheck(0);
-    }
+VOID
+RtlpImportUnicodeCasemap(PUSHORT TableBase,
+                        ULONG Size)
+{
+  NlsUnicodeCasemapTable = TableBase;
+  NlsUnicodeCasemapTableSize = Size;
+}
 
-  pwc = UnicodeUpcaseTable;
-  for (i = 0; i < 65536; i++, pwc++)
-    *pwc = (WCHAR)i;
-  for (i = 'a'; i < ('z'+ 1); i++)
-    UnicodeUpcaseTable[i] = (WCHAR)i + (L'A' - L'a');
 
+VOID
+RtlpCreateInitialNlsTables(VOID)
+{
+  NLSTABLEINFO NlsTable;
 
-  /* allocate and initialize unicode lowercase table */
-  UnicodeLowercaseTable = ExAllocatePool(NonPagedPool, 65536 * sizeof(WCHAR));
-  if (UnicodeLowercaseTable == NULL)
+  if (NlsAnsiCodePageTable == NULL || NlsAnsiCodePageTableSize == 0 ||
+      NlsOemCodePageTable == NULL || NlsOemCodePageTableSize == 0 ||
+      NlsUnicodeCasemapTable == NULL || NlsUnicodeCasemapTableSize == 0)
     {
-      DbgPrint("Allocation of 'UnicodeLowercaseTable' failed\n");
-      KeBugCheck(0);
+      KEBUGCHECKEX (0x32, STATUS_UNSUCCESSFUL, 1, 0, 0);
     }
 
-  pwc = UnicodeLowercaseTable;
-  for (i = 0; i < 65536; i++, pwc++)
-    *pwc = (WCHAR)i;
-  for (i = 'A'; i < ('Z'+ 1); i++)
-    UnicodeLowercaseTable[i] = (WCHAR)i - (L'A' - L'a');
-
-  /* FIXME: initialize codepage info */
+  RtlInitNlsTables (NlsAnsiCodePageTable,
+                   NlsOemCodePageTable,
+                   NlsUnicodeCasemapTable,
+                   &NlsTable);
 
+  RtlResetRtlTranslations (&NlsTable);
 }
 
 
-NTSTATUS
-RtlpInitNlsSections(ULONG Mod1Start,
-                   ULONG Mod1End,
-                   ULONG Mod2Start,
-                   ULONG Mod2End,
-                   ULONG Mod3Start,
-                   ULONG Mod3End)
+VOID
+RtlpCreateNlsSection(VOID)
 {
-  UNICODE_STRING UnicodeString;
-  OBJECT_ATTRIBUTES ObjectAttributes;
-  HANDLE DirectoryHandle;
+  NLSTABLEINFO NlsTable;
+  LARGE_INTEGER SectionSize;
   HANDLE SectionHandle;
   NTSTATUS Status;
-  LARGE_INTEGER SectionSize;
 
-  DPRINT("Ansi section start: 0x%08lX\n", Mod1Start);
-  DPRINT("Ansi section end: 0x%08lX\n", Mod1End);
-  DPRINT("Oem section start: 0x%08lX\n", Mod2Start);
-  DPRINT("Oem section end: 0x%08lX\n", Mod2End);
-  DPRINT("Upcase section start: 0x%08lX\n", Mod3Start);
-  DPRINT("Upcase section end: 0x%08lX\n", Mod3End);
-
-  /* Create the '\NLS' directory */
-  RtlInitUnicodeStringFromLiteral(&UnicodeString,
-                      L"\\NLS");
-  InitializeObjectAttributes(&ObjectAttributes,
-                            &UnicodeString,
-                            OBJ_PERMANENT,
-                            NULL,
-                            NULL);
-  Status = NtCreateDirectoryObject(&DirectoryHandle,
-                                  0,
-                                  &ObjectAttributes);
-  if (!NT_SUCCESS(Status))
-    return(Status);
-
-  /* Create the 'NlsSectionUnicode' section */
-  RtlInitUnicodeStringFromLiteral(&UnicodeString,
-                      L"NlsSectionUnicode");
-  InitializeObjectAttributes(&ObjectAttributes,
-                            &UnicodeString,
-                            OBJ_PERMANENT,
-                            DirectoryHandle,
-                            NULL);
-  SectionSize.QuadPart = (Mod1End - Mod1Start) +
-    (Mod2End - Mod2Start) + (Mod3End - Mod3Start);
-  DPRINT("NlsSectionUnicode size: 0x%I64X\n", SectionSize.QuadPart);
+  DPRINT("RtlpCreateNlsSection() called\n");
+
+  NlsSectionViewSize = ROUND_UP(NlsAnsiCodePageTableSize, PAGE_SIZE) +
+                      ROUND_UP(NlsOemCodePageTableSize, PAGE_SIZE) +
+                      ROUND_UP(NlsUnicodeCasemapTableSize, PAGE_SIZE);
 
+  DPRINT("NlsSectionViewSize %lx\n", NlsSectionViewSize);
+
+  SectionSize.QuadPart = (LONGLONG)NlsSectionViewSize;
   Status = NtCreateSection(&SectionHandle,
                           SECTION_ALL_ACCESS,
-                          &ObjectAttributes,
+                          NULL,
                           &SectionSize,
                           PAGE_READWRITE,
-                          0,
+                          SEC_COMMIT,
                           NULL);
   if (!NT_SUCCESS(Status))
-    return(Status);
+    {
+      DPRINT1("NtCreateSection() failed\n");
+      KEBUGCHECKEX(0x32, Status, 1, 1, 0);
+    }
 
+  Status = ObReferenceObjectByHandle(SectionHandle,
+                                    SECTION_ALL_ACCESS,
+                                    MmSectionObjectType,
+                                    KernelMode,
+                                    &NlsSectionObject,
+                                    NULL);
+  NtClose(SectionHandle);
+  if (!NT_SUCCESS(Status))
+    {
+      DPRINT1("ObReferenceObjectByHandle() failed\n");
+      KEBUGCHECKEX(0x32, Status, 1, 2, 0);
+    }
+
+  Status = MmMapViewInSystemSpace(NlsSectionObject,
+                                 &NlsSectionBase,
+                                 &NlsSectionViewSize);
+  if (!NT_SUCCESS(Status))
+    {
+      DPRINT1("MmMapViewInSystemSpace() failed\n");
+      KEBUGCHECKEX(0x32, Status, 1, 3, 0);
+    }
 
-  /* create and initialize code page table */
+  DPRINT("NlsSection: Base %p  Size %lx\n", 
+        NlsSectionBase,
+        NlsSectionViewSize);
 
-  /* map the nls table into the 'NlsSectionUnicode' section */
+  NlsAnsiTableOffset = 0;
+  RtlCopyMemory((PVOID)((ULONG)NlsSectionBase + NlsAnsiTableOffset),
+               NlsAnsiCodePageTable,
+               NlsAnsiCodePageTableSize);
 
+  NlsOemTableOffset = NlsAnsiTableOffset + ROUND_UP(NlsAnsiCodePageTableSize, PAGE_SIZE);
+  RtlCopyMemory((PVOID)((ULONG)NlsSectionBase + NlsOemTableOffset),
+               NlsOemCodePageTable,
+               NlsOemCodePageTableSize);
 
-  NtClose(SectionHandle);
-  NtClose(DirectoryHandle);
+  NlsUnicodeTableOffset = NlsOemTableOffset + ROUND_UP(NlsOemCodePageTableSize, PAGE_SIZE);
+  RtlCopyMemory((PVOID)((ULONG)NlsSectionBase + NlsUnicodeTableOffset),
+               NlsUnicodeCasemapTable,
+               NlsUnicodeCasemapTableSize);
 
-  return(STATUS_SUCCESS);
+  RtlInitNlsTables ((PVOID)((ULONG)NlsSectionBase + NlsAnsiTableOffset),
+                   (PVOID)((ULONG)NlsSectionBase + NlsOemTableOffset),
+                   (PVOID)((ULONG)NlsSectionBase + NlsUnicodeTableOffset),
+                   &NlsTable);
+
+  RtlResetRtlTranslations (&NlsTable);
 }
 
 
+/*
+ * @unimplemented
+ */
 NTSTATUS STDCALL
-RtlCustomCPToUnicodeN(PRTL_NLS_DATA NlsData,
+RtlCustomCPToUnicodeN(IN PCPTABLEINFO CustomCP,
                      PWCHAR UnicodeString,
                      ULONG UnicodeSize,
                      PULONG ResultSize,
@@ -231,7 +204,7 @@ RtlCustomCPToUnicodeN(PRTL_NLS_DATA NlsData,
   ULONG Size = 0;
   ULONG i;
 
-  if (NlsData->DbcsFlag == FALSE)
+  if (CustomCP->DBCSCodePage == 0)
     {
       /* single-byte code page */
       if (CustomSize > (UnicodeSize / sizeof(WCHAR)))
@@ -244,7 +217,7 @@ RtlCustomCPToUnicodeN(PRTL_NLS_DATA NlsData,
 
       for (i = 0; i < Size; i++)
        {
-         *UnicodeString = NlsData->MultiByteToUnicode[(unsigned int)*CustomString];
+         *UnicodeString = CustomCP->MultiByteTable[(unsigned int)*CustomString];
          UnicodeString++;
          CustomString++;
        }
@@ -259,6 +232,36 @@ RtlCustomCPToUnicodeN(PRTL_NLS_DATA NlsData,
 }
 
 
+WCHAR
+RtlDowncaseUnicodeChar (IN WCHAR Source)
+{
+  USHORT Offset;
+
+  if (Source < L'A')
+    return Source;
+
+  if (Source <= L'Z')
+    return Source + (L'a' - L'A');
+
+  if (Source < 0x80)
+    return Source;
+
+  Offset = ((USHORT)Source >> 8);
+  Offset = NlsUnicodeLowercaseTable[Offset];
+
+  Offset += (((USHORT)Source & 0x00F0) >> 4);
+  Offset = NlsUnicodeLowercaseTable[Offset];
+
+  Offset += ((USHORT)Source & 0x000F);
+  Offset = NlsUnicodeLowercaseTable[Offset];
+
+  return Source + (SHORT)Offset;
+}
+
+
+/*
+ * @implemented
+ */
 VOID STDCALL
 RtlGetDefaultCodePage(PUSHORT AnsiCodePage,
                      PUSHORT OemCodePage)
@@ -268,11 +271,91 @@ RtlGetDefaultCodePage(PUSHORT AnsiCodePage,
 }
 
 
+/*
+ * @implemented
+ */
+VOID STDCALL
+RtlInitCodePageTable(IN PUSHORT TableBase,
+                    OUT PCPTABLEINFO CodePageTable)
+{
+  PNLS_FILE_HEADER NlsFileHeader;
+  PUSHORT Ptr;
+  USHORT Offset;
+
+  DPRINT("RtlInitCodePageTable() called\n");
+
+  NlsFileHeader = (PNLS_FILE_HEADER)TableBase;
+
+  CodePageTable->CodePage = NlsFileHeader->CodePage;
+  CodePageTable->MaximumCharacterSize = NlsFileHeader->MaximumCharacterSize;
+  CodePageTable->DefaultChar = NlsFileHeader->DefaultChar;
+  CodePageTable->UniDefaultChar = NlsFileHeader->UniDefaultChar;
+  CodePageTable->TransDefaultChar = NlsFileHeader->TransDefaultChar;
+  CodePageTable->TransUniDefaultChar = NlsFileHeader->TransUniDefaultChar;
+
+  RtlCopyMemory(&CodePageTable->LeadByte,
+               &NlsFileHeader->LeadByte,
+               MAXIMUM_LEADBYTES);
+
+  /* Set Pointer to start of multi byte table */
+  Ptr = (PUSHORT)((ULONG_PTR)TableBase + 2 * NlsFileHeader->HeaderSize);
+
+  /* Get offset to the wide char table */
+  Offset = (USHORT)(*Ptr++) + NlsFileHeader->HeaderSize + 1;
+
+  /* Set pointer to the multi byte table */
+  CodePageTable->MultiByteTable = Ptr;
+
+  /* Skip ANSI and OEM table */
+  Ptr += 256;
+  if (*Ptr++)
+    Ptr += 256;
+
+  /* Set pointer to DBCS ranges */
+  CodePageTable->DBCSRanges = (PUSHORT)Ptr;
+
+  if (*Ptr > 0)
+    {
+      CodePageTable->DBCSCodePage = 1;
+      CodePageTable->DBCSOffsets = (PUSHORT)++Ptr;
+    }
+  else
+    {
+      CodePageTable->DBCSCodePage = 0;
+      CodePageTable->DBCSOffsets = 0;
+    }
+
+  CodePageTable->WideCharTable = (PVOID)((ULONG_PTR)TableBase + 2 * Offset);
+}
+
+
+VOID STDCALL
+RtlInitNlsTables(IN PUSHORT AnsiTableBase,
+                IN PUSHORT OemTableBase,
+                IN PUSHORT CaseTableBase,
+                OUT PNLSTABLEINFO NlsTable)
+{
+  DPRINT("RtlInitNlsTables()called\n");
+
+  RtlInitCodePageTable (AnsiTableBase,
+                       &NlsTable->AnsiTableInfo);
+
+  RtlInitCodePageTable (OemTableBase,
+                       &NlsTable->OemTableInfo);
+
+  NlsTable->UpperCaseTable = (PUSHORT)CaseTableBase + 2;
+  NlsTable->LowerCaseTable = (PUSHORT)CaseTableBase + *((PUSHORT)CaseTableBase + 1) + 2;
+}
+
+
+/*
+ * @unimplemented
+ */
 NTSTATUS STDCALL
 RtlMultiByteToUnicodeN(PWCHAR UnicodeString,
                       ULONG UnicodeSize,
                       PULONG ResultSize,
-                      PCHAR MbString,
+                      const PCHAR MbString,
                       ULONG MbSize)
 {
   ULONG Size = 0;
@@ -290,11 +373,7 @@ RtlMultiByteToUnicodeN(PWCHAR UnicodeString,
        *ResultSize = Size * sizeof(WCHAR);
 
       for (i = 0; i < Size; i++)
-       {
-         *UnicodeString = AnsiToUnicodeTable[(unsigned int)*MbString];
-         UnicodeString++;
-         MbString++;
-       }
+       UnicodeString[i] = NlsAnsiToUnicodeTable[(unsigned int)MbString[i]];
     }
   else
     {
@@ -306,11 +385,16 @@ RtlMultiByteToUnicodeN(PWCHAR UnicodeString,
 }
 
 
+/*
+ * @implemented
+ */
 NTSTATUS STDCALL
 RtlMultiByteToUnicodeSize(PULONG UnicodeSize,
                          PCHAR MbString,
                          ULONG MbSize)
 {
+  ULONG Length;
+
   if (NlsMbCodePageTag == FALSE)
     {
       /* single-byte code page */
@@ -319,13 +403,26 @@ RtlMultiByteToUnicodeSize(PULONG UnicodeSize,
   else
     {
       /* multi-byte code page */
-      /* FIXME */
+      for (Length = 0; MbSize; MbSize--, MbString++, Length++)
+       {
+         if (NlsLeadByteInfo[(UCHAR)*MbString] != 0)
+           {
+             if (!--MbSize)
+               break;  /* partial char, ignore it */
+             MbString++;
+           }
+       }
+
+      *UnicodeSize = Length * sizeof(WCHAR);
     }
 
-  return(STATUS_SUCCESS);
+  return STATUS_SUCCESS;
 }
 
 
+/*
+ * @unimplemented
+ */
 NTSTATUS STDCALL
 RtlOemToUnicodeN(PWCHAR UnicodeString,
                 ULONG UnicodeSize,
@@ -349,7 +446,7 @@ RtlOemToUnicodeN(PWCHAR UnicodeString,
 
       for (i = 0; i < Size; i++)
        {
-         *UnicodeString = OemToUnicodeTable[(unsigned int)*OemString];
+         *UnicodeString = NlsOemToUnicodeTable[(unsigned int)*OemString];
          UnicodeString++;
          OemString++;
        }
@@ -364,8 +461,40 @@ RtlOemToUnicodeN(PWCHAR UnicodeString,
 }
 
 
+VOID STDCALL
+RtlResetRtlTranslations(IN PNLSTABLEINFO NlsTable)
+{
+  DPRINT("RtlResetRtlTranslations() called\n");
+
+  /* Set ANSI data */
+  NlsAnsiToUnicodeTable = NlsTable->AnsiTableInfo.MultiByteTable;
+  NlsUnicodeToAnsiTable = NlsTable->AnsiTableInfo.WideCharTable;
+  NlsDbcsUnicodeToAnsiTable = (PWCHAR)NlsTable->AnsiTableInfo.WideCharTable;
+  NlsMbCodePageTag = (NlsTable->AnsiTableInfo.DBCSCodePage != 0);
+  NlsLeadByteInfo = NlsTable->AnsiTableInfo.DBCSOffsets;
+  NlsAnsiCodePage = NlsTable->AnsiTableInfo.CodePage;
+  DPRINT("Ansi codepage %hu\n", NlsAnsiCodePage);
+
+  /* Set OEM data */
+  NlsOemToUnicodeTable = NlsTable->OemTableInfo.MultiByteTable;
+  NlsUnicodeToOemTable = NlsTable->OemTableInfo.WideCharTable;
+  NlsDbcsUnicodeToOemTable = (PWCHAR)NlsTable->OemTableInfo.WideCharTable;
+  NlsMbOemCodePageTag = (NlsTable->OemTableInfo.DBCSCodePage != 0);
+  NlsOemLeadByteInfo = NlsTable->OemTableInfo.DBCSOffsets;
+  NlsOemCodePage = NlsTable->OemTableInfo.CodePage;
+  DPRINT("Oem codepage %hu\n", NlsOemCodePage);
+
+  /* Set Unicode case map data */
+  NlsUnicodeUpcaseTable = NlsTable->UpperCaseTable;
+  NlsUnicodeLowercaseTable = NlsTable->LowerCaseTable;
+}
+
+
+/*
+ * @unimplemented
+ */
 NTSTATUS STDCALL
-RtlUnicodeToCustomCPN(PRTL_NLS_DATA NlsData,
+RtlUnicodeToCustomCPN(IN PCPTABLEINFO CustomCP,
                      PCHAR CustomString,
                      ULONG CustomSize,
                      PULONG ResultSize,
@@ -375,7 +504,7 @@ RtlUnicodeToCustomCPN(PRTL_NLS_DATA NlsData,
   ULONG Size = 0;
   ULONG i;
 
-  if (NlsData->DbcsFlag == 0)
+  if (CustomCP->DBCSCodePage == 0)
     {
       /* single-byte code page */
       if (UnicodeSize > (CustomSize * sizeof(WCHAR)))
@@ -388,7 +517,7 @@ RtlUnicodeToCustomCPN(PRTL_NLS_DATA NlsData,
 
       for (i = 0; i < Size; i++)
        {
-         *CustomString = NlsData->UnicodeToMultiByte[(unsigned int)*UnicodeString];
+         *CustomString = ((PCHAR)CustomCP->WideCharTable)[(unsigned int)*UnicodeString];
          CustomString++;
          UnicodeString++;
        }
@@ -403,6 +532,9 @@ RtlUnicodeToCustomCPN(PRTL_NLS_DATA NlsData,
 }
 
 
+/*
+ * @unimplemented
+ */
 NTSTATUS
 STDCALL
 RtlUnicodeToMultiByteN(PCHAR MbString,
@@ -427,7 +559,7 @@ RtlUnicodeToMultiByteN(PCHAR MbString,
 
       for (i = 0; i < Size; i++)
        {
-         *MbString = UnicodeToAnsiTable[(unsigned int)*UnicodeString];
+         *MbString = NlsUnicodeToAnsiTable[(unsigned int)*UnicodeString];
          MbString++;
          UnicodeString++;
        }
@@ -442,11 +574,17 @@ RtlUnicodeToMultiByteN(PCHAR MbString,
 }
 
 
+/*
+ * @implemented
+ */
 NTSTATUS STDCALL
 RtlUnicodeToMultiByteSize(PULONG MbSize,
                          PWCHAR UnicodeString,
                          ULONG UnicodeSize)
 {
+  ULONG UnicodeLength;
+  ULONG MbLength;
+
   if (NlsMbCodePageTag == FALSE)
     {
       /* single-byte code page */
@@ -455,13 +593,28 @@ RtlUnicodeToMultiByteSize(PULONG MbSize,
   else
     {
       /* multi-byte code page */
-      /* FIXME */
+      UnicodeLength = UnicodeSize / sizeof(WCHAR);
+      MbLength = 0;
+      while (UnicodeLength > 0)
+       {
+         if (NlsLeadByteInfo[*UnicodeString] & 0xff00)
+           MbLength++;
+
+         MbLength++;
+         UnicodeLength--;
+         UnicodeString++;
+       }
+
+      *MbSize = MbLength;
     }
 
   return(STATUS_SUCCESS);
 }
 
 
+/*
+ * @unimplemented
+ */
 NTSTATUS STDCALL
 RtlUnicodeToOemN(PCHAR OemString,
                 ULONG OemSize,
@@ -485,7 +638,7 @@ RtlUnicodeToOemN(PCHAR OemString,
 
       for (i = 0; i < Size; i++)
        {
-         *OemString = UnicodeToOemTable[(unsigned int)*UnicodeString];
+         *OemString = NlsUnicodeToOemTable[(unsigned int)*UnicodeString];
          OemString++;
          UnicodeString++;
        }
@@ -500,8 +653,38 @@ RtlUnicodeToOemN(PCHAR OemString,
 }
 
 
+/*
+ * @implemented
+ */
+WCHAR STDCALL
+RtlUpcaseUnicodeChar(IN WCHAR Source)
+{
+  USHORT Offset;
+
+  if (Source < L'a')
+    return Source;
+
+  if (Source <= L'z')
+    return (Source - (L'a' - L'A'));
+
+  Offset = ((USHORT)Source >> 8);
+  Offset = NlsUnicodeUpcaseTable[Offset];
+
+  Offset += (((USHORT)Source & 0x00F0) >> 4);
+  Offset = NlsUnicodeUpcaseTable[Offset];
+
+  Offset += ((USHORT)Source & 0x000F);
+  Offset = NlsUnicodeUpcaseTable[Offset];
+
+  return Source + (SHORT)Offset;
+}
+
+
+/*
+ * @unimplemented
+ */
 NTSTATUS STDCALL
-RtlUpcaseUnicodeToCustomCPN(PRTL_NLS_DATA NlsData,
+RtlUpcaseUnicodeToCustomCPN(IN PCPTABLEINFO CustomCP,
                            PCHAR CustomString,
                            ULONG CustomSize,
                            PULONG ResultSize,
@@ -512,7 +695,7 @@ RtlUpcaseUnicodeToCustomCPN(PRTL_NLS_DATA NlsData,
   ULONG i;
   WCHAR wc;
 
-  if (NlsData->DbcsFlag == 0)
+  if (CustomCP->DBCSCodePage == 0)
     {
       /* single-byte code page */
       if (UnicodeSize > (CustomSize * sizeof(WCHAR)))
@@ -525,8 +708,8 @@ RtlUpcaseUnicodeToCustomCPN(PRTL_NLS_DATA NlsData,
 
       for (i = 0; i < Size; i++)
        {
-         wc = UnicodeUpcaseTable[(unsigned int)*UnicodeString];
-         *CustomString = NlsData->UnicodeToMultiByte[(unsigned int)wc];
+         wc = RtlUpcaseUnicodeChar(*UnicodeString);
+         *CustomString = ((PCHAR)CustomCP->WideCharTable)[(unsigned int)wc];
          CustomString++;
          UnicodeString++;
        }
@@ -541,6 +724,9 @@ RtlUpcaseUnicodeToCustomCPN(PRTL_NLS_DATA NlsData,
 }
 
 
+/*
+ * @unimplemented
+ */
 NTSTATUS STDCALL
 RtlUpcaseUnicodeToMultiByteN(PCHAR MbString,
                             ULONG MbSize,
@@ -565,8 +751,8 @@ RtlUpcaseUnicodeToMultiByteN(PCHAR MbString,
 
       for (i = 0; i < Size; i++)
        {
-         wc = UnicodeUpcaseTable[(unsigned int)*UnicodeString];
-         *MbString = UnicodeToAnsiTable[(unsigned int)wc];
+         wc = RtlUpcaseUnicodeChar(*UnicodeString);
+         *MbString = NlsUnicodeToAnsiTable[(unsigned int)wc];
          MbString++;
          UnicodeString++;
        }
@@ -581,6 +767,9 @@ RtlUpcaseUnicodeToMultiByteN(PCHAR MbString,
 }
 
 
+/*
+ * @unimplemented
+ */
 NTSTATUS STDCALL
 RtlUpcaseUnicodeToOemN(PCHAR OemString,
                       ULONG OemSize,
@@ -605,8 +794,8 @@ RtlUpcaseUnicodeToOemN(PCHAR OemString,
 
       for (i = 0; i < Size; i++)
        {
-         wc = UnicodeUpcaseTable[(unsigned int)*UnicodeString];
-         *OemString = UnicodeToOemTable[(unsigned int)wc];
+         wc = RtlUpcaseUnicodeChar(*UnicodeString);
+         *OemString = NlsUnicodeToOemTable[(unsigned int)wc];
          OemString++;
          UnicodeString++;
        }
@@ -620,4 +809,37 @@ RtlUpcaseUnicodeToOemN(PCHAR OemString,
   return(STATUS_SUCCESS);
 }
 
+
+/*
+ * @unimplemented
+ */
+CHAR STDCALL
+RtlUpperChar (IN CHAR Source)
+{
+  WCHAR Unicode;
+  CHAR Destination;
+
+  if (NlsMbCodePageTag == FALSE)
+    {
+      /* single-byte code page */
+
+      /* ansi->unicode */
+      Unicode = NlsAnsiToUnicodeTable[(unsigned int)Source];
+
+      /* upcase conversion */
+      Unicode = RtlUpcaseUnicodeChar (Unicode);
+
+      /* unicode -> ansi */
+      Destination = NlsUnicodeToAnsiTable[(unsigned int)Unicode];
+    }
+  else
+    {
+      /* multi-byte code page */
+      /* FIXME */
+      Destination = Source;
+    }
+
+  return Destination;
+}
+
 /* EOF */