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