Merge from amd64-branch:
[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 ULONGLONG Val = Value->QuadPart;
1563 NTSTATUS Status = STATUS_SUCCESS;
1564 CHAR Buffer[65];
1565 CHAR Digit;
1566 ULONG Len;
1567 PCHAR Pos;
1568
1569 if (Base == 0) Base = 10;
1570
1571 if ((Base != 2) && (Base != 8) &&
1572 (Base != 10) && (Base != 16))
1573 {
1574 return STATUS_INVALID_PARAMETER;
1575 }
1576
1577 Pos = &Buffer[64];
1578 *Pos = '\0';
1579
1580 do
1581 {
1582 Pos--;
1583 Digit = Val % Base;
1584 Val = Val / Base;
1585 if (Digit < 10)
1586 *Pos = '0' + Digit;
1587 else
1588 *Pos = 'A' + Digit - 10;
1589 }
1590 while (Val != 0L);
1591
1592 Len = &Buffer[64] - Pos;
1593
1594 if (Len > Length)
1595 return STATUS_BUFFER_OVERFLOW;
1596
1597 #if 1 /* It needs to be removed, when will probably use SEH in rtl */
1598 if (String == NULL)
1599 {
1600 return STATUS_ACCESS_VIOLATION;
1601 }
1602 #endif
1603
1604 #if 0
1605 _SEH2_TRY
1606 {
1607 #endif
1608 if (Len == Length)
1609 RtlCopyMemory(String, Pos, Len);
1610 else
1611 RtlCopyMemory(String, Pos, Len + 1);
1612 #if 0
1613 }
1614 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
1615 {
1616 /* Get the error code */
1617 Status = _SEH2_GetExceptionCode();
1618 }
1619 _SEH2_END;
1620 #endif
1621
1622 return Status;
1623 }
1624
1625 /*
1626 * @implemented
1627 *
1628 * NOTES
1629 * dest is never '\0' terminated because it may be equal to src, and src
1630 * might not be '\0' terminated. dest->Length is only set upon success.
1631 */
1632 NTSTATUS
1633 NTAPI
1634 RtlUpcaseUnicodeString(
1635 IN OUT PUNICODE_STRING UniDest,
1636 IN PCUNICODE_STRING UniSource,
1637 IN BOOLEAN AllocateDestinationString)
1638 {
1639 ULONG i, j;
1640
1641 PAGED_CODE_RTL();
1642
1643 if (AllocateDestinationString == TRUE)
1644 {
1645 UniDest->MaximumLength = UniSource->Length;
1646 UniDest->Buffer = RtlpAllocateStringMemory(UniDest->MaximumLength, TAG_USTR);
1647 if (UniDest->Buffer == NULL) return STATUS_NO_MEMORY;
1648 }
1649 else if (UniSource->Length > UniDest->MaximumLength)
1650 {
1651 return STATUS_BUFFER_OVERFLOW;
1652 }
1653
1654 j = UniSource->Length / sizeof(WCHAR);
1655
1656 for (i = 0; i < j; i++)
1657 {
1658 UniDest->Buffer[i] = RtlUpcaseUnicodeChar(UniSource->Buffer[i]);
1659 }
1660
1661 UniDest->Length = UniSource->Length;
1662 return STATUS_SUCCESS;
1663 }
1664
1665 /*
1666 * @implemented
1667 *
1668 * NOTES
1669 * This function always writes a terminating '\0'.
1670 * It performs a partial copy if ansi is too small.
1671 */
1672 NTSTATUS
1673 NTAPI
1674 RtlUpcaseUnicodeStringToAnsiString(
1675 IN OUT PANSI_STRING AnsiDest,
1676 IN PUNICODE_STRING UniSource,
1677 IN BOOLEAN AllocateDestinationString)
1678 {
1679 NTSTATUS Status;
1680 ULONG Length;
1681 ULONG Index;
1682
1683 PAGED_CODE_RTL();
1684
1685 Length = RtlUnicodeStringToAnsiSize(UniSource);
1686 if (Length > MAXUSHORT) return STATUS_INVALID_PARAMETER_2;
1687
1688 AnsiDest->Length = (USHORT)Length - sizeof(CHAR);
1689
1690 if (AllocateDestinationString)
1691 {
1692 AnsiDest->Buffer = RtlpAllocateStringMemory(Length, TAG_ASTR);
1693 AnsiDest->MaximumLength = Length;
1694 if (!AnsiDest->Buffer) return STATUS_NO_MEMORY;
1695 }
1696 else if (AnsiDest->Length >= AnsiDest->MaximumLength)
1697 {
1698 if (!AnsiDest->MaximumLength) return STATUS_BUFFER_OVERFLOW;
1699 }
1700
1701 Status = RtlUpcaseUnicodeToMultiByteN(AnsiDest->Buffer,
1702 AnsiDest->Length,
1703 &Index,
1704 UniSource->Buffer,
1705 UniSource->Length);
1706
1707 if (!NT_SUCCESS(Status) && AllocateDestinationString)
1708 {
1709 RtlpFreeStringMemory(AnsiDest->Buffer, TAG_ASTR);
1710 AnsiDest->Buffer = NULL;
1711 return Status;
1712 }
1713
1714 AnsiDest->Buffer[Index] = ANSI_NULL;
1715 return Status;
1716 }
1717
1718 /*
1719 * @implemented
1720 *
1721 * NOTES
1722 * This function always writes a terminating '\0'.
1723 * It performs a partial copy if ansi is too small.
1724 */
1725 NTSTATUS
1726 NTAPI
1727 RtlUpcaseUnicodeStringToCountedOemString(
1728 IN OUT POEM_STRING OemDest,
1729 IN PCUNICODE_STRING UniSource,
1730 IN BOOLEAN AllocateDestinationString)
1731 {
1732 NTSTATUS Status;
1733 ULONG Length;
1734 ULONG Index;
1735
1736 PAGED_CODE_RTL();
1737
1738 Length = RtlUnicodeStringToCountedOemSize(UniSource);
1739
1740 if (!Length)
1741 {
1742 RtlZeroMemory(OemDest, sizeof(OEM_STRING));
1743 }
1744
1745 if (Length > MAXUSHORT) return STATUS_INVALID_PARAMETER_2;
1746
1747 OemDest->Length = (USHORT)Length;
1748
1749 if (AllocateDestinationString)
1750 {
1751 OemDest->Buffer = RtlpAllocateStringMemory(Length, TAG_OSTR);
1752 OemDest->MaximumLength = Length;
1753 if (!OemDest->Buffer) return STATUS_NO_MEMORY;
1754 }
1755 else if (OemDest->Length > OemDest->MaximumLength)
1756 {
1757 return STATUS_BUFFER_OVERFLOW;
1758 }
1759
1760 Status = RtlUpcaseUnicodeToOemN(OemDest->Buffer,
1761 OemDest->Length,
1762 &Index,
1763 UniSource->Buffer,
1764 UniSource->Length);
1765
1766 /* FIXME: Special check needed and return STATUS_UNMAPPABLE_CHARACTER */
1767
1768 if (!NT_SUCCESS(Status) && AllocateDestinationString)
1769 {
1770 RtlpFreeStringMemory(OemDest->Buffer, TAG_OSTR);
1771 OemDest->Buffer = NULL;
1772 return Status;
1773 }
1774
1775 return Status;
1776 }
1777
1778 /*
1779 * @implemented
1780 * NOTES
1781 * Oem string is allways nullterminated
1782 * It performs a partial copy if oem is too small.
1783 */
1784 NTSTATUS
1785 NTAPI
1786 RtlUpcaseUnicodeStringToOemString (
1787 IN OUT POEM_STRING OemDest,
1788 IN PCUNICODE_STRING UniSource,
1789 IN BOOLEAN AllocateDestinationString)
1790 {
1791 NTSTATUS Status;
1792 ULONG Length;
1793 ULONG Index;
1794
1795 PAGED_CODE_RTL();
1796
1797 Length = RtlUnicodeStringToOemSize(UniSource);
1798 if (Length > MAXUSHORT) return STATUS_INVALID_PARAMETER_2;
1799
1800 OemDest->Length = (USHORT)Length - sizeof(CHAR);
1801
1802 if (AllocateDestinationString)
1803 {
1804 OemDest->Buffer = RtlpAllocateStringMemory(Length, TAG_OSTR);
1805 OemDest->MaximumLength = Length;
1806 if (!OemDest->Buffer) return STATUS_NO_MEMORY;
1807 }
1808 else if (OemDest->Length >= OemDest->MaximumLength)
1809 {
1810 return STATUS_BUFFER_OVERFLOW;
1811 }
1812
1813 Status = RtlUpcaseUnicodeToOemN(OemDest->Buffer,
1814 OemDest->Length,
1815 &Index,
1816 UniSource->Buffer,
1817 UniSource->Length);
1818
1819 /* FIXME: Special check needed and return STATUS_UNMAPPABLE_CHARACTER */
1820
1821 if (!NT_SUCCESS(Status) && AllocateDestinationString)
1822 {
1823 RtlpFreeStringMemory(OemDest->Buffer, TAG_OSTR);
1824 OemDest->Buffer = NULL;
1825 return Status;
1826 }
1827
1828 OemDest->Buffer[Index] = ANSI_NULL;
1829 return Status;
1830 }
1831
1832 /*
1833 * @implemented
1834 *
1835 * RETURNS
1836 * Bytes calculated including nullterm
1837 */
1838 ULONG
1839 NTAPI
1840 RtlxOemStringToUnicodeSize(IN PCOEM_STRING OemString)
1841 {
1842 ULONG Size;
1843
1844 /* Convert the Mb String to Unicode Size */
1845 RtlMultiByteToUnicodeSize(&Size,
1846 OemString->Buffer,
1847 OemString->Length);
1848
1849 /* Return the size + null-char */
1850 return (Size + sizeof(WCHAR));
1851 }
1852
1853 /*
1854 * @implemented
1855 */
1856 NTSTATUS
1857 NTAPI
1858 RtlStringFromGUID (IN REFGUID Guid,
1859 OUT PUNICODE_STRING GuidString)
1860 {
1861 /* Setup the string */
1862 GuidString->Length = 38 * sizeof(WCHAR);
1863 GuidString->MaximumLength = GuidString->Length + sizeof(UNICODE_NULL);
1864 GuidString->Buffer = RtlpAllocateStringMemory(GuidString->MaximumLength,
1865 TAG_USTR);
1866 if (!GuidString->Buffer) return STATUS_NO_MEMORY;
1867
1868 /* Now format the GUID */
1869 swprintf(GuidString->Buffer,
1870 L"{%08lx-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x}",
1871 Guid->Data1,
1872 Guid->Data2,
1873 Guid->Data3,
1874 Guid->Data4[0],
1875 Guid->Data4[1],
1876 Guid->Data4[2],
1877 Guid->Data4[3],
1878 Guid->Data4[4],
1879 Guid->Data4[5],
1880 Guid->Data4[6],
1881 Guid->Data4[7]);
1882 return STATUS_SUCCESS;
1883 }
1884
1885 /*
1886 * @implemented
1887 *
1888 * RETURNS
1889 * Bytes calculated including nullterm
1890 */
1891 ULONG
1892 NTAPI
1893 RtlxUnicodeStringToAnsiSize(IN PCUNICODE_STRING UnicodeString)
1894 {
1895 ULONG Size;
1896
1897 /* Convert the Unicode String to Mb Size */
1898 RtlUnicodeToMultiByteSize(&Size,
1899 UnicodeString->Buffer,
1900 UnicodeString->Length);
1901
1902 /* Return the size + null-char */
1903 return (Size + sizeof(CHAR));
1904 }
1905
1906 /*
1907 * @implemented
1908 */
1909 LONG
1910 NTAPI
1911 RtlCompareUnicodeString(
1912 IN PCUNICODE_STRING s1,
1913 IN PCUNICODE_STRING s2,
1914 IN BOOLEAN CaseInsensitive)
1915 {
1916 unsigned int len;
1917 LONG ret = 0;
1918 LPCWSTR p1, p2;
1919
1920 len = min(s1->Length, s2->Length) / sizeof(WCHAR);
1921 p1 = s1->Buffer;
1922 p2 = s2->Buffer;
1923
1924 if (CaseInsensitive)
1925 {
1926 while (!ret && len--) ret = RtlUpcaseUnicodeChar(*p1++) - RtlUpcaseUnicodeChar(*p2++);
1927 }
1928 else
1929 {
1930 while (!ret && len--) ret = *p1++ - *p2++;
1931 }
1932 if (!ret) ret = s1->Length - s2->Length;
1933 return ret;
1934 }
1935
1936 /*
1937 * @implemented
1938 */
1939 VOID
1940 NTAPI
1941 RtlCopyString(
1942 IN OUT PSTRING DestinationString,
1943 IN PSTRING SourceString OPTIONAL)
1944 {
1945 ULONG SourceLength;
1946 PCHAR p1, p2;
1947
1948 /* Check if there was no source given */
1949 if(!SourceString)
1950 {
1951 /* Simply return an empty string */
1952 DestinationString->Length = 0;
1953 }
1954 else
1955 {
1956 /* Choose the smallest length */
1957 SourceLength = min(DestinationString->MaximumLength,
1958 SourceString->Length);
1959
1960 /* Set it */
1961 DestinationString->Length = (USHORT)SourceLength;
1962
1963 /* Save the pointers to each buffer */
1964 p1 = DestinationString->Buffer;
1965 p2 = SourceString->Buffer;
1966
1967 /* Loop the buffer */
1968 while (SourceLength)
1969 {
1970 /* Copy the character and move on */
1971 *p1++ = * p2++;
1972 SourceLength--;
1973 }
1974 }
1975 }
1976
1977 /*
1978 * @implemented
1979 */
1980 VOID
1981 NTAPI
1982 RtlCopyUnicodeString(
1983 IN OUT PUNICODE_STRING DestinationString,
1984 IN PCUNICODE_STRING SourceString)
1985 {
1986 ULONG SourceLength;
1987
1988 if(SourceString == NULL)
1989 {
1990 DestinationString->Length = 0;
1991 }
1992 else
1993 {
1994 SourceLength = min(DestinationString->MaximumLength,
1995 SourceString->Length);
1996 DestinationString->Length = (USHORT)SourceLength;
1997
1998 RtlCopyMemory(DestinationString->Buffer,
1999 SourceString->Buffer,
2000 SourceLength);
2001
2002 if (DestinationString->Length < DestinationString->MaximumLength)
2003 {
2004 DestinationString->Buffer[SourceLength / sizeof(WCHAR)] = UNICODE_NULL;
2005 }
2006 }
2007 }
2008
2009 /*
2010 * @implemented
2011 *
2012 * NOTES
2013 * Creates a nullterminated UNICODE_STRING
2014 */
2015 BOOLEAN
2016 NTAPI
2017 RtlCreateUnicodeString(
2018 IN OUT PUNICODE_STRING UniDest,
2019 IN PCWSTR Source)
2020 {
2021 ULONG Length;
2022
2023 PAGED_CODE_RTL();
2024
2025 Length = (wcslen(Source) + 1) * sizeof(WCHAR);
2026 if (Length > 0xFFFE) return FALSE;
2027
2028 UniDest->Buffer = RtlpAllocateStringMemory(Length, TAG_USTR);
2029
2030 if (UniDest->Buffer == NULL) return FALSE;
2031
2032 RtlCopyMemory(UniDest->Buffer, Source, Length);
2033 UniDest->MaximumLength = (USHORT)Length;
2034 UniDest->Length = Length - sizeof (WCHAR);
2035
2036 return TRUE;
2037 }
2038
2039 /*
2040 * @implemented
2041 */
2042 BOOLEAN
2043 NTAPI
2044 RtlCreateUnicodeStringFromAsciiz(
2045 OUT PUNICODE_STRING Destination,
2046 IN PCSZ Source)
2047 {
2048 ANSI_STRING AnsiString;
2049 NTSTATUS Status;
2050
2051 RtlInitAnsiString(&AnsiString, Source);
2052
2053 Status = RtlAnsiStringToUnicodeString(Destination,
2054 &AnsiString,
2055 TRUE);
2056
2057 return NT_SUCCESS(Status);
2058 }
2059
2060 /*
2061 * @implemented
2062 *
2063 * NOTES
2064 * Dest is never '\0' terminated because it may be equal to src, and src
2065 * might not be '\0' terminated.
2066 * Dest->Length is only set upon success.
2067 */
2068 NTSTATUS
2069 NTAPI
2070 RtlDowncaseUnicodeString(
2071 IN OUT PUNICODE_STRING UniDest,
2072 IN PCUNICODE_STRING UniSource,
2073 IN BOOLEAN AllocateDestinationString)
2074 {
2075 ULONG i;
2076 ULONG StopGap;
2077
2078 PAGED_CODE_RTL();
2079
2080 if (AllocateDestinationString)
2081 {
2082 UniDest->MaximumLength = UniSource->Length;
2083 UniDest->Buffer = RtlpAllocateStringMemory(UniSource->Length, TAG_USTR);
2084 if (UniDest->Buffer == NULL) return STATUS_NO_MEMORY;
2085 }
2086 else if (UniSource->Length > UniDest->MaximumLength)
2087 {
2088 return STATUS_BUFFER_OVERFLOW;
2089 }
2090
2091 UniDest->Length = UniSource->Length;
2092 StopGap = UniSource->Length / sizeof(WCHAR);
2093
2094 for (i= 0 ; i < StopGap; i++)
2095 {
2096 if (UniSource->Buffer[i] < L'A')
2097 {
2098 UniDest->Buffer[i] = UniSource->Buffer[i];
2099 }
2100 else if (UniSource->Buffer[i] <= L'Z')
2101 {
2102 UniDest->Buffer[i] = (UniSource->Buffer[i] + (L'a' - L'A'));
2103 }
2104 else
2105 {
2106 UniDest->Buffer[i] = RtlDowncaseUnicodeChar(UniSource->Buffer[i]);
2107 }
2108 }
2109
2110 return STATUS_SUCCESS;
2111 }
2112
2113 /*
2114 * @implemented
2115 *
2116 * NOTES
2117 * if src is NULL dest is unchanged.
2118 * dest is '\0' terminated when the MaximumLength allowes it.
2119 * When dest fits exactly in MaximumLength characters the '\0' is ommitted.
2120 */
2121 NTSTATUS
2122 NTAPI
2123 RtlAppendUnicodeToString(IN OUT PUNICODE_STRING Destination,
2124 IN PCWSTR Source)
2125 {
2126 USHORT Length;
2127 PWCHAR DestBuffer;
2128
2129 if (Source)
2130 {
2131 UNICODE_STRING UnicodeSource;
2132
2133 RtlInitUnicodeString(&UnicodeSource, Source);
2134 Length = UnicodeSource.Length;
2135
2136 if (Destination->Length + Length > Destination->MaximumLength)
2137 {
2138 return STATUS_BUFFER_TOO_SMALL;
2139 }
2140
2141 DestBuffer = &Destination->Buffer[Destination->Length / sizeof(WCHAR)];
2142 RtlMoveMemory(DestBuffer, Source, Length);
2143 Destination->Length += Length;
2144
2145 /* append terminating '\0' if enough space */
2146 if(Destination->MaximumLength > Destination->Length)
2147 {
2148 DestBuffer[Length / sizeof(WCHAR)] = UNICODE_NULL;
2149 }
2150 }
2151
2152 return STATUS_SUCCESS;
2153 }
2154
2155 /*
2156 * @implemented
2157 *
2158 * NOTES
2159 * if src is NULL dest is unchanged.
2160 * dest is never '\0' terminated.
2161 */
2162 NTSTATUS
2163 NTAPI
2164 RtlAppendAsciizToString(
2165 IN OUT PSTRING Destination,
2166 IN PCSZ Source)
2167 {
2168 ULONG Length;
2169
2170 if (Source)
2171 {
2172 Length = (USHORT)strlen(Source);
2173
2174 if (Destination->Length + Length > Destination->MaximumLength)
2175 {
2176 return STATUS_BUFFER_TOO_SMALL;
2177 }
2178
2179 RtlMoveMemory(&Destination->Buffer[Destination->Length], Source, Length);
2180 Destination->Length += Length;
2181 }
2182
2183 return STATUS_SUCCESS;
2184 }
2185
2186 /*
2187 * @implemented
2188 */
2189 VOID
2190 NTAPI
2191 RtlUpperString(PSTRING DestinationString,
2192 PSTRING SourceString)
2193 {
2194 ULONG Length;
2195 PCHAR Src, Dest;
2196
2197 Length = min(SourceString->Length,
2198 DestinationString->MaximumLength);
2199
2200 Src = SourceString->Buffer;
2201 Dest = DestinationString->Buffer;
2202 DestinationString->Length = Length;
2203 while (Length)
2204 {
2205 *Dest++ = RtlUpperChar(*Src++);
2206 Length--;
2207 }
2208 }
2209
2210 /*
2211 * @implemented
2212 *
2213 * NOTES
2214 * See RtlpDuplicateUnicodeString
2215 */
2216 NTSTATUS
2217 NTAPI
2218 RtlDuplicateUnicodeString(
2219 IN ULONG Flags,
2220 IN PCUNICODE_STRING SourceString,
2221 OUT PUNICODE_STRING DestinationString)
2222 {
2223 PAGED_CODE_RTL();
2224
2225 if (SourceString == NULL || DestinationString == NULL ||
2226 SourceString->Length > SourceString->MaximumLength ||
2227 (SourceString->Length == 0 && SourceString->MaximumLength > 0 && SourceString->Buffer == NULL) ||
2228 Flags == RTL_DUPLICATE_UNICODE_STRING_ALLOCATE_NULL_STRING || Flags >= 4) {
2229 return STATUS_INVALID_PARAMETER;
2230 }
2231
2232
2233 if ((SourceString->Length == 0) &&
2234 (Flags != (RTL_DUPLICATE_UNICODE_STRING_NULL_TERMINATE |
2235 RTL_DUPLICATE_UNICODE_STRING_ALLOCATE_NULL_STRING)))
2236 {
2237 DestinationString->Length = 0;
2238 DestinationString->MaximumLength = 0;
2239 DestinationString->Buffer = NULL;
2240 }
2241 else
2242 {
2243 UINT DestMaxLength = SourceString->Length;
2244
2245 if (Flags & RTL_DUPLICATE_UNICODE_STRING_NULL_TERMINATE)
2246 DestMaxLength += sizeof(UNICODE_NULL);
2247
2248 DestinationString->Buffer = RtlpAllocateStringMemory(DestMaxLength, TAG_USTR);
2249 if (DestinationString->Buffer == NULL)
2250 return STATUS_NO_MEMORY;
2251
2252 RtlCopyMemory(DestinationString->Buffer, SourceString->Buffer, SourceString->Length);
2253 DestinationString->Length = SourceString->Length;
2254 DestinationString->MaximumLength = DestMaxLength;
2255
2256 if (Flags & RTL_DUPLICATE_UNICODE_STRING_NULL_TERMINATE)
2257 DestinationString->Buffer[DestinationString->Length / sizeof(WCHAR)] = 0;
2258 }
2259
2260 return STATUS_SUCCESS;
2261 }
2262
2263 /*
2264 * @implemented
2265 */
2266 NTSTATUS NTAPI
2267 RtlValidateUnicodeString(IN ULONG Flags,
2268 IN PCUNICODE_STRING UnicodeString)
2269 {
2270 /* currently no flags are supported! */
2271 ASSERT(Flags == 0);
2272
2273 if ((Flags == 0) &&
2274 ((UnicodeString == NULL) ||
2275 ((UnicodeString->Length != 0) &&
2276 (UnicodeString->Buffer != NULL) &&
2277 ((UnicodeString->Length % sizeof(WCHAR)) == 0) &&
2278 ((UnicodeString->MaximumLength % sizeof(WCHAR)) == 0) &&
2279 (UnicodeString->MaximumLength >= UnicodeString->Length))))
2280 {
2281 /* a NULL pointer as a unicode string is considered to be a valid unicode
2282 string! */
2283 return STATUS_SUCCESS;
2284 }
2285 else
2286 {
2287 return STATUS_INVALID_PARAMETER;
2288 }
2289 }
2290
2291 NTSTATUS
2292 NTAPI
2293 RtlFindCharInUnicodeString(IN ULONG Flags,
2294 IN PUNICODE_STRING SearchString,
2295 IN PCUNICODE_STRING MatchString,
2296 OUT PUSHORT Position)
2297 {
2298 int main_idx;
2299 unsigned int search_idx;
2300
2301 switch (Flags)
2302 {
2303 case 0:
2304 {
2305 for (main_idx = 0; main_idx < SearchString->Length / sizeof(WCHAR); main_idx++)
2306 {
2307 for (search_idx = 0; search_idx < MatchString->Length / sizeof(WCHAR); search_idx++)
2308 {
2309 if (SearchString->Buffer[main_idx] == MatchString->Buffer[search_idx])
2310 {
2311 *Position = (main_idx + 1) * sizeof(WCHAR);
2312 return STATUS_SUCCESS;
2313 }
2314 }
2315 }
2316 *Position = 0;
2317 return STATUS_NOT_FOUND;
2318 }
2319
2320 case 1:
2321 {
2322 for (main_idx = SearchString->Length / sizeof(WCHAR) - 1; main_idx >= 0; main_idx--)
2323 {
2324 for (search_idx = 0; search_idx < MatchString->Length / sizeof(WCHAR); search_idx++)
2325 {
2326 if (SearchString->Buffer[main_idx] == MatchString->Buffer[search_idx])
2327 {
2328 *Position = main_idx * sizeof(WCHAR);
2329 return STATUS_SUCCESS;
2330 }
2331 }
2332 }
2333 *Position = 0;
2334 return STATUS_NOT_FOUND;
2335 }
2336
2337 case 2:
2338 {
2339 for (main_idx = 0; main_idx < SearchString->Length / sizeof(WCHAR); main_idx++)
2340 {
2341 search_idx = 0;
2342 while (search_idx < MatchString->Length / sizeof(WCHAR) &&
2343 SearchString->Buffer[main_idx] != MatchString->Buffer[search_idx])
2344 {
2345 search_idx++;
2346 }
2347 if (search_idx >= MatchString->Length / sizeof(WCHAR))
2348 {
2349 *Position = (main_idx + 1) * sizeof(WCHAR);
2350 return STATUS_SUCCESS;
2351 }
2352 }
2353 *Position = 0;
2354 return STATUS_NOT_FOUND;
2355 }
2356
2357 case 3:
2358 {
2359 for (main_idx = SearchString->Length / sizeof(WCHAR) - 1; main_idx >= 0; main_idx--)
2360 {
2361 search_idx = 0;
2362 while (search_idx < MatchString->Length / sizeof(WCHAR) &&
2363 SearchString->Buffer[main_idx] != MatchString->Buffer[search_idx])
2364 {
2365 search_idx++;
2366 }
2367 if (search_idx >= MatchString->Length / sizeof(WCHAR))
2368 {
2369 *Position = main_idx * sizeof(WCHAR);
2370 return STATUS_SUCCESS;
2371 }
2372 }
2373 *Position = 0;
2374 return STATUS_NOT_FOUND;
2375 }
2376 } /* switch */
2377
2378 return STATUS_NOT_FOUND;
2379 }