gck-map-extract-objects/read_gzp.py

134 lines
3.6 KiB
Python
Raw Normal View History

2020-02-24 01:07:35 +01:00
import logging
import argparse
import struct
def main():
objects = []
_ch = logging.StreamHandler()
_ch.setLevel("DEBUG")
_formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s')
_ch.setFormatter(_formatter)
logger = logging.getLogger(__name__)
logger.addHandler(_ch)
logger.setLevel("DEBUG")
parser = argparse.ArgumentParser()
parser.add_argument("gzp_file", help="gzp file to read")
args = parser.parse_args()
gzp_file = args.gzp_file
logger.info("Opening "+gzp_file)
with open(gzp_file, "rb") as gzp_fp:
checksum = read_int(gzp_fp)
if checksum != 0x6608F101:
raise Exception("Invalid GZP checksum")
logger.info("Checksum OK")
meta_info_offset = read_int(gzp_fp)
gzp_fp.seek(meta_info_offset)
unk = read_int(gzp_fp)
entries_count = read_int(gzp_fp)
if entries_count == 0:
logger.info("No entries found, skipping")
return
logger.info(str(entries_count)+" entries in GZP")
for index in range(entries_count):
logger.info("Reading index "+str(index))
compressed_size = read_int(gzp_fp)
original_size = read_int(gzp_fp)
# original_size = read_int(gzp_fp)
file_time = read_int(gzp_fp)
content_offset = read_int(gzp_fp) + 16
compression = read_byte(gzp_fp) # compression: 1 if compressed else 0
name_length = read_byte(gzp_fp)
name = read_bytes(gzp_fp, name_length).decode("utf8").strip('\x00')
logger.info(name + " compression: "+str(compression) + ", filesize: "+sizeof_fmt(original_size) + ", start: "+str(content_offset))
curr_pos = gzp_fp.tell()
gzp_fp.seek(content_offset)
buffer = gzp_fp.read(compressed_size)
gzp_fp.seek(curr_pos)
if compression == 1:
logger.info("File is compressed, decompressing it")
buffer = decompress(buffer, original_size)
logger.info("Writing file "+name)
with open(name, "wb") as entry_fp:
entry_fp.write(buffer)
# separator = read_byte(gzp_fp)
def sizeof_fmt(num, suffix='B'):
for unit in ['','Ki','Mi','Gi','Ti','Pi','Ei','Zi']:
if abs(num) < 1024.0:
return "%3.1f%s%s" % (num, unit, suffix)
num /= 1024.0
return "%.1f%s%s" % (num, 'Yi', suffix)
def read_byte(fp):
return struct.unpack("<B", fp.read(1))[0]
def read_bytes(fp, num):
return bytes(struct.unpack('<'+str(num)+'B', fp.read(num)))
def read_int(fp):
return struct.unpack("<L", fp.read(4))[0]
def decompress(buffer, finalsize):
i = 0
j = 0
decByte = 0
decBits = 8
buffStart = 0xFEE
res = bytearray(finalsize)
if finalsize == 0:
return res
while j < finalsize:
if decBits == 8:
decByte = buffer[i]
i += 1
decBits = 0
if (decByte >> decBits & 1) == 0:
decPos = ((buffer[i] + ((buffer[i + 1] & 0xF0) << 4) - buffStart - j) & 0xFFF) - 0x1000 + j
decLen = (buffer[i + 1] & 0xF) + 3
i += 2
while decLen > 0:
if decPos >= 0:
# print("j:" +str(j))
# print("decPos: "+str(decPos))
res[j] = res[decPos]
else:
res[j] = 32
j += 1
decPos += 1
decLen -= 1
else:
res[j] = buffer[i]
i += 1
j += 1
decBits += 1
return res
if __name__ == '__main__':
main()