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