home *** CD-ROM | disk | FTP | other *** search
/ Amiga ACS 1998 #6 / amigaacscoverdisc1998-061998.iso / games / descent / source / iff / iff.c next >
Text File  |  1998-06-08  |  35KB  |  1,389 lines

  1. /*
  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-1998 PARALLAX SOFTWARE CORPORATION.  ALL RIGHTS RESERVED.
  12. */
  13. /*
  14.  * $Source: f:/miner/source/iff/rcs/iff.c $
  15.  * $Revision: 1.43 $
  16.  * $Author: john $
  17.  * $Date: 1994/12/08 19:03:17 $
  18.  *
  19.  * Routines for reading and writing IFF files
  20.  *
  21.  * $Log: iff.c $
  22.  * Revision 1.43  1994/12/08  19:03:17  john
  23.  * Added code to use cfile.
  24.  * 
  25.  * Revision 1.42  1994/12/08  17:45:32  john
  26.  * Put back in cfile stuff.
  27.  * 
  28.  * Revision 1.41  1994/11/19  16:41:06  matt
  29.  * Took out unused code
  30.  * 
  31.  * Revision 1.40  1994/11/07  21:26:39  matt
  32.  * Added new function iff_read_into_bitmap()
  33.  * 
  34.  * Revision 1.39  1994/10/27  00:12:03  john
  35.  * Used nocfile
  36.  * 
  37.  * Revision 1.38  1994/08/10  19:49:58  matt
  38.  * Fixed bitmaps in ILBM format with masking (stencil) on.
  39.  * 
  40.  * Revision 1.37  1994/06/02  18:53:17  matt
  41.  * Clear flags & selector in new bitmap structure
  42.  * 
  43.  * Revision 1.36  1994/05/17  14:00:33  matt
  44.  * Fixed bug with odd-width deltas & odd-length body chunks
  45.  * 
  46.  * Revision 1.35  1994/05/16  20:38:55  matt
  47.  * Made anim brushes work when odd width
  48.  * 
  49.  * Revision 1.34  1994/05/06  19:37:26  matt
  50.  * Improved error handling and checking
  51.  * 
  52.  * Revision 1.33  1994/04/27  20:57:07  matt
  53.  * Fixed problem with RLE decompression and odd-width bitmap
  54.  * Added more error checking
  55.  * 
  56.  * Revision 1.32  1994/04/16  21:44:19  matt
  57.  * Fixed bug introduced last version
  58.  * 
  59.  * Revision 1.31  1994/04/16  20:12:40  matt
  60.  * Made masked (stenciled) bitmaps work
  61.  * 
  62.  * Revision 1.30  1994/04/13  23:46:16  matt
  63.  * Added function, iff_errormsg(), which returns ptr to error message.
  64.  * 
  65.  * Revision 1.29  1994/04/13  23:27:25  matt
  66.  * Put in support for anim brushes (.abm files)
  67.  * 
  68.  * Revision 1.28  1994/04/13  16:33:31  matt
  69.  * Cleaned up file read code, adding fake_file structure (FFILE), which
  70.  * cleanly implements reading the entire file into a buffer and then reading
  71.  * out of that buffer.
  72.  * 
  73.  * Revision 1.27  1994/04/06  23:07:43  matt
  74.  * Cleaned up code; added prototype (but no new code) for anim brush read
  75.  * 
  76.  * Revision 1.26  1994/03/19  02:51:52  matt
  77.  * Really did what I said I did last revision.
  78.  * 
  79.  * Revision 1.25  1994/03/19  02:16:07  matt
  80.  * Made work ILBMs which didn't have 8 planes
  81.  * 
  82.  * Revision 1.24  1994/03/15  14:45:26  matt
  83.  * When error, only free memory if has been allocated
  84.  * 
  85.  * Revision 1.23  1994/02/18  12:39:05  john
  86.  * Made code read from buffer.
  87.  * 
  88.  * Revision 1.22  1994/02/15  18:15:26  john
  89.  * Took out cfile attempt (too slow)
  90.  * 
  91.  * Revision 1.21  1994/02/15  13:17:48  john
  92.  * added assert to cfseek.
  93.  * 
  94.  * Revision 1.20  1994/02/15  13:13:11  john
  95.  * Made iff code work normally.
  96.  * 
  97.  * Revision 1.19  1994/02/15  12:51:07  john
  98.  * crappy inbetween version.
  99.  * 
  100.  * Revision 1.18  1994/02/10  18:31:32  matt
  101.  * Changed 'if DEBUG_ON' to 'ifndef NDEBUG'
  102.  * 
  103.  * Revision 1.17  1994/01/24  11:51:26  john
  104.  * Made write routine write transparency info.
  105.  * 
  106.  * Revision 1.16  1994/01/22  14:41:11  john
  107.  * Fixed bug with declareations.
  108.  * 
  109.  * Revision 1.15  1994/01/22  14:23:00  john
  110.  * Added global vars to check transparency
  111.  * 
  112.  * Revision 1.14  1993/12/08  19:00:42  matt
  113.  * Changed while loop to memset
  114.  * 
  115.  * Revision 1.13  1993/12/08  17:23:51  mike
  116.  * Speedup by converting while...getc to fread.
  117.  * 
  118.  * Revision 1.12  1993/12/08  12:37:35  mike
  119.  * Optimize parse_body.
  120.  * 
  121.  * Revision 1.11  1993/12/05  17:30:14  matt
  122.  * Made bitmaps with width <= 64 not compress
  123.  * 
  124.  * Revision 1.10  1993/12/03  12:24:51  matt
  125.  * Fixed TINY chunk when bitmap was part of a larger bitmap
  126.  * 
  127.  * Revision 1.9  1993/11/22  17:26:43  matt
  128.  * iff write now writes out a tiny chunk
  129.  * 
  130.  * Revision 1.8  1993/11/21  22:04:13  matt
  131.  * Fixed error with non-compressed bitmaps
  132.  * Added Yuan's code to free raw data if we get an error parsing the body
  133.  * 
  134.  * Revision 1.7  1993/11/11  12:12:12  yuan
  135.  * Changed mallocs to MALLOCs.
  136.  * 
  137.  * Revision 1.6  1993/11/01  19:02:23  matt
  138.  * Fixed a couple bugs in rle compression
  139.  * 
  140.  * Revision 1.5  1993/10/27  12:47:39  john
  141.  * *** empty log message ***
  142.  * 
  143.  * Revision 1.4  1993/10/27  12:37:31  yuan
  144.  * Added mem.h
  145.  * 
  146.  * Revision 1.3  1993/09/22  19:16:57  matt
  147.  * Added new error type, IFF_CORRUPT, for internally bad IFF files.
  148.  * 
  149.  * Revision 1.2  1993/09/08  19:24:16  matt
  150.  * Fixed bug in RLE compression
  151.  * Changed a bunch of unimportant values like aspect and page size when writing
  152.  * Added new error condition, IFF_BAD_BM_TYPE
  153.  * Make sub-bitmaps work correctly
  154.  * Added compile flag to turn compression off (COMPRESS)
  155.  * 
  156.  * Revision 1.1  1993/09/08  14:24:15  matt
  157.  * Initial revision
  158.  * 
  159.  *
  160.  */
  161.  
  162. #define COMPRESS        1    //do the RLE or not? (for debugging mostly)
  163. #define WRITE_TINY    0    //should we write a TINY chunk?
  164.  
  165. #define MIN_COMPRESS_WIDTH    65    //don't compress if less than this wide
  166.  
  167. #pragma off (unreferenced)
  168. static char rcsid[] = "$Id: iff.c 1.43 1994/12/08 19:03:17 john Exp $";
  169. #pragma on (unreferenced)
  170.  
  171. #include <stdio.h>
  172. #include <stdlib.h>
  173. #include <malloc.h>
  174. #include <conio.h>
  175. #include <string.h>
  176.  
  177. #include "mem.h"
  178. #include "iff.h"
  179.  
  180. //#include "nocfile.h"
  181. #include "cfile.h"
  182. #include "error.h"
  183.  
  184. //Internal constants and structures for this library
  185.  
  186. //Type values for bitmaps
  187. #define TYPE_PBM        0
  188. #define TYPE_ILBM        1
  189.  
  190. //Compression types
  191. #define cmpNone    0
  192. #define cmpByteRun1    1
  193.  
  194. //Masking types
  195. #define mskNone    0
  196. #define mskHasMask    1
  197. #define mskHasTransparentColor 2
  198.  
  199. //Palette entry structure
  200. typedef struct pal_entry {byte r,g,b;} pal_entry;
  201.  
  202. //structure of the header in the file
  203. typedef struct iff_bitmap_header {
  204.     short w,h;                        //width and height of this bitmap
  205.     short x,y;                        //generally unused
  206.     short type;                        //see types above
  207.     short transparentcolor;        //which color is transparent (if any)
  208.     short pagewidth,pageheight; //width & height of source screen
  209.     byte nplanes;                    //number of planes (8 for 256 color image)
  210.     byte masking,compression;    //see constants above
  211.     byte xaspect,yaspect;        //aspect ratio (usually 5/6)
  212.     pal_entry palette[256];        //the palette for this bitmap
  213.     ubyte *raw_data;                //ptr to array of data
  214.     short row_size;                //offset to next row
  215. } iff_bitmap_header;
  216.  
  217. ubyte iff_transparent_color;
  218. ubyte iff_has_transparency;    // 0=no transparency, 1=iff_transparent_color is valid
  219.  
  220. typedef struct fake_file {
  221.     ubyte *data;
  222.     int position;
  223.     int length;
  224. } FFILE;
  225.  
  226. #define MIN(a,b) ((a<b)?a:b)
  227.  
  228. #define MAKE_SIG(a,b,c,d) (((long)(a)<<24)+((long)(b)<<16)+((c)<<8)+(d))
  229.  
  230. #define form_sig MAKE_SIG('F','O','R','M')
  231. #define ilbm_sig MAKE_SIG('I','L','B','M')
  232. #define body_sig MAKE_SIG('B','O','D','Y')
  233. #define pbm_sig  MAKE_SIG('P','B','M',' ')
  234. #define bmhd_sig MAKE_SIG('B','M','H','D')
  235. #define anhd_sig MAKE_SIG('A','N','H','D')
  236. #define cmap_sig MAKE_SIG('C','M','A','P')
  237. #define tiny_sig MAKE_SIG('T','I','N','Y')
  238. #define anim_sig MAKE_SIG('A','N','I','M')
  239. #define dlta_sig MAKE_SIG('D','L','T','A')
  240.  
  241. #ifndef NDEBUG
  242. //void printsig(long s)
  243. //{
  244. //    char *t=(char *) &s;
  245. //
  246. ///*  printf("%c%c%c%c",*(&s+3),*(&s+2),*(&s+1),s);*/
  247. //    printf("%c%c%c%c",t[3],t[2],t[1],t[0]);
  248. //}
  249. #endif
  250.  
  251. long get_sig(FFILE *f)
  252. {
  253.     char s[4];
  254.  
  255. //    if ((s[3]=cfgetc(f))==EOF) return(EOF);
  256. //    if ((s[2]=cfgetc(f))==EOF) return(EOF);
  257. //    if ((s[1]=cfgetc(f))==EOF) return(EOF);
  258. //    if ((s[0]=cfgetc(f))==EOF) return(EOF);
  259.  
  260.     if (f->position>=f->length) return EOF;
  261.     s[3] = f->data[f->position++];
  262.     if (f->position>=f->length) return EOF;
  263.     s[2] = f->data[f->position++];
  264.     if (f->position>=f->length) return EOF;
  265.     s[1] = f->data[f->position++];
  266.     if (f->position>=f->length) return EOF;
  267.     s[0] = f->data[f->position++];
  268.  
  269.     return(*((long *) s));
  270. }
  271.  
  272. int put_sig(long sig,FILE *f)
  273. {
  274.     char *s = (char *) &sig;
  275.  
  276.     fputc(s[3],f);
  277.     fputc(s[2],f);
  278.     fputc(s[1],f);
  279.     return fputc(s[0],f);
  280.  
  281. }
  282.     
  283.  
  284. int get_word(FFILE *f)
  285. {
  286.     unsigned char c0,c1;
  287.  
  288. //    c1=cfgetc(f);
  289. //    c0=cfgetc(f);
  290.  
  291.     if (f->position>=f->length) return EOF;
  292.     c1 = f->data[f->position++];
  293.     if (f->position>=f->length) return EOF;
  294.     c0 = f->data[f->position++];
  295.  
  296.     if (c0==0xff) return(EOF);
  297.  
  298.     return(((int)c1<<8) + c0);
  299.  
  300. }
  301.  
  302. int put_word(int n,FILE *f)
  303. {
  304.     unsigned char c0,c1;
  305.  
  306.     c0 = (n & 0xff00) >> 8;
  307.     c1 = n & 0xff;
  308.  
  309.     put_byte(c0,f);
  310.     return put_byte(c1,f);
  311. }
  312.  
  313. int put_long(long n,FILE *f)
  314. {
  315.     int n0,n1;
  316.  
  317.     n0 = (int) ((n & 0xffff0000l) >> 16);
  318.     n1 = (int) (n & 0xffff);
  319.  
  320.     put_word(n0,f);
  321.     return put_word(n1,f);
  322.  
  323. }
  324.  
  325. char get_byte(FFILE *f)
  326. {
  327.     //return cfgetc(f);
  328.     return f->data[f->position++];
  329. }
  330.  
  331. int put_byte(unsigned char c,FILE *f)
  332. {
  333.     return fputc(c,f);
  334. }
  335.  
  336. long get_long(FFILE *f)
  337. {
  338.     unsigned char c0,c1,c2,c3;
  339.  
  340.     //c3=cfgetc(f);
  341.     //c2=cfgetc(f);
  342.     //c1=cfgetc(f);
  343.     //c0=cfgetc(f);
  344.  
  345.     if (f->position>=f->length) return EOF;
  346.     c3 = f->data[f->position++];
  347.     if (f->position>=f->length) return EOF;
  348.     c2 = f->data[f->position++];
  349.     if (f->position>=f->length) return EOF;
  350.     c1 = f->data[f->position++];
  351.     if (f->position>=f->length) return EOF;
  352.     c0 = f->data[f->position++];
  353.  
  354. //printf("get_long %x %x %x %x\n",c3,c2,c1,c0);
  355.  
  356. //  if (c0==0xff) return(EOF);
  357.  
  358.     return(((long)c3<<24) + ((long)c2<<16) + ((long)c1<<8) + c0);
  359.  
  360. }
  361.  
  362. int parse_bmhd(FFILE *ifile,long len,iff_bitmap_header *bmheader)
  363. {
  364.     len++;  /* so no "parm not used" warning */
  365.  
  366. //  debug("parsing bmhd len=%ld\n",len);
  367.  
  368.     bmheader->w = get_word(ifile);
  369.     bmheader->h = get_word(ifile);
  370.     bmheader->x = get_word(ifile);
  371.     bmheader->y = get_word(ifile);
  372.  
  373.     bmheader->nplanes = get_byte(ifile);
  374.     bmheader->masking = get_byte(ifile);
  375.     bmheader->compression = get_byte(ifile);
  376.     get_byte(ifile);        /* skip pad */
  377.  
  378.     bmheader->transparentcolor = get_word(ifile);
  379.     bmheader->xaspect = get_byte(ifile);
  380.     bmheader->yaspect = get_byte(ifile);
  381.  
  382.     bmheader->pagewidth = get_word(ifile);
  383.     bmheader->pageheight = get_word(ifile);
  384.  
  385.     iff_transparent_color = bmheader->transparentcolor;
  386.  
  387.     iff_has_transparency = 0;
  388.  
  389.     if (bmheader->masking == mskHasTransparentColor)
  390.         iff_has_transparency = 1;
  391.  
  392.     else if (bmheader->masking != mskNone && bmheader->masking != mskHasMask)
  393.         return IFF_UNKNOWN_MASK;
  394.  
  395. //  debug("w,h=%d,%d x,y=%d,%d\n",w,h,x,y);
  396. //  debug("nplanes=%d, masking=%d ,compression=%d, transcolor=%d\n",nplanes,masking,compression,transparentcolor);
  397.  
  398.     return IFF_NO_ERROR;
  399. }
  400.  
  401.  
  402. //  the buffer pointed to by raw_data is stuffed with a pointer to decompressed pixel data
  403. int parse_body(FFILE *ifile,long len,iff_bitmap_header *bmheader)
  404. {
  405.     unsigned char  *p=bmheader->raw_data;
  406.     int width,depth;
  407.     signed char n;
  408.     int nn,wid_cnt,end_cnt,plane;
  409.     char ignore=0;
  410.     unsigned char *data_end;
  411.     int end_pos;
  412.     int row_count=0;
  413.  
  414.     end_pos = ifile->position + len;
  415.     if (len&1)
  416.         end_pos++;
  417.  
  418.     if (bmheader->type == TYPE_PBM) {
  419.         width=bmheader->w;
  420.         depth=1;
  421.     } else if (bmheader->type == TYPE_ILBM) {
  422.         width = (bmheader->w+7)/8;
  423.         depth=bmheader->nplanes;
  424.     }
  425.  
  426.     end_cnt = (width&1)?-1:0;
  427.  
  428.     data_end = p + width*bmheader->h*depth;
  429.  
  430.     if (bmheader->compression == cmpNone) {        /* no compression */
  431.         int y;
  432.  
  433.         for (y=bmheader->h;y;y--) {
  434.             int x;
  435. //            for (x=bmheader->w;x;x--) *p++=cfgetc(ifile);
  436. //            cfread(p, bmheader->w, 1, ifile);
  437. //            p += bmheader->w;
  438.  
  439.             for (x=0;x<width*depth;x++)
  440.                 *p++=ifile->data[ifile->position++];
  441.  
  442.             if (bmheader->masking == mskHasMask)
  443.                 ifile->position += width;                //skip mask!
  444.  
  445. //            if (bmheader->w & 1) ignore = cfgetc(ifile);
  446.             if (bmheader->w & 1) ifile->position++;
  447.         }
  448.  
  449.         //cnt = len - bmheader->h * ((bmheader->w+1)&~1);
  450.  
  451.     }
  452.     else if (bmheader->compression == cmpByteRun1)
  453.         for (wid_cnt=width,plane=0;ifile->position<end_pos && p<data_end;) {
  454.             unsigned char c;
  455.  
  456. //            if (old_cnt-cnt > 2048) {
  457. //              printf(".");
  458. //                old_cnt=cnt;
  459. //            }
  460.  
  461.             if (wid_cnt == end_cnt) {
  462.                 wid_cnt = width;
  463.                 plane++;
  464.                 if ((bmheader->masking == mskHasMask && plane==depth+1) ||
  465.                     (bmheader->masking != mskHasMask && plane==depth))
  466.                     plane=0;
  467.             }
  468.  
  469.             Assert(wid_cnt > end_cnt);
  470.  
  471.             //n=cfgetc(ifile);
  472.             n=ifile->data[ifile->position++];
  473.  
  474.             if (n >= 0) {                       // copy next n+1 bytes from source, they are not compressed
  475.                 nn = (int) n+1;
  476.                 wid_cnt -= nn;
  477.                 if (wid_cnt==-1) {--nn; Assert(width&1);}
  478.                 if (plane==depth)    //masking row
  479.                     ifile->position += nn;
  480.                 else
  481.                     while (nn--) *p++=ifile->data[ifile->position++];
  482.                 if (wid_cnt==-1) ifile->position++;
  483.             }
  484.             else if (n>=-127) {             // next -n + 1 bytes are following byte
  485.                 c=ifile->data[ifile->position++];
  486.                 nn = (int) -n+1;
  487.                 wid_cnt -= nn;
  488.                 if (wid_cnt==-1) {--nn; Assert(width&1);}
  489.                 if (plane!=depth)    //not masking row
  490.                     {memset(p,c,nn); p+=nn;}
  491.             }
  492.  
  493.             #ifndef NDEBUG
  494.             if ((p-bmheader->raw_data) % width == 0)
  495.                     row_count++;
  496.  
  497.             Assert((p-bmheader->raw_data) - (width*row_count) < width);
  498.             #endif
  499.  
  500.         }
  501.  
  502.     if (bmheader->masking==mskHasMask && p==data_end && ifile->position==end_pos-2)        //I don't know why...
  503.         ifile->position++;        //...but if I do this it works
  504.  
  505.     if (p==data_end && ifile->position==end_pos-1)        //must be a pad byte
  506.         //ignore = cfgetc(ifile);        //get pad byte
  507.         ifile->position++;
  508.     else
  509.         if (ifile->position!=end_pos || p!=data_end) {
  510. //            debug("IFF Error: p=%x, data_end=%x, cnt=%d\n",p,data_end,cnt);
  511.             return IFF_CORRUPT;
  512.         }
  513.  
  514.     if (ignore) ignore++;   // haha, suppress the evil warning message
  515.  
  516.     return IFF_NO_ERROR;
  517. }
  518.  
  519. //modify passed bitmap
  520. int parse_delta(FFILE *ifile,long len,iff_bitmap_header *bmheader)
  521. {
  522.     unsigned char  *p=bmheader->raw_data;
  523.     int y;
  524.     long chunk_end = ifile->position + len;
  525.  
  526.     get_long(ifile);        //longword, seems to be equal to 4.  Don't know what it is
  527.  
  528.     for (y=0;y<bmheader->h;y++) {
  529.         ubyte n_items;
  530.         int cnt = bmheader->w;
  531.         ubyte code;
  532.  
  533.         n_items = get_byte(ifile);
  534.  
  535.         while (n_items--) {
  536.  
  537.             code = get_byte(ifile);
  538.  
  539.             if (code==0) {                //repeat
  540.                 ubyte rep,val;
  541.  
  542.                 rep = get_byte(ifile);
  543.                 val = get_byte(ifile);
  544.  
  545.                 cnt -= rep;
  546.                 if (cnt==-1)
  547.                     rep--;
  548.                 while (rep--)
  549.                     *p++ = val;
  550.             }
  551.             else if (code > 0x80) {    //skip
  552.                 cnt -= (code-0x80);
  553.                 p += (code-0x80);
  554.                 if (cnt==-1)
  555.                     p--;
  556.             }
  557.             else {                        //literal
  558.                 cnt -= code;
  559.                 if (cnt==-1)
  560.                     code--;
  561.  
  562.                 while (code--)
  563.                     *p++ = get_byte(ifile);
  564.  
  565.                 if (cnt==-1)
  566.                     get_byte(ifile);
  567.             }
  568.  
  569.         }
  570.  
  571.         if (cnt == -1) {
  572.             if (!bmheader->w&1)
  573.                 return IFF_CORRUPT;
  574.         }
  575.         else if (cnt)
  576.             return IFF_CORRUPT;
  577.     }
  578.  
  579.     if (ifile->position == chunk_end-1)        //pad
  580.         ifile->position++;
  581.  
  582.     if (ifile->position != chunk_end)
  583.         return IFF_CORRUPT;
  584.     else
  585.         return IFF_NO_ERROR;
  586. }
  587.  
  588. //  the buffer pointed to by raw_data is stuffed with a pointer to bitplane pixel data
  589. void skip_chunk(FFILE *ifile,long len)
  590. {
  591.     //int c,i;
  592.     int ilen;
  593.     ilen = len+1 & ~1;
  594.  
  595. //printf( "Skipping %d chunk\n", ilen );
  596.  
  597.     ifile->position += ilen;
  598.  
  599.     if (ifile->position >= ifile->length )    {
  600.         ifile->position = ifile->length;
  601.     }
  602.  
  603.  
  604. //    for (i=0; i<ilen; i++ )
  605. //        c = cfgetc(ifile);
  606.     //Assert(cfseek(ifile,ilen,SEEK_CUR)==0);
  607. }
  608.  
  609. //read an ILBM or PBM file
  610. // Pass pointer to opened file, and to empty bitmap_header structure, and form length
  611. int iff_parse_ilbm_pbm(FFILE *ifile,long form_type,iff_bitmap_header *bmheader,int form_len,grs_bitmap *prev_bm)
  612. {
  613.     long sig,len;
  614.     //char ignore=0;
  615.     long start_pos,end_pos;
  616.  
  617.     start_pos = ifile->position;
  618.     end_pos = start_pos-4+form_len;
  619.  
  620. //      printf(" %ld ",form_len);
  621. //      printsig(form_type);
  622. //      printf("\n");
  623.  
  624.             if (form_type == pbm_sig)
  625.                 bmheader->type = TYPE_PBM;
  626.             else
  627.                 bmheader->type = TYPE_ILBM;
  628.  
  629.             while ((ifile->position < end_pos) && (sig=get_sig(ifile)) != EOF) {
  630.  
  631.                 len=get_long(ifile);
  632.                 if (len==EOF) break;
  633.  
  634. //              printf(" ");
  635. //              printsig(sig);
  636. //              printf(" %ld\n",len);
  637.  
  638.                 switch (sig) {
  639.  
  640.                     case bmhd_sig: {
  641.                         int ret;
  642.                         int save_w=bmheader->w,save_h=bmheader->h;
  643.  
  644.                         //printf("Parsing header\n");
  645.  
  646.                         ret = parse_bmhd(ifile,len,bmheader);
  647.  
  648.                         if (ret != IFF_NO_ERROR)
  649.                             return ret;
  650.  
  651.                         if (bmheader->raw_data) {
  652.  
  653.                             if (save_w != bmheader->w  ||  save_h != bmheader->h)
  654.                                 return IFF_BM_MISMATCH;
  655.  
  656.                         }
  657.                         else {
  658.  
  659.                             //MALLOC( bmheader->raw_data, ubyte, bmheader->w * bmheader->h );//Hack by KRB
  660.                             bmheader->raw_data=(ubyte *)malloc((bmheader->w * bmheader->h)*sizeof(ubyte));
  661.                             if (!bmheader->raw_data)
  662.                                 return IFF_NO_MEM;
  663.                         }
  664.  
  665.                         break;
  666.  
  667.                     }
  668.  
  669.                     case anhd_sig:
  670.  
  671.                         if (!prev_bm) return IFF_CORRUPT;
  672.  
  673.                         bmheader->w = prev_bm->bm_w;
  674.                         bmheader->h = prev_bm->bm_h;
  675.                         bmheader->type = prev_bm->bm_type;
  676.  
  677.                         //MALLOC( bmheader->raw_data, ubyte, bmheader->w * bmheader->h );//Hack by KRB
  678.                         bmheader->raw_data=(ubyte *)malloc((bmheader->w * bmheader->h)*sizeof(ubyte));
  679.  
  680.                         memcpy(bmheader->raw_data, prev_bm->bm_data, bmheader->w * bmheader->h );
  681.                         skip_chunk(ifile,len);
  682.  
  683.                         break;
  684.  
  685.                     case cmap_sig:
  686.                     {
  687.                         int ncolors=(int) (len/3),cnum;
  688.                         unsigned char r,g,b;
  689.  
  690.                         //printf("Parsing RGB map\n");
  691.                         for (cnum=0;cnum<ncolors;cnum++) {
  692. //                            r=cfgetc(ifile);
  693. //                            g=cfgetc(ifile);
  694. //                            b=cfgetc(ifile);
  695.                             r = ifile->data[ifile->position++];
  696.                             g = ifile->data[ifile->position++];
  697.                             b = ifile->data[ifile->position++];
  698.                             r >>= 2; bmheader->palette[cnum].r = r;
  699.                             g >>= 2; bmheader->palette[cnum].g = g;
  700.                             b >>= 2; bmheader->palette[cnum].b = b;
  701.                         }
  702.                         //if (len & 1) ignore = cfgetc(ifile);
  703.                         if (len & 1 ) ifile->position++;
  704.  
  705.                         break;
  706.                     }
  707.  
  708.                     case body_sig:
  709.                     {
  710.                         int r;
  711.                         //printf("Parsing body\n");
  712.                         if ((r=parse_body(ifile,len,bmheader))!=IFF_NO_ERROR)
  713.                             return r;
  714.                         break;
  715.                     }
  716.                     case dlta_sig:
  717.                     {
  718.                         int r;
  719.                         if ((r=parse_delta(ifile,len,bmheader))!=IFF_NO_ERROR)
  720.                             return r;
  721.                         break;
  722.                     }
  723.                     default:
  724.                         skip_chunk(ifile,len);
  725.                         break;
  726.                 }
  727.             }
  728.  
  729.     //if (ignore) ignore++;
  730.  
  731.     if (ifile->position != start_pos-4+form_len)
  732.         return IFF_CORRUPT;
  733.  
  734.     return IFF_NO_ERROR;    /* ok! */
  735. }
  736.  
  737. //convert an ILBM file to a PBM file
  738. int convert_ilbm_to_pbm(iff_bitmap_header *bmheader)
  739. {
  740.     int x,y,p;
  741.     byte *new_data,*destptr,*rowptr;
  742.     int bytes_per_row,byteofs;
  743.     ubyte checkmask,newbyte,setbit;
  744.  
  745.     //MALLOC( new_data, byte, bmheader->w * bmheader->h );//hack by KRB
  746.     new_data = (byte *)malloc((bmheader->w * bmheader->h)*sizeof(byte));
  747.     if (new_data == NULL) return IFF_NO_MEM;
  748.  
  749.     destptr = new_data;
  750.  
  751.     bytes_per_row = 2*((bmheader->w+15)/16);
  752.  
  753.     for (y=0;y<bmheader->h;y++) {
  754.  
  755.         rowptr = &bmheader->raw_data[y * bytes_per_row * bmheader->nplanes];
  756.  
  757.         for (x=0,checkmask=0x80;x<bmheader->w;x++) {
  758.  
  759.             byteofs = x >> 3;
  760.  
  761.             for (p=newbyte=0,setbit=1;p<bmheader->nplanes;p++) {
  762.  
  763.                 if (rowptr[bytes_per_row * p + byteofs] & checkmask)
  764.                     newbyte |= setbit;
  765.  
  766.                 setbit <<= 1;
  767.             }
  768.  
  769.             *destptr++ = newbyte;
  770.  
  771.             if ((checkmask >>= 1) == 0) checkmask=0x80;
  772.         }
  773.  
  774.     }
  775.  
  776.     free(bmheader->raw_data);
  777.     bmheader->raw_data = new_data;
  778.  
  779.     bmheader->type = TYPE_PBM;
  780.  
  781.     return IFF_NO_ERROR;
  782. }
  783.  
  784. #define INDEX_TO_15BPP(i) ((short)((((palptr[(i)].r/2)&31)<<10)+(((palptr[(i)].g/2)&31)<<5)+((palptr[(i)].b/2 )&31)))
  785.  
  786. int convert_rgb15(grs_bitmap *bm,iff_bitmap_header *bmheader)
  787. {
  788.     ushort *new_data;
  789.     int x,y;
  790.     int newptr = 0;
  791.     pal_entry *palptr;
  792.  
  793.     palptr = bmheader->palette;
  794.  
  795. //        if ((new_data = malloc(bm->bm_w * bm->bm_h * 2)) == NULL)
  796. //            {ret=IFF_NO_MEM; goto done;}
  797.        //MALLOC(new_data, ushort, bm->bm_w * bm->bm_h * 2);//hack by KRB also a bug I believe. It is allocating twice the needed memory.
  798.         new_data = malloc(bm->bm_w * bm->bm_h * 2);//I left it as previously done, thinking the *2 means sizeof(ushort)
  799.        if (new_data == NULL)
  800.            return IFF_NO_MEM;
  801.  
  802.     for (y=0; y<bm->bm_h; y++) {
  803.  
  804.         for (x=0; x<bmheader->w; x++)
  805.             new_data[newptr++] = INDEX_TO_15BPP(bmheader->raw_data[y*bmheader->w+x]);
  806.  
  807.     }
  808.  
  809.     free(bm->bm_data);                //get rid of old-style data
  810.     bm->bm_data = (ubyte *) new_data;            //..and point to new data
  811.  
  812.     bm->bm_rowsize *= 2;                //two bytes per row
  813.  
  814.     return IFF_NO_ERROR;
  815.  
  816. }
  817.  
  818. //read in a entire file into a fake file structure
  819. int open_fake_file(char *ifilename,FFILE *ffile)
  820. {
  821.     CFILE *ifile;
  822.     int ret;
  823.  
  824.     //printf( "Reading %s\n", ifilename );
  825.  
  826.     ffile->data=NULL;
  827.  
  828.     if ((ifile = cfopen(ifilename,"rb")) == NULL) return IFF_NO_FILE;
  829.  
  830.     ffile->length = cfilelength(ifile);
  831.  
  832.     //MALLOC(ffile->data,ubyte,ffile->length);//Hack by KRB
  833.     ffile->data = (ubyte *)malloc(ffile->length*sizeof(ubyte));
  834.  
  835.     if (cfread(ffile->data, 1, ffile->length, ifile) < ffile->length)
  836.         ret = IFF_READ_ERROR;
  837.     else
  838.         ret = IFF_NO_ERROR;
  839.  
  840.     ffile->position = 0;
  841.  
  842.     if (ifile) cfclose(ifile);
  843.  
  844.     return ret;
  845. }
  846.  
  847. close_fake_file(FFILE *f)
  848. {
  849.     if (f->data)
  850.         free(f->data);
  851.  
  852.     f->data = NULL;
  853. }
  854.  
  855. //copy an iff header structure to a grs_bitmap structure
  856. copy_iff_to_grs(grs_bitmap *bm,iff_bitmap_header *bmheader)
  857. {
  858.     bm->bm_x = bm->bm_y = 0;
  859.     bm->bm_w = bmheader->w;
  860.     bm->bm_h = bmheader->h;
  861.     bm->bm_type = bmheader->type;
  862.     bm->bm_rowsize = bmheader->w;
  863.     bm->bm_data = bmheader->raw_data;
  864.  
  865.     bm->bm_flags = bm->bm_selector = 0;
  866. }
  867.  
  868. //if bm->bm_data is set, use it (making sure w & h are correct), else
  869. //allocate the memory
  870. int iff_parse_bitmap(FFILE *ifile,grs_bitmap *bm,int bitmap_type,byte *palette,grs_bitmap *prev_bm)
  871. {
  872.     int ret;            //return code
  873.     iff_bitmap_header bmheader;
  874.     long sig,form_len;
  875.     long form_type;
  876.  
  877.     bmheader.raw_data = bm->bm_data;
  878.  
  879.     if (bmheader.raw_data) {
  880.         bmheader.w = bm->bm_w;
  881.         bmheader.h = bm->bm_h;
  882.     }
  883.  
  884.     sig=get_sig(ifile);
  885.  
  886.     if (sig != form_sig) {
  887.         ret = IFF_NOT_IFF;
  888.         goto done;
  889.     }
  890.  
  891.     form_len = get_long(ifile);
  892.  
  893.     form_type = get_sig(ifile);
  894.  
  895.     if (form_type == anim_sig)
  896.         ret = IFF_FORM_ANIM;
  897.     else if ((form_type == pbm_sig) || (form_type == ilbm_sig))
  898.         ret = iff_parse_ilbm_pbm(ifile,form_type,&bmheader,form_len,prev_bm);
  899.     else
  900.         ret = IFF_UNKNOWN_FORM;
  901.  
  902.     if (ret != IFF_NO_ERROR) {        //got an error parsing
  903.         if (bmheader.raw_data) free(bmheader.raw_data); 
  904.         goto done;
  905.     }
  906.  
  907.     //If IFF file is ILBM, convert to PPB
  908.     if (bmheader.type == TYPE_ILBM) {
  909.  
  910.         ret = convert_ilbm_to_pbm(&bmheader);
  911.  
  912.         if (ret != IFF_NO_ERROR) goto done;
  913.     }
  914.  
  915.     //Copy data from iff_bitmap_header structure into grs_bitmap structure
  916.  
  917.     copy_iff_to_grs(bm,&bmheader);
  918.  
  919.     if (palette) memcpy(palette,&bmheader.palette,sizeof(bmheader.palette));
  920.  
  921.     //Now do post-process if required
  922.  
  923.     if (bitmap_type == BM_RGB15) {
  924.         ret = convert_rgb15(bm,&bmheader);
  925.         if (ret != IFF_NO_ERROR) goto done;
  926.     }
  927.  
  928. done:
  929.  
  930.     return ret;
  931.  
  932. }
  933.  
  934. //returns error codes - see IFF.H.  see GR.H for bitmap_type
  935. int iff_read_bitmap(char *ifilename,grs_bitmap *bm,int bitmap_type,byte *palette)
  936. {
  937.     int ret;            //return code
  938.     FFILE ifile;
  939.  
  940.     ret = open_fake_file(ifilename,&ifile);        //read in entire file
  941.     if (ret != IFF_NO_ERROR) goto done;
  942.  
  943.     bm->bm_data = NULL;
  944.  
  945.     ret = iff_parse_bitmap(&ifile,bm,bitmap_type,palette,NULL);
  946.  
  947. done:
  948.  
  949.     if (ifile.data) free(ifile.data);
  950.  
  951.     close_fake_file(&ifile);
  952.  
  953.     return ret;
  954.  
  955.  
  956. }
  957.  
  958. //like iff_read_bitmap(), but reads into a bitmap that already exists,
  959. //without allocating memory for the bitmap. 
  960. int iff_read_into_bitmap(char *ifilename,grs_bitmap *bm,byte *palette)
  961. {
  962.     int ret;            //return code
  963.     FFILE ifile;
  964.  
  965.     ret = open_fake_file(ifilename,&ifile);        //read in entire file
  966.     if (ret != IFF_NO_ERROR) goto done;
  967.  
  968.     ret = iff_parse_bitmap(&ifile,bm,bm->bm_type,palette,NULL);
  969.  
  970. done:
  971.  
  972.     if (ifile.data) free(ifile.data);
  973.  
  974.     close_fake_file(&ifile);
  975.  
  976.     return ret;
  977.  
  978.  
  979. }
  980.  
  981. #define BMHD_SIZE 20
  982.  
  983. int write_bmhd(FILE *ofile,iff_bitmap_header *bitmap_header)
  984. {
  985.     put_sig(bmhd_sig,ofile);
  986.     put_long((long) BMHD_SIZE,ofile);
  987.  
  988.     put_word(bitmap_header->w,ofile);
  989.     put_word(bitmap_header->h,ofile);
  990.     put_word(bitmap_header->x,ofile);
  991.     put_word(bitmap_header->y,ofile);
  992.  
  993.     put_byte(bitmap_header->nplanes,ofile);
  994.     put_byte(bitmap_header->masking,ofile);
  995.     put_byte(bitmap_header->compression,ofile);
  996.     put_byte(0,ofile);    /* pad */
  997.  
  998.     put_word(bitmap_header->transparentcolor,ofile);
  999.     put_byte(bitmap_header->xaspect,ofile);
  1000.     put_byte(bitmap_header->yaspect,ofile);
  1001.  
  1002.     put_word(bitmap_header->pagewidth,ofile);
  1003.     put_word(bitmap_header->pageheight,ofile);
  1004.  
  1005.     return IFF_NO_ERROR;
  1006.  
  1007. }
  1008.  
  1009. int write_pal(FILE *ofile,iff_bitmap_header *bitmap_header)
  1010. {
  1011.     int    i;
  1012.  
  1013.     int n_colors = 1<<bitmap_header->nplanes;
  1014.  
  1015.     put_sig(cmap_sig,ofile);
  1016. //    put_long(sizeof(pal_entry) * n_colors,ofile);
  1017.     put_long(3 * n_colors,ofile);
  1018.  
  1019. //printf("new write pal %d %d\n",3,n_colors);
  1020.  
  1021.     for (i=0; i<256; i++) {
  1022.         unsigned char r,g,b;
  1023.         r = bitmap_header->palette[i].r * 4 + (bitmap_header->palette[i].r?3:0);
  1024.         g = bitmap_header->palette[i].g * 4 + (bitmap_header->palette[i].g?3:0);
  1025.         b = bitmap_header->palette[i].b * 4 + (bitmap_header->palette[i].b?3:0);
  1026.         fputc(r,ofile);
  1027.         fputc(g,ofile);
  1028.         fputc(b,ofile);
  1029.     }
  1030.  
  1031. //printf("write pal %d %d\n",sizeof(pal_entry),n_colors);
  1032. //    fwrite(bitmap_header->palette,sizeof(pal_entry),n_colors,ofile);
  1033.  
  1034.     return IFF_NO_ERROR;
  1035. }
  1036.  
  1037. int rle_span(ubyte *dest,ubyte *src,int len)
  1038. {
  1039.     int n,lit_cnt,rep_cnt;
  1040.     ubyte last,*cnt_ptr,*dptr;
  1041.  
  1042.     dptr = dest;
  1043.  
  1044.     last=src[0]; lit_cnt=1;
  1045.  
  1046.     for (n=1;n<len;n++) {
  1047.  
  1048.         if (src[n] == last) {
  1049.  
  1050.             rep_cnt = 2;
  1051.  
  1052.             n++;
  1053.             while (n<len && rep_cnt<128 && src[n]==last) {n++; rep_cnt++;}
  1054.  
  1055.             if (rep_cnt > 2 || lit_cnt < 2) {
  1056.  
  1057.                 if (lit_cnt > 1) {*cnt_ptr = lit_cnt-2; --dptr;}        //save old lit count
  1058.                 *dptr++ = -(rep_cnt-1);
  1059.                 *dptr++ = last;
  1060.                 last = src[n];
  1061.                 lit_cnt = (n<len)?1:0;
  1062.  
  1063.                 continue;        //go to next char
  1064.             } else n--;
  1065.  
  1066.         }
  1067.  
  1068.         {
  1069.  
  1070.             if (lit_cnt==1) {
  1071.                 cnt_ptr = dptr++;        //save place for count
  1072.                 *dptr++=last;            //store first char
  1073.             }
  1074.  
  1075.             *dptr++ = last = src[n];
  1076.  
  1077.             if (lit_cnt == 127) {
  1078.                 *cnt_ptr = lit_cnt;
  1079.                 //cnt_ptr = dptr++;
  1080.                 lit_cnt = 1;
  1081.                 last = src[++n];
  1082.             }
  1083.             else lit_cnt++;
  1084.         }
  1085.  
  1086.  
  1087.     }
  1088.  
  1089.     if (lit_cnt==1) {
  1090.         *dptr++ = 0;
  1091.         *dptr++=last;            //store first char
  1092.     }
  1093.     else if (lit_cnt > 1)
  1094.         *cnt_ptr = lit_cnt-1;
  1095.  
  1096.     return dptr-dest;
  1097. }
  1098.  
  1099. #define EVEN(a) ((a+1)&0xfffffffel)
  1100.  
  1101. //returns length of chunk
  1102. int write_body(FILE *ofile,iff_bitmap_header *bitmap_header,int compression_on)
  1103. {
  1104.     int w=bitmap_header->w,h=bitmap_header->h;
  1105.     int y,odd=w&1;
  1106.     long len = EVEN(w) * h,newlen,total_len=0;
  1107.     ubyte *p=bitmap_header->raw_data,*new_span;
  1108.     long save_pos;
  1109.  
  1110.     put_sig(body_sig,ofile);
  1111.     save_pos = ftell(ofile);
  1112.     put_long(len,ofile);
  1113.  
  1114.     //if (! (new_span = malloc(bitmap_header->w+(bitmap_header->w/128+2)*2))) return IFF_NO_MEM;
  1115.    // MALLOC( new_span, ubyte, bitmap_header->w + (bitmap_header->w/128+2)*2);//hack by KRB, also allocating twice the needed memory, probably a bug
  1116.     new_span = malloc(bitmap_header->w+(bitmap_header->w/128+2)*2);//left it alone, as in 2 lines above -KRB
  1117.     if (new_span == NULL) return IFF_NO_MEM;
  1118.  
  1119.     for (y=bitmap_header->h;y--;) {
  1120.  
  1121.         if (compression_on) {
  1122.             total_len += newlen = rle_span(new_span,p,bitmap_header->w+odd);
  1123.             fwrite(new_span,newlen,1,ofile);
  1124.         }
  1125.         else
  1126.             fwrite(p,bitmap_header->w+odd,1,ofile);
  1127.  
  1128.         p+=bitmap_header->row_size;    //bitmap_header->w;
  1129.     }
  1130.  
  1131.     if (compression_on) {        //write actual data length
  1132.         Assert(fseek(ofile,save_pos,SEEK_SET)==0);
  1133.         put_long(total_len,ofile);
  1134.         Assert(fseek(ofile,total_len,SEEK_CUR)==0);
  1135.         if (total_len&1) fputc(0,ofile);        //pad to even
  1136.     }
  1137.  
  1138.     free(new_span);
  1139.  
  1140.     return ((compression_on) ? (EVEN(total_len)+8) : (len+8));
  1141.  
  1142. }
  1143.  
  1144. #if WRITE_TINY
  1145. //write a small representation of a bitmap. returns size
  1146. int write_tiny(CFILE *ofile,iff_bitmap_header *bitmap_header,int compression_on)
  1147. {
  1148.     int skip;
  1149.     int new_w,new_h;
  1150.     int len,total_len=0,newlen;
  1151.     int x,y,xofs,odd;
  1152.     ubyte *p = bitmap_header->raw_data;
  1153.     ubyte tspan[80],new_span[80*2];
  1154.     long save_pos;
  1155.  
  1156.     skip = max((bitmap_header->w+79)/80,(bitmap_header->h+63)/64);
  1157.  
  1158.     new_w = bitmap_header->w / skip;
  1159.     new_h = bitmap_header->h / skip;
  1160.  
  1161.     odd = new_w & 1;
  1162.  
  1163.     len = new_w * new_h + 4;
  1164.  
  1165.     put_sig(tiny_sig,ofile);
  1166.     save_pos = cftell(ofile);
  1167.     put_long(EVEN(len),ofile);
  1168.  
  1169.     put_word(new_w,ofile);
  1170.     put_word(new_h,ofile);
  1171.  
  1172.     for (y=0;y<new_h;y++) {
  1173.         for (x=xofs=0;x<new_w;x++,xofs+=skip)
  1174.             tspan[x] = p[xofs];
  1175.  
  1176.         if (compression_on) {
  1177.             total_len += newlen = rle_span(new_span,tspan,new_w+odd);
  1178.             fwrite(new_span,newlen,1,ofile);
  1179.         }
  1180.         else
  1181.             fwrite(p,new_w+odd,1,ofile);
  1182.  
  1183.         p += skip * bitmap_header->row_size;        //bitmap_header->w;
  1184.  
  1185.     }
  1186.  
  1187.     if (compression_on) {
  1188.         Assert(cfseek(ofile,save_pos,SEEK_SET)==0);
  1189.         put_long(4+total_len,ofile);
  1190.         Assert(cfseek(ofile,4+total_len,SEEK_CUR)==0);
  1191.         if (total_len&1) cfputc(0,ofile);        //pad to even
  1192.     }
  1193.  
  1194.     return ((compression_on) ? (EVEN(total_len)+8+4) : (len+8));
  1195. }
  1196. #endif
  1197.  
  1198. int write_pbm(FILE *ofile,iff_bitmap_header *bitmap_header,int compression_on)            /* writes a pbm iff file */
  1199. {
  1200.     int ret;
  1201.     long raw_size = EVEN(bitmap_header->w) * bitmap_header->h;
  1202.     long body_size,tiny_size,pbm_size = 4 + BMHD_SIZE + 8 + EVEN(raw_size) + sizeof(pal_entry)*(1<<bitmap_header->nplanes)+8;
  1203.     long save_pos;
  1204.  
  1205. //printf("write_pbm\n");
  1206.  
  1207.     put_sig(form_sig,ofile);
  1208.     save_pos = ftell(ofile);
  1209.     put_long(pbm_size+8,ofile);
  1210.     put_sig(pbm_sig,ofile);
  1211.  
  1212.     ret = write_bmhd(ofile,bitmap_header);
  1213.     if (ret != IFF_NO_ERROR) return ret;
  1214.  
  1215.     ret = write_pal(ofile,bitmap_header);
  1216.     if (ret != IFF_NO_ERROR) return ret;
  1217.  
  1218. #if WRITE_TINY
  1219.     tiny_size = write_tiny(ofile,bitmap_header,compression_on);
  1220. #else
  1221.     tiny_size = 0;
  1222. #endif
  1223.  
  1224.     body_size = write_body(ofile,bitmap_header,compression_on);
  1225.  
  1226.     pbm_size = 4 + BMHD_SIZE + body_size + tiny_size + sizeof(pal_entry)*(1<<bitmap_header->nplanes)+8;
  1227.  
  1228.     Assert(fseek(ofile,save_pos,SEEK_SET)==0);
  1229.     put_long(pbm_size+8,ofile);
  1230.     Assert(fseek(ofile,pbm_size+8,SEEK_CUR)==0);
  1231.  
  1232.     return ret;
  1233.  
  1234. }
  1235.  
  1236. //writes an IFF file from a grs_bitmap structure. writes palette if not null
  1237. //returns error codes - see IFF.H.
  1238. int iff_write_bitmap(char *ofilename,grs_bitmap *bm,byte *palette)
  1239. {
  1240.     FILE *ofile;
  1241.     iff_bitmap_header bmheader;
  1242.     int ret;
  1243.     int compression_on;
  1244.  
  1245.     if (bm->bm_type == BM_RGB15) return IFF_BAD_BM_TYPE;
  1246.  
  1247. #if COMPRESS
  1248.     compression_on = (bm->bm_w>=MIN_COMPRESS_WIDTH);
  1249. #else
  1250.     compression_on = 0;
  1251. #endif
  1252.  
  1253.     //fill in values in bmheader
  1254.  
  1255.     bmheader.x = bmheader.y = 0;
  1256.     bmheader.w = bm->bm_w;
  1257.     bmheader.h = bm->bm_h;
  1258.     bmheader.type = TYPE_PBM;
  1259.     bmheader.transparentcolor = iff_transparent_color;
  1260.     bmheader.pagewidth = bm->bm_w;    //I don't think it matters what I write
  1261.     bmheader.pageheight = bm->bm_h;
  1262.     bmheader.nplanes = 8;
  1263.     bmheader.masking = mskNone;
  1264.     if (iff_has_transparency)    {
  1265.          bmheader.masking |= mskHasTransparentColor;
  1266.     }
  1267.     bmheader.compression = (compression_on?cmpByteRun1:cmpNone);
  1268.  
  1269.     bmheader.xaspect = bmheader.yaspect = 1;    //I don't think it matters what I write
  1270.     bmheader.raw_data = bm->bm_data;
  1271.     bmheader.row_size = bm->bm_rowsize;
  1272.  
  1273.     if (palette) memcpy(&bmheader.palette,palette,256*3);
  1274.  
  1275.     //open file and write
  1276.  
  1277.     if ((ofile = fopen(ofilename,"wb")) == NULL) {ret=IFF_NO_FILE; goto done;}
  1278.  
  1279.     ret = write_pbm(ofile,&bmheader,compression_on);
  1280.  
  1281. done:
  1282.  
  1283.     fclose(ofile);
  1284.  
  1285.     return ret;
  1286. }
  1287.  
  1288. //read in many brushes.  fills in array of pointers, and n_bitmaps.
  1289. //returns iff error codes
  1290. int iff_read_animbrush(char *ifilename,grs_bitmap **bm_list,int max_bitmaps,int *n_bitmaps,ubyte *palette)
  1291. {
  1292.     int ret;            //return code
  1293.     FFILE ifile;
  1294.     iff_bitmap_header bmheader;
  1295.     long sig,form_len;
  1296.     long form_type;
  1297.  
  1298.     *n_bitmaps=0;
  1299.  
  1300.     ret = open_fake_file(ifilename,&ifile);        //read in entire file
  1301.     if (ret != IFF_NO_ERROR) goto done;
  1302.  
  1303.     bmheader.raw_data = NULL;
  1304.  
  1305.     sig=get_sig(&ifile);
  1306.     form_len = get_long(&ifile);
  1307.  
  1308.     if (sig != form_sig) {
  1309.         ret = IFF_NOT_IFF;
  1310.         goto done;
  1311.     }
  1312.  
  1313.     form_type = get_sig(&ifile);
  1314.  
  1315.     if ((form_type == pbm_sig) || (form_type == ilbm_sig))
  1316.         ret = IFF_FORM_BITMAP;
  1317.     else if (form_type == anim_sig) {
  1318.         int anim_end = ifile.position + form_len - 4;
  1319.  
  1320.         while (ifile.position < anim_end && *n_bitmaps < max_bitmaps) {
  1321.  
  1322.             grs_bitmap *prev_bm;
  1323.  
  1324.             prev_bm = *n_bitmaps>0?bm_list[*n_bitmaps-1]:NULL;
  1325.  
  1326.            //MALLOC(bm_list[*n_bitmaps] , grs_bitmap, 1 );//hack by KRB
  1327.             bm_list[*n_bitmaps]=(grs_bitmap *)malloc(1*sizeof(grs_bitmap));
  1328.             bm_list[*n_bitmaps]->bm_data = NULL;
  1329.  
  1330.             ret = iff_parse_bitmap(&ifile,bm_list[*n_bitmaps],form_type,*n_bitmaps>0?NULL:palette,prev_bm);
  1331.  
  1332.             if (ret != IFF_NO_ERROR)
  1333.                 goto done;
  1334.  
  1335.             (*n_bitmaps)++;
  1336.         }
  1337.  
  1338.         if (ifile.position < anim_end)    //ran out of room
  1339.             ret = IFF_TOO_MANY_BMS;
  1340.  
  1341.     }
  1342.     else
  1343.         ret = IFF_UNKNOWN_FORM;
  1344.  
  1345. done:
  1346.  
  1347.     close_fake_file(&ifile);
  1348.  
  1349.     return ret;
  1350.  
  1351. }
  1352.  
  1353. //text for error messges
  1354. char error_messages[] = {
  1355.     "No error.\0"
  1356.     "Not enough mem for loading or processing bitmap.\0"
  1357.     "IFF file has unknown FORM type.\0"
  1358.     "Not an IFF file.\0"
  1359.     "Cannot open file.\0"
  1360.     "Tried to save invalid type, like BM_RGB15.\0"
  1361.     "Bad data in file.\0"
  1362.     "ANIM file cannot be loaded with normal bitmap loader.\0"
  1363.     "Normal bitmap file cannot be loaded with anim loader.\0"
  1364.     "Array not big enough on anim brush read.\0"
  1365.     "Unknown mask type in bitmap header.\0"
  1366.     "Error reading file.\0"
  1367. };
  1368.  
  1369.  
  1370. //function to return pointer to error message
  1371. char *iff_errormsg(int error_number)
  1372. {
  1373.     char *p = error_messages;
  1374.  
  1375.     while (error_number--) {
  1376.  
  1377.         if (!p) return NULL;
  1378.  
  1379.         p += strlen(p)+1;
  1380.  
  1381.     }
  1382.  
  1383.     return p;
  1384.  
  1385. }
  1386.  
  1387.  
  1388. 
  1389.