Add support for disks with arbitrary number of tracks; add sample disk images

This commit is contained in:
Chris Torrence 2024-02-21 09:13:55 -07:00
parent 2f199f601c
commit 6cd06758c2
8 changed files with 54 additions and 36 deletions

1
.gitignore vendored Normal file
View File

@ -0,0 +1 @@
__pycache__/dsk2po.cpython-311.pyc

BIN
35track.dsk Normal file

Binary file not shown.

BIN
35track.po Normal file

Binary file not shown.

BIN
40track.dsk Normal file

Binary file not shown.

BIN
40track.po Normal file

Binary file not shown.

View File

@ -1,5 +1,6 @@
# dsk2po # dsk2po and po2dsk
Python script to convert Apple II/III .DSK (DO) images to ProDOS-ordered images 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 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, 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 ./dsk2po.py image.dsk
This will create image.dsk.po alongside it. Pretty much no checking is done. 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: This can be used as an action for find, like so:

View File

@ -1,33 +1,39 @@
#!/usr/bin/env python3 #!/usr/bin/env python3
# unscramble dsk into po # unscramble dsk into po
# Paul Hagstrom, Dec 2015 # Paul Hagstrom, Dec 2015
import sys, getopt, re import sys, getopt, re, os
def main(argv=None): def main(argv=None):
print("dsk2po - convert dsk files to po files") print("dsk2po - convert dsk files to po files")
try: try:
opts, args = getopt.getopt(sys.argv[1:], '') opts, args = getopt.getopt(sys.argv[1:], '')
except getopt.GetoptError as err: except getopt.GetoptError as err:
print(str(err)) print(str(err))
usage() usage()
return 1 return 1
try: try:
dskfilename = args[0] dskfilename = args[0]
except: except:
print('You need to provide the name of a DSK file to begin.') print('You need to provide the name of a DSK file to begin.')
return 1 return 1
potracks = [] # Handle arbitrary number of tracks (normally should be 35)
with open(dskfilename, mode="rb") as dskfile: fileSize = os.path.getsize(dskfilename)
for track in range(35): ntracks = fileSize // 4096
trackbuffer = dskfile.read(4096) if ntracks != 35:
potracks.append(dsk2po(trackbuffer)) print("Warning: DSK file has non-standard {} tracks".format(ntracks))
pofilename = re.sub('\.dsk$', '', dskfilename, flags=re.IGNORECASE) + ".po"
print('Writing po image to {}'.format(pofilename)) potracks = []
with open(pofilename, mode="wb") as pofile: with open(dskfilename, mode="rb") as dskfile:
for potrack in potracks: for track in range(ntracks):
pofile.write(potrack) trackbuffer = dskfile.read(4096)
return 0 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 # From Beneath Apple ProDOS, table 3.1
# block 000 physical 0, 2 DOS 0, E page 0, 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] block_map = [0, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 15]
def dsk2po(trackbuffer): def dsk2po(trackbuffer):
potrack = bytearray() potrack = bytearray()
for chunk in range(16): for chunk in range(16):
chunk_start = 256*block_map[chunk] chunk_start = 256*block_map[chunk]
chunk_end = chunk_start + 256 chunk_end = chunk_start + 256
potrack.extend(trackbuffer[chunk_start:chunk_end]) potrack.extend(trackbuffer[chunk_start:chunk_end])
return potrack return potrack
if __name__ == "__main__": if __name__ == "__main__":
sys.exit(main()) sys.exit(main())

View File

@ -1,7 +1,7 @@
#!/usr/bin/env python3 #!/usr/bin/env python3
# scramble po back into dsk # scramble po back into dsk
# Chris Torrence, Oct 2020 # Chris Torrence, Oct 2020
import sys, getopt, re import sys, getopt, re, os
from dsk2po import dsk2po from dsk2po import dsk2po
def main(argv=None): def main(argv=None):
print("po2dsk - convert po files to dsk files") 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.') print('You need to provide the name of a PO file to begin.')
return 1 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 = [] tracks = []
# Note that the same algorithm can be used to convert in either direction # Note that the same algorithm can be used to convert in either direction
with open(filenameIn, mode="rb") as fileIn: with open(filenameIn, mode="rb") as fileIn:
for track in range(35): for track in range(ntracks):
trackbuffer = fileIn.read(4096) trackbuffer = fileIn.read(4096)
tracks.append(dsk2po(trackbuffer)) tracks.append(dsk2po(trackbuffer))
dskfilename = re.sub('\.po$', '', filenameIn, flags=re.IGNORECASE) + ".dsk" dskfilename = re.sub('\.po$', '', filenameIn, flags=re.IGNORECASE) + ".dsk"