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