ExFreePool -> ExFreePoolWithTag changes
[reactos.git] / reactos / lib / rtl / unicode.c
1 /*
2 * Rtl string functions
3 *
4 * Copyright (C) 1996-1998 Marcus Meissner
5 * Copyright (C) 2000 Alexandre Julliard
6 * Copyright (C) 2003 Thomas Mertes
7 *
8 * This library is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Lesser General Public
10 * License as published by the Free Software Foundation; either
11 * version 2.1 of the License, or (at your option) any later version.
12 *
13 * This library is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * Lesser General Public License for more details.
17 *
18 * You should have received a copy of the GNU Lesser General Public
19 * License along with this library; if not, write to the Free Software
20 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
21 */
22
23
24 #define __NTDRIVER__
25 #include <ddk/ntddk.h>
26
27 #include <ntdll/rtl.h>
28
29 #include <ntos/minmax.h>
30 #define __NO_CTYPE_INLINES
31 #include <ctype.h>
32
33 #define NDEBUG
34 #include <debug.h>
35
36 /* GLOBALS *******************************************************************/
37
38 #define TAG_USTR TAG('U', 'S', 'T', 'R')
39 #define TAG_ASTR TAG('A', 'S', 'T', 'R')
40 #define TAG_OSTR TAG('O', 'S', 'T', 'R')
41
42
43 extern BOOLEAN NlsMbCodePageTag;
44 extern BOOLEAN NlsMbOemCodePageTag;
45
46 /* FUNCTIONS *****************************************************************/
47
48
49 /*
50 * @implemented
51 */
52 WCHAR STDCALL
53 RtlAnsiCharToUnicodeChar (IN CHAR AnsiChar)
54 {
55 ULONG Size;
56 WCHAR UnicodeChar;
57
58 Size = 1;
59 #if 0
60
61 Size = (NlsLeadByteInfo[AnsiChar] == 0) ? 1 : 2;
62 #endif
63
64 RtlMultiByteToUnicodeN (&UnicodeChar,
65 sizeof(WCHAR),
66 NULL,
67 &AnsiChar,
68 Size);
69
70 return UnicodeChar;
71 }
72
73
74 /*
75 * @implemented
76 *
77 * RETURNS
78 * The calculated size in bytes including nullterm.
79 */
80 ULONG
81 STDCALL
82 RtlAnsiStringToUnicodeSize(IN PANSI_STRING AnsiString)
83 {
84 ULONG Size;
85
86 RtlMultiByteToUnicodeSize(&Size,
87 AnsiString->Buffer,
88 AnsiString->Length);
89
90 return(Size);
91 }
92
93
94
95 /*
96 * @implemented
97 *
98 * NOTES
99 * If src->length is zero dest is unchanged.
100 * Dest is never nullterminated.
101 */
102 NTSTATUS
103 STDCALL
104 RtlAppendStringToString(IN OUT PSTRING Destination,
105 IN PSTRING Source)
106 {
107 PCHAR Ptr;
108
109 if (Source->Length == 0)
110 return(STATUS_SUCCESS);
111
112 if (Destination->Length + Source->Length >= Destination->MaximumLength)
113 return(STATUS_BUFFER_TOO_SMALL);
114
115 Ptr = Destination->Buffer + Destination->Length;
116 memmove(Ptr,
117 Source->Buffer,
118 Source->Length);
119 Ptr += Source->Length;
120 *Ptr = 0;
121
122 Destination->Length += Source->Length;
123
124 return(STATUS_SUCCESS);
125 }
126
127
128
129 /*
130 * @implemented
131 *
132 * NOTES
133 * If src->length is zero dest is unchanged.
134 * Dest is nullterminated when the MaximumLength allowes it.
135 * When dest fits exactly in MaximumLength characters the nullterm is ommitted.
136 */
137 NTSTATUS
138 STDCALL
139 RtlAppendUnicodeStringToString(
140 IN OUT PUNICODE_STRING Destination,
141 IN PUNICODE_STRING Source)
142 {
143
144 if ((Source->Length + Destination->Length) > Destination->MaximumLength)
145 return STATUS_BUFFER_TOO_SMALL;
146
147 memcpy((char*)Destination->Buffer + Destination->Length, Source->Buffer, Source->Length);
148 Destination->Length += Source->Length;
149 /* append terminating '\0' if enough space */
150 if( Destination->MaximumLength > Destination->Length )
151 Destination->Buffer[Destination->Length / sizeof(WCHAR)] = 0;
152
153 return STATUS_SUCCESS;
154 }
155
156
157 /*
158 * @implemented
159 */
160 NTSTATUS
161 STDCALL
162 RtlCharToInteger(
163 IN PCSZ String,
164 IN ULONG Base,
165 IN OUT PULONG Value)
166 {
167 ULONG Val;
168
169 *Value = 0;
170
171 if (Base == 0)
172 {
173 Base = 10;
174 if (*String == '0')
175 {
176 Base = 8;
177 String++;
178 if ((*String == 'x') && isxdigit (String[1]))
179 {
180 String++;
181 Base = 16;
182 }
183 }
184 }
185
186 if (!isxdigit (*String))
187 return STATUS_INVALID_PARAMETER;
188
189 while (isxdigit (*String) &&
190 (Val = isdigit (*String) ? * String - '0' : (islower (*String)
191 ? toupper (*String) : *String) - 'A' + 10) < Base)
192 {
193 *Value = *Value * Base + Val;
194 String++;
195 }
196
197 return STATUS_SUCCESS;
198 }
199
200
201
202 /*
203 * @implemented
204 */
205 LONG
206 STDCALL
207 RtlCompareString(
208 IN PSTRING String1,
209 IN PSTRING String2,
210 IN BOOLEAN CaseInsensitive)
211 {
212 ULONG len1, len2;
213 PCHAR s1, s2;
214 CHAR c1, c2;
215
216 if (String1 && String2)
217 {
218 len1 = String1->Length;
219 len2 = String2->Length;
220 s1 = String1->Buffer;
221 s2 = String2->Buffer;
222
223 if (s1 && s2)
224 {
225 if (CaseInsensitive)
226 {
227 for(;;)
228 {
229 c1 = len1-- ? RtlUpperChar (*s1++) : 0;
230 c2 = len2-- ? RtlUpperChar (*s2++) : 0;
231 if (!c1 || !c2 || c1 != c2)
232 return c1 - c2;
233 }
234 }
235 else
236 {
237 for(;;)
238 {
239 c1 = len1-- ? *s1++ : 0;
240 c2 = len2-- ? *s2++ : 0;
241 if (!c1 || !c2 || c1 != c2)
242 return c1 - c2;
243 }
244 }
245 }
246 }
247
248 return 0;
249 }
250
251
252 /*
253 * @implemented
254 *
255 * RETURNS
256 * TRUE if strings are equal.
257 */
258 BOOLEAN
259 STDCALL
260 RtlEqualString(
261 IN PSTRING String1,
262 IN PSTRING String2,
263 IN BOOLEAN CaseInsensitive)
264 {
265 ULONG i;
266 CHAR c1, c2;
267 PCHAR p1, p2;
268
269 if (String1->Length != String2->Length)
270 return FALSE;
271
272 p1 = String1->Buffer;
273 p2 = String2->Buffer;
274 for (i = 0; i < String1->Length; i++)
275 {
276 if (CaseInsensitive == TRUE)
277 {
278 c1 = RtlUpperChar (*p1);
279 c2 = RtlUpperChar (*p2);
280 }
281 else
282 {
283 c1 = *p1;
284 c2 = *p2;
285 }
286
287 if (c1 != c2)
288 return FALSE;
289
290 p1++;
291 p2++;
292 }
293
294 return TRUE;
295 }
296
297
298 /*
299 * @implemented
300 *
301 * RETURNS
302 * TRUE if strings are equal.
303 */
304 BOOLEAN
305 STDCALL
306 RtlEqualUnicodeString(
307 IN PUNICODE_STRING String1,
308 IN PUNICODE_STRING String2,
309 IN BOOLEAN CaseInsensitive)
310 {
311 ULONG i;
312 WCHAR wc1, wc2;
313 PWCHAR pw1, pw2;
314
315 if (String1->Length != String2->Length)
316 return FALSE;
317
318 pw1 = String1->Buffer;
319 pw2 = String2->Buffer;
320
321 for (i = 0; i < String1->Length / sizeof(WCHAR); i++)
322 {
323 if (CaseInsensitive == TRUE)
324 {
325 wc1 = RtlUpcaseUnicodeChar (*pw1);
326 wc2 = RtlUpcaseUnicodeChar (*pw2);
327 }
328 else
329 {
330 wc1 = *pw1;
331 wc2 = *pw2;
332 }
333
334 if (wc1 != wc2)
335 return FALSE;
336
337 pw1++;
338 pw2++;
339 }
340
341 return TRUE;
342 }
343
344
345 /*
346 * @implemented
347 */
348 VOID
349 STDCALL
350 RtlFreeAnsiString(IN PANSI_STRING AnsiString)
351 {
352 if (AnsiString->Buffer == NULL)
353 return;
354
355 ExFreePoolWithTag(AnsiString->Buffer, TAG_ASTR);
356
357 AnsiString->Buffer = NULL;
358 AnsiString->Length = 0;
359 AnsiString->MaximumLength = 0;
360 }
361
362
363 /*
364 * @implemented
365 */
366 VOID
367 STDCALL
368 RtlFreeOemString(IN POEM_STRING OemString)
369 {
370 if (OemString->Buffer == NULL)
371 return;
372
373 ExFreePoolWithTag(OemString->Buffer, TAG_OSTR);
374
375 OemString->Buffer = NULL;
376 OemString->Length = 0;
377 OemString->MaximumLength = 0;
378 }
379
380
381 /*
382 * @implemented
383 */
384 VOID
385 STDCALL
386 RtlFreeUnicodeString(IN PUNICODE_STRING UnicodeString)
387 {
388 if (UnicodeString->Buffer == NULL)
389 return;
390
391 ExFreePoolWithTag(UnicodeString->Buffer, TAG_USTR);
392
393 UnicodeString->Buffer = NULL;
394 UnicodeString->Length = 0;
395 UnicodeString->MaximumLength = 0;
396 }
397
398 /*
399 * @unimplemented
400 */
401 BOOLEAN
402 STDCALL
403 RtlIsValidOemCharacter (
404 IN PWCHAR Char
405 )
406 {
407 UNIMPLEMENTED;
408 return FALSE;
409 }
410
411 /*
412 * @implemented
413 *
414 * NOTES
415 * If source is NULL the length of source is assumed to be 0.
416 */
417 VOID
418 STDCALL
419 RtlInitAnsiString(IN OUT PANSI_STRING DestinationString,
420 IN PCSZ SourceString)
421 {
422 ULONG DestSize;
423
424 if (SourceString == NULL)
425 {
426 DestinationString->Length = 0;
427 DestinationString->MaximumLength = 0;
428 }
429 else
430 {
431 DestSize = strlen ((const char *)SourceString);
432 DestinationString->Length = DestSize;
433 DestinationString->MaximumLength = DestSize + sizeof(CHAR);
434 }
435 DestinationString->Buffer = (PCHAR)SourceString;
436 }
437
438
439
440 /*
441 * @implemented
442 *
443 * NOTES
444 * If source is NULL the length of source is assumed to be 0.
445 */
446 VOID
447 STDCALL
448 RtlInitString(
449 IN OUT PSTRING DestinationString,
450 IN PCSZ SourceString)
451 {
452 ULONG DestSize;
453
454 if (SourceString == NULL)
455 {
456 DestinationString->Length = 0;
457 DestinationString->MaximumLength = 0;
458 }
459 else
460 {
461 DestSize = strlen((const char *)SourceString);
462 DestinationString->Length = DestSize;
463 DestinationString->MaximumLength = DestSize + sizeof(CHAR);
464 }
465 DestinationString->Buffer = (PCHAR)SourceString;
466 }
467
468
469 /*
470 * @implemented
471 *
472 * NOTES
473 * If source is NULL the length of source is assumed to be 0.
474 */
475 VOID
476 STDCALL
477 RtlInitUnicodeString(IN OUT PUNICODE_STRING DestinationString,
478 IN PCWSTR SourceString)
479 {
480 ULONG DestSize;
481
482 DPRINT("RtlInitUnicodeString(DestinationString %x, SourceString %x)\n",
483 DestinationString,
484 SourceString);
485
486 if (SourceString == NULL)
487 {
488 DestinationString->Length = 0;
489 DestinationString->MaximumLength = 0;
490 }
491 else
492 {
493 DestSize = wcslen((PWSTR)SourceString) * sizeof(WCHAR);
494 DestinationString->Length = DestSize;
495 DestinationString->MaximumLength = DestSize + sizeof(WCHAR);
496 }
497 DestinationString->Buffer = (PWSTR)SourceString;
498 }
499
500 /*
501 * @implemented
502 */
503 NTSTATUS STDCALL
504 RtlInitUnicodeStringEx(OUT PUNICODE_STRING DestinationString,
505 IN PCWSTR SourceString)
506 {
507 ULONG Length;
508
509 if (SourceString != NULL)
510 {
511 Length = wcslen(SourceString) * sizeof(WCHAR);
512 if (Length > 0xFFFC)
513 return STATUS_NAME_TOO_LONG;
514
515 DestinationString->Length = Length;
516 DestinationString->MaximumLength = Length + sizeof(WCHAR);
517 DestinationString->Buffer = (PWSTR)SourceString;
518 }
519 else
520 {
521 DestinationString->Length = 0;
522 DestinationString->MaximumLength = 0;
523 DestinationString->Buffer = NULL;
524 }
525
526 return STATUS_SUCCESS;
527 }
528
529 /*
530 * @implemented
531 *
532 * NOTES
533 * Writes at most length characters to the string str.
534 * Str is nullterminated when length allowes it.
535 * When str fits exactly in length characters the nullterm is ommitted.
536 */
537 NTSTATUS
538 STDCALL
539 RtlIntegerToChar(
540 IN ULONG Value,
541 IN ULONG Base,
542 IN ULONG Length,
543 IN OUT PCHAR String)
544 {
545 ULONG Radix;
546 CHAR temp[33];
547 ULONG v = Value;
548 ULONG i;
549 PCHAR tp;
550 PCHAR sp;
551
552 Radix = Base;
553 if (Radix == 0)
554 Radix = 10;
555
556 if ((Radix != 2) && (Radix != 8) &&
557 (Radix != 10) && (Radix != 16))
558 {
559 return STATUS_INVALID_PARAMETER;
560 }
561
562 tp = temp;
563 while (v || tp == temp)
564 {
565 i = v % Radix;
566 v = v / Radix;
567 if (i < 10)
568 *tp = i + '0';
569 else
570 *tp = i + 'a' - 10;
571 tp++;
572 }
573
574 if (tp - temp >= Length)
575 {
576 return STATUS_BUFFER_TOO_SMALL;
577 }
578
579 sp = String;
580 while (tp > temp)
581 *sp++ = *--tp;
582 *sp = 0;
583
584 return STATUS_SUCCESS;
585 }
586
587
588 /*
589 * @implemented
590 */
591 NTSTATUS
592 STDCALL
593 RtlIntegerToUnicode(
594 IN ULONG Value,
595 IN ULONG Base OPTIONAL,
596 IN ULONG Length OPTIONAL,
597 IN OUT LPWSTR String
598 )
599 {
600 ULONG Radix;
601 WCHAR temp[33];
602 ULONG v = Value;
603 ULONG i;
604 PWCHAR tp;
605 PWCHAR sp;
606
607 Radix = Base;
608 if (Radix == 0)
609 Radix = 10;
610
611 if ((Radix != 2) && (Radix != 8) &&
612 (Radix != 10) && (Radix != 16))
613 {
614 return STATUS_INVALID_PARAMETER;
615 }
616
617 tp = temp;
618 while (v || tp == temp)
619 {
620 i = v % Radix;
621 v = v / Radix;
622 if (i < 10)
623 *tp = i + L'0';
624 else
625 *tp = i + L'a' - 10;
626 tp++;
627 }
628
629 if (tp - temp >= Length)
630 {
631 return STATUS_BUFFER_TOO_SMALL;
632 }
633
634 sp = String;
635 while (tp > temp)
636 *sp++ = *--tp;
637 *sp = 0;
638
639 return STATUS_SUCCESS;
640 }
641
642
643
644 /*
645 * @implemented
646 */
647 NTSTATUS
648 STDCALL
649 RtlIntegerToUnicodeString(
650 IN ULONG Value,
651 IN ULONG Base, /* optional */
652 IN OUT PUNICODE_STRING String)
653 {
654 ANSI_STRING AnsiString;
655 CHAR Buffer[33];
656 NTSTATUS Status;
657
658 Status = RtlIntegerToChar (Value,
659 Base,
660 sizeof(Buffer),
661 Buffer);
662 if (!NT_SUCCESS(Status))
663 return Status;
664
665 AnsiString.Buffer = Buffer;
666 AnsiString.Length = strlen (Buffer);
667 AnsiString.MaximumLength = sizeof(Buffer);
668
669 Status = RtlAnsiStringToUnicodeString (String,
670 &AnsiString,
671 FALSE);
672
673 return Status;
674 }
675
676
677 /*
678 * @implemented
679 */
680 NTSTATUS
681 STDCALL
682 RtlInt64ToUnicodeString (
683 IN ULONGLONG Value,
684 IN ULONG Base OPTIONAL,
685 IN OUT PUNICODE_STRING String
686 )
687 {
688 LARGE_INTEGER LargeInt;
689 ANSI_STRING AnsiString;
690 CHAR Buffer[33];
691 NTSTATUS Status;
692
693 LargeInt.QuadPart = Value;
694
695 Status = RtlLargeIntegerToChar (&LargeInt,
696 Base,
697 sizeof(Buffer),
698 Buffer);
699 if (!NT_SUCCESS(Status))
700 return Status;
701
702 AnsiString.Buffer = Buffer;
703 AnsiString.Length = strlen (Buffer);
704 AnsiString.MaximumLength = sizeof(Buffer);
705
706 Status = RtlAnsiStringToUnicodeString (String,
707 &AnsiString,
708 FALSE);
709
710 return Status;
711 }
712
713
714 /*
715 * @implemented
716 *
717 * RETURNS
718 * TRUE if String2 contains String1 as a prefix.
719 */
720 BOOLEAN
721 STDCALL
722 RtlPrefixString(
723 PANSI_STRING String1,
724 PANSI_STRING String2,
725 BOOLEAN CaseInsensitive)
726 {
727 PCHAR pc1;
728 PCHAR pc2;
729 ULONG Length;
730
731 if (String2->Length < String1->Length)
732 return FALSE;
733
734 Length = String1->Length;
735 pc1 = String1->Buffer;
736 pc2 = String2->Buffer;
737
738 if (pc1 && pc2)
739 {
740 if (CaseInsensitive)
741 {
742 while (Length--)
743 {
744 if (RtlUpperChar (*pc1++) != RtlUpperChar (*pc2++))
745 return FALSE;
746 }
747 }
748 else
749 {
750 while (Length--)
751 {
752 if (*pc1++ != *pc2++)
753 return FALSE;
754 }
755 }
756 return TRUE;
757 }
758 return FALSE;
759 }
760
761
762 /*
763 * @implemented
764 *
765 * RETURNS
766 * TRUE if String2 contains String1 as a prefix.
767 */
768 BOOLEAN
769 STDCALL
770 RtlPrefixUnicodeString(
771 PUNICODE_STRING String1,
772 PUNICODE_STRING String2,
773 BOOLEAN CaseInsensitive)
774 {
775 PWCHAR pc1;
776 PWCHAR pc2;
777 ULONG Length;
778
779 if (String2->Length < String1->Length)
780 return FALSE;
781
782 Length = String1->Length / 2;
783 pc1 = String1->Buffer;
784 pc2 = String2->Buffer;
785
786 if (pc1 && pc2)
787 {
788 if (CaseInsensitive)
789 {
790 while (Length--)
791 {
792 if (RtlUpcaseUnicodeChar (*pc1++)
793 != RtlUpcaseUnicodeChar (*pc2++))
794 return FALSE;
795 }
796 }
797 else
798 {
799 while (Length--)
800 {
801 if( *pc1++ != *pc2++ )
802 return FALSE;
803 }
804 }
805 return TRUE;
806 }
807 return FALSE;
808 }
809
810
811
812 /*
813 * @implemented
814 *
815 * Note that regardless of success or failure status, we should leave the
816 * partial value in Value. An error is never returned based on the chars
817 * in the string.
818 *
819 * This function does check the base. Only 2, 8, 10, 16 are permitted,
820 * else STATUS_INVALID_PARAMETER is returned.
821 */
822 NTSTATUS
823 STDCALL
824 RtlUnicodeStringToInteger(
825 IN PUNICODE_STRING String,
826 IN ULONG Base,
827 OUT PULONG Value)
828 {
829 PWCHAR Str;
830 ULONG lenmin = 0;
831 ULONG i;
832 ULONG Val;
833 BOOLEAN addneg = FALSE;
834 NTSTATUS Status = STATUS_SUCCESS;
835
836 *Value = 0;
837 Str = String->Buffer;
838
839 if( Base && Base != 2 && Base != 8 && Base != 10 && Base != 16 )
840 return STATUS_INVALID_PARAMETER;
841
842 for (i = 0; i < String->Length / sizeof(WCHAR); i++)
843 {
844 if (*Str == L'b')
845 {
846 Base = 2;
847 lenmin++;
848 }
849 else if (*Str == L'o')
850 {
851 Base = 8;
852 lenmin++;
853 }
854 else if (*Str == L'd')
855 {
856 Base = 10;
857 lenmin++;
858 }
859 else if (*Str == L'x')
860 {
861 Base = 16;
862 lenmin++;
863 }
864 else if (*Str == L'+')
865 {
866 lenmin++;
867 }
868 else if (*Str == L'-')
869 {
870 addneg = TRUE;
871 lenmin++;
872 }
873 else if ((*Str > L'1') && (Base == 2))
874 {
875 break;
876 }
877 else if (((*Str > L'7') || (*Str < L'0')) && (Base == 8))
878 {
879 break;
880 }
881 else if (((*Str > L'9') || (*Str < L'0')) && (Base == 10))
882 {
883 break;
884 }
885 else if ( ((*Str > L'9') || (*Str < L'0')) &&
886 ((towupper (*Str) > L'F') || (towupper (*Str) < L'A')) &&
887 (Base == 16))
888 {
889 break;
890 }
891 Str++;
892 }
893
894 Str = String->Buffer + lenmin;
895
896 if (Base == 0)
897 Base = 10;
898
899 while (iswxdigit (*Str) &&
900 (Val =
901 iswdigit (*Str) ?
902 *Str - L'0' :
903 (towupper (*Str) - L'A' + 10)) < Base)
904 {
905 *Value = *Value * Base + Val;
906 Str++;
907 }
908
909 if (addneg == TRUE)
910 *Value *= -1;
911
912 return Status;
913 }
914
915
916
917 /*
918 * @implemented
919 *
920 * RETURNS
921 * Bytes necessary for the conversion including nullterm.
922 */
923 ULONG
924 STDCALL
925 RtlUnicodeStringToOemSize(
926 IN PUNICODE_STRING UnicodeString)
927 {
928 ULONG Size;
929
930 RtlUnicodeToMultiByteSize (&Size,
931 UnicodeString->Buffer,
932 UnicodeString->Length);
933
934 return Size+1; //NB: incl. nullterm
935 }
936
937
938 /*
939 * @implemented
940 *
941
942 * NOTES
943 * See RtlpUnicodeStringToAnsiString
944 */
945 NTSTATUS
946 STDCALL
947 RtlUnicodeStringToAnsiString(
948 IN OUT PANSI_STRING AnsiDest,
949 IN PUNICODE_STRING UniSource,
950 IN BOOLEAN AllocateDestinationString)
951 {
952 return RtlpUnicodeStringToAnsiString(
953 AnsiDest,
954 UniSource,
955 AllocateDestinationString,
956 NonPagedPool);
957 }
958
959
960 /*
961 * private
962 *
963 * NOTES
964 * This function always writes a terminating '\0'.
965 * It performs a partial copy if ansi is too small.
966 */
967 NTSTATUS
968 FASTCALL
969 RtlpUnicodeStringToAnsiString(
970 IN OUT PANSI_STRING AnsiDest,
971 IN PUNICODE_STRING UniSource,
972 IN BOOLEAN AllocateDestinationString,
973 IN POOL_TYPE PoolType)
974 {
975 NTSTATUS Status = STATUS_SUCCESS;
976 ULONG Length; //including nullterm
977
978 if (NlsMbCodePageTag == TRUE)
979 {
980 Length = RtlUnicodeStringToAnsiSize(UniSource);
981 }
982 else
983 Length = (UniSource->Length / sizeof(WCHAR)) + sizeof(CHAR);
984
985 AnsiDest->Length = Length - sizeof(CHAR);
986
987 if (AllocateDestinationString)
988 {
989 AnsiDest->Buffer = ExAllocatePoolWithTag(PoolType, Length, TAG_ASTR);
990 if (AnsiDest->Buffer == NULL)
991 return STATUS_NO_MEMORY;
992
993 AnsiDest->MaximumLength = Length;
994 }
995 else if (AnsiDest->MaximumLength == 0)
996 {
997 return STATUS_BUFFER_TOO_SMALL;
998 }
999 else if (Length > AnsiDest->MaximumLength)
1000 {
1001 //make room for nullterm
1002 AnsiDest->Length = AnsiDest->MaximumLength - sizeof(CHAR);
1003 }
1004
1005 Status = RtlUnicodeToMultiByteN (AnsiDest->Buffer,
1006 AnsiDest->Length,
1007 NULL,
1008 UniSource->Buffer,
1009 UniSource->Length);
1010
1011 if (!NT_SUCCESS(Status) && AllocateDestinationString)
1012 {
1013 ExFreePoolWithTag(AnsiDest->Buffer, TAG_ASTR);
1014 return Status;
1015 }
1016
1017 AnsiDest->Buffer[AnsiDest->Length] = 0;
1018 return Status;
1019 }
1020
1021
1022 /*
1023 * @implemented
1024 *
1025 * NOTES
1026 * See RtlpOemStringToUnicodeString
1027 */
1028 NTSTATUS
1029 STDCALL
1030 RtlOemStringToUnicodeString(
1031 IN OUT PUNICODE_STRING UniDest,
1032 IN POEM_STRING OemSource,
1033 IN BOOLEAN AllocateDestinationString)
1034 {
1035 return RtlpOemStringToUnicodeString(
1036 UniDest,
1037 OemSource,
1038 AllocateDestinationString,
1039 NonPagedPool);
1040 }
1041
1042
1043 /*
1044 * private
1045 *
1046 * NOTES
1047 * This function always writes a terminating '\0'.
1048 * Does NOT perform a partial copy if unicode is too small!
1049 */
1050 NTSTATUS
1051 FASTCALL
1052 RtlpOemStringToUnicodeString(
1053 IN OUT PUNICODE_STRING UniDest,
1054 IN POEM_STRING OemSource,
1055 IN BOOLEAN AllocateDestinationString,
1056 IN POOL_TYPE PoolType)
1057 {
1058 NTSTATUS Status;
1059 ULONG Length; //including nullterm
1060
1061 if (NlsMbOemCodePageTag == TRUE)
1062 Length = RtlOemStringToUnicodeSize(OemSource);
1063 else
1064 Length = (OemSource->Length * sizeof(WCHAR)) + sizeof(WCHAR);
1065
1066 if (Length > 0xffff)
1067 return STATUS_INVALID_PARAMETER_2;
1068
1069 UniDest->Length = (WORD)(Length - sizeof(WCHAR));
1070
1071 if (AllocateDestinationString)
1072 {
1073 UniDest->Buffer = ExAllocatePoolWithTag(PoolType, Length, TAG_USTR);
1074 if (UniDest->Buffer == NULL)
1075 return STATUS_NO_MEMORY;
1076
1077 UniDest->MaximumLength = Length;
1078 }
1079 else if (Length > UniDest->MaximumLength)
1080 {
1081 DPRINT("STATUS_BUFFER_TOO_SMALL\n");
1082 return STATUS_BUFFER_TOO_SMALL;
1083 }
1084
1085 //FIXME: Do we need this????? -Gunnar
1086 RtlZeroMemory (UniDest->Buffer,
1087 UniDest->Length);
1088
1089 Status = RtlOemToUnicodeN (UniDest->Buffer,
1090 UniDest->Length,
1091 NULL,
1092 OemSource->Buffer,
1093 OemSource->Length);
1094
1095 if (!NT_SUCCESS(Status) && AllocateDestinationString)
1096 {
1097 ExFreePoolWithTag(UniDest->Buffer, TAG_USTR);
1098 return Status;
1099 }
1100
1101 UniDest->Buffer[UniDest->Length / sizeof(WCHAR)] = 0;
1102 return STATUS_SUCCESS;
1103 }
1104
1105
1106 /*
1107 * @implemented
1108 *
1109 * NOTES
1110 * See RtlpUnicodeStringToOemString.
1111 */
1112 NTSTATUS
1113 STDCALL
1114 RtlUnicodeStringToOemString(
1115 IN OUT POEM_STRING OemDest,
1116 IN PUNICODE_STRING UniSource,
1117 IN BOOLEAN AllocateDestinationString)
1118 {
1119 return RtlpUnicodeStringToOemString(
1120 OemDest,
1121 UniSource,
1122 AllocateDestinationString,
1123 NonPagedPool);
1124 }
1125
1126
1127
1128 /*
1129 * private
1130 *
1131 * NOTES
1132 * This function always '\0' terminates the string returned.
1133 */
1134 NTSTATUS
1135 FASTCALL
1136 RtlpUnicodeStringToOemString(
1137 IN OUT POEM_STRING OemDest,
1138 IN PUNICODE_STRING UniSource,
1139 IN BOOLEAN AllocateDestinationString,
1140 IN POOL_TYPE PoolType)
1141 {
1142 NTSTATUS Status = STATUS_SUCCESS;
1143 ULONG Length; //including nullterm
1144
1145 if (NlsMbOemCodePageTag == TRUE)
1146 Length = RtlUnicodeStringToAnsiSize (UniSource);
1147 else
1148 Length = (UniSource->Length / sizeof(WCHAR)) + sizeof(CHAR);
1149
1150 if (Length > 0x0000FFFF)
1151 return STATUS_INVALID_PARAMETER_2;
1152
1153 OemDest->Length = (WORD)(Length - sizeof(CHAR));
1154
1155 if (AllocateDestinationString)
1156 {
1157 OemDest->Buffer = ExAllocatePoolWithTag(PoolType, Length, TAG_OSTR);
1158 if (OemDest->Buffer == NULL)
1159 return STATUS_NO_MEMORY;
1160
1161 OemDest->MaximumLength = Length;
1162 }
1163 else if (OemDest->MaximumLength == 0)
1164 {
1165 return STATUS_BUFFER_TOO_SMALL;
1166 }
1167 else if (Length > OemDest->MaximumLength)
1168 {
1169 //make room for nullterm
1170 OemDest->Length = OemDest->MaximumLength - sizeof(CHAR);
1171 }
1172
1173 Status = RtlUnicodeToOemN (OemDest->Buffer,
1174 OemDest->Length,
1175 NULL,
1176 UniSource->Buffer,
1177 UniSource->Length);
1178
1179 if (!NT_SUCCESS(Status) && AllocateDestinationString)
1180 {
1181 ExFreePoolWithTag(OemDest->Buffer, TAG_OSTR);
1182 return Status;
1183 }
1184
1185 OemDest->Buffer[OemDest->Length] = 0;
1186 return Status;
1187 }
1188
1189
1190
1191 #define ITU_IMPLEMENTED_TESTS (IS_TEXT_UNICODE_ODD_LENGTH|IS_TEXT_UNICODE_SIGNATURE)
1192
1193
1194 /*
1195 * @implemented
1196 *
1197 * RETURNS
1198 * The length of the string if all tests were passed, 0 otherwise.
1199 */
1200 ULONG STDCALL
1201 RtlIsTextUnicode (PVOID Buffer,
1202 ULONG Length,
1203 ULONG *Flags)
1204 {
1205 PWSTR s = Buffer;
1206 ULONG in_flags = (ULONG)-1;
1207 ULONG out_flags = 0;
1208
1209 if (Length == 0)
1210 goto done;
1211
1212 if (Flags != 0)
1213 in_flags = *Flags;
1214
1215 /*
1216 * Apply various tests to the text string. According to the
1217 * docs, each test "passed" sets the corresponding flag in
1218 * the output flags. But some of the tests are mutually
1219 * exclusive, so I don't see how you could pass all tests ...
1220 */
1221
1222 /* Check for an odd length ... pass if even. */
1223 if (!(Length & 1))
1224 out_flags |= IS_TEXT_UNICODE_ODD_LENGTH;
1225
1226 /* Check for the BOM (byte order mark). */
1227 if (*s == 0xFEFF)
1228 out_flags |= IS_TEXT_UNICODE_SIGNATURE;
1229
1230 #if 0
1231 /* Check for the reverse BOM (byte order mark). */
1232 if (*s == 0xFFFE)
1233 out_flags |= IS_TEXT_UNICODE_REVERSE_SIGNATURE;
1234 #endif
1235
1236 /* FIXME: Add more tests */
1237
1238 /*
1239 * Check whether the string passed all of the tests.
1240 */
1241 in_flags &= ITU_IMPLEMENTED_TESTS;
1242 if ((out_flags & in_flags) != in_flags)
1243 Length = 0;
1244
1245 done:
1246 if (Flags != 0)
1247 *Flags = out_flags;
1248
1249 return Length;
1250 }
1251
1252
1253 /*
1254 * @implemented
1255 *
1256 * NOTES
1257 * See RtlpOemStringToCountedUnicodeString
1258 */
1259 NTSTATUS
1260 STDCALL
1261 RtlOemStringToCountedUnicodeString(
1262 IN OUT PUNICODE_STRING UniDest,
1263 IN POEM_STRING OemSource,
1264 IN BOOLEAN AllocateDestinationString)
1265 {
1266 return RtlpOemStringToCountedUnicodeString(
1267 UniDest,
1268 OemSource,
1269 AllocateDestinationString,
1270 NonPagedPool);
1271 }
1272
1273
1274 /*
1275 * private
1276 *
1277 * NOTES
1278 * Same as RtlOemStringToUnicodeString but doesn't write terminating null
1279 * A partial copy is NOT performed if the dest buffer is too small!
1280 */
1281 NTSTATUS
1282 FASTCALL
1283 RtlpOemStringToCountedUnicodeString(
1284 IN OUT PUNICODE_STRING UniDest,
1285 IN POEM_STRING OemSource,
1286 IN BOOLEAN AllocateDestinationString,
1287 IN POOL_TYPE PoolType)
1288 {
1289 NTSTATUS Status;
1290 ULONG Length; //excluding nullterm
1291
1292 if (NlsMbCodePageTag == TRUE)
1293 Length = RtlOemStringToUnicodeSize(OemSource) - sizeof(WCHAR);
1294 else
1295 Length = OemSource->Length * sizeof(WCHAR);
1296
1297 if (Length > 65535)
1298 return STATUS_INVALID_PARAMETER_2;
1299
1300 if (AllocateDestinationString == TRUE)
1301 {
1302 UniDest->Buffer = ExAllocatePoolWithTag (PoolType, Length, TAG_USTR);
1303 if (UniDest->Buffer == NULL)
1304 return STATUS_NO_MEMORY;
1305
1306 UniDest->MaximumLength = Length;
1307 }
1308 else if (Length > UniDest->MaximumLength)
1309 {
1310 return STATUS_BUFFER_TOO_SMALL;
1311 }
1312
1313 UniDest->Length = Length;
1314
1315 Status = RtlOemToUnicodeN (UniDest->Buffer,
1316 UniDest->Length,
1317 NULL,
1318 OemSource->Buffer,
1319 OemSource->Length);
1320
1321 if (!NT_SUCCESS(Status) && AllocateDestinationString)
1322 {
1323 ExFreePoolWithTag(UniDest->Buffer, TAG_USTR);
1324 return Status;
1325 }
1326
1327 return Status;
1328 }
1329
1330
1331 /*
1332 * @implemented
1333 *
1334 * RETURNS
1335 * TRUE if the names are equal, FALSE if not
1336 *
1337 * NOTES
1338 * The comparison is case insensitive.
1339 */
1340 BOOLEAN
1341 STDCALL
1342 RtlEqualComputerName(
1343 IN PUNICODE_STRING ComputerName1,
1344 IN PUNICODE_STRING ComputerName2)
1345 {
1346 OEM_STRING OemString1;
1347 OEM_STRING OemString2;
1348 BOOLEAN Result = FALSE;
1349
1350 if (NT_SUCCESS(RtlUpcaseUnicodeStringToOemString( &OemString1, ComputerName1, TRUE )))
1351 {
1352 if (NT_SUCCESS(RtlUpcaseUnicodeStringToOemString( &OemString2, ComputerName2, TRUE )))
1353 {
1354 Result = RtlEqualString( &OemString1, &OemString2, TRUE );
1355 RtlFreeOemString( &OemString2 );
1356 }
1357 RtlFreeOemString( &OemString1 );
1358 }
1359
1360 return Result;
1361 }
1362
1363 /*
1364 * @implemented
1365 *
1366 * RETURNS
1367 * TRUE if the names are equal, FALSE if not
1368 *
1369 * NOTES
1370 * The comparison is case insensitive.
1371 */
1372 BOOLEAN
1373 STDCALL
1374 RtlEqualDomainName (
1375 IN PUNICODE_STRING DomainName1,
1376 IN PUNICODE_STRING DomainName2
1377 )
1378 {
1379 return RtlEqualComputerName(DomainName1, DomainName2);
1380 }
1381
1382
1383 /*
1384 * @implemented
1385 */
1386 /*
1387 BOOLEAN
1388 STDCALL
1389 RtlEqualDomainName (
1390 IN PUNICODE_STRING DomainName1,
1391 IN PUNICODE_STRING DomainName2
1392 )
1393 {
1394 OEM_STRING OemString1;
1395 OEM_STRING OemString2;
1396 BOOLEAN Result;
1397
1398 RtlUpcaseUnicodeStringToOemString (&OemString1,
1399 DomainName1,
1400 TRUE);
1401 RtlUpcaseUnicodeStringToOemString (&OemString2,
1402 DomainName2,
1403 TRUE);
1404
1405 Result = RtlEqualString (&OemString1,
1406 &OemString2,
1407 FALSE);
1408
1409 RtlFreeOemString (&OemString1);
1410 RtlFreeOemString (&OemString2);
1411
1412 return Result;
1413
1414 }
1415 */
1416
1417 /*
1418 * @implemented
1419 *
1420 * RIPPED FROM WINE's ntdll\rtlstr.c rev 1.45
1421 *
1422 * Convert a string representation of a GUID into a GUID.
1423 *
1424 * PARAMS
1425 * str [I] String representation in the format "{XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX}"
1426 * guid [O] Destination for the converted GUID
1427 *
1428 * RETURNS
1429 * Success: STATUS_SUCCESS. guid contains the converted value.
1430 * Failure: STATUS_INVALID_PARAMETER, if str is not in the expected format.
1431 *
1432 * SEE ALSO
1433 * See RtlStringFromGUID.
1434 */
1435 NTSTATUS
1436 STDCALL
1437 RtlGUIDFromString(
1438 IN UNICODE_STRING *str,
1439 OUT GUID* guid
1440 )
1441 {
1442 int i = 0;
1443 const WCHAR *lpszCLSID = str->Buffer;
1444 BYTE* lpOut = (BYTE*)guid;
1445
1446 //TRACE("(%s,%p)\n", debugstr_us(str), guid);
1447
1448 /* Convert string: {XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX}
1449 * to memory: DWORD... WORD WORD BYTES............
1450 */
1451 while (i < 37)
1452 {
1453 switch (i)
1454 {
1455 case 0:
1456 if (*lpszCLSID != '{')
1457 return STATUS_INVALID_PARAMETER;
1458 break;
1459
1460 case 9:
1461 case 14:
1462 case 19:
1463 case 24:
1464 if (*lpszCLSID != '-')
1465 return STATUS_INVALID_PARAMETER;
1466 break;
1467
1468 case 37:
1469 if (*lpszCLSID != '}')
1470 return STATUS_INVALID_PARAMETER;
1471 break;
1472
1473 default:
1474 {
1475 WCHAR ch = *lpszCLSID, ch2 = lpszCLSID[1];
1476 unsigned char byte;
1477
1478 /* Read two hex digits as a byte value */
1479 if (ch >= '0' && ch <= '9')
1480 ch = ch - '0';
1481 else if (ch >= 'a' && ch <= 'f')
1482 ch = ch - 'a' + 10;
1483 else if (ch >= 'A' && ch <= 'F')
1484 ch = ch - 'A' + 10;
1485 else
1486 return STATUS_INVALID_PARAMETER;
1487
1488 if (ch2 >= '0' && ch2 <= '9')
1489 ch2 = ch2 - '0';
1490 else if (ch2 >= 'a' && ch2 <= 'f')
1491 ch2 = ch2 - 'a' + 10;
1492 else if (ch2 >= 'A' && ch2 <= 'F')
1493 ch2 = ch2 - 'A' + 10;
1494 else
1495 return STATUS_INVALID_PARAMETER;
1496
1497 byte = ch << 4 | ch2;
1498
1499 switch (i)
1500 {
1501 #ifndef WORDS_BIGENDIAN
1502 /* For Big Endian machines, we store the data such that the
1503 * dword/word members can be read as DWORDS and WORDS correctly. */
1504 /* Dword */
1505 case 1:
1506 lpOut[3] = byte;
1507 break;
1508 case 3:
1509 lpOut[2] = byte;
1510 break;
1511 case 5:
1512 lpOut[1] = byte;
1513 break;
1514 case 7:
1515 lpOut[0] = byte;
1516 lpOut += 4;
1517 break;
1518 /* Word */
1519 case 10:
1520 case 15:
1521 lpOut[1] = byte;
1522 break;
1523 case 12:
1524 case 17:
1525 lpOut[0] = byte;
1526 lpOut += 2;
1527 break;
1528 #endif
1529 /* Byte */
1530 default:
1531 lpOut[0] = byte;
1532 lpOut++;
1533 break;
1534 }
1535 lpszCLSID++; /* Skip 2nd character of byte */
1536 i++;
1537 }
1538 }
1539 lpszCLSID++;
1540 i++;
1541 }
1542
1543 return STATUS_SUCCESS;
1544 }
1545
1546 /*
1547 * @implemented
1548 */
1549 VOID
1550 STDCALL
1551 RtlEraseUnicodeString(
1552 IN PUNICODE_STRING String)
1553 {
1554 if (String->Buffer == NULL)
1555 return;
1556
1557 if (String->MaximumLength == 0)
1558 return;
1559
1560 memset (String->Buffer,
1561 0,
1562 String->MaximumLength);
1563
1564 String->Length = 0;
1565 }
1566
1567 /*
1568 * @unimplemented
1569 */
1570 NTSTATUS
1571 STDCALL
1572 RtlHashUnicodeString(
1573 IN const UNICODE_STRING *String,
1574 IN BOOLEAN CaseInSensitive,
1575 IN ULONG HashAlgorithm,
1576 OUT PULONG HashValue
1577 )
1578 {
1579 UNIMPLEMENTED;
1580 return STATUS_NOT_IMPLEMENTED;
1581 }
1582
1583 /*
1584 * @implemented
1585 *
1586 * NOTES
1587 * See RtlpUnicodeStringToCountedOemString.
1588 */
1589 NTSTATUS
1590 STDCALL
1591 RtlUnicodeStringToCountedOemString(
1592 IN OUT POEM_STRING OemDest,
1593 IN PUNICODE_STRING UniSource,
1594 IN BOOLEAN AllocateDestinationString)
1595 {
1596 return RtlpUnicodeStringToCountedOemString(
1597 OemDest,
1598 UniSource,
1599 AllocateDestinationString,
1600 NonPagedPool);
1601 }
1602
1603 /*
1604 * private
1605 *
1606 * NOTES
1607 * Same as RtlUnicodeStringToOemString but doesn't write terminating null
1608 * Does a partial copy if the dest buffer is too small
1609 */
1610 NTSTATUS
1611 FASTCALL
1612 RtlpUnicodeStringToCountedOemString(
1613 IN OUT POEM_STRING OemDest,
1614 IN PUNICODE_STRING UniSource,
1615 IN BOOLEAN AllocateDestinationString,
1616 IN POOL_TYPE PoolType)
1617 {
1618 NTSTATUS Status;
1619 ULONG Length; //excluding nullterm
1620
1621 if (NlsMbOemCodePageTag == TRUE)
1622 Length = RtlUnicodeStringToAnsiSize(UniSource) - sizeof(CHAR);
1623 else
1624 Length = (UniSource->Length / sizeof(WCHAR));
1625
1626 if (Length > 0x0000FFFF)
1627 return STATUS_INVALID_PARAMETER_2;
1628
1629 OemDest->Length = (WORD)(Length);
1630
1631 if (AllocateDestinationString)
1632 {
1633 OemDest->Buffer = ExAllocatePoolWithTag(PoolType, Length, TAG_OSTR);
1634 if (OemDest->Buffer == NULL)
1635 return STATUS_NO_MEMORY;
1636
1637 OemDest->MaximumLength = Length;
1638 }
1639 else if (OemDest->MaximumLength == 0)
1640 {
1641 return STATUS_BUFFER_TOO_SMALL;
1642 }
1643 else if (Length > OemDest->MaximumLength)
1644 {
1645 OemDest->Length = OemDest->MaximumLength;
1646 }
1647
1648 Status = RtlUnicodeToOemN (OemDest->Buffer,
1649 OemDest->Length,
1650 NULL,
1651 UniSource->Buffer,
1652 UniSource->Length);
1653
1654 if (!NT_SUCCESS(Status) && AllocateDestinationString)
1655 {
1656 ExFreePoolWithTag(OemDest->Buffer, TAG_OSTR);
1657 }
1658
1659 return Status;
1660 }
1661
1662
1663 /*
1664 * @implemented
1665 */
1666 NTSTATUS
1667 STDCALL
1668 RtlLargeIntegerToChar(
1669 IN PLARGE_INTEGER Value,
1670 IN ULONG Base,
1671 IN ULONG Length,
1672 IN OUT PCHAR String)
1673 {
1674 ULONG Radix;
1675 CHAR temp[65];
1676 ULONGLONG v = Value->QuadPart;
1677 ULONG i;
1678 PCHAR tp;
1679 PCHAR sp;
1680
1681 Radix = Base;
1682 if (Radix == 0)
1683 Radix = 10;
1684
1685 if ((Radix != 2) && (Radix != 8) &&
1686 (Radix != 10) && (Radix != 16))
1687 return STATUS_INVALID_PARAMETER;
1688
1689 tp = temp;
1690 while (v || tp == temp)
1691 {
1692 i = v % Radix;
1693 v = v / Radix;
1694 if (i < 10)
1695 *tp = i + '0';
1696 else
1697 *tp = i + 'a' - 10;
1698 tp++;
1699 }
1700
1701 if (tp - temp >= Length)
1702 return STATUS_BUFFER_TOO_SMALL;
1703
1704 sp = String;
1705 while (tp > temp)
1706 *sp++ = *--tp;
1707 *sp = 0;
1708
1709 return STATUS_SUCCESS;
1710 }
1711
1712
1713
1714 /*
1715 * @implemented
1716 *
1717 * NOTES
1718 * See RtlpUpcaseUnicodeString
1719 */
1720 NTSTATUS
1721 STDCALL
1722 RtlUpcaseUnicodeString(
1723 IN OUT PUNICODE_STRING UniDest,
1724 IN PCUNICODE_STRING UniSource,
1725 IN BOOLEAN AllocateDestinationString)
1726 {
1727
1728 return RtlpUpcaseUnicodeString(
1729 UniDest,
1730 UniSource,
1731 AllocateDestinationString,
1732 NonPagedPool);
1733 }
1734
1735
1736 /*
1737 * private
1738 *
1739 * NOTES
1740 * dest is never '\0' terminated because it may be equal to src, and src
1741 * might not be '\0' terminated. dest->Length is only set upon success.
1742 */
1743 NTSTATUS
1744 FASTCALL
1745 RtlpUpcaseUnicodeString(
1746 IN OUT PUNICODE_STRING UniDest,
1747 IN PCUNICODE_STRING UniSource,
1748 IN BOOLEAN AllocateDestinationString,
1749 IN POOL_TYPE PoolType)
1750 {
1751 ULONG i;
1752 PWCHAR Src, Dest;
1753
1754 if (AllocateDestinationString == TRUE)
1755 {
1756 UniDest->MaximumLength = UniSource->Length;
1757 UniDest->Buffer = ExAllocatePoolWithTag(PoolType, UniDest->MaximumLength, TAG_USTR);
1758 if (UniDest->Buffer == NULL)
1759 return STATUS_NO_MEMORY;
1760 }
1761 else if (UniSource->Length > UniDest->MaximumLength)
1762 {
1763 return STATUS_BUFFER_TOO_SMALL;
1764 }
1765
1766 UniDest->Length = UniSource->Length;
1767
1768 Src = UniSource->Buffer;
1769 Dest = UniDest->Buffer;
1770 for (i = 0; i < UniSource->Length / sizeof(WCHAR); i++)
1771 {
1772 *Dest = RtlUpcaseUnicodeChar (*Src);
1773 Dest++;
1774 Src++;
1775 }
1776
1777 return STATUS_SUCCESS;
1778 }
1779
1780
1781
1782 /*
1783 * @implemented
1784 *
1785 * NOTES
1786 * See RtlpUpcaseUnicodeStringToAnsiString
1787 */
1788 NTSTATUS
1789 STDCALL
1790 RtlUpcaseUnicodeStringToAnsiString(
1791 IN OUT PANSI_STRING AnsiDest,
1792 IN PUNICODE_STRING UniSource,
1793 IN BOOLEAN AllocateDestinationString)
1794 {
1795 return RtlpUpcaseUnicodeStringToAnsiString(
1796 AnsiDest,
1797 UniSource,
1798 AllocateDestinationString,
1799 NonPagedPool);
1800 }
1801
1802 /*
1803 * private
1804 *
1805 * NOTES
1806 * This function always writes a terminating '\0'.
1807 * It performs a partial copy if ansi is too small.
1808 */
1809 NTSTATUS
1810 FASTCALL
1811 RtlpUpcaseUnicodeStringToAnsiString(
1812 IN OUT PANSI_STRING AnsiDest,
1813 IN PUNICODE_STRING UniSource,
1814 IN BOOLEAN AllocateDestinationString,
1815 IN POOL_TYPE PoolType)
1816 {
1817 NTSTATUS Status;
1818 ULONG Length; //including nullterm
1819
1820 if (NlsMbCodePageTag == TRUE)
1821 Length = RtlUnicodeStringToAnsiSize(UniSource);
1822 else
1823 Length = (UniSource->Length / sizeof(WCHAR)) + sizeof(CHAR);
1824
1825 if (Length > 0x0000FFFF)
1826 return STATUS_INVALID_PARAMETER_2;
1827
1828 AnsiDest->Length = (WORD)(Length - sizeof(CHAR));
1829
1830 if (AllocateDestinationString)
1831 {
1832 AnsiDest->Buffer = ExAllocatePoolWithTag(PoolType, Length, TAG_ASTR);
1833 if (AnsiDest->Buffer == NULL)
1834 return STATUS_NO_MEMORY;
1835
1836 AnsiDest->MaximumLength = Length;
1837 }
1838 else if (AnsiDest->MaximumLength == 0)
1839 {
1840 return STATUS_BUFFER_TOO_SMALL;
1841 }
1842 else if (Length > AnsiDest->MaximumLength)
1843 {
1844 //make room for nullterm
1845 AnsiDest->Length = AnsiDest->MaximumLength - sizeof(CHAR);
1846 }
1847
1848 //FIXME: do we need this??????? -Gunnar
1849 RtlZeroMemory (AnsiDest->Buffer,
1850 AnsiDest->Length);
1851
1852 Status = RtlUpcaseUnicodeToMultiByteN (AnsiDest->Buffer,
1853 AnsiDest->Length,
1854 NULL,
1855 UniSource->Buffer,
1856 UniSource->Length);
1857
1858 if (!NT_SUCCESS(Status) && AllocateDestinationString)
1859 {
1860 ExFreePoolWithTag(AnsiDest->Buffer, TAG_ASTR);
1861 return Status;
1862 }
1863
1864 AnsiDest->Buffer[AnsiDest->Length] = 0;
1865 return Status;
1866 }
1867
1868
1869
1870 /*
1871 * @implemented
1872 *
1873 * NOTES
1874 * See RtlpUpcaseUnicodeStringToCountedOemString
1875 */
1876 NTSTATUS
1877 STDCALL
1878 RtlUpcaseUnicodeStringToCountedOemString(
1879 IN OUT POEM_STRING OemDest,
1880 IN PUNICODE_STRING UniSource,
1881 IN BOOLEAN AllocateDestinationString)
1882 {
1883 return RtlpUpcaseUnicodeStringToCountedOemString(
1884 OemDest,
1885 UniSource,
1886 AllocateDestinationString,
1887 NonPagedPool);
1888 }
1889
1890
1891
1892 /*
1893 * private
1894 *
1895 * NOTES
1896 * Same as RtlUpcaseUnicodeStringToOemString but doesn't write terminating null
1897 * It performs a partial copy if oem is too small.
1898 */
1899 NTSTATUS
1900 FASTCALL
1901 RtlpUpcaseUnicodeStringToCountedOemString(
1902 IN OUT POEM_STRING OemDest,
1903 IN PUNICODE_STRING UniSource,
1904 IN BOOLEAN AllocateDestinationString,
1905 IN POOL_TYPE PoolType)
1906 {
1907 NTSTATUS Status;
1908 ULONG Length; //excluding nullterm
1909
1910 if (NlsMbCodePageTag == TRUE)
1911 Length = RtlUnicodeStringToAnsiSize(UniSource) - sizeof(CHAR);
1912 else
1913 Length = UniSource->Length / sizeof(WCHAR);
1914
1915 if (Length > 0x0000FFFF)
1916 return(STATUS_INVALID_PARAMETER_2);
1917
1918 OemDest->Length = (WORD)(Length);
1919
1920 if (AllocateDestinationString)
1921 {
1922 OemDest->Buffer = ExAllocatePoolWithTag(PoolType, Length, TAG_OSTR);
1923 if (OemDest->Buffer == NULL)
1924 return(STATUS_NO_MEMORY);
1925
1926 //FIXME: Do we need this?????
1927 RtlZeroMemory (OemDest->Buffer, Length);
1928
1929 OemDest->MaximumLength = (WORD)Length;
1930 }
1931 else if (OemDest->MaximumLength == 0)
1932 {
1933 return(STATUS_BUFFER_TOO_SMALL);
1934 }
1935 else if (Length > OemDest->MaximumLength)
1936 {
1937 OemDest->Length = OemDest->MaximumLength;
1938 }
1939
1940 Status = RtlUpcaseUnicodeToOemN(OemDest->Buffer,
1941 OemDest->Length,
1942 NULL,
1943 UniSource->Buffer,
1944 UniSource->Length);
1945
1946 if (!NT_SUCCESS(Status) && AllocateDestinationString)
1947 {
1948 ExFreePoolWithTag(OemDest->Buffer, TAG_OSTR);
1949 return Status;
1950 }
1951
1952 return Status;
1953 }
1954
1955
1956 /*
1957 * @implemented
1958 * NOTES
1959 * See RtlpUpcaseUnicodeStringToOemString
1960 */
1961 NTSTATUS
1962 STDCALL
1963 RtlUpcaseUnicodeStringToOemString (
1964 IN OUT POEM_STRING OemDest,
1965 IN PUNICODE_STRING UniSource,
1966 IN BOOLEAN AllocateDestinationString
1967 )
1968 {
1969 return RtlpUpcaseUnicodeStringToOemString(
1970 OemDest,
1971 UniSource,
1972 AllocateDestinationString,
1973 NonPagedPool);
1974 }
1975
1976
1977 /*
1978 * private
1979 *
1980 * NOTES
1981 * Oem string is allways nullterminated
1982 * It performs a partial copy if oem is too small.
1983 */
1984 NTSTATUS
1985 FASTCALL
1986 RtlpUpcaseUnicodeStringToOemString (
1987 IN OUT POEM_STRING OemDest,
1988 IN PUNICODE_STRING UniSource,
1989 IN BOOLEAN AllocateDestinationString,
1990 IN POOL_TYPE PoolType
1991 )
1992 {
1993 NTSTATUS Status;
1994 ULONG Length; //including nullterm
1995
1996 if (NlsMbOemCodePageTag == TRUE)
1997 Length = RtlUnicodeStringToAnsiSize(UniSource);
1998 else
1999 Length = (UniSource->Length / sizeof(WCHAR)) + sizeof(CHAR);
2000
2001 if (Length > 0x0000FFFF)
2002 return STATUS_INVALID_PARAMETER_2;
2003
2004 OemDest->Length = (WORD)(Length - sizeof(CHAR));
2005
2006 if (AllocateDestinationString)
2007 {
2008 OemDest->Buffer = ExAllocatePoolWithTag(PoolType, Length, TAG_OSTR);
2009 if (OemDest->Buffer == NULL)
2010 return STATUS_NO_MEMORY;
2011
2012 //FIXME: Do we need this????
2013 RtlZeroMemory (OemDest->Buffer, Length);
2014
2015 OemDest->MaximumLength = (WORD)Length;
2016 }
2017 else if (OemDest->MaximumLength == 0)
2018 {
2019 return STATUS_BUFFER_OVERFLOW;
2020 }
2021 else if (Length > OemDest->MaximumLength)
2022 {
2023 //make room for nullterm
2024 OemDest->Length = OemDest->MaximumLength - sizeof(CHAR);
2025 }
2026
2027 Status = RtlUpcaseUnicodeToOemN (OemDest->Buffer,
2028 OemDest->Length,
2029 NULL,
2030 UniSource->Buffer,
2031 UniSource->Length);
2032
2033 if (!NT_SUCCESS(Status) && AllocateDestinationString)
2034 {
2035 ExFreePoolWithTag(OemDest->Buffer, TAG_OSTR);
2036 return Status;
2037 }
2038
2039 OemDest->Buffer[OemDest->Length] = 0;
2040 return Status;
2041 }
2042
2043
2044 /*
2045 * @implemented
2046 *
2047 * RETURNS
2048 * Bytes calculated including nullterm
2049 */
2050 ULONG
2051 STDCALL
2052 RtlOemStringToUnicodeSize(IN POEM_STRING OemString)
2053 {
2054 ULONG Size;
2055
2056 //this function returns size including nullterm
2057 RtlMultiByteToUnicodeSize(&Size,
2058 OemString->Buffer,
2059 OemString->Length);
2060
2061 return(Size);
2062 }
2063
2064
2065
2066 /*
2067 * @implemented
2068 */
2069 NTSTATUS
2070 STDCALL
2071 RtlStringFromGUID (IN REFGUID Guid,
2072 OUT PUNICODE_STRING GuidString)
2073 {
2074 STATIC CONST PWCHAR Hex = L"0123456789ABCDEF";
2075 WCHAR Buffer[40];
2076 PWCHAR BufferPtr;
2077 ULONG i;
2078
2079 if (Guid == NULL)
2080 {
2081 return STATUS_INVALID_PARAMETER;
2082 }
2083
2084 swprintf (Buffer,
2085 L"{%08lX-%04X-%04X-%02X%02X-",
2086 Guid->Data1,
2087 Guid->Data2,
2088 Guid->Data3,
2089 Guid->Data4[0],
2090 Guid->Data4[1]);
2091 BufferPtr = Buffer + 25;
2092
2093 /* 6 hex bytes */
2094 for (i = 2; i < 8; i++)
2095 {
2096 *BufferPtr++ = Hex[Guid->Data4[i] >> 4];
2097 *BufferPtr++ = Hex[Guid->Data4[i] & 0xf];
2098 }
2099
2100 *BufferPtr++ = L'}';
2101 *BufferPtr++ = L'\0';
2102
2103 return RtlCreateUnicodeString (GuidString, Buffer);
2104 }
2105
2106
2107 /*
2108 * @implemented
2109 *
2110 * RETURNS
2111 * Bytes calculated including nullterm
2112 */
2113 ULONG
2114 STDCALL
2115 RtlUnicodeStringToAnsiSize(
2116 IN PUNICODE_STRING UnicodeString)
2117 {
2118 ULONG Size;
2119
2120 //this function return size without nullterm!
2121 RtlUnicodeToMultiByteSize (&Size,
2122 UnicodeString->Buffer,
2123 UnicodeString->Length);
2124
2125 return Size + sizeof(CHAR); //NB: incl. nullterm
2126 }
2127
2128
2129
2130
2131 /*
2132 * @implemented
2133 */
2134 LONG
2135 STDCALL
2136 RtlCompareUnicodeString(
2137 IN PUNICODE_STRING String1,
2138 IN PUNICODE_STRING String2,
2139 IN BOOLEAN CaseInsensitive)
2140 {
2141 ULONG len1, len2;
2142 PWCHAR s1, s2;
2143 WCHAR c1, c2;
2144
2145 if (String1 && String2)
2146 {
2147 len1 = String1->Length / sizeof(WCHAR);
2148 len2 = String2->Length / sizeof(WCHAR);
2149 s1 = String1->Buffer;
2150 s2 = String2->Buffer;
2151
2152 if (s1 && s2)
2153 {
2154 if (CaseInsensitive)
2155 {
2156 while (1)
2157 {
2158 c1 = len1-- ? RtlUpcaseUnicodeChar (*s1++) : 0;
2159 c2 = len2-- ? RtlUpcaseUnicodeChar (*s2++) : 0;
2160 if (!c1 || !c2 || c1 != c2)
2161 return c1 - c2;
2162 }
2163 }
2164 else
2165 {
2166 while (1)
2167 {
2168 c1 = len1-- ? *s1++ : 0;
2169 c2 = len2-- ? *s2++ : 0;
2170 if (!c1 || !c2 || c1 != c2)
2171 return c1 - c2;
2172 }
2173 }
2174 }
2175 }
2176
2177 return 0;
2178 }
2179
2180
2181 /*
2182 * @implemented
2183 */
2184 VOID
2185 STDCALL
2186 RtlCopyString(
2187 IN OUT PSTRING DestinationString,
2188 IN PSTRING SourceString)
2189 {
2190 ULONG copylen;
2191
2192 if(SourceString == NULL)
2193 {
2194 DestinationString->Length = 0;
2195 return;
2196 }
2197
2198 copylen = min (DestinationString->MaximumLength,
2199 SourceString->Length);
2200
2201 memcpy(DestinationString->Buffer, SourceString->Buffer, copylen);
2202 if (DestinationString->MaximumLength >= copylen + sizeof(CHAR))
2203 {
2204 DestinationString->Buffer[copylen] = 0;
2205 }
2206 DestinationString->Length = copylen;
2207 }
2208
2209
2210
2211 /*
2212 * @implemented
2213 */
2214 VOID
2215 STDCALL
2216 RtlCopyUnicodeString(
2217 IN OUT PUNICODE_STRING DestinationString,
2218 IN PUNICODE_STRING SourceString)
2219 {
2220 ULONG copylen;
2221
2222 if (SourceString == NULL)
2223 {
2224 DestinationString->Length = 0;
2225 return;
2226 }
2227
2228 copylen = min (DestinationString->MaximumLength,
2229 SourceString->Length);
2230 memcpy(DestinationString->Buffer, SourceString->Buffer, copylen);
2231 if (DestinationString->MaximumLength >= copylen + sizeof(WCHAR))
2232 {
2233 DestinationString->Buffer[copylen / sizeof(WCHAR)] = 0;
2234 }
2235 DestinationString->Length = copylen;
2236 }
2237
2238
2239 /*
2240 * @implemented
2241 *
2242 * NOTES
2243 * See RtlpCreateUnicodeString
2244 */
2245 BOOLEAN
2246 STDCALL
2247 RtlCreateUnicodeString(
2248 IN OUT PUNICODE_STRING UniDest,
2249 IN PCWSTR Source)
2250 {
2251
2252 DPRINT("RtlCreateUnicodeString\n");
2253 return RtlpCreateUnicodeString(UniDest, Source, NonPagedPool);
2254 }
2255
2256
2257 /*
2258 * private
2259 *
2260 * Creates a nullterminated UNICODE_STRING
2261 */
2262 BOOLEAN
2263 FASTCALL
2264 RtlpCreateUnicodeString(
2265 IN OUT PUNICODE_STRING UniDest,
2266 IN PCWSTR Source,
2267 IN POOL_TYPE PoolType)
2268 {
2269 ULONG Length;
2270
2271 Length = (wcslen (Source) + 1) * sizeof(WCHAR);
2272
2273 UniDest->Buffer = ExAllocatePoolWithTag(PoolType, Length, TAG_USTR);
2274 if (UniDest->Buffer == NULL)
2275 return FALSE;
2276
2277 memmove (UniDest->Buffer,
2278 Source,
2279 Length);
2280
2281 UniDest->MaximumLength = Length;
2282 UniDest->Length = Length - sizeof (WCHAR);
2283
2284 return TRUE;
2285 }
2286
2287
2288
2289 /*
2290 * @implemented
2291 */
2292 BOOLEAN
2293 STDCALL
2294 RtlCreateUnicodeStringFromAsciiz(
2295 OUT PUNICODE_STRING Destination,
2296 IN PCSZ Source)
2297 {
2298 ANSI_STRING AnsiString;
2299 NTSTATUS Status;
2300
2301 RtlInitAnsiString (&AnsiString,
2302 Source);
2303
2304 Status = RtlAnsiStringToUnicodeString (Destination,
2305 &AnsiString,
2306 TRUE);
2307
2308 return NT_SUCCESS(Status);
2309 }
2310
2311
2312
2313 /*
2314 * @implemented
2315 *
2316 * NOTES
2317 * See RtlpDowncaseUnicodeString
2318 */
2319 NTSTATUS STDCALL
2320 RtlDowncaseUnicodeString(
2321 IN OUT PUNICODE_STRING UniDest,
2322 IN PUNICODE_STRING UniSource,
2323 IN BOOLEAN AllocateDestinationString)
2324 {
2325 return RtlpDowncaseUnicodeString(
2326 UniDest,
2327 UniSource,
2328 AllocateDestinationString,
2329 NonPagedPool);
2330 }
2331
2332
2333 /*
2334 * private
2335 *
2336 * NOTES
2337 * Dest is never '\0' terminated because it may be equal to src, and src
2338 * might not be '\0' terminated.
2339 * Dest->Length is only set upon success.
2340 */
2341 NTSTATUS
2342 FASTCALL
2343 RtlpDowncaseUnicodeString(
2344 IN OUT PUNICODE_STRING UniDest,
2345 IN PUNICODE_STRING UniSource,
2346 IN BOOLEAN AllocateDestinationString,
2347 IN POOL_TYPE PoolType)
2348 {
2349 ULONG i;
2350 PWCHAR Src, Dest;
2351
2352 if (AllocateDestinationString)
2353 {
2354 UniDest->Buffer = ExAllocatePoolWithTag(PoolType, UniSource->Length, TAG_USTR);
2355 if (UniDest->Buffer == NULL)
2356 return STATUS_NO_MEMORY;
2357
2358 UniDest->MaximumLength = UniSource->Length;
2359 }
2360 else if (UniSource->Length > UniDest->MaximumLength)
2361 {
2362 return STATUS_BUFFER_TOO_SMALL;
2363 }
2364
2365 UniDest->Length = UniSource->Length;
2366
2367 Src = UniSource->Buffer;
2368 Dest = UniDest->Buffer;
2369 for (i=0; i < UniSource->Length / sizeof(WCHAR); i++)
2370 {
2371 if (*Src < L'A')
2372 {
2373 *Dest = *Src;
2374 }
2375 else if (*Src <= L'Z')
2376 {
2377 *Dest = (*Src + (L'a' - L'A'));
2378 }
2379 else
2380 {
2381 *Dest = RtlDowncaseUnicodeChar(*Src);
2382 }
2383
2384 Dest++;
2385 Src++;
2386 }
2387
2388 return STATUS_SUCCESS;
2389 }
2390
2391
2392
2393 /*
2394 * @implemented
2395 *
2396 * NOTES
2397 * if src is NULL dest is unchanged.
2398 * dest is '\0' terminated when the MaximumLength allowes it.
2399 * When dest fits exactly in MaximumLength characters the '\0' is ommitted.
2400 */
2401 NTSTATUS STDCALL
2402 RtlAppendUnicodeToString(IN OUT PUNICODE_STRING Destination,
2403 IN PCWSTR Source)
2404 {
2405 ULONG slen;
2406
2407 slen = wcslen(Source) * sizeof(WCHAR);
2408
2409 if (Destination->Length + slen > Destination->MaximumLength)
2410 return(STATUS_BUFFER_TOO_SMALL);
2411
2412 memcpy((char*)Destination->Buffer + Destination->Length, Source, slen);
2413 Destination->Length += slen;
2414 /* append terminating '\0' if enough space */
2415 if( Destination->MaximumLength > Destination->Length )
2416 Destination->Buffer[Destination->Length / sizeof(WCHAR)] = 0;
2417
2418 return(STATUS_SUCCESS);
2419 }
2420
2421
2422 /*
2423 * @implemented
2424 *
2425 * NOTES
2426 * See RtlpAnsiStringToUnicodeString
2427 */
2428 NTSTATUS
2429 STDCALL
2430 RtlAnsiStringToUnicodeString(
2431 IN OUT PUNICODE_STRING UniDest,
2432 IN PANSI_STRING AnsiSource,
2433 IN BOOLEAN AllocateDestinationString)
2434 {
2435 return RtlpAnsiStringToUnicodeString(
2436 UniDest,
2437 AnsiSource,
2438 AllocateDestinationString,
2439 NonPagedPool);
2440 }
2441
2442
2443
2444 /*
2445 * private
2446 *
2447 * NOTES
2448 * This function always writes a terminating '\0'.
2449 * If the dest buffer is too small a partial copy is NOT performed!
2450 */
2451 NTSTATUS
2452 FASTCALL
2453 RtlpAnsiStringToUnicodeString(
2454 IN OUT PUNICODE_STRING UniDest,
2455 IN PANSI_STRING AnsiSource,
2456 IN BOOLEAN AllocateDestinationString,
2457 IN POOL_TYPE PoolType)
2458 {
2459 NTSTATUS Status;
2460 ULONG Length; //including nullterm
2461
2462 if (NlsMbCodePageTag == TRUE)
2463 Length = RtlAnsiStringToUnicodeSize(AnsiSource);
2464 else
2465 Length = (AnsiSource->Length * sizeof(WCHAR)) + sizeof(WCHAR);
2466
2467 if (Length > 0xffff)
2468 return STATUS_INVALID_PARAMETER_2;
2469
2470 if (AllocateDestinationString == TRUE)
2471 {
2472 UniDest->Buffer = ExAllocatePoolWithTag(PoolType, Length, TAG_USTR);
2473 if (UniDest->Buffer == NULL)
2474 return STATUS_NO_MEMORY;
2475
2476 UniDest->MaximumLength = Length;
2477 }
2478 else if (Length > UniDest->MaximumLength)
2479 {
2480 DPRINT("STATUS_BUFFER_TOO_SMALL\n");
2481 return STATUS_BUFFER_TOO_SMALL;
2482 }
2483
2484 UniDest->Length = Length - sizeof(WCHAR);
2485
2486 //FIXME: We don't need this??? -Gunnar
2487 RtlZeroMemory (UniDest->Buffer,
2488 UniDest->Length);
2489
2490 Status = RtlMultiByteToUnicodeN (UniDest->Buffer,
2491 UniDest->Length,
2492 NULL,
2493 AnsiSource->Buffer,
2494 AnsiSource->Length);
2495
2496 if (!NT_SUCCESS(Status) && AllocateDestinationString)
2497 {
2498 ExFreePoolWithTag(UniDest->Buffer, TAG_USTR);
2499 return Status;
2500 }
2501
2502 UniDest->Buffer[UniDest->Length / sizeof(WCHAR)] = 0;
2503 return Status;
2504 }
2505
2506
2507
2508 /*
2509 * @implemented
2510 *
2511 * NOTES
2512 * if src is NULL dest is unchanged.
2513 * dest is never '\0' terminated.
2514 */
2515 NTSTATUS
2516 STDCALL
2517 RtlAppendAsciizToString(
2518 IN OUT PSTRING Destination,
2519 IN PCSZ Source)
2520 {
2521 ULONG Length;
2522 PCHAR Ptr;
2523
2524 if (Source == NULL)
2525 return STATUS_SUCCESS;
2526
2527 Length = strlen (Source);
2528 if (Destination->Length + Length >= Destination->MaximumLength)
2529 return STATUS_BUFFER_TOO_SMALL;
2530
2531 Ptr = Destination->Buffer + Destination->Length;
2532 memmove (Ptr,
2533 Source,
2534 Length);
2535 Ptr += Length;
2536 *Ptr = 0;
2537
2538 Destination->Length += Length;
2539
2540 return STATUS_SUCCESS;
2541 }
2542
2543
2544 /*
2545 * @implemented
2546 */
2547 VOID STDCALL
2548 RtlUpperString(PSTRING DestinationString,
2549 PSTRING SourceString)
2550 {
2551 ULONG Length;
2552 ULONG i;
2553 PCHAR Src;
2554 PCHAR Dest;
2555
2556 Length = min(SourceString->Length,
2557 DestinationString->MaximumLength - 1);
2558
2559 Src = SourceString->Buffer;
2560 Dest = DestinationString->Buffer;
2561 for (i = 0; i < Length; i++)
2562 {
2563 *Dest = RtlUpperChar(*Src);
2564 Src++;
2565 Dest++;
2566 }
2567 *Dest = 0;
2568
2569 DestinationString->Length = SourceString->Length;
2570 }
2571
2572
2573 /*
2574 * @implemented
2575 */
2576 ULONG STDCALL
2577 RtlxAnsiStringToUnicodeSize(IN PANSI_STRING AnsiString)
2578 {
2579 return RtlAnsiStringToUnicodeSize(AnsiString);
2580 }
2581
2582
2583 /*
2584 * @implemented
2585 */
2586 ULONG STDCALL
2587 RtlxOemStringToUnicodeSize(IN POEM_STRING OemString)
2588 {
2589 return RtlOemStringToUnicodeSize((PANSI_STRING)OemString);
2590 }
2591
2592
2593
2594 /*
2595 * @implemented
2596 */
2597 ULONG STDCALL
2598 RtlxUnicodeStringToAnsiSize(IN PUNICODE_STRING UnicodeString)
2599 {
2600 return RtlUnicodeStringToAnsiSize(UnicodeString);
2601 }
2602
2603
2604 /*
2605 * @implemented
2606 */
2607 ULONG STDCALL
2608 RtlxUnicodeStringToOemSize(IN PUNICODE_STRING UnicodeString)
2609 {
2610 return RtlUnicodeStringToOemSize(UnicodeString);
2611 }
2612
2613
2614 /*
2615 * @implemented
2616 *
2617 * NOTES
2618 * See RtlpDuplicateUnicodeString
2619 */
2620 NTSTATUS STDCALL
2621 RtlDuplicateUnicodeString(
2622 INT AddNull,
2623 IN PUNICODE_STRING SourceString,
2624 PUNICODE_STRING DestinationString)
2625 {
2626 return RtlpDuplicateUnicodeString(
2627 AddNull,
2628 SourceString,
2629 DestinationString,
2630 NonPagedPool);
2631 }
2632
2633
2634 /*
2635 * @implemented
2636 */
2637 NTSTATUS STDCALL
2638 RtlpDuplicateUnicodeString(
2639 INT AddNull,
2640 IN PUNICODE_STRING SourceString,
2641 PUNICODE_STRING DestinationString,
2642 POOL_TYPE PoolType)
2643 {
2644 if (SourceString == NULL || DestinationString == NULL)
2645 return STATUS_INVALID_PARAMETER;
2646
2647
2648 if (SourceString->Length == 0 && AddNull != 3)
2649 {
2650 DestinationString->Length = 0;
2651 DestinationString->MaximumLength = 0;
2652 DestinationString->Buffer = NULL;
2653 }
2654 else
2655 {
2656 unsigned int DestMaxLength = SourceString->Length;
2657
2658 if (AddNull)
2659 DestMaxLength += sizeof(UNICODE_NULL);
2660
2661 DestinationString->Buffer = ExAllocatePool(PoolType, DestMaxLength);
2662 if (DestinationString->Buffer == NULL)
2663 return STATUS_NO_MEMORY;
2664
2665 RtlCopyMemory(DestinationString->Buffer, SourceString->Buffer, SourceString->Length);
2666 DestinationString->Length = SourceString->Length;
2667 DestinationString->MaximumLength = DestMaxLength;
2668
2669 if (AddNull)
2670 DestinationString->Buffer[DestinationString->Length / sizeof(WCHAR)] = 0;
2671 }
2672
2673 return STATUS_SUCCESS;
2674 }
2675
2676
2677 /*
2678 * @implemented
2679 */
2680 NTSTATUS STDCALL
2681 RtlValidateUnicodeString(IN ULONG Flags,
2682 IN PUNICODE_STRING UnicodeString)
2683 {
2684 /* currently no flags are supported! */
2685 ASSERT(Flags == 0);
2686
2687 if ((Flags == 0) &&
2688 ((UnicodeString == NULL) ||
2689 ((UnicodeString->Length != 0) &&
2690 (UnicodeString->Buffer != NULL) &&
2691 ((UnicodeString->Length % sizeof(WCHAR)) == 0) &&
2692 ((UnicodeString->MaximumLength % sizeof(WCHAR)) == 0) &&
2693 (UnicodeString->MaximumLength >= UnicodeString->Length))))
2694 {
2695 /* a NULL pointer as a unicode string is considered to be a valid unicode
2696 string! */
2697 return STATUS_SUCCESS;
2698 }
2699 else
2700 {
2701 return STATUS_INVALID_PARAMETER;
2702 }
2703 }
2704
2705 /* EOF */