2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS system libraries
5 * PURPOSE: National Language Support (NLS) functions
6 * PROGRAMMERS: Emanuele Aliberti
9 /* INCLUDES *****************************************************************/
16 /* GLOBALS *******************************************************************/
18 PUSHORT NlsUnicodeUpcaseTable
= NULL
;
19 PUSHORT NlsUnicodeLowercaseTable
= NULL
;
21 USHORT NlsAnsiCodePage
= 0; /* exported */
22 BOOLEAN NlsMbCodePageTag
= FALSE
; /* exported */
23 PWCHAR NlsAnsiToUnicodeTable
= NULL
;
24 PCHAR NlsUnicodeToAnsiTable
= NULL
;
25 PWCHAR NlsDbcsUnicodeToAnsiTable
= NULL
;
26 PUSHORT NlsLeadByteInfo
= NULL
; /* exported */
29 USHORT NlsOemCodePage
= 0;
30 BOOLEAN NlsMbOemCodePageTag
= FALSE
; /* exported */
31 PWCHAR NlsOemToUnicodeTable
= NULL
;
32 PCHAR NlsUnicodeToOemTable
=NULL
;
33 PWCHAR NlsDbcsUnicodeToOemTable
= NULL
;
34 PUSHORT NlsOemLeadByteInfo
= NULL
; /* exported */
36 USHORT NlsOemDefaultChar
= '\0';
37 USHORT NlsUnicodeDefaultChar
= 0;
42 /* FUNCTIONS *****************************************************************/
48 RtlCustomCPToUnicodeN(IN PCPTABLEINFO CustomCP
,
58 if (CustomCP
->DBCSCodePage
== 0)
60 /* single-byte code page */
61 if (CustomSize
> (UnicodeSize
/ sizeof(WCHAR
)))
62 Size
= UnicodeSize
/ sizeof(WCHAR
);
66 if (ResultSize
!= NULL
)
67 *ResultSize
= Size
* sizeof(WCHAR
);
69 for (i
= 0; i
< Size
; i
++)
71 *UnicodeString
= CustomCP
->MultiByteTable
[(UCHAR
)*CustomString
];
78 /* multi-byte code page */
83 return(STATUS_SUCCESS
);
89 RtlDowncaseUnicodeChar (IN WCHAR Source
)
97 return Source
+ (L
'a' - L
'A');
102 Offset
= ((USHORT
)Source
>> 8);
103 DPRINT("Offset: %hx\n", Offset
);
105 Offset
= NlsUnicodeLowercaseTable
[Offset
];
106 DPRINT("Offset: %hx\n", Offset
);
108 Offset
+= (((USHORT
)Source
& 0x00F0) >> 4);
109 DPRINT("Offset: %hx\n", Offset
);
111 Offset
= NlsUnicodeLowercaseTable
[Offset
];
112 DPRINT("Offset: %hx\n", Offset
);
114 Offset
+= ((USHORT
)Source
& 0x000F);
115 DPRINT("Offset: %hx\n", Offset
);
117 Offset
= NlsUnicodeLowercaseTable
[Offset
];
118 DPRINT("Offset: %hx\n", Offset
);
120 DPRINT("Result: %hx\n", Source
+ (SHORT
)Offset
);
122 return Source
+ (SHORT
)Offset
;
132 RtlGetDefaultCodePage(OUT PUSHORT AnsiCodePage
,
133 OUT PUSHORT OemCodePage
)
135 *AnsiCodePage
= NlsAnsiCodePage
;
136 *OemCodePage
= NlsOemCodePage
;
146 RtlInitCodePageTable(IN PUSHORT TableBase
,
147 OUT PCPTABLEINFO CodePageTable
)
149 PNLS_FILE_HEADER NlsFileHeader
;
151 DPRINT("RtlInitCodePageTable() called\n");
153 NlsFileHeader
= (PNLS_FILE_HEADER
)TableBase
;
155 /* Copy header fields first */
156 CodePageTable
->CodePage
= NlsFileHeader
->CodePage
;
157 CodePageTable
->MaximumCharacterSize
= NlsFileHeader
->MaximumCharacterSize
;
158 CodePageTable
->DefaultChar
= NlsFileHeader
->DefaultChar
;
159 CodePageTable
->UniDefaultChar
= NlsFileHeader
->UniDefaultChar
;
160 CodePageTable
->TransDefaultChar
= NlsFileHeader
->TransDefaultChar
;
161 CodePageTable
->TransUniDefaultChar
= NlsFileHeader
->TransUniDefaultChar
;
163 RtlCopyMemory(&CodePageTable
->LeadByte
,
164 &NlsFileHeader
->LeadByte
,
167 /* Offset to wide char table is after the header */
168 CodePageTable
->WideCharTable
= TableBase
+ NlsFileHeader
->HeaderSize
+ 1 +
169 TableBase
[NlsFileHeader
->HeaderSize
];
171 /* Then multibyte table (256 wchars) follows */
172 CodePageTable
->MultiByteTable
= TableBase
+ NlsFileHeader
->HeaderSize
+ 1;
174 /* Check the presence of glyph table (256 wchars) */
175 if (!CodePageTable
->MultiByteTable
[256])
176 CodePageTable
->DBCSRanges
= CodePageTable
->MultiByteTable
+ 256 + 1;
178 CodePageTable
->DBCSRanges
= CodePageTable
->MultiByteTable
+ 256 + 1 + 256;
180 /* Is this double-byte code page? */
181 if (*CodePageTable
->DBCSRanges
)
183 CodePageTable
->DBCSCodePage
= 1;
184 CodePageTable
->DBCSOffsets
= CodePageTable
->DBCSRanges
+ 1;
188 CodePageTable
->DBCSCodePage
= 0;
189 CodePageTable
->DBCSOffsets
= NULL
;
200 RtlInitNlsTables(IN PUSHORT AnsiTableBase
,
201 IN PUSHORT OemTableBase
,
202 IN PUSHORT CaseTableBase
,
203 OUT PNLSTABLEINFO NlsTable
)
205 DPRINT("RtlInitNlsTables()called\n");
207 if (AnsiTableBase
== NULL
||
208 OemTableBase
== NULL
||
209 CaseTableBase
== NULL
)
212 RtlInitCodePageTable(AnsiTableBase
, &NlsTable
->AnsiTableInfo
);
214 RtlInitCodePageTable(OemTableBase
, &NlsTable
->OemTableInfo
);
216 NlsTable
->UpperCaseTable
= (PUSHORT
)CaseTableBase
+ 2;
217 NlsTable
->LowerCaseTable
= (PUSHORT
)CaseTableBase
+ *((PUSHORT
)CaseTableBase
+ 1) + 2;
225 RtlMultiByteToUnicodeN(
226 OUT PWCHAR UnicodeString
,
227 IN ULONG UnicodeSize
,
228 OUT PULONG ResultSize
,
237 if (NlsMbCodePageTag
== FALSE
)
239 /* single-byte code page */
240 if (MbSize
> (UnicodeSize
/ sizeof(WCHAR
)))
241 Size
= UnicodeSize
/ sizeof(WCHAR
);
245 if (ResultSize
!= NULL
)
246 *ResultSize
= Size
* sizeof(WCHAR
);
248 for (i
= 0; i
< Size
; i
++)
249 UnicodeString
[i
] = NlsAnsiToUnicodeTable
[(UCHAR
)MbString
[i
]];
253 /* multi-byte code page */
258 PCSTR MbEnd
= MbString
+ MbSize
;
260 for (i
= 0; i
< UnicodeSize
/ sizeof(WCHAR
) && MbString
< MbEnd
; i
++)
262 Char
= *(PUCHAR
)MbString
++;
266 *UnicodeString
++ = Char
;
270 LeadByteInfo
= NlsLeadByteInfo
[Char
];
274 *UnicodeString
++ = NlsAnsiToUnicodeTable
[Char
];
278 if (MbString
< MbEnd
)
279 *UnicodeString
++ = NlsLeadByteInfo
[LeadByteInfo
+ *(PUCHAR
)MbString
++];
282 if (ResultSize
!= NULL
)
283 *ResultSize
= i
* sizeof(WCHAR
);
286 return STATUS_SUCCESS
;
295 RtlConsoleMultiByteToUnicodeN(
296 OUT PWCHAR UnicodeString
,
297 IN ULONG UnicodeSize
,
298 OUT PULONG ResultSize
,
306 DPRINT1("RtlConsoleMultiByteToUnicodeN calling RtlMultiByteToUnicodeN\n");
308 return RtlMultiByteToUnicodeN(UnicodeString
,
322 RtlMultiByteToUnicodeSize(PULONG UnicodeSize
,
330 if (!NlsMbCodePageTag
)
332 /* single-byte code page */
333 *UnicodeSize
= MbSize
* sizeof (WCHAR
);
337 /* multi-byte code page */
342 UCHAR Char
= *(PUCHAR
)MbString
++;
344 if (Char
>= 0x80 && NlsLeadByteInfo
[Char
])
354 /* Increase returned size */
358 /* Return final size */
359 *UnicodeSize
= Length
* sizeof(WCHAR
);
363 return STATUS_SUCCESS
;
372 RtlOemToUnicodeN (PWCHAR UnicodeString
,
381 if (NlsMbOemCodePageTag
== FALSE
)
383 /* single-byte code page */
384 if (OemSize
> (UnicodeSize
/ sizeof(WCHAR
)))
385 Size
= UnicodeSize
/ sizeof(WCHAR
);
389 if (ResultSize
!= NULL
)
390 *ResultSize
= Size
* sizeof(WCHAR
);
392 for (i
= 0; i
< Size
; i
++)
394 *UnicodeString
= NlsOemToUnicodeTable
[(UCHAR
)*OemString
];
401 /* multi-byte code page */
405 USHORT OemLeadByteInfo
;
406 PCCH OemEnd
= OemString
+ OemSize
;
408 for (i
= 0; i
< UnicodeSize
/ sizeof(WCHAR
) && OemString
< OemEnd
; i
++)
410 Char
= *(PUCHAR
)OemString
++;
414 *UnicodeString
++ = Char
;
418 OemLeadByteInfo
= NlsOemLeadByteInfo
[Char
];
420 if (!OemLeadByteInfo
)
422 *UnicodeString
++ = NlsOemToUnicodeTable
[Char
];
426 if (OemString
< OemEnd
)
428 NlsOemLeadByteInfo
[OemLeadByteInfo
+ *(PUCHAR
)OemString
++];
431 if (ResultSize
!= NULL
)
432 *ResultSize
= i
* sizeof(WCHAR
);
435 return STATUS_SUCCESS
;
444 RtlResetRtlTranslations(IN PNLSTABLEINFO NlsTable
)
446 DPRINT("RtlResetRtlTranslations() called\n");
449 NlsAnsiToUnicodeTable
= (PWCHAR
)NlsTable
->AnsiTableInfo
.MultiByteTable
; /* Real type is PUSHORT */
450 NlsUnicodeToAnsiTable
= NlsTable
->AnsiTableInfo
.WideCharTable
;
451 NlsDbcsUnicodeToAnsiTable
= (PWCHAR
)NlsTable
->AnsiTableInfo
.WideCharTable
;
452 NlsMbCodePageTag
= (NlsTable
->AnsiTableInfo
.DBCSCodePage
!= 0);
453 NlsLeadByteInfo
= NlsTable
->AnsiTableInfo
.DBCSOffsets
;
454 NlsAnsiCodePage
= NlsTable
->AnsiTableInfo
.CodePage
;
455 DPRINT("Ansi codepage %hu\n", NlsAnsiCodePage
);
458 NlsOemToUnicodeTable
= (PWCHAR
)NlsTable
->OemTableInfo
.MultiByteTable
; /* Real type is PUSHORT */
459 NlsUnicodeToOemTable
= NlsTable
->OemTableInfo
.WideCharTable
;
460 NlsDbcsUnicodeToOemTable
= (PWCHAR
)NlsTable
->OemTableInfo
.WideCharTable
;
461 NlsMbOemCodePageTag
= (NlsTable
->OemTableInfo
.DBCSCodePage
!= 0);
462 NlsOemLeadByteInfo
= NlsTable
->OemTableInfo
.DBCSOffsets
;
463 NlsOemCodePage
= NlsTable
->OemTableInfo
.CodePage
;
464 DPRINT("Oem codepage %hu\n", NlsOemCodePage
);
466 /* Set Unicode case map data */
467 NlsUnicodeUpcaseTable
= NlsTable
->UpperCaseTable
;
468 NlsUnicodeLowercaseTable
= NlsTable
->LowerCaseTable
;
470 /* set the default characters for RtlpDidUnicodeToOemWork */
471 NlsOemDefaultChar
= NlsTable
->OemTableInfo
.DefaultChar
;
472 NlsUnicodeDefaultChar
= NlsTable
->OemTableInfo
.TransDefaultChar
;
481 RtlUnicodeToCustomCPN(IN PCPTABLEINFO CustomCP
,
485 PWCHAR UnicodeString
,
491 if (CustomCP
->DBCSCodePage
== 0)
493 /* single-byte code page */
494 if (UnicodeSize
> (CustomSize
* sizeof(WCHAR
)))
497 Size
= UnicodeSize
/ sizeof(WCHAR
);
499 if (ResultSize
!= NULL
)
502 for (i
= 0; i
< Size
; i
++)
504 *CustomString
= ((PCHAR
)CustomCP
->WideCharTable
)[*UnicodeString
];
511 /* multi-byte code page */
516 return STATUS_SUCCESS
;
525 RtlUnicodeToMultiByteN (PCHAR MbString
,
536 if (NlsMbCodePageTag
== FALSE
)
538 /* single-byte code page */
539 Size
= (UnicodeSize
> (MbSize
* sizeof (WCHAR
)))
541 : (UnicodeSize
/ sizeof (WCHAR
));
543 if (ResultSize
!= NULL
)
548 for (i
= 0; i
< Size
; i
++)
550 *MbString
++ = NlsUnicodeToAnsiTable
[*UnicodeString
++];
555 /* multi-byte code page */
561 for (i
= MbSize
, Size
= UnicodeSize
/ sizeof(WCHAR
); i
&& Size
; i
--, Size
--)
563 WideChar
= *UnicodeString
++;
567 *MbString
++ = LOBYTE(WideChar
);
571 MbChar
= NlsDbcsUnicodeToAnsiTable
[WideChar
];
575 *MbString
++ = LOBYTE(MbChar
);
581 *MbString
++ = HIBYTE(MbChar
);
582 *MbString
++ = LOBYTE(MbChar
);
588 if (ResultSize
!= NULL
)
589 *ResultSize
= MbSize
- i
;
592 return STATUS_SUCCESS
;
600 RtlUnicodeToMultiByteSize(PULONG MbSize
,
604 ULONG UnicodeLength
= UnicodeSize
/ sizeof(WCHAR
);
607 if (!NlsMbCodePageTag
)
609 /* single-byte code page */
610 *MbSize
= UnicodeLength
;
614 /* multi-byte code page */
617 while (UnicodeLength
--)
619 USHORT WideChar
= *UnicodeString
++;
621 if (WideChar
>= 0x80 && HIBYTE(NlsDbcsUnicodeToAnsiTable
[WideChar
]))
623 MbLength
+= sizeof(WCHAR
);
635 return STATUS_SUCCESS
;
642 RtlUnicodeToOemN (PCHAR OemString
,
651 if (NlsMbOemCodePageTag
== FALSE
)
653 /* single-byte code page */
654 if (UnicodeSize
> (OemSize
* sizeof(WCHAR
)))
657 Size
= UnicodeSize
/ sizeof(WCHAR
);
659 if (ResultSize
!= NULL
)
662 for (i
= 0; i
< Size
; i
++)
664 *OemString
= NlsUnicodeToOemTable
[*UnicodeString
];
671 /* multi-byte code page */
677 for (i
= OemSize
, Size
= UnicodeSize
/ sizeof(WCHAR
); i
&& Size
; i
--, Size
--)
679 WideChar
= *UnicodeString
++;
683 *OemString
++ = LOBYTE(WideChar
);
687 OemChar
= NlsDbcsUnicodeToOemTable
[WideChar
];
689 if (!HIBYTE(OemChar
))
691 *OemString
++ = LOBYTE(OemChar
);
697 *OemString
++ = HIBYTE(OemChar
);
698 *OemString
++ = LOBYTE(OemChar
);
704 if (ResultSize
!= NULL
)
705 *ResultSize
= OemSize
- i
;
708 return STATUS_SUCCESS
;
718 RtlUpcaseUnicodeChar(IN WCHAR Source
)
726 return (Source
- ('a' - 'A'));
728 Offset
= ((USHORT
)Source
>> 8) & 0xFF;
729 Offset
= NlsUnicodeUpcaseTable
[Offset
];
731 Offset
+= ((USHORT
)Source
>> 4) & 0xF;
732 Offset
= NlsUnicodeUpcaseTable
[Offset
];
734 Offset
+= ((USHORT
)Source
& 0xF);
735 Offset
= NlsUnicodeUpcaseTable
[Offset
];
737 return Source
+ (SHORT
)Offset
;
746 RtlUpcaseUnicodeToCustomCPN (IN PCPTABLEINFO CustomCP
,
750 PWCHAR UnicodeString
,
757 if (CustomCP
->DBCSCodePage
== 0)
759 /* single-byte code page */
760 if (UnicodeSize
> (CustomSize
* sizeof(WCHAR
)))
763 Size
= UnicodeSize
/ sizeof(WCHAR
);
765 if (ResultSize
!= NULL
)
768 for (i
= 0; i
< Size
; i
++)
770 UpcaseChar
= RtlUpcaseUnicodeChar(*UnicodeString
);
771 *CustomString
= ((PCHAR
)CustomCP
->WideCharTable
)[UpcaseChar
];
778 /* multi-byte code page */
783 return STATUS_SUCCESS
;
791 RtlUpcaseUnicodeToMultiByteN (PCHAR MbString
,
801 if (NlsMbCodePageTag
== FALSE
)
803 /* single-byte code page */
804 if (UnicodeSize
> (MbSize
* sizeof(WCHAR
)))
807 Size
= UnicodeSize
/ sizeof(WCHAR
);
809 if (ResultSize
!= NULL
)
812 for (i
= 0; i
< Size
; i
++)
814 UpcaseChar
= RtlUpcaseUnicodeChar(*UnicodeString
);
815 *MbString
= NlsUnicodeToAnsiTable
[UpcaseChar
];
822 /* multi-byte code page */
827 return STATUS_SUCCESS
;
835 RtlUpcaseUnicodeToOemN (PCHAR OemString
,
845 ASSERT(NlsUnicodeToOemTable
!= NULL
);
847 if (NlsMbOemCodePageTag
== FALSE
)
849 /* single-byte code page */
850 if (UnicodeSize
> (OemSize
* sizeof(WCHAR
)))
853 Size
= UnicodeSize
/ sizeof(WCHAR
);
855 if (ResultSize
!= NULL
)
858 for (i
= 0; i
< Size
; i
++)
860 UpcaseChar
= RtlUpcaseUnicodeChar(*UnicodeString
);
861 *OemString
= NlsUnicodeToOemTable
[UpcaseChar
];
868 /* multi-byte code page */
874 for (i
= OemSize
, Size
= UnicodeSize
/ sizeof(WCHAR
); i
&& Size
; i
--, Size
--)
876 WideChar
= RtlUpcaseUnicodeChar(*UnicodeString
++);
880 *OemString
++ = LOBYTE(WideChar
);
884 OemChar
= NlsDbcsUnicodeToOemTable
[WideChar
];
886 if (!HIBYTE(OemChar
))
888 *OemString
++ = LOBYTE(OemChar
);
894 *OemString
++ = HIBYTE(OemChar
);
895 *OemString
++ = LOBYTE(OemChar
);
901 if (ResultSize
!= NULL
)
902 *ResultSize
= OemSize
- i
;
905 return STATUS_SUCCESS
;
914 RtlUpperChar (IN CHAR Source
)
919 /* Check for simple ANSI case */
922 /* Check for simple downcase a-z case */
925 /* Just XOR with the difference */
926 return Source
^ ('a' - 'A');
930 /* Otherwise return the same char, it's already upcase */
936 if (NlsMbCodePageTag
== FALSE
)
938 /* single-byte code page */
941 Unicode
= NlsAnsiToUnicodeTable
[(UCHAR
)Source
];
943 /* upcase conversion */
944 Unicode
= RtlUpcaseUnicodeChar (Unicode
);
946 /* unicode -> ansi */
947 Destination
= NlsUnicodeToAnsiTable
[(USHORT
)Unicode
];
951 /* multi-byte code page */
953 Destination
= Source
;