mirror of
https://github.com/robmcmullen/atrcopy.git
synced 2025-01-15 11:29:53 +00:00
Removed SectorBuilder class; fixed DOS 3.3 track/sector list
* put SectorBuildeR functionality into DiskImage
This commit is contained in:
parent
9e1e60420c
commit
605f77afb3
@ -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):
|
||||
|
@ -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)
|
||||
|
@ -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)
|
||||
|
@ -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
|
||||
|
Loading…
x
Reference in New Issue
Block a user