# format specs: http://wiki.xentax.com/index.php/GRAF:AFS_AFS
import struct
import os, sys
# create a folder to dump the files to
dir = 'AFS_DUMP'
if not os.path.exists(dir):
os.makedirs(dir)
try:
filename = sys.argv[1]
except:
filename = 'datadvd.afs'
file = open(filename, 'rb')
# Little Endian
header = file.read(4)
if header != 'AFS\0':
print 'Not an AFS file or header corrupt:', header
sys.exit()
numoffiles = struct.unpack('<I', file.read(4))[0]
print 'Number of files:', numoffiles
# TOC: Table of Contents
lenghtsandoffsets = []
for i in range(numoffiles):
offset = struct.unpack('<I', file.read(4))[0]
print ' file', i, 'offset:', offset
lenght = struct.unpack('<I', file.read(4))[0]
print ' file', i, 'lenght:', lenght
lenghtsandoffsets.append([offset, lenght])
filenamediroffset = struct.unpack('<I', file.read(4))[0]
print 'Filename directory offset:', filenamediroffset
filenamedirlenght = struct.unpack('<I', file.read(4))[0]
print 'Filename directory lenght:', filenamedirlenght
# jump to filename directory to get the file names, before dumping the files which are located before it
currentpos = file.tell()
file.seek(filenamediroffset)
filenames = []
for i in range(numoffiles):
# name
name = file.read(32).rstrip('\0')
print ' ', name
filenames.append(name)
# we don't need these
file.read(12)
filelenght = struct.unpack('<I', file.read(4))[0]
#if filelenght != lenghtsandoffsets[i][1]:
# print 'file' ,name, "lenght doesn't match the one in the TOC:", filelenght, lenghtsandoffsets[i][1]
# jump back to file data section
file.seek(currentpos)
for i in range(numoffiles):
file.seek(lenghtsandoffsets[i][0])
outfile = open('AFS_DUMP/'+filenames[i], 'wb')
data = file.read(lenghtsandoffsets[i][1])
outfile.write(data)
outfile.close()