Support write on dsk files
This commit is contained in:
parent
9935510445
commit
8cfd448f95
|
@ -2,7 +2,6 @@ package apple2
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"errors"
|
"errors"
|
||||||
"strings"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
type diskette interface {
|
type diskette interface {
|
||||||
|
@ -25,9 +24,8 @@ func loadDiskette(filename string) (diskette, error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
if isFileDsk(data) {
|
if isFileDsk(data) {
|
||||||
isPO := strings.HasSuffix(strings.ToLower(filename), "po")
|
var d diskette16sectorWritable
|
||||||
var d diskette16sector
|
d.nib = newFileDsk(data, filename)
|
||||||
d.nib = newFileDsk(data, isPO)
|
|
||||||
return &d, nil
|
return &d, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,51 @@
|
||||||
|
package apple2
|
||||||
|
|
||||||
|
/*
|
||||||
|
See:
|
||||||
|
"Beneath Apple DOS" https://fabiensanglard.net/fd_proxy/prince_of_persia/Beneath%20Apple%20DOS.pdf
|
||||||
|
https://github.com/TomHarte/CLK/wiki/Apple-GCR-disk-encoding
|
||||||
|
*/
|
||||||
|
|
||||||
|
type diskette16sectorWritable struct {
|
||||||
|
nib *fileNib
|
||||||
|
position int
|
||||||
|
|
||||||
|
// Needed to write back
|
||||||
|
hasDirtyTrack bool
|
||||||
|
dirtyTrack int
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *diskette16sectorWritable) powerOn(cycle uint64) {
|
||||||
|
// Not used
|
||||||
|
}
|
||||||
|
func (d *diskette16sectorWritable) powerOff(_ uint64) {
|
||||||
|
d.commit()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *diskette16sectorWritable) read(quarterTrack int, cycle uint64) uint8 {
|
||||||
|
track := d.nib.track[quarterTrack/stepsPerTrack]
|
||||||
|
value := track[d.position]
|
||||||
|
d.position = (d.position + 1) % nibBytesPerTrack
|
||||||
|
return value
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *diskette16sectorWritable) write(quarterTrack int, value uint8, _ uint64) {
|
||||||
|
track := quarterTrack / stepsPerTrack
|
||||||
|
|
||||||
|
if d.hasDirtyTrack && track != d.dirtyTrack {
|
||||||
|
d.commit()
|
||||||
|
}
|
||||||
|
|
||||||
|
d.nib.track[track][d.position] = value
|
||||||
|
d.position = (d.position + 1) % nibBytesPerTrack
|
||||||
|
|
||||||
|
d.hasDirtyTrack = true
|
||||||
|
d.dirtyTrack = track
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *diskette16sectorWritable) commit() {
|
||||||
|
if d.hasDirtyTrack {
|
||||||
|
d.nib.saveTrack(d.dirtyTrack)
|
||||||
|
d.hasDirtyTrack = false
|
||||||
|
}
|
||||||
|
}
|
49
fileNib.go
49
fileNib.go
|
@ -4,6 +4,7 @@ import (
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"os"
|
"os"
|
||||||
|
"strings"
|
||||||
)
|
)
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -26,6 +27,11 @@ const (
|
||||||
|
|
||||||
type fileNib struct {
|
type fileNib struct {
|
||||||
track [numberOfTracks][]byte
|
track [numberOfTracks][]byte
|
||||||
|
|
||||||
|
// Needed to write back
|
||||||
|
supportsWrite bool
|
||||||
|
filename string
|
||||||
|
logicalOrder *[16]int
|
||||||
}
|
}
|
||||||
|
|
||||||
func isFileNib(data []uint8) bool {
|
func isFileNib(data []uint8) bool {
|
||||||
|
@ -46,22 +52,50 @@ func isFileDsk(data []uint8) bool {
|
||||||
return len(data) == dskImageSize
|
return len(data) == dskImageSize
|
||||||
}
|
}
|
||||||
|
|
||||||
func newFileDsk(data []uint8, isPO bool) *fileNib {
|
func newFileDsk(data []uint8, filename string) *fileNib {
|
||||||
var f fileNib
|
var f fileNib
|
||||||
|
|
||||||
logicalOrder := dos33SectorsLogicalOrder
|
isPO := strings.HasSuffix(strings.ToLower(filename), "po")
|
||||||
|
f.logicalOrder = &dos33SectorsLogicalOrder
|
||||||
if isPO {
|
if isPO {
|
||||||
logicalOrder = prodosSectorsLogicalOrder
|
f.logicalOrder = &prodosSectorsLogicalOrder
|
||||||
}
|
}
|
||||||
|
|
||||||
|
f.filename = filename
|
||||||
|
f.supportsWrite = true
|
||||||
|
|
||||||
for i := 0; i < numberOfTracks; i++ {
|
for i := 0; i < numberOfTracks; i++ {
|
||||||
trackData := data[i*bytesPerTrack : (i+1)*bytesPerTrack]
|
trackData := data[i*bytesPerTrack : (i+1)*bytesPerTrack]
|
||||||
f.track[i] = nibEncodeTrack(trackData, defaultVolumeTag, byte(i), &logicalOrder)
|
f.track[i] = nibEncodeTrack(trackData, defaultVolumeTag, byte(i), f.logicalOrder)
|
||||||
}
|
}
|
||||||
|
|
||||||
return &f
|
return &f
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (f *fileNib) saveTrack(track int) {
|
||||||
|
if f.supportsWrite {
|
||||||
|
file, err := os.OpenFile(f.filename, os.O_RDWR, 0)
|
||||||
|
if err != nil {
|
||||||
|
// We can't open the file for writing"
|
||||||
|
f.supportsWrite = false
|
||||||
|
fmt.Printf("Data can't be written for %v\n", f.filename)
|
||||||
|
}
|
||||||
|
|
||||||
|
data, err := nibDecodeTrack(f.track[track], f.logicalOrder)
|
||||||
|
if err != nil {
|
||||||
|
f.supportsWrite = false
|
||||||
|
fmt.Printf("Data written can't be decoded from nibbles\n")
|
||||||
|
}
|
||||||
|
|
||||||
|
offset := int64(track * bytesPerTrack)
|
||||||
|
_, err = file.WriteAt(data, offset)
|
||||||
|
if err != nil {
|
||||||
|
f.supportsWrite = false
|
||||||
|
fmt.Printf("Data can't be written\n")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func (f *fileNib) saveNib(filename string) error {
|
func (f *fileNib) saveNib(filename string) error {
|
||||||
file, err := os.Create(filename)
|
file, err := os.Create(filename)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -235,7 +269,7 @@ func findProlog(diskPrologByte3 uint8, data []byte, position int) int {
|
||||||
return -1
|
return -1
|
||||||
}
|
}
|
||||||
|
|
||||||
func nibDecodeTrack(data []byte, track byte, logicalOrder *[16]int) ([]byte, error) {
|
func nibDecodeTrack(data []byte, logicalOrder *[16]int) ([]byte, error) {
|
||||||
b := make([]byte, bytesPerTrack) // Buffer slice with enough capacity
|
b := make([]byte, bytesPerTrack) // Buffer slice with enough capacity
|
||||||
|
|
||||||
i := int(0)
|
i := int(0)
|
||||||
|
@ -247,15 +281,14 @@ func nibDecodeTrack(data []byte, track byte, logicalOrder *[16]int) ([]byte, err
|
||||||
if i == -1 {
|
if i == -1 {
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
|
|
||||||
// We just want the sector from the address field, we ignore the rest, no error detection
|
// We just want the sector from the address field, we ignore the rest, no error detection
|
||||||
sector := oddEvenDecodeByte(data[(i+4)%l], data[(i+5)%l])
|
sector := oddEvenDecodeByte(data[(i+4)%l], data[(i+5)%l])
|
||||||
logicalSector := logicalOrder[sector]
|
logicalSector := logicalOrder[sector]
|
||||||
dst := int(logicalSector) * bytesPerSector
|
dst := int(logicalSector) * bytesPerSector
|
||||||
fmt.Printf("Processing sector %v (%v), destination: %v\n", sector, logicalSector, dst)
|
|
||||||
|
|
||||||
i = (i + 8 + 3) % l // We skip the four two byte fields and the epilog
|
|
||||||
|
|
||||||
// Find data prolog
|
// Find data prolog
|
||||||
|
i = (i + 8 + 3) % l // We skip the four two byte fields and the epilog
|
||||||
i = findProlog(diskPrologByte3Data, data, i)
|
i = findProlog(diskPrologByte3Data, data, i)
|
||||||
|
|
||||||
// Read secondary buffer
|
// Read secondary buffer
|
||||||
|
|
Loading…
Reference in New Issue