From: Vibhav Pant vibhavp@gmail.com
--- dlls/rometadata/assembly.c | 98 ++++++++++++++++++++++++++++-- dlls/rometadata/mdtables.c | 32 ++++++++-- dlls/rometadata/rometadatapriv.h | 10 +++ dlls/rometadata/tests/rometadata.c | 27 -------- 4 files changed, 130 insertions(+), 37 deletions(-)
diff --git a/dlls/rometadata/assembly.c b/dlls/rometadata/assembly.c index b4298ec3bcd..2703d62fbc7 100644 --- a/dlls/rometadata/assembly.c +++ b/dlls/rometadata/assembly.c @@ -18,6 +18,7 @@ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA */
+#define _DEFINE_META_DATA_META_CONSTANTS #include "rometadatapriv.h"
#include <assert.h> @@ -119,8 +120,26 @@ enum table TABLE_MAX = 0x2d };
+enum coded_idx_type +{ + CT_TypeDefOrRef = 64, + CT_HasConstant = 65, + CT_HasCustomAttribute = 66, + CT_HasFieldMarshal = 67, + CT_HasDeclSecurity = 68, + CT_MemberRefParent = 69, + CT_HasSemantics = 70, + CT_MethodDefOrRef = 71, + CT_MemberForwarded = 72, + CT_Implementation = 73, + CT_CustomAttributeType = 74, + CT_ResolutionScope = 75, + CT_TypeOrMethodDef = 76 +}; + struct table_coded_idx { + enum coded_idx_type type; UINT8 len; const enum table *tables; }; @@ -139,7 +158,11 @@ enum table_column_type
union table_column_size { - UINT8 basic; + struct { + UINT8 type; + UINT8 size; + UINT8 size_padded; + } basic; enum heap_type heap; enum table table; struct table_coded_idx coded; @@ -205,12 +228,13 @@ struct table_schema static const struct table_column name##_columns[] = {__VA_ARGS__}; \ static const struct table_schema name##_schema = { ARRAY_SIZE(name##_columns), name##_columns, #name }
-#define BASIC(n, t) { COLUMN_BASIC, { .basic = sizeof(t) }, n } +#define BASIC_PADDED(n, t, p) { COLUMN_BASIC, { .basic = {i##t, sizeof(t), sizeof(p) } }, n } +#define BASIC(n, t) BASIC_PADDED(n, t, t) #define HEAP(n, h) { COLUMN_HEAP_IDX, { .heap = (HEAP_##h) }, n } #define TABLE(n, t) { COLUMN_TABLE_IDX, { .table = TABLE_##t }, n } #define TABLE_PRIMARY(n, t) { COLUMN_TABLE_IDX, { .table= TABLE_##t }, n, TRUE } -#define CODED(n, c) { COLUMN_CODED_IDX, { .coded = { ARRAY_SIZE(c##_tables), c##_tables } }, n } -#define CODED_PRIMARY(n, c) { COLUMN_CODED_IDX, { .coded = { ARRAY_SIZE(c##_tables), c##_tables } }, n, TRUE } +#define CODED(n, c) { COLUMN_CODED_IDX, { .coded = { CT_##c, ARRAY_SIZE(c##_tables), c##_tables } }, n } +#define CODED_PRIMARY(n, c) { COLUMN_CODED_IDX, { .coded = { CT_##c, ARRAY_SIZE(c##_tables), c##_tables } }, n, TRUE }
/* Partition II.22.2, "Assembly" */ DEFINE_TABLE_SCHEMA(Assembly, @@ -262,7 +286,7 @@ DEFINE_TABLE_SCHEMA(ClassLayout, TABLE_PRIMARY("Parent", TYPEDEF));
/* Partition II.22.9, "Constant" */ -DEFINE_TABLE_SCHEMA(Constant, BASIC("Type", USHORT), CODED_PRIMARY("Parent", HasConstant), HEAP("Value", BLOB)); +DEFINE_TABLE_SCHEMA(Constant, BASIC_PADDED("Type", BYTE, USHORT), CODED_PRIMARY("Parent", HasConstant), HEAP("Value", BLOB));
/* Partition II.2.10, "CustomAttribute" */ DEFINE_TABLE_SCHEMA(CustomAttribute, @@ -563,6 +587,23 @@ static ULONG assembly_get_coded_index_size(const assembly_t *assembly, const str return max_row_idx < (1 << (16 - tag_bits)) ? 2 : 4; }
+#define TokenFromTable(idx) ((idx) << 24) + +/* Encode a coded index value as a token. The table and column *must* point to a coded index type. */ +ULONG metadata_coded_value_as_token(ULONG table_idx, ULONG column_idx, ULONG value) +{ + const struct table_column *column; + ULONG table_mask, tag_bits; + + assert(table_idx < TABLE_MAX && column_idx < table_schemas[table_idx]->columns_len); + column = &table_schemas[table_idx]->columns[column_idx]; + assert(column->type == COLUMN_CODED_IDX); + + tag_bits = bit_width(column->size.coded.len - 1); + table_mask = ((1UL << tag_bits) - 1); + return TokenFromRid((value & ~table_mask) >> tag_bits, TokenFromTable(column->size.coded.tables[value & table_mask])); +} + static HRESULT assembly_calculate_table_sizes(assembly_t *assembly, enum table table) { const struct table_schema *schema; @@ -583,7 +624,7 @@ static HRESULT assembly_calculate_table_sizes(assembly_t *assembly, enum table t switch (column->type) { case COLUMN_BASIC: - column_size = column->size.basic; + column_size = column->size.basic.size_padded; break; case COLUMN_HEAP_IDX: column_size = assembly_heap_idx_size(assembly, column->size.heap); @@ -828,6 +869,51 @@ HRESULT assembly_get_table(const assembly_t *assembly, ULONG table_idx, struct m return S_OK; }
+HRESULT assembly_get_column(const assembly_t *assembly, ULONG table_idx, ULONG column_idx, struct metadata_column_info *info) +{ + const struct table_schema *schema; + const struct table_column *column; + struct metadata_table_info table; + ULONG i, offset = 0; + HRESULT hr; + + if (FAILED(hr = assembly_get_table(assembly, table_idx, &table))) return hr; + if (column_idx >= table.num_columns) return E_INVALIDARG; + + schema = table_schemas[table_idx]; + column = &schema->columns[column_idx]; + if (column->type == COLUMN_BASIC) + info->size = column->size.basic.size; + else + info->size = table.column_sizes[column_idx]; + switch (column->type) + { + case COLUMN_BASIC: + info->type = column->size.basic.type; + break; + case COLUMN_HEAP_IDX: + info->type = iSTRING + column->size.heap; + break; + case COLUMN_TABLE_IDX: + info->type = column->size.table; + break; + case COLUMN_CODED_IDX: + info->type = column->size.coded.type; + break; + DEFAULT_UNREACHABLE; + } + for (i = 0; i < column_idx; i++) + { + if (schema->columns[i].type == COLUMN_BASIC) + offset += schema->columns[i].size.basic.size_padded; + else + offset += table.column_sizes[i]; + } + info->offset = offset; + info->name = column->name; + return S_OK; +} + ULONG assembly_get_heap_size(const assembly_t *assembly, enum heap_type heap) { switch (heap) diff --git a/dlls/rometadata/mdtables.c b/dlls/rometadata/mdtables.c index b66fac6487f..b5804bd987b 100644 --- a/dlls/rometadata/mdtables.c +++ b/dlls/rometadata/mdtables.c @@ -151,8 +151,19 @@ static HRESULT WINAPI tables_GetTableInfo(IMetaDataTables *iface, ULONG idx_tbl, static HRESULT WINAPI tables_GetColumnInfo(IMetaDataTables *iface, ULONG idx_tbl, ULONG idx_col, ULONG *offset, ULONG *col_size, ULONG *type, const char **name) { - FIXME("(%p, %lu, %lu, %p, %p, %p, %p) stub!\n", iface, idx_tbl, idx_col, offset, col_size, type, name); - return E_NOTIMPL; + struct metadata_tables *impl = impl_from_IMetaDataTables(iface); + struct metadata_column_info column; + HRESULT hr; + + TRACE("(%p, %lu, %lu, %p, %p, %p, %p)\n", iface, idx_tbl, idx_col, offset, col_size, type, name); + + if (FAILED(hr = assembly_get_column(impl->assembly, idx_tbl, idx_col, &column))) return hr; + + *offset = column.offset; + *col_size = column.size; + *type = column.type; + *name = column.name; + return S_OK; }
static HRESULT WINAPI tables_GetCodedTokenInfo(IMetaDataTables *iface, ULONG type, ULONG *tokens_len, @@ -181,8 +192,21 @@ static HRESULT WINAPI tables_GetRow(IMetaDataTables *iface, ULONG idx_tbl, ULONG
static HRESULT WINAPI tables_GetColumn(IMetaDataTables *iface, ULONG idx_tbl, ULONG idx_col, ULONG idx_row, ULONG *val) { - FIXME("(%p, %lu, %lu, %lu, %p): stub!\n", iface, idx_tbl, idx_col, idx_row, val); - return E_NOTIMPL; + ULONG raw_val = 0, offset, size, type; + const BYTE *row = NULL; + const char *name; + HRESULT hr; + + TRACE("(%p, %lu, %lu, %lu, %p)\n", iface, idx_tbl, idx_col, idx_row, val); + + if (FAILED(hr = IMetaDataTables_GetRow(iface, idx_tbl, idx_row, (BYTE *)&row))) return hr; + if (FAILED(hr = IMetaDataTables_GetColumnInfo(iface, idx_tbl, idx_col, &offset, &size, &type, &name))) return hr; + + memcpy(&raw_val, row + offset, size); + if (type >= 64 && type <= 95) /* IsCodedTokenType */ + raw_val = metadata_coded_value_as_token(idx_tbl, idx_col, raw_val); + *val = raw_val; + return S_OK; }
static HRESULT WINAPI tables_GetString(IMetaDataTables *iface, ULONG idx, const char **str) diff --git a/dlls/rometadata/rometadatapriv.h b/dlls/rometadata/rometadatapriv.h index 3d1d2f21873..3e5ddaf8649 100644 --- a/dlls/rometadata/rometadatapriv.h +++ b/dlls/rometadata/rometadatapriv.h @@ -38,6 +38,14 @@ struct metadata_table_info const BYTE *start; };
+struct metadata_column_info +{ + ULONG offset; + ULONG size; + ULONG type; + const char *name; +}; + enum heap_type { HEAP_STRING = 0, @@ -49,9 +57,11 @@ enum heap_type extern HRESULT assembly_open_from_file(const WCHAR *path, 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); extern ULONG assembly_get_heap_size(const assembly_t *assembly, enum heap_type heap); extern const char *assembly_get_string(const assembly_t *assembly, ULONG idx); extern HRESULT assembly_get_blob(const assembly_t *assembly, ULONG idx, const BYTE **blob, ULONG *size); extern const GUID *assembly_get_guid(const assembly_t *assembly, ULONG idx); +extern ULONG metadata_coded_value_as_token(ULONG table_idx, ULONG column_idx, ULONG value);
#endif /* __WINE_ROMETADATA_PRIVATE__ */ diff --git a/dlls/rometadata/tests/rometadata.c b/dlls/rometadata/tests/rometadata.c index d752770302b..ad62d6759af 100644 --- a/dlls/rometadata/tests/rometadata.c +++ b/dlls/rometadata/tests/rometadata.c @@ -602,13 +602,7 @@ static void test_MetaDataDispenser_OpenScope(void) winetest_push_context("column=%lu", j);
hr = IMetaDataTables_GetColumnInfo(md_tables, i, j, &offset, &col_size, &type, &name); - todo_wine ok(hr == S_OK, "got hr %#lx\n", hr); - if (FAILED(hr)) - { - winetest_pop_context(); - continue; - }
ok(offset == column->exp_offset, "got offset %lu != %lu\n", offset, column->exp_offset); ok(col_size == column->exp_col_size, "got col_size %lu != %lu\n", col_size, column->exp_col_size); @@ -636,15 +630,11 @@ static void test_MetaDataDispenser_OpenScope(void) ok(!!guid, "got guid %p\n", guid);
hr = IMetaDataTables_GetColumn(md_tables, TABLE_MODULE, 1, 1, &val); - todo_wine ok(hr == S_OK, "got hr %#lx\n", hr); - todo_wine ok(val == module->Name, "got val %#lx != %#x\n", val, module->Name);
hr = IMetaDataTables_GetColumn(md_tables, TABLE_MODULE, 2, 1, &val); - todo_wine ok(hr == S_OK, "got hr %#lx\n", hr); - todo_wine ok(val == module->Mvid, "got val %#lx != %#x\n", val, module->Mvid);
/* Read defined types. */ @@ -677,21 +667,15 @@ static void test_MetaDataDispenser_OpenScope(void) }
hr = IMetaDataTables_GetColumn(md_tables, TABLE_TYPEDEF, 0, i + 1, &val); - todo_wine ok(hr == S_OK, "got hr %#lx\n", hr); - todo_wine ok(val == type_def->Flags, "got val %#lx != %#lx\n", val, type_def->Flags);
hr = IMetaDataTables_GetColumn(md_tables, TABLE_TYPEDEF, 1, i + 1, &val); - todo_wine ok(hr == S_OK, "got hr %#lx\n", hr); - todo_wine ok(val == type_def->Name, "got val %#lx != %#x\n", val, type_def->Name);
hr = IMetaDataTables_GetColumn(md_tables, TABLE_TYPEDEF, 2, i + 1, &val); - todo_wine ok(hr == S_OK, "got hr %#lx\n", hr); - todo_wine ok(val == type_def->Namespace, "got val %#lx != %#x\n", val, type_def->Namespace);
winetest_pop_context(); @@ -732,32 +716,23 @@ static void test_MetaDataDispenser_OpenScope(void) }
hr = IMetaDataTables_GetColumn(md_tables, TABLE_TYPEREF, 1, typeref_row, &val); - todo_wine ok(hr == S_OK, "got hr %#lx\n", hr); - todo_wine ok(val == typeref->Name, "got val %#lx != %#x\n", val, typeref->Name);
hr = IMetaDataTables_GetColumn(md_tables, TABLE_TYPEREF, 2, typeref_row, &val); - todo_wine ok(hr == S_OK, "got hr %#lx\n", hr); - todo_wine ok(val == typeref->Namespace, "got val %#lx != %#x\n", val, typeref->Namespace);
hr = IMetaDataTables_GetColumn(md_tables, TABLE_MEMBERREF, 0, i + 1, &val); - todo_wine ok(hr == S_OK, "got hr %#lx\n", hr); rid = RidFromToken(val); type = TypeFromToken(val); - todo_wine ok(rid == typeref_row, "got rid %#lx != %#lx\n", rid, typeref_row); - todo_wine ok(type == mdtTypeRef, "got type %#lx != %#x\n", type, mdtTypeRef); }
hr = IMetaDataTables_GetColumn(md_tables, TABLE_MEMBERREF, 1, i + 1, &val); - todo_wine ok(hr == S_OK, "got hr %#lx\n", hr); - todo_wine ok(val == ref->Name, "got val %#lx != %#x\n", val, ref->Name);
winetest_pop_context(); @@ -790,9 +765,7 @@ static void test_MetaDataDispenser_OpenScope(void) }
hr = IMetaDataTables_GetColumn(md_tables, TABLE_CUSTOMATTRIBUTE, 2, i + 1, &val); - todo_wine ok(hr == S_OK, "got hr %#lx\n", hr); - todo_wine ok(val == attr->Value, "got val %#lx != %#x\n", val, attr->Value);
winetest_pop_context();