diff --git a/cmd/iffmaster/main.go b/cmd/iffmaster/main.go index d77032c..5778b1b 100644 --- a/cmd/iffmaster/main.go +++ b/cmd/iffmaster/main.go @@ -1,6 +1,15 @@ // Copyright (c) 2025 Matthias Rustler // Licensed under the MIT License - see LICENSE for details +/* +Iffmaster is a tool to inspect IFF files as defined under EA-85. + +Usage: + + iffmaster + +There aren't any command line options yet. +*/ package main import "github.com/mattrust/iffmaster/internal/gui" diff --git a/internal/chunks/chunk.go b/internal/chunks/chunk.go index 4db230c..f2b55c3 100644 --- a/internal/chunks/chunk.go +++ b/internal/chunks/chunk.go @@ -1,6 +1,7 @@ // Copyright (c) 2025 Matthias Rustler // Licensed under the MIT License - see LICENSE for details +// Package chunks provides functions to read IFF files. package chunks import ( @@ -13,6 +14,7 @@ import ( "fyne.io/fyne/v2" ) +// IFFChunk represents a chunk in an IFF file. type IFFChunk struct { // the chunk data from the file ID string @@ -31,7 +33,10 @@ type IFFChunk struct { ChType string } +// ReadIFFFile reads an IFF file and returns the root chunk. +// In case of an error, the function returns nil and the error. func ReadIFFFile(reader fyne.URIReadCloser) (*IFFChunk, error) { + // TODO: get rid of fyne.URIReadCloser var chunk *IFFChunk file, err := os.Open(reader.URI().Path()) @@ -51,7 +56,10 @@ func ReadIFFFile(reader fyne.URIReadCloser) (*IFFChunk, error) { return chunk, err } +// readChunkID reads the ID of a chunk from the reader. +// In case of an error, the function returns an empty string and the error. func readChunkID(reader io.Reader) (string, error) { + //TODO: check for valid characters var id [4]byte _, err := reader.Read(id[:]) if err != nil { @@ -61,6 +69,8 @@ func readChunkID(reader io.Reader) (string, error) { return string(id[:]), nil } +// readChunkSize reads the size of a chunk from the reader. +// In case of an error, the function returns 0 and the error. func readChunkSize(reader io.Reader) (uint32, error) { var size uint32 err := binary.Read(reader, binary.BigEndian, &size) @@ -71,6 +81,8 @@ func readChunkSize(reader io.Reader) (uint32, error) { return size, nil } +// readChunk recursively reads the chunks from the reader. +// In case of an error, the function returns nil and the error. func readChunk(reader io.Reader, parentChunk *IFFChunk, maxSize int64, level int) (*IFFChunk, error) { var chunk IFFChunk var err error @@ -159,6 +171,8 @@ func readChunk(reader io.Reader, parentChunk *IFFChunk, maxSize int64, level int return &chunk, nil } +// PrintIffChunk prints the chunk and its children to stdout. +// The level parameter must be set to 0. func PrintIffChunk(chunk *IFFChunk, level int) { for i := 0; i < level; i++ { fmt.Print(" ") @@ -169,6 +183,7 @@ func PrintIffChunk(chunk *IFFChunk, level int) { } } +// isGeneric returns true if the chunk ID is generic. func isGeneric(id string) bool { return slices.Contains([]string{"ANNO", "AUTH", "CHRS", diff --git a/internal/chunks/database.go b/internal/chunks/database.go index 075bcf2..0712862 100644 --- a/internal/chunks/database.go +++ b/internal/chunks/database.go @@ -7,13 +7,19 @@ import ( "fmt" ) +// StructResult is a list of key-value pairs. type StructResult [][2]string + +// ChunkHandler is a function that processes a chunk and returns the structured data. type ChunkHandler func(data []byte) (StructResult, error) + +// ChunkData contains the handler and the description for each chunk type. type ChunkData struct { Handler ChunkHandler Description string } +// structData contains the handler and the description for each chunk type. var structData = map[string]ChunkData{ // generic chunks "(any).ANNO": {handleAnyIso8859, "Annotation"}, @@ -137,6 +143,11 @@ var structData = map[string]ChunkData{ "YUVN": {nil, "YUV Image Data"}, } +// GetStructData returns the description and the structured data of a chunk. +// - chType is the chunk type, e.g. "ILBM", "ILBM.BMHD" +// - data is the chunk data +// It returns the description and the structured data as a list of key-value pairs. +// In case of an error the incomplete result is returned. func GetStructData(chType string, data []byte) (string, StructResult, error) { var result StructResult var description string @@ -161,6 +172,9 @@ func GetStructData(chType string, data []byte) (string, StructResult, error) { return description, result, err } +// getBeUword reads a big-endian unsigned WORD from the data at the given offset. +// The offset is incremented by 2. +// In case of an error, it returns 0 and the error. The offset is unchanged. func getBeUword(data []byte, offset *uint32) (uint16, error) { var result uint16 @@ -172,6 +186,9 @@ func getBeUword(data []byte, offset *uint32) (uint16, error) { return result, nil } +// getBeWord reads a big-endian signed WORD from the data at the given offset. +// The offset is incremented by 2. +// In case of an error, it returns 0 and the error. The offset is unchanged. func getBeWord(data []byte, offset *uint32) (int16, error) { var result int16 @@ -183,6 +200,9 @@ func getBeWord(data []byte, offset *uint32) (int16, error) { return result, nil } +// getBeUlong reads a big-endian unsigned LONG from the data at the given offset. +// The offset is incremented by 4. +// In case of an error, it returns 0 and the error. The offset is unchanged. func getBeUlong(data []byte, offset *uint32) (uint32, error) { var result uint32 @@ -195,6 +215,9 @@ func getBeUlong(data []byte, offset *uint32) (uint32, error) { return result, nil } +// getBeLong reads a big-endian signed LONG from the data at the given offset. +// The offset is incremented by 4. +// In case of an error, it returns 0 and the error. The offset is unchanged. func getBeLong(data []byte, offset *uint32) (int32, error) { var result int32 @@ -207,6 +230,9 @@ func getBeLong(data []byte, offset *uint32) (int32, error) { return result, nil } +// getUbyte reads an unsigned BYTE from the data at the given offset. +// The offset is incremented by 1. +// In case of an error, it returns 0 and the error. The offset is unchanged. func getUbyte(data []byte, offset *uint32) (uint8, error) { var result uint8 @@ -218,6 +244,9 @@ func getUbyte(data []byte, offset *uint32) (uint8, error) { return result, nil } +// getByte reads a signed BYTE from the data at the given offset. +// The offset is incremented by 1. +// In case of an error, it returns 0 and the error. The offset is unchanged. func getByte(data []byte, offset *uint32) (int8, error) { var result int8 diff --git a/internal/chunks/handle_8svx.go b/internal/chunks/handle_8svx.go index 97a0aa9..3671fc0 100644 --- a/internal/chunks/handle_8svx.go +++ b/internal/chunks/handle_8svx.go @@ -8,6 +8,7 @@ import ( "log" ) +// handle8svxVhdr processes the 8SVX.VHDR chunk. func handle8svxVhdr(data []byte) (StructResult, error) { log.Println("Handling 8SVX.VHDR chunk") @@ -74,6 +75,7 @@ func handle8svxVhdr(data []byte) (StructResult, error) { return result, nil } +// handle8svxAtakRlse processes the 8SVX.ATAK or 8SVX.RLSE chunk. func handle8svxAtakRlse(data []byte) (StructResult, error) { log.Println("Handling 8SVX.ATAK or 8SVX.RLSE chunk") diff --git a/internal/chunks/handle_anim.go b/internal/chunks/handle_anim.go index 66c2c60..f8c6097 100644 --- a/internal/chunks/handle_anim.go +++ b/internal/chunks/handle_anim.go @@ -8,6 +8,7 @@ import ( "log" ) +// handleAnimAnhd processes the ANIM.ANHD chunk. func handleAnimAnhd(data []byte) (StructResult, error) { log.Println("Handling ANIM.ANHD chunk") @@ -151,6 +152,7 @@ func handleAnimAnhd(data []byte) (StructResult, error) { return result, nil } +// handleAnimDpan processes the ANIM.DPAN chunk. func handleAnimDpan(data []byte) (StructResult, error) { log.Println("Handling ANIM.DPAN chunk") diff --git a/internal/chunks/handle_any.go b/internal/chunks/handle_any.go index 795765d..d603d9d 100644 --- a/internal/chunks/handle_any.go +++ b/internal/chunks/handle_any.go @@ -7,6 +7,7 @@ import ( "golang.org/x/text/encoding/charmap" ) +// handleAnyIso8859 processes any chunk with ISO-8859-1 encoding. func handleAnyIso8859(data []byte) (StructResult, error) { var result StructResult @@ -19,6 +20,7 @@ func handleAnyIso8859(data []byte) (StructResult, error) { return result, nil } +// handleAnyUtf8 processes any chunk with UTF-8 encoding. func handleAnyUtf8(data []byte) (StructResult, error) { var result StructResult diff --git a/internal/chunks/handle_ilbm.go b/internal/chunks/handle_ilbm.go index c99fd29..94f17e1 100644 --- a/internal/chunks/handle_ilbm.go +++ b/internal/chunks/handle_ilbm.go @@ -8,6 +8,7 @@ import ( "log" ) +// handleIlbmBmhd processes the ILBM.BMHD chunk. func handleIlbmBmhd(data []byte) (StructResult, error) { log.Println("Handling ILBM.BMHD chunk") @@ -109,6 +110,7 @@ func handleIlbmBmhd(data []byte) (StructResult, error) { return result, nil } +// handleIlbmCmap processes the ILBM.CMAP chunk. func handleIlbmCmap(data []byte) (StructResult, error) { log.Println("Handling ILBM.CMAP chunk") @@ -133,6 +135,7 @@ func handleIlbmCmap(data []byte) (StructResult, error) { return result, nil } +// handleIlbmGrab processes the ILBM.GRAB chunk. func handleIlbmGrab(data []byte) (StructResult, error) { log.Println("Handling ILBM.GRAB chunk") @@ -156,6 +159,7 @@ func handleIlbmGrab(data []byte) (StructResult, error) { return result, nil } +// handleIlbmCamg processes the ILBM.CAMG chunk. func handleIlbmCamg(data []byte) (StructResult, error) { log.Println("Handling ILBM.CAMG chunk") @@ -173,6 +177,7 @@ func handleIlbmCamg(data []byte) (StructResult, error) { return result, nil } +// handleIlbmDpi processes the ILBM.DPI chunk. func handleIlbmDpi(data []byte) (StructResult, error) { log.Println("Handling ILBM.DPI chunk") @@ -199,6 +204,7 @@ func handleIlbmDpi(data []byte) (StructResult, error) { return result, err } +// handleIlbmDest processes the ILBM.DEST chunk. func handleIlbmDest(data []byte) (StructResult, error) { log.Println("Handling ILBM.DEST chunk") @@ -242,6 +248,7 @@ func handleIlbmDest(data []byte) (StructResult, error) { return result, nil } +// handleIlbmSplt processes the ILBM.SPLT chunk. func handleIlbmSprt(data []byte) (StructResult, error) { log.Println("Handling ILBM.SPRT chunk") @@ -259,6 +266,7 @@ func handleIlbmSprt(data []byte) (StructResult, error) { return result, nil } +// handleIlbmCrng processes the ILBM.CRNG chunk. func handleIlbmCrng(data []byte) (StructResult, error) { log.Println("Handling ILBM.CRNG chunk") diff --git a/internal/chunks/handle_pefs.go b/internal/chunks/handle_pefs.go index 5a9b3d2..58cfdda 100644 --- a/internal/chunks/handle_pefs.go +++ b/internal/chunks/handle_pefs.go @@ -8,6 +8,7 @@ import ( "log" ) +// handlePrefPrhd processes the PREF.PRHD chunk. func handlePrefPrhd(data []byte) (StructResult, error) { log.Println("Handling PREF.PRHD chunk") diff --git a/internal/gui/chunkview.go b/internal/gui/chunkview.go index 1591dea..98ba3d8 100644 --- a/internal/gui/chunkview.go +++ b/internal/gui/chunkview.go @@ -11,6 +11,7 @@ import ( "golang.org/x/text/encoding/charmap" ) +// NewHexTableView creates a new fyne table for the hexadecimal view. func NewHexTableView(appData *AppData) *widget.Table { table := widget.NewTable( // Provide the size of the table @@ -46,6 +47,7 @@ func NewHexTableView(appData *AppData) *widget.Table { return table } +// NewIsoTableView creates a new fyne table for the ISO-8859-1 view. func NewIsoTableView(appData *AppData) *widget.Table { table := widget.NewTable( // Provide the size of the table @@ -82,6 +84,7 @@ func NewIsoTableView(appData *AppData) *widget.Table { return table } +// NewStructTableView creates a new fyne table for the structure view. func NewStructTableView(appData *AppData) *widget.Table { table := widget.NewTable( // Provide the size of the table @@ -113,6 +116,8 @@ func NewStructTableView(appData *AppData) *widget.Table { return table } +// iso8859ToUtf8Char converts an ISO-8859-1 character to a UTF-8 string. +// Some special characters are converted to escape sequences. func iso8859ToUtf8Char(isoChar byte) string { // handle special characters if isoChar == 0 { diff --git a/internal/gui/gui.go b/internal/gui/gui.go index cf37a3b..706e731 100644 --- a/internal/gui/gui.go +++ b/internal/gui/gui.go @@ -1,6 +1,7 @@ // Copyright (c) 2025 Matthias Rustler // Licensed under the MIT License - see LICENSE for details +// Package gui provides the GUI for the IFF Master application package gui import ( @@ -32,6 +33,7 @@ type AppData struct { structTableView *widget.Table } +// OpenGUI layouts the main window and opens it func OpenGUI() { var appData AppData var fileDlg *dialog.FileDialog diff --git a/internal/gui/nodelistview.go b/internal/gui/nodelistview.go index 90181e4..3de61e0 100644 --- a/internal/gui/nodelistview.go +++ b/internal/gui/nodelistview.go @@ -12,6 +12,8 @@ import ( "github.com/mattrust/iffmaster/internal/chunks" ) +// ListEntry is a struct to hold the data for the list view. +// It embeds the IFFChunk struct to hold the chunk data. type ListEntry struct { label string description string @@ -19,6 +21,8 @@ type ListEntry struct { *chunks.IFFChunk // Embedding the IFFChunk struct } +// NewListView creates a new fyne list view. +// It creates a list widget with the chunk ID. func NewListView(appData *AppData) *widget.List { list := widget.NewList( @@ -48,6 +52,8 @@ func NewListView(appData *AppData) *widget.List { return list } +// ConvertIFFChunkToListNode traverses to a IFF chunk nodes and appends +// data which is neede for ghe GUI. func ConvertIFFChunkToListNode(chunk *chunks.IFFChunk) []ListEntry { var nodeList []ListEntry