From 9bd51ae6c7693c6bb970b58786537d2923139aec Mon Sep 17 00:00:00 2001 From: Mc-muffin <8714476+Mc-muffin@users.noreply.github.com> Date: Tue, 16 Jan 2024 22:30:13 -0500 Subject: [PATCH] Rework isotool dumping so it's less cringe --- isotool.py | 287 ++++++++++++++++++++++++++++------------------------- 1 file changed, 151 insertions(+), 136 deletions(-) diff --git a/isotool.py b/isotool.py index 6418b8d..eacaf47 100644 --- a/isotool.py +++ b/isotool.py @@ -5,15 +5,18 @@ from pathlib import Path from dataclasses import dataclass import typing -SCRIPT_VERSION = "1.1" +SCRIPT_VERSION = "1.2" SECTOR_SIZE = 0x800 SYSTEM_AREA_SIZE = 0x10 * SECTOR_SIZE +LAYER0_PVD_LOCATION = SYSTEM_AREA_SIZE + @dataclass class FileListData: path: Path inode: int lba: int + size: int = 0 @dataclass @@ -25,6 +28,7 @@ class FileListInfo: def main(): print(f"pyPS2 ISO Rebuilder v{SCRIPT_VERSION}") print("Original by RaynĂȘ Games") + print() args = get_arguments() @@ -114,168 +118,179 @@ def check_pvd(fp: typing.BinaryIO, pvd_loc: int) -> bool: return False +def dump_dir_records(iso: typing.BinaryIO, pvd_loc: int, pvd_off: int) -> FileListInfo: + path_parts = [] + record_ends = [] + record_pos = [] + file_info = FileListInfo([], 0) + + # get the root directory record off the PVD + iso.seek(pvd_loc + 0x9E) + dr_data_pos, dr_data_len = struct.unpack("= record_ends[-1]: + if len(record_ends) == 1: + # If it's the last one, we finished + break + else: + # Otherwise keep reading the previous one + record_ends.pop() + path_parts.pop() + iso.seek(record_pos.pop() + pvd_off) + continue + + # Parse the record + inode = iso.tell() + dr_len = struct.unpack(" None: + for file in file_info.files: + print(f"SAVING {file.path.as_posix()}") + + final_path = base_folder / file.path + final_path.parent.mkdir(exist_ok=True, parents=True) + iso.seek(file.lba) + + with open(final_path, "wb+") as f: + f.write(iso.read(file.size)) + + def dump_iso(iso_path: Path, filelist: Path, iso_files: Path) -> None: if iso_path.exists() is False: print(f"Could not to find '{iso_path.name}'!") return - iso_files.mkdir(parents=True, exist_ok=True) - with open(iso_path, "rb") as iso: # Sanity check - assert check_pvd(iso, 0x8000), "No valid PVD found in Layer0!" + assert check_pvd(iso, LAYER0_PVD_LOCATION), "No valid PVD found in Layer0!" # Test dual-layer-dness - iso.seek(0x8050) - layer0_sector_count = struct.unpack("") + print() else: print("WARNING: Iso data suggest this is a double layer image") - print(" but no valid PVD was found for Layer1, iso might be corrupt") + print( + " but no valid PVD was found for Layer1, iso might be corrupt" + ) + print() + layer0_data = dump_dir_records(iso, LAYER0_PVD_LOCATION, 0) + layer0_data.files.sort( + key=lambda x: x.lba + ) # The files are ordered based on their disc position - path_parts = [] - record_ends = [] - record_pos = [] - file_info = FileListInfo([], 0) - - # get the root directory record off the PVD in Layer1 if has_second_layer: - iso.seek(layer1_pvd_pos + 0x9E) - dr_data_pos, dr_data_len = struct.unpack("= record_ends[-1]: - if len(record_ends) == 2 and has_second_layer: - print("") - print("< Dumping Second Layer >") - print("") - path_parts.append("") - read_offset = layer1_pvd_pos - (SECTOR_SIZE * 0x10) - in_layer1 = True - - if len(record_ends) == 1: - # If it's the last one, we finished - break - else: - # Otherwise keep reading the previous one - record_ends.pop() - path_parts.pop() - iso.seek(record_pos.pop() + read_offset) - continue + if has_second_layer: + print("\n< SECOND LAYER >\n") - # Parse the record - inode = iso.tell() - print(inode) - dr_len = struct.unpack("