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') |
