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