[← Home](../README.md) · [Libraries](README.md)
# 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
```mermaid
flowchart TD
subgraph "IFF ILBM File"
FORM["FORM ILBM"] --> BMHD["BMHD
(bitmap header)"]
FORM --> CMAP["CMAP
(colour palette)"]
FORM --> CAMG["CAMG
(Amiga view mode)"]
FORM --> BODY["BODY
(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
[pad byte if odd size]
[pad byte]
...
Nested FORMs:
LIST
FORM
...
FORM
...
```
| 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
```c
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
```c
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
```c
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)
```
```c
/* 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
```c
/* 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](../08_graphics/ham_ehb_modes.md) — HAM-encoded ILBM files