655c04d16c361e64aeecc1851db7e04656c21673
[reactos.git] / reactos / sdk / lib / rtl / unicode.c
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
28
29 /* FUNCTIONS *****************************************************************/
30
31 NTSTATUS
32 NTAPI
33 RtlMultiAppendUnicodeStringBuffer(IN PVOID Unknown,
34 IN ULONG Unknown2,
35 IN PVOID Unknown3)
36 {
37 UNIMPLEMENTED;
38 return STATUS_NOT_IMPLEMENTED;
39 }
40
41 /*
42 * @implemented
43 */
44 WCHAR
45 NTAPI
46 RtlAnsiCharToUnicodeChar(IN OUT PUCHAR *AnsiChar)
47 {
48 ULONG Size;
49 NTSTATUS Status;
50 WCHAR UnicodeChar = L' ';
51 PAGED_CODE_RTL();
52
53 if (NlsLeadByteInfo)
54 {
55 Size = (NlsLeadByteInfo[**AnsiChar] == 0) ? 1 : 2;
56 }
57 else
58 {
59 DPRINT("HACK::Shouldn't have happened! Consider fixing Usetup and registry entries it creates on install\n");
60 Size = 1;
61 }
62
63 Status = RtlMultiByteToUnicodeN(&UnicodeChar,
64 sizeof(WCHAR),
65 NULL,
66 (PCHAR)*AnsiChar,
67 Size);
68
69 if (!NT_SUCCESS(Status))
70 {
71 UnicodeChar = L' ';
72 }
73
74 *AnsiChar += Size;
75 return UnicodeChar;
76 }
77
78 /*
79 * @implemented
80 *
81 * NOTES
82 * This function always writes a terminating '\0'.
83 * If the dest buffer is too small a partial copy is NOT performed!
84 */
85 NTSTATUS
86 NTAPI
87 RtlAnsiStringToUnicodeString(
88 IN OUT PUNICODE_STRING UniDest,
89 IN PANSI_STRING AnsiSource,
90 IN BOOLEAN AllocateDestinationString)
91 {
92 NTSTATUS Status;
93 ULONG Length;
94 ULONG Index;
95
96 PAGED_CODE_RTL();
97
98 if (NlsMbCodePageTag == FALSE)
99 {
100 Length = AnsiSource->Length * 2 + sizeof(WCHAR);
101 }
102 else
103 {
104 Length = RtlxAnsiStringToUnicodeSize(AnsiSource);
105 }
106 if (Length > MAXUSHORT) return STATUS_INVALID_PARAMETER_2;
107 UniDest->Length = (USHORT)Length - sizeof(WCHAR);
108
109 if (AllocateDestinationString)
110 {
111 UniDest->Buffer = RtlpAllocateStringMemory(Length, TAG_USTR);
112 UniDest->MaximumLength = (USHORT)Length;
113 if (!UniDest->Buffer) return STATUS_NO_MEMORY;
114 }
115 else if (UniDest->Length >= UniDest->MaximumLength)
116 {
117 return STATUS_BUFFER_OVERFLOW;
118 }
119
120 /* UniDest->MaximumLength must be even due to sizeof(WCHAR) being 2 */
121 ASSERT(!(UniDest->MaximumLength & 1) && UniDest->Length <= UniDest->MaximumLength);
122
123 Status = RtlMultiByteToUnicodeN(UniDest->Buffer,
124 UniDest->Length,
125 &Index,
126 AnsiSource->Buffer,
127 AnsiSource->Length);
128
129 if (!NT_SUCCESS(Status))
130 {
131 if (AllocateDestinationString)
132 {
133 RtlpFreeStringMemory(UniDest->Buffer, TAG_USTR);
134 UniDest->Buffer = NULL;
135 }
136
137 return Status;
138 }
139
140 UniDest->Buffer[Index / sizeof(WCHAR)] = UNICODE_NULL;
141 return Status;
142 }
143
144 /*
145 * @implemented
146 *
147 * RETURNS
148 * The calculated size in bytes including nullterm.
149 */
150 ULONG
151 NTAPI
152 RtlxAnsiStringToUnicodeSize(IN PCANSI_STRING AnsiString)
153 {
154 ULONG Size;
155 PAGED_CODE_RTL();
156
157 /* Convert from Mb String to Unicode Size */
158 RtlMultiByteToUnicodeSize(&Size,
159 AnsiString->Buffer,
160 AnsiString->Length);
161
162 /* Return the size plus the null-char */
163 return(Size + sizeof(WCHAR));
164 }
165
166 /*
167 * @implemented
168 *
169 * NOTES
170 * If src->length is zero dest is unchanged.
171 * Dest is never nullterminated.
172 */
173 NTSTATUS
174 NTAPI
175 RtlAppendStringToString(IN PSTRING Destination,
176 IN const STRING *Source)
177 {
178 USHORT SourceLength = Source->Length;
179
180 if (SourceLength)
181 {
182 if (Destination->Length + SourceLength > Destination->MaximumLength)
183 {
184 return STATUS_BUFFER_TOO_SMALL;
185 }
186
187 RtlMoveMemory(&Destination->Buffer[Destination->Length],
188 Source->Buffer,
189 SourceLength);
190
191 Destination->Length += SourceLength;
192 }
193
194 return STATUS_SUCCESS;
195 }
196
197 /*
198 * @implemented
199 *
200 * NOTES
201 * If src->length is zero dest is unchanged.
202 * Dest is nullterminated when the MaximumLength allowes it.
203 * When dest fits exactly in MaximumLength characters the nullterm is ommitted.
204 */
205 NTSTATUS
206 NTAPI
207 RtlAppendUnicodeStringToString(
208 IN OUT PUNICODE_STRING Destination,
209 IN PCUNICODE_STRING Source)
210 {
211 USHORT SourceLength = Source->Length;
212 PWCHAR Buffer = &Destination->Buffer[Destination->Length / sizeof(WCHAR)];
213
214 if (SourceLength)
215 {
216 if ((SourceLength + Destination->Length) > Destination->MaximumLength)
217 {
218 return STATUS_BUFFER_TOO_SMALL;
219 }
220
221 RtlMoveMemory(Buffer, Source->Buffer, SourceLength);
222 Destination->Length += SourceLength;
223
224 /* append terminating '\0' if enough space */
225 if (Destination->MaximumLength > Destination->Length)
226 {
227 Buffer[SourceLength / sizeof(WCHAR)] = UNICODE_NULL;
228 }
229 }
230
231 return STATUS_SUCCESS;
232 }
233
234 /**************************************************************************
235 * RtlCharToInteger (NTDLL.@)
236 * @implemented
237 * Converts a character string into its integer equivalent.
238 *
239 * RETURNS
240 * Success: STATUS_SUCCESS. value contains the converted number
241 * Failure: STATUS_INVALID_PARAMETER, if base is not 0, 2, 8, 10 or 16.
242 * STATUS_ACCESS_VIOLATION, if value is NULL.
243 *
244 * NOTES
245 * For base 0 it uses 10 as base and the string should be in the format
246 * "{whitespace} [+|-] [0[x|o|b]] {digits}".
247 * For other bases the string should be in the format
248 * "{whitespace} [+|-] {digits}".
249 * No check is made for value overflow, only the lower 32 bits are assigned.
250 * If str is NULL it crashes, as the native function does.
251 *
252 * DIFFERENCES
253 * This function does not read garbage behind '\0' as the native version does.
254 */
255 NTSTATUS
256 NTAPI
257 RtlCharToInteger(
258 PCSZ str, /* [I] '\0' terminated single-byte string containing a number */
259 ULONG base, /* [I] Number base for conversion (allowed 0, 2, 8, 10 or 16) */
260 PULONG value) /* [O] Destination for the converted value */
261 {
262 CHAR chCurrent;
263 int digit;
264 ULONG RunningTotal = 0;
265 char bMinus = 0;
266
267 /* skip leading whitespaces */
268 while (*str != '\0' && *str <= ' ') str++;
269
270 /* Check for +/- */
271 if (*str == '+')
272 {
273 str++;
274 }
275 else if (*str == '-')
276 {
277 bMinus = 1;
278 str++;
279 }
280
281 /* base = 0 means autobase */
282 if (base == 0)
283 {
284 base = 10;
285
286 if (str[0] == '0')
287 {
288 if (str[1] == 'b')
289 {
290 str += 2;
291 base = 2;
292 }
293 else if (str[1] == 'o')
294 {
295 str += 2;
296 base = 8;
297 }
298 else if (str[1] == 'x')
299 {
300 str += 2;
301 base = 16;
302 }
303 }
304 }
305 else if (base != 2 && base != 8 && base != 10 && base != 16)
306 {
307 return STATUS_INVALID_PARAMETER;
308 }
309
310 if (value == NULL) return STATUS_ACCESS_VIOLATION;
311
312 while (*str != '\0')
313 {
314 chCurrent = *str;
315
316 if (chCurrent >= '0' && chCurrent <= '9')
317 {
318 digit = chCurrent - '0';
319 }
320 else if (chCurrent >= 'A' && chCurrent <= 'Z')
321 {
322 digit = chCurrent - 'A' + 10;
323 }
324 else if (chCurrent >= 'a' && chCurrent <= 'z')
325 {
326 digit = chCurrent - 'a' + 10;
327 }
328 else
329 {
330 digit = -1;
331 }
332
333 if (digit < 0 || digit >= (int)base) break;
334
335 RunningTotal = RunningTotal * base + digit;
336 str++;
337 }
338
339 *value = bMinus ? (0 - RunningTotal) : RunningTotal;
340 return STATUS_SUCCESS;
341 }
342
343 /*
344 * @implemented
345 */
346 LONG
347 NTAPI
348 RtlCompareString(
349 IN const STRING *s1,
350 IN const STRING *s2,
351 IN BOOLEAN CaseInsensitive)
352 {
353 unsigned int len;
354 LONG ret = 0;
355 LPCSTR p1, p2;
356
357 len = min(s1->Length, s2->Length);
358 p1 = s1->Buffer;
359 p2 = s2->Buffer;
360
361 if (CaseInsensitive)
362 {
363 while (!ret && len--)
364 ret = RtlUpperChar(*p1++) - RtlUpperChar(*p2++);
365 }
366 else
367 {
368 while (!ret && len--) ret = *p1++ - *p2++;
369 }
370
371 if (!ret) ret = s1->Length - s2->Length;
372
373 return ret;
374 }
375
376 /*
377 * @implemented
378 *
379 * RETURNS
380 * TRUE if strings are equal.
381 */
382 BOOLEAN
383 NTAPI
384 RtlEqualString(
385 IN const STRING *s1,
386 IN const STRING *s2,
387 IN BOOLEAN CaseInsensitive)
388 {
389 if (s1->Length != s2->Length) return FALSE;
390 return !RtlCompareString(s1, s2, CaseInsensitive);
391 }
392
393 /*
394 * @implemented
395 *
396 * RETURNS
397 * TRUE if strings are equal.
398 */
399 BOOLEAN
400 NTAPI
401 RtlEqualUnicodeString(
402 IN CONST UNICODE_STRING *s1,
403 IN CONST UNICODE_STRING *s2,
404 IN BOOLEAN CaseInsensitive)
405 {
406 if (s1->Length != s2->Length) return FALSE;
407 return !RtlCompareUnicodeString(s1, s2, CaseInsensitive );
408 }
409
410 /*
411 * @implemented
412 */
413 VOID
414 NTAPI
415 RtlFreeAnsiString(IN PANSI_STRING AnsiString)
416 {
417 PAGED_CODE_RTL();
418
419 if (AnsiString->Buffer)
420 {
421 RtlpFreeStringMemory(AnsiString->Buffer, TAG_ASTR);
422 RtlZeroMemory(AnsiString, sizeof(ANSI_STRING));
423 }
424 }
425
426 /*
427 * @implemented
428 */
429 VOID
430 NTAPI
431 RtlFreeOemString(IN POEM_STRING OemString)
432 {
433 PAGED_CODE_RTL();
434
435 if (OemString->Buffer) RtlpFreeStringMemory(OemString->Buffer, TAG_OSTR);
436 }
437
438 /*
439 * @implemented
440 */
441 VOID
442 NTAPI
443 RtlFreeUnicodeString(IN PUNICODE_STRING UnicodeString)
444 {
445 PAGED_CODE_RTL();
446
447 if (UnicodeString->Buffer)
448 {
449 RtlpFreeStringMemory(UnicodeString->Buffer, TAG_USTR);
450 RtlZeroMemory(UnicodeString, sizeof(UNICODE_STRING));
451 }
452 }
453
454
455 /*
456 * @implemented
457 *
458 * NOTES
459 * Check the OEM string to match the Unicode string.
460 *
461 * Functions which convert Unicode strings to OEM strings will set a
462 * DefaultChar from the OEM codepage when the characters are unknown.
463 * So check it against the Unicode string and return false when the
464 * Unicode string does not contain a TransDefaultChar.
465 */
466 BOOLEAN
467 NTAPI
468 RtlpDidUnicodeToOemWork(IN PCUNICODE_STRING UnicodeString,
469 IN POEM_STRING OemString)
470 {
471 ULONG i = 0;
472
473 if (NlsMbOemCodePageTag == FALSE)
474 {
475 /* single-byte code page */
476 /* Go through all characters of a string */
477 while (i < OemString->Length)
478 {
479 /* Check if it got translated into a default char,
480 * but source char wasn't a default char equivalent
481 */
482 if ((OemString->Buffer[i] == NlsOemDefaultChar) &&
483 (UnicodeString->Buffer[i] != NlsUnicodeDefaultChar))
484 {
485 /* Yes, it means unmappable characters were found */
486 return FALSE;
487 }
488
489 /* Move to the next char */
490 i++;
491 }
492
493 /* All chars were translated successfuly */
494 return TRUE;
495 }
496 else
497 {
498 /* multibyte code page */
499
500 /* FIXME */
501 return TRUE;
502 }
503 }
504
505 /*
506 * @unimplemented
507 */
508 BOOLEAN
509 NTAPI
510 RtlIsValidOemCharacter(IN PWCHAR Char)
511 {
512 UNIMPLEMENTED;
513 return FALSE;
514 }
515
516 /*
517 * @implemented
518 *
519 * NOTES
520 * If source is NULL the length of source is assumed to be 0.
521 */
522 VOID
523 NTAPI
524 RtlInitAnsiString(IN OUT PANSI_STRING DestinationString,
525 IN PCSZ SourceString)
526 {
527 SIZE_T Size;
528
529 if (SourceString)
530 {
531 Size = strlen(SourceString);
532 if (Size > (MAXUSHORT - sizeof(CHAR))) Size = MAXUSHORT - sizeof(CHAR);
533 DestinationString->Length = (USHORT)Size;
534 DestinationString->MaximumLength = (USHORT)Size + sizeof(CHAR);
535 }
536 else
537 {
538 DestinationString->Length = 0;
539 DestinationString->MaximumLength = 0;
540 }
541
542 DestinationString->Buffer = (PCHAR)SourceString;
543 }
544
545 NTSTATUS
546 NTAPI
547 RtlInitAnsiStringEx(IN OUT PANSI_STRING DestinationString,
548 IN PCSZ SourceString)
549 {
550 SIZE_T Size;
551
552 if (SourceString)
553 {
554 Size = strlen(SourceString);
555 if (Size > (MAXUSHORT - sizeof(CHAR))) return STATUS_NAME_TOO_LONG;
556 DestinationString->Length = (USHORT)Size;
557 DestinationString->MaximumLength = (USHORT)Size + sizeof(CHAR);
558 }
559 else
560 {
561 DestinationString->Length = 0;
562 DestinationString->MaximumLength = 0;
563 }
564
565 DestinationString->Buffer = (PCHAR)SourceString;
566 return STATUS_SUCCESS;
567
568 }
569 /*
570 * @implemented
571 *
572 * NOTES
573 * If source is NULL the length of source is assumed to be 0.
574 */
575 VOID
576 NTAPI
577 RtlInitString(
578 IN OUT PSTRING DestinationString,
579 IN PCSZ SourceString)
580 {
581 RtlInitAnsiString(DestinationString, SourceString);
582 }
583
584 /*
585 * @implemented
586 *
587 * NOTES
588 * If source is NULL the length of source is assumed to be 0.
589 */
590 VOID
591 NTAPI
592 RtlInitUnicodeString(
593 IN OUT PUNICODE_STRING DestinationString,
594 IN PCWSTR SourceString)
595 {
596 SIZE_T Size;
597 CONST SIZE_T MaxSize = (MAXUSHORT & ~1) - sizeof(UNICODE_NULL); // an even number
598
599 if (SourceString)
600 {
601 Size = wcslen(SourceString) * sizeof(WCHAR);
602 __analysis_assume(Size <= MaxSize);
603
604 if (Size > MaxSize)
605 Size = MaxSize;
606 DestinationString->Length = (USHORT)Size;
607 DestinationString->MaximumLength = (USHORT)Size + sizeof(UNICODE_NULL);
608 }
609 else
610 {
611 DestinationString->Length = 0;
612 DestinationString->MaximumLength = 0;
613 }
614
615 DestinationString->Buffer = (PWCHAR)SourceString;
616 }
617
618 /*
619 * @implemented
620 */
621 NTSTATUS
622 NTAPI
623 RtlInitUnicodeStringEx(
624 OUT PUNICODE_STRING DestinationString,
625 IN PCWSTR SourceString)
626 {
627 SIZE_T Size;
628 CONST SIZE_T MaxSize = (MAXUSHORT & ~1) - sizeof(WCHAR); // an even number
629
630 if (SourceString)
631 {
632 Size = wcslen(SourceString) * sizeof(WCHAR);
633 if (Size > MaxSize) return STATUS_NAME_TOO_LONG;
634 DestinationString->Length = (USHORT)Size;
635 DestinationString->MaximumLength = (USHORT)Size + sizeof(WCHAR);
636 }
637 else
638 {
639 DestinationString->Length = 0;
640 DestinationString->MaximumLength = 0;
641 }
642
643 DestinationString->Buffer = (PWCHAR)SourceString;
644 return STATUS_SUCCESS;
645 }
646
647 /*
648 * @implemented
649 *
650 * NOTES
651 * Writes at most length characters to the string str.
652 * Str is nullterminated when length allowes it.
653 * When str fits exactly in length characters the nullterm is ommitted.
654 */
655 NTSTATUS NTAPI RtlIntegerToChar(
656 ULONG value, /* [I] Value to be converted */
657 ULONG base, /* [I] Number base for conversion (allowed 0, 2, 8, 10 or 16) */
658 ULONG length, /* [I] Length of the str buffer in bytes */
659 PCHAR str) /* [O] Destination for the converted value */
660 {
661 CHAR buffer[33];
662 PCHAR pos;
663 CHAR digit;
664 SIZE_T len;
665
666 if (base == 0)
667 {
668 base = 10;
669 }
670 else if (base != 2 && base != 8 && base != 10 && base != 16)
671 {
672 return STATUS_INVALID_PARAMETER;
673 }
674
675 pos = &buffer[32];
676 *pos = '\0';
677
678 do
679 {
680 pos--;
681 digit = (CHAR)(value % base);
682 value = value / base;
683
684 if (digit < 10)
685 {
686 *pos = '0' + digit;
687 }
688 else
689 {
690 *pos = 'A' + digit - 10;
691 }
692 }
693 while (value != 0L);
694
695 len = &buffer[32] - pos;
696
697 if (len > length)
698 {
699 return STATUS_BUFFER_OVERFLOW;
700 }
701 else if (str == NULL)
702 {
703 return STATUS_ACCESS_VIOLATION;
704 }
705 else if (len == length)
706 {
707 memcpy(str, pos, len);
708 }
709 else
710 {
711 memcpy(str, pos, len + 1);
712 }
713
714 return STATUS_SUCCESS;
715 }
716
717 /*
718 * @implemented
719 */
720 NTSTATUS
721 NTAPI
722 RtlIntegerToUnicode(
723 IN ULONG Value,
724 IN ULONG Base OPTIONAL,
725 IN ULONG Length OPTIONAL,
726 IN OUT LPWSTR String)
727 {
728 ULONG Radix;
729 WCHAR temp[33];
730 ULONG v = Value;
731 ULONG i;
732 PWCHAR tp;
733 PWCHAR sp;
734
735 Radix = Base;
736
737 if (Radix == 0) Radix = 10;
738
739 if ((Radix != 2) && (Radix != 8) &&
740 (Radix != 10) && (Radix != 16))
741 {
742 return STATUS_INVALID_PARAMETER;
743 }
744
745 tp = temp;
746
747 while (v || tp == temp)
748 {
749 i = v % Radix;
750 v = v / Radix;
751
752 if (i < 10) *tp = (WCHAR)(i + L'0');
753 else *tp = (WCHAR)(i + L'a' - 10);
754
755 tp++;
756 }
757
758 if ((ULONG)((ULONG_PTR)tp - (ULONG_PTR)temp) >= Length)
759 {
760 return STATUS_BUFFER_TOO_SMALL;
761 }
762
763 sp = String;
764
765 while (tp > temp) *sp++ = *--tp;
766
767 *sp = 0;
768
769 return STATUS_SUCCESS;
770 }
771
772 /*
773 * @implemented
774 */
775 NTSTATUS
776 NTAPI
777 RtlIntegerToUnicodeString(
778 IN ULONG Value,
779 IN ULONG Base OPTIONAL,
780 IN OUT PUNICODE_STRING String)
781 {
782 ANSI_STRING AnsiString;
783 CHAR Buffer[33];
784 NTSTATUS Status;
785
786 Status = RtlIntegerToChar(Value, Base, sizeof(Buffer), Buffer);
787 if (NT_SUCCESS(Status))
788 {
789 AnsiString.Buffer = Buffer;
790 AnsiString.Length = (USHORT)strlen(Buffer);
791 AnsiString.MaximumLength = sizeof(Buffer);
792
793 Status = RtlAnsiStringToUnicodeString(String, &AnsiString, FALSE);
794 }
795
796 return Status;
797 }
798
799 /*
800 * @implemented
801 */
802 NTSTATUS
803 NTAPI
804 RtlInt64ToUnicodeString (
805 IN ULONGLONG Value,
806 IN ULONG Base OPTIONAL,
807 IN OUT PUNICODE_STRING String)
808 {
809 LARGE_INTEGER LargeInt;
810 ANSI_STRING AnsiString;
811 CHAR Buffer[65];
812 NTSTATUS Status;
813
814 LargeInt.QuadPart = Value;
815
816 Status = RtlLargeIntegerToChar(&LargeInt, Base, sizeof(Buffer), Buffer);
817 if (NT_SUCCESS(Status))
818 {
819 AnsiString.Buffer = Buffer;
820 AnsiString.Length = (USHORT)strlen(Buffer);
821 AnsiString.MaximumLength = sizeof(Buffer);
822
823 Status = RtlAnsiStringToUnicodeString(String, &AnsiString, FALSE);
824 }
825
826 return Status;
827 }
828
829 /*
830 * @implemented
831 *
832 * RETURNS
833 * TRUE if String2 contains String1 as a prefix.
834 */
835 BOOLEAN
836 NTAPI
837 RtlPrefixString(
838 const STRING *String1,
839 const STRING *String2,
840 BOOLEAN CaseInsensitive)
841 {
842 PCHAR pc1;
843 PCHAR pc2;
844 ULONG NumChars;
845
846 if (String2->Length < String1->Length)
847 return FALSE;
848
849 NumChars = String1->Length;
850 pc1 = String1->Buffer;
851 pc2 = String2->Buffer;
852
853 if (pc1 && pc2)
854 {
855 if (CaseInsensitive)
856 {
857 while (NumChars--)
858 {
859 if (RtlUpperChar(*pc1++) != RtlUpperChar(*pc2++))
860 return FALSE;
861 }
862 }
863 else
864 {
865 while (NumChars--)
866 {
867 if (*pc1++ != *pc2++)
868 return FALSE;
869 }
870 }
871
872 return TRUE;
873 }
874
875 return FALSE;
876 }
877
878 /*
879 * @implemented
880 *
881 * RETURNS
882 * TRUE if String2 contains String1 as a prefix.
883 */
884 BOOLEAN
885 NTAPI
886 RtlPrefixUnicodeString(
887 PCUNICODE_STRING String1,
888 PCUNICODE_STRING String2,
889 BOOLEAN CaseInsensitive)
890 {
891 PWCHAR pc1;
892 PWCHAR pc2;
893 ULONG NumChars;
894
895 if (String2->Length < String1->Length)
896 return FALSE;
897
898 NumChars = String1->Length / sizeof(WCHAR);
899 pc1 = String1->Buffer;
900 pc2 = String2->Buffer;
901
902 if (pc1 && pc2)
903 {
904 if (CaseInsensitive)
905 {
906 while (NumChars--)
907 {
908 if (RtlUpcaseUnicodeChar(*pc1++) !=
909 RtlUpcaseUnicodeChar(*pc2++))
910 return FALSE;
911 }
912 }
913 else
914 {
915 while (NumChars--)
916 {
917 if (*pc1++ != *pc2++)
918 return FALSE;
919 }
920 }
921
922 return TRUE;
923 }
924
925 return FALSE;
926 }
927
928 /*
929 * @implemented
930 */
931 NTSTATUS
932 NTAPI
933 RtlUnicodeStringToInteger(
934 const UNICODE_STRING *str, /* [I] Unicode string to be converted */
935 ULONG base, /* [I] Number base for conversion (allowed 0, 2, 8, 10 or 16) */
936 ULONG *value) /* [O] Destination for the converted value */
937 {
938 LPWSTR lpwstr = str->Buffer;
939 USHORT CharsRemaining = str->Length / sizeof(WCHAR);
940 WCHAR wchCurrent;
941 int digit;
942 ULONG RunningTotal = 0;
943 char bMinus = 0;
944
945 while (CharsRemaining >= 1 && *lpwstr <= ' ')
946 {
947 lpwstr++;
948 CharsRemaining--;
949 }
950
951 if (CharsRemaining >= 1)
952 {
953 if (*lpwstr == '+')
954 {
955 lpwstr++;
956 CharsRemaining--;
957 }
958 else if (*lpwstr == '-')
959 {
960 bMinus = 1;
961 lpwstr++;
962 CharsRemaining--;
963 }
964 }
965
966 if (base == 0)
967 {
968 base = 10;
969
970 if (CharsRemaining >= 2 && lpwstr[0] == '0')
971 {
972 if (lpwstr[1] == 'b')
973 {
974 lpwstr += 2;
975 CharsRemaining -= 2;
976 base = 2;
977 }
978 else if (lpwstr[1] == 'o')
979 {
980 lpwstr += 2;
981 CharsRemaining -= 2;
982 base = 8;
983 }
984 else if (lpwstr[1] == 'x')
985 {
986 lpwstr += 2;
987 CharsRemaining -= 2;
988 base = 16;
989 }
990 }
991 }
992 else if (base != 2 && base != 8 && base != 10 && base != 16)
993 {
994 return STATUS_INVALID_PARAMETER;
995 }
996
997 if (value == NULL)
998 {
999 return STATUS_ACCESS_VIOLATION;
1000 }
1001
1002 while (CharsRemaining >= 1)
1003 {
1004 wchCurrent = *lpwstr;
1005
1006 if (wchCurrent >= '0' && wchCurrent <= '9')
1007 {
1008 digit = wchCurrent - '0';
1009 }
1010 else if (wchCurrent >= 'A' && wchCurrent <= 'Z')
1011 {
1012 digit = wchCurrent - 'A' + 10;
1013 }
1014 else if (wchCurrent >= 'a' && wchCurrent <= 'z')
1015 {
1016 digit = wchCurrent - 'a' + 10;
1017 }
1018 else
1019 {
1020 digit = -1;
1021 }
1022
1023 if (digit < 0 || (ULONG)digit >= base) break;
1024
1025 RunningTotal = RunningTotal * base + digit;
1026 lpwstr++;
1027 CharsRemaining--;
1028 }
1029
1030 *value = bMinus ? (0 - RunningTotal) : RunningTotal;
1031 return STATUS_SUCCESS;
1032 }
1033
1034 /*
1035 * @implemented
1036 *
1037 * RETURNS
1038 * Bytes necessary for the conversion including nullterm.
1039 */
1040 ULONG
1041 NTAPI
1042 RtlxUnicodeStringToOemSize(IN PCUNICODE_STRING UnicodeString)
1043 {
1044 ULONG Size;
1045
1046 /* Convert the Unicode String to Mb Size */
1047 RtlUnicodeToMultiByteSize(&Size,
1048 UnicodeString->Buffer,
1049 UnicodeString->Length);
1050
1051 /* Return the size + the null char */
1052 return (Size + sizeof(CHAR));
1053 }
1054
1055 /*
1056 * @implemented
1057 *
1058 * NOTES
1059 * This function always writes a terminating '\0'.
1060 * It performs a partial copy if ansi is too small.
1061 */
1062 NTSTATUS
1063 NTAPI
1064 RtlUnicodeStringToAnsiString(
1065 IN OUT PANSI_STRING AnsiDest,
1066 IN PCUNICODE_STRING UniSource,
1067 IN BOOLEAN AllocateDestinationString)
1068 {
1069 NTSTATUS Status = STATUS_SUCCESS;
1070 NTSTATUS RealStatus;
1071 ULONG Length;
1072 ULONG Index;
1073
1074 PAGED_CODE_RTL();
1075
1076 ASSERT(!(UniSource->Length & 1));
1077
1078 if (NlsMbCodePageTag == FALSE)
1079 {
1080 Length = (UniSource->Length + sizeof(WCHAR)) / sizeof(WCHAR);
1081 }
1082 else
1083 {
1084 Length = RtlxUnicodeStringToAnsiSize(UniSource);
1085 }
1086
1087 if (Length > MAXUSHORT) return STATUS_INVALID_PARAMETER_2;
1088
1089 AnsiDest->Length = (USHORT)Length - sizeof(CHAR);
1090
1091 if (AllocateDestinationString)
1092 {
1093 AnsiDest->Buffer = RtlpAllocateStringMemory(Length, TAG_ASTR);
1094 AnsiDest->MaximumLength = (USHORT)Length;
1095
1096 if (!AnsiDest->Buffer) return STATUS_NO_MEMORY;
1097 }
1098 else if (AnsiDest->Length >= AnsiDest->MaximumLength)
1099 {
1100 if (!AnsiDest->MaximumLength) return STATUS_BUFFER_OVERFLOW;
1101
1102 Status = STATUS_BUFFER_OVERFLOW;
1103 AnsiDest->Length = AnsiDest->MaximumLength - 1;
1104 }
1105
1106 RealStatus = RtlUnicodeToMultiByteN(AnsiDest->Buffer,
1107 AnsiDest->Length,
1108 &Index,
1109 UniSource->Buffer,
1110 UniSource->Length);
1111
1112 if (!NT_SUCCESS(RealStatus) && AllocateDestinationString)
1113 {
1114 RtlpFreeStringMemory(AnsiDest->Buffer, TAG_ASTR);
1115 return RealStatus;
1116 }
1117
1118 AnsiDest->Buffer[Index] = ANSI_NULL;
1119 return Status;
1120 }
1121
1122 /*
1123 * @implemented
1124 *
1125 * NOTES
1126 * This function always writes a terminating '\0'.
1127 * Does NOT perform a partial copy if unicode is too small!
1128 */
1129 NTSTATUS
1130 NTAPI
1131 RtlOemStringToUnicodeString(
1132 IN OUT PUNICODE_STRING UniDest,
1133 IN PCOEM_STRING OemSource,
1134 IN BOOLEAN AllocateDestinationString)
1135 {
1136 NTSTATUS Status;
1137 ULONG Length;
1138 ULONG Index;
1139
1140 PAGED_CODE_RTL();
1141
1142 Length = RtlOemStringToUnicodeSize(OemSource);
1143
1144 if (Length > MAXUSHORT) return STATUS_INVALID_PARAMETER_2;
1145
1146 UniDest->Length = (USHORT)Length - sizeof(WCHAR);
1147
1148 if (AllocateDestinationString)
1149 {
1150 UniDest->Buffer = RtlpAllocateStringMemory(Length, TAG_USTR);
1151 UniDest->MaximumLength = (USHORT)Length;
1152
1153 if (!UniDest->Buffer) return STATUS_NO_MEMORY;
1154 }
1155 else if (UniDest->Length >= UniDest->MaximumLength)
1156 {
1157 return STATUS_BUFFER_OVERFLOW;
1158 }
1159
1160 Status = RtlOemToUnicodeN(UniDest->Buffer,
1161 UniDest->Length,
1162 &Index,
1163 OemSource->Buffer,
1164 OemSource->Length);
1165
1166 if (!NT_SUCCESS(Status) && AllocateDestinationString)
1167 {
1168 RtlpFreeStringMemory(UniDest->Buffer, TAG_USTR);
1169 UniDest->Buffer = NULL;
1170 return Status;
1171 }
1172
1173 UniDest->Buffer[Index / sizeof(WCHAR)] = UNICODE_NULL;
1174 return Status;
1175 }
1176
1177 /*
1178 * @implemented
1179 *
1180 * NOTES
1181 * This function always '\0' terminates the string returned.
1182 */
1183 NTSTATUS
1184 NTAPI
1185 RtlUnicodeStringToOemString(
1186 IN OUT POEM_STRING OemDest,
1187 IN PCUNICODE_STRING UniSource,
1188 IN BOOLEAN AllocateDestinationString)
1189 {
1190 NTSTATUS Status;
1191 ULONG Length;
1192 ULONG Index;
1193
1194 PAGED_CODE_RTL();
1195
1196 Length = RtlUnicodeStringToOemSize(UniSource);
1197
1198 if (Length > MAXUSHORT) return STATUS_INVALID_PARAMETER_2;
1199
1200 OemDest->Length = (USHORT)Length - sizeof(CHAR);
1201
1202 if (AllocateDestinationString)
1203 {
1204 OemDest->Buffer = RtlpAllocateStringMemory(Length, TAG_OSTR);
1205 OemDest->MaximumLength = (USHORT)Length;
1206
1207 if (!OemDest->Buffer) return STATUS_NO_MEMORY;
1208 }
1209 else if (OemDest->Length >= OemDest->MaximumLength)
1210 {
1211 return STATUS_BUFFER_OVERFLOW;
1212 }
1213
1214 Status = RtlUnicodeToOemN(OemDest->Buffer,
1215 OemDest->Length,
1216 &Index,
1217 UniSource->Buffer,
1218 UniSource->Length);
1219
1220 if (!NT_SUCCESS(Status) && AllocateDestinationString)
1221 {
1222 RtlpFreeStringMemory(OemDest->Buffer, TAG_OSTR);
1223 OemDest->Buffer = NULL;
1224 return Status;
1225 }
1226
1227 OemDest->Buffer[Index] = ANSI_NULL;
1228 return Status;
1229 }
1230
1231 #define ITU_IMPLEMENTED_TESTS (IS_TEXT_UNICODE_ODD_LENGTH|IS_TEXT_UNICODE_SIGNATURE)
1232
1233 /*
1234 * @implemented
1235 *
1236 * RETURNS
1237 * The length of the string if all tests were passed, 0 otherwise.
1238 */
1239 BOOLEAN
1240 NTAPI
1241 RtlIsTextUnicode(CONST VOID* buf, INT len, INT* pf)
1242 {
1243 static const WCHAR std_control_chars[] = {'\r', '\n', '\t', ' ', 0x3000, 0};
1244 static const WCHAR byterev_control_chars[] = {0x0d00, 0x0a00, 0x0900, 0x2000, 0};
1245 const WCHAR *s = buf;
1246 int i;
1247 unsigned int flags = MAXULONG, out_flags = 0;
1248 UCHAR last_lo_byte = 0;
1249 UCHAR last_hi_byte = 0;
1250 ULONG hi_byte_diff = 0;
1251 ULONG lo_byte_diff = 0;
1252 ULONG weight = 3;
1253 ULONG lead_byte = 0;
1254
1255 if (len < sizeof(WCHAR))
1256 {
1257 /* FIXME: MSDN documents IS_TEXT_UNICODE_BUFFER_TOO_SMALL but there is no such thing... */
1258 if (pf) *pf = 0;
1259
1260 return FALSE;
1261 }
1262
1263 if (pf)
1264 flags = *pf;
1265
1266 /*
1267 * Apply various tests to the text string. According to the
1268 * docs, each test "passed" sets the corresponding flag in
1269 * the output flags. But some of the tests are mutually
1270 * exclusive, so I don't see how you could pass all tests ...
1271 */
1272
1273 /* Check for an odd length ... pass if even. */
1274 if (len & 1) out_flags |= IS_TEXT_UNICODE_ODD_LENGTH;
1275
1276 if (((char *)buf)[len - 1] == 0)
1277 len--; /* Windows seems to do something like that to avoid e.g. false IS_TEXT_UNICODE_NULL_BYTES */
1278
1279 len /= sizeof(WCHAR);
1280
1281 /* Windows only checks the first 256 characters */
1282 if (len > 256) len = 256;
1283
1284 /* Check for the special byte order unicode marks. */
1285 if (*s == 0xFEFF) out_flags |= IS_TEXT_UNICODE_SIGNATURE;
1286 if (*s == 0xFFFE) out_flags |= IS_TEXT_UNICODE_REVERSE_SIGNATURE;
1287
1288 for (i = 0; i < len; i++)
1289 {
1290 UCHAR lo_byte = LOBYTE(s[i]);
1291 UCHAR hi_byte = HIBYTE(s[i]);
1292
1293 lo_byte_diff += max(lo_byte, last_lo_byte) - min(lo_byte, last_lo_byte);
1294 hi_byte_diff += max(hi_byte, last_hi_byte) - min(hi_byte, last_hi_byte);
1295
1296 last_lo_byte = lo_byte;
1297 last_hi_byte = hi_byte;
1298
1299 switch (s[i])
1300 {
1301 case 0xFFFE: /* Reverse BOM */
1302 case UNICODE_NULL:
1303 case 0x0A0D: /* ASCII CRLF (packed into one word) */
1304 case 0xFFFF: /* Unicode 0xFFFF */
1305 out_flags |= IS_TEXT_UNICODE_ILLEGAL_CHARS;
1306 break;
1307 }
1308 }
1309
1310 if (lo_byte_diff < 127 && !hi_byte_diff)
1311 {
1312 out_flags |= IS_TEXT_UNICODE_ASCII16;
1313 }
1314
1315 if (NlsMbCodePageTag)
1316 {
1317 for (i = 0; i < len; i++)
1318 {
1319 if (NlsLeadByteInfo[s[i]])
1320 {
1321 ++lead_byte;
1322 ++i;
1323 }
1324 }
1325
1326 if (lead_byte)
1327 {
1328 weight = (len / 2) - 1;
1329
1330 if (lead_byte < (weight / 3))
1331 weight = 3;
1332 else if (lead_byte < ((weight * 2) / 3))
1333 weight = 2;
1334 else
1335 weight = 1;
1336 }
1337 }
1338
1339 /* apply some statistical analysis */
1340 if ((flags & IS_TEXT_UNICODE_STATISTICS) &&
1341 ((weight * hi_byte_diff) < lo_byte_diff))
1342 {
1343 out_flags |= IS_TEXT_UNICODE_STATISTICS;
1344 }
1345
1346 /* Check for unicode NULL chars */
1347 if (flags & IS_TEXT_UNICODE_NULL_BYTES)
1348 {
1349 for (i = 0; i < len; i++)
1350 {
1351 if (!(s[i] & 0xff) || !(s[i] >> 8))
1352 {
1353 out_flags |= IS_TEXT_UNICODE_NULL_BYTES;
1354 break;
1355 }
1356 }
1357 }
1358
1359 if (flags & IS_TEXT_UNICODE_CONTROLS)
1360 {
1361 for (i = 0; i < len; i++)
1362 {
1363 if (strchrW(std_control_chars, s[i]))
1364 {
1365 out_flags |= IS_TEXT_UNICODE_CONTROLS;
1366 break;
1367 }
1368 }
1369 }
1370
1371 if (flags & IS_TEXT_UNICODE_REVERSE_CONTROLS)
1372 {
1373 for (i = 0; i < len; i++)
1374 {
1375 if (strchrW(byterev_control_chars, s[i]))
1376 {
1377 out_flags |= IS_TEXT_UNICODE_REVERSE_CONTROLS;
1378 break;
1379 }
1380 }
1381
1382 if (hi_byte_diff && !lo_byte_diff)
1383 {
1384 out_flags |= IS_TEXT_UNICODE_REVERSE_ASCII16;
1385 }
1386
1387 if ((weight * lo_byte_diff) < hi_byte_diff)
1388 {
1389 out_flags |= IS_TEXT_UNICODE_REVERSE_STATISTICS;
1390 }
1391 }
1392
1393 if (pf)
1394 {
1395 out_flags &= *pf;
1396 *pf = out_flags;
1397 }
1398
1399 /* check for flags that indicate it's definitely not valid Unicode */
1400 if (out_flags & (IS_TEXT_UNICODE_REVERSE_MASK | IS_TEXT_UNICODE_NOT_UNICODE_MASK)) return FALSE;
1401
1402 /* now check for invalid ASCII, and assume Unicode if so */
1403 if (out_flags & IS_TEXT_UNICODE_NOT_ASCII_MASK) return TRUE;
1404
1405 /* now check for Unicode flags */
1406 if (out_flags & IS_TEXT_UNICODE_UNICODE_MASK) return TRUE;
1407
1408 /* no flags set */
1409 return FALSE;
1410 }
1411
1412
1413 /*
1414 * @implemented
1415 *
1416 * NOTES
1417 * Same as RtlOemStringToUnicodeString but doesn't write terminating null
1418 * A partial copy is NOT performed if the dest buffer is too small!
1419 */
1420 NTSTATUS
1421 NTAPI
1422 RtlOemStringToCountedUnicodeString(
1423 IN OUT PUNICODE_STRING UniDest,
1424 IN PCOEM_STRING OemSource,
1425 IN BOOLEAN AllocateDestinationString)
1426 {
1427 NTSTATUS Status;
1428 ULONG Length;
1429 ULONG Index;
1430
1431 PAGED_CODE_RTL();
1432
1433 /* Calculate size of the string */
1434 Length = RtlOemStringToCountedUnicodeSize(OemSource);
1435
1436 /* If it's 0 then zero out dest string and return */
1437 if (!Length)
1438 {
1439 RtlZeroMemory(UniDest, sizeof(UNICODE_STRING));
1440 return STATUS_SUCCESS;
1441 }
1442
1443 /* Check if length is a sane value */
1444 if (Length > MAXUSHORT) return STATUS_INVALID_PARAMETER_2;
1445
1446 /* Store it in dest string */
1447 UniDest->Length = (USHORT)Length;
1448
1449 /* If we're asked to alloc the string - do so */
1450 if (AllocateDestinationString)
1451 {
1452 UniDest->Buffer = RtlpAllocateStringMemory(Length, TAG_USTR);
1453 UniDest->MaximumLength = (USHORT)Length;
1454
1455 if (!UniDest->Buffer) return STATUS_NO_MEMORY;
1456 }
1457 else if (UniDest->Length > UniDest->MaximumLength)
1458 {
1459 return STATUS_BUFFER_OVERFLOW;
1460 }
1461
1462 /* Do the conversion */
1463 Status = RtlOemToUnicodeN(UniDest->Buffer,
1464 UniDest->Length,
1465 &Index,
1466 OemSource->Buffer,
1467 OemSource->Length);
1468
1469 if (!NT_SUCCESS(Status) && AllocateDestinationString)
1470 {
1471 /* Conversion failed, free dest string and return status code */
1472 RtlpFreeStringMemory(UniDest->Buffer, TAG_USTR);
1473 UniDest->Buffer = NULL;
1474 return Status;
1475 }
1476
1477 return STATUS_SUCCESS;
1478 }
1479
1480 /*
1481 * @implemented
1482 *
1483 * RETURNS
1484 * TRUE if the names are equal, FALSE if not
1485 *
1486 * NOTES
1487 * The comparison is case insensitive.
1488 */
1489 BOOLEAN
1490 NTAPI
1491 RtlEqualComputerName(
1492 IN PUNICODE_STRING ComputerName1,
1493 IN PUNICODE_STRING ComputerName2)
1494 {
1495 OEM_STRING OemString1;
1496 OEM_STRING OemString2;
1497 BOOLEAN Result = FALSE;
1498
1499 if (NT_SUCCESS(RtlUpcaseUnicodeStringToOemString(&OemString1,
1500 ComputerName1,
1501 TRUE)))
1502 {
1503 if (NT_SUCCESS(RtlUpcaseUnicodeStringToOemString(&OemString2,
1504 ComputerName2,
1505 TRUE)))
1506 {
1507 Result = RtlEqualString(&OemString1, &OemString2, FALSE);
1508 RtlFreeOemString(&OemString2);
1509 }
1510
1511 RtlFreeOemString(&OemString1);
1512 }
1513
1514 return Result;
1515 }
1516
1517 /*
1518 * @implemented
1519 *
1520 * RETURNS
1521 * TRUE if the names are equal, FALSE if not
1522 *
1523 * NOTES
1524 * The comparison is case insensitive.
1525 */
1526 BOOLEAN
1527 NTAPI
1528 RtlEqualDomainName (
1529 IN PUNICODE_STRING DomainName1,
1530 IN PUNICODE_STRING DomainName2)
1531 {
1532 return RtlEqualComputerName(DomainName1, DomainName2);
1533 }
1534
1535 /*
1536 * @implemented
1537 *
1538 * RIPPED FROM WINE's ntdll\rtlstr.c rev 1.45
1539 *
1540 * Convert a string representation of a GUID into a GUID.
1541 *
1542 * PARAMS
1543 * str [I] String representation in the format "{XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX}"
1544 * guid [O] Destination for the converted GUID
1545 *
1546 * RETURNS
1547 * Success: STATUS_SUCCESS. guid contains the converted value.
1548 * Failure: STATUS_INVALID_PARAMETER, if str is not in the expected format.
1549 *
1550 * SEE ALSO
1551 * See RtlStringFromGUID.
1552 */
1553 NTSTATUS
1554 NTAPI
1555 RtlGUIDFromString(
1556 IN UNICODE_STRING *str,
1557 OUT GUID* guid)
1558 {
1559 int i = 0;
1560 const WCHAR *lpszCLSID = str->Buffer;
1561 BYTE* lpOut = (BYTE*)guid;
1562
1563 //TRACE("(%s,%p)\n", debugstr_us(str), guid);
1564
1565 /* Convert string: {XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX}
1566 * to memory: DWORD... WORD WORD BYTES............
1567 */
1568 while (i <= 37)
1569 {
1570 switch (i)
1571 {
1572 case 0:
1573 if (*lpszCLSID != '{')
1574 return STATUS_INVALID_PARAMETER;
1575 break;
1576
1577 case 9:
1578 case 14:
1579 case 19:
1580 case 24:
1581 if (*lpszCLSID != '-')
1582 return STATUS_INVALID_PARAMETER;
1583 break;
1584
1585 case 37:
1586 if (*lpszCLSID != '}')
1587 return STATUS_INVALID_PARAMETER;
1588
1589 break;
1590
1591 default:
1592 {
1593 WCHAR ch = *lpszCLSID, ch2 = lpszCLSID[1];
1594 unsigned char byte;
1595
1596 /* Read two hex digits as a byte value */
1597 if (ch >= '0' && ch <= '9')
1598 ch = ch - '0';
1599 else if (ch >= 'a' && ch <= 'f')
1600 ch = ch - 'a' + 10;
1601 else if (ch >= 'A' && ch <= 'F')
1602 ch = ch - 'A' + 10;
1603 else
1604 return STATUS_INVALID_PARAMETER;
1605
1606 if (ch2 >= '0' && ch2 <= '9')
1607 ch2 = ch2 - '0';
1608 else if (ch2 >= 'a' && ch2 <= 'f')
1609 ch2 = ch2 - 'a' + 10;
1610 else if (ch2 >= 'A' && ch2 <= 'F')
1611 ch2 = ch2 - 'A' + 10;
1612 else
1613 return STATUS_INVALID_PARAMETER;
1614
1615 byte = ch << 4 | ch2;
1616
1617 switch (i)
1618 {
1619 #ifndef WORDS_BIGENDIAN
1620 /* For Big Endian machines, we store the data such that the
1621 * dword/word members can be read as DWORDS and WORDS correctly. */
1622 /* Dword */
1623 case 1:
1624 lpOut[3] = byte;
1625 break;
1626 case 3:
1627 lpOut[2] = byte;
1628 break;
1629 case 5:
1630 lpOut[1] = byte;
1631 break;
1632 case 7:
1633 lpOut[0] = byte;
1634 lpOut += 4;
1635 break;
1636 /* Word */
1637 case 10:
1638 case 15:
1639 lpOut[1] = byte;
1640 break;
1641 case 12:
1642 case 17:
1643 lpOut[0] = byte;
1644 lpOut += 2;
1645 break;
1646 #endif
1647 /* Byte */
1648 default:
1649 lpOut[0] = byte;
1650 lpOut++;
1651 break;
1652 }
1653
1654 lpszCLSID++; /* Skip 2nd character of byte */
1655 i++;
1656 }
1657 }
1658
1659 lpszCLSID++;
1660 i++;
1661 }
1662
1663 return STATUS_SUCCESS;
1664 }
1665
1666 /*
1667 * @implemented
1668 */
1669 VOID
1670 NTAPI
1671 RtlEraseUnicodeString(
1672 IN PUNICODE_STRING String)
1673 {
1674 if (String->Buffer && String->MaximumLength)
1675 {
1676 RtlZeroMemory(String->Buffer, String->MaximumLength);
1677 String->Length = 0;
1678 }
1679 }
1680
1681 /*
1682 * @implemented
1683 */
1684 NTSTATUS
1685 NTAPI
1686 RtlHashUnicodeString(
1687 IN CONST UNICODE_STRING *String,
1688 IN BOOLEAN CaseInSensitive,
1689 IN ULONG HashAlgorithm,
1690 OUT PULONG HashValue)
1691 {
1692 if (String != NULL && HashValue != NULL)
1693 {
1694 switch (HashAlgorithm)
1695 {
1696 case HASH_STRING_ALGORITHM_DEFAULT:
1697 case HASH_STRING_ALGORITHM_X65599:
1698 {
1699 WCHAR *c, *end;
1700
1701 *HashValue = 0;
1702 end = String->Buffer + (String->Length / sizeof(WCHAR));
1703
1704 if (CaseInSensitive)
1705 {
1706 for (c = String->Buffer; c != end; c++)
1707 {
1708 /* only uppercase characters if they are 'a' ... 'z'! */
1709 *HashValue = ((65599 * (*HashValue)) +
1710 (ULONG)(((*c) >= L'a' && (*c) <= L'z') ?
1711 (*c) - L'a' + L'A' : (*c)));
1712 }
1713 }
1714 else
1715 {
1716 for (c = String->Buffer; c != end; c++)
1717 {
1718 *HashValue = ((65599 * (*HashValue)) + (ULONG)(*c));
1719 }
1720 }
1721
1722 return STATUS_SUCCESS;
1723 }
1724 }
1725 }
1726
1727 return STATUS_INVALID_PARAMETER;
1728 }
1729
1730 /*
1731 * @implemented
1732 *
1733 * NOTES
1734 * Same as RtlUnicodeStringToOemString but doesn't write terminating null
1735 * Does a partial copy if the dest buffer is too small
1736 */
1737 NTSTATUS
1738 NTAPI
1739 RtlUnicodeStringToCountedOemString(
1740 IN OUT POEM_STRING OemDest,
1741 IN PUNICODE_STRING UniSource,
1742 IN BOOLEAN AllocateDestinationString)
1743 {
1744 NTSTATUS Status;
1745 ULONG Length;
1746 ULONG Index;
1747
1748 PAGED_CODE_RTL();
1749
1750 /* Calculate size of the string */
1751 Length = RtlUnicodeStringToCountedOemSize(UniSource);
1752
1753 /* If it's 0 then zero out dest string and return */
1754 if (!Length)
1755 {
1756 RtlZeroMemory(OemDest, sizeof(OEM_STRING));
1757 return STATUS_SUCCESS;
1758 }
1759
1760 /* Check if length is a sane value */
1761 if (Length > MAXUSHORT) return STATUS_INVALID_PARAMETER_2;
1762
1763 /* Store it in dest string */
1764 OemDest->Length = (USHORT)Length;
1765
1766 /* If we're asked to alloc the string - do so */
1767 if (AllocateDestinationString)
1768 {
1769 OemDest->Buffer = RtlpAllocateStringMemory(Length, TAG_OSTR);
1770 OemDest->MaximumLength = (USHORT)Length;
1771 if (!OemDest->Buffer) return STATUS_NO_MEMORY;
1772 }
1773 else if (OemDest->Length > OemDest->MaximumLength)
1774 {
1775 return STATUS_BUFFER_OVERFLOW;
1776 }
1777
1778 /* Do the conversion */
1779 Status = RtlUnicodeToOemN(OemDest->Buffer,
1780 OemDest->Length,
1781 &Index,
1782 UniSource->Buffer,
1783 UniSource->Length);
1784
1785 /* Check for unmapped character */
1786 if (NT_SUCCESS(Status) && !RtlpDidUnicodeToOemWork(UniSource, OemDest))
1787 Status = STATUS_UNMAPPABLE_CHARACTER;
1788
1789 if (!NT_SUCCESS(Status) && AllocateDestinationString)
1790 {
1791 /* Conversion failed, free dest string and return status code */
1792 RtlpFreeStringMemory(OemDest->Buffer, TAG_OSTR);
1793 OemDest->Buffer = NULL;
1794 return Status;
1795 }
1796
1797 return Status;
1798 }
1799
1800 /*
1801 * @implemented
1802 */
1803 NTSTATUS
1804 NTAPI
1805 RtlLargeIntegerToChar(
1806 IN PLARGE_INTEGER Value,
1807 IN ULONG Base,
1808 IN ULONG Length,
1809 IN OUT PCHAR String)
1810 {
1811 ULONGLONG Val = Value->QuadPart;
1812 CHAR Buffer[65];
1813 CHAR Digit;
1814 SIZE_T Len;
1815 PCHAR Pos;
1816
1817 if (Base == 0) Base = 10;
1818
1819 if ((Base != 2) && (Base != 8) && (Base != 10) && (Base != 16))
1820 {
1821 return STATUS_INVALID_PARAMETER;
1822 }
1823
1824 Pos = &Buffer[64];
1825 *Pos = '\0';
1826
1827 do
1828 {
1829 Pos--;
1830 Digit = (CHAR)(Val % Base);
1831 Val = Val / Base;
1832
1833 if (Digit < 10)
1834 *Pos = '0' + Digit;
1835 else
1836 *Pos = 'A' + Digit - 10;
1837 }
1838 while (Val != 0L);
1839
1840 Len = &Buffer[64] - Pos;
1841
1842 if (Len > Length)
1843 return STATUS_BUFFER_OVERFLOW;
1844
1845 /* If possible, add the 0 termination */
1846 if (Len < Length)
1847 Len += 1;
1848
1849 /* Copy the string to the target using SEH */
1850 return RtlpSafeCopyMemory(String, Pos, Len);
1851 }
1852
1853 /*
1854 * @implemented
1855 *
1856 * NOTES
1857 * dest is never '\0' terminated because it may be equal to src, and src
1858 * might not be '\0' terminated. dest->Length is only set upon success.
1859 */
1860 NTSTATUS
1861 NTAPI
1862 RtlUpcaseUnicodeString(
1863 IN OUT PUNICODE_STRING UniDest,
1864 IN PCUNICODE_STRING UniSource,
1865 IN BOOLEAN AllocateDestinationString)
1866 {
1867 ULONG i, j;
1868
1869 PAGED_CODE_RTL();
1870
1871 if (AllocateDestinationString)
1872 {
1873 UniDest->MaximumLength = UniSource->Length;
1874 UniDest->Buffer = RtlpAllocateStringMemory(UniDest->MaximumLength, TAG_USTR);
1875 if (UniDest->Buffer == NULL) return STATUS_NO_MEMORY;
1876 }
1877 else if (UniSource->Length > UniDest->MaximumLength)
1878 {
1879 return STATUS_BUFFER_OVERFLOW;
1880 }
1881
1882 j = UniSource->Length / sizeof(WCHAR);
1883
1884 for (i = 0; i < j; i++)
1885 {
1886 UniDest->Buffer[i] = RtlUpcaseUnicodeChar(UniSource->Buffer[i]);
1887 }
1888
1889 UniDest->Length = UniSource->Length;
1890 return STATUS_SUCCESS;
1891 }
1892
1893 /*
1894 * @implemented
1895 *
1896 * NOTES
1897 * This function always writes a terminating '\0'.
1898 * It performs a partial copy if ansi is too small.
1899 */
1900 NTSTATUS
1901 NTAPI
1902 RtlUpcaseUnicodeStringToAnsiString(
1903 IN OUT PANSI_STRING AnsiDest,
1904 IN PUNICODE_STRING UniSource,
1905 IN BOOLEAN AllocateDestinationString)
1906 {
1907 NTSTATUS Status;
1908 ULONG Length;
1909 ULONG Index;
1910 PAGED_CODE_RTL();
1911
1912 Length = RtlUnicodeStringToAnsiSize(UniSource);
1913 if (Length > MAXUSHORT) return STATUS_INVALID_PARAMETER_2;
1914
1915 AnsiDest->Length = (USHORT)Length - sizeof(CHAR);
1916
1917 if (AllocateDestinationString)
1918 {
1919 AnsiDest->Buffer = RtlpAllocateStringMemory(Length, TAG_ASTR);
1920 AnsiDest->MaximumLength = (USHORT)Length;
1921 if (!AnsiDest->Buffer) return STATUS_NO_MEMORY;
1922 }
1923 else if (AnsiDest->Length >= AnsiDest->MaximumLength)
1924 {
1925 if (!AnsiDest->MaximumLength) return STATUS_BUFFER_OVERFLOW;
1926 }
1927
1928 Status = RtlUpcaseUnicodeToMultiByteN(AnsiDest->Buffer,
1929 AnsiDest->Length,
1930 &Index,
1931 UniSource->Buffer,
1932 UniSource->Length);
1933
1934 if (!NT_SUCCESS(Status) && AllocateDestinationString)
1935 {
1936 RtlpFreeStringMemory(AnsiDest->Buffer, TAG_ASTR);
1937 AnsiDest->Buffer = NULL;
1938 return Status;
1939 }
1940
1941 AnsiDest->Buffer[Index] = ANSI_NULL;
1942 return Status;
1943 }
1944
1945 /*
1946 * @implemented
1947 *
1948 * NOTES
1949 * This function always writes a terminating '\0'.
1950 * It performs a partial copy if ansi is too small.
1951 */
1952 NTSTATUS
1953 NTAPI
1954 RtlUpcaseUnicodeStringToCountedOemString(
1955 IN OUT POEM_STRING OemDest,
1956 IN PCUNICODE_STRING UniSource,
1957 IN BOOLEAN AllocateDestinationString)
1958 {
1959 NTSTATUS Status;
1960 ULONG Length;
1961 ULONG Index;
1962 PAGED_CODE_RTL();
1963
1964 Length = RtlUnicodeStringToCountedOemSize(UniSource);
1965
1966 if (!Length)
1967 {
1968 RtlZeroMemory(OemDest, sizeof(OEM_STRING));
1969 }
1970
1971 if (Length > MAXUSHORT) return STATUS_INVALID_PARAMETER_2;
1972
1973 OemDest->Length = (USHORT)Length;
1974
1975 if (AllocateDestinationString)
1976 {
1977 OemDest->Buffer = RtlpAllocateStringMemory(Length, TAG_OSTR);
1978 OemDest->MaximumLength = (USHORT)Length;
1979 if (!OemDest->Buffer) return STATUS_NO_MEMORY;
1980 }
1981 else if (OemDest->Length > OemDest->MaximumLength)
1982 {
1983 return STATUS_BUFFER_OVERFLOW;
1984 }
1985
1986 Status = RtlUpcaseUnicodeToOemN(OemDest->Buffer,
1987 OemDest->Length,
1988 &Index,
1989 UniSource->Buffer,
1990 UniSource->Length);
1991
1992 /* Check for unmapped characters */
1993 if (NT_SUCCESS(Status) && !RtlpDidUnicodeToOemWork(UniSource, OemDest))
1994 Status = STATUS_UNMAPPABLE_CHARACTER;
1995
1996 if (!NT_SUCCESS(Status) && AllocateDestinationString)
1997 {
1998 RtlpFreeStringMemory(OemDest->Buffer, TAG_OSTR);
1999 OemDest->Buffer = NULL;
2000 return Status;
2001 }
2002
2003 return Status;
2004 }
2005
2006 /*
2007 * @implemented
2008 * NOTES
2009 * OEM string is always nullterminated
2010 * It performs a partial copy if oem is too small.
2011 */
2012 NTSTATUS
2013 NTAPI
2014 RtlUpcaseUnicodeStringToOemString (
2015 IN OUT POEM_STRING OemDest,
2016 IN PCUNICODE_STRING UniSource,
2017 IN BOOLEAN AllocateDestinationString)
2018 {
2019 NTSTATUS Status;
2020 ULONG Length;
2021 ULONG Index;
2022 PAGED_CODE_RTL();
2023
2024 Length = RtlUnicodeStringToOemSize(UniSource);
2025 if (Length > MAXUSHORT) return STATUS_INVALID_PARAMETER_2;
2026
2027 OemDest->Length = (USHORT)Length - sizeof(CHAR);
2028
2029 if (AllocateDestinationString)
2030 {
2031 OemDest->Buffer = RtlpAllocateStringMemory(Length, TAG_OSTR);
2032 OemDest->MaximumLength = (USHORT)Length;
2033 if (!OemDest->Buffer) return STATUS_NO_MEMORY;
2034 }
2035 else if (OemDest->Length >= OemDest->MaximumLength)
2036 {
2037 return STATUS_BUFFER_OVERFLOW;
2038 }
2039
2040 Status = RtlUpcaseUnicodeToOemN(OemDest->Buffer,
2041 OemDest->Length,
2042 &Index,
2043 UniSource->Buffer,
2044 UniSource->Length);
2045
2046 /* Check for unmapped characters */
2047 if (NT_SUCCESS(Status) && !RtlpDidUnicodeToOemWork(UniSource, OemDest))
2048 Status = STATUS_UNMAPPABLE_CHARACTER;
2049
2050 if (!NT_SUCCESS(Status) && AllocateDestinationString)
2051 {
2052 RtlpFreeStringMemory(OemDest->Buffer, TAG_OSTR);
2053 OemDest->Buffer = NULL;
2054 return Status;
2055 }
2056
2057 OemDest->Buffer[Index] = ANSI_NULL;
2058 return Status;
2059 }
2060
2061 /*
2062 * @implemented
2063 *
2064 * RETURNS
2065 * Bytes calculated including nullterm
2066 */
2067 ULONG
2068 NTAPI
2069 RtlxOemStringToUnicodeSize(IN PCOEM_STRING OemString)
2070 {
2071 ULONG Size;
2072
2073 /* Convert the Mb String to Unicode Size */
2074 RtlMultiByteToUnicodeSize(&Size,
2075 OemString->Buffer,
2076 OemString->Length);
2077
2078 /* Return the size + null-char */
2079 return (Size + sizeof(WCHAR));
2080 }
2081
2082 /*
2083 * @implemented
2084 */
2085 NTSTATUS
2086 NTAPI
2087 RtlStringFromGUID (IN REFGUID Guid,
2088 OUT PUNICODE_STRING GuidString)
2089 {
2090 /* Setup the string */
2091 GuidString->Length = 38 * sizeof(WCHAR);
2092 GuidString->MaximumLength = GuidString->Length + sizeof(UNICODE_NULL);
2093 GuidString->Buffer = RtlpAllocateStringMemory(GuidString->MaximumLength,
2094 TAG_USTR);
2095 if (!GuidString->Buffer) return STATUS_NO_MEMORY;
2096
2097 /* Now format the GUID */
2098 swprintf(GuidString->Buffer,
2099 L"{%08lx-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x}",
2100 Guid->Data1,
2101 Guid->Data2,
2102 Guid->Data3,
2103 Guid->Data4[0],
2104 Guid->Data4[1],
2105 Guid->Data4[2],
2106 Guid->Data4[3],
2107 Guid->Data4[4],
2108 Guid->Data4[5],
2109 Guid->Data4[6],
2110 Guid->Data4[7]);
2111 return STATUS_SUCCESS;
2112 }
2113
2114 /*
2115 * @implemented
2116 *
2117 * RETURNS
2118 * Bytes calculated including nullterm
2119 */
2120 ULONG
2121 NTAPI
2122 RtlxUnicodeStringToAnsiSize(IN PCUNICODE_STRING UnicodeString)
2123 {
2124 ULONG Size;
2125 PAGED_CODE_RTL();
2126
2127 ASSERT(!(UnicodeString->Length & 1));
2128
2129 /* Convert the Unicode String to Mb Size */
2130 RtlUnicodeToMultiByteSize(&Size,
2131 UnicodeString->Buffer,
2132 UnicodeString->Length);
2133
2134 /* Return the size + null-char */
2135 return (Size + sizeof(CHAR));
2136 }
2137
2138 /*
2139 * @implemented
2140 */
2141 LONG
2142 NTAPI
2143 RtlCompareUnicodeString(
2144 IN PCUNICODE_STRING s1,
2145 IN PCUNICODE_STRING s2,
2146 IN BOOLEAN CaseInsensitive)
2147 {
2148 unsigned int len;
2149 LONG ret = 0;
2150 LPCWSTR p1, p2;
2151
2152 len = min(s1->Length, s2->Length) / sizeof(WCHAR);
2153 p1 = s1->Buffer;
2154 p2 = s2->Buffer;
2155
2156 if (CaseInsensitive)
2157 {
2158 while (!ret && len--) ret = RtlUpcaseUnicodeChar(*p1++) - RtlUpcaseUnicodeChar(*p2++);
2159 }
2160 else
2161 {
2162 while (!ret && len--) ret = *p1++ - *p2++;
2163 }
2164
2165 if (!ret) ret = s1->Length - s2->Length;
2166
2167 return ret;
2168 }
2169
2170 /*
2171 * @implemented
2172 */
2173 VOID
2174 NTAPI
2175 RtlCopyString(
2176 IN OUT PSTRING DestinationString,
2177 IN const STRING *SourceString OPTIONAL)
2178 {
2179 ULONG SourceLength;
2180 PCHAR p1, p2;
2181
2182 /* Check if there was no source given */
2183 if(!SourceString)
2184 {
2185 /* Simply return an empty string */
2186 DestinationString->Length = 0;
2187 }
2188 else
2189 {
2190 /* Choose the smallest length */
2191 SourceLength = min(DestinationString->MaximumLength,
2192 SourceString->Length);
2193
2194 /* Set it */
2195 DestinationString->Length = (USHORT)SourceLength;
2196
2197 /* Save the pointers to each buffer */
2198 p1 = DestinationString->Buffer;
2199 p2 = SourceString->Buffer;
2200
2201 /* Loop the buffer */
2202 while (SourceLength)
2203 {
2204 /* Copy the character and move on */
2205 *p1++ = * p2++;
2206 SourceLength--;
2207 }
2208 }
2209 }
2210
2211 /*
2212 * @implemented
2213 */
2214 VOID
2215 NTAPI
2216 RtlCopyUnicodeString(
2217 IN OUT PUNICODE_STRING DestinationString,
2218 IN PCUNICODE_STRING SourceString)
2219 {
2220 ULONG SourceLength;
2221
2222 if(SourceString == NULL)
2223 {
2224 DestinationString->Length = 0;
2225 }
2226 else
2227 {
2228 SourceLength = min(DestinationString->MaximumLength,
2229 SourceString->Length);
2230 DestinationString->Length = (USHORT)SourceLength;
2231
2232 RtlCopyMemory(DestinationString->Buffer,
2233 SourceString->Buffer,
2234 SourceLength);
2235
2236 if (DestinationString->Length < DestinationString->MaximumLength)
2237 {
2238 DestinationString->Buffer[SourceLength / sizeof(WCHAR)] = UNICODE_NULL;
2239 }
2240 }
2241 }
2242
2243 /*
2244 * @implemented
2245 *
2246 * NOTES
2247 * Creates a nullterminated UNICODE_STRING
2248 */
2249 BOOLEAN
2250 NTAPI
2251 RtlCreateUnicodeString(
2252 IN OUT PUNICODE_STRING UniDest,
2253 IN PCWSTR Source)
2254 {
2255 SIZE_T Size;
2256 PAGED_CODE_RTL();
2257
2258 Size = (wcslen(Source) + 1) * sizeof(WCHAR);
2259 if (Size > MAXUSHORT) return FALSE;
2260
2261 UniDest->Buffer = RtlpAllocateStringMemory((ULONG)Size, TAG_USTR);
2262
2263 if (UniDest->Buffer == NULL) return FALSE;
2264
2265 RtlCopyMemory(UniDest->Buffer, Source, Size);
2266 UniDest->MaximumLength = (USHORT)Size;
2267 UniDest->Length = (USHORT)Size - sizeof (WCHAR);
2268
2269 return TRUE;
2270 }
2271
2272 /*
2273 * @implemented
2274 */
2275 BOOLEAN
2276 NTAPI
2277 RtlCreateUnicodeStringFromAsciiz(
2278 OUT PUNICODE_STRING Destination,
2279 IN PCSZ Source)
2280 {
2281 ANSI_STRING AnsiString;
2282 NTSTATUS Status;
2283
2284 RtlInitAnsiString(&AnsiString, Source);
2285
2286 Status = RtlAnsiStringToUnicodeString(Destination,
2287 &AnsiString,
2288 TRUE);
2289
2290 return NT_SUCCESS(Status);
2291 }
2292
2293 /*
2294 * @implemented
2295 *
2296 * NOTES
2297 * Dest is never '\0' terminated because it may be equal to src, and src
2298 * might not be '\0' terminated.
2299 * Dest->Length is only set upon success.
2300 */
2301 NTSTATUS
2302 NTAPI
2303 RtlDowncaseUnicodeString(
2304 IN OUT PUNICODE_STRING UniDest,
2305 IN PCUNICODE_STRING UniSource,
2306 IN BOOLEAN AllocateDestinationString)
2307 {
2308 ULONG i;
2309 ULONG StopGap;
2310 PAGED_CODE_RTL();
2311
2312 if (AllocateDestinationString)
2313 {
2314 UniDest->MaximumLength = UniSource->Length;
2315 UniDest->Buffer = RtlpAllocateStringMemory(UniSource->Length, TAG_USTR);
2316 if (UniDest->Buffer == NULL) return STATUS_NO_MEMORY;
2317 }
2318 else if (UniSource->Length > UniDest->MaximumLength)
2319 {
2320 return STATUS_BUFFER_OVERFLOW;
2321 }
2322
2323 UniDest->Length = UniSource->Length;
2324 StopGap = UniSource->Length / sizeof(WCHAR);
2325
2326 for (i = 0 ; i < StopGap; i++)
2327 {
2328 if (UniSource->Buffer[i] < L'A')
2329 {
2330 UniDest->Buffer[i] = UniSource->Buffer[i];
2331 }
2332 else if (UniSource->Buffer[i] <= L'Z')
2333 {
2334 UniDest->Buffer[i] = (UniSource->Buffer[i] + (L'a' - L'A'));
2335 }
2336 else
2337 {
2338 UniDest->Buffer[i] = RtlDowncaseUnicodeChar(UniSource->Buffer[i]);
2339 }
2340 }
2341
2342 return STATUS_SUCCESS;
2343 }
2344
2345 /*
2346 * @implemented
2347 *
2348 * NOTES
2349 * if src is NULL dest is unchanged.
2350 * dest is '\0' terminated when the MaximumLength allowes it.
2351 * When dest fits exactly in MaximumLength characters the '\0' is ommitted.
2352 */
2353 NTSTATUS
2354 NTAPI
2355 RtlAppendUnicodeToString(IN OUT PUNICODE_STRING Destination,
2356 IN PCWSTR Source)
2357 {
2358 USHORT Length;
2359 PWCHAR DestBuffer;
2360
2361 if (Source)
2362 {
2363 UNICODE_STRING UnicodeSource;
2364
2365 RtlInitUnicodeString(&UnicodeSource, Source);
2366 Length = UnicodeSource.Length;
2367
2368 if (Destination->Length + Length > Destination->MaximumLength)
2369 {
2370 return STATUS_BUFFER_TOO_SMALL;
2371 }
2372
2373 DestBuffer = &Destination->Buffer[Destination->Length / sizeof(WCHAR)];
2374 RtlMoveMemory(DestBuffer, Source, Length);
2375 Destination->Length += Length;
2376
2377 /* append terminating '\0' if enough space */
2378 if(Destination->MaximumLength > Destination->Length)
2379 {
2380 DestBuffer[Length / sizeof(WCHAR)] = UNICODE_NULL;
2381 }
2382 }
2383
2384 return STATUS_SUCCESS;
2385 }
2386
2387 /*
2388 * @implemented
2389 *
2390 * NOTES
2391 * if src is NULL dest is unchanged.
2392 * dest is never '\0' terminated.
2393 */
2394 NTSTATUS
2395 NTAPI
2396 RtlAppendAsciizToString(
2397 IN OUT PSTRING Destination,
2398 IN PCSZ Source)
2399 {
2400 SIZE_T Size;
2401
2402 if (Source)
2403 {
2404 Size = strlen(Source);
2405
2406 if (Destination->Length + Size > Destination->MaximumLength)
2407 {
2408 return STATUS_BUFFER_TOO_SMALL;
2409 }
2410
2411 RtlMoveMemory(&Destination->Buffer[Destination->Length], Source, Size);
2412 Destination->Length += (USHORT)Size;
2413 }
2414
2415 return STATUS_SUCCESS;
2416 }
2417
2418 /*
2419 * @implemented
2420 */
2421 VOID
2422 NTAPI
2423 RtlUpperString(PSTRING DestinationString,
2424 const STRING *SourceString)
2425 {
2426 USHORT Length;
2427 PCHAR Src, Dest;
2428
2429 Length = min(SourceString->Length,
2430 DestinationString->MaximumLength);
2431
2432 Src = SourceString->Buffer;
2433 Dest = DestinationString->Buffer;
2434 DestinationString->Length = Length;
2435
2436 while (Length)
2437 {
2438 *Dest++ = RtlUpperChar(*Src++);
2439 Length--;
2440 }
2441 }
2442
2443 /*
2444 * @implemented
2445 *
2446 * NOTES
2447 * See RtlpDuplicateUnicodeString
2448 */
2449 NTSTATUS
2450 NTAPI
2451 RtlDuplicateUnicodeString(
2452 IN ULONG Flags,
2453 IN PCUNICODE_STRING SourceString,
2454 OUT PUNICODE_STRING DestinationString)
2455 {
2456 PAGED_CODE_RTL();
2457
2458 if (SourceString == NULL || DestinationString == NULL ||
2459 SourceString->Length > SourceString->MaximumLength ||
2460 (SourceString->Length == 0 && SourceString->MaximumLength > 0 && SourceString->Buffer == NULL) ||
2461 Flags == RTL_DUPLICATE_UNICODE_STRING_ALLOCATE_NULL_STRING || Flags >= 4)
2462 {
2463 return STATUS_INVALID_PARAMETER;
2464 }
2465
2466
2467 if ((SourceString->Length == 0) &&
2468 (Flags != (RTL_DUPLICATE_UNICODE_STRING_NULL_TERMINATE |
2469 RTL_DUPLICATE_UNICODE_STRING_ALLOCATE_NULL_STRING)))
2470 {
2471 DestinationString->Length = 0;
2472 DestinationString->MaximumLength = 0;
2473 DestinationString->Buffer = NULL;
2474 }
2475 else
2476 {
2477 UINT DestMaxLength = SourceString->Length;
2478
2479 if (Flags & RTL_DUPLICATE_UNICODE_STRING_NULL_TERMINATE)
2480 DestMaxLength += sizeof(UNICODE_NULL);
2481
2482 DestinationString->Buffer = RtlpAllocateStringMemory(DestMaxLength, TAG_USTR);
2483
2484 if (DestinationString->Buffer == NULL)
2485 return STATUS_NO_MEMORY;
2486
2487 RtlCopyMemory(DestinationString->Buffer, SourceString->Buffer, SourceString->Length);
2488 DestinationString->Length = SourceString->Length;
2489 DestinationString->MaximumLength = DestMaxLength;
2490
2491 if (Flags & RTL_DUPLICATE_UNICODE_STRING_NULL_TERMINATE)
2492 DestinationString->Buffer[DestinationString->Length / sizeof(WCHAR)] = 0;
2493 }
2494
2495 return STATUS_SUCCESS;
2496 }
2497
2498 /*
2499 * @implemented
2500 */
2501 NTSTATUS
2502 NTAPI
2503 RtlValidateUnicodeString(IN ULONG Flags,
2504 IN PCUNICODE_STRING UnicodeString)
2505 {
2506 /* currently no flags are supported! */
2507 ASSERT(Flags == 0);
2508
2509 if ((Flags == 0) &&
2510 ((UnicodeString == NULL) ||
2511 ((UnicodeString->Length != 0) &&
2512 (UnicodeString->Buffer != NULL) &&
2513 ((UnicodeString->Length % sizeof(WCHAR)) == 0) &&
2514 ((UnicodeString->MaximumLength % sizeof(WCHAR)) == 0) &&
2515 (UnicodeString->MaximumLength >= UnicodeString->Length))))
2516 {
2517 /* a NULL pointer as a unicode string is considered to be a valid unicode
2518 string! */
2519 return STATUS_SUCCESS;
2520 }
2521 else
2522 {
2523 return STATUS_INVALID_PARAMETER;
2524 }
2525 }
2526
2527 /*
2528 * @unimplemented
2529 */
2530 NTSTATUS
2531 NTAPI
2532 RtlpEnsureBufferSize(ULONG Unknown1, ULONG Unknown2, ULONG Unknown3)
2533 {
2534 DPRINT1("RtlpEnsureBufferSize: stub\n");
2535 return STATUS_NOT_IMPLEMENTED;
2536 }
2537
2538 static
2539 BOOLEAN
2540 RtlpIsCharInUnicodeString(
2541 IN WCHAR Char,
2542 IN PCUNICODE_STRING MatchString,
2543 IN BOOLEAN CaseInSensitive)
2544 {
2545 USHORT i;
2546
2547 if (CaseInSensitive)
2548 Char = RtlUpcaseUnicodeChar(Char);
2549
2550 for (i = 0; i < MatchString->Length / sizeof(WCHAR); i++)
2551 {
2552 WCHAR OtherChar = MatchString->Buffer[i];
2553 if (CaseInSensitive)
2554 OtherChar = RtlUpcaseUnicodeChar(OtherChar);
2555
2556 if (Char == OtherChar)
2557 return TRUE;
2558 }
2559
2560 return FALSE;
2561 }
2562
2563 /*
2564 * @implemented
2565 */
2566 NTSTATUS
2567 NTAPI
2568 RtlFindCharInUnicodeString(
2569 IN ULONG Flags,
2570 IN PCUNICODE_STRING SearchString,
2571 IN PCUNICODE_STRING MatchString,
2572 OUT PUSHORT Position)
2573 {
2574 BOOLEAN Found;
2575 const BOOLEAN WantToFind = (Flags & RTL_FIND_CHAR_IN_UNICODE_STRING_COMPLEMENT_CHAR_SET) == 0;
2576 const BOOLEAN CaseInSensitive = (Flags & RTL_FIND_CHAR_IN_UNICODE_STRING_CASE_INSENSITIVE) != 0;
2577 USHORT i, Length;
2578
2579 DPRINT("RtlFindCharInUnicodeString(%u, '%wZ', '%wZ', %p)\n",
2580 Flags, SearchString, MatchString, Position);
2581
2582 /* Parameter checks */
2583 if (Position == NULL)
2584 return STATUS_INVALID_PARAMETER;
2585
2586 *Position = 0;
2587
2588 if (Flags & ~(RTL_FIND_CHAR_IN_UNICODE_STRING_START_AT_END |
2589 RTL_FIND_CHAR_IN_UNICODE_STRING_COMPLEMENT_CHAR_SET |
2590 RTL_FIND_CHAR_IN_UNICODE_STRING_CASE_INSENSITIVE))
2591 return STATUS_INVALID_PARAMETER;
2592
2593 /* Search */
2594 Length = SearchString->Length / sizeof(WCHAR);
2595 if (Flags & RTL_FIND_CHAR_IN_UNICODE_STRING_START_AT_END)
2596 {
2597 for (i = Length - 1; (SHORT)i >= 0; i--)
2598 {
2599 Found = RtlpIsCharInUnicodeString(SearchString->Buffer[i], MatchString, CaseInSensitive);
2600 if (Found == WantToFind)
2601 {
2602 *Position = i * sizeof(WCHAR);
2603 return STATUS_SUCCESS;
2604 }
2605 }
2606 }
2607 else
2608 {
2609 for (i = 0; i < Length; i++)
2610 {
2611 Found = RtlpIsCharInUnicodeString(SearchString->Buffer[i], MatchString, CaseInSensitive);
2612 if (Found == WantToFind)
2613 {
2614 *Position = (i + 1) * sizeof(WCHAR);
2615 return STATUS_SUCCESS;
2616 }
2617 }
2618 }
2619
2620 return STATUS_NOT_FOUND;
2621 }
2622
2623 /*
2624 * @implemented
2625 *
2626 * NOTES
2627 * Get the maximum of MAX_COMPUTERNAME_LENGTH characters from the dns.host name until the dot is found.
2628 * Convert is to an uppercase oem string and check for unmapped characters.
2629 * Then convert the oem string back to an unicode string.
2630 */
2631 NTSTATUS
2632 NTAPI
2633 RtlDnsHostNameToComputerName(PUNICODE_STRING ComputerName, PUNICODE_STRING DnsHostName, BOOLEAN AllocateComputerNameString)
2634 {
2635 NTSTATUS Status;
2636 ULONG Length;
2637 ULONG ComputerNameLength;
2638 ULONG ComputerNameOemNLength;
2639 OEM_STRING ComputerNameOem;
2640 CHAR ComputerNameOemN[MAX_COMPUTERNAME_LENGTH + 1];
2641
2642 Status = STATUS_INVALID_COMPUTER_NAME;
2643 ComputerNameLength = DnsHostName->Length;
2644
2645 /* find the first dot in the dns host name */
2646 for (Length = 0; Length < DnsHostName->Length / sizeof(WCHAR); Length++)
2647 {
2648 if (DnsHostName->Buffer[Length] == L'.')
2649 {
2650 /* dot found, so set the length for the oem translation */
2651 ComputerNameLength = Length * sizeof(WCHAR);
2652 break;
2653 }
2654 }
2655
2656 /* the computername must have one character */
2657 if (ComputerNameLength > 0)
2658 {
2659 ComputerNameOemNLength = 0;
2660 /* convert to oem string and use uppercase letters */
2661 Status = RtlUpcaseUnicodeToOemN(ComputerNameOemN,
2662 MAX_COMPUTERNAME_LENGTH,
2663 &ComputerNameOemNLength,
2664 DnsHostName->Buffer,
2665 ComputerNameLength);
2666
2667 /* status STATUS_BUFFER_OVERFLOW is not a problem since the computername shoud only
2668 have MAX_COMPUTERNAME_LENGTH characters */
2669 if ((Status == STATUS_SUCCESS) ||
2670 (Status == STATUS_BUFFER_OVERFLOW))
2671 {
2672 /* set the termination for the oem string */
2673 ComputerNameOemN[MAX_COMPUTERNAME_LENGTH] = 0;
2674 /* set status for the case the next function failed */
2675 Status = STATUS_INVALID_COMPUTER_NAME;
2676 /* fillup the oem string structure with the converted computername
2677 and check it for unmapped characters */
2678 ComputerNameOem.Buffer = ComputerNameOemN;
2679 ComputerNameOem.Length = (USHORT)ComputerNameOemNLength;
2680 ComputerNameOem.MaximumLength = (USHORT)(MAX_COMPUTERNAME_LENGTH + 1);
2681
2682 if (RtlpDidUnicodeToOemWork(DnsHostName, &ComputerNameOem))
2683 {
2684 /* no unmapped character so convert it back to an unicode string */
2685 Status = RtlOemStringToUnicodeString(ComputerName,
2686 &ComputerNameOem,
2687 AllocateComputerNameString);
2688 }
2689 }
2690 }
2691
2692 return Status;
2693 }
2694