From: Vibhav Pant vibhavp@gmail.com
--- dlls/rometadata/assembly.c | 61 +++++++++++++++++++++--------- dlls/rometadata/main.c | 13 +++++-- dlls/rometadata/mdtables.c | 21 +++++++++- dlls/rometadata/rometadatapriv.h | 4 +- dlls/rometadata/tests/rometadata.c | 12 +++--- 5 files changed, 83 insertions(+), 28 deletions(-)
diff --git a/dlls/rometadata/assembly.c b/dlls/rometadata/assembly.c index 1fb4d82a383..bcdd4c6890e 100644 --- a/dlls/rometadata/assembly.c +++ b/dlls/rometadata/assembly.c @@ -455,6 +455,7 @@ struct table_info
struct assembly { + BOOL mapped; HANDLE file; HANDLE map; const BYTE *data; @@ -603,13 +604,13 @@ static HRESULT assembly_parse_metadata_tables(assembly_t *assembly) for (i = 0; i < 64; i++) { if (!assembly_table_exists(assembly, i)) continue; - if (i >= TABLE_MAX) return E_INVALIDARG; + if (i >= TABLE_MAX) return CLDB_E_FILE_CORRUPT; assert(table_schemas[i]); num_tables++; }
cur_table = tables_stream_start + offsetof(struct stream_tables_hdr, table_rows[num_tables]); - if ((UINT_PTR)(cur_table - assembly->data) > assembly->size) return E_INVALIDARG; + if ((UINT_PTR)(cur_table - assembly->data) > assembly->size) return CLDB_E_FILE_CORRUPT;
num_tables = 0; for (i = 0; i < TABLE_MAX; i++) @@ -627,7 +628,7 @@ static HRESULT assembly_parse_metadata_tables(assembly_t *assembly) { table->start = cur_table; cur_table += (size_t)(assembly->tables[i].num_rows * table->row_size); - if ((UINT_PTR)(cur_table - assembly->data) > assembly->size) return E_INVALIDARG; + if ((UINT_PTR)(cur_table - assembly->data) > assembly->size) return CLDB_E_FILE_CORRUPT; } } return S_OK; @@ -644,12 +645,13 @@ static HRESULT assembly_parse_headers(assembly_t *assembly) UINT32 rva, num_sections, offset; UINT8 num_streams, i;
+ if (!assembly->size) return CLDB_E_NO_DATA; if (assembly->size < sizeof(IMAGE_DOS_HEADER) || dos_hdr->e_magic != IMAGE_DOS_SIGNATURE || assembly->size < (dos_hdr->e_lfanew + sizeof(IMAGE_NT_HEADERS32))) - return E_INVALIDARG; + return CLDB_E_FILE_CORRUPT;
nt_hdrs = (IMAGE_NT_HEADERS32 *)(assembly->data + dos_hdr->e_lfanew); - if (!(num_sections = nt_hdrs->FileHeader.NumberOfSections)) return E_INVALIDARG; + if (!(num_sections = nt_hdrs->FileHeader.NumberOfSections)) return CLDB_E_FILE_CORRUPT; switch (nt_hdrs->OptionalHeader.Magic) { case IMAGE_NT_OPTIONAL_HDR32_MAGIC: @@ -660,29 +662,29 @@ static HRESULT assembly_parse_headers(assembly_t *assembly) { const IMAGE_NT_HEADERS64 *hdr64 = (IMAGE_NT_HEADERS64 *)(assembly->data + dos_hdr->e_lfanew);
- if (dos_hdr->e_lfanew + sizeof(IMAGE_NT_HEADERS64) > assembly->size) return E_INVALIDARG; + if (dos_hdr->e_lfanew + sizeof(IMAGE_NT_HEADERS64) > assembly->size) return CLDB_E_FILE_CORRUPT; rva = hdr64->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR].VirtualAddress; sections = (IMAGE_SECTION_HEADER *)(assembly->data + dos_hdr->e_lfanew + sizeof(IMAGE_NT_HEADERS64)); break; } default: - return E_INVALIDARG; + return CLDB_E_FILE_CORRUPT; }
if (!pe_rva_to_offset(sections, num_sections, rva, &offset) || offset + sizeof(IMAGE_COR20_HEADER) > assembly->size) - return E_INVALIDARG; + return CLDB_E_FILE_CORRUPT;
cor_hdr = (IMAGE_COR20_HEADER *)(assembly->data + offset); - if (cor_hdr->cb != sizeof(IMAGE_COR20_HEADER)) return E_INVALIDARG; + if (cor_hdr->cb != sizeof(IMAGE_COR20_HEADER)) return CLDB_E_FILE_CORRUPT; if (!(pe_rva_to_offset(sections, num_sections, cor_hdr->MetaData.VirtualAddress, &offset)) || offset + sizeof(struct metadata_hdr) > assembly->size) - return E_INVALIDARG; + return CLDB_E_FILE_CORRUPT;
md_start = assembly->data + offset; md_hdr = (struct metadata_hdr *)md_start; if (md_hdr->signature != METADATA_MAGIC || offset + offsetof(struct metadata_hdr, version[md_hdr->length]) + sizeof(UINT16) * 2 > assembly->size) - return E_INVALIDARG; + return CLDB_E_FILE_CORRUPT;
num_streams = *(UINT8 *)(md_start + offsetof(struct metadata_hdr, version[md_hdr->length]) + sizeof(UINT16)); /* Flags */ streams_cur = md_start + offsetof(struct metadata_hdr, version[md_hdr->length]) + sizeof(UINT16) * 2; /* Flags + Streams */ @@ -703,10 +705,10 @@ static HRESULT assembly_parse_headers(assembly_t *assembly) { "#GUID", 5, &assembly->stream_guids }, { "#US", 3, &assembly->stream_user_strings } }; - HRESULT hr = E_INVALIDARG; + HRESULT hr = CLDB_E_FILE_CORRUPT; int j;
- if ((UINT_PTR)(streams_cur - assembly->data) > assembly->size) return E_INVALIDARG; + if ((UINT_PTR)(streams_cur - assembly->data) > assembly->size) return CLDB_E_FILE_CORRUPT; for (j = 0; j < ARRAY_SIZE(streams); j++) { if (!strncmp(streams[j].name, md_stream_hdr->name, streams[j].name_len)) @@ -735,12 +737,32 @@ static HRESULT assembly_parse_headers(assembly_t *assembly) ptr--; }
- if (assembly->stream_tables.size < sizeof(struct stream_tables_hdr)) return E_INVALIDARG; + if (assembly->stream_tables.size < sizeof(struct stream_tables_hdr)) return CLDB_E_FILE_CORRUPT; assembly->tables_hdr = (struct stream_tables_hdr *)assembly->stream_tables.start;
return assembly_parse_metadata_tables(assembly); }
+HRESULT assembly_open_from_data(const BYTE *data, ULONG data_size, assembly_t **ret) +{ + assembly_t *assembly; + HRESULT hr; + + TRACE("(%p, %lu, %p)\n", data, data_size, ret); + + if (!data) return E_FAIL; + if (!(assembly = calloc(1, sizeof(*assembly)))) return E_OUTOFMEMORY; + + assembly->mapped = FALSE; + assembly->data = data; + assembly->size = data_size; + if (FAILED((hr = assembly_parse_headers(assembly)))) + assembly_free(assembly); + else + *ret = assembly; + return hr; +} + HRESULT assembly_open_from_file(const WCHAR *path, assembly_t **ret) { assembly_t *assembly; @@ -749,6 +771,8 @@ HRESULT assembly_open_from_file(const WCHAR *path, assembly_t **ret) TRACE("(%s, %p)\n", debugstr_w(path), ret);
if (!(assembly = calloc(1, sizeof(*assembly)))) return E_OUTOFMEMORY; + + assembly->mapped = TRUE; assembly->file = CreateFileW(path, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); if (assembly->file == INVALID_HANDLE_VALUE) { @@ -786,9 +810,12 @@ void assembly_free(assembly_t *assembly) ULONG i;
for (i = 0; i < TABLE_MAX; i++) free(assembly->tables[i].columns_size); - if (assembly->data) UnmapViewOfFile(assembly->data); - CloseHandle(assembly->map); - CloseHandle(assembly->file); + if (assembly->mapped) + { + if (assembly->data) UnmapViewOfFile(assembly->data); + CloseHandle(assembly->map); + CloseHandle(assembly->file); + } free(assembly); }
diff --git a/dlls/rometadata/main.c b/dlls/rometadata/main.c index 346753009a7..025f0ffa19f 100644 --- a/dlls/rometadata/main.c +++ b/dlls/rometadata/main.c @@ -96,7 +96,7 @@ static HRESULT WINAPI MetaDataDispenser_OpenScope(IMetaDataDispenserEx *iface, c FIXME("%p %s %lx %s %p semi-stub!\n", iface, debugstr_w(scope), open_flags, debugstr_guid(riid), obj);
*obj = NULL; - hr = IMetaDataTables_create(scope, &tables); + hr = IMetaDataTables_create_from_file(scope, &tables); if (FAILED(hr)) return hr;
@@ -109,8 +109,15 @@ static HRESULT WINAPI MetaDataDispenser_OpenScopeOnMemory(IMetaDataDispenserEx * ULONG data_size, DWORD open_flags, REFIID riid, IUnknown **obj) { - FIXME("%p %p %lu %lx %s %p\n", iface, data, data_size, open_flags, debugstr_guid(riid), obj); - return E_NOTIMPL; + IMetaDataTables *tables; + HRESULT hr; + + FIXME("%p %p %lu %lx %s %p semi-stub!\n", iface, data, data_size, open_flags, debugstr_guid(riid), obj); + + *obj = NULL; + if (FAILED((hr = IMetaDataTables_create_from_data(data, data_size, &tables)))) return hr; + hr = IMetaDataTables_QueryInterface(tables, riid, (void **)obj); + return hr; }
static HRESULT WINAPI MetaDataDispenser_SetOption(IMetaDataDispenserEx *iface, REFGUID option_id, const VARIANT *value) diff --git a/dlls/rometadata/mdtables.c b/dlls/rometadata/mdtables.c index 71cacb10f95..0cb471fb3e4 100644 --- a/dlls/rometadata/mdtables.c +++ b/dlls/rometadata/mdtables.c @@ -1376,7 +1376,7 @@ static const IMetaDataImportVtbl import_vtbl = { import_IsGlobal };
-HRESULT IMetaDataTables_create(const WCHAR *path, IMetaDataTables **iface) +HRESULT IMetaDataTables_create_from_file(const WCHAR *path, IMetaDataTables **iface) { struct metadata_tables *impl; HRESULT hr; @@ -1394,3 +1394,22 @@ HRESULT IMetaDataTables_create(const WCHAR *path, IMetaDataTables **iface) *iface = &impl->IMetaDataTables_iface; return S_OK; } + +HRESULT IMetaDataTables_create_from_data(const BYTE *data, ULONG data_size, IMetaDataTables **iface) +{ + struct metadata_tables *impl; + HRESULT hr; + + if (!(impl = calloc(1, sizeof(*impl)))) return E_OUTOFMEMORY; + if (FAILED((hr = assembly_open_from_data(data, data_size, &impl->assembly)))) + { + free(impl); + return hr; + } + + impl->IMetaDataTables_iface.lpVtbl = &tables_vtbl; + impl->IMetaDataImport_iface.lpVtbl = &import_vtbl; + impl->ref = 1; + *iface = &impl->IMetaDataTables_iface; + return S_OK; +} \ No newline at end of file diff --git a/dlls/rometadata/rometadatapriv.h b/dlls/rometadata/rometadatapriv.h index e91a50a133f..2198ed44f34 100644 --- a/dlls/rometadata/rometadatapriv.h +++ b/dlls/rometadata/rometadatapriv.h @@ -21,7 +21,8 @@
#include <rometadataapi.h>
-extern HRESULT IMetaDataTables_create(const WCHAR *path, IMetaDataTables **iface); +extern HRESULT IMetaDataTables_create_from_file(const WCHAR *path, IMetaDataTables **iface); +extern HRESULT IMetaDataTables_create_from_data(const BYTE *data, ULONG data_size, IMetaDataTables **iface);
typedef struct assembly assembly_t; struct metadata_table_info @@ -105,6 +106,7 @@ enum table };
extern HRESULT assembly_open_from_file(const WCHAR *path, assembly_t **out); +extern HRESULT assembly_open_from_data(const BYTE *data, ULONG data_size, assembly_t **out); extern void assembly_free(assembly_t *assembly); extern HRESULT assembly_get_table(const assembly_t *assembly, ULONG table_idx, struct metadata_table_info *info); extern HRESULT assembly_get_column(const assembly_t *assembly, ULONG table_idx, ULONG column_idx, struct metadata_column_info *info); diff --git a/dlls/rometadata/tests/rometadata.c b/dlls/rometadata/tests/rometadata.c index 1d656467ff3..d6f856b0fce 100644 --- a/dlls/rometadata/tests/rometadata.c +++ b/dlls/rometadata/tests/rometadata.c @@ -565,24 +565,24 @@ static void test_MetaDataDispenser_OpenScope(void) ok(hr == S_OK, "got hr %#lx\n", hr);
hr = IMetaDataDispenser_OpenScopeOnMemory(dispenser, NULL, 0, 0, &IID_IMetaDataTables, (IUnknown **)&md_tables); - todo_wine ok(hr == E_FAIL, "got hr %#lx\n", hr); + ok(hr == E_FAIL, "got hr %#lx\n", hr);
hr = IMetaDataDispenser_OpenScopeOnMemory(dispenser, NULL, md_size, 0, &IID_IMetaDataTables, (IUnknown **)&md_tables); - todo_wine ok(hr == E_FAIL, "got hr %#lx\n", hr); + ok(hr == E_FAIL, "got hr %#lx\n", hr);
hr = IMetaDataDispenser_OpenScopeOnMemory(dispenser, md_bytes, 0, 0, &IID_IMetaDataTables, (IUnknown **)&md_tables); - todo_wine ok(hr == CLDB_E_NO_DATA, "got hr %#lx\n", hr); + ok(hr == CLDB_E_NO_DATA, "got hr %#lx\n", hr);
hr = IMetaDataDispenser_OpenScopeOnMemory(dispenser, md_bytes, sizeof(IMAGE_DOS_HEADER), 0, &IID_IMetaDataTables, (IUnknown **)&md_tables); - todo_wine ok(hr == CLDB_E_FILE_CORRUPT, "got hr %#lx\n", hr); + ok(hr == CLDB_E_FILE_CORRUPT, "got hr %#lx\n", hr);
hr = IMetaDataDispenser_OpenScopeOnMemory(dispenser, md_bytes, md_size, 0, &IID_IMetaDataTables, (IUnknown **)&md_tables); - todo_wine ok(hr == S_OK, "got hr %#lx\n", hr); - if (SUCCEEDED(hr)) IMetaDataTables_Release(md_tables); + ok(hr == S_OK, "got hr %#lx\n", hr); + IMetaDataTables_Release(md_tables);
hr = IMetaDataDispenser_OpenScope(dispenser, filename, 0, &IID_IMetaDataTables, (IUnknown **)&md_tables); ok(hr == S_OK, "got hr %#lx\n", hr);