- Remove deprecated CHECKPOINT/CHECKPOINT1 macros which basically translated into...
[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_USTR);
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 NTSTATUS
436 NTAPI
437 RtlInitAnsiStringEx(IN OUT PANSI_STRING DestinationString,
438 IN PCSZ SourceString)
439 {
440 ULONG DestSize;
441
442 if(SourceString)
443 {
444 DestSize = strlen(SourceString);
445 if (DestSize >= 0xFFFF) return STATUS_NAME_TOO_LONG;
446 DestinationString->Length = (USHORT)DestSize;
447 DestinationString->MaximumLength = (USHORT)DestSize + sizeof(CHAR);
448 }
449 else
450 {
451 DestinationString->Length = 0;
452 DestinationString->MaximumLength = 0;
453 }
454
455 DestinationString->Buffer = (PCHAR)SourceString;
456 return STATUS_SUCCESS;
457
458 }
459 /*
460 * @implemented
461 *
462 * NOTES
463 * If source is NULL the length of source is assumed to be 0.
464 */
465 VOID
466 NTAPI
467 RtlInitString(
468 IN OUT PSTRING DestinationString,
469 IN PCSZ SourceString)
470 {
471 RtlInitAnsiString(DestinationString, SourceString);
472 }
473
474 /*
475 * @implemented
476 *
477 * NOTES
478 * If source is NULL the length of source is assumed to be 0.
479 */
480 VOID
481 NTAPI
482 RtlInitUnicodeString(IN OUT PUNICODE_STRING DestinationString,
483 IN PCWSTR SourceString)
484 {
485 ULONG DestSize;
486
487 if(SourceString)
488 {
489 DestSize = wcslen(SourceString) * sizeof(WCHAR);
490 DestinationString->Length = (USHORT)DestSize;
491 DestinationString->MaximumLength = (USHORT)DestSize + sizeof(WCHAR);
492 }
493 else
494 {
495 DestinationString->Length = 0;
496 DestinationString->MaximumLength = 0;
497 }
498
499 DestinationString->Buffer = (PWCHAR)SourceString;
500 }
501
502 /*
503 * @implemented
504 */
505 NTSTATUS
506 NTAPI
507 RtlInitUnicodeStringEx(OUT PUNICODE_STRING DestinationString,
508 IN PCWSTR SourceString)
509 {
510 ULONG DestSize;
511
512 if(SourceString)
513 {
514 DestSize = wcslen(SourceString) * sizeof(WCHAR);
515 if (DestSize >= 0xFFFC) return STATUS_NAME_TOO_LONG;
516 DestinationString->Length = (USHORT)DestSize;
517 DestinationString->MaximumLength = (USHORT)DestSize + sizeof(WCHAR);
518 }
519 else
520 {
521 DestinationString->Length = 0;
522 DestinationString->MaximumLength = 0;
523 }
524
525 DestinationString->Buffer = (PWCHAR)SourceString;
526 return STATUS_SUCCESS;
527 }
528
529 /*
530 * @implemented
531 *
532 * NOTES
533 * Writes at most length characters to the string str.
534 * Str is nullterminated when length allowes it.
535 * When str fits exactly in length characters the nullterm is ommitted.
536 */
537 NTSTATUS NTAPI RtlIntegerToChar(
538 ULONG value, /* [I] Value to be converted */
539 ULONG base, /* [I] Number base for conversion (allowed 0, 2, 8, 10 or 16) */
540 ULONG length, /* [I] Length of the str buffer in bytes */
541 PCHAR str) /* [O] Destination for the converted value */
542 {
543 CHAR buffer[33];
544 PCHAR pos;
545 CHAR digit;
546 ULONG len;
547
548 if (base == 0) {
549 base = 10;
550 } else if (base != 2 && base != 8 && base != 10 && base != 16) {
551 return STATUS_INVALID_PARAMETER;
552 } /* if */
553
554 pos = &buffer[32];
555 *pos = '\0';
556
557 do {
558 pos--;
559 digit = value % base;
560 value = value / base;
561 if (digit < 10) {
562 *pos = '0' + digit;
563 } else {
564 *pos = 'A' + digit - 10;
565 } /* if */
566 } while (value != 0L);
567
568 len = &buffer[32] - pos;
569 if (len > length) {
570 return STATUS_BUFFER_OVERFLOW;
571 } else if (str == NULL) {
572 return STATUS_ACCESS_VIOLATION;
573 } else if (len == length) {
574 memcpy(str, pos, len);
575 } else {
576 memcpy(str, pos, len + 1);
577 } /* if */
578 return STATUS_SUCCESS;
579 }
580
581 /*
582 * @implemented
583 */
584 NTSTATUS
585 NTAPI
586 RtlIntegerToUnicode(
587 IN ULONG Value,
588 IN ULONG Base OPTIONAL,
589 IN ULONG Length OPTIONAL,
590 IN OUT LPWSTR String
591 )
592 {
593 ULONG Radix;
594 WCHAR temp[33];
595 ULONG v = Value;
596 ULONG i;
597 PWCHAR tp;
598 PWCHAR sp;
599
600 Radix = Base;
601 if (Radix == 0)
602 Radix = 10;
603
604 if ((Radix != 2) && (Radix != 8) &&
605 (Radix != 10) && (Radix != 16))
606 {
607 return STATUS_INVALID_PARAMETER;
608 }
609
610 tp = temp;
611 while (v || tp == temp)
612 {
613 i = v % Radix;
614 v = v / Radix;
615 if (i < 10)
616 *tp = i + L'0';
617 else
618 *tp = i + L'a' - 10;
619 tp++;
620 }
621
622 if ((ULONG)((ULONG_PTR)tp - (ULONG_PTR)temp) >= Length)
623 {
624 return STATUS_BUFFER_TOO_SMALL;
625 }
626
627 sp = String;
628 while (tp > temp)
629 *sp++ = *--tp;
630 *sp = 0;
631
632 return STATUS_SUCCESS;
633 }
634
635 /*
636 * @implemented
637 */
638 NTSTATUS
639 NTAPI
640 RtlIntegerToUnicodeString(
641 IN ULONG Value,
642 IN ULONG Base OPTIONAL,
643 IN OUT PUNICODE_STRING String)
644 {
645 ANSI_STRING AnsiString;
646 CHAR Buffer[33];
647 NTSTATUS Status;
648
649 Status = RtlIntegerToChar(Value, 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 NTSTATUS
666 NTAPI
667 RtlInt64ToUnicodeString (
668 IN ULONGLONG Value,
669 IN ULONG Base OPTIONAL,
670 IN OUT PUNICODE_STRING String)
671 {
672 LARGE_INTEGER LargeInt;
673 ANSI_STRING AnsiString;
674 CHAR Buffer[65];
675 NTSTATUS Status;
676
677 LargeInt.QuadPart = Value;
678
679 Status = RtlLargeIntegerToChar(&LargeInt, Base, sizeof(Buffer), Buffer);
680 if (NT_SUCCESS(Status))
681 {
682 AnsiString.Buffer = Buffer;
683 AnsiString.Length = (USHORT)strlen(Buffer);
684 AnsiString.MaximumLength = sizeof(Buffer);
685
686 Status = RtlAnsiStringToUnicodeString(String, &AnsiString, FALSE);
687 }
688
689 return Status;
690 }
691
692 /*
693 * @implemented
694 *
695 * RETURNS
696 * TRUE if String2 contains String1 as a prefix.
697 */
698 BOOLEAN
699 NTAPI
700 RtlPrefixString(
701 PANSI_STRING String1,
702 PANSI_STRING String2,
703 BOOLEAN CaseInsensitive)
704 {
705 PCHAR pc1;
706 PCHAR pc2;
707 ULONG Length;
708
709 if (String2->Length < String1->Length)
710 return FALSE;
711
712 Length = String1->Length;
713 pc1 = String1->Buffer;
714 pc2 = String2->Buffer;
715
716 if (pc1 && pc2)
717 {
718 if (CaseInsensitive)
719 {
720 while (Length--)
721 {
722 if (RtlUpperChar (*pc1++) != RtlUpperChar (*pc2++))
723 return FALSE;
724 }
725 }
726 else
727 {
728 while (Length--)
729 {
730 if (*pc1++ != *pc2++)
731 return FALSE;
732 }
733 }
734 return TRUE;
735 }
736 return FALSE;
737 }
738
739 /*
740 * @implemented
741 *
742 * RETURNS
743 * TRUE if String2 contains String1 as a prefix.
744 */
745 BOOLEAN
746 NTAPI
747 RtlPrefixUnicodeString(
748 PCUNICODE_STRING String1,
749 PCUNICODE_STRING String2,
750 BOOLEAN CaseInsensitive)
751 {
752 PWCHAR pc1;
753 PWCHAR pc2;
754 ULONG Length;
755
756 if (String2->Length < String1->Length)
757 return FALSE;
758
759 Length = String1->Length / 2;
760 pc1 = String1->Buffer;
761 pc2 = String2->Buffer;
762
763 if (pc1 && pc2)
764 {
765 if (CaseInsensitive)
766 {
767 while (Length--)
768 {
769 if (RtlUpcaseUnicodeChar (*pc1++)
770 != RtlUpcaseUnicodeChar (*pc2++))
771 return FALSE;
772 }
773 }
774 else
775 {
776 while (Length--)
777 {
778 if( *pc1++ != *pc2++ )
779 return FALSE;
780 }
781 }
782 return TRUE;
783 }
784 return FALSE;
785 }
786 /*
787 * @implemented
788 */
789 NTSTATUS
790 NTAPI
791 RtlUnicodeStringToInteger(const UNICODE_STRING *str, /* [I] Unicode string to be converted */
792 ULONG base, /* [I] Number base for conversion (allowed 0, 2, 8, 10 or 16) */
793 ULONG *value) /* [O] Destination for the converted value */
794 {
795 LPWSTR lpwstr = str->Buffer;
796 USHORT CharsRemaining = str->Length / sizeof(WCHAR);
797 WCHAR wchCurrent;
798 int digit;
799 ULONG RunningTotal = 0;
800 char bMinus = 0;
801
802 while (CharsRemaining >= 1 && *lpwstr <= ' ') {
803 lpwstr++;
804 CharsRemaining--;
805 } /* while */
806
807 if (CharsRemaining >= 1) {
808 if (*lpwstr == '+') {
809 lpwstr++;
810 CharsRemaining--;
811 } else if (*lpwstr == '-') {
812 bMinus = 1;
813 lpwstr++;
814 CharsRemaining--;
815 } /* if */
816 } /* if */
817
818 if (base == 0) {
819 base = 10;
820 if (CharsRemaining >= 2 && lpwstr[0] == '0') {
821 if (lpwstr[1] == 'b') {
822 lpwstr += 2;
823 CharsRemaining -= 2;
824 base = 2;
825 } else if (lpwstr[1] == 'o') {
826 lpwstr += 2;
827 CharsRemaining -= 2;
828 base = 8;
829 } else if (lpwstr[1] == 'x') {
830 lpwstr += 2;
831 CharsRemaining -= 2;
832 base = 16;
833 } /* if */
834 } /* if */
835 } else if (base != 2 && base != 8 && base != 10 && base != 16) {
836 return STATUS_INVALID_PARAMETER;
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 >= '0' && wchCurrent <= '9') {
846 digit = wchCurrent - '0';
847 } else if (wchCurrent >= 'A' && wchCurrent <= 'Z') {
848 digit = wchCurrent - 'A' + 10;
849 } else if (wchCurrent >= 'a' && wchCurrent <= 'z') {
850 digit = wchCurrent - 'a' + 10;
851 } else {
852 digit = -1;
853 } /* if */
854 if (digit < 0 || digit >= 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 NTAPI
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 NTAPI
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 PAGED_CODE_RTL();
909
910 Length = RtlUnicodeStringToAnsiSize(UniSource);
911 if (Length > MAXUSHORT) return STATUS_INVALID_PARAMETER_2;
912
913 AnsiDest->Length = (USHORT)Length - sizeof(CHAR);
914
915 if (AllocateDestinationString)
916 {
917 AnsiDest->Buffer = RtlpAllocateStringMemory(Length, TAG_ASTR);
918 AnsiDest->MaximumLength = Length;
919 if (!AnsiDest->Buffer) return STATUS_NO_MEMORY;
920 }
921 else if (AnsiDest->Length >= AnsiDest->MaximumLength)
922 {
923 if (!AnsiDest->MaximumLength) return STATUS_BUFFER_OVERFLOW;
924
925 Status = STATUS_BUFFER_OVERFLOW;
926 AnsiDest->Length = AnsiDest->MaximumLength - 1;
927 }
928
929 RealStatus = RtlUnicodeToMultiByteN(AnsiDest->Buffer,
930 AnsiDest->Length,
931 &Index,
932 UniSource->Buffer,
933 UniSource->Length);
934
935 if (!NT_SUCCESS(RealStatus) && AllocateDestinationString)
936 {
937 RtlpFreeStringMemory(AnsiDest->Buffer, TAG_ASTR);
938 return RealStatus;
939 }
940
941 AnsiDest->Buffer[Index] = ANSI_NULL;
942 return Status;
943 }
944
945 /*
946 * @implemented
947 *
948 * NOTES
949 * This function always writes a terminating '\0'.
950 * Does NOT perform a partial copy if unicode is too small!
951 */
952 NTSTATUS
953 NTAPI
954 RtlOemStringToUnicodeString(
955 IN OUT PUNICODE_STRING UniDest,
956 IN PCOEM_STRING OemSource,
957 IN BOOLEAN AllocateDestinationString)
958 {
959 NTSTATUS Status;
960 ULONG Length;
961 ULONG Index;
962
963 PAGED_CODE_RTL();
964
965 Length = RtlOemStringToUnicodeSize(OemSource);
966 if (Length > MAXUSHORT) return STATUS_INVALID_PARAMETER_2;
967
968 UniDest->Length = (USHORT)Length - sizeof(WCHAR);
969
970 if (AllocateDestinationString)
971 {
972 UniDest->Buffer = RtlpAllocateStringMemory(Length, TAG_USTR);
973 UniDest->MaximumLength = Length;
974 if (!UniDest->Buffer) return STATUS_NO_MEMORY;
975 }
976 else if (UniDest->Length >= UniDest->MaximumLength)
977 {
978 return STATUS_BUFFER_OVERFLOW;
979 }
980
981 Status = RtlOemToUnicodeN(UniDest->Buffer,
982 UniDest->Length,
983 &Index,
984 OemSource->Buffer,
985 OemSource->Length);
986
987 if (!NT_SUCCESS(Status) && AllocateDestinationString)
988 {
989 RtlpFreeStringMemory(UniDest->Buffer, TAG_USTR);
990 UniDest->Buffer = NULL;
991 return Status;
992 }
993
994 UniDest->Buffer[Index / sizeof(WCHAR)] = UNICODE_NULL;
995 return Status;
996 }
997
998 /*
999 * @implemented
1000 *
1001 * NOTES
1002 * This function always '\0' terminates the string returned.
1003 */
1004 NTSTATUS
1005 NTAPI
1006 RtlUnicodeStringToOemString(
1007 IN OUT POEM_STRING OemDest,
1008 IN PCUNICODE_STRING UniSource,
1009 IN BOOLEAN AllocateDestinationString)
1010 {
1011 NTSTATUS Status;
1012 ULONG Length;
1013 ULONG Index;
1014
1015 PAGED_CODE_RTL();
1016
1017 Length = RtlUnicodeStringToOemSize(UniSource);
1018 if (Length > MAXUSHORT) return STATUS_INVALID_PARAMETER_2;
1019
1020 OemDest->Length = (USHORT)Length - sizeof(CHAR);
1021
1022 if (AllocateDestinationString)
1023 {
1024 OemDest->Buffer = RtlpAllocateStringMemory(Length, TAG_OSTR);
1025 OemDest->MaximumLength = Length;
1026 if (!OemDest->Buffer) return STATUS_NO_MEMORY;
1027 }
1028 else if (OemDest->Length >= OemDest->MaximumLength)
1029 {
1030 return STATUS_BUFFER_OVERFLOW;
1031 }
1032
1033 Status = RtlUnicodeToOemN(OemDest->Buffer,
1034 OemDest->Length,
1035 &Index,
1036 UniSource->Buffer,
1037 UniSource->Length);
1038
1039 if (!NT_SUCCESS(Status) && AllocateDestinationString)
1040 {
1041 RtlpFreeStringMemory(OemDest->Buffer, TAG_OSTR);
1042 OemDest->Buffer = NULL;
1043 return Status;
1044 }
1045
1046 OemDest->Buffer[Index] = ANSI_NULL;
1047 return Status;
1048 }
1049
1050 #define ITU_IMPLEMENTED_TESTS (IS_TEXT_UNICODE_ODD_LENGTH|IS_TEXT_UNICODE_SIGNATURE)
1051
1052 /*
1053 * @implemented
1054 *
1055 * RETURNS
1056 * The length of the string if all tests were passed, 0 otherwise.
1057 */
1058 BOOLEAN
1059 NTAPI
1060 RtlIsTextUnicode( LPCVOID buf, INT len, INT *pf )
1061 {
1062 const WCHAR *s = buf;
1063 int i;
1064 unsigned int flags = ~0U, out_flags = 0;
1065
1066 if (len < sizeof(WCHAR))
1067 {
1068 /* FIXME: MSDN documents IS_TEXT_UNICODE_BUFFER_TOO_SMALL but there is no such thing... */
1069 if (pf) *pf = 0;
1070 return FALSE;
1071 }
1072 if (pf)
1073 flags = *pf;
1074 /*
1075 * Apply various tests to the text string. According to the
1076 * docs, each test "passed" sets the corresponding flag in
1077 * the output flags. But some of the tests are mutually
1078 * exclusive, so I don't see how you could pass all tests ...
1079 */
1080
1081 /* Check for an odd length ... pass if even. */
1082 if (len & 1) out_flags |= IS_TEXT_UNICODE_ODD_LENGTH;
1083
1084 if (((char *)buf)[len - 1] == 0)
1085 len--; /* Windows seems to do something like that to avoid e.g. false IS_TEXT_UNICODE_NULL_BYTES */
1086
1087 len /= sizeof(WCHAR);
1088 /* Windows only checks the first 256 characters */
1089 if (len > 256) len = 256;
1090
1091 /* Check for the special byte order unicode marks. */
1092 if (*s == 0xFEFF) out_flags |= IS_TEXT_UNICODE_SIGNATURE;
1093 if (*s == 0xFFFE) out_flags |= IS_TEXT_UNICODE_REVERSE_SIGNATURE;
1094
1095 /* apply some statistical analysis */
1096 if (flags & IS_TEXT_UNICODE_STATISTICS)
1097 {
1098 int stats = 0;
1099 /* FIXME: checks only for ASCII characters in the unicode stream */
1100 for (i = 0; i < len; i++)
1101 {
1102 if (s[i] <= 255) stats++;
1103 }
1104 if (stats > len / 2)
1105 out_flags |= IS_TEXT_UNICODE_STATISTICS;
1106 }
1107
1108 /* Check for unicode NULL chars */
1109 if (flags & IS_TEXT_UNICODE_NULL_BYTES)
1110 {
1111 for (i = 0; i < len; i++)
1112 {
1113 if (!(s[i] & 0xff) || !(s[i] >> 8))
1114 {
1115 out_flags |= IS_TEXT_UNICODE_NULL_BYTES;
1116 break;
1117 }
1118 }
1119 }
1120
1121 if (pf)
1122 {
1123 out_flags &= *pf;
1124 *pf = out_flags;
1125 }
1126 /* check for flags that indicate it's definitely not valid Unicode */
1127 if (out_flags & (IS_TEXT_UNICODE_REVERSE_MASK | IS_TEXT_UNICODE_NOT_UNICODE_MASK)) return FALSE;
1128 /* now check for invalid ASCII, and assume Unicode if so */
1129 if (out_flags & IS_TEXT_UNICODE_NOT_ASCII_MASK) return TRUE;
1130 /* now check for Unicode flags */
1131 if (out_flags & IS_TEXT_UNICODE_UNICODE_MASK) return TRUE;
1132 /* no flags set */
1133 return FALSE;
1134 }
1135
1136
1137 /*
1138 * @implemented
1139 *
1140 * NOTES
1141 * Same as RtlOemStringToUnicodeString but doesn't write terminating null
1142 * A partial copy is NOT performed if the dest buffer is too small!
1143 */
1144 NTSTATUS
1145 NTAPI
1146 RtlOemStringToCountedUnicodeString(
1147 IN OUT PUNICODE_STRING UniDest,
1148 IN PCOEM_STRING OemSource,
1149 IN BOOLEAN AllocateDestinationString)
1150 {
1151 NTSTATUS Status;
1152 ULONG Length;
1153 ULONG Index;
1154
1155 PAGED_CODE_RTL();
1156
1157 Length = RtlOemStringToCountedUnicodeSize(OemSource);
1158
1159 if (!Length)
1160 {
1161 RtlZeroMemory(UniDest, sizeof(UNICODE_STRING));
1162 return STATUS_SUCCESS;
1163 }
1164
1165 if (Length > MAXUSHORT) return STATUS_INVALID_PARAMETER_2;
1166
1167 UniDest->Length = (USHORT)Length;
1168
1169 if (AllocateDestinationString)
1170 {
1171 UniDest->Buffer = RtlpAllocateStringMemory(Length, TAG_USTR);
1172 UniDest->MaximumLength = Length;
1173 if (!UniDest->Buffer) return STATUS_NO_MEMORY;
1174 }
1175 else if (UniDest->Length >= UniDest->MaximumLength)
1176 {
1177 return STATUS_BUFFER_OVERFLOW;
1178 }
1179
1180 Status = RtlOemToUnicodeN(UniDest->Buffer,
1181 UniDest->Length,
1182 &Index,
1183 OemSource->Buffer,
1184 OemSource->Length);
1185
1186 if (!NT_SUCCESS(Status) && AllocateDestinationString)
1187 {
1188 RtlpFreeStringMemory(UniDest->Buffer, TAG_USTR);
1189 UniDest->Buffer = NULL;
1190 return Status;
1191 }
1192
1193 return STATUS_SUCCESS;
1194 }
1195
1196 /*
1197 * @implemented
1198 *
1199 * RETURNS
1200 * TRUE if the names are equal, FALSE if not
1201 *
1202 * NOTES
1203 * The comparison is case insensitive.
1204 */
1205 BOOLEAN
1206 NTAPI
1207 RtlEqualComputerName(
1208 IN PUNICODE_STRING ComputerName1,
1209 IN PUNICODE_STRING ComputerName2)
1210 {
1211 OEM_STRING OemString1;
1212 OEM_STRING OemString2;
1213 BOOLEAN Result = FALSE;
1214
1215 if (NT_SUCCESS(RtlUpcaseUnicodeStringToOemString(&OemString1,
1216 ComputerName1,
1217 TRUE)))
1218 {
1219 if (NT_SUCCESS(RtlUpcaseUnicodeStringToOemString(&OemString2,
1220 ComputerName2,
1221 TRUE)))
1222 {
1223 Result = RtlEqualString(&OemString1, &OemString2, FALSE);
1224 RtlFreeOemString(&OemString2);
1225 }
1226 RtlFreeOemString(&OemString1);
1227 }
1228
1229 return Result;
1230 }
1231
1232 /*
1233 * @implemented
1234 *
1235 * RETURNS
1236 * TRUE if the names are equal, FALSE if not
1237 *
1238 * NOTES
1239 * The comparison is case insensitive.
1240 */
1241 BOOLEAN
1242 NTAPI
1243 RtlEqualDomainName (
1244 IN PUNICODE_STRING DomainName1,
1245 IN PUNICODE_STRING DomainName2
1246 )
1247 {
1248 return RtlEqualComputerName(DomainName1, DomainName2);
1249 }
1250
1251 /*
1252 * @implemented
1253 *
1254 * RIPPED FROM WINE's ntdll\rtlstr.c rev 1.45
1255 *
1256 * Convert a string representation of a GUID into a GUID.
1257 *
1258 * PARAMS
1259 * str [I] String representation in the format "{XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX}"
1260 * guid [O] Destination for the converted GUID
1261 *
1262 * RETURNS
1263 * Success: STATUS_SUCCESS. guid contains the converted value.
1264 * Failure: STATUS_INVALID_PARAMETER, if str is not in the expected format.
1265 *
1266 * SEE ALSO
1267 * See RtlStringFromGUID.
1268 */
1269 NTSTATUS
1270 NTAPI
1271 RtlGUIDFromString(
1272 IN UNICODE_STRING *str,
1273 OUT GUID* guid
1274 )
1275 {
1276 int i = 0;
1277 const WCHAR *lpszCLSID = str->Buffer;
1278 BYTE* lpOut = (BYTE*)guid;
1279
1280 //TRACE("(%s,%p)\n", debugstr_us(str), guid);
1281
1282 /* Convert string: {XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX}
1283 * to memory: DWORD... WORD WORD BYTES............
1284 */
1285 while (i <= 37)
1286 {
1287 switch (i)
1288 {
1289 case 0:
1290 if (*lpszCLSID != '{')
1291 return STATUS_INVALID_PARAMETER;
1292 break;
1293
1294 case 9:
1295 case 14:
1296 case 19:
1297 case 24:
1298 if (*lpszCLSID != '-')
1299 return STATUS_INVALID_PARAMETER;
1300 break;
1301
1302 case 37:
1303 if (*lpszCLSID != '}')
1304 return STATUS_INVALID_PARAMETER;
1305 break;
1306
1307 default:
1308 {
1309 WCHAR ch = *lpszCLSID, ch2 = lpszCLSID[1];
1310 unsigned char byte;
1311
1312 /* Read two hex digits as a byte value */
1313 if (ch >= '0' && ch <= '9')
1314 ch = ch - '0';
1315 else if (ch >= 'a' && ch <= 'f')
1316 ch = ch - 'a' + 10;
1317 else if (ch >= 'A' && ch <= 'F')
1318 ch = ch - 'A' + 10;
1319 else
1320 return STATUS_INVALID_PARAMETER;
1321
1322 if (ch2 >= '0' && ch2 <= '9')
1323 ch2 = ch2 - '0';
1324 else if (ch2 >= 'a' && ch2 <= 'f')
1325 ch2 = ch2 - 'a' + 10;
1326 else if (ch2 >= 'A' && ch2 <= 'F')
1327 ch2 = ch2 - 'A' + 10;
1328 else
1329 return STATUS_INVALID_PARAMETER;
1330
1331 byte = ch << 4 | ch2;
1332
1333 switch (i)
1334 {
1335 #ifndef WORDS_BIGENDIAN
1336 /* For Big Endian machines, we store the data such that the
1337 * dword/word members can be read as DWORDS and WORDS correctly. */
1338 /* Dword */
1339 case 1:
1340 lpOut[3] = byte;
1341 break;
1342 case 3:
1343 lpOut[2] = byte;
1344 break;
1345 case 5:
1346 lpOut[1] = byte;
1347 break;
1348 case 7:
1349 lpOut[0] = byte;
1350 lpOut += 4;
1351 break;
1352 /* Word */
1353 case 10:
1354 case 15:
1355 lpOut[1] = byte;
1356 break;
1357 case 12:
1358 case 17:
1359 lpOut[0] = byte;
1360 lpOut += 2;
1361 break;
1362 #endif
1363 /* Byte */
1364 default:
1365 lpOut[0] = byte;
1366 lpOut++;
1367 break;
1368 }
1369 lpszCLSID++; /* Skip 2nd character of byte */
1370 i++;
1371 }
1372 }
1373 lpszCLSID++;
1374 i++;
1375 }
1376
1377 return STATUS_SUCCESS;
1378 }
1379
1380 /*
1381 * @implemented
1382 */
1383 VOID
1384 NTAPI
1385 RtlEraseUnicodeString(
1386 IN PUNICODE_STRING String)
1387 {
1388 if (String->Buffer && String->MaximumLength)
1389 {
1390 RtlZeroMemory(String->Buffer, String->MaximumLength);
1391 String->Length = 0;
1392 }
1393 }
1394
1395 /*
1396 * @implemented
1397 */
1398 NTSTATUS
1399 NTAPI
1400 RtlHashUnicodeString(
1401 IN CONST UNICODE_STRING *String,
1402 IN BOOLEAN CaseInSensitive,
1403 IN ULONG HashAlgorithm,
1404 OUT PULONG HashValue)
1405 {
1406 if (String != NULL && HashValue != NULL)
1407 {
1408 switch (HashAlgorithm)
1409 {
1410 case HASH_STRING_ALGORITHM_DEFAULT:
1411 case HASH_STRING_ALGORITHM_X65599:
1412 {
1413 WCHAR *c, *end;
1414
1415 *HashValue = 0;
1416 end = String->Buffer + (String->Length / sizeof(WCHAR));
1417
1418 if (CaseInSensitive)
1419 {
1420 for (c = String->Buffer;
1421 c != end;
1422 c++)
1423 {
1424 /* only uppercase characters if they are 'a' ... 'z'! */
1425 *HashValue = ((65599 * (*HashValue)) +
1426 (ULONG)(((*c) >= L'a' && (*c) <= L'z') ?
1427 (*c) - L'a' + L'A' : (*c)));
1428 }
1429 }
1430 else
1431 {
1432 for (c = String->Buffer;
1433 c != end;
1434 c++)
1435 {
1436 *HashValue = ((65599 * (*HashValue)) + (ULONG)(*c));
1437 }
1438 }
1439 return STATUS_SUCCESS;
1440 }
1441 }
1442 }
1443
1444 return STATUS_INVALID_PARAMETER;
1445 }
1446
1447 /*
1448 * @implemented
1449 *
1450 * NOTES
1451 * Same as RtlUnicodeStringToOemString but doesn't write terminating null
1452 * Does a partial copy if the dest buffer is too small
1453 */
1454 NTSTATUS
1455 NTAPI
1456 RtlUnicodeStringToCountedOemString(
1457 IN OUT POEM_STRING OemDest,
1458 IN PUNICODE_STRING UniSource,
1459 IN BOOLEAN AllocateDestinationString)
1460 {
1461 NTSTATUS Status;
1462 ULONG Length;
1463 ULONG Index;
1464
1465 PAGED_CODE_RTL();
1466
1467 Length = RtlUnicodeStringToCountedOemSize(UniSource);
1468
1469 if (!Length)
1470 {
1471 RtlZeroMemory(OemDest, sizeof(OEM_STRING));
1472 }
1473
1474 if (Length > MAXUSHORT) return STATUS_INVALID_PARAMETER_2;
1475
1476 OemDest->Length = (USHORT)Length;
1477
1478 if (AllocateDestinationString)
1479 {
1480 OemDest->Buffer = RtlpAllocateStringMemory(Length, TAG_OSTR);
1481 OemDest->MaximumLength = Length;
1482 if (!OemDest->Buffer) return STATUS_NO_MEMORY;
1483 }
1484 else if (OemDest->Length >= OemDest->MaximumLength)
1485 {
1486 return STATUS_BUFFER_OVERFLOW;
1487 }
1488
1489 Status = RtlUnicodeToOemN(OemDest->Buffer,
1490 OemDest->Length,
1491 &Index,
1492 UniSource->Buffer,
1493 UniSource->Length);
1494
1495 /* FIXME: Special check needed and return STATUS_UNMAPPABLE_CHARACTER */
1496
1497 if (!NT_SUCCESS(Status) && AllocateDestinationString)
1498 {
1499 RtlpFreeStringMemory(OemDest->Buffer, TAG_OSTR);
1500 OemDest->Buffer = NULL;
1501 return Status;
1502 }
1503
1504 return Status;
1505 }
1506
1507 /*
1508 * @implemented
1509 */
1510 NTSTATUS
1511 NTAPI
1512 RtlLargeIntegerToChar(
1513 IN PLARGE_INTEGER Value,
1514 IN ULONG Base,
1515 IN ULONG Length,
1516 IN OUT PCHAR String)
1517 {
1518 NTSTATUS Status = STATUS_SUCCESS;
1519 ULONG Radix;
1520 CHAR temp[65];
1521 ULONGLONG v = Value->QuadPart;
1522 ULONG i;
1523 PCHAR tp;
1524 PCHAR sp;
1525
1526 Radix = Base;
1527 if (Radix == 0)
1528 Radix = 10;
1529
1530 if ((Radix != 2) && (Radix != 8) &&
1531 (Radix != 10) && (Radix != 16))
1532 return STATUS_INVALID_PARAMETER;
1533
1534 tp = temp;
1535 while (v || tp == temp)
1536 {
1537 i = v % Radix;
1538 v = v / Radix;
1539 if (i < 10)
1540 *tp = i + '0';
1541 else
1542 *tp = i + 'A' - 10;
1543 tp++;
1544 }
1545
1546 if ((ULONG)((ULONG_PTR)tp - (ULONG_PTR)temp) > Length)
1547 return STATUS_BUFFER_OVERFLOW;
1548
1549 //_SEH_TRY
1550 {
1551 sp = String;
1552 while (tp > temp)
1553 *sp++ = *--tp;
1554
1555 if((ULONG)((ULONG_PTR)sp - (ULONG_PTR)String) < Length)
1556 *sp = 0;
1557 }
1558 #if 0
1559 _SEH_HANDLE
1560 {
1561 /* Get the error code */
1562 Status = _SEH_GetExceptionCode();
1563 }
1564 _SEH_END;
1565 #endif
1566
1567 return Status;
1568 }
1569
1570 /*
1571 * @implemented
1572 *
1573 * NOTES
1574 * dest is never '\0' terminated because it may be equal to src, and src
1575 * might not be '\0' terminated. dest->Length is only set upon success.
1576 */
1577 NTSTATUS
1578 NTAPI
1579 RtlUpcaseUnicodeString(
1580 IN OUT PUNICODE_STRING UniDest,
1581 IN PCUNICODE_STRING UniSource,
1582 IN BOOLEAN AllocateDestinationString)
1583 {
1584 ULONG i, j;
1585
1586 PAGED_CODE_RTL();
1587
1588 if (AllocateDestinationString == TRUE)
1589 {
1590 UniDest->MaximumLength = UniSource->Length;
1591 UniDest->Buffer = RtlpAllocateStringMemory(UniDest->MaximumLength, TAG_USTR);
1592 if (UniDest->Buffer == NULL) return STATUS_NO_MEMORY;
1593 }
1594 else if (UniSource->Length > UniDest->MaximumLength)
1595 {
1596 return STATUS_BUFFER_OVERFLOW;
1597 }
1598
1599 j = UniSource->Length / sizeof(WCHAR);
1600
1601 for (i = 0; i < j; i++)
1602 {
1603 UniDest->Buffer[i] = RtlUpcaseUnicodeChar(UniSource->Buffer[i]);
1604 }
1605
1606 UniDest->Length = UniSource->Length;
1607 return STATUS_SUCCESS;
1608 }
1609
1610 /*
1611 * @implemented
1612 *
1613 * NOTES
1614 * This function always writes a terminating '\0'.
1615 * It performs a partial copy if ansi is too small.
1616 */
1617 NTSTATUS
1618 NTAPI
1619 RtlUpcaseUnicodeStringToAnsiString(
1620 IN OUT PANSI_STRING AnsiDest,
1621 IN PUNICODE_STRING UniSource,
1622 IN BOOLEAN AllocateDestinationString)
1623 {
1624 NTSTATUS Status;
1625 ULONG Length;
1626 ULONG Index;
1627
1628 PAGED_CODE_RTL();
1629
1630 Length = RtlUnicodeStringToAnsiSize(UniSource);
1631 if (Length > MAXUSHORT) return STATUS_INVALID_PARAMETER_2;
1632
1633 AnsiDest->Length = (USHORT)Length - sizeof(CHAR);
1634
1635 if (AllocateDestinationString)
1636 {
1637 AnsiDest->Buffer = RtlpAllocateStringMemory(Length, TAG_ASTR);
1638 AnsiDest->MaximumLength = Length;
1639 if (!AnsiDest->Buffer) return STATUS_NO_MEMORY;
1640 }
1641 else if (AnsiDest->Length >= AnsiDest->MaximumLength)
1642 {
1643 if (!AnsiDest->MaximumLength) return STATUS_BUFFER_OVERFLOW;
1644 }
1645
1646 Status = RtlUpcaseUnicodeToMultiByteN(AnsiDest->Buffer,
1647 AnsiDest->Length,
1648 &Index,
1649 UniSource->Buffer,
1650 UniSource->Length);
1651
1652 if (!NT_SUCCESS(Status) && AllocateDestinationString)
1653 {
1654 RtlpFreeStringMemory(AnsiDest->Buffer, TAG_ASTR);
1655 AnsiDest->Buffer = NULL;
1656 return Status;
1657 }
1658
1659 AnsiDest->Buffer[Index] = ANSI_NULL;
1660 return Status;
1661 }
1662
1663 /*
1664 * @implemented
1665 *
1666 * NOTES
1667 * This function always writes a terminating '\0'.
1668 * It performs a partial copy if ansi is too small.
1669 */
1670 NTSTATUS
1671 NTAPI
1672 RtlUpcaseUnicodeStringToCountedOemString(
1673 IN OUT POEM_STRING OemDest,
1674 IN PCUNICODE_STRING UniSource,
1675 IN BOOLEAN AllocateDestinationString)
1676 {
1677 NTSTATUS Status;
1678 ULONG Length;
1679 ULONG Index;
1680
1681 PAGED_CODE_RTL();
1682
1683 Length = RtlUnicodeStringToCountedOemSize(UniSource);
1684
1685 if (!Length)
1686 {
1687 RtlZeroMemory(OemDest, sizeof(OEM_STRING));
1688 }
1689
1690 if (Length > MAXUSHORT) return STATUS_INVALID_PARAMETER_2;
1691
1692 OemDest->Length = (USHORT)Length;
1693
1694 if (AllocateDestinationString)
1695 {
1696 OemDest->Buffer = RtlpAllocateStringMemory(Length, TAG_OSTR);
1697 OemDest->MaximumLength = Length;
1698 if (!OemDest->Buffer) return STATUS_NO_MEMORY;
1699 }
1700 else if (OemDest->Length > OemDest->MaximumLength)
1701 {
1702 return STATUS_BUFFER_OVERFLOW;
1703 }
1704
1705 Status = RtlUpcaseUnicodeToOemN(OemDest->Buffer,
1706 OemDest->Length,
1707 &Index,
1708 UniSource->Buffer,
1709 UniSource->Length);
1710
1711 /* FIXME: Special check needed and return STATUS_UNMAPPABLE_CHARACTER */
1712
1713 if (!NT_SUCCESS(Status) && AllocateDestinationString)
1714 {
1715 RtlpFreeStringMemory(OemDest->Buffer, TAG_OSTR);
1716 OemDest->Buffer = NULL;
1717 return Status;
1718 }
1719
1720 return Status;
1721 }
1722
1723 /*
1724 * @implemented
1725 * NOTES
1726 * Oem string is allways nullterminated
1727 * It performs a partial copy if oem is too small.
1728 */
1729 NTSTATUS
1730 NTAPI
1731 RtlUpcaseUnicodeStringToOemString (
1732 IN OUT POEM_STRING OemDest,
1733 IN PCUNICODE_STRING UniSource,
1734 IN BOOLEAN AllocateDestinationString)
1735 {
1736 NTSTATUS Status;
1737 ULONG Length;
1738 ULONG Index;
1739
1740 PAGED_CODE_RTL();
1741
1742 Length = RtlUnicodeStringToOemSize(UniSource);
1743 if (Length > MAXUSHORT) return STATUS_INVALID_PARAMETER_2;
1744
1745 OemDest->Length = (USHORT)Length - sizeof(CHAR);
1746
1747 if (AllocateDestinationString)
1748 {
1749 OemDest->Buffer = RtlpAllocateStringMemory(Length, TAG_OSTR);
1750 OemDest->MaximumLength = Length;
1751 if (!OemDest->Buffer) return STATUS_NO_MEMORY;
1752 }
1753 else if (OemDest->Length >= OemDest->MaximumLength)
1754 {
1755 return STATUS_BUFFER_OVERFLOW;
1756 }
1757
1758 Status = RtlUpcaseUnicodeToOemN(OemDest->Buffer,
1759 OemDest->Length,
1760 &Index,
1761 UniSource->Buffer,
1762 UniSource->Length);
1763
1764 /* FIXME: Special check needed and return STATUS_UNMAPPABLE_CHARACTER */
1765
1766 if (!NT_SUCCESS(Status) && AllocateDestinationString)
1767 {
1768 RtlpFreeStringMemory(OemDest->Buffer, TAG_OSTR);
1769 OemDest->Buffer = NULL;
1770 return Status;
1771 }
1772
1773 OemDest->Buffer[Index] = ANSI_NULL;
1774 return Status;
1775 }
1776
1777 /*
1778 * @implemented
1779 *
1780 * RETURNS
1781 * Bytes calculated including nullterm
1782 */
1783 ULONG
1784 NTAPI
1785 RtlxOemStringToUnicodeSize(IN PCOEM_STRING OemString)
1786 {
1787 ULONG Size;
1788
1789 /* Convert the Mb String to Unicode Size */
1790 RtlMultiByteToUnicodeSize(&Size,
1791 OemString->Buffer,
1792 OemString->Length);
1793
1794 /* Return the size + null-char */
1795 return (Size + sizeof(WCHAR));
1796 }
1797
1798 /*
1799 * @implemented
1800 */
1801 NTSTATUS
1802 NTAPI
1803 RtlStringFromGUID (IN REFGUID Guid,
1804 OUT PUNICODE_STRING GuidString)
1805 {
1806 /* Setup the string */
1807 GuidString->Length = 38 * sizeof(WCHAR);
1808 GuidString->MaximumLength = GuidString->Length + sizeof(UNICODE_NULL);
1809 GuidString->Buffer = RtlpAllocateStringMemory(GuidString->MaximumLength,
1810 TAG_USTR);
1811 if (!GuidString->Buffer) return STATUS_NO_MEMORY;
1812
1813 /* Now format the GUID */
1814 swprintf(GuidString->Buffer,
1815 L"{%08lx-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x}",
1816 Guid->Data1,
1817 Guid->Data2,
1818 Guid->Data3,
1819 Guid->Data4[0],
1820 Guid->Data4[1],
1821 Guid->Data4[2],
1822 Guid->Data4[3],
1823 Guid->Data4[4],
1824 Guid->Data4[5],
1825 Guid->Data4[6],
1826 Guid->Data4[7]);
1827 return STATUS_SUCCESS;
1828 }
1829
1830 /*
1831 * @implemented
1832 *
1833 * RETURNS
1834 * Bytes calculated including nullterm
1835 */
1836 ULONG
1837 NTAPI
1838 RtlxUnicodeStringToAnsiSize(IN PCUNICODE_STRING UnicodeString)
1839 {
1840 ULONG Size;
1841
1842 /* Convert the Unicode String to Mb Size */
1843 RtlUnicodeToMultiByteSize(&Size,
1844 UnicodeString->Buffer,
1845 UnicodeString->Length);
1846
1847 /* Return the size + null-char */
1848 return (Size + sizeof(CHAR));
1849 }
1850
1851 /*
1852 * @implemented
1853 */
1854 LONG
1855 NTAPI
1856 RtlCompareUnicodeString(
1857 IN PCUNICODE_STRING s1,
1858 IN PCUNICODE_STRING s2,
1859 IN BOOLEAN CaseInsensitive)
1860 {
1861 unsigned int len;
1862 LONG ret = 0;
1863 LPCWSTR p1, p2;
1864
1865 len = min(s1->Length, s2->Length) / sizeof(WCHAR);
1866 p1 = s1->Buffer;
1867 p2 = s2->Buffer;
1868
1869 if (CaseInsensitive)
1870 {
1871 while (!ret && len--) ret = RtlUpcaseUnicodeChar(*p1++) - RtlUpcaseUnicodeChar(*p2++);
1872 }
1873 else
1874 {
1875 while (!ret && len--) ret = *p1++ - *p2++;
1876 }
1877 if (!ret) ret = s1->Length - s2->Length;
1878 return ret;
1879 }
1880
1881 /*
1882 * @implemented
1883 */
1884 VOID
1885 NTAPI
1886 RtlCopyString(
1887 IN OUT PSTRING DestinationString,
1888 IN PSTRING SourceString OPTIONAL)
1889 {
1890 ULONG SourceLength;
1891 PCHAR p1, p2;
1892
1893 /* Check if there was no source given */
1894 if(!SourceString)
1895 {
1896 /* Simply return an empty string */
1897 DestinationString->Length = 0;
1898 }
1899 else
1900 {
1901 /* Choose the smallest length */
1902 SourceLength = min(DestinationString->MaximumLength,
1903 SourceString->Length);
1904
1905 /* Set it */
1906 DestinationString->Length = (USHORT)SourceLength;
1907
1908 /* Save the pointers to each buffer */
1909 p1 = DestinationString->Buffer;
1910 p2 = SourceString->Buffer;
1911
1912 /* Loop the buffer */
1913 while (SourceLength)
1914 {
1915 /* Copy the character and move on */
1916 *p1++ = * p2++;
1917 SourceLength--;
1918 }
1919 }
1920 }
1921
1922 /*
1923 * @implemented
1924 */
1925 VOID
1926 NTAPI
1927 RtlCopyUnicodeString(
1928 IN OUT PUNICODE_STRING DestinationString,
1929 IN PCUNICODE_STRING SourceString)
1930 {
1931 ULONG SourceLength;
1932
1933 if(SourceString == NULL)
1934 {
1935 DestinationString->Length = 0;
1936 }
1937 else
1938 {
1939 SourceLength = min(DestinationString->MaximumLength,
1940 SourceString->Length);
1941 DestinationString->Length = (USHORT)SourceLength;
1942
1943 RtlCopyMemory(DestinationString->Buffer,
1944 SourceString->Buffer,
1945 SourceLength);
1946
1947 if (DestinationString->Length < DestinationString->MaximumLength)
1948 {
1949 DestinationString->Buffer[SourceLength / sizeof(WCHAR)] = UNICODE_NULL;
1950 }
1951 }
1952 }
1953
1954 /*
1955 * @implemented
1956 *
1957 * NOTES
1958 * Creates a nullterminated UNICODE_STRING
1959 */
1960 BOOLEAN
1961 NTAPI
1962 RtlCreateUnicodeString(
1963 IN OUT PUNICODE_STRING UniDest,
1964 IN PCWSTR Source)
1965 {
1966 ULONG Length;
1967
1968 PAGED_CODE_RTL();
1969
1970 Length = (wcslen(Source) + 1) * sizeof(WCHAR);
1971 if (Length > 0xFFFE) return FALSE;
1972
1973 UniDest->Buffer = RtlpAllocateStringMemory(Length, TAG_USTR);
1974
1975 if (UniDest->Buffer == NULL) return FALSE;
1976
1977 RtlCopyMemory(UniDest->Buffer, Source, Length);
1978 UniDest->MaximumLength = (USHORT)Length;
1979 UniDest->Length = Length - sizeof (WCHAR);
1980
1981 return TRUE;
1982 }
1983
1984 /*
1985 * @implemented
1986 */
1987 BOOLEAN
1988 NTAPI
1989 RtlCreateUnicodeStringFromAsciiz(
1990 OUT PUNICODE_STRING Destination,
1991 IN PCSZ Source)
1992 {
1993 ANSI_STRING AnsiString;
1994 NTSTATUS Status;
1995
1996 RtlInitAnsiString(&AnsiString, Source);
1997
1998 Status = RtlAnsiStringToUnicodeString(Destination,
1999 &AnsiString,
2000 TRUE);
2001
2002 return NT_SUCCESS(Status);
2003 }
2004
2005 /*
2006 * @implemented
2007 *
2008 * NOTES
2009 * Dest is never '\0' terminated because it may be equal to src, and src
2010 * might not be '\0' terminated.
2011 * Dest->Length is only set upon success.
2012 */
2013 NTSTATUS
2014 NTAPI
2015 RtlDowncaseUnicodeString(
2016 IN OUT PUNICODE_STRING UniDest,
2017 IN PCUNICODE_STRING UniSource,
2018 IN BOOLEAN AllocateDestinationString)
2019 {
2020 ULONG i;
2021 ULONG StopGap;
2022
2023 PAGED_CODE_RTL();
2024
2025 if (AllocateDestinationString)
2026 {
2027 UniDest->MaximumLength = UniSource->Length;
2028 UniDest->Buffer = RtlpAllocateStringMemory(UniSource->Length, TAG_USTR);
2029 if (UniDest->Buffer == NULL) return STATUS_NO_MEMORY;
2030 }
2031 else if (UniSource->Length > UniDest->MaximumLength)
2032 {
2033 return STATUS_BUFFER_OVERFLOW;
2034 }
2035
2036 UniDest->Length = UniSource->Length;
2037 StopGap = UniSource->Length / sizeof(WCHAR);
2038
2039 for (i= 0 ; i < StopGap; i++)
2040 {
2041 if (UniSource->Buffer[i] < L'A')
2042 {
2043 UniDest->Buffer[i] = UniSource->Buffer[i];
2044 }
2045 else if (UniSource->Buffer[i] <= L'Z')
2046 {
2047 UniDest->Buffer[i] = (UniSource->Buffer[i] + (L'a' - L'A'));
2048 }
2049 else
2050 {
2051 UniDest->Buffer[i] = RtlDowncaseUnicodeChar(UniSource->Buffer[i]);
2052 }
2053 }
2054
2055 return STATUS_SUCCESS;
2056 }
2057
2058 /*
2059 * @implemented
2060 *
2061 * NOTES
2062 * if src is NULL dest is unchanged.
2063 * dest is '\0' terminated when the MaximumLength allowes it.
2064 * When dest fits exactly in MaximumLength characters the '\0' is ommitted.
2065 */
2066 NTSTATUS
2067 NTAPI
2068 RtlAppendUnicodeToString(IN OUT PUNICODE_STRING Destination,
2069 IN PCWSTR Source)
2070 {
2071 USHORT Length;
2072 PWCHAR DestBuffer;
2073
2074 if (Source)
2075 {
2076 UNICODE_STRING UnicodeSource;
2077
2078 RtlInitUnicodeString(&UnicodeSource, Source);
2079 Length = UnicodeSource.Length;
2080
2081 if (Destination->Length + Length > Destination->MaximumLength)
2082 {
2083 return STATUS_BUFFER_TOO_SMALL;
2084 }
2085
2086 DestBuffer = &Destination->Buffer[Destination->Length / sizeof(WCHAR)];
2087 RtlMoveMemory(DestBuffer, Source, Length);
2088 Destination->Length += Length;
2089
2090 /* append terminating '\0' if enough space */
2091 if(Destination->MaximumLength > Destination->Length)
2092 {
2093 DestBuffer[Length / sizeof(WCHAR)] = UNICODE_NULL;
2094 }
2095 }
2096
2097 return STATUS_SUCCESS;
2098 }
2099
2100 /*
2101 * @implemented
2102 *
2103 * NOTES
2104 * if src is NULL dest is unchanged.
2105 * dest is never '\0' terminated.
2106 */
2107 NTSTATUS
2108 NTAPI
2109 RtlAppendAsciizToString(
2110 IN OUT PSTRING Destination,
2111 IN PCSZ Source)
2112 {
2113 ULONG Length;
2114
2115 if (Source)
2116 {
2117 Length = (USHORT)strlen(Source);
2118
2119 if (Destination->Length + Length > Destination->MaximumLength)
2120 {
2121 return STATUS_BUFFER_TOO_SMALL;
2122 }
2123
2124 RtlMoveMemory(&Destination->Buffer[Destination->Length], Source, Length);
2125 Destination->Length += Length;
2126 }
2127
2128 return STATUS_SUCCESS;
2129 }
2130
2131 /*
2132 * @implemented
2133 */
2134 VOID
2135 NTAPI
2136 RtlUpperString(PSTRING DestinationString,
2137 PSTRING SourceString)
2138 {
2139 ULONG Length;
2140 PCHAR Src, Dest;
2141
2142 Length = min(SourceString->Length,
2143 DestinationString->MaximumLength);
2144
2145 Src = SourceString->Buffer;
2146 Dest = DestinationString->Buffer;
2147 DestinationString->Length = Length;
2148 while (Length)
2149 {
2150 *Dest++ = RtlUpperChar(*Src++);
2151 Length--;
2152 }
2153 }
2154
2155 /*
2156 * @implemented
2157 *
2158 * NOTES
2159 * See RtlpDuplicateUnicodeString
2160 */
2161 NTSTATUS
2162 NTAPI
2163 RtlDuplicateUnicodeString(
2164 IN ULONG Flags,
2165 IN PCUNICODE_STRING SourceString,
2166 OUT PUNICODE_STRING DestinationString)
2167 {
2168 PAGED_CODE_RTL();
2169
2170 if (SourceString == NULL || DestinationString == NULL ||
2171 SourceString->Length > SourceString->MaximumLength ||
2172 (SourceString->Length == 0 && SourceString->MaximumLength > 0 && SourceString->Buffer == NULL) ||
2173 Flags == RTL_DUPLICATE_UNICODE_STRING_ALLOCATE_NULL_STRING || Flags >= 4) {
2174 return STATUS_INVALID_PARAMETER;
2175 }
2176
2177
2178 if ((SourceString->Length == 0) &&
2179 (Flags != (RTL_DUPLICATE_UNICODE_STRING_NULL_TERMINATE |
2180 RTL_DUPLICATE_UNICODE_STRING_ALLOCATE_NULL_STRING)))
2181 {
2182 DestinationString->Length = 0;
2183 DestinationString->MaximumLength = 0;
2184 DestinationString->Buffer = NULL;
2185 }
2186 else
2187 {
2188 UINT DestMaxLength = SourceString->Length;
2189
2190 if (Flags & RTL_DUPLICATE_UNICODE_STRING_NULL_TERMINATE)
2191 DestMaxLength += sizeof(UNICODE_NULL);
2192
2193 DestinationString->Buffer = RtlpAllocateStringMemory(DestMaxLength, TAG_USTR);
2194 if (DestinationString->Buffer == NULL)
2195 return STATUS_NO_MEMORY;
2196
2197 RtlCopyMemory(DestinationString->Buffer, SourceString->Buffer, SourceString->Length);
2198 DestinationString->Length = SourceString->Length;
2199 DestinationString->MaximumLength = DestMaxLength;
2200
2201 if (Flags & RTL_DUPLICATE_UNICODE_STRING_NULL_TERMINATE)
2202 DestinationString->Buffer[DestinationString->Length / sizeof(WCHAR)] = 0;
2203 }
2204
2205 return STATUS_SUCCESS;
2206 }
2207
2208 /*
2209 * @implemented
2210 */
2211 NTSTATUS NTAPI
2212 RtlValidateUnicodeString(IN ULONG Flags,
2213 IN PCUNICODE_STRING UnicodeString)
2214 {
2215 /* currently no flags are supported! */
2216 ASSERT(Flags == 0);
2217
2218 if ((Flags == 0) &&
2219 ((UnicodeString == NULL) ||
2220 ((UnicodeString->Length != 0) &&
2221 (UnicodeString->Buffer != NULL) &&
2222 ((UnicodeString->Length % sizeof(WCHAR)) == 0) &&
2223 ((UnicodeString->MaximumLength % sizeof(WCHAR)) == 0) &&
2224 (UnicodeString->MaximumLength >= UnicodeString->Length))))
2225 {
2226 /* a NULL pointer as a unicode string is considered to be a valid unicode
2227 string! */
2228 return STATUS_SUCCESS;
2229 }
2230 else
2231 {
2232 return STATUS_INVALID_PARAMETER;
2233 }
2234 }
2235
2236 /* EOF */