update for HEAD-2003091401
[reactos.git] / ntoskrnl / rtl / nls.c
1 /* $Id$
2  *
3  * COPYRIGHT:       See COPYING in the top level directory
4  * PROJECT:         ReactOS kernel
5  * FILE:            ntoskrnl/rtl/nls.c
6  * PURPOSE:         National Language Support (NLS) functions
7  * UPDATE HISTORY:
8  *                  20/08/99 Created by Emanuele Aliberti
9  *                  10/11/99 Added translation functions.
10  *
11  * TODO:
12  *   1) Add multi-byte translation code.
13  */
14
15 #include <ddk/ntddk.h>
16 #include <internal/mm.h>
17 #include <internal/nls.h>
18
19 #define NDEBUG
20 #include <internal/debug.h>
21
22
23 /* GLOBALS *******************************************************************/
24
25 USHORT NlsAnsiCodePage = 0; /* exported */
26 BOOLEAN NlsMbCodePageTag = FALSE; /* exported */
27 PWCHAR NlsAnsiToUnicodeTable = NULL;
28 PCHAR NlsUnicodeToAnsiTable = NULL;
29 PWCHAR NlsDbcsUnicodeToAnsiTable = NULL;
30 PUSHORT NlsLeadByteInfo = NULL; /* exported */
31
32
33 USHORT NlsOemCodePage = 0;
34 BOOLEAN NlsMbOemCodePageTag = FALSE; /* exported */
35 PWCHAR NlsOemToUnicodeTable = NULL;
36 PCHAR NlsUnicodeToOemTable =NULL;
37 PWCHAR NlsDbcsUnicodeToOemTable = NULL;
38 PUSHORT NlsOemLeadByteInfo = NULL; /* exported */
39
40
41 PUSHORT NlsUnicodeUpcaseTable = NULL;
42 PUSHORT NlsUnicodeLowercaseTable = NULL;
43
44
45 static PUSHORT NlsAnsiCodePageTable = NULL;
46 static ULONG NlsAnsiCodePageTableSize = 0;
47
48 static PUSHORT NlsOemCodePageTable = NULL;
49 static ULONG NlsOemCodePageTableSize = 0;
50
51 static PUSHORT NlsUnicodeCasemapTable = NULL;
52 static ULONG NlsUnicodeCasemapTableSize = 0;
53
54 PVOID NlsSectionObject = NULL;
55 static PVOID NlsSectionBase = NULL;
56 static ULONG NlsSectionViewSize = 0;
57
58 ULONG NlsAnsiTableOffset = 0;
59 ULONG NlsOemTableOffset = 0;
60 ULONG NlsUnicodeTableOffset = 0;
61
62
63 /* FUNCTIONS *****************************************************************/
64
65 VOID
66 RtlpImportAnsiCodePage(PUSHORT TableBase,
67                        ULONG Size)
68 {
69   NlsAnsiCodePageTable = TableBase;
70   NlsAnsiCodePageTableSize = Size;
71 }
72
73
74 VOID
75 RtlpImportOemCodePage(PUSHORT TableBase,
76                       ULONG Size)
77 {
78   NlsOemCodePageTable = TableBase;
79   NlsOemCodePageTableSize = Size;
80 }
81
82
83 VOID
84 RtlpImportUnicodeCasemap(PUSHORT TableBase,
85                          ULONG Size)
86 {
87   NlsUnicodeCasemapTable = TableBase;
88   NlsUnicodeCasemapTableSize = Size;
89 }
90
91
92 VOID
93 RtlpCreateInitialNlsTables(VOID)
94 {
95   NLSTABLEINFO NlsTable;
96
97   if (NlsAnsiCodePageTable == NULL || NlsAnsiCodePageTableSize == 0 ||
98       NlsOemCodePageTable == NULL || NlsOemCodePageTableSize == 0 ||
99       NlsUnicodeCasemapTable == NULL || NlsUnicodeCasemapTableSize == 0)
100     {
101       KEBUGCHECKEX (0x32, STATUS_UNSUCCESSFUL, 1, 0, 0);
102     }
103
104   RtlInitNlsTables (NlsAnsiCodePageTable,
105                     NlsOemCodePageTable,
106                     NlsUnicodeCasemapTable,
107                     &NlsTable);
108
109   RtlResetRtlTranslations (&NlsTable);
110 }
111
112
113 VOID
114 RtlpCreateNlsSection(VOID)
115 {
116   NLSTABLEINFO NlsTable;
117   LARGE_INTEGER SectionSize;
118   HANDLE SectionHandle;
119   NTSTATUS Status;
120
121   DPRINT("RtlpCreateNlsSection() called\n");
122
123   NlsSectionViewSize = ROUND_UP(NlsAnsiCodePageTableSize, PAGE_SIZE) +
124                        ROUND_UP(NlsOemCodePageTableSize, PAGE_SIZE) +
125                        ROUND_UP(NlsUnicodeCasemapTableSize, PAGE_SIZE);
126
127   DPRINT("NlsSectionViewSize %lx\n", NlsSectionViewSize);
128
129   SectionSize.QuadPart = (LONGLONG)NlsSectionViewSize;
130   Status = NtCreateSection(&SectionHandle,
131                            SECTION_ALL_ACCESS,
132                            NULL,
133                            &SectionSize,
134                            PAGE_READWRITE,
135                            SEC_COMMIT,
136                            NULL);
137   if (!NT_SUCCESS(Status))
138     {
139       DPRINT1("NtCreateSection() failed\n");
140       KEBUGCHECKEX(0x32, Status, 1, 1, 0);
141     }
142
143   Status = ObReferenceObjectByHandle(SectionHandle,
144                                      SECTION_ALL_ACCESS,
145                                      MmSectionObjectType,
146                                      KernelMode,
147                                      &NlsSectionObject,
148                                      NULL);
149   NtClose(SectionHandle);
150   if (!NT_SUCCESS(Status))
151     {
152       DPRINT1("ObReferenceObjectByHandle() failed\n");
153       KEBUGCHECKEX(0x32, Status, 1, 2, 0);
154     }
155
156   Status = MmMapViewInSystemSpace(NlsSectionObject,
157                                   &NlsSectionBase,
158                                   &NlsSectionViewSize);
159   if (!NT_SUCCESS(Status))
160     {
161       DPRINT1("MmMapViewInSystemSpace() failed\n");
162       KEBUGCHECKEX(0x32, Status, 1, 3, 0);
163     }
164
165   DPRINT("NlsSection: Base %p  Size %lx\n", 
166          NlsSectionBase,
167          NlsSectionViewSize);
168
169   NlsAnsiTableOffset = 0;
170   RtlCopyMemory((PVOID)((ULONG)NlsSectionBase + NlsAnsiTableOffset),
171                 NlsAnsiCodePageTable,
172                 NlsAnsiCodePageTableSize);
173
174   NlsOemTableOffset = NlsAnsiTableOffset + ROUND_UP(NlsAnsiCodePageTableSize, PAGE_SIZE);
175   RtlCopyMemory((PVOID)((ULONG)NlsSectionBase + NlsOemTableOffset),
176                 NlsOemCodePageTable,
177                 NlsOemCodePageTableSize);
178
179   NlsUnicodeTableOffset = NlsOemTableOffset + ROUND_UP(NlsOemCodePageTableSize, PAGE_SIZE);
180   RtlCopyMemory((PVOID)((ULONG)NlsSectionBase + NlsUnicodeTableOffset),
181                 NlsUnicodeCasemapTable,
182                 NlsUnicodeCasemapTableSize);
183
184   RtlInitNlsTables ((PVOID)((ULONG)NlsSectionBase + NlsAnsiTableOffset),
185                     (PVOID)((ULONG)NlsSectionBase + NlsOemTableOffset),
186                     (PVOID)((ULONG)NlsSectionBase + NlsUnicodeTableOffset),
187                     &NlsTable);
188
189   RtlResetRtlTranslations (&NlsTable);
190 }
191
192
193 /*
194  * @unimplemented
195  */
196 NTSTATUS STDCALL
197 RtlCustomCPToUnicodeN(IN PCPTABLEINFO CustomCP,
198                       PWCHAR UnicodeString,
199                       ULONG UnicodeSize,
200                       PULONG ResultSize,
201                       PCHAR CustomString,
202                       ULONG CustomSize)
203 {
204   ULONG Size = 0;
205   ULONG i;
206
207   if (CustomCP->DBCSCodePage == 0)
208     {
209       /* single-byte code page */
210       if (CustomSize > (UnicodeSize / sizeof(WCHAR)))
211         Size = UnicodeSize / sizeof(WCHAR);
212       else
213         Size = CustomSize;
214
215       if (ResultSize != NULL)
216         *ResultSize = Size * sizeof(WCHAR);
217
218       for (i = 0; i < Size; i++)
219         {
220           *UnicodeString = CustomCP->MultiByteTable[(unsigned int)*CustomString];
221           UnicodeString++;
222           CustomString++;
223         }
224     }
225   else
226     {
227       /* multi-byte code page */
228       /* FIXME */
229     }
230
231   return(STATUS_SUCCESS);
232 }
233
234
235 WCHAR
236 RtlDowncaseUnicodeChar (IN WCHAR Source)
237 {
238   USHORT Offset;
239
240   if (Source < L'A')
241     return Source;
242
243   if (Source <= L'Z')
244     return Source + (L'a' - L'A');
245
246   if (Source < 0x80)
247     return Source;
248
249   Offset = ((USHORT)Source >> 8);
250   Offset = NlsUnicodeLowercaseTable[Offset];
251
252   Offset += (((USHORT)Source & 0x00F0) >> 4);
253   Offset = NlsUnicodeLowercaseTable[Offset];
254
255   Offset += ((USHORT)Source & 0x000F);
256   Offset = NlsUnicodeLowercaseTable[Offset];
257
258   return Source + (SHORT)Offset;
259 }
260
261
262 /*
263  * @implemented
264  */
265 VOID STDCALL
266 RtlGetDefaultCodePage(PUSHORT AnsiCodePage,
267                       PUSHORT OemCodePage)
268 {
269   *AnsiCodePage = NlsAnsiCodePage;
270   *OemCodePage = NlsOemCodePage;
271 }
272
273
274 /*
275  * @implemented
276  */
277 VOID STDCALL
278 RtlInitCodePageTable(IN PUSHORT TableBase,
279                      OUT PCPTABLEINFO CodePageTable)
280 {
281   PNLS_FILE_HEADER NlsFileHeader;
282   PUSHORT Ptr;
283   USHORT Offset;
284
285   DPRINT("RtlInitCodePageTable() called\n");
286
287   NlsFileHeader = (PNLS_FILE_HEADER)TableBase;
288
289   CodePageTable->CodePage = NlsFileHeader->CodePage;
290   CodePageTable->MaximumCharacterSize = NlsFileHeader->MaximumCharacterSize;
291   CodePageTable->DefaultChar = NlsFileHeader->DefaultChar;
292   CodePageTable->UniDefaultChar = NlsFileHeader->UniDefaultChar;
293   CodePageTable->TransDefaultChar = NlsFileHeader->TransDefaultChar;
294   CodePageTable->TransUniDefaultChar = NlsFileHeader->TransUniDefaultChar;
295
296   RtlCopyMemory(&CodePageTable->LeadByte,
297                 &NlsFileHeader->LeadByte,
298                 MAXIMUM_LEADBYTES);
299
300   /* Set Pointer to start of multi byte table */
301   Ptr = (PUSHORT)((ULONG_PTR)TableBase + 2 * NlsFileHeader->HeaderSize);
302
303   /* Get offset to the wide char table */
304   Offset = (USHORT)(*Ptr++) + NlsFileHeader->HeaderSize + 1;
305
306   /* Set pointer to the multi byte table */
307   CodePageTable->MultiByteTable = Ptr;
308
309   /* Skip ANSI and OEM table */
310   Ptr += 256;
311   if (*Ptr++)
312     Ptr += 256;
313
314   /* Set pointer to DBCS ranges */
315   CodePageTable->DBCSRanges = (PUSHORT)Ptr;
316
317   if (*Ptr > 0)
318     {
319       CodePageTable->DBCSCodePage = 1;
320       CodePageTable->DBCSOffsets = (PUSHORT)++Ptr;
321     }
322   else
323     {
324       CodePageTable->DBCSCodePage = 0;
325       CodePageTable->DBCSOffsets = 0;
326     }
327
328   CodePageTable->WideCharTable = (PVOID)((ULONG_PTR)TableBase + 2 * Offset);
329 }
330
331
332 VOID STDCALL
333 RtlInitNlsTables(IN PUSHORT AnsiTableBase,
334                  IN PUSHORT OemTableBase,
335                  IN PUSHORT CaseTableBase,
336                  OUT PNLSTABLEINFO NlsTable)
337 {
338   DPRINT("RtlInitNlsTables()called\n");
339
340   RtlInitCodePageTable (AnsiTableBase,
341                         &NlsTable->AnsiTableInfo);
342
343   RtlInitCodePageTable (OemTableBase,
344                         &NlsTable->OemTableInfo);
345
346   NlsTable->UpperCaseTable = (PUSHORT)CaseTableBase + 2;
347   NlsTable->LowerCaseTable = (PUSHORT)CaseTableBase + *((PUSHORT)CaseTableBase + 1) + 2;
348 }
349
350
351 /*
352  * @unimplemented
353  */
354 NTSTATUS STDCALL
355 RtlMultiByteToUnicodeN(PWCHAR UnicodeString,
356                        ULONG UnicodeSize,
357                        PULONG ResultSize,
358                        const PCHAR MbString,
359                        ULONG MbSize)
360 {
361   ULONG Size = 0;
362   ULONG i;
363
364   if (NlsMbCodePageTag == FALSE)
365     {
366       /* single-byte code page */
367       if (MbSize > (UnicodeSize / sizeof(WCHAR)))
368         Size = UnicodeSize / sizeof(WCHAR);
369       else
370         Size = MbSize;
371
372       if (ResultSize != NULL)
373         *ResultSize = Size * sizeof(WCHAR);
374
375       for (i = 0; i < Size; i++)
376         UnicodeString[i] = NlsAnsiToUnicodeTable[(unsigned int)MbString[i]];
377     }
378   else
379     {
380       /* multi-byte code page */
381       /* FIXME */
382     }
383
384   return(STATUS_SUCCESS);
385 }
386
387
388 /*
389  * @implemented
390  */
391 NTSTATUS STDCALL
392 RtlMultiByteToUnicodeSize(PULONG UnicodeSize,
393                           PCHAR MbString,
394                           ULONG MbSize)
395 {
396   ULONG Length;
397
398   if (NlsMbCodePageTag == FALSE)
399     {
400       /* single-byte code page */
401       *UnicodeSize = MbSize * sizeof (WCHAR);
402     }
403   else
404     {
405       /* multi-byte code page */
406       for (Length = 0; MbSize; MbSize--, MbString++, Length++)
407         {
408           if (NlsLeadByteInfo[(UCHAR)*MbString] != 0)
409             {
410               if (!--MbSize)
411                 break;  /* partial char, ignore it */
412               MbString++;
413             }
414         }
415
416       *UnicodeSize = Length * sizeof(WCHAR);
417     }
418
419   return STATUS_SUCCESS;
420 }
421
422
423 /*
424  * @unimplemented
425  */
426 NTSTATUS STDCALL
427 RtlOemToUnicodeN(PWCHAR UnicodeString,
428                  ULONG UnicodeSize,
429                  PULONG ResultSize,
430                  PCHAR OemString,
431                  ULONG OemSize)
432 {
433   ULONG Size = 0;
434   ULONG i;
435
436   if (NlsMbOemCodePageTag == FALSE)
437     {
438       /* single-byte code page */
439       if (OemSize > (UnicodeSize / sizeof(WCHAR)))
440         Size = UnicodeSize / sizeof(WCHAR);
441       else
442         Size = OemSize;
443
444       if (ResultSize != NULL)
445         *ResultSize = Size * sizeof(WCHAR);
446
447       for (i = 0; i < Size; i++)
448         {
449           *UnicodeString = NlsOemToUnicodeTable[(unsigned int)*OemString];
450           UnicodeString++;
451           OemString++;
452         }
453     }
454   else
455     {
456       /* multi-byte code page */
457       /* FIXME */
458     }
459
460   return(STATUS_SUCCESS);
461 }
462
463
464 VOID STDCALL
465 RtlResetRtlTranslations(IN PNLSTABLEINFO NlsTable)
466 {
467   DPRINT("RtlResetRtlTranslations() called\n");
468
469   /* Set ANSI data */
470   NlsAnsiToUnicodeTable = NlsTable->AnsiTableInfo.MultiByteTable;
471   NlsUnicodeToAnsiTable = NlsTable->AnsiTableInfo.WideCharTable;
472   NlsDbcsUnicodeToAnsiTable = (PWCHAR)NlsTable->AnsiTableInfo.WideCharTable;
473   NlsMbCodePageTag = (NlsTable->AnsiTableInfo.DBCSCodePage != 0);
474   NlsLeadByteInfo = NlsTable->AnsiTableInfo.DBCSOffsets;
475   NlsAnsiCodePage = NlsTable->AnsiTableInfo.CodePage;
476   DPRINT("Ansi codepage %hu\n", NlsAnsiCodePage);
477
478   /* Set OEM data */
479   NlsOemToUnicodeTable = NlsTable->OemTableInfo.MultiByteTable;
480   NlsUnicodeToOemTable = NlsTable->OemTableInfo.WideCharTable;
481   NlsDbcsUnicodeToOemTable = (PWCHAR)NlsTable->OemTableInfo.WideCharTable;
482   NlsMbOemCodePageTag = (NlsTable->OemTableInfo.DBCSCodePage != 0);
483   NlsOemLeadByteInfo = NlsTable->OemTableInfo.DBCSOffsets;
484   NlsOemCodePage = NlsTable->OemTableInfo.CodePage;
485   DPRINT("Oem codepage %hu\n", NlsOemCodePage);
486
487   /* Set Unicode case map data */
488   NlsUnicodeUpcaseTable = NlsTable->UpperCaseTable;
489   NlsUnicodeLowercaseTable = NlsTable->LowerCaseTable;
490 }
491
492
493 /*
494  * @unimplemented
495  */
496 NTSTATUS STDCALL
497 RtlUnicodeToCustomCPN(IN PCPTABLEINFO CustomCP,
498                       PCHAR CustomString,
499                       ULONG CustomSize,
500                       PULONG ResultSize,
501                       PWCHAR UnicodeString,
502                       ULONG UnicodeSize)
503 {
504   ULONG Size = 0;
505   ULONG i;
506
507   if (CustomCP->DBCSCodePage == 0)
508     {
509       /* single-byte code page */
510       if (UnicodeSize > (CustomSize * sizeof(WCHAR)))
511         Size = CustomSize;
512       else
513         Size = UnicodeSize / sizeof(WCHAR);
514
515       if (ResultSize != NULL)
516         *ResultSize = Size;
517
518       for (i = 0; i < Size; i++)
519         {
520           *CustomString = ((PCHAR)CustomCP->WideCharTable)[(unsigned int)*UnicodeString];
521           CustomString++;
522           UnicodeString++;
523         }
524     }
525   else
526     {
527       /* multi-byte code page */
528       /* FIXME */
529     }
530
531   return(STATUS_SUCCESS);
532 }
533
534
535 /*
536  * @unimplemented
537  */
538 NTSTATUS
539 STDCALL
540 RtlUnicodeToMultiByteN(PCHAR MbString,
541                        ULONG MbSize,
542                        PULONG ResultSize,
543                        PWCHAR UnicodeString,
544                        ULONG UnicodeSize)
545 {
546   ULONG Size = 0;
547   ULONG i;
548
549   if (NlsMbCodePageTag == FALSE)
550     {
551       /* single-byte code page */
552       if (UnicodeSize > (MbSize * sizeof(WCHAR)))
553         Size = MbSize;
554       else
555         Size = UnicodeSize / sizeof(WCHAR);
556
557       if (ResultSize != NULL)
558         *ResultSize = Size;
559
560       for (i = 0; i < Size; i++)
561         {
562           *MbString = NlsUnicodeToAnsiTable[(unsigned int)*UnicodeString];
563           MbString++;
564           UnicodeString++;
565         }
566     }
567   else
568     {
569       /* multi-byte code page */
570       /* FIXME */
571     }
572
573   return(STATUS_SUCCESS);
574 }
575
576
577 /*
578  * @implemented
579  */
580 NTSTATUS STDCALL
581 RtlUnicodeToMultiByteSize(PULONG MbSize,
582                           PWCHAR UnicodeString,
583                           ULONG UnicodeSize)
584 {
585   ULONG UnicodeLength;
586   ULONG MbLength;
587
588   if (NlsMbCodePageTag == FALSE)
589     {
590       /* single-byte code page */
591       *MbSize = UnicodeSize / sizeof (WCHAR);
592     }
593   else
594     {
595       /* multi-byte code page */
596       UnicodeLength = UnicodeSize / sizeof(WCHAR);
597       MbLength = 0;
598       while (UnicodeLength > 0)
599         {
600           if (NlsLeadByteInfo[*UnicodeString] & 0xff00)
601             MbLength++;
602
603           MbLength++;
604           UnicodeLength--;
605           UnicodeString++;
606         }
607
608       *MbSize = MbLength;
609     }
610
611   return(STATUS_SUCCESS);
612 }
613
614
615 /*
616  * @unimplemented
617  */
618 NTSTATUS STDCALL
619 RtlUnicodeToOemN(PCHAR OemString,
620                  ULONG OemSize,
621                  PULONG ResultSize,
622                  PWCHAR UnicodeString,
623                  ULONG UnicodeSize)
624 {
625   ULONG Size = 0;
626   ULONG i;
627
628   if (NlsMbOemCodePageTag == FALSE)
629     {
630       /* single-byte code page */
631       if (UnicodeSize > (OemSize * sizeof(WCHAR)))
632         Size = OemSize;
633       else
634         Size = UnicodeSize / sizeof(WCHAR);
635
636       if (ResultSize != NULL)
637         *ResultSize = Size;
638
639       for (i = 0; i < Size; i++)
640         {
641           *OemString = NlsUnicodeToOemTable[(unsigned int)*UnicodeString];
642           OemString++;
643           UnicodeString++;
644         }
645     }
646   else
647     {
648       /* multi-byte code page */
649       /* FIXME */
650     }
651
652   return(STATUS_SUCCESS);
653 }
654
655
656 /*
657  * @implemented
658  */
659 WCHAR STDCALL
660 RtlUpcaseUnicodeChar(IN WCHAR Source)
661 {
662   USHORT Offset;
663
664   if (Source < L'a')
665     return Source;
666
667   if (Source <= L'z')
668     return (Source - (L'a' - L'A'));
669
670   Offset = ((USHORT)Source >> 8);
671   Offset = NlsUnicodeUpcaseTable[Offset];
672
673   Offset += (((USHORT)Source & 0x00F0) >> 4);
674   Offset = NlsUnicodeUpcaseTable[Offset];
675
676   Offset += ((USHORT)Source & 0x000F);
677   Offset = NlsUnicodeUpcaseTable[Offset];
678
679   return Source + (SHORT)Offset;
680 }
681
682
683 /*
684  * @unimplemented
685  */
686 NTSTATUS STDCALL
687 RtlUpcaseUnicodeToCustomCPN(IN PCPTABLEINFO CustomCP,
688                             PCHAR CustomString,
689                             ULONG CustomSize,
690                             PULONG ResultSize,
691                             PWCHAR UnicodeString,
692                             ULONG UnicodeSize)
693 {
694   ULONG Size = 0;
695   ULONG i;
696   WCHAR wc;
697
698   if (CustomCP->DBCSCodePage == 0)
699     {
700       /* single-byte code page */
701       if (UnicodeSize > (CustomSize * sizeof(WCHAR)))
702         Size = CustomSize;
703       else
704         Size = UnicodeSize / sizeof(WCHAR);
705
706       if (ResultSize != NULL)
707         *ResultSize = Size;
708
709       for (i = 0; i < Size; i++)
710         {
711           wc = RtlUpcaseUnicodeChar(*UnicodeString);
712           *CustomString = ((PCHAR)CustomCP->WideCharTable)[(unsigned int)wc];
713           CustomString++;
714           UnicodeString++;
715         }
716     }
717   else
718     {
719       /* multi-byte code page */
720       /* FIXME */
721     }
722
723   return(STATUS_SUCCESS);
724 }
725
726
727 /*
728  * @unimplemented
729  */
730 NTSTATUS STDCALL
731 RtlUpcaseUnicodeToMultiByteN(PCHAR MbString,
732                              ULONG MbSize,
733                              PULONG ResultSize,
734                              PWCHAR UnicodeString,
735                              ULONG UnicodeSize)
736 {
737   ULONG Size = 0;
738   ULONG i;
739   WCHAR wc;
740
741   if (NlsMbCodePageTag == FALSE)
742     {
743       /* single-byte code page */
744       if (UnicodeSize > (MbSize * sizeof(WCHAR)))
745         Size = MbSize;
746       else
747         Size = UnicodeSize / sizeof(WCHAR);
748
749       if (ResultSize != NULL)
750         *ResultSize = Size;
751
752       for (i = 0; i < Size; i++)
753         {
754           wc = RtlUpcaseUnicodeChar(*UnicodeString);
755           *MbString = NlsUnicodeToAnsiTable[(unsigned int)wc];
756           MbString++;
757           UnicodeString++;
758         }
759     }
760   else
761     {
762       /* multi-byte code page */
763       /* FIXME */
764     }
765
766   return(STATUS_SUCCESS);
767 }
768
769
770 /*
771  * @unimplemented
772  */
773 NTSTATUS STDCALL
774 RtlUpcaseUnicodeToOemN(PCHAR OemString,
775                        ULONG OemSize,
776                        PULONG ResultSize,
777                        PWCHAR UnicodeString,
778                        ULONG UnicodeSize)
779 {
780   ULONG Size = 0;
781   ULONG i;
782   UCHAR wc;
783
784   if (NlsMbOemCodePageTag == FALSE)
785     {
786       /* single-byte code page */
787       if (UnicodeSize > (OemSize * sizeof(WCHAR)))
788         Size = OemSize;
789       else
790         Size = UnicodeSize / sizeof(WCHAR);
791
792       if (ResultSize != NULL)
793         *ResultSize = Size;
794
795       for (i = 0; i < Size; i++)
796         {
797           wc = RtlUpcaseUnicodeChar(*UnicodeString);
798           *OemString = NlsUnicodeToOemTable[(unsigned int)wc];
799           OemString++;
800           UnicodeString++;
801         }
802     }
803   else
804     {
805       /* multi-byte code page */
806       /* FIXME */
807     }
808
809   return(STATUS_SUCCESS);
810 }
811
812
813 /*
814  * @unimplemented
815  */
816 CHAR STDCALL
817 RtlUpperChar (IN CHAR Source)
818 {
819   WCHAR Unicode;
820   CHAR Destination;
821
822   if (NlsMbCodePageTag == FALSE)
823     {
824       /* single-byte code page */
825
826       /* ansi->unicode */
827       Unicode = NlsAnsiToUnicodeTable[(unsigned int)Source];
828
829       /* upcase conversion */
830       Unicode = RtlUpcaseUnicodeChar (Unicode);
831
832       /* unicode -> ansi */
833       Destination = NlsUnicodeToAnsiTable[(unsigned int)Unicode];
834     }
835   else
836     {
837       /* multi-byte code page */
838       /* FIXME */
839       Destination = Source;
840     }
841
842   return Destination;
843 }
844
845 /* EOF */