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