
/* JIFF.H */

/************ I usually put these in a file called format.h ****/


#define XMAX 640
#define LOXMAX 320
#define YMAX 200
#define XASPECT 5
#define YASPECT 11

/* EA handy make a long from 4 chars macros redone to work with Aztec*/
#define MAKE_ID(a, b, c, d)\
( ((long)(a)<<24) | ((long)(b)<<16) | ((long)(c)<<8) | (long)(d) )

/* These are the IFF types I deal with */
#define FORM MAKE_ID('F', 'O', 'R', 'M')
#define ILBM MAKE_ID('I', 'L', 'B', 'M')
#define BMHD MAKE_ID('B', 'M', 'H', 'D')
#define CMAP MAKE_ID('C', 'M', 'A', 'P')
#define BODY MAKE_ID('B', 'O', 'D', 'Y')

/* And these are the IFF types I ignore but don't squawk about */
#define GRAB MAKE_ID('G', 'R', 'A', 'B')
#define DEST MAKE_ID('D', 'E', 'S', 'T')
#define SPRT MAKE_ID('S', 'P', 'R', 'T')
#define CAMG MAKE_ID('C', 'A', 'M', 'G')
#define CRNG MAKE_ID('C', 'R', 'N', 'G')
#define CCRT MAKE_ID('C', 'C', 'R', 'T')

#define EVEN(x)	(((x) + 1) & ~1)
#define MANDEL

/* Some macros for raster memory allocation ... redefine if you're
   sensible and manage memory locally */

#ifndef MANDEL

	/* ralloc - raster alloc */
# define ralloc(amount)  (PLANEPTR)AllocMem((long)(amount), MEMF_CHIP)
	/* rfree - raster free */
# define rfree(pt, amount)	FreeMem( (pt), (long)(amount) )

#else /* MANDEL */

# include <mandel.h>
/*
 * We don't want to allocate a complete raster for the picture, since we
 * already have a screen with a window where we want to have it.
 * Therefore, we allocate some small buffers, which get blitted into
 * our window as soon as they fill up.
 */
# define MAXPLANESIZE	1040L
	/* ralloc - raster alloc */
# define ralloc(amount) (PLANEPTR)AllocMem(MAXPLANESIZE, MEMF_CHIP)
	/* rfree - raster free */
# define rfree(pt, amount)	FreeMem( (pt), MAXPLANESIZE )

#endif /* !MANDEL */

/* line_bytes = the number of words * 2 (for bytes) a raster line takes up */
#define line_bytes(width)	(((width + 15) >> 3) & ~0x0001)

/* psize - plane size in bytes (an even number) of a raster given
   width and height */
#define psize(width, height) ( line_bytes(width)*height)

/* The place to throw excess bits */
#define bit_bucket(file, length) fseek(file, (long)EVEN(length), 1)


union bytes4
{
	char b4_name[4];
	long b4_type;
};

struct iff_chunk
{
	union bytes4 iff_type;
	long iff_length;
};

struct form_chunk
{
	union bytes4 fc_type; /* == FORM */
	long fc_length;
	union bytes4 fc_subtype;
};

#ifndef MANDEL		/* We have this already in Mandel.H */
struct BitMapHeader
{
	UWORD w, h;
	UWORD x, y;
	UBYTE nPlanes;
	UBYTE masking;
	UBYTE compression;
	UBYTE pad1;
	UWORD transparentColor;
	UBYTE xAspect, yAspect;
	WORD pageWidth, pageHeight;
};

/* ILBM_info is the structure read_iff returns, and is hopefully all
   you need to deal with out of the iff reader routines below */
struct ILBM_info
{
	struct BitMapHeader header;
	UBYTE cmap[MAXCOL*3];
	struct BitMap bitmap;
};

#endif /* !MANDEL */

/* I sure wish C function "prototypes" were real and not just ANSI
 * extern struct ILBM_info *read_iff();
 * read_iff( char *filename, short just_colors, int ExtraSize,
 * 	APTR ExtraInfo );
 * extern void free_planes();  free_planes( struct BitMap *bitmap);
 * extern int write_iff();
 * write_iff(char *name, unsigned char *colors, struct BitMap *bits,
 *	short xoff, short yoff, short width, short compressed);
 */

/* extern char *AllocMem(); */


/* Anyone know where some useful minterms are defined? */
#define COPY_MINTERM		0x0C0L

/***

		A meditation for the guru from the Diamond Sutra -

		So shall you think of all this fleeting world:
		A star at dawn, a bubble in a stream;
		A flash of lightning in a summer cloud,
		A flickering lamp, a phantom, and a dream.

***/


/**********************************************************************
*
*			jiff.c   Jim Kent's iff - ilbm  reader
*
* This is the (sortof) short (sortof) simple no-frills IFF reader
* to get something out of DPaint, Images, or the Animator.  It
* works well with the Aztec C compiler.  It should work with Lattice
* but you never know until you try it.  I haven't.
*
* I've included a simple main program.  This is just to make it
* stand alone.  Since amiga screen initializations are massive, all
* it does as is is read it into a BitMap, and then free up the BitMap.
* Should crash it if it's gonna crash though.
*
* The main interface to this is through the routine read_iff(filename).
* This returns a ILBM_info structure-pointer on success, and NULL on
* failure.  It cleans up after itself on failure.
*
* I hope you will find this useful and easy to use.  Please forgive
* my funky indentation style?  Well at least I'm consistent!
* (* Run through the C-Beautifier by Olaf Seibert !! *)
*
* To demonstrate what a nice guy I am even though I'm far from wild
* about the IFF standard I'm placing this in the public domain.  When
* you remove the DEBUG and PARANOID definitions the code is only
* 1536 bytes long.
*
*		-Jim Kent  April 22, 1986
************************************************************************/


#include <stdio.h>
#include <exec/types.h>
#include <exec/memory.h>
#include <graphics/gfx.h>
#include <libraries/dos.h>
/* #include "jiff.h"	*/


/* This is an all too common state of software development.  Get rid
   of this define as soon as it runs. */
#undef DEBUG

/* This is the normal state of software development.  Seriously undefine
   this to make it shut up about errors and reduce code size half way
   through beta testing... */
#undef PARANOID

/* This is nice if you want to use a debugger on the STATIC data and
   routines in this file. Redefine only if you don't need a debugger. */
/* #undef STATIC */
/* #define STATIC */

STATIC struct ILBM_info *read_ilbm(), *read_body();

/* OK this code is almost re-entrant.  Pass this guy from above to
   make it really re-entrant.  (Why do you need a reentrant ILBM
   reader though??  Maybe for Dale ... )
   Well, look in the IFF specs for instance... [Olaf Seibert, KosmoSoft] */
STATIC struct ILBM_info root_info;  /* static so get initialized to zero */


#ifdef PARANOID
/* a little paranoid routine that say's where we got before EOF */
STATIC void iff_truncated(where)
int where;
{
	printf("ILBM truncated %d\n", where);
	free_planes(&root_info.bitmap);
}
#endif PARANOID


struct ILBM_info *read_iff(name, just_colors, ExtraSize, ExtraPointer)
char *name;
short just_colors;
int ExtraSize;
APTR ExtraPointer;
{
	struct ILBM_info *info = &root_info;
	FILE *file;
	struct form_chunk chunk;

	if ((file = fopen(name, "r") ) == 0) {
#ifdef PARANOID
		printf("couldn't Open %s to read\n", name);
#endif PARANOID
		return NULL;
	}

	if ( fread(&chunk, sizeof(struct form_chunk), 1, file) != 1) {
#ifdef PARANOID
		iff_truncated(0);
#endif PARANOID
		fclose(file);
		return NULL;
	}

	if (chunk.fc_type.b4_type != FORM) {
#ifdef PARANOID
		printf("not a FORM - %s\n", name);
#endif PARANOID
		fclose(file);
		return NULL;
	}

	if (chunk.fc_subtype.b4_type != ILBM) {
#ifdef PARANOID
		printf("FORM not an ILBM - %s\n", name);
#endif PARANOID
		fclose(file);
		return NULL;
	}

#ifdef DEBUG
	printf("FORM %ld ILBM\n", chunk.fc_length);
#endif DEBUG

	info = read_ilbm(file, info, chunk.fc_length - sizeof(chunk), just_colors);
#ifdef DEBUG
	printf("info = %lx\n", info);
#endif DEBUG

#ifdef MANDEL
	if (info && ExtraSize) {
		/* We may want to read the extra MAND */
		fread(ExtraPointer, 1, ExtraSize, file);
	}
#endif MANDEL

	fclose(file);

	return info;
}

STATIC struct ILBM_info *read_ilbm(file, info, length, just_colors)
FILE *file;
struct ILBM_info *info;
long length;
short just_colors;
{
	struct iff_chunk chunk;
	int i;
	long read_in = 0;
	int got_header = FALSE;  /* To make sure gots the header first */
	int got_cmap = FALSE;    /* Make sure get cmap before "BODY" */

/* Make sure the Planes are all NULL so can free up memory easily
   on error abort */
	for (i=0; i<8; i++)
		info->bitmap.Planes[i] = NULL;

	while (read_in < length) {
		if (fread(&chunk, sizeof(chunk), 1, file) != 1) {
#ifdef PARANOID
			iff_truncated(1);
#endif PARANOID
			return NULL;
		}
		switch (chunk.iff_type.b4_type) {
		case BMHD:
#ifdef DEBUG
			printf("\tBMHD %ld\n", chunk.iff_length);
#endif DEBUG
			if (fread(&info->header, sizeof(info->header), 1, file) != 1) {
#ifdef PARANOID
				iff_truncated(2);
#endif PARANOID
				return NULL;
			}
			got_header = TRUE;
			break;
		case CMAP:
#ifdef DEBUG
			printf("\tCMAP %ld\n", chunk.iff_length);
#endif DEBUG
			if (!got_header) {
#ifdef PARANOID
				printf("CMAP befor BMHD\n");
#endif PARANOID
				return NULL;
			}
			if (chunk.iff_length <= 3*MAXCOL ) {
				if (fread(info->cmap, (int)chunk.iff_length, 1, file) != 1) {
#ifdef PARANOID
					iff_truncated(3);
#endif PARANOID
					return NULL;
				}
			} else {
#ifdef PARANOID
				printf("warning, more than %d colors in ILBM CMAP\n",
					MAXCOL);
#endif PARANOID
				if (fread(info->cmap, (int) 3*MAXCOL, 1, file) != 1) {
#ifdef PARANOID
					iff_truncated(4);
#endif PARANOID
					return NULL;
				}
				bit_bucket(file, chunk.iff_length - 3*MAXCOL);
			}
			got_cmap = TRUE;
			if (just_colors)
				return info;
			break;
		case BODY:
			if (!got_cmap) {
#ifdef PARANOID
				printf("BODY before CMAP\n");
#endif PARANOID
				return NULL;
			}
#ifdef DEBUG
			printf("\tBODY %ld\n", chunk.iff_length);
#endif DEBUG
			return read_body(file, info, chunk.iff_length);

		default:	/* Squawk about unknown types if PARANOID */
#ifdef PARANOID
			printf("\t unknown type %lx of b4_type\n", chunk.iff_type.b4_type);
		case GRAB:  /* Ignore documented but unwanted types */
		case DEST:
		case SPRT:
		case CAMG:
		case CRNG:
		case CCRT:
#endif PARANOID
			bit_bucket(file, chunk.iff_length);
			break;
		}
		read_in += EVEN(chunk.iff_length) + sizeof(chunk);
	}
#ifdef PARANOID
	printf("no BODY in ILBM\n");
#endif PARANOID
	return NULL; 
}



