Advertisement
Guest User

Falcom Decompress v2

a guest
Aug 31st, 2016
549
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Python 6.13 KB | None | 0 0
  1. import io
  2. import pdb
  3. import struct
  4.  
  5. def decompress_FALCOM3(indata):
  6.     global infilestream, outfilestream          #Other functions need access
  7.     infilestream = io.BytesIO(indata)
  8.     outfilestream = io.BytesIO()
  9.     compressed_size = struct.unpack('<I', infilestream.read(4))[0]
  10.     uncompressed_size = struct.unpack('<I', infilestream.read(4))[0]
  11.     chunks = struct.unpack('<I', infilestream.read(4))[0]
  12.     for x in range(chunks):
  13.         chunk_size = struct.unpack('<H', infilestream.read(2))[0]
  14.         decompress(infilestream, outfilestream)
  15.         if ord(infilestream.read(1)) == 0:
  16.             break
  17.         if outfilestream.tell() >= uncompressed_size:
  18.             break
  19.     outfilestream.seek(0)
  20.     return outfilestream.read()
  21. def decompress_FALCOM2(indata):
  22.     global infilestream, outfilestream          #Other functions need access
  23.     infilestream = io.BytesIO(indata)
  24.     outfilestream = io.BytesIO()
  25.     decompress(infilestream, outfilestream)
  26.     outfilestream.seek(0)
  27.     return outfilestream.read()
  28. def decompress_FALCOM2_1(indata):
  29.     global infilestream, outfilestream          #Other functions need access
  30.     infilestream = io.BytesIO(indata)
  31.     outfilestream = io.BytesIO()
  32.     while True:
  33.         size = struct.unpack('<H', infilestream.read(2))
  34.         decompress(infilestream, outfilestream)
  35.         flag = ord(infilestream.read(1))
  36.         if flag == 0:
  37.             break
  38.     outfilestream.seek(0)
  39.     return outfilestream.read()
  40. def _getflag(f):
  41.     bits = 8    #8 to start off with, then 16
  42.     flags = struct.unpack('<H', f.read(2))[0] >> 8
  43.     while True:
  44.         if bits == 0:
  45.             flags = struct.unpack('<H', f.read(2))[0]
  46.             bits = 16
  47. ##            print('load', f.tell())
  48.         flag = flags & 1
  49. ##        print(flag, flags)
  50.         flags >>= 1
  51.         bits -= 1
  52.         yield flag
  53. def setup_run(prev_u_buffer_pos):
  54.     global getflag, output
  55.     run = 2
  56.     if not next(getflag):
  57.         run += 1
  58.         if not next(getflag):
  59.             run += 1
  60.             if not next(getflag):
  61.                 run += 1
  62.                 if not next(getflag):
  63.                     if not next(getflag):
  64.                         run = ord(infilestream.read(1)) + 0xE
  65.                     else:
  66.                         run = 0
  67.                         for x in range(3):
  68.                             run <<= 1
  69.                             run |= next(getflag)
  70.                         run += 0x6
  71. ##    print(run, prev_u_buffer_pos, len(output))
  72. #Does the 'copy from buffer' thing
  73.     for x in range(run):
  74.         output.append(output[-1 * prev_u_buffer_pos])
  75.    
  76. def decompress(infilestream, outfilestream):
  77.     global getflag, output              #Other functions need access?
  78.     x = infilestream.tell()
  79.     end_of_stream = infilestream.seek(0, 2)
  80.     infilestream.seek(x)
  81.     output = bytearray(0)
  82.     getflag = _getflag(infilestream)    #Setup/reset generator
  83.     while True:
  84.         if infilestream.tell() == end_of_stream:
  85.             raise Exception('Incomplete compressed stream.')
  86.         if next(getflag):               #Call next method to process next flag
  87.             if next(getflag):           #Long look-back distance or exit program or repeating sequence (flags = 11)
  88.                 prev_u_buffer_pos = 0
  89.                 run = 0
  90.                 for x in range(5):                              #Load high-order distance from flags (max = 0x31)
  91.                     run <<= 1
  92.                     run |= next(getflag)
  93.                 prev_u_buffer_pos = ord(infilestream.read(1))   #Load low-order distance (max = 0xFF)
  94.                                                                 #Also acts as flag byte
  95.                                                                 #run = 0 and byte = 0 -> exit program
  96.                                                                 #run = 0 and byte = 1 -> sequence of repeating bytes
  97.                 if run != 0:
  98.                     prev_u_buffer_pos |= (run << 8)             #Add high and low order distance (max distance = 0x31FF)
  99.                     setup_run(prev_u_buffer_pos)                #Get run length and finish unpacking (write to output)
  100.                 elif prev_u_buffer_pos > 2:                     #Is this used? Seems inefficient.
  101.                     setup_run(prev_u_buffer_pos)
  102.                 elif prev_u_buffer_pos == 0:                    #Decompression complete. End program.
  103. ##                        pdb.set_trace()
  104. ##                        print('hit')
  105.                     break
  106.                 else:                                           #Repeating byte
  107.                     branch = next(getflag)                      #True = long repeating sequence (> 30)
  108.                     for x in range(4):                          #Load run length from flags
  109.                         run <<= 1
  110.                         run |= next(getflag)
  111.                     if branch:                                  #Long run length
  112.                         run <<= 0x8                             #Load run length from byte and
  113.                         run |= ord(infilestream.read(1))        #add high-order run length (max = 0xFFF + 0xE)
  114.                     run += 0xE
  115.                     byte = infilestream.read(1)                 #Get byte to repeat
  116.                     for x in range(run):
  117.                         output += byte
  118.             else:                       #Short look-back distance (flags = 10)
  119.                 prev_u_buffer_pos = ord(infilestream.read(1))   #Get the look-back distance (max = 0xFF)
  120.                 setup_run(prev_u_buffer_pos)                    #Get run length and finish unpacking (write to output)
  121.         else:                           #Copy byte (flags = 0)
  122.             output += infilestream.read(1)                      
  123.     outfilestream.write(output)
  124. if __name__ == '__main__':
  125.     pass
  126.     ##with open('FALCOM2_test.cmp', 'rb') as f:
  127.     ##    with open('output.unc', 'wb') as g:
  128.     ##        g.write(decompress_FALCOM2(f.read()))
  129.     ##with open('skill.tbb', 'rb') as f:
  130.     ##    with open('output.unc', 'wb') as g:
  131.     ##        f.seek(4)
  132.     ##        g.write(decompress_FALCOM3(f.read()))
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement