Skip to content

Commit e47fcad

Browse files
Darkhood148TiCoKH
authored andcommitted
DEVTOOLS: COMPANION: Add autodetection of file system and extensions if unspecified
Add functions which detect the file system (which was provided on discord thanks to eintei) and extensions if not specified by the user; combine iso9660, hfs and hybrid parsers into one common iso parser
1 parent dfc4b3e commit e47fcad

File tree

1 file changed

+100
-77
lines changed

1 file changed

+100
-77
lines changed

devtools/dumper-companion.py

Lines changed: 100 additions & 77 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
from __future__ import annotations
1919

2020
import argparse
21+
import copy
2122
import logging
2223
import os
2324
import sys
@@ -290,6 +291,82 @@ def encode_string(args: argparse.Namespace) -> int:
290291
return 0
291292

292293

294+
def check_extension(args):
295+
args_copy = copy.copy(args)
296+
args_copy.dryrun = True
297+
extensions = ['joliet', 'rr', 'udf']
298+
args_copy.dir = args.dir.joinpath('test')
299+
args_copy.fs = 'iso9660'
300+
args.silent = True
301+
for extension in extensions:
302+
args_copy.extension = extension
303+
try:
304+
extract_volume_iso(args_copy)
305+
except Exception as e:
306+
pass
307+
else:
308+
return extension
309+
310+
311+
def check_fs(iso):
312+
APPLE_PM_SIGNATURE = b"PM\x00\x00"
313+
SECTOR_SIZE = 512
314+
315+
disk_formats = []
316+
f = open(iso, "rb")
317+
318+
# ISO Primary Volume Descriptor
319+
f.seek(64 * SECTOR_SIZE)
320+
if f.read(6) == b"\x01CD001":
321+
# print('Found ISO PVD')
322+
disk_formats.append("iso9660")
323+
324+
f.seek(0)
325+
mac_1 = f.read(4)
326+
f.seek(1 * SECTOR_SIZE)
327+
mac_2 = f.read(4)
328+
f.seek(2 * SECTOR_SIZE)
329+
mac_3 = f.read(2)
330+
if mac_2 == APPLE_PM_SIGNATURE:
331+
partition_num = 1
332+
while True:
333+
num_partitions, partition_start, partition_size = unpack(">III", f.read(12))
334+
f.seek(32, 1)
335+
partition_type = f.read(32).decode("mac-roman").split("\x00")[0]
336+
if partition_type == "Apple_HFS":
337+
disk_formats.append("hfs")
338+
break
339+
# Check if there are more partitions
340+
if partition_num <= num_partitions:
341+
# Move onto the next partition
342+
partition_num += 1
343+
f.seek(partition_num * SECTOR_SIZE + 4)
344+
# Bootable Mac-only disc
345+
elif mac_1 == b"LK\x60\x00" and mac_3 == b"BD":
346+
disk_formats.append("hfs")
347+
348+
if len(disk_formats) > 1:
349+
return 'hybrid'
350+
else:
351+
return disk_formats[0]
352+
353+
354+
def extract_iso(args: argparse.Namespace):
355+
if not args.fs:
356+
args.fs = check_fs(args.src)
357+
print('Detected filesystem:', args.fs)
358+
if (args.fs == 'hybrid' or args.fs == 'iso9660') and not args.extension:
359+
args.extension = check_extension(args)
360+
print('Detected extension:', args.extension)
361+
362+
if args.fs == 'iso9660':
363+
extract_volume_iso(args)
364+
elif args.fs == 'hfs':
365+
extract_volume_hfs(args)
366+
else:
367+
extract_volume_hybrid(args)
368+
369+
293370
def extract_volume_hfs(args: argparse.Namespace) -> int:
294371
"""Extract an HFS volume"""
295372
source_volume: Path = args.src
@@ -381,15 +458,15 @@ def extract_volume_iso(args: argparse.Namespace):
381458
joined_path = os.path.join(pwd, dir)
382459
if not dryrun:
383460
os.makedirs(joined_path, exist_ok=True)
384-
else:
461+
elif not args.silent:
385462
print(joined_path)
386463

387464
if dryrun:
388465
continue
389466

390467
for file in filelist:
391468
filename = file.split(';')[0]
392-
iso_file_path = os.path.join(dirname, filename)
469+
iso_file_path = os.path.join(dirname, file)
393470
with open(os.path.join(pwd, filename), 'wb') as f:
394471
arg[path_type] = iso_file_path
395472
iso.get_file_from_iso_fp(outfp=f, **arg)
@@ -409,15 +486,13 @@ def extract_volume_hybrid(args: argparse.Namespace):
409486

410487
logging.info(f"Loading {source_volume} ...")
411488

412-
if not args.macdump and not args.iso9660dump:
413-
logging.error("Please provide at least one dump for the hybrid drive")
414-
return
415-
if args.macdump:
416-
args.dir = args.macdump
417-
extract_volume_hfs(args)
418-
if args.iso9660dump:
419-
args.dir = args.iso9660dump
420-
extract_volume_iso(args)
489+
main_dir = args.dir
490+
491+
args.dir = main_dir.joinpath('hfs')
492+
extract_volume_hfs(args)
493+
494+
args.dir = main_dir.joinpath('iso9660')
495+
extract_volume_iso(args)
421496

