mirror of
https://github.com/bulletphysics/bullet3
synced 2025-01-10 17:30:12 +00:00
2a721c7489
Plan is to convert COLLADA XML into IFF, for faster, more compact and easier to read and parse files. Reading/writing code is a few hundred lines of code, instead of COLLADA-DOM and libxml combo. So it would be suitable as a run-time format for platforms ranging from iPhone to PlayStation 3. Relevant physics data (and perhaps other data) will be converted from COLLADA -> IFF. We could call the resulting files COLLADA binary IFF -> CLIFF.
1424 lines
63 KiB
Plaintext
1424 lines
63 KiB
Plaintext
|
||
"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
|