credit to https://github.com/rileyzzz/ChumpLib/blob/main/chumplib/src/tzarcfile.cpp for the tzarc v1 file format
Last active
June 21, 2024 00:08
-
-
Save Puyodead1/31eac3fd8eb941a0880e909849d25fc2 to your computer and use it in GitHub Desktop.
Trainz 22 TZarc extractor
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
# trainz 22 tzarc extractor by Puyodead1 | |
# only works for v1, v2 archives need to be decompressed first and then feed into this script | |
import argparse | |
import pathlib | |
import struct | |
# pip install binreader | |
from binreader import BinaryReader | |
def swap32(i): | |
return struct.unpack("<I", struct.pack(">I", i))[0] | |
def serialize_string(reader: BinaryReader): | |
str_len = reader.read_byte() | |
return reader.read_string(str_len) | |
class TZArcFile: | |
name: str | |
size: int | |
data: bytes | |
def __init__(self): | |
pass | |
def extract(reader: BinaryReader, file_path: str, list_only: bool): | |
file_count = swap32(reader.read_uint32()) | |
print(f"File Count: {file_count}") | |
files = [] | |
for i in range(file_count): | |
file = TZArcFile() | |
file_name = serialize_string(reader) | |
file.name = file_name | |
# compression? | |
unknown = swap32(reader.read_uint32()) | |
file_size = swap32(reader.read_uint32()) | |
file.size = file_size | |
files.append(file) | |
# print(f"[DEBUG] File {file_name} size {file_size}") | |
# crc? | |
unknown2 = swap32(reader.read_uint32()) | |
# print(f"[DEBUG] Unknown2: {unknown2}") | |
for i in range(file_count): | |
file = files[i] | |
file_name = file.name | |
file.data = reader.read(file.size) | |
# print(f"[DEBUG] Read file data for {file.name}, stream pos {reader.tell()}") | |
if list_only: | |
for file in files: | |
print(file.name) | |
return | |
# create a directory using the name of the file | |
dir_name = pathlib.Path(file_path).stem.replace(" ", "_") | |
for file in files: | |
fp = pathlib.Path(dir_name, file.name) | |
fp.parent.mkdir(exist_ok=True, parents=True) | |
print(f"Writing {fp}") | |
with open(fp, "wb") as f: | |
f.write(file.data) | |
def main(file_path: str, list_only: bool): | |
with open(file_path, "rb") as f: | |
reader = BinaryReader(f) | |
magic = reader.read_uint32() | |
assert magic == 0x63615A54, "Not a valid TZArc file" | |
version = swap32(reader.read_uint32()) | |
print(f"File Version: {version}") | |
if version == 2: | |
raise AssertionError("Version 2 archives need to be decompressed first!") | |
assert version == 1, "Unsupported version" | |
extract(reader, file_path, list_only) | |
if __name__ == "__main__": | |
parser = argparse.ArgumentParser(description="Auran TZArc extractor") | |
parser.add_argument("file", help="The file to extract") | |
parser.add_argument("--list", help="List files instead of extracting", action="store_true") | |
args = parser.parse_args() | |
main(args.file, args.list) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment