From 45556df05e442147a3ffa7c15e81f222868ed7c1 Mon Sep 17 00:00:00 2001 From: itsme Date: Tue, 13 Jul 2021 14:11:15 +0200 Subject: improved formating of field-def output. renamed the 'bankdump' command to 'recdump', now supports --index, --bank, --stru, --sys options. --- crodump.py | 73 ++++++++++++++++++++++++++++++++++++++++++++++---------------- 1 file changed, 54 insertions(+), 19 deletions(-) diff --git a/crodump.py b/crodump.py index d0cd67c..af4dc36 100644 --- a/crodump.py +++ b/crodump.py @@ -90,6 +90,8 @@ class Datafile: """ extract and decode a single record. """ + if idx==0: + raise Exception("recnum must be a positive number") ofs, ln, chk = self.tadidx[idx-1] if ln==0xFFFFFFFF: # deleted record @@ -239,7 +241,7 @@ def decode_field(data): unk4 = rd.readdword() # Always 0x00000009 or 0x0001000d remain = rd.readbytes() - print("Type: %2d (%2d/%2d) %04x,(%d-%4d),%04x - '%s' -- %s" % (typ, idx1, idx2, unk1, unk2, unk3, unk4, name, tohex(remain))) + print("Type: %2d (%2d/%2d) %04x,(%d-%4d),%04x - %-40s -- %s" % (typ, idx1, idx2, unk1, unk2, unk3, unk4, "'%s'" % name, tohex(remain))) else: print("Type: %2d %2d %d,%d - '%s'" % (typ, idx1, unk1, unk2, name)) @@ -402,6 +404,13 @@ class Database: return d def dumptabledefs(self, args): + """ + decode the table defs from recid #1, which always has table-id #3 + Note that I don't know if it is better to refer to this by recid, or by table-id. + + other table-id's found in CroStru: + #4 -> large values referenced from tableid#3 + """ dbinfo = self.stru.readrec(1) if dbinfo[:1] != b"\x03": print("WARN: expected dbinfo to start with 0x03") @@ -413,18 +422,30 @@ class Database: print("== %s ==" % k) tbdef = destruct_base_definition(args, v) - def bankdump(self, args): - if not self.bank: - print("No CroBank.dat found") + def recdump(self, args): + if args.index: + db = self.index + elif args.sys: + db = self.sys + elif args.stru: + db = self.stru + else: + db = self.bank + + if not db: + print(".dat not found") return - if args.skipencrypted and self.bank.encoding==3: + if args.skipencrypted and db.encoding==3: print("Skipping encrypted CroBank") return nerr = 0 - xref = defaultdict(int) - for i in range(args.maxrecs): + nr_recnone = 0 + nr_recempty = 0 + tabidxref = [0] * 256 + bytexref = [0] * 256 + for i in range(1, args.maxrecs+1): try: - data = self.bank.readrec(i) + data = db.readrec(i) if args.find1d: if data and (data.find(b"\x1d")>0 or data.find(b"\x1b")>0): print("%d -> %s" % (i, b2a_hex(data))) @@ -437,23 +458,32 @@ class Database: print("%5d: %s" % (i, toout(args, data))) else: if data is None: - xref["None"] += 1 + nr_recnone += 1 elif not len(data): - xref["Empty"] += 1 + nr_recempty += 1 else: - xref["%02x" % data[0]] += 1 + tabidxref[data[0]] += 1 + for b in data[1:]: + bytexref[b] += 1 nerr = 0 except IndexError: break except Exception as e: print("%5d: <%s>" % (i, e)) + if args.debug: + raise nerr += 1 if nerr > 5: break if args.stats: - print("-- stats --") - for k, v in xref.items(): - print("%5d * %s" % (v, k)) + print("-- table-id stats --, %d * none, %d * empty" % (nr_recnone, nr_recempty)) + for k, v in enumerate(tabidxref): + if v: + print("%5d * %02x" % (v, k)) + print("-- byte stats --") + for k, v in enumerate(bytexref): + if v: + print("%5d * %02x" % (v, k)) def readrec(self, sysnum): data = self.bank.readrec(sysnum) @@ -543,8 +573,8 @@ def sys_dump(args): if db.sys: db.sys.dump(args) -def bank_dump(args): - """ hexdump all records """ +def rec_dump(args): + """ hexdump all records of the specified CroXXX.dat file. """ if args.maxrecs: args.maxrecs = int(args.maxrecs, 0) else: @@ -552,7 +582,7 @@ def bank_dump(args): args.maxrecs = 0xFFFFFFFF db = Database(args.dbdir) - db.bankdump(args) + db.recdump(args) def destruct(args): """ @@ -575,6 +605,7 @@ def main(): parser = argparse.ArgumentParser(description='CRO hexdumper') subparsers = parser.add_subparsers() parser.set_defaults(handler=None) + parser.add_argument('--debug', action='store_true', help='break on exceptions') ko = subparsers.add_parser('kodump', help='KOD/hex dumper') ko.add_argument('--offset', '-o', type=str, default="0") @@ -606,15 +637,19 @@ def main(): p.set_defaults(handler=sys_dump) - p = subparsers.add_parser('bankdump', help='BANKdumper') + p = subparsers.add_parser('recdump', help='record dumper') p.add_argument('--verbose', '-v', action='store_true') p.add_argument('--ascdump', '-a', action='store_true') p.add_argument('--maxrecs', '-n', type=str, help="max nr or recots to output") p.add_argument('--find1d', action='store_true') p.add_argument('--inclencrypted', action='store_false', dest='skipencrypted', default='true', help='include encrypted records in the output') p.add_argument('--stats', action='store_true', help='calc table stats from the first byte of each record') + p.add_argument('--index', action='store_true', help='dump CroIndex') + p.add_argument('--stru', action='store_true', help='dump CroIndex') + p.add_argument('--bank', action='store_true', help='dump CroBank') + p.add_argument('--sys', action='store_true', help='dump CroSys') p.add_argument('dbdir', type=str) - p.set_defaults(handler=bank_dump) + p.set_defaults(handler=rec_dump) p = subparsers.add_parser('strudump', help='STRUdumper') p.add_argument('--verbose', '-v', action='store_true') -- cgit v1.2.3