422497

423498
def extract_partition(args: argparse.Namespace, vol) -> int:
@@ -811,91 +886,39 @@ def generate_parser() -> argparse.ArgumentParser:
811886
"""
812887
parser = argparse.ArgumentParser()
813888
subparsers = parser.add_subparsers()
814-
parser_hfs = subparsers.add_parser("hfs", help="Dump HFS ISOs")
889+
parser_iso = subparsers.add_parser("iso", help="Dump HFS ISOs")
815890

816-
parser_hfs.add_argument("src", metavar="INPUT", type=Path, help="Disk image")
817-
parser_hfs.add_argument(
891+
parser_iso.add_argument("src", metavar="INPUT", type=Path, help="Disk image")
892+
parser_iso.add_argument(
818893
"--nopunycode", action="store_true", help="never encode pathnames into punycode"
819894
)
820-
parser_hfs.add_argument(
895+
parser_iso.add_argument(
821896
"--japanese", action="store_true", help="read MacJapanese HFS"
822897
)
823-
parser_hfs.add_argument(
898+
parser_iso.add_argument(
824899
"--dryrun", action="store_true", help="do not write any files"
825900
)
826-
parser_hfs.add_argument(
901+
parser_iso.add_argument(
827902
"--log", metavar="LEVEL", help="set logging level", default="INFO"
828903
)
829-
parser_hfs.add_argument(
904+
parser_iso.add_argument(
830905
"--forcemacbinary",
831906
action="store_true",
832907
help="always encode using MacBinary, even for files with no resource fork",
833908
)
834-
parser_hfs.add_argument(
909+
parser_iso.add_argument(
835910
"--addmacbinaryext",
836911
action="store_true",
837912
help="add .bin extension when using MacBinary",
838913
)
839-
parser_hfs.add_argument(
840-
"dir", metavar="OUTPUT", type=Path, help="Destination folder"
841-
)
842-
parser_hfs.set_defaults(func=extract_volume_hfs)
843-
844-
parser_iso9660 = subparsers.add_parser(
845-
"iso9660", help="Dump ISO9660 ISOs"
846-
)
847-
parser_iso9660.add_argument(
848-
"--log", metavar="LEVEL", help="set logging level", default="INFO"
849-
)
850-
parser_iso9660.add_argument("--extension", choices=['joliet', 'rr', 'udf'], metavar="EXTENSION", help="Use if the iso9660 has an extension")
851-
parser_iso9660.add_argument(
852-
"--nopunycode", action="store_true", help="never encode pathnames into punycode"
853-
)
854-
parser_iso9660.add_argument(
855-
"--dryrun", action="store_true", help="do not write any files"
856-
)
857-
parser_iso9660.add_argument(
858-
"--japanese", action="store_true", help="read MacJapanese HFS"
859-
)
860-
parser_iso9660.add_argument("src", metavar="INPUT", type=Path, help="Disk image")
861-
parser_iso9660.add_argument(
914+
parser_iso.add_argument("--extension", choices=['joliet', 'rr', 'udf'], metavar="EXTENSION",
915+
help="Use if the iso9660 has an extension")
916+
parser_iso.add_argument("--fs", choices=['iso9660', 'hfs', 'hybrid'], metavar="FILE_SYSTEM",
917+
help="Specify the file system of the ISO")
918+
parser_iso.add_argument(
862919
"dir", metavar="OUTPUT", type=Path, help="Destination folder"
863920
)
864-
parser_iso9660.set_defaults(func=extract_volume_iso)
865-
866-
parser_hybrid = subparsers.add_parser(
867-
"hybrid", help="Dump Hybrid ISOs"
868-
)
869-
parser_hybrid.add_argument("src", metavar="INPUT", type=Path, help="Disk image")
870-
parser_hybrid.add_argument(
871-
"--nopunycode", action="store_true", help="never encode pathnames into punycode"
872-
)
873-
parser_hybrid.add_argument(
874-
"--japanese", action="store_true", help="read MacJapanese HFS"
875-
)
876-
parser_hybrid.add_argument(
877-
"--dryrun", action="store_true", help="do not write any files"
878-
)
879-
parser_hybrid.add_argument(
880-
"--log", metavar="LEVEL", help="set logging level", default="INFO"
881-
)
882-
parser_hybrid.add_argument(
883-
"--forcemacbinary",
884-
action="store_true",
885-
help="always encode using MacBinary, even for files with no resource fork",
886-
)
887-
parser_hybrid.add_argument(
888-
"--addmacbinaryext",
889-
action="store_true",
890-
help="add .bin extension when using MacBinary",
891-
)
892-
parser_hybrid.add_argument(
893-
"--macdump", metavar="OUTPUT", type=Path, help="Destination Folder for HFS Dump"
894-
)
895-
parser_hybrid.add_argument(
896-
"--iso9660dump", metavar="OUTPUT", type=Path, help="Destination Folder for ISO9660 Dump"
897-
)
898-
parser_hybrid.set_defaults(func=extract_volume_hybrid)
921+
parser_iso.set_defaults(func=extract_iso)
899922

900923
parser_dir = subparsers.add_parser(
901924
"dir", help="Punyencode all files and dirs in place"

0 commit comments

Comments
 (0)