Created
March 11, 2021 18:56
-
-
Save gingerBill/64400b872584d9875d8347dbead5ae1e to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package main | |
import "core:os" | |
import "core:fmt" | |
import "core:mem" | |
import "core:slice" | |
import "intrinsics" | |
Image_Dos_Header :: struct { | |
e_signature: u16, | |
e_cblp: u16, | |
e_cp: u16, | |
e_crlc: u16, | |
e_cparhdr: u16, | |
e_minalloc: u16, | |
e_maxalloc: u16, | |
e_ss: u16, | |
e_sp: u16, | |
e_csum: u16, | |
e_ip: u16, | |
e_cs: u16, | |
e_lfarlc: u16, | |
e_ovno: u16, | |
e_res: [4]u16, | |
e_oemid: u16, | |
e_oeminfo: u16, | |
e_res2: [10]u16, | |
e_lfanew: i32, | |
}; | |
Image_File_Header :: struct { | |
Machine: u16, | |
NumberOfSections: u16, | |
TimeDateStamp: u32, | |
PointerToSymbolTable: u32, | |
NumberOfSymbols: u32, | |
SizeOfOptionalHeader: u16, | |
Characteristics: u16, | |
}; | |
Image_Data_Directory :: struct { | |
VirtualAddress: u32, | |
Size: u32, | |
}; | |
Image_Optional_Header32 :: struct { | |
Magic: u16, | |
MajorLinkerVersion: u8, | |
MinorLinkerVersion: u8, | |
SizeOfCode: u32, | |
SizeOfInitializedData: u32, | |
SizeOfUninitializedData: u32, | |
AddressOfEntryPoint: u32, | |
BaseOfCode: u32, | |
BaseOfData: u32, | |
ImageBase: u32, | |
SectionAlignment: u32, | |
FileAlignment: u32, | |
MajorOperatingSystemVersion: u16, | |
MinorOperatingSystemVersion: u16, | |
MajorImageVersion: u16, | |
MinorImageVersion: u16, | |
MajorSubsystemVersion: u16, | |
MinorSubsystemVersion: u16, | |
Win32VersionValue: u32, | |
SizeOfImage: u32, | |
SizeOfHeaders: u32, | |
CheckSum: u32, | |
Subsystem: u16, | |
DllCharacteristics: u16, | |
SizeOfStackReserve: u32, | |
SizeOfStackCommit: u32, | |
SizeOfHeapReserve: u32, | |
SizeOfHeapCommit: u32, | |
LoaderFlags: u32, | |
NumberOfRvaAndSizes: u32, | |
DataDirectory: [16]Image_Data_Directory, | |
}; | |
Image_Nt_Headers32 :: struct { | |
Signature: u32, | |
FileHeader: Image_File_Header, | |
OptionalHeader: Image_Optional_Header32, | |
}; | |
Image_Optional_Header32plus :: struct { | |
Magic: u16, | |
MajorLinkerVersion: u8, | |
MinorLinkerVersion: u8, | |
SizeOfCode: u32, | |
SizeOfInitializedData: u32, | |
SizeOfUninitializedData: u32, | |
AddressOfEntryPoint: u32, | |
BaseOfCode: u32, | |
ImageBase: u64, | |
SectionAlignment: u32, | |
FileAlignment: u32, | |
MajorOperatingSystemVersion: u16, | |
MinorOperatingSystemVersion: u16, | |
MajorImageVersion: u16, | |
MinorImageVersion: u16, | |
MajorSubsystemVersion: u16, | |
MinorSubsystemVersion: u16, | |
Win32VersionValue: u32, | |
SizeOfImage: u32, | |
SizeOfHeaders: u32, | |
CheckSum: u32, | |
Subsystem: u16, | |
DllCharacteristics: u16, | |
SizeOfStackReserve: u64, | |
SizeOfStackCommit: u64, | |
SizeOfHeapReserve: u64, | |
SizeOfHeapCommit: u64, | |
LoaderFlags: u32, | |
NumberOfRvaAndSizes: u32, | |
DataDirectory: [16]Image_Data_Directory, | |
}; | |
Image_Nt_Headers32plus :: struct { | |
Signature: u32, | |
FileHeader: Image_File_Header, | |
OptionalHeader: Image_Optional_Header32plus, | |
}; | |
Image_Section_Header :: struct { | |
Name: [8]u8, // IMAGE_SIZEOF_SHORT_NAME | |
Misc: struct #raw_union { | |
PhysicalAddress: u32, | |
VirtualSize: u32, | |
}, | |
VirtualAddress: u32, | |
SizeOfRawData: u32, | |
PointerToRawData: u32, | |
PointerToRelocations: u32, | |
PointerToLinenumbers: u32, | |
NumberOfRelocations: u16, | |
NumberOfLinenumbers: u16, | |
Characteristics: u32, | |
}; | |
Image_Cor20_Header :: struct { | |
cb: u32, | |
MajorRuntimeVersion: u16, | |
MinorRuntimeVersion: u16, | |
MetaData: Image_Data_Directory, | |
Flags: u32, | |
dummyunionname: struct #raw_union { | |
EntryPointToken: u32, | |
EntryPointRVA: u32, | |
}, | |
Resources: Image_Data_Directory, | |
StrongNameSignature: Image_Data_Directory, | |
CodeManagerTable: Image_Data_Directory, | |
VTableFixups: Image_Data_Directory, | |
ExportAddressTableJumps: Image_Data_Directory, | |
ManagedNativeHeader: Image_Data_Directory, | |
}; | |
section_from_rva :: proc(sections: []Image_Section_Header, rva: u32) -> ^Image_Section_Header { | |
for _, i in sections { | |
s := §ions[i]; | |
if rva >= s.VirtualAddress && rva < s.VirtualAddress + s.Misc.VirtualSize { | |
return s; | |
} | |
} | |
return nil; | |
} | |
offset_from_rva :: proc(section: Image_Section_Header, rva: u32) -> uintptr { | |
return uintptr(rva - section.VirtualAddress + section.PointerToRawData); | |
} | |
to_string :: proc(s: []byte) -> string { | |
n := 0; | |
for c in s { | |
if c == 0 { | |
break; | |
} | |
n += 1; | |
} | |
return string(s[:n]); | |
} | |
uncompress_unsigned :: proc(cursor: ^[]byte) -> u32 { | |
data := uintptr(raw_data(cursor^)); | |
value: u32; | |
length: u32; | |
switch x := (^u8)(data)^; { | |
case x & 0x80 == 0x00: | |
length = 1; | |
value = u32(x); | |
case x & 0xc0 == 0x80: | |
length = 2; | |
value = u32(x & 0x3f) << 8; | |
data += 1; | |
value |= u32((^u8)(data)^); | |
case x & 0xe0 == 0xc0: | |
length = 4; | |
value = u32(x & 0x1f) << 24; | |
data += 1; | |
value |= u32((^u8)(data)^) << 16; | |
data += 1; | |
value |= u32((^u8)(data)^) << 8; | |
data += 1; | |
value |= u32((^u8)(data)^); | |
case: | |
panic("invalid compressed integer in blob"); | |
} | |
cursor^ = cursor[length:]; | |
return value; | |
} | |
uncompress_enum :: proc($T: typeid, cursor: ^[]byte) -> T where intrinsics.type_is_enum(T) { | |
return T(uncompress_unsigned(cursor)); | |
} | |
read_data :: proc($T: typeid, cursor: ^[]byte) -> T { | |
res := (^T)(raw_data(cursor^))^; | |
cursor^ = cursor[size_of(T):]; | |
return res; | |
} | |
read_string :: proc(cursor: ^[]byte) -> string { | |
length := uncompress_unsigned(cursor); | |
s := string(cursor[:length]); | |
cursor^ = cursor[length:]; | |
return s; | |
} | |
Database :: struct { | |
data: []byte, | |
ptr: uintptr, | |
strings: []byte, | |
blobs: []byte, | |
guids: []byte, | |
tables: []byte, | |
module: Table, | |
type_ref: Table, | |
type_def: Table, | |
field: Table, | |
method_def: Table, | |
param: Table, | |
interface_impl: Table, | |
member_ref: Table, | |
constant: Table, | |
custom_attribute: Table, | |
field_marshal: Table, | |
decl_security: Table, | |
class_layout: Table, | |
field_layout: Table, | |
stand_alone_sig: Table, | |
event_map: Table, | |
event: Table, | |
property_map: Table, | |
property: Table, | |
method_semantics: Table, | |
method_impl: Table, | |
module_ref: Table, | |
type_spec: Table, | |
impl_map: Table, | |
field_rva: Table, | |
assembly: Table, | |
assembly_processor: Table, | |
assembly_os: Table, | |
assembly_ref: Table, | |
assembly_ref_processor: Table, | |
assembly_ref_os: Table, | |
file: Table, | |
exported_type: Table, | |
manifest_resource: Table, | |
nested_class: Table, | |
generic_param: Table, | |
method_spec: Table, | |
generic_param_constraint: Table, | |
} | |
Table_Column :: struct { | |
offset, size: u8, | |
} | |
Table :: struct { | |
ptr: uintptr, | |
row_count: u32, | |
row_size: u8, | |
columns: [6]Table_Column, | |
} | |
table_set_columns :: proc(t: ^Table, a: u8, b := u8(0), c := u8(0), d := u8(0), e := u8(0), f := u8(0)) { | |
assert(a != 0); | |
assert(a <= 8); | |
assert(b <= 8); | |
assert(c <= 8); | |
assert(d <= 8); | |
assert(e <= 8); | |
assert(f <= 8); | |
assert(t.row_size == 0); | |
t.row_size = a + b + c + d + e + f; | |
t.columns[0] = {0, a}; | |
if b != 0 { t.columns[1] = {u8(a), b}; } | |
if c != 0 { t.columns[2] = {u8(a+b), c}; } | |
if d != 0 { t.columns[3] = {u8(a+b+c), d}; } | |
if e != 0 { t.columns[4] = {u8(a+b+c+d), e}; } | |
if f != 0 { t.columns[5] = {u8(a+b+c+d+e), f}; } | |
} | |
table_index_size :: proc(t: Table) -> u8 { | |
return 2 if t.row_count < 1<<16 else 4; | |
} | |
table_get_value :: proc(t: ^Table, $T: typeid, row, column: u32) -> T { | |
data_size := t.columns[column].size; | |
assert(data_size == 1 || data_size == 2 || data_size == 4 || data_size == 8); | |
fmt.assertf(data_size <= size_of(T), "%v <= %v, expected %v", data_size, size_of(T), typeid_of(T)); | |
assert(row <= t.row_count); | |
ptr := t.ptr + uintptr(row*u32(t.row_size) + u32(t.columns[column].offset)); | |
switch data_size { | |
case 1: return T((^ u8)(ptr)^); | |
case 2: return T((^u16)(ptr)^); | |
case 4: return T((^u32)(ptr)^); | |
case 8: return T((^u64)(ptr)^); | |
} | |
return T((^u64)(ptr)^); | |
} | |
Row :: struct { | |
table: ^Table, | |
index: u32, | |
} | |
bits_needed :: proc(value: u32) -> u8 { | |
value := value; | |
value -= 1; | |
bits := u8(1); | |
for { | |
value >>= 1; | |
if value == 0 { | |
break; | |
} | |
bits += 1; | |
} | |
return bits; | |
} | |
is_composite_index_size :: proc(row_count: u32, bits: u8) -> bool { | |
return row_count < (u32(1) << (16-bits)); | |
} | |
composite_index_size :: proc(tables: ..Table) -> u8 { | |
assert(len(tables) > 0); | |
n := bits_needed(u32(len(tables))); | |
for table in tables { | |
if !is_composite_index_size(table.row_count, n) { | |
return 4; | |
} | |
} | |
return 2; | |
} | |
table_set_data :: proc(table: ^Table, table_ptr: uintptr) { | |
table.ptr = table_ptr + uintptr(table.row_count) * uintptr(table.row_size); | |
} | |
database_get_blob :: proc(db: ^Database, index: u32) -> []byte { | |
data := db.blobs[index:]; | |
initial_byte := data[0]; | |
blob_size_bytes: u32; | |
switch initial_byte>>5 { | |
case 0, 1, 2, 3: | |
blob_size_bytes = 1; | |
initial_byte &= 0x7f; | |
case 4, 5: | |
blob_size_bytes = 2; | |
initial_byte &= 0x3f; | |
case 6: | |
blob_size_bytes = 4; | |
initial_byte &= 0x1f; | |
case: | |
panic("invalid blob encoding"); | |
} | |
blob_size := u32(initial_byte); | |
for b in data[1:blob_size_bytes-1] { | |
blob_size = (blob_size << 8) + u32(b); | |
} | |
return data[blob_size_bytes:][:blob_size]; | |
} | |
database_get_string :: proc(db: ^Database, index: u32) -> (string, bool) { | |
if index >= u32(len(db.strings)) { | |
return "", false; | |
} | |
s := db.strings[index:]; | |
if i, ok := slice.linear_search(s[:], 0); ok { | |
return string(s[:i]), true; | |
} | |
return "", false; | |
} | |
table_get_string :: proc(db: ^Database, table: ^Table, row, column: u32) -> (string, bool) { | |
index := table_get_value(table, u32, row, column); | |
return database_get_string(db, index); | |
} | |
parse_database :: proc(db: ^Database) -> bool { | |
if len(db.data) < size_of(Image_Dos_Header) { | |
return false; | |
} | |
db.ptr = uintptr(raw_data(db.data)); | |
ptr := db.ptr; | |
dos := (^Image_Dos_Header)(ptr); | |
if dos.e_signature != 0x5a4d { | |
return false; | |
} | |
if len(db.data) < int(dos.e_lfanew) + size_of(Image_Nt_Headers32) { | |
return false; | |
} | |
pe := (^Image_Nt_Headers32)(ptr + uintptr(dos.e_lfanew)); | |
// fmt.printf("%#v\n", pe); | |
if pe.FileHeader.NumberOfSections == 0 || pe.FileHeader.NumberOfSections > 100 { | |
return false; | |
} | |
sections_ptr: ^Image_Section_Header; | |
com_virtual_address: u32; | |
switch pe.OptionalHeader.Magic { | |
case 0x10b: // PE32 | |
com_virtual_address = pe.OptionalHeader.DataDirectory[14].VirtualAddress; | |
sections_ptr = (^Image_Section_Header)(ptr + uintptr(dos.e_lfanew) + size_of(Image_Nt_Headers32)); | |
case 0x20b: // PE32+ | |
pe_plus := (^Image_Nt_Headers32plus)(ptr + uintptr(dos.e_lfanew)); | |
com_virtual_address = pe_plus.OptionalHeader.DataDirectory[14].VirtualAddress; | |
sections_ptr = (^Image_Section_Header)(ptr + uintptr(dos.e_lfanew) + size_of(Image_Nt_Headers32plus)); | |
case: | |
return false; | |
} | |
sections := mem.slice_ptr(sections_ptr, int(pe.FileHeader.NumberOfSections)); | |
section := section_from_rva(sections, com_virtual_address); | |
if section == nil { | |
return false; | |
} | |
offset := offset_from_rva(section^, com_virtual_address); | |
cli := (^Image_Cor20_Header)(ptr + offset); | |
if cli.cb != size_of(Image_Cor20_Header) { | |
return false; | |
} | |
section = section_from_rva(sections, cli.MetaData.VirtualAddress); | |
if section == nil { | |
return false; | |
} | |
offset = offset_from_rva(section^, cli.MetaData.VirtualAddress); | |
if (^u32)(ptr + offset)^ != 0x424a5342 { | |
return false; | |
} | |
version_length := (^u32)(ptr + offset + 12)^; | |
stream_count := (^u16)(ptr + offset + uintptr(version_length) + 18)^; | |
stream_ptr := ptr + offset + uintptr(version_length) + 20; | |
Stream_Range :: struct { | |
offset: u32, | |
size: u32, | |
}; | |
for i in 0..<stream_count { | |
stream := (^Stream_Range)(stream_ptr); | |
name := to_string((^[12]byte)(stream_ptr + 8)[:]); | |
table_offset := offset+uintptr(stream.offset); | |
switch name { | |
case "#Strings": | |
db.strings = db.data[table_offset:][:stream.size]; | |
case "#Blob": | |
db.blobs = db.data[table_offset:][:stream.size]; | |
case "#GUID": | |
db.guids = db.data[table_offset:][:stream.size]; | |
case "#~": | |
db.tables = db.data[table_offset:][:stream.size]; | |
case "#US": | |
// ignore | |
case: | |
return false; | |
} | |
{ | |
n := uintptr(len(name)); | |
padding := 4 - n%4; | |
if padding == 0 { | |
padding = 4; | |
} | |
stream_ptr += 8 + n + padding; | |
} | |
} | |
heap_sizes := (^bit_set[0..<8; u8])(&db.tables[6])^; | |
string_index_size: u8 = 4 if (0 in heap_sizes) else 2; | |
guid_index_size: u8 = 4 if (1 in heap_sizes) else 2; | |
blob_index_size: u8 = 4 if (2 in heap_sizes) else 2; | |
valid_bits := (^bit_set[0..<64; u64])(&db.tables[8])^; | |
table_ptr := uintptr(&db.tables[24]); | |
for i in 0..<64 { | |
if i not_in valid_bits { | |
continue; | |
} | |
row_count := (^u32)(table_ptr)^; | |
table_ptr += 4; | |
switch i { | |
case 0x00: db.module.row_count = row_count; | |
case 0x01: db.type_ref.row_count = row_count; | |
case 0x02: db.type_def.row_count = row_count; | |
case 0x04: db.field.row_count = row_count; | |
case 0x06: db.method_def.row_count = row_count; | |
case 0x08: db.param.row_count = row_count; | |
case 0x09: db.interface_impl.row_count = row_count; | |
case 0x0a: db.member_ref.row_count = row_count; | |
case 0x0b: db.constant.row_count = row_count; | |
case 0x0c: db.custom_attribute.row_count = row_count; | |
case 0x0d: db.field_marshal.row_count = row_count; | |
case 0x0e: db.decl_security.row_count = row_count; | |
case 0x0f: db.class_layout.row_count = row_count; | |
case 0x10: db.field_layout.row_count = row_count; | |
case 0x11: db.stand_alone_sig.row_count = row_count; | |
case 0x12: db.event_map.row_count = row_count; | |
case 0x14: db.event.row_count = row_count; | |
case 0x15: db.property_map.row_count = row_count; | |
case 0x17: db.property.row_count = row_count; | |
case 0x18: db.method_semantics.row_count = row_count; | |
case 0x19: db.method_impl.row_count = row_count; | |
case 0x1a: db.module_ref.row_count = row_count; | |
case 0x1b: db.type_spec.row_count = row_count; | |
case 0x1c: db.impl_map.row_count = row_count; | |
case 0x1d: db.field_rva.row_count = row_count; | |
case 0x20: db.assembly.row_count = row_count; | |
case 0x21: db.assembly_processor.row_count = row_count; | |
case 0x22: db.assembly_os.row_count = row_count; | |
case 0x23: db.assembly_ref.row_count = row_count; | |
case 0x24: db.assembly_ref_processor.row_count = row_count; | |
case 0x25: db.assembly_ref_os.row_count = row_count; | |
case 0x26: db.file.row_count = row_count; | |
case 0x27: db.exported_type.row_count = row_count; | |
case 0x28: db.manifest_resource.row_count = row_count; | |
case 0x29: db.nested_class.row_count = row_count; | |
case 0x2a: db.generic_param.row_count = row_count; | |
case 0x2b: db.method_spec.row_count = row_count; | |
case 0x2c: db.generic_param_constraint.row_count = row_count; | |
case: | |
fmt.println("unknown metadata table", i); | |
return false; | |
}; | |
} | |
empty_table := Table{}; | |
type_def_or_ref, has_constant, has_custom_attribute, has_field_marshal, has_decl_security: u8; | |
member_ref_parent, has_semantics, method_def_or_ref, member_forwarded, implementation: u8; | |
custom_attribute_type, resolution_scope, type_or_method_def: u8; | |
{ | |
using db; | |
type_def_or_ref = composite_index_size(type_def, type_ref, type_spec); | |
has_constant = composite_index_size(field, param, property); | |
has_custom_attribute = composite_index_size(method_def, field, type_ref, type_def, param, interface_impl, member_ref, module, property, event, stand_alone_sig, module_ref, type_spec, assembly, assembly_ref, file, exported_type, manifest_resource, generic_param, generic_param_constraint, method_spec); | |
has_field_marshal = composite_index_size(field, param); | |
has_decl_security = composite_index_size(type_def, method_def, assembly); | |
member_ref_parent = composite_index_size(type_def, type_ref, module_ref, method_def, type_spec); | |
has_semantics = composite_index_size(event, property); | |
method_def_or_ref = composite_index_size(method_def, member_ref); | |
member_forwarded = composite_index_size(field, method_def); | |
implementation = composite_index_size(file, assembly_ref, exported_type); | |
custom_attribute_type = composite_index_size(method_def, member_ref, empty_table, empty_table, empty_table); | |
resolution_scope = composite_index_size(module, module_ref, assembly_ref, type_ref); | |
type_or_method_def = composite_index_size(type_def, method_def); | |
table_set_columns(&assembly, 4, 8, 4, blob_index_size, string_index_size, string_index_size); | |
table_set_columns(&assembly_os, 4, 4, 4); | |
table_set_columns(&assembly_processor, 4); | |
table_set_columns(&assembly_ref, 8, 4, blob_index_size, string_index_size, string_index_size, blob_index_size); | |
table_set_columns(&assembly_ref_os, 4, 4, 4, table_index_size(assembly_ref)); | |
table_set_columns(&assembly_ref_processor, 4, table_index_size(assembly_ref)); | |
table_set_columns(&class_layout, 2, 4, table_index_size(type_def)); | |
table_set_columns(&constant, 2, has_constant, blob_index_size); | |
table_set_columns(&custom_attribute, has_custom_attribute, custom_attribute_type, blob_index_size); | |
table_set_columns(&decl_security, 2, has_decl_security, blob_index_size); | |
table_set_columns(&event_map, table_index_size(type_def), table_index_size(event)); | |
table_set_columns(&event, 2, string_index_size, type_def_or_ref); | |
table_set_columns(&exported_type, 4, 4, string_index_size, string_index_size, implementation); | |
table_set_columns(&field, 2, string_index_size, blob_index_size); | |
table_set_columns(&field_layout, 4, table_index_size(field)); | |
table_set_columns(&field_marshal, has_field_marshal, blob_index_size); | |
table_set_columns(&field_rva, 4, table_index_size(field)); | |
table_set_columns(&file, 4, string_index_size, blob_index_size); | |
table_set_columns(&generic_param, 2, 2, type_or_method_def, string_index_size); | |
table_set_columns(&generic_param_constraint, table_index_size(generic_param), type_def_or_ref); | |
table_set_columns(&impl_map, 2, member_forwarded, string_index_size, table_index_size(module_ref)); | |
table_set_columns(&interface_impl, table_index_size(type_def), type_def_or_ref); | |
table_set_columns(&manifest_resource, 4, 4, string_index_size, implementation); | |
table_set_columns(&member_ref, member_ref_parent, string_index_size, blob_index_size); | |
table_set_columns(&method_def, 4, 2, 2, string_index_size, blob_index_size, table_index_size(param)); | |
table_set_columns(&method_impl, table_index_size(type_def), method_def_or_ref, method_def_or_ref); | |
table_set_columns(&method_semantics, 2, table_index_size(method_def), has_semantics); | |
table_set_columns(&method_spec, method_def_or_ref, blob_index_size); | |
table_set_columns(&module, 2, string_index_size, guid_index_size, guid_index_size, guid_index_size); | |
table_set_columns(&module_ref, string_index_size); | |
table_set_columns(&nested_class, table_index_size(type_def), table_index_size(type_def)); | |
table_set_columns(¶m, 2, 2, string_index_size); | |
table_set_columns(&property, 2, string_index_size, blob_index_size); | |
table_set_columns(&property_map, table_index_size(type_def), table_index_size(property)); | |
table_set_columns(&stand_alone_sig, blob_index_size); | |
table_set_columns(&type_def, 4, string_index_size, string_index_size, type_def_or_ref, table_index_size(field), table_index_size(method_def)); | |
table_set_columns(&type_ref, resolution_scope, string_index_size, string_index_size); | |
table_set_columns(&type_spec, blob_index_size); | |
table_set_data(&assembly, table_ptr); | |
table_set_data(&assembly_os, table_ptr); | |
table_set_data(&assembly_processor, table_ptr); | |
table_set_data(&assembly_ref, table_ptr); | |
table_set_data(&assembly_ref_os, table_ptr); | |
table_set_data(&assembly_ref_processor, table_ptr); | |
table_set_data(&class_layout, table_ptr); | |
table_set_data(&constant, table_ptr); | |
table_set_data(&custom_attribute, table_ptr); | |
table_set_data(&decl_security, table_ptr); | |
table_set_data(&event_map, table_ptr); | |
table_set_data(&event, table_ptr); | |
table_set_data(&exported_type, table_ptr); | |
table_set_data(&field, table_ptr); | |
table_set_data(&field_layout, table_ptr); | |
table_set_data(&field_marshal, table_ptr); | |
table_set_data(&field_rva, table_ptr); | |
table_set_data(&file, table_ptr); | |
table_set_data(&generic_param, table_ptr); | |
table_set_data(&generic_param_constraint, table_ptr); | |
table_set_data(&impl_map, table_ptr); | |
table_set_data(&interface_impl, table_ptr); | |
table_set_data(&manifest_resource, table_ptr); | |
table_set_data(&member_ref, table_ptr); | |
table_set_data(&method_def, table_ptr); | |
table_set_data(&method_impl, table_ptr); | |
table_set_data(&method_semantics, table_ptr); | |
table_set_data(&method_spec, table_ptr); | |
table_set_data(&module, table_ptr); | |
table_set_data(&module_ref, table_ptr); | |
table_set_data(&nested_class, table_ptr); | |
table_set_data(¶m, table_ptr); | |
table_set_data(&property, table_ptr); | |
table_set_data(&property_map, table_ptr); | |
table_set_data(&stand_alone_sig, table_ptr); | |
table_set_data(&type_def, table_ptr); | |
table_set_data(&type_ref, table_ptr); | |
table_set_data(&type_spec, table_ptr); | |
} | |
return true; | |
} | |
main :: proc() { | |
path := "misc/tools/win32metadata-master/scripts/BaselineWinmd/10.0.19041.5/Windows.Win32.winmd"; | |
// path := "misc/tools/win32metadata-master/scripts/BaselineWinmd/10.0.21287.1009/Windows.Win32.winmd"; | |
data, data_ok := os.read_entire_file(path); | |
if !data_ok { | |
os.exit(1); | |
} | |
db := &Database{data=data}; | |
if !parse_database(db) { | |
os.exit(1); | |
} | |
fmt.println("module ", db.module); | |
fmt.println("type_ref ", db.type_ref); | |
fmt.println("type_def ", db.type_def); | |
fmt.println("field ", db.field); | |
fmt.println("method_def ", db.method_def); | |
fmt.println("param ", db.param); | |
fmt.println("interface_impl ", db.interface_impl); | |
fmt.println("member_ref ", db.member_ref); | |
fmt.println("constant ", db.constant); | |
fmt.println("custom_attribute", db.custom_attribute); | |
fmt.println("class_layout ", db.class_layout); | |
fmt.println("field_layout ", db.field_layout); | |
fmt.println("module_ref ", db.module_ref); | |
fmt.println("impl_map ", db.impl_map); | |
fmt.println("assembly ", db.assembly); | |
fmt.println("assembly_ref ", db.assembly_ref); | |
fmt.println("nested_class ", db.nested_class); | |
{ | |
t := &db.assembly_ref; | |
for row_idx in 0..<t.row_count { | |
if row_idx > 20 { | |
break; | |
} | |
for c, i in t.columns { | |
if c.size == 0 { | |
break; | |
} | |
if i > 0 { | |
fmt.print(", "); | |
} | |
s, _ := table_get_string(db, t, row_idx, u32(i)); | |
fmt.printf("%q", s); | |
} | |
fmt.println(); | |
} | |
fmt.println(); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment