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