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