From a8824d8041a975d6304106dbb33d547a97ada4a1 Mon Sep 17 00:00:00 2001 From: itsme Date: Wed, 7 Jul 2021 12:25:09 +0200 Subject: crodump: the --struonly option now prints detailed info on tables and fields --- crodump.py | 108 +++++++++++++++++++++++++++++++++++++++++++++++++------------ 1 file changed, 88 insertions(+), 20 deletions(-) diff --git a/crodump.py b/crodump.py index 46fd969..e311190 100644 --- a/crodump.py +++ b/crodump.py @@ -53,7 +53,7 @@ class Datafile: return self.dat.read(size) def readrec(self, idx): - ofs, ln, chk = self.tabidx[idx-1] + ofs, ln, chk = self.tadidx[idx-1] if ln==0xFFFFFFFF: # deleted record return @@ -133,6 +133,75 @@ class Datafile: dat = self.readdata(o, l) print("%08x-%08x: %s" % (o, o+l, toout(args, dat))) +def destruct_bank_definition(args, data): + """ + decode the 'bank' / database definition + """ + rd = ByteReader(data) + + version = rd.readbyte() + print("bank version: %02x" % version) + + d = dict() + while not rd.eof(): + keyname = rd.readname() + if keyname in d: + print("WARN: duplicate key: %s" % keyname) + + index_or_length = rd.readdword() + if index_or_length >> 31: + d[keyname] = rd.readbytes(index_or_length & 0x7FFFFFFF) + print("%-20s - %s" % (keyname, toout(args, d[keyname]))) + else: + d[keyname] = index_or_length + print("%-20s -> %s" % (keyname, d[keyname])) + return d + +def decode_field(data): + rd = ByteReader(data) + typ = rd.readword() + idx1 = rd.readdword() + name = rd.readname() + unk1 = rd.readdword() + unk2 = rd.readbyte() + if typ: + idx2 = rd.readdword() + unk3 = rd.readdword() + unk4 = rd.readdword() + remain = rd.readbytes() + + print("%d %2d/%2d %d,%d,%d,%d - '%s' -- %s" % (typ, idx1, idx2, unk1, unk2, unk3, unk4, name, tohex(remain))) + else: + print("%d %2d %d,%d - '%s'" % (typ, idx1, unk1, unk2, name)) + + +def destruct_base_definition(args, data): + """ + decode the 'base' / table definition + """ + rd = ByteReader(data) + + version = rd.readbyte() + print("base version: %02x" % version) + unk123 = [rd.readword() for _ in range(3)] + unk45 = [rd.readdword() for _ in range(2)] + tablename = rd.readname() + unkname = rd.readname() + unk7 = rd.readdword() + nrfields = rd.readdword() + print("%d,%d,%d,%d,%d %d,%d '%s' '%s'" % (*unk123, *unk45, unk7, nrfields, tablename, unkname)) + fields = [] + for _ in range(nrfields): + l = rd.readword() + fielddef = rd.readbytes(l) + if args.verbose: + print("field: @%04x: %04x - %s" % (rd.o, l, tohex(fielddef))) + fields.append(decode_field(fielddef)) + remaining = rd.readbytes() + + print("rem: %s" % tohex(remaining)) + + class Database: """ represent the entire database, consisting of stru, index and bank files """ @@ -170,6 +239,7 @@ class Database: print("stru") self.stru.dump(args) if args.struonly: + self.dumptabledefs(args) return if self.index: print("index") @@ -181,6 +251,17 @@ class Database: print("sys") self.sys.dump(args) + def dumptabledefs(self, args): + dbinfo = self.stru.readrec(1) + dbdef = destruct_bank_definition(args, dbinfo) + + for i in range(1, 100): + idx = dbdef.get("Base%03d" % i) + if idx: + print("== Base%03d ==" % i) + tbinfo = self.stru.readrec(idx) + tbdef = destruct_base_definition(args, tbinfo) + def incdata(data, s): """ @@ -262,25 +343,10 @@ def destruct(args): data = sys.stdin.buffer.read() data = unhex(data) - d = dict() - - rd = ByteReader(data) - - o = 0 - startbyte = rd.readbyte() - while not rd.eof(): - keylen = rd.readbyte() - keyname = rd.readbytes(keylen).decode('ascii') - if keyname in d: - print("duplicate key: %s" % keyname) - - index_or_length = rd.readdword() - if index_or_length >> 31: - d[keyname] = rd.readbytes(index_or_length & 0x7FFFFFFF) - print("%-20s - %s" % (keyname, toout(args, d[keyname]))) - else: - d[keyname] = index_or_length - print("%-20s -> %s" % (keyname, d[keyname])) + if args.type==1: + destruct_bank_definition(args, data) + elif args.type==2: + destruct_base_definition(args, data) def main(): import argparse @@ -310,7 +376,9 @@ def main(): cro.set_defaults(handler=cro_dump) des = subparsers.add_parser('destruct', help='Stru dumper') + des.add_argument('--verbose', '-v', action='store_true') des.add_argument('--ascdump', '-a', action='store_true') + des.add_argument('--type', '-t', type=int, help='what type of record to destruct') des.set_defaults(handler=destruct) args = parser.parse_args() -- cgit v1.2.3