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