1 /* $Id: nls.c,v 1.21 2003/10/11 17:23:52 hbirr Exp $
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
[(UCHAR
)*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
[(UCHAR
)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
[(UCHAR
)*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
)[(USHORT
)*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
[(USHORT
)*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
[(USHORT
)*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
[(USHORT
)*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
)[(USHORT
)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
[(USHORT
)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
[(USHORT
)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
[(UCHAR
)Source
];
829 /* upcase conversion */
830 Unicode
= RtlUpcaseUnicodeChar (Unicode
);
832 /* unicode -> ansi */
833 Destination
= NlsUnicodeToAnsiTable
[(USHORT
)Unicode
];
837 /* multi-byte code page */
839 Destination
= Source
;