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