Added BaseHeader for superclass

This commit is contained in:
Rob McMullen 2017-02-23 13:02:56 -08:00
parent 04edbed853
commit 35c13bb9d5
2 changed files with 96 additions and 70 deletions

View File

@ -8,7 +8,74 @@ import logging
log = logging.getLogger(__name__)
class AtrHeader(object):
class BaseHeader(object):
file_format = "generic" # text descriptor of file format
def __init__(self, sector_size=256, initial_sectors=0, vtoc_sector=0, starting_sector_label=0):
self.image_size = 0
self.sector_size = sector_size
self.initial_sector_size = 0
self.num_initial_sectors = 0
self.crc = 0
self.unused = 0
self.flags = 0
self.header_offset = 0
self.starting_sector_label = starting_sector_label
self.max_sectors = 0 # number of sectors, -1 is unlimited
self.tracks_per_disk = 0
self.sectors_per_track = 0
self.first_vtoc = vtoc_sector
self.num_vtoc = 1
self.extra_vtoc = []
self.first_directory = 0
self.num_directory = 0
def __len__(self):
return self.header_offset
def to_array(self):
header_bytes = np.zeros([self.header_offset], dtype=np.uint8)
self.encode(header_bytes)
return header_bytes
def encode(self, header_bytes):
"""Subclasses should override this to put the byte values into the
header.
"""
return
def sector_is_valid(self, sector):
return (self.max_sectors < 0) | (sector >= self.starting_sector_label and sector < (self.max_sectors + self.starting_sector_label))
def get_pos(self, sector):
"""Get index (into the raw data of the disk image) of start of sector
This base class method assumes the sectors are one after another, in
order starting from the beginning of the raw data.
"""
if not self.sector_is_valid(sector):
raise ByteNotInFile166("Sector %d out of range" % sector)
pos = sector * self.sector_size + self.header_offset
size = self.sector_size
return pos, size
def sector_from_track(self, track, sector):
return (track * self.sectors_per_track) + sector
def track_from_sector(self, sector):
track, sector = divmod(sector, self.sectors_per_track)
return track, sector
def check_size(self, size):
raise InvalidDiskImage("BaseHeader subclasses need custom checks for size")
def strict_check(self, image):
pass
class AtrHeader(BaseHeader):
# ATR Format described in http://www.atarimax.com/jindroush.atari.org/afmtatr.html
format = np.dtype([
('wMagic', '<u2'),
@ -22,16 +89,7 @@ class AtrHeader(object):
file_format = "ATR"
def __init__(self, bytes=None, sector_size=128, initial_sectors=3, create=False):
self.image_size = 0
self.sector_size = sector_size
self.crc = 0
self.unused = 0
self.flags = 0
self.header_offset = 0
self.starting_sector_label = 1
self.initial_sector_size = sector_size
self.num_initial_sectors = initial_sectors
self.max_sectors = 0
BaseHeader.__init__(self, sector_size, initial_sectors, 360)
if create:
self.header_offset = 16
self.check_size(0)
@ -54,11 +112,7 @@ class AtrHeader(object):
def __str__(self):
return "%s Disk Image (size=%d (%dx%db), crc=%d flags=%d unused=%d)" % (self.file_format, self.image_size, self.max_sectors, self.sector_size, self.crc, self.flags, self.unused)
def __len__(self):
return self.header_offset
def to_array(self):
raw = np.zeros([16], dtype=np.uint8)
def encode(self, raw):
values = raw.view(dtype=self.format)[0]
values[0] = 0x296
paragraphs = self.image_size / 16
@ -89,15 +143,15 @@ class AtrHeader(object):
self.num_initial_sectors = 3
else:
self.image_size = size
self.first_vtoc = 360
self.num_vtoc = 1
self.first_directory = 361
self.num_directory = 8
self.tracks_per_disk = 40
self.sectors_per_track = 18
initial_bytes = self.initial_sector_size * self.num_initial_sectors
self.max_sectors = ((self.image_size - initial_bytes) / self.sector_size) + self.num_initial_sectors
def strict_check(self, image):
pass
def sector_is_valid(self, sector):
return sector > 0 and sector <= self.max_sectors
def get_pos(self, sector):
if not self.sector_is_valid(sector):
raise ByteNotInFile166("Sector %d out of range" % sector)

View File

@ -1,7 +1,7 @@
import numpy as np
from errors import *
from diskimages import AtrHeader, DiskImageBase, Directory, VTOC, WriteableSector, BaseSectorList
from diskimages import BaseHeader, DiskImageBase, Directory, VTOC, WriteableSector, BaseSectorList
from segments import DefaultSegment, EmptySegment, ObjSegment, RawTrackSectorSegment, SegmentSaver
import logging
@ -279,59 +279,30 @@ class Dos33Dirent(object):
self.deleted = False
class Dos33Header(AtrHeader):
class Dos33Header(BaseHeader):
file_format = "DOS 3.3"
def __init__(self):
AtrHeader.__init__(self, None, 256, 0)
self.starting_sector_label = 0
self.header_offset = 0
self.sector_order = range(16)
self.vtoc_sector = 17 * 16
self.tracks_per_disk = 0
self.sectors_per_track = 0
self.max_sectors = -1
BaseHeader.__init__(self, 256)
def __str__(self):
return "%s Disk Image (size=%d (%dx%db)" % (self.file_format, self.image_size, self.max_sectors, self.sector_size)
def __len__(self):
return 0
def to_array(self):
raw = np.zeros([0], dtype=np.uint8)
return raw
def check_size(self, size):
AtrHeader.check_size(self, size)
if size != 143360:
raise InvalidDiskImage("Incorrect size for DOS 3.3 image")
self.first_vtoc = 17 * 16
self.num_vtoc = 1
self.first_directory = self.first_vtoc + 15
self.num_directory = 8
self.tracks_per_disk = 35
self.sectors_per_track = 16
self.max_sectors = self.tracks_per_disk * self.sectors_per_track
def sector_is_valid(self, sector):
# DOS 3.3 sectors count from 0
return (self.max_sectors < 0) | (sector >= 0 and sector < self.max_sectors)
def get_pos(self, sector):
if not self.sector_is_valid(sector):
raise ByteNotInFile166("Sector %d out of range" % sector)
pos = sector * self.sector_size
size = self.sector_size
return pos, size
def sector_from_track(self, track, sector):
return track * 16 + sector
def track_from_sector(self, sector):
track, sector = divmod(sector, 16)
return track, sector
class Dos33DiskImage(DiskImageBase):
def __init__(self, rawdata, filename=""):
self.first_catalog = 0
self.first_directory = 0
DiskImageBase.__init__(self, rawdata, filename)
def __str__(self):
@ -367,10 +338,10 @@ class Dos33DiskImage(DiskImageBase):
if (magic == [1, 56, 176, 3]).all():
raise InvalidDiskImage("ProDOS format found; not DOS 3.3 image")
swap_order = False
data, style = self.get_sectors(self.header.vtoc_sector)
data, style = self.get_sectors(self.header.first_vtoc)
if data[3] == 3:
if data[1] < 35 and data[2] < 16:
data, style = self.get_sectors(self.header.vtoc_sector + 14)
data, style = self.get_sectors(self.header.first_vtoc + 14)
if data[2] != 13:
swap_order = True
else:
@ -397,17 +368,18 @@ class Dos33DiskImage(DiskImageBase):
])
def get_vtoc(self):
data, style = self.get_sectors(self.header.vtoc_sector)
data, style = self.get_sectors(self.header.first_vtoc)
values = data[0:self.vtoc_type.itemsize].view(dtype=self.vtoc_type)[0]
self.first_catalog = self.header.sector_from_track(values[1], values[2])
self.assert_valid_sector(self.first_catalog)
self.total_sectors = int(values['num_tracks']) * int(values['sectors_per_track'])
self.first_directory = self.header.sector_from_track(values['cat_track'], values['cat_sector'])
self.sector_size = int(values['bytes_per_sector'])
self.max_sectors = int(values['num_tracks']) * int(values['sectors_per_track'])
self.dos_release = values['dos_release']
self.last_track_num = values['last_track']
self.track_alloc_dir = values['track_dir']
self.assert_valid_sector(self.first_directory)
def get_directory(self, directory=None):
sector = self.first_catalog
sector = self.first_directory
num = 0
files = []
while sector > 0:
@ -451,8 +423,8 @@ class Dos33DiskImage(DiskImageBase):
r = self.rawdata
segments = []
addr = 0
start, count = self.get_contiguous_sectors(self.header.vtoc_sector, 1)
segment = RawTrackSectorSegment(r[start:start+count], self.header.vtoc_sector, 1, count, 0, 0, self.header.sector_size, name="VTOC")
start, count = self.get_contiguous_sectors(self.header.first_vtoc, 1)
segment = RawTrackSectorSegment(r[start:start+count], self.header.first_vtoc, 1, count, 0, 0, self.header.sector_size, name="VTOC")
segments.append(segment)
return segments
@ -460,7 +432,7 @@ class Dos33DiskImage(DiskImageBase):
byte_order = []
r = self.rawdata
segments = []
sector = self.first_catalog
sector = self.first_directory
while sector > 0:
self.assert_valid_sector(sector)
print "reading catalog sector", sector
@ -474,7 +446,7 @@ class Dos33DiskImage(DiskImageBase):
def get_next_directory_sector(self, sector):
if sector == -1:
sector = self.first_catalog
sector = self.first_directory
print "reading catalog sector", sector
self.assert_valid_sector(sector)
raw, _, _ = self.get_raw_bytes(sector)