Created
March 21, 2020 21:40
-
-
Save infval/fc1b80efe16b034887f3c8e0e4b7f91c to your computer and use it in GitHub Desktop.
[PS2] Psi-Ops MOVIES.MPK unpacker / packer (PlayStation 2, Psi-Ops: The Mindgate Conspiracy)
This file contains hidden or 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
#!/usr/bin/env python3 | |
__version__ = "1.0" | |
__author__ = "infval" | |
import argparse | |
from pathlib import Path | |
from struct import unpack, pack | |
def unpack_mpk(mpk_path, unpack_path): | |
with open(mpk_path, "rb") as f: | |
header = f.read(16) | |
table_offset = unpack("<IIII", header)[2] | |
f.seek(table_offset) | |
table_header = f.read(16) | |
t_size, _, _, t_count = unpack("<IIII", table_header) | |
print("{:32} | {:10} | {:10}".format("Filename", "Offset", "Size")) | |
print("-" * (32 + 10 + 10 + 6)) | |
for i in range(t_count): | |
f.seek(table_offset + 16 * (i + 1)) | |
video = f.read(16) | |
v_name_offset, _, v_offset, v_size = unpack("<IIII", video) | |
f.seek(table_offset + v_name_offset) | |
v_name = f.read(32) | |
s = v_name.find(b"\x00") | |
v_name = v_name[:s].decode("latin_1") | |
print("{:32} | {:10} | {:10}".format(v_name, v_offset, v_size)) | |
f.seek(v_offset) | |
with open(unpack_path / v_name, "wb") as out: | |
out.write(f.read(v_size)) | |
def replace_mpk(mpk_path, unpack_path, new_mpk_path): | |
files = [] | |
with open(mpk_path, "rb") as f: | |
header = f.read(16) | |
table_offset = unpack("<IIII", header)[2] | |
f.seek(table_offset) | |
table_header = f.read(16) | |
t_size, _, _, t_count = unpack("<IIII", table_header) | |
for i in range(t_count): | |
f.seek(table_offset + 16 * (i + 1)) | |
video = f.read(16) | |
v_name_offset, _, v_offset, v_size = unpack("<IIII", video) | |
f.seek(table_offset + v_name_offset) | |
v_name = f.read(32) | |
s = v_name.find(b"\x00") | |
v_name = v_name[:s].decode("latin_1") | |
files.append(v_name) | |
f.seek(0) | |
header = f.read(2048) | |
f.seek(table_offset) | |
table = f.read(4096) | |
header = bytearray(header) | |
table = bytearray(table) | |
offset = 0x800 | |
for i, filename in enumerate(files): | |
path = unpack_path / filename | |
size = path.stat().st_size | |
elem_pos = (i + 1) * 16 | |
table[elem_pos+8: elem_pos+16] = pack("<II", offset, size) | |
offset += size | |
header[8: 8+4] = pack("<I", offset) | |
with open(new_mpk_path, "wb") as out: | |
out.write(header) | |
for filename in files: | |
print(filename) | |
path = unpack_path / filename | |
out.write(path.read_bytes()) | |
out.write(table) | |
def get_argparser(): | |
parser = argparse.ArgumentParser(description='[PS2] Psi-Ops MOVIES.MPK (un)packer v' + __version__) | |
parser.add_argument('--version', action='version', version='%(prog)s ' + __version__) | |
parser.add_argument('-i', '--input', metavar='INPUT_MPK', | |
help='movies.mpk file to (un)pack (default: movies.mpk)') | |
parser.add_argument('-o', '--output', metavar='OUTPUT_SFD', | |
help='directory for SFD files (default: filename + _unpack)') | |
parser.add_argument('-r', '--replace', metavar='OUTPUT_MPK', | |
help='create mpk with SFD files from OUTPUT_SFD; based on INPUT_MPK') | |
parser.add_argument('-y', action='store_true', help='overwrite output files without asking') | |
return parser | |
def main_cli(): | |
parser = get_argparser() | |
args = parser.parse_args() | |
input_path = Path("movies.mpk") | |
if args.input: | |
input_path = Path(args.input) | |
unpack_path = Path("{}_unpack".format(input_path)) | |
if args.output: | |
unpack_path = Path(args.output) | |
if args.replace: | |
new_mpk_path = Path(args.replace) | |
if new_mpk_path.exists() and not args.y: | |
answer = input("File '{}' already exists. Overwrite ? [y/N]".format(new_mpk_path)) | |
if answer.strip().lower() != 'y': | |
return | |
print("### Pack ###") | |
replace_mpk(input_path, unpack_path, new_mpk_path) | |
else: | |
if unpack_path.exists() and not args.y: | |
answer = input("Directory '{}' already exists. Overwrite ? [y/N]".format(unpack_path)) | |
if answer.strip().lower() != 'y': | |
return | |
unpack_path.mkdir(exist_ok=True) | |
print("### Unpack ###") | |
unpack_mpk(input_path, unpack_path) | |
if __name__ == '__main__': | |
main_cli() |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment