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