💾 Archived View for mirrors.apple2.org.za › archive › apple.cabi.net › Graphics › IFF.2.txt captured on 2024-02-05 at 11:30:27.

View Raw

More Information

⬅️ Previous capture (2023-01-29)

-=-=-=-=-=-=-

"EA IFF 85" Standard for Interchange Format Files

Document Date:          January 14, 1985
From:                   Jerry Morrison, Electronic Arts
Status of Standard:     Released and in use

1. Introduction

Standards are Good for Software Developers

As home computer hardware evolves to better and better media machines,
the demand increases for higher quality, more detailed data. Data
development gets more expensive, requires more expertise and better
tools, and has to be shared across projects. Think about several ports
of a product on one CD-ROM with 500M Bytes of common data!

Development tools need standard interchange file formats. Imagine
scanning in images of "player" shapes, moving them to a paint program
for editing, then incorporating them into a game. Or writing a theme
song with a Macintosh score editor and incorporating it into an Amiga
game. The data must at times be transformed, clipped, filled out,
and moved across machine kinds. Media projects will depend on data
transfer from graphic, music, sound effect, animation, and script
tools.

Standards are Good for Software Users

Customers should be able to move their own data between independently
developed software products. And they should be able to buy data libraries
usable across many such products. The types of data objects to exchange
are open-ended and include plain and formatted text, raster and structured
graphics, fonts, music, sound effects, musical instrument descriptions,
and animation.

The problem with expedient file formats typically memory dumps is
that they're too provincial. By designing data for one particular
use (e.g. a screen snapshot), they preclude future expansion (would
you like a full page picture? a multi-page document?). In neglecting
the possibility that other programs might read their data, they fail
to save contextual information (how many bit planes? what resolution?).
Ignoring that other programs might create such files, they're intolerant
of extra data (texture palette for a picture editor), missing data
(no color map), or minor variations (smaller image). In practice,
a filed representation should rarely mirror an in-memory representation.
The former should be designed for longevity; the latter to optimize
the manipulations of a particular program. The same filed data will
be read into different memory formats by different programs.

The IFF philosophy: "A little behind-the-scenes conversion when programs
read and write files is far better than NxM explicit conversion utilities
for highly specialized formats."

So we need some standardization for data interchange among development
tools and products. The more developers that adopt a standard, the
better for all of us and our customers.

Here is "EA IFF 1985"

Here is our offering: Electronic Arts' IFF standard for Interchange
File Format. The full name is "EA IFF 1985". Alternatives and justifications
are included for certain choices. Public domain subroutine packages
and utility programs are available to make it easy to write and use
IFF-compatible programs.

Part 1 introduces the standard. Part 2 presents its requirements and
background. Parts 3, 4, and 5 define the primitive data types, FORMs,
and LISTs, respectively, and how to define new high level types. Part
6 specifies the top level file structure. Appendix A is included for
quick reference and Appendix B names the committee responsible for
this standard.

References

American National Standard Additional Control Codes for Use with ASCII,
ANSI standard 3.64-1979 for an 8-bit character set. See also ISO standard
2022 and ISO/DIS standard 6429.2.

Amiga[tm] is a trademark of Commodore-Amiga, Inc.

C, A Reference Manual, Samuel P. Harbison and Guy L. Steele Jr., Tartan
Laboratories. Prentice-Hall, Englewood Cliffs, NJ, 1984.

Compiler Construction, An Advanced Course, edited by F. L. Bauer and
J. Eickel (Springer-Verlag, 1976). This book is one of many sources
for information on recursive descent parsing.

DIF Technical Specification (c)1981 by Software Arts, Inc. DIF[tm] is
the format for spreadsheet data interchange developed by Software
Arts, Inc.
DIF[tm] is a trademark of Software Arts, Inc.

Electronic Arts[tm] is a trademark of Electronic Arts.

"FTXT" IFF Formatted Text, from Electronic Arts. IFF supplement document
for a text format.

Inside Macintosh (c) 1982, 1983, 1984, 1985 Apple Computer, Inc., a
programmer's reference manual.
Apple(R) is a trademark of Apple Computer, Inc.
Macintosh[tm] is a trademark licensed to Apple Computer, Inc.

"ILBM" IFF Interleaved Bitmap, from Electronic Arts. IFF supplement
document for a raster image format.

M68000 16/32-Bit Microprocessor Programmer's Reference Manual(c) 1984,
1982, 1980, 1979 by Motorola, Inc.

PostScript Language Manual (c) 1984 Adobe Systems Incorporated.
PostScript[tm] is a trademark of Adobe Systems, Inc.
Times and Helvetica(R) are trademarks of Allied Corporation.

InterScript: A Proposal for a Standard for the Interchange of Editable
Documents (c)1984 Xerox Corporation.
Introduction to InterScript (c) 1985 Xerox Corporation.




2. Background for Designers

Part 2 is about the background, requirements, and goals for the standard.
It's geared for people who want to design new types of IFF objects.
People just interested in using the standard may wish to skip this
part.

What Do We Need?

A standard should be long on prescription and short on overhead. It
should give lots of rules for designing programs and data files for
synergy. But neither the programs nor the files should cost too much
more than the expedient variety. While we're looking to a future with
CD-ROMs and perpendicular recording, the standard must work well on
floppy disks.

For program portability, simplicity, and efficiency, formats should
be designed with more than one implementation style in mind. (In practice,
pure stream I/O is adequate although random access makes it easier
to write files.) It ought to be possible to read one of many objects
in a file without scanning all the preceding data. Some programs need
to read and play out their data in real time, so we need good compromises
between generality and efficiency.

As much as we need standards, they can't hold up product schedules.
So we also need a kind of decentralized extensibility where any software
developer can define and refine new object types without some "standards
authority" in the loop. Developers must be able to extend existing
formats in a forward- and backward-compatible way. A central repository
for design information and example programs can help us take full
advantage of the standard.

For convenience, data formats should heed the restrictions of various
processors and environments. E.g. word-alignment greatly helps 68000
access at insignificant cost to 8088 programs.

Other goals include the ability to share common elements over a list
of objects and the ability to construct composite objects containing
other data objects with structural information like directories.

And finally, "Simple things should be simple and complex things should
be possible."   Alan Kay.

Think Ahead

Let's think ahead and build programs that read and write files for
each other and for programs yet to be designed. Build data formats
to last for future computers so long as the overhead is acceptable.
This extends the usefulness and life of today's programs and data.

To maximize interconnectivity, the standard file structure and the
specific object formats must all be general and extensible. Think
ahead when designing an object. It should serve many purposes and
allow many programs to store and read back all the information they
need; even squeeze in custom data. Then a programmer can store the
available data and is encouraged to include fixed contextual details.
Recipient programs can read the needed parts, skip unrecognized stuff,
default missing data, and use the stored context to help transform
the data as needed.

Scope

IFF addresses these needs by defining a standard file structure, some
initial data object types, ways to define new types, and rules for
accessing these files. We can accomplish a great deal by writing programs
according to this standard, but don't expect direct compatibility
with existing software. We'll need conversion programs to bridge the
gap from the old world.

IFF is geared for computers that readily process information in 8-bit
bytes. It assumes a "physical layer" of data storage and transmission
that reliably maintains "files" as strings of 8-bit bytes. The standard
treats a "file" as a container of data bytes and is independent of
how to find a file and whether it has a byte count.

This standard does not by itself implement a clipboard for cutting
and pasting data between programs. A clipboard needs software to mediate
access, to maintain a "contents version number" so programs can detect
updates, and to manage the data in "virtual memory".

Data Abstraction

The basic problem is how to represent information  in a way that's
program-independent, compiler- independent, machine-independent, and
device-independent.

The computer science approach is "data abstraction", also known as
"objects", "actors", and "abstract data types". A data abstraction
has a "concrete representation" (its storage format), an "abstract
representation" (its capabilities and uses), and access procedures
that isolate all the calling software from the concrete representation.
Only the access procedures touch the data storage. Hiding mutable
details behind an interface is called "information hiding". What data
abstraction does is abstract from details of implementing the object,
namely the selected storage representation and algorithms for manipulating
it.

The power of this approach is modularity. By adjusting the access
procedures we can extend and restructure the data without impacting
the interface or its callers. Conversely, we can extend and restructure
the interface and callers without making existing data obsolete. It's
great for interchange!

But we seem to need the opposite: fixed file formats for all programs
to access. Actually, we could file data abstractions ("filed objects")
by storing the data and access procedures together. We'd have to encode
the access procedures in a standard machine-independent programming
language   la PostScript. Even still, the interface can't evolve freely
since we can't update all copies of the access procedures. So we'll
have to design our abstract representations for limited evolution
and occasional revolution (conversion).

In any case, today's microcomputers can't practically store data abstractions.
They can do the next best thing: store arbitrary types of data in
"data chunks", each with a type identifier and a length count. The
type identifier is a reference by name to the access procedures (any
local implementation). The length count enables storage-level object
operations like "copy" and "skip to next" independent of object type.

Chunk writing is straightforward. Chunk reading requires a trivial
parser to scan each chunk and dispatch to the proper access/conversion
procedure. Reading chunks nested inside other chunks requires recursion,
but no lookahead or backup.

That's the main idea of IFF. There are, of course, a few other detailsI

Previous Work

Where our needs are similar, we borrow from existing standards.

Our basic need to move data between independently developed programs
is similar to that addressed by the Apple Macintosh desk scrap or
"clipboard" [Inside Macintosh chapter "Scrap Manager"]. The Scrap
Manager works closely with the Resource Manager, a handy filer and
swapper for data objects (text strings, dialog window templates, pictures,
fontsI) including types yet to be designed [Inside Macintosh chapter
"Resource Manager"]. The Resource Manager is a kin to Smalltalk's
object swapper.

We will probably write a Macintosh desk accessory that converts IFF
files to and from the Macintosh clipboard for quick and easy interchange
with programs like MacPaint and Resource Mover.

Macintosh uses a simple and elegant scheme of 4-character "identifiers"
to identify resource types, clipboard format types, file types, and
file creator programs. Alternatives are unique ID numbers assigned
by a central authority or by hierarchical authorities, unique ID numbers
generated by algorithm, other fixed length character strings, and
variable length strings. Character string identifiers double as readable
signposts in data files and programs. The choice of 4 characters is
a good tradeoff between storage space, fetch/compare/store time, and
name space size. We'll honor Apple's designers by adopting this scheme.

"PICT" is a good example of a standard structured graphics format
(including raster images) and its many uses [Inside Macintosh chapter
"QuickDraw"]. Macintosh provides QuickDraw routines in ROM to create,
manipulate, and display PICTs. Any application can create a PICT by
simply asking QuickDraw to record a sequence of drawing commands.
Since it's just as easy to ask QuickDraw to render a PICT to a screen
or a printer, it's very effective to pass them between programs, say
from an illustrator to a word processor. An important feature is the
ability to store "comments" in a PICT which QuickDraw will ignore.
Actually, it passes them to your optional custom "comment handler".

PostScript, Adobe's print file standard, is a more general way to
represent any print image (which is a specification for putting marks
on paper) [PostScript Language Manual]. In fact, PostScript is a full-fledged
programming language. To interpret a PostScript program is to render
a document on a raster output device. The language is defined in layers:
a lexical layer of identifiers, constants, and operators; a layer
of reverse polish semantics including scope rules and a way to define
new subroutines; and a printing-specific layer of built-in identifiers
and operators for rendering graphic images. It is clearly a powerful
(Turing equivalent) image definition language. PICT and a subset of
PostScript are candidates for structured graphics standards.

A PostScript document can be printed on any raster output device (including
a display) but cannot generally be edited. That's because the original
flexibility and constraints have been discarded. Besides, a PostScript
program may use arbitrary computation to supply parameters like placement
and size to each operator. A QuickDraw PICT, in comparison, is a more
restricted format of graphic primitives parameterized by constants.
So a PICT can be edited at the level of the primitives, e.g. move
or thicken a line. It cannot be edited at the higher level of, say,
the bar chart data which generated the picture.

PostScript has another limitation: Not all kinds of data amount to
marks on paper. A musical instrument description is one example. PostScript
is just not geared for such uses.

"DIF" is another example of data being stored in a general format
usable by future programs [DIF Technical Specification]. DIF is a
format for spreadsheet data interchange. DIF and PostScript are both
expressed in plain ASCII text files. This is very handy for printing,
debugging, experimenting, and transmitting across modems. It can have
substantial cost in compaction and read/write work, depending on use.
We won't store IFF files this way but we could define an ASCII alternate
representation with a converter program.

InterScript is Xerox' standard for interchange of editable documents
[Introduction to InterScript]. It approaches a harder problem: How
to represent editable word processor documents that may contain formatted
text, pictures, cross-references like figure numbers, and even highly
specialized objects like mathematical equations? InterScript aims
to define one standard representation for each kind of information.
Each InterScript-compatible editor is supposed to preserve the objects
it doesn't understand and even maintain nested cross-references. So
a simple word processor would let you edit the text of a fancy document
without discarding the equations or disrupting the equation numbers.

Our task is similarly to store high level information and preserve
as much content as practical while moving it between programs. But
we need to span a larger universe of data types and cannot expect
to centrally define them all. Fortunately, we don't need to make programs
preserve information that they don't understand. And for better or
worse, we don't have to tackle general-purpose cross-references yet.




3. Primitive Data Types

Atomic components such as integers and characters that are interpretable
directly by the CPU are specified in one format for all processors.
We chose a format that's most convenient for the Motorola MC68000
processor [M68000 16/32-Bit Microprocessor Programmer's Reference
Manual].

N.B.: Part 3 dictates the format for "primitive" data types where and
only where used in the overall file structure and standard kinds of
chunks (Cf. Chunks). The number of such occurrences will be small
enough that the costs of conversion, storage, and management of processor-
specific files would far exceed the costs of conversion during I/O by "foreign"
programs. A particular data chunk may be specified with a different
format for its internal primitive types or with processor- or environment-
speci fic variants if necessary to optimize local usage. Since that hurts
data interchange, it's not recommended. (Cf. Designing New Data Sections,
in Part 4.)

Alignment

All data objects larger than a byte are aligned on even byte addresses
relative to the start of the file. This may require padding. Pad bytes
are to be written as zeros, but don't count on that when reading.

This means that every odd-length "chunk" (see below) must be padded
so that the next one will fall on an even boundary. Also, designers
of structures to be stored in chunks should include pad fields where
needed to align every field larger than a byte. Zeros should be stored
in all the pad bytes.

Justification: Even-alignment causes a little extra work for files
that are used only on certain processors but allows 68000 programs
to construct and scan the data in memory and do block I/O. You just
add an occasional pad field to data structures that you're going to
block read/write or else stream read/write an extra byte. And the
same source code works on all processors. Unspecified alignment, on
the other hand, would force 68000 programs to (dis)assemble word and
long-word data one byte at a time. Pretty cumbersome in a high level
language. And if you don't conditionally compile that out for other
processors, you won't gain anything.

Numbers

Numeric types supported are two's complement binary integers in the
format used by the MC68000 processor high byte first, high word first the
reverse of 8088 and 6502 format. They could potentially include signed
and unsigned 8, 16, and 32 bit integers but the standard only uses
the following:

UBYTE    8 bits unsigned
WORD    16 bits signed
UWORD   16 bits unsigned
LONG    32 bits signed

The actual type definitions depend on the CPU and the compiler. In
this document, we'll express data type definitions in the C programming
language. [See C, A Reference Manual.] In 68000 Lattice C:

typedef unsigned char   UBYTE;  /*  8 bits unsigned     */
typedef short   WORD;   /* 16 bits signed       */
typedef unsigned short  UWORD;  /* 16 bits unsigned     */
typedef long    LONG;   /* 32 bits signed       */

Characters

The following character set is assumed wherever characters are used,
e.g. in text strings, IDs, and TEXT chunks (see below).

Characters are encoded in 8-bit ASCII. Characters in the range NUL
(hex 0) through DEL (hex 7F) are well defined by the 7-bit ASCII standard.
IFF uses the graphic group RJS (SP, hex 20) through R~S (hex 7E).

Most of the control character group hex 01 through hex 1F have no
standard meaning in IFF. The control character LF (hex 0A) is defined
as a "newline" character. It denotes an intentional line break, that
is, a paragraph or line terminator. (There is no way to store an automatic
line break. That is strictly a function of the margins in the environment
the text is placed.) The control character ESC (hex 1B) is a reserved
escape character under the rules of ANSI standard 3.64-1979 American
National Standard Additional Control Codes for Use with ASCII, ISO
standard 2022, and ISO/DIS standard 6429.2.

Characters in the range hex 7F through hex FF are not globally defined
in IFF. They are best left reserved for future standardization. But
note that the FORM type FTXT (formatted text) defines the meaning
of these characters within FTXT forms. In particular, character values
hex 7F through hex 9F are control codes while characters hex A0 through
hex FF are extended graphic characters like  , as per the ISO and
ANSI standards cited above. [See the supplementary document "FTXT"
IFF Formatted Text.]

Dates

A "creation date" is defined as the date and time a stream of data
bytes was created. (Some systems call this a "last modified date".)
Editing some data changes its creation date. Moving the data between
volumes or machines does not.

The IFF standard date format will be one of those used in MS-DOS,
Macintosh, or Amiga DOS (probably a 32-bit unsigned number of seconds
since a reference point). Issue: Investigate these three.

Type IDs

A "type ID", "property name", "FORM type", or any other IFF identifier
is a 32-bit value: the concatenation of four ASCII characters in the
range R S (SP, hex 20) through R~S (hex 7E). Spaces (hex 20) should
not precede printing characters; trailing spaces are ok. Control characters
are forbidden.

typedef CHAR ID[4];

IDs are compared using a simple 32-bit case-dependent equality test.

Data section type IDs (aka FORM types) are restriced IDs. (Cf. Data
Sections.) Since they may be stored in filename extensions (Cf. Single
Purpose Files) lower case letters and punctuation marks are forbidden.
Trailing spaces are ok.

Carefully choose those four characters when you pick a new ID. Make
them mnemonic so programmers can look at an interchange format file
and figure out what kind of data it contains. The name space makes
it possible for developers scattered around the globe to generate
ID values with minimal collisions so long as they choose specific
names like "MUS4" instead of general ones like "TYPE" and "FILE".
EA will "register" new FORM type IDs and format descriptions as they're
devised, but collisions will be improbable so there will be no pressure
on this "clearinghouse" process. Appendix A has a list of currently
defined IDs.

Sometimes it's necessary to make data format changes that aren't backward
compatible. Since IDs are used to denote data formats in IFF, new
IDs are chosen to denote revised formats. Since programs won't read
chunks whose IDs they don't recognize (see Chunks, below), the new
IDs keep old programs from stumbling over new data. The conventional
way to chose a "revision" ID is to increment the last character if
it's a digit or else change the last character to a digit. E.g. first
and second revisions of the ID "XY" would be "XY1" and "XY2". Revisions
of "CMAP" would be "CMA1" and "CMA2".

Chunks

Chunks are the building blocks in the IFF structure. The form expressed
as a C typedef is:

typedef struct {
        ID      ckID;
        LONG    ckSize; /* sizeof(ckData) */
        UBYTE   ckData[/* ckSize */];
        } Chunk;

We can diagram an example chunk a "CMAP" chunk containing 12 data
bytes like this:
                        ----------------
                ckID:   |    'CMAP'    |
                ckSize: |      12      |
                ckData: | 0, 0, 0, 32  |   --------
                        | 0, 0, 64, 0  |    12 bytes
                        | 0, 0, 64, 0  |   ---------
                        ----------------

The fixed header part means "Here's a type ckID chunk with ckSize
bytes of data."

The ckID identifies the format and purpose of the chunk. As a rule,
a program must recognize ckID to interpret ckData. It should skip
over all unrecognized chunks. The ckID also serves as a format version
number as long as we pick new IDs to identify new formats of ckData
(see above).

The following ckIDs are universally reserved to identify chunks with
particular IFF meanings: "LIST", "FORM", "PROP", "CAT ", and "
". The special ID "    " (4 spaces) is a ckID for "filler" chunks,
that is, chunks that fill space but have no meaningful contents. The
IDs "LIS1" through "LIS9", "FOR1" through "FOR9", and "CAT1" through
"CAT9" are reserved for future "version number" variations. All IFF-compatible
software must account for these 23 chunk IDs. Appendix A has a list
of predefined IDs.

The ckSize is a logical block size how many data bytes are in ckData.
If ckData is an odd number of bytes long, a 0 pad byte follows which
is not included in ckSize. (Cf. Alignment.) A chunk's total physical
size is ckSize rounded up to an even number plus the size of the header.
So the smallest chunk is 8 bytes long with ckSize = 0. For the sake
of following chunks, programs must respect every chunk's ckSize as
a virtual end-of-file for reading its ckData even if that data is
malformed, e.g. if nested contents are truncated.

We can describe the syntax of a chunk as a regular expression with
"#" representing the ckSize, i.e. the length of the following {braced}
bytes. The "[0]" represents a sometimes needed pad byte. (The regular
expressions in this document are collected in Appendix A along with
an explanation of notation.)

Chunk   ::= ID #{ UBYTE* } [0]

One chunk output technique is to stream write a chunk header, stream
write the chunk contents, then random access back to the header to
fill in the size. Another technique is to make a preliminary pass
over the data to compute the size, then write it out all at once.

Strings, String Chunks, and String Properties

In a string of ASCII text, LF denotes a forced line break (paragraph
or line terminator). Other control characters are not used. (Cf. Characters.)

The ckID for a chunk that contains a string of plain, unformatted
text is "TEXT". As a practical matter, a text string should probably
not be longer than 32767 bytes. The standard allows up to 231 - 1
bytes.

When used as a data property (see below), a text string chunk may
be 0 to 255 characters long. Such a string is readily converted to
a C string or a Pascal STRING[255]. The ckID of a property must be
the property name, not "TEXT".

When used as a part of a chunk or data property, restricted C string
format is normally used. That means 0 to 255 characters followed by
a NUL byte (ASCII value 0).

Data Properties

Data properties specify attributes for following (non-property) chunks.
A data property essentially says "identifier = value", for example
"XY = (10, 200)", telling something about following chunks. Properties
may only appear inside data sections ("FORM" chunks, cf. Data Sections)
and property sections ("PROP" chunks, cf. Group PROP).

The form of a data property is a special case of Chunk. The ckID is
a property name as well as a property type. The ckSize should be small
since data properties are intended to be accumulated in RAM when reading
a file. (256 bytes is a reasonable upper bound.) Syntactically:

Property        ::= Chunk

When designing a data object, use properties to describe context information
like the size of an image, even if they don't vary in your program.
Other programs will need this information.

Think of property settings as assignments to variables in a programming
language. Multiple assignments are redundant and local assignments
temporarily override global assignments. The order of assignments
doesn't matter as long as they precede the affected chunks. (Cf. LISTs,
CATs, and Shared Properties.)

Each object type (FORM type) is a local name space for property IDs.
Think of a "CMAP" property in a "FORM ILBM" as the qualified ID "ILBM.CMAP".
Property IDs specified when an object type is designed (and therefore
known to all clients) are called "standard" while specialized ones
added later are "nonstandard".

Links

Issue: A standard mechanism for "links" or "cross references" is very
desirable for things like combining images and sounds into animations.
Perhaps we'll define "link" chunks within FORMs that refer to other
FORMs or to specific chunks within the same and other FORMs. This
needs further work. EA IFF 1985 has no standard link mechanism.

For now, it may suffice to read a list of, say, musical instruments,
and then just refer to them within a musical score by index number.

File References

Issue: We may need a standard form for references to other files.
A "file ref" could name a directory and a file in the same type of
operating system as the ref's originator. Following the reference
would expect the file to be on some mounted volume. In a network environment,
a file ref could name a server, too.

Issue: How can we express operating-system independent file refs?

Issue: What about a means to reference a portion of another file?
Would this be a "file ref" plus a reference to a "link" within the
target file?




4. Data Sections

The first thing we need of a file is to check: Does it contain IFF
data and, if so, does it contain the kind of data we're looking for?
So we come to the notion of a "data section".

A "data section" or IFF "FORM" is one self-contained "data object"
that might be stored in a file by itself. It is one high level data
object such as a picture or a sound effect. The IFF structure "FORM"
makes it self- identifying. It could be a composite object like a
musical score with nested musical instrument descriptions.

Group FORM

A data section is a chunk with ckID "FORM" and this arrangement:

FORM    ::= "FORM" #{ FormType (LocalChunk | FORM | LIST | CAT)*
}
FormType        ::= ID
LocalChunk      ::= Property | Chunk

The ID "FORM" is a syntactic keyword like "struct" in C. Think of
a "struct ILBM" containing a field "CMAP". If you see "FORM" you'll
know to expect a FORM type ID (the structure name, "ILBM" in this
example) and a particular contents arrangement or "syntax" (local
chunks, FORMs, LISTs, and CATs). (LISTs and CATs are discussed in
part 5, below.) A "FORM ILBM", in particular, might contain a local
chunk "CMAP", an "ILBM.CMAP" (to use a qualified name).

So the chunk ID "FORM" indicates a data section. It implies that the
chunk contains an ID and some number of nested chunks. In reading
a FORM, like any other chunk, programs must respect its ckSize as
a virtual end-of-file for reading its contents, even if they're truncated.

The FormType (or FORM type) is a restricted ID that may not contain
lower case letters or punctuation characters. (Cf. Type IDs. Cf. Single
Purpose Files.)

The type-specific information in a FORM is composed of its "local
chunks": data properties and other chunks. Each FORM type is a local
name space for local chunk IDs. So "CMAP" local chunks in other FORM
types may be unrelated to "ILBM.CMAP". More than that, each FORM type
defines semantic scope. If you know what a FORM ILBM is, you'll know
what an ILBM.CMAP is.

Local chunks defined when the FORM type is designed (and therefore
known to all clients of this type) are called "standard" while specialized
ones added later are "nonstandard".

Among the local chunks, property chunks give settings for various
details like text font while the other chunks supply the essential
information. This distinction is not clear cut. A property setting
cancelled by a later setting of the same property has effect only
on data chunks in between. E.g. in the sequence:

prop1 = x  (propN = value)*  prop1 = y

where the propNs are not prop1, the setting prop1 = x has no effect.

The following universal chunk IDs are reserved inside any FORM: "LIST",
"FORM", "PROP", "CAT ", "JJJJ", "LIS1" through "LIS9", "FOR1" through
"FOR9", and "CAT1" through "CAT9". (Cf. Chunks. Cf. Group LIST. Cf.
Group PROP.) For clarity, these universal chunk names may not be FORM
type IDs, either.

Part 5, below, talks about grouping FORMs into LISTs and CATs. They
let you group a bunch of FORMs but don't impose any particular meaning
or constraints on the grouping. Read on.

Composite FORMs

A FORM chunk inside a FORM is a full-fledged data section. This means
you can build a composite object like a multi-frame animation sequence
from available picture FORMs and sound effect FORMs. You can insert
additional chunks with information like frame rate and frame count.

Using composite FORMs, you leverage on existing programs that create
and edit the component FORMs. Those editors may even look into your
composite object to copy out its type of component, although it'll
be the rare program that's fancy enough to do that. Such editors are
not allowed to replace their component objects within your composite
object. That's because the IFF standard lets you specify consistency
requirements for the composite FORM such as maintaining a count or
a directory of the components. Only programs that are written to uphold
the rules of your FORM type should create or modify such FORMs.

Therefore, in designing a program that creates composite objects,
you are strongly requested to provide a facility for your users to
import and export the nested FORMs. Import and export could move the
data through a clipboard or a file.

Here are several existing FORM types and rules for defining new ones.

FTXT

An FTXT data section contains text with character formatting information
like fonts and faces. It has no paragraph or document formatting information
like margins and page headers. FORM FTXT is well matched to the text
representation in Amiga's Intuition environment. See the supplemental
document "FTXT" IFF Formatted Text.

ILBM

"ILBM" is an InterLeaved BitMap image with color map; a machine-independent
format for raster images. FORM ILBM is the standard image file format
for the Commodore-Amiga computer and is useful in other environments,
too. See the supplemental document "ILBM" IFF Interleaved Bitmap.

PICS

The data chunk inside a "PICS" data section has ID "PICT" and holds
a QuickDraw picture. Issue: Allow more than one PICT in a PICS? See
Inside Macintosh chapter "QuickDraw" for details on PICTs and how
to create and display them on the Macintosh computer.

The only standard property for PICS is "XY", an optional property
that indicates the position of the PICT relative to "the big picture".
The contents of an XY is a QuickDraw Point.

Note: PICT may be limited to Macintosh use, in which case there'll
be another format for structured graphics in other environments.

Other Macintosh Resource Types

Some other Macintosh resource types could be adopted for use within
IFF files; perhaps MWRT, ICN, ICN#, and STR#.

Issue: Consider the candidates and reserve some more IDs.

Designing New Data Sections

Supplemental documents will define additional object types. A supplement
needs to specify the object's purpose, its FORM type ID, the IDs and
formats of standard local chunks, and rules for generating and interpreting
the data. It's a good idea to supply typedefs and an example source
program that accesses the new object. See "ILBM" IFF Interleaved Bitmap
for a good example.

Anyone can pick a new FORM type ID but should reserve it with Electronic
Arts at their earliest convenience. [Issue: EA contact person? Hand
this off to another organization?] While decentralized format definitions
and extensions are possible in IFF, our preference is to get design
consensus by committee, implement a program to read and write it,
perhaps tune the format, and then publish the format with example
code. Some organization should remain in charge of answering questions
and coordinating extensions to the format.

If it becomes necessary to revise the design of some data section,
its FORM type ID will serve as a version number (Cf. Type IDs). E.g.
a revised "VDEO" data section could be called "VDE1". But try to get
by with compatible revisions within the existing FORM type.

In a new FORM type, the rules for primitive data types and word-alignment
(Cf. Primitive Data Types) may be overriden for the contents of its
local chunks but not for the chunk structure itself if your documentation
spells out the deviations. If machine-specific type variants are needed,
e.g. to store vast numbers of integers in reverse bit order, then
outline the conversion algorithm and indicate the variant inside each
file, perhaps via different FORM types. Needless to say, variations
should be minimized.

In designing a FORM type, encapsulate all the data that other programs
will need to interpret your files. E.g. a raster graphics image should
specify the image size even if your program always uses 320 x 200
pixels x 3 bitplanes. Receiving programs are then empowered to append
or clip the image rectangle, to add or drop bitplanes, etc. This enables
a lot more compatibility.

Separate the central data (like musical notes) from more specialized
information (like note beams) so simpler programs can extract the
central parts during read-in. Leave room for expansion so other programs
can squeeze in new kinds of information (like lyrics). And remember
to keep the property chunks manageably short let's say 2 256 bytes.

When designing a data object, try to strike a good tradeoff between
a super-general format and a highly-specialized one. Fit the details
to at least one particular need, for example a raster image might
as well store pixels in the current machine's scan order. But add
the kind of generality that makes it usable with foreseeable hardware
and software. E.g. use a whole byte for each red, green, and blue
color value even if this year's computer has only 4-bit video DACs.
Think ahead and help other programs so long as the overhead is acceptable.
E.g. run compress a raster by scan line rather than as a unit so future
programs can swap images by scan line to and from secondary storage.

Try to design a general purpose "least common multiple" format that
encompasses the needs of many programs without getting too complicated.
Let's coalesce our uses around a few such formats widely separated
in the vast design space. Two factors make this flexibility and simplicity
practical. First, file storage space is getting very plentiful, so
compaction is not a priority. Second, nearly any locally-performed
data conversion work during file reading and writing will be cheap
compared to the I/O time.

It must be ok to copy a LIST or FORM or CAT intact, e.g. to incorporate
it into a composite FORM. So any kind of internal references within
a FORM must be relative references. They could be relative to the
start of the containing FORM, relative from the referencing chunk,
or a sequence number into a collection.

With composite FORMs, you leverage on existing programs that create
and edit the components. If you write a program that creates composite
objects, please provide a facility for your users to import and export
the nested FORMs. The import and export functions may move data through
a separate file or a clipboard.

Finally, don't forget to specify all implied rules in detail.




5. LISTs, CATs, and Shared Properties

Data often needs to be grouped together like a list of icons. Sometimes
a trick like arranging little images into a big raster works, but
generally they'll need to be structured as a first class group. The
objects "LIST" and "CAT" are IFF-universal mechanisms for this purpose.

Property settings sometimes need to be shared over a list of similar
objects. E.g. a list of icons may share one color map. LIST provides
a means called "PROP" to do this. One purpose of a LIST is to define
the scope of a PROP. A "CAT", on the other hand, is simply a concatenation
of objects.

Simpler programs may skip LISTs and PROPs altogether and just handle
FORMs and CATs. All "fully-conforming" IFF programs also know about
"CAT ", "LIST", and "PROP". Any program that reads a FORM inside a
LIST must process shared PROPs to correctly interpret that FORM.

Group CAT

A CAT is just an untyped group of data objects.

Structurally, a CAT is a chunk with chunk ID "CAT " containing a "contents
type" ID followed by the nested objects. The ckSize of each contained
chunk is essentially a relative pointer to the next one.

CAT     ::= "CAT " #{ ContentsType (FORM | LIST | CAT)* }
ContentsType    ::= ID  -- a hint or an "abstract data type" ID

In reading a CAT, like any other chunk, programs must respect it's
ckSize as a virtual end-of-file for reading the nested objects even
if they're malformed or truncated.

The "contents type" following the CAT's ckSize indicates what kind
of FORMs are inside. So a CAT of ILBMs would store "ILBM" there. It's
just a hint. It may be used to store an "abstract data type". A CAT
could just have blank contents ID ("JJJJ") if it contains more than
one kind of FORM.

CAT defines only the format of the group. The group's meaning is open
to interpretation. This is like a list in LISP: the structure of cells
is predefined but the meaning of the contents as, say, an association
list depends on use. If you need a group with an enforced meaning
(an "abstract data type" or Smalltalk "subclass"), some consistency
constraints, or additional data chunks, use a composite FORM instead
(Cf. Composite FORMs).

Since a CAT just means a concatenation of objects, CATs are rarely
nested. Programs should really merge CATs rather than nest them.

Group LIST

A LIST defines a group very much like CAT but it also gives a scope
for PROPs (see below). And unlike CATs, LISTs should not be merged
without understanding their contents.

Structurally, a LIST is a chunk with ckID "LIST" containing a "contents
type" ID, optional shared properties, and the nested contents (FORMs,
LISTs, and CATs), in that order. The ckSize of each contained chunk
is a relative pointer to the next one. A LIST is not an arbitrary
linked list the cells are simply concatenated.

LIST    ::= "LIST" #{ ContentsType PROP* (FORM | LIST | CAT)* }
ContentsType    ::= ID

Group PROP

PROP chunks may appear in LISTs (not in FORMs or CATs). They supply
shared properties for the FORMs in that LIST. This ability to elevate
some property settings to shared status for a list of forms is useful
for both indirection and compaction. E.g. a list of images with the
same size and colors can share one "size" property and one "color
map" property. Individual FORMs can override the shared settings.

The contents of a PROP is like a FORM with no data chunks:

PROP    ::= "PROP" #{ FormType Property* }

It means, "Here are the shared properties for FORM type <<FormType>."

A LIST may have at most one PROP of a FORM type, and all the PROPs
must appear before any of the FORMs or nested LISTs and CATs. You
can have subsequences of FORMs sharing properties by making each subsequence
a LIST.

Scoping: Think of property settings as variable bindings in nested
blocks of a programming language. Where in C you could write:

TEXT_FONT text_font = Courier;  /* program's global default     */

File(); {
        TEXT_FONT text_font = TimesRoman;       /* shared setting       */

                {
                TEXT_FONT text_font = Helvetica;  /* local setting      */
                Print("Hello ");        /* uses font Helvetica  */
                }

                {
                Print("there.");        /* uses font TimesRoman */
                }
        }

An IFF file could contain:

LIST {
        PROP TEXT {
                FONT {TimesRoman}       /* shared setting       */
                }

        FORM TEXT {
                FONT {Helvetica}        /* local setting        */
                CHRS {Hello }           /* uses font Helvetica  */
                }

        FORM TEXT {
                CHRS {there.}   /* uses font TimesRoman */
                }
        }

The shared property assignments selectively override the reader's
global defaults, but only for FORMs within the group. A FORM's own
property assignments selectively override the global and group-supplied
values. So when reading an IFF file, keep property settings on a stack.
They're designed to be small enough to hold in main memory.

Shared properties are semantically equivalent to copying those properties
into each of the nested FORMs right after their FORM type IDs.

Properties for LIST

Optional "properties for LIST" store the origin of the list's contents
in a PROP chunk for the fake FORM type "LIST". They are the properties
originating program "OPGM", processor family "OCPU", computer type
"OCMP", computer serial number or network address "OSN ", and user
name "UNAM". In our imperfect world, these could be called upon to
distinguish between unintended variations of a data format or to work
around bugs in particular originating/receiving program pairs. Issue:
Specify the format of these properties.

A creation date could also be stored in a property but let's ask that
file creating, editing, and transporting programs maintain the correct
date in the local file system. Programs that move files between machine
types are expected to copy across the creation dates.




6. Standard File Structure

File Structure Overview

An IFF file is just a single chunk of type FORM, LIST, or CAT. Therefore
an IFF file can be recognized by its first 4 bytes: "FORM", "LIST",
or "CAT ". Any file contents after the chunk's end are to be ignored.

Since an IFF file can be a group of objects, programs that read/write
single objects can communicate to an extent with programs that read/write
groups. You're encouraged to write programs that handle all the objects
in a LIST or CAT. A graphics editor, for example, could process a
list of pictures as a multiple page document, one page at a time.

Programs should enforce IFF's syntactic rules when reading and writing
files. This ensures robust data transfer. The public domain IFF reader/writer
subroutine package does this for you. A utility program "IFFCheck"
is available that scans an IFF file and checks it for conformance
to IFF's syntactic rules. IFFCheck also prints an outline of the chunks
in the file, showing the ckID and ckSize of each. This is quite handy
when building IFF programs. Example programs are also available to
show details of reading and writing IFF files.

A merge program "IFFJoin" will be available that logically appends
IFF files into a single CAT group. It "unwraps" each input file that
is a CAT so that the combined file isn't nested CATs.

If we need to revise the IFF standard, the three anchoring IDs will
be used as "version numbers". That's why IDs "FOR1" through "FOR9",
"LIS1" through "LIS9", and "CAT1" through "CAT9" are reserved.

IFF formats are designed for reasonable performance with floppy disks.
We achieve considerable simplicity in the formats and programs by
relying on the host file system rather than defining universal grouping
structures like directories for LIST contents. On huge storage systems,
IFF files could be leaf nodes in a file structure like a B-tree. Let's
hope the host file system implements that for us!

Thre are two kinds of IFF files: single purpose files and scrap files.
They differ in the interpretation of multiple data objects and in
the file's external type.

Single Purpose Files

A single purpose IFF file is for normal "document" and "archive" storage.
This is in contrast with "scrap files" (see below) and temporary backing
storage (non-interchange files).

The external file type (or filename extension, depending on the host
file system) indicates the file's contents. It's generally the FORM
type of the data contained, hence the restrictions on FORM type IDs.

Programmers and users may pick an "intended use" type as the filename
extension to make it easy to filter for the relevant files in a filename
requestor. This is actually a "subclass" or "subtype" that conveniently
separates files of the same FORM type that have different uses. Programs
cannot demand conformity to its expected subtypes without overly restricting
data interchange since they cannot know about the subtypes to be used
by future programs that users will want to exchange data with.

Issue: How to generate 3-letter MS-DOS extensions from 4-letter FORM
type IDs?

Most single purpose files will be a single FORM (perhaps a composite
FORM like a musical score containing nested FORMs like musical instrument
descriptions). If it's a LIST or a CAT, programs should skip over
unrecognized objects to read the recognized ones or the first recognized
one. Then a program that can read a single purpose file can read something
out of a "scrap file", too.

Scrap Files

A "scrap file" is for maximum interconnectivity in getting data between
programs; the core of a clipboard function. Scrap files may have type
"IFF " or filename extension ".IFF".

A scrap file is typically a CAT containing alternate representations
of the same basic information. Include as many alternatives as you
can readily generate. This redundancy improves interconnectivity in
situations where we can't make all programs read and write super-general
formats. [Inside Macintosh chapter "Scrap Manager".] E.g. a graphically-
annotated musical score might be supplemented by a stripped down 4-voice
melody and by a text (the lyrics).

The originating program should write the alternate representations
in order of "preference": most preferred (most comprehensive) type
to least preferred (least comprehensive) type. A receiving program
should either use the first appearing type that it understands or
search for its own "preferred" type.

A scrap file should have at most one alternative of any type. (A LIST
of same type objects is ok as one of the alternatives.) But don't
count on this when reading; ignore extra sections of a type. Then
a program that reads scrap files can read something out of single
purpose files.

Rules for Reader Programs

Here are some notes on building programs that read IFF files. If you
use the standard IFF reader module "IFFR.C", many of these rules and
details will be automatically handled. (See "Support Software" in
Appendix A.) We recommend that you start from the example program
"ShowILBM.C". You should also read up on recursive descent parsers.
[See, for example, Compiler Construction, An Advanced Course.]

%       The standard is very flexible so many programs can exchange
data. This implies a program has to scan the file and react to what's
actually there in whatever order it appears. An IFF reader program
is a parser.

%       For interchange to really work, programs must be willing to
do some conversion during read-in. If the data isn't exactly what
you expect, say, the raster is smaller than those created by your
program, then adjust it. Similarly, your program could crop a large
picture, add or drop bitplanes, and create/discard a mask plane. The
program should give up gracefully on data that it can't convert.

%       If it doesn't start with "FORM", "LIST", or "CAT ", it's not
an IFF-85 file.

%       For any chunk you encounter, you must recognize its type ID
to understand its contents.

%       For any FORM chunk you encounter, you must recognize its FORM
type ID to understand the contained "local chunks". Even if you don't
recognize the FORM type, you can still scan it for nested FORMs, LISTs,
and CATs of interest.

%       Don't forget to skip the pad byte after every odd-length chunk.

%       Chunk types LIST, FORM, PROP, and CAT are generic groups. They
always contain a subtype ID followed by chunks.

%       Readers ought to handle a CAT of FORMs in a file. You may treat
the FORMs like document pages to sequence through or just use the
first FORM.

%       Simpler IFF readers completely skip LISTs. "Fully IFF-conforming"
readers are those that handle LISTs, even if just to read the first
FORM from a file. If you do look into a LIST, you must process shared
properties (in PROP chunks) properly. The idea is to get the correct
data or none at all.

%       The nicest readers are willing to look into unrecognized FORMs
for nested FORM types that they do recognize. For example, a musical
score may contain nested instrument descriptions and an animation
file may contain still pictures.

Note to programmers: Processing PROP chunks is not simple! You'll
need some background in interpreters with stack frames. If this is
foreign to you, build programs that read/write only one FORM per file.
For the more intrepid programmers, the next paragraph summarizes how
to process LISTs and PROPs. See the general IFF reader module "IFFR.C"
and the example program "ShowILBM.C" for details.

Allocate a stack frame for every LIST and FORM you encounter and initialize
it by copying the stack frame of the parent LIST or FORM. At the top
level, you'll need a stack frame initialized to your program's global
defaults. While reading each LIST or FORM, store all encountered properties
into the current stack frame. In the example ShowILBM, each stack
frame has a place for a bitmap header property ILBM.BMHD and a color
map property ILBM.CMAP. When you finally get to the ILBM's BODY chunk,
use the property settings accumulated in the current stack frame.

An alternate implementation would just remember PROPs encountered,
forgetting each on reaching the end of its scope (the end of the containing
LIST). When a FORM XXXX is encountered, scan the chunks in all remembered
PROPs XXXX, in order, as if they appeared before the chunks actually
in the FORM XXXX. This gets trickier if you read FORMs inside of FORMs.

Rules for Writer Programs

Here are some notes on building programs that write IFF files, which
is much easier than reading them. If you use the standard IFF writer
module "IFFW.C" (see "Support Software" in Appendix A), many of these
rules and details will automatically be enforced. See the example
program "Raw2ILBM.C".

%       An IFF file is a single FORM, LIST, or CAT chunk.

%       Any IFF-85 file must start with the 4 characters "FORM", "LIST",
or "CAT ", followed by a LONG ckSize. There should be no data after
the chunk end.

%       Chunk types LIST, FORM, PROP, and CAT are generic. They always
contain a subtype ID followed by chunks. These three IDs are universally
reserved, as are "LIS1" through "LIS9", "FOR1" through "FOR9", "CAT1"
through "CAT9", and "    ".

%       Don't forget to write a 0 pad byte after each odd-length chunk.

%       Four techniques for writing an IFF group: (1) build the data
in a file mapped into virtual memory, (2) build the data in memory
blocks and use block I/O, (3) stream write the data piecemeal and
(don't forget!) random access back to set the group length count,
and (4) make a preliminary pass to compute the length count then stream
write the data.

%       Do not try to edit a file that you don't know how to create.
Programs may look into a file and copy out nested FORMs of types that
they recognize, but don't edit and replace the nested FORMs and don't
add or remove them. That could make the containing structure inconsistent.
You may write a new file containing items you copied (or copied and
modified) from another IFF file, but don't copy structural parts you
don't understand.

%       You must adhere to the syntax descriptions in Appendex A. E.g.
PROPs may only appear inside LISTs.





Appendix A. Reference

Type Definitions

The following C typedefs describe standard IFF structures. Declarations
to use in practice will vary with the CPU and compiler. For example,
68000 Lattice C produces efficient comparison code if we define ID
as a "LONG". A macro "MakeID" builds these IDs at compile time.

/* Standard IFF types, expressed in 68000 Lattice C.    */

typedef unsigned char UBYTE;    /*  8 bits unsigned     */
typedef short WORD;     /* 16 bits signed       */
typedef unsigned short UWORD;   /* 16 bits unsigned     */
typedef long LONG;      /* 32 bits signed       */

typedef char ID[4];     /* 4 chars in ' ' through '~'   */

typedef struct {
        ID      ckID;
        LONG    ckSize; /* sizeof(ckData)       */
        UBYTE   ckData[/* ckSize */];
        } Chunk;

/* ID typedef and builder for 68000 Lattice C. */
typedef LONG ID;        /* 4 chars in ' ' through '~'   */
#define MakeID(a,b,c,d) ( (a)<<<<24 | (b)<<<<16 | (c)<<<<8 | (d) )

/* Globally reserved IDs. */
#define ID_FORM   MakeID('F','O','R','M')
#define ID_LIST   MakeID('L','I','S','T')
#define ID_PROP   MakeID('P','R','O','P')
#define ID_CAT    MakeID('C','A','T',' ')
#define ID_FILLER MakeID(' ',' ',' ',' ')

Syntax Definitions

Here's a collection of the syntax definitions in this document.

Chunk   ::= ID #{ UBYTE* } [0]

Property        ::= Chunk

FORM    ::= "FORM" #{ FormType (LocalChunk | FORM | LIST | CAT)*
}
FormType        ::= ID
LocalChunk      ::= Property | Chunk

CAT     ::= "CAT " #{ ContentsType (FORM | LIST | CAT)* }
ContentsType    ::= ID  -- a hint or an "abstract data type" ID

LIST    ::= "LIST" #{ ContentsType PROP* (FORM | LIST | CAT)* }
PROP    ::= "PROP" #{ FormType Property* }

In this extended regular expression notation, the token "#" represents
a ckSize LONG count of the following {braced} data bytes. Literal
items are shown in "quotes", [square bracketed items] are optional,
and "*" means 0 or more instances. A sometimes-needed pad byte is
shown as "[0]".

Defined Chunk IDs

This is a table of currently defined chunk IDs. We may also borrow
some Macintosh IDs and data formats.

Group chunk IDs
        FORM, LIST, PROP, CAT.
Future revision group chunk IDs
        FOR1 I FOR9, LIS1 I LIS9, CAT1 I CAT9.
FORM type IDs
        (The above group chunk IDs may not be used for FORM type IDs.)
        (Lower case letters and punctuation marks are forbidden in FORM
type IDs.)
        8SVX 8-bit sampled sound voice, ANBM animated bitmap, FNTR raster
font, FNTV vector font, FTXT formatted text, GSCR general-use musical
score, ILBM interleaved raster bitmap image, PDEF Deluxe Print page
definition, PICS Macintosh picture, PLBM (obsolete), USCR Uhuru Sound
Software musical score, UVOX Uhuru Sound Software Macintosh voice,
SMUS simple musical score, VDEO Deluxe Video Construction Set video.
Data chunk IDs
        "JJJJ", TEXT, PICT.
PROP LIST property IDs
        OPGM, OCPU, OCMP, OSN, UNAM.




Support Software

These public domain C source programs are available for use in building
IFF-compatible programs:

IFF.H, IFFR.C, IFFW.C

                IFF reader and writer package.
                These modules handle many of the details of reliably
                reading and writing IFF files.

IFFCheck.C      This handy utility program scans an IFF file, checks
                that the contents are well formed, and prints an outline
                of the chunks.

PACKER.H, Packer.C, UnPacker.C

                Run encoder and decoder used for ILBM files.

ILBM.H, ILBMR.C, ILBMW.C

                Reader and writer support routines for raster image
                FORM ILBM. ILBMR calls IFFR and UnPacker. ILBMW calls
                IFFW and Packer.

ShowILBM.C
                Example caller of IFFR and ILBMR modules. This
                Commodore-Amiga program reads and displays a FORM ILBM.
Raw2ILBM.C
                Example ILBM writer program. As a demonstration, it
                reads a raw raster image file and writes the image
                as a FORM ILBM file.
ILBM2Raw.C
                Example ILBM reader program.  Reads a FORM ILBM file
                and writes it into a raw raster image.

REMALLOC.H, Remalloc.c

                Memory allocation routines used in these examples.

INTUALL.H       generic "include almost everything" include-file
                with the sequence of includes correctly specified.

READPICT.H, ReadPict.c

                given an ILBM file, read it into a bitmap and
                a color map

PUTPICT.H, PutPict.c

                given a bitmap and a color map, save it as
                an ILBM file.

GIO.H, Gio.c    generic I/O speedup package.  Attempts to speed
                disk I/O by buffering writes and reads.

giocall.c       sample call to gio.

ilbmdump.c      reads in ILBM file, prints out ascii representation
                for including in C files.

bmprintc.c      prints out a C-language representation of data for
                a bitmap.




Example Diagrams

Here's a box diagram for an example IFF file, a raster image FORM
ILBM. This FORM contains a bitmap header property chunk BMHD, a color
map property chunk CMAP, and a raster data chunk BODY. This particular
raster is 320 x 200 pixels x 3 bit planes uncompressed. The "0" after
the CMAP chunk represents a zero pad byte; included since the CMAP
chunk has an odd length. The text to the right of the diagram shows
the outline that would be printed by the IFFCheck utility program
for this particular file.

        +-----------------------------------+
        |'FORM'         24070               |   FORM 24070 IBLM
        +-----------------------------------+
        |'ILBM'                             |
        +-----------------------------------+
        | +-------------------------------+ |
        | | 'BMHD'      20                | |   .BMHD  20
        | | 320, 200, 0, 0, 3, 0, 0, ...  | |
        | + ------------------------------+ |
        | | 'CMAP'      21                | |   .CMAP  21
        | | 0, 0, 0; 32, 0, 0; 64,0,0; .. | |
        | +-------------------------------+ |
        | 0                                 |
        +-----------------------------------+
        |'BODY'         24000               |   .BODY 24000
        |0, 0, 0, ...                       |
        +-----------------------------------+

This second diagram shows a LIST of two FORMs ILBM sharing a common
BMHD property and a common CMAP property. Again, the text on the right
is an outline  a la IFFCheck.


     +-----------------------------------------+
     |'LIST'            48114                  |  LIST  48114  AAAA
     +-----------------------------------------+
     |'AAAA'                                   |  .PROP  62  ILBM
     |  +-----------------------------------+  |
     |  |'PROP'         62                  |  |
     |  +-----------------------------------+  |
     |  |'ILBM'                             |  |
     |  +-----------------------------------+  |
     |  | +-------------------------------+ |  |
     |  | | 'BMHD'      20                | |  |  ..BMHD  20
     |  | | 320, 200, 0, 0, 3, 0, 0, ...  | |  |
     |  | | ------------------------------+ |  |
     |  | | 'CMAP'      21                | |  |  ..CMAP  21
     |  | | 0, 0, 0; 32, 0, 0; 64,0,0; .. | |  |
     |  | +-------------------------------+ |  |
     |  | 0                                 |  |
     |  +-----------------------------------+  |
     |  +-----------------------------------+  |
     |  |'FORM'         24012               |  |  .FORM  24012  ILBM
     |  +-----------------------------------+  |
     |  |'ILBM'                             |  |
     |  +-----------------------------------+  |
     |  |  +-----------------------------+  |  |
     |  |  |'BODY'              24000    |  |  |  ..BODY  24000
     |  |  |0, 0, 0, ...                 |  |  |
     |  |  +-----------------------------+  |  |
     |  +-----------------------------------+  |
     |  +-----------------------------------+  |
     |  |'FORM'         24012               |  |  .FORM  24012  ILBM
     |  +-----------------------------------+  |
     |  |'ILBM'                             |  |
     |  +-----------------------------------+  |
     |  |  +-----------------------------+  |  |
     |  |  |'BODY'              24000    |  |  |  ..BODY  24000
     |  |  |0, 0, 0, ...                 |  |  |
     |  |  +-----------------------------+  |  |
     |  +-----------------------------------+  |
     +-----------------------------------------+




Appendix B. Standards Committee

The following people contributed to the design of this IFF standard:

Bob "Kodiak" Burns, Commodore-Amiga
R. J. Mical, Commodore-Amiga
Jerry Morrison, Electronic Arts
Greg Riker, Electronic Arts
Steve Shaw, Electronic Arts
Barry Walsh, Commodore-Amiga