go-fds/reader.go

217 lines
4.5 KiB
Go

package fds
import (
//"os"
"fmt"
"io"
"bufio"
"bytes"
"encoding/binary"
"github.com/sigurn/crc16"
)
func ReadRom(r io.Reader, IsFds bool) (*Rom, error) {
reader := bufio.NewReader(r)
magic, err := reader.Peek(4)
if err != nil {
return nil, fmt.Errorf("Unable to peek header: %w", err)
}
rom := &Rom{Header: &FdsHeader{}}
// "FDS" + EOF. header may be omitted.
if bytes.Equal(magic, FdsHeaderMagic) {
err = binary.Read(reader, binary.LittleEndian, rom.Header)
if err != nil {
return nil, fmt.Errorf("Error reading header: %w", err)
}
}
rom.Blocks, err = ReadBlocks(reader, IsFds)
return rom, err
}
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
//}