Skip to content

Commit 46ae5a8

Browse files
Darkhood148TiCoKH
authored andcommitted
DEVTOOLS: DUMPERCOMPANION: support iso9660 and hybrid disk images
Add parsers to handle iso9660 and hybrid disk images Add functions for extracting iso9660 and hybrid disk images
1 parent 9320ba4 commit 46ae5a8

File tree

1 file changed

+115
-12
lines changed

1 file changed

+115
-12
lines changed

devtools/dumper-companion.py

Lines changed: 115 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
# See https://wiki.scummvm.org/index.php?title=HOWTO-Dump_Macintosh_Media for
88
# the full documentation
99
#
10-
# prerequisites: pip3 install machfs
10+
# prerequisites: pip3 install machfs pycdlib
1111
#
1212
# Development information:
1313
# This file contains tests. They can be run with:
@@ -31,6 +31,7 @@
3131
from typing import Any
3232

3333
import machfs
34+
import pycdlib
3435

3536

3637
# fmt: off
@@ -289,7 +290,7 @@ def encode_string(args: argparse.Namespace) -> int:
289290
return 0
290291

291292

292-
def extract_volume(args: argparse.Namespace) -> int:
293+
def extract_volume_hfs(args: argparse.Namespace) -> int:
293294
"""Extract an HFS volume"""
294295
source_volume: Path = args.src
295296
loglevel: str = args.log
@@ -340,6 +341,62 @@ def extract_volume(args: argparse.Namespace) -> int:
340341
extract_partition(args, vol)
341342

342343

344+
def extract_volume_iso(args: argparse.Namespace):
345+
"""Extract an ISO volume"""
346+
source_volume = args.src
347+
loglevel: str = args.log
348+
349+
numeric_level = getattr(logging, loglevel.upper(), None)
350+
if not isinstance(numeric_level, int):
351+
raise ValueError("Invalid log level: %s" % loglevel)
352+
logging.basicConfig(format="%(levelname)s: %(message)s", level=numeric_level)
353+
354+
logging.info(f"Loading {source_volume} ...")
355+
356+
iso = pycdlib.PyCdlib()
357+
iso.open(source_volume)
358+
359+
output_dir = str(args.dir)
360+
361+
for dirname, dirlist, filelist in iso.walk(iso_path='/'):
362+
pwd = output_dir + dirname
363+
for dir in dirlist:
364+
joined_path = os.path.join(pwd, dir)
365+
os.makedirs(joined_path, exist_ok=True)
366+
for file in filelist:
367+
filename = file.split(';')[0]
368+
if dirname != '/':
369+
iso_file_path = dirname + '/' + file
370+
else:
371+
iso_file_path = dirname + file
372+
with open(os.path.join(pwd, filename), 'wb') as f:
373+
iso.get_file_from_iso_fp(outfp=f, iso_path=iso_file_path)
374+
375+
iso.close()
376+
377+
378+
def extract_volume_hybrid(args: argparse.Namespace):
379+
source_volume = args.src
380+
loglevel: str = args.log
381+
382+
numeric_level = getattr(logging, loglevel.upper(), None)
383+
if not isinstance(numeric_level, int):
384+
raise ValueError("Invalid log level: %s" % loglevel)
385+
logging.basicConfig(format="%(levelname)s: %(message)s", level=numeric_level)
386+
387+
logging.info(f"Loading {source_volume} ...")
388+
389+
if not args.macdump and not args.iso9660dump:
390+
logging.error("Please provide at least one dump for the hybrid drive")
391+
return
392+
if args.macdump:
393+
args.dir = args.macdump
394+
extract_volume_hfs(args)
395+
if args.iso9660dump:
396+
args.dir = args.iso9660dump
397+
extract_volume_iso(args)
398+
399+
343400
def extract_partition(args: argparse.Namespace, vol) -> int:
344401
destination_dir: Path = args.dir
345402
japanese: bool = args.japanese
@@ -731,35 +788,81 @@ def generate_parser() -> argparse.ArgumentParser:
731788
"""
732789
parser = argparse.ArgumentParser()
733790
subparsers = parser.add_subparsers()
734-
parser_iso = subparsers.add_parser("iso", help="Dump HFS ISOs")
791+
parser_hfs = subparsers.add_parser("hfs", help="Dump HFS ISOs")
735792

736-
parser_iso.add_argument("src", metavar="INPUT", type=Path, help="Disk image")
737-
parser_iso.add_argument(
793+
parser_hfs.add_argument("src", metavar="INPUT", type=Path, help="Disk image")
794+
parser_hfs.add_argument(
738795
"--nopunycode", action="store_true", help="never encode pathnames into punycode"
739796
)
740-
parser_iso.add_argument(
797+
parser_hfs.add_argument(
741798
"--japanese", action="store_true", help="read MacJapanese HFS"
742799
)
743-
parser_iso.add_argument(
800+
parser_hfs.add_argument(
744801
"--dryrun", action="store_true", help="do not write any files"
745802
)
746-
parser_iso.add_argument(
803+
parser_hfs.add_argument(
747804
"--log", metavar="LEVEL", help="set logging level", default="INFO"
748805
)
749-
parser_iso.add_argument(
806+
parser_hfs.add_argument(
750807
"--forcemacbinary",
751808
action="store_true",
752809
help="always encode using MacBinary, even for files with no resource fork",
753810
)
754-
parser_iso.add_argument(
811+
parser_hfs.add_argument(
755812
"--addmacbinaryext",
756813
action="store_true",
757814
help="add .bin extension when using MacBinary",
758815
)
759-
parser_iso.add_argument(
816+
parser_hfs.add_argument(
760817
"dir", metavar="OUTPUT", type=Path, help="Destination folder"
761818
)
762-
parser_iso.set_defaults(func=extract_volume)
819+
parser_hfs.set_defaults(func=extract_volume_hfs)
820+
821+
parser_iso9660 = subparsers.add_parser(
822+
"iso9660", help="Dump ISO9660 ISOs"
823+
)
824+
parser_iso9660.add_argument(
825+
"--log", metavar="LEVEL", help="set logging level", default="INFO"
826+
)
827+
parser_iso9660.add_argument("src", metavar="INPUT", type=Path, help="Disk image")
828+
parser_iso9660.add_argument(
829+
"dir", metavar="OUTPUT", type=Path, help="Destination folder"
830+
)
831+
parser_iso9660.set_defaults(func=extract_volume_iso)
832+
833+
parser_hybrid = subparsers.add_parser(
834+
"hybrid", help="Dump Hybrid ISOs"
835+
)
836+
parser_hybrid.add_argument("src", metavar="INPUT", type=Path, help="Disk image")
837+
parser_hybrid.add_argument(
838+
"--nopunycode", action="store_true", help="never encode pathnames into punycode"
839+
)
840+
parser_hybrid.add_argument(
841+
"--japanese", action="store_true", help="read MacJapanese HFS"
842+
)
843+
parser_hybrid.add_argument(
844+
"--dryrun", action="store_true", help="do not write any files"
845+
)
846+
parser_hybrid.add_argument(
847+
"--log", metavar="LEVEL", help="set logging level", default="INFO"
848+
)
849+
parser_hybrid.add_argument(
850+
"--forcemacbinary",
851+
action="store_true",
852+
help="always encode using MacBinary, even for files with no resource fork",
853+
)
854+
parser_hybrid.add_argument(
855+
"--addmacbinaryext",
856+
action="store_true",
857+
help="add .bin extension when using MacBinary",
858+
)
859+
parser_hybrid.add_argument(
860+
"--macdump", metavar="OUTPUT", type=Path, help="Destination Folder for HFS Dump"
861+
)
862+
parser_hybrid.add_argument(
863+
"--iso9660dump", metavar="OUTPUT", type=Path, help="Destination Folder for ISO9660 Dump"
864+
)
865+
parser_hybrid.set_defaults(func=extract_volume_hybrid)
763866

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

0 commit comments

Comments
 (0)