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