mirror of
https://github.com/robmcmullen/atrcopy.git
synced 2024-12-27 23:32:06 +00:00
PEP8 whitespace fixes
This commit is contained in:
parent
6f29e6053a
commit
c897460df0
@ -32,7 +32,7 @@ def process(image, dirent, options):
|
||||
outfilename = "%s%s.XEX" % (dirent.filename, dirent.ext)
|
||||
if options.lower:
|
||||
outfilename = outfilename.lower()
|
||||
|
||||
|
||||
if options.dry_run:
|
||||
action = "DRY_RUN: %s" % action
|
||||
skip = True
|
||||
@ -45,6 +45,7 @@ def process(image, dirent, options):
|
||||
else:
|
||||
print dirent
|
||||
|
||||
|
||||
def find_diskimage(filename):
|
||||
try:
|
||||
with open(filename, "rb") as fh:
|
||||
@ -72,6 +73,7 @@ def find_diskimage(filename):
|
||||
parser.image.ext = ""
|
||||
return parser
|
||||
|
||||
|
||||
def extract_files(image, files):
|
||||
for name in files:
|
||||
try:
|
||||
@ -85,6 +87,7 @@ def extract_files(image, files):
|
||||
with open(dirent.filename, "wb") as fh:
|
||||
fh.write(data)
|
||||
|
||||
|
||||
def save_file(image, name, filetype, data):
|
||||
try:
|
||||
dirent = image.find_dirent(name)
|
||||
@ -114,6 +117,7 @@ def add_files(image, files):
|
||||
if changed:
|
||||
image.save()
|
||||
|
||||
|
||||
def remove_files(image, files):
|
||||
changed = False
|
||||
for name in files:
|
||||
@ -129,6 +133,7 @@ def remove_files(image, files):
|
||||
if changed:
|
||||
image.save()
|
||||
|
||||
|
||||
def list_files(image, files):
|
||||
files = set(files)
|
||||
for dirent in image.files:
|
||||
@ -137,6 +142,7 @@ def list_files(image, files):
|
||||
if options.metadata:
|
||||
print dirent.extra_metadata(image)
|
||||
|
||||
|
||||
def assemble(image, source_files, data_files):
|
||||
if source_files:
|
||||
try:
|
||||
@ -170,6 +176,7 @@ def assemble(image, source_files, data_files):
|
||||
if changed:
|
||||
image.save()
|
||||
|
||||
|
||||
def shred_image(image, value=0):
|
||||
print "shredding: free sectors from %s filled with %d" % (image, value)
|
||||
if not options.dry_run:
|
||||
@ -182,7 +189,7 @@ def run():
|
||||
import argparse
|
||||
|
||||
global options
|
||||
|
||||
|
||||
parser = argparse.ArgumentParser(description="Manipulate files on several types of 8-bit computer disk images")
|
||||
parser.add_argument("-v", "--verbose", default=0, action="count")
|
||||
parser.add_argument("--dry-run", action="store_true", default=False, help="don't perform operation, just show what would have happened")
|
||||
@ -214,7 +221,7 @@ def run():
|
||||
log.setLevel(logging.DEBUG)
|
||||
else:
|
||||
log.setLevel(logging.INFO)
|
||||
|
||||
|
||||
file_list = []
|
||||
if options.add or options.extract or options.delete:
|
||||
image = options.files.pop()
|
||||
|
@ -91,7 +91,7 @@ class AtariDosDirent(Dirent):
|
||||
self.current_read = 0
|
||||
self.sectors_seen = None
|
||||
self.parse_raw_dirent(image, bytes)
|
||||
|
||||
|
||||
def __str__(self):
|
||||
return "File #%-2d (%s) %03d %-8s%-3s %03d" % (self.file_num, self.summary, self.starting_sector, self.basename, self.ext, self.num_sectors)
|
||||
|
||||
@ -102,7 +102,7 @@ class AtariDosDirent(Dirent):
|
||||
def filename(self):
|
||||
ext = ("." + self.ext) if self.ext else ""
|
||||
return self.basename + ext
|
||||
|
||||
|
||||
@property
|
||||
def summary(self):
|
||||
output = "o" if self.opened_output else "."
|
||||
@ -113,7 +113,7 @@ class AtariDosDirent(Dirent):
|
||||
locked = "*" if self.locked else " "
|
||||
flags = "%s%s%s%s%s%s" % (output, dos2, mydos, in_use, deleted, locked)
|
||||
return flags
|
||||
|
||||
|
||||
@property
|
||||
def verbose_info(self):
|
||||
flags = []
|
||||
@ -131,7 +131,7 @@ class AtariDosDirent(Dirent):
|
||||
def parse_raw_dirent(self, image, bytes):
|
||||
if bytes is None:
|
||||
return
|
||||
values = bytes.view(dtype=self.format)[0]
|
||||
values = bytes.view(dtype=self.format)[0]
|
||||
flag = values[0]
|
||||
self.flag = flag
|
||||
self.opened_output = (flag&0x01) > 0
|
||||
@ -170,7 +170,7 @@ class AtariDosDirent(Dirent):
|
||||
# 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:
|
||||
return True
|
||||
@ -179,7 +179,7 @@ class AtariDosDirent(Dirent):
|
||||
if self.num_sectors < 0 or self.num_sectors > image.header.max_sectors:
|
||||
return False
|
||||
return True
|
||||
|
||||
|
||||
def get_sectors_in_vtoc(self, image):
|
||||
sector_list = BaseSectorList(image.header)
|
||||
self.start_read(image)
|
||||
@ -197,7 +197,7 @@ class AtariDosDirent(Dirent):
|
||||
self.current_sector = self.starting_sector
|
||||
self.current_read = self.num_sectors
|
||||
self.sectors_seen = set()
|
||||
|
||||
|
||||
def read_sector(self, image):
|
||||
raw, pos, size = image.get_raw_bytes(self.current_sector)
|
||||
bytes, num_data_bytes = self.process_raw_sector(image, raw)
|
||||
@ -256,12 +256,13 @@ class AtariDosFile(object):
|
||||
|
||||
Ref: http://www.atarimax.com/jindroush.atari.org/afmtexe.html
|
||||
"""
|
||||
|
||||
def __init__(self, rawdata):
|
||||
self.rawdata = rawdata
|
||||
self.size = len(rawdata)
|
||||
self.segments = []
|
||||
self.files = []
|
||||
|
||||
|
||||
def __str__(self):
|
||||
return "\n".join(str(s) for s in self.segments) + "\n"
|
||||
|
||||
@ -270,7 +271,7 @@ class AtariDosFile(object):
|
||||
|
||||
def relaxed_check(self):
|
||||
pass
|
||||
|
||||
|
||||
def parse_segments(self):
|
||||
r = self.rawdata
|
||||
b = r.get_data()
|
||||
@ -325,7 +326,7 @@ class AtrHeader(BaseHeader):
|
||||
('btFlags','u1'),
|
||||
])
|
||||
file_format = "ATR"
|
||||
|
||||
|
||||
def __init__(self, bytes=None, sector_size=128, initial_sectors=3, create=False):
|
||||
BaseHeader.__init__(self, sector_size, initial_sectors, 360, 1)
|
||||
if create:
|
||||
@ -333,7 +334,7 @@ class AtrHeader(BaseHeader):
|
||||
self.check_size(0)
|
||||
if bytes is None:
|
||||
return
|
||||
|
||||
|
||||
if len(bytes) == 16:
|
||||
values = bytes.view(dtype=self.format)[0]
|
||||
if values[0] != 0x296:
|
||||
@ -346,10 +347,10 @@ class AtrHeader(BaseHeader):
|
||||
self.header_offset = 16
|
||||
else:
|
||||
raise InvalidAtrHeader
|
||||
|
||||
|
||||
def __str__(self):
|
||||
return "%s Disk Image (size=%d (%dx%db), crc=%d flags=%d unused=%d)" % (self.file_format, self.image_size, self.max_sectors, self.sector_size, self.crc, self.flags, self.unused)
|
||||
|
||||
|
||||
def encode(self, raw):
|
||||
values = raw.view(dtype=self.format)[0]
|
||||
values[0] = 0x296
|
||||
@ -390,7 +391,7 @@ class AtrHeader(BaseHeader):
|
||||
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
|
||||
|
||||
|
||||
def get_pos(self, sector):
|
||||
if not self.sector_is_valid(sector):
|
||||
raise ByteNotInFile166("Sector %d out of range" % sector)
|
||||
@ -406,13 +407,13 @@ class AtrHeader(BaseHeader):
|
||||
|
||||
class XfdHeader(AtrHeader):
|
||||
file_format = "XFD"
|
||||
|
||||
|
||||
def __str__(self):
|
||||
return "%s Disk Image (size=%d (%dx%db)" % (self.file_format, self.image_size, self.max_sectors, self.sector_size)
|
||||
|
||||
|
||||
def __len__(self):
|
||||
return 0
|
||||
|
||||
|
||||
def to_array(self):
|
||||
raw = np.zeros([0], dtype=np.uint8)
|
||||
return raw
|
||||
@ -446,7 +447,7 @@ class AtariDosDiskImage(DiskImageBase):
|
||||
|
||||
def __str__(self):
|
||||
return "%s Atari DOS Format: %d usable sectors (%d free), %d files" % (self.header, self.total_sectors, self.unused_sectors, len(self.files))
|
||||
|
||||
|
||||
@classmethod
|
||||
def new_header(cls, diskimage, format="ATR"):
|
||||
if format.lower() == "atr":
|
||||
@ -455,7 +456,7 @@ class AtariDosDiskImage(DiskImageBase):
|
||||
else:
|
||||
raise RuntimeError("Unknown header type %s" % format)
|
||||
return header
|
||||
|
||||
|
||||
def as_new_format(self, format="ATR"):
|
||||
""" Create a new disk image in the specified format
|
||||
"""
|
||||
@ -465,13 +466,13 @@ class AtariDosDiskImage(DiskImageBase):
|
||||
newraw = SegmentData(data)
|
||||
image = self.__class__(newraw)
|
||||
return image
|
||||
|
||||
|
||||
vtoc_type = np.dtype([
|
||||
('code', 'u1'),
|
||||
('total','<u2'),
|
||||
('unused','<u2'),
|
||||
])
|
||||
|
||||
|
||||
def read_header(self):
|
||||
bytes = self.bytes[0:16]
|
||||
try:
|
||||
@ -509,7 +510,7 @@ class AtariDosDiskImage(DiskImageBase):
|
||||
self.num_vtoc = num
|
||||
if num < 0 or num > self.calc_vtoc_code():
|
||||
raise InvalidDiskImage("Invalid number of VTOC sectors: %d" % num)
|
||||
|
||||
|
||||
self.total_sectors = values[1]
|
||||
self.unused_sectors = values[2]
|
||||
if self.header.image_size == 133120:
|
||||
@ -518,7 +519,7 @@ class AtariDosDiskImage(DiskImageBase):
|
||||
data, style = self.get_sectors(self.vtoc2)
|
||||
extra_free = data[122:124].view(dtype='<u2')[0]
|
||||
self.unused_sectors += extra_free
|
||||
|
||||
|
||||
def get_directory(self, directory=None):
|
||||
dir_bytes, style = self.get_sectors(361, 368)
|
||||
i = 0
|
||||
@ -528,7 +529,7 @@ class AtariDosDiskImage(DiskImageBase):
|
||||
dirent = AtariDosDirent(self, num, dir_bytes[i:i+16])
|
||||
if dirent.mydos:
|
||||
dirent = MydosDirent(self, num, dir_bytes[i:i+16])
|
||||
|
||||
|
||||
if dirent.in_use:
|
||||
files.append(dirent)
|
||||
if not dirent.is_sane:
|
||||
@ -541,7 +542,7 @@ class AtariDosDiskImage(DiskImageBase):
|
||||
i += 16
|
||||
num += 1
|
||||
self.files = files
|
||||
|
||||
|
||||
boot_record_type = np.dtype([
|
||||
('BFLAG', 'u1'),
|
||||
('BRCNT', 'u1'),
|
||||
@ -561,7 +562,7 @@ class AtariDosDiskImage(DiskImageBase):
|
||||
|
||||
def get_boot_segments(self):
|
||||
data, style = self.get_sectors(360)
|
||||
values = data[0:20].view(dtype=self.boot_record_type)[0]
|
||||
values = data[0:20].view(dtype=self.boot_record_type)[0]
|
||||
flag = int(values[0])
|
||||
segments = []
|
||||
if flag == 0:
|
||||
@ -574,7 +575,7 @@ class AtariDosDiskImage(DiskImageBase):
|
||||
code = ObjSegment(r[20:], 0, 0, addr + 20, addr + len(r), name="Boot Code")
|
||||
segments = [sectors, header, code]
|
||||
return segments
|
||||
|
||||
|
||||
def get_vtoc_segments(self):
|
||||
r = self.rawdata
|
||||
segments = []
|
||||
@ -600,7 +601,7 @@ class AtariDosDiskImage(DiskImageBase):
|
||||
segment.set_comment_at(0x7c, "unused")
|
||||
segments.append(segment)
|
||||
return segments
|
||||
|
||||
|
||||
def get_directory_segments(self):
|
||||
r = self.rawdata
|
||||
segments = []
|
||||
@ -618,7 +619,7 @@ class AtariDosDiskImage(DiskImageBase):
|
||||
index += 16
|
||||
segments.append(segment)
|
||||
return segments
|
||||
|
||||
|
||||
def get_file_segment(self, dirent):
|
||||
byte_order = []
|
||||
dirent.start_read(self)
|
||||
@ -635,7 +636,7 @@ class AtariDosDiskImage(DiskImageBase):
|
||||
else:
|
||||
segment = EmptySegment(self.rawdata, name=dirent.filename)
|
||||
return segment
|
||||
|
||||
|
||||
def get_file_segments(self):
|
||||
segments_in = DiskImageBase.get_file_segments(self)
|
||||
segments_out = []
|
||||
@ -655,7 +656,7 @@ class AtariDosDiskImage(DiskImageBase):
|
||||
class BootDiskImage(AtariDosDiskImage):
|
||||
def __str__(self):
|
||||
return "%s Boot Disk" % (self.header)
|
||||
|
||||
|
||||
def check_size(self):
|
||||
if self.header is None:
|
||||
return
|
||||
@ -667,7 +668,7 @@ class BootDiskImage(AtariDosDiskImage):
|
||||
raise InvalidDiskImage("Appears to be an executable")
|
||||
nsec = b[i + 1]
|
||||
bload = b[i + 2:i + 4].view(dtype='<u2')[0]
|
||||
|
||||
|
||||
# Sanity check: number of sectors to be loaded can't be more than the
|
||||
# lower 48k of ram because there's no way to bank switch or anything
|
||||
# before the boot sectors are finished loading
|
||||
@ -687,17 +688,17 @@ class BootDiskImage(AtariDosDiskImage):
|
||||
|
||||
def get_directory(self, directory=None):
|
||||
pass
|
||||
|
||||
|
||||
boot_record_type = np.dtype([
|
||||
('BFLAG', 'u1'),
|
||||
('BRCNT', 'u1'),
|
||||
('BLDADR', '<u2'),
|
||||
('BWTARR', '<u2'),
|
||||
])
|
||||
|
||||
|
||||
def get_boot_segments(self):
|
||||
data, style = self.get_sectors(1)
|
||||
values = data[0:6].view(dtype=self.boot_record_type)[0]
|
||||
values = data[0:6].view(dtype=self.boot_record_type)[0]
|
||||
flag = int(values[0])
|
||||
segments = []
|
||||
if flag == 0:
|
||||
@ -746,6 +747,7 @@ def get_xex(segments, runaddr=None):
|
||||
i += len(s)
|
||||
return bytes
|
||||
|
||||
|
||||
def add_atr_header(bytes):
|
||||
header = AtrHeader(create=True)
|
||||
header.check_size(len(bytes))
|
||||
|
@ -95,6 +95,7 @@ known_cart_types = [
|
||||
|
||||
known_cart_type_map = {c[0]:i for i, c in enumerate(known_cart_types)}
|
||||
|
||||
|
||||
def get_known_carts():
|
||||
grouped = defaultdict(list)
|
||||
for c in known_cart_types[1:]:
|
||||
@ -102,6 +103,7 @@ def get_known_carts():
|
||||
grouped[size].append(c)
|
||||
return grouped
|
||||
|
||||
|
||||
def get_cart(cart_type):
|
||||
try:
|
||||
return known_cart_types[known_cart_type_map[cart_type]]
|
||||
@ -118,7 +120,7 @@ class A8CartHeader(object):
|
||||
('unused','>u4')
|
||||
])
|
||||
file_format = "Cart"
|
||||
|
||||
|
||||
def __init__(self, bytes=None, create=False):
|
||||
self.image_size = 0
|
||||
self.cart_type = -1
|
||||
@ -140,7 +142,7 @@ class A8CartHeader(object):
|
||||
self.check_size(0)
|
||||
if bytes is None:
|
||||
return
|
||||
|
||||
|
||||
if len(bytes) == 16:
|
||||
values = bytes.view(dtype=self.format)[0]
|
||||
if values[0] != 'CART':
|
||||
@ -151,13 +153,13 @@ class A8CartHeader(object):
|
||||
self.set_type(self.cart_type)
|
||||
else:
|
||||
raise InvalidCartHeader
|
||||
|
||||
|
||||
def __str__(self):
|
||||
return "%s Cartridge (atari800 type=%d size=%d, %d banks, crc=%d)" % (self.cart_name, self.cart_type, self.cart_size, self.bank_size, self.crc)
|
||||
|
||||
|
||||
def __len__(self):
|
||||
return self.header_offset
|
||||
|
||||
|
||||
def to_array(self):
|
||||
raw = np.zeros([16], dtype=np.uint8)
|
||||
values = raw.view(dtype=self.format)[0]
|
||||
@ -201,7 +203,7 @@ class AtariCartImage(DiskImageBase):
|
||||
|
||||
def __str__(self):
|
||||
return str(self.header)
|
||||
|
||||
|
||||
def read_header(self):
|
||||
bytes = self.bytes[0:16]
|
||||
try:
|
||||
@ -219,7 +221,7 @@ class AtariCartImage(DiskImageBase):
|
||||
# force the header to be the specified cart type
|
||||
self.header = A8CartHeader()
|
||||
self.header.set_type(self.cart_type)
|
||||
|
||||
|
||||
def check_size(self):
|
||||
if self.header is None:
|
||||
return
|
||||
@ -230,7 +232,7 @@ class AtariCartImage(DiskImageBase):
|
||||
raise InvalidDiskImage("Cart not multiple of 1K")
|
||||
if k != c[2]:
|
||||
raise InvalidDiskImage("Image size %d doesn't match cart type %d size %d" % (k, self.cart_type, c[2]))
|
||||
|
||||
|
||||
def parse_segments(self):
|
||||
r = self.rawdata
|
||||
i = self.header.header_offset
|
||||
|
@ -31,10 +31,10 @@ class BaseHeader(object):
|
||||
self.extra_vtoc = []
|
||||
self.first_directory = 0
|
||||
self.num_directory = 0
|
||||
|
||||
|
||||
def __len__(self):
|
||||
return self.header_offset
|
||||
|
||||
|
||||
def to_array(self):
|
||||
header_bytes = np.zeros([self.header_offset], dtype=np.uint8)
|
||||
self.encode(header_bytes)
|
||||
@ -55,7 +55,7 @@ class BaseHeader(object):
|
||||
pos, size = self.get_pos(i)
|
||||
yield i, pos, size
|
||||
i += 1
|
||||
|
||||
|
||||
def get_pos(self, sector):
|
||||
"""Get index (into the raw data of the disk image) of start of sector
|
||||
|
||||
@ -119,13 +119,13 @@ class DiskImageBase(object):
|
||||
@property
|
||||
def directory_class(self):
|
||||
return Directory
|
||||
|
||||
|
||||
def set_filename(self, filename):
|
||||
if "." in filename:
|
||||
self.filename, self.ext = filename.rsplit(".", 1)
|
||||
else:
|
||||
self.filename, self.ext = filename, ""
|
||||
|
||||
|
||||
def dir(self):
|
||||
lines = []
|
||||
lines.append(str(self))
|
||||
@ -156,16 +156,16 @@ class DiskImageBase(object):
|
||||
format.
|
||||
"""
|
||||
pass
|
||||
|
||||
|
||||
@classmethod
|
||||
def new_header(cls, diskimage, format="ATR"):
|
||||
raise NotImplementedError
|
||||
|
||||
|
||||
def as_new_format(self, format="ATR"):
|
||||
""" Create a new disk image in the specified format
|
||||
"""
|
||||
raise NotImplementedError
|
||||
|
||||
|
||||
def save(self, filename=""):
|
||||
if not filename:
|
||||
filename = self.filename
|
||||
@ -176,35 +176,35 @@ class DiskImageBase(object):
|
||||
bytes = self.bytes[:]
|
||||
with open(filename, "wb") as fh:
|
||||
bytes.tofile(fh)
|
||||
|
||||
|
||||
def assert_valid_sector(self, sector):
|
||||
if not self.header.sector_is_valid(sector):
|
||||
raise ByteNotInFile166("Sector %d out of range" % sector)
|
||||
|
||||
|
||||
def check_sane(self):
|
||||
if not self.all_sane:
|
||||
raise InvalidDiskImage("Invalid directory entries; may be boot disk")
|
||||
|
||||
|
||||
def read_header(self):
|
||||
return BaseHeader()
|
||||
|
||||
|
||||
def check_size(self):
|
||||
pass
|
||||
|
||||
|
||||
def get_boot_sector_info(self):
|
||||
pass
|
||||
|
||||
|
||||
def get_vtoc(self):
|
||||
"""Get information from VTOC and populate the VTOC object"""
|
||||
pass
|
||||
|
||||
|
||||
def get_directory(self, directory=None):
|
||||
pass
|
||||
|
||||
|
||||
def get_raw_bytes(self, sector):
|
||||
pos, size = self.header.get_pos(sector)
|
||||
return self.bytes[pos:pos + size], pos, size
|
||||
|
||||
|
||||
def get_sector_slice(self, start, end=None):
|
||||
""" Get contiguous sectors
|
||||
|
||||
@ -220,7 +220,7 @@ class DiskImageBase(object):
|
||||
_, more = self.header.get_pos(start)
|
||||
size += more
|
||||
return slice(pos, pos + size)
|
||||
|
||||
|
||||
def get_sectors(self, start, end=None):
|
||||
""" Get contiguous sectors
|
||||
|
||||
@ -230,7 +230,7 @@ class DiskImageBase(object):
|
||||
"""
|
||||
s = self.get_sector_slice(start, end)
|
||||
return self.bytes[s], self.style[s]
|
||||
|
||||
|
||||
def get_contiguous_sectors(self, sector, num):
|
||||
start = 0
|
||||
count = 0
|
||||
@ -240,7 +240,7 @@ class DiskImageBase(object):
|
||||
start = pos
|
||||
count += size
|
||||
return start, count
|
||||
|
||||
|
||||
def parse_segments(self):
|
||||
r = self.rawdata
|
||||
i = self.header.header_offset
|
||||
@ -251,16 +251,16 @@ class DiskImageBase(object):
|
||||
self.segments.extend(self.get_vtoc_segments())
|
||||
self.segments.extend(self.get_directory_segments())
|
||||
self.segments.extend(self.get_file_segments())
|
||||
|
||||
|
||||
def get_boot_segments(self):
|
||||
return []
|
||||
|
||||
|
||||
def get_vtoc_segments(self):
|
||||
return []
|
||||
|
||||
def get_directory_segments(self):
|
||||
return []
|
||||
|
||||
|
||||
def find_dirent(self, filename):
|
||||
# check if we've been passed a dirent instead of a filename
|
||||
if hasattr(filename, "filename"):
|
||||
@ -269,18 +269,18 @@ class DiskImageBase(object):
|
||||
if filename == dirent.filename:
|
||||
return dirent
|
||||
raise FileNotFound("%s not found on disk" % filename)
|
||||
|
||||
|
||||
def find_file(self, filename):
|
||||
dirent = self.find_dirent(filename)
|
||||
return self.get_file(dirent)
|
||||
|
||||
|
||||
def get_file(self, dirent):
|
||||
segment = self.get_file_segment(dirent)
|
||||
return segment.tostring()
|
||||
|
||||
|
||||
def get_file_segment(self, dirent):
|
||||
pass
|
||||
|
||||
|
||||
def get_file_segments(self):
|
||||
segments = []
|
||||
for dirent in self.files:
|
||||
|
@ -168,13 +168,13 @@ class Dos33Dirent(Dirent):
|
||||
self.sectors_seen = None
|
||||
self.sector_map = None
|
||||
self.parse_raw_dirent(image, bytes)
|
||||
|
||||
|
||||
def __str__(self):
|
||||
return "File #%-2d (%s) %03d %-30s %03d %03d" % (self.file_num, self.summary, self.num_sectors, self.filename, self.track, self.sector)
|
||||
|
||||
def __eq__(self, other):
|
||||
return self.__class__ == other.__class__ and self.filename == other.filename and self.track == other.track and self.sector == other.sector and self.num_sectors == other.num_sectors
|
||||
|
||||
|
||||
type_to_text = {
|
||||
0x0: "T", # text
|
||||
0x1: "I", # integer basic
|
||||
@ -202,7 +202,7 @@ class Dos33Dirent(Dirent):
|
||||
file_type = self.file_type
|
||||
flag = "%s%s" % (locked, file_type)
|
||||
return flag
|
||||
|
||||
|
||||
@property
|
||||
def verbose_info(self):
|
||||
return self.summary
|
||||
@ -221,7 +221,7 @@ class Dos33Dirent(Dirent):
|
||||
lines.append("track/sector list at: " + str(ts))
|
||||
lines.append("sector map: " + str(self.sector_map))
|
||||
return "\n".join(lines)
|
||||
|
||||
|
||||
def parse_raw_dirent(self, image, bytes):
|
||||
if bytes is None:
|
||||
return
|
||||
@ -275,7 +275,7 @@ class Dos33Dirent(Dirent):
|
||||
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:
|
||||
return True
|
||||
@ -304,7 +304,7 @@ class Dos33Dirent(Dirent):
|
||||
self.sector_map = sector_map[0:self.num_sectors - len(tslist)]
|
||||
self.track_sector_list = tslist
|
||||
return tslist
|
||||
|
||||
|
||||
def get_sectors_in_vtoc(self, image):
|
||||
self.get_track_sector_list(image)
|
||||
sectors = BaseSectorList(image.header)
|
||||
@ -321,7 +321,7 @@ class Dos33Dirent(Dirent):
|
||||
log.debug("start_read: %s, t/s list: %s" % (str(self), str(self.sector_map)))
|
||||
self.current_sector_index = 0
|
||||
self.current_read = self.num_sectors
|
||||
|
||||
|
||||
def read_sector(self, image):
|
||||
try:
|
||||
sector = self.sector_map[self.current_sector_index]
|
||||
@ -337,7 +337,7 @@ class Dos33Dirent(Dirent):
|
||||
self.current_sector_index += 1
|
||||
num_bytes = len(raw)
|
||||
return raw[0:num_bytes], num_bytes
|
||||
|
||||
|
||||
def get_filename(self):
|
||||
return self.filename
|
||||
|
||||
@ -359,7 +359,7 @@ class Dos33Header(BaseHeader):
|
||||
|
||||
def __init__(self):
|
||||
BaseHeader.__init__(self, 256)
|
||||
|
||||
|
||||
def __str__(self):
|
||||
return "%s Disk Image (size=%d (%dx%db)" % (self.file_format, self.image_size, self.max_sectors, self.sector_size)
|
||||
|
||||
@ -383,7 +383,7 @@ class Dos33DiskImage(DiskImageBase):
|
||||
|
||||
def __str__(self):
|
||||
return str(self.header)
|
||||
|
||||
|
||||
def read_header(self):
|
||||
self.header = Dos33Header()
|
||||
|
||||
@ -394,7 +394,7 @@ class Dos33DiskImage(DiskImageBase):
|
||||
@property
|
||||
def directory_class(self):
|
||||
return Dos33Directory
|
||||
|
||||
|
||||
@property
|
||||
def raw_sector_class(self):
|
||||
return RawTrackSectorSegment
|
||||
@ -416,7 +416,7 @@ class Dos33DiskImage(DiskImageBase):
|
||||
raise InvalidDiskImage("Invalid VTOC location for DOS 3.3")
|
||||
|
||||
log.debug("DOS 3.3 byte swap: %s" % swap_order)
|
||||
|
||||
|
||||
vtoc_type = np.dtype([
|
||||
('unused1', 'S1'),
|
||||
('cat_track','u1'),
|
||||
@ -446,7 +446,7 @@ class Dos33DiskImage(DiskImageBase):
|
||||
self.header.last_track_num = values['last_track']
|
||||
self.header.track_alloc_dir = values['track_dir']
|
||||
self.assert_valid_sector(self.header.first_directory)
|
||||
|
||||
|
||||
def get_directory(self, directory=None):
|
||||
sector = self.header.first_directory
|
||||
num = 0
|
||||
@ -488,7 +488,7 @@ class Dos33DiskImage(DiskImageBase):
|
||||
r = self.rawdata[s]
|
||||
boot3 = ObjSegment(r, 0, 0, 0x1d00, name="Boot 3")
|
||||
return [boot1, boot2, relocator, boot3]
|
||||
|
||||
|
||||
def get_vtoc_segments(self):
|
||||
r = self.rawdata
|
||||
segments = []
|
||||
@ -517,7 +517,7 @@ class Dos33DiskImage(DiskImageBase):
|
||||
index += 4
|
||||
segments.append(segment)
|
||||
return segments
|
||||
|
||||
|
||||
def get_directory_segments(self):
|
||||
byte_order = []
|
||||
r = self.rawdata
|
||||
@ -561,7 +561,7 @@ class Dos33DiskImage(DiskImageBase):
|
||||
if next_sector == 0:
|
||||
raise NoSpaceInDirectory("No space left in catalog")
|
||||
return sector_num, next_sector
|
||||
|
||||
|
||||
def get_file_segment(self, dirent):
|
||||
byte_order = []
|
||||
dirent.start_read(self)
|
||||
@ -605,10 +605,6 @@ class Dos33DiskImage(DiskImageBase):
|
||||
return image, 'B'
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
class ProdosHeader(Dos33Header):
|
||||
file_format = "ProDOS"
|
||||
|
||||
|
@ -1,12 +1,15 @@
|
||||
class AtrError(RuntimeError):
|
||||
pass
|
||||
|
||||
|
||||
class InvalidAtrHeader(AtrError):
|
||||
pass
|
||||
|
||||
|
||||
class InvalidCartHeader(AtrError):
|
||||
pass
|
||||
|
||||
|
||||
class InvalidDiskImage(AtrError):
|
||||
""" Disk image is not recognized by a parser.
|
||||
|
||||
@ -15,6 +18,7 @@ class InvalidDiskImage(AtrError):
|
||||
"""
|
||||
pass
|
||||
|
||||
|
||||
class UnsupportedDiskImage(AtrError):
|
||||
""" Disk image is recognized by a parser but it isn't supported yet.
|
||||
|
||||
@ -22,32 +26,42 @@ class UnsupportedDiskImage(AtrError):
|
||||
"""
|
||||
pass
|
||||
|
||||
|
||||
class InvalidDirent(AtrError):
|
||||
pass
|
||||
|
||||
|
||||
class LastDirent(AtrError):
|
||||
pass
|
||||
|
||||
|
||||
class InvalidFile(AtrError):
|
||||
pass
|
||||
|
||||
|
||||
class FileNumberMismatchError164(InvalidFile):
|
||||
pass
|
||||
|
||||
|
||||
class ByteNotInFile166(InvalidFile):
|
||||
pass
|
||||
|
||||
|
||||
class InvalidBinaryFile(InvalidFile):
|
||||
pass
|
||||
|
||||
|
||||
class InvalidSegmentParser(AtrError):
|
||||
pass
|
||||
|
||||
|
||||
class NoSpaceInDirectory(AtrError):
|
||||
pass
|
||||
|
||||
|
||||
class NotEnoughSpaceOnDisk(AtrError):
|
||||
pass
|
||||
|
||||
|
||||
class FileNotFound(AtrError):
|
||||
pass
|
||||
|
@ -25,7 +25,7 @@ class KBootDirent(AtariDosDirent):
|
||||
self.exe_size = count
|
||||
self.exe_start = start
|
||||
self.num_sectors = count / 128 + 1
|
||||
|
||||
|
||||
def parse_raw_dirent(self, image, bytes):
|
||||
pass
|
||||
|
||||
@ -37,14 +37,14 @@ class KBootDirent(AtariDosDirent):
|
||||
class KBootImage(AtariDosDiskImage):
|
||||
def __str__(self):
|
||||
return "%s KBoot Format: %d byte executable" % (self.header, self.files[0].exe_size)
|
||||
|
||||
|
||||
def check_sane(self):
|
||||
if not self.all_sane:
|
||||
raise InvalidDiskImage("Doesn't seem to be KBoot header")
|
||||
|
||||
def get_vtoc(self):
|
||||
pass
|
||||
|
||||
|
||||
def get_directory(self):
|
||||
dirent = KBootDirent(self)
|
||||
if not dirent.is_sane:
|
||||
@ -57,8 +57,10 @@ class KBootImage(AtariDosDiskImage):
|
||||
raw = self.rawdata[start:end]
|
||||
return XexSegment(raw, 0, 0, start, end, name="KBoot Executable")
|
||||
|
||||
|
||||
xexboot_header = '\x00\x03\x00\x07\r\x07L\r\x07\x1c[\x00\x00\xa0\x00\x8c\t\x03\x8c\x04\x03\x8cD\x02\x8c\xe2\x02\x8c\xe3\x02\xc8\x84\t\x8c\x01\x03\xce\x06\x03\xa91\x8d\x00\x03\xa9R\x8d\x02\x03\xa9\x80\x8d\x08\x03\xa9\x01\x8d\x05\x03\xa9\xe3\x8d0\x02\x8d\x02\xd4\xa9\x07\x8d1\x02\x8d\x03\xd4\xa9\x00\xaa\x8d\x0b\x03\xa9\x04\x8d\n\x03 \xbc\x07\xca \xa5\x07\x85C \xa5\x07\x85D%C\xc9\xff\xf0\xf0 \xa5\x07\x85E \xa5\x07\x85F \xa5\x07\x91C\xe6C\xd0\x02\xe6D\xa5E\xc5C\xa5F\xe5D\xb0\xeb\xad\xe2\x02\r\xe3\x02\xf0\xc9\x86\x19 \xa2\x07\xa6\x19\xa0\x00\x8c\xe2\x02\x8c\xe3\x02\xf0\xb8l\xe2\x02\xad\t\x07\xd0\x0b\xad\n\x07\xd0\x03l\xe0\x02\xce\n\x07\xce\t\x07\xe0\x80\x90"\xa9@\x8d\x03\x03 Y\xe4\x10\x06\xce\x01\x07\xd0\xf1\x00\xee\n\x03\xd0\x03\xee\x0b\x03\xad\n\x03\x8d\x19\xd0\xa0\x00\xa2\x00\xbd\x00\x01\xe8`pppppF\xf8\x07p\x07ppp\x06p\x06p\x06A\xe3\x07\x00\x00\x00\x00\x00,/!$).\'\x0e\x0e\x0e\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00&2/-'
|
||||
|
||||
|
||||
def insert_string(data, offset, string, color):
|
||||
s = np.fromstring(string.upper(), dtype=np.uint8) - 32 # convert to internal
|
||||
s = s | color
|
||||
@ -66,6 +68,7 @@ def insert_string(data, offset, string, color):
|
||||
tx = offset + (20 - count)/ 2
|
||||
data[tx:tx+count] = s
|
||||
|
||||
|
||||
def add_xexboot_header(bytes, bootcode=None, title="DEMO", author="an atari user"):
|
||||
sec_size = 128
|
||||
xex_size = len(bytes)
|
||||
@ -74,7 +77,7 @@ def add_xexboot_header(bytes, bootcode=None, title="DEMO", author="an atari user
|
||||
if xex_size < padded_size:
|
||||
bytes = np.append(bytes, np.zeros([padded_size - xex_size], dtype=np.uint8))
|
||||
paragraphs = padded_size / 16
|
||||
|
||||
|
||||
if bootcode is None:
|
||||
bootcode = np.fromstring(xexboot_header, dtype=np.uint8)
|
||||
else:
|
||||
@ -85,7 +88,7 @@ def add_xexboot_header(bytes, bootcode=None, title="DEMO", author="an atari user
|
||||
bootsize = np.alen(bootcode)
|
||||
v = bootcode[9:11].view(dtype="<u2")
|
||||
v[0] = xex_size
|
||||
|
||||
|
||||
bootsectors = np.zeros([384], dtype=np.uint8)
|
||||
bootsectors[0:bootsize] = bootcode
|
||||
|
||||
|
@ -34,7 +34,7 @@ class MameZipImage(DiskImageBase):
|
||||
|
||||
def relaxed_check(self):
|
||||
pass
|
||||
|
||||
|
||||
def check_zip_size(self, zf):
|
||||
for item in zf.infolist():
|
||||
_, r = divmod(item.file_size, 16)
|
||||
@ -56,7 +56,7 @@ class MameZipImage(DiskImageBase):
|
||||
|
||||
def check_size(self):
|
||||
pass
|
||||
|
||||
|
||||
def parse_segments(self):
|
||||
r = self.rawdata
|
||||
self.segments = []
|
||||
|
@ -17,7 +17,7 @@ class SegmentParser(object):
|
||||
menu_name = ""
|
||||
image_type = None
|
||||
container_segment = DefaultSegment
|
||||
|
||||
|
||||
def __init__(self, segment_data, strict=False):
|
||||
self.image = None
|
||||
self.segments = []
|
||||
@ -53,7 +53,7 @@ class SegmentParser(object):
|
||||
|
||||
class DefaultSegmentParser(SegmentParser):
|
||||
menu_name = "Raw Data"
|
||||
|
||||
|
||||
def parse(self):
|
||||
self.segments = [DefaultSegment(self.segment_data, 0)]
|
||||
|
||||
@ -122,6 +122,7 @@ def guess_parser_for_mime(mime, r, verbose=False):
|
||||
pass
|
||||
return found
|
||||
|
||||
|
||||
def guess_parser_for_system(mime_base, r):
|
||||
for mime in mime_parse_order:
|
||||
if mime.startswith(mime_base):
|
||||
@ -130,6 +131,7 @@ def guess_parser_for_system(mime_base, r):
|
||||
return mime, p
|
||||
return None, None
|
||||
|
||||
|
||||
def iter_parsers(r):
|
||||
for mime in mime_parse_order:
|
||||
p = guess_parser_for_mime(mime, r)
|
||||
@ -197,6 +199,7 @@ known_segment_parsers = [DefaultSegmentParser]
|
||||
for mime in mime_parse_order:
|
||||
known_segment_parsers.extend(mime_parsers[mime])
|
||||
|
||||
|
||||
def iter_known_segment_parsers():
|
||||
yield "application/octet-stream", "", [DefaultSegmentParser]
|
||||
for mime in mime_parse_order:
|
||||
|
@ -16,6 +16,7 @@ match_bit_mask = 0x20
|
||||
comment_bit_mask = 0x40
|
||||
selected_bit_mask = 0x80
|
||||
|
||||
|
||||
def get_style_bits(match=False, comment=False, selected=False, data=False, diff=False, user=0):
|
||||
""" Return an int value that contains the specified style bits set.
|
||||
|
||||
@ -41,6 +42,7 @@ def get_style_bits(match=False, comment=False, selected=False, data=False, diff=
|
||||
style_bits |= selected_bit_mask
|
||||
return style_bits
|
||||
|
||||
|
||||
def get_style_mask(**kwargs):
|
||||
"""Get the bit mask that, when anded with data, will turn off the
|
||||
selected bits
|
||||
@ -51,12 +53,12 @@ def get_style_mask(**kwargs):
|
||||
else:
|
||||
bits &= (0xff ^ user_bit_mask)
|
||||
return 0xff ^ bits
|
||||
|
||||
|
||||
|
||||
class SegmentSaver(object):
|
||||
export_data_name = "Raw Data"
|
||||
export_extensions = [".dat"]
|
||||
|
||||
|
||||
@classmethod
|
||||
def encode_data(cls, segment, ui_control):
|
||||
return segment.tostring()
|
||||
@ -70,27 +72,28 @@ class OrderWrapper(object):
|
||||
intermediate layer is needed that defines the __setitem__ method that
|
||||
explicitly references the byte ordering in the data array.
|
||||
"""
|
||||
|
||||
def __init__(self, data, byte_order):
|
||||
self.np_data = data
|
||||
self.base = data.base # base array for numpy bounds determination
|
||||
self.order = byte_order
|
||||
|
||||
|
||||
def __len__(self):
|
||||
return np.alen(self.order)
|
||||
|
||||
|
||||
def __and__(self, other):
|
||||
return self.np_data[self.order] & other
|
||||
|
||||
|
||||
def __iand__(self, other):
|
||||
self.np_data[self.order] &= other
|
||||
return self
|
||||
|
||||
|
||||
def __getitem__(self, index):
|
||||
return self.np_data[self.order[index]]
|
||||
|
||||
|
||||
def __setitem__(self, index, value):
|
||||
self.np_data[self.order[index]] = value
|
||||
|
||||
|
||||
def sub_index(self, index):
|
||||
"""Return index of index so it can be used directly in a new
|
||||
SegmentData object, rather than propagating multiple index lookups by
|
||||
@ -109,6 +112,7 @@ class OrderWrapper(object):
|
||||
def tostring(self):
|
||||
return self.np_data[self.order].tostring()
|
||||
|
||||
|
||||
class UserExtraData(object):
|
||||
def __init__(self):
|
||||
self.comments = dict()
|
||||
@ -146,10 +150,10 @@ class SegmentData(object):
|
||||
extra = UserExtraData()
|
||||
self.extra = extra
|
||||
self.reverse_index_mapping = None
|
||||
|
||||
|
||||
def __str__(self):
|
||||
return "SegmentData id=%x indexed=%s data=%s" % (id(self), self.is_indexed, type(self.data))
|
||||
|
||||
|
||||
def __len__(self):
|
||||
return len(self.data)
|
||||
|
||||
@ -199,10 +203,10 @@ class SegmentData(object):
|
||||
@property
|
||||
def style_base(self):
|
||||
return self.style.np_data if self.is_indexed else self.style.base if self.style.base is not None else self.style
|
||||
|
||||
|
||||
def get_data(self):
|
||||
return self.data
|
||||
|
||||
|
||||
def get_style(self):
|
||||
return self.style
|
||||
|
||||
@ -217,7 +221,7 @@ class SegmentData(object):
|
||||
if self.is_indexed:
|
||||
return self.style.unindexed
|
||||
return self.style
|
||||
|
||||
|
||||
def byte_bounds_offset(self):
|
||||
"""Return start and end offsets of this segment's data into the
|
||||
base array's data.
|
||||
@ -234,7 +238,7 @@ class SegmentData(object):
|
||||
data_start, data_end = np.byte_bounds(self.data)
|
||||
base_start, base_end = np.byte_bounds(self.data.base)
|
||||
return int(data_start - base_start), int(data_end - base_start)
|
||||
|
||||
|
||||
def get_raw_index(self, i):
|
||||
"""Get index into base array's raw data, given the index into this
|
||||
segment
|
||||
@ -246,7 +250,7 @@ class SegmentData(object):
|
||||
data_start, data_end = np.byte_bounds(self.data)
|
||||
base_start, base_end = np.byte_bounds(self.data.base)
|
||||
return int(data_start - base_start + i)
|
||||
|
||||
|
||||
def get_indexes_from_base(self):
|
||||
"""Get array of indexes from the base array, as if this raw data were
|
||||
indexed.
|
||||
@ -258,7 +262,7 @@ class SegmentData(object):
|
||||
else:
|
||||
i = self.get_raw_index(0)
|
||||
return np.arange(i, i + len(self), dtype=np.uint32)
|
||||
|
||||
|
||||
def __getitem__(self, index):
|
||||
if self.is_indexed:
|
||||
order = self.data.sub_index(index)
|
||||
@ -289,7 +293,7 @@ class SegmentData(object):
|
||||
print "copy: start, end =", start, end
|
||||
copy = SegmentData(d[start:end], s[start:end])
|
||||
return copy
|
||||
|
||||
|
||||
def get_bases(self):
|
||||
if self.data.base is None:
|
||||
data_base = self.data
|
||||
@ -303,15 +307,15 @@ class SegmentData(object):
|
||||
index = to_numpy_list(index)
|
||||
if self.is_indexed:
|
||||
return self[index]
|
||||
|
||||
|
||||
# check to make sure all indexes are valid, raises IndexError if not
|
||||
check = self.data[index]
|
||||
|
||||
|
||||
# index needs to be relative to the base array
|
||||
base_index = index + self.get_raw_index(0)
|
||||
data_base, style_base = self.get_bases()
|
||||
return SegmentData(data_base, style_base, self.extra, order=base_index)
|
||||
|
||||
|
||||
def get_reverse_index(self, base_index):
|
||||
"""Get index into this segment's data given the index into the base data
|
||||
|
||||
@ -337,7 +341,7 @@ class DefaultSegment(object):
|
||||
savers = [SegmentSaver]
|
||||
use_origin_default = False
|
||||
can_resize_default = False
|
||||
|
||||
|
||||
def __init__(self, rawdata, start_addr=0, name="All", error=None, verbose_name=None):
|
||||
self.start_addr = int(start_addr) # force python int to decouple from possibly being a numpy datatype
|
||||
self.set_raw(rawdata)
|
||||
@ -355,13 +359,13 @@ class DefaultSegment(object):
|
||||
# Some segments may be resized to contain additional segments not
|
||||
# present when the segment was created.
|
||||
self.can_resize = self.__class__.can_resize_default
|
||||
|
||||
|
||||
def set_raw(self, rawdata):
|
||||
self.rawdata = rawdata
|
||||
self.data = rawdata.get_data()
|
||||
self.style = rawdata.get_style()
|
||||
self._search_copy = None
|
||||
|
||||
|
||||
def get_raw(self):
|
||||
return self.rawdata
|
||||
|
||||
@ -397,7 +401,7 @@ class DefaultSegment(object):
|
||||
|
||||
def replace_data(self, container):
|
||||
self.rawdata.replace_arrays(container.rawdata)
|
||||
|
||||
|
||||
def __getstate__(self):
|
||||
state = dict()
|
||||
for key in ['start_addr', 'error', 'name', 'verbose_name', 'page_size', 'map_width', 'uuid', 'use_origin', 'can_resize']:
|
||||
@ -424,7 +428,7 @@ class DefaultSegment(object):
|
||||
self.use_origin = self.__class__.use_origin_default
|
||||
if not hasattr(self, 'can_resize'):
|
||||
self.can_resize = self.__class__.can_resize_default
|
||||
|
||||
|
||||
def reconstruct_raw(self, rawdata):
|
||||
start, end = self._rawdata_bounds
|
||||
r = rawdata[start:end]
|
||||
@ -438,7 +442,7 @@ class DefaultSegment(object):
|
||||
pass
|
||||
self.set_raw(r)
|
||||
self.reconstruct_missing()
|
||||
|
||||
|
||||
def get_parallel_raw_data(self, other):
|
||||
""" Get the raw data that is similar to the specified other segment
|
||||
"""
|
||||
@ -463,7 +467,7 @@ class DefaultSegment(object):
|
||||
if r:
|
||||
slot = "user style %d" % i
|
||||
mdict[slot] = r
|
||||
|
||||
|
||||
# json serialization doesn't allow int keys, so convert to list of
|
||||
# pairs
|
||||
mdict["comments"] = self.get_sorted_comments()
|
||||
@ -492,7 +496,6 @@ class DefaultSegment(object):
|
||||
if slot in e:
|
||||
self.set_style_ranges(e[slot], user=i)
|
||||
|
||||
|
||||
def __str__(self):
|
||||
if self.start_addr > 0:
|
||||
origin = " @ %04x" % (self.start_addr)
|
||||
@ -502,7 +505,7 @@ class DefaultSegment(object):
|
||||
if self.error:
|
||||
s += " " + self.error
|
||||
return s
|
||||
|
||||
|
||||
@property
|
||||
def verbose_info(self):
|
||||
name = self.verbose_name or self.name
|
||||
@ -513,32 +516,32 @@ class DefaultSegment(object):
|
||||
if self.error:
|
||||
s += " error='%s'" % self.error
|
||||
return s
|
||||
|
||||
|
||||
def __len__(self):
|
||||
return len(self.rawdata)
|
||||
|
||||
|
||||
def __getitem__(self, index):
|
||||
return self.data[index]
|
||||
|
||||
|
||||
def __setitem__(self, index, value):
|
||||
self.data[index] = value
|
||||
self._search_copy = None
|
||||
|
||||
|
||||
def byte_bounds_offset(self):
|
||||
"""Return start and end offsets of this segment's data into the
|
||||
base array's data
|
||||
"""
|
||||
return self.rawdata.byte_bounds_offset()
|
||||
|
||||
|
||||
def is_valid_index(self, i):
|
||||
return i >= 0 and i < len(self)
|
||||
|
||||
|
||||
def get_raw_index(self, i):
|
||||
"""Get index into base array's raw data, given the index into this
|
||||
segment
|
||||
"""
|
||||
return self.rawdata.get_raw_index(i)
|
||||
|
||||
|
||||
def get_index_from_base_index(self, base_index):
|
||||
"""Get index into this array's data given the index into the base array
|
||||
"""
|
||||
@ -553,13 +556,13 @@ class DefaultSegment(object):
|
||||
|
||||
def tostring(self):
|
||||
return self.data.tostring()
|
||||
|
||||
|
||||
def get_style_bits(self, **kwargs):
|
||||
return get_style_bits(**kwargs)
|
||||
|
||||
|
||||
def get_style_mask(self, **kwargs):
|
||||
return get_style_mask(**kwargs)
|
||||
|
||||
|
||||
def set_style_ranges(self, ranges, **kwargs):
|
||||
style_bits = self.get_style_bits(**kwargs)
|
||||
s = self.style
|
||||
@ -567,7 +570,7 @@ class DefaultSegment(object):
|
||||
if end < start:
|
||||
start, end = end, start
|
||||
s[start:end] |= style_bits
|
||||
|
||||
|
||||
def clear_style_ranges(self, ranges, **kwargs):
|
||||
style_mask = self.get_style_mask(**kwargs)
|
||||
s = self.style
|
||||
@ -575,14 +578,14 @@ class DefaultSegment(object):
|
||||
if end < start:
|
||||
start, end = end, start
|
||||
s[start:end] &= style_mask
|
||||
|
||||
|
||||
def get_style_ranges(self, **kwargs):
|
||||
"""Return a list of start, end pairs that match the specified style
|
||||
"""
|
||||
style_bits = self.get_style_bits(**kwargs)
|
||||
matches = (self.style & style_bits) == style_bits
|
||||
return self.bool_to_ranges(matches)
|
||||
|
||||
|
||||
def get_comment_locations(self, **kwargs):
|
||||
style_bits = self.get_style_bits(**kwargs)
|
||||
r = self.rawdata.copy()
|
||||
@ -655,7 +658,7 @@ class DefaultSegment(object):
|
||||
if np.alen(group) > 0:
|
||||
ranges.append((int(group[0]), int(group[-1]) + 1))
|
||||
return ranges
|
||||
|
||||
|
||||
def find_next(self, index, **kwargs):
|
||||
ranges = self.get_style_ranges(**kwargs)
|
||||
if len(ranges) > 0:
|
||||
@ -665,7 +668,7 @@ class DefaultSegment(object):
|
||||
match_index = 0
|
||||
return ranges[match_index][0]
|
||||
return None
|
||||
|
||||
|
||||
def find_previous(self, index, **kwargs):
|
||||
ranges = self.get_style_ranges(**kwargs)
|
||||
if len(ranges) > 0:
|
||||
@ -676,7 +679,7 @@ class DefaultSegment(object):
|
||||
match_index = len(ranges) - 1
|
||||
return ranges[match_index][0]
|
||||
return None
|
||||
|
||||
|
||||
def get_rect_indexes(self, anchor_start, anchor_end):
|
||||
# determine row,col of upper left and lower right of selected
|
||||
# rectangle. The values are inclusive, so ul=(0,0) and lr=(1,2)
|
||||
@ -714,7 +717,7 @@ class DefaultSegment(object):
|
||||
anchor_end = r2 * bpr + c2
|
||||
r2 += 1
|
||||
return anchor_start, anchor_end, (r1, c1), (r2, c2)
|
||||
|
||||
|
||||
def set_style_ranges_rect(self, ranges, **kwargs):
|
||||
style_bits = self.get_style_bits(**kwargs)
|
||||
s = self.style
|
||||
@ -741,7 +744,7 @@ class DefaultSegment(object):
|
||||
c = c2 - c1
|
||||
indexes = np.tile(np.arange(c), r) + np.repeat(np.arange(r) * self.map_width, c) + start
|
||||
s[indexes] |= style_bits
|
||||
|
||||
|
||||
def rects_to_ranges(self, rects):
|
||||
ranges = []
|
||||
bpr = self.map_width
|
||||
@ -750,25 +753,25 @@ class DefaultSegment(object):
|
||||
end = (r2 - 1) * bpr + c2
|
||||
ranges.append((start, end))
|
||||
return ranges
|
||||
|
||||
|
||||
def clear_style_bits(self, **kwargs):
|
||||
style_mask = self.get_style_mask(**kwargs)
|
||||
self.style &= style_mask
|
||||
|
||||
|
||||
def set_user_data(self, ranges, user_index, user_data):
|
||||
for start, end in ranges:
|
||||
# FIXME: this is slow
|
||||
for i in range(start, end):
|
||||
rawindex = self.get_raw_index(i)
|
||||
self.rawdata.extra.user_data[user_index][rawindex] = user_data
|
||||
|
||||
|
||||
def get_user_data(self, index, user_index):
|
||||
rawindex = self.get_raw_index(index)
|
||||
try:
|
||||
return self.rawdata.extra.user_data[user_index][rawindex]
|
||||
except KeyError:
|
||||
return 0
|
||||
|
||||
|
||||
def get_sorted_user_data(self, user_index):
|
||||
d = self.rawdata.extra.user_data[user_index]
|
||||
indexes = sorted(d.keys())
|
||||
@ -787,7 +790,7 @@ class DefaultSegment(object):
|
||||
if start is not None:
|
||||
ranges.append([[start, end], current])
|
||||
return ranges
|
||||
|
||||
|
||||
def get_style_at_indexes(self, indexes):
|
||||
return self.style[indexes]
|
||||
|
||||
@ -893,7 +896,7 @@ class DefaultSegment(object):
|
||||
self.set_style_ranges(ranges, comment=True)
|
||||
for start, end in ranges:
|
||||
self.set_comment_at(start, text)
|
||||
|
||||
|
||||
def get_comment(self, index):
|
||||
rawindex = self.get_raw_index(index)
|
||||
return self.rawdata.extra.comments.get(rawindex, "")
|
||||
@ -904,19 +907,19 @@ class DefaultSegment(object):
|
||||
del self.rawdata.extra.comments[rawindex]
|
||||
except KeyError:
|
||||
pass
|
||||
|
||||
|
||||
def get_first_comment(self, ranges):
|
||||
start = reduce(min, [r[0] for r in ranges])
|
||||
rawindex = self.get_raw_index(start)
|
||||
return self.rawdata.extra.comments.get(rawindex, "")
|
||||
|
||||
|
||||
def clear_comment(self, ranges):
|
||||
self.clear_style_ranges(ranges, comment=True)
|
||||
for start, end in ranges:
|
||||
rawindex = self.get_raw_index(start)
|
||||
if rawindex in self.rawdata.extra.comments:
|
||||
del self.rawdata.extra.comments[rawindex]
|
||||
|
||||
|
||||
def get_sorted_comments(self):
|
||||
return sorted([[k, v] for k, v in self.rawdata.extra.comments.iteritems()])
|
||||
|
||||
@ -927,19 +930,19 @@ class DefaultSegment(object):
|
||||
for k, v in self.rawdata.extra.comments.iteritems():
|
||||
if k >= start_index and k < end_index:
|
||||
yield self.rawdata.get_reverse_index(k), v
|
||||
|
||||
|
||||
def label(self, index, lower_case=True):
|
||||
if lower_case:
|
||||
return "%04x" % (index + self.start_addr)
|
||||
else:
|
||||
return "%04X" % (index + self.start_addr)
|
||||
|
||||
|
||||
@property
|
||||
def search_copy(self):
|
||||
if self._search_copy is None:
|
||||
self._search_copy = self.data.tostring()
|
||||
return self._search_copy
|
||||
|
||||
|
||||
def compare_segment(self, other_segment):
|
||||
self.clear_style_bits(diff=True)
|
||||
diff = self.rawdata.data != other_segment.rawdata.data
|
||||
@ -953,20 +956,20 @@ class DefaultSegment(object):
|
||||
class EmptySegment(DefaultSegment):
|
||||
def __init__(self, rawdata, name="", error=None):
|
||||
DefaultSegment.__init__(self, rawdata, 0, name, error)
|
||||
|
||||
|
||||
def __str__(self):
|
||||
s = "%s (empty file)" % (self.name, )
|
||||
if self.error:
|
||||
s += " " + self.error
|
||||
return s
|
||||
|
||||
|
||||
@property
|
||||
def verbose_info(self):
|
||||
s = "%s (empty file)" % (self.name, )
|
||||
if self.error:
|
||||
s += " error='%s'" % self.error
|
||||
return s
|
||||
|
||||
|
||||
def __len__(self):
|
||||
return 0
|
||||
|
||||
@ -977,14 +980,14 @@ class ObjSegment(DefaultSegment):
|
||||
self.metadata_start = metadata_start
|
||||
self.data_start = data_start
|
||||
self.use_origin = True
|
||||
|
||||
|
||||
def __str__(self):
|
||||
count = len(self)
|
||||
s = "%s $%04x-$%04x ($%04x @ $%04x)" % (self.name, self.start_addr, self.start_addr + count, count, self.data_start)
|
||||
if self.error:
|
||||
s += " " + self.error
|
||||
return s
|
||||
|
||||
|
||||
@property
|
||||
def verbose_info(self):
|
||||
count = len(self)
|
||||
@ -1007,7 +1010,7 @@ class RawSectorsSegment(DefaultSegment):
|
||||
self.page_size = sector_size
|
||||
self.first_sector = first_sector
|
||||
self.num_sectors = num_sectors
|
||||
|
||||
|
||||
def __str__(self):
|
||||
if self.num_sectors > 1:
|
||||
s = "%s (sectors %d-%d)" % (self.name, self.first_sector, self.first_sector + self.num_sectors - 1)
|
||||
@ -1016,7 +1019,7 @@ class RawSectorsSegment(DefaultSegment):
|
||||
if self.error:
|
||||
s += " " + self.error
|
||||
return s
|
||||
|
||||
|
||||
@property
|
||||
def verbose_info(self):
|
||||
name = self.verbose_name or self.name
|
||||
@ -1028,7 +1031,7 @@ class RawSectorsSegment(DefaultSegment):
|
||||
if self.error:
|
||||
s += " error='%s'" % self.error
|
||||
return s
|
||||
|
||||
|
||||
def label(self, index, lower_case=True):
|
||||
boot_size = self.num_boot_sectors * self.boot_sector_size
|
||||
if index >= boot_size:
|
||||
@ -1055,6 +1058,7 @@ class RawTrackSectorSegment(RawSectorsSegment):
|
||||
return "t%02ds%02d:%02x" % (t, s, byte)
|
||||
return "t%02ds%02d:%02X" % (t, s, byte)
|
||||
|
||||
|
||||
def interleave_indexes(segments, num_bytes):
|
||||
num_segments = len(segments)
|
||||
size = len(segments[0])
|
||||
@ -1074,6 +1078,7 @@ def interleave_indexes(segments, num_bytes):
|
||||
start += 1
|
||||
return interleave
|
||||
|
||||
|
||||
def interleave_segments(segments, num_bytes):
|
||||
new_index = interleave_indexes(segments, num_bytes)
|
||||
data_base, style_base = segments[0].rawdata.get_bases()
|
||||
|
@ -30,7 +30,7 @@ class SpartaDosDirent(AtariDosDirent):
|
||||
# rather the boot sector so it must be specified here.
|
||||
self.starting_sector = starting_sector
|
||||
self.is_sane = self.sanity_check(image)
|
||||
|
||||
|
||||
def __str__(self):
|
||||
output = "o" if self.opened_output else "."
|
||||
subdir = "D" if self.is_dir else "."
|
||||
@ -39,7 +39,7 @@ class SpartaDosDirent(AtariDosDirent):
|
||||
locked = "*" if self.locked else " "
|
||||
flags = "%s%s%s%s%s %03d" % (output, subdir, in_use, deleted, locked, self.starting_sector)
|
||||
return "File #%-2d (%s) %-8s%-3s %8d %s" % (self.file_num, flags, self.filename, self.ext, self.length, self.str_timestamp)
|
||||
|
||||
|
||||
@property
|
||||
def verbose_info(self):
|
||||
flags = []
|
||||
@ -49,11 +49,11 @@ class SpartaDosDirent(AtariDosDirent):
|
||||
if self.deleted: flags.append("DEL")
|
||||
if self.locked: flags.append("LOCK")
|
||||
return "flags=[%s]" % ", ".join(flags)
|
||||
|
||||
|
||||
def parse_raw_dirent(self, image, bytes):
|
||||
if bytes is None:
|
||||
return
|
||||
values = bytes.view(dtype=self.format)[0]
|
||||
values = bytes.view(dtype=self.format)[0]
|
||||
flag = values['status']
|
||||
self.flag = flag
|
||||
self.locked = (flag&0x1) > 0
|
||||
@ -73,14 +73,14 @@ class SpartaDosDirent(AtariDosDirent):
|
||||
self.date_array = tuple(bytes[17:20])
|
||||
self.time_array = tuple(bytes[20:23])
|
||||
self.is_sane = self.sanity_check(image)
|
||||
|
||||
|
||||
def sanity_check(self, image):
|
||||
if not self.in_use:
|
||||
return True
|
||||
if not image.header.sector_is_valid(self.starting_sector):
|
||||
return False
|
||||
return True
|
||||
|
||||
|
||||
@property
|
||||
def str_timestamp(self):
|
||||
str_date = "%d/%d/%d" % self.date_array
|
||||
@ -94,7 +94,7 @@ class SpartaDosDirent(AtariDosDirent):
|
||||
self.sector_map = image.get_sector_map(self.starting_sector)
|
||||
self.sector_map_index = 0
|
||||
self.length_remaining = self.length
|
||||
|
||||
|
||||
def read_sector(self, image):
|
||||
sector = self.sector_map[self.sector_map_index]
|
||||
if sector == 0:
|
||||
@ -114,10 +114,10 @@ class SpartaDosDiskImage(AtariDosDiskImage):
|
||||
self.root_dir_dirent = None
|
||||
self.fs_version = 0
|
||||
AtariDosDiskImage.__init__(self, *args, **kwargs)
|
||||
|
||||
|
||||
def __str__(self):
|
||||
return "%s Sparta DOS Format: %d usable sectors (%d free), %d files" % (self.header, self.total_sectors, self.unused_sectors, len(self.files))
|
||||
|
||||
|
||||
boot_record_type = np.dtype([
|
||||
('unused', 'u1'),
|
||||
('num_boot', 'u1'),
|
||||
@ -137,12 +137,12 @@ class SpartaDosDiskImage(AtariDosDiskImage):
|
||||
('sector_size','u1'),
|
||||
('fs_version','u1'),
|
||||
])
|
||||
|
||||
|
||||
sector_size_map = {0: 256,
|
||||
1: 512,
|
||||
0x80: 128,
|
||||
}
|
||||
|
||||
|
||||
def get_boot_sector_info(self):
|
||||
data, style = self.get_sectors(1)
|
||||
values = data[0:33].view(dtype=self.boot_record_type)[0]
|
||||
@ -163,7 +163,7 @@ class SpartaDosDiskImage(AtariDosDiskImage):
|
||||
|
||||
def get_vtoc(self):
|
||||
pass
|
||||
|
||||
|
||||
def get_directory(self):
|
||||
self.files = []
|
||||
dir_map = self.get_sector_map(self.root_dir)
|
||||
@ -177,7 +177,7 @@ class SpartaDosDiskImage(AtariDosDiskImage):
|
||||
dirent = SpartaDosDirent(self, filenum + 1, s[i:i + 23])
|
||||
self.files.append(dirent)
|
||||
self.root_dir_dirent = d
|
||||
|
||||
|
||||
def get_boot_segments(self):
|
||||
segments = []
|
||||
num = min(self.num_boot, 1)
|
||||
@ -191,7 +191,7 @@ class SpartaDosDiskImage(AtariDosDiskImage):
|
||||
code = ObjSegment(r[43:], 0, 0, addr + 43, addr + len(r), name="Boot Code")
|
||||
segments.extend([header, code])
|
||||
return segments
|
||||
|
||||
|
||||
def get_vtoc_segments(self):
|
||||
r = self.rawdata
|
||||
segments = []
|
||||
@ -206,7 +206,7 @@ class SpartaDosDiskImage(AtariDosDiskImage):
|
||||
segment = RawSectorsSegment(r[start:start+count], self.first_bitmap, self.num_bitmap, count, 0, 0, self.sector_size, name="Bitmap")
|
||||
segments.append(segment)
|
||||
return segments
|
||||
|
||||
|
||||
def get_sector_map(self, sector):
|
||||
m = None
|
||||
while sector > 0:
|
||||
@ -217,7 +217,7 @@ class SpartaDosDiskImage(AtariDosDiskImage):
|
||||
else:
|
||||
m = np.hstack((m, b[4:].view(dtype='<u2')))
|
||||
return m
|
||||
|
||||
|
||||
def get_directory_segments(self):
|
||||
dirent = self.root_dir_dirent
|
||||
segment = self.get_file_segment(dirent)
|
||||
@ -225,7 +225,7 @@ class SpartaDosDiskImage(AtariDosDiskImage):
|
||||
segment.map_width = 23
|
||||
segments = [segment]
|
||||
return segments
|
||||
|
||||
|
||||
def get_file_segment(self, dirent):
|
||||
byte_order = []
|
||||
dirent.start_read(self)
|
||||
|
@ -137,6 +137,7 @@ class Dirent(object):
|
||||
"""Abstract base class for a directory entry
|
||||
|
||||
"""
|
||||
|
||||
def __init__(self, file_num=0):
|
||||
self.file_num = file_num
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user