summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--crodump.py73
1 files 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:
90 """ 90 """
91 extract and decode a single record. 91 extract and decode a single record.
92 """ 92 """
93 if idx==0:
94 raise Exception("recnum must be a positive number")
93 ofs, ln, chk = self.tadidx[idx-1] 95 ofs, ln, chk = self.tadidx[idx-1]
94 if ln==0xFFFFFFFF: 96 if ln==0xFFFFFFFF:
95 # deleted record 97 # deleted record
@@ -239,7 +241,7 @@ def decode_field(data):
239 unk4 = rd.readdword() # Always 0x00000009 or 0x0001000d 241 unk4 = rd.readdword() # Always 0x00000009 or 0x0001000d
240 remain = rd.readbytes() 242 remain = rd.readbytes()
241 243
242 print("Type: %2d (%2d/%2d) %04x,(%d-%4d),%04x - '%s' -- %s" % (typ, idx1, idx2, unk1, unk2, unk3, unk4, name, tohex(remain))) 244 print("Type: %2d (%2d/%2d) %04x,(%d-%4d),%04x - %-40s -- %s" % (typ, idx1, idx2, unk1, unk2, unk3, unk4, "'%s'" % name, tohex(remain)))
243 else: 245 else:
244 print("Type: %2d %2d %d,%d - '%s'" % (typ, idx1, unk1, unk2, name)) 246 print("Type: %2d %2d %d,%d - '%s'" % (typ, idx1, unk1, unk2, name))
245 247
@@ -402,6 +404,13 @@ class Database:
402 return d 404 return d
403 405
404 def dumptabledefs(self, args): 406 def dumptabledefs(self, args):
407 """
408 decode the table defs from recid #1, which always has table-id #3
409 Note that I don't know if it is better to refer to this by recid, or by table-id.
410
411 other table-id's found in CroStru:
412 #4 -> large values referenced from tableid#3
413 """
405 dbinfo = self.stru.readrec(1) 414 dbinfo = self.stru.readrec(1)
406 if dbinfo[:1] != b"\x03": 415 if dbinfo[:1] != b"\x03":
407 print("WARN: expected dbinfo to start with 0x03") 416 print("WARN: expected dbinfo to start with 0x03")
@@ -413,18 +422,30 @@ class Database:
413 print("== %s ==" % k) 422 print("== %s ==" % k)
414 tbdef = destruct_base_definition(args, v) 423 tbdef = destruct_base_definition(args, v)
415 424
416 def bankdump(self, args): 425 def recdump(self, args):
417 if not self.bank: 426 if args.index:
418 print("No CroBank.dat found") 427 db = self.index
428 elif args.sys:
429 db = self.sys
430 elif args.stru:
431 db = self.stru
432 else:
433 db = self.bank
434
435 if not db:
436 print(".dat not found")
419 return 437 return
420 if args.skipencrypted and self.bank.encoding==3: 438 if args.skipencrypted and db.encoding==3:
421 print("Skipping encrypted CroBank") 439 print("Skipping encrypted CroBank")
422 return 440 return
423 nerr = 0 441 nerr = 0
424 xref = defaultdict(int) 442 nr_recnone = 0
425 for i in range(args.maxrecs): 443 nr_recempty = 0
444 tabidxref = [0] * 256
445 bytexref = [0] * 256
446 for i in range(1, args.maxrecs+1):
426 try: 447 try:
427 data = self.bank.readrec(i) 448 data = db.readrec(i)
428 if args.find1d: 449 if args.find1d:
429 if data and (data.find(b"\x1d")>0 or data.find(b"\x1b")>0): 450 if data and (data.find(b"\x1d")>0 or data.find(b"\x1b")>0):
430 print("%d -> %s" % (i, b2a_hex(data))) 451 print("%d -> %s" % (i, b2a_hex(data)))
@@ -437,23 +458,32 @@ class Database:
437 print("%5d: %s" % (i, toout(args, data))) 458 print("%5d: %s" % (i, toout(args, data)))
438 else: 459 else:
439 if data is None: 460 if data is None:
440 xref["None"] += 1 461 nr_recnone += 1
441 elif not len(data): 462 elif not len(data):
442 xref["Empty"] += 1 463 nr_recempty += 1
443 else: 464 else:
444 xref["%02x" % data[0]] += 1 465 tabidxref[data[0]] += 1
466 for b in data[1:]:
467 bytexref[b] += 1
445 nerr = 0 468 nerr = 0
446 except IndexError: 469 except IndexError:
447 break 470 break
448 except Exception as e: 471 except Exception as e:
449 print("%5d: <%s>" % (i, e)) 472 print("%5d: <%s>" % (i, e))
473 if args.debug:
474 raise
450 nerr += 1 475 nerr += 1
451 if nerr > 5: 476 if nerr > 5:
452 break 477 break
453 if args.stats: 478 if args.stats:
454 print("-- stats --") 479 print("-- table-id stats --, %d * none, %d * empty" % (nr_recnone, nr_recempty))
455 for k, v in xref.items(): 480 for k, v in enumerate(tabidxref):
456 print("%5d * %s" % (v, k)) 481 if v:
482 print("%5d * %02x" % (v, k))
483 print("-- byte stats --")
484 for k, v in enumerate(bytexref):
485 if v:
486 print("%5d * %02x" % (v, k))
457 487
458 def readrec(self, sysnum): 488 def readrec(self, sysnum):
459 data = self.bank.readrec(sysnum) 489 data = self.bank.readrec(sysnum)
@@ -543,8 +573,8 @@ def sys_dump(args):
543 if db.sys: 573 if db.sys:
544 db.sys.dump(args) 574 db.sys.dump(args)
545 575
546def bank_dump(args): 576def rec_dump(args):
547 """ hexdump all records """ 577 """ hexdump all records of the specified CroXXX.dat file. """
548 if args.maxrecs: 578 if args.maxrecs:
549 args.maxrecs = int(args.maxrecs, 0) 579 args.maxrecs = int(args.maxrecs, 0)
550 else: 580 else:
@@ -552,7 +582,7 @@ def bank_dump(args):
552 args.maxrecs = 0xFFFFFFFF 582 args.maxrecs = 0xFFFFFFFF
553 583
554 db = Database(args.dbdir) 584 db = Database(args.dbdir)
555 db.bankdump(args) 585 db.recdump(args)
556 586
557def destruct(args): 587def destruct(args):
558 """ 588 """
@@ -575,6 +605,7 @@ def main():
575 parser = argparse.ArgumentParser(description='CRO hexdumper') 605 parser = argparse.ArgumentParser(description='CRO hexdumper')
576 subparsers = parser.add_subparsers() 606 subparsers = parser.add_subparsers()
577 parser.set_defaults(handler=None) 607 parser.set_defaults(handler=None)
608 parser.add_argument('--debug', action='store_true', help='break on exceptions')
578 609
579 ko = subparsers.add_parser('kodump', help='KOD/hex dumper') 610 ko = subparsers.add_parser('kodump', help='KOD/hex dumper')
580 ko.add_argument('--offset', '-o', type=str, default="0") 611 ko.add_argument('--offset', '-o', type=str, default="0")
@@ -606,15 +637,19 @@ def main():
606 p.set_defaults(handler=sys_dump) 637 p.set_defaults(handler=sys_dump)
607 638
608 639
609 p = subparsers.add_parser('bankdump', help='BANKdumper') 640 p = subparsers.add_parser('recdump', help='record dumper')
610 p.add_argument('--verbose', '-v', action='store_true') 641 p.add_argument('--verbose', '-v', action='store_true')
611 p.add_argument('--ascdump', '-a', action='store_true') 642 p.add_argument('--ascdump', '-a', action='store_true')
612 p.add_argument('--maxrecs', '-n', type=str, help="max nr or recots to output") 643 p.add_argument('--maxrecs', '-n', type=str, help="max nr or recots to output")
613 p.add_argument('--find1d', action='store_true') 644 p.add_argument('--find1d', action='store_true')
614 p.add_argument('--inclencrypted', action='store_false', dest='skipencrypted', default='true', help='include encrypted records in the output') 645 p.add_argument('--inclencrypted', action='store_false', dest='skipencrypted', default='true', help='include encrypted records in the output')
615 p.add_argument('--stats', action='store_true', help='calc table stats from the first byte of each record') 646 p.add_argument('--stats', action='store_true', help='calc table stats from the first byte of each record')
647 p.add_argument('--index', action='store_true', help='dump CroIndex')
648 p.add_argument('--stru', action='store_true', help='dump CroIndex')
649 p.add_argument('--bank', action='store_true', help='dump CroBank')
650 p.add_argument('--sys', action='store_true', help='dump CroSys')
616 p.add_argument('dbdir', type=str) 651 p.add_argument('dbdir', type=str)
617 p.set_defaults(handler=bank_dump) 652 p.set_defaults(handler=rec_dump)
618 653
619 p = subparsers.add_parser('strudump', help='STRUdumper') 654 p = subparsers.add_parser('strudump', help='STRUdumper')
620 p.add_argument('--verbose', '-v', action='store_true') 655 p.add_argument('--verbose', '-v', action='store_true')