bmp: Rewrote the RLE decompressor
[deark.git] / modules / ilbm.c
blob47656a8632b7b4e992afdd5621f7729b4f464bc3
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);
13 DE_DECLARE_MODULE(de_module_deep);
15 #define ANIM_MAX_FRAMES 10000
17 #define CODE_8SVX 0x38535658U
18 #define CODE_ABIT 0x41424954U
19 #define CODE_ACBM 0x4143424dU
20 #define CODE_ANHD 0x414e4844U
21 #define CODE_ANIM 0x414e494dU
22 #define CODE_ANSQ 0x414e5351U
23 #define CODE_BEAM 0x4245414dU
24 #define CODE_BMHD 0x424d4844U
25 #define CODE_BODY 0x424f4459U
26 #define CODE_CAMG 0x43414d47U
27 #define CODE_CCRT 0x43435254U
28 #define CODE_CLUT 0x434c5554U
29 #define CODE_CMAP 0x434d4150U
30 #define CODE_CRNG 0x43524e47U
31 #define CODE_CTBL 0x4354424cU
32 #define CODE_DLTA 0x444c5441U
33 #define CODE_DPAN 0x4450414eU
34 #define CODE_DPI 0x44504920U
35 #define CODE_DRNG 0x44524e47U
36 #define CODE_FORM 0x464f524dU
37 #define CODE_GRAB 0x47524142U
38 #define CODE_ILBM 0x494c424dU
39 #define CODE_PBM 0x50424d20U
40 #define CODE_PCHG 0x50434847U
41 #define CODE_RGB8 0x52474238U
42 #define CODE_RGBN 0x5247424eU
43 #define CODE_SBDY 0x53424459U
44 #define CODE_SHAM 0x5348414dU
45 #define CODE_TINY 0x54494e59U
46 #define CODE_VDAT 0x56444154U
47 #define CODE_XS24 0x58533234U
49 #define ANIM_OP_XOR 1
51 #define MASKINGTYPE_NONE 0
52 #define MASKINGTYPE_1BITMASK 1
53 #define MASKINGTYPE_COLORKEY 2
54 #define MASKINGTYPE_LASSO 3
56 enum colortype_enum {
57 COLORTYPE_DEFAULT = 0,
58 COLORTYPE_RGB24
61 // Parameters for a single image, derived from a combination of the global
62 // state and the image context.
63 struct imgbody_info {
64 i64 width, height;
65 i64 planes_fg;
66 i64 planes_total; // Different from planes_fg if MASKINGTYPE_1BITMASK.
67 u8 compression;
68 u8 masking_code;
69 u8 use_colorkey_transparency;
70 UI transparent_color;
71 i64 x_aspect, y_aspect;
72 i64 bits_per_row_per_plane;
73 i64 bytes_per_row_per_plane;
74 i64 frame_buffer_rowspan;
75 i64 frame_buffer_size;
76 enum colortype_enum colortype;
77 int is_thumb;
78 u8 is_pbm; // frame buffer is PBM pixel format
79 u8 is_rgb24; // frame buffer is RGB24 pixel format
82 struct frame_ctx {
83 u32 formtype;
84 int frame_idx;
85 int done_flag; // Have we processed the image (BODY/DLTA/etc. chunk)?
86 int change_flag; // Is this frame different from the previous one?
87 u8 op;
88 UI interleave;
89 UI bits;
90 dbuf *frame_buffer;
93 typedef struct localctx_ilbm {
94 int is_anim;
95 u32 formtype;
96 char formtype_sanitized_sz[8];
97 i64 main_chunk_endpos;
98 int FORM_level; // nesting level of the frames' FORM chunks
99 int errflag;
100 int num_frames_started;
101 int num_frames_finished;
102 int debug_frame_buffer;
103 #define TRANS_REMOVE 0
104 #define TRANS_RESPECT 1
105 #define TRANS_AUTO 2
106 u8 trans_setting;
107 u8 fixpal_setting;
108 u8 opt_allowsham;
109 u8 opt_allowdctv;
110 u8 opt_allowhame;
111 u8 opt_anim_includedups;
112 u8 found_bmhd;
113 u8 found_cmap;
114 u8 cmap_changed_flag;
115 u8 bmhd_changed_flag;
116 u8 camg_changed_flag;
117 u8 has_camg;
118 u8 ham_flag; // "hold and modify"
119 u8 is_ham6;
120 u8 is_ham8;
121 u8 ehb_flag; // "extra halfbrite"
122 u8 uses_color_cycling;
123 u8 color_cycling_warned;
124 u8 is_sham;
125 u8 is_ctbl;
126 u8 is_pchg;
127 u8 is_beam;
128 u8 found_clut;
129 u8 found_rast;
130 u8 found_audio;
131 u8 uses_anim4_5_xor_mode;
132 u8 uses_anim_long_data;
133 u8 multipalette_warned;
134 u8 extra_content_warned;
135 u8 is_hame;
136 u8 is_dctv;
137 UI camg_mode;
139 i64 width, height;
140 i64 planes_raw;
141 u8 compression;
142 u8 masking_code;
143 UI transparent_color;
144 i64 x_aspect, y_aspect;
145 i64 x_dpi, y_dpi;
146 i64 thumb_width, thumb_height;
147 u8 has_hotspot;
148 int hotspot_x, hotspot_y;
150 struct frame_ctx *frctx; // Non-NULL means we're inside a frame
151 struct frame_ctx *oldfrctx[2];
152 i64 pal_ncolors; // Number of colors we read from the file
153 int pal_is_grayscale;
154 u32 pal_raw[256]; // Palette as read from the file
155 u32 pal[256]; // Palette that we will use
156 u8 delta_ops_used[256];
157 } lctx;
159 static const char *anim_get_op_name(u8 op)
161 const char *name = NULL;
163 switch(op) {
164 case 0: name="direct"; break;
165 case ANIM_OP_XOR: name="XOR"; break;
166 case 2: name="long delta"; break;
167 case 3: name="short delta"; break;
168 case 4: name="short/long delta"; break;
169 case 5: name="byte vert. delta"; break;
170 case 7: name="short/long vert. delta, separated"; break;
171 case 8: name="short/long vert. delta, contiguous"; break;
172 case 74: name="ANIM-J (Eric Graham)"; break;
173 case 100: name="ANIM32"; break;
174 case 101: name="ANIM16"; break;
175 case 108: name="ANIM-l (Eric Graham)"; break;
177 return name?name:"?";
180 static const char *get_maskingtype_name(u8 n)
182 const char *name = NULL;
184 switch(n) {
185 case MASKINGTYPE_NONE: name = "no transparency"; break;
186 case MASKINGTYPE_1BITMASK: name = "1-bit transparency mask"; break;
187 case MASKINGTYPE_COLORKEY: name = "color-key transparency"; break;
188 case MASKINGTYPE_LASSO: name = "lasso"; break;
190 return name?name:"?";
193 static const char *get_cmprtype_name(lctx *d, u8 n)
195 const char *name = NULL;
197 if(d->formtype==CODE_ACBM) return "n/a";
199 switch(n) {
200 case 0: name = "uncompressed"; break;
201 case 1: name = "PackBits"; break;
202 case 2: name = "VDAT"; break;
203 case 3: case 4:
204 if(d->formtype==CODE_RGBN || d->formtype==CODE_RGB8) {
205 name = "RGBN/RGB8";
207 break;
209 return name?name:"?";
212 static void on_color_cycling_enabled(deark *c, lctx *d)
214 d->uses_color_cycling = 1;
215 if(d->color_cycling_warned) return;
216 de_warn(c, "This image uses color cycling animation, which is not supported.");
217 d->color_cycling_warned = 1;
220 static void on_multipalette_enabled(deark *c, lctx *d)
222 if(!d->opt_allowsham) {
223 d->errflag = 1;
225 if(d->multipalette_warned) return;
226 if(d->opt_allowsham) {
227 de_warn(c, "This is a multi-palette image, which is not correctly supported.");
229 else {
230 de_err(c, "Multi-palette ILBM images are not supported. "
231 "(\"-opt ilbm:allowspecial\" to decode anyway)");
235 static struct frame_ctx *create_frame(deark *c, lctx *d)
237 struct frame_ctx *frctx;
238 frctx = de_malloc(c, sizeof(struct frame_ctx));
239 return frctx;
242 static void destroy_frame(deark *c, lctx *d, struct frame_ctx *frctx)
244 if(!frctx) return;
245 dbuf_close(frctx->frame_buffer);
246 de_free(c, frctx);
249 static void do_cmap(deark *c, lctx *d, i64 pos, i64 len)
251 i64 ncolors;
253 d->found_cmap = 1;
254 d->cmap_changed_flag = 1;
255 ncolors = len/3;
256 de_dbg(c, "number of palette colors: %d", (int)ncolors);
257 if(ncolors>256) ncolors=256;
259 de_read_palette_rgb(c->infile, pos, ncolors, 3, d->pal_raw, 256, 0);
260 if(ncolors > d->pal_ncolors) {
261 d->pal_ncolors = ncolors;
265 static int do_bmhd(deark *c, lctx *d, i64 pos1, i64 len)
267 i64 pos = pos1;
268 int retval = 0;
269 const char *masking_name;
271 d->bmhd_changed_flag = 1;
272 if(len<20) {
273 de_err(c, "Bad BMHD chunk");
274 goto done;
277 d->found_bmhd = 1;
278 d->width = de_getu16be_p(&pos);
279 d->height = de_getu16be_p(&pos);
280 de_dbg_dimensions(c, d->width, d->height);
281 pos += 4;
283 d->planes_raw = (i64)de_getbyte_p(&pos);
284 de_dbg(c, "planes: %d", (int)d->planes_raw);
285 d->masking_code = de_getbyte_p(&pos);
286 masking_name = get_maskingtype_name(d->masking_code);
288 d->compression = de_getbyte_p(&pos);
289 de_dbg(c, "compression: %d (%s)", (int)d->compression, get_cmprtype_name(d, d->compression));
291 pos++;
292 d->transparent_color = (UI)de_getu16be_p(&pos);
293 de_dbg(c, "masking: %d (%s)", (int)d->masking_code, masking_name);
294 if(d->masking_code==MASKINGTYPE_COLORKEY || d->masking_code==MASKINGTYPE_LASSO) {
295 de_dbg_indent(c, 1);
296 de_dbg(c, "color key: %u", d->transparent_color);
297 de_dbg_indent(c, -1);
300 d->x_aspect = (i64)de_getbyte_p(&pos);
301 d->y_aspect = (i64)de_getbyte_p(&pos);
302 de_dbg(c, "aspect ratio: %d, %d", (int)d->x_aspect, (int)d->y_aspect);
304 retval = 1;
305 done:
306 return retval;
309 static i64 delta3_calc_elem_pos(i64 elemnum, i64 elemsize, i64 elems_per_row, i64 plane_offset,
310 i64 frame_buffer_rowspan)
312 i64 row, col;
314 row = elemnum / elems_per_row;
315 col = elemnum % elems_per_row;
316 return row * frame_buffer_rowspan + plane_offset + elemsize * col;
319 // Note - It should be easy to modify this to work for DLTA#2 compression as well
320 // (need a sample file).
321 static void decompress_plane_delta_op3(deark *c, lctx *d, struct imgbody_info *ibi,
322 struct frame_ctx *frctx, i64 plane, i64 pos1, i64 maxlen)
324 i64 endpos = pos1+maxlen;
325 i64 pos = pos1;
326 i64 elemnum = 0;
327 i64 elemsize = 2;
328 i64 elems_per_row;
329 i64 elems_total;
330 i64 plane_offset;
331 i64 dstpos;
332 u8 elembuf[2];
334 de_dbg2(c, "delta3 plane at %"I64_FMT", maxlen=%"I64_FMT, pos1, maxlen);
336 elems_per_row = (ibi->bytes_per_row_per_plane + (elemsize-1) ) / elemsize;
337 if(elems_per_row<1) goto done;
338 elems_total = elems_per_row * ibi->height;
339 plane_offset = plane * ibi->bytes_per_row_per_plane;
341 while(1) {
342 i64 code;
343 i64 offset;
345 if(elemnum >= elems_total) break;
346 if(pos+2 >= endpos) goto done;
347 code = de_geti16be_p(&pos);
349 if(code == -1) { // Stop.
350 break;
352 else if(code >= 0) { // Skip some number of elements, then write one element.
353 frctx->change_flag = 1;
354 offset = code;
355 elemnum += offset;
356 de_read(elembuf, pos, elemsize);
357 pos += elemsize;
358 dstpos = delta3_calc_elem_pos(elemnum, elemsize, elems_per_row, plane_offset,
359 ibi->frame_buffer_rowspan);
360 dbuf_write_at(frctx->frame_buffer, dstpos, elembuf, elemsize);
362 else { // Skip some number of elements, then write multiple elements.
363 i64 count;
364 i64 k;
366 offset = -(code+2);
367 elemnum += offset;
368 count = de_getu16be_p(&pos);
369 if(count>0) {
370 frctx->change_flag = 1;
372 for(k=0; k<count; k++) {
373 de_read(elembuf, pos, elemsize);
374 pos += elemsize;
375 elemnum++;
376 dstpos = delta3_calc_elem_pos(elemnum, elemsize, elems_per_row, plane_offset,
377 ibi->frame_buffer_rowspan);
378 dbuf_write_at(frctx->frame_buffer, dstpos, elembuf, elemsize);
383 done:
387 // "Short Delta" mode
388 // Decompress into frctx->frame_buffer
389 static void decompress_delta_op3(deark *c, lctx *d, struct imgbody_info *ibi,
390 struct frame_ctx *frctx, i64 pos1, i64 len)
392 i64 i;
393 i64 pos = pos1;
394 i64 planedata_offs[8];
396 de_dbg(c, "[delta3 data]");
398 for(i=0; i<8; i++) {
399 planedata_offs[i] = de_getu32be_p(&pos);
400 if(i<ibi->planes_total) {
401 de_dbg2(c, "plane[%d] offs: %"I64_FMT, (int)i, planedata_offs[i]);
402 if(planedata_offs[i]>0) {
403 decompress_plane_delta_op3(c, d, ibi, frctx, i,
404 pos1+planedata_offs[i], len-planedata_offs[i]);
410 static i64 get_elem_as_int_p(dbuf *f, i64 *ppos, i64 elem_size)
412 if(elem_size==1) {
413 return (i64)dbuf_getbyte_p(f, ppos);
415 if(elem_size==2) {
416 return dbuf_getu16be_p(f, ppos);
418 return dbuf_getu32be_p(f, ppos);
421 // This routine decompresses most frame types used in DLTA#5, #7, and #8.
422 // For #7, the codestream and datastream are stored separately, and have different
423 // element sizes.
424 // For #5 and #8, datapos1 is not used.
425 static void decompress_plane_vdelta(deark *c, lctx *d, struct imgbody_info *ibi,
426 struct frame_ctx *frctx, i64 plane_idx,
427 dbuf *inf, i64 codepos1, i64 datapos1, i64 endpos,
428 i64 code_size, i64 dataelem_size, int separate_data_stream, u8 xor_mode)
430 i64 pos = codepos1; // If !separate_data_stream, this is for code and data
431 i64 datapos = datapos1;
432 i64 num_columns;
433 i64 col;
434 i64 dststride = ibi->frame_buffer_rowspan;
435 UI unc_threshold;
436 u8 last_col_quirk = 0;
437 int baddata_flag = 0;
439 if(separate_data_stream) {
440 de_dbg2(c, "vdelta(%d,%d) plane %d at (%"I64_FMT",%"I64_FMT")", (int)code_size,
441 (int)dataelem_size, (int)plane_idx, codepos1, datapos1);
443 else {
444 de_dbg2(c, "vdelta(%d) plane at (%"I64_FMT")", (int)code_size, codepos1);
446 if(code_size!=1 && code_size!=2 && code_size!=4) goto done;
447 if(dataelem_size!=1 && dataelem_size!=2 && dataelem_size!=4) goto done;
448 if(xor_mode && dataelem_size!=1) goto done;
450 if(code_size==1) {
451 unc_threshold = 0x80;
453 else if(code_size==2) {
454 unc_threshold = 0x8000;
456 else {
457 unc_threshold = 0x80000000U;
460 if(dataelem_size==1) {
461 num_columns = (ibi->width+7)/8;
463 else if(dataelem_size==2) {
464 num_columns = (ibi->width+15)/16;
466 else {
467 num_columns = (ibi->width+31)/32;
470 if(frctx->op==8 && dataelem_size==4) {
471 i64 num_columns_if_size2;
473 num_columns_if_size2 = (ibi->width+15)/16;
474 if(num_columns*2 != num_columns_if_size2) {
475 // A dumb quirk of ANIM-8: The last column may use "word" mode,
476 // even when when all other columns use "long" mode.
477 last_col_quirk = 1;
481 for(col=0; col<num_columns; col++) {
482 i64 opcount;
483 i64 opidx;
484 i64 elem_bytes_to_write;
485 i64 ypos = 0;
486 i64 col_start_dstpos;
487 i64 dataelem_size_thiscol;
488 i64 code_size_thiscol;
489 UI unc_threshold_thiscol;
490 u8 is_last_col;
492 if(c->debug_level>=3) {
493 de_dbg3(c, "col %u at %"I64_FMT, (UI)col, pos);
496 is_last_col = (col+1 == num_columns);
497 code_size_thiscol = code_size;
498 dataelem_size_thiscol = dataelem_size;
499 unc_threshold_thiscol = unc_threshold;
500 if(is_last_col && last_col_quirk) {
501 code_size_thiscol = 2;
502 dataelem_size_thiscol = 2;
503 unc_threshold_thiscol = 0x8000;
506 if(pos>=endpos) {
507 baddata_flag = 1;
508 goto done;
511 // Defend against writing beyond the right edge of this plane
512 if(is_last_col && (dataelem_size_thiscol==4) && (ibi->bytes_per_row_per_plane%4)) {
513 elem_bytes_to_write = 2;
515 else {
516 elem_bytes_to_write = dataelem_size_thiscol;
519 col_start_dstpos = plane_idx * ibi->bytes_per_row_per_plane + dataelem_size*col;
521 opcount = get_elem_as_int_p(inf, &pos, code_size_thiscol);
522 if(c->debug_level>=3) {
523 de_dbg3(c, "col %d op count: %"I64_FMT, (int)col, opcount);
526 for(opidx=0; opidx<opcount; opidx++) {
527 i64 dstpos;
528 i64 count;
529 i64 k;
530 UI op;
531 u8 valbuf[4];
533 if(pos>=endpos) {
534 baddata_flag = 1;
535 goto done;
537 op = (UI)get_elem_as_int_p(inf, &pos, code_size_thiscol);
539 if(op==0) { // RLE
540 count = get_elem_as_int_p(inf, &pos, code_size_thiscol);
541 if(ypos+count > ibi->height) {
542 // TODO: Should we tolerate this, and set count = 0?
543 baddata_flag = 1;
544 goto done;
547 if(count>0) {
548 frctx->change_flag = 1;
551 if(separate_data_stream) {
552 if(datapos>=endpos) {
553 baddata_flag = 1;
554 goto done;
556 dbuf_read(inf, valbuf, datapos, dataelem_size_thiscol);
557 datapos += dataelem_size_thiscol;
559 else {
560 dbuf_read(inf, valbuf, pos, dataelem_size_thiscol);
561 pos += dataelem_size_thiscol;
564 for(k=0; k<count; k++) {
565 dstpos = col_start_dstpos + ypos*dststride;
566 if(xor_mode) {
567 u8 val;
569 val = valbuf[0] ^ dbuf_getbyte(frctx->frame_buffer, dstpos);
570 dbuf_writebyte_at(frctx->frame_buffer, dstpos, val);
572 else {
573 dbuf_write_at(frctx->frame_buffer, dstpos, valbuf, elem_bytes_to_write);
575 ypos++;
578 else if(op < unc_threshold_thiscol) { // skip
579 ypos += (i64)op;
581 else { // uncompressed run
582 count = (i64)(op - unc_threshold_thiscol);
583 if(ypos+count > ibi->height) {
584 baddata_flag = 1;
585 goto done;
588 if(count>0) {
589 frctx->change_flag = 1;
592 for(k=0; k<count; k++) {
593 if(separate_data_stream) {
594 if(datapos>=endpos) {
595 baddata_flag = 1;
596 goto done;
598 dbuf_read(inf, valbuf, datapos, dataelem_size_thiscol);
599 datapos += dataelem_size_thiscol;
601 else {
602 dbuf_read(inf, valbuf, pos, dataelem_size_thiscol);
603 pos += dataelem_size_thiscol;
606 dstpos = col_start_dstpos + ypos*dststride;
607 if(xor_mode) {
608 valbuf[0] ^= dbuf_getbyte(frctx->frame_buffer, dstpos);
610 dbuf_write_at(frctx->frame_buffer, dstpos, valbuf, elem_bytes_to_write);
611 ypos++;
617 done:
618 if(baddata_flag && !d->errflag) {
619 de_err(c, "Delta decompression failed");
620 d->errflag = 1;
624 // Decompress into frctx->frame_buffer
625 static void decompress_delta_op5(deark *c, lctx *d, struct imgbody_info *ibi,
626 struct frame_ctx *frctx, i64 pos1, i64 len)
628 i64 planedata_offs[16];
629 i64 pos = pos1;
630 int i;
631 int saved_indent_level;
632 u8 delta4_5_xor_mode = 0;
634 de_dbg_indent_save(c, &saved_indent_level);
635 if(!frctx->frame_buffer) goto done;
637 de_dbg(c, "[delta5 data]");
639 // Note that we ignore the 0x8 bit ("RLC - run length coded").
640 // I don't know what this option is for. *All* ANIM4/5 frames use run length
641 // coding, but they almost never have have this bit set.
642 // The rare files that do set this bit don't seem to be any different from
643 // those that don't.
644 if((frctx->bits & 0xfffffff5U) != 0) {
645 de_err(c, "Unsupported ANHD options");
646 d->errflag = 1;
647 goto done;
650 if(frctx->bits & 0x2) {
651 delta4_5_xor_mode = 1;
654 for(i=0; i<16; i++) {
655 if(d->errflag) goto done;
656 planedata_offs[i] = de_getu32be_p(&pos);
657 if(i<ibi->planes_total) {
658 de_dbg2(c, "plane[%d] offs: %"I64_FMT, i, planedata_offs[i]);
659 if(planedata_offs[i]>0) {
660 decompress_plane_vdelta(c, d, ibi, frctx, i, c->infile,
661 pos1+planedata_offs[i], 0, pos1+len, 1, 1,
662 0, delta4_5_xor_mode);
667 done:
668 de_dbg_indent_restore(c, saved_indent_level);
671 // Decompress into frctx->frame_buffer
672 static void decompress_delta_op7(deark *c, lctx *d, struct imgbody_info *ibi,
673 struct frame_ctx *frctx, i64 pos1, i64 len)
675 i64 opcodelist_offs[8];
676 i64 datalist_offs[8];
677 i64 infpos;
678 int i;
679 int saved_indent_level;
680 i64 dataelem_size;
681 dbuf *inf = NULL;
683 de_dbg_indent_save(c, &saved_indent_level);
684 if(!frctx->frame_buffer) goto done;
686 de_dbg(c, "[delta7 data]");
688 if(frctx->bits & 0xfffffffeU) {
689 de_err(c, "Unsupported ANHD options");
690 d->errflag = 1;
691 goto done;
693 if(frctx->bits & 0x00000001) {
694 dataelem_size = 4;
696 else {
697 dataelem_size = 2;
700 // We'll have to interleave lots of short reads between two different segments of
701 // the file, with no way to know how big either segment is.
702 // I see no good way to process this DLTA#7 format, except by first reading the
703 // entire chunk into memory.
704 if(len > DE_MAX_SANE_OBJECT_SIZE) {
705 d->errflag = 1;
706 goto done;
708 inf = dbuf_create_membuf(c, len, 0);
709 dbuf_copy(c->infile, pos1, len, inf);
710 infpos = 0;
712 for(i=0; i<8; i++) {
713 opcodelist_offs[i] = dbuf_getu32be_p(inf, &infpos);
716 for(i=0; i<8; i++) {
717 datalist_offs[i] = dbuf_getu32be_p(inf, &infpos);
720 for(i=0; i<8; i++) {
721 if(d->errflag) goto done;
722 if(i<ibi->planes_total) {
723 de_dbg2(c, "opcode_list[%d] offs: %"I64_FMT, i, opcodelist_offs[i]);
724 de_dbg2(c, "data_list[%d] offs: %"I64_FMT, i, datalist_offs[i]);
725 if(opcodelist_offs[i]>0) {
726 decompress_plane_vdelta(c, d, ibi, frctx, i, inf,
727 opcodelist_offs[i], datalist_offs[i], len,
728 1, dataelem_size, 1, 0);
733 done:
734 dbuf_close(inf);
735 de_dbg_indent_restore(c, saved_indent_level);
738 static void decompress_delta_op8(deark *c, lctx *d, struct imgbody_info *ibi,
739 struct frame_ctx *frctx, i64 pos1, i64 len)
741 i64 planedata_offs[16];
742 i64 pos = pos1;
743 i64 elem_size;
744 int i;
745 int saved_indent_level;
747 de_dbg_indent_save(c, &saved_indent_level);
748 if(!frctx->frame_buffer) goto done;
750 de_dbg(c, "[delta8 data]");
752 if(frctx->bits & 0xfffffffeU) {
753 de_err(c, "Unsupported ANHD options");
754 d->errflag = 1;
755 goto done;
757 if(frctx->bits & 0x00000001) {
758 elem_size = 4;
760 else {
761 elem_size = 2;
764 for(i=0; i<16; i++) {
765 if(d->errflag) goto done;
766 planedata_offs[i] = de_getu32be_p(&pos);
767 if(i<ibi->planes_total) {
768 de_dbg2(c, "plane[%d] offs: %"I64_FMT, i, planedata_offs[i]);
769 if(planedata_offs[i]>0) {
770 decompress_plane_vdelta(c, d, ibi, frctx, i, c->infile,
771 pos1+planedata_offs[i], 0, pos1+len, elem_size, elem_size, 0, 0);
776 done:
777 de_dbg_indent_restore(c, saved_indent_level);
780 struct d74state {
781 struct imgbody_info *ibi;
782 struct frame_ctx *frctx;
783 i64 pos;
784 i64 endpos;
786 // Temporary use:
787 UI op;
788 i64 nblocks;
789 i64 nrows; // block height in rows
790 i64 nbytes; // block width in bytes per plane
793 static void do_delta74_blocks(deark *c, struct d74state *d74s)
795 i64 blkidx, rowidx, planeidx, byteidx;
796 i64 d74_bytes_per_row_per_plane;
798 // Reportedly, the 'offset' field assumes a potentially-different measuring
799 // system than one would expect.
800 d74_bytes_per_row_per_plane = (d74s->ibi->width + 7)/8;
802 for(blkidx=0; blkidx<d74s->nblocks; blkidx++) {
803 i64 offset;
804 i64 block_srcpos = d74s->pos;
805 i64 block_dstpos;
807 if(d74s->pos+2 >= d74s->endpos) goto done;
808 offset = de_getu16be_p(&d74s->pos);
810 block_dstpos = (offset / d74_bytes_per_row_per_plane) * d74s->ibi->frame_buffer_rowspan +
811 (offset % d74_bytes_per_row_per_plane);
813 for(rowidx=0; rowidx<d74s->nrows; rowidx++) {
814 for(planeidx=0; planeidx<d74s->ibi->planes_total; planeidx++) {
815 i64 dstpos;
817 // Calculate the offset in our frame buffer.
818 dstpos = block_dstpos + (rowidx * d74s->ibi->frame_buffer_rowspan) +
819 planeidx * d74s->ibi->bytes_per_row_per_plane;
821 for(byteidx=0; byteidx<d74s->nbytes; byteidx++) {
822 u8 val;
824 val = de_getbyte_p(&d74s->pos);
825 if(d74s->op) val ^= dbuf_getbyte(d74s->frctx->frame_buffer, dstpos);
826 dbuf_writebyte_at(d74s->frctx->frame_buffer, dstpos, val);
827 dstpos++;
832 if((d74s->pos - block_srcpos) & 0x1) {
833 d74s->pos++; // padding byte
837 done:
841 static void decompress_delta_op74(deark *c, lctx *d, struct imgbody_info *ibi,
842 struct frame_ctx *frctx, i64 pos1, i64 len)
844 struct d74state d74s;
846 de_zeromem(&d74s, sizeof(struct d74state));
847 d74s.ibi = ibi;
848 d74s.frctx = frctx;
849 d74s.pos = pos1;
850 d74s.endpos = pos1+len;
852 if(!d->delta_ops_used[74]) { // If this is the first DLTA#7 chunk...
853 if(ibi->width < 320) {
854 // The XAnim code says this is a special case, but I haven't found any
855 // sample files. (TODO)
856 de_warn(c, "ANIM-J with width < 320 might not be supported correctly");
860 while(1) {
861 UI code;
863 if(d74s.pos+2 >= d74s.endpos) goto done;
864 code = (UI)de_getu16be_p(&d74s.pos);
865 if(code==1) {
866 frctx->change_flag = 1;
867 d74s.op = (UI)de_getu16be_p(&d74s.pos);
868 d74s.nrows = de_getu16be_p(&d74s.pos);
869 d74s.nbytes = 1;
870 d74s.nblocks = de_getu16be_p(&d74s.pos);
871 do_delta74_blocks(c, &d74s);
873 else if(code==2) {
874 frctx->change_flag = 1;
875 d74s.op = (UI)de_getu16be_p(&d74s.pos);
876 d74s.nrows = de_getu16be_p(&d74s.pos);
877 d74s.nbytes = de_getu16be_p(&d74s.pos);
878 d74s.nblocks = de_getu16be_p(&d74s.pos);
879 do_delta74_blocks(c, &d74s);
881 else if(code==0) {
882 break;
884 else {
885 de_warn(c, "Bad or unsupported ANIM-J compression code: %u", code);
886 goto done;
890 done:
894 // ANIM-l
895 // Similar to op3, but different in enough ways that it probably isn't worth
896 // combining into one function.
897 static void decompress_plane_delta_op108(deark *c, lctx *d, struct imgbody_info *ibi,
898 struct frame_ctx *frctx, i64 plane_idx, dbuf *inf, i64 codepos1, i64 datapos1,
899 i64 endpos)
901 i64 codepos = codepos1;
902 i64 datapos = datapos1;
903 const i64 code_size = 2;
904 const i64 dataelem_size = 2;
905 i64 elems_per_row;
906 i64 plane_offset;
907 u8 elembuf[2];
908 int baddata_flag = 0;
910 de_dbg2(c, "delta108 plane %d at (%"I64_FMT",%"I64_FMT")", (int)plane_idx,
911 codepos1, datapos1);
913 elems_per_row = (ibi->bytes_per_row_per_plane + (dataelem_size-1) ) / dataelem_size;
914 if(elems_per_row<1) goto done;
915 plane_offset = plane_idx * ibi->bytes_per_row_per_plane;
917 while(1) {
918 i64 elemnum;
919 i64 count_code;
920 i64 xpos, ypos;
921 i64 dstpos;
923 if(codepos+code_size > endpos) goto done;
924 elemnum = dbuf_getu16be_p(inf, &codepos);
926 if(elemnum == 0xffff) { // Stop.
927 goto done;
930 ypos = elemnum / elems_per_row;
931 xpos = elemnum % elems_per_row;
932 dstpos = plane_offset + ypos * ibi->frame_buffer_rowspan + dataelem_size*xpos;
934 if(codepos+code_size > endpos) goto done;
935 count_code = dbuf_geti16be_p(inf, &codepos);
937 if(count_code < 0) { // an uncompressed run
938 i64 count = -count_code;
939 i64 k;
941 frctx->change_flag = 1;
943 if(datapos + dataelem_size > endpos) {
944 baddata_flag = 1;
945 goto done;
947 dbuf_read(inf, elembuf, datapos, dataelem_size);
948 datapos += dataelem_size;
950 for(k=0; k<count; k++) {
951 if(ypos >= ibi->height) {
952 baddata_flag = 1;
953 goto done;
956 dbuf_write_at(frctx->frame_buffer, dstpos, elembuf, dataelem_size);
957 ypos++;
958 dstpos += ibi->frame_buffer_rowspan;
961 else { // an RLE run
962 i64 count = count_code;
963 i64 k;
965 if(count > 0) frctx->change_flag = 1;
967 for(k=0; k<count; k++) {
968 if(ypos >= ibi->height) {
969 baddata_flag = 1;
970 goto done;
972 if(datapos + dataelem_size > endpos) {
973 baddata_flag = 1;
974 goto done;
976 dbuf_read(inf, elembuf, datapos, dataelem_size);
977 datapos += dataelem_size;
979 dbuf_write_at(frctx->frame_buffer, dstpos, elembuf, dataelem_size);
980 ypos++;
981 dstpos += ibi->frame_buffer_rowspan;
986 done:
987 if(baddata_flag && !d->errflag) {
988 de_err(c, "Delta decompression failed");
989 d->errflag = 1;
993 static void decompress_delta_op108(deark *c, lctx *d, struct imgbody_info *ibi,
994 struct frame_ctx *frctx, i64 pos1, i64 len)
996 i64 opcodelist_offs[8];
997 i64 datalist_offs[8];
998 i64 infpos;
999 int i;
1000 int saved_indent_level;
1001 dbuf *inf = NULL;
1003 de_dbg_indent_save(c, &saved_indent_level);
1004 if(!frctx->frame_buffer) goto done;
1006 de_dbg(c, "[delta108 data]");
1008 // Read the entire chunk into memory, so that the random-access reads will be
1009 // faster.
1010 if(len > DE_MAX_SANE_OBJECT_SIZE) {
1011 d->errflag = 1;
1012 goto done;
1014 inf = dbuf_create_membuf(c, len, 0);
1015 dbuf_copy(c->infile, pos1, len, inf);
1016 infpos = 0;
1018 for(i=0; i<8; i++) {
1019 datalist_offs[i] = dbuf_getu32be_p(inf, &infpos);
1022 for(i=0; i<8; i++) {
1023 opcodelist_offs[i] = dbuf_getu32be_p(inf, &infpos);
1026 for(i=0; i<8; i++) {
1027 if(d->errflag) goto done;
1028 if(i<ibi->planes_total) {
1029 de_dbg2(c, "opcode_list[%d] offs: %"I64_FMT, i, opcodelist_offs[i]);
1030 de_dbg2(c, "data_list[%d] offs: %"I64_FMT, i, datalist_offs[i]);
1031 if(opcodelist_offs[i]>0) {
1032 decompress_plane_delta_op108(c, d, ibi, frctx, i, inf,
1033 2*opcodelist_offs[i], 2*datalist_offs[i], len);
1038 done:
1039 dbuf_close(inf);
1040 de_dbg_indent_restore(c, saved_indent_level);
1043 static void pal_fixup4(deark *c, lctx *d)
1045 i64 k;
1046 u8 cr, cg, cb;
1048 for(k=0; k<d->pal_ncolors; k++) {
1049 cr = DE_COLOR_R(d->pal[k]);
1050 cg = DE_COLOR_G(d->pal[k]);
1051 cb = DE_COLOR_B(d->pal[k]);
1052 cr = 17*(cr>>4);
1053 cg = 17*(cg>>4);
1054 cb = 17*(cb>>4);
1055 d->pal[k] = DE_MAKE_RGB(cr, cg, cb);
1059 static void pal_fixup6(deark *c, lctx *d)
1061 i64 k;
1062 u8 cr, cg, cb;
1064 for(k=0; k<d->pal_ncolors; k++) {
1065 cr = DE_COLOR_R(d->pal[k]);
1066 cg = DE_COLOR_G(d->pal[k]);
1067 cb = DE_COLOR_B(d->pal[k]);
1068 cr = (cr&0xfc)|(cr>>6);
1069 cg = (cg&0xfc)|(cg>>6);
1070 cb = (cb&0xfc)|(cb>>6);
1071 d->pal[k] = DE_MAKE_RGB(cr, cg, cb);
1075 // It's clear that some ILBM images have palette colors with only 4 bits of
1076 // precision (the low bits often being set to 0), while others have 8, or
1077 // something in between.
1078 // What's not clear is how to tell them apart.
1079 // We'll guess that
1080 // * HAM6 images always have 4.
1081 // * HAM8 images always have 6.
1082 // * For anything else, assume 4 if the low 4 bits are all 0.
1083 // * Otherwise, 8.
1084 // TODO: It may be safe to assume that 8-plane images always have 8, but
1085 // more research is needed.
1086 static void fixup_palette(deark *c, lctx *d)
1088 i64 k;
1089 u8 cr, cg, cb;
1091 if(d->pal_ncolors<1) return;
1092 if(d->formtype==CODE_RGBN || d->formtype==CODE_RGB8) return;
1094 if(d->is_ham8) {
1095 pal_fixup6(c, d);
1096 return;
1098 if(d->is_ham6) {
1099 pal_fixup4(c, d);
1100 return;
1103 for(k=0; k<d->pal_ncolors; k++) {
1104 cr = DE_COLOR_R(d->pal[k]);
1105 cg = DE_COLOR_G(d->pal[k]);
1106 cb = DE_COLOR_B(d->pal[k]);
1107 if((cr&0x0f) != 0) return;
1108 if((cg&0x0f) != 0) return;
1109 if((cb&0x0f) != 0) return;
1111 de_dbg(c, "Palette seems to have 4 bits of precision. Rescaling palette.");
1112 pal_fixup4(c, d);
1115 // Called when we encounter a BODY or DLTA or TINY chunk
1116 static void do_before_image_chunk(deark *c, lctx *d)
1118 if(d->bmhd_changed_flag || d->camg_changed_flag) {
1119 if(d->ham_flag) {
1120 if(d->planes_raw==6 || d->planes_raw==5) {
1121 d->is_ham6 = 1;
1123 else if(d->planes_raw==8 || d->planes_raw==7) {
1124 d->is_ham8 = 1;
1126 else {
1127 de_warn(c, "Invalid bit depth (%d) for HAM image.", (int)d->planes_raw);
1131 if(!d->found_cmap && d->planes_raw<=8) {
1132 de_make_grayscale_palette(d->pal, (i64)1<<(UI)d->planes_raw, 0);
1135 if(d->planes_raw==6 && d->pal_ncolors==32 && !d->ehb_flag && !d->ham_flag) {
1136 de_warn(c, "Assuming this is an EHB image");
1137 d->ehb_flag = 1;
1141 if(d->cmap_changed_flag) {
1142 de_memcpy(d->pal, d->pal_raw, (size_t)d->pal_ncolors * sizeof(d->pal_raw[0]));
1145 if(d->cmap_changed_flag && d->ehb_flag && d->planes_raw==6) {
1146 UI k;
1148 // TODO: Should we still do this if the palette already has 64 colors
1149 // (as it often does)?
1150 for(k=0; k<32; k++) {
1151 u8 cr, cg, cb;
1153 cr = DE_COLOR_R(d->pal[k]);
1154 cg = DE_COLOR_G(d->pal[k]);
1155 cb = DE_COLOR_B(d->pal[k]);
1156 d->pal[k+32] = DE_MAKE_RGB(cr/2, cg/2, cb/2);
1160 if(d->fixpal_setting && d->cmap_changed_flag) {
1161 fixup_palette(c, d);
1164 if(d->cmap_changed_flag) {
1165 d->pal_is_grayscale = de_is_grayscale_palette(d->pal, 256);
1168 d->cmap_changed_flag = 0;
1169 d->bmhd_changed_flag = 0;
1170 d->camg_changed_flag = 0;
1173 static int init_imgbody_info(deark *c, lctx *d, struct imgbody_info *ibi, int is_thumb)
1175 int retval = 0;
1177 ibi->is_thumb = is_thumb;
1179 // Unlike ACBM, it would be messy and slow to convert PBM to the standard ILBM
1180 // frame buffer format (and back). So we support a special frame buffer format
1181 // just for PBM.
1182 ibi->is_pbm = (d->formtype==CODE_PBM);
1183 // We also have a special nonplanar RGB24 format (is_rgb24).
1185 if(d->formtype==CODE_RGBN || d->formtype==CODE_RGB8) {
1186 ibi->is_rgb24 = 1;
1187 if(((d->formtype==CODE_RGBN && d->planes_raw==13) ||
1188 (d->formtype==CODE_RGB8 && d->planes_raw==25)) &&
1189 (d->compression==3 || d->compression==4) &&
1190 d->masking_code==MASKINGTYPE_NONE)
1194 else {
1195 de_err(c, "Unsupported RGBN/RGB8 format");
1196 goto done;
1200 if(is_thumb) {
1201 ibi->width = d->thumb_width;
1202 ibi->height = d->thumb_height;
1204 else {
1205 ibi->width = d->width;
1206 ibi->height = d->height;
1209 // Quick & dirty support for -padpix.
1210 // TODO: Some of these conditions could be removed, with care.
1211 if(c->padpix && (d->width%16) && !is_thumb && !d->is_anim && d->formtype==CODE_ILBM &&
1212 !d->ham_flag)
1214 ibi->width = de_pad_to_n(ibi->width, 16);
1217 ibi->compression = d->compression;
1219 ibi->masking_code = d->masking_code;
1220 // Based on what little data I have, it seems that TINY images do not have
1221 // a transparency mask, even if the main image does.
1222 if(is_thumb && ibi->masking_code==MASKINGTYPE_1BITMASK) {
1223 ibi->masking_code = MASKINGTYPE_NONE;
1226 if(d->planes_raw==24) {
1227 ibi->colortype = COLORTYPE_RGB24;
1229 else {
1230 ibi->colortype = COLORTYPE_DEFAULT;
1233 if(ibi->is_pbm || ibi->is_rgb24) {
1234 ibi->planes_fg = 1;
1235 ibi->planes_total = 1;
1237 else {
1238 ibi->planes_fg = d->planes_raw;
1239 ibi->planes_total = d->planes_raw;
1240 if(ibi->masking_code==MASKINGTYPE_1BITMASK) {
1241 ibi->planes_total++;
1244 ibi->transparent_color = d->transparent_color;
1245 ibi->x_aspect = d->x_aspect;
1246 ibi->y_aspect = d->y_aspect;
1248 if(ibi->is_pbm) {
1249 if(d->planes_raw!=8 || d->masking_code==MASKINGTYPE_1BITMASK) {
1250 de_err(c, "Not a supported PBM format");
1251 goto done;
1255 if(ibi->is_pbm) {
1256 ibi->bytes_per_row_per_plane = ibi->width;
1257 if(ibi->bytes_per_row_per_plane%2) {
1258 ibi->bytes_per_row_per_plane++;
1260 ibi->bits_per_row_per_plane = ibi->bytes_per_row_per_plane * 8;
1261 // Note: The PBM row size might be adjusted later, after decompression.
1263 else if(ibi->is_rgb24) {
1264 ibi->bytes_per_row_per_plane = ibi->width*3;
1265 ibi->bits_per_row_per_plane = ibi->bytes_per_row_per_plane * 8;
1267 else {
1268 ibi->bits_per_row_per_plane = de_pad_to_n(ibi->width, 16);
1269 ibi->bytes_per_row_per_plane = ibi->bits_per_row_per_plane/8;
1271 ibi->frame_buffer_rowspan = ibi->bytes_per_row_per_plane * ibi->planes_total;
1272 ibi->frame_buffer_size = ibi->frame_buffer_rowspan * ibi->height;
1274 if(ibi->masking_code==MASKINGTYPE_NONE) {
1277 else if(ibi->masking_code==MASKINGTYPE_COLORKEY) {
1278 if(ibi->planes_fg<=8 && !d->ham_flag) {
1279 ibi->use_colorkey_transparency = 1;
1282 else if(ibi->masking_code==MASKINGTYPE_1BITMASK) {
1285 else {
1286 de_warn(c, "This type of transparency is not supported");
1289 if(ibi->use_colorkey_transparency && ibi->transparent_color<=255) {
1290 d->pal[ibi->transparent_color] = DE_SET_ALPHA(d->pal[ibi->transparent_color], 0);
1293 if(ibi->colortype==COLORTYPE_RGB24) {
1296 else if(ibi->planes_fg<1 || ibi->planes_fg>8) {
1297 de_err(c, "Bad or unsupported number of planes: %d", (int)ibi->planes_fg);
1298 goto done;
1300 retval = 1;
1302 done:
1303 return retval;
1306 static void write_frame(deark *c, lctx *d, struct imgbody_info *ibi, struct frame_ctx *frctx);
1308 static void do_dlta(deark *c, lctx *d, i64 pos1, i64 len)
1310 struct frame_ctx *frctx = d->frctx;
1311 struct frame_ctx *reference_frctx = NULL;
1312 struct imgbody_info *ibi = NULL;
1313 int saved_indent_level;
1315 de_dbg_indent_save(c, &saved_indent_level);
1317 if(d->errflag) goto done;
1318 if(!d->found_bmhd) goto done;
1319 if(!frctx) goto done;
1320 if(frctx->done_flag) goto done;
1321 frctx->done_flag = 1;
1323 // TODO: Should the imgbody_info be saved somewhere, or recalculated for every frame?
1324 ibi = de_malloc(c, sizeof(struct imgbody_info));
1326 do_before_image_chunk(c, d);
1328 if(!init_imgbody_info(c, d, ibi, 0)) {
1329 d->errflag = 1;
1330 goto done;
1333 // Find the reference frame (if it exists).
1334 // It is the highest numbered oldfrctx[] item whose index is at most
1335 // frctx->interleave-1, and which is non-NULL.
1336 if(frctx->interleave>=2) {
1337 reference_frctx = d->oldfrctx[1];
1338 if(!reference_frctx) {
1339 reference_frctx = d->oldfrctx[0];
1342 else {
1343 reference_frctx = d->oldfrctx[0];
1346 // Allocate buffer for this frame
1347 if(!frctx->frame_buffer) {
1348 frctx->frame_buffer = dbuf_create_membuf(c, ibi->frame_buffer_size, 0x1);
1351 // Start by copying the reference frame to this frame. The decompress function
1352 // will then modify this frame.
1353 if(reference_frctx && reference_frctx->frame_buffer) {
1354 dbuf_copy(reference_frctx->frame_buffer, 0, reference_frctx->frame_buffer->len,
1355 frctx->frame_buffer);
1358 switch(frctx->op) {
1359 case 3:
1360 decompress_delta_op3(c, d, ibi, frctx, pos1, len);
1361 break;
1362 case 5:
1363 decompress_delta_op5(c, d, ibi, frctx, pos1, len);
1364 break;
1365 case 7:
1366 decompress_delta_op7(c, d, ibi, frctx, pos1, len);
1367 break;
1368 case 8:
1369 decompress_delta_op8(c, d, ibi, frctx, pos1, len);
1370 break;
1371 case 74:
1372 decompress_delta_op74(c, d, ibi, frctx, pos1, len);
1373 break;
1374 case 108:
1375 decompress_delta_op108(c, d, ibi, frctx, pos1, len);
1376 break;
1377 default:
1378 de_err(c, "Unsupported DLTA operation: %d", (int)frctx->op);
1379 d->errflag = 1;
1381 if(d->errflag) goto done;
1383 if(frctx->change_flag || d->opt_anim_includedups) {
1384 write_frame(c, d, ibi, frctx);
1386 else {
1387 de_dbg(c, "[suppressing duplicate frame]");
1390 done:
1391 // For the summary line, and so we can know when encountering an op for the
1392 // first time.
1393 if(frctx) {
1394 d->delta_ops_used[(size_t)frctx->op] = 1;
1397 de_free(c, ibi);
1398 de_dbg_indent_restore(c, saved_indent_level);
1401 static int decompress_method0(deark *c, lctx *d, i64 pos, i64 len, dbuf *unc_pixels,
1402 i64 expected_len)
1404 i64 amt_to_copy;
1406 amt_to_copy = de_min_int(len, expected_len);
1407 dbuf_copy(c->infile, pos, amt_to_copy, unc_pixels);
1408 return 1;
1411 static int decompress_rgbn8(deark *c, lctx *d, struct imgbody_info *ibi,
1412 i64 pos1, i64 len, dbuf *unc_pixels)
1414 int retval = 0;
1415 i64 pos = pos1;
1416 i64 endpos = pos1+len;
1417 i64 npixels = 0;
1418 i64 npixels_expected;
1419 u8 is_rgb8 = (d->formtype==CODE_RGB8);
1421 npixels_expected = ibi->width * ibi->height;
1423 while(1) {
1424 i64 i;
1425 u32 n;
1426 i64 count;
1427 u8 cbuf[3];
1429 if(npixels >= npixels_expected) {
1430 retval = 1;
1431 goto done;
1433 if(pos >= endpos) {
1434 goto done;
1438 if(is_rgb8) {
1439 n = (u32)de_getu32be_p(&pos);
1440 cbuf[0] = (u8)(n>>24);
1441 cbuf[1] = (u8)((n&0x00ff0000U)>>16);
1442 cbuf[2] = (u8)((n&0x0000ff00U)>>8);
1443 // TODO?: There's also a "genlock" bit that's sort of a transparency mask.
1444 count = (i64)(n & 0x7f);
1446 else {
1447 n = (u32)de_getu16be_p(&pos);
1448 cbuf[0] = (u8)(n>>12);
1449 cbuf[1] = (u8)((n&0x0f00)>>8);
1450 cbuf[2] = (u8)((n&0x00f0)>>4);
1451 for(i=0; i<3; i++) {
1452 cbuf[i] *= 17;
1454 count = (i64)(n & 0x07);
1457 if(count==0) {
1458 u8 c2raw;
1460 c2raw = de_getbyte_p(&pos);
1461 if(c2raw!=0) {
1462 count = (i64)c2raw;
1464 else {
1465 count = de_getu16be_p(&pos);
1469 for(i=0; i<count; i++) {
1470 dbuf_write(unc_pixels, cbuf, 3);
1472 npixels += count;
1475 done:
1476 if(!retval) {
1477 de_err(c, "RGBN/RGB8 decompression failed");
1479 return retval;
1482 static int decompress_ilbm_packbits(deark *c, dbuf *inf, i64 pos, i64 len,
1483 dbuf *unc_pixels, i64 expected_len, UI nbytes_per_unit)
1485 int retval = 0;
1486 struct de_dfilter_in_params dcmpri;
1487 struct de_dfilter_out_params dcmpro;
1488 struct de_dfilter_results dres;
1489 struct de_packbits_params pbparams;
1491 de_zeromem(&pbparams, sizeof(struct de_packbits_params));
1492 pbparams.nbytes_per_unit = nbytes_per_unit;
1493 de_dfilter_init_objects(c, &dcmpri, &dcmpro, &dres);
1494 dcmpri.f = inf;
1495 dcmpri.pos = pos;
1496 dcmpri.len = len;
1497 dcmpro.f = unc_pixels;
1498 dcmpro.len_known = 1;
1499 dcmpro.expected_len = expected_len;
1501 fmtutil_decompress_packbits_ex(c, &dcmpri, &dcmpro, &dres, &pbparams);
1502 dbuf_flush(dcmpro.f);
1503 if(dres.errcode) {
1504 de_err(c, "Decompression failed: %s", dres.errmsg);
1505 goto done;
1507 de_dbg(c, "decompressed %"I64_FMT" to %"I64_FMT" bytes", len, unc_pixels->len);
1508 retval = 1;
1509 done:
1510 return retval;
1513 struct vdat_ctx {
1514 lctx *d;
1515 struct imgbody_info *ibi;
1516 dbuf *unc_pixels;
1517 i64 vdat_chunk_count; // (the plane number)
1518 i64 cur_col;
1519 i64 ypos;
1522 static void vdat_write_element(deark *c, struct vdat_ctx *vdctx, const u8 *elembuf)
1524 i64 dstpos;
1526 dstpos = vdctx->ibi->bytes_per_row_per_plane * vdctx->vdat_chunk_count;
1527 dstpos += 2*vdctx->cur_col;
1528 dstpos += vdctx->ypos * vdctx->ibi->frame_buffer_rowspan;
1530 dbuf_write_at(vdctx->unc_pixels, dstpos, elembuf, 2);
1531 vdctx->ypos++;
1532 if(vdctx->ypos >= vdctx->ibi->height) {
1533 vdctx->ypos = 0;
1534 vdctx->cur_col++;
1538 static void do_vdat_chunk(deark *c, struct vdat_ctx *vdctx, i64 pos1, i64 len)
1540 i64 pos;
1541 i64 endpos;
1542 i64 count;
1543 i64 cmd_cnt;
1544 i64 i, k;
1545 u8 cmd;
1546 u8 *cmds = NULL;
1547 u8 elembuf[2];
1549 vdctx->cur_col = 0;
1550 vdctx->ypos = 0;
1551 pos = pos1;
1552 endpos = pos1+len;
1554 cmd_cnt = de_getu16be(pos); // command count + 2
1555 pos+=2;
1556 cmd_cnt -= 2;
1557 de_dbg(c, "number of command bytes: %d", (int)cmd_cnt);
1558 if(cmd_cnt<1) goto done;
1560 cmds = de_mallocarray(c, cmd_cnt, sizeof(u8));
1562 // Read commands
1563 de_read(cmds, pos, cmd_cnt);
1564 pos += cmd_cnt;
1566 // Read data
1567 for(i=0; i<cmd_cnt; i++) {
1568 if(pos>=endpos) {
1569 break;
1572 cmd = cmds[i];
1574 if(cmd==0x00) {
1575 count = de_getu16be(pos);
1576 pos += 2;
1577 for(k=0; k<count; k++) {
1578 de_read(elembuf, pos, 2);
1579 pos += 2;
1580 vdat_write_element(c, vdctx, elembuf);
1583 else if(cmd==0x01) {
1584 count = de_getu16be(pos);
1585 pos += 2;
1586 de_read(elembuf, pos, 2);
1587 pos += 2;
1588 for(k=0; k<count; k++) {
1589 vdat_write_element(c, vdctx, elembuf);
1592 else if(cmd>=0x80) {
1593 count = (128-(i64)(cmd&0x7f));
1594 for(k=0; k<count; k++) {
1595 de_read(elembuf, pos, 2);
1596 pos += 2;
1597 vdat_write_element(c, vdctx, elembuf);
1600 else { // cmd is from 0x02 to 0x7f
1601 de_read(elembuf, pos, 2);
1602 pos += 2;
1603 count = (i64)cmd;
1604 for(k=0; k<count; k++) {
1605 vdat_write_element(c, vdctx, elembuf);
1610 done:
1611 de_free(c, cmds);
1614 static int my_vdat_chunk_handler(struct de_iffctx *ictx)
1616 deark *c = ictx->c;
1617 struct vdat_ctx *vdctx = (struct vdat_ctx*)ictx->userdata;
1619 if(ictx->chunkctx->chunk4cc.id != CODE_VDAT) {
1620 goto done;
1622 ictx->handled = 1;
1624 if(vdctx->vdat_chunk_count >= vdctx->ibi->planes_total) goto done;
1625 do_vdat_chunk(c, vdctx, ictx->chunkctx->dpos, ictx->chunkctx->dlen);
1627 done:
1628 if(ictx->chunkctx->chunk4cc.id == CODE_VDAT) {
1629 vdctx->vdat_chunk_count++;
1631 return 1;
1634 static int decompress_method2(deark *c, lctx *d, struct imgbody_info *ibi,
1635 i64 pos, i64 len, dbuf *unc_pixels, i64 expected_len)
1637 struct vdat_ctx vdctx;
1638 struct de_iffctx *ictx_vdat = NULL;
1640 // For sanity, we'll use a separate IFF decoder for the contents of this BODY chunk.
1641 de_zeromem(&vdctx, sizeof(struct vdat_ctx));
1642 vdctx.d = d;
1643 vdctx.ibi = ibi;
1644 vdctx.unc_pixels = unc_pixels;
1646 ictx_vdat = fmtutil_create_iff_decoder(c);
1647 ictx_vdat->userdata = (void*)&vdctx;
1648 ictx_vdat->handle_chunk_fn = my_vdat_chunk_handler;
1649 ictx_vdat->f = c->infile;
1650 fmtutil_read_iff_format(ictx_vdat, pos, len);
1652 fmtutil_destroy_iff_decoder(ictx_vdat);
1653 return 1;
1656 // Convert ACBM ABIT image to standard ILBM frame buffer format.
1657 static int convert_abit(deark *c, lctx *d, struct imgbody_info *ibi,
1658 i64 pos, i64 len, dbuf *frame_buffer)
1660 i64 plane, j;
1661 i64 planespan;
1663 planespan = ibi->height * ibi->bytes_per_row_per_plane;
1665 for(plane=0; plane<ibi->planes_total; plane++) {
1666 for(j=0; j<ibi->height; j++) {
1667 dbuf_copy_at(c->infile, pos + plane*planespan + j*ibi->bytes_per_row_per_plane,
1668 ibi->bytes_per_row_per_plane, frame_buffer,
1669 j*ibi->frame_buffer_rowspan + plane*ibi->bytes_per_row_per_plane);
1672 return 1;
1675 // Detect and warn about HAM-E, which we don't support.
1676 static void detect_hame(deark *c, lctx *d, struct imgbody_info *ibi,
1677 struct frame_ctx *frctx)
1679 i64 plane;
1680 i64 k;
1681 UI firstword[4];
1682 u8 pixelval[16];
1683 static const u8 sig[15] = { 0xa, 0x2, 0xf, 0x5, 0x8, 0x4, 0xd, 0xc,
1684 0x6, 0xd, 0xb, 0x0, 0x7, 0xf, 0x1 };
1686 if(d->is_hame) return;
1687 if(d->ham_flag) return;
1688 if(!d->found_cmap) return;
1689 if(ibi->width<640) return;
1690 if(ibi->planes_fg!=4 || ibi->planes_total!=4) return;
1691 if(ibi->is_thumb) return;
1692 if(frctx->formtype!=CODE_ILBM && frctx->formtype!=CODE_ACBM) return;
1693 if(!frctx || !frctx->frame_buffer) return;
1695 // Note: This is quite possibly not the right way to detect HAM-E.
1696 // RECOIL does it by looking up the palette color of each pixel, and using
1697 // certain bits in the palette entry. In all the HAM-E images I have, the
1698 // palette is constructed so as to make that process a no-op.
1700 // Need to examine the values of the first 16 pixels, so need the first 2
1701 // bytes of each of the 4 planes of row 0.
1702 for(plane=0; plane<4; plane++) {
1703 firstword[plane] = (UI)dbuf_getu16be(frctx->frame_buffer,
1704 plane * ibi->bytes_per_row_per_plane);
1707 for(k=0; k<16; k++) {
1708 pixelval[k] = 0;
1709 for(plane=0; plane<4; plane++) {
1710 if(firstword[plane] & (1U<<(15-(UI)k))) {
1711 pixelval[k] |= 1U<<(UI)plane;
1716 if(de_memcmp(pixelval, sig, 15)) return;
1717 if(pixelval[15]!=0x4 && pixelval[15]!=0x8) return;
1719 if(d->opt_allowhame) {
1720 de_warn(c, "This is probably a HAM-E image, which is not supported correctly.");
1722 else {
1723 de_err(c, "HAM-E images are not supported. "
1724 "(\"-opt ilbm:allowspecial\" to decode anyway)");
1725 d->errflag = 1;
1728 d->is_hame = 1;
1731 static int is_dctv_sig_at(dbuf *f, i64 pos)
1733 u8 x;
1735 static const u8 sig[31] = {
1736 0x49, 0x87, 0x28, 0xde, 0x11, 0x0b, 0xef, 0xd2, 0x0c, 0x8e, 0x8b, 0x35, 0x5b, 0x75, 0xec, 0xb8,
1737 0x29, 0x6b, 0x03, 0xf9, 0x2b, 0xb4, 0x34, 0xee, 0x67, 0x1e, 0x7c, 0x4f, 0x53, 0x63, 0x15 };
1739 x = dbuf_getbyte(f, pos);
1740 if(x != sig[0]) return 0;
1741 if(dbuf_memcmp(f, pos, sig, 31)) return 0;
1742 return 1;
1745 // Detect and warn about DCTV, which we don't support.
1746 static void detect_dctv(deark *c, lctx *d, struct imgbody_info *ibi,
1747 struct frame_ctx *frctx)
1749 i64 pos;
1750 int result;
1752 // As far as I can tell, in DCTV images, the last plane of the first row is
1753 // as follows:
1754 // <00> <31-byte signature> <00 fill> <31-byte signature> <00>
1755 // (Sometimes, the last plane of the *second* row is the same.)
1756 // (But I have a 2-plane image in which it's the *first* plane of the first
1757 // two rows that are special. TODO: Figure this out.)
1759 // Unknowns:
1760 // * Is DCTV possible if there are fewer than 64 bytes per row per plane (i.e. width < 512)?
1761 // * Can a DCTV image have transparency?
1762 // * If a DCTV image has a thumbnail image, what format does the thumbnail use?
1764 if(d->is_dctv) return;
1765 if(!frctx || !frctx->frame_buffer) return;
1766 if(ibi->is_thumb) return;
1767 if(frctx->formtype!=CODE_ILBM && frctx->formtype!=CODE_ACBM) return;
1768 if(ibi->bytes_per_row_per_plane<64) return;
1770 // Test end of last plane of first row
1771 pos = d->planes_raw * ibi->bytes_per_row_per_plane - 32;
1772 result = is_dctv_sig_at(frctx->frame_buffer, pos);
1774 if(!result) {
1775 // Test end of first plane of first row
1776 pos = ibi->bytes_per_row_per_plane - 32;
1777 result = is_dctv_sig_at(frctx->frame_buffer, pos);
1780 if(!result) return;
1782 if(d->opt_allowdctv) {
1783 de_warn(c, "This is probably a DCTV image, which is not supported correctly.");
1785 else {
1786 de_err(c, "DCTV images are not supported. "
1787 "(\"-opt ilbm:allowspecial\" to decode anyway)");
1788 d->errflag = 1;
1791 d->is_dctv = 1;
1794 // BODY/ABIT/TINY
1795 static int do_image_chunk_internal(deark *c, lctx *d, struct frame_ctx *frctx, i64 pos1, i64 len, int is_thumb)
1797 struct imgbody_info *ibi = NULL;
1798 int ret;
1799 int retval = 0;
1801 if(d->errflag) goto done;
1802 if(!d->found_bmhd) goto done;
1803 if(!frctx) goto done;
1804 if(frctx->done_flag) goto done;
1805 frctx->done_flag = 1;
1807 ibi = de_malloc(c, sizeof(struct imgbody_info));
1809 do_before_image_chunk(c, d);
1811 if(!init_imgbody_info(c, d, ibi, is_thumb)) {
1812 goto done;
1815 if(!frctx->frame_buffer) {
1816 frctx->frame_buffer = dbuf_create_membuf(c, ibi->frame_buffer_size, 0x1);
1819 if(d->formtype==CODE_ACBM) {
1820 // Note: I don't think ABIT images are ever compressed.
1821 if(!convert_abit(c, d, ibi, pos1, len, frctx->frame_buffer)) goto done;
1823 else if(d->formtype==CODE_RGBN || d->formtype==CODE_RGB8) {
1824 if(!decompress_rgbn8(c, d, ibi, pos1, len, frctx->frame_buffer)) goto done;
1826 else if(ibi->compression==0) {
1827 if(!decompress_method0(c, d, pos1, len, frctx->frame_buffer, ibi->frame_buffer_size)) goto done;
1829 else if(ibi->compression==1) {
1830 dbuf_enable_wbuffer(frctx->frame_buffer);
1831 ret = decompress_ilbm_packbits(c, c->infile, pos1, len,
1832 frctx->frame_buffer, ibi->frame_buffer_size, 1);
1833 dbuf_disable_wbuffer(frctx->frame_buffer);
1834 if(!ret) goto done;
1836 else if(ibi->compression==2) {
1837 if(!decompress_method2(c, d, ibi, pos1, len, frctx->frame_buffer, ibi->frame_buffer_size)) goto done;
1839 else {
1840 de_err(c, "Unsupported compression method: %d", (int)ibi->compression);
1841 goto done;
1844 if(ibi->is_pbm && (frctx->frame_buffer->len != ibi->frame_buffer_size) && (ibi->width%2)) {
1845 if(frctx->frame_buffer->len == ibi->width*ibi->height) {
1846 // Hack: I have some PBM images (e.g. BBM thumbnails) that aren't row-padded.
1847 de_dbg(c, "[assuming rows are not 16-bit padded]");
1848 ibi->bytes_per_row_per_plane = ibi->width;
1849 ibi->bits_per_row_per_plane = ibi->bytes_per_row_per_plane * 8;
1850 ibi->frame_buffer_rowspan = ibi->bytes_per_row_per_plane * ibi->planes_total;
1851 ibi->frame_buffer_size = ibi->frame_buffer_rowspan * ibi->height;
1855 if(frctx->frame_buffer->len != ibi->frame_buffer_size) {
1856 de_warn(c, "Expected %"I64_FMT" decompressed bytes, got %"I64_FMT, ibi->frame_buffer_size,
1857 frctx->frame_buffer->len);
1860 detect_dctv(c, d, ibi, frctx);
1861 detect_hame(c, d, ibi, frctx);
1863 write_frame(c, d, ibi, frctx);
1865 retval = 1;
1867 done:
1868 de_free(c, ibi);
1869 return retval;
1872 static void do_body_or_abit(deark *c, lctx *d, struct de_iffctx *ictx, i64 pos1, i64 len)
1874 if(!de_good_image_dimensions(c, d->width, d->height)) {
1875 d->errflag = 1;
1876 goto done;
1878 if(!do_image_chunk_internal(c, d, d->frctx, pos1, len, 0)) {
1879 d->errflag = 1;
1880 goto done;
1882 done:
1886 static void do_tiny(deark *c, lctx *d, i64 pos1, i64 len)
1888 struct frame_ctx *frctx = NULL;
1889 i64 pos = pos1;
1891 if(len<=4) goto done;
1893 d->thumb_width = de_getu16be_p(&pos);
1894 d->thumb_height = de_getu16be_p(&pos);
1895 de_dbg(c, "thumbnail image, dimensions: %d"DE_CHAR_TIMES"%d", (int)d->thumb_width, (int)d->thumb_height);
1896 if(!de_good_image_dimensions_noerr(c, d->thumb_width, d->thumb_height)) {
1897 de_warn(c, "Bad thumbnail image dimensions");
1898 goto done;
1901 frctx = create_frame(c, d);
1902 (void)do_image_chunk_internal(c, d, frctx, pos, pos1+len-pos, 1);
1904 done:
1905 destroy_frame(c, d, frctx);
1908 // A few ILBM files with extension ".iff24" have this chunk, as
1909 // do some DEEP files.
1910 static void do_xs24(deark *c, dbuf *f, i64 pos1, i64 len)
1912 i64 w, h, rowspan;
1913 i64 pos = pos1;
1914 de_bitmap *img = NULL;
1916 w = de_getu16be_p(&pos);
1917 rowspan = w*3;
1918 h = de_getu16be_p(&pos);
1919 de_dbg(c, "24-bit thumbnail image, dimensions: %u"DE_CHAR_TIMES"%u", (UI)w, (UI)h);
1920 if(!de_good_image_dimensions_noerr(c, w, h)) goto done;
1921 if(rowspan*h+6 != len) goto done;
1922 pos += 2; // unknown field
1924 img = de_bitmap_create(c, w, h, 3);
1925 de_convert_image_rgb(f, pos, rowspan, 3, img, 0);
1926 de_bitmap_write_to_file(img, "thumb", DE_CREATEFLAG_IS_AUX|DE_CREATEFLAG_OPT_IMAGE);
1927 done:
1928 de_bitmap_destroy(img);
1931 static void get_bits_descr(deark *c, lctx *d, struct frame_ctx *frctx, de_ucstring *s)
1933 UI bits = frctx->bits;
1935 if(frctx->op==4 || frctx->op==5 || frctx->op==7 || frctx->op==8) {
1936 if(bits & 0x1) {
1937 ucstring_append_flags_item(s, "long data");
1938 bits -= 0x1;
1939 d->uses_anim_long_data = 1;
1942 if(frctx->op==4 || frctx->op==5) {
1943 if(bits & 0x2) {
1944 ucstring_append_flags_item(s, "XOR");
1945 bits -= 0x2;
1946 d->uses_anim4_5_xor_mode = 1;
1948 if(bits & 0x4) {
1949 ucstring_append_flags_item(s, "one info list");
1950 bits -= 0x4;
1952 if(bits & 0x8) {
1953 ucstring_append_flags_item(s, "RLC");
1954 bits -= 0x8;
1956 if(bits & 0x10) {
1957 ucstring_append_flags_item(s, "vertical");
1958 bits -= 0x10;
1960 if(bits & 0x20) {
1961 ucstring_append_flags_item(s, "long info offsets");
1962 bits -= 0x20;
1966 if(bits!=0) {
1967 ucstring_append_flags_itemf(s, "0x%08x", bits);
1971 static void do_anim_anhd(deark *c, lctx *d, i64 pos, i64 len)
1973 i64 tmp;
1974 u8 ileave_raw;
1975 de_ucstring *bits_descr = NULL;
1976 struct frame_ctx *frctx = d->frctx;
1978 if(!frctx) return;
1979 if(len<24) return;
1981 frctx->op = de_getbyte(pos++);
1982 de_dbg(c, "operation: %d (%s)", (int)frctx->op, anim_get_op_name(frctx->op));
1984 if(frctx->op==ANIM_OP_XOR) {
1985 pos++; // Mask
1986 pos += 2; // w
1987 pos += 2; // h
1988 pos += 2; // x
1989 pos += 2; // y
1991 else {
1992 pos += 9;
1994 pos += 4; // abstime
1996 tmp = de_getu32be_p(&pos); // reltime
1997 de_dbg(c, "reltime: %.5f sec", ((double)tmp)/60.0);
1999 ileave_raw = de_getbyte_p(&pos);
2000 de_dbg(c, "interleave: %d", (int)ileave_raw);
2001 if(ileave_raw==0) {
2002 frctx->interleave = 2;
2004 else {
2005 frctx->interleave = (UI)ileave_raw;
2007 if(frctx->interleave>2 && !d->errflag) {
2008 de_err(c, "Unsupported interleave");
2009 d->errflag = 1;
2012 pos++; // pad0
2014 frctx->bits = (UI)de_getu32be_p(&pos);
2015 bits_descr = ucstring_create(c);
2016 get_bits_descr(c, d, frctx, bits_descr);
2017 de_dbg(c, "bits: 0x%08x (%s)", frctx->bits, ucstring_getpsz_d(bits_descr));
2019 ucstring_destroy(bits_descr);
2022 static void do_camg(deark *c, lctx *d, i64 pos, i64 len)
2024 if(len<4) return;
2025 d->has_camg = 1;
2026 d->camg_changed_flag = 1;
2028 d->ham_flag = 0;
2029 d->is_ham6 = 0;
2030 d->is_ham8 = 0;
2031 d->ehb_flag = 0;
2033 d->camg_mode = (UI)de_getu32be(pos);
2034 de_dbg(c, "CAMG mode: 0x%x", d->camg_mode);
2036 if(d->camg_mode & 0x0800)
2037 d->ham_flag = 1;
2038 if(d->camg_mode & 0x0080)
2039 d->ehb_flag = 1;
2041 if(d->formtype==CODE_RGBN || d->formtype==CODE_RGB8) {
2042 d->ham_flag = 0;
2043 d->ehb_flag = 0;
2046 de_dbg_indent(c, 1);
2047 de_dbg(c, "HAM: %d", (int)d->ham_flag);
2048 de_dbg(c, "EHB: %d", (int)d->ehb_flag);
2049 de_dbg_indent(c, -1);
2052 static void do_dpi(deark *c, lctx *d, i64 pos, i64 len)
2054 if(len<4) return;
2055 d->x_dpi = de_getu16be(pos);
2056 d->y_dpi = de_getu16be(pos+2);
2057 de_dbg(c, "dpi: %d"DE_CHAR_TIMES"%d", (int)d->x_dpi, (int)d->y_dpi);
2060 static void do_grab(deark *c, lctx *d, i64 pos, i64 len)
2062 if(len<4) return;
2063 d->has_hotspot = 1;
2064 d->hotspot_x = (int)de_getu16be(pos);
2065 d->hotspot_y = (int)de_getu16be(pos+2);
2066 de_dbg(c, "hotspot: (%d, %d)", d->hotspot_x, d->hotspot_y);
2069 static void do_dpan(deark *c, lctx *d, i64 pos, i64 len)
2071 i64 nframes;
2073 if(!d->is_anim) return;
2074 if(len<4) return;
2075 nframes = de_getu16be(pos+2);
2076 de_dbg(c, "number of frames: %d", (int)nframes);
2079 static void do_crng(deark *c, lctx *d, i64 pos1, i64 len)
2081 UI tmp1, tmp2;
2083 if(len<8) return;
2084 tmp1 = (UI)de_getu16be(pos1+2);
2085 tmp2 = (UI)de_getu16be(pos1+4);
2086 de_dbg(c, "CRNG flags: 0x%04x", tmp2);
2087 if(tmp2&0x1) {
2088 de_dbg(c, "rate: %.2f fps", (double)(((double)tmp1)*(60.0/16384.0)));
2089 on_color_cycling_enabled(c, d);
2093 static void do_drng(deark *c, lctx *d, i64 pos1, i64 len)
2095 UI tmp2;
2097 tmp2 = (UI)de_getu16be(pos1+4);
2098 de_dbg(c, "DRNG flags: 0x%04x", tmp2);
2099 if(tmp2&0x1) {
2100 on_color_cycling_enabled(c, d);
2104 // Graphicraft Color Cycling Range and Timing
2105 static void do_ccrt(deark *c, lctx *d, i64 pos1, i64 len)
2107 i64 tmp1;
2109 tmp1 = de_geti16be(pos1);
2110 de_dbg(c, "cycling direction: %d", (int)tmp1);
2111 if(tmp1!=0) {
2112 d->uses_color_cycling = 1;
2116 // Frame sequencing chunk used in ANIM-J
2117 static void do_ansq(deark *c, lctx *d, i64 pos1, i64 len)
2119 i64 num_items;
2120 i64 i;
2122 // TODO: Figure out how critical this ANSQ info is.
2123 // If deltas are supposed to be applied out of sequence, we could at least
2124 // emit a warning.
2126 num_items = len / 4;
2127 de_dbg(c, "number of frames in sequence: %d", (int)num_items);
2128 if(c->debug_level<2) return;
2129 de_dbg_indent(c, 1);
2130 for(i=0; i<num_items && i<2000; i++) {
2131 i64 frnum, dur;
2133 frnum = de_getu16be(pos1+i*4);
2134 dur = de_getu16be(pos1+i*4+2);
2135 de_dbg2(c, "item[%d]: frame=%d, dur=%d", (int)i, (int)frnum, (int)dur);
2137 de_dbg_indent(c, -1);
2140 static void render_pixel_row_ham6(deark *c, lctx *d, i64 rownum, const u32 *rowbuf,
2141 UI rowbuf_size, de_bitmap *img)
2143 UI i;
2144 u8 cr, cg, cb;
2146 // At the beginning of each row, the color accumulators are
2147 // initialized to palette entry 0.
2148 cr = DE_COLOR_R(d->pal[0]);
2149 cg = DE_COLOR_G(d->pal[0]);
2150 cb = DE_COLOR_B(d->pal[0]);
2152 for(i=0; i<rowbuf_size; i++) {
2153 u32 clr;
2154 u8 val = rowbuf[i] & 0xff;
2156 switch((val>>4)&0x3) {
2157 case 0x1: // Modify blue value
2158 cb = 17*(val&0x0f);
2159 break;
2160 case 0x2: // Modify red value
2161 cr = 17*(val&0x0f);
2162 break;
2163 case 0x3: // Modify green value
2164 cg = 17*(val&0x0f);
2165 break;
2166 default: // 0: Use colormap value
2167 clr = d->pal[(UI)val];
2168 cr = DE_COLOR_R(clr);
2169 cg = DE_COLOR_G(clr);
2170 cb = DE_COLOR_B(clr);
2171 break;
2174 de_bitmap_setpixel_rgb(img, (i64)i, rownum, DE_MAKE_RGB(cr, cg, cb));
2178 static void render_pixel_row_ham8(deark *c, lctx *d, i64 rownum, const u32 *rowbuf,
2179 UI rowbuf_size, de_bitmap *img)
2181 UI i;
2182 u8 cr, cg, cb;
2184 // At the beginning of each row, the color accumulators are
2185 // initialized to palette entry 0.
2186 cr = DE_COLOR_R(d->pal[0]);
2187 cg = DE_COLOR_G(d->pal[0]);
2188 cb = DE_COLOR_B(d->pal[0]);
2190 for(i=0; i<rowbuf_size; i++) {
2191 u32 clr;
2192 u8 val = rowbuf[i] & 0xff;
2194 switch((val>>6)&0x3) {
2195 case 0x1:
2196 cb = ((val&0x3f)<<2)|((val&0x3f)>>4);
2197 break;
2198 case 0x2:
2199 cr = ((val&0x3f)<<2)|((val&0x3f)>>4);
2200 break;
2201 case 0x3:
2202 cg = ((val&0x3f)<<2)|((val&0x3f)>>4);
2203 break;
2204 default:
2205 clr = d->pal[(UI)val];
2206 cr = DE_COLOR_R(clr);
2207 cg = DE_COLOR_G(clr);
2208 cb = DE_COLOR_B(clr);
2209 break;
2212 de_bitmap_setpixel_rgb(img, (i64)i, rownum, DE_MAKE_RGB(cr, cg, cb));
2216 static void render_pixel_row_normal(deark *c, lctx *d, struct imgbody_info *ibi,
2217 i64 rownum, const u32 *rowbuf, UI rowbuf_size, de_bitmap *img)
2219 UI k;
2221 for(k=0; k<rowbuf_size; k++) {
2222 de_bitmap_setpixel_rgb(img, (i64)k, rownum, d->pal[(UI)rowbuf[k] & 0xff]);
2226 static void render_pixel_row_rgb24(deark *c, lctx *d, struct imgbody_info *ibi,
2227 i64 rownum, const u32 *rowbuf, UI rowbuf_size, de_bitmap *img)
2229 UI k;
2231 for(k=0; k<rowbuf_size; k++) {
2232 UI r, g, b;
2234 r = (rowbuf[k] & 0x0000ff);
2235 g = (rowbuf[k] & 0x00ff00)>>8;
2236 b = (rowbuf[k] & 0xff0000)>>16;
2237 de_bitmap_setpixel_rgb(img, (i64)k, rownum, DE_MAKE_RGB(r, g, b));
2241 static void set_finfo_data(deark *c, lctx *d, struct imgbody_info *ibi, de_finfo *fi)
2243 int has_aspect = 0;
2244 int has_dpi = 0;
2246 if(ibi->is_thumb) {
2247 de_finfo_set_name_from_sz(c, fi, "thumb", 0, DE_ENCODING_LATIN1);
2250 if(d->x_aspect>0 && d->y_aspect>0) {
2251 has_aspect = 1;
2253 if(!ibi->is_thumb && d->x_dpi>0 && d->y_dpi>0) {
2254 has_dpi = 1;
2257 if(has_dpi) {
2258 fi->density.code = DE_DENSITY_DPI;
2259 fi->density.xdens = (double)d->x_dpi;
2260 fi->density.ydens = (double)d->y_dpi;
2262 else if(has_aspect) {
2263 fi->density.code = DE_DENSITY_UNK_UNITS;
2264 fi->density.ydens = (double)d->x_aspect;
2265 fi->density.xdens = (double)d->y_aspect;
2268 if(!ibi->is_thumb && d->has_hotspot) {
2269 fi->has_hotspot = 1;
2270 fi->hotspot_x = d->hotspot_x;
2271 fi->hotspot_y = d->hotspot_y;
2275 // Generate the final image and write it to a file.
2276 static void write_frame(deark *c, lctx *d, struct imgbody_info *ibi, struct frame_ctx *frctx)
2278 de_bitmap *img = NULL;
2279 i64 j;
2280 u32 *rowbuf = NULL; // The current row of pixel (palette or RGB) values
2281 u8 *rowbuf_trns = NULL; // The current row's 1-bit transparency mask values
2282 UI rowbuf_size;
2283 int bypp;
2284 de_finfo *fi = NULL;
2285 UI createflags = 0;
2286 u32 pixelval[8];
2287 u8 pixeltrnsval[8];
2289 if(d->errflag) goto done;
2290 if(!frctx) goto done;
2291 if(!frctx->frame_buffer) {
2292 d->errflag = 1;
2293 goto done;
2295 if(ibi->colortype==COLORTYPE_RGB24) {
2296 if(ibi->planes_fg!=24) goto done;
2298 else if(ibi->planes_fg<1 || ibi->planes_fg>8) {
2299 goto done;
2302 if(d->debug_frame_buffer) {
2303 de_finfo *fi_fb;
2305 fi_fb = de_finfo_create(c);
2306 de_finfo_set_name_from_sz(c, fi_fb, "fb", 0, DE_ENCODING_LATIN1);
2307 de_convert_and_write_image_bilevel(frctx->frame_buffer, 0,
2308 ibi->bits_per_row_per_plane * ibi->planes_total,
2309 ibi->height, ibi->frame_buffer_rowspan, 0, fi_fb, 0);
2310 de_finfo_destroy(c, fi_fb);
2313 rowbuf_size = (UI)ibi->width;
2314 rowbuf = de_mallocarray(c, rowbuf_size, sizeof(rowbuf[0]));
2315 rowbuf_trns = de_mallocarray(c, rowbuf_size, sizeof(rowbuf_trns[0]));
2317 if(ibi->is_rgb24) {
2318 bypp = 3;
2320 else if(d->found_cmap && d->pal_is_grayscale && d->planes_raw<=8 && !d->is_ham6 && !d->is_ham8) {
2321 bypp = 1;
2323 else {
2324 bypp = 3;
2327 if(ibi->use_colorkey_transparency || ibi->masking_code==MASKINGTYPE_1BITMASK) {
2328 bypp++;
2331 img = de_bitmap_create(c, ibi->width, ibi->height, bypp);
2333 if(ibi->is_pbm) {
2334 de_convert_image_paletted(frctx->frame_buffer, 0, 8, ibi->frame_buffer_rowspan,
2335 d->pal, img, 0);
2336 goto after_render;
2338 else if(ibi->is_rgb24) {
2339 de_convert_image_rgb(frctx->frame_buffer, 0, ibi->bytes_per_row_per_plane, 3,
2340 img, 0);
2341 goto after_render;
2344 for(j=0; j<ibi->height; j++) {
2345 i64 z;
2346 i64 plane;
2347 UI k;
2349 // Process 8 pixels at a time
2350 for(z=0; z<ibi->bytes_per_row_per_plane; z++) {
2351 de_zeromem(pixelval, sizeof(pixelval));
2352 de_zeromem(pixeltrnsval, sizeof(pixeltrnsval));
2354 // Read the zth byte in each plane
2355 for(plane=0; plane<ibi->planes_total; plane++) {
2356 u8 b;
2358 b = dbuf_getbyte(frctx->frame_buffer,
2359 j*ibi->frame_buffer_rowspan +
2360 plane*ibi->bytes_per_row_per_plane + z);
2362 for(k=0; k<8; k++) {
2363 if(b & (1U<<(7-k))) {
2364 if(plane < ibi->planes_fg) {
2365 pixelval[k] |= 1U<<(UI)plane;
2367 else {
2368 // The only way this can happen is if this plane is a
2369 // 1-bit transparency mask.
2370 pixeltrnsval[k] = 1;
2376 for(k=0; k<8; k++) {
2377 UI idx;
2379 idx = (UI)z*8+k;
2380 if(idx < rowbuf_size) {
2381 rowbuf[idx] = pixelval[k];
2382 rowbuf_trns[idx] = pixeltrnsval[k];
2387 if(ibi->colortype==COLORTYPE_RGB24) {
2388 render_pixel_row_rgb24(c, d, ibi, j, rowbuf, rowbuf_size, img);
2390 else if(d->is_ham6) {
2391 render_pixel_row_ham6(c, d, j, rowbuf, rowbuf_size, img);
2393 else if(d->is_ham8) {
2394 render_pixel_row_ham8(c, d, j, rowbuf, rowbuf_size, img);
2396 else {
2397 render_pixel_row_normal(c, d, ibi, j, rowbuf, rowbuf_size, img);
2400 // Handle 1-bit transparency masks here, for all color types.
2401 if(ibi->masking_code==MASKINGTYPE_1BITMASK) {
2402 i64 i;
2404 for(i=0; i<rowbuf_size; i++) {
2405 u32 clr;
2407 if(rowbuf_trns[i]==0) {
2408 clr = de_bitmap_getpixel(img, i, j);
2409 clr = DE_SET_ALPHA(clr, 0);
2410 de_bitmap_setpixel_rgba(img, i, j, clr);
2416 after_render:
2417 if(d->trans_setting==TRANS_AUTO) {
2418 if(ibi->masking_code==MASKINGTYPE_1BITMASK) {
2419 de_bitmap_optimize_alpha(img, 0x2|0x4);
2422 else if(d->trans_setting==TRANS_REMOVE) {
2423 de_bitmap_remove_alpha(img);
2426 fi = de_finfo_create(c);
2427 set_finfo_data(c, d, ibi, fi);
2428 if(ibi->is_thumb) {
2429 createflags |= DE_CREATEFLAG_IS_AUX;
2431 if(!d->is_anim) {
2432 // TODO: Enable this for ANIM?
2433 createflags |= DE_CREATEFLAG_OPT_IMAGE;
2436 de_bitmap_write_to_file_finfo(img, fi, createflags);
2438 done:
2439 de_bitmap_destroy(img);
2440 de_finfo_destroy(c, fi);
2441 de_free(c, rowbuf);
2442 de_free(c, rowbuf_trns);
2445 static void on_frame_begin(deark *c, lctx *d, u32 formtype)
2447 if(d->frctx) return;
2448 d->num_frames_started++;
2449 d->frctx = create_frame(c, d);
2450 d->frctx->formtype = formtype;
2451 d->frctx->frame_idx = d->num_frames_finished;
2452 if(d->is_anim) de_dbg(c, "[frame #%d begin]", d->frctx->frame_idx);
2455 static void on_frame_end(deark *c, lctx *d)
2457 if(!d->frctx) return;
2459 if(d->is_anim) de_dbg(c, "[frame #%d end]", d->frctx->frame_idx);
2461 destroy_frame(c, d, d->oldfrctx[1]); // Destroy the frame that's aged out
2462 d->oldfrctx[1] = d->oldfrctx[0]; // Make room for the new frame
2463 d->oldfrctx[0] = d->frctx; // Save the new frame
2464 d->frctx = NULL;
2465 d->num_frames_finished++;
2468 static int my_iff_chunk_handler(struct de_iffctx *ictx)
2470 deark *c = ictx->c;
2471 int quitflag = 0;
2472 lctx *d = (lctx*)ictx->userdata;
2474 if(d->num_frames_finished >= ANIM_MAX_FRAMES) {
2475 quitflag = 1;
2476 goto done;
2479 // Chunks that we support even if they are not in FORM:ILBM, FORM:PBM, etc. chunk.
2481 switch(ictx->chunkctx->chunk4cc.id) {
2482 case CODE_FORM:
2483 if(ictx->level==0) {
2484 // Remember this for later
2485 d->main_chunk_endpos = ictx->chunkctx->dpos + ictx->chunkctx->dlen;
2487 if(ictx->level>d->FORM_level) break;
2488 ictx->is_std_container = 1;
2489 goto done;
2492 // Chunks that we process only inside a FORM:ILBM, etc. chunk.
2494 if(!d->frctx) goto done;
2496 switch(ictx->chunkctx->chunk4cc.id) {
2497 case CODE_BMHD:
2498 ictx->handled = 1;
2499 if(!do_bmhd(c, d, ictx->chunkctx->dpos, ictx->chunkctx->dlen)) {
2500 d->errflag = 1;
2501 goto done;
2503 break;
2505 case CODE_ANHD:
2506 do_anim_anhd(c, d, ictx->chunkctx->dpos, ictx->chunkctx->dlen);
2507 ictx->handled = 1;
2508 break;
2510 case CODE_CMAP:
2511 do_cmap(c, d, ictx->chunkctx->dpos, ictx->chunkctx->dlen);
2512 ictx->handled = 1;
2513 break;
2515 case CODE_CAMG:
2516 do_camg(c, d, ictx->chunkctx->dpos, ictx->chunkctx->dlen);
2517 ictx->handled = 1;
2518 break;
2520 case CODE_BODY:
2521 case CODE_ABIT:
2522 ictx->handled = 1;
2523 do_body_or_abit(c, d, ictx, ictx->chunkctx->dpos, ictx->chunkctx->dlen);
2524 break;
2526 case CODE_DLTA:
2527 ictx->handled = 1;
2528 if(ictx->curr_container_contentstype4cc.id != CODE_ILBM) {
2529 d->errflag = 1;
2530 goto done;
2532 do_dlta(c, d, ictx->chunkctx->dpos, ictx->chunkctx->dlen);
2533 break;
2535 case CODE_TINY:
2536 do_tiny(c, d, ictx->chunkctx->dpos, ictx->chunkctx->dlen);
2537 ictx->handled = 1;
2538 break;
2539 case CODE_XS24:
2540 do_xs24(c, ictx->f, ictx->chunkctx->dpos, ictx->chunkctx->dlen);
2541 ictx->handled = 1;
2542 break;
2544 case CODE_DPI:
2545 do_dpi(c, d, ictx->chunkctx->dpos, ictx->chunkctx->dlen);
2546 ictx->handled = 1;
2547 break;
2548 case CODE_GRAB:
2549 do_grab(c, d, ictx->chunkctx->dpos, ictx->chunkctx->dlen);
2550 ictx->handled = 1;
2551 break;
2552 case CODE_DPAN:
2553 do_dpan(c, d, ictx->chunkctx->dpos, ictx->chunkctx->dlen);
2554 ictx->handled = 1;
2555 break;
2556 case CODE_CRNG:
2557 do_crng(c, d, ictx->chunkctx->dpos, ictx->chunkctx->dlen);
2558 ictx->handled = 1;
2559 break;
2560 case CODE_DRNG:
2561 do_drng(c, d, ictx->chunkctx->dpos, ictx->chunkctx->dlen);
2562 ictx->handled = 1;
2563 break;
2564 case CODE_CCRT:
2565 do_ccrt(c, d, ictx->chunkctx->dpos, ictx->chunkctx->dlen);
2566 ictx->handled = 1;
2567 break;
2568 case CODE_SHAM:
2569 d->is_sham = 1;
2570 on_multipalette_enabled(c, d);
2571 break;
2572 case CODE_PCHG:
2573 d->is_pchg = 1;
2574 on_multipalette_enabled(c, d);
2575 break;
2576 case CODE_CTBL:
2577 d->is_ctbl = 1;
2578 on_multipalette_enabled(c, d);
2579 break;
2580 case CODE_BEAM:
2581 d->is_beam = 1;
2582 on_multipalette_enabled(c, d);
2583 break;
2584 case CODE_CLUT:
2585 d->found_clut = 1;
2586 break;
2587 case CODE_ANSQ:
2588 do_ansq(c, d, ictx->chunkctx->dpos, ictx->chunkctx->dlen);
2589 ictx->handled = 1;
2590 break;
2591 case CODE_SBDY:
2592 if(d->is_anim && !d->found_audio) {
2593 de_info(c, "Note: This file includes AnimFX-style audio, which is "
2594 "not supported.");
2595 d->found_audio = 1;
2597 break;
2600 done:
2601 return (quitflag) ? 0 : 1;
2604 static int my_preprocess_iff_chunk_fn(struct de_iffctx *ictx)
2606 lctx *d = (lctx*)ictx->userdata;
2607 const char *name = NULL;
2609 // frctx will be set if we're in an "image" container, such as FORM:ILBM.
2610 // It is possible, e.g., for an ANIM file to contain FORM:8SVX containers
2611 // which contain BODY chunks that are not "image data".
2612 if(d->frctx) {
2613 switch(ictx->chunkctx->chunk4cc.id) {
2614 case CODE_ANHD: name="animation header"; break;
2615 case CODE_BMHD: name="bitmap header"; break;
2616 case CODE_BODY: name="image data"; break;
2617 case CODE_CAMG: name="Amiga viewport mode"; break;
2618 case CODE_CMAP: name="color map"; break;
2619 case CODE_CRNG: name="color register range info"; break;
2620 case CODE_DLTA: name="delta-compressed data"; break;
2621 case CODE_DPI : name="dots/inch"; break;
2622 case CODE_DRNG: name="color cycle"; break;
2623 case CODE_GRAB: name="hotspot"; break;
2624 case CODE_TINY: name="thumbnail"; break;
2628 if(name) {
2629 ictx->chunkctx->chunk_name = name;
2631 return 1;
2634 static int my_on_std_container_start_fn(struct de_iffctx *ictx)
2636 deark *c = ictx->c;
2637 lctx *d = (lctx*)ictx->userdata;
2639 if(ictx->level==d->FORM_level) {
2640 if(d->frctx) {
2641 on_frame_end(c, d);
2643 if((ictx->curr_container_contentstype4cc.id == CODE_ILBM) ||
2644 (ictx->curr_container_contentstype4cc.id == CODE_PBM) ||
2645 (ictx->curr_container_contentstype4cc.id == CODE_ACBM) ||
2646 (ictx->curr_container_contentstype4cc.id == CODE_RGBN) ||
2647 (ictx->curr_container_contentstype4cc.id == CODE_RGB8))
2649 on_frame_begin(c, d, ictx->curr_container_contentstype4cc.id);
2651 else {
2652 if(d->is_anim) {
2653 if(ictx->curr_container_contentstype4cc.id == CODE_8SVX) {
2654 d->found_audio = 1;
2656 if(!d->extra_content_warned) {
2657 de_warn(c, "File includes unsupported content of type '%s'",
2658 ictx->curr_container_contentstype4cc.id_sanitized_sz);
2659 d->extra_content_warned = 1;
2662 else {
2663 de_err(c, "Unsupported ILBM-like format");
2664 d->errflag = 1;
2668 return 1;
2671 static void look_for_RAST(deark *c, lctx *d, i64 pos)
2673 if(d->found_rast) return;
2674 if(!dbuf_memcmp(c->infile, pos, "RAST", 4)) {
2675 d->found_rast = 1;
2679 static void do_eof_stuff(deark *c, lctx *d)
2681 i64 endpos, endpos_padded;
2682 i64 extra_bytes;
2684 endpos = d->main_chunk_endpos;
2685 if(endpos<1) return;
2686 endpos_padded = de_pad_to_2(endpos);
2687 extra_bytes = c->infile->len - endpos_padded;
2688 if(extra_bytes<1) return;
2689 de_dbg(c, "[found %"I64_FMT" extra bytes at end of file, starting at %"I64_FMT"]",
2690 extra_bytes, endpos_padded);
2692 look_for_RAST(c, d, endpos);
2693 if(endpos_padded!=endpos) {
2694 look_for_RAST(c, d, endpos_padded);
2696 if(d->found_rast) {
2697 de_warn(c, "Possible RAST data found, which is not supported. "
2698 "Image might not be decoded correctly.");
2702 static int my_on_container_end_fn(struct de_iffctx *ictx)
2704 if(ictx->level==0) {
2705 // Stop after the first top-level chunk (the FORM chunk).
2706 return 0;
2708 return 1;
2711 static void summary_append(de_ucstring *s, const char *fmt, ...)
2712 de_gnuc_attribute ((format (printf, 2, 3)));
2714 static void summary_append(de_ucstring *s, const char *fmt, ...)
2716 va_list ap;
2718 ucstring_append_char(s, ' ');
2719 va_start(ap, fmt);
2720 ucstring_vprintf(s, DE_ENCODING_LATIN1, fmt, ap);
2721 va_end(ap);
2724 // Print a summary line indicating the main characteristics of this file.
2725 static void print_summary(deark *c, lctx *d)
2727 de_ucstring *s = NULL;
2728 size_t k;
2730 if(c->debug_level<1) goto done;
2731 if(!d->found_bmhd) goto done;
2733 s = ucstring_create(c);
2735 summary_append(s,"%s", d->formtype_sanitized_sz);
2736 summary_append(s, "planes=%d", (int)d->planes_raw);
2737 if(d->masking_code!=0) summary_append(s, "masking=%d", (int)d->masking_code);
2738 summary_append(s, "cmpr=%d", (int)d->compression);
2739 for(k=0; k<256; k++) {
2740 if(d->delta_ops_used[k]) {
2741 summary_append(s, "delta%u", (UI)k);
2744 if(d->uses_anim_long_data) summary_append(s, "long_data");
2745 if(d->uses_anim4_5_xor_mode) summary_append(s, "xor_mode");
2747 if(d->ham_flag) summary_append(s, "HAM");
2748 if(d->ehb_flag) summary_append(s, "EHB");
2749 if(d->is_sham) summary_append(s, "SHAM");
2750 if(d->is_pchg) summary_append(s, "PCHG");
2751 if(d->is_ctbl) summary_append(s, "CTBL");
2752 if(d->is_beam) summary_append(s, "BEAM");
2753 if(d->is_hame) summary_append(s, "HAM-E");
2754 if(d->is_dctv) summary_append(s, "DCTV");
2755 if(d->found_rast) summary_append(s, "RAST");
2756 if(d->uses_color_cycling) summary_append(s, "color-cycling");
2757 if(d->found_clut) summary_append(s, "CLUT");
2758 if(d->found_audio) summary_append(s, "audio");
2759 if(!d->found_cmap) summary_append(s, "no-CMAP");
2761 de_dbg(c, "summary:%s", ucstring_getpsz(s));
2763 done:
2764 ucstring_destroy(s);
2767 static void strip_trailing_space_sz(char *sz)
2769 size_t n;
2771 n = de_strlen(sz);
2772 if(n>1 && sz[n-1]==0x20) {
2773 sz[n-1] = '\0';
2777 static void de_run_ilbm_or_anim(deark *c, de_module_params *mparams)
2779 u32 id;
2780 u8 opt_notrans = 0;
2781 u8 opt_fixpal;
2782 int opt;
2783 const char *opt_trans_str;
2784 lctx *d = NULL;
2785 struct de_iffctx *ictx = NULL;
2786 struct de_fourcc formtype_4cc;
2788 d = de_malloc(c, sizeof(lctx));
2789 opt_fixpal = (u8)de_get_ext_option_bool(c, "ilbm:fixpal", 0xff);
2791 opt_trans_str = de_get_ext_option(c, "ilbm:trans");
2793 if(!opt_trans_str) {
2794 if(de_get_ext_option(c, "ilbm:notrans")) { // Deprecated option
2795 opt_notrans = 1;
2799 if(de_get_ext_option_bool(c, "ilbm:allowspecial", 0)) {
2800 d->opt_allowsham = 1;
2801 d->opt_allowdctv = 1;
2802 d->opt_allowhame = 1;
2804 // allowsham is deprecated
2805 opt = de_get_ext_option_bool(c, "ilbm:allowsham", -1);
2806 if(opt==0) d->opt_allowsham = 0;
2807 else if(opt>0) d->opt_allowsham = 1;
2809 id = (u32)de_getu32be(0);
2810 if(id!=CODE_FORM) {
2811 de_err(c, "Not an IFF file");
2812 goto done;
2815 dbuf_read_fourcc(c->infile, 8, &formtype_4cc, 4, 0);
2816 d->formtype = formtype_4cc.id;
2817 de_strlcpy(d->formtype_sanitized_sz, formtype_4cc.id_sanitized_sz, sizeof(d->formtype_sanitized_sz));
2819 // A quick hack, so we have "PBM" instead of "PBM ".
2820 // TODO: Maybe dbuf_read_fourcc should do this, or have an option to.
2821 strip_trailing_space_sz(d->formtype_sanitized_sz);
2823 switch(d->formtype) {
2824 case CODE_ANIM:
2825 d->is_anim = 1;
2826 break;
2827 case CODE_ILBM:
2828 case CODE_ACBM:
2829 case CODE_PBM:
2830 case CODE_RGBN:
2831 case CODE_RGB8:
2832 break;
2833 default:
2834 de_err(c, "Not a supported ILBM-like format (%s)", d->formtype_sanitized_sz);
2835 goto done;
2837 de_declare_fmtf(c, "IFF-%s", d->formtype_sanitized_sz);
2839 if(d->is_anim) {
2840 d->opt_anim_includedups = (u8)de_get_ext_option_bool(c, "anim:includedups", 0);
2843 if(opt_fixpal==0xff) {
2844 // Fixpal option defaults to No for ANIM format, othersize Yes.
2845 // (The concern with ANIM is that we don't want frame 1's colors
2846 // to fail to match frame 2's colors.)
2847 d->fixpal_setting = (d->is_anim ? 0 : 1);
2849 else {
2850 d->fixpal_setting = opt_fixpal;
2853 // Default for d->trans_setting
2854 if(d->is_anim) {
2855 // I don't think AUTO makes sense for ANIM.
2856 d->trans_setting = TRANS_RESPECT;
2858 else {
2859 d->trans_setting = TRANS_AUTO;
2862 if(opt_trans_str) {
2863 if(!de_strcmp(opt_trans_str, "auto")) {
2864 d->trans_setting = TRANS_AUTO;
2866 else if(!de_strcmp(opt_trans_str, "")) {
2867 d->trans_setting = TRANS_RESPECT;
2869 else {
2870 int opt_trans_n;
2872 opt_trans_n = de_atoi(opt_trans_str);
2873 if(opt_trans_n==0) {
2874 d->trans_setting = TRANS_REMOVE;
2876 else if(opt_trans_n>0) {
2877 d->trans_setting = TRANS_RESPECT;
2881 else if(opt_notrans) {
2882 d->trans_setting = TRANS_REMOVE;
2885 d->FORM_level = d->is_anim ? 1 : 0;
2887 ictx = fmtutil_create_iff_decoder(c);
2888 ictx->has_standard_iff_chunks = 1;
2889 ictx->userdata = (void*)d;
2890 ictx->input_encoding = de_get_input_encoding(c, NULL, DE_ENCODING_ASCII);
2891 ictx->handle_chunk_fn = my_iff_chunk_handler;
2892 ictx->preprocess_chunk_fn = my_preprocess_iff_chunk_fn;
2893 ictx->on_std_container_start_fn = my_on_std_container_start_fn;
2894 ictx->on_container_end_fn = my_on_container_end_fn;
2895 ictx->f = c->infile;
2896 fmtutil_read_iff_format(ictx, 0, c->infile->len);
2898 if(d->frctx) {
2899 on_frame_end(c, d);
2901 do_eof_stuff(c, d);
2902 print_summary(c, d);
2904 done:
2905 fmtutil_destroy_iff_decoder(ictx);
2906 if(d) {
2907 destroy_frame(c, d, d->frctx);
2908 destroy_frame(c, d, d->oldfrctx[0]);
2909 destroy_frame(c, d, d->oldfrctx[1]);
2910 de_free(c, d);
2914 static void de_run_ilbm(deark *c, de_module_params *mparams)
2916 de_run_ilbm_or_anim(c, mparams);
2919 static void de_run_anim(deark *c, de_module_params *mparams)
2921 de_run_ilbm_or_anim(c, mparams);
2924 static int de_identify_ilbm(deark *c)
2926 u32 id;
2928 id = (u32)de_getu32be(0);
2929 if(id!=CODE_FORM) return 0;
2930 id = (u32)de_getu32be(8);
2931 switch(id) {
2932 case CODE_ILBM:
2933 case CODE_PBM:
2934 case CODE_ACBM:
2935 case CODE_RGBN:
2936 case CODE_RGB8:
2937 return 100;
2939 return 0;
2942 static int de_identify_anim(deark *c)
2944 u32 id;
2946 id = (u32)de_getu32be(0);
2947 if(id!=CODE_FORM) return 0;
2948 id = (u32)de_getu32be(8);
2949 if(id==CODE_ANIM) return 100;
2950 return 0;
2953 static void do_help_ilbm_anim(deark *c, int is_anim)
2955 de_msg(c, "-opt ilbm:trans=<0|1|auto> : Always remove (0) or respect (1) "
2956 "transparency");
2957 de_msg(c, "-opt ilbm:fixpal=<0|1> : Don't/Do try to fix palettes that are "
2958 "slightly too dark");
2959 de_msg(c, "-opt ilbm:allowspecial : Suppress an error on some images");
2960 if(is_anim) {
2961 de_msg(c, "-opt anim:includedups : Do not suppress duplicate frames");
2965 static void de_help_ilbm(deark *c)
2967 do_help_ilbm_anim(c, 0);
2970 static void de_help_anim(deark *c)
2972 do_help_ilbm_anim(c, 1);
2975 void de_module_ilbm(deark *c, struct deark_module_info *mi)
2977 mi->id = "ilbm";
2978 mi->desc = "IFF-ILBM and related image formats";
2979 mi->run_fn = de_run_ilbm;
2980 mi->identify_fn = de_identify_ilbm;
2981 mi->help_fn = de_help_ilbm;
2984 void de_module_anim(deark *c, struct deark_module_info *mi)
2986 mi->id = "anim";
2987 mi->desc = "IFF-ANIM animation";
2988 mi->run_fn = de_run_anim;
2989 mi->identify_fn = de_identify_anim;
2990 mi->help_fn = de_help_anim;
2993 ///// IFF-DEEP
2995 #define CODE_DBOD 0x44424f44U
2996 #define CODE_DEEP 0x44454550U
2997 #define CODE_DGBL 0x4447424cU
2998 #define CODE_DLOC 0x444c4f43U
2999 #define CODE_DPEL 0x4450454cU
3000 #define CODE_MPIC 0x4d504943U
3001 #define CODE_TVDC 0x54564443U
3002 #define CODE_TVPP 0x54565050U
3004 #define DEEP_MAX_COMPONENTS 8
3006 struct deep_ctx {
3007 UI cmpr_meth;
3008 int DBOD_count;
3009 u8 trans_setting; // TRANS_*
3010 u8 found_DLOC;
3011 u8 found_TVDC;
3012 u8 found_DPEL;
3013 i64 dspw, dsph;
3014 i64 width, height;
3015 i64 x_aspect, y_aspect;
3016 i64 expected_image_size;
3017 i64 num_components;
3018 u8 have_alpha;
3019 u8 have_alpha_hint; // Preliminary, set while reading DPEL
3020 u8 is_assoc_alpha;
3021 UI cmp_nbits[DEEP_MAX_COMPONENTS];
3022 UI cmp_type[DEEP_MAX_COMPONENTS];
3023 UI sample_map[DEEP_MAX_COMPONENTS];
3024 u8 tvdc_data[32];
3027 static void do_deep_DGBL(deark *c, struct deep_ctx *d, struct de_iffctx *ictx)
3029 i64 pos = ictx->chunkctx->dpos;
3031 d->dspw = dbuf_getu16be_p(ictx->f, &pos);
3032 d->dsph = dbuf_getu16be_p(ictx->f, &pos);
3033 de_dbg(c, "display size: %"I64_FMT DE_CHAR_TIMES "%"I64_FMT, d->dspw, d->dsph);
3034 if(!d->found_DLOC) {
3035 d->width = d->dspw;
3036 d->height = d->dsph;
3038 d->cmpr_meth = (UI)dbuf_getu16be_p(ictx->f, &pos);
3039 de_dbg(c, "cmpr meth: %u", d->cmpr_meth);
3040 d->x_aspect = (i64)dbuf_getbyte_p(ictx->f, &pos);
3041 d->y_aspect = (i64)dbuf_getbyte_p(ictx->f, &pos);
3042 de_dbg(c, "aspect ratio: %d, %d", (int)d->x_aspect, (int)d->y_aspect);
3045 static void do_deep_DLOC(deark *c, struct deep_ctx *d, struct de_iffctx *ictx)
3047 i64 pos = ictx->chunkctx->dpos;
3048 i64 pixpos_x, pixpos_y;
3050 d->found_DLOC = 1;
3051 d->width = dbuf_getu16be_p(ictx->f, &pos);
3052 d->height = dbuf_getu16be_p(ictx->f, &pos);
3053 de_dbg_dimensions(c, d->width, d->height);
3054 pixpos_x = dbuf_geti16be_p(ictx->f, &pos);
3055 pixpos_y = dbuf_geti16be_p(ictx->f, &pos);
3056 de_dbg(c, "position: %"I64_FMT", %"I64_FMT, pixpos_x, pixpos_y);
3059 static void do_deep_DPEL(deark *c, struct deep_ctx *d, struct de_iffctx *ictx)
3061 i64 pos = ictx->chunkctx->dpos;
3062 i64 endpos = ictx->chunkctx->dpos + ictx->chunkctx->dlen;
3063 UI i;
3065 d->found_DPEL = 1;
3066 d->num_components = (UI)dbuf_getu32be_p(ictx->f, &pos);
3067 de_dbg(c, "num cmpts: %u", (UI)d->num_components);
3068 if(d->num_components>DEEP_MAX_COMPONENTS) {
3069 d->num_components = 0;
3070 goto done;
3072 for(i=0; i<d->num_components; i++) {
3073 if(pos+4 > endpos) break;
3074 d->cmp_type[i] = (UI)dbuf_getu16be_p(ictx->f, &pos);
3075 if(d->cmp_type[i]==4 || d->cmp_type[i]==17) {
3076 d->have_alpha_hint = 1;
3078 d->cmp_nbits[i] = (UI)dbuf_getu16be_p(ictx->f, &pos);
3079 de_dbg(c, "cmpt[%u]: type=%u depth=%u", i, d->cmp_type[i], d->cmp_nbits[i]);
3081 done:
3085 // Sets d->sample_map[], d->have_alpha...
3086 // If unsupported image type, reports an error and returns 0.
3087 static int deep_make_sample_map(deark *c, struct deep_ctx *d)
3089 UI k;
3090 u8 flags[5] = {0,0,0,0,0};
3091 int retval = 0;
3093 de_zeromem(d->sample_map, sizeof(d->sample_map));
3094 d->have_alpha = 0;
3095 d->is_assoc_alpha = 0;
3097 if(d->num_components<3 || d->num_components>DEEP_MAX_COMPONENTS) {
3098 goto done;
3101 for(k=0; k<(UI)d->num_components; k++) {
3102 switch(d->cmp_type[k]) {
3103 case 1:
3104 d->sample_map[k] = 0;
3105 break;
3106 case 2:
3107 d->sample_map[k] = 1;
3108 break;
3109 case 3:
3110 d->sample_map[k] = 2;
3111 break;
3112 case 4:
3113 d->sample_map[k] = 3;
3114 d->have_alpha = 1;
3115 d->is_assoc_alpha = 0;
3116 break;
3117 case 17: // Undocumented type 17 used in Video Toaster "Brushes" files.
3118 d->sample_map[k] = 3;
3119 d->have_alpha = 1;
3120 d->is_assoc_alpha = 1;
3121 break;
3122 default:
3123 d->sample_map[k] = 4;
3126 flags[d->sample_map[k]] = 1;
3129 if(!flags[0] || !flags[1] || !flags[2]) { // Need R, G, B
3130 goto done;
3132 if(flags[4]) { // Found an unsupported sample type
3133 de_warn(c, "Image type not fully supported");
3135 retval = 1;
3137 done:
3138 if(!retval) {
3139 de_err(c, "Unsupported image type");
3141 return retval;
3144 static void deep_decode_image_unc(deark *c, struct deep_ctx *d,
3145 dbuf *f, i64 pos1, i64 len)
3147 i64 i, j;
3148 i64 pos = pos1;
3149 UI k;
3150 UI dst_samples_per_pixel;
3151 de_bitmap *img = NULL;
3152 de_finfo *fi = NULL;
3153 u8 s[5] = {0,0,0,0,0};
3155 fi = de_finfo_create(c);
3156 if(d->x_aspect && d->y_aspect) {
3157 fi->density.code = DE_DENSITY_UNK_UNITS;
3158 fi->density.ydens = (double)d->x_aspect;
3159 fi->density.xdens = (double)d->y_aspect;
3162 dst_samples_per_pixel = d->have_alpha ? 4 : 3;
3163 img = de_bitmap_create(c, d->width, d->height, dst_samples_per_pixel);
3165 for(j=0; j<d->height; j++) {
3166 for(i=0; i<d->width; i++) {
3167 de_color clr;
3169 if(pos > pos1+len) {
3170 de_warn(c, "Premature end of image");
3171 goto after_image;
3174 for(k=0; k<(UI)d->num_components; k++) {
3175 s[d->sample_map[k]] = dbuf_getbyte_p(f, &pos);
3177 if(d->have_alpha) {
3178 clr = DE_MAKE_RGBA(s[0], s[1], s[2], s[3]);
3179 if(d->is_assoc_alpha) {
3180 clr = de_unpremultiply_alpha_clr(clr);
3183 else {
3184 clr = DE_MAKE_RGB(s[0], s[1], s[2]);
3186 de_bitmap_setpixel_rgba(img, i, j, clr);
3190 after_image:
3191 if(d->trans_setting==TRANS_AUTO) {
3192 de_bitmap_optimize_alpha(img, (0x4|0x02));
3194 else if(d->trans_setting==TRANS_REMOVE) {
3195 de_bitmap_remove_alpha(img);
3197 de_bitmap_write_to_file_finfo(img, fi, DE_CREATEFLAG_OPT_IMAGE);
3199 de_bitmap_destroy(img);
3200 de_finfo_destroy(c, fi);
3203 static int decompress_deep_5(deark *c, struct deep_ctx *d, dbuf *inf,
3204 i64 pos1, i64 len, dbuf *unc_pixels)
3206 i64 xpos = 0;
3207 i64 ypos = 0;
3208 i64 output_pos = 0;
3209 i64 curr_component = 0;
3210 u8 v = 0;
3211 int retval = 0;
3212 struct de_bitreader bitrd;
3214 de_zeromem(&bitrd, sizeof(struct de_bitreader));
3215 bitrd.f = inf;
3216 bitrd.curpos = pos1;
3217 bitrd.endpos = pos1+len;
3218 bitrd.bbll.is_lsb = 0;
3219 dbuf_disable_wbuffer(unc_pixels);
3221 if(!d->found_TVDC) {
3222 de_err(c, "Missing TVDC chunk");
3223 goto done;
3225 retval = 1;
3227 while(1) {
3228 UI n;
3229 UI k;
3230 UI count;
3232 n = (UI)de_bitreader_getbits(&bitrd, 4);
3233 if(bitrd.eof_flag) goto done;
3235 if(d->tvdc_data[n*2+1]!=0 || d->tvdc_data[n*2]!=0) {
3236 v += (u8)(d->tvdc_data[n*2+1]);
3237 count = 1;
3239 else {
3240 n = (UI)de_bitreader_getbits(&bitrd, 4);
3241 count = n+1;
3244 for(k=0; k<count; k++) {
3245 dbuf_writebyte_at(unc_pixels, output_pos, v);
3246 output_pos += d->num_components;
3247 xpos++;
3248 if(xpos >= d->width) break;
3251 if(xpos >= d->width) {
3252 de_bitreader_skip_to_byte_boundary(&bitrd);
3253 xpos = 0;
3254 v = 0;
3255 curr_component++;
3256 if(curr_component >= d->num_components) {
3257 ypos++;
3258 if(ypos >= d->height) goto done;
3259 curr_component = 0;
3261 output_pos = ypos*(d->width * d->num_components) + curr_component;
3265 done:
3266 return retval;
3269 static void deep_decompress_and_decode_image(deark *c, struct deep_ctx *d,
3270 dbuf *f, i64 pos1, i64 len)
3272 int ret;
3273 dbuf *unc_pixels = NULL;
3275 unc_pixels = dbuf_create_membuf(c, d->expected_image_size, 0x1);
3276 if(d->cmpr_meth!=5) {
3277 dbuf_enable_wbuffer(unc_pixels);
3279 if(d->cmpr_meth==5) {
3280 ret = decompress_deep_5(c, d, f, pos1, len, unc_pixels);
3282 else {
3283 ret = decompress_ilbm_packbits(c, f, pos1, len, unc_pixels, d->expected_image_size,
3284 (UI)d->num_components);
3286 dbuf_flush(unc_pixels);
3287 if(!ret) goto done;
3289 deep_decode_image_unc(c, d, unc_pixels, 0, unc_pixels->len);
3290 done:
3291 dbuf_close(unc_pixels);
3294 static void do_deep_DBOD(deark *c, struct deep_ctx *d, struct de_iffctx *ictx)
3296 if(d->cmpr_meth!=0 && d->cmpr_meth!=1 && d->cmpr_meth!=5) {
3297 de_err(c, "Unsupported compression type: %u", d->cmpr_meth);
3298 goto done;
3301 if(!deep_make_sample_map(c, d)) goto done;
3303 if(!de_good_image_dimensions(c, d->width, d->height)) {
3304 goto done;
3307 d->expected_image_size = d->width * d->height * d->num_components;
3309 if(d->cmpr_meth==0) {
3310 deep_decode_image_unc(c, d, ictx->f, ictx->chunkctx->dpos,
3311 ictx->chunkctx->dlen);
3313 else {
3314 deep_decompress_and_decode_image(c, d, ictx->f, ictx->chunkctx->dpos,
3315 ictx->chunkctx->dlen);
3318 done:
3322 static void convert_image_rgba(dbuf *f, i64 fpos,
3323 de_bitmap *img)
3325 i64 i, j;
3326 de_color clr;
3327 i64 pos;
3328 u8 buf[4];
3330 pos = fpos;
3331 for(j=0; j<img->height; j++) {
3332 for(i=0; i<img->width; i++) {
3333 dbuf_read(f, buf, pos, 4);
3334 pos += 4;
3335 clr = DE_MAKE_RGBA(buf[0], buf[1], buf[2], buf[3]);
3336 de_bitmap_setpixel_rgba(img, i, j, clr);
3341 static void do_deep_mpic(deark *c, struct deep_ctx *d, dbuf *f, i64 pos1, i64 len)
3343 i64 w, h, rowspan;
3344 i64 pos = pos1;
3345 UI n;
3346 u8 ok = 0;
3347 de_bitmap *img = NULL;
3349 w = de_getu16be_p(&pos);
3350 rowspan = w*4;
3351 h = de_getu16be_p(&pos);
3352 de_dbg(c, "32-bit thumbnail image, dimensions: %u"DE_CHAR_TIMES"%u", (UI)w, (UI)h);
3354 // I have no documentation for MPIC.
3355 // I'm guessing that it's always RGBA or RGBx, and doesn't depend on DPEL.
3356 // I have some images where DBOD has 3 components, and MPIC has 4 components.
3357 // So I'm guessing that MPIC is *not* defined to be "the same format as DBOD".
3359 // Not sure what these fields are. First one might be sample count.
3360 n = (UI)de_getu32be_p(&pos);
3361 if(n != 0x00040002) goto done;
3363 if(pos + rowspan*h > pos1+len) goto done;
3365 img = de_bitmap_create(c, w, h, 4);
3366 convert_image_rgba(f, pos, img);
3368 // If the main image doesn't have an alpha channel, we assume the MPIC
3369 // thumbnail doesn't have transparency.
3370 if(d->trans_setting==TRANS_REMOVE || (d->found_DPEL && d->have_alpha_hint==0)) {
3371 de_bitmap_remove_alpha(img);
3373 else if(d->trans_setting==TRANS_AUTO) {
3374 de_bitmap_optimize_alpha(img, 0x1);
3377 de_bitmap_write_to_file(img, "thumb", DE_CREATEFLAG_IS_AUX|DE_CREATEFLAG_OPT_IMAGE);
3378 ok = 1;
3380 done:
3381 if(!ok) {
3382 de_warn(c, "Unsupported MPIC thumbnail");
3384 de_bitmap_destroy(img);
3388 static int my_deep_chunk_handler(struct de_iffctx *ictx)
3390 deark *c = ictx->c;
3391 struct deep_ctx *d = (struct deep_ctx*)ictx->userdata;
3393 switch(ictx->chunkctx->chunk4cc.id) {
3394 case CODE_FORM:
3395 ictx->is_std_container = 1;
3396 goto done;
3399 if(ictx->level != 1) goto done;
3401 switch(ictx->chunkctx->chunk4cc.id) {
3402 case CODE_DGBL:
3403 do_deep_DGBL(c, d, ictx);
3404 ictx->handled = 1;
3405 break;
3406 case CODE_DLOC:
3407 do_deep_DLOC(c, d, ictx);
3408 ictx->handled = 1;
3409 break;
3410 case CODE_DPEL:
3411 do_deep_DPEL(c, d, ictx);
3412 ictx->handled = 1;
3413 break;
3414 case CODE_DBOD:
3415 do_deep_DBOD(c, d, ictx);
3416 d->DBOD_count++;
3417 ictx->handled = 1;
3418 break;
3419 case CODE_TVDC:
3420 d->found_TVDC = 1;
3421 dbuf_read(ictx->f, d->tvdc_data, ictx->chunkctx->dpos, sizeof(d->tvdc_data));
3422 // Don't set ictx->handled, since we don't emit dbg info.
3423 break;
3424 case CODE_MPIC:
3425 do_deep_mpic(c, d, ictx->f, ictx->chunkctx->dpos, ictx->chunkctx->dlen);
3426 ictx->handled = 1;
3427 break;
3428 case CODE_XS24:
3429 do_xs24(c, ictx->f, ictx->chunkctx->dpos, ictx->chunkctx->dlen);
3430 ictx->handled = 1;
3431 break;
3434 done:
3435 return 1;
3438 static void de_run_deep(deark *c, de_module_params *mparams)
3440 struct deep_ctx *d = NULL;
3441 struct de_iffctx *ictx = NULL;
3442 const char *opt_trans_str;
3444 d = de_malloc(c, sizeof(struct deep_ctx));
3446 d->trans_setting = TRANS_AUTO; // default
3447 opt_trans_str = de_get_ext_option(c, "deep:trans");
3448 if(opt_trans_str) {
3449 if(!de_strcmp(opt_trans_str, "auto")) {
3450 d->trans_setting = TRANS_AUTO;
3452 else if(!de_strcmp(opt_trans_str, "")) {
3453 d->trans_setting = TRANS_RESPECT;
3455 else {
3456 int opt_trans_n;
3458 opt_trans_n = de_atoi(opt_trans_str);
3459 if(opt_trans_n==0) {
3460 d->trans_setting = TRANS_REMOVE;
3462 else if(opt_trans_n>0) {
3463 d->trans_setting = TRANS_RESPECT;
3468 de_declare_fmt(c, "IFF-DEEP");
3470 ictx = fmtutil_create_iff_decoder(c);
3471 ictx->has_standard_iff_chunks = 1;
3472 ictx->alignment = 2;
3473 ictx->userdata = (void*)d;
3474 ictx->handle_chunk_fn = my_deep_chunk_handler;
3475 ictx->f = c->infile;
3477 fmtutil_read_iff_format(ictx, 0, c->infile->len);
3478 de_dbg(c, "image count: %d", d->DBOD_count);
3480 fmtutil_destroy_iff_decoder(ictx);
3481 if(d) {
3482 de_free(c, d);
3486 static int de_identify_deep(deark *c)
3488 UI n;
3490 if((UI)de_getu32be(0)!=CODE_FORM) return 0;
3491 n = (UI)de_getu32be(8);
3492 if(n==CODE_DEEP || n==CODE_TVPP) return 100;
3493 return 0;
3496 static void de_help_deep(deark *c)
3498 de_msg(c, "-opt deep:trans=<0|1|auto> : Always remove (0) or respect (1) "
3499 "transparency");
3502 void de_module_deep(deark *c, struct deark_module_info *mi)
3504 mi->id = "deep";
3505 mi->desc = "IFF-DEEP";
3506 mi->run_fn = de_run_deep;
3507 mi->identify_fn = de_identify_deep;
3508 mi->help_fn = de_help_deep;