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