1 /*
2 * xviff.c - load routine for IFF ILBM format pictures
3 *
4 * LoadIFF(fname, pinfo) - loads an IFF file
5 *
6 *
7 * This loader module for xv will load most types of IFF ILBM pictures.
8 * Apart from any 'normal' ILBM format, this loader understands
9 * HAM (Hold-And-Modify), HAM8 (extended HAM), EHB (Extra Half Brite)
10 * and 24-Bit.
11 * Multipalette ILBMs are not supported yet, but I'll be working on that!
12 *
13 *
14 * History:
15 * 30-May-93: Project started
16 * ILBMs can now be loaded from xv
17 * EHB support added
18 * HAM support added
19 * 01-May-93: Started HAM8 support
20 * 04-Jun-93: HAM8 finally works! =:)
21 * 24 Bit support works!
22 */
23
24
25 /* Copyright Notice
26 * ================
27 * Copyright 1993 by Thomas Meyer
28 *
29 * Author:
30 * Thomas Meyer
31 * i03a@alf.zfn.uni-bremen.de
32 *
33 * Permission is hereby granted to use this code only as a part of
34 * the xv distribution by John Bradley.
35 */
36
37
38 #include "xv.h"
39
40 static long filesize;
41
42 /* static int readID PARM((FILE *, char *)); DOES NOT EXIST */
43 static int iffError PARM((const char *, const char *));
44 static void decomprle PARM((byte *, byte *, long, long));
45 static unsigned int iff_getword PARM((byte *));
46 static unsigned long iff_getlong PARM((byte *));
47
48
49 static const char *bname;
50
51
52 /* Define internal ILBM types */
53 #define ILBM_NORMAL 0
54 #define ILBM_EHB 1
55 #define ILBM_HAM 2
56 #define ILBM_HAM8 3
57 #define ILBM_24BIT 4
58
59
60
61 /*******************************************/
LoadIFF(fname,pinfo)62 int LoadIFF(fname, pinfo)
63 char *fname;
64 PICINFO *pinfo;
65 /*******************************************/
66 {
67 /* returns '1' on success */
68
69 register byte bitmsk, rval, gval, bval;
70 register long col, colbit;
71 FILE *fp;
72 int rv;
73 int BMHDok, CMAPok, CAMGok;
74 int bmhd_width, bmhd_height, bmhd_bitplanes, bmhd_transcol;
75 int i, j, k, lineskip, colors, fmt;
76 int npixels = 0; /* needs to be initialized _outside_ while-loop */
77 byte bmhd_masking, bmhd_compression;
78 long chunkLen, camg_viewmode;
79 byte *databuf, *dataptr, *cmapptr, *picptr, *pic, *bodyptr;
80 byte *workptr, *workptr2, *workptr3, *decomp_mem;
81
82 BMHDok = CAMGok = bmhd_width = bmhd_height = bmhd_bitplanes = colors = 0;
83 bmhd_compression = 0;
84 camg_viewmode = 0;
85
86 bname = BaseName(fname);
87 databuf = picptr = decomp_mem = NULL;
88
89 pinfo->pic = (byte *) NULL;
90 pinfo->comment = (char *) NULL;
91
92 /* open the file */
93 fp = xv_fopen(fname,"r");
94 if (!fp) return (iffError(bname, "cannot open file"));
95
96 /* compute file length */
97 fseek(fp, 0L, 2);
98 filesize = ftell(fp);
99 fseek(fp, 0L, 0);
100
101 /* allocate memory for complete file */
102 if((databuf = (byte *) malloc((size_t) filesize)) == NULL) {
103 fclose(fp);
104 FatalError("xviff: cannot malloc file buffer");
105 }
106
107 fread(databuf, (size_t) filesize, (size_t) 1, fp);
108 fclose(fp);
109
110
111 /* initialize work pointer. used to trace the buffer for IFF chunks */
112 dataptr = databuf;
113
114
115 /* check if we really got an IFF file */
116 if(strncmp((char *) dataptr, "FORM", (size_t) 4) != 0) {
117 free(databuf);
118 return(iffError(bname, "not an IFF file"));
119 }
120
121
122 dataptr = dataptr + 8; /* skip ID and length of FORM */
123
124 /* check if the IFF file is an ILBM (picture) file */
125 if(strncmp((char *) dataptr, "ILBM", (size_t) 4) != 0) {
126 free(databuf);
127 return(iffError(bname, "not an ILBM file"));
128 }
129
130 if (DEBUG) fprintf(stderr,"IFF ILBM file recognized\n");
131
132 dataptr = dataptr + 4; /* skip ID */
133
134 /* initialize return value to -1. used to indicate when we are finished with
135 decoding the picture (happens when BODY chunk was found */
136 rv = -1;
137
138 /* main decoding loop. searches IFF chunks and handles them. terminates when
139 BODY chunk was found or dataptr ran over end of file */
140
141 while ((rv<0) && (dataptr < (databuf + filesize))) {
142 chunkLen = (iff_getlong(dataptr + 4) + 1) & 0xfffffffe; /* make even */
143
144 if (strncmp((char *) dataptr, "BMHD", (size_t) 4)==0) { /* BMHD chunk? */
145 bmhd_width = iff_getword(dataptr + 8); /* width of picture */
146 bmhd_height = iff_getword(dataptr + 8 + 2); /* height of picture */
147 bmhd_bitplanes = *(dataptr + 8 + 8); /* # of bitplanes */
148 bmhd_masking = *(dataptr + 8 + 9);
149 bmhd_compression = *(dataptr + 8 + 10); /* get compression */
150 bmhd_transcol = iff_getword(dataptr + 8 + 12);
151 BMHDok = 1; /* got BMHD */
152 dataptr += 8 + chunkLen; /* to next chunk */
153
154 npixels = bmhd_width * bmhd_height; /* 65535*65535 max */
155 if (bmhd_width <= 0 || bmhd_height <= 0
156 || npixels/bmhd_width != bmhd_height)
157 return (iffError(bname, "xviff: image dimensions out of range"));
158 }
159
160
161 else if (strncmp((char *) dataptr, "CMAP", (size_t) 4)==0) { /* CMAP ? */
162 cmapptr = dataptr + 8;
163 colors = chunkLen / 3; /* calc no of colors */
164
165 /* copy colors to color map */
166 for (i=0; i < colors; i++) {
167 pinfo->r[i] = *cmapptr++;
168 pinfo->g[i] = *cmapptr++;
169 pinfo->b[i] = *cmapptr++;
170 }
171
172 CMAPok = 1; /* got CMAP */
173 dataptr += 8 + chunkLen; /* to next chunk */
174 }
175
176
177 else if (strncmp((char *) dataptr, "CAMG", (size_t) 4)==0) { /* CAMG ? */
178 camg_viewmode = iff_getlong(dataptr + 8); /* get viewmodes */
179 CAMGok = 1; /* got CAMG */
180 dataptr += 8 + chunkLen; /* to next chunk */
181 }
182
183
184 else if (strncmp((char *) dataptr, "BODY", (size_t) 4)==0) { /* BODY ? */
185 int byte_width = (((bmhd_width + 15) >> 4) << 1); /* 8192 max */
186
187 bodyptr = dataptr + 8; /* -> BODY data */
188
189 if (BMHDok) { /* BMHD found? */
190 /* if BODY is compressed, allocate buffer for decrunched BODY and
191 decompress it (run length encoding) */
192
193 if (bmhd_compression == 1) {
194 /* calc size of decrunch buffer - (size of the actual picture
195 decompressed in interleaved Amiga bitplane format) */
196
197 int bytes_per_bitplane = byte_width * bmhd_height; /* 536862720 max */
198 long decomp_bufsize = bytes_per_bitplane * bmhd_bitplanes;
199
200 if (byte_width <= 0 || bmhd_height <= 0 ||
201 bytes_per_bitplane/byte_width != bmhd_height ||
202 decomp_bufsize/bytes_per_bitplane != bmhd_bitplanes)
203 {
204 return (iffError(bname, "xviff: image dimensions out of range"));
205 }
206
207 if ((decomp_mem = (byte *)malloc((size_t) decomp_bufsize)) != NULL) {
208 decomprle(dataptr + 8, decomp_mem, chunkLen, decomp_bufsize);
209 bodyptr = decomp_mem; /* -> uncompressed BODY */
210 free(databuf); /* free old data buffer */
211 databuf = NULL;
212 }
213 else {
214 free(databuf);
215 FatalError("xviff: cannot malloc() decrunch buffer");
216 }
217 }
218
219
220 /* the following determines the type of the ILBM file.
221 it's either NORMAL, EHB, HAM, HAM8 or 24BIT */
222
223 fmt = ILBM_NORMAL; /* assume normal ILBM */
224 /* FIXME: does ILBM_NORMAL really support up to 255 bitplanes? */
225
226 if (bmhd_bitplanes == 24) fmt = ILBM_24BIT;
227 else if (bmhd_bitplanes == 8) {
228 if (CAMGok && (camg_viewmode & 0x800)) fmt = ILBM_HAM8;
229 }
230
231 else if ((bmhd_bitplanes > 5) && CAMGok) {
232 if (camg_viewmode & 0x80) fmt = ILBM_EHB;
233 else if (camg_viewmode & 0x800) fmt = ILBM_HAM;
234 }
235
236
237 if (DEBUG) {
238 fprintf(stderr, "LoadIFF: %s %dx%d, planes=%d (%d cols), comp=%d\n",
239 (fmt==ILBM_NORMAL) ? "Normal ILBM" :
240 (fmt==ILBM_HAM) ? "HAM ILBM" :
241 (fmt==ILBM_HAM8) ? "HAM8 ILBM" :
242 (fmt==ILBM_EHB) ? "EHB ILBM" :
243 (fmt==ILBM_24BIT) ? "24BIT ILBM" : "unknown ILBM",
244 bmhd_width, bmhd_height, bmhd_bitplanes,
245 1<<bmhd_bitplanes, bmhd_compression);
246 }
247
248
249 if ((fmt==ILBM_NORMAL) || (fmt==ILBM_EHB) || (fmt==ILBM_HAM)) {
250 if (DEBUG) fprintf(stderr,"Converting CMAP from normal ILBM CMAP\n");
251
252 switch(fmt) {
253 case ILBM_NORMAL: colors = 1 << bmhd_bitplanes; break;
254 case ILBM_EHB: colors = 32; break;
255 case ILBM_HAM: colors = 16; break;
256 }
257
258 for (i=0; i < colors; i++) {
259 pinfo->r[i] = (pinfo->r[i] >> 4) * 17;
260 pinfo->g[i] = (pinfo->g[i] >> 4) * 17;
261 pinfo->b[i] = (pinfo->b[i] >> 4) * 17;
262 }
263 }
264
265
266 if ((fmt == ILBM_HAM) || (fmt == ILBM_HAM8) || (fmt == ILBM_24BIT)) {
267 int bufsize = 3 * npixels;
268
269 if (bufsize/3 != npixels) {
270 if (databuf) free(databuf);
271 if (decomp_mem) free(decomp_mem);
272 return (iffError(bname, "xviff: image dimensions out of range"));
273 }
274 if ((picptr=(byte *) malloc((size_t) bufsize)) == NULL) {
275 if (databuf) free(databuf);
276 if (decomp_mem) free(decomp_mem);
277 return (iffError(bname, "xviff: no memory for decoded picture"));
278 }
279
280 else {
281 pic = picptr;
282 workptr = bodyptr;
283 lineskip = byte_width;
284
285 for (i=0; i<bmhd_height; i++) {
286 bitmsk = 0x80;
287 workptr2 = workptr;
288
289 /* at start of each line, init RGB values to background */
290 rval = pinfo->r[0];
291 gval = pinfo->g[0];
292 bval = pinfo->b[0];
293
294 for (j=0; j<bmhd_width; j++) {
295 col = 0;
296 colbit = 1;
297 workptr3 = workptr2;
298 for (k=0; k<bmhd_bitplanes; k++) {
299 if (*workptr3 & bitmsk) col += colbit;
300 workptr3 += lineskip;
301 colbit <<= 1;
302 }
303
304 if (fmt==ILBM_HAM) {
305 switch (col & 0x30) {
306 case 0x00: rval = pinfo->r[col & 0x0f];
307 gval = pinfo->g[col & 0x0f];
308 bval = pinfo->b[col & 0x0f];
309 break;
310
311 case 0x10: bval = (col & 0x0f) * 17;
312 break;
313
314 case 0x20: rval = (col & 0x0f) * 17;
315 break;
316
317 case 0x30: gval = (col & 0x0f) * 17;
318 }
319 }
320
321 else if (fmt == ILBM_HAM8) {
322 switch(col & 0xc0) {
323 case 0x00: rval = pinfo->r[col & 0x3f];
324 gval = pinfo->g[col & 0x3f];
325 bval = pinfo->b[col & 0x3f];
326 break;
327
328 case 0x40: bval = (bval & 3) | ((col & 0x3f) << 2);
329 break;
330
331 case 0x80: rval = (rval & 3) | ((col & 0x3f) << 2);
332 break;
333
334 case 0xc0: gval = (rval & 3) | ((col & 0x3f) << 2);
335 }
336 }
337
338 else {
339 rval = col & 0xff;
340 gval = (col >> 8) & 0xff;
341 bval = (col >> 16) & 0xff;
342 }
343
344 *pic++ = rval;
345 *pic++ = gval;
346 *pic++ = bval;
347
348 bitmsk = bitmsk >> 1;
349 if (bitmsk == 0) {
350 bitmsk = 0x80;
351 workptr2++;
352 }
353 }
354 workptr += lineskip * bmhd_bitplanes;
355 }
356
357 pinfo->type = PIC24;
358 }
359 } /* HAM, HAM8, or 24BIT */
360
361
362 else if ((fmt == ILBM_NORMAL) || (fmt == ILBM_EHB)) {
363 /* if bmhd_width and bmhd_height are OK (checked in BMHD block
364 * above; guaranteed by BMHDok), then npixels is OK, too */
365 if ((picptr = (byte *) malloc((size_t) npixels)) == NULL) {
366 if (databuf) free(databuf);
367 if (decomp_mem) free(decomp_mem);
368 return (iffError(bname, "xviff: no memory for decoded picture"));
369 }
370
371 else if (fmt == ILBM_EHB) {
372 if (DEBUG) fprintf(stderr,"Doubling CMAP for EHB mode\n");
373
374 for (i=0; i<32; i++) {
375 pinfo->r[i + colors] = pinfo->r[i] >> 1;
376 pinfo->g[i + colors] = pinfo->g[i] >> 1;
377 pinfo->b[i + colors] = pinfo->b[i] >> 1;
378 }
379 }
380
381 pic = picptr; /* ptr to chunky buffer */
382 workptr = bodyptr; /* ptr to uncmp'd pic, planar format */
383 lineskip = byte_width;
384
385 for (i=0; i<bmhd_height; i++) {
386 bitmsk = 0x80; /* left most bit (mask) */
387 workptr2 = workptr; /* work ptr to source */
388 for (j=0; j<bmhd_width; j++) {
389 col = 0;
390 colbit = 1;
391 workptr3 = workptr2; /* ptr to byte in 1st pln */
392
393 for (k=0; k<bmhd_bitplanes; k++) {
394 if (*workptr3 & bitmsk) /* if bit set in this pln */
395 col = col + colbit; /* add bit to chunky byte */
396 workptr3 += lineskip; /* go to next line */
397 colbit <<= 1; /* shift color bit */
398 }
399
400 *pic++ = col; /* write to chunky buffer */
401 bitmsk = bitmsk >> 1; /* shift mask to next bit */
402 if (bitmsk == 0) { /* if mask is zero */
403 bitmsk = 0x80; /* reset mask */
404 workptr2++; /* mv ptr to next byte */
405 }
406 } /* for j ... */
407
408 workptr += lineskip * bmhd_bitplanes; /* to next line */
409 } /* for i ... */
410
411 pinfo->type = PIC8;
412 } /* if NORMAL or EHB */
413
414
415 /* fill up PICINFO */
416
417 pinfo->pic = picptr;
418 pinfo->w = bmhd_width;
419 pinfo->h = bmhd_height;
420 pinfo->normw = pinfo->w; pinfo->normh = pinfo->h;
421 pinfo->colType = F_FULLCOLOR;
422 pinfo->frmType = -1;
423
424 sprintf(pinfo->fullInfo, "%s (%ld bytes)",
425 (fmt==ILBM_NORMAL) ? "IFF ILBM" :
426 (fmt==ILBM_HAM) ? "HAM ILBM" :
427 (fmt==ILBM_HAM8) ? "HAM8 ILBM" :
428 (fmt==ILBM_EHB) ? "EHB ILBM" :
429 (fmt==ILBM_24BIT) ? "24BIT ILBM" : "unknown ILBM",
430 filesize);
431
432 sprintf(pinfo->shrtInfo, "%dx%d ILBM.", bmhd_width, bmhd_height);
433
434 rv = 1;
435
436 } /* if BMHDok */
437
438 else rv = 0; /* didn't get BMHD header */
439
440 } /* "BODY" chunk */
441
442 else {
443 if (DEBUG)
444 fprintf(stderr,"Skipping unknown chunk '%c%c%c%c'\n",
445 *dataptr, *(dataptr+1), *(dataptr+2), *(dataptr+3));
446
447 dataptr = dataptr + 8 + chunkLen; /* skip unknown chunk */
448 }
449 }
450
451
452 if (decomp_mem) free(decomp_mem);
453 if (databuf) free(databuf);
454
455 if (rv != 1) free(picptr);
456
457 return rv;
458 }
459
460
461
462
463
464 /**************************************************************************
465 void decomprle(source, destination, source length, buffer size)
466
467 Decompress run-length encoded data from source to destination. Terminates
468 when source is decoded completely or destination buffer is full.
469
470 The decruncher is as optimized as I could make it, without risking
471 safety in case of corrupt BODY chunks.
472 ***************************************************************************/
473
474
475 /*******************************************/
decomprle(sptr,dptr,slen,dlen)476 static void decomprle(sptr, dptr, slen, dlen)
477 byte *sptr, *dptr;
478 register long slen, dlen;
479 {
480 register byte codeByte, dataByte;
481
482 while ((slen > 0) && (dlen > 0)) {
483
484 /* read control byte */
485 codeByte = *sptr++;
486
487 if (codeByte < 0x80) {
488 codeByte++;
489 if ((slen > (long) codeByte) && (dlen >= (long) codeByte)) {
490 slen -= codeByte + 1;
491 dlen -= codeByte;
492 while (codeByte > 0) {
493 *dptr++ = *sptr++;
494 codeByte--;
495 }
496 }
497 else slen = 0;
498 }
499
500 else if (codeByte > 0x80) {
501 codeByte = 0x81 - (codeByte & 0x7f);
502 if ((slen > (long) 0) && (dlen >= (long) codeByte)) {
503 dataByte = *sptr++;
504 slen -= 2;
505 dlen -= codeByte;
506 while (codeByte > 0) {
507 *dptr++ = dataByte;
508 codeByte--;
509 }
510 }
511 else slen = 0;
512 }
513 }
514 }
515
516
517
518 /*******************************************/
iff_getword(ptr)519 static unsigned int iff_getword(ptr)
520 byte *ptr;
521 {
522 register unsigned int v;
523
524 v = *ptr++;
525 v = (v << 8) + *ptr;
526
527 return v;
528 }
529
530
531 /*******************************************/
iff_getlong(ptr)532 static unsigned long iff_getlong(ptr)
533 byte *ptr;
534 {
535 register unsigned long l;
536
537 l = *ptr++;
538 l = (l << 8) + *ptr++;
539 l = (l << 8) + *ptr++;
540 l = (l << 8) + *ptr;
541
542 return l;
543 }
544
545
546 /*******************************************/
iffError(fname,st)547 static int iffError(fname, st)
548 const char *fname, *st;
549 {
550 SetISTR(ISTR_WARNING,"%s: %s", fname, st);
551 return 0;
552 }
553