mirror of
https://github.com/robmcmullen/atrcopy.git
synced 2024-11-26 08:49:50 +00:00
Added BaseHeader for superclass
This commit is contained in:
parent
04edbed853
commit
35c13bb9d5
@ -8,7 +8,74 @@ import logging
|
|||||||
log = logging.getLogger(__name__)
|
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
|
# ATR Format described in http://www.atarimax.com/jindroush.atari.org/afmtatr.html
|
||||||
format = np.dtype([
|
format = np.dtype([
|
||||||
('wMagic', '<u2'),
|
('wMagic', '<u2'),
|
||||||
@ -22,16 +89,7 @@ class AtrHeader(object):
|
|||||||
file_format = "ATR"
|
file_format = "ATR"
|
||||||
|
|
||||||
def __init__(self, bytes=None, sector_size=128, initial_sectors=3, create=False):
|
def __init__(self, bytes=None, sector_size=128, initial_sectors=3, create=False):
|
||||||
self.image_size = 0
|
BaseHeader.__init__(self, sector_size, initial_sectors, 360)
|
||||||
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
|
|
||||||
if create:
|
if create:
|
||||||
self.header_offset = 16
|
self.header_offset = 16
|
||||||
self.check_size(0)
|
self.check_size(0)
|
||||||
@ -54,11 +112,7 @@ class AtrHeader(object):
|
|||||||
def __str__(self):
|
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)
|
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):
|
def encode(self, raw):
|
||||||
return self.header_offset
|
|
||||||
|
|
||||||
def to_array(self):
|
|
||||||
raw = np.zeros([16], dtype=np.uint8)
|
|
||||||
values = raw.view(dtype=self.format)[0]
|
values = raw.view(dtype=self.format)[0]
|
||||||
values[0] = 0x296
|
values[0] = 0x296
|
||||||
paragraphs = self.image_size / 16
|
paragraphs = self.image_size / 16
|
||||||
@ -89,14 +143,14 @@ class AtrHeader(object):
|
|||||||
self.num_initial_sectors = 3
|
self.num_initial_sectors = 3
|
||||||
else:
|
else:
|
||||||
self.image_size = size
|
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
|
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
|
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):
|
def get_pos(self, sector):
|
||||||
if not self.sector_is_valid(sector):
|
if not self.sector_is_valid(sector):
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
import numpy as np
|
import numpy as np
|
||||||
|
|
||||||
from errors import *
|
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
|
from segments import DefaultSegment, EmptySegment, ObjSegment, RawTrackSectorSegment, SegmentSaver
|
||||||
|
|
||||||
import logging
|
import logging
|
||||||
@ -279,59 +279,30 @@ class Dos33Dirent(object):
|
|||||||
self.deleted = False
|
self.deleted = False
|
||||||
|
|
||||||
|
|
||||||
class Dos33Header(AtrHeader):
|
class Dos33Header(BaseHeader):
|
||||||
file_format = "DOS 3.3"
|
file_format = "DOS 3.3"
|
||||||
|
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
AtrHeader.__init__(self, None, 256, 0)
|
BaseHeader.__init__(self, 256)
|
||||||
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
|
|
||||||
|
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
return "%s Disk Image (size=%d (%dx%db)" % (self.file_format, self.image_size, self.max_sectors, self.sector_size)
|
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):
|
def check_size(self, size):
|
||||||
AtrHeader.check_size(self, size)
|
|
||||||
if size != 143360:
|
if size != 143360:
|
||||||
raise InvalidDiskImage("Incorrect size for DOS 3.3 image")
|
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.tracks_per_disk = 35
|
||||||
self.sectors_per_track = 16
|
self.sectors_per_track = 16
|
||||||
self.max_sectors = self.tracks_per_disk * self.sectors_per_track
|
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):
|
class Dos33DiskImage(DiskImageBase):
|
||||||
def __init__(self, rawdata, filename=""):
|
def __init__(self, rawdata, filename=""):
|
||||||
self.first_catalog = 0
|
self.first_directory = 0
|
||||||
DiskImageBase.__init__(self, rawdata, filename)
|
DiskImageBase.__init__(self, rawdata, filename)
|
||||||
|
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
@ -367,10 +338,10 @@ class Dos33DiskImage(DiskImageBase):
|
|||||||
if (magic == [1, 56, 176, 3]).all():
|
if (magic == [1, 56, 176, 3]).all():
|
||||||
raise InvalidDiskImage("ProDOS format found; not DOS 3.3 image")
|
raise InvalidDiskImage("ProDOS format found; not DOS 3.3 image")
|
||||||
swap_order = False
|
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[3] == 3:
|
||||||
if data[1] < 35 and data[2] < 16:
|
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:
|
if data[2] != 13:
|
||||||
swap_order = True
|
swap_order = True
|
||||||
else:
|
else:
|
||||||
@ -397,17 +368,18 @@ class Dos33DiskImage(DiskImageBase):
|
|||||||
])
|
])
|
||||||
|
|
||||||
def get_vtoc(self):
|
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]
|
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.first_directory = self.header.sector_from_track(values['cat_track'], values['cat_sector'])
|
||||||
self.assert_valid_sector(self.first_catalog)
|
self.sector_size = int(values['bytes_per_sector'])
|
||||||
self.total_sectors = int(values['num_tracks']) * int(values['sectors_per_track'])
|
self.max_sectors = int(values['num_tracks']) * int(values['sectors_per_track'])
|
||||||
self.dos_release = values['dos_release']
|
self.dos_release = values['dos_release']
|
||||||
self.last_track_num = values['last_track']
|
self.last_track_num = values['last_track']
|
||||||
self.track_alloc_dir = values['track_dir']
|
self.track_alloc_dir = values['track_dir']
|
||||||
|
self.assert_valid_sector(self.first_directory)
|
||||||
|
|
||||||
def get_directory(self, directory=None):
|
def get_directory(self, directory=None):
|
||||||
sector = self.first_catalog
|
sector = self.first_directory
|
||||||
num = 0
|
num = 0
|
||||||
files = []
|
files = []
|
||||||
while sector > 0:
|
while sector > 0:
|
||||||
@ -451,8 +423,8 @@ class Dos33DiskImage(DiskImageBase):
|
|||||||
r = self.rawdata
|
r = self.rawdata
|
||||||
segments = []
|
segments = []
|
||||||
addr = 0
|
addr = 0
|
||||||
start, count = self.get_contiguous_sectors(self.header.vtoc_sector, 1)
|
start, count = self.get_contiguous_sectors(self.header.first_vtoc, 1)
|
||||||
segment = RawTrackSectorSegment(r[start:start+count], self.header.vtoc_sector, 1, count, 0, 0, self.header.sector_size, name="VTOC")
|
segment = RawTrackSectorSegment(r[start:start+count], self.header.first_vtoc, 1, count, 0, 0, self.header.sector_size, name="VTOC")
|
||||||
segments.append(segment)
|
segments.append(segment)
|
||||||
return segments
|
return segments
|
||||||
|
|
||||||
@ -460,7 +432,7 @@ class Dos33DiskImage(DiskImageBase):
|
|||||||
byte_order = []
|
byte_order = []
|
||||||
r = self.rawdata
|
r = self.rawdata
|
||||||
segments = []
|
segments = []
|
||||||
sector = self.first_catalog
|
sector = self.first_directory
|
||||||
while sector > 0:
|
while sector > 0:
|
||||||
self.assert_valid_sector(sector)
|
self.assert_valid_sector(sector)
|
||||||
print "reading catalog sector", sector
|
print "reading catalog sector", sector
|
||||||
@ -474,7 +446,7 @@ class Dos33DiskImage(DiskImageBase):
|
|||||||
|
|
||||||
def get_next_directory_sector(self, sector):
|
def get_next_directory_sector(self, sector):
|
||||||
if sector == -1:
|
if sector == -1:
|
||||||
sector = self.first_catalog
|
sector = self.first_directory
|
||||||
print "reading catalog sector", sector
|
print "reading catalog sector", sector
|
||||||
self.assert_valid_sector(sector)
|
self.assert_valid_sector(sector)
|
||||||
raw, _, _ = self.get_raw_bytes(sector)
|
raw, _, _ = self.get_raw_bytes(sector)
|
||||||
|
Loading…
Reference in New Issue
Block a user