diff --git a/atrcopy/errors.py b/atrcopy/errors.py index 8b2030a..3488115 100644 --- a/atrcopy/errors.py +++ b/atrcopy/errors.py @@ -92,9 +92,16 @@ class InvalidMediaSize(MediaError): pass -class InvalidAtrHeader(MediaError): +class InvalidHeader(MediaError): pass -class InvalidCartHeader(MediaError): +# Errors when trying to determine filesystem + +class FilesystemError(AtrError): pass + + +class IncompatibleMediaError(FilesystemError): + pass + diff --git a/atrcopy/media_type.py b/atrcopy/media_type.py index 4590333..fee688b 100644 --- a/atrcopy/media_type.py +++ b/atrcopy/media_type.py @@ -31,6 +31,7 @@ class MediaType(Segment): if self.header is not None: self.check_header() self.check_media_size() + self.check_magic() #### initialization @@ -65,6 +66,16 @@ class MediaType(Segment): """ pass + def check_magic(self): + """Subclasses should override this method if there is some "magic" + values that can identify (or rule out) this disk image class as a + canditate. + + Subclasses should raise the appropriate MediaError if the data is + incompatible with this media type. + """ + pass + def find_filesystem(self): fs = filesystem.guess_filesystem(self) if fs: diff --git a/atrcopy/media_types/atari_carts.py b/atrcopy/media_types/atari_carts.py index f67e6a5..d20961b 100644 --- a/atrcopy/media_types/atari_carts.py +++ b/atrcopy/media_types/atari_carts.py @@ -104,7 +104,7 @@ def get_cart(cart_type): try: return known_cart_types[known_cart_type_map[cart_type]] except KeyError: - raise errors.InvalidCartHeader("Unsupported cart type %d" % cart_type) + raise errors.InvalidHeader("Unsupported cart type %d" % cart_type) class A8CartHeader: @@ -120,12 +120,12 @@ class A8CartHeader: if len(data) == 16: header = data.view(dtype=self.format)[0] if header[0] != b'CART': - raise errors.InvalidCartHeader + raise errors.InvalidHeader self.cart_type = int(header[1]) self.crc = int(header[2]) self.set_type(self.cart_type) else: - raise errors.InvalidCartHeader + raise errors.InvalidHeader def __str__(self): return "%s Cartridge (atari800 type=%d size=%d, %d banks, crc=%d)" % (self.cart_name, self.cart_type, self.cart_size, self.bank_size, self.crc) @@ -150,7 +150,7 @@ class A8CartHeader: def check_media(self, media): media_size = len(media) - 16 if self.cart_size != media_size: - raise errors.InvalidCartHeader("Invalid cart size: {media_size}, expected {self.cart_size} for {self.cart_name}") + raise errors.InvalidHeader("Invalid cart size: {media_size}, expected {self.cart_size} for {self.cart_name}") class Atari8bitCart(CartImage): diff --git a/atrcopy/media_types/atari_disks.py b/atrcopy/media_types/atari_disks.py index d8ae5ef..057df42 100644 --- a/atrcopy/media_types/atari_disks.py +++ b/atrcopy/media_types/atari_disks.py @@ -27,14 +27,14 @@ class AtrHeader(Segment): if len(header) == 16: values = header.view(dtype=self.format)[0] if values[0] != 0x296: - raise errors.InvalidAtrHeader("no ATR header magic value") + raise errors.InvalidHeader("no ATR header magic value") self.image_size = (int(values[3]) * 256 * 256 + int(values[1])) * 16 self.sector_size = int(values[2]) self.crc = int(values[4]) self.unused = int(values[5]) self.flags = int(values[6]) else: - raise errors.InvalidAtrHeader("incorrect AHC header size of %d" % len(bytes)) + raise errors.InvalidHeader("incorrect AHC header size of %d" % len(bytes)) def encode(self, raw): values = raw.view(dtype=self.format)[0] @@ -51,10 +51,10 @@ class AtrHeader(Segment): def check_media(self, media): if self.sector_size != media.sector_size: - raise errors.InvalidAtrHeader("ExpectedMismatch between sector sizes: header claims {self.sector_size}, expected {media.sector_size} for {media.pretty_name}") + raise errors.InvalidHeader("ExpectedMismatch between sector sizes: header claims {self.sector_size}, expected {media.sector_size} for {media.pretty_name}") media_size = len(media) - 16 if self.image_size != media_size: - raise errors.InvalidAtrHeader("Invalid media size: header claims {self.image_size}, expected {media_size} for {media.pretty_name}") + raise errors.InvalidHeader("Invalid media size: header claims {self.image_size}, expected {media_size} for {media.pretty_name}") class AtariSingleDensity(DiskImage): @@ -71,10 +71,10 @@ class AtariSingleDensity(DiskImage): if len(header_data) == 16: try: header = AtrHeader(container) - except errors.InvalidAtrHeader: + except errors.InvalidHeader: header = None else: - raise errors.InvalidAtrHeader(f"file size {len(data)} small to be {self.pretty_name}") + raise errors.InvalidHeader(f"file size {len(data)} small to be {self.pretty_name}") return header @@ -86,6 +86,14 @@ class AtariSingleDensityShortImage(AtariSingleDensity): if size >= self.expected_size: raise errors.InvalidMediaSize(f"{self.pretty_name} must be less than size {self.expected_size}") + def check_magic(self): + # Must have an ATR header for this to be a disk image + if self.header is None: + raise errors.InvalidHeader("Must have an ATR header for a non-standard image size") + flag = self[0:2].view(dtype='