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