STATIC struct ILBM_info *read_body(file, info, length)
FILE *file;
register struct ILBM_info *info;
long length;
{
	struct ILBM_header *header;
	struct BitMap *bm;
	int i, j;
	int rlength;
	int plane_offset;
#ifdef MANDEL
	int YSize, DestY = 0;
#endif

#ifdef DEBUG
	printf("read_body( %lx %lx %ld)\n", file, info, length);
#endif DEBUG

#ifdef PARANOID
/* When paranoid do a little error checking first ... fail fast! */
	if (info->header.nPlanes > 8) {
		printf("Whoa, woe  Dale only speaks 8 planes boy, not %d\n",
		info->header.nPlanes);
		return NULL;
	}
#endif PARANOID

/* Ok a little more error checking */
	if (info->header.compression != 0 && info->header.compression != 1) {
#ifdef PARANOID
		printf("unrecognized compression type %d\n", info->header.compression);
#endif PARANOID
		return NULL;
	}

/* Set up the bitmap part that doesn't involve memory allocation first -
   hey this part does get done, and let's be optimistic...*/
	info->bitmap.BytesPerRow = line_bytes(info->header.w);
	info->bitmap.Rows = info->header.h;
	info->bitmap.Depth = info->header.nPlanes;
	info->bitmap.Flags = info->bitmap.pad = 0;

	rlength = info->bitmap.Rows * info->bitmap.BytesPerRow;

	for (i=0; i<info->header.nPlanes; i++) {
		if ((info->bitmap.Planes[i] = ralloc(rlength)) == NULL) {
#ifdef PARANOID
			printf("couldn't alloc plane %d in read_body\n",i);
#endif PARANOID
			free_planes( &info->bitmap );
			return NULL;
		}
	}

	plane_offset = 0;
#ifdef MANDEL
	YSize = (MAXPLANESIZE / info->bitmap.BytesPerRow);
#endif MANDEL
	for (i=0; i<info->bitmap.Rows; i++) {
	/* This test should be in the inner loop for shortest code,			*/
	/* in the outer loop for greatest speed, so sue me I compromised	*/
		if (info->header.compression == 0) {
			for (j = 0; j < info->bitmap.Depth; j++) {
				if ( fread(info->bitmap.Planes[j] + plane_offset,
					info->bitmap.BytesPerRow, 1, file) != 1) {
#ifdef PARANOID
					iff_truncated(6);
#endif PARANOID
					free_planes( &info->bitmap);
					return NULL;
				}
			}
		} else {
			register char *dest, value;
			register int so_far, count;  /* How much have unpacked so far */

			for (j = 0; j < info->bitmap.Depth; j++) {
				so_far = info->bitmap.BytesPerRow;
				dest = (char *)info->bitmap.Planes[j] + plane_offset;
				while (so_far > 0) {
					if ( (value = getc(file)) == 128) {
#ifdef DEBUG
						printf("NOP\n");
#endif DEBUG
					} else if (value > 0) {
						count = (int)value + 1;
						so_far -= count;
						if ( fread(dest, count, 1, file) != 1) {
#ifdef PARANOID
							iff_truncated(7);
#endif PARANOID
							free_planes( &info->bitmap);
							return NULL;
						}
						dest += count;
					} else  {
						count = (int)-value + 1;
						so_far -= count;
						value = getc(file);
						while (--count >= 0)  /* This is fastest loop on the 68000 */
							*dest++ = value;
					}
				}
				if (so_far != 0) {
#ifdef PARANOID
					printf("compression quite screwed up, aborting %d\n", so_far);
#endif PARANOID
					free_planes( &info->bitmap);
					return NULL;
				}
			}
		}
		plane_offset += info->bitmap.BytesPerRow;
#ifdef MANDEL
		if (plane_offset > MAXPLANESIZE - info->bitmap.BytesPerRow) {
			BltBitMapRastPort(&info->bitmap, 0L, 0L, MainWindow->RPort,
				0L, (long) DestY, info->bitmap.BytesPerRow * 8L,
				(long) YSize, COPY_MINTERM);
			plane_offset = 0;
			DestY += YSize;
		}
#endif MANDEL
	}
#ifdef MANDEL
	if (plane_offset) {
		BltBitMapRastPort(&info->bitmap, 0L, 0L, MainWindow->RPort,
			0L, (long) DestY, info->bitmap.BytesPerRow * 8L,
			(long) plane_offset / info->bitmap.BytesPerRow, COPY_MINTERM);
	}
#endif MANDEL

	if (length & 1) {
		/* Skip padding byte */
		getc(file);
	}

	return info;
}


