Skip to content

Instantly share code, notes, and snippets.

@NWPlayer123
Last active March 25, 2018 02:59
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 NWPlayer123/97906c810d38b25b5d07358cb7e01d6c to your computer and use it in GitHub Desktop.
Save NWPlayer123/97906c810d38b25b5d07358cb7e01d6c to your computer and use it in GitHub Desktop.
from struct import pack, unpack
from os import mkdir, makedirs
from os.path import exists
import sys
def half(f, en):
return unpack("%sH" % en, f.read(2))[0]
def full(f, en):
return unpack("%sI" % en, f.read(4))[0]
def getstr(f):
ret = b"";char = f.read(1)
while char != b"\x00":
ret += char
char = f.read(1)
return ret.decode("UTF-8")
def gethash(name, multiplier):
result = 0
for i in range(len(name)):
result = ord(name[i]) + (result * multiplier)
result &= 0xFFFFFFFF
return result
if __name__ == "__main__":
with open(sys.argv[1], "rb") as f:
assert f.read(4) == b"SARC" #magic
f.seek(6) #need to read endian before 0x14
en = ["<", ">"][half(f, ">") & 1]
f.seek(4) #now we can check it with endian
assert half(f, en) == 0x14 #header size
f.seek(0, 2) #end of file, verify correct size
size = f.tell()
f.seek(8) #expected size
assert full(f, en) == size #filesize
start = full(f, en) #of raw data
assert full(f, en) == 0x100 #???
assert f.read(4) == b"SFAT"
assert half(f, en) == 12 #header size
count = half(f, en)
multi = full(f, en)
if multi != 0x65:
print("WARNING: odd hash multiplier, may not be supp.")
attr = [];count1 = count #backup for below
while count: #may be giant, do a decrement
attr.append(unpack("%s4I" % en, f.read(16)))
count -= 1
assert f.read(4) == b"SFNT"
assert half(f, en) == 8 #SFNT header size
assert half(f, en) == 0 #????
SFNT = f.tell()
base = ".".join(sys.argv[1].split(".")[:-1])
if not exists(base):
mkdir(base)
print("%s%s %s" % ("NAME".ljust(80), "SIZE", "HASH"))
unknown = 0;i = 0;count = count1
while count:
if attr[i][1] & 0x01000000: #file has name
f.seek(SFNT + ((attr[i][1] & 0xFFFF) * 4))
name = getstr(f)
assert gethash(name, multi) == attr[i][0]
else:
f.seek(start + attr[i][2])
name = b"UNKNOWN%d.%s" % (unknown, getext(f.read(4)))
unknown += 1
if len(name) < 80:
print("%s%08X %08X" % (name.ljust(80), attr[i][3]\
- attr[i][2], attr[i][0]))
else:
trun = "..." + name[-76:] + " "
print("%s%08X %08X" % (trun, attr[i][3]-attr[i][2],\
attr[i][0]))
if "/" in name: #assume all are encoded this way
path = base + "/" + "/".join(name.split("/")[:-1])
else:
path = base
if not exists(path): makedirs(path)
with open(base + "/" + name, "wb") as o:
f.seek(start + attr[i][2])
o.write(f.read(attr[i][3]-attr[i][2]))
count -= 1;i += 1
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment