mirror of
https://github.com/WerWolv/ImHex-Patterns.git
synced 2026-03-27 23:37:04 -05:00
205 lines
5.5 KiB
Python
205 lines
5.5 KiB
Python
import yaml
|
|
import sys
|
|
import re
|
|
import string
|
|
|
|
output = ""
|
|
|
|
top_level_struct_name = ""
|
|
top_level_struct = ""
|
|
|
|
def fixTypeName(name):
|
|
name = name.replace("_", " ")
|
|
name = string.capwords(name)
|
|
name = name.replace(" ", "")
|
|
|
|
return name
|
|
|
|
def add_line(line, indent = 0):
|
|
global output
|
|
output += (" " * indent) + line + "\n"
|
|
|
|
def handle_meta_xref(xref):
|
|
if "mime" in xref:
|
|
add_line(f"#pragma MIME {xref['mime']}")
|
|
|
|
def handle_meta_endian(meta_endian):
|
|
if meta_endian == "be":
|
|
add_line("#pragma endian big")
|
|
elif meta_endian == "le":
|
|
add_line("#pragma endian little")
|
|
else:
|
|
print(f"Unknown endian: {meta_endian}")
|
|
exit(1)
|
|
|
|
def handle_meta(meta):
|
|
if "xref" in meta:
|
|
handle_meta_xref(meta["xref"])
|
|
if "endian" in meta:
|
|
handle_meta_endian(meta["endian"])
|
|
if "id" in meta:
|
|
global top_level_struct_name
|
|
top_level_struct_name = str(meta["id"]).capitalize()
|
|
|
|
def handle_types(types):
|
|
result = ""
|
|
for type in types:
|
|
entry = types[type]
|
|
|
|
is_bitfield = False
|
|
lines = ""
|
|
|
|
if "seq" in entry:
|
|
is_bitfield, lines = handle_seq(entry["seq"])
|
|
if "instances" in entry:
|
|
lines += handle_instances(entry["instances"])
|
|
|
|
if is_bitfield:
|
|
result += f"bitfield {fixTypeName(type)} {{\n"
|
|
else:
|
|
result += f"struct {fixTypeName(type)} {{\n"
|
|
|
|
result += lines + "\n"
|
|
|
|
result += "};\n\n"
|
|
|
|
return result
|
|
|
|
def handle_instances(instances):
|
|
result = ""
|
|
for name in instances:
|
|
instance = instances[name]
|
|
result += f" auto {name} = {instance['value']} [[export]];"
|
|
|
|
if "doc" in instance:
|
|
result += " // " + instance["doc"].replace('\n', ' ')
|
|
|
|
result += "\n"
|
|
|
|
return result.rstrip()
|
|
|
|
|
|
def handle_seq(seq):
|
|
result = ""
|
|
|
|
is_bitfield = False
|
|
lines = []
|
|
|
|
for entry in seq:
|
|
name = entry["id"]
|
|
entry_type = ""
|
|
array_size = ""
|
|
bitfield_field_size = ""
|
|
content_check = ""
|
|
docs = ""
|
|
|
|
if "doc" in entry:
|
|
docs = entry["doc"]
|
|
|
|
if "type" in entry:
|
|
entry_type = entry["type"]
|
|
|
|
if entry_type == "str":
|
|
if entry["encoding"] == "UTF-16LE":
|
|
entry_type = "le char16"
|
|
elif entry["encoding"] == "UTF-16BE":
|
|
entry_type = "be char16"
|
|
else:
|
|
entry_type = "char"
|
|
elif entry_type == "u1":
|
|
entry_type = "u8"
|
|
elif entry_type == "u2":
|
|
entry_type = "u16"
|
|
elif entry_type == "u4":
|
|
entry_type = "u32"
|
|
elif entry_type == "u8":
|
|
entry_type = "u64"
|
|
elif entry_type == "s1":
|
|
entry_type = "s8"
|
|
elif entry_type == "s2":
|
|
entry_type = "s16"
|
|
elif entry_type == "s4":
|
|
entry_type = "s32"
|
|
elif entry_type == "s8":
|
|
entry_type = "s64"
|
|
elif entry_type == "f4":
|
|
entry_type = "float"
|
|
elif entry_type == "f8":
|
|
entry_type = "double"
|
|
else:
|
|
entry_type = fixTypeName(entry_type)
|
|
|
|
if "contents" in entry:
|
|
if isinstance(entry["contents"], str):
|
|
entry_type = f"type::Magic<\"{entry['contents']}\">"
|
|
else:
|
|
array_size = len(entry["contents"])
|
|
encoded_string = ""
|
|
for char in entry["contents"]:
|
|
encoded_string += f"\\x{char:02X}"
|
|
|
|
entry_type = f"type::Magic<\"{encoded_string}\">"
|
|
elif "size" in entry:
|
|
array_size = entry["size"]
|
|
if isinstance(array_size, str):
|
|
array_size = array_size.replace("_root", "parent")
|
|
entry_type = "u8"
|
|
|
|
if re.compile("^b[0-9]+$").match(entry_type):
|
|
is_bitfield = True
|
|
bitfield_field_size = int(entry_type[1:])
|
|
|
|
new_line = ""
|
|
|
|
if "if" in entry:
|
|
new_line += f" if ({entry['if']})\n "
|
|
|
|
if array_size != "":
|
|
new_line += f" {entry_type} {name}[{array_size}];"
|
|
elif bitfield_field_size != "":
|
|
new_line += f" {name} : {bitfield_field_size};"
|
|
else:
|
|
new_line += f" {entry_type} {name};"
|
|
|
|
if docs != "":
|
|
new_line += " // " + docs.replace('\n', ' ')
|
|
|
|
lines.append(new_line)
|
|
|
|
for line in lines:
|
|
result += line + "\n"
|
|
|
|
return (is_bitfield, result)
|
|
|
|
def generate_imhex_pattern(data):
|
|
global top_level_struct
|
|
|
|
add_line("import type.magic;\n")
|
|
|
|
if "meta" in data:
|
|
handle_meta(data["meta"])
|
|
|
|
add_line("")
|
|
|
|
if "types" in data:
|
|
add_line(handle_types(data["types"]))
|
|
|
|
if "seq" in data:
|
|
add_line(handle_types({ top_level_struct_name: { "seq": data["seq"] } }))
|
|
|
|
add_line(f"{fixTypeName(top_level_struct_name)} {fixTypeName(top_level_struct_name).lower()} @ 0x00;\n")
|
|
|
|
if __name__ == "__main__":
|
|
if len(sys.argv) < 2:
|
|
print("Usage: ksy2pat.py <ksy file>")
|
|
exit(1)
|
|
|
|
file_content = ""
|
|
with open(sys.argv[1]) as f:
|
|
file_content = f.read()
|
|
|
|
data = yaml.load(file_content, Loader=yaml.CLoader)
|
|
generate_imhex_pattern(data)
|
|
|
|
with open(f"{sys.argv[1]}.hexpat", "w") as f:
|
|
f.write(output) |