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