214 lines
4.4 KiB
Go
214 lines
4.4 KiB
Go
package fds
|
|
|
|
import (
|
|
//"os"
|
|
"fmt"
|
|
"io"
|
|
"bufio"
|
|
"bytes"
|
|
"encoding/binary"
|
|
|
|
"github.com/sigurn/crc16"
|
|
)
|
|
|
|
func ReadRom(r io.Reader, IsFds bool) ([]DiskBlock, error) {
|
|
reader := bufio.NewReader(r)
|
|
magic, err := reader.Peek(4)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("Unable to peek header: %w", err)
|
|
}
|
|
|
|
// "FDS" + EOF. header may be omitted.
|
|
if bytes.Equal(magic, FdsHeaderMagic) {
|
|
_, err = reader.Discard(binary.Size(&FdsHeader{}))
|
|
if err != nil {
|
|
return nil, fmt.Errorf("Error reading header: %w", err)
|
|
}
|
|
}
|
|
|
|
return ReadBlocks(reader, IsFds)
|
|
}
|
|
|
|
func ReadBlocks(r io.Reader, IsFds bool) ([]DiskBlock, error) {
|
|
blocks := []DiskBlock{}
|
|
dataSize := -1
|
|
readBytes := 0
|
|
|
|
reader := bufio.NewReader(r)
|
|
|
|
for {
|
|
raw, err := reader.Peek(1)
|
|
if err != nil {
|
|
if err == io.EOF {
|
|
break
|
|
}
|
|
|
|
return blocks, fmt.Errorf("error peeking block type: %w", err)
|
|
}
|
|
|
|
var readLen int
|
|
var block DiskBlock
|
|
idByte := raw[0]
|
|
|
|
switch idByte {
|
|
case 0x01:
|
|
block = &BlockInfo{}
|
|
case 0x02:
|
|
block = &BlockFileAmount{}
|
|
case 0x03:
|
|
block = &BlockFileHeader{}
|
|
case 0x04:
|
|
block = &BlockFileData{}
|
|
|
|
// variable length
|
|
readLen = dataSize+3
|
|
|
|
case 0x00:
|
|
reader.Discard(1)
|
|
continue
|
|
|
|
default:
|
|
fmt.Printf("readBytes: %d ($%04X)\n", readBytes, readBytes)
|
|
return blocks, fmt.Errorf("Invalid block type: $%02X", idByte)
|
|
}
|
|
//fmt.Println("")
|
|
|
|
if idByte != 0x04 {
|
|
readLen = binary.Size(block)
|
|
}
|
|
|
|
//fmt.Println("readLen:;", readLen)
|
|
// FDS doesn't have the two byte CRC in the data
|
|
if IsFds {
|
|
readLen -=2
|
|
}
|
|
|
|
//fmt.Println("readLen::", readLen)
|
|
buf := make([]byte, readLen)
|
|
n, err := io.ReadFull(reader, buf)
|
|
if err != nil {
|
|
return blocks, fmt.Errorf("Error reading block id 0x%02X: %w", idByte, err)
|
|
}
|
|
readBytes += n
|
|
|
|
//var sum uint16
|
|
if IsFds {
|
|
//sum = crc16.Checksum(buf, crc16.MakeTable(crc16.CRC16_KERMIT))
|
|
//fmt.Printf("checksum: %04X\n", sum)
|
|
buf = append(buf, []byte{0x00, 0x00}...)
|
|
}
|
|
|
|
//fmt.Printf("idByte:$%02X\nreadLen:%d\nlen(buf):%d\nblocksize:%d\n", idByte, readLen, len(buf), binary.Size(block))
|
|
|
|
if idByte != 0x04 {
|
|
_, err = binary.Decode(buf, binary.LittleEndian, block)
|
|
if err != nil {
|
|
return blocks, fmt.Errorf("Error decoding block id 0x%02X: %w", idByte, err)
|
|
}
|
|
|
|
if idByte == 0x03 {
|
|
fh := block.(*BlockFileHeader)
|
|
dataSize = int(fh.FileSize)
|
|
} else {
|
|
dataSize = -1
|
|
}
|
|
|
|
} else {
|
|
db := block.(*BlockFileData)
|
|
db.BlockCode = buf[0]
|
|
|
|
if !IsFds {
|
|
db.CRC = uint16(buf[len(buf)-2]) | (uint16(buf[len(buf)-2])<<8)
|
|
readLen -= 2
|
|
|
|
} else {
|
|
db.CRC = crc16.Checksum(buf[:len(buf)-2], crc16.MakeTable(crc16.CRC16_KERMIT))
|
|
}
|
|
|
|
db.Data = buf[1:readLen]
|
|
//fmt.Println("len(db.Data)", len(db.Data))
|
|
block = db
|
|
//fmt.Printf("Block:%#v\n", block)
|
|
}
|
|
|
|
blocks = append(blocks, block)
|
|
}
|
|
|
|
return blocks, nil
|
|
}
|
|
|
|
//func ReadBlocksFds(r io.Reader) ([]FdsBlock, error) {
|
|
// reader := bufio.NewReader(r)
|
|
//
|
|
// var dataSize int
|
|
// blocks := []FdsBlock{}
|
|
// for {
|
|
// typ, err := reader.Peek(1)
|
|
// if err != nil {
|
|
// if err == io.EOF {
|
|
// break
|
|
// } else {
|
|
// return nil, err
|
|
// }
|
|
// }
|
|
//
|
|
// if len(typ) != 1 {
|
|
// return nil, fmt.Errorf("typ read length error")
|
|
// }
|
|
// //fmt.Printf("typ: %v\n", typ)
|
|
//
|
|
// if typ[0] == 0x00 {
|
|
// //fmt.Println("00 'block'")
|
|
// break
|
|
// }
|
|
//
|
|
// var block FdsBlock
|
|
// switch BlockType(typ[0]) {
|
|
// case BlockInfo:
|
|
// block = &FdsBlockInfo{}
|
|
// case BlockFileAmount:
|
|
// block = &FdsFileAmount{}
|
|
// case BlockFileHeader:
|
|
// block = &FdsFileHeader{}
|
|
// case BlockFileData:
|
|
// block = &FdsFileData{}
|
|
// default:
|
|
// return nil, fmt.Errorf("invalid block type: %02X", typ[0])
|
|
// }
|
|
//
|
|
// if block.Type() != BlockFileData {
|
|
// err = binary.Read(reader, binary.LittleEndian, block)
|
|
// if err != nil {
|
|
// return nil, fmt.Errorf("decode error: %w", err)
|
|
// }
|
|
// } else {
|
|
// fb := block.(*FdsFileData)
|
|
// fb.BlockCode = byte(BlockFileData)
|
|
// reader.Discard(1)
|
|
//
|
|
// if dataSize == 0 {
|
|
// return nil, fmt.Errorf("FileData without size")
|
|
// }
|
|
// fmt.Println("dataSize:", dataSize)
|
|
//
|
|
// fb.Data = make([]byte, dataSize)
|
|
// _, err = reader.Read(fb.Data)
|
|
// if err != nil {
|
|
// return nil, fmt.Errorf("data read err: %w", err)
|
|
// }
|
|
// dataSize = 0
|
|
// }
|
|
//
|
|
// switch block.Type() {
|
|
// case BlockFileHeader:
|
|
// bh := block.(*FdsFileHeader)
|
|
// dataSize = int(bh.FileSize)
|
|
// }
|
|
//
|
|
// fmt.Println(block)
|
|
// blocks = append(blocks, block)
|
|
// }
|
|
//
|
|
// return blocks, nil
|
|
//}
|