diff options
| author | itsme <itsme@xs4all.nl> | 2021-07-06 19:26:42 +0200 |
|---|---|---|
| committer | itsme <itsme@xs4all.nl> | 2021-07-06 19:26:42 +0200 |
| commit | a9886b9d52c3bce0a4b58805b5597efccc55225a (patch) | |
| tree | 4133e30e57109385ade3f756970058fe1edac255 /crodump.py | |
initial commit
Diffstat (limited to 'crodump.py')
| -rw-r--r-- | crodump.py | 160 |
1 files changed, 160 insertions, 0 deletions
diff --git a/crodump.py b/crodump.py new file mode 100644 index 0000000..a2a94a1 --- /dev/null +++ b/crodump.py | |||
| @@ -0,0 +1,160 @@ | |||
| 1 | import os.path | ||
| 2 | import struct | ||
| 3 | from binascii import b2a_hex | ||
| 4 | from hexdump import hexdump, asasc, tohex | ||
| 5 | from koddecoder import kodecode | ||
| 6 | """ | ||
| 7 | python3 crodump.py crodump chechnya_proverki_ul_2012 | ||
| 8 | python3 crodump.py kodump -s 6 -o 0x4cc9 -e 0x5d95 chechnya_proverki_ul_2012/CroStru.dat | ||
| 9 | """ | ||
| 10 | |||
| 11 | class Datafile: | ||
| 12 | def __init__(self, dat, tad): | ||
| 13 | self.dat = dat | ||
| 14 | self.tad = tad | ||
| 15 | |||
| 16 | self.readtad() | ||
| 17 | |||
| 18 | def readtad(self): | ||
| 19 | self.tad.seek(0) | ||
| 20 | hdrdata = self.tad.read(2*4) | ||
| 21 | self.tadhdr = struct.unpack("<2L", hdrdata) | ||
| 22 | indexdata = self.tad.read() | ||
| 23 | self.tadidx = [ struct.unpack_from("<3L", indexdata, 12*_) for _ in range(len(indexdata)//12) ] | ||
| 24 | |||
| 25 | def readdata(self, ofs, size): | ||
| 26 | self.dat.seek(ofs) | ||
| 27 | return self.dat.read(size) | ||
| 28 | |||
| 29 | def dump(self, args, dokodecode=False, plainbytes=0): | ||
| 30 | print("tadhdr: %08x %08x" % tuple(self.tadhdr)) | ||
| 31 | for i, (ofs, ln, chk) in enumerate(self.tadidx): | ||
| 32 | if ln==0xFFFFFFFF: | ||
| 33 | print("%5d: %08x %08x %08x" % (i, ofs, ln, chk)) | ||
| 34 | continue | ||
| 35 | flags = ln>>24 | ||
| 36 | ln &= 0xFFFFFFF | ||
| 37 | dat = self.readdata(ofs, ln) | ||
| 38 | plain = b'' | ||
| 39 | if dokodecode and not args.nokod: | ||
| 40 | plain = dat[:plainbytes] | ||
| 41 | dat = kodecode(i+1, dat[plainbytes:]) | ||
| 42 | if args.ascdump: | ||
| 43 | print("%5d: %08x-%08x: (%02x:%08x) %s %s" % (i, ofs, ofs+ln, flags, chk, tohex(plain), asasc(dat))) | ||
| 44 | else: | ||
| 45 | print("%5d: %08x-%08x: (%02x:%08x) %s %s" % (i, ofs, ofs+ln, flags, chk, tohex(plain), tohex(dat))) | ||
| 46 | |||
| 47 | class Database: | ||
| 48 | def __init__(self, dbdir): | ||
| 49 | self.dbdir = dbdir | ||
| 50 | |||
| 51 | self.stru = self.getfile("Stru") | ||
| 52 | self.index = self.getfile("Index") | ||
| 53 | self.bank = self.getfile("Bank") | ||
| 54 | self.sys = self.getfile("Sys") | ||
| 55 | |||
| 56 | def getfile(self, name): | ||
| 57 | try: | ||
| 58 | return Datafile(open(self.getname(name, "dat"), "rb"), open(self.getname(name, "tad"), "rb")) | ||
| 59 | except IOError: | ||
| 60 | return | ||
| 61 | |||
| 62 | def getname(self, name, ext): | ||
| 63 | return os.path.join(self.dbdir, "Cro%s.%s" % (name, ext)) | ||
| 64 | |||
| 65 | |||
| 66 | def decode_kod(args, data): | ||
| 67 | """ | ||
| 68 | various methods of hexdumping KOD decoded data. | ||
| 69 | """ | ||
| 70 | if args.nokod: | ||
| 71 | # plain hexdump, no KOD decode | ||
| 72 | hexdump(args.offset, data) | ||
| 73 | elif args.shift: | ||
| 74 | # explicitly specified shift. | ||
| 75 | args.shift = int(args.shift, 0) | ||
| 76 | enc = kodecode(args.shift, data) | ||
| 77 | hexdump(args.offset, enc) | ||
| 78 | else: | ||
| 79 | # output with all possible 'shift' values. | ||
| 80 | for s in range(256): | ||
| 81 | enc = kodecode(s, data) | ||
| 82 | if args.ascdump: | ||
| 83 | print("%02x: %s" % (s, asasc(enc))) | ||
| 84 | else: | ||
| 85 | print("%02x: %s" % (s, tohex(enc))) | ||
| 86 | |||
| 87 | |||
| 88 | |||
| 89 | def kod_hexdump(args): | ||
| 90 | """ | ||
| 91 | KOD decode a section of a data file | ||
| 92 | """ | ||
| 93 | args.offset = int(args.offset, 0) | ||
| 94 | if args.length: | ||
| 95 | args.length = int(args.length, 0) | ||
| 96 | elif args.endofs: | ||
| 97 | args.endofs = int(args.endofs, 0) | ||
| 98 | args.length = args.endofs - args.offset | ||
| 99 | |||
| 100 | if args.filename: | ||
| 101 | with open(args.filename, "rb") as fh: | ||
| 102 | fh.seek(args.offset) | ||
| 103 | data = fh.read(args.length) | ||
| 104 | decode_kod(args, data) | ||
| 105 | else: | ||
| 106 | # no filename -> read from stdin. | ||
| 107 | import sys | ||
| 108 | data = sys.stdin.buffer.read() | ||
| 109 | decode_kod(args, data) | ||
| 110 | |||
| 111 | |||
| 112 | def cro_dump(args): | ||
| 113 | db = Database(args.dbdir) | ||
| 114 | |||
| 115 | if db.stru: | ||
| 116 | print("stru") | ||
| 117 | db.stru.dump(args, dokodecode=True) | ||
| 118 | if db.index: | ||
| 119 | print("index") | ||
| 120 | db.index.dump(args) | ||
| 121 | if db.bank: | ||
| 122 | print("bank") | ||
| 123 | db.bank.dump(args) | ||
| 124 | if db.sys: | ||
| 125 | print("sys") | ||
| 126 | db.sys.dump(args, dokodecode=True, plainbytes=8) | ||
| 127 | |||
| 128 | |||
| 129 | def main(): | ||
| 130 | import argparse | ||
| 131 | parser = argparse.ArgumentParser(description='CRO hexdumper') | ||
| 132 | subparsers = parser.add_subparsers() | ||
| 133 | parser.set_defaults(handler=None) | ||
| 134 | |||
| 135 | ko = subparsers.add_parser('kodump', help='KOD dumper') | ||
| 136 | ko.add_argument('--offset', '-o', type=str, default="0") | ||
| 137 | ko.add_argument('--length', '-l', type=str) | ||
| 138 | ko.add_argument('--endofs', '-e', type=str) | ||
| 139 | ko.add_argument('--shift', '-s', type=str) | ||
| 140 | ko.add_argument('--ascdump', '-a', action='store_true') | ||
| 141 | ko.add_argument('--nokod', '-n', action='store_true') | ||
| 142 | ko.add_argument('filename', type=str, nargs='?') | ||
| 143 | ko.set_defaults(handler=kod_hexdump) | ||
| 144 | |||
| 145 | cro = subparsers.add_parser('crodump', help='CROdumper') | ||
| 146 | cro.add_argument('--kodecode', '-k', action='store_true') | ||
| 147 | cro.add_argument('--ascdump', '-a', action='store_true') | ||
| 148 | cro.add_argument('--nokod', '-n', action='store_true') | ||
| 149 | cro.add_argument('dbdir', type=str) | ||
| 150 | cro.set_defaults(handler=cro_dump) | ||
| 151 | |||
| 152 | args = parser.parse_args() | ||
| 153 | |||
| 154 | if args.handler: | ||
| 155 | args.handler(args) | ||
| 156 | |||
| 157 | |||
| 158 | if __name__=='__main__': | ||
| 159 | main() | ||
| 160 | |||
