From d851a06ae1a0e090c44a9b1682a3f2c68f1ce280 Mon Sep 17 00:00:00 2001 From: Rob McMullen Date: Wed, 22 Feb 2017 07:19:52 -0800 Subject: [PATCH] WIP on DOS 3.3 support --- atrcopy/ataridos.py | 4 +- atrcopy/diskimages.py | 29 ++++++------ atrcopy/dos33.py | 101 ++++++++++++++++++++++++++++++++++++++++-- 3 files changed, 116 insertions(+), 18 deletions(-) diff --git a/atrcopy/ataridos.py b/atrcopy/ataridos.py index 6fc53e5..0d21cf8 100644 --- a/atrcopy/ataridos.py +++ b/atrcopy/ataridos.py @@ -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 diff --git a/atrcopy/diskimages.py b/atrcopy/diskimages.py index ba33230..99fc02d 100644 --- a/atrcopy/diskimages.py +++ b/atrcopy/diskimages.py @@ -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 diff --git a/atrcopy/dos33.py b/atrcopy/dos33.py index e1634d8..0ffc88a 100644 --- a/atrcopy/dos33.py +++ b/atrcopy/dos33.py @@ -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 = []