3 * COPYRIGHT: See COPYING in the top level directory
4 * PROJECT: ReactOS kernel
5 * FILE: ntoskrnl/rtl/nls.c
6 * PURPOSE: National Language Support (NLS) functions
8 * 20/08/99 Created by Emanuele Aliberti
9 * 10/11/99 Added translation functions.
12 * 1) Add multi-byte translation code.
15 #include <ddk/ntddk.h>
16 #include <internal/mm.h>
17 #include <internal/nls.h>
20 #include <internal/debug.h>
23 /* GLOBALS *******************************************************************/
25 USHORT NlsAnsiCodePage = 0; /* exported */
26 BOOLEAN NlsMbCodePageTag = FALSE; /* exported */
28 PWCHAR NlsAnsiToUnicodeTable = NULL;
29 PCHAR NlsUnicodeToAnsiTable = NULL;
30 PWCHAR NlsDbcsUnicodeToAnsiTable = NULL;
31 PUSHORT NlsLeadByteInfo = NULL; /* exported */
32 #endif /* LIBCAPTIVE */
35 USHORT NlsOemCodePage = 0;
36 BOOLEAN NlsMbOemCodePageTag = FALSE; /* exported */
38 PWCHAR NlsOemToUnicodeTable = NULL;
39 PCHAR NlsUnicodeToOemTable =NULL;
40 PWCHAR NlsDbcsUnicodeToOemTable = NULL;
41 PUSHORT NlsOemLeadByteInfo = NULL; /* exported */
42 #else /* !LIBCAPTIVE */
43 USHORT NlsOemLeadByteInfo = 0;
44 #endif /* LIBCAPTIVE */
48 PUSHORT NlsUnicodeUpcaseTable = NULL;
49 PUSHORT NlsUnicodeLowercaseTable = NULL;
52 static PUSHORT NlsAnsiCodePageTable = NULL;
53 static ULONG NlsAnsiCodePageTableSize = 0;
55 static PUSHORT NlsOemCodePageTable = NULL;
56 static ULONG NlsOemCodePageTableSize = 0;
58 static PUSHORT NlsUnicodeCasemapTable = NULL;
59 static ULONG NlsUnicodeCasemapTableSize = 0;
61 PVOID NlsSectionObject = NULL;
62 static PVOID NlsSectionBase = NULL;
63 static ULONG NlsSectionViewSize = 0;
65 ULONG NlsAnsiTableOffset = 0;
66 ULONG NlsOemTableOffset = 0;
67 ULONG NlsUnicodeTableOffset = 0;
68 #endif /* LIBCAPTIVE */
71 /* FUNCTIONS *****************************************************************/
75 RtlpImportAnsiCodePage(PUSHORT TableBase,
78 NlsAnsiCodePageTable = TableBase;
79 NlsAnsiCodePageTableSize = Size;
84 RtlpImportOemCodePage(PUSHORT TableBase,
87 NlsOemCodePageTable = TableBase;
88 NlsOemCodePageTableSize = Size;
93 RtlpImportUnicodeCasemap(PUSHORT TableBase,
96 NlsUnicodeCasemapTable = TableBase;
97 NlsUnicodeCasemapTableSize = Size;
102 RtlpCreateInitialNlsTables(VOID)
104 NLSTABLEINFO NlsTable;
106 if (NlsAnsiCodePageTable == NULL || NlsAnsiCodePageTableSize == 0 ||
107 NlsOemCodePageTable == NULL || NlsOemCodePageTableSize == 0 ||
108 NlsUnicodeCasemapTable == NULL || NlsUnicodeCasemapTableSize == 0)
110 KEBUGCHECKEX (0x32, STATUS_UNSUCCESSFUL, 1, 0, 0);
113 RtlInitNlsTables (NlsAnsiCodePageTable,
115 NlsUnicodeCasemapTable,
118 RtlResetRtlTranslations (&NlsTable);
123 RtlpCreateNlsSection(VOID)
125 NLSTABLEINFO NlsTable;
126 LARGE_INTEGER SectionSize;
127 HANDLE SectionHandle;
130 DPRINT("RtlpCreateNlsSection() called\n");
132 NlsSectionViewSize = ROUND_UP(NlsAnsiCodePageTableSize, PAGE_SIZE) +
133 ROUND_UP(NlsOemCodePageTableSize, PAGE_SIZE) +
134 ROUND_UP(NlsUnicodeCasemapTableSize, PAGE_SIZE);
136 DPRINT("NlsSectionViewSize %lx\n", NlsSectionViewSize);
138 SectionSize.QuadPart = (LONGLONG)NlsSectionViewSize;
139 Status = NtCreateSection(&SectionHandle,
146 if (!NT_SUCCESS(Status))
148 DPRINT1("NtCreateSection() failed\n");
149 KEBUGCHECKEX(0x32, Status, 1, 1, 0);
152 Status = ObReferenceObjectByHandle(SectionHandle,
158 NtClose(SectionHandle);
159 if (!NT_SUCCESS(Status))
161 DPRINT1("ObReferenceObjectByHandle() failed\n");
162 KEBUGCHECKEX(0x32, Status, 1, 2, 0);
165 Status = MmMapViewInSystemSpace(NlsSectionObject,
167 &NlsSectionViewSize);
168 if (!NT_SUCCESS(Status))
170 DPRINT1("MmMapViewInSystemSpace() failed\n");
171 KEBUGCHECKEX(0x32, Status, 1, 3, 0);
174 DPRINT("NlsSection: Base %p Size %lx\n",
178 NlsAnsiTableOffset = 0;
179 RtlCopyMemory((PVOID)((ULONG)NlsSectionBase + NlsAnsiTableOffset),
180 NlsAnsiCodePageTable,
181 NlsAnsiCodePageTableSize);
183 NlsOemTableOffset = NlsAnsiTableOffset + ROUND_UP(NlsAnsiCodePageTableSize, PAGE_SIZE);
184 RtlCopyMemory((PVOID)((ULONG)NlsSectionBase + NlsOemTableOffset),
186 NlsOemCodePageTableSize);
188 NlsUnicodeTableOffset = NlsOemTableOffset + ROUND_UP(NlsOemCodePageTableSize, PAGE_SIZE);
189 RtlCopyMemory((PVOID)((ULONG)NlsSectionBase + NlsUnicodeTableOffset),
190 NlsUnicodeCasemapTable,
191 NlsUnicodeCasemapTableSize);
193 RtlInitNlsTables ((PVOID)((ULONG)NlsSectionBase + NlsAnsiTableOffset),
194 (PVOID)((ULONG)NlsSectionBase + NlsOemTableOffset),
195 (PVOID)((ULONG)NlsSectionBase + NlsUnicodeTableOffset),
198 RtlResetRtlTranslations (&NlsTable);
206 RtlCustomCPToUnicodeN(IN PCPTABLEINFO CustomCP,
207 PWCHAR UnicodeString,
216 if (CustomCP->DBCSCodePage == 0)
218 /* single-byte code page */
219 if (CustomSize > (UnicodeSize / sizeof(WCHAR)))
220 Size = UnicodeSize / sizeof(WCHAR);
224 if (ResultSize != NULL)
225 *ResultSize = Size * sizeof(WCHAR);
227 for (i = 0; i < Size; i++)
229 *UnicodeString = CustomCP->MultiByteTable[(unsigned int)*CustomString];
236 /* multi-byte code page */
240 return(STATUS_SUCCESS);
243 #endif /* LIBCAPTIVE */
246 RtlDowncaseUnicodeChar (IN WCHAR Source)
250 #endif /* LIBCAPTIVE */
256 return Source + (L'a' - L'A');
262 Offset = ((USHORT)Source >> 8);
263 Offset = NlsUnicodeLowercaseTable[Offset];
265 Offset += (((USHORT)Source & 0x00F0) >> 4);
266 Offset = NlsUnicodeLowercaseTable[Offset];
268 Offset += ((USHORT)Source & 0x000F);
269 Offset = NlsUnicodeLowercaseTable[Offset];
271 return Source + (SHORT)Offset;
272 #else /* !LIBCAPTIVE */
274 #endif /* LIBCAPTIVE */
283 RtlGetDefaultCodePage(PUSHORT AnsiCodePage,
286 *AnsiCodePage = NlsAnsiCodePage;
287 *OemCodePage = NlsOemCodePage;
290 #endif /* LIBCAPTIVE */
296 RtlInitCodePageTable(IN PUSHORT TableBase,
297 OUT PCPTABLEINFO CodePageTable)
299 PNLS_FILE_HEADER NlsFileHeader;
303 DPRINT("RtlInitCodePageTable() called\n");
305 NlsFileHeader = (PNLS_FILE_HEADER)TableBase;
307 CodePageTable->CodePage = NlsFileHeader->CodePage;
308 CodePageTable->MaximumCharacterSize = NlsFileHeader->MaximumCharacterSize;
309 CodePageTable->DefaultChar = NlsFileHeader->DefaultChar;
310 CodePageTable->UniDefaultChar = NlsFileHeader->UniDefaultChar;
311 CodePageTable->TransDefaultChar = NlsFileHeader->TransDefaultChar;
312 CodePageTable->TransUniDefaultChar = NlsFileHeader->TransUniDefaultChar;
314 RtlCopyMemory(&CodePageTable->LeadByte,
315 &NlsFileHeader->LeadByte,
318 /* Set Pointer to start of multi byte table */
319 Ptr = (PUSHORT)((ULONG_PTR)TableBase + 2 * NlsFileHeader->HeaderSize);
321 /* Get offset to the wide char table */
322 Offset = (USHORT)(*Ptr++) + NlsFileHeader->HeaderSize + 1;
324 /* Set pointer to the multi byte table */
325 CodePageTable->MultiByteTable = Ptr;
327 /* Skip ANSI and OEM table */
332 /* Set pointer to DBCS ranges */
333 CodePageTable->DBCSRanges = (PUSHORT)Ptr;
337 CodePageTable->DBCSCodePage = 1;
338 CodePageTable->DBCSOffsets = (PUSHORT)++Ptr;
342 CodePageTable->DBCSCodePage = 0;
343 CodePageTable->DBCSOffsets = 0;
346 CodePageTable->WideCharTable = (PVOID)((ULONG_PTR)TableBase + 2 * Offset);
351 RtlInitNlsTables(IN PUSHORT AnsiTableBase,
352 IN PUSHORT OemTableBase,
353 IN PUSHORT CaseTableBase,
354 OUT PNLSTABLEINFO NlsTable)
356 DPRINT("RtlInitNlsTables()called\n");
358 RtlInitCodePageTable (AnsiTableBase,
359 &NlsTable->AnsiTableInfo);
361 RtlInitCodePageTable (OemTableBase,
362 &NlsTable->OemTableInfo);
364 NlsTable->UpperCaseTable = (PUSHORT)CaseTableBase + 2;
365 NlsTable->LowerCaseTable = (PUSHORT)CaseTableBase + *((PUSHORT)CaseTableBase + 1) + 2;
373 RtlMultiByteToUnicodeN(PWCHAR UnicodeString,
376 const PCHAR MbString,
382 if (NlsMbCodePageTag == FALSE)
384 /* single-byte code page */
385 if (MbSize > (UnicodeSize / sizeof(WCHAR)))
386 Size = UnicodeSize / sizeof(WCHAR);
390 if (ResultSize != NULL)
391 *ResultSize = Size * sizeof(WCHAR);
393 for (i = 0; i < Size; i++)
395 UnicodeString[i] = NlsAnsiToUnicodeTable[(unsigned int)MbString[i]];
396 #else /* !LIBCAPTIVE */
397 UnicodeString[i] = (unsigned int)MbString[i];
398 #endif /* LIBCAPTIVE */
402 /* multi-byte code page */
406 return(STATUS_SUCCESS);
414 RtlMultiByteToUnicodeSize(PULONG UnicodeSize,
420 #endif /* LIBCAPTIVE */
422 if (NlsMbCodePageTag == FALSE)
424 /* single-byte code page */
425 *UnicodeSize = MbSize * sizeof (WCHAR);
430 /* multi-byte code page */
431 for (Length = 0; MbSize; MbSize--, MbString++, Length++)
433 if (NlsLeadByteInfo[(UCHAR)*MbString] != 0)
436 break; /* partial char, ignore it */
441 *UnicodeSize = Length * sizeof(WCHAR);
442 #else /* !LIBCAPTIVE */
444 #endif /* LIBCAPTIVE */
447 return STATUS_SUCCESS;
455 RtlOemToUnicodeN(PWCHAR UnicodeString,
464 if (NlsMbOemCodePageTag == FALSE)
466 /* single-byte code page */
467 if (OemSize > (UnicodeSize / sizeof(WCHAR)))
468 Size = UnicodeSize / sizeof(WCHAR);
472 if (ResultSize != NULL)
473 *ResultSize = Size * sizeof(WCHAR);
475 for (i = 0; i < Size; i++)
478 *UnicodeString = NlsOemToUnicodeTable[(unsigned int)*OemString];
479 #else /* !LIBCAPTIVE */
480 *UnicodeString = *OemString;
481 #endif /* LIBCAPTIVE */
488 /* multi-byte code page */
492 return(STATUS_SUCCESS);
498 RtlResetRtlTranslations(IN PNLSTABLEINFO NlsTable)
500 DPRINT("RtlResetRtlTranslations() called\n");
503 NlsAnsiToUnicodeTable = NlsTable->AnsiTableInfo.MultiByteTable;
504 NlsUnicodeToAnsiTable = NlsTable->AnsiTableInfo.WideCharTable;
505 NlsDbcsUnicodeToAnsiTable = (PWCHAR)NlsTable->AnsiTableInfo.WideCharTable;
506 NlsMbCodePageTag = (NlsTable->AnsiTableInfo.DBCSCodePage != 0);
507 NlsLeadByteInfo = NlsTable->AnsiTableInfo.DBCSOffsets;
508 NlsAnsiCodePage = NlsTable->AnsiTableInfo.CodePage;
509 DPRINT("Ansi codepage %hu\n", NlsAnsiCodePage);
512 NlsOemToUnicodeTable = NlsTable->OemTableInfo.MultiByteTable;
513 NlsUnicodeToOemTable = NlsTable->OemTableInfo.WideCharTable;
514 NlsDbcsUnicodeToOemTable = (PWCHAR)NlsTable->OemTableInfo.WideCharTable;
515 NlsMbOemCodePageTag = (NlsTable->OemTableInfo.DBCSCodePage != 0);
516 NlsOemLeadByteInfo = NlsTable->OemTableInfo.DBCSOffsets;
517 NlsOemCodePage = NlsTable->OemTableInfo.CodePage;
518 DPRINT("Oem codepage %hu\n", NlsOemCodePage);
520 /* Set Unicode case map data */
521 NlsUnicodeUpcaseTable = NlsTable->UpperCaseTable;
522 NlsUnicodeLowercaseTable = NlsTable->LowerCaseTable;
530 RtlUnicodeToCustomCPN(IN PCPTABLEINFO CustomCP,
534 PWCHAR UnicodeString,
540 if (CustomCP->DBCSCodePage == 0)
542 /* single-byte code page */
543 if (UnicodeSize > (CustomSize * sizeof(WCHAR)))
546 Size = UnicodeSize / sizeof(WCHAR);
548 if (ResultSize != NULL)
551 for (i = 0; i < Size; i++)
553 *CustomString = ((PCHAR)CustomCP->WideCharTable)[(unsigned int)*UnicodeString];
560 /* multi-byte code page */
564 return(STATUS_SUCCESS);
567 #endif /* LIBCAPTIVE */
574 RtlUnicodeToMultiByteN(PCHAR MbString,
577 PWCHAR UnicodeString,
583 if (NlsMbCodePageTag == FALSE)
585 /* single-byte code page */
586 if (UnicodeSize > (MbSize * sizeof(WCHAR)))
589 Size = UnicodeSize / sizeof(WCHAR);
591 if (ResultSize != NULL)
594 for (i = 0; i < Size; i++)
597 *MbString = NlsUnicodeToAnsiTable[(unsigned int)*UnicodeString];
598 #else /* !LIBCAPTIVE */
599 *MbString = *UnicodeString;
600 #endif /* LIBCAPTIVE */
607 /* multi-byte code page */
611 return(STATUS_SUCCESS);
619 RtlUnicodeToMultiByteSize(PULONG MbSize,
620 PWCHAR UnicodeString,
626 #endif /* LIBCAPTIVE */
628 if (NlsMbCodePageTag == FALSE)
630 /* single-byte code page */
631 *MbSize = UnicodeSize / sizeof (WCHAR);
636 /* multi-byte code page */
637 UnicodeLength = UnicodeSize / sizeof(WCHAR);
639 while (UnicodeLength > 0)
641 if (NlsLeadByteInfo[*UnicodeString] & 0xff00)
650 #else /* !LIBCAPTIVE */
652 #endif /* LIBCAPTIVE */
655 return(STATUS_SUCCESS);
663 RtlUnicodeToOemN(PCHAR OemString,
666 PWCHAR UnicodeString,
672 if (NlsMbOemCodePageTag == FALSE)
674 /* single-byte code page */
675 if (UnicodeSize > (OemSize * sizeof(WCHAR)))
678 Size = UnicodeSize / sizeof(WCHAR);
680 if (ResultSize != NULL)
683 for (i = 0; i < Size; i++)
686 *OemString = NlsUnicodeToOemTable[(unsigned int)*UnicodeString];
687 #else /* !LIBCAPTIVE */
688 *OemString = *UnicodeString;
689 #endif /* LIBCAPTIVE */
696 /* multi-byte code page */
700 return(STATUS_SUCCESS);
709 RtlUpcaseUnicodeChar(IN WCHAR Source)
717 return (Source - (L'a' - L'A'));
719 Offset = ((USHORT)Source >> 8);
720 Offset = NlsUnicodeUpcaseTable[Offset];
722 Offset += (((USHORT)Source & 0x00F0) >> 4);
723 Offset = NlsUnicodeUpcaseTable[Offset];
725 Offset += ((USHORT)Source & 0x000F);
726 Offset = NlsUnicodeUpcaseTable[Offset];
728 return Source + (SHORT)Offset;
736 RtlUpcaseUnicodeToCustomCPN(IN PCPTABLEINFO CustomCP,
740 PWCHAR UnicodeString,
747 if (CustomCP->DBCSCodePage == 0)
749 /* single-byte code page */
750 if (UnicodeSize > (CustomSize * sizeof(WCHAR)))
753 Size = UnicodeSize / sizeof(WCHAR);
755 if (ResultSize != NULL)
758 for (i = 0; i < Size; i++)
760 wc = RtlUpcaseUnicodeChar(*UnicodeString);
761 *CustomString = ((PCHAR)CustomCP->WideCharTable)[(unsigned int)wc];
768 /* multi-byte code page */
772 return(STATUS_SUCCESS);
775 #endif /* LIBCAPTIVE */
781 RtlUpcaseUnicodeToMultiByteN(PCHAR MbString,
784 PWCHAR UnicodeString,
791 if (NlsMbCodePageTag == FALSE)
793 /* single-byte code page */
794 if (UnicodeSize > (MbSize * sizeof(WCHAR)))
797 Size = UnicodeSize / sizeof(WCHAR);
799 if (ResultSize != NULL)
802 for (i = 0; i < Size; i++)
804 wc = RtlUpcaseUnicodeChar(*UnicodeString);
806 *MbString = NlsUnicodeToAnsiTable[(unsigned int)wc];
807 #else /* !LIBCAPTIVE */
809 #endif /* LIBCAPTIVE */
816 /* multi-byte code page */
820 return(STATUS_SUCCESS);
828 RtlUpcaseUnicodeToOemN(PCHAR OemString,
831 PWCHAR UnicodeString,
838 if (NlsMbOemCodePageTag == FALSE)
840 /* single-byte code page */
841 if (UnicodeSize > (OemSize * sizeof(WCHAR)))
844 Size = UnicodeSize / sizeof(WCHAR);
846 if (ResultSize != NULL)
849 for (i = 0; i < Size; i++)
851 wc = RtlUpcaseUnicodeChar(*UnicodeString);
853 *OemString = NlsUnicodeToOemTable[(unsigned int)wc];
854 #else /* !LIBCAPTIVE */
856 #endif /* LIBCAPTIVE */
863 /* multi-byte code page */
867 return(STATUS_SUCCESS);
875 RtlUpperChar (IN CHAR Source)
880 if (NlsMbCodePageTag == FALSE)
882 /* single-byte code page */
886 Unicode = NlsAnsiToUnicodeTable[(unsigned int)Source];
887 #else /* !LIBCAPTIVE */
889 #endif /* LIBCAPTIVE */
891 /* upcase conversion */
892 Unicode = RtlUpcaseUnicodeChar (Unicode);
894 /* unicode -> ansi */
896 Destination = NlsUnicodeToAnsiTable[(unsigned int)Unicode];
897 #else /* !LIBCAPTIVE */
898 Destination = Unicode;
899 #endif /* LIBCAPTIVE */
903 /* multi-byte code page */
905 Destination = Source;