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) 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 if (pf && (*pf & IS_TEXT_UNICODE_DBCS_LEADBYTE)) 1382 out_flags |= IS_TEXT_UNICODE_DBCS_LEADBYTE; 1383 } 1384 } 1385 1386 if (lo_byte_diff < 127 && !hi_byte_diff) 1387 { 1388 out_flags |= IS_TEXT_UNICODE_ASCII16; 1389 } 1390 1391 if (hi_byte_diff && !lo_byte_diff) 1392 { 1393 out_flags |= IS_TEXT_UNICODE_REVERSE_ASCII16; 1394 } 1395 1396 if ((weight * lo_byte_diff) < hi_byte_diff) 1397 { 1398 out_flags |= IS_TEXT_UNICODE_REVERSE_STATISTICS; 1399 } 1400 1401 /* apply some statistical analysis */ 1402 if ((flags & IS_TEXT_UNICODE_STATISTICS) && 1403 ((weight * hi_byte_diff) < lo_byte_diff)) 1404 { 1405 out_flags |= IS_TEXT_UNICODE_STATISTICS; 1406 } 1407 1408 /* Check for unicode NULL chars */ 1409 if (flags & IS_TEXT_UNICODE_NULL_BYTES) 1410 { 1411 for (i = 0; i < len; i++) 1412 { 1413 if (!(s[i] & 0xff) || !(s[i] >> 8)) 1414 { 1415 out_flags |= IS_TEXT_UNICODE_NULL_BYTES; 1416 break; 1417 } 1418 } 1419 } 1420 1421 if (flags & IS_TEXT_UNICODE_CONTROLS) 1422 { 1423 for (i = 0; i < len; i++) 1424 { 1425 if (strchrW(std_control_chars, s[i])) 1426 { 1427 out_flags |= IS_TEXT_UNICODE_CONTROLS; 1428 break; 1429 } 1430 } 1431 } 1432 1433 if (flags & IS_TEXT_UNICODE_REVERSE_CONTROLS) 1434 { 1435 for (i = 0; i < len; i++) 1436 { 1437 if (strchrW(byterev_control_chars, s[i])) 1438 { 1439 out_flags |= IS_TEXT_UNICODE_REVERSE_CONTROLS; 1440 break; 1441 } 1442 } 1443 } 1444 1445 if (pf) 1446 { 1447 out_flags &= *pf; 1448 *pf = out_flags; 1449 } 1450 1451 /* check for flags that indicate it's definitely not valid Unicode */ 1452 if (out_flags & (IS_TEXT_UNICODE_REVERSE_MASK | IS_TEXT_UNICODE_NOT_UNICODE_MASK)) return FALSE; 1453 1454 /* now check for invalid ASCII, and assume Unicode if so */ 1455 if (out_flags & IS_TEXT_UNICODE_NOT_ASCII_MASK) return TRUE; 1456 1457 /* now check for Unicode flags */ 1458 if (out_flags & IS_TEXT_UNICODE_UNICODE_MASK) return TRUE; 1459 1460 /* no flags set */ 1461 return FALSE; 1462 } 1463 1464 1465 /* 1466 * @implemented 1467 * 1468 * NOTES 1469 * Same as RtlOemStringToUnicodeString but doesn't write terminating null 1470 * A partial copy is NOT performed if the dest buffer is too small! 1471 */ 1472 NTSTATUS 1473 NTAPI 1474 RtlOemStringToCountedUnicodeString( 1475 IN OUT PUNICODE_STRING UniDest, 1476 IN PCOEM_STRING OemSource, 1477 IN BOOLEAN AllocateDestinationString) 1478 { 1479 NTSTATUS Status; 1480 ULONG Length; 1481 ULONG Index; 1482 1483 PAGED_CODE_RTL(); 1484 1485 /* Calculate size of the string */ 1486 Length = RtlOemStringToCountedUnicodeSize(OemSource); 1487 1488 /* If it's 0 then zero out dest string and return */ 1489 if (!Length) 1490 { 1491 RtlZeroMemory(UniDest, sizeof(UNICODE_STRING)); 1492 return STATUS_SUCCESS; 1493 } 1494 1495 /* Check if length is a sane value */ 1496 if (Length > MAXUSHORT) return STATUS_INVALID_PARAMETER_2; 1497 1498 /* Store it in dest string */ 1499 UniDest->Length = (USHORT)Length; 1500 1501 /* If we're asked to alloc the string - do so */ 1502 if (AllocateDestinationString) 1503 { 1504 UniDest->Buffer = RtlpAllocateStringMemory(Length, TAG_USTR); 1505 UniDest->MaximumLength = (USHORT)Length; 1506 1507 if (!UniDest->Buffer) return STATUS_NO_MEMORY; 1508 } 1509 else if (UniDest->Length > UniDest->MaximumLength) 1510 { 1511 return STATUS_BUFFER_OVERFLOW; 1512 } 1513 1514 /* Do the conversion */ 1515 Status = RtlOemToUnicodeN(UniDest->Buffer, 1516 UniDest->Length, 1517 &Index, 1518 OemSource->Buffer, 1519 OemSource->Length); 1520 1521 if (!NT_SUCCESS(Status) && AllocateDestinationString) 1522 { 1523 /* Conversion failed, free dest string and return status code */ 1524 RtlpFreeStringMemory(UniDest->Buffer, TAG_USTR); 1525 UniDest->Buffer = NULL; 1526 return Status; 1527 } 1528 1529 return STATUS_SUCCESS; 1530 } 1531 1532 /* 1533 * @implemented 1534 * 1535 * RETURNS 1536 * TRUE if the names are equal, FALSE if not 1537 * 1538 * NOTES 1539 * The comparison is case insensitive. 1540 */ 1541 BOOLEAN 1542 NTAPI 1543 RtlEqualComputerName( 1544 IN PUNICODE_STRING ComputerName1, 1545 IN PUNICODE_STRING ComputerName2) 1546 { 1547 OEM_STRING OemString1; 1548 OEM_STRING OemString2; 1549 BOOLEAN Result = FALSE; 1550 1551 if (NT_SUCCESS(RtlUpcaseUnicodeStringToOemString(&OemString1, 1552 ComputerName1, 1553 TRUE))) 1554 { 1555 if (NT_SUCCESS(RtlUpcaseUnicodeStringToOemString(&OemString2, 1556 ComputerName2, 1557 TRUE))) 1558 { 1559 Result = RtlEqualString(&OemString1, &OemString2, FALSE); 1560 RtlFreeOemString(&OemString2); 1561 } 1562 1563 RtlFreeOemString(&OemString1); 1564 } 1565 1566 return Result; 1567 } 1568 1569 /* 1570 * @implemented 1571 * 1572 * RETURNS 1573 * TRUE if the names are equal, FALSE if not 1574 * 1575 * NOTES 1576 * The comparison is case insensitive. 1577 */ 1578 BOOLEAN 1579 NTAPI 1580 RtlEqualDomainName ( 1581 IN PUNICODE_STRING DomainName1, 1582 IN PUNICODE_STRING DomainName2) 1583 { 1584 return RtlEqualComputerName(DomainName1, DomainName2); 1585 } 1586 1587 /* 1588 * @implemented 1589 * 1590 * RIPPED FROM WINE's ntdll\rtlstr.c rev 1.45 1591 * 1592 * Convert a string representation of a GUID into a GUID. 1593 * 1594 * PARAMS 1595 * str [I] String representation in the format "{XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX}" 1596 * guid [O] Destination for the converted GUID 1597 * 1598 * RETURNS 1599 * Success: STATUS_SUCCESS. guid contains the converted value. 1600 * Failure: STATUS_INVALID_PARAMETER, if str is not in the expected format. 1601 * 1602 * SEE ALSO 1603 * See RtlStringFromGUID. 1604 */ 1605 NTSTATUS 1606 NTAPI 1607 RtlGUIDFromString( 1608 IN UNICODE_STRING *str, 1609 OUT GUID* guid) 1610 { 1611 int i = 0; 1612 const WCHAR *lpszCLSID = str->Buffer; 1613 BYTE* lpOut = (BYTE*)guid; 1614 1615 //TRACE("(%s,%p)\n", debugstr_us(str), guid); 1616 1617 /* Convert string: {XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX} 1618 * to memory: DWORD... WORD WORD BYTES............ 1619 */ 1620 while (i <= 37) 1621 { 1622 switch (i) 1623 { 1624 case 0: 1625 if (*lpszCLSID != '{') 1626 return STATUS_INVALID_PARAMETER; 1627 break; 1628 1629 case 9: 1630 case 14: 1631 case 19: 1632 case 24: 1633 if (*lpszCLSID != '-') 1634 return STATUS_INVALID_PARAMETER; 1635 break; 1636 1637 case 37: 1638 if (*lpszCLSID != '}') 1639 return STATUS_INVALID_PARAMETER; 1640 1641 break; 1642 1643 default: 1644 { 1645 WCHAR ch = *lpszCLSID, ch2 = lpszCLSID[1]; 1646 unsigned char byte; 1647 1648 /* Read two hex digits as a byte value */ 1649 if (ch >= '0' && ch <= '9') 1650 ch = ch - '0'; 1651 else if (ch >= 'a' && ch <= 'f') 1652 ch = ch - 'a' + 10; 1653 else if (ch >= 'A' && ch <= 'F') 1654 ch = ch - 'A' + 10; 1655 else 1656 return STATUS_INVALID_PARAMETER; 1657 1658 if (ch2 >= '0' && ch2 <= '9') 1659 ch2 = ch2 - '0'; 1660 else if (ch2 >= 'a' && ch2 <= 'f') 1661 ch2 = ch2 - 'a' + 10; 1662 else if (ch2 >= 'A' && ch2 <= 'F') 1663 ch2 = ch2 - 'A' + 10; 1664 else 1665 return STATUS_INVALID_PARAMETER; 1666 1667 byte = ch << 4 | ch2; 1668 1669 switch (i) 1670 { 1671 #ifndef WORDS_BIGENDIAN 1672 /* For Big Endian machines, we store the data such that the 1673 * dword/word members can be read as DWORDS and WORDS correctly. */ 1674 /* Dword */ 1675 case 1: 1676 lpOut[3] = byte; 1677 break; 1678 case 3: 1679 lpOut[2] = byte; 1680 break; 1681 case 5: 1682 lpOut[1] = byte; 1683 break; 1684 case 7: 1685 lpOut[0] = byte; 1686 lpOut += 4; 1687 break; 1688 /* Word */ 1689 case 10: 1690 case 15: 1691 lpOut[1] = byte; 1692 break; 1693 case 12: 1694 case 17: 1695 lpOut[0] = byte; 1696 lpOut += 2; 1697 break; 1698 #endif 1699 /* Byte */ 1700 default: 1701 lpOut[0] = byte; 1702 lpOut++; 1703 break; 1704 } 1705 1706 lpszCLSID++; /* Skip 2nd character of byte */ 1707 i++; 1708 } 1709 } 1710 1711 lpszCLSID++; 1712 i++; 1713 } 1714 1715 return STATUS_SUCCESS; 1716 } 1717 1718 /* 1719 * @implemented 1720 */ 1721 VOID 1722 NTAPI 1723 RtlEraseUnicodeString( 1724 IN PUNICODE_STRING String) 1725 { 1726 if (String->Buffer && String->MaximumLength) 1727 { 1728 RtlZeroMemory(String->Buffer, String->MaximumLength); 1729 String->Length = 0; 1730 } 1731 } 1732 1733 /* 1734 * @implemented 1735 */ 1736 NTSTATUS 1737 NTAPI 1738 RtlHashUnicodeString( 1739 IN CONST UNICODE_STRING *String, 1740 IN BOOLEAN CaseInSensitive, 1741 IN ULONG HashAlgorithm, 1742 OUT PULONG HashValue) 1743 { 1744 if (String != NULL && HashValue != NULL) 1745 { 1746 switch (HashAlgorithm) 1747 { 1748 case HASH_STRING_ALGORITHM_DEFAULT: 1749 case HASH_STRING_ALGORITHM_X65599: 1750 { 1751 WCHAR *c, *end; 1752 1753 *HashValue = 0; 1754 end = String->Buffer + (String->Length / sizeof(WCHAR)); 1755 1756 if (CaseInSensitive) 1757 { 1758 for (c = String->Buffer; c != end; c++) 1759 { 1760 /* only uppercase characters if they are 'a' ... 'z'! */ 1761 *HashValue = ((65599 * (*HashValue)) + 1762 (ULONG)(((*c) >= L'a' && (*c) <= L'z') ? 1763 (*c) - L'a' + L'A' : (*c))); 1764 } 1765 } 1766 else 1767 { 1768 for (c = String->Buffer; c != end; c++) 1769 { 1770 *HashValue = ((65599 * (*HashValue)) + (ULONG)(*c)); 1771 } 1772 } 1773 1774 return STATUS_SUCCESS; 1775 } 1776 } 1777 } 1778 1779 return STATUS_INVALID_PARAMETER; 1780 } 1781 1782 /* 1783 * @implemented 1784 * 1785 * NOTES 1786 * Same as RtlUnicodeStringToOemString but doesn't write terminating null 1787 */ 1788 _IRQL_requires_max_(PASSIVE_LEVEL) 1789 _Must_inspect_result_ 1790 NTSYSAPI 1791 NTSTATUS 1792 NTAPI 1793 RtlUnicodeStringToCountedOemString( 1794 _When_(AllocateDestinationString, _Out_ _At_(DestinationString->Buffer, __drv_allocatesMem(Mem))) 1795 _When_(!AllocateDestinationString, _Inout_) 1796 POEM_STRING OemDest, 1797 _In_ PCUNICODE_STRING UniSource, 1798 _In_ BOOLEAN AllocateDestinationString) 1799 { 1800 NTSTATUS Status; 1801 ULONG Length; 1802 ULONG Index; 1803 1804 PAGED_CODE_RTL(); 1805 1806 /* Calculate size of the string */ 1807 Length = RtlUnicodeStringToCountedOemSize(UniSource); 1808 1809 /* If it's 0 then zero out dest string and return */ 1810 if (!Length) 1811 { 1812 RtlZeroMemory(OemDest, sizeof(OEM_STRING)); 1813 return STATUS_SUCCESS; 1814 } 1815 1816 /* Check if length is a sane value */ 1817 if (Length > MAXUSHORT) return STATUS_INVALID_PARAMETER_2; 1818 1819 /* Store it in dest string */ 1820 OemDest->Length = (USHORT)Length; 1821 1822 /* If we're asked to alloc the string - do so */ 1823 if (AllocateDestinationString) 1824 { 1825 OemDest->Buffer = RtlpAllocateStringMemory(Length, TAG_OSTR); 1826 OemDest->MaximumLength = (USHORT)Length; 1827 if (!OemDest->Buffer) return STATUS_NO_MEMORY; 1828 } 1829 else if (OemDest->Length > OemDest->MaximumLength) 1830 { 1831 return STATUS_BUFFER_OVERFLOW; 1832 } 1833 1834 /* Do the conversion */ 1835 Status = RtlUnicodeToOemN(OemDest->Buffer, 1836 OemDest->Length, 1837 &Index, 1838 UniSource->Buffer, 1839 UniSource->Length); 1840 1841 /* Check for unmapped character */ 1842 if (NT_SUCCESS(Status) && !RtlpDidUnicodeToOemWork(UniSource, OemDest)) 1843 Status = STATUS_UNMAPPABLE_CHARACTER; 1844 1845 if (!NT_SUCCESS(Status) && AllocateDestinationString) 1846 { 1847 /* Conversion failed, free dest string and return status code */ 1848 RtlpFreeStringMemory(OemDest->Buffer, TAG_OSTR); 1849 OemDest->Buffer = NULL; 1850 return Status; 1851 } 1852 1853 return Status; 1854 } 1855 1856 /* 1857 * @implemented 1858 */ 1859 NTSTATUS 1860 NTAPI 1861 RtlLargeIntegerToChar( 1862 IN PLARGE_INTEGER Value, 1863 IN ULONG Base, 1864 IN ULONG Length, 1865 IN OUT PCHAR String) 1866 { 1867 ULONGLONG Val = Value->QuadPart; 1868 CHAR Buffer[65]; 1869 CHAR Digit; 1870 SIZE_T Len; 1871 PCHAR Pos; 1872 1873 if (Base == 0) Base = 10; 1874 1875 if ((Base != 2) && (Base != 8) && (Base != 10) && (Base != 16)) 1876 { 1877 return STATUS_INVALID_PARAMETER; 1878 } 1879 1880 Pos = &Buffer[64]; 1881 *Pos = '\0'; 1882 1883 do 1884 { 1885 Pos--; 1886 Digit = (CHAR)(Val % Base); 1887 Val = Val / Base; 1888 1889 if (Digit < 10) 1890 *Pos = '0' + Digit; 1891 else 1892 *Pos = 'A' + Digit - 10; 1893 } 1894 while (Val != 0L); 1895 1896 Len = &Buffer[64] - Pos; 1897 1898 if (Len > Length) 1899 return STATUS_BUFFER_OVERFLOW; 1900 1901 /* If possible, add the 0 termination */ 1902 if (Len < Length) 1903 Len += 1; 1904 1905 /* Copy the string to the target using SEH */ 1906 return RtlpSafeCopyMemory(String, Pos, Len); 1907 } 1908 1909 /* 1910 * @implemented 1911 * 1912 * NOTES 1913 * dest is never '\0' terminated because it may be equal to src, and src 1914 * might not be '\0' terminated. dest->Length is only set upon success. 1915 */ 1916 NTSTATUS 1917 NTAPI 1918 RtlUpcaseUnicodeString( 1919 IN OUT PUNICODE_STRING UniDest, 1920 IN PCUNICODE_STRING UniSource, 1921 IN BOOLEAN AllocateDestinationString) 1922 { 1923 ULONG i, j; 1924 1925 PAGED_CODE_RTL(); 1926 1927 if (AllocateDestinationString) 1928 { 1929 UniDest->MaximumLength = UniSource->Length; 1930 UniDest->Buffer = RtlpAllocateStringMemory(UniDest->MaximumLength, TAG_USTR); 1931 if (UniDest->Buffer == NULL) return STATUS_NO_MEMORY; 1932 } 1933 else if (UniSource->Length > UniDest->MaximumLength) 1934 { 1935 return STATUS_BUFFER_OVERFLOW; 1936 } 1937 1938 j = UniSource->Length / sizeof(WCHAR); 1939 1940 for (i = 0; i < j; i++) 1941 { 1942 UniDest->Buffer[i] = RtlpUpcaseUnicodeChar(UniSource->Buffer[i]); 1943 } 1944 1945 UniDest->Length = UniSource->Length; 1946 return STATUS_SUCCESS; 1947 } 1948 1949 /* 1950 * @implemented 1951 * 1952 * NOTES 1953 * This function always writes a terminating '\0'. 1954 * It performs a partial copy if ansi is too small. 1955 */ 1956 NTSTATUS 1957 NTAPI 1958 RtlUpcaseUnicodeStringToAnsiString( 1959 IN OUT PANSI_STRING AnsiDest, 1960 IN PCUNICODE_STRING UniSource, 1961 IN BOOLEAN AllocateDestinationString) 1962 { 1963 NTSTATUS Status; 1964 ULONG Length; 1965 ULONG Index; 1966 PAGED_CODE_RTL(); 1967 1968 Length = RtlUnicodeStringToAnsiSize(UniSource); 1969 if (Length > MAXUSHORT) return STATUS_INVALID_PARAMETER_2; 1970 1971 AnsiDest->Length = (USHORT)Length - sizeof(CHAR); 1972 1973 if (AllocateDestinationString) 1974 { 1975 AnsiDest->Buffer = RtlpAllocateStringMemory(Length, TAG_ASTR); 1976 AnsiDest->MaximumLength = (USHORT)Length; 1977 if (!AnsiDest->Buffer) return STATUS_NO_MEMORY; 1978 } 1979 else if (AnsiDest->Length >= AnsiDest->MaximumLength) 1980 { 1981 if (!AnsiDest->MaximumLength) return STATUS_BUFFER_OVERFLOW; 1982 } 1983 1984 Status = RtlUpcaseUnicodeToMultiByteN(AnsiDest->Buffer, 1985 AnsiDest->Length, 1986 &Index, 1987 UniSource->Buffer, 1988 UniSource->Length); 1989 1990 if (!NT_SUCCESS(Status) && AllocateDestinationString) 1991 { 1992 RtlpFreeStringMemory(AnsiDest->Buffer, TAG_ASTR); 1993 AnsiDest->Buffer = NULL; 1994 return Status; 1995 } 1996 1997 AnsiDest->Buffer[Index] = ANSI_NULL; 1998 return Status; 1999 } 2000 2001 /* 2002 * @implemented 2003 * 2004 * NOTES 2005 * This function always writes a terminating '\0'. 2006 * It performs a partial copy if ansi is too small. 2007 */ 2008 NTSTATUS 2009 NTAPI 2010 RtlUpcaseUnicodeStringToCountedOemString( 2011 IN OUT POEM_STRING OemDest, 2012 IN PCUNICODE_STRING UniSource, 2013 IN BOOLEAN AllocateDestinationString) 2014 { 2015 NTSTATUS Status; 2016 ULONG Length; 2017 ULONG Index; 2018 PAGED_CODE_RTL(); 2019 2020 Length = RtlUnicodeStringToCountedOemSize(UniSource); 2021 2022 if (!Length) 2023 { 2024 RtlZeroMemory(OemDest, sizeof(OEM_STRING)); 2025 } 2026 2027 if (Length > MAXUSHORT) return STATUS_INVALID_PARAMETER_2; 2028 2029 OemDest->Length = (USHORT)Length; 2030 2031 if (AllocateDestinationString) 2032 { 2033 OemDest->Buffer = RtlpAllocateStringMemory(Length, TAG_OSTR); 2034 OemDest->MaximumLength = (USHORT)Length; 2035 if (!OemDest->Buffer) return STATUS_NO_MEMORY; 2036 } 2037 else if (OemDest->Length > OemDest->MaximumLength) 2038 { 2039 return STATUS_BUFFER_OVERFLOW; 2040 } 2041 2042 Status = RtlUpcaseUnicodeToOemN(OemDest->Buffer, 2043 OemDest->Length, 2044 &Index, 2045 UniSource->Buffer, 2046 UniSource->Length); 2047 2048 /* Check for unmapped characters */ 2049 if (NT_SUCCESS(Status) && !RtlpDidUnicodeToOemWork(UniSource, OemDest)) 2050 Status = STATUS_UNMAPPABLE_CHARACTER; 2051 2052 if (!NT_SUCCESS(Status) && AllocateDestinationString) 2053 { 2054 RtlpFreeStringMemory(OemDest->Buffer, TAG_OSTR); 2055 OemDest->Buffer = NULL; 2056 return Status; 2057 } 2058 2059 return Status; 2060 } 2061 2062 /* 2063 * @implemented 2064 * NOTES 2065 * OEM string is always nullterminated 2066 * It performs a partial copy if oem is too small. 2067 */ 2068 NTSTATUS 2069 NTAPI 2070 RtlUpcaseUnicodeStringToOemString ( 2071 IN OUT POEM_STRING OemDest, 2072 IN PCUNICODE_STRING UniSource, 2073 IN BOOLEAN AllocateDestinationString) 2074 { 2075 NTSTATUS Status; 2076 ULONG Length; 2077 ULONG Index; 2078 PAGED_CODE_RTL(); 2079 2080 Length = RtlUnicodeStringToOemSize(UniSource); 2081 if (Length > MAXUSHORT) return STATUS_INVALID_PARAMETER_2; 2082 2083 OemDest->Length = (USHORT)Length - sizeof(CHAR); 2084 2085 if (AllocateDestinationString) 2086 { 2087 OemDest->Buffer = RtlpAllocateStringMemory(Length, TAG_OSTR); 2088 OemDest->MaximumLength = (USHORT)Length; 2089 if (!OemDest->Buffer) return STATUS_NO_MEMORY; 2090 } 2091 else if (OemDest->Length >= OemDest->MaximumLength) 2092 { 2093 return STATUS_BUFFER_OVERFLOW; 2094 } 2095 2096 Status = RtlUpcaseUnicodeToOemN(OemDest->Buffer, 2097 OemDest->Length, 2098 &Index, 2099 UniSource->Buffer, 2100 UniSource->Length); 2101 2102 /* Check for unmapped characters */ 2103 if (NT_SUCCESS(Status) && !RtlpDidUnicodeToOemWork(UniSource, OemDest)) 2104 Status = STATUS_UNMAPPABLE_CHARACTER; 2105 2106 if (!NT_SUCCESS(Status) && AllocateDestinationString) 2107 { 2108 RtlpFreeStringMemory(OemDest->Buffer, TAG_OSTR); 2109 OemDest->Buffer = NULL; 2110 return Status; 2111 } 2112 2113 OemDest->Buffer[Index] = ANSI_NULL; 2114 return Status; 2115 } 2116 2117 /* 2118 * @implemented 2119 * 2120 * RETURNS 2121 * Bytes calculated including nullterm 2122 */ 2123 ULONG 2124 NTAPI 2125 RtlxOemStringToUnicodeSize(IN PCOEM_STRING OemString) 2126 { 2127 ULONG Size; 2128 2129 /* Convert the Mb String to Unicode Size */ 2130 RtlMultiByteToUnicodeSize(&Size, 2131 OemString->Buffer, 2132 OemString->Length); 2133 2134 /* Return the size + null-char */ 2135 return (Size + sizeof(WCHAR)); 2136 } 2137 2138 /* 2139 * @implemented 2140 */ 2141 NTSTATUS 2142 NTAPI 2143 RtlStringFromGUID (IN REFGUID Guid, 2144 OUT PUNICODE_STRING GuidString) 2145 { 2146 /* Setup the string */ 2147 GuidString->Length = 38 * sizeof(WCHAR); 2148 GuidString->MaximumLength = GuidString->Length + sizeof(UNICODE_NULL); 2149 GuidString->Buffer = RtlpAllocateStringMemory(GuidString->MaximumLength, 2150 TAG_USTR); 2151 if (!GuidString->Buffer) return STATUS_NO_MEMORY; 2152 2153 /* Now format the GUID */ 2154 swprintf(GuidString->Buffer, 2155 L"{%08lx-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x}", 2156 Guid->Data1, 2157 Guid->Data2, 2158 Guid->Data3, 2159 Guid->Data4[0], 2160 Guid->Data4[1], 2161 Guid->Data4[2], 2162 Guid->Data4[3], 2163 Guid->Data4[4], 2164 Guid->Data4[5], 2165 Guid->Data4[6], 2166 Guid->Data4[7]); 2167 return STATUS_SUCCESS; 2168 } 2169 2170 /* 2171 * @implemented 2172 * 2173 * RETURNS 2174 * Bytes calculated including nullterm 2175 */ 2176 ULONG 2177 NTAPI 2178 RtlxUnicodeStringToAnsiSize(IN PCUNICODE_STRING UnicodeString) 2179 { 2180 ULONG Size; 2181 PAGED_CODE_RTL(); 2182 2183 ASSERT(!(UnicodeString->Length & 1)); 2184 2185 /* Convert the Unicode String to Mb Size */ 2186 RtlUnicodeToMultiByteSize(&Size, 2187 UnicodeString->Buffer, 2188 UnicodeString->Length); 2189 2190 /* Return the size + null-char */ 2191 return (Size + sizeof(CHAR)); 2192 } 2193 2194 /* 2195 * @implemented 2196 */ 2197 LONG 2198 NTAPI 2199 RtlCompareUnicodeString( 2200 IN PCUNICODE_STRING s1, 2201 IN PCUNICODE_STRING s2, 2202 IN BOOLEAN CaseInsensitive) 2203 { 2204 unsigned int len; 2205 LONG ret = 0; 2206 LPCWSTR p1, p2; 2207 2208 len = min(s1->Length, s2->Length) / sizeof(WCHAR); 2209 p1 = s1->Buffer; 2210 p2 = s2->Buffer; 2211 2212 if (CaseInsensitive) 2213 { 2214 while (!ret && len--) ret = RtlpUpcaseUnicodeChar(*p1++) - RtlpUpcaseUnicodeChar(*p2++); 2215 } 2216 else 2217 { 2218 while (!ret && len--) ret = *p1++ - *p2++; 2219 } 2220 2221 if (!ret) ret = s1->Length - s2->Length; 2222 2223 return ret; 2224 } 2225 2226 /* 2227 * @implemented 2228 */ 2229 VOID 2230 NTAPI 2231 RtlCopyString( 2232 IN OUT PSTRING DestinationString, 2233 IN const STRING *SourceString OPTIONAL) 2234 { 2235 ULONG SourceLength; 2236 PCHAR p1, p2; 2237 2238 /* Check if there was no source given */ 2239 if (!SourceString) 2240 { 2241 /* Simply return an empty string */ 2242 DestinationString->Length = 0; 2243 } 2244 else 2245 { 2246 /* Choose the smallest length */ 2247 SourceLength = min(DestinationString->MaximumLength, 2248 SourceString->Length); 2249 2250 /* Set it */ 2251 DestinationString->Length = (USHORT)SourceLength; 2252 2253 /* Save the pointers to each buffer */ 2254 p1 = DestinationString->Buffer; 2255 p2 = SourceString->Buffer; 2256 2257 /* Loop the buffer */ 2258 while (SourceLength) 2259 { 2260 /* Copy the character and move on */ 2261 *p1++ = * p2++; 2262 SourceLength--; 2263 } 2264 } 2265 } 2266 2267 /* 2268 * @implemented 2269 */ 2270 VOID 2271 NTAPI 2272 RtlCopyUnicodeString( 2273 IN OUT PUNICODE_STRING DestinationString, 2274 IN PCUNICODE_STRING SourceString) 2275 { 2276 ULONG SourceLength; 2277 2278 if (!SourceString) 2279 { 2280 DestinationString->Length = 0; 2281 } 2282 else 2283 { 2284 SourceLength = min(DestinationString->MaximumLength, 2285 SourceString->Length); 2286 DestinationString->Length = (USHORT)SourceLength; 2287 2288 RtlCopyMemory(DestinationString->Buffer, 2289 SourceString->Buffer, 2290 SourceLength); 2291 2292 if (DestinationString->Length < DestinationString->MaximumLength) 2293 { 2294 DestinationString->Buffer[SourceLength / sizeof(WCHAR)] = UNICODE_NULL; 2295 } 2296 } 2297 } 2298 2299 /* 2300 * @implemented 2301 * 2302 * NOTES 2303 * Creates a nullterminated UNICODE_STRING 2304 */ 2305 BOOLEAN 2306 NTAPI 2307 RtlCreateUnicodeString( 2308 IN OUT PUNICODE_STRING UniDest, 2309 IN PCWSTR Source) 2310 { 2311 SIZE_T Size; 2312 PAGED_CODE_RTL(); 2313 2314 Size = (wcslen(Source) + 1) * sizeof(WCHAR); 2315 if (Size > MAXUSHORT) return FALSE; 2316 2317 UniDest->Buffer = RtlpAllocateStringMemory((ULONG)Size, TAG_USTR); 2318 2319 if (UniDest->Buffer == NULL) return FALSE; 2320 2321 RtlCopyMemory(UniDest->Buffer, Source, Size); 2322 UniDest->MaximumLength = (USHORT)Size; 2323 UniDest->Length = (USHORT)Size - sizeof (WCHAR); 2324 2325 return TRUE; 2326 } 2327 2328 /* 2329 * @implemented 2330 */ 2331 BOOLEAN 2332 NTAPI 2333 RtlCreateUnicodeStringFromAsciiz( 2334 OUT PUNICODE_STRING Destination, 2335 IN PCSZ Source) 2336 { 2337 ANSI_STRING AnsiString; 2338 NTSTATUS Status; 2339 2340 RtlInitAnsiString(&AnsiString, Source); 2341 2342 Status = RtlAnsiStringToUnicodeString(Destination, 2343 &AnsiString, 2344 TRUE); 2345 2346 return NT_SUCCESS(Status); 2347 } 2348 2349 /* 2350 * @implemented 2351 * 2352 * NOTES 2353 * Dest is never '\0' terminated because it may be equal to src, and src 2354 * might not be '\0' terminated. 2355 * Dest->Length is only set upon success. 2356 */ 2357 NTSTATUS 2358 NTAPI 2359 RtlDowncaseUnicodeString( 2360 IN OUT PUNICODE_STRING UniDest, 2361 IN PCUNICODE_STRING UniSource, 2362 IN BOOLEAN AllocateDestinationString) 2363 { 2364 ULONG i; 2365 ULONG StopGap; 2366 PAGED_CODE_RTL(); 2367 2368 if (AllocateDestinationString) 2369 { 2370 UniDest->MaximumLength = UniSource->Length; 2371 UniDest->Buffer = RtlpAllocateStringMemory(UniSource->Length, TAG_USTR); 2372 if (UniDest->Buffer == NULL) return STATUS_NO_MEMORY; 2373 } 2374 else if (UniSource->Length > UniDest->MaximumLength) 2375 { 2376 return STATUS_BUFFER_OVERFLOW; 2377 } 2378 2379 UniDest->Length = UniSource->Length; 2380 StopGap = UniSource->Length / sizeof(WCHAR); 2381 2382 for (i = 0 ; i < StopGap; i++) 2383 { 2384 if (UniSource->Buffer[i] < L'A') 2385 { 2386 UniDest->Buffer[i] = UniSource->Buffer[i]; 2387 } 2388 else if (UniSource->Buffer[i] <= L'Z') 2389 { 2390 UniDest->Buffer[i] = (UniSource->Buffer[i] + (L'a' - L'A')); 2391 } 2392 else 2393 { 2394 UniDest->Buffer[i] = RtlpDowncaseUnicodeChar(UniSource->Buffer[i]); 2395 } 2396 } 2397 2398 return STATUS_SUCCESS; 2399 } 2400 2401 /* 2402 * @implemented 2403 * 2404 * NOTES 2405 * if src is NULL dest is unchanged. 2406 * dest is '\0' terminated when the MaximumLength allowes it. 2407 * When dest fits exactly in MaximumLength characters the '\0' is ommitted. 2408 */ 2409 NTSTATUS 2410 NTAPI 2411 RtlAppendUnicodeToString(IN OUT PUNICODE_STRING Destination, 2412 IN PCWSTR Source) 2413 { 2414 USHORT Length; 2415 PWCHAR DestBuffer; 2416 2417 if (Source) 2418 { 2419 UNICODE_STRING UnicodeSource; 2420 2421 RtlInitUnicodeString(&UnicodeSource, Source); 2422 Length = UnicodeSource.Length; 2423 2424 if (Destination->Length + Length > Destination->MaximumLength) 2425 { 2426 return STATUS_BUFFER_TOO_SMALL; 2427 } 2428 2429 DestBuffer = &Destination->Buffer[Destination->Length / sizeof(WCHAR)]; 2430 RtlMoveMemory(DestBuffer, Source, Length); 2431 Destination->Length += Length; 2432 2433 /* append terminating '\0' if enough space */ 2434 if (Destination->MaximumLength > Destination->Length) 2435 { 2436 DestBuffer[Length / sizeof(WCHAR)] = UNICODE_NULL; 2437 } 2438 } 2439 2440 return STATUS_SUCCESS; 2441 } 2442 2443 /* 2444 * @implemented 2445 * 2446 * NOTES 2447 * if src is NULL dest is unchanged. 2448 * dest is never '\0' terminated. 2449 */ 2450 NTSTATUS 2451 NTAPI 2452 RtlAppendAsciizToString( 2453 IN OUT PSTRING Destination, 2454 IN PCSZ Source) 2455 { 2456 SIZE_T Size; 2457 2458 if (Source) 2459 { 2460 Size = strlen(Source); 2461 2462 if (Destination->Length + Size > Destination->MaximumLength) 2463 { 2464 return STATUS_BUFFER_TOO_SMALL; 2465 } 2466 2467 RtlMoveMemory(&Destination->Buffer[Destination->Length], Source, Size); 2468 Destination->Length += (USHORT)Size; 2469 } 2470 2471 return STATUS_SUCCESS; 2472 } 2473 2474 /* 2475 * @implemented 2476 */ 2477 VOID 2478 NTAPI 2479 RtlUpperString(PSTRING DestinationString, 2480 const STRING *SourceString) 2481 { 2482 USHORT Length; 2483 PCHAR Src, Dest; 2484 2485 Length = min(SourceString->Length, 2486 DestinationString->MaximumLength); 2487 2488 Src = SourceString->Buffer; 2489 Dest = DestinationString->Buffer; 2490 DestinationString->Length = Length; 2491 2492 while (Length) 2493 { 2494 *Dest++ = RtlUpperChar(*Src++); 2495 Length--; 2496 } 2497 } 2498 2499 /* 2500 * @implemented 2501 * 2502 * NOTES 2503 * See RtlpDuplicateUnicodeString 2504 */ 2505 NTSTATUS 2506 NTAPI 2507 RtlDuplicateUnicodeString( 2508 IN ULONG Flags, 2509 IN PCUNICODE_STRING SourceString, 2510 OUT PUNICODE_STRING DestinationString) 2511 { 2512 PAGED_CODE_RTL(); 2513 2514 if (SourceString == NULL || DestinationString == NULL || 2515 SourceString->Length > SourceString->MaximumLength || 2516 (SourceString->Length == 0 && SourceString->MaximumLength > 0 && SourceString->Buffer == NULL) || 2517 Flags == RTL_DUPLICATE_UNICODE_STRING_ALLOCATE_NULL_STRING || Flags >= 4) 2518 { 2519 return STATUS_INVALID_PARAMETER; 2520 } 2521 2522 2523 if ((SourceString->Length == 0) && 2524 (Flags != (RTL_DUPLICATE_UNICODE_STRING_NULL_TERMINATE | 2525 RTL_DUPLICATE_UNICODE_STRING_ALLOCATE_NULL_STRING))) 2526 { 2527 DestinationString->Length = 0; 2528 DestinationString->MaximumLength = 0; 2529 DestinationString->Buffer = NULL; 2530 } 2531 else 2532 { 2533 UINT DestMaxLength = SourceString->Length; 2534 2535 if (Flags & RTL_DUPLICATE_UNICODE_STRING_NULL_TERMINATE) 2536 DestMaxLength += sizeof(UNICODE_NULL); 2537 2538 DestinationString->Buffer = RtlpAllocateStringMemory(DestMaxLength, TAG_USTR); 2539 2540 if (DestinationString->Buffer == NULL) 2541 return STATUS_NO_MEMORY; 2542 2543 RtlCopyMemory(DestinationString->Buffer, SourceString->Buffer, SourceString->Length); 2544 DestinationString->Length = SourceString->Length; 2545 DestinationString->MaximumLength = DestMaxLength; 2546 2547 if (Flags & RTL_DUPLICATE_UNICODE_STRING_NULL_TERMINATE) 2548 DestinationString->Buffer[DestinationString->Length / sizeof(WCHAR)] = 0; 2549 } 2550 2551 return STATUS_SUCCESS; 2552 } 2553 2554 /* 2555 * @implemented 2556 */ 2557 NTSTATUS 2558 NTAPI 2559 RtlValidateUnicodeString( 2560 _In_ ULONG Flags, 2561 _In_ PCUNICODE_STRING String) 2562 { 2563 /* In Windows <= 2003 no flags are supported yet! */ 2564 if (Flags != 0) 2565 return STATUS_INVALID_PARAMETER; 2566 2567 /* NOTE: a NULL Unicode string pointer is considered to be a valid one! */ 2568 if (String == NULL) 2569 { 2570 return STATUS_SUCCESS; 2571 } 2572 else if (!((String->Buffer == NULL) && (String->Length != 0 || String->MaximumLength != 0)) && 2573 (String->Length % sizeof(WCHAR) == 0) && 2574 (String->MaximumLength % sizeof(WCHAR) == 0) && 2575 (String->Length <= String->MaximumLength)) 2576 { 2577 return STATUS_SUCCESS; 2578 } 2579 else 2580 { 2581 return STATUS_INVALID_PARAMETER; 2582 } 2583 } 2584 2585 /* 2586 * @implemented 2587 */ 2588 NTSTATUS 2589 NTAPI 2590 RtlpEnsureBufferSize( 2591 IN ULONG Flags, 2592 IN OUT PRTL_BUFFER Buffer, 2593 IN SIZE_T RequiredSize) 2594 { 2595 PUCHAR NewBuffer; 2596 2597 /* Parameter checks */ 2598 if (Flags & ~RTL_SKIP_BUFFER_COPY) 2599 return STATUS_INVALID_PARAMETER; 2600 if (Buffer == NULL) 2601 return STATUS_INVALID_PARAMETER; 2602 2603 /* 2604 * We don't need to grow the buffer if its size 2605 * is already larger than the required size. 2606 */ 2607 if (Buffer->Size >= RequiredSize) 2608 return STATUS_SUCCESS; 2609 2610 /* 2611 * When we are using the static buffer as our buffer, we don't need 2612 * to grow it if its size is already larger than the required size. 2613 * In this case, just keep it but update the current buffer size to 2614 * the one requested. 2615 * (But NEVER EVER modify the size of the static buffer!!) 2616 * Otherwise, we'll need to create a new buffer and use this one instead. 2617 */ 2618 if ( (Buffer->Buffer == Buffer->StaticBuffer) && 2619 (Buffer->StaticSize >= RequiredSize) ) 2620 { 2621 Buffer->Size = RequiredSize; 2622 return STATUS_SUCCESS; 2623 } 2624 2625 /* The buffer we are using is not large enough, try to create a bigger one */ 2626 NewBuffer = RtlpAllocateStringMemory(RequiredSize, TAG_USTR); 2627 if (NewBuffer == NULL) 2628 return STATUS_NO_MEMORY; 2629 2630 /* Copy the original content if needed */ 2631 if (!(Flags & RTL_SKIP_BUFFER_COPY)) 2632 { 2633 RtlMoveMemory(NewBuffer, Buffer->Buffer, Buffer->Size); 2634 } 2635 2636 /* Free the original buffer only if it's not the static buffer */ 2637 if (Buffer->Buffer != Buffer->StaticBuffer) 2638 { 2639 RtlpFreeStringMemory(Buffer->Buffer, TAG_USTR); 2640 } 2641 2642 /* Update the members */ 2643 Buffer->Buffer = NewBuffer; 2644 Buffer->Size = RequiredSize; 2645 2646 /* Done */ 2647 return STATUS_SUCCESS; 2648 } 2649 2650 static 2651 BOOLEAN 2652 RtlpIsCharInUnicodeString( 2653 IN WCHAR Char, 2654 IN PCUNICODE_STRING MatchString, 2655 IN BOOLEAN CaseInSensitive) 2656 { 2657 USHORT i; 2658 2659 if (CaseInSensitive) 2660 Char = RtlpUpcaseUnicodeChar(Char); 2661 2662 for (i = 0; i < MatchString->Length / sizeof(WCHAR); i++) 2663 { 2664 WCHAR OtherChar = MatchString->Buffer[i]; 2665 if (CaseInSensitive) 2666 OtherChar = RtlpUpcaseUnicodeChar(OtherChar); 2667 2668 if (Char == OtherChar) 2669 return TRUE; 2670 } 2671 2672 return FALSE; 2673 } 2674 2675 /* 2676 * @implemented 2677 */ 2678 NTSTATUS 2679 NTAPI 2680 RtlFindCharInUnicodeString( 2681 IN ULONG Flags, 2682 IN PCUNICODE_STRING SearchString, 2683 IN PCUNICODE_STRING MatchString, 2684 OUT PUSHORT Position) 2685 { 2686 BOOLEAN Found; 2687 const BOOLEAN WantToFind = (Flags & RTL_FIND_CHAR_IN_UNICODE_STRING_COMPLEMENT_CHAR_SET) == 0; 2688 const BOOLEAN CaseInSensitive = (Flags & RTL_FIND_CHAR_IN_UNICODE_STRING_CASE_INSENSITIVE) != 0; 2689 USHORT i, Length; 2690 2691 DPRINT("RtlFindCharInUnicodeString(%u, '%wZ', '%wZ', %p)\n", 2692 Flags, SearchString, MatchString, Position); 2693 2694 /* Parameter checks */ 2695 if (Position == NULL) 2696 return STATUS_INVALID_PARAMETER; 2697 2698 *Position = 0; 2699 2700 if (Flags & ~(RTL_FIND_CHAR_IN_UNICODE_STRING_START_AT_END | 2701 RTL_FIND_CHAR_IN_UNICODE_STRING_COMPLEMENT_CHAR_SET | 2702 RTL_FIND_CHAR_IN_UNICODE_STRING_CASE_INSENSITIVE)) 2703 return STATUS_INVALID_PARAMETER; 2704 2705 /* Search */ 2706 Length = SearchString->Length / sizeof(WCHAR); 2707 if (Flags & RTL_FIND_CHAR_IN_UNICODE_STRING_START_AT_END) 2708 { 2709 for (i = Length - 1; (SHORT)i >= 0; i--) 2710 { 2711 Found = RtlpIsCharInUnicodeString(SearchString->Buffer[i], MatchString, CaseInSensitive); 2712 if (Found == WantToFind) 2713 { 2714 *Position = i * sizeof(WCHAR); 2715 return STATUS_SUCCESS; 2716 } 2717 } 2718 } 2719 else 2720 { 2721 for (i = 0; i < Length; i++) 2722 { 2723 Found = RtlpIsCharInUnicodeString(SearchString->Buffer[i], MatchString, CaseInSensitive); 2724 if (Found == WantToFind) 2725 { 2726 *Position = (i + 1) * sizeof(WCHAR); 2727 return STATUS_SUCCESS; 2728 } 2729 } 2730 } 2731 2732 return STATUS_NOT_FOUND; 2733 } 2734 2735 /* 2736 * @implemented 2737 * 2738 * NOTES 2739 * Get the maximum of MAX_COMPUTERNAME_LENGTH characters from the dns.host name until the dot is found. 2740 * Convert is to an uppercase oem string and check for unmapped characters. 2741 * Then convert the oem string back to an unicode string. 2742 */ 2743 NTSTATUS 2744 NTAPI 2745 RtlDnsHostNameToComputerName(PUNICODE_STRING ComputerName, PUNICODE_STRING DnsHostName, BOOLEAN AllocateComputerNameString) 2746 { 2747 NTSTATUS Status; 2748 ULONG Length; 2749 ULONG ComputerNameLength; 2750 ULONG ComputerNameOemNLength; 2751 OEM_STRING ComputerNameOem; 2752 CHAR ComputerNameOemN[MAX_COMPUTERNAME_LENGTH + 1]; 2753 2754 Status = STATUS_INVALID_COMPUTER_NAME; 2755 ComputerNameLength = DnsHostName->Length; 2756 2757 /* find the first dot in the dns host name */ 2758 for (Length = 0; Length < DnsHostName->Length / sizeof(WCHAR); Length++) 2759 { 2760 if (DnsHostName->Buffer[Length] == L'.') 2761 { 2762 /* dot found, so set the length for the oem translation */ 2763 ComputerNameLength = Length * sizeof(WCHAR); 2764 break; 2765 } 2766 } 2767 2768 /* the computername must have one character */ 2769 if (ComputerNameLength > 0) 2770 { 2771 ComputerNameOemNLength = 0; 2772 /* convert to oem string and use uppercase letters */ 2773 Status = RtlUpcaseUnicodeToOemN(ComputerNameOemN, 2774 MAX_COMPUTERNAME_LENGTH, 2775 &ComputerNameOemNLength, 2776 DnsHostName->Buffer, 2777 ComputerNameLength); 2778 2779 /* status STATUS_BUFFER_OVERFLOW is not a problem since the computername shoud only 2780 have MAX_COMPUTERNAME_LENGTH characters */ 2781 if ((Status == STATUS_SUCCESS) || 2782 (Status == STATUS_BUFFER_OVERFLOW)) 2783 { 2784 /* set the termination for the oem string */ 2785 ComputerNameOemN[MAX_COMPUTERNAME_LENGTH] = 0; 2786 /* set status for the case the next function failed */ 2787 Status = STATUS_INVALID_COMPUTER_NAME; 2788 /* fillup the oem string structure with the converted computername 2789 and check it for unmapped characters */ 2790 ComputerNameOem.Buffer = ComputerNameOemN; 2791 ComputerNameOem.Length = (USHORT)ComputerNameOemNLength; 2792 ComputerNameOem.MaximumLength = (USHORT)(MAX_COMPUTERNAME_LENGTH + 1); 2793 2794 if (RtlpDidUnicodeToOemWork(DnsHostName, &ComputerNameOem)) 2795 { 2796 /* no unmapped character so convert it back to an unicode string */ 2797 Status = RtlOemStringToUnicodeString(ComputerName, 2798 &ComputerNameOem, 2799 AllocateComputerNameString); 2800 } 2801 } 2802 } 2803 2804 return Status; 2805 } 2806 2807