Skip to content

Instantly share code, notes, and snippets.

@NWPlayer123
Last active September 3, 2019 20:43
Show Gist options
  • Save NWPlayer123/27199c50ae7ee83cb3e3fd06ea4b3d82 to your computer and use it in GitHub Desktop.
Save NWPlayer123/27199c50ae7ee83cb3e3fd06ea4b3d82 to your computer and use it in GitHub Desktop.
Astral Chain pkz
#"pkzl", 0x10000, full_size, ???
#4 vars in each entry, count, decsize, offset, encsize?
#!! pip install zstd !!
from struct import unpack
from zstd import decompress
from os.path import exists, splitext
from os import makedirs
import sys
def read16(f):
return unpack("<H", f.read(2))[0]
def read32(f):
return unpack("<I", f.read(4))[0]
def getstr(f):
ret = b"";char = f.read(1)
while char != b"\x00":
ret += char
char = f.read(1)
if f.tell() % 8: #normally don't align but only strings here are
f.seek(8 - (f.tell() % 8), 1)
return ret
with open(sys.argv[1], "rb") as f:
outname = sys.argv[1][:-4]
assert f.read(4) == b"pkzl" #magic
assert read32(f) == 0x10000 #??? version?
f.seek(0, 2)
full_size = f.tell()
f.seek(8)
assert read32(f) == full_size #assert file+8 = filesize
header = unpack("<5I", f.read(0x14)) #0x20 header
entries = [unpack("<4Q", f.read(32)) for i in range(header[1])] #4 lwords
assert f.read(16) == b"ZStandard".ljust(16, b"\x00") #always 0x10 afaict
filenames = [getstr(f).decode("UTF-8") for i in range(header[1])]
#variable length, aligned to 8-byte boundary, "UTF-8" so py3's happy >.>
if not exists(outname): #make output folder if it doesn't exist
makedirs(outname)
for i in range(header[1]):
#print("%016X %016X %016X %016X" % entries[i])
if entries[i][1] != 0: #entry_size can be 0, skip those? null zstd header
print(filenames[i]) #pretty print
with open(outname + "/" + filenames[i], "wb") as o:
f.seek(entries[i][2]) #seek to entry_offset
o.write(decompress(f.read(entries[i][3]))) #decompress dec_size
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment