Last active
March 14, 2017 20:11
-
-
Save NWPlayer123/65490bf7a16135589b3e74d0a9856ad7 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#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