qazmlpok

Gensokyo Tower Defense extraction

May 14th, 2012
157
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Python 4.43 KB | None | 0 0
  1. import os
  2. import sys
  3.  
  4. #Constants taken from insani tools.
  5. LITTLE_ENDIAN = 1
  6. BIG_ENDIAN = -1
  7.  
  8. BYTE_LENGTH = 1
  9. SHORT_LENGTH = 2
  10. INT_LENGTH = 4
  11. LONG_LENGTH = 8
  12.  
  13. ERROR_NONE = 0
  14. ERROR_WARNING = 1
  15. ERROR_ABORT = 2
  16.  
  17. def readbytes(infile, bytecount, key=-1):
  18.     ret = infile.read(bytecount)
  19.  
  20.     if (key != -1):
  21.         mask = int('FF' * bytecount, 16)
  22.         value = converttoint(ret, bytecount)
  23.         value = (value - key)&mask
  24.         value = (~value)&mask
  25.  
  26.         ret = convertfromint(value, bytecount)
  27.  
  28.     return ret
  29.  
  30. def converttoint(bytes, size=INT_LENGTH, endian=LITTLE_ENDIAN):
  31.     result = 0
  32.     for i in xrange(size):
  33.         temp=long(ord(bytes[i]))
  34.         if endian == LITTLE_ENDIAN :
  35.             result |= (temp << (8*i))
  36.         elif endian == BIG_ENDIAN :
  37.             result = (result << 8) | temp
  38.         else :
  39.                 raise Exception('converttoint: Unknown endian specification')
  40.  
  41.         return result
  42.  
  43. def convertfromint(value, size=INT_LENGTH, endian=LITTLE_ENDIAN):
  44.     result = ""
  45.     for i in xrange(size):
  46.         if endian == LITTLE_ENDIAN :
  47.             #result |= (temp << (8*i))
  48.             temp = (value >> (8*i)) & 0x00FF
  49.         elif endian == BIG_ENDIAN :
  50.             #result = (result << 8) | temp
  51.             temp = (value >> (8*(size-i-1))) & 0x00FF
  52.         else :
  53.                 raise Exception('convertfromint: Unknown endian specification')
  54.             result += chr(temp)
  55.  
  56.         return result
  57.  
  58. #program
  59.  
  60. files = sys.argv[1:]
  61. for filename in files:
  62.     infile = open(filename, 'rb')
  63.  
  64.     print "Reading file", filename
  65.  
  66.     #Header:
  67.     #4 bytes for the decryption key, 4 bytes for the number of files in the archive, then 8 bytes of I have no idea.
  68.  
  69.     #Decryption:
  70.     #The first byte (padded to 4) is the decryption key. This game uses subtraction/addition and binary NOT.
  71.         #To decrypt, convert the value to an int (this is done either on a 4 byte block or a single byte),
  72.         #subtract the key (values roll over, e.g. 5 - 10 = 251 on single byte)
  73.         #NOT the result (251 becomes 4)
  74.     #Then this process is reversed on encryption: NOT the value, add the key.
  75.     #Presumably any arbitrary key can be used when rebuilding the archive. Maybe even 0 (you still need to NOT it).
  76.     #The encryption applies to everything but the files and the key itself. File entries and the last 12 bytes of header are encrypted.
  77.  
  78.     decryptkey = converttoint(readbytes(infile, 4))
  79.  
  80.     filecount = converttoint(readbytes(infile, 4, decryptkey))
  81.     print "Expecting", filecount, "files. Decryption key is " + ("%02X" % decryptkey)
  82.  
  83.     #Almost certainly 2 4 byte ints. One might be a CRC. I can't be arsed to confirm this.
  84.     unk = readbytes(infile, 8, decryptkey)
  85.  
  86.     #Each file entry is
  87.     #4 bytes    2C bytes    4 bytes     4 bytes     4 bytes     4 bytes
  88.     #Filename len   Filename    Filesize    Filestart   unk     unk
  89.  
  90.     #Total of x40 bytes per entry.
  91.     #Filename is encrypted one byte at a time. Everything else is 4 bytes at a time.
  92.  
  93.     entries = []
  94.  
  95.     for i in xrange(filecount):
  96.         entry = {}
  97.         namelen = converttoint(readbytes(infile, 4, decryptkey))
  98.         nameraw = ""
  99.         for i in xrange(0x2C):
  100.             #Need to do this one byte at a time. Or write a separate function.
  101.             nameraw += readbytes(infile, 1, decryptkey)
  102.         entry['name'] = nameraw[0:namelen]
  103.         entry['filesize'] = converttoint(readbytes(infile, 4, decryptkey))
  104.         entry['filestart'] = converttoint(readbytes(infile, 4, decryptkey))
  105.         entry['unk1'] = converttoint(readbytes(infile, 4, decryptkey))      #Neither of these is a CRC.
  106.         entry['unk2'] = converttoint(readbytes(infile, 4, decryptkey))      #
  107.  
  108.         entries.append(entry)
  109.  
  110.  
  111.     #print "Current position is now %d / %X" % (infile.tell(), infile.tell())
  112.  
  113.     #for entry in entries:
  114.     #   for i in entry:
  115.     #       print i + ":", entry[i]
  116.     #   print ""
  117.  
  118.     #sys.exit(0)
  119.  
  120.     dirname = filename[0:filename.find(".")]
  121.     if not os.path.isdir(dirname):
  122.         os.mkdir(dirname)
  123.  
  124.     i = 0
  125.     for entry in entries:
  126.         filename = entry['name'].strip(" \n\t\x00")
  127.  
  128.         dirsegment, filesegment = os.path.split(filename)
  129.         #filename = os.path.join(dirsegment, ("%03d_" % i) + filesegment)       #Can be done to enforce correct order on repacking
  130.         if (not os.path.isdir(os.path.join(dirname, dirsegment))):
  131.             os.makedirs(os.path.join(dirname, dirsegment))
  132.  
  133.         infile.seek(entry['filestart'])
  134.         data = readbytes(infile, entry['filesize'])
  135.         outfile = open(os.path.join(dirname, filename), 'wb')
  136.         outfile.write(data)
  137.         outfile.close()
  138.  
  139.         print "Created file %s of size %08X from position %08X" % (filename, entry['filesize'], entry['filestart'])
  140.         #print "Unks are %08X and %08X" % (entry['unk1'], entry['unk2'])
  141.  
  142.         i += 1
  143.  
  144.     infile.close()
Advertisement
Add Comment
Please, Sign In to add comment