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