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 //}