dreamcast/iso9660/byte_position.py

120 lines
3.1 KiB
Python

import sys
from dataclasses import dataclass
from os.path import splitext
from csv_input import read_input
from generate import renderer
from pprint import pprint
def parse_bp(s):
if ' to ' in s:
start0, end0 = s.split(' to ')
if '(' in end0 and ')' in end0 and 'LEN_' in end0:
end0 = int(start0) - 1
start, end = int(start0), int(end0)
return start, end
else:
start, end = int(start0), int(end0)
assert start <= end, (start, end)
return start, end
else:
start = int(s)
return start, start
def bp_range(start, end):
return set(range(start, end+1))
reserved = 0
def sanitize_field_name(name):
global reserved
if name == "(Reserved for future standardization)" or name == "Unused field":
reserved += 1
return f"_res{reserved}";
if '(' in name:
assert 'LEN_' in name, name
name = name.split('(')[0].strip()
name = name.lower().replace(' ', '_')
return name
def sanitize_content_name(name):
if name == 'Numerical value':
return 'numerical_value'
else:
return 'bytes'
@dataclass
class Field:
start: int
end: int
name: str
content: str
def parse(rows):
seen_bps = set()
seen_names = set()
for row in rows:
start, end = parse_bp(row['BP'])
_range = bp_range(start, end)
assert seen_bps.intersection(_range) == set(), row
seen_bps = seen_bps.union(_range)
field_name = sanitize_field_name(row["Field name"])
assert field_name not in seen_names
seen_names.add(field_name)
content_name = sanitize_content_name(row["Content"])
yield Field(
start=start,
end=end,
name=field_name,
content=content_name
)
type_dict = {
1: 'uint8_t',
2: 'uint16_t',
4: 'uint16_le_be',
8: 'uint32_le_be',
}
def header():
yield "#pragma once"
yield ""
yield "#include <cstdint>"
yield "#include <cstddef>"
yield ""
yield '#include "uint_le_be.hpp"'
yield ""
def render_fields(input_name, fields):
yield f"struct {input_name} {{"
for field in fields:
field_size = (field.end - field.start) + 1
if field.content == 'numerical_value':
assert field_size in type_dict, field
type = type_dict[field_size]
yield f"const {type} {field.name};"
else:
if field_size == 1:
yield f"const uint8_t {field.name};"
elif field_size == 0:
yield f"const uint8_t {field.name}[];"
else:
yield f"const uint8_t {field.name}[{field_size}];"
yield "};"
for field in fields:
yield f"static_assert((offsetof (struct {input_name}, {field.name})) == {field.start - 1});"
if __name__ == "__main__":
input_file = sys.argv[1]
input_name, _ = splitext(input_file)
rows = read_input(input_file)
fields = list(parse(rows))
render, out = renderer()
render(header())
render(render_fields(input_name, fields))
sys.stdout.write(out.getvalue())