diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..ed097e1 --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +__pycache__/dsk2po.cpython-311.pyc diff --git a/35track.dsk b/35track.dsk new file mode 100644 index 0000000..2b87e0d Binary files /dev/null and b/35track.dsk differ diff --git a/35track.po b/35track.po new file mode 100644 index 0000000..deffc25 Binary files /dev/null and b/35track.po differ diff --git a/40track.dsk b/40track.dsk new file mode 100644 index 0000000..f02c548 Binary files /dev/null and b/40track.dsk differ diff --git a/40track.po b/40track.po new file mode 100644 index 0000000..986be50 Binary files /dev/null and b/40track.po differ diff --git a/README.md b/README.md index 90541f3..b898e17 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,6 @@ -# dsk2po -Python script to convert Apple II/III .DSK (DO) images to ProDOS-ordered images +# dsk2po and po2dsk +Python scripts to convert Apple II/III .DSK (DO) images to ProDOS-ordered images +and vice versa. This is nothing very exciting, it just maps sectors in .dsk (DOS-order, .do) files into those of a .po (ProDOS-order) file. Most Apple II emulators can handle both, @@ -11,7 +12,10 @@ Usage is just (assuming you've done `chmod 755 dsk2po.py`, else precede with pyt ./dsk2po.py image.dsk This will create image.dsk.po alongside it. Pretty much no checking is done. -It just goes through 35 tracks and converts them, then ends. +It just goes through all the tracks and converts them, then ends. + +Both scripts will handle an arbitrary number of tracks, but will print a +warning if the number of tracks is not 35. This can be used as an action for find, like so: diff --git a/dsk2po.py b/dsk2po.py index 3c638b8..546d620 100755 --- a/dsk2po.py +++ b/dsk2po.py @@ -1,33 +1,39 @@ #!/usr/bin/env python3 # unscramble dsk into po # Paul Hagstrom, Dec 2015 -import sys, getopt, re +import sys, getopt, re, os def main(argv=None): - print("dsk2po - convert dsk files to po files") + print("dsk2po - convert dsk files to po files") - try: - opts, args = getopt.getopt(sys.argv[1:], '') - except getopt.GetoptError as err: - print(str(err)) - usage() - return 1 - try: - dskfilename = args[0] - except: - print('You need to provide the name of a DSK file to begin.') - return 1 + try: + opts, args = getopt.getopt(sys.argv[1:], '') + except getopt.GetoptError as err: + print(str(err)) + usage() + return 1 + try: + dskfilename = args[0] + except: + print('You need to provide the name of a DSK file to begin.') + return 1 - potracks = [] - with open(dskfilename, mode="rb") as dskfile: - for track in range(35): - trackbuffer = dskfile.read(4096) - potracks.append(dsk2po(trackbuffer)) - pofilename = re.sub('\.dsk$', '', dskfilename, flags=re.IGNORECASE) + ".po" - print('Writing po image to {}'.format(pofilename)) - with open(pofilename, mode="wb") as pofile: - for potrack in potracks: - pofile.write(potrack) - return 0 + # Handle arbitrary number of tracks (normally should be 35) + fileSize = os.path.getsize(dskfilename) + ntracks = fileSize // 4096 + if ntracks != 35: + print("Warning: DSK file has non-standard {} tracks".format(ntracks)) + + potracks = [] + with open(dskfilename, mode="rb") as dskfile: + for track in range(ntracks): + trackbuffer = dskfile.read(4096) + potracks.append(dsk2po(trackbuffer)) + pofilename = re.sub('\.dsk$', '', dskfilename, flags=re.IGNORECASE) + ".po" + print('Writing po image to {}'.format(pofilename)) + with open(pofilename, mode="wb") as pofile: + for potrack in potracks: + pofile.write(potrack) + return 0 # From Beneath Apple ProDOS, table 3.1 # block 000 physical 0, 2 DOS 0, E page 0, 1 @@ -45,12 +51,12 @@ def main(argv=None): block_map = [0, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 15] def dsk2po(trackbuffer): - potrack = bytearray() - for chunk in range(16): - chunk_start = 256*block_map[chunk] - chunk_end = chunk_start + 256 - potrack.extend(trackbuffer[chunk_start:chunk_end]) - return potrack + potrack = bytearray() + for chunk in range(16): + chunk_start = 256*block_map[chunk] + chunk_end = chunk_start + 256 + potrack.extend(trackbuffer[chunk_start:chunk_end]) + return potrack if __name__ == "__main__": - sys.exit(main()) + sys.exit(main()) diff --git a/po2dsk.py b/po2dsk.py index fe49b59..8f6060f 100755 --- a/po2dsk.py +++ b/po2dsk.py @@ -1,7 +1,7 @@ #!/usr/bin/env python3 # scramble po back into dsk # Chris Torrence, Oct 2020 -import sys, getopt, re +import sys, getopt, re, os from dsk2po import dsk2po def main(argv=None): print("po2dsk - convert po files to dsk files") @@ -18,10 +18,17 @@ def main(argv=None): print('You need to provide the name of a PO file to begin.') return 1 + # Handle arbitrary number of tracks (normally should be 35) + fileSize = os.path.getsize(filenameIn) + ntracks = fileSize // 4096 + if ntracks != 35: + print("Warning: PO file has non-standard {} tracks".format(ntracks)) + tracks = [] + # Note that the same algorithm can be used to convert in either direction with open(filenameIn, mode="rb") as fileIn: - for track in range(35): + for track in range(ntracks): trackbuffer = fileIn.read(4096) tracks.append(dsk2po(trackbuffer)) dskfilename = re.sub('\.po$', '', filenameIn, flags=re.IGNORECASE) + ".dsk"