From 7a5402698467389be64b576479d4ca77877aeb4a Mon Sep 17 00:00:00 2001 From: Thomas Daede Date: Mon, 2 Oct 2023 23:13:12 -0700 Subject: [PATCH] D88: Add read support for multiple disks in one file. --- src/greaseweazle/image/a2r.py | 2 +- src/greaseweazle/image/caps.py | 2 +- src/greaseweazle/image/d64.py | 3 ++- src/greaseweazle/image/d88.py | 33 +++++++++++++++++++++++------- src/greaseweazle/image/dsk.py | 2 +- src/greaseweazle/image/edsk.py | 2 +- src/greaseweazle/image/hfe.py | 2 +- src/greaseweazle/image/image.py | 3 ++- src/greaseweazle/image/imd.py | 2 +- src/greaseweazle/image/img.py | 2 +- src/greaseweazle/image/kryoflux.py | 2 +- src/greaseweazle/image/msa.py | 2 +- src/greaseweazle/image/scp.py | 2 +- src/greaseweazle/image/td0.py | 2 +- src/greaseweazle/tools/convert.py | 4 +++- src/greaseweazle/tools/write.py | 4 +++- 16 files changed, 47 insertions(+), 22 deletions(-) diff --git a/src/greaseweazle/image/a2r.py b/src/greaseweazle/image/a2r.py index 5a9fdfc0..4f21683a 100644 --- a/src/greaseweazle/image/a2r.py +++ b/src/greaseweazle/image/a2r.py @@ -106,7 +106,7 @@ def process_rwcp(self, dat: bytes) -> None: @classmethod - def from_file(cls, name: str, _fmt) -> Image: + def from_file(cls, name: str, _fmt, _index: int = -1) -> Image: splices = None diff --git a/src/greaseweazle/image/caps.py b/src/greaseweazle/image/caps.py index 1c470cb5..947801a5 100644 --- a/src/greaseweazle/image/caps.py +++ b/src/greaseweazle/image/caps.py @@ -184,7 +184,7 @@ def get_track(self, cyl: int, head: int) -> Optional[MasterTrack]: raise NotImplementedError @classmethod - def from_file(cls, name: str, _fmt) -> Image: + def from_file(cls, name: str, _fmt, _index = -1) -> Image: caps = cls() errprefix = f'CAPS: {cls.imagetype}' diff --git a/src/greaseweazle/image/d64.py b/src/greaseweazle/image/d64.py index cb8e4a16..c7537865 100644 --- a/src/greaseweazle/image/d64.py +++ b/src/greaseweazle/image/d64.py @@ -31,7 +31,8 @@ def get_disk_id(self): return disk_id @classmethod - def from_file(cls, name: str, fmt: Optional[codec.DiskDef]) -> Image: + def from_file(cls, name: str, fmt: Optional[codec.DiskDef], + _index: int = -1) -> Image: img = super().from_file(name, fmt) assert isinstance(img, D64) disk_id = img.get_disk_id() diff --git a/src/greaseweazle/image/d88.py b/src/greaseweazle/image/d88.py index 3b90401d..0d7e2866 100644 --- a/src/greaseweazle/image/d88.py +++ b/src/greaseweazle/image/d88.py @@ -36,9 +36,32 @@ def remove_duplicate_sectors(secs) -> List[Tuple[int,int,int,int,bytes]]: return new_secs @classmethod - def from_file(cls, name: str, _fmt) -> Image: + def from_file(cls, name: str, _fmt, index: int = -1) -> Image: with open(name, "rb") as f: + f.seek(0, os.SEEK_END) + file_size = f.tell() + f.seek(0) + disk_offsets: List[int] = [] + current_disk_index = 0 + while 1: + disk_offsets.append(f.tell()) + header = struct.unpack('<16sB9xBBL', f.read(32)) + _, _, _, _, disk_size = header + if f.tell() + disk_size >= file_size: + break + f.seek(disk_offsets[current_disk_index] + disk_size) + current_disk_index += 1 + + if index < 0 and len(disk_offsets) > 1: + print('D88: Warning: Multiple disks found in image, ' + 'only using first.') + index = 0 + if index >= len(disk_offsets): + raise error.Fatal("D88: No disk with index %d in image file." + % index) + + f.seek(disk_offsets[index]) header = struct.unpack('<16sB9xBBL', f.read(32)) disk_name, terminator, write_prot, media_flag, disk_size = header track_table = [x[0] for x in struct.iter_unpack(' Image: struct.iter_unpack('= disk_size: + f.seek(disk_offsets[index] + track_offset) + if f.tell() >= disk_offsets[index] + disk_size: continue cyl = track_index // 2 head = track_index % 2 diff --git a/src/greaseweazle/image/dsk.py b/src/greaseweazle/image/dsk.py index 3651be3e..db4a8078 100644 --- a/src/greaseweazle/image/dsk.py +++ b/src/greaseweazle/image/dsk.py @@ -12,7 +12,7 @@ class DSK(IMG): @classmethod - def from_file(cls, name: str, fmt) -> Image: + def from_file(cls, name: str, fmt, _index: int = -1) -> Image: with open(name, "rb") as f: sig = f.read(16) diff --git a/src/greaseweazle/image/edsk.py b/src/greaseweazle/image/edsk.py index a95bbc05..093a9927 100644 --- a/src/greaseweazle/image/edsk.py +++ b/src/greaseweazle/image/edsk.py @@ -287,7 +287,7 @@ def addcrc(t,n): return track @classmethod - def from_file(cls, name: str, _fmt) -> Image: + def from_file(cls, name: str, _fmt, _index = -1) -> Image: with open(name, "rb") as f: dat = f.read() diff --git a/src/greaseweazle/image/hfe.py b/src/greaseweazle/image/hfe.py index f5a62c55..d69ae78b 100644 --- a/src/greaseweazle/image/hfe.py +++ b/src/greaseweazle/image/hfe.py @@ -166,7 +166,7 @@ def __init__(self) -> None: @classmethod - def from_file(cls, name: str, _fmt): + def from_file(cls, name: str, _fmt, _index = -1): with open(name, "rb") as f: dat = f.read() diff --git a/src/greaseweazle/image/image.py b/src/greaseweazle/image/image.py index 31be5e16..75a6d7ac 100644 --- a/src/greaseweazle/image/image.py +++ b/src/greaseweazle/image/image.py @@ -67,7 +67,8 @@ def max_cylinder(self): ## Read support: @classmethod - def from_file(cls, name: str, fmt: Optional[codec.DiskDef]) -> Image: + def from_file(cls, name: str, fmt: Optional[codec.DiskDef], + index: int = -1) -> Image: raise NotImplementedError def get_track(self, cyl: int, side: int) -> Optional[HasFlux]: diff --git a/src/greaseweazle/image/imd.py b/src/greaseweazle/image/imd.py index b470f5ca..b7b9d9b5 100644 --- a/src/greaseweazle/image/imd.py +++ b/src/greaseweazle/image/imd.py @@ -31,7 +31,7 @@ def __init__(self, name: str, noclobber=False): @classmethod - def from_file(cls, name: str, _fmt) -> Image: + def from_file(cls, name: str, _fmt, _index = -1) -> Image: with open(name, "rb") as f: dat = f.read() diff --git a/src/greaseweazle/image/img.py b/src/greaseweazle/image/img.py index b1beba3a..cf68c7b0 100644 --- a/src/greaseweazle/image/img.py +++ b/src/greaseweazle/image/img.py @@ -41,7 +41,7 @@ def track_list(self): @classmethod - def from_file(cls, name: str, fmt: Optional[codec.DiskDef]) -> Image: + def from_file(cls, name: str, fmt: Optional[codec.DiskDef], _index: int = -1) -> Image: with open(name, "rb") as f: dat = f.read() diff --git a/src/greaseweazle/image/kryoflux.py b/src/greaseweazle/image/kryoflux.py index b1664e24..389e9b85 100644 --- a/src/greaseweazle/image/kryoflux.py +++ b/src/greaseweazle/image/kryoflux.py @@ -51,7 +51,7 @@ def to_file(cls, name, fmt, noclobber): return kf @classmethod - def from_file(cls, name, _fmt): + def from_file(cls, name, _fmt, _index = -1): # Check that the specified raw file actually exists. with open(name, 'rb') as _: pass diff --git a/src/greaseweazle/image/msa.py b/src/greaseweazle/image/msa.py index 988f0f69..e2fa89b3 100644 --- a/src/greaseweazle/image/msa.py +++ b/src/greaseweazle/image/msa.py @@ -23,7 +23,7 @@ def __init__(self, name: str, fmt=None, noclobber=False): @classmethod - def from_file(cls, name: str, _fmt) -> Image: + def from_file(cls, name: str, _fmt, _index = -1) -> Image: with open(name, "rb") as f: dat = f.read() diff --git a/src/greaseweazle/image/scp.py b/src/greaseweazle/image/scp.py index 06263483..9d0d89a6 100644 --- a/src/greaseweazle/image/scp.py +++ b/src/greaseweazle/image/scp.py @@ -125,7 +125,7 @@ def side_count(self) -> List[int]: @classmethod - def from_file(cls, name: str, _fmt) -> Image: + def from_file(cls, name: str, _fmt, _index = -1) -> Image: splices = None diff --git a/src/greaseweazle/image/td0.py b/src/greaseweazle/image/td0.py index aca86ce2..ce320b33 100644 --- a/src/greaseweazle/image/td0.py +++ b/src/greaseweazle/image/td0.py @@ -27,7 +27,7 @@ def __init__(self) -> None: @classmethod - def from_file(cls, name: str, _fmt) -> Image: + def from_file(cls, name: str, _fmt, _index = -1) -> Image: with open(name, "rb") as f: dat = f.read() diff --git a/src/greaseweazle/tools/convert.py b/src/greaseweazle/tools/convert.py index 5e62edb6..f8cb44aa 100644 --- a/src/greaseweazle/tools/convert.py +++ b/src/greaseweazle/tools/convert.py @@ -23,7 +23,7 @@ plls = track.plls def open_input_image(args, image_class: Type[Image]) -> Image: - return image_class.from_file(args.in_file, args.fmt_cls) + return image_class.from_file(args.in_file, args.fmt_cls, int(args.disk_index)) def open_output_image(args, image_class: Type[Image]) -> Image: @@ -117,6 +117,8 @@ def main(argv) -> None: epilog=epilog) parser.add_argument("--diskdefs", help="disk definitions file") parser.add_argument("--format", help="disk format") + parser.add_argument("--disk-index", help="disk index within input " + "image file", default=-1) parser.add_argument("--tracks", type=util.TrackSet, help="which tracks to read & convert from input", metavar="TSPEC") diff --git a/src/greaseweazle/tools/write.py b/src/greaseweazle/tools/write.py index 3abf820f..0bc60c29 100644 --- a/src/greaseweazle/tools/write.py +++ b/src/greaseweazle/tools/write.py @@ -22,7 +22,7 @@ # Read and parse the image file. def open_image(args, image_class: Type[image.Image]) -> image.Image: - return image_class.from_file(args.file, args.fmt_cls) + return image_class.from_file(args.file, args.fmt_cls, int(args.disk_index)) # write_from_image: # Writes the specified image file to floppy disk. @@ -188,6 +188,8 @@ def main(argv) -> None: help="drive to read") parser.add_argument("--diskdefs", help="disk definitions file") parser.add_argument("--format", help="disk format") + parser.add_argument("--disk-index", help="disk index within image file", + default=-1) parser.add_argument("--tracks", type=util.TrackSet, metavar="TSPEC", help="which tracks to write") parser.add_argument("--pre-erase", action="store_true",