more lints, removed woz

This commit is contained in:
Zellyn Hunter 2021-07-31 23:49:22 -04:00
parent 23c9b1edcf
commit c2dd6362de
22 changed files with 74 additions and 389 deletions

View File

@ -1,3 +1,5 @@
issues:
exclude-use-default: false
linters:
enable:
- gocritic

View File

@ -11,10 +11,12 @@ import (
"github.com/zellyn/diskii/types"
)
// ApplesoftCmd is the kong `applesoft` command.
type ApplesoftCmd struct {
Decode DecodeCmd `kong:"cmd,help='Convert a binary Applesoft program to a text LISTing.'"`
}
// DecodeCmd is the kong `decode` command.
type DecodeCmd struct {
Filename string `kong:"arg,default='-',type='existingfile',help='Binary Applesoft file to read, or “-” for stdin.'"`
@ -22,12 +24,14 @@ type DecodeCmd struct {
Raw bool `kong:"short='r',help='Print raw control codes (no escaping)'"`
}
// Help displays extended help and examples.
func (d DecodeCmd) Help() string {
return `Examples:
# Dump the contents of HELLO and then decode it.
diskii dump dos33master.dsk HELLO | diskii applesoft decode -`
}
// Run the decode command.
func (d *DecodeCmd) Run(globals *types.Globals) error {
contents, err := helpers.FileContentsOrStdIn(d.Filename)
if err != nil {
@ -38,9 +42,9 @@ func (d *DecodeCmd) Run(globals *types.Globals) error {
return err
}
if d.Raw {
os.Stdout.WriteString(listing.String())
_, _ = os.Stdout.WriteString(listing.String())
} else {
os.Stdout.WriteString(basic.ChevronControlCodes(listing.String()))
_, _ = os.Stdout.WriteString(basic.ChevronControlCodes(listing.String()))
}
return nil
}

View File

@ -10,6 +10,7 @@ import (
"github.com/zellyn/diskii/types"
)
// LsCmd is the kong `ls` command.
type LsCmd struct {
Order types.DiskOrder `kong:"default='auto',enum='auto,do,po',help='Logical-to-physical sector order.'"`
System string `kong:"default='auto',enum='auto,dos3,prodos,nakedos',help='DOS system used for image.'"`
@ -19,6 +20,7 @@ type LsCmd struct {
Directory string `kong:"arg,optional,help='Directory to list (ProDOS only).'"`
}
// Help displays extended help and examples.
func (l LsCmd) Help() string {
return `Examples:
# Simple ls of a disk image
@ -27,6 +29,7 @@ func (l LsCmd) Help() string {
diskii ls --order do --system nakedos Super-Mon-2.0.dsk`
}
// Run the `ls` command.
func (l *LsCmd) Run(globals *types.Globals) error {
op, order, err := disk.OpenFile(l.Image, l.Order, l.System, globals.DiskOperatorFactories, globals.Debug)
if err != nil {

View File

@ -9,6 +9,7 @@ import (
"github.com/zellyn/diskii/types"
)
// DeleteCmd is the kong `delete` command.
type DeleteCmd struct {
Order types.DiskOrder `kong:"default='auto',enum='auto,do,po',help='Logical-to-physical sector order.'"`
System string `kong:"default='auto',enum='auto,dos3',help='DOS system used for image.'"`
@ -18,12 +19,14 @@ type DeleteCmd struct {
Filename string `kong:"arg,required,help='Filename to use on disk.'"`
}
// Help displays extended help and examples.
func (d DeleteCmd) Help() string {
return `Examples:
# Delete file GREMLINS on disk image games.dsk.
diskii rm games.dsk GREMLINS`
}
// Run the `delete` command.
func (d *DeleteCmd) Run(globals *types.Globals) error {
op, order, err := disk.OpenFilename(d.DiskImage, d.Order, d.System, globals.DiskOperatorFactories, globals.Debug)
if err != nil {

2
cmd/doc.go Normal file
View File

@ -0,0 +1,2 @@
// Package cmd contains the actual command implementations.
package cmd

View File

@ -9,6 +9,7 @@ import (
"github.com/zellyn/diskii/types"
)
// DumpCmd is the kong `dump` command.
type DumpCmd struct {
Order types.DiskOrder `kong:"default='auto',enum='auto,do,po',help='Logical-to-physical sector order.'"`
System string `kong:"default='auto',enum='auto,dos3',help='DOS system used for image.'"`
@ -17,12 +18,14 @@ type DumpCmd struct {
Filename string `kong:"arg,required,help='Filename to use on disk.'"`
}
// Help displays extended help and examples.
func (d DumpCmd) Help() string {
return `Examples:
# Dump file GREMLINS on disk image games.dsk.
diskii dump games.dsk GREMLINS`
}
// Run the `dump` command.
func (d *DumpCmd) Run(globals *types.Globals) error {
op, _, err := disk.OpenFilename(d.DiskImage, d.Order, d.System, globals.DiskOperatorFactories, globals.Debug)
if err != nil {

View File

@ -10,10 +10,12 @@ import (
"github.com/zellyn/diskii/types"
)
// FiletypesCmd is the kong `filetypes` command.
type FiletypesCmd struct {
All bool `kong:"help='Display all types, including SOS types and reserved ranges.'"`
}
// Run the `filetypes` command.
func (f *FiletypesCmd) Run(globals *types.Globals) error {
w := tabwriter.NewWriter(os.Stdout, 0, 0, 1, ' ', 0)
fmt.Fprintln(w, "Description\tName\tThree-letter Name\tOne-letter Name")
@ -21,6 +23,6 @@ func (f *FiletypesCmd) Run(globals *types.Globals) error {
for _, typ := range types.FiletypeInfos(f.All) {
fmt.Fprintf(w, "%s\t%s\t%s\t%s\n", typ.Desc, typ.Name, typ.ThreeLetter, typ.OneLetter)
}
w.Flush()
_ = w.Flush()
return nil
}

View File

@ -12,6 +12,7 @@ import (
const helloName = "FHELLO" // filename to use (if Super-Mon)
// NakedOSCmd is the kong `nakedos` sub-command.
type NakedOSCmd struct {
Mkhello MkHelloCmd `kong:"cmd,help='Create an FHELLO program that loads and runs another file.'"`
}
@ -23,6 +24,7 @@ func (n NakedOSCmd) Help() string {
Presentation: https://www.kansasfest.org/2012/08/2010-haye-nakedos/`
}
// MkHelloCmd is the kong `mkhello` command.
type MkHelloCmd struct {
Order types.DiskOrder `kong:"default='auto',enum='auto,do,po',help='Logical-to-physical sector order.'"`
@ -33,6 +35,7 @@ type MkHelloCmd struct {
Start uint16 `kong:"type='anybaseuint16',default='0xFFFF',help='Address to jump to. Defaults to 0xFFFF, which means “same as address flag”'"`
}
// Help displays extended help and examples.
func (m MkHelloCmd) Help() string {
return `This command creates a very short DF01:FHELLO program that simply loads another program of your choice.
@ -44,6 +47,7 @@ Examples:
mkhello test.dsk --address 0x2000 --start 0x2100 DF06`
}
// Run the `mkhello` command.
func (m *MkHelloCmd) Run(globals *types.Globals) error {
if m.Start == 0xFFFF {
m.Start = m.Address

View File

@ -10,6 +10,7 @@ import (
"github.com/zellyn/diskii/types"
)
// PutCmd is the kong `put` command.
type PutCmd struct {
Order types.DiskOrder `kong:"default='auto',enum='auto,do,po',help='Logical-to-physical sector order.'"`
System string `kong:"default='auto',enum='auto,dos3',help='DOS system used for image.'"`
@ -21,12 +22,14 @@ type PutCmd struct {
SourceFilename string `kong:"arg,required,type='existingfile',help='Name of file containing data to put.'"`
}
// Help displays extended help and examples.
func (p PutCmd) Help() string {
return `Examples:
# Put file gremlins.o onto disk image games.dsk, using the filename GREMLINS.
diskii put games.dsk GREMLINS gremlins.o`
}
// Run the `put` command.
func (p *PutCmd) Run(globals *types.Globals) error {
if p.DiskImage == "-" {
if p.SourceFilename == "-" {

View File

@ -8,6 +8,7 @@ import (
"github.com/zellyn/diskii/types"
)
// ReorderCmd is the kong `reorder` command.
type ReorderCmd struct {
Order types.DiskOrder `kong:"default='auto',enum='auto,do,po',help='Logical-to-physical sector order.'"`
NewOrder types.DiskOrder `kong:"default='auto',enum='auto,do,po',help='New Logical-to-physical sector order.'"`
@ -17,6 +18,7 @@ type ReorderCmd struct {
NewDiskImage string `kong:"arg,optional,type='path',help='Disk image to write, if different.'"`
}
// Run the `reorder` command.
func (r *ReorderCmd) Run(globals *types.Globals) error {
fromOrderName, toOrderName, err := getOrders(r.DiskImage, r.Order, r.NewDiskImage, r.NewOrder)
if err != nil {

View File

@ -12,6 +12,7 @@ import (
"github.com/zellyn/diskii/types"
)
// SDCmd is the kong `mksd` command.
type SDCmd struct {
Order types.DiskOrder `kong:"default='auto',enum='auto,do,po',help='Logical-to-physical sector order.'"`
@ -22,6 +23,7 @@ type SDCmd struct {
Start uint16 `kong:"type='anybaseuint16',default='0xFFFF',help='Address to jump to. Defaults to 0xFFFF, which means “same as address flag”'"`
}
// Help displays extended help and examples.
func (s SDCmd) Help() string {
return `
See https://github.com/peterferrie/standard-delivery for details.
@ -34,6 +36,7 @@ Examples:
diskii mksd test.dsk foo.o --address 0x2000 --start 0x2100`
}
// Run the `mksd` command.
func (s *SDCmd) Run(globals *types.Globals) error {
if s.Start == 0xFFFF {
s.Start = s.Address

View File

@ -1,3 +1,4 @@
// Package data is a bunch of go:embed embedded files.
package data
import _ "embed"

View File

@ -1,73 +0,0 @@
// Copyright © 2017 Zellyn Hunter <zellyn@gmail.com>
// dev.go contains logic for reading ".po" disk images.
package disk
import (
"fmt"
"io"
"io/ioutil"
)
// A ProDOS block.
type Block [512]byte
// Dev represents a .po disk image.
type Dev struct {
data []byte // The actual data in the file
blocks uint16 // Number of blocks
}
// LoadDev loads a .po image from a file.
func LoadDev(filename string) (Dev, error) {
bb, err := ioutil.ReadFile(filename)
if err != nil {
return Dev{}, err
}
if len(bb)%512 != 0 {
return Dev{}, fmt.Errorf("expected file %q to contain a multiple of 512 bytes, but got %d", filename, len(bb))
}
return Dev{
data: bb,
blocks: uint16(len(bb) / 512),
}, nil
}
// Empty creates a .po image that is all zeros.
func EmptyDev(blocks uint16) Dev {
return Dev{
data: make([]byte, 512*int(blocks)),
blocks: blocks,
}
}
// ReadBlock reads a single block from the device. It always returns
// 512 byes.
func (d Dev) ReadBlock(index uint16) (Block, error) {
var b Block
copy(b[:], d.data[int(index)*512:int(index+1)*512])
return b, nil
}
// WriteBlock writes a single block to a device. It expects exactly
// 512 bytes.
func (d Dev) WriteBlock(index uint16, data Block) error {
copy(d.data[int(index)*512:int(index+1)*512], data[:])
return nil
}
// Blocks returns the number of blocks in the device.
func (d Dev) Blocks() uint16 {
return d.blocks
}
// Order returns the order of blocks on the device.
func (d Dev) Order() string {
return "prodos"
}
// Write writes the device contents to the given file.
func (d Dev) Write(w io.Writer) (n int, err error) {
return w.Write(d.data)
}

View File

@ -65,3 +65,6 @@ type TrackSector struct {
Track byte
Sector byte
}
// Block is a ProDOS block: 512 bytes.
type Block [512]byte

View File

@ -5,6 +5,7 @@ import (
"io"
"os"
"path"
"path/filepath"
"strings"
"github.com/zellyn/diskii/helpers"
@ -16,15 +17,15 @@ func OpenFilename(filename string, order types.DiskOrder, system string, operato
if filename == "-" {
return OpenFile(os.Stdin, order, system, operatorFactories, debug)
}
file, err := os.Open(filename)
file, err := os.Open(filepath.Clean(filename))
if err != nil {
return nil, "", err
}
return OpenFile(file, order, system, operatorFactories, debug)
}
// OpenImage attempts to open a disk or device image, using the provided ordering and system type.
// OpenImage will close the file.
// OpenFile attempts to open a disk or device image, using the provided ordering and system type.
// OpenFile will close the file.
func OpenFile(file *os.File, order types.DiskOrder, system string, operatorFactories []types.OperatorFactory, debug bool) (types.Operator, types.DiskOrder, error) {
bb, err := io.ReadAll(file)
if err != nil {
@ -173,17 +174,6 @@ func Swizzle(diskimage []byte, order []int) ([]byte, error) {
return result, nil
}
func UnSwizzle(diskimage []byte, order []int) ([]byte, error) {
if err := validateOrder(order); err != nil {
return nil, fmt.Errorf("called UnSwizzle with weird order: %w", err)
}
reverseOrder := make([]int, FloppySectors)
for index, mapping := range order {
reverseOrder[mapping] = index
}
return Swizzle(diskimage, reverseOrder)
}
// validateOrder validates that an order mapping is valid, and maps [0,15] onto
// [0,15] without repeats.
func validateOrder(order []int) error {

View File

@ -21,6 +21,7 @@ func FileContentsOrStdIn(s string) ([]byte, error) {
return os.ReadFile(s)
}
// WriteOutput writes a byte slice to the given filename, using `-` for standard out.
func WriteOutput(filename string, contents []byte, force bool) error {
if filename == "-" {
_, err := os.Stdout.Write(contents)

View File

@ -60,8 +60,10 @@ func (bp bitmapPart) ToBlock() (disk.Block, error) {
return bp.data, nil
}
// VolumeBitMap represents a volume bitmap.
type VolumeBitMap []bitmapPart
// NewVolumeBitMap returns a volume bitmap of the given size.
func NewVolumeBitMap(startBlock uint16, blocks uint16) VolumeBitMap {
vbm := VolumeBitMap(make([]bitmapPart, (blocks+(512*8)-1)/(512*8)))
for i := range vbm {
@ -73,10 +75,12 @@ func NewVolumeBitMap(startBlock uint16, blocks uint16) VolumeBitMap {
return vbm
}
// MarkUsed marks the given block as used.
func (vbm VolumeBitMap) MarkUsed(block uint16) {
vbm.mark(block, false)
}
// MarkUnused marks the given block as free.
func (vbm VolumeBitMap) MarkUnused(block uint16) {
vbm.mark(block, true)
}
@ -261,6 +265,7 @@ func (vdb VolumeDirectoryBlock) Validate() (errors []error) {
return errors
}
// VolumeDirectoryHeader represents a volume directory header.
type VolumeDirectoryHeader struct {
TypeAndNameLength byte // Storage type (top four bits) and volume name length (lower four).
VolumeName [15]byte // Volume name (actual length defined in TypeAndNameLength)
@ -319,14 +324,20 @@ func (vdh VolumeDirectoryHeader) Validate() (errors []error) {
return errors
}
// Access represents a level of file access.
type Access byte
const (
AccessReadable Access = 0x01
AccessWritable Access = 0x02
// AccessReadable denotes a file as readable.
AccessReadable Access = 0x01
// AccessWritable denotes a file as writable.
AccessWritable Access = 0x02
// AccessChangedSinceBackup is (I think) always true on real disks.
AccessChangedSinceBackup Access = 0x20
AccessRenamable Access = 0x40
AccessDestroyable Access = 0x80
// AccessRenamable denotes a file as renamable.
AccessRenamable Access = 0x40
// AccessDestroyable denotes a file as deletable.
AccessDestroyable Access = 0x80
)
// FileDescriptor is the entry in the volume directory for a file or
@ -420,7 +431,7 @@ func (fd FileDescriptor) Validate() (errors []error) {
return errors
}
// An index block contains 256 16-bit block numbers, pointing to other
// IndexBlock is an index block, containing 256 16-bit block numbers, pointing to other
// blocks. The LSBs are stored in the first half, MSBs in the second.
type IndexBlock disk.Block
@ -537,6 +548,7 @@ func (sb SubdirectoryBlock) Validate() (errors []error) {
return errors
}
// SubdirectoryHeader represents a subdirectory header.
type SubdirectoryHeader struct {
TypeAndNameLength byte // Storage type (top four bits) and subdirectory name length (lower four).
SubdirectoryName [15]byte // Subdirectory name (actual length defined in TypeAndNameLength)

View File

@ -4,6 +4,7 @@ package supermon
import (
"os"
"path/filepath"
"reflect"
"strings"
"testing"
@ -48,7 +49,7 @@ func loadSectorMap(filename string) (SectorMap, []byte, error) {
// getOperator gets a types.Operator for the given NakedOS disk, assumed to be
// in "do" order.
func getOperator(filename string) (types.Operator, error) {
f, err := os.Open(filename)
f, err := os.Open(filepath.Clean(filename))
if err != nil {
return nil, err
}

View File

@ -17,13 +17,19 @@ type Descriptor struct {
Type Filetype
}
// DiskOrder specifies the logical disk ordering.
type DiskOrder string
const (
DiskOrderDO = DiskOrder("do")
DiskOrderPO = DiskOrder("po")
DiskOrderRaw = DiskOrder("raw")
DiskOrderAuto = DiskOrder("auto")
// DiskOrderDO is the DOS 3.3 logical ordering.
DiskOrderDO = DiskOrder("do")
// DiskOrderPO is the ProDOS logical ordering.
DiskOrderPO = DiskOrder("po")
// DiskOrderRaw is the logical ordering that doesn't change anything.
DiskOrderRaw = DiskOrder("raw")
// DiskOrderAuto is the logical ordering that tells diskii to guess.
DiskOrderAuto = DiskOrder("auto")
// DiskOrderUnknown is usually an error condition, or a signal that guessing failed.
DiskOrderUnknown = DiskOrder("")
)

View File

@ -1,3 +1,5 @@
// Package types holds various types that are needed all over the place. They're
// in their own package to avoid circular dependencies.
package types
// Globals holds flags and configuration that are shared globally.

View File

@ -1,268 +0,0 @@
package woz
import (
"encoding/binary"
"fmt"
"hash"
"hash/crc32"
"io"
"strings"
)
const wozHeader = "WOZ1\xFF\n\r\n"
const TrackLength = 6656
type Woz struct {
Info Info
Unknowns []UnknownChunk
TMap [160]uint8
TRKS []TRK
Metadata Metadata
}
type UnknownChunk struct {
ID string
Data []byte
}
type DiskType uint8
const (
DiskType525 DiskType = 1
DiskType35 DiskType = 2
)
type Info struct {
Version uint8
DiskType DiskType
WriteProtected bool
Synchronized bool
Cleaned bool
Creator string
}
type TRK struct {
BitStream [6646]uint8
BytesUsed uint16
BitCount uint16
SplicePoint uint16
SpliceNibble uint8
SpliceBitCount uint8
Reserved uint16
}
type Metadata struct {
Keys []string
RawValues map[string]string
}
type decoder struct {
r io.Reader
woz *Woz
crc hash.Hash32
tmp [3 * 256]byte
crcVal uint32
}
// A FormatError reports that the input is not a valid woz file.
type FormatError string
func (e FormatError) Error() string { return "woz: invalid format: " + string(e) }
type CRCError struct {
Declared uint32
Computed uint32
}
func (e CRCError) Error() string {
return fmt.Sprintf("woz: failed checksum: declared=%d; computed=%d", e.Declared, e.Computed)
}
func (d *decoder) info(format string, args ...interface{}) {
if !strings.HasSuffix(format, "\n") {
format += "\n"
}
fmt.Printf("INFO: "+format, args...)
}
func (d *decoder) warn(format string, args ...interface{}) {
if !strings.HasSuffix(format, "\n") {
format += "\n"
}
fmt.Printf("WARN: "+format, args...)
}
func (d *decoder) checkHeader() error {
_, err := io.ReadFull(d.r, d.tmp[:len(wozHeader)])
if err != nil {
return err
}
if string(d.tmp[:len(wozHeader)]) != wozHeader {
return FormatError("not a woz file")
}
return binary.Read(d.r, binary.LittleEndian, &d.crcVal)
}
func (d *decoder) parseChunk() (done bool, err error) {
// Read the chunk type and length
n, err := io.ReadFull(d.r, d.tmp[:8])
if err != nil {
if n == 0 && err == io.EOF {
return true, nil
}
return false, err
}
length := binary.LittleEndian.Uint32(d.tmp[4:8])
d.crc.Write(d.tmp[:8])
switch string(d.tmp[:4]) {
case "INFO":
return false, d.parseINFO(length)
case "TMAP":
return false, d.parseTMAP(length)
case "TRKS":
return false, d.parseTRKS(length)
case "META":
return false, d.parseMETA(length)
default:
return false, d.parseUnknown(string(d.tmp[:4]), length)
}
}
func (d *decoder) parseINFO(length uint32) error {
d.info("INFO chunk!\n")
if length != 60 {
d.warn("expected INFO chunk length of 60; got %d", length)
}
if _, err := io.ReadFull(d.r, d.tmp[:length]); err != nil {
return err
}
d.crc.Write(d.tmp[:length])
d.woz.Info.Version = d.tmp[0]
d.woz.Info.DiskType = DiskType(d.tmp[1])
d.woz.Info.WriteProtected = d.tmp[2] == 1
d.woz.Info.Synchronized = d.tmp[3] == 1
d.woz.Info.Cleaned = d.tmp[4] == 1
d.woz.Info.Creator = strings.TrimRight(string(d.tmp[5:37]), " ")
return nil
}
func (d *decoder) parseTMAP(length uint32) error {
d.info("TMAP chunk!\n")
if length != 160 {
d.warn("expected TMAP chunk length of 160; got %d", length)
}
if _, err := io.ReadFull(d.r, d.woz.TMap[:]); err != nil {
return err
}
d.crc.Write(d.woz.TMap[:])
return nil
}
func (d *decoder) parseTRKS(length uint32) error {
d.info("TRKS chunk!\n")
if length%TrackLength != 0 {
return FormatError(fmt.Sprintf("expected TRKS chunk length to be a multiple of %d; got %d", TrackLength, length))
}
buf := make([]byte, length)
if _, err := io.ReadFull(d.r, buf); err != nil {
return err
}
d.crc.Write(buf)
for offset := 0; offset < int(length); offset += TrackLength {
b := buf[offset : offset+TrackLength]
t := TRK{
BytesUsed: binary.LittleEndian.Uint16(b[6646:6648]),
BitCount: binary.LittleEndian.Uint16(b[6648:6650]),
SplicePoint: binary.LittleEndian.Uint16(b[6650:6652]),
SpliceNibble: b[6652],
SpliceBitCount: b[6653],
Reserved: binary.LittleEndian.Uint16(b[6654:6656]),
}
copy(t.BitStream[:], b)
d.woz.TRKS = append(d.woz.TRKS, t)
}
// type TRK struct {
// Bitstream [6646]uint8
// BytesUsed uint16
// BitCount uint16
// SplicePoint uint16
// SpliceNibble uint8
// SpliceBitCount uint8
// Reserved uint16
// }
return nil
}
func (d *decoder) parseMETA(length uint32) error {
d.info("META chunk!\n")
buf := make([]byte, length)
if _, err := io.ReadFull(d.r, buf); err != nil {
return err
}
d.crc.Write(buf)
rows := strings.Split(string(buf), "\n")
m := &d.woz.Metadata
m.RawValues = make(map[string]string, len(rows))
for _, row := range rows {
parts := strings.SplitN(row, "\t", 2)
if len(parts) == 0 {
return FormatError("empty metadata line")
}
if len(parts) == 1 {
return FormatError("strange metadata line with no tab: " + parts[0])
}
m.Keys = append(m.Keys, parts[0])
m.RawValues[parts[0]] = parts[1]
}
return nil
}
func (d *decoder) parseUnknown(id string, length uint32) error {
d.info("unknown chunk type (%s): ignoring\n", id)
buf := make([]byte, length)
if _, err := io.ReadFull(d.r, buf); err != nil {
return err
}
d.crc.Write(buf)
d.woz.Unknowns = append(d.woz.Unknowns, UnknownChunk{ID: id, Data: buf})
return nil
}
// Decode reads a woz disk image from r and returns it as a *Woz.
func Decode(r io.Reader) (*Woz, error) {
d := &decoder{
r: r,
crc: crc32.NewIEEE(),
woz: &Woz{},
}
if err := d.checkHeader(); err != nil {
if err == io.EOF {
err = io.ErrUnexpectedEOF
}
return nil, err
}
// Read all chunks.
for {
done, err := d.parseChunk()
if err != nil {
return nil, err
}
if done {
break
}
}
// Check CRC.
if d.crcVal != d.crc.Sum32() {
return d.woz, CRCError{Declared: d.crcVal, Computed: d.crc.Sum32()}
}
return d.woz, nil
}

View File

@ -1,21 +0,0 @@
package woz_test
import (
"bytes"
"testing"
"github.com/zellyn/diskii/data"
"github.com/zellyn/diskii/woz"
)
func TestBasicLoad(t *testing.T) {
wz, err := woz.Decode(bytes.NewReader(data.DOS33masterWOZ))
if err != nil {
t.Fatal(err)
}
if len(wz.Unknowns) > 0 {
t.Fatalf("want 0 unknowns; got %d", len(wz.Unknowns))
}
// fmt.Printf("%#v\n", wz)
// t.Fatal("NOTHING")
}