-- v3: rometadata: Implement IMetaDataImport::GetCustomAttributeByName. rometadata: Implement IMetaDataTables::{EnumProperties, GetPropertyProps}. rometadata: Implement IMetaDataDispenser::OpenScopeOnMemory.
From: Vibhav Pant vibhavp@gmail.com
--- dlls/rometadata/tests/rometadata.c | 48 ++++++++++++++++++++++++------ 1 file changed, 39 insertions(+), 9 deletions(-)
diff --git a/dlls/rometadata/tests/rometadata.c b/dlls/rometadata/tests/rometadata.c index 6be43222c6f..da12578a6dd 100644 --- a/dlls/rometadata/tests/rometadata.c +++ b/dlls/rometadata/tests/rometadata.c @@ -65,13 +65,24 @@ static void test_MetaDataGetDispenser(void) IMetaDataDispenserEx_Release(dispenser_ex); }
+static const BYTE *load_resource_data(const WCHAR *name, ULONG *data_size) +{ + const BYTE *data; + HRSRC res; + + res = FindResourceW(NULL, name, (LPCWSTR)RT_RCDATA); + ok(!!res, "Failed to load resource %s, error %lu.\n", debugstr_w(name), GetLastError()); + data = LockResource(LoadResource(GetModuleHandleA(NULL), res)); + *data_size = SizeofResource(GetModuleHandleA(NULL), res); + return data; +} + static WCHAR *load_resource(const WCHAR *name) { static WCHAR pathW[MAX_PATH]; - DWORD written; + DWORD written, res_size; + const BYTE *data; HANDLE file; - HRSRC res; - void *ptr;
GetTempPathW(ARRAY_SIZE(pathW), pathW); wcscat(pathW, name); @@ -80,11 +91,9 @@ static WCHAR *load_resource(const WCHAR *name) ok(file != INVALID_HANDLE_VALUE, "Failed to create file %s, error %lu.\n", wine_dbgstr_w(pathW), GetLastError());
- res = FindResourceW(NULL, name, (LPCWSTR)RT_RCDATA); - ok(!!res, "Failed to load resource, error %lu.\n", GetLastError()); - ptr = LockResource(LoadResource(GetModuleHandleA(NULL), res)); - WriteFile(file, ptr, SizeofResource( GetModuleHandleA(NULL), res), &written, NULL); - ok(written == SizeofResource(GetModuleHandleA(NULL), res), "Failed to write resource.\n"); + data = load_resource_data(name, &res_size); + WriteFile(file, data, res_size, &written, NULL); + ok(written == res_size, "Failed to write resource.\n"); CloseHandle(file);
return pathW; @@ -541,8 +550,9 @@ static void test_MetaDataDispenser_OpenScope(void) { tdInterface | tdAbstract | tdWindowsRuntime, "ITest1", "Wine.Test" }, { tdPublic | tdSealed | tdWindowsRuntime, "Test1", "Wine.Test" }, }; + ULONG val = 0, i, guid_ctor_idx = 0, itest1_def_idx = 0, md_size; + const BYTE *md_bytes = load_resource_data(L"test-simple.winmd", &md_size); const WCHAR *filename = load_resource(L"test-simple.winmd"); - ULONG val = 0, i, guid_ctor_idx = 0, itest1_def_idx = 0; const struct row_typedef *type_def = NULL; const struct row_module *module = NULL; IMetaDataDispenser *dispenser; @@ -554,6 +564,26 @@ static void test_MetaDataDispenser_OpenScope(void) hr = MetaDataGetDispenser(&CLSID_CorMetaDataDispenser, &IID_IMetaDataDispenser, (void **)&dispenser); 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); + + hr = IMetaDataDispenser_OpenScopeOnMemory(dispenser, NULL, md_size, 0, &IID_IMetaDataTables, + (IUnknown **)&md_tables); + todo_wine 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); + + 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); + + 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); + hr = IMetaDataDispenser_OpenScope(dispenser, filename, 0, &IID_IMetaDataTables, (IUnknown **)&md_tables); ok(hr == S_OK, "got hr %#lx\n", hr); IMetaDataDispenser_Release(dispenser);
From: Vibhav Pant vibhavp@gmail.com
--- dlls/rometadata/tests/rometadata.c | 9 +++++++++ 1 file changed, 9 insertions(+)
diff --git a/dlls/rometadata/tests/rometadata.c b/dlls/rometadata/tests/rometadata.c index da12578a6dd..1d656467ff3 100644 --- a/dlls/rometadata/tests/rometadata.c +++ b/dlls/rometadata/tests/rometadata.c @@ -1258,6 +1258,15 @@ static void test_IMetaDataImport(void) guid = (GUID *)&data[2]; ok(IsEqualGUID(guid, &IID_ITest2), "got guid %s\n", debugstr_guid(guid)); } + hr = IMetaDataImport_GetCustomAttributeByName(md_import, typedef1, guid_attribute_name, NULL, NULL); + todo_wine ok(hr == S_OK, "got hr %#lx\n", hr); + hr = IMetaDataImport_GetCustomAttributeByName(md_import, typedef1, NULL, &data, &buf_len); + todo_wine ok(hr == S_FALSE, "got hr %#lx\n", hr); + hr = IMetaDataImport_GetCustomAttributeByName(md_import, mdTypeDefNil, L"foo", &data, &buf_len); + todo_wine ok(hr == S_FALSE, "got hr %#lx\n", hr); + hr = IMetaDataImport_GetCustomAttributeByName(md_import, TokenFromRid(1, mdtCustomAttribute), L"foo", &data, + &buf_len); + todo_wine ok(hr == S_FALSE, "got hr %#lx\n", hr);
typedef1 = buf_len = 0; hr = IMetaDataImport_FindTypeDefByName(md_import, L"Wine.Test.ITest3", 0, &typedef1);
From: Vibhav Pant vibhavp@gmail.com
--- dlls/rometadata/assembly.c | 20 +++++++++++++------- 1 file changed, 13 insertions(+), 7 deletions(-)
diff --git a/dlls/rometadata/assembly.c b/dlls/rometadata/assembly.c index 83b8e7338bb..88865cf37a5 100644 --- a/dlls/rometadata/assembly.c +++ b/dlls/rometadata/assembly.c @@ -885,8 +885,9 @@ const char *assembly_get_string(const assembly_t *assembly, ULONG idx) return idx < assembly->stream_strings.size ? (const char *)&assembly->stream_strings.start[idx] : NULL; }
-static HRESULT decode_int(const BYTE *encoded, ULONG *val, ULONG *len) +static BOOL decode_int(const BYTE *encoded, SIZE_T encoded_len, ULONG *val, ULONG *len) { + if (!encoded_len) return FALSE; if (!(encoded[0] & 0x80)) { *len = 1; @@ -894,28 +895,33 @@ static HRESULT decode_int(const BYTE *encoded, ULONG *val, ULONG *len) } else if (!(encoded[0] & 0x40)) { + if (encoded_len < 2) return FALSE; *len = 2; *val = ((encoded[0] & ~0xc0) << 8) + encoded[1]; } else if (!(encoded[0] & 0x20)) { + if (encoded_len < 4) return FALSE; *len = 4; *val = ((encoded[0] & ~0xe0) << 24) + (encoded[1] << 16) + (encoded[2] << 8) + encoded[3]; } else - return E_INVALIDARG; - return S_OK; + return FALSE; + return TRUE; }
-HRESULT assembly_get_blob(const assembly_t *assembly, ULONG idx, const BYTE **blob, ULONG *size) +HRESULT assembly_get_blob(const assembly_t *assembly, ULONG idx, const BYTE **blob, ULONG *ret_size) { + ULONG size, size_len; const BYTE *ptr; - ULONG size_len; - HRESULT hr;
if (idx >= assembly->stream_blobs.size) return E_INVALIDARG; ptr = assembly->stream_blobs.start + idx; - if (FAILED(hr = decode_int(ptr, size, &size_len))) return hr; + /* We can decode upto the end of the blobs stream. */ + if (!decode_int(ptr, assembly->stream_blobs.size - idx, &size, &size_len) || + ptr + size_len >= assembly->stream_blobs.start + assembly->stream_blobs.size) + return E_INVALIDARG; + *ret_size = size; *blob = ptr + size_len; return S_OK; }
From: Vibhav Pant vibhavp@gmail.com
--- dlls/rometadata/assembly.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-)
diff --git a/dlls/rometadata/assembly.c b/dlls/rometadata/assembly.c index 88865cf37a5..1fb4d82a383 100644 --- a/dlls/rometadata/assembly.c +++ b/dlls/rometadata/assembly.c @@ -513,7 +513,7 @@ static ULONG bit_width(ULONG n) { ULONG bits = 1;
- for (n = n - 1; n; n >>= 1) + for (n = (n - 1) >> 1; n; n >>= 1) bits++; return bits; } @@ -549,8 +549,9 @@ ULONG metadata_coded_value_as_token(ULONG table_idx, ULONG column_idx, ULONG val column = &table_schemas[table_idx]->columns[column_idx]; assert(column->type == COLUMN_CODED_IDX);
- tag_bits = bit_width(column->size.coded.len - 1); + tag_bits = bit_width(column->size.coded.len); table_mask = ((1UL << tag_bits) - 1); + assert((value & table_mask) < column->size.coded.len); return TokenFromRid((value & ~table_mask) >> tag_bits, TokenFromTable(column->size.coded.tables[value & table_mask])); }
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);
From: Vibhav Pant vibhavp@gmail.com
--- dlls/rometadata/mdtables.c | 148 ++++++++++++++++++++++++++--- dlls/rometadata/tests/rometadata.c | 34 +++---- include/corhdr.h | 10 ++ 3 files changed, 162 insertions(+), 30 deletions(-)
diff --git a/dlls/rometadata/mdtables.c b/dlls/rometadata/mdtables.c index 0cb471fb3e4..773400457de 100644 --- a/dlls/rometadata/mdtables.c +++ b/dlls/rometadata/mdtables.c @@ -845,7 +845,7 @@ static HRESULT token_get_parent_typedef(IMetaDataImport *iface, mdToken token, t
TRACE("(%p, %s, %p, %p)\n", iface, debugstr_mdToken(token), enum_func, parent);
- assert(type == mdtMethodDef || type == mdtFieldDef); + assert(type == mdtMethodDef || type == mdtFieldDef || type == mdtProperty);
*parent = mdTypeDefNil; hr = IMetaDataImport_EnumTypeDefs(iface, &typedef_enum, &cur_typedef, 1, NULL); @@ -957,11 +957,41 @@ static HRESULT WINAPI import_GetMemberRefProps(IMetaDataImport *iface, mdMemberR return E_NOTIMPL; }
-static HRESULT WINAPI import_EnumProperties(IMetaDataImport *iface, HCORENUM *henum, mdTypeDef type_def, +static HRESULT WINAPI import_EnumProperties(IMetaDataImport *iface, HCORENUM *ret_henum, mdTypeDef type_def, mdProperty *props, ULONG len, ULONG *count) { - FIXME("(%p, %p, %#x, %p, %lu, %p): stub!\n", iface, henum, type_def, props, len, count); - return E_NOTIMPL; + struct metadata_tables *impl = impl_from_IMetaDataImport(iface); + ULONG num_propertymap_rows, i; + HRESULT hr; + + TRACE("(%p, %p, %s, %p, %lu, %p)\n", iface, ret_henum, debugstr_mdToken(type_def), props, len, count); + + if (count) *count = 0; + if (TypeFromToken(type_def) != mdtTypeDef || IsNilToken(type_def)) return S_FALSE; + + if (!*ret_henum) + { + if (FAILED((hr = table_get_num_rows(&impl->IMetaDataTables_iface, TABLE_PROPERTYMAP, &num_propertymap_rows)))) + return hr; + for (i = 1; i <= num_propertymap_rows; i++) + { + ULONG parent; + + hr = IMetaDataTables_GetColumn(&impl->IMetaDataTables_iface, TABLE_PROPERTYMAP, 0, i, &parent); + if (FAILED(hr)) return hr; + + if (parent == RidFromToken(type_def)) + { + hr = table_create_enum_from_token_list(&impl->IMetaDataTables_iface, TABLE_PROPERTYMAP, TABLE_PROPERTY, + i, 1, ret_henum); + if (hr != S_OK) return hr; + break; + } + } + if (!*ret_henum) return S_FALSE; + } + + return token_enum_get_entries(*ret_henum, mdtProperty, props, len, count); }
static HRESULT WINAPI import_EnumEvents(IMetaDataImport *iface, HCORENUM *henum, mdTypeDef type_def, mdEvent *events, @@ -1253,17 +1283,109 @@ static HRESULT WINAPI import_GetFieldProps(IMetaDataImport *iface, mdFieldDef fi return (field_name && name_needed > name_len) ? CLDB_S_TRUNCATION : S_OK; }
+static HRESULT property_get_parent_typedef(IMetaDataImport *iface, mdProperty property, mdTypeDef *parent) +{ + return token_get_parent_typedef(iface, property, iface->lpVtbl->EnumProperties, parent); +} + static HRESULT WINAPI import_GetPropertyProps(IMetaDataImport *iface, mdProperty prop, mdTypeDef *type_def, WCHAR *name, ULONG name_len, ULONG *name_written, ULONG *prop_flags, - const COR_SIGNATURE **sig_blob, ULONG *sig_len, ULONG *value_type_flag, - UVCP_CONSTANT *default_value, ULONG *value_len, mdMethodDef *set_method, - mdMethodDef *get_method, mdMethodDef *other_methods, ULONG other_len, - ULONG *other_count) -{ - FIXME("(%p, %#x, %p, %p, %lu, %p, %p, %p, %p, %p, %p, %p, %p, %p, %p, %lu, %p): stub!\n", iface, prop, type_def, - name, name_len, name_written, prop_flags, sig_blob, sig_len, value_type_flag, default_value, value_len, - set_method, get_method, other_methods, other_len, other_count); - return E_NOTIMPL; + const COR_SIGNATURE **ret_sig_blob, ULONG *ret_sig_len, + ULONG *value_type_flag, UVCP_CONSTANT *default_value, ULONG *value_len, + mdMethodDef *ret_set_method, mdMethodDef *ret_get_method, + mdMethodDef *other_methods, ULONG other_len, ULONG *ret_other_count) +{ + ULONG flags = 0, sig_len = 0, name_needed = 0, val_len = 0, val_type = ELEMENT_TYPE_VOID, other_count = 0; + mdToken parent = mdTypeDefNil, get_method = mdMethodDefNil, set_method = mdMethodDefNil; + struct metadata_tables *impl = impl_from_IMetaDataImport(iface); + const BYTE *sig_blob = NULL, *val_blob = NULL; + HRESULT hr; + + TRACE("(%p, %s, %p, %p, %lu, %p, %p, %p, %p, %p, %p, %p, %p, %p, %p, %lu, %p)\n", iface, debugstr_mdToken(prop), + type_def, name, name_len, name_written, prop_flags, ret_sig_blob, ret_sig_len, value_type_flag, default_value, + value_len, ret_set_method, ret_get_method, other_methods, other_len, ret_other_count); + + if (TypeFromToken(prop) != mdtProperty) return S_FALSE; + + if (name && name_len) + name[0] = L'\0'; + if (!IsNilToken(prop)) + { + ULONG name_idx, sig_idx, num_methodsemantics, semantic_row; + const ULONG row = RidFromToken(prop); + const char *nameA; + + if (FAILED((hr = IMetaDataTables_GetColumn(&impl->IMetaDataTables_iface, TABLE_PROPERTY, 0, row, &flags)))) + return hr; + if (FAILED((hr = IMetaDataTables_GetColumn(&impl->IMetaDataTables_iface, TABLE_PROPERTY, 1, row, &name_idx)))) + return hr; + if (FAILED((hr = IMetaDataTables_GetColumn(&impl->IMetaDataTables_iface, TABLE_PROPERTY, 2, row, &sig_idx)))) + return hr; + + if (FAILED((hr = IMetaDataTables_GetString(&impl->IMetaDataTables_iface, name_idx, &nameA)))) + return hr; + if (FAILED((hr = IMetaDataTables_GetBlob(&impl->IMetaDataTables_iface, sig_idx, &sig_len, &sig_blob)))) + return hr; + if (FAILED((hr = property_get_parent_typedef(&impl->IMetaDataImport_iface, prop, &parent)))) + return hr; + if (FAILED((hr = token_get_constant_value(&impl->IMetaDataImport_iface, prop, &val_type, &val_blob, &val_len)))) + return hr; + + if (FAILED((hr = table_get_num_rows(&impl->IMetaDataTables_iface, TABLE_METHODSEMANTICS, &num_methodsemantics)))) + return hr; + + for (semantic_row = 1; semantic_row <= num_methodsemantics; semantic_row++) + { + ULONG assoc_token, semantic, method; + + hr = IMetaDataTables_GetColumn(&impl->IMetaDataTables_iface, TABLE_METHODSEMANTICS, 2, semantic_row, + &assoc_token); + if (FAILED(hr)) return hr; + if (assoc_token != prop) continue; + hr = IMetaDataTables_GetColumn(&impl->IMetaDataTables_iface, TABLE_METHODSEMANTICS, 0, semantic_row, + &semantic); + if (FAILED(hr)) return hr; + hr = IMetaDataTables_GetColumn(&impl->IMetaDataTables_iface, TABLE_METHODSEMANTICS, 1, semantic_row, + &method); + if (FAILED(hr)) return hr; + if (IsNilToken(get_method) && semantic & msGetter) + get_method = TokenFromRid(method, mdtMethodDef); + else if (IsNilToken(set_method) && semantic & msSetter) + set_method = TokenFromRid(method, mdtMethodDef); + else if (other_methods && other_count < other_len && semantic & msOther) + other_methods[other_count++] = TokenFromRid(method, mdtMethodDef); + } + + name_needed = MultiByteToWideChar(CP_ACP, 0, nameA, -1, NULL, 0); + if (name && name_len) + { + ULONG n = MultiByteToWideChar(CP_ACP, 0, nameA, min(strlen(nameA), name_len - 1), name, name_len - 1); + name[n] = L'\0'; + } + } + if (type_def) + *type_def = parent; + if (name_written) + *name_written = name_needed; + if (prop_flags) + *prop_flags = flags; + if (ret_sig_blob) + *ret_sig_blob = sig_blob; + if (ret_sig_len) + *ret_sig_len = sig_len; + if (value_type_flag) + *value_type_flag = val_type; + if (default_value) + *default_value = (UVCP_CONSTANT)val_blob; + if (value_len) + *value_len = val_len; + if (ret_get_method) + *ret_get_method = get_method; + if (ret_set_method) + *ret_set_method = set_method; + if (ret_other_count) + *ret_other_count = other_count; + return S_OK; }
static HRESULT WINAPI import_GetParamProps(IMetaDataImport *iface, mdParamDef param_def, mdMethodDef *method_def, diff --git a/dlls/rometadata/tests/rometadata.c b/dlls/rometadata/tests/rometadata.c index d6f856b0fce..9f81e1e29ba 100644 --- a/dlls/rometadata/tests/rometadata.c +++ b/dlls/rometadata/tests/rometadata.c @@ -950,16 +950,15 @@ static void test_prop_method_token_(int line, IMetaDataImport *md_import, mdType
ok_(__FILE__, line)(token && token != mdMethodDefNil, "got token %#x\n", token); valid = IMetaDataImport_IsValidToken(md_import, token); - ok_(__FILE__, line)(valid, "got value %d\n", valid); + todo_wine ok_(__FILE__, line)(valid, "got value %d\n", valid); name[0] = L'\0'; hr = IMetaDataImport_GetMethodProps(md_import, token, &type_def, name, ARRAY_SIZE(name), NULL, &attrs, NULL, NULL, NULL, &impl); - todo_wine ok_(__FILE__, line)(hr == S_OK, "GetMethodProps failed, got hr %#lx\n", hr); + ok_(__FILE__, line)(hr == S_OK, "GetMethodProps failed, got hr %#lx\n", hr); swprintf(exp_name, ARRAY_SIZE(exp_name), L"%s_%s", prefix, prop_name); - todo_wine ok_(__FILE__, line)(!wcscmp(name, exp_name), "got name %s != %s\n", debugstr_w(name), - debugstr_w(exp_name)); - todo_wine ok_(__FILE__, line)(attrs == exp_attrs, "got attrs %#lx != %#x\n", attrs, exp_attrs); - todo_wine ok_(__FILE__, line)(!impl, "got impl %#lx\n", impl); + ok_(__FILE__, line)(!wcscmp(name, exp_name), "got name %s != %s\n", debugstr_w(name), debugstr_w(exp_name)); + ok_(__FILE__, line)(attrs == exp_attrs, "got attrs %#lx != %#x\n", attrs, exp_attrs); + ok_(__FILE__, line)(!impl, "got impl %#lx\n", impl); }
static void test_IMetaDataImport(void) @@ -1273,16 +1272,17 @@ static void test_IMetaDataImport(void) ok(hr == S_OK, "got hr %#lx\n", hr); henum = NULL; hr = IMetaDataImport_EnumProperties(md_import, &henum, typedef1, NULL, 0, NULL); - todo_wine ok(hr == S_FALSE, "got hr %#lx\n", hr); + ok(hr == S_FALSE, "got hr %#lx\n", hr); hr = IMetaDataImport_CountEnum(md_import, henum, &buf_len); ok(hr == S_OK, "got hr %#lx\n", hr); - todo_wine ok(buf_len == ARRAY_SIZE(test3_props), "got buf_len %lu\n", buf_len); + ok(buf_len == ARRAY_SIZE(test3_props), "got buf_len %lu\n", buf_len); property_tokens = calloc(buf_len, sizeof(*property_tokens)); ok(!!property_tokens, "got property_tokens %p\n", property_tokens); buf_count = 0xdeadbeef; hr = IMetaDataImport_EnumProperties(md_import, &henum, typedef1, property_tokens, buf_len, &buf_count); - todo_wine ok(hr == S_OK, "got hr %#lx\n", hr); - todo_wine ok(buf_count == buf_len, "got buf_count %lu != %lu\n", buf_count, buf_len); + ok(hr == S_OK, "got hr %#lx\n", hr); + + ok(buf_count == buf_len, "got buf_count %lu != %lu\n", buf_count, buf_len); IMetaDataImport_CloseEnum(md_import, henum); for (i = 0; i < buf_len; i++) { @@ -1300,11 +1300,11 @@ static void test_IMetaDataImport(void) hr = IMetaDataImport_GetPropertyProps(md_import, property_tokens[i], &typedef2, name, ARRAY_SIZE(name), &str_reqd, &val, &sig_blob, &sig_len, &value_type, &value, &value_len, &set_method, &get_method, NULL, 0, NULL); - todo_wine ok(hr == S_OK, "got hr %#lx\n", hr); - todo_wine ok(typedef1 == typedef2, "got typedef1 %#x != %#x\n", typedef1, typedef2); - todo_wine ok(!wcscmp(name, props->exp_name), "got name %s != %s\n", debugstr_w(name), debugstr_w(props->exp_name)); - todo_wine ok(!!sig_blob, "got sig_blob %p\n", sig_blob); - todo_wine ok(sig_len == props->exp_sig_len, "got sig_len %lu != %lu\n", sig_len, props->exp_sig_len); + ok(hr == S_OK, "got hr %#lx\n", hr); + ok(typedef1 == typedef2, "got typedef1 %#x != %#x\n", typedef1, typedef2); + ok(!wcscmp(name, props->exp_name), "got name %s != %s\n", debugstr_w(name), debugstr_w(props->exp_name)); + ok(!!sig_blob, "got sig_blob %p\n", sig_blob); + ok(sig_len == props->exp_sig_len, "got sig_len %lu != %lu\n", sig_len, props->exp_sig_len); if (sig_blob && sig_len == props->exp_sig_len) ok(!memcmp(sig_blob, props->exp_sig_blob, sig_len), "got unexpected sig_blob\n"); ok(!value_len, "got value_len %lu\n", value_len); @@ -1312,11 +1312,11 @@ static void test_IMetaDataImport(void) if (props->has_get) test_prop_method_token(md_import, typedef1, props->exp_name, PROP_METHOD_GET, get_method); else - todo_wine ok(get_method == mdMethodDefNil, "got get_method %#x\n", get_method); + ok(get_method == mdMethodDefNil, "got get_method %#x\n", get_method); if (props->has_set) test_prop_method_token(md_import, typedef1, props->exp_name, PROP_METHOD_SET, set_method); else - todo_wine ok(set_method == mdMethodDefNil, "got set_method %#x\n", set_method); + ok(set_method == mdMethodDefNil, "got set_method %#x\n", set_method); winetest_pop_context(); } IMetaDataImport_Release(md_import); diff --git a/include/corhdr.h b/include/corhdr.h index afa2d1e14e0..d18ed677167 100644 --- a/include/corhdr.h +++ b/include/corhdr.h @@ -303,4 +303,14 @@ typedef enum CorFieldAttr #define COR_ENUM_FIELD_NAME ("value__") #define COR_ENUM_FIELD_NAME_W (L"value__")
+typedef enum CorMethodSemanticsAttr +{ + msSetter = 0x01, + msGetter = 0x02, + msOther = 0x04, + msAddOn = 0x08, + msRemoveOn = 0x10, + msFire = 0x20, +} CorMethodSemanticsAttr; + #endif /* __WINE_CORHDR_H */
From: Vibhav Pant vibhavp@gmail.com
--- dlls/rometadata/assembly.c | 1 + dlls/rometadata/mdtables.c | 333 +++++++++++++++++++++-------- dlls/rometadata/tests/rometadata.c | 25 ++- include/corhdr.h | 12 +- 4 files changed, 270 insertions(+), 101 deletions(-)
diff --git a/dlls/rometadata/assembly.c b/dlls/rometadata/assembly.c index bcdd4c6890e..ebe60376f9c 100644 --- a/dlls/rometadata/assembly.c +++ b/dlls/rometadata/assembly.c @@ -141,6 +141,7 @@ DEFINE_CODED_IDX(HasCustomAttribute, TABLE_MEMBERREF, TABLE_MODULE, TABLE_PROPERTY, + TABLE_DECLSECURITY, TABLE_EVENT, TABLE_STANDALONESIG, TABLE_MODULEREF, diff --git a/dlls/rometadata/mdtables.c b/dlls/rometadata/mdtables.c index 773400457de..5a357350469 100644 --- a/dlls/rometadata/mdtables.c +++ b/dlls/rometadata/mdtables.c @@ -477,34 +477,123 @@ static HRESULT WINAPI import_EnumTypeRefs(IMetaDataImport *iface, HCORENUM *henu return E_NOTIMPL; }
-static void type_split_name(const char *nameA, const char **namespace, size_t *ns_len, const char **type_name) +struct clr_type_path { + const char *namespace; + size_t ns_len; + const char *type_name; +}; + +static struct clr_type_path type_split_name(const char *nameA) +{ + struct clr_type_path path; const char *sep;
if ((sep = strrchr(nameA, '.'))) { - *namespace = nameA; - *ns_len = sep - nameA; - *type_name = &sep[1]; + path.namespace = nameA; + path.ns_len = sep - nameA; + path.type_name = &sep[1]; } else { - *namespace = NULL; - *ns_len = 0; - *type_name = nameA; + path.namespace = ""; + path.ns_len = 0; + path.type_name = nameA; + } + + return path; +} + +static BOOL clr_type_path_equals(const struct clr_type_path *path1, const struct clr_type_path *path2) +{ + assert(!!path1->ns_len == !!path1->namespace[0] && !!path2->ns_len == !!path2->namespace[0]); + + return path1->ns_len == path2->ns_len && !strncmp(path1->namespace, path2->namespace, path1->ns_len) && + !strcmp(path1->type_name, path2->type_name); +} + +static BOOL clr_type_path_join(const struct clr_type_path *path, WCHAR *out, ULONG out_len, ULONG *needed) +{ + ULONG full_name_len; + char *full_name; + + assert(!!path->ns_len == !!path->namespace[0]); + + full_name_len = path->ns_len + strlen(path->type_name) + 1; + if (path->ns_len) + full_name_len++; /* For the dot seaparator */ + if (!(full_name = malloc(full_name_len))) return FALSE; + if (path->ns_len && path->type_name[0]) + snprintf(full_name, full_name_len, "%s.%s", path->namespace, path->type_name); + else + strcpy(full_name, path->ns_len ? path->namespace : path->type_name); + *needed = MultiByteToWideChar(CP_ACP, 0, full_name, -1, NULL, 0); + if (out && out_len) + { + ULONG n = MultiByteToWideChar(CP_ACP, 0, full_name, min(full_name_len, out_len) - 1, out, out_len - 1); + out[n] = L'\0'; } + free(full_name); + return TRUE; +} + +static HRESULT table_get_column_as_string(IMetaDataTables *iface, enum table table, ULONG col, ULONG row, + const char **str) +{ + ULONG str_idx; + HRESULT hr; + + TRACE("(%p, %#x, %lu, %lu, %p)\n", iface, table, col, row, str); + + if (FAILED((hr = IMetaDataTables_GetColumn(iface, table, col, row, &str_idx)))) return hr; + return IMetaDataTables_GetString(iface, str_idx, str); +} + +static HRESULT table_get_column_as_blob(IMetaDataTables *iface, enum table table, ULONG col, ULONG row, ULONG *blob_len, + const BYTE **blob) +{ + ULONG blob_idx; + HRESULT hr; + + TRACE("(%p, %#x, %lu, %lu, %p, %p)\n", iface, table, col, row, blob_len, blob); + + if (FAILED((hr = IMetaDataTables_GetColumn(iface, table, col, row, &blob_idx)))) return hr; + return IMetaDataTables_GetBlob(iface, blob_idx, blob_len, blob); +} + +static HRESULT token_typedeforref_get_type_path(IMetaDataTables *iface, mdToken token, struct clr_type_path *type_path) +{ + const ULONG row = RidFromToken(token); + const ULONG type = TypeFromToken(token); + const enum table table = type >> 24; + const char *name, *namespace; + HRESULT hr; + + TRACE("(%p, %s, %p)\n", iface, debugstr_mdToken(token), type_path); + + assert(type == mdtTypeDef || type == mdtTypeRef); + + /* The TypeDef and TypeRef use the same column indices for the name and namespace. */ + if (FAILED((hr = table_get_column_as_string(iface, table, 1, row, &name)))) return hr; + if (FAILED((hr = table_get_column_as_string(iface, table, 2, row, &namespace)))) return hr; + + type_path->namespace = namespace; + type_path->ns_len = strlen(namespace); + type_path->type_name = name; + return S_OK; }
static HRESULT WINAPI import_FindTypeDefByName(IMetaDataImport *iface, const WCHAR *name, mdToken enclosing_class, mdTypeDef *type_def) { struct metadata_tables *impl = impl_from_IMetaDataImport(iface); - const char *namespace, *type_name; + struct clr_type_path type_path; HCORENUM henum = NULL; mdTypeDef cur_typedef; - size_t len, ns_len; BOOL found = FALSE; char *nameA; + size_t len; HRESULT hr;
TRACE("(%p, %s, %s, %p)\n", iface, debugstr_w(name), debugstr_mdToken(enclosing_class), type_def); @@ -522,7 +611,7 @@ static HRESULT WINAPI import_FindTypeDefByName(IMetaDataImport *iface, const WCH len = WideCharToMultiByte(CP_ACP, 0, name, -1, NULL, 0, NULL, NULL); if (!(nameA = malloc(len))) return E_OUTOFMEMORY; WideCharToMultiByte(CP_ACP, 0, name, -1, nameA, len, NULL, NULL); - type_split_name(nameA, &namespace, &ns_len, &type_name); + type_path = type_split_name(nameA);
hr = IMetaDataImport_EnumTypeDefs(&impl->IMetaDataImport_iface, &henum, NULL, 0, NULL); if (FAILED(hr)) @@ -533,17 +622,11 @@ static HRESULT WINAPI import_FindTypeDefByName(IMetaDataImport *iface, const WCH hr = IMetaDataImport_EnumTypeDefs(&impl->IMetaDataImport_iface, &henum, &cur_typedef, 1, NULL); while (hr == S_OK) { - ULONG row = RidFromToken(cur_typedef), idx; - const char *cur_type_name, *cur_ns; - - if (FAILED((hr = IMetaDataTables_GetColumn(&impl->IMetaDataTables_iface, TABLE_TYPEDEF, 1, row, &idx)))) break; - if (FAILED((hr = IMetaDataTables_GetString(&impl->IMetaDataTables_iface, idx, &cur_type_name)))) break; - if (FAILED((hr = IMetaDataTables_GetColumn(&impl->IMetaDataTables_iface, TABLE_TYPEDEF, 2, row, &idx)))) break; - if (FAILED((hr = IMetaDataTables_GetString(&impl->IMetaDataTables_iface, idx, &cur_ns)))) break; + struct clr_type_path cur_type_path;
- if (!!namespace == !!cur_ns[0] && - (!namespace || !strncmp(namespace, cur_ns, ns_len)) && - !strcmp(type_name, cur_type_name)) + if (FAILED((hr = token_typedeforref_get_type_path(&impl->IMetaDataTables_iface, cur_typedef, &cur_type_path)))) + break; + if (clr_type_path_equals(&type_path, &cur_type_path)) { found = TRUE; *type_def = cur_typedef; @@ -573,30 +656,6 @@ static HRESULT WINAPI import_GetModuleFromScope(IMetaDataImport *iface, mdModule return E_NOTIMPL; }
-static BOOL type_full_name(WCHAR *out, ULONG out_len, ULONG *needed, const char *namespace, const char *name) -{ - ULONG full_name_len; - char *full_name; - - if (namespace[0] && name[0]) - full_name_len = strlen(namespace) + 1 + strlen(name) + 1; - else - full_name_len = strlen(namespace[0] ? namespace : name) + 1; - if (!(full_name = malloc(full_name_len))) return FALSE; - if (namespace[0] && name[0]) - snprintf(full_name, full_name_len, "%s.%s", namespace, name); - else - strcpy(full_name, namespace[0] ? namespace : name); - *needed = MultiByteToWideChar(CP_ACP, 0, full_name, -1, NULL, 0); - if (out && out_len) - { - ULONG n = MultiByteToWideChar(CP_ACP, 0, full_name, min(full_name_len, out_len) - 1, out, out_len - 1); - out[n] = L'\0'; - } - free(full_name); - return TRUE; -} - static HRESULT WINAPI import_GetTypeDefProps(IMetaDataImport *iface, mdTypeDef type_def, WCHAR *name, ULONG len, ULONG *written, ULONG *ret_flags, mdToken *base) { @@ -612,23 +671,16 @@ static HRESULT WINAPI import_GetTypeDefProps(IMetaDataImport *iface, mdTypeDef t if (type_def != mdTypeDefNil) { const ULONG row = RidFromToken(type_def); - const char *namespace, *nameA; - ULONG name_idx, ns_idx; + struct clr_type_path type_path; HRESULT hr;
if (FAILED((hr = IMetaDataTables_GetColumn(&impl->IMetaDataTables_iface, TABLE_TYPEDEF, 0, row, &flags)))) return hr; - if (FAILED((hr = IMetaDataTables_GetColumn(&impl->IMetaDataTables_iface, TABLE_TYPEDEF, 1, row, &name_idx)))) - return hr; - if (FAILED((hr = IMetaDataTables_GetColumn(&impl->IMetaDataTables_iface, TABLE_TYPEDEF, 2, row, &ns_idx)))) - return hr; + hr = token_typedeforref_get_type_path(&impl->IMetaDataTables_iface, type_def, &type_path); + if (FAILED(hr)) return hr; if (FAILED((hr = IMetaDataTables_GetColumn(&impl->IMetaDataTables_iface, TABLE_TYPEDEF, 3, row, &extends)))) return hr; - if (FAILED(hr = IMetaDataTables_GetString(&impl->IMetaDataTables_iface, name_idx, &nameA))) - return hr; - if (FAILED(hr = IMetaDataTables_GetString(&impl->IMetaDataTables_iface, ns_idx, &namespace))) - return hr; - if (!type_full_name(name, len, &needed, namespace, nameA)) return E_OUTOFMEMORY; + if (!clr_type_path_join(&type_path, name, len, &needed)) return E_OUTOFMEMORY; /* Native replaces tokens with rid 0 with mdTypeRefNil. */ if (IsNilToken(extends)) extends = mdTypeRefNil; @@ -901,7 +953,6 @@ static HRESULT WINAPI import_GetMethodProps(IMetaDataImport *iface, mdMethodDef if (method_def != mdMethodDefNil) { const ULONG row = RidFromToken(method_def); - ULONG name_idx, sig_idx; const char *nameA = NULL; HRESULT hr;
@@ -911,15 +962,11 @@ static HRESULT WINAPI import_GetMethodProps(IMetaDataImport *iface, mdMethodDef return hr; if (FAILED((hr = IMetaDataTables_GetColumn(&impl->IMetaDataTables_iface, TABLE_METHODDEF, 2, row, &attrs)))) return hr; - if (FAILED((hr = IMetaDataTables_GetColumn(&impl->IMetaDataTables_iface, TABLE_METHODDEF, 3, row, &name_idx)))) - return hr; - if (FAILED((hr = IMetaDataTables_GetColumn(&impl->IMetaDataTables_iface, TABLE_METHODDEF, 4, row, &sig_idx)))) - return hr; + hr = table_get_column_as_string(&impl->IMetaDataTables_iface, TABLE_METHODDEF, 3, row, &nameA); + if (FAILED((hr))) return hr; + hr = table_get_column_as_blob(&impl->IMetaDataTables_iface, TABLE_METHODDEF, 4, row, &sig_len, &sig_blob); + if (FAILED((hr))) return hr;
- if (FAILED(hr = IMetaDataTables_GetString(&impl->IMetaDataTables_iface, name_idx, &nameA))) - return hr; - if (FAILED((hr = IMetaDataTables_GetBlob(&impl->IMetaDataTables_iface, sig_idx, &sig_len, &sig_blob)))) - return hr; if (FAILED((hr = methoddef_get_parent_typedef(iface, method_def, &parent)))) return hr;
@@ -1194,15 +1241,11 @@ static HRESULT token_get_constant_value(IMetaDataImport *iface, mdToken token, U break; if (parent == token) { - ULONG blob_idx; - hr = IMetaDataTables_GetColumn(&impl->IMetaDataTables_iface, TABLE_CONSTANT, 0, row, value_type); if (FAILED(hr)) break; - hr = IMetaDataTables_GetColumn(&impl->IMetaDataTables_iface, TABLE_CONSTANT, 2, row, &blob_idx); + hr = table_get_column_as_blob(&impl->IMetaDataTables_iface, TABLE_CONSTANT, 2, row, &len, value); if (FAILED(hr)) break;
- if (FAILED((hr = IMetaDataTables_GetBlob(&impl->IMetaDataTables_iface, blob_idx, &len, value)))) - break; if (*value_type == ELEMENT_TYPE_STRING) *value_len = len / sizeof(WCHAR); break; @@ -1236,21 +1279,16 @@ static HRESULT WINAPI import_GetFieldProps(IMetaDataImport *iface, mdFieldDef fi if (!IsNilToken(fielddef)) { const ULONG row = RidFromToken(fielddef); - ULONG name_idx, sig_idx; const char *nameA; HRESULT hr;
if (FAILED((hr = IMetaDataTables_GetColumn(&impl->IMetaDataTables_iface, TABLE_FIELD, 0, row, &attrs)))) return hr; - if (FAILED((hr = IMetaDataTables_GetColumn(&impl->IMetaDataTables_iface, TABLE_FIELD, 1, row, &name_idx)))) - return hr; - if (FAILED((hr = IMetaDataTables_GetColumn(&impl->IMetaDataTables_iface, TABLE_FIELD, 2, row, &sig_idx)))) - return hr; + hr = table_get_column_as_string(&impl->IMetaDataTables_iface, TABLE_FIELD, 1, row, &nameA); + if (FAILED((hr))) return hr; + hr = table_get_column_as_blob(&impl->IMetaDataTables_iface, TABLE_FIELD, 2, row, &sig_len, &sig_blob); + if (FAILED((hr))) return hr;
- if (FAILED((hr = IMetaDataTables_GetString(&impl->IMetaDataTables_iface, name_idx, &nameA)))) - return hr; - if (FAILED((hr = IMetaDataTables_GetBlob(&impl->IMetaDataTables_iface, sig_idx, &sig_len, &sig_blob)))) - return hr; if (FAILED((hr = fielddef_get_parent_typedef(iface, fielddef, &parent)))) return hr; if (FAILED((hr = token_get_constant_value(iface, fielddef, &val_type, &val_blob, &val_len)))) @@ -1311,21 +1349,16 @@ static HRESULT WINAPI import_GetPropertyProps(IMetaDataImport *iface, mdProperty name[0] = L'\0'; if (!IsNilToken(prop)) { - ULONG name_idx, sig_idx, num_methodsemantics, semantic_row; + ULONG num_methodsemantics, semantic_row; const ULONG row = RidFromToken(prop); const char *nameA;
if (FAILED((hr = IMetaDataTables_GetColumn(&impl->IMetaDataTables_iface, TABLE_PROPERTY, 0, row, &flags)))) return hr; - if (FAILED((hr = IMetaDataTables_GetColumn(&impl->IMetaDataTables_iface, TABLE_PROPERTY, 1, row, &name_idx)))) - return hr; - if (FAILED((hr = IMetaDataTables_GetColumn(&impl->IMetaDataTables_iface, TABLE_PROPERTY, 2, row, &sig_idx)))) - return hr; - - if (FAILED((hr = IMetaDataTables_GetString(&impl->IMetaDataTables_iface, name_idx, &nameA)))) - return hr; - if (FAILED((hr = IMetaDataTables_GetBlob(&impl->IMetaDataTables_iface, sig_idx, &sig_len, &sig_blob)))) + if (FAILED((hr = table_get_column_as_string(&impl->IMetaDataTables_iface, TABLE_PROPERTY, 1, row, &nameA)))) return hr; + hr = table_get_column_as_blob(&impl->IMetaDataTables_iface, TABLE_PROPERTY , 2, row, &sig_len, &sig_blob); + if (FAILED(hr)) return hr; if (FAILED((hr = property_get_parent_typedef(&impl->IMetaDataImport_iface, prop, &parent)))) return hr; if (FAILED((hr = token_get_constant_value(&impl->IMetaDataImport_iface, prop, &val_type, &val_blob, &val_len)))) @@ -1397,11 +1430,131 @@ static HRESULT WINAPI import_GetParamProps(IMetaDataImport *iface, mdParamDef pa return E_NOTIMPL; }
+static HRESULT token_memberrefparent_get_type_path(IMetaDataImport *iface, mdToken token, struct clr_type_path *path) +{ + struct metadata_tables *impl = impl_from_IMetaDataImport(iface); + const CorTokenType type = TypeFromToken(token); + + switch (type) + { + case mdtTypeDef: + case mdtTypeRef: + return token_typedeforref_get_type_path(&impl->IMetaDataTables_iface, token, path); + case mdtMethodDef: + { + mdTypeDef parent; + HRESULT hr; + + if (FAILED((hr = methoddef_get_parent_typedef(&impl->IMetaDataImport_iface, token, &parent)))) + return hr; + return token_memberrefparent_get_type_path(&impl->IMetaDataImport_iface, parent, path); + } + case mdtModuleRef: + case mdtTypeSpec: + FIXME("Unsupported token: %s\n", debugstr_mdToken(token)); + return S_FALSE; + default: + ERR("Unexpected MemberRefParent token: %s\n", debugstr_mdToken(token)); + return S_FALSE; + } +} + +/* The token should should be of type HasCustomAttribute, i.e a MethodDef/MemberRef row pointing to the custom attribute + * constructor. */ +static HRESULT token_hascustomattribute_get_name(IMetaDataImport *iface, mdToken token, const char **ctor_name, + struct clr_type_path *attr_type_path) +{ + struct metadata_tables *impl = impl_from_IMetaDataImport(iface); + const CorTokenType type = TypeFromToken(token); + const ULONG row = RidFromToken(token); + HRESULT hr; + + TRACE("(%p, %s, %p, %p)\n", iface, debugstr_mdToken(token), ctor_name, attr_type_path); + + assert(type == mdtMemberRef || type == mdtMethodDef); + + if (type == mdtMemberRef) + { + ULONG parent_class; + + hr = IMetaDataTables_GetColumn(&impl->IMetaDataTables_iface, TABLE_MEMBERREF, 0, row, &parent_class); + if (FAILED(hr)) return hr; + if (FAILED((hr = token_memberrefparent_get_type_path(iface, parent_class, attr_type_path)))) return hr; + hr = table_get_column_as_string(&impl->IMetaDataTables_iface, TABLE_MEMBERREF, 1, row, ctor_name); + } + else /* mdtMethodDef */ + { + hr = table_get_column_as_string(&impl->IMetaDataTables_iface, TABLE_METHODDEF, 3, row, ctor_name); + if (FAILED(hr)) return hr; + hr = token_memberrefparent_get_type_path(iface, token, attr_type_path); + } + + return hr; +} + static HRESULT WINAPI import_GetCustomAttributeByName(IMetaDataImport *iface, mdToken obj, const WCHAR *name, const BYTE **data, ULONG *len) { - FIXME("(%p, %#x, %s, %p, %p): stub!\n", iface, obj, debugstr_w(name), data, len); - return E_NOTIMPL; + struct metadata_tables *impl = impl_from_IMetaDataImport(iface); + struct clr_type_path attr_type_path; + ULONG row, num_rows, data_len = 0; + const BYTE *data_blob = NULL; + BOOL found = FALSE; + size_t lenA; + char *nameA; + HRESULT hr; + + TRACE("(%p, %s, %s, %p, %p)\n", iface, debugstr_mdToken(obj), debugstr_w(name), data, len); + + /* From Partition II.22.10, "CustomAttribute": "Parent can be an index into any metadata table, except the + * CustomAttribute table itself." */ + if (!name || IsNilToken(obj) || TypeFromToken(obj) == mdtCustomAttribute) return S_FALSE; + + lenA = WideCharToMultiByte(0, 0, name, -1, NULL, 0, NULL, NULL); + if (!(nameA = calloc(lenA, sizeof(*nameA)))) return E_OUTOFMEMORY; + WideCharToMultiByte(0, 0, name, -1, nameA, lenA, NULL, NULL); + attr_type_path = type_split_name(nameA); + + if (FAILED((hr = table_get_num_rows(&impl->IMetaDataTables_iface, TABLE_CUSTOMATTRIBUTE, &num_rows)))) goto done; + for (row = 1; row <= num_rows; row++) + { + ULONG parent = 0, type; + + hr = IMetaDataTables_GetColumn(&impl->IMetaDataTables_iface, TABLE_CUSTOMATTRIBUTE, 0, row, &parent); + if (FAILED(hr)) goto done; + if (parent == obj) + { + struct clr_type_path cur_type_path; + const char *cur_ctor_name; + + hr = IMetaDataTables_GetColumn(&impl->IMetaDataTables_iface, TABLE_CUSTOMATTRIBUTE, 1, row, &type); + if (FAILED(hr)) goto done; + hr = token_hascustomattribute_get_name(&impl->IMetaDataImport_iface, type, &cur_ctor_name, &cur_type_path); + if (FAILED(hr)) goto done; + + if (strcmp(COR_CTOR_METHOD_NAME, cur_ctor_name)) + { + ERR("Unexpected constructor name for CustomAttribute %#lx: %s\n", row, debugstr_a(cur_ctor_name)); + continue; + } + if (!clr_type_path_equals(&attr_type_path, &cur_type_path)) continue; + hr = table_get_column_as_blob(&impl->IMetaDataTables_iface, TABLE_CUSTOMATTRIBUTE, 2, row, &data_len, + &data_blob); + found = TRUE; + break; + } + } + if (found) + { + if (data) *data = data_blob; + if (len) *len = data_len; + } + +done: + free(nameA); + if (FAILED(hr)) + return hr; + return found ? S_OK : S_FALSE; }
static BOOL WINAPI import_IsValidToken(IMetaDataImport *iface, mdToken token) @@ -1534,4 +1687,4 @@ HRESULT IMetaDataTables_create_from_data(const BYTE *data, ULONG data_size, IMet impl->ref = 1; *iface = &impl->IMetaDataTables_iface; return S_OK; -} \ No newline at end of file +} diff --git a/dlls/rometadata/tests/rometadata.c b/dlls/rometadata/tests/rometadata.c index 9f81e1e29ba..1db4d18a9b8 100644 --- a/dlls/rometadata/tests/rometadata.c +++ b/dlls/rometadata/tests/rometadata.c @@ -1017,6 +1017,7 @@ static void test_IMetaDataImport(void) mdFieldDef *fielddef_tokens; mdProperty *property_tokens; IMetaDataImport *md_import; + IMetaDataTables *md_tables; const BYTE *data = NULL; HCORENUM henum = 0; const GUID *guid; @@ -1029,8 +1030,14 @@ static void test_IMetaDataImport(void)
hr = IMetaDataDispenser_OpenScope(dispenser, filename, 0, &IID_IMetaDataImport, (IUnknown **)&md_import); ok(hr == S_OK, "got hr %#lx\n", hr); + hr = IMetaDataDispenser_OpenScope(dispenser, filename, 0, &IID_IMetaDataTables, (IUnknown **)&md_tables); + ok(hr == S_OK, "got hr %#lx\n", hr); IMetaDataDispenser_Release(dispenser);
+ hr = IMetaDataTables_GetColumn(md_tables, TABLE_CUSTOMATTRIBUTE, 0, 1, &val); + ok( hr == S_OK, "got hr %#lx\n", hr); + trace("val: %#lx\n", val); + buf_count = 0xdeadbeef; henum = NULL; hr = IMetaDataImport_EnumTypeDefs(md_import, &henum, NULL, 0, &buf_count); @@ -1098,8 +1105,8 @@ static void test_IMetaDataImport(void) data_len = 0; data = NULL; hr = IMetaDataImport_GetCustomAttributeByName(md_import, typedef_tokens[i], contract_attribute_name, &data, &data_len); - todo_wine ok(hr == S_OK, "got hr %#lx\n", hr); - todo_wine test_contract_value(data, data_len, info->exp_contract_name, info->exp_contract_version); + ok(hr == S_OK, "got hr %#lx\n", hr); + test_contract_value(data, data_len, info->exp_contract_name, info->exp_contract_version); }
winetest_pop_context(); @@ -1249,23 +1256,23 @@ static void test_IMetaDataImport(void) ok(hr == S_OK, "got hr %#lx\n", hr); test_token(md_import, typedef1, mdtTypeDef, FALSE); hr = IMetaDataImport_GetCustomAttributeByName(md_import, typedef1, guid_attribute_name, &data, &buf_len); - todo_wine ok(hr == S_OK, "got hr %#lx\n", hr); - todo_wine ok(!!data, "got data %p\n", data); - todo_wine ok(buf_len == sizeof(GUID) + 4, "got buf_len %lu\n", buf_len); + ok(hr == S_OK, "got hr %#lx\n", hr); + ok(!!data, "got data %p\n", data); + ok(buf_len == sizeof(GUID) + 4, "got buf_len %lu\n", buf_len); if (data && buf_len == sizeof(GUID) + 4) { guid = (GUID *)&data[2]; ok(IsEqualGUID(guid, &IID_ITest2), "got guid %s\n", debugstr_guid(guid)); } hr = IMetaDataImport_GetCustomAttributeByName(md_import, typedef1, guid_attribute_name, NULL, NULL); - todo_wine ok(hr == S_OK, "got hr %#lx\n", hr); + ok(hr == S_OK, "got hr %#lx\n", hr); hr = IMetaDataImport_GetCustomAttributeByName(md_import, typedef1, NULL, &data, &buf_len); - todo_wine ok(hr == S_FALSE, "got hr %#lx\n", hr); + ok(hr == S_FALSE, "got hr %#lx\n", hr); hr = IMetaDataImport_GetCustomAttributeByName(md_import, mdTypeDefNil, L"foo", &data, &buf_len); - todo_wine ok(hr == S_FALSE, "got hr %#lx\n", hr); + ok(hr == S_FALSE, "got hr %#lx\n", hr); hr = IMetaDataImport_GetCustomAttributeByName(md_import, TokenFromRid(1, mdtCustomAttribute), L"foo", &data, &buf_len); - todo_wine ok(hr == S_FALSE, "got hr %#lx\n", hr); + ok(hr == S_FALSE, "got hr %#lx\n", hr);
typedef1 = buf_len = 0; hr = IMetaDataImport_FindTypeDefByName(md_import, L"Wine.Test.ITest3", 0, &typedef1); diff --git a/include/corhdr.h b/include/corhdr.h index d18ed677167..769d19e6786 100644 --- a/include/corhdr.h +++ b/include/corhdr.h @@ -300,8 +300,16 @@ typedef enum CorFieldAttr fdReservedMask = 0x9500 } CorFieldAttr;
-#define COR_ENUM_FIELD_NAME ("value__") -#define COR_ENUM_FIELD_NAME_W (L"value__") +#define COR_ENUM_FIELD_NAME ("value__") +#define COR_CTOR_METHOD_NAME (".ctor") + +#if defined(_MSC_VER) || defined(__MINGW32__) +#define COR_ENUM_FIELD_NAME_W (L"value__") +#define COR_CTOR_METHOD_NAME_W (L".ctor") +#else +static const WCHAR COR_ENUM_FIELD_NAME_W[] = {'v','a','l','u','e','_','_',0}; +static const WCHAR COR_CTOR_METHOD_NAME_W[] = {'.','c','t','o','r',0}; +#endif
typedef enum CorMethodSemanticsAttr {