diff options
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 | |||