1 /* $Id: nls.c,v 1.17 2003/07/11 01:23:15 royce 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
);
116 RtlpCreateNlsSection(VOID
)
118 NLSTABLEINFO NlsTable
;
119 LARGE_INTEGER SectionSize
;
120 HANDLE SectionHandle
;
123 DPRINT("RtlpCreateNlsSection() called\n");
125 NlsSectionViewSize
= ROUND_UP(NlsAnsiCodePageTableSize
, PAGE_SIZE
) +
126 ROUND_UP(NlsOemCodePageTableSize
, PAGE_SIZE
) +
127 ROUND_UP(NlsUnicodeCasemapTableSize
, PAGE_SIZE
);
129 DPRINT("NlsSectionViewSize %lx\n", NlsSectionViewSize
);
131 SectionSize
.QuadPart
= (LONGLONG
)NlsSectionViewSize
;
132 Status
= NtCreateSection(&SectionHandle
,
139 if (!NT_SUCCESS(Status
))
141 DPRINT1("NtCreateSection() failed\n");
142 KeBugCheckEx(0x32, Status
, 1, 1, 0);
145 Status
= ObReferenceObjectByHandle(SectionHandle
,
151 NtClose(SectionHandle
);
152 if (!NT_SUCCESS(Status
))
154 DPRINT1("ObReferenceObjectByHandle() failed\n");
155 KeBugCheckEx(0x32, Status
, 1, 2, 0);
158 Status
= MmMapViewInSystemSpace(NlsSectionObject
,
160 &NlsSectionViewSize
);
161 NtClose(SectionHandle
);
162 if (!NT_SUCCESS(Status
))
164 DPRINT1("MmMapViewInSystemSpace() failed\n");
165 KeBugCheckEx(0x32, Status
, 1, 3, 0);
168 DPRINT("NlsSection: Base %p Size %lx\n",
172 NlsAnsiTableOffset
= 0;
173 RtlCopyMemory((PVOID
)((ULONG
)NlsSectionBase
+ NlsAnsiTableOffset
),
174 NlsAnsiCodePageTable
,
175 NlsAnsiCodePageTableSize
);
177 NlsOemTableOffset
= NlsAnsiTableOffset
+ ROUND_UP(NlsAnsiCodePageTableSize
, PAGE_SIZE
);
178 RtlCopyMemory((PVOID
)((ULONG
)NlsSectionBase
+ NlsOemTableOffset
),
180 NlsOemCodePageTableSize
);
182 NlsUnicodeTableOffset
= NlsOemTableOffset
+ ROUND_UP(NlsOemCodePageTableSize
, PAGE_SIZE
);
183 RtlCopyMemory((PVOID
)((ULONG
)NlsSectionBase
+ NlsUnicodeTableOffset
),
184 NlsUnicodeCasemapTable
,
185 NlsUnicodeCasemapTableSize
);
187 RtlInitNlsTables ((PVOID
)((ULONG
)NlsSectionBase
+ NlsAnsiTableOffset
),
188 (PVOID
)((ULONG
)NlsSectionBase
+ NlsOemTableOffset
),
189 (PVOID
)((ULONG
)NlsSectionBase
+ NlsUnicodeTableOffset
),
192 RtlResetRtlTranslations (&NlsTable
);
200 RtlCustomCPToUnicodeN(IN PCPTABLEINFO CustomCP
,
201 PWCHAR UnicodeString
,
210 if (CustomCP
->DBCSCodePage
== 0)
212 /* single-byte code page */
213 if (CustomSize
> (UnicodeSize
/ sizeof(WCHAR
)))
214 Size
= UnicodeSize
/ sizeof(WCHAR
);
218 if (ResultSize
!= NULL
)
219 *ResultSize
= Size
* sizeof(WCHAR
);
221 for (i
= 0; i
< Size
; i
++)
223 *UnicodeString
= CustomCP
->MultiByteTable
[(unsigned int)*CustomString
];
230 /* multi-byte code page */
234 return(STATUS_SUCCESS
);
239 RtlDowncaseUnicodeChar (IN WCHAR Source
)
247 return Source
+ (L
'a' - L
'A');
252 Offset
= ((USHORT
)Source
>> 8);
253 Offset
= NlsUnicodeLowercaseTable
[Offset
];
255 Offset
+= (((USHORT
)Source
& 0x00F0) >> 4);
256 Offset
= NlsUnicodeLowercaseTable
[Offset
];
258 Offset
+= ((USHORT
)Source
& 0x000F);
259 Offset
= NlsUnicodeLowercaseTable
[Offset
];
261 return Source
+ (SHORT
)Offset
;
269 RtlGetDefaultCodePage(PUSHORT AnsiCodePage
,
272 *AnsiCodePage
= NlsAnsiCodePage
;
273 *OemCodePage
= NlsOemCodePage
;
281 RtlInitCodePageTable(IN PUSHORT TableBase
,
282 OUT PCPTABLEINFO CodePageTable
)
284 PNLS_FILE_HEADER NlsFileHeader
;
288 DPRINT("RtlInitCodePageTable() called\n");
290 NlsFileHeader
= (PNLS_FILE_HEADER
)TableBase
;
292 CodePageTable
->CodePage
= NlsFileHeader
->CodePage
;
293 CodePageTable
->MaximumCharacterSize
= NlsFileHeader
->MaximumCharacterSize
;
294 CodePageTable
->DefaultChar
= NlsFileHeader
->DefaultChar
;
295 CodePageTable
->UniDefaultChar
= NlsFileHeader
->UniDefaultChar
;
296 CodePageTable
->TransDefaultChar
= NlsFileHeader
->TransDefaultChar
;
297 CodePageTable
->TransUniDefaultChar
= NlsFileHeader
->TransUniDefaultChar
;
299 RtlCopyMemory(&CodePageTable
->LeadByte
,
300 &NlsFileHeader
->LeadByte
,
303 /* Set Pointer to start of multi byte table */
304 Ptr
= (PUSHORT
)((ULONG_PTR
)TableBase
+ 2 * NlsFileHeader
->HeaderSize
);
306 /* Get offset to the wide char table */
307 Offset
= (USHORT
)(*Ptr
++) + NlsFileHeader
->HeaderSize
+ 1;
309 /* Set pointer to the multi byte table */
310 CodePageTable
->MultiByteTable
= Ptr
;
312 /* Skip ANSI and OEM table */
317 /* Set pointer to DBCS ranges */
318 CodePageTable
->DBCSRanges
= (PUSHORT
)Ptr
;
322 CodePageTable
->DBCSCodePage
= 1;
323 CodePageTable
->DBCSOffsets
= (PUSHORT
)++Ptr
;
327 CodePageTable
->DBCSCodePage
= 0;
328 CodePageTable
->DBCSOffsets
= 0;
331 CodePageTable
->WideCharTable
= (PVOID
)((ULONG_PTR
)TableBase
+ 2 * Offset
);
336 RtlInitNlsTables(IN PUSHORT AnsiTableBase
,
337 IN PUSHORT OemTableBase
,
338 IN PUSHORT CaseTableBase
,
339 OUT PNLSTABLEINFO NlsTable
)
341 DPRINT("RtlInitNlsTables()called\n");
343 RtlInitCodePageTable (AnsiTableBase
,
344 &NlsTable
->AnsiTableInfo
);
346 RtlInitCodePageTable (OemTableBase
,
347 &NlsTable
->OemTableInfo
);
349 NlsTable
->UpperCaseTable
= (PUSHORT
)CaseTableBase
+ 2;
350 NlsTable
->LowerCaseTable
= (PUSHORT
)CaseTableBase
+ *((PUSHORT
)CaseTableBase
+ 1) + 2;
358 RtlMultiByteToUnicodeN(PWCHAR UnicodeString
,
367 if (NlsMbCodePageTag
== FALSE
)
369 /* single-byte code page */
370 if (MbSize
> (UnicodeSize
/ sizeof(WCHAR
)))
371 Size
= UnicodeSize
/ sizeof(WCHAR
);
375 if (ResultSize
!= NULL
)
376 *ResultSize
= Size
* sizeof(WCHAR
);
378 for (i
= 0; i
< Size
; i
++)
380 *UnicodeString
= NlsAnsiToUnicodeTable
[(unsigned int)*MbString
];
387 /* multi-byte code page */
391 return(STATUS_SUCCESS
);
399 RtlMultiByteToUnicodeSize(PULONG UnicodeSize
,
403 if (NlsMbCodePageTag
== FALSE
)
405 /* single-byte code page */
406 *UnicodeSize
= MbSize
* sizeof (WCHAR
);
410 /* multi-byte code page */
414 return(STATUS_SUCCESS
);
422 RtlOemToUnicodeN(PWCHAR UnicodeString
,
431 if (NlsMbOemCodePageTag
== FALSE
)
433 /* single-byte code page */
434 if (OemSize
> (UnicodeSize
/ sizeof(WCHAR
)))
435 Size
= UnicodeSize
/ sizeof(WCHAR
);
439 if (ResultSize
!= NULL
)
440 *ResultSize
= Size
* sizeof(WCHAR
);
442 for (i
= 0; i
< Size
; i
++)
444 *UnicodeString
= NlsOemToUnicodeTable
[(unsigned int)*OemString
];
451 /* multi-byte code page */
455 return(STATUS_SUCCESS
);
460 RtlResetRtlTranslations(IN PNLSTABLEINFO NlsTable
)
462 DPRINT("RtlResetRtlTranslations() called\n");
465 NlsAnsiToUnicodeTable
= NlsTable
->AnsiTableInfo
.MultiByteTable
;
466 NlsUnicodeToAnsiTable
= NlsTable
->AnsiTableInfo
.WideCharTable
;
467 NlsDbcsUnicodeToAnsiTable
= (PWCHAR
)NlsTable
->AnsiTableInfo
.WideCharTable
;
468 NlsMbCodePageTag
= (NlsTable
->AnsiTableInfo
.DBCSCodePage
!= 0);
469 NlsLeadByteInfo
= NlsTable
->AnsiTableInfo
.DBCSOffsets
;
470 NlsAnsiCodePage
= NlsTable
->AnsiTableInfo
.CodePage
;
471 DPRINT("Ansi codepage %hu\n", NlsAnsiCodePage
);
474 NlsOemToUnicodeTable
= NlsTable
->OemTableInfo
.MultiByteTable
;
475 NlsUnicodeToOemTable
= NlsTable
->OemTableInfo
.WideCharTable
;
476 NlsDbcsUnicodeToOemTable
= (PWCHAR
)NlsTable
->OemTableInfo
.WideCharTable
;
477 NlsMbOemCodePageTag
= (NlsTable
->OemTableInfo
.DBCSCodePage
!= 0);
478 NlsOemLeadByteInfo
= NlsTable
->OemTableInfo
.DBCSOffsets
;
479 NlsOemCodePage
= NlsTable
->OemTableInfo
.CodePage
;
480 DPRINT("Oem codepage %hu\n", NlsOemCodePage
);
482 /* Set Unicode case map data */
483 NlsUnicodeUpcaseTable
= NlsTable
->UpperCaseTable
;
484 NlsUnicodeLowercaseTable
= NlsTable
->LowerCaseTable
;
492 RtlUnicodeToCustomCPN(IN PCPTABLEINFO CustomCP
,
496 PWCHAR UnicodeString
,
502 if (CustomCP
->DBCSCodePage
== 0)
504 /* single-byte code page */
505 if (UnicodeSize
> (CustomSize
* sizeof(WCHAR
)))
508 Size
= UnicodeSize
/ sizeof(WCHAR
);
510 if (ResultSize
!= NULL
)
513 for (i
= 0; i
< Size
; i
++)
515 *CustomString
= ((PCHAR
)CustomCP
->WideCharTable
)[(unsigned int)*UnicodeString
];
522 /* multi-byte code page */
526 return(STATUS_SUCCESS
);
535 RtlUnicodeToMultiByteN(PCHAR MbString
,
538 PWCHAR UnicodeString
,
544 if (NlsMbCodePageTag
== FALSE
)
546 /* single-byte code page */
547 if (UnicodeSize
> (MbSize
* sizeof(WCHAR
)))
550 Size
= UnicodeSize
/ sizeof(WCHAR
);
552 if (ResultSize
!= NULL
)
555 for (i
= 0; i
< Size
; i
++)
557 *MbString
= NlsUnicodeToAnsiTable
[(unsigned int)*UnicodeString
];
564 /* multi-byte code page */
568 return(STATUS_SUCCESS
);
576 RtlUnicodeToMultiByteSize(PULONG MbSize
,
577 PWCHAR UnicodeString
,
583 if (NlsMbCodePageTag
== FALSE
)
585 /* single-byte code page */
586 *MbSize
= UnicodeSize
/ sizeof (WCHAR
);
590 /* multi-byte code page */
591 UnicodeLength
= UnicodeSize
/ sizeof(WCHAR
);
593 while (UnicodeLength
> 0)
595 if (NlsLeadByteInfo
[*UnicodeString
] & 0xff00)
606 return(STATUS_SUCCESS
);
614 RtlUnicodeToOemN(PCHAR OemString
,
617 PWCHAR UnicodeString
,
623 if (NlsMbOemCodePageTag
== FALSE
)
625 /* single-byte code page */
626 if (UnicodeSize
> (OemSize
* sizeof(WCHAR
)))
629 Size
= UnicodeSize
/ sizeof(WCHAR
);
631 if (ResultSize
!= NULL
)
634 for (i
= 0; i
< Size
; i
++)
636 *OemString
= NlsUnicodeToOemTable
[(unsigned int)*UnicodeString
];
643 /* multi-byte code page */
647 return(STATUS_SUCCESS
);
655 RtlUpcaseUnicodeChar(IN WCHAR Source
)
663 return (Source
- (L
'a' - L
'A'));
665 Offset
= ((USHORT
)Source
>> 8);
666 Offset
= NlsUnicodeUpcaseTable
[Offset
];
668 Offset
+= (((USHORT
)Source
& 0x00F0) >> 4);
669 Offset
= NlsUnicodeUpcaseTable
[Offset
];
671 Offset
+= ((USHORT
)Source
& 0x000F);
672 Offset
= NlsUnicodeUpcaseTable
[Offset
];
674 return Source
+ (SHORT
)Offset
;
682 RtlUpcaseUnicodeToCustomCPN(IN PCPTABLEINFO CustomCP
,
686 PWCHAR UnicodeString
,
693 if (CustomCP
->DBCSCodePage
== 0)
695 /* single-byte code page */
696 if (UnicodeSize
> (CustomSize
* sizeof(WCHAR
)))
699 Size
= UnicodeSize
/ sizeof(WCHAR
);
701 if (ResultSize
!= NULL
)
704 for (i
= 0; i
< Size
; i
++)
706 wc
= RtlUpcaseUnicodeChar(*UnicodeString
);
707 *CustomString
= ((PCHAR
)CustomCP
->WideCharTable
)[(unsigned int)wc
];
714 /* multi-byte code page */
718 return(STATUS_SUCCESS
);
726 RtlUpcaseUnicodeToMultiByteN(PCHAR MbString
,
729 PWCHAR UnicodeString
,
736 if (NlsMbCodePageTag
== FALSE
)
738 /* single-byte code page */
739 if (UnicodeSize
> (MbSize
* sizeof(WCHAR
)))
742 Size
= UnicodeSize
/ sizeof(WCHAR
);
744 if (ResultSize
!= NULL
)
747 for (i
= 0; i
< Size
; i
++)
749 wc
= RtlUpcaseUnicodeChar(*UnicodeString
);
750 *MbString
= NlsUnicodeToAnsiTable
[(unsigned int)wc
];
757 /* multi-byte code page */
761 return(STATUS_SUCCESS
);
769 RtlUpcaseUnicodeToOemN(PCHAR OemString
,
772 PWCHAR UnicodeString
,
779 if (NlsMbOemCodePageTag
== FALSE
)
781 /* single-byte code page */
782 if (UnicodeSize
> (OemSize
* sizeof(WCHAR
)))
785 Size
= UnicodeSize
/ sizeof(WCHAR
);
787 if (ResultSize
!= NULL
)
790 for (i
= 0; i
< Size
; i
++)
792 wc
= RtlUpcaseUnicodeChar(*UnicodeString
);
793 *OemString
= NlsUnicodeToOemTable
[(unsigned int)wc
];
800 /* multi-byte code page */
804 return(STATUS_SUCCESS
);
812 RtlUpperChar (IN CHAR Source
)
817 if (NlsMbCodePageTag
== FALSE
)
819 /* single-byte code page */
822 Unicode
= NlsAnsiToUnicodeTable
[(unsigned int)Source
];
824 /* upcase conversion */
825 Unicode
= RtlUpcaseUnicodeChar (Unicode
);
827 /* unicode -> ansi */
828 Destination
= NlsUnicodeToAnsiTable
[(unsigned int)Unicode
];
832 /* multi-byte code page */
834 Destination
= Source
;