mirror of
https://github.com/tjboldt/ProDOS-Utilities.git
synced 2024-06-01 05:41:32 +00:00
Change ints to specific uints
This commit is contained in:
parent
0aa838ffe1
commit
bf94ac8822
32
main.go
32
main.go
|
@ -25,21 +25,21 @@ func main() {
|
||||||
var command string
|
var command string
|
||||||
var outFileName string
|
var outFileName string
|
||||||
var inFileName string
|
var inFileName string
|
||||||
var blockNumber int
|
var blockNumber uint
|
||||||
var volumeSize int
|
var volumeSize uint
|
||||||
var volumeName string
|
var volumeName string
|
||||||
var fileType int
|
var fileType uint
|
||||||
var auxType int
|
var auxType uint
|
||||||
flag.StringVar(&fileName, "d", "", "A ProDOS format drive image")
|
flag.StringVar(&fileName, "d", "", "A ProDOS format drive image")
|
||||||
flag.StringVar(&pathName, "p", "", "Path name in ProDOS drive image (default is root of volume)")
|
flag.StringVar(&pathName, "p", "", "Path name in ProDOS drive image (default is root of volume)")
|
||||||
flag.StringVar(&command, "c", "ls", "Command to execute: ls, get, put, rm, mkdir, readblock, writeblock, create, putall, putallrecursive")
|
flag.StringVar(&command, "c", "ls", "Command to execute: ls, get, put, rm, mkdir, readblock, writeblock, create, putall, putallrecursive")
|
||||||
flag.StringVar(&outFileName, "o", "", "Name of file to write")
|
flag.StringVar(&outFileName, "o", "", "Name of file to write")
|
||||||
flag.StringVar(&inFileName, "i", "", "Name of file to read")
|
flag.StringVar(&inFileName, "i", "", "Name of file to read")
|
||||||
flag.IntVar(&volumeSize, "s", 65535, "Number of blocks to create the volume with (default 65535, 64 to 65535, 0x0040 to 0xFFFF hex input accepted)")
|
flag.UintVar(&volumeSize, "s", 65535, "Number of blocks to create the volume with (default 65535, 64 to 65535, 0x0040 to 0xFFFF hex input accepted)")
|
||||||
flag.StringVar(&volumeName, "v", "NO.NAME", "Specifiy a name for the volume from 1 to 15 characters")
|
flag.StringVar(&volumeName, "v", "NO.NAME", "Specifiy a name for the volume from 1 to 15 characters")
|
||||||
flag.IntVar(&blockNumber, "b", 0, "A block number to read/write from 0 to 65535 (0x0000 to 0xFFFF hex input accepted)")
|
flag.UintVar(&blockNumber, "b", 0, "A block number to read/write from 0 to 65535 (0x0000 to 0xFFFF hex input accepted)")
|
||||||
flag.IntVar(&fileType, "t", 0, "ProDOS FileType: 0x04 for TXT, 0x06 for BIN, 0xFC for BAS, 0xFF for SYS etc., omit to autodetect")
|
flag.UintVar(&fileType, "t", 0, "ProDOS FileType: 0x04 for TXT, 0x06 for BIN, 0xFC for BAS, 0xFF for SYS etc., omit to autodetect")
|
||||||
flag.IntVar(&auxType, "a", 0, "ProDOS AuxType from 0 to 65535 (0x0000 to 0xFFFF hex input accepted), omit to autodetect")
|
flag.UintVar(&auxType, "a", 0, "ProDOS AuxType from 0 to 65535 (0x0000 to 0xFFFF hex input accepted), omit to autodetect")
|
||||||
flag.Parse()
|
flag.Parse()
|
||||||
|
|
||||||
if len(fileName) == 0 {
|
if len(fileName) == 0 {
|
||||||
|
@ -54,13 +54,13 @@ func main() {
|
||||||
case "get":
|
case "get":
|
||||||
get(fileName, pathName, outFileName)
|
get(fileName, pathName, outFileName)
|
||||||
case "put":
|
case "put":
|
||||||
put(fileName, pathName, fileType, auxType, inFileName)
|
put(fileName, pathName, uint8(fileType), uint16(auxType), inFileName)
|
||||||
case "readblock":
|
case "readblock":
|
||||||
readBlock(blockNumber, fileName)
|
readBlock(uint16(blockNumber), fileName)
|
||||||
case "writeblock":
|
case "writeblock":
|
||||||
writeBlock(blockNumber, fileName, inFileName)
|
writeBlock(uint16(blockNumber), fileName, inFileName)
|
||||||
case "create":
|
case "create":
|
||||||
create(fileName, volumeName, volumeSize)
|
create(fileName, volumeName, uint16(volumeSize))
|
||||||
case "putall":
|
case "putall":
|
||||||
putall(fileName, inFileName, pathName, false)
|
putall(fileName, inFileName, pathName, false)
|
||||||
case "putallrecursive":
|
case "putallrecursive":
|
||||||
|
@ -147,7 +147,7 @@ func putall(fileName string, inFileName string, pathName string, recursive bool)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func create(fileName string, volumeName string, volumeSize int) {
|
func create(fileName string, volumeName string, volumeSize uint16) {
|
||||||
file, err := os.Create(fileName)
|
file, err := os.Create(fileName)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Printf("failed to create file: %s\n", err)
|
fmt.Printf("failed to create file: %s\n", err)
|
||||||
|
@ -157,7 +157,7 @@ func create(fileName string, volumeName string, volumeSize int) {
|
||||||
prodos.CreateVolume(file, volumeName, volumeSize)
|
prodos.CreateVolume(file, volumeName, volumeSize)
|
||||||
}
|
}
|
||||||
|
|
||||||
func writeBlock(blockNumber int, fileName string, inFileName string) {
|
func writeBlock(blockNumber uint16, fileName string, inFileName string) {
|
||||||
checkInFileName(inFileName)
|
checkInFileName(inFileName)
|
||||||
fmt.Printf("Writing block 0x%04X (%d):\n\n", blockNumber, blockNumber)
|
fmt.Printf("Writing block 0x%04X (%d):\n\n", blockNumber, blockNumber)
|
||||||
file, err := os.OpenFile(fileName, os.O_RDWR, 0755)
|
file, err := os.OpenFile(fileName, os.O_RDWR, 0755)
|
||||||
|
@ -174,7 +174,7 @@ func writeBlock(blockNumber int, fileName string, inFileName string) {
|
||||||
prodos.WriteBlock(file, blockNumber, inFile)
|
prodos.WriteBlock(file, blockNumber, inFile)
|
||||||
}
|
}
|
||||||
|
|
||||||
func readBlock(blockNumber int, fileName string) {
|
func readBlock(blockNumber uint16, fileName string) {
|
||||||
fmt.Printf("Reading block 0x%04X (%d):\n\n", blockNumber, blockNumber)
|
fmt.Printf("Reading block 0x%04X (%d):\n\n", blockNumber, blockNumber)
|
||||||
file, err := os.OpenFile(fileName, os.O_RDONLY, 0755)
|
file, err := os.OpenFile(fileName, os.O_RDONLY, 0755)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -190,7 +190,7 @@ func readBlock(blockNumber int, fileName string) {
|
||||||
prodos.DumpBlock(block)
|
prodos.DumpBlock(block)
|
||||||
}
|
}
|
||||||
|
|
||||||
func put(fileName string, pathName string, fileType int, auxType int, inFileName string) {
|
func put(fileName string, pathName string, fileType uint8, auxType uint16, inFileName string) {
|
||||||
checkPathName(pathName)
|
checkPathName(pathName)
|
||||||
checkInFileName(inFileName)
|
checkInFileName(inFileName)
|
||||||
file, err := os.OpenFile(fileName, os.O_RDWR, 0755)
|
file, err := os.OpenFile(fileName, os.O_RDWR, 0755)
|
||||||
|
|
112
prodos/bitmap.go
112
prodos/bitmap.go
|
@ -33,13 +33,13 @@ func ReadVolumeBitmap(reader io.ReaderAt) ([]byte, error) {
|
||||||
totalBitmapBlocks++
|
totalBitmapBlocks++
|
||||||
}
|
}
|
||||||
|
|
||||||
for i := 0; i < totalBitmapBlocks; i++ {
|
for i := uint16(0); i < totalBitmapBlocks; i++ {
|
||||||
bitmapBlock, err := ReadBlock(reader, i+volumeHeader.BitmapStartBlock)
|
bitmapBlock, err := ReadBlock(reader, i+volumeHeader.BitmapStartBlock)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
for j := 0; j < 512 && i*512+j < totalBitmapBytes; j++ {
|
for j := uint16(0); j < 512 && i*512+j < totalBitmapBytes; j++ {
|
||||||
bitmap[i*512+j] = bitmapBlock[j]
|
bitmap[i*512+j] = bitmapBlock[j]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -48,10 +48,10 @@ func ReadVolumeBitmap(reader io.ReaderAt) ([]byte, error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetFreeBlockCount gets the number of free blocks on a ProDOS image
|
// GetFreeBlockCount gets the number of free blocks on a ProDOS image
|
||||||
func GetFreeBlockCount(volumeBitmap []byte, totalBlocks int) int {
|
func GetFreeBlockCount(volumeBitmap []byte, totalBlocks uint16) uint16 {
|
||||||
freeBlockCount := 0
|
freeBlockCount := uint16(0)
|
||||||
|
|
||||||
for i := 0; i < totalBlocks; i++ {
|
for i := uint16(0); i < totalBlocks; i++ {
|
||||||
if checkFreeBlockInVolumeBitmap(volumeBitmap, i) {
|
if checkFreeBlockInVolumeBitmap(volumeBitmap, i) {
|
||||||
freeBlockCount++
|
freeBlockCount++
|
||||||
}
|
}
|
||||||
|
@ -77,13 +77,13 @@ func writeVolumeBitmap(readerWriter ReaderWriterAt, bitmap []byte) error {
|
||||||
totalBitmapBlocks++
|
totalBitmapBlocks++
|
||||||
}
|
}
|
||||||
|
|
||||||
for i := 0; i < totalBitmapBlocks; i++ {
|
for i := uint16(0); i < totalBitmapBlocks; i++ {
|
||||||
bitmapBlock, err := ReadBlock(readerWriter, i+volumeHeader.BitmapStartBlock)
|
bitmapBlock, err := ReadBlock(readerWriter, i+volumeHeader.BitmapStartBlock)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
for j := 0; j < 512 && i*512+j < totalBitmapBytes; j++ {
|
for j := uint16(0); j < 512 && i*512+j < totalBitmapBytes; j++ {
|
||||||
bitmapBlock[j] = bitmap[i*512+j]
|
bitmapBlock[j] = bitmap[i*512+j]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -96,9 +96,10 @@ func writeVolumeBitmap(readerWriter ReaderWriterAt, bitmap []byte) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func createVolumeBitmap(numberOfBlocks int) []byte {
|
func createVolumeBitmap(numberOfBlocks uint16) []byte {
|
||||||
volumeBitmapBlocks := numberOfBlocks / 512 / 8
|
// needs to be > uint16 because it's multiplying by a uint16
|
||||||
if volumeBitmapBlocks*8*512 < numberOfBlocks {
|
volumeBitmapBlocks := uint32(numberOfBlocks / 512 / 8)
|
||||||
|
if volumeBitmapBlocks*8*512 < uint32(numberOfBlocks) {
|
||||||
volumeBitmapBlocks++
|
volumeBitmapBlocks++
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -119,30 +120,31 @@ func createVolumeBitmap(numberOfBlocks int) []byte {
|
||||||
markBlockInVolumeBitmap(volumeBitmap, 5)
|
markBlockInVolumeBitmap(volumeBitmap, 5)
|
||||||
|
|
||||||
// volume bitmap blocks
|
// volume bitmap blocks
|
||||||
for i := 0; i < volumeBitmapBlocks; i++ {
|
for i := uint32(0); i < volumeBitmapBlocks; i++ {
|
||||||
markBlockInVolumeBitmap(volumeBitmap, 6+i)
|
markBlockInVolumeBitmap(volumeBitmap, uint16(6+i))
|
||||||
}
|
}
|
||||||
|
|
||||||
// blocks beyond the volume
|
// blocks beyond the volume
|
||||||
totalBlocksInBitmap := volumeBitmapBlocks * 512 * 8
|
totalBlocksInBitmap := volumeBitmapBlocks * 512 * 8
|
||||||
blocksBeyondEnd := totalBlocksInBitmap - numberOfBlocks
|
blocksBeyondEnd := totalBlocksInBitmap - uint32(numberOfBlocks)
|
||||||
if blocksBeyondEnd > 0 {
|
if blocksBeyondEnd > 0 {
|
||||||
for i := totalBlocksInBitmap - blocksBeyondEnd; i < totalBlocksInBitmap; i++ {
|
for i := totalBlocksInBitmap - blocksBeyondEnd; i < totalBlocksInBitmap; i++ {
|
||||||
markBlockInVolumeBitmap(volumeBitmap, i)
|
markBlockInVolumeBitmap(volumeBitmap, uint16(i))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return volumeBitmap
|
return volumeBitmap
|
||||||
}
|
}
|
||||||
|
|
||||||
func findFreeBlocks(volumeBitmap []byte, numberOfBlocks int) []int {
|
func findFreeBlocks(volumeBitmap []byte, numberOfBlocks uint16) []uint16 {
|
||||||
blocks := make([]int, numberOfBlocks)
|
blocks := make([]uint16, numberOfBlocks)
|
||||||
|
|
||||||
blocksFound := 0
|
blocksFound := uint16(0)
|
||||||
|
|
||||||
for i := 0; i < len(volumeBitmap)*8; i++ {
|
// needs to be > uint16 because it's multiplying by a uint16
|
||||||
if checkFreeBlockInVolumeBitmap(volumeBitmap, i) {
|
for i := uint32(0); i < uint32(len(volumeBitmap))*8; i++ {
|
||||||
blocks[blocksFound] = i
|
if checkFreeBlockInVolumeBitmap(volumeBitmap, uint16(i)) {
|
||||||
|
blocks[blocksFound] = uint16(i)
|
||||||
blocksFound++
|
blocksFound++
|
||||||
if blocksFound == numberOfBlocks {
|
if blocksFound == numberOfBlocks {
|
||||||
return blocks
|
return blocks
|
||||||
|
@ -153,87 +155,29 @@ func findFreeBlocks(volumeBitmap []byte, numberOfBlocks int) []int {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func markBlockInVolumeBitmap(volumeBitmap []byte, blockNumber int) {
|
func markBlockInVolumeBitmap(volumeBitmap []byte, blockNumber uint16) {
|
||||||
bitToChange := blockNumber % 8
|
bitToChange := blockNumber % 8
|
||||||
byteToChange := blockNumber / 8
|
byteToChange := blockNumber / 8
|
||||||
|
|
||||||
byteToAnd := 0b11111111
|
byteToAnd := (uint8(0b10000000) >> uint8(bitToChange)) ^ 0b11111111
|
||||||
|
|
||||||
switch bitToChange {
|
|
||||||
case 0:
|
|
||||||
byteToAnd = 0b01111111
|
|
||||||
case 1:
|
|
||||||
byteToAnd = 0b10111111
|
|
||||||
case 2:
|
|
||||||
byteToAnd = 0b11011111
|
|
||||||
case 3:
|
|
||||||
byteToAnd = 0b11101111
|
|
||||||
case 4:
|
|
||||||
byteToAnd = 0b11110111
|
|
||||||
case 5:
|
|
||||||
byteToAnd = 0b11111011
|
|
||||||
case 6:
|
|
||||||
byteToAnd = 0b11111101
|
|
||||||
case 7:
|
|
||||||
byteToAnd = 0b11111110
|
|
||||||
}
|
|
||||||
|
|
||||||
//fmt.Printf("blockNumber: $%04X byteToWrite: 0b%08b volumeBitmap: $%02X byteToChange: $%04X\n", blockNumber, byteToWrite, volumeBitmap[byteToChange], byteToChange)
|
|
||||||
volumeBitmap[byteToChange] &= byte(byteToAnd)
|
volumeBitmap[byteToChange] &= byte(byteToAnd)
|
||||||
}
|
}
|
||||||
|
|
||||||
func freeBlockInVolumeBitmap(volumeBitmap []byte, blockNumber int) {
|
func freeBlockInVolumeBitmap(volumeBitmap []byte, blockNumber uint16) {
|
||||||
bitToChange := blockNumber % 8
|
bitToChange := blockNumber % 8
|
||||||
byteToChange := blockNumber / 8
|
byteToChange := blockNumber / 8
|
||||||
|
|
||||||
byteToOr := 0b00000000
|
byteToOr := uint8(0b10000000) >> uint8(bitToChange)
|
||||||
|
|
||||||
switch bitToChange {
|
|
||||||
case 0:
|
|
||||||
byteToOr = 0b10000000
|
|
||||||
case 1:
|
|
||||||
byteToOr = 0b01000000
|
|
||||||
case 2:
|
|
||||||
byteToOr = 0b00100000
|
|
||||||
case 3:
|
|
||||||
byteToOr = 0b00010000
|
|
||||||
case 4:
|
|
||||||
byteToOr = 0b00001000
|
|
||||||
case 5:
|
|
||||||
byteToOr = 0b00000100
|
|
||||||
case 6:
|
|
||||||
byteToOr = 0b00000010
|
|
||||||
case 7:
|
|
||||||
byteToOr = 0b00000001
|
|
||||||
}
|
|
||||||
|
|
||||||
volumeBitmap[byteToChange] |= byte(byteToOr)
|
volumeBitmap[byteToChange] |= byte(byteToOr)
|
||||||
}
|
}
|
||||||
|
|
||||||
func checkFreeBlockInVolumeBitmap(volumeBitmap []byte, blockNumber int) bool {
|
func checkFreeBlockInVolumeBitmap(volumeBitmap []byte, blockNumber uint16) bool {
|
||||||
bitToCheck := blockNumber % 8
|
bitToCheck := blockNumber % 8
|
||||||
byteToCheck := blockNumber / 8
|
byteToCheck := blockNumber / 8
|
||||||
|
|
||||||
byteToAnd := 0b00000000
|
byteToAnd := uint8(0b10000000) >> uint8(bitToCheck)
|
||||||
|
|
||||||
switch bitToCheck {
|
|
||||||
case 0:
|
|
||||||
byteToAnd = 0b10000000
|
|
||||||
case 1:
|
|
||||||
byteToAnd = 0b01000000
|
|
||||||
case 2:
|
|
||||||
byteToAnd = 0b00100000
|
|
||||||
case 3:
|
|
||||||
byteToAnd = 0b00010000
|
|
||||||
case 4:
|
|
||||||
byteToAnd = 0b00001000
|
|
||||||
case 5:
|
|
||||||
byteToAnd = 0b00000100
|
|
||||||
case 6:
|
|
||||||
byteToAnd = 0b00000010
|
|
||||||
case 7:
|
|
||||||
byteToAnd = 0b00000001
|
|
||||||
}
|
|
||||||
|
|
||||||
return (volumeBitmap[byteToCheck] & byte(byteToAnd)) > 0
|
return (volumeBitmap[byteToCheck] & byte(byteToAnd)) > 0
|
||||||
}
|
}
|
||||||
|
|
|
@ -14,10 +14,10 @@ import (
|
||||||
|
|
||||||
func TestCreateVolumeBitmap(t *testing.T) {
|
func TestCreateVolumeBitmap(t *testing.T) {
|
||||||
var tests = []struct {
|
var tests = []struct {
|
||||||
blocks int
|
blocks uint16
|
||||||
want int
|
want uint16
|
||||||
}{
|
}{
|
||||||
{65536, 8192},
|
{65535, 8192},
|
||||||
{65533, 8192},
|
{65533, 8192},
|
||||||
{140, 512},
|
{140, 512},
|
||||||
}
|
}
|
||||||
|
@ -26,7 +26,7 @@ func TestCreateVolumeBitmap(t *testing.T) {
|
||||||
testname := fmt.Sprintf("%d", tt.blocks)
|
testname := fmt.Sprintf("%d", tt.blocks)
|
||||||
t.Run(testname, func(t *testing.T) {
|
t.Run(testname, func(t *testing.T) {
|
||||||
volumeBitMap := createVolumeBitmap(tt.blocks)
|
volumeBitMap := createVolumeBitmap(tt.blocks)
|
||||||
ans := len(volumeBitMap)
|
ans := uint16(len(volumeBitMap))
|
||||||
if ans != tt.want {
|
if ans != tt.want {
|
||||||
t.Errorf("got %d, want %d", ans, tt.want)
|
t.Errorf("got %d, want %d", ans, tt.want)
|
||||||
}
|
}
|
||||||
|
@ -36,7 +36,7 @@ func TestCreateVolumeBitmap(t *testing.T) {
|
||||||
|
|
||||||
func TestCheckFreeBlockInVolumeBitmap(t *testing.T) {
|
func TestCheckFreeBlockInVolumeBitmap(t *testing.T) {
|
||||||
var tests = []struct {
|
var tests = []struct {
|
||||||
blocks int
|
blocks uint16
|
||||||
want bool
|
want bool
|
||||||
}{
|
}{
|
||||||
{0, false}, // boot block
|
{0, false}, // boot block
|
||||||
|
@ -63,7 +63,7 @@ func TestCheckFreeBlockInVolumeBitmap(t *testing.T) {
|
||||||
|
|
||||||
func TestMarkBlockInVolumeBitmap(t *testing.T) {
|
func TestMarkBlockInVolumeBitmap(t *testing.T) {
|
||||||
var tests = []struct {
|
var tests = []struct {
|
||||||
blocks int
|
blocks uint16
|
||||||
want bool
|
want bool
|
||||||
}{
|
}{
|
||||||
{0, false}, // boot block
|
{0, false}, // boot block
|
||||||
|
|
|
@ -14,7 +14,7 @@ import (
|
||||||
)
|
)
|
||||||
|
|
||||||
// ReadBlock reads a block from a ProDOS volume into a byte array
|
// ReadBlock reads a block from a ProDOS volume into a byte array
|
||||||
func ReadBlock(reader io.ReaderAt, block int) ([]byte, error) {
|
func ReadBlock(reader io.ReaderAt, block uint16) ([]byte, error) {
|
||||||
buffer := make([]byte, 512)
|
buffer := make([]byte, 512)
|
||||||
|
|
||||||
_, err := reader.ReadAt(buffer, int64(block)*512)
|
_, err := reader.ReadAt(buffer, int64(block)*512)
|
||||||
|
@ -27,7 +27,7 @@ func ReadBlock(reader io.ReaderAt, block int) ([]byte, error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// WriteBlock writes a block to a ProDOS volume from a byte array
|
// WriteBlock writes a block to a ProDOS volume from a byte array
|
||||||
func WriteBlock(writer io.WriterAt, block int, buffer []byte) error {
|
func WriteBlock(writer io.WriterAt, block uint16, buffer []byte) error {
|
||||||
_, err := writer.WriteAt(buffer, int64(block)*512)
|
_, err := writer.WriteAt(buffer, int64(block)*512)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
errString := fmt.Sprintf("failed to write block %04X: %s", block, err.Error())
|
errString := fmt.Sprintf("failed to write block %04X: %s", block, err.Error())
|
||||||
|
|
|
@ -19,33 +19,33 @@ import (
|
||||||
type VolumeHeader struct {
|
type VolumeHeader struct {
|
||||||
VolumeName string
|
VolumeName string
|
||||||
CreationTime time.Time
|
CreationTime time.Time
|
||||||
ActiveFileCount int
|
ActiveFileCount uint16
|
||||||
BitmapStartBlock int
|
BitmapStartBlock uint16
|
||||||
TotalBlocks int
|
TotalBlocks uint16
|
||||||
NextBlock int
|
NextBlock uint16
|
||||||
EntryLength int
|
EntryLength uint8
|
||||||
EntriesPerBlock int
|
EntriesPerBlock uint8
|
||||||
MinVersion int
|
MinVersion uint8
|
||||||
Version int
|
Version uint8
|
||||||
}
|
}
|
||||||
|
|
||||||
// DirectoryHeader from ProDOS
|
// DirectoryHeader from ProDOS
|
||||||
type DirectoryHeader struct {
|
type DirectoryHeader struct {
|
||||||
PreviousBlock int
|
PreviousBlock uint16
|
||||||
NextBlock int
|
NextBlock uint16
|
||||||
IsSubDirectory bool
|
IsSubDirectory bool
|
||||||
Name string
|
Name string
|
||||||
CreationTime time.Time
|
CreationTime time.Time
|
||||||
Version int
|
Version uint8
|
||||||
MinVersion int
|
MinVersion uint8
|
||||||
Access int
|
Access uint8
|
||||||
EntryLength int
|
EntryLength uint8
|
||||||
EntriesPerBlock int
|
EntriesPerBlock uint8
|
||||||
ActiveFileCount int
|
ActiveFileCount uint16
|
||||||
StartingBlock int
|
StartingBlock uint16
|
||||||
ParentBlock int
|
ParentBlock uint16
|
||||||
ParentEntry int
|
ParentEntry uint16
|
||||||
ParentEntryLength int
|
ParentEntryLength uint8
|
||||||
}
|
}
|
||||||
|
|
||||||
const (
|
const (
|
||||||
|
@ -65,22 +65,22 @@ const (
|
||||||
|
|
||||||
// FileEntry from ProDOS
|
// FileEntry from ProDOS
|
||||||
type FileEntry struct {
|
type FileEntry struct {
|
||||||
StorageType int
|
StorageType uint8
|
||||||
FileName string
|
FileName string
|
||||||
FileType int
|
FileType uint8
|
||||||
CreationTime time.Time
|
CreationTime time.Time
|
||||||
KeyPointer int
|
KeyPointer uint16
|
||||||
Version int
|
Version uint8
|
||||||
MinVersion int
|
MinVersion uint8
|
||||||
BlocksUsed int
|
BlocksUsed uint16
|
||||||
EndOfFile int
|
EndOfFile uint32
|
||||||
Access int
|
Access uint8
|
||||||
AuxType int
|
AuxType uint16
|
||||||
ModifiedTime time.Time
|
ModifiedTime time.Time
|
||||||
HeaderPointer int
|
HeaderPointer uint16
|
||||||
|
|
||||||
DirectoryBlock int
|
DirectoryBlock uint16
|
||||||
DirectoryOffset int
|
DirectoryOffset uint16
|
||||||
}
|
}
|
||||||
|
|
||||||
// ReadDirectory reads the directory information from a specified path
|
// ReadDirectory reads the directory information from a specified path
|
||||||
|
@ -183,7 +183,7 @@ func CreateDirectory(readerWriter ReaderWriterAt, path string) error {
|
||||||
ActiveFileCount: 0,
|
ActiveFileCount: 0,
|
||||||
StartingBlock: blockList[0],
|
StartingBlock: blockList[0],
|
||||||
ParentBlock: fileEntry.DirectoryBlock,
|
ParentBlock: fileEntry.DirectoryBlock,
|
||||||
ParentEntry: (fileEntry.DirectoryOffset - 0x04) / 0x27,
|
ParentEntry: uint16(fileEntry.DirectoryOffset-0x04) / 0x27,
|
||||||
ParentEntryLength: 0x27,
|
ParentEntryLength: 0x27,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -219,18 +219,18 @@ func getFreeFileEntryInDirectory(readerWriter ReaderWriterAt, directory string)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return FileEntry{}, err
|
return FileEntry{}, err
|
||||||
}
|
}
|
||||||
entryOffset := 43 // start at offset after header
|
entryOffset := uint16(43) // start at offset after header
|
||||||
entryNumber := 2 // header is essentially the first entry so start at 2
|
entryNumber := 2 // header is essentially the first entry so start at 2
|
||||||
|
|
||||||
for {
|
for {
|
||||||
if entryNumber > 13 {
|
if entryNumber > 13 {
|
||||||
nextBlockNumber := int(buffer[2]) + int(buffer[3])*256
|
nextBlockNumber := uint16(buffer[2]) + uint16(buffer[3])*256
|
||||||
// if we ran out of blocks in the directory, expand directory or fail
|
// if we ran out of blocks in the directory, expand directory or fail
|
||||||
if nextBlockNumber == 0 {
|
if nextBlockNumber == 0 {
|
||||||
if !directoryHeader.IsSubDirectory {
|
if !directoryHeader.IsSubDirectory {
|
||||||
return FileEntry{}, errors.New("no free file entries found")
|
return FileEntry{}, errors.New("no free file entries found")
|
||||||
}
|
}
|
||||||
nextBlockNumber, err = expandDirectory(readerWriter, nextBlockNumber, buffer, blockNumber, directoryHeader)
|
nextBlockNumber, err = expandDirectory(readerWriter, buffer, blockNumber, directoryHeader)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return FileEntry{}, err
|
return FileEntry{}, err
|
||||||
}
|
}
|
||||||
|
@ -260,7 +260,7 @@ func getFreeFileEntryInDirectory(readerWriter ReaderWriterAt, directory string)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func expandDirectory(readerWriter ReaderWriterAt, nextBlockNumber int, buffer []byte, blockNumber int, directoryHeader DirectoryHeader) (int, error) {
|
func expandDirectory(readerWriter ReaderWriterAt, buffer []byte, blockNumber uint16, directoryHeader DirectoryHeader) (uint16, error) {
|
||||||
volumeBitMap, err := ReadVolumeBitmap(readerWriter)
|
volumeBitMap, err := ReadVolumeBitmap(readerWriter)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
errString := fmt.Sprintf("failed to get volume bitmap to expand directory: %s", err)
|
errString := fmt.Sprintf("failed to get volume bitmap to expand directory: %s", err)
|
||||||
|
@ -271,7 +271,7 @@ func expandDirectory(readerWriter ReaderWriterAt, nextBlockNumber int, buffer []
|
||||||
return 0, errors.New("failed to get free block to expand directory")
|
return 0, errors.New("failed to get free block to expand directory")
|
||||||
}
|
}
|
||||||
|
|
||||||
nextBlockNumber = blockList[0]
|
nextBlockNumber := blockList[0]
|
||||||
buffer[0x02] = byte(nextBlockNumber & 0x00FF)
|
buffer[0x02] = byte(nextBlockNumber & 0x00FF)
|
||||||
buffer[0x03] = byte(nextBlockNumber >> 8)
|
buffer[0x03] = byte(nextBlockNumber >> 8)
|
||||||
WriteBlock(readerWriter, blockNumber, buffer)
|
WriteBlock(readerWriter, blockNumber, buffer)
|
||||||
|
@ -296,8 +296,8 @@ func expandDirectory(readerWriter ReaderWriterAt, nextBlockNumber int, buffer []
|
||||||
errString := fmt.Sprintf("failed to read parent block to expand directory: %s", err)
|
errString := fmt.Sprintf("failed to read parent block to expand directory: %s", err)
|
||||||
return 0, errors.New(errString)
|
return 0, errors.New(errString)
|
||||||
}
|
}
|
||||||
directoryEntryOffset := directoryHeader.ParentEntry*directoryHeader.EntryLength + 0x04
|
directoryEntryOffset := directoryHeader.ParentEntry*uint16(directoryHeader.EntryLength) + 0x04
|
||||||
directoryFileEntry := parseFileEntry(buffer[directoryEntryOffset:directoryEntryOffset+0x28], directoryHeader.ParentBlock, directoryHeader.ParentEntry*directoryHeader.EntryLength+0x04)
|
directoryFileEntry := parseFileEntry(buffer[directoryEntryOffset:directoryEntryOffset+0x28], directoryHeader.ParentBlock, directoryHeader.ParentEntry*uint16(directoryHeader.EntryLength)+0x04)
|
||||||
directoryFileEntry.BlocksUsed++
|
directoryFileEntry.BlocksUsed++
|
||||||
directoryFileEntry.EndOfFile += 0x200
|
directoryFileEntry.EndOfFile += 0x200
|
||||||
writeFileEntry(readerWriter, directoryFileEntry)
|
writeFileEntry(readerWriter, directoryFileEntry)
|
||||||
|
@ -305,7 +305,7 @@ func expandDirectory(readerWriter ReaderWriterAt, nextBlockNumber int, buffer []
|
||||||
return nextBlockNumber, nil
|
return nextBlockNumber, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func getFileEntriesInDirectory(reader io.ReaderAt, blockNumber int, currentPath int, paths []string) (DirectoryHeader, []FileEntry, error) {
|
func getFileEntriesInDirectory(reader io.ReaderAt, blockNumber uint16, currentPath int, paths []string) (DirectoryHeader, []FileEntry, error) {
|
||||||
buffer, err := ReadBlock(reader, blockNumber)
|
buffer, err := ReadBlock(reader, blockNumber)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return DirectoryHeader{}, nil, err
|
return DirectoryHeader{}, nil, err
|
||||||
|
@ -314,9 +314,9 @@ func getFileEntriesInDirectory(reader io.ReaderAt, blockNumber int, currentPath
|
||||||
directoryHeader := parseDirectoryHeader(buffer, blockNumber)
|
directoryHeader := parseDirectoryHeader(buffer, blockNumber)
|
||||||
|
|
||||||
fileEntries := make([]FileEntry, directoryHeader.ActiveFileCount)
|
fileEntries := make([]FileEntry, directoryHeader.ActiveFileCount)
|
||||||
entryOffset := 43 // start at offset after header
|
entryOffset := uint16(43) // start at offset after header
|
||||||
activeEntries := 0
|
activeEntries := uint16(0)
|
||||||
entryNumber := 2 // header is essentially the first entry so start at 2
|
entryNumber := uint8(2) // header is essentially the first entry so start at 2
|
||||||
|
|
||||||
nextBlock := directoryHeader.NextBlock
|
nextBlock := directoryHeader.NextBlock
|
||||||
|
|
||||||
|
@ -338,7 +338,7 @@ func getFileEntriesInDirectory(reader io.ReaderAt, blockNumber int, currentPath
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return DirectoryHeader{}, nil, err
|
return DirectoryHeader{}, nil, err
|
||||||
}
|
}
|
||||||
nextBlock = int(buffer[2]) + int(buffer[3])*256
|
nextBlock = uint16(buffer[2]) + uint16(buffer[3])*256
|
||||||
}
|
}
|
||||||
fileEntry := parseFileEntry(buffer[entryOffset:entryOffset+40], blockNumber, entryOffset)
|
fileEntry := parseFileEntry(buffer[entryOffset:entryOffset+40], blockNumber, entryOffset)
|
||||||
|
|
||||||
|
@ -359,21 +359,21 @@ func getFileEntriesInDirectory(reader io.ReaderAt, blockNumber int, currentPath
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func parseFileEntry(buffer []byte, blockNumber int, entryOffset int) FileEntry {
|
func parseFileEntry(buffer []byte, blockNumber uint16, entryOffset uint16) FileEntry {
|
||||||
storageType := int(buffer[0] >> 4)
|
storageType := buffer[0] >> 4
|
||||||
fileNameLength := int(buffer[0] & 15)
|
fileNameLength := buffer[0] & 15
|
||||||
fileName := string(buffer[1 : fileNameLength+1])
|
fileName := string(buffer[1 : fileNameLength+1])
|
||||||
fileType := int(buffer[16])
|
fileType := buffer[16]
|
||||||
startingBlock := int(buffer[17]) + int(buffer[18])*256
|
startingBlock := uint16(buffer[17]) + uint16(buffer[18])*256
|
||||||
blocksUsed := int(buffer[19]) + int(buffer[20])*256
|
blocksUsed := uint16(buffer[19]) + uint16(buffer[20])*256
|
||||||
endOfFile := int(buffer[21]) + int(buffer[22])*256 + int(buffer[23])*65536
|
endOfFile := uint32(buffer[21]) + uint32(buffer[22])*256 + uint32(buffer[23])*65536
|
||||||
creationTime := DateTimeFromProDOS(buffer[24:28])
|
creationTime := DateTimeFromProDOS(buffer[24:28])
|
||||||
version := int(buffer[28])
|
version := buffer[28]
|
||||||
minVersion := int(buffer[29])
|
minVersion := buffer[29]
|
||||||
access := int(buffer[30])
|
access := buffer[30]
|
||||||
auxType := int(buffer[31]) + int(buffer[32])*256
|
auxType := uint16(buffer[31]) + uint16(buffer[32])*256
|
||||||
modifiedTime := DateTimeFromProDOS((buffer[33:37]))
|
modifiedTime := DateTimeFromProDOS((buffer[33:37]))
|
||||||
headerPointer := int(buffer[0x25]) + int(buffer[0x26])*256
|
headerPointer := uint16(buffer[0x25]) + uint16(buffer[0x26])*256
|
||||||
|
|
||||||
fileEntry := FileEntry{
|
fileEntry := FileEntry{
|
||||||
StorageType: storageType,
|
StorageType: storageType,
|
||||||
|
@ -427,24 +427,24 @@ func writeFileEntry(writer io.WriterAt, fileEntry FileEntry) {
|
||||||
buffer[0x26] = byte(fileEntry.HeaderPointer >> 8)
|
buffer[0x26] = byte(fileEntry.HeaderPointer >> 8)
|
||||||
|
|
||||||
//fmt.Printf("Writing file entry at block: %04X offset: %04X\n", fileEntry.DirectoryBlock, fileEntry.DirectoryOffset)
|
//fmt.Printf("Writing file entry at block: %04X offset: %04X\n", fileEntry.DirectoryBlock, fileEntry.DirectoryOffset)
|
||||||
_, err := writer.WriteAt(buffer, int64(fileEntry.DirectoryBlock*512+fileEntry.DirectoryOffset))
|
_, err := writer.WriteAt(buffer, int64(fileEntry.DirectoryBlock)*512+int64(fileEntry.DirectoryOffset))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func parseVolumeHeader(buffer []byte) VolumeHeader {
|
func parseVolumeHeader(buffer []byte) VolumeHeader {
|
||||||
nextBlock := int(buffer[2]) + int(buffer[3])*256
|
nextBlock := uint16(buffer[2]) + uint16(buffer[3])*256
|
||||||
filenameLength := buffer[4] & 15
|
filenameLength := buffer[4] & 15
|
||||||
volumeName := string(buffer[5 : filenameLength+5])
|
volumeName := string(buffer[5 : filenameLength+5])
|
||||||
creationTime := DateTimeFromProDOS(buffer[28:32])
|
creationTime := DateTimeFromProDOS(buffer[28:32])
|
||||||
version := int(buffer[32])
|
version := buffer[32]
|
||||||
minVersion := int(buffer[33])
|
minVersion := buffer[33]
|
||||||
entryLength := int(buffer[35])
|
entryLength := buffer[35]
|
||||||
entriesPerBlock := int(buffer[36])
|
entriesPerBlock := buffer[36]
|
||||||
fileCount := int(buffer[37]) + int(buffer[38])*256
|
fileCount := uint16(buffer[37]) + uint16(buffer[38])*256
|
||||||
bitmapBlock := int(buffer[39]) + int(buffer[40])*256
|
bitmapBlock := uint16(buffer[39]) + uint16(buffer[40])*256
|
||||||
totalBlocks := int(buffer[41]) + int(buffer[42])*256
|
totalBlocks := uint16(buffer[41]) + uint16(buffer[42])*256
|
||||||
|
|
||||||
if minVersion > 0 {
|
if minVersion > 0 {
|
||||||
panic("Unsupported ProDOS version")
|
panic("Unsupported ProDOS version")
|
||||||
|
@ -465,22 +465,22 @@ func parseVolumeHeader(buffer []byte) VolumeHeader {
|
||||||
return volumeHeader
|
return volumeHeader
|
||||||
}
|
}
|
||||||
|
|
||||||
func parseDirectoryHeader(buffer []byte, blockNumber int) DirectoryHeader {
|
func parseDirectoryHeader(buffer []byte, blockNumber uint16) DirectoryHeader {
|
||||||
previousBlock := int(buffer[0x00]) + int(buffer[0x01])*256
|
previousBlock := uint16(buffer[0x00]) + uint16(buffer[0x01])*256
|
||||||
nextBlock := int(buffer[0x02]) + int(buffer[0x03])*256
|
nextBlock := uint16(buffer[0x02]) + uint16(buffer[0x03])*256
|
||||||
isSubDirectory := (buffer[0x04] & 0xF0) == 0xE0
|
isSubDirectory := (buffer[0x04] & 0xF0) == 0xE0
|
||||||
filenameLength := buffer[0x04] & 0x0F
|
filenameLength := buffer[0x04] & 0x0F
|
||||||
name := string(buffer[0x05 : filenameLength+0x05])
|
name := string(buffer[0x05 : filenameLength+0x05])
|
||||||
creationTime := DateTimeFromProDOS(buffer[0x1C:0x20])
|
creationTime := DateTimeFromProDOS(buffer[0x1C:0x20])
|
||||||
version := int(buffer[0x20])
|
version := buffer[0x20]
|
||||||
minVersion := int(buffer[0x21])
|
minVersion := buffer[0x21]
|
||||||
access := int(buffer[0x22])
|
access := buffer[0x22]
|
||||||
entryLength := int(buffer[0x23])
|
entryLength := buffer[0x23]
|
||||||
entriesPerBlock := int(buffer[0x24])
|
entriesPerBlock := buffer[0x24]
|
||||||
fileCount := int(buffer[0x25]) + int(buffer[0x26])*256
|
fileCount := uint16(buffer[0x25]) + uint16(buffer[0x26])*256
|
||||||
parentBlock := int(buffer[0x27]) + int(buffer[0x28])*256
|
parentBlock := uint16(buffer[0x27]) + uint16(buffer[0x28])*256
|
||||||
parentEntry := int(buffer[0x29])
|
parentEntry := uint16(buffer[0x29])
|
||||||
parentEntryLength := int(buffer[0x2A])
|
parentEntryLength := buffer[0x2A]
|
||||||
|
|
||||||
directoryEntry := DirectoryHeader{
|
directoryEntry := DirectoryHeader{
|
||||||
PreviousBlock: previousBlock,
|
PreviousBlock: previousBlock,
|
||||||
|
|
|
@ -29,12 +29,12 @@ func LoadFile(reader io.ReaderAt, path string) ([]byte, error) {
|
||||||
|
|
||||||
buffer := make([]byte, fileEntry.EndOfFile)
|
buffer := make([]byte, fileEntry.EndOfFile)
|
||||||
|
|
||||||
for i := 0; i < len(blockList); i++ {
|
for i := uint16(0); i < uint16(len(blockList)); i++ {
|
||||||
block, err := ReadBlock(reader, blockList[i])
|
block, err := ReadBlock(reader, blockList[i])
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
for j := 0; j < 512 && i*512+j < fileEntry.EndOfFile; j++ {
|
for j := uint16(0); j < 512 && uint32(i)*512+uint32(j) < fileEntry.EndOfFile; j++ {
|
||||||
buffer[i*512+j] = block[j]
|
buffer[i*512+j] = block[j]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -43,7 +43,7 @@ func LoadFile(reader io.ReaderAt, path string) ([]byte, error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// WriteFile writes a file to a ProDOS volume from a byte array
|
// WriteFile writes a file to a ProDOS volume from a byte array
|
||||||
func WriteFile(readerWriter ReaderWriterAt, path string, fileType int, auxType int, createdTime time.Time, modifiedTime time.Time, buffer []byte) error {
|
func WriteFile(readerWriter ReaderWriterAt, path string, fileType uint8, auxType uint16, createdTime time.Time, modifiedTime time.Time, buffer []byte) error {
|
||||||
directory, fileName := GetDirectoryAndFileNameFromPath(path)
|
directory, fileName := GetDirectoryAndFileNameFromPath(path)
|
||||||
|
|
||||||
if len(fileName) > 15 {
|
if len(fileName) > 15 {
|
||||||
|
@ -56,7 +56,7 @@ func WriteFile(readerWriter ReaderWriterAt, path string, fileType int, auxType i
|
||||||
}
|
}
|
||||||
|
|
||||||
// get list of blocks to write file to
|
// get list of blocks to write file to
|
||||||
blockList, err := createBlockList(readerWriter, len(buffer))
|
blockList, err := createBlockList(readerWriter, uint32(len(buffer)))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -88,11 +88,11 @@ func WriteFile(readerWriter ReaderWriterAt, path string, fileType int, auxType i
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
fileEntry.FileName = fileName
|
fileEntry.FileName = fileName
|
||||||
fileEntry.BlocksUsed = len(blockList)
|
fileEntry.BlocksUsed = uint16(len(blockList))
|
||||||
fileEntry.CreationTime = createdTime
|
fileEntry.CreationTime = createdTime
|
||||||
fileEntry.ModifiedTime = modifiedTime
|
fileEntry.ModifiedTime = modifiedTime
|
||||||
fileEntry.AuxType = auxType
|
fileEntry.AuxType = auxType
|
||||||
fileEntry.EndOfFile = len(buffer)
|
fileEntry.EndOfFile = uint32(len(buffer))
|
||||||
fileEntry.FileType = fileType
|
fileEntry.FileType = fileType
|
||||||
fileEntry.KeyPointer = blockList[0]
|
fileEntry.KeyPointer = blockList[0]
|
||||||
fileEntry.Version = 0x24
|
fileEntry.Version = 0x24
|
||||||
|
@ -197,24 +197,24 @@ func GetDirectoryAndFileNameFromPath(path string) (string, string) {
|
||||||
return directory, fileName
|
return directory, fileName
|
||||||
}
|
}
|
||||||
|
|
||||||
func updateVolumeBitmap(readerWriter ReaderWriterAt, blockList []int) error {
|
func updateVolumeBitmap(readerWriter ReaderWriterAt, blockList []uint16) error {
|
||||||
|
|
||||||
volumeBitmap, err := ReadVolumeBitmap(readerWriter)
|
volumeBitmap, err := ReadVolumeBitmap(readerWriter)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Printf("%s", err)
|
fmt.Printf("%s", err)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
for i := 0; i < len(blockList); i++ {
|
for i := uint16(0); i < uint16(len(blockList)); i++ {
|
||||||
markBlockInVolumeBitmap(volumeBitmap, blockList[i])
|
markBlockInVolumeBitmap(volumeBitmap, blockList[i])
|
||||||
}
|
}
|
||||||
return writeVolumeBitmap(readerWriter, volumeBitmap)
|
return writeVolumeBitmap(readerWriter, volumeBitmap)
|
||||||
}
|
}
|
||||||
|
|
||||||
func writeSeedlingFile(writer io.WriterAt, buffer []byte, blockList []int) {
|
func writeSeedlingFile(writer io.WriterAt, buffer []byte, blockList []uint16) {
|
||||||
WriteBlock(writer, blockList[0], buffer)
|
WriteBlock(writer, blockList[0], buffer)
|
||||||
}
|
}
|
||||||
|
|
||||||
func writeSaplingFile(writer io.WriterAt, buffer []byte, blockList []int) {
|
func writeSaplingFile(writer io.WriterAt, buffer []byte, blockList []uint16) {
|
||||||
// write index block with pointers to data blocks
|
// write index block with pointers to data blocks
|
||||||
indexBuffer := make([]byte, 512)
|
indexBuffer := make([]byte, 512)
|
||||||
for i := 0; i < 256; i++ {
|
for i := 0; i < 256; i++ {
|
||||||
|
@ -249,7 +249,7 @@ func writeSaplingFile(writer io.WriterAt, buffer []byte, blockList []int) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func writeTreeFile(writer io.WriterAt, buffer []byte, blockList []int) {
|
func writeTreeFile(writer io.WriterAt, buffer []byte, blockList []uint16) {
|
||||||
// write master index block with pointers to index blocks
|
// write master index block with pointers to index blocks
|
||||||
indexBuffer := make([]byte, 512)
|
indexBuffer := make([]byte, 512)
|
||||||
numberOfIndexBlocks := len(blockList)/256 + 1
|
numberOfIndexBlocks := len(blockList)/256 + 1
|
||||||
|
@ -303,17 +303,17 @@ func writeTreeFile(writer io.WriterAt, buffer []byte, blockList []int) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func getDataBlocklist(reader io.ReaderAt, fileEntry FileEntry) ([]int, error) {
|
func getDataBlocklist(reader io.ReaderAt, fileEntry FileEntry) ([]uint16, error) {
|
||||||
return getBlocklist(reader, fileEntry, true)
|
return getBlocklist(reader, fileEntry, true)
|
||||||
}
|
}
|
||||||
|
|
||||||
func getAllBlockList(reader io.ReaderAt, fileEntry FileEntry) ([]int, error) {
|
func getAllBlockList(reader io.ReaderAt, fileEntry FileEntry) ([]uint16, error) {
|
||||||
return getBlocklist(reader, fileEntry, false)
|
return getBlocklist(reader, fileEntry, false)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Returns all blocks, including index blocks
|
// Returns all blocks, including index blocks
|
||||||
func getBlocklist(reader io.ReaderAt, fileEntry FileEntry, dataOnly bool) ([]int, error) {
|
func getBlocklist(reader io.ReaderAt, fileEntry FileEntry, dataOnly bool) ([]uint16, error) {
|
||||||
blocks := make([]int, fileEntry.BlocksUsed)
|
blocks := make([]uint16, fileEntry.BlocksUsed)
|
||||||
|
|
||||||
switch fileEntry.StorageType {
|
switch fileEntry.StorageType {
|
||||||
case StorageSeedling:
|
case StorageSeedling:
|
||||||
|
@ -324,10 +324,10 @@ func getBlocklist(reader io.ReaderAt, fileEntry FileEntry, dataOnly bool) ([]int
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
blockOffset := 1
|
blockOffset := uint16(1)
|
||||||
blocks[0] = fileEntry.KeyPointer
|
blocks[0] = fileEntry.KeyPointer
|
||||||
for i := 0; i < fileEntry.BlocksUsed-1; i++ {
|
for i := uint16(0); i < fileEntry.BlocksUsed-1; i++ {
|
||||||
blocks[i+blockOffset] = int(index[i]) + int(index[i+256])*256
|
blocks[i+blockOffset] = uint16(index[i]) + uint16(index[i+256])*256
|
||||||
}
|
}
|
||||||
if dataOnly {
|
if dataOnly {
|
||||||
return blocks[1:], nil
|
return blocks[1:], nil
|
||||||
|
@ -335,10 +335,10 @@ func getBlocklist(reader io.ReaderAt, fileEntry FileEntry, dataOnly bool) ([]int
|
||||||
return blocks, nil
|
return blocks, nil
|
||||||
case StorageTree:
|
case StorageTree:
|
||||||
// this is actually too large
|
// this is actually too large
|
||||||
dataBlocks := make([]int, fileEntry.BlocksUsed)
|
dataBlocks := make([]uint16, fileEntry.BlocksUsed)
|
||||||
// this is also actually too large
|
// this is also actually too large
|
||||||
numberOfIndexBlocks := fileEntry.BlocksUsed/256 + 2
|
numberOfIndexBlocks := fileEntry.BlocksUsed/256 + 2
|
||||||
indexBlocks := make([]int, numberOfIndexBlocks)
|
indexBlocks := make([]uint16, numberOfIndexBlocks)
|
||||||
masterIndex, err := ReadBlock(reader, fileEntry.KeyPointer)
|
masterIndex, err := ReadBlock(reader, fileEntry.KeyPointer)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
|
@ -348,8 +348,8 @@ func getBlocklist(reader io.ReaderAt, fileEntry FileEntry, dataOnly bool) ([]int
|
||||||
indexBlocks[0] = fileEntry.KeyPointer
|
indexBlocks[0] = fileEntry.KeyPointer
|
||||||
indexBlockCount := 1
|
indexBlockCount := 1
|
||||||
|
|
||||||
for i := 0; i < 128; i++ {
|
for i := uint16(0); i < 128; i++ {
|
||||||
indexBlock := int(masterIndex[i]) + int(masterIndex[i+256])*256
|
indexBlock := uint16(masterIndex[i]) + uint16(masterIndex[i+256])*256
|
||||||
if indexBlock == 0 {
|
if indexBlock == 0 {
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
|
@ -359,12 +359,12 @@ func getBlocklist(reader io.ReaderAt, fileEntry FileEntry, dataOnly bool) ([]int
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
for j := 0; j < 256 && i*256+j < fileEntry.BlocksUsed; j++ {
|
for j := uint16(0); j < 256 && i*256+j < fileEntry.BlocksUsed; j++ {
|
||||||
if (int(index[j]) + int(index[j+256])*256) == 0 {
|
if (uint16(index[j]) + uint16(index[j+256])*256) == 0 {
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
numberOfDataBlocks++
|
numberOfDataBlocks++
|
||||||
dataBlocks[i*256+j] = int(index[j]) + int(index[j+256])*256
|
dataBlocks[i*256+j] = uint16(index[j]) + uint16(index[j+256])*256
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -379,8 +379,8 @@ func getBlocklist(reader io.ReaderAt, fileEntry FileEntry, dataOnly bool) ([]int
|
||||||
return nil, errors.New("unsupported file storage type")
|
return nil, errors.New("unsupported file storage type")
|
||||||
}
|
}
|
||||||
|
|
||||||
func createBlockList(reader io.ReaderAt, fileSize int) ([]int, error) {
|
func createBlockList(reader io.ReaderAt, fileSize uint32) ([]uint16, error) {
|
||||||
numberOfBlocks := fileSize / 512
|
numberOfBlocks := uint16(fileSize / 512)
|
||||||
|
|
||||||
if fileSize%512 > 0 {
|
if fileSize%512 > 0 {
|
||||||
numberOfBlocks++
|
numberOfBlocks++
|
||||||
|
|
|
@ -11,8 +11,8 @@ import (
|
||||||
|
|
||||||
func TestCreateBlocklist(t *testing.T) {
|
func TestCreateBlocklist(t *testing.T) {
|
||||||
var tests = []struct {
|
var tests = []struct {
|
||||||
fileSize int
|
fileSize uint32
|
||||||
wantBlocks int
|
wantBlocks uint16
|
||||||
}{
|
}{
|
||||||
{1, 1},
|
{1, 1},
|
||||||
{512, 1},
|
{512, 1},
|
||||||
|
@ -33,7 +33,7 @@ func TestCreateBlocklist(t *testing.T) {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Error("got error, want nil")
|
t.Error("got error, want nil")
|
||||||
}
|
}
|
||||||
if len(blockList) != tt.wantBlocks {
|
if uint16(len(blockList)) != tt.wantBlocks {
|
||||||
t.Errorf("got %d blocks, want %d", len(blockList), tt.wantBlocks)
|
t.Errorf("got %d blocks, want %d", len(blockList), tt.wantBlocks)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
@ -41,7 +41,7 @@ func TestCreateBlocklist(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestUpdateVolumeBitmap(t *testing.T) {
|
func TestUpdateVolumeBitmap(t *testing.T) {
|
||||||
blockList := []int{10, 11, 12, 100, 120}
|
blockList := []uint16{10, 11, 12, 100, 120}
|
||||||
|
|
||||||
virtualDisk := NewMemoryFile(0x2000000)
|
virtualDisk := NewMemoryFile(0x2000000)
|
||||||
CreateVolume(virtualDisk, "VIRTUAL.DISK", 0xFFFE)
|
CreateVolume(virtualDisk, "VIRTUAL.DISK", 0xFFFE)
|
||||||
|
|
|
@ -14,7 +14,7 @@ import (
|
||||||
|
|
||||||
// CreateVolume formats a new ProDOS volume including boot block,
|
// CreateVolume formats a new ProDOS volume including boot block,
|
||||||
// volume bitmap and empty directory
|
// volume bitmap and empty directory
|
||||||
func CreateVolume(readerWriter ReaderWriterAt, volumeName string, numberOfBlocks int) {
|
func CreateVolume(readerWriter ReaderWriterAt, volumeName string, numberOfBlocks uint16) {
|
||||||
if numberOfBlocks > 65535 || numberOfBlocks < 64 {
|
if numberOfBlocks > 65535 || numberOfBlocks < 64 {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
@ -26,7 +26,7 @@ func CreateVolume(readerWriter ReaderWriterAt, volumeName string, numberOfBlocks
|
||||||
}
|
}
|
||||||
|
|
||||||
blankBlock := make([]byte, 512)
|
blankBlock := make([]byte, 512)
|
||||||
for i := 0; i < numberOfBlocks; i++ {
|
for i := uint16(0); i < numberOfBlocks; i++ {
|
||||||
WriteBlock(readerWriter, i, blankBlock)
|
WriteBlock(readerWriter, i, blankBlock)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -13,9 +13,9 @@ import (
|
||||||
|
|
||||||
func TestCreateVolume(t *testing.T) {
|
func TestCreateVolume(t *testing.T) {
|
||||||
var tests = []struct {
|
var tests = []struct {
|
||||||
blocks int
|
blocks uint16
|
||||||
wantVolumeName string
|
wantVolumeName string
|
||||||
wantFreeBlocks int
|
wantFreeBlocks uint16
|
||||||
}{
|
}{
|
||||||
{65535, "MAX", 65513},
|
{65535, "MAX", 65513},
|
||||||
{65500, "ALMOST.MAX", 65478},
|
{65500, "ALMOST.MAX", 65478},
|
||||||
|
|
|
@ -12,6 +12,8 @@ import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"os"
|
"os"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
|
"regexp"
|
||||||
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
)
|
)
|
||||||
|
@ -75,8 +77,8 @@ func AddFilesFromHostDirectory(
|
||||||
func WriteFileFromFile(
|
func WriteFileFromFile(
|
||||||
readerWriter ReaderWriterAt,
|
readerWriter ReaderWriterAt,
|
||||||
pathName string,
|
pathName string,
|
||||||
fileType int,
|
fileType uint8,
|
||||||
auxType int,
|
auxType uint16,
|
||||||
modifiedTime time.Time,
|
modifiedTime time.Time,
|
||||||
inFileName string,
|
inFileName string,
|
||||||
ignoreDuplicates bool,
|
ignoreDuplicates bool,
|
||||||
|
@ -117,6 +119,11 @@ func WriteFileFromFile(
|
||||||
case ".SYS", ".TXT", ".BAS", ".BIN":
|
case ".SYS", ".TXT", ".BAS", ".BIN":
|
||||||
pathName = strings.TrimSuffix(pathName, ext)
|
pathName = strings.TrimSuffix(pathName, ext)
|
||||||
}
|
}
|
||||||
|
match, err := regexp.MatchString("^\\.(BIN|SYS|TXT|BAS)\\$[0-9]{4}", ext)
|
||||||
|
|
||||||
|
if err == nil && match {
|
||||||
|
pathName = strings.TrimSuffix(pathName, ext)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -140,9 +147,12 @@ func WriteFileFromFile(
|
||||||
return WriteFile(readerWriter, pathName, fileType, auxType, time.Now(), modifiedTime, inFile)
|
return WriteFile(readerWriter, pathName, fileType, auxType, time.Now(), modifiedTime, inFile)
|
||||||
}
|
}
|
||||||
|
|
||||||
func convertFileByType(inFileName string, inFile []byte) (int, int, []byte, error) {
|
func convertFileByType(inFileName string, inFile []byte) (uint16, uint8, []byte, error) {
|
||||||
fileType := 0x06 // default to BIN
|
var auxType uint16
|
||||||
auxType := 0x2000 // default to $2000
|
var fileType uint8
|
||||||
|
|
||||||
|
fileType = 0x06 // default to BIN
|
||||||
|
auxType = 0x2000 // default to $2000
|
||||||
|
|
||||||
var err error
|
var err error
|
||||||
|
|
||||||
|
@ -166,36 +176,57 @@ func convertFileByType(inFileName string, inFile []byte) (int, int, []byte, erro
|
||||||
// Length
|
// Length
|
||||||
binary.BigEndian.Uint32(inFile[0x2E:]) == 0x00000008 {
|
binary.BigEndian.Uint32(inFile[0x2E:]) == 0x00000008 {
|
||||||
|
|
||||||
fileType = int(binary.BigEndian.Uint16(inFile[0x34:]))
|
fileType = uint8(binary.BigEndian.Uint16(inFile[0x34:]))
|
||||||
auxType = int(binary.BigEndian.Uint32(inFile[0x36:]))
|
auxType = uint16(binary.BigEndian.Uint32(inFile[0x36:]))
|
||||||
inFile = inFile[0x3A:]
|
inFile = inFile[0x3A:]
|
||||||
} else {
|
} else {
|
||||||
// use extension to determine file type
|
// use extension to determine file type
|
||||||
ext := strings.ToUpper(filepath.Ext(inFileName))
|
ext := strings.ToUpper(filepath.Ext(inFileName))
|
||||||
|
|
||||||
switch ext {
|
match, err := regexp.MatchString("^\\.(BIN|SYS|TXT|BAS)\\$[0-9]{4}", ext)
|
||||||
case ".BAS":
|
|
||||||
inFile, err = ConvertTextToBasic(string(inFile))
|
|
||||||
fileType = 0xFC
|
|
||||||
auxType = 0x0801
|
|
||||||
|
|
||||||
|
if err == nil && match {
|
||||||
|
parts := strings.Split(ext, "$")
|
||||||
|
extAuxType, err := strconv.ParseUint(parts[1], 16, 16)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return 0, 0, nil, err
|
return 0, 0, nil, err
|
||||||
}
|
}
|
||||||
case ".SYS":
|
auxType = uint16(extAuxType)
|
||||||
fileType = 0xFF
|
switch parts[0] {
|
||||||
auxType = 0x2000
|
case ".BAS":
|
||||||
case ".BIN":
|
fileType = 0xFC
|
||||||
fileType = 0x06
|
case ".SYS":
|
||||||
auxType = 0x2000
|
fileType = 0xFF
|
||||||
case ".TXT":
|
case ".BIN":
|
||||||
inFile = []byte(strings.ReplaceAll(strings.ReplaceAll(string(inFile), "\r\n", "r"), "\n", "\r"))
|
fileType = 0x06
|
||||||
fileType = 0x04
|
case ".TXT":
|
||||||
auxType = 0x0000
|
fileType = 0x04
|
||||||
case ".JPG", ".PNG":
|
}
|
||||||
inFile = ConvertImageToHiResMonochrome(inFile)
|
} else {
|
||||||
fileType = 0x06
|
switch ext {
|
||||||
auxType = 0x2000
|
case ".BAS":
|
||||||
|
inFile, err = ConvertTextToBasic(string(inFile))
|
||||||
|
fileType = 0xFC
|
||||||
|
auxType = 0x0801
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return 0, 0, nil, err
|
||||||
|
}
|
||||||
|
case ".SYS":
|
||||||
|
fileType = 0xFF
|
||||||
|
auxType = 0x2000
|
||||||
|
case ".BIN":
|
||||||
|
fileType = 0x06
|
||||||
|
auxType = 0x2000
|
||||||
|
case ".TXT":
|
||||||
|
inFile = []byte(strings.ReplaceAll(strings.ReplaceAll(string(inFile), "\r\n", "r"), "\n", "\r"))
|
||||||
|
fileType = 0x04
|
||||||
|
auxType = 0x0000
|
||||||
|
case ".JPG", ".PNG":
|
||||||
|
inFile = ConvertImageToHiResMonochrome(inFile)
|
||||||
|
fileType = 0x06
|
||||||
|
auxType = 0x2000
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -25,7 +25,7 @@ func TimeToString(printTime time.Time) string {
|
||||||
}
|
}
|
||||||
|
|
||||||
// FileTypeToString display the file type as a string
|
// FileTypeToString display the file type as a string
|
||||||
func FileTypeToString(fileType int) string {
|
func FileTypeToString(fileType uint8) string {
|
||||||
switch fileType {
|
switch fileType {
|
||||||
case 1:
|
case 1:
|
||||||
return "BAD"
|
return "BAD"
|
||||||
|
@ -159,7 +159,7 @@ func DumpBlock(buffer []byte) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// DumpDirectory displays the directory similar to ProDOS catalog
|
// DumpDirectory displays the directory similar to ProDOS catalog
|
||||||
func DumpDirectory(blocksFree int, totalBlocks int, path string, fileEntries []FileEntry) {
|
func DumpDirectory(blocksFree uint16, totalBlocks uint16, path string, fileEntries []FileEntry) {
|
||||||
fmt.Printf("%s\n\n", path)
|
fmt.Printf("%s\n\n", path)
|
||||||
fmt.Printf("NAME TYPE BLOCKS MODIFIED CREATED ENDFILE SUBTYPE\n\n")
|
fmt.Printf("NAME TYPE BLOCKS MODIFIED CREATED ENDFILE SUBTYPE\n\n")
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue
Block a user