Advertisement
Guest User

pak_extract.py

a guest
Jun 22nd, 2013
297
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Python 2.15 KB | None | 0 0
  1. import os
  2. import struct
  3. from collections import namedtuple
  4. from sys import argv
  5.  
  6. # This script exports files contained in Quake 1 format .pak files.
  7. # > python pak_extract.py PAK0.PAK
  8. # extracts the contents of PAK0.PAK to a folder named PAK0
  9.  
  10. # type definitions
  11. PAKHeader = namedtuple('PAKHeader', "format, dir_ofs, dir_size")
  12. fmt_PAKHeader = '<4s2i'
  13.  
  14. PAKEntry = namedtuple('PAKDirectory', "path, ofs, size")
  15. fmt_PAKEntry = '<56s2I'
  16.  
  17. def extract(pak_path):
  18.     with open(pak_path, 'rb') as pak_file:
  19.         header_data = pak_file.read(struct.calcsize(fmt_PAKHeader))
  20.         header = PAKHeader._make(struct.unpack(fmt_PAKHeader, header_data))
  21.  
  22.         entry_struct = struct.Struct(fmt_PAKEntry)
  23.         entry_size = struct.calcsize(fmt_PAKEntry)
  24.         num_entries = int(header.dir_size / struct.calcsize(fmt_PAKEntry))
  25.  
  26.         print("File: %s (found directory at %d containing %d entries)" % (pak_path, header.dir_ofs, num_entries))
  27.  
  28.         pak_file.seek(header.dir_ofs)
  29.         pak_directory_data = pak_file.read(header.dir_size)
  30.  
  31.         for i in range(0, num_entries):
  32.             entry_ofs = i * entry_size
  33.             entry_data = pak_directory_data[entry_ofs:entry_ofs+entry_size]
  34.             entry = PAKEntry._make(entry_struct.unpack_from(entry_data))
  35.             # some entries (e.g. PAK0.PAK/progs.dat) are not correctly 0 padded,
  36.             # so this is required as .decode doesn't work
  37.             entry_path = ""
  38.             for j, b in enumerate(entry.path):
  39.                 if b == '\x00':
  40.                     entry_path = entry.path[0:j].decode('ascii')
  41.                     break
  42.                 elif j == 55:
  43.                     entry_path = entry.path.decode('ascii')
  44.             # save the file
  45.             if entry_path != "":
  46.                 print("[%d] %s (%d bytes at %d)" % (i, entry.path, entry.size, entry.ofs))
  47.                 file_name = os.path.basename(entry_path)
  48.                 file_path = os.path.dirname(entry_path)
  49.                 # read the file data
  50.                 pak_file.seek(entry.ofs)
  51.                 file_data = pak_file.read(entry.size)
  52.                 # prepare the output path
  53.                 output_dir = os.path.splitext(pak_path)[0] + "/" + file_path
  54.                 if not os.path.exists(output_dir):
  55.                     os.makedirs(output_dir)
  56.                 output_path = output_dir + "/" + file_name
  57.                 # write the file
  58.                 with open(output_path, 'wb') as output_file:
  59.                     output_file.write(file_data)
  60.  
  61. extract(argv[1])
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement