diff --git a/heuristics.py b/heuristics.py new file mode 100644 index 0000000..4f29b44 --- /dev/null +++ b/heuristics.py @@ -0,0 +1,40 @@ +def try_scene(f): + f.seek(0) + while True: + command = f.read(8) + if len(command) == 0: + return False + if command[2:4] != b'\x00\x00': + return False + if command[0] > 0x1e: + return False + if command[4] != 0x02 and command[4] != 0x00: + if command[0] not in (0x05, 0x10, 0x11, 0x12): + return False + if command == b'\x14\x00\x00\x00\x00\x00\x00\x00': + return True + +def try_room(f): + # note: doesn't detect syotes_room_0 because it's missing a header + f.seek(0) + while True: + command = f.read(8) + if len(command) == 0: + return False + if command[2:4] != b'\x00\x00': + return False + if command[0] > 0x1e: + return False + if command[4] != 0x03 and command[4] != 0x00: + if command[0] not in (0x05, 0x10, 0x11, 0x12): + return False + if command == b'\x14\x00\x00\x00\x00\x00\x00\x00': + return True + +def detect_format(f, fn=None): + if try_scene(f): + return 'scene' + if try_room(f): + return 'room' + + return None diff --git a/z64dump.py b/z64dump.py index af201a8..2130674 100755 --- a/z64dump.py +++ b/z64dump.py @@ -7,6 +7,7 @@ from io import BytesIO from hashlib import sha1 from util import * +from heuristics import * import n64 import Yaz0 @@ -15,6 +16,12 @@ lament = lambda *args, **kwargs: print(*args, file=sys.stderr, **kwargs) # assume first entry is makerom (0x1060), and second entry begins from makerom dma_sig = b"\x00\x00\x00\x00\x00\x00\x10\x60\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x10\x60" +def dump_wrap(data, fn, size): + kind = detect_format(BytesIO(data), fn) + if kind is not None: + fn += '.' + kind + dump_as(data, fn, size) + def z_dump_file(f, i=0, name=None): vs = R4(f.read(4)) # virtual start ve = R4(f.read(4)) # virtual end @@ -41,20 +48,20 @@ def z_dump_file(f, i=0, name=None): pe = ps + size f.seek(ps) data = f.read(pe - ps) - dump_as(data, fn, size) + dump_wrap(data, fn, size) else: #lament('file is compressed') f.seek(ps) compressed = f.read(pe - ps) if compressed[:4] == b'Yaz0': data = Yaz0.decode(compressed) - dump_as(data, fn, size) + dump_wrap(data, fn, size) else: lament('unknown compression; skipping:', fn) lament(compressed[:4]) f.seek(here) - return True, fn, vs, ve, ps, pe + return True def z_find_dma(f): while True: