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 PUSHORT NlsAnsiToUnicodeTable
= NULL
;
24 PCHAR NlsUnicodeToAnsiTable
= NULL
;
25 PUSHORT NlsUnicodeToMbAnsiTable
= NULL
;
26 PUSHORT NlsLeadByteInfo
= NULL
; /* exported */
28 USHORT NlsOemCodePage
= 0;
29 BOOLEAN NlsMbOemCodePageTag
= FALSE
; /* exported */
30 PUSHORT NlsOemToUnicodeTable
= NULL
;
31 PCHAR NlsUnicodeToOemTable
= NULL
;
32 PUSHORT NlsUnicodeToMbOemTable
= NULL
;
33 PUSHORT NlsOemLeadByteInfo
= NULL
; /* exported */
35 USHORT NlsOemDefaultChar
= '\0';
36 USHORT NlsUnicodeDefaultChar
= 0;
39 /* FUNCTIONS *****************************************************************/
45 RtlCustomCPToUnicodeN(IN PCPTABLEINFO CustomCP
,
46 OUT PWCHAR UnicodeString
,
48 OUT PULONG ResultSize OPTIONAL
,
49 IN PCHAR CustomString
,
57 if (!CustomCP
->DBCSCodePage
)
59 /* single-byte code page */
60 if (CustomSize
> (UnicodeSize
/ sizeof(WCHAR
)))
61 Size
= UnicodeSize
/ sizeof(WCHAR
);
66 *ResultSize
= Size
* sizeof(WCHAR
);
68 for (i
= 0; i
< Size
; i
++)
70 *UnicodeString
= CustomCP
->MultiByteTable
[(UCHAR
)*CustomString
];
77 /* multi-byte code page */
82 return STATUS_SUCCESS
;
89 RtlpDowncaseUnicodeChar(IN WCHAR Source
)
99 return Source
+ (L
'a' - L
'A');
104 Offset
= ((USHORT
)Source
>> 8);
105 DPRINT("Offset: %hx\n", Offset
);
107 Offset
= NlsUnicodeLowercaseTable
[Offset
];
108 DPRINT("Offset: %hx\n", Offset
);
110 Offset
+= (((USHORT
)Source
& 0x00F0) >> 4);
111 DPRINT("Offset: %hx\n", Offset
);
113 Offset
= NlsUnicodeLowercaseTable
[Offset
];
114 DPRINT("Offset: %hx\n", Offset
);
116 Offset
+= ((USHORT
)Source
& 0x000F);
117 DPRINT("Offset: %hx\n", Offset
);
119 Offset
= NlsUnicodeLowercaseTable
[Offset
];
120 DPRINT("Offset: %hx\n", Offset
);
122 DPRINT("Result: %hx\n", Source
+ (SHORT
)Offset
);
124 return Source
+ (SHORT
)Offset
;
131 RtlDowncaseUnicodeChar(IN WCHAR Source
)
135 return RtlpDowncaseUnicodeChar(Source
);
142 RtlGetDefaultCodePage(OUT PUSHORT AnsiCodePage
,
143 OUT PUSHORT OemCodePage
)
147 *AnsiCodePage
= NlsAnsiCodePage
;
148 *OemCodePage
= NlsOemCodePage
;
155 RtlInitCodePageTable(IN PUSHORT TableBase
,
156 OUT PCPTABLEINFO CodePageTable
)
158 PNLS_FILE_HEADER NlsFileHeader
;
162 DPRINT("RtlInitCodePageTable() called\n");
164 NlsFileHeader
= (PNLS_FILE_HEADER
)TableBase
;
166 /* Copy header fields first */
167 CodePageTable
->CodePage
= NlsFileHeader
->CodePage
;
168 CodePageTable
->MaximumCharacterSize
= NlsFileHeader
->MaximumCharacterSize
;
169 CodePageTable
->DefaultChar
= NlsFileHeader
->DefaultChar
;
170 CodePageTable
->UniDefaultChar
= NlsFileHeader
->UniDefaultChar
;
171 CodePageTable
->TransDefaultChar
= NlsFileHeader
->TransDefaultChar
;
172 CodePageTable
->TransUniDefaultChar
= NlsFileHeader
->TransUniDefaultChar
;
174 RtlCopyMemory(&CodePageTable
->LeadByte
,
175 &NlsFileHeader
->LeadByte
,
178 /* Offset to wide char table is after the header */
179 CodePageTable
->WideCharTable
=
180 TableBase
+ NlsFileHeader
->HeaderSize
+ 1 + TableBase
[NlsFileHeader
->HeaderSize
];
182 /* Then multibyte table (256 wchars) follows */
183 CodePageTable
->MultiByteTable
= TableBase
+ NlsFileHeader
->HeaderSize
+ 1;
185 /* Check the presence of glyph table (256 wchars) */
186 if (!CodePageTable
->MultiByteTable
[256])
187 CodePageTable
->DBCSRanges
= CodePageTable
->MultiByteTable
+ 256 + 1;
189 CodePageTable
->DBCSRanges
= CodePageTable
->MultiByteTable
+ 256 + 1 + 256;
191 /* Is this double-byte code page? */
192 if (*CodePageTable
->DBCSRanges
)
194 CodePageTable
->DBCSCodePage
= 1;
195 CodePageTable
->DBCSOffsets
= CodePageTable
->DBCSRanges
+ 1;
199 CodePageTable
->DBCSCodePage
= 0;
200 CodePageTable
->DBCSOffsets
= NULL
;
208 RtlInitNlsTables(IN PUSHORT AnsiTableBase
,
209 IN PUSHORT OemTableBase
,
210 IN PUSHORT CaseTableBase
,
211 OUT PNLSTABLEINFO NlsTable
)
215 DPRINT("RtlInitNlsTables()called\n");
217 if (AnsiTableBase
&& OemTableBase
&& CaseTableBase
)
219 RtlInitCodePageTable(AnsiTableBase
, &NlsTable
->AnsiTableInfo
);
220 RtlInitCodePageTable(OemTableBase
, &NlsTable
->OemTableInfo
);
222 NlsTable
->UpperCaseTable
= (PUSHORT
)CaseTableBase
+ 2;
223 NlsTable
->LowerCaseTable
= (PUSHORT
)CaseTableBase
+ *((PUSHORT
)CaseTableBase
+ 1) + 2;
231 RtlMultiByteToUnicodeN(OUT PWCHAR UnicodeString
,
232 IN ULONG UnicodeSize
,
233 OUT PULONG ResultSize
,
242 if (!NlsMbCodePageTag
)
244 /* single-byte code page */
245 if (MbSize
> (UnicodeSize
/ sizeof(WCHAR
)))
246 Size
= UnicodeSize
/ sizeof(WCHAR
);
251 *ResultSize
= Size
* sizeof(WCHAR
);
253 for (i
= 0; i
< Size
; i
++)
254 UnicodeString
[i
] = NlsAnsiToUnicodeTable
[(UCHAR
)MbString
[i
]];
258 /* multi-byte code page */
263 PCSTR MbEnd
= MbString
+ MbSize
;
265 for (i
= 0; i
< UnicodeSize
/ sizeof(WCHAR
) && MbString
< MbEnd
; i
++)
267 Char
= *(PUCHAR
)MbString
++;
271 *UnicodeString
++ = Char
;
275 LeadByteInfo
= NlsLeadByteInfo
[Char
];
279 *UnicodeString
++ = NlsAnsiToUnicodeTable
[Char
];
283 if (MbString
< MbEnd
)
284 *UnicodeString
++ = NlsLeadByteInfo
[LeadByteInfo
+ *(PUCHAR
)MbString
++];
288 *ResultSize
= i
* sizeof(WCHAR
);
291 return STATUS_SUCCESS
;
299 RtlConsoleMultiByteToUnicodeN(OUT PWCHAR UnicodeString
,
300 IN ULONG UnicodeSize
,
301 OUT PULONG ResultSize
,
309 DPRINT1("RtlConsoleMultiByteToUnicodeN calling RtlMultiByteToUnicodeN\n");
311 return RtlMultiByteToUnicodeN(UnicodeString
,
323 RtlMultiByteToUnicodeSize(OUT PULONG UnicodeSize
,
331 if (!NlsMbCodePageTag
)
333 /* single-byte code page */
334 *UnicodeSize
= MbSize
* sizeof (WCHAR
);
338 /* multi-byte code page */
343 UCHAR Char
= *(PUCHAR
)MbString
++;
345 if (Char
>= 0x80 && NlsLeadByteInfo
[Char
])
355 /* Increase returned size */
359 /* Return final size */
360 *UnicodeSize
= Length
* sizeof(WCHAR
);
364 return STATUS_SUCCESS
;
371 RtlOemToUnicodeN(OUT PWCHAR UnicodeString
,
372 IN ULONG UnicodeSize
,
373 OUT PULONG ResultSize OPTIONAL
,
382 if (!NlsMbOemCodePageTag
)
384 /* single-byte code page */
385 if (OemSize
> (UnicodeSize
/ sizeof(WCHAR
)))
386 Size
= UnicodeSize
/ sizeof(WCHAR
);
391 *ResultSize
= Size
* sizeof(WCHAR
);
393 for (i
= 0; i
< Size
; i
++)
395 *UnicodeString
= NlsOemToUnicodeTable
[(UCHAR
)*OemString
];
402 /* multi-byte code page */
406 USHORT OemLeadByteInfo
;
407 PCCH OemEnd
= OemString
+ OemSize
;
409 for (i
= 0; i
< UnicodeSize
/ sizeof(WCHAR
) && OemString
< OemEnd
; i
++)
411 Char
= *(PUCHAR
)OemString
++;
415 *UnicodeString
++ = Char
;
419 OemLeadByteInfo
= NlsOemLeadByteInfo
[Char
];
421 if (!OemLeadByteInfo
)
423 *UnicodeString
++ = NlsOemToUnicodeTable
[Char
];
427 if (OemString
< OemEnd
)
429 NlsOemLeadByteInfo
[OemLeadByteInfo
+ *(PUCHAR
)OemString
++];
433 *ResultSize
= i
* sizeof(WCHAR
);
436 return STATUS_SUCCESS
;
443 RtlResetRtlTranslations(IN PNLSTABLEINFO NlsTable
)
447 DPRINT("RtlResetRtlTranslations() called\n");
450 NlsAnsiToUnicodeTable
= (PUSHORT
)NlsTable
->AnsiTableInfo
.MultiByteTable
;
451 NlsUnicodeToAnsiTable
= NlsTable
->AnsiTableInfo
.WideCharTable
;
452 NlsUnicodeToMbAnsiTable
= (PUSHORT
)NlsTable
->AnsiTableInfo
.WideCharTable
;
453 NlsMbCodePageTag
= (NlsTable
->AnsiTableInfo
.DBCSCodePage
!= 0);
454 NlsLeadByteInfo
= NlsTable
->AnsiTableInfo
.DBCSOffsets
;
455 NlsAnsiCodePage
= NlsTable
->AnsiTableInfo
.CodePage
;
456 DPRINT("Ansi codepage %hu\n", NlsAnsiCodePage
);
459 NlsOemToUnicodeTable
= (PUSHORT
)NlsTable
->OemTableInfo
.MultiByteTable
;
460 NlsUnicodeToOemTable
= NlsTable
->OemTableInfo
.WideCharTable
;
461 NlsUnicodeToMbOemTable
= (PUSHORT
)NlsTable
->OemTableInfo
.WideCharTable
;
462 NlsMbOemCodePageTag
= (NlsTable
->OemTableInfo
.DBCSCodePage
!= 0);
463 NlsOemLeadByteInfo
= NlsTable
->OemTableInfo
.DBCSOffsets
;
464 NlsOemCodePage
= NlsTable
->OemTableInfo
.CodePage
;
465 DPRINT("Oem codepage %hu\n", NlsOemCodePage
);
467 /* Set Unicode case map data */
468 NlsUnicodeUpcaseTable
= NlsTable
->UpperCaseTable
;
469 NlsUnicodeLowercaseTable
= NlsTable
->LowerCaseTable
;
471 /* set the default characters for RtlpDidUnicodeToOemWork */
472 NlsOemDefaultChar
= NlsTable
->OemTableInfo
.DefaultChar
;
473 NlsUnicodeDefaultChar
= NlsTable
->OemTableInfo
.TransDefaultChar
;
480 RtlUnicodeToCustomCPN(IN PCPTABLEINFO CustomCP
,
481 OUT PCHAR CustomString
,
483 OUT PULONG ResultSize OPTIONAL
,
484 IN PWCHAR UnicodeString
,
485 IN ULONG UnicodeSize
)
492 if (!CustomCP
->DBCSCodePage
)
494 /* single-byte code page */
495 if (UnicodeSize
> (CustomSize
* sizeof(WCHAR
)))
498 Size
= UnicodeSize
/ sizeof(WCHAR
);
503 for (i
= 0; i
< Size
; i
++)
505 *CustomString
= ((PCHAR
)CustomCP
->WideCharTable
)[*UnicodeString
];
512 /* multi-byte code page */
517 return STATUS_SUCCESS
;
524 RtlUnicodeToMultiByteN(OUT PCHAR MbString
,
526 OUT PULONG ResultSize OPTIONAL
,
527 IN PCWCH UnicodeString
,
528 IN ULONG UnicodeSize
)
535 if (!NlsMbCodePageTag
)
537 /* single-byte code page */
538 Size
= (UnicodeSize
> (MbSize
* sizeof (WCHAR
)))
539 ? MbSize
: (UnicodeSize
/ sizeof (WCHAR
));
544 for (i
= 0; i
< Size
; i
++)
546 *MbString
++ = NlsUnicodeToAnsiTable
[*UnicodeString
++];
551 /* multi-byte code page */
557 for (i
= MbSize
, Size
= UnicodeSize
/ sizeof(WCHAR
); i
&& Size
; i
--, Size
--)
559 WideChar
= *UnicodeString
++;
563 *MbString
++ = LOBYTE(WideChar
);
567 MbChar
= NlsUnicodeToMbAnsiTable
[WideChar
];
571 *MbString
++ = LOBYTE(MbChar
);
577 *MbString
++ = HIBYTE(MbChar
);
578 *MbString
++ = LOBYTE(MbChar
);
585 *ResultSize
= MbSize
- i
;
588 return STATUS_SUCCESS
;
596 RtlUnicodeToMultiByteSize(OUT PULONG MbSize
,
597 IN PCWCH UnicodeString
,
598 IN ULONG UnicodeSize
)
600 ULONG UnicodeLength
= UnicodeSize
/ sizeof(WCHAR
);
605 if (!NlsMbCodePageTag
)
607 /* single-byte code page */
608 *MbSize
= UnicodeLength
;
612 /* multi-byte code page */
615 while (UnicodeLength
--)
617 USHORT WideChar
= *UnicodeString
++;
619 if (WideChar
>= 0x80 && HIBYTE(NlsUnicodeToMbAnsiTable
[WideChar
]))
621 MbLength
+= sizeof(WCHAR
);
633 return STATUS_SUCCESS
;
640 RtlUnicodeToOemN(OUT PCHAR OemString
,
642 OUT PULONG ResultSize OPTIONAL
,
643 IN PCWCH UnicodeString
,
644 IN ULONG UnicodeSize
)
651 if (!NlsMbOemCodePageTag
)
653 /* single-byte code page */
654 if (UnicodeSize
> (OemSize
* sizeof(WCHAR
)))
657 Size
= UnicodeSize
/ sizeof(WCHAR
);
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
= NlsUnicodeToMbOemTable
[WideChar
];
689 if (!HIBYTE(OemChar
))
691 *OemString
++ = LOBYTE(OemChar
);
697 *OemString
++ = HIBYTE(OemChar
);
698 *OemString
++ = LOBYTE(OemChar
);
705 *ResultSize
= OemSize
- i
;
708 return STATUS_SUCCESS
;
715 RtlpUpcaseUnicodeChar(IN WCHAR Source
)
723 return (Source
- ('a' - 'A'));
725 Offset
= ((USHORT
)Source
>> 8) & 0xFF;
726 Offset
= NlsUnicodeUpcaseTable
[Offset
];
728 Offset
+= ((USHORT
)Source
>> 4) & 0xF;
729 Offset
= NlsUnicodeUpcaseTable
[Offset
];
731 Offset
+= ((USHORT
)Source
& 0xF);
732 Offset
= NlsUnicodeUpcaseTable
[Offset
];
734 return Source
+ (SHORT
)Offset
;
741 RtlUpcaseUnicodeChar(IN WCHAR Source
)
745 return RtlpUpcaseUnicodeChar(Source
);
752 RtlUpcaseUnicodeToCustomCPN(IN PCPTABLEINFO CustomCP
,
753 OUT PCHAR CustomString
,
755 OUT PULONG ResultSize OPTIONAL
,
756 IN PWCHAR UnicodeString
,
757 IN ULONG UnicodeSize
)
765 if (!CustomCP
->DBCSCodePage
)
767 /* single-byte code page */
768 if (UnicodeSize
> (CustomSize
* sizeof(WCHAR
)))
771 Size
= UnicodeSize
/ sizeof(WCHAR
);
776 for (i
= 0; i
< Size
; i
++)
778 UpcaseChar
= RtlpUpcaseUnicodeChar(*UnicodeString
);
779 *CustomString
= ((PCHAR
)CustomCP
->WideCharTable
)[UpcaseChar
];
786 /* multi-byte code page */
791 return STATUS_SUCCESS
;
798 RtlUpcaseUnicodeToMultiByteN(OUT PCHAR MbString
,
800 OUT PULONG ResultSize OPTIONAL
,
801 IN PCWCH UnicodeString
,
802 IN ULONG UnicodeSize
)
810 if (!NlsMbCodePageTag
)
812 /* single-byte code page */
813 if (UnicodeSize
> (MbSize
* sizeof(WCHAR
)))
816 Size
= UnicodeSize
/ sizeof(WCHAR
);
821 for (i
= 0; i
< Size
; i
++)
823 UpcaseChar
= RtlpUpcaseUnicodeChar(*UnicodeString
);
824 *MbString
= NlsUnicodeToAnsiTable
[UpcaseChar
];
831 /* multi-byte code page */
836 return STATUS_SUCCESS
;
843 RtlUpcaseUnicodeToOemN(OUT PCHAR OemString
,
845 OUT PULONG ResultSize OPTIONAL
,
846 IN PCWCH UnicodeString
,
847 IN ULONG UnicodeSize
)
855 ASSERT(NlsUnicodeToOemTable
!= NULL
);
857 if (!NlsMbOemCodePageTag
)
859 /* single-byte code page */
860 if (UnicodeSize
> (OemSize
* sizeof(WCHAR
)))
863 Size
= UnicodeSize
/ sizeof(WCHAR
);
868 for (i
= 0; i
< Size
; i
++)
870 UpcaseChar
= RtlpUpcaseUnicodeChar(*UnicodeString
);
871 *OemString
= NlsUnicodeToOemTable
[UpcaseChar
];
878 /* multi-byte code page */
884 for (i
= OemSize
, Size
= UnicodeSize
/ sizeof(WCHAR
); i
&& Size
; i
--, Size
--)
886 WideChar
= RtlpUpcaseUnicodeChar(*UnicodeString
++);
890 *OemString
++ = LOBYTE(WideChar
);
894 OemChar
= NlsUnicodeToMbOemTable
[WideChar
];
896 if (!HIBYTE(OemChar
))
898 *OemString
++ = LOBYTE(OemChar
);
904 *OemString
++ = HIBYTE(OemChar
);
905 *OemString
++ = LOBYTE(OemChar
);
912 *ResultSize
= OemSize
- i
;
915 return STATUS_SUCCESS
;
922 RtlUpperChar(IN CHAR Source
)
929 /* Check for simple ANSI case */
932 /* Check for simple downcase a-z case */
935 /* Just XOR with the difference */
936 return Source
^ ('a' - 'A');
940 /* Otherwise return the same char, it's already upcase */
946 if (!NlsMbCodePageTag
)
948 /* single-byte code page */
951 Unicode
= NlsAnsiToUnicodeTable
[(UCHAR
)Source
];
953 /* upcase conversion */
954 Unicode
= RtlpUpcaseUnicodeChar (Unicode
);
956 /* unicode -> ansi */
957 Destination
= NlsUnicodeToAnsiTable
[(USHORT
)Unicode
];
961 /* multi-byte code page */
963 Destination
= Source
;