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