[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 = 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)
324 {
325 *value = bMinus ? -RunningTotal : RunningTotal;
326 return STATUS_SUCCESS;
327 }
328
329 RunningTotal = RunningTotal * base + digit;
330 str++;
331 }
332
333 *value = bMinus ? -RunningTotal : RunningTotal;
334 return STATUS_SUCCESS;
335 }
336
337 /*
338 * @implemented
339 */
340 LONG
341 NTAPI
342 RtlCompareString(
343 IN PSTRING s1,
344 IN PSTRING s2,
345 IN BOOLEAN CaseInsensitive)
346 {
347 unsigned int len;
348 LONG ret = 0;
349 LPCSTR p1, p2;
350
351 len = min(s1->Length, s2->Length);
352 p1 = s1->Buffer;
353 p2 = s2->Buffer;
354
355 if (CaseInsensitive)
356 {
357 while (!ret && len--)
358 ret = RtlUpperChar(*p1++) - RtlUpperChar(*p2++);
359 }
360 else
361 {
362 while (!ret && len--) ret = *p1++ - *p2++;
363 }
364
365 if (!ret) ret = s1->Length - s2->Length;
366
367 return ret;
368 }
369
370 /*
371 * @implemented
372 *
373 * RETURNS
374 * TRUE if strings are equal.
375 */
376 BOOLEAN
377 NTAPI
378 RtlEqualString(
379 IN PSTRING s1,
380 IN PSTRING s2,
381 IN BOOLEAN CaseInsensitive)
382 {
383 if (s1->Length != s2->Length) return FALSE;
384 return !RtlCompareString(s1, s2, CaseInsensitive);
385 }
386
387 /*
388 * @implemented
389 *
390 * RETURNS
391 * TRUE if strings are equal.
392 */
393 BOOLEAN
394 NTAPI
395 RtlEqualUnicodeString(
396 IN CONST UNICODE_STRING *s1,
397 IN CONST UNICODE_STRING *s2,
398 IN BOOLEAN CaseInsensitive)
399 {
400 if (s1->Length != s2->Length) return FALSE;
401 return !RtlCompareUnicodeString(s1, s2, CaseInsensitive );
402 }
403
404 /*
405 * @implemented
406 */
407 VOID
408 NTAPI
409 RtlFreeAnsiString(IN PANSI_STRING AnsiString)
410 {
411 PAGED_CODE_RTL();
412
413 if (AnsiString->Buffer)
414 {
415 RtlpFreeStringMemory(AnsiString->Buffer, TAG_ASTR);
416 RtlZeroMemory(AnsiString, sizeof(ANSI_STRING));
417 }
418 }
419
420 /*
421 * @implemented
422 */
423 VOID
424 NTAPI
425 RtlFreeOemString(IN POEM_STRING OemString)
426 {
427 PAGED_CODE_RTL();
428
429 if (OemString->Buffer) RtlpFreeStringMemory(OemString->Buffer, TAG_OSTR);
430 }
431
432 /*
433 * @implemented
434 */
435 VOID
436 NTAPI
437 RtlFreeUnicodeString(IN PUNICODE_STRING UnicodeString)
438 {
439 PAGED_CODE_RTL();
440
441 if (UnicodeString->Buffer)
442 {
443 RtlpFreeStringMemory(UnicodeString->Buffer, TAG_USTR);
444 RtlZeroMemory(UnicodeString, sizeof(UNICODE_STRING));
445 }
446 }
447
448
449 /*
450 * @implemented
451 *
452 * NOTES
453 * Check the OEM string to match the Unicode string.
454 *
455 * Functions which convert Unicode strings to OEM strings will set a
456 * DefaultChar from the OEM codepage when the characters are unknown.
457 * So check it against the Unicode string and return false when the
458 * Unicode string does not contain a TransDefaultChar.
459 */
460 BOOLEAN
461 NTAPI
462 RtlpDidUnicodeToOemWork(IN PCUNICODE_STRING UnicodeString,
463 IN POEM_STRING OemString)
464 {
465 ULONG i = 0;
466
467 if (NlsMbOemCodePageTag == FALSE)
468 {
469 /* single-byte code page */
470 /* Go through all characters of a string */
471 while (i < OemString->Length)
472 {
473 /* Check if it got translated into a default char,
474 * but source char wasn't a default char equivalent
475 */
476 if ((OemString->Buffer[i] == NlsOemDefaultChar) &&
477 (UnicodeString->Buffer[i] != NlsUnicodeDefaultChar))
478 {
479 /* Yes, it means unmappable characters were found */
480 return FALSE;
481 }
482
483 /* Move to the next char */
484 i++;
485 }
486
487 /* All chars were translated successfuly */
488 return TRUE;
489 }
490 else
491 {
492 /* multibyte code page */
493
494 /* FIXME */
495 return TRUE;
496 }
497 }
498
499 /*
500 * @unimplemented
501 */
502 BOOLEAN
503 NTAPI
504 RtlIsValidOemCharacter(IN PWCHAR Char)
505 {
506 UNIMPLEMENTED;
507 return FALSE;
508 }
509
510 /*
511 * @implemented
512 *
513 * NOTES
514 * If source is NULL the length of source is assumed to be 0.
515 */
516 VOID
517 NTAPI
518 RtlInitAnsiString(IN OUT PANSI_STRING DestinationString,
519 IN PCSZ SourceString)
520 {
521 ULONG DestSize;
522
523 if(SourceString)
524 {
525 DestSize = strlen(SourceString);
526 DestinationString->Length = (USHORT)DestSize;
527 DestinationString->MaximumLength = (USHORT)DestSize + sizeof(CHAR);
528 }
529 else
530 {
531 DestinationString->Length = 0;
532 DestinationString->MaximumLength = 0;
533 }
534
535 DestinationString->Buffer = (PCHAR)SourceString;
536 }
537
538 NTSTATUS
539 NTAPI
540 RtlInitAnsiStringEx(IN OUT PANSI_STRING DestinationString,
541 IN PCSZ SourceString)
542 {
543 ULONG DestSize;
544
545 if(SourceString)
546 {
547 DestSize = strlen(SourceString);
548 if (DestSize >= 0xFFFF) return STATUS_NAME_TOO_LONG;
549 DestinationString->Length = (USHORT)DestSize;
550 DestinationString->MaximumLength = (USHORT)DestSize + sizeof(CHAR);
551 }
552 else
553 {
554 DestinationString->Length = 0;
555 DestinationString->MaximumLength = 0;
556 }
557
558 DestinationString->Buffer = (PCHAR)SourceString;
559 return STATUS_SUCCESS;
560
561 }
562 /*
563 * @implemented
564 *
565 * NOTES
566 * If source is NULL the length of source is assumed to be 0.
567 */
568 VOID
569 NTAPI
570 RtlInitString(
571 IN OUT PSTRING DestinationString,
572 IN PCSZ SourceString)
573 {
574 RtlInitAnsiString(DestinationString, SourceString);
575 }
576
577 /*
578 * @implemented
579 *
580 * NOTES
581 * If source is NULL the length of source is assumed to be 0.
582 */
583 VOID
584 NTAPI
585 RtlInitUnicodeString(IN OUT PUNICODE_STRING DestinationString,
586 IN PCWSTR SourceString)
587 {
588 ULONG DestSize;
589
590 if(SourceString)
591 {
592 DestSize = wcslen(SourceString) * sizeof(WCHAR);
593 DestinationString->Length = (USHORT)DestSize;
594 DestinationString->MaximumLength = (USHORT)DestSize + 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(OUT PUNICODE_STRING DestinationString,
611 IN PCWSTR SourceString)
612 {
613 ULONG DestSize;
614
615 if(SourceString)
616 {
617 DestSize = wcslen(SourceString) * sizeof(WCHAR);
618 if (DestSize >= 0xFFFC) return STATUS_NAME_TOO_LONG;
619 DestinationString->Length = (USHORT)DestSize;
620 DestinationString->MaximumLength = (USHORT)DestSize + 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 ULONG 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 = 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 = i + L'0';
738 else *tp = 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 || digit >= base)
1007 {
1008 *value = bMinus ? -RunningTotal : RunningTotal;
1009 return STATUS_SUCCESS;
1010 }
1011
1012 RunningTotal = RunningTotal * base + digit;
1013 lpwstr++;
1014 CharsRemaining--;
1015 }
1016
1017 *value = bMinus ? -RunningTotal : RunningTotal;
1018 return STATUS_SUCCESS;
1019 }
1020
1021 /*
1022 * @implemented
1023 *
1024 * RETURNS
1025 * Bytes necessary for the conversion including nullterm.
1026 */
1027 ULONG
1028 NTAPI
1029 RtlxUnicodeStringToOemSize(IN PCUNICODE_STRING UnicodeString)
1030 {
1031 ULONG Size;
1032
1033 /* Convert the Unicode String to Mb Size */
1034 RtlUnicodeToMultiByteSize(&Size,
1035 UnicodeString->Buffer,
1036 UnicodeString->Length);
1037
1038 /* Return the size + the null char */
1039 return (Size + sizeof(CHAR));
1040 }
1041
1042 /*
1043 * @implemented
1044 *
1045 * NOTES
1046 * This function always writes a terminating '\0'.
1047 * It performs a partial copy if ansi is too small.
1048 */
1049 NTSTATUS
1050 NTAPI
1051 RtlUnicodeStringToAnsiString(
1052 IN OUT PANSI_STRING AnsiDest,
1053 IN PCUNICODE_STRING UniSource,
1054 IN BOOLEAN AllocateDestinationString)
1055 {
1056 NTSTATUS Status = STATUS_SUCCESS;
1057 NTSTATUS RealStatus;
1058 ULONG Length;
1059 ULONG Index;
1060
1061 PAGED_CODE_RTL();
1062
1063 ASSERT(!(UniSource->Length & 1));
1064
1065 if (NlsMbCodePageTag == FALSE)
1066 {
1067 Length = (UniSource->Length + sizeof(WCHAR)) / sizeof(WCHAR);
1068 }
1069 else
1070 {
1071 Length = RtlxUnicodeStringToAnsiSize(UniSource);
1072 }
1073
1074 if (Length > MAXUSHORT) return STATUS_INVALID_PARAMETER_2;
1075
1076 AnsiDest->Length = (USHORT)Length - sizeof(CHAR);
1077
1078 if (AllocateDestinationString)
1079 {
1080 AnsiDest->Buffer = RtlpAllocateStringMemory(Length, TAG_ASTR);
1081 AnsiDest->MaximumLength = Length;
1082
1083 if (!AnsiDest->Buffer) return STATUS_NO_MEMORY;
1084 }
1085 else if (AnsiDest->Length >= AnsiDest->MaximumLength)
1086 {
1087 if (!AnsiDest->MaximumLength) return STATUS_BUFFER_OVERFLOW;
1088
1089 Status = STATUS_BUFFER_OVERFLOW;
1090 AnsiDest->Length = AnsiDest->MaximumLength - 1;
1091 }
1092
1093 RealStatus = RtlUnicodeToMultiByteN(AnsiDest->Buffer,
1094 AnsiDest->Length,
1095 &Index,
1096 UniSource->Buffer,
1097 UniSource->Length);
1098
1099 if (!NT_SUCCESS(RealStatus) && AllocateDestinationString)
1100 {
1101 RtlpFreeStringMemory(AnsiDest->Buffer, TAG_ASTR);
1102 return RealStatus;
1103 }
1104
1105 AnsiDest->Buffer[Index] = ANSI_NULL;
1106 return Status;
1107 }
1108
1109 /*
1110 * @implemented
1111 *
1112 * NOTES
1113 * This function always writes a terminating '\0'.
1114 * Does NOT perform a partial copy if unicode is too small!
1115 */
1116 NTSTATUS
1117 NTAPI
1118 RtlOemStringToUnicodeString(
1119 IN OUT PUNICODE_STRING UniDest,
1120 IN PCOEM_STRING OemSource,
1121 IN BOOLEAN AllocateDestinationString)
1122 {
1123 NTSTATUS Status;
1124 ULONG Length;
1125 ULONG Index;
1126
1127 PAGED_CODE_RTL();
1128
1129 Length = RtlOemStringToUnicodeSize(OemSource);
1130
1131 if (Length > MAXUSHORT) return STATUS_INVALID_PARAMETER_2;
1132
1133 UniDest->Length = (USHORT)Length - sizeof(WCHAR);
1134
1135 if (AllocateDestinationString)
1136 {
1137 UniDest->Buffer = RtlpAllocateStringMemory(Length, TAG_USTR);
1138 UniDest->MaximumLength = Length;
1139
1140 if (!UniDest->Buffer) return STATUS_NO_MEMORY;
1141 }
1142 else if (UniDest->Length >= UniDest->MaximumLength)
1143 {
1144 return STATUS_BUFFER_OVERFLOW;
1145 }
1146
1147 Status = RtlOemToUnicodeN(UniDest->Buffer,
1148 UniDest->Length,
1149 &Index,
1150 OemSource->Buffer,
1151 OemSource->Length);
1152
1153 if (!NT_SUCCESS(Status) && AllocateDestinationString)
1154 {
1155 RtlpFreeStringMemory(UniDest->Buffer, TAG_USTR);
1156 UniDest->Buffer = NULL;
1157 return Status;
1158 }
1159
1160 UniDest->Buffer[Index / sizeof(WCHAR)] = UNICODE_NULL;
1161 return Status;
1162 }
1163
1164 /*
1165 * @implemented
1166 *
1167 * NOTES
1168 * This function always '\0' terminates the string returned.
1169 */
1170 NTSTATUS
1171 NTAPI
1172 RtlUnicodeStringToOemString(
1173 IN OUT POEM_STRING OemDest,
1174 IN PCUNICODE_STRING UniSource,
1175 IN BOOLEAN AllocateDestinationString)
1176 {
1177 NTSTATUS Status;
1178 ULONG Length;
1179 ULONG Index;
1180
1181 PAGED_CODE_RTL();
1182
1183 Length = RtlUnicodeStringToOemSize(UniSource);
1184
1185 if (Length > MAXUSHORT) return STATUS_INVALID_PARAMETER_2;
1186
1187 OemDest->Length = (USHORT)Length - sizeof(CHAR);
1188
1189 if (AllocateDestinationString)
1190 {
1191 OemDest->Buffer = RtlpAllocateStringMemory(Length, TAG_OSTR);
1192 OemDest->MaximumLength = Length;
1193
1194 if (!OemDest->Buffer) return STATUS_NO_MEMORY;
1195 }
1196 else if (OemDest->Length >= OemDest->MaximumLength)
1197 {
1198 return STATUS_BUFFER_OVERFLOW;
1199 }
1200
1201 Status = RtlUnicodeToOemN(OemDest->Buffer,
1202 OemDest->Length,
1203 &Index,
1204 UniSource->Buffer,
1205 UniSource->Length);
1206
1207 if (!NT_SUCCESS(Status) && AllocateDestinationString)
1208 {
1209 RtlpFreeStringMemory(OemDest->Buffer, TAG_OSTR);
1210 OemDest->Buffer = NULL;
1211 return Status;
1212 }
1213
1214 OemDest->Buffer[Index] = ANSI_NULL;
1215 return Status;
1216 }
1217
1218 #define ITU_IMPLEMENTED_TESTS (IS_TEXT_UNICODE_ODD_LENGTH|IS_TEXT_UNICODE_SIGNATURE)
1219
1220 /*
1221 * @implemented
1222 *
1223 * RETURNS
1224 * The length of the string if all tests were passed, 0 otherwise.
1225 */
1226 BOOLEAN
1227 NTAPI
1228 RtlIsTextUnicode( PVOID buf, INT len, INT *pf )
1229 {
1230 static const WCHAR std_control_chars[] = {'\r', '\n', '\t', ' ', 0x3000, 0};
1231 static const WCHAR byterev_control_chars[] = {0x0d00, 0x0a00, 0x0900, 0x2000, 0};
1232 const WCHAR *s = buf;
1233 int i;
1234 unsigned int flags = MAXULONG, out_flags = 0;
1235
1236 if (len < sizeof(WCHAR))
1237 {
1238 /* FIXME: MSDN documents IS_TEXT_UNICODE_BUFFER_TOO_SMALL but there is no such thing... */
1239 if (pf) *pf = 0;
1240
1241 return FALSE;
1242 }
1243
1244 if (pf)
1245 flags = *pf;
1246
1247 /*
1248 * Apply various tests to the text string. According to the
1249 * docs, each test "passed" sets the corresponding flag in
1250 * the output flags. But some of the tests are mutually
1251 * exclusive, so I don't see how you could pass all tests ...
1252 */
1253
1254 /* Check for an odd length ... pass if even. */
1255 if (len & 1) out_flags |= IS_TEXT_UNICODE_ODD_LENGTH;
1256
1257 if (((char *)buf)[len - 1] == 0)
1258 len--; /* Windows seems to do something like that to avoid e.g. false IS_TEXT_UNICODE_NULL_BYTES */
1259
1260 len /= sizeof(WCHAR);
1261
1262 /* Windows only checks the first 256 characters */
1263 if (len > 256) len = 256;
1264
1265 /* Check for the special byte order unicode marks. */
1266 if (*s == 0xFEFF) out_flags |= IS_TEXT_UNICODE_SIGNATURE;
1267 if (*s == 0xFFFE) out_flags |= IS_TEXT_UNICODE_REVERSE_SIGNATURE;
1268
1269 /* apply some statistical analysis */
1270 if (flags & IS_TEXT_UNICODE_STATISTICS)
1271 {
1272 int stats = 0;
1273
1274 /* FIXME: checks only for ASCII characters in the unicode stream */
1275 for (i = 0; i < len; i++)
1276 {
1277 if (s[i] <= 255) stats++;
1278 }
1279
1280 if (stats > len / 2)
1281 out_flags |= IS_TEXT_UNICODE_STATISTICS;
1282 }
1283
1284 /* Check for unicode NULL chars */
1285 if (flags & IS_TEXT_UNICODE_NULL_BYTES)
1286 {
1287 for (i = 0; i < len; i++)
1288 {
1289 if (!(s[i] & 0xff) || !(s[i] >> 8))
1290 {
1291 out_flags |= IS_TEXT_UNICODE_NULL_BYTES;
1292 break;
1293 }
1294 }
1295 }
1296
1297 if (flags & IS_TEXT_UNICODE_CONTROLS)
1298 {
1299 for (i = 0; i < len; i++)
1300 {
1301 if (strchrW(std_control_chars, s[i]))
1302 {
1303 out_flags |= IS_TEXT_UNICODE_CONTROLS;
1304 break;
1305 }
1306 }
1307 }
1308
1309 if (flags & IS_TEXT_UNICODE_REVERSE_CONTROLS)
1310 {
1311 for (i = 0; i < len; i++)
1312 {
1313 if (strchrW(byterev_control_chars, s[i]))
1314 {
1315 out_flags |= IS_TEXT_UNICODE_REVERSE_CONTROLS;
1316 break;
1317 }
1318 }
1319 }
1320
1321 if (pf)
1322 {
1323 out_flags &= *pf;
1324 *pf = out_flags;
1325 }
1326
1327 /* check for flags that indicate it's definitely not valid Unicode */
1328 if (out_flags & (IS_TEXT_UNICODE_REVERSE_MASK | IS_TEXT_UNICODE_NOT_UNICODE_MASK)) return FALSE;
1329
1330 /* now check for invalid ASCII, and assume Unicode if so */
1331 if (out_flags & IS_TEXT_UNICODE_NOT_ASCII_MASK) return TRUE;
1332
1333 /* now check for Unicode flags */
1334 if (out_flags & IS_TEXT_UNICODE_UNICODE_MASK) return TRUE;
1335
1336 /* no flags set */
1337 return FALSE;
1338 }
1339
1340
1341 /*
1342 * @implemented
1343 *
1344 * NOTES
1345 * Same as RtlOemStringToUnicodeString but doesn't write terminating null
1346 * A partial copy is NOT performed if the dest buffer is too small!
1347 */
1348 NTSTATUS
1349 NTAPI
1350 RtlOemStringToCountedUnicodeString(
1351 IN OUT PUNICODE_STRING UniDest,
1352 IN PCOEM_STRING OemSource,
1353 IN BOOLEAN AllocateDestinationString)
1354 {
1355 NTSTATUS Status;
1356 ULONG Length;
1357 ULONG Index;
1358
1359 PAGED_CODE_RTL();
1360
1361 /* Calculate size of the string */
1362 Length = RtlOemStringToCountedUnicodeSize(OemSource);
1363
1364 /* If it's 0 then zero out dest string and return */
1365 if (!Length)
1366 {
1367 RtlZeroMemory(UniDest, sizeof(UNICODE_STRING));
1368 return STATUS_SUCCESS;
1369 }
1370
1371 /* Check if length is a sane value */
1372 if (Length > MAXUSHORT) return STATUS_INVALID_PARAMETER_2;
1373
1374 /* Store it in dest string */
1375 UniDest->Length = (USHORT)Length;
1376
1377 /* If we're asked to alloc the string - do so */
1378 if (AllocateDestinationString)
1379 {
1380 UniDest->Buffer = RtlpAllocateStringMemory(Length, TAG_USTR);
1381 UniDest->MaximumLength = Length;
1382
1383 if (!UniDest->Buffer) return STATUS_NO_MEMORY;
1384 }
1385 else if (UniDest->Length > UniDest->MaximumLength)
1386 {
1387 return STATUS_BUFFER_OVERFLOW;
1388 }
1389
1390 /* Do the conversion */
1391 Status = RtlOemToUnicodeN(UniDest->Buffer,
1392 UniDest->Length,
1393 &Index,
1394 OemSource->Buffer,
1395 OemSource->Length);
1396
1397 if (!NT_SUCCESS(Status) && AllocateDestinationString)
1398 {
1399 /* Conversion failed, free dest string and return status code */
1400 RtlpFreeStringMemory(UniDest->Buffer, TAG_USTR);
1401 UniDest->Buffer = NULL;
1402 return Status;
1403 }
1404
1405 return STATUS_SUCCESS;
1406 }
1407
1408 /*
1409 * @implemented
1410 *
1411 * RETURNS
1412 * TRUE if the names are equal, FALSE if not
1413 *
1414 * NOTES
1415 * The comparison is case insensitive.
1416 */
1417 BOOLEAN
1418 NTAPI
1419 RtlEqualComputerName(
1420 IN PUNICODE_STRING ComputerName1,
1421 IN PUNICODE_STRING ComputerName2)
1422 {
1423 OEM_STRING OemString1;
1424 OEM_STRING OemString2;
1425 BOOLEAN Result = FALSE;
1426
1427 if (NT_SUCCESS(RtlUpcaseUnicodeStringToOemString(&OemString1,
1428 ComputerName1,
1429 TRUE)))
1430 {
1431 if (NT_SUCCESS(RtlUpcaseUnicodeStringToOemString(&OemString2,
1432 ComputerName2,
1433 TRUE)))
1434 {
1435 Result = RtlEqualString(&OemString1, &OemString2, FALSE);
1436 RtlFreeOemString(&OemString2);
1437 }
1438
1439 RtlFreeOemString(&OemString1);
1440 }
1441
1442 return Result;
1443 }
1444
1445 /*
1446 * @implemented
1447 *
1448 * RETURNS
1449 * TRUE if the names are equal, FALSE if not
1450 *
1451 * NOTES
1452 * The comparison is case insensitive.
1453 */
1454 BOOLEAN
1455 NTAPI
1456 RtlEqualDomainName (
1457 IN PUNICODE_STRING DomainName1,
1458 IN PUNICODE_STRING DomainName2
1459 )
1460 {
1461 return RtlEqualComputerName(DomainName1, DomainName2);
1462 }
1463
1464 /*
1465 * @implemented
1466 *
1467 * RIPPED FROM WINE's ntdll\rtlstr.c rev 1.45
1468 *
1469 * Convert a string representation of a GUID into a GUID.
1470 *
1471 * PARAMS
1472 * str [I] String representation in the format "{XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX}"
1473 * guid [O] Destination for the converted GUID
1474 *
1475 * RETURNS
1476 * Success: STATUS_SUCCESS. guid contains the converted value.
1477 * Failure: STATUS_INVALID_PARAMETER, if str is not in the expected format.
1478 *
1479 * SEE ALSO
1480 * See RtlStringFromGUID.
1481 */
1482 NTSTATUS
1483 NTAPI
1484 RtlGUIDFromString(
1485 IN UNICODE_STRING *str,
1486 OUT GUID* guid
1487 )
1488 {
1489 int i = 0;
1490 const WCHAR *lpszCLSID = str->Buffer;
1491 BYTE* lpOut = (BYTE*)guid;
1492
1493 //TRACE("(%s,%p)\n", debugstr_us(str), guid);
1494
1495 /* Convert string: {XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX}
1496 * to memory: DWORD... WORD WORD BYTES............
1497 */
1498 while (i <= 37)
1499 {
1500 switch (i)
1501 {
1502 case 0:
1503 if (*lpszCLSID != '{')
1504 return STATUS_INVALID_PARAMETER;
1505 break;
1506
1507 case 9:
1508 case 14:
1509 case 19:
1510 case 24:
1511 if (*lpszCLSID != '-')
1512 return STATUS_INVALID_PARAMETER;
1513 break;
1514
1515 case 37:
1516 if (*lpszCLSID != '}')
1517 return STATUS_INVALID_PARAMETER;
1518
1519 break;
1520
1521 default:
1522 {
1523 WCHAR ch = *lpszCLSID, ch2 = lpszCLSID[1];
1524 unsigned char byte;
1525
1526 /* Read two hex digits as a byte value */
1527 if (ch >= '0' && ch <= '9')
1528 ch = ch - '0';
1529 else if (ch >= 'a' && ch <= 'f')
1530 ch = ch - 'a' + 10;
1531 else if (ch >= 'A' && ch <= 'F')
1532 ch = ch - 'A' + 10;
1533 else
1534 return STATUS_INVALID_PARAMETER;
1535
1536 if (ch2 >= '0' && ch2 <= '9')
1537 ch2 = ch2 - '0';
1538 else if (ch2 >= 'a' && ch2 <= 'f')
1539 ch2 = ch2 - 'a' + 10;
1540 else if (ch2 >= 'A' && ch2 <= 'F')
1541 ch2 = ch2 - 'A' + 10;
1542 else
1543 return STATUS_INVALID_PARAMETER;
1544
1545 byte = ch << 4 | ch2;
1546
1547 switch (i)
1548 {
1549 #ifndef WORDS_BIGENDIAN
1550 /* For Big Endian machines, we store the data such that the
1551 * dword/word members can be read as DWORDS and WORDS correctly. */
1552 /* Dword */
1553 case 1:
1554 lpOut[3] = byte;
1555 break;
1556 case 3:
1557 lpOut[2] = byte;
1558 break;
1559 case 5:
1560 lpOut[1] = byte;
1561 break;
1562 case 7:
1563 lpOut[0] = byte;
1564 lpOut += 4;
1565 break;
1566 /* Word */
1567 case 10:
1568 case 15:
1569 lpOut[1] = byte;
1570 break;
1571 case 12:
1572 case 17:
1573 lpOut[0] = byte;
1574 lpOut += 2;
1575 break;
1576 #endif
1577 /* Byte */
1578 default:
1579 lpOut[0] = byte;
1580 lpOut++;
1581 break;
1582 }
1583
1584 lpszCLSID++; /* Skip 2nd character of byte */
1585 i++;
1586 }
1587 }
1588
1589 lpszCLSID++;
1590 i++;
1591 }
1592
1593 return STATUS_SUCCESS;
1594 }
1595
1596 /*
1597 * @implemented
1598 */
1599 VOID
1600 NTAPI
1601 RtlEraseUnicodeString(
1602 IN PUNICODE_STRING String)
1603 {
1604 if (String->Buffer && String->MaximumLength)
1605 {
1606 RtlZeroMemory(String->Buffer, String->MaximumLength);
1607 String->Length = 0;
1608 }
1609 }
1610
1611 /*
1612 * @implemented
1613 */
1614 NTSTATUS
1615 NTAPI
1616 RtlHashUnicodeString(
1617 IN CONST UNICODE_STRING *String,
1618 IN BOOLEAN CaseInSensitive,
1619 IN ULONG HashAlgorithm,
1620 OUT PULONG HashValue)
1621 {
1622 if (String != NULL && HashValue != NULL)
1623 {
1624 switch (HashAlgorithm)
1625 {
1626 case HASH_STRING_ALGORITHM_DEFAULT:
1627 case HASH_STRING_ALGORITHM_X65599:
1628 {
1629 WCHAR *c, *end;
1630
1631 *HashValue = 0;
1632 end = String->Buffer + (String->Length / sizeof(WCHAR));
1633
1634 if (CaseInSensitive)
1635 {
1636 for (c = String->Buffer; c != end; c++)
1637 {
1638 /* only uppercase characters if they are 'a' ... 'z'! */
1639 *HashValue = ((65599 * (*HashValue)) +
1640 (ULONG)(((*c) >= L'a' && (*c) <= L'z') ?
1641 (*c) - L'a' + L'A' : (*c)));
1642 }
1643 }
1644 else
1645 {
1646 for (c = String->Buffer; c != end; c++)
1647 {
1648 *HashValue = ((65599 * (*HashValue)) + (ULONG)(*c));
1649 }
1650 }
1651
1652 return STATUS_SUCCESS;
1653 }
1654 }
1655 }
1656
1657 return STATUS_INVALID_PARAMETER;
1658 }
1659
1660 /*
1661 * @implemented
1662 *
1663 * NOTES
1664 * Same as RtlUnicodeStringToOemString but doesn't write terminating null
1665 * Does a partial copy if the dest buffer is too small
1666 */
1667 NTSTATUS
1668 NTAPI
1669 RtlUnicodeStringToCountedOemString(
1670 IN OUT POEM_STRING OemDest,
1671 IN PUNICODE_STRING UniSource,
1672 IN BOOLEAN AllocateDestinationString)
1673 {
1674 NTSTATUS Status;
1675 ULONG Length;
1676 ULONG Index;
1677
1678 PAGED_CODE_RTL();
1679
1680 /* Calculate size of the string */
1681 Length = RtlUnicodeStringToCountedOemSize(UniSource);
1682
1683 /* If it's 0 then zero out dest string and return */
1684 if (!Length)
1685 {
1686 RtlZeroMemory(OemDest, sizeof(OEM_STRING));
1687 return STATUS_SUCCESS;
1688 }
1689
1690 /* Check if length is a sane value */
1691 if (Length > MAXUSHORT) return STATUS_INVALID_PARAMETER_2;
1692
1693 /* Store it in dest string */
1694 OemDest->Length = (USHORT)Length;
1695
1696 /* If we're asked to alloc the string - do so */
1697 if (AllocateDestinationString)
1698 {
1699 OemDest->Buffer = RtlpAllocateStringMemory(Length, TAG_OSTR);
1700 OemDest->MaximumLength = Length;
1701 if (!OemDest->Buffer) return STATUS_NO_MEMORY;
1702 }
1703 else if (OemDest->Length > OemDest->MaximumLength)
1704 {
1705 return STATUS_BUFFER_OVERFLOW;
1706 }
1707
1708 /* Do the conversion */
1709 Status = RtlUnicodeToOemN(OemDest->Buffer,
1710 OemDest->Length,
1711 &Index,
1712 UniSource->Buffer,
1713 UniSource->Length);
1714
1715 /* Check for unmapped character */
1716 if (NT_SUCCESS(Status) && !RtlpDidUnicodeToOemWork(UniSource, OemDest))
1717 Status = STATUS_UNMAPPABLE_CHARACTER;
1718
1719 if (!NT_SUCCESS(Status) && AllocateDestinationString)
1720 {
1721 /* Conversion failed, free dest string and return status code */
1722 RtlpFreeStringMemory(OemDest->Buffer, TAG_OSTR);
1723 OemDest->Buffer = NULL;
1724 return Status;
1725 }
1726
1727 return Status;
1728 }
1729
1730 /*
1731 * @implemented
1732 */
1733 NTSTATUS
1734 NTAPI
1735 RtlLargeIntegerToChar(
1736 IN PLARGE_INTEGER Value,
1737 IN ULONG Base,
1738 IN ULONG Length,
1739 IN OUT PCHAR String)
1740 {
1741 ULONGLONG Val = Value->QuadPart;
1742 NTSTATUS Status = STATUS_SUCCESS;
1743 CHAR Buffer[65];
1744 CHAR Digit;
1745 ULONG Len;
1746 PCHAR Pos;
1747
1748 if (Base == 0) Base = 10;
1749
1750 if ((Base != 2) && (Base != 8) &&
1751 (Base != 10) && (Base != 16))
1752 {
1753 return STATUS_INVALID_PARAMETER;
1754 }
1755
1756 Pos = &Buffer[64];
1757 *Pos = '\0';
1758
1759 do
1760 {
1761 Pos--;
1762 Digit = Val % Base;
1763 Val = Val / Base;
1764
1765 if (Digit < 10)
1766 *Pos = '0' + Digit;
1767 else
1768 *Pos = 'A' + Digit - 10;
1769 }
1770 while (Val != 0L);
1771
1772 Len = &Buffer[64] - Pos;
1773
1774 if (Len > Length)
1775 return STATUS_BUFFER_OVERFLOW;
1776
1777 #if 1 /* It needs to be removed, when will probably use SEH in rtl */
1778
1779 if (String == NULL)
1780 {
1781 return STATUS_ACCESS_VIOLATION;
1782 }
1783
1784 #endif
1785
1786 #if 0
1787 _SEH2_TRY
1788 {
1789 #endif
1790
1791 if (Len == Length)
1792 RtlCopyMemory(String, Pos, Len);
1793 else
1794 RtlCopyMemory(String, Pos, Len + 1);
1795
1796 #if 0
1797 }
1798 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
1799 {
1800 /* Get the error code */
1801 Status = _SEH2_GetExceptionCode();
1802 }
1803 _SEH2_END;
1804 #endif
1805
1806 return Status;
1807 }
1808
1809 /*
1810 * @implemented
1811 *
1812 * NOTES
1813 * dest is never '\0' terminated because it may be equal to src, and src
1814 * might not be '\0' terminated. dest->Length is only set upon success.
1815 */
1816 NTSTATUS
1817 NTAPI
1818 RtlUpcaseUnicodeString(
1819 IN OUT PUNICODE_STRING UniDest,
1820 IN PCUNICODE_STRING UniSource,
1821 IN BOOLEAN AllocateDestinationString)
1822 {
1823 ULONG i, j;
1824
1825 PAGED_CODE_RTL();
1826
1827 if (AllocateDestinationString == TRUE)
1828 {
1829 UniDest->MaximumLength = UniSource->Length;
1830 UniDest->Buffer = RtlpAllocateStringMemory(UniDest->MaximumLength, TAG_USTR);
1831 if (UniDest->Buffer == NULL) return STATUS_NO_MEMORY;
1832 }
1833 else if (UniSource->Length > UniDest->MaximumLength)
1834 {
1835 return STATUS_BUFFER_OVERFLOW;
1836 }
1837
1838 j = UniSource->Length / sizeof(WCHAR);
1839
1840 for (i = 0; i < j; i++)
1841 {
1842 UniDest->Buffer[i] = RtlUpcaseUnicodeChar(UniSource->Buffer[i]);
1843 }
1844
1845 UniDest->Length = UniSource->Length;
1846 return STATUS_SUCCESS;
1847 }
1848
1849 /*
1850 * @implemented
1851 *
1852 * NOTES
1853 * This function always writes a terminating '\0'.
1854 * It performs a partial copy if ansi is too small.
1855 */
1856 NTSTATUS
1857 NTAPI
1858 RtlUpcaseUnicodeStringToAnsiString(
1859 IN OUT PANSI_STRING AnsiDest,
1860 IN PUNICODE_STRING UniSource,
1861 IN BOOLEAN AllocateDestinationString)
1862 {
1863 NTSTATUS Status;
1864 ULONG Length;
1865 ULONG Index;
1866 PAGED_CODE_RTL();
1867
1868 Length = RtlUnicodeStringToAnsiSize(UniSource);
1869 if (Length > MAXUSHORT) return STATUS_INVALID_PARAMETER_2;
1870
1871 AnsiDest->Length = (USHORT)Length - sizeof(CHAR);
1872
1873 if (AllocateDestinationString)
1874 {
1875 AnsiDest->Buffer = RtlpAllocateStringMemory(Length, TAG_ASTR);
1876 AnsiDest->MaximumLength = Length;
1877 if (!AnsiDest->Buffer) return STATUS_NO_MEMORY;
1878 }
1879 else if (AnsiDest->Length >= AnsiDest->MaximumLength)
1880 {
1881 if (!AnsiDest->MaximumLength) return STATUS_BUFFER_OVERFLOW;
1882 }
1883
1884 Status = RtlUpcaseUnicodeToMultiByteN(AnsiDest->Buffer,
1885 AnsiDest->Length,
1886 &Index,
1887 UniSource->Buffer,
1888 UniSource->Length);
1889
1890 if (!NT_SUCCESS(Status) && AllocateDestinationString)
1891 {
1892 RtlpFreeStringMemory(AnsiDest->Buffer, TAG_ASTR);
1893 AnsiDest->Buffer = NULL;
1894 return Status;
1895 }
1896
1897 AnsiDest->Buffer[Index] = ANSI_NULL;
1898 return Status;
1899 }
1900
1901 /*
1902 * @implemented
1903 *
1904 * NOTES
1905 * This function always writes a terminating '\0'.
1906 * It performs a partial copy if ansi is too small.
1907 */
1908 NTSTATUS
1909 NTAPI
1910 RtlUpcaseUnicodeStringToCountedOemString(
1911 IN OUT POEM_STRING OemDest,
1912 IN PCUNICODE_STRING UniSource,
1913 IN BOOLEAN AllocateDestinationString)
1914 {
1915 NTSTATUS Status;
1916 ULONG Length;
1917 ULONG Index;
1918 PAGED_CODE_RTL();
1919
1920 Length = RtlUnicodeStringToCountedOemSize(UniSource);
1921
1922 if (!Length)
1923 {
1924 RtlZeroMemory(OemDest, sizeof(OEM_STRING));
1925 }
1926
1927 if (Length > MAXUSHORT) return STATUS_INVALID_PARAMETER_2;
1928
1929 OemDest->Length = (USHORT)Length;
1930
1931 if (AllocateDestinationString)
1932 {
1933 OemDest->Buffer = RtlpAllocateStringMemory(Length, TAG_OSTR);
1934 OemDest->MaximumLength = Length;
1935 if (!OemDest->Buffer) return STATUS_NO_MEMORY;
1936 }
1937 else if (OemDest->Length > OemDest->MaximumLength)
1938 {
1939 return STATUS_BUFFER_OVERFLOW;
1940 }
1941
1942 Status = RtlUpcaseUnicodeToOemN(OemDest->Buffer,
1943 OemDest->Length,
1944 &Index,
1945 UniSource->Buffer,
1946 UniSource->Length);
1947
1948 /* Check for unmapped characters */
1949 if (NT_SUCCESS(Status) && !RtlpDidUnicodeToOemWork(UniSource, OemDest))
1950 Status = STATUS_UNMAPPABLE_CHARACTER;
1951
1952 if (!NT_SUCCESS(Status) && AllocateDestinationString)
1953 {
1954 RtlpFreeStringMemory(OemDest->Buffer, TAG_OSTR);
1955 OemDest->Buffer = NULL;
1956 return Status;
1957 }
1958
1959 return Status;
1960 }
1961
1962 /*
1963 * @implemented
1964 * NOTES
1965 * Oem string is allways nullterminated
1966 * It performs a partial copy if oem is too small.
1967 */
1968 NTSTATUS
1969 NTAPI
1970 RtlUpcaseUnicodeStringToOemString (
1971 IN OUT POEM_STRING OemDest,
1972 IN PCUNICODE_STRING UniSource,
1973 IN BOOLEAN AllocateDestinationString)
1974 {
1975 NTSTATUS Status;
1976 ULONG Length;
1977 ULONG Index;
1978 PAGED_CODE_RTL();
1979
1980 Length = RtlUnicodeStringToOemSize(UniSource);
1981 if (Length > MAXUSHORT) return STATUS_INVALID_PARAMETER_2;
1982
1983 OemDest->Length = (USHORT)Length - sizeof(CHAR);
1984
1985 if (AllocateDestinationString)
1986 {
1987 OemDest->Buffer = RtlpAllocateStringMemory(Length, TAG_OSTR);
1988 OemDest->MaximumLength = Length;
1989 if (!OemDest->Buffer) return STATUS_NO_MEMORY;
1990 }
1991 else if (OemDest->Length >= OemDest->MaximumLength)
1992 {
1993 return STATUS_BUFFER_OVERFLOW;
1994 }
1995
1996 Status = RtlUpcaseUnicodeToOemN(OemDest->Buffer,
1997 OemDest->Length,
1998 &Index,
1999 UniSource->Buffer,
2000 UniSource->Length);
2001
2002 /* Check for unmapped characters */
2003 if (NT_SUCCESS(Status) && !RtlpDidUnicodeToOemWork(UniSource, OemDest))
2004 Status = STATUS_UNMAPPABLE_CHARACTER;
2005
2006 if (!NT_SUCCESS(Status) && AllocateDestinationString)
2007 {
2008 RtlpFreeStringMemory(OemDest->Buffer, TAG_OSTR);
2009 OemDest->Buffer = NULL;
2010 return Status;
2011 }
2012
2013 OemDest->Buffer[Index] = ANSI_NULL;
2014 return Status;
2015 }
2016
2017 /*
2018 * @implemented
2019 *
2020 * RETURNS
2021 * Bytes calculated including nullterm
2022 */
2023 ULONG
2024 NTAPI
2025 RtlxOemStringToUnicodeSize(IN PCOEM_STRING OemString)
2026 {
2027 ULONG Size;
2028
2029 /* Convert the Mb String to Unicode Size */
2030 RtlMultiByteToUnicodeSize(&Size,
2031 OemString->Buffer,
2032 OemString->Length);
2033
2034 /* Return the size + null-char */
2035 return (Size + sizeof(WCHAR));
2036 }
2037
2038 /*
2039 * @implemented
2040 */
2041 NTSTATUS
2042 NTAPI
2043 RtlStringFromGUID (IN REFGUID Guid,
2044 OUT PUNICODE_STRING GuidString)
2045 {
2046 /* Setup the string */
2047 GuidString->Length = 38 * sizeof(WCHAR);
2048 GuidString->MaximumLength = GuidString->Length + sizeof(UNICODE_NULL);
2049 GuidString->Buffer = RtlpAllocateStringMemory(GuidString->MaximumLength,
2050 TAG_USTR);
2051 if (!GuidString->Buffer) return STATUS_NO_MEMORY;
2052
2053 /* Now format the GUID */
2054 swprintf(GuidString->Buffer,
2055 L"{%08lx-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x}",
2056 Guid->Data1,
2057 Guid->Data2,
2058 Guid->Data3,
2059 Guid->Data4[0],
2060 Guid->Data4[1],
2061 Guid->Data4[2],
2062 Guid->Data4[3],
2063 Guid->Data4[4],
2064 Guid->Data4[5],
2065 Guid->Data4[6],
2066 Guid->Data4[7]);
2067 return STATUS_SUCCESS;
2068 }
2069
2070 /*
2071 * @implemented
2072 *
2073 * RETURNS
2074 * Bytes calculated including nullterm
2075 */
2076 ULONG
2077 NTAPI
2078 RtlxUnicodeStringToAnsiSize(IN PCUNICODE_STRING UnicodeString)
2079 {
2080 ULONG Size;
2081 PAGED_CODE_RTL();
2082
2083 ASSERT(!(UnicodeString->Length & 1));
2084
2085 /* Convert the Unicode String to Mb Size */
2086 RtlUnicodeToMultiByteSize(&Size,
2087 UnicodeString->Buffer,
2088 UnicodeString->Length);
2089
2090 /* Return the size + null-char */
2091 return (Size + sizeof(CHAR));
2092 }
2093
2094 /*
2095 * @implemented
2096 */
2097 LONG
2098 NTAPI
2099 RtlCompareUnicodeString(
2100 IN PCUNICODE_STRING s1,
2101 IN PCUNICODE_STRING s2,
2102 IN BOOLEAN CaseInsensitive)
2103 {
2104 unsigned int len;
2105 LONG ret = 0;
2106 LPCWSTR p1, p2;
2107
2108 len = min(s1->Length, s2->Length) / sizeof(WCHAR);
2109 p1 = s1->Buffer;
2110 p2 = s2->Buffer;
2111
2112 if (CaseInsensitive)
2113 {
2114 while (!ret && len--) ret = RtlUpcaseUnicodeChar(*p1++) - RtlUpcaseUnicodeChar(*p2++);
2115 }
2116 else
2117 {
2118 while (!ret && len--) ret = *p1++ - *p2++;
2119 }
2120
2121 if (!ret) ret = s1->Length - s2->Length;
2122
2123 return ret;
2124 }
2125
2126 /*
2127 * @implemented
2128 */
2129 VOID
2130 NTAPI
2131 RtlCopyString(
2132 IN OUT PSTRING DestinationString,
2133 IN PSTRING SourceString OPTIONAL)
2134 {
2135 ULONG SourceLength;
2136 PCHAR p1, p2;
2137
2138 /* Check if there was no source given */
2139 if(!SourceString)
2140 {
2141 /* Simply return an empty string */
2142 DestinationString->Length = 0;
2143 }
2144 else
2145 {
2146 /* Choose the smallest length */
2147 SourceLength = min(DestinationString->MaximumLength,
2148 SourceString->Length);
2149
2150 /* Set it */
2151 DestinationString->Length = (USHORT)SourceLength;
2152
2153 /* Save the pointers to each buffer */
2154 p1 = DestinationString->Buffer;
2155 p2 = SourceString->Buffer;
2156
2157 /* Loop the buffer */
2158 while (SourceLength)
2159 {
2160 /* Copy the character and move on */
2161 *p1++ = * p2++;
2162 SourceLength--;
2163 }
2164 }
2165 }
2166
2167 /*
2168 * @implemented
2169 */
2170 VOID
2171 NTAPI
2172 RtlCopyUnicodeString(
2173 IN OUT PUNICODE_STRING DestinationString,
2174 IN PCUNICODE_STRING SourceString)
2175 {
2176 ULONG SourceLength;
2177
2178 if(SourceString == NULL)
2179 {
2180 DestinationString->Length = 0;
2181 }
2182 else
2183 {
2184 SourceLength = min(DestinationString->MaximumLength,
2185 SourceString->Length);
2186 DestinationString->Length = (USHORT)SourceLength;
2187
2188 RtlCopyMemory(DestinationString->Buffer,
2189 SourceString->Buffer,
2190 SourceLength);
2191
2192 if (DestinationString->Length < DestinationString->MaximumLength)
2193 {
2194 DestinationString->Buffer[SourceLength / sizeof(WCHAR)] = UNICODE_NULL;
2195 }
2196 }
2197 }
2198
2199 /*
2200 * @implemented
2201 *
2202 * NOTES
2203 * Creates a nullterminated UNICODE_STRING
2204 */
2205 BOOLEAN
2206 NTAPI
2207 RtlCreateUnicodeString(
2208 IN OUT PUNICODE_STRING UniDest,
2209 IN PCWSTR Source)
2210 {
2211 ULONG Length;
2212 PAGED_CODE_RTL();
2213
2214 Length = (wcslen(Source) + 1) * sizeof(WCHAR);
2215 if (Length > 0xFFFE) return FALSE;
2216
2217 UniDest->Buffer = RtlpAllocateStringMemory(Length, TAG_USTR);
2218
2219 if (UniDest->Buffer == NULL) return FALSE;
2220
2221 RtlCopyMemory(UniDest->Buffer, Source, Length);
2222 UniDest->MaximumLength = (USHORT)Length;
2223 UniDest->Length = Length - sizeof (WCHAR);
2224
2225 return TRUE;
2226 }
2227
2228 /*
2229 * @implemented
2230 */
2231 BOOLEAN
2232 NTAPI
2233 RtlCreateUnicodeStringFromAsciiz(
2234 OUT PUNICODE_STRING Destination,
2235 IN PCSZ Source)
2236 {
2237 ANSI_STRING AnsiString;
2238 NTSTATUS Status;
2239
2240 RtlInitAnsiString(&AnsiString, Source);
2241
2242 Status = RtlAnsiStringToUnicodeString(Destination,
2243 &AnsiString,
2244 TRUE);
2245
2246 return NT_SUCCESS(Status);
2247 }
2248
2249 /*
2250 * @implemented
2251 *
2252 * NOTES
2253 * Dest is never '\0' terminated because it may be equal to src, and src
2254 * might not be '\0' terminated.
2255 * Dest->Length is only set upon success.
2256 */
2257 NTSTATUS
2258 NTAPI
2259 RtlDowncaseUnicodeString(
2260 IN OUT PUNICODE_STRING UniDest,
2261 IN PCUNICODE_STRING UniSource,
2262 IN BOOLEAN AllocateDestinationString)
2263 {
2264 ULONG i;
2265 ULONG StopGap;
2266 PAGED_CODE_RTL();
2267
2268 if (AllocateDestinationString)
2269 {
2270 UniDest->MaximumLength = UniSource->Length;
2271 UniDest->Buffer = RtlpAllocateStringMemory(UniSource->Length, TAG_USTR);
2272 if (UniDest->Buffer == NULL) return STATUS_NO_MEMORY;
2273 }
2274 else if (UniSource->Length > UniDest->MaximumLength)
2275 {
2276 return STATUS_BUFFER_OVERFLOW;
2277 }
2278
2279 UniDest->Length = UniSource->Length;
2280 StopGap = UniSource->Length / sizeof(WCHAR);
2281
2282 for (i = 0 ; i < StopGap; i++)
2283 {
2284 if (UniSource->Buffer[i] < L'A')
2285 {
2286 UniDest->Buffer[i] = UniSource->Buffer[i];
2287 }
2288 else if (UniSource->Buffer[i] <= L'Z')
2289 {
2290 UniDest->Buffer[i] = (UniSource->Buffer[i] + (L'a' - L'A'));
2291 }
2292 else
2293 {
2294 UniDest->Buffer[i] = RtlDowncaseUnicodeChar(UniSource->Buffer[i]);
2295 }
2296 }
2297
2298 return STATUS_SUCCESS;
2299 }
2300
2301 /*
2302 * @implemented
2303 *
2304 * NOTES
2305 * if src is NULL dest is unchanged.
2306 * dest is '\0' terminated when the MaximumLength allowes it.
2307 * When dest fits exactly in MaximumLength characters the '\0' is ommitted.
2308 */
2309 NTSTATUS
2310 NTAPI
2311 RtlAppendUnicodeToString(IN OUT PUNICODE_STRING Destination,
2312 IN PCWSTR Source)
2313 {
2314 USHORT Length;
2315 PWCHAR DestBuffer;
2316
2317 if (Source)
2318 {
2319 UNICODE_STRING UnicodeSource;
2320
2321 RtlInitUnicodeString(&UnicodeSource, Source);
2322 Length = UnicodeSource.Length;
2323
2324 if (Destination->Length + Length > Destination->MaximumLength)
2325 {
2326 return STATUS_BUFFER_TOO_SMALL;
2327 }
2328
2329 DestBuffer = &Destination->Buffer[Destination->Length / sizeof(WCHAR)];
2330 RtlMoveMemory(DestBuffer, Source, Length);
2331 Destination->Length += Length;
2332
2333 /* append terminating '\0' if enough space */
2334 if(Destination->MaximumLength > Destination->Length)
2335 {
2336 DestBuffer[Length / sizeof(WCHAR)] = UNICODE_NULL;
2337 }
2338 }
2339
2340 return STATUS_SUCCESS;
2341 }
2342
2343 /*
2344 * @implemented
2345 *
2346 * NOTES
2347 * if src is NULL dest is unchanged.
2348 * dest is never '\0' terminated.
2349 */
2350 NTSTATUS
2351 NTAPI
2352 RtlAppendAsciizToString(
2353 IN OUT PSTRING Destination,
2354 IN PCSZ Source)
2355 {
2356 ULONG Length;
2357
2358 if (Source)
2359 {
2360 Length = (USHORT)strlen(Source);
2361
2362 if (Destination->Length + Length > Destination->MaximumLength)
2363 {
2364 return STATUS_BUFFER_TOO_SMALL;
2365 }
2366
2367 RtlMoveMemory(&Destination->Buffer[Destination->Length], Source, Length);
2368 Destination->Length += Length;
2369 }
2370
2371 return STATUS_SUCCESS;
2372 }
2373
2374 /*
2375 * @implemented
2376 */
2377 VOID
2378 NTAPI
2379 RtlUpperString(PSTRING DestinationString,
2380 PSTRING SourceString)
2381 {
2382 ULONG Length;
2383 PCHAR Src, Dest;
2384
2385 Length = min(SourceString->Length,
2386 DestinationString->MaximumLength);
2387
2388 Src = SourceString->Buffer;
2389 Dest = DestinationString->Buffer;
2390 DestinationString->Length = Length;
2391
2392 while (Length)
2393 {
2394 *Dest++ = RtlUpperChar(*Src++);
2395 Length--;
2396 }
2397 }
2398
2399 /*
2400 * @implemented
2401 *
2402 * NOTES
2403 * See RtlpDuplicateUnicodeString
2404 */
2405 NTSTATUS
2406 NTAPI
2407 RtlDuplicateUnicodeString(
2408 IN ULONG Flags,
2409 IN PCUNICODE_STRING SourceString,
2410 OUT PUNICODE_STRING DestinationString)
2411 {
2412 PAGED_CODE_RTL();
2413
2414 if (SourceString == NULL || DestinationString == NULL ||
2415 SourceString->Length > SourceString->MaximumLength ||
2416 (SourceString->Length == 0 && SourceString->MaximumLength > 0 && SourceString->Buffer == NULL) ||
2417 Flags == RTL_DUPLICATE_UNICODE_STRING_ALLOCATE_NULL_STRING || Flags >= 4)
2418 {
2419 return STATUS_INVALID_PARAMETER;
2420 }
2421
2422
2423 if ((SourceString->Length == 0) &&
2424 (Flags != (RTL_DUPLICATE_UNICODE_STRING_NULL_TERMINATE |
2425 RTL_DUPLICATE_UNICODE_STRING_ALLOCATE_NULL_STRING)))
2426 {
2427 DestinationString->Length = 0;
2428 DestinationString->MaximumLength = 0;
2429 DestinationString->Buffer = NULL;
2430 }
2431 else
2432 {
2433 UINT DestMaxLength = SourceString->Length;
2434
2435 if (Flags & RTL_DUPLICATE_UNICODE_STRING_NULL_TERMINATE)
2436 DestMaxLength += sizeof(UNICODE_NULL);
2437
2438 DestinationString->Buffer = RtlpAllocateStringMemory(DestMaxLength, TAG_USTR);
2439
2440 if (DestinationString->Buffer == NULL)
2441 return STATUS_NO_MEMORY;
2442
2443 RtlCopyMemory(DestinationString->Buffer, SourceString->Buffer, SourceString->Length);
2444 DestinationString->Length = SourceString->Length;
2445 DestinationString->MaximumLength = DestMaxLength;
2446
2447 if (Flags & RTL_DUPLICATE_UNICODE_STRING_NULL_TERMINATE)
2448 DestinationString->Buffer[DestinationString->Length / sizeof(WCHAR)] = 0;
2449 }
2450
2451 return STATUS_SUCCESS;
2452 }
2453
2454 /*
2455 * @implemented
2456 */
2457 NTSTATUS
2458 NTAPI
2459 RtlValidateUnicodeString(IN ULONG Flags,
2460 IN PCUNICODE_STRING UnicodeString)
2461 {
2462 /* currently no flags are supported! */
2463 ASSERT(Flags == 0);
2464
2465 if ((Flags == 0) &&
2466 ((UnicodeString == NULL) ||
2467 ((UnicodeString->Length != 0) &&
2468 (UnicodeString->Buffer != NULL) &&
2469 ((UnicodeString->Length % sizeof(WCHAR)) == 0) &&
2470 ((UnicodeString->MaximumLength % sizeof(WCHAR)) == 0) &&
2471 (UnicodeString->MaximumLength >= UnicodeString->Length))))
2472 {
2473 /* a NULL pointer as a unicode string is considered to be a valid unicode
2474 string! */
2475 return STATUS_SUCCESS;
2476 }
2477 else
2478 {
2479 return STATUS_INVALID_PARAMETER;
2480 }
2481 }
2482
2483 /*
2484 * @unimplemented
2485 */
2486 NTSTATUS
2487 NTAPI
2488 RtlpEnsureBufferSize(ULONG Unknown1, ULONG Unknown2, ULONG Unknown3)
2489 {
2490 DPRINT1("RtlpEnsureBufferSize: stub\n");
2491 return STATUS_NOT_IMPLEMENTED;
2492 }
2493
2494 /*
2495 * @implemented
2496 */
2497 NTSTATUS
2498 NTAPI
2499 RtlFindCharInUnicodeString(
2500 IN ULONG Flags,
2501 IN PUNICODE_STRING SearchString,
2502 IN PCUNICODE_STRING MatchString,
2503 OUT PUSHORT Position)
2504 {
2505 int main_idx;
2506 unsigned int search_idx;
2507
2508 switch (Flags)
2509 {
2510 case 0:
2511 {
2512 for (main_idx = 0; main_idx < SearchString->Length / sizeof(WCHAR); main_idx++)
2513 {
2514 for (search_idx = 0; search_idx < MatchString->Length / sizeof(WCHAR); search_idx++)
2515 {
2516 if (SearchString->Buffer[main_idx] == MatchString->Buffer[search_idx])
2517 {
2518 *Position = (main_idx + 1) * sizeof(WCHAR);
2519 return STATUS_SUCCESS;
2520 }
2521 }
2522 }
2523
2524 *Position = 0;
2525 return STATUS_NOT_FOUND;
2526 }
2527
2528 case 1:
2529 {
2530 for (main_idx = SearchString->Length / sizeof(WCHAR) - 1; main_idx >= 0; main_idx--)
2531 {
2532 for (search_idx = 0; search_idx < MatchString->Length / sizeof(WCHAR); search_idx++)
2533 {
2534 if (SearchString->Buffer[main_idx] == MatchString->Buffer[search_idx])
2535 {
2536 *Position = main_idx * sizeof(WCHAR);
2537 return STATUS_SUCCESS;
2538 }
2539 }
2540 }
2541
2542 *Position = 0;
2543 return STATUS_NOT_FOUND;
2544 }
2545
2546 case 2:
2547 {
2548 for (main_idx = 0; main_idx < SearchString->Length / sizeof(WCHAR); main_idx++)
2549 {
2550 search_idx = 0;
2551
2552 while (search_idx < MatchString->Length / sizeof(WCHAR) &&
2553 SearchString->Buffer[main_idx] != MatchString->Buffer[search_idx])
2554 {
2555 search_idx++;
2556 }
2557
2558 if (search_idx >= MatchString->Length / sizeof(WCHAR))
2559 {
2560 *Position = (main_idx + 1) * sizeof(WCHAR);
2561 return STATUS_SUCCESS;
2562 }
2563 }
2564
2565 *Position = 0;
2566 return STATUS_NOT_FOUND;
2567 }
2568
2569 case 3:
2570 {
2571 for (main_idx = SearchString->Length / sizeof(WCHAR) - 1; main_idx >= 0; main_idx--)
2572 {
2573 search_idx = 0;
2574
2575 while (search_idx < MatchString->Length / sizeof(WCHAR) &&
2576 SearchString->Buffer[main_idx] != MatchString->Buffer[search_idx])
2577 {
2578 search_idx++;
2579 }
2580
2581 if (search_idx >= MatchString->Length / sizeof(WCHAR))
2582 {
2583 *Position = main_idx * sizeof(WCHAR);
2584 return STATUS_SUCCESS;
2585 }
2586 }
2587
2588 *Position = 0;
2589 return STATUS_NOT_FOUND;
2590 }
2591 }
2592
2593 return STATUS_NOT_FOUND;
2594 }
2595
2596 /*
2597 * @implemented
2598 *
2599 * NOTES
2600 * Get the maximum of MAX_COMPUTERNAME_LENGTH characters from the dns.host name until the dot is found.
2601 * Convert is to an uppercase oem string and check for unmapped characters.
2602 * Then convert the oem string back to an unicode string.
2603 */
2604 NTSTATUS
2605 NTAPI
2606 RtlDnsHostNameToComputerName(PUNICODE_STRING ComputerName, PUNICODE_STRING DnsHostName, BOOLEAN AllocateComputerNameString)
2607 {
2608 NTSTATUS Status;
2609 ULONG Length;
2610 ULONG ComputerNameLength;
2611 ULONG ComputerNameOemNLength;
2612 OEM_STRING ComputerNameOem;
2613 CHAR ComputerNameOemN[MAX_COMPUTERNAME_LENGTH + 1];
2614
2615 Status = STATUS_INVALID_COMPUTER_NAME;
2616 ComputerNameLength = DnsHostName->Length;
2617
2618 /* find the first dot in the dns host name */
2619 for (Length = 0; Length < DnsHostName->Length / sizeof(WCHAR); Length++)
2620 {
2621 if (DnsHostName->Buffer[Length] == L'.')
2622 {
2623 /* dot found, so set the length for the oem translation */
2624 ComputerNameLength = Length * sizeof(WCHAR);
2625 break;
2626 }
2627 }
2628
2629 /* the computername must have one character */
2630 if (ComputerNameLength > 0)
2631 {
2632 ComputerNameOemNLength = 0;
2633 /* convert to oem string and use uppercase letters */
2634 Status = RtlUpcaseUnicodeToOemN(ComputerNameOemN,
2635 MAX_COMPUTERNAME_LENGTH,
2636 &ComputerNameOemNLength,
2637 DnsHostName->Buffer,
2638 ComputerNameLength);
2639
2640 /* status STATUS_BUFFER_OVERFLOW is not a problem since the computername shoud only
2641 have MAX_COMPUTERNAME_LENGTH characters */
2642 if ((Status == STATUS_SUCCESS) ||
2643 (Status == STATUS_BUFFER_OVERFLOW))
2644 {
2645 /* set the termination for the oem string */
2646 ComputerNameOemN[MAX_COMPUTERNAME_LENGTH] = 0;
2647 /* set status for the case the next function failed */
2648 Status = STATUS_INVALID_COMPUTER_NAME;
2649 /* fillup the oem string structure with the converted computername
2650 and check it for unmapped characters */
2651 ComputerNameOem.Buffer = ComputerNameOemN;
2652 ComputerNameOem.Length = (USHORT)ComputerNameOemNLength;
2653 ComputerNameOem.MaximumLength = (USHORT)(MAX_COMPUTERNAME_LENGTH + 1);
2654
2655 if (RtlpDidUnicodeToOemWork(DnsHostName, &ComputerNameOem) == TRUE)
2656 {
2657 /* no unmapped character so convert it back to an unicode string */
2658 Status = RtlOemStringToUnicodeString(ComputerName,
2659 &ComputerNameOem,
2660 AllocateComputerNameString);
2661 }
2662 }
2663 }
2664
2665 return Status;
2666 }
2667