Removed SectorBuilder class; fixed DOS 3.3 track/sector list

* put SectorBuildeR functionality into DiskImage
This commit is contained in:
Rob McMullen 2017-02-23 19:13:48 -08:00
parent 9e1e60420c
commit 605f77afb3
4 changed files with 106 additions and 96 deletions

View File

@ -154,6 +154,11 @@ class AtariDosDirent(object):
def update_sector_info(self, sector_list):
self.num_sectors = sector_list.num_sectors
self.starting_sector = sector_list.first_sector
def add_metadata_sectors(self, vtoc, sector_list, header):
# no extra sectors are needed for an Atari DOS file; the links to the
# next sector is contained in the sector.
pass
def sanity_check(self, image):
if not self.in_use:
@ -367,6 +372,7 @@ class AtrHeader(BaseHeader):
self.num_directory = 8
self.tracks_per_disk = 40
self.sectors_per_track = 18
self.payload_bytes = self.sector_size - 3
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
@ -410,14 +416,6 @@ class AtariDosDiskImage(DiskImageBase):
self.vtoc2 = 0
self.first_data_after_vtoc = 369
DiskImageBase.__init__(self, *args, **kwargs)
@property
def bytes_per_sector(self):
return self.header.sector_size
@property
def payload_bytes_per_sector(self):
return self.header.sector_size - 3
@property
def writeable_sector_class(self):

View File

@ -15,6 +15,7 @@ class BaseHeader(object):
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.payload_bytes = sector_size
self.initial_sector_size = 0
self.num_initial_sectors = 0
self.crc = 0
@ -95,14 +96,6 @@ class DiskImageBase(object):
def __len__(self):
return len(self.rawdata)
@property
def bytes_per_sector(self):
raise NotImplementedError
@property
def payload_bytes_per_sector(self):
raise NotImplementedError
@property
def writeable_sector_class(self):
return WriteableSector
@ -118,10 +111,6 @@ class DiskImageBase(object):
@property
def directory_class(self):
return Directory
@property
def sector_builder_class(self):
return SectorBuilder
def set_filename(self, filename):
if "." in filename:
@ -334,7 +323,7 @@ class DiskImageBase(object):
self.get_directory(directory)
dirent = directory.add_dirent(filename, filetype)
data = to_numpy(data)
sector_list = self.sector_builder_class(self.header, self.payload_bytes_per_sector, data, self.writeable_sector_class)
sector_list = self.build_sectors(data)
vtoc_segments = self.get_vtoc_segments()
vtoc = self.vtoc_class(self.header, vtoc_segments)
directory.save_dirent(self, dirent, vtoc, sector_list)
@ -348,6 +337,17 @@ class DiskImageBase(object):
finally:
self.get_metadata()
def build_sectors(self, data):
data = to_numpy(data)
sectors = BaseSectorList(self.header.sector_size)
index = 0
while index < len(data):
count = min(self.header.payload_bytes, len(data) - index)
sector = self.header.create_sector(data[index:index + count])
sectors.append(sector)
index += count
return sectors
def write_sector_list(self, sector_list):
for sector in sector_list:
pos, size = self.header.get_pos(sector.sector_num)

View File

@ -1,13 +1,42 @@
import numpy as np
from errors import *
from diskimages import BaseHeader, DiskImageBase, Directory, VTOC, WriteableSector, BaseSectorList, SectorBuilder
from diskimages import BaseHeader, DiskImageBase, Directory, VTOC, WriteableSector, BaseSectorList
from segments import DefaultSegment, EmptySegment, ObjSegment, RawTrackSectorSegment, SegmentSaver
import logging
log = logging.getLogger(__name__)
class Dos33TSSector(WriteableSector):
def __init__(self, header, sector_list, start, end):
WriteableSector.__init__(self, header.sector_size)
self.header = header
self.used = header.sector_size
self.set_tslist(sector_list, start, end)
def set_tslist(self, sector_list, start, end):
index = 0xc
for i in range(start, end):
sector = sector_list[i]
t, s = self.header.track_from_sector(sector.sector_num)
self.data[index] = t
self.data[index + 1] = s
log.debug("tslist entry #%d: %d, %d" % (index, t, s))
index += 2
@property
def next_sector_num(self):
return self._next_sector_num
@next_sector_num.setter
def next_sector_num(self, value):
self._next_sector_num = value
t, s = self.header.track_from_sector(value)
self.data[1] = t
self.data[2] = s
class Dos33VTOC(VTOC):
max_tracks = (256 - 0x38) / 4 # 50, but kept here in case sector size changed
max_sectors = max_tracks * 16
@ -199,6 +228,22 @@ class Dos33Dirent(object):
def update_sector_info(self, sector_list):
self.num_sectors = sector_list.num_sectors
self.starting_sector = sector_list.first_sector
def add_metadata_sectors(self, vtoc, sector_list, header):
"""Add track/sector list
"""
tslist = BaseSectorList(header.sector_size)
for start in range(0, len(sector_list), header.ts_pairs):
end = min(start + header.ts_pairs, len(sector_list))
log.debug("ts: %d-%d" % (start, end))
s = Dos33TSSector(header, sector_list, start, end)
s.ts_start, s.ts_end = start, end
tslist.append(s)
self.num_tslists = len(tslist)
vtoc.assign_sector_numbers(self, tslist)
sector_list.extend(tslist)
self.track, self.sector = header.track_from_sector(tslist[0].sector_num)
log.debug("track/sector lists:\n%s" % str(tslist))
def sanity_check(self, image):
if self.deleted:
@ -279,14 +324,6 @@ class Dos33Dirent(object):
self.deleted = False
class Dos33SectorBuilder(SectorBuilder):
def calc_extra_sectors(self):
"""Add track/sector list
"""
for ts_group_start in range(0, len(self), self.header.ts_pairs):
print ts_group_start
class Dos33Header(BaseHeader):
file_format = "DOS 3.3"
@ -319,14 +356,6 @@ class Dos33DiskImage(DiskImageBase):
def read_header(self):
self.header = Dos33Header()
@property
def sector_size(self):
return 256
@property
def payload_sector_size(self):
return 256
@property
def vtoc_class(self):
return Dos33VTOC
@ -339,10 +368,6 @@ class Dos33DiskImage(DiskImageBase):
def raw_sector_class(self):
return RawTrackSectorSegment
@property
def sector_builder_class(self):
return Dos33SectorBuilder
def get_boot_sector_info(self):
# based on logic from a2server
data, style = self.get_sectors(0)
@ -406,6 +431,7 @@ class Dos33DiskImage(DiskImageBase):
if dirent.flag == 0:
break
if not dirent.is_sane:
print "not sane: %s" % dirent
self.all_sane = False
else:
files.append(dirent)

