|
37 | 37 |
|
38 | 38 | #include <windows.h> |
39 | 39 | #include <winnt.h> |
| 40 | +#include <tchar.h> |
40 | 41 | #ifdef DEBUG_OUTPUT |
41 | 42 | #include <stdio.h> |
42 | 43 | #endif |
@@ -517,3 +518,208 @@ void MemoryFreeLibrary(HMEMORYMODULE mod) |
517 | 518 | HeapFree(GetProcessHeap(), 0, module); |
518 | 519 | } |
519 | 520 | } |
| 521 | + |
| 522 | +#define DEFAULT_LANGUAGE MAKELANGID(LANG_NEUTRAL, SUBLANG_NEUTRAL) |
| 523 | + |
| 524 | +HMEMORYRSRC MemoryFindResource(HMEMORYMODULE module, LPCTSTR name, LPCTSTR type) |
| 525 | +{ |
| 526 | + return MemoryFindResourceEx(module, name, type, DEFAULT_LANGUAGE); |
| 527 | +} |
| 528 | + |
| 529 | +static PIMAGE_RESOURCE_DIRECTORY_ENTRY _MemorySearchResourceEntry( |
| 530 | + void *root, |
| 531 | + PIMAGE_RESOURCE_DIRECTORY resources, |
| 532 | + LPCTSTR key) |
| 533 | +{ |
| 534 | + PIMAGE_RESOURCE_DIRECTORY_ENTRY entries = (PIMAGE_RESOURCE_DIRECTORY_ENTRY) (resources + 1); |
| 535 | + PIMAGE_RESOURCE_DIRECTORY_ENTRY result = NULL; |
| 536 | + DWORD start; |
| 537 | + DWORD end; |
| 538 | + DWORD middle; |
| 539 | + |
| 540 | + if (!IS_INTRESOURCE(key) && key[0] == _T('#')) { |
| 541 | + // special case: resource id given as string |
| 542 | + _TCHAR *endpos = NULL; |
| 543 | + long int tmpkey = (WORD) _tcstol((_TCHAR *) &key[1], &endpos, 10); |
| 544 | + if (tmpkey <= 0xffff && _tcslen(endpos) == 0) { |
| 545 | + key = MAKEINTRESOURCE(tmpkey); |
| 546 | + } |
| 547 | + } |
| 548 | + |
| 549 | + // entries are stored as ordered list of named entries, |
| 550 | + // followed by an ordered list of id entries - we can do |
| 551 | + // a binary search to find faster... |
| 552 | + if (IS_INTRESOURCE(key)) { |
| 553 | + WORD check = (WORD) (POINTER_TYPE) key; |
| 554 | + start = resources->NumberOfNamedEntries; |
| 555 | + end = start + resources->NumberOfIdEntries; |
| 556 | + |
| 557 | + while (end > start) { |
| 558 | + WORD entryName; |
| 559 | + middle = (start + end) >> 1; |
| 560 | + entryName = (WORD) entries[middle].Name; |
| 561 | + if (check < entryName) { |
| 562 | + end = middle; |
| 563 | + } else if (check > entryName) { |
| 564 | + start = middle; |
| 565 | + } else { |
| 566 | + result = &entries[middle]; |
| 567 | + break; |
| 568 | + } |
| 569 | + } |
| 570 | + } else { |
| 571 | + start = 0; |
| 572 | + end = resources->NumberOfIdEntries; |
| 573 | +#ifndef _UNICODE |
| 574 | + _TCHAR *searchKey = NULL; |
| 575 | + int searchKeyLength = 0; |
| 576 | +#endif |
| 577 | + while (end > start) { |
| 578 | + // resource names are always stored using 16bit characters |
| 579 | + middle = (start + end) >> 1; |
| 580 | + PIMAGE_RESOURCE_DIR_STRING_U resourceString = (PIMAGE_RESOURCE_DIR_STRING_U) (((char *) root) + (entries[middle].Name & 0x7FFFFFFF)); |
| 581 | + int cmp; |
| 582 | +#ifndef _UNICODE |
| 583 | + if (searchKey == NULL || searchKeyLength < resourceString->Length) { |
| 584 | + void *tmp = realloc(searchKey, resourceString->Length); |
| 585 | + if (tmp == NULL) { |
| 586 | + break; |
| 587 | + } |
| 588 | + |
| 589 | + searchKey = (_TCHAR *) tmp; |
| 590 | + } |
| 591 | + wcstombs(searchKey, resourceString->NameString, resourceString->Length); |
| 592 | + cmp = strncmp(key, searchKey, resourceString->Length); |
| 593 | +#else |
| 594 | + cmp = wcsncmp((_TCHAR *) key, resourceString->NameString, resourceString->Length); |
| 595 | +#endif |
| 596 | + if (cmp < 0) { |
| 597 | + end = middle; |
| 598 | + } else if (cmp > 0) { |
| 599 | + start = middle; |
| 600 | + } else { |
| 601 | + result = &entries[middle]; |
| 602 | + break; |
| 603 | + } |
| 604 | + } |
| 605 | +#ifndef _UNICODE |
| 606 | + free(searchKey); |
| 607 | +#endif |
| 608 | + } |
| 609 | + |
| 610 | + |
| 611 | + return result; |
| 612 | +} |
| 613 | + |
| 614 | +HMEMORYRSRC MemoryFindResourceEx(HMEMORYMODULE module, LPCTSTR name, LPCTSTR type, WORD language) |
| 615 | +{ |
| 616 | + unsigned char *codeBase = ((PMEMORYMODULE) module)->codeBase; |
| 617 | + PIMAGE_DATA_DIRECTORY directory = GET_HEADER_DICTIONARY((PMEMORYMODULE) module, IMAGE_DIRECTORY_ENTRY_RESOURCE); |
| 618 | + PIMAGE_RESOURCE_DIRECTORY rootResources; |
| 619 | + PIMAGE_RESOURCE_DIRECTORY nameResources; |
| 620 | + PIMAGE_RESOURCE_DIRECTORY typeResources; |
| 621 | + PIMAGE_RESOURCE_DIRECTORY_ENTRY foundType; |
| 622 | + PIMAGE_RESOURCE_DIRECTORY_ENTRY foundName; |
| 623 | + PIMAGE_RESOURCE_DIRECTORY_ENTRY foundLanguage; |
| 624 | + if (directory->Size == 0) { |
| 625 | + // no resource table found |
| 626 | + SetLastError(ERROR_RESOURCE_DATA_NOT_FOUND); |
| 627 | + return NULL; |
| 628 | + } |
| 629 | + |
| 630 | + if (language == DEFAULT_LANGUAGE) { |
| 631 | + // use language from current thread |
| 632 | + language = LANGIDFROMLCID(GetThreadLocale()); |
| 633 | + } |
| 634 | + |
| 635 | + // resources are stored as three-level tree |
| 636 | + // - first node is the type |
| 637 | + // - second node is the name |
| 638 | + // - third node is the language |
| 639 | + rootResources = (PIMAGE_RESOURCE_DIRECTORY) (codeBase + directory->VirtualAddress); |
| 640 | + foundType = _MemorySearchResourceEntry(rootResources, rootResources, type); |
| 641 | + if (foundType == NULL) { |
| 642 | + SetLastError(ERROR_RESOURCE_TYPE_NOT_FOUND); |
| 643 | + return NULL; |
| 644 | + } |
| 645 | + |
| 646 | + typeResources = (PIMAGE_RESOURCE_DIRECTORY) (codeBase + directory->VirtualAddress + (foundType->OffsetToData & 0x7fffffff)); |
| 647 | + foundName = _MemorySearchResourceEntry(rootResources, typeResources, name); |
| 648 | + if (foundName == NULL) { |
| 649 | + SetLastError(ERROR_RESOURCE_NAME_NOT_FOUND); |
| 650 | + return NULL; |
| 651 | + } |
| 652 | + |
| 653 | + nameResources = (PIMAGE_RESOURCE_DIRECTORY) (codeBase + directory->VirtualAddress + (foundName->OffsetToData & 0x7fffffff)); |
| 654 | + foundLanguage = _MemorySearchResourceEntry(rootResources, nameResources, (LPCTSTR) (POINTER_TYPE) language); |
| 655 | + if (foundLanguage == NULL) { |
| 656 | + // requested language not found, use first available |
| 657 | + if (nameResources->NumberOfIdEntries == 0) { |
| 658 | + SetLastError(ERROR_RESOURCE_LANG_NOT_FOUND); |
| 659 | + return NULL; |
| 660 | + } |
| 661 | + |
| 662 | + foundLanguage = (PIMAGE_RESOURCE_DIRECTORY_ENTRY) (nameResources + 1); |
| 663 | + } |
| 664 | + |
| 665 | + return (codeBase + directory->VirtualAddress + (foundLanguage->OffsetToData & 0x7fffffff)); |
| 666 | +} |
| 667 | + |
| 668 | +DWORD MemorySizeofResource(HMEMORYMODULE module, HMEMORYRSRC resource) |
| 669 | +{ |
| 670 | + PIMAGE_RESOURCE_DATA_ENTRY entry = (PIMAGE_RESOURCE_DATA_ENTRY) resource; |
| 671 | + |
| 672 | + return entry->Size; |
| 673 | +} |
| 674 | + |
| 675 | +LPVOID MemoryLoadResource(HMEMORYMODULE module, HMEMORYRSRC resource) |
| 676 | +{ |
| 677 | + unsigned char *codeBase = ((PMEMORYMODULE) module)->codeBase; |
| 678 | + PIMAGE_RESOURCE_DATA_ENTRY entry = (PIMAGE_RESOURCE_DATA_ENTRY) resource; |
| 679 | + |
| 680 | + return codeBase + entry->OffsetToData; |
| 681 | +} |
| 682 | + |
| 683 | +int |
| 684 | +MemoryLoadString(HMEMORYMODULE module, UINT id, LPTSTR buffer, int maxsize) |
| 685 | +{ |
| 686 | + return MemoryLoadStringEx(module, id, buffer, maxsize, DEFAULT_LANGUAGE); |
| 687 | +} |
| 688 | + |
| 689 | +int |
| 690 | +MemoryLoadStringEx(HMEMORYMODULE module, UINT id, LPTSTR buffer, int maxsize, WORD language) |
| 691 | +{ |
| 692 | + if (maxsize == 0) { |
| 693 | + return 0; |
| 694 | + } |
| 695 | + |
| 696 | + HMEMORYRSRC resource = MemoryFindResourceEx(module, MAKEINTRESOURCE((id >> 4) + 1), RT_STRING, language); |
| 697 | + if (resource == NULL) { |
| 698 | + buffer[0] = 0; |
| 699 | + return 0; |
| 700 | + } |
| 701 | + |
| 702 | + PIMAGE_RESOURCE_DIR_STRING_U data = MemoryLoadResource(module, resource); |
| 703 | + id = id & 0x0f; |
| 704 | + while (id--) { |
| 705 | + data = (PIMAGE_RESOURCE_DIR_STRING_U) (((char *) data) + (data->Length + 1) * sizeof(WCHAR)); |
| 706 | + } |
| 707 | + if (data->Length == 0) { |
| 708 | + SetLastError(ERROR_RESOURCE_NAME_NOT_FOUND); |
| 709 | + buffer[0] = 0; |
| 710 | + return 0; |
| 711 | + } |
| 712 | + |
| 713 | + DWORD size = data->Length; |
| 714 | + if (size >= maxsize) { |
| 715 | + size = maxsize; |
| 716 | + } else { |
| 717 | + buffer[size] = 0; |
| 718 | + } |
| 719 | +#ifdef _UNICODE |
| 720 | + _tcsncpy(buffer, data->NameString, size); |
| 721 | +#else |
| 722 | + wcstombs(buffer, data->NameString, size); |
| 723 | +#endif |
| 724 | + return size; |
| 725 | +} |
0 commit comments