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