Reactos
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#include <wine/unicode.h>
19
20/* GLOBALS *******************************************************************/
21
22extern BOOLEAN NlsMbCodePageTag;
23extern BOOLEAN NlsMbOemCodePageTag;
24extern PUSHORT NlsLeadByteInfo;
25extern USHORT NlsOemDefaultChar;
26extern USHORT NlsUnicodeDefaultChar;
27extern PUSHORT NlsOemLeadByteInfo;
28extern PWCHAR NlsOemToUnicodeTable;
29extern PCHAR NlsUnicodeToOemTable;
30extern PUSHORT NlsUnicodeToMbOemTable;
31
32
33/* FUNCTIONS *****************************************************************/
34
35NTSTATUS
36NTAPI
37RtlMultiAppendUnicodeStringBuffer(OUT PRTL_UNICODE_STRING_BUFFER StringBuffer,
38 IN ULONG NumberOfAddends,
39 IN PCUNICODE_STRING Addends)
40{
41 UNIMPLEMENTED;
42 return STATUS_NOT_IMPLEMENTED;
43}
44
45/*
46* @implemented
47*/
48WCHAR
49NTAPI
50RtlAnsiCharToUnicodeChar(IN OUT PUCHAR *AnsiChar)
51{
52 ULONG Size;
53 NTSTATUS Status;
54 WCHAR UnicodeChar = L' ';
55 PAGED_CODE_RTL();
56
57 if (NlsLeadByteInfo)
58 {
59 Size = (NlsLeadByteInfo[**AnsiChar] == 0) ? 1 : 2;
60 }
61 else
62 {
63 DPRINT("HACK::Shouldn't have happened! Consider fixing Usetup and registry entries it creates on install\n");
64 Size = 1;
65 }
66
67 Status = RtlMultiByteToUnicodeN(&UnicodeChar,
68 sizeof(WCHAR),
69 NULL,
70 (PCHAR)*AnsiChar,
71 Size);
72
73 if (!NT_SUCCESS(Status))
74 {
75 UnicodeChar = L' ';
76 }
77
78 *AnsiChar += Size;
79 return UnicodeChar;
80}
81
82/*
83 * @implemented
84 *
85 * NOTES
86 * This function always writes a terminating '\0'.
87 * If the dest buffer is too small a partial copy is NOT performed!
88 */
89NTSTATUS
90NTAPI
91RtlAnsiStringToUnicodeString(
92 IN OUT PUNICODE_STRING UniDest,
93 IN PANSI_STRING AnsiSource,
94 IN BOOLEAN AllocateDestinationString)
95{
96 NTSTATUS Status;
97 ULONG Length;
98 ULONG Index;
99
100 PAGED_CODE_RTL();
101
102 if (NlsMbCodePageTag == FALSE)
103 {
104 Length = (AnsiSource->Length + 1) * sizeof(WCHAR);
105 }
106 else
107 {
108 Length = RtlxAnsiStringToUnicodeSize(AnsiSource);
109 }
110 if (Length > MAXUSHORT) return STATUS_INVALID_PARAMETER_2;
111 UniDest->Length = (USHORT)Length - sizeof(WCHAR);
112
113 if (AllocateDestinationString)
114 {
115 UniDest->Buffer = RtlpAllocateStringMemory(Length, TAG_USTR);
116 UniDest->MaximumLength = (USHORT)Length;
117 if (!UniDest->Buffer) return STATUS_NO_MEMORY;
118 }
119 else if (UniDest->Length >= UniDest->MaximumLength)
120 {
121 return STATUS_BUFFER_OVERFLOW;
122 }
123
124 /* UniDest->MaximumLength must be even due to sizeof(WCHAR) being 2 */
125 ASSERT(!(UniDest->MaximumLength & 1) && UniDest->Length <= UniDest->MaximumLength);
126
127 Status = RtlMultiByteToUnicodeN(UniDest->Buffer,
128 UniDest->Length,
129 &Index,
130 AnsiSource->Buffer,
131 AnsiSource->Length);
132
133 if (!NT_SUCCESS(Status))
134 {
135 if (AllocateDestinationString)
136 {
137 RtlpFreeStringMemory(UniDest->Buffer, TAG_USTR);
138 UniDest->Buffer = NULL;
139 }
140
141 return Status;
142 }
143
144 UniDest->Buffer[Index / sizeof(WCHAR)] = UNICODE_NULL;
145 return Status;
146}
147
148/*
149 * @implemented
150 *
151 * RETURNS
152 * The calculated size in bytes including nullterm.
153 */
154ULONG
155NTAPI
156RtlxAnsiStringToUnicodeSize(IN PCANSI_STRING AnsiString)
157{
158 ULONG Size;
159 PAGED_CODE_RTL();
160
161 /* Convert from Mb String to Unicode Size */
162 RtlMultiByteToUnicodeSize(&Size,
163 AnsiString->Buffer,
164 AnsiString->Length);
165
166 /* Return the size plus the null-char */
167 return(Size + sizeof(WCHAR));
168}
169
170/*
171 * @implemented
172 *
173 * NOTES
174 * If src->length is zero dest is unchanged.
175 * Dest is never nullterminated.
176 */
177NTSTATUS
178NTAPI
179RtlAppendStringToString(IN PSTRING Destination,
180 IN const STRING *Source)
181{
182 USHORT SourceLength = Source->Length;
183
184 if (SourceLength)
185 {
186 if (Destination->Length + SourceLength > Destination->MaximumLength)
187 {
188 return STATUS_BUFFER_TOO_SMALL;
189 }
190
191 RtlMoveMemory(&Destination->Buffer[Destination->Length],
192 Source->Buffer,
193 SourceLength);
194
195 Destination->Length += SourceLength;
196 }
197
198 return STATUS_SUCCESS;
199}
200
201/*
202 * @implemented
203 *
204 * NOTES
205 * If src->length is zero dest is unchanged.
206 * Dest is nullterminated when the MaximumLength allowes it.
207 * When dest fits exactly in MaximumLength characters the nullterm is ommitted.
208 */
209NTSTATUS
210NTAPI
211RtlAppendUnicodeStringToString(
212 IN OUT PUNICODE_STRING Destination,
213 IN PCUNICODE_STRING Source)
214{
215 USHORT SourceLength = Source->Length;
216 PWCHAR Buffer = &Destination->Buffer[Destination->Length / sizeof(WCHAR)];
217
218 if (SourceLength)
219 {
220 if ((SourceLength + Destination->Length) > Destination->MaximumLength)
221 {
222 return STATUS_BUFFER_TOO_SMALL;
223 }
224
225 RtlMoveMemory(Buffer, Source->Buffer, SourceLength);
226 Destination->Length += SourceLength;
227
228 /* append terminating '\0' if enough space */
229 if (Destination->MaximumLength > Destination->Length)
230 {
231 Buffer[SourceLength / sizeof(WCHAR)] = UNICODE_NULL;
232 }
233 }
234
235 return STATUS_SUCCESS;
236}
237
238/**************************************************************************
239 * RtlCharToInteger (NTDLL.@)
240 * @implemented
241 * Converts a character string into its integer equivalent.
242 *
243 * RETURNS
244 * Success: STATUS_SUCCESS. value contains the converted number
245 * Failure: STATUS_INVALID_PARAMETER, if base is not 0, 2, 8, 10 or 16.
246 * STATUS_ACCESS_VIOLATION, if value is NULL.
247 *
248 * NOTES
249 * For base 0 it uses 10 as base and the string should be in the format
250 * "{whitespace} [+|-] [0[x|o|b]] {digits}".
251 * For other bases the string should be in the format
252 * "{whitespace} [+|-] {digits}".
253 * No check is made for value overflow, only the lower 32 bits are assigned.
254 * If str is NULL it crashes, as the native function does.
255 *
256 * DIFFERENCES
257 * This function does not read garbage behind '\0' as the native version does.
258 */
259NTSTATUS
260NTAPI
261RtlCharToInteger(
262 PCSZ str, /* [I] '\0' terminated single-byte string containing a number */
263 ULONG base, /* [I] Number base for conversion (allowed 0, 2, 8, 10 or 16) */
264 PULONG value) /* [O] Destination for the converted value */
265{
266 CHAR chCurrent;
267 int digit;
268 ULONG RunningTotal = 0;
269 char bMinus = 0;
270
271 /* skip leading whitespaces */
272 while (*str != '\0' && *str <= ' ') str++;
273
274 /* Check for +/- */
275 if (*str == '+')
276 {
277 str++;
278 }
279 else if (*str == '-')
280 {
281 bMinus = 1;
282 str++;
283 }
284
285 /* base = 0 means autobase */
286 if (base == 0)
287 {
288 base = 10;
289
290 if (str[0] == '0')
291 {
292 if (str[1] == 'b')
293 {
294 str += 2;
295 base = 2;
296 }
297 else if (str[1] == 'o')
298 {
299 str += 2;
300 base = 8;
301 }
302 else if (str[1] == 'x')
303 {
304 str += 2;
305 base = 16;
306 }
307 }
308 }
309 else if (base != 2 && base != 8 && base != 10 && base != 16)
310 {
311 return STATUS_INVALID_PARAMETER;
312 }
313
314 if (value == NULL) return STATUS_ACCESS_VIOLATION;
315
316 while (*str != '\0')
317 {
318 chCurrent = *str;
319
320 if (chCurrent >= '0' && chCurrent <= '9')
321 {
322 digit = chCurrent - '0';
323 }
324 else if (chCurrent >= 'A' && chCurrent <= 'Z')
325 {
326 digit = chCurrent - 'A' + 10;
327 }
328 else if (chCurrent >= 'a' && chCurrent <= 'z')
329 {
330 digit = chCurrent - 'a' + 10;
331 }
332 else
333 {
334 digit = -1;
335 }
336
337 if (digit < 0 || digit >= (int)base) break;
338
339 RunningTotal = RunningTotal * base + digit;
340 str++;
341 }
342
343 *value = bMinus ? (0 - RunningTotal) : RunningTotal;
344 return STATUS_SUCCESS;
345}
346
347/*
348 * @implemented
349 */
350LONG
351NTAPI
352RtlCompareString(
353 IN const STRING *s1,
354 IN const STRING *s2,
355 IN BOOLEAN CaseInsensitive)
356{
357 unsigned int len;
358 LONG ret = 0;
359 LPCSTR p1, p2;
360
361 len = min(s1->Length, s2->Length);
362 p1 = s1->Buffer;
363 p2 = s2->Buffer;
364
365 if (CaseInsensitive)
366 {
367 while (!ret && len--)
368 ret = RtlUpperChar(*p1++) - RtlUpperChar(*p2++);
369 }
370 else
371 {
372 while (!ret && len--) ret = *p1++ - *p2++;
373 }
374
375 if (!ret) ret = s1->Length - s2->Length;
376
377 return ret;
378}
379
380/*
381 * @implemented
382 *
383 * RETURNS
384 * TRUE if strings are equal.
385 */
386BOOLEAN
387NTAPI
388RtlEqualString(
389 IN const STRING *s1,
390 IN const STRING *s2,
391 IN BOOLEAN CaseInsensitive)
392{
393 if (s1->Length != s2->Length) return FALSE;
394 return !RtlCompareString(s1, s2, CaseInsensitive);
395}
396
397/*
398 * @implemented
399 *
400 * RETURNS
401 * TRUE if strings are equal.
402 */
403BOOLEAN
404NTAPI
405RtlEqualUnicodeString(
406 IN CONST UNICODE_STRING *s1,
407 IN CONST UNICODE_STRING *s2,
408 IN BOOLEAN CaseInsensitive)
409{
410 if (s1->Length != s2->Length) return FALSE;
411 return !RtlCompareUnicodeString(s1, s2, CaseInsensitive );
412}
413
414/*
415 * @implemented
416 */
417VOID
418NTAPI
419RtlFreeAnsiString(IN PANSI_STRING AnsiString)
420{
421 PAGED_CODE_RTL();
422
423 if (AnsiString->Buffer)
424 {
425 RtlpFreeStringMemory(AnsiString->Buffer, TAG_ASTR);
426 RtlZeroMemory(AnsiString, sizeof(ANSI_STRING));
427 }
428}
429
430/*
431 * @implemented
432 */
433VOID
434NTAPI
435RtlFreeOemString(IN POEM_STRING OemString)
436{
437 PAGED_CODE_RTL();
438
439 if (OemString->Buffer) RtlpFreeStringMemory(OemString->Buffer, TAG_OSTR);
440}
441
442/*
443 * @implemented
444 */
445VOID
446NTAPI
447RtlFreeUnicodeString(IN PUNICODE_STRING UnicodeString)
448{
449 PAGED_CODE_RTL();
450
451 if (UnicodeString->Buffer)
452 {
453 RtlpFreeStringMemory(UnicodeString->Buffer, TAG_USTR);
454 RtlZeroMemory(UnicodeString, sizeof(UNICODE_STRING));
455 }
456}
457
458
459/*
460 * @implemented
461 *
462 * NOTES
463 * Check the OEM string to match the Unicode string.
464 *
465 * Functions which convert Unicode strings to OEM strings will set a
466 * DefaultChar from the OEM codepage when the characters are unknown.
467 * So check it against the Unicode string and return false when the
468 * Unicode string does not contain a TransDefaultChar.
469 */
470BOOLEAN
471NTAPI
472RtlpDidUnicodeToOemWork(IN PCUNICODE_STRING UnicodeString,
473 IN POEM_STRING OemString)
474{
475 ULONG i = 0;
476
477 if (NlsMbOemCodePageTag == FALSE)
478 {
479 /* single-byte code page */
480 /* Go through all characters of a string */
481 while (i < OemString->Length)
482 {
483 /* Check if it got translated into a default char,
484 * but source char wasn't a default char equivalent
485 */
486 if ((OemString->Buffer[i] == NlsOemDefaultChar) &&
487 (UnicodeString->Buffer[i] != NlsUnicodeDefaultChar))
488 {
489 /* Yes, it means unmappable characters were found */
490 return FALSE;
491 }
492
493 /* Move to the next char */
494 i++;
495 }
496
497 /* All chars were translated successfuly */
498 return TRUE;
499 }
500 else
501 {
502 /* multibyte code page */
503
504 /* FIXME */
505 return TRUE;
506 }
507}
508
509/*
510* @implemented
511*/
512BOOLEAN
513NTAPI
514RtlIsValidOemCharacter(IN PWCHAR Char)
515{
516 WCHAR UnicodeChar;
517 WCHAR OemChar;
518
519 /* If multi-byte code page present */
520 if (NlsMbOemCodePageTag)
521 {
522 USHORT Offset;
523
524 OemChar = NlsUnicodeToMbOemTable[*Char];
525
526 /* If character has Lead Byte */
527 Offset = NlsOemLeadByteInfo[HIBYTE(OemChar)];
528 if (Offset)
529 {
530 /* Use DBCS table */
531 UnicodeChar = NlsOemLeadByteInfo[Offset + LOBYTE(OemChar)];
532 }
533 else
534 {
535 UnicodeChar = NlsOemToUnicodeTable[OemChar];
536 }
537
538 /* Upcase */
539 UnicodeChar = RtlpUpcaseUnicodeChar(UnicodeChar);
540
541 /* Receive OEM character from the table */
542 OemChar = NlsUnicodeToMbOemTable[UnicodeChar];
543 }
544 else
545 {
546 /* Receive Unicode character from the table */
547 UnicodeChar = RtlpUpcaseUnicodeChar(NlsOemToUnicodeTable[(UCHAR)NlsUnicodeToOemTable[*Char]]);
548
549 /* Receive OEM character from the table */
550 OemChar = NlsUnicodeToOemTable[UnicodeChar];
551 }
552
553 /* Not valid character, failed */
554 if (OemChar == NlsOemDefaultChar)
555 {
556 DPRINT1("\\u%04x is not valid for OEM\n", *Char);
557 return FALSE;
558 }
559
560 *Char = UnicodeChar;
561
562 return TRUE;
563}
564
565/*
566 * @implemented
567 *
568 * NOTES
569 * If source is NULL the length of source is assumed to be 0.
570 */
571VOID
572NTAPI
573RtlInitAnsiString(IN OUT PANSI_STRING DestinationString,
574 IN PCSZ SourceString)
575{
576 SIZE_T Size;
577
578 if (SourceString)
579 {
580 Size = strlen(SourceString);
581 if (Size > (MAXUSHORT - sizeof(CHAR))) Size = MAXUSHORT - sizeof(CHAR);
582 DestinationString->Length = (USHORT)Size;
583 DestinationString->MaximumLength = (USHORT)Size + sizeof(CHAR);
584 }
585 else
586 {
587 DestinationString->Length = 0;
588 DestinationString->MaximumLength = 0;
589 }
590
591 DestinationString->Buffer = (PCHAR)SourceString;
592}
593
594NTSTATUS
595NTAPI
596RtlInitAnsiStringEx(IN OUT PANSI_STRING DestinationString,
597 IN PCSZ SourceString)
598{
599 SIZE_T Size;
600
601 if (SourceString)
602 {
603 Size = strlen(SourceString);
604 if (Size > (MAXUSHORT - sizeof(CHAR))) return STATUS_NAME_TOO_LONG;
605 DestinationString->Length = (USHORT)Size;
606 DestinationString->MaximumLength = (USHORT)Size + sizeof(CHAR);
607 }
608 else
609 {
610 DestinationString->Length = 0;
611 DestinationString->MaximumLength = 0;
612 }
613
614 DestinationString->Buffer = (PCHAR)SourceString;
615 return STATUS_SUCCESS;
616
617}
618/*
619 * @implemented
620 *
621 * NOTES
622 * If source is NULL the length of source is assumed to be 0.
623 */
624VOID
625NTAPI
626RtlInitString(
627 IN OUT PSTRING DestinationString,
628 IN PCSZ SourceString)
629{
630 RtlInitAnsiString(DestinationString, SourceString);
631}
632
633/*
634 * @implemented
635 *
636 * NOTES
637 * If source is NULL the length of source is assumed to be 0.
638 */
639VOID
640NTAPI
641RtlInitUnicodeString(
642 IN OUT PUNICODE_STRING DestinationString,
643 IN PCWSTR SourceString)
644{
645 SIZE_T Size;
646 CONST SIZE_T MaxSize = (MAXUSHORT & ~1) - sizeof(UNICODE_NULL); // an even number
647
648 if (SourceString)
649 {
650 Size = wcslen(SourceString) * sizeof(WCHAR);
651 __analysis_assume(Size <= MaxSize);
652
653 if (Size > MaxSize)
654 Size = MaxSize;
655 DestinationString->Length = (USHORT)Size;
656 DestinationString->MaximumLength = (USHORT)Size + sizeof(UNICODE_NULL);
657 }
658 else
659 {
660 DestinationString->Length = 0;
661 DestinationString->MaximumLength = 0;
662 }
663
664 DestinationString->Buffer = (PWCHAR)SourceString;
665}
666
667/*
668 * @implemented
669 */
670NTSTATUS
671NTAPI
672RtlInitUnicodeStringEx(
673 OUT PUNICODE_STRING DestinationString,
674 IN PCWSTR SourceString)
675{
676 SIZE_T Size;
677 CONST SIZE_T MaxSize = (MAXUSHORT & ~1) - sizeof(WCHAR); // an even number
678
679 if (SourceString)
680 {
681 Size = wcslen(SourceString) * sizeof(WCHAR);
682 if (Size > MaxSize) return STATUS_NAME_TOO_LONG;
683 DestinationString->Length = (USHORT)Size;
684 DestinationString->MaximumLength = (USHORT)Size + sizeof(WCHAR);
685 }
686 else
687 {
688 DestinationString->Length = 0;
689 DestinationString->MaximumLength = 0;
690 }
691
692 DestinationString->Buffer = (PWCHAR)SourceString;
693 return STATUS_SUCCESS;
694}
695
696/*
697 * @implemented
698 *
699 * NOTES
700 * Writes at most length characters to the string str.
701 * Str is nullterminated when length allowes it.
702 * When str fits exactly in length characters the nullterm is ommitted.
703 */
704NTSTATUS NTAPI RtlIntegerToChar(
705 ULONG value, /* [I] Value to be converted */
706 ULONG base, /* [I] Number base for conversion (allowed 0, 2, 8, 10 or 16) */
707 ULONG length, /* [I] Length of the str buffer in bytes */
708 PCHAR str) /* [O] Destination for the converted value */
709{
710 CHAR buffer[33];
711 PCHAR pos;
712 CHAR digit;
713 SIZE_T len;
714
715 if (base == 0)
716 {
717 base = 10;
718 }
719 else if (base != 2 && base != 8 && base != 10 && base != 16)
720 {
721 return STATUS_INVALID_PARAMETER;
722 }
723
724 pos = &buffer[32];
725 *pos = '\0';
726
727 do
728 {
729 pos--;
730 digit = (CHAR)(value % base);
731 value = value / base;
732
733 if (digit < 10)
734 {
735 *pos = '0' + digit;
736 }
737 else
738 {
739 *pos = 'A' + digit - 10;
740 }
741 }
742 while (value != 0L);
743
744 len = &buffer[32] - pos;
745
746 if (len > length)
747 {
748 return STATUS_BUFFER_OVERFLOW;
749 }
750 else if (str == NULL)
751 {
752 return STATUS_ACCESS_VIOLATION;
753 }
754 else if (len == length)
755 {
756 RtlCopyMemory(str, pos, len);
757 }
758 else
759 {
760 RtlCopyMemory(str, pos, len + 1);
761 }
762
763 return STATUS_SUCCESS;
764}
765
766/*
767 * @implemented
768 */
769NTSTATUS
770NTAPI
771RtlIntegerToUnicode(
772 IN ULONG Value,
773 IN ULONG Base OPTIONAL,
774 IN ULONG Length OPTIONAL,
775 IN OUT LPWSTR String)
776{
777 ULONG Radix;
778 WCHAR temp[33];
779 ULONG v = Value;
780 ULONG i;
781 PWCHAR tp;
782 PWCHAR sp;
783
784 Radix = Base;
785
786 if (Radix == 0) Radix = 10;
787
788 if ((Radix != 2) && (Radix != 8) &&
789 (Radix != 10) && (Radix != 16))
790 {
791 return STATUS_INVALID_PARAMETER;
792 }
793
794 tp = temp;
795
796 while (v || tp == temp)
797 {
798 i = v % Radix;
799 v = v / Radix;
800
801 if (i < 10) *tp = (WCHAR)(i + L'0');
802 else *tp = (WCHAR)(i + L'a' - 10);
803
804 tp++;
805 }
806
807 if ((ULONG)((ULONG_PTR)tp - (ULONG_PTR)temp) >= Length)
808 {
809 return STATUS_BUFFER_TOO_SMALL;
810 }
811
812 sp = String;
813
814 while (tp > temp) *sp++ = *--tp;
815
816 *sp = 0;
817
818 return STATUS_SUCCESS;
819}
820
821/*
822 * @implemented
823 */
824NTSTATUS
825NTAPI
826RtlIntegerToUnicodeString(
827 IN ULONG Value,
828 IN ULONG Base OPTIONAL,
829 IN OUT PUNICODE_STRING String)
830{
831 ANSI_STRING AnsiString;
832 CHAR Buffer[33];
833 NTSTATUS Status;
834
835 Status = RtlIntegerToChar(Value, Base, sizeof(Buffer), Buffer);
836 if (NT_SUCCESS(Status))
837 {
838 AnsiString.Buffer = Buffer;
839 AnsiString.Length = (USHORT)strlen(Buffer);
840 AnsiString.MaximumLength = sizeof(Buffer);
841
842 Status = RtlAnsiStringToUnicodeString(String, &AnsiString, FALSE);
843 }
844
845 return Status;
846}
847
848/*
849 * @implemented
850 */
851NTSTATUS
852NTAPI
853RtlInt64ToUnicodeString (
854 IN ULONGLONG Value,
855 IN ULONG Base OPTIONAL,
856 IN OUT PUNICODE_STRING String)
857{
858 LARGE_INTEGER LargeInt;
859 ANSI_STRING AnsiString;
860 CHAR Buffer[65];
861 NTSTATUS Status;
862
863 LargeInt.QuadPart = Value;
864
865 Status = RtlLargeIntegerToChar(&LargeInt, Base, sizeof(Buffer), Buffer);
866 if (NT_SUCCESS(Status))
867 {
868 AnsiString.Buffer = Buffer;
869 AnsiString.Length = (USHORT)strlen(Buffer);
870 AnsiString.MaximumLength = sizeof(Buffer);
871
872 Status = RtlAnsiStringToUnicodeString(String, &AnsiString, FALSE);
873 }
874
875 return Status;
876}
877
878/*
879 * @implemented
880 *
881 * RETURNS
882 * TRUE if String2 contains String1 as a prefix.
883 */
884BOOLEAN
885NTAPI
886RtlPrefixString(
887 const STRING *String1,
888 const STRING *String2,
889 BOOLEAN CaseInsensitive)
890{
891 PCHAR pc1;
892 PCHAR pc2;
893 ULONG NumChars;
894
895 if (String2->Length < String1->Length)
896 return FALSE;
897
898 NumChars = String1->Length;
899 pc1 = String1->Buffer;
900 pc2 = String2->Buffer;
901
902 if (pc1 && pc2)
903 {
904 if (CaseInsensitive)
905 {
906 while (NumChars--)
907 {
908 if (RtlUpperChar(*pc1++) != RtlUpperChar(*pc2++))
909 return FALSE;
910 }
911 }
912 else
913 {
914 while (NumChars--)
915 {
916 if (*pc1++ != *pc2++)
917 return FALSE;
918 }
919 }
920
921 return TRUE;
922 }
923
924 return FALSE;
925}
926
927/*
928 * @implemented
929 *
930 * RETURNS
931 * TRUE if String2 contains String1 as a prefix.
932 */
933BOOLEAN
934NTAPI
935RtlPrefixUnicodeString(
936 PCUNICODE_STRING String1,
937 PCUNICODE_STRING String2,
938 BOOLEAN CaseInsensitive)
939{
940 PWCHAR pc1;
941 PWCHAR pc2;
942 ULONG NumChars;
943
944 if (String2->Length < String1->Length)
945 return FALSE;
946
947 NumChars = String1->Length / sizeof(WCHAR);
948 pc1 = String1->Buffer;
949 pc2 = String2->Buffer;
950
951 if (pc1 && pc2)
952 {
953 if (CaseInsensitive)
954 {
955 while (NumChars--)
956 {
957 if (RtlpUpcaseUnicodeChar(*pc1++) !=
958 RtlpUpcaseUnicodeChar(*pc2++))
959 return FALSE;
960 }
961 }
962 else
963 {
964 while (NumChars--)
965 {
966 if (*pc1++ != *pc2++)
967 return FALSE;
968 }
969 }
970
971 return TRUE;
972 }
973
974 return FALSE;
975}
976
977/*
978 * @implemented
979 */
980NTSTATUS
981NTAPI
982RtlUnicodeStringToInteger(
983 const UNICODE_STRING *str, /* [I] Unicode string to be converted */
984 ULONG base, /* [I] Number base for conversion (allowed 0, 2, 8, 10 or 16) */
985 ULONG *value) /* [O] Destination for the converted value */
986{
987 LPWSTR lpwstr = str->Buffer;
988 USHORT CharsRemaining = str->Length / sizeof(WCHAR);
989 WCHAR wchCurrent;
990 int digit;
991 ULONG RunningTotal = 0;
992 char bMinus = 0;
993
994 while (CharsRemaining >= 1 && *lpwstr <= ' ')
995 {
996 lpwstr++;
997 CharsRemaining--;
998 }
999
1000 if (CharsRemaining >= 1)
1001 {
1002 if (*lpwstr == '+')
1003 {
1004 lpwstr++;
1005 CharsRemaining--;
1006 }
1007 else if (*lpwstr == '-')
1008 {
1009 bMinus = 1;
1010 lpwstr++;
1011 CharsRemaining--;
1012 }
1013 }
1014
1015 if (base == 0)
1016 {
1017 base = 10;
1018
1019 if (CharsRemaining >= 2 && lpwstr[0] == '0')
1020 {
1021 if (lpwstr[1] == 'b')
1022 {
1023 lpwstr += 2;
1024 CharsRemaining -= 2;
1025 base = 2;
1026 }
1027 else if (lpwstr[1] == 'o')
1028 {
1029 lpwstr += 2;
1030 CharsRemaining -= 2;
1031 base = 8;
1032 }
1033 else if (lpwstr[1] == 'x')
1034 {
1035 lpwstr += 2;
1036 CharsRemaining -= 2;
1037 base = 16;
1038 }
1039 }
1040 }
1041 else if (base != 2 && base != 8 && base != 10 && base != 16)
1042 {
1043 return STATUS_INVALID_PARAMETER;
1044 }
1045
1046 if (value == NULL)
1047 {
1048 return STATUS_ACCESS_VIOLATION;
1049 }
1050
1051 while (CharsRemaining >= 1)
1052 {
1053 wchCurrent = *lpwstr;
1054
1055 if (wchCurrent >= '0' && wchCurrent <= '9')
1056 {
1057 digit = wchCurrent - '0';
1058 }
1059 else if (wchCurrent >= 'A' && wchCurrent <= 'Z')
1060 {
1061 digit = wchCurrent - 'A' + 10;
1062 }
1063 else if (wchCurrent >= 'a' && wchCurrent <= 'z')
1064 {
1065 digit = wchCurrent - 'a' + 10;
1066 }
1067 else
1068 {
1069 digit = -1;
1070 }
1071
1072 if (digit < 0 || (ULONG)digit >= base) break;
1073
1074 RunningTotal = RunningTotal * base + digit;
1075 lpwstr++;
1076 CharsRemaining--;
1077 }
1078
1079 *value = bMinus ? (0 - RunningTotal) : RunningTotal;
1080 return STATUS_SUCCESS;
1081}
1082
1083/*
1084 * @implemented
1085 *
1086 * RETURNS
1087 * Bytes necessary for the conversion including nullterm.
1088 */
1089ULONG
1090NTAPI
1091RtlxUnicodeStringToOemSize(IN PCUNICODE_STRING UnicodeString)
1092{
1093 ULONG Size;
1094
1095 /* Convert the Unicode String to Mb Size */
1096 RtlUnicodeToMultiByteSize(&Size,
1097 UnicodeString->Buffer,
1098 UnicodeString->Length);
1099
1100 /* Return the size + the null char */
1101 return (Size + sizeof(CHAR));
1102}
1103
1104/*
1105 * @implemented
1106 *
1107 * NOTES
1108 * This function always writes a terminating '\0'.
1109 * It performs a partial copy if ansi is too small.
1110 */
1111NTSTATUS
1112NTAPI
1113RtlUnicodeStringToAnsiString(
1114 IN OUT PANSI_STRING AnsiDest,
1115 IN PCUNICODE_STRING UniSource,
1116 IN BOOLEAN AllocateDestinationString)
1117{
1118 NTSTATUS Status = STATUS_SUCCESS;
1119 NTSTATUS RealStatus;
1120 ULONG Length;
1121 ULONG Index;
1122
1123 PAGED_CODE_RTL();
1124
1125 ASSERT(!(UniSource->Length & 1));
1126
1127 if (NlsMbCodePageTag == FALSE)
1128 {
1129 Length = (UniSource->Length + sizeof(WCHAR)) / sizeof(WCHAR);
1130 }
1131 else
1132 {
1133 Length = RtlxUnicodeStringToAnsiSize(UniSource);
1134 }
1135
1136 if (Length > MAXUSHORT) return STATUS_INVALID_PARAMETER_2;
1137
1138 AnsiDest->Length = (USHORT)Length - sizeof(CHAR);
1139
1140 if (AllocateDestinationString)
1141 {
1142 AnsiDest->Buffer = RtlpAllocateStringMemory(Length, TAG_ASTR);
1143 AnsiDest->MaximumLength = (USHORT)Length;
1144
1145 if (!AnsiDest->Buffer) return STATUS_NO_MEMORY;
1146 }
1147 else if (AnsiDest->Length >= AnsiDest->MaximumLength)
1148 {
1149 if (!AnsiDest->MaximumLength) return STATUS_BUFFER_OVERFLOW;
1150
1151 Status = STATUS_BUFFER_OVERFLOW;
1152 AnsiDest->Length = AnsiDest->MaximumLength - 1;
1153 }
1154
1155 RealStatus = RtlUnicodeToMultiByteN(AnsiDest->Buffer,
1156 AnsiDest->Length,
1157 &Index,
1158 UniSource->Buffer,
1159 UniSource->Length);
1160
1161 if (!NT_SUCCESS(RealStatus) && AllocateDestinationString)
1162 {
1163 RtlpFreeStringMemory(AnsiDest->Buffer, TAG_ASTR);
1164 return RealStatus;
1165 }
1166
1167 AnsiDest->Buffer[Index] = ANSI_NULL;
1168 return Status;
1169}
1170
1171/*
1172 * @implemented
1173 *
1174 * NOTES
1175 * This function always writes a terminating '\0'.
1176 * Does NOT perform a partial copy if unicode is too small!
1177 */
1178NTSTATUS
1179NTAPI
1180RtlOemStringToUnicodeString(
1181 IN OUT PUNICODE_STRING UniDest,
1182 IN PCOEM_STRING OemSource,
1183 IN BOOLEAN AllocateDestinationString)
1184{
1185 NTSTATUS Status;
1186 ULONG Length;
1187 ULONG Index;
1188
1189 PAGED_CODE_RTL();
1190
1191 Length = RtlOemStringToUnicodeSize(OemSource);
1192
1193 if (Length > MAXUSHORT) return STATUS_INVALID_PARAMETER_2;
1194
1195 UniDest->Length = (USHORT)Length - sizeof(WCHAR);
1196
1197 if (AllocateDestinationString)
1198 {
1199 UniDest->Buffer = RtlpAllocateStringMemory(Length, TAG_USTR);
1200 UniDest->MaximumLength = (USHORT)Length;
1201
1202 if (!UniDest->Buffer) return STATUS_NO_MEMORY;
1203 }
1204 else if (UniDest->Length >= UniDest->MaximumLength)
1205 {
1206 return STATUS_BUFFER_OVERFLOW;
1207 }
1208
1209 Status = RtlOemToUnicodeN(UniDest->Buffer,
1210 UniDest->Length,
1211 &Index,
1212 OemSource->Buffer,
1213 OemSource->Length);
1214
1215 if (!NT_SUCCESS(Status) && AllocateDestinationString)
1216 {
1217 RtlpFreeStringMemory(UniDest->Buffer, TAG_USTR);
1218 UniDest->Buffer = NULL;
1219 return Status;
1220 }
1221
1222 UniDest->Buffer[Index / sizeof(WCHAR)] = UNICODE_NULL;
1223 return Status;
1224}
1225
1226/*
1227 * @implemented
1228 *
1229 * NOTES
1230 * This function always '\0' terminates the string returned.
1231 */
1232NTSTATUS
1233NTAPI
1234RtlUnicodeStringToOemString(
1235 IN OUT POEM_STRING OemDest,
1236 IN PCUNICODE_STRING UniSource,
1237 IN BOOLEAN AllocateDestinationString)
1238{
1239 NTSTATUS Status;
1240 ULONG Length;
1241 ULONG Index;
1242
1243 PAGED_CODE_RTL();
1244
1245 Length = RtlUnicodeStringToOemSize(UniSource);
1246
1247 if (Length > MAXUSHORT) return STATUS_INVALID_PARAMETER_2;
1248
1249 OemDest->Length = (USHORT)Length - sizeof(CHAR);
1250
1251 if (AllocateDestinationString)
1252 {
1253 OemDest->Buffer = RtlpAllocateStringMemory(Length, TAG_OSTR);
1254 OemDest->MaximumLength = (USHORT)Length;
1255
1256 if (!OemDest->Buffer) return STATUS_NO_MEMORY;
1257 }
1258 else if (OemDest->Length >= OemDest->MaximumLength)
1259 {
1260 return STATUS_BUFFER_OVERFLOW;
1261 }
1262
1263 Status = RtlUnicodeToOemN(OemDest->Buffer,
1264 OemDest->Length,
1265 &Index,
1266 UniSource->Buffer,
1267 UniSource->Length);
1268
1269 if (!NT_SUCCESS(Status) && AllocateDestinationString)
1270 {
1271 RtlpFreeStringMemory(OemDest->Buffer, TAG_OSTR);
1272 OemDest->Buffer = NULL;
1273 return Status;
1274 }
1275
1276 OemDest->Buffer[Index] = ANSI_NULL;
1277 return Status;
1278}
1279
1280#define ITU_IMPLEMENTED_TESTS (IS_TEXT_UNICODE_ODD_LENGTH|IS_TEXT_UNICODE_SIGNATURE)
1281
1282/*
1283 * @implemented
1284 *
1285 * RETURNS
1286 * The length of the string if all tests were passed, 0 otherwise.
1287 */
1288BOOLEAN
1289NTAPI
1290RtlIsTextUnicode(CONST VOID* buf, INT len, INT* pf)
1291{
1292 static const WCHAR std_control_chars[] = {'\r', '\n', '\t', ' ', 0x3000, 0};
1293 static const WCHAR byterev_control_chars[] = {0x0d00, 0x0a00, 0x0900, 0x2000, 0};
1294 const WCHAR *s = buf;
1295 int i;
1296 unsigned int flags = MAXULONG, out_flags = 0;
1297 UCHAR last_lo_byte = 0;
1298 UCHAR last_hi_byte = 0;
1299 ULONG hi_byte_diff = 0;
1300 ULONG lo_byte_diff = 0;
1301 ULONG weight = 3;
1302 ULONG lead_byte = 0;
1303
1304 if (len < sizeof(WCHAR))
1305 {
1306 /* FIXME: MSDN documents IS_TEXT_UNICODE_BUFFER_TOO_SMALL but there is no such thing... */
1307 if (pf) *pf = 0;
1308
1309 return FALSE;
1310 }
1311
1312 if (pf)
1313 flags = *pf;
1314
1315 /*
1316 * Apply various tests to the text string. According to the
1317 * docs, each test "passed" sets the corresponding flag in
1318 * the output flags. But some of the tests are mutually
1319 * exclusive, so I don't see how you could pass all tests ...
1320 */
1321
1322 /* Check for an odd length ... pass if even. */
1323 if (len & 1) out_flags |= IS_TEXT_UNICODE_ODD_LENGTH;
1324
1325 if (((char *)buf)[len - 1] == 0)
1326 len--; /* Windows seems to do something like that to avoid e.g. false IS_TEXT_UNICODE_NULL_BYTES */
1327
1328 len /= sizeof(WCHAR);
1329
1330 /* Windows only checks the first 256 characters */
1331 if (len > 256) len = 256;
1332
1333 /* Check for the special byte order unicode marks. */
1334 if (*s == 0xFEFF) out_flags |= IS_TEXT_UNICODE_SIGNATURE;
1335 if (*s == 0xFFFE) out_flags |= IS_TEXT_UNICODE_REVERSE_SIGNATURE;
1336
1337 for (i = 0; i < len; i++)
1338 {
1339 UCHAR lo_byte = LOBYTE(s[i]);
1340 UCHAR hi_byte = HIBYTE(s[i]);
1341
1342 lo_byte_diff += max(lo_byte, last_lo_byte) - min(lo_byte, last_lo_byte);
1343 hi_byte_diff += max(hi_byte, last_hi_byte) - min(hi_byte, last_hi_byte);
1344
1345 last_lo_byte = lo_byte;
1346 last_hi_byte = hi_byte;
1347
1348 switch (s[i])
1349 {
1350 case 0xFFFE: /* Reverse BOM */
1351 case UNICODE_NULL:
1352 case 0x0A0D: /* ASCII CRLF (packed into one word) */
1353 case 0xFFFF: /* Unicode 0xFFFF */
1354 out_flags |= IS_TEXT_UNICODE_ILLEGAL_CHARS;
1355 break;
1356 }
1357 }
1358
1359 if (NlsMbCodePageTag && pf && (*pf & IS_TEXT_UNICODE_DBCS_LEADBYTE))
1360 {
1361 for (i = 0; i < len; i++)
1362 {
1363 if (NlsLeadByteInfo[s[i]])
1364 {
1365 ++lead_byte;
1366 ++i;
1367 }
1368 }
1369
1370 if (lead_byte)
1371 {
1372 weight = (len / 2) - 1;
1373
1374 if (lead_byte < (weight / 3))
1375 weight = 3;
1376 else if (lead_byte < ((weight * 2) / 3))
1377 weight = 2;
1378 else
1379 weight = 1;
1380
1381 out_flags |= IS_TEXT_UNICODE_DBCS_LEADBYTE;
1382 }
1383 }
1384
1385 if (lo_byte_diff < 127 && !hi_byte_diff)
1386 {
1387 out_flags |= IS_TEXT_UNICODE_ASCII16;
1388 }
1389
1390 if (hi_byte_diff && !lo_byte_diff)
1391 {
1392 out_flags |= IS_TEXT_UNICODE_REVERSE_ASCII16;
1393 }
1394
1395 if ((weight * lo_byte_diff) < hi_byte_diff)
1396 {
1397 out_flags |= IS_TEXT_UNICODE_REVERSE_STATISTICS;
1398 }
1399
1400 /* apply some statistical analysis */
1401 if ((flags & IS_TEXT_UNICODE_STATISTICS) &&
1402 ((weight * hi_byte_diff) < lo_byte_diff))
1403 {
1404 out_flags |= IS_TEXT_UNICODE_STATISTICS;
1405 }
1406
1407 /* Check for unicode NULL chars */
1408 if (flags & IS_TEXT_UNICODE_NULL_BYTES)
1409 {
1410 for (i = 0; i < len; i++)
1411 {
1412 if (!(s[i] & 0xff) || !(s[i] >> 8))
1413 {
1414 out_flags |= IS_TEXT_UNICODE_NULL_BYTES;
1415 break;
1416 }
1417 }
1418 }
1419
1420 if (flags & IS_TEXT_UNICODE_CONTROLS)
1421 {
1422 for (i = 0; i < len; i++)
1423 {
1424 if (strchrW(std_control_chars, s[i]))
1425 {
1426 out_flags |= IS_TEXT_UNICODE_CONTROLS;
1427 break;
1428 }
1429 }
1430 }
1431
1432 if (flags & IS_TEXT_UNICODE_REVERSE_CONTROLS)
1433 {
1434 for (i = 0; i < len; i++)
1435 {
1436 if (strchrW(byterev_control_chars, s[i]))
1437 {
1438 out_flags |= IS_TEXT_UNICODE_REVERSE_CONTROLS;
1439 break;
1440 }
1441 }
1442 }
1443
1444 if (pf)
1445 {
1446 out_flags &= *pf;
1447 *pf = out_flags;
1448 }
1449
1450 /* check for flags that indicate it's definitely not valid Unicode */
1451 if (out_flags & (IS_TEXT_UNICODE_REVERSE_MASK | IS_TEXT_UNICODE_NOT_UNICODE_MASK)) return FALSE;
1452
1453 /* now check for invalid ASCII, and assume Unicode if so */
1454 if (out_flags & IS_TEXT_UNICODE_NOT_ASCII_MASK) return TRUE;
1455
1456 /* now check for Unicode flags */
1457 if (out_flags & IS_TEXT_UNICODE_UNICODE_MASK) return TRUE;
1458
1459 /* no flags set */
1460 return FALSE;
1461}
1462
1463
1464/*
1465 * @implemented
1466 *
1467 * NOTES
1468 * Same as RtlOemStringToUnicodeString but doesn't write terminating null
1469 * A partial copy is NOT performed if the dest buffer is too small!
1470 */
1471NTSTATUS
1472NTAPI
1473RtlOemStringToCountedUnicodeString(
1474 IN OUT PUNICODE_STRING UniDest,
1475 IN PCOEM_STRING OemSource,
1476 IN BOOLEAN AllocateDestinationString)
1477{
1478 NTSTATUS Status;
1479 ULONG Length;
1480 ULONG Index;
1481
1482 PAGED_CODE_RTL();
1483
1484 /* Calculate size of the string */
1485 Length = RtlOemStringToCountedUnicodeSize(OemSource);
1486
1487 /* If it's 0 then zero out dest string and return */
1488 if (!Length)
1489 {
1490 RtlZeroMemory(UniDest, sizeof(UNICODE_STRING));
1491 return STATUS_SUCCESS;
1492 }
1493
1494 /* Check if length is a sane value */
1495 if (Length > MAXUSHORT) return STATUS_INVALID_PARAMETER_2;
1496
1497 /* Store it in dest string */
1498 UniDest->Length = (USHORT)Length;
1499
1500 /* If we're asked to alloc the string - do so */
1501 if (AllocateDestinationString)
1502 {
1503 UniDest->Buffer = RtlpAllocateStringMemory(Length, TAG_USTR);
1504 UniDest->MaximumLength = (USHORT)Length;
1505
1506 if (!UniDest->Buffer) return STATUS_NO_MEMORY;
1507 }
1508 else if (UniDest->Length > UniDest->MaximumLength)
1509 {
1510 return STATUS_BUFFER_OVERFLOW;
1511 }
1512
1513 /* Do the conversion */
1514 Status = RtlOemToUnicodeN(UniDest->Buffer,
1515 UniDest->Length,
1516 &Index,
1517 OemSource->Buffer,
1518 OemSource->Length);
1519
1520 if (!NT_SUCCESS(Status) && AllocateDestinationString)
1521 {
1522 /* Conversion failed, free dest string and return status code */
1523 RtlpFreeStringMemory(UniDest->Buffer, TAG_USTR);
1524 UniDest->Buffer = NULL;
1525 return Status;
1526 }
1527
1528 return STATUS_SUCCESS;
1529}
1530
1531/*
1532 * @implemented
1533 *
1534 * RETURNS
1535 * TRUE if the names are equal, FALSE if not
1536 *
1537 * NOTES
1538 * The comparison is case insensitive.
1539 */
1540BOOLEAN
1541NTAPI
1542RtlEqualComputerName(
1543 IN PUNICODE_STRING ComputerName1,
1544 IN PUNICODE_STRING ComputerName2)
1545{
1546 OEM_STRING OemString1;
1547 OEM_STRING OemString2;
1548 BOOLEAN Result = FALSE;
1549
1550 if (NT_SUCCESS(RtlUpcaseUnicodeStringToOemString(&OemString1,
1551 ComputerName1,
1552 TRUE)))
1553 {
1554 if (NT_SUCCESS(RtlUpcaseUnicodeStringToOemString(&OemString2,
1555 ComputerName2,
1556 TRUE)))
1557 {
1558 Result = RtlEqualString(&OemString1, &OemString2, FALSE);
1559 RtlFreeOemString(&OemString2);
1560 }
1561
1562 RtlFreeOemString(&OemString1);
1563 }
1564
1565 return Result;
1566}
1567
1568/*
1569 * @implemented
1570 *
1571 * RETURNS
1572 * TRUE if the names are equal, FALSE if not
1573 *
1574 * NOTES
1575 * The comparison is case insensitive.
1576 */
1577BOOLEAN
1578NTAPI
1579RtlEqualDomainName (
1580 IN PUNICODE_STRING DomainName1,
1581 IN PUNICODE_STRING DomainName2)
1582{
1583 return RtlEqualComputerName(DomainName1, DomainName2);
1584}
1585
1586/*
1587 * @implemented
1588 *
1589 * RIPPED FROM WINE's ntdll\rtlstr.c rev 1.45
1590 *
1591 * Convert a string representation of a GUID into a GUID.
1592 *
1593 * PARAMS
1594 * str [I] String representation in the format "{XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX}"
1595 * guid [O] Destination for the converted GUID
1596 *
1597 * RETURNS
1598 * Success: STATUS_SUCCESS. guid contains the converted value.
1599 * Failure: STATUS_INVALID_PARAMETER, if str is not in the expected format.
1600 *
1601 * SEE ALSO
1602 * See RtlStringFromGUID.
1603 */
1604NTSTATUS
1605NTAPI
1606RtlGUIDFromString(
1607 IN UNICODE_STRING *str,
1608 OUT GUID* guid)
1609{
1610 int i = 0;
1611 const WCHAR *lpszCLSID = str->Buffer;
1612 BYTE* lpOut = (BYTE*)guid;
1613
1614 //TRACE("(%s,%p)\n", debugstr_us(str), guid);
1615
1616 /* Convert string: {XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX}
1617 * to memory: DWORD... WORD WORD BYTES............
1618 */
1619 while (i <= 37)
1620 {
1621 switch (i)
1622 {
1623 case 0:
1624 if (*lpszCLSID != '{')
1625 return STATUS_INVALID_PARAMETER;
1626 break;
1627
1628 case 9:
1629 case 14:
1630 case 19:
1631 case 24:
1632 if (*lpszCLSID != '-')
1633 return STATUS_INVALID_PARAMETER;
1634 break;
1635
1636 case 37:
1637 if (*lpszCLSID != '}')
1638 return STATUS_INVALID_PARAMETER;
1639
1640 break;
1641
1642 default:
1643 {
1644 WCHAR ch = *lpszCLSID, ch2 = lpszCLSID[1];
1645 unsigned char byte;
1646
1647 /* Read two hex digits as a byte value */
1648 if (ch >= '0' && ch <= '9')
1649 ch = ch - '0';
1650 else if (ch >= 'a' && ch <= 'f')
1651 ch = ch - 'a' + 10;
1652 else if (ch >= 'A' && ch <= 'F')
1653 ch = ch - 'A' + 10;
1654 else
1655 return STATUS_INVALID_PARAMETER;
1656
1657 if (ch2 >= '0' && ch2 <= '9')
1658 ch2 = ch2 - '0';
1659 else if (ch2 >= 'a' && ch2 <= 'f')
1660 ch2 = ch2 - 'a' + 10;
1661 else if (ch2 >= 'A' && ch2 <= 'F')
1662 ch2 = ch2 - 'A' + 10;
1663 else
1664 return STATUS_INVALID_PARAMETER;
1665
1666 byte = ch << 4 | ch2;
1667
1668 switch (i)
1669 {
1670#ifndef WORDS_BIGENDIAN
1671 /* For Big Endian machines, we store the data such that the
1672 * dword/word members can be read as DWORDS and WORDS correctly. */
1673 /* Dword */
1674 case 1:
1675 lpOut[3] = byte;
1676 break;
1677 case 3:
1678 lpOut[2] = byte;
1679 break;
1680 case 5:
1681 lpOut[1] = byte;
1682 break;
1683 case 7:
1684 lpOut[0] = byte;
1685 lpOut += 4;
1686 break;
1687 /* Word */
1688 case 10:
1689 case 15:
1690 lpOut[1] = byte;
1691 break;
1692 case 12:
1693 case 17:
1694 lpOut[0] = byte;
1695 lpOut += 2;
1696 break;
1697#endif
1698 /* Byte */
1699 default:
1700 lpOut[0] = byte;
1701 lpOut++;
1702 break;
1703 }
1704
1705 lpszCLSID++; /* Skip 2nd character of byte */
1706 i++;
1707 }
1708 }
1709
1710 lpszCLSID++;
1711 i++;
1712 }
1713
1714 return STATUS_SUCCESS;
1715}
1716
1717/*
1718 * @implemented
1719 */
1720VOID
1721NTAPI
1722RtlEraseUnicodeString(
1723 IN PUNICODE_STRING String)
1724{
1725 if (String->Buffer && String->MaximumLength)
1726 {
1727 RtlZeroMemory(String->Buffer, String->MaximumLength);
1728 String->Length = 0;
1729 }
1730}
1731
1732/*
1733* @implemented
1734*/
1735NTSTATUS
1736NTAPI
1737RtlHashUnicodeString(
1738 IN CONST UNICODE_STRING *String,
1739 IN BOOLEAN CaseInSensitive,
1740 IN ULONG HashAlgorithm,
1741 OUT PULONG HashValue)
1742{
1743 if (String != NULL && HashValue != NULL)
1744 {
1745 switch (HashAlgorithm)
1746 {
1747 case HASH_STRING_ALGORITHM_DEFAULT:
1748 case HASH_STRING_ALGORITHM_X65599:
1749 {
1750 WCHAR *c, *end;
1751
1752 *HashValue = 0;
1753 end = String->Buffer + (String->Length / sizeof(WCHAR));
1754
1755 if (CaseInSensitive)
1756 {
1757 for (c = String->Buffer; c != end; c++)
1758 {
1759 /* only uppercase characters if they are 'a' ... 'z'! */
1760 *HashValue = ((65599 * (*HashValue)) +
1761 (ULONG)(((*c) >= L'a' && (*c) <= L'z') ?
1762 (*c) - L'a' + L'A' : (*c)));
1763 }
1764 }
1765 else
1766 {
1767 for (c = String->Buffer; c != end; c++)
1768 {
1769 *HashValue = ((65599 * (*HashValue)) + (ULONG)(*c));
1770 }
1771 }
1772
1773 return STATUS_SUCCESS;
1774 }
1775 }
1776 }
1777
1778 return STATUS_INVALID_PARAMETER;
1779}
1780
1781/*
1782 * @implemented
1783 *
1784 * NOTES
1785 * Same as RtlUnicodeStringToOemString but doesn't write terminating null
1786 */
1787_IRQL_requires_max_(PASSIVE_LEVEL)
1788_Must_inspect_result_
1789NTSYSAPI
1790NTSTATUS
1791NTAPI
1792RtlUnicodeStringToCountedOemString(
1793 _When_(AllocateDestinationString, _Out_ _At_(DestinationString->Buffer, __drv_allocatesMem(Mem)))
1794 _When_(!AllocateDestinationString, _Inout_)
1795 POEM_STRING OemDest,
1796 _In_ PCUNICODE_STRING UniSource,
1797 _In_ BOOLEAN AllocateDestinationString)
1798{
1799 NTSTATUS Status;
1800 ULONG Length;
1801 ULONG Index;
1802
1803 PAGED_CODE_RTL();
1804
1805 /* Calculate size of the string */
1806 Length = RtlUnicodeStringToCountedOemSize(UniSource);
1807
1808 /* If it's 0 then zero out dest string and return */
1809 if (!Length)
1810 {
1811 RtlZeroMemory(OemDest, sizeof(OEM_STRING));
1812 return STATUS_SUCCESS;
1813 }
1814
1815 /* Check if length is a sane value */
1816 if (Length > MAXUSHORT) return STATUS_INVALID_PARAMETER_2;
1817
1818 /* Store it in dest string */
1819 OemDest->Length = (USHORT)Length;
1820
1821 /* If we're asked to alloc the string - do so */
1822 if (AllocateDestinationString)
1823 {
1824 OemDest->Buffer = RtlpAllocateStringMemory(Length, TAG_OSTR);
1825 OemDest->MaximumLength = (USHORT)Length;
1826 if (!OemDest->Buffer) return STATUS_NO_MEMORY;
1827 }
1828 else if (OemDest->Length > OemDest->MaximumLength)
1829 {
1830 return STATUS_BUFFER_OVERFLOW;
1831 }
1832
1833 /* Do the conversion */
1834 Status = RtlUnicodeToOemN(OemDest->Buffer,
1835 OemDest->Length,
1836 &Index,
1837 UniSource->Buffer,
1838 UniSource->Length);
1839
1840 /* Check for unmapped character */
1841 if (NT_SUCCESS(Status) && !RtlpDidUnicodeToOemWork(UniSource, OemDest))
1842 Status = STATUS_UNMAPPABLE_CHARACTER;
1843
1844 if (!NT_SUCCESS(Status) && AllocateDestinationString)
1845 {
1846 /* Conversion failed, free dest string and return status code */
1847 RtlpFreeStringMemory(OemDest->Buffer, TAG_OSTR);
1848 OemDest->Buffer = NULL;
1849 return Status;
1850 }
1851
1852 return Status;
1853}
1854
1855/*
1856 * @implemented
1857 */
1858NTSTATUS
1859NTAPI
1860RtlLargeIntegerToChar(
1861 IN PLARGE_INTEGER Value,
1862 IN ULONG Base,
1863 IN ULONG Length,
1864 IN OUT PCHAR String)
1865{
1866 ULONGLONG Val = Value->QuadPart;
1867 CHAR Buffer[65];
1868 CHAR Digit;
1869 SIZE_T Len;
1870 PCHAR Pos;
1871
1872 if (Base == 0) Base = 10;
1873
1874 if ((Base != 2) && (Base != 8) && (Base != 10) && (Base != 16))
1875 {
1876 return STATUS_INVALID_PARAMETER;
1877 }
1878
1879 Pos = &Buffer[64];
1880 *Pos = '\0';
1881
1882 do
1883 {
1884 Pos--;
1885 Digit = (CHAR)(Val % Base);
1886 Val = Val / Base;
1887
1888 if (Digit < 10)
1889 *Pos = '0' + Digit;
1890 else
1891 *Pos = 'A' + Digit - 10;
1892 }
1893 while (Val != 0L);
1894
1895 Len = &Buffer[64] - Pos;
1896
1897 if (Len > Length)
1898 return STATUS_BUFFER_OVERFLOW;
1899
1900 /* If possible, add the 0 termination */
1901 if (Len < Length)
1902 Len += 1;
1903
1904 /* Copy the string to the target using SEH */
1905 return RtlpSafeCopyMemory(String, Pos, Len);
1906}
1907
1908/*
1909 * @implemented
1910 *
1911 * NOTES
1912 * dest is never '\0' terminated because it may be equal to src, and src
1913 * might not be '\0' terminated. dest->Length is only set upon success.
1914 */
1915NTSTATUS
1916NTAPI
1917RtlUpcaseUnicodeString(
1918 IN OUT PUNICODE_STRING UniDest,
1919 IN PCUNICODE_STRING UniSource,
1920 IN BOOLEAN AllocateDestinationString)
1921{
1922 ULONG i, j;
1923
1924 PAGED_CODE_RTL();
1925
1926 if (AllocateDestinationString)
1927 {
1928 UniDest->MaximumLength = UniSource->Length;
1929 UniDest->Buffer = RtlpAllocateStringMemory(UniDest->MaximumLength, TAG_USTR);
1930 if (UniDest->Buffer == NULL) return STATUS_NO_MEMORY;
1931 }
1932 else if (UniSource->Length > UniDest->MaximumLength)
1933 {
1934 return STATUS_BUFFER_OVERFLOW;
1935 }
1936
1937 j = UniSource->Length / sizeof(WCHAR);
1938
1939 for (i = 0; i < j; i++)
1940 {
1941 UniDest->Buffer[i] = RtlpUpcaseUnicodeChar(UniSource->Buffer[i]);
1942 }
1943
1944 UniDest->Length = UniSource->Length;
1945 return STATUS_SUCCESS;
1946}
1947
1948/*
1949 * @implemented
1950 *
1951 * NOTES
1952 * This function always writes a terminating '\0'.
1953 * It performs a partial copy if ansi is too small.
1954 */
1955NTSTATUS
1956NTAPI
1957RtlUpcaseUnicodeStringToAnsiString(
1958 IN OUT PANSI_STRING AnsiDest,
1959 IN PCUNICODE_STRING UniSource,
1960 IN BOOLEAN AllocateDestinationString)
1961{
1962 NTSTATUS Status;
1963 ULONG Length;
1964 ULONG Index;
1965 PAGED_CODE_RTL();
1966
1967 Length = RtlUnicodeStringToAnsiSize(UniSource);
1968 if (Length > MAXUSHORT) return STATUS_INVALID_PARAMETER_2;
1969
1970 AnsiDest->Length = (USHORT)Length - sizeof(CHAR);
1971
1972 if (AllocateDestinationString)
1973 {
1974 AnsiDest->Buffer = RtlpAllocateStringMemory(Length, TAG_ASTR);
1975 AnsiDest->MaximumLength = (USHORT)Length;
1976 if (!AnsiDest->Buffer) return STATUS_NO_MEMORY;
1977 }
1978 else if (AnsiDest->Length >= AnsiDest->MaximumLength)
1979 {
1980 if (!AnsiDest->MaximumLength) return STATUS_BUFFER_OVERFLOW;
1981 }
1982
1983 Status = RtlUpcaseUnicodeToMultiByteN(AnsiDest->Buffer,
1984 AnsiDest->Length,
1985 &Index,
1986 UniSource->Buffer,
1987 UniSource->Length);
1988
1989 if (!NT_SUCCESS(Status) && AllocateDestinationString)
1990 {
1991 RtlpFreeStringMemory(AnsiDest->Buffer, TAG_ASTR);
1992 AnsiDest->Buffer = NULL;
1993 return Status;
1994 }
1995
1996 AnsiDest->Buffer[Index] = ANSI_NULL;
1997 return Status;
1998}
1999
2000/*
2001 * @implemented
2002 *
2003 * NOTES
2004 * This function always writes a terminating '\0'.
2005 * It performs a partial copy if ansi is too small.
2006 */
2007NTSTATUS
2008NTAPI
2009RtlUpcaseUnicodeStringToCountedOemString(
2010 IN OUT POEM_STRING OemDest,
2011 IN PCUNICODE_STRING UniSource,
2012 IN BOOLEAN AllocateDestinationString)
2013{
2014 NTSTATUS Status;
2015 ULONG Length;
2016 ULONG Index;
2017 PAGED_CODE_RTL();
2018
2019 Length = RtlUnicodeStringToCountedOemSize(UniSource);
2020
2021 if (!Length)
2022 {
2023 RtlZeroMemory(OemDest, sizeof(OEM_STRING));
2024 }
2025
2026 if (Length > MAXUSHORT) return STATUS_INVALID_PARAMETER_2;
2027
2028 OemDest->Length = (USHORT)Length;
2029
2030 if (AllocateDestinationString)
2031 {
2032 OemDest->Buffer = RtlpAllocateStringMemory(Length, TAG_OSTR);
2033 OemDest->MaximumLength = (USHORT)Length;
2034 if (!OemDest->Buffer) return STATUS_NO_MEMORY;
2035 }
2036 else if (OemDest->Length > OemDest->MaximumLength)
2037 {
2038 return STATUS_BUFFER_OVERFLOW;
2039 }
2040
2041 Status = RtlUpcaseUnicodeToOemN(OemDest->Buffer,
2042 OemDest->Length,
2043 &Index,
2044 UniSource->Buffer,
2045 UniSource->Length);
2046
2047 /* Check for unmapped characters */
2048 if (NT_SUCCESS(Status) && !RtlpDidUnicodeToOemWork(UniSource, OemDest))
2049 Status = STATUS_UNMAPPABLE_CHARACTER;
2050
2051 if (!NT_SUCCESS(Status) && AllocateDestinationString)
2052 {
2053 RtlpFreeStringMemory(OemDest->Buffer, TAG_OSTR);
2054 OemDest->Buffer = NULL;
2055 return Status;
2056 }
2057
2058 return Status;
2059}
2060
2061/*
2062 * @implemented
2063 * NOTES
2064 * OEM string is always nullterminated
2065 * It performs a partial copy if oem is too small.
2066 */
2067NTSTATUS
2068NTAPI
2069RtlUpcaseUnicodeStringToOemString (
2070 IN OUT POEM_STRING OemDest,
2071 IN PCUNICODE_STRING UniSource,
2072 IN BOOLEAN AllocateDestinationString)
2073{
2074 NTSTATUS Status;
2075 ULONG Length;
2076 ULONG Index;
2077 PAGED_CODE_RTL();
2078
2079 Length = RtlUnicodeStringToOemSize(UniSource);
2080 if (Length > MAXUSHORT) return STATUS_INVALID_PARAMETER_2;
2081
2082 OemDest->Length = (USHORT)Length - sizeof(CHAR);
2083
2084 if (AllocateDestinationString)
2085 {
2086 OemDest->Buffer = RtlpAllocateStringMemory(Length, TAG_OSTR);
2087 OemDest->MaximumLength = (USHORT)Length;
2088 if (!OemDest->Buffer) return STATUS_NO_MEMORY;
2089 }
2090 else if (OemDest->Length >= OemDest->MaximumLength)
2091 {
2092 return STATUS_BUFFER_OVERFLOW;
2093 }
2094
2095 Status = RtlUpcaseUnicodeToOemN(OemDest->Buffer,
2096 OemDest->Length,
2097 &Index,
2098 UniSource->Buffer,
2099 UniSource->Length);
2100
2101 /* Check for unmapped characters */
2102 if (NT_SUCCESS(Status) && !RtlpDidUnicodeToOemWork(UniSource, OemDest))
2103 Status = STATUS_UNMAPPABLE_CHARACTER;
2104
2105 if (!NT_SUCCESS(Status) && AllocateDestinationString)
2106 {
2107 RtlpFreeStringMemory(OemDest->Buffer, TAG_OSTR);
2108 OemDest->Buffer = NULL;
2109 return Status;
2110 }
2111
2112 OemDest->Buffer[Index] = ANSI_NULL;
2113 return Status;
2114}
2115
2116/*
2117 * @implemented
2118 *
2119 * RETURNS
2120 * Bytes calculated including nullterm
2121 */
2122ULONG
2123NTAPI
2124RtlxOemStringToUnicodeSize(IN PCOEM_STRING OemString)
2125{
2126 ULONG Size;
2127
2128 /* Convert the Mb String to Unicode Size */
2129 RtlMultiByteToUnicodeSize(&Size,
2130 OemString->Buffer,
2131 OemString->Length);
2132
2133 /* Return the size + null-char */
2134 return (Size + sizeof(WCHAR));
2135}
2136
2137/*
2138 * @implemented
2139 */
2140NTSTATUS
2141NTAPI
2142RtlStringFromGUID (IN REFGUID Guid,
2143 OUT PUNICODE_STRING GuidString)
2144{
2145 /* Setup the string */
2146 GuidString->Length = 38 * sizeof(WCHAR);
2147 GuidString->MaximumLength = GuidString->Length + sizeof(UNICODE_NULL);
2148 GuidString->Buffer = RtlpAllocateStringMemory(GuidString->MaximumLength,
2149 TAG_USTR);
2150 if (!GuidString->Buffer) return STATUS_NO_MEMORY;
2151
2152 /* Now format the GUID */
2153 swprintf(GuidString->Buffer,
2154 L"{%08lx-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x}",
2155 Guid->Data1,
2156 Guid->Data2,
2157 Guid->Data3,
2158 Guid->Data4[0],
2159 Guid->Data4[1],
2160 Guid->Data4[2],
2161 Guid->Data4[3],
2162 Guid->Data4[4],
2163 Guid->Data4[5],
2164 Guid->Data4[6],
2165 Guid->Data4[7]);
2166 return STATUS_SUCCESS;
2167}
2168
2169/*
2170 * @implemented
2171 *
2172 * RETURNS
2173 * Bytes calculated including nullterm
2174 */
2175ULONG
2176NTAPI
2177RtlxUnicodeStringToAnsiSize(IN PCUNICODE_STRING UnicodeString)
2178{
2179 ULONG Size;
2180 PAGED_CODE_RTL();
2181
2182 ASSERT(!(UnicodeString->Length & 1));
2183
2184 /* Convert the Unicode String to Mb Size */
2185 RtlUnicodeToMultiByteSize(&Size,
2186 UnicodeString->Buffer,
2187 UnicodeString->Length);
2188
2189 /* Return the size + null-char */
2190 return (Size + sizeof(CHAR));
2191}
2192
2193/*
2194 * @implemented
2195 */
2196LONG
2197NTAPI
2198RtlCompareUnicodeString(
2199 IN PCUNICODE_STRING s1,
2200 IN PCUNICODE_STRING s2,
2201 IN BOOLEAN CaseInsensitive)
2202{
2203 unsigned int len;
2204 LONG ret = 0;
2205 LPCWSTR p1, p2;
2206
2207 len = min(s1->Length, s2->Length) / sizeof(WCHAR);
2208 p1 = s1->Buffer;
2209 p2 = s2->Buffer;
2210
2211 if (CaseInsensitive)
2212 {
2213 while (!ret && len--) ret = RtlpUpcaseUnicodeChar(*p1++) - RtlpUpcaseUnicodeChar(*p2++);
2214 }
2215 else
2216 {
2217 while (!ret && len--) ret = *p1++ - *p2++;
2218 }
2219
2220 if (!ret) ret = s1->Length - s2->Length;
2221
2222 return ret;
2223}
2224
2225/*
2226 * @implemented
2227 */
2228_IRQL_requires_max_(PASSIVE_LEVEL)
2229_Must_inspect_result_
2230NTSYSAPI
2231LONG
2232NTAPI
2233RtlCompareUnicodeStrings(
2234 _In_reads_(String1Length) PCWCH String1,
2235 _In_ SIZE_T String1Length,
2236 _In_reads_(String2Length) PCWCH String2,
2237 _In_ SIZE_T String2Length,
2238 _In_ BOOLEAN CaseInSensitive)
2239{
2240 LONG Result = 0;
2241 SIZE_T MinStringLength = min(String1Length, String2Length);
2242 SIZE_T Index;
2243
2244 if (CaseInSensitive)
2245 {
2246 for (Index = 0; Index < MinStringLength; Index++)
2247 {
2248 WCHAR Char1 = RtlpUpcaseUnicodeChar(String1[Index]);
2249 WCHAR Char2 = RtlpUpcaseUnicodeChar(String2[Index]);
2250 Result = Char1 - Char2;
2251 if (Result != 0)
2252 {
2253 return Result;
2254 }
2255 }
2256 }
2257 else
2258 {
2259 for (Index = 0; Index < MinStringLength; Index++)
2260 {
2261 Result = String1[Index] - String2[Index];
2262 if (Result != 0)
2263 {
2264 return Result;
2265 }
2266 }
2267 }
2268
2269 return String1Length - String2Length;
2270}
2271
2272/*
2273 * @implemented
2274 */
2275VOID
2276NTAPI
2277RtlCopyString(
2278 IN OUT PSTRING DestinationString,
2279 IN const STRING *SourceString OPTIONAL)
2280{
2281 ULONG SourceLength;
2282 PCHAR p1, p2;
2283
2284 /* Check if there was no source given */
2285 if (!SourceString)
2286 {
2287 /* Simply return an empty string */
2288 DestinationString->Length = 0;
2289 }
2290 else
2291 {
2292 /* Choose the smallest length */
2293 SourceLength = min(DestinationString->MaximumLength,
2294 SourceString->Length);
2295
2296 /* Set it */
2297 DestinationString->Length = (USHORT)SourceLength;
2298
2299 /* Save the pointers to each buffer */
2300 p1 = DestinationString->Buffer;
2301 p2 = SourceString->Buffer;
2302
2303 /* Loop the buffer */
2304 while (SourceLength)
2305 {
2306 /* Copy the character and move on */
2307 *p1++ = * p2++;
2308 SourceLength--;
2309 }
2310 }
2311}
2312
2313/*
2314 * @implemented
2315 */
2316VOID
2317NTAPI
2318RtlCopyUnicodeString(
2319 IN OUT PUNICODE_STRING DestinationString,
2320 IN PCUNICODE_STRING SourceString)
2321{
2322 ULONG SourceLength;
2323
2324 if (!SourceString)
2325 {
2326 DestinationString->Length = 0;
2327 }
2328 else
2329 {
2330 SourceLength = min(DestinationString->MaximumLength,
2331 SourceString->Length);
2332 DestinationString->Length = (USHORT)SourceLength;
2333
2334 RtlCopyMemory(DestinationString->Buffer,
2335 SourceString->Buffer,
2336 SourceLength);
2337
2338 if (DestinationString->Length < DestinationString->MaximumLength)
2339 {
2340 DestinationString->Buffer[SourceLength / sizeof(WCHAR)] = UNICODE_NULL;
2341 }
2342 }
2343}
2344
2345/*
2346 * @implemented
2347 *
2348 * NOTES
2349 * Creates a nullterminated UNICODE_STRING
2350 */
2351BOOLEAN
2352NTAPI
2353RtlCreateUnicodeString(
2354 IN OUT PUNICODE_STRING UniDest,
2355 IN PCWSTR Source)
2356{
2357 SIZE_T Size;
2358 PAGED_CODE_RTL();
2359
2360 Size = (wcslen(Source) + 1) * sizeof(WCHAR);
2361 if (Size > MAXUSHORT) return FALSE;
2362
2363 UniDest->Buffer = RtlpAllocateStringMemory((ULONG)Size, TAG_USTR);
2364
2365 if (UniDest->Buffer == NULL) return FALSE;
2366
2367 RtlCopyMemory(UniDest->Buffer, Source, Size);
2368 UniDest->MaximumLength = (USHORT)Size;
2369 UniDest->Length = (USHORT)Size - sizeof (WCHAR);
2370
2371 return TRUE;
2372}
2373
2374/*
2375 * @implemented
2376 */
2377BOOLEAN
2378NTAPI
2379RtlCreateUnicodeStringFromAsciiz(
2380 OUT PUNICODE_STRING Destination,
2381 IN PCSZ Source)
2382{
2383 ANSI_STRING AnsiString;
2384 NTSTATUS Status;
2385
2386 RtlInitAnsiString(&AnsiString, Source);
2387
2388 Status = RtlAnsiStringToUnicodeString(Destination,
2389 &AnsiString,
2390 TRUE);
2391
2392 return NT_SUCCESS(Status);
2393}
2394
2395/*
2396 * @implemented
2397 *
2398 * NOTES
2399 * Dest is never '\0' terminated because it may be equal to src, and src
2400 * might not be '\0' terminated.
2401 * Dest->Length is only set upon success.
2402 */
2403NTSTATUS
2404NTAPI
2405RtlDowncaseUnicodeString(
2406 IN OUT PUNICODE_STRING UniDest,
2407 IN PCUNICODE_STRING UniSource,
2408 IN BOOLEAN AllocateDestinationString)
2409{
2410 ULONG i;
2411 ULONG StopGap;
2412 PAGED_CODE_RTL();
2413
2414 if (AllocateDestinationString)
2415 {
2416 UniDest->MaximumLength = UniSource->Length;
2417 UniDest->Buffer = RtlpAllocateStringMemory(UniSource->Length, TAG_USTR);
2418 if (UniDest->Buffer == NULL) return STATUS_NO_MEMORY;
2419 }
2420 else if (UniSource->Length > UniDest->MaximumLength)
2421 {
2422 return STATUS_BUFFER_OVERFLOW;
2423 }
2424
2425 UniDest->Length = UniSource->Length;
2426 StopGap = UniSource->Length / sizeof(WCHAR);
2427
2428 for (i = 0 ; i < StopGap; i++)
2429 {
2430 if (UniSource->Buffer[i] < L'A')
2431 {
2432 UniDest->Buffer[i] = UniSource->Buffer[i];
2433 }
2434 else if (UniSource->Buffer[i] <= L'Z')
2435 {
2436 UniDest->Buffer[i] = (UniSource->Buffer[i] + (L'a' - L'A'));
2437 }
2438 else
2439 {
2440 UniDest->Buffer[i] = RtlpDowncaseUnicodeChar(UniSource->Buffer[i]);
2441 }
2442 }
2443
2444 return STATUS_SUCCESS;
2445}
2446
2447/*
2448 * @implemented
2449 *
2450 * NOTES
2451 * if src is NULL dest is unchanged.
2452 * dest is '\0' terminated when the MaximumLength allowes it.
2453 * When dest fits exactly in MaximumLength characters the '\0' is ommitted.
2454 */
2455NTSTATUS
2456NTAPI
2457RtlAppendUnicodeToString(IN OUT PUNICODE_STRING Destination,
2458 IN PCWSTR Source)
2459{
2460 USHORT Length;
2461 PWCHAR DestBuffer;
2462
2463 if (Source)
2464 {
2465 UNICODE_STRING UnicodeSource;
2466
2467 RtlInitUnicodeString(&UnicodeSource, Source);
2468 Length = UnicodeSource.Length;
2469
2470 if (Destination->Length + Length > Destination->MaximumLength)
2471 {
2472 return STATUS_BUFFER_TOO_SMALL;
2473 }
2474
2475 DestBuffer = &Destination->Buffer[Destination->Length / sizeof(WCHAR)];
2476 RtlMoveMemory(DestBuffer, Source, Length);
2477 Destination->Length += Length;
2478
2479 /* append terminating '\0' if enough space */
2480 if (Destination->MaximumLength > Destination->Length)
2481 {
2482 DestBuffer[Length / sizeof(WCHAR)] = UNICODE_NULL;
2483 }
2484 }
2485
2486 return STATUS_SUCCESS;
2487}
2488
2489/*
2490 * @implemented
2491 *
2492 * NOTES
2493 * if src is NULL dest is unchanged.
2494 * dest is never '\0' terminated.
2495 */
2496NTSTATUS
2497NTAPI
2498RtlAppendAsciizToString(
2499 IN OUT PSTRING Destination,
2500 IN PCSZ Source)
2501{
2502 SIZE_T Size;
2503
2504 if (Source)
2505 {
2506 Size = strlen(Source);
2507
2508 if (Destination->Length + Size > Destination->MaximumLength)
2509 {
2510 return STATUS_BUFFER_TOO_SMALL;
2511 }
2512
2513 RtlMoveMemory(&Destination->Buffer[Destination->Length], Source, Size);
2514 Destination->Length += (USHORT)Size;
2515 }
2516
2517 return STATUS_SUCCESS;
2518}
2519
2520/*
2521 * @implemented
2522 */
2523VOID
2524NTAPI
2525RtlUpperString(PSTRING DestinationString,
2526 const STRING *SourceString)
2527{
2528 USHORT Length;
2529 PCHAR Src, Dest;
2530
2531 Length = min(SourceString->Length,
2532 DestinationString->MaximumLength);
2533
2534 Src = SourceString->Buffer;
2535 Dest = DestinationString->Buffer;
2536 DestinationString->Length = Length;
2537
2538 while (Length)
2539 {
2540 *Dest++ = RtlUpperChar(*Src++);
2541 Length--;
2542 }
2543}
2544
2545/*
2546 * @implemented
2547 *
2548 * NOTES
2549 * See RtlpDuplicateUnicodeString
2550 */
2551NTSTATUS
2552NTAPI
2553RtlDuplicateUnicodeString(
2554 IN ULONG Flags,
2555 IN PCUNICODE_STRING SourceString,
2556 OUT PUNICODE_STRING DestinationString)
2557{
2558 PAGED_CODE_RTL();
2559
2560 if (SourceString == NULL || DestinationString == NULL ||
2561 SourceString->Length > SourceString->MaximumLength ||
2562 (SourceString->Length == 0 && SourceString->MaximumLength > 0 && SourceString->Buffer == NULL) ||
2563 Flags == RTL_DUPLICATE_UNICODE_STRING_ALLOCATE_NULL_STRING || Flags >= 4)
2564 {
2565 return STATUS_INVALID_PARAMETER;
2566 }
2567
2568
2569 if ((SourceString->Length == 0) &&
2570 (Flags != (RTL_DUPLICATE_UNICODE_STRING_NULL_TERMINATE |
2571 RTL_DUPLICATE_UNICODE_STRING_ALLOCATE_NULL_STRING)))
2572 {
2573 DestinationString->Length = 0;
2574 DestinationString->MaximumLength = 0;
2575 DestinationString->Buffer = NULL;
2576 }
2577 else
2578 {
2579 UINT DestMaxLength = SourceString->Length;
2580
2581 if (Flags & RTL_DUPLICATE_UNICODE_STRING_NULL_TERMINATE)
2582 DestMaxLength += sizeof(UNICODE_NULL);
2583
2584 DestinationString->Buffer = RtlpAllocateStringMemory(DestMaxLength, TAG_USTR);
2585
2586 if (DestinationString->Buffer == NULL)
2587 return STATUS_NO_MEMORY;
2588
2589 RtlCopyMemory(DestinationString->Buffer, SourceString->Buffer, SourceString->Length);
2590 DestinationString->Length = SourceString->Length;
2591 DestinationString->MaximumLength = DestMaxLength;
2592
2593 if (Flags & RTL_DUPLICATE_UNICODE_STRING_NULL_TERMINATE)
2594 DestinationString->Buffer[DestinationString->Length / sizeof(WCHAR)] = 0;
2595 }
2596
2597 return STATUS_SUCCESS;
2598}
2599
2600/*
2601 * @implemented
2602 */
2603NTSTATUS
2604NTAPI
2605RtlValidateUnicodeString(
2606 _In_ ULONG Flags,
2607 _In_ PCUNICODE_STRING String)
2608{
2609 /* In Windows <= 2003 no flags are supported yet! */
2610 if (Flags != 0)
2611 return STATUS_INVALID_PARAMETER;
2612
2613 /* NOTE: a NULL Unicode string pointer is considered to be a valid one! */
2614 if (String == NULL)
2615 {
2616 return STATUS_SUCCESS;
2617 }
2618 else if (!((String->Buffer == NULL) && (String->Length != 0 || String->MaximumLength != 0)) &&
2619 (String->Length % sizeof(WCHAR) == 0) &&
2620 (String->MaximumLength % sizeof(WCHAR) == 0) &&
2621 (String->Length <= String->MaximumLength))
2622 {
2623 return STATUS_SUCCESS;
2624 }
2625 else
2626 {
2627 return STATUS_INVALID_PARAMETER;
2628 }
2629}
2630
2631/*
2632 * @implemented
2633 */
2634NTSTATUS
2635NTAPI
2636RtlpEnsureBufferSize(
2637 IN ULONG Flags,
2638 IN OUT PRTL_BUFFER Buffer,
2639 IN SIZE_T RequiredSize)
2640{
2641 PUCHAR NewBuffer;
2642
2643 /* Parameter checks */
2644 if (Flags & ~RTL_SKIP_BUFFER_COPY)
2645 return STATUS_INVALID_PARAMETER;
2646 if (Buffer == NULL)
2647 return STATUS_INVALID_PARAMETER;
2648
2649 /*
2650 * We don't need to grow the buffer if its size
2651 * is already larger than the required size.
2652 */
2653 if (Buffer->Size >= RequiredSize)
2654 return STATUS_SUCCESS;
2655
2656 /*
2657 * When we are using the static buffer as our buffer, we don't need
2658 * to grow it if its size is already larger than the required size.
2659 * In this case, just keep it but update the current buffer size to
2660 * the one requested.
2661 * (But NEVER EVER modify the size of the static buffer!!)
2662 * Otherwise, we'll need to create a new buffer and use this one instead.
2663 */
2664 if ( (Buffer->Buffer == Buffer->StaticBuffer) &&
2665 (Buffer->StaticSize >= RequiredSize) )
2666 {
2667 Buffer->Size = RequiredSize;
2668 return STATUS_SUCCESS;
2669 }
2670
2671 /* The buffer we are using is not large enough, try to create a bigger one */
2672 NewBuffer = RtlpAllocateStringMemory(RequiredSize, TAG_USTR);
2673 if (NewBuffer == NULL)
2674 return STATUS_NO_MEMORY;
2675
2676 /* Copy the original content if needed */
2677 if (!(Flags & RTL_SKIP_BUFFER_COPY))
2678 {
2679 RtlMoveMemory(NewBuffer, Buffer->Buffer, Buffer->Size);
2680 }
2681
2682 /* Free the original buffer only if it's not the static buffer */
2683 if (Buffer->Buffer != Buffer->StaticBuffer)
2684 {
2685 RtlpFreeStringMemory(Buffer->Buffer, TAG_USTR);
2686 }
2687
2688 /* Update the members */
2689 Buffer->Buffer = NewBuffer;
2690 Buffer->Size = RequiredSize;
2691
2692 /* Done */
2693 return STATUS_SUCCESS;
2694}
2695
2696static
2697BOOLEAN
2698RtlpIsCharInUnicodeString(
2699 IN WCHAR Char,
2700 IN PCUNICODE_STRING MatchString,
2701 IN BOOLEAN CaseInSensitive)
2702{
2703 USHORT i;
2704
2705 if (CaseInSensitive)
2706 Char = RtlpUpcaseUnicodeChar(Char);
2707
2708 for (i = 0; i < MatchString->Length / sizeof(WCHAR); i++)
2709 {
2710 WCHAR OtherChar = MatchString->Buffer[i];
2711 if (CaseInSensitive)
2712 OtherChar = RtlpUpcaseUnicodeChar(OtherChar);
2713
2714 if (Char == OtherChar)
2715 return TRUE;
2716 }
2717
2718 return FALSE;
2719}
2720
2721/*
2722 * @implemented
2723 */
2724NTSTATUS
2725NTAPI
2726RtlFindCharInUnicodeString(
2727 IN ULONG Flags,
2728 IN PCUNICODE_STRING SearchString,
2729 IN PCUNICODE_STRING MatchString,
2730 OUT PUSHORT Position)
2731{
2732 BOOLEAN Found;
2733 const BOOLEAN WantToFind = (Flags & RTL_FIND_CHAR_IN_UNICODE_STRING_COMPLEMENT_CHAR_SET) == 0;
2734 const BOOLEAN CaseInSensitive = (Flags & RTL_FIND_CHAR_IN_UNICODE_STRING_CASE_INSENSITIVE) != 0;
2735 USHORT i, Length;
2736
2737 DPRINT("RtlFindCharInUnicodeString(%u, '%wZ', '%wZ', %p)\n",
2738 Flags, SearchString, MatchString, Position);
2739
2740 /* Parameter checks */
2741 if (Position == NULL)
2742 return STATUS_INVALID_PARAMETER;
2743
2744 *Position = 0;
2745
2746 if (Flags & ~(RTL_FIND_CHAR_IN_UNICODE_STRING_START_AT_END |
2747 RTL_FIND_CHAR_IN_UNICODE_STRING_COMPLEMENT_CHAR_SET |
2748 RTL_FIND_CHAR_IN_UNICODE_STRING_CASE_INSENSITIVE))
2749 return STATUS_INVALID_PARAMETER;
2750
2751 /* Search */
2752 Length = SearchString->Length / sizeof(WCHAR);
2753 if (Flags & RTL_FIND_CHAR_IN_UNICODE_STRING_START_AT_END)
2754 {
2755 for (i = Length - 1; (SHORT)i >= 0; i--)
2756 {
2757 Found = RtlpIsCharInUnicodeString(SearchString->Buffer[i], MatchString, CaseInSensitive);
2758 if (Found == WantToFind)
2759 {
2760 *Position = i * sizeof(WCHAR);
2761 return STATUS_SUCCESS;
2762 }
2763 }
2764 }
2765 else
2766 {
2767 for (i = 0; i < Length; i++)
2768 {
2769 Found = RtlpIsCharInUnicodeString(SearchString->Buffer[i], MatchString, CaseInSensitive);
2770 if (Found == WantToFind)
2771 {
2772 *Position = (i + 1) * sizeof(WCHAR);
2773 return STATUS_SUCCESS;
2774 }
2775 }
2776 }
2777
2778 return STATUS_NOT_FOUND;
2779}
2780
2781/*
2782 * @implemented
2783 *
2784 * NOTES
2785 * Get the maximum of MAX_COMPUTERNAME_LENGTH characters from the dns.host name until the dot is found.
2786 * Convert is to an uppercase oem string and check for unmapped characters.
2787 * Then convert the oem string back to an unicode string.
2788 */
2789NTSTATUS
2790NTAPI
2791RtlDnsHostNameToComputerName(PUNICODE_STRING ComputerName, PUNICODE_STRING DnsHostName, BOOLEAN AllocateComputerNameString)
2792{
2793 NTSTATUS Status;
2794 ULONG Length;
2795 ULONG ComputerNameLength;
2796 ULONG ComputerNameOemNLength;
2797 OEM_STRING ComputerNameOem;
2798 CHAR ComputerNameOemN[MAX_COMPUTERNAME_LENGTH + 1];
2799
2800 Status = STATUS_INVALID_COMPUTER_NAME;
2801 ComputerNameLength = DnsHostName->Length;
2802
2803 /* find the first dot in the dns host name */
2804 for (Length = 0; Length < DnsHostName->Length / sizeof(WCHAR); Length++)
2805 {
2806 if (DnsHostName->Buffer[Length] == L'.')
2807 {
2808 /* dot found, so set the length for the oem translation */
2809 ComputerNameLength = Length * sizeof(WCHAR);
2810 break;
2811 }
2812 }
2813
2814 /* the computername must have one character */
2815 if (ComputerNameLength > 0)
2816 {
2817 ComputerNameOemNLength = 0;
2818 /* convert to oem string and use uppercase letters */
2819 Status = RtlUpcaseUnicodeToOemN(ComputerNameOemN,
2820 MAX_COMPUTERNAME_LENGTH,
2821 &ComputerNameOemNLength,
2822 DnsHostName->Buffer,
2823 ComputerNameLength);
2824
2825 /* status STATUS_BUFFER_OVERFLOW is not a problem since the computername shoud only
2826 have MAX_COMPUTERNAME_LENGTH characters */
2827 if ((Status == STATUS_SUCCESS) ||
2828 (Status == STATUS_BUFFER_OVERFLOW))
2829 {
2830 /* set the termination for the oem string */
2831 ComputerNameOemN[MAX_COMPUTERNAME_LENGTH] = 0;
2832 /* set status for the case the next function failed */
2833 Status = STATUS_INVALID_COMPUTER_NAME;
2834 /* fillup the oem string structure with the converted computername
2835 and check it for unmapped characters */
2836 ComputerNameOem.Buffer = ComputerNameOemN;
2837 ComputerNameOem.Length = (USHORT)ComputerNameOemNLength;
2838 ComputerNameOem.MaximumLength = (USHORT)(MAX_COMPUTERNAME_LENGTH + 1);
2839
2840 if (RtlpDidUnicodeToOemWork(DnsHostName, &ComputerNameOem))
2841 {
2842 /* no unmapped character so convert it back to an unicode string */
2843 Status = RtlOemStringToUnicodeString(ComputerName,
2844 &ComputerNameOem,
2845 AllocateComputerNameString);
2846 }
2847 }
2848 }
2849
2850 return Status;
2851}
2852