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