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