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