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)
return data
def set_sector_numbers(self):
def set_sector_numbers(self, image):
num = 361
for sector in self.sectors:
sector.sector_num = num
@ -137,7 +137,7 @@ class AtariDosDirent(object):
self.is_sane = self.sanity_check(image)
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]
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

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)
vtoc_segments = self.get_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(vtoc)
self.write_sector_list(directory)
@ -427,7 +427,7 @@ class DiskImageBase(object):
sector_list = dirent.get_sector_list(self)
vtoc_segments = self.get_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(vtoc)
self.write_sector_list(directory)
@ -554,10 +554,10 @@ class Directory(BaseSectorList):
return dirent
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)
dirent.update_sector_info(sector_list)
self.calc_sectors()
self.calc_sectors(image)
def place_sector_list(self, dirent, vtoc, sector_list):
""" Map out the sectors and link the sectors together
@ -583,18 +583,18 @@ class Directory(BaseSectorList):
last_sector.next_sector_num = 0
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)
dirent.mark_deleted()
self.calc_sectors()
self.calc_sectors(image)
@property
def dirent_class(self):
raise NotImplementedError
def calc_sectors(self):
def calc_sectors(self, image):
self.sectors = []
self.current_sector = self.sector_class(self.bytes_per_sector)
self.current_sector = self.get_dirent_sector()
self.encode_index = 0
d = self.dirents.items()
@ -610,7 +610,10 @@ class Directory(BaseSectorList):
data = self.encode_dirent(dirent)
self.store_encoded(data)
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):
raise NotImplementedError
@ -624,16 +627,16 @@ class Directory(BaseSectorList):
data = self.current_sector.add_data(data)
if len(data) > 0:
self.sectors.append(self.current_sector)
self.current_sector = self.sector_class(self.bytes_per_sector)
self.current_sector = self.get_dirent_sector()
else:
break
def finish_encoding(self):
def finish_encoding(self, image):
if not self.current_sector.is_empty:
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

View File

@ -1,13 +1,58 @@
import numpy as np
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
import logging
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):
format = np.dtype([
('track', 'u1'),
@ -44,8 +89,8 @@ class Dos33Dirent(object):
0x4: "B",
0x8: "S",
0x10: "R",
0x20: "A",
0x40: "B",
0x20: "new A",
0x40: "new B",
}
def summary(self):
@ -76,6 +121,25 @@ class Dos33Dirent(object):
self.filename = (bytes[3:0x20] - 0x80).tostring().rstrip()
self.num_sectors = int(values[4])
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):
if self.deleted:
@ -107,6 +171,20 @@ class Dos33Dirent(object):
break
sector_list.append(image.header.sector_from_track(t, s))
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):
if not self.is_sane:
@ -135,6 +213,11 @@ class Dos33Dirent(object):
def get_filename(self):
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):
file_format = "DOS 3.3"
@ -175,6 +258,10 @@ class Dos33Header(AtrHeader):
def sector_from_track(self, track, sector):
return track * 16 + sector
def pair_from_sector(self, sector):
track, sector = divmod(sector, 16)
return track, sector
class Dos33DiskImage(DiskImageBase):
def __init__(self, rawdata, filename=""):
@ -300,6 +387,14 @@ class Dos33DiskImage(DiskImageBase):
segment = DefaultSegment(raw, name="Catalog")
segments.append(segment)
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):
byte_order = []