1 /* $Id: nls.c,v 1.19 2003/07/29 16:44:48 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
,
361 const PCHAR MbString
,
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
++)
379 UnicodeString
[i
] = NlsAnsiToUnicodeTable
[(unsigned int)MbString
[i
]];
383 /* multi-byte code page */
387 return(STATUS_SUCCESS
);
395 RtlMultiByteToUnicodeSize(PULONG UnicodeSize
,
399 if (NlsMbCodePageTag
== FALSE
)
401 /* single-byte code page */
402 *UnicodeSize
= MbSize
* sizeof (WCHAR
);
406 /* multi-byte code page */
410 return(STATUS_SUCCESS
);
418 RtlOemToUnicodeN(PWCHAR UnicodeString
,
427 if (NlsMbOemCodePageTag
== FALSE
)
429 /* single-byte code page */
430 if (OemSize
> (UnicodeSize
/ sizeof(WCHAR
)))
431 Size
= UnicodeSize
/ sizeof(WCHAR
);
435 if (ResultSize
!= NULL
)
436 *ResultSize
= Size
* sizeof(WCHAR
);
438 for (i
= 0; i
< Size
; i
++)
440 *UnicodeString
= NlsOemToUnicodeTable
[(unsigned int)*OemString
];
447 /* multi-byte code page */
451 return(STATUS_SUCCESS
);
456 RtlResetRtlTranslations(IN PNLSTABLEINFO NlsTable
)
458 DPRINT("RtlResetRtlTranslations() called\n");
461 NlsAnsiToUnicodeTable
= NlsTable
->AnsiTableInfo
.MultiByteTable
;
462 NlsUnicodeToAnsiTable
= NlsTable
->AnsiTableInfo
.WideCharTable
;
463 NlsDbcsUnicodeToAnsiTable
= (PWCHAR
)NlsTable
->AnsiTableInfo
.WideCharTable
;
464 NlsMbCodePageTag
= (NlsTable
->AnsiTableInfo
.DBCSCodePage
!= 0);
465 NlsLeadByteInfo
= NlsTable
->AnsiTableInfo
.DBCSOffsets
;
466 NlsAnsiCodePage
= NlsTable
->AnsiTableInfo
.CodePage
;
467 DPRINT("Ansi codepage %hu\n", NlsAnsiCodePage
);
470 NlsOemToUnicodeTable
= NlsTable
->OemTableInfo
.MultiByteTable
;
471 NlsUnicodeToOemTable
= NlsTable
->OemTableInfo
.WideCharTable
;
472 NlsDbcsUnicodeToOemTable
= (PWCHAR
)NlsTable
->OemTableInfo
.WideCharTable
;
473 NlsMbOemCodePageTag
= (NlsTable
->OemTableInfo
.DBCSCodePage
!= 0);
474 NlsOemLeadByteInfo
= NlsTable
->OemTableInfo
.DBCSOffsets
;
475 NlsOemCodePage
= NlsTable
->OemTableInfo
.CodePage
;
476 DPRINT("Oem codepage %hu\n", NlsOemCodePage
);
478 /* Set Unicode case map data */
479 NlsUnicodeUpcaseTable
= NlsTable
->UpperCaseTable
;
480 NlsUnicodeLowercaseTable
= NlsTable
->LowerCaseTable
;
488 RtlUnicodeToCustomCPN(IN PCPTABLEINFO CustomCP
,
492 PWCHAR UnicodeString
,
498 if (CustomCP
->DBCSCodePage
== 0)
500 /* single-byte code page */
501 if (UnicodeSize
> (CustomSize
* sizeof(WCHAR
)))
504 Size
= UnicodeSize
/ sizeof(WCHAR
);
506 if (ResultSize
!= NULL
)
509 for (i
= 0; i
< Size
; i
++)
511 *CustomString
= ((PCHAR
)CustomCP
->WideCharTable
)[(unsigned int)*UnicodeString
];
518 /* multi-byte code page */
522 return(STATUS_SUCCESS
);
531 RtlUnicodeToMultiByteN(PCHAR MbString
,
534 PWCHAR UnicodeString
,
540 if (NlsMbCodePageTag
== FALSE
)
542 /* single-byte code page */
543 if (UnicodeSize
> (MbSize
* sizeof(WCHAR
)))
546 Size
= UnicodeSize
/ sizeof(WCHAR
);
548 if (ResultSize
!= NULL
)
551 for (i
= 0; i
< Size
; i
++)
553 *MbString
= NlsUnicodeToAnsiTable
[(unsigned int)*UnicodeString
];
560 /* multi-byte code page */
564 return(STATUS_SUCCESS
);
572 RtlUnicodeToMultiByteSize(PULONG MbSize
,
573 PWCHAR UnicodeString
,
579 if (NlsMbCodePageTag
== FALSE
)
581 /* single-byte code page */
582 *MbSize
= UnicodeSize
/ sizeof (WCHAR
);
586 /* multi-byte code page */
587 UnicodeLength
= UnicodeSize
/ sizeof(WCHAR
);
589 while (UnicodeLength
> 0)
591 if (NlsLeadByteInfo
[*UnicodeString
] & 0xff00)
602 return(STATUS_SUCCESS
);
610 RtlUnicodeToOemN(PCHAR OemString
,
613 PWCHAR UnicodeString
,
619 if (NlsMbOemCodePageTag
== FALSE
)
621 /* single-byte code page */
622 if (UnicodeSize
> (OemSize
* sizeof(WCHAR
)))
625 Size
= UnicodeSize
/ sizeof(WCHAR
);
627 if (ResultSize
!= NULL
)
630 for (i
= 0; i
< Size
; i
++)
632 *OemString
= NlsUnicodeToOemTable
[(unsigned int)*UnicodeString
];
639 /* multi-byte code page */
643 return(STATUS_SUCCESS
);
651 RtlUpcaseUnicodeChar(IN WCHAR Source
)
659 return (Source
- (L
'a' - L
'A'));
661 Offset
= ((USHORT
)Source
>> 8);
662 Offset
= NlsUnicodeUpcaseTable
[Offset
];
664 Offset
+= (((USHORT
)Source
& 0x00F0) >> 4);
665 Offset
= NlsUnicodeUpcaseTable
[Offset
];
667 Offset
+= ((USHORT
)Source
& 0x000F);
668 Offset
= NlsUnicodeUpcaseTable
[Offset
];
670 return Source
+ (SHORT
)Offset
;
678 RtlUpcaseUnicodeToCustomCPN(IN PCPTABLEINFO CustomCP
,
682 PWCHAR UnicodeString
,
689 if (CustomCP
->DBCSCodePage
== 0)
691 /* single-byte code page */
692 if (UnicodeSize
> (CustomSize
* sizeof(WCHAR
)))
695 Size
= UnicodeSize
/ sizeof(WCHAR
);
697 if (ResultSize
!= NULL
)
700 for (i
= 0; i
< Size
; i
++)
702 wc
= RtlUpcaseUnicodeChar(*UnicodeString
);
703 *CustomString
= ((PCHAR
)CustomCP
->WideCharTable
)[(unsigned int)wc
];
710 /* multi-byte code page */
714 return(STATUS_SUCCESS
);
722 RtlUpcaseUnicodeToMultiByteN(PCHAR MbString
,
725 PWCHAR UnicodeString
,
732 if (NlsMbCodePageTag
== FALSE
)
734 /* single-byte code page */
735 if (UnicodeSize
> (MbSize
* sizeof(WCHAR
)))
738 Size
= UnicodeSize
/ sizeof(WCHAR
);
740 if (ResultSize
!= NULL
)
743 for (i
= 0; i
< Size
; i
++)
745 wc
= RtlUpcaseUnicodeChar(*UnicodeString
);
746 *MbString
= NlsUnicodeToAnsiTable
[(unsigned int)wc
];
753 /* multi-byte code page */
757 return(STATUS_SUCCESS
);
765 RtlUpcaseUnicodeToOemN(PCHAR OemString
,
768 PWCHAR UnicodeString
,
775 if (NlsMbOemCodePageTag
== FALSE
)
777 /* single-byte code page */
778 if (UnicodeSize
> (OemSize
* sizeof(WCHAR
)))
781 Size
= UnicodeSize
/ sizeof(WCHAR
);
783 if (ResultSize
!= NULL
)
786 for (i
= 0; i
< Size
; i
++)
788 wc
= RtlUpcaseUnicodeChar(*UnicodeString
);
789 *OemString
= NlsUnicodeToOemTable
[(unsigned int)wc
];
796 /* multi-byte code page */
800 return(STATUS_SUCCESS
);
808 RtlUpperChar (IN CHAR Source
)
813 if (NlsMbCodePageTag
== FALSE
)
815 /* single-byte code page */
818 Unicode
= NlsAnsiToUnicodeTable
[(unsigned int)Source
];
820 /* upcase conversion */
821 Unicode
= RtlUpcaseUnicodeChar (Unicode
);
823 /* unicode -> ansi */
824 Destination
= NlsUnicodeToAnsiTable
[(unsigned int)Unicode
];
828 /* multi-byte code page */
830 Destination
= Source
;