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