From b0500ecd5ab7a2b59716c6865fb1aaf880e4669e Mon Sep 17 00:00:00 2001 From: Christopher Kobayashi Date: Mon, 4 Apr 2016 17:49:11 +0900 Subject: [PATCH 01/19] Skip first 128 bytes if -t/--tifiles is an argument. Allows listing programs in TIFILES format without altering source. TIFILES write support is forthcoming in the next few days. --- xbas99.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/xbas99.py b/xbas99.py index bdf7dff..0e924c0 100755 --- a/xbas99.py +++ b/xbas99.py @@ -493,6 +493,8 @@ def main(): help="join split source lines (for -e)") args.add_argument("-o", "--output", dest="output", metavar="", help="set output filename") + args.add_argument("-t", "--tifiles", action="store_true", dest="astifiles", + help="assume TIFILES format program to list or decode") opts = args.parse_args() #setup @@ -507,6 +509,8 @@ def main(): else: with open(opts.source, "rb") as fin: image = fin.read() + if opts.astifiles: + image = image[128:] if opts.merge: program = BasicProgram() program.merge(image) From fac201de97e56184417ebf460f39b5f3191de1d6 Mon Sep 17 00:00:00 2001 From: Christopher KOBAYASHI Date: Tue, 5 Apr 2016 14:53:47 +0900 Subject: [PATCH 02/19] Convert from IV254 to PROGRAM to handle TIFILES formatted files. This should fix erroneous "program is corrupt" issues while decoding. --- xbas99.py | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-) diff --git a/xbas99.py b/xbas99.py index 0e924c0..e017f49 100755 --- a/xbas99.py +++ b/xbas99.py @@ -22,6 +22,7 @@ import sys import re import os.path +import traceback VERSION = "1.5.0" @@ -169,15 +170,16 @@ class BasicProgram: # maximum number of bytes/tokens per BASIC line maxTokensPerLine = 254 - def __init__(self, data=None, source=None, long_=False): + def __init__(self, data=None, source=None, long_=False, _tifiles=False): self.lines = {} self.textlits = [] self.warnings = [] if data: try: - self.load(data, long_) + self.load(data, long_, _tifiles) except IndexError: self.warn("Program file is corrupted") + print traceback.format_exc() elif source: self.parse(source) @@ -188,7 +190,13 @@ def warn(self, text): # program -> source - def load(self, data, long_): + def load(self, data, long_, _tifiles): + if _tifiles: + newdata = data[0:11] + print len(data) + for i in range(1, (len(data) / 255)): + newdata += data[(i*256):(i*256)+255] + data = newdata """load tokenized BASIC program""" if long_ or data[1:3] == "\xab\xcd": # convert long format INT/VAR 254 to PROGRAM @@ -468,6 +476,7 @@ def join(lines, minLinoDelta=1, maxLinoDelta=3): def main(): import argparse + tifiles = False args = argparse.ArgumentParser( version=VERSION, @@ -511,11 +520,12 @@ def main(): image = fin.read() if opts.astifiles: image = image[128:] + tifiles = True if opts.merge: program = BasicProgram() program.merge(image) else: - program = BasicProgram(data=image, long_=opts.long_) + program = BasicProgram(data=image, long_=opts.long_, _tifiles=tifiles) data = program.getSource() output = "-" if opts.list_ else opts.output or barename + ".b99" elif opts.dump: From d4ab1bf1f15fe4aa6e74e4e9964c39f71e27a83d Mon Sep 17 00:00:00 2001 From: Christopher KOBAYASHI Date: Tue, 5 Apr 2016 15:04:03 +0900 Subject: [PATCH 03/19] Only do IV254 conversion if program actually is IV254. --- xbas99.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/xbas99.py b/xbas99.py index e017f49..2af3ca8 100755 --- a/xbas99.py +++ b/xbas99.py @@ -191,15 +191,15 @@ def warn(self, text): # program -> source def load(self, data, long_, _tifiles): - if _tifiles: + """load tokenized BASIC program""" + if long_ or data[1:3] == "\xab\xcd": + # convert long format INT/VAR 254 to PROGRAM + if _tifiles: newdata = data[0:11] print len(data) for i in range(1, (len(data) / 255)): newdata += data[(i*256):(i*256)+255] data = newdata - """load tokenized BASIC program""" - if long_ or data[1:3] == "\xab\xcd": - # convert long format INT/VAR 254 to PROGRAM program, p = "", 11 while p < len(data): l = ord(data[p]) + 1 From ce99b70d578a4c60f5176525564e8e7e19a85b11 Mon Sep 17 00:00:00 2001 From: Christopher KOBAYASHI Date: Tue, 5 Apr 2016 15:18:29 +0900 Subject: [PATCH 04/19] Fix off-by-one and remove debug print statement. --- xbas99.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/xbas99.py b/xbas99.py index 2af3ca8..b7b959a 100755 --- a/xbas99.py +++ b/xbas99.py @@ -196,8 +196,7 @@ def load(self, data, long_, _tifiles): # convert long format INT/VAR 254 to PROGRAM if _tifiles: newdata = data[0:11] - print len(data) - for i in range(1, (len(data) / 255)): + for i in range(1, (len(data) / 256)): newdata += data[(i*256):(i*256)+255] data = newdata program, p = "", 11 From 300eac4151bbccfb0fa9e0e91f5ec067964905ea Mon Sep 17 00:00:00 2001 From: Christopher Kobayashi Date: Wed, 6 Apr 2016 15:31:52 +0900 Subject: [PATCH 05/19] Revert "Fix off-by-one and remove debug print statement." This reverts commit ce99b70d578a4c60f5176525564e8e7e19a85b11. --- xbas99.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/xbas99.py b/xbas99.py index b7b959a..2af3ca8 100755 --- a/xbas99.py +++ b/xbas99.py @@ -196,7 +196,8 @@ def load(self, data, long_, _tifiles): # convert long format INT/VAR 254 to PROGRAM if _tifiles: newdata = data[0:11] - for i in range(1, (len(data) / 256)): + print len(data) + for i in range(1, (len(data) / 255)): newdata += data[(i*256):(i*256)+255] data = newdata program, p = "", 11 From aec042ba68dfd79fc32bda1a2be5f68e6c2f32b5 Mon Sep 17 00:00:00 2001 From: Christopher Kobayashi Date: Wed, 6 Apr 2016 15:32:10 +0900 Subject: [PATCH 06/19] Revert "Only do IV254 conversion if program actually is IV254." This reverts commit d4ab1bf1f15fe4aa6e74e4e9964c39f71e27a83d. --- xbas99.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/xbas99.py b/xbas99.py index 2af3ca8..e017f49 100755 --- a/xbas99.py +++ b/xbas99.py @@ -191,15 +191,15 @@ def warn(self, text): # program -> source def load(self, data, long_, _tifiles): - """load tokenized BASIC program""" - if long_ or data[1:3] == "\xab\xcd": - # convert long format INT/VAR 254 to PROGRAM - if _tifiles: + if _tifiles: newdata = data[0:11] print len(data) for i in range(1, (len(data) / 255)): newdata += data[(i*256):(i*256)+255] data = newdata + """load tokenized BASIC program""" + if long_ or data[1:3] == "\xab\xcd": + # convert long format INT/VAR 254 to PROGRAM program, p = "", 11 while p < len(data): l = ord(data[p]) + 1 From e8c3ee4127123b78207fa012bec586898fd7c415 Mon Sep 17 00:00:00 2001 From: Christopher Kobayashi Date: Wed, 6 Apr 2016 15:32:29 +0900 Subject: [PATCH 07/19] Revert "Convert from IV254 to PROGRAM to handle TIFILES formatted files. This should fix erroneous "program is corrupt" issues while decoding." This reverts commit fac201de97e56184417ebf460f39b5f3191de1d6. --- xbas99.py | 18 ++++-------------- 1 file changed, 4 insertions(+), 14 deletions(-) diff --git a/xbas99.py b/xbas99.py index e017f49..0e924c0 100755 --- a/xbas99.py +++ b/xbas99.py @@ -22,7 +22,6 @@ import sys import re import os.path -import traceback VERSION = "1.5.0" @@ -170,16 +169,15 @@ class BasicProgram: # maximum number of bytes/tokens per BASIC line maxTokensPerLine = 254 - def __init__(self, data=None, source=None, long_=False, _tifiles=False): + def __init__(self, data=None, source=None, long_=False): self.lines = {} self.textlits = [] self.warnings = [] if data: try: - self.load(data, long_, _tifiles) + self.load(data, long_) except IndexError: self.warn("Program file is corrupted") - print traceback.format_exc() elif source: self.parse(source) @@ -190,13 +188,7 @@ def warn(self, text): # program -> source - def load(self, data, long_, _tifiles): - if _tifiles: - newdata = data[0:11] - print len(data) - for i in range(1, (len(data) / 255)): - newdata += data[(i*256):(i*256)+255] - data = newdata + def load(self, data, long_): """load tokenized BASIC program""" if long_ or data[1:3] == "\xab\xcd": # convert long format INT/VAR 254 to PROGRAM @@ -476,7 +468,6 @@ def join(lines, minLinoDelta=1, maxLinoDelta=3): def main(): import argparse - tifiles = False args = argparse.ArgumentParser( version=VERSION, @@ -520,12 +511,11 @@ def main(): image = fin.read() if opts.astifiles: image = image[128:] - tifiles = True if opts.merge: program = BasicProgram() program.merge(image) else: - program = BasicProgram(data=image, long_=opts.long_, _tifiles=tifiles) + program = BasicProgram(data=image, long_=opts.long_) data = program.getSource() output = "-" if opts.list_ else opts.output or barename + ".b99" elif opts.dump: From 47fa4d61240973d1a19743b623f8f0ed195d453c Mon Sep 17 00:00:00 2001 From: Christopher Kobayashi Date: Thu, 7 Apr 2016 08:58:19 +0900 Subject: [PATCH 08/19] Attempt to autodetect IV254 (at image read time), and stub in IV254 write. --- xbas99.py | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/xbas99.py b/xbas99.py index 0e924c0..ca45c8d 100755 --- a/xbas99.py +++ b/xbas99.py @@ -412,8 +412,10 @@ def getImage(self, long_=False, protected=False): chrw(checksum) + chrw(lastAddr - 1)) chunks = [(linoTable + tokenTable)[i:i + 254] for i in xrange(0, len(linoTable + tokenTable), 254)] - return (chr(len(header)) + header + - "".join([chr(len(c)) + c for c in chunks])) + return (chr(len(header)) + header + chr(0x00)*(len(header)-1) + + chr(0xff) + + (chr(0x00)*(254-len(header))) + chr(0xfe) + + "".join([chr(len(c)) + c + chr(0xff) for c in chunks])) else: header = (chrw(checksum) + chrw(tokenTabAddr - 1) + chrw(linoTabAddr) + chrw(lastAddr - 1)) @@ -511,6 +513,8 @@ def main(): image = fin.read() if opts.astifiles: image = image[128:] + if image[1:3] == "\xab\xcd": + long_ = True; if opts.merge: program = BasicProgram() program.merge(image) From 4a655d34e4c6c2e566e5f98bbce2b8e539cd4783 Mon Sep 17 00:00:00 2001 From: Christopher Kobayashi Date: Thu, 7 Apr 2016 09:00:45 +0900 Subject: [PATCH 09/19] Git will be the death of me. This reverts commit e8c3ee4127123b78207fa012bec586898fd7c415. --- xbas99.py | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-) diff --git a/xbas99.py b/xbas99.py index ca45c8d..d4dfdd5 100755 --- a/xbas99.py +++ b/xbas99.py @@ -22,6 +22,7 @@ import sys import re import os.path +import traceback VERSION = "1.5.0" @@ -169,15 +170,16 @@ class BasicProgram: # maximum number of bytes/tokens per BASIC line maxTokensPerLine = 254 - def __init__(self, data=None, source=None, long_=False): + def __init__(self, data=None, source=None, long_=False, _tifiles=False): self.lines = {} self.textlits = [] self.warnings = [] if data: try: - self.load(data, long_) + self.load(data, long_, _tifiles) except IndexError: self.warn("Program file is corrupted") + print traceback.format_exc() elif source: self.parse(source) @@ -188,7 +190,13 @@ def warn(self, text): # program -> source - def load(self, data, long_): + def load(self, data, long_, _tifiles): + if _tifiles: + newdata = data[0:11] + print len(data) + for i in range(1, (len(data) / 255)): + newdata += data[(i*256):(i*256)+255] + data = newdata """load tokenized BASIC program""" if long_ or data[1:3] == "\xab\xcd": # convert long format INT/VAR 254 to PROGRAM @@ -470,6 +478,7 @@ def join(lines, minLinoDelta=1, maxLinoDelta=3): def main(): import argparse + tifiles = False args = argparse.ArgumentParser( version=VERSION, @@ -513,13 +522,14 @@ def main(): image = fin.read() if opts.astifiles: image = image[128:] + tifiles = True if image[1:3] == "\xab\xcd": long_ = True; if opts.merge: program = BasicProgram() program.merge(image) else: - program = BasicProgram(data=image, long_=opts.long_) + program = BasicProgram(data=image, long_=opts.long_, _tifiles=tifiles) data = program.getSource() output = "-" if opts.list_ else opts.output or barename + ".b99" elif opts.dump: From bec62314c7bfcfa0d725cd43661f7c97b1502bfe Mon Sep 17 00:00:00 2001 From: Christopher Kobayashi Date: Thu, 7 Apr 2016 09:02:12 +0900 Subject: [PATCH 10/19] Revert "Revert "Fix off-by-one and remove debug print statement."" because it apparently is needed. This reverts commit 300eac4151bbccfb0fa9e0e91f5ec067964905ea. --- xbas99.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/xbas99.py b/xbas99.py index d4dfdd5..9391252 100755 --- a/xbas99.py +++ b/xbas99.py @@ -193,8 +193,7 @@ def warn(self, text): def load(self, data, long_, _tifiles): if _tifiles: newdata = data[0:11] - print len(data) - for i in range(1, (len(data) / 255)): + for i in range(1, (len(data) / 256)): newdata += data[(i*256):(i*256)+255] data = newdata """load tokenized BASIC program""" From 9247088bf31e17958cb76700151cb03b86bc6448 Mon Sep 17 00:00:00 2001 From: Christopher Kobayashi Date: Thu, 7 Apr 2016 09:08:07 +0900 Subject: [PATCH 11/19] Zap typo that shows that I'm a C programmer at heart. --- xbas99.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/xbas99.py b/xbas99.py index 9391252..5eb6868 100755 --- a/xbas99.py +++ b/xbas99.py @@ -523,7 +523,7 @@ def main(): image = image[128:] tifiles = True if image[1:3] == "\xab\xcd": - long_ = True; + long_ = True if opts.merge: program = BasicProgram() program.merge(image) From 5ab281b24f6a611da78f37edb76ebc083dc6950e Mon Sep 17 00:00:00 2001 From: Christopher Kobayashi Date: Thu, 7 Apr 2016 09:19:09 +0900 Subject: [PATCH 12/19] Properly set long_ for propagation through program, and switch from _tifiles to tifiles_ --- xbas99.py | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/xbas99.py b/xbas99.py index 5eb6868..d9483a3 100755 --- a/xbas99.py +++ b/xbas99.py @@ -170,13 +170,13 @@ class BasicProgram: # maximum number of bytes/tokens per BASIC line maxTokensPerLine = 254 - def __init__(self, data=None, source=None, long_=False, _tifiles=False): + def __init__(self, data=None, source=None, long_=False, tifiles_=False): self.lines = {} self.textlits = [] self.warnings = [] if data: try: - self.load(data, long_, _tifiles) + self.load(data, long_, tifiles_) except IndexError: self.warn("Program file is corrupted") print traceback.format_exc() @@ -190,8 +190,8 @@ def warn(self, text): # program -> source - def load(self, data, long_, _tifiles): - if _tifiles: + def load(self, data, long_, tifiles_): + if long_ and tifiles_: newdata = data[0:11] for i in range(1, (len(data) / 256)): newdata += data[(i*256):(i*256)+255] @@ -523,12 +523,12 @@ def main(): image = image[128:] tifiles = True if image[1:3] == "\xab\xcd": - long_ = True + opts.long_ = True if opts.merge: program = BasicProgram() program.merge(image) else: - program = BasicProgram(data=image, long_=opts.long_, _tifiles=tifiles) + program = BasicProgram(data=image, long_=opts.long_, tifiles_=tifiles) data = program.getSource() output = "-" if opts.list_ else opts.output or barename + ".b99" elif opts.dump: From 820db7e1f82c776acb1906121ce8df8b6146ab02 Mon Sep 17 00:00:00 2001 From: Christopher Kobayashi Date: Thu, 7 Apr 2016 09:41:24 +0900 Subject: [PATCH 13/19] Revert this properly. --- xbas99.py | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/xbas99.py b/xbas99.py index d9483a3..980fcb5 100755 --- a/xbas99.py +++ b/xbas99.py @@ -419,9 +419,7 @@ def getImage(self, long_=False, protected=False): chrw(checksum) + chrw(lastAddr - 1)) chunks = [(linoTable + tokenTable)[i:i + 254] for i in xrange(0, len(linoTable + tokenTable), 254)] - return (chr(len(header)) + header + chr(0x00)*(len(header)-1) + - chr(0xff) + - (chr(0x00)*(254-len(header))) + chr(0xfe) + + return (chr(len(header)) + header + (chr(0x00)*(256-len(header)) + "".join([chr(len(c)) + c + chr(0xff) for c in chunks])) else: header = (chrw(checksum) + chrw(tokenTabAddr - 1) + From 162a9d3df5d937356c5081c72df5ef1e01893a64 Mon Sep 17 00:00:00 2001 From: Christopher Kobayashi Date: Thu, 7 Apr 2016 09:50:02 +0900 Subject: [PATCH 14/19] Fix missing end parenthesis. --- xbas99.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/xbas99.py b/xbas99.py index 980fcb5..55e1070 100755 --- a/xbas99.py +++ b/xbas99.py @@ -419,7 +419,7 @@ def getImage(self, long_=False, protected=False): chrw(checksum) + chrw(lastAddr - 1)) chunks = [(linoTable + tokenTable)[i:i + 254] for i in xrange(0, len(linoTable + tokenTable), 254)] - return (chr(len(header)) + header + (chr(0x00)*(256-len(header)) + + return (chr(len(header)) + header + (chr(0x00)*(256-len(header))) + "".join([chr(len(c)) + c + chr(0xff) for c in chunks])) else: header = (chrw(checksum) + chrw(tokenTabAddr - 1) + From fc099322fd97a3f6ce3c590d03ccf77480b0f53c Mon Sep 17 00:00:00 2001 From: Christopher KOBAYASHI Date: Thu, 7 Apr 2016 13:55:01 +0900 Subject: [PATCH 15/19] Refactor my long-format code into the original code; turns out the issue was an off-by-one error (and not accounting for TIFILES padding) --- xbas99.py | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/xbas99.py b/xbas99.py index 55e1070..56cf13b 100755 --- a/xbas99.py +++ b/xbas99.py @@ -191,19 +191,18 @@ def warn(self, text): # program -> source def load(self, data, long_, tifiles_): - if long_ and tifiles_: - newdata = data[0:11] - for i in range(1, (len(data) / 256)): - newdata += data[(i*256):(i*256)+255] - data = newdata """load tokenized BASIC program""" if long_ or data[1:3] == "\xab\xcd": # convert long format INT/VAR 254 to PROGRAM - program, p = "", 11 + if tifiles_: + p = 128 + else: + p = 11 + program = "" while p < len(data): l = ord(data[p]) + 1 program += data[p + 1:p + l] - p += l + p += l + 1 data = "XX" + data[5:7] + data[3:5] + "XX" + program # extract line number table and token table ptrTokens = ordw(data[2:4]) + 1 From a97b491d07b5c91075504d4cd6a5876fa638ef40 Mon Sep 17 00:00:00 2001 From: Christopher KOBAYASHI Date: Thu, 7 Apr 2016 14:12:08 +0900 Subject: [PATCH 16/19] Autodetect TIFILES. --- xbas99.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/xbas99.py b/xbas99.py index 56cf13b..7f048a6 100755 --- a/xbas99.py +++ b/xbas99.py @@ -516,6 +516,8 @@ def main(): else: with open(opts.source, "rb") as fin: image = fin.read() + if image[1:8] == "TIFILES": + opts.astifiles = True if opts.astifiles: image = image[128:] tifiles = True From 405ed70ce347cd2d71d50e625a20cb9b669572bd Mon Sep 17 00:00:00 2001 From: Christopher KOBAYASHI Date: Wed, 13 Apr 2016 14:30:58 +0900 Subject: [PATCH 17/19] Perform identification/sanity checks on programs set as TIFILES, and check to see if we have an invalid token instead of trying to dereference a null. --- xbas99.py | 34 ++++++++++++++++++++++++++++++---- 1 file changed, 30 insertions(+), 4 deletions(-) diff --git a/xbas99.py b/xbas99.py index 7f048a6..6566904 100755 --- a/xbas99.py +++ b/xbas99.py @@ -179,7 +179,7 @@ def __init__(self, data=None, source=None, long_=False, tifiles_=False): self.load(data, long_, tifiles_) except IndexError: self.warn("Program file is corrupted") - print traceback.format_exc() +# print traceback.format_exc() elif source: self.parse(source) @@ -204,6 +204,9 @@ def load(self, data, long_, tifiles_): program += data[p + 1:p + l] p += l + 1 data = "XX" + data[5:7] + data[3:5] + "XX" + program +# f = open("data", "wb") +# f.write(data) +# f.close() # extract line number table and token table ptrTokens = ordw(data[2:4]) + 1 ptrLineNumbers = ordw(data[4:6]) @@ -263,6 +266,9 @@ def getSource(self): softspace = True else: lit, typ, n = Tokens.literal(tokens[p:]) + if not lit: + sys.stderr.write("Illegal token\n") + sys.exit(1) istext = (lit[0] in "ABCDEFGHIJKLMNOPQRSTUVWXYZ" + Tokens.STMTSEP) and typ is None if (((istext or lit == "#" or @@ -418,7 +424,7 @@ def getImage(self, long_=False, protected=False): chrw(checksum) + chrw(lastAddr - 1)) chunks = [(linoTable + tokenTable)[i:i + 254] for i in xrange(0, len(linoTable + tokenTable), 254)] - return (chr(len(header)) + header + (chr(0x00)*(256-len(header))) + + return (chr(len(header)) + header + (chr(0x00)*(255-len(header))) + "".join([chr(len(c)) + c + chr(0xff) for c in chunks])) else: header = (chrw(checksum) + chrw(tokenTabAddr - 1) + @@ -519,8 +525,14 @@ def main(): if image[1:8] == "TIFILES": opts.astifiles = True if opts.astifiles: - image = image[128:] - tifiles = True + flags = ord(image[0x0a]) + reclen = ord(image[0x0d]) + if (flags & 0x01) or ( (flags & 0x82) and reclen == 0xfe): + image = image[128:] + tifiles = True + else: + print "File is not in TIFILES PROGRAM or IV254 format." + sys.exit(1) if image[1:3] == "\xab\xcd": opts.long_ = True if opts.merge: @@ -551,6 +563,20 @@ def main(): raise BasicError("Invalid line delta for join") program = BasicProgram(source=lines) data = program.getImage(long_=opts.long_, protected=opts.protect) + if opts.astifiles: + tifiles_header = chr(0x07) + "TIFILES" + chr(0x00) + print hex(len(data)), len(data), (len(data) // 256) + data += chr(0x00)*( (((len(data) // 256) + 1) * 256) - len(data)) + tifiles_header += chr( (len(data) / 256) + 1) + if opts.long_: + tifiles_header += chr(0x82) + chr(0x01) + tifiles_header += chr(0xba) # wrong, placeholder + else: + tifiles_header += chr(0x01) + chr(0x00) + tifiles_header += chr(0xba) # wrong, placeholder + tifiles_header += chr(0x00)*(128-len(tifiles_header)) + + data = tifiles_header + data output = opts.output or barename + ".prg" if program and program.warnings: From 8decd3a55a08644e5d1c3b08ca25ef72cb622002 Mon Sep 17 00:00:00 2001 From: Christopher KOBAYASHI Date: Sun, 17 Apr 2016 15:45:02 +0900 Subject: [PATCH 18/19] First attempt at supporting 2S2D80T. Myarc changed the sector allocation map semantics so that each bit represents two contiguous sectors, with the result that a file is always a multiple of two sectors long. This is not complete; the "comparing allocated sectors to file lengths" comparison is broken for 2880-sector images, but this code commit is functional. --- xdm99.py | 25 ++++++++++++++++++------- 1 file changed, 18 insertions(+), 7 deletions(-) diff --git a/xdm99.py b/xdm99.py index 8726ae5..2d47132 100755 --- a/xdm99.py +++ b/xdm99.py @@ -99,8 +99,9 @@ class Disk: bytesPerSector = 256 defaultSectorsPerTrack = 9 defaultTracks = 40 - maxSectors = 1600 + maxSectors = 2880 blankByte = "\xe5" + clusterSize = 1 def __init__(self, image): if len(image) < 2 * Disk.bytesPerSector: @@ -125,10 +126,13 @@ def __init__(self, image): if len(self.image) < self.totalSectors * Disk.bytesPerSector: self.warn("Disk image truncated", "image") self.checkGeometry() + if self.totalSectors == 2880: + Disk.clusterSize = 2 self.usedSectors = 0 try: - for i in xrange(used(self.totalSectors, 8)): - self.usedSectors += bin(ord(self.allocBitmap[i])).count("1") + for i in xrange(used(self.totalSectors / self.clusterSize, 8)): + self.usedSectors += bin(ord(self.allocBitmap[i])).count("1") * self.clusterSize + except IndexError: self.warn("Allocation map corrupted", "alloc") self.catalog = {} @@ -187,7 +191,13 @@ def readFile(self, name, sectors, clusters): self.warn("%s: File contents corrupted" % name) error = True continue - if len(data) != sectors * Disk.bytesPerSector: + if Disk.clusterSize is 2 and ((Disk.bytesPerSector * sectors) % 512): + # pad to multiple of 2 sectors for DSDD80T + expectedLength = Disk.bytesPerSector * (sectors+1) + else: + expectedLength = Disk.bytesPerSector * sectors + + if len(data) != expectedLength: self.warn("%s: File size mismatch: found %d bytes, expected %d" % ( name, len(data), sectors * Disk.bytesPerSector)) error = True @@ -321,10 +331,11 @@ def checkAllocation(self): """check sector allocation for consistency""" reads = {n: [] for n in xrange(self.totalSectors)} allocated = [] - for i in xrange(used(self.totalSectors, 8)): + for i in xrange(used(self.totalSectors / self.clusterSize, 8)): byte = ord(self.allocBitmap[i]) - for j in xrange(8): - allocated.append(byte & 1 << j != 0) + for j in xrange(8): + for k in xrange(self.clusterSize): + allocated.append(byte & 1 << j != 0) # unallocated sectors for n, context in self.readSectors: reads[n].append(context) From bbb1de540ee056356868f368d67cc40e25bac48c Mon Sep 17 00:00:00 2001 From: Christopher Kobayashi Date: Tue, 19 Apr 2016 11:21:05 +0900 Subject: [PATCH 19/19] Fix sector allocation check for DSDD80T. DSDD80T works now. --- xdm99.py | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/xdm99.py b/xdm99.py index 2d47132..fc939d2 100755 --- a/xdm99.py +++ b/xdm99.py @@ -167,7 +167,11 @@ def initCatalog(self): if error: fd.error = True self.catalog[fd.name] = File(fd=fd, data=data) - scount += fd.totalSectors + 1 + # Myarc DSDD80T always uses multiple of 512 bytes, including dir + # entries + if ((fd.totalSectors % 2) != 0) and Disk.clusterSize == 2: + fd.totalSectors += 1 + scount += fd.totalSectors + Disk.clusterSize # consistency check if scount != self.usedSectors - 2: self.warn( @@ -196,7 +200,7 @@ def readFile(self, name, sectors, clusters): expectedLength = Disk.bytesPerSector * (sectors+1) else: expectedLength = Disk.bytesPerSector * sectors - + if len(data) != expectedLength: self.warn("%s: File size mismatch: found %d bytes, expected %d" % ( name, len(data), sectors * Disk.bytesPerSector))