/* Sample IFF File Reader

 This function will return a pointer to a buffer that holds the raw image.
 just free the pointer to delete this buffer. After returning, the array
 colordat will hold the adjusted palette of this pic.

 Also, this has been modified to only read in form PBM brushes. form ILBM's
 (the "old" type) are not supported. use the "new" deluxe paint .lbm type
 and do not choose "old".
*/

#include <stdio.h>
#include <fcntl.h>
#include "ack3d.h"
#include "ackext.h"
#include "iff.h"

unsigned char  colordat[768];  /* maximum it can be...256 colors	*/

unsigned char  cplanes[8][80]; /* setting max at 640 pixels width	*/
				   /* thats 8 pixels per byte per plane */
unsigned char  *pplanes= (char*) &cplanes[0][0];  /* for a form pbm	    */

int ErrorCode;

unsigned char * Readiff(char *picname)
{
FILE *pic;
form_chunk	fchunk;
ChunkHeader	chunk;
BitMapHeader bmhd;
long length;
char value;	   /* must remain signed, no matter what. ignore any warnings. */
int sofar;
int width,height,planes;
int pixw;
unsigned char *destx, *savedestx;

	fprintf(stderr, "%s\n", picname);
   	if ((pic = fopen(picname,"r"))== NULL) {
		ErrorCode = ERR_BADPICNAME;
		return(0L);
	}

   	fread(&fchunk,1,sizeof(form_chunk),pic); /* read in the first 12 bytes*/

   	if (fchunk.type != FORM) {
      		fclose(pic);
      		ErrorCode = ERR_INVALIDFORM;
      		return(0L);
      	}

   	if (fchunk.subtype != ID_PBM) {
      		printf("Error: Not form PBM!");
      		fclose(pic);
      		ErrorCode = ERR_NOPBM;
      		return(0L);
      	}
   	/* now lets loop...Because the Chunks can be in any order! */
   	while(1) {
      		fread(&chunk,1,sizeof(ChunkHeader),pic);
      		ByteFlipLong(&chunk.ckSize);
      		if (chunk.ckSize & 1) chunk.ckSize ++;	/* must be word aligned */
      		if(chunk.ckID == ID_BMHD) {
	  		fread(&bmhd,1,sizeof(BitMapHeader),pic);
	  		bmhd.w=swab(bmhd.w);			/* the only things we need. */
	  		bmhd.h=swab(bmhd.h);
	  		destx = (unsigned char*)malloc((bmhd.w * bmhd.h)+4);
	  		if ( !destx ) {
	    			fclose(pic);
	    			ErrorCode = ERR_NOMEMORY;
	    			return(0L);
	    		}

	  		savedestx = destx;

	  		destx[0] = bmhd.w%256;
	  		destx[1] = bmhd.w/256;
	  		destx[2] = bmhd.h%256;
	  		destx[3] = bmhd.h/256;
	  		destx += 4;
	  		continue;
	  	}
      		if(chunk.ckID == ID_CMAP) {
	  	int i;
	  	unsigned char r,g;

	  		fread(colordat,1,chunk.ckSize,pic);
	  		for (i=0;i<768;i++) {
	       			r = colordat[i];	  /* r,g do not stand for red and green */
	      			g = r >> 2;
	      			colordat[i] = g;
	      		}
	  		continue;
	  	}
      		if(chunk.ckID == ID_BODY) {
	  		for(height = 0; height<bmhd.h; height ++) {
	     		unsigned char *dest;
	     			dest = (unsigned char *)&(pplanes[0]); /* point at first char  */
	     			sofar = bmhd.w;			    /* number of bytes = 8  */
	     			if (sofar&1) sofar++;
	     			while (sofar) {
					if (bmhd.compression) {
		   				value=fgetc(pic);	  /* get the next byte	  */
		   				/* if (value == 128) continue; /* NOP..just get another*/
		   				if (value > 0) {
		      				int len;
		      					len = value +1;
		      					sofar -= len;
		      					if(!(fread(dest,len,1,pic))) {
			  					fclose(pic);
			  					ErrorCode = ERR_BADPICFILE;
			  					free(savedestx);
			  					return(0L);
			  				}
		      					dest +=len;
		      				} else {
		      				int count;
		      					count = -value; /* get amount to dup */
		      					count ++;
		      					sofar -= count;
		      					value=fgetc(pic);
		      					while (--count >= 0) *dest++ = value;
		      				}
		   			} else {
		   				fread(dest,sofar,1,pic); /* just throw on plane */
		   				sofar = 0;
		   			}
				}
	     			if (sofar < 0) {
					fclose(pic);
				}
	     			memcpy(destx,pplanes,bmhd.w);
	     			destx += bmhd.w;
	     		}
	  		break; /* leave if we've unpacked the BODY*/
	 	}
      		fseek(pic,chunk.ckSize,SEEK_CUR);
      	}

   	fclose(pic);
   	return((char*)savedestx);
}

void ByteFlipLong(long *NUMBER)
{
   /* Hey, I didn;t write this function!!! */
long int Y, T;
int I;

   	T = *NUMBER;
   	Y = 0;
   	for (I = 0; I < 4; I++) {
   		Y = Y | (T & 0xFF);
   		if (I<3) { 
   			Y = Y << 8;T = T >> 8;
   		}
   	}
   	*NUMBER = Y;
}

int swab(unsigned short number)
{
unsigned int xx1,xx2;
unsigned int result;

   	xx1 = number <<8; xx2 = number >>8; result = xx1|xx2;
   	return(result);
}
