1 /* $Id: iff.c,v 1.7 2003-10-04 03:14:47 btb Exp $ */
3 THE COMPUTER CODE CONTAINED HEREIN IS THE SOLE PROPERTY OF PARALLAX
4 SOFTWARE CORPORATION ("PARALLAX"). PARALLAX, IN DISTRIBUTING THE CODE TO
5 END-USERS, AND SUBJECT TO ALL OF THE TERMS AND CONDITIONS HEREIN, GRANTS A
6 ROYALTY-FREE, PERPETUAL LICENSE TO SUCH END-USERS FOR USE BY SUCH END-USERS
7 IN USING, DISPLAYING, AND CREATING DERIVATIVE WORKS THEREOF, SO LONG AS
8 SUCH USE, DISPLAY OR CREATION IS FOR NON-COMMERCIAL, ROYALTY OR REVENUE
9 FREE PURPOSES. IN NO EVENT SHALL THE END-USER USE THE COMPUTER CODE
10 CONTAINED HEREIN FOR REVENUE-BEARING PURPOSES. THE END-USER UNDERSTANDS
11 AND AGREES TO THE TERMS HEREIN AND ACCEPTS THE SAME BY USE OF THIS FILE.
12 COPYRIGHT 1993-1999 PARALLAX SOFTWARE CORPORATION. ALL RIGHTS RESERVED.
17 * Routines for reading and writing IFF files
20 * Revision 1.2 1995/05/12 11:54:43 allender
21 * changed memory stuff again
23 * Revision 1.1 1995/05/05 08:59:41 allender
26 * Revision 1.43 1994/12/08 19:03:17 john
27 * Added code to use cfile.
29 * Revision 1.42 1994/12/08 17:45:32 john
30 * Put back in cfile stuff.
32 * Revision 1.41 1994/11/19 16:41:06 matt
33 * Took out unused code
35 * Revision 1.40 1994/11/07 21:26:39 matt
36 * Added new function iff_read_into_bitmap()
38 * Revision 1.39 1994/10/27 00:12:03 john
41 * Revision 1.38 1994/08/10 19:49:58 matt
42 * Fixed bitmaps in ILBM format with masking (stencil) on.
44 * Revision 1.37 1994/06/02 18:53:17 matt
45 * Clear flags & selector in new bitmap structure
47 * Revision 1.36 1994/05/17 14:00:33 matt
48 * Fixed bug with odd-width deltas & odd-length body chunks
50 * Revision 1.35 1994/05/16 20:38:55 matt
51 * Made anim brushes work when odd width
53 * Revision 1.34 1994/05/06 19:37:26 matt
54 * Improved error handling and checking
56 * Revision 1.33 1994/04/27 20:57:07 matt
57 * Fixed problem with RLE decompression and odd-width bitmap
58 * Added more error checking
60 * Revision 1.32 1994/04/16 21:44:19 matt
61 * Fixed bug introduced last version
63 * Revision 1.31 1994/04/16 20:12:40 matt
64 * Made masked (stenciled) bitmaps work
66 * Revision 1.30 1994/04/13 23:46:16 matt
67 * Added function, iff_errormsg(), which returns ptr to error message.
69 * Revision 1.29 1994/04/13 23:27:25 matt
70 * Put in support for anim brushes (.abm files)
72 * Revision 1.28 1994/04/13 16:33:31 matt
73 * Cleaned up file read code, adding fake_file structure (FFILE), which
74 * cleanly implements reading the entire file into a buffer and then reading
77 * Revision 1.27 1994/04/06 23:07:43 matt
78 * Cleaned up code; added prototype (but no new code) for anim brush read
80 * Revision 1.26 1994/03/19 02:51:52 matt
81 * Really did what I said I did last revision.
83 * Revision 1.25 1994/03/19 02:16:07 matt
84 * Made work ILBMs which didn't have 8 planes
86 * Revision 1.24 1994/03/15 14:45:26 matt
87 * When error, only free memory if has been allocated
89 * Revision 1.23 1994/02/18 12:39:05 john
90 * Made code read from buffer.
92 * Revision 1.22 1994/02/15 18:15:26 john
93 * Took out cfile attempt (too slow)
95 * Revision 1.21 1994/02/15 13:17:48 john
96 * added assert to cfseek.
98 * Revision 1.20 1994/02/15 13:13:11 john
99 * Made iff code work normally.
101 * Revision 1.19 1994/02/15 12:51:07 john
102 * crappy inbetween version.
104 * Revision 1.18 1994/02/10 18:31:32 matt
105 * Changed 'if DEBUG_ON' to 'ifndef NDEBUG'
107 * Revision 1.17 1994/01/24 11:51:26 john
108 * Made write routine write transparency info.
110 * Revision 1.16 1994/01/22 14:41:11 john
111 * Fixed bug with declareations.
113 * Revision 1.15 1994/01/22 14:23:00 john
114 * Added global vars to check transparency
116 * Revision 1.14 1993/12/08 19:00:42 matt
117 * Changed while loop to memset
119 * Revision 1.13 1993/12/08 17:23:51 mike
120 * Speedup by converting while...getc to fread.
122 * Revision 1.12 1993/12/08 12:37:35 mike
123 * Optimize parse_body.
125 * Revision 1.11 1993/12/05 17:30:14 matt
126 * Made bitmaps with width <= 64 not compress
128 * Revision 1.10 1993/12/03 12:24:51 matt
129 * Fixed TINY chunk when bitmap was part of a larger bitmap
131 * Revision 1.9 1993/11/22 17:26:43 matt
132 * iff write now writes out a tiny chunk
134 * Revision 1.8 1993/11/21 22:04:13 matt
135 * Fixed error with non-compressed bitmaps
136 * Added Yuan's code to free raw data if we get an error parsing the body
138 * Revision 1.7 1993/11/11 12:12:12 yuan
139 * Changed mallocs to MALLOCs.
141 * Revision 1.6 1993/11/01 19:02:23 matt
142 * Fixed a couple bugs in rle compression
144 * Revision 1.5 1993/10/27 12:47:39 john
145 * *** empty log message ***
147 * Revision 1.4 1993/10/27 12:37:31 yuan
150 * Revision 1.3 1993/09/22 19:16:57 matt
151 * Added new error type, IFF_CORRUPT, for internally bad IFF files.
153 * Revision 1.2 1993/09/08 19:24:16 matt
154 * Fixed bug in RLE compression
155 * Changed a bunch of unimportant values like aspect and page size when writing
156 * Added new error condition, IFF_BAD_BM_TYPE
157 * Make sub-bitmaps work correctly
158 * Added compile flag to turn compression off (COMPRESS)
160 * Revision 1.1 1993/09/08 14:24:15 matt
171 static char rcsid[] = "$Id: iff.c,v 1.7 2003-10-04 03:14:47 btb Exp $";
174 #define COMPRESS 1 //do the RLE or not? (for debugging mostly)
175 #define WRITE_TINY 0 //should we write a TINY chunk?
177 #define MIN_COMPRESS_WIDTH 65 //don't compress if less than this wide
186 //#include "nocfile.h"
190 //Internal constants and structures for this library
192 //Type values for bitmaps
198 #define cmpByteRun1 1
203 #define mskHasTransparentColor 2
205 //Palette entry structure
206 typedef struct pal_entry {
210 //structure of the header in the file
211 typedef struct iff_bitmap_header {
212 short w,h; //width and height of this bitmap
213 short x,y; //generally unused
214 short type; //see types above
215 short transparentcolor; //which color is transparent (if any)
216 short pagewidth,pageheight; //width & height of source screen
217 sbyte nplanes; //number of planes (8 for 256 color image)
218 sbyte masking,compression; //see constants above
219 sbyte xaspect,yaspect; //aspect ratio (usually 5/6)
220 pal_entry palette[256]; //the palette for this bitmap
221 ubyte *raw_data; //ptr to array of data
222 short row_size; //offset to next row
225 ubyte iff_transparent_color;
226 ubyte iff_has_transparency; // 0=no transparency, 1=iff_transparent_color is valid
228 typedef struct fake_file {
234 #define MIN(a,b) ((a<b)?a:b)
236 #define MAKE_SIG(a,b,c,d) (((long)(a)<<24)+((long)(b)<<16)+((c)<<8)+(d))
238 #define form_sig MAKE_SIG('F','O','R','M')
239 #define ilbm_sig MAKE_SIG('I','L','B','M')
240 #define body_sig MAKE_SIG('B','O','D','Y')
241 #define pbm_sig MAKE_SIG('P','B','M',' ')
242 #define bmhd_sig MAKE_SIG('B','M','H','D')
243 #define anhd_sig MAKE_SIG('A','N','H','D')
244 #define cmap_sig MAKE_SIG('C','M','A','P')
245 #define tiny_sig MAKE_SIG('T','I','N','Y')
246 #define anim_sig MAKE_SIG('A','N','I','M')
247 #define dlta_sig MAKE_SIG('D','L','T','A')
250 //void printsig(long s)
252 // char *t=(char *) &s;
254 ///* printf("%c%c%c%c",*(&s+3),*(&s+2),*(&s+1),s);*/
255 // printf("%c%c%c%c",t[3],t[2],t[1],t[0]);
259 long get_sig(FFILE *f)
263 // if ((s[3]=cfgetc(f))==EOF) return(EOF);
264 // if ((s[2]=cfgetc(f))==EOF) return(EOF);
265 // if ((s[1]=cfgetc(f))==EOF) return(EOF);
266 // if ((s[0]=cfgetc(f))==EOF) return(EOF);
268 #ifndef WORDS_BIGENDIAN
269 if (f->position>=f->length) return EOF;
270 s[3] = f->data[f->position++];
271 if (f->position>=f->length) return EOF;
272 s[2] = f->data[f->position++];
273 if (f->position>=f->length) return EOF;
274 s[1] = f->data[f->position++];
275 if (f->position>=f->length) return EOF;
276 s[0] = f->data[f->position++];
278 if (f->position>=f->length) return EOF;
279 s[0] = f->data[f->position++];
280 if (f->position>=f->length) return EOF;
281 s[1] = f->data[f->position++];
282 if (f->position>=f->length) return EOF;
283 s[2] = f->data[f->position++];
284 if (f->position>=f->length) return EOF;
285 s[3] = f->data[f->position++];
288 return(*((long *) s));
291 int put_sig(long sig,FILE *f)
293 char *s = (char *) &sig;
298 return fputc(s[0],f);
302 char get_byte(FFILE *f)
305 return f->data[f->position++];
308 int put_byte(unsigned char c,FILE *f)
313 int get_word(FFILE *f)
320 if (f->position>=f->length) return EOF;
321 c1 = f->data[f->position++];
322 if (f->position>=f->length) return EOF;
323 c0 = f->data[f->position++];
325 if (c0==0xff) return(EOF);
327 return(((int)c1<<8) + c0);
331 int put_word(int n,FILE *f)
335 c0 = (n & 0xff00) >> 8;
339 return put_byte(c1,f);
342 int put_long(long n,FILE *f)
346 n0 = (int) ((n & 0xffff0000l) >> 16);
347 n1 = (int) (n & 0xffff);
350 return put_word(n1,f);
354 long get_long(FFILE *f)
356 unsigned char c0,c1,c2,c3;
363 if (f->position>=f->length) return EOF;
364 c3 = f->data[f->position++];
365 if (f->position>=f->length) return EOF;
366 c2 = f->data[f->position++];
367 if (f->position>=f->length) return EOF;
368 c1 = f->data[f->position++];
369 if (f->position>=f->length) return EOF;
370 c0 = f->data[f->position++];
372 //printf("get_long %x %x %x %x\n",c3,c2,c1,c0);
374 // if (c0==0xff) return(EOF);
376 return(((long)c3<<24) + ((long)c2<<16) + ((long)c1<<8) + c0);
380 int parse_bmhd(FFILE *ifile,long len,iff_bitmap_header *bmheader)
382 len++; /* so no "parm not used" warning */
384 // debug("parsing bmhd len=%ld\n",len);
386 bmheader->w = get_word(ifile);
387 bmheader->h = get_word(ifile);
388 bmheader->x = get_word(ifile);
389 bmheader->y = get_word(ifile);
391 bmheader->nplanes = get_byte(ifile);
392 bmheader->masking = get_byte(ifile);
393 bmheader->compression = get_byte(ifile);
394 get_byte(ifile); /* skip pad */
396 bmheader->transparentcolor = get_word(ifile);
397 bmheader->xaspect = get_byte(ifile);
398 bmheader->yaspect = get_byte(ifile);
400 bmheader->pagewidth = get_word(ifile);
401 bmheader->pageheight = get_word(ifile);
403 iff_transparent_color = bmheader->transparentcolor;
405 iff_has_transparency = 0;
407 if (bmheader->masking == mskHasTransparentColor)
408 iff_has_transparency = 1;
410 else if (bmheader->masking != mskNone && bmheader->masking != mskHasMask)
411 return IFF_UNKNOWN_MASK;
413 // debug("w,h=%d,%d x,y=%d,%d\n",w,h,x,y);
414 // debug("nplanes=%d, masking=%d ,compression=%d, transcolor=%d\n",nplanes,masking,compression,transparentcolor);
420 // the buffer pointed to by raw_data is stuffed with a pointer to decompressed pixel data
421 int parse_body(FFILE *ifile,long len,iff_bitmap_header *bmheader)
423 unsigned char *p=bmheader->raw_data;
426 int nn,wid_cnt,end_cnt,plane;
428 unsigned char *data_end;
437 end_pos = ifile->position + len;
441 if (bmheader->type == TYPE_PBM) {
444 } else if (bmheader->type == TYPE_ILBM) {
445 width = (bmheader->w+7)/8;
446 depth=bmheader->nplanes;
449 end_cnt = (width&1)?-1:0;
451 data_end = p + width*bmheader->h*depth;
453 if (bmheader->compression == cmpNone) { /* no compression */
456 for (y=bmheader->h;y;y--) {
458 // for (x=bmheader->w;x;x--) *p++=cfgetc(ifile);
459 // cfread(p, bmheader->w, 1, ifile);
462 for (x=0;x<width*depth;x++)
463 *p++=ifile->data[ifile->position++];
465 if (bmheader->masking == mskHasMask)
466 ifile->position += width; //skip mask!
468 // if (bmheader->w & 1) ignore = cfgetc(ifile);
469 if (bmheader->w & 1) ifile->position++;
472 //cnt = len - bmheader->h * ((bmheader->w+1)&~1);
475 else if (bmheader->compression == cmpByteRun1)
476 for (wid_cnt=width,plane=0;ifile->position<end_pos && p<data_end;) {
479 // if (old_cnt-cnt > 2048) {
484 if (wid_cnt == end_cnt) {
487 if ((bmheader->masking == mskHasMask && plane==depth+1) ||
488 (bmheader->masking != mskHasMask && plane==depth))
492 Assert(wid_cnt > end_cnt);
495 n=ifile->data[ifile->position++];
497 if (n >= 0) { // copy next n+1 bytes from source, they are not compressed
500 if (wid_cnt==-1) {--nn; Assert(width&1);}
501 if (plane==depth) //masking row
502 ifile->position += nn;
504 while (nn--) *p++=ifile->data[ifile->position++];
505 if (wid_cnt==-1) ifile->position++;
507 else if (n>=-127) { // next -n + 1 bytes are following byte
508 c=ifile->data[ifile->position++];
511 if (wid_cnt==-1) {--nn; Assert(width&1);}
512 if (plane!=depth) //not masking row
513 {memset(p,c,nn); p+=nn;}
517 if ((p-bmheader->raw_data) % width == 0)
520 Assert((p-bmheader->raw_data) - (width*row_count) < width);
525 if (p!=data_end) //if we don't have the whole bitmap...
526 return IFF_CORRUPT; //...the give an error
528 //Pretend we read the whole chuck, because if we didn't, it's because
529 //we didn't read the last mask like or the last rle record for padding
530 //or whatever and it's not important, because we check to make sure
531 //we got the while bitmap, and that's what really counts.
533 ifile->position = end_pos;
535 if (ignore) ignore++; // haha, suppress the evil warning message
540 //modify passed bitmap
541 int parse_delta(FFILE *ifile,long len,iff_bitmap_header *bmheader)
543 unsigned char *p=bmheader->raw_data;
545 long chunk_end = ifile->position + len;
547 get_long(ifile); //longword, seems to be equal to 4. Don't know what it is
549 for (y=0;y<bmheader->h;y++) {
551 int cnt = bmheader->w;
554 n_items = get_byte(ifile);
558 code = get_byte(ifile);
560 if (code==0) { //repeat
563 rep = get_byte(ifile);
564 val = get_byte(ifile);
572 else if (code > 0x80) { //skip
584 *p++ = get_byte(ifile);
600 if (ifile->position == chunk_end-1) //pad
603 if (ifile->position != chunk_end)
609 // the buffer pointed to by raw_data is stuffed with a pointer to bitplane pixel data
610 void skip_chunk(FFILE *ifile,long len)
616 //printf( "Skipping %d chunk\n", ilen );
618 ifile->position += ilen;
620 if (ifile->position >= ifile->length ) {
621 ifile->position = ifile->length;
625 // for (i=0; i<ilen; i++ )
626 // c = cfgetc(ifile);
627 //Assert(cfseek(ifile,ilen,SEEK_CUR)==0);
630 //read an ILBM or PBM file
631 // Pass pointer to opened file, and to empty bitmap_header structure, and form length
632 int iff_parse_ilbm_pbm(FFILE *ifile,long form_type,iff_bitmap_header *bmheader,int form_len,grs_bitmap *prev_bm)
636 long start_pos,end_pos;
638 start_pos = ifile->position;
639 end_pos = start_pos-4+form_len;
641 // printf(" %ld ",form_len);
642 // printsig(form_type);
645 if (form_type == pbm_sig)
646 bmheader->type = TYPE_PBM;
648 bmheader->type = TYPE_ILBM;
650 while ((ifile->position < end_pos) && (sig=get_sig(ifile)) != EOF) {
657 // printf(" %ld\n",len);
663 int save_w=bmheader->w,save_h=bmheader->h;
665 //printf("Parsing header\n");
667 ret = parse_bmhd(ifile,len,bmheader);
669 if (ret != IFF_NO_ERROR)
672 if (bmheader->raw_data) {
674 if (save_w != bmheader->w || save_h != bmheader->h)
675 return IFF_BM_MISMATCH;
680 MALLOC( bmheader->raw_data, ubyte, bmheader->w * bmheader->h );
681 if (!bmheader->raw_data)
691 if (!prev_bm) return IFF_CORRUPT;
693 bmheader->w = prev_bm->bm_w;
694 bmheader->h = prev_bm->bm_h;
695 bmheader->type = prev_bm->bm_type;
697 MALLOC( bmheader->raw_data, ubyte, bmheader->w * bmheader->h );
699 memcpy(bmheader->raw_data, prev_bm->bm_data, bmheader->w * bmheader->h );
700 skip_chunk(ifile,len);
706 int ncolors=(int) (len/3),cnum;
709 //printf("Parsing RGB map\n");
710 for (cnum=0;cnum<ncolors;cnum++) {
714 r = ifile->data[ifile->position++];
715 g = ifile->data[ifile->position++];
716 b = ifile->data[ifile->position++];
717 r >>= 2; bmheader->palette[cnum].r = r;
718 g >>= 2; bmheader->palette[cnum].g = g;
719 b >>= 2; bmheader->palette[cnum].b = b;
721 //if (len & 1) ignore = cfgetc(ifile);
722 if (len & 1 ) ifile->position++;
730 //printf("Parsing body\n");
731 if ((r=parse_body(ifile,len,bmheader))!=IFF_NO_ERROR)
738 if ((r=parse_delta(ifile,len,bmheader))!=IFF_NO_ERROR)
743 skip_chunk(ifile,len);
748 //if (ignore) ignore++;
750 if (ifile->position != start_pos-4+form_len)
753 return IFF_NO_ERROR; /* ok! */
756 //convert an ILBM file to a PBM file
757 int convert_ilbm_to_pbm(iff_bitmap_header *bmheader)
760 sbyte *new_data, *destptr, *rowptr;
761 int bytes_per_row,byteofs;
762 ubyte checkmask,newbyte,setbit;
764 MALLOC(new_data, sbyte, bmheader->w * bmheader->h);
765 if (new_data == NULL) return IFF_NO_MEM;
769 bytes_per_row = 2*((bmheader->w+15)/16);
771 for (y=0;y<bmheader->h;y++) {
773 rowptr = &bmheader->raw_data[y * bytes_per_row * bmheader->nplanes];
775 for (x=0,checkmask=0x80;x<bmheader->w;x++) {
779 for (p=newbyte=0,setbit=1;p<bmheader->nplanes;p++) {
781 if (rowptr[bytes_per_row * p + byteofs] & checkmask)
787 *destptr++ = newbyte;
789 if ((checkmask >>= 1) == 0) checkmask=0x80;
794 d_free(bmheader->raw_data);
795 bmheader->raw_data = new_data;
797 bmheader->type = TYPE_PBM;
802 #define INDEX_TO_15BPP(i) ((short)((((palptr[(i)].r/2)&31)<<10)+(((palptr[(i)].g/2)&31)<<5)+((palptr[(i)].b/2 )&31)))
804 int convert_rgb15(grs_bitmap *bm,iff_bitmap_header *bmheader)
811 palptr = bmheader->palette;
813 // if ((new_data = d_malloc(bm->bm_w * bm->bm_h * 2)) == NULL)
814 // {ret=IFF_NO_MEM; goto done;}
815 MALLOC(new_data, ushort, bm->bm_w * bm->bm_h * 2);
816 if (new_data == NULL)
819 for (y=0; y<bm->bm_h; y++) {
821 for (x=0; x<bmheader->w; x++)
822 new_data[newptr++] = INDEX_TO_15BPP(bmheader->raw_data[y*bmheader->w+x]);
826 d_free(bm->bm_data); //get rid of old-style data
827 bm->bm_data = (ubyte *) new_data; //..and point to new data
829 bm->bm_rowsize *= 2; //two bytes per row
835 //read in a entire file into a fake file structure
836 int open_fake_file(char *ifilename,FFILE *ffile)
841 //printf( "Reading %s\n", ifilename );
845 if ((ifile = cfopen(ifilename,"rb")) == NULL) return IFF_NO_FILE;
847 ffile->length = cfilelength(ifile);
849 MALLOC(ffile->data,ubyte,ffile->length);
851 if (cfread(ffile->data, 1, ffile->length, ifile) < ffile->length)
852 ret = IFF_READ_ERROR;
858 if (ifile) cfclose(ifile);
863 void close_fake_file(FFILE *f)
871 //copy an iff header structure to a grs_bitmap structure
872 void copy_iff_to_grs(grs_bitmap *bm,iff_bitmap_header *bmheader)
874 bm->bm_x = bm->bm_y = 0;
875 bm->bm_w = bmheader->w;
876 bm->bm_h = bmheader->h;
877 bm->bm_type = bmheader->type;
878 bm->bm_rowsize = bmheader->w;
879 bm->bm_data = bmheader->raw_data;
881 bm->bm_flags = bm->bm_handle = 0;
885 //if bm->bm_data is set, use it (making sure w & h are correct), else
886 //allocate the memory
887 int iff_parse_bitmap(FFILE *ifile, grs_bitmap *bm, int bitmap_type, sbyte *palette, grs_bitmap *prev_bm)
889 int ret; //return code
890 iff_bitmap_header bmheader;
894 bmheader.raw_data = bm->bm_data;
896 if (bmheader.raw_data) {
897 bmheader.w = bm->bm_w;
898 bmheader.h = bm->bm_h;
903 if (sig != form_sig) {
907 form_len = get_long(ifile);
909 form_type = get_sig(ifile);
911 if (form_type == anim_sig)
913 else if ((form_type == pbm_sig) || (form_type == ilbm_sig))
914 ret = iff_parse_ilbm_pbm(ifile,form_type,&bmheader,form_len,prev_bm);
916 ret = IFF_UNKNOWN_FORM;
918 if (ret != IFF_NO_ERROR) { //got an error parsing
919 if (bmheader.raw_data) d_free(bmheader.raw_data);
923 //If IFF file is ILBM, convert to PPB
924 if (bmheader.type == TYPE_ILBM) {
926 ret = convert_ilbm_to_pbm(&bmheader);
928 if (ret != IFF_NO_ERROR)
932 //Copy data from iff_bitmap_header structure into grs_bitmap structure
934 copy_iff_to_grs(bm,&bmheader);
937 if (palette) memcpy(palette,&bmheader.palette,sizeof(bmheader.palette));
939 // if (palette) memcpy(palette,&bmheader.palette, 768); // pal_entry is 4 bytes on mac
945 for (i = 0; i < 256; i++) {
946 *c++ = bmheader.palette[i].r;
947 *c++ = bmheader.palette[i].g;
948 *c++ = bmheader.palette[i].b;
953 //Now do post-process if required
955 if (bitmap_type == BM_RGB15) {
956 ret = convert_rgb15(bm,&bmheader);
957 if (ret != IFF_NO_ERROR)
965 //returns error codes - see IFF.H. see GR.H for bitmap_type
966 int iff_read_bitmap(char *ifilename,grs_bitmap *bm,int bitmap_type,ubyte *palette)
968 int ret; //return code
971 ret = open_fake_file(ifilename,&ifile); //read in entire file
972 if (ret == IFF_NO_ERROR) {
974 ret = iff_parse_bitmap(&ifile,bm,bitmap_type,palette,NULL);
977 if (ifile.data) d_free(ifile.data);
979 close_fake_file(&ifile);
986 //like iff_read_bitmap(), but reads into a bitmap that already exists,
987 //without allocating memory for the bitmap.
988 int iff_read_into_bitmap(char *ifilename, grs_bitmap *bm, sbyte *palette)
990 int ret; //return code
993 ret = open_fake_file(ifilename,&ifile); //read in entire file
994 if (ret == IFF_NO_ERROR) {
995 ret = iff_parse_bitmap(&ifile,bm,bm->bm_type,palette,NULL);
998 if (ifile.data) d_free(ifile.data);
1000 close_fake_file(&ifile);
1007 #define BMHD_SIZE 20
1009 int write_bmhd(FILE *ofile,iff_bitmap_header *bitmap_header)
1011 put_sig(bmhd_sig,ofile);
1012 put_long((long) BMHD_SIZE,ofile);
1014 put_word(bitmap_header->w,ofile);
1015 put_word(bitmap_header->h,ofile);
1016 put_word(bitmap_header->x,ofile);
1017 put_word(bitmap_header->y,ofile);
1019 put_byte(bitmap_header->nplanes,ofile);
1020 put_byte(bitmap_header->masking,ofile);
1021 put_byte(bitmap_header->compression,ofile);
1022 put_byte(0,ofile); /* pad */
1024 put_word(bitmap_header->transparentcolor,ofile);
1025 put_byte(bitmap_header->xaspect,ofile);
1026 put_byte(bitmap_header->yaspect,ofile);
1028 put_word(bitmap_header->pagewidth,ofile);
1029 put_word(bitmap_header->pageheight,ofile);
1031 return IFF_NO_ERROR;
1035 int write_pal(FILE *ofile,iff_bitmap_header *bitmap_header)
1039 int n_colors = 1<<bitmap_header->nplanes;
1041 put_sig(cmap_sig,ofile);
1042 // put_long(sizeof(pal_entry) * n_colors,ofile);
1043 put_long(3 * n_colors,ofile);
1045 //printf("new write pal %d %d\n",3,n_colors);
1047 for (i=0; i<256; i++) {
1048 unsigned char r,g,b;
1049 r = bitmap_header->palette[i].r * 4 + (bitmap_header->palette[i].r?3:0);
1050 g = bitmap_header->palette[i].g * 4 + (bitmap_header->palette[i].g?3:0);
1051 b = bitmap_header->palette[i].b * 4 + (bitmap_header->palette[i].b?3:0);
1057 //printf("write pal %d %d\n",sizeof(pal_entry),n_colors);
1058 // fwrite(bitmap_header->palette,sizeof(pal_entry),n_colors,ofile);
1060 return IFF_NO_ERROR;
1063 int rle_span(ubyte *dest,ubyte *src,int len)
1065 int n,lit_cnt,rep_cnt;
1066 ubyte last,*cnt_ptr,*dptr;
1072 last=src[0]; lit_cnt=1;
1074 for (n=1;n<len;n++) {
1076 if (src[n] == last) {
1081 while (n<len && rep_cnt<128 && src[n]==last) {n++; rep_cnt++;}
1083 if (rep_cnt > 2 || lit_cnt < 2) {
1085 if (lit_cnt > 1) {*cnt_ptr = lit_cnt-2; --dptr;} //save old lit count
1086 *dptr++ = -(rep_cnt-1);
1089 lit_cnt = (n<len)?1:0;
1091 continue; //go to next char
1099 cnt_ptr = dptr++; //save place for count
1100 *dptr++=last; //store first char
1103 *dptr++ = last = src[n];
1105 if (lit_cnt == 127) {
1119 *dptr++=last; //store first char
1121 else if (lit_cnt > 1)
1122 *cnt_ptr = lit_cnt-1;
1127 #define EVEN(a) ((a+1)&0xfffffffel)
1129 //returns length of chunk
1130 int write_body(FILE *ofile,iff_bitmap_header *bitmap_header,int compression_on)
1132 int w=bitmap_header->w,h=bitmap_header->h;
1134 long len = EVEN(w) * h,newlen,total_len=0;
1135 ubyte *p=bitmap_header->raw_data,*new_span;
1138 put_sig(body_sig,ofile);
1139 save_pos = ftell(ofile);
1140 put_long(len,ofile);
1142 //if (! (new_span = d_malloc(bitmap_header->w+(bitmap_header->w/128+2)*2))) return IFF_NO_MEM;
1143 MALLOC( new_span, ubyte, bitmap_header->w + (bitmap_header->w/128+2)*2);
1144 if (new_span == NULL) return IFF_NO_MEM;
1146 for (y=bitmap_header->h;y--;) {
1148 if (compression_on) {
1149 total_len += newlen = rle_span(new_span,p,bitmap_header->w+odd);
1150 fwrite(new_span,newlen,1,ofile);
1153 fwrite(p,bitmap_header->w+odd,1,ofile);
1155 p+=bitmap_header->row_size; //bitmap_header->w;
1158 if (compression_on) { //write actual data length
1159 Assert(fseek(ofile,save_pos,SEEK_SET)==0);
1160 put_long(total_len,ofile);
1161 Assert(fseek(ofile,total_len,SEEK_CUR)==0);
1162 if (total_len&1) fputc(0,ofile); //pad to even
1167 return ((compression_on) ? (EVEN(total_len)+8) : (len+8));
1172 //write a small representation of a bitmap. returns size
1173 int write_tiny(CFILE *ofile,iff_bitmap_header *bitmap_header,int compression_on)
1177 int len,total_len=0,newlen;
1179 ubyte *p = bitmap_header->raw_data;
1180 ubyte tspan[80],new_span[80*2];
1183 skip = max((bitmap_header->w+79)/80,(bitmap_header->h+63)/64);
1185 new_w = bitmap_header->w / skip;
1186 new_h = bitmap_header->h / skip;
1190 len = new_w * new_h + 4;
1192 put_sig(tiny_sig,ofile);
1193 save_pos = cftell(ofile);
1194 put_long(EVEN(len),ofile);
1196 put_word(new_w,ofile);
1197 put_word(new_h,ofile);
1199 for (y=0;y<new_h;y++) {
1200 for (x=xofs=0;x<new_w;x++,xofs+=skip)
1203 if (compression_on) {
1204 total_len += newlen = rle_span(new_span,tspan,new_w+odd);
1205 fwrite(new_span,newlen,1,ofile);
1208 fwrite(p,new_w+odd,1,ofile);
1210 p += skip * bitmap_header->row_size; //bitmap_header->w;
1214 if (compression_on) {
1215 Assert(cfseek(ofile,save_pos,SEEK_SET)==0);
1216 put_long(4+total_len,ofile);
1217 Assert(cfseek(ofile,4+total_len,SEEK_CUR)==0);
1218 if (total_len&1) cfputc(0,ofile); //pad to even
1221 return ((compression_on) ? (EVEN(total_len)+8+4) : (len+8));
1225 int write_pbm(FILE *ofile,iff_bitmap_header *bitmap_header,int compression_on) /* writes a pbm iff file */
1228 long raw_size = EVEN(bitmap_header->w) * bitmap_header->h;
1229 long body_size,tiny_size,pbm_size = 4 + BMHD_SIZE + 8 + EVEN(raw_size) + sizeof(pal_entry)*(1<<bitmap_header->nplanes)+8;
1232 //printf("write_pbm\n");
1234 put_sig(form_sig,ofile);
1235 save_pos = ftell(ofile);
1236 put_long(pbm_size+8,ofile);
1237 put_sig(pbm_sig,ofile);
1239 ret = write_bmhd(ofile,bitmap_header);
1240 if (ret != IFF_NO_ERROR) return ret;
1242 ret = write_pal(ofile,bitmap_header);
1243 if (ret != IFF_NO_ERROR) return ret;
1246 tiny_size = write_tiny(ofile,bitmap_header,compression_on);
1251 body_size = write_body(ofile,bitmap_header,compression_on);
1253 pbm_size = 4 + BMHD_SIZE + body_size + tiny_size + sizeof(pal_entry)*(1<<bitmap_header->nplanes)+8;
1255 Assert(fseek(ofile,save_pos,SEEK_SET)==0);
1256 put_long(pbm_size+8,ofile);
1257 Assert(fseek(ofile,pbm_size+8,SEEK_CUR)==0);
1263 //writes an IFF file from a grs_bitmap structure. writes palette if not null
1264 //returns error codes - see IFF.H.
1265 int iff_write_bitmap(char *ofilename,grs_bitmap *bm,ubyte *palette)
1268 iff_bitmap_header bmheader;
1272 if (bm->bm_type == BM_RGB15) return IFF_BAD_BM_TYPE;
1275 compression_on = (bm->bm_w>=MIN_COMPRESS_WIDTH);
1280 //fill in values in bmheader
1282 bmheader.x = bmheader.y = 0;
1283 bmheader.w = bm->bm_w;
1284 bmheader.h = bm->bm_h;
1285 bmheader.type = TYPE_PBM;
1286 bmheader.transparentcolor = iff_transparent_color;
1287 bmheader.pagewidth = bm->bm_w; //I don't think it matters what I write
1288 bmheader.pageheight = bm->bm_h;
1289 bmheader.nplanes = 8;
1290 bmheader.masking = mskNone;
1291 if (iff_has_transparency) {
1292 bmheader.masking |= mskHasTransparentColor;
1294 bmheader.compression = (compression_on?cmpByteRun1:cmpNone);
1296 bmheader.xaspect = bmheader.yaspect = 1; //I don't think it matters what I write
1297 bmheader.raw_data = bm->bm_data;
1298 bmheader.row_size = bm->bm_rowsize;
1300 if (palette) memcpy(&bmheader.palette,palette,256*3);
1302 //open file and write
1304 if ((ofile = fopen(ofilename,"wb")) == NULL) {
1307 ret = write_pbm(ofile,&bmheader,compression_on);
1315 //read in many brushes. fills in array of pointers, and n_bitmaps.
1316 //returns iff error codes
1317 int iff_read_animbrush(char *ifilename,grs_bitmap **bm_list,int max_bitmaps,int *n_bitmaps,ubyte *palette)
1319 int ret; //return code
1321 iff_bitmap_header bmheader;
1327 ret = open_fake_file(ifilename,&ifile); //read in entire file
1328 if (ret != IFF_NO_ERROR) goto done;
1330 bmheader.raw_data = NULL;
1332 sig=get_sig(&ifile);
1333 form_len = get_long(&ifile);
1335 if (sig != form_sig) {
1340 form_type = get_sig(&ifile);
1342 if ((form_type == pbm_sig) || (form_type == ilbm_sig))
1343 ret = IFF_FORM_BITMAP;
1344 else if (form_type == anim_sig) {
1345 int anim_end = ifile.position + form_len - 4;
1347 while (ifile.position < anim_end && *n_bitmaps < max_bitmaps) {
1349 grs_bitmap *prev_bm;
1351 prev_bm = *n_bitmaps>0?bm_list[*n_bitmaps-1]:NULL;
1353 MALLOC(bm_list[*n_bitmaps] , grs_bitmap, 1 );
1354 bm_list[*n_bitmaps]->bm_data = NULL;
1356 ret = iff_parse_bitmap(&ifile,bm_list[*n_bitmaps],form_type,*n_bitmaps>0?NULL:palette,prev_bm);
1358 if (ret != IFF_NO_ERROR)
1364 if (ifile.position < anim_end) //ran out of room
1365 ret = IFF_TOO_MANY_BMS;
1369 ret = IFF_UNKNOWN_FORM;
1373 close_fake_file(&ifile);
1379 //text for error messges
1380 char error_messages[] = {
1382 "Not enough mem for loading or processing bitmap.\0"
1383 "IFF file has unknown FORM type.\0"
1384 "Not an IFF file.\0"
1385 "Cannot open file.\0"
1386 "Tried to save invalid type, like BM_RGB15.\0"
1387 "Bad data in file.\0"
1388 "ANIM file cannot be loaded with normal bitmap loader.\0"
1389 "Normal bitmap file cannot be loaded with anim loader.\0"
1390 "Array not big enough on anim brush read.\0"
1391 "Unknown mask type in bitmap header.\0"
1392 "Error reading file.\0"
1396 //function to return pointer to error message
1397 char *iff_errormsg(int error_number)
1399 char *p = error_messages;
1401 while (error_number--) {
1403 if (!p) return NULL;