zip: Better parsing of Info-ZIP type 1 extra field
[deark.git] / modules / makichan.c
blob0ed39d3915244718f36111ab042cfe176e3edf78
1 // This file is part of Deark.
2 // Copyright (C) 2016 Jason Summers
3 // See the file COPYING for terms of use.
5 // MAKIchan graphics
6 // Supported: Most .MAG, .MKI
7 // Not supported: .MAX, some variant formats
9 #include <deark-config.h>
10 #include <deark-private.h>
11 DE_DECLARE_MODULE(de_module_makichan);
13 typedef struct localctx_struct {
14 i64 width, height;
15 i64 header_pos;
16 i64 flag_a_offset;
17 i64 flag_b_offset;
18 i64 flag_b_size;
19 i64 pixels_offset;
20 i64 pixels_size;
21 i64 num_colors;
22 i64 bits_per_pixel;
23 i64 rowspan;
24 i64 width_adj, height_adj;
26 u8 aspect_ratio_flag;
27 int is_max;
28 int is_mki;
29 int is_mki_b;
30 dbuf *virtual_screen;
31 dbuf *unc_pixels;
32 u32 pal[256];
33 } lctx;
35 static i64 de_int_round_up(i64 n, i64 m)
37 return ((n+(m-1))/m)*m;
40 static void read_palette(deark *c, lctx *d, i64 pos)
42 i64 k;
43 u8 cr, cg, cb;
45 de_dbg(c, "palette at %d", (int)pos);
46 de_dbg_indent(c, 1);
48 for(k=0; k<d->num_colors; k++) {
49 cg = de_getbyte(pos+3*k);
50 cr = de_getbyte(pos+3*k+1);
51 cb = de_getbyte(pos+3*k+2);
52 d->pal[k] = DE_MAKE_RGB(cr,cg,cb);
53 de_dbg_pal_entry(c, k, d->pal[k]);
56 de_dbg_indent(c, -1);
59 static int read_mki_header(deark *c, lctx *d)
61 i64 xoffset, yoffset;
62 i64 width_raw, height_raw;
63 i64 pos;
64 i64 flag_a_size;
65 i64 pix_data_a_size;
66 i64 pix_data_b_size;
67 i64 expected_file_size;
68 unsigned int extension_flags;
69 int retval = 0;
71 de_dbg(c, "MKI header at %d", (int)d->header_pos);
72 de_dbg_indent(c, 1);
74 pos = d->header_pos;
76 d->flag_b_size = de_getu16be(pos+0);
77 pix_data_a_size = de_getu16be(pos+2);
78 pix_data_b_size = de_getu16be(pos+4);
79 d->pixels_size = pix_data_a_size + pix_data_b_size;
81 extension_flags = (unsigned int)de_getu16be(pos+6);
82 de_dbg(c, "extension flags: 0x%04x", extension_flags);
83 de_dbg_indent(c, 1);
84 d->aspect_ratio_flag = extension_flags&0x0001;
85 if(extension_flags&0x0002) {
86 d->num_colors = 8;
88 else {
89 d->num_colors = 16;
90 d->bits_per_pixel = 4;
92 de_dbg(c, "number of colors: %d", (int)d->num_colors);
93 de_dbg_indent(c, -1);
95 xoffset = de_getu16be(pos+8);
96 yoffset = de_getu16be(pos+10);
97 de_dbg(c, "image offset: (%d,%d)", (int)xoffset, (int)yoffset);
99 width_raw = de_getu16be(pos+12);
100 d->width = width_raw - xoffset;
101 height_raw = de_getu16be(pos+14);
102 d->height = height_raw - yoffset;
103 de_dbg_dimensions(c, d->width, d->height);
104 if(d->width%64 != 0) {
105 de_warn(c, "Width is not a multiple of 64. This image may not be handled correctly.");
107 d->width_adj = de_int_round_up(d->width, 64);
108 if(d->height%4 != 0) {
109 de_warn(c, "Height is not a multiple of 4. This image may not be handled correctly.");
111 d->height_adj = de_int_round_up(d->height, 4);
113 d->flag_a_offset = pos + 16 + 48;
114 // The documentation seems to say that flag A is *always* 1000 bytes, regardless of
115 // how many bytes would actually be needed.
116 // This would imply that a MAKI image can't have more than 256000 pixels.
117 flag_a_size = 1000;
118 //flag_a_size = (d->width_adj*d->height_adj)/256;
120 d->flag_b_offset = d->flag_a_offset + flag_a_size;
121 d->pixels_offset = d->flag_b_offset + d->flag_b_size;
122 expected_file_size = d->pixels_offset + d->pixels_size;
123 de_dbg(c, "flag A offset=%d, size=%d", (int)d->flag_a_offset, (int)flag_a_size);
124 de_dbg(c, "flag B calculated_offset=%d, size=%d", (int)d->flag_b_offset, (int)d->flag_b_size);
125 de_dbg(c, "pix data size_A=%d, size_B=%d", (int)pix_data_a_size, (int)pix_data_b_size);
126 de_dbg(c, "pix data calculated_offset=%d, calculated_size=%d", (int)d->pixels_offset, (int)d->pixels_size);
127 de_dbg(c, "calculated file size: %d", (int)expected_file_size);
129 if(d->bits_per_pixel!=4 && d->bits_per_pixel!=8) {
130 de_err(c, "Unsupported or unknown bits/pixel");
131 goto done;
134 retval = 1;
136 done:
137 de_dbg_indent(c, -1);
138 return retval;
141 static void mki_decompress_virtual_screen(deark *c, lctx *d)
143 i64 i, j;
144 i64 a_pos, b_pos;
145 i64 vs_rowspan;
146 i64 k;
147 u8 tmpn[4];
148 u8 v;
149 u8 a_byte = 0x00;
150 int a_bitnum;
152 vs_rowspan = d->width_adj/16;
153 a_pos = d->flag_a_offset;
154 a_bitnum = -1;
155 b_pos = d->flag_b_offset;
156 d->virtual_screen = dbuf_create_membuf(c, vs_rowspan*d->height_adj, 1);
158 for(j=0; j<d->height_adj/4; j++) {
159 for(i=0; i<d->width_adj/8; i++) {
160 u8 flag_a_bit;
162 // Read next flag A bit
163 if(a_bitnum<0) {
164 a_byte = de_getbyte(a_pos++);
165 a_bitnum = 7;
167 flag_a_bit = a_byte & (1 << a_bitnum--);
169 if(!flag_a_bit)
170 continue;
172 // Read the next two bytes from flag B, and split them into 4 nibbles.
173 tmpn[0] = de_getbyte(b_pos++);
174 tmpn[2] = de_getbyte(b_pos++);
175 tmpn[1] = tmpn[0]&0x0f;
176 tmpn[3] = tmpn[2]&0x0f;
177 tmpn[0] >>= 4;
178 tmpn[2] >>= 4;
180 for(k=0; k<4; k++) {
181 i64 vs_pos;
183 vs_pos = (4*j+k)*vs_rowspan + i/2;
184 if(i%2==0) {
185 v = tmpn[k]<<4;
187 else {
188 v = dbuf_getbyte(d->virtual_screen, vs_pos) | tmpn[k];
190 dbuf_writebyte_at(d->virtual_screen, vs_pos, v);
196 static void mki_decompress_pixels(deark *c, lctx *d)
198 i64 i, j;
199 i64 p_pos;
200 i64 delta_y;
201 i64 vs_pos;
202 int vs_bitnum;
203 u8 vs_byte = 0x00;
205 d->rowspan = d->width_adj/2;
206 vs_pos = 0;
207 vs_bitnum = -1;
208 p_pos = d->pixels_offset;
209 delta_y = d->is_mki_b ? 4 : 2;
210 d->unc_pixels = dbuf_create_membuf(c, d->rowspan*d->height_adj, 1);
212 for(j=0; j<d->height; j++) {
213 for(i=0; i<d->rowspan; i++) {
214 u8 vs_bit;
215 u8 v;
217 // Read the next virtual-screen bit
218 if(vs_bitnum<0) {
219 vs_byte = dbuf_getbyte(d->virtual_screen, vs_pos++);
220 vs_bitnum = 7;
222 vs_bit = vs_byte & (1 << vs_bitnum--);
224 if(vs_bit) {
225 v = de_getbyte(p_pos++);
227 else {
228 v = 0x00;
231 if(j>=delta_y) {
232 v ^= dbuf_getbyte(d->unc_pixels, (j-delta_y)*d->rowspan + i);
234 dbuf_writebyte(d->unc_pixels, v);
239 static int read_mag_header(deark *c, lctx *d)
241 i64 xoffset, yoffset;
242 i64 width_raw, height_raw;
243 i64 pos;
244 u8 model_code;
245 u8 model_flags;
246 u8 screen_mode;
247 u8 colors_code;
248 int retval = 0;
250 de_dbg(c, "header at %d", (int)d->header_pos);
251 de_dbg_indent(c, 1);
253 pos = d->header_pos;
255 model_code = de_getbyte(pos+1);
256 model_flags = de_getbyte(pos+2);
257 de_dbg(c, "model code: 0x%02x, flags: 0x%02x",
258 (unsigned int)model_code, (unsigned int)model_flags);
259 if(model_code==0x03 && (model_flags==0x44 || model_flags==0x24)) {
260 de_warn(c, "This looks like MAX format, which is not correctly supported.");
261 d->is_max = 1;
264 screen_mode = de_getbyte(pos+3);
265 de_dbg(c, "screen mode: %d", (int)screen_mode);
266 de_dbg_indent(c, 1);
267 d->aspect_ratio_flag = screen_mode&0x01;
268 colors_code = screen_mode&0x82;
269 if(colors_code==0x00) {
270 d->num_colors = 16;
271 d->bits_per_pixel = 4;
273 else if(colors_code==0x80) {
274 d->num_colors = 256;
275 d->bits_per_pixel = 8;
277 else if(colors_code==0x02) {
278 d->num_colors = 8;
279 // TODO: Support 8 color images
281 de_dbg(c, "number of colors: %d", (int)d->num_colors);
282 de_dbg_indent(c, -1);
284 xoffset = de_getu16le(pos+4);
285 yoffset = de_getu16le(pos+6);
286 de_dbg(c, "image offset: (%d,%d)", (int)xoffset, (int)yoffset);
288 width_raw = de_getu16le(pos+8);
289 height_raw = de_getu16le(pos+10);
290 d->width = width_raw - xoffset + 1;
291 d->height = height_raw - yoffset + 1;
292 de_dbg_dimensions(c, d->width, d->height);
294 d->flag_a_offset = de_getu32le(pos+12);
295 d->flag_a_offset += d->header_pos;
296 de_dbg(c, "flag A offset: %d", (int)d->flag_a_offset);
298 d->flag_b_offset = de_getu32le(pos+16);
299 d->flag_b_offset += d->header_pos;
300 d->flag_b_size = de_getu32le(pos+20);
301 de_dbg(c, "flag B offset: %d, size=%d", (int)d->flag_b_offset, (int)d->flag_b_size);
303 d->pixels_offset = de_getu32le(pos+24);
304 d->pixels_offset += d->header_pos;
305 d->pixels_size = de_getu32le(pos+28);
306 de_dbg(c, "pixels offset: %d, size=%d", (int)d->pixels_offset, (int)d->pixels_size);
308 if(d->bits_per_pixel!=4 && d->bits_per_pixel!=8) {
309 de_err(c, "Unsupported or unknown bits/pixel");
310 goto done;
313 retval = 1;
314 done:
315 de_dbg_indent(c, -1);
316 return retval;
319 static int do_mag_decompress(deark *c, lctx *d)
321 static const u8 delta_x[16] = { 0,1,2,4,0,1,0,1,2,0,1,2,0,1,2, 0 };
322 static const u8 delta_y[16] = { 0,0,0,0,1,1,2,2,2,4,4,4,8,8,8,16 };
323 i64 x, y;
324 i64 a_pos, b_pos;
325 i64 p_pos;
326 int a_bitnum; // Index of next bit to read. -1 = no more bits in a_byte.
327 u8 a_byte = 0x00;
328 u8 b_byte;
329 int k;
330 i64 dpos;
331 u8 *action_byte_buf = NULL;
332 u8 wordbuf[2];
334 de_dbg(c, "decompressing pixels");
336 // Presumably, due to the compression scheme, every row must have a
337 // multiple of 4 bytes.
338 d->rowspan = ((d->width * d->bits_per_pixel + 31)/32)*4;
340 d->unc_pixels = dbuf_create_membuf(c, d->rowspan * d->height, 1);
342 a_pos = d->flag_a_offset;
343 a_bitnum = -1;
344 b_pos = d->flag_b_offset;
345 p_pos = d->pixels_offset;
347 action_byte_buf = de_malloc(c, d->rowspan/4);
349 for(y=0; y<d->height; y++) {
350 for(x=0; x<d->rowspan/4; x++) {
351 u8 action_byte;
352 u8 flag_a_bit;
354 // Read next flag A bit
355 if(a_bitnum<0) {
356 a_byte = de_getbyte(a_pos++);
357 a_bitnum = 7;
359 flag_a_bit = a_byte & (1 << a_bitnum--);
361 if(flag_a_bit) {
362 // If flag_a_bit is unset, re-use the action byte from the
363 // previous row.
364 // If flag bit A is set, the new action byte is the one from the
365 // previous row XORed with the next B byte (don't ask me why).
366 b_byte = de_getbyte(b_pos++);
367 action_byte_buf[x] ^= b_byte;
370 action_byte = action_byte_buf[x];
372 // Produce 4 uncompressed bytes, 2 for each nibble in the
373 // action byte.
374 for(k=0; k<2; k++) {
375 unsigned int dcode;
377 if(k==0)
378 dcode = (unsigned int)((action_byte&0xf0)>>4);
379 else
380 dcode = (unsigned int)(action_byte&0x0f);
382 if(dcode==0) {
383 // An "uncompressed" data word. Read it from the source file.
384 de_read(wordbuf, p_pos, 2);
385 p_pos += 2;
387 else {
388 // Copy the data word from an earlier location in the image.
389 dpos = d->unc_pixels->len -
390 d->rowspan*(i64)delta_y[dcode] -
391 2*(i64)delta_x[dcode];
392 dbuf_read(d->unc_pixels, wordbuf, dpos, 2);
394 dbuf_write(d->unc_pixels, wordbuf, 2);
399 de_free(c, action_byte_buf);
400 return 1;
403 static void do_create_image(deark *c, lctx *d)
405 de_bitmap *img = NULL;
406 de_finfo *fi = NULL;
408 img = de_bitmap_create(c, d->width, d->height, 3);
410 fi = de_finfo_create(c);
412 if(d->aspect_ratio_flag) {
413 fi->density.code = DE_DENSITY_UNK_UNITS;
414 fi->density.xdens = 2.0;
415 fi->density.ydens = 1.0;
418 de_convert_image_paletted(d->unc_pixels, 0,
419 d->bits_per_pixel, d->rowspan, d->pal, img, 0);
421 de_bitmap_write_to_file_finfo(img, fi, 0);
422 de_bitmap_destroy(img);
423 de_finfo_destroy(c, fi);
426 // Sets d->header_pos
427 static int find_mag_header(deark *c, lctx *d)
429 i64 pos_1a = 0;
430 int ret;
432 // Find the first 0x1a byte.
433 ret = dbuf_search_byte(c->infile, '\x1a', 0, c->infile->len, &pos_1a);
434 if(ret) {
435 // Find the first 0x00 byte after the first 0x1a byte.
436 // TODO: Is this the correct algorithm, or should we just assume the
437 // header starts immediately after the first 0x1a byte?
438 ret = dbuf_search_byte(c->infile, '\0', pos_1a+1, c->infile->len-pos_1a-1, &d->header_pos);
439 if(ret) {
440 de_dbg(c, "header found at %d", (int)d->header_pos);
441 return 1;
445 de_err(c, "Failed to find header. This is probably not a MAKIchan file.");
446 return 0;
449 static void do_mag(deark *c, lctx *d)
451 if(!find_mag_header(c, d)) goto done;
452 if(!read_mag_header(c, d)) goto done;
453 read_palette(c, d, d->header_pos+32);
454 if(!de_good_image_dimensions(c, d->width, d->height)) goto done;
455 if(!do_mag_decompress(c, d)) goto done;
456 do_create_image(c, d);
457 done:
461 static void do_mki(deark *c, lctx *d)
463 d->header_pos = 32;
464 if(!read_mki_header(c, d)) goto done;
465 read_palette(c, d, d->header_pos+16);
466 if(!de_good_image_dimensions(c, d->width, d->height)) goto done;
467 mki_decompress_virtual_screen(c, d);
468 mki_decompress_pixels(c, d);
469 do_create_image(c, d);
470 done:
474 static void de_run_makichan(deark *c, de_module_params *mparams)
476 lctx *d = NULL;
478 d = de_malloc(c, sizeof(lctx));
480 if(!dbuf_memcmp(c->infile, 0, "MAKI01", 6)) {
481 d->is_mki = 1;
482 if(de_getbyte(6)=='B') {
483 d->is_mki_b = 1;
487 if(d->is_mki) {
488 do_mki(c, d);
490 else {
491 do_mag(c, d);
494 dbuf_close(d->unc_pixels);
495 dbuf_close(d->virtual_screen);
496 de_free(c, d);
499 static int de_identify_makichan(deark *c)
501 if(!dbuf_memcmp(c->infile, 0, "MAKI0", 5))
502 return 100;
503 return 0;
506 void de_module_makichan(deark *c, struct deark_module_info *mi)
508 mi->id = "makichan";
509 mi->desc = "MAKIchan graphics";
510 mi->run_fn = de_run_makichan;
511 mi->identify_fn = de_identify_makichan;