Created
June 18, 2014 02:03
-
-
Save mdavey/4b984e021bf484035cfa to your computer and use it in GitHub Desktop.
Crimsonland (Steam) Pak Format
This file contains 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
import os | |
import struct | |
""" | |
Crimsonland (Steam) pak file format | |
Header format: | |
50 40 4B 00 56 31 31 00 ("PAK" NUL "V11" NUL) | |
int32 index offset (eg: 28679361) | |
int32 end index offset (eg: 28885444) | |
Index Format: | |
int32 number of indexes? | |
Index_File format: | |
null terminated string | |
int32 absolute offset of file | |
int32 file length | |
unknown maybe always (?) equal to: FF 26 E2 50 20 00 00 00 | |
""" | |
class ClPak(object): | |
def __init__(self, filename): | |
self.file = open(filename, 'rb') | |
def read_header(self): | |
self.file.seek(0) | |
bytes = self.file.read(16) | |
(magic_1, magic_2, index_start_offset, index_end_offset) = struct.unpack('3sx3sxii', bytes) | |
if magic_1 != 'PAK' or magic_2 != 'V11': | |
raise Exception('Unknown file format') | |
return index_start_offset, index_end_offset | |
def read_index(self): | |
start_offset, end_offset = self.read_header() | |
self.file.seek(start_offset) | |
bytes = self.file.read(end_offset - start_offset) | |
# index_size = struct.unpack('i', bytes[:4]) | |
return self.read_index_file_details(bytes[4:]) | |
def read_index_file_details(self, bytes): | |
details = {'name': '', 'offset': 0, 'length': 0, 'unknown': ''} | |
sequence = iter(bytes) | |
for char in sequence: | |
if char != chr(0): | |
details['name'] += char | |
else: | |
offset_bytes = sequence.next() + sequence.next() + sequence.next() + sequence.next() | |
length_bytes = sequence.next() + sequence.next() + sequence.next() + sequence.next() | |
(details['offset'],) = struct.unpack('i', offset_bytes) | |
(details['length'],) = struct.unpack('i', length_bytes) | |
for x in range(0, 8): | |
details['unknown'] += sequence.next() | |
yield details | |
details = {'name': '', 'offset': 0, 'length': 0, 'unknown': ''} | |
def dump_file(self, details, base_directory): | |
dest_filename = base_directory + '/' + details['name'] | |
if not os.path.exists(os.path.dirname(dest_filename)): | |
os.makedirs(os.path.dirname(dest_filename)) | |
with open(dest_filename, 'wb') as dest: | |
self.file.seek(details['offset']) | |
dest.write(self.file.read(details['length'])) | |
if __name__ == '__main__': | |
cl_pak = ClPak(r'D:\Steam\steamapps\common\Crimsonland\data.pak') | |
for file_details in cl_pak.read_index(): | |
print file_details | |
cl_pak.dump_file(file_details, 'd:/clpak_files') |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment