xref: /reactos/sdk/lib/rtl/nls.c (revision d2c667c6)
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         {
255             UnicodeString[i] = NlsAnsiToUnicodeTable[(UCHAR)MbString[i]];
256         }
257     }
258     else
259     {
260         /* multi-byte code page */
261         /* FIXME */
262 
263         UCHAR Char;
264         USHORT LeadByteInfo;
265         PCSTR MbEnd = MbString + MbSize;
266 
267         for (i = 0; i < UnicodeSize / sizeof(WCHAR) && MbString < MbEnd; i++)
268         {
269             Char = *(PUCHAR)MbString++;
270 
271             if (Char < 0x80)
272             {
273                 *UnicodeString++ = Char;
274                 continue;
275             }
276 
277             LeadByteInfo = NlsLeadByteInfo[Char];
278 
279             if (!LeadByteInfo)
280             {
281                 *UnicodeString++ = NlsAnsiToUnicodeTable[Char];
282                 continue;
283             }
284 
285             if (MbString < MbEnd)
286                 *UnicodeString++ = NlsLeadByteInfo[LeadByteInfo + *(PUCHAR)MbString++];
287         }
288 
289         if (ResultSize)
290             *ResultSize = i * sizeof(WCHAR);
291     }
292 
293     return STATUS_SUCCESS;
294 }
295 
296 /*
297  * @unimplemented
298  */
299 NTSTATUS
300 NTAPI
301 RtlConsoleMultiByteToUnicodeN(OUT PWCHAR UnicodeString,
302                               IN ULONG UnicodeSize,
303                               OUT PULONG ResultSize,
304                               IN PCSTR MbString,
305                               IN ULONG MbSize,
306                               OUT PULONG Unknown)
307 {
308     PAGED_CODE_RTL();
309 
310     UNIMPLEMENTED;
311     DPRINT1("RtlConsoleMultiByteToUnicodeN calling RtlMultiByteToUnicodeN\n");
312     *Unknown = 1;
313     return RtlMultiByteToUnicodeN(UnicodeString,
314                                   UnicodeSize,
315                                   ResultSize,
316                                   MbString,
317                                   MbSize);
318 }
319 
320 /*
321  * @implemented
322  */
323 NTSTATUS
324 NTAPI
325 RtlMultiByteToUnicodeSize(OUT PULONG UnicodeSize,
326                           IN PCSTR MbString,
327                           IN ULONG MbSize)
328 {
329     ULONG Length = 0;
330 
331     PAGED_CODE_RTL();
332 
333     if (!NlsMbCodePageTag)
334     {
335         /* single-byte code page */
336         *UnicodeSize = MbSize * sizeof(WCHAR);
337     }
338     else
339     {
340         /* multi-byte code page */
341         /* FIXME */
342 
343         while (MbSize--)
344         {
345             UCHAR Char = *(PUCHAR)MbString++;
346 
347             if (Char >= 0x80 && NlsLeadByteInfo[Char])
348             {
349                 if (MbSize)
350                 {
351                     /* Move on */
352                     MbSize--;
353                     MbString++;
354                 }
355             }
356 
357             /* Increase returned size */
358             Length++;
359         }
360 
361         /* Return final size */
362         *UnicodeSize = Length * sizeof(WCHAR);
363     }
364 
365     /* Success */
366     return STATUS_SUCCESS;
367 }
368 
369 /*
370  * @unimplemented
371  */
372 NTSTATUS NTAPI
373 RtlOemToUnicodeN(OUT PWCHAR UnicodeString,
374                  IN ULONG UnicodeSize,
375                  OUT PULONG ResultSize OPTIONAL,
376                  IN PCCH OemString,
377                  IN ULONG OemSize)
378 {
379     ULONG Size = 0;
380     ULONG i;
381 
382     PAGED_CODE_RTL();
383 
384     if (!NlsMbOemCodePageTag)
385     {
386         /* single-byte code page */
387         if (OemSize > (UnicodeSize / sizeof(WCHAR)))
388             Size = UnicodeSize / sizeof(WCHAR);
389         else
390             Size = OemSize;
391 
392         if (ResultSize)
393             *ResultSize = Size * sizeof(WCHAR);
394 
395         for (i = 0; i < Size; i++)
396         {
397             *UnicodeString = NlsOemToUnicodeTable[(UCHAR)*OemString];
398             UnicodeString++;
399             OemString++;
400         }
401     }
402     else
403     {
404         /* multi-byte code page */
405         /* FIXME */
406 
407         UCHAR Char;
408         USHORT OemLeadByteInfo;
409         PCCH OemEnd = OemString + OemSize;
410 
411         for (i = 0; i < UnicodeSize / sizeof(WCHAR) && OemString < OemEnd; i++)
412         {
413             Char = *(PUCHAR)OemString++;
414 
415             if (Char < 0x80)
416             {
417                 *UnicodeString++ = Char;
418                 continue;
419             }
420 
421             OemLeadByteInfo = NlsOemLeadByteInfo[Char];
422 
423             if (!OemLeadByteInfo)
424             {
425                 *UnicodeString++ = NlsOemToUnicodeTable[Char];
426                 continue;
427             }
428 
429             if (OemString < OemEnd)
430                 *UnicodeString++ =
431                     NlsOemLeadByteInfo[OemLeadByteInfo + *(PUCHAR)OemString++];
432         }
433 
434         if (ResultSize)
435             *ResultSize = i * sizeof(WCHAR);
436     }
437 
438     return STATUS_SUCCESS;
439 }
440 
441 /*
442  * @implemented
443  */
444 VOID NTAPI
445 RtlResetRtlTranslations(IN PNLSTABLEINFO NlsTable)
446 {
447     PAGED_CODE_RTL();
448 
449     DPRINT("RtlResetRtlTranslations() called\n");
450 
451     /* Set ANSI data */
452     NlsAnsiToUnicodeTable = (PUSHORT)NlsTable->AnsiTableInfo.MultiByteTable;
453     NlsUnicodeToAnsiTable = NlsTable->AnsiTableInfo.WideCharTable;
454     NlsUnicodeToMbAnsiTable = (PUSHORT)NlsTable->AnsiTableInfo.WideCharTable;
455     NlsMbCodePageTag = (NlsTable->AnsiTableInfo.DBCSCodePage != 0);
456     NlsLeadByteInfo = NlsTable->AnsiTableInfo.DBCSOffsets;
457     NlsAnsiCodePage = NlsTable->AnsiTableInfo.CodePage;
458     DPRINT("Ansi codepage %hu\n", NlsAnsiCodePage);
459 
460     /* Set OEM data */
461     NlsOemToUnicodeTable = (PUSHORT)NlsTable->OemTableInfo.MultiByteTable;
462     NlsUnicodeToOemTable = NlsTable->OemTableInfo.WideCharTable;
463     NlsUnicodeToMbOemTable = (PUSHORT)NlsTable->OemTableInfo.WideCharTable;
464     NlsMbOemCodePageTag = (NlsTable->OemTableInfo.DBCSCodePage != 0);
465     NlsOemLeadByteInfo = NlsTable->OemTableInfo.DBCSOffsets;
466     NlsOemCodePage = NlsTable->OemTableInfo.CodePage;
467     DPRINT("Oem codepage %hu\n", NlsOemCodePage);
468 
469     /* Set Unicode case map data */
470     NlsUnicodeUpcaseTable = NlsTable->UpperCaseTable;
471     NlsUnicodeLowercaseTable = NlsTable->LowerCaseTable;
472 
473     /* set the default characters for RtlpDidUnicodeToOemWork */
474     NlsOemDefaultChar = NlsTable->OemTableInfo.DefaultChar;
475     NlsUnicodeDefaultChar = NlsTable->OemTableInfo.TransDefaultChar;
476 }
477 
478 /*
479  * @unimplemented
480  */
481 NTSTATUS NTAPI
482 RtlUnicodeToCustomCPN(IN PCPTABLEINFO CustomCP,
483                       OUT PCHAR CustomString,
484                       IN ULONG CustomSize,
485                       OUT PULONG ResultSize OPTIONAL,
486                       IN PWCHAR UnicodeString,
487                       IN ULONG UnicodeSize)
488 {
489     ULONG Size = 0;
490     ULONG i;
491 
492     PAGED_CODE_RTL();
493 
494     if (!CustomCP->DBCSCodePage)
495     {
496         /* single-byte code page */
497         if (UnicodeSize > (CustomSize * sizeof(WCHAR)))
498             Size = CustomSize;
499         else
500             Size = UnicodeSize / sizeof(WCHAR);
501 
502         if (ResultSize)
503             *ResultSize = Size;
504 
505         for (i = 0; i < Size; i++)
506         {
507             *CustomString = ((PCHAR)CustomCP->WideCharTable)[*UnicodeString];
508             CustomString++;
509             UnicodeString++;
510         }
511     }
512     else
513     {
514         /* multi-byte code page */
515         /* FIXME */
516         ASSERT(FALSE);
517     }
518 
519     return STATUS_SUCCESS;
520 }
521 
522 /*
523  * @unimplemented
524  */
525 NTSTATUS NTAPI
526 RtlUnicodeToMultiByteN(OUT PCHAR MbString,
527                        IN ULONG MbSize,
528                        OUT PULONG ResultSize OPTIONAL,
529                        IN PCWCH UnicodeString,
530                        IN ULONG UnicodeSize)
531 {
532     ULONG Size = 0;
533     ULONG i;
534 
535     PAGED_CODE_RTL();
536 
537     if (!NlsMbCodePageTag)
538     {
539         /* single-byte code page */
540         Size = (UnicodeSize > (MbSize * sizeof(WCHAR)))
541                 ? MbSize : (UnicodeSize / sizeof(WCHAR));
542 
543         if (ResultSize)
544             *ResultSize = Size;
545 
546         for (i = 0; i < Size; i++)
547         {
548             *MbString++ = NlsUnicodeToAnsiTable[*UnicodeString++];
549         }
550     }
551     else
552     {
553         /* multi-byte code page */
554         /* FIXME */
555 
556         USHORT WideChar;
557         USHORT MbChar;
558 
559         for (i = MbSize, Size = UnicodeSize / sizeof(WCHAR); i && Size; i--, Size--)
560         {
561             WideChar = *UnicodeString++;
562 
563             if (WideChar < 0x80)
564             {
565                 *MbString++ = LOBYTE(WideChar);
566                 continue;
567             }
568 
569             MbChar = NlsUnicodeToMbAnsiTable[WideChar];
570 
571             if (!HIBYTE(MbChar))
572             {
573                 *MbString++ = LOBYTE(MbChar);
574                 continue;
575             }
576 
577             if (i >= 2)
578             {
579                 *MbString++ = HIBYTE(MbChar);
580                 *MbString++ = LOBYTE(MbChar);
581                 i--;
582             }
583             else break;
584         }
585 
586         if (ResultSize)
587             *ResultSize = MbSize - i;
588     }
589 
590     return STATUS_SUCCESS;
591 }
592 
593 /*
594  * @implemented
595  */
596 NTSTATUS
597 NTAPI
598 RtlUnicodeToMultiByteSize(OUT PULONG MbSize,
599                           IN PCWCH UnicodeString,
600                           IN ULONG UnicodeSize)
601 {
602     ULONG UnicodeLength = UnicodeSize / sizeof(WCHAR);
603     ULONG MbLength = 0;
604 
605     PAGED_CODE_RTL();
606 
607     if (!NlsMbCodePageTag)
608     {
609         /* single-byte code page */
610         *MbSize = UnicodeLength;
611     }
612     else
613     {
614         /* multi-byte code page */
615         /* FIXME */
616 
617         while (UnicodeLength--)
618         {
619             USHORT WideChar = *UnicodeString++;
620 
621             if (WideChar >= 0x80 && HIBYTE(NlsUnicodeToMbAnsiTable[WideChar]))
622             {
623                 MbLength += sizeof(WCHAR);
624             }
625             else
626             {
627                 MbLength++;
628             }
629         }
630 
631         *MbSize = MbLength;
632     }
633 
634     /* Success */
635     return STATUS_SUCCESS;
636 }
637 
638 /*
639  * @implemented
640  */
641 NTSTATUS
642 NTAPI
643 RtlUnicodeToOemN(OUT PCHAR OemString,
644                  IN ULONG OemSize,
645                  OUT PULONG ResultSize OPTIONAL,
646                  IN PCWCH UnicodeString,
647                  IN ULONG UnicodeSize)
648 {
649     ULONG Size = 0;
650 
651     PAGED_CODE_RTL();
652 
653     /* Bytes -> chars */
654     UnicodeSize /= sizeof(WCHAR);
655 
656     if (!NlsMbOemCodePageTag)
657     {
658         while (OemSize && UnicodeSize)
659         {
660             OemString[Size] = NlsUnicodeToOemTable[*UnicodeString++];
661             Size++;
662             OemSize--;
663             UnicodeSize--;
664         }
665     }
666     else
667     {
668         while (OemSize && UnicodeSize)
669         {
670             USHORT OemChar = NlsUnicodeToMbOemTable[*UnicodeString++];
671 
672             if (HIBYTE(OemChar))
673             {
674                 if (OemSize < 2)
675                     break;
676                 OemString[Size++] = HIBYTE(OemChar);
677                 OemSize--;
678             }
679             OemString[Size++] = LOBYTE(OemChar);
680             OemSize--;
681             UnicodeSize--;
682         }
683     }
684 
685     if (ResultSize)
686         *ResultSize = Size;
687 
688     return UnicodeSize ? STATUS_BUFFER_OVERFLOW : STATUS_SUCCESS;
689 }
690 
691 /*
692  * @implemented
693  */
694 WCHAR NTAPI
695 RtlpUpcaseUnicodeChar(IN WCHAR Source)
696 {
697     USHORT Offset;
698 
699     if (Source < 'a')
700         return Source;
701 
702     if (Source <= 'z')
703         return (Source - ('a' - 'A'));
704 
705     Offset = ((USHORT)Source >> 8) & 0xFF;
706     Offset = NlsUnicodeUpcaseTable[Offset];
707 
708     Offset += ((USHORT)Source >> 4) & 0xF;
709     Offset = NlsUnicodeUpcaseTable[Offset];
710 
711     Offset += ((USHORT)Source & 0xF);
712     Offset = NlsUnicodeUpcaseTable[Offset];
713 
714     return Source + (SHORT)Offset;
715 }
716 
717 /*
718  * @implemented
719  */
720 WCHAR NTAPI
721 RtlUpcaseUnicodeChar(IN WCHAR Source)
722 {
723     PAGED_CODE_RTL();
724 
725     return RtlpUpcaseUnicodeChar(Source);
726 }
727 
728 /*
729  * @implemented
730  */
731 NTSTATUS NTAPI
732 RtlUpcaseUnicodeToCustomCPN(IN PCPTABLEINFO CustomCP,
733                             OUT PCHAR CustomString,
734                             IN ULONG CustomSize,
735                             OUT PULONG ResultSize OPTIONAL,
736                             IN PWCHAR UnicodeString,
737                             IN ULONG UnicodeSize)
738 {
739     WCHAR UpcaseChar;
740     ULONG Size = 0;
741     ULONG i;
742 
743     PAGED_CODE_RTL();
744 
745     if (!CustomCP->DBCSCodePage)
746     {
747         /* single-byte code page */
748         if (UnicodeSize > (CustomSize * sizeof(WCHAR)))
749             Size = CustomSize;
750         else
751             Size = UnicodeSize / sizeof(WCHAR);
752 
753         if (ResultSize)
754             *ResultSize = Size;
755 
756         for (i = 0; i < Size; i++)
757         {
758             UpcaseChar = RtlpUpcaseUnicodeChar(*UnicodeString);
759             *CustomString = ((PCHAR)CustomCP->WideCharTable)[UpcaseChar];
760             ++CustomString;
761             ++UnicodeString;
762         }
763     }
764     else
765     {
766         /* multi-byte code page */
767         /* FIXME */
768         ASSERT(FALSE);
769     }
770 
771     return STATUS_SUCCESS;
772 }
773 
774 /*
775  * @unimplemented
776  */
777 NTSTATUS NTAPI
778 RtlUpcaseUnicodeToMultiByteN(OUT PCHAR MbString,
779                              IN ULONG MbSize,
780                              OUT PULONG ResultSize OPTIONAL,
781                              IN PCWCH UnicodeString,
782                              IN ULONG UnicodeSize)
783 {
784     WCHAR UpcaseChar;
785     ULONG Size = 0;
786     ULONG i;
787 
788     PAGED_CODE_RTL();
789 
790     if (!NlsMbCodePageTag)
791     {
792         /* single-byte code page */
793         if (UnicodeSize > (MbSize * sizeof(WCHAR)))
794             Size = MbSize;
795         else
796             Size = UnicodeSize / sizeof(WCHAR);
797 
798         if (ResultSize)
799             *ResultSize = Size;
800 
801         for (i = 0; i < Size; i++)
802         {
803             UpcaseChar = RtlpUpcaseUnicodeChar(*UnicodeString);
804             *MbString = NlsUnicodeToAnsiTable[UpcaseChar];
805             MbString++;
806             UnicodeString++;
807         }
808     }
809     else
810     {
811         /* multi-byte code page */
812         /* FIXME */
813         ASSERT(FALSE);
814     }
815 
816     return STATUS_SUCCESS;
817 }
818 
819 /*
820  * @unimplemented
821  */
822 NTSTATUS NTAPI
823 RtlUpcaseUnicodeToOemN(OUT PCHAR OemString,
824                        IN ULONG OemSize,
825                        OUT PULONG ResultSize OPTIONAL,
826                        IN PCWCH UnicodeString,
827                        IN ULONG UnicodeSize)
828 {
829     WCHAR UpcaseChar;
830     ULONG Size = 0;
831     ULONG i;
832 
833     PAGED_CODE_RTL();
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