Skip to content

Instantly share code, notes, and snippets.

@NWPlayer123
Last active March 14, 2017 20:11
Show Gist options
  • Save NWPlayer123/65490bf7a16135589b3e74d0a9856ad7 to your computer and use it in GitHub Desktop.
Save NWPlayer123/65490bf7a16135589b3e74d0a9856ad7 to your computer and use it in GitHub Desktop.
#Only tested on Python 2.7.13 but it *might* work on 3.X
from struct import pack, unpack
from os.path import exists
from os import mkdir, makedirs
import sys
endian = ">" #Initial endian until we read the BOM
def byte(f):
return unpack("%sB" % endian, f.read(1))[0]
def half(f):
return unpack("%sH" % endian, f.read(2))[0]
def trip(f):
return unpack("%sI" % endian, "\x00"+f.read(3))[0]
def full(f):
return unpack("%sI" % endian, f.read(4))[0]
def getstr(f):
ret = ""; char = f.read(1)
while char != "\x00":
ret += char
char = f.read(1)
return ret
with open(sys.argv[1], "rb") as f:
assert f.read(4) == b"SARC"
assert half(f) == 0x14 #Header size
endian = ["<", ">"][half(f) & 1]
f.seek(0, 2)
size = f.tell()
f.seek(8, 0)
assert full(f) == size #Sanity check
print("size: %08X" % size)
align = full(f)
print("align: %08X" % align)
f.seek(4, 1) #Probably static
start1 = f.tell()
assert f.read(4) == b"SFAT"
assert half(f) == 0x0C #Header size
count = half(f)
start2 = 0x20 + (0x10 * count)
#NOTE: Data start is not always at [align], so
#we can read last *name, go there and read it
#to get the end of SFNT, and then pad that
f.seek(start2 - 11)
offset = trip(f)
f.seek(start2 + 8 + (offset * 4))
getstr(f)
start3 = f.tell() + (align - (f.tell() % align))
#Now we can start extracting all files non-linearly
f.seek(start1 + 0x10)
for i in range(count):
assert byte(f) == 1 #has filename
name = trip(f)
start = full(f)
end = full(f)
back = f.tell() + 4 #I'm ignoring hashes, warning
f.seek(start2 + 8 + (name * 4))
name = getstr(f).split("/")
print("/".join(name))
base = ".".join(sys.argv[1].split(".")[:-1])
path = "/".join([base] + name[:-1])
name = name[-1]
if not exists(path): makedirs(path)
with open(path + "/" + name, "wb") as o:
f.seek(start3 + start)
o.write(f.read(end - start))
#print("%s/%s" % (path, name))
f.seek(back)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment