iccprofile: Refactoring
[deark.git] / modules / ilbm.c
blob8754033316a4e304d000409753b38a96e5a2321c
1 // This file is part of Deark.
2 // Copyright (C) 2016-2020 Jason Summers
3 // See the file COPYING for terms of use.
5 // IFF-ILBM and related image formats
6 // IFF-ANIM animation format
8 #include <deark-config.h>
9 #include <deark-private.h>
10 #include <deark-fmtutil.h>
11 DE_DECLARE_MODULE(de_module_ilbm);
12 DE_DECLARE_MODULE(de_module_anim);
14 #define ANIM_MAX_FRAMES 10000
16 #define CODE_8SVX 0x38535658U
17 #define CODE_ABIT 0x41424954U
18 #define CODE_ACBM 0x4143424dU
19 #define CODE_ANHD 0x414e4844U
20 #define CODE_ANIM 0x414e494dU
21 #define CODE_ANSQ 0x414e5351U
22 #define CODE_BEAM 0x4245414dU
23 #define CODE_BMHD 0x424d4844U
24 #define CODE_BODY 0x424f4459U
25 #define CODE_CAMG 0x43414d47U
26 #define CODE_CCRT 0x43435254U
27 #define CODE_CLUT 0x434c5554U
28 #define CODE_CMAP 0x434d4150U
29 #define CODE_CRNG 0x43524e47U
30 #define CODE_CTBL 0x4354424cU
31 #define CODE_DLTA 0x444c5441U
32 #define CODE_DPAN 0x4450414eU
33 #define CODE_DPI 0x44504920U
34 #define CODE_DRNG 0x44524e47U
35 #define CODE_FORM 0x464f524dU
36 #define CODE_GRAB 0x47524142U
37 #define CODE_ILBM 0x494c424dU
38 #define CODE_PBM 0x50424d20U
39 #define CODE_PCHG 0x50434847U
40 #define CODE_SBDY 0x53424459U
41 #define CODE_SHAM 0x5348414dU
42 #define CODE_TINY 0x54494e59U
43 #define CODE_VDAT 0x56444154U
45 #define ANIM_OP_XOR 1
47 #define MASKINGTYPE_NONE 0
48 #define MASKINGTYPE_1BITMASK 1
49 #define MASKINGTYPE_COLORKEY 2
50 #define MASKINGTYPE_LASSO 3
52 enum colortype_enum {
53 COLORTYPE_DEFAULT = 0,
54 COLORTYPE_RGB24
57 // Parameters for a single image, derived from a combination of the global
58 // state and the image context.
59 struct imgbody_info {
60 i64 width, height;
61 i64 planes_fg;
62 i64 planes_total; // Different from planes_fg if MASKINGTYPE_1BITMASK.
63 u8 compression;
64 u8 masking_code;
65 u8 use_colorkey_transparency;
66 UI transparent_color;
67 i64 x_aspect, y_aspect;
68 i64 bits_per_row_per_plane;
69 i64 bytes_per_row_per_plane;
70 i64 frame_buffer_rowspan;
71 i64 frame_buffer_size;
72 enum colortype_enum colortype;
73 int is_thumb;
74 int is_pbm; // frame buffer is PBM pixel format
77 struct frame_ctx {
78 u32 formtype;
79 int frame_idx;
80 int done_flag; // Have we processed the image (BODY/DLTA/etc. chunk)?
81 int change_flag; // Is this frame different from the previous one?
82 u8 op;
83 UI interleave;
84 UI bits;
85 dbuf *frame_buffer;
88 typedef struct localctx_struct {
89 int is_anim;
90 u32 formtype;
91 i64 main_chunk_endpos;
92 int FORM_level; // nesting level of the frames' FORM chunks
93 int errflag;
94 int num_frames_started;
95 int num_frames_finished;
96 int debug_frame_buffer;
97 u8 opt_notrans;
98 u8 opt_fixpal;
99 u8 opt_allowsham;
100 u8 opt_anim_includedups;
101 u8 found_bmhd;
102 u8 found_cmap;
103 u8 cmap_changed_flag;
104 u8 bmhd_changed_flag;
105 u8 has_camg;
106 u8 ham_flag; // "hold and modify"
107 u8 is_ham6;
108 u8 is_ham8;
109 u8 ehb_flag; // "extra halfbrite"
110 u8 uses_color_cycling;
111 u8 color_cycling_warned;
112 u8 is_sham;
113 u8 is_ctbl;
114 u8 is_pchg;
115 u8 is_beam;
116 u8 found_clut;
117 u8 found_rast;
118 u8 found_audio;
119 u8 uses_anim4_5_xor_mode;
120 u8 uses_anim_long_data;
121 u8 multipalette_warned;
122 u8 extra_content_warned;
123 u8 is_hame;
124 u8 is_dctv;
125 UI camg_mode;
127 i64 width, height;
128 i64 planes_raw;
129 u8 compression;
130 u8 masking_code;
131 UI transparent_color;
132 i64 x_aspect, y_aspect;
133 i64 x_dpi, y_dpi;
134 i64 thumb_width, thumb_height;
135 u8 has_hotspot;
136 int hotspot_x, hotspot_y;
138 struct frame_ctx *frctx; // Non-NULL means we're inside a frame
139 struct frame_ctx *oldfrctx[2];
140 i64 pal_ncolors; // Number of colors we read from the file
141 int pal_is_grayscale;
142 u32 pal_raw[256]; // Palette as read from the file
143 u32 pal[256]; // Palette that we will use
144 u8 delta_ops_used[256];
145 } lctx;
147 static const char *anim_get_op_name(u8 op)
149 const char *name = NULL;
151 switch(op) {
152 case 0: name="direct"; break;
153 case ANIM_OP_XOR: name="XOR"; break;
154 case 2: name="long delta"; break;
155 case 3: name="short delta"; break;
156 case 4: name="short/long delta"; break;
157 case 5: name="byte vert. delta"; break;
158 case 7: name="short/long vert. delta, separated"; break;
159 case 8: name="short/long vert. delta, contiguous"; break;
160 case 74: name="ANIM-J (Eric Graham)"; break;
161 case 100: name="ANIM32"; break;
162 case 101: name="ANIM16"; break;
163 case 108: name="ANIM-l (Eric Graham)"; break;
165 return name?name:"?";
168 static const char *get_maskingtype_name(u8 n)
170 const char *name = NULL;
172 switch(n) {
173 case MASKINGTYPE_NONE: name = "no transparency"; break;
174 case MASKINGTYPE_1BITMASK: name = "1-bit transparency mask"; break;
175 case MASKINGTYPE_COLORKEY: name = "color-key transparency"; break;
176 case MASKINGTYPE_LASSO: name = "lasso"; break;
178 return name?name:"?";
181 static const char *get_cmprtype_name(lctx *d, u8 n)
183 const char *name = NULL;
185 if(d->formtype==CODE_ACBM) return "n/a";
187 switch(n) {
188 case 0: name = "uncompressed"; break;
189 case 1: name = "PackBits"; break;
190 case 2: name = "VDAT"; break;
192 return name?name:"?";
195 static void on_color_cycling_enabled(deark *c, lctx *d)
197 d->uses_color_cycling = 1;
198 if(d->color_cycling_warned) return;
199 de_warn(c, "This image uses color cycling animation, which is not supported.");
200 d->color_cycling_warned = 1;
203 static void on_multipalette_enabled(deark *c, lctx *d)
205 if(!d->opt_allowsham) {
206 d->errflag = 1;
208 if(d->multipalette_warned) return;
209 if(d->opt_allowsham) {
210 de_warn(c, "This is a multi-palette image, which is not correctly supported.");
212 else {
213 de_err(c, "Multi-palette ILBM images are not supported. "
214 "(\"-opt ilbm:allowsham\" to decode anyway)");
218 static struct frame_ctx *create_frame(deark *c, lctx *d)
220 struct frame_ctx *frctx;
221 frctx = de_malloc(c, sizeof(struct frame_ctx));
222 return frctx;
225 static void destroy_frame(deark *c, lctx *d, struct frame_ctx *frctx)
227 if(!frctx) return;
228 dbuf_close(frctx->frame_buffer);
229 de_free(c, frctx);
232 static void do_cmap(deark *c, lctx *d, i64 pos, i64 len)
234 i64 ncolors;
236 d->found_cmap = 1;
237 d->cmap_changed_flag = 1;
238 ncolors = len/3;
239 de_dbg(c, "number of palette colors: %d", (int)ncolors);
240 if(ncolors>256) ncolors=256;
242 de_read_palette_rgb(c->infile, pos, ncolors, 3, d->pal_raw, 256, 0);
243 if(ncolors > d->pal_ncolors) {
244 d->pal_ncolors = ncolors;
248 static int do_bmhd(deark *c, lctx *d, i64 pos1, i64 len)
250 i64 pos = pos1;
251 int retval = 0;
252 const char *masking_name;
254 d->bmhd_changed_flag = 1;
255 if(len<20) {
256 de_err(c, "Bad BMHD chunk");
257 goto done;
260 d->found_bmhd = 1;
261 d->width = de_getu16be_p(&pos);
262 d->height = de_getu16be_p(&pos);
263 de_dbg_dimensions(c, d->width, d->height);
264 pos += 4;
266 d->planes_raw = (i64)de_getbyte_p(&pos);
267 de_dbg(c, "planes: %d", (int)d->planes_raw);
268 d->masking_code = de_getbyte_p(&pos);
269 masking_name = get_maskingtype_name(d->masking_code);
271 d->compression = de_getbyte_p(&pos);
272 de_dbg(c, "compression: %d (%s)", (int)d->compression, get_cmprtype_name(d, d->compression));
274 pos++;
275 d->transparent_color = (UI)de_getu16be_p(&pos);
276 de_dbg(c, "masking: %d (%s)", (int)d->masking_code, masking_name);
277 if(d->masking_code==MASKINGTYPE_COLORKEY || d->masking_code==MASKINGTYPE_LASSO) {
278 de_dbg_indent(c, 1);
279 de_dbg(c, "color key: %u", d->transparent_color);
280 de_dbg_indent(c, -1);
283 d->x_aspect = (i64)de_getbyte_p(&pos);
284 d->y_aspect = (i64)de_getbyte_p(&pos);
285 de_dbg(c, "aspect ratio: %d, %d", (int)d->x_aspect, (int)d->y_aspect);
287 retval = 1;
288 done:
289 return retval;
292 static i64 delta3_calc_elem_pos(i64 elemnum, i64 elemsize, i64 elems_per_row, i64 plane_offset,
293 i64 frame_buffer_rowspan)
295 i64 row, col;
297 row = elemnum / elems_per_row;
298 col = elemnum % elems_per_row;
299 return row * frame_buffer_rowspan + plane_offset + elemsize * col;
302 // Note - It should be easy to modify this to work for DLTA#2 compression as well
303 // (need a sample file).
304 static void decompress_plane_delta_op3(deark *c, lctx *d, struct imgbody_info *ibi,
305 struct frame_ctx *frctx, i64 plane, i64 pos1, i64 maxlen)
307 i64 endpos = pos1+maxlen;
308 i64 pos = pos1;
309 i64 elemnum = 0;
310 i64 elemsize = 2;
311 i64 elems_per_row;
312 i64 elems_total;
313 i64 plane_offset;
314 i64 dstpos;
315 u8 elembuf[2];
317 de_dbg2(c, "delta3 plane at %"I64_FMT", maxlen=%"I64_FMT, pos1, maxlen);
319 elems_per_row = (ibi->bytes_per_row_per_plane + (elemsize-1) ) / elemsize;
320 if(elems_per_row<1) goto done;
321 elems_total = elems_per_row * ibi->height;
322 plane_offset = plane * ibi->bytes_per_row_per_plane;
324 while(1) {
325 i64 code;
326 i64 offset;
328 if(elemnum >= elems_total) break;
329 if(pos+2 >= endpos) goto done;
330 code = de_geti16be_p(&pos);
332 if(code == -1) { // Stop.
333 break;
335 else if(code >= 0) { // Skip some number of elements, then write one element.
336 frctx->change_flag = 1;
337 offset = code;
338 elemnum += offset;
339 de_read(elembuf, pos, elemsize);
340 pos += elemsize;
341 dstpos = delta3_calc_elem_pos(elemnum, elemsize, elems_per_row, plane_offset,
342 ibi->frame_buffer_rowspan);
343 dbuf_write_at(frctx->frame_buffer, dstpos, elembuf, elemsize);
345 else { // Skip some number of elements, then write multiple elements.
346 i64 count;
347 i64 k;
349 offset = -(code+2);
350 elemnum += offset;
351 count = de_getu16be_p(&pos);
352 if(count>0) {
353 frctx->change_flag = 1;
355 for(k=0; k<count; k++) {
356 de_read(elembuf, pos, elemsize);
357 pos += elemsize;
358 elemnum++;
359 dstpos = delta3_calc_elem_pos(elemnum, elemsize, elems_per_row, plane_offset,
360 ibi->frame_buffer_rowspan);
361 dbuf_write_at(frctx->frame_buffer, dstpos, elembuf, elemsize);
366 done:
370 // "Short Delta" mode
371 // Decompress into frctx->frame_buffer
372 static void decompress_delta_op3(deark *c, lctx *d, struct imgbody_info *ibi,
373 struct frame_ctx *frctx, i64 pos1, i64 len)
375 i64 i;
376 i64 pos = pos1;
377 i64 planedata_offs[8];
379 de_dbg(c, "[delta3 data]");
381 for(i=0; i<8; i++) {
382 planedata_offs[i] = de_getu32be_p(&pos);
383 if(i<ibi->planes_total) {
384 de_dbg2(c, "plane[%d] offs: %"I64_FMT, (int)i, planedata_offs[i]);
385 if(planedata_offs[i]>0) {
386 decompress_plane_delta_op3(c, d, ibi, frctx, i,
387 pos1+planedata_offs[i], len-planedata_offs[i]);
393 static i64 get_elem_as_int_p(dbuf *f, i64 *ppos, i64 elem_size)
395 if(elem_size==1) {
396 return (i64)dbuf_getbyte_p(f, ppos);
398 if(elem_size==2) {
399 return dbuf_getu16be_p(f, ppos);
401 return dbuf_getu32be_p(f, ppos);
404 // This routine decompresses most frame types used in DLTA#5, #7, and #8.
405 // For #7, the codestream and datastream are stored separately, and have different
406 // element sizes.
407 // For #5 and #8, datapos1 is not used.
408 static void decompress_plane_vdelta(deark *c, lctx *d, struct imgbody_info *ibi,
409 struct frame_ctx *frctx, i64 plane_idx,
410 dbuf *inf, i64 codepos1, i64 datapos1, i64 endpos,
411 i64 code_size, i64 dataelem_size, int separate_data_stream, u8 xor_mode)
413 i64 pos = codepos1; // If !separate_data_stream, this is for code and data
414 i64 datapos = datapos1;
415 i64 num_columns;
416 i64 col;
417 i64 dststride = ibi->frame_buffer_rowspan;
418 UI unc_threshold;
419 int baddata_flag = 0;
421 if(separate_data_stream) {
422 de_dbg2(c, "vdelta(%d,%d) plane %d at (%"I64_FMT",%"I64_FMT")", (int)code_size,
423 (int)dataelem_size, (int)plane_idx, codepos1, datapos1);
425 else {
426 de_dbg2(c, "vdelta(%d) plane at (%"I64_FMT")", (int)code_size, codepos1);
428 if(code_size!=1 && code_size!=2 && code_size!=4) goto done;
429 if(dataelem_size!=1 && dataelem_size!=2 && dataelem_size!=4) goto done;
430 if(xor_mode && dataelem_size!=1) goto done;
432 if(code_size==1) {
433 unc_threshold = 0x80;
435 else if(code_size==2) {
436 unc_threshold = 0x8000;
438 else {
439 unc_threshold = 0x80000000U;
442 if(dataelem_size==1) {
443 num_columns = (ibi->width+7)/8;
445 else if(dataelem_size==2) {
446 num_columns = (ibi->width+15)/16;
448 else {
449 num_columns = (ibi->width+31)/32;
452 for(col=0; col<num_columns; col++) {
453 i64 opcount;
454 i64 opidx;
455 i64 elem_bytes_to_write;
456 i64 ypos = 0;
457 i64 col_start_dstpos;
459 if(pos>=endpos) {
460 baddata_flag = 1;
461 goto done;
464 // Defend against writing beyond the right edge of this plane
465 if((dataelem_size==4) && (col+1 == num_columns) && (ibi->bytes_per_row_per_plane%4)) {
466 elem_bytes_to_write = 2;
468 else {
469 elem_bytes_to_write = dataelem_size;
472 col_start_dstpos = plane_idx * ibi->bytes_per_row_per_plane + dataelem_size*col;
474 opcount = get_elem_as_int_p(inf, &pos, code_size);
475 if(c->debug_level>=3) {
476 de_dbg3(c, "col %d op count: %"I64_FMT, (int)col, opcount);
479 for(opidx=0; opidx<opcount; opidx++) {
480 i64 dstpos;
481 i64 count;
482 i64 k;
483 UI op;
484 u8 valbuf[4];
486 if(pos>=endpos) {
487 baddata_flag = 1;
488 goto done;
490 op = (UI)get_elem_as_int_p(inf, &pos, code_size);
492 if(op==0) { // RLE
493 count = get_elem_as_int_p(inf, &pos, code_size);
494 if(ypos+count > ibi->height) {
495 baddata_flag = 1;
496 goto done;
499 if(count>0) {
500 frctx->change_flag = 1;
503 if(separate_data_stream) {
504 if(datapos>=endpos) {
505 baddata_flag = 1;
506 goto done;
508 dbuf_read(inf, valbuf, datapos, dataelem_size);
509 datapos += dataelem_size;
511 else {
512 dbuf_read(inf, valbuf, pos, dataelem_size);
513 pos += dataelem_size;
516 for(k=0; k<count; k++) {
517 dstpos = col_start_dstpos + ypos*dststride;
518 if(xor_mode) {
519 u8 val;
521 val = valbuf[0] ^ dbuf_getbyte(frctx->frame_buffer, dstpos);
522 dbuf_writebyte_at(frctx->frame_buffer, dstpos, val);
524 else {
525 dbuf_write_at(frctx->frame_buffer, dstpos, valbuf, elem_bytes_to_write);
527 ypos++;
530 else if(op < unc_threshold) { // skip
531 ypos += (i64)op;
533 else { // uncompressed run
534 count = (i64)(op - unc_threshold);
535 if(ypos+count > ibi->height) {
536 baddata_flag = 1;
537 goto done;
540 if(count>0) {
541 frctx->change_flag = 1;
544 for(k=0; k<count; k++) {
545 if(separate_data_stream) {
546 if(datapos>=endpos) {
547 baddata_flag = 1;
548 goto done;
550 dbuf_read(inf, valbuf, datapos, dataelem_size);
551 datapos += dataelem_size;
553 else {
554 dbuf_read(inf, valbuf, pos, dataelem_size);
555 pos += dataelem_size;
558 dstpos = col_start_dstpos + ypos*dststride;
559 if(xor_mode) {
560 valbuf[0] ^= dbuf_getbyte(frctx->frame_buffer, dstpos);
562 dbuf_write_at(frctx->frame_buffer, dstpos, valbuf, elem_bytes_to_write);
563 ypos++;
569 done:
570 if(baddata_flag && !d->errflag) {
571 de_err(c, "Delta decompression failed");
572 d->errflag = 1;
576 // Decompress into frctx->frame_buffer
577 static void decompress_delta_op5(deark *c, lctx *d, struct imgbody_info *ibi,
578 struct frame_ctx *frctx, i64 pos1, i64 len)
580 i64 planedata_offs[16];
581 i64 pos = pos1;
582 int i;
583 int saved_indent_level;
584 u8 delta4_5_xor_mode = 0;
586 de_dbg_indent_save(c, &saved_indent_level);
587 if(!frctx->frame_buffer) goto done;
589 de_dbg(c, "[delta5 data]");
591 // Note that we ignore the 0x8 bit ("RLC - run length coded").
592 // I don't know what this option is for. *All* ANIM4/5 frames use run length
593 // coding, but they almost never have have this bit set.
594 // The rare files that do set this bit don't seem to be any different from
595 // those that don't.
596 if((frctx->bits & 0xfffffff5U) != 0) {
597 de_err(c, "Unsupported ANHD options");
598 d->errflag = 1;
599 goto done;
602 if(frctx->bits & 0x2) {
603 delta4_5_xor_mode = 1;
606 for(i=0; i<16; i++) {
607 if(d->errflag) goto done;
608 planedata_offs[i] = de_getu32be_p(&pos);
609 if(i<ibi->planes_total) {
610 de_dbg2(c, "plane[%d] offs: %"I64_FMT, i, planedata_offs[i]);
611 if(planedata_offs[i]>0) {
612 decompress_plane_vdelta(c, d, ibi, frctx, i, c->infile,
613 pos1+planedata_offs[i], 0, pos1+len, 1, 1,
614 0, delta4_5_xor_mode);
619 done:
620 de_dbg_indent_restore(c, saved_indent_level);
623 // Decompress into frctx->frame_buffer
624 static void decompress_delta_op7(deark *c, lctx *d, struct imgbody_info *ibi,
625 struct frame_ctx *frctx, i64 pos1, i64 len)
627 i64 opcodelist_offs[8];
628 i64 datalist_offs[8];
629 i64 infpos;
630 int i;
631 int saved_indent_level;
632 i64 dataelem_size;
633 dbuf *inf = NULL;
635 de_dbg_indent_save(c, &saved_indent_level);
636 if(!frctx->frame_buffer) goto done;
638 de_dbg(c, "[delta7 data]");
640 if(frctx->bits & 0xfffffffeU) {
641 de_err(c, "Unsupported ANHD options");
642 d->errflag = 1;
643 goto done;
645 if(frctx->bits & 0x00000001) {
646 dataelem_size = 4;
648 else {
649 dataelem_size = 2;
652 // We'll have to interleave lots of short reads between two different segments of
653 // the file, with no way to know how big either segment is.
654 // I see no good way to process this DLTA#7 format, except by first reading the
655 // entire chunk into memory.
656 if(len > DE_MAX_SANE_OBJECT_SIZE) {
657 d->errflag = 1;
658 goto done;
660 inf = dbuf_create_membuf(c, len, 0);
661 dbuf_copy(c->infile, pos1, len, inf);
662 infpos = 0;
664 for(i=0; i<8; i++) {
665 opcodelist_offs[i] = dbuf_getu32be_p(inf, &infpos);
668 for(i=0; i<8; i++) {
669 datalist_offs[i] = dbuf_getu32be_p(inf, &infpos);
672 for(i=0; i<8; i++) {
673 if(d->errflag) goto done;
674 if(i<ibi->planes_total) {
675 de_dbg2(c, "opcode_list[%d] offs: %"I64_FMT, i, opcodelist_offs[i]);
676 de_dbg2(c, "data_list[%d] offs: %"I64_FMT, i, datalist_offs[i]);
677 if(opcodelist_offs[i]>0) {
678 decompress_plane_vdelta(c, d, ibi, frctx, i, inf,
679 opcodelist_offs[i], datalist_offs[i], len,
680 1, dataelem_size, 1, 0);
685 done:
686 dbuf_close(inf);
687 de_dbg_indent_restore(c, saved_indent_level);
690 static void decompress_delta_op8(deark *c, lctx *d, struct imgbody_info *ibi,
691 struct frame_ctx *frctx, i64 pos1, i64 len)
693 i64 planedata_offs[16];
694 i64 pos = pos1;
695 i64 elem_size;
696 int i;
697 int saved_indent_level;
699 de_dbg_indent_save(c, &saved_indent_level);
700 if(!frctx->frame_buffer) goto done;
702 de_dbg(c, "[delta8 data]");
704 if(frctx->bits & 0xfffffffeU) {
705 de_err(c, "Unsupported ANHD options");
706 d->errflag = 1;
707 goto done;
709 if(frctx->bits & 0x00000001) {
710 elem_size = 4;
712 else {
713 elem_size = 2;
716 for(i=0; i<16; i++) {
717 if(d->errflag) goto done;
718 planedata_offs[i] = de_getu32be_p(&pos);
719 if(i<ibi->planes_total) {
720 de_dbg2(c, "plane[%d] offs: %"I64_FMT, i, planedata_offs[i]);
721 if(planedata_offs[i]>0) {
722 decompress_plane_vdelta(c, d, ibi, frctx, i, c->infile,
723 pos1+planedata_offs[i], 0, pos1+len, elem_size, elem_size, 0, 0);
728 done:
729 de_dbg_indent_restore(c, saved_indent_level);
732 struct d74state {
733 struct imgbody_info *ibi;
734 struct frame_ctx *frctx;
735 i64 pos;
736 i64 endpos;
738 // Temporary use:
739 UI op;
740 i64 nblocks;
741 i64 nrows; // block height in rows
742 i64 nbytes; // block width in bytes per plane
745 static void do_delta74_blocks(deark *c, struct d74state *d74s)
747 i64 blkidx, rowidx, planeidx, byteidx;
748 i64 d74_bytes_per_row_per_plane;
750 // Reportedly, the 'offset' field assumes a potentially-different measuring
751 // system than one would expect.
752 d74_bytes_per_row_per_plane = (d74s->ibi->width + 7)/8;
754 for(blkidx=0; blkidx<d74s->nblocks; blkidx++) {
755 i64 offset;
756 i64 block_srcpos = d74s->pos;
757 i64 block_dstpos;
759 if(d74s->pos+2 >= d74s->endpos) goto done;
760 offset = de_getu16be_p(&d74s->pos);
762 block_dstpos = (offset / d74_bytes_per_row_per_plane) * d74s->ibi->frame_buffer_rowspan +
763 (offset % d74_bytes_per_row_per_plane);
765 for(rowidx=0; rowidx<d74s->nrows; rowidx++) {
766 for(planeidx=0; planeidx<d74s->ibi->planes_total; planeidx++) {
767 i64 dstpos;
769 // Calculate the offset in our frame buffer.
770 dstpos = block_dstpos + (rowidx * d74s->ibi->frame_buffer_rowspan) +
771 planeidx * d74s->ibi->bytes_per_row_per_plane;
773 for(byteidx=0; byteidx<d74s->nbytes; byteidx++) {
774 u8 val;
776 val = de_getbyte_p(&d74s->pos);
777 if(d74s->op) val ^= dbuf_getbyte(d74s->frctx->frame_buffer, dstpos);
778 dbuf_writebyte_at(d74s->frctx->frame_buffer, dstpos, val);
779 dstpos++;
784 if((d74s->pos - block_srcpos) & 0x1) {
785 d74s->pos++; // padding byte
789 done:
793 static void decompress_delta_op74(deark *c, lctx *d, struct imgbody_info *ibi,
794 struct frame_ctx *frctx, i64 pos1, i64 len)
796 struct d74state d74s;
798 de_zeromem(&d74s, sizeof(struct d74state));
799 d74s.ibi = ibi;
800 d74s.frctx = frctx;
801 d74s.pos = pos1;
802 d74s.endpos = pos1+len;
804 if(!d->delta_ops_used[74]) { // If this is the first DLTA#7 chunk...
805 if(ibi->width < 320) {
806 // The XAnim code says this is a special case, but I haven't found any
807 // sample files. (TODO)
808 de_warn(c, "ANIM-J with width < 320 might not be supported correctly");
812 while(1) {
813 UI code;
815 if(d74s.pos+2 >= d74s.endpos) goto done;
816 code = (UI)de_getu16be_p(&d74s.pos);
817 if(code==1) {
818 frctx->change_flag = 1;
819 d74s.op = (UI)de_getu16be_p(&d74s.pos);
820 d74s.nrows = de_getu16be_p(&d74s.pos);
821 d74s.nbytes = 1;
822 d74s.nblocks = de_getu16be_p(&d74s.pos);
823 do_delta74_blocks(c, &d74s);
825 else if(code==2) {
826 frctx->change_flag = 1;
827 d74s.op = (UI)de_getu16be_p(&d74s.pos);
828 d74s.nrows = de_getu16be_p(&d74s.pos);
829 d74s.nbytes = de_getu16be_p(&d74s.pos);
830 d74s.nblocks = de_getu16be_p(&d74s.pos);
831 do_delta74_blocks(c, &d74s);
833 else if(code==0) {
834 break;
836 else {
837 de_warn(c, "Bad or unsupported ANIM-J compression code (%u)", code);
838 goto done;
842 done:
846 // ANIM-l
847 // Similar to op3, but different in enough ways that it probably isn't worth
848 // combining into one function.
849 static void decompress_plane_delta_op108(deark *c, lctx *d, struct imgbody_info *ibi,
850 struct frame_ctx *frctx, i64 plane_idx, dbuf *inf, i64 codepos1, i64 datapos1,
851 i64 endpos)
853 i64 codepos = codepos1;
854 i64 datapos = datapos1;
855 const i64 code_size = 2;
856 const i64 dataelem_size = 2;
857 i64 elems_per_row;
858 i64 plane_offset;
859 u8 elembuf[2];
860 int baddata_flag = 0;
862 de_dbg2(c, "delta108 plane %d at (%"I64_FMT",%"I64_FMT")", (int)plane_idx,
863 codepos1, datapos1);
865 elems_per_row = (ibi->bytes_per_row_per_plane + (dataelem_size-1) ) / dataelem_size;
866 if(elems_per_row<1) goto done;
867 plane_offset = plane_idx * ibi->bytes_per_row_per_plane;
869 while(1) {
870 i64 elemnum;
871 i64 count_code;
872 i64 xpos, ypos;
873 i64 dstpos;
875 if(codepos+code_size > endpos) goto done;
876 elemnum = dbuf_getu16be_p(inf, &codepos);
878 if(elemnum == 0xffff) { // Stop.
879 goto done;
882 ypos = elemnum / elems_per_row;
883 xpos = elemnum % elems_per_row;
884 dstpos = plane_offset + ypos * ibi->frame_buffer_rowspan + dataelem_size*xpos;
886 if(codepos+code_size > endpos) goto done;
887 count_code = dbuf_geti16be_p(inf, &codepos);
889 if(count_code < 0) { // an uncompressed run
890 i64 count = -count_code;
891 i64 k;
893 frctx->change_flag = 1;
895 if(datapos + dataelem_size > endpos) {
896 baddata_flag = 1;
897 goto done;
899 dbuf_read(inf, elembuf, datapos, dataelem_size);
900 datapos += dataelem_size;
902 for(k=0; k<count; k++) {
903 if(ypos >= ibi->height) {
904 baddata_flag = 1;
905 goto done;
908 dbuf_write_at(frctx->frame_buffer, dstpos, elembuf, dataelem_size);
909 ypos++;
910 dstpos += ibi->frame_buffer_rowspan;
913 else { // an RLE run
914 i64 count = count_code;
915 i64 k;
917 if(count > 0) frctx->change_flag = 1;
919 for(k=0; k<count; k++) {
920 if(ypos >= ibi->height) {
921 baddata_flag = 1;
922 goto done;
924 if(datapos + dataelem_size > endpos) {
925 baddata_flag = 1;
926 goto done;
928 dbuf_read(inf, elembuf, datapos, dataelem_size);
929 datapos += dataelem_size;
931 dbuf_write_at(frctx->frame_buffer, dstpos, elembuf, dataelem_size);
932 ypos++;
933 dstpos += ibi->frame_buffer_rowspan;
938 done:
939 if(baddata_flag && !d->errflag) {
940 de_err(c, "Delta decompression failed");
941 d->errflag = 1;
945 static void decompress_delta_op108(deark *c, lctx *d, struct imgbody_info *ibi,
946 struct frame_ctx *frctx, i64 pos1, i64 len)
948 i64 opcodelist_offs[8];
949 i64 datalist_offs[8];
950 i64 infpos;
951 int i;
952 int saved_indent_level;
953 dbuf *inf = NULL;
955 de_dbg_indent_save(c, &saved_indent_level);
956 if(!frctx->frame_buffer) goto done;
958 de_dbg(c, "[delta108 data]");
960 // Read the entire chunk into memory, so that the random-access reads will be
961 // faster.
962 if(len > DE_MAX_SANE_OBJECT_SIZE) {
963 d->errflag = 1;
964 goto done;
966 inf = dbuf_create_membuf(c, len, 0);
967 dbuf_copy(c->infile, pos1, len, inf);
968 infpos = 0;
970 for(i=0; i<8; i++) {
971 datalist_offs[i] = dbuf_getu32be_p(inf, &infpos);
974 for(i=0; i<8; i++) {
975 opcodelist_offs[i] = dbuf_getu32be_p(inf, &infpos);
978 for(i=0; i<8; i++) {
979 if(d->errflag) goto done;
980 if(i<ibi->planes_total) {
981 de_dbg2(c, "opcode_list[%d] offs: %"I64_FMT, i, opcodelist_offs[i]);
982 de_dbg2(c, "data_list[%d] offs: %"I64_FMT, i, datalist_offs[i]);
983 if(opcodelist_offs[i]>0) {
984 decompress_plane_delta_op108(c, d, ibi, frctx, i, inf,
985 2*opcodelist_offs[i], 2*datalist_offs[i], len);
990 done:
991 dbuf_close(inf);
992 de_dbg_indent_restore(c, saved_indent_level);
995 static void pal_fixup4(deark *c, lctx *d)
997 i64 k;
998 u8 cr, cg, cb;
1000 for(k=0; k<d->pal_ncolors; k++) {
1001 cr = DE_COLOR_R(d->pal[k]);
1002 cg = DE_COLOR_G(d->pal[k]);
1003 cb = DE_COLOR_B(d->pal[k]);
1004 cr = 17*(cr>>4);
1005 cg = 17*(cg>>4);
1006 cb = 17*(cb>>4);
1007 d->pal[k] = DE_MAKE_RGB(cr, cg, cb);
1011 static void pal_fixup6(deark *c, lctx *d)
1013 i64 k;
1014 u8 cr, cg, cb;
1016 for(k=0; k<d->pal_ncolors; k++) {
1017 cr = DE_COLOR_R(d->pal[k]);
1018 cg = DE_COLOR_G(d->pal[k]);
1019 cb = DE_COLOR_B(d->pal[k]);
1020 cr = (cr&0xfc)|(cr>>6);
1021 cg = (cg&0xfc)|(cg>>6);
1022 cb = (cb&0xfc)|(cb>>6);
1023 d->pal[k] = DE_MAKE_RGB(cr, cg, cb);
1027 // It's clear that some ILBM images have palette colors with only 4 bits of
1028 // precision (the low bits often being set to 0), while others have 8, or
1029 // something in between.
1030 // What's not clear is how to tell them apart.
1031 // We'll guess that
1032 // * HAM6 images always have 4.
1033 // * HAM8 images always have 6.
1034 // * For anything else, assume 4 if the low 4 bits are all 0.
1035 // * Otherwise, 8.
1036 // TODO: It may be safe to assume that 8-plane images always have 8, but
1037 // more research is needed.
1038 static void fixup_palette(deark *c, lctx *d)
1040 i64 k;
1041 u8 cr, cg, cb;
1043 if(d->pal_ncolors<1) return;
1045 if(d->is_ham8) {
1046 pal_fixup6(c, d);
1047 return;
1049 if(d->is_ham6) {
1050 pal_fixup4(c, d);
1051 return;
1054 for(k=0; k<d->pal_ncolors; k++) {
1055 cr = DE_COLOR_R(d->pal[k]);
1056 cg = DE_COLOR_G(d->pal[k]);
1057 cb = DE_COLOR_B(d->pal[k]);
1058 if((cr&0x0f) != 0) return;
1059 if((cg&0x0f) != 0) return;
1060 if((cb&0x0f) != 0) return;
1062 de_dbg(c, "Palette seems to have 4 bits of precision. Rescaling palette.");
1063 pal_fixup4(c, d);
1066 // Called when we encounter a BODY or DLTA or TINY chunk
1067 static void do_before_image_chunk(deark *c, lctx *d)
1069 if(d->bmhd_changed_flag) {
1070 if(!d->found_cmap && d->planes_raw<=8) {
1071 de_make_grayscale_palette(d->pal, (i64)1<<(UI)d->planes_raw, 0);
1074 if(d->planes_raw==6 && d->pal_ncolors==32 && !d->ehb_flag && !d->ham_flag) {
1075 de_warn(c, "Assuming this is an EHB image");
1076 d->ehb_flag = 1;
1080 if(d->cmap_changed_flag) {
1081 de_memcpy(d->pal, d->pal_raw, (size_t)d->pal_ncolors * sizeof(d->pal_raw[0]));
1084 if(d->cmap_changed_flag && d->ehb_flag && d->planes_raw==6) {
1085 UI k;
1087 // TODO: Should we still do this if the palette already has 64 colors
1088 // (as it often does)?
1089 for(k=0; k<32; k++) {
1090 u8 cr, cg, cb;
1092 cr = DE_COLOR_R(d->pal[k]);
1093 cg = DE_COLOR_G(d->pal[k]);
1094 cb = DE_COLOR_B(d->pal[k]);
1095 d->pal[k+32] = DE_MAKE_RGB(cr/2, cg/2, cb/2);
1100 if(d->opt_fixpal && !d->is_anim && d->cmap_changed_flag) {
1101 fixup_palette(c, d);
1104 if(d->cmap_changed_flag) {
1105 d->pal_is_grayscale = de_is_grayscale_palette(d->pal, 256);
1108 d->cmap_changed_flag = 0;
1109 d->bmhd_changed_flag = 0;
1112 static int init_imgbody_info(deark *c, lctx *d, struct imgbody_info *ibi, int is_thumb)
1114 int retval = 0;
1116 ibi->is_thumb = is_thumb;
1118 // Unlike ACBM, it would be messy and slow to convert PBM to the standard ILBM
1119 // frame buffer format (and back). So we support a special frame buffer format
1120 // just for PBM.
1121 ibi->is_pbm = (d->formtype==CODE_PBM);
1123 if(is_thumb) {
1124 ibi->width = d->thumb_width;
1125 ibi->height = d->thumb_height;
1127 else {
1128 ibi->width = d->width;
1129 ibi->height = d->height;
1132 // Quick & dirty support for -padpix.
1133 // TODO: Some of these conditions could be removed, with care.
1134 if(c->padpix && (d->width%16) && !is_thumb && !d->is_anim && d->formtype==CODE_ILBM &&
1135 !d->ham_flag)
1137 ibi->width = de_pad_to_n(ibi->width, 16);
1140 ibi->compression = d->compression;
1142 ibi->masking_code = d->masking_code;
1143 // Based on what little data I have, it seems that TINY images do not have
1144 // a transparency mask, even if the main image does.
1145 if(is_thumb && ibi->masking_code==MASKINGTYPE_1BITMASK) {
1146 ibi->masking_code = MASKINGTYPE_NONE;
1149 if(d->planes_raw==24) {
1150 ibi->colortype = COLORTYPE_RGB24;
1152 else {
1153 ibi->colortype = COLORTYPE_DEFAULT;
1156 if(ibi->is_pbm) {
1157 ibi->planes_fg = 1;
1158 ibi->planes_total = 1;
1160 else {
1161 ibi->planes_fg = d->planes_raw;
1162 ibi->planes_total = d->planes_raw;
1163 if(ibi->masking_code==MASKINGTYPE_1BITMASK) {
1164 ibi->planes_total++;
1167 ibi->transparent_color = d->transparent_color;
1168 ibi->x_aspect = d->x_aspect;
1169 ibi->y_aspect = d->y_aspect;
1171 if(ibi->is_pbm) {
1172 if(d->planes_raw!=8 || d->masking_code==MASKINGTYPE_1BITMASK) {
1173 de_err(c, "Not a supported PBM format");
1174 goto done;
1178 if(ibi->is_pbm) {
1179 ibi->bytes_per_row_per_plane = ibi->width;
1180 if(ibi->bytes_per_row_per_plane%2) {
1181 ibi->bytes_per_row_per_plane++;
1183 ibi->bits_per_row_per_plane = ibi->bytes_per_row_per_plane * 8;
1184 // Note: The PBM row size might be adjusted later, after decompression.
1186 else {
1187 ibi->bits_per_row_per_plane = de_pad_to_n(ibi->width, 16);
1188 ibi->bytes_per_row_per_plane = ibi->bits_per_row_per_plane/8;
1190 ibi->frame_buffer_rowspan = ibi->bytes_per_row_per_plane * ibi->planes_total;
1191 ibi->frame_buffer_size = ibi->frame_buffer_rowspan * ibi->height;
1193 if(ibi->masking_code==MASKINGTYPE_NONE) {
1196 else if(ibi->masking_code==MASKINGTYPE_COLORKEY) {
1197 if(!d->opt_notrans && ibi->planes_fg<=8 && !d->ham_flag) {
1198 ibi->use_colorkey_transparency = 1;
1201 else if(ibi->masking_code==MASKINGTYPE_1BITMASK) {
1204 else {
1205 de_warn(c, "This type of transparency is not supported");
1208 if(ibi->use_colorkey_transparency && ibi->transparent_color<=255) {
1209 d->pal[ibi->transparent_color] = DE_SET_ALPHA(d->pal[ibi->transparent_color], 0);
1212 if(ibi->colortype==COLORTYPE_RGB24) {
1215 else if(ibi->planes_fg<1 || ibi->planes_fg>8) {
1216 de_err(c, "Bad or unsupported number of planes (%d)", (int)ibi->planes_fg);
1217 goto done;
1219 retval = 1;
1221 done:
1222 return retval;
1225 static void write_frame(deark *c, lctx *d, struct imgbody_info *ibi, struct frame_ctx *frctx);
1227 static void do_dlta(deark *c, lctx *d, i64 pos1, i64 len)
1229 struct frame_ctx *frctx = d->frctx;
1230 struct frame_ctx *reference_frctx = NULL;
1231 struct imgbody_info *ibi = NULL;
1232 int saved_indent_level;
1234 de_dbg_indent_save(c, &saved_indent_level);
1236 if(d->errflag) goto done;
1237 if(!d->found_bmhd) goto done;
1238 if(!frctx) goto done;
1239 if(frctx->done_flag) goto done;
1240 frctx->done_flag = 1;
1242 // TODO: Should the imgbody_info be saved somewhere, or recalculated for every frame?
1243 ibi = de_malloc(c, sizeof(struct imgbody_info));
1245 do_before_image_chunk(c, d);
1247 if(!init_imgbody_info(c, d, ibi, 0)) {
1248 d->errflag = 1;
1249 goto done;
1252 // Find the reference frame (if it exists).
1253 // It is the highest numbered oldfrctx[] item whose index is at most
1254 // frctx->interleave-1, and which is non-NULL.
1255 if(frctx->interleave>=2) {
1256 reference_frctx = d->oldfrctx[1];
1257 if(!reference_frctx) {
1258 reference_frctx = d->oldfrctx[0];
1261 else {
1262 reference_frctx = d->oldfrctx[0];
1265 // Allocate buffer for this frame
1266 if(!frctx->frame_buffer) {
1267 frctx->frame_buffer = dbuf_create_membuf(c, ibi->frame_buffer_size, 0x1);
1270 // Start by copying the reference frame to this frame. The decompress function
1271 // will then modify this frame.
1272 if(reference_frctx && reference_frctx->frame_buffer) {
1273 dbuf_copy(reference_frctx->frame_buffer, 0, reference_frctx->frame_buffer->len,
1274 frctx->frame_buffer);
1277 switch(frctx->op) {
1278 case 3:
1279 decompress_delta_op3(c, d, ibi, frctx, pos1, len);
1280 break;
1281 case 5:
1282 decompress_delta_op5(c, d, ibi, frctx, pos1, len);
1283 break;
1284 case 7:
1285 decompress_delta_op7(c, d, ibi, frctx, pos1, len);
1286 break;
1287 case 8:
1288 decompress_delta_op8(c, d, ibi, frctx, pos1, len);
1289 break;
1290 case 74:
1291 decompress_delta_op74(c, d, ibi, frctx, pos1, len);
1292 break;
1293 case 108:
1294 decompress_delta_op108(c, d, ibi, frctx, pos1, len);
1295 break;
1296 default:
1297 de_err(c, "Unsupported DLTA operation: %d", (int)frctx->op);
1298 d->errflag = 1;
1300 if(d->errflag) goto done;
1302 if(frctx->change_flag || d->opt_anim_includedups) {
1303 write_frame(c, d, ibi, frctx);
1305 else {
1306 de_dbg(c, "[suppressing duplicate frame]");
1309 done:
1310 // For the summary line, and so we can know when encountering an op for the
1311 // first time.
1312 if(frctx) {
1313 d->delta_ops_used[(size_t)frctx->op] = 1;
1316 de_free(c, ibi);
1317 de_dbg_indent_restore(c, saved_indent_level);
1320 static int decompress_method0(deark *c, lctx *d, i64 pos, i64 len, dbuf *unc_pixels,
1321 i64 expected_len)
1323 i64 amt_to_copy;
1325 amt_to_copy = de_min_int(len, expected_len);
1326 dbuf_copy(c->infile, pos, amt_to_copy, unc_pixels);
1327 return 1;
1330 static int decompress_method1(deark *c, lctx *d, i64 pos, i64 len, dbuf *unc_pixels,
1331 i64 expected_len)
1333 int retval = 0;
1334 struct de_dfilter_in_params dcmpri;
1335 struct de_dfilter_out_params dcmpro;
1336 struct de_dfilter_results dres;
1338 de_dfilter_init_objects(c, &dcmpri, &dcmpro, &dres);
1339 dcmpri.f = c->infile;
1340 dcmpri.pos = pos;
1341 dcmpri.len = len;
1342 dcmpro.f = unc_pixels;
1343 dcmpro.len_known = 1;
1344 dcmpro.expected_len = expected_len;
1346 fmtutil_decompress_packbits_ex(c, &dcmpri, &dcmpro, &dres, NULL);
1347 if(dres.errcode) {
1348 de_err(c, "Decompression failed: %s", dres.errmsg);
1349 goto done;
1351 de_dbg(c, "decompressed %"I64_FMT" to %"I64_FMT" bytes", len, unc_pixels->len);
1352 retval = 1;
1353 done:
1354 return retval;
1357 struct vdat_ctx {
1358 lctx *d;
1359 struct imgbody_info *ibi;
1360 dbuf *unc_pixels;
1361 i64 vdat_chunk_count; // (the plane number)
1362 i64 cur_col;
1363 i64 ypos;
1366 static void vdat_write_element(deark *c, struct vdat_ctx *vdctx, const u8 *elembuf)
1368 i64 dstpos;
1370 dstpos = vdctx->ibi->bytes_per_row_per_plane * vdctx->vdat_chunk_count;
1371 dstpos += 2*vdctx->cur_col;
1372 dstpos += vdctx->ypos * vdctx->ibi->frame_buffer_rowspan;
1374 dbuf_write_at(vdctx->unc_pixels, dstpos, elembuf, 2);
1375 vdctx->ypos++;
1376 if(vdctx->ypos >= vdctx->ibi->height) {
1377 vdctx->ypos = 0;
1378 vdctx->cur_col++;
1382 static void do_vdat_chunk(deark *c, struct vdat_ctx *vdctx, i64 pos1, i64 len)
1384 i64 pos;
1385 i64 endpos;
1386 i64 count;
1387 i64 cmd_cnt;
1388 i64 i, k;
1389 u8 cmd;
1390 u8 *cmds = NULL;
1391 u8 elembuf[2];
1393 vdctx->cur_col = 0;
1394 vdctx->ypos = 0;
1395 pos = pos1;
1396 endpos = pos1+len;
1398 cmd_cnt = de_getu16be(pos); // command count + 2
1399 pos+=2;
1400 cmd_cnt -= 2;
1401 de_dbg(c, "number of command bytes: %d", (int)cmd_cnt);
1402 if(cmd_cnt<1) goto done;
1404 cmds = de_mallocarray(c, cmd_cnt, sizeof(u8));
1406 // Read commands
1407 de_read(cmds, pos, cmd_cnt);
1408 pos += cmd_cnt;
1410 // Read data
1411 for(i=0; i<cmd_cnt; i++) {
1412 if(pos>=endpos) {
1413 break;
1416 cmd = cmds[i];
1418 if(cmd==0x00) {
1419 count = de_getu16be(pos);
1420 pos += 2;
1421 for(k=0; k<count; k++) {
1422 de_read(elembuf, pos, 2);
1423 pos += 2;
1424 vdat_write_element(c, vdctx, elembuf);
1427 else if(cmd==0x01) {
1428 count = de_getu16be(pos);
1429 pos += 2;
1430 de_read(elembuf, pos, 2);
1431 pos += 2;
1432 for(k=0; k<count; k++) {
1433 vdat_write_element(c, vdctx, elembuf);
1436 else if(cmd>=0x80) {
1437 count = (128-(i64)(cmd&0x7f));
1438 for(k=0; k<count; k++) {
1439 de_read(elembuf, pos, 2);
1440 pos += 2;
1441 vdat_write_element(c, vdctx, elembuf);
1444 else { // cmd is from 0x02 to 0x7f
1445 de_read(elembuf, pos, 2);
1446 pos += 2;
1447 count = (i64)cmd;
1448 for(k=0; k<count; k++) {
1449 vdat_write_element(c, vdctx, elembuf);
1454 done:
1455 de_free(c, cmds);
1458 static int my_vdat_chunk_handler(struct de_iffctx *ictx)
1460 deark *c = ictx->c;
1461 struct vdat_ctx *vdctx = (struct vdat_ctx*)ictx->userdata;
1463 if(ictx->chunkctx->chunk4cc.id != CODE_VDAT) {
1464 goto done;
1466 ictx->handled = 1;
1468 if(vdctx->vdat_chunk_count >= vdctx->ibi->planes_total) goto done;
1469 do_vdat_chunk(c, vdctx, ictx->chunkctx->dpos, ictx->chunkctx->dlen);
1471 done:
1472 if(ictx->chunkctx->chunk4cc.id == CODE_VDAT) {
1473 vdctx->vdat_chunk_count++;
1475 return 1;
1478 static int decompress_method2(deark *c, lctx *d, struct imgbody_info *ibi,
1479 i64 pos, i64 len, dbuf *unc_pixels, i64 expected_len)
1481 struct vdat_ctx vdctx;
1482 struct de_iffctx *ictx_vdat = NULL;
1484 // For sanity, we'll use a separate IFF decoder for the contents of this BODY chunk.
1485 de_zeromem(&vdctx, sizeof(struct vdat_ctx));
1486 vdctx.d = d;
1487 vdctx.ibi = ibi;
1488 vdctx.unc_pixels = unc_pixels;
1490 ictx_vdat = fmtutil_create_iff_decoder(c);
1491 ictx_vdat->userdata = (void*)&vdctx;
1492 ictx_vdat->handle_chunk_fn = my_vdat_chunk_handler;
1493 ictx_vdat->f = c->infile;
1494 fmtutil_read_iff_format(ictx_vdat, pos, len);
1496 fmtutil_destroy_iff_decoder(ictx_vdat);
1497 return 1;
1500 // Convert ACBM ABIT image to standard ILBM frame buffer format.
1501 static int convert_abit(deark *c, lctx *d, struct imgbody_info *ibi,
1502 i64 pos, i64 len, dbuf *frame_buffer)
1504 i64 plane, j;
1505 i64 planespan;
1507 planespan = ibi->height * ibi->bytes_per_row_per_plane;
1509 for(plane=0; plane<ibi->planes_total; plane++) {
1510 for(j=0; j<ibi->height; j++) {
1511 dbuf_copy_at(c->infile, pos + plane*planespan + j*ibi->bytes_per_row_per_plane,
1512 ibi->bytes_per_row_per_plane, frame_buffer,
1513 j*ibi->frame_buffer_rowspan + plane*ibi->bytes_per_row_per_plane);
1516 return 1;
1519 // Detect and warn about HAM-E, which we don't support.
1520 static void detect_hame(deark *c, lctx *d, struct imgbody_info *ibi,
1521 struct frame_ctx *frctx)
1523 i64 plane;
1524 i64 k;
1525 UI firstword[4];
1526 u8 pixelval[16];
1527 static const u8 sig[15] = { 0xa, 0x2, 0xf, 0x5, 0x8, 0x4, 0xd, 0xc,
1528 0x6, 0xd, 0xb, 0x0, 0x7, 0xf, 0x1 };
1530 if(d->is_hame) return;
1531 if(d->ham_flag) return;
1532 if(!d->found_cmap) return;
1533 if(ibi->width<640) return;
1534 if(ibi->planes_fg!=4 || ibi->planes_total!=4) return;
1535 if(ibi->is_thumb) return;
1536 if(frctx->formtype!=CODE_ILBM && frctx->formtype!=CODE_ACBM) return;
1537 if(!frctx || !frctx->frame_buffer) return;
1539 // Note: This is quite possibly not the right way to detect HAM-E.
1540 // RECOIL does it by looking up the palette color of each pixel, and using
1541 // certain bits in the palette entry. In all the HAM-E images I have, the
1542 // palette is constructed so as to make that process a no-op.
1544 // Need to examine the values of the first 16 pixels, so need the first 2
1545 // bytes of each of the 4 planes of row 0.
1546 for(plane=0; plane<4; plane++) {
1547 firstword[plane] = (UI)dbuf_getu16be(frctx->frame_buffer,
1548 plane * ibi->bytes_per_row_per_plane);
1551 for(k=0; k<16; k++) {
1552 pixelval[k] = 0;
1553 for(plane=0; plane<4; plane++) {
1554 if(firstword[plane] & (1U<<(15-(UI)k))) {
1555 pixelval[k] |= 1U<<(UI)plane;
1560 if(de_memcmp(pixelval, sig, 15)) return;
1561 if(pixelval[15]!=0x4 && pixelval[15]!=0x8) return;
1562 de_warn(c, "This is probably a HAM-E image, which is not supported correctly.");
1563 d->is_hame = 1;
1566 // Detect and warn about DCTV, which we don't support.
1567 static void detect_dctv(deark *c, lctx *d, struct imgbody_info *ibi,
1568 struct frame_ctx *frctx)
1570 static const u8 sig[31] = {
1571 0x49, 0x87, 0x28, 0xde, 0x11, 0x0b, 0xef, 0xd2, 0x0c, 0x8e, 0x8b, 0x35, 0x5b, 0x75, 0xec, 0xb8,
1572 0x29, 0x6b, 0x03, 0xf9, 0x2b, 0xb4, 0x34, 0xee, 0x67, 0x1e, 0x7c, 0x4f, 0x53, 0x63, 0x15 };
1573 i64 pos;
1575 // As far as I can tell, in DCTV images, the last plane of the first row is
1576 // as follows:
1577 // <00> <31-byte signature> <00 fill> <31-byte signature> <00>
1578 // (Sometimes, the last plane of the *second* row is the same.)
1579 // Unknowns:
1580 // * Is DCTV possible if there are fewer than 64 bytes per row per plane (i.e. width < 512)?
1581 // * Can a DCTV image have transparency?
1582 // * If a DCTV image has a thumbnail image, what format does the thumbnail use?
1584 if(d->is_dctv) return;
1585 if(!frctx || !frctx->frame_buffer) return;
1586 if(ibi->is_thumb) return;
1587 if(frctx->formtype!=CODE_ILBM && frctx->formtype!=CODE_ACBM) return;
1588 if(ibi->bytes_per_row_per_plane<64) return;
1589 pos = d->planes_raw * ibi->bytes_per_row_per_plane - 32;
1590 if(dbuf_getbyte(frctx->frame_buffer, pos) != sig[0]) return;
1591 if(dbuf_memcmp(frctx->frame_buffer, pos, sig, 31)) return;
1592 de_warn(c, "This is probably a DCTV image, which is not supported correctly.");
1593 d->is_dctv = 1;
1596 // BODY/ABIT/TINY
1597 static int do_image_chunk_internal(deark *c, lctx *d, struct frame_ctx *frctx, i64 pos1, i64 len, int is_thumb)
1599 struct imgbody_info *ibi = NULL;
1600 int retval = 0;
1602 if(d->errflag) goto done;
1603 if(!d->found_bmhd) goto done;
1604 if(!frctx) goto done;
1605 if(frctx->done_flag) goto done;
1606 frctx->done_flag = 1;
1608 ibi = de_malloc(c, sizeof(struct imgbody_info));
1610 do_before_image_chunk(c, d);
1612 if(!init_imgbody_info(c, d, ibi, is_thumb)) {
1613 goto done;
1616 if(!frctx->frame_buffer) {
1617 frctx->frame_buffer = dbuf_create_membuf(c, ibi->frame_buffer_size, 0x1);
1620 if(d->formtype==CODE_ACBM) {
1621 // Note: I don't think ABIT images are ever compressed.
1622 if(!convert_abit(c, d, ibi, pos1, len, frctx->frame_buffer)) goto done;
1624 else if(ibi->compression==0) {
1625 if(!decompress_method0(c, d, pos1, len, frctx->frame_buffer, ibi->frame_buffer_size)) goto done;
1627 else if(ibi->compression==1) {
1628 if(!decompress_method1(c, d, pos1, len, frctx->frame_buffer, ibi->frame_buffer_size)) goto done;
1630 else if(ibi->compression==2) {
1631 if(!decompress_method2(c, d, ibi, pos1, len, frctx->frame_buffer, ibi->frame_buffer_size)) goto done;
1633 else {
1634 de_err(c, "Unsupported compression method (%d)", (int)ibi->compression);
1635 goto done;
1638 if(ibi->is_pbm && (frctx->frame_buffer->len != ibi->frame_buffer_size) && (ibi->width%2)) {
1639 if(frctx->frame_buffer->len == ibi->width*ibi->height) {
1640 // Hack: I have some PBM images (e.g. BBM thumbnails) that aren't row-padded.
1641 de_dbg(c, "[assuming rows are not 16-bit padded]");
1642 ibi->bytes_per_row_per_plane = ibi->width;
1643 ibi->bits_per_row_per_plane = ibi->bytes_per_row_per_plane * 8;
1644 ibi->frame_buffer_rowspan = ibi->bytes_per_row_per_plane * ibi->planes_total;
1645 ibi->frame_buffer_size = ibi->frame_buffer_rowspan * ibi->height;
1649 if(frctx->frame_buffer->len != ibi->frame_buffer_size) {
1650 de_warn(c, "Expected %"I64_FMT" decompressed bytes, got %"I64_FMT, ibi->frame_buffer_size,
1651 frctx->frame_buffer->len);
1654 detect_dctv(c, d, ibi, frctx);
1655 detect_hame(c, d, ibi, frctx);
1657 write_frame(c, d, ibi, frctx);
1659 retval = 1;
1661 done:
1662 de_free(c, ibi);
1663 return retval;
1666 static void do_body_or_abit(deark *c, lctx *d, struct de_iffctx *ictx, i64 pos1, i64 len)
1668 if(!de_good_image_dimensions(c, d->width, d->height)) {
1669 d->errflag = 1;
1670 goto done;
1672 if(!do_image_chunk_internal(c, d, d->frctx, pos1, len, 0)) {
1673 d->errflag = 1;
1674 goto done;
1676 done:
1680 static void do_tiny(deark *c, lctx *d, i64 pos1, i64 len)
1682 struct frame_ctx *frctx = NULL;
1683 i64 pos = pos1;
1685 if(len<=4) goto done;
1687 d->thumb_width = de_getu16be_p(&pos);
1688 d->thumb_height = de_getu16be_p(&pos);
1689 de_dbg(c, "thumbnail image, dimensions: %d"DE_CHAR_TIMES"%d", (int)d->thumb_width, (int)d->thumb_height);
1690 if(!de_good_image_dimensions_noerr(c, d->thumb_width, d->thumb_height)) {
1691 de_warn(c, "Bad thumbnail image dimensions");
1692 goto done;
1695 frctx = create_frame(c, d);
1696 (void)do_image_chunk_internal(c, d, frctx, pos, pos1+len-pos, 1);
1698 done:
1699 destroy_frame(c, d, frctx);
1702 static void get_bits_descr(deark *c, lctx *d, struct frame_ctx *frctx, de_ucstring *s)
1704 UI bits = frctx->bits;
1706 if(frctx->op==4 || frctx->op==5 || frctx->op==7 || frctx->op==8) {
1707 if(bits & 0x1) {
1708 ucstring_append_flags_item(s, "long data");
1709 bits -= 0x1;
1710 d->uses_anim_long_data = 1;
1713 if(frctx->op==4 || frctx->op==5) {
1714 if(bits & 0x2) {
1715 ucstring_append_flags_item(s, "XOR");
1716 bits -= 0x2;
1717 d->uses_anim4_5_xor_mode = 1;
1719 if(bits & 0x4) {
1720 ucstring_append_flags_item(s, "one info list");
1721 bits -= 0x4;
1723 if(bits & 0x8) {
1724 ucstring_append_flags_item(s, "RLC");
1725 bits -= 0x8;
1727 if(bits & 0x10) {
1728 ucstring_append_flags_item(s, "vertical");
1729 bits -= 0x10;
1731 if(bits & 0x20) {
1732 ucstring_append_flags_item(s, "long info offsets");
1733 bits -= 0x20;
1737 if(bits!=0) {
1738 ucstring_append_flags_itemf(s, "0x%08x", bits);
1742 static void do_anim_anhd(deark *c, lctx *d, i64 pos, i64 len)
1744 i64 tmp;
1745 u8 ileave_raw;
1746 de_ucstring *bits_descr = NULL;
1747 struct frame_ctx *frctx = d->frctx;
1749 if(!frctx) return;
1750 if(len<24) return;
1752 frctx->op = de_getbyte(pos++);
1753 de_dbg(c, "operation: %d (%s)", (int)frctx->op, anim_get_op_name(frctx->op));
1755 if(frctx->op==ANIM_OP_XOR) {
1756 pos++; // Mask
1757 pos += 2; // w
1758 pos += 2; // h
1759 pos += 2; // x
1760 pos += 2; // y
1762 else {
1763 pos += 9;
1765 pos += 4; // abstime
1767 tmp = de_getu32be_p(&pos); // reltime
1768 de_dbg(c, "reltime: %.5f sec", ((double)tmp)/60.0);
1770 ileave_raw = de_getbyte_p(&pos);
1771 de_dbg(c, "interleave: %d", (int)ileave_raw);
1772 if(ileave_raw==0) {
1773 frctx->interleave = 2;
1775 else {
1776 frctx->interleave = (UI)ileave_raw;
1778 if(frctx->interleave>2 && !d->errflag) {
1779 de_err(c, "Unsupported interleave");
1780 d->errflag = 1;
1783 pos++; // pad0
1785 frctx->bits = (UI)de_getu32be_p(&pos);
1786 bits_descr = ucstring_create(c);
1787 get_bits_descr(c, d, frctx, bits_descr);
1788 de_dbg(c, "bits: 0x%08x (%s)", frctx->bits, ucstring_getpsz_d(bits_descr));
1790 ucstring_destroy(bits_descr);
1793 static void do_camg(deark *c, lctx *d, i64 pos, i64 len)
1795 if(len<4) return;
1796 d->has_camg = 1;
1798 d->ham_flag = 0;
1799 d->is_ham6 = 0;
1800 d->is_ham8 = 0;
1801 d->ehb_flag = 0;
1803 d->camg_mode = (UI)de_getu32be(pos);
1804 de_dbg(c, "CAMG mode: 0x%x", d->camg_mode);
1806 if(d->camg_mode & 0x0800)
1807 d->ham_flag = 1;
1808 if(d->camg_mode & 0x0080)
1809 d->ehb_flag = 1;
1811 de_dbg_indent(c, 1);
1812 de_dbg(c, "HAM: %d", (int)d->ham_flag);
1813 de_dbg(c, "EHB: %d", (int)d->ehb_flag);
1814 de_dbg_indent(c, -1);
1816 if(d->ham_flag) {
1817 if(d->planes_raw==6 || d->planes_raw==5) {
1818 d->is_ham6 = 1;
1820 else if(d->planes_raw==8 || d->planes_raw==7) {
1821 d->is_ham8 = 1;
1823 else {
1824 de_warn(c, "Invalid bit depth (%d) for HAM image.", (int)d->planes_raw);
1829 static void do_dpi(deark *c, lctx *d, i64 pos, i64 len)
1831 if(len<4) return;
1832 d->x_dpi = de_getu16be(pos);
1833 d->y_dpi = de_getu16be(pos+2);
1834 de_dbg(c, "dpi: %d"DE_CHAR_TIMES"%d", (int)d->x_dpi, (int)d->y_dpi);
1837 static void do_grab(deark *c, lctx *d, i64 pos, i64 len)
1839 if(len<4) return;
1840 d->has_hotspot = 1;
1841 d->hotspot_x = (int)de_getu16be(pos);
1842 d->hotspot_y = (int)de_getu16be(pos+2);
1843 de_dbg(c, "hotspot: (%d, %d)", d->hotspot_x, d->hotspot_y);
1846 static void do_dpan(deark *c, lctx *d, i64 pos, i64 len)
1848 i64 nframes;
1850 if(!d->is_anim) return;
1851 if(len<4) return;
1852 nframes = de_getu16be(pos+2);
1853 de_dbg(c, "number of frames: %d", (int)nframes);
1856 static void do_crng(deark *c, lctx *d, i64 pos1, i64 len)
1858 UI tmp1, tmp2;
1860 if(len<8) return;
1861 tmp1 = (UI)de_getu16be(pos1+2);
1862 tmp2 = (UI)de_getu16be(pos1+4);
1863 de_dbg(c, "CRNG flags: 0x%04x", tmp2);
1864 if(tmp2&0x1) {
1865 de_dbg(c, "rate: %.2f fps", (double)(((double)tmp1)*(60.0/16384.0)));
1866 on_color_cycling_enabled(c, d);
1870 static void do_drng(deark *c, lctx *d, i64 pos1, i64 len)
1872 UI tmp2;
1874 tmp2 = (UI)de_getu16be(pos1+4);
1875 de_dbg(c, "DRNG flags: 0x%04x", tmp2);
1876 if(tmp2&0x1) {
1877 on_color_cycling_enabled(c, d);
1881 // Graphicraft Color Cycling Range and Timing
1882 static void do_ccrt(deark *c, lctx *d, i64 pos1, i64 len)
1884 i64 tmp1;
1886 tmp1 = de_geti16be(pos1);
1887 de_dbg(c, "cycling direction: %d", (int)tmp1);
1888 if(tmp1!=0) {
1889 d->uses_color_cycling = 1;
1893 // Frame sequencing chunk used in ANIM-J
1894 static void do_ansq(deark *c, lctx *d, i64 pos1, i64 len)
1896 i64 num_items;
1897 i64 i;
1899 // TODO: Figure out how critical this ANSQ info is.
1900 // If deltas are supposed to be applied out of sequence, we could at least
1901 // emit a warning.
1903 num_items = len / 4;
1904 de_dbg(c, "number of frames in sequence: %d", (int)num_items);
1905 if(c->debug_level<2) return;
1906 de_dbg_indent(c, 1);
1907 for(i=0; i<num_items && i<2000; i++) {
1908 i64 frnum, dur;
1910 frnum = de_getu16be(pos1+i*4);
1911 dur = de_getu16be(pos1+i*4+2);
1912 de_dbg2(c, "item[%d]: frame=%d, dur=%d", (int)i, (int)frnum, (int)dur);
1914 de_dbg_indent(c, -1);
1917 static void render_pixel_row_ham6(deark *c, lctx *d, i64 rownum, const u32 *rowbuf,
1918 UI rowbuf_size, de_bitmap *img)
1920 UI i;
1921 u8 cr, cg, cb;
1923 // At the beginning of each row, the color accumulators are
1924 // initialized to palette entry 0.
1925 cr = DE_COLOR_R(d->pal[0]);
1926 cg = DE_COLOR_G(d->pal[0]);
1927 cb = DE_COLOR_B(d->pal[0]);
1929 for(i=0; i<rowbuf_size; i++) {
1930 u32 clr;
1931 u8 val = rowbuf[i] & 0xff;
1933 switch((val>>4)&0x3) {
1934 case 0x1: // Modify blue value
1935 cb = 17*(val&0x0f);
1936 break;
1937 case 0x2: // Modify red value
1938 cr = 17*(val&0x0f);
1939 break;
1940 case 0x3: // Modify green value
1941 cg = 17*(val&0x0f);
1942 break;
1943 default: // 0: Use colormap value
1944 clr = d->pal[(UI)val];
1945 cr = DE_COLOR_R(clr);
1946 cg = DE_COLOR_G(clr);
1947 cb = DE_COLOR_B(clr);
1948 break;
1951 de_bitmap_setpixel_rgb(img, (i64)i, rownum, DE_MAKE_RGB(cr, cg, cb));
1955 static void render_pixel_row_ham8(deark *c, lctx *d, i64 rownum, const u32 *rowbuf,
1956 UI rowbuf_size, de_bitmap *img)
1958 UI i;
1959 u8 cr, cg, cb;
1961 // At the beginning of each row, the color accumulators are
1962 // initialized to palette entry 0.
1963 cr = DE_COLOR_R(d->pal[0]);
1964 cg = DE_COLOR_G(d->pal[0]);
1965 cb = DE_COLOR_B(d->pal[0]);
1967 for(i=0; i<rowbuf_size; i++) {
1968 u32 clr;
1969 u8 val = rowbuf[i] & 0xff;
1971 switch((val>>6)&0x3) {
1972 case 0x1:
1973 cb = ((val&0x3f)<<2)|((val&0x3f)>>4);
1974 break;
1975 case 0x2:
1976 cr = ((val&0x3f)<<2)|((val&0x3f)>>4);
1977 break;
1978 case 0x3:
1979 cg = ((val&0x3f)<<2)|((val&0x3f)>>4);
1980 break;
1981 default:
1982 clr = d->pal[(UI)val];
1983 cr = DE_COLOR_R(clr);
1984 cg = DE_COLOR_G(clr);
1985 cb = DE_COLOR_B(clr);
1986 break;
1989 de_bitmap_setpixel_rgb(img, (i64)i, rownum, DE_MAKE_RGB(cr, cg, cb));
1993 static void render_pixel_row_normal(deark *c, lctx *d, struct imgbody_info *ibi,
1994 i64 rownum, const u32 *rowbuf, UI rowbuf_size, de_bitmap *img)
1996 UI k;
1998 for(k=0; k<rowbuf_size; k++) {
1999 de_bitmap_setpixel_rgb(img, (i64)k, rownum, d->pal[(UI)rowbuf[k] & 0xff]);
2003 static void render_pixel_row_rgb24(deark *c, lctx *d, struct imgbody_info *ibi,
2004 i64 rownum, const u32 *rowbuf, UI rowbuf_size, de_bitmap *img)
2006 UI k;
2008 for(k=0; k<rowbuf_size; k++) {
2009 UI r, g, b;
2011 r = (rowbuf[k] & 0x0000ff);
2012 g = (rowbuf[k] & 0x00ff00)>>8;
2013 b = (rowbuf[k] & 0xff0000)>>16;
2014 de_bitmap_setpixel_rgb(img, (i64)k, rownum, DE_MAKE_RGB(r, g, b));
2018 static void set_finfo_data(deark *c, lctx *d, struct imgbody_info *ibi, de_finfo *fi)
2020 int has_aspect = 0;
2021 int has_dpi = 0;
2023 if(ibi->is_thumb) {
2024 de_finfo_set_name_from_sz(c, fi, "thumb", 0, DE_ENCODING_LATIN1);
2027 if(d->x_aspect>0 && d->y_aspect>0) {
2028 has_aspect = 1;
2030 if(!ibi->is_thumb && d->x_dpi>0 && d->y_dpi>0) {
2031 has_dpi = 1;
2034 if(has_dpi) {
2035 fi->density.code = DE_DENSITY_DPI;
2036 fi->density.xdens = (double)d->x_dpi;
2037 fi->density.ydens = (double)d->y_dpi;
2039 else if(has_aspect) {
2040 fi->density.code = DE_DENSITY_UNK_UNITS;
2041 fi->density.ydens = (double)d->x_aspect;
2042 fi->density.xdens = (double)d->y_aspect;
2045 if(!ibi->is_thumb && d->has_hotspot) {
2046 fi->has_hotspot = 1;
2047 fi->hotspot_x = d->hotspot_x;
2048 fi->hotspot_y = d->hotspot_y;
2052 // Generate the final image and write it to a file.
2053 static void write_frame(deark *c, lctx *d, struct imgbody_info *ibi, struct frame_ctx *frctx)
2055 de_bitmap *img = NULL;
2056 i64 j;
2057 u32 *rowbuf = NULL; // The current row of pixel (palette or RGB) values
2058 u8 *rowbuf_trns = NULL; // The current row's 1-bit transparency mask values
2059 UI rowbuf_size;
2060 int bypp;
2061 de_finfo *fi = NULL;
2062 UI createflags = 0;
2063 u32 pixelval[8];
2064 u8 pixeltrnsval[8];
2066 if(d->errflag) goto done;
2067 if(!frctx) goto done;
2068 if(!frctx->frame_buffer) {
2069 d->errflag = 1;
2070 goto done;
2072 if(ibi->colortype==COLORTYPE_RGB24) {
2073 if(ibi->planes_fg!=24) goto done;
2075 else if(ibi->planes_fg<1 || ibi->planes_fg>8) {
2076 goto done;
2079 if(d->debug_frame_buffer) {
2080 de_finfo *fi_fb;
2082 fi_fb = de_finfo_create(c);
2083 de_finfo_set_name_from_sz(c, fi_fb, "fb", 0, DE_ENCODING_LATIN1);
2084 de_convert_and_write_image_bilevel(frctx->frame_buffer, 0,
2085 ibi->bits_per_row_per_plane * ibi->planes_total,
2086 ibi->height, ibi->frame_buffer_rowspan, 0, fi_fb, 0);
2087 de_finfo_destroy(c, fi_fb);
2090 rowbuf_size = (UI)ibi->width;
2091 rowbuf = de_mallocarray(c, rowbuf_size, sizeof(rowbuf[0]));
2092 rowbuf_trns = de_mallocarray(c, rowbuf_size, sizeof(rowbuf_trns[0]));
2094 if(d->found_cmap && d->pal_is_grayscale && d->planes_raw<=8 && !d->is_ham6 && !d->is_ham8) {
2095 bypp = 1;
2097 else {
2098 bypp = 3;
2101 if(ibi->use_colorkey_transparency || ibi->masking_code==MASKINGTYPE_1BITMASK) {
2102 if(!d->opt_notrans) {
2103 bypp++;
2107 img = de_bitmap_create(c, ibi->width, ibi->height, bypp);
2109 if(ibi->is_pbm) {
2110 de_convert_image_paletted(frctx->frame_buffer, 0, 8, ibi->frame_buffer_rowspan,
2111 d->pal, img, 0);
2112 goto after_render;
2115 for(j=0; j<ibi->height; j++) {
2116 i64 z;
2117 i64 plane;
2118 UI k;
2120 // Process 8 pixels at a time
2121 for(z=0; z<ibi->bytes_per_row_per_plane; z++) {
2122 de_zeromem(pixelval, sizeof(pixelval));
2123 de_zeromem(pixeltrnsval, sizeof(pixeltrnsval));
2125 // Read the zth byte in each plane
2126 for(plane=0; plane<ibi->planes_total; plane++) {
2127 u8 b;
2129 b = dbuf_getbyte(frctx->frame_buffer,
2130 j*ibi->frame_buffer_rowspan +
2131 plane*ibi->bytes_per_row_per_plane + z);
2133 for(k=0; k<8; k++) {
2134 if(b & (1U<<(7-k))) {
2135 if(plane < ibi->planes_fg) {
2136 pixelval[k] |= 1U<<(UI)plane;
2138 else {
2139 // The only way this can happen is if this plane is a
2140 // 1-bit transparency mask.
2141 pixeltrnsval[k] = 1;
2147 for(k=0; k<8; k++) {
2148 UI idx;
2150 idx = (UI)z*8+k;
2151 if(idx < rowbuf_size) {
2152 rowbuf[idx] = pixelval[k];
2153 rowbuf_trns[idx] = pixeltrnsval[k];
2158 if(ibi->colortype==COLORTYPE_RGB24) {
2159 render_pixel_row_rgb24(c, d, ibi, j, rowbuf, rowbuf_size, img);
2161 else if(d->is_ham6) {
2162 render_pixel_row_ham6(c, d, j, rowbuf, rowbuf_size, img);
2164 else if(d->is_ham8) {
2165 render_pixel_row_ham8(c, d, j, rowbuf, rowbuf_size, img);
2167 else {
2168 render_pixel_row_normal(c, d, ibi, j, rowbuf, rowbuf_size, img);
2171 // Handle 1-bit transparency masks here, for all color types.
2172 if(ibi->masking_code==MASKINGTYPE_1BITMASK && !d->opt_notrans) {
2173 i64 i;
2175 for(i=0; i<rowbuf_size; i++) {
2176 u32 clr;
2178 if(rowbuf_trns[i]==0) {
2179 clr = de_bitmap_getpixel(img, i, j);
2180 clr = DE_SET_ALPHA(clr, 0);
2181 de_bitmap_setpixel_rgba(img, i, j, clr);
2187 after_render:
2188 fi = de_finfo_create(c);
2189 set_finfo_data(c, d, ibi, fi);
2190 if(ibi->is_thumb) {
2191 createflags |= DE_CREATEFLAG_IS_AUX;
2193 if(!d->is_anim) {
2194 createflags |= DE_CREATEFLAG_OPT_IMAGE;
2197 de_bitmap_write_to_file_finfo(img, fi, createflags);
2199 done:
2200 de_bitmap_destroy(img);
2201 de_finfo_destroy(c, fi);
2202 de_free(c, rowbuf);
2203 de_free(c, rowbuf_trns);
2206 static void on_frame_begin(deark *c, lctx *d, u32 formtype)
2208 if(d->frctx) return;
2209 d->num_frames_started++;
2210 d->frctx = create_frame(c, d);
2211 d->frctx->formtype = formtype;
2212 d->frctx->frame_idx = d->num_frames_finished;
2213 if(d->is_anim) de_dbg(c, "[frame #%d begin]", d->frctx->frame_idx);
2216 static void on_frame_end(deark *c, lctx *d)
2218 if(!d->frctx) return;
2220 if(d->is_anim) de_dbg(c, "[frame #%d end]", d->frctx->frame_idx);
2222 destroy_frame(c, d, d->oldfrctx[1]); // Destroy the frame that's aged out
2223 d->oldfrctx[1] = d->oldfrctx[0]; // Make room for the new frame
2224 d->oldfrctx[0] = d->frctx; // Save the new frame
2225 d->frctx = NULL;
2226 d->num_frames_finished++;
2229 static int my_iff_chunk_handler(struct de_iffctx *ictx)
2231 deark *c = ictx->c;
2232 int quitflag = 0;
2233 lctx *d = (lctx*)ictx->userdata;
2235 if(d->num_frames_finished >= ANIM_MAX_FRAMES) {
2236 quitflag = 1;
2237 goto done;
2240 // Chunks that we support even if they are not in FORM:ILBM, FORM:PBM, etc. chunk.
2242 switch(ictx->chunkctx->chunk4cc.id) {
2243 case CODE_FORM:
2244 if(ictx->level==0) {
2245 // Remember this for later
2246 d->main_chunk_endpos = ictx->chunkctx->dpos + ictx->chunkctx->dlen;
2248 if(ictx->level>d->FORM_level) break;
2249 ictx->is_std_container = 1;
2250 goto done;
2253 // Chunks that we process only inside a FORM:ILBM, etc. chunk.
2255 if(!d->frctx) goto done;
2257 switch(ictx->chunkctx->chunk4cc.id) {
2258 case CODE_BMHD:
2259 ictx->handled = 1;
2260 if(!do_bmhd(c, d, ictx->chunkctx->dpos, ictx->chunkctx->dlen)) {
2261 d->errflag = 1;
2262 goto done;
2264 break;
2266 case CODE_ANHD:
2267 do_anim_anhd(c, d, ictx->chunkctx->dpos, ictx->chunkctx->dlen);
2268 ictx->handled = 1;
2269 break;
2271 case CODE_CMAP:
2272 do_cmap(c, d, ictx->chunkctx->dpos, ictx->chunkctx->dlen);
2273 ictx->handled = 1;
2274 break;
2276 case CODE_CAMG:
2277 do_camg(c, d, ictx->chunkctx->dpos, ictx->chunkctx->dlen);
2278 ictx->handled = 1;
2279 break;
2281 case CODE_BODY:
2282 case CODE_ABIT:
2283 ictx->handled = 1;
2284 do_body_or_abit(c, d, ictx, ictx->chunkctx->dpos, ictx->chunkctx->dlen);
2285 break;
2287 case CODE_DLTA:
2288 ictx->handled = 1;
2289 if(ictx->curr_container_contentstype4cc.id != CODE_ILBM) {
2290 d->errflag = 1;
2291 goto done;
2293 do_dlta(c, d, ictx->chunkctx->dpos, ictx->chunkctx->dlen);
2294 break;
2296 case CODE_TINY:
2297 do_tiny(c, d, ictx->chunkctx->dpos, ictx->chunkctx->dlen);
2298 ictx->handled = 1;
2299 break;
2301 case CODE_DPI:
2302 do_dpi(c, d, ictx->chunkctx->dpos, ictx->chunkctx->dlen);
2303 ictx->handled = 1;
2304 break;
2305 case CODE_GRAB:
2306 do_grab(c, d, ictx->chunkctx->dpos, ictx->chunkctx->dlen);
2307 ictx->handled = 1;
2308 break;
2309 case CODE_DPAN:
2310 do_dpan(c, d, ictx->chunkctx->dpos, ictx->chunkctx->dlen);
2311 ictx->handled = 1;
2312 break;
2313 case CODE_CRNG:
2314 do_crng(c, d, ictx->chunkctx->dpos, ictx->chunkctx->dlen);
2315 ictx->handled = 1;
2316 break;
2317 case CODE_DRNG:
2318 do_drng(c, d, ictx->chunkctx->dpos, ictx->chunkctx->dlen);
2319 ictx->handled = 1;
2320 break;
2321 case CODE_CCRT:
2322 do_ccrt(c, d, ictx->chunkctx->dpos, ictx->chunkctx->dlen);
2323 ictx->handled = 1;
2324 break;
2325 case CODE_SHAM:
2326 d->is_sham = 1;
2327 on_multipalette_enabled(c, d);
2328 break;
2329 case CODE_PCHG:
2330 d->is_pchg = 1;
2331 on_multipalette_enabled(c, d);
2332 break;
2333 case CODE_CTBL:
2334 d->is_ctbl = 1;
2335 on_multipalette_enabled(c, d);
2336 break;
2337 case CODE_BEAM:
2338 d->is_beam = 1;
2339 on_multipalette_enabled(c, d);
2340 break;
2341 case CODE_CLUT:
2342 d->found_clut = 1;
2343 break;
2344 case CODE_ANSQ:
2345 do_ansq(c, d, ictx->chunkctx->dpos, ictx->chunkctx->dlen);
2346 ictx->handled = 1;
2347 break;
2348 case CODE_SBDY:
2349 if(d->is_anim && !d->found_audio) {
2350 de_info(c, "Note: This file includes AnimFX-style audio, which is "
2351 "not supported.");
2352 d->found_audio = 1;
2354 break;
2357 done:
2358 return (quitflag) ? 0 : 1;
2361 static int my_preprocess_iff_chunk_fn(struct de_iffctx *ictx)
2363 lctx *d = (lctx*)ictx->userdata;
2364 const char *name = NULL;
2366 // frctx will be set if we're in an "image" container, such as FORM:ILBM.
2367 // It is possible, e.g., for an ANIM file to contain FORM:8SVX containers
2368 // which contain BODY chunks that are not "image data".
2369 if(d->frctx) {
2370 switch(ictx->chunkctx->chunk4cc.id) {
2371 case CODE_ANHD: name="animation header"; break;
2372 case CODE_BMHD: name="bitmap header"; break;
2373 case CODE_BODY: name="image data"; break;
2374 case CODE_CAMG: name="Amiga viewport mode"; break;
2375 case CODE_CMAP: name="color map"; break;
2376 case CODE_CRNG: name="color register range info"; break;
2377 case CODE_DLTA: name="delta-compressed data"; break;
2378 case CODE_DPI : name="dots/inch"; break;
2379 case CODE_DRNG: name="color cycle"; break;
2380 case CODE_GRAB: name="hotspot"; break;
2381 case CODE_TINY: name="thumbnail"; break;
2385 if(name) {
2386 ictx->chunkctx->chunk_name = name;
2388 return 1;
2391 static int my_on_std_container_start_fn(struct de_iffctx *ictx)
2393 deark *c = ictx->c;
2394 lctx *d = (lctx*)ictx->userdata;
2396 if(ictx->level==d->FORM_level) {
2397 if(d->frctx) {
2398 on_frame_end(c, d);
2400 if((ictx->curr_container_contentstype4cc.id == CODE_ILBM) ||
2401 (ictx->curr_container_contentstype4cc.id == CODE_PBM) ||
2402 (ictx->curr_container_contentstype4cc.id == CODE_ACBM))
2404 on_frame_begin(c, d, ictx->curr_container_contentstype4cc.id);
2406 else {
2407 if(d->is_anim) {
2408 if(ictx->curr_container_contentstype4cc.id == CODE_8SVX) {
2409 d->found_audio = 1;
2411 if(!d->extra_content_warned) {
2412 de_warn(c, "File includes unsupported content of type '%s'",
2413 ictx->curr_container_contentstype4cc.id_sanitized_sz);
2414 d->extra_content_warned = 1;
2417 else {
2418 de_err(c, "Unsupported ILBM-like format");
2419 d->errflag = 1;
2423 return 1;
2426 static void look_for_RAST(deark *c, lctx *d, i64 pos)
2428 if(d->found_rast) return;
2429 if(!dbuf_memcmp(c->infile, pos, "RAST", 4)) {
2430 d->found_rast = 1;
2434 static void do_eof_stuff(deark *c, lctx *d)
2436 i64 endpos, endpos_padded;
2437 i64 extra_bytes;
2439 endpos = d->main_chunk_endpos;
2440 if(endpos<1) return;
2441 endpos_padded = de_pad_to_2(endpos);
2442 extra_bytes = c->infile->len - endpos_padded;
2443 if(extra_bytes<1) return;
2444 de_dbg(c, "[found %"I64_FMT" extra bytes at end of file, starting at %"I64_FMT"]",
2445 extra_bytes, endpos_padded);
2447 look_for_RAST(c, d, endpos);
2448 if(endpos_padded!=endpos) {
2449 look_for_RAST(c, d, endpos_padded);
2451 if(d->found_rast) {
2452 de_warn(c, "Possible RAST data found, which is not supported. "
2453 "Image might not be decoded correctly.");
2457 static int my_on_container_end_fn(struct de_iffctx *ictx)
2459 if(ictx->level==0) {
2460 // Stop after the first top-level chunk (the FORM chunk).
2461 return 0;
2463 return 1;
2466 static void summary_append(de_ucstring *s, const char *fmt, ...)
2467 de_gnuc_attribute ((format (printf, 2, 3)));
2469 static void summary_append(de_ucstring *s, const char *fmt, ...)
2471 va_list ap;
2473 ucstring_append_char(s, ' ');
2474 va_start(ap, fmt);
2475 ucstring_vprintf(s, DE_ENCODING_LATIN1, fmt, ap);
2476 va_end(ap);
2479 // Print a summary line indicating the main characteristics of this file.
2480 static void print_summary(deark *c, lctx *d)
2482 de_ucstring *s = NULL;
2483 size_t k;
2485 if(c->debug_level<1) goto done;
2486 if(!d->found_bmhd) goto done;
2488 s = ucstring_create(c);
2490 switch(d->formtype) {
2491 case CODE_ANIM: summary_append(s, "ANIM"); break;
2492 case CODE_ILBM: summary_append(s, "ILBM"); break;
2493 case CODE_PBM: summary_append(s, "PBM"); break;
2494 case CODE_ACBM: summary_append(s, "ACBM"); break;
2495 default: summary_append(s, "???"); break;
2498 summary_append(s, "planes=%d", (int)d->planes_raw);
2499 if(d->masking_code!=0) summary_append(s, "masking=%d", (int)d->masking_code);
2500 summary_append(s, "cmpr=%d", (int)d->compression);
2501 for(k=0; k<256; k++) {
2502 if(d->delta_ops_used[k]) {
2503 summary_append(s, "delta%u", (UI)k);
2506 if(d->uses_anim_long_data) summary_append(s, "long_data");
2507 if(d->uses_anim4_5_xor_mode) summary_append(s, "xor_mode");
2509 if(d->ham_flag) summary_append(s, "HAM");
2510 if(d->ehb_flag) summary_append(s, "EHB");
2511 if(d->is_sham) summary_append(s, "SHAM");
2512 if(d->is_pchg) summary_append(s, "PCHG");
2513 if(d->is_ctbl) summary_append(s, "CBTL");
2514 if(d->is_beam) summary_append(s, "BEAM");
2515 if(d->is_hame) summary_append(s, "HAM-E");
2516 if(d->is_dctv) summary_append(s, "DCTV");
2517 if(d->found_rast) summary_append(s, "RAST");
2518 if(d->uses_color_cycling) summary_append(s, "color-cycling");
2519 if(d->found_clut) summary_append(s, "CLUT");
2520 if(d->found_audio) summary_append(s, "audio");
2521 if(!d->found_cmap) summary_append(s, "no-CMAP");
2523 de_dbg(c, "summary:%s", ucstring_getpsz(s));
2525 done:
2526 ucstring_destroy(s);
2529 static void de_run_ilbm_or_anim(deark *c, de_module_params *mparams)
2531 u32 id;
2532 lctx *d = NULL;
2533 struct de_iffctx *ictx = NULL;
2535 d = de_malloc(c, sizeof(lctx));
2536 d->opt_fixpal = (u8)de_get_ext_option_bool(c, "ilbm:fixpal", 1);
2537 if(de_get_ext_option(c, "ilbm:notrans")) {
2538 d->opt_notrans = 1;
2540 if(de_get_ext_option(c, "ilbm:allowsham")) {
2541 d->opt_allowsham = 1;
2544 id = (u32)de_getu32be(0);
2545 if(id!=CODE_FORM) {
2546 de_err(c, "Not an IFF file");
2547 goto done;
2549 d->formtype = (u32)de_getu32be(8);
2550 switch(d->formtype) {
2551 case CODE_ANIM:
2552 de_declare_fmt(c, "IFF-ANIM");
2553 d->is_anim = 1;
2554 break;
2555 case CODE_ILBM:
2556 de_declare_fmt(c, "IFF-ILBM");
2557 break;
2558 case CODE_ACBM:
2559 de_declare_fmt(c, "IFF-ACBM");
2560 break;
2561 case CODE_PBM:
2562 de_declare_fmt(c, "IFF-PBM");
2563 break;
2564 default:
2565 de_err(c, "Not a supported IFF format");
2566 goto done;
2569 if(d->is_anim) {
2570 d->opt_anim_includedups = (u8)de_get_ext_option_bool(c, "anim:includedups", 0);
2573 d->FORM_level = d->is_anim ? 1 : 0;
2575 ictx = fmtutil_create_iff_decoder(c);
2576 ictx->has_standard_iff_chunks = 1;
2577 ictx->userdata = (void*)d;
2578 ictx->input_encoding = de_get_input_encoding(c, NULL, DE_ENCODING_ASCII);
2579 ictx->handle_chunk_fn = my_iff_chunk_handler;
2580 ictx->preprocess_chunk_fn = my_preprocess_iff_chunk_fn;
2581 ictx->on_std_container_start_fn = my_on_std_container_start_fn;
2582 ictx->on_container_end_fn = my_on_container_end_fn;
2583 ictx->f = c->infile;
2584 fmtutil_read_iff_format(ictx, 0, c->infile->len);
2586 if(d->frctx) {
2587 on_frame_end(c, d);
2589 do_eof_stuff(c, d);
2590 print_summary(c, d);
2592 done:
2593 fmtutil_destroy_iff_decoder(ictx);
2594 if(d) {
2595 destroy_frame(c, d, d->frctx);
2596 destroy_frame(c, d, d->oldfrctx[0]);
2597 destroy_frame(c, d, d->oldfrctx[1]);
2598 de_free(c, d);
2602 static void de_run_ilbm(deark *c, de_module_params *mparams)
2604 de_run_ilbm_or_anim(c, mparams);
2607 static void de_run_anim(deark *c, de_module_params *mparams)
2609 de_run_ilbm_or_anim(c, mparams);
2612 static int de_identify_ilbm(deark *c)
2614 u32 id;
2616 id = (u32)de_getu32be(0);
2617 if(id!=CODE_FORM) return 0;
2618 id = (u32)de_getu32be(8);
2619 if(id==CODE_ILBM) return 100;
2620 if(id==CODE_PBM ) return 100;
2621 if(id==CODE_ACBM) return 100;
2622 return 0;
2625 static int de_identify_anim(deark *c)
2627 u32 id;
2629 id = (u32)de_getu32be(0);
2630 if(id!=CODE_FORM) return 0;
2631 id = (u32)de_getu32be(8);
2632 if(id==CODE_ANIM) return 100;
2633 return 0;
2636 static void do_help_ilbm_anim(deark *c, int is_anim)
2638 de_msg(c, "-opt ilbm:notrans : Disable support for transparency");
2639 if(!is_anim) {
2640 de_msg(c, "-opt ilbm:fixpal=<0|1> : Don't/Do try to fix palettes that are "
2641 "slightly too dark");
2643 de_msg(c, "-opt ilbm:allowsham : Suppress an error on some images");
2644 if(is_anim) {
2645 de_msg(c, "-opt anim:includedups : Do not suppress duplicate frames");
2649 static void de_help_ilbm(deark *c)
2651 do_help_ilbm_anim(c, 0);
2654 static void de_help_anim(deark *c)
2656 do_help_ilbm_anim(c, 1);
2659 void de_module_ilbm(deark *c, struct deark_module_info *mi)
2661 mi->id = "ilbm";
2662 mi->desc = "IFF-ILBM and related image formats";
2663 mi->run_fn = de_run_ilbm;
2664 mi->identify_fn = de_identify_ilbm;
2665 mi->help_fn = de_help_ilbm;
2668 void de_module_anim(deark *c, struct deark_module_info *mi)
2670 mi->id = "anim";
2671 mi->desc = "IFF-ANIM animation";
2672 mi->run_fn = de_run_anim;
2673 mi->identify_fn = de_identify_anim;
2674 mi->help_fn = de_help_anim;