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 */
38 /* FUNCTIONS *****************************************************************/
44 RtlCustomCPToUnicodeN(IN PCPTABLEINFO CustomCP
,
54 if (CustomCP
->DBCSCodePage
== 0)
56 /* single-byte code page */
57 if (CustomSize
> (UnicodeSize
/ sizeof(WCHAR
)))
58 Size
= UnicodeSize
/ sizeof(WCHAR
);
62 if (ResultSize
!= NULL
)
63 *ResultSize
= Size
* sizeof(WCHAR
);
65 for (i
= 0; i
< Size
; i
++)
67 *UnicodeString
= CustomCP
->MultiByteTable
[(UCHAR
)*CustomString
];
74 /* multi-byte code page */
79 return(STATUS_SUCCESS
);
85 RtlDowncaseUnicodeChar (IN WCHAR Source
)
93 return Source
+ (L
'a' - L
'A');
98 Offset
= ((USHORT
)Source
>> 8);
99 DPRINT("Offset: %hx\n", Offset
);
101 Offset
= NlsUnicodeLowercaseTable
[Offset
];
102 DPRINT("Offset: %hx\n", Offset
);
104 Offset
+= (((USHORT
)Source
& 0x00F0) >> 4);
105 DPRINT("Offset: %hx\n", Offset
);
107 Offset
= NlsUnicodeLowercaseTable
[Offset
];
108 DPRINT("Offset: %hx\n", Offset
);
110 Offset
+= ((USHORT
)Source
& 0x000F);
111 DPRINT("Offset: %hx\n", Offset
);
113 Offset
= NlsUnicodeLowercaseTable
[Offset
];
114 DPRINT("Offset: %hx\n", Offset
);
116 DPRINT("Result: %hx\n", Source
+ (SHORT
)Offset
);
118 return Source
+ (SHORT
)Offset
;
128 RtlGetDefaultCodePage(OUT PUSHORT AnsiCodePage
,
129 OUT PUSHORT OemCodePage
)
131 *AnsiCodePage
= NlsAnsiCodePage
;
132 *OemCodePage
= NlsOemCodePage
;
142 RtlInitCodePageTable(IN PUSHORT TableBase
,
143 OUT PCPTABLEINFO CodePageTable
)
145 PNLS_FILE_HEADER NlsFileHeader
;
149 DPRINT("RtlInitCodePageTable() called\n");
151 NlsFileHeader
= (PNLS_FILE_HEADER
)TableBase
;
153 CodePageTable
->CodePage
= NlsFileHeader
->CodePage
;
154 CodePageTable
->MaximumCharacterSize
= NlsFileHeader
->MaximumCharacterSize
;
155 CodePageTable
->DefaultChar
= NlsFileHeader
->DefaultChar
;
156 CodePageTable
->UniDefaultChar
= NlsFileHeader
->UniDefaultChar
;
157 CodePageTable
->TransDefaultChar
= NlsFileHeader
->TransDefaultChar
;
158 CodePageTable
->TransUniDefaultChar
= NlsFileHeader
->TransUniDefaultChar
;
160 RtlCopyMemory(&CodePageTable
->LeadByte
,
161 &NlsFileHeader
->LeadByte
,
164 /* Set Pointer to start of multi byte table */
165 Ptr
= (PUSHORT
)((ULONG_PTR
)TableBase
+ 2 * NlsFileHeader
->HeaderSize
);
167 /* Get offset to the wide char table */
168 Offset
= (USHORT
)(*Ptr
++) + NlsFileHeader
->HeaderSize
+ 1;
170 /* Set pointer to the multi byte table */
171 CodePageTable
->MultiByteTable
= Ptr
;
173 /* Skip ANSI and OEM table */
178 /* Set pointer to DBCS ranges */
179 CodePageTable
->DBCSRanges
= (PUSHORT
)Ptr
;
183 CodePageTable
->DBCSCodePage
= 1;
184 CodePageTable
->DBCSOffsets
= (PUSHORT
)++Ptr
;
188 CodePageTable
->DBCSCodePage
= 0;
189 CodePageTable
->DBCSOffsets
= 0;
192 CodePageTable
->WideCharTable
= (PVOID
)((ULONG_PTR
)TableBase
+ 2 * Offset
);
202 RtlInitNlsTables(IN PUSHORT AnsiTableBase
,
203 IN PUSHORT OemTableBase
,
204 IN PUSHORT CaseTableBase
,
205 OUT PNLSTABLEINFO NlsTable
)
207 DPRINT("RtlInitNlsTables()called\n");
209 if (AnsiTableBase
== NULL
||
210 OemTableBase
== NULL
||
211 CaseTableBase
== NULL
)
214 RtlInitCodePageTable (AnsiTableBase
,
215 &NlsTable
->AnsiTableInfo
);
217 RtlInitCodePageTable (OemTableBase
,
218 &NlsTable
->OemTableInfo
);
220 NlsTable
->UpperCaseTable
= (PUSHORT
)CaseTableBase
+ 2;
221 NlsTable
->LowerCaseTable
= (PUSHORT
)CaseTableBase
+ *((PUSHORT
)CaseTableBase
+ 1) + 2;
229 RtlMultiByteToUnicodeN(
230 IN PWCHAR UnicodeString
,
231 IN ULONG UnicodeSize
,
232 IN PULONG ResultSize
,
239 if (NlsMbCodePageTag
== FALSE
)
241 /* single-byte code page */
242 if (MbSize
> (UnicodeSize
/ sizeof(WCHAR
)))
243 Size
= UnicodeSize
/ sizeof(WCHAR
);
247 if (ResultSize
!= NULL
)
248 *ResultSize
= Size
* sizeof(WCHAR
);
250 for (i
= 0; i
< Size
; i
++)
251 UnicodeString
[i
] = NlsAnsiToUnicodeTable
[(UCHAR
)MbString
[i
]];
255 /* multi-byte code page */
260 PCSTR MbEnd
= MbString
+ MbSize
;
262 for (i
= 0; i
< UnicodeSize
/ sizeof(WCHAR
) && MbString
< MbEnd
; i
++)
264 Char
= *(PUCHAR
)MbString
++;
268 *UnicodeString
++ = Char
;
272 LeadByteInfo
= NlsLeadByteInfo
[Char
];
276 *UnicodeString
++ = NlsAnsiToUnicodeTable
[Char
];
280 if (MbString
< MbEnd
)
281 *UnicodeString
++ = NlsLeadByteInfo
[LeadByteInfo
+ *(PUCHAR
)MbString
++];
284 if (ResultSize
!= NULL
)
285 *ResultSize
= i
* sizeof(WCHAR
);
288 return(STATUS_SUCCESS
);
298 RtlMultiByteToUnicodeSize(PULONG UnicodeSize
,
304 if (!NlsMbCodePageTag
)
306 /* single-byte code page */
307 *UnicodeSize
= MbSize
* sizeof (WCHAR
);
311 /* multi-byte code page */
316 UCHAR Char
= *(PUCHAR
)MbString
++;
318 if (Char
>= 0x80 && NlsLeadByteInfo
[Char
])
328 /* Increase returned size */
332 /* Return final size */
333 *UnicodeSize
= Length
* sizeof(WCHAR
);
337 return STATUS_SUCCESS
;
346 RtlOemToUnicodeN (PWCHAR UnicodeString
,
355 if (NlsMbOemCodePageTag
== FALSE
)
357 /* single-byte code page */
358 if (OemSize
> (UnicodeSize
/ sizeof(WCHAR
)))
359 Size
= UnicodeSize
/ sizeof(WCHAR
);
363 if (ResultSize
!= NULL
)
364 *ResultSize
= Size
* sizeof(WCHAR
);
366 for (i
= 0; i
< Size
; i
++)
368 *UnicodeString
= NlsOemToUnicodeTable
[(INT
)*OemString
];
375 /* multi-byte code page */
379 USHORT OemLeadByteInfo
;
380 PCHAR OemEnd
= OemString
+ OemSize
;
382 for (i
= 0; i
< UnicodeSize
/ sizeof(WCHAR
) && OemString
< OemEnd
; i
++)
384 Char
= *(PUCHAR
)OemString
++;
388 *UnicodeString
++ = Char
;
392 OemLeadByteInfo
= NlsOemLeadByteInfo
[Char
];
394 if (!OemLeadByteInfo
)
396 *UnicodeString
++ = NlsOemToUnicodeTable
[Char
];
400 if (OemString
< OemEnd
)
402 NlsOemLeadByteInfo
[OemLeadByteInfo
+ *(PUCHAR
)OemString
++];
405 if (ResultSize
!= NULL
)
406 *ResultSize
= i
* sizeof(WCHAR
);
409 return STATUS_SUCCESS
;
418 RtlResetRtlTranslations(IN PNLSTABLEINFO NlsTable
)
420 DPRINT("RtlResetRtlTranslations() called\n");
423 NlsAnsiToUnicodeTable
= (PWCHAR
)NlsTable
->AnsiTableInfo
.MultiByteTable
; /* Real type is PUSHORT */
424 NlsUnicodeToAnsiTable
= NlsTable
->AnsiTableInfo
.WideCharTable
;
425 NlsDbcsUnicodeToAnsiTable
= (PWCHAR
)NlsTable
->AnsiTableInfo
.WideCharTable
;
426 NlsMbCodePageTag
= (NlsTable
->AnsiTableInfo
.DBCSCodePage
!= 0);
427 NlsLeadByteInfo
= NlsTable
->AnsiTableInfo
.DBCSOffsets
;
428 NlsAnsiCodePage
= NlsTable
->AnsiTableInfo
.CodePage
;
429 DPRINT("Ansi codepage %hu\n", NlsAnsiCodePage
);
432 NlsOemToUnicodeTable
= (PWCHAR
)NlsTable
->OemTableInfo
.MultiByteTable
; /* Real type is PUSHORT */
433 NlsUnicodeToOemTable
= NlsTable
->OemTableInfo
.WideCharTable
;
434 NlsDbcsUnicodeToOemTable
= (PWCHAR
)NlsTable
->OemTableInfo
.WideCharTable
;
435 NlsMbOemCodePageTag
= (NlsTable
->OemTableInfo
.DBCSCodePage
!= 0);
436 NlsOemLeadByteInfo
= NlsTable
->OemTableInfo
.DBCSOffsets
;
437 NlsOemCodePage
= NlsTable
->OemTableInfo
.CodePage
;
438 DPRINT("Oem codepage %hu\n", NlsOemCodePage
);
440 /* Set Unicode case map data */
441 NlsUnicodeUpcaseTable
= NlsTable
->UpperCaseTable
;
442 NlsUnicodeLowercaseTable
= NlsTable
->LowerCaseTable
;
451 RtlUnicodeToCustomCPN(IN PCPTABLEINFO CustomCP
,
455 PWCHAR UnicodeString
,
461 if (CustomCP
->DBCSCodePage
== 0)
463 /* single-byte code page */
464 if (UnicodeSize
> (CustomSize
* sizeof(WCHAR
)))
467 Size
= UnicodeSize
/ sizeof(WCHAR
);
469 if (ResultSize
!= NULL
)
472 for (i
= 0; i
< Size
; i
++)
474 *CustomString
= ((PCHAR
)CustomCP
->WideCharTable
)[*UnicodeString
];
481 /* multi-byte code page */
486 return STATUS_SUCCESS
;
495 RtlUnicodeToMultiByteN (PCHAR MbString
,
498 PWCHAR UnicodeString
,
504 if (NlsMbCodePageTag
== FALSE
)
506 /* single-byte code page */
507 Size
= (UnicodeSize
> (MbSize
* sizeof (WCHAR
)))
509 : (UnicodeSize
/ sizeof (WCHAR
));
511 if (ResultSize
!= NULL
)
516 for (i
= 0; i
< Size
; i
++)
518 *MbString
++ = NlsUnicodeToAnsiTable
[*UnicodeString
++];
523 /* multi-byte code page */
529 for (i
= MbSize
, Size
= UnicodeSize
/ sizeof(WCHAR
); i
&& Size
; i
--, Size
--)
531 WideChar
= *UnicodeString
++;
535 *MbString
++ = LOBYTE(WideChar
);
539 MbChar
= NlsDbcsUnicodeToAnsiTable
[WideChar
];
543 *MbString
++ = LOBYTE(MbChar
);
549 *MbString
++ = HIBYTE(MbChar
);
550 *MbString
++ = LOBYTE(MbChar
);
556 if (ResultSize
!= NULL
)
557 *ResultSize
= MbSize
- i
;
560 return STATUS_SUCCESS
;
568 RtlUnicodeToMultiByteSize(PULONG MbSize
,
569 PWCHAR UnicodeString
,
572 ULONG UnicodeLength
= UnicodeSize
/ sizeof(WCHAR
);
575 if (!NlsMbCodePageTag
)
577 /* single-byte code page */
578 *MbSize
= UnicodeLength
;
582 /* multi-byte code page */
585 while (UnicodeLength
--)
587 USHORT WideChar
= *UnicodeString
++;
589 if (WideChar
>= 0x80 && HIBYTE(NlsDbcsUnicodeToAnsiTable
[WideChar
]))
591 MbLength
+= sizeof(WCHAR
);
603 return STATUS_SUCCESS
;
610 RtlUnicodeToOemN (PCHAR OemString
,
613 PWCHAR UnicodeString
,
619 if (NlsMbOemCodePageTag
== FALSE
)
621 /* single-byte code page */
622 if (UnicodeSize
> (OemSize
* sizeof(WCHAR
)))
625 Size
= UnicodeSize
/ sizeof(WCHAR
);
627 if (ResultSize
!= NULL
)
630 for (i
= 0; i
< Size
; i
++)
632 *OemString
= NlsUnicodeToOemTable
[*UnicodeString
];
639 /* multi-byte code page */
645 for (i
= OemSize
, Size
= UnicodeSize
/ sizeof(WCHAR
); i
&& Size
; i
--, Size
--)
647 WideChar
= *UnicodeString
++;
651 *OemString
++ = LOBYTE(WideChar
);
655 OemChar
= NlsDbcsUnicodeToOemTable
[WideChar
];
657 if (!HIBYTE(OemChar
))
659 *OemString
++ = LOBYTE(OemChar
);
665 *OemString
++ = HIBYTE(OemChar
);
666 *OemString
++ = LOBYTE(OemChar
);
672 if (ResultSize
!= NULL
)
673 *ResultSize
= OemSize
- i
;
676 return STATUS_SUCCESS
;
686 RtlUpcaseUnicodeChar(IN WCHAR Source
)
694 return (Source
- ('a' - 'A'));
696 Offset
= ((USHORT
)Source
>> 8) & 0xFF;
697 Offset
= NlsUnicodeUpcaseTable
[Offset
];
699 Offset
+= ((USHORT
)Source
>> 4) & 0xF;
700 Offset
= NlsUnicodeUpcaseTable
[Offset
];
702 Offset
+= ((USHORT
)Source
& 0xF);
703 Offset
= NlsUnicodeUpcaseTable
[Offset
];
705 return Source
+ (SHORT
)Offset
;
714 RtlUpcaseUnicodeToCustomCPN (IN PCPTABLEINFO CustomCP
,
718 PWCHAR UnicodeString
,
725 if (CustomCP
->DBCSCodePage
== 0)
727 /* single-byte code page */
728 if (UnicodeSize
> (CustomSize
* sizeof(WCHAR
)))
731 Size
= UnicodeSize
/ sizeof(WCHAR
);
733 if (ResultSize
!= NULL
)
736 for (i
= 0; i
< Size
; i
++)
738 UpcaseChar
= RtlUpcaseUnicodeChar(*UnicodeString
);
739 *CustomString
= ((PCHAR
)CustomCP
->WideCharTable
)[UpcaseChar
];
746 /* multi-byte code page */
751 return STATUS_SUCCESS
;
759 RtlUpcaseUnicodeToMultiByteN (PCHAR MbString
,
762 PWCHAR UnicodeString
,
769 if (NlsMbCodePageTag
== FALSE
)
771 /* single-byte code page */
772 if (UnicodeSize
> (MbSize
* sizeof(WCHAR
)))
775 Size
= UnicodeSize
/ sizeof(WCHAR
);
777 if (ResultSize
!= NULL
)
780 for (i
= 0; i
< Size
; i
++)
782 UpcaseChar
= RtlUpcaseUnicodeChar(*UnicodeString
);
783 *MbString
= NlsUnicodeToAnsiTable
[UpcaseChar
];
790 /* multi-byte code page */
795 return STATUS_SUCCESS
;
803 RtlUpcaseUnicodeToOemN (PCHAR OemString
,
806 PWCHAR UnicodeString
,
813 ASSERT(NlsUnicodeToOemTable
!= NULL
);
815 if (NlsMbOemCodePageTag
== FALSE
)
817 /* single-byte code page */
818 if (UnicodeSize
> (OemSize
* sizeof(WCHAR
)))
821 Size
= UnicodeSize
/ sizeof(WCHAR
);
823 if (ResultSize
!= NULL
)
826 for (i
= 0; i
< Size
; i
++)
828 UpcaseChar
= RtlUpcaseUnicodeChar(*UnicodeString
);
829 *OemString
= NlsUnicodeToOemTable
[UpcaseChar
];
836 /* multi-byte code page */
842 for (i
= OemSize
, Size
= UnicodeSize
/ sizeof(WCHAR
); i
&& Size
; i
--, Size
--)
844 WideChar
= RtlUpcaseUnicodeChar(*UnicodeString
++);
848 *OemString
++ = LOBYTE(WideChar
);
852 OemChar
= NlsDbcsUnicodeToOemTable
[WideChar
];
854 if (!HIBYTE(OemChar
))
856 *OemString
++ = LOBYTE(OemChar
);
862 *OemString
++ = HIBYTE(OemChar
);
863 *OemString
++ = LOBYTE(OemChar
);
869 if (ResultSize
!= NULL
)
870 *ResultSize
= OemSize
- i
;
873 return STATUS_SUCCESS
;
882 RtlUpperChar (IN CHAR Source
)
887 /* Check for simple ANSI case */
890 /* Check for simple downcase a-z case */
893 /* Just XOR with the difference */
894 return Source
^ ('a' - 'A');
898 /* Otherwise return the same char, it's already upcase */
904 if (NlsMbCodePageTag
== FALSE
)
906 /* single-byte code page */
909 Unicode
= NlsAnsiToUnicodeTable
[(UCHAR
)Source
];
911 /* upcase conversion */
912 Unicode
= RtlUpcaseUnicodeChar (Unicode
);
914 /* unicode -> ansi */
915 Destination
= NlsUnicodeToAnsiTable
[(USHORT
)Unicode
];
919 /* multi-byte code page */
921 Destination
= Source
;