diff options
Diffstat (limited to 'crodump.py')
-rw-r--r-- | crodump.py | 56 |
1 files changed, 46 insertions, 10 deletions
@@ -87,6 +87,9 @@ class Datafile: | |||
87 | return self.dat.read(size) | 87 | return self.dat.read(size) |
88 | 88 | ||
89 | def readrec(self, idx): | 89 | def readrec(self, idx): |
90 | """ | ||
91 | extract and decode a single record. | ||
92 | """ | ||
90 | ofs, ln, chk = self.tadidx[idx-1] | 93 | ofs, ln, chk = self.tadidx[idx-1] |
91 | if ln==0xFFFFFFFF: | 94 | if ln==0xFFFFFFFF: |
92 | # deleted record | 95 | # deleted record |
@@ -120,6 +123,9 @@ class Datafile: | |||
120 | 123 | ||
121 | 124 | ||
122 | def dump(self, args): | 125 | def dump(self, args): |
126 | """ | ||
127 | dump decodes all references data, and optionally will print out all unused bytes in the .dat file. | ||
128 | """ | ||
123 | print("hdr: %-6s dat: %04x %s enc:%04x bs:%04x, tad: %08x %08x" % (self.name, self.hdrunk, self.version, self.encoding, self.blocksize, self.nrdeleted, self.firstdeleted)) | 129 | print("hdr: %-6s dat: %04x %s enc:%04x bs:%04x, tad: %08x %08x" % (self.name, self.hdrunk, self.version, self.encoding, self.blocksize, self.nrdeleted, self.firstdeleted)) |
124 | ranges = [] # keep track of used bytes in the .dat file. | 130 | ranges = [] # keep track of used bytes in the .dat file. |
125 | for i, (ofs, ln, chk) in enumerate(self.tadidx): | 131 | for i, (ofs, ln, chk) in enumerate(self.tadidx): |
@@ -183,20 +189,31 @@ class Datafile: | |||
183 | print("%08x-%08x: %s" % (o, o+l, toout(args, dat))) | 189 | print("%08x-%08x: %s" % (o, o+l, toout(args, dat))) |
184 | 190 | ||
185 | def iscompressed(self, data): | 191 | def iscompressed(self, data): |
192 | """ | ||
193 | Note that the compression header uses big-endian numbers. | ||
194 | """ | ||
186 | if len(data)<11: | 195 | if len(data)<11: |
187 | return | 196 | return |
188 | size, flag = struct.unpack_from(">HH", data, 0) | ||
189 | if size+5 != len(data): | ||
190 | return | ||
191 | if flag!=0x800: | ||
192 | return | ||
193 | if data[-3:] != b"\x00\x00\x02": | 197 | if data[-3:] != b"\x00\x00\x02": |
194 | return | 198 | return |
199 | o = 0 | ||
200 | while o < len(data)-3: | ||
201 | size, flag = struct.unpack_from(">HH", data, o) | ||
202 | if flag!=0x800 and flag!=0x008: | ||
203 | return | ||
204 | o += size + 2 | ||
195 | return True | 205 | return True |
196 | 206 | ||
197 | def decompress(self, data): | 207 | def decompress(self, data): |
198 | C = zlib.decompressobj(-15) | 208 | result = b"" |
199 | return C.decompress(data[8:-3]) | 209 | o = 0 |
210 | while o < len(data)-3: | ||
211 | size, flag, crc = struct.unpack_from(">HHL", data, o) | ||
212 | C = zlib.decompressobj(-15) | ||
213 | result += C.decompress(data[o+8:o+8+size]) | ||
214 | o += size + 2 | ||
215 | return result | ||
216 | |||
200 | 217 | ||
201 | def dump_bank_definition(args, bankdict): | 218 | def dump_bank_definition(args, bankdict): |
202 | """ | 219 | """ |
@@ -222,9 +239,9 @@ def decode_field(data): | |||
222 | unk4 = rd.readdword() # Always 0x00000009 or 0x0001000d | 239 | unk4 = rd.readdword() # Always 0x00000009 or 0x0001000d |
223 | remain = rd.readbytes() | 240 | remain = rd.readbytes() |
224 | 241 | ||
225 | print("Type: %d (%02d/%02d) %04x,(%d-%d),%04x - '%s' -- %s" % (typ, idx1, idx2, unk1, unk2, unk3, unk4, name, tohex(remain))) | 242 | print("Type: %2d (%2d/%2d) %04x,(%d-%4d),%04x - '%s' -- %s" % (typ, idx1, idx2, unk1, unk2, unk3, unk4, name, tohex(remain))) |
226 | else: | 243 | else: |
227 | print("Type: %d %2d %d,%d - '%s'" % (typ, idx1, unk1, unk2, name)) | 244 | print("Type: %2d %2d %d,%d - '%s'" % (typ, idx1, unk1, unk2, name)) |
228 | 245 | ||
229 | """ | 246 | """ |
230 | 2 Base000 - 000001 050001 000000000000000546696c657302464c01000000010000001b000000000000000fd1e8f1f2e5ecedfbe920edeeece5f0010000000000000000010000000000000000 | 247 | 2 Base000 - 000001 050001 000000000000000546696c657302464c01000000010000001b000000000000000fd1e8f1f2e5ecedfbe920edeeece5f0010000000000000000010000000000000000 |
@@ -272,7 +289,11 @@ def destruct_base_definition(args, data): | |||
272 | abbrev = rd.readname() | 289 | abbrev = rd.readname() |
273 | unk7 = rd.readdword() | 290 | unk7 = rd.readdword() |
274 | nrfields = rd.readdword() | 291 | nrfields = rd.readdword() |
292 | |||
293 | if args.verbose: | ||
294 | print("table: %s" % tohex(data[:rd.o])) | ||
275 | print("%d,%d,%d,%d,%d,%d %d,%d '%s' '%s'" % (unk1, version, unk2, unk3, unk4, unk5, unk7, nrfields, tablename, abbrev)) | 295 | print("%d,%d,%d,%d,%d,%d %d,%d '%s' '%s'" % (unk1, version, unk2, unk3, unk4, unk5, unk7, nrfields, tablename, abbrev)) |
296 | |||
276 | fields = [] | 297 | fields = [] |
277 | for _ in range(nrfields): | 298 | for _ in range(nrfields): |
278 | l = rd.readword() | 299 | l = rd.readword() |
@@ -396,12 +417,20 @@ class Database: | |||
396 | if not self.bank: | 417 | if not self.bank: |
397 | print("No CroBank.dat found") | 418 | print("No CroBank.dat found") |
398 | return | 419 | return |
420 | if args.skipencrypted and self.bank.encoding==3: | ||
421 | print("Skipping encrypted CroBank") | ||
422 | return | ||
399 | nerr = 0 | 423 | nerr = 0 |
400 | xref = defaultdict(int) | 424 | xref = defaultdict(int) |
401 | for i in range(args.maxrecs): | 425 | for i in range(args.maxrecs): |
402 | try: | 426 | try: |
403 | data = self.bank.readrec(i) | 427 | data = self.bank.readrec(i) |
404 | if not args.stats: | 428 | if args.find1d: |
429 | if data and (data.find(b"\x1d")>0 or data.find(b"\x1b")>0): | ||
430 | print("%d -> %s" % (i, b2a_hex(data))) | ||
431 | break | ||
432 | |||
433 | elif not args.stats: | ||
405 | if data is None: | 434 | if data is None: |
406 | print("%5d: <deleted>" % i) | 435 | print("%5d: <deleted>" % i) |
407 | else: | 436 | else: |
@@ -426,6 +455,11 @@ class Database: | |||
426 | for k, v in xref.items(): | 455 | for k, v in xref.items(): |
427 | print("%5d * %s" % (v, k)) | 456 | print("%5d * %s" % (v, k)) |
428 | 457 | ||
458 | def readrec(self, sysnum): | ||
459 | data = self.bank.readrec(sysnum) | ||
460 | tabnum, = struct.unpack_from("<B", data, 0) | ||
461 | fields = data[1:].split(b"\x1e") | ||
462 | |||
429 | def incdata(data, s): | 463 | def incdata(data, s): |
430 | """ | 464 | """ |
431 | add 's' to each byte. | 465 | add 's' to each byte. |
@@ -576,6 +610,8 @@ def main(): | |||
576 | p.add_argument('--verbose', '-v', action='store_true') | 610 | p.add_argument('--verbose', '-v', action='store_true') |
577 | p.add_argument('--ascdump', '-a', action='store_true') | 611 | p.add_argument('--ascdump', '-a', action='store_true') |
578 | p.add_argument('--maxrecs', '-n', type=str, help="max nr or recots to output") | 612 | p.add_argument('--maxrecs', '-n', type=str, help="max nr or recots to output") |
613 | 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') | ||
579 | p.add_argument('--stats', action='store_true', help='calc table stats from the first byte of each record') | 615 | p.add_argument('--stats', action='store_true', help='calc table stats from the first byte of each record') |
580 | p.add_argument('dbdir', type=str) | 616 | p.add_argument('dbdir', type=str) |
581 | p.set_defaults(handler=bank_dump) | 617 | p.set_defaults(handler=bank_dump) |