RtlUpcaseUnicodeString(): Allow also non-zero-terminable 'DestinationString'
[reactos.git] / ntoskrnl / rtl / unicode.c
1 /* $Id$
2  *
3  * COPYRIGHT:       See COPYING in the top level directory
4  * PROJECT:         ReactOS kernel
5  * FILE:            ntoskrnl/rtl/unicode.c
6  * PURPOSE:         String functions
7  * PROGRAMMER:      Jason Filby (jasonfilby@yahoo.com)
8  * UPDATE HISTORY:
9  *                  Created 10/08/98
10  */
11
12 #include <ddk/ntddk.h>
13 //#include <internal/nls.h>
14 #include <msvcrt/ctype.h>       /* <ctype.h> does not need to define isw*() */
15 #include <ntos/minmax.h>
16 #include <internal/pool.h>
17
18 #define NDEBUG
19 #include <internal/debug.h>
20
21 /* GLOBALS *******************************************************************/
22
23 #define TAG_USTR  TAG('U', 'S', 'T', 'R')
24 #define TAG_ASTR  TAG('A', 'S', 'T', 'R')
25 #define TAG_OSTR  TAG('O', 'S', 'T', 'R')
26
27 /* FUNCTIONS *****************************************************************/
28
29 WCHAR STDCALL
30 RtlAnsiCharToUnicodeChar(IN CHAR AnsiChar)
31 {
32   ULONG Size;
33   WCHAR UnicodeChar;
34
35   Size = 1;
36 #if 0
37   Size = (NlsLeadByteInfo[AnsiChar] == 0) ? 1 : 2;
38 #endif
39
40   RtlMultiByteToUnicodeN(&UnicodeChar,
41                          sizeof(WCHAR),
42                          NULL,
43                          &AnsiChar,
44                          Size);
45
46   return(UnicodeChar);
47 }
48
49
50 ULONG STDCALL
51 RtlAnsiStringToUnicodeSize(IN PANSI_STRING AnsiString)
52 {
53   ULONG Size;
54
55   RtlMultiByteToUnicodeSize(&Size,
56                             AnsiString->Buffer,
57                             AnsiString->Length);
58
59   return(Size);
60 }
61
62
63 NTSTATUS STDCALL
64 RtlAnsiStringToUnicodeString(IN OUT PUNICODE_STRING DestinationString,
65                              IN PANSI_STRING SourceString,
66                              IN BOOLEAN AllocateDestinationString)
67 {
68         NTSTATUS Status;
69         ULONG Length;
70
71         if (NlsMbCodePageTag == TRUE)
72                 Length = RtlAnsiStringToUnicodeSize (SourceString);
73         else
74                 Length = SourceString->Length * sizeof(WCHAR);
75
76         if (Length > 65535)
77                 return STATUS_INVALID_PARAMETER_2;
78
79         if (AllocateDestinationString == TRUE)
80         {
81                 DestinationString->MaximumLength = Length + sizeof(WCHAR);
82                 DestinationString->Buffer =
83                   ExAllocatePoolWithTag (NonPagedPool,
84                                          DestinationString->MaximumLength,
85                                          TAG_USTR);
86                 if (DestinationString->Buffer == NULL)
87                         return STATUS_NO_MEMORY;
88         }
89         else
90         {
91                 if (Length + sizeof(WCHAR) > DestinationString->MaximumLength)
92                 {
93                         DPRINT("STATUS_BUFFER_TOO_SMALL\n");
94                         return STATUS_BUFFER_TOO_SMALL;
95                 }
96         }
97         DestinationString->Length = Length;
98
99         RtlZeroMemory (DestinationString->Buffer,
100                        DestinationString->Length);
101
102         Status = RtlMultiByteToUnicodeN (DestinationString->Buffer,
103                                          DestinationString->Length,
104                                          NULL,
105                                          SourceString->Buffer,
106                                          SourceString->Length);
107         if (!NT_SUCCESS(Status))
108         {
109                 if (AllocateDestinationString)
110                         ExFreePool (DestinationString->Buffer);
111                 return Status;
112         }
113
114         DestinationString->Buffer[Length / sizeof(WCHAR)] = 0;
115
116         return STATUS_SUCCESS;
117 }
118
119
120 NTSTATUS STDCALL
121 RtlAppendAsciizToString(IN OUT PSTRING Destination,
122                         IN PCSZ Source)
123 {
124         ULONG Length;
125         PCHAR Ptr;
126
127         if (Source == NULL)
128                 return STATUS_SUCCESS;
129
130         Length = strlen (Source);
131         if (Destination->Length + Length >= Destination->MaximumLength)
132                 return STATUS_BUFFER_TOO_SMALL;
133
134         Ptr = Destination->Buffer + Destination->Length;
135         memmove (Ptr,
136                  Source,
137                  Length);
138         Ptr += Length;
139         *Ptr = 0;
140
141         Destination->Length += Length;
142
143         return STATUS_SUCCESS;
144 }
145
146
147 NTSTATUS STDCALL
148 RtlAppendStringToString(IN OUT PSTRING Destination,
149                         IN PSTRING Source)
150 {
151   PCHAR Ptr;
152
153   if (Source->Length == 0)
154     return(STATUS_SUCCESS);
155
156   if (Destination->Length + Source->Length >= Destination->MaximumLength)
157     return(STATUS_BUFFER_TOO_SMALL);
158
159   Ptr = Destination->Buffer + Destination->Length;
160   memmove(Ptr,
161           Source->Buffer,
162           Source->Length);
163   Ptr += Source->Length;
164   *Ptr = 0;
165
166   Destination->Length += Source->Length;
167
168   return(STATUS_SUCCESS);
169 }
170
171
172 NTSTATUS STDCALL
173 RtlAppendUnicodeStringToString(IN OUT PUNICODE_STRING Destination,
174                                IN PUNICODE_STRING Source)
175 {
176         PWCHAR Src, Dest;
177         ULONG i;
178
179         if ((Source->Length + Destination->Length) >= Destination->MaximumLength)
180                 return STATUS_BUFFER_TOO_SMALL;
181
182         Src  = Source->Buffer;
183         Dest = Destination->Buffer + (Destination->Length / sizeof (WCHAR));
184         for (i = 0; i < (Source->Length / sizeof(WCHAR)); i++)
185         {
186                 *Dest = *Src;
187                 Dest++;
188                 Src++;
189         }
190         *Dest = 0;
191
192         Destination->Length += Source->Length;
193
194         return STATUS_SUCCESS;
195 }
196
197
198 NTSTATUS STDCALL
199 RtlAppendUnicodeToString(IN OUT PUNICODE_STRING Destination,
200                          IN PWSTR Source)
201 {
202   PWCHAR Src;
203   PWCHAR Dest;
204   ULONG  i;
205   ULONG  slen;
206
207   slen = wcslen(Source) * sizeof(WCHAR);
208
209   if (Destination->Length + slen >= Destination->MaximumLength)
210     return(STATUS_BUFFER_TOO_SMALL);
211
212   Src = Source;
213   Dest = Destination->Buffer + (Destination->Length / sizeof(WCHAR));
214
215   for (i = 0; i < (slen / sizeof(WCHAR)); i++)
216     {
217       *Dest = *Src;
218       Dest++;
219       Src++;
220     }
221   *Dest = 0;
222
223   Destination->Length += slen;
224
225   return(STATUS_SUCCESS);
226 }
227
228
229 NTSTATUS STDCALL
230 RtlCharToInteger(IN PCSZ String,
231                  IN ULONG Base,
232                  IN OUT PULONG Value)
233 {
234   ULONG Val;
235
236   *Value = 0;
237
238   if (Base == 0)
239     {
240       Base = 10;
241       if (*String == '0')
242         {
243           Base = 8;
244           String++;
245           if ((*String == 'x') && isxdigit (String[1]))
246             {
247               String++;
248               Base = 16;
249             }
250         }
251     }
252
253   if (!isxdigit (*String))
254     return(STATUS_INVALID_PARAMETER);
255
256   while (isxdigit (*String) &&
257          (Val = isdigit (*String) ? * String - '0' : (islower (*String)
258           ? toupper (*String) : *String) - 'A' + 10) < Base)
259     {
260       *Value = *Value * Base + Val;
261       String++;
262     }
263
264   return(STATUS_SUCCESS);
265 }
266
267
268 LONG STDCALL
269 RtlCompareString(IN PSTRING String1,
270                  IN PSTRING String2,
271                  IN BOOLEAN CaseInsensitive)
272 {
273         ULONG len1, len2;
274         PCHAR s1, s2;
275         CHAR  c1, c2;
276
277         if (String1 && String2)
278         {
279                 len1 = String1->Length;
280                 len2 = String2->Length;
281                 s1 = String1->Buffer;
282                 s2 = String2->Buffer;
283
284                 if (s1 && s2)
285                 {
286                         if (CaseInsensitive)
287                         {
288                                 while (1)
289                                 {
290                                         c1 = len1-- ? RtlUpperChar (*s1++) : 0;
291                                         c2 = len2-- ? RtlUpperChar (*s2++) : 0;
292                                         if (!c1 || !c2 || c1 != c2)
293                                                 return c1 - c2;
294                                 }
295                         }
296                         else
297                         {
298                                 while (1)
299                                 {
300                                         c1 = len1-- ? *s1++ : 0;
301                                         c2 = len2-- ? *s2++ : 0;
302                                         if (!c1 || !c2 || c1 != c2)
303                                                 return c1 - c2;
304                                 }
305                         }
306                 }
307         }
308
309         return 0;
310 }
311
312
313 LONG STDCALL
314 RtlCompareUnicodeString(IN PUNICODE_STRING String1,
315                         IN PUNICODE_STRING String2,
316                         IN BOOLEAN CaseInsensitive)
317 {
318         ULONG len1, len2;
319         PWCHAR s1, s2;
320         WCHAR  c1, c2;
321
322         if (String1 && String2)
323         {
324                 len1 = String1->Length / sizeof(WCHAR);
325                 len2 = String2->Length / sizeof(WCHAR);
326                 s1 = String1->Buffer;
327                 s2 = String2->Buffer;
328
329                 if (s1 && s2)
330                 {
331                         if (CaseInsensitive)
332                         {
333                                 while (1)
334                                 {
335                                         c1 = len1-- ? RtlUpcaseUnicodeChar (*s1++) : 0;
336                                         c2 = len2-- ? RtlUpcaseUnicodeChar (*s2++) : 0;
337                                         if (!c1 || !c2 || c1 != c2)
338                                                 return c1 - c2;
339                                 }
340                         }
341                         else
342                         {
343                                 while (1)
344                                 {
345                                         c1 = len1-- ? *s1++ : 0;
346                                         c2 = len2-- ? *s2++ : 0;
347                                         if (!c1 || !c2 || c1 != c2)
348                                                 return c1 - c2;
349                                 }
350                         }
351                 }
352         }
353
354         return 0;
355 }
356
357
358 VOID STDCALL
359 RtlCopyString(IN OUT PSTRING DestinationString,
360               IN PSTRING SourceString)
361 {
362         ULONG copylen, i;
363         PCHAR Src, Dest;
364
365         if(SourceString == NULL)
366         {
367                 DestinationString->Length = 0;
368                 return;
369         }
370
371         copylen = min (DestinationString->MaximumLength - sizeof(CHAR),
372                        SourceString->Length);
373         Src = SourceString->Buffer;
374         Dest = DestinationString->Buffer;
375
376         for (i = 0; i < copylen; i++)
377         {
378                 *Dest = *Src;
379                 Dest++;
380                 Src++;
381         }
382         *Dest = 0;
383
384         DestinationString->Length = copylen;
385 }
386
387
388 VOID STDCALL
389 RtlCopyUnicodeString(IN OUT PUNICODE_STRING DestinationString,
390                      IN PUNICODE_STRING SourceString)
391 {
392         ULONG copylen, i;
393         PWCHAR Src, Dest;
394
395         if(SourceString==NULL)
396         {
397                 DestinationString->Length=0;
398                 return;
399         }
400
401         copylen = min(DestinationString->MaximumLength - sizeof(WCHAR),
402                       SourceString->Length);
403         Src = SourceString->Buffer;
404         Dest = DestinationString->Buffer;
405
406         for (i = 0; i < (copylen / sizeof (WCHAR)); i++)
407         {
408                 *Dest = *Src;
409                 Dest++;
410                 Src++;
411         }
412         *Dest = 0;
413
414         DestinationString->Length = copylen;
415 }
416
417
418 BOOLEAN STDCALL
419 RtlCreateUnicodeString(IN OUT PUNICODE_STRING Destination,
420                        IN PWSTR Source)
421 {
422         ULONG Length;
423
424         Length = (wcslen (Source) + 1) * sizeof(WCHAR);
425
426         Destination->Buffer = ExAllocatePoolWithTag (NonPagedPool,
427                                                      Length,
428                                                      TAG_USTR);
429         if (Destination->Buffer == NULL)
430                 return FALSE;
431
432         memmove (Destination->Buffer,
433                  Source,
434                  Length);
435
436         Destination->MaximumLength = Length;
437         Destination->Length = Length - sizeof (WCHAR);
438
439         return TRUE;
440 }
441
442
443 BOOLEAN STDCALL
444 RtlCreateUnicodeStringFromAsciiz(IN OUT PUNICODE_STRING Destination,
445                                  IN PCSZ Source)
446 {
447   ANSI_STRING AnsiString;
448   NTSTATUS Status;
449
450   RtlInitAnsiString(&AnsiString,
451                     Source);
452
453   Status = RtlAnsiStringToUnicodeString(Destination,
454                                         &AnsiString,
455                                         TRUE);
456
457   return(NT_SUCCESS(Status));
458 }
459
460
461 NTSTATUS STDCALL
462 RtlDowncaseUnicodeString(IN OUT PUNICODE_STRING DestinationString,
463                          IN PUNICODE_STRING SourceString,
464                          IN BOOLEAN AllocateDestinationString)
465 {
466   ULONG i;
467   PWCHAR Src, Dest;
468   
469   if (AllocateDestinationString == TRUE)
470     {
471       DestinationString->MaximumLength = SourceString->Length + sizeof(WCHAR);
472       DestinationString->Buffer = 
473         ExAllocatePoolWithTag (NonPagedPool,
474                                SourceString->Length + sizeof(WCHAR),
475                                TAG_USTR);
476       if (DestinationString->Buffer == NULL)
477         return STATUS_NO_MEMORY;
478     }
479   else
480     {
481       if (SourceString->Length >= DestinationString->MaximumLength)
482         return STATUS_BUFFER_TOO_SMALL;
483     }
484   DestinationString->Length = SourceString->Length;
485   
486   Src = SourceString->Buffer;
487   Dest = DestinationString->Buffer;
488   for (i=0; i < SourceString->Length / sizeof(WCHAR); i++)
489     {
490       if (*Src < L'A')
491         {
492           *Dest = *Src;
493         }
494       else if (*Src <= L'Z')
495         {
496           *Dest = (*Src + (L'a' - L'A'));
497         }
498       else
499         {
500           /* FIXME: characters above 'Z' */
501           *Dest = *Src;
502         }
503       
504       Dest++;
505       Src++;
506     }
507   *Dest = 0;
508   
509   return STATUS_SUCCESS;
510 }
511
512
513 BOOLEAN STDCALL
514 RtlEqualString(IN PSTRING String1,
515                IN PSTRING String2,
516                IN BOOLEAN CaseInsensitive)
517 {
518         unsigned long s1l=String1->Length;
519         unsigned long s2l=String2->Length;
520         unsigned long i;
521         char c1, c2;
522
523         if (s1l != s2l)
524                 return FALSE;
525
526         for (i = 0; i < s1l; i++)
527         {
528                 c1 = *String1->Buffer;
529                 c2 = *String2->Buffer;
530
531                 if (CaseInsensitive == TRUE)
532                 {
533                         c1 = RtlUpperChar (c1);
534                         c2 = RtlUpperChar (c2);
535                 }
536
537                 if (c1 != c2)
538                 {
539                         String1->Buffer -= i;
540                         String2->Buffer -= i;
541                         return FALSE;
542                 }
543
544                 String1->Buffer++;
545                 String2->Buffer++;
546         }
547
548         String1->Buffer -= i;
549         String2->Buffer -= i;
550
551         return TRUE;
552 }
553
554
555 BOOLEAN STDCALL
556 RtlEqualUnicodeString(IN PUNICODE_STRING String1,
557                       IN PUNICODE_STRING String2,
558                       IN BOOLEAN CaseInsensitive)
559 {
560         unsigned long s1l = String1->Length / sizeof(WCHAR);
561         unsigned long s2l = String2->Length / sizeof(WCHAR);
562         unsigned long i;
563         WCHAR wc1, wc2;
564         PWCHAR pw1, pw2;
565
566         if (s1l != s2l)
567                 return FALSE;
568
569         pw1 = String1->Buffer;
570         pw2 = String2->Buffer;
571
572         for (i = 0; i < s1l; i++)
573         {
574                 if(CaseInsensitive == TRUE)
575                 {
576                         wc1 = RtlUpcaseUnicodeChar (*pw1);
577                         wc2 = RtlUpcaseUnicodeChar (*pw2);
578                 }
579                 else
580                 {
581                         wc1 = *pw1;
582                         wc2 = *pw2;
583                 }
584
585                 if (wc1 != wc2)
586                         return FALSE;
587
588                 pw1++;
589                 pw2++;
590         }
591
592         return TRUE;
593 }
594
595
596 VOID STDCALL
597 RtlFreeAnsiString(IN PANSI_STRING AnsiString)
598 {
599         if (AnsiString->Buffer == NULL)
600                 return;
601
602         ExFreePool (AnsiString->Buffer);
603
604         AnsiString->Buffer = NULL;
605         AnsiString->Length = 0;
606         AnsiString->MaximumLength = 0;
607 }
608
609
610 VOID STDCALL
611 RtlFreeOemString(IN POEM_STRING OemString)
612 {
613         if (OemString->Buffer == NULL)
614                 return;
615
616         ExFreePool (OemString->Buffer);
617
618         OemString->Buffer = NULL;
619         OemString->Length = 0;
620         OemString->MaximumLength = 0;
621 }
622
623
624 VOID STDCALL
625 RtlFreeUnicodeString(IN PUNICODE_STRING UnicodeString)
626 {
627         if (UnicodeString->Buffer == NULL)
628                 return;
629
630         ExFreePool (UnicodeString->Buffer);
631
632         UnicodeString->Buffer = NULL;
633         UnicodeString->Length = 0;
634         UnicodeString->MaximumLength = 0;
635 }
636
637
638 VOID STDCALL
639 RtlInitAnsiString(IN OUT PANSI_STRING DestinationString,
640                   IN PCSZ SourceString)
641 {
642         ULONG DestSize;
643
644         if (SourceString == NULL)
645         {
646                 DestinationString->Length = 0;
647                 DestinationString->MaximumLength = 0;
648         }
649         else
650         {
651                 DestSize = strlen ((const char *)SourceString);
652                 DestinationString->Length = DestSize;
653                 DestinationString->MaximumLength = DestSize + sizeof(CHAR);
654         }
655         DestinationString->Buffer = (PCHAR)SourceString;
656 }
657
658
659 VOID STDCALL
660 RtlInitString(IN OUT PSTRING DestinationString,
661               IN PCSZ SourceString)
662 {
663         ULONG DestSize;
664
665         if (SourceString == NULL)
666         {
667                 DestinationString->Length = 0;
668                 DestinationString->MaximumLength = 0;
669         }
670         else
671         {
672                 DestSize = strlen((const char *)SourceString);
673                 DestinationString->Length = DestSize;
674                 DestinationString->MaximumLength = DestSize + sizeof(CHAR);
675         }
676         DestinationString->Buffer = (PCHAR)SourceString;
677 }
678
679
680 VOID STDCALL
681 RtlInitUnicodeString(IN OUT PUNICODE_STRING DestinationString,
682                      IN PCWSTR SourceString)
683 {
684         ULONG DestSize;
685
686         DPRINT("RtlInitUnicodeString(DestinationString %x, SourceString %x)\n",
687                DestinationString,
688                SourceString);
689
690         if (SourceString == NULL)
691         {
692                 DestinationString->Length = 0;
693                 DestinationString->MaximumLength = 0;
694         }
695         else
696         {
697                 DestSize = wcslen((PWSTR)SourceString) * sizeof(WCHAR);
698                 DestinationString->Length = DestSize;
699                 DestinationString->MaximumLength = DestSize + sizeof(WCHAR);
700         }
701         DestinationString->Buffer = (PWSTR)SourceString;
702 }
703
704
705 NTSTATUS STDCALL
706 RtlIntegerToChar(IN ULONG Value,
707                  IN ULONG Base,
708                  IN ULONG Length,
709                  IN OUT PCHAR String)
710 {
711         ULONG Radix;
712         CHAR  temp[33];
713         ULONG v = 0;
714         ULONG i;
715         PCHAR tp;
716         PCHAR sp;
717
718         Radix = Base;
719         if (Radix == 0)
720                 Radix = 10;
721
722         if ((Radix != 2) && (Radix != 8) &&
723             (Radix != 10) && (Radix != 16))
724                 return STATUS_INVALID_PARAMETER;
725
726         tp = temp;
727         while (v || tp == temp)
728         {
729                 i = v % Radix;
730                 v = v / Radix;
731                 if (i < 10)
732                         *tp = i + '0';
733                 else
734                         *tp = i + 'a' - 10;
735                 tp++;
736         }
737
738         if ((ULONG)(tp - temp) >= Length)
739                 return STATUS_BUFFER_TOO_SMALL;
740
741         sp = String;
742         while (tp > temp)
743                 *sp++ = *--tp;
744         *sp = 0;
745
746         return STATUS_SUCCESS;
747 }
748
749
750 NTSTATUS STDCALL
751 RtlIntegerToUnicodeString(IN ULONG Value,
752                           IN ULONG Base,        /* optional */
753                           IN OUT PUNICODE_STRING String)
754 {
755         ANSI_STRING AnsiString;
756         CHAR Buffer[33];
757         NTSTATUS Status;
758
759         Status = RtlIntegerToChar (Value,
760                                    Base,
761                                    33,
762                                    Buffer);
763         if (!NT_SUCCESS(Status))
764                 return Status;
765
766         AnsiString.Buffer = Buffer;
767         AnsiString.Length = strlen (Buffer);
768         AnsiString.MaximumLength = 33;
769
770         Status = RtlAnsiStringToUnicodeString (String,
771                                                &AnsiString,
772                                                FALSE);
773
774         return Status;
775 }
776
777
778 NTSTATUS STDCALL
779 RtlOemStringToCountedUnicodeString(IN OUT PUNICODE_STRING DestinationString,
780                                    IN POEM_STRING SourceString,
781                                    IN BOOLEAN AllocateDestinationString)
782 {
783   NTSTATUS Status;
784   ULONG Length;
785   
786   if (NlsMbCodePageTag == TRUE)
787     Length = RtlAnsiStringToUnicodeSize (SourceString);
788   else
789     Length = SourceString->Length * sizeof(WCHAR);
790   
791   if (Length > 65535)
792     return STATUS_INVALID_PARAMETER_2;
793   
794   if (AllocateDestinationString == TRUE)
795     {
796       DestinationString->MaximumLength = Length + sizeof(WCHAR);
797       DestinationString->Buffer =
798         ExAllocatePoolWithTag (NonPagedPool,
799                                DestinationString->MaximumLength,
800                                TAG_USTR);
801       if (DestinationString->Buffer == NULL)
802         return STATUS_NO_MEMORY;
803     }
804   else
805     {
806       if (Length > DestinationString->MaximumLength)
807         return STATUS_BUFFER_TOO_SMALL;
808     }
809   DestinationString->Length = Length;
810   
811   RtlZeroMemory (DestinationString->Buffer,
812                  DestinationString->Length);
813   
814   Status = RtlOemToUnicodeN (DestinationString->Buffer,
815                              DestinationString->Length,
816                              NULL,
817                              SourceString->Buffer,
818                              SourceString->Length);
819   if (!NT_SUCCESS(Status))
820     {
821       if (AllocateDestinationString)
822         ExFreePool (DestinationString->Buffer);
823       
824       return Status;
825     }
826
827   DestinationString->Buffer[Length / sizeof(WCHAR)] = 0;
828   
829   return STATUS_SUCCESS;
830 }
831
832
833 ULONG STDCALL
834 RtlOemStringToUnicodeSize(IN POEM_STRING OemString)
835 {
836   ULONG Size;
837
838   RtlMultiByteToUnicodeSize(&Size,
839                             OemString->Buffer,
840                             OemString->Length);
841
842   return(Size);
843 }
844
845
846 NTSTATUS STDCALL
847 RtlOemStringToUnicodeString(IN OUT PUNICODE_STRING DestinationString,
848                             IN POEM_STRING SourceString,
849                             IN BOOLEAN AllocateDestinationString)
850 {
851   NTSTATUS Status;
852   ULONG Length;
853   
854   if (NlsMbCodePageTag == TRUE)
855     Length = RtlAnsiStringToUnicodeSize (SourceString);
856   else
857     Length = SourceString->Length * sizeof(WCHAR);
858   
859   if (Length > 65535)
860     return STATUS_INVALID_PARAMETER_2;
861   
862   if (AllocateDestinationString == TRUE)
863     {
864       DestinationString->MaximumLength = Length + sizeof(WCHAR);
865       DestinationString->Buffer =
866         ExAllocatePoolWithTag (NonPagedPool,
867                                DestinationString->MaximumLength,
868                                TAG_USTR);
869       if (DestinationString->Buffer == NULL)
870         return STATUS_NO_MEMORY;
871     }
872   else
873     {
874       if (Length + sizeof(WCHAR) > DestinationString->MaximumLength)
875       {
876         DPRINT("STATUS_BUFFER_TOO_SMALL\n");
877         return STATUS_BUFFER_TOO_SMALL;
878       }
879     }
880   DestinationString->Length = Length;
881   
882   RtlZeroMemory (DestinationString->Buffer,
883                  DestinationString->Length);
884   
885   Status = RtlOemToUnicodeN (DestinationString->Buffer,
886                              DestinationString->Length,
887                              NULL,
888                              SourceString->Buffer,
889                                    SourceString->Length);
890   if (!NT_SUCCESS(Status))
891     {
892       if (AllocateDestinationString)
893         ExFreePool (DestinationString->Buffer);
894       return Status;
895     }
896
897   DestinationString->Buffer[Length / sizeof(WCHAR)] = 0;
898   
899   return STATUS_SUCCESS;
900 }
901
902
903 BOOLEAN STDCALL
904 RtlPrefixString(IN PANSI_STRING String1,
905                 IN PANSI_STRING String2,
906                 IN BOOLEAN CaseInsensitive)
907 {
908         PCHAR pc1;
909         PCHAR pc2;
910         ULONG Length;
911
912         if (String2->Length < String1->Length)
913                 return FALSE;
914
915         Length = String1->Length;
916         pc1 = String1->Buffer;
917         pc2 = String2->Buffer;
918
919         if (pc1 && pc2)
920         {
921                 if (CaseInsensitive)
922                 {
923                         while (Length--)
924                         {
925                                 if (RtlUpperChar (*pc1++) != RtlUpperChar (*pc2++))
926                                         return FALSE;
927                         }
928                 }
929                 else
930                 {
931                         while (Length--)
932                         {
933                                 if (*pc1++ != *pc2++)
934                                         return FALSE;
935                         }
936                 }
937                 return TRUE;
938         }
939         return FALSE;
940 }
941
942
943 BOOLEAN STDCALL
944 RtlPrefixUnicodeString(IN PUNICODE_STRING String1,
945                        IN PUNICODE_STRING String2,
946                        IN BOOLEAN CaseInsensitive)
947 {
948         PWCHAR pc1;
949         PWCHAR pc2;
950         ULONG Length;
951
952         if (String2->Length < String1->Length)
953                 return FALSE;
954
955         Length = String1->Length / 2;
956         pc1 = String1->Buffer;
957         pc2  = String2->Buffer;
958
959         if (pc1 && pc2)
960         {
961                 if (CaseInsensitive)
962                 {
963                         while (Length--)
964                         {
965                                 if (RtlUpcaseUnicodeChar (*pc1++)
966                                     != RtlUpcaseUnicodeChar (*pc2++))
967                                         return FALSE;
968                         }
969                 }
970                 else
971                 {
972                         while (Length--)
973                         {
974                                 if( *pc1++ != *pc2++ )
975                                         return FALSE;
976                         }
977                 }
978                 return TRUE;
979         }
980         return FALSE;
981 }
982
983
984 ULONG STDCALL
985 RtlUnicodeStringToAnsiSize(IN PUNICODE_STRING UnicodeString)
986 {
987   ULONG Size;
988
989   RtlUnicodeToMultiByteSize(&Size,
990                             UnicodeString->Buffer,
991                             UnicodeString->Length);
992
993   return(Size+1);
994 }
995
996
997 NTSTATUS STDCALL
998 RtlUnicodeStringToAnsiString(IN OUT PANSI_STRING DestinationString,
999                              IN PUNICODE_STRING SourceString,
1000                              IN BOOLEAN AllocateDestinationString)
1001 {
1002   NTSTATUS Status;
1003   ULONG Length;
1004   
1005   if (NlsMbCodePageTag == TRUE){
1006     Length = RtlUnicodeStringToAnsiSize (SourceString); Length--;
1007   }
1008   else
1009     Length = SourceString->Length / sizeof(WCHAR);
1010   
1011   if (AllocateDestinationString == TRUE)
1012     {
1013       DestinationString->MaximumLength = Length + sizeof(CHAR);
1014       DestinationString->Buffer =
1015         ExAllocatePoolWithTag (NonPagedPool,
1016                                DestinationString->MaximumLength,
1017                                TAG_ASTR);
1018       if (DestinationString->Buffer == NULL)
1019         return STATUS_NO_MEMORY;
1020     }
1021   else
1022     {
1023       if (Length >= DestinationString->MaximumLength)
1024         return STATUS_BUFFER_TOO_SMALL;
1025     }
1026   DestinationString->Length = Length;
1027   
1028   RtlZeroMemory (DestinationString->Buffer,
1029                  DestinationString->Length);
1030   
1031   Status = RtlUnicodeToMultiByteN (DestinationString->Buffer,
1032                                    DestinationString->Length,
1033                                    NULL,
1034                                    SourceString->Buffer,
1035                                    SourceString->Length);
1036   if (!NT_SUCCESS(Status))
1037     {
1038       if (AllocateDestinationString)
1039         ExFreePool (DestinationString->Buffer);
1040                 return Status;
1041     }
1042   
1043   DestinationString->Buffer[Length] = 0;
1044   
1045   return STATUS_SUCCESS;
1046 }
1047
1048
1049 NTSTATUS STDCALL
1050 RtlUnicodeStringToCountedOemString(IN OUT POEM_STRING DestinationString,
1051                                    IN PUNICODE_STRING SourceString,
1052                                    IN BOOLEAN AllocateDestinationString)
1053 {
1054   NTSTATUS Status;
1055   ULONG Length;
1056   ULONG Size;
1057   
1058   if (NlsMbOemCodePageTag == TRUE)
1059     Length = RtlUnicodeStringToAnsiSize (SourceString)/* + 1*/;
1060   else
1061     Length = SourceString->Length / sizeof(WCHAR) + 1;
1062   
1063   if (Length > 0x0000FFFF)
1064     return STATUS_INVALID_PARAMETER_2;
1065   
1066   DestinationString->Length = (WORD)(Length - 1);
1067   
1068   if (AllocateDestinationString)
1069     {
1070       DestinationString->Buffer = ExAllocatePoolWithTag (NonPagedPool,
1071                                                          Length,
1072                                                          TAG_ASTR);
1073       
1074       if (DestinationString->Buffer == NULL)
1075         return STATUS_NO_MEMORY;
1076       
1077       RtlZeroMemory (DestinationString->Buffer,
1078                      Length);
1079       DestinationString->MaximumLength = (WORD)Length;
1080         }
1081   else
1082     {
1083       if (Length > DestinationString->MaximumLength)
1084         {
1085           if (DestinationString->MaximumLength == 0)
1086             return STATUS_BUFFER_OVERFLOW;
1087           DestinationString->Length =
1088             DestinationString->MaximumLength - 1;
1089         }
1090     }
1091   
1092   Status = RtlUnicodeToOemN (DestinationString->Buffer,
1093                              DestinationString->Length,
1094                              &Size,
1095                              SourceString->Buffer,
1096                              SourceString->Length);
1097   if (!NT_SUCCESS(Status))
1098     {
1099       if (AllocateDestinationString)
1100         ExFreePool (DestinationString->Buffer);
1101
1102       return Status;
1103     }
1104   
1105   DestinationString->Buffer[Size] = 0;
1106   
1107   return STATUS_SUCCESS;
1108 }
1109
1110
1111 NTSTATUS STDCALL
1112 RtlUnicodeStringToInteger(IN PUNICODE_STRING String,
1113                           IN ULONG Base,
1114                           OUT PULONG Value)
1115 {
1116         PWCHAR Str;
1117         ULONG lenmin = 0;
1118         ULONG i;
1119         ULONG Val;
1120         BOOLEAN addneg = FALSE;
1121
1122     *Value = 0;
1123         Str = String->Buffer;
1124
1125         for (i = 0; i < String->Length / sizeof(WCHAR); i++)
1126         {
1127                 if (*Str == L'b')
1128                 {
1129                         Base = 2;
1130                         lenmin++;
1131                 }
1132                 else if (*Str == L'o')
1133                 {
1134                         Base = 8;
1135                         lenmin++;
1136                 }
1137                 else if (*Str == L'd')
1138                 {
1139                         Base = 10;
1140                         lenmin++;
1141                 }
1142                 else if (*Str == L'x')
1143                 {
1144                         Base = 16;
1145                         lenmin++;
1146                 }
1147                 else if (*Str == L'+')
1148                 {
1149                         lenmin++;
1150                 }
1151                 else if (*Str == L'-')
1152                 {
1153                         addneg = TRUE;
1154                         lenmin++;
1155                 }
1156                 else if ((*Str > L'1') && (Base == 2))
1157                 {
1158                         return STATUS_INVALID_PARAMETER;
1159                 }
1160                 else if (((*Str > L'7') || (*Str < L'0')) && (Base == 8))
1161                 {
1162                         return STATUS_INVALID_PARAMETER;
1163                 }
1164                 else if (((*Str > L'9') || (*Str < L'0')) && (Base == 10))
1165                 {
1166                         return STATUS_INVALID_PARAMETER;
1167                 }
1168                 else if ((((*Str > L'9') || (*Str < L'0')) ||
1169                           ((towupper (*Str) > L'F') ||
1170                            (towupper (*Str) < L'A'))) && (Base == 16))
1171                 {
1172                         return STATUS_INVALID_PARAMETER;
1173                 }
1174                 else
1175                         Str++;
1176         }
1177
1178         Str = String->Buffer + lenmin;
1179
1180         if (Base == 0)
1181                 Base = 10;
1182
1183         while (iswxdigit (*Str) &&
1184                (Val = iswdigit (*Str) ? *Str - L'0' : (iswlower (*Str)
1185                 ? toupper (*Str) : *Str) - L'A' + 10) < Base)
1186         {
1187                 *Value = *Value * Base + Val;
1188                 Str++;
1189         }
1190
1191         if (addneg == TRUE)
1192                 *Value *= -1;
1193
1194         return STATUS_SUCCESS;
1195 }
1196
1197
1198 ULONG STDCALL
1199 RtlUnicodeStringToOemSize(IN PUNICODE_STRING UnicodeString)
1200 {
1201   ULONG Size;
1202
1203   RtlUnicodeToMultiByteSize(&Size,
1204                             UnicodeString->Buffer,
1205                             UnicodeString->Length);
1206   return(Size+1);
1207 }
1208
1209
1210 NTSTATUS STDCALL
1211 RtlUnicodeStringToOemString(IN OUT POEM_STRING DestinationString,
1212                             IN PUNICODE_STRING SourceString,
1213                             IN BOOLEAN AllocateDestinationString)
1214 {
1215   NTSTATUS Status;
1216   ULONG Length;
1217   
1218   if (NlsMbOemCodePageTag == TRUE){
1219     Length = RtlUnicodeStringToAnsiSize (SourceString); Length--;
1220   }
1221   else
1222     Length = SourceString->Length / sizeof(WCHAR);
1223   
1224   if (AllocateDestinationString == TRUE)
1225     {
1226       DestinationString->MaximumLength = Length + sizeof(CHAR);
1227       DestinationString->Buffer =
1228         ExAllocatePoolWithTag (NonPagedPool,
1229                                DestinationString->MaximumLength,
1230                                TAG_OSTR);
1231       if (DestinationString->Buffer == NULL)
1232         return STATUS_NO_MEMORY;
1233     }
1234   else
1235     {
1236       if (Length >= DestinationString->MaximumLength)
1237         return STATUS_BUFFER_TOO_SMALL;
1238     }
1239   DestinationString->Length = Length;
1240   
1241   RtlZeroMemory(DestinationString->Buffer,
1242                 DestinationString->Length);
1243   
1244   Status = RtlUnicodeToOemN(DestinationString->Buffer,
1245                             DestinationString->Length,
1246                             NULL,
1247                             SourceString->Buffer,
1248                             SourceString->Length);
1249   if (!NT_SUCCESS(Status))
1250     {
1251       if (AllocateDestinationString)
1252         ExFreePool(DestinationString->Buffer);
1253       return Status;
1254     }
1255   
1256   DestinationString->Buffer[Length] = 0;
1257   
1258   return STATUS_SUCCESS;
1259 }
1260
1261
1262 WCHAR STDCALL
1263 RtlUpcaseUnicodeChar(IN WCHAR Source)
1264 {
1265   if (Source < L'a')
1266     return(Source);
1267
1268   if (Source <= L'z')
1269     return(Source - (L'a' - L'A'));
1270
1271   /* FIXME: characters above 'z' */
1272
1273   return(Source);
1274 }
1275
1276
1277 /*
1278  * If 'AllocateDestinationString==TRUE' we return zero-terminated 'DestinationString' 
1279  * with: DestinationString->MaximumLength=SourceString->Length+sizeof(WCHAR)
1280  * If 'AllocateDestinationString==FALSE' we try to zero-terminate the passed 'DestinationString'
1281  * but we will succeed with no termination if: SourceString->Length==DestinationString->MaximumLength
1282  * Any zero-termination-related behaviour is undocumented by W32,
1283  * is 'DestinationString' required to be zero-terminated at all? Dunno.
1284  */
1285 NTSTATUS STDCALL
1286 RtlUpcaseUnicodeString(IN OUT PUNICODE_STRING DestinationString,
1287                        IN PUNICODE_STRING SourceString,
1288                        IN BOOLEAN AllocateDestinationString)
1289 {
1290   ULONG i;
1291   PWCHAR Src, Dest;
1292   
1293   if (AllocateDestinationString == TRUE)
1294     {
1295       DestinationString->MaximumLength = SourceString->Length + sizeof(WCHAR);
1296       DestinationString->Buffer = 
1297         ExAllocatePoolWithTag(NonPagedPool,
1298                               SourceString->Length + sizeof(WCHAR),
1299                               TAG_USTR);
1300       if (DestinationString->Buffer == NULL)
1301         return(STATUS_NO_MEMORY);
1302     }
1303   else
1304     {
1305       if (SourceString->Length > DestinationString->MaximumLength)
1306         return(STATUS_BUFFER_TOO_SMALL);
1307     }
1308   DestinationString->Length = SourceString->Length;
1309   
1310   Src = SourceString->Buffer;
1311   Dest = DestinationString->Buffer;
1312   for (i=0; i < SourceString->Length / sizeof(WCHAR); i++)
1313     {
1314       *Dest = RtlUpcaseUnicodeChar(*Src);
1315       Dest++;
1316       Src++;
1317     }
1318   /* We may get pre-allocated 'DestinationString' with no space for the terminator! */
1319   if (SourceString->Length+sizeof(WCHAR) <= DestinationString->MaximumLength)
1320     *Dest = 0;
1321   
1322   return(STATUS_SUCCESS);
1323 }
1324
1325
1326 NTSTATUS STDCALL
1327 RtlUpcaseUnicodeStringToAnsiString(IN OUT PANSI_STRING DestinationString,
1328                                    IN PUNICODE_STRING SourceString,
1329                                    IN BOOLEAN AllocateDestinationString)
1330 {
1331   NTSTATUS Status;
1332   ULONG Length;
1333   
1334   if (NlsMbCodePageTag == TRUE){
1335     Length = RtlUnicodeStringToAnsiSize(SourceString); Length--;
1336   }
1337   else
1338     Length = SourceString->Length / sizeof(WCHAR);
1339   
1340   if (AllocateDestinationString == TRUE)
1341     {
1342       DestinationString->MaximumLength = Length + sizeof(CHAR);
1343       DestinationString->Buffer = 
1344         ExAllocatePoolWithTag(NonPagedPool,
1345                               DestinationString->MaximumLength,
1346                               TAG_ASTR);
1347       if (DestinationString->Buffer == NULL)
1348         return(STATUS_NO_MEMORY);
1349     }
1350   else
1351     {
1352       if (Length >= DestinationString->MaximumLength)
1353         return(STATUS_BUFFER_TOO_SMALL);
1354     }
1355   DestinationString->Length = Length;
1356   
1357   RtlZeroMemory(DestinationString->Buffer,
1358                 DestinationString->Length);
1359   
1360   Status = RtlUpcaseUnicodeToMultiByteN(DestinationString->Buffer,
1361                                         DestinationString->Length,
1362                                         NULL,
1363                                         SourceString->Buffer,
1364                                         SourceString->Length);
1365   if (!NT_SUCCESS(Status))
1366     {
1367       if (AllocateDestinationString)
1368         ExFreePool(DestinationString->Buffer);
1369       return(Status);
1370     }
1371   
1372   DestinationString->Buffer[Length] = 0;
1373   
1374   return(STATUS_SUCCESS);
1375 }
1376
1377
1378 NTSTATUS STDCALL
1379 RtlUpcaseUnicodeStringToCountedOemString(IN OUT POEM_STRING DestinationString,
1380                                          IN PUNICODE_STRING SourceString,
1381                                          IN BOOLEAN AllocateDestinationString)
1382 {
1383   NTSTATUS Status;
1384   ULONG Length;
1385   ULONG Size;
1386
1387   if (NlsMbCodePageTag == TRUE)
1388     Length = RtlUnicodeStringToAnsiSize (SourceString)/* + 1*/;
1389   else
1390     Length = SourceString->Length / sizeof(WCHAR) + 1;
1391
1392   if (Length > 0x0000FFFF)
1393     return(STATUS_INVALID_PARAMETER_2);
1394
1395   DestinationString->Length = (WORD)(Length - 1);
1396
1397   if (AllocateDestinationString == TRUE)
1398     {
1399       DestinationString->Buffer =
1400         ExAllocatePoolWithTag(NonPagedPool,
1401                               Length,
1402                               TAG_OSTR);
1403       if (DestinationString->Buffer == NULL)
1404         return(STATUS_NO_MEMORY);
1405
1406       RtlZeroMemory(DestinationString->Buffer,
1407                     Length);
1408       DestinationString->MaximumLength = (WORD)Length;
1409     }
1410   else
1411     {
1412       if (Length > DestinationString->MaximumLength)
1413         {
1414           if (DestinationString->MaximumLength == 0)
1415             return(STATUS_BUFFER_OVERFLOW);
1416           DestinationString->Length =
1417             DestinationString->MaximumLength - 1;
1418         }
1419     }
1420
1421   Status = RtlUpcaseUnicodeToOemN(DestinationString->Buffer,
1422                                   DestinationString->Length,
1423                                   &Size,
1424                                   SourceString->Buffer,
1425                                   SourceString->Length);
1426   if (!NT_SUCCESS(Status))
1427     {
1428       if (AllocateDestinationString)
1429         ExFreePool(DestinationString->Buffer);
1430       return(Status);
1431     }
1432
1433   DestinationString->Buffer[Size] = 0;
1434
1435   return(STATUS_SUCCESS);
1436 }
1437
1438
1439 NTSTATUS STDCALL
1440 RtlUpcaseUnicodeStringToOemString(IN OUT POEM_STRING DestinationString,
1441                                   IN PUNICODE_STRING SourceString,
1442                                   IN BOOLEAN AllocateDestinationString)
1443 {
1444   NTSTATUS Status;
1445   ULONG Length;
1446
1447   if (NlsMbOemCodePageTag == TRUE) {
1448     Length = RtlUnicodeStringToOemSize(SourceString); Length--;
1449   }
1450   else
1451     Length = SourceString->Length / sizeof(WCHAR);
1452
1453   if (AllocateDestinationString == TRUE)
1454     {
1455       DestinationString->MaximumLength = Length + sizeof(CHAR);
1456       DestinationString->Buffer =
1457         ExAllocatePoolWithTag(NonPagedPool,
1458                               DestinationString->MaximumLength,
1459                               TAG_OSTR);
1460       if (DestinationString->Buffer == NULL)
1461         return(STATUS_NO_MEMORY);
1462     }
1463   else
1464     {
1465       if (Length >= DestinationString->MaximumLength)
1466         return(STATUS_BUFFER_TOO_SMALL);
1467     }
1468   DestinationString->Length = Length;
1469
1470   RtlZeroMemory(DestinationString->Buffer,
1471                 DestinationString->Length);
1472
1473   Status = RtlUpcaseUnicodeToOemN(DestinationString->Buffer,
1474                                   DestinationString->Length,
1475                                   NULL,
1476                                   SourceString->Buffer,
1477                                   SourceString->Length);
1478   if (!NT_SUCCESS(Status))
1479     {
1480       if (AllocateDestinationString)
1481         ExFreePool(DestinationString->Buffer);
1482       return(Status);
1483     }
1484
1485   DestinationString->Buffer[Length] = 0;
1486
1487   return(STATUS_SUCCESS);
1488 }
1489
1490
1491 CHAR STDCALL
1492 RtlUpperChar(IN CHAR Source)
1493 {
1494   WCHAR Unicode;
1495   CHAR Destination;
1496
1497         if (NlsMbCodePageTag == FALSE)
1498         {
1499                 /* single-byte code page */
1500                 /* ansi->unicode */
1501                 Unicode = (WCHAR)Source;
1502 #if 0
1503                 Unicode = NlsAnsiToUnicodeData[Source];
1504 #endif
1505
1506                 /* upcase conversion */
1507                 Unicode = RtlUpcaseUnicodeChar (Unicode);
1508
1509                 /* unicode -> ansi */
1510                 Destination = (CHAR)Unicode;
1511 #if 0
1512                 Destination = NlsUnicodeToAnsiData[Unicode];
1513 #endif
1514         }
1515         else
1516         {
1517                 /* single-byte code page */
1518                 /* FIXME: implement the multi-byte stuff!! */
1519                 Destination = Source;
1520         }
1521
1522   return(Destination);
1523 }
1524
1525
1526 VOID STDCALL
1527 RtlUpperString(PSTRING DestinationString,
1528                PSTRING SourceString)
1529 {
1530   ULONG Length;
1531   ULONG i;
1532   PCHAR Src;
1533   PCHAR Dest;
1534
1535   Length = min(SourceString->Length,
1536                DestinationString->MaximumLength - 1);
1537
1538   Src = SourceString->Buffer;
1539   Dest = DestinationString->Buffer;
1540   for (i = 0; i < Length; i++)
1541     {
1542       *Dest = RtlUpperChar(*Src);
1543       Src++;
1544       Dest++;
1545     }
1546   *Dest = 0;
1547
1548   DestinationString->Length = SourceString->Length;
1549 }
1550
1551
1552 ULONG STDCALL
1553 RtlxAnsiStringToUnicodeSize(IN PANSI_STRING AnsiString)
1554 {
1555   return(RtlAnsiStringToUnicodeSize(AnsiString));
1556 }
1557
1558
1559 ULONG STDCALL
1560 RtlxOemStringToUnicodeSize(IN POEM_STRING OemString)
1561 {
1562   return(RtlOemStringToUnicodeSize((PANSI_STRING)OemString));
1563 }
1564
1565
1566 ULONG STDCALL
1567 RtlxUnicodeStringToAnsiSize(IN PUNICODE_STRING UnicodeString)
1568 {
1569   return(RtlUnicodeStringToAnsiSize(UnicodeString));
1570 }
1571
1572
1573 ULONG STDCALL
1574 RtlxUnicodeStringToOemSize(IN PUNICODE_STRING UnicodeString)
1575 {
1576   return(RtlUnicodeStringToOemSize(UnicodeString));
1577 }
1578
1579 /* EOF */