Files
padlab/tools/bin2h.py
2023-06-28 00:28:06 +10:00

128 lines
2.7 KiB
Python

#!/usr/bin/env python3
import sys
from pathlib import Path
from typing import BinaryIO, TextIO
from os import SEEK_SET, SEEK_END
import re
label_invalid = re.compile(r"\W") # Turn invalid label chars into underscores
label_lstrip = re.compile(r"^[\d_]+") # Trim all underscores or numbers from the beginning
def sanitise_label(label: str) -> str:
tmp = label_invalid.sub("_", label, re.I)
return label_lstrip.sub("", tmp, re.I)
def bin2h(name: str, binf: BinaryIO, h: TextIO):
label = sanitise_label(name)
binf.seek(0, SEEK_END)
length = binf.tell()
binf.seek(0, SEEK_SET)
h.write(f"#define {label.upper()}_SIZE {length}\n")
whitespace = "\t"
h.write(f"static const unsigned char {label}[{length}] = {{\n{whitespace}")
for i, c in enumerate(binf.read()):
if i != 0:
h.write(", ")
if i % 16 == 0:
h.write(f"\n{whitespace}")
h.write(f"0x{c:02X}")
h.write("\n};\n")
def txt2h(name: str, txt: TextIO, h: TextIO):
h.write(f"static const char* const {sanitise_label(name)} = \n")
h.write("\"")
remap = {
"\a": "\\a", "\b": "\\b", "\f": "\\f", "\n": "\\n", "\r": "\\r",
"\t": "\\t", "\v": "\\v", "\\": "\\\\", "\"": "\\\""}
esc_numeric = False
for idx, c in enumerate(txt.read()):
if m := remap.get(c):
h.write(m)
else:
if (i := ord(c)) < 0x7F:
if c.isprintable() and not (esc_numeric and c.isnumeric()):
h.write(c)
else:
if i < 8:
h.write(f"\\{i:o}")
else:
h.write(f"\\x{i:02X}")
esc_numeric = True
continue
elif i < 0x10000:
h.write(f"\\u{i:04X}")
else:
h.write(f"\\U{i:08X}")
esc_numeric = False
h.write("\";\n")
def main():
usage = "Usage [-b data.bin] [-t text.txt] <out.h>"
binfiles = []
txtfiles = []
out = None
opt = None
for arg in sys.argv[1:]:
if opt is not None:
if opt == "b":
binfiles.append(arg)
elif opt == "t":
txtfiles.append(arg)
else:
sys.exit(usage)
opt = None
if arg.startswith("-"):
opt = arg[1:]
else:
out = Path(arg)
if opt is not None or out is None:
sys.exit(usage)
if len(binfiles) == 0 and len(txtfiles) == 0:
sys.exit(usage)
with out.open("w") as h:
guard = f"BIN2H_{sanitise_label(out.name).upper()}"
if not guard.endswith("_H"):
guard += "_H"
h.writelines([
"/*DO NOT EDIT*/\n",
"// Autogenerated by bin2h\n",
"\n",
f"#ifndef {guard}\n",
f"#define {guard}\n",
"\n"])
# Write binaries
for i in binfiles:
path = Path(i)
with path.open("rb") as file:
bin2h(path.name, file, h)
h.write("\n")
# Write texts
for i in txtfiles:
path = Path(i)
with path.open("r") as file:
txt2h(path.name, file, h)
h.write("\n")
h.write(f"#endif//{guard}\n")
if __name__ == "__main__":
main()