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;
40 #define NlsOemLeadByteInfo _NlsOemLeadByteInfo
43 /* FUNCTIONS *****************************************************************/
49 RtlCustomCPToUnicodeN(IN PCPTABLEINFO CustomCP
,
59 if (CustomCP
->DBCSCodePage
== 0)
61 /* single-byte code page */
62 if (CustomSize
> (UnicodeSize
/ sizeof(WCHAR
)))
63 Size
= UnicodeSize
/ sizeof(WCHAR
);
67 if (ResultSize
!= NULL
)
68 *ResultSize
= Size
* sizeof(WCHAR
);
70 for (i
= 0; i
< Size
; i
++)
72 *UnicodeString
= CustomCP
->MultiByteTable
[(UCHAR
)*CustomString
];
79 /* multi-byte code page */
84 return(STATUS_SUCCESS
);
90 RtlDowncaseUnicodeChar (IN WCHAR Source
)
98 return Source
+ (L
'a' - L
'A');
103 Offset
= ((USHORT
)Source
>> 8);
104 DPRINT("Offset: %hx\n", Offset
);
106 Offset
= NlsUnicodeLowercaseTable
[Offset
];
107 DPRINT("Offset: %hx\n", Offset
);
109 Offset
+= (((USHORT
)Source
& 0x00F0) >> 4);
110 DPRINT("Offset: %hx\n", Offset
);
112 Offset
= NlsUnicodeLowercaseTable
[Offset
];
113 DPRINT("Offset: %hx\n", Offset
);
115 Offset
+= ((USHORT
)Source
& 0x000F);
116 DPRINT("Offset: %hx\n", Offset
);
118 Offset
= NlsUnicodeLowercaseTable
[Offset
];
119 DPRINT("Offset: %hx\n", Offset
);
121 DPRINT("Result: %hx\n", Source
+ (SHORT
)Offset
);
123 return Source
+ (SHORT
)Offset
;
133 RtlGetDefaultCodePage(OUT PUSHORT AnsiCodePage
,
134 OUT PUSHORT OemCodePage
)
136 *AnsiCodePage
= NlsAnsiCodePage
;
137 *OemCodePage
= NlsOemCodePage
;
147 RtlInitCodePageTable(IN PUSHORT TableBase
,
148 OUT PCPTABLEINFO CodePageTable
)
150 PNLS_FILE_HEADER NlsFileHeader
;
152 DPRINT("RtlInitCodePageTable() called\n");
154 NlsFileHeader
= (PNLS_FILE_HEADER
)TableBase
;
156 /* Copy header fields first */
157 CodePageTable
->CodePage
= NlsFileHeader
->CodePage
;
158 CodePageTable
->MaximumCharacterSize
= NlsFileHeader
->MaximumCharacterSize
;
159 CodePageTable
->DefaultChar
= NlsFileHeader
->DefaultChar
;
160 CodePageTable
->UniDefaultChar
= NlsFileHeader
->UniDefaultChar
;
161 CodePageTable
->TransDefaultChar
= NlsFileHeader
->TransDefaultChar
;
162 CodePageTable
->TransUniDefaultChar
= NlsFileHeader
->TransUniDefaultChar
;
164 RtlCopyMemory(&CodePageTable
->LeadByte
,
165 &NlsFileHeader
->LeadByte
,
168 /* Offset to wide char table is after the header */
169 CodePageTable
->WideCharTable
= TableBase
+ NlsFileHeader
->HeaderSize
+ 1 +
170 TableBase
[NlsFileHeader
->HeaderSize
];
172 /* Then multibyte table (256 wchars) follows */
173 CodePageTable
->MultiByteTable
= TableBase
+ NlsFileHeader
->HeaderSize
+ 1;
175 /* Check the presence of glyph table (256 wchars) */
176 if (!CodePageTable
->MultiByteTable
[256])
177 CodePageTable
->DBCSRanges
= CodePageTable
->MultiByteTable
+ 256 + 1;
179 CodePageTable
->DBCSRanges
= CodePageTable
->MultiByteTable
+ 256 + 1 + 256;
181 /* Is this double-byte code page? */
182 if (*CodePageTable
->DBCSRanges
)
184 CodePageTable
->DBCSCodePage
= 1;
185 CodePageTable
->DBCSOffsets
= CodePageTable
->DBCSRanges
+ 1;
189 CodePageTable
->DBCSCodePage
= 0;
190 CodePageTable
->DBCSOffsets
= NULL
;
201 RtlInitNlsTables(IN PUSHORT AnsiTableBase
,
202 IN PUSHORT OemTableBase
,
203 IN PUSHORT CaseTableBase
,
204 OUT PNLSTABLEINFO NlsTable
)
206 DPRINT("RtlInitNlsTables()called\n");
208 if (AnsiTableBase
== NULL
||
209 OemTableBase
== NULL
||
210 CaseTableBase
== NULL
)
213 RtlInitCodePageTable(AnsiTableBase
, &NlsTable
->AnsiTableInfo
);
215 RtlInitCodePageTable(OemTableBase
, &NlsTable
->OemTableInfo
);
217 NlsTable
->UpperCaseTable
= (PUSHORT
)CaseTableBase
+ 2;
218 NlsTable
->LowerCaseTable
= (PUSHORT
)CaseTableBase
+ *((PUSHORT
)CaseTableBase
+ 1) + 2;
226 RtlMultiByteToUnicodeN(
227 OUT PWCHAR UnicodeString
,
228 IN ULONG UnicodeSize
,
229 OUT PULONG ResultSize
,
238 if (NlsMbCodePageTag
== FALSE
)
240 /* single-byte code page */
241 if (MbSize
> (UnicodeSize
/ sizeof(WCHAR
)))
242 Size
= UnicodeSize
/ sizeof(WCHAR
);
246 if (ResultSize
!= NULL
)
247 *ResultSize
= Size
* sizeof(WCHAR
);
249 for (i
= 0; i
< Size
; i
++)
250 UnicodeString
[i
] = NlsAnsiToUnicodeTable
[(UCHAR
)MbString
[i
]];
254 /* multi-byte code page */
259 PCSTR MbEnd
= MbString
+ MbSize
;
261 for (i
= 0; i
< UnicodeSize
/ sizeof(WCHAR
) && MbString
< MbEnd
; i
++)
263 Char
= *(PUCHAR
)MbString
++;
267 *UnicodeString
++ = Char
;
271 LeadByteInfo
= NlsLeadByteInfo
[Char
];
275 *UnicodeString
++ = NlsAnsiToUnicodeTable
[Char
];
279 if (MbString
< MbEnd
)
280 *UnicodeString
++ = NlsLeadByteInfo
[LeadByteInfo
+ *(PUCHAR
)MbString
++];
283 if (ResultSize
!= NULL
)
284 *ResultSize
= i
* sizeof(WCHAR
);
287 return STATUS_SUCCESS
;
296 RtlConsoleMultiByteToUnicodeN(
297 OUT PWCHAR UnicodeString
,
298 IN ULONG UnicodeSize
,
299 OUT PULONG ResultSize
,
307 DPRINT1("RtlConsoleMultiByteToUnicodeN calling RtlMultiByteToUnicodeN\n");
309 return RtlMultiByteToUnicodeN(UnicodeString
,
323 RtlMultiByteToUnicodeSize(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
;
373 RtlOemToUnicodeN (PWCHAR UnicodeString
,
382 if (NlsMbOemCodePageTag
== FALSE
)
384 /* single-byte code page */
385 if (OemSize
> (UnicodeSize
/ sizeof(WCHAR
)))
386 Size
= UnicodeSize
/ sizeof(WCHAR
);
390 if (ResultSize
!= NULL
)
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
++];
432 if (ResultSize
!= NULL
)
433 *ResultSize
= i
* sizeof(WCHAR
);
436 return STATUS_SUCCESS
;
445 RtlResetRtlTranslations(IN PNLSTABLEINFO NlsTable
)
447 DPRINT("RtlResetRtlTranslations() called\n");
450 NlsAnsiToUnicodeTable
= (PWCHAR
)NlsTable
->AnsiTableInfo
.MultiByteTable
; /* Real type is PUSHORT */
451 NlsUnicodeToAnsiTable
= NlsTable
->AnsiTableInfo
.WideCharTable
;
452 NlsDbcsUnicodeToAnsiTable
= (PWCHAR
)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
= (PWCHAR
)NlsTable
->OemTableInfo
.MultiByteTable
; /* Real type is PUSHORT */
460 NlsUnicodeToOemTable
= NlsTable
->OemTableInfo
.WideCharTable
;
461 NlsDbcsUnicodeToOemTable
= (PWCHAR
)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
;
482 RtlUnicodeToCustomCPN(IN PCPTABLEINFO CustomCP
,
486 PWCHAR UnicodeString
,
492 if (CustomCP
->DBCSCodePage
== 0)
494 /* single-byte code page */
495 if (UnicodeSize
> (CustomSize
* sizeof(WCHAR
)))
498 Size
= UnicodeSize
/ sizeof(WCHAR
);
500 if (ResultSize
!= NULL
)
503 for (i
= 0; i
< Size
; i
++)
505 *CustomString
= ((PCHAR
)CustomCP
->WideCharTable
)[*UnicodeString
];
512 /* multi-byte code page */
517 return STATUS_SUCCESS
;
526 RtlUnicodeToMultiByteN (PCHAR MbString
,
537 if (NlsMbCodePageTag
== FALSE
)
539 /* single-byte code page */
540 Size
= (UnicodeSize
> (MbSize
* sizeof (WCHAR
)))
542 : (UnicodeSize
/ sizeof (WCHAR
));
544 if (ResultSize
!= NULL
)
549 for (i
= 0; i
< Size
; i
++)
551 *MbString
++ = NlsUnicodeToAnsiTable
[*UnicodeString
++];
556 /* multi-byte code page */
562 for (i
= MbSize
, Size
= UnicodeSize
/ sizeof(WCHAR
); i
&& Size
; i
--, Size
--)
564 WideChar
= *UnicodeString
++;
568 *MbString
++ = LOBYTE(WideChar
);
572 MbChar
= NlsDbcsUnicodeToAnsiTable
[WideChar
];
576 *MbString
++ = LOBYTE(MbChar
);
582 *MbString
++ = HIBYTE(MbChar
);
583 *MbString
++ = LOBYTE(MbChar
);
589 if (ResultSize
!= NULL
)
590 *ResultSize
= MbSize
- i
;
593 return STATUS_SUCCESS
;
601 RtlUnicodeToMultiByteSize(PULONG MbSize
,
605 ULONG UnicodeLength
= UnicodeSize
/ sizeof(WCHAR
);
608 if (!NlsMbCodePageTag
)
610 /* single-byte code page */
611 *MbSize
= UnicodeLength
;
615 /* multi-byte code page */
618 while (UnicodeLength
--)
620 USHORT WideChar
= *UnicodeString
++;
622 if (WideChar
>= 0x80 && HIBYTE(NlsDbcsUnicodeToAnsiTable
[WideChar
]))
624 MbLength
+= sizeof(WCHAR
);
636 return STATUS_SUCCESS
;
643 RtlUnicodeToOemN (PCHAR OemString
,
652 if (NlsMbOemCodePageTag
== FALSE
)
654 /* single-byte code page */
655 if (UnicodeSize
> (OemSize
* sizeof(WCHAR
)))
658 Size
= UnicodeSize
/ sizeof(WCHAR
);
660 if (ResultSize
!= NULL
)
663 for (i
= 0; i
< Size
; i
++)
665 *OemString
= NlsUnicodeToOemTable
[*UnicodeString
];
672 /* multi-byte code page */
678 for (i
= OemSize
, Size
= UnicodeSize
/ sizeof(WCHAR
); i
&& Size
; i
--, Size
--)
680 WideChar
= *UnicodeString
++;
684 *OemString
++ = LOBYTE(WideChar
);
688 OemChar
= NlsDbcsUnicodeToOemTable
[WideChar
];
690 if (!HIBYTE(OemChar
))
692 *OemString
++ = LOBYTE(OemChar
);
698 *OemString
++ = HIBYTE(OemChar
);
699 *OemString
++ = LOBYTE(OemChar
);
705 if (ResultSize
!= NULL
)
706 *ResultSize
= OemSize
- i
;
709 return STATUS_SUCCESS
;
719 RtlUpcaseUnicodeChar(IN WCHAR Source
)
727 return (Source
- ('a' - 'A'));
729 Offset
= ((USHORT
)Source
>> 8) & 0xFF;
730 Offset
= NlsUnicodeUpcaseTable
[Offset
];
732 Offset
+= ((USHORT
)Source
>> 4) & 0xF;
733 Offset
= NlsUnicodeUpcaseTable
[Offset
];
735 Offset
+= ((USHORT
)Source
& 0xF);
736 Offset
= NlsUnicodeUpcaseTable
[Offset
];
738 return Source
+ (SHORT
)Offset
;
747 RtlUpcaseUnicodeToCustomCPN (IN PCPTABLEINFO CustomCP
,
751 PWCHAR UnicodeString
,
758 if (CustomCP
->DBCSCodePage
== 0)
760 /* single-byte code page */
761 if (UnicodeSize
> (CustomSize
* sizeof(WCHAR
)))
764 Size
= UnicodeSize
/ sizeof(WCHAR
);
766 if (ResultSize
!= NULL
)
769 for (i
= 0; i
< Size
; i
++)
771 UpcaseChar
= RtlUpcaseUnicodeChar(*UnicodeString
);
772 *CustomString
= ((PCHAR
)CustomCP
->WideCharTable
)[UpcaseChar
];
779 /* multi-byte code page */
784 return STATUS_SUCCESS
;
792 RtlUpcaseUnicodeToMultiByteN (PCHAR MbString
,
802 if (NlsMbCodePageTag
== FALSE
)
804 /* single-byte code page */
805 if (UnicodeSize
> (MbSize
* sizeof(WCHAR
)))
808 Size
= UnicodeSize
/ sizeof(WCHAR
);
810 if (ResultSize
!= NULL
)
813 for (i
= 0; i
< Size
; i
++)
815 UpcaseChar
= RtlUpcaseUnicodeChar(*UnicodeString
);
816 *MbString
= NlsUnicodeToAnsiTable
[UpcaseChar
];
823 /* multi-byte code page */
828 return STATUS_SUCCESS
;
836 RtlUpcaseUnicodeToOemN (PCHAR OemString
,
846 ASSERT(NlsUnicodeToOemTable
!= NULL
);
848 if (NlsMbOemCodePageTag
== FALSE
)
850 /* single-byte code page */
851 if (UnicodeSize
> (OemSize
* sizeof(WCHAR
)))
854 Size
= UnicodeSize
/ sizeof(WCHAR
);
856 if (ResultSize
!= NULL
)
859 for (i
= 0; i
< Size
; i
++)
861 UpcaseChar
= RtlUpcaseUnicodeChar(*UnicodeString
);
862 *OemString
= NlsUnicodeToOemTable
[UpcaseChar
];
869 /* multi-byte code page */
875 for (i
= OemSize
, Size
= UnicodeSize
/ sizeof(WCHAR
); i
&& Size
; i
--, Size
--)
877 WideChar
= RtlUpcaseUnicodeChar(*UnicodeString
++);
881 *OemString
++ = LOBYTE(WideChar
);
885 OemChar
= NlsDbcsUnicodeToOemTable
[WideChar
];
887 if (!HIBYTE(OemChar
))
889 *OemString
++ = LOBYTE(OemChar
);
895 *OemString
++ = HIBYTE(OemChar
);
896 *OemString
++ = LOBYTE(OemChar
);
902 if (ResultSize
!= NULL
)
903 *ResultSize
= OemSize
- i
;
906 return STATUS_SUCCESS
;
915 RtlUpperChar (IN CHAR Source
)
920 /* Check for simple ANSI case */
923 /* Check for simple downcase a-z case */
926 /* Just XOR with the difference */
927 return Source
^ ('a' - 'A');
931 /* Otherwise return the same char, it's already upcase */
937 if (NlsMbCodePageTag
== FALSE
)
939 /* single-byte code page */
942 Unicode
= NlsAnsiToUnicodeTable
[(UCHAR
)Source
];
944 /* upcase conversion */
945 Unicode
= RtlUpcaseUnicodeChar (Unicode
);
947 /* unicode -> ansi */
948 Destination
= NlsUnicodeToAnsiTable
[(USHORT
)Unicode
];
952 /* multi-byte code page */
954 Destination
= Source
;