Correct some checks, fix bug 748 (qemu networking). Fix by his vaingloriousness Alex...
[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 = 0;
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 && newbase == 0) {
915 base = 10;
916 } else if (base == 0 && newbase != 0) {
917 base = newbase;
918 } else if ((newbase != 0 && base != newbase) ||
919 (base != 2 && base != 8 && base != 10 && base != 16)) {
920 return STATUS_INVALID_PARAMETER;
921
922 } /* if */
923
924 if (value == NULL) {
925 return STATUS_ACCESS_VIOLATION;
926 } /* if */
927
928 while (CharsRemaining >= 1) {
929 wchCurrent = *lpwstr;
930 if (wchCurrent >= L'0' && wchCurrent <= L'9') {
931 digit = wchCurrent - L'0';
932 } else if (wchCurrent >= L'A' && wchCurrent <= L'Z') {
933 digit = wchCurrent - L'A' + 10;
934 } else if (wchCurrent >= L'a' && wchCurrent <= L'z') {
935 digit = wchCurrent - L'a' + 10;
936 } else {
937 digit = -1;
938 } /* if */
939 if (digit < 0 || digit >= (int)base) {
940 *value = bMinus ? -RunningTotal : RunningTotal;
941 return STATUS_SUCCESS;
942 } /* if */
943
944 RunningTotal = RunningTotal * base + digit;
945 lpwstr++;
946 CharsRemaining--;
947 } /* while */
948
949 *value = bMinus ? -RunningTotal : RunningTotal;
950 return STATUS_SUCCESS;
951 }
952
953
954 /*
955 * @implemented
956 *
957 * RETURNS
958 * Bytes necessary for the conversion including nullterm.
959 */
960 ULONG
961 STDCALL
962 RtlUnicodeStringToOemSize(
963 IN PUNICODE_STRING UnicodeString)
964 {
965 ULONG Size;
966
967 RtlUnicodeToMultiByteSize (&Size,
968 UnicodeString->Buffer,
969 UnicodeString->Length);
970
971 return Size+1; //NB: incl. nullterm
972 }
973
974 /*
975 * @implemented
976 *
977
978 * NOTES
979 * This function always writes a terminating '\0'.
980 * It performs a partial copy if ansi is too small.
981 */
982 NTSTATUS
983 STDCALL
984 RtlUnicodeStringToAnsiString(
985 IN OUT PANSI_STRING AnsiDest,
986 IN PUNICODE_STRING UniSource,
987 IN BOOLEAN AllocateDestinationString)
988 {
989 NTSTATUS Status = STATUS_SUCCESS;
990 ULONG Length; /* including nullterm */
991
992 if (NlsMbCodePageTag == TRUE)
993 {
994 Length = RtlUnicodeStringToAnsiSize(UniSource);
995 }
996 else
997 Length = (UniSource->Length / sizeof(WCHAR)) + sizeof(CHAR);
998
999 AnsiDest->Length = Length - sizeof(CHAR);
1000
1001 if (AllocateDestinationString)
1002 {
1003 AnsiDest->Buffer = RtlpAllocateStringMemory(Length, TAG_ASTR);
1004 if (AnsiDest->Buffer == NULL)
1005 return STATUS_NO_MEMORY;
1006
1007 AnsiDest->MaximumLength = Length;
1008 }
1009 else if (AnsiDest->MaximumLength == 0)
1010 {
1011 return STATUS_BUFFER_TOO_SMALL;
1012 }
1013 else if (Length > AnsiDest->MaximumLength)
1014 {
1015 /* make room for nullterm */
1016 AnsiDest->Length = AnsiDest->MaximumLength - sizeof(CHAR);
1017 }
1018
1019 Status = RtlUnicodeToMultiByteN (AnsiDest->Buffer,
1020 AnsiDest->Length,
1021 NULL,
1022 UniSource->Buffer,
1023 UniSource->Length);
1024
1025 if (!NT_SUCCESS(Status) && AllocateDestinationString)
1026 {
1027 RtlpFreeStringMemory(AnsiDest->Buffer, TAG_ASTR);
1028 return Status;
1029 }
1030
1031 AnsiDest->Buffer[AnsiDest->Length] = 0;
1032 return Status;
1033 }
1034
1035
1036 /*
1037 * @implemented
1038 *
1039 * NOTES
1040 * This function always writes a terminating '\0'.
1041 * Does NOT perform a partial copy if unicode is too small!
1042 */
1043 NTSTATUS
1044 STDCALL
1045 RtlOemStringToUnicodeString(
1046 IN OUT PUNICODE_STRING UniDest,
1047 IN POEM_STRING OemSource,
1048 IN BOOLEAN AllocateDestinationString)
1049 {
1050 NTSTATUS Status;
1051 ULONG Length; /* including nullterm */
1052
1053 if (NlsMbOemCodePageTag == TRUE)
1054 Length = RtlOemStringToUnicodeSize(OemSource);
1055 else
1056 Length = (OemSource->Length * sizeof(WCHAR)) + sizeof(WCHAR);
1057
1058 if (Length > 0xffff)
1059 return STATUS_INVALID_PARAMETER_2;
1060
1061 UniDest->Length = (WORD)(Length - sizeof(WCHAR));
1062
1063 if (AllocateDestinationString)
1064 {
1065 UniDest->Buffer = RtlpAllocateStringMemory(Length, TAG_USTR);
1066 if (UniDest->Buffer == NULL)
1067 return STATUS_NO_MEMORY;
1068
1069 UniDest->MaximumLength = Length;
1070 }
1071 else if (Length > UniDest->MaximumLength)
1072 {
1073 DPRINT("STATUS_BUFFER_TOO_SMALL\n");
1074 return STATUS_BUFFER_TOO_SMALL;
1075 }
1076
1077 /* FIXME: Do we need this????? -Gunnar */
1078 RtlZeroMemory (UniDest->Buffer,
1079 UniDest->Length);
1080
1081 Status = RtlOemToUnicodeN (UniDest->Buffer,
1082 UniDest->Length,
1083 NULL,
1084 OemSource->Buffer,
1085 OemSource->Length);
1086
1087 if (!NT_SUCCESS(Status) && AllocateDestinationString)
1088 {
1089 RtlpFreeStringMemory(UniDest->Buffer, TAG_USTR);
1090 return Status;
1091 }
1092
1093 UniDest->Buffer[UniDest->Length / sizeof(WCHAR)] = 0;
1094 return STATUS_SUCCESS;
1095 }
1096
1097
1098 /*
1099 * @implemented
1100 *
1101 * NOTES
1102 * This function always '\0' terminates the string returned.
1103 */
1104 NTSTATUS
1105 STDCALL
1106 RtlUnicodeStringToOemString(
1107 IN OUT POEM_STRING OemDest,
1108 IN PUNICODE_STRING UniSource,
1109 IN BOOLEAN AllocateDestinationString)
1110 {
1111 NTSTATUS Status = STATUS_SUCCESS;
1112 ULONG Length; //including nullterm
1113
1114 if (NlsMbOemCodePageTag == TRUE)
1115 Length = RtlUnicodeStringToAnsiSize (UniSource);
1116 else
1117 Length = (UniSource->Length / sizeof(WCHAR)) + sizeof(CHAR);
1118
1119 if (Length > 0x0000FFFF)
1120 return STATUS_INVALID_PARAMETER_2;
1121
1122 OemDest->Length = (WORD)(Length - sizeof(CHAR));
1123
1124 if (AllocateDestinationString)
1125 {
1126 OemDest->Buffer = RtlpAllocateStringMemory(Length, TAG_OSTR);
1127 if (OemDest->Buffer == NULL)
1128 return STATUS_NO_MEMORY;
1129
1130 OemDest->MaximumLength = Length;
1131 }
1132 else if (OemDest->MaximumLength == 0)
1133 {
1134 return STATUS_BUFFER_TOO_SMALL;
1135 }
1136 else if (Length > OemDest->MaximumLength)
1137 {
1138 //make room for nullterm
1139 OemDest->Length = OemDest->MaximumLength - sizeof(CHAR);
1140 }
1141
1142 Status = RtlUnicodeToOemN (OemDest->Buffer,
1143 OemDest->Length,
1144 NULL,
1145 UniSource->Buffer,
1146 UniSource->Length);
1147
1148 if (!NT_SUCCESS(Status) && AllocateDestinationString)
1149 {
1150 RtlpFreeStringMemory(OemDest->Buffer, TAG_OSTR);
1151 return Status;
1152 }
1153
1154 OemDest->Buffer[OemDest->Length] = 0;
1155 return Status;
1156 }
1157
1158 #define ITU_IMPLEMENTED_TESTS (IS_TEXT_UNICODE_ODD_LENGTH|IS_TEXT_UNICODE_SIGNATURE)
1159
1160
1161 /*
1162 * @implemented
1163 *
1164 * RETURNS
1165 * The length of the string if all tests were passed, 0 otherwise.
1166 */
1167 ULONG STDCALL
1168 RtlIsTextUnicode (PVOID Buffer,
1169 ULONG Length,
1170 ULONG *Flags)
1171 {
1172 PWSTR s = Buffer;
1173 ULONG in_flags = (ULONG)-1;
1174 ULONG out_flags = 0;
1175
1176 if (Length == 0)
1177 goto done;
1178
1179 if (Flags != 0)
1180 in_flags = *Flags;
1181
1182 /*
1183 * Apply various tests to the text string. According to the
1184 * docs, each test "passed" sets the corresponding flag in
1185 * the output flags. But some of the tests are mutually
1186 * exclusive, so I don't see how you could pass all tests ...
1187 */
1188
1189 /* Check for an odd length ... pass if even. */
1190 if (!(Length & 1))
1191 out_flags |= IS_TEXT_UNICODE_ODD_LENGTH;
1192
1193 /* Check for the BOM (byte order mark). */
1194 if (*s == 0xFEFF)
1195 out_flags |= IS_TEXT_UNICODE_SIGNATURE;
1196
1197 #if 0
1198 /* Check for the reverse BOM (byte order mark). */
1199 if (*s == 0xFFFE)
1200 out_flags |= IS_TEXT_UNICODE_REVERSE_SIGNATURE;
1201 #endif
1202
1203 /* FIXME: Add more tests */
1204
1205 /*
1206 * Check whether the string passed all of the tests.
1207 */
1208 in_flags &= ITU_IMPLEMENTED_TESTS;
1209 if ((out_flags & in_flags) != in_flags)
1210 Length = 0;
1211
1212 done:
1213 if (Flags != 0)
1214 *Flags = out_flags;
1215
1216 return Length;
1217 }
1218
1219
1220 /*
1221 * @implemented
1222 *
1223 * NOTES
1224 * Same as RtlOemStringToUnicodeString but doesn't write terminating null
1225 * A partial copy is NOT performed if the dest buffer is too small!
1226 */
1227 NTSTATUS
1228 STDCALL
1229 RtlOemStringToCountedUnicodeString(
1230 IN OUT PUNICODE_STRING UniDest,
1231 IN POEM_STRING OemSource,
1232 IN BOOLEAN AllocateDestinationString)
1233 {
1234 NTSTATUS Status;
1235 ULONG Length; /* excluding nullterm */
1236
1237 if (NlsMbCodePageTag == TRUE)
1238 Length = RtlOemStringToUnicodeSize(OemSource) - sizeof(WCHAR);
1239 else
1240 Length = OemSource->Length * sizeof(WCHAR);
1241
1242 if (Length > 65535)
1243 return STATUS_INVALID_PARAMETER_2;
1244
1245 if (AllocateDestinationString == TRUE)
1246 {
1247 UniDest->Buffer = RtlpAllocateStringMemory (Length, TAG_USTR);
1248 if (UniDest->Buffer == NULL)
1249 return STATUS_NO_MEMORY;
1250
1251 UniDest->MaximumLength = Length;
1252 }
1253 else if (Length > UniDest->MaximumLength)
1254 {
1255 return STATUS_BUFFER_TOO_SMALL;
1256 }
1257
1258 UniDest->Length = Length;
1259
1260 Status = RtlOemToUnicodeN (UniDest->Buffer,
1261 UniDest->Length,
1262 NULL,
1263 OemSource->Buffer,
1264 OemSource->Length);
1265
1266 if (!NT_SUCCESS(Status) && AllocateDestinationString)
1267 {
1268 RtlpFreeStringMemory(UniDest->Buffer, TAG_USTR);
1269 return Status;
1270 }
1271
1272 return Status;
1273 }
1274
1275 /*
1276 * @implemented
1277 *
1278 * RETURNS
1279 * TRUE if the names are equal, FALSE if not
1280 *
1281 * NOTES
1282 * The comparison is case insensitive.
1283 */
1284 BOOLEAN
1285 STDCALL
1286 RtlEqualComputerName(
1287 IN PUNICODE_STRING ComputerName1,
1288 IN PUNICODE_STRING ComputerName2)
1289 {
1290 OEM_STRING OemString1;
1291 OEM_STRING OemString2;
1292 BOOLEAN Result = FALSE;
1293
1294 if (NT_SUCCESS(RtlUpcaseUnicodeStringToOemString( &OemString1, ComputerName1, TRUE )))
1295 {
1296 if (NT_SUCCESS(RtlUpcaseUnicodeStringToOemString( &OemString2, ComputerName2, TRUE )))
1297 {
1298 Result = RtlEqualString( &OemString1, &OemString2, TRUE );
1299 RtlFreeOemString( &OemString2 );
1300 }
1301 RtlFreeOemString( &OemString1 );
1302 }
1303
1304 return Result;
1305 }
1306
1307 /*
1308 * @implemented
1309 *
1310 * RETURNS
1311 * TRUE if the names are equal, FALSE if not
1312 *
1313 * NOTES
1314 * The comparison is case insensitive.
1315 */
1316 BOOLEAN
1317 STDCALL
1318 RtlEqualDomainName (
1319 IN PUNICODE_STRING DomainName1,
1320 IN PUNICODE_STRING DomainName2
1321 )
1322 {
1323 return RtlEqualComputerName(DomainName1, DomainName2);
1324 }
1325
1326
1327 /*
1328 * @implemented
1329 */
1330 /*
1331 BOOLEAN
1332 STDCALL
1333 RtlEqualDomainName (
1334 IN PUNICODE_STRING DomainName1,
1335 IN PUNICODE_STRING DomainName2
1336 )
1337 {
1338 OEM_STRING OemString1;
1339 OEM_STRING OemString2;
1340 BOOLEAN Result;
1341
1342 RtlUpcaseUnicodeStringToOemString (&OemString1,
1343 DomainName1,
1344 TRUE);
1345 RtlUpcaseUnicodeStringToOemString (&OemString2,
1346 DomainName2,
1347 TRUE);
1348
1349 Result = RtlEqualString (&OemString1,
1350 &OemString2,
1351 FALSE);
1352
1353 RtlFreeOemString (&OemString1);
1354 RtlFreeOemString (&OemString2);
1355
1356 return Result;
1357
1358 }
1359 */
1360
1361 /*
1362 * @implemented
1363 *
1364 * RIPPED FROM WINE's ntdll\rtlstr.c rev 1.45
1365 *
1366 * Convert a string representation of a GUID into a GUID.
1367 *
1368 * PARAMS
1369 * str [I] String representation in the format "{XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX}"
1370 * guid [O] Destination for the converted GUID
1371 *
1372 * RETURNS
1373 * Success: STATUS_SUCCESS. guid contains the converted value.
1374 * Failure: STATUS_INVALID_PARAMETER, if str is not in the expected format.
1375 *
1376 * SEE ALSO
1377 * See RtlStringFromGUID.
1378 */
1379 NTSTATUS
1380 STDCALL
1381 RtlGUIDFromString(
1382 IN UNICODE_STRING *str,
1383 OUT GUID* guid
1384 )
1385 {
1386 int i = 0;
1387 const WCHAR *lpszCLSID = str->Buffer;
1388 BYTE* lpOut = (BYTE*)guid;
1389
1390 //TRACE("(%s,%p)\n", debugstr_us(str), guid);
1391
1392 /* Convert string: {XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX}
1393 * to memory: DWORD... WORD WORD BYTES............
1394 */
1395 while (i < 37)
1396 {
1397 switch (i)
1398 {
1399 case 0:
1400 if (*lpszCLSID != '{')
1401 return STATUS_INVALID_PARAMETER;
1402 break;
1403
1404 case 9:
1405 case 14:
1406 case 19:
1407 case 24:
1408 if (*lpszCLSID != '-')
1409 return STATUS_INVALID_PARAMETER;
1410 break;
1411
1412 case 37:
1413 if (*lpszCLSID != '}')
1414 return STATUS_INVALID_PARAMETER;
1415 break;
1416
1417 default:
1418 {
1419 WCHAR ch = *lpszCLSID, ch2 = lpszCLSID[1];
1420 unsigned char byte;
1421
1422 /* Read two hex digits as a byte value */
1423 if (ch >= '0' && ch <= '9')
1424 ch = ch - '0';
1425 else if (ch >= 'a' && ch <= 'f')
1426 ch = ch - 'a' + 10;
1427 else if (ch >= 'A' && ch <= 'F')
1428 ch = ch - 'A' + 10;
1429 else
1430 return STATUS_INVALID_PARAMETER;
1431
1432 if (ch2 >= '0' && ch2 <= '9')
1433 ch2 = ch2 - '0';
1434 else if (ch2 >= 'a' && ch2 <= 'f')
1435 ch2 = ch2 - 'a' + 10;
1436 else if (ch2 >= 'A' && ch2 <= 'F')
1437 ch2 = ch2 - 'A' + 10;
1438 else
1439 return STATUS_INVALID_PARAMETER;
1440
1441 byte = ch << 4 | ch2;
1442
1443 switch (i)
1444 {
1445 #ifndef WORDS_BIGENDIAN
1446 /* For Big Endian machines, we store the data such that the
1447 * dword/word members can be read as DWORDS and WORDS correctly. */
1448 /* Dword */
1449 case 1:
1450 lpOut[3] = byte;
1451 break;
1452 case 3:
1453 lpOut[2] = byte;
1454 break;
1455 case 5:
1456 lpOut[1] = byte;
1457 break;
1458 case 7:
1459 lpOut[0] = byte;
1460 lpOut += 4;
1461 break;
1462 /* Word */
1463 case 10:
1464 case 15:
1465 lpOut[1] = byte;
1466 break;
1467 case 12:
1468 case 17:
1469 lpOut[0] = byte;
1470 lpOut += 2;
1471 break;
1472 #endif
1473 /* Byte */
1474 default:
1475 lpOut[0] = byte;
1476 lpOut++;
1477 break;
1478 }
1479 lpszCLSID++; /* Skip 2nd character of byte */
1480 i++;
1481 }
1482 }
1483 lpszCLSID++;
1484 i++;
1485 }
1486
1487 return STATUS_SUCCESS;
1488 }
1489
1490 /*
1491 * @implemented
1492 */
1493 VOID
1494 STDCALL
1495 RtlEraseUnicodeString(
1496 IN PUNICODE_STRING String)
1497 {
1498 if (String->Buffer != NULL &&
1499 String->MaximumLength != 0)
1500 {
1501 RtlZeroMemory (String->Buffer,
1502 String->MaximumLength);
1503
1504 String->Length = 0;
1505 }
1506 }
1507
1508 /*
1509 * @implemented
1510 */
1511 NTSTATUS
1512 STDCALL
1513 RtlHashUnicodeString(
1514 IN CONST UNICODE_STRING *String,
1515 IN BOOLEAN CaseInSensitive,
1516 IN ULONG HashAlgorithm,
1517 OUT PULONG HashValue)
1518 {
1519 if (String != NULL && HashValue != NULL)
1520 {
1521 switch (HashAlgorithm)
1522 {
1523 case HASH_STRING_ALGORITHM_DEFAULT:
1524 case HASH_STRING_ALGORITHM_X65599:
1525 {
1526 WCHAR *c, *end;
1527
1528 *HashValue = 0;
1529 end = String->Buffer + (String->Length / sizeof(WCHAR));
1530
1531 if (CaseInSensitive)
1532 {
1533 for (c = String->Buffer;
1534 c != end;
1535 c++)
1536 {
1537 /* only uppercase characters if they are 'a' ... 'z'! */
1538 *HashValue = ((65599 * (*HashValue)) +
1539 (ULONG)(((*c) >= L'a' && (*c) <= L'z') ?
1540 (*c) - L'a' + L'A' : (*c)));
1541 }
1542 }
1543 else
1544 {
1545 for (c = String->Buffer;
1546 c != end;
1547 c++)
1548 {
1549 *HashValue = ((65599 * (*HashValue)) + (ULONG)(*c));
1550 }
1551 }
1552 return STATUS_SUCCESS;
1553 }
1554 }
1555 }
1556
1557 return STATUS_INVALID_PARAMETER;
1558 }
1559
1560 /*
1561 * @implemented
1562 *
1563 * NOTES
1564 * Same as RtlUnicodeStringToOemString but doesn't write terminating null
1565 * Does a partial copy if the dest buffer is too small
1566 */
1567 NTSTATUS
1568 STDCALL
1569 RtlUnicodeStringToCountedOemString(
1570 IN OUT POEM_STRING OemDest,
1571 IN PUNICODE_STRING UniSource,
1572 IN BOOLEAN AllocateDestinationString)
1573 {
1574 NTSTATUS Status;
1575 ULONG Length; //excluding nullterm
1576
1577 if (NlsMbOemCodePageTag == TRUE)
1578 Length = RtlUnicodeStringToAnsiSize(UniSource) - sizeof(CHAR);
1579 else
1580 Length = (UniSource->Length / sizeof(WCHAR));
1581
1582 if (Length > 0x0000FFFF)
1583 return STATUS_INVALID_PARAMETER_2;
1584
1585 OemDest->Length = (WORD)(Length);
1586
1587 if (AllocateDestinationString)
1588 {
1589 OemDest->Buffer = RtlpAllocateStringMemory(Length, TAG_OSTR);
1590 if (OemDest->Buffer == NULL)
1591 return STATUS_NO_MEMORY;
1592
1593 OemDest->MaximumLength = Length;
1594 }
1595 else if (OemDest->MaximumLength == 0)
1596 {
1597 return STATUS_BUFFER_TOO_SMALL;
1598 }
1599 else if (Length > OemDest->MaximumLength)
1600 {
1601 OemDest->Length = OemDest->MaximumLength;
1602 }
1603
1604 Status = RtlUnicodeToOemN (OemDest->Buffer,
1605 OemDest->Length,
1606 NULL,
1607 UniSource->Buffer,
1608 UniSource->Length);
1609
1610 if (!NT_SUCCESS(Status) && AllocateDestinationString)
1611 {
1612 RtlpFreeStringMemory(OemDest->Buffer, TAG_OSTR);
1613 }
1614
1615 return Status;
1616 }
1617
1618 /*
1619 * @implemented
1620 */
1621 NTSTATUS
1622 STDCALL
1623 RtlLargeIntegerToChar(
1624 IN PLARGE_INTEGER Value,
1625 IN ULONG Base,
1626 IN ULONG Length,
1627 IN OUT PCHAR String)
1628 {
1629 ULONG Radix;
1630 CHAR temp[65];
1631 ULONGLONG v = Value->QuadPart;
1632 ULONG i;
1633 PCHAR tp;
1634 PCHAR sp;
1635
1636 Radix = Base;
1637 if (Radix == 0)
1638 Radix = 10;
1639
1640 if ((Radix != 2) && (Radix != 8) &&
1641 (Radix != 10) && (Radix != 16))
1642 return STATUS_INVALID_PARAMETER;
1643
1644 tp = temp;
1645 while (v || tp == temp)
1646 {
1647 i = v % Radix;
1648 v = v / Radix;
1649 if (i < 10)
1650 *tp = i + '0';
1651 else
1652 *tp = i + 'a' - 10;
1653 tp++;
1654 }
1655
1656 if ((ULONG)((ULONG_PTR)tp - (ULONG_PTR)temp) >= Length)
1657 return STATUS_BUFFER_TOO_SMALL;
1658
1659 sp = String;
1660 while (tp > temp)
1661 *sp++ = *--tp;
1662 *sp = 0;
1663
1664 return STATUS_SUCCESS;
1665 }
1666
1667 /*
1668 * @implemented
1669 *
1670 * NOTES
1671 * dest is never '\0' terminated because it may be equal to src, and src
1672 * might not be '\0' terminated. dest->Length is only set upon success.
1673 */
1674 NTSTATUS
1675 STDCALL
1676 RtlUpcaseUnicodeString(
1677 IN OUT PUNICODE_STRING UniDest,
1678 IN PCUNICODE_STRING UniSource,
1679 IN BOOLEAN AllocateDestinationString)
1680 {
1681 ULONG i;
1682 PWCHAR Src, Dest;
1683
1684 if (AllocateDestinationString == TRUE)
1685 {
1686 UniDest->MaximumLength = UniSource->Length;
1687 UniDest->Buffer = RtlpAllocateStringMemory(UniDest->MaximumLength, TAG_USTR);
1688 if (UniDest->Buffer == NULL)
1689 return STATUS_NO_MEMORY;
1690 }
1691 else if (UniSource->Length > UniDest->MaximumLength)
1692 {
1693 return STATUS_BUFFER_TOO_SMALL;
1694 }
1695
1696 UniDest->Length = UniSource->Length;
1697
1698 Src = UniSource->Buffer;
1699 Dest = UniDest->Buffer;
1700 for (i = 0; i < UniSource->Length / sizeof(WCHAR); i++)
1701 {
1702 *Dest = RtlUpcaseUnicodeChar (*Src);
1703 Dest++;
1704 Src++;
1705 }
1706
1707 return STATUS_SUCCESS;
1708 }
1709
1710 /*
1711 * @implemented
1712 *
1713 * NOTES
1714 * This function always writes a terminating '\0'.
1715 * It performs a partial copy if ansi is too small.
1716 */
1717 NTSTATUS
1718 STDCALL
1719 RtlUpcaseUnicodeStringToAnsiString(
1720 IN OUT PANSI_STRING AnsiDest,
1721 IN PUNICODE_STRING UniSource,
1722 IN BOOLEAN AllocateDestinationString)
1723 {
1724 NTSTATUS Status;
1725 ULONG Length; /* including nullterm */
1726
1727 if (NlsMbCodePageTag == TRUE)
1728 Length = RtlUnicodeStringToAnsiSize(UniSource);
1729 else
1730 Length = (UniSource->Length / sizeof(WCHAR)) + sizeof(CHAR);
1731
1732 if (Length > 0x0000FFFF)
1733 return STATUS_INVALID_PARAMETER_2;
1734
1735 AnsiDest->Length = (WORD)(Length - sizeof(CHAR));
1736
1737 if (AllocateDestinationString)
1738 {
1739 AnsiDest->Buffer = RtlpAllocateStringMemory(Length, TAG_ASTR);
1740 if (AnsiDest->Buffer == NULL)
1741 return STATUS_NO_MEMORY;
1742
1743 AnsiDest->MaximumLength = Length;
1744 }
1745 else if (AnsiDest->MaximumLength == 0)
1746 {
1747 return STATUS_BUFFER_TOO_SMALL;
1748 }
1749 else if (Length > AnsiDest->MaximumLength)
1750 {
1751 /* make room for nullterm */
1752 AnsiDest->Length = AnsiDest->MaximumLength - sizeof(CHAR);
1753 }
1754
1755 /* FIXME: do we need this??????? -Gunnar */
1756 RtlZeroMemory (AnsiDest->Buffer,
1757 AnsiDest->Length);
1758
1759 Status = RtlUpcaseUnicodeToMultiByteN (AnsiDest->Buffer,
1760 AnsiDest->Length,
1761 NULL,
1762 UniSource->Buffer,
1763 UniSource->Length);
1764
1765 if (!NT_SUCCESS(Status) && AllocateDestinationString)
1766 {
1767 RtlpFreeStringMemory(AnsiDest->Buffer, TAG_ASTR);
1768 return Status;
1769 }
1770
1771 AnsiDest->Buffer[AnsiDest->Length] = 0;
1772 return Status;
1773 }
1774
1775 /*
1776 * @implemented
1777 *
1778 * NOTES
1779 * This function always writes a terminating '\0'.
1780 * It performs a partial copy if ansi is too small.
1781 */
1782 NTSTATUS
1783 STDCALL
1784 RtlUpcaseUnicodeStringToCountedOemString(
1785 IN OUT POEM_STRING OemDest,
1786 IN PUNICODE_STRING UniSource,
1787 IN BOOLEAN AllocateDestinationString)
1788 {
1789 NTSTATUS Status;
1790 ULONG Length; /* excluding nullterm */
1791
1792 if (NlsMbCodePageTag == TRUE)
1793 Length = RtlUnicodeStringToAnsiSize(UniSource) - sizeof(CHAR);
1794 else
1795 Length = UniSource->Length / sizeof(WCHAR);
1796
1797 if (Length > 0x0000FFFF)
1798 return(STATUS_INVALID_PARAMETER_2);
1799
1800 OemDest->Length = (WORD)(Length);
1801
1802 if (AllocateDestinationString)
1803 {
1804 OemDest->Buffer = RtlpAllocateStringMemory(Length, TAG_OSTR);
1805 if (OemDest->Buffer == NULL)
1806 return(STATUS_NO_MEMORY);
1807
1808 /* FIXME: Do we need this????? */
1809 RtlZeroMemory (OemDest->Buffer, Length);
1810
1811 OemDest->MaximumLength = (WORD)Length;
1812 }
1813 else if (OemDest->MaximumLength == 0)
1814 {
1815 return(STATUS_BUFFER_TOO_SMALL);
1816 }
1817 else if (Length > OemDest->MaximumLength)
1818 {
1819 OemDest->Length = OemDest->MaximumLength;
1820 }
1821
1822 Status = RtlUpcaseUnicodeToOemN(OemDest->Buffer,
1823 OemDest->Length,
1824 NULL,
1825 UniSource->Buffer,
1826 UniSource->Length);
1827
1828 if (!NT_SUCCESS(Status) && AllocateDestinationString)
1829 {
1830 RtlpFreeStringMemory(OemDest->Buffer, TAG_OSTR);
1831 return Status;
1832 }
1833
1834 return Status;
1835 }
1836
1837 /*
1838 * @implemented
1839 * NOTES
1840 * Oem string is allways nullterminated
1841 * It performs a partial copy if oem is too small.
1842 */
1843 NTSTATUS
1844 STDCALL
1845 RtlUpcaseUnicodeStringToOemString (
1846 IN OUT POEM_STRING OemDest,
1847 IN PUNICODE_STRING UniSource,
1848 IN BOOLEAN AllocateDestinationString
1849 )
1850 {
1851 NTSTATUS Status;
1852 ULONG Length; /* including nullterm */
1853
1854 if (NlsMbOemCodePageTag == TRUE)
1855 Length = RtlUnicodeStringToAnsiSize(UniSource);
1856 else
1857 Length = (UniSource->Length / sizeof(WCHAR)) + sizeof(CHAR);
1858
1859 if (Length > 0x0000FFFF)
1860 return STATUS_INVALID_PARAMETER_2;
1861
1862 OemDest->Length = (WORD)(Length - sizeof(CHAR));
1863
1864 if (AllocateDestinationString)
1865 {
1866 OemDest->Buffer = RtlpAllocateStringMemory(Length, TAG_OSTR);
1867 if (OemDest->Buffer == NULL)
1868 return STATUS_NO_MEMORY;
1869
1870 /* FIXME: Do we need this???? */
1871 RtlZeroMemory (OemDest->Buffer, Length);
1872
1873 OemDest->MaximumLength = (WORD)Length;
1874 }
1875 else if (OemDest->MaximumLength == 0)
1876 {
1877 return STATUS_BUFFER_OVERFLOW;
1878 }
1879 else if (Length > OemDest->MaximumLength)
1880 {
1881 /* make room for nullterm */
1882 OemDest->Length = OemDest->MaximumLength - sizeof(CHAR);
1883 }
1884
1885 Status = RtlUpcaseUnicodeToOemN (OemDest->Buffer,
1886 OemDest->Length,
1887 NULL,
1888 UniSource->Buffer,
1889 UniSource->Length);
1890
1891 if (!NT_SUCCESS(Status) && AllocateDestinationString)
1892 {
1893 RtlpFreeStringMemory(OemDest->Buffer, TAG_OSTR);
1894 return Status;
1895 }
1896
1897 OemDest->Buffer[OemDest->Length] = 0;
1898 return Status;
1899 }
1900
1901 /*
1902 * @implemented
1903 *
1904 * RETURNS
1905 * Bytes calculated including nullterm
1906 */
1907 ULONG
1908 STDCALL
1909 RtlOemStringToUnicodeSize(IN POEM_STRING OemString)
1910 {
1911 ULONG Size;
1912
1913 //this function returns size including nullterm
1914 RtlMultiByteToUnicodeSize(&Size,
1915 OemString->Buffer,
1916 OemString->Length);
1917
1918 return(Size);
1919 }
1920
1921
1922
1923 /*
1924 * @implemented
1925 */
1926 NTSTATUS
1927 STDCALL
1928 RtlStringFromGUID (IN REFGUID Guid,
1929 OUT PUNICODE_STRING GuidString)
1930 {
1931 STATIC CONST PWCHAR Hex = L"0123456789ABCDEF";
1932 WCHAR Buffer[40];
1933 PWCHAR BufferPtr;
1934 ULONG i;
1935
1936 if (Guid == NULL)
1937 {
1938 return STATUS_INVALID_PARAMETER;
1939 }
1940
1941 swprintf (Buffer,
1942 L"{%08lX-%04X-%04X-%02X%02X-",
1943 Guid->Data1,
1944 Guid->Data2,
1945 Guid->Data3,
1946 Guid->Data4[0],
1947 Guid->Data4[1]);
1948 BufferPtr = Buffer + 25;
1949
1950 /* 6 hex bytes */
1951 for (i = 2; i < 8; i++)
1952 {
1953 *BufferPtr++ = Hex[Guid->Data4[i] >> 4];
1954 *BufferPtr++ = Hex[Guid->Data4[i] & 0xf];
1955 }
1956
1957 *BufferPtr++ = L'}';
1958 *BufferPtr++ = L'\0';
1959
1960 return RtlCreateUnicodeString (GuidString, Buffer);
1961 }
1962
1963
1964 /*
1965 * @implemented
1966 *
1967 * RETURNS
1968 * Bytes calculated including nullterm
1969 */
1970 ULONG
1971 STDCALL
1972 RtlUnicodeStringToAnsiSize(
1973 IN PUNICODE_STRING UnicodeString)
1974 {
1975 ULONG Size;
1976
1977 //this function return size without nullterm!
1978 RtlUnicodeToMultiByteSize (&Size,
1979 UnicodeString->Buffer,
1980 UnicodeString->Length);
1981
1982 return Size + sizeof(CHAR); //NB: incl. nullterm
1983 }
1984
1985
1986
1987
1988 /*
1989 * @implemented
1990 */
1991 LONG
1992 STDCALL
1993 RtlCompareUnicodeString(
1994 IN PUNICODE_STRING String1,
1995 IN PUNICODE_STRING String2,
1996 IN BOOLEAN CaseInsensitive)
1997 {
1998 ULONG len1, len2;
1999 PWCHAR s1, s2;
2000 WCHAR c1, c2;
2001
2002 if (String1 && String2)
2003 {
2004 len1 = String1->Length / sizeof(WCHAR);
2005 len2 = String2->Length / sizeof(WCHAR);
2006 s1 = String1->Buffer;
2007 s2 = String2->Buffer;
2008
2009 if (s1 && s2)
2010 {
2011 if (CaseInsensitive)
2012 {
2013 while (1)
2014 {
2015 c1 = len1-- ? RtlUpcaseUnicodeChar (*s1++) : 0;
2016 c2 = len2-- ? RtlUpcaseUnicodeChar (*s2++) : 0;
2017 if (!c1 || !c2 || c1 != c2)
2018 return c1 - c2;
2019 }
2020 }
2021 else
2022 {
2023 while (1)
2024 {
2025 c1 = len1-- ? *s1++ : 0;
2026 c2 = len2-- ? *s2++ : 0;
2027 if (!c1 || !c2 || c1 != c2)
2028 return c1 - c2;
2029 }
2030 }
2031 }
2032 }
2033
2034 return 0;
2035 }
2036
2037
2038 /*
2039 * @implemented
2040 */
2041 VOID
2042 STDCALL
2043 RtlCopyString(
2044 IN OUT PSTRING DestinationString,
2045 IN PSTRING SourceString)
2046 {
2047 ULONG copylen;
2048
2049 if(SourceString == NULL)
2050 {
2051 DestinationString->Length = 0;
2052 return;
2053 }
2054
2055 copylen = min (DestinationString->MaximumLength,
2056 SourceString->Length);
2057
2058 memcpy(DestinationString->Buffer, SourceString->Buffer, copylen);
2059 if (DestinationString->MaximumLength >= copylen + sizeof(CHAR))
2060 {
2061 DestinationString->Buffer[copylen] = 0;
2062 }
2063 DestinationString->Length = copylen;
2064 }
2065
2066
2067
2068 /*
2069 * @implemented
2070 */
2071 VOID
2072 STDCALL
2073 RtlCopyUnicodeString(
2074 IN OUT PUNICODE_STRING DestinationString,
2075 IN PUNICODE_STRING SourceString)
2076 {
2077 ULONG copylen;
2078
2079 if (SourceString == NULL)
2080 {
2081 DestinationString->Length = 0;
2082 return;
2083 }
2084
2085 copylen = min (DestinationString->MaximumLength,
2086 SourceString->Length);
2087 memcpy(DestinationString->Buffer, SourceString->Buffer, copylen);
2088 if (DestinationString->MaximumLength >= copylen + sizeof(WCHAR))
2089 {
2090 DestinationString->Buffer[copylen / sizeof(WCHAR)] = 0;
2091 }
2092 DestinationString->Length = copylen;
2093 }
2094
2095 /*
2096 * @implemented
2097 *
2098 * NOTES
2099 * Creates a nullterminated UNICODE_STRING
2100 */
2101 BOOLEAN
2102 STDCALL
2103 RtlCreateUnicodeString(
2104 IN OUT PUNICODE_STRING UniDest,
2105 IN PCWSTR Source)
2106 {
2107 ULONG Length;
2108
2109 Length = (wcslen (Source) + 1) * sizeof(WCHAR);
2110 UniDest->Buffer = RtlpAllocateStringMemory(Length, TAG_USTR);
2111 if (UniDest->Buffer == NULL)
2112 return FALSE;
2113
2114 RtlCopyMemory (UniDest->Buffer,
2115 Source,
2116 Length);
2117
2118 UniDest->MaximumLength = Length;
2119 UniDest->Length = Length - sizeof (WCHAR);
2120
2121 return TRUE;
2122 }
2123
2124 /*
2125 * @implemented
2126 */
2127 BOOLEAN
2128 STDCALL
2129 RtlCreateUnicodeStringFromAsciiz(
2130 OUT PUNICODE_STRING Destination,
2131 IN PCSZ Source)
2132 {
2133 ANSI_STRING AnsiString;
2134 NTSTATUS Status;
2135
2136 RtlInitAnsiString (&AnsiString,
2137 Source);
2138
2139 Status = RtlAnsiStringToUnicodeString (Destination,
2140 &AnsiString,
2141 TRUE);
2142
2143 return NT_SUCCESS(Status);
2144 }
2145
2146 /*
2147 * @implemented
2148 *
2149 * NOTES
2150 * Dest is never '\0' terminated because it may be equal to src, and src
2151 * might not be '\0' terminated.
2152 * Dest->Length is only set upon success.
2153 */
2154 NTSTATUS STDCALL
2155 RtlDowncaseUnicodeString(
2156 IN OUT PUNICODE_STRING UniDest,
2157 IN PUNICODE_STRING UniSource,
2158 IN BOOLEAN AllocateDestinationString)
2159 {
2160 ULONG i;
2161 PWCHAR Src, Dest;
2162
2163 if (AllocateDestinationString)
2164 {
2165 UniDest->Buffer = RtlpAllocateStringMemory(UniSource->Length, TAG_USTR);
2166 if (UniDest->Buffer == NULL)
2167 return STATUS_NO_MEMORY;
2168
2169 UniDest->MaximumLength = UniSource->Length;
2170 }
2171 else if (UniSource->Length > UniDest->MaximumLength)
2172 {
2173 return STATUS_BUFFER_TOO_SMALL;
2174 }
2175
2176 UniDest->Length = UniSource->Length;
2177
2178 Src = UniSource->Buffer;
2179 Dest = UniDest->Buffer;
2180 for (i=0; i < UniSource->Length / sizeof(WCHAR); i++)
2181 {
2182 if (*Src < L'A')
2183 {
2184 *Dest = *Src;
2185 }
2186 else if (*Src <= L'Z')
2187 {
2188 *Dest = (*Src + (L'a' - L'A'));
2189 }
2190 else
2191 {
2192 *Dest = RtlDowncaseUnicodeChar(*Src);
2193 }
2194
2195 Dest++;
2196 Src++;
2197 }
2198
2199 return STATUS_SUCCESS;
2200 }
2201
2202 /*
2203 * @implemented
2204 *
2205 * NOTES
2206 * if src is NULL dest is unchanged.
2207 * dest is '\0' terminated when the MaximumLength allowes it.
2208 * When dest fits exactly in MaximumLength characters the '\0' is ommitted.
2209 */
2210 NTSTATUS STDCALL
2211 RtlAppendUnicodeToString(IN OUT PUNICODE_STRING Destination,
2212 IN PCWSTR Source)
2213 {
2214 ULONG slen;
2215
2216 slen = wcslen(Source) * sizeof(WCHAR);
2217
2218 if (Destination->Length + slen > Destination->MaximumLength)
2219 return(STATUS_BUFFER_TOO_SMALL);
2220
2221 memcpy((char*)Destination->Buffer + Destination->Length, Source, slen);
2222 Destination->Length += slen;
2223 /* append terminating '\0' if enough space */
2224 if( Destination->MaximumLength > Destination->Length )
2225 Destination->Buffer[Destination->Length / sizeof(WCHAR)] = 0;
2226
2227 return(STATUS_SUCCESS);
2228 }
2229
2230 /*
2231 * @implemented
2232 *
2233 * NOTES
2234 * This function always writes a terminating '\0'.
2235 * If the dest buffer is too small a partial copy is NOT performed!
2236 */
2237 NTSTATUS
2238 STDCALL
2239 RtlAnsiStringToUnicodeString(
2240 IN OUT PUNICODE_STRING UniDest,
2241 IN PANSI_STRING AnsiSource,
2242 IN BOOLEAN AllocateDestinationString)
2243 {
2244 NTSTATUS Status;
2245 ULONG Length; //including nullterm
2246
2247 if (NlsMbCodePageTag == TRUE)
2248 Length = RtlAnsiStringToUnicodeSize(AnsiSource);
2249 else
2250 Length = (AnsiSource->Length * sizeof(WCHAR)) + sizeof(WCHAR);
2251
2252 if (Length > 0xffff)
2253 return STATUS_INVALID_PARAMETER_2;
2254
2255 if (AllocateDestinationString == TRUE)
2256 {
2257 UniDest->Buffer = RtlpAllocateStringMemory(Length, TAG_USTR);
2258 if (UniDest->Buffer == NULL)
2259 return STATUS_NO_MEMORY;
2260
2261 UniDest->MaximumLength = Length;
2262 }
2263 else if (Length > UniDest->MaximumLength)
2264 {
2265 DPRINT("STATUS_BUFFER_TOO_SMALL\n");
2266 return STATUS_BUFFER_TOO_SMALL;
2267 }
2268
2269 UniDest->Length = Length - sizeof(WCHAR);
2270
2271 //FIXME: We don't need this??? -Gunnar
2272 RtlZeroMemory (UniDest->Buffer,
2273 UniDest->Length);
2274
2275 Status = RtlMultiByteToUnicodeN (UniDest->Buffer,
2276 UniDest->Length,
2277 NULL,
2278 AnsiSource->Buffer,
2279 AnsiSource->Length);
2280
2281 if (!NT_SUCCESS(Status) && AllocateDestinationString)
2282 {
2283 RtlpFreeStringMemory(UniDest->Buffer, TAG_USTR);
2284 return Status;
2285 }
2286
2287 UniDest->Buffer[UniDest->Length / sizeof(WCHAR)] = 0;
2288 return Status;
2289 }
2290
2291 /*
2292 * @implemented
2293 *
2294 * NOTES
2295 * if src is NULL dest is unchanged.
2296 * dest is never '\0' terminated.
2297 */
2298 NTSTATUS
2299 STDCALL
2300 RtlAppendAsciizToString(
2301 IN OUT PSTRING Destination,
2302 IN PCSZ Source)
2303 {
2304 ULONG Length;
2305 PCHAR Ptr;
2306
2307 if (Source == NULL)
2308 return STATUS_SUCCESS;
2309
2310 Length = strlen (Source);
2311 if (Destination->Length + Length >= Destination->MaximumLength)
2312 return STATUS_BUFFER_TOO_SMALL;
2313
2314 Ptr = Destination->Buffer + Destination->Length;
2315 memmove (Ptr,
2316 Source,
2317 Length);
2318 Ptr += Length;
2319 *Ptr = 0;
2320
2321 Destination->Length += Length;
2322
2323 return STATUS_SUCCESS;
2324 }
2325
2326
2327 /*
2328 * @implemented
2329 */
2330 VOID STDCALL
2331 RtlUpperString(PSTRING DestinationString,
2332 PSTRING SourceString)
2333 {
2334 ULONG Length;
2335 ULONG i;
2336 PCHAR Src;
2337 PCHAR Dest;
2338
2339 Length = min(SourceString->Length,
2340 DestinationString->MaximumLength - 1);
2341
2342 Src = SourceString->Buffer;
2343 Dest = DestinationString->Buffer;
2344 for (i = 0; i < Length; i++)
2345 {
2346 *Dest = RtlUpperChar(*Src);
2347 Src++;
2348 Dest++;
2349 }
2350 *Dest = 0;
2351
2352 DestinationString->Length = SourceString->Length;
2353 }
2354
2355
2356 /*
2357 * @implemented
2358 */
2359 ULONG STDCALL
2360 RtlxAnsiStringToUnicodeSize(IN PANSI_STRING AnsiString)
2361 {
2362 return RtlAnsiStringToUnicodeSize(AnsiString);
2363 }
2364
2365
2366 /*
2367 * @implemented
2368 */
2369 ULONG STDCALL
2370 RtlxOemStringToUnicodeSize(IN POEM_STRING OemString)
2371 {
2372 return RtlOemStringToUnicodeSize(OemString);
2373 }
2374
2375
2376
2377 /*
2378 * @implemented
2379 */
2380 ULONG STDCALL
2381 RtlxUnicodeStringToAnsiSize(IN PUNICODE_STRING UnicodeString)
2382 {
2383 return RtlUnicodeStringToAnsiSize(UnicodeString);
2384 }
2385
2386
2387 /*
2388 * @implemented
2389 */
2390 ULONG STDCALL
2391 RtlxUnicodeStringToOemSize(IN PUNICODE_STRING UnicodeString)
2392 {
2393 return RtlUnicodeStringToOemSize(UnicodeString);
2394 }
2395
2396 /*
2397 * @implemented
2398 *
2399 * NOTES
2400 * See RtlpDuplicateUnicodeString
2401 */
2402 NTSTATUS STDCALL
2403 RtlDuplicateUnicodeString(
2404 INT AddNull,
2405 IN PUNICODE_STRING SourceString,
2406 PUNICODE_STRING DestinationString)
2407 {
2408 if (SourceString == NULL || DestinationString == NULL)
2409 return STATUS_INVALID_PARAMETER;
2410
2411
2412 if (SourceString->Length == 0 && AddNull != 3)
2413 {
2414 DestinationString->Length = 0;
2415 DestinationString->MaximumLength = 0;
2416 DestinationString->Buffer = NULL;
2417 }
2418 else
2419 {
2420 UINT DestMaxLength = SourceString->Length;
2421
2422 if (AddNull)
2423 DestMaxLength += sizeof(UNICODE_NULL);
2424
2425 DestinationString->Buffer = RtlpAllocateStringMemory(DestMaxLength, TAG_USTR);
2426 if (DestinationString->Buffer == NULL)
2427 return STATUS_NO_MEMORY;
2428
2429 RtlCopyMemory(DestinationString->Buffer, SourceString->Buffer, SourceString->Length);
2430 DestinationString->Length = SourceString->Length;
2431 DestinationString->MaximumLength = DestMaxLength;
2432
2433 if (AddNull)
2434 DestinationString->Buffer[DestinationString->Length / sizeof(WCHAR)] = 0;
2435 }
2436
2437 return STATUS_SUCCESS;
2438 }
2439
2440 /*
2441 * @implemented
2442 */
2443 NTSTATUS STDCALL
2444 RtlValidateUnicodeString(IN ULONG Flags,
2445 IN PUNICODE_STRING UnicodeString)
2446 {
2447 /* currently no flags are supported! */
2448 ASSERT(Flags == 0);
2449
2450 if ((Flags == 0) &&
2451 ((UnicodeString == NULL) ||
2452 ((UnicodeString->Length != 0) &&
2453 (UnicodeString->Buffer != NULL) &&
2454 ((UnicodeString->Length % sizeof(WCHAR)) == 0) &&
2455 ((UnicodeString->MaximumLength % sizeof(WCHAR)) == 0) &&
2456 (UnicodeString->MaximumLength >= UnicodeString->Length))))
2457 {
2458 /* a NULL pointer as a unicode string is considered to be a valid unicode
2459 string! */
2460 return STATUS_SUCCESS;
2461 }
2462 else
2463 {
2464 return STATUS_INVALID_PARAMETER;
2465 }
2466 }
2467
2468 /* EOF */