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