xref: /reactos/sdk/lib/rtl/unicode.c (revision e5993f13)
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 
22 extern BOOLEAN NlsMbCodePageTag;
23 extern BOOLEAN NlsMbOemCodePageTag;
24 extern PUSHORT NlsLeadByteInfo;
25 extern USHORT NlsOemDefaultChar;
26 extern USHORT NlsUnicodeDefaultChar;
27 extern PUSHORT NlsOemLeadByteInfo;
28 extern PWCHAR NlsOemToUnicodeTable;
29 extern PCHAR NlsUnicodeToOemTable;
30 extern PUSHORT NlsUnicodeToMbOemTable;
31 
32 
33 /* FUNCTIONS *****************************************************************/
34 
35 NTSTATUS
36 NTAPI
37 RtlMultiAppendUnicodeStringBuffer(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 */
48 WCHAR
49 NTAPI
50 RtlAnsiCharToUnicodeChar(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  */
89 NTSTATUS
90 NTAPI
91 RtlAnsiStringToUnicodeString(
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  */
154 ULONG
155 NTAPI
156 RtlxAnsiStringToUnicodeSize(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  */
177 NTSTATUS
178 NTAPI
179 RtlAppendStringToString(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  */
209 NTSTATUS
210 NTAPI
211 RtlAppendUnicodeStringToString(
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  */
259 NTSTATUS
260 NTAPI
261 RtlCharToInteger(
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  */
350 LONG
351 NTAPI
352 RtlCompareString(
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  */
386 BOOLEAN
387 NTAPI
388 RtlEqualString(
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  */
403 BOOLEAN
404 NTAPI
405 RtlEqualUnicodeString(
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  */
417 VOID
418 NTAPI
419 RtlFreeAnsiString(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  */
433 VOID
434 NTAPI
435 RtlFreeOemString(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  */
445 VOID
446 NTAPI
447 RtlFreeUnicodeString(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  */
470 BOOLEAN
471 NTAPI
472 RtlpDidUnicodeToOemWork(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 */
512 BOOLEAN
513 NTAPI
514 RtlIsValidOemCharacter(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  */
571 VOID
572 NTAPI
573 RtlInitAnsiString(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 
594 NTSTATUS
595 NTAPI
596 RtlInitAnsiStringEx(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  */
624 VOID
625 NTAPI
626 RtlInitString(
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  */
639 VOID
640 NTAPI
641 RtlInitUnicodeString(
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  */
670 NTSTATUS
671 NTAPI
672 RtlInitUnicodeStringEx(
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  */
704 NTSTATUS 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  */
769 NTSTATUS
770 NTAPI
771 RtlIntegerToUnicode(
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  */
824 NTSTATUS
825 NTAPI
826 RtlIntegerToUnicodeString(
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  */
851 NTSTATUS
852 NTAPI
853 RtlInt64ToUnicodeString (
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  */
884 BOOLEAN
885 NTAPI
886 RtlPrefixString(
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  */
933 BOOLEAN
934 NTAPI
935 RtlPrefixUnicodeString(
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  */
980 NTSTATUS
981 NTAPI
982 RtlUnicodeStringToInteger(
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  */
1089 ULONG
1090 NTAPI
1091 RtlxUnicodeStringToOemSize(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  */
1111 NTSTATUS
1112 NTAPI
1113 RtlUnicodeStringToAnsiString(
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  */
1178 NTSTATUS
1179 NTAPI
1180 RtlOemStringToUnicodeString(
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  */
1232 NTSTATUS
1233 NTAPI
1234 RtlUnicodeStringToOemString(
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  */
1288 BOOLEAN
1289 NTAPI
1290 RtlIsTextUnicode(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  */
1471 NTSTATUS
1472 NTAPI
1473 RtlOemStringToCountedUnicodeString(
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  */
1540 BOOLEAN
1541 NTAPI
1542 RtlEqualComputerName(
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  */
1577 BOOLEAN
1578 NTAPI
1579 RtlEqualDomainName (
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  */
1604 NTSTATUS
1605 NTAPI
1606 RtlGUIDFromString(
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  */
1720 VOID
1721 NTAPI
1722 RtlEraseUnicodeString(
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 */
1735 NTSTATUS
1736 NTAPI
1737 RtlHashUnicodeString(
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_
1789 NTSYSAPI
1790 NTSTATUS
1791 NTAPI
1792 RtlUnicodeStringToCountedOemString(
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  */
1858 NTSTATUS
1859 NTAPI
1860 RtlLargeIntegerToChar(
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  */
1915 NTSTATUS
1916 NTAPI
1917 RtlUpcaseUnicodeString(
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  */
1955 NTSTATUS
1956 NTAPI
1957 RtlUpcaseUnicodeStringToAnsiString(
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  */
2007 NTSTATUS
2008 NTAPI
2009 RtlUpcaseUnicodeStringToCountedOemString(
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  */
2067 NTSTATUS
2068 NTAPI
2069 RtlUpcaseUnicodeStringToOemString (
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  */
2122 ULONG
2123 NTAPI
2124 RtlxOemStringToUnicodeSize(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  */
2140 NTSTATUS
2141 NTAPI
2142 RtlStringFromGUID (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  */
2175 ULONG
2176 NTAPI
2177 RtlxUnicodeStringToAnsiSize(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  */
2196 LONG
2197 NTAPI
2198 RtlCompareUnicodeString(
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 VOID
2229 NTAPI
2230 RtlCopyString(
2231     IN OUT PSTRING DestinationString,
2232     IN const STRING *SourceString OPTIONAL)
2233 {
2234     ULONG SourceLength;
2235     PCHAR p1, p2;
2236 
2237     /* Check if there was no source given */
2238     if (!SourceString)
2239     {
2240         /* Simply return an empty string */
2241         DestinationString->Length = 0;
2242     }
2243     else
2244     {
2245         /* Choose the smallest length */
2246         SourceLength = min(DestinationString->MaximumLength,
2247                            SourceString->Length);
2248 
2249         /* Set it */
2250         DestinationString->Length = (USHORT)SourceLength;
2251 
2252         /* Save the pointers to each buffer */
2253         p1 = DestinationString->Buffer;
2254         p2 = SourceString->Buffer;
2255 
2256         /* Loop the buffer */
2257         while (SourceLength)
2258         {
2259             /* Copy the character and move on */
2260             *p1++ = * p2++;
2261             SourceLength--;
2262         }
2263     }
2264 }
2265 
2266 /*
2267  * @implemented
2268  */
2269 VOID
2270 NTAPI
2271 RtlCopyUnicodeString(
2272     IN OUT PUNICODE_STRING DestinationString,
2273     IN PCUNICODE_STRING SourceString)
2274 {
2275     ULONG SourceLength;
2276 
2277     if (!SourceString)
2278     {
2279         DestinationString->Length = 0;
2280     }
2281     else
2282     {
2283         SourceLength = min(DestinationString->MaximumLength,
2284                            SourceString->Length);
2285         DestinationString->Length = (USHORT)SourceLength;
2286 
2287         RtlCopyMemory(DestinationString->Buffer,
2288                       SourceString->Buffer,
2289                       SourceLength);
2290 
2291         if (DestinationString->Length < DestinationString->MaximumLength)
2292         {
2293             DestinationString->Buffer[SourceLength / sizeof(WCHAR)] = UNICODE_NULL;
2294         }
2295     }
2296 }
2297 
2298 /*
2299  * @implemented
2300  *
2301  * NOTES
2302  * Creates a nullterminated UNICODE_STRING
2303  */
2304 BOOLEAN
2305 NTAPI
2306 RtlCreateUnicodeString(
2307     IN OUT PUNICODE_STRING UniDest,
2308     IN PCWSTR  Source)
2309 {
2310     SIZE_T Size;
2311     PAGED_CODE_RTL();
2312 
2313     Size = (wcslen(Source) + 1) * sizeof(WCHAR);
2314     if (Size > MAXUSHORT) return FALSE;
2315 
2316     UniDest->Buffer = RtlpAllocateStringMemory((ULONG)Size, TAG_USTR);
2317 
2318     if (UniDest->Buffer == NULL) return FALSE;
2319 
2320     RtlCopyMemory(UniDest->Buffer, Source, Size);
2321     UniDest->MaximumLength = (USHORT)Size;
2322     UniDest->Length = (USHORT)Size - sizeof (WCHAR);
2323 
2324     return TRUE;
2325 }
2326 
2327 /*
2328  * @implemented
2329  */
2330 BOOLEAN
2331 NTAPI
2332 RtlCreateUnicodeStringFromAsciiz(
2333     OUT PUNICODE_STRING Destination,
2334     IN PCSZ Source)
2335 {
2336     ANSI_STRING AnsiString;
2337     NTSTATUS Status;
2338 
2339     RtlInitAnsiString(&AnsiString, Source);
2340 
2341     Status = RtlAnsiStringToUnicodeString(Destination,
2342                                           &AnsiString,
2343                                           TRUE);
2344 
2345     return NT_SUCCESS(Status);
2346 }
2347 
2348 /*
2349  * @implemented
2350  *
2351  * NOTES
2352  *  Dest is never '\0' terminated because it may be equal to src, and src
2353  *  might not be '\0' terminated.
2354  *  Dest->Length is only set upon success.
2355  */
2356 NTSTATUS
2357 NTAPI
2358 RtlDowncaseUnicodeString(
2359     IN OUT PUNICODE_STRING UniDest,
2360     IN PCUNICODE_STRING UniSource,
2361     IN BOOLEAN AllocateDestinationString)
2362 {
2363     ULONG i;
2364     ULONG StopGap;
2365     PAGED_CODE_RTL();
2366 
2367     if (AllocateDestinationString)
2368     {
2369         UniDest->MaximumLength = UniSource->Length;
2370         UniDest->Buffer = RtlpAllocateStringMemory(UniSource->Length, TAG_USTR);
2371         if (UniDest->Buffer == NULL) return STATUS_NO_MEMORY;
2372     }
2373     else if (UniSource->Length > UniDest->MaximumLength)
2374     {
2375         return STATUS_BUFFER_OVERFLOW;
2376     }
2377 
2378     UniDest->Length = UniSource->Length;
2379     StopGap = UniSource->Length / sizeof(WCHAR);
2380 
2381     for (i = 0 ; i < StopGap; i++)
2382     {
2383         if (UniSource->Buffer[i] < L'A')
2384         {
2385             UniDest->Buffer[i] = UniSource->Buffer[i];
2386         }
2387         else if (UniSource->Buffer[i] <= L'Z')
2388         {
2389             UniDest->Buffer[i] = (UniSource->Buffer[i] + (L'a' - L'A'));
2390         }
2391         else
2392         {
2393             UniDest->Buffer[i] = RtlpDowncaseUnicodeChar(UniSource->Buffer[i]);
2394         }
2395     }
2396 
2397     return STATUS_SUCCESS;
2398 }
2399 
2400 /*
2401  * @implemented
2402  *
2403  * NOTES
2404  *  if src is NULL dest is unchanged.
2405  *  dest is '\0' terminated when the MaximumLength allowes it.
2406  *  When dest fits exactly in MaximumLength characters the '\0' is ommitted.
2407  */
2408 NTSTATUS
2409 NTAPI
2410 RtlAppendUnicodeToString(IN OUT PUNICODE_STRING Destination,
2411                          IN PCWSTR Source)
2412 {
2413     USHORT Length;
2414     PWCHAR DestBuffer;
2415 
2416     if (Source)
2417     {
2418         UNICODE_STRING UnicodeSource;
2419 
2420         RtlInitUnicodeString(&UnicodeSource, Source);
2421         Length = UnicodeSource.Length;
2422 
2423         if (Destination->Length + Length > Destination->MaximumLength)
2424         {
2425             return STATUS_BUFFER_TOO_SMALL;
2426         }
2427 
2428         DestBuffer = &Destination->Buffer[Destination->Length / sizeof(WCHAR)];
2429         RtlMoveMemory(DestBuffer, Source, Length);
2430         Destination->Length += Length;
2431 
2432         /* append terminating '\0' if enough space */
2433         if (Destination->MaximumLength > Destination->Length)
2434         {
2435             DestBuffer[Length / sizeof(WCHAR)] = UNICODE_NULL;
2436         }
2437     }
2438 
2439     return STATUS_SUCCESS;
2440 }
2441 
2442 /*
2443  * @implemented
2444  *
2445  * NOTES
2446  *  if src is NULL dest is unchanged.
2447  *  dest is never '\0' terminated.
2448  */
2449 NTSTATUS
2450 NTAPI
2451 RtlAppendAsciizToString(
2452     IN OUT   PSTRING  Destination,
2453     IN PCSZ  Source)
2454 {
2455     SIZE_T Size;
2456 
2457     if (Source)
2458     {
2459         Size = strlen(Source);
2460 
2461         if (Destination->Length + Size > Destination->MaximumLength)
2462         {
2463             return STATUS_BUFFER_TOO_SMALL;
2464         }
2465 
2466         RtlMoveMemory(&Destination->Buffer[Destination->Length], Source, Size);
2467         Destination->Length += (USHORT)Size;
2468     }
2469 
2470     return STATUS_SUCCESS;
2471 }
2472 
2473 /*
2474  * @implemented
2475  */
2476 VOID
2477 NTAPI
2478 RtlUpperString(PSTRING DestinationString,
2479                const STRING *SourceString)
2480 {
2481     USHORT Length;
2482     PCHAR Src, Dest;
2483 
2484     Length = min(SourceString->Length,
2485                  DestinationString->MaximumLength);
2486 
2487     Src = SourceString->Buffer;
2488     Dest = DestinationString->Buffer;
2489     DestinationString->Length = Length;
2490 
2491     while (Length)
2492     {
2493         *Dest++ = RtlUpperChar(*Src++);
2494         Length--;
2495     }
2496 }
2497 
2498 /*
2499  * @implemented
2500  *
2501  * NOTES
2502  *  See RtlpDuplicateUnicodeString
2503  */
2504 NTSTATUS
2505 NTAPI
2506 RtlDuplicateUnicodeString(
2507     IN ULONG Flags,
2508     IN PCUNICODE_STRING SourceString,
2509     OUT PUNICODE_STRING DestinationString)
2510 {
2511     PAGED_CODE_RTL();
2512 
2513     if (SourceString == NULL || DestinationString == NULL ||
2514         SourceString->Length > SourceString->MaximumLength ||
2515         (SourceString->Length == 0 && SourceString->MaximumLength > 0 && SourceString->Buffer == NULL) ||
2516         Flags == RTL_DUPLICATE_UNICODE_STRING_ALLOCATE_NULL_STRING || Flags >= 4)
2517     {
2518         return STATUS_INVALID_PARAMETER;
2519     }
2520 
2521 
2522     if ((SourceString->Length == 0) &&
2523         (Flags != (RTL_DUPLICATE_UNICODE_STRING_NULL_TERMINATE |
2524                    RTL_DUPLICATE_UNICODE_STRING_ALLOCATE_NULL_STRING)))
2525     {
2526         DestinationString->Length = 0;
2527         DestinationString->MaximumLength = 0;
2528         DestinationString->Buffer = NULL;
2529     }
2530     else
2531     {
2532         UINT DestMaxLength = SourceString->Length;
2533 
2534         if (Flags & RTL_DUPLICATE_UNICODE_STRING_NULL_TERMINATE)
2535             DestMaxLength += sizeof(UNICODE_NULL);
2536 
2537         DestinationString->Buffer = RtlpAllocateStringMemory(DestMaxLength, TAG_USTR);
2538 
2539         if (DestinationString->Buffer == NULL)
2540             return STATUS_NO_MEMORY;
2541 
2542         RtlCopyMemory(DestinationString->Buffer, SourceString->Buffer, SourceString->Length);
2543         DestinationString->Length = SourceString->Length;
2544         DestinationString->MaximumLength = DestMaxLength;
2545 
2546         if (Flags & RTL_DUPLICATE_UNICODE_STRING_NULL_TERMINATE)
2547             DestinationString->Buffer[DestinationString->Length / sizeof(WCHAR)] = 0;
2548     }
2549 
2550     return STATUS_SUCCESS;
2551 }
2552 
2553 /*
2554  * @implemented
2555  */
2556 NTSTATUS
2557 NTAPI
2558 RtlValidateUnicodeString(
2559     _In_ ULONG Flags,
2560     _In_ PCUNICODE_STRING String)
2561 {
2562     /* In Windows <= 2003 no flags are supported yet! */
2563     if (Flags != 0)
2564         return STATUS_INVALID_PARAMETER;
2565 
2566     /* NOTE: a NULL Unicode string pointer is considered to be a valid one! */
2567     if (String == NULL)
2568     {
2569         return STATUS_SUCCESS;
2570     }
2571     else if (!((String->Buffer == NULL) && (String->Length != 0 || String->MaximumLength != 0)) &&
2572               (String->Length % sizeof(WCHAR) == 0) &&
2573               (String->MaximumLength % sizeof(WCHAR) == 0) &&
2574               (String->Length <= String->MaximumLength))
2575     {
2576         return STATUS_SUCCESS;
2577     }
2578     else
2579     {
2580         return STATUS_INVALID_PARAMETER;
2581     }
2582 }
2583 
2584 /*
2585  * @implemented
2586  */
2587 NTSTATUS
2588 NTAPI
2589 RtlpEnsureBufferSize(
2590     IN ULONG Flags,
2591     IN OUT PRTL_BUFFER Buffer,
2592     IN SIZE_T RequiredSize)
2593 {
2594     PUCHAR NewBuffer;
2595 
2596     /* Parameter checks */
2597     if (Flags & ~RTL_SKIP_BUFFER_COPY)
2598         return STATUS_INVALID_PARAMETER;
2599     if (Buffer == NULL)
2600         return STATUS_INVALID_PARAMETER;
2601 
2602     /*
2603      * We don't need to grow the buffer if its size
2604      * is already larger than the required size.
2605      */
2606     if (Buffer->Size >= RequiredSize)
2607         return STATUS_SUCCESS;
2608 
2609     /*
2610      * When we are using the static buffer as our buffer, we don't need
2611      * to grow it if its size is already larger than the required size.
2612      * In this case, just keep it but update the current buffer size to
2613      * the one requested.
2614      * (But NEVER EVER modify the size of the static buffer!!)
2615      * Otherwise, we'll need to create a new buffer and use this one instead.
2616      */
2617     if ( (Buffer->Buffer == Buffer->StaticBuffer) &&
2618          (Buffer->StaticSize >= RequiredSize) )
2619     {
2620         Buffer->Size = RequiredSize;
2621         return STATUS_SUCCESS;
2622     }
2623 
2624     /* The buffer we are using is not large enough, try to create a bigger one */
2625     NewBuffer = RtlpAllocateStringMemory(RequiredSize, TAG_USTR);
2626     if (NewBuffer == NULL)
2627         return STATUS_NO_MEMORY;
2628 
2629     /* Copy the original content if needed */
2630     if (!(Flags & RTL_SKIP_BUFFER_COPY))
2631     {
2632         RtlMoveMemory(NewBuffer, Buffer->Buffer, Buffer->Size);
2633     }
2634 
2635     /* Free the original buffer only if it's not the static buffer */
2636     if (Buffer->Buffer != Buffer->StaticBuffer)
2637     {
2638         RtlpFreeStringMemory(Buffer->Buffer, TAG_USTR);
2639     }
2640 
2641     /* Update the members */
2642     Buffer->Buffer = NewBuffer;
2643     Buffer->Size   = RequiredSize;
2644 
2645     /* Done */
2646     return STATUS_SUCCESS;
2647 }
2648 
2649 static
2650 BOOLEAN
2651 RtlpIsCharInUnicodeString(
2652     IN WCHAR Char,
2653     IN PCUNICODE_STRING MatchString,
2654     IN BOOLEAN CaseInSensitive)
2655 {
2656     USHORT i;
2657 
2658     if (CaseInSensitive)
2659         Char = RtlpUpcaseUnicodeChar(Char);
2660 
2661     for (i = 0; i < MatchString->Length / sizeof(WCHAR); i++)
2662     {
2663         WCHAR OtherChar = MatchString->Buffer[i];
2664         if (CaseInSensitive)
2665             OtherChar = RtlpUpcaseUnicodeChar(OtherChar);
2666 
2667         if (Char == OtherChar)
2668             return TRUE;
2669     }
2670 
2671     return FALSE;
2672 }
2673 
2674 /*
2675  * @implemented
2676  */
2677 NTSTATUS
2678 NTAPI
2679 RtlFindCharInUnicodeString(
2680     IN ULONG Flags,
2681     IN PCUNICODE_STRING SearchString,
2682     IN PCUNICODE_STRING MatchString,
2683     OUT PUSHORT Position)
2684 {
2685     BOOLEAN Found;
2686     const BOOLEAN WantToFind = (Flags & RTL_FIND_CHAR_IN_UNICODE_STRING_COMPLEMENT_CHAR_SET) == 0;
2687     const BOOLEAN CaseInSensitive = (Flags & RTL_FIND_CHAR_IN_UNICODE_STRING_CASE_INSENSITIVE) != 0;
2688     USHORT i, Length;
2689 
2690     DPRINT("RtlFindCharInUnicodeString(%u, '%wZ', '%wZ', %p)\n",
2691            Flags, SearchString, MatchString, Position);
2692 
2693     /* Parameter checks */
2694     if (Position == NULL)
2695         return STATUS_INVALID_PARAMETER;
2696 
2697     *Position = 0;
2698 
2699     if (Flags & ~(RTL_FIND_CHAR_IN_UNICODE_STRING_START_AT_END |
2700                   RTL_FIND_CHAR_IN_UNICODE_STRING_COMPLEMENT_CHAR_SET |
2701                   RTL_FIND_CHAR_IN_UNICODE_STRING_CASE_INSENSITIVE))
2702         return STATUS_INVALID_PARAMETER;
2703 
2704     /* Search */
2705     Length = SearchString->Length / sizeof(WCHAR);
2706     if (Flags & RTL_FIND_CHAR_IN_UNICODE_STRING_START_AT_END)
2707     {
2708         for (i = Length - 1; (SHORT)i >= 0; i--)
2709         {
2710             Found = RtlpIsCharInUnicodeString(SearchString->Buffer[i], MatchString, CaseInSensitive);
2711             if (Found == WantToFind)
2712             {
2713                 *Position = i * sizeof(WCHAR);
2714                 return STATUS_SUCCESS;
2715             }
2716         }
2717     }
2718     else
2719     {
2720         for (i = 0; i < Length; i++)
2721         {
2722             Found = RtlpIsCharInUnicodeString(SearchString->Buffer[i], MatchString, CaseInSensitive);
2723             if (Found == WantToFind)
2724             {
2725                 *Position = (i + 1) * sizeof(WCHAR);
2726                 return STATUS_SUCCESS;
2727             }
2728         }
2729     }
2730 
2731     return STATUS_NOT_FOUND;
2732 }
2733 
2734 /*
2735  * @implemented
2736  *
2737  * NOTES
2738  *  Get the maximum of MAX_COMPUTERNAME_LENGTH characters from the dns.host name until the dot is found.
2739  *  Convert is to an uppercase oem string and check for unmapped characters.
2740  *  Then convert the oem string back to an unicode string.
2741  */
2742 NTSTATUS
2743 NTAPI
2744 RtlDnsHostNameToComputerName(PUNICODE_STRING ComputerName, PUNICODE_STRING DnsHostName, BOOLEAN AllocateComputerNameString)
2745 {
2746     NTSTATUS Status;
2747     ULONG Length;
2748     ULONG ComputerNameLength;
2749     ULONG ComputerNameOemNLength;
2750     OEM_STRING ComputerNameOem;
2751     CHAR ComputerNameOemN[MAX_COMPUTERNAME_LENGTH + 1];
2752 
2753     Status = STATUS_INVALID_COMPUTER_NAME;
2754     ComputerNameLength = DnsHostName->Length;
2755 
2756     /* find the first dot in the dns host name */
2757     for (Length = 0; Length < DnsHostName->Length / sizeof(WCHAR); Length++)
2758     {
2759         if (DnsHostName->Buffer[Length] == L'.')
2760         {
2761             /* dot found, so set the length for the oem translation */
2762             ComputerNameLength = Length * sizeof(WCHAR);
2763             break;
2764         }
2765     }
2766 
2767     /* the computername must have one character */
2768     if (ComputerNameLength > 0)
2769     {
2770         ComputerNameOemNLength = 0;
2771         /* convert to oem string and use uppercase letters */
2772         Status = RtlUpcaseUnicodeToOemN(ComputerNameOemN,
2773                                         MAX_COMPUTERNAME_LENGTH,
2774                                         &ComputerNameOemNLength,
2775                                         DnsHostName->Buffer,
2776                                         ComputerNameLength);
2777 
2778         /* status STATUS_BUFFER_OVERFLOW is not a problem since the computername shoud only
2779            have MAX_COMPUTERNAME_LENGTH characters */
2780         if ((Status == STATUS_SUCCESS) ||
2781                 (Status == STATUS_BUFFER_OVERFLOW))
2782         {
2783             /* set the termination for the oem string */
2784             ComputerNameOemN[MAX_COMPUTERNAME_LENGTH] = 0;
2785             /* set status for the case the next function failed */
2786             Status = STATUS_INVALID_COMPUTER_NAME;
2787             /* fillup the oem string structure with the converted computername
2788                and check it for unmapped characters */
2789             ComputerNameOem.Buffer = ComputerNameOemN;
2790             ComputerNameOem.Length = (USHORT)ComputerNameOemNLength;
2791             ComputerNameOem.MaximumLength = (USHORT)(MAX_COMPUTERNAME_LENGTH + 1);
2792 
2793             if (RtlpDidUnicodeToOemWork(DnsHostName, &ComputerNameOem))
2794             {
2795                 /* no unmapped character so convert it back to an unicode string */
2796                 Status = RtlOemStringToUnicodeString(ComputerName,
2797                                                      &ComputerNameOem,
2798                                                      AllocateComputerNameString);
2799             }
2800         }
2801     }
2802 
2803     return Status;
2804 }
2805 
2806