Skip to content

Commit d197073

Browse files
committed
Avoid (re-)allocations when searching for named resources.
Also add tests to load resources by name.
1 parent 8d5dbf3 commit d197073

File tree

3 files changed

+174
-19
lines changed

3 files changed

+174
-19
lines changed

MemoryModule.c

Lines changed: 34 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -729,32 +729,45 @@ static PIMAGE_RESOURCE_DIRECTORY_ENTRY _MemorySearchResourceEntry(
729729
}
730730
}
731731
} else {
732-
#if !defined(UNICODE)
733-
char *searchKey = NULL;
734-
int searchKeyLength = 0;
732+
LPCWSTR searchKey;
733+
size_t searchKeyLen = _tcslen(key);
734+
#if defined(UNICODE)
735+
searchKey = key;
736+
#else
737+
// Resource names are always stored using 16bit characters, need to
738+
// convert string we search for.
739+
#define MAX_LOCAL_KEY_LENGTH 2048
740+
// In most cases resource names are short, so optimize for that by
741+
// using a pre-allocated array.
742+
wchar_t _searchKeySpace[MAX_LOCAL_KEY_LENGTH+1];
743+
LPWSTR _searchKey;
744+
if (searchKeyLen > MAX_LOCAL_KEY_LENGTH) {
745+
size_t _searchKeySize = (searchKeyLen + 1) * sizeof(wchar_t);
746+
_searchKey = (LPWSTR) malloc(_searchKeySize);
747+
if (_searchKey == NULL) {
748+
SetLastError(ERROR_OUTOFMEMORY);
749+
return NULL;
750+
}
751+
} else {
752+
_searchKey = &_searchKeySpace[0];
753+
}
754+
755+
mbstowcs(_searchKey, key, searchKeyLen);
756+
_searchKey[searchKeyLen] = 0;
757+
searchKey = _searchKey;
735758
#endif
736759
start = 0;
737760
end = resources->NumberOfNamedEntries;
738761
while (end > start) {
739-
// resource names are always stored using 16bit characters
740762
int cmp;
741763
PIMAGE_RESOURCE_DIR_STRING_U resourceString;
742764
middle = (start + end) >> 1;
743765
resourceString = (PIMAGE_RESOURCE_DIR_STRING_U) (((char *) root) + (entries[middle].Name & 0x7FFFFFFF));
744-
#if !defined(UNICODE)
745-
if (searchKey == NULL || searchKeyLength < resourceString->Length) {
746-
void *tmp = realloc(searchKey, resourceString->Length);
747-
if (tmp == NULL) {
748-
break;
749-
}
750-
751-
searchKey = (char *) tmp;
766+
cmp = wcsnicmp(searchKey, resourceString->NameString, resourceString->Length);
767+
if (cmp == 0) {
768+
// Handle partial match
769+
cmp = searchKeyLen - resourceString->Length;
752770
}
753-
wcstombs(searchKey, resourceString->NameString, resourceString->Length);
754-
cmp = strncmp(key, searchKey, resourceString->Length);
755-
#else
756-
cmp = wcsncmp(key, resourceString->NameString, resourceString->Length);
757-
#endif
758771
if (cmp < 0) {
759772
end = (middle != end ? middle : middle-1);
760773
} else if (cmp > 0) {
@@ -765,11 +778,13 @@ static PIMAGE_RESOURCE_DIRECTORY_ENTRY _MemorySearchResourceEntry(
765778
}
766779
}
767780
#if !defined(UNICODE)
768-
free(searchKey);
781+
if (searchKeyLen > MAX_LOCAL_KEY_LENGTH) {
782+
free(_searchKey);
783+
}
784+
#undef MAX_LOCAL_KEY_LENGTH
769785
#endif
770786
}
771787

772-
773788
return result;
774789
}
775790

tests/LoadDll.cpp

Lines changed: 116 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,64 @@
99

1010
typedef int (*addNumberProc)(int, int);
1111

12+
// Thanks to Tim Cooper (from http://stackoverflow.com/a/8584708)
13+
const char *sstrstr(const char *haystack, const char *needle, size_t length) {
14+
size_t needle_length = strlen(needle);
15+
size_t i;
16+
17+
for (i = 0; i < length; i++) {
18+
if (i + needle_length > length) {
19+
return NULL;
20+
}
21+
22+
if (strncmp(&haystack[i], needle, needle_length) == 0) {
23+
return &haystack[i];
24+
}
25+
}
26+
return NULL;
27+
}
28+
29+
const wchar_t *swcsstr(const wchar_t *haystack, const wchar_t *needle, size_t length) {
30+
size_t needle_length = wcslen(needle);
31+
size_t i;
32+
33+
for (i = 0; i < length; i++) {
34+
if (i + needle_length > length) {
35+
return NULL;
36+
}
37+
38+
if (wcsncmp(&haystack[i], needle, needle_length) == 0) {
39+
return &haystack[i];
40+
}
41+
}
42+
return NULL;
43+
}
44+
45+
BOOL CheckResourceStrings(LPVOID data, DWORD size, const char *first, const wchar_t *second) {
46+
const char *first_pos;
47+
const wchar_t *second_pos;
48+
const wchar_t *src;
49+
50+
if (data == NULL || size == 0) {
51+
return FALSE;
52+
}
53+
54+
first_pos = sstrstr((const char *) data, first, size);
55+
if (first_pos == NULL) {
56+
fprintf(stderr, "ERROR: data doesn't start with %s\n", first);
57+
return FALSE;
58+
}
59+
60+
src = (const wchar_t *) (((const char *) data) + strlen(first) + 1);
61+
second_pos = swcsstr(src, second, (size - strlen(first) - 1) / sizeof(wchar_t));
62+
if (second_pos == NULL) {
63+
fprintf(stderr, "ERROR: data doesn't continue with %S\n", second);
64+
return FALSE;
65+
}
66+
67+
return TRUE;
68+
}
69+
1270
BOOL LoadFromMemory(char *filename)
1371
{
1472
FILE *fp;
@@ -88,6 +146,64 @@ BOOL LoadFromMemory(char *filename)
88146
result = FALSE;
89147
}
90148

149+
resourceInfo = MemoryFindResource(handle, _T("stringres"), RT_RCDATA);
150+
_tprintf(_T("MemoryFindResource returned 0x%p\n"), resourceInfo);
151+
if (resourceInfo != NULL) {
152+
resourceSize = MemorySizeofResource(handle, resourceInfo);
153+
resourceData = MemoryLoadResource(handle, resourceInfo);
154+
155+
_tprintf(_T("Memory resource data: %ld bytes at 0x%p\n"), resourceSize, resourceData);
156+
if (!CheckResourceStrings(resourceData, resourceSize, "This is a ANSI string", L"This is a UNICODE string")) {
157+
result = FALSE;
158+
}
159+
} else {
160+
result = FALSE;
161+
}
162+
163+
resourceInfo = MemoryFindResource(handle, _T("stringres1"), RT_RCDATA);
164+
_tprintf(_T("MemoryFindResource returned 0x%p\n"), resourceInfo);
165+
if (resourceInfo != NULL) {
166+
resourceSize = MemorySizeofResource(handle, resourceInfo);
167+
resourceData = MemoryLoadResource(handle, resourceInfo);
168+
169+
_tprintf(_T("Memory resource data: %ld bytes at 0x%p\n"), resourceSize, resourceData);
170+
if (!CheckResourceStrings(resourceData, resourceSize, "This is ANSI string 1", L"This is UNICODE string 1")) {
171+
result = FALSE;
172+
}
173+
} else {
174+
result = FALSE;
175+
}
176+
177+
178+
resourceInfo = MemoryFindResource(handle, _T("stringres2"), RT_RCDATA);
179+
_tprintf(_T("MemoryFindResource returned 0x%p\n"), resourceInfo);
180+
if (resourceInfo != NULL) {
181+
resourceSize = MemorySizeofResource(handle, resourceInfo);
182+
resourceData = MemoryLoadResource(handle, resourceInfo);
183+
184+
_tprintf(_T("Memory resource data: %ld bytes at 0x%p\n"), resourceSize, resourceData);
185+
if (!CheckResourceStrings(resourceData, resourceSize, "This is ANSI string 2", L"This is UNICODE string 2")) {
186+
result = FALSE;
187+
}
188+
} else {
189+
result = FALSE;
190+
}
191+
192+
193+
resourceInfo = MemoryFindResource(handle, _T("stringres3"), RT_RCDATA);
194+
_tprintf(_T("MemoryFindResource returned 0x%p\n"), resourceInfo);
195+
if (resourceInfo != NULL) {
196+
resourceSize = MemorySizeofResource(handle, resourceInfo);
197+
resourceData = MemoryLoadResource(handle, resourceInfo);
198+
199+
_tprintf(_T("Memory resource data: %ld bytes at 0x%p\n"), resourceSize, resourceData);
200+
if (!CheckResourceStrings(resourceData, resourceSize, "This is ANSI string 3", L"This is UNICODE string 3")) {
201+
result = FALSE;
202+
}
203+
} else {
204+
result = FALSE;
205+
}
206+
91207
MemoryFreeLibrary(handle);
92208

93209
exit:

tests/SampleDLL.rc

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,3 +32,27 @@ STRINGTABLE
3232
IDS_HELLO, "Hello"
3333
IDS_WORLD, "World!"
3434
}
35+
36+
STRINGRES RCDATA
37+
{
38+
"This is a ANSI string\0",
39+
L"This is a UNICODE string\0",
40+
}
41+
42+
STRINGRES1 RCDATA
43+
{
44+
"This is ANSI string 1\0",
45+
L"This is UNICODE string 1\0",
46+
}
47+
48+
STRINGRES2 RCDATA
49+
{
50+
"This is ANSI string 2\0",
51+
L"This is UNICODE string 2\0",
52+
}
53+
54+
STRINGRES3 RCDATA
55+
{
56+
"This is ANSI string 3\0",
57+
L"This is UNICODE string 3\0",
58+
}

0 commit comments

Comments
 (0)