2 THE COMPUTER CODE CONTAINED HEREIN IS THE SOLE PROPERTY OF PARALLAX
3 SOFTWARE CORPORATION ("PARALLAX"). PARALLAX, IN DISTRIBUTING THE CODE TO
4 END-USERS, AND SUBJECT TO ALL OF THE TERMS AND CONDITIONS HEREIN, GRANTS A
5 ROYALTY-FREE, PERPETUAL LICENSE TO SUCH END-USERS FOR USE BY SUCH END-USERS
6 IN USING, DISPLAYING, AND CREATING DERIVATIVE WORKS THEREOF, SO LONG AS
7 SUCH USE, DISPLAY OR CREATION IS FOR NON-COMMERCIAL, ROYALTY OR REVENUE
8 FREE PURPOSES. IN NO EVENT SHALL THE END-USER USE THE COMPUTER CODE
9 CONTAINED HEREIN FOR REVENUE-BEARING PURPOSES. THE END-USER UNDERSTANDS
10 AND AGREES TO THE TERMS HEREIN AND ACCEPTS THE SAME BY USE OF THIS FILE.
11 COPYRIGHT 1993-1999 PARALLAX SOFTWARE CORPORATION. ALL RIGHTS RESERVED.
16 * Routines for reading and writing IFF files
24 #define COMPRESS 1 //do the RLE or not? (for debugging mostly)
25 #define WRITE_TINY 0 //should we write a TINY chunk?
27 #define MIN_COMPRESS_WIDTH 65 //don't compress if less than this wide
36 //#include "nocfile.h"
42 //Internal constants and structures for this library
44 //Type values for bitmaps
55 #define mskHasTransparentColor 2
57 //Palette entry structure
58 typedef struct pal_entry {
62 //structure of the header in the file
63 typedef struct iff_bitmap_header {
64 int16_t w, h; // width and height of this bitmap
65 int16_t x, y; // generally unused
66 int16_t type; // see types above
67 int16_t transparentcolor; // which color is transparent (if any)
68 int16_t pagewidth, pageheight; // width & height of source screen
69 sbyte nplanes; //number of planes (8 for 256 color image)
70 sbyte masking,compression; //see constants above
71 sbyte xaspect,yaspect; //aspect ratio (usually 5/6)
72 pal_entry palette[256]; //the palette for this bitmap
73 ubyte *raw_data; // ptr to array of data
74 int16_t row_size; // offset to next row
77 ubyte iff_transparent_color;
78 ubyte iff_has_transparency; // 0=no transparency, 1=iff_transparent_color is valid
80 #define form_sig MAKE_SIG('F','O','R','M')
81 #define ilbm_sig MAKE_SIG('I','L','B','M')
82 #define body_sig MAKE_SIG('B','O','D','Y')
83 #define pbm_sig MAKE_SIG('P','B','M',' ')
84 #define bmhd_sig MAKE_SIG('B','M','H','D')
85 #define anhd_sig MAKE_SIG('A','N','H','D')
86 #define cmap_sig MAKE_SIG('C','M','A','P')
87 #define tiny_sig MAKE_SIG('T','I','N','Y')
88 #define anim_sig MAKE_SIG('A','N','I','M')
89 #define dlta_sig MAKE_SIG('D','L','T','A')
92 //void printsig(int32_t s)
94 // char *t=(char *) &s;
96 ///* printf("%c%c%c%c",*(&s+3),*(&s+2),*(&s+1),s);*/
97 // printf("%c%c%c%c",t[3],t[2],t[1],t[0]);
101 int32_t get_sig(PHYSFS_file *f)
105 PHYSFS_readSBE32(f, &s);
109 #define put_sig(sig, f) PHYSFS_writeSBE32(f, sig)
111 int parse_bmhd(PHYSFS_file *ifile, int32_t len, iff_bitmap_header *bmheader)
113 len++; /* so no "parm not used" warning */
115 // debug("parsing bmhd len=%ld\n",len);
117 PHYSFS_readSBE16(ifile, &bmheader->w);
118 PHYSFS_readSBE16(ifile, &bmheader->h);
119 PHYSFS_readSBE16(ifile, &bmheader->x);
120 PHYSFS_readSBE16(ifile, &bmheader->y);
122 bmheader->nplanes = cfile_read_byte(ifile);
123 bmheader->masking = cfile_read_byte(ifile);
124 bmheader->compression = cfile_read_byte(ifile);
125 cfile_read_byte(ifile); /* skip pad */
127 PHYSFS_readSBE16(ifile, &bmheader->transparentcolor);
128 bmheader->xaspect = cfile_read_byte(ifile);
129 bmheader->yaspect = cfile_read_byte(ifile);
131 PHYSFS_readSBE16(ifile, &bmheader->pagewidth);
132 PHYSFS_readSBE16(ifile, &bmheader->pageheight);
134 iff_transparent_color = bmheader->transparentcolor;
136 iff_has_transparency = 0;
138 if (bmheader->masking == mskHasTransparentColor)
139 iff_has_transparency = 1;
141 else if (bmheader->masking != mskNone && bmheader->masking != mskHasMask)
142 return IFF_UNKNOWN_MASK;
144 // debug("w,h=%d,%d x,y=%d,%d\n",w,h,x,y);
145 // debug("nplanes=%d, masking=%d ,compression=%d, transcolor=%d\n",nplanes,masking,compression,transparentcolor);
151 // the buffer pointed to by raw_data is stuffed with a pointer to decompressed pixel data
152 int parse_body(PHYSFS_file *ifile, int32_t len, iff_bitmap_header *bmheader)
154 unsigned char *p=bmheader->raw_data;
157 int nn,wid_cnt,end_cnt,plane;
158 unsigned char *data_end;
167 end_pos = (int)PHYSFS_tell(ifile) + len;
171 if (bmheader->type == TYPE_PBM) {
174 } else if (bmheader->type == TYPE_ILBM) {
175 width = (bmheader->w+7)/8;
176 depth=bmheader->nplanes;
179 end_cnt = (width&1)?-1:0;
181 data_end = p + width*bmheader->h*depth;
183 if (bmheader->compression == cmpNone) { /* no compression */
186 for (y=bmheader->h;y;y--) {
187 cfread(p, bmheader->w, 1, ifile);
190 if (bmheader->masking == mskHasMask)
191 cfseek(ifile, width, SEEK_CUR); //skip mask!
193 if (bmheader->w & 1) cfgetc(ifile);
196 //cnt = len - bmheader->h * ((bmheader->w+1)&~1);
199 else if (bmheader->compression == cmpByteRun1)
200 for (wid_cnt=width,plane=0; PHYSFS_tell(ifile) < end_pos && p<data_end;) {
203 // if (old_cnt-cnt > 2048) {
208 if (wid_cnt == end_cnt) {
211 if ((bmheader->masking == mskHasMask && plane==depth+1) ||
212 (bmheader->masking != mskHasMask && plane==depth))
216 Assert(wid_cnt > end_cnt);
220 if (n >= 0) { // copy next n+1 bytes from source, they are not compressed
223 if (wid_cnt==-1) {--nn; Assert(width&1);}
224 if (plane==depth) //masking row
225 cfseek(ifile, nn, SEEK_CUR);
227 cfread(p += nn, nn, 1, ifile);
228 if (wid_cnt==-1) cfseek(ifile, 1, SEEK_CUR);
230 else if (n>=-127) { // next -n + 1 bytes are following byte
234 if (wid_cnt==-1) {--nn; Assert(width&1);}
235 if (plane!=depth) //not masking row
236 {memset(p,c,nn); p+=nn;}
240 if ((p-bmheader->raw_data) % width == 0)
243 Assert((p-bmheader->raw_data) - (width*row_count) < width);
248 if (p!=data_end) //if we don't have the whole bitmap...
249 return IFF_CORRUPT; //...the give an error
251 //Pretend we read the whole chuck, because if we didn't, it's because
252 //we didn't read the last mask like or the last rle record for padding
253 //or whatever and it's not important, because we check to make sure
254 //we got the while bitmap, and that's what really counts.
259 //modify passed bitmap
260 int parse_delta(PHYSFS_file *ifile, int32_t len, iff_bitmap_header *bmheader)
262 unsigned char *p=bmheader->raw_data;
264 int32_t chunk_end = (int)PHYSFS_tell(ifile) + len;
266 cfseek(ifile, 4, SEEK_CUR); //longword, seems to be equal to 4. Don't know what it is
268 for (y=0;y<bmheader->h;y++) {
270 int cnt = bmheader->w;
273 n_items = cfile_read_byte(ifile);
277 code = cfile_read_byte(ifile);
279 if (code==0) { //repeat
282 rep = cfile_read_byte(ifile);
283 val = cfile_read_byte(ifile);
291 else if (code > 0x80) { //skip
303 *p++ = cfile_read_byte(ifile);
306 cfile_read_byte(ifile);
312 if (!(bmheader->w & 1)) // width is odd?
319 if (PHYSFS_tell(ifile) == chunk_end-1) //pad
320 cfseek(ifile, 1, SEEK_CUR);
322 if (PHYSFS_tell(ifile) != chunk_end)
328 // the buffer pointed to by raw_data is stuffed with a pointer to bitplane pixel data
329 void skip_chunk(PHYSFS_file *ifile, int32_t len)
335 //printf( "Skipping %d chunk\n", ilen );
337 // for (i=0; i<ilen; i++ )
338 // c = cfgetc(ifile);
339 cfseek(ifile,ilen,SEEK_CUR);
342 //read an ILBM or PBM file
343 // Pass pointer to opened file, and to empty bitmap_header structure, and form length
344 int iff_parse_ilbm_pbm(PHYSFS_file *ifile, int32_t form_type, iff_bitmap_header *bmheader, int form_len, grs_bitmap *prev_bm)
348 int32_t start_pos, end_pos;
350 start_pos = (int)PHYSFS_tell(ifile);
351 end_pos = start_pos-4+form_len;
353 // printf(" %ld ",form_len);
354 // printsig(form_type);
357 if (form_type == pbm_sig)
358 bmheader->type = TYPE_PBM;
360 bmheader->type = TYPE_ILBM;
362 while ((PHYSFS_tell(ifile) < end_pos) && (sig=get_sig(ifile)) != EOF) {
364 if (PHYSFS_readSBE32(ifile, &len)==EOF) break;
368 // printf(" %ld\n",len);
374 int save_w=bmheader->w,save_h=bmheader->h;
376 //printf("Parsing header\n");
378 ret = parse_bmhd(ifile,len,bmheader);
380 if (ret != IFF_NO_ERROR)
383 if (bmheader->raw_data) {
385 if (save_w != bmheader->w || save_h != bmheader->h)
386 return IFF_BM_MISMATCH;
391 MALLOC( bmheader->raw_data, ubyte, bmheader->w * bmheader->h );
392 if (!bmheader->raw_data)
402 if (!prev_bm) return IFF_CORRUPT;
404 bmheader->w = prev_bm->bm_w;
405 bmheader->h = prev_bm->bm_h;
406 bmheader->type = prev_bm->bm_type;
408 MALLOC( bmheader->raw_data, ubyte, bmheader->w * bmheader->h );
410 memcpy(bmheader->raw_data, prev_bm->bm_data, bmheader->w * bmheader->h );
411 skip_chunk(ifile,len);
417 int ncolors=(int) (len/3),cnum;
420 //printf("Parsing RGB map\n");
421 for (cnum=0;cnum<ncolors;cnum++) {
425 // r = ifile->data[ifile->position++];
426 // g = ifile->data[ifile->position++];
427 // b = ifile->data[ifile->position++];
428 r >>= 2; bmheader->palette[cnum].r = r;
429 g >>= 2; bmheader->palette[cnum].g = g;
430 b >>= 2; bmheader->palette[cnum].b = b;
432 if (len & 1) cfgetc(ifile);
433 //if (len & 1 ) ifile->position++;
441 //printf("Parsing body\n");
442 if ((r=parse_body(ifile,len,bmheader))!=IFF_NO_ERROR)
449 if ((r=parse_delta(ifile,len,bmheader))!=IFF_NO_ERROR)
454 skip_chunk(ifile,len);
459 if (PHYSFS_tell(ifile) != start_pos-4+form_len)
462 return IFF_NO_ERROR; /* ok! */
465 //convert an ILBM file to a PBM file
466 int convert_ilbm_to_pbm(iff_bitmap_header *bmheader)
469 sbyte *new_data, *destptr, *rowptr;
470 int bytes_per_row,byteofs;
471 ubyte checkmask,newbyte,setbit;
473 MALLOC(new_data, sbyte, bmheader->w * bmheader->h);
474 if (new_data == NULL) return IFF_NO_MEM;
478 bytes_per_row = 2*((bmheader->w+15)/16);
480 for (y=0;y<bmheader->h;y++) {
482 rowptr = (signed char *) &bmheader->raw_data[y * bytes_per_row * bmheader->nplanes];
484 for (x=0,checkmask=0x80;x<bmheader->w;x++) {
488 for (p=newbyte=0,setbit=1;p<bmheader->nplanes;p++) {
490 if (rowptr[bytes_per_row * p + byteofs] & checkmask)
496 *destptr++ = newbyte;
498 if ((checkmask >>= 1) == 0) checkmask=0x80;
503 d_free(bmheader->raw_data);
504 bmheader->raw_data = (unsigned char *) new_data;
506 bmheader->type = TYPE_PBM;
511 #define INDEX_TO_15BPP(i) ((int16_t)((((palptr[(i)].r/2)&31)<<10)+(((palptr[(i)].g/2)&31)<<5)+((palptr[(i)].b/2 )&31)))
513 int convert_rgb15(grs_bitmap *bm,iff_bitmap_header *bmheader)
520 palptr = bmheader->palette;
522 // if ((new_data = d_malloc(bm->bm_w * bm->bm_h * 2)) == NULL)
523 // {ret=IFF_NO_MEM; goto done;}
524 MALLOC(new_data, uint16_t, bm->bm_w * bm->bm_h * 2);
525 if (new_data == NULL)
528 for (y=0; y<bm->bm_h; y++) {
530 for (x=0; x<bmheader->w; x++)
531 new_data[newptr++] = INDEX_TO_15BPP(bmheader->raw_data[y*bmheader->w+x]);
535 d_free(bm->bm_data); //get rid of old-style data
536 bm->bm_data = (ubyte *) new_data; //..and point to new data
538 bm->bm_rowsize *= 2; //two bytes per row
544 //copy an iff header structure to a grs_bitmap structure
545 void copy_iff_to_grs(grs_bitmap *bm,iff_bitmap_header *bmheader)
547 bm->bm_x = bm->bm_y = 0;
548 bm->bm_w = bmheader->w;
549 bm->bm_h = bmheader->h;
550 bm->bm_type = bmheader->type;
551 bm->bm_rowsize = bmheader->w;
552 bm->bm_data = bmheader->raw_data;
554 bm->bm_flags = bm->bm_handle = 0;
558 //if bm->bm_data is set, use it (making sure w & h are correct), else
559 //allocate the memory
560 int iff_parse_bitmap(PHYSFS_file *ifile, grs_bitmap *bm, int bitmap_type, sbyte *palette, grs_bitmap *prev_bm)
562 int ret; //return code
563 iff_bitmap_header bmheader;
564 int32_t sig,form_len;
567 bmheader.raw_data = bm->bm_data;
569 if (bmheader.raw_data) {
570 bmheader.w = bm->bm_w;
571 bmheader.h = bm->bm_h;
576 if (sig != form_sig) {
580 PHYSFS_readSBE32(ifile, &form_len);
582 form_type = get_sig(ifile);
584 if (form_type == anim_sig)
586 else if ((form_type == pbm_sig) || (form_type == ilbm_sig))
587 ret = iff_parse_ilbm_pbm(ifile,form_type,&bmheader,form_len,prev_bm);
589 ret = IFF_UNKNOWN_FORM;
591 if (ret != IFF_NO_ERROR) { //got an error parsing
592 if (bmheader.raw_data) d_free(bmheader.raw_data);
596 //If IFF file is ILBM, convert to PPB
597 if (bmheader.type == TYPE_ILBM) {
599 ret = convert_ilbm_to_pbm(&bmheader);
601 if (ret != IFF_NO_ERROR)
605 //Copy data from iff_bitmap_header structure into grs_bitmap structure
607 copy_iff_to_grs(bm,&bmheader);
610 if (palette) memcpy(palette,&bmheader.palette,sizeof(bmheader.palette));
612 // if (palette) memcpy(palette,&bmheader.palette, 768); // pal_entry is 4 bytes on mac
618 for (i = 0; i < 256; i++) {
619 *c++ = bmheader.palette[i].r;
620 *c++ = bmheader.palette[i].g;
621 *c++ = bmheader.palette[i].b;
626 //Now do post-process if required
628 if (bitmap_type == BM_RGB15) {
629 ret = convert_rgb15(bm,&bmheader);
630 if (ret != IFF_NO_ERROR)
638 //returns error codes - see IFF.H. see GR.H for bitmap_type
639 int iff_read_bitmap(char *ifilename,grs_bitmap *bm,int bitmap_type,ubyte *palette)
641 int ret; //return code
644 ifile = cfopen(ifilename, "rb");
649 ret = iff_parse_bitmap(ifile,bm,bitmap_type,(signed char *) palette,NULL);
658 //like iff_read_bitmap(), but reads into a bitmap that already exists,
659 //without allocating memory for the bitmap.
660 int iff_read_into_bitmap(char *ifilename, grs_bitmap *bm, sbyte *palette)
662 int ret; //return code
665 ifile = cfopen(ifilename, "rb");
669 ret = iff_parse_bitmap(ifile,bm,bm->bm_type,palette,NULL);
680 int write_bmhd(PHYSFS_file *ofile,iff_bitmap_header *bitmap_header)
682 put_sig(bmhd_sig,ofile);
683 PHYSFS_writeSBE32(ofile, (int32_t)BMHD_SIZE);
685 PHYSFS_writeSBE16(ofile, bitmap_header->w);
686 PHYSFS_writeSBE16(ofile, bitmap_header->h);
687 PHYSFS_writeSBE16(ofile, bitmap_header->x);
688 PHYSFS_writeSBE16(ofile, bitmap_header->y);
690 PHYSFSX_writeU8(ofile, bitmap_header->nplanes);
691 PHYSFSX_writeU8(ofile, bitmap_header->masking);
692 PHYSFSX_writeU8(ofile, bitmap_header->compression);
693 PHYSFSX_writeU8(ofile, 0); /* pad */
695 PHYSFS_writeSBE16(ofile, bitmap_header->transparentcolor);
696 PHYSFSX_writeU8(ofile, bitmap_header->xaspect);
697 PHYSFSX_writeU8(ofile, bitmap_header->yaspect);
699 PHYSFS_writeSBE16(ofile, bitmap_header->pagewidth);
700 PHYSFS_writeSBE16(ofile, bitmap_header->pageheight);
706 int write_pal(PHYSFS_file *ofile,iff_bitmap_header *bitmap_header)
710 int n_colors = 1<<bitmap_header->nplanes;
712 put_sig(cmap_sig,ofile);
713 // PHYSFS_writeSBE32(sizeof(pal_entry) * n_colors,ofile);
714 PHYSFS_writeSBE32(ofile, 3 * n_colors);
716 //printf("new write pal %d %d\n",3,n_colors);
718 for (i=0; i<256; i++) {
720 r = bitmap_header->palette[i].r * 4 + (bitmap_header->palette[i].r?3:0);
721 g = bitmap_header->palette[i].g * 4 + (bitmap_header->palette[i].g?3:0);
722 b = bitmap_header->palette[i].b * 4 + (bitmap_header->palette[i].b?3:0);
723 PHYSFSX_writeU8(ofile, r);
724 PHYSFSX_writeU8(ofile, g);
725 PHYSFSX_writeU8(ofile, b);
728 //printf("write pal %d %d\n",sizeof(pal_entry),n_colors);
729 // fwrite(bitmap_header->palette,sizeof(pal_entry),n_colors,ofile);
734 int rle_span(ubyte *dest,ubyte *src,int len)
736 int n,lit_cnt,rep_cnt;
737 ubyte last,*cnt_ptr,*dptr;
743 last=src[0]; lit_cnt=1;
745 for (n=1;n<len;n++) {
747 if (src[n] == last) {
752 while (n<len && rep_cnt<128 && src[n]==last) {n++; rep_cnt++;}
754 if (rep_cnt > 2 || lit_cnt < 2) {
756 if (lit_cnt > 1) {*cnt_ptr = lit_cnt-2; --dptr;} //save old lit count
757 *dptr++ = -(rep_cnt-1);
760 lit_cnt = (n<len)?1:0;
762 continue; //go to next char
770 cnt_ptr = dptr++; //save place for count
771 *dptr++=last; //store first char
774 *dptr++ = last = src[n];
776 if (lit_cnt == 127) {
790 *dptr++=last; //store first char
792 else if (lit_cnt > 1)
793 *cnt_ptr = lit_cnt-1;
795 return (int)(dptr - dest);
798 #define EVEN(a) ((a+1)&0xfffffffel)
800 //returns length of chunk
801 int write_body(PHYSFS_file *ofile,iff_bitmap_header *bitmap_header,int compression_on)
803 int w=bitmap_header->w,h=bitmap_header->h;
805 int32_t len = EVEN(w) * h, newlen, total_len = 0;
806 ubyte *p=bitmap_header->raw_data,*new_span;
809 put_sig(body_sig,ofile);
810 save_pos = (int32_t)PHYSFS_tell(ofile);
811 PHYSFS_writeSBE32(ofile, len);
813 //if (! (new_span = d_malloc(bitmap_header->w+(bitmap_header->w/128+2)*2))) return IFF_NO_MEM;
814 MALLOC( new_span, ubyte, bitmap_header->w + (bitmap_header->w/128+2)*2);
815 if (new_span == NULL) return IFF_NO_MEM;
817 for (y=bitmap_header->h;y--;) {
819 if (compression_on) {
820 total_len += newlen = rle_span(new_span,p,bitmap_header->w+odd);
821 PHYSFS_write(ofile,new_span,newlen,1);
824 PHYSFS_write(ofile,p,bitmap_header->w+odd,1);
826 p+=bitmap_header->row_size; //bitmap_header->w;
829 if (compression_on) { //write actual data length
830 Assert(cfseek(ofile,save_pos,SEEK_SET)==0);
831 PHYSFS_writeSBE32(ofile, total_len);
832 Assert(cfseek(ofile,total_len,SEEK_CUR)==0);
833 if (total_len&1) PHYSFSX_writeU8(ofile, 0); //pad to even
838 return ((compression_on) ? (EVEN(total_len)+8) : (len+8));
843 //write a small representation of a bitmap. returns size
844 int write_tiny(PHYSFS_file *ofile,iff_bitmap_header *bitmap_header,int compression_on)
848 int len,total_len=0,newlen;
850 ubyte *p = bitmap_header->raw_data;
851 ubyte tspan[80],new_span[80*2];
854 skip = max((bitmap_header->w+79)/80,(bitmap_header->h+63)/64);
856 new_w = bitmap_header->w / skip;
857 new_h = bitmap_header->h / skip;
861 len = new_w * new_h + 4;
863 put_sig(tiny_sig,ofile);
864 save_pos = PHYSFS_tell(ofile);
865 PHYSFS_writeSBE32(ofile, EVEN(len));
867 PHYSFS_writeSBE16(ofile, new_w);
868 PHYSFS_writeSBE16(ofile, new_h);
870 for (y=0;y<new_h;y++) {
871 for (x=xofs=0;x<new_w;x++,xofs+=skip)
874 if (compression_on) {
875 total_len += newlen = rle_span(new_span,tspan,new_w+odd);
876 PHYSFS_write(ofile,new_span,newlen,1);
879 PHYSFS_write(ofile,p,new_w+odd,1);
881 p += skip * bitmap_header->row_size; //bitmap_header->w;
885 if (compression_on) {
886 Assert(cfseek(ofile,save_pos,SEEK_SET)==0);
887 PHYSFS_writeSBE32(ofile, 4+total_len);
888 Assert(cfseek(ofile,4+total_len,SEEK_CUR)==0);
889 if (total_len&1) PHYSFSX_writeU8(ofile, 0); //pad to even
892 return ((compression_on) ? (EVEN(total_len)+8+4) : (len+8));
896 int write_pbm(PHYSFS_file *ofile,iff_bitmap_header *bitmap_header,int compression_on) /* writes a pbm iff file */
899 int32_t raw_size = EVEN(bitmap_header->w) * bitmap_header->h;
900 int32_t body_size, tiny_size;
901 int32_t pbm_size = 4 + BMHD_SIZE + 8 + EVEN(raw_size) + sizeof(pal_entry) * (1<<bitmap_header->nplanes) + 8;
904 //printf("write_pbm\n");
906 put_sig(form_sig,ofile);
907 save_pos = (int32_t)PHYSFS_tell(ofile);
908 PHYSFS_writeSBE32(ofile, pbm_size+8);
909 put_sig(pbm_sig,ofile);
911 ret = write_bmhd(ofile,bitmap_header);
912 if (ret != IFF_NO_ERROR) return ret;
914 ret = write_pal(ofile,bitmap_header);
915 if (ret != IFF_NO_ERROR) return ret;
918 tiny_size = write_tiny(ofile,bitmap_header,compression_on);
923 body_size = write_body(ofile,bitmap_header,compression_on);
925 pbm_size = 4 + BMHD_SIZE + body_size + tiny_size + sizeof(pal_entry)*(1<<bitmap_header->nplanes)+8;
927 Assert(cfseek(ofile,save_pos,SEEK_SET)==0);
928 PHYSFS_writeSBE32(ofile, pbm_size+8);
929 Assert(cfseek(ofile,pbm_size+8,SEEK_CUR)==0);
935 //writes an IFF file from a grs_bitmap structure. writes palette if not null
936 //returns error codes - see IFF.H.
937 int iff_write_bitmap(char *ofilename,grs_bitmap *bm,ubyte *palette)
940 iff_bitmap_header bmheader;
944 if (bm->bm_type == BM_RGB15) return IFF_BAD_BM_TYPE;
947 compression_on = (bm->bm_w>=MIN_COMPRESS_WIDTH);
952 //fill in values in bmheader
954 bmheader.x = bmheader.y = 0;
955 bmheader.w = bm->bm_w;
956 bmheader.h = bm->bm_h;
957 bmheader.type = TYPE_PBM;
958 bmheader.transparentcolor = iff_transparent_color;
959 bmheader.pagewidth = bm->bm_w; //I don't think it matters what I write
960 bmheader.pageheight = bm->bm_h;
961 bmheader.nplanes = 8;
962 bmheader.masking = mskNone;
963 if (iff_has_transparency) {
964 bmheader.masking |= mskHasTransparentColor;
966 bmheader.compression = (compression_on?cmpByteRun1:cmpNone);
968 bmheader.xaspect = bmheader.yaspect = 1; //I don't think it matters what I write
969 bmheader.raw_data = bm->bm_data;
970 bmheader.row_size = bm->bm_rowsize;
972 if (palette) memcpy(&bmheader.palette,palette,256*3);
974 //open file and write
976 if ((ofile = PHYSFS_openWrite(ofilename)) == NULL)
979 ret = write_pbm(ofile,&bmheader,compression_on);
986 //read in many brushes. fills in array of pointers, and n_bitmaps.
987 //returns iff error codes
988 int iff_read_animbrush(char *ifilename,grs_bitmap **bm_list,int max_bitmaps,int *n_bitmaps,ubyte *palette)
990 int ret = IFF_READ_ERROR; //return code
992 iff_bitmap_header bmheader;
993 int32_t sig, form_len;
998 ifile = cfopen(ifilename, "rb");
1002 bmheader.raw_data = NULL;
1005 PHYSFS_readSBE32(ifile, &form_len);
1007 if (sig != form_sig) {
1012 form_type = get_sig(ifile);
1014 if ((form_type == pbm_sig) || (form_type == ilbm_sig))
1015 ret = IFF_FORM_BITMAP;
1016 else if (form_type == anim_sig) {
1017 int anim_end = (int)PHYSFS_tell(ifile) + form_len - 4;
1019 while (PHYSFS_tell(ifile) < anim_end && *n_bitmaps < max_bitmaps) {
1021 grs_bitmap *prev_bm;
1023 prev_bm = *n_bitmaps>0?bm_list[*n_bitmaps-1]:NULL;
1025 MALLOC(bm_list[*n_bitmaps] , grs_bitmap, 1 );
1026 bm_list[*n_bitmaps]->bm_data = NULL;
1028 ret = iff_parse_bitmap(ifile,bm_list[*n_bitmaps],form_type,*n_bitmaps>0?NULL:(signed char *)palette,prev_bm);
1030 if (ret != IFF_NO_ERROR)
1036 if (PHYSFS_tell(ifile) < anim_end) //ran out of room
1037 ret = IFF_TOO_MANY_BMS;
1041 ret = IFF_UNKNOWN_FORM;
1045 PHYSFS_close(ifile);
1051 //text for error messges
1052 static const char error_messages[] = {
1054 "Not enough mem for loading or processing bitmap.\0"
1055 "IFF file has unknown FORM type.\0"
1056 "Not an IFF file.\0"
1057 "Cannot open file.\0"
1058 "Tried to save invalid type, like BM_RGB15.\0"
1059 "Bad data in file.\0"
1060 "ANIM file cannot be loaded with normal bitmap loader.\0"
1061 "Normal bitmap file cannot be loaded with anim loader.\0"
1062 "Array not big enough on anim brush read.\0"
1063 "Unknown mask type in bitmap header.\0"
1064 "Error reading file.\0"
1068 //function to return pointer to error message
1069 const char *iff_errormsg(int error_number)
1071 const char *p = error_messages;
1073 while (error_number--) {
1075 if (!p) return NULL;