void free_planes(bmap)
register struct BitMap *bmap;
{
	PLANEPTR plane;
	long length;
	short i;

	length = bmap->BytesPerRow * bmap->Rows;

	for (i=0; i<8; i++)
		if ( (plane = bmap->Planes[i]) != NULL)
			rfree(plane, length);
}






#undef DEBUG
#undef PARANOID

/*----------------------------------------------------------------------*
 * jpacker.c Convert data to "cmpByteRun1" run compression.  
 *
 * pack_row() is an adaptation of PackRow() 
 * by Jerry Morrison and Steve Shaw, Electronic Arts,
 * modified and tweaked by Jim Kent, Dancing Flame 05/02/86
 *
 *	control bytes:
 *	 [0..127]   : followed by n+1 bytes of data.
 *	 [-1..-127] : followed by byte to be repeated(-n)+1 times.
 *	 -128       : NOOP.
 *
 *
 * write_iff() is the only function you can access in this module.
 *----------------------------------------------------------------------*/

/*
	#include <exec/types.h>
	#include <graphics/gfx.h>
	#include <stdio.h>
	#include "jiff.h"
*/

#define DUMP	0
#define RUN	1

#define MINRUN 3	
#define MAXRUN 128
#define MAXDAT 128

/* pack_row - pass source line pointer, length of line, and file.
   Returns # of bytes after compression.  Returns 0 on write error.
   Pass file = NULL to just find out length, 
   otherwise will write compressed row to file. */
