1
0
Files
convert-tow-switch2pc/convert.py
2025-11-02 19:40:44 +00:00

111 lines
2.9 KiB
Python
Executable File

#!/usr/bin/env python3
import os
import os.path
import shutil
from struct import pack, unpack
import sys
import zlib
FOLDER = sys.argv[1]
if not os.path.isdir(FOLDER):
print(f"Syntax: {sys.argv[0]} SAVEDIR")
sys.exit(10)
FOLDER = os.path.realpath(FOLDER)
folder_name = os.path.basename(FOLDER)
print(f"Selected folder: {folder_name}")
if not os.path.isfile(FOLDER + "/SavedState.dat"):
print("ERROR: Save folder doesn't have a SavedState.dat. Make sure to specify a Switch savegame.")
sys.exit(11)
output_folder = FOLDER + "_PC"
try:
os.mkdir(output_folder)
except:
print(f"Error creating output folder: {output_folder}")
sys.exit(12)
shutil.copy2(FOLDER + "/Metadata.dat", output_folder)
shutil.copy2(FOLDER + "/SaveGameScreenshot.png", output_folder)
print("Reading SavedState.dat...")
with open(FOLDER + "/SavedState.dat", "rb") as f:
zlib_save = f.read()
print(f"Read {len(zlib_save)} Bytes.")
print("Decompressing savegame...")
save = zlib.decompress(zlib_save)
size_real = len(save)
print(f"Size after decompression: {size_real} Bytes.")
size_header = unpack("<I", save[0:4])[0]
print(f"Size read from savegame : {size_header} Bytes.")
if size_real != size_header:
print("ERROR: Savegame data size mismatch!")
sys.exit(13)
num_records = unpack("<I", save[4:8])[0]
print(f"Savegame has {num_records} records according to header.")
save = save[8:]
output = b""
output += pack("<I5sIH", 5, b"SGDF", 1, 10)
records = 0
while True:
name_bin_len = unpack("<Q", save[0:8])[0]
name_utf16_len = name_bin_len * 2
name_utf16 = save[8:8+name_utf16_len]
save = save[8+name_utf16_len:]
payload_length = unpack("<I", save[0:4])[0]
save = save[4:]
name = name_utf16.decode("utf16")
print(f"- {name} ({payload_length} Bytes)", end="")
name_len = len(name) + 1 # add cstr NUL byte
output += pack("<I", name_len)
output += name.encode("utf8")
output += b"\x00"
output += pack("<I", payload_length)
output += save[:payload_length]
print("")
records += 1
save = save[payload_length:]
if len(save) == 0:
break
print(f"Processed {records} records.")
if records != num_records:
print(f"WARNING: This doesn't match the {num_records} indicated in the header! Savegame might not work.")
output_len = len(output)
print(f"New savegame size: {output_len} Bytes.")
# DEBUG:
#with open(output_folder + "/SaveGame.dec.dat", "wb") as f:
# f.write(output)
zlib_output = zlib.compress(output)
print(f"New savegame size after compression: {len(zlib_output)} Bytes.")
print("Writing SaveGame.dat...")
with open(output_folder + "/SaveGame.dat", "wb") as f:
f.write(zlib_output)
print("Output file written successfully.")
# Metadata.dat has the uncompressed size and if it doesn't match
# the savegame won't load
print("Fixing metadata.")
with open(output_folder + "/Metadata.dat", "rb+") as f:
f.seek(-28, 2)
f.write(pack("<I", output_len))
print("All done.")