New "ea_data" module
[deark.git] / modules / fli.c
blobcfb5ebc85b7c9a6ae95b344c95f0cab4ce2f0c8d
1 // This file is part of Deark.
2 // Copyright (C) 2020 Jason Summers
3 // See the file COPYING for terms of use.
5 // FLI/FLC animation
7 #include <deark-config.h>
8 #include <deark-private.h>
9 DE_DECLARE_MODULE(de_module_fli);
11 #define CHUNKTYPE_COLORMAP256 0x0004
12 #define CHUNKTYPE_DELTA_FLC 0x0007
13 #define CHUNKTYPE_COLORMAP64 0x000b
14 #define CHUNKTYPE_DELTA_FLI 0x000c
15 #define CHUNKTYPE_BLACK 0x000d
16 #define CHUNKTYPE_RLE 0x000f
17 #define CHUNKTYPE_COPY 0x0010
18 #define CHUNKTYPE_THUMBNAIL 0x0012
19 #define CHUNKTYPE_FLI 0xaf11
20 #define CHUNKTYPE_FLC 0xaf12
21 #define CHUNKTYPE_PREFIX 0xf100
22 #define CHUNKTYPE_FRAME 0xf1fa
24 // Unfortunately, the above chunk types are sometimes context-sensitive.
25 // So we'll define our own types that are not.
26 enum mapped_chunktype_enum {
27 MCT_UNKNOWN = 0x10001,
28 MCT_NONE,
29 MCT_FLI_OR_FLC,
30 MCT_FRAME,
31 MCT_PREFIX,
32 MCT_COLORMAP,
33 MCT_COPY,
34 MCT_BLACK,
35 MCT_RLE,
36 MCT_DELTA_FLI,
37 MCT_DELTA_FLC,
38 MCT_THUMBNAIL,
39 MCT_SETTINGS,
40 MCT_ONESETTING,
41 MCT_CELDATA
44 struct localctx_struct;
45 typedef struct localctx_struct lctx;
46 struct chunk_info_type;
48 typedef void (*chunk_handler_type)(deark *c, lctx *d, struct chunk_info_type *ci);
50 struct image_ctx_type {
51 i64 w;
52 i64 h;
53 int use_count;
54 int error_flag;
55 struct de_density_info density;
56 de_bitmap *img;
57 u32 pal[256];
60 struct chunk_info_type {
61 UI chunktype;
62 int level;
63 enum mapped_chunktype_enum mct;
64 i64 pos;
65 i64 len;
67 struct chunk_info_type *parent;
68 chunk_handler_type handler_fn;
69 const char *chunk_type_name;
71 // Current image context. Can be NULL. Do not free this directly.
72 struct image_ctx_type *ictx;
75 struct localctx_struct {
76 UI main_chunktype;
77 i64 num_frames;
78 i64 frame_count;
79 struct de_timestamp create_timestamp;
80 struct de_timestamp mod_timestamp;
81 int depth;
82 i64 aspect_x;
83 i64 aspect_y;
86 // Caller supplies pal[256]
87 static void make_6cube_pal(u32 *pal)
89 UI r, g, b;
90 UI k;
92 for(k=0; k<216; k++) {
93 b = (k%6) * 51;
94 g = ((k/6)%6) * 51;
95 r = (k/36) * 51;
96 pal[k] = DE_MAKE_RGB(r, g, b);
100 static struct image_ctx_type *create_image_ctx(deark *c, lctx *d, i64 w, i64 h)
102 struct image_ctx_type *ictx;
104 ictx = de_malloc(c, sizeof(struct image_ctx_type));
105 ictx->w = w;
106 ictx->h = h;
107 ictx->img = de_bitmap_create(c, w, h, 3);
108 return ictx;
111 static void destroy_image_ctx(deark *c, struct image_ctx_type *ictx)
113 if(!ictx) return;
114 if(ictx->img) {
115 de_bitmap_destroy(ictx->img);
117 de_free(c, ictx);
120 static void do_sequence_of_chunks(deark *c, lctx *d, struct chunk_info_type *parent_ci,
121 i64 pos1, i64 max_nchunks);
123 static void do_chunk_rle(deark *c, lctx *d, struct chunk_info_type *ci)
125 i64 xpos = 0;
126 i64 ypos = 0;
127 i64 pos = ci->pos + 6;
128 struct image_ctx_type *ictx;
130 if(!ci->ictx) goto done;
131 de_dbg(c, "doing RLE decompression");
132 ictx = ci->ictx;
133 ictx->use_count++;
134 pos++; // First byte of each line is a packet count (not needed)
136 while(1) {
137 UI clridx;
138 u8 code;
139 i64 count;
140 i64 k;
142 if(pos >= ci->pos + ci->len) break;
144 code = de_getbyte_p(&pos); // packet type/size
145 if(code >= 128) { // "negative" = run of uncompressed pixels
146 count = (i64)256 - (i64)code;
147 for(k=0; k<count; k++) {
148 clridx = (UI)de_getbyte_p(&pos);
149 de_bitmap_setpixel_rgb(ictx->img, xpos, ypos, ictx->pal[clridx]);
150 xpos++;
153 else { // "positive" = RLE
154 count = (i64)code;
155 clridx = (UI)de_getbyte_p(&pos);
156 for(k=0; k<count; k++) {
157 de_bitmap_setpixel_rgb(ictx->img, xpos, ypos, ictx->pal[clridx]);
158 xpos++;
162 if(xpos >= ictx->w) {
163 xpos = 0;
164 ypos++;
165 pos++; // packet count
166 if(ypos>=ictx->h) break;
170 done:
174 static void do_chunk_delta_fli(deark *c, lctx *d, struct chunk_info_type *ci)
176 i64 ypos;
177 i64 num_encoded_lines;
178 i64 line_idx;
179 i64 pos = ci->pos + 6;
180 struct image_ctx_type *ictx;
182 if(!ci->ictx) goto done;
183 de_dbg(c, "doing delta (FLI-style) decompression");
184 ictx = ci->ictx;
185 ictx->use_count++;
187 ypos = de_getu16le_p(&pos);
188 num_encoded_lines = de_getu16le_p(&pos);
190 for(line_idx=0; line_idx<num_encoded_lines; line_idx++) {
191 UI npackets;
192 UI pkidx;
193 i64 xpos = 0;
195 if(pos >= ci->pos + ci->len) goto done;
197 npackets = (UI)de_getbyte_p(&pos);
199 for(pkidx=0; pkidx<npackets; pkidx++) {
200 UI clridx;
201 u8 code;
202 i64 count;
203 i64 k;
204 i64 skip_count;
206 if(pos >= ci->pos + ci->len) goto done;
207 skip_count = (i64)de_getbyte_p(&pos);
208 xpos += skip_count;
209 code = de_getbyte_p(&pos);
210 if(code<128) { // "positive" = run of uncompressed pixels
211 count = (i64)code;
212 for(k=0; k<count; k++) {
213 clridx = (UI)de_getbyte_p(&pos);
214 de_bitmap_setpixel_rgb(ictx->img, xpos, ypos, ictx->pal[clridx]);
215 xpos++;
218 else { // "negative" = RLE
219 clridx = (UI)de_getbyte_p(&pos);
220 count = (i64)256 - (i64)code;
221 for(k=0; k<count; k++) {
222 de_bitmap_setpixel_rgb(ictx->img, xpos, ypos, ictx->pal[clridx]);
223 xpos++;
228 ypos++;
231 done:
235 static void do_chunk_delta_flc(deark *c, lctx *d, struct chunk_info_type *ci)
237 i64 ypos = 0;
238 i64 num_encoded_lines;
239 i64 line_idx;
240 i64 pos = ci->pos + 6;
241 struct image_ctx_type *ictx;
243 if(!ci->ictx) goto done;
244 de_dbg(c, "doing delta (FLC-style) decompression");
245 ictx = ci->ictx;
246 ictx->use_count++;
248 num_encoded_lines = de_getu16le_p(&pos);
250 for(line_idx=0; line_idx<num_encoded_lines; line_idx++) {
251 UI npackets = 0;
252 UI pkidx;
253 UI wcode, wcode_hi;
254 i64 xpos = 0;
256 // Read code words until we find one the high 2 bits == 0.
257 while(1) {
258 if(pos >= ci->pos + ci->len) goto done;
260 wcode = (UI)de_getu16le_p(&pos);
261 wcode_hi = wcode>>14;
263 if(wcode_hi==0) {
264 npackets = wcode;
265 break;
267 else if(wcode_hi==3) {
268 ypos += (i64)65536 - (i64)wcode;
270 else if(wcode_hi==2) {
271 // Set the "last byte of current line".
272 // (UNTESTED) This feature is only expected to be used if the
273 // screen width is odd, and I haven't found such a file.
274 de_bitmap_setpixel_rgb(ictx->img, ictx->w-1, ypos, ictx->pal[wcode & 0x00ff]);
278 for(pkidx=0; pkidx<npackets; pkidx++) {
279 UI clridx, clridx2;
280 u8 code;
281 i64 count;
282 i64 k;
283 i64 skip_count;
285 if(pos >= ci->pos + ci->len) goto done;
286 skip_count = (i64)de_getbyte_p(&pos);
287 xpos += skip_count;
288 code = de_getbyte_p(&pos);
289 if(code<128) { // "positive" = run of uncompressed pixels
290 count = 2 * (i64)code;
291 for(k=0; k<count; k++) {
292 clridx = (UI)de_getbyte_p(&pos);
293 de_bitmap_setpixel_rgb(ictx->img, xpos, ypos, ictx->pal[clridx]);
294 xpos++;
297 else { // "negative" = RLE
298 count = (i64)256 - (i64)code;
299 clridx = (UI)de_getbyte_p(&pos);
300 clridx2 = (UI)de_getbyte_p(&pos);
301 for(k=0; k<count; k++) {
302 de_bitmap_setpixel_rgb(ictx->img, xpos, ypos, ictx->pal[clridx]);
303 xpos++;
304 de_bitmap_setpixel_rgb(ictx->img, xpos, ypos, ictx->pal[clridx2]);
305 xpos++;
310 ypos++;
313 done:
317 // (UNTESTED)
318 static void do_chunk_copy(deark *c, lctx *d, struct chunk_info_type *ci)
320 if(!ci->ictx) return;
321 ci->ictx->use_count++;
322 de_convert_image_paletted(c->infile, ci->pos, 8, ci->ictx->w, ci->ictx->pal,
323 ci->ictx->img, 0);
326 // (UNTESTED)
327 static void do_chunk_black(deark *c, lctx *d, struct chunk_info_type *ci)
329 if(!ci->ictx) return;
330 de_bitmap_rect(ci->ictx->img, 0, 0, ci->ictx->w, ci->ictx->h,
331 ci->ictx->pal[0], 0);
334 static void do_chunk_colormap(deark *c, lctx *d, struct chunk_info_type *ci)
336 i64 npackets;
337 i64 pknum;
338 i64 pos = ci->pos + 6;
339 int bps;
340 UI num_entries_total = 0;
341 UI next_idx = 0;
343 if(!ci->ictx) return;
344 if(ci->chunktype==CHUNKTYPE_COLORMAP256)
345 bps = 8;
346 else
347 bps = 6;
348 npackets = de_getu16le_p(&pos);
350 for(pknum=0; pknum<npackets; pknum++) {
351 UI num_entries_to_skip;
352 UI num_entries_to_set;
353 UI k;
355 if(pos >= ci->pos + ci->len) goto done;
356 num_entries_to_skip = (UI)de_getbyte_p(&pos);
357 next_idx += num_entries_to_skip;
358 num_entries_to_set = (UI)de_getbyte_p(&pos);
359 if(num_entries_to_set==0) num_entries_to_set = 256;
360 num_entries_total += num_entries_to_set;
362 for(k=0; k<num_entries_to_set; k++) {
363 u8 samp[3];
364 u32 clr;
365 UI z;
367 for(z=0; z<3; z++) {
368 samp[z] = de_getbyte_p(&pos);
369 if(bps==6) {
370 samp[z] = de_scale_63_to_255(samp[z]);
374 clr = DE_MAKE_RGB(samp[0], samp[1], samp[2]);
375 if(next_idx < 256) {
376 ci->ictx->pal[next_idx] = clr;
377 de_dbg_pal_entry(c, (i64)next_idx, clr);
379 next_idx++;
382 done:
383 de_dbg(c, "number of entries: %u", num_entries_total);
386 static void dbg_id(deark *c, lctx *d, i64 pos, const char *name)
388 i64 n;
389 struct de_fourcc id4cc;
391 n = de_getu32le(pos);
392 if(n<0x01000000) {
393 de_dbg(c, "%s: %"I64_FMT,name, n);
394 return;
396 dbuf_read_fourcc(c->infile, pos, &id4cc, 4, 0x0);
397 de_dbg(c, "%s: %"I64_FMT" (0x%08x, '%s')", name, n, (UI)n,
398 id4cc.id_dbgstr);
401 static void read_timestamp(deark *c, lctx *d, i64 pos, struct de_timestamp *ts,
402 const char *name)
404 i64 datetime_raw;
405 i64 date_raw, time_raw;
406 struct de_timestamp tmp_timestamp;
407 char timestamp_buf[64];
409 de_zeromem(ts, sizeof(struct de_timestamp));
411 // The timestamp is said to be "MS-DOS formatted", but that's uncomfortably
412 // vague, and bogus timestamps seem to be common.
414 datetime_raw = de_getu32le_p(&pos);
415 de_dbg(c, "%s time: %"I64_FMT, name, datetime_raw);
416 if(datetime_raw==0) return;
418 de_dbg_indent(c, 1);
419 time_raw = datetime_raw & 0xffff;
420 date_raw = (datetime_raw >> 16) & 0xffff;
422 de_zeromem(&tmp_timestamp, sizeof(struct de_timestamp));
423 de_dos_datetime_to_timestamp(&tmp_timestamp, date_raw, time_raw);
424 tmp_timestamp.tzcode = DE_TZCODE_LOCAL;
425 de_timestamp_to_string(&tmp_timestamp, timestamp_buf, sizeof(timestamp_buf), 0);
426 de_dbg(c, "... if DOS time/date: %s", timestamp_buf);
428 // Autodesk animator was first released in 1989. Assume timestamps older than
429 // the middle of 1988 are bogus.
430 if(de_timestamp_to_unix_time(&tmp_timestamp) >= 583718400) {
431 *ts = tmp_timestamp;
434 de_dbg_indent(c, -1);
437 static void do_chunk_FLI_FLC(deark *c, lctx *d, struct chunk_info_type *ci)
439 i64 pos = ci->pos + 6;
440 i64 scr_width, scr_height;
441 i64 n;
442 struct image_ctx_type *ictx = NULL;
443 double fps = 0.0;
444 int can_decode_images = 1;
446 d->main_chunktype = ci->chunktype;
447 if(d->main_chunktype==CHUNKTYPE_FLI) {
448 de_declare_fmt(c, "FLI");
450 else if(d->main_chunktype==CHUNKTYPE_FLC) {
451 de_declare_fmt(c, "FLC");
453 else {
454 de_warn(c, "Unrecognized signature (0x%04x). This might not be a FLI/FLC file.",
455 d->main_chunktype);
458 d->num_frames = de_getu16le_p(&pos);
459 de_dbg(c, "num frames: %d", (int)d->num_frames);
461 scr_width = de_getu16le_p(&pos);
462 scr_height = de_getu16le_p(&pos);
463 de_dbg(c, "screen dimensions: %"I64_FMT DE_CHAR_TIMES "%"I64_FMT, scr_width, scr_height);
465 d->depth = (int)de_getu16le_p(&pos);
466 de_dbg(c, "depth: %d", d->depth);
467 if(d->depth==0) d->depth = 8;
468 pos += 2; // flags
470 n = de_getu32le_p(&pos);
471 if(ci->chunktype==CHUNKTYPE_FLI && n!=0) {
472 fps = 70.0/(double)n;
474 else if(ci->chunktype==CHUNKTYPE_FLC && n!=0) {
475 fps = 1000.0/(double)n;
477 de_dbg(c, "speed: %"I64_FMT" (%.4f frames/sec)", n, fps);
479 pos += 2; // reserved
481 if(ci->chunktype==CHUNKTYPE_FLI) {
482 if(scr_width==320 && scr_height==200) {
483 d->aspect_x = 6;
484 d->aspect_y = 5;
488 if(ci->chunktype==CHUNKTYPE_FLC) {
489 read_timestamp(c, d, pos, &d->create_timestamp, "create");
490 pos += 4;
491 dbg_id(c, d, pos, "creator ID");
492 pos += 4;
494 read_timestamp(c, d, pos, &d->mod_timestamp, "mod");
495 pos += 4;
496 dbg_id(c, d, pos, "updater ID");
497 pos += 4;
499 d->aspect_x = de_getu16le_p(&pos);
500 d->aspect_y = de_getu16le_p(&pos);
501 de_dbg(c, "aspect ratio: %d,%d", (int)d->aspect_x, (int)d->aspect_y);
504 can_decode_images = 1;
505 if(d->depth != 8) {
506 de_err(c, "Unsupported depth: %d", d->depth);
507 can_decode_images = 0;
509 if(!de_good_image_dimensions(c, scr_width, scr_height)) {
510 can_decode_images = 0;
513 if(can_decode_images) {
514 ictx = create_image_ctx(c, d, scr_width, scr_height);
515 ci->ictx = ictx;
516 if(d->aspect_x && d->aspect_y) {
517 ictx->density.code = DE_DENSITY_UNK_UNITS;
518 ictx->density.xdens = (double)d->aspect_x;
519 ictx->density.ydens = (double)d->aspect_y;
523 pos = ci->pos + 128;
524 do_sequence_of_chunks(c, d, ci, pos, -1);
526 destroy_image_ctx(c, ictx);
527 ci->ictx = NULL;
530 static void do_chunk_frame(deark *c, lctx *d, struct chunk_info_type *ci)
532 i64 num_subchunks;
533 i64 frame_idx;
534 i64 prev_use_count = 0;
535 de_finfo *fi = NULL;
537 frame_idx = d->frame_count;
538 d->frame_count++;
539 de_dbg(c, "frame number: %d", (int)frame_idx);
541 num_subchunks = de_getu16le(ci->pos+6);
542 de_dbg(c, "num subchunks: %"I64_FMT, num_subchunks);
544 if(ci->ictx) {
545 prev_use_count = ci->ictx->use_count;
548 do_sequence_of_chunks(c, d, ci, ci->pos+16, num_subchunks);
550 if(ci->ictx) {
551 if(ci->ictx->use_count > prev_use_count && !ci->ictx->error_flag) {
552 if(d->num_frames>0 && frame_idx==d->num_frames && c->extract_level<2) {
553 de_dbg(c, "[not extracting ring frame]");
554 goto done;
557 fi = de_finfo_create(c);
558 fi->density = ci->ictx->density;
559 fi->internal_mod_time = d->mod_timestamp;
560 de_bitmap_write_to_file_finfo(ci->ictx->img, fi, 0);
564 done:
565 de_finfo_destroy(c, fi);
568 static void do_chunk_thumbnail(deark *c, lctx *d, struct chunk_info_type *ci)
570 UI colortype;
571 i64 w, h;
572 struct image_ctx_type *ictx = NULL;
573 i64 pos = ci->pos + 6;
574 de_finfo *fi = NULL;
576 h = de_getu16le_p(&pos);
577 w = de_getu16le_p(&pos);
578 de_dbg_dimensions(c, w, h);
579 colortype = (UI)de_getu16le_p(&pos);
580 de_dbg(c, "color type: %u", colortype);
581 if(colortype!=1) goto done;
583 ictx = create_image_ctx(c, d, w, h);
584 ci->ictx = ictx;
585 make_6cube_pal(ictx->pal);
586 do_sequence_of_chunks(c, d, ci, pos, -1);
588 fi = de_finfo_create(c);
589 fi->internal_mod_time = d->mod_timestamp;
590 if(d->aspect_x && d->aspect_y) {
591 // Evidence suggests the thumbnail has the same aspect ratio as the animation,
592 // at least approximately.
593 fi->density.code = DE_DENSITY_UNK_UNITS;
594 fi->density.xdens = (double)d->aspect_x;
595 fi->density.ydens = (double)d->aspect_y;
597 de_finfo_set_name_from_sz(c, fi, "thumb", 0, DE_ENCODING_LATIN1);
599 if(ictx->use_count>0 && !ictx->error_flag) {
600 de_bitmap_write_to_file_finfo(ictx->img, fi, DE_CREATEFLAG_IS_AUX);
603 done:
604 destroy_image_ctx(c, ictx);
605 ci->ictx = NULL;
606 de_finfo_destroy(c, fi);
609 static void do_chunk_prefix(deark *c, lctx *d, struct chunk_info_type *ci)
611 do_sequence_of_chunks(c, d, ci, ci->pos+6, -1);
614 static void do_chunk_settings(deark *c, lctx *d, struct chunk_info_type *ci)
616 do_sequence_of_chunks(c, d, ci, ci->pos+8, -1);
619 static void do_chunk_hexdump(deark *c, lctx *d, struct chunk_info_type *ci)
621 if(c->debug_level<2) return;
622 de_dbg_hexdump(c, c->infile, ci->pos+6, ci->len-6, 256, NULL, 0x1);
625 // Sets ci->mct,
626 // ci->chunk_type_name (never to NULL),
627 // ci->handler_fn (sometimes to NULL)
628 static void identify_chunk(deark *c, lctx *d, struct chunk_info_type *ci)
630 enum mapped_chunktype_enum parent_mct;
631 UI ct = ci->chunktype;
633 parent_mct = ci->parent ? ci->parent->mct : MCT_NONE;
634 ci->mct = MCT_NONE;
635 ci->handler_fn = NULL;
636 ci->chunk_type_name = "?";
638 if(parent_mct==MCT_NONE) {
639 if(ct==CHUNKTYPE_FLI) {
640 ci->chunk_type_name = "FLI";
642 else if(ct==CHUNKTYPE_FLC) {
643 ci->chunk_type_name = "FLC";
645 ci->mct = MCT_FLI_OR_FLC;
646 ci->handler_fn = do_chunk_FLI_FLC;
647 goto done;
650 if(parent_mct==MCT_FLI_OR_FLC) {
651 if(ct==CHUNKTYPE_FRAME) {
652 ci->mct = MCT_FRAME;
653 ci->chunk_type_name = "frame";
654 ci->handler_fn = do_chunk_frame;
655 goto done;
657 else if(ct==0xf5fa) {
658 ci->mct = MCT_FRAME;
659 ci->chunk_type_name = "frame-variant";
660 ci->handler_fn = do_chunk_frame;
661 goto done;
663 else if(ct==CHUNKTYPE_PREFIX) {
664 ci->mct = MCT_PREFIX;
665 ci->chunk_type_name = "prefix";
666 ci->handler_fn = do_chunk_prefix;
667 goto done;
671 if(parent_mct==MCT_FRAME || parent_mct==MCT_THUMBNAIL) {
672 if(ct==CHUNKTYPE_COLORMAP64) {
673 ci->mct = MCT_COLORMAP;
674 ci->chunk_type_name = "color map 64";
675 ci->handler_fn = do_chunk_colormap;
676 goto done;
678 else if(ct==CHUNKTYPE_COLORMAP256) {
679 ci->mct = MCT_COLORMAP;
680 ci->chunk_type_name = "color map 256";
681 ci->handler_fn = do_chunk_colormap;
682 goto done;
684 else if(ct==CHUNKTYPE_RLE) {
685 ci->mct = MCT_RLE;
686 ci->chunk_type_name = "RLE compressed data";
687 ci->handler_fn = do_chunk_rle;
688 goto done;
690 else if(ct==CHUNKTYPE_DELTA_FLI) {
691 ci->mct = MCT_DELTA_FLI;
692 ci->chunk_type_name = "delta compressed data (old)";
693 ci->handler_fn = do_chunk_delta_fli;
694 goto done;
696 else if(ct==CHUNKTYPE_DELTA_FLC) {
697 ci->mct = MCT_DELTA_FLC;
698 ci->chunk_type_name = "delta compressed data (new)";
699 ci->handler_fn = do_chunk_delta_flc;
700 goto done;
702 else if(ct==CHUNKTYPE_COPY) {
703 ci->mct = MCT_COPY;
704 ci->chunk_type_name = "uncompressed data";
705 ci->handler_fn = do_chunk_copy;
706 goto done;
708 else if(ct==CHUNKTYPE_BLACK) {
709 ci->mct = MCT_BLACK;
710 ci->chunk_type_name = "clear screen";
711 ci->handler_fn = do_chunk_black;
712 goto done;
716 if(parent_mct==MCT_FRAME) {
717 if(ct==CHUNKTYPE_THUMBNAIL) {
718 ci->mct = MCT_THUMBNAIL;
719 ci->chunk_type_name = "thumbnail image";
720 ci->handler_fn = do_chunk_thumbnail;
721 goto done;
725 if(parent_mct==MCT_PREFIX) {
726 if(ct==0x0002) {
727 ci->mct = MCT_SETTINGS;
728 ci->chunk_type_name = "settings";
729 ci->handler_fn = do_chunk_settings;
730 goto done;
732 else if(ct==0x0003) {
733 ci->mct = MCT_CELDATA;
734 ci->chunk_type_name = "CEL data";
735 ci->handler_fn = do_chunk_hexdump;
736 goto done;
740 if(parent_mct==MCT_SETTINGS) {
741 ci->mct = MCT_ONESETTING;
742 ci->handler_fn = do_chunk_hexdump;
743 goto done;
746 done:
750 static int do_chunk(deark *c, lctx *d, struct chunk_info_type *parent_ci,
751 i64 pos1, i64 bytes_avail, int level, i64 *pbytes_consumed)
753 i64 pos = pos1;
754 int saved_indent_level;
755 int retval = 0;
756 struct chunk_info_type *ci = NULL;
757 enum mapped_chunktype_enum parent_mct;
759 de_dbg_indent_save(c, &saved_indent_level);
760 if(bytes_avail<6) goto done;
761 parent_mct = parent_ci ? parent_ci->mct : MCT_NONE;
763 ci = de_malloc(c, sizeof(struct chunk_info_type));
764 ci->parent = parent_ci;
765 ci->level = level;
766 ci->pos = pos1;
768 // Inherit the image context.
769 if(parent_ci) {
770 ci->ictx = parent_ci->ictx;
773 de_dbg(c, "chunk at %"I64_FMT, ci->pos);
774 de_dbg_indent(c, 1);
776 ci->len = de_getu32le_p(&pos);
777 de_dbg(c, "chunk len: %"I64_FMT, ci->len);
778 if(ci->len==0 && level==0) {
779 ci->len = c->infile->len;
781 if(ci->len==0) {
782 goto done;
784 if(ci->len<6) {
785 de_err(c, "Bad chunk header at %"I64_FMT, ci->pos);
786 goto done;
788 if(ci->len > bytes_avail) {
789 de_warn(c, "Chunk at %"I64_FMT" exceeds its parent's bounds (ends at %"I64_FMT
790 ", parent ends at %"I64_FMT")", ci->pos, ci->pos+ci->len, ci->pos+bytes_avail);
791 ci->len = bytes_avail;
794 *pbytes_consumed = ci->len;
795 retval = 1;
797 ci->chunktype = (UI)de_getu16le_p(&pos);
799 identify_chunk(c, d, ci);
800 de_dbg(c, "chunk type: 0x%04x (%s)", ci->chunktype, ci->chunk_type_name);
802 if(ci->handler_fn) {
803 ci->handler_fn(c, d, ci);
806 if(ci->handler_fn==NULL && (parent_mct==MCT_FLI_OR_FLC || parent_mct==MCT_FRAME))
808 de_warn(c, "Unknown chunk type 0x%04x at %"I64_FMT, ci->chunktype, ci->pos);
811 done:
812 de_free(c, ci);
813 de_dbg_indent_restore(c, saved_indent_level);
814 return retval;
817 // if max_nchunks==-1, no maximum
818 static void do_sequence_of_chunks(deark *c, lctx *d, struct chunk_info_type *parent_ci,
819 i64 pos1, i64 max_nchunks)
821 i64 pos = pos1;
822 i64 endpos = parent_ci->pos + parent_ci->len;
823 i64 chunk_idx = 0;
824 int saved_indent_level;
826 de_dbg_indent_save(c, &saved_indent_level);
828 if(!parent_ci) goto done;
829 if(parent_ci->level > 10) goto done;
830 if(pos+6 >= endpos) goto done;
831 de_dbg(c, "sequence of chunks at %"I64_FMT, pos1);
832 de_dbg_indent(c, 1);
834 while(1) {
835 i64 bytes_avail;
836 i64 bytes_consumed = 0;
837 int ret;
839 if(max_nchunks>=0 && chunk_idx>=max_nchunks) break;
840 bytes_avail = endpos - pos;
841 if(bytes_avail<6) break;
843 ret = do_chunk(c, d, parent_ci, pos, bytes_avail, parent_ci->level+1, &bytes_consumed);
844 if(!ret || bytes_consumed<1) break;
845 pos += bytes_consumed;
846 chunk_idx++;
849 done:
850 de_dbg_indent_restore(c, saved_indent_level);
853 static void de_run_fli(deark *c, de_module_params *mparams)
855 lctx *d = NULL;
856 i64 bytes_consumed = 0;
858 d = de_malloc(c, sizeof(lctx));
860 (void)do_chunk(c, d, NULL, 0, c->infile->len, 0, &bytes_consumed);
862 if(d) {
863 de_free(c, d);
867 static int de_identify_fli(deark *c)
869 UI ct;
870 int has_ext;
872 ct = (UI)de_getu16le(4);
873 if((ct>>8) != 0xaf) return 0;
874 has_ext = de_input_file_has_ext(c, "fli") ||
875 de_input_file_has_ext(c, "flc");
876 if(ct==CHUNKTYPE_FLI || ct==CHUNKTYPE_FLC) {
877 if(has_ext) return 100;
878 return 20;
880 if(has_ext) return 9;
881 return 0;
884 void de_module_fli(deark *c, struct deark_module_info *mi)
886 mi->id = "fli";
887 mi->desc = "FLI/FLC animation";
888 mi->run_fn = de_run_fli;
889 mi->identify_fn = de_identify_fli;