import os import sys import struct import string from pprint import pprint from io import BytesIO from contextlib import contextmanager from datetime import timedelta, datetime import glob printable_chars = set(bytes(string.printable, "ascii")) - set(b"\n\r\t\x0b\x0c") def hexdump(data, cols=16, offset=0, markers=None): if markers is None: markers = [] lines = [] while True: hexdata = " ".join("{:02X}".format(v) for v in data[:cols]).ljust( 3 * cols - 1, " " ) print_data = "".join( [chr(v) if v in printable_chars else "." for v in data[:cols]] ) lines.append("{:04X} {} {}".format(offset, hexdata, print_data)) offset += len(data[:cols]) data = data[cols:] if not data: break return "\n".join(lines).strip() @contextmanager def seek_to(fh, offset, pos=None): if pos is None: pos = fh.tell() fh.seek(offset) yield fh.seek(pos) def read_array(s, fh): ret = [] count = read_struct("".format(rest)) fh.seek(0) return "".format(magic, len(fh.read())) def parse(self, magic, data, depth=0): print("{}[{}] {} bytes".format(" " * self.depth, magic, len(data))) self.depth += 1 fh = BytesIO(data) if len(data) != 0: ret = getattr(self, magic, lambda fh: self._default(magic, fh))(fh) else: ret = None pos = fh.tell() leftover = len(fh.read()) fh.seek(pos) self.depth -= 1 if leftover: print("{}[{}] {} bytes unparsed".format(" " * self.depth, magic, leftover)) if self.debug: print(hexdump(fh.read(self.dump_size))) rest = len(fh.read()) if rest: print("<{} more bytes>".format(rest)) print("-" * 50) return ret def parse_block(self, fh): block = read_block(fh) if block: return self.parse(*block) # Block definitions def SM3(self, fh): ret = {} ret["unk_1"] = fh.read(4) # always F8156500 ret["timestamp_2"] = datetime.fromtimestamp(read_struct("7I", fh)] # ret["maps"]=[] # for _ in range(ret["num_maps"]): # ret["maps"].append(self.parse_block(fh)) return {"maps": fh.read().count(b"MAP\0")} def MAP(self, fh): ret = {} ret["unk_1"] = read_struct("