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