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
,
214 &NlsTable
->AnsiTableInfo
);
216 RtlInitCodePageTable (OemTableBase
,
217 &NlsTable
->OemTableInfo
);
219 NlsTable
->UpperCaseTable
= (PUSHORT
)CaseTableBase
+ 2;
220 NlsTable
->LowerCaseTable
= (PUSHORT
)CaseTableBase
+ *((PUSHORT
)CaseTableBase
+ 1) + 2;
228 RtlMultiByteToUnicodeN(
229 IN PWCHAR UnicodeString
,
230 IN ULONG UnicodeSize
,
231 IN 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
,
303 if (!NlsMbCodePageTag
)
305 /* single-byte code page */
306 *UnicodeSize
= MbSize
* sizeof (WCHAR
);
310 /* multi-byte code page */
315 UCHAR Char
= *(PUCHAR
)MbString
++;
317 if (Char
>= 0x80 && NlsLeadByteInfo
[Char
])
327 /* Increase returned size */
331 /* Return final size */
332 *UnicodeSize
= Length
* sizeof(WCHAR
);
336 return STATUS_SUCCESS
;
345 RtlOemToUnicodeN (PWCHAR UnicodeString
,
354 if (NlsMbOemCodePageTag
== FALSE
)
356 /* single-byte code page */
357 if (OemSize
> (UnicodeSize
/ sizeof(WCHAR
)))
358 Size
= UnicodeSize
/ sizeof(WCHAR
);
362 if (ResultSize
!= NULL
)
363 *ResultSize
= Size
* sizeof(WCHAR
);
365 for (i
= 0; i
< Size
; i
++)
367 *UnicodeString
= NlsOemToUnicodeTable
[(UCHAR
)*OemString
];
374 /* multi-byte code page */
378 USHORT OemLeadByteInfo
;
379 PCHAR OemEnd
= OemString
+ OemSize
;
381 for (i
= 0; i
< UnicodeSize
/ sizeof(WCHAR
) && OemString
< OemEnd
; i
++)
383 Char
= *(PUCHAR
)OemString
++;
387 *UnicodeString
++ = Char
;
391 OemLeadByteInfo
= NlsOemLeadByteInfo
[Char
];
393 if (!OemLeadByteInfo
)
395 *UnicodeString
++ = NlsOemToUnicodeTable
[Char
];
399 if (OemString
< OemEnd
)
401 NlsOemLeadByteInfo
[OemLeadByteInfo
+ *(PUCHAR
)OemString
++];
404 if (ResultSize
!= NULL
)
405 *ResultSize
= i
* sizeof(WCHAR
);
408 return STATUS_SUCCESS
;
417 RtlResetRtlTranslations(IN PNLSTABLEINFO NlsTable
)
419 DPRINT("RtlResetRtlTranslations() called\n");
422 NlsAnsiToUnicodeTable
= (PWCHAR
)NlsTable
->AnsiTableInfo
.MultiByteTable
; /* Real type is PUSHORT */
423 NlsUnicodeToAnsiTable
= NlsTable
->AnsiTableInfo
.WideCharTable
;
424 NlsDbcsUnicodeToAnsiTable
= (PWCHAR
)NlsTable
->AnsiTableInfo
.WideCharTable
;
425 NlsMbCodePageTag
= (NlsTable
->AnsiTableInfo
.DBCSCodePage
!= 0);
426 NlsLeadByteInfo
= NlsTable
->AnsiTableInfo
.DBCSOffsets
;
427 NlsAnsiCodePage
= NlsTable
->AnsiTableInfo
.CodePage
;
428 DPRINT("Ansi codepage %hu\n", NlsAnsiCodePage
);
431 NlsOemToUnicodeTable
= (PWCHAR
)NlsTable
->OemTableInfo
.MultiByteTable
; /* Real type is PUSHORT */
432 NlsUnicodeToOemTable
= NlsTable
->OemTableInfo
.WideCharTable
;
433 NlsDbcsUnicodeToOemTable
= (PWCHAR
)NlsTable
->OemTableInfo
.WideCharTable
;
434 NlsMbOemCodePageTag
= (NlsTable
->OemTableInfo
.DBCSCodePage
!= 0);
435 NlsOemLeadByteInfo
= NlsTable
->OemTableInfo
.DBCSOffsets
;
436 NlsOemCodePage
= NlsTable
->OemTableInfo
.CodePage
;
437 DPRINT("Oem codepage %hu\n", NlsOemCodePage
);
439 /* Set Unicode case map data */
440 NlsUnicodeUpcaseTable
= NlsTable
->UpperCaseTable
;
441 NlsUnicodeLowercaseTable
= NlsTable
->LowerCaseTable
;
443 /* set the default characters for RtlpDidUnicodeToOemWork */
444 NlsOemDefaultChar
= NlsTable
->OemTableInfo
.DefaultChar
;
445 NlsUnicodeDefaultChar
= NlsTable
->OemTableInfo
.TransDefaultChar
;
454 RtlUnicodeToCustomCPN(IN PCPTABLEINFO CustomCP
,
458 PWCHAR UnicodeString
,
464 if (CustomCP
->DBCSCodePage
== 0)
466 /* single-byte code page */
467 if (UnicodeSize
> (CustomSize
* sizeof(WCHAR
)))
470 Size
= UnicodeSize
/ sizeof(WCHAR
);
472 if (ResultSize
!= NULL
)
475 for (i
= 0; i
< Size
; i
++)
477 *CustomString
= ((PCHAR
)CustomCP
->WideCharTable
)[*UnicodeString
];
484 /* multi-byte code page */
489 return STATUS_SUCCESS
;
498 RtlUnicodeToMultiByteN (PCHAR MbString
,
501 PWCHAR UnicodeString
,
507 if (NlsMbCodePageTag
== FALSE
)
509 /* single-byte code page */
510 Size
= (UnicodeSize
> (MbSize
* sizeof (WCHAR
)))
512 : (UnicodeSize
/ sizeof (WCHAR
));
514 if (ResultSize
!= NULL
)
519 for (i
= 0; i
< Size
; i
++)
521 *MbString
++ = NlsUnicodeToAnsiTable
[*UnicodeString
++];
526 /* multi-byte code page */
532 for (i
= MbSize
, Size
= UnicodeSize
/ sizeof(WCHAR
); i
&& Size
; i
--, Size
--)
534 WideChar
= *UnicodeString
++;
538 *MbString
++ = LOBYTE(WideChar
);
542 MbChar
= NlsDbcsUnicodeToAnsiTable
[WideChar
];
546 *MbString
++ = LOBYTE(MbChar
);
552 *MbString
++ = HIBYTE(MbChar
);
553 *MbString
++ = LOBYTE(MbChar
);
559 if (ResultSize
!= NULL
)
560 *ResultSize
= MbSize
- i
;
563 return STATUS_SUCCESS
;
571 RtlUnicodeToMultiByteSize(PULONG MbSize
,
572 PWCHAR UnicodeString
,
575 ULONG UnicodeLength
= UnicodeSize
/ sizeof(WCHAR
);
578 if (!NlsMbCodePageTag
)
580 /* single-byte code page */
581 *MbSize
= UnicodeLength
;
585 /* multi-byte code page */
588 while (UnicodeLength
--)
590 USHORT WideChar
= *UnicodeString
++;
592 if (WideChar
>= 0x80 && HIBYTE(NlsDbcsUnicodeToAnsiTable
[WideChar
]))
594 MbLength
+= sizeof(WCHAR
);
606 return STATUS_SUCCESS
;
613 RtlUnicodeToOemN (PCHAR OemString
,
616 PWCHAR UnicodeString
,
622 if (NlsMbOemCodePageTag
== FALSE
)
624 /* single-byte code page */
625 if (UnicodeSize
> (OemSize
* sizeof(WCHAR
)))
628 Size
= UnicodeSize
/ sizeof(WCHAR
);
630 if (ResultSize
!= NULL
)
633 for (i
= 0; i
< Size
; i
++)
635 *OemString
= NlsUnicodeToOemTable
[*UnicodeString
];
642 /* multi-byte code page */
648 for (i
= OemSize
, Size
= UnicodeSize
/ sizeof(WCHAR
); i
&& Size
; i
--, Size
--)
650 WideChar
= *UnicodeString
++;
654 *OemString
++ = LOBYTE(WideChar
);
658 OemChar
= NlsDbcsUnicodeToOemTable
[WideChar
];
660 if (!HIBYTE(OemChar
))
662 *OemString
++ = LOBYTE(OemChar
);
668 *OemString
++ = HIBYTE(OemChar
);
669 *OemString
++ = LOBYTE(OemChar
);
675 if (ResultSize
!= NULL
)
676 *ResultSize
= OemSize
- i
;
679 return STATUS_SUCCESS
;
689 RtlUpcaseUnicodeChar(IN WCHAR Source
)
697 return (Source
- ('a' - 'A'));
699 Offset
= ((USHORT
)Source
>> 8) & 0xFF;
700 Offset
= NlsUnicodeUpcaseTable
[Offset
];
702 Offset
+= ((USHORT
)Source
>> 4) & 0xF;
703 Offset
= NlsUnicodeUpcaseTable
[Offset
];
705 Offset
+= ((USHORT
)Source
& 0xF);
706 Offset
= NlsUnicodeUpcaseTable
[Offset
];
708 return Source
+ (SHORT
)Offset
;
717 RtlUpcaseUnicodeToCustomCPN (IN PCPTABLEINFO CustomCP
,
721 PWCHAR UnicodeString
,
728 if (CustomCP
->DBCSCodePage
== 0)
730 /* single-byte code page */
731 if (UnicodeSize
> (CustomSize
* sizeof(WCHAR
)))
734 Size
= UnicodeSize
/ sizeof(WCHAR
);
736 if (ResultSize
!= NULL
)
739 for (i
= 0; i
< Size
; i
++)
741 UpcaseChar
= RtlUpcaseUnicodeChar(*UnicodeString
);
742 *CustomString
= ((PCHAR
)CustomCP
->WideCharTable
)[UpcaseChar
];
749 /* multi-byte code page */
754 return STATUS_SUCCESS
;
762 RtlUpcaseUnicodeToMultiByteN (PCHAR MbString
,
765 PWCHAR UnicodeString
,
772 if (NlsMbCodePageTag
== FALSE
)
774 /* single-byte code page */
775 if (UnicodeSize
> (MbSize
* sizeof(WCHAR
)))
778 Size
= UnicodeSize
/ sizeof(WCHAR
);
780 if (ResultSize
!= NULL
)
783 for (i
= 0; i
< Size
; i
++)
785 UpcaseChar
= RtlUpcaseUnicodeChar(*UnicodeString
);
786 *MbString
= NlsUnicodeToAnsiTable
[UpcaseChar
];
793 /* multi-byte code page */
798 return STATUS_SUCCESS
;
806 RtlUpcaseUnicodeToOemN (PCHAR OemString
,
809 PWCHAR UnicodeString
,
816 ASSERT(NlsUnicodeToOemTable
!= NULL
);
818 if (NlsMbOemCodePageTag
== FALSE
)
820 /* single-byte code page */
821 if (UnicodeSize
> (OemSize
* sizeof(WCHAR
)))
824 Size
= UnicodeSize
/ sizeof(WCHAR
);
826 if (ResultSize
!= NULL
)
829 for (i
= 0; i
< Size
; i
++)
831 UpcaseChar
= RtlUpcaseUnicodeChar(*UnicodeString
);
832 *OemString
= NlsUnicodeToOemTable
[UpcaseChar
];
839 /* multi-byte code page */
845 for (i
= OemSize
, Size
= UnicodeSize
/ sizeof(WCHAR
); i
&& Size
; i
--, Size
--)
847 WideChar
= RtlUpcaseUnicodeChar(*UnicodeString
++);
851 *OemString
++ = LOBYTE(WideChar
);
855 OemChar
= NlsDbcsUnicodeToOemTable
[WideChar
];
857 if (!HIBYTE(OemChar
))
859 *OemString
++ = LOBYTE(OemChar
);
865 *OemString
++ = HIBYTE(OemChar
);
866 *OemString
++ = LOBYTE(OemChar
);
872 if (ResultSize
!= NULL
)
873 *ResultSize
= OemSize
- i
;
876 return STATUS_SUCCESS
;
885 RtlUpperChar (IN CHAR Source
)
890 /* Check for simple ANSI case */
893 /* Check for simple downcase a-z case */
896 /* Just XOR with the difference */
897 return Source
^ ('a' - 'A');
901 /* Otherwise return the same char, it's already upcase */
907 if (NlsMbCodePageTag
== FALSE
)
909 /* single-byte code page */
912 Unicode
= NlsAnsiToUnicodeTable
[(UCHAR
)Source
];
914 /* upcase conversion */
915 Unicode
= RtlUpcaseUnicodeChar (Unicode
);
917 /* unicode -> ansi */
918 Destination
= NlsUnicodeToAnsiTable
[(USHORT
)Unicode
];
922 /* multi-byte code page */
924 Destination
= Source
;