amd64 fixes
[btb/d2x.git] / iff / archive / iffmike.c
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-1999 PARALLAX SOFTWARE CORPORATION.  ALL RIGHTS RESERVED.
12 */
13
14 #include <stdio.h>
15 #include <stdlib.h>
16 #include <alloc.h>
17
18 #include "iff.h"
19
20 #define MIN(a,b) ((a<b)?a:b)
21
22 #define MAKE_SIG(a,b,c,d) (((long)(a)<<24)+((long)(b)<<16)+((c)<<8)+(d))
23
24 #define form_sig MAKE_SIG('F','O','R','M')
25 #define ilbm_sig MAKE_SIG('I','L','B','M')
26 #define body_sig MAKE_SIG('B','O','D','Y')
27 #define pbm_sig MAKE_SIG('P','B','M',' ')
28 #define bmhd_sig MAKE_SIG('B','M','H','D')
29 #define cmap_sig MAKE_SIG('C','M','A','P')
30
31 void printsig(long s)
32 {
33         char *t=(char *) &s;
34
35 /*      printf("%c%c%c%c",*(&s+3),*(&s+2),*(&s+1),s);*/
36         printf("%c%c%c%c",t[3],t[2],t[1],t[0]);
37 }
38
39 long get_sig(FILE *f)
40 {
41         char s[4];
42
43         if ((s[3]=getc(f))==EOF) return(EOF);
44         if ((s[2]=getc(f))==EOF) return(EOF);
45         if ((s[1]=getc(f))==EOF) return(EOF);
46         if ((s[0]=getc(f))==EOF) return(EOF);
47
48         return(*((long *) s));
49 }
50
51 int put_sig(long sig,FILE *f)
52 {
53         char *s = (char *) &sig;
54
55         putc(s[3],f);
56         putc(s[2],f);
57         putc(s[1],f);
58         return putc(s[0],f);
59
60 }
61         
62 int get_word(FILE *f)
63 {
64         unsigned char c0,c1;
65
66         c1=getc(f);
67         c0=getc(f);
68
69         if (c0==0xff) return(EOF);
70
71         return(((int)c1<<8) + c0);
72
73 }
74
75 char get_byte(FILE *f)
76 {
77         return getc(f);
78 }
79
80 char put_byte(unsigned char c,FILE *f)
81 {
82         return putc(c,f);
83 }
84
85 int put_word(int n,FILE *f)
86 {
87         unsigned char c0,c1;
88
89         c0 = (n & 0xff00) >> 8;
90         c1 = n & 0xff;
91
92         put_byte(c0,f);
93         return put_byte(c1,f);
94 }
95
96 int put_long(long n,FILE *f)
97 {
98         int n0,n1;
99
100         n0 = (int) ((n & 0xffff0000l) >> 16);
101         n1 = (int) (n & 0xffff);
102
103         put_word(n0,f);
104         return put_word(n1,f);
105
106 }
107
108 long get_long(FILE *f)
109 {
110         unsigned char c0,c1,c2,c3;
111
112         c3=getc(f);
113         c2=getc(f);
114         c1=getc(f);
115         c0=getc(f);
116
117 //printf("get_long %x %x %x %x\n",c3,c2,c1,c0);
118
119 //      if (c0==0xff) return(EOF);
120
121         return(((long)c3<<24) + ((long)c2<<16) + ((long)c1<<8) + c0);
122
123 }
124
125 void parse_bmhd(FILE *ifile,long len,struct bitmap_header *bitmap_header)
126 {
127         len++;  /* so no "parm not used" warning */
128
129 //      debug("parsing bmhd len=%ld\n",len);
130
131         bitmap_header->w = get_word(ifile);
132         bitmap_header->h = get_word(ifile);
133         bitmap_header->x = get_word(ifile);
134         bitmap_header->y = get_word(ifile);
135
136         bitmap_header->nplanes = get_byte(ifile);
137         bitmap_header->masking = get_byte(ifile);
138         bitmap_header->compression = get_byte(ifile);
139         get_byte(ifile);                /* skip pad */
140
141         bitmap_header->transparentcolor = get_word(ifile);
142         bitmap_header->xaspect = get_byte(ifile);
143         bitmap_header->yaspect = get_byte(ifile);
144
145         bitmap_header->pagewidth = get_word(ifile);
146         bitmap_header->pageheight = get_word(ifile);
147
148 //      debug("w,h=%d,%d x,y=%d,%d\n",w,h,x,y);
149 //      debug("nplanes=%d, masking=%d ,compression=%d, transcolor=%d\n",nplanes,masking,compression,transparentcolor);
150
151 }
152
153
154 //      the buffer pointed to by raw_data is stuffed with a pointer to decompressed pixel data
155 int parse_body_pbm(FILE *ifile,long len,struct bitmap_header *bitmap_header)
156 {
157         unsigned char huge *p=bitmap_header->raw_data;
158         int width=bitmap_header->w;
159         long cnt,old_cnt;
160         char n;
161         int nn,wid_cnt;
162         char ignore;
163
164         if (bitmap_header->compression == cmpNone) {            /* no compression */
165                 int x,y;
166
167                 for (y=bitmap_header->h;y;y--) {
168                         for (x=bitmap_header->w;x;x--) *p++=getc(ifile);
169                         if (bitmap_header->w & 1) ignore = getc(ifile);
170                 }
171
172         }
173         else if (bitmap_header->compression == cmpByteRun1)
174                 for (old_cnt=cnt=len,wid_cnt=width;cnt>0;) {
175                         unsigned char c;
176         
177                         if (old_cnt-cnt > 2048) {
178 //                              printf(".");
179                                 old_cnt=cnt;
180                         }
181         
182                         if (wid_cnt <= 0) wid_cnt = width;
183         
184                         n=getc(ifile);
185                         if (n >= 0) {                                           // copy next n+1 bytes from source, they are not compressed
186                                 nn = (int) n+1;
187                                 cnt -= nn+1;
188                                 wid_cnt -= nn;
189                                 if (wid_cnt==-1) --nn;
190                                 while (nn--) *p++=getc(ifile);
191                                 if (wid_cnt==-1) ignore = getc(ifile);          /* extra char */
192                         }
193                         else if (n>=-127) {                             // next -n + 1 bytes are following byte
194                                 cnt -= 2;
195                                 c=getc(ifile);
196                                 nn = (int) -n+1;
197                                 wid_cnt -= nn;
198                                 if (wid_cnt==-1) --nn;
199                                 while (nn--) *p++=c;
200                         }
201         
202                 }
203         
204         if (len & 1) ignore = getc(ifile);
205
206         if (ignore) ignore++;   // haha, suppress the evil warning message
207
208         return IFF_NO_ERROR;
209 }
210
211 //      the buffer pointed to by raw_data is stuffed with a pointer to bitplane pixel data
212 int parse_body_ilbm(FILE *ifile,long len,struct bitmap_header *bitmap_header)
213 {
214         unsigned char huge *p=bitmap_header->raw_data;
215         int width=bitmap_header->w;
216         long cnt,old_cnt;
217         char n;
218         int nn,wid_cnt;
219         char    ignore;
220
221         if (bitmap_header->compression == cmpNone) {            /* no compression */
222                 int x,y;
223
224                 for (y=bitmap_header->h;y;y--) {
225                         for (x=bitmap_header->w;x;x--) *p++=getc(ifile);
226                         if (bitmap_header->w & 1) ignore = getc(ifile);
227                 }
228
229         }
230         else if (bitmap_header->compression == cmpByteRun1)
231                 for (old_cnt=cnt=len,wid_cnt=width;cnt>0;) {
232                         unsigned char c;
233         
234                         if (old_cnt-cnt > 2048) {
235 //                              printf(".");
236                                 old_cnt=cnt;
237                         }
238         
239                         if (wid_cnt <= 0) wid_cnt = width;
240         
241                         n=getc(ifile);
242                         if (n >= 0) {                                           // copy next n+1 bytes from source, they are not compressed
243                                 nn = (int) n+1;
244                                 cnt -= nn+1;
245                                 wid_cnt -= nn;
246                                 if (wid_cnt==-1) --nn;
247                                 while (nn--) *p++=getc(ifile);
248                                 if (wid_cnt==-1) ignore = getc(ifile);          /* extra char */
249                         }
250                         else if (n>=-127) {                             // next -n + 1 bytes are following byte
251                                 cnt -= 2;
252                                 c=getc(ifile);
253                                 nn = (int) -n+1;
254                                 wid_cnt -= nn;
255                                 if (wid_cnt==-1) --nn;
256                                 while (nn--) *p++=c;
257                         }
258         
259                 }
260         
261         if (len & 1) ignore = getc(ifile);
262
263         if (ignore) ignore++;   // haha, suppress the evil warning message
264
265         return IFF_NO_ERROR;
266 }
267
268 void skip_chunk(FILE *ifile,long len)
269 {
270         len = len+1 & ~1;
271         fseek(ifile,len,SEEK_CUR);
272 }
273
274 // Pass pointer to opened file, and to empty bitmap header.
275 int parse_iff(FILE *ifile,struct bitmap_header *bitmap_header)
276 {
277         long sig,form_len,len,form_type;
278         char    ignore;
279
280         sig=get_sig(ifile);
281
282 //      printsig(sig);
283
284         if (sig==form_sig) {
285
286                 form_len = get_long(ifile);
287                 form_len++;             /* get rid of never used message */
288
289                 form_type = get_sig(ifile);
290
291 //              printf(" %ld ",form_len);
292 //              printsig(form_type);
293 //              printf("\n");
294
295                 if ((form_type == pbm_sig) || (form_type == ilbm_sig)) {
296
297                         if (form_type == pbm_sig)
298                                 bitmap_header->type = PBM_TYPE;
299                         else
300                                 bitmap_header->type = ILBM_TYPE;
301
302                         while ((sig=get_sig(ifile)) != EOF) {
303
304                                 len=get_long(ifile);
305
306 //                              printf(" ");
307 //                              printsig(sig);
308 //                              printf(" %ld\n",len);
309
310                                 switch (sig) {
311
312                                         case bmhd_sig:
313
314                                                 parse_bmhd(ifile,len,bitmap_header);
315
316                                                 if (! (bitmap_header->raw_data = farmalloc((long) bitmap_header->w * bitmap_header->h))) return IFF_NO_MEM;
317                                                 
318                                                 break;
319
320                                         case cmap_sig:
321                                         {
322                                                 int ncolors=(int) (len/3),cnum;
323                                                 unsigned char r,g,b;
324         
325                                                 for (cnum=0;cnum<ncolors;cnum++) {
326                                                         r=getc(ifile);
327                                                         g=getc(ifile);
328                                                         b=getc(ifile);
329                                                         r >>= 2; bitmap_header->palette[cnum].r = r;
330                                                         g >>= 2; bitmap_header->palette[cnum].g = g;
331                                                         b >>= 2; bitmap_header->palette[cnum].b = b;
332                                                 }
333                                                 if (len & 1) ignore = getc(ifile);
334
335                                                 break;
336                                         }
337
338                                         case body_sig:
339                                         {
340                                                 int r;
341                                                 switch (form_type) {
342                                                         case pbm_sig:
343                                                                 if (!(r=parse_body_pbm(ifile,len,bitmap_header))) return r;
344                                                                 break;
345                                                         case ilbm_sig:
346                                                                 if (!(r=parse_body_ilbm(ifile,len,bitmap_header))) return r;
347                                                                 break;
348                                                 }
349                                                 break;
350                                         }
351                                         default:
352                                                 skip_chunk(ifile,len);
353                                                 break;
354                                 }
355                         }
356                 }
357                 else return IFF_UNKNOWN_FORM;
358         }
359         else
360                 {printf("Not an IFF file\n"); return IFF_NOT_IFF;}
361
362         if (ignore) ignore++;
363
364         return IFF_NO_ERROR;    /* ok! */
365 }
366
367 #define BMHD_SIZE 20
368
369 int write_bmhd(FILE *ofile,struct bitmap_header *bitmap_header)
370 {
371
372         put_sig(bmhd_sig,ofile);
373         put_long((long) BMHD_SIZE,ofile);
374
375         put_word(bitmap_header->w,ofile);
376         put_word(bitmap_header->h,ofile);
377         put_word(bitmap_header->x,ofile);
378         put_word(bitmap_header->y,ofile);
379
380         put_byte(bitmap_header->nplanes,ofile);
381         put_byte(bitmap_header->masking,ofile);
382         put_byte(bitmap_header->compression,ofile);
383         put_byte(0,ofile);      /* pad */
384
385         put_word(bitmap_header->transparentcolor,ofile);
386         put_byte(bitmap_header->xaspect,ofile);
387         put_byte(bitmap_header->yaspect,ofile);
388
389         put_word(bitmap_header->pagewidth,ofile);
390         put_word(bitmap_header->pageheight,ofile);
391
392         return 1;
393
394 }
395
396 int write_huge(unsigned char huge *huge_ptr,long len,FILE *f)
397 {
398         unsigned char temp_buffer[256],*t;
399
400 //printf("write_huge %ld\n",len);
401
402         while (len) {
403                 int n,wsize = (int) MIN(len,256);
404
405 //printf("len,wsize=%ld,%d\n",len,wsize);
406                 for (t=temp_buffer,n=wsize;n--;) *t++ = *huge_ptr++;
407
408                 fwrite(temp_buffer,wsize,1,f);
409
410                 len -= wsize;
411
412         }
413
414         return 1;
415 }
416
417 int write_pal(FILE *ofile,struct bitmap_header *bitmap_header)
418 {
419         int     i;
420
421         int n_colors = 1<<bitmap_header->nplanes;
422
423         put_sig(cmap_sig,ofile);
424 //      put_long(sizeof(struct pal_entry) * n_colors,ofile);
425         put_long(3 * n_colors,ofile);
426
427 //printf("new write pal %d %d\n",3,n_colors);
428
429         for (i=0; i<256; i++) {
430                 unsigned char r,g,b;
431                 r = bitmap_header->palette[i].r * 4;
432                 g = bitmap_header->palette[i].g * 4;
433                 b = bitmap_header->palette[i].b * 4;
434                 fputc(r,ofile);
435                 fputc(g,ofile);
436                 fputc(b,ofile);
437         }
438
439 //printf("write pal %d %d\n",sizeof(struct pal_entry),n_colors);
440 //      fwrite(bitmap_header->palette,sizeof(struct pal_entry),n_colors,ofile);
441
442         return 1;
443 }
444
445 #define EVEN(a) ((a+1)&0xfffffffel)
446
447 int write_body(FILE *ofile,struct bitmap_header *bitmap_header)
448 {
449         int w=bitmap_header->w,h=bitmap_header->h;
450         int y,odd=w&1;
451         long len = EVEN(w) * h;
452         unsigned char huge *p=bitmap_header->raw_data;
453
454         put_sig(body_sig,ofile);
455         put_long(len,ofile);
456
457         for (y=bitmap_header->h;y--;) {
458
459                 write_huge(p,bitmap_header->w,ofile);
460                 if (odd) putc(0,ofile);
461                 p+=bitmap_header->w;
462
463         }
464
465         return 1;
466 }
467
468 int write_pbm(FILE *ofile,struct bitmap_header *bitmap_header)                  /* writes a pbm iff file */
469 {
470         long raw_size = EVEN(bitmap_header->w) * bitmap_header->h;
471         long pbm_size = 4 + BMHD_SIZE + 8 + EVEN(raw_size) + sizeof(struct pal_entry)*(1<<bitmap_header->nplanes)+8;
472
473 //printf("write_pbm\n");
474
475         put_sig(form_sig,ofile);
476         put_long(pbm_size+8,ofile);
477         put_sig(pbm_sig,ofile);
478
479         write_bmhd(ofile,bitmap_header);
480
481         write_pal(ofile,bitmap_header);
482
483         write_body(ofile,bitmap_header);
484
485         return 1;
486
487 }
488