diff options
author | itsme <itsme@xs4all.nl> | 2021-07-13 14:11:15 +0200 |
---|---|---|
committer | itsme <itsme@xs4all.nl> | 2021-07-13 14:11:28 +0200 |
commit | 45556df05e442147a3ffa7c15e81f222868ed7c1 (patch) | |
tree | f0e6542cd3dd21e8447ef89e79e1b2698154338d | |
parent | 543c1b54d67b7ff45296e6ae5571ad1f85b3e946 (diff) |
improved formating of field-def output. renamed the 'bankdump' command to 'recdump', now supports --index, --bank, --stru, --sys options.
-rw-r--r-- | crodump.py | 73 |
1 files changed, 54 insertions, 19 deletions
@@ -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 | ||
546 | def bank_dump(args): | 576 | def 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 | ||
557 | def destruct(args): | 587 | def 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') |