xref: /reactos/sdk/lib/rtl/unicode.c (revision 24cb57fd)
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)
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             if (pf && (*pf & IS_TEXT_UNICODE_DBCS_LEADBYTE))
1382                 out_flags |= IS_TEXT_UNICODE_DBCS_LEADBYTE;
1383         }
1384     }
1385 
1386     if (lo_byte_diff < 127 && !hi_byte_diff)
1387     {
1388         out_flags |= IS_TEXT_UNICODE_ASCII16;
1389     }
1390 
1391     if (hi_byte_diff && !lo_byte_diff)
1392     {
1393         out_flags |= IS_TEXT_UNICODE_REVERSE_ASCII16;
1394     }
1395 
1396     if ((weight * lo_byte_diff) < hi_byte_diff)
1397     {
1398         out_flags |= IS_TEXT_UNICODE_REVERSE_STATISTICS;
1399     }
1400 
1401     /* apply some statistical analysis */
1402     if ((flags & IS_TEXT_UNICODE_STATISTICS) &&
1403         ((weight * hi_byte_diff) < lo_byte_diff))
1404     {
1405         out_flags |= IS_TEXT_UNICODE_STATISTICS;
1406     }
1407 
1408     /* Check for unicode NULL chars */
1409     if (flags & IS_TEXT_UNICODE_NULL_BYTES)
1410     {
1411         for (i = 0; i < len; i++)
1412         {
1413             if (!(s[i] & 0xff) || !(s[i] >> 8))
1414             {
1415                 out_flags |= IS_TEXT_UNICODE_NULL_BYTES;
1416                 break;
1417             }
1418         }
1419     }
1420 
1421     if (flags & IS_TEXT_UNICODE_CONTROLS)
1422     {
1423         for (i = 0; i < len; i++)
1424         {
1425             if (strchrW(std_control_chars, s[i]))
1426             {
1427                 out_flags |= IS_TEXT_UNICODE_CONTROLS;
1428                 break;
1429             }
1430         }
1431     }
1432 
1433     if (flags & IS_TEXT_UNICODE_REVERSE_CONTROLS)
1434     {
1435         for (i = 0; i < len; i++)
1436         {
1437             if (strchrW(byterev_control_chars, s[i]))
1438             {
1439                 out_flags |= IS_TEXT_UNICODE_REVERSE_CONTROLS;
1440                 break;
1441             }
1442         }
1443     }
1444 
1445     if (pf)
1446     {
1447         out_flags &= *pf;
1448         *pf = out_flags;
1449     }
1450 
1451     /* check for flags that indicate it's definitely not valid Unicode */
1452     if (out_flags & (IS_TEXT_UNICODE_REVERSE_MASK | IS_TEXT_UNICODE_NOT_UNICODE_MASK)) return FALSE;
1453 
1454     /* now check for invalid ASCII, and assume Unicode if so */
1455     if (out_flags & IS_TEXT_UNICODE_NOT_ASCII_MASK) return TRUE;
1456 
1457     /* now check for Unicode flags */
1458     if (out_flags & IS_TEXT_UNICODE_UNICODE_MASK) return TRUE;
1459 
1460     /* no flags set */
1461     return FALSE;
1462 }
1463 
1464 
1465 /*
1466  * @implemented
1467  *
1468  * NOTES
1469  *  Same as RtlOemStringToUnicodeString but doesn't write terminating null
1470  *  A partial copy is NOT performed if the dest buffer is too small!
1471  */
1472 NTSTATUS
1473 NTAPI
1474 RtlOemStringToCountedUnicodeString(
1475     IN OUT PUNICODE_STRING UniDest,
1476     IN PCOEM_STRING OemSource,
1477     IN BOOLEAN AllocateDestinationString)
1478 {
1479     NTSTATUS Status;
1480     ULONG Length;
1481     ULONG Index;
1482 
1483     PAGED_CODE_RTL();
1484 
1485     /* Calculate size of the string */
1486     Length = RtlOemStringToCountedUnicodeSize(OemSource);
1487 
1488     /* If it's 0 then zero out dest string and return */
1489     if (!Length)
1490     {
1491         RtlZeroMemory(UniDest, sizeof(UNICODE_STRING));
1492         return STATUS_SUCCESS;
1493     }
1494 
1495     /* Check if length is a sane value */
1496     if (Length > MAXUSHORT) return STATUS_INVALID_PARAMETER_2;
1497 
1498     /* Store it in dest string */
1499     UniDest->Length = (USHORT)Length;
1500 
1501     /* If we're asked to alloc the string - do so */
1502     if (AllocateDestinationString)
1503     {
1504         UniDest->Buffer = RtlpAllocateStringMemory(Length, TAG_USTR);
1505         UniDest->MaximumLength = (USHORT)Length;
1506 
1507         if (!UniDest->Buffer) return STATUS_NO_MEMORY;
1508     }
1509     else if (UniDest->Length > UniDest->MaximumLength)
1510     {
1511         return STATUS_BUFFER_OVERFLOW;
1512     }
1513 
1514     /* Do the conversion */
1515     Status = RtlOemToUnicodeN(UniDest->Buffer,
1516                               UniDest->Length,
1517                               &Index,
1518                               OemSource->Buffer,
1519                               OemSource->Length);
1520 
1521     if (!NT_SUCCESS(Status) && AllocateDestinationString)
1522     {
1523         /* Conversion failed, free dest string and return status code */
1524         RtlpFreeStringMemory(UniDest->Buffer, TAG_USTR);
1525         UniDest->Buffer = NULL;
1526         return Status;
1527     }
1528 
1529     return STATUS_SUCCESS;
1530 }
1531 
1532 /*
1533  * @implemented
1534  *
1535  * RETURNS
1536  *  TRUE if the names are equal, FALSE if not
1537  *
1538  * NOTES
1539  *  The comparison is case insensitive.
1540  */
1541 BOOLEAN
1542 NTAPI
1543 RtlEqualComputerName(
1544     IN PUNICODE_STRING ComputerName1,
1545     IN PUNICODE_STRING ComputerName2)
1546 {
1547     OEM_STRING OemString1;
1548     OEM_STRING OemString2;
1549     BOOLEAN Result = FALSE;
1550 
1551     if (NT_SUCCESS(RtlUpcaseUnicodeStringToOemString(&OemString1,
1552                                                      ComputerName1,
1553                                                      TRUE)))
1554     {
1555         if (NT_SUCCESS(RtlUpcaseUnicodeStringToOemString(&OemString2,
1556                                                          ComputerName2,
1557                                                          TRUE)))
1558         {
1559             Result = RtlEqualString(&OemString1, &OemString2, FALSE);
1560             RtlFreeOemString(&OemString2);
1561         }
1562 
1563         RtlFreeOemString(&OemString1);
1564     }
1565 
1566     return Result;
1567 }
1568 
1569 /*
1570  * @implemented
1571  *
1572  * RETURNS
1573  *  TRUE if the names are equal, FALSE if not
1574  *
1575  * NOTES
1576  *  The comparison is case insensitive.
1577  */
1578 BOOLEAN
1579 NTAPI
1580 RtlEqualDomainName (
1581     IN PUNICODE_STRING DomainName1,
1582     IN PUNICODE_STRING DomainName2)
1583 {
1584     return RtlEqualComputerName(DomainName1, DomainName2);
1585 }
1586 
1587 /*
1588  * @implemented
1589  *
1590  * RIPPED FROM WINE's ntdll\rtlstr.c rev 1.45
1591  *
1592  * Convert a string representation of a GUID into a GUID.
1593  *
1594  * PARAMS
1595  *  str  [I] String representation in the format "{XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX}"
1596  *  guid [O] Destination for the converted GUID
1597  *
1598  * RETURNS
1599  *  Success: STATUS_SUCCESS. guid contains the converted value.
1600  *  Failure: STATUS_INVALID_PARAMETER, if str is not in the expected format.
1601  *
1602  * SEE ALSO
1603  *  See RtlStringFromGUID.
1604  */
1605 NTSTATUS
1606 NTAPI
1607 RtlGUIDFromString(
1608     IN UNICODE_STRING *str,
1609     OUT GUID* guid)
1610 {
1611     int i = 0;
1612     const WCHAR *lpszCLSID = str->Buffer;
1613     BYTE* lpOut = (BYTE*)guid;
1614 
1615     //TRACE("(%s,%p)\n", debugstr_us(str), guid);
1616 
1617     /* Convert string: {XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX}
1618      * to memory:       DWORD... WORD WORD BYTES............
1619      */
1620     while (i <= 37)
1621     {
1622         switch (i)
1623         {
1624             case 0:
1625                 if (*lpszCLSID != '{')
1626                     return STATUS_INVALID_PARAMETER;
1627                 break;
1628 
1629             case 9:
1630             case 14:
1631             case 19:
1632             case 24:
1633                 if (*lpszCLSID != '-')
1634                     return STATUS_INVALID_PARAMETER;
1635                 break;
1636 
1637             case 37:
1638                 if (*lpszCLSID != '}')
1639                     return STATUS_INVALID_PARAMETER;
1640 
1641                 break;
1642 
1643             default:
1644             {
1645                 WCHAR ch = *lpszCLSID, ch2 = lpszCLSID[1];
1646                 unsigned char byte;
1647 
1648                 /* Read two hex digits as a byte value */
1649                 if      (ch >= '0' && ch <= '9')
1650                     ch = ch - '0';
1651                 else if (ch >= 'a' && ch <= 'f')
1652                     ch = ch - 'a' + 10;
1653                 else if (ch >= 'A' && ch <= 'F')
1654                     ch = ch - 'A' + 10;
1655                 else
1656                     return STATUS_INVALID_PARAMETER;
1657 
1658                 if      (ch2 >= '0' && ch2 <= '9')
1659                     ch2 = ch2 - '0';
1660                 else if (ch2 >= 'a' && ch2 <= 'f')
1661                     ch2 = ch2 - 'a' + 10;
1662                 else if (ch2 >= 'A' && ch2 <= 'F')
1663                     ch2 = ch2 - 'A' + 10;
1664                 else
1665                     return STATUS_INVALID_PARAMETER;
1666 
1667                 byte = ch << 4 | ch2;
1668 
1669                 switch (i)
1670                 {
1671 #ifndef WORDS_BIGENDIAN
1672                         /* For Big Endian machines, we store the data such that the
1673                          * dword/word members can be read as DWORDS and WORDS correctly. */
1674                         /* Dword */
1675                     case 1:
1676                         lpOut[3] = byte;
1677                         break;
1678                     case 3:
1679                         lpOut[2] = byte;
1680                         break;
1681                     case 5:
1682                         lpOut[1] = byte;
1683                         break;
1684                     case 7:
1685                         lpOut[0] = byte;
1686                         lpOut += 4;
1687                         break;
1688                         /* Word */
1689                     case 10:
1690                     case 15:
1691                         lpOut[1] = byte;
1692                         break;
1693                     case 12:
1694                     case 17:
1695                         lpOut[0] = byte;
1696                         lpOut += 2;
1697                         break;
1698 #endif
1699                         /* Byte */
1700                     default:
1701                         lpOut[0] = byte;
1702                         lpOut++;
1703                         break;
1704                 }
1705 
1706                 lpszCLSID++; /* Skip 2nd character of byte */
1707                 i++;
1708             }
1709         }
1710 
1711         lpszCLSID++;
1712         i++;
1713     }
1714 
1715     return STATUS_SUCCESS;
1716 }
1717 
1718 /*
1719  * @implemented
1720  */
1721 VOID
1722 NTAPI
1723 RtlEraseUnicodeString(
1724     IN PUNICODE_STRING String)
1725 {
1726     if (String->Buffer && String->MaximumLength)
1727     {
1728         RtlZeroMemory(String->Buffer, String->MaximumLength);
1729         String->Length = 0;
1730     }
1731 }
1732 
1733 /*
1734 * @implemented
1735 */
1736 NTSTATUS
1737 NTAPI
1738 RtlHashUnicodeString(
1739     IN CONST UNICODE_STRING *String,
1740     IN BOOLEAN CaseInSensitive,
1741     IN ULONG HashAlgorithm,
1742     OUT PULONG HashValue)
1743 {
1744     if (String != NULL && HashValue != NULL)
1745     {
1746         switch (HashAlgorithm)
1747         {
1748             case HASH_STRING_ALGORITHM_DEFAULT:
1749             case HASH_STRING_ALGORITHM_X65599:
1750             {
1751                 WCHAR *c, *end;
1752 
1753                 *HashValue = 0;
1754                 end = String->Buffer + (String->Length / sizeof(WCHAR));
1755 
1756                 if (CaseInSensitive)
1757                 {
1758                     for (c = String->Buffer; c != end; c++)
1759                     {
1760                         /* only uppercase characters if they are 'a' ... 'z'! */
1761                         *HashValue = ((65599 * (*HashValue)) +
1762                                       (ULONG)(((*c) >= L'a' && (*c) <= L'z') ?
1763                                               (*c) - L'a' + L'A' : (*c)));
1764                     }
1765                 }
1766                 else
1767                 {
1768                     for (c = String->Buffer; c != end; c++)
1769                     {
1770                         *HashValue = ((65599 * (*HashValue)) + (ULONG)(*c));
1771                     }
1772                 }
1773 
1774                 return STATUS_SUCCESS;
1775             }
1776         }
1777     }
1778 
1779     return STATUS_INVALID_PARAMETER;
1780 }
1781 
1782 /*
1783  * @implemented
1784  *
1785  * NOTES
1786  *  Same as RtlUnicodeStringToOemString but doesn't write terminating null
1787  */
1788 _IRQL_requires_max_(PASSIVE_LEVEL)
1789 _Must_inspect_result_
1790 NTSYSAPI
1791 NTSTATUS
1792 NTAPI
1793 RtlUnicodeStringToCountedOemString(
1794     _When_(AllocateDestinationString, _Out_ _At_(DestinationString->Buffer, __drv_allocatesMem(Mem)))
1795     _When_(!AllocateDestinationString, _Inout_)
1796         POEM_STRING OemDest,
1797     _In_ PCUNICODE_STRING UniSource,
1798     _In_ BOOLEAN AllocateDestinationString)
1799 {
1800     NTSTATUS Status;
1801     ULONG Length;
1802     ULONG Index;
1803 
1804     PAGED_CODE_RTL();
1805 
1806     /* Calculate size of the string */
1807     Length = RtlUnicodeStringToCountedOemSize(UniSource);
1808 
1809     /* If it's 0 then zero out dest string and return */
1810     if (!Length)
1811     {
1812         RtlZeroMemory(OemDest, sizeof(OEM_STRING));
1813         return STATUS_SUCCESS;
1814     }
1815 
1816     /* Check if length is a sane value */
1817     if (Length > MAXUSHORT) return STATUS_INVALID_PARAMETER_2;
1818 
1819     /* Store it in dest string */
1820     OemDest->Length = (USHORT)Length;
1821 
1822     /* If we're asked to alloc the string - do so */
1823     if (AllocateDestinationString)
1824     {
1825         OemDest->Buffer = RtlpAllocateStringMemory(Length, TAG_OSTR);
1826         OemDest->MaximumLength = (USHORT)Length;
1827         if (!OemDest->Buffer) return STATUS_NO_MEMORY;
1828     }
1829     else if (OemDest->Length > OemDest->MaximumLength)
1830     {
1831         return STATUS_BUFFER_OVERFLOW;
1832     }
1833 
1834     /* Do the conversion */
1835     Status = RtlUnicodeToOemN(OemDest->Buffer,
1836                               OemDest->Length,
1837                               &Index,
1838                               UniSource->Buffer,
1839                               UniSource->Length);
1840 
1841     /* Check for unmapped character */
1842     if (NT_SUCCESS(Status) && !RtlpDidUnicodeToOemWork(UniSource, OemDest))
1843         Status = STATUS_UNMAPPABLE_CHARACTER;
1844 
1845     if (!NT_SUCCESS(Status) && AllocateDestinationString)
1846     {
1847         /* Conversion failed, free dest string and return status code */
1848         RtlpFreeStringMemory(OemDest->Buffer, TAG_OSTR);
1849         OemDest->Buffer = NULL;
1850         return Status;
1851     }
1852 
1853     return Status;
1854 }
1855 
1856 /*
1857  * @implemented
1858  */
1859 NTSTATUS
1860 NTAPI
1861 RtlLargeIntegerToChar(
1862     IN PLARGE_INTEGER Value,
1863     IN ULONG  Base,
1864     IN ULONG  Length,
1865     IN OUT PCHAR  String)
1866 {
1867     ULONGLONG Val = Value->QuadPart;
1868     CHAR Buffer[65];
1869     CHAR Digit;
1870     SIZE_T Len;
1871     PCHAR Pos;
1872 
1873     if (Base == 0) Base = 10;
1874 
1875     if ((Base != 2) && (Base != 8) && (Base != 10) && (Base != 16))
1876     {
1877         return STATUS_INVALID_PARAMETER;
1878     }
1879 
1880     Pos = &Buffer[64];
1881     *Pos = '\0';
1882 
1883     do
1884     {
1885         Pos--;
1886         Digit = (CHAR)(Val % Base);
1887         Val = Val / Base;
1888 
1889         if (Digit < 10)
1890             *Pos = '0' + Digit;
1891         else
1892             *Pos = 'A' + Digit - 10;
1893     }
1894     while (Val != 0L);
1895 
1896     Len = &Buffer[64] - Pos;
1897 
1898     if (Len > Length)
1899         return STATUS_BUFFER_OVERFLOW;
1900 
1901     /* If possible, add the 0 termination */
1902     if (Len < Length)
1903         Len += 1;
1904 
1905     /* Copy the string to the target using SEH */
1906     return RtlpSafeCopyMemory(String, Pos, Len);
1907 }
1908 
1909 /*
1910  * @implemented
1911  *
1912  * NOTES
1913  *  dest is never '\0' terminated because it may be equal to src, and src
1914  *  might not be '\0' terminated. dest->Length is only set upon success.
1915  */
1916 NTSTATUS
1917 NTAPI
1918 RtlUpcaseUnicodeString(
1919     IN OUT PUNICODE_STRING UniDest,
1920     IN PCUNICODE_STRING UniSource,
1921     IN BOOLEAN  AllocateDestinationString)
1922 {
1923     ULONG i, j;
1924 
1925     PAGED_CODE_RTL();
1926 
1927     if (AllocateDestinationString)
1928     {
1929         UniDest->MaximumLength = UniSource->Length;
1930         UniDest->Buffer = RtlpAllocateStringMemory(UniDest->MaximumLength, TAG_USTR);
1931         if (UniDest->Buffer == NULL) return STATUS_NO_MEMORY;
1932     }
1933     else if (UniSource->Length > UniDest->MaximumLength)
1934     {
1935         return STATUS_BUFFER_OVERFLOW;
1936     }
1937 
1938     j = UniSource->Length / sizeof(WCHAR);
1939 
1940     for (i = 0; i < j; i++)
1941     {
1942         UniDest->Buffer[i] = RtlpUpcaseUnicodeChar(UniSource->Buffer[i]);
1943     }
1944 
1945     UniDest->Length = UniSource->Length;
1946     return STATUS_SUCCESS;
1947 }
1948 
1949 /*
1950  * @implemented
1951  *
1952  * NOTES
1953  *  This function always writes a terminating '\0'.
1954  *  It performs a partial copy if ansi is too small.
1955  */
1956 NTSTATUS
1957 NTAPI
1958 RtlUpcaseUnicodeStringToAnsiString(
1959     IN OUT PANSI_STRING AnsiDest,
1960     IN PCUNICODE_STRING UniSource,
1961     IN BOOLEAN  AllocateDestinationString)
1962 {
1963     NTSTATUS Status;
1964     ULONG Length;
1965     ULONG Index;
1966     PAGED_CODE_RTL();
1967 
1968     Length = RtlUnicodeStringToAnsiSize(UniSource);
1969     if (Length > MAXUSHORT) return STATUS_INVALID_PARAMETER_2;
1970 
1971     AnsiDest->Length = (USHORT)Length - sizeof(CHAR);
1972 
1973     if (AllocateDestinationString)
1974     {
1975         AnsiDest->Buffer = RtlpAllocateStringMemory(Length, TAG_ASTR);
1976         AnsiDest->MaximumLength = (USHORT)Length;
1977         if (!AnsiDest->Buffer) return STATUS_NO_MEMORY;
1978     }
1979     else if (AnsiDest->Length >= AnsiDest->MaximumLength)
1980     {
1981         if (!AnsiDest->MaximumLength) return STATUS_BUFFER_OVERFLOW;
1982     }
1983 
1984     Status = RtlUpcaseUnicodeToMultiByteN(AnsiDest->Buffer,
1985                                           AnsiDest->Length,
1986                                           &Index,
1987                                           UniSource->Buffer,
1988                                           UniSource->Length);
1989 
1990     if (!NT_SUCCESS(Status) && AllocateDestinationString)
1991     {
1992         RtlpFreeStringMemory(AnsiDest->Buffer, TAG_ASTR);
1993         AnsiDest->Buffer = NULL;
1994         return Status;
1995     }
1996 
1997     AnsiDest->Buffer[Index] = ANSI_NULL;
1998     return Status;
1999 }
2000 
2001 /*
2002  * @implemented
2003  *
2004  * NOTES
2005  *  This function always writes a terminating '\0'.
2006  *  It performs a partial copy if ansi is too small.
2007  */
2008 NTSTATUS
2009 NTAPI
2010 RtlUpcaseUnicodeStringToCountedOemString(
2011     IN OUT POEM_STRING OemDest,
2012     IN PCUNICODE_STRING UniSource,
2013     IN BOOLEAN AllocateDestinationString)
2014 {
2015     NTSTATUS Status;
2016     ULONG Length;
2017     ULONG Index;
2018     PAGED_CODE_RTL();
2019 
2020     Length = RtlUnicodeStringToCountedOemSize(UniSource);
2021 
2022     if (!Length)
2023     {
2024         RtlZeroMemory(OemDest, sizeof(OEM_STRING));
2025     }
2026 
2027     if (Length > MAXUSHORT) return STATUS_INVALID_PARAMETER_2;
2028 
2029     OemDest->Length = (USHORT)Length;
2030 
2031     if (AllocateDestinationString)
2032     {
2033         OemDest->Buffer = RtlpAllocateStringMemory(Length, TAG_OSTR);
2034         OemDest->MaximumLength = (USHORT)Length;
2035         if (!OemDest->Buffer) return STATUS_NO_MEMORY;
2036     }
2037     else if (OemDest->Length > OemDest->MaximumLength)
2038     {
2039         return STATUS_BUFFER_OVERFLOW;
2040     }
2041 
2042     Status = RtlUpcaseUnicodeToOemN(OemDest->Buffer,
2043                                     OemDest->Length,
2044                                     &Index,
2045                                     UniSource->Buffer,
2046                                     UniSource->Length);
2047 
2048     /* Check for unmapped characters */
2049     if (NT_SUCCESS(Status) && !RtlpDidUnicodeToOemWork(UniSource, OemDest))
2050         Status = STATUS_UNMAPPABLE_CHARACTER;
2051 
2052     if (!NT_SUCCESS(Status) && AllocateDestinationString)
2053     {
2054         RtlpFreeStringMemory(OemDest->Buffer, TAG_OSTR);
2055         OemDest->Buffer = NULL;
2056         return Status;
2057     }
2058 
2059     return Status;
2060 }
2061 
2062 /*
2063  * @implemented
2064  * NOTES
2065  *  OEM string is always nullterminated
2066  *  It performs a partial copy if oem is too small.
2067  */
2068 NTSTATUS
2069 NTAPI
2070 RtlUpcaseUnicodeStringToOemString (
2071     IN OUT POEM_STRING OemDest,
2072     IN PCUNICODE_STRING UniSource,
2073     IN BOOLEAN  AllocateDestinationString)
2074 {
2075     NTSTATUS Status;
2076     ULONG Length;
2077     ULONG Index;
2078     PAGED_CODE_RTL();
2079 
2080     Length = RtlUnicodeStringToOemSize(UniSource);
2081     if (Length > MAXUSHORT) return STATUS_INVALID_PARAMETER_2;
2082 
2083     OemDest->Length = (USHORT)Length - sizeof(CHAR);
2084 
2085     if (AllocateDestinationString)
2086     {
2087         OemDest->Buffer = RtlpAllocateStringMemory(Length, TAG_OSTR);
2088         OemDest->MaximumLength = (USHORT)Length;
2089         if (!OemDest->Buffer) return STATUS_NO_MEMORY;
2090     }
2091     else if (OemDest->Length >= OemDest->MaximumLength)
2092     {
2093         return STATUS_BUFFER_OVERFLOW;
2094     }
2095 
2096     Status = RtlUpcaseUnicodeToOemN(OemDest->Buffer,
2097                                     OemDest->Length,
2098                                     &Index,
2099                                     UniSource->Buffer,
2100                                     UniSource->Length);
2101 
2102     /* Check for unmapped characters */
2103     if (NT_SUCCESS(Status) && !RtlpDidUnicodeToOemWork(UniSource, OemDest))
2104         Status = STATUS_UNMAPPABLE_CHARACTER;
2105 
2106     if (!NT_SUCCESS(Status) && AllocateDestinationString)
2107     {
2108         RtlpFreeStringMemory(OemDest->Buffer, TAG_OSTR);
2109         OemDest->Buffer = NULL;
2110         return Status;
2111     }
2112 
2113     OemDest->Buffer[Index] = ANSI_NULL;
2114     return Status;
2115 }
2116 
2117 /*
2118  * @implemented
2119  *
2120  * RETURNS
2121  *  Bytes calculated including nullterm
2122  */
2123 ULONG
2124 NTAPI
2125 RtlxOemStringToUnicodeSize(IN PCOEM_STRING OemString)
2126 {
2127     ULONG Size;
2128 
2129     /* Convert the Mb String to Unicode Size */
2130     RtlMultiByteToUnicodeSize(&Size,
2131                               OemString->Buffer,
2132                               OemString->Length);
2133 
2134     /* Return the size + null-char */
2135     return (Size + sizeof(WCHAR));
2136 }
2137 
2138 /*
2139  * @implemented
2140  */
2141 NTSTATUS
2142 NTAPI
2143 RtlStringFromGUID (IN REFGUID Guid,
2144                    OUT PUNICODE_STRING GuidString)
2145 {
2146     /* Setup the string */
2147     GuidString->Length = 38 * sizeof(WCHAR);
2148     GuidString->MaximumLength = GuidString->Length + sizeof(UNICODE_NULL);
2149     GuidString->Buffer = RtlpAllocateStringMemory(GuidString->MaximumLength,
2150                                                   TAG_USTR);
2151     if (!GuidString->Buffer) return STATUS_NO_MEMORY;
2152 
2153     /* Now format the GUID */
2154     swprintf(GuidString->Buffer,
2155              L"{%08lx-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x}",
2156              Guid->Data1,
2157              Guid->Data2,
2158              Guid->Data3,
2159              Guid->Data4[0],
2160              Guid->Data4[1],
2161              Guid->Data4[2],
2162              Guid->Data4[3],
2163              Guid->Data4[4],
2164              Guid->Data4[5],
2165              Guid->Data4[6],
2166              Guid->Data4[7]);
2167     return STATUS_SUCCESS;
2168 }
2169 
2170 /*
2171  * @implemented
2172  *
2173  * RETURNS
2174  *  Bytes calculated including nullterm
2175  */
2176 ULONG
2177 NTAPI
2178 RtlxUnicodeStringToAnsiSize(IN PCUNICODE_STRING UnicodeString)
2179 {
2180     ULONG Size;
2181     PAGED_CODE_RTL();
2182 
2183     ASSERT(!(UnicodeString->Length & 1));
2184 
2185     /* Convert the Unicode String to Mb Size */
2186     RtlUnicodeToMultiByteSize(&Size,
2187                               UnicodeString->Buffer,
2188                               UnicodeString->Length);
2189 
2190     /* Return the size + null-char */
2191     return (Size + sizeof(CHAR));
2192 }
2193 
2194 /*
2195  * @implemented
2196  */
2197 LONG
2198 NTAPI
2199 RtlCompareUnicodeString(
2200     IN PCUNICODE_STRING s1,
2201     IN PCUNICODE_STRING s2,
2202     IN BOOLEAN  CaseInsensitive)
2203 {
2204     unsigned int len;
2205     LONG ret = 0;
2206     LPCWSTR p1, p2;
2207 
2208     len = min(s1->Length, s2->Length) / sizeof(WCHAR);
2209     p1 = s1->Buffer;
2210     p2 = s2->Buffer;
2211 
2212     if (CaseInsensitive)
2213     {
2214         while (!ret && len--) ret = RtlpUpcaseUnicodeChar(*p1++) - RtlpUpcaseUnicodeChar(*p2++);
2215     }
2216     else
2217     {
2218         while (!ret && len--) ret = *p1++ - *p2++;
2219     }
2220 
2221     if (!ret) ret = s1->Length - s2->Length;
2222 
2223     return ret;
2224 }
2225 
2226 /*
2227  * @implemented
2228  */
2229 VOID
2230 NTAPI
2231 RtlCopyString(
2232     IN OUT PSTRING DestinationString,
2233     IN const STRING *SourceString OPTIONAL)
2234 {
2235     ULONG SourceLength;
2236     PCHAR p1, p2;
2237 
2238     /* Check if there was no source given */
2239     if (!SourceString)
2240     {
2241         /* Simply return an empty string */
2242         DestinationString->Length = 0;
2243     }
2244     else
2245     {
2246         /* Choose the smallest length */
2247         SourceLength = min(DestinationString->MaximumLength,
2248                            SourceString->Length);
2249 
2250         /* Set it */
2251         DestinationString->Length = (USHORT)SourceLength;
2252 
2253         /* Save the pointers to each buffer */
2254         p1 = DestinationString->Buffer;
2255         p2 = SourceString->Buffer;
2256 
2257         /* Loop the buffer */
2258         while (SourceLength)
2259         {
2260             /* Copy the character and move on */
2261             *p1++ = * p2++;
2262             SourceLength--;
2263         }
2264     }
2265 }
2266 
2267 /*
2268  * @implemented
2269  */
2270 VOID
2271 NTAPI
2272 RtlCopyUnicodeString(
2273     IN OUT PUNICODE_STRING DestinationString,
2274     IN PCUNICODE_STRING SourceString)
2275 {
2276     ULONG SourceLength;
2277 
2278     if (!SourceString)
2279     {
2280         DestinationString->Length = 0;
2281     }
2282     else
2283     {
2284         SourceLength = min(DestinationString->MaximumLength,
2285                            SourceString->Length);
2286         DestinationString->Length = (USHORT)SourceLength;
2287 
2288         RtlCopyMemory(DestinationString->Buffer,
2289                       SourceString->Buffer,
2290                       SourceLength);
2291 
2292         if (DestinationString->Length < DestinationString->MaximumLength)
2293         {
2294             DestinationString->Buffer[SourceLength / sizeof(WCHAR)] = UNICODE_NULL;
2295         }
2296     }
2297 }
2298 
2299 /*
2300  * @implemented
2301  *
2302  * NOTES
2303  * Creates a nullterminated UNICODE_STRING
2304  */
2305 BOOLEAN
2306 NTAPI
2307 RtlCreateUnicodeString(
2308     IN OUT PUNICODE_STRING UniDest,
2309     IN PCWSTR  Source)
2310 {
2311     SIZE_T Size;
2312     PAGED_CODE_RTL();
2313 
2314     Size = (wcslen(Source) + 1) * sizeof(WCHAR);
2315     if (Size > MAXUSHORT) return FALSE;
2316 
2317     UniDest->Buffer = RtlpAllocateStringMemory((ULONG)Size, TAG_USTR);
2318 
2319     if (UniDest->Buffer == NULL) return FALSE;
2320 
2321     RtlCopyMemory(UniDest->Buffer, Source, Size);
2322     UniDest->MaximumLength = (USHORT)Size;
2323     UniDest->Length = (USHORT)Size - sizeof (WCHAR);
2324 
2325     return TRUE;
2326 }
2327 
2328 /*
2329  * @implemented
2330  */
2331 BOOLEAN
2332 NTAPI
2333 RtlCreateUnicodeStringFromAsciiz(
2334     OUT PUNICODE_STRING Destination,
2335     IN PCSZ Source)
2336 {
2337     ANSI_STRING AnsiString;
2338     NTSTATUS Status;
2339 
2340     RtlInitAnsiString(&AnsiString, Source);
2341 
2342     Status = RtlAnsiStringToUnicodeString(Destination,
2343                                           &AnsiString,
2344                                           TRUE);
2345 
2346     return NT_SUCCESS(Status);
2347 }
2348 
2349 /*
2350  * @implemented
2351  *
2352  * NOTES
2353  *  Dest is never '\0' terminated because it may be equal to src, and src
2354  *  might not be '\0' terminated.
2355  *  Dest->Length is only set upon success.
2356  */
2357 NTSTATUS
2358 NTAPI
2359 RtlDowncaseUnicodeString(
2360     IN OUT PUNICODE_STRING UniDest,
2361     IN PCUNICODE_STRING UniSource,
2362     IN BOOLEAN AllocateDestinationString)
2363 {
2364     ULONG i;
2365     ULONG StopGap;
2366     PAGED_CODE_RTL();
2367 
2368     if (AllocateDestinationString)
2369     {
2370         UniDest->MaximumLength = UniSource->Length;
2371         UniDest->Buffer = RtlpAllocateStringMemory(UniSource->Length, TAG_USTR);
2372         if (UniDest->Buffer == NULL) return STATUS_NO_MEMORY;
2373     }
2374     else if (UniSource->Length > UniDest->MaximumLength)
2375     {
2376         return STATUS_BUFFER_OVERFLOW;
2377     }
2378 
2379     UniDest->Length = UniSource->Length;
2380     StopGap = UniSource->Length / sizeof(WCHAR);
2381 
2382     for (i = 0 ; i < StopGap; i++)
2383     {
2384         if (UniSource->Buffer[i] < L'A')
2385         {
2386             UniDest->Buffer[i] = UniSource->Buffer[i];
2387         }
2388         else if (UniSource->Buffer[i] <= L'Z')
2389         {
2390             UniDest->Buffer[i] = (UniSource->Buffer[i] + (L'a' - L'A'));
2391         }
2392         else
2393         {
2394             UniDest->Buffer[i] = RtlpDowncaseUnicodeChar(UniSource->Buffer[i]);
2395         }
2396     }
2397 
2398     return STATUS_SUCCESS;
2399 }
2400 
2401 /*
2402  * @implemented
2403  *
2404  * NOTES
2405  *  if src is NULL dest is unchanged.
2406  *  dest is '\0' terminated when the MaximumLength allowes it.
2407  *  When dest fits exactly in MaximumLength characters the '\0' is ommitted.
2408  */
2409 NTSTATUS
2410 NTAPI
2411 RtlAppendUnicodeToString(IN OUT PUNICODE_STRING Destination,
2412                          IN PCWSTR Source)
2413 {
2414     USHORT Length;
2415     PWCHAR DestBuffer;
2416 
2417     if (Source)
2418     {
2419         UNICODE_STRING UnicodeSource;
2420 
2421         RtlInitUnicodeString(&UnicodeSource, Source);
2422         Length = UnicodeSource.Length;
2423 
2424         if (Destination->Length + Length > Destination->MaximumLength)
2425         {
2426             return STATUS_BUFFER_TOO_SMALL;
2427         }
2428 
2429         DestBuffer = &Destination->Buffer[Destination->Length / sizeof(WCHAR)];
2430         RtlMoveMemory(DestBuffer, Source, Length);
2431         Destination->Length += Length;
2432 
2433         /* append terminating '\0' if enough space */
2434         if (Destination->MaximumLength > Destination->Length)
2435         {
2436             DestBuffer[Length / sizeof(WCHAR)] = UNICODE_NULL;
2437         }
2438     }
2439 
2440     return STATUS_SUCCESS;
2441 }
2442 
2443 /*
2444  * @implemented
2445  *
2446  * NOTES
2447  *  if src is NULL dest is unchanged.
2448  *  dest is never '\0' terminated.
2449  */
2450 NTSTATUS
2451 NTAPI
2452 RtlAppendAsciizToString(
2453     IN OUT   PSTRING  Destination,
2454     IN PCSZ  Source)
2455 {
2456     SIZE_T Size;
2457 
2458     if (Source)
2459     {
2460         Size = strlen(Source);
2461 
2462         if (Destination->Length + Size > Destination->MaximumLength)
2463         {
2464             return STATUS_BUFFER_TOO_SMALL;
2465         }
2466 
2467         RtlMoveMemory(&Destination->Buffer[Destination->Length], Source, Size);
2468         Destination->Length += (USHORT)Size;
2469     }
2470 
2471     return STATUS_SUCCESS;
2472 }
2473 
2474 /*
2475  * @implemented
2476  */
2477 VOID
2478 NTAPI
2479 RtlUpperString(PSTRING DestinationString,
2480                const STRING *SourceString)
2481 {
2482     USHORT Length;
2483     PCHAR Src, Dest;
2484 
2485     Length = min(SourceString->Length,
2486                  DestinationString->MaximumLength);
2487 
2488     Src = SourceString->Buffer;
2489     Dest = DestinationString->Buffer;
2490     DestinationString->Length = Length;
2491 
2492     while (Length)
2493     {
2494         *Dest++ = RtlUpperChar(*Src++);
2495         Length--;
2496     }
2497 }
2498 
2499 /*
2500  * @implemented
2501  *
2502  * NOTES
2503  *  See RtlpDuplicateUnicodeString
2504  */
2505 NTSTATUS
2506 NTAPI
2507 RtlDuplicateUnicodeString(
2508     IN ULONG Flags,
2509     IN PCUNICODE_STRING SourceString,
2510     OUT PUNICODE_STRING DestinationString)
2511 {
2512     PAGED_CODE_RTL();
2513 
2514     if (SourceString == NULL || DestinationString == NULL ||
2515         SourceString->Length > SourceString->MaximumLength ||
2516         (SourceString->Length == 0 && SourceString->MaximumLength > 0 && SourceString->Buffer == NULL) ||
2517         Flags == RTL_DUPLICATE_UNICODE_STRING_ALLOCATE_NULL_STRING || Flags >= 4)
2518     {
2519         return STATUS_INVALID_PARAMETER;
2520     }
2521 
2522 
2523     if ((SourceString->Length == 0) &&
2524         (Flags != (RTL_DUPLICATE_UNICODE_STRING_NULL_TERMINATE |
2525                    RTL_DUPLICATE_UNICODE_STRING_ALLOCATE_NULL_STRING)))
2526     {
2527         DestinationString->Length = 0;
2528         DestinationString->MaximumLength = 0;
2529         DestinationString->Buffer = NULL;
2530     }
2531     else
2532     {
2533         UINT DestMaxLength = SourceString->Length;
2534 
2535         if (Flags & RTL_DUPLICATE_UNICODE_STRING_NULL_TERMINATE)
2536             DestMaxLength += sizeof(UNICODE_NULL);
2537 
2538         DestinationString->Buffer = RtlpAllocateStringMemory(DestMaxLength, TAG_USTR);
2539 
2540         if (DestinationString->Buffer == NULL)
2541             return STATUS_NO_MEMORY;
2542 
2543         RtlCopyMemory(DestinationString->Buffer, SourceString->Buffer, SourceString->Length);
2544         DestinationString->Length = SourceString->Length;
2545         DestinationString->MaximumLength = DestMaxLength;
2546 
2547         if (Flags & RTL_DUPLICATE_UNICODE_STRING_NULL_TERMINATE)
2548             DestinationString->Buffer[DestinationString->Length / sizeof(WCHAR)] = 0;
2549     }
2550 
2551     return STATUS_SUCCESS;
2552 }
2553 
2554 /*
2555  * @implemented
2556  */
2557 NTSTATUS
2558 NTAPI
2559 RtlValidateUnicodeString(
2560     _In_ ULONG Flags,
2561     _In_ PCUNICODE_STRING String)
2562 {
2563     /* In Windows <= 2003 no flags are supported yet! */
2564     if (Flags != 0)
2565         return STATUS_INVALID_PARAMETER;
2566 
2567     /* NOTE: a NULL Unicode string pointer is considered to be a valid one! */
2568     if (String == NULL)
2569     {
2570         return STATUS_SUCCESS;
2571     }
2572     else if (!((String->Buffer == NULL) && (String->Length != 0 || String->MaximumLength != 0)) &&
2573               (String->Length % sizeof(WCHAR) == 0) &&
2574               (String->MaximumLength % sizeof(WCHAR) == 0) &&
2575               (String->Length <= String->MaximumLength))
2576     {
2577         return STATUS_SUCCESS;
2578     }
2579     else
2580     {
2581         return STATUS_INVALID_PARAMETER;
2582     }
2583 }
2584 
2585 /*
2586  * @implemented
2587  */
2588 NTSTATUS
2589 NTAPI
2590 RtlpEnsureBufferSize(
2591     IN ULONG Flags,
2592     IN OUT PRTL_BUFFER Buffer,
2593     IN SIZE_T RequiredSize)
2594 {
2595     PUCHAR NewBuffer;
2596 
2597     /* Parameter checks */
2598     if (Flags & ~RTL_SKIP_BUFFER_COPY)
2599         return STATUS_INVALID_PARAMETER;
2600     if (Buffer == NULL)
2601         return STATUS_INVALID_PARAMETER;
2602 
2603     /*
2604      * We don't need to grow the buffer if its size
2605      * is already larger than the required size.
2606      */
2607     if (Buffer->Size >= RequiredSize)
2608         return STATUS_SUCCESS;
2609 
2610     /*
2611      * When we are using the static buffer as our buffer, we don't need
2612      * to grow it if its size is already larger than the required size.
2613      * In this case, just keep it but update the current buffer size to
2614      * the one requested.
2615      * (But NEVER EVER modify the size of the static buffer!!)
2616      * Otherwise, we'll need to create a new buffer and use this one instead.
2617      */
2618     if ( (Buffer->Buffer == Buffer->StaticBuffer) &&
2619          (Buffer->StaticSize >= RequiredSize) )
2620     {
2621         Buffer->Size = RequiredSize;
2622         return STATUS_SUCCESS;
2623     }
2624 
2625     /* The buffer we are using is not large enough, try to create a bigger one */
2626     NewBuffer = RtlpAllocateStringMemory(RequiredSize, TAG_USTR);
2627     if (NewBuffer == NULL)
2628         return STATUS_NO_MEMORY;
2629 
2630     /* Copy the original content if needed */
2631     if (!(Flags & RTL_SKIP_BUFFER_COPY))
2632     {
2633         RtlMoveMemory(NewBuffer, Buffer->Buffer, Buffer->Size);
2634     }
2635 
2636     /* Free the original buffer only if it's not the static buffer */
2637     if (Buffer->Buffer != Buffer->StaticBuffer)
2638     {
2639         RtlpFreeStringMemory(Buffer->Buffer, TAG_USTR);
2640     }
2641 
2642     /* Update the members */
2643     Buffer->Buffer = NewBuffer;
2644     Buffer->Size   = RequiredSize;
2645 
2646     /* Done */
2647     return STATUS_SUCCESS;
2648 }
2649 
2650 static
2651 BOOLEAN
2652 RtlpIsCharInUnicodeString(
2653     IN WCHAR Char,
2654     IN PCUNICODE_STRING MatchString,
2655     IN BOOLEAN CaseInSensitive)
2656 {
2657     USHORT i;
2658 
2659     if (CaseInSensitive)
2660         Char = RtlpUpcaseUnicodeChar(Char);
2661 
2662     for (i = 0; i < MatchString->Length / sizeof(WCHAR); i++)
2663     {
2664         WCHAR OtherChar = MatchString->Buffer[i];
2665         if (CaseInSensitive)
2666             OtherChar = RtlpUpcaseUnicodeChar(OtherChar);
2667 
2668         if (Char == OtherChar)
2669             return TRUE;
2670     }
2671 
2672     return FALSE;
2673 }
2674 
2675 /*
2676  * @implemented
2677  */
2678 NTSTATUS
2679 NTAPI
2680 RtlFindCharInUnicodeString(
2681     IN ULONG Flags,
2682     IN PCUNICODE_STRING SearchString,
2683     IN PCUNICODE_STRING MatchString,
2684     OUT PUSHORT Position)
2685 {
2686     BOOLEAN Found;
2687     const BOOLEAN WantToFind = (Flags & RTL_FIND_CHAR_IN_UNICODE_STRING_COMPLEMENT_CHAR_SET) == 0;
2688     const BOOLEAN CaseInSensitive = (Flags & RTL_FIND_CHAR_IN_UNICODE_STRING_CASE_INSENSITIVE) != 0;
2689     USHORT i, Length;
2690 
2691     DPRINT("RtlFindCharInUnicodeString(%u, '%wZ', '%wZ', %p)\n",
2692            Flags, SearchString, MatchString, Position);
2693 
2694     /* Parameter checks */
2695     if (Position == NULL)
2696         return STATUS_INVALID_PARAMETER;
2697 
2698     *Position = 0;
2699 
2700     if (Flags & ~(RTL_FIND_CHAR_IN_UNICODE_STRING_START_AT_END |
2701                   RTL_FIND_CHAR_IN_UNICODE_STRING_COMPLEMENT_CHAR_SET |
2702                   RTL_FIND_CHAR_IN_UNICODE_STRING_CASE_INSENSITIVE))
2703         return STATUS_INVALID_PARAMETER;
2704 
2705     /* Search */
2706     Length = SearchString->Length / sizeof(WCHAR);
2707     if (Flags & RTL_FIND_CHAR_IN_UNICODE_STRING_START_AT_END)
2708     {
2709         for (i = Length - 1; (SHORT)i >= 0; i--)
2710         {
2711             Found = RtlpIsCharInUnicodeString(SearchString->Buffer[i], MatchString, CaseInSensitive);
2712             if (Found == WantToFind)
2713             {
2714                 *Position = i * sizeof(WCHAR);
2715                 return STATUS_SUCCESS;
2716             }
2717         }
2718     }
2719     else
2720     {
2721         for (i = 0; i < Length; i++)
2722         {
2723             Found = RtlpIsCharInUnicodeString(SearchString->Buffer[i], MatchString, CaseInSensitive);
2724             if (Found == WantToFind)
2725             {
2726                 *Position = (i + 1) * sizeof(WCHAR);
2727                 return STATUS_SUCCESS;
2728             }
2729         }
2730     }
2731 
2732     return STATUS_NOT_FOUND;
2733 }
2734 
2735 /*
2736  * @implemented
2737  *
2738  * NOTES
2739  *  Get the maximum of MAX_COMPUTERNAME_LENGTH characters from the dns.host name until the dot is found.
2740  *  Convert is to an uppercase oem string and check for unmapped characters.
2741  *  Then convert the oem string back to an unicode string.
2742  */
2743 NTSTATUS
2744 NTAPI
2745 RtlDnsHostNameToComputerName(PUNICODE_STRING ComputerName, PUNICODE_STRING DnsHostName, BOOLEAN AllocateComputerNameString)
2746 {
2747     NTSTATUS Status;
2748     ULONG Length;
2749     ULONG ComputerNameLength;
2750     ULONG ComputerNameOemNLength;
2751     OEM_STRING ComputerNameOem;
2752     CHAR ComputerNameOemN[MAX_COMPUTERNAME_LENGTH + 1];
2753 
2754     Status = STATUS_INVALID_COMPUTER_NAME;
2755     ComputerNameLength = DnsHostName->Length;
2756 
2757     /* find the first dot in the dns host name */
2758     for (Length = 0; Length < DnsHostName->Length / sizeof(WCHAR); Length++)
2759     {
2760         if (DnsHostName->Buffer[Length] == L'.')
2761         {
2762             /* dot found, so set the length for the oem translation */
2763             ComputerNameLength = Length * sizeof(WCHAR);
2764             break;
2765         }
2766     }
2767 
2768     /* the computername must have one character */
2769     if (ComputerNameLength > 0)
2770     {
2771         ComputerNameOemNLength = 0;
2772         /* convert to oem string and use uppercase letters */
2773         Status = RtlUpcaseUnicodeToOemN(ComputerNameOemN,
2774                                         MAX_COMPUTERNAME_LENGTH,
2775                                         &ComputerNameOemNLength,
2776                                         DnsHostName->Buffer,
2777                                         ComputerNameLength);
2778 
2779         /* status STATUS_BUFFER_OVERFLOW is not a problem since the computername shoud only
2780            have MAX_COMPUTERNAME_LENGTH characters */
2781         if ((Status == STATUS_SUCCESS) ||
2782                 (Status == STATUS_BUFFER_OVERFLOW))
2783         {
2784             /* set the termination for the oem string */
2785             ComputerNameOemN[MAX_COMPUTERNAME_LENGTH] = 0;
2786             /* set status for the case the next function failed */
2787             Status = STATUS_INVALID_COMPUTER_NAME;
2788             /* fillup the oem string structure with the converted computername
2789                and check it for unmapped characters */
2790             ComputerNameOem.Buffer = ComputerNameOemN;
2791             ComputerNameOem.Length = (USHORT)ComputerNameOemNLength;
2792             ComputerNameOem.MaximumLength = (USHORT)(MAX_COMPUTERNAME_LENGTH + 1);
2793 
2794             if (RtlpDidUnicodeToOemWork(DnsHostName, &ComputerNameOem))
2795             {
2796                 /* no unmapped character so convert it back to an unicode string */
2797                 Status = RtlOemStringToUnicodeString(ComputerName,
2798                                                      &ComputerNameOem,
2799                                                      AllocateComputerNameString);
2800             }
2801         }
2802     }
2803 
2804     return Status;
2805 }
2806 
2807