View File

@ -2,6 +2,8 @@ import types
import numpy as np
from errors import *
import logging
log = logging.getLogger(__name__)
@ -79,6 +81,9 @@ class BaseSectorList(object):
def __len__(self):
return len(self.sectors)
def __str__(self):
return "\n".join(" %d: %s" % (i, str(s)) for i, s in enumerate(self))
def __getitem__(self, index):
if index < 0 or index >= len(self):
raise IndexError
@ -94,9 +99,19 @@ class BaseSectorList(object):
return self.sectors[0].sector_num
return -1
@property
def bytes_used(self):
size = 0
for s in self:
size += s.used
return size
def append(self, sector):
self.sectors.append(sector)
def extend(self, sectors):
self.sectors.extend(sectors)
class Directory(BaseSectorList):
def __init__(self, header, num_dirents=-1, sector_class=WriteableSector):
@ -138,34 +153,11 @@ class Directory(BaseSectorList):
raise FileNotFound("%s not found on disk" % filename)
def save_dirent(self, image, dirent, vtoc, sector_list):
self.place_sector_list(dirent, vtoc, sector_list)
vtoc.assign_sector_numbers(dirent, sector_list)
dirent.add_metadata_sectors(vtoc, sector_list, image.header)
dirent.update_sector_info(sector_list)
self.calc_sectors(image)
def place_sector_list(self, dirent, vtoc, sector_list):
""" Map out the sectors and link the sectors together
raises NotEnoughSpaceOnDisk if the whole file won't fit. It will not
allow partial writes.
"""
sector_list.calc_extra_sectors()
num = len(sector_list)
order = vtoc.reserve_space(num)
if len(order) != num:
raise InvalidFile("VTOC reserved space for %d sectors. Sectors needed: %d" % (len(order), num))
file_length = 0
last_sector = None
for sector, sector_num in zip(sector_list.sectors, order):
sector.sector_num = sector_num
sector.file_num = dirent.file_num
file_length += sector.used
if last_sector is not None:
last_sector.next_sector_num = sector_num
last_sector = sector
if last_sector is not None:
last_sector.next_sector_num = 0
sector_list.file_length = file_length
def remove_dirent(self, image, dirent, vtoc, sector_list):
vtoc.free_sector_list(sector_list)
dirent.mark_deleted()
@ -235,6 +227,29 @@ class VTOC(BaseSectorList):
def parse_segments(self, segments):
raise NotImplementedError
def assign_sector_numbers(self, dirent, sector_list):
""" Map out the sectors and link the sectors together
raises NotEnoughSpaceOnDisk if the whole file won't fit. It will not
allow partial writes.
"""
num = len(sector_list)
order = self.reserve_space(num)
if len(order) != num:
raise InvalidFile("VTOC reserved space for %d sectors. Sectors needed: %d" % (len(order), num))
file_length = 0
last_sector = None
for sector, sector_num in zip(sector_list.sectors, order):
sector.sector_num = sector_num
sector.file_num = dirent.file_num
file_length += sector.used
if last_sector is not None:
last_sector.next_sector_num = sector_num
last_sector = sector
if last_sector is not None:
last_sector.next_sector_num = 0
sector_list.file_length = file_length
def reserve_space(self, num):
order = []
for i in range(num):
@ -258,32 +273,3 @@ class VTOC(BaseSectorList):
def free_sector_list(self, sector_list):
for sector in sector_list:
self.sector_map[sector.sector_num] = 1
class SectorBuilder(BaseSectorList):
def __init__(self, header, usable, data, sector_class):
BaseSectorList.__init__(self, header.sector_size)
self.data = to_numpy(data)
self.usable_bytes = usable
self.split_into_sectors(header)
self.file_length = -1
def split_into_sectors(self, header):
index = 0
while index < len(self.data):
count = min(self.usable_bytes, len(self.data) - index)
sector = header.create_sector(self.data[index:index + count])
self.sectors.append(sector)
index += count
def calc_extra_sectors(self):
""" Add extra sectors to the list.
For example, DOS 3.3 uses a track/sector list at the beginning
of the file
Sectors will have their sector assignments when this function is
called.
"""
pass