[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
588 if (SourceString)
589 {
590 Size = wcslen(SourceString) * sizeof(WCHAR);
591 if (Size > (MAXUSHORT - sizeof(WCHAR))) Size = MAXUSHORT - sizeof(WCHAR);
592 DestinationString->Length = (USHORT)Size;
593 DestinationString->MaximumLength = (USHORT)Size + sizeof(WCHAR);
594 }
595 else
596 {
597 DestinationString->Length = 0;
598 DestinationString->MaximumLength = 0;
599 }
600
601 DestinationString->Buffer = (PWCHAR)SourceString;
602 }
603
604 /*
605 * @implemented
606 */
607 NTSTATUS
608 NTAPI
609 RtlInitUnicodeStringEx(
610 OUT PUNICODE_STRING DestinationString,
611 IN PCWSTR SourceString)
612 {
613 SIZE_T Size;
614
615 if (SourceString)
616 {
617 Size = wcslen(SourceString) * sizeof(WCHAR);
618 if (Size > (MAXUSHORT - sizeof(WCHAR))) return STATUS_NAME_TOO_LONG;
619 DestinationString->Length = (USHORT)Size;
620 DestinationString->MaximumLength = (USHORT)Size + sizeof(WCHAR);
621 }
622 else
623 {
624 DestinationString->Length = 0;
625 DestinationString->MaximumLength = 0;
626 }
627
628 DestinationString->Buffer = (PWCHAR)SourceString;
629 return STATUS_SUCCESS;
630 }
631
632 /*
633 * @implemented
634 *
635 * NOTES
636 * Writes at most length characters to the string str.
637 * Str is nullterminated when length allowes it.
638 * When str fits exactly in length characters the nullterm is ommitted.
639 */
640 NTSTATUS NTAPI RtlIntegerToChar(
641 ULONG value, /* [I] Value to be converted */
642 ULONG base, /* [I] Number base for conversion (allowed 0, 2, 8, 10 or 16) */
643 ULONG length, /* [I] Length of the str buffer in bytes */
644 PCHAR str) /* [O] Destination for the converted value */
645 {
646 CHAR buffer[33];
647 PCHAR pos;
648 CHAR digit;
649 SIZE_T len;
650
651 if (base == 0)
652 {
653 base = 10;
654 }
655 else if (base != 2 && base != 8 && base != 10 && base != 16)
656 {
657 return STATUS_INVALID_PARAMETER;
658 }
659
660 pos = &buffer[32];
661 *pos = '\0';
662
663 do
664 {
665 pos--;
666 digit = (CHAR)(value % base);
667 value = value / base;
668
669 if (digit < 10)
670 {
671 *pos = '0' + digit;
672 }
673 else
674 {
675 *pos = 'A' + digit - 10;
676 }
677 }
678 while (value != 0L);
679
680 len = &buffer[32] - pos;
681
682 if (len > length)
683 {
684 return STATUS_BUFFER_OVERFLOW;
685 }
686 else if (str == NULL)
687 {
688 return STATUS_ACCESS_VIOLATION;
689 }
690 else if (len == length)
691 {
692 memcpy(str, pos, len);
693 }
694 else
695 {
696 memcpy(str, pos, len + 1);
697 }
698
699 return STATUS_SUCCESS;
700 }
701
702 /*
703 * @implemented
704 */
705 NTSTATUS
706 NTAPI
707 RtlIntegerToUnicode(
708 IN ULONG Value,
709 IN ULONG Base OPTIONAL,
710 IN ULONG Length OPTIONAL,
711 IN OUT LPWSTR String)
712 {
713 ULONG Radix;
714 WCHAR temp[33];
715 ULONG v = Value;
716 ULONG i;
717 PWCHAR tp;
718 PWCHAR sp;
719
720 Radix = Base;
721
722 if (Radix == 0) Radix = 10;
723
724 if ((Radix != 2) && (Radix != 8) &&
725 (Radix != 10) && (Radix != 16))
726 {
727 return STATUS_INVALID_PARAMETER;
728 }
729
730 tp = temp;
731
732 while (v || tp == temp)
733 {
734 i = v % Radix;
735 v = v / Radix;
736
737 if (i < 10) *tp = (WCHAR)(i + L'0');
738 else *tp = (WCHAR)(i + L'a' - 10);
739
740 tp++;
741 }
742
743 if ((ULONG)((ULONG_PTR)tp - (ULONG_PTR)temp) >= Length)
744 {
745 return STATUS_BUFFER_TOO_SMALL;
746 }
747
748 sp = String;
749
750 while (tp > temp) *sp++ = *--tp;
751
752 *sp = 0;
753
754 return STATUS_SUCCESS;
755 }
756
757 /*
758 * @implemented
759 */
760 NTSTATUS
761 NTAPI
762 RtlIntegerToUnicodeString(
763 IN ULONG Value,
764 IN ULONG Base OPTIONAL,
765 IN OUT PUNICODE_STRING String)
766 {
767 ANSI_STRING AnsiString;
768 CHAR Buffer[33];
769 NTSTATUS Status;
770
771 Status = RtlIntegerToChar(Value, Base, sizeof(Buffer), Buffer);
772 if (NT_SUCCESS(Status))
773 {
774 AnsiString.Buffer = Buffer;
775 AnsiString.Length = (USHORT)strlen(Buffer);
776 AnsiString.MaximumLength = sizeof(Buffer);
777
778 Status = RtlAnsiStringToUnicodeString(String, &AnsiString, FALSE);
779 }
780
781 return Status;
782 }
783
784 /*
785 * @implemented
786 */
787 NTSTATUS
788 NTAPI
789 RtlInt64ToUnicodeString (
790 IN ULONGLONG Value,
791 IN ULONG Base OPTIONAL,
792 IN OUT PUNICODE_STRING String)
793 {
794 LARGE_INTEGER LargeInt;
795 ANSI_STRING AnsiString;
796 CHAR Buffer[65];
797 NTSTATUS Status;
798
799 LargeInt.QuadPart = Value;
800
801 Status = RtlLargeIntegerToChar(&LargeInt, Base, sizeof(Buffer), Buffer);
802 if (NT_SUCCESS(Status))
803 {
804 AnsiString.Buffer = Buffer;
805 AnsiString.Length = (USHORT)strlen(Buffer);
806 AnsiString.MaximumLength = sizeof(Buffer);
807
808 Status = RtlAnsiStringToUnicodeString(String, &AnsiString, FALSE);
809 }
810
811 return Status;
812 }
813
814 /*
815 * @implemented
816 *
817 * RETURNS
818 * TRUE if String2 contains String1 as a prefix.
819 */
820 BOOLEAN
821 NTAPI
822 RtlPrefixString(
823 PANSI_STRING String1,
824 PANSI_STRING String2,
825 BOOLEAN CaseInsensitive)
826 {
827 PCHAR pc1;
828 PCHAR pc2;
829 ULONG Length;
830
831 if (String2->Length < String1->Length) return FALSE;
832
833 Length = String1->Length;
834 pc1 = String1->Buffer;
835 pc2 = String2->Buffer;
836
837 if (pc1 && pc2)
838 {
839 if (CaseInsensitive)
840 {
841 while (Length--)
842 {
843 if (RtlUpperChar (*pc1++) != RtlUpperChar (*pc2++))
844 return FALSE;
845 }
846 }
847 else
848 {
849 while (Length--)
850 {
851 if (*pc1++ != *pc2++)
852 return FALSE;
853 }
854 }
855
856 return TRUE;
857 }
858
859 return FALSE;
860 }
861
862 /*
863 * @implemented
864 *
865 * RETURNS
866 * TRUE if String2 contains String1 as a prefix.
867 */
868 BOOLEAN
869 NTAPI
870 RtlPrefixUnicodeString(
871 PCUNICODE_STRING String1,
872 PCUNICODE_STRING String2,
873 BOOLEAN CaseInsensitive)
874 {
875 PWCHAR pc1;
876 PWCHAR pc2;
877 ULONG Length;
878
879 if (String2->Length < String1->Length)
880 return FALSE;
881
882 Length = String1->Length / 2;
883 pc1 = String1->Buffer;
884 pc2 = String2->Buffer;
885
886 if (pc1 && pc2)
887 {
888 if (CaseInsensitive)
889 {
890 while (Length--)
891 {
892 if (RtlUpcaseUnicodeChar(*pc1++) !=
893 RtlUpcaseUnicodeChar(*pc2++))
894 return FALSE;
895 }
896 }
897 else
898 {
899 while (Length--)
900 {
901 if( *pc1++ != *pc2++ )
902 return FALSE;
903 }
904 }
905
906 return TRUE;
907 }
908
909 return FALSE;
910 }
911 /*
912 * @implemented
913 */
914 NTSTATUS
915 NTAPI
916 RtlUnicodeStringToInteger(
917 const UNICODE_STRING *str, /* [I] Unicode string to be converted */
918 ULONG base, /* [I] Number base for conversion (allowed 0, 2, 8, 10 or 16) */
919 ULONG *value) /* [O] Destination for the converted value */
920 {
921 LPWSTR lpwstr = str->Buffer;
922 USHORT CharsRemaining = str->Length / sizeof(WCHAR);
923 WCHAR wchCurrent;
924 int digit;
925 ULONG RunningTotal = 0;
926 char bMinus = 0;
927
928 while (CharsRemaining >= 1 && *lpwstr <= ' ')
929 {
930 lpwstr++;
931 CharsRemaining--;
932 }
933
934 if (CharsRemaining >= 1)
935 {
936 if (*lpwstr == '+')
937 {
938 lpwstr++;
939 CharsRemaining--;
940 }
941 else if (*lpwstr == '-')
942 {
943 bMinus = 1;
944 lpwstr++;
945 CharsRemaining--;
946 }
947 }
948
949 if (base == 0)
950 {
951 base = 10;
952
953 if (CharsRemaining >= 2 && lpwstr[0] == '0')
954 {
955 if (lpwstr[1] == 'b')
956 {
957 lpwstr += 2;
958 CharsRemaining -= 2;
959 base = 2;
960 }
961 else if (lpwstr[1] == 'o')
962 {
963 lpwstr += 2;
964 CharsRemaining -= 2;
965 base = 8;
966 }
967 else if (lpwstr[1] == 'x')
968 {
969 lpwstr += 2;
970 CharsRemaining -= 2;
971 base = 16;
972 }
973 }
974 }
975 else if (base != 2 && base != 8 && base != 10 && base != 16)
976 {
977 return STATUS_INVALID_PARAMETER;
978 }
979
980 if (value == NULL)
981 {
982 return STATUS_ACCESS_VIOLATION;
983 }
984
985 while (CharsRemaining >= 1)
986 {
987 wchCurrent = *lpwstr;
988
989 if (wchCurrent >= '0' && wchCurrent <= '9')
990 {
991 digit = wchCurrent - '0';
992 }
993 else if (wchCurrent >= 'A' && wchCurrent <= 'Z')
994 {
995 digit = wchCurrent - 'A' + 10;
996 }
997 else if (wchCurrent >= 'a' && wchCurrent <= 'z')
998 {
999 digit = wchCurrent - 'a' + 10;
1000 }
1001 else
1002 {
1003 digit = -1;
1004 }
1005
1006 if (digit < 0 || (ULONG)digit >= base) break;
1007
1008 RunningTotal = RunningTotal * base + digit;
1009 lpwstr++;
1010 CharsRemaining--;
1011 }
1012
1013 *value = bMinus ? (0 - RunningTotal) : RunningTotal;
1014 return STATUS_SUCCESS;
1015 }
1016
1017 /*
1018 * @implemented
1019 *
1020 * RETURNS
1021 * Bytes necessary for the conversion including nullterm.
1022 */
1023 ULONG
1024 NTAPI
1025 RtlxUnicodeStringToOemSize(IN PCUNICODE_STRING UnicodeString)
1026 {
1027 ULONG Size;
1028
1029 /* Convert the Unicode String to Mb Size */
1030 RtlUnicodeToMultiByteSize(&Size,
1031 UnicodeString->Buffer,
1032 UnicodeString->Length);
1033
1034 /* Return the size + the null char */
1035 return (Size + sizeof(CHAR));
1036 }
1037
1038 /*
1039 * @implemented
1040 *
1041 * NOTES
1042 * This function always writes a terminating '\0'.
1043 * It performs a partial copy if ansi is too small.
1044 */
1045 NTSTATUS
1046 NTAPI
1047 RtlUnicodeStringToAnsiString(
1048 IN OUT PANSI_STRING AnsiDest,
1049 IN PCUNICODE_STRING UniSource,
1050 IN BOOLEAN AllocateDestinationString)
1051 {
1052 NTSTATUS Status = STATUS_SUCCESS;
1053 NTSTATUS RealStatus;
1054 ULONG Length;
1055 ULONG Index;
1056
1057 PAGED_CODE_RTL();
1058
1059 ASSERT(!(UniSource->Length & 1));
1060
1061 if (NlsMbCodePageTag == FALSE)
1062 {
1063 Length = (UniSource->Length + sizeof(WCHAR)) / sizeof(WCHAR);
1064 }
1065 else
1066 {
1067 Length = RtlxUnicodeStringToAnsiSize(UniSource);
1068 }
1069
1070 if (Length > MAXUSHORT) return STATUS_INVALID_PARAMETER_2;
1071
1072 AnsiDest->Length = (USHORT)Length - sizeof(CHAR);
1073
1074 if (AllocateDestinationString)
1075 {
1076 AnsiDest->Buffer = RtlpAllocateStringMemory(Length, TAG_ASTR);
1077 AnsiDest->MaximumLength = (USHORT)Length;
1078
1079 if (!AnsiDest->Buffer) return STATUS_NO_MEMORY;
1080 }
1081 else if (AnsiDest->Length >= AnsiDest->MaximumLength)
1082 {
1083 if (!AnsiDest->MaximumLength) return STATUS_BUFFER_OVERFLOW;
1084
1085 Status = STATUS_BUFFER_OVERFLOW;
1086 AnsiDest->Length = AnsiDest->MaximumLength - 1;
1087 }
1088
1089 RealStatus = RtlUnicodeToMultiByteN(AnsiDest->Buffer,
1090 AnsiDest->Length,
1091 &Index,
1092 UniSource->Buffer,
1093 UniSource->Length);
1094
1095 if (!NT_SUCCESS(RealStatus) && AllocateDestinationString)
1096 {
1097 RtlpFreeStringMemory(AnsiDest->Buffer, TAG_ASTR);
1098 return RealStatus;
1099 }
1100
1101 AnsiDest->Buffer[Index] = ANSI_NULL;
1102 return Status;
1103 }
1104
1105 /*
1106 * @implemented
1107 *
1108 * NOTES
1109 * This function always writes a terminating '\0'.
1110 * Does NOT perform a partial copy if unicode is too small!
1111 */
1112 NTSTATUS
1113 NTAPI
1114 RtlOemStringToUnicodeString(
1115 IN OUT PUNICODE_STRING UniDest,
1116 IN PCOEM_STRING OemSource,
1117 IN BOOLEAN AllocateDestinationString)
1118 {
1119 NTSTATUS Status;
1120 ULONG Length;
1121 ULONG Index;
1122
1123 PAGED_CODE_RTL();
1124
1125 Length = RtlOemStringToUnicodeSize(OemSource);
1126
1127 if (Length > MAXUSHORT) return STATUS_INVALID_PARAMETER_2;
1128
1129 UniDest->Length = (USHORT)Length - sizeof(WCHAR);
1130
1131 if (AllocateDestinationString)
1132 {
1133 UniDest->Buffer = RtlpAllocateStringMemory(Length, TAG_USTR);
1134 UniDest->MaximumLength = (USHORT)Length;
1135
1136 if (!UniDest->Buffer) return STATUS_NO_MEMORY;
1137 }
1138 else if (UniDest->Length >= UniDest->MaximumLength)
1139 {
1140 return STATUS_BUFFER_OVERFLOW;
1141 }
1142
1143 Status = RtlOemToUnicodeN(UniDest->Buffer,
1144 UniDest->Length,
1145 &Index,
1146 OemSource->Buffer,
1147 OemSource->Length);
1148
1149 if (!NT_SUCCESS(Status) && AllocateDestinationString)
1150 {
1151 RtlpFreeStringMemory(UniDest->Buffer, TAG_USTR);
1152 UniDest->Buffer = NULL;
1153 return Status;
1154 }
1155
1156 UniDest->Buffer[Index / sizeof(WCHAR)] = UNICODE_NULL;
1157 return Status;
1158 }
1159
1160 /*
1161 * @implemented
1162 *
1163 * NOTES
1164 * This function always '\0' terminates the string returned.
1165 */
1166 NTSTATUS
1167 NTAPI
1168 RtlUnicodeStringToOemString(
1169 IN OUT POEM_STRING OemDest,
1170 IN PCUNICODE_STRING UniSource,
1171 IN BOOLEAN AllocateDestinationString)
1172 {
1173 NTSTATUS Status;
1174 ULONG Length;
1175 ULONG Index;
1176
1177 PAGED_CODE_RTL();
1178
1179 Length = RtlUnicodeStringToOemSize(UniSource);
1180
1181 if (Length > MAXUSHORT) return STATUS_INVALID_PARAMETER_2;
1182
1183 OemDest->Length = (USHORT)Length - sizeof(CHAR);
1184
1185 if (AllocateDestinationString)
1186 {
1187 OemDest->Buffer = RtlpAllocateStringMemory(Length, TAG_OSTR);
1188 OemDest->MaximumLength = (USHORT)Length;
1189
1190 if (!OemDest->Buffer) return STATUS_NO_MEMORY;
1191 }
1192 else if (OemDest->Length >= OemDest->MaximumLength)
1193 {
1194 return STATUS_BUFFER_OVERFLOW;
1195 }
1196
1197 Status = RtlUnicodeToOemN(OemDest->Buffer,
1198 OemDest->Length,
1199 &Index,
1200 UniSource->Buffer,
1201 UniSource->Length);
1202
1203 if (!NT_SUCCESS(Status) && AllocateDestinationString)
1204 {
1205 RtlpFreeStringMemory(OemDest->Buffer, TAG_OSTR);
1206 OemDest->Buffer = NULL;
1207 return Status;
1208 }
1209
1210 OemDest->Buffer[Index] = ANSI_NULL;
1211 return Status;
1212 }
1213
1214 #define ITU_IMPLEMENTED_TESTS (IS_TEXT_UNICODE_ODD_LENGTH|IS_TEXT_UNICODE_SIGNATURE)
1215
1216 /*
1217 * @implemented
1218 *
1219 * RETURNS
1220 * The length of the string if all tests were passed, 0 otherwise.
1221 */
1222 BOOLEAN
1223 NTAPI
1224 RtlIsTextUnicode( PVOID buf, INT len, INT *pf )
1225 {
1226 static const WCHAR std_control_chars[] = {'\r', '\n', '\t', ' ', 0x3000, 0};
1227 static const WCHAR byterev_control_chars[] = {0x0d00, 0x0a00, 0x0900, 0x2000, 0};
1228 const WCHAR *s = buf;
1229 int i;
1230 unsigned int flags = MAXULONG, out_flags = 0;
1231
1232 if (len < sizeof(WCHAR))
1233 {
1234 /* FIXME: MSDN documents IS_TEXT_UNICODE_BUFFER_TOO_SMALL but there is no such thing... */
1235 if (pf) *pf = 0;
1236
1237 return FALSE;
1238 }
1239
1240 if (pf)
1241 flags = *pf;
1242
1243 /*
1244 * Apply various tests to the text string. According to the
1245 * docs, each test "passed" sets the corresponding flag in
1246 * the output flags. But some of the tests are mutually
1247 * exclusive, so I don't see how you could pass all tests ...
1248 */
1249
1250 /* Check for an odd length ... pass if even. */
1251 if (len & 1) out_flags |= IS_TEXT_UNICODE_ODD_LENGTH;
1252
1253 if (((char *)buf)[len - 1] == 0)
1254 len--; /* Windows seems to do something like that to avoid e.g. false IS_TEXT_UNICODE_NULL_BYTES */
1255
1256 len /= sizeof(WCHAR);
1257
1258 /* Windows only checks the first 256 characters */
1259 if (len > 256) len = 256;
1260
1261 /* Check for the special byte order unicode marks. */
1262 if (*s == 0xFEFF) out_flags |= IS_TEXT_UNICODE_SIGNATURE;
1263 if (*s == 0xFFFE) out_flags |= IS_TEXT_UNICODE_REVERSE_SIGNATURE;
1264
1265 /* apply some statistical analysis */
1266 if (flags & IS_TEXT_UNICODE_STATISTICS)
1267 {
1268 int stats = 0;
1269
1270 /* FIXME: checks only for ASCII characters in the unicode stream */
1271 for (i = 0; i < len; i++)
1272 {
1273 if (s[i] <= 255) stats++;
1274 }
1275
1276 if (stats > len / 2)
1277 out_flags |= IS_TEXT_UNICODE_STATISTICS;
1278 }
1279
1280 /* Check for unicode NULL chars */
1281 if (flags & IS_TEXT_UNICODE_NULL_BYTES)
1282 {
1283 for (i = 0; i < len; i++)
1284 {
1285 if (!(s[i] & 0xff) || !(s[i] >> 8))
1286 {
1287 out_flags |= IS_TEXT_UNICODE_NULL_BYTES;
1288 break;
1289 }
1290 }
1291 }
1292
1293 if (flags & IS_TEXT_UNICODE_CONTROLS)
1294 {
1295 for (i = 0; i < len; i++)
1296 {
1297 if (strchrW(std_control_chars, s[i]))
1298 {
1299 out_flags |= IS_TEXT_UNICODE_CONTROLS;
1300 break;
1301 }
1302 }
1303 }
1304
1305 if (flags & IS_TEXT_UNICODE_REVERSE_CONTROLS)
1306 {
1307 for (i = 0; i < len; i++)
1308 {
1309 if (strchrW(byterev_control_chars, s[i]))
1310 {
1311 out_flags |= IS_TEXT_UNICODE_REVERSE_CONTROLS;
1312 break;
1313 }
1314 }
1315 }
1316
1317 if (pf)
1318 {
1319 out_flags &= *pf;
1320 *pf = out_flags;
1321 }
1322
1323 /* check for flags that indicate it's definitely not valid Unicode */
1324 if (out_flags & (IS_TEXT_UNICODE_REVERSE_MASK | IS_TEXT_UNICODE_NOT_UNICODE_MASK)) return FALSE;
1325
1326 /* now check for invalid ASCII, and assume Unicode if so */
1327 if (out_flags & IS_TEXT_UNICODE_NOT_ASCII_MASK) return TRUE;
1328
1329 /* now check for Unicode flags */
1330 if (out_flags & IS_TEXT_UNICODE_UNICODE_MASK) return TRUE;
1331
1332 /* no flags set */
1333 return FALSE;
1334 }
1335
1336
1337 /*
1338 * @implemented
1339 *
1340 * NOTES
1341 * Same as RtlOemStringToUnicodeString but doesn't write terminating null
1342 * A partial copy is NOT performed if the dest buffer is too small!
1343 */
1344 NTSTATUS
1345 NTAPI
1346 RtlOemStringToCountedUnicodeString(
1347 IN OUT PUNICODE_STRING UniDest,
1348 IN PCOEM_STRING OemSource,
1349 IN BOOLEAN AllocateDestinationString)
1350 {
1351 NTSTATUS Status;
1352 ULONG Length;
1353 ULONG Index;
1354
1355 PAGED_CODE_RTL();
1356
1357 /* Calculate size of the string */
1358 Length = RtlOemStringToCountedUnicodeSize(OemSource);
1359
1360 /* If it's 0 then zero out dest string and return */
1361 if (!Length)
1362 {
1363 RtlZeroMemory(UniDest, sizeof(UNICODE_STRING));
1364 return STATUS_SUCCESS;
1365 }
1366
1367 /* Check if length is a sane value */
1368 if (Length > MAXUSHORT) return STATUS_INVALID_PARAMETER_2;
1369
1370 /* Store it in dest string */
1371 UniDest->Length = (USHORT)Length;
1372
1373 /* If we're asked to alloc the string - do so */
1374 if (AllocateDestinationString)
1375 {
1376 UniDest->Buffer = RtlpAllocateStringMemory(Length, TAG_USTR);
1377 UniDest->MaximumLength = (USHORT)Length;
1378
1379 if (!UniDest->Buffer) return STATUS_NO_MEMORY;
1380 }
1381 else if (UniDest->Length > UniDest->MaximumLength)
1382 {
1383 return STATUS_BUFFER_OVERFLOW;
1384 }
1385
1386 /* Do the conversion */
1387 Status = RtlOemToUnicodeN(UniDest->Buffer,
1388 UniDest->Length,
1389 &Index,
1390 OemSource->Buffer,
1391 OemSource->Length);
1392
1393 if (!NT_SUCCESS(Status) && AllocateDestinationString)
1394 {
1395 /* Conversion failed, free dest string and return status code */
1396 RtlpFreeStringMemory(UniDest->Buffer, TAG_USTR);
1397 UniDest->Buffer = NULL;
1398 return Status;
1399 }
1400
1401 return STATUS_SUCCESS;
1402 }
1403
1404 /*
1405 * @implemented
1406 *
1407 * RETURNS
1408 * TRUE if the names are equal, FALSE if not
1409 *
1410 * NOTES
1411 * The comparison is case insensitive.
1412 */
1413 BOOLEAN
1414 NTAPI
1415 RtlEqualComputerName(
1416 IN PUNICODE_STRING ComputerName1,
1417 IN PUNICODE_STRING ComputerName2)
1418 {
1419 OEM_STRING OemString1;
1420 OEM_STRING OemString2;
1421 BOOLEAN Result = FALSE;
1422
1423 if (NT_SUCCESS(RtlUpcaseUnicodeStringToOemString(&OemString1,
1424 ComputerName1,
1425 TRUE)))
1426 {
1427 if (NT_SUCCESS(RtlUpcaseUnicodeStringToOemString(&OemString2,
1428 ComputerName2,
1429 TRUE)))
1430 {
1431 Result = RtlEqualString(&OemString1, &OemString2, FALSE);
1432 RtlFreeOemString(&OemString2);
1433 }
1434
1435 RtlFreeOemString(&OemString1);
1436 }
1437
1438 return Result;
1439 }
1440
1441 /*
1442 * @implemented
1443 *
1444 * RETURNS
1445 * TRUE if the names are equal, FALSE if not
1446 *
1447 * NOTES
1448 * The comparison is case insensitive.
1449 */
1450 BOOLEAN
1451 NTAPI
1452 RtlEqualDomainName (
1453 IN PUNICODE_STRING DomainName1,
1454 IN PUNICODE_STRING DomainName2)
1455 {
1456 return RtlEqualComputerName(DomainName1, DomainName2);
1457 }
1458
1459 /*
1460 * @implemented
1461 *
1462 * RIPPED FROM WINE's ntdll\rtlstr.c rev 1.45
1463 *
1464 * Convert a string representation of a GUID into a GUID.
1465 *
1466 * PARAMS
1467 * str [I] String representation in the format "{XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX}"
1468 * guid [O] Destination for the converted GUID
1469 *
1470 * RETURNS
1471 * Success: STATUS_SUCCESS. guid contains the converted value.
1472 * Failure: STATUS_INVALID_PARAMETER, if str is not in the expected format.
1473 *
1474 * SEE ALSO
1475 * See RtlStringFromGUID.
1476 */
1477 NTSTATUS
1478 NTAPI
1479 RtlGUIDFromString(
1480 IN UNICODE_STRING *str,
1481 OUT GUID* guid)
1482 {
1483 int i = 0;
1484 const WCHAR *lpszCLSID = str->Buffer;
1485 BYTE* lpOut = (BYTE*)guid;
1486
1487 //TRACE("(%s,%p)\n", debugstr_us(str), guid);
1488
1489 /* Convert string: {XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX}
1490 * to memory: DWORD... WORD WORD BYTES............
1491 */
1492 while (i <= 37)
1493 {
1494 switch (i)
1495 {
1496 case 0:
1497 if (*lpszCLSID != '{')
1498 return STATUS_INVALID_PARAMETER;
1499 break;
1500
1501 case 9:
1502 case 14:
1503 case 19:
1504 case 24:
1505 if (*lpszCLSID != '-')
1506 return STATUS_INVALID_PARAMETER;
1507 break;
1508
1509 case 37:
1510 if (*lpszCLSID != '}')
1511 return STATUS_INVALID_PARAMETER;
1512
1513 break;
1514
1515 default:
1516 {
1517 WCHAR ch = *lpszCLSID, ch2 = lpszCLSID[1];
1518 unsigned char byte;
1519
1520 /* Read two hex digits as a byte value */
1521 if (ch >= '0' && ch <= '9')
1522 ch = ch - '0';
1523 else if (ch >= 'a' && ch <= 'f')
1524 ch = ch - 'a' + 10;
1525 else if (ch >= 'A' && ch <= 'F')
1526 ch = ch - 'A' + 10;
1527 else
1528 return STATUS_INVALID_PARAMETER;
1529
1530 if (ch2 >= '0' && ch2 <= '9')
1531 ch2 = ch2 - '0';
1532 else if (ch2 >= 'a' && ch2 <= 'f')
1533 ch2 = ch2 - 'a' + 10;
1534 else if (ch2 >= 'A' && ch2 <= 'F')
1535 ch2 = ch2 - 'A' + 10;
1536 else
1537 return STATUS_INVALID_PARAMETER;
1538
1539 byte = ch << 4 | ch2;
1540
1541 switch (i)
1542 {
1543 #ifndef WORDS_BIGENDIAN
1544 /* For Big Endian machines, we store the data such that the
1545 * dword/word members can be read as DWORDS and WORDS correctly. */
1546 /* Dword */
1547 case 1:
1548 lpOut[3] = byte;
1549 break;
1550 case 3:
1551 lpOut[2] = byte;
1552 break;
1553 case 5:
1554 lpOut[1] = byte;
1555 break;
1556 case 7:
1557 lpOut[0] = byte;
1558 lpOut += 4;
1559 break;
1560 /* Word */
1561 case 10:
1562 case 15:
1563 lpOut[1] = byte;
1564 break;
1565 case 12:
1566 case 17:
1567 lpOut[0] = byte;
1568 lpOut += 2;
1569 break;
1570 #endif
1571 /* Byte */
1572 default:
1573 lpOut[0] = byte;
1574 lpOut++;
1575 break;
1576 }
1577
1578 lpszCLSID++; /* Skip 2nd character of byte */
1579 i++;
1580 }
1581 }
1582
1583 lpszCLSID++;
1584 i++;
1585 }
1586
1587 return STATUS_SUCCESS;
1588 }
1589
1590 /*
1591 * @implemented
1592 */
1593 VOID
1594 NTAPI
1595 RtlEraseUnicodeString(
1596 IN PUNICODE_STRING String)
1597 {
1598 if (String->Buffer && String->MaximumLength)
1599 {
1600 RtlZeroMemory(String->Buffer, String->MaximumLength);
1601 String->Length = 0;
1602 }
1603 }
1604
1605 /*
1606 * @implemented
1607 */
1608 NTSTATUS
1609 NTAPI
1610 RtlHashUnicodeString(
1611 IN CONST UNICODE_STRING *String,
1612 IN BOOLEAN CaseInSensitive,
1613 IN ULONG HashAlgorithm,
1614 OUT PULONG HashValue)
1615 {
1616 if (String != NULL && HashValue != NULL)
1617 {
1618 switch (HashAlgorithm)
1619 {
1620 case HASH_STRING_ALGORITHM_DEFAULT:
1621 case HASH_STRING_ALGORITHM_X65599:
1622 {
1623 WCHAR *c, *end;
1624
1625 *HashValue = 0;
1626 end = String->Buffer + (String->Length / sizeof(WCHAR));
1627
1628 if (CaseInSensitive)
1629 {
1630 for (c = String->Buffer; c != end; c++)
1631 {
1632 /* only uppercase characters if they are 'a' ... 'z'! */
1633 *HashValue = ((65599 * (*HashValue)) +
1634 (ULONG)(((*c) >= L'a' && (*c) <= L'z') ?
1635 (*c) - L'a' + L'A' : (*c)));
1636 }
1637 }
1638 else
1639 {
1640 for (c = String->Buffer; c != end; c++)
1641 {
1642 *HashValue = ((65599 * (*HashValue)) + (ULONG)(*c));
1643 }
1644 }
1645
1646 return STATUS_SUCCESS;
1647 }
1648 }
1649 }
1650
1651 return STATUS_INVALID_PARAMETER;
1652 }
1653
1654 /*
1655 * @implemented
1656 *
1657 * NOTES
1658 * Same as RtlUnicodeStringToOemString but doesn't write terminating null
1659 * Does a partial copy if the dest buffer is too small
1660 */
1661 NTSTATUS
1662 NTAPI
1663 RtlUnicodeStringToCountedOemString(
1664 IN OUT POEM_STRING OemDest,
1665 IN PUNICODE_STRING UniSource,
1666 IN BOOLEAN AllocateDestinationString)
1667 {
1668 NTSTATUS Status;
1669 ULONG Length;
1670 ULONG Index;
1671
1672 PAGED_CODE_RTL();
1673
1674 /* Calculate size of the string */
1675 Length = RtlUnicodeStringToCountedOemSize(UniSource);
1676
1677 /* If it's 0 then zero out dest string and return */
1678 if (!Length)
1679 {
1680 RtlZeroMemory(OemDest, sizeof(OEM_STRING));
1681 return STATUS_SUCCESS;
1682 }
1683
1684 /* Check if length is a sane value */
1685 if (Length > MAXUSHORT) return STATUS_INVALID_PARAMETER_2;
1686
1687 /* Store it in dest string */
1688 OemDest->Length = (USHORT)Length;
1689
1690 /* If we're asked to alloc the string - do so */
1691 if (AllocateDestinationString)
1692 {
1693 OemDest->Buffer = RtlpAllocateStringMemory(Length, TAG_OSTR);
1694 OemDest->MaximumLength = (USHORT)Length;
1695 if (!OemDest->Buffer) return STATUS_NO_MEMORY;
1696 }
1697 else if (OemDest->Length > OemDest->MaximumLength)
1698 {
1699 return STATUS_BUFFER_OVERFLOW;
1700 }
1701
1702 /* Do the conversion */
1703 Status = RtlUnicodeToOemN(OemDest->Buffer,
1704 OemDest->Length,
1705 &Index,
1706 UniSource->Buffer,
1707 UniSource->Length);
1708
1709 /* Check for unmapped character */
1710 if (NT_SUCCESS(Status) && !RtlpDidUnicodeToOemWork(UniSource, OemDest))
1711 Status = STATUS_UNMAPPABLE_CHARACTER;
1712
1713 if (!NT_SUCCESS(Status) && AllocateDestinationString)
1714 {
1715 /* Conversion failed, free dest string and return status code */
1716 RtlpFreeStringMemory(OemDest->Buffer, TAG_OSTR);
1717 OemDest->Buffer = NULL;
1718 return Status;
1719 }
1720
1721 return Status;
1722 }
1723
1724 /*
1725 * @implemented
1726 */
1727 NTSTATUS
1728 NTAPI
1729 RtlLargeIntegerToChar(
1730 IN PLARGE_INTEGER Value,
1731 IN ULONG Base,
1732 IN ULONG Length,
1733 IN OUT PCHAR String)
1734 {
1735 ULONGLONG Val = Value->QuadPart;
1736 NTSTATUS Status = STATUS_SUCCESS;
1737 CHAR Buffer[65];
1738 CHAR Digit;
1739 SIZE_T Len;
1740 PCHAR Pos;
1741
1742 if (Base == 0) Base = 10;
1743
1744 if ((Base != 2) && (Base != 8) && (Base != 10) && (Base != 16))
1745 {
1746 return STATUS_INVALID_PARAMETER;
1747 }
1748
1749 Pos = &Buffer[64];
1750 *Pos = '\0';
1751
1752 do
1753 {
1754 Pos--;
1755 Digit = (CHAR)(Val % Base);
1756 Val = Val / Base;
1757
1758 if (Digit < 10)
1759 *Pos = '0' + Digit;
1760 else
1761 *Pos = 'A' + Digit - 10;
1762 }
1763 while (Val != 0L);
1764
1765 Len = &Buffer[64] - Pos;
1766
1767 if (Len > Length)
1768 return STATUS_BUFFER_OVERFLOW;
1769
1770 #if 1 /* It needs to be removed, when will probably use SEH in rtl */
1771
1772 if (String == NULL)
1773 {
1774 return STATUS_ACCESS_VIOLATION;
1775 }
1776
1777 #endif
1778
1779 #if 0
1780 _SEH2_TRY
1781 {
1782 #endif
1783
1784 if (Len == Length)
1785 RtlCopyMemory(String, Pos, Len);
1786 else
1787 RtlCopyMemory(String, Pos, Len + 1);
1788
1789 #if 0
1790 }
1791 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
1792 {
1793 /* Get the error code */
1794 Status = _SEH2_GetExceptionCode();
1795 }
1796 _SEH2_END;
1797 #endif
1798
1799 return Status;
1800 }
1801
1802 /*
1803 * @implemented
1804 *
1805 * NOTES
1806 * dest is never '\0' terminated because it may be equal to src, and src
1807 * might not be '\0' terminated. dest->Length is only set upon success.
1808 */
1809 NTSTATUS
1810 NTAPI
1811 RtlUpcaseUnicodeString(
1812 IN OUT PUNICODE_STRING UniDest,
1813 IN PCUNICODE_STRING UniSource,
1814 IN BOOLEAN AllocateDestinationString)
1815 {
1816 ULONG i, j;
1817
1818 PAGED_CODE_RTL();
1819
1820 if (AllocateDestinationString == TRUE)
1821 {
1822 UniDest->MaximumLength = UniSource->Length;
1823 UniDest->Buffer = RtlpAllocateStringMemory(UniDest->MaximumLength, TAG_USTR);
1824 if (UniDest->Buffer == NULL) return STATUS_NO_MEMORY;
1825 }
1826 else if (UniSource->Length > UniDest->MaximumLength)
1827 {
1828 return STATUS_BUFFER_OVERFLOW;
1829 }
1830
1831 j = UniSource->Length / sizeof(WCHAR);
1832
1833 for (i = 0; i < j; i++)
1834 {
1835 UniDest->Buffer[i] = RtlUpcaseUnicodeChar(UniSource->Buffer[i]);
1836 }
1837
1838 UniDest->Length = UniSource->Length;
1839 return STATUS_SUCCESS;
1840 }
1841
1842 /*
1843 * @implemented
1844 *
1845 * NOTES
1846 * This function always writes a terminating '\0'.
1847 * It performs a partial copy if ansi is too small.
1848 */
1849 NTSTATUS
1850 NTAPI
1851 RtlUpcaseUnicodeStringToAnsiString(
1852 IN OUT PANSI_STRING AnsiDest,
1853 IN PUNICODE_STRING UniSource,
1854 IN BOOLEAN AllocateDestinationString)
1855 {
1856 NTSTATUS Status;
1857 ULONG Length;
1858 ULONG Index;
1859 PAGED_CODE_RTL();
1860
1861 Length = RtlUnicodeStringToAnsiSize(UniSource);
1862 if (Length > MAXUSHORT) return STATUS_INVALID_PARAMETER_2;
1863
1864 AnsiDest->Length = (USHORT)Length - sizeof(CHAR);
1865
1866 if (AllocateDestinationString)
1867 {
1868 AnsiDest->Buffer = RtlpAllocateStringMemory(Length, TAG_ASTR);
1869 AnsiDest->MaximumLength = (USHORT)Length;
1870 if (!AnsiDest->Buffer) return STATUS_NO_MEMORY;
1871 }
1872 else if (AnsiDest->Length >= AnsiDest->MaximumLength)
1873 {
1874 if (!AnsiDest->MaximumLength) return STATUS_BUFFER_OVERFLOW;
1875 }
1876
1877 Status = RtlUpcaseUnicodeToMultiByteN(AnsiDest->Buffer,
1878 AnsiDest->Length,
1879 &Index,
1880 UniSource->Buffer,
1881 UniSource->Length);
1882
1883 if (!NT_SUCCESS(Status) && AllocateDestinationString)
1884 {
1885 RtlpFreeStringMemory(AnsiDest->Buffer, TAG_ASTR);
1886 AnsiDest->Buffer = NULL;
1887 return Status;
1888 }
1889
1890 AnsiDest->Buffer[Index] = ANSI_NULL;
1891 return Status;
1892 }
1893
1894 /*
1895 * @implemented
1896 *
1897 * NOTES
1898 * This function always writes a terminating '\0'.
1899 * It performs a partial copy if ansi is too small.
1900 */
1901 NTSTATUS
1902 NTAPI
1903 RtlUpcaseUnicodeStringToCountedOemString(
1904 IN OUT POEM_STRING OemDest,
1905 IN PCUNICODE_STRING UniSource,
1906 IN BOOLEAN AllocateDestinationString)
1907 {
1908 NTSTATUS Status;
1909 ULONG Length;
1910 ULONG Index;
1911 PAGED_CODE_RTL();
1912
1913 Length = RtlUnicodeStringToCountedOemSize(UniSource);
1914
1915 if (!Length)
1916 {
1917 RtlZeroMemory(OemDest, sizeof(OEM_STRING));
1918 }
1919
1920 if (Length > MAXUSHORT) return STATUS_INVALID_PARAMETER_2;
1921
1922 OemDest->Length = (USHORT)Length;
1923
1924 if (AllocateDestinationString)
1925 {
1926 OemDest->Buffer = RtlpAllocateStringMemory(Length, TAG_OSTR);
1927 OemDest->MaximumLength = (USHORT)Length;
1928 if (!OemDest->Buffer) return STATUS_NO_MEMORY;
1929 }
1930 else if (OemDest->Length > OemDest->MaximumLength)
1931 {
1932 return STATUS_BUFFER_OVERFLOW;
1933 }
1934
1935 Status = RtlUpcaseUnicodeToOemN(OemDest->Buffer,
1936 OemDest->Length,
1937 &Index,
1938 UniSource->Buffer,
1939 UniSource->Length);
1940
1941 /* Check for unmapped characters */
1942 if (NT_SUCCESS(Status) && !RtlpDidUnicodeToOemWork(UniSource, OemDest))
1943 Status = STATUS_UNMAPPABLE_CHARACTER;
1944
1945 if (!NT_SUCCESS(Status) && AllocateDestinationString)
1946 {
1947 RtlpFreeStringMemory(OemDest->Buffer, TAG_OSTR);
1948 OemDest->Buffer = NULL;
1949 return Status;
1950 }
1951
1952 return Status;
1953 }
1954
1955 /*
1956 * @implemented
1957 * NOTES
1958 * Oem string is allways nullterminated
1959 * It performs a partial copy if oem is too small.
1960 */
1961 NTSTATUS
1962 NTAPI
1963 RtlUpcaseUnicodeStringToOemString (
1964 IN OUT POEM_STRING OemDest,
1965 IN PCUNICODE_STRING UniSource,
1966 IN BOOLEAN AllocateDestinationString)
1967 {
1968 NTSTATUS Status;
1969 ULONG Length;
1970 ULONG Index;
1971 PAGED_CODE_RTL();
1972
1973 Length = RtlUnicodeStringToOemSize(UniSource);
1974 if (Length > MAXUSHORT) return STATUS_INVALID_PARAMETER_2;
1975
1976 OemDest->Length = (USHORT)Length - sizeof(CHAR);
1977
1978 if (AllocateDestinationString)
1979 {
1980 OemDest->Buffer = RtlpAllocateStringMemory(Length, TAG_OSTR);
1981 OemDest->MaximumLength = (USHORT)Length;
1982 if (!OemDest->Buffer) return STATUS_NO_MEMORY;
1983 }
1984 else if (OemDest->Length >= OemDest->MaximumLength)
1985 {
1986 return STATUS_BUFFER_OVERFLOW;
1987 }
1988
1989 Status = RtlUpcaseUnicodeToOemN(OemDest->Buffer,
1990 OemDest->Length,
1991 &Index,
1992 UniSource->Buffer,
1993 UniSource->Length);
1994
1995 /* Check for unmapped characters */
1996 if (NT_SUCCESS(Status) && !RtlpDidUnicodeToOemWork(UniSource, OemDest))
1997 Status = STATUS_UNMAPPABLE_CHARACTER;
1998
1999 if (!NT_SUCCESS(Status) && AllocateDestinationString)
2000 {
2001 RtlpFreeStringMemory(OemDest->Buffer, TAG_OSTR);
2002 OemDest->Buffer = NULL;
2003 return Status;
2004 }
2005
2006 OemDest->Buffer[Index] = ANSI_NULL;
2007 return Status;
2008 }
2009
2010 /*
2011 * @implemented
2012 *
2013 * RETURNS
2014 * Bytes calculated including nullterm
2015 */
2016 ULONG
2017 NTAPI
2018 RtlxOemStringToUnicodeSize(IN PCOEM_STRING OemString)
2019 {
2020 ULONG Size;
2021
2022 /* Convert the Mb String to Unicode Size */
2023 RtlMultiByteToUnicodeSize(&Size,
2024 OemString->Buffer,
2025 OemString->Length);
2026
2027 /* Return the size + null-char */
2028 return (Size + sizeof(WCHAR));
2029 }
2030
2031 /*
2032 * @implemented
2033 */
2034 NTSTATUS
2035 NTAPI
2036 RtlStringFromGUID (IN REFGUID Guid,
2037 OUT PUNICODE_STRING GuidString)
2038 {
2039 /* Setup the string */
2040 GuidString->Length = 38 * sizeof(WCHAR);
2041 GuidString->MaximumLength = GuidString->Length + sizeof(UNICODE_NULL);
2042 GuidString->Buffer = RtlpAllocateStringMemory(GuidString->MaximumLength,
2043 TAG_USTR);
2044 if (!GuidString->Buffer) return STATUS_NO_MEMORY;
2045
2046 /* Now format the GUID */
2047 swprintf(GuidString->Buffer,
2048 L"{%08lx-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x}",
2049 Guid->Data1,
2050 Guid->Data2,
2051 Guid->Data3,
2052 Guid->Data4[0],
2053 Guid->Data4[1],
2054 Guid->Data4[2],
2055 Guid->Data4[3],
2056 Guid->Data4[4],
2057 Guid->Data4[5],
2058 Guid->Data4[6],
2059 Guid->Data4[7]);
2060 return STATUS_SUCCESS;
2061 }
2062
2063 /*
2064 * @implemented
2065 *
2066 * RETURNS
2067 * Bytes calculated including nullterm
2068 */
2069 ULONG
2070 NTAPI
2071 RtlxUnicodeStringToAnsiSize(IN PCUNICODE_STRING UnicodeString)
2072 {
2073 ULONG Size;
2074 PAGED_CODE_RTL();
2075
2076 ASSERT(!(UnicodeString->Length & 1));
2077
2078 /* Convert the Unicode String to Mb Size */
2079 RtlUnicodeToMultiByteSize(&Size,
2080 UnicodeString->Buffer,
2081 UnicodeString->Length);
2082
2083 /* Return the size + null-char */
2084 return (Size + sizeof(CHAR));
2085 }
2086
2087 /*
2088 * @implemented
2089 */
2090 LONG
2091 NTAPI
2092 RtlCompareUnicodeString(
2093 IN PCUNICODE_STRING s1,
2094 IN PCUNICODE_STRING s2,
2095 IN BOOLEAN CaseInsensitive)
2096 {
2097 unsigned int len;
2098 LONG ret = 0;
2099 LPCWSTR p1, p2;
2100
2101 len = min(s1->Length, s2->Length) / sizeof(WCHAR);
2102 p1 = s1->Buffer;
2103 p2 = s2->Buffer;
2104
2105 if (CaseInsensitive)
2106 {
2107 while (!ret && len--) ret = RtlUpcaseUnicodeChar(*p1++) - RtlUpcaseUnicodeChar(*p2++);
2108 }
2109 else
2110 {
2111 while (!ret && len--) ret = *p1++ - *p2++;
2112 }
2113
2114 if (!ret) ret = s1->Length - s2->Length;
2115
2116 return ret;
2117 }
2118
2119 /*
2120 * @implemented
2121 */
2122 VOID
2123 NTAPI
2124 RtlCopyString(
2125 IN OUT PSTRING DestinationString,
2126 IN PSTRING SourceString OPTIONAL)
2127 {
2128 ULONG SourceLength;
2129 PCHAR p1, p2;
2130
2131 /* Check if there was no source given */
2132 if(!SourceString)
2133 {
2134 /* Simply return an empty string */
2135 DestinationString->Length = 0;
2136 }
2137 else
2138 {
2139 /* Choose the smallest length */
2140 SourceLength = min(DestinationString->MaximumLength,
2141 SourceString->Length);
2142
2143 /* Set it */
2144 DestinationString->Length = (USHORT)SourceLength;
2145
2146 /* Save the pointers to each buffer */
2147 p1 = DestinationString->Buffer;
2148 p2 = SourceString->Buffer;
2149
2150 /* Loop the buffer */
2151 while (SourceLength)
2152 {
2153 /* Copy the character and move on */
2154 *p1++ = * p2++;
2155 SourceLength--;
2156 }
2157 }
2158 }
2159
2160 /*
2161 * @implemented
2162 */
2163 VOID
2164 NTAPI
2165 RtlCopyUnicodeString(
2166 IN OUT PUNICODE_STRING DestinationString,
2167 IN PCUNICODE_STRING SourceString)
2168 {
2169 ULONG SourceLength;
2170
2171 if(SourceString == NULL)
2172 {
2173 DestinationString->Length = 0;
2174 }
2175 else
2176 {
2177 SourceLength = min(DestinationString->MaximumLength,
2178 SourceString->Length);
2179 DestinationString->Length = (USHORT)SourceLength;
2180
2181 RtlCopyMemory(DestinationString->Buffer,
2182 SourceString->Buffer,
2183 SourceLength);
2184
2185 if (DestinationString->Length < DestinationString->MaximumLength)
2186 {
2187 DestinationString->Buffer[SourceLength / sizeof(WCHAR)] = UNICODE_NULL;
2188 }
2189 }
2190 }
2191
2192 /*
2193 * @implemented
2194 *
2195 * NOTES
2196 * Creates a nullterminated UNICODE_STRING
2197 */
2198 BOOLEAN
2199 NTAPI
2200 RtlCreateUnicodeString(
2201 IN OUT PUNICODE_STRING UniDest,
2202 IN PCWSTR Source)
2203 {
2204 SIZE_T Size;
2205 PAGED_CODE_RTL();
2206
2207 Size = (wcslen(Source) + 1) * sizeof(WCHAR);
2208 if (Size > MAXUSHORT) return FALSE;
2209
2210 UniDest->Buffer = RtlpAllocateStringMemory((ULONG)Size, TAG_USTR);
2211
2212 if (UniDest->Buffer == NULL) return FALSE;
2213
2214 RtlCopyMemory(UniDest->Buffer, Source, Size);
2215 UniDest->MaximumLength = (USHORT)Size;
2216 UniDest->Length = (USHORT)Size - sizeof (WCHAR);
2217
2218 return TRUE;
2219 }
2220
2221 /*
2222 * @implemented
2223 */
2224 BOOLEAN
2225 NTAPI
2226 RtlCreateUnicodeStringFromAsciiz(
2227 OUT PUNICODE_STRING Destination,
2228 IN PCSZ Source)
2229 {
2230 ANSI_STRING AnsiString;
2231 NTSTATUS Status;
2232
2233 RtlInitAnsiString(&AnsiString, Source);
2234
2235 Status = RtlAnsiStringToUnicodeString(Destination,
2236 &AnsiString,
2237 TRUE);
2238
2239 return NT_SUCCESS(Status);
2240 }
2241
2242 /*
2243 * @implemented
2244 *
2245 * NOTES
2246 * Dest is never '\0' terminated because it may be equal to src, and src
2247 * might not be '\0' terminated.
2248 * Dest->Length is only set upon success.
2249 */
2250 NTSTATUS
2251 NTAPI
2252 RtlDowncaseUnicodeString(
2253 IN OUT PUNICODE_STRING UniDest,
2254 IN PCUNICODE_STRING UniSource,
2255 IN BOOLEAN AllocateDestinationString)
2256 {
2257 ULONG i;
2258 ULONG StopGap;
2259 PAGED_CODE_RTL();
2260
2261 if (AllocateDestinationString)
2262 {
2263 UniDest->MaximumLength = UniSource->Length;
2264 UniDest->Buffer = RtlpAllocateStringMemory(UniSource->Length, TAG_USTR);
2265 if (UniDest->Buffer == NULL) return STATUS_NO_MEMORY;
2266 }
2267 else if (UniSource->Length > UniDest->MaximumLength)
2268 {
2269 return STATUS_BUFFER_OVERFLOW;
2270 }
2271
2272 UniDest->Length = UniSource->Length;
2273 StopGap = UniSource->Length / sizeof(WCHAR);
2274
2275 for (i = 0 ; i < StopGap; i++)
2276 {
2277 if (UniSource->Buffer[i] < L'A')
2278 {
2279 UniDest->Buffer[i] = UniSource->Buffer[i];
2280 }
2281 else if (UniSource->Buffer[i] <= L'Z')
2282 {
2283 UniDest->Buffer[i] = (UniSource->Buffer[i] + (L'a' - L'A'));
2284 }
2285 else
2286 {
2287 UniDest->Buffer[i] = RtlDowncaseUnicodeChar(UniSource->Buffer[i]);
2288 }
2289 }
2290
2291 return STATUS_SUCCESS;
2292 }
2293
2294 /*
2295 * @implemented
2296 *
2297 * NOTES
2298 * if src is NULL dest is unchanged.
2299 * dest is '\0' terminated when the MaximumLength allowes it.
2300 * When dest fits exactly in MaximumLength characters the '\0' is ommitted.
2301 */
2302 NTSTATUS
2303 NTAPI
2304 RtlAppendUnicodeToString(IN OUT PUNICODE_STRING Destination,
2305 IN PCWSTR Source)
2306 {
2307 USHORT Length;
2308 PWCHAR DestBuffer;
2309
2310 if (Source)
2311 {
2312 UNICODE_STRING UnicodeSource;
2313
2314 RtlInitUnicodeString(&UnicodeSource, Source);
2315 Length = UnicodeSource.Length;
2316
2317 if (Destination->Length + Length > Destination->MaximumLength)
2318 {
2319 return STATUS_BUFFER_TOO_SMALL;
2320 }
2321
2322 DestBuffer = &Destination->Buffer[Destination->Length / sizeof(WCHAR)];
2323 RtlMoveMemory(DestBuffer, Source, Length);
2324 Destination->Length += Length;
2325
2326 /* append terminating '\0' if enough space */
2327 if(Destination->MaximumLength > Destination->Length)
2328 {
2329 DestBuffer[Length / sizeof(WCHAR)] = UNICODE_NULL;
2330 }
2331 }
2332
2333 return STATUS_SUCCESS;
2334 }
2335
2336 /*
2337 * @implemented
2338 *
2339 * NOTES
2340 * if src is NULL dest is unchanged.
2341 * dest is never '\0' terminated.
2342 */
2343 NTSTATUS
2344 NTAPI
2345 RtlAppendAsciizToString(
2346 IN OUT PSTRING Destination,
2347 IN PCSZ Source)
2348 {
2349 SIZE_T Size;
2350
2351 if (Source)
2352 {
2353 Size = strlen(Source);
2354
2355 if (Destination->Length + Size > Destination->MaximumLength)
2356 {
2357 return STATUS_BUFFER_TOO_SMALL;
2358 }
2359
2360 RtlMoveMemory(&Destination->Buffer[Destination->Length], Source, Size);
2361 Destination->Length += (USHORT)Size;
2362 }
2363
2364 return STATUS_SUCCESS;
2365 }
2366
2367 /*
2368 * @implemented
2369 */
2370 VOID
2371 NTAPI
2372 RtlUpperString(PSTRING DestinationString,
2373 PSTRING SourceString)
2374 {
2375 USHORT Length;
2376 PCHAR Src, Dest;
2377
2378 Length = min(SourceString->Length,
2379 DestinationString->MaximumLength);
2380
2381 Src = SourceString->Buffer;
2382 Dest = DestinationString->Buffer;
2383 DestinationString->Length = Length;
2384
2385 while (Length)
2386 {
2387 *Dest++ = RtlUpperChar(*Src++);
2388 Length--;
2389 }
2390 }
2391
2392 /*
2393 * @implemented
2394 *
2395 * NOTES
2396 * See RtlpDuplicateUnicodeString
2397 */
2398 NTSTATUS
2399 NTAPI
2400 RtlDuplicateUnicodeString(
2401 IN ULONG Flags,
2402 IN PCUNICODE_STRING SourceString,
2403 OUT PUNICODE_STRING DestinationString)
2404 {
2405 PAGED_CODE_RTL();
2406
2407 if (SourceString == NULL || DestinationString == NULL ||
2408 SourceString->Length > SourceString->MaximumLength ||
2409 (SourceString->Length == 0 && SourceString->MaximumLength > 0 && SourceString->Buffer == NULL) ||
2410 Flags == RTL_DUPLICATE_UNICODE_STRING_ALLOCATE_NULL_STRING || Flags >= 4)
2411 {
2412 return STATUS_INVALID_PARAMETER;
2413 }
2414
2415
2416 if ((SourceString->Length == 0) &&
2417 (Flags != (RTL_DUPLICATE_UNICODE_STRING_NULL_TERMINATE |
2418 RTL_DUPLICATE_UNICODE_STRING_ALLOCATE_NULL_STRING)))
2419 {
2420 DestinationString->Length = 0;
2421 DestinationString->MaximumLength = 0;
2422 DestinationString->Buffer = NULL;
2423 }
2424 else
2425 {
2426 UINT DestMaxLength = SourceString->Length;
2427
2428 if (Flags & RTL_DUPLICATE_UNICODE_STRING_NULL_TERMINATE)
2429 DestMaxLength += sizeof(UNICODE_NULL);
2430
2431 DestinationString->Buffer = RtlpAllocateStringMemory(DestMaxLength, TAG_USTR);
2432
2433 if (DestinationString->Buffer == NULL)
2434 return STATUS_NO_MEMORY;
2435
2436 RtlCopyMemory(DestinationString->Buffer, SourceString->Buffer, SourceString->Length);
2437 DestinationString->Length = SourceString->Length;
2438 DestinationString->MaximumLength = DestMaxLength;
2439
2440 if (Flags & RTL_DUPLICATE_UNICODE_STRING_NULL_TERMINATE)
2441 DestinationString->Buffer[DestinationString->Length / sizeof(WCHAR)] = 0;
2442 }
2443
2444 return STATUS_SUCCESS;
2445 }
2446
2447 /*
2448 * @implemented
2449 */
2450 NTSTATUS
2451 NTAPI
2452 RtlValidateUnicodeString(IN ULONG Flags,
2453 IN PCUNICODE_STRING UnicodeString)
2454 {
2455 /* currently no flags are supported! */
2456 ASSERT(Flags == 0);
2457
2458 if ((Flags == 0) &&
2459 ((UnicodeString == NULL) ||
2460 ((UnicodeString->Length != 0) &&
2461 (UnicodeString->Buffer != NULL) &&
2462 ((UnicodeString->Length % sizeof(WCHAR)) == 0) &&
2463 ((UnicodeString->MaximumLength % sizeof(WCHAR)) == 0) &&
2464 (UnicodeString->MaximumLength >= UnicodeString->Length))))
2465 {
2466 /* a NULL pointer as a unicode string is considered to be a valid unicode
2467 string! */
2468 return STATUS_SUCCESS;
2469 }
2470 else
2471 {
2472 return STATUS_INVALID_PARAMETER;
2473 }
2474 }
2475
2476 /*
2477 * @unimplemented
2478 */
2479 NTSTATUS
2480 NTAPI
2481 RtlpEnsureBufferSize(ULONG Unknown1, ULONG Unknown2, ULONG Unknown3)
2482 {
2483 DPRINT1("RtlpEnsureBufferSize: stub\n");
2484 return STATUS_NOT_IMPLEMENTED;
2485 }
2486
2487 /*
2488 * @implemented
2489 */
2490 NTSTATUS
2491 NTAPI
2492 RtlFindCharInUnicodeString(
2493 IN ULONG Flags,
2494 IN PUNICODE_STRING SearchString,
2495 IN PCUNICODE_STRING MatchString,
2496 OUT PUSHORT Position)
2497 {
2498 SHORT i;
2499 USHORT j;
2500
2501 switch (Flags)
2502 {
2503 case 0:
2504 {
2505 for (i = 0; i < SearchString->Length / sizeof(WCHAR); i++)
2506 {
2507 for (j = 0; j < MatchString->Length / sizeof(WCHAR); j++)
2508 {
2509 if (SearchString->Buffer[i] == MatchString->Buffer[j])
2510 {
2511 *Position = (i + 1) * sizeof(WCHAR);
2512 return STATUS_SUCCESS;
2513 }
2514 }
2515 }
2516
2517 *Position = 0;
2518 return STATUS_NOT_FOUND;
2519 }
2520
2521 case 1:
2522 {
2523 for (i = SearchString->Length / sizeof(WCHAR) - 1; i >= 0; i--)
2524 {
2525 for (j = 0; j < MatchString->Length / sizeof(WCHAR); j++)
2526 {
2527 if (SearchString->Buffer[i] == MatchString->Buffer[j])
2528 {
2529 *Position = i * sizeof(WCHAR);
2530 return STATUS_SUCCESS;
2531 }
2532 }
2533 }
2534
2535 *Position = 0;
2536 return STATUS_NOT_FOUND;
2537 }
2538
2539 case 2:
2540 {
2541 for (i = 0; i < SearchString->Length / sizeof(WCHAR); i++)
2542 {
2543 j = 0;
2544
2545 while (j < MatchString->Length / sizeof(WCHAR) &&
2546 SearchString->Buffer[i] != MatchString->Buffer[j])
2547 {
2548 j++;
2549 }
2550
2551 if (j >= MatchString->Length / sizeof(WCHAR))
2552 {
2553 *Position = (i + 1) * sizeof(WCHAR);
2554 return STATUS_SUCCESS;
2555 }
2556 }
2557
2558 *Position = 0;
2559 return STATUS_NOT_FOUND;
2560 }
2561
2562 case 3:
2563 {
2564 for (i = SearchString->Length / sizeof(WCHAR) - 1; i >= 0; i--)
2565 {
2566 j = 0;
2567
2568 while (j < MatchString->Length / sizeof(WCHAR) &&
2569 SearchString->Buffer[i] != MatchString->Buffer[j])
2570 {
2571 j++;
2572 }
2573
2574 if (j >= MatchString->Length / sizeof(WCHAR))
2575 {
2576 *Position = i * sizeof(WCHAR);
2577 return STATUS_SUCCESS;
2578 }
2579 }
2580
2581 *Position = 0;
2582 return STATUS_NOT_FOUND;
2583 }
2584 }
2585
2586 return STATUS_NOT_FOUND;
2587 }
2588
2589 /*
2590 * @implemented
2591 *
2592 * NOTES
2593 * Get the maximum of MAX_COMPUTERNAME_LENGTH characters from the dns.host name until the dot is found.
2594 * Convert is to an uppercase oem string and check for unmapped characters.
2595 * Then convert the oem string back to an unicode string.
2596 */
2597 NTSTATUS
2598 NTAPI
2599 RtlDnsHostNameToComputerName(PUNICODE_STRING ComputerName, PUNICODE_STRING DnsHostName, BOOLEAN AllocateComputerNameString)
2600 {
2601 NTSTATUS Status;
2602 ULONG Length;
2603 ULONG ComputerNameLength;
2604 ULONG ComputerNameOemNLength;
2605 OEM_STRING ComputerNameOem;
2606 CHAR ComputerNameOemN[MAX_COMPUTERNAME_LENGTH + 1];
2607
2608 Status = STATUS_INVALID_COMPUTER_NAME;
2609 ComputerNameLength = DnsHostName->Length;
2610
2611 /* find the first dot in the dns host name */
2612 for (Length = 0; Length < DnsHostName->Length / sizeof(WCHAR); Length++)
2613 {
2614 if (DnsHostName->Buffer[Length] == L'.')
2615 {
2616 /* dot found, so set the length for the oem translation */
2617 ComputerNameLength = Length * sizeof(WCHAR);
2618 break;
2619 }
2620 }
2621
2622 /* the computername must have one character */
2623 if (ComputerNameLength > 0)
2624 {
2625 ComputerNameOemNLength = 0;
2626 /* convert to oem string and use uppercase letters */
2627 Status = RtlUpcaseUnicodeToOemN(ComputerNameOemN,
2628 MAX_COMPUTERNAME_LENGTH,
2629 &ComputerNameOemNLength,
2630 DnsHostName->Buffer,
2631 ComputerNameLength);
2632
2633 /* status STATUS_BUFFER_OVERFLOW is not a problem since the computername shoud only
2634 have MAX_COMPUTERNAME_LENGTH characters */
2635 if ((Status == STATUS_SUCCESS) ||
2636 (Status == STATUS_BUFFER_OVERFLOW))
2637 {
2638 /* set the termination for the oem string */
2639 ComputerNameOemN[MAX_COMPUTERNAME_LENGTH] = 0;
2640 /* set status for the case the next function failed */
2641 Status = STATUS_INVALID_COMPUTER_NAME;
2642 /* fillup the oem string structure with the converted computername
2643 and check it for unmapped characters */
2644 ComputerNameOem.Buffer = ComputerNameOemN;
2645 ComputerNameOem.Length = (USHORT)ComputerNameOemNLength;
2646 ComputerNameOem.MaximumLength = (USHORT)(MAX_COMPUTERNAME_LENGTH + 1);
2647
2648 if (RtlpDidUnicodeToOemWork(DnsHostName, &ComputerNameOem) == TRUE)
2649 {
2650 /* no unmapped character so convert it back to an unicode string */
2651 Status = RtlOemStringToUnicodeString(ComputerName,
2652 &ComputerNameOem,
2653 AllocateComputerNameString);
2654 }
2655 }
2656 }
2657
2658 return Status;
2659 }
2660