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