xref: /reactos/sdk/lib/rtl/nls.c (revision 6924b8ff)
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  * @implemented
638  */
639 NTSTATUS
640 NTAPI
641 RtlUnicodeToOemN(OUT PCHAR OemString,
642                  IN ULONG OemSize,
643                  OUT PULONG ResultSize OPTIONAL,
644                  IN PCWCH UnicodeString,
645                  IN ULONG UnicodeSize)
646 {
647     ULONG Size = 0;
648 
649     PAGED_CODE_RTL();
650 
651     /* Bytes -> chars */
652     UnicodeSize /= sizeof(WCHAR);
653 
654     if (!NlsMbOemCodePageTag)
655     {
656         while (OemSize && UnicodeSize)
657         {
658             OemString[Size] = NlsUnicodeToOemTable[*UnicodeString++];
659             Size++;
660             OemSize--;
661             UnicodeSize--;
662         }
663     }
664     else
665     {
666         while (OemSize && UnicodeSize)
667         {
668             USHORT OemChar = NlsUnicodeToMbOemTable[*UnicodeString++];
669 
670             if (HIBYTE(OemChar))
671             {
672                 if (OemSize < 2)
673                     break;
674                 OemString[Size++] = HIBYTE(OemChar);
675                 OemSize--;
676             }
677             OemString[Size++] = LOBYTE(OemChar);
678             OemSize--;
679             UnicodeSize--;
680         }
681     }
682 
683     if (ResultSize)
684         *ResultSize = Size;
685 
686     return UnicodeSize ? STATUS_BUFFER_OVERFLOW : STATUS_SUCCESS;
687 }
688 
689 /*
690  * @implemented
691  */
692 WCHAR NTAPI
693 RtlpUpcaseUnicodeChar(IN WCHAR Source)
694 {
695     USHORT Offset;
696 
697     if (Source < 'a')
698         return Source;
699 
700     if (Source <= 'z')
701         return (Source - ('a' - 'A'));
702 
703     Offset = ((USHORT)Source >> 8) & 0xFF;
704     Offset = NlsUnicodeUpcaseTable[Offset];
705 
706     Offset += ((USHORT)Source >> 4) & 0xF;
707     Offset = NlsUnicodeUpcaseTable[Offset];
708 
709     Offset += ((USHORT)Source & 0xF);
710     Offset = NlsUnicodeUpcaseTable[Offset];
711 
712     return Source + (SHORT)Offset;
713 }
714 
715 /*
716  * @implemented
717  */
718 WCHAR NTAPI
719 RtlUpcaseUnicodeChar(IN WCHAR Source)
720 {
721     PAGED_CODE_RTL();
722 
723     return RtlpUpcaseUnicodeChar(Source);
724 }
725 
726 /*
727  * @implemented
728  */
729 NTSTATUS NTAPI
730 RtlUpcaseUnicodeToCustomCPN(IN PCPTABLEINFO CustomCP,
731                             OUT PCHAR CustomString,
732                             IN ULONG CustomSize,
733                             OUT PULONG ResultSize OPTIONAL,
734                             IN PWCHAR UnicodeString,
735                             IN ULONG UnicodeSize)
736 {
737     WCHAR UpcaseChar;
738     ULONG Size = 0;
739     ULONG i;
740 
741     PAGED_CODE_RTL();
742 
743     if (!CustomCP->DBCSCodePage)
744     {
745         /* single-byte code page */
746         if (UnicodeSize > (CustomSize * sizeof(WCHAR)))
747             Size = CustomSize;
748         else
749             Size = UnicodeSize / sizeof(WCHAR);
750 
751         if (ResultSize)
752             *ResultSize = Size;
753 
754         for (i = 0; i < Size; i++)
755         {
756             UpcaseChar = RtlpUpcaseUnicodeChar(*UnicodeString);
757             *CustomString = ((PCHAR)CustomCP->WideCharTable)[UpcaseChar];
758             ++CustomString;
759             ++UnicodeString;
760         }
761     }
762     else
763     {
764         /* multi-byte code page */
765         /* FIXME */
766         ASSERT(FALSE);
767     }
768 
769     return STATUS_SUCCESS;
770 }
771 
772 /*
773  * @unimplemented
774  */
775 NTSTATUS NTAPI
776 RtlUpcaseUnicodeToMultiByteN(OUT PCHAR MbString,
777                              IN ULONG MbSize,
778                              OUT PULONG ResultSize OPTIONAL,
779                              IN PCWCH UnicodeString,
780                              IN ULONG UnicodeSize)
781 {
782     WCHAR UpcaseChar;
783     ULONG Size = 0;
784     ULONG i;
785 
786     PAGED_CODE_RTL();
787 
788     if (!NlsMbCodePageTag)
789     {
790         /* single-byte code page */
791         if (UnicodeSize > (MbSize * sizeof(WCHAR)))
792             Size = MbSize;
793         else
794             Size = UnicodeSize / sizeof(WCHAR);
795 
796         if (ResultSize)
797             *ResultSize = Size;
798 
799         for (i = 0; i < Size; i++)
800         {
801             UpcaseChar = RtlpUpcaseUnicodeChar(*UnicodeString);
802             *MbString = NlsUnicodeToAnsiTable[UpcaseChar];
803             MbString++;
804             UnicodeString++;
805         }
806     }
807     else
808     {
809         /* multi-byte code page */
810         /* FIXME */
811         ASSERT(FALSE);
812     }
813 
814     return STATUS_SUCCESS;
815 }
816 
817 /*
818  * @unimplemented
819  */
820 NTSTATUS NTAPI
821 RtlUpcaseUnicodeToOemN(OUT PCHAR OemString,
822                        IN ULONG OemSize,
823                        OUT PULONG ResultSize OPTIONAL,
824                        IN PCWCH UnicodeString,
825                        IN ULONG UnicodeSize)
826 {
827     WCHAR UpcaseChar;
828     ULONG Size = 0;
829     ULONG i;
830 
831     PAGED_CODE_RTL();
832 
833     ASSERT(NlsUnicodeToOemTable != NULL);
834 
835     if (!NlsMbOemCodePageTag)
836     {
837         /* single-byte code page */
838         if (UnicodeSize > (OemSize * sizeof(WCHAR)))
839             Size = OemSize;
840         else
841             Size = UnicodeSize / sizeof(WCHAR);
842 
843         if (ResultSize)
844             *ResultSize = Size;
845 
846         for (i = 0; i < Size; i++)
847         {
848             UpcaseChar = RtlpUpcaseUnicodeChar(*UnicodeString);
849             *OemString = NlsUnicodeToOemTable[UpcaseChar];
850             OemString++;
851             UnicodeString++;
852         }
853     }
854     else
855     {
856         /* multi-byte code page */
857         /* FIXME */
858 
859         USHORT WideChar;
860         USHORT OemChar;
861 
862         for (i = OemSize, Size = UnicodeSize / sizeof(WCHAR); i && Size; i--, Size--)
863         {
864             WideChar = RtlpUpcaseUnicodeChar(*UnicodeString++);
865 
866             if (WideChar < 0x80)
867             {
868                 *OemString++ = LOBYTE(WideChar);
869                 continue;
870             }
871 
872             OemChar = NlsUnicodeToMbOemTable[WideChar];
873 
874             if (!HIBYTE(OemChar))
875             {
876                 *OemString++ = LOBYTE(OemChar);
877                 continue;
878             }
879 
880             if (i >= 2)
881             {
882                 *OemString++ = HIBYTE(OemChar);
883                 *OemString++ = LOBYTE(OemChar);
884                 i--;
885             }
886             else break;
887         }
888 
889         if (ResultSize)
890             *ResultSize = OemSize - i;
891     }
892 
893     return STATUS_SUCCESS;
894 }
895 
896 /*
897  * @unimplemented
898  */
899 CHAR NTAPI
900 RtlUpperChar(IN CHAR Source)
901 {
902     WCHAR Unicode;
903     CHAR Destination;
904 
905     PAGED_CODE_RTL();
906 
907     /* Check for simple ANSI case */
908     if (Source <= 'z')
909     {
910         /* Check for simple downcase a-z case */
911         if (Source >= 'a')
912         {
913             /* Just XOR with the difference */
914             return Source ^ ('a' - 'A');
915         }
916         else
917         {
918             /* Otherwise return the same char, it's already upcase */
919             return Source;
920         }
921     }
922     else
923     {
924         if (!NlsMbCodePageTag)
925         {
926             /* single-byte code page */
927 
928             /* ansi->unicode */
929             Unicode = NlsAnsiToUnicodeTable[(UCHAR)Source];
930 
931             /* upcase conversion */
932             Unicode = RtlpUpcaseUnicodeChar (Unicode);
933 
934             /* unicode -> ansi */
935             Destination = NlsUnicodeToAnsiTable[(USHORT)Unicode];
936         }
937         else
938         {
939             /* multi-byte code page */
940             /* FIXME */
941             Destination = Source;
942         }
943     }
944 
945     return Destination;
946 }
947 
948 /* EOF */
949