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 /* FUNCTIONS *****************************************************************/
46 RtlCustomCPToUnicodeN(IN PCPTABLEINFO CustomCP
,
56 if (CustomCP
->DBCSCodePage
== 0)
58 /* single-byte code page */
59 if (CustomSize
> (UnicodeSize
/ sizeof(WCHAR
)))
60 Size
= UnicodeSize
/ sizeof(WCHAR
);
64 if (ResultSize
!= NULL
)
65 *ResultSize
= Size
* sizeof(WCHAR
);
67 for (i
= 0; i
< Size
; i
++)
69 *UnicodeString
= CustomCP
->MultiByteTable
[(UCHAR
)*CustomString
];
76 /* multi-byte code page */
81 return(STATUS_SUCCESS
);
87 RtlDowncaseUnicodeChar (IN WCHAR Source
)
95 return Source
+ (L
'a' - L
'A');
100 Offset
= ((USHORT
)Source
>> 8);
101 DPRINT("Offset: %hx\n", Offset
);
103 Offset
= NlsUnicodeLowercaseTable
[Offset
];
104 DPRINT("Offset: %hx\n", Offset
);
106 Offset
+= (((USHORT
)Source
& 0x00F0) >> 4);
107 DPRINT("Offset: %hx\n", Offset
);
109 Offset
= NlsUnicodeLowercaseTable
[Offset
];
110 DPRINT("Offset: %hx\n", Offset
);
112 Offset
+= ((USHORT
)Source
& 0x000F);
113 DPRINT("Offset: %hx\n", Offset
);
115 Offset
= NlsUnicodeLowercaseTable
[Offset
];
116 DPRINT("Offset: %hx\n", Offset
);
118 DPRINT("Result: %hx\n", Source
+ (SHORT
)Offset
);
120 return Source
+ (SHORT
)Offset
;
130 RtlGetDefaultCodePage(OUT PUSHORT AnsiCodePage
,
131 OUT PUSHORT OemCodePage
)
133 *AnsiCodePage
= NlsAnsiCodePage
;
134 *OemCodePage
= NlsOemCodePage
;
144 RtlInitCodePageTable(IN PUSHORT TableBase
,
145 OUT PCPTABLEINFO CodePageTable
)
147 PNLS_FILE_HEADER NlsFileHeader
;
149 DPRINT("RtlInitCodePageTable() called\n");
151 NlsFileHeader
= (PNLS_FILE_HEADER
)TableBase
;
153 /* Copy header fields first */
154 CodePageTable
->CodePage
= NlsFileHeader
->CodePage
;
155 CodePageTable
->MaximumCharacterSize
= NlsFileHeader
->MaximumCharacterSize
;
156 CodePageTable
->DefaultChar
= NlsFileHeader
->DefaultChar
;
157 CodePageTable
->UniDefaultChar
= NlsFileHeader
->UniDefaultChar
;
158 CodePageTable
->TransDefaultChar
= NlsFileHeader
->TransDefaultChar
;
159 CodePageTable
->TransUniDefaultChar
= NlsFileHeader
->TransUniDefaultChar
;
161 RtlCopyMemory(&CodePageTable
->LeadByte
,
162 &NlsFileHeader
->LeadByte
,
165 /* Offset to wide char table is after the header */
166 CodePageTable
->WideCharTable
= TableBase
+ NlsFileHeader
->HeaderSize
+ 1 +
167 TableBase
[NlsFileHeader
->HeaderSize
];
169 /* Then multibyte table (256 wchars) follows */
170 CodePageTable
->MultiByteTable
= TableBase
+ NlsFileHeader
->HeaderSize
+ 1;
172 /* Check the presence of glyph table (256 wchars) */
173 if (!CodePageTable
->MultiByteTable
[256])
174 CodePageTable
->DBCSRanges
= CodePageTable
->MultiByteTable
+ 256 + 1;
176 CodePageTable
->DBCSRanges
= CodePageTable
->MultiByteTable
+ 256 + 1 + 256;
178 /* Is this double-byte code page? */
179 if (*CodePageTable
->DBCSRanges
)
181 CodePageTable
->DBCSCodePage
= 1;
182 CodePageTable
->DBCSOffsets
= CodePageTable
->DBCSRanges
+ 1;
186 CodePageTable
->DBCSCodePage
= 0;
187 CodePageTable
->DBCSOffsets
= NULL
;
198 RtlInitNlsTables(IN PUSHORT AnsiTableBase
,
199 IN PUSHORT OemTableBase
,
200 IN PUSHORT CaseTableBase
,
201 OUT PNLSTABLEINFO NlsTable
)
203 DPRINT("RtlInitNlsTables()called\n");
205 if (AnsiTableBase
== NULL
||
206 OemTableBase
== NULL
||
207 CaseTableBase
== NULL
)
210 RtlInitCodePageTable(AnsiTableBase
, &NlsTable
->AnsiTableInfo
);
212 RtlInitCodePageTable(OemTableBase
, &NlsTable
->OemTableInfo
);
214 NlsTable
->UpperCaseTable
= (PUSHORT
)CaseTableBase
+ 2;
215 NlsTable
->LowerCaseTable
= (PUSHORT
)CaseTableBase
+ *((PUSHORT
)CaseTableBase
+ 1) + 2;
223 RtlMultiByteToUnicodeN(
224 OUT PWCHAR UnicodeString
,
225 IN ULONG UnicodeSize
,
226 OUT PULONG ResultSize
,
235 if (NlsMbCodePageTag
== FALSE
)
237 /* single-byte code page */
238 if (MbSize
> (UnicodeSize
/ sizeof(WCHAR
)))
239 Size
= UnicodeSize
/ sizeof(WCHAR
);
243 if (ResultSize
!= NULL
)
244 *ResultSize
= Size
* sizeof(WCHAR
);
246 for (i
= 0; i
< Size
; i
++)
247 UnicodeString
[i
] = NlsAnsiToUnicodeTable
[(UCHAR
)MbString
[i
]];
251 /* multi-byte code page */
256 PCSTR MbEnd
= MbString
+ MbSize
;
258 for (i
= 0; i
< UnicodeSize
/ sizeof(WCHAR
) && MbString
< MbEnd
; i
++)
260 Char
= *(PUCHAR
)MbString
++;
264 *UnicodeString
++ = Char
;
268 LeadByteInfo
= NlsLeadByteInfo
[Char
];
272 *UnicodeString
++ = NlsAnsiToUnicodeTable
[Char
];
276 if (MbString
< MbEnd
)
277 *UnicodeString
++ = NlsLeadByteInfo
[LeadByteInfo
+ *(PUCHAR
)MbString
++];
280 if (ResultSize
!= NULL
)
281 *ResultSize
= i
* sizeof(WCHAR
);
284 return STATUS_SUCCESS
;
293 RtlConsoleMultiByteToUnicodeN(
294 OUT PWCHAR UnicodeString
,
295 IN ULONG UnicodeSize
,
296 OUT PULONG ResultSize
,
304 DPRINT1("RtlConsoleMultiByteToUnicodeN calling RtlMultiByteToUnicodeN\n");
306 return RtlMultiByteToUnicodeN(UnicodeString
,
320 RtlMultiByteToUnicodeSize(PULONG UnicodeSize
,
328 if (!NlsMbCodePageTag
)
330 /* single-byte code page */
331 *UnicodeSize
= MbSize
* sizeof (WCHAR
);
335 /* multi-byte code page */
340 UCHAR Char
= *(PUCHAR
)MbString
++;
342 if (Char
>= 0x80 && NlsLeadByteInfo
[Char
])
352 /* Increase returned size */
356 /* Return final size */
357 *UnicodeSize
= Length
* sizeof(WCHAR
);
361 return STATUS_SUCCESS
;
370 RtlOemToUnicodeN (PWCHAR UnicodeString
,
379 if (NlsMbOemCodePageTag
== FALSE
)
381 /* single-byte code page */
382 if (OemSize
> (UnicodeSize
/ sizeof(WCHAR
)))
383 Size
= UnicodeSize
/ sizeof(WCHAR
);
387 if (ResultSize
!= NULL
)
388 *ResultSize
= Size
* sizeof(WCHAR
);
390 for (i
= 0; i
< Size
; i
++)
392 *UnicodeString
= NlsOemToUnicodeTable
[(UCHAR
)*OemString
];
399 /* multi-byte code page */
403 USHORT OemLeadByteInfo
;
404 PCCH OemEnd
= OemString
+ OemSize
;
406 for (i
= 0; i
< UnicodeSize
/ sizeof(WCHAR
) && OemString
< OemEnd
; i
++)
408 Char
= *(PUCHAR
)OemString
++;
412 *UnicodeString
++ = Char
;
416 OemLeadByteInfo
= NlsOemLeadByteInfo
[Char
];
418 if (!OemLeadByteInfo
)
420 *UnicodeString
++ = NlsOemToUnicodeTable
[Char
];
424 if (OemString
< OemEnd
)
426 NlsOemLeadByteInfo
[OemLeadByteInfo
+ *(PUCHAR
)OemString
++];
429 if (ResultSize
!= NULL
)
430 *ResultSize
= i
* sizeof(WCHAR
);
433 return STATUS_SUCCESS
;
442 RtlResetRtlTranslations(IN PNLSTABLEINFO NlsTable
)
444 DPRINT("RtlResetRtlTranslations() called\n");
447 NlsAnsiToUnicodeTable
= (PWCHAR
)NlsTable
->AnsiTableInfo
.MultiByteTable
; /* Real type is PUSHORT */
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
= (PWCHAR
)NlsTable
->OemTableInfo
.MultiByteTable
; /* Real type is PUSHORT */
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
;
468 /* set the default characters for RtlpDidUnicodeToOemWork */
469 NlsOemDefaultChar
= NlsTable
->OemTableInfo
.DefaultChar
;
470 NlsUnicodeDefaultChar
= NlsTable
->OemTableInfo
.TransDefaultChar
;
479 RtlUnicodeToCustomCPN(IN PCPTABLEINFO CustomCP
,
483 PWCHAR UnicodeString
,
489 if (CustomCP
->DBCSCodePage
== 0)
491 /* single-byte code page */
492 if (UnicodeSize
> (CustomSize
* sizeof(WCHAR
)))
495 Size
= UnicodeSize
/ sizeof(WCHAR
);
497 if (ResultSize
!= NULL
)
500 for (i
= 0; i
< Size
; i
++)
502 *CustomString
= ((PCHAR
)CustomCP
->WideCharTable
)[*UnicodeString
];
509 /* multi-byte code page */
514 return STATUS_SUCCESS
;
523 RtlUnicodeToMultiByteN (PCHAR MbString
,
534 if (NlsMbCodePageTag
== FALSE
)
536 /* single-byte code page */
537 Size
= (UnicodeSize
> (MbSize
* sizeof (WCHAR
)))
539 : (UnicodeSize
/ sizeof (WCHAR
));
541 if (ResultSize
!= NULL
)
546 for (i
= 0; i
< Size
; i
++)
548 *MbString
++ = NlsUnicodeToAnsiTable
[*UnicodeString
++];
553 /* multi-byte code page */
559 for (i
= MbSize
, Size
= UnicodeSize
/ sizeof(WCHAR
); i
&& Size
; i
--, Size
--)
561 WideChar
= *UnicodeString
++;
565 *MbString
++ = LOBYTE(WideChar
);
569 MbChar
= NlsDbcsUnicodeToAnsiTable
[WideChar
];
573 *MbString
++ = LOBYTE(MbChar
);
579 *MbString
++ = HIBYTE(MbChar
);
580 *MbString
++ = LOBYTE(MbChar
);
586 if (ResultSize
!= NULL
)
587 *ResultSize
= MbSize
- i
;
590 return STATUS_SUCCESS
;
598 RtlUnicodeToMultiByteSize(PULONG MbSize
,
602 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(NlsDbcsUnicodeToAnsiTable
[WideChar
]))
621 MbLength
+= sizeof(WCHAR
);
633 return STATUS_SUCCESS
;
640 RtlUnicodeToOemN (PCHAR OemString
,
649 if (NlsMbOemCodePageTag
== FALSE
)
651 /* single-byte code page */
652 if (UnicodeSize
> (OemSize
* sizeof(WCHAR
)))
655 Size
= UnicodeSize
/ sizeof(WCHAR
);
657 if (ResultSize
!= NULL
)
660 for (i
= 0; i
< Size
; i
++)
662 *OemString
= NlsUnicodeToOemTable
[*UnicodeString
];
669 /* multi-byte code page */
675 for (i
= OemSize
, Size
= UnicodeSize
/ sizeof(WCHAR
); i
&& Size
; i
--, Size
--)
677 WideChar
= *UnicodeString
++;
681 *OemString
++ = LOBYTE(WideChar
);
685 OemChar
= NlsDbcsUnicodeToOemTable
[WideChar
];
687 if (!HIBYTE(OemChar
))
689 *OemString
++ = LOBYTE(OemChar
);
695 *OemString
++ = HIBYTE(OemChar
);
696 *OemString
++ = LOBYTE(OemChar
);
702 if (ResultSize
!= NULL
)
703 *ResultSize
= OemSize
- i
;
706 return STATUS_SUCCESS
;
716 RtlUpcaseUnicodeChar(IN WCHAR Source
)
724 return (Source
- ('a' - 'A'));
726 Offset
= ((USHORT
)Source
>> 8) & 0xFF;
727 Offset
= NlsUnicodeUpcaseTable
[Offset
];
729 Offset
+= ((USHORT
)Source
>> 4) & 0xF;
730 Offset
= NlsUnicodeUpcaseTable
[Offset
];
732 Offset
+= ((USHORT
)Source
& 0xF);
733 Offset
= NlsUnicodeUpcaseTable
[Offset
];
735 return Source
+ (SHORT
)Offset
;
744 RtlUpcaseUnicodeToCustomCPN (IN PCPTABLEINFO CustomCP
,
748 PWCHAR UnicodeString
,
755 if (CustomCP
->DBCSCodePage
== 0)
757 /* single-byte code page */
758 if (UnicodeSize
> (CustomSize
* sizeof(WCHAR
)))
761 Size
= UnicodeSize
/ sizeof(WCHAR
);
763 if (ResultSize
!= NULL
)
766 for (i
= 0; i
< Size
; i
++)
768 UpcaseChar
= RtlUpcaseUnicodeChar(*UnicodeString
);
769 *CustomString
= ((PCHAR
)CustomCP
->WideCharTable
)[UpcaseChar
];
776 /* multi-byte code page */
781 return STATUS_SUCCESS
;
789 RtlUpcaseUnicodeToMultiByteN (PCHAR MbString
,
799 if (NlsMbCodePageTag
== FALSE
)
801 /* single-byte code page */
802 if (UnicodeSize
> (MbSize
* sizeof(WCHAR
)))
805 Size
= UnicodeSize
/ sizeof(WCHAR
);
807 if (ResultSize
!= NULL
)
810 for (i
= 0; i
< Size
; i
++)
812 UpcaseChar
= RtlUpcaseUnicodeChar(*UnicodeString
);
813 *MbString
= NlsUnicodeToAnsiTable
[UpcaseChar
];
820 /* multi-byte code page */
825 return STATUS_SUCCESS
;
833 RtlUpcaseUnicodeToOemN (PCHAR OemString
,
843 ASSERT(NlsUnicodeToOemTable
!= NULL
);
845 if (NlsMbOemCodePageTag
== FALSE
)
847 /* single-byte code page */
848 if (UnicodeSize
> (OemSize
* sizeof(WCHAR
)))
851 Size
= UnicodeSize
/ sizeof(WCHAR
);
853 if (ResultSize
!= NULL
)
856 for (i
= 0; i
< Size
; i
++)
858 UpcaseChar
= RtlUpcaseUnicodeChar(*UnicodeString
);
859 *OemString
= NlsUnicodeToOemTable
[UpcaseChar
];
866 /* multi-byte code page */
872 for (i
= OemSize
, Size
= UnicodeSize
/ sizeof(WCHAR
); i
&& Size
; i
--, Size
--)
874 WideChar
= RtlUpcaseUnicodeChar(*UnicodeString
++);
878 *OemString
++ = LOBYTE(WideChar
);
882 OemChar
= NlsDbcsUnicodeToOemTable
[WideChar
];
884 if (!HIBYTE(OemChar
))
886 *OemString
++ = LOBYTE(OemChar
);
892 *OemString
++ = HIBYTE(OemChar
);
893 *OemString
++ = LOBYTE(OemChar
);
899 if (ResultSize
!= NULL
)
900 *ResultSize
= OemSize
- i
;
903 return STATUS_SUCCESS
;
912 RtlUpperChar (IN CHAR Source
)
917 /* Check for simple ANSI case */
920 /* Check for simple downcase a-z case */
923 /* Just XOR with the difference */
924 return Source
^ ('a' - 'A');
928 /* Otherwise return the same char, it's already upcase */
934 if (NlsMbCodePageTag
== FALSE
)
936 /* single-byte code page */
939 Unicode
= NlsAnsiToUnicodeTable
[(UCHAR
)Source
];
941 /* upcase conversion */
942 Unicode
= RtlUpcaseUnicodeChar (Unicode
);
944 /* unicode -> ansi */
945 Destination
= NlsUnicodeToAnsiTable
[(USHORT
)Unicode
];
949 /* multi-byte code page */
951 Destination
= Source
;