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