bmp: Rewrote the RLE decompressor
[deark.git] / modules / flif.c
blobdc78f41204fc33abb89ff46c4c7611b3b52d4f2f
1 // This file is part of Deark.
2 // Copyright (C) 2017 Jason Summers
3 // See the file COPYING for terms of use.
5 // FLIF
7 #include <deark-config.h>
8 #include <deark-private.h>
9 DE_DECLARE_MODULE(de_module_flif);
11 typedef struct localctx_struct {
12 int is_interlaced;
13 int is_animated;
14 i64 num_channels;
15 i64 bytes_per_channel;
16 i64 width, height;
17 i64 nb_frames;
18 } lctx;
20 static int read_varint(deark *c, i64 pos1, i64 *result, i64 *bytes_consumed)
22 i64 val = 0;
23 u8 b;
24 i64 pos = pos1;
25 int retval = 0;
27 *result = 0;
29 while(1) {
30 b = de_getbyte(pos++);
31 val = (val<<7)|(b&0x7f);
32 if((b&0x80)==0) break;
33 if(pos - pos1 >= 8) {
34 // We allow varints up to 8 bytes (8*7=56 bits).
35 // If we've read 8 bytes without finding the terminating byte,
36 // give up.
37 // (Note that if we were to allow 63 bits, we could have int64
38 // overflow when we convert from a physical value to a logical
39 // value.)
40 de_err(c, "Excessively large varint at %d", (int)pos1);
41 goto done;
45 *result = val;
46 retval = 1;
47 done:
48 *bytes_consumed = pos - pos1;
49 return retval;
52 static int do_read_header(deark *c, lctx *d, i64 pos1,
53 i64 *bytes_consumed)
55 i64 pos = pos1;
56 u8 b;
57 u8 intl_anim_code;
58 u8 bytes_per_channel_code;
59 i64 tmpcode;
60 i64 bytes_consumed2;
61 int retval = 0;
62 char tmps[80];
64 de_dbg(c, "header at %d", (int)pos1);
65 de_dbg_indent(c, 1);
67 pos += 4; // Magic
69 b = de_getbyte(pos++);
71 intl_anim_code = (b&0xf0)>>4;
72 switch(intl_anim_code) {
73 case 3: break;
74 case 4: d->is_interlaced = 1; break;
75 case 5: d->is_animated = 1; break;
76 case 6: d->is_interlaced = 1; d->is_animated = 1; break;
77 default:
78 de_warn(c, "Unknown interlace/animation code: %d", (int)intl_anim_code);
80 de_dbg(c, "interlaced: %d", d->is_interlaced);
81 de_dbg(c, "animated: %d", d->is_animated);
83 d->num_channels = (i64)(b&0x0f);
84 de_dbg(c, "number of channels: %d", (int)d->num_channels);
86 bytes_per_channel_code = de_getbyte(pos++);
87 if(bytes_per_channel_code=='0') {
88 de_strlcpy(tmps, "custom", sizeof(tmps));
90 else if(bytes_per_channel_code=='1' || bytes_per_channel_code=='2') {
91 d->bytes_per_channel = (i64)(bytes_per_channel_code-'0');
92 de_snprintf(tmps, sizeof(tmps), "%d", (int)(d->bytes_per_channel));
94 else {
95 de_strlcpy(tmps, "?", sizeof(tmps));
97 de_dbg(c, "bytes per channel: 0x%02x (%s)",
98 (unsigned int)bytes_per_channel_code, tmps);
100 if(!read_varint(c, pos, &tmpcode, &bytes_consumed2)) goto done;
101 d->width = tmpcode+1;
102 pos += bytes_consumed2;
104 if(!read_varint(c, pos, &tmpcode, &bytes_consumed2)) goto done;
105 d->height = tmpcode+1;
106 pos += bytes_consumed2;
108 de_dbg_dimensions(c, d->width, d->height);
110 if(d->is_animated) {
111 if(!read_varint(c, pos, &tmpcode, &bytes_consumed2)) goto done;
112 d->nb_frames = tmpcode+2;
113 pos += bytes_consumed2;
114 de_dbg(c, "number of frames: %d", (int)d->nb_frames);
116 else {
117 d->nb_frames = 1;
120 retval = 1;
121 done:
122 *bytes_consumed = pos - pos1;
123 de_dbg_indent(c, -1);
124 return retval;
127 static int do_read_metadata(deark *c, lctx *d, i64 pos1,
128 i64 *bytes_consumed)
130 u8 b;
131 i64 pos = pos1;
132 int saved_indent_level;
133 int retval = 0;
135 de_dbg_indent_save(c, &saved_indent_level);
136 *bytes_consumed = 0;
138 // peek at the next byte, to see if there is a metadata segment.
139 b = de_getbyte(pos);
140 if(b<32) {
141 de_dbg(c, "[metadata segment not present]");
142 retval = 1;
143 goto done;
146 de_dbg(c, "metadata segment at %d", (int)pos1);
147 de_err(c, "not implemented");
149 // TODO (need samples)
151 done:
152 de_dbg_indent_restore(c, saved_indent_level);
153 return retval;
156 static int do_second_header(deark *c, lctx *d, i64 pos1,
157 i64 *bytes_consumed)
159 u8 ct;
160 i64 pos = pos1;
162 de_dbg(c, "second header segment at %d", (int)pos1);
163 de_dbg_indent(c, 1);
165 ct = de_getbyte(pos++);
166 de_dbg(c, "chunk type: 0x%02x", (unsigned int)ct);
168 if(ct!=0x00) {
169 de_err(c, "unsupported chunk type: 0x%02x", (unsigned int)ct);
170 goto done;
173 done:
174 de_dbg_indent(c, -1);
175 return 0;
178 static void de_run_flif(deark *c, de_module_params *mparams)
180 lctx *d = NULL;
181 i64 pos;
182 i64 bytes_consumed;
184 d = de_malloc(c, sizeof(lctx));
186 pos = 0;
188 if(!do_read_header(c, d, pos, &bytes_consumed)) goto done;
189 pos += bytes_consumed;
192 if(!do_read_metadata(c, d, pos, &bytes_consumed)) goto done;
193 pos += bytes_consumed;
195 if(!do_second_header(c, d, pos, &bytes_consumed)) goto done;
197 done:
198 de_free(c, d);
201 static int de_identify_flif(deark *c)
203 if(!dbuf_memcmp(c->infile, 0, "FLIF", 4))
204 return 90;
205 return 0;
208 void de_module_flif(deark *c, struct deark_module_info *mi)
210 mi->id = "flif";
211 mi->desc = "FLIF image format";
212 mi->run_fn = de_run_flif;
213 mi->identify_fn = de_identify_flif;
214 mi->flags |= DE_MODFLAG_NONWORKING;