#!/usr/bin/env python3 import sys from pathlib import Path from typing import BinaryIO, TextIO 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): raise NotImplementedError 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] " 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) # Write texts for i in txtfiles: path = Path(i) with path.open("r") as file: txt2h(path.name, file, h) h.writelines([ "\n", f"#endif//{guard}\n"]) if __name__ == "__main__": main()