Fix for file $xx$xxxx extensions

This commit is contained in:
Terence Boldt
2024-07-18 12:57:18 -04:00
parent c13d1f8930
commit 7819427853
3 changed files with 103 additions and 37 deletions

1
.gitignore vendored
View File

@@ -21,3 +21,4 @@
*.swp
.DS_Store
ProDOS-Utilities
binaries

36
main.go
View File

@@ -17,7 +17,7 @@ import (
"github.com/tjboldt/ProDOS-Utilities/prodos"
)
const version = "0.5.0"
const version = "0.5.1"
func main() {
var fileName string
@@ -32,7 +32,7 @@ func main() {
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(&command, "c", "ls", "Command to execute: ls, create, rm, mkdir, get, getraw, put, putall, putallrecursive, readblock, writeblock")
flag.StringVar(&outFileName, "o", "", "Name of file to write")
flag.StringVar(&inFileName, "i", "", "Name of file to read")
flag.UintVar(&volumeSize, "s", 65535, "Number of blocks to create the volume with (default 65535, 64 to 65535, 0x0040 to 0xFFFF hex input accepted)")
@@ -53,6 +53,8 @@ func main() {
ls(fileName, pathName)
case "get":
get(fileName, pathName, outFileName)
case "getraw":
getRaw(fileName, pathName)
case "put":
put(fileName, pathName, uint8(fileType), uint16(auxType), inFileName)
case "readblock":
@@ -246,6 +248,36 @@ func get(fileName string, pathName string, outFileName string) {
}
}
func getRaw(fileName string, pathName string) {
checkPathName(pathName)
file, err := os.OpenFile(fileName, os.O_RDONLY, 0755)
if err != nil {
fmt.Printf("Failed to open drive image %s:\n %s", fileName, err)
os.Exit(1)
}
defer file.Close()
getFile, err := prodos.LoadFile(file, pathName)
if err != nil {
fmt.Printf("Failed to read file %s: %s\n", pathName, err)
os.Exit(1)
}
fileEntry, err := prodos.GetFileEntry(file, pathName)
if err != nil {
fmt.Printf("Failed to get file entry %s: %s\n", pathName, err)
os.Exit(1)
}
fileType := prodos.FileTypeToString(fileEntry.FileType)
outFileName := fmt.Sprintf("%s.%s$%04X", fileEntry.FileName, fileType, fileEntry.AuxType)
outFile, err := os.Create(outFileName)
if err != nil {
fmt.Printf("Failed to create output file %s: %s\n", outFileName, err)
os.Exit(1)
}
outFile.Write(getFile)
}
func ls(fileName string, pathName string) {
file, err := os.OpenFile(fileName, os.O_RDONLY, 0755)
if err != nil {

View File

@@ -118,11 +118,11 @@ func WriteFileFromFile(
ext := filepath.Ext(pathName)
if len(ext) > 0 {
switch ext {
switch strings.ToUpper(ext) {
case ".SYS", ".TXT", ".BAS", ".BIN":
pathName = strings.TrimSuffix(pathName, ext)
}
match, err := regexp.MatchString("^\\.(BIN|SYS|TXT|BAS)\\$[0-9]{4}", ext)
match, err := regexp.MatchString("^\\.(BIN|SYS|TXT|BAS|bin|sys|txt|bas|\\$[0-9,A-F,a-f]{2})\\$[0-9,A-F,a-f]{4}", ext)
if err == nil && match {
pathName = strings.TrimSuffix(pathName, ext)
@@ -160,24 +160,7 @@ func convertFileByType(inFileName string, inFile []byte) (uint16, uint8, []byte,
var err error
// Check for an AppleSingle file as produced by cc65
if // Magic number
binary.BigEndian.Uint32(inFile[0x00:]) == 0x00051600 &&
// Version number
binary.BigEndian.Uint32(inFile[0x04:]) == 0x00020000 &&
// Number of entries
binary.BigEndian.Uint16(inFile[0x18:]) == 0x0002 &&
// Data Fork ID
binary.BigEndian.Uint32(inFile[0x1A:]) == 0x00000001 &&
// Offset
binary.BigEndian.Uint32(inFile[0x1E:]) == 0x0000003A &&
// Length
binary.BigEndian.Uint32(inFile[0x22:]) == uint32(len(inFile))-0x3A &&
// ProDOS File Info ID
binary.BigEndian.Uint32(inFile[0x26:]) == 0x0000000B &&
// Offset
binary.BigEndian.Uint32(inFile[0x2A:]) == 0x00000032 &&
// Length
binary.BigEndian.Uint32(inFile[0x2E:]) == 0x00000008 {
if isAppleSingleMagicNumber(inFile) {
fileType = uint8(binary.BigEndian.Uint16(inFile[0x34:]))
auxType = uint16(binary.BigEndian.Uint32(inFile[0x36:]))
@@ -186,27 +169,15 @@ func convertFileByType(inFileName string, inFile []byte) (uint16, uint8, []byte,
// use extension to determine file type
ext := strings.ToUpper(filepath.Ext(inFileName))
match, err := regexp.MatchString("^\\.(BIN|SYS|TXT|BAS)\\$[0-9]{4}", ext)
match, err := regexp.MatchString("^\\.(BIN|SYS|TXT|BAS|bin|sys|txt|bas|\\$[0-9,A-F,a-f]{2})\\$[0-9,A-F,a-f]{4}", ext)
if err == nil && match {
parts := strings.Split(ext, "$")
extAuxType, err := strconv.ParseUint(parts[1], 16, 16)
auxType, fileType, err = parseRawFile(ext)
if err != nil {
return 0, 0, nil, err
}
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 {
switch strings.ToUpper(ext) {
case ".BAS":
inFile, err = ConvertTextToBasic(string(inFile))
fileType = 0xFC
@@ -229,9 +200,71 @@ func convertFileByType(inFileName string, inFile []byte) (uint16, uint8, []byte,
inFile = ConvertImageToHiResMonochrome(inFile)
fileType = 0x06
auxType = 0x2000
default:
fileType = 0x06
auxType = 0x0000
}
}
}
return auxType, fileType, inFile, err
}
func parseRawFile(ext string) (uint16, uint8, error) {
parts := strings.Split(ext, "$")
extAuxType, err := strconv.ParseUint(parts[1], 16, 16)
if err != nil {
return 0, 0, err
}
auxType := uint16(extAuxType)
fileType := uint8(0x06)
switch strings.ToUpper(parts[0]) {
case ".BAS":
fileType = 0xFC
case ".SYS":
fileType = 0xFF
case ".BIN":
fileType = 0x06
case ".TXT":
fileType = 0x04
default:
// we can assume parts[0] is empty and parts splitting on $
longFileType, err := strconv.ParseUint(parts[1][:2], 16, 8)
if err == nil {
fileType = uint8(longFileType)
}
// and we need to reparse aux type as it's in part 2 instead of 1
extAuxType, err := strconv.ParseUint(parts[2], 16, 16)
if err != nil {
return 0, 0, err
}
auxType = uint16(extAuxType)
}
return auxType, fileType, nil
}
func isAppleSingleMagicNumber(inFile []byte) bool {
if binary.BigEndian.Uint32(inFile[0x00:]) == 0x00051600 &&
// Version number
binary.BigEndian.Uint32(inFile[0x04:]) == 0x00020000 &&
// Number of entries
binary.BigEndian.Uint16(inFile[0x18:]) == 0x0002 &&
// Data Fork ID
binary.BigEndian.Uint32(inFile[0x1A:]) == 0x00000001 &&
// Offset
binary.BigEndian.Uint32(inFile[0x1E:]) == 0x0000003A &&
// Length
binary.BigEndian.Uint32(inFile[0x22:]) == uint32(len(inFile))-0x3A &&
// ProDOS File Info ID
binary.BigEndian.Uint32(inFile[0x26:]) == 0x0000000B &&
// Offset
binary.BigEndian.Uint32(inFile[0x2A:]) == 0x00000032 &&
// Length
binary.BigEndian.Uint32(inFile[0x2E:]) == 0x00000008 {
return true
}
return false
}