WIP on DOS 3.3 support

This commit is contained in:
Rob McMullen 2017-02-22 07:19:52 -08:00
parent 7151739ad3
commit d851a06ae1
3 changed files with 116 additions and 18 deletions

View File

@ -55,7 +55,7 @@ class AtariDosDirectory(Directory):
log.debug("encoded dirent: %s" % data) log.debug("encoded dirent: %s" % data)
return data return data
def set_sector_numbers(self): def set_sector_numbers(self, image):
num = 361 num = 361
for sector in self.sectors: for sector in self.sectors:
sector.sector_num = num sector.sector_num = num
@ -137,7 +137,7 @@ class AtariDosDirent(object):
self.is_sane = self.sanity_check(image) self.is_sane = self.sanity_check(image)
def encode_dirent(self): def encode_dirent(self):
data = np.zeros([16], dtype=np.uint8) data = np.zeros([self.format.itemsize], dtype=np.uint8)
values = data.view(dtype=self.format)[0] values = data.view(dtype=self.format)[0]
flag = (1 * int(self.opened_output)) | (2 * int(self.dos_2)) | (4 * int(self.mydos)) | (0x10 * int(self.is_dir)) | (0x20 * int(self.locked)) | (0x40 * int(self.in_use)) | (0x80 * int(self.deleted)) flag = (1 * int(self.opened_output)) | (2 * int(self.dos_2)) | (4 * int(self.mydos)) | (0x10 * int(self.is_dir)) | (0x20 * int(self.locked)) | (0x40 * int(self.in_use)) | (0x80 * int(self.deleted))
values[0] = flag values[0] = flag

View File

@ -401,7 +401,7 @@ class DiskImageBase(object):
sector_list = self.sector_list_class(self.bytes_per_sector, self.payload_bytes_per_sector, data, self.writeable_sector_class) sector_list = self.sector_list_class(self.bytes_per_sector, self.payload_bytes_per_sector, data, self.writeable_sector_class)
vtoc_segments = self.get_vtoc_segments() vtoc_segments = self.get_vtoc_segments()
vtoc = self.vtoc_class(self.bytes_per_sector, vtoc_segments) vtoc = self.vtoc_class(self.bytes_per_sector, vtoc_segments)
directory.save_dirent(dirent, vtoc, sector_list) directory.save_dirent(self, dirent, vtoc, sector_list)
self.write_sector_list(sector_list) self.write_sector_list(sector_list)
self.write_sector_list(vtoc) self.write_sector_list(vtoc)
self.write_sector_list(directory) self.write_sector_list(directory)
@ -427,7 +427,7 @@ class DiskImageBase(object):
sector_list = dirent.get_sector_list(self) sector_list = dirent.get_sector_list(self)
vtoc_segments = self.get_vtoc_segments() vtoc_segments = self.get_vtoc_segments()
vtoc = self.vtoc_class(self.bytes_per_sector, vtoc_segments) vtoc = self.vtoc_class(self.bytes_per_sector, vtoc_segments)
directory.remove_dirent(dirent, vtoc, sector_list) directory.remove_dirent(self, dirent, vtoc, sector_list)
self.write_sector_list(sector_list) self.write_sector_list(sector_list)
self.write_sector_list(vtoc) self.write_sector_list(vtoc)
self.write_sector_list(directory) self.write_sector_list(directory)
@ -554,10 +554,10 @@ class Directory(BaseSectorList):
return dirent return dirent
raise FileNotFound("%s not found on disk" % filename) raise FileNotFound("%s not found on disk" % filename)
def save_dirent(self, dirent, vtoc, sector_list): def save_dirent(self, image, dirent, vtoc, sector_list):
self.place_sector_list(dirent, vtoc, sector_list) self.place_sector_list(dirent, vtoc, sector_list)
dirent.update_sector_info(sector_list) dirent.update_sector_info(sector_list)
self.calc_sectors() self.calc_sectors(image)
def place_sector_list(self, dirent, vtoc, sector_list): def place_sector_list(self, dirent, vtoc, sector_list):
""" Map out the sectors and link the sectors together """ Map out the sectors and link the sectors together
@ -583,18 +583,18 @@ class Directory(BaseSectorList):
last_sector.next_sector_num = 0 last_sector.next_sector_num = 0
sector_list.file_length = file_length sector_list.file_length = file_length
def remove_dirent(self, dirent, vtoc, sector_list): def remove_dirent(self, image, dirent, vtoc, sector_list):
vtoc.free_sector_list(sector_list) vtoc.free_sector_list(sector_list)
dirent.mark_deleted() dirent.mark_deleted()
self.calc_sectors() self.calc_sectors(image)
@property @property
def dirent_class(self): def dirent_class(self):
raise NotImplementedError raise NotImplementedError
def calc_sectors(self): def calc_sectors(self, image):
self.sectors = [] self.sectors = []
self.current_sector = self.sector_class(self.bytes_per_sector) self.current_sector = self.get_dirent_sector()
self.encode_index = 0 self.encode_index = 0
d = self.dirents.items() d = self.dirents.items()
@ -610,7 +610,10 @@ class Directory(BaseSectorList):
data = self.encode_dirent(dirent) data = self.encode_dirent(dirent)
self.store_encoded(data) self.store_encoded(data)
current = index + 1 current = index + 1
self.finish_encoding() self.finish_encoding(image)
def get_dirent_sector(self):
return self.sector_class(self.bytes_per_sector)
def encode_empty(self): def encode_empty(self):
raise NotImplementedError raise NotImplementedError
@ -624,16 +627,16 @@ class Directory(BaseSectorList):
data = self.current_sector.add_data(data) data = self.current_sector.add_data(data)
if len(data) > 0: if len(data) > 0:
self.sectors.append(self.current_sector) self.sectors.append(self.current_sector)
self.current_sector = self.sector_class(self.bytes_per_sector) self.current_sector = self.get_dirent_sector()
else: else:
break break
def finish_encoding(self): def finish_encoding(self, image):
if not self.current_sector.is_empty: if not self.current_sector.is_empty:
self.sectors.append(self.current_sector) self.sectors.append(self.current_sector)
self.set_sector_numbers() self.set_sector_numbers(image)
def set_sector_numbers(self): def set_sector_numbers(self, image):
raise NotImplementedError raise NotImplementedError

