summaryrefslogtreecommitdiff
path: root/src/utilcode
diff options
context:
space:
mode:
authorDavid Wrighton <davidwr@microsoft.com>2019-05-01 15:29:34 -0700
committerGitHub <noreply@github.com>2019-05-01 15:29:34 -0700
commit4d820df4437139275b7c05330dd98631db708802 (patch)
tree1fd8c1b6c43880f5dace1ef33952139ea010779f /src/utilcode
parent75fd45860789ad54223e223ed04a24b2f2d2a8d5 (diff)
downloadcoreclr-4d820df4437139275b7c05330dd98631db708802.tar.gz
coreclr-4d820df4437139275b7c05330dd98631db708802.tar.bz2
coreclr-4d820df4437139275b7c05330dd98631db708802.zip
Copy all win32 resources (#24308)
- Add crossgen test to verify file version is preserved - Add support for general win32 resource copying to ReadyToRun - Copy all resources
Diffstat (limited to 'src/utilcode')
-rw-r--r--src/utilcode/pedecoder.cpp326
1 files changed, 298 insertions, 28 deletions
diff --git a/src/utilcode/pedecoder.cpp b/src/utilcode/pedecoder.cpp
index 24cde95441..411b462a94 100644
--- a/src/utilcode/pedecoder.cpp
+++ b/src/utilcode/pedecoder.cpp
@@ -1790,26 +1790,73 @@ void PEDecoder::LayoutILOnly(void *base, BOOL allowFullPE) const
#endif // #ifndef DACCESS_COMPILE
-DWORD PEDecoder::ReadResourceDictionary(DWORD rvaOfResourceSection, DWORD rva, LPCWSTR name, BOOL *pIsDictionary) const
+bool ReadResourceDirectoryHeader(const PEDecoder *pDecoder, DWORD rvaOfResourceSection, DWORD rva, IMAGE_RESOURCE_DIRECTORY_ENTRY** ppDirectoryEntries, IMAGE_RESOURCE_DIRECTORY **ppResourceDirectory)
{
- *pIsDictionary = FALSE;
+ if (!pDecoder->CheckRva(rva, sizeof(IMAGE_RESOURCE_DIRECTORY)))
+ {
+ return false;
+ }
- if (!CheckRva(rva, sizeof(IMAGE_RESOURCE_DIRECTORY)))
+ *ppResourceDirectory = (IMAGE_RESOURCE_DIRECTORY *)pDecoder->GetRvaData(rva);
+
+ // Check to see if entire resource directory is accessible
+ if (!pDecoder->CheckRva(rva + sizeof(IMAGE_RESOURCE_DIRECTORY),
+ (sizeof(IMAGE_RESOURCE_DIRECTORY_ENTRY) * (*ppResourceDirectory)->NumberOfNamedEntries) +
+ (sizeof(IMAGE_RESOURCE_DIRECTORY_ENTRY) * (*ppResourceDirectory)->NumberOfIdEntries)))
{
- return 0;
+ return false;
}
- IMAGE_RESOURCE_DIRECTORY *pResourceDirectory = (IMAGE_RESOURCE_DIRECTORY *)GetRvaData(rva);
+ *ppDirectoryEntries = (IMAGE_RESOURCE_DIRECTORY_ENTRY *)pDecoder->GetRvaData(rva + sizeof(IMAGE_RESOURCE_DIRECTORY));
+ return true;
+}
+
+bool ReadNameFromResourceDirectoryEntry(const PEDecoder *pDecoder, DWORD rvaOfResourceSection, IMAGE_RESOURCE_DIRECTORY_ENTRY* pDirectoryEntries, DWORD iEntry, DWORD *pNameUInt, WCHAR **pNameStr)
+{
+ *pNameStr = NULL;
+ *pNameUInt = 0;
- // Check to see if entire resource dictionary is accessible
- if (!CheckRva(rva + sizeof(IMAGE_RESOURCE_DIRECTORY),
- (sizeof(IMAGE_RESOURCE_DIRECTORY_ENTRY) * pResourceDirectory->NumberOfNamedEntries) +
- (sizeof(IMAGE_RESOURCE_DIRECTORY_ENTRY) * pResourceDirectory->NumberOfIdEntries)))
+ if (!IS_INTRESOURCE(pDirectoryEntries[iEntry].Name))
{
- return 0;
+ DWORD entryName = pDirectoryEntries[iEntry].Name;
+ if (!(entryName & IMAGE_RESOURCE_NAME_IS_STRING))
+ return false;
+ DWORD entryNameRva = (entryName & ~IMAGE_RESOURCE_NAME_IS_STRING) + rvaOfResourceSection;
+
+ if (!pDecoder->CheckRva(entryNameRva, sizeof(WORD)))
+ return false;
+
+ size_t entryNameLen = *(WORD*)pDecoder->GetRvaData(entryNameRva);
+ if (!pDecoder->CheckRva(entryNameRva, (COUNT_T)(sizeof(WORD) * (1 + entryNameLen))))
+ return false;
+ *pNameStr = new(nothrow) WCHAR[entryNameLen + 1];
+ if ((*pNameStr) == NULL)
+ return false;
+ memcpy((*pNameStr), (WCHAR*)pDecoder->GetRvaData(entryNameRva + sizeof(WORD)), entryNameLen * sizeof(WCHAR));
+ (*pNameStr)[entryNameLen] = 0;
+ }
+ else
+ {
+ DWORD name = pDirectoryEntries[iEntry].Name;
+ if (!IS_INTRESOURCE(name))
+ return false;
+
+ *pNameUInt = name;
}
- IMAGE_RESOURCE_DIRECTORY_ENTRY* pDirectoryEntries = (IMAGE_RESOURCE_DIRECTORY_ENTRY *)GetRvaData(rva + sizeof(IMAGE_RESOURCE_DIRECTORY));
+ return true;
+}
+
+DWORD ReadResourceDirectory(const PEDecoder *pDecoder, DWORD rvaOfResourceSection, DWORD rva, LPCWSTR name, BOOL *pisDirectory)
+{
+ *pisDirectory = FALSE;
+
+ IMAGE_RESOURCE_DIRECTORY* pResourceDirectory;
+ IMAGE_RESOURCE_DIRECTORY_ENTRY* pDirectoryEntries;
+ if (!ReadResourceDirectoryHeader(pDecoder, rvaOfResourceSection, rva, &pDirectoryEntries, &pResourceDirectory))
+ {
+ return 0;
+ }
// A fast implementation of resource lookup uses a binary search, but our needs are simple, and a linear search
// is easier to prove correct, so do that instead.
@@ -1819,7 +1866,7 @@ DWORD PEDecoder::ReadResourceDictionary(DWORD rvaOfResourceSection, DWORD rva, L
{
BOOL foundEntry = FALSE;
- if (((UINT_PTR)name) <= 0xFFFF)
+ if (IS_INTRESOURCE(name))
{
// name is id
if (pDirectoryEntries[iEntry].Name == (DWORD)(SIZE_T)name)
@@ -1834,24 +1881,24 @@ DWORD PEDecoder::ReadResourceDictionary(DWORD rvaOfResourceSection, DWORD rva, L
DWORD entryNameRva = (entryName & ~IMAGE_RESOURCE_NAME_IS_STRING) + rvaOfResourceSection;
- if (!CheckRva(entryNameRva, sizeof(WORD)))
+ if (!pDecoder->CheckRva(entryNameRva, sizeof(WORD)))
return 0;
- size_t entryNameLen = *(WORD*)GetRvaData(entryNameRva);
+ size_t entryNameLen = *(WORD*)pDecoder->GetRvaData(entryNameRva);
if (wcslen(name) != entryNameLen)
continue;
- if (!CheckRva(entryNameRva, (COUNT_T)(sizeof(WORD) * (1 + entryNameLen))))
+ if (!pDecoder->CheckRva(entryNameRva, (COUNT_T)(sizeof(WORD) * (1 + entryNameLen))))
return 0;
- if (memcmp((WCHAR*)GetRvaData(entryNameRva + sizeof(WORD)), name, entryNameLen * sizeof(WCHAR)) == 0)
+ if (memcmp((WCHAR*)pDecoder->GetRvaData(entryNameRva + sizeof(WORD)), name, entryNameLen * sizeof(WCHAR)) == 0)
foundEntry = TRUE;
}
if (!foundEntry)
continue;
- *pIsDictionary = !!(pDirectoryEntries[iEntry].OffsetToData & IMAGE_RESOURCE_DATA_IS_DIRECTORY);
+ *pisDirectory = !!(pDirectoryEntries[iEntry].OffsetToData & IMAGE_RESOURCE_DATA_IS_DIRECTORY);
DWORD offsetToData = pDirectoryEntries[iEntry].OffsetToData & ~IMAGE_RESOURCE_DATA_IS_DIRECTORY;
DWORD dataRva = rvaOfResourceSection + offsetToData;
return dataRva;
@@ -1860,16 +1907,16 @@ DWORD PEDecoder::ReadResourceDictionary(DWORD rvaOfResourceSection, DWORD rva, L
return 0;
}
-DWORD PEDecoder::ReadResourceDataEntry(DWORD rva, COUNT_T *pSize) const
+DWORD ReadResourceDataEntry(const PEDecoder *pDecoder, DWORD rva, COUNT_T *pSize)
{
*pSize = 0;
- if (!CheckRva(rva, sizeof(IMAGE_RESOURCE_DATA_ENTRY)))
+ if (!pDecoder->CheckRva(rva, sizeof(IMAGE_RESOURCE_DATA_ENTRY)))
{
return 0;
}
- IMAGE_RESOURCE_DATA_ENTRY *pDataEntry = (IMAGE_RESOURCE_DATA_ENTRY *)GetRvaData(rva);
+ IMAGE_RESOURCE_DATA_ENTRY *pDataEntry = (IMAGE_RESOURCE_DATA_ENTRY *)pDecoder->GetRvaData(rva);
*pSize = pDataEntry->Size;
return pDataEntry->OffsetToData;
}
@@ -1898,17 +1945,17 @@ void * PEDecoder::GetWin32Resource(LPCWSTR lpName, LPCWSTR lpType, COUNT_T *pSiz
if (pDir->VirtualAddress == 0)
return NULL;
- BOOL isDictionary = FALSE;
- DWORD nameTableRva = ReadResourceDictionary(pDir->VirtualAddress, pDir->VirtualAddress, lpType, &isDictionary);
+ BOOL isDirectory = FALSE;
+ DWORD nameTableRva = ReadResourceDirectory(this, pDir->VirtualAddress, pDir->VirtualAddress, lpType, &isDirectory);
- if (!isDictionary)
+ if (!isDirectory)
return NULL;
if (nameTableRva == 0)
return NULL;
- DWORD languageTableRva = ReadResourceDictionary(pDir->VirtualAddress, nameTableRva, lpName, &isDictionary);
- if (!isDictionary)
+ DWORD languageTableRva = ReadResourceDirectory(this, pDir->VirtualAddress, nameTableRva, lpName, &isDirectory);
+ if (!isDirectory)
return NULL;
if (languageTableRva == 0)
@@ -1918,14 +1965,14 @@ void * PEDecoder::GetWin32Resource(LPCWSTR lpName, LPCWSTR lpType, COUNT_T *pSiz
// This translates to LANGID 0 as the initial lookup point, which is sufficient for the needs of this api at this time
// (FindResource in the Windows api implements a large number of fallback paths which this api does not implement)
- DWORD resourceDataEntryRva = ReadResourceDictionary(pDir->VirtualAddress, languageTableRva, 0, &isDictionary);
- if (isDictionary) // This must not be a resource dictionary itself
+ DWORD resourceDataEntryRva = ReadResourceDirectory(this, pDir->VirtualAddress, languageTableRva, 0, &isDirectory);
+ if (isDirectory) // This must not be a resource directory itself
return NULL;
if (resourceDataEntryRva == 0)
return NULL;
- DWORD resourceDataRva = ReadResourceDataEntry(resourceDataEntryRva, pSize);
+ DWORD resourceDataRva = ReadResourceDataEntry(this, resourceDataEntryRva, pSize);
if (!CheckRva(resourceDataRva, *pSize))
{
*pSize = 0;
@@ -1935,6 +1982,229 @@ void * PEDecoder::GetWin32Resource(LPCWSTR lpName, LPCWSTR lpType, COUNT_T *pSiz
return (void*)GetRvaData(resourceDataRva);
}
+typedef bool (*PEDecoder_EnumerateResourceTableFunction)(const PEDecoder *pDecoder, DWORD rvaOfResourceSection, bool isDirectory, LPCWSTR name, DWORD dataRVA, void *context);
+
+struct ResourceEnumerateNamesState
+{
+ PEDecoder_ResourceNamesCallbackFunction namesCallback;
+ PEDecoder_ResourceCallbackFunction langIDcallback;
+ void *context;
+ LPCWSTR nameType;
+ LPCWSTR nameName;
+ PEDecoder_EnumerateResourceTableFunction callbackPerName;
+ PEDecoder_EnumerateResourceTableFunction callbackPerLangID;
+};
+
+struct ResourceEnumerateTypesState
+{
+ PEDecoder_ResourceTypesCallbackFunction callback;
+ void *context;
+ LPCWSTR nameType;
+};
+
+bool EnumerateWin32ResourceTable(const PEDecoder *pDecoder, DWORD rvaOfResourceSection, DWORD rvaOfResourceTable, PEDecoder_EnumerateResourceTableFunction resourceTableEnumerator, void *context)
+{
+ IMAGE_RESOURCE_DIRECTORY* pResourceDirectory;
+ IMAGE_RESOURCE_DIRECTORY_ENTRY* pDirectoryEntries;
+ if (!ReadResourceDirectoryHeader(pDecoder, rvaOfResourceSection, rvaOfResourceTable, &pDirectoryEntries, &pResourceDirectory))
+ {
+ return false;
+ }
+
+ DWORD iEntryCount = (DWORD)pResourceDirectory->NumberOfNamedEntries + (DWORD)pResourceDirectory->NumberOfIdEntries;
+
+ for (DWORD iEntry = 0; iEntry < iEntryCount; iEntry++)
+ {
+ DWORD nameUInt;
+ NewArrayHolder<WCHAR> nameString;
+ if (!ReadNameFromResourceDirectoryEntry(pDecoder, rvaOfResourceSection, pDirectoryEntries, iEntry, &nameUInt, &nameString))
+ return false;
+
+ LPCWSTR name = MAKEINTRESOURCEW(nameUInt);
+ if (nameString != NULL)
+ name = &nameString[0];
+
+ bool isDirectory = !!(pDirectoryEntries[iEntry].OffsetToData & IMAGE_RESOURCE_DATA_IS_DIRECTORY);
+ DWORD offsetToData = pDirectoryEntries[iEntry].OffsetToData & ~IMAGE_RESOURCE_DATA_IS_DIRECTORY;
+ DWORD dataRva = rvaOfResourceSection + offsetToData;
+
+ if (!resourceTableEnumerator(pDecoder, rvaOfResourceSection, isDirectory, name, dataRva, context))
+ return false;
+ }
+
+ return true;
+}
+
+bool DoesResourceNameMatch(LPCWSTR nameA, LPCWSTR nameB)
+{
+ bool foundEntry = false;
+
+ if (IS_INTRESOURCE(nameA))
+ {
+ // name is id
+ if (nameA == nameB)
+ foundEntry = true;
+ }
+ else
+ {
+ // name is a string.
+
+ // Check for name enumerated is an id. If so, it doesn't match, skip to next.
+ if (IS_INTRESOURCE(nameB))
+ return false;
+ else
+ foundEntry = !wcscmp(nameB, nameA);
+ }
+
+ return foundEntry;
+}
+
+bool EnumerateLangIDs(const PEDecoder *pDecoder, DWORD rvaOfResourceSection, bool isDirectory, LPCWSTR name, DWORD dataRVA, void *context)
+{
+ ResourceEnumerateNamesState *state = (ResourceEnumerateNamesState*)context;
+ if (isDirectory)
+ return false;
+
+ // Only LangIDs are permitted here
+ if (!IS_INTRESOURCE(name))
+ return false;
+
+ if (dataRVA == 0)
+ return false;
+
+ COUNT_T cbData;
+ DWORD resourceDataRva = ReadResourceDataEntry(pDecoder, dataRVA, &cbData);
+ if (!pDecoder->CheckRva(resourceDataRva, cbData))
+ {
+ return false;
+ }
+
+ BYTE *pData = (BYTE*)pDecoder->GetRvaData(resourceDataRva);
+
+ return state->langIDcallback(state->nameName, state->nameType, (DWORD)name, pData, cbData, state->context);
+}
+
+
+bool EnumerateNames(const PEDecoder *pDecoder, DWORD rvaOfResourceSection, bool isDirectory, LPCWSTR name, DWORD dataRVA, void *context)
+{
+ ResourceEnumerateNamesState *state = (ResourceEnumerateNamesState*)context;
+ if (!isDirectory)
+ return false;
+
+ state->nameName = name;
+ return state->namesCallback(state->nameName, state->nameType, state->context);
+}
+
+bool EnumerateNamesForLangID(const PEDecoder *pDecoder, DWORD rvaOfResourceSection, bool isDirectory, LPCWSTR name, DWORD dataRVA, void *context)
+{
+ ResourceEnumerateNamesState *state = (ResourceEnumerateNamesState*)context;
+ if (!isDirectory)
+ return false;
+
+ bool foundEntry = DoesResourceNameMatch(state->nameName, name);
+
+ if (foundEntry)
+ return EnumerateWin32ResourceTable(pDecoder, rvaOfResourceSection, dataRVA, state->callbackPerLangID, context);
+ else
+ return true; // Keep scanning
+}
+
+
+bool EnumerateTypes(const PEDecoder *pDecoder, DWORD rvaOfResourceSection, bool isDirectory, LPCWSTR name, DWORD dataRVA, void *context)
+{
+ ResourceEnumerateTypesState *state = (ResourceEnumerateTypesState*)context;
+ if (!isDirectory)
+ return false;
+
+ state->nameType = name;
+ return state->callback(name, state->context);
+}
+
+bool EnumerateTypesForNames(const PEDecoder *pDecoder, DWORD rvaOfResourceSection, bool isDirectory, LPCWSTR name, DWORD dataRVA, void *context)
+{
+ ResourceEnumerateNamesState *state = (ResourceEnumerateNamesState*)context;
+ if (!isDirectory)
+ return false;
+
+ bool foundEntry = DoesResourceNameMatch(state->nameType, name);
+
+ if (foundEntry)
+ return EnumerateWin32ResourceTable(pDecoder, rvaOfResourceSection, dataRVA, state->callbackPerName, context);
+ else
+ return true; // Keep scanning
+}
+
+
+bool PEDecoder::EnumerateWin32ResourceTypes(PEDecoder_ResourceTypesCallbackFunction callback, void* context) const
+{
+ if (!HasDirectoryEntry(IMAGE_DIRECTORY_ENTRY_RESOURCE))
+ return true;
+
+ COUNT_T resourceDataSize = 0;
+ IMAGE_DATA_DIRECTORY *pDir = GetDirectoryEntry(IMAGE_DIRECTORY_ENTRY_RESOURCE);
+
+ if (pDir->VirtualAddress == 0)
+ return true;
+
+ DWORD rvaOfResourceSection = pDir->VirtualAddress;
+
+ ResourceEnumerateTypesState state;
+ state.context = context;
+ state.callback = callback;
+
+ return EnumerateWin32ResourceTable(this, rvaOfResourceSection, rvaOfResourceSection, EnumerateTypes, &state);
+}
+
+bool PEDecoder::EnumerateWin32ResourceNames(LPCWSTR lpType, PEDecoder_ResourceNamesCallbackFunction callback, void* context) const
+{
+ if (!HasDirectoryEntry(IMAGE_DIRECTORY_ENTRY_RESOURCE))
+ return true;
+
+ COUNT_T resourceDataSize = 0;
+ IMAGE_DATA_DIRECTORY *pDir = GetDirectoryEntry(IMAGE_DIRECTORY_ENTRY_RESOURCE);
+
+ if (pDir->VirtualAddress == 0)
+ return true;
+
+ DWORD rvaOfResourceSection = pDir->VirtualAddress;
+
+ ResourceEnumerateNamesState state;
+ state.context = context;
+ state.namesCallback = callback;
+ state.langIDcallback = NULL;
+ state.nameType = lpType;
+ state.nameName = NULL;
+ state.callbackPerName = EnumerateNames;
+ state.callbackPerLangID = NULL;
+
+ return EnumerateWin32ResourceTable(this, rvaOfResourceSection, rvaOfResourceSection, EnumerateTypesForNames, &state);
+}
+
+bool PEDecoder::EnumerateWin32Resources(LPCWSTR lpName, LPCWSTR lpType, PEDecoder_ResourceCallbackFunction callback, void* context) const
+{
+ if (!HasDirectoryEntry(IMAGE_DIRECTORY_ENTRY_RESOURCE))
+ return true;
+
+ COUNT_T resourceDataSize = 0;
+ IMAGE_DATA_DIRECTORY *pDir = GetDirectoryEntry(IMAGE_DIRECTORY_ENTRY_RESOURCE);
+
+ if (pDir->VirtualAddress == 0)
+ return true;
+
+ DWORD rvaOfResourceSection = pDir->VirtualAddress;
+
+ ResourceEnumerateNamesState state;
+ state.context = context;
+ state.namesCallback = NULL;
+ state.langIDcallback = callback;
+ state.nameType = lpType;
+ state.nameName = lpName;
+ state.callbackPerName = EnumerateNamesForLangID;
+ state.callbackPerLangID = EnumerateLangIDs;
+
+ return EnumerateWin32ResourceTable(this, rvaOfResourceSection, rvaOfResourceSection, EnumerateTypesForNames, &state);
+}
+
BOOL PEDecoder::HasNativeHeader() const
{
CONTRACT(BOOL)