STATIC unsigned int pack_row(file, source, size)
FILE *file;
char *source;
int size;
{
	char    c,
	lastc = '\0';
	short mode = DUMP;
	short   nbuf = 0;		/* Number of chars in buffer */
	short   rstart = 0;		/* Buffer index current run starts */
	unsigned short putsize;
	char    buf[MAXDAT*3/2];		/* I think MAXDAT+1 would suffice */

	putsize = 0;
	buf[0] = lastc = *source++;/* So have valid lastc */
	nbuf = 1;
	size--;			/* Since one byte eaten. */


	for (; size; --size) {
		buf[nbuf++] = c = *source++;
		switch (mode) {
		case DUMP: 
			/* If the buffer is full, write the length byte, then the data */
			if (nbuf > MAXDAT) {
				if (file != NULL) {
					if (putc(nbuf-2, file) == EOF)
						return 0;
					if (fwrite(buf, nbuf-1, 1, file) != 1)
						return 0;
				}
				putsize += nbuf;
				buf[0] = c;
				nbuf = 1;
				rstart = 0;
				break;
			}

			if (c == lastc) {
				if (nbuf - rstart >= MINRUN) {
					if (rstart > 0) {
						if (file != NULL) {
							if (putc(rstart-1, file) == EOF)
								return 0;
							if (fwrite(buf, rstart, 1, file) != 1)
								return 0;
						}
						putsize += rstart+1;
					}
					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 */
				if (file != NULL) {
					if (putc( -(nbuf - rstart - 2), file) == EOF)
						return 0;
					if (putc( lastc, file) == EOF)
						return 0;
				}
				putsize += 2;
				buf[0] = c;
				nbuf = 1;
				rstart = 0;
				mode = DUMP;
			}
			break;
		}

		lastc = c;
	}

	switch (mode) {
	case DUMP: 
		if (file != NULL) {
			if (putc(nbuf-1, file) == EOF)
				return 0;
			if (fwrite(buf, nbuf, 1, file) != 1)
				return 0;
		}
		putsize += nbuf+1;
		break;
	case RUN: 
		if (file != NULL) {
			if (putc( -(nbuf - rstart - 1), file) == EOF)
				return 0;
			if (putc( lastc, file) == EOF)
				return 0;
		}
		putsize += 2;
		break;
	}
	return putsize;
}


STATIC unsigned long pack_bitmap(file, bm)
FILE *file;
struct BitMap *bm;
{
	unsigned short i, j;
	unsigned row_length;
	unsigned long compressed_length;
	unsigned plane_offset;

#ifdef DEBUG
	printf("pack_bitmap( %lx %lx)\n", file, bm);
#endif DEBUG

#ifdef PARANOID
/* When paranoid do a little error checking first ... Fail fast! */
	if (bm->BytesPerRow <= 0 || bm->Rows <= 0 || bm->BytesPerRow > MAXDAT) {
		printf("bitmap %d bytes by %d rows?????\n", bm->BytesPerRow,
		bm->Rows);
		return 0;
	}
	if (bm->Depth <= 0 || bm->Depth > 8) {
		printf("bitmap with %d planes ??????\n", bm->Depth);
		return 0;
	}
#endif PARANOID

	compressed_length = 0;
	plane_offset = 0;
	for (i=0; i<bm->Rows; i++) {
		for (j = 0; j < bm->Depth; j++) {
			if ( (row_length = pack_row(file, bm->Planes[j] + plane_offset, 
			bm->BytesPerRow)) == 0) {
#ifdef PARANOID
				printf("error packing row %d plane %d\n", i, j);
#endif PARANOID
				return 0;
			}
			compressed_length += row_length;
		}
		plane_offset += bm->BytesPerRow;
	}
	if ( compressed_length & 1) {  /* Check to see odd length */
		if (file != NULL) {
			if ( putc( 0, file) == EOF) {
				return 0;
			}
		}
		/* compressed_length++; Deleted!!! Padding should NOT be included */
		/* in the chunk size !!! */
	}
	return compressed_length;
}

int write_iff(name, colors, bits, xoff, yoff, width, compressed, ExtraSize, ExtraInfo)
char *name;
unsigned char *colors;
register struct BitMap *bits;
short xoff, yoff;
short compressed;
int ExtraSize;
APTR ExtraInfo;
{
	FILE *file;
	struct form_chunk chunk;
	struct iff_chunk ichunk;
	struct BitMapHeader header;
	long bits_size;
	short i;
	register short j;
	register short row_offset;

	if ((file = fopen(name, "w") ) == 0) {
#ifdef PARANOID
		printf("couldn't Open %s to write\n", name);
#endif PARANOID
		goto abort;
	}

	/* Say its a FORM ILBM */
	chunk.fc_type.b4_type = FORM;
	chunk.fc_subtype.b4_type = ILBM;
#ifdef MANDEL
	chunk.fc_length = 4 + 3*sizeof(struct iff_chunk) + MAXCOL*3 + 
	    sizeof(struct BitMapHeader) + ExtraSize;
#else
	chunk.fc_length = 4 + 3*sizeof(struct iff_chunk) + MAXCOL*3 + 
	    sizeof(struct BitMapHeader);
#endif MANDEL
	if (bits) {
		if (compressed) {
			if ( (bits_size = pack_bitmap(NULL, bits)) == 0)
				goto abort;
		} else {
			bits_size =  bits->BytesPerRow*bits->Rows*bits->Depth;
		}
		chunk.fc_length += bits_size;
		if (bits_size & 1)	chunk.fc_length++;
	}
	if (fwrite(&chunk, sizeof(chunk), 1, file) != 1)
		goto abort;

/* Here comes a BitMapHeader */
	ichunk.iff_type.b4_type = BMHD;
	ichunk.iff_length = sizeof(header);
	if (fwrite(&ichunk, sizeof(ichunk), 1, file) != 1)
		goto abort;

/* Initialize the BitMapHeader to normal values */
	header.masking = 0;
	header.pad1 = 0;
	header.transparentColor = 0;
	if (compressed)
		header.compression = 1;
	else
		header.compression = 0;
	header.pageWidth = width;
	header.pageHeight = bits? bits->Rows: YMAX;
	header.xAspect = width > LOXMAX? XASPECT: XASPECT*2;
	header.yAspect = YASPECT;
/* If it's not just a color map give the dimensions of rasters */
	if (bits) {
		header.w = width;
		header.h = bits->Rows;
		header.nPlanes = bits->Depth;
		header.x = xoff;
		header.y = yoff;
	}
	if (fwrite(&header, sizeof(header), 1, file) != 1)
		goto abort;

/* Squirt out the color map */
	ichunk.iff_type.b4_type = CMAP;
	ichunk.iff_length = MAXCOL*3;
	if (fwrite(&ichunk, sizeof(ichunk), 1, file) != 1)
		goto abort;
	if (fwrite(colors, (int) 3*MAXCOL, 1, file) != 1)
		goto abort;

/* If they be bits then squirt out the bits */
	if (bits) {
		ichunk.iff_type.b4_type = BODY;
		ichunk.iff_length = bits_size;
		if (fwrite(&ichunk, sizeof(ichunk), 1, file) != 1)
			goto abort;
		if (compressed) {
			if (pack_bitmap(file, bits) == 0)
				goto abort;
		} else {
			i = bits->Rows;
			row_offset = 0;
			while (--i >= 0) {
				for (j=0; j<bits->Depth; j++) {
					if (fwrite( bits->Planes[j]+row_offset,
						bits->BytesPerRow, 1, file) != 1)
						goto abort;
				}
				row_offset += bits->BytesPerRow;
			}
		}
	}

#ifdef MANDEL
	if (ExtraSize) {
		/* We want to tack on an extra MAND */
		if (fwrite(ExtraInfo, ExtraSize, 1, file) != 1) goto abort;
	}
#endif MANDEL

	fclose(file);

	return 1;
abort:
	fclose(file);
	return 0;
}


/***********************************************************************
* put_ea_cmap given an ea-type color map:
* an array of unsigned chars of form ea_cmap[] = {r, g, b, r, g, b...}
* turn it into an amiga-type color map:
* an array of unsigned short of form amiga_cmap = {0xrgb, 0xrgb, ...}
* and then tell Dale this is the colors we want for our viewport
*/
void put_ea_cmap(ea_cmap, colors, Screen)
unsigned char *ea_cmap;
int colors;
struct Screen *Screen;
{
	unsigned short amy_cmap[MAXCOL];
	register int i;
	register short color;

	if (colors > MAXCOL)   /* Color clipping */
		colors = MAXCOL;
	for (i=0; i<colors; i++) {
		color  = (*ea_cmap++ & 0xF0) << 4;
		color |=  *ea_cmap++ & 0xF0;
		color |= (*ea_cmap++ & 0xF0) >> 4;
		amy_cmap[i] = color;
	}
	LoadRGB4( &Screen->ViewPort, amy_cmap, (long)colors);
}

void get_ea_cmap(ea_cmap, colors, Screen)
unsigned char *ea_cmap;
int colors;
struct Screen *Screen;
{
	register long i;
	register unsigned short rgb;

	if (colors > MAXCOL)   /* Color clipping */
		colors = MAXCOL;
	for (i=0; i<colors; i++) {
		rgb = GetRGB4(Screen->ViewPort.ColorMap, i);
		*ea_cmap++ = (rgb & 0xF00) >> 4;
		*ea_cmap++ = (rgb & 0x0F0);
		*ea_cmap++ = (rgb & 0x00F) << 4;
	}
}
