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