Advertisement
MrCheeze

LZ Decompressors for CGX files (LZ19 and LZ3)

May 19th, 2020
425
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 6.40 KB | None | 0 0
  1. # Some CGX files are LZ19, and some are LZ3. you have to try both
  2.  
  3. bit_flipped = [
  4. sum(((byte >> i) & 1) << (7 - i) for i in range(8))
  5. for byte in range(0x100)
  6. ]
  7. def lc_lz19_Decompress(lz):
  8.  
  9. addr = 0
  10. output = []
  11.  
  12. while lz[addr] != 0xFF:
  13.  
  14. cmd = lz[addr] >> 5
  15.  
  16. if cmd == 7:
  17. cmd = (lz[addr] >> 2) & 0x7
  18. length = (lz[addr] & 0x3)*0x100 + lz[addr+1] + 1
  19. addr += 2
  20. else:
  21. length = (lz[addr] & 0x1F) + 1
  22. addr += 1
  23.  
  24. if cmd==0:
  25. output += lz[addr:addr+length]
  26. addr += length
  27. elif cmd==1:
  28. val = lz[addr]
  29. addr += 1
  30. output += [val] * length
  31. elif cmd==2:
  32. val1 = lz[addr]
  33. addr += 1
  34. val2 = lz[addr]
  35. addr += 1
  36. output += [val1, val2] * length
  37. elif cmd==3:
  38. val = lz[addr]
  39. addr += 1
  40. for i in range(length):
  41. output += [(val+i)%256]
  42. elif cmd==4:
  43. outbuf_addr = lz[addr]*0x100 + lz[addr+1]
  44. addr += 2
  45. for i in range(length):
  46. output.append(output[outbuf_addr+i])
  47. elif cmd==5:
  48. outbuf_addr = lz[addr]*0x100 + lz[addr+1]
  49. addr += 2
  50. for i in range(length):
  51. output.append(bit_flipped[output[outbuf_addr+i]])
  52. elif cmd==6:
  53. outbuf_addr = lz[addr]*0x100 + lz[addr+1]
  54. addr += 2
  55. for i in range(length):
  56. output.append(output[outbuf_addr-i])
  57. else:
  58. print('unimplemented cmd '+str(cmd))
  59. 1/0
  60.  
  61. return output
  62.  
  63. def lc_lz3_Decompress(lz):
  64.  
  65. addr = 0
  66. output = []
  67.  
  68. while lz[addr] != 0xFF:
  69.  
  70. cmd = lz[addr] >> 5
  71.  
  72. if cmd == 7:
  73. cmd = (lz[addr] >> 2) & 0x7
  74. length = (lz[addr] & 0x3)*0x100 + lz[addr+1] + 1
  75. addr += 2
  76. else:
  77. length = (lz[addr] & 0x1F) + 1
  78. addr += 1
  79.  
  80. if cmd==0:
  81. output += lz[addr:addr+length]
  82. addr += length
  83. elif cmd==1:
  84. val = lz[addr]
  85. addr += 1
  86. output += [val] * length
  87. elif cmd==2:
  88. vals = (lz[addr], lz[addr+1])
  89. addr += 2
  90. for i in range(length):
  91. output.append(vals[i%2])
  92. elif cmd==3:
  93. output += [0] * length
  94. elif cmd==4:
  95. if lz[addr] & 0x80:
  96. outbuf_addr = len(output) - 1 - (lz[addr]&0x7F)
  97. addr += 1
  98. else:
  99. outbuf_addr = lz[addr]*0x100 + lz[addr+1]
  100. addr += 2
  101. for i in range(length):
  102. output.append(output[outbuf_addr+i])
  103. elif cmd==5:
  104. if lz[addr] & 0x80:
  105. outbuf_addr = len(output) - 1 - (lz[addr]&0x7F)
  106. addr += 1
  107. else:
  108. outbuf_addr = lz[addr]*0x100 + lz[addr+1]
  109. addr += 2
  110. for i in range(length):
  111. output.append(bit_flipped[output[outbuf_addr+i]])
  112. elif cmd==6:
  113. if lz[addr] & 0x80:
  114. outbuf_addr = len(output) - 1 - (lz[addr]&0x7F)
  115. addr += 1
  116. else:
  117. outbuf_addr = lz[addr]*0x100 + lz[addr+1]
  118. addr += 2
  119. for i in range(length):
  120. output.append(output[outbuf_addr-i])
  121. else:
  122. print('unimplemented cmd '+str(cmd))
  123. 1/0
  124.  
  125. return output
  126.  
  127. def convertTxt(filename):
  128. print(filename)
  129. ret = []
  130. f=open(filename,'r')
  131. ignore_mode = False
  132.  
  133. width=0
  134. height=0
  135. first_len = 0
  136. len_sum = 0
  137. prev_len = 0
  138.  
  139. width_solved = False
  140. needsCommon = False
  141.  
  142. for line in f:
  143. if 'ifn' in line:
  144. ignore_mode = True
  145. elif 'else' in line or 'endif' in line:
  146. ignore_mode = False
  147. elif not ignore_mode:
  148. if '\tdb' in line:
  149. words=re.sub(r';.*','',line).replace('\tdb','').strip().strip(',').split(',')
  150. if len(words) > 0 and not width_solved:
  151. if first_len == 0:
  152. first_len = len(words)
  153. width = len(words)
  154. if ';20' in line:
  155. needsCommon = True
  156. elif first_len == len(words) and prev_len != len(words):
  157. width = len_sum
  158. width_solved = True
  159. len_sum += len(words)
  160. prev_len = len(words)
  161. for word in words:
  162. word=word.strip()
  163. if word[0]!='0':
  164. print(word, word[0])
  165. assert word[0]=='0'
  166. assert word[-1]=='h'
  167. if len(word) == 4:
  168. ret.append(int(word[1:3], 16))
  169. elif len(word) == 6:
  170. 1/0
  171. ret.append(int(word[1:3], 16))
  172. ret.append(int(word[3:5], 16))
  173. else:
  174. 1/0
  175. elif '\tdw' in line:
  176. words=re.sub(r';.*','',line).replace('\tdw','').strip().strip(',').split(',')
  177. for word in words:
  178. word=word.strip()
  179. if len(word) == 5:
  180. word = '0'+word
  181. assert word[0]=='0'
  182. assert word[-1]=='h'
  183. if len(word) == 6:
  184. ret.append(int(word[3:5], 16))
  185. ret.append(int(word[1:3], 16))
  186. else:
  187. 1/0
  188. elif '\tdh' in line:
  189. 1/0 #todo
  190. f.close()
  191. if width != 0:
  192. height = len(ret)//width
  193.  
  194. if '.CGX' in filename:
  195. ret_lz19 = lc_lz19_Decompress(ret)
  196.  
  197. if len(ret_lz19)%0x100 == 0:
  198. ret = ret_lz19
  199. else:
  200. ret_lz3 = lc_lz3_Decompress(ret)
  201.  
  202. if len(ret_lz3)%0x100 == 0:
  203. ret = ret_lz3
  204. else:
  205. 1/0
  206.  
  207. f2=open('temp_'+filename.split('/')[-1]+'.2bpp','wb')
  208. f2.write(bytearray(ret))
  209. f2.close()
  210.  
  211. return ret, width, height, needsCommon
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement