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