1. # format specs: http://wiki.xentax.com/index.php/GRAF:AFS_AFS
  2.  
  3. import struct
  4. import os, sys
  5.  
  6. # create a folder to dump the files to
  7. dir = 'AFS_DUMP'
  8. if not os.path.exists(dir):
  9.     os.makedirs(dir)
  10.  
  11. try:
  12.     filename = sys.argv[1]
  13. except:
  14.     filename = 'datadvd.afs'
  15.  
  16. file = open(filename, 'rb')
  17.  
  18. # Little Endian
  19.  
  20. header = file.read(4)
  21. if header != 'AFS\0':
  22.     print 'Not an AFS file or header corrupt:', header
  23.     sys.exit()
  24.    
  25. numoffiles = struct.unpack('<I', file.read(4))[0]
  26. print 'Number of files:', numoffiles
  27.  
  28. # TOC: Table of Contents
  29. lenghtsandoffsets = []
  30.  
  31. for i in range(numoffiles):
  32.     offset = struct.unpack('<I', file.read(4))[0]
  33.     print ' file', i, 'offset:', offset
  34.    
  35.     lenght = struct.unpack('<I', file.read(4))[0]
  36.     print ' file', i, 'lenght:', lenght
  37.    
  38.     lenghtsandoffsets.append([offset, lenght])
  39.    
  40. filenamediroffset = struct.unpack('<I', file.read(4))[0]
  41. print 'Filename directory offset:', filenamediroffset
  42. filenamedirlenght = struct.unpack('<I', file.read(4))[0]
  43. print 'Filename directory lenght:', filenamedirlenght
  44.  
  45. # jump to filename directory to get the file names, before dumping the files which are located before it
  46. currentpos = file.tell()
  47.  
  48. file.seek(filenamediroffset)
  49.  
  50. filenames = []
  51. for i in range(numoffiles):
  52.     # name
  53.     name = file.read(32).rstrip('\0')
  54.     print ' ', name
  55.    
  56.     filenames.append(name)
  57.    
  58.     # we don't need these
  59.     file.read(12)
  60.    
  61.     filelenght = struct.unpack('<I', file.read(4))[0]
  62.     #if filelenght != lenghtsandoffsets[i][1]:
  63.     #   print 'file' ,name, "lenght doesn't match the one in the TOC:", filelenght, lenghtsandoffsets[i][1]
  64.  
  65. # jump back to file data section
  66. file.seek(currentpos)
  67.  
  68. for i in range(numoffiles):
  69.     file.seek(lenghtsandoffsets[i][0])
  70.    
  71.     outfile = open('AFS_DUMP/'+filenames[i], 'wb')
  72.    
  73.     data = file.read(lenghtsandoffsets[i][1])
  74.    
  75.     outfile.write(data)
  76.    
  77.     outfile.close()