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
;
297 RtlMultiByteToUnicodeSize(PULONG UnicodeSize
,
305 if (!NlsMbCodePageTag
)
307 /* single-byte code page */
308 *UnicodeSize
= MbSize
* sizeof (WCHAR
);
312 /* multi-byte code page */
317 UCHAR Char
= *(PUCHAR
)MbString
++;
319 if (Char
>= 0x80 && NlsLeadByteInfo
[Char
])
329 /* Increase returned size */
333 /* Return final size */
334 *UnicodeSize
= Length
* sizeof(WCHAR
);
338 return STATUS_SUCCESS
;
347 RtlOemToUnicodeN (PWCHAR UnicodeString
,
356 if (NlsMbOemCodePageTag
== FALSE
)
358 /* single-byte code page */
359 if (OemSize
> (UnicodeSize
/ sizeof(WCHAR
)))
360 Size
= UnicodeSize
/ sizeof(WCHAR
);
364 if (ResultSize
!= NULL
)
365 *ResultSize
= Size
* sizeof(WCHAR
);
367 for (i
= 0; i
< Size
; i
++)
369 *UnicodeString
= NlsOemToUnicodeTable
[(UCHAR
)*OemString
];
376 /* multi-byte code page */
380 USHORT OemLeadByteInfo
;
381 PCCH OemEnd
= OemString
+ OemSize
;
383 for (i
= 0; i
< UnicodeSize
/ sizeof(WCHAR
) && OemString
< OemEnd
; i
++)
385 Char
= *(PUCHAR
)OemString
++;
389 *UnicodeString
++ = Char
;
393 OemLeadByteInfo
= NlsOemLeadByteInfo
[Char
];
395 if (!OemLeadByteInfo
)
397 *UnicodeString
++ = NlsOemToUnicodeTable
[Char
];
401 if (OemString
< OemEnd
)
403 NlsOemLeadByteInfo
[OemLeadByteInfo
+ *(PUCHAR
)OemString
++];
406 if (ResultSize
!= NULL
)
407 *ResultSize
= i
* sizeof(WCHAR
);
410 return STATUS_SUCCESS
;
419 RtlResetRtlTranslations(IN PNLSTABLEINFO NlsTable
)
421 DPRINT("RtlResetRtlTranslations() called\n");
424 NlsAnsiToUnicodeTable
= (PWCHAR
)NlsTable
->AnsiTableInfo
.MultiByteTable
; /* Real type is PUSHORT */
425 NlsUnicodeToAnsiTable
= NlsTable
->AnsiTableInfo
.WideCharTable
;
426 NlsDbcsUnicodeToAnsiTable
= (PWCHAR
)NlsTable
->AnsiTableInfo
.WideCharTable
;
427 NlsMbCodePageTag
= (NlsTable
->AnsiTableInfo
.DBCSCodePage
!= 0);
428 NlsLeadByteInfo
= NlsTable
->AnsiTableInfo
.DBCSOffsets
;
429 NlsAnsiCodePage
= NlsTable
->AnsiTableInfo
.CodePage
;
430 DPRINT("Ansi codepage %hu\n", NlsAnsiCodePage
);
433 NlsOemToUnicodeTable
= (PWCHAR
)NlsTable
->OemTableInfo
.MultiByteTable
; /* Real type is PUSHORT */
434 NlsUnicodeToOemTable
= NlsTable
->OemTableInfo
.WideCharTable
;
435 NlsDbcsUnicodeToOemTable
= (PWCHAR
)NlsTable
->OemTableInfo
.WideCharTable
;
436 NlsMbOemCodePageTag
= (NlsTable
->OemTableInfo
.DBCSCodePage
!= 0);
437 NlsOemLeadByteInfo
= NlsTable
->OemTableInfo
.DBCSOffsets
;
438 NlsOemCodePage
= NlsTable
->OemTableInfo
.CodePage
;
439 DPRINT("Oem codepage %hu\n", NlsOemCodePage
);
441 /* Set Unicode case map data */
442 NlsUnicodeUpcaseTable
= NlsTable
->UpperCaseTable
;
443 NlsUnicodeLowercaseTable
= NlsTable
->LowerCaseTable
;
445 /* set the default characters for RtlpDidUnicodeToOemWork */
446 NlsOemDefaultChar
= NlsTable
->OemTableInfo
.DefaultChar
;
447 NlsUnicodeDefaultChar
= NlsTable
->OemTableInfo
.TransDefaultChar
;
456 RtlUnicodeToCustomCPN(IN PCPTABLEINFO CustomCP
,
460 PWCHAR UnicodeString
,
466 if (CustomCP
->DBCSCodePage
== 0)
468 /* single-byte code page */
469 if (UnicodeSize
> (CustomSize
* sizeof(WCHAR
)))
472 Size
= UnicodeSize
/ sizeof(WCHAR
);
474 if (ResultSize
!= NULL
)
477 for (i
= 0; i
< Size
; i
++)
479 *CustomString
= ((PCHAR
)CustomCP
->WideCharTable
)[*UnicodeString
];
486 /* multi-byte code page */
491 return STATUS_SUCCESS
;
500 RtlUnicodeToMultiByteN (PCHAR MbString
,
511 if (NlsMbCodePageTag
== FALSE
)
513 /* single-byte code page */
514 Size
= (UnicodeSize
> (MbSize
* sizeof (WCHAR
)))
516 : (UnicodeSize
/ sizeof (WCHAR
));
518 if (ResultSize
!= NULL
)
523 for (i
= 0; i
< Size
; i
++)
525 *MbString
++ = NlsUnicodeToAnsiTable
[*UnicodeString
++];
530 /* multi-byte code page */
536 for (i
= MbSize
, Size
= UnicodeSize
/ sizeof(WCHAR
); i
&& Size
; i
--, Size
--)
538 WideChar
= *UnicodeString
++;
542 *MbString
++ = LOBYTE(WideChar
);
546 MbChar
= NlsDbcsUnicodeToAnsiTable
[WideChar
];
550 *MbString
++ = LOBYTE(MbChar
);
556 *MbString
++ = HIBYTE(MbChar
);
557 *MbString
++ = LOBYTE(MbChar
);
563 if (ResultSize
!= NULL
)
564 *ResultSize
= MbSize
- i
;
567 return STATUS_SUCCESS
;
575 RtlUnicodeToMultiByteSize(PULONG MbSize
,
579 ULONG UnicodeLength
= UnicodeSize
/ sizeof(WCHAR
);
582 if (!NlsMbCodePageTag
)
584 /* single-byte code page */
585 *MbSize
= UnicodeLength
;
589 /* multi-byte code page */
592 while (UnicodeLength
--)
594 USHORT WideChar
= *UnicodeString
++;
596 if (WideChar
>= 0x80 && HIBYTE(NlsDbcsUnicodeToAnsiTable
[WideChar
]))
598 MbLength
+= sizeof(WCHAR
);
610 return STATUS_SUCCESS
;
617 RtlUnicodeToOemN (PCHAR OemString
,
626 if (NlsMbOemCodePageTag
== FALSE
)
628 /* single-byte code page */
629 if (UnicodeSize
> (OemSize
* sizeof(WCHAR
)))
632 Size
= UnicodeSize
/ sizeof(WCHAR
);
634 if (ResultSize
!= NULL
)
637 for (i
= 0; i
< Size
; i
++)
639 *OemString
= NlsUnicodeToOemTable
[*UnicodeString
];
646 /* multi-byte code page */
652 for (i
= OemSize
, Size
= UnicodeSize
/ sizeof(WCHAR
); i
&& Size
; i
--, Size
--)
654 WideChar
= *UnicodeString
++;
658 *OemString
++ = LOBYTE(WideChar
);
662 OemChar
= NlsDbcsUnicodeToOemTable
[WideChar
];
664 if (!HIBYTE(OemChar
))
666 *OemString
++ = LOBYTE(OemChar
);
672 *OemString
++ = HIBYTE(OemChar
);
673 *OemString
++ = LOBYTE(OemChar
);
679 if (ResultSize
!= NULL
)
680 *ResultSize
= OemSize
- i
;
683 return STATUS_SUCCESS
;
693 RtlUpcaseUnicodeChar(IN WCHAR Source
)
701 return (Source
- ('a' - 'A'));
703 Offset
= ((USHORT
)Source
>> 8) & 0xFF;
704 Offset
= NlsUnicodeUpcaseTable
[Offset
];
706 Offset
+= ((USHORT
)Source
>> 4) & 0xF;
707 Offset
= NlsUnicodeUpcaseTable
[Offset
];
709 Offset
+= ((USHORT
)Source
& 0xF);
710 Offset
= NlsUnicodeUpcaseTable
[Offset
];
712 return Source
+ (SHORT
)Offset
;
721 RtlUpcaseUnicodeToCustomCPN (IN PCPTABLEINFO CustomCP
,
725 PWCHAR UnicodeString
,
732 if (CustomCP
->DBCSCodePage
== 0)
734 /* single-byte code page */
735 if (UnicodeSize
> (CustomSize
* sizeof(WCHAR
)))
738 Size
= UnicodeSize
/ sizeof(WCHAR
);
740 if (ResultSize
!= NULL
)
743 for (i
= 0; i
< Size
; i
++)
745 UpcaseChar
= RtlUpcaseUnicodeChar(*UnicodeString
);
746 *CustomString
= ((PCHAR
)CustomCP
->WideCharTable
)[UpcaseChar
];
753 /* multi-byte code page */
758 return STATUS_SUCCESS
;
766 RtlUpcaseUnicodeToMultiByteN (PCHAR MbString
,
776 if (NlsMbCodePageTag
== FALSE
)
778 /* single-byte code page */
779 if (UnicodeSize
> (MbSize
* sizeof(WCHAR
)))
782 Size
= UnicodeSize
/ sizeof(WCHAR
);
784 if (ResultSize
!= NULL
)
787 for (i
= 0; i
< Size
; i
++)
789 UpcaseChar
= RtlUpcaseUnicodeChar(*UnicodeString
);
790 *MbString
= NlsUnicodeToAnsiTable
[UpcaseChar
];
797 /* multi-byte code page */
802 return STATUS_SUCCESS
;
810 RtlUpcaseUnicodeToOemN (PCHAR OemString
,
820 ASSERT(NlsUnicodeToOemTable
!= NULL
);
822 if (NlsMbOemCodePageTag
== FALSE
)
824 /* single-byte code page */
825 if (UnicodeSize
> (OemSize
* sizeof(WCHAR
)))
828 Size
= UnicodeSize
/ sizeof(WCHAR
);
830 if (ResultSize
!= NULL
)
833 for (i
= 0; i
< Size
; i
++)
835 UpcaseChar
= RtlUpcaseUnicodeChar(*UnicodeString
);
836 *OemString
= NlsUnicodeToOemTable
[UpcaseChar
];
843 /* multi-byte code page */
849 for (i
= OemSize
, Size
= UnicodeSize
/ sizeof(WCHAR
); i
&& Size
; i
--, Size
--)
851 WideChar
= RtlUpcaseUnicodeChar(*UnicodeString
++);
855 *OemString
++ = LOBYTE(WideChar
);
859 OemChar
= NlsDbcsUnicodeToOemTable
[WideChar
];
861 if (!HIBYTE(OemChar
))
863 *OemString
++ = LOBYTE(OemChar
);
869 *OemString
++ = HIBYTE(OemChar
);
870 *OemString
++ = LOBYTE(OemChar
);
876 if (ResultSize
!= NULL
)
877 *ResultSize
= OemSize
- i
;
880 return STATUS_SUCCESS
;
889 RtlUpperChar (IN CHAR Source
)
894 /* Check for simple ANSI case */
897 /* Check for simple downcase a-z case */
900 /* Just XOR with the difference */
901 return Source
^ ('a' - 'A');
905 /* Otherwise return the same char, it's already upcase */
911 if (NlsMbCodePageTag
== FALSE
)
913 /* single-byte code page */
916 Unicode
= NlsAnsiToUnicodeTable
[(UCHAR
)Source
];
918 /* upcase conversion */
919 Unicode
= RtlUpcaseUnicodeChar (Unicode
);
921 /* unicode -> ansi */
922 Destination
= NlsUnicodeToAnsiTable
[(USHORT
)Unicode
];
926 /* multi-byte code page */
928 Destination
= Source
;