amiga-bootcamp/11_libraries/iffparse.md
Ilia Sharin f61c26b542 Expand documentation suite: 30+ articles enriched with diagrams, code examples, and hardware details
Graphics: text_fonts (bitmap layout, styles), sprites (DMA, multiplexing), gfx_base (chipset detection), rastport (draw modes, clipping), ham_ehb (mermaid fixes), display_modes (HAM palettes)

Devices: scsi (per-model interfaces, Gayle limits, CD-ROM, native vs vendor drivers), console (ANSI sequences, CON:/RAW:), parallel (CIA registers, pinout), timer (resource exhaustion), gameport (quadrature, XOR state)

Libraries: workbench (WBStartup, AppWindow/Icon/MenuItem), rexxsyslib (ARexx port hosting, command parsing), diskfont (font directory, colour fonts), keymap (rawkey codes, dead keys), locale (catalogue system, date formatting), layers (ClipRect, refresh types), utility (TagItem chains), icon (DiskObject, ToolTypes), iffparse (IFF structure, ByteRun1), expansion (Zorro AutoConfig)

Networking: tcp_ip_stacks (major rewrite - Amiga vs Unix architecture, SANA-II pipeline, PPP/SLIP dial-up, Ethernet cards, MiSTer), bsdsocket (pure API ref), sana2 (buffer hooks, driver requirements), protocols (all code examples). Deduplicated overlap between the three files.

Toolchain: debugging (Enforcer patterns, SnoopDOS, GDB remote, kprintf checklist), sasc (pragma encoding, __saveds idioms), stormc (NEW - StormC IDE, C++, PowerPC)

References: error_codes (DOS, Exec, trackdisk, Intuition error tables)
Driver development: rtg_driver (Native driver analysis, P96 tuning)

All 22 README indexes updated. Root README synced with stormc.md entry.
2026-04-23 21:37:26 -04:00

7.1 KiB
Raw Blame History

← Home · Libraries

iffparse.library — IFF File Parsing

Overview

IFF (Interchange File Format) is EA/Commodore's universal container format used throughout the Amiga ecosystem. iffparse.library provides stream-oriented parsing and writing of IFF files, handling the nested chunk structure, byte ordering, and padding automatically.

Common IFF types:

  • ILBM — Interleaved Bitmap (images)
  • 8SVX — 8-bit sampled voice (audio)
  • ANIM — Animation sequences
  • FTXT — Formatted text
flowchart TD
    subgraph "IFF ILBM File"
        FORM["FORM ILBM"] --> BMHD["BMHD<br/>(bitmap header)"]
        FORM --> CMAP["CMAP<br/>(colour palette)"]
        FORM --> CAMG["CAMG<br/>(Amiga view mode)"]
        FORM --> BODY["BODY<br/>(pixel data)"]
    end

    subgraph "iffparse.library"
        IH["AllocIFF"] --> INIT["InitIFFasDOS"]
        INIT --> OPEN["OpenIFF(READ)"]
        OPEN --> PARSE["ParseIFF(SCAN)"]
        PARSE --> READ["ReadChunkBytes"]
        READ --> CLOSE["CloseIFF"]
    end

    FORM -.-> PARSE
    style FORM fill:#e8f4fd,stroke:#2196f3,color:#333

IFF Structure

All IFF files follow a nested chunk structure. Everything is big-endian (network byte order):

FORM <size:LONG> <type:4 chars>
    <chunk_id:4 chars> <size:LONG> <data...> [pad byte if odd size]
    <chunk_id:4 chars> <size:LONG> <data...> [pad byte]
    ...

Nested FORMs:
    LIST <size> <type>
        FORM <size> <type>
            ...
        FORM <size> <type>
            ...
Container Purpose
FORM A single structured data object
LIST Ordered collection of FORMs
CAT Unordered concatenation of FORMs
PROP Default property block (within LIST)

Reading an IFF File

struct Library *IFFParseBase = OpenLibrary("iffparse.library", 0);
struct IFFHandle *iff = AllocIFF();

/* Open from AmigaDOS file: */
iff->iff_Stream = (ULONG)Open("image.iff", MODE_OLDFILE);
if (!iff->iff_Stream) { /* error */ }

InitIFFasDOS(iff);  /* use DOS Read/Write/Seek hooks */

if (OpenIFF(iff, IFFF_READ)) { /* error */ }

/* Register chunks we want to stop at: */
StopChunk(iff, ID_ILBM, ID_BMHD);
StopChunk(iff, ID_ILBM, ID_CMAP);
StopChunk(iff, ID_ILBM, ID_CAMG);
StopChunk(iff, ID_ILBM, ID_BODY);

