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