7e95c73343eff24b1ce8121e0bc3ad98ba7694e5
[reactos.git] / lib / ntdll / rtl / nls.c
1 /* $Id$
2  *
3  * COPYRIGHT:       See COPYING in the top level directory
4  * PROJECT:         ReactOS kernel
5  * FILE:            lib/ntdll/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
17 #define NDEBUG
18 #include <debug.h>
19
20
21 /* GLOBALS *******************************************************************/
22
23 USHORT NlsAnsiCodePage = 0; /* exported */
24 BOOLEAN NlsMbCodePageTag = FALSE; /* exported */
25 PWCHAR NlsAnsiToUnicodeTable = NULL;
26 PCHAR NlsUnicodeToAnsiTable = NULL;
27 PUSHORT NlsLeadByteInfo = NULL;
28
29
30 USHORT NlsOemCodePage = 0;
31 BOOLEAN NlsMbOemCodePageTag = FALSE; /* exported */
32 PWCHAR NlsOemToUnicodeTable = NULL;
33 PCHAR NlsUnicodeToOemTable = NULL;
34 PUSHORT NlsOemLeadByteInfo = NULL;
35
36
37 PUSHORT NlsUnicodeUpcaseTable = NULL;
38 PUSHORT NlsUnicodeLowercaseTable = NULL;
39
40
41 /* FUNCTIONS *****************************************************************/
42
43 /*
44  * RtlConsoleMultiByteToUnicodeN@24
45  */
46
47
48 NTSTATUS STDCALL
49 RtlCustomCPToUnicodeN(IN PCPTABLEINFO CustomCP,
50                       PWCHAR UnicodeString,
51                       ULONG UnicodeSize,
52                       PULONG ResultSize,
53                       PCHAR CustomString,
54                       ULONG CustomSize)
55 {
56   ULONG Size = 0;
57   ULONG i;
58
59   if (CustomCP->DBCSCodePage == 0)
60     {
61       /* single-byte code page */
62       if (CustomSize > (UnicodeSize / sizeof(WCHAR)))
63         Size = UnicodeSize / sizeof(WCHAR);
64       else
65         Size = CustomSize;
66
67       if (ResultSize != NULL)
68         *ResultSize = Size * sizeof(WCHAR);
69
70       for (i = 0; i < Size; i++)
71         {
72           *UnicodeString = CustomCP->MultiByteTable[(int)*CustomString];
73           UnicodeString++;
74           CustomString++;
75         }
76     }
77   else
78     {
79       /* multi-byte code page */
80       /* FIXME */
81       assert(FALSE);
82     }
83
84   return STATUS_SUCCESS;
85 }
86
87
88 WCHAR
89 RtlDowncaseUnicodeChar (IN WCHAR Source)
90 {
91   USHORT Offset;
92
93   if (Source < L'A')
94     return Source;
95
96   if (Source <= L'Z')
97     return Source + (L'a' - L'A');
98
99   if (Source < 0x80)
100     return Source;
101
102   Offset = ((USHORT)Source >> 8);
103   DPRINT("Offset: %hx\n", Offset);
104
105   Offset = NlsUnicodeLowercaseTable[Offset];
106   DPRINT("Offset: %hx\n", Offset);
107
108   Offset += (((USHORT)Source & 0x00F0) >> 4);
109   DPRINT("Offset: %hx\n", Offset);
110
111   Offset = NlsUnicodeLowercaseTable[Offset];
112   DPRINT("Offset: %hx\n", Offset);
113
114   Offset += ((USHORT)Source & 0x000F);
115   DPRINT("Offset: %hx\n", Offset);
116
117   Offset = NlsUnicodeLowercaseTable[Offset];
118   DPRINT("Offset: %hx\n", Offset);
119
120   DPRINT("Result: %hx\n", Source + (SHORT)Offset);
121
122   return Source + (SHORT)Offset;
123 }
124
125
126 VOID STDCALL
127 RtlGetDefaultCodePage(OUT PUSHORT AnsiCodePage,
128                       OUT PUSHORT OemCodePage)
129 {
130   *AnsiCodePage = NlsAnsiCodePage;
131   *OemCodePage = NlsOemCodePage;
132 }
133
134
135 /*
136  * @implemented
137  */
138 VOID STDCALL
139 RtlInitCodePageTable(IN PUSHORT TableBase,
140                      OUT PCPTABLEINFO CodePageTable)
141 {
142   PNLS_FILE_HEADER NlsFileHeader;
143   PUSHORT Ptr;
144   USHORT Offset;
145
146   DPRINT("RtlInitCodePageTable() called\n");
147
148   NlsFileHeader = (PNLS_FILE_HEADER)TableBase;
149
150   CodePageTable->CodePage = NlsFileHeader->CodePage;
151   CodePageTable->MaximumCharacterSize = NlsFileHeader->MaximumCharacterSize;
152   CodePageTable->DefaultChar = NlsFileHeader->DefaultChar;
153   CodePageTable->UniDefaultChar = NlsFileHeader->UniDefaultChar;
154   CodePageTable->TransDefaultChar = NlsFileHeader->TransDefaultChar;
155   CodePageTable->TransUniDefaultChar = NlsFileHeader->TransUniDefaultChar;
156
157   RtlCopyMemory(&CodePageTable->LeadByte,
158                 &NlsFileHeader->LeadByte,
159                 MAXIMUM_LEADBYTES);
160
161   /* Set Pointer to start of multi byte table */
162   Ptr = (PUSHORT)((ULONG_PTR)TableBase + 2 * NlsFileHeader->HeaderSize);
163
164   /* Get offset to the wide char table */
165   Offset = (USHORT)(*Ptr++) + NlsFileHeader->HeaderSize + 1;
166
167   /* Set pointer to the multi byte table */
168   CodePageTable->MultiByteTable = Ptr;
169
170   /* Skip ANSI and OEM table */
171   Ptr += 256;
172   if (*Ptr++)
173     Ptr += 256;
174
175   /* Set pointer to DBCS ranges */
176   CodePageTable->DBCSRanges = (PUSHORT)Ptr;
177
178   if (*Ptr > 0)
179     {
180       CodePageTable->DBCSCodePage = 1;
181       CodePageTable->DBCSOffsets = (PUSHORT)++Ptr;
182     }
183   else
184     {
185       CodePageTable->DBCSCodePage = 0;
186       CodePageTable->DBCSOffsets = 0;
187     }
188
189   CodePageTable->WideCharTable = (PVOID)((ULONG_PTR)TableBase + 2 * Offset);
190 }
191
192
193 /*
194  * @implemented
195  */
196 VOID STDCALL
197 RtlInitNlsTables(IN PUSHORT AnsiTableBase,
198                  IN PUSHORT OemTableBase,
199                  IN PUSHORT CaseTableBase,
200                  OUT PNLSTABLEINFO NlsTable)
201 {
202   DPRINT("RtlInitNlsTables()called\n");
203
204   if (AnsiTableBase == NULL ||
205       OemTableBase == NULL ||
206       CaseTableBase == NULL)
207     return;
208
209   RtlInitCodePageTable (AnsiTableBase,
210                         &NlsTable->AnsiTableInfo);
211
212   RtlInitCodePageTable (OemTableBase,
213                         &NlsTable->OemTableInfo);
214
215   NlsTable->UpperCaseTable = (PUSHORT)CaseTableBase + 2;
216   NlsTable->LowerCaseTable = (PUSHORT)CaseTableBase + *((PUSHORT)CaseTableBase + 1) + 2;
217 }
218
219
220 /*
221  * @unimplemented
222  */
223 NTSTATUS STDCALL
224 RtlMultiByteToUnicodeN (IN OUT PWCHAR UnicodeString,
225                         IN ULONG UnicodeSize,
226                         OUT PULONG ResultSize,
227                         IN PCHAR MbString,
228                         IN ULONG MbSize)
229 {
230   ULONG Size = 0;
231   ULONG i;
232
233   if (NlsMbCodePageTag == FALSE)
234     {
235       /* single-byte code page */
236       if (MbSize > (UnicodeSize / sizeof(WCHAR)))
237         Size = UnicodeSize / sizeof(WCHAR);
238       else
239         Size = MbSize;
240
241       if (ResultSize != NULL)
242         *ResultSize = Size * sizeof(WCHAR);
243
244       for (i = 0; i < Size; i++)
245         {
246           *UnicodeString = NlsAnsiToUnicodeTable[*((unsigned char *) MbString)];
247           UnicodeString++;
248           MbString++;
249         }
250     }
251   else
252     {
253       /* multi-byte code page */
254       /* FIXME */
255       assert(FALSE);
256     }
257
258   return STATUS_SUCCESS;
259 }
260
261
262 /*
263  * @implemented
264  */
265 NTSTATUS STDCALL
266 RtlMultiByteToUnicodeSize (OUT PULONG UnicodeSize,
267                            IN PCHAR MbString,
268                            IN ULONG MbSize)
269 {
270   if (NlsMbCodePageTag == FALSE)
271     {
272       /* single-byte code page */
273       *UnicodeSize = MbSize * sizeof (WCHAR);
274     }
275   else
276     {
277       /* multi-byte code page */
278       /* FIXME */
279       assert(FALSE);
280     }
281
282   return STATUS_SUCCESS;
283 }
284
285
286 /*
287  * @unimplemented
288  */
289 NTSTATUS STDCALL
290 RtlOemToUnicodeN (PWCHAR UnicodeString,
291                   ULONG UnicodeSize,
292                   PULONG ResultSize,
293                   PCHAR OemString,
294                   ULONG OemSize)
295 {
296   ULONG Size = 0;
297   ULONG i;
298
299   if (NlsMbOemCodePageTag == FALSE)
300     {
301       /* single-byte code page */
302       if (OemSize > (UnicodeSize / sizeof(WCHAR)))
303         Size = UnicodeSize / sizeof(WCHAR);
304       else
305         Size = OemSize;
306
307       if (ResultSize != NULL)
308         *ResultSize = Size * sizeof(WCHAR);
309
310       for (i = 0; i < Size; i++)
311         {
312           *UnicodeString = NlsOemToUnicodeTable[(INT)*OemString];
313           UnicodeString++;
314           OemString++;
315         }
316     }
317   else
318     {
319       /* multi-byte code page */
320       /* FIXME */
321       assert(FALSE);
322     }
323
324   return STATUS_SUCCESS;
325 }
326
327
328 /*
329  * @implemented
330  */
331 VOID STDCALL
332 RtlResetRtlTranslations(IN PNLSTABLEINFO NlsTable)
333 {
334   DPRINT("RtlResetRtlTranslations() called\n");
335
336   /* Set ANSI data */
337   NlsAnsiToUnicodeTable = NlsTable->AnsiTableInfo.MultiByteTable;
338   NlsUnicodeToAnsiTable = NlsTable->AnsiTableInfo.WideCharTable;
339   NlsMbCodePageTag = (NlsTable->AnsiTableInfo.DBCSCodePage != 0);
340   NlsLeadByteInfo = NlsTable->AnsiTableInfo.DBCSOffsets;
341   NlsAnsiCodePage = NlsTable->AnsiTableInfo.CodePage;
342   DPRINT("Ansi codepage %hu\n", NlsAnsiCodePage);
343
344   /* Set OEM data */
345   NlsOemToUnicodeTable = NlsTable->OemTableInfo.MultiByteTable;
346   NlsUnicodeToOemTable = NlsTable->OemTableInfo.WideCharTable;
347   NlsMbOemCodePageTag = (NlsTable->OemTableInfo.DBCSCodePage != 0);
348   NlsOemLeadByteInfo = NlsTable->OemTableInfo.DBCSOffsets;
349   NlsOemCodePage = NlsTable->OemTableInfo.CodePage;
350   DPRINT("Oem codepage %hu\n", NlsOemCodePage);
351
352   /* Set Unicode case map data */
353   NlsUnicodeUpcaseTable = NlsTable->UpperCaseTable;
354   NlsUnicodeLowercaseTable = NlsTable->LowerCaseTable;
355 }
356
357
358 /*
359  * @unimplemented
360  */
361 NTSTATUS STDCALL
362 RtlUnicodeToCustomCPN(IN PCPTABLEINFO CustomCP,
363                       PCHAR CustomString,
364                       ULONG CustomSize,
365                       PULONG ResultSize,
366                       PWCHAR UnicodeString,
367                       ULONG UnicodeSize)
368 {
369   ULONG Size = 0;
370   ULONG i;
371
372   if (CustomCP->DBCSCodePage == 0)
373     {
374       /* single-byte code page */
375       if (UnicodeSize > (CustomSize * sizeof(WCHAR)))
376         Size = CustomSize;
377       else
378         Size = UnicodeSize / sizeof(WCHAR);
379
380       if (ResultSize != NULL)
381         *ResultSize = Size;
382
383       for (i = 0; i < Size; i++)
384         {
385           *CustomString = ((PCHAR)CustomCP->WideCharTable)[*UnicodeString];
386           CustomString++;
387           UnicodeString++;
388         }
389     }
390   else
391     {
392       /* multi-byte code page */
393       /* FIXME */
394       assert(FALSE);
395     }
396
397   return STATUS_SUCCESS;
398 }
399
400
401 /*
402  * @unimplemented
403  */
404 NTSTATUS STDCALL
405 RtlUnicodeToMultiByteN (PCHAR MbString,
406                         ULONG MbSize,
407                         PULONG ResultSize,
408                         PWCHAR UnicodeString,
409                         ULONG UnicodeSize)
410 {
411   ULONG Size = 0;
412   ULONG i;
413
414   if (NlsMbCodePageTag == FALSE)
415     {
416       /* single-byte code page */
417       if (UnicodeSize > (MbSize * sizeof(WCHAR)))
418         Size = MbSize;
419       else
420         Size = UnicodeSize / sizeof(WCHAR);
421
422       if (ResultSize != NULL)
423         *ResultSize = Size;
424
425       for (i = 0; i < Size; i++)
426         {
427           *MbString = NlsUnicodeToAnsiTable[*UnicodeString];
428           MbString++;
429           UnicodeString++;
430         }
431     }
432   else
433     {
434       /* multi-byte code page */
435       /* FIXME */
436       assert(FALSE);
437     }
438
439   return STATUS_SUCCESS;
440 }
441
442
443 /*
444  * @unimplemented
445  */
446 NTSTATUS STDCALL
447 RtlUnicodeToMultiByteSize (PULONG MbSize,
448                            PWCHAR UnicodeString,
449                            ULONG UnicodeSize)
450 {
451   if (NlsMbCodePageTag == FALSE)
452     {
453       /* single-byte code page */
454       *MbSize = UnicodeSize / sizeof (WCHAR);
455     }
456   else
457     {
458       /* multi-byte code page */
459       /* FIXME */
460       *MbSize = 0;
461       assert(FALSE);
462     }
463
464   return STATUS_SUCCESS;
465 }
466
467
468 /*
469  * @unimplemented
470  */
471 NTSTATUS STDCALL
472 RtlUnicodeToOemN (PCHAR OemString,
473                   ULONG OemSize,
474                   PULONG ResultSize,
475                   PWCHAR UnicodeString,
476                   ULONG UnicodeSize)
477 {
478   ULONG Size = 0;
479   ULONG i;
480
481   if (NlsMbOemCodePageTag == FALSE)
482     {
483       /* single-byte code page */
484       if (UnicodeSize > (OemSize * sizeof(WCHAR)))
485         Size = OemSize;
486       else
487         Size = UnicodeSize / sizeof(WCHAR);
488
489       if (ResultSize != NULL)
490         *ResultSize = Size;
491
492       for (i = 0; i < Size; i++)
493         {
494           *OemString = NlsUnicodeToOemTable[*UnicodeString];
495           OemString++;
496           UnicodeString++;
497         }
498     }
499   else
500     {
501       /* multi-byte code page */
502       /* FIXME */
503       assert(FALSE);
504     }
505
506   return STATUS_SUCCESS;
507 }
508
509
510 /*
511  * @implemented
512  */
513 WCHAR STDCALL
514 RtlUpcaseUnicodeChar(IN WCHAR Source)
515 {
516   USHORT Offset;
517
518   if (Source < L'a')
519     return Source;
520
521   if (Source <= L'z')
522     return (Source - (L'a' - L'A'));
523
524   Offset = ((USHORT)Source >> 8);
525   Offset = NlsUnicodeUpcaseTable[Offset];
526
527   Offset += (((USHORT)Source & 0x00F0) >> 4);
528   Offset = NlsUnicodeUpcaseTable[Offset];
529
530   Offset += ((USHORT)Source & 0x000F);
531   Offset = NlsUnicodeUpcaseTable[Offset];
532
533   return Source + (SHORT)Offset;
534 }
535
536
537 /*
538  * @unimplemented
539  */
540 NTSTATUS STDCALL
541 RtlUpcaseUnicodeToCustomCPN (IN PCPTABLEINFO CustomCP,
542                              PCHAR CustomString,
543                              ULONG CustomSize,
544                              PULONG ResultSize,
545                              PWCHAR UnicodeString,
546                              ULONG UnicodeSize)
547 {
548   WCHAR UpcaseChar;
549   ULONG Size = 0;
550   ULONG i;
551
552   if (CustomCP->DBCSCodePage == 0)
553     {
554       /* single-byte code page */
555       if (UnicodeSize > (CustomSize * sizeof(WCHAR)))
556         Size = CustomSize;
557       else
558         Size = UnicodeSize / sizeof(WCHAR);
559
560       if (ResultSize != NULL)
561         *ResultSize = Size;
562
563       for (i = 0; i < Size; i++)
564         {
565           UpcaseChar = RtlUpcaseUnicodeChar(*UnicodeString);
566           *CustomString = ((PCHAR)CustomCP->WideCharTable)[UpcaseChar];
567           CustomString++;
568           UnicodeString++;
569         }
570     }
571   else
572     {
573       /* multi-byte code page */
574       /* FIXME */
575       assert(FALSE);
576     }
577
578   return STATUS_SUCCESS;
579 }
580
581
582 /*
583  * @unimplemented
584  */
585 NTSTATUS STDCALL
586 RtlUpcaseUnicodeToMultiByteN (PCHAR MbString,
587                               ULONG MbSize,
588                               PULONG ResultSize,
589                               PWCHAR UnicodeString,
590                               ULONG UnicodeSize)
591 {
592   WCHAR UpcaseChar;
593   ULONG Size = 0;
594   ULONG i;
595
596   if (NlsMbCodePageTag == FALSE)
597     {
598       /* single-byte code page */
599       if (UnicodeSize > (MbSize * sizeof(WCHAR)))
600         Size = MbSize;
601       else
602         Size = UnicodeSize / sizeof(WCHAR);
603
604       if (ResultSize != NULL)
605         *ResultSize = Size;
606
607       for (i = 0; i < Size; i++)
608         {
609           UpcaseChar = RtlUpcaseUnicodeChar(*UnicodeString);
610           *MbString = NlsUnicodeToAnsiTable[UpcaseChar];
611           MbString++;
612           UnicodeString++;
613         }
614     }
615   else
616     {
617       /* multi-byte code page */
618       /* FIXME */
619       assert(FALSE);
620     }
621
622   return STATUS_SUCCESS;
623 }
624
625
626 /*
627  * @unimplemented
628  */
629 NTSTATUS STDCALL
630 RtlUpcaseUnicodeToOemN (PCHAR OemString,
631                         ULONG OemSize,
632                         PULONG ResultSize,
633                         PWCHAR UnicodeString,
634                         ULONG UnicodeSize)
635 {
636   WCHAR UpcaseChar;
637   ULONG Size = 0;
638   ULONG i;
639
640   if (NlsMbOemCodePageTag == FALSE)
641     {
642       /* single-byte code page */
643       if (UnicodeSize > (OemSize * sizeof(WCHAR)))
644         Size = OemSize;
645       else
646         Size = UnicodeSize / sizeof(WCHAR);
647
648       if (ResultSize != NULL)
649         *ResultSize = Size;
650
651       for (i = 0; i < Size; i++)
652         {
653           UpcaseChar = RtlUpcaseUnicodeChar(*UnicodeString);
654           *OemString = NlsUnicodeToOemTable[UpcaseChar];
655           OemString++;
656           UnicodeString++;
657         }
658     }
659   else
660     {
661       /* multi-byte code page */
662       /* FIXME */
663       assert(FALSE);
664     }
665
666   return STATUS_SUCCESS;
667 }
668
669
670 /*
671  * @unimplemented
672  */
673 CHAR STDCALL
674 RtlUpperChar (IN CHAR Source)
675 {
676   WCHAR Unicode;
677   CHAR Destination;
678
679   if (NlsMbCodePageTag == FALSE)
680     {
681       /* single-byte code page */
682
683       /* ansi->unicode */
684       Unicode = NlsAnsiToUnicodeTable[(INT)Source];
685
686       /* upcase conversion */
687       Unicode = RtlUpcaseUnicodeChar (Unicode);
688
689       /* unicode -> ansi */
690       Destination = NlsUnicodeToAnsiTable[Unicode];
691     }
692   else
693     {
694       /* single-byte code page */
695       /* FIXME: implement the multi-byte stuff!! */
696       Destination = Source;
697     }
698
699   return Destination;
700 }
701
702 /* EOF */