View File

@ -1,13 +1,58 @@
import numpy as np import numpy as np
from errors import * from errors import *
from diskimages import AtrHeader, DiskImageBase from diskimages import AtrHeader, DiskImageBase, Directory, VTOC, WriteableSector, BaseSectorList
from segments import DefaultSegment, EmptySegment, ObjSegment, RawSectorsSegment, SegmentSaver from segments import DefaultSegment, EmptySegment, ObjSegment, RawSectorsSegment, SegmentSaver
import logging import logging
log = logging.getLogger(__name__) log = logging.getLogger(__name__)
class Dos33VTOC(VTOC):
def parse_segments(self, segments):
self.vtoc1 = segments[0].data
bits = np.unpackbits(self.vtoc1[0x0a:0x64])
log.debug("vtoc before: %s" % bits)
self.sector_map[0:720] = bits
def calc_bitmap(self):
log.debug("vtoc after: %s" % self.sector_map[0:720])
packed = np.packbits(self.sector_map[0:720])
self.vtoc1[0x0a:0x64] = packed
s = WriteableSector(self.bytes_per_sector, self.vtoc1)
s.sector_num = 360
self.sectors.append(s)
class Dos33Directory(Directory):
@property
def dirent_class(self):
return Dos33Dirent
def get_dirent_sector(self):
s = self.sector_class(self.bytes_per_sector)
data = np.zeros([0x0b], dtype=np.uint8)
s.add_data(data)
return s
def encode_empty(self):
return np.zeros([Dos33Dirent.format.itemsize], dtype=np.uint8)
def encode_dirent(self, dirent):
data = dirent.encode_dirent()
log.debug("encoded dirent: %s" % data)
return data
def set_sector_numbers(self, image):
num = image.get_next_directory_sector(-1)
for sector in self.sectors:
sector.sector_num = num
num = image.get_next_directory_sector(num)
t, s = image.pair_from_sector(num)
sector.data[1] = t
sector.data[2] = s
class Dos33Dirent(object): class Dos33Dirent(object):
format = np.dtype([ format = np.dtype([
('track', 'u1'), ('track', 'u1'),
@ -44,8 +89,8 @@ class Dos33Dirent(object):
0x4: "B", 0x4: "B",
0x8: "S", 0x8: "S",
0x10: "R", 0x10: "R",
0x20: "A", 0x20: "new A",
0x40: "B", 0x40: "new B",
} }
def summary(self): def summary(self):
@ -76,6 +121,25 @@ class Dos33Dirent(object):
self.filename = (bytes[3:0x20] - 0x80).tostring().rstrip() self.filename = (bytes[3:0x20] - 0x80).tostring().rstrip()
self.num_sectors = int(values[4]) self.num_sectors = int(values[4])
self.is_sane = self.sanity_check(image) self.is_sane = self.sanity_check(image)
def encode_dirent(self):
data = np.zeros([self.format.itemsize], dtype=np.uint8)
values = data.view(dtype=self.format)[0]
flag = (1 * int(self.opened_output)) | (2 * int(self.dos_2)) | (4 * int(self.mydos)) | (0x10 * int(self.is_dir)) | (0x20 * int(self.locked)) | (0x40 * int(self.in_use)) | (0x80 * int(self.locked))
values[0] = flag
values[1] = self.num_sectors
values[2] = self.starting_sector
values[3] = self.filename
values[4] = self.ext
return data
def mark_deleted(self):
self.deleted = True
self.in_use = False
def update_sector_info(self, sector_list):
self.num_sectors = sector_list.num_sectors
self.starting_sector = sector_list.first_sector
def sanity_check(self, image): def sanity_check(self, image):
if self.deleted: if self.deleted:
@ -107,6 +171,20 @@ class Dos33Dirent(object):
break break
sector_list.append(image.header.sector_from_track(t, s)) sector_list.append(image.header.sector_from_track(t, s))
self.sector_map = sector_list self.sector_map = sector_list
def get_sector_list(self, image):
sector_list = BaseSectorList(image.bytes_per_sector)
self.start_read(image)
sector_num = image.header.sector_from_track(self.track, self.sector)
while sector_num > 0:
sector = WriteableSector(image.bytes_per_sector, None, sector_num)
sector_list.append(sector)
values, style = image.get_sectors(sector_num)
sector = image.header.sector_from_track(values[1], values[2])
for sector_num in sector_list:
sector = WriteableSector(image.bytes_per_sector, None, sector_num)
sector_list.append(sector)
return sector_list
def start_read(self, image): def start_read(self, image):
if not self.is_sane: if not self.is_sane:
@ -135,6 +213,11 @@ class Dos33Dirent(object):
def get_filename(self): def get_filename(self):
return self.filename return self.filename
def set_values(self, filename, filetype, index):
self.filename = "%-30s" % filename[0:30]
self.flag = self.type_map.get(filetype, 0x04)
self.locked = False
class Dos33Header(AtrHeader): class Dos33Header(AtrHeader):
file_format = "DOS 3.3" file_format = "DOS 3.3"
@ -175,6 +258,10 @@ class Dos33Header(AtrHeader):
def sector_from_track(self, track, sector): def sector_from_track(self, track, sector):
return track * 16 + sector return track * 16 + sector
def pair_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=""):
@ -300,6 +387,14 @@ class Dos33DiskImage(DiskImageBase):
segment = DefaultSegment(raw, name="Catalog") segment = DefaultSegment(raw, name="Catalog")
segments.append(segment) segments.append(segment)
return segments return segments
def get_next_directory_sector(self, sector):
self.assert_valid_sector(sector)
print "reading catalog sector", sector
raw, _, _ = self.get_raw_bytes(sector)
next_sector = self.header.sector_from_track(raw[1], raw[2])
if next_sector == 0:
# need to figure out where the next sector should be
def get_file_segment(self, dirent): def get_file_segment(self, dirent):
byte_order = [] byte_order = []