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