Differences between revisions 1 and 2
Revision 1 as of 2018-05-13 00:43:06
Size: 2472
Editor: weh
Comment:
Revision 2 as of 2018-05-13 02:14:47
Size: 2746
Editor: weh
Comment:
Deletions are marked like this. Additions are marked like this.
Line 4: Line 4:
#!python
Line 10: Line 11:
        print(f"decompressing {fname}")
Line 21: Line 23:
                 with open(fname.replace(".cst", "")+".bin", "wb") as f2:
            f2.write(fdata)
Line 67: Line 72:
            elif op in [0x03]: # some other kind of linefeed (grisaia)
                print("")
                i += 1
Line 68: Line 76:
                print(f"unknown op {op:02X} at {i+headerlen+0x10:08X} in {fname}")                 print(f"\n\nunknown op {op:02X} at {i+headerlen+0x10:08X} in {fname}\n")
Line 70: Line 78:
        print("")                      print("")

Invoke on something like dump/*.cst. Needs regex postprocessing, as is common.

   1 #!python
   2 
   3 import os, sys, zlib
   4 from struct import unpack
   5 
   6 for fname in sys.argv[1:]:
   7     with open(fname, "rb") as f:
   8         print(f"decompressing {fname}")
   9         fdata = f.read()
  10         
  11         header = fdata[:8].decode("utf-8")
  12         if header != "CatScene":
  13             continue
  14         
  15         compressed_len = unpack("<I", bytes(fdata[0x08:0x0C]))[0]
  16         decompressed_len = unpack("<I", bytes(fdata[0x0C:0x10]))[0]
  17         
  18         decompressed = zlib.decompress(bytes(fdata[0x10:compressed_len+0x10]))
  19         fdata = decompressed
  20         
  21         with open(fname.replace(".cst", "")+".bin", "wb") as f2:
  22             f2.write(fdata)
  23         
  24         flen          = unpack("<I", bytes(fdata[0x00:0x04]))[0]
  25         ranges        = unpack("<I", bytes(fdata[0x04:0x08]))[0]
  26         ranges_bytes  = unpack("<I", bytes(fdata[0x08:0x0C]))[0]
  27         headerlen     = unpack("<I", bytes(fdata[0x0C:0x10]))[0]
  28         
  29         # header structure is something like
  30         # uint32 filelen
  31         # uint32 num_ranges
  32         # uint32 len_ranges_bytes
  33         # uint32 len_header_bytes (excluding these first four words)
  34         
  35         # struct[num_ranges] {uint32, uint32} // where first is length of range, second is index of range
  36         # uint32[entries] // indexed into by ranges
  37         # with this part (the two arrays together) being len_header_bytes bytes long
  38         
  39         # we don't actually need any of that for just script ripping
  40         
  41         code = fdata[headerlen+0x10:]
  42         
  43         i = 0
  44         while len(code[i:]) > 0:
  45             # guess
  46             oplen = code[i]
  47             if oplen != 1:
  48                 print("oplen error")
  49                 exit()
  50             i += 1
  51             
  52             op = code[i]
  53             i += 1
  54             if op in [0x20, 0x21, 0x30]:
  55                 string = []
  56                 char = code[i]
  57                 while char != 0:
  58                     string += [char]
  59                     i += 1
  60                     char = code[i]
  61                 i += 1
  62                 string = bytes(string).decode("cp932")
  63                 
  64                 if op == 0x20:
  65                     print(string.replace("\n", "").replace("\\n",""), end="")
  66             elif op in [0x02]: # linefeed
  67                 print("")
  68                 i += 1
  69             elif op in [0x03]: # some other kind of linefeed (grisaia)
  70                 print("")
  71                 i += 1
  72             else:
  73                 print(f"\n\nunknown op {op:02X} at {i+headerlen+0x10:08X} in {fname}\n")
  74                 exit()
  75         print("")

CatSystem2 (last edited 2018-05-13 02:17:11 by weh)