Change ints to specific uints

This commit is contained in:
Terence Boldt 2024-03-11 08:05:23 -05:00
parent 0aa838ffe1
commit bf94ac8822
11 changed files with 225 additions and 250 deletions

32
main.go
View File

@ -25,21 +25,21 @@ func main() {
var command string
var outFileName string
var inFileName string
var blockNumber int
var volumeSize int
var blockNumber uint
var volumeSize uint
var volumeName string
var fileType int
var auxType int
var fileType uint
var auxType uint
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(&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(&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.IntVar(&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.IntVar(&auxType, "a", 0, "ProDOS AuxType from 0 to 65535 (0x0000 to 0xFFFF hex input accepted), omit to autodetect")
flag.UintVar(&blockNumber, "b", 0, "A block number to read/write from 0 to 65535 (0x0000 to 0xFFFF hex input accepted)")
flag.UintVar(&fileType, "t", 0, "ProDOS FileType: 0x04 for TXT, 0x06 for BIN, 0xFC for BAS, 0xFF for SYS etc., 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()
if len(fileName) == 0 {
@ -54,13 +54,13 @@ func main() {
case "get":
get(fileName, pathName, outFileName)
case "put":
put(fileName, pathName, fileType, auxType, inFileName)
put(fileName, pathName, uint8(fileType), uint16(auxType), inFileName)
case "readblock":
readBlock(blockNumber, fileName)
readBlock(uint16(blockNumber), fileName)
case "writeblock":
writeBlock(blockNumber, fileName, inFileName)
writeBlock(uint16(blockNumber), fileName, inFileName)
case "create":
create(fileName, volumeName, volumeSize)
create(fileName, volumeName, uint16(volumeSize))
case "putall":
putall(fileName, inFileName, pathName, false)
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)
if err != nil {
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)
}
func writeBlock(blockNumber int, fileName string, inFileName string) {
func writeBlock(blockNumber uint16, fileName string, inFileName string) {
checkInFileName(inFileName)
fmt.Printf("Writing block 0x%04X (%d):\n\n", blockNumber, blockNumber)
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)
}
func readBlock(blockNumber int, fileName string) {
func readBlock(blockNumber uint16, fileName string) {
fmt.Printf("Reading block 0x%04X (%d):\n\n", blockNumber, blockNumber)
file, err := os.OpenFile(fileName, os.O_RDONLY, 0755)
if err != nil {
@ -190,7 +190,7 @@ func readBlock(blockNumber int, fileName string) {
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)
checkInFileName(inFileName)
file, err := os.OpenFile(fileName, os.O_RDWR, 0755)

View File

@ -33,13 +33,13 @@ func ReadVolumeBitmap(reader io.ReaderAt) ([]byte, error) {
totalBitmapBlocks++
}
for i := 0; i < totalBitmapBlocks; i++ {
for i := uint16(0); i < totalBitmapBlocks; i++ {
bitmapBlock, err := ReadBlock(reader, i+volumeHeader.BitmapStartBlock)
if err != nil {
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]
}
}
@ -48,10 +48,10 @@ func ReadVolumeBitmap(reader io.ReaderAt) ([]byte, error) {
}
// GetFreeBlockCount gets the number of free blocks on a ProDOS image
func GetFreeBlockCount(volumeBitmap []byte, totalBlocks int) int {
freeBlockCount := 0
func GetFreeBlockCount(volumeBitmap []byte, totalBlocks uint16) uint16 {
freeBlockCount := uint16(0)
for i := 0; i < totalBlocks; i++ {
for i := uint16(0); i < totalBlocks; i++ {
if checkFreeBlockInVolumeBitmap(volumeBitmap, i) {
freeBlockCount++
}
@ -77,13 +77,13 @@ func writeVolumeBitmap(readerWriter ReaderWriterAt, bitmap []byte) error {
totalBitmapBlocks++
}
for i := 0; i < totalBitmapBlocks; i++ {
for i := uint16(0); i < totalBitmapBlocks; i++ {
bitmapBlock, err := ReadBlock(readerWriter, i+volumeHeader.BitmapStartBlock)
if err != nil {
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]
}
@ -96,9 +96,10 @@ func writeVolumeBitmap(readerWriter ReaderWriterAt, bitmap []byte) error {
return nil
}
func createVolumeBitmap(numberOfBlocks int) []byte {
volumeBitmapBlocks := numberOfBlocks / 512 / 8
if volumeBitmapBlocks*8*512 < numberOfBlocks {
func createVolumeBitmap(numberOfBlocks uint16) []byte {
// needs to be > uint16 because it's multiplying by a uint16
volumeBitmapBlocks := uint32(numberOfBlocks / 512 / 8)
if volumeBitmapBlocks*8*512 < uint32(numberOfBlocks) {
volumeBitmapBlocks++
}
@ -119,30 +120,31 @@ func createVolumeBitmap(numberOfBlocks int) []byte {
markBlockInVolumeBitmap(volumeBitmap, 5)
// volume bitmap blocks
for i := 0; i < volumeBitmapBlocks; i++ {
markBlockInVolumeBitmap(volumeBitmap, 6+i)
for i := uint32(0); i < volumeBitmapBlocks; i++ {
markBlockInVolumeBitmap(volumeBitmap, uint16(6+i))
}
// blocks beyond the volume
totalBlocksInBitmap := volumeBitmapBlocks * 512 * 8
blocksBeyondEnd := totalBlocksInBitmap - numberOfBlocks
blocksBeyondEnd := totalBlocksInBitmap - uint32(numberOfBlocks)
if blocksBeyondEnd > 0 {
for i := totalBlocksInBitmap - blocksBeyondEnd; i < totalBlocksInBitmap; i++ {
markBlockInVolumeBitmap(volumeBitmap, i)
markBlockInVolumeBitmap(volumeBitmap, uint16(i))
}
}
return volumeBitmap
}
func findFreeBlocks(volumeBitmap []byte, numberOfBlocks int) []int {
blocks := make([]int, numberOfBlocks)
func findFreeBlocks(volumeBitmap []byte, numberOfBlocks uint16) []uint16 {
blocks := make([]uint16, numberOfBlocks)
blocksFound := 0
blocksFound := uint16(0)
for i := 0; i < len(volumeBitmap)*8; i++ {
if checkFreeBlockInVolumeBitmap(volumeBitmap, i) {
blocks[blocksFound] = i
// needs to be > uint16 because it's multiplying by a uint16
for i := uint32(0); i < uint32(len(volumeBitmap))*8; i++ {
if checkFreeBlockInVolumeBitmap(volumeBitmap, uint16(i)) {
blocks[blocksFound] = uint16(i)
blocksFound++
if blocksFound == numberOfBlocks {
return blocks
@ -153,87 +155,29 @@ func findFreeBlocks(volumeBitmap []byte, numberOfBlocks int) []int {
return nil
}
func markBlockInVolumeBitmap(volumeBitmap []byte, blockNumber int) {
func markBlockInVolumeBitmap(volumeBitmap []byte, blockNumber uint16) {
bitToChange := 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)
}
func freeBlockInVolumeBitmap(volumeBitmap []byte, blockNumber int) {
func freeBlockInVolumeBitmap(volumeBitmap []byte, blockNumber uint16) {
bitToChange := blockNumber % 8
byteToChange := blockNumber / 8
byteToOr := 0b00000000
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
}
byteToOr := uint8(0b10000000) >> uint8(bitToChange)
volumeBitmap[byteToChange] |= byte(byteToOr)
}
func checkFreeBlockInVolumeBitmap(volumeBitmap []byte, blockNumber int) bool {
func checkFreeBlockInVolumeBitmap(volumeBitmap []byte, blockNumber uint16) bool {
bitToCheck := blockNumber % 8
byteToCheck := blockNumber / 8
byteToAnd := 0b00000000
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
}
byteToAnd := uint8(0b10000000) >> uint8(bitToCheck)
return (volumeBitmap[byteToCheck] & byte(byteToAnd)) > 0
}

View File

@ -14,10 +14,10 @@ import (
func TestCreateVolumeBitmap(t *testing.T) {
var tests = []struct {
blocks int
want int
blocks uint16
want uint16
}{
{65536, 8192},
{65535, 8192},
{65533, 8192},
{140, 512},
}
@ -26,7 +26,7 @@ func TestCreateVolumeBitmap(t *testing.T) {
testname := fmt.Sprintf("%d", tt.blocks)
t.Run(testname, func(t *testing.T) {
volumeBitMap := createVolumeBitmap(tt.blocks)
ans := len(volumeBitMap)
ans := uint16(len(volumeBitMap))
if 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) {
var tests = []struct {
blocks int
blocks uint16
want bool
}{
{0, false}, // boot block
@ -63,7 +63,7 @@ func TestCheckFreeBlockInVolumeBitmap(t *testing.T) {
func TestMarkBlockInVolumeBitmap(t *testing.T) {
var tests = []struct {
blocks int
blocks uint16
want bool
}{
{0, false}, // boot block

View File

@ -14,7 +14,7 @@ import (
)
// 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)
_, 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
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)
if err != nil {
errString := fmt.Sprintf("failed to write block %04X: %s", block, err.Error())

View File

@ -19,33 +19,33 @@ import (
type VolumeHeader struct {
VolumeName string
CreationTime time.Time
ActiveFileCount int
BitmapStartBlock int
TotalBlocks int
NextBlock int
EntryLength int
EntriesPerBlock int
MinVersion int
Version int
ActiveFileCount uint16
BitmapStartBlock uint16
TotalBlocks uint16
NextBlock uint16
EntryLength uint8
EntriesPerBlock uint8
MinVersion uint8
Version uint8
}
// DirectoryHeader from ProDOS
type DirectoryHeader struct {
PreviousBlock int
NextBlock int
PreviousBlock uint16
NextBlock uint16
IsSubDirectory bool
Name string
CreationTime time.Time
Version int
MinVersion int
Access int
EntryLength int
EntriesPerBlock int
ActiveFileCount int
StartingBlock int
ParentBlock int
ParentEntry int
ParentEntryLength int
Version uint8
MinVersion uint8
Access uint8
EntryLength uint8
EntriesPerBlock uint8
ActiveFileCount uint16
StartingBlock uint16
ParentBlock uint16
ParentEntry uint16
ParentEntryLength uint8
}
const (
@ -65,22 +65,22 @@ const (
// FileEntry from ProDOS
type FileEntry struct {
StorageType int
StorageType uint8
FileName string
FileType int
FileType uint8
CreationTime time.Time
KeyPointer int
Version int
MinVersion int
BlocksUsed int
EndOfFile int
Access int
AuxType int
KeyPointer uint16
Version uint8
MinVersion uint8
BlocksUsed uint16
EndOfFile uint32
Access uint8
AuxType uint16
ModifiedTime time.Time
HeaderPointer int
HeaderPointer uint16
DirectoryBlock int
DirectoryOffset int
DirectoryBlock uint16
DirectoryOffset uint16
}
// ReadDirectory reads the directory information from a specified path
@ -183,7 +183,7 @@ func CreateDirectory(readerWriter ReaderWriterAt, path string) error {
ActiveFileCount: 0,
StartingBlock: blockList[0],
ParentBlock: fileEntry.DirectoryBlock,
ParentEntry: (fileEntry.DirectoryOffset - 0x04) / 0x27,
ParentEntry: uint16(fileEntry.DirectoryOffset-0x04) / 0x27,
ParentEntryLength: 0x27,
}
@ -219,18 +219,18 @@ func getFreeFileEntryInDirectory(readerWriter ReaderWriterAt, directory string)
if err != nil {
return FileEntry{}, err
}
entryOffset := 43 // start at offset after header
entryNumber := 2 // header is essentially the first entry so start at 2
entryOffset := uint16(43) // start at offset after header
entryNumber := 2 // header is essentially the first entry so start at 2
for {
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 nextBlockNumber == 0 {
if !directoryHeader.IsSubDirectory {
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 {
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)
if err != nil {
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")
}
nextBlockNumber = blockList[0]
nextBlockNumber := blockList[0]
buffer[0x02] = byte(nextBlockNumber & 0x00FF)
buffer[0x03] = byte(nextBlockNumber >> 8)
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)
return 0, errors.New(errString)
}
directoryEntryOffset := directoryHeader.ParentEntry*directoryHeader.EntryLength + 0x04
directoryFileEntry := parseFileEntry(buffer[directoryEntryOffset:directoryEntryOffset+0x28], directoryHeader.ParentBlock, directoryHeader.ParentEntry*directoryHeader.EntryLength+0x04)
directoryEntryOffset := directoryHeader.ParentEntry*uint16(directoryHeader.EntryLength) + 0x04
directoryFileEntry := parseFileEntry(buffer[directoryEntryOffset:directoryEntryOffset+0x28], directoryHeader.ParentBlock, directoryHeader.ParentEntry*uint16(directoryHeader.EntryLength)+0x04)
directoryFileEntry.BlocksUsed++
directoryFileEntry.EndOfFile += 0x200
writeFileEntry(readerWriter, directoryFileEntry)
@ -305,7 +305,7 @@ func expandDirectory(readerWriter ReaderWriterAt, nextBlockNumber int, buffer []
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)
if err != nil {
return DirectoryHeader{}, nil, err
@ -314,9 +314,9 @@ func getFileEntriesInDirectory(reader io.ReaderAt, blockNumber int, currentPath
directoryHeader := parseDirectoryHeader(buffer, blockNumber)
fileEntries := make([]FileEntry, directoryHeader.ActiveFileCount)
entryOffset := 43 // start at offset after header
activeEntries := 0
entryNumber := 2 // header is essentially the first entry so start at 2
entryOffset := uint16(43) // start at offset after header
activeEntries := uint16(0)
entryNumber := uint8(2) // header is essentially the first entry so start at 2
nextBlock := directoryHeader.NextBlock
@ -338,7 +338,7 @@ func getFileEntriesInDirectory(reader io.ReaderAt, blockNumber int, currentPath
if err != nil {
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)
@ -359,21 +359,21 @@ func getFileEntriesInDirectory(reader io.ReaderAt, blockNumber int, currentPath
}
}
func parseFileEntry(buffer []byte, blockNumber int, entryOffset int) FileEntry {
storageType := int(buffer[0] >> 4)
fileNameLength := int(buffer[0] & 15)
func parseFileEntry(buffer []byte, blockNumber uint16, entryOffset uint16) FileEntry {
storageType := buffer[0] >> 4
fileNameLength := buffer[0] & 15
fileName := string(buffer[1 : fileNameLength+1])
fileType := int(buffer[16])
startingBlock := int(buffer[17]) + int(buffer[18])*256
blocksUsed := int(buffer[19]) + int(buffer[20])*256
endOfFile := int(buffer[21]) + int(buffer[22])*256 + int(buffer[23])*65536
fileType := buffer[16]
startingBlock := uint16(buffer[17]) + uint16(buffer[18])*256
blocksUsed := uint16(buffer[19]) + uint16(buffer[20])*256
endOfFile := uint32(buffer[21]) + uint32(buffer[22])*256 + uint32(buffer[23])*65536
creationTime := DateTimeFromProDOS(buffer[24:28])
version := int(buffer[28])
minVersion := int(buffer[29])
access := int(buffer[30])
auxType := int(buffer[31]) + int(buffer[32])*256
version := buffer[28]
minVersion := buffer[29]
access := buffer[30]
auxType := uint16(buffer[31]) + uint16(buffer[32])*256
modifiedTime := DateTimeFromProDOS((buffer[33:37]))
headerPointer := int(buffer[0x25]) + int(buffer[0x26])*256
headerPointer := uint16(buffer[0x25]) + uint16(buffer[0x26])*256
fileEntry := FileEntry{
StorageType: storageType,
@ -427,24 +427,24 @@ func writeFileEntry(writer io.WriterAt, fileEntry FileEntry) {
buffer[0x26] = byte(fileEntry.HeaderPointer >> 8)
//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 {
}
}
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
volumeName := string(buffer[5 : filenameLength+5])
creationTime := DateTimeFromProDOS(buffer[28:32])
version := int(buffer[32])
minVersion := int(buffer[33])
entryLength := int(buffer[35])
entriesPerBlock := int(buffer[36])
fileCount := int(buffer[37]) + int(buffer[38])*256
bitmapBlock := int(buffer[39]) + int(buffer[40])*256
totalBlocks := int(buffer[41]) + int(buffer[42])*256
version := buffer[32]
minVersion := buffer[33]
entryLength := buffer[35]
entriesPerBlock := buffer[36]
fileCount := uint16(buffer[37]) + uint16(buffer[38])*256
bitmapBlock := uint16(buffer[39]) + uint16(buffer[40])*256
totalBlocks := uint16(buffer[41]) + uint16(buffer[42])*256
if minVersion > 0 {
panic("Unsupported ProDOS version")
@ -465,22 +465,22 @@ func parseVolumeHeader(buffer []byte) VolumeHeader {
return volumeHeader
}
func parseDirectoryHeader(buffer []byte, blockNumber int) DirectoryHeader {
previousBlock := int(buffer[0x00]) + int(buffer[0x01])*256
nextBlock := int(buffer[0x02]) + int(buffer[0x03])*256
func parseDirectoryHeader(buffer []byte, blockNumber uint16) DirectoryHeader {
previousBlock := uint16(buffer[0x00]) + uint16(buffer[0x01])*256
nextBlock := uint16(buffer[0x02]) + uint16(buffer[0x03])*256
isSubDirectory := (buffer[0x04] & 0xF0) == 0xE0
filenameLength := buffer[0x04] & 0x0F
name := string(buffer[0x05 : filenameLength+0x05])
creationTime := DateTimeFromProDOS(buffer[0x1C:0x20])
version := int(buffer[0x20])
minVersion := int(buffer[0x21])
access := int(buffer[0x22])
entryLength := int(buffer[0x23])
entriesPerBlock := int(buffer[0x24])
fileCount := int(buffer[0x25]) + int(buffer[0x26])*256
parentBlock := int(buffer[0x27]) + int(buffer[0x28])*256
parentEntry := int(buffer[0x29])
parentEntryLength := int(buffer[0x2A])
version := buffer[0x20]
minVersion := buffer[0x21]
access := buffer[0x22]
entryLength := buffer[0x23]
entriesPerBlock := buffer[0x24]
fileCount := uint16(buffer[0x25]) + uint16(buffer[0x26])*256
parentBlock := uint16(buffer[0x27]) + uint16(buffer[0x28])*256
parentEntry := uint16(buffer[0x29])
parentEntryLength := buffer[0x2A]
directoryEntry := DirectoryHeader{
PreviousBlock: previousBlock,

View File

@ -29,12 +29,12 @@ func LoadFile(reader io.ReaderAt, path string) ([]byte, error) {
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])
if err != nil {
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]
}
}
@ -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
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)
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
blockList, err := createBlockList(readerWriter, len(buffer))
blockList, err := createBlockList(readerWriter, uint32(len(buffer)))
if err != nil {
return err
}
@ -88,11 +88,11 @@ func WriteFile(readerWriter ReaderWriterAt, path string, fileType int, auxType i
return err
}
fileEntry.FileName = fileName
fileEntry.BlocksUsed = len(blockList)
fileEntry.BlocksUsed = uint16(len(blockList))
fileEntry.CreationTime = createdTime
fileEntry.ModifiedTime = modifiedTime
fileEntry.AuxType = auxType
fileEntry.EndOfFile = len(buffer)
fileEntry.EndOfFile = uint32(len(buffer))
fileEntry.FileType = fileType
fileEntry.KeyPointer = blockList[0]
fileEntry.Version = 0x24
@ -197,24 +197,24 @@ func GetDirectoryAndFileNameFromPath(path string) (string, string) {
return directory, fileName
}
func updateVolumeBitmap(readerWriter ReaderWriterAt, blockList []int) error {
func updateVolumeBitmap(readerWriter ReaderWriterAt, blockList []uint16) error {
volumeBitmap, err := ReadVolumeBitmap(readerWriter)
if err != nil {
fmt.Printf("%s", err)
return err
}
for i := 0; i < len(blockList); i++ {
for i := uint16(0); i < uint16(len(blockList)); i++ {
markBlockInVolumeBitmap(volumeBitmap, blockList[i])
}
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)
}
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
indexBuffer := make([]byte, 512)
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
indexBuffer := make([]byte, 512)
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)
}
func getAllBlockList(reader io.ReaderAt, fileEntry FileEntry) ([]int, error) {
func getAllBlockList(reader io.ReaderAt, fileEntry FileEntry) ([]uint16, error) {
return getBlocklist(reader, fileEntry, false)
}
// Returns all blocks, including index blocks
func getBlocklist(reader io.ReaderAt, fileEntry FileEntry, dataOnly bool) ([]int, error) {
blocks := make([]int, fileEntry.BlocksUsed)
func getBlocklist(reader io.ReaderAt, fileEntry FileEntry, dataOnly bool) ([]uint16, error) {
blocks := make([]uint16, fileEntry.BlocksUsed)
switch fileEntry.StorageType {
case StorageSeedling:
@ -324,10 +324,10 @@ func getBlocklist(reader io.ReaderAt, fileEntry FileEntry, dataOnly bool) ([]int
if err != nil {
return nil, err
}
blockOffset := 1
blockOffset := uint16(1)
blocks[0] = fileEntry.KeyPointer
for i := 0; i < fileEntry.BlocksUsed-1; i++ {
blocks[i+blockOffset] = int(index[i]) + int(index[i+256])*256
for i := uint16(0); i < fileEntry.BlocksUsed-1; i++ {
blocks[i+blockOffset] = uint16(index[i]) + uint16(index[i+256])*256
}
if dataOnly {
return blocks[1:], nil
@ -335,10 +335,10 @@ func getBlocklist(reader io.ReaderAt, fileEntry FileEntry, dataOnly bool) ([]int
return blocks, nil
case StorageTree:
// this is actually too large
dataBlocks := make([]int, fileEntry.BlocksUsed)
dataBlocks := make([]uint16, fileEntry.BlocksUsed)
// this is also actually too large
numberOfIndexBlocks := fileEntry.BlocksUsed/256 + 2
indexBlocks := make([]int, numberOfIndexBlocks)
indexBlocks := make([]uint16, numberOfIndexBlocks)
masterIndex, err := ReadBlock(reader, fileEntry.KeyPointer)
if err != nil {
return nil, err
@ -348,8 +348,8 @@ func getBlocklist(reader io.ReaderAt, fileEntry FileEntry, dataOnly bool) ([]int
indexBlocks[0] = fileEntry.KeyPointer
indexBlockCount := 1
for i := 0; i < 128; i++ {
indexBlock := int(masterIndex[i]) + int(masterIndex[i+256])*256
for i := uint16(0); i < 128; i++ {
indexBlock := uint16(masterIndex[i]) + uint16(masterIndex[i+256])*256
if indexBlock == 0 {
break
}
@ -359,12 +359,12 @@ func getBlocklist(reader io.ReaderAt, fileEntry FileEntry, dataOnly bool) ([]int
if err != nil {
return nil, err
}
for j := 0; j < 256 && i*256+j < fileEntry.BlocksUsed; j++ {
if (int(index[j]) + int(index[j+256])*256) == 0 {
for j := uint16(0); j < 256 && i*256+j < fileEntry.BlocksUsed; j++ {
if (uint16(index[j]) + uint16(index[j+256])*256) == 0 {
break
}
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")
}
func createBlockList(reader io.ReaderAt, fileSize int) ([]int, error) {
numberOfBlocks := fileSize / 512
func createBlockList(reader io.ReaderAt, fileSize uint32) ([]uint16, error) {
numberOfBlocks := uint16(fileSize / 512)
if fileSize%512 > 0 {
numberOfBlocks++

View File

@ -11,8 +11,8 @@ import (
func TestCreateBlocklist(t *testing.T) {
var tests = []struct {
fileSize int
wantBlocks int
fileSize uint32
wantBlocks uint16
}{
{1, 1},
{512, 1},
@ -33,7 +33,7 @@ func TestCreateBlocklist(t *testing.T) {
if err != 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)
}
})
@ -41,7 +41,7 @@ func TestCreateBlocklist(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)
CreateVolume(virtualDisk, "VIRTUAL.DISK", 0xFFFE)

View File

@ -14,7 +14,7 @@ import (
// CreateVolume formats a new ProDOS volume including boot block,
// 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 {
return
}
@ -26,7 +26,7 @@ func CreateVolume(readerWriter ReaderWriterAt, volumeName string, numberOfBlocks
}
blankBlock := make([]byte, 512)
for i := 0; i < numberOfBlocks; i++ {
for i := uint16(0); i < numberOfBlocks; i++ {
WriteBlock(readerWriter, i, blankBlock)
}

View File

@ -13,9 +13,9 @@ import (
func TestCreateVolume(t *testing.T) {
var tests = []struct {
blocks int
blocks uint16
wantVolumeName string
wantFreeBlocks int
wantFreeBlocks uint16
}{
{65535, "MAX", 65513},
{65500, "ALMOST.MAX", 65478},

View File

@ -12,6 +12,8 @@ import (
"fmt"
"os"
"path/filepath"
"regexp"
"strconv"
"strings"
"time"
)
@ -75,8 +77,8 @@ func AddFilesFromHostDirectory(
func WriteFileFromFile(
readerWriter ReaderWriterAt,
pathName string,
fileType int,
auxType int,
fileType uint8,
auxType uint16,
modifiedTime time.Time,
inFileName string,
ignoreDuplicates bool,
@ -117,6 +119,11 @@ func WriteFileFromFile(
case ".SYS", ".TXT", ".BAS", ".BIN":
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)
}
func convertFileByType(inFileName string, inFile []byte) (int, int, []byte, error) {
fileType := 0x06 // default to BIN
auxType := 0x2000 // default to $2000
func convertFileByType(inFileName string, inFile []byte) (uint16, uint8, []byte, error) {
var auxType uint16
var fileType uint8
fileType = 0x06 // default to BIN
auxType = 0x2000 // default to $2000
var err error
@ -166,36 +176,57 @@ func convertFileByType(inFileName string, inFile []byte) (int, int, []byte, erro
// Length
binary.BigEndian.Uint32(inFile[0x2E:]) == 0x00000008 {
fileType = int(binary.BigEndian.Uint16(inFile[0x34:]))
auxType = int(binary.BigEndian.Uint32(inFile[0x36:]))
fileType = uint8(binary.BigEndian.Uint16(inFile[0x34:]))
auxType = uint16(binary.BigEndian.Uint32(inFile[0x36:]))
inFile = inFile[0x3A:]
} else {
// use extension to determine file type
ext := strings.ToUpper(filepath.Ext(inFileName))
switch ext {
case ".BAS":
inFile, err = ConvertTextToBasic(string(inFile))
fileType = 0xFC
auxType = 0x0801
match, err := regexp.MatchString("^\\.(BIN|SYS|TXT|BAS)\\$[0-9]{4}", ext)
if err == nil && match {
parts := strings.Split(ext, "$")
extAuxType, err := strconv.ParseUint(parts[1], 16, 16)
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
auxType = uint16(extAuxType)
switch parts[0] {
case ".BAS":
fileType = 0xFC
case ".SYS":
fileType = 0xFF
case ".BIN":
fileType = 0x06
case ".TXT":
fileType = 0x04
}
} else {
switch ext {
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
}
}
}

View File

@ -25,7 +25,7 @@ func TimeToString(printTime time.Time) string {
}
// FileTypeToString display the file type as a string
func FileTypeToString(fileType int) string {
func FileTypeToString(fileType uint8) string {
switch fileType {
case 1:
return "BAD"
@ -159,7 +159,7 @@ func DumpBlock(buffer []byte) {
}
// 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("NAME TYPE BLOCKS MODIFIED CREATED ENDFILE SUBTYPE\n\n")