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 */
27 PWCHAR NlsAnsiToUnicodeTable = NULL;
28 PCHAR NlsUnicodeToAnsiTable = NULL;
29 PWCHAR NlsDbcsUnicodeToAnsiTable = NULL;
30 PUSHORT NlsLeadByteInfo = NULL; /* exported */
33 USHORT NlsOemCodePage = 0;
34 BOOLEAN NlsMbOemCodePageTag = FALSE; /* exported */
35 PWCHAR NlsOemToUnicodeTable = NULL;
36 PCHAR NlsUnicodeToOemTable =NULL;
37 PWCHAR NlsDbcsUnicodeToOemTable = NULL;
38 PUSHORT NlsOemLeadByteInfo = NULL; /* exported */
41 PUSHORT NlsUnicodeUpcaseTable = NULL;
42 PUSHORT NlsUnicodeLowercaseTable = NULL;
45 static PUSHORT NlsAnsiCodePageTable = NULL;
46 static ULONG NlsAnsiCodePageTableSize = 0;
48 static PUSHORT NlsOemCodePageTable = NULL;
49 static ULONG NlsOemCodePageTableSize = 0;
51 static PUSHORT NlsUnicodeCasemapTable = NULL;
52 static ULONG NlsUnicodeCasemapTableSize = 0;
54 PVOID NlsSectionObject = NULL;
55 static PVOID NlsSectionBase = NULL;
56 static ULONG NlsSectionViewSize = 0;
58 ULONG NlsAnsiTableOffset = 0;
59 ULONG NlsOemTableOffset = 0;
60 ULONG NlsUnicodeTableOffset = 0;
63 /* FUNCTIONS *****************************************************************/
66 RtlpImportAnsiCodePage(PUSHORT TableBase,
69 NlsAnsiCodePageTable = TableBase;
70 NlsAnsiCodePageTableSize = Size;
75 RtlpImportOemCodePage(PUSHORT TableBase,
78 NlsOemCodePageTable = TableBase;
79 NlsOemCodePageTableSize = Size;
84 RtlpImportUnicodeCasemap(PUSHORT TableBase,
87 NlsUnicodeCasemapTable = TableBase;
88 NlsUnicodeCasemapTableSize = Size;
93 RtlpCreateInitialNlsTables(VOID)
95 NLSTABLEINFO NlsTable;
97 if (NlsAnsiCodePageTable == NULL || NlsAnsiCodePageTableSize == 0 ||
98 NlsOemCodePageTable == NULL || NlsOemCodePageTableSize == 0 ||
99 NlsUnicodeCasemapTable == NULL || NlsUnicodeCasemapTableSize == 0)
101 KEBUGCHECKEX (0x32, STATUS_UNSUCCESSFUL, 1, 0, 0);
104 RtlInitNlsTables (NlsAnsiCodePageTable,
106 NlsUnicodeCasemapTable,
109 RtlResetRtlTranslations (&NlsTable);
114 RtlpCreateNlsSection(VOID)
116 NLSTABLEINFO NlsTable;
117 LARGE_INTEGER SectionSize;
118 HANDLE SectionHandle;
121 DPRINT("RtlpCreateNlsSection() called\n");
123 NlsSectionViewSize = ROUND_UP(NlsAnsiCodePageTableSize, PAGE_SIZE) +
124 ROUND_UP(NlsOemCodePageTableSize, PAGE_SIZE) +
125 ROUND_UP(NlsUnicodeCasemapTableSize, PAGE_SIZE);
127 DPRINT("NlsSectionViewSize %lx\n", NlsSectionViewSize);
129 SectionSize.QuadPart = (LONGLONG)NlsSectionViewSize;
130 Status = NtCreateSection(&SectionHandle,
137 if (!NT_SUCCESS(Status))
139 DPRINT1("NtCreateSection() failed\n");
140 KEBUGCHECKEX(0x32, Status, 1, 1, 0);
143 Status = ObReferenceObjectByHandle(SectionHandle,
149 NtClose(SectionHandle);
150 if (!NT_SUCCESS(Status))
152 DPRINT1("ObReferenceObjectByHandle() failed\n");
153 KEBUGCHECKEX(0x32, Status, 1, 2, 0);
156 Status = MmMapViewInSystemSpace(NlsSectionObject,
158 &NlsSectionViewSize);
159 if (!NT_SUCCESS(Status))
161 DPRINT1("MmMapViewInSystemSpace() failed\n");
162 KEBUGCHECKEX(0x32, Status, 1, 3, 0);
165 DPRINT("NlsSection: Base %p Size %lx\n",
169 NlsAnsiTableOffset = 0;
170 RtlCopyMemory((PVOID)((ULONG)NlsSectionBase + NlsAnsiTableOffset),
171 NlsAnsiCodePageTable,
172 NlsAnsiCodePageTableSize);
174 NlsOemTableOffset = NlsAnsiTableOffset + ROUND_UP(NlsAnsiCodePageTableSize, PAGE_SIZE);
175 RtlCopyMemory((PVOID)((ULONG)NlsSectionBase + NlsOemTableOffset),
177 NlsOemCodePageTableSize);
179 NlsUnicodeTableOffset = NlsOemTableOffset + ROUND_UP(NlsOemCodePageTableSize, PAGE_SIZE);
180 RtlCopyMemory((PVOID)((ULONG)NlsSectionBase + NlsUnicodeTableOffset),
181 NlsUnicodeCasemapTable,
182 NlsUnicodeCasemapTableSize);
184 RtlInitNlsTables ((PVOID)((ULONG)NlsSectionBase + NlsAnsiTableOffset),
185 (PVOID)((ULONG)NlsSectionBase + NlsOemTableOffset),
186 (PVOID)((ULONG)NlsSectionBase + NlsUnicodeTableOffset),
189 RtlResetRtlTranslations (&NlsTable);
197 RtlCustomCPToUnicodeN(IN PCPTABLEINFO CustomCP,
198 PWCHAR UnicodeString,
207 if (CustomCP->DBCSCodePage == 0)
209 /* single-byte code page */
210 if (CustomSize > (UnicodeSize / sizeof(WCHAR)))
211 Size = UnicodeSize / sizeof(WCHAR);
215 if (ResultSize != NULL)
216 *ResultSize = Size * sizeof(WCHAR);
218 for (i = 0; i < Size; i++)
220 *UnicodeString = CustomCP->MultiByteTable[(unsigned int)*CustomString];
227 /* multi-byte code page */
231 return(STATUS_SUCCESS);
236 RtlDowncaseUnicodeChar (IN WCHAR Source)
244 return Source + (L'a' - L'A');
249 Offset = ((USHORT)Source >> 8);
250 Offset = NlsUnicodeLowercaseTable[Offset];
252 Offset += (((USHORT)Source & 0x00F0) >> 4);
253 Offset = NlsUnicodeLowercaseTable[Offset];
255 Offset += ((USHORT)Source & 0x000F);
256 Offset = NlsUnicodeLowercaseTable[Offset];
258 return Source + (SHORT)Offset;
266 RtlGetDefaultCodePage(PUSHORT AnsiCodePage,
269 *AnsiCodePage = NlsAnsiCodePage;
270 *OemCodePage = NlsOemCodePage;
278 RtlInitCodePageTable(IN PUSHORT TableBase,
279 OUT PCPTABLEINFO CodePageTable)
281 PNLS_FILE_HEADER NlsFileHeader;
285 DPRINT("RtlInitCodePageTable() called\n");
287 NlsFileHeader = (PNLS_FILE_HEADER)TableBase;
289 CodePageTable->CodePage = NlsFileHeader->CodePage;
290 CodePageTable->MaximumCharacterSize = NlsFileHeader->MaximumCharacterSize;
291 CodePageTable->DefaultChar = NlsFileHeader->DefaultChar;
292 CodePageTable->UniDefaultChar = NlsFileHeader->UniDefaultChar;
293 CodePageTable->TransDefaultChar = NlsFileHeader->TransDefaultChar;
294 CodePageTable->TransUniDefaultChar = NlsFileHeader->TransUniDefaultChar;
296 RtlCopyMemory(&CodePageTable->LeadByte,
297 &NlsFileHeader->LeadByte,
300 /* Set Pointer to start of multi byte table */
301 Ptr = (PUSHORT)((ULONG_PTR)TableBase + 2 * NlsFileHeader->HeaderSize);
303 /* Get offset to the wide char table */
304 Offset = (USHORT)(*Ptr++) + NlsFileHeader->HeaderSize + 1;
306 /* Set pointer to the multi byte table */
307 CodePageTable->MultiByteTable = Ptr;
309 /* Skip ANSI and OEM table */
314 /* Set pointer to DBCS ranges */
315 CodePageTable->DBCSRanges = (PUSHORT)Ptr;
319 CodePageTable->DBCSCodePage = 1;
320 CodePageTable->DBCSOffsets = (PUSHORT)++Ptr;
324 CodePageTable->DBCSCodePage = 0;
325 CodePageTable->DBCSOffsets = 0;
328 CodePageTable->WideCharTable = (PVOID)((ULONG_PTR)TableBase + 2 * Offset);
333 RtlInitNlsTables(IN PUSHORT AnsiTableBase,
334 IN PUSHORT OemTableBase,
335 IN PUSHORT CaseTableBase,
336 OUT PNLSTABLEINFO NlsTable)
338 DPRINT("RtlInitNlsTables()called\n");
340 RtlInitCodePageTable (AnsiTableBase,
341 &NlsTable->AnsiTableInfo);
343 RtlInitCodePageTable (OemTableBase,
344 &NlsTable->OemTableInfo);
346 NlsTable->UpperCaseTable = (PUSHORT)CaseTableBase + 2;
347 NlsTable->LowerCaseTable = (PUSHORT)CaseTableBase + *((PUSHORT)CaseTableBase + 1) + 2;
355 RtlMultiByteToUnicodeN(PWCHAR UnicodeString,
358 const PCHAR MbString,
364 if (NlsMbCodePageTag == FALSE)
366 /* single-byte code page */
367 if (MbSize > (UnicodeSize / sizeof(WCHAR)))
368 Size = UnicodeSize / sizeof(WCHAR);
372 if (ResultSize != NULL)
373 *ResultSize = Size * sizeof(WCHAR);
375 for (i = 0; i < Size; i++)
376 UnicodeString[i] = NlsAnsiToUnicodeTable[(unsigned int)MbString[i]];
380 /* multi-byte code page */
384 return(STATUS_SUCCESS);
392 RtlMultiByteToUnicodeSize(PULONG UnicodeSize,
398 if (NlsMbCodePageTag == FALSE)
400 /* single-byte code page */
401 *UnicodeSize = MbSize * sizeof (WCHAR);
405 /* multi-byte code page */
406 for (Length = 0; MbSize; MbSize--, MbString++, Length++)
408 if (NlsLeadByteInfo[(UCHAR)*MbString] != 0)
411 break; /* partial char, ignore it */
416 *UnicodeSize = Length * sizeof(WCHAR);
419 return STATUS_SUCCESS;
427 RtlOemToUnicodeN(PWCHAR UnicodeString,
436 if (NlsMbOemCodePageTag == FALSE)
438 /* single-byte code page */
439 if (OemSize > (UnicodeSize / sizeof(WCHAR)))
440 Size = UnicodeSize / sizeof(WCHAR);
444 if (ResultSize != NULL)
445 *ResultSize = Size * sizeof(WCHAR);
447 for (i = 0; i < Size; i++)
449 *UnicodeString = NlsOemToUnicodeTable[(unsigned int)*OemString];
456 /* multi-byte code page */
460 return(STATUS_SUCCESS);
465 RtlResetRtlTranslations(IN PNLSTABLEINFO NlsTable)
467 DPRINT("RtlResetRtlTranslations() called\n");
470 NlsAnsiToUnicodeTable = NlsTable->AnsiTableInfo.MultiByteTable;
471 NlsUnicodeToAnsiTable = NlsTable->AnsiTableInfo.WideCharTable;
472 NlsDbcsUnicodeToAnsiTable = (PWCHAR)NlsTable->AnsiTableInfo.WideCharTable;
473 NlsMbCodePageTag = (NlsTable->AnsiTableInfo.DBCSCodePage != 0);
474 NlsLeadByteInfo = NlsTable->AnsiTableInfo.DBCSOffsets;
475 NlsAnsiCodePage = NlsTable->AnsiTableInfo.CodePage;
476 DPRINT("Ansi codepage %hu\n", NlsAnsiCodePage);
479 NlsOemToUnicodeTable = NlsTable->OemTableInfo.MultiByteTable;
480 NlsUnicodeToOemTable = NlsTable->OemTableInfo.WideCharTable;
481 NlsDbcsUnicodeToOemTable = (PWCHAR)NlsTable->OemTableInfo.WideCharTable;
482 NlsMbOemCodePageTag = (NlsTable->OemTableInfo.DBCSCodePage != 0);
483 NlsOemLeadByteInfo = NlsTable->OemTableInfo.DBCSOffsets;
484 NlsOemCodePage = NlsTable->OemTableInfo.CodePage;
485 DPRINT("Oem codepage %hu\n", NlsOemCodePage);
487 /* Set Unicode case map data */
488 NlsUnicodeUpcaseTable = NlsTable->UpperCaseTable;
489 NlsUnicodeLowercaseTable = NlsTable->LowerCaseTable;
497 RtlUnicodeToCustomCPN(IN PCPTABLEINFO CustomCP,
501 PWCHAR UnicodeString,
507 if (CustomCP->DBCSCodePage == 0)
509 /* single-byte code page */
510 if (UnicodeSize > (CustomSize * sizeof(WCHAR)))
513 Size = UnicodeSize / sizeof(WCHAR);
515 if (ResultSize != NULL)
518 for (i = 0; i < Size; i++)
520 *CustomString = ((PCHAR)CustomCP->WideCharTable)[(unsigned int)*UnicodeString];
527 /* multi-byte code page */
531 return(STATUS_SUCCESS);
540 RtlUnicodeToMultiByteN(PCHAR MbString,
543 PWCHAR UnicodeString,
549 if (NlsMbCodePageTag == FALSE)
551 /* single-byte code page */
552 if (UnicodeSize > (MbSize * sizeof(WCHAR)))
555 Size = UnicodeSize / sizeof(WCHAR);
557 if (ResultSize != NULL)
560 for (i = 0; i < Size; i++)
562 *MbString = NlsUnicodeToAnsiTable[(unsigned int)*UnicodeString];
569 /* multi-byte code page */
573 return(STATUS_SUCCESS);
581 RtlUnicodeToMultiByteSize(PULONG MbSize,
582 PWCHAR UnicodeString,
588 if (NlsMbCodePageTag == FALSE)
590 /* single-byte code page */
591 *MbSize = UnicodeSize / sizeof (WCHAR);
595 /* multi-byte code page */
596 UnicodeLength = UnicodeSize / sizeof(WCHAR);
598 while (UnicodeLength > 0)
600 if (NlsLeadByteInfo[*UnicodeString] & 0xff00)
611 return(STATUS_SUCCESS);
619 RtlUnicodeToOemN(PCHAR OemString,
622 PWCHAR UnicodeString,
628 if (NlsMbOemCodePageTag == FALSE)
630 /* single-byte code page */
631 if (UnicodeSize > (OemSize * sizeof(WCHAR)))
634 Size = UnicodeSize / sizeof(WCHAR);
636 if (ResultSize != NULL)
639 for (i = 0; i < Size; i++)
641 *OemString = NlsUnicodeToOemTable[(unsigned int)*UnicodeString];
648 /* multi-byte code page */
652 return(STATUS_SUCCESS);
660 RtlUpcaseUnicodeChar(IN WCHAR Source)
668 return (Source - (L'a' - L'A'));
670 Offset = ((USHORT)Source >> 8);
671 Offset = NlsUnicodeUpcaseTable[Offset];
673 Offset += (((USHORT)Source & 0x00F0) >> 4);
674 Offset = NlsUnicodeUpcaseTable[Offset];
676 Offset += ((USHORT)Source & 0x000F);
677 Offset = NlsUnicodeUpcaseTable[Offset];
679 return Source + (SHORT)Offset;
687 RtlUpcaseUnicodeToCustomCPN(IN PCPTABLEINFO CustomCP,
691 PWCHAR UnicodeString,
698 if (CustomCP->DBCSCodePage == 0)
700 /* single-byte code page */
701 if (UnicodeSize > (CustomSize * sizeof(WCHAR)))
704 Size = UnicodeSize / sizeof(WCHAR);
706 if (ResultSize != NULL)
709 for (i = 0; i < Size; i++)
711 wc = RtlUpcaseUnicodeChar(*UnicodeString);
712 *CustomString = ((PCHAR)CustomCP->WideCharTable)[(unsigned int)wc];
719 /* multi-byte code page */
723 return(STATUS_SUCCESS);
731 RtlUpcaseUnicodeToMultiByteN(PCHAR MbString,
734 PWCHAR UnicodeString,
741 if (NlsMbCodePageTag == FALSE)
743 /* single-byte code page */
744 if (UnicodeSize > (MbSize * sizeof(WCHAR)))
747 Size = UnicodeSize / sizeof(WCHAR);
749 if (ResultSize != NULL)
752 for (i = 0; i < Size; i++)
754 wc = RtlUpcaseUnicodeChar(*UnicodeString);
755 *MbString = NlsUnicodeToAnsiTable[(unsigned int)wc];
762 /* multi-byte code page */
766 return(STATUS_SUCCESS);
774 RtlUpcaseUnicodeToOemN(PCHAR OemString,
777 PWCHAR UnicodeString,
784 if (NlsMbOemCodePageTag == FALSE)
786 /* single-byte code page */
787 if (UnicodeSize > (OemSize * sizeof(WCHAR)))
790 Size = UnicodeSize / sizeof(WCHAR);
792 if (ResultSize != NULL)
795 for (i = 0; i < Size; i++)
797 wc = RtlUpcaseUnicodeChar(*UnicodeString);
798 *OemString = NlsUnicodeToOemTable[(unsigned int)wc];
805 /* multi-byte code page */
809 return(STATUS_SUCCESS);
817 RtlUpperChar (IN CHAR Source)
822 if (NlsMbCodePageTag == FALSE)
824 /* single-byte code page */
827 Unicode = NlsAnsiToUnicodeTable[(unsigned int)Source];
829 /* upcase conversion */
830 Unicode = RtlUpcaseUnicodeChar (Unicode);
832 /* unicode -> ansi */
833 Destination = NlsUnicodeToAnsiTable[(unsigned int)Unicode];
837 /* multi-byte code page */
839 Destination = Source;