1 /* $Id: nls.c,v 1.16 2003/06/17 10:44:16 ekohl 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
);
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
;
263 RtlGetDefaultCodePage(PUSHORT AnsiCodePage
,
266 *AnsiCodePage
= NlsAnsiCodePage
;
267 *OemCodePage
= NlsOemCodePage
;
272 RtlInitCodePageTable(IN PUSHORT TableBase
,
273 OUT PCPTABLEINFO CodePageTable
)
275 PNLS_FILE_HEADER NlsFileHeader
;
279 DPRINT("RtlInitCodePageTable() called\n");
281 NlsFileHeader
= (PNLS_FILE_HEADER
)TableBase
;
283 CodePageTable
->CodePage
= NlsFileHeader
->CodePage
;
284 CodePageTable
->MaximumCharacterSize
= NlsFileHeader
->MaximumCharacterSize
;
285 CodePageTable
->DefaultChar
= NlsFileHeader
->DefaultChar
;
286 CodePageTable
->UniDefaultChar
= NlsFileHeader
->UniDefaultChar
;
287 CodePageTable
->TransDefaultChar
= NlsFileHeader
->TransDefaultChar
;
288 CodePageTable
->TransUniDefaultChar
= NlsFileHeader
->TransUniDefaultChar
;
290 RtlCopyMemory(&CodePageTable
->LeadByte
,
291 &NlsFileHeader
->LeadByte
,
294 /* Set Pointer to start of multi byte table */
295 Ptr
= (PUSHORT
)((ULONG_PTR
)TableBase
+ 2 * NlsFileHeader
->HeaderSize
);
297 /* Get offset to the wide char table */
298 Offset
= (USHORT
)(*Ptr
++) + NlsFileHeader
->HeaderSize
+ 1;
300 /* Set pointer to the multi byte table */
301 CodePageTable
->MultiByteTable
= Ptr
;
303 /* Skip ANSI and OEM table */
308 /* Set pointer to DBCS ranges */
309 CodePageTable
->DBCSRanges
= (PUSHORT
)Ptr
;
313 CodePageTable
->DBCSCodePage
= 1;
314 CodePageTable
->DBCSOffsets
= (PUSHORT
)++Ptr
;
318 CodePageTable
->DBCSCodePage
= 0;
319 CodePageTable
->DBCSOffsets
= 0;
322 CodePageTable
->WideCharTable
= (PVOID
)((ULONG_PTR
)TableBase
+ 2 * Offset
);
327 RtlInitNlsTables(IN PUSHORT AnsiTableBase
,
328 IN PUSHORT OemTableBase
,
329 IN PUSHORT CaseTableBase
,
330 OUT PNLSTABLEINFO NlsTable
)
332 DPRINT("RtlInitNlsTables()called\n");
334 RtlInitCodePageTable (AnsiTableBase
,
335 &NlsTable
->AnsiTableInfo
);
337 RtlInitCodePageTable (OemTableBase
,
338 &NlsTable
->OemTableInfo
);
340 NlsTable
->UpperCaseTable
= (PUSHORT
)CaseTableBase
+ 2;
341 NlsTable
->LowerCaseTable
= (PUSHORT
)CaseTableBase
+ *((PUSHORT
)CaseTableBase
+ 1) + 2;
346 RtlMultiByteToUnicodeN(PWCHAR UnicodeString
,
355 if (NlsMbCodePageTag
== FALSE
)
357 /* single-byte code page */
358 if (MbSize
> (UnicodeSize
/ sizeof(WCHAR
)))
359 Size
= UnicodeSize
/ sizeof(WCHAR
);
363 if (ResultSize
!= NULL
)
364 *ResultSize
= Size
* sizeof(WCHAR
);
366 for (i
= 0; i
< Size
; i
++)
368 *UnicodeString
= NlsAnsiToUnicodeTable
[(unsigned int)*MbString
];
375 /* multi-byte code page */
379 return(STATUS_SUCCESS
);
384 RtlMultiByteToUnicodeSize(PULONG UnicodeSize
,
388 if (NlsMbCodePageTag
== FALSE
)
390 /* single-byte code page */
391 *UnicodeSize
= MbSize
* sizeof (WCHAR
);
395 /* multi-byte code page */
399 return(STATUS_SUCCESS
);
404 RtlOemToUnicodeN(PWCHAR UnicodeString
,
413 if (NlsMbOemCodePageTag
== FALSE
)
415 /* single-byte code page */
416 if (OemSize
> (UnicodeSize
/ sizeof(WCHAR
)))
417 Size
= UnicodeSize
/ sizeof(WCHAR
);
421 if (ResultSize
!= NULL
)
422 *ResultSize
= Size
* sizeof(WCHAR
);
424 for (i
= 0; i
< Size
; i
++)
426 *UnicodeString
= NlsOemToUnicodeTable
[(unsigned int)*OemString
];
433 /* multi-byte code page */
437 return(STATUS_SUCCESS
);
442 RtlResetRtlTranslations(IN PNLSTABLEINFO NlsTable
)
444 DPRINT("RtlResetRtlTranslations() called\n");
447 NlsAnsiToUnicodeTable
= NlsTable
->AnsiTableInfo
.MultiByteTable
;
448 NlsUnicodeToAnsiTable
= NlsTable
->AnsiTableInfo
.WideCharTable
;
449 NlsDbcsUnicodeToAnsiTable
= (PWCHAR
)NlsTable
->AnsiTableInfo
.WideCharTable
;
450 NlsMbCodePageTag
= (NlsTable
->AnsiTableInfo
.DBCSCodePage
!= 0);
451 NlsLeadByteInfo
= NlsTable
->AnsiTableInfo
.DBCSOffsets
;
452 NlsAnsiCodePage
= NlsTable
->AnsiTableInfo
.CodePage
;
453 DPRINT("Ansi codepage %hu\n", NlsAnsiCodePage
);
456 NlsOemToUnicodeTable
= NlsTable
->OemTableInfo
.MultiByteTable
;
457 NlsUnicodeToOemTable
= NlsTable
->OemTableInfo
.WideCharTable
;
458 NlsDbcsUnicodeToOemTable
= (PWCHAR
)NlsTable
->OemTableInfo
.WideCharTable
;
459 NlsMbOemCodePageTag
= (NlsTable
->OemTableInfo
.DBCSCodePage
!= 0);
460 NlsOemLeadByteInfo
= NlsTable
->OemTableInfo
.DBCSOffsets
;
461 NlsOemCodePage
= NlsTable
->OemTableInfo
.CodePage
;
462 DPRINT("Oem codepage %hu\n", NlsOemCodePage
);
464 /* Set Unicode case map data */
465 NlsUnicodeUpcaseTable
= NlsTable
->UpperCaseTable
;
466 NlsUnicodeLowercaseTable
= NlsTable
->LowerCaseTable
;
471 RtlUnicodeToCustomCPN(IN PCPTABLEINFO CustomCP
,
475 PWCHAR UnicodeString
,
481 if (CustomCP
->DBCSCodePage
== 0)
483 /* single-byte code page */
484 if (UnicodeSize
> (CustomSize
* sizeof(WCHAR
)))
487 Size
= UnicodeSize
/ sizeof(WCHAR
);
489 if (ResultSize
!= NULL
)
492 for (i
= 0; i
< Size
; i
++)
494 *CustomString
= ((PCHAR
)CustomCP
->WideCharTable
)[(unsigned int)*UnicodeString
];
501 /* multi-byte code page */
505 return(STATUS_SUCCESS
);
511 RtlUnicodeToMultiByteN(PCHAR MbString
,
514 PWCHAR UnicodeString
,
520 if (NlsMbCodePageTag
== FALSE
)
522 /* single-byte code page */
523 if (UnicodeSize
> (MbSize
* sizeof(WCHAR
)))
526 Size
= UnicodeSize
/ sizeof(WCHAR
);
528 if (ResultSize
!= NULL
)
531 for (i
= 0; i
< Size
; i
++)
533 *MbString
= NlsUnicodeToAnsiTable
[(unsigned int)*UnicodeString
];
540 /* multi-byte code page */
544 return(STATUS_SUCCESS
);
549 RtlUnicodeToMultiByteSize(PULONG MbSize
,
550 PWCHAR UnicodeString
,
556 if (NlsMbCodePageTag
== FALSE
)
558 /* single-byte code page */
559 *MbSize
= UnicodeSize
/ sizeof (WCHAR
);
563 /* multi-byte code page */
564 UnicodeLength
= UnicodeSize
/ sizeof(WCHAR
);
566 while (UnicodeLength
> 0)
568 if (NlsLeadByteInfo
[*UnicodeString
] & 0xff00)
579 return(STATUS_SUCCESS
);
584 RtlUnicodeToOemN(PCHAR OemString
,
587 PWCHAR UnicodeString
,
593 if (NlsMbOemCodePageTag
== FALSE
)
595 /* single-byte code page */
596 if (UnicodeSize
> (OemSize
* sizeof(WCHAR
)))
599 Size
= UnicodeSize
/ sizeof(WCHAR
);
601 if (ResultSize
!= NULL
)
604 for (i
= 0; i
< Size
; i
++)
606 *OemString
= NlsUnicodeToOemTable
[(unsigned int)*UnicodeString
];
613 /* multi-byte code page */
617 return(STATUS_SUCCESS
);
622 RtlUpcaseUnicodeChar(IN WCHAR Source
)
630 return (Source
- (L
'a' - L
'A'));
632 Offset
= ((USHORT
)Source
>> 8);
633 Offset
= NlsUnicodeUpcaseTable
[Offset
];
635 Offset
+= (((USHORT
)Source
& 0x00F0) >> 4);
636 Offset
= NlsUnicodeUpcaseTable
[Offset
];
638 Offset
+= ((USHORT
)Source
& 0x000F);
639 Offset
= NlsUnicodeUpcaseTable
[Offset
];
641 return Source
+ (SHORT
)Offset
;
646 RtlUpcaseUnicodeToCustomCPN(IN PCPTABLEINFO CustomCP
,
650 PWCHAR UnicodeString
,
657 if (CustomCP
->DBCSCodePage
== 0)
659 /* single-byte code page */
660 if (UnicodeSize
> (CustomSize
* sizeof(WCHAR
)))
663 Size
= UnicodeSize
/ sizeof(WCHAR
);
665 if (ResultSize
!= NULL
)
668 for (i
= 0; i
< Size
; i
++)
670 wc
= RtlUpcaseUnicodeChar(*UnicodeString
);
671 *CustomString
= ((PCHAR
)CustomCP
->WideCharTable
)[(unsigned int)wc
];
678 /* multi-byte code page */
682 return(STATUS_SUCCESS
);
687 RtlUpcaseUnicodeToMultiByteN(PCHAR MbString
,
690 PWCHAR UnicodeString
,
697 if (NlsMbCodePageTag
== FALSE
)
699 /* single-byte code page */
700 if (UnicodeSize
> (MbSize
* sizeof(WCHAR
)))
703 Size
= UnicodeSize
/ sizeof(WCHAR
);
705 if (ResultSize
!= NULL
)
708 for (i
= 0; i
< Size
; i
++)
710 wc
= RtlUpcaseUnicodeChar(*UnicodeString
);
711 *MbString
= NlsUnicodeToAnsiTable
[(unsigned int)wc
];
718 /* multi-byte code page */
722 return(STATUS_SUCCESS
);
727 RtlUpcaseUnicodeToOemN(PCHAR OemString
,
730 PWCHAR UnicodeString
,
737 if (NlsMbOemCodePageTag
== FALSE
)
739 /* single-byte code page */
740 if (UnicodeSize
> (OemSize
* sizeof(WCHAR
)))
743 Size
= UnicodeSize
/ sizeof(WCHAR
);
745 if (ResultSize
!= NULL
)
748 for (i
= 0; i
< Size
; i
++)
750 wc
= RtlUpcaseUnicodeChar(*UnicodeString
);
751 *OemString
= NlsUnicodeToOemTable
[(unsigned int)wc
];
758 /* multi-byte code page */
762 return(STATUS_SUCCESS
);
767 RtlUpperChar (IN CHAR Source
)
772 if (NlsMbCodePageTag
== FALSE
)
774 /* single-byte code page */
777 Unicode
= NlsAnsiToUnicodeTable
[(unsigned int)Source
];
779 /* upcase conversion */
780 Unicode
= RtlUpcaseUnicodeChar (Unicode
);
782 /* unicode -> ansi */
783 Destination
= NlsUnicodeToAnsiTable
[(unsigned int)Unicode
];
787 /* multi-byte code page */
789 Destination
= Source
;