xref: /reactos/sdk/lib/rtl/nls.c (revision 8a978a17)
1 /*
2  * COPYRIGHT:         See COPYING in the top level directory
3  * PROJECT:           ReactOS system libraries
4  * FILE:              lib/rtl/nls.c
5  * PURPOSE:           National Language Support (NLS) functions
6  * PROGRAMMERS:       Emanuele Aliberti
7  */
8 
9 /* INCLUDES *****************************************************************/
10 
11 #include <rtl.h>
12 
13 #define NDEBUG
14 #include <debug.h>
15 
16 /* GLOBALS *******************************************************************/
17 
18 PUSHORT NlsUnicodeUpcaseTable = NULL;
19 PUSHORT NlsUnicodeLowercaseTable = NULL;
20 
21 USHORT NlsAnsiCodePage = 0; /* exported */
22 BOOLEAN NlsMbCodePageTag = FALSE; /* exported */
23 PUSHORT NlsAnsiToUnicodeTable = NULL;
24 PCHAR NlsUnicodeToAnsiTable = NULL;
25 PUSHORT NlsUnicodeToMbAnsiTable = NULL;
26 PUSHORT NlsLeadByteInfo = NULL; /* exported */
27 
28 USHORT NlsOemCodePage = 0;
29 BOOLEAN NlsMbOemCodePageTag = FALSE; /* exported */
30 PUSHORT NlsOemToUnicodeTable = NULL;
31 PCHAR NlsUnicodeToOemTable = NULL;
32 PUSHORT NlsUnicodeToMbOemTable = NULL;
33 PUSHORT NlsOemLeadByteInfo = NULL; /* exported */
34 
35 USHORT NlsOemDefaultChar = '\0';
36 USHORT NlsUnicodeDefaultChar = 0;
37 
38 
39 /* FUNCTIONS *****************************************************************/
40 
41 /*
42  * @unimplemented
43  */
44 NTSTATUS NTAPI
45 RtlCustomCPToUnicodeN(IN PCPTABLEINFO CustomCP,
46                       OUT PWCHAR UnicodeString,
47                       IN ULONG UnicodeSize,
48                       OUT PULONG ResultSize OPTIONAL,
49                       IN PCHAR CustomString,
50                       IN ULONG CustomSize)
51 {
52     ULONG Size = 0;
53     ULONG i;
54 
55     PAGED_CODE_RTL();
56 
57     if (!CustomCP->DBCSCodePage)
58     {
59         /* single-byte code page */
60         if (CustomSize > (UnicodeSize / sizeof(WCHAR)))
61             Size = UnicodeSize / sizeof(WCHAR);
62         else
63             Size = CustomSize;
64 
65         if (ResultSize)
66             *ResultSize = Size * sizeof(WCHAR);
67 
68         for (i = 0; i < Size; i++)
69         {
70             *UnicodeString = CustomCP->MultiByteTable[(UCHAR)*CustomString];
71             UnicodeString++;
72             CustomString++;
73         }
74     }
75     else
76     {
77         /* multi-byte code page */
78         /* FIXME */
79         ASSERT(FALSE);
80     }
81 
82     return STATUS_SUCCESS;
83 }
84 
85 /*
86  * @implemented
87  */
88 WCHAR NTAPI
89 RtlpDowncaseUnicodeChar(IN WCHAR Source)
90 {
91     USHORT Offset;
92 
93     PAGED_CODE_RTL();
94 
95     if (Source < L'A')
96         return Source;
97 
98     if (Source <= L'Z')
99         return Source + (L'a' - L'A');
100 
101     if (Source < 0x80)
102         return Source;
103 
104     Offset = ((USHORT)Source >> 8);
105     DPRINT("Offset: %hx\n", Offset);
106 
107     Offset = NlsUnicodeLowercaseTable[Offset];
108     DPRINT("Offset: %hx\n", Offset);
109 
110     Offset += (((USHORT)Source & 0x00F0) >> 4);
111     DPRINT("Offset: %hx\n", Offset);
112 
113     Offset = NlsUnicodeLowercaseTable[Offset];
114     DPRINT("Offset: %hx\n", Offset);
115 
116     Offset += ((USHORT)Source & 0x000F);
117     DPRINT("Offset: %hx\n", Offset);
118 
119     Offset = NlsUnicodeLowercaseTable[Offset];
120     DPRINT("Offset: %hx\n", Offset);
121 
122     DPRINT("Result: %hx\n", Source + (SHORT)Offset);
123 
124     return Source + (SHORT)Offset;
125 }
126 
127 /*
128  * @implemented
129  */
130 WCHAR NTAPI
131 RtlDowncaseUnicodeChar(IN WCHAR Source)
132 {
133     PAGED_CODE_RTL();
134 
135     return RtlpDowncaseUnicodeChar(Source);
136 }
137 
138 /*
139  * @implemented
140  */
141 VOID NTAPI
142 RtlGetDefaultCodePage(OUT PUSHORT AnsiCodePage,
143                       OUT PUSHORT OemCodePage)
144 {
145     PAGED_CODE_RTL();
146 
147     *AnsiCodePage = NlsAnsiCodePage;
148     *OemCodePage = NlsOemCodePage;
149 }
150 
151 /*
152  * @implemented
153  */
154 VOID NTAPI
155 RtlInitCodePageTable(IN PUSHORT TableBase,
156                      OUT PCPTABLEINFO CodePageTable)
157 {
158     PNLS_FILE_HEADER NlsFileHeader;
159 
160     PAGED_CODE_RTL();
161 
162     DPRINT("RtlInitCodePageTable() called\n");
163 
164     NlsFileHeader = (PNLS_FILE_HEADER)TableBase;
165 
166     /* Copy header fields first */
167     CodePageTable->CodePage = NlsFileHeader->CodePage;
168     CodePageTable->MaximumCharacterSize = NlsFileHeader->MaximumCharacterSize;
169     CodePageTable->DefaultChar = NlsFileHeader->DefaultChar;
170     CodePageTable->UniDefaultChar = NlsFileHeader->UniDefaultChar;
171     CodePageTable->TransDefaultChar = NlsFileHeader->TransDefaultChar;
172     CodePageTable->TransUniDefaultChar = NlsFileHeader->TransUniDefaultChar;
173 
174     RtlCopyMemory(&CodePageTable->LeadByte,
175                   &NlsFileHeader->LeadByte,
176                   MAXIMUM_LEADBYTES);
177 
178     /* Offset to wide char table is after the header */
179     CodePageTable->WideCharTable =
180         TableBase + NlsFileHeader->HeaderSize + 1 + TableBase[NlsFileHeader->HeaderSize];
181 
182     /* Then multibyte table (256 wchars) follows */
183     CodePageTable->MultiByteTable = TableBase + NlsFileHeader->HeaderSize + 1;
184 
185     /* Check the presence of glyph table (256 wchars) */
186     if (!CodePageTable->MultiByteTable[256])
187         CodePageTable->DBCSRanges = CodePageTable->MultiByteTable + 256 + 1;
188     else
189         CodePageTable->DBCSRanges = CodePageTable->MultiByteTable + 256 + 1 + 256;
190 
191     /* Is this double-byte code page? */
192     if (*CodePageTable->DBCSRanges)
193     {
194         CodePageTable->DBCSCodePage = 1;
195         CodePageTable->DBCSOffsets = CodePageTable->DBCSRanges + 1;
196     }
197     else
198     {
199         CodePageTable->DBCSCodePage = 0;
200         CodePageTable->DBCSOffsets = NULL;
201     }
202 }
203 
204 /*
205  * @implemented
206  */
207 VOID NTAPI
208 RtlInitNlsTables(IN PUSHORT AnsiTableBase,
209                  IN PUSHORT OemTableBase,
210                  IN PUSHORT CaseTableBase,
211                  OUT PNLSTABLEINFO NlsTable)
212 {
213     PAGED_CODE_RTL();
214 
215     DPRINT("RtlInitNlsTables()called\n");
216 
217     if (AnsiTableBase && OemTableBase && CaseTableBase)
218     {
219         RtlInitCodePageTable(AnsiTableBase, &NlsTable->AnsiTableInfo);
220         RtlInitCodePageTable(OemTableBase, &NlsTable->OemTableInfo);
221 
222         NlsTable->UpperCaseTable = (PUSHORT)CaseTableBase + 2;
223         NlsTable->LowerCaseTable = (PUSHORT)CaseTableBase + *((PUSHORT)CaseTableBase + 1) + 2;
224     }
225 }
226 
227 /*
228  * @unimplemented
229  */
230 NTSTATUS NTAPI
231 RtlMultiByteToUnicodeN(OUT PWCHAR UnicodeString,
232                        IN ULONG UnicodeSize,
233                        OUT PULONG ResultSize,
234                        IN PCSTR MbString,
235                        IN ULONG MbSize)
236 {
237     ULONG Size = 0;
238     ULONG i;
239 
240     PAGED_CODE_RTL();
241 
242     if (!NlsMbCodePageTag)
243     {
244         /* single-byte code page */
245         if (MbSize > (UnicodeSize / sizeof(WCHAR)))
246             Size = UnicodeSize / sizeof(WCHAR);
247         else
248             Size = MbSize;
249 
250         if (ResultSize)
251             *ResultSize = Size * sizeof(WCHAR);
252 
253         for (i = 0; i < Size; i++)
254             UnicodeString[i] = NlsAnsiToUnicodeTable[(UCHAR)MbString[i]];
255     }
256     else
257     {
258         /* multi-byte code page */
259         /* FIXME */
260 
261         UCHAR Char;
262         USHORT LeadByteInfo;
263         PCSTR MbEnd = MbString + MbSize;
264 
265         for (i = 0; i < UnicodeSize / sizeof(WCHAR) && MbString < MbEnd; i++)
266         {
267             Char = *(PUCHAR)MbString++;
268 
269             if (Char < 0x80)
270             {
271                 *UnicodeString++ = Char;
272                 continue;
273             }
274 
275             LeadByteInfo = NlsLeadByteInfo[Char];
276 
277             if (!LeadByteInfo)
278             {
279                 *UnicodeString++ = NlsAnsiToUnicodeTable[Char];
280                 continue;
281             }
282 
283             if (MbString < MbEnd)
284                 *UnicodeString++ = NlsLeadByteInfo[LeadByteInfo + *(PUCHAR)MbString++];
285         }
286 
287         if (ResultSize)
288             *ResultSize = i * sizeof(WCHAR);
289     }
290 
291     return STATUS_SUCCESS;
292 }
293 
294 /*
295  * @unimplemented
296  */
297 NTSTATUS
298 NTAPI
299 RtlConsoleMultiByteToUnicodeN(OUT PWCHAR UnicodeString,
300                               IN ULONG UnicodeSize,
301                               OUT PULONG ResultSize,
302                               IN PCSTR MbString,
303                               IN ULONG MbSize,
304                               OUT PULONG Unknown)
305 {
306     PAGED_CODE_RTL();
307 
308     UNIMPLEMENTED;
309     DPRINT1("RtlConsoleMultiByteToUnicodeN calling RtlMultiByteToUnicodeN\n");
310     *Unknown = 1;
311     return RtlMultiByteToUnicodeN(UnicodeString,
312                                   UnicodeSize,
313                                   ResultSize,
314                                   MbString,
315                                   MbSize);
316 }
317 
318 /*
319  * @implemented
320  */
321 NTSTATUS
322 NTAPI
323 RtlMultiByteToUnicodeSize(OUT PULONG UnicodeSize,
324                           IN PCSTR MbString,
325                           IN ULONG MbSize)
326 {
327     ULONG Length = 0;
328 
329     PAGED_CODE_RTL();
330 
331     if (!NlsMbCodePageTag)
332     {
333         /* single-byte code page */
334         *UnicodeSize = MbSize * sizeof (WCHAR);
335     }
336     else
337     {
338         /* multi-byte code page */
339         /* FIXME */
340 
341         while (MbSize--)
342         {
343             UCHAR Char = *(PUCHAR)MbString++;
344 
345             if (Char >= 0x80 && NlsLeadByteInfo[Char])
346             {
347                 if (MbSize)
348                 {
349                     /* Move on */
350                     MbSize--;
351                     MbString++;
352                 }
353             }
354 
355             /* Increase returned size */
356             Length++;
357         }
358 
359         /* Return final size */
360         *UnicodeSize = Length * sizeof(WCHAR);
361     }
362 
363     /* Success */
364     return STATUS_SUCCESS;
365 }
366 
367 /*
368  * @unimplemented
369  */
370 NTSTATUS NTAPI
371 RtlOemToUnicodeN(OUT PWCHAR UnicodeString,
372                  IN ULONG UnicodeSize,
373                  OUT PULONG ResultSize OPTIONAL,
374                  IN PCCH OemString,
375                  IN ULONG OemSize)
376 {
377     ULONG Size = 0;
378     ULONG i;
379 
380     PAGED_CODE_RTL();
381 
382     if (!NlsMbOemCodePageTag)
383     {
384         /* single-byte code page */
385         if (OemSize > (UnicodeSize / sizeof(WCHAR)))
386             Size = UnicodeSize / sizeof(WCHAR);
387         else
388             Size = OemSize;
389 
390         if (ResultSize)
391             *ResultSize = Size * sizeof(WCHAR);
392 
393         for (i = 0; i < Size; i++)
394         {
395             *UnicodeString = NlsOemToUnicodeTable[(UCHAR)*OemString];
396             UnicodeString++;
397             OemString++;
398         }
399     }
400     else
401     {
402         /* multi-byte code page */
403         /* FIXME */
404 
405         UCHAR Char;
406         USHORT OemLeadByteInfo;
407         PCCH OemEnd = OemString + OemSize;
408 
409         for (i = 0; i < UnicodeSize / sizeof(WCHAR) && OemString < OemEnd; i++)
410         {
411             Char = *(PUCHAR)OemString++;
412 
413             if (Char < 0x80)
414             {
415                 *UnicodeString++ = Char;
416                 continue;
417             }
418 
419             OemLeadByteInfo = NlsOemLeadByteInfo[Char];
420 
421             if (!OemLeadByteInfo)
422             {
423                 *UnicodeString++ = NlsOemToUnicodeTable[Char];
424                 continue;
425             }
426 
427             if (OemString < OemEnd)
428                 *UnicodeString++ =
429                     NlsOemLeadByteInfo[OemLeadByteInfo + *(PUCHAR)OemString++];
430         }
431 
432         if (ResultSize)
433             *ResultSize = i * sizeof(WCHAR);
434     }
435 
436     return STATUS_SUCCESS;
437 }
438 
439 /*
440  * @implemented
441  */
442 VOID NTAPI
443 RtlResetRtlTranslations(IN PNLSTABLEINFO NlsTable)
444 {
445     PAGED_CODE_RTL();
446 
447     DPRINT("RtlResetRtlTranslations() called\n");
448 
449     /* Set ANSI data */
450     NlsAnsiToUnicodeTable = (PUSHORT)NlsTable->AnsiTableInfo.MultiByteTable;
451     NlsUnicodeToAnsiTable = NlsTable->AnsiTableInfo.WideCharTable;
452     NlsUnicodeToMbAnsiTable = (PUSHORT)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);
457 
458     /* Set OEM data */
459     NlsOemToUnicodeTable = (PUSHORT)NlsTable->OemTableInfo.MultiByteTable;
460     NlsUnicodeToOemTable = NlsTable->OemTableInfo.WideCharTable;
461     NlsUnicodeToMbOemTable = (PUSHORT)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);
466 
467     /* Set Unicode case map data */
468     NlsUnicodeUpcaseTable = NlsTable->UpperCaseTable;
469     NlsUnicodeLowercaseTable = NlsTable->LowerCaseTable;
470 
471     /* set the default characters for RtlpDidUnicodeToOemWork */
472     NlsOemDefaultChar = NlsTable->OemTableInfo.DefaultChar;
473     NlsUnicodeDefaultChar = NlsTable->OemTableInfo.TransDefaultChar;
474 }
475 
476 /*
477  * @unimplemented
478  */
479 NTSTATUS NTAPI
480 RtlUnicodeToCustomCPN(IN PCPTABLEINFO CustomCP,
481                       OUT PCHAR CustomString,
482                       IN ULONG CustomSize,
483                       OUT PULONG ResultSize OPTIONAL,
484                       IN PWCHAR UnicodeString,
485                       IN ULONG UnicodeSize)
486 {
487     ULONG Size = 0;
488     ULONG i;
489 
490     PAGED_CODE_RTL();
491 
492     if (!CustomCP->DBCSCodePage)
493     {
494         /* single-byte code page */
495         if (UnicodeSize > (CustomSize * sizeof(WCHAR)))
496             Size = CustomSize;
497         else
498             Size = UnicodeSize / sizeof(WCHAR);
499 
500         if (ResultSize)
501             *ResultSize = Size;
502 
503         for (i = 0; i < Size; i++)
504         {
505             *CustomString = ((PCHAR)CustomCP->WideCharTable)[*UnicodeString];
506             CustomString++;
507             UnicodeString++;
508         }
509     }
510     else
511     {
512         /* multi-byte code page */
513         /* FIXME */
514         ASSERT(FALSE);
515     }
516 
517     return STATUS_SUCCESS;
518 }
519 
520 /*
521  * @unimplemented
522  */
523 NTSTATUS NTAPI
524 RtlUnicodeToMultiByteN(OUT PCHAR MbString,
525                        IN ULONG MbSize,
526                        OUT PULONG ResultSize OPTIONAL,
527                        IN PCWCH UnicodeString,
528                        IN ULONG UnicodeSize)
529 {
530     ULONG Size = 0;
531     ULONG i;
532 
533     PAGED_CODE_RTL();
534 
535     if (!NlsMbCodePageTag)
536     {
537         /* single-byte code page */
538         Size =  (UnicodeSize > (MbSize * sizeof (WCHAR)))
539                  ? MbSize : (UnicodeSize / sizeof (WCHAR));
540 
541         if (ResultSize)
542             *ResultSize = Size;
543 
544         for (i = 0; i < Size; i++)
545         {
546             *MbString++ = NlsUnicodeToAnsiTable[*UnicodeString++];
547         }
548     }
549     else
550     {
551         /* multi-byte code page */
552         /* FIXME */
553 
554         USHORT WideChar;
555         USHORT MbChar;
556 
557         for (i = MbSize, Size = UnicodeSize / sizeof(WCHAR); i && Size; i--, Size--)
558         {
559             WideChar = *UnicodeString++;
560 
561             if (WideChar < 0x80)
562             {
563                 *MbString++ = LOBYTE(WideChar);
564                 continue;
565             }
566 
567             MbChar = NlsUnicodeToMbAnsiTable[WideChar];
568 
569             if (!HIBYTE(MbChar))
570             {
571                 *MbString++ = LOBYTE(MbChar);
572                 continue;
573             }
574 
575             if (i >= 2)
576             {
577                 *MbString++ = HIBYTE(MbChar);
578                 *MbString++ = LOBYTE(MbChar);
579                 i--;
580             }
581             else break;
582         }
583 
584         if (ResultSize)
585             *ResultSize = MbSize - i;
586     }
587 
588     return STATUS_SUCCESS;
589 }
590 
591 /*
592  * @implemented
593  */
594 NTSTATUS
595 NTAPI
596 RtlUnicodeToMultiByteSize(OUT PULONG MbSize,
597                           IN PCWCH UnicodeString,
598                           IN ULONG UnicodeSize)
599 {
600     ULONG UnicodeLength = UnicodeSize / sizeof(WCHAR);
601     ULONG MbLength = 0;
602 
603     PAGED_CODE_RTL();
604 
605     if (!NlsMbCodePageTag)
606     {
607         /* single-byte code page */
608         *MbSize = UnicodeLength;
609     }
610     else
611     {
612         /* multi-byte code page */
613         /* FIXME */
614 
615         while (UnicodeLength--)
616         {
617             USHORT WideChar = *UnicodeString++;
618 
619             if (WideChar >= 0x80 && HIBYTE(NlsUnicodeToMbAnsiTable[WideChar]))
620             {
621                 MbLength += sizeof(WCHAR);
622             }
623             else
624             {
625                 MbLength++;
626             }
627         }
628 
629         *MbSize = MbLength;
630     }
631 
632     /* Success */
633     return STATUS_SUCCESS;
634 }
635 
636 /*
637  * @unimplemented
638  */
639 NTSTATUS NTAPI
640 RtlUnicodeToOemN(OUT PCHAR OemString,
641                  IN ULONG OemSize,
642                  OUT PULONG ResultSize OPTIONAL,
643                  IN PCWCH UnicodeString,
644                  IN ULONG UnicodeSize)
645 {
646     ULONG Size = 0;
647     ULONG i;
648 
649     PAGED_CODE_RTL();
650 
651     if (!NlsMbOemCodePageTag)
652     {
653         /* single-byte code page */
654         if (UnicodeSize > (OemSize * sizeof(WCHAR)))
655             Size = OemSize;
656         else
657             Size = UnicodeSize / sizeof(WCHAR);
658 
659         if (ResultSize)
660             *ResultSize = Size;
661 
662         for (i = 0; i < Size; i++)
663         {
664             *OemString = NlsUnicodeToOemTable[*UnicodeString];
665             OemString++;
666             UnicodeString++;
667         }
668     }
669     else
670     {
671         /* multi-byte code page */
672         /* FIXME */
673 
674         USHORT WideChar;
675         USHORT OemChar;
676 
677         for (i = OemSize, Size = UnicodeSize / sizeof(WCHAR); i && Size; i--, Size--)
678         {
679             WideChar = *UnicodeString++;
680 
681             if (WideChar < 0x80)
682             {
683                 *OemString++ = LOBYTE(WideChar);
684                 continue;
685             }
686 
687             OemChar = NlsUnicodeToMbOemTable[WideChar];
688 
689             if (!HIBYTE(OemChar))
690             {
691                 *OemString++ = LOBYTE(OemChar);
692                 continue;
693             }
694 
695             if (i >= 2)
696             {
697                 *OemString++ = HIBYTE(OemChar);
698                 *OemString++ = LOBYTE(OemChar);
699                 i--;
700             }
701             else break;
702         }
703 
704         if (ResultSize)
705             *ResultSize = OemSize - i;
706     }
707 
708     return STATUS_SUCCESS;
709 }
710 
711 /*
712  * @implemented
713  */
714 WCHAR NTAPI
715 RtlpUpcaseUnicodeChar(IN WCHAR Source)
716 {
717     USHORT Offset;
718 
719     if (Source < 'a')
720         return Source;
721 
722     if (Source <= 'z')
723         return (Source - ('a' - 'A'));
724 
725     Offset = ((USHORT)Source >> 8) & 0xFF;
726     Offset = NlsUnicodeUpcaseTable[Offset];
727 
728     Offset += ((USHORT)Source >> 4) & 0xF;
729     Offset = NlsUnicodeUpcaseTable[Offset];
730 
731     Offset += ((USHORT)Source & 0xF);
732     Offset = NlsUnicodeUpcaseTable[Offset];
733 
734     return Source + (SHORT)Offset;
735 }
736 
737 /*
738  * @implemented
739  */
740 WCHAR NTAPI
741 RtlUpcaseUnicodeChar(IN WCHAR Source)
742 {
743     PAGED_CODE_RTL();
744 
745     return RtlpUpcaseUnicodeChar(Source);
746 }
747 
748 /*
749  * @implemented
750  */
751 NTSTATUS NTAPI
752 RtlUpcaseUnicodeToCustomCPN(IN PCPTABLEINFO CustomCP,
753                             OUT PCHAR CustomString,
754                             IN ULONG CustomSize,
755                             OUT PULONG ResultSize OPTIONAL,
756                             IN PWCHAR UnicodeString,
757                             IN ULONG UnicodeSize)
758 {
759     WCHAR UpcaseChar;
760     ULONG Size = 0;
761     ULONG i;
762 
763     PAGED_CODE_RTL();
764 
765     if (!CustomCP->DBCSCodePage)
766     {
767         /* single-byte code page */
768         if (UnicodeSize > (CustomSize * sizeof(WCHAR)))
769             Size = CustomSize;
770         else
771             Size = UnicodeSize / sizeof(WCHAR);
772 
773         if (ResultSize)
774             *ResultSize = Size;
775 
776         for (i = 0; i < Size; i++)
777         {
778             UpcaseChar = RtlpUpcaseUnicodeChar(*UnicodeString);
779             *CustomString = ((PCHAR)CustomCP->WideCharTable)[UpcaseChar];
780             ++CustomString;
781             ++UnicodeString;
782         }
783     }
784     else
785     {
786         /* multi-byte code page */
787         /* FIXME */
788         ASSERT(FALSE);
789     }
790 
791     return STATUS_SUCCESS;
792 }
793 
794 /*
795  * @unimplemented
796  */
797 NTSTATUS NTAPI
798 RtlUpcaseUnicodeToMultiByteN(OUT PCHAR MbString,
799                              IN ULONG MbSize,
800                              OUT PULONG ResultSize OPTIONAL,
801                              IN PCWCH UnicodeString,
802                              IN ULONG UnicodeSize)
803 {
804     WCHAR UpcaseChar;
805     ULONG Size = 0;
806     ULONG i;
807 
808     PAGED_CODE_RTL();
809 
810     if (!NlsMbCodePageTag)
811     {
812         /* single-byte code page */
813         if (UnicodeSize > (MbSize * sizeof(WCHAR)))
814             Size = MbSize;
815         else
816             Size = UnicodeSize / sizeof(WCHAR);
817 
818         if (ResultSize)
819             *ResultSize = Size;
820 
821         for (i = 0; i < Size; i++)
822         {
823             UpcaseChar = RtlpUpcaseUnicodeChar(*UnicodeString);
824             *MbString = NlsUnicodeToAnsiTable[UpcaseChar];
825             MbString++;
826             UnicodeString++;
827         }
828     }
829     else
830     {
831         /* multi-byte code page */
832         /* FIXME */
833         ASSERT(FALSE);
834     }
835 
836     return STATUS_SUCCESS;
837 }
838 
839 /*
840  * @unimplemented
841  */
842 NTSTATUS NTAPI
843 RtlUpcaseUnicodeToOemN(OUT PCHAR OemString,
844                        IN ULONG OemSize,
845                        OUT PULONG ResultSize OPTIONAL,
846                        IN PCWCH UnicodeString,
847                        IN ULONG UnicodeSize)
848 {
849     WCHAR UpcaseChar;
850     ULONG Size = 0;
851     ULONG i;
852 
853     PAGED_CODE_RTL();
854 
855     ASSERT(NlsUnicodeToOemTable != NULL);
856 
857     if (!NlsMbOemCodePageTag)
858     {
859         /* single-byte code page */
860         if (UnicodeSize > (OemSize * sizeof(WCHAR)))
861             Size = OemSize;
862         else
863             Size = UnicodeSize / sizeof(WCHAR);
864 
865         if (ResultSize)
866             *ResultSize = Size;
867 
868         for (i = 0; i < Size; i++)
869         {
870             UpcaseChar = RtlpUpcaseUnicodeChar(*UnicodeString);
871             *OemString = NlsUnicodeToOemTable[UpcaseChar];
872             OemString++;
873             UnicodeString++;
874         }
875     }
876     else
877     {
878         /* multi-byte code page */
879         /* FIXME */
880 
881         USHORT WideChar;
882         USHORT OemChar;
883 
884         for (i = OemSize, Size = UnicodeSize / sizeof(WCHAR); i && Size; i--, Size--)
885         {
886             WideChar = RtlpUpcaseUnicodeChar(*UnicodeString++);
887 
888             if (WideChar < 0x80)
889             {
890                 *OemString++ = LOBYTE(WideChar);
891                 continue;
892             }
893 
894             OemChar = NlsUnicodeToMbOemTable[WideChar];
895 
896             if (!HIBYTE(OemChar))
897             {
898                 *OemString++ = LOBYTE(OemChar);
899                 continue;
900             }
901 
902             if (i >= 2)
903             {
904                 *OemString++ = HIBYTE(OemChar);
905                 *OemString++ = LOBYTE(OemChar);
906                 i--;
907             }
908             else break;
909         }
910 
911         if (ResultSize)
912             *ResultSize = OemSize - i;
913     }
914 
915     return STATUS_SUCCESS;
916 }
917 
918 /*
919  * @unimplemented
920  */
921 CHAR NTAPI
922 RtlUpperChar(IN CHAR Source)
923 {
924     WCHAR Unicode;
925     CHAR Destination;
926 
927     PAGED_CODE_RTL();
928 
929     /* Check for simple ANSI case */
930     if (Source <= 'z')
931     {
932         /* Check for simple downcase a-z case */
933         if (Source >= 'a')
934         {
935             /* Just XOR with the difference */
936             return Source ^ ('a' - 'A');
937         }
938         else
939         {
940             /* Otherwise return the same char, it's already upcase */
941             return Source;
942         }
943     }
944     else
945     {
946         if (!NlsMbCodePageTag)
947         {
948             /* single-byte code page */
949 
950             /* ansi->unicode */
951             Unicode = NlsAnsiToUnicodeTable[(UCHAR)Source];
952 
953             /* upcase conversion */
954             Unicode = RtlpUpcaseUnicodeChar (Unicode);
955 
956             /* unicode -> ansi */
957             Destination = NlsUnicodeToAnsiTable[(USHORT)Unicode];
958         }
959         else
960         {
961             /* multi-byte code page */
962             /* FIXME */
963             Destination = Source;
964         }
965     }
966 
967     return Destination;
968 }
969 
970 /* EOF */
971