Skip to content

Instantly share code, notes, and snippets.

@NWPlayer123
Created September 15, 2019 01:29
Show Gist options
  • Save NWPlayer123/5102f95f132206458de8d01a31cb60ef to your computer and use it in GitHub Desktop.
Save NWPlayer123/5102f95f132206458de8d01a31cb60ef to your computer and use it in GitHub Desktop.
*.bin.gz converter script for Hyrule Warriors (Wii U only prob bc big endian)
'''
word 0 = chunk_size (read 0x10000 bytes, compress, store)
word 1 = num_chunks
word 2 = dec_size
table, compressed chunk size + 4 (there's a size word at the start of the section)
align to 0x80
(write enc_chunk_size, enc_chunk, align to 0x80) * num_chunks
'''
from struct import unpack, pack
from io import BytesIO
import zlib, sys
def align_128(f):
if (f.tell() % 0x80):
f.seek(0x80 - (f.tell() % 0x80), 1)
def write_128(o):
if (o.tell() % 0x80):
o.write(b"\x00" * (0x80 - (o.tell() % 0x80)))
def full(f):
return unpack(">I", f.read(4))[0]
def hyrule_decompress(filename, outname):
with open(filename, "rb") as f:
with open(outname, "wb") as o:
header = unpack(">3I", f.read(12))
section_sizes = unpack(">%dI" % header[1], f.read(4*header[1]))
align_128(f)
for i in range(header[1]):
size = full(f)
o.write(zlib.decompress(f.read(size)))
align_128(f)
def hyrule_compress(filename, outname):
with open(filename, "rb") as f:
with open(outname, "wb+") as o:
section_sizes = []
f.seek(0, 2)
if not f.tell() % 0x10000: #multiple of 0x10000
section_count = int(f.tell() / 0x10000)
else: #add one chunk for overflow bytes
section_count = int(f.tell() / 0x10000) + 1
o.write(pack(">I", 0x10000))
o.write(pack(">I", section_count))
o.write(pack(">I", f.tell()))
o.write(b"\x00\x00\x00\x00" * section_count) #sizes, will fix later
write_128(o)
f.seek(0) #start of file, time to start compressing
for i in range(section_count):
data = BytesIO(zlib.compress(f.read(0x10000), 9))
data.seek(0, 2)
section_sizes.append(data.tell())
data.seek(0)
o.write(pack(">I", section_sizes[-1]))
o.write(data.read())
write_128(o)
o.seek(12) #go back to write section table
for i in range(section_count):
o.write(pack(">I", section_sizes[i] + 4))
if __name__ == "__main__":
if len(sys.argv) == 4:
if sys.argv[1] == "decompress":
hyrule_decompress(sys.argv[2], sys.argv[3])
elif sys.argv[1] == "compress":
hyrule_compress(sys.argv[2], sys.argv[3])
else:
print('unknown option, expected "decompress" or "compress"')
print("hyrule_convert.py <de/compress> <filename> <outname>")
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment