diff --git a/MemoryModule.c b/MemoryModule.c index 35920a4..567799a 100644 --- a/MemoryModule.c +++ b/MemoryModule.c @@ -729,32 +729,45 @@ static PIMAGE_RESOURCE_DIRECTORY_ENTRY _MemorySearchResourceEntry( } } } else { -#if !defined(UNICODE) - char *searchKey = NULL; - int searchKeyLength = 0; + LPCWSTR searchKey; + size_t searchKeyLen = _tcslen(key); +#if defined(UNICODE) + searchKey = key; +#else + // Resource names are always stored using 16bit characters, need to + // convert string we search for. +#define MAX_LOCAL_KEY_LENGTH 2048 + // In most cases resource names are short, so optimize for that by + // using a pre-allocated array. + wchar_t _searchKeySpace[MAX_LOCAL_KEY_LENGTH+1]; + LPWSTR _searchKey; + if (searchKeyLen > MAX_LOCAL_KEY_LENGTH) { + size_t _searchKeySize = (searchKeyLen + 1) * sizeof(wchar_t); + _searchKey = (LPWSTR) malloc(_searchKeySize); + if (_searchKey == NULL) { + SetLastError(ERROR_OUTOFMEMORY); + return NULL; + } + } else { + _searchKey = &_searchKeySpace[0]; + } + + mbstowcs(_searchKey, key, searchKeyLen); + _searchKey[searchKeyLen] = 0; + searchKey = _searchKey; #endif start = 0; end = resources->NumberOfNamedEntries; while (end > start) { - // resource names are always stored using 16bit characters int cmp; PIMAGE_RESOURCE_DIR_STRING_U resourceString; middle = (start + end) >> 1; resourceString = (PIMAGE_RESOURCE_DIR_STRING_U) (((char *) root) + (entries[middle].Name & 0x7FFFFFFF)); -#if !defined(UNICODE) - if (searchKey == NULL || searchKeyLength < resourceString->Length) { - void *tmp = realloc(searchKey, resourceString->Length); - if (tmp == NULL) { - break; - } - - searchKey = (char *) tmp; + cmp = wcsnicmp(searchKey, resourceString->NameString, resourceString->Length); + if (cmp == 0) { + // Handle partial match + cmp = searchKeyLen - resourceString->Length; } - wcstombs(searchKey, resourceString->NameString, resourceString->Length); - cmp = strncmp(key, searchKey, resourceString->Length); -#else - cmp = wcsncmp(key, resourceString->NameString, resourceString->Length); -#endif if (cmp < 0) { end = (middle != end ? middle : middle-1); } else if (cmp > 0) { @@ -765,11 +778,13 @@ static PIMAGE_RESOURCE_DIRECTORY_ENTRY _MemorySearchResourceEntry( } } #if !defined(UNICODE) - free(searchKey); + if (searchKeyLen > MAX_LOCAL_KEY_LENGTH) { + free(_searchKey); + } +#undef MAX_LOCAL_KEY_LENGTH #endif } - return result; } diff --git a/tests/LoadDll.cpp b/tests/LoadDll.cpp index 4413f48..43cf8fd 100644 --- a/tests/LoadDll.cpp +++ b/tests/LoadDll.cpp @@ -9,6 +9,64 @@ typedef int (*addNumberProc)(int, int); +// Thanks to Tim Cooper (from http://stackoverflow.com/a/8584708) +const char *sstrstr(const char *haystack, const char *needle, size_t length) { + size_t needle_length = strlen(needle); + size_t i; + + for (i = 0; i < length; i++) { + if (i + needle_length > length) { + return NULL; + } + + if (strncmp(&haystack[i], needle, needle_length) == 0) { + return &haystack[i]; + } + } + return NULL; +} + +const wchar_t *swcsstr(const wchar_t *haystack, const wchar_t *needle, size_t length) { + size_t needle_length = wcslen(needle); + size_t i; + + for (i = 0; i < length; i++) { + if (i + needle_length > length) { + return NULL; + } + + if (wcsncmp(&haystack[i], needle, needle_length) == 0) { + return &haystack[i]; + } + } + return NULL; +} + +BOOL CheckResourceStrings(LPVOID data, DWORD size, const char *first, const wchar_t *second) { + const char *first_pos; + const wchar_t *second_pos; + const wchar_t *src; + + if (data == NULL || size == 0) { + return FALSE; + } + + first_pos = sstrstr((const char *) data, first, size); + if (first_pos == NULL) { + fprintf(stderr, "ERROR: data doesn't start with %s\n", first); + return FALSE; + } + + src = (const wchar_t *) (((const char *) data) + strlen(first) + 1); + second_pos = swcsstr(src, second, (size - strlen(first) - 1) / sizeof(wchar_t)); + if (second_pos == NULL) { + fprintf(stderr, "ERROR: data doesn't continue with %S\n", second); + return FALSE; + } + + return TRUE; +} + BOOL LoadFromMemory(char *filename) { FILE *fp; @@ -88,6 +146,64 @@ BOOL LoadFromMemory(char *filename) result = FALSE; } + resourceInfo = MemoryFindResource(handle, _T("stringres"), RT_RCDATA); + _tprintf(_T("MemoryFindResource returned 0x%p\n"), resourceInfo); + if (resourceInfo != NULL) { + resourceSize = MemorySizeofResource(handle, resourceInfo); + resourceData = MemoryLoadResource(handle, resourceInfo); + + _tprintf(_T("Memory resource data: %ld bytes at 0x%p\n"), resourceSize, resourceData); + if (!CheckResourceStrings(resourceData, resourceSize, "This is a ANSI string", L"This is a UNICODE string")) { + result = FALSE; + } + } else { + result = FALSE; + } + + resourceInfo = MemoryFindResource(handle, _T("stringres1"), RT_RCDATA); + _tprintf(_T("MemoryFindResource returned 0x%p\n"), resourceInfo); + if (resourceInfo != NULL) { + resourceSize = MemorySizeofResource(handle, resourceInfo); + resourceData = MemoryLoadResource(handle, resourceInfo); + + _tprintf(_T("Memory resource data: %ld bytes at 0x%p\n"), resourceSize, resourceData); + if (!CheckResourceStrings(resourceData, resourceSize, "This is ANSI string 1", L"This is UNICODE string 1")) { + result = FALSE; + } + } else { + result = FALSE; + } + + + resourceInfo = MemoryFindResource(handle, _T("stringres2"), RT_RCDATA); + _tprintf(_T("MemoryFindResource returned 0x%p\n"), resourceInfo); + if (resourceInfo != NULL) { + resourceSize = MemorySizeofResource(handle, resourceInfo); + resourceData = MemoryLoadResource(handle, resourceInfo); + + _tprintf(_T("Memory resource data: %ld bytes at 0x%p\n"), resourceSize, resourceData); + if (!CheckResourceStrings(resourceData, resourceSize, "This is ANSI string 2", L"This is UNICODE string 2")) { + result = FALSE; + } + } else { + result = FALSE; + } + + + resourceInfo = MemoryFindResource(handle, _T("stringres3"), RT_RCDATA); + _tprintf(_T("MemoryFindResource returned 0x%p\n"), resourceInfo); + if (resourceInfo != NULL) { + resourceSize = MemorySizeofResource(handle, resourceInfo); + resourceData = MemoryLoadResource(handle, resourceInfo); + + _tprintf(_T("Memory resource data: %ld bytes at 0x%p\n"), resourceSize, resourceData); + if (!CheckResourceStrings(resourceData, resourceSize, "This is ANSI string 3", L"This is UNICODE string 3")) { + result = FALSE; + } + } else { + result = FALSE; + } + MemoryFreeLibrary(handle); exit: diff --git a/tests/SampleDLL.rc b/tests/SampleDLL.rc index 5a0da61..bbe5774 100644 --- a/tests/SampleDLL.rc +++ b/tests/SampleDLL.rc @@ -32,3 +32,27 @@ STRINGTABLE IDS_HELLO, "Hello" IDS_WORLD, "World!" } + +STRINGRES RCDATA +{ + "This is a ANSI string\0", + L"This is a UNICODE string\0", +} + +STRINGRES1 RCDATA +{ + "This is ANSI string 1\0", + L"This is UNICODE string 1\0", +} + +STRINGRES2 RCDATA +{ + "This is ANSI string 2\0", + L"This is UNICODE string 2\0", +} + +STRINGRES3 RCDATA +{ + "This is ANSI string 3\0", + L"This is UNICODE string 3\0", +}