Skip to content

Instantly share code, notes, and snippets.

@amatus
Created May 14, 2014 18:32
Show Gist options
  • Save amatus/e085a7a0bae076cd8f60 to your computer and use it in GitHub Desktop.
Save amatus/e085a7a0bae076cd8f60 to your computer and use it in GitHub Desktop.
Python script to extract an AVPK archive
import sys
import io
import struct
def int32(f):
return struct.unpack('<i', f.read(4))[0]
def string(f):
bs = []
while True:
b = f.read(1)
if len(b) == 0:
raise ValueError('Unterminated string')
if b[0] == 0:
break
bs.append(b[0])
return str(bytes(bs), 'utf-8')
def copy_file(f, out, file_length):
while file_length > 0:
buf = f.read(min(file_length, 4096))
if len(buf) == 0:
raise ValueError('Truncated file')
rc = out.write(buf)
if rc != len(buf):
raise IOError('Unable to write to file')
file_length -= rc
def extract(f):
if f.read(4) != b'AVPK':
raise ValueError('Bad file signature')
length = int32(f)
strings_offset = int32(f)
strings_length = int32(f)
files_offset = int32(f)
files_length = int32(f)
data_offset = int32(f)
data_length = int32(f)
# Parse strings
f.seek(strings_offset, io.SEEK_SET)
num_strings = int32(f)
strings = [(int32(f), int32(f)) for i in range(num_strings)]
for (name_offset, val_offset) in strings:
f.seek(strings_offset + name_offset, io.SEEK_SET)
name = string(f)
f.seek(strings_offset + val_offset, io.SEEK_SET)
val = string(f)
print(name + ": " + val)
# Parse files
f.seek(files_offset, io.SEEK_SET)
num_files = int32(f)
files = [(int32(f), int32(f), int32(f)) for i in range(num_files)]
for (file_length, file_name_offset, file_offset) in files:
f.seek(files_offset + file_name_offset, io.SEEK_SET)
file_name = string(f)
print(file_name + " " + str(file_length) + " bytes")
with open(file_name, 'wb') as out:
f.seek(data_offset + file_offset, io.SEEK_SET)
copy_file(f, out, file_length)
with open(sys.argv[1], 'rb') as f:
extract(f)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment