Copyright (c) Hyperion Entertainment and contributors.

IFF Source Code

From AmigaOS Documentation Wiki
Jump to navigation Jump to search
Codereview.png Code samples on this page are not yet updated to AmigaOS 4.x some of them may be obsolete or incompatible with AmigaOS 4.x.

IFF Source Code

This section contains a variety of source code listings showing how to use IFF files in applications. All of these programs require the new iffparse.library included with Release 2.0 of the Amiga operating system (Kickstart V36 and greater). There are four parts:

  • IFF include files. These have been updated to be compatible with iffparse.library.
  • Link modules which provide convenient IFF handling routines such as showilbm.c.
  • Example programs showing how to use the link modules.
  • Stand-alone utility and example programs.

IFFP_Modules.README

These iffparse.library code modules and examples are designed as
replacements for the original EA IFF code.  In some modules, it has been
possible to retain much of the original code.  However, most structures
and most higher level function interfaces have changed.

On the plus side, these new modules contain many new high-level
easy-to-use functions for querying, loading, displaying, and saving ILBMs.
During their development, modules similar to these have been used inhouse
for the 2.0 Display program and several other ILBM
applications.  The screen.c module provides powerful display-opening
functions which are 1.3-compatible yet provide a host of new options under
2.0 such as centered overscan screens, full-video display clips, border
transparency control, and autoscroll.  New modules have been added for
printing (screendump) and for preserving/adding chunks (copychunks). And
the 8SVX example now actually plays samples and instruments. In addition,
clipboard support is automatic for all applications that use the IFFP
modules because parse.c's openifile() interprets the filename -c[n] (ie.
"-c", "-c1", "-c2", etc.) as clipboard unit n.

All of the applications presented here require iffparse.library which is
distributed on Workbench 2.0.  Please note that iffparse.library is a
1.3-compatible library, and that all of these modules and examples have
been designed to take advantage of 2.0, but also work under 1.3.
Developers who wish to distribute iffparse.library on their commercial
products may execute a 2.0 Workbench license, or may get an addendum to
their 1.3 Workbench license to allow distribution of iffparse.library.

It was not necessary to port the gio IO speedup code since iffparse can
use your compiler's own buffered IO routines through the callback
stdio_stream() in parse.c.  Depending on your application, you may want to
add your own additional buffering to this stdio_stream() code.

Most of the high-level function pairs provided in these modules have been
designed to provide safe cleanup for themselves.  For example, a
loadbrush() that succeeds or fails at any point can be cleaned up via
unloadbrush.  The cleanup routines null out the appropriate pointers so
that allocations will not be freed twice.

All applications are built upon the parse.c module.  The basic concept of
using the parse.c module are:

        - Define tag-like arrays of your desired chunks (readers only)
        - Allocates one or more [form]Info structures as defined in
            iffp/[form]app.h (for example an ILBMInfo defined in
            iffp/ilbmapp.h).
        - Initialize the ParseInfo part of these structures to the desired
            chunk arrays, and to an IFFHandle allocated via iffparse
            AllocIFF().
        - Use the provided high level load/save functions, or use the
            lower level parse.c openifile(), reader-only parseifile()/
            getcontext()/nextcontext(), and closeifile().  The filename
            -c[n] may be used to read/write clipboard unit n.
        - Clean up, FreeIFF(), and deallocate [form]Info's.


IMPORTANT NOTES - Most of the higher-level load functions keep the
        IFFHandle (file or clipboard) open.  While the handle is
        open, you may use parse.c functions (such as findpropdata)
        OR direct iffparse functions (FindProp(), FindCollection())
        for accessing the gathered chunks.  However, it is not a good
        idea to keep a filehandle OR the clipboard open.  While
        a clipboard unit is open, no other applications can clip
        to the unit.  And while a file is open, you can't write the
        file back out.  So, instead of keeping the file or unit
        open, you can use copychunks (in copychunks.c) to create
        a copy of your gathered chunks, and do an early closeifile()
        (parse.c).  Then access and later write back out (if you wish)
        and deallocate your copied chunks via the routines in the
        copychunks module (findchunk, writechunklist, freechunklist).

WARNING REGARDING COMPLEX FORMS
        Regarding Complex FORMs - The parse.c module will enter complex
        formats such as CATSs, LISTs, and nested FORMs to find the FORM
        that you are interested in.  This is great.  However, if you are
        a read-modify-write program, you should warn your user when this
        occurs unless YOU are capable of recreating the complex format.
        Otherwise, your user may unknowingly destroy his complex file
        by writing over it with your program.  Example - a paint
        program could read an ILBM out of a complex LIST containing
        pictures and music, and then save it back out as a simple ILBM,
        causing the user to lose his music and other pictures.
        To determine if a complex form was entered after a load,
        check the (form)Info.ParseInfo.hunt field.  If TRUE (non-zero),
        then your file was found inside a complex format.

COMPILATION NOTES
        These modules and examples have been compiled using SAS C 5.10a
        and Manx C 5.0d, with 2.0 (37.1) include files and 2.0 amiga.lib.
        You must have at least 37.1 alib_protos.h (older versions of
        this include file contained the amiga.lib stdio protos also
        which conflict with both SAS and Manx stdio).  For Manx, I
        also had to comment out the conditional definition of abs() in
        libraries/mathffp.h.  These modules do not use mathffp, but
        the mathffp include file is pulled in by alib_protos.h.
        When compiling with Manx, a warning seems to be generated for
        each string constant assigned to a UBYTE * field, and also
        by some references to ilbm->colortable.



                LIST OF IFFP MODULES AND APPLICATIONS
                -------------------------------------
        NOTE - Some useful functions are listed with each module
           See module source code for docs on each function.


APPLICATIONS (these require linkage with modules - see Makefiles)
------------
ILBMDemo        Displays an ILBM, loads a brush, saves an ILBM, opt. print
ILBMLoad        Queries an ILBM and loads it into an existing screen
ILBMtoC         Outputs an ILBM as C source code
ILBMtoRaw       Converts an ILBM to raw plane/color file
RawtoILBM       Converts raw plane/color file (from ILBMtoRaw) to an ILBM
24bitDemo       Saves a simple 24-bit ILBM and then shows it 4 planes at
                a time (if given filename, just does the show part)
Play8SVX        Reads and plays an 8SVX sound effect or instrument
                  - LoadSample, UnloadSample, PlaySample, OpenAudio,
                    CloseAudio, and body load/unpack functions
ScreenSave      Save the front screen as an ILBM, with an icon


OTHER EXAMPLES (use iffparse.library directly and require no modules)
--------------
Sift            Checks and prints outline of any IFF file (uses RAWSTEP)
ILBMScan        Prints out useful info about any ILBM
ClipFTXT        Demonstrates simply clipping of FTXT to/from clipboard
cycvb.c         Dan Silva's routine for interrupt based color cycling
apack.asm       Dr. Gerald Hull's assembler replacement for packer.c


GENERAL IFFPARSE SUPPORT MODULE
-------------------------------
parse.c         File/clipboard IO and general parsing
                  - openifile, closeifile, parseifile, getcontext,
                    nextcontext, contextis, currentchunkis, PutCk chunk
                    writing function, and IFFerr text error routine


ILBM READ MODULES
-----------------
loadilbm.c      High level ILBM load routines which are passed filenames
                (calls getbitmap)
                  - loadbrush/unloadbrush,loadilbm/unloadilbm,and queryilbm
getbitmap.c     brush/bitmap loading (non-display, calls ilbmr.c)
                  - createbrush/deletebrush, getbitmap/freebitmap
getdisplay.c    bitmap load/display (calls screen.c, ilbmr.c)
                  - showilbm/unshowilbm, createdisplay/deletedisplay
screen.c        1.3/2.0 ECS/non-ECS compatible screen/window module
                  - opendisplay, openidscreen, modefallback, clipit
ilbmr.c         Lower level ILBM body/color load routines(calls unpacker.c)
                  - loadbody, loadcmap, getcolors/freecolors,
                    alloccolortable, getcamg (gets or creates modeid)
unpacker.c      BODY unpacker


ILBM WRITE MODULES
------------------
saveilbm.c      High level ILBM saving routines which are passed filenames
                (calls ilbmw.c)
                  - screensave and saveilbm
ilbmw.c         Lower level ILBM body/color save routines (calls packer.c)
                  - InitBMHD, PutCMAP, PutBODY
packer.c        BODY packer


EXTRA MODULES
-------------
copychunks.c    Chunk cloning and chunk list writing routines
                  - copychunks, findchunk, writechunklist, freechunklist
screendump.c    Screen printing module (iffparse not required)
bmprintc.c      Module to output ILBM as C code


INCLUDE FILES
-------------
iffp/#?.h       This subdirectory may be kept in your current directory
                or in your main include directory.


Thanks to Steve Walton for his code changes for Manx/SAS compatibility,
and to Bill Barton and John Bittner for their comments and suggestions.

Makefile.SAS

#MYLIBS= LIB:debug.lib

CC = lc
ASM = asm

CFLAGS = -cfistq -v -j73 -iINCLUDE:
AFLAGS = -iINCLUDE:
LFLAGS = SC BATCH ND

M      = modules/
A      = apps/

# Our iffparse support object modules to link with
IFFO      = $(M)parse.o $(M)Hook.o
ILBMRO    = $(M)ilbmr.o $(M)unpacker.o
ILBMSO    = $(M)getdisplay.o $(M)screen.o
ILBMLO    = $(M)loadilbm.o $(M)getbitmap.o
ILBMWO    = $(M)saveilbm.o $(M)ilbmw.o $(M)packer.o
ILBMO     = $(IFFO) $(ILBMRO) $(ILBMLO) $(ILBMSO) $(ILBMWO)
EXTRAO    = $(M)copychunks.o $(M)screendump.o $(M)bmprintc.o


# Our iffparse applications
APP1   = $(A)ILBMDemo/ILBMDemo
APP2   = $(A)ILBMLoad/ILBMLoad
APP3   = $(A)Play8SVX/Play8SVX
APP4   = $(A)ILBMtoC/ILBMtoC
APP5   = $(A)ILBMtoRaw/ILBMtoRaw
APP6   = $(A)ScreenSave/ScreenSave
APP7   = $(A)RawtoILBM/RawtoILBM
APP8   = $(A)24bitDemo/24bitDemo


# The object modules needed by each application example
APP1O  = $(APP1).o $(ILBMO) $(M)screendump.o $(M)copychunks.o
APP2O  = $(APP2).o $(IFFO) $(ILBMRO) $(ILBMLO) $(ILBMSO)
APP3O  = $(APP3).o $(IFFO)
APP4O  = $(APP4).o $(IFFO) $(ILBMRO) $(ILBMLO) $(M)bmprintc.o
APP5O  = $(APP5).o $(IFFO) $(ILBMRO) $(ILBMLO)
APP6O  = $(APP6).o $(IFFO) $(ILBMWO)
APP7O  = $(APP7).o $(IFFO) $(ILBMWO)
APP8O  = $(APP8).o $(IFFO) $(ILBMRO) $(ILBMLO) $(ILBMSO) $(ILBMWO)

.SUFFIXES:
.SUFFIXES:      .o .c .h .asm .i

# Make all of the applications
all:    $(APP1) $(APP2) $(APP3) $(APP4) $(APP5) $(APP6) $(APP7) $(APP8)

# Linkage for each application

$(APP1): $(APP1O)
  blink <WITH <
FROM lib:c.o $(APP1O)
LIBRARY lib:lc.lib LIB:amiga.lib $(MYLIBS)
TO $(APP1) $(LFLAGS)
<

$(APP2): $(APP2O)
  blink <WITH <
FROM lib:c.o $(APP2O)
LIBRARY lib:lc.lib LIB:amiga.lib $(MYLIBS)
TO $(APP2) $(LFLAGS)
<

$(APP3): $(APP3O)
  blink <WITH <
FROM lib:c.o $(APP3O)
LIBRARY lib:lc.lib LIB:amiga.lib $(MYLIBS)
TO $(APP3) $(LFLAGS)
<

$(APP4): $(APP4O)
  blink <WITH <
FROM lib:c.o $(APP4O)
LIBRARY lib:lc.lib LIB:amiga.lib $(MYLIBS)
TO $(APP4) $(LFLAGS)
<

$(APP5): $(APP5O)
  blink <WITH <
FROM lib:c.o $(APP5O)
LIBRARY lib:lc.lib LIB:amiga.lib $(MYLIBS)
TO $(APP5) $(LFLAGS)
<

$(APP6): $(APP6O)
  blink <WITH <
FROM lib:c.o $(APP6O)
LIBRARY lib:lc.lib LIB:amiga.lib $(MYLIBS)
TO $(APP6) $(LFLAGS)
<

$(APP7): $(APP7O)
  blink <WITH <
FROM lib:c.o $(APP7O)
LIBRARY lib:lc.lib LIB:amiga.lib $(MYLIBS)
TO $(APP7) $(LFLAGS)
<

$(APP8): $(APP8O)
  blink <WITH <
FROM lib:c.o $(APP8O)
LIBRARY lib:lc.lib LIB:amiga.lib $(MYLIBS)
TO $(APP8) $(LFLAGS)
<

.c.o:
        $(CC) $(CFLAGS) $*.c

.asm.o:
        $(ASM) $(AFLAGS) $*.asm

iffp/8svx.h

/*-----------------------------------------------------------------------*
 * 8SVX.H  Definitions for 8-bit sampled voice (VOX).   2/10/86
 *
 * By Jerry Morrison and Steve Hayes, Electronic Arts.
 * This software is in the public domain.
 * 
 * Modified for use with iffparse.library 05/91 - CAS_CBM
 *
 * This version for the Amiga computer.
 *----------------------------------------------------------------------*/
#ifndef EIGHTSVX_H
#define EIGHTSVX_H

#ifndef COMPILER_H
#include "iffp/compiler.h"
#endif

#include "iffp/iff.h"

#define ID_8SVX      MAKE_ID('8', 'S', 'V', 'X')
#define ID_VHDR      MAKE_ID('V', 'H', 'D', 'R')

#define ID_ATAK      MAKE_ID('A', 'T', 'A', 'K')
#define ID_RLSE      MAKE_ID('R', 'L', 'S', 'E')

/* defined in iffp/iff.h
#define ID_NAME      MAKE_ID('N', 'A', 'M', 'E')
#define ID_Copyright MAKE_ID('(', 'c', ')', ' ')
#define ID_AUTH      MAKE_ID('A', 'U', 'T', 'H')
#define ID_ANNO      MAKE_ID('A', 'N', 'N', 'O')
#define ID_BODY      MAKE_ID('B', 'O', 'D', 'Y')
*/


/* ---------- Voice8Header ---------------------------------------------*/
typedef LONG Fixed;     /* A fixed-point value, 16 bits to the left of
                         * the point and 16 to the right. A Fixed is a
                         * number of 2**16ths, i.e. 65536ths. */
#define Unity 0x10000L  /* Unity = Fixed 1.0 = maximum volume */

/* sCompression: Choice of compression algorithm applied to the samples. */
#define sCmpNone       0        /* not compressed */
#define sCmpFibDelta   1        /* Fibonacci-delta encoding (Appendix C) */
                                /* Could be more kinds in the future. */
typedef struct {
    ULONG oneShotHiSamples,     /* # samples in the high octave 1-shot part */
          repeatHiSamples,      /* # samples in the high octave repeat part */
          samplesPerHiCycle;    /* # samples/cycle in high octave, else 0 */
    UWORD samplesPerSec;        /* data sampling rate */
    UBYTE ctOctave,             /* # of octaves of waveforms */
          sCompression;         /* data compression technique used */
    Fixed volume;               /* playback nominal volume from 0 to Unity
                                 * (full volume). Map this value into
                                 * the output hardware's dynamic range.
                                 */
    } Voice8Header;

/* ---------- NAME -----------------------------------------------------*/
/* NAME chunk contains a CHAR[], the voice's name. */

/* ---------- Copyright ------------------------------------------------*/
/* "(c) " chunk contains a CHAR[], the FORM's copyright notice. */

/* ---------- AUTH -----------------------------------------------------*/
/* AUTH chunk contains a CHAR[], the author's name. */

/* ---------- ANNO -----------------------------------------------------*/
/* ANNO chunk contains a CHAR[], the author's text annotations. */

/* ---------- Envelope ATAK & RLSE -------------------------------------*/
typedef struct {
    UWORD duration;     /* segment duration in milliseconds, > 0 */
    Fixed dest;         /* destination volume factor */
    } EGPoint;

/* ATAK and RLSE chunks contain an EGPoint[], piecewise-linear envelope. */

/* The envelope defines a function of time returning Fixed values.
 * It's used to scale the nominal volume specified in the Voice8Header.
 */

/* ---------- BODY -----------------------------------------------------*/
/* BODY chunk contains a BYTE[], array of audio data samples. */
/* (8-bit signed numbers, -128 through 127.) */


/* ---------- 8SVX Writer Support Routines -----------------------------*/

/* Just call this macro to write a VHDR chunk. */
#define PutVHDR(iff, vHdr)  \
    PutCk(iff, ID_VHDR, sizeof(Voice8Header), (BYTE *)vHdr)

#endif

iffp/8svxapp.h

/* 8svxapp.h
 * - definition of EightSVXInfo structure
 * - inclusion of includes needed by modules and application
 * - application-specific definitions
 */
#ifndef EIGHTSVXAPP_H
#define EIGHTSVXAPP_H

#include "iffp/8svx.h"

#include <devices/audio.h>

#define MAXOCT 16

struct EightSVXInfo {
        /* general parse.c related */
        struct  ParseInfo ParseInfo;

        /* For convenient access to VHDR, Name, and sample.
         * Other chunks will be accessible through FindProp()
         *  (or findchunk() if the chunks have been copied)
         */
        /* 8SVX */
        Voice8Header    Vhdr;           

        BYTE            *sample;
        ULONG           samplebytes;

        BYTE            *osamps[MAXOCT];
        ULONG           osizes[MAXOCT];
        BYTE            *rsamps[MAXOCT];
        ULONG           rsizes[MAXOCT];
        ULONG           spcycs[MAXOCT];

        UBYTE           name[80];

        ULONG           Reserved[8];    /* must be 0 for now */

        /* Applications may add variables here */
        };

/* referenced by modules */
extern struct Library *IFFParseBase;

#endif

iffp/amiga.h

/* IFF application include files
 */

#ifndef  AMIGA_H
#define  AMIGA_H

#include <exec/types.h>
#include <exec/memory.h>
#include <exec/libraries.h>

#include <libraries/dos.h>

#include <intuition/intuition.h>
#include <intuition/screens.h>

#include <graphics/view.h>
#include <graphics/displayinfo.h>
#include <graphics/videocontrol.h>
#include <graphics/gfxmacros.h>

#include <libraries/iffparse.h>

#include <clib/exec_protos.h>
#include <clib/dos_protos.h>
#include <clib/intuition_protos.h>
#include <clib/graphics_protos.h>
#include <clib/iffparse_protos.h>

#include <stdlib.h>
#include <stdio.h>
#include <string.h>

#include "iffp/debug.h"

#endif

iffp/compiler.h

#ifndef COMPILER_H
#define COMPILER_H
/*** compiler.h *********************************************************/
/*  Steve Shaw                                                  1/29/86 */
/*  Portability file to handle compiler idiosyncrasies.                 */
/*                                                                      */ 
/* This software is in the public domain.                               */ 
/* modified 05/91 for use with iffparse - CAS_CBM                       */ 
/************************************************************************/

#ifndef EXEC_TYPES_H
#include "exec/types.h"
#endif

/*
#define NO_PROTOS
*/

#endif COMPILER_H

iffp/debug.h

/*
 * mydebug.h - #include this file sometime after stdio.h
 * Set MYDEBUG to 1 to turn on debugging, 0 to turn off debugging
 */

#ifndef MYDEBUG_H
#define MYDEBUG_H

#define MYDEBUG  0


#if MYDEBUG

/*
 * MYDEBUG User Options
 */

/* Set to 1 to turn second level D2(bug()) statements */
#define DEBUGLEVEL2     1

/* Set to a non-zero # of ticks if a delay is wanted after each debug message */
#define DEBUGDELAY              0

/* Always non-zero for the DDx macros */
#define DDEBUGDELAY             50

/* Set to 1 for serial debugging (link with debug.lib) */
#define KDEBUG          0

/* Set to 1 for parallel debugging (link with ddebug.lib) */
#define DDEBUG          0

#endif /* MYDEBUG */


/* Prototypes for Delay, kprintf, dprintf. Or use proto/dos.h or functions.h. */
#include <clib/dos_protos.h>
void kprintf(UBYTE *fmt,...);
void dprintf(UBYTE *fmt,...);

/*
 * D(bug()), D2(bug()), DQ((bug()) only generate code if MYDEBUG is non-zero
 *
 * Use D(bug()) for general debugging, D2(bug()) for extra debugging that
 * you usually won't need to see, DD(bug()) for debugging statements that
 * you always want followed by a delay, and DQ(bug()) for debugging that
 * you'll NEVER want a delay after (ie. debugging inside a Forbid, Disable,
 * Task, or Interrupt)
 *
 * Some example uses (all are used the same):
 * D(bug("about to do xyz. variable = $%lx\n",myvariable)); 
 * D2(bug("v1=$%lx v2=$%lx v3=$%lx\n",v1,v2,v3)); 
 * DQ(bug("in subtask: variable = $%lx\n",myvariable));
 * DD(bug("About to do xxx\n"));
 *
 * Set MYDEBUG above to 1 when debugging is desired and recompile the modules
 *  you wish to debug.  Set to 0 and recompile to turn off debugging.
 *
 * User options set above:
 * Set DEBUGDELAY to a non-zero # of ticks (ex. 50) when a delay is desired.
 * Set DEBUGLEVEL2 nonzero to turn on second level (D2) debugging statements
 * Set KDEBUG to 1 and link with debug.lib for serial debugging.
 * Set DDEBUG to 1 and link with ddebug.lib for parallel debugging.
 */


/* 
 * Debugging function automaticaly set to printf, kprintf, or dprintf
 */

#if KDEBUG
#define bug kprintf
#elif DDEBUG
#define bug dprintf
#else   /* else changes all bug's to printf's */
#define bug printf
#endif

/*
 * Debugging macros
 */

/* D(bug(       delays DEBUGDELAY if DEBUGDELAY is > 0
 * DD(bug(      always delays DDEBUGDELAY
 * DQ(bug(      (debug quick) never uses Delay.  Use in forbids,disables,ints
 * The similar macros with "2" in their names are second level debugging
 */
#if MYDEBUG    /* Turn on first level debugging */
#define D(x)  (x); if(DEBUGDELAY>0) Delay(DEBUGDELAY)
#define DD(x) (x); Delay(DDEBUGDELAY)
#define DQ(x) (x)
#if DEBUGLEVEL2 /* Turn on second level debugging */
#define D2(x)  (x); if(DEBUGDELAY>0) Delay(DEBUGDELAY)
#define DD2(x) (x); Delay(DDEBUGDELAY)
#define DQ2(x) (x)
#else  /* Second level debugging turned off */
#define D2(x) ;
#define DD2(x) ;
#define DQ2(x) ;
#endif /* DEBUGLEVEL2 */
#else  /* First level debugging turned off */
#define D(x) ;
#define DQ(x) ;
#define D2(x) ;
#define DD(x) ;
#endif


#endif /* MYDEBUG_H */

iffp/iff.h

/* 
 *
 * iff.h:       General Definitions for IFFParse modules
 *
 * 6/27/91
 */

#ifndef IFFP_IFF_H
#define IFFP_IFF_H

#include "iffp/compiler.h"

#ifndef EXEC_TYPES_H
#include <exec/types.h>
#endif
#ifndef EXEC_MEMORY_H
#include <exec/memory.h>
#endif
#ifndef UTILITY_TAGITEM_H
#include <utility/tagitem.h>
#endif
#ifndef UTILITY_HOOKS_H
#include <utility/hooks.h>
#endif
#ifndef LIBRARIES_IFFPARSE_H
#include <libraries/iffparse.h>
#endif

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#ifndef MYDEBUG_H
#include "iffp/debug.h"
#endif

#ifndef NO_PROTOS
#include <clib/exec_protos.h>
#include <clib/iffparse_protos.h>
#endif

#ifndef MAX
#define MAX(a,b)        ((a) > (b) ? (a) : (b))
#endif
#ifndef MIN
#define MIN(a,b)        ((a) < (b) ? (a) : (b))
#endif
#ifndef ABS
#define ABS(x)          ((x) < 0 ? -(x) : (x))
#endif


#define CkErr(expression)  {if (!error) error = (expression);}
#define ChunkMoreBytes(cn)      (cn->cn_Size - cn->cn_Scan)
#define IS_ODD(a)               (a & 1)

#define IFF_OKAY        0L
#define CLIENT_ERROR    1L
#define NOFILE          5L

#define message printf

/* Generic Chunk ID's we may encounter */
#define ID_ANNO         MAKE_ID('A','N','N','O')
#define ID_AUTH         MAKE_ID('A','U','T','H')
#define ID_CHRS         MAKE_ID('C','H','R','S')
#define ID_Copyright    MAKE_ID('(','c',')',' ')
#define ID_CSET         MAKE_ID('C','S','E','T')
#define ID_FVER         MAKE_ID('F','V','E','R')
#define ID_NAME         MAKE_ID('N','A','M','E')
#define ID_TEXT         MAKE_ID('T','E','X','T')
#define ID_BODY         MAKE_ID('B','O','D','Y')


/* Used to keep track of allocated IFFHandle, and whether file is
 * clipboard or not, filename, copied chunks, etc.
 * This structure is included in the beginning of every
 * form-specific info structure used by the example modules.
 */
struct ParseInfo {
        /* general parse.c related */
        struct  IFFHandle *iff;         /* to be alloc'd with AllocIFF */
        UBYTE   *filename;              /* current filename of this ui */
        LONG    *propchks;              /* properties to get */
        LONG    *collectchks;           /* properties to collect */
        LONG    *stopchks;              /* stop on these (like BODY) */
        BOOL    opened;                 /* this iff has been opened */
        BOOL    clipboard;              /* file is clipboard */
        BOOL    hunt;                   /* we are parsing a complex file */
        BOOL    Reserved1;              /* must be zero for now */              

        /* for copychunks.c - for read/modify/write programs
         * and programs that need to keep parsed chunk info
         * around after closing file.
         * Deallocated by freechunklist();
         */
        struct Chunk *copiedchunks;

        /* application may hang its own list of new chunks here
         * just to keep it with the frame.
         */
        struct Chunk *newchunks;

        ULONG   Reserved[8];
        };


/*
 * Used by some modules to save or pass a singly linked list of chunks
 */
struct Chunk {
        struct  Chunk *ch_Next;
        long    ch_Type;
        long    ch_ID;
        long    ch_Size;
        void    *ch_Data;
};


#ifndef NO_PROTOS
/* parse.c */
LONG openifile(struct ParseInfo *,UBYTE *,ULONG);
void closeifile(struct ParseInfo *);
LONG parseifile(struct ParseInfo *,
                LONG, LONG, LONG *, LONG *, LONG *);
LONG getcontext(struct IFFHandle *);
LONG nextcontext(struct IFFHandle *);
LONG currentchunkis(struct IFFHandle *, LONG type, LONG id);
LONG contextis(struct IFFHandle *, LONG type, LONG id);
UBYTE *findpropdata(struct IFFHandle *iff, LONG type, LONG id);
void initiffasstdio(struct IFFHandle *);
UBYTE *IFFerr(LONG);
LONG chkcnt(LONG *);
long PutCk(struct IFFHandle *iff, long id, long size, void *data);

/* copychunks.c */
struct Chunk *copychunks(struct IFFHandle *iff,
                 LONG *propchks, LONG *collectchks, ULONG memtype);
void freechunklist(struct Chunk *first);
struct Chunk *findchunk(struct Chunk *first, long type, long id);
long writechunklist(struct IFFHandle *iff, struct Chunk *first);
#endif /* NO_PROTOS */

#endif /* IFFP_IFF_H */

iffp/ilbm.h

/* 
 *
 * ilbm.h:      Definitions for IFFParse ILBM reader.
 *
 * 6/27/91
 */

#ifndef IFFP_ILBM_H
#define IFFP_ILBM_H

#ifndef IFFP_IFF_H
#include "iffp/iff.h"
#endif

#ifndef INTUITION_INTUITION_H
#include <intuition/intuition.h>
#endif
#ifndef GRAPHICS_VIDEOCONTROL_H
#include <graphics/videocontrol.h>
#endif

#ifndef NO_PROTOS
#include <clib/graphics_protos.h>
#include <clib/intuition_protos.h>
#include <clib/alib_protos.h>
#endif

/*  IFF types we may encounter  */
#define ID_ILBM         MAKE_ID('I','L','B','M')

/* ILBM Chunk ID's we may encounter
 * (see iffp/iff.h for some other generic chunks)
 */
#define ID_BMHD         MAKE_ID('B','M','H','D')
#define ID_CMAP         MAKE_ID('C','M','A','P')
#define ID_CRNG         MAKE_ID('C','R','N','G')
#define ID_CCRT         MAKE_ID('C','C','R','T')
#define ID_GRAB         MAKE_ID('G','R','A','B')
#define ID_SPRT         MAKE_ID('S','P','R','T')
#define ID_DEST         MAKE_ID('D','E','S','T')
#define ID_CAMG         MAKE_ID('C','A','M','G')

/* Use this constant instead of sizeof(ColorRegister). */
#define sizeofColorRegister  3

typedef WORD Color4;   /* Amiga RAM version of a color-register,
          * with 4 bits each RGB in low 12 bits.*/

/* Maximum number of bitplanes storable in BitMap structure */
#define MAXAMDEPTH 8
#define MAXAMCOLORREG 32

/* Maximum planes we can save */
#define MAXSAVEDEPTH 24

/* convert width to BytesPerRow */
#define BytesPerRow(w)  ((w) + 15 >> 4 << 1)
#define BitsPerRow(w)   ((w) + 15 >> 4 << 4)

/* Flags that should be masked out of old 16-bit CAMG before save or use.
 * Note that 32-bit mode id (non-zero high word) bits should not be twiddled
 */
#define BADFLAGS  (SPRITES|VP_HIDE|GENLOCK_AUDIO|GENLOCK_VIDEO)
#define OLDCAMGMASK  (~BADFLAGS)


/*  Masking techniques  */
#define mskNone                 0
#define mskHasMask              1
#define mskHasTransparentColor  2
#define mskLasso                3

/*  Compression techniques  */
#define cmpNone                 0
#define cmpByteRun1             1

#define RowBytes(w)     ((((w) + 15) >> 4) << 1)

/* ---------- BitMapHeader ---------------------------------------------*/
/*  Required Bitmap header (BMHD) structure describes an ILBM */
typedef struct {
        UWORD   w, h;           /* Width, height in pixels */
        WORD    x, y;           /* x, y position for this bitmap  */
        UBYTE   nPlanes;        /* # of planes (not including mask) */
        UBYTE   masking;        /* a masking technique listed above */
        UBYTE   compression;    /* cmpNone or cmpByteRun1 */
        UBYTE   reserved1;      /* must be zero for now */
        UWORD   transparentColor;
        UBYTE   xAspect, yAspect;
        WORD    pageWidth, pageHeight;
} BitMapHeader;

/* ---------- ColorRegister --------------------------------------------*/
/* A CMAP chunk is a packed array of ColorRegisters (3 bytes each). */
typedef struct {
    UBYTE red, green, blue;   /* MUST be UBYTEs so ">> 4" won't sign extend.*/
    } ColorRegister;

/* ---------- Point2D --------------------------------------------------*/
/* A Point2D is stored in a GRAB chunk. */
typedef struct {
    WORD x, y;      /* coordinates (pixels) */
    } Point2D;

/* ---------- DestMerge ------------------------------------------------*/
/* A DestMerge is stored in a DEST chunk. */
typedef struct {
    UBYTE depth;   /* # bitplanes in the original source */
    UBYTE pad1;      /* UNUSED; for consistency store 0 here */
    UWORD planePick;   /* how to scatter source bitplanes into destination */
    UWORD planeOnOff;   /* default bitplane data for planePick */
    UWORD planeMask;   /* selects which bitplanes to store into */
    } DestMerge;

/* ---------- SpritePrecedence -----------------------------------------*/
/* A SpritePrecedence is stored in a SPRT chunk. */
typedef UWORD SpritePrecedence;

/* ---------- Camg Amiga Viewport Mode ---------------------------------*/
/* An Amiga ViewPort->Modes is stored in a CAMG chunk. */
/* The chunk's content is declared as a LONG. */
typedef struct {
   ULONG ViewModes;
   } CamgChunk;

/* ---------- CRange cycling chunk -------------------------------------*/
#define RNG_NORATE  36   /* Dpaint uses this rate to mean non-active */
/* A CRange is store in a CRNG chunk. */
typedef struct {
    WORD  pad1;              /* reserved for future use; store 0 here */
    WORD  rate;      /* 60/sec=16384, 30/sec=8192, 1/sec=16384/60=273 */
    WORD  active;     /* bit0 set = active, bit 1 set = reverse */
    UBYTE low, high;   /* lower and upper color registers selected */
    } CRange;

/* ---------- Ccrt (Graphicraft) cycling chunk -------------------------*/
/* A Ccrt is stored in a CCRT chunk. */
typedef struct {
   WORD  direction;  /* 0=don't cycle, 1=forward, -1=backwards */
   UBYTE start;      /* range lower */
   UBYTE end;        /* range upper */
   LONG  seconds;    /* seconds between cycling */
   LONG  microseconds; /* msecs between cycling */
   WORD  pad;        /* future exp - store 0 here */
   } CcrtChunk;

/* If you are writing all of your chunks by hand,
 * you can use these macros for these simple chunks.
 */
#define putbmhd(iff, bmHdr)  \
    PutCk(iff, ID_BMHD, sizeof(BitMapHeader), (BYTE *)bmHdr)
#define putgrab(iff, point2D)  \
    PutCk(iff, ID_GRAB, sizeof(Point2D), (BYTE *)point2D)
#define putdest(iff, destMerge)  \
    PutCk(iff, ID_DEST, sizeof(DestMerge), (BYTE *)destMerge)
#define putsprt(iff, spritePrec)  \
    PutCk(iff, ID_SPRT, sizeof(SpritePrecedence), (BYTE *)spritePrec)
#define putcamg(iff, camg)  \
    PutCk(iff, ID_CAMG, sizeof(CamgChunk),(BYTE *)camg)
#define putcrng(iff, crng)  \
    PutCk(iff, ID_CRNG, sizeof(CRange),(BYTE *)crng)
#define putccrt(iff, ccrt)  \
    PutCk(iff, ID_CCRT, sizeof(CcrtChunk),(BYTE *)ccrt)

#ifndef NO_PROTOS
/* unpacker.c */
BOOL unpackrow(BYTE **pSource, BYTE **pDest, WORD srcBytes0, WORD dstBytes0);

/* packer.c */
LONG packrow(BYTE **pSource, BYTE **pDest, LONG rowSize);

/* ilbmr.c  ILBM reader routines */
LONG loadbody(struct IFFHandle *iff, struct BitMap *bitmap,
                BitMapHeader *bmhd);
LONG loadbody2(struct IFFHandle *iff, struct BitMap *bitmap, 
                BYTE *mask, BitMapHeader *bmhd, 
                BYTE *buffer, ULONG bufsize);
LONG loadcmap(struct IFFHandle *, WORD *colortable, USHORT *pNcolors);
LONG getcolors(struct ILBMInfo *ilbm);
void freecolors(struct ILBMInfo *ilbm);
LONG alloccolortable(struct ILBMInfo *ilbm);
ULONG getcamg(struct ILBMInfo *ilbm);

/* ilbmw.c  ILBM writer routines */
long initbmhd(BitMapHeader *bmhd, struct BitMap *bitmap,
              WORD masking, WORD compression, WORD transparentColor,
              WORD width, WORD height, WORD pageWidth, WORD pageHeight,
              ULONG modeid);
long putcmap(struct IFFHandle *iff,APTR colortable,UWORD ncolors,UWORD bitspergun);
long putbody(struct IFFHandle *iff, struct BitMap *bitmap,
                BYTE *mask, BitMapHeader *bmHdr,
                BYTE *buffer, LONG bufsize);

/* getdisplay.c (used to load a display) */
LONG showilbm(struct ILBMInfo *ilbm, UBYTE *filename);
void unshowilbm(struct ILBMInfo *ilbm);
LONG createdisplay(struct ILBMInfo *);
void deletedisplay(struct ILBMInfo *);
LONG getdisplay(struct ILBMInfo *);
void freedisplay(struct ILBMInfo *);

/* getbitmap.c (used if just loading brush or bitmap) */
LONG createbrush(struct ILBMInfo *);
void deletebrush(struct ILBMInfo *);
LONG getbitmap(struct ILBMInfo *);
void freebitmap(struct ILBMInfo *);

/* screen.c (opens 1.3 or 2.0 screen) */
struct Screen *openidscreen(struct ILBMInfo *,SHORT,SHORT,SHORT,ULONG);
struct Window *opendisplay(struct ILBMInfo *,SHORT,SHORT,SHORT,ULONG);
ULONG  modefallback(ULONG, SHORT, SHORT, SHORT);
void clipit(SHORT wide, SHORT high, struct Rectangle *spos,
        struct Rectangle *dclip, struct Rectangle *txto,
        struct Rectangle *stdo,struct Rectangle *maxo,
        struct Rectangle * uclip);
void closedisplay(struct ILBMInfo *);
void modeErrorMsg(ULONG,ULONG);

/* loadilbm.c */
LONG loadbrush(struct ILBMInfo *ilbm, UBYTE *filename);
void unloadbrush(struct ILBMInfo *ilbm);

LONG queryilbm(struct ILBMInfo *ilbm, UBYTE *filename);

LONG loadilbm(struct ILBMInfo *ilbm, UBYTE *filename);
void unloadilbm(struct ILBMInfo *ilbm);

/* saveilbm.c */
LONG screensave(struct ILBMInfo *ilbm,
                        struct Screen *scr,
                        struct Chunk *chunklist1, struct Chunk *chunklist2,
                        UBYTE *filename);

LONG saveilbm(struct ILBMInfo *ilbm,
                struct BitMap *bitmap, ULONG modeid,
                WORD width, WORD height, WORD pagewidth, WORD pageheight,
                APTR colortable, UWORD count, UWORD bitspergun,
                WORD masking, WORD transparentColor,
                struct Chunk *chunklist1, struct Chunk *chunklist2,
                UBYTE *filename);


/* screendump.c (print screen or brush) */
int screendump(struct Screen *scr,
     UWORD srcx, UWORD srcy, UWORD srcw, UWORD srch,
     LONG destcols, UWORD special);

/* bmprintc.c (write C source for ILBM) */
void BMPrintCRep(struct BitMap *bm, FILE *fp, UBYTE *name, UBYTE *fmt);  

#endif /* NO_PROTOS */

#endif /* IFFP_ILBM_H */

iffp/ilbmapp.h

/* ilbmapp.h
 * - definition of ILBMInfo structure
 * - inclusion of includes needed by modules and application
 * - application-specific definitions
 *
 * 07/03/91 - added ilbm->stags for screen.c
 */
#ifndef ILBMAPP_H
#define ILBMAPP_H

#include "iffp/ilbm.h"

struct ILBMInfo {
        /* general parse.c related */
        struct  ParseInfo ParseInfo;

        /* The following variables are for
         * programs using the ILBM-related modules.
         * They may be removed or replaced for
         * programs parsing other forms.
         */
        /* ILBM */
        BitMapHeader Bmhd;              /* filled in by load and save ops */
        ULONG   camg;                   /* filled in by load and save ops */
        Color4  *colortable;            /* allocated by getcolors */
        ULONG   ctabsize;               /* size of colortable in bytes */
        USHORT  ncolors;                /* number of color registers loaded */
        USHORT  Reserved1;

        /* for getbitmap.c */
        struct BitMap *brbitmap;        /* for loaded brushes only */

        /* for screen.c */
        struct Screen *scr;             /* screen of loaded display   */
        struct Window *win;             /* window of loaded display   */
        struct ViewPort *vp;            /* viewport of loaded display */
        struct RastPort *srp;           /* screen's rastport */
        struct RastPort *wrp;           /* window's rastport */
        BOOL TBState;                   /* state of titlebar hiddenness */

        /* caller preferences */
        struct NewWindow *windef;       /* definition for window */
        UBYTE *stitle;          /* screen title */
        LONG stype;             /* additional screen types */
        WORD ucliptype;         /* overscan display clip type */
        BOOL EHB;               /* default to EHB for 6-plane/NoCAMG */
        BOOL Video;             /* Max Video Display Clip (non-adjustable) */
        BOOL Autoscroll;        /* Enable Autoscroll of screens */
        BOOL Notransb;          /* Borders not transparent to genlock */
        ULONG *stags;           /* Additional screen tags for 2.0 screens */

        ULONG Reserved[7];      /* must be 0 for now */

        /* Application-specific variables may go here */
        };

/* referenced by modules */

extern struct Library *IFFParseBase;

/* protos for application module(s) */

#endif

iffp/packer.h

#ifndef PACKER_H
#define PACKER_H
/*----------------------------------------------------------------------*
 * PACKER.H  typedefs for Data-Compresser.                      1/22/86
 *
 * This module implements the run compression algorithm "cmpByteRun1"; the
 * same encoding generated by Mac's PackBits.
 *
 * By Jerry Morrison and Steve Shaw, Electronic Arts.
 * This software is in the public domain.
 *
 * This version for the Amiga computer.
 *----------------------------------------------------------------------*/

#include <exec/types.h>

/* This macro computes the worst case packed size of a "row" of bytes. */
#define MaxPackedSize(rowSize)  ( (rowSize) + ( ((rowSize)+127) >> 7 ) )


/* Given POINTERS to POINTER variables, packs one row, updating the source
 * and destination pointers. Returns the size in bytes of the packed row.
 * ASSUMES destination buffer is large enough for the packed row.
 * See MaxPackedSize. */
extern LONG PackRow(BYTE **, BYTE **, LONG);
                /*  pSource, pDest,   rowSize */

/* Given POINTERS to POINTER variables, unpacks one row, updating the source
 * and destination pointers until it produces dstBytes bytes (i.e., the
 * rowSize that went into PackRow).
 * If it would exceed the source's limit srcBytes or if a run would overrun
 * the destination buffer size dstBytes, it stops and returns TRUE.
 * Otherwise, it returns FALSE (no error). */
extern BOOL UnPackRow(BYTE **, BYTE **, WORD,     WORD);
                  /*  pSource, pDest,   srcBytes, dstBytes  */


BYTE *PutDump(BYTE *, int);
BYTE *PutRun(BYTE *,int,int);
LONG PackRow(BYTE **,BYTE **,LONG);
BOOL UnPackRow(BYTE **,BYTE **,WORD,WORD);

#endif

iffp/smus.h

/*----------------------------------------------------------------------*
 * SMUS.H  Definitions for Simple MUSical score.   2/12/86
 *
 * By Jerry Morrison and Steve Hayes, Electronic Arts.
 * This software is in the public domain.
 *
 * Modified for use with iffparse.library 05/91 - CAS_CBM
 *
 * This version for the Amiga computer.
 *----------------------------------------------------------------------*/

#ifndef SMUS_H
#define SMUS_H

#ifndef COMPILER_H
#include "iffp/compiler.h"
#endif

#include "iffp/iff.h"

#define ID_SMUS      MAKE_ID('S', 'M', 'U', 'S')
#define ID_SHDR      MAKE_ID('S', 'H', 'D', 'R')

/* Now defined in iffp/iff.h as generic chunks
#define ID_NAME      MAKE_ID('N', 'A', 'M', 'E')
#define ID_Copyright MAKE_ID('(', 'c', ')', ' ')
#define ID_AUTH      MAKE_ID('A', 'U', 'T', 'H')
#define ID_ANNO      MAKE_ID('A', 'N', 'N', 'O')
*/

#define ID_INS1      MAKE_ID('I', 'N', 'S', '1')
#define ID_TRAK      MAKE_ID('T', 'R', 'A', 'K')


/* ---------- SScoreHeader ---------------------------------------------*/
typedef struct {
    UWORD tempo;        /* tempo, 128ths quarter note/minute */
    UBYTE volume;       /* playback volume 0 through 127 */
    UBYTE ctTrack;      /* count of tracks in the score */
    } SScoreHeader;

/* ---------- NAME -----------------------------------------------------*/
/* NAME chunk contains a CHAR[], the musical score's name. */

/* ---------- Copyright (c) --------------------------------------------*/
/* "(c) " chunk contains a CHAR[], the FORM's copyright notice. */

/* ---------- AUTH -----------------------------------------------------*/
/* AUTH chunk contains a CHAR[], the name of the score's author. */

/* ---------- ANNO -----------------------------------------------------*/
/* ANNO chunk contains a CHAR[], the author's text annotations. */

/* ---------- INS1 -----------------------------------------------------*/
/* Constants for the RefInstrument's "type" field. */
#define INS1_Name  0    /* just use the name; ignore data1, data2 */
#define INS1_MIDI  1    /* <data1, data2> = MIDI <channel, preset> */

typedef struct {
    UBYTE iRegister;    /* set this instrument register number */
    UBYTE type;         /* instrument reference type (see above) */
    UBYTE data1, data2; /* depends on the "type" field */
    char name[60];      /* instrument name */
    } RefInstrument;

/* ---------- TRAK -----------------------------------------------------*/
/* TRAK chunk contains an SEvent[]. */

/* SEvent: Simple musical event. */
typedef struct {
    UBYTE sID;          /* SEvent type code */
    UBYTE data;         /* sID-dependent data */
    } SEvent;

/* SEvent type codes "sID". */
#define SID_FirstNote     0
#define SID_LastNote    127     /* sIDs in the range SID_FirstNote through
                                 * SID_LastNote (sign bit = 0) are notes. The
                                 * sID is the MIDI tone number (pitch). */
#define SID_Rest        128     /* a rest; same data format as a note. */

#define SID_Instrument  129     /* set instrument number for this track. */
#define SID_TimeSig     130     /* set time signature for this track. */
#define SID_KeySig      131     /* set key signature for this track. */
#define SID_Dynamic     132     /* set volume for this track. */
#define SID_MIDI_Chnl   133     /* set MIDI channel number (sequencers) */
#define SID_MIDI_Preset 134     /* set MIDI preset number (sequencers) */
#define SID_Clef        135     /* inline clef change. 
                                 * 0=Treble, 1=Bass, 2=Alto, 3=Tenor. */
#define SID_Tempo       136     /* Inline tempo change in beats per minute.*/

/* SID values 144 through 159: reserved for Instant Music SEvents. */

/* The remaining sID values up through 254: reserved for future
 * standardization. */
#define SID_Mark        255     /* SID reserved for an end-mark in RAM. */


/* ---------- SEvent FirstNote..LastNote or Rest -----------------------*/
typedef struct {
    unsigned tone     :8,       /* MIDI tone number 0 to 127; 128 = rest */
             chord    :1,       /* 1 = a chorded note */
             tieOut   :1,       /* 1 = tied to the next note or chord */
             nTuplet  :2,       /* 0 = none, 1 = triplet, 2 = quintuplet,
                                 * 3 = septuplet */
             dot      :1,       /* dotted note; multiply duration by 3/2 */
             division :3;       /* basic note duration is 2**-division:
                                 * 0 = whole note, 1 = half note, 2 = quarter
                                 * note, ... 7 = 128th note */
    } SNote;

/* Warning: An SNote is supposed to be a 16-bit entity.
 * Some C compilers will not pack bit fields into anything smaller
 * than an int. So avoid the actual use of this type unless you are certain
 * that the compiler packs it into a 16-bit word.
 */


/* You may get better object code by masking, ORing, and shifting using the
 * following definitions rather than the bit-packed fields, above. */
#define noteChord  (1<<7)       /* note is chorded to next note */

#define noteTieOut (1<<6)       /* note/chord is tied to next note/chord */

#define noteNShift 4                    /* shift count for nTuplet field */
#define noteN3     (1<<noteNShift)      /* note is a triplet */
#define noteN5     (2<<noteNShift)      /* note is a quintuplet */
#define noteN7     (3<<noteNShift)      /* note is a septuplet */
#define noteNMask  noteN7               /* bit mask for the nTuplet field */

#define noteDot    (1<<3)               /* note is dotted */

#define noteDShift 0                    /* shift count for division field */
#define noteD1     (0<<noteDShift)      /* whole note division */
#define noteD2     (1<<noteDShift)      /* half note division */
#define noteD4     (2<<noteDShift)      /* quarter note division */
#define noteD8     (3<<noteDShift)      /* eighth note division */
#define noteD16    (4<<noteDShift)      /* sixteenth note division */
#define noteD32    (5<<noteDShift)      /* thirty-secondth note division */
#define noteD64    (6<<noteDShift)      /* sixty-fourth note division */
#define noteD128   (7<<noteDShift)      /* 1/128 note division */
#define noteDMask  noteD128             /* bit mask for the division field */

#define noteDurMask 0x3F                /* bit mask for all duration fields
                                         * division, nTuplet, dot */

/* Field access: */
#define IsChord(snote)  (((UWORD)snote) & noteChord)
#define IsTied(snote)   (((UWORD)snote) & noteTieOut)
#define NTuplet(snote)  ((((UWORD)snote) & noteNMask) >> noteNShift)
#define IsDot(snote)    (((UWORD)snote) & noteDot)
#define Division(snote) ((((UWORD)snote) & noteDMask) >> noteDShift)

/* ---------- TimeSig SEvent -------------------------------------------*/
typedef struct {
    unsigned type     :8,       /* = SID_TimeSig */
             timeNSig :5,       /* time signature "numerator" timeNSig + 1 */
             timeDSig :3;       /* time signature "denominator" is
                                 * 2**timeDSig: 0 = whole note, 1 = half
                                 * note, 2 = quarter note, ...
                                 * 7 = 128th note */
    } STimeSig;

#define timeNMask  0xF8         /* bit mask for timeNSig field */
#define timeNShift 3            /* shift count for timeNSig field */

#define timeDMask  0x07         /*  bit mask for timeDSig field */

/* Field access: */
#define TimeNSig(sTime)  ((((UWORD)sTime) & timeNMask) >> timeNShift)
#define TimeDSig(sTime)   (((UWORD)sTime) & timeDMask)

/* ---------- KeySig SEvent --------------------------------------------*/
/* "data" value 0 = Cmaj; 1 through 7 = G,D,A,E,B,F#,C#;
 * 8 through 14 = F,Bb,Eb,Ab,Db,Gb,Cb.                                  */

/* ---------- Dynamic SEvent -------------------------------------------*/
/* "data" value is a MIDI key velocity 0..127. */


/* ---------- SMUS Writer Support Routines -----------------------------*/

/* Just call this to write a SHDR chunk. */
#define PutSHDR(iff, ssHdr)  \
    PutCk(iff, ID_SHDR, sizeof(SScoreHeader), (BYTE *)ssHdr)

#endif

apps/24bitDemo/24bitDemo.c

/* 24bitDemo.c 05/91  C. Scheppner CBM
 *
 * Example which creates a 24-bit raster, saves it as a 24-bit ILBM,
 *   then loads it as a brush and shows it to you 4 planes at a time
 *   Optionally (if given a filename) just displays 4 planes at a time.
 *
 * requires linkage with several IFF modules
 * see Makefile
 */

#include "iffp/ilbmapp.h"


#ifdef LATTICE
int CXBRK(void) { return(0); }  /* Disable Lattice CTRL/C handling */
int chkabort(void) { return(0); }  /* really */
#endif

void cleanup(void);
void bye(UBYTE *s,int error);

#define MINARGS 1
char *vers = "\0$VER: 24bitDemo 37.5";
char *Copyright = "24bitDemo v37.5 (Freely Redistributable)";
char *usage = "Usage: 24bitDemo [loadname] (saves/loads if no loadname given)";


struct Library *IntuitionBase  = NULL;
struct Library *GfxBase        = NULL;
struct Library *IFFParseBase   = NULL;

/* Note - these fields are also available in the ILBMInfo structure */
struct   Screen         *scr;         /* for ptr to screen structure */
struct   Window         *win;         /* for ptr to window structure */
struct   RastPort       *wrp;         /* for ptr to RastPort  */
struct   ViewPort       *vp;          /* for ptr to Viewport  */


struct   NewWindow      mynw = {
   0, 0,                                  /* LeftEdge and TopEdge */
   0, 0,                                  /* Width and Height */
   -1, -1,                                /* DetailPen and BlockPen */
   VANILLAKEY|MOUSEBUTTONS,               /* IDCMP Flags with Flags below */
   BACKDROP|BORDERLESS|SMART_REFRESH|NOCAREREFRESH|ACTIVATE|RMBTRAP,
   NULL, NULL,                            /* Gadget and Image pointers */
   NULL,                                  /* Title string */
   NULL,                                  /* Screen ptr null till opened */
   NULL,                                  /* BitMap pointer */
   50, 20,                                /* MinWidth and MinHeight */
   0 , 0,                                 /* MaxWidth and MaxHeight */
   CUSTOMSCREEN                           /* Type of window */
   };


BOOL   FromWb;


/* ILBM Property chunks to be grabbed
 * List BMHD, CMAP and CAMG first so we can skip them when we write
 * the file back out (they will be written out with separate code)
 */
LONG    ilbmprops[] = {
                ID_ILBM, ID_BMHD,
                ID_ILBM, ID_CMAP,
                ID_ILBM, ID_CAMG,
                ID_ILBM, ID_CCRT,
                ID_ILBM, ID_AUTH,
                ID_ILBM, ID_Copyright,
                TAG_END
                };

/* ILBM Collection chunks (more than one in file) to be gathered */
LONG    ilbmcollects[] = {
                ID_ILBM, ID_CRNG,
                TAG_END
                };

/* ILBM Chunk to stop on */
LONG    ilbmstops[] = {
                ID_ILBM, ID_BODY,
                TAG_END
                };


UBYTE nomem[]  = "Not enough memory\n";
UBYTE noiffh[] = "Can't alloc iff\n";


/* For our allocated ILBM frames */
struct ILBMInfo  *ilbm[2];

#define SCRPLANES 4

USHORT colortable[32];
USHORT cstarts[]= { 0x000, 0x800, 0x000, 0x080, 0x000, 0x008 };
USHORT coffs[]  = { 0x100, 0x100, 0x010, 0x010, 0x001, 0x001 };

UBYTE *ilbmname = "RAM:24bit.ilbm";
UBYTE *rgbnames[]={"R0","R1","R2","R3","R4","R5","R6","R7",
                   "G0","G1","G2","G3","G4","G5","G6","G7",
                   "B0","B1","B2","B3","B4","B5","B6","B7" };

UBYTE *endtext1 = "Displayed 24 planes, 4 at a time.";
UBYTE *endtext2 = "Press mousebutton or key to exit.";

/* 
 * MAIN 
 */
void main(int argc, char **argv)
   {
    struct RastPort *rp = NULL;
    struct BitMap dummy = {0};
    struct BitMap *bm = NULL, *xbm, *sbm;
    LONG        error = 0L;
    USHORT      width, height, depth, pwidth, pheight, pmode, extra, rgb;
    ULONG       plsize;
    UBYTE       *tpp;
    BOOL        DoSave = TRUE;
    int         k, p, s, n;

   FromWb = argc ? FALSE : TRUE;

   if((argc > 1)&&(argv[argc-1][0]=='?'))
        {
        printf("%s\n%s\n",Copyright,usage);
        bye("",RETURN_OK);
        }

   if(argc==2)
        {
        ilbmname = argv[1];
        DoSave = FALSE;
        }

   /* Open Libraries */

   if(!(IntuitionBase = OpenLibrary("intuition.library", 0)))
      bye("Can't open intuition library.\n",RETURN_WARN);
      
   if(!(GfxBase = OpenLibrary("graphics.library",0)))
      bye("Can't open graphics library.\n",RETURN_WARN);

   if(!(IFFParseBase = OpenLibrary("iffparse.library",0)))
      bye("Can't open iffparse library.\n",RETURN_WARN);


/* 
 * Alloc ILBMInfo structs
 */
    if(!(ilbm[0] = (struct ILBMInfo *)
        AllocMem(sizeof(struct ILBMInfo),MEMF_PUBLIC|MEMF_CLEAR))) 
                bye(nomem,RETURN_FAIL);
    if(!(ilbm[1] = (struct ILBMInfo *)
        AllocMem(sizeof(struct ILBMInfo),MEMF_PUBLIC|MEMF_CLEAR))) 
                bye(nomem,RETURN_FAIL);

/*
 * Here we set up our ILBMInfo fields for our
 * application.
 * Above we have defined the propery and collection chunks
 * we are interested in (some required like BMHD)
 */

    ilbm[0]->ParseInfo.propchks         = ilbmprops;
    ilbm[0]->ParseInfo.collectchks      = ilbmcollects;
    ilbm[0]->ParseInfo.stopchks         = ilbmstops;

    ilbm[0]->windef     = &mynw;

    *ilbm[1] = *ilbm[0];


/* 
 * Alloc IFF handles for frame
 */
    if(!(ilbm[0]->ParseInfo.iff = AllocIFF())) bye(noiffh,RETURN_FAIL);
    if(!(ilbm[1]->ParseInfo.iff = AllocIFF())) bye(noiffh,RETURN_FAIL);


/* for saving our demo 24-bit ILBM */

    width  = 320;
    height = 200;
    depth  = 24;

    /* Page width, height, and mode for saved ILBM */
    pwidth  = width  < 320 ? 320 : width;
    pheight = height < 200 ? 200 : height;
    pmode   = pwidth >= 640  ? HIRES : 0L;
    pmode  |= pheight >= 400 ? LACE  : 0L;

    plsize = RASSIZE(width,height);

    if(!DoSave) goto nosave;

    /*
     * Allocate Bitmap and planes
     */
    extra = depth > 8 ? depth - 8 : 0;
    if(ilbm[0]->brbitmap = AllocMem(sizeof(struct BitMap) + (extra<<2),
                                MEMF_CLEAR))
        {
        bm = ilbm[0]->brbitmap;
        InitBitMap(bm,depth,width,height);
        for(k=0, error=0; k<depth && (!error); k++) 
            {
            if(!(bm->Planes[k] = AllocRaster(width,height)))
                        error = IFFERR_NOMEM;
            if(! error)
                {
                BltClear(bm->Planes[k], RASSIZE(width,height),0);
                }
            }

        if(!error)
            {
            if(!(rp = AllocMem(sizeof(struct RastPort),MEMF_CLEAR)))
                error = IFFERR_NOMEM;
            else
                {
                InitRastPort(rp);
                rp->BitMap = bm;
                rp->Mask = 0x01;        /* we'll render 1 plane at a time */
                SetAPen(rp,1);
                SetDrMd(rp,JAM1);
                }
            }

        if(!error)
            {
            /* Put something recognizable in the planes.
             * Our bitmap is not part of a screen or viewport
             * so we can fiddle with the pointers and depth
             */
            tpp = bm->Planes[0];        /* save first plane pointer */
            bm->Depth = 1;
            for(k=0; k<depth; k++)      /* swap in planeptrs 1 at a time */
                {
                bm->Planes[0] = bm->Planes[k];
                Move(rp,k * 10, (k * 8) + 8);   /* render rgb bitname text */
                Text(rp, rgbnames[k], 2);
                }
            bm->Depth = depth;          /* restore depth */
            bm->Planes[0] = tpp;        /* and first pointer */

            /* Save the 24-bit ILBM */
            printf("Saving %s\n",ilbmname);
            error = saveilbm(ilbm[0], ilbm[0]->brbitmap, pmode,
                width,  height, pwidth, pheight,
                NULL, 0, 0,     /* colortable */
                mskNone, 0,     /* masking, transparent */
                NULL, NULL,     /* chunklists */
                ilbmname);
            }

        /* Free our bitmap */
        for(k=0; k<depth; k++) 
            {
            if(ilbm[0]->brbitmap->Planes[k])
                        FreeRaster(ilbm[0]->brbitmap->Planes[k],width,height);
            }
        FreeMem(ilbm[0]->brbitmap, sizeof(struct BitMap) + (extra << 2));
        ilbm[0]->brbitmap = NULL;
        if(rp)  FreeMem(rp, sizeof(struct RastPort));
        }

    if(error)
        {
        printf("%s\n",IFFerr(error));
        bye(" ", RETURN_FAIL);
        }

nosave:

/* Normally you would use showilbm() to open an appropriate acreen
 * and display an ILBM in it.  However, this is a 24-bit ILBM
 * so we will load it as a brush (bitmap).
 * Here we are demonstrating
 *  - first querying an ILBM to get its BMHD and CAMG (real or computed)
 *  - then opening our own display
 *  - then loading the 24-bit ILBM as a brush (bitmap) and displaying
 *      it 4 planes at a time in our 4-plane screen.
 */

    printf("Attempting to load %s as a bitmap and display 4 planes at a time\n",
                ilbmname);

    if(!(error = queryilbm(ilbm[0],ilbmname)))
        {
        D(bug("24bitDemo: after query, this ILBM is %ld x %ld x %ld,modeid=$%lx\n",
          ilbm[0]->Bmhd.w, ilbm[0]->Bmhd.h, ilbm[0]->Bmhd.nPlanes, ilbm[0]->camg));

        /* Note - you could use your own routines to open your
         * display, but if so, you must initialize ilbm[0]->scr,
         * ilbm[0]->win, ilbm[0]->wrp, ilbm[0]->srp, and ilbm[0]->vp for your
         * display.  Here we will use opendisplay() which will initialize
         * those fields.
         */

        if(!(opendisplay(ilbm[0],
                        MAX(ilbm[0]->Bmhd.pageWidth, ilbm[0]->Bmhd.w),
                        MAX(ilbm[0]->Bmhd.pageHeight,ilbm[0]->Bmhd.h),
                        MIN(ilbm[0]->Bmhd.nPlanes, SCRPLANES),
                        ilbm[0]->camg)))
            {
            printf("Failed to open display\n");
            }
        else
            {
            D(bug("24bitDemo: opendisplay (%ld planes) successful\n",SCRPLANES));

            scr = ilbm[0]->scr;
            win = ilbm[0]->win;
            wrp = ilbm[0]->wrp;
            vp  = ilbm[0]->vp;

            if(!(error = loadbrush(ilbm[1], ilbmname)))
                {
                D(bug("24bitDemo: loadbrush successful\n"));

                /* Note - we don't need to examine or copy any
                 * chunks from the file, so we will close file now
                 */
                closeifile(ilbm[0]);
                ScreenToFront(ilbm[0]->scr);

                xbm = &dummy;           /* spare bitmap */
                sbm = &scr->BitMap;     /* screen's bitmap */
                bm = ilbm[1]->brbitmap; /* the 24-plane bitmap */
                depth = bm->Depth;

                InitBitMap(xbm,SCRPLANES,scr->Width,scr->Height);

                /* Show the 24 planes */
                for(p=0; p<depth; p+=SCRPLANES) /* 4 at a time */
                    {
                    SetRast(&scr->RastPort, 0);
                    for(s=0; s<SCRPLANES; s++)
                        {
                        if((p+s) < depth) xbm->Planes[s] = bm->Planes[p+s];
                        else              xbm->Planes[s] = NULL, xbm->Depth--;
                        }
                    /* Blit planes to the screen */
                    BltBitMap(xbm, 0, 0,
                              sbm, 0, 0,
                              scr->Width, scr->Height,
                              0xC0, 0x0F, NULL);

                    /* Emulate 8-bit color with 4-bit per gun colors
                     * by using each rgb value twice
                     */
                    for(n=0, rgb=cstarts[p /SCRPLANES]; n < 16; n++)
                        {
                        if(!n)  colortable[n] = 0xFFF;
                        else    colortable[n] = rgb;
                        /* bump gun for every 2 planes since
                         * we only have 8 bits per gun
                         */
                        if(n & 1)  rgb += coffs[ p / SCRPLANES];
                        }
                    LoadRGB4(vp, colortable, 16);
                    Delay(50);
                    }

                SetRast(&scr->RastPort, 0);

                SetAPen(wrp, 1);
                Move(wrp, 24, 80);
                Text(wrp, endtext1, strlen(endtext1));
                Move(wrp, 24, 120);
                Text(wrp, endtext2, strlen(endtext2));

                Wait(1<<win->UserPort->mp_SigBit);
                unloadbrush(ilbm[1]);   /* deallocs colors, closeifile if needed */
                }
            closedisplay(ilbm[0]);
            printf("Done\n");
            }
        }

    if(error)   printf("%s\n",IFFerr(error));

    cleanup();
    exit(RETURN_OK);
    }



void bye(UBYTE *s,int error)
   {
   if((*s)&&(!FromWb)) printf("%s\n",s);
   cleanup();
   exit(error);
   }


void cleanup()
   {
   if(ilbm[0])
        {
        if(ilbm[0]->ParseInfo.iff)      FreeIFF(ilbm[0]->ParseInfo.iff);
        FreeMem(ilbm[0],sizeof(struct ILBMInfo));
        }
   if(ilbm[1])
        {
        if(ilbm[1]->ParseInfo.iff)      FreeIFF(ilbm[1]->ParseInfo.iff);
        FreeMem(ilbm[1],sizeof(struct ILBMInfo));
        }

   if(GfxBase)          CloseLibrary(GfxBase);
   if(IntuitionBase)    CloseLibrary(IntuitionBase);
   if(IFFParseBase)     CloseLibrary(IFFParseBase);
   }

apps/ILBMDemo/ILBMDemo.c

/* ILBMDemo.c  05/91   C. Scheppner CBM
 *
 * Demonstrates displaying an ILBM, loading a brush,
 *   saving an ILBM, and optionally printing a screen (CTRL-p)
 *   Use -c (or -c1, -c2, etc) as filename to read from or save to clipboard.
 *
 * requires linkage with several iffp modules - see Makefile
 */

#include "iffp/ilbmapp.h"


#ifdef LATTICE
int CXBRK(void) { return(0); }  /* Disable Lattice CTRL/C handling */
int chkabort(void) { return(0); }  /* really */
#endif

void chkmsg(void);
void cleanup(void);
void bye(UBYTE *s,int error);

#define SAVECHANGES

#define MINARGS 3
char *vers = "\0$VER: ILBMDemo 37.5";
char *Copyright = "ILBMDemo v37.5 (Freely Redistributable)";
char *usage =
"Usage: ILBMDemo sourceilbm destilbm [brushname]  (CTRL-p to print screen)\n"
"Displays source, optionally loads and blits brush, saves to dest\n"
"Use filename -c[unit] (ie. -c, -c1, -c2, etc.) for clipboard\n";

char *savename;

struct Library *IntuitionBase  = NULL;
struct Library *GfxBase        = NULL;
struct Library *IFFParseBase   = NULL;

/* Note - these fields are also available in the ILBMInfo structure */
struct   Screen         *scr;         /* for ptr to screen structure */
struct   Window         *win;         /* for ptr to window structure */
struct   RastPort       *wrp;         /* for ptr to RastPort  */
struct   ViewPort       *vp;          /* for ptr to Viewport  */

struct   IntuiMessage   *msg;

struct   NewWindow      mynw = {
   0, 0,                                  /* LeftEdge and TopEdge */
   0, 0,                                  /* Width and Height */
   -1, -1,                                /* DetailPen and BlockPen */
   VANILLAKEY|MOUSEBUTTONS,               /* IDCMP Flags with Flags below */
   BACKDROP|BORDERLESS|SMART_REFRESH|NOCAREREFRESH|ACTIVATE|RMBTRAP,
   NULL, NULL,                            /* Gadget and Image pointers */
   NULL,                                  /* Title string */
   NULL,                                  /* Screen ptr null till opened */
   NULL,                                  /* BitMap pointer */
   50, 20,                                /* MinWidth and MinHeight */
   0 , 0,                                 /* MaxWidth and MaxHeight */
   CUSTOMSCREEN                           /* Type of window */
   };


BOOL   FromWb, Done;


/* ILBM Property chunks to be grabbed
 * List BMHD, CMAP and CAMG first so we can skip them when we write
 * the file back out (they will be written out with separate code)
 */
LONG    ilbmprops[] = {
                ID_ILBM, ID_BMHD,
                ID_ILBM, ID_CMAP,
                ID_ILBM, ID_CAMG,
                ID_ILBM, ID_CCRT,
                ID_ILBM, ID_AUTH,
                ID_ILBM, ID_Copyright,
                TAG_END
                };

/* ILBM Collection chunks (more than one in file) to be gathered */
LONG    ilbmcollects[] = {
                ID_ILBM, ID_CRNG,
                TAG_END
                };

/* ILBM Chunk to stop on */
LONG    ilbmstops[] = {
                ID_ILBM, ID_BODY,
                TAG_END
                };


/* For test of adding new chunks to saved FORM */
struct Chunk newchunks[2] = {
        {
        &newchunks[1],
        ID_ILBM, ID_AUTH, IFFSIZE_UNKNOWN,
        "CAS_CBM"},
        {
        NULL,
        ID_ILBM, ID_NAME, IFFSIZE_UNKNOWN,
        "Untitled No. 27"},
        };


UBYTE nomem[]  = "Not enough memory\n";
UBYTE noiffh[] = "Can't alloc iff\n";

/* our indexes to reference our frames
 * DEFault, BRUsh, and SCReen
 */
#define DEF     0
#define BRU     1
#define SCR     2
#define UICOUNT 3

/* For our ILBM frames */
struct ILBMInfo  *ilbms[UICOUNT]  = { NULL };


/* 
 * MAIN 
 */
void main(int argc, char **argv)
   {
#ifdef SAVECHANGES
   struct Chunk *chunk;
   CamgChunk *camg;
   LONG saverror;
#endif
   UBYTE *ilbmname=NULL, *brushname=NULL, ans, c;
   BPTR lock;
   LONG error;

   FromWb = argc ? FALSE : TRUE;

   if((argc<MINARGS)||(argv[argc-1][0]=='?'))
        {
        printf("%s\n%s\n",Copyright,usage);
        bye("",RETURN_OK);
        }

   switch(argc)
      {
      case 4:
         brushname      = argv[3];
      case 3:
         savename       = argv[2];
         ilbmname       = argv[1];
         break;
      }

   /* if dest not clipboard, warn if dest file already exists */
   if(strcmp(savename,"-c"))
        {
        if(lock = Lock(savename,ACCESS_READ))
            {
            UnLock(lock);
            printf("Dest file \"%s\" already exists.  Overwrite (y or n) ? ",
                        savename);
            ans = 0;
            while((c = getchar()) != '\n') if(!ans)  ans = c | 0x20;
            if(ans == 'n')   bye("Exiting.\n",RETURN_OK);
            }
        }
            
   /* Open Libraries */

   if(!(IntuitionBase = OpenLibrary("intuition.library", 0)))
      bye("Can't open intuition library.\n",RETURN_WARN);
      
   if(!(GfxBase = OpenLibrary("graphics.library",0)))
      bye("Can't open graphics library.\n",RETURN_WARN);

   if(!(IFFParseBase = OpenLibrary("iffparse.library",0)))
      bye("Can't open iffparse library.\n",RETURN_WARN);



/* 
 * Alloc three ILBMInfo structs (one each for defaults, screen, brush) 
 */
    if(!(ilbms[0] = (struct ILBMInfo *)
        AllocMem(UICOUNT * sizeof(struct ILBMInfo),MEMF_PUBLIC|MEMF_CLEAR))) 
                bye(nomem,RETURN_FAIL);
    else 
        {
        ilbms[BRU] = ilbms[0] + 1;
        ilbms[SCR] = ilbms[0] + 2;
        }

/*
 * Here we set up default ILBMInfo fields for our
 * application's frames.
 * Above we have defined the propery and collection chunks
 * we are interested in (some required like BMHD)
 * Since all of our frames are for ILBM's, we'll initialize
 * one default frame and clone the others from it.
 */
    ilbms[DEF]->ParseInfo.propchks      = ilbmprops;
    ilbms[DEF]->ParseInfo.collectchks   = ilbmcollects;
    ilbms[DEF]->ParseInfo.stopchks      = ilbmstops;

    ilbms[DEF]->windef  = &mynw;
/* 
 * Initialize our working ILBM frames from our default one
 */
    *ilbms[SCR] = *ilbms[DEF];  /* for our screen */
    *ilbms[BRU] = *ilbms[DEF];  /* for our brush  */

/* 
 * Alloc two IFF handles (one for screen frame, one for brush frame) 
 */
    if(!(ilbms[SCR]->ParseInfo.iff = AllocIFF())) bye(noiffh,RETURN_FAIL);
    if(!(ilbms[BRU]->ParseInfo.iff = AllocIFF())) bye(noiffh,RETURN_FAIL);

/* Load and display an ILBM
 */
    if(error = showilbm(ilbms[SCR],ilbmname))
        {
        printf("Can't load background \"%s\"\n",ilbmname);
        bye("",RETURN_WARN);
        }

    /* These were set up by our successful showilbm() above */
    win = ilbms[SCR]->win;      /* our window */
    wrp = ilbms[SCR]->wrp;      /* our window's RastPort */
    scr = ilbms[SCR]->scr;      /* our screen */
    vp  = ilbms[SCR]->vp;               /* our screen's ViewPort */

    ScreenToFront(scr);


 /* Now let's load a brush and blit it into the window
  */
    if(brushname)
        {
        if (error = loadbrush(ilbms[BRU],brushname))
            {
            printf("Can't load brush \"%s\"\n",brushname);
            bye("",RETURN_WARN);
            }
        else    /* Success */
            {
            D(bug("About to Blt bitmap $%lx to rp $%lx, w=%ld h=%ld\n",
                ilbms[BRU]->brbitmap,wrp,ilbms[BRU]->Bmhd.w,ilbms[BRU]->Bmhd.h));
            BltBitMapRastPort(ilbms[BRU]->brbitmap,0,0,
                                wrp,0,0,
                                ilbms[BRU]->Bmhd.w, ilbms[BRU]->Bmhd.h,
                                0xC0);
            }
        }

#ifdef SAVECHANGES

 /* This code is an example for Read/Modify/Write programs
  *
  * We copy off the parsed chunks we want to preserve,
  * close the IFF read file, reopen it for write,
  * and save a new ILBM which
  * will include the chunks we have preserved, but
  * with newly computed and set-up BMHD, CMAP, and CAMG.
  */ 

   if(!(ilbms[SCR]->ParseInfo.copiedchunks =
        copychunks(ilbms[SCR]->ParseInfo.iff,
                   ilbmprops, ilbmcollects,
                   MEMF_PUBLIC)))
                printf("error cloning chunks\n");
   else
        {
        /* we can close the file now */
        closeifile(ilbms[SCR]);

        printf("Test of copychunks and findchunk:\n");

        /* Find copied CAMG chunk if any */
        if(chunk = findchunk(ilbms[SCR]->ParseInfo.copiedchunks,ID_ILBM,ID_CAMG))
            {
            camg = (CamgChunk *)chunk->ch_Data;
            printf("CAMG: $%08lx\n",camg->ViewModes);
            }
        else printf("No CAMG found\n");

        /* Find copied CRNG chunks if any */
        if(chunk = findchunk(ilbms[SCR]->ParseInfo.copiedchunks,ID_ILBM,ID_CRNG))
            {
            while((chunk)&&(chunk->ch_ID == ID_CRNG))
                {
                printf("Found a CRNG chunk\n");
                chunk = chunk->ch_Next;
                }
            }
        else printf("No CRNG chunks found\n");
        }

    printf("\nAbout to save screen as %s, adding NAME and AUTH chunks\n",
                savename);

    if(saverror = screensave(ilbms[SCR], ilbms[SCR]->scr,
                                ilbms[SCR]->ParseInfo.copiedchunks,
                                newchunks,
                                savename))
                        printf("%s\n",IFFerr(saverror));

#endif

   Done = FALSE;
   while(!Done)
      {
      Wait(1<<win->UserPort->mp_SigBit);
      chkmsg();
      }


   cleanup();
   exit(RETURN_OK);
   }


void chkmsg(void)
    {
    LONG  error;
    ULONG class;
    UWORD code;
    WORD  mousex, mousey;

    while(msg = (struct IntuiMessage *)GetMsg(win->UserPort))
        {
        class = msg->Class;
        code  = msg->Code;
        mousex = msg->MouseX;
        mousey = msg->MouseY;

        ReplyMsg(msg);
        switch(class)
            {
            case MOUSEBUTTONS:
            switch(code)
                {
                /* emulate a close gadget */
                case SELECTDOWN:
                   if((mousex < 12)&&(mousey < 12))     Done = TRUE;
                   break;
                default:
                   break;
                }
            case VANILLAKEY:
            switch(code)
                {
                /* also quit on CTRL-C, CTRL-D, or q */
                case 'q': case 0x04: case 0x03:
                  Done = TRUE;
                  break;
                case 0x10:      /* CTRL-p means print */

                  /* Print the whole screen */
                  if(error=screendump(ilbms[SCR]->scr,
                                0,0,
                                ilbms[SCR]->scr->Width,
                                ilbms[SCR]->scr->Height,
                                0,0))
                        printf("Screendump printer error=%ld\n",error);
                  break;
                        
                default:
                  break;
                }
            default:
            break;
            }
        }
    }


void bye(UBYTE *s,int error)
   {
   if((*s)&&(!FromWb)) printf("%s\n",s);
   cleanup();
   exit(error);
   }


void cleanup()
   {
   if(ilbms[SCR])
        {
        if(ilbms[SCR]->scr)             unshowilbm(ilbms[SCR]);
#ifdef SAVECHANGES
        freechunklist(ilbms[SCR]->ParseInfo.copiedchunks);
#endif
        if(ilbms[SCR]->ParseInfo.iff)   FreeIFF(ilbms[SCR]->ParseInfo.iff);
        }

   if(ilbms[BRU])
        {
        if(ilbms[BRU]->brbitmap)        unloadbrush(ilbms[BRU]);
        if(ilbms[BRU]->ParseInfo.iff)   FreeIFF(ilbms[BRU]->ParseInfo.iff);
        }

   if(ilbms[0])
        {
        FreeMem(ilbms[0],UICOUNT * sizeof(struct ILBMInfo));
        }

   if(GfxBase)       CloseLibrary(GfxBase);
   if(IntuitionBase) CloseLibrary(IntuitionBase);
   if(IFFParseBase)  CloseLibrary(IFFParseBase);
   }

apps/ILBMLoad/ILBMLoad.c

/* ILBMLoad.c 05/91  C. Scheppner CBM
 *
 * Example which
 *  - first queries an ILBM to determine size and mode
 *  - then opens an appropriate screen and window
 *  - then loads the ILBM into the already opened screen
 *
 * For clipboard, use filename -c[unit] (like -c, -c1, -c2, etc.)
 *
 * requires linkage with several IFF modules
 * see Makefile
 */

#include "iffp/ilbmapp.h"


#ifdef LATTICE
int CXBRK(void) { return(0); }  /* Disable Lattice CTRL/C handling */
int chkabort(void) { return(0); }  /* really */
#endif

void cleanup(void);
void bye(UBYTE *s,int error);

#define MINARGS 2
char *vers = "\0$VER: ILBMLoad 37.5";
char *Copyright = "ILBMLoad v37.5 (Freely Redistributable)";
char *usage = "Usage: ILBMLoad ilbmname (-c[unit] for clipboard";


struct Library *IntuitionBase  = NULL;
struct Library *GfxBase        = NULL;
struct Library *IFFParseBase   = NULL;

/* Note - these fields are also available in the ILBMInfo structure */
struct   Screen         *scr;         /* for ptr to screen structure */
struct   Window         *win;         /* for ptr to window structure */
struct   RastPort       *wrp;         /* for ptr to RastPort  */
struct   ViewPort       *vp;          /* for ptr to Viewport  */

struct   IntuiMessage   *msg;

struct   NewWindow      mynw = {
   0, 0,                                  /* LeftEdge and TopEdge */
   0, 0,                                  /* Width and Height */
   -1, -1,                                /* DetailPen and BlockPen */
   VANILLAKEY|MOUSEBUTTONS,               /* IDCMP Flags with Flags below */
   BACKDROP|BORDERLESS|SMART_REFRESH|NOCAREREFRESH|ACTIVATE|RMBTRAP,
   NULL, NULL,                            /* Gadget and Image pointers */
   NULL,                                  /* Title string */
   NULL,                                  /* Screen ptr null till opened */
   NULL,                                  /* BitMap pointer */
   50, 20,                                /* MinWidth and MinHeight */
   0 , 0,                                 /* MaxWidth and MaxHeight */
   CUSTOMSCREEN                           /* Type of window */
   };


BOOL   FromWb;


/* ILBM Property chunks to be grabbed
 * List BMHD, CMAP and CAMG first so we can skip them when we write
 * the file back out (they will be written out with separate code)
 */
LONG    ilbmprops[] = {
                ID_ILBM, ID_BMHD,
                ID_ILBM, ID_CMAP,
                ID_ILBM, ID_CAMG,
                ID_ILBM, ID_CCRT,
                ID_ILBM, ID_AUTH,
                ID_ILBM, ID_Copyright,
                TAG_END
                };

/* ILBM Collection chunks (more than one in file) to be gathered */
LONG    ilbmcollects[] = {
                ID_ILBM, ID_CRNG,
                TAG_END
                };

/* ILBM Chunk to stop on */
LONG    ilbmstops[] = {
                ID_ILBM, ID_BODY,
                TAG_END
                };


UBYTE nomem[]  = "Not enough memory\n";
UBYTE noiffh[] = "Can't alloc iff\n";



/* For our allocated ILBM frame */
struct ILBMInfo  *ilbm;


/* 
 * MAIN 
 */
void main(int argc, char **argv)
   {
   UBYTE *ilbmname=NULL;
   LONG error = 0L;

   FromWb = argc ? FALSE : TRUE;

   if((argc<MINARGS)||(argv[argc-1][0]=='?'))
        {
        printf("%s\n%s\n",Copyright,usage);
        bye("",RETURN_OK);
        }

   ilbmname = argv[1];

   /* Open Libraries */

   if(!(IntuitionBase = OpenLibrary("intuition.library", 0)))
      bye("Can't open intuition library.\n",RETURN_WARN);
      
   if(!(GfxBase = OpenLibrary("graphics.library",0)))
      bye("Can't open graphics library.\n",RETURN_WARN);

   if(!(IFFParseBase = OpenLibrary("iffparse.library",0)))
      bye("Can't open iffparse library.\n",RETURN_WARN);



/* 
 * Alloc one ILBMInfo struct
 */
    if(!(ilbm = (struct ILBMInfo *)
        AllocMem(sizeof(struct ILBMInfo),MEMF_PUBLIC|MEMF_CLEAR))) 
                bye(nomem,RETURN_FAIL);

/*
 * Here we set up our ILBMInfo fields for our
 * application.
 * Above we have defined the propery and collection chunks
 * we are interested in (some required like BMHD)
 */

    ilbm->ParseInfo.propchks    = ilbmprops;
    ilbm->ParseInfo.collectchks = ilbmcollects;
    ilbm->ParseInfo.stopchks    = ilbmstops;

    ilbm->windef        = &mynw;

/* 
 * Alloc IFF handle for frame
 */
    if(!(ilbm->ParseInfo.iff = AllocIFF())) bye(noiffh,RETURN_FAIL);

/* Normally you would use showilbm() to open an appropriate acreen
 * and display an ILBM in it.
 *
 * However, here we are demonstrating
 *  - first querying an ILBM to get its BMHD and CAMG (real or computed)
 *  - then opening our own display
 *  - then loading the ILBM into it
 */

    if(!(error = queryilbm(ilbm,ilbmname)))
        {
        D(bug("ilbmload: after query, this ILBM is %ld x %ld x %ld, modeid=$%lx\n",
                ilbm->Bmhd.w, ilbm->Bmhd.h, ilbm->Bmhd.nPlanes, ilbm->camg));

        /* Note - you could use your own routines to open your
         * display, but if so, you must initialize ilbm->scr,
         * ilbm->win, ilbm->wrp, ilbm->srp, and ilbm->vp for your display.
         * Here we will use opendisplay() which will initialize
         * those fields.
         */
        if(!(opendisplay(ilbm,
                        MAX(ilbm->Bmhd.pageWidth, ilbm->Bmhd.w),
                        MAX(ilbm->Bmhd.pageHeight,ilbm->Bmhd.h),
                        MIN(ilbm->Bmhd.nPlanes,MAXAMDEPTH),
                        ilbm->camg)))
            {
            printf("Failed to open display\n");
            }
        else
            {
            D(bug("ilbmload: opendisplay successful\n"));

            scr = ilbm->scr;
            win = ilbm->win;

            if(!(error = loadilbm(ilbm, ilbmname)))
                {
                D(bug("ilbmload: loadilbm successful\n"));

                /* Note - we don't need to examine or copy any
                 * chunks from the file, so we will close file now
                 */
                closeifile(ilbm);
                ScreenToFront(ilbm->scr);
                Wait(1<<win->UserPort->mp_SigBit);
                unloadilbm(ilbm);       /* deallocs colors, closeifile if needed */
                }
            closedisplay(ilbm);
            }
        }

    if(error)   printf("%s\n",IFFerr(error));

    cleanup();
    exit(RETURN_OK);
    }


void bye(UBYTE *s,int error)
   {
   if((*s)&&(!FromWb)) printf("%s\n",s);
   cleanup();
   exit(error);
   }


void cleanup()
   {
   if(ilbm)
        {
        if(ilbm->ParseInfo.iff)         FreeIFF(ilbm->ParseInfo.iff);
        FreeMem(ilbm,sizeof(struct ILBMInfo));
        }

   if(GfxBase)          CloseLibrary(GfxBase);
   if(IntuitionBase)    CloseLibrary(IntuitionBase);
   if(IFFParseBase)     CloseLibrary(IFFParseBase);
   }

apps/ILBMtoC/ILBMtoC.c

/*--------------------------------------------------------------*/
/*                                                              */
/* ILBMtoC: reads in ILBM, prints out ascii representation,     */
/*  for including in C files.                                   */
/*                                                              */
/* Based on ILBMDump.c by Jerry Morrison and Steve Shaw,        */
/* Electronic Arts.                                             */
/* Jan 31, 1986                                                 */
/*                                                              */
/* This software is in the public domain.                       */
/* This version for the Amiga computer.                         */
/*                                                              */
/*  Callable from CLI ONLY                                      */
/*  modified 05-91 for use wuth iffparse modules                */
/*  Requires linkage with several other modules - see Makefile  */
/*--------------------------------------------------------------*/

#include "iffp/ilbmapp.h"

#ifdef LATTICE
int CXBRK(void) { return(0); }  /* Disable Lattice CTRL/C handling */
int chkabort(void) { return(0); }  /* really */
#endif

char *vers = "\0$VER: ILBMtoC 37.5";
char *Copyright = "ILBMtoC v37.5 (Freely Redistributable)";

void GetSuffix(UBYTE *to, UBYTE *fr);
void bye(UBYTE *s, int e);
void cleanup(void);

struct Library *IFFParseBase = NULL;
struct Library *GfxBase = NULL;

/* ILBM frame */
struct ILBMInfo ilbm = {0};


/* ILBM Property chunks to be grabbed - only BMHD needed for this app
 */
LONG    ilbmprops[] = {
                ID_ILBM, ID_BMHD,
                TAG_END
                };

/* ILBM Collection chunks (more than one in file) to be gathered */
LONG    *ilbmcollects = NULL;   /* none needed for this app */

/* ILBM Chunk to stop on */
LONG    ilbmstops[] = {
                ID_ILBM, ID_BODY,
                TAG_END
                };


UBYTE defSwitch[] = "b";

/** main() ******************************************************************/

void main(int argc, char **argv)
    {
    UBYTE *sw;
    FILE *fp;
    LONG error=NULL;
    UBYTE *ilbmname, name[80], fname[80];

    if ((argc < 2)||(argv[argc-1][0]=='?'))
        {
        printf("Usage from CLI: 'ILBMtoC filename switch-string'\n");
        printf(" where switch-string = \n");
        printf("  <nothing> : Bob format (default)\n");
        printf("  s         : Sprite format (with header and trailer words)\n");
        printf("  sn        : Sprite format (No header and trailer words)\n");
        printf("  a         : Attached sprite (with header and trailer)\n");
        printf("  an        : Attached sprite (No header and trailer)\n");
        printf(" Add 'c' to switch list to output CR's with LF's   \n");
        exit(RETURN_OK);
        }
    

    if(!(GfxBase = OpenLibrary("graphics.library",0)))
        bye("Can't open graphics.library",RETURN_FAIL);

    if(!(IFFParseBase = OpenLibrary("iffparse.library",0)))
        bye("Can't open iffparse.library",RETURN_FAIL);

/*
 * Here we set up default ILBMInfo fields for our
 * application's frames.
 * Above we have defined the propery and collection chunks
 * we are interested in (some required like BMHD)
 */
    ilbm.ParseInfo.propchks      = ilbmprops;
    ilbm.ParseInfo.collectchks   = ilbmcollects;
    ilbm.ParseInfo.stopchks      = ilbmstops;
    if(!(ilbm.ParseInfo.iff = AllocIFF()))
        bye(IFFerr(IFFERR_NOMEM),RETURN_FAIL);  /* Alloc an IFFHandle */

    sw = (argc>2) ? (UBYTE *)argv[2] : defSwitch;
    ilbmname = argv[1];

    if (error = loadbrush(&ilbm,ilbmname))
        {
        printf("Can't load ilbm \"%s\", ifferr=%s\n",ilbmname,IFFerr(error));
        bye("",RETURN_WARN);
        }
    else /* Successfully loaded ILBM */
        {
        printf(" Creating file %s.c \n",argv[1]);
        GetSuffix(name,argv[1]);
        strcpy(fname,argv[1]);
        strcat(fname,".c");
        fp = fopen(fname,"w");
        if(fp)
            {
            BMPrintCRep(ilbm.brbitmap,fp,name,sw);
            fclose(fp);
            }
        else  printf("Couldn't open output file: %s. \n", fname);
        unloadbrush(&ilbm);
        }
    printf("\n");
    bye("",RETURN_OK);
    }



/* this copies part of string after the last '/' or ':' */
void GetSuffix(to, fr) UBYTE *to, *fr; {
    int i;
    UBYTE c,*s = fr;
    for (i=0; ;i++) {
        c = *s++;
        if (c == 0) break;
        if (c == '/') fr = s;
        else if (c == ':') fr = s;
        }
    strcpy(to,fr);
    }


void bye(UBYTE *s, int e)
    {
    if(s&&(*s)) printf("%s\n",s);
    cleanup();
    exit(e);
    }


void cleanup()
    {
    if(ilbm.ParseInfo.iff)              FreeIFF(ilbm.ParseInfo.iff);

    if(IFFParseBase)    CloseLibrary(IFFParseBase);
    if(GfxBase)         CloseLibrary(GfxBase);
    }

apps/ILBMtoRaw/ILBMtoRaw.c

/*--------------------------------------------------------------*/
/*                                                              */
/* ILBMtoRaw: reads in ILBM, writes out raw file (raw planes,   */
/*  followed by colormap)                                       */
/*                                                              */
/* Based on ILBMRaw.c by Jerry Morrison and Steve Shaw,         */
/* Electronic Arts.                                             */
/* Jan 31, 1986                                                 */
/*                                                              */
/* This software is in the public domain.                       */
/* This version for the Amiga computer.                         */
/*                                                              */
/*  Callable from CLI ONLY                                      */
/*  modified 05-91 for use wuth iffparse modules                */
/*  Requires linkage with several other modules - see Makefile  */
/*--------------------------------------------------------------*/

#include "iffp/ilbmapp.h"

#ifdef LATTICE
int CXBRK(void) { return(0); }  /* Disable Lattice CTRL/C handling */
int chkabort(void) { return(0); }  /* really */
#endif

char *vers = "\0$VER: ILBMtoRaw 37.5";
char *Copyright = "ILBMtoRaw v37.5 (Freely Redistributable)";

void bye(UBYTE *s, int e);
void cleanup(void);

LONG SaveBitMap(UBYTE *name, struct BitMap *bm, SHORT *cols, int ncols);

struct Library *IFFParseBase = NULL;
struct Library *GfxBase = NULL;

/* ILBM frame */
struct ILBMInfo ilbm = {0};


/* ILBM Property chunks to be grabbed - BMHD and CMAP needed for this app
 */
LONG    ilbmprops[] = {
                ID_ILBM, ID_BMHD,
                ID_ILBM, ID_CMAP,
                TAG_END
                };

/* ILBM Collection chunks (more than one in file) to be gathered */
LONG    *ilbmcollects = NULL;   /* none needed for this app */

/* ILBM Chunk to stop on */
LONG    ilbmstops[] = {
                ID_ILBM, ID_BODY,
                TAG_END
                };


/** main() ******************************************************************/

void main(int argc, char **argv)
    {
    LONG error=NULL;
    UBYTE *ilbmname, fname[80], buf[24];

    if ((argc < 2)||(argv[argc-1][0]=='?'))
        bye("Usage from CLI: 'ILBMtoRaw filename'\n",RETURN_OK);
    
    if(!(GfxBase = OpenLibrary("graphics.library",0)))
        bye("Can't open graphics.library",RETURN_FAIL);

    if(!(IFFParseBase = OpenLibrary("iffparse.library",0)))
        bye("Can't open iffparse.library",RETURN_FAIL);

/*
 * Here we set up default ILBMInfo fields for our
 * application's frames.
 * Above we have defined the propery and collection chunks
 * we are interested in (some required like BMHD)
 */
    ilbm.ParseInfo.propchks      = ilbmprops;
    ilbm.ParseInfo.collectchks   = ilbmcollects;
    ilbm.ParseInfo.stopchks      = ilbmstops;
    if(!(ilbm.ParseInfo.iff = AllocIFF()))
        bye(IFFerr(IFFERR_NOMEM),RETURN_FAIL);  /* Alloc an IFFHandle */

    ilbmname = argv[1];

    /* Load as a brush since we don't need to display it */
    if (error = loadbrush(&ilbm,ilbmname))
        {
        printf("Can't load ilbm \"%s\", ifferr=%s\n",ilbmname,IFFerr(error));
        bye("",RETURN_WARN);
        }
    else /* Successfully loaded ILBM */
        {
        strcpy(fname,argv[1]);

        if(ilbm.camg & HAM)     strcat(fname, ".ham");
        if(ilbm.camg & EXTRA_HALFBRITE) strcat(fname, ".ehb");

        if(ilbm.camg & HIRES)   strcat(fname, ".hi");
        else strcat(fname, ".lo");

        if(ilbm.camg & LACE)    strcat(fname, ".lace");

        strcat(fname,".");
        sprintf(buf,"%d",ilbm.Bmhd.w);
        strcat(fname,buf);
        strcat(fname,"x");
        sprintf(buf,"%d",ilbm.Bmhd.h);
        strcat(fname,buf);
        strcat(fname,"x");
        sprintf(buf,"%d",ilbm.brbitmap->Depth);
        strcat(fname, buf);
        printf(" Creating file %s \n", fname);
        error=SaveBitMap(fname, ilbm.brbitmap, ilbm.colortable, ilbm.ncolors);

        unloadbrush(&ilbm);
        }

    if(error)   bye(IFFerr(error),RETURN_WARN);
    else        bye("",RETURN_OK);
    }


/* SaveBitMap (as raw planes and colortable)
 *
 * Given filename, bitmap structure, and colortable pointer,
 * writes out raw bitplanes and colortable (not an ILBM)
 * Returns 0 for success
 */


LONG SaveBitMap(UBYTE *name, struct BitMap *bm, SHORT *cols, int ncols)
    {
    SHORT i;
    LONG nb,plsize;

    LONG file = Open( name, MODE_NEWFILE);
    if( file == 0 )
        {
        printf(" couldn't open %s \n",name);
        return(CLIENT_ERROR);   /* couldnt open a load-file */  
        }
    plsize = bm->BytesPerRow*bm->Rows;
    for (i=0; i<bm->Depth; i++)
        {
        nb =  Write(file, bm->Planes[i], plsize);
        if (nb<plsize) break;
        }
    if(nb>0)    nb=Write(file, cols, (1<<bm->Depth)*2); /* save color map */
    Close(file);
    return(nb >= 0 ? 0L : IFFERR_WRITE);
    }

void bye(UBYTE *s, int e)
    {
    if(s&&(*s)) printf("%s\n",s);
    cleanup();
    exit(e);
    }

void cleanup()
    {
    if(ilbm.ParseInfo.iff)              FreeIFF(ilbm.ParseInfo.iff);

    if(IFFParseBase)    CloseLibrary(IFFParseBase);
    if(GfxBase)         CloseLibrary(GfxBase);
    }

apps/Play8SVX/Play8SVX.c

/** Play8SVX.c ************************************************************** 
 * 
 * Read and play sound sample from an IFF file.  21Jan85 
 * 
 * By Steve Hayes, Electronic Arts. 
 * This software is in the public domain. 
 * 
 * Modified 05/91 for use with iffparse & to play notes - CAS_CBM
 * requires linkage with several IFF modules - see Makefile
 ****************************************************************************/ 

#include "iffp/8svxapp.h"

#include <exec/execbase.h>
#include <graphics/gfxbase.h>
#include <clib/alib_protos.h>

#ifdef LATTICE
int CXBRK(void) { return(0); }  /* Disable Lattice CTRL/C handling */
int chkabort(void) { return(0); }  /* really */
#endif

/* prototypes for our functions */
void cleanup(void);
void bye(UBYTE *s,int error);
void DUnpack(BYTE source[], LONG n, BYTE dest[]);
BYTE D1Unpack(BYTE source[], LONG n, BYTE dest[], BYTE x);
LONG LoadSample(struct EightSVXInfo *esvx, UBYTE *filename);
void UnloadSample(struct EightSVXInfo *esvx);
LONG LoadSBody(struct EightSVXInfo *esvx);
void UnloadSBody(struct EightSVXInfo *esvx);

LONG ShowSample(struct EightSVXInfo *esvx);

LONG OpenAudio(void);
void CloseAudio(void);
LONG PlaySample(struct EightSVXInfo *esvx,
                LONG octave, LONG note, UWORD volume, ULONG delay);

struct IOAudio *playbigsample(struct IOAudio *aio0, struct IOAudio *aio1,
                BYTE *samptr, LONG ssize, ULONG period, UWORD volume);

#define MINARGS 2
char *vers = "\0$VER: Play8SVX 37.5";
char *Copyright = "Play8SVX v37.5 (Freely Redistributable)";
char *usage = "Usage: Play8SVX 8SVXname";


/* globals */
struct Library *IFFParseBase   = NULL;
struct Library *GfxBase = NULL;

BOOL   FromWb;

/* 8SVX Property chunks to be grabbed
 */
LONG    esvxprops[] = {
                ID_8SVX, ID_VHDR,
                ID_8SVX, ID_NAME,
                ID_8SVX, ID_ATAK,
                ID_8SVX, ID_RLSE,
                ID_8SVX, ID_AUTH,
                ID_8SVX, ID_Copyright,
                TAG_END
                };

/* 8SVX Collection chunks (more than one in file) to be gathered */
LONG    esvxcollects[] = {
                ID_8SVX, ID_ANNO,
                TAG_END
                };

/* 8SVX Chunk to stop on */
LONG    esvxstops[] = {
                ID_8SVX, ID_BODY,
                TAG_END
                };


UBYTE nomem[]  = "Not enough memory\n";
UBYTE noiffh[] = "Can't alloc iff\n";



/* For our allocated EightSVXInfo */
struct EightSVXInfo  *esvx = NULL;


/* 
 * MAIN 
 */
void main(int argc, char **argv)
   {
   UBYTE *esvxname=NULL;
   ULONG oct;
   LONG error=0L;

   FromWb = argc ? FALSE : TRUE;

   if((argc<MINARGS)||(argv[argc-1][0]=='?'))
        {
        printf("%s\n%s\n",Copyright,usage);
        bye("",RETURN_OK);
        }

   esvxname = argv[1];

/* Open Libraries */
   if(!(IFFParseBase = OpenLibrary("iffparse.library",0)))
      bye("Can't open iffparse library.\n",RETURN_WARN);


/* 
 * Alloc one EightSVXInfo struct
 */
    if(!(esvx = (struct EightSVXInfo *)
        AllocMem(sizeof(struct EightSVXInfo),MEMF_PUBLIC|MEMF_CLEAR))) 
                bye(nomem,RETURN_FAIL);

/*
 * Here we set up our EightSVXInfo fields for our
 * application.
 * Above we have defined the propery and collection chunks
 * we are interested in (some required like VHDR).
 * We want to stop on BODY.
 */
    esvx->ParseInfo.propchks    = esvxprops;
    esvx->ParseInfo.collectchks = esvxcollects;
    esvx->ParseInfo.stopchks    = esvxstops;
/* 
 * Alloc the IFF handle for the frame
 */
    if(!(esvx->ParseInfo.iff = AllocIFF())) bye(noiffh,RETURN_FAIL);


    if(!(error = LoadSample(esvx, esvxname)))
        {
        ShowSample(esvx);

        if(!(error = OpenAudio()))
            {
            /* If we think this is a sound effect, play it as such (note=-1) */
            if((esvx->Vhdr.ctOctave==1)&&(esvx->Vhdr.samplesPerSec)
                &&(esvx->Vhdr.oneShotHiSamples)&&(!esvx->Vhdr.repeatHiSamples))
                {
                PlaySample(esvx,0,-1,64,0);
                }
            /* Else play it like an instrument */
            else
                {
                for(oct=0; oct < esvx->Vhdr.ctOctave; oct++)
                    {
                    PlaySample(esvx,oct,0,64,50);
                    PlaySample(esvx,oct,4,64,50);
                    PlaySample(esvx,oct,7,64,50);
                    }
                }
            CloseAudio();
            }
        else printf("error opening audio device\n");
        }
    else
        printf("%s\n",IFFerr(error));

    cleanup();
    exit(RETURN_OK);
    }


void bye(UBYTE *s,int error)
   {
   if((*s)&&(!FromWb)) printf("%s\n",s);
   cleanup();
   exit(error);
   }


void cleanup()
   {
   if(esvx)             
        {
        DD(bug("About to UnloadSample\n"));
        UnloadSample(esvx);

        DD(bug("About to FreeIFF\n"));
        if(esvx->ParseInfo.iff)         FreeIFF(esvx->ParseInfo.iff);

        DD(bug("About to free EightSVXInfo\n"));
        FreeMem(esvx,sizeof(struct EightSVXInfo));
        }

   if(IFFParseBase)     CloseLibrary(IFFParseBase);
   }

 
/** ShowSample() **********************************************
 * 
 * Show sample information after calling LoadSample()
 * 
 *************************************************************************/
LONG ShowSample(struct EightSVXInfo *esvx)
    {
    LONG error = 0L;
    BYTE *buf;
    Voice8Header *vhdr;

    if(!esvx)                   return(CLIENT_ERROR);
    if(!(buf = esvx->sample))   return(CLIENT_ERROR);

    /* LoadSample copied VHDR and NAME (if any) to our esvx frame */
    vhdr = &esvx->Vhdr;
    if(esvx->name[0]) printf("\nNAME: %s",esvx->name);

    printf("\n\nVHDR Info:");
    printf("\noneShotHiSamples=%ld", vhdr->oneShotHiSamples); 
    printf("\nrepeatHiSamples=%ld", vhdr->repeatHiSamples); 
    printf("\nsamplesPerHiCycle=%ld", vhdr->samplesPerHiCycle); 
    printf("\nsamplesPerSec=%ld", vhdr->samplesPerSec); 
    printf("\nctOctave=%ld", vhdr->ctOctave); 
    printf("\nsCompression=%ld", vhdr->sCompression); 
    printf("\nvolume=0x%lx", vhdr->volume); 
    printf("\nData = %3ld %3ld %3ld %3ld %3ld %3ld %3ld %3ld",  
           buf[0],buf[1],buf[2],buf[3],buf[4],buf[5],buf[6],buf[7]); 
    printf("\n       %3ld %3ld %3ld %3ld %3ld %3ld %3ld %3ld ...\n",  
           buf[8+0],buf[8+1],buf[8+2],buf[8+3],buf[8+4],buf[8+5],
           buf[8+6],buf[8+ 7]); 

    return(error);
    } 
 

/* OpenAudio
 *
 * Opens audio device for one audio channel, 2 IO requests
 * Returns 0 for success
 *
 * Based on code by Dan Baker
 */

UBYTE           whichannel[] = { 1,2,4,8 };

/* periods for scale starting at   65.40Hz (C) with 128 samples per cycle
 *                            or  130.81Hz (C) with  64 samples per cycle
 *                            or  261.63Hz (C) with  32 samples per cycle
 *                            or  523.25Hz (C) with  16 samples per cycle
 *                            or 1046.50Hz (C) with   8 samples per cycle
 *                            or 2093.00Hz (C) with   4 samples per cycle
 */

UWORD   per_ntsc[12]= { 428, 404, 380, 360,
                        340, 320, 302, 286,
                        270, 254, 240, 226 };

/* periods adjusted for system clock frequency */
UWORD   per[12];

/* Note - these values 3579545 NTSC, 3546895 PAL */
#define NTSC_CLOCK 3579545L
#define PAL_CLOCK  3546895L

#define AIOCNT 4
struct  IOAudio *aio[AIOCNT] = {NULL};    /* Ptrs to IO blocks for commands  */

struct  MsgPort *port;          /* Pointer to a port so the device can reply */
BOOL    devopened;
ULONG   clock = NTSC_CLOCK;     /* Will check for PAL and change if necessary */


LONG OpenAudio()
{
extern  struct ExecBase *SysBase;
LONG    error=0L;
ULONG   period;
int     k;

if(devopened)   return(-1);

/*-------------------------------------------------------------------------*/
/* Ask the system if we are PAL or NTSC and set clock constant accordingly */
/*-------------------------------------------------------------------------*/
if(GfxBase=OpenLibrary("graphics.library",0L))
    {
    if(((struct GfxBase *)GfxBase)->DisplayFlags & PAL)
                clock = PAL_CLOCK;
    else
                clock = NTSC_CLOCK;
    CloseLibrary((struct Library *) GfxBase);
    }

printf("OpenAudio: For period calculations, clock=%ld\n", clock);

/* calculate period values for one octave based on system clock */
for(k=0; k<12; k++)
    {
    period = ((per_ntsc[k] * clock) + (NTSC_CLOCK >> 1)) / NTSC_CLOCK;
    per[k] = period;
    D(bug("per[%ld]=%ld ",k,per[k]));
    }
D(bug("\n"));

/*-------------------------------------------------------------------*/
/* Create a reply port so the audio device can reply to our commands */
/*-------------------------------------------------------------------*/
if(!(port=CreatePort(0,0)))
        { error = 1; goto bailout; }

/*--------------------------------------------------------------------------*/
/*  Create audio I/O blocks so we can send commands to the audio device     */
/*--------------------------------------------------------------------------*/
for(k=0; k<AIOCNT; k++)
    {
    if(!(aio[k]=(struct IOAudio *)CreateExtIO(port,sizeof(struct IOAudio))))
        { error = k+2; goto bailout; }
    }

/*----------------------------------------------------------------------*/
/* Set up the audio I/O block for channel allocation:                   */
/* ioa_Request.io_Message.mn_ReplyPort is the address of a reply port.  */
/* ioa_Request.io_Message.mn_Node.ln_Pri sets the precedence (priority) */
/*   of our use of the audio device. Any tasks asking to use the audio  */
/*   device that have a higher precedence will steal the channel from us.*/
/* ioa_Request.io_Command is the command field for IO.                  */
/* ioa_Request.io_Flags is used for the IO flags.                       */
/* ioa_AllocKey will be filled in by the audio device if the allocation */
/*   succeeds. We must use the key it gives for all other commands sent.*/
/* ioa_Data is a pointer to the array listing the channels we want.     */
/* ioa_Length tells how long our list of channels is.                   */
/*----------------------------------------------------------------------*/
aio[0]->ioa_Request.io_Command               = ADCMD_ALLOCATE;
aio[0]->ioa_Request.io_Flags                 = ADIOF_NOWAIT;
aio[0]->ioa_AllocKey                         = 0;
aio[0]->ioa_Data                             = whichannel;
aio[0]->ioa_Length                           = sizeof(whichannel);

/*-----------------------------------------------*/
/* Open the audio device and allocate a channel  */
/*-----------------------------------------------*/
if(!(OpenDevice("audio.device",0L, (struct IORequest *) aio[0] ,0L)))
        devopened = TRUE;
else { error = 5; goto bailout; }

/* Clone the flags, channel allocation, etc. into other IOAudio requests */
for(k=1; k<AIOCNT; k++) *aio[k] = *aio[0];

bailout:
if(error)       
    {
    printf("OpenAudio errored out at step %ld\n",error);
    CloseAudio();
    }
return(error);
}


/* CloseAudio
 *
 * Close audio device as opened by OpenAudio, null out pointers
 */
void CloseAudio()
{
int k;

D(bug("Closing audio device...\n"));

/* Note - we know we have no outstanding audio requests */
if(devopened)
    {
    CloseDevice((struct IORequest *) aio[0]);
    devopened = FALSE;
    }

for(k=0; k<AIOCNT; k++)
    {
    if(aio[k])  DeleteExtIO(aio[k]), aio[k] = NULL;
    }

if(port)        DeletePort(port),  port = NULL;
}


/** PlaySample() **********************************************
 * 
 * Play a note in octave for delay/50ths of a second 
 * OR Play a sound effect (set octave and note to 0, -1)
 *
 * Requires successful OpenAudio() called previously
 *
 * When playing notes:
 * Expects note values between 0 (C) and 11 (B#)
 * Uses largest octave sample in 8SVX as octave 0, next smallest
 *   as octave 1, etc.
 *
 * Notes - this simple example routine does not do ATAK and RLSE)
 *       - use of Delay for timing is simplistic, synchronous, and does
 *              not take into account that the oneshot itself may be
 *              longer than the delay.
 *         Use timer.device for more accurate asynchronous delays
 *
 *************************************************************************/
/* Max playable sample in one IO request is 128K */
#define MAXSAMPLE 131072

LONG    PlaySample(struct EightSVXInfo *esvx,
                        LONG octave, LONG note, UWORD volume, ULONG delay)
{
/* pointers to outstanding requests */
struct          IOAudio *aout0=NULL, *aout1=NULL;       
ULONG           period;
LONG            osize, rsize;
BYTE            *oneshot, *repeat;

if(!devopened)  return(-1);

if(note > 11) note=0;

if( note == -1 ) period = clock / esvx->Vhdr.samplesPerSec;
else             period = per[note]; /* table set up by OpenAudio */

if(octave > esvx->Vhdr.ctOctave) octave = 0;
if(volume > 64) volume = 64;

oneshot = esvx->osamps[octave];
osize   = esvx->osizes[octave];
repeat  = esvx->rsamps[octave];
rsize   = esvx->rsizes[octave];

D(bug("oneshot $%lx size %ld, repeat $%lx size %ld\n",
        oneshot, osize, repeat, rsize));

/*------------------------------------------------------------*/
/* Set up audio I/O blocks to play a sample using CMD_WRITE.  */
/* Set up one request for the oneshot and one for repeat      */
/* (all ready for simple case, but we may not need both)      */
/* The io_Flags are set to ADIOF_PERVOL so we can set the     */
/*    period (speed) and volume with the our sample;          */
/* ioa_Data points to the sample; ioa_Length gives the length */
/* ioa_Cycles tells how many times to repeat the sample       */
/* If you want to play the sample at a given sampling rate,   */
/* set ioa_Period = clock/(given sampling rate)               */
/*------------------------------------------------------------*/
aio[0]->ioa_Request.io_Command             =CMD_WRITE;
aio[0]->ioa_Request.io_Flags               =ADIOF_PERVOL;
aio[0]->ioa_Data                           =oneshot;
aio[0]->ioa_Length                         =osize;
aio[0]->ioa_Period                         =period;
aio[0]->ioa_Volume                         =volume;
aio[0]->ioa_Cycles                         =1;

aio[2]->ioa_Request.io_Command             =CMD_WRITE;
aio[2]->ioa_Request.io_Flags               =ADIOF_PERVOL;
aio[2]->ioa_Data                           =repeat;
aio[2]->ioa_Length                         =rsize;
aio[2]->ioa_Period                         =period;
aio[2]->ioa_Volume                         =volume;
aio[2]->ioa_Cycles                         =0;  /* repeat until stopped */

/*---------------------------------------------------*/
/* Send the command to start a sound using BeginIO() */
/* Go to sleep and wait for the sound to finish with */
/* WaitIO() to wait and get the get the ReplyMsg     */
/*---------------------------------------------------*/
printf("Starting tone O len %ld for %0ld cyc, R len %ld for %0ld cyc, per=%ld...",
                osize, aio[0]->ioa_Cycles, rsize, aio[1]->ioa_Cycles, period);

if(osize)
    {
    /* Simple case for oneshot sample <= 128K (ie. most samples) */
    if(osize <= MAXSAMPLE)      BeginIO((struct IORequest *)(aout0=aio[0]));

    /* Note - this else case code is for samples >128K */
    else
        {
        *aio[1] = *aio[0];
        aout0 = playbigsample(aio[0],aio[1],oneshot,osize,period,volume);
        }
     }

if(rsize)
    {
    /* Simple case for oneshot sample <= 128K (ie. most samples) */
    if(rsize <= MAXSAMPLE)      BeginIO((struct IORequest *)(aout1=aio[2]));

    /* Note - this else case code is for samples >128K */
    else
        {
        *aio[3] = *aio[2];
        aout1 = playbigsample(aio[2],aio[3],repeat,rsize,period,volume);
        }
     }

if(delay)       Delay(delay);   /* crude timing for notes */

/* Wait for any requests we still have out */
if(aout0) WaitIO(aout0);

if(aout1)
   {
   if(note >= 0) AbortIO(aout1);        /* if a note, stop it now */
   WaitIO(aout1);
   }

printf("Done\n");
}


/** playbigsample() ********************************************************
 * 
 *  called by playsample to deal with samples > 128K
 *
 *  wants pointers to two ready-to-use IOAudio iorequest blocks
 *
 *  returns pointer to the IOAudio request that is still out
 *   or NULL if none (error)
 *************************************************************************/

struct IOAudio *playbigsample(struct IOAudio *aio0, struct IOAudio* aio1,
                        BYTE *samptr, LONG ssize, ULONG period, UWORD volume)
{
struct IOAudio *aio[2];
LONG   size;
int    req=0, reqn=1;   /* current and next IOAudio request indexes */

if((!aio0)||(!aio1)||(ssize < MAXSAMPLE))       return(NULL);

aio[req]  = aio0;
aio[reqn] = aio1;

/* start the first 128 K playing */
aio[req]->ioa_Request.io_Command             =CMD_WRITE;
aio[req]->ioa_Request.io_Flags               =ADIOF_PERVOL;
aio[req]->ioa_Data                           =samptr;
aio[req]->ioa_Length                         =MAXSAMPLE;
aio[req]->ioa_Period                         =period;
aio[req]->ioa_Volume                         =volume;
aio[req]->ioa_Cycles                         =1;
BeginIO((struct IORequest*)aio[req]);

for(samptr=samptr + MAXSAMPLE, size = ssize - MAXSAMPLE;
        size > 0;
                samptr += MAXSAMPLE)
    {
    /* queue the next piece of sample */
    reqn = req ^ 1;     /* alternate IO blocks 0 and 1 */
    aio[reqn]->ioa_Request.io_Command             =CMD_WRITE;
    aio[reqn]->ioa_Request.io_Flags               =ADIOF_PERVOL;
    aio[reqn]->ioa_Data                           =samptr;
    aio[reqn]->ioa_Length = (size > MAXSAMPLE) ? MAXSAMPLE : size;
    aio[reqn]->ioa_Period                         =period;
    aio[reqn]->ioa_Volume                         =volume;
    aio[reqn]->ioa_Cycles                         =1;
    BeginIO((struct IORequest*)aio[reqn]);

    /* Wait for previous request to finish */
    WaitIO(aio[req]);
    /* decrement size */
    size = (size > MAXSAMPLE) ? size-MAXSAMPLE : 0;
    req = reqn;         /* switch between aio[0] and aio[1] */
    }
return(aio[reqn]);
}

/** LoadSample() **********************************************************
 * 
 * Read 8SVX, given an initialized EightSVXInfo with not-in-use IFFHandle,
 *   and filename.  Leaves the IFFHandle open so you can FindProp()
 *   additional chunks or copychunks().  You must UnloadSample()
 *   when done.  UnloadSample will closeifile if the file is still
 *   open.
 *
 * Fills in esvx->Vhdr and Name, and allocates/loads esvx->sample,
 *   setting esvx->samplebytes to size for deallocation.
 *
 * Returns 0 for success of an IFFERR (libraries/iffparse.h)
 *************************************************************************/
LONG LoadSample(struct EightSVXInfo *esvx, UBYTE *filename)
    {
    struct IFFHandle *iff;
    struct StoredProperty *sp;
    Voice8Header *vhdr;
    BYTE *oneshot, *repeat;
    ULONG osize, rsize, spcyc;
    int oct;
    LONG error = 0L;

    D(bug("LoadSample:\n"));
    
    if(!esvx)                           return(CLIENT_ERROR);
    if(!(iff=esvx->ParseInfo.iff))      return(CLIENT_ERROR);

    if(!(error = openifile((struct ParseInfo *)esvx, filename, IFFF_READ)))
        {
        printf("Reading '%s'...\n",filename);
        error = parseifile((struct ParseInfo *)esvx,
                        ID_FORM, ID_8SVX,
                        esvx->ParseInfo.propchks,
                        esvx->ParseInfo.collectchks,
                        esvx->ParseInfo.stopchks);

        D(bug("LoadSample: after parseifile - error = %ld\n",error));

        if((!error)||(error == IFFERR_EOC)||(error == IFFERR_EOF))
            {
            if(contextis(iff,ID_8SVX,ID_FORM))
                {
                D(bug("LoadSample: context is 8SVX\n"));
                if(!(sp = FindProp(iff,ID_8SVX,ID_VHDR)))
                    {
                    message("No 8SVX.VHDR!");
                    error = IFFERR_SYNTAX;
                    }
                else
                    {
                    D(bug("LoadSample: Have VHDR\n"));
                    /* copy Voice8Header into frame */
                    vhdr = (Voice8Header *)(sp->sp_Data);
                    *(&esvx->Vhdr) = *vhdr;
                    /* copy name if any */
                    esvx->name[0]='\0';
                    if(sp = FindProp(iff,ID_8SVX,ID_NAME))
                        {
                        strncpy(esvx->name,sp->sp_Data,sp->sp_Size);
                        esvx->name[MIN(sp->sp_Size,79)] = '\0';
                        }
                    error = LoadSBody(esvx);
                    D(bug("LoadSample: After LoadSBody - error = %ld\n",error));
                    if(!error)
                        {
                        osize   = esvx->Vhdr.oneShotHiSamples;
                        rsize   = esvx->Vhdr.repeatHiSamples;
                        spcyc   = esvx->Vhdr.samplesPerHiCycle;
                        if(!spcyc) spcyc = esvx->Vhdr.repeatHiSamples;
                        if(!spcyc) spcyc = 8;

                        oneshot = esvx->sample;

                        for(oct = esvx->Vhdr.ctOctave-1; oct >= 0;
                                 oct--, oneshot+=(osize+rsize),
                                        osize <<= 1, rsize <<=1, spcyc <<=1)
                            {
                            repeat  = oneshot + osize;
                            esvx->osizes[oct] = osize;
                            if(osize) esvx->osamps[oct] = oneshot;
                            else      esvx->osamps[oct] = 0;
                            esvx->rsizes[oct] = rsize;
                            if(rsize) esvx->rsamps[oct] = repeat;
                            else      esvx->rsamps[oct] = 0;
                            esvx->spcycs[oct] = spcyc;

                        D(bug("oneshot $%lx size %ld, repeat $%lx size %ld\n",
                                oneshot, osize, repeat, rsize));

                            }
                        }
                    }
                }
            else
                {
                message("Not an 8SVX\n");
                error = NOFILE;
                }
            }
        }

    if(error)
        {
        closeifile((struct ParseInfo *)esvx);
        UnloadSample(esvx);
        }
    return(error);
    }

 
/** UnloadSample() *******************************************************
 * 
 * Frees and closes everything opened/alloc'd by LoadSample()
 *
 *************************************************************************/
void UnloadSample(struct EightSVXInfo *esvx)
    {
    if(esvx)
        {
        UnloadSBody(esvx);
        closeifile((struct ParseInfo *)esvx);
        }
    }


/** LoadSBody() ***********************************************************
 * 
 * Read a 8SVX Sample BODY into RAM.  
 * 
 *************************************************************************/
LONG LoadSBody(struct EightSVXInfo *esvx)
    {
    struct IFFHandle *iff;
    LONG sbytes, rlen, error = 0L; 
    ULONG memtype;
    Voice8Header *vhdr = &esvx->Vhdr;
    BYTE *t;

    D(bug("LoadSBody:\n"));

    if(!(iff=esvx->ParseInfo.iff))      return(CLIENT_ERROR);
    if(!esvx)                           return(CLIENT_ERROR);

    if(!(currentchunkis(iff,ID_8SVX,ID_BODY)))
        {
        message("LoadSBody: not at BODY!");
        return(IFFERR_READ);
        }

    sbytes  = ChunkMoreBytes(CurrentChunk(iff)); 

    /* if we have to decompress, let's just load it into public mem */
    memtype = vhdr->sCompression ? MEMF_PUBLIC : MEMF_CHIP;

    D(bug("LoadSBody: samplebytes=%ld, compression=%ld\n",
                        sbytes,vhdr->sCompression));
    
    if(!(esvx->sample = (BYTE *)AllocMem(sbytes, memtype))) 
        {
        error = CLIENT_ERROR; 
        }
    else 
        {
        D(bug("LoadSBody: have load buffer\n"));
        esvx->samplebytes = sbytes; 
        if(rlen=ReadChunkBytes(iff,esvx->sample,sbytes) != sbytes)
            error = IFFERR_READ;

        if(error)
            {
            D(bug("LoadSBody: ReadChunkBytes error = %ld, read %ld bytes\n",
                        error));
            UnloadSample(esvx);
            }
        else if (vhdr->sCompression) /* Decompress, if needed. */
            { 
            if(t = (BYTE *)AllocMem(sbytes<<1, MEMF_CHIP)) 
                {
                D(bug("LoadSBody: have decompression buffer\n"));
                DUnpack(esvx->sample, sbytes, t); 
                FreeMem(esvx->sample, sbytes); 
                esvx->sample = t;
                esvx->samplebytes = sbytes << 1;
                }
            else
                {
                UnloadSample(esvx);
                error = IFFERR_NOMEM;
                }
            } 
        }
    return(error);
    } 


/** UnloadSBody() ********************************************************
 * 
 * Deallocates esvx->smaple  
 * 
 *************************************************************************/
void UnloadSBody(struct EightSVXInfo *esvx)
    {
    if(esvx)
        {
        if(esvx->sample)
            {
            DD(bug("About to free SBody\n"));
            FreeMem(esvx->sample,esvx->samplebytes);
            esvx->sample = NULL;
            }
        esvx->samplebytes = NULL;
        }
    }
 

/* DUnpack.c --- Fibonacci Delta decompression by Steve Hayes */

/* Fibonacci delta encoding for sound data */
BYTE codeToDelta[16] = {-34,-21,-13,-8,-5,-3,-2,-1,0,1,2,3,5,8,13,21};

/* Unpack Fibonacci-delta encoded data from n byte source
 * buffer into 2*n byte dest buffer, given initial data
 * value x.  It returns the lats data value x so you can
 * call it several times to incrementally decompress the data.
 */

BYTE D1Unpack(BYTE source[], LONG n, BYTE dest[], BYTE x)
   {
   BYTE d;
   LONG i, lim;

   lim = n << 1;
   for (i=0; i < lim; ++i)
      {
      /* Decode a data nibble, high nibble then low nibble */
      d = source[i >> 1];    /* get a pair of nibbles */
      if (i & 1)             /* select low or high nibble */
         d &= 0xf;           /* mask to get the low nibble */
      else
         d >>= 4;            /* shift to get the high nibble */
      x += codeToDelta[d];   /* add in the decoded delta */
      dest[i] = x;           /* store a 1 byte sample */
      }
   return(x);
   }

/* Unpack Fibonacci-delta encoded data from n byte
 * source buffer into 2*(n-2) byte dest buffer.
 * Source buffer has a pad byte, an 8-bit initial
 * value, followed by n-2 bytes comprising 2*(n-2)
 * 4-bit encoded samples.
 */

void DUnpack(source, n, dest)
BYTE source[], dest[];
LONG n;
   {
   D1Unpack(source+2, n-2, dest, source[1]);
   }

apps/RawtoILBM/RawtoILBM.c

/* RawtoILBM
 * Converts raw file (from ILBMtoRaw) into an ILBM
 * Requires linkage with several iffparse modiules - See Makefile
 */ 

#include "iffp/ilbmapp.h"

#include <intuition/intuitionbase.h>
#include <workbench/workbench.h>

#ifdef LATTICE
int CXBRK(void) { return(0); }  /* Disable Lattice CTRL/C handling */
int chkabort(void) { return(0); }  /* really */
#endif

char *vers = "\0$VER: RawtoILBM 37.5";
char *Copyright = 
  "RawtoILBM v37.5 - converts raw file to ILBM - Freely Redistributable";
#define MINARGS 6
char *usage = "Usage: RawtoILBM rawname ilbmname width height depth\n";

void bye(UBYTE *s,int e);
void cleanup(void);

struct Library  *IntuitionBase = NULL;
struct Library  *GfxBase = NULL;
struct Library  *IFFParseBase = NULL;

struct ILBMInfo ilbm = {0};

USHORT  colortable[MAXAMCOLORREG];

BOOL fromWB;


void main(int argc, char **argv)
    {
    LONG        error = 0L, rawfile, rlen;
    USHORT      width, height, depth, pwidth, pheight, pmode, extra;
    ULONG       plsize;
    char        *rawname,*ilbmname;
    int         k;

    fromWB = (argc==0) ? TRUE : FALSE;

    if(!(IntuitionBase = OpenLibrary("intuition.library", 0)))
      bye("Can't open intuition library.\n",RETURN_WARN);
      
    if(!(GfxBase = OpenLibrary("graphics.library",0)))
      bye("Can't open graphics library.\n",RETURN_WARN);

    if(!(IFFParseBase = OpenLibrary("iffparse.library",0)))
      bye("Can't open iffparse library.\n",RETURN_WARN);

    if(!(ilbm.ParseInfo.iff = AllocIFF()))
      bye(IFFerr(IFFERR_NOMEM),RETURN_WARN);

    if(argc==MINARGS)                 /* Passed filenames via command line  */
        {
        rawname  = argv[1];
        ilbmname = argv[2];
        width  = atoi(argv[3]);
        height = atoi(argv[4]);
        depth  = atoi(argv[5]);

        /* Page width, height, and mode for saved ILBM */
        pwidth  = width  < 320 ? 320 : width;
        pheight = height < 200 ? 200 : height;
        pmode   = pwidth >= 640  ? HIRES : 0L;
        pmode  |= pheight >= 400 ? LACE  : 0L;

        plsize = RASSIZE(width,height);
        }
    else
        {
        printf("%s\n%s\n",Copyright,usage);
        bye("\n",RETURN_OK);
        }
     

    if(!(rawfile = Open(rawname,MODE_OLDFILE)))
        {
        printf("Can't open raw file '%s'\n",rawname);
        bye(" ",RETURN_WARN);
        }

    /*
     * Allocate Bitmap and planes
     */
     extra = depth > 8 ? depth - 8 : 0;
     if(ilbm.brbitmap = AllocMem(sizeof(struct BitMap) + (extra<<2),
                                MEMF_CLEAR))
        {
        InitBitMap(ilbm.brbitmap,depth,width,height);
        for(k=0, error=0, rlen=1; k<depth && (!error) && (rlen >0); k++) 
            {
            if(!(ilbm.brbitmap->Planes[k] = AllocRaster(width,height)))
                        error = IFFERR_NOMEM;
            if(! error)
                {
                BltClear(ilbm.brbitmap->Planes[k], RASSIZE(width,height),0);
                /* Read a plane */
                rlen = Read(rawfile,ilbm.brbitmap->Planes[k],plsize);
                }
            }

        /* get colortable */
        if((!error)&&(rlen > 0))
                rlen=Read(rawfile,colortable,(MIN(1<<depth,MAXAMCOLORREG)<<1));

        if((error)||(rlen<=0))
            {
            if(rlen <= 0)       printf("Error loading raw file - check dimensions\n");
            else                printf("Error allocating planes\n");
            }
        else
            {
            error = saveilbm(&ilbm, ilbm.brbitmap, pmode,
                width,  height, pwidth, pheight,
                colortable, MIN(1<<depth,MAXAMCOLORREG), 4,    /* colors */ 
                mskNone, 0,             /* masking. transColor */
                NULL, NULL,             /* additional chunk lists */
                ilbmname);
            }

        for(k=0; k<depth; k++) 
            {
            if(ilbm.brbitmap->Planes[k])
                        FreeRaster(ilbm.brbitmap->Planes[k],width,height);
            }
        FreeMem(ilbm.brbitmap, sizeof(struct BitMap) + (extra << 2));
        }

    Close(rawfile);

    if(error)
        {
        printf("%s\n",IFFerr(error));
        bye(" ", RETURN_FAIL);
        }
    else bye("",RETURN_OK);
    }


void bye(UBYTE *s,int e)
    {
    if(s&&(*s)) printf("%s\n",s);
    if ((fromWB)&&(*s))    /* Wait so user can read messages */
        {
        printf("\nPRESS RETURN TO EXIT\n");
        while(getchar() != '\n');
        }
    cleanup();
    exit(e);
    }

void cleanup()
    {
    if(ilbm.ParseInfo.iff)      FreeIFF(ilbm.ParseInfo.iff);

    if(GfxBase)         CloseLibrary(GfxBase);
    if(IntuitionBase)   CloseLibrary(IntuitionBase);
    if(IFFParseBase)    CloseLibrary(IFFParseBase);
    }

apps/ScreenSave/ScreenSave.c

/* ScreenSave
 * Saves front screen as an ILBM
 * Requires linkage with several iffparse modiules - See Makefile
 */ 

#include "iffp/ilbmapp.h"

#include <intuition/intuitionbase.h>
#include <workbench/workbench.h>

#include <clib/icon_protos.h>

#ifdef LATTICE
int CXBRK(void) { return(0); }  /* Disable Lattice CTRL/C handling */
int chkabort(void) { return(0); }  /* really */
#endif

char *vers = "\0$VER: screensave 37.5";
char *Copyright = 
  "screensave v37.5 - supports new modes - Freely Redistributable";
char *usage =
 "Usage: screensave filename (filename -c[unit] for clipboard)\n" 
 "Options: QUIET, NODELAY, NOICON, SEQUENCE (sequence adds a number to name)\n"
 "Saves front screen after 10-sec delay (unless NODELAY).\n";

int mygets(char *s);
void bye(UBYTE *s,int e);
void cleanup(void);

struct Library  *IntuitionBase = NULL;
struct Library  *GfxBase = NULL;
struct Library  *IconBase = NULL;
struct Library  *IFFParseBase = NULL;

struct ILBMInfo ilbm = {0};

BOOL fromWB, Quiet, NoDelay, NoIcon, Sequence;



#define INBUFSZ 128
char nbuf[INBUFSZ];

/* Data for project icon for saved ILBM
 *
 */
UWORD ILBMI1Data[] =
{
/* Plane 0 */
    0x0000,0x0000,0x0000,0x0001,0x0000,0x0000,0x0000,0x0003,
    0x0FFF,0xFFFF,0xFFFF,0xFFF3,0x0FFF,0x0000,0x0000,0xFFF3,
    0x0FFC,0x0000,0x0000,0x3FF3,0x0FE0,0x0E80,0xF800,0x07F3,
    0x0F80,0x1C01,0x8C00,0x01F3,0x0F00,0x0001,0x8C00,0x00F3,
    0x0600,0x0000,0x0600,0x0063,0x0600,0x0003,0xBC00,0x0063,
    0x0600,0x0001,0xFC00,0x0063,0x0600,0x0000,0xFC00,0x0063,
    0x0600,0x1FC1,0xFE40,0x0063,0x0600,0x1DC1,0xFE20,0x0063,
    0x0600,0x1CE3,0xFF12,0x0063,0x0F00,0x1CE0,0x004F,0xC0F3,
    0x0F80,0x1CE0,0x002F,0x01F3,0x0FE0,0x0E78,0x423D,0x07F3,
    0x0FFC,0x0000,0x0000,0x3FF3,0x0FFF,0x0000,0x0000,0xFFF3,
    0x0FFF,0xFFFF,0xFFFF,0xFFF3,0x0000,0x0000,0x0000,0x0003,
    0x7FFF,0xFFFF,0xFFFF,0xFFFF,
/* Plane 1 */
    0xFFFF,0xFFFF,0xFFFF,0xFFFE,0xD555,0x5555,0x5555,0x5554,
    0xD000,0x0000,0x0000,0x0004,0xD3FC,0xFFFF,0xFFFF,0x3FC4,
    0xD3C0,0x0000,0x0000,0x03C4,0xD300,0x0100,0xF800,0x00C4,
    0xD300,0x0381,0xFC00,0x00C4,0xD080,0x0701,0xFC00,0x0104,
    0xD180,0xF883,0xFE00,0x0194,0xD181,0xDF80,0x4700,0x0194,
    0xD181,0xDF82,0x0180,0x0194,0xD180,0x6F82,0x00C0,0x0194,
    0xD180,0x0002,0x0020,0x0194,0xD180,0x0000,0x0000,0x0194,
    0xD180,0x0000,0x0002,0x0194,0xD080,0x0000,0xCC46,0xC104,
    0xD300,0x0000,0xCC2F,0x00C4,0xD300,0x0E78,0x883D,0x00C4,
    0xD3C0,0x0000,0x0000,0x03C4,0xD3FC,0xFFFF,0xFFFF,0x3FC4,
    0xD000,0x0000,0x0000,0x0004,0xD555,0x5555,0x5555,0x5554,
    0x8000,0x0000,0x0000,0x0000,
};

struct Image ILBMI1 =
{
    0, 0,                       /* Upper left corner */
    64, 23, 2,                  /* Width, Height, Depth */
    ILBMI1Data,                 /* Image data */
    0x0003, 0x0000,             /* PlanePick, PlaneOnOff */
    NULL                        /* Next image */
};

UBYTE *ILBMTools[] =
{
    "FILETYPE=ILBM",
    NULL
};

struct DiskObject ILBMobject =
{
    WB_DISKMAGIC,               /* Magic Number */
    WB_DISKVERSION,             /* Version */
    {                           /* Embedded Gadget Structure */
        NULL,                   /* Next Gadget Pointer */
        0, 0, 64, 24,           /* Left,Top,Width,Height */
        GADGIMAGE | GADGBACKFILL,       /* Flags */
        RELVERIFY | GADGIMMEDIATE,              /* Activation Flags */
        BOOLGADGET,             /* Gadget Type */
        (APTR)&ILBMI1,  /* Render Image */
        NULL,                   /* Select Image */
        NULL,                   /* Gadget Text */
        NULL,                   /* Mutual Exclude */
        NULL,                   /* Special Info */
        0,                      /* Gadget ID */
        NULL,                   /* User Data */
    },
    WBPROJECT,                  /* Icon Type */
    "Display",                  /* Default Tool */
    ILBMTools,                  /* Tool Type Array */
    NO_ICON_POSITION,           /* Current X */
    NO_ICON_POSITION,           /* Current Y */
    NULL,                       /* Drawer Structure */
    NULL,                       /* Tool Window */
    0                           /* Stack Size */
};



void main(int argc, char **argv)
   {
   struct Screen   *frontScreen;
   LONG         error = 0L, seqlock;
   char         *filename;
   int l, k;

   fromWB = (argc==0) ? TRUE : FALSE;


   if(!(IntuitionBase = OpenLibrary("intuition.library", 0)))
      bye("Can't open intuition library.\n",RETURN_WARN);
      
   if(!(GfxBase = OpenLibrary("graphics.library",0)))
      bye("Can't open graphics library.\n",RETURN_WARN);

   if(!(IFFParseBase = OpenLibrary("iffparse.library",0)))
      bye("Can't open iffparse library.\n",RETURN_WARN);

   if(!(IconBase = OpenLibrary("icon.library",0)))
      bye("Can't open icon library.\n",RETURN_WARN);

   if(!(ilbm.ParseInfo.iff = AllocIFF()))
      bye(IFFerr(IFFERR_NOMEM),RETURN_WARN);

   if(argc>1)                 /* Passed filename via command line  */
      {
      if(argv[1][0]=='?') 
            {
            printf("%s\n%s\n",Copyright,usage);
            bye("\n",RETURN_OK);
            }
      else filename = argv[1];

      NoDelay = NoIcon = Quiet = Sequence = FALSE;
      for(k=2; k < (argc); k++)
        {
        if(!(stricmp(argv[k],"NODELAY")))       NoDelay  = TRUE;
        else if(!(stricmp(argv[k],"NOICON")))   NoIcon   = TRUE;
        else if(!(stricmp(argv[k],"QUIET")))    Quiet    = TRUE;
        else if(!(stricmp(argv[k],"SEQUENCE"))) Sequence = TRUE;
        }
      if(Sequence)
        {
        for(k=1; k<9999; k++)
            {
            sprintf(nbuf,"%s%04ld",filename,k);
            if(seqlock = Lock(nbuf,ACCESS_READ))        UnLock(seqlock);
            else break;
            }
        filename = nbuf;
        }
      }
   else
      {
      printf("%s\n%s\n",Copyright,usage);
      printf("Enter filename for save: ");
      l = mygets(&nbuf[0]);

      if(l==0)                /* No filename - Exit */
         {
         bye("\nScreen not saved, filename required\n",RETURN_FAIL);
         }
      else
         {
         filename = &nbuf[0];
         }
      }
     
   if(!NoDelay) Delay(500);

   Forbid();
   frontScreen  = ((struct IntuitionBase *)IntuitionBase)->FirstScreen;
   Permit();

   if(error = screensave(&ilbm, frontScreen,
                                NULL, NULL,
                                filename))
        {
        printf("%s\n",IFFerr(error));
        }
   else
        {
        if(!Quiet) printf("Screen saved as %s... ",filename);
        if((!NoIcon)&&(filename[0]!='-')&&(filename[1]!='c')) /* not clipboard */
            {
            if(!(PutDiskObject(filename,&ILBMobject)))
                {
                bye("Error saving icon\n",RETURN_WARN);
                }
            if(!Quiet) printf("Icon saved\n");
            }
        else if(!Quiet) printf("\n");
        bye("",RETURN_OK);
        }
    }


void bye(UBYTE *s,int e)
   {
   if(s&&(*s)) printf("%s\n",s);
   if ((fromWB)&&(*s))    /* Wait so user can read messages */
      {
      printf("\nPRESS RETURN TO EXIT\n");
      mygets(&nbuf[0]);
      }
   cleanup();
   exit(e);
   }

void cleanup()
   {
   if(ilbm.ParseInfo.iff)       FreeIFF(ilbm.ParseInfo.iff);

   if(GfxBase)          CloseLibrary(GfxBase);
   if(IntuitionBase)    CloseLibrary(IntuitionBase);
   if(IconBase)         CloseLibrary(IconBase);
   if(IFFParseBase)     CloseLibrary(IFFParseBase);
   }


int mygets(char *s)
   {
   int l = 0, max = INBUFSZ - 1;

   while (((*s = getchar()) !='\n' )&&(l < max)) s++, l++;
   *s = NULL;
   return(l);
   }

modules/bmprintc.c

/*--------------------------------------------------------------*/ 
/*                                                              */ 
/*                      bmprintc.c                              */ 
/*                                                              */ 
/* print out a C-language representation of data for bitmap     */ 
/*                                                              */  
/* By Jerry Morrison and Steve Shaw, Electronic Arts.           */ 
/* This software is in the public domain.                       */ 
/*                                                              */ 
/* This version for the Amiga computer.                         */ 
/* Cleaned up and modified a bit by Chuck McManis, Aug 1988     */ 
/* Modified 05/91 by CBM for use with iffparse modules          */
/*                                                              */ 
/*--------------------------------------------------------------*/ 
 
#include "iffp/ilbmapp.h"
#include <stdio.h> 
 
#define NO  0 
#define YES 1 

void PSprite(struct BitMap *bm, FILE *fp, UBYTE *name, int p, BOOL dohead);
void PrCRLF(FILE *fp);
void PrintBob(struct BitMap *bm, FILE *fp, UBYTE *name);
void PrintSprite(struct BitMap *bm, FILE *fp, UBYTE *name,
                 BOOL attach, BOOL dohdr);

static BOOL doCRLF; 
char sp_colors[] = ".oO@";

void PrCRLF(FILE *fp)  
{ 
        if (doCRLF)  
                fprintf(fp, "%c%c", 0xD, 0xA);  
        else 
                fprintf(fp, "\n"); 
} 
     
void PrintBob(struct BitMap *bm, FILE *fp, UBYTE *name)  
{ 
        register UWORD  *wp;    /* Pointer to the bitmap data */ 
 
        short   p,i,j,nb;       /* temporaries */ 
        short   nwords = (bm->BytesPerRow/2)*bm->Rows; 
         
        fprintf(fp, "/*----- bitmap : w = %ld, h = %ld ------ */", 
                    bm->BytesPerRow*8, bm->Rows); 
 
        PrCRLF(fp); 
         
        for (p = 0; p < bm->Depth; ++p) {       /* For each bit plane */ 
                wp = (UWORD *)bm->Planes[p]; 
                fprintf(fp, "/*------ plane # %ld: --------*/", p); 
                PrCRLF(fp); 
                fprintf(fp, "UWORD %s%c[%ld] = { ", name, (p?('0'+p):' '), nwords); 
                PrCRLF(fp); 
                for (j = 0; j < bm->Rows; j++, wp += (bm->BytesPerRow >> 1)) {  
                        fprintf(fp, "   "); 
                        for (nb = 0; nb < (bm->BytesPerRow) >> 1; nb++) 
                                fprintf(fp, "0x%04x,", *(wp+nb)); 
                        if (bm->BytesPerRow <= 6) { 
                                fprintf(fp, "\t/* "); 
                                for (nb = 0; nb < (bm->BytesPerRow) >> 1; nb++) 
                                        for (i=0 ; i<16; i++) 
                                                fprintf(fp, "%c", 
                                            (((*(wp+nb)>>(15-i))&1) ? '*' : '.')); 
                                fprintf(fp, " */"); 
                        } 
                        PrCRLF(fp); 
                 
                } 
                fprintf(fp,"    };"); 
                PrCRLF(fp); 
        } 
} 



void PSprite(struct BitMap *bm, FILE *fp, UBYTE *name, int p, BOOL dohead)  
{ 
        UWORD   *wp0, *wp1;     /* Pointer temporaries  */ 
        short   i, j, nwords,   /* Counter temporaries  */ 
                color;          /* pixel color          */ 
        short   wplen = bm->BytesPerRow/2; 
 
        nwords =  2*bm->Rows + (dohead?4:0); 
        wp0 = (UWORD *)bm->Planes[p]; 
        wp1 = (UWORD *)bm->Planes[p+1]; 
 
        fprintf(fp, "UWORD %s[%ld] = {", name, nwords); 
        PrCRLF(fp); 
 
        if (dohead) { 
                fprintf(fp,"  0x0000, 0x0000, /* VStart, VStop */"); 
                PrCRLF(fp); 
        } 
        for (j=0 ; j < bm->Rows; j++) { 
                fprintf(fp, "  0x%04x, 0x%04x", *wp0, *wp1); 
                if (dohead || (j != bm->Rows-1)) { 
                        fprintf(fp, ","); 
                } 
                fprintf(fp, "\t/*  "); 
                for (i = 0; i < 16; i++) { 
                        color = ((*wp1 >> (14-i)) & 2) + ((*wp0 >> (15-i)) & 1); 
                        fprintf(fp, "%c", sp_colors[color]); 
                } 
                fprintf(fp,"  */"); 
                PrCRLF(fp); 
                wp0 += wplen; 
                wp1 += wplen; 
        } 
        if (dohead)  
                fprintf(fp, "  0x0000, 0x0000 }; /* End of Sprite */"); 
        else  
                fprintf(fp," };");       
        PrCRLF(fp); 
        PrCRLF(fp); 
} 
 
void PrintSprite(struct BitMap *bm, FILE *fp, UBYTE *name,
                 BOOL attach, BOOL dohdr)
{ 
        fprintf(fp,"/*----- Sprite format: h = %ld ------ */", bm->Rows); 
        PrCRLF(fp); 
 
        if (bm->Depth > 1) { 
                fprintf(fp, "/*--Sprite containing lower order two planes:   */"); 
                PrCRLF(fp); 
                PSprite(bm, fp, name, 0, dohdr); 
        } 
        if (attach && (bm->Depth > 3) ) { 
                strcat(name, "1"); 
                fprintf(fp, "/*--Sprite containing higher order two planes:   */"); 
                PrCRLF(fp); 
                PSprite(bm, fp, name, 2, dohdr); 
        }  
} 
 
#define BOB     0 
#define SPRITE  1 

/* BMPrintCRep
 * Passed pointer to BitMap structure, C filehandle opened for write,
 * name associated with file, and string describing the output
 * format desired (see cases below), outputs C representation of the ILBM.
 */
void BMPrintCRep(struct BitMap *bm, FILE *fp, UBYTE *name, UBYTE *fmt)  
{ 
        BOOL attach, doHdr; 
        char c; 
        SHORT type; 
 
        doCRLF = NO; 
        doHdr = YES; 
        type = BOB; 
        attach = NO; 
        while ( (c=*fmt++) != 0 )  
                switch (c) { 
                        case 'b':  
                                type = BOB;  
                                break; 
                        case 's':  
                                type = SPRITE; 
                                attach = NO;  
                                break; 
                        case 'a':  
                                type = SPRITE;  
                                attach = YES;  
                                break; 
                        case 'n':  
                                doHdr = NO;  
                                break; 
                        case 'c':  
                                doCRLF = YES;  
                                break; 
                } 
        switch(type) { 
                case BOB:  
                        PrintBob(bm, fp, name);  
                        break; 
                case SPRITE:   
                        PrintSprite(bm, fp, name, attach, doHdr); 
                        break; 
        } 
}

modules/copychunks.c

/* copychunks
 *
 * For Read/Modify/Write programs and other programs that need
 *   to close the IFF file but still reference gathered chunks.
 * Copies your gathered property and collection chunks
 *   from an iff context so that IFF handle may be
 *   closed right after parsing (allowing file or clipboard to
 *   to be reopened for read or write by self or other programs)
 *
 * The created list of chunks can be modified and written
 *   back out to a new handle with writechunklist().
 *
 * If you have used copychunks(), remember to free the copied
 *   chunks with freechunklist(), when ready, to deallocate them.
 * 
 * Note that this implementation is flat and is suitable only
 *   for simple FORMs.
 */

#include "iffp/iff.h"

/* copychunks()
 *
 * Copies chunks specified in propchks and collectchks
 *   FROM an already-parsed IFFHandle
 *   TO a singly linked list of Chunk structures,
 * and returns a pointer to the start of the list.
 *
 * Generally you would store this pointer in parseInfo.copiedchunks.
 *
 * You must later free the list of copied chunks by calling
 *   FreeChunkList().
 *
 * Reorders collection chunks so they appear in SAME ORDER
 * in chunk list as they did in the file.
 *
 * Returns 0 for failure
 */  
struct Chunk *copychunks(struct IFFHandle *iff,
                        LONG *propchks, LONG *collectchks,
                        ULONG memtype)
    {
    struct Chunk *chunk, *first=NULL, *prevchunk = NULL;
    struct StoredProperty *sp;
    struct CollectionItem *ci, *cii;
    long error;
    int k, kk, bk;

    if(!iff)    return(NULL);

    /* Copy gathered property chunks */
    error = 0;
    for(k=0; (!error) && (propchks) && (propchks[k] != TAG_END); k+=2)
        {
        if(sp=FindProp(iff,propchks[k],propchks[k+1]))
            {
            D(bug("copying %.4s.%.4s chunk\n",&propchks[k],&propchks[k+1]));
 
            if(chunk=(struct Chunk *)
                        AllocMem(sizeof(struct Chunk),memtype|MEMF_CLEAR))
                {
                chunk->ch_Type = propchks[k];
                chunk->ch_ID   = propchks[k+1];
                if(chunk->ch_Data = AllocMem(sp->sp_Size,memtype))
                    {
                    chunk->ch_Size = sp->sp_Size;
                    CopyMem(sp->sp_Data,chunk->ch_Data,sp->sp_Size);
                    if(prevchunk)       prevchunk->ch_Next = chunk;
                    else                first = chunk;
                    prevchunk = chunk;
                    }
                else
                    {
                    FreeMem(chunk,sizeof(struct Chunk));
                    chunk=NULL;
                    error = 1;
                    }
                }
            else error = 1;
            }
        }

    /* Copy gathered collection chunks in reverse order */
    for(k=0; (!error) && (collectchks) && (collectchks[k] != TAG_END); k+=2)
        {
        if(ci=FindCollection(iff,collectchks[k],collectchks[k+1]))
            {
            D(bug("copying %.4s.%.4s collection\n",&collectchks[k],&collectchks[k+1]));
            for(cii=ci, bk=0; cii; cii=cii->ci_Next)    bk++;

            D(bug(" There are %ld of these, first is at $%lx\n",bk,ci));

            for( bk; bk; bk--)
                {
                for(kk=1, cii=ci; kk<bk; kk++) cii=cii->ci_Next;

                D(bug("  copying number %ld\n",kk));

                if(chunk=(struct Chunk *)
                    AllocMem(sizeof(struct Chunk),memtype|MEMF_CLEAR))
                    {
                    chunk->ch_Type = collectchks[k];
                    chunk->ch_ID   = collectchks[k+1];
                    if(chunk->ch_Data = AllocMem(cii->ci_Size,memtype))
                        {
                        chunk->ch_Size = cii->ci_Size;
                        CopyMem(cii->ci_Data,chunk->ch_Data,cii->ci_Size);
                        if(prevchunk)   prevchunk->ch_Next = chunk;
                        else            first = chunk;
                        prevchunk = chunk;
                        }
                    else
                        {
                        FreeMem(chunk,sizeof(struct Chunk));
                        chunk=NULL;
                        error = 1;
                        }
                    }
                else error = 1;
                }
            }
        }

    if(error)
        {
        if(first) freechunklist(first);
        first = NULL;
        }

    return(first);
    }

/* freechunklist - Free a dynamically allocated Chunk list and
 *   all of its ch_Data.
 *
 * Note - if a chunk's ch_Size is IFFSIZE_UNKNOWN, its ch_Data
 *   will not be deallocated.
 */
void freechunklist(struct Chunk *first)
    {
    struct Chunk *chunk, *next;

    chunk = first;
    while(chunk)
        {
        next = chunk->ch_Next;
        if((chunk->ch_Data)&&(chunk->ch_Size != IFFSIZE_UNKNOWN))
                FreeMem(chunk->ch_Data,chunk->ch_Size);
        FreeMem(chunk, sizeof(struct Chunk));   
        chunk = next;
        }
    }


/* findchunk - find first matching chunk in list of struct Chunks
 *    example  finchunk(pi->copiedchunks,ID_ILBM,ID_CRNG);
 *
 * returns struct Chunk *, or NULL if none found
 */
struct Chunk *findchunk(struct Chunk *first, long type, long id)
    {
    struct Chunk *chunk;

    for(chunk=first; chunk; chunk=chunk->ch_Next)
        {
        if((chunk->ch_Type == type)&&(chunk->ch_ID == id)) return(chunk); 
        }
    return(NULL);
    }


/* writechunklist - write out list of struct Chunk's
 * If data is a null terminated string, you may use
 * IFFSIZE_UNKNOWN as the ch_Szie and strlen(chunk->ch_Data)
 * will be used here as size.
 *
 * Returns 0 for success or an IFFERR
 */
long writechunklist(struct IFFHandle *iff, struct Chunk *first)
    {
    struct Chunk *chunk;
    long size, error = 0;

    D(bug("writechunklist: first chunk pointer = $%lx\n",first));

    for(chunk=first; chunk && (!error); chunk=chunk->ch_Next)
        {
        size  = (chunk->ch_Size == IFFSIZE_UNKNOWN) ?
                        strlen(chunk->ch_Data) :  chunk->ch_Size;
        error = PutCk(iff, chunk->ch_ID, size, chunk->ch_Data);
        D(bug("writechunklist: put %.4s size=%ld, error=%ld\n",
                                &chunk->ch_ID,size, error));
        }
    return(error);
    }

modules/getbitmap.c

/*----------------------------------------------------------------------*
 * GETBITMAP.C  Support routines for reading ILBM files.
 * (IFF is Interchange Format File.)
 *
 * Based on code by Jerry Morrison and Steve Shaw, Electronic Arts.
 * This software is in the public domain.
 * Modified for iffparse.library by CBM 04/90
 * This version for the Amiga computer.
 *----------------------------------------------------------------------*/

#include "iffp/ilbm.h"
#include "iffp/packer.h"
#include "iffp/ilbmapp.h"

/* createbrush
 *
 * Passed an initialized ILBMInfo with a parsed IFFHandle (chunks parsed,
 * stopped at BODY),
 * gets the bitmap and colors
 * Sets up ilbm->brbitmap, ilbm->colortable, ilbm->ncolors
 * Returns 0 for success
 */
LONG createbrush(struct ILBMInfo *ilbm)
        {
        int error;

        error                   = getbitmap(ilbm);
        if(!error) error        = loadbody(ilbm->ParseInfo.iff,
                                                ilbm->brbitmap,&ilbm->Bmhd);
        if(!error)              getcolors(ilbm);
        if(error)               deletebrush(ilbm);
        return(error);
        }

/* deletebrush
 *
 * closes and deallocates created brush bitmap and colors
 */
void deletebrush(ilbm)
struct ILBMInfo         *ilbm;
        {
        freebitmap(ilbm);
        freecolors(ilbm);
        }


/* getbitmap
 *
 * Passed an initialized ILBMInfo with parsed IFFHandle (chunks parsed,
 * stopped at BODY), allocates a BitMap structure and planes just large
 * enough for the BODY.  Generally used for brushes but may be used
 * to load backgrounds without displaying, or to load deep ILBM's.
 * Sets ilbm->brbitmap.  Returns 0 for success.
 */
LONG getbitmap(struct ILBMInfo *ilbm)
        {
        struct IFFHandle        *iff;
        BitMapHeader    *bmhd;
        USHORT                  wide, high;
        LONG  error = NULL;
        int k, extra=0;
        BYTE deep;

        if(!(iff=ilbm->ParseInfo.iff))  return(CLIENT_ERROR);

        ilbm->brbitmap = NULL;

        if (!( bmhd = (BitMapHeader *)
                        findpropdata(iff, ID_ILBM, ID_BMHD)))
                {
                message("No ILBM.BMHD chunk!\n");
                return(IFFERR_SYNTAX);
                }

        *(&ilbm->Bmhd) = *bmhd; /* copy contents of BMHD */

        wide = BitsPerRow(bmhd->w);
        high = bmhd->h;
        deep = bmhd->nPlanes;

        ilbm->camg = getcamg(ilbm);

        D(bug("allocbitmap: bmhd=$%lx wide=%ld high=%ld deep=%ld\n",
                        bmhd,wide,high,deep));
        /*
         * Allocate Bitmap and planes
         */
        extra = deep > 8 ? deep - 8 : 0;
        if(ilbm->brbitmap = AllocMem(sizeof(struct BitMap)+(extra<<2),MEMF_CLEAR))
                {
                InitBitMap(ilbm->brbitmap,deep,wide,high);
                for(k=0; k<deep && (!error); k++) 
                    {
                    if(!(ilbm->brbitmap->Planes[k] = AllocRaster(wide,high))) 
                        error = 1;
                    if(! error)
                        BltClear(ilbm->brbitmap->Planes[k],RASSIZE(wide,high),0);
                    }

                if(error)
                    {
                    message("Failed to allocate raster\n");
                    freebitmap(ilbm);
                    }
                }
        else error = 1;
        return(error);
        }

        
/* freebitmap
 *
 * deallocates ilbm->brbitmap BitMap structure and planes 
 */
void freebitmap(struct ILBMInfo * ilbm)
        {
        int k, extra=0;

        if(ilbm->brbitmap)
                {       
                for(k=0; k< ilbm->brbitmap->Depth; k++) 
                        {
                        if(ilbm->brbitmap->Planes[k]) 
                                FreeRaster(ilbm->brbitmap->Planes[k],
                                        (USHORT)(ilbm->brbitmap->BytesPerRow << 3),
                                        ilbm->brbitmap->Rows);
                        }

                extra = ilbm->brbitmap->Depth > 8 ? ilbm->brbitmap->Depth - 8 : 0;
                FreeMem(ilbm->brbitmap,sizeof(struct BitMap) + (extra << 2));
                ilbm->brbitmap = NULL;
                }
        }

/* end */

modules/getdisplay.c

/*----------------------------------------------------------------------*
 * GETDISPLAY.C  Support routines for reading/displaying ILBM files.
 * (IFF is Interchange Format File.)
 *
 * Based on code by Jerry Morrison and Steve Shaw, Electronic Arts.
 * This software is in the public domain.
 * Modified for iffparse.library by CBM 04/90
 * This version for the Amiga computer.
 *----------------------------------------------------------------------*/

#include "iffp/ilbm.h"
#include "iffp/packer.h"
#include "iffp/ilbmapp.h"

extern struct Library *GfxBase;

/* showilbm
 *
 * Passed an ILBMInfo initilized with with a not-in-use ParseInfo.iff
 *   IFFHandle and desired propchks, collectchks, stopchks, and a filename,
 *   will load and display an ILBM, initializing ilbm->Bmhd, ilbm->camg,
 *   ilbm->scr, ilbm->win, ilbm->vp, ilbm->srp, ilbm->wrp,
 *   ilbm->colortable, and ilbm->ncolors.
 *
 *   Note that ncolors may be more colors than you can LoadRGB4.
 *   Use MIN(ilbm->ncolors,MAXAMCOLORREG) for color count if you change
 *   the colors yourself using 1.3/2.0 functions.
 *
 * Returns 0 for success or an IFFERR (libraries/iffparse.h)
 */

LONG showilbm(struct ILBMInfo *ilbm, UBYTE *filename)
{
LONG error = 0L;

    if(!(ilbm->ParseInfo.iff))  return(CLIENT_ERROR);

    if(!(error = openifile((struct ParseInfo *)ilbm, filename, IFFF_READ)))
        {
        D(bug("showilbm: openifile successful\n"));

        error = parseifile((struct ParseInfo *)ilbm,
                                ID_FORM, ID_ILBM,
                                ilbm->ParseInfo.propchks,
                                ilbm->ParseInfo.collectchks,
                                ilbm->ParseInfo.stopchks);

        if((!error)||(error == IFFERR_EOC)||(error == IFFERR_EOF))
            {
            D(bug("showilbm: parseifile successful\n"));

            if(contextis(ilbm->ParseInfo.iff,ID_ILBM,ID_FORM))
                {
                if(error = createdisplay(ilbm)) deletedisplay(ilbm);
                }
            else
                {
                closeifile((struct ParseInfo *)ilbm);
                message("Not an ILBM\n");
                error = NOFILE;
                }
            }
        }
    return(error);
}


/* unshowilbm
 *
 * frees and closes everything alloc'd/opened by showilbm
 */
void unshowilbm(struct ILBMInfo *ilbm)
{
        deletedisplay(ilbm);
        closeifile((struct ParseInfo *)ilbm);
}



/* createdisplay
 *
 * Passed a initialized ILBMInfo with parsed IFFHandle (chunks parsed,
 * stopped at BODY),
 * opens/allocs the display and colortable, and displays the ILBM.
 *
 * If successful, sets up ilbm->Bmhd, ilbm->camg, ilbm->scr, ilbm->win,
 *   ilbm->vp,  ilbm->wrp, ilbm->srp and also ilbm->colortable and
 *   ilbm->ncolors.
 *
 * Note that ncolors may be more colors than you can LoadRGB4.
 * Use MIN(ilbm->ncolors,MAXAMCOLORREG) for color count if you change
 *   the colors yourself using 1.3/2.0 functions.
 *
 * Returns 0 for success or an IFFERR (libraries/iffparse.h)
 */

LONG createdisplay(struct ILBMInfo *ilbm)
        {
        int error;

        D(bug("createdisplay:\n"));

        error                   = getdisplay(ilbm);

        D(bug("createdisplay: after getdisplay, error = %ld\n", error));

        if(!error)      error   = loadbody(ilbm->ParseInfo.iff,
                                                &ilbm->scr->BitMap,&ilbm->Bmhd);

        D(bug("createdisplay: after loadbody, error = %ld\n", error));

        if(!error)
                { 
                if(!(getcolors(ilbm)))
                   LoadRGB4(ilbm->vp, ilbm->colortable,
                                MIN(ilbm->ncolors,MAXAMCOLORREG));
                }
        if(error)  deletedisplay(ilbm);
        return(error);
        }


/* deletedisplay
 *
 * closes and deallocates created display and colors
 */
void deletedisplay(struct ILBMInfo *ilbm)
        {
        freedisplay(ilbm);
        freecolors(ilbm);
        }



/* getdisplay
 *
 * Passed an initialized ILBMInfo with a parsed IFFHandle (chunks parsed,
 * stopped at BODY),
 * gets the dimensions and mode for the display and calls the external
 * routine opendisplay().  Our opendisplay() is in the screen.c
 * module.  It opens a 2.0 or 1.3, ECS or non-ECS screen and window.
 * It also does 2.0 overscan centering based on the closest user prefs.
 *
 * If successful, sets up ilbm->Bmhd, ilbm->camg, ilbm->scr, ilbm->win,
 *   ilbm->vp, ilbm->wrp, ilbm->srp
 *
 * Returns 0 for success or an IFFERR (libraries/iffparse.h)
 */
LONG getdisplay(struct ILBMInfo *ilbm)
        {
        struct IFFHandle *iff;
        BitMapHeader *bmhd;
        ULONG                           modeid;
        UWORD                           wide, high, deep;


        if(!(iff=ilbm->ParseInfo.iff))  return(CLIENT_ERROR);

        if(!(bmhd = (BitMapHeader *)findpropdata(iff, ID_ILBM, ID_BMHD)))
                {
                message ("No ILBM.BMHD chunk\n");
                return(IFFERR_SYNTAX);
                }

        *(&ilbm->Bmhd)  = *bmhd;

        wide = (RowBytes(bmhd->w)) >= (RowBytes(bmhd->pageWidth)) ?
                bmhd->w : bmhd->pageWidth;
        high = MAX(bmhd->h, bmhd->pageHeight);
        deep = MIN(bmhd->nPlanes,MAXAMDEPTH);

        ilbm->camg = modeid = getcamg(ilbm);

        /*
         * Open the display
         */
        if(!(opendisplay(ilbm,wide,high,deep,modeid)))
                {
                message("Failed to open display.\n");
                return(1);
                }
        return(0);
        }


/* freedisplay
 *
 * closes and deallocates display from getdisplay (not colors)
 */
void freedisplay(struct ILBMInfo *ilbm)
        {
        closedisplay(ilbm);
        }

modules/ilbmr.c

/* ilbmr.c --- ILBM loading routines for use with iffparse */

/*----------------------------------------------------------------------*
 * ILBMR.C  Support routines for reading ILBM files.
 * (IFF is Interchange Format File.)
 *
 * Based on code by Jerry Morrison and Steve Shaw, Electronic Arts.
 * This software is in the public domain.
 * Modified for iffparse.library 05/90
 * This version for the Amiga computer.
 *----------------------------------------------------------------------*/

#include "iffp/ilbm.h"
#include "iffp/packer.h"
#include "iffp/ilbmapp.h"

#define movmem CopyMem

#define MaxSrcPlanes (25)

extern struct Library *GfxBase;

/*---------- loadbody ---------------------------------------------------*/

LONG loadbody(iff, bitmap, bmhd)
struct IFFHandle *iff;
struct BitMap *bitmap;
BitMapHeader *bmhd;
        {
        BYTE *buffer;
        ULONG bufsize;
        LONG error = 1;

        D(bug("In loadbody\n"));

        if(!(currentchunkis(iff,ID_ILBM,ID_BODY)))
            {
            message("ILBM has no BODY\n");      /* Maybe it's a palette */
            return(IFF_OKAY);
            }

        if((bitmap)&&(bmhd))
            {
            D(bug("Have bitmap and bmhd\n"));

            bufsize = MaxPackedSize(RowBytes(bmhd->w)) << 4;
            if(!(buffer = AllocMem(bufsize,0L)))
                {
                D(bug("Buffer alloc of %ld failed\n",bufsize));
                return(IFFERR_NOMEM);
                }
            error = loadbody2(iff, bitmap, NULL, bmhd, buffer, bufsize);
            D(bug("Returned from getbody, error = %ld\n",error));
            }
        FreeMem(buffer,bufsize);
        return(error);
        }


/* like the old GetBODY */
LONG loadbody2(iff, bitmap, mask, bmhd, buffer, bufsize)
struct IFFHandle *iff;
struct BitMap *bitmap;
BYTE *mask;
BitMapHeader *bmhd;
BYTE *buffer;
ULONG bufsize;
   {
   UBYTE srcPlaneCnt = bmhd->nPlanes;   /* Haven't counted for mask plane yet*/
   WORD srcRowBytes = RowBytes(bmhd->w);
   WORD destRowBytes = bitmap->BytesPerRow;
   LONG bufRowBytes = MaxPackedSize(srcRowBytes);
   int nRows = bmhd->h;
   WORD compression = bmhd->compression;
   register int iPlane, iRow, nEmpty;
   register WORD nFilled;
   BYTE *buf, *nullDest, *nullBuf, **pDest;
   BYTE *planes[MaxSrcPlanes]; /* array of ptrs to planes & mask */
   struct ContextNode *cn;

   D(bug("srcRowBytes = %ld\n",srcRowBytes));

   cn = CurrentChunk(iff);

   if (compression > cmpByteRun1)
      return(CLIENT_ERROR);

   D(bug("loadbody2: compression=%ld srcBytes=%ld bitmapBytes=%ld\n",
                compression, srcRowBytes, bitmap->BytesPerRow));
   D(bug("loadbody2: bufsize=%ld bufRowBytes=%ld, srcPlaneCnt=%ld\n",
                        bufsize, bufRowBytes, srcPlaneCnt));

   /* Complain if client asked for a conversion GetBODY doesn't handle.*/
   if ( srcRowBytes  >  bitmap->BytesPerRow  ||
         bufsize < bufRowBytes * 2  ||
         srcPlaneCnt > MaxSrcPlanes )
      return(CLIENT_ERROR);

   D(bug("loadbody2: past conversion checks\n"));

   if (nRows > bitmap->Rows)   nRows = bitmap->Rows;

   D(bug("loadbody2: srcRowBytes=%ld, srcRows=%ld, srcDepth=%ld, destDepth=%ld\n",
                srcRowBytes, nRows, bmhd->nPlanes, bitmap->Depth));
   
   /* Initialize array "planes" with bitmap ptrs; NULL in empty slots.*/
   for (iPlane = 0; iPlane < bitmap->Depth; iPlane++)
      planes[iPlane] = (BYTE *)bitmap->Planes[iPlane];
   for ( ;  iPlane < MaxSrcPlanes;  iPlane++)
      planes[iPlane] = NULL;

   /* Copy any mask plane ptr into corresponding "planes" slot.*/
   if (bmhd->masking == mskHasMask)
        {
        if (mask != NULL)
             planes[srcPlaneCnt] = mask;  /* If there are more srcPlanes than
               * dstPlanes, there will be NULL plane-pointers before this.*/
        else
             planes[srcPlaneCnt] = NULL;  /* In case more dstPlanes than src.*/
        srcPlaneCnt += 1;  /* Include mask plane in count.*/
        }

   /* Setup a sink for dummy destination of rows from unwanted planes.*/
   nullDest = buffer;
   buffer  += srcRowBytes;
   bufsize -= srcRowBytes;

   /* Read the BODY contents into client's bitmap.
    * De-interleave planes and decompress rows.
    * MODIFIES: Last iteration modifies bufsize.*/

   buf = buffer + bufsize;  /* Buffer is currently empty.*/
   for (iRow = nRows; iRow > 0; iRow--)
        {
        for (iPlane = 0; iPlane < srcPlaneCnt; iPlane++)
            {
            pDest = &planes[iPlane];

            /* Establish a sink for any unwanted plane.*/
            if (*pDest == NULL)
                {
                nullBuf = nullDest;
                pDest   = &nullBuf;
                }

            /* Read in at least enough bytes to uncompress next row.*/
            nEmpty  = buf - buffer;       /* size of empty part of buffer.*/
            nFilled = bufsize - nEmpty;   /* this part has data.*/
            if (nFilled < bufRowBytes)
                {
                /* Need to read more.*/

                /* Move the existing data to the front of the buffer.*/
                /* Now covers range buffer[0]..buffer[nFilled-1].*/
                movmem(buf, buffer, nFilled);  /* Could be moving 0 bytes.*/

                if(nEmpty > ChunkMoreBytes(cn))
                    {
                    /* There aren't enough bytes left to fill the buffer.*/
                    nEmpty = ChunkMoreBytes(cn);
                    bufsize = nFilled + nEmpty;  /* heh-heh */
                    }

                /* Append new data to the existing data.*/
                if(ReadChunkBytes(iff, &buffer[nFilled], nEmpty) < nEmpty)
                        return(CLIENT_ERROR);

                buf     = buffer;
                nFilled = bufsize;
                nEmpty  = 0;
                }

            /* Copy uncompressed row to destination plane.*/
            if(compression == cmpNone)
                {
                if(nFilled < srcRowBytes)  return(IFFERR_MANGLED);
                movmem(buf, *pDest, srcRowBytes);
                buf    += srcRowBytes;
                *pDest += destRowBytes;
                }
            else
                {
                /* Decompress row to destination plane.*/
                if ( unpackrow(&buf, pDest, nFilled,  srcRowBytes) )
                    /*  pSource, pDest, srcBytes, dstBytes  */
                        return(IFFERR_MANGLED);
                else *pDest += (destRowBytes - srcRowBytes);
                }
            }
        }
   return(IFF_OKAY);
   }


/* ----------- getcolors ------------- */

/* getcolors - allocates a ilbm->colortable for at least MAXAMCOLORREG
 *      and loads CMAP colors into it, setting ilbm->ncolors to number
 *      of colors actually loaded.
 */ 
LONG getcolors(struct ILBMInfo *ilbm)
        {
        struct IFFHandle        *iff;
        int error = 1;

        if(!(iff=ilbm->ParseInfo.iff))  return(CLIENT_ERROR);

        if(!(error = alloccolortable(ilbm)))
           error = loadcmap(iff, ilbm->colortable, &ilbm->ncolors);
        if(error) freecolors(ilbm);
        D(bug("getcolors: error = %ld\n",error));
        return(error);
        }


/* alloccolortable - allocates ilbm->colortable and sets ilbm->ncolors
 *      to the number of colors we have room for in the table.
 */ 

LONG alloccolortable(struct ILBMInfo *ilbm)
        {
        struct IFFHandle        *iff;
        struct  StoredProperty  *sp;

        LONG    error = CLIENT_ERROR;
        ULONG   ctabsize;
        USHORT  ncolors;

        if(!(iff=ilbm->ParseInfo.iff))  return(CLIENT_ERROR);

        if(sp = FindProp (iff, ID_ILBM, ID_CMAP))
                {
                /*
                 * Compute the size table we need
                 */
                ncolors = sp->sp_Size / 3;              /* how many in CMAP */
                ncolors = MAX(ncolors, MAXAMCOLORREG);

                ctabsize = ncolors * sizeof(Color4);
                if(ilbm->colortable = 
                   (Color4 *)AllocMem(ctabsize,MEMF_CLEAR|MEMF_PUBLIC))
                    {
                    ilbm->ncolors = ncolors;
                    ilbm->ctabsize = ctabsize;
                    error = 0L;
                    }
                else error = IFFERR_NOMEM;
                }
        D(bug("alloccolortable for %ld colors: error = %ld\n",ncolors,error));
        return(error);
        }


void freecolors(struct ILBMInfo *ilbm)
        {
        if(ilbm->colortable)
                {
                FreeMem(ilbm->colortable, ilbm->ctabsize);
                }
        ilbm->colortable = NULL;
        ilbm->ctabsize = 0;
        }



/* Passed IFFHandle, pointer to colortable array, and pointer to
 * a USHORT containing number of colors caller has space to hold,
 * loads the colors and sets pNcolors to the number actually read.
 *
 * NOTE !!! - Old GetCMAP passed a pointer to a UBYTE for pNcolors
 *            This one is passed a pointer to a USHORT
 */
LONG loadcmap(struct IFFHandle *iff, WORD *colortable,USHORT *pNcolors)
        {
        register struct StoredProperty  *sp;
        register LONG                   idx;
        register ULONG                  ncolors;
        register UBYTE                  *rgb;
        LONG                            r, g, b;

        if(!(colortable))
                {
                message("No colortable allocated\n");
                return(1);
                }

        if(!(sp = FindProp (iff, ID_ILBM, ID_CMAP)))    return(1);

        rgb = sp->sp_Data;
        ncolors = sp->sp_Size / sizeofColorRegister;
        if(*pNcolors < ncolors) ncolors = *pNcolors;
        *pNcolors = ncolors;

        idx = 0;
        while (ncolors--) 
                {
                r = (*rgb++ & 0xF0) << 4;
                g = *rgb++ & 0xF0;
                b = *rgb++ >> 4;
                colortable[idx] = r | g | b;
                idx++;
                }
        return(0);
        }

/*
 * Returns CAMG or computed mode for storage in ilbm->camg
 *
 * ilbm->Bmhd structure must be initialized prior to this call.
 */
ULONG getcamg(struct ILBMInfo *ilbm)
        {
        struct IFFHandle *iff;
        struct StoredProperty *sp;
        UWORD  wide,high,deep;
        ULONG modeid = 0L;

        if(!(iff=ilbm->ParseInfo.iff))  return(0L);

        wide = ilbm->Bmhd.pageWidth;
        high = ilbm->Bmhd.pageHeight;
        deep = ilbm->Bmhd.nPlanes;

        D(bug("Getting CAMG for w=%ld h=%ld d=%ld ILBM\n",wide,high,deep));

        /*
         * Grab CAMG's idea of the viewmodes.
         */
        if (sp = FindProp (iff, ID_ILBM, ID_CAMG))
                {
                modeid = (* (ULONG *) sp->sp_Data);

                /* knock bad bits out of old-style 16-bit viewmode CAMGs
                 */
                if((!(modeid & MONITOR_ID_MASK))||
                  ((modeid & EXTENDED_MODE)&&(!(modeid & 0xFFFF0000))))
                   modeid &= 
                    (~(EXTENDED_MODE|SPRITES|GENLOCK_AUDIO|GENLOCK_VIDEO|VP_HIDE));

                /* check for bogus CAMG like DPaintII brushes
                 * with junk in upper word and extended bit
                 * not set in lower word.
                 */
                if((modeid & 0xFFFF0000)&&(!(modeid & 0x00001000))) sp=NULL;
                }

        if(!sp) {
                /*
                 * No CAMG (or bad CAMG) present; use computed modes.
                 */
                if (wide >= 640)        modeid = HIRES;
                if (high >= 400)        modeid |= LACE;
                if (deep == 6)
                        {
                        modeid |= ilbm->EHB ? EXTRA_HALFBRITE : HAM;
                        }
                D(bug("No CAMG found - using mode $%08lx\n",modeid));
                }

        D(bug("getcamg: modeid = $%08lx\n",modeid));
        return(modeid);
        }

modules/ilbmw.c

/*----------------------------------------------------------------------*
 * ILBMW.C  Support routines for writing ILBM files using IFFParse.
 * (IFF is Interchange Format File.)
 *
 * Based on code by Jerry Morrison and Steve Shaw, Electronic Arts.
 * This software is in the public domain.
 *
 * This version for the Amiga computer.
 *----------------------------------------------------------------------*/

#include "iffp/ilbm.h"
#include "iffp/packer.h"

#include <graphics/gfxbase.h>

extern struct Library *GfxBase;

/*---------- initbmhd -------------------------------------------------*/
long initbmhd(BitMapHeader *bmhd, struct BitMap *bitmap,
              WORD masking, WORD compression, WORD transparentColor,
              WORD width, WORD height, WORD pageWidth, WORD pageHeight,
              ULONG modeid)
    {
    extern struct Library *GfxBase;
    struct DisplayInfo DI;

    WORD rowBytes = bitmap->BytesPerRow;

    D(bug("In InitBMHD\n"));

    bmhd->w = width;
    bmhd->h = height;
    bmhd->x = bmhd->y = 0;      /* Default position is (0,0).*/
    bmhd->nPlanes = bitmap->Depth;
    bmhd->masking = masking;
    bmhd->compression = compression;
    bmhd->reserved1 = 0;
    bmhd->transparentColor = transparentColor;
    bmhd->pageWidth = pageWidth;
    bmhd->pageHeight = pageHeight;

    bmhd->xAspect = 0;  /* So we can tell when we've got it */
    if(GfxBase->lib_Version >=36)
        {
        if(GetDisplayInfoData(NULL, (UBYTE *)&DI,
                sizeof(struct DisplayInfo), DTAG_DISP, modeid))
                {
                bmhd->xAspect =  DI.Resolution.x;
                bmhd->yAspect =  DI.Resolution.y;
                }
        }

    /* If running under 1.3 or GetDisplayInfoData failed, use old method
     * of guessing aspect ratio
     */
    if(! bmhd->xAspect)
        {
        bmhd->xAspect =  44;
        bmhd->yAspect =
                ((struct GfxBase *)GfxBase)->DisplayFlags & PAL ? 44 : 52;
        if(modeid & HIRES)      bmhd->xAspect = bmhd->xAspect >> 1;
        if(modeid & LACE)       bmhd->yAspect = bmhd->yAspect >> 1;
        }

    return( IS_ODD(rowBytes) ? CLIENT_ERROR : IFF_OKAY );
    }

/*---------- putcmap ---------------------------------------------------*/
/* This function will accept a table of color values in one of the
 * following forms:
 *  if bitspergun=4,  colortable is words, each with nibbles 0RGB
 *  if bitspergun=8,  colortable is bytes of RGBRGB etc. (like a CMAP)
 *  if bitspergun=32, colortable is ULONGS of RGBRGB etc.
 *     (only the high eight bits of each gun will be written to CMAP)
 */
long putcmap(struct IFFHandle *iff, APTR colortable,
             UWORD ncolors, UWORD bitspergun)   
   {
   long error, offs;
   WORD  *tabw;
   UBYTE *tab8;
   ColorRegister cmapReg;

   D(bug("In PutCMAP\n"));

   if((!iff)||(!colortable))    return(CLIENT_ERROR);

   /* size of CMAP is 3 bytes * ncolors */
   if(error = PushChunk(iff, NULL, ID_CMAP, ncolors * sizeofColorRegister))
        return(error);

   D(bug("Pushed ID_CMAP, error = %ld\n",error));

   if(bitspergun == 4)
        {
        /* Store each 4-bit value n as nn */
        tabw = (UWORD *)colortable; 
        for( ;  ncolors;  --ncolors )
            {
            cmapReg.red    = ( *tabw >> 4 ) & 0xf0;
            cmapReg.red   |= (cmapReg.red >> 4);

            cmapReg.green  = ( *tabw      ) & 0xf0;
            cmapReg.green |= (cmapReg.green >> 4);

            cmapReg.blue   = ( *tabw << 4 ) & 0xf0;
            cmapReg.blue  |= (cmapReg.blue >> 4);

            if((WriteChunkBytes(iff, (BYTE *)&cmapReg, sizeofColorRegister))
                != sizeofColorRegister)
                        return(IFFERR_WRITE);
            ++tabw;
            }
        }
   else if((bitspergun == 8)||(bitspergun == 32))
        {
        tab8 = (UBYTE *)colortable;
        offs = (bitspergun == 8) ? 1 : 4;
        for( ;  ncolors;  --ncolors )
            {
            cmapReg.red   = *tab8;
            tab8 += offs;
            cmapReg.green = *tab8;
            tab8 += offs;
            cmapReg.blue  = *tab8;
            tab8 += offs;
            if((WriteChunkBytes(iff, (BYTE *)&cmapReg, sizeofColorRegister))
                != sizeofColorRegister)
                        return(IFFERR_WRITE);
            }
        }
   else (error = CLIENT_ERROR)

   D(bug("Wrote registers, error = %ld\n",error));

   error = PopChunk(iff);
   return(error);
   }

/*---------- putbody ---------------------------------------------------*/
/* NOTE: This implementation could be a LOT faster if it used more of the
 * supplied buffer. It would make far fewer calls to IFFWriteBytes (and
 * therefore to DOS Write). */
long putbody(struct IFFHandle *iff, struct BitMap *bitmap, BYTE *mask,
             BitMapHeader *bmhd, BYTE *buffer, LONG bufsize)
   {         
   long error;
   LONG rowBytes = bitmap->BytesPerRow;
   int dstDepth = bmhd->nPlanes;
   UBYTE compression = bmhd->compression;
   int planeCnt;                /* number of bit planes including mask */
   register int iPlane, iRow;
   register LONG packedRowBytes;
   BYTE *buf;
   BYTE *planes[MAXSAVEDEPTH + 1]; /* array of ptrs to planes & mask */

   D(bug("In PutBODY\n"));

   if ( bufsize < MaxPackedSize(rowBytes)  ||   /* Must buffer a comprsd row*/
        compression > cmpByteRun1  ||           /* bad arg */
        bitmap->Rows != bmhd->h   ||            /* inconsistent */
        rowBytes != RowBytes(bmhd->w)  ||       /* inconsistent*/
        bitmap->Depth < dstDepth   ||           /* inconsistent */
        dstDepth > MAXSAVEDEPTH )               /* too many for this routine*/
      return(CLIENT_ERROR);

   planeCnt = dstDepth + (mask == NULL ? 0 : 1);

   /* Copy the ptrs to bit & mask planes into local array "planes" */
   for (iPlane = 0; iPlane < dstDepth; iPlane++)
      planes[iPlane] = (BYTE *)bitmap->Planes[iPlane];
   if (mask != NULL)
      planes[dstDepth] = mask;

   /* Write out a BODY chunk header */
   if(error = PushChunk(iff, NULL, ID_BODY, IFFSIZE_UNKNOWN)) return(error);

   /* Write out the BODY contents */
   for (iRow = bmhd->h; iRow > 0; iRow--)  {
      for (iPlane = 0; iPlane < planeCnt; iPlane++)  {

         /* Write next row.*/
         if (compression == cmpNone) {
            if(WriteChunkBytes(iff,planes[iPlane],rowBytes) != rowBytes)
                error = IFFERR_WRITE;
            planes[iPlane] += rowBytes;
            }

         /* Compress and write next row.*/
         else {
            buf = buffer;
            packedRowBytes = packrow(&planes[iPlane], &buf, rowBytes);
            if(WriteChunkBytes(iff,buffer,packedRowBytes) != packedRowBytes)
                error = IFFERR_WRITE;
            }

         if(error)      return(error);
         }
      }

   /* Finish the chunk */
   error = PopChunk(iff);
   return(error);
   }

modules/loadilbm.c

/* loadilbm.c 05/91  C. Scheppner CBM
 *
 * High-level ILBM load routines
 */

#include "iffp/ilbm.h"
#include "iffp/ilbmapp.h"

extern struct Library *GfxBase;

/* loadbrush
 *
 * Passed an initialized ILBMInfo with a not-in-use ParseInfo.iff
 *   IFFHandle and desired propchks, collectchks, and stopchks, and filename,
 *   will load an ILBM as a brush, setting up ilbm->Bmhd, ilbm->camg,
 *   ilbm->brbitmap, ilbm->colortable, and ilbm->ncolors
 *
 *   Note that ncolors may be more colors than you can LoadRGB4.
 *   Use MIN(ilbm->ncolors,MAXAMCOLORREG) for color count if you change
 *   the colors yourself using 1.3/2.0 functions.
 *
 * Returns 0 for success or an IFFERR (libraries/iffparse.h)
 */

LONG loadbrush(struct ILBMInfo *ilbm, UBYTE *filename)
{
LONG error = 0L;

    if(!(ilbm->ParseInfo.iff))  return(CLIENT_ERROR);

    if(!(error = openifile((struct ParseInfo *)ilbm, filename, IFFF_READ)))
        {
        error = parseifile((struct ParseInfo *)ilbm,
                                ID_FORM, ID_ILBM,
                                ilbm->ParseInfo.propchks,
                                ilbm->ParseInfo.collectchks,
                                ilbm->ParseInfo.stopchks);
        if((!error)||(error == IFFERR_EOC)||(error == IFFERR_EOF))
            {
            if(contextis(ilbm->ParseInfo.iff,ID_ILBM,ID_FORM))
                {
                if(error = createbrush(ilbm))   deletebrush(ilbm);
                }
            else
                {
                closeifile((struct ParseInfo *)ilbm);
                message("Not an ILBM\n");
                error = NOFILE;
                }
            }
        }
    return(error);
}


/* unloadbrush
 *
 * frees and close everything alloc'd/opened by loadbrush
 */
void unloadbrush(struct ILBMInfo *ilbm)
{
    closeifile((struct ParseInfo *)ilbm);
    deletebrush(ilbm);
}


/* queryilbm
 *
 * Passed an initilized ILBMInfo with a not-in-use IFFHandle,
 *   and a filename,
 *   will open an ILBM, fill in ilbm->camg and ilbm->bmhd,
 *   and close the ILBM.
 *
 * This allows you to determine if the ILBM is a size and
 *   type you want to deal with.
 *
 * Returns 0 for success or an IFFERR (libraries/iffparse.h)
 */

/* query just wants these chunks */
LONG queryprops[] = { ID_ILBM, ID_BMHD,
                      ID_ILBM, ID_CAMG,
                      TAG_END };

/* scan can stop when a CMAP or BODY is reached */
LONG querystops[] = { ID_ILBM, ID_CMAP,
                      ID_ILBM, ID_BODY,
                      TAG_END };

LONG queryilbm(struct ILBMInfo *ilbm, UBYTE *filename)
{
LONG error = 0L;
BitMapHeader *bmhd;

    if(!(ilbm->ParseInfo.iff))  return(CLIENT_ERROR);

    if(!(error = openifile((struct ParseInfo *)ilbm, filename, IFFF_READ)))
        {
        D(bug("queryilbm: openifile successful\n"));

        error = parseifile((struct ParseInfo *)ilbm,
                        ID_FORM, ID_ILBM,
                        queryprops, NULL, querystops);

        D(bug("queryilbm: after parseifile, error = %ld\n",error));

        if((!error)||(error == IFFERR_EOC)||(error == IFFERR_EOF))
            {
            if(contextis(ilbm->ParseInfo.iff,ID_ILBM,ID_FORM))
                {
                if(bmhd = (BitMapHeader*)
                        findpropdata(ilbm->ParseInfo.iff,ID_ILBM,ID_BMHD))
                    {
                    *(&ilbm->Bmhd) = *bmhd;
                    ilbm->camg = getcamg(ilbm);
                    }
                else error = NOFILE;
                }
            else
                {
                message("Not an ILBM\n");
                error = NOFILE;
                }
            }
        closeifile(ilbm);
        }
    return(error);
}


/* loadilbm
 *
 * Passed a not-in-use IFFHandle, an initialized ILBMInfo, and filename,
 *   will load an ILBM into your already opened ilbm->scr, setting up
 *   ilbm->Bmhd, ilbm->camg, ilbm->colortable, and ilbm->ncolors
 *   and loading the colors into the screen's viewport
 *
 *   Note that ncolors may be more colors than you can LoadRGB4.
 *   Use MIN(ilbm->ncolors,MAXAMCOLORREG) for color count if you change
 *   the colors yourself using 1.3/2.0 functions.
 *
 * Returns 0 for success or an IFFERR (libraries/iffparse.h)
 *
 * NOTE - loadilbm() keeps the IFFHandle open so you can copy
 *   or examine other chunks.  You must call closeifile(iff,ilbm)
 *   to close the file and deallocate the parsed context
 *
 */

LONG loadilbm(struct ILBMInfo *ilbm, UBYTE *filename)
{
LONG error = 0L;


    D(bug("loadilbm:\n"));

    if(!(ilbm->ParseInfo.iff))  return(CLIENT_ERROR);
    if(!ilbm->scr)              return(CLIENT_ERROR);

    if(!(error = openifile((struct ParseInfo *)ilbm, filename, IFFF_READ)))
        {
        D(bug("loadilbm: openifile successful\n"));

        error = parseifile((struct ParseInfo *)ilbm,
                        ID_FORM, ID_ILBM,
                        ilbm->ParseInfo.propchks,
                        ilbm->ParseInfo.collectchks,
                        ilbm->ParseInfo.stopchks);

        D(bug("loadilbm: after parseifile, error = %ld\n",error));

        if((!error)||(error == IFFERR_EOC)||(error == IFFERR_EOF))
            {
            if(contextis(ilbm->ParseInfo.iff,ID_ILBM,ID_FORM))
                {
                error = loadbody(ilbm->ParseInfo.iff,
                                        &ilbm->scr->BitMap, &ilbm->Bmhd);

                D(bug("loadilbm: after loadbody, error = %ld\n",error));

                if(!error)
                    {
                    if(!(getcolors(ilbm)))
                                LoadRGB4(&ilbm->scr->ViewPort,ilbm->colortable,
                                        MIN(ilbm->ncolors,MAXAMCOLORREG));
                    } 
                }
            else
                {
                closeifile((struct ParseInfo *)ilbm);
                message("Not an ILBM\n");
                error = NOFILE;
                }
            }
        }
    return(error);
}


/* unloadilbm
 *
 * frees and closes everything allocated by loadilbm
 */
void unloadilbm(struct ILBMInfo *ilbm)
{
    closeifile((struct ParseInfo *)ilbm);
    freecolors(ilbm);
}

modules/packer.c

/*----------------------------------------------------------------------*
 * packer.c Convert data to "cmpByteRun1" run compression.     11/15/85
 *
 * By Jerry Morrison and Steve Shaw, Electronic Arts.
 * This software is in the public domain.
 *
 *      control bytes:
 *       [0..127]   : followed by n+1 bytes of data.
 *       [-1..-127] : followed by byte to be repeated (-n)+1 times.
 *       -128       : NOOP.
 *
 * This version for the Amiga computer.
 *----------------------------------------------------------------------*/
#include "iffp/packer.h"

#define DUMP    0
#define RUN     1

#define MinRun 3        
#define MaxRun 128
#define MaxDat 128

/* When used on global definitions, static means private.
 * This keeps these names, which are only referenced in this
 * module, from conficting with same-named objects in your program.
 */ 
static LONG putSize;
static char buf[256];   /* [TBD] should be 128?  on stack?*/

#define GetByte()       (*source++)
#define PutByte(c)      { *dest++ = (c);   ++putSize; }

static BYTE *PutDump(dest, nn)  BYTE *dest;  int nn; {
        int i;

        PutByte(nn-1);
        for(i = 0;  i < nn;  i++)   PutByte(buf[i]);
        return(dest);
        }

static BYTE *PutRun(dest, nn, cc)   BYTE *dest;  int nn, cc; {
        PutByte(-(nn-1));
        PutByte(cc);
        return(dest);
        }

#define OutDump(nn)   dest = PutDump(dest, nn)
#define OutRun(nn,cc) dest = PutRun(dest, nn, cc)

/*----------- packrow --------------------------------------------------*/
/* Given POINTERS TO POINTERS, packs one row, updating the source and
 * destination pointers.  RETURNs count of packed bytes.
 */
LONG packrow(BYTE **pSource, BYTE **pDest, LONG rowSize)
    {
    BYTE *source, *dest;
    char c,lastc = '\0';
    BOOL mode = DUMP;
    short nbuf = 0;             /* number of chars in buffer */
    short rstart = 0;           /* buffer index current run starts */

    source = *pSource;
    dest = *pDest;
    putSize = 0;
    buf[0] = lastc = c = GetByte();  /* so have valid lastc */
    nbuf = 1;   rowSize--;      /* since one byte eaten.*/


    for (;  rowSize;  --rowSize) {
        buf[nbuf++] = c = GetByte();
        switch (mode) {
                case DUMP: 
                        /* If the buffer is full, write the length byte,
                           then the data */
                        if (nbuf>MaxDat) {
                                OutDump(nbuf-1);  
                                buf[0] = c; 
                                nbuf = 1;   rstart = 0; 
                                break;
                                }

                        if (c == lastc) {
                            if (nbuf-rstart >= MinRun) {
                                if (rstart > 0) OutDump(rstart);
                                mode = RUN;
                                }
                            else if (rstart == 0)
                                mode = RUN;     /* no dump in progress,
                                so can't lose by making these 2 a run.*/
                            }
                        else  rstart = nbuf-1;          /* first of run */ 
                        break;

                case RUN: if ( (c != lastc)|| ( nbuf-rstart > MaxRun)) {
                        /* output run */
                        OutRun(nbuf-1-rstart,lastc);
                        buf[0] = c;
                        nbuf = 1; rstart = 0;
                        mode = DUMP;
                        }
                        break;
                }

        lastc = c;
        }

    switch (mode) {
        case DUMP: OutDump(nbuf); break;
        case RUN: OutRun(nbuf-rstart,lastc); break;
        }
    *pSource = source;
    *pDest = dest;
    return(putSize);
    }

modules/parse.c

/*  
 * parse.c - iffparse file IO support module
 *   based on some of looki.c by Leo Schwab
 *
 * The filename for clipboard is -c or -cUnit as in -c0 -c1 etc. (default 0)
 */

#include <exec/types.h>

#include "iffp/iff.h"

/* local function prototypes */

LONG stdio_stream(struct Hook *, struct IFFHandle *, struct IFFStreamCmd *);

UBYTE *omodes[2] = {"r","w"};


/* openifile
 *
 * Passed a ParseInfo structure with a not-in-use IFFHandle, filename
 *   ("-c" or -cUnit like "-c1" for clipboard), and IFF open mode
 *   (IFFF_READ or IFFF_WRITE) opens file or clipboard for use with
 *   iffparse.library support modules.
 *
 * Returns 0 for success or an IFFERR (libraries/iffparse.h)
 */

LONG openifile(struct ParseInfo *pi, UBYTE *filename, ULONG iffopenmode)
{
        struct IFFHandle        *iff;
        BOOL    cboard;
        ULONG   unit = PRIMARY_CLIP;
        LONG    error;

        if(!pi)                 return(CLIENT_ERROR);
        if(!(iff=pi->iff))      return(CLIENT_ERROR);

        cboard = (*filename == '-'  &&  filename[1] == 'c');
        if(cboard && filename[2])       unit = atoi(&filename[2]);

        if (cboard)
                {
                /*
                 * Set up IFFHandle for Clipboard I/O.
                 */
                pi->clipboard = TRUE;
                if (!(iff->iff_Stream =
                                (ULONG)OpenClipboard(unit)))
                        {
                        message("Clipboard open of unit %ld failed.\n",unit);
                        return(NOFILE);
                        }
                InitIFFasClip(iff);
                }
        else
                {
                pi->clipboard = FALSE;
                /*
                 * Set up IFFHandle for buffered stdio I/O.
                 */
                if (!(iff->iff_Stream = (ULONG)
                   fopen(filename, omodes[iffopenmode & 1])))
                        {
                        message("%s: File open failed.\n",filename);
                        return(NOFILE);
                        }
                else initiffasstdio(iff);
                }

        D(bug("%s file opened: \n", cboard ? "[Clipboard]" : filename));

        pi->filename = filename;

        error=OpenIFF(iff, iffopenmode);

        pi->opened = error ? FALSE : TRUE;      /* currently open handle */

        D(bug("OpenIFF error = %ld\n",error));
        return(error);
}


/* closeifile
 *
 * closes file or clipboard opened with openifile, and frees all
 *   iffparse context parsed by parseifile.
 *
 * Note - You should closeifile as soon as possible if using clipboard
 *   ("-c[n]").  You also need to closeifile if, for example, you wish to
 *   reopen the file to write changes back out.  See the copychunks.c
 *   module for routines which allow you clone the chunks iffparse has
 *   gathered so that you can closeifile and still be able to modify and
 *   write back out gathered chunks.
 *   
 */

void closeifile(struct ParseInfo *pi)
{
struct IFFHandle *iff;

        D(bug("closeifile:\n"));

        if(!pi)                 return;
        if(!(iff=pi->iff))      return;

        DD(bug("closeifile: About to CloseIFF if open, iff=$%lx, opened=%ld\n",
                        iff, pi->opened));

        if(pi->opened)  CloseIFF(iff);

        DD(bug("closeifile: About to close %s, stream=$%lx\n",
                        pi->clipboard ? "clipboard" : "file", iff->iff_Stream));
        if(iff->iff_Stream)
                {
                if (pi->clipboard)
                   CloseClipboard((struct ClipHandle *)(iff->iff_Stream));
                else
                   fclose ((FILE *)(iff->iff_Stream));
                }

        iff->iff_Stream = NULL;
        pi->clipboard = NULL;
        pi->opened = NULL;
}


/* parseifile
 *
 * Passed a ParseInfo with an initialized and open IFFHandle,
 *  grouptype (like ID_FORM), groupid (like ID_ILBM),
 *  and TAG_END terminated longword arrays of type,id
 *  for chunks to be grabbed, gathered, and stopped on
 *  (like { ID_ILBM, ID_BMHD, ID_ILBM, ID_CAMG, TAG_END })
 *  will parse an IFF file, grabbing/gathering and stopping
 *  on specified chunk.
 *
 * Note - you can call getcontext() (to continue after a stop chunk) or
 *  nextcontext() (after IFFERR_EOC, to parse next form in the same file)
 *  if you wish to continue parsing the same IFF file.  If parseifile()
 *  has to delve into a complex format to find your desired FORM, the
 *  pi->hunt flag will be set.  This should be a signal to you that
 *  you may not have the capability to simply modify and rewrite
 *  the data you have gathered.
 *
 * Returns 0 for success else and IFFERR (libraries/iffparse.h)
 */ 

LONG parseifile(pi,groupid,grouptype,propchks,collectchks,stopchks)
struct  ParseInfo *pi;
LONG groupid, grouptype;
LONG *propchks, *collectchks, *stopchks;
{
struct IFFHandle *iff;  
register struct ContextNode     *cn;
LONG                    error = 0L;


        if(!(iff=pi->iff))      return(CLIENT_ERROR);

        if(!iff->iff_Stream)    return(IFFERR_READ);

        pi->hunt = FALSE;

        /*
         * Declare property, collection and stop chunks.
         */
        if (propchks)
          if (error = PropChunks (iff, propchks, chkcnt(propchks)))
                return (error);
        if (collectchks)
          if (error =
              CollectionChunks(iff, collectchks, chkcnt(collectchks)))
                return (error);
        if (stopchks)
          if (error = StopChunks (iff, stopchks, chkcnt(stopchks)))
                return (error);

        /*
         * We want to stop at the end of an ILBM context.
         */
        if (grouptype)
          if (error = StopOnExit (iff, grouptype, groupid))
                return(error);

        /*
         * Take first parse step to enter main chunk.
         */
        if (error = ParseIFF (iff, IFFPARSE_STEP))
                return(error);

        /*
         * Test the chunk info to see if simple form of type we want (ILBM).
         */
        if (!(cn = CurrentChunk (iff)))
                {
                /*
                 * This really should never happen.  If it does, it means
                 * our parser is broken.
                 */
                message("Parsing error; no top chunk!\n");
                return(NOFILE);
                }

        if (cn->cn_ID != groupid  ||  cn->cn_Type != grouptype)
                {
                
                D(bug("This is a(n) %.4s.%.4s.  Looking for embedded %.4s's...\n",
                  &cn->cn_Type, &cn->cn_ID, &grouptype));

                pi->hunt = TRUE;        /* Warning - this is a complex file */
                }

        if(!error)      error = getcontext(iff);
        return(error);
}

/* chkcnt
 *
 * simply counts the number of chunk pairs (type,id) in array
 */
LONG chkcnt(LONG *taggedarray)
{
LONG k = 0;

        while(taggedarray[k] != TAG_END) k++;
        return(k>>1);
}


/* currentchunkis
 *
 * returns the ID of the current chunk (like ID_CAMG)
 */
LONG currentchunkis(struct IFFHandle *iff, LONG type, LONG id)
{
register struct ContextNode     *cn;
LONG result = 0;

        if (cn = CurrentChunk (iff))
                {
                if((cn->cn_Type == type)&&(cn->cn_ID == id)) result = 1;
                }
        return(result);
}


/* contextis
 *
 * returns the enclosing context of the current chunk (like ID_ILBM)
 */
LONG contextis(struct IFFHandle *iff, LONG type, LONG id)
{
register struct ContextNode     *cn;
LONG result = 0;

       if (cn = (CurrentChunk (iff)))
           {
           if (cn = (ParentChunk(cn)))
               {
               if((cn->cn_Type == type)&&(cn->cn_ID == id)) result = 1;
               }
           }

        D(bug("This is a %.4s %.4s\n",&cn->cn_Type,&cn->cn_ID));

        return(result);
}


/* getcontext()
 *
 * Continues to gather the context which was specified to parseifile(),
 *  stopping at specified stop chunk, or end of context, or EOF
 *
 * Returns 0 (stopped on a stop chunk)
 *      or IFFERR_EOC (end of context, not an error)
 *      or IFFER_EOF (end of file)
 */
LONG getcontext(iff)
struct  IFFHandle *iff;
{
        LONG error = 0L;

        /* Based on our parse initialization,
         * ParseIFF() will return on a stop chunk (error = 0)
         * or end of context for an ILBM FORM (error = IFFERR_EOC)
         * or end of file (error = IFFERR_EOF)
         */
        return(error = ParseIFF(iff, IFFPARSE_SCAN));
}


/* nextcontext
 *
 * If you have finished parsing and reading your context (IFFERR_EOC),
 *   nextcontext will enter the next context contained in the file
 *   and parse it.
 *
 * Returns 0 or an IFFERR such as IFFERR_EOF (end of file)
 */

LONG nextcontext(iff)
struct  IFFHandle *iff;
{
        LONG error = 0L;

        error = ParseIFF(iff, IFFPARSE_STEP);

        D(bug("nextcontext: Got through next step\n"));

        return(error);
}


/* findpropdata
 *
 * finds specified chunk parsed from IFF file, and
 *   returns pointer to its sp_Data (or 0 for not found)
 */
UBYTE *findpropdata(iff, type, id)
struct IFFHandle        *iff;
LONG type, id;
        {
        register struct StoredProperty  *sp;

        if(sp = FindProp (iff, type, id)) return(sp->sp_Data);
        return(0);
        }


/*
 * File I/O hook functions which the IFF library will call.
 * A return of 0 indicates success (no error).
 *
 * Iffparse.library calls this code via struct Hook and Hook.asm
 */
static LONG
stdio_stream (hook, iff, actionpkt)
struct Hook             *hook;
struct IFFHandle        *iff;
struct IFFStreamCmd     *actionpkt;
{
        register FILE   *stream;
        register LONG   nbytes;
        register int    actual;
        register UBYTE  *buf;
        long    len;

        stream  = (FILE *) iff->iff_Stream;
        if(!stream)     return(1);

        nbytes  = actionpkt->sc_NBytes;
        buf     = (UBYTE *) actionpkt->sc_Buf;

        switch (actionpkt->sc_Command) {
        case IFFSCC_READ:
                do {
                        actual = nbytes > 32767 ? 32767 : nbytes;
                        if ((len=fread (buf, 1, actual, stream)) != actual)
                                break;
                        nbytes -= actual;
                        buf += actual;
                } while (nbytes > 0);
                return (nbytes ? IFFERR_READ : 0 );

        case IFFSCC_WRITE:
                do {
                        actual = nbytes > 32767 ? 32767 : nbytes;
                        if ((len=fwrite (buf, 1, actual, stream)) != actual)
                                break;
                        nbytes -= actual;
                        buf += actual;
                } while (nbytes > 0);
                return (nbytes ? IFFERR_WRITE : 0);

        case IFFSCC_SEEK:
                return ((fseek (stream, nbytes, 1) == -1) ? IFFERR_SEEK : 0);

        default:
                /*  No _INIT or _CLEANUP required.  */
                return (0);
        }
}

/* initiffasstdio (ie. init iff as stdio)
 *
 * sets up hook callback for the file stream handler above
 */
void initiffasstdio (iff)
struct IFFHandle *iff;
{
        extern LONG             HookEntry();
        static struct Hook      stdiohook = {
                { NULL },
                (ULONG (*)()) HookEntry,
                (ULONG (*)()) stdio_stream,
                NULL
        };

        /*
         * Initialize the IFF structure to point to the buffered I/O
         * routines.  Unbuffered I/O is terribly slow.
         */
        InitIFF (iff, IFFF_FSEEK | IFFF_RSEEK, &stdiohook);
}


/*
 * IFFerr
 *
 * Returns pointer to IFF Error string or NULL (no error)
 */
UBYTE *IFFerr(error)
LONG    error;
{
        /*
         * English error messages for possible IFFERR_#? returns from various
         * IFF routines.  To get the index into this array, take your IFFERR
         * code, negate it, and subtract one.
         *  idx = -error - 1;
         */
        static UBYTE    *errormsgs[] = {
                "End of file (not an error).",
                "End of context (not an error).",
                "No lexical scope.",
                "Insufficient memory.",
                "Stream read error.",
                "Stream write error.",
                "Stream seek error.",
                "File is corrupt.",
                "IFF syntax error.",
                "Not an IFF file.",
                "Required hook vector missing.",
                "Return to client."
        };
        static UBYTE unknown[32];
        static UBYTE client[] = "Client error";
        static UBYTE nofile[] = "File not found or wrong type";

        if (error < 0)
                {
                return(errormsgs[(-error) - 1]);
                }
        else if(error = CLIENT_ERROR)
                {
                return(client);
                }
        else if(error = NOFILE)
                {
                return(nofile);
                }
        else if(error)
                {
                sprintf(unknown,"Unknown error %ld",error);
                return(unknown);
                }
        else return(NULL);
}


/*
 * PutCk
 *
 * Writes one chunk of data to an iffhandle
 *
 */
long PutCk(struct IFFHandle *iff, long id, long size, void *data)
    {
    long error = 0, wlen;

    D(bug("PutCk: asked to push chunk \"%.4s\" ($%lx) length %ld\n",&id,id,size));

    if(error=PushChunk(iff, 0, id, size))
        {
        D(bug("PutCk: PushChunk of %.4s, error = %s, size = %ld\n",
                id, IFFerr(error), id));
        }
    else
        {
        D(bug("PutCk: PushChunk of %.4s, error = %ld\n",&id, error));

        /* Write the actual data */
        if((wlen = WriteChunkBytes(iff,data,size)) != size)
            {
            D(bug("WriteChunkBytes error: size = %ld, wrote %ld\n",size,wlen));
            error = IFFERR_WRITE;
            }
        else error = PopChunk(iff);
        D(bug("PutCk: After PopChunk - error = %ld\n",error));
        }
    return(error);
    }

modules/saveilbm.c

/* saveilbm.c 05/91  C. Scheppner CBM
 *
 * High-level ILBM save routines
 */

#include "iffp/ilbm.h"
#include "iffp/ilbmapp.h"

extern struct Library *GfxBase;

/* screensave.c
 *
 * Given an ILBMInfo with a  currently available (not in use)
 *   ParseInfo->iff IFFHandle, a screen pointer, filename, and
 *   optional chunklist, will save screen as an ILBM
 * The struct Chunk *chunklist1 and 2 are for chunks you wish written
 * out other than BMHD, CMAP, and CAMG (they will be screened out
 * because they are computed and written separately).
 *
 * Note -  screensave passes NULL for transparent color and mask
 *
 * Returns 0 for success or an IFFERR (libraries/iffparse.h)
 */
LONG screensave(struct ILBMInfo *ilbm,
                        struct Screen *scr,
                        struct Chunk *chunklist1, struct Chunk *chunklist2,
                        UBYTE *filename)
{
extern struct Library *GfxBase;
UWORD *colortable, count;
ULONG modeid;
LONG error;
int k;

    if(GfxBase->lib_Version >= 36)
        modeid=GetVPModeID(&scr->ViewPort);
    else
        modeid = scr->ViewPort.Modes & OLDCAMGMASK;

    count = scr->ViewPort.ColorMap->Count;
    if(colortable = (UWORD *)AllocMem(count << 1, MEMF_CLEAR))
        {
        for(k=0; k<count; k++)  colortable[k]=GetRGB4(scr->ViewPort.ColorMap,k);

        error = saveilbm(ilbm, &scr->BitMap, modeid,
                scr->Width, scr->Height, scr->Width, scr->Height,
                colortable, count, 4,
                mskNone, 0,
                chunklist1, chunklist2, filename);
        FreeMem(colortable,count << 1);
        }
    else error = IFFERR_NOMEM;
    return(error);
}


/* saveilbm
 *
 * Given an ILBMInfo with a currently available (not-in-use)
 *   ParseInfo->iff IFFHandle, a BitMap ptr,
 *   modeid, widths/heights, colortable, ncolors, bitspergun,
 *   masking, transparent color, optional chunklists, and filename,
 *   will save the bitmap as an ILBM.
 *
 *  if bitspergun=4,  colortable is words, each with nibbles 0RGB
 *  if bitspergun=8,  colortable is byte guns of RGBRGB etc. (like a CMAP)
 *  if bitspergun=32, colortable is ULONG guns of RGBRGB etc.
 *     Only the high eight bits of each gun will be written to CMAP.
 *     Four bit guns n will be saved as nn
 *
 * The struct Chunk *chunklist is for chunks you wish written
 * other than BMHD, CMAP, and CAMG (they will be screened out)
 * because they are calculated and written separately
 *
 * Returns 0 for success, or an IFFERR
 */
LONG saveilbm(struct ILBMInfo *ilbm,
                struct BitMap *bitmap, ULONG modeid,
                WORD width, WORD height, WORD pagewidth, WORD pageheight,
                APTR colortable, UWORD ncolors, UWORD bitspergun,
                WORD masking, WORD transparentColor,
                struct Chunk *chunklist1, struct Chunk *chunklist2,
                UBYTE *filename)
{
struct IFFHandle *iff;
struct Chunk *chunk;
ULONG chunkID;
UBYTE *bodybuf;
LONG size, error = 0L;
#define BODYBUFSZ       4096

    iff = ilbm->ParseInfo.iff;

    if(!(modeid & 0xFFFF0000))  modeid &= OLDCAMGMASK;

    if(!(bodybuf = AllocMem(BODYBUFSZ,MEMF_PUBLIC)))
        {
        message("Not enough memory\n");
        return(IFFERR_NOMEM);
        }

    if(!(error = openifile(ilbm, filename, IFFF_WRITE)))
        {
        D(bug("Opened %s for write\n",filename));

        error = PushChunk(iff, ID_ILBM, ID_FORM, IFFSIZE_UNKNOWN);

        D(bug("After PushChunk FORM ILBM - error = %ld\n", error));

        initbmhd(&ilbm->Bmhd, bitmap, masking, cmpByteRun1, transparentColor,
                        width, height, pagewidth, pageheight, modeid);

        D(bug("Error before putbmhd = %ld\n",error));

        CkErr(putbmhd(iff,&ilbm->Bmhd));        

        if(colortable)  CkErr(putcmap(iff,colortable,ncolors,bitspergun));

        ilbm->camg = modeid;
        D(bug("before putcamg - error = %ld\n",error));
        CkErr(putcamg(iff,&modeid));

        D(bug("Past putBMHD, CMAP, CAMG - error = %ld\n",error));

        /* Write out chunklists 1 & 2 (if any), except for
         * any BMHD, CMAP, or CAMG (computed/written separately)
         */
        for(chunk = chunklist1; chunk; chunk = chunk->ch_Next)
            {
            D(bug("chunklist1 - have a %.4s\n",&chunk->ch_ID));
            chunkID = chunk->ch_ID;
            if((chunkID != ID_BMHD)&&(chunkID != ID_CMAP)&&(chunkID != ID_CAMG))
                {
                size = chunk->ch_Size==IFFSIZE_UNKNOWN ?
                        strlen(chunk->ch_Data) : chunk->ch_Size;
                D(bug("Putting %.4s\n",&chunk->ch_ID));
                CkErr(PutCk(iff, chunkID, size, chunk->ch_Data));
                }
            }

        for(chunk = chunklist2; chunk; chunk = chunk->ch_Next)
            {
            chunkID = chunk->ch_ID;
            D(bug("chunklist2 - have a %.4s\n",&chunk->ch_ID));
            if((chunkID != ID_BMHD)&&(chunkID != ID_CMAP)&&(chunkID != ID_CAMG))
                {
                size = chunk->ch_Size==IFFSIZE_UNKNOWN ?
                        strlen(chunk->ch_Data) : chunk->ch_Size;
                D(bug("Putting %.4s\n",&chunk->ch_ID));
                CkErr(PutCk(iff, chunkID, size, chunk->ch_Data));
                }
            }

        /* Write out the BODY
         */
        CkErr(putbody(iff, bitmap, NULL, &ilbm->Bmhd, bodybuf, BODYBUFSZ));

        D(bug("Past putbody - error = %ld\n",error));


        CkErr(PopChunk(iff));   /* close out the FORM */
        closeifile(ilbm);       /* and the file */
        }

    FreeMem(bodybuf,BODYBUFSZ);

    return(error);
}

modules/screen.c

/* screen.c - 2.0 screen module for Display
 * based on scdemo, oscandemo, looki
 */

/*
Copyright (c) 1989, 1990 Amiga, Inc.

Executables based on this information may be used in software
for Amiga computers. All other rights reserved.
This information is provided "as is"; no warranties are made.
All use is at your own risk, and no liability or responsibility
is assumed.
*/

#include "iffp/ilbmapp.h"

BOOL   VideoControlTags(struct ColorMap *,ULONG tags, ...);

extern struct Library *GfxBase;
extern struct Library *IntuitionBase;

struct TextAttr SafeFont = { (UBYTE *) "topaz.font", 8, 0, 0, };
UWORD  penarray[] = {~0};

/* default new window if none supplied in ilbm->nw */
struct   NewWindow      defnw = {
   0, 0,                                  /* LeftEdge and TopEdge */
   0, 0,                                  /* Width and Height */
   -1, -1,                                /* DetailPen and BlockPen */
   VANILLAKEY|MOUSEBUTTONS,               /* IDCMP Flags with Flags below */
   BACKDROP|BORDERLESS|SMART_REFRESH|NOCAREREFRESH|ACTIVATE|RMBTRAP,
   NULL, NULL,                            /* Gadget and Image pointers */
   NULL,                                  /* Title string */
   NULL,                                  /* Screen ptr null till opened */
   NULL,                                  /* BitMap pointer */
   50, 20,                                /* MinWidth and MinHeight */
   0 , 0,                                 /* MaxWidth and MaxHeight */
   CUSTOMSCREEN                           /* Type of window */
   };


/* opendisplay - passed ILBMInfo, dimensions, modeID
 *
 *    Attempts to open correct 2.0 modeID screen and window,
 *    else an old 1.3 mode screen and window.
 *
 * Returns *window or NULL.
 */

struct Window *opendisplay(struct ILBMInfo *ilbm,
                           SHORT wide, SHORT high, SHORT deep,
                           ULONG mode)
    {
    struct NewWindow newwin, *nw;

    closedisplay(ilbm);
    if(ilbm->scr = openidscreen(ilbm, wide, high, deep, mode))
        {
        nw = &newwin;
        if(ilbm->windef) *nw = *(ilbm->windef);
        else *nw = *(&defnw);
        nw->Screen      = ilbm->scr;

        D(bug("sizes: scr= %ld x %ld  passed= %ld x %ld\n",
                ilbm->scr->Width,ilbm->scr->Height,wide,high)); 

        nw->Width       = wide;
        nw->Height      = high;
        if (!(ilbm->win = OpenWindow(nw)))
            {
            closedisplay(ilbm);
            D(bug("Failed to open window."));
            }
        else
            {
            if(ilbm->win->Flags & BACKDROP)
                {
                ShowTitle(ilbm->scr, FALSE);
                ilbm->TBState = FALSE;
                }
            }
        }

    if(ilbm->scr)       /* nulled out by closedisplay if OpenWindow failed */
        {
        ilbm->vp  = &ilbm->scr->ViewPort;
        ilbm->srp = &ilbm->scr->RastPort;
        ilbm->wrp = ilbm->win->RPort;
        }
    return(ilbm->win);
    }


void closedisplay(struct ILBMInfo *ilbm)
    {
    if(ilbm)
        {
        if (ilbm->win)  CloseWindow(ilbm->win), ilbm->win = NULL;
        if (ilbm->scr)  CloseScreen(ilbm->scr), ilbm->scr = NULL;
        ilbm->vp  = NULL;
        ilbm->srp = ilbm->wrp = NULL;
        }
    }



/* openidscreen - ILBMInfo, dimensions, modeID
 *
 *    Attempts to open correct 2.0 modeID screen with centered
 *    overscan based on user's prefs,
 *    else old 1.3 mode screen.
 *
 * If ilbm->stype includes CUSTOMBITMAP, ilbm->brbitmap will be
 *      used as the screen's bitmap.
 * If ilbm->stags is non-NULL, these tags will be added to the
 *      end of the taglist.
 *
 * Returns *screen or NULL.
 */

struct Screen *openidscreen(struct ILBMInfo *ilbm,
                            SHORT wide, SHORT high, SHORT deep,
                            ULONG mode)
    {
    struct NewScreen ns;                        /* for old style OpenScreen */
    struct Rectangle spos, dclip, txto, stdo, maxo, uclip;  /* display rectangles */
    struct Rectangle *uclipp;
    struct Screen   *scr = NULL;
    LONG   error, trynew;
    ULONG  bitmaptag, passedtags;
    BOOL   vctl;

    if (trynew = ((((struct Library *)GfxBase)->lib_Version >= 36)&&
          (((struct Library *)IntuitionBase)->lib_Version >= 36)))
        {
        /* if >= v36, see if mode is available */
        if(error = ModeNotAvailable(mode))
            {
            D(bug("Mode $%08lx not available, error=%ld:\n",mode,error));
            /* if not available, try fall back mode */
            mode = modefallback(mode,wide,high,deep);
            error = ModeNotAvailable(mode);

            D(bug("$%08lx ModeNotAvailable=%ld:\n",mode,error));
            }

        if(error) trynew = FALSE;
        else trynew=((QueryOverscan(mode,&txto,OSCAN_TEXT))&&
                        (QueryOverscan(mode,&stdo,OSCAN_STANDARD))&&
                            (QueryOverscan(mode,&maxo,OSCAN_MAX)));
        }

    D(bug("\nILBM: w=%ld, h=%ld, d=%ld, mode=0x%08lx\n",
                wide,high,deep,mode));  
    D(bug("OPEN: %s.\n",
        trynew  ? "Is >= 2.0 and mode available, trying OpenScreenTags"
                : "Not 2.0, doing old OpenScreen"));

    if(trynew)
        {
        /* If user clip type specified and available, use it */
        if(ilbm->Video) ilbm->ucliptype = OSCAN_VIDEO;
        if((ilbm->ucliptype)&&(QueryOverscan(mode,&uclip,ilbm->ucliptype)))
                uclipp = &uclip;
        else uclipp = NULL;

        clipit(wide,high,&spos,&dclip,&txto,&stdo,&maxo,uclipp);

        D(bug("Using dclip  %ld,%ld  to  %ld,%ld... width=%ld height=%ld\n",
                        dclip.MinX,dclip.MinY,dclip.MaxX,dclip.MaxY,
                        dclip.MaxX-dclip.MinX+1,dclip.MaxY-dclip.MinY+1));
        D(bug("spos->minx = %ld, spos->miny = %ld\n",spos.MinX,spos.MinY));
        D(bug("DEBUG: About to attempt OpenScreenTags\n"));

        bitmaptag = ((ilbm->brbitmap)&&(ilbm->stype & CUSTOMBITMAP)) ?
                SA_BitMap : TAG_IGNORE;
        passedtags = ilbm->stags ? TAG_MORE : TAG_IGNORE;

        scr=(struct Screen *)OpenScreenTags((struct NewScreen *)NULL,
                SA_DisplayID,   mode,
                SA_Type,        ilbm->stype,
                SA_Behind,      TRUE,
                SA_Top,         spos.MinY,
                SA_Left,        spos.MinX,
                SA_Width,       wide,
                SA_Height,      high,
                SA_Depth,       deep,
                SA_DClip,       &dclip,
                SA_AutoScroll,  ilbm->Autoscroll ? TRUE : FALSE,
                SA_Title,       ilbm->stitle,
                SA_Font,        &SafeFont,
                SA_Pens,        penarray,
                SA_ErrorCode,   &error,
                bitmaptag,      ilbm->brbitmap,
                passedtags,     ilbm->stags,
                TAG_END
                );

            D(bug("DEBUG: OpenScreenTags scr at 0x%lx\n",scr));

            if(scr)
                {
                if(ilbm->Notransb)
                    {
                    vctl=VideoControlTags(scr->ViewPort.ColorMap,
                                VTAG_BORDERNOTRANS_SET, TRUE,
                                TAG_END);

        D(bug("VideoControl to set bordernotrans, error = %ld\n",vctl));

                    MakeScreen(scr);
                    RethinkDisplay();
                    }
                }
            else modeErrorMsg(mode,error);
        }

    if(!scr)
        {
        /* ns initialization for 1.3 old style OpenScreen only
         */
        ns.LeftEdge = ns.TopEdge = 0;   
        ns.Width        =       wide;
        ns.Height       =       high;
        ns.Depth        =       deep;
        ns.ViewModes    =       modefallback(mode,wide,high,deep);
        ns.DetailPen    =       0;
        ns.BlockPen     =       1;
        ns.Gadgets      =       NULL;
        ns.CustomBitMap =       ((ilbm->brbitmap)&&(ilbm->stype & CUSTOMBITMAP))
                                        ? ilbm->brbitmap : NULL;
        ns.Font         =       &SafeFont;
        ns.DefaultTitle =       ilbm->stitle;
        ns.Type         =       ilbm->stype & 0x01FF;  /* allow only 1.3 types */

        scr=(struct Screen *)OpenScreen(&ns);

        D(bug("DEBUG: ns.ViewModes=0x%lx, vp->Modes=0x%lx\n",
                 ns.ViewModes,scr->ViewPort.Modes));
        D(bug("DEBUG: non-extended scr at 0x%lx (0=failure)\n",scr));
        }
    return(scr);
    }


/*
 * modefallback - passed a mode id, attempts to provide a
 *                suitable old mode to use instead
 */

/* for old 1.3 screens */
#define MODE_ID_MASK (LACE|HIRES|HAM|EXTRA_HALFBRITE)

ULONG modefallback(ULONG mode, SHORT wide, SHORT high, SHORT deep)
{
ULONG newmode;

    /* For now, simply masks out everything but old mode bits.
     * This is just a cheap way to get some kind of display open
     *   and may be totally invalid for future modes.
     * Should search the display database for a suitable mode
     * based on the specific needs of your application.
     */
    newmode = mode & MODE_ID_MASK;

    D(bug("Try 0x%08lx instead of 0x%08lx\n",newmode,mode));
    return(newmode);
}


/*
 * clipit - passed width and height of a display, and the text, std, and
 *          max overscan rectangles for the mode, clipit fills in the
 *          spos (screen pos) and dclip rectangles to use in centering.
 *          Centered around smallest containing user-editable oscan pref,
 *          with dclip confined to legal maxoscan limits.
 *          Screens which center such that their top is below text
 *          oscan top, will be moved up.
 *          If a non-null uclip is passed, that clip is used instead.
 */
void clipit(SHORT wide, SHORT high,
            struct Rectangle *spos, struct Rectangle *dclip,
            struct Rectangle *txto, struct Rectangle *stdo,
            struct Rectangle *maxo, struct Rectangle *uclip)
{
struct  Rectangle *besto;
SHORT   minx, maxx, miny, maxy;
SHORT   txtw, txth, stdw, stdh, maxw, maxh, bestw, besth;

    /* get the txt, std and max widths and heights */
    txtw = txto->MaxX - txto->MinX + 1;
    txth = txto->MaxY - txto->MinY + 1;
    stdw = stdo->MaxX - stdo->MinX + 1;
    stdh = stdo->MaxY - stdo->MinY + 1;
    maxw = maxo->MaxX - maxo->MinX + 1;
    maxh = maxo->MaxY - maxo->MinY + 1;

    if((wide <= txtw)&&(high <= txth))
        {
        besto = txto;
        bestw = txtw;
        besth = txth;

        D(bug("Best clip is txto\n"));
        }
    else
        {
        besto = stdo;
        bestw = stdw;
        besth = stdh;

        D(bug("Best clip is stdo\n"));
        }

    D(bug("TXTO: mnx=%ld mny=%ld mxx=%ld mxy=%ld  stdw=%ld stdh=%ld\n",
                txto->MinX,txto->MinY,txto->MaxX,txto->MaxY,txtw,txth));
    D(bug("STDO: mnx=%ld mny=%ld mxx=%ld mxy=%ld  stdw=%ld stdh=%ld\n",
                stdo->MinX,stdo->MinY,stdo->MaxX,stdo->MaxY,stdw,stdh));
    D(bug("MAXO: mnx=%ld mny=%ld mxx=%ld mxy=%ld  maxw=%ld maxh=%ld\n",
                maxo->MinX,maxo->MinY,maxo->MaxX,maxo->MaxY,maxw,maxh));

    if(uclip)
        {
        *dclip = *uclip;
        spos->MinX = uclip->MinX;
        spos->MinY = uclip->MinY;

        D(bug("UCLIP: mnx=%ld mny=%ld maxx=%ld maxy=%ld\n",
                        dclip->MinX,dclip->MinY,dclip->MaxX,dclip->MaxY));
        }
    else
        {
        /* CENTER the screen based on best oscan prefs
        * but confine dclip within max oscan limits
        *
        * FIX MinX first */
        spos->MinX = minx = besto->MinX - ((wide - bestw) >> 1);
        maxx = wide + minx - 1;
        if(maxx > maxo->MaxX)  maxx = maxo->MaxX;       /* too right */
        if(minx < maxo->MinX)  minx = maxo->MinX;       /* too left  */

        D(bug("DCLIP: minx adjust from %ld to %ld\n",spos->MinX,minx));

        /* FIX MinY */
        spos->MinY = miny = besto->MinY - ((high - besth) >> 1);
        /* if lower than top of txto, move up */
        spos->MinY = miny = MIN(spos->MinY,txto->MinY);
        maxy = high + miny - 1;
        if(maxy > maxo->MaxY)  maxy = maxo->MaxY;       /* too down  */
        if(miny < maxo->MinY)  miny = maxo->MinY;       /* too up    */

        D(bug("DCLIP: miny adjust from %ld to %ld\n",spos->MinY,miny));

        /* SET up dclip */
        dclip->MinX = minx;
        dclip->MinY = miny;
        dclip->MaxX = maxx;
        dclip->MaxY = maxy;

        D(bug("CENTER: mnx=%ld mny=%ld maxx=%ld maxy=%ld\n",
                        dclip->MinX,dclip->MinY,dclip->MaxX,dclip->MaxY));
        }
}


void modeErrorMsg(ULONG mode, ULONG errorcode)
   {
   UBYTE *s=NULL;

        D(bug("DEBUG: Can't open mode ID 0x%08lx screen: ",mode));

        switch ( errorcode )
        {
        case OSERR_NOMEM:
            s="Not enough memory.";
            break;
        case OSERR_NOCHIPMEM:
            s="Not enough chip memory.";
            break;
#ifdef DEBUG
        case OSERR_NOMONITOR:
            s="monitor not available.";
            break;

        case OSERR_NOCHIPS:
            s="new chipset not available.";
            break;

        case OSERR_PUBNOTUNIQUE:
            s="public screen already open.";
            break;
        case OSERR_UNKNOWNMODE:
            s="mode ID is unknown.";
            break;
        default:
            message("unknown mode error %ld\n",errorcode);
#endif
        }
    if(s) message("%s\n",s);
    }


/*----------------------------------------------------------------------*/

BOOL VideoControlTags(struct ColorMap *cm, ULONG tags, ...)
    {
    return (VideoControl(cm, (struct TagItem *)&tags));
    }


/*----------------------------------------------------------------------*/

modules/screendump.c

/*
 * screendump.c    - routine to dump rastport (iffparse not required)
 *
 */

#include <exec/types.h>
#include <intuition/screens.h>
#include <devices/printer.h>

#ifndef NO_PROTOS
#include <clib/exec_protos.h>
#include <clib/alib_protos.h>
#endif


/* screendump
 * 
 * Passed a screen pointer, source x, source y, width, height,
 *   destcols and io_Special flags, will print part or all of a screen.
 *
 * If 0 is passed for BOTH destcols and special, screendump()
 *   assumes you want IT to compute suitable values.
 * In this case:
 *   1. If srcx and srcy are 0, and srcw and srch are same as
 *      screen width and height, screendump will set destcols=0,
 *      and special = SPECIAL_FULLCOLS|SPECIAL_ASPECT
 *      for a full width aspected dump.
 *
 *   2. If srcx or srcy are nonzero, or srcw or srch are different
 *      from screen width or height, screendump will print a
 *      fractional size dump relative to the size whole screendump
 *      would have been.
 *
 * Returns 0 for success or printer io_Error (devices/printer.h)
 */

int screendump(struct Screen *scr,
                UWORD srcx, UWORD srcy, UWORD srcw, UWORD srch,
                LONG destcols, UWORD iospecial)
    {
    struct IODRPReq *iodrp;
    struct MsgPort  *printerPort;
    struct ViewPort *vp;
    ULONG tmpl;
    int error = PDERR_BADDIMENSION;

    if(!scr)    return(error);

    if((!destcols)&&(!iospecial))
        {
        /* Then we compute what they should be */
        if((!srcx)&&(!srcy)&&(srcw==scr->Width)&&(srch==scr->Height))
            {
            iospecial = SPECIAL_FULLCOLS|SPECIAL_ASPECT;
            }
        else
            {
            iospecial = SPECIAL_FRACCOLS|SPECIAL_ASPECT;
            tmpl = srcw;
            tmpl = tmpl << 16;
            destcols = (tmpl / scr->Width) << 16;
            }
        }

    if(printerPort = CreatePort(0,0))
        {
        if(iodrp=
           (struct IODRPReq *)CreateExtIO(printerPort,sizeof(struct IODRPReq)))
            {
            if(!(error=OpenDevice("printer.device",0,iodrp,0)))
                {
                vp = &scr->ViewPort;
                iodrp->io_Command = PRD_DUMPRPORT;
                iodrp->io_RastPort = &scr->RastPort;
                iodrp->io_ColorMap = vp->ColorMap;
                iodrp->io_Modes = (ULONG)vp->Modes;
                iodrp->io_SrcX = srcx;
                iodrp->io_SrcY = srcy;
                iodrp->io_SrcWidth = srcw;
                iodrp->io_SrcHeight = srch;
                iodrp->io_DestCols = destcols;
        /*      iodrp->io_DestRows = 0; cleared by allocation */
                iodrp->io_Special = iospecial;

                error = DoIO(iodrp);

                CloseDevice(iodrp);
                }
            DeleteExtIO(iodrp);
            }
        DeletePort(printerPort);
        }
    return(error);
    }

modules/unpacker.c

#include "iffp/ilbm.h"
#include "iffp/packer.h"

/*----------------------------------------------------------------------*
 * unpacker.c Convert data from "cmpByteRun1" run compression. 11/15/85
 *
 * Based on code by Jerry Morrison and Steve Shaw, Electronic Arts.
 * This software is in the public domain.
 *
 *      control bytes:
 *       [0..127]   : followed by n+1 bytes of data.
 *       [-1..-127] : followed by byte to be repeated (-n)+1 times.
 *       -128       : NOOP.
 *
 * This version for the Amiga computer.
 *----------------------------------------------------------------------*/

/*----------- UnPackRow ------------------------------------------------*/

#define UGetByte()      (*source++)
#define UPutByte(c)     (*dest++ = (c))

/* Given POINTERS to POINTER variables, unpacks one row, updating the source
 * and destination pointers until it produces dstBytes bytes.
 */

BOOL unpackrow(BYTE **pSource, BYTE **pDest, WORD srcBytes0, WORD dstBytes0)
    {
    register BYTE *source = *pSource;
    register BYTE *dest   = *pDest;
    register WORD n;
    register BYTE c;
    register WORD srcBytes = srcBytes0, dstBytes = dstBytes0;
    BOOL error = TRUE;  /* assume error until we make it through the loop */
    WORD minus128 = -128;  /* get the compiler to generate a CMP.W */

    while( dstBytes > 0 )  {
        if ( (srcBytes -= 1) < 0 )  goto ErrorExit;
        n = UGetByte();

        if (n >= 0) {
            n += 1;
            if ( (srcBytes -= n) < 0 )  goto ErrorExit;
            if ( (dstBytes -= n) < 0 )  goto ErrorExit;
            do {  UPutByte(UGetByte());  } while (--n > 0);
            }

        else if (n != minus128) {
            n = -n + 1;
            if ( (srcBytes -= 1) < 0 )  goto ErrorExit;
            if ( (dstBytes -= n) < 0 )  goto ErrorExit;
            c = UGetByte();
            do {  UPutByte(c);  } while (--n > 0);
            }
        }
    error = FALSE;      /* success! */

  ErrorExit:
    *pSource = source;  *pDest = dest;
    return(error);
    }


/* end */

other/clipftxt.c

;/* clipftxt.c - Execute me to compile me with SAS C 5.10
LC -b1 -cfistq -v -j73 clipftxt.c
Blink FROM LIB:c.o,clipftxt.o TO clipftxt LIBRARY LIB:LC.lib,LIB:Amiga.lib
quit

*
* clipftxt.c:   Writes ASCII text to clipboard unit as FTXT
*               (All clipboard data must be IFF)
*
* Usage: clipftxt unitnumber
*
* To convert to an example of reading only, comment out #define WRITEREAD
*/

#include <exec/types.h>
#include <exec/memory.h>
#include <libraries/dos.h>
#include <libraries/iffparse.h>

#include <clib/exec_protos.h>
#include <clib/dos_protos.h>
#include <clib/iffparse_protos.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>

#ifdef LATTICE
int CXBRK(void) { return(0); }  /* Disable Lattice CTRL/C handling */
int chkabort(void) { return(0); }  /* really */
#endif

/* Causes example to write FTXT first, then read it back
 * Comment out to create a reader only
 */
#define WRITEREAD


#define MINARGS 2

/* 2.0 Version string for c:Version to find */
UBYTE vers[] = "\0$VER: clipftxt 37.2";

UBYTE usage[] = "Usage: clipftxt unitnumber (use zero for primary unit)";

/*
 * Text error messages for possible IFFERR_#? returns from various
 * IFF routines.  To get the index into this array, take your IFFERR code,
 * negate it, and subtract one.
 *  idx = -error - 1;
 */
char    *errormsgs[] = {
        "End of file (not an error).",
        "End of context (not an error).",
        "No lexical scope.",
        "Insufficient memory.",
        "Stream read error.",
        "Stream write error.",
        "Stream seek error.",
        "File is corrupt.",
        "IFF syntax error.",
        "Not an IFF file.",
        "Required call-back hook missing.",
        "Return to client.  You should never see this."
};

#define RBUFSZ 512

#define  ID_FTXT        MAKE_ID('F','T','X','T')
#define  ID_CHRS        MAKE_ID('C','H','R','S')

struct Library *IFFParseBase;

UBYTE mytext[]="This FTXT written to clipboard by clipftxt example.\n";

void main(int argc, char **argv)
{
    struct IFFHandle    *iff = NULL;
    struct ContextNode  *cn;
    long                error=0, unitnumber=0, rlen;
    int textlen;
    UBYTE readbuf[RBUFSZ];

        /* if not enough args or '?', print usage */
        if(((argc)&&(argc<MINARGS))||(argv[argc-1][0]=='?'))
                {
                printf("%s\n",usage);
                exit(RETURN_WARN);
                }

        unitnumber = atoi(argv[1]);
        
        if (!(IFFParseBase = OpenLibrary ("iffparse.library", 0L)))
                {
                puts("Can't open iff parsing library.");
                goto bye;
                }

        /*
         * Allocate IFF_File structure.
         */
        if (!(iff = AllocIFF ()))
                {
                puts ("AllocIFF() failed.");
                goto bye;
                }

        /*
         * Set up IFF_File for Clipboard I/O.
         */
        if (!(iff->iff_Stream = (ULONG) OpenClipboard (unitnumber)))
                {
                puts ("Clipboard open failed.");
                goto bye;
                }
        else printf("Opened clipboard unit %ld\n",unitnumber);

        InitIFFasClip (iff);

#ifdef WRITEREAD

        /*
         * Start the IFF transaction.
         */
        if (error = OpenIFF (iff, IFFF_WRITE))
                {
                puts ("OpenIFF for write failed.");
                goto bye;
                }

        /*
         * Write our text to the clipboard as CHRS chunk in FORM FTXT
         *
         * First, write the FORM ID (FTXT)
         */
        if(!(error=PushChunk(iff, ID_FTXT, ID_FORM, IFFSIZE_UNKNOWN)))
                {
                /* Now the CHRS chunk ID followed by the chunk data
                 * We'll just write one CHRS chunk.
                 * You could write more chunks.
                 */
                if(!(error=PushChunk(iff, 0, ID_CHRS, IFFSIZE_UNKNOWN)))
                        {
                        /* Now the actual data (the text) */
                        textlen = strlen(mytext);
                        if(WriteChunkBytes(iff, mytext, textlen) != textlen)
                                {
                                puts("Error writing CHRS data.");
                                error = IFFERR_WRITE;
                                }
                        }
                if(!error) error = PopChunk(iff);
                }
        if(!error) error = PopChunk(iff);


        if(error)
                {
                printf ("IFF write failed, error %ld: %s\n",
                        error, errormsgs[-error - 1]);
                goto bye;
                }
        else printf("Wrote text to clipboard as FTXT\n");

        /*
         * Now let's close it, then read it back
         * First close the write handle, then close the clipboard
         */
        CloseIFF(iff);
        if (iff->iff_Stream) CloseClipboard ((struct ClipboardHandle *)
                                                iff->iff_Stream);

        if (!(iff->iff_Stream = (ULONG) OpenClipboard (unitnumber)))
                {
                puts ("Reopen of Clipboard failed.");
                goto bye;
                }
        else printf("Reopened clipboard unit %ld\n",unitnumber);

#endif /* WRITEREAD */

        if (error = OpenIFF (iff, IFFF_READ))
                {
                puts ("OpenIFF for read failed.");
                goto bye;
                }

        /* Tell iffparse we want to stop on FTXT CHRS chunks */
        if (error = StopChunk(iff, ID_FTXT, ID_CHRS))
                {
                puts ("StopChunk failed.");
                goto bye;
                }

        /* Find all of the FTXT CHRS chunks */
        while(1)
                {
                error = ParseIFF(iff,IFFPARSE_SCAN);
                if(error == IFFERR_EOC) continue;       /* enter next context */
                else if(error) break;

                /* We only asked to stop at FTXT CHRS chunks
                 * If no error we've hit a stop chunk
                 * Read the CHRS chunk data
                 */
                cn = CurrentChunk(iff);

                if((cn)&&(cn->cn_Type == ID_FTXT)&&(cn->cn_ID == ID_CHRS))
                        {
                        printf("CHRS chunk contains:\n");
                        while((rlen = ReadChunkBytes(iff,readbuf,RBUFSZ)) > 0)
                                {
                                Write(Output(),readbuf,rlen);
                                }
                        if(rlen < 0)    error = rlen;   
                        }
                }

        if((error)&&(error != IFFERR_EOF))
                {
                printf ("IFF read failed, error %ld: %s\n",
                        error, errormsgs[-error - 1]);
                }

bye:
        if (iff) {
                /*
                 * Terminate the IFF transaction with the stream.  Free
                 * all associated structures.
                 */
                CloseIFF (iff);

                /*
                 * Close the clipboard stream
                 */
                if (iff->iff_Stream)
                                CloseClipboard ((struct ClipboardHandle *)
                                                iff->iff_Stream);
                /*
                 * Free the IFF_File structure itself.
                 */
                FreeIFF (iff);
                }
        if (IFFParseBase)       CloseLibrary (IFFParseBase);

        exit (RETURN_OK);
}

other/cycvb.c

/*
 * cycvb.c --- Dan Silva's DPaint color cycling interrupt code
 *
 *    Use this fragment as an example for interrupt driven color cycling
 *    If compiled with SAS, include flags -v -y on LC2
 */

#include <exec/types.h>
#include <exec/interrupts.h>
#include <graphics/view.h>
#include <iff/compiler.h>

#define MAXNCYCS 4
#define NO  FALSE
#define YES TRUE
#define LOCAL static

typedef struct {
    SHORT count;
    SHORT rate;
    SHORT flags;
    UBYTE low, high;  /* bounds of range */
    } Range;

/* Range flags values */
#define RNG_ACTIVE  1
#define RNG_REVERSE 2
#define RNG_NORATE 36  /* if rate == NORATE, don't cycle */

/* cycling frame rates */
#define OnePerTick   16384
#define OnePerSec    OnePerTick/60

extern Range  cycles[];
extern BOOL   cycling[];
extern WORD   cycols[];
extern struct ViewPort *vport;
extern SHORT  nColors;


MyVBlank()  {
   int i,j;
   LOCAL  Range *cyc;
   LOCAL  WORD  temp;
   LOCAL  BOOL  anyChange;

#ifdef IS_AZTEC
#asm
       movem.l  a2-a7/d2-d7,-(sp)
       move.l   a1,a4
#endasm
#endif

   if (cycling)  {
      anyChange = NO;
      for (i=0; i<MAXNCYCS; i++)  {
         cyc = &cycles[i];
         if ( (cyc->low == cyc->high) ||
              ((cyc->flags&RNG_ACTIVE) == 0) ||
              (cyc->rate == RNG_NORATE) )
                 continue;

         cyc->count += cyc->rate;
         if (cyc->count >= OnePerTick)  {
            anyChange = YES;
            cyc->count -= OnePerTick;

            if (cyc->flags&RNG_REVERSE)  {
               temp = cycols[cyc->low];
               for (j=cyc->low; j < cyc->high; j++)
                  cycols[j] = cycols[j+1];
               cycols[cyc->low] = temp;
               }
            else  {
               temp = cycols[cyc->high];
               for (j=cyc->high; j > cyc->low; j--)
                  cycols[j] = cycols[j-1];
               cycols[cyc->low] = temp;
               }
            }
         }
      if (anyChange) LoadRGB4(vport,cycols,nColors);
      }

#ifdef IS_AZTEC
      ;   /* this is necessary */
#asm
      movem.l  (sp)+,a2-a7/d2-d7
#endasm
#endif

   return(0);  /* interrupt routines have to do this */
   }


/*
 *  Code to install/remove cycling interrupt handler
 */

LOCAL char myname[] = "MyVB";  /* Name of interrupt handler */
LOCAL struct Interrupt intServ;

typedef void (*VoidFunc)();

StartVBlank()  {
#ifdef IS_AZTEC
   intServ.is_Data = GETAZTEC();  /* returns contents of register a4 */
#else
   intServ.is_Data = NULL;
#endif
   intServ.is_Code = (VoidFunc)&MyVBlank;
   intServ.is_Node.ln_Succ = NULL;
   intServ.is_Node.ln_Pred = NULL;
   intServ.is_Node.ln_Type = NT_INTERRUPT;
   intServ.is_Node.ln_Pri  = 0;
   intServ.is_Node.ln_Name = myname;
   AddIntServer(5,&intServ);
   }

StopVBlank() { RemIntServer(5,&intServ); }

/**/

other/ilbmscan.c

;/* ilbmscan.c - Execute me to compile me with SAS C 5.10
LC -b1 -cfistq -v -j73 ilbmscan.c
Blink FROM LIB:c.o,ilbmscan.o TO ilbmscan LIBRARY LIB:LC.lib,LIB:Amiga.lib
quit

*
* ilbmscan.c:   Prints the size, aspect, mode, etc. of ILBM's
*               Scans through an IFF file for all ILBM's
*
* Usage: ilbmscan -c            ; For clipboard scanning
*    or  ilbmscan <file>        ; For DOS file scanning
*
* Based on sift.c by by Stuart Ferguson and Leo Schwab
*/

#include <exec/types.h>
#include <exec/memory.h>
#include <libraries/dos.h>
#include <libraries/iffparse.h>

#include <clib/exec_protos.h>
#include <clib/dos_protos.h>
#include <clib/iffparse_protos.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>

#ifdef LATTICE
int CXBRK(void) { return(0); }  /* Disable Lattice CTRL/C handling */
int chkabort(void) { return(0); }  /* really */
#endif

/*  The structure of a FORM ILBM 'BMHD' and 'CAMG' chunks
 *  Such structures are defined in the spec for a FORM
 *  and may also be provided in include files
 */
/*  Bitmap header (BMHD) structure  */
typedef struct {
        UWORD   w, h;           /*  Width, height in pixels */
        WORD    x, y;           /*  x, y position for this bitmap  */
        UBYTE   nplanes;        /*  # of planes  */
        UBYTE   Masking;
        UBYTE   Compression;
        UBYTE   pad1;
        UWORD   TransparentColor;
        UBYTE   XAspect, YAspect;
        WORD    PageWidth, PageHeight;
} BitMapHeader;

/* Amiga (CAMG) Viewmodes structure */
typedef struct {
   ULONG ViewModes;
   } CamgChunk;

#define ID_ILBM         MAKE_ID('I','L','B','M')
#define ID_BMHD         MAKE_ID('B','M','H','D')
#define ID_CMAP         MAKE_ID('C','M','A','P')
#define ID_CAMG         MAKE_ID('C','A','M','G')
#define ID_BODY         MAKE_ID('B','O','D','Y')

void PrintILBMInfo(struct IFFHandle *);

#define MINARGS 2

/* 2.0 Version string for c:Version to find */
UBYTE vers[] = "\0$VER: ilbmscan 37.3";

UBYTE usage[] = "Usage: ilbmscan IFFfilename (or -c for clipboard)";

/*
 * Text error messages for possible IFFERR_#? returns from various
 * IFF routines.  To get the index into this array, take your IFFERR code,
 * negate it, and subtract one.
 *  idx = -error - 1;
 */
char    *errormsgs[] = {
        "End of file (not an error).",
        "End of context (not an error).",
        "No lexical scope.",
        "Insufficient memory.",
        "Stream read error.",
        "Stream write error.",
        "Stream seek error.",
        "File is corrupt.",
        "IFF syntax error.",
        "Not an IFF file.",
        "Required call-back hook missing.",
        "Return to client.  You should never see this."
};

struct Library *IFFParseBase;


void main(int argc, char **argv)
{
    struct IFFHandle    *iff = NULL;
    long                error;
    short               cbio;

        /* if not enough args or '?', print usage */
        if(((argc)&&(argc<MINARGS))||(argv[argc-1][0]=='?'))
                {
                printf("%s\n",usage);
                exit(RETURN_OK);
                }

        /*
         * Check to see if we are doing I/O to the Clipboard.
         */
        cbio = (argv[1][0] == '-'  &&  argv[1][1] == 'c');

        if (!(IFFParseBase = OpenLibrary ("iffparse.library", 0L)))
                {
                printf("Can't open iff parsing library.");
                goto bye;
                }

        /*
         * Allocate IFF_File structure.
         */
        if (!(iff = AllocIFF ()))
                {
                printf ("AllocIFF() failed.");
                goto bye;
                }

        /*
         * Internal support is provided for both AmigaDOS files, and the
         * clipboard.device.  This bizarre 'if' statement performs the
         * appropriate machinations for each case.
         */
        if (cbio)
                {
                /*
                 * Set up IFF_File for Clipboard I/O.
                 */
                if (!(iff->iff_Stream =
                                (ULONG) OpenClipboard (PRIMARY_CLIP)))
                        {
                        printf("Clipboard open failed.");
                        goto bye;
                        }
                InitIFFasClip (iff);
                }
        else
                {
                /*
                 * Set up IFF_File for AmigaDOS I/O.
                 */
                if (!(iff->iff_Stream = Open (argv[1], MODE_OLDFILE)))
                        {
                        printf("File open failed.");
                        goto bye;
                        }
                InitIFFasDOS (iff);
                }

        /*
         * Start the IFF transaction.
         */
        if (error = OpenIFF (iff, IFFF_READ))
                {
                printf("OpenIFF failed.");
                goto bye;
                }

        /* We want to collect BMHD and CAMG */
        PropChunk(iff, ID_ILBM, ID_BMHD);
        PropChunk(iff, ID_ILBM, ID_CAMG);
        PropChunk(iff, ID_ILBM, ID_CMAP);

        /* Stop at the BODY */
        StopChunk(iff, ID_ILBM, ID_BODY);

        /* And let us know (IFFERR_EOC) when leaving a FORM ILBM */
        StopOnExit(iff,ID_ILBM, ID_FORM);

        /* Do the scan.
         * The while(1) will let us delve into more complex formats
         * to find FORM ILBM's
         */
        while (1)
                {
                error = ParseIFF(iff, IFFPARSE_SCAN);
                /*
                 * Since we're only interested in when we enter a context,
                 * we "discard" end-of-context (_EOC) events.
                 */
                if (error == IFFERR_EOC)
                        {
                        printf("Exiting FORM ILBM\n\n");
                        continue;
                        }
                else if (error)
                        /*
                         * Leave the loop if there is any other error.
                         */
                        break;

                /*
                 * If we get here, error was zero
                 * Since we did IFFPARSE_SCAN, zero error should mean
                 * we are at our Stop Chunk (BODY)
                 */
                PrintILBMInfo(iff);
                }

        /*
         * If error was IFFERR_EOF, then the parser encountered the end of
         * the file without problems.  Otherwise, we print a diagnostic.
         */
        if (error == IFFERR_EOF)
                printf("File scan complete.\n");
        else
                printf("File scan aborted, error %ld: %s\n",
                        error, errormsgs[-error - 1]);

bye:
        if (iff) {
                /*
                 * Terminate the IFF transaction with the stream.  Free
                 * all associated structures.
                 */
                CloseIFF (iff);

                /*
                 * Close the stream itself.
                 */
                if (iff->iff_Stream)
                        if (cbio)
                                CloseClipboard ((struct ClipboardHandle *)
                                                iff->iff_Stream);
                        else
                                Close (iff->iff_Stream);

                /*
                 * Free the IFF_File structure itself.
                 */
                FreeIFF (iff);
                }
        if (IFFParseBase)       CloseLibrary (IFFParseBase);

        exit (RETURN_OK);
}


void
PrintILBMInfo(iff)
struct IFFHandle *iff;
{
        struct StoredProperty   *sp;
        BitMapHeader    *bmhd;
        CamgChunk       *camg;

        /*
         * Get a pointer to the stored propery BMHD
         */
        if (!(sp = FindProp(iff, ID_ILBM, ID_BMHD)))
                printf("No BMHD found\n");
        else
                {
                /* If property is BMHD, sp->sp_Data is ptr to data in BMHD */
                bmhd = (BitMapHeader *)sp->sp_Data;
                printf("BMHD: Width      = %ld\n",bmhd->w);
                printf("      Height     = %ld\n",bmhd->h);
                printf("      PageWidth  = %ld\n",bmhd->PageWidth);
                printf("      PageHeight = %ld\n",bmhd->PageHeight);
                printf("      nplanes    = %ld\n",bmhd->nplanes);
                printf("      Masking    = %ld\n",bmhd->Masking);
                printf("      Compression= %ld\n",bmhd->Compression);
                printf("      TransColor = %ld\n",bmhd->TransparentColor);
                printf("      X/Y Aspect = %ld/%ld\n",bmhd->XAspect,bmhd->YAspect);
                }

        /*
         * Get a pointer to the stored propery CMAP
         */
        if (!(sp = FindProp(iff, ID_ILBM, ID_CMAP)))
                printf("No CMAP found\n");
        else
                {
                /* If property is CMAP, sp->sp_Data is ptr to data in CMAP */
                printf("CMAP: contains RGB values for %ld registers\n",
                                sp->sp_Size / 3);
                }

        /*
         * Get a pointer to the stored propery CAMG
         */
        if (!(sp = FindProp(iff, ID_ILBM, ID_CAMG)))
                printf("No CAMG found\n");
        else
                {
                /* If property is CAMG, sp->sp_Data is ptr to data in CAMG */
                camg = (CamgChunk *)sp->sp_Data;
                printf("CAMG: ModeID     = $%08lx\n\n",camg->ViewModes);
                }
        
}

other/sift.c

;/* sift.c - Execute me to compile me with SAS C 5.10
LC -b1 -cfistq -v -j73 sift.c
Blink FROM LIB:c.o,sift.o TO sift LIBRARY LIB:LC.lib,LIB:Amiga.lib
quit

*
* sift.c:       Takes any IFF file and tells you what's in it.  Verifies
*               syntax and all that cool stuff.
*
* Usage: sift -c                ; For clipboard scanning
*    or  sift <file>            ; For DOS file scanning
*
* Reads the specified stream and prints an IFFCheck-like listing of the
* contents of the IFF file, if any.  Stream is a DOS file for <file>
* argument, or is the clipboard's primary clip for -c.
* This program must be run from a CLI.
*
* Based on original sift.c by by Stuart Ferguson and Leo Schwab
*/

#include <exec/types.h>
#include <exec/memory.h>
#include <libraries/dos.h>
#include <libraries/iffparse.h>

#include <clib/exec_protos.h>
#include <clib/dos_protos.h>
#include <clib/iffparse_protos.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>

#ifdef LATTICE
int CXBRK(void) { return(0); }  /* Disable Lattice CTRL/C handling */
int chkabort(void) { return(0); }  /* really */
#endif

#define MINARGS 2

/* 2.0 Version string for c:Version to find */
UBYTE vers[] = "\0$VER: sift 37.1";

UBYTE usage[] = "Usage: sift IFFfilename (or -c for clipboard)";

/* proto for our function */
void PrintTopChunk (struct IFFHandle *);

/*
 * Text error messages for possible IFFERR_#? returns from various
 * IFF routines.  To get the index into this array, take your IFFERR code,
 * negate it, and subtract one.
 *  idx = -error - 1;
 */
char    *errormsgs[] = {
        "End of file (not an error).",
        "End of context (not an error).",
        "No lexical scope.",
        "Insufficient memory.",
        "Stream read error.",
        "Stream write error.",
        "Stream seek error.",
        "File is corrupt.",
        "IFF syntax error.",
        "Not an IFF file.",
        "Required call-back hook missing.",
        "Return to client.  You should never see this."
};

struct Library *IFFParseBase;


void main(int argc, char **argv)
{
    struct IFFHandle    *iff = NULL;
    long                error;
    short               cbio;

        /* if not enough args or '?', print usage */
        if(((argc)&&(argc<MINARGS))||(argv[argc-1][0]=='?'))
                {
                printf("%s\n",usage);
                goto bye;
                }

        /*
         * Check to see if we are doing I/O to the Clipboard.
         */
        cbio = (argv[1][0] == '-'  &&  argv[1][1] == 'c');

        if (!(IFFParseBase = OpenLibrary ("iffparse.library", 0L)))
                {
                puts("Can't open iff parsing library.");
                goto bye;
                }

        /*
         * Allocate IFF_File structure.
         */
        if (!(iff = AllocIFF ()))
                {
                puts ("AllocIFF() failed.");
                goto bye;
                }

        /*
         * Internal support is provided for both AmigaDOS files, and the
         * clipboard.device.  This bizarre 'if' statement performs the
         * appropriate machinations for each case.
         */
        if (cbio)
                {
                /*
                 * Set up IFF_File for Clipboard I/O.
                 */
                if (!(iff->iff_Stream =
                                (ULONG) OpenClipboard (PRIMARY_CLIP)))
                        {
                        puts ("Clipboard open failed.");
                        goto bye;
                        }
                InitIFFasClip (iff);
                }
        else
                {
                /*
                 * Set up IFF_File for AmigaDOS I/O.
                 */
                if (!(iff->iff_Stream = Open (argv[1], MODE_OLDFILE)))
                        {
                        puts ("File open failed.");
                        goto bye;
                        }
                InitIFFasDOS (iff);
                }

        /*
         * Start the IFF transaction.
         */
        if (error = OpenIFF (iff, IFFF_READ))
                {
                puts ("OpenIFF failed.");
                goto bye;
                }

        while (1)
                {
                /*
                 * The interesting bit.  IFFPARSE_RAWSTEP permits us to
                 * have precision monitoring of the parsing process, which
                 * is necessary if we wish to print the structure of an
                 * IFF file.  ParseIFF() with _RAWSTEP will return the
                 * following things for the following reasons:
                 *
                 * Return code:                 Reason:
                 * 0                            Entered new context.
                 * IFFERR_EOC                   About to leave a context.
                 * IFFERR_EOF                   Encountered end-of-file.
                 * <anything else>              A parsing error.
                 */
                error = ParseIFF (iff, IFFPARSE_RAWSTEP);

                /*
                 * Since we're only interested in when we enter a context,
                 * we "discard" end-of-context (_EOC) events.
                 */
                if (error == IFFERR_EOC)
                        continue;
                else if (error)
                        /*
                         * Leave the loop if there is any other error.
                         */
                        break;

                /*
                 * If we get here, error was zero.
                 * Print out the current state of affairs.
                 */
                PrintTopChunk (iff);
                }

        /*
         * If error was IFFERR_EOF, then the parser encountered the end of
         * the file without problems.  Otherwise, we print a diagnostic.
         */
        if (error == IFFERR_EOF)
                puts ("File scan complete.");
        else
                printf ("File scan aborted, error %ld: %s\n",
                        error, errormsgs[-error - 1]);

bye:
        if (iff) {
                /*
                 * Terminate the IFF transaction with the stream.  Free
                 * all associated structures.
                 */
                CloseIFF (iff);

                /*
                 * Close the stream itself.
                 */
                if (iff->iff_Stream)
                        if (cbio)
                                CloseClipboard ((struct ClipboardHandle *)
                                                iff->iff_Stream);
                        else
                                Close (iff->iff_Stream);

                /*
                 * Free the IFF_File structure itself.
                 */
                FreeIFF (iff);
                }
        if (IFFParseBase)       CloseLibrary (IFFParseBase);

        exit (RETURN_OK);
}


void
PrintTopChunk (iff)
struct IFFHandle *iff;
{
        struct ContextNode      *top;
        short                   i;
        char                    idbuf[5];

        /*
         * Get a pointer to the context node describing the current context.
         */
        if (!(top = CurrentChunk (iff)))
                return;

        /*
         * Print a series of dots equivalent to the current nesting depth of
         * chunks processed so far.  This will cause nested chunks to be
         * printed out indented.
         */
        for (i = iff->iff_Depth;  i--; )
                printf (". ");

        /*
         * Print out the current chunk's ID and size.
         */
        printf ("%s %ld ", IDtoStr (top->cn_ID, idbuf), top->cn_Size);

        /*
         * Print the current chunk's type, with a newline.
         */
        puts (IDtoStr (top->cn_Type, idbuf));
}