/* Parse — stops at each registered chunk: */
LONG error;
while ((error = ParseIFF(iff, IFFPARSE_SCAN)) == 0)
{
    struct ContextNode *cn = CurrentChunk(iff);

    switch (cn->cn_ID)
    {
        case ID_BMHD:
        {
            struct BitMapHeader bmhd;
            ReadChunkBytes(iff, &bmhd, sizeof(bmhd));
            Printf("Image: %ldx%ld, %ld planes\n",
                   bmhd.bmh_Width, bmhd.bmh_Height, bmhd.bmh_Depth);
            break;
        }
        case ID_CMAP:
        {
            UBYTE palette[256 * 3];
            LONG palSize = ReadChunkBytes(iff, palette, cn->cn_Size);
            LONG numColours = palSize / 3;
            Printf("Palette: %ld colours\n", numColours);
            break;
        }
        case ID_CAMG:
        {
            ULONG viewMode;
            ReadChunkBytes(iff, &viewMode, 4);
            if (viewMode & HAM) Printf("HAM mode\n");
            break;
        }
        case ID_BODY:
        {
            /* Read pixel data (may be compressed) */
            UBYTE *bodyData = AllocMem(cn->cn_Size, MEMF_ANY);
            ReadChunkBytes(iff, bodyData, cn->cn_Size);
            /* ... decompress if bmhd.bmh_Compression == 1 (ByteRun1) ... */
            FreeMem(bodyData, cn->cn_Size);
            break;
        }
    }
}

CloseIFF(iff);
Close((BPTR)iff->iff_Stream);
FreeIFF(iff);

Writing an IFF File

struct IFFHandle *iff = AllocIFF();
iff->iff_Stream = (ULONG)Open("output.iff", MODE_NEWFILE);
InitIFFasDOS(iff);
OpenIFF(iff, IFFF_WRITE);

/* Start the FORM: */
PushChunk(iff, ID_ILBM, ID_FORM, IFFSIZE_UNKNOWN);

/* Write BMHD chunk: */
PushChunk(iff, 0, ID_BMHD, sizeof(struct BitMapHeader));
WriteChunkBytes(iff, &bmhd, sizeof(bmhd));
PopChunk(iff);

/* Write CMAP chunk: */
PushChunk(iff, 0, ID_CMAP, numColours * 3);
WriteChunkBytes(iff, palette, numColours * 3);
PopChunk(iff);

/* Write BODY chunk: */
PushChunk(iff, 0, ID_BODY, IFFSIZE_UNKNOWN);
WriteChunkBytes(iff, bodyData, bodySize);
PopChunk(iff);

/* Close the FORM: */
PopChunk(iff);

CloseIFF(iff);
Close((BPTR)iff->iff_Stream);
FreeIFF(iff);

ILBM BitMapHeader

struct BitMapHeader {
    UWORD bmh_Width;        /* image width in pixels */
    UWORD bmh_Height;       /* image height in pixels */
    WORD  bmh_Left;         /* x offset (usually 0) */
    WORD  bmh_Top;          /* y offset (usually 0) */
    UBYTE bmh_Depth;        /* number of bitplanes */
    UBYTE bmh_Masking;      /* 0=none, 1=hasMask, 2=hasTransparentColor */
    UBYTE bmh_Compression;  /* 0=none, 1=ByteRun1 */
    UBYTE bmh_Pad;
    UWORD bmh_Transparent;  /* transparent colour index */
    UBYTE bmh_XAspect;      /* pixel aspect ratio */
    UBYTE bmh_YAspect;
    WORD  bmh_PageWidth;    /* source page width */
    WORD  bmh_PageHeight;   /* source page height */
};

ByteRun1 Compression

ILBM BODY data is typically compressed with ByteRun1 (a simple RLE):

For each byte n:
  0..127:   copy next n+1 bytes literally
  -1..-127: repeat next byte (-n+1) times
  -128:     no-op (skip)
/* Decompress ByteRun1: */
void DecompressByteRun1(UBYTE *src, UBYTE *dst, LONG dstSize)
{
    UBYTE *end = dst + dstSize;
    while (dst < end)
    {
        BYTE n = *src++;
        if (n >= 0)
        {
            LONG count = n + 1;
            memcpy(dst, src, count);
            src += count;
            dst += count;
        }
        else if (n != -128)
        {
            LONG count = -n + 1;
            memset(dst, *src++, count);
            dst += count;
        }
    }
}

Common Chunk IDs

FORM Type Chunk Size Description
ILBM BMHD 20 Bitmap header (width, height, depth, compression)
ILBM CMAP n×3 Colour map (R,G,B triples, 8-bit each)
ILBM CAMG 4 Amiga display mode (ModeID for ViewPort)
ILBM BODY varies Pixel data (interleaved bitplanes)
ILBM CRNG 8 Colour cycling range (DPaint)
ILBM GRAB 4 Hotspot (cursor/brush grab point)
8SVX VHDR 20 Voice header (rate, volume, octaves)
8SVX BODY varies Audio sample data (signed 8-bit)
ANIM ANHD 24 Animation frame header
ANIM DLTA varies Delta-compressed frame data
FTXT CHRS varies Character string data

Using IFF with Clipboard

/* Read from clipboard instead of file: */
struct IFFHandle *iff = AllocIFF();
struct ClipboardHandle *ch = OpenClipboard(PRIMARY_CLIP);
iff->iff_Stream = (ULONG)ch;
InitIFFasClip(iff);  /* use clipboard hooks instead of DOS */
OpenIFF(iff, IFFF_READ);
/* ... parse as normal ... */
CloseIFF(iff);
CloseClipboard(ch);
FreeIFF(iff);

References

  • NDK39: libraries/iffparse.h, datatypes/pictureclass.h
  • EA IFF-85 specification: the original format definition
  • ADCD 2.1: iffparse.library autodocs
  • See also: ham_ehb_modes.md — HAM-encoded ILBM files