Skip to content

Instantly share code, notes, and snippets.

@auramagi
Last active April 26, 2018 08:14
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save auramagi/c194c97143f6b68b069c29cae5f31d8c to your computer and use it in GitHub Desktop.
Save auramagi/c194c97143f6b68b069c29cae5f31d8c to your computer and use it in GitHub Desktop.
3DS ECD archive decompression
def bit_is_set(byteval,idx):
return ((byteval&(1<<idx))!=0)
def read_int_bbo(f, s, signed=False):
return int.from_bytes(f.read(s), byteorder='big', signed=signed)
def decompressECD(f, out_fname): #file handle at ECD start position, out file name
magic = f.read(3)
if not magic == b'ECD':
return
version = f.read(1)
skip = read_int_bbo(f, 4)
compSize = read_int_bbo(f, 4)
uncompSize = read_int_bbo(f, 4)
output = bytearray()
buffer = bytearray(bytes(1024))
output.extend(f.read(skip))
while True:
flag = f.read(1)
if len(flag) == 0:
break
flagi = int.from_bytes(flag, 'big')
for i in range(0, 8):
if bit_is_set(flagi, i):
c = read_int_bbo(f, 1)
buffer[len(output) % 1024] = c
output.append(c)
else:
b1 = read_int_bbo(f, 1)
b2 = read_int_bbo(f, 1)
l = b2 % 64 + 3
off = ((b2 >> 6) << 8) + b1 + 74
for i in range(off, off+l):
offset=i % 1024
c = buffer[offset]
buffer[len(output) % 1024] = c
output.append(c)
if len(output) >= uncompSize:
break
else:
continue
break
with open(out_fname, 'wb') as x:
x.write(output)
with open('test_ecd.bin', 'rb') as r:
decompressECD(r, 'test_ecd_decompressed.bin')
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment