bmp: Rewrote the RLE decompressor
[deark.git] / modules / misc2.c
blobc57a7e3611cc00e76f925f6f33dfdb76b66a07b8
1 // This file is part of Deark.
2 // Copyright (C) 2016-2021 Jason Summers
3 // See the file COPYING for terms of use.
5 // This file is for miscellaneous small modules that primarily do image decoding.
7 #include <deark-private.h>
8 #include <deark-fmtutil.h>
9 DE_DECLARE_MODULE(de_module_hpicn);
10 DE_DECLARE_MODULE(de_module_xpuzzle);
11 DE_DECLARE_MODULE(de_module_bob);
12 DE_DECLARE_MODULE(de_module_alias_pix);
13 DE_DECLARE_MODULE(de_module_applevol);
14 DE_DECLARE_MODULE(de_module_hr);
15 DE_DECLARE_MODULE(de_module_ripicon);
16 DE_DECLARE_MODULE(de_module_lss16);
17 DE_DECLARE_MODULE(de_module_vbm);
18 DE_DECLARE_MODULE(de_module_fp_art);
19 DE_DECLARE_MODULE(de_module_ybm);
20 DE_DECLARE_MODULE(de_module_olpc565);
21 DE_DECLARE_MODULE(de_module_iim);
22 DE_DECLARE_MODULE(de_module_pm_xv);
23 DE_DECLARE_MODULE(de_module_crg);
24 DE_DECLARE_MODULE(de_module_farbfeld);
25 DE_DECLARE_MODULE(de_module_hsiraw);
26 DE_DECLARE_MODULE(de_module_qdv);
27 DE_DECLARE_MODULE(de_module_vitec);
28 DE_DECLARE_MODULE(de_module_hs2);
29 DE_DECLARE_MODULE(de_module_lumena_cel);
30 DE_DECLARE_MODULE(de_module_deskmate_pnt);
31 DE_DECLARE_MODULE(de_module_mdesk_icn);
32 DE_DECLARE_MODULE(de_module_animator_pic);
33 DE_DECLARE_MODULE(de_module_dgi);
34 DE_DECLARE_MODULE(de_module_cserve_rle);
35 DE_DECLARE_MODULE(de_module_lotus_mscr);
36 DE_DECLARE_MODULE(de_module_fastgraph_spr);
37 DE_DECLARE_MODULE(de_module_fastgraph_ppr);
38 DE_DECLARE_MODULE(de_module_young_picasso);
39 DE_DECLARE_MODULE(de_module_iconmgr_ica);
40 DE_DECLARE_MODULE(de_module_thumbsplus);
41 DE_DECLARE_MODULE(de_module_fmtowns_icn);
42 DE_DECLARE_MODULE(de_module_pixfolio);
43 DE_DECLARE_MODULE(de_module_apple2icons);
45 static void datetime_dbgmsg(deark *c, struct de_timestamp *ts, const char *name)
47 char timestamp_buf[64];
49 de_timestamp_to_string(ts, timestamp_buf, sizeof(timestamp_buf), 0);
50 de_dbg(c, "%s: %s", name, timestamp_buf);
53 // Assumes path separators are '/' or '\'.
54 static void get_base_filename(de_ucstring *s1, de_ucstring *s2)
56 i64 i;
57 i64 len;
59 ucstring_empty(s2);
60 len = s1->len;
61 for(i=0; i<len; i++) {
62 de_rune ch;
64 ch = s1->str[i];
65 if(ch=='\\' || ch=='/') {
66 ucstring_empty(s2);
68 else {
69 ucstring_append_char(s2, ch);
74 // **************************************************************************
75 // HP 100LX / HP 200LX .ICN icon format
76 // **************************************************************************
78 struct hpicn_params {
79 i64 w, h;
80 i64 rowspan;
83 static void read_hpicn_params(deark *c, struct hpicn_params *icnp)
85 icnp->w = de_getu16le(4);
86 icnp->h = de_getu16le(6);
87 icnp->rowspan = (icnp->w+7)/8;
90 static void de_run_hpicn(deark *c, de_module_params *mparams)
92 struct hpicn_params icnp;
94 read_hpicn_params(c, &icnp);
95 de_dbg_dimensions(c, icnp.w, icnp.h);
96 de_convert_and_write_image_bilevel2(c->infile, 8, icnp.w, icnp.h, icnp.rowspan,
97 DE_CVTF_WHITEISZERO, NULL, 0);
100 static int de_identify_hpicn(deark *c)
102 struct hpicn_params icnp;
104 if(dbuf_memcmp(c->infile, 0, "\x01\x00\x01\x00", 4))
105 return 0;
106 read_hpicn_params(c, &icnp);
107 if(8 + icnp.rowspan*icnp.h != c->infile->len) return 0;
108 if(icnp.w<1 || icnp.w>2048 || icnp.h<1 || icnp.h>2048) return 0;
109 if(icnp.w==44 && icnp.h==32) return 100;
110 return 60;
113 void de_module_hpicn(deark *c, struct deark_module_info *mi)
115 mi->id = "hpicn";
116 mi->desc = "HP 100LX/200LX .ICN icon";
117 mi->run_fn = de_run_hpicn;
118 mi->identify_fn = de_identify_hpicn;
121 // **************************************************************************
122 // X11 "puzzle" format
123 // ftp://ftp.x.org/pub/unsupported/programs/puzzle/
124 // This is the format generated by Netpbm's ppmtopuzz utility.
125 // **************************************************************************
127 struct xpuzzhdr {
128 i64 w, h;
129 i64 palentries;
132 static void xpuzz_read_header(deark *c, struct xpuzzhdr *hdr)
134 hdr->w = de_getu32be(0);
135 hdr->h = de_getu32be(4);
136 hdr->palentries = (i64)de_getbyte(8);
137 if(hdr->palentries==0) hdr->palentries = 256;
140 static void de_run_xpuzzle(deark *c, de_module_params *mparams)
142 de_bitmap *img = NULL;
143 struct xpuzzhdr hdr;
144 de_color pal[256];
145 i64 p;
147 xpuzz_read_header(c, &hdr);
148 de_dbg_dimensions(c, hdr.w, hdr.h);
149 if(!de_good_image_dimensions(c, hdr.w, hdr.h)) goto done;
151 img = de_bitmap_create(c, hdr.w, hdr.h, 3);
153 // Read the palette
154 p = 9;
155 de_read_simple_palette(c, c->infile, p, hdr.palentries, 3, pal, 256,
156 DE_RDPALTYPE_24BIT, DE_RDPALFLAG_INITPAL);
157 p += 3*hdr.palentries;
159 // Read the bitmap
160 de_convert_image_paletted(c->infile, p, 8, hdr.w, pal, img, 0);
162 de_bitmap_write_to_file(img, NULL, 0);
164 done:
165 de_bitmap_destroy(img);
168 static int de_identify_xpuzzle(deark *c)
170 struct xpuzzhdr hdr;
171 int retval = 0;
173 xpuzz_read_header(c, &hdr);
174 // 4096 is an arbitrary limit.
175 if(hdr.w<1 || hdr.w>4096 || hdr.h<1 || hdr.h>4096) goto done;
176 if(hdr.w * hdr.h + 3*hdr.palentries + 9 == c->infile->len) {
177 retval = 20;
180 done:
181 return retval;
184 void de_module_xpuzzle(deark *c, struct deark_module_info *mi)
186 mi->id = "xpuzzle";
187 mi->desc = "X11 \"puzzle\" image";
188 mi->run_fn = de_run_xpuzzle;
189 mi->identify_fn = de_identify_xpuzzle;
192 // **************************************************************************
193 // "Bob" bitmap image
194 // Used by the Bob ray tracer.
195 // **************************************************************************
197 static void de_run_bob(deark *c, de_module_params *mparams)
199 de_bitmap *img = NULL;
200 i64 w, h;
201 u32 pal[256];
202 i64 p;
204 w = de_getu16le(0);
205 h = de_getu16le(2);
206 if(!de_good_image_dimensions(c, w, h)) goto done;
207 img = de_bitmap_create(c, w, h, 3);
209 // Read the palette
210 p = 4;
211 de_read_simple_palette(c, c->infile, p, 256, 3, pal, 256, DE_RDPALTYPE_24BIT, 0);
212 p += 256*3;
214 // Read the bitmap
215 de_convert_image_paletted(c->infile, p, 8, w, pal, img, 0);
217 de_bitmap_write_to_file(img, NULL, 0);
219 done:
220 de_bitmap_destroy(img);
223 static int de_identify_bob(deark *c)
225 i64 w, h;
227 if(!de_input_file_has_ext(c, "bob")) return 0;
229 w = de_getu16le(0);
230 h = de_getu16le(2);
231 if(c->infile->len == 4 + 768 + w*h) {
232 return 100;
234 return 0;
237 void de_module_bob(deark *c, struct deark_module_info *mi)
239 mi->id = "bob";
240 mi->desc = "Bob Ray Tracer bitmap image";
241 mi->run_fn = de_run_bob;
242 mi->identify_fn = de_identify_bob;
245 // **************************************************************************
246 // Alias PIX bitmap image.
247 // Also used by the Vivid ray tracer.
248 // **************************************************************************
250 static void de_run_alias_pix(deark *c, de_module_params *mparams)
252 de_bitmap *img = NULL;
253 i64 w, h;
254 i64 i;
255 i64 pos;
256 i64 firstline;
257 i64 depth;
258 i64 xpos, ypos;
259 i64 runlen;
260 u32 clr;
262 w = de_getu16be(0);
263 h = de_getu16be(2);
264 firstline = de_getu16be(4);
265 depth = de_getu16be(8);
267 if(!de_good_image_dimensions(c, w, h)) goto done;
268 if(firstline >= h) goto done;
269 if(depth!=24) {
270 de_err(c, "Unsupported image type");
271 goto done;
274 img = de_bitmap_create(c, w, h, 3);
276 pos = 10;
277 xpos = 0;
278 // I don't know for sure what to do with the "first scanline" field, in the
279 // unlikely event it is not 0. The documentation doesn't say.
280 ypos = firstline;
281 while(1) {
282 if(pos+4 > c->infile->len) {
283 break; // EOF
285 runlen = (i64)de_getbyte(pos);
286 clr = dbuf_getRGB(c->infile, pos+1, DE_GETRGBFLAG_BGR);
287 pos+=4;
289 for(i=0; i<runlen; i++) {
290 de_bitmap_setpixel_rgb(img, xpos, ypos, clr);
291 xpos++; // Runs are not allowed to span rows
294 if(xpos >= w) {
295 xpos=0;
296 ypos++;
300 de_bitmap_write_to_file(img, NULL, 0);
301 done:
302 de_bitmap_destroy(img);
305 static int de_identify_alias_pix(deark *c)
307 i64 w, h, firstline, lastline, depth;
309 if(!de_input_file_has_ext(c, "img") &&
310 !de_input_file_has_ext(c, "als") &&
311 !de_input_file_has_ext(c, "pix"))
313 return 0;
316 w = de_getu16be(0);
317 h = de_getu16be(2);
318 firstline = de_getu16be(4);
319 lastline = de_getu16be(6);
320 depth = de_getu16be(8);
322 if(depth!=24) return 0;
323 if(firstline>lastline) return 0;
324 // 'lastline' should usually be h-1, but XnView apparently sets it to h.
325 if(firstline>h-1 || lastline>h) return 0;
326 if(!de_good_image_dimensions_noerr(c, w, h)) return 0;
327 return 30;
330 void de_module_alias_pix(deark *c, struct deark_module_info *mi)
332 mi->id = "alias_pix";
333 mi->id_alias[0] = "vivid";
334 mi->desc = "Alias PIX image, Vivid .IMG";
335 mi->run_fn = de_run_alias_pix;
336 mi->identify_fn = de_identify_alias_pix;
339 // **************************************************************************
340 // Apple volume label image
341 // Written by netpbm: ppmtoapplevol
342 // **************************************************************************
344 static u8 applevol_get_gray_shade(u8 clr)
346 switch(clr) {
347 // TODO: These gray shades may not be quite right. I can't find good
348 // information about them.
349 case 0x00: return 0xff;
350 case 0xf6: return 0xee;
351 case 0xf7: return 0xdd;
352 case 0x2a: return 0xcc;
353 case 0xf8: return 0xbb;
354 case 0xf9: return 0xaa;
355 case 0x55: return 0x99;
356 case 0xfa: return 0x88;
357 case 0xfb: return 0x77;
358 case 0x80: return 0x66;
359 case 0xfc: return 0x55;
360 case 0xfd: return 0x44;
361 case 0xab: return 0x33;
362 case 0xfe: return 0x22;
363 case 0xff: return 0x11;
364 case 0xd6: return 0x00;
366 return 0xff;
369 static void de_run_applevol(deark *c, de_module_params *mparams)
371 de_bitmap *img = NULL;
372 i64 w, h;
373 i64 i, j;
374 i64 p;
375 u8 palent;
377 w = de_getu16be(1);
378 h = de_getu16be(3);
379 if(!de_good_image_dimensions(c, w, h)) goto done;
380 img = de_bitmap_create(c, w, h, 1);
382 p = 5;
383 for(j=0; j<h; j++) {
384 for(i=0; i<w; i++) {
385 palent = de_getbyte(p+w*j+i);
386 de_bitmap_setpixel_gray(img, i, j, applevol_get_gray_shade(palent));
390 de_bitmap_write_to_file(img, NULL, 0);
392 done:
393 de_bitmap_destroy(img);
396 static int de_identify_applevol(deark *c)
398 u8 buf[5];
400 de_read(buf, 0, sizeof(buf));
402 if(buf[0]==0x01 && buf[3]==0x00 && buf[4]==0x0c)
403 return 20;
404 return 0;
407 void de_module_applevol(deark *c, struct deark_module_info *mi)
409 mi->id = "applevol";
410 mi->desc = "Apple volume label image";
411 mi->run_fn = de_run_applevol;
412 mi->identify_fn = de_identify_applevol;
415 // **************************************************************************
416 // TRS-80 "HR" ("High Resolution") image
417 // **************************************************************************
419 static void de_run_hr(deark *c, de_module_params *mparams)
421 de_bitmap *img = NULL;
422 de_finfo *fi = NULL;
424 fi = de_finfo_create(c);
425 fi->density.code = DE_DENSITY_UNK_UNITS;
426 fi->density.xdens = 2;
427 fi->density.ydens = 1;
428 img = de_bitmap_create(c, 640, 240, 1);
429 de_convert_image_bilevel(c->infile, 0, 640/8, img, 0);
430 de_bitmap_write_to_file_finfo(img, fi, DE_CREATEFLAG_IS_BWIMG);
431 de_bitmap_destroy(img);
432 de_finfo_destroy(c, fi);
435 static int de_identify_hr(deark *c)
437 if(de_input_file_has_ext(c, "hr")) {
438 if(c->infile->len==19200) return 70;
439 if(c->infile->len>19200 && c->infile->len<=19456) return 30;
441 return 0;
444 void de_module_hr(deark *c, struct deark_module_info *mi)
446 mi->id = "hr";
447 mi->desc = "TRS-80 HR (High Resolution) image";
448 mi->run_fn = de_run_hr;
449 mi->identify_fn = de_identify_hr;
452 // **************************************************************************
453 // RIPterm icon (.ICN)
454 // **************************************************************************
456 // Don't know what this should be, but a limit will help us decide what is
457 // and isn't an image.
458 #define MAX_RIPICON_DIMENSION 2048
460 static int do_one_ripicon(deark *c, i64 pos1, i64 *pbytes_consumed, int scan_mode)
462 i64 width, height;
463 de_bitmap *img = NULL;
464 i64 chunk_span;
465 i64 src_rowspan;
466 i64 bitmap_len;
467 i64 pos = pos1;
468 int saved_indent_level;
469 de_color pal[16];
471 if(pos1+8 > c->infile->len) return 0;
472 width = 1 + de_getu16le_p(&pos);
473 height = 1 + de_getu16le_p(&pos);
474 if(width>MAX_RIPICON_DIMENSION || height>MAX_RIPICON_DIMENSION) return 0;
475 chunk_span = (width+7)/8;
476 src_rowspan = 4*chunk_span;
477 bitmap_len = src_rowspan * height;
478 if(pos+bitmap_len > c->infile->len) return 0;
480 *pbytes_consumed = 4 + bitmap_len + 2;
481 if(scan_mode) return 1;
483 de_dbg_indent_save(c, &saved_indent_level);
484 de_dbg(c, "image at %"I64_FMT, pos1);
485 de_dbg_indent(c, 1);
486 de_dbg_dimensions(c, width, height);
488 de_dbg(c, "bitmap at %"I64_FMT", len=%"I64_FMT, pos, bitmap_len);
489 if(!de_good_image_dimensions(c, width, height)) goto done;
490 img = de_bitmap_create2(c, width, chunk_span*8, height, 3);
491 de_copy_std_palette(DE_PALID_PC16, 0, 0, pal, 16, 0);
492 de_convert_image_paletted_planar(c->infile, pos, 4, src_rowspan, chunk_span,
493 pal, img, 0);
494 de_bitmap_write_to_file(img, NULL, DE_CREATEFLAG_OPT_IMAGE);
496 done:
497 if(img) de_bitmap_destroy(img);
498 de_dbg_indent_restore(c, saved_indent_level);
499 return 1;
502 static void de_run_ripicon(deark *c, de_module_params *mparams)
504 i64 pos = 0;
506 while(1) {
507 i64 bytes_consumed = 0;
509 if(!do_one_ripicon(c, pos, &bytes_consumed, 0)) break;
510 pos += bytes_consumed;
514 static int de_identify_ripicon(deark *c)
516 int has_ext = 0;
517 i64 pos = 0;
518 size_t i;
519 static const char *exts[] = { "icn", "hot", "msk", "bgi" };
521 for(i=0; i<DE_ARRAYCOUNT(exts); i++) {
522 if(de_input_file_has_ext(c, exts[i])) {
523 has_ext = 1;
524 break;
527 if(!has_ext) return 0;
529 while(1) {
530 i64 bytes_consumed = 0;
532 if(!do_one_ripicon(c, pos, &bytes_consumed, 1)) break;
533 pos += bytes_consumed;
534 if(pos == c->infile->len) return 50;
536 return 0;
539 void de_module_ripicon(deark *c, struct deark_module_info *mi)
541 mi->id = "ripicon";
542 mi->desc = "RIP/RIPscrip/RIPterm Icon / BGI image";
543 mi->run_fn = de_run_ripicon;
544 mi->identify_fn = de_identify_ripicon;
547 // **************************************************************************
548 // LSS16 image (Used by SYSLINUX)
549 // **************************************************************************
551 struct lss16ctx {
552 i64 pos;
553 int nextnibble_valid;
554 u8 nextnibble;
557 static u8 lss16_get_nibble(deark *c, struct lss16ctx *d)
559 u8 n;
560 if(d->nextnibble_valid) {
561 d->nextnibble_valid = 0;
562 return d->nextnibble;
564 n = de_getbyte(d->pos);
565 d->pos++;
566 // The low nibble of each byte is interpreted first.
567 // Record the high nibble, and return the low nibble.
568 d->nextnibble = (n&0xf0)>>4;
569 d->nextnibble_valid = 1;
570 return n&0x0f;
573 static void de_run_lss16(deark *c, de_module_params *mparams)
575 struct lss16ctx *d = NULL;
576 de_bitmap *img = NULL;
577 i64 width, height;
578 i64 i;
579 i64 xpos, ypos;
580 u8 n;
581 u8 prev;
582 i64 run_len;
583 u32 pal[16];
585 d = de_malloc(c, sizeof(struct lss16ctx));
587 d->pos = 4;
588 width = de_getu16le(d->pos);
589 height = de_getu16le(d->pos+2);
590 de_dbg_dimensions(c, width, height);
591 if(!de_good_image_dimensions(c, width, height)) goto done;
593 d->pos += 4;
594 de_read_simple_palette(c, c->infile, d->pos, 16, 3, pal, 16, DE_RDPALTYPE_VGA18BIT, 0);
595 d->pos += 16*3;
597 img = de_bitmap_create(c, width, height, 3);
599 xpos=0; ypos=0;
600 prev=0;
601 while(d->pos<c->infile->len && ypos<height) {
602 n = lss16_get_nibble(c, d);
604 if(n == prev) {
605 // A run of pixels
606 run_len = (i64)lss16_get_nibble(c, d);
607 if(run_len==0) {
608 run_len = lss16_get_nibble(c, d);
609 run_len |= ((i64)lss16_get_nibble(c, d)<<4);
610 run_len += 16;
612 for(i=0; i<run_len; i++) {
613 de_bitmap_setpixel_rgb(img, xpos, ypos, pal[prev]);
614 xpos++;
617 else {
618 // An uncompressed pixel
619 de_bitmap_setpixel_rgb(img, xpos, ypos, pal[n]);
620 xpos++;
621 prev = n;
624 // End of row reached?
625 if(xpos>=width) {
626 xpos=0;
627 ypos++;
628 d->nextnibble_valid = 0;
629 prev = 0;
633 de_bitmap_write_to_file(img, NULL, 0);
634 done:
635 de_bitmap_destroy(img);
636 de_free(c, d);
639 static int de_identify_lss16(deark *c)
641 if(!dbuf_memcmp(c->infile, 0, "\x3d\xf3\x13\x14", 4))
642 return 100;
643 return 0;
646 void de_module_lss16(deark *c, struct deark_module_info *mi)
648 mi->id = "lss16";
649 mi->desc = "SYSLINUX LSS16 image";
650 mi->run_fn = de_run_lss16;
651 mi->identify_fn = de_identify_lss16;
654 // **************************************************************************
655 // VBM (VDC BitMap)
656 // **************************************************************************
658 static void de_run_vbm(deark *c, de_module_params *mparams)
660 i64 width, height;
661 u8 ver;
663 ver = de_getbyte(3);
664 if(ver!=2) {
665 // TODO: Support VBM v3.
666 de_err(c, "Unsupported VBM version (%d)", (int)ver);
667 return;
669 width = de_getu16be(4);
670 height = de_getu16be(6);
671 de_convert_and_write_image_bilevel2(c->infile, 8, width, height, (width+7)/8,
672 DE_CVTF_WHITEISZERO, NULL, 0);
675 // Note that this function must work together with de_identify_bmp().
676 static int de_identify_vbm(deark *c)
678 u8 b[4];
679 de_read(b, 0, 4);
680 if(de_memcmp(b, "BM\xcb", 3)) return 0;
681 if(b[3]!=2 && b[3]!=3) return 0;
682 if(de_input_file_has_ext(c, "vbm")) return 100;
683 return 80;
686 void de_module_vbm(deark *c, struct deark_module_info *mi)
688 mi->id = "vbm";
689 mi->desc = "C64/128 VBM (VDC BitMap)";
690 mi->run_fn = de_run_vbm;
691 mi->identify_fn = de_identify_vbm;
694 // **************************************************************************
695 // PFS: 1st Publisher clip art (.ART)
696 // **************************************************************************
698 static void de_run_fp_art(deark *c, de_module_params *mparams)
700 i64 width, height;
701 i64 rowspan;
703 width = de_getu16le(2);
704 height = de_getu16le(6);
705 rowspan = ((width+15)/16)*2;
706 de_convert_and_write_image_bilevel2(c->infile, 8, width, height, rowspan, 0, NULL, 0);
709 static int de_identify_fp_art(deark *c)
711 i64 width, height;
712 i64 rowspan;
714 if(!de_input_file_has_ext(c, "art")) return 0;
716 width = de_getu16le(2);
717 height = de_getu16le(6);
718 rowspan = ((width+15)/16)*2;
719 if(8 + rowspan*height == c->infile->len) {
720 return 100;
723 return 0;
726 void de_module_fp_art(deark *c, struct deark_module_info *mi)
728 mi->id = "fp_art";
729 mi->desc = "PFS: 1st Publisher clip art (.ART)";
730 mi->run_fn = de_run_fp_art;
731 mi->identify_fn = de_identify_fp_art;
734 // **************************************************************************
735 // YBM
736 // **************************************************************************
738 static void de_run_ybm(deark *c, de_module_params *mparams)
740 de_bitmap *img = NULL;
741 i64 npwidth, pdwidth, height;
742 i64 i, j;
743 i64 words_per_row;
744 i64 pos;
746 pos = 2;
747 npwidth = de_getu16be_p(&pos);
748 height = de_getu16be_p(&pos);
749 de_dbg_dimensions(c, npwidth, height);
750 if(!de_good_image_dimensions(c, npwidth, height)) goto done;
751 pdwidth = de_pad_to_n(npwidth, 16);
752 words_per_row = pdwidth/16;
754 img = de_bitmap_create2(c, npwidth, pdwidth, height, 1);
756 for(j=0; j<height; j++) {
757 for(i=0; i<words_per_row; i++) {
758 u8 x;
760 // This encoding is unusual: LSB-first 16-bit integers.
761 x = de_getbyte_p(&pos);
762 de_unpack_pixels_bilevel_from_byte(img, i*16+8, j, x, 8,
763 DE_CVTF_WHITEISZERO|DE_CVTF_LSBFIRST|DE_CVTF_ONLYWHITE);
764 x = de_getbyte_p(&pos);
765 de_unpack_pixels_bilevel_from_byte(img, i*16, j, x, 8,
766 DE_CVTF_WHITEISZERO|DE_CVTF_LSBFIRST|DE_CVTF_ONLYWHITE);
769 de_bitmap_write_to_file(img, NULL, 0);
771 done:
772 de_bitmap_destroy(img);
775 static int de_identify_ybm(deark *c)
777 i64 width, height;
778 i64 rowspan;
780 if(dbuf_memcmp(c->infile, 0, "!!", 2))
781 return 0;
782 width = de_getu16be(2);
783 height = de_getu16be(4);
784 rowspan = ((width+15)/16)*2;
785 if(6+height*rowspan == c->infile->len)
786 return 100;
787 return 0;
790 void de_module_ybm(deark *c, struct deark_module_info *mi)
792 mi->id = "ybm";
793 mi->desc = "Bennet Yee's face format, a.k.a. YBM";
794 mi->run_fn = de_run_ybm;
795 mi->identify_fn = de_identify_ybm;
798 // **************************************************************************
799 // OLPC .565 firmware icon
800 // **************************************************************************
802 static void de_run_olpc565(deark *c, de_module_params *mparams)
804 de_bitmap *img = NULL;
805 i64 width, height;
806 i64 i, j;
807 i64 rowspan;
808 u8 b0, b1;
809 u32 clr;
811 width = de_getu16le(4);
812 height = de_getu16le(6);
813 if(!de_good_image_dimensions(c, width, height)) goto done;
814 rowspan = width*2;
816 img = de_bitmap_create(c, width, height, 3);
818 for(j=0; j<height; j++) {
819 for(i=0; i<width; i++) {
820 b0 = de_getbyte(8 + j*rowspan + i*2);
821 b1 = de_getbyte(8 + j*rowspan + i*2 + 1);
822 clr = (((u32)b1)<<8) | b0;
823 clr = de_rgb565_to_888(clr);
824 de_bitmap_setpixel_rgb(img, i, j, clr);
827 de_bitmap_write_to_file(img, NULL, 0);
829 done:
830 de_bitmap_destroy(img);
833 static int de_identify_olpc565(deark *c)
835 if(!dbuf_memcmp(c->infile, 0, "C565", 4))
836 return 100;
837 return 0;
840 void de_module_olpc565(deark *c, struct deark_module_info *mi)
842 mi->id = "olpc565";
843 mi->desc = "OLPC .565 firmware icon";
844 mi->run_fn = de_run_olpc565;
845 mi->identify_fn = de_identify_olpc565;
848 // **************************************************************************
849 // InShape .IIM
850 // **************************************************************************
852 static void de_run_iim(deark *c, de_module_params *mparams)
854 de_bitmap *img = NULL;
855 i64 width, height;
856 i64 i, j;
857 i64 n, bpp;
858 i64 rowspan;
859 u32 clr;
861 // This code is based on reverse engineering, and may be incorrect.
863 n = de_getu16be(8); // Unknown field
864 bpp = de_getu16be(10);
865 if(n!=4 || bpp!=24) {
866 de_dbg(c, "This type of IIM image is not supported");
867 goto done;
869 width = de_getu16be(12);
870 height = de_getu16be(14);
871 if(!de_good_image_dimensions(c, width, height)) goto done;
872 rowspan = width*3;
874 img = de_bitmap_create(c, width, height, 3);
876 for(j=0; j<height; j++) {
877 for(i=0; i<width; i++) {
878 clr = dbuf_getRGB(c->infile, 16+j*rowspan+i*3, 0);
879 de_bitmap_setpixel_rgb(img, i, j, clr);
882 de_bitmap_write_to_file(img, NULL, 0);
884 done:
885 de_bitmap_destroy(img);
888 static int de_identify_iim(deark *c)
890 if(!dbuf_memcmp(c->infile, 0, "IS_IMAGE", 8))
891 return 100;
892 return 0;
895 void de_module_iim(deark *c, struct deark_module_info *mi)
897 mi->id = "iim";
898 mi->desc = "InShape IIM";
899 mi->run_fn = de_run_iim;
900 mi->identify_fn = de_identify_iim;
903 // **************************************************************************
904 // PM (format supported by the XV image viewer)
905 // **************************************************************************
907 static void de_run_pm_xv(deark *c, de_module_params *mparams)
909 de_bitmap *img = NULL;
910 int is_le;
911 i64 width, height;
912 i64 nplanes;
913 i64 nbands;
914 i64 pixelformat;
915 i64 commentsize;
916 i64 i, j;
917 i64 plane;
918 i64 rowspan;
919 i64 planespan;
920 i64 pos;
921 u8 b;
923 if(!dbuf_memcmp(c->infile, 0, "WEIV", 4))
924 is_le = 1;
925 else
926 is_le = 0;
928 nplanes = dbuf_geti32x(c->infile, 4, is_le);
929 de_dbg(c, "planes: %d", (int)nplanes);
931 height = dbuf_geti32x(c->infile, 8, is_le);
932 width = dbuf_geti32x(c->infile, 12, is_le);
933 de_dbg_dimensions(c, width, height);
934 if(!de_good_image_dimensions(c, width, height)) goto done;
936 nbands = dbuf_geti32x(c->infile, 16, is_le);
937 de_dbg(c, "bands: %d", (int)nbands);
939 pixelformat = dbuf_geti32x(c->infile, 20, is_le);
940 de_dbg(c, "pixel format: 0x%04x", (unsigned int)pixelformat);
942 commentsize = dbuf_geti32x(c->infile, 24, is_le);
943 de_dbg(c, "comment size: %d", (int)commentsize);
945 pos = 28;
947 if((pixelformat==0x8001 && nplanes==3 && nbands==1) ||
948 (pixelformat==0x8001 && nplanes==1 && nbands==1))
952 else {
953 de_err(c, "Unsupported image type (pixel format=0x%04x, "
954 "planes=%d, bands=%d)", (unsigned int)pixelformat,
955 (int)nplanes, (int)nbands);
956 goto done;
959 rowspan = width;
960 planespan = rowspan*height;
962 img = de_bitmap_create(c, width, height, (int)nplanes);
964 for(plane=0; plane<nplanes; plane++) {
965 for(j=0; j<height; j++) {
966 for(i=0; i<width; i++) {
967 b = de_getbyte(pos + plane*planespan + j*rowspan + i);
968 if(nplanes==3) {
969 de_bitmap_setsample(img, i, j, plane, b);
971 else {
972 de_bitmap_setpixel_gray(img, i, j, b);
977 de_bitmap_write_to_file(img, NULL, 0);
979 done:
980 de_bitmap_destroy(img);
983 static int de_identify_pm_xv(deark *c)
985 if(!dbuf_memcmp(c->infile, 0, "VIEW", 4))
986 return 15;
987 if(!dbuf_memcmp(c->infile, 0, "WEIV", 4))
988 return 15;
989 return 0;
992 void de_module_pm_xv(deark *c, struct deark_module_info *mi)
994 mi->id = "pm_xv";
995 mi->desc = "PM (XV)";
996 mi->run_fn = de_run_pm_xv;
997 mi->identify_fn = de_identify_pm_xv;
1000 // **************************************************************************
1001 // Calamus Raster Graphic - CRG
1002 // **************************************************************************
1004 // Warning: The CRG decoder is based on reverse engineering, may not be
1005 // correct, and is definitely incomplete.
1007 static void de_run_crg(deark *c, de_module_params *mparams)
1009 i64 width, height;
1010 i64 rowspan;
1011 i64 pos;
1012 u8 b1, b2;
1013 i64 count;
1014 i64 cmpr_img_start;
1015 i64 num_cmpr_bytes;
1016 dbuf *unc_pixels = NULL;
1018 width = de_getu32be(20);
1019 height = de_getu32be(24);
1020 de_dbg_dimensions(c, width, height);
1021 if(!de_good_image_dimensions(c, width, height)) goto done;
1023 b1 = de_getbyte(32);
1024 if(b1!=0x01) {
1025 de_err(c, "Unsupported CRG format");
1026 goto done;
1029 num_cmpr_bytes = de_getu32be(38);
1030 de_dbg(c, "compressed data size: %d", (int)num_cmpr_bytes);
1031 cmpr_img_start = 42;
1033 if(cmpr_img_start + num_cmpr_bytes > c->infile->len) {
1034 num_cmpr_bytes = c->infile->len - cmpr_img_start;
1037 // Uncompress the image
1038 rowspan = (width+7)/8;
1039 unc_pixels = dbuf_create_membuf(c, height*rowspan, 1);
1041 pos = cmpr_img_start;
1042 while(pos < cmpr_img_start + num_cmpr_bytes) {
1043 b1 = de_getbyte(pos++);
1044 if(b1<=0x7f) { // Uncompressed bytes
1045 count = 1+(i64)b1;
1046 dbuf_copy(c->infile, pos, count, unc_pixels);
1047 pos += count;
1049 else { // A compressed run
1050 b2 = de_getbyte(pos++);
1051 count = (i64)(b1-127);
1052 dbuf_write_run(unc_pixels, b2, count);
1055 de_dbg(c, "decompressed to %d bytes", (int)unc_pixels->len);
1057 de_convert_and_write_image_bilevel2(unc_pixels, 0, width, height, rowspan,
1058 DE_CVTF_WHITEISZERO, NULL, 0);
1060 done:
1061 dbuf_close(unc_pixels);
1064 static int de_identify_crg(deark *c)
1066 if(!dbuf_memcmp(c->infile, 0, "CALAMUSCRG", 10))
1067 return 100;
1068 return 0;
1071 void de_module_crg(deark *c, struct deark_module_info *mi)
1073 mi->id = "crg";
1074 mi->desc = "Calamus Raster Graphic";
1075 mi->run_fn = de_run_crg;
1076 mi->identify_fn = de_identify_crg;
1079 // **************************************************************************
1080 // farbfeld
1081 // **************************************************************************
1083 static void de_run_farbfeld(deark *c, de_module_params *mparams)
1085 de_bitmap *imghi = NULL; // high 8 bits of each sample
1086 de_bitmap *imglo = NULL; // low 8 bits of each sample
1087 i64 width, height;
1088 i64 i, j, k;
1089 i64 ppos;
1090 u8 sh[4];
1091 u8 sl[4];
1093 width = de_getu32be(8);
1094 height = de_getu32be(12);
1095 de_dbg_dimensions(c, width, height);
1096 if(!de_good_image_dimensions(c, width, height)) return;
1098 imghi = de_bitmap_create(c, width, height, 4);
1099 imglo = de_bitmap_create(c, width, height, 4);
1101 for(j=0; j<height; j++) {
1102 for(i=0; i<width; i++) {
1103 ppos = 16 + 8*(width*j + i);
1104 for(k=0; k<4; k++) {
1105 sh[k] = de_getbyte(ppos+2*k);
1106 sl[k] = de_getbyte(ppos+2*k+1);
1108 de_bitmap_setpixel_rgba(imghi, i, j,
1109 DE_MAKE_RGBA(sh[0],sh[1],sh[2],sh[3]));
1110 de_bitmap_setpixel_rgba(imglo, i, j,
1111 DE_MAKE_RGBA(sl[0],sl[1],sl[2],sl[3]));
1114 de_bitmap16_write_to_file_finfo(imghi, imglo, NULL, DE_CREATEFLAG_OPT_IMAGE);
1115 de_bitmap_destroy(imghi);
1116 de_bitmap_destroy(imglo);
1119 static int de_identify_farbfeld(deark *c)
1121 if(!dbuf_memcmp(c->infile, 0, "farbfeld", 8))
1122 return 100;
1123 return 0;
1126 void de_module_farbfeld(deark *c, struct deark_module_info *mi)
1128 mi->id = "farbfeld";
1129 mi->desc = "farbfeld image";
1130 mi->run_fn = de_run_farbfeld;
1131 mi->identify_fn = de_identify_farbfeld;
1134 // **************************************************************************
1135 // HSI Raw image format (from Image Alchemy / Handmade Software)
1136 // **************************************************************************
1138 static void de_run_hsiraw(deark *c, de_module_params *mparams)
1140 i64 w, h;
1141 i64 num_pal_colors;
1142 i64 pos;
1143 i64 ver;
1144 i64 hdpi, vdpi;
1145 i64 cmpr;
1146 i64 alpha_info;
1147 de_bitmap *img = NULL;
1148 de_color pal[256];
1149 int is_grayscale;
1151 ver = de_getu16be(6);
1152 de_dbg(c, "version: %d", (int)ver);
1153 if(ver!=4) {
1154 de_warn(c, "HSI Raw version %d might not be supported correctly", (int)ver);
1157 w = de_getu16be(8);
1158 if(w==0) {
1159 // MPlayer extension?
1160 de_dbg2(c, "reading 32-bit width");
1161 w = de_getu32be(28);
1163 h = de_getu16be(10);
1164 de_dbg_dimensions(c, w, h);
1165 num_pal_colors = de_getu16be(12);
1166 de_dbg(c, "number of palette colors: %d", (int)num_pal_colors);
1168 hdpi = de_geti16be(14);
1169 vdpi = de_geti16be(16);
1170 de_dbg(c, "density: %d"DE_CHAR_TIMES"%d", (int)hdpi, (int)vdpi);
1171 // [18: Gamma]
1172 cmpr = de_getu16be(20);
1173 de_dbg(c, "compression: %d", (int)cmpr);
1174 alpha_info = de_getu16be(22);
1175 de_dbg(c, "alpha: %d", (int)alpha_info);
1177 if(num_pal_colors>256 || cmpr!=0 || alpha_info!=0) {
1178 de_err(c, "This type of HSI Raw image is not supported");
1179 goto done;
1181 if(!de_good_image_dimensions(c, w, h)) goto done;
1183 pos = 32;
1184 de_zeromem(pal, sizeof(pal));
1185 if(num_pal_colors==0) { // 24-bit RGB
1186 is_grayscale = 0;
1188 else { // 8-bit paletted
1189 de_read_simple_palette(c, c->infile, pos, num_pal_colors, 3, pal, 256,
1190 DE_RDPALTYPE_24BIT, 0);
1191 pos += 3*num_pal_colors;
1192 is_grayscale = de_is_grayscale_palette(pal, num_pal_colors);
1195 img = de_bitmap_create(c, w, h, is_grayscale?1:3);
1197 if(num_pal_colors==0) {
1198 de_convert_image_rgb(c->infile, pos, 3*w, 3, img, 0);
1200 else {
1201 de_convert_image_paletted(c->infile, pos, 8, w, pal, img, 0);
1204 de_bitmap_write_to_file(img, NULL, 0);
1206 done:
1207 de_bitmap_destroy(img);
1210 static int de_identify_hsiraw(deark *c)
1212 if(!dbuf_memcmp(c->infile, 0, "mhwanh", 6))
1213 return 100;
1214 return 0;
1217 void de_module_hsiraw(deark *c, struct deark_module_info *mi)
1219 mi->id = "hsiraw";
1220 mi->desc = "HSI Raw";
1221 mi->run_fn = de_run_hsiraw;
1222 mi->identify_fn = de_identify_hsiraw;
1225 // **************************************************************************
1226 // QDV (Giffer)
1227 // **************************************************************************
1229 static void de_run_qdv(deark *c, de_module_params *mparams)
1231 i64 w, h;
1232 i64 num_pal_colors;
1233 i64 pos;
1234 de_bitmap *img = NULL;
1235 de_color pal[256];
1237 // Warning: This decoder is based on reverse engineering, and may be
1238 // incorrect or incomplete.
1240 w = de_getu16be(0);
1241 h = de_getu16be(2);
1242 de_dbg_dimensions(c, w, h);
1243 if(!de_good_image_dimensions(c, w, h)) goto done;
1245 num_pal_colors = 1 + (i64)de_getbyte(4);
1246 de_dbg(c, "number of palette colors: %d", (int)num_pal_colors);
1248 pos = 5;
1249 de_read_simple_palette(c, c->infile, pos, num_pal_colors, 3, pal, 256,
1250 DE_RDPALTYPE_24BIT, DE_RDPALFLAG_INITPAL);
1251 pos += 3*num_pal_colors;
1253 img = de_bitmap_create(c, w, h, 3);
1254 de_convert_image_paletted(c->infile, pos, 8, w, pal, img, 0);
1255 de_bitmap_write_to_file(img, NULL, 0);
1257 done:
1258 de_bitmap_destroy(img);
1261 static int de_identify_qdv(deark *c)
1263 i64 w, h;
1264 i64 num_pal_colors;
1266 w = de_getu16be(0);
1267 h = de_getu16be(2);
1268 num_pal_colors = 1 + (i64)de_getbyte(4);
1269 if(5+num_pal_colors*3+w*h != c->infile->len)
1270 return 0;
1271 if(de_input_file_has_ext(c, "qdv"))
1272 return 100;
1273 return 30;
1276 void de_module_qdv(deark *c, struct deark_module_info *mi)
1278 mi->id = "qdv";
1279 mi->desc = "QDV (Giffer)";
1280 mi->run_fn = de_run_qdv;
1281 mi->identify_fn = de_identify_qdv;
1284 // **************************************************************************
1285 // VITec image format
1286 // **************************************************************************
1288 static void de_run_vitec(deark *c, de_module_params *mparams)
1290 i64 npwidth, pdwidth, h;
1291 i64 i, j, plane;
1292 de_bitmap *img = NULL;
1293 i64 samplesperpixel;
1294 i64 rowspan, planespan;
1295 i64 pos;
1296 u8 b;
1297 i64 h1size, h2size;
1298 int saved_indent_level;
1300 // This code is based on reverse engineering, and may be incorrect.
1302 de_dbg_indent_save(c, &saved_indent_level);
1303 de_warn(c, "VITec image support is experimental, and may not work correctly.");
1305 pos = 4;
1306 h1size = de_getu32be(pos);
1307 de_dbg(c, "header 1 at %d, len=%d", (int)pos, (int)h1size);
1308 // Don't know what's in this part of the header. Just ignore it.
1309 pos += h1size;
1310 if(pos>=c->infile->len) goto done;
1312 h2size = de_getu32be(pos);
1313 de_dbg(c, "header 2 at %d, len=%d", (int)pos, (int)h2size);
1314 de_dbg_indent(c, 1);
1316 // pos+4: Bits size?
1317 // pos+24: Unknown field, usually 7
1319 npwidth = de_getu32be(pos+36);
1320 h = de_getu32be(pos+40);
1321 de_dbg_dimensions(c, npwidth, h);
1322 if(!de_good_image_dimensions(c, npwidth, h)) goto done;
1324 // pos+52: Unknown field, 1 in grayscale images
1326 samplesperpixel = de_getu32be(pos+56);
1327 de_dbg(c, "samples/pixel: %d", (int)samplesperpixel);
1328 if(samplesperpixel!=1 && samplesperpixel!=3) {
1329 de_err(c, "Unsupported samples/pixel: %d", (int)samplesperpixel);
1330 goto done;
1333 pos += h2size;
1334 if(pos>=c->infile->len) goto done;
1335 de_dbg_indent(c, -1);
1337 de_dbg(c, "bitmap at %d", (int)pos);
1338 pdwidth = de_pad_to_n(npwidth, 8);
1339 img = de_bitmap_create2(c, npwidth, pdwidth, h, (int)samplesperpixel);
1340 rowspan = pdwidth;
1341 planespan = rowspan*h;
1343 for(plane=0; plane<samplesperpixel; plane++) {
1344 for(j=0; j<h; j++) {
1345 for(i=0; i<pdwidth; i++) {
1346 b = de_getbyte(pos + plane*planespan + j*rowspan + i);
1347 if(samplesperpixel==3) {
1348 de_bitmap_setsample(img, i, j, plane, b);
1350 else {
1351 de_bitmap_setpixel_gray(img, i, j, b);
1357 de_bitmap_write_to_file(img, NULL, 0);
1359 done:
1360 de_bitmap_destroy(img);
1361 de_dbg_indent_restore(c, saved_indent_level);
1364 static int de_identify_vitec(deark *c)
1366 if(!dbuf_memcmp(c->infile, 0, "\x00\x5b\x07\x20", 4))
1367 return 100;
1368 return 0;
1371 void de_module_vitec(deark *c, struct deark_module_info *mi)
1373 mi->id = "vitec";
1374 mi->desc = "VITec image format";
1375 mi->run_fn = de_run_vitec;
1376 mi->identify_fn = de_identify_vitec;
1379 // **************************************************************************
1380 // HS2 module
1382 // .HS2 format is associated with a program called POSTERING.
1383 // **************************************************************************
1385 static void de_run_hs2(deark *c, de_module_params *mparams)
1387 i64 width, height;
1388 i64 rowspan;
1390 rowspan = 105;
1391 width = rowspan*8;
1392 height = (c->infile->len+(rowspan-1))/rowspan;
1393 de_convert_and_write_image_bilevel(c->infile, 0, width, height, rowspan, 0, NULL, 0);
1396 static int de_identify_hs2(deark *c)
1398 if(!de_input_file_has_ext(c, "hs2")) return 0;
1399 if(c->infile->len>0 && (c->infile->len%105 == 0)) {
1400 return 15;
1402 return 0;
1405 void de_module_hs2(deark *c, struct deark_module_info *mi)
1407 mi->id = "hs2";
1408 mi->desc = "HS2 (POSTERING)";
1409 mi->run_fn = de_run_hs2;
1410 mi->identify_fn = de_identify_hs2;
1414 // **************************************************************************
1415 // Lumena CEL
1416 // **************************************************************************
1418 static void de_run_lumena_cel(deark *c, de_module_params *mparams)
1420 i64 width, height;
1421 i64 rowspan;
1422 i64 i, j;
1423 u32 clr;
1424 u8 a;
1425 int is_16bit = 0;
1426 int is_32bit = 0;
1427 de_bitmap *img = NULL;
1428 const i64 headersize = 4;
1429 i64 bypp;
1431 width = de_getu16le(0);
1432 height = de_getu16le(2);
1433 if(!de_good_image_dimensions_noerr(c, width, height)) goto done;
1435 // TODO: Support multi-image files
1436 is_16bit = (c->infile->len == headersize + width*height*2);
1437 is_32bit = (c->infile->len == headersize + width*height*4);
1438 if(!is_16bit && !is_32bit) {
1439 de_warn(c, "Cannot detect bits/pixel, assuming 32");
1440 is_32bit = 1;
1443 bypp = (is_32bit) ? 4 : 2;
1444 de_dbg(c, "bytes/pixel: %d", (int)bypp);
1445 rowspan = width * bypp;
1447 img = de_bitmap_create(c, width, height, is_32bit?4:3);
1449 for(j=0; j<height; j++) {
1450 for(i=0; i<width; i++) {
1451 i64 pos = headersize + j*rowspan + i*bypp;
1452 if(is_32bit) {
1453 clr = dbuf_getRGB(c->infile, pos, 0);
1454 a = de_getbyte(pos + 3);
1455 clr = DE_SET_ALPHA(clr, a);
1457 else {
1458 clr = (u32)de_getu16le(pos);
1459 clr = de_rgb555_to_888(clr);
1461 de_bitmap_setpixel_rgba(img, i, j, clr);
1465 de_bitmap_optimize_alpha(img, 0x3);
1466 de_bitmap_write_to_file(img, NULL, DE_CREATEFLAG_FLIP_IMAGE);
1468 done:
1469 de_bitmap_destroy(img);
1472 static int de_identify_lumena_cel(deark *c)
1474 i64 width, height;
1475 int is_16bit = 0;
1476 int is_32bit = 0;
1478 if(!de_input_file_has_ext(c, "cel")) return 0;
1479 width = de_getu16le(0);
1480 height = de_getu16le(2);
1482 is_16bit = (c->infile->len == 4 + width*height*2);
1483 is_32bit = (c->infile->len == 4 + width*height*4);
1485 if(is_16bit || is_32bit)
1486 return 60;
1488 return 0;
1491 void de_module_lumena_cel(deark *c, struct deark_module_info *mi)
1493 mi->id = "lumena_cel";
1494 mi->desc = "Lumena CEL";
1495 mi->run_fn = de_run_lumena_cel;
1496 mi->identify_fn = de_identify_lumena_cel;
1499 // **************************************************************************
1500 // Tandy DeskMate Paint .PNT
1501 // **************************************************************************
1503 static void de_run_deskmate_pnt(deark *c, de_module_params *mparams)
1505 i64 w, h;
1506 i64 rowspan;
1507 i64 pos = 0;
1508 int is_compressed;
1509 de_bitmap *img = NULL;
1510 dbuf *unc_pixels = NULL;
1511 i64 unc_pixels_size;
1512 de_color pal[16];
1514 pos += 22;
1515 de_dbg(c, "image at %"I64_FMT, pos);
1516 w = 312;
1517 h = 176;
1518 rowspan = w/2;
1519 unc_pixels_size = rowspan * h;
1521 de_copy_std_palette(DE_PALID_PC16, 0, 0, pal, 16, 0);
1523 is_compressed = (pos+unc_pixels_size != c->infile->len);
1524 de_dbg(c, "compressed: %d", is_compressed);
1526 if(is_compressed) {
1527 unc_pixels = dbuf_create_membuf(c, unc_pixels_size, 0x1);
1528 while(1) {
1529 i64 count;
1530 u8 val;
1532 if(pos >= c->infile->len) break; // out of source data
1533 if(unc_pixels->len >= unc_pixels_size) break; // enough dst data
1534 val = de_getbyte_p(&pos);
1535 count = (i64)de_getbyte_p(&pos);
1536 dbuf_write_run(unc_pixels, val, count);
1539 else {
1540 unc_pixels = dbuf_open_input_subfile(c->infile, pos, unc_pixels_size);
1543 img = de_bitmap_create(c, w, h, 3);
1544 de_convert_image_paletted(unc_pixels, 0, 4, rowspan, pal, img, 0);
1545 de_bitmap_write_to_file(img, NULL, 0);
1547 dbuf_close(unc_pixels);
1548 de_bitmap_destroy(img);
1551 static int de_identify_deskmate_pnt(deark *c)
1553 if(!dbuf_memcmp(c->infile, 0, "\x13" "PNT", 4)) return 100;
1554 return 0;
1557 void de_module_deskmate_pnt(deark *c, struct deark_module_info *mi)
1559 mi->id = "deskmate_pnt";
1560 mi->desc = "Tandy DeskMate Paint";
1561 mi->run_fn = de_run_deskmate_pnt;
1562 mi->identify_fn = de_identify_deskmate_pnt;
1565 // **************************************************************************
1566 // Magic Desk icon (.ICN)
1567 // **************************************************************************
1569 static void de_run_mdesk_icn(deark *c, de_module_params *mparams)
1571 const char *s;
1572 int pal_req = 0;
1573 u8 toybox_mode = 0;
1574 u8 b2;
1575 de_bitmap *img = NULL;
1576 de_color pal[16];
1577 static const de_color pal_mdesk[16] = {
1578 0xff000000U, 0xffaa0000U, 0xff00aa00U, 0xffaaaa00U,
1579 0xff0000aaU, 0xffaa00aaU, 0xff00aaaaU, 0xff7d7d7dU,
1580 0xffbababaU, 0xffff5555U, 0xff55ff55U, 0xffffff55U,
1581 0xff5555ffU, 0xffff55ffU, 0xff55ffffU, 0xffffffffU
1584 s = de_get_ext_option(c, "mdesk_icn:pal");
1585 if(s) {
1586 pal_req = de_atoi(s);
1589 if(pal_req<1 || pal_req>4) pal_req = 4; // default = prefer Magic Desk
1591 b2 = de_getbyte(2);
1592 de_dbg2(c, "byte[2]: 0x%02x", (UI)b2);
1594 if(pal_req==1) { // ToyBox only
1595 toybox_mode = 1;
1597 else if(pal_req==2) { // Magic Desk only
1598 toybox_mode = 0;
1600 else if(pal_req==3) { // prefer ToyBox
1601 toybox_mode = (b2 != 0x03);
1603 else {
1604 toybox_mode = (b2 == 0x00);
1607 de_declare_fmtf(c, "%s icon", (toybox_mode?"ToyBox":"Magic Desk"));
1609 if(toybox_mode) {
1610 de_copy_std_palette(DE_PALID_PC16, 0, 0, pal, 16, 0);
1612 else {
1613 de_memcpy(pal, pal_mdesk, sizeof(pal));
1616 img = de_bitmap_create(c, 32, 32, 3);
1617 de_convert_image_paletted(c->infile, 3, 4, 16, pal, img, 0);
1618 de_bitmap_transpose(img);
1619 de_bitmap_write_to_file(img, NULL, 0);
1620 de_bitmap_destroy(img);
1623 static int de_identify_mdesk_icn(deark *c)
1625 u8 b2;
1626 int has_ext;
1627 int b2_ok;
1629 if(c->infile->len!=515) return 0;
1630 if(de_getu16be(0)!=0x1f1f) return 0;
1631 b2 = de_getbyte(2);
1633 has_ext = (de_input_file_has_ext(c, "icn") ||
1634 de_input_file_has_ext(c, "tbi"));
1635 b2_ok = (b2==0x00 || b2==0x03 || b2==0xff);
1637 if(has_ext && b2_ok) {
1638 return 90;
1640 return 14;
1643 static void de_help_mdesk_icn(deark *c)
1645 de_msg(c, "-opt mdesk_icn:pal=<n> : Refer to documentation");
1648 void de_module_mdesk_icn(deark *c, struct deark_module_info *mi)
1650 mi->id = "mdesk_icn";
1651 mi->desc = "Magic Desk icon";
1652 mi->run_fn = de_run_mdesk_icn;
1653 mi->identify_fn = de_identify_mdesk_icn;
1654 mi->help_fn = de_help_mdesk_icn;
1657 // **************************************************************************
1658 // Autodesk Animator PIC/CEL
1659 // **************************************************************************
1661 static void de_run_animator_pic(deark *c, de_module_params *mparams)
1663 de_bitmap *img = NULL;
1664 de_finfo *fi = NULL;
1665 i64 pos = 2;
1666 i64 w, h;
1667 i64 imgsize;
1668 de_color pal[256];
1670 w = de_getu16le_p(&pos);
1671 h = de_getu16le_p(&pos);
1672 de_dbg_dimensions(c, w, h);
1673 if(!de_good_image_dimensions(c, w, h)) goto done;
1674 pos += 4; // xcoord/ycoord
1675 pos += 1; // depth
1676 pos += 1; // compression type
1677 imgsize = de_getu32le_p(&pos);
1678 de_dbg(c, "image size: %"I64_FMT, imgsize);
1679 pos += 16;
1680 de_read_simple_palette(c, c->infile, pos, 256, 3, pal, 256, DE_RDPALTYPE_VGA18BIT, 0);
1681 pos += 3*256;
1683 fi = de_finfo_create(c);
1684 fi->density.code = DE_DENSITY_UNK_UNITS;
1685 fi->density.xdens = 240.0;
1686 fi->density.ydens = 200.0;
1687 img = de_bitmap_create(c, w, h, 3);
1688 de_convert_image_paletted(c->infile, pos, 8, w, pal, img, 0);;
1689 de_bitmap_write_to_file_finfo(img, fi, 0);
1691 done:
1692 de_bitmap_destroy(img);
1693 de_finfo_destroy(c, fi);
1696 static int de_identify_animator_pic(deark *c)
1698 if(de_getu16le(0)!=0x9119) return 0;
1699 if(de_getbyte(10)!=0x08) return 0;
1700 if(de_getbyte(11)!=0x00) return 0;
1701 if(de_input_file_has_ext(c, "pic") ||
1702 de_input_file_has_ext(c, "cel"))
1704 return 100;
1706 return 80;
1709 void de_module_animator_pic(deark *c, struct deark_module_info *mi)
1711 mi->id = "animator_pic";
1712 mi->desc = "Autodesk Animator PIC/CEL";
1713 mi->run_fn = de_run_animator_pic;
1714 mi->identify_fn = de_identify_animator_pic;
1717 // **************************************************************************
1718 // DGI (Digi-Pic 2)
1719 // **************************************************************************
1721 static void do_dgi_convert_quadrant(deark *c, dbuf *imgbuf, i64 srcoffs, i64 dstoffs)
1723 i64 j;
1725 for(j=0; j<50; j++) {
1726 dbuf_copy_at(c->infile, srcoffs+j*160, 80, imgbuf, dstoffs+j*640);
1727 dbuf_copy_at(c->infile, srcoffs+j*160+80, 80, imgbuf, dstoffs+j*640+320);
1728 dbuf_copy_at(c->infile, srcoffs+8000+j*160, 80, imgbuf, dstoffs+j*640+160);
1729 dbuf_copy_at(c->infile, srcoffs+8000+j*160+80, 80, imgbuf, dstoffs+j*640+480);
1733 static void de_run_dgi(deark *c, de_module_params *mparams)
1735 dbuf *imgbuf = NULL;
1736 de_bitmap *img = NULL;
1737 de_finfo *fi = NULL;
1738 de_color pal[4];
1740 imgbuf = dbuf_create_membuf(c, 64000, 0x1);
1742 // Full 640x400 image is stored as four 320x200-pixel quadrants.
1743 // Each quadrant is interlaced.
1744 do_dgi_convert_quadrant(c, imgbuf, 0, 0);
1745 do_dgi_convert_quadrant(c, imgbuf, 16000, 80);
1746 do_dgi_convert_quadrant(c, imgbuf, 32008, 32000);
1747 do_dgi_convert_quadrant(c, imgbuf, 48008, 32080);
1749 de_copy_std_palette(DE_PALID_CGA, 1, 0, pal, 4, 0);
1751 fi = de_finfo_create(c);
1752 img = de_bitmap_create(c, 640, 400, 3);
1753 de_convert_image_paletted(imgbuf, 0, 2, 160, pal, img, 0);
1755 // DGI targets CGA 320x200.
1756 fi->density.code = DE_DENSITY_UNK_UNITS;
1757 fi->density.xdens = 240;
1758 fi->density.ydens = 200;
1760 de_bitmap_write_to_file_finfo(img, fi, 0);
1762 dbuf_close(imgbuf);
1763 de_bitmap_destroy(img);
1764 de_finfo_destroy(c, fi);
1767 static int de_identify_dgi(deark *c)
1769 int has_ext;
1771 if(c->infile->len < 64008) return 0;
1772 has_ext = de_input_file_has_ext(c, "dgi");
1773 if(!has_ext && c->infile->len!=64008) return 0;
1774 if(dbuf_memcmp(c->infile, 32000, (const void*)"\x01\x04\0\0\0\0\0\0", 8)) return 0;
1775 if(has_ext && c->infile->len==64008) return 100;
1776 return 20; // either no .dgi extension, or file unexpectedly large (but not both)
1779 void de_module_dgi(deark *c, struct deark_module_info *mi)
1781 mi->id = "dgi";
1782 mi->desc = "DGI (Digi-Pic)";
1783 mi->run_fn = de_run_dgi;
1784 mi->identify_fn = de_identify_dgi;
1787 // **************************************************************************
1788 // CompuServe RLE
1789 // **************************************************************************
1791 static int get_cserve_rle_fmt(deark *c)
1793 u8 buf[3];
1795 de_read(buf, 0, 3);
1796 if(buf[0]!=0x1b || buf[1]!=0x47) return 0;
1797 if(buf[2]==0x4d) return 1;
1798 if(buf[2]==0x48) return 2;
1799 return 0;
1802 static void de_run_cserve_rle(deark *c, de_module_params *mparams)
1804 int fmt;
1805 i64 w, expected_h, actual_h;
1806 i64 max_npixels;
1807 i64 npixels_expected;
1808 i64 npixels_found;
1809 i64 pos;
1810 u8 next_color;
1811 dbuf *unc_pixels = NULL;
1812 de_bitmap *img = NULL;
1813 de_color pal[256];
1815 fmt = get_cserve_rle_fmt(c);
1816 if(fmt==1) {
1817 w = 128;
1818 expected_h = 96;
1820 else if(fmt==2) {
1821 w = 256;
1822 expected_h = 192;
1824 else {
1825 de_err(c, "Not a CompuServe RLE file");
1826 goto done;
1829 de_dbg(c, "width: %"I64_FMT, w);
1830 npixels_expected = w*expected_h;
1831 #define CSRLE_MAX_H 1920 // arbitrary
1832 max_npixels = w*CSRLE_MAX_H;
1833 unc_pixels = dbuf_create_membuf(c, max_npixels, 0x1);
1834 dbuf_enable_wbuffer(unc_pixels);
1835 pos = 3;
1836 npixels_found = 0;
1837 next_color = 1; // 1=black, 2=white, 0=unset
1838 while(1) {
1839 u8 x;
1841 if(npixels_found >= max_npixels) {
1842 break;
1844 if(pos >= c->infile->len) break;
1846 x = de_getbyte_p(&pos);
1847 if(x>=0x20) {
1848 i64 count;
1850 count = (i64)x - 0x20;
1851 dbuf_write_run(unc_pixels, next_color, count);
1852 npixels_found += count;
1853 next_color = (next_color==1)?2:1;
1855 else if(x==0x1b) {
1856 break;
1858 // TODO: Could do more error checking
1861 dbuf_flush(unc_pixels);
1862 actual_h = expected_h;
1863 if(npixels_found != npixels_expected) {
1864 de_warn(c, "Expected %"I64_FMT" pixels, found %"I64_FMT"%s", npixels_expected,
1865 npixels_found,
1866 ((npixels_found>npixels_expected && !c->padpix)?" (try -padpix)":""));
1867 if(npixels_found>npixels_expected && c->padpix) {
1868 actual_h = de_pad_to_n(npixels_found, w)/w;
1872 img = de_bitmap_create(c, w, actual_h, 3);
1873 de_zeromem(pal, sizeof(pal));
1874 // Images that don't end cleanly are common enough that we go to
1875 // the trouble of making missing pixels a special color.
1876 pal[0] = DE_MAKE_RGB(255,0,255);
1877 pal[1] = DE_STOCKCOLOR_BLACK;
1878 pal[2] = DE_STOCKCOLOR_WHITE;
1879 de_convert_image_paletted(unc_pixels, 0, 8, w, pal, img, 0);
1880 de_bitmap_write_to_file(img, NULL, DE_CREATEFLAG_OPT_IMAGE);
1882 done:
1883 dbuf_close(unc_pixels);
1884 de_bitmap_destroy(img);
1887 static int de_identify_cserve_rle(deark *c)
1889 int x;
1891 x = get_cserve_rle_fmt(c);
1892 if(x==0) return 0;
1893 return 85;
1896 void de_module_cserve_rle(deark *c, struct deark_module_info *mi)
1898 mi->id = "cserve_rle";
1899 mi->desc = "CompuServe RLE";
1900 mi->run_fn = de_run_cserve_rle;
1901 mi->identify_fn = de_identify_cserve_rle;
1904 // **************************************************************************
1905 // Lotus Manuscript graphics (.bit, .rle)
1906 // **************************************************************************
1908 struct lotus_mscr_ctx {
1909 i64 w, h;
1910 i64 rowspan;
1911 de_finfo *fi;
1914 // Warning: This algorithm is based on reverse engineering, and might not
1915 // be quite right.
1916 static void do_lotus_mscr_rle(deark *c, struct lotus_mscr_ctx *d)
1918 i64 npixels_expected;
1919 i64 npixels_found;
1920 i64 pos;
1921 dbuf *unc_pixels = NULL;
1922 de_bitmap *img = NULL;
1923 de_color pal[256];
1925 npixels_expected = d->w*d->h;
1926 unc_pixels = dbuf_create_membuf(c, npixels_expected, 0x1);
1927 dbuf_enable_wbuffer(unc_pixels);
1928 pos = 9;
1929 npixels_found = 0;
1931 while(1) {
1932 i64 count;
1933 u8 color;
1934 u8 x;
1936 if(npixels_found >= npixels_expected) break;
1937 if(pos >= c->infile->len) break;
1939 x = de_getbyte_p(&pos);
1940 color = x>>7;
1941 count = (i64)(x & 0x7f);
1942 if(count==0) count = 128;
1944 dbuf_write_run(unc_pixels, color, count);
1945 npixels_found += count;
1948 dbuf_flush(unc_pixels);
1949 if(npixels_found != npixels_expected) {
1950 de_warn(c, "Expected %"I64_FMT" pixels, found %"I64_FMT, npixels_expected,
1951 npixels_found);
1954 img = de_bitmap_create(c, d->w, d->h, 1);
1955 de_zeromem(pal, sizeof(pal));
1956 pal[0] = DE_STOCKCOLOR_WHITE;
1957 pal[1] = DE_STOCKCOLOR_BLACK;
1958 de_convert_image_paletted(unc_pixels, 0, 8, d->w, pal, img, 0);
1959 de_bitmap_write_to_file_finfo(img, d->fi, 0);
1961 dbuf_close(unc_pixels);
1962 de_bitmap_destroy(img);
1965 static void de_run_lotus_mscr(deark *c, de_module_params *mparams)
1967 i64 pos = 0;
1968 i64 dens1, dens2;
1969 u8 x;
1970 u8 is_rle;
1971 struct lotus_mscr_ctx *d = NULL;
1973 d = de_malloc(c, sizeof(struct lotus_mscr_ctx));
1974 d->fi = de_finfo_create(c);
1975 x = de_getbyte_p(&pos);
1976 if(x=='B') {
1977 is_rle = 0;
1979 else if(x=='R') {
1980 is_rle = 1;
1982 else {
1983 de_err(c, "Not a Lotus Manuscript file");
1984 goto done;
1986 de_dbg(c, "compressed: %u", (UI)is_rle);
1987 dens1 = de_getu16le_p(&pos);
1988 dens2 = de_getu16le_p(&pos);
1989 de_dbg(c, "dpi: %d, %d", (int)dens1, (int)dens2);
1990 // TODO: Figure out which dpi is which.
1991 // ART2WP thinks x is first, but that's a little surprising when the y
1992 // *dimension* is first, so I'm not trusting it.
1993 if(dens1==dens2 && dens1>=50 && dens1<=1200) {
1994 d->fi->density.code = DE_DENSITY_DPI;
1995 d->fi->density.xdens = (double)dens1;
1996 d->fi->density.ydens = d->fi->density.xdens;
1998 d->h = de_getu16le_p(&pos);
1999 d->rowspan = de_getu16le_p(&pos);
2000 d->w = d->rowspan * 8;
2001 de_dbg_dimensions(c, d->w, d->h);
2002 if(!de_good_image_dimensions(c, d->w, d->h)) goto done;
2003 if(is_rle) {
2004 do_lotus_mscr_rle(c, d);
2006 else {
2007 de_convert_and_write_image_bilevel(c->infile, pos, d->w, d->h, d->rowspan,
2008 DE_CVTF_WHITEISZERO, d->fi, 0);
2011 done:
2012 if(d) {
2013 de_finfo_destroy(c, d->fi);
2014 de_free(c, d);
2018 static int de_identify_lotus_mscr(deark *c)
2020 u8 is_rle, x;
2021 i64 d1, d2, h, rb;
2023 x = de_getbyte(0);
2024 if(x=='B' && de_input_file_has_ext(c, "bit")) {
2025 is_rle = 0;
2027 else if(x=='R' && de_input_file_has_ext(c, "rle")) {
2028 is_rle = 1;
2030 else {
2031 return 0;
2034 d1 = de_getu16le(1);
2035 d2 = de_getu16le(3);
2036 if(is_rle) {
2037 // RLE is particularly hard to detect, because we can't use the file size.
2038 if(d1!=d2) return 0;
2039 if(d1!=72 && d1!=300) return 0;
2041 else {
2042 if(d1>=600 || d2>600) return 0;
2045 h = de_getu16le(5);
2046 rb = de_getu16le(7);
2047 if(h==0 || rb==0 || h>3300 || rb>320) return 0;
2048 if(is_rle) {
2049 return 12;
2051 else {
2052 if(9+h*rb == c->infile->len) return 75;
2055 return 0;
2058 void de_module_lotus_mscr(deark *c, struct deark_module_info *mi)
2060 mi->id = "lotus_mscr";
2061 mi->desc = "Lotus Manuscript graphics";
2062 mi->run_fn = de_run_lotus_mscr;
2063 mi->identify_fn = de_identify_lotus_mscr;
2066 // **************************************************************************
2067 // Fastgraph SPR
2068 // Minimal support.
2069 // **************************************************************************
2071 struct fastgraph_ctx {
2072 u8 is_ppr;
2073 u8 pal_is_set;
2074 i64 w, h; // 0 if unknown
2075 i64 img_startpos;
2076 i64 max_unc_bytes;
2077 de_color pal[256];
2078 u8 max_color_used;
2081 static void decompress_fastgraph_spr(deark *c, struct fastgraph_ctx *d,
2082 dbuf *unc_pixels, i64 pos1)
2084 i64 pos = pos1;
2085 i64 unc_total = 0;
2087 d->max_color_used = 1;
2089 while(1) {
2090 u8 clr;
2091 i64 count;
2093 if(pos >= c->infile->len) break;
2094 if(unc_total >= d->max_unc_bytes) break;
2096 clr = de_getbyte_p(&pos);
2097 count = (i64)de_getbyte_p(&pos);
2098 if(count>0) {
2099 if(clr > d->max_color_used) {
2100 d->max_color_used = clr;
2102 dbuf_write_run(unc_pixels, clr, count);
2104 unc_total += count;
2107 dbuf_flush(unc_pixels);
2110 // This is a pixel-oriented 4bpp format. We expand it to 8 bits per pixel.
2111 static void decompress_fastgraph_ppr(deark *c, struct fastgraph_ctx *d,
2112 dbuf *unc_pixels, i64 pos1)
2114 i64 pos = pos1;
2115 i64 unc_total = 0;
2117 d->max_color_used = 1;
2119 while(1) {
2120 u8 b;
2121 u8 clr[2];
2122 i64 count;
2123 UI k;
2125 if(pos >= c->infile->len) break;
2126 if(unc_total >= d->max_unc_bytes) break;
2128 b = de_getbyte_p(&pos);
2129 clr[0] = b>>4;
2130 clr[1] = b & 0x0f;
2132 for(k=0; k<2; k++) {
2133 count = (i64)de_getbyte_p(&pos);
2134 if(count>0) {
2135 if(clr[k] > d->max_color_used) {
2136 d->max_color_used = clr[k];
2138 dbuf_write_run(unc_pixels, clr[k], count);
2139 unc_total += count;
2144 dbuf_flush(unc_pixels);
2147 static int has_fastgraph_spr_sig(deark *c)
2149 return !dbuf_memcmp(c->infile, 0, (const u8*)"F\0A\0S\0T\0G\0", 10);
2152 // Caller sets
2153 // d->is_ppr
2154 // optional: ->w, or both ->w and ->h
2155 // optional: ->pal_is_set and ->pal
2156 // optional: ->img_startpos
2157 static void do_fastgraph_internal(deark *c, struct fastgraph_ctx *d)
2159 dbuf *unc_pixels = NULL;
2160 de_bitmap *img = NULL;
2161 const char *s;
2163 if(d->w==0) {
2164 s = de_get_ext_option(c, "width");
2165 if(s) {
2166 d->w = de_atoi64(s);
2169 if(d->h==0) {
2170 s = de_get_ext_option(c, "height");
2171 if(s) {
2172 d->h = de_atoi64(s);
2176 if(d->w==0) {
2177 de_err(c, "Image width unknown. Try \"-opt width=...\".");
2178 goto done;
2181 if(d->h>0) {
2182 de_dbg_dimensions(c, d->w, d->h);
2184 else {
2185 de_dbg(c, "width: %"I64_FMT, d->w);
2188 if(d->w<1 || d->w>c->max_image_dimension ||
2189 d->h<0 || d->h>c->max_image_dimension)
2191 de_err(c, "Bad image dimensions");
2192 goto done;
2195 if(d->h==0) {
2196 d->max_unc_bytes = DE_MAX_SANE_OBJECT_SIZE;
2197 unc_pixels = dbuf_create_membuf(c, 0, 0);
2199 else {
2200 d->max_unc_bytes = d->w * d->h;
2201 unc_pixels = dbuf_create_membuf(c, d->max_unc_bytes, 0x1);
2204 if(d->is_ppr) {
2205 decompress_fastgraph_ppr(c, d, unc_pixels, d->img_startpos);
2207 else {
2208 decompress_fastgraph_spr(c, d, unc_pixels, d->img_startpos);
2211 de_dbg(c, "decompressed %"I64_FMT" pixels", unc_pixels->len);
2212 if(d->h==0) {
2213 d->h = de_pad_to_n(unc_pixels->len, d->w) / d->w;
2214 de_dbg(c, "height: %"I64_FMT, d->h);
2217 if(!de_good_image_dimensions(c, d->w, d->h)) goto done;
2219 img = de_bitmap_create(c, d->w, d->h, d->pal_is_set?3:1);
2220 if(!d->pal_is_set) {
2221 de_info(c, "Note: Color map unknown. Rendering as grayscale.");
2222 de_make_grayscale_palette(d->pal, 1+(i64)d->max_color_used, 0);
2225 de_convert_image_paletted(unc_pixels, 0, 8, d->w, d->pal, img, 0);
2226 de_bitmap_write_to_file(img, NULL, DE_CREATEFLAG_FLIP_IMAGE |
2227 DE_CREATEFLAG_OPT_IMAGE);
2229 done:
2230 dbuf_close(unc_pixels);
2231 de_bitmap_destroy(img);
2234 static void de_run_fastgraph_spr(deark *c, de_module_params *mparams)
2236 struct fastgraph_ctx *d = NULL;
2238 d = de_malloc(c, sizeof(struct fastgraph_ctx));
2239 d->is_ppr = 0;
2241 if(has_fastgraph_spr_sig(c)) {
2242 d->w = 1 + 256*(i64)de_getbyte(18) + (i64)de_getbyte(16);
2243 d->h = 1 + 256*(i64)de_getbyte(22) + (i64)de_getbyte(20);
2244 d->img_startpos = 26;
2247 do_fastgraph_internal(c, d);
2249 de_free(c, d);
2252 static int de_identify_fastgraph_spr(deark *c)
2254 if(has_fastgraph_spr_sig(c)) {
2255 return 90;
2257 return 0;
2260 static void help_fastgraph_common(deark *c)
2262 de_msg(c, "-opt width=<n> : Hint: image width");
2263 de_msg(c, "-opt height=<n> : Hint: image height");
2266 static void de_help_fastgraph_spr(deark *c)
2268 help_fastgraph_common(c);
2271 void de_module_fastgraph_spr(deark *c, struct deark_module_info *mi)
2273 mi->id = "fastgraph_spr";
2274 mi->desc = "Fastgraph SPR";
2275 mi->run_fn = de_run_fastgraph_spr;
2276 mi->identify_fn = de_identify_fastgraph_spr;
2277 mi->help_fn = de_help_fastgraph_spr;
2278 mi->flags |= DE_MODFLAG_HIDDEN;
2281 // **************************************************************************
2282 // Fastgraph PPR
2283 // Minimal support.
2284 // **************************************************************************
2286 static void de_run_fastgraph_ppr(deark *c, de_module_params *mparams)
2288 struct fastgraph_ctx *d = NULL;
2290 d = de_malloc(c, sizeof(struct fastgraph_ctx));
2291 d->is_ppr = 1;
2293 do_fastgraph_internal(c, d);
2295 de_free(c, d);
2298 static void de_help_fastgraph_ppr(deark *c)
2300 help_fastgraph_common(c);
2303 void de_module_fastgraph_ppr(deark *c, struct deark_module_info *mi)
2305 mi->id = "fastgraph_ppr";
2306 mi->desc = "Fastgraph PPR";
2307 mi->run_fn = de_run_fastgraph_ppr;
2308 mi->identify_fn = NULL;
2309 mi->help_fn = de_help_fastgraph_ppr;
2310 mi->flags |= DE_MODFLAG_HIDDEN;
2313 // **************************************************************************
2314 // Young Picasso .YP
2315 // **************************************************************************
2317 static int has_yp_sig(deark *c)
2319 return !dbuf_memcmp(c->infile, 0, (const u8*)"P\0\0P\0\0R\0\0", 9);
2322 static void de_run_yp(deark *c, de_module_params *mparams)
2324 struct fastgraph_ctx *d = NULL;
2325 de_bitmap *img = NULL;
2326 de_finfo *fi = NULL;
2327 dbuf *unc_pixels = NULL;
2329 d = de_malloc(c, sizeof(struct fastgraph_ctx));
2330 // TODO?: Maybe we should call do_fastgraph_internal() instead of
2331 // just decompress_fastgraph_ppr(), but it would be a bit messy.
2332 d->is_ppr = 1;
2334 if(has_yp_sig(c)) {
2335 d->w = (i64)de_getbyte(9) * 256;
2336 d->w += (i64)de_getbyte(12);
2337 d->h = (i64)de_getbyte(15) * 256;
2338 d->h += (i64)de_getbyte(18);
2339 d->img_startpos = 24; // (Not actually necessary)
2341 else {
2342 d->w = 320;
2343 d->h = 200;
2346 de_dbg_dimensions(c, d->w, d->h);
2347 if(!de_good_image_dimensions(c, d->w, d->h)) goto done;
2349 d->max_unc_bytes = d->w * d->h;
2350 unc_pixels = dbuf_create_membuf(c, d->max_unc_bytes, 0x1);
2351 dbuf_enable_wbuffer(unc_pixels);
2352 decompress_fastgraph_ppr(c, d, unc_pixels, d->img_startpos);
2354 fi = de_finfo_create(c);
2355 fi->density.code = DE_DENSITY_UNK_UNITS;
2356 fi->density.xdens = 6.0;
2357 fi->density.ydens = 5.0;
2359 de_copy_std_palette(DE_PALID_PC16, 0, 0, d->pal, 16, 0);
2360 img = de_bitmap_create(c, d->w, d->h, 3);
2361 de_convert_image_paletted(unc_pixels, 0, 8, d->w, d->pal, img, 0);
2362 de_bitmap_write_to_file_finfo(img, fi, DE_CREATEFLAG_FLIP_IMAGE |
2363 DE_CREATEFLAG_OPT_IMAGE);
2365 done:
2366 dbuf_close(unc_pixels);
2367 de_bitmap_destroy(img);
2368 de_finfo_destroy(c, fi);
2369 de_free(c, d);
2372 static int de_identify_yp(deark *c)
2374 if(has_yp_sig(c)) {
2375 if(de_input_file_has_ext(c, "yp")) return 100;
2376 return 75;
2378 return 0;
2381 void de_module_young_picasso(deark *c, struct deark_module_info *mi)
2383 mi->id = "young_picasso";
2384 mi->desc = "Young Picasso .YP";
2385 mi->run_fn = de_run_yp;
2386 mi->identify_fn = de_identify_yp;
2389 // **************************************************************************
2390 // Icon Manager .ICA (Impact Software, Leonard A. Gray)
2391 // **************************************************************************
2393 struct iconmgr_icon_ctx {
2394 i64 icon_pos;
2395 i64 total_len;
2396 de_ucstring *name;
2399 struct iconmgr_ica_ctx {
2400 u8 ver;
2401 u8 need_errmsg;
2402 de_encoding input_encoding;
2403 i64 icon_count;
2404 i64 reported_file_size;
2405 de_color pal[16];
2408 static void iconmgr_icon_destroy(deark *c, struct iconmgr_icon_ctx *md)
2410 if(!md) return;
2411 ucstring_destroy(md->name);
2412 de_free(c, md);
2415 // On fatal error, leaves md->total_len set to 0.
2416 static void do_iconmgr_icon(deark *c, struct iconmgr_ica_ctx *d,
2417 struct iconmgr_icon_ctx *md)
2419 de_bitmap *img = NULL;
2420 de_bitmap *mask = NULL;
2421 de_finfo *fi = NULL;
2422 i64 pos;
2423 i64 bpp, xpos, ypos;
2424 int saved_indent_level;
2426 de_dbg_indent_save(c, &saved_indent_level);
2427 de_dbg(c, "icon at %"I64_FMT, md->icon_pos);
2428 de_dbg_indent(c, 1);
2429 pos = md->icon_pos;
2431 // Try to detect if we've gone off the rails.
2432 // TODO: Are bit depths other than 4 possible?
2433 bpp = de_getbyte_p(&pos);
2434 xpos = de_getu16le_p(&pos);
2435 ypos = de_getu16le_p(&pos);
2436 if(bpp!=4 || xpos>=4096 || ypos>=4096) {
2437 d->need_errmsg = 1;
2438 goto done;
2441 if(d->ver==2) {
2442 md->name = ucstring_create(c);
2443 dbuf_read_to_ucstring(c->infile, pos, 26, md->name, DE_CONVFLAG_STOP_AT_NUL,
2444 d->input_encoding);
2445 de_dbg(c, "name: \"%s\"", ucstring_getpsz_d(md->name));
2446 pos += 26;
2449 de_dbg(c, "bitmap at %"I64_FMT, pos);
2450 img = de_bitmap_create(c, 32, 32, 4);
2451 de_convert_image_paletted(c->infile, pos, 4, 16, d->pal, img, 0);
2452 pos += 512;
2454 de_dbg(c, "mask at %"I64_FMT, pos);
2455 mask = de_bitmap_create(c, 32, 32, 1);
2456 de_convert_image_bilevel(c->infile, pos, 4, mask, 0);
2457 pos += 128;
2459 de_bitmap_apply_mask(img, mask, DE_BITMAPFLAG_WHITEISTRNS);
2461 fi = de_finfo_create(c);
2462 if(c->filenames_from_file && ucstring_isnonempty(md->name)) {
2463 de_finfo_set_name_from_ucstring(c, fi, md->name, 0);
2466 de_bitmap_write_to_file_finfo(img, fi, DE_CREATEFLAG_FLIP_IMAGE|DE_CREATEFLAG_OPT_IMAGE);
2467 md->total_len = pos - md->icon_pos;
2469 done:
2470 de_bitmap_destroy(img);
2471 de_bitmap_destroy(mask);
2472 de_finfo_destroy(c, fi);
2473 de_dbg_indent_restore(c, saved_indent_level);
2476 static void de_run_iconmgr_ica(deark *c, de_module_params *mparams)
2478 struct iconmgr_ica_ctx *d = NULL;
2479 struct iconmgr_icon_ctx *md = NULL;
2480 u8 b;
2481 i64 pos;
2483 d = de_malloc(c, sizeof(struct iconmgr_ica_ctx));
2484 d->input_encoding = de_get_input_encoding(c, NULL, DE_ENCODING_WINDOWS1252);
2486 b = de_getbyte(2);
2487 if(b=='M') {
2488 d->ver = 1;
2490 else if(b=='2') {
2491 d->ver = 2;
2493 else {
2494 d->need_errmsg = 1;
2495 goto done;
2498 d->icon_count = de_getu16le(4);
2499 de_dbg(c, "count: %d", (int)d->icon_count);
2500 d->reported_file_size = de_getu32le(4);
2502 de_copy_std_palette(DE_PALID_WIN16, 0, 0, d->pal, 16, 0);
2503 pos = 18;
2504 while(1) {
2505 if(pos>=c->infile->len || pos>=d->reported_file_size) goto done;
2506 if(md) {
2507 iconmgr_icon_destroy(c, md);
2508 md = NULL;
2510 md = de_malloc(c, sizeof(struct iconmgr_icon_ctx));
2511 md->icon_pos = pos;
2512 do_iconmgr_icon(c, d, md);
2513 if(md->total_len<=0) goto done;
2514 pos += md->total_len;
2517 done:
2518 iconmgr_icon_destroy(c, md);
2519 if(d) {
2520 if(d->need_errmsg) {
2521 de_err(c, "Bad or unsupported file");
2523 de_free(c, d);
2527 static int de_identify_iconmgr_ica(deark *c)
2529 u8 b;
2531 if(dbuf_memcmp(c->infile, 0, "IC", 2)) return 0;
2532 b = de_getbyte(2);
2533 if(de_getbyte(3) != 0) return 0;
2534 if(b=='M' || b=='2') {
2535 return 90;
2537 return 0;
2540 void de_module_iconmgr_ica(deark *c, struct deark_module_info *mi)
2542 mi->id = "iconmgr_ica";
2543 mi->desc = "Icon Manager Archive (.ica)";
2544 mi->run_fn = de_run_iconmgr_ica;
2545 mi->identify_fn = de_identify_iconmgr_ica;
2548 // **************************************************************************
2549 // ThumbsPlus (v1.x-2.x) thumbnail database (.tud)
2550 // **************************************************************************
2552 #define THUMBSPLUS_W 96
2553 #define THUMBSPLUS_H 72
2554 #define THUMBSPLUS_IMGSIZE (THUMBSPLUS_W*THUMBSPLUS_H)
2556 struct thumbsplus_icon_ctx {
2557 i64 icon_pos;
2558 i64 data_len;
2559 i64 total_len;
2560 struct de_stringreaderdata *orig_name_srd;
2561 de_ucstring *name_token;
2562 struct de_timestamp mod_dt;
2565 struct thumbsplus_ctx {
2566 u8 ver;
2567 u8 need_errmsg;
2568 de_encoding input_encoding;
2569 i64 icon_count;
2570 i64 reported_file_size;
2571 de_color pal[256];
2574 static void thumbsplus_icon_destroy(deark *c, struct thumbsplus_icon_ctx *md)
2576 if(!md) return;
2577 de_destroy_stringreaderdata(c, md->orig_name_srd);
2578 ucstring_destroy(md->name_token);
2579 de_free(c, md);
2582 static void thumbsplus_decompress(deark *c, struct thumbsplus_ctx *d,
2583 struct thumbsplus_icon_ctx *md, i64 pos1, i64 len, dbuf *unc_pixels)
2585 i64 endpos = pos1 + len;
2586 i64 pos = pos1;
2588 while(1) {
2589 i64 count;
2590 u8 val;
2591 u8 b;
2593 if(pos >= endpos) break;
2594 b = de_getbyte_p(&pos);
2595 if(b>=236) {
2596 if(b==0xff) {
2597 count = (i64)de_getbyte_p(&pos);
2599 else {
2600 count = (i64)b - 233;
2602 val = de_getbyte_p(&pos);
2603 dbuf_write_run(unc_pixels, val, count);
2605 else {
2606 dbuf_writebyte(unc_pixels, b);
2611 // On success, sets md->total_len.
2612 static void do_thumbsplus_icon(deark *c, struct thumbsplus_ctx *d,
2613 struct thumbsplus_icon_ctx *md)
2615 de_bitmap *img = NULL;
2616 de_finfo *fi = NULL;
2617 dbuf *unc_pixels = NULL;
2618 i64 pos;
2619 i64 mod_time_raw, mod_date_raw;
2620 int saved_indent_level;
2622 de_dbg_indent_save(c, &saved_indent_level);
2623 de_dbg(c, "icon at %"I64_FMT, md->icon_pos);
2624 de_dbg_indent(c, 1);
2625 pos = md->icon_pos;
2626 pos += 2; // ?
2628 mod_date_raw = de_getu16le_p(&pos);
2629 mod_time_raw = de_getu16le_p(&pos);
2630 de_dos_datetime_to_timestamp(&md->mod_dt, mod_date_raw, mod_time_raw);
2631 md->mod_dt.tzcode = DE_TZCODE_LOCAL;
2632 datetime_dbgmsg(c, &md->mod_dt, "mod time");
2634 md->data_len = de_getu16le_p(&pos);
2635 de_dbg(c, "cmpr len: %"I64_FMT, md->data_len);
2636 pos += 12; // ?
2638 md->orig_name_srd = dbuf_read_string(c->infile, pos, 260, 260,
2639 DE_CONVFLAG_STOP_AT_NUL, d->input_encoding);
2640 if(!md->orig_name_srd->found_nul) {
2641 d->need_errmsg = 1;
2642 goto done;
2644 de_dbg(c, "name: \"%s\"", ucstring_getpsz_d(md->orig_name_srd->str));
2645 pos += md->orig_name_srd->bytes_consumed;
2647 md->name_token = ucstring_create(c);
2648 get_base_filename(md->orig_name_srd->str, md->name_token);
2650 de_dbg(c, "bitmap at %"I64_FMT, pos);
2651 unc_pixels = dbuf_create_membuf(c, THUMBSPLUS_IMGSIZE+2, 0x1);
2652 dbuf_enable_wbuffer(unc_pixels);
2653 thumbsplus_decompress(c, d, md, pos, md->data_len, unc_pixels);
2654 dbuf_flush(unc_pixels);
2655 if(unc_pixels->len != THUMBSPLUS_IMGSIZE) {
2656 // We're strict about this, because it's how we detect if we've gone off
2657 // the rails.
2658 de_err(c, "Decompression failed");
2659 goto done;
2662 img = de_bitmap_create(c, THUMBSPLUS_W, THUMBSPLUS_H, 3);
2663 de_convert_image_paletted(unc_pixels, 0, 8, THUMBSPLUS_W, d->pal, img, 0);
2665 fi = de_finfo_create(c);
2666 if(c->filenames_from_file && ucstring_isnonempty(md->name_token)) {
2667 de_finfo_set_name_from_ucstring(c, fi, md->name_token, 0);
2669 fi->timestamp[DE_TIMESTAMPIDX_MODIFY] = md->mod_dt;
2670 de_bitmap_write_to_file_finfo(img, fi, DE_CREATEFLAG_FLIP_IMAGE|DE_CREATEFLAG_OPT_IMAGE);
2672 pos += md->data_len;
2673 md->total_len = pos - md->icon_pos;
2675 done:
2676 dbuf_close(unc_pixels);
2677 de_bitmap_destroy(img);
2678 de_finfo_destroy(c, fi);
2679 de_dbg_indent_restore(c, saved_indent_level);
2682 static void make_thumbsplus_pal(deark *c, struct thumbsplus_ctx *d)
2684 static const u8 tppal[236*3] = {
2685 0x00,0x00,0x00,0xff,0xff,0xff,0x09,0x09,0x09,0x13,0x13,0x13,0x1d,0x1d,0x1d,0x27,0x27,0x27,
2686 0x31,0x31,0x31,0x3b,0x3b,0x3b,0x44,0x44,0x44,0x4e,0x4e,0x4e,0x58,0x58,0x58,0x62,0x62,0x62,
2687 0x6c,0x6c,0x6c,0x76,0x76,0x76,0x89,0x89,0x89,0x93,0x93,0x93,0x9d,0x9d,0x9d,0xa7,0xa7,0xa7,
2688 0xb0,0xb0,0xb0,0xba,0xba,0xba,0xc4,0xc4,0xc4,0xce,0xce,0xce,0xd7,0xd7,0xd7,0xe1,0xe1,0xe1,
2689 0xeb,0xeb,0xeb,0xf5,0xf5,0xf5,0x03,0x13,0x03,0x06,0x27,0x06,0x09,0x3a,0x09,0x0c,0x4e,0x0c,
2690 0x0f,0x62,0x0f,0x12,0x75,0x12,0x15,0x89,0x15,0x18,0x9c,0x18,0x1b,0xb0,0x1b,0x1e,0xc4,0x1e,
2691 0x21,0xd7,0x21,0x24,0xeb,0x24,0x38,0xff,0x38,0x49,0xff,0x49,0x59,0xff,0x59,0x6a,0xff,0x6a,
2692 0x7a,0xff,0x7a,0x8b,0xff,0x8b,0x9b,0xff,0x9b,0xac,0xff,0xac,0xbc,0xff,0xbc,0xcd,0xff,0xcd,
2693 0xdd,0xff,0xdd,0xee,0xff,0xee,0x03,0x03,0x13,0x06,0x06,0x27,0x09,0x09,0x3a,0x0c,0x0c,0x4e,
2694 0x0f,0x0f,0x62,0x12,0x12,0x75,0x15,0x15,0x89,0x18,0x18,0x9c,0x1b,0x1b,0xb0,0x1e,0x1e,0xc4,
2695 0x21,0x21,0xd7,0x24,0x24,0xeb,0x38,0x38,0xff,0x49,0x49,0xff,0x59,0x59,0xff,0x6a,0x6a,0xff,
2696 0x7a,0x7a,0xff,0x8b,0x8b,0xff,0x9b,0x9b,0xff,0xac,0xac,0xff,0xbc,0xbc,0xff,0xcd,0xcd,0xff,
2697 0xdd,0xdd,0xff,0xee,0xee,0xff,0x13,0x13,0x03,0x27,0x27,0x06,0x3a,0x3a,0x09,0x4e,0x4e,0x0c,
2698 0x62,0x62,0x0f,0x75,0x75,0x12,0x89,0x89,0x15,0x9c,0x9c,0x18,0xb0,0xb0,0x1b,0xc4,0xc4,0x1e,
2699 0xd7,0xd7,0x21,0xeb,0xeb,0x24,0xff,0xff,0x38,0xff,0xff,0x49,0xff,0xff,0x59,0xff,0xff,0x6a,
2700 0xff,0xff,0x7a,0xff,0xff,0x8b,0xff,0xff,0x9b,0xff,0xff,0xac,0xff,0xff,0xbc,0xff,0xff,0xcd,
2701 0xff,0xff,0xdd,0xff,0xff,0xee,0x0d,0x03,0x13,0x1b,0x06,0x27,0x29,0x09,0x3a,0x37,0x0c,0x4e,
2702 0x45,0x0f,0x62,0x53,0x12,0x75,0x60,0x15,0x89,0x6e,0x18,0x9c,0x7c,0x1b,0xb0,0x8a,0x1e,0xc4,
2703 0x98,0x21,0xd7,0xa6,0x24,0xeb,0xb9,0x38,0xff,0xbf,0x49,0xff,0xc5,0x59,0xff,0xcb,0x6a,0xff,
2704 0xd0,0x7a,0xff,0xd6,0x8b,0xff,0xdc,0x9b,0xff,0xe2,0xac,0xff,0xe7,0xbc,0xff,0xed,0xcd,0xff,
2705 0xf3,0xdd,0xff,0xf9,0xee,0xff,0x03,0x13,0x13,0x06,0x27,0x27,0x09,0x3a,0x3a,0x0c,0x4e,0x4e,
2706 0x0f,0x62,0x62,0x12,0x75,0x75,0x15,0x89,0x89,0x18,0x9c,0x9c,0x1b,0xb0,0xb0,0x1e,0xc4,0xc4,
2707 0x21,0xd7,0xd7,0x24,0xeb,0xeb,0x38,0xff,0xff,0x49,0xff,0xff,0x59,0xff,0xff,0x6a,0xff,0xff,
2708 0x7a,0xff,0xff,0x8b,0xff,0xff,0x9b,0xff,0xff,0xac,0xff,0xff,0xbc,0xff,0xff,0xcd,0xff,0xff,
2709 0xdd,0xff,0xff,0xee,0xff,0xff,0x12,0x0a,0x03,0x24,0x15,0x06,0x37,0x20,0x09,0x49,0x2b,0x0c,
2710 0x5c,0x35,0x0f,0x6e,0x40,0x12,0x81,0x4b,0x15,0x93,0x56,0x18,0xa6,0x60,0x1b,0xb8,0x6b,0x1e,
2711 0xcb,0x76,0x21,0xdd,0x81,0x24,0xf1,0x94,0x38,0xf2,0x9d,0x49,0xf3,0xa6,0x59,0xf4,0xaf,0x6a,
2712 0xf5,0xb8,0x7a,0xf6,0xc1,0x8b,0xf8,0xc9,0x9b,0xf9,0xd2,0xac,0xfa,0xdb,0xbc,0xfb,0xe4,0xcd,
2713 0xfc,0xed,0xdd,0xfd,0xf6,0xee,0x13,0x03,0x03,0x27,0x06,0x06,0x3a,0x09,0x09,0x4e,0x0c,0x0c,
2714 0x62,0x0f,0x0f,0x75,0x12,0x12,0x89,0x15,0x15,0x9c,0x18,0x18,0xb0,0x1b,0x1b,0xc4,0x1e,0x1e,
2715 0xd7,0x21,0x21,0xeb,0x24,0x24,0xff,0x38,0x38,0xff,0x49,0x49,0xff,0x59,0x59,0xff,0x6a,0x6a,
2716 0xff,0x7a,0x7a,0xff,0x8b,0x8b,0xff,0x9b,0x9b,0xff,0xac,0xac,0xff,0xbc,0xbc,0xff,0xcd,0xcd,
2717 0xff,0xdd,0xdd,0xff,0xee,0xee,0x12,0x0c,0x08,0x25,0x18,0x10,0x38,0x24,0x19,0x4a,0x30,0x21,
2718 0x5d,0x3c,0x29,0x70,0x48,0x32,0x82,0x54,0x3a,0x95,0x60,0x42,0xa8,0x6c,0x4b,0xba,0x78,0x53,
2719 0xcd,0x84,0x5b,0xe2,0x98,0x6f,0xe4,0xa1,0x7b,0xe7,0xa9,0x87,0xe9,0xb2,0x93,0xeb,0xba,0x9f,
2720 0xee,0xc3,0xab,0xf0,0xcb,0xb7,0xf3,0xd4,0xc3,0xf5,0xdc,0xcf,0xf7,0xe5,0xdb,0xfa,0xed,0xe7,
2721 0xfc,0xf6,0xf3,0x12,0x14,0x18,0x24,0x28,0x30,0x36,0x3c,0x48,0x48,0x50,0x60,0x75,0x7d,0x8e,
2722 0x91,0x97,0xa5,0xac,0xb1,0xbb,0xc8,0xcb,0xd2,0xe3,0xe5,0xe8,0x10,0x14,0x0f,0x21,0x28,0x1e,
2723 0x32,0x3c,0x2d,0x42,0x50,0x3c,0x53,0x64,0x4b,0x7d,0x8e,0x75,0x97,0xa5,0x91,0xb1,0xbb,0xac,
2724 0xcb,0xd2,0xc8,0xe5,0xe8,0xe3 };
2726 de_copy_palette_from_rgb24(tppal, d->pal, 236);
2729 static void de_run_thumbsplus(deark *c, de_module_params *mparams)
2731 struct thumbsplus_ctx *d = NULL;
2732 struct thumbsplus_icon_ctx *md = NULL;
2733 i64 pos;
2735 d = de_malloc(c, sizeof(struct thumbsplus_ctx));
2736 d->input_encoding = de_get_input_encoding(c, NULL, DE_ENCODING_WINDOWS1252);
2738 pos = 4;
2739 d->icon_count = de_getu32le_p(&pos);
2740 de_dbg(c, "count: %"I64_FMT, d->icon_count);
2741 d->reported_file_size = de_getu32le_p(&pos);
2743 make_thumbsplus_pal(c, d);
2745 pos = 16;
2746 while(1) {
2747 if(pos>=c->infile->len || pos>=d->reported_file_size) goto done;
2748 if(md) {
2749 thumbsplus_icon_destroy(c, md);
2750 md = NULL;
2752 md = de_malloc(c, sizeof(struct thumbsplus_icon_ctx));
2753 md->icon_pos = pos;
2754 do_thumbsplus_icon(c, d, md);
2755 if(md->total_len<=0) goto done;
2756 pos += md->total_len;
2759 done:
2760 thumbsplus_icon_destroy(c, md);
2761 if(d) {
2762 if(d->need_errmsg) {
2763 de_err(c, "Bad or unsupported file");
2765 de_free(c, d);
2769 static int de_identify_thumbsplus(deark *c)
2771 if((UI)de_getu32be(0) == 0xbebadabeU) {
2772 return 95;
2774 return 0;
2777 void de_module_thumbsplus(deark *c, struct deark_module_info *mi)
2779 mi->id = "thumbsplus";
2780 mi->desc = "ThumbsPlus v1-2 database (.tud)";
2781 mi->run_fn = de_run_thumbsplus;
2782 mi->identify_fn = de_identify_thumbsplus;
2785 // **************************************************************************
2786 // FM Towns icon
2787 // **************************************************************************
2789 struct fmtownsicn_table_ctx {
2790 i64 idx;
2791 i64 num_icons;
2792 i64 icon_arr_offs;
2795 struct fmtownsicn_ctx {
2796 u8 fatalerrflag;
2797 u8 need_errmsg;
2798 int is_le;
2799 i64 num_tables;
2800 de_color pal16[16];
2801 de_color pal2[2];
2804 static void do_fmtownsicn_icon(deark *c, struct fmtownsicn_ctx *d,
2805 struct fmtownsicn_table_ctx *tbl, i64 idx, i64 pos1)
2807 int saved_indent_level;
2808 i64 pos = pos1;
2809 de_bitmap *img = NULL;
2810 UI createflags = 0;
2811 i64 w, h;
2812 i64 rowspan;
2813 i64 isize;
2814 i64 fg_pos;
2815 UI ncolors;
2816 UI bits_per_pixel;
2818 de_dbg_indent_save(c, &saved_indent_level);
2819 if(pos1>=c->infile->len) {
2820 d->fatalerrflag = 1;
2821 d->need_errmsg = 1;
2822 goto done;
2824 de_dbg(c, "icon header (table #%u icon #%u) at %"I64_FMT, (UI)tbl->idx,
2825 (UI)idx, pos1);
2826 de_dbg_indent(c, 1);
2827 pos += 2;
2828 pos += 4;
2829 w = de_getu16le_p(&pos);
2830 h = de_getu16le_p(&pos);
2831 de_dbg_dimensions(c, w, h);
2832 ncolors = (UI)de_getu32le_p(&pos);
2833 de_dbg(c, "num colors: %u", ncolors);
2834 isize = de_getu16le_p(&pos);
2835 de_dbg(c, "size: %"I64_FMT, isize);
2836 pos += 4;
2837 fg_pos = de_getu32le_p(&pos);
2838 de_dbg(c, "fg pos: %"I64_FMT, fg_pos);
2840 if(fg_pos <= pos1 || fg_pos + isize > c->infile->len) {
2841 d->fatalerrflag = 1;
2842 d->need_errmsg = 1;
2843 goto done;
2846 if(ncolors==2) {
2847 bits_per_pixel = 1;
2849 else if(ncolors==16) {
2850 bits_per_pixel = 4;
2852 else {
2853 de_err(c, "Unsupported image type");
2854 goto done;
2857 if(!de_good_image_dimensions(c, w, h)) goto done;
2858 img = de_bitmap_create(c, w, h, 3);
2861 if(bits_per_pixel==1) {
2862 rowspan = de_pad_to_n(w*bits_per_pixel, 8) / 8;
2863 de_convert_image_paletted(c->infile, fg_pos, 1, rowspan,
2864 d->pal2, img, 0);
2865 createflags |= DE_CREATEFLAG_IS_BWIMG;
2867 else { // 4
2868 rowspan = de_pad_to_n(w*bits_per_pixel, 32) / 8;
2869 de_convert_image_paletted(c->infile, fg_pos, 4, rowspan,
2870 d->pal16, img, 0x01);
2871 createflags |= DE_CREATEFLAG_OPT_IMAGE;
2874 de_bitmap_write_to_file(img, NULL, createflags);
2876 done:
2877 de_bitmap_destroy(img);
2878 de_dbg_indent_restore(c, saved_indent_level);
2881 static void do_fmtownsicn_table(deark *c, struct fmtownsicn_ctx *d, i64 idx,
2882 i64 pos1)
2884 int saved_indent_level;
2885 i64 pos = pos1;
2886 struct fmtownsicn_table_ctx *tbl = NULL;
2887 i64 i;
2889 de_dbg_indent_save(c, &saved_indent_level);
2891 if(pos1+32>c->infile->len) {
2892 d->fatalerrflag = 1;
2893 d->need_errmsg = 1;
2894 goto done;
2897 tbl = de_malloc(c, sizeof(struct fmtownsicn_table_ctx));
2898 tbl->idx = idx;
2900 de_dbg(c, "table #%"I64_FMT" at %"I64_FMT, idx, pos1);
2901 de_dbg_indent(c, 1);
2902 pos += 2; // id
2903 tbl->num_icons = de_getu16le_p(&pos);
2904 de_dbg(c, "num icons: %u", (UI)tbl->num_icons);
2905 pos += 2;
2906 pos += 2;
2908 tbl->icon_arr_offs = de_getu32le_p(&pos);
2909 de_dbg(c, "offset of icon array: %"I64_FMT, tbl->icon_arr_offs);
2910 if(tbl->icon_arr_offs <= pos1) {
2911 d->fatalerrflag = 1;
2912 d->need_errmsg = 1;
2913 goto done;
2916 for(i=0; i<tbl->num_icons; i++) {
2917 if(d->fatalerrflag) goto done;
2918 do_fmtownsicn_icon(c, d, tbl, i, tbl->icon_arr_offs+48*i);
2921 done:
2922 de_free(c, tbl);
2923 de_dbg_indent_restore(c, saved_indent_level);
2926 static void fmtownsicn_make_palettes(deark *c, struct fmtownsicn_ctx *d)
2928 static const u8 pal16_std[16*3] = {
2929 0x22,0x22,0x22, 0x22,0x77,0xbb, 0xcc,0x66,0x44, 0xff,0xcc,0xaa,
2930 0x99,0x99,0x99, 0x00,0xcc,0x77, 0xcc,0xcc,0xcc, 0x77,0x77,0x77,
2931 0x00,0x00,0x00, 0x88,0xbb,0xee, 0xdd,0x00,0x00, 0x00,0x00,0xaa,
2932 0x55,0x55,0x55, 0x00,0xff,0xff, 0xff,0xdd,0x00, 0xff,0xff,0xff
2935 de_make_grayscale_palette(d->pal2, 2, 0x1);
2936 de_copy_palette_from_rgb24(pal16_std, d->pal16, 16);
2939 static void do_fmtownsicn_ICNFILE(deark *c, struct fmtownsicn_ctx *d)
2941 i64 i;
2942 i64 pos1 = 0;
2943 i64 pos = pos1;
2945 de_dbg(c, "header at %"I64_FMT, pos1);
2946 de_dbg_indent(c, 1);
2947 pos += 10;
2948 pos += 2; // version
2949 d->num_tables = de_getu16le_p(&pos);
2950 de_dbg(c, "num tables: %u", (UI)d->num_tables);
2951 de_dbg_indent(c, -1);
2953 for(i=0; i<d->num_tables; i++) {
2954 if(d->fatalerrflag) goto done;
2955 do_fmtownsicn_table(c, d, i, 32+32*i);
2958 done:
2962 static void do_fmtownsicn_FJ(deark *c, struct fmtownsicn_ctx *d)
2964 i64 num_icons;
2965 i64 num_icons_capacity;
2966 i64 w, h;
2967 i64 rowspan;
2968 i64 icon_size;
2969 UI bits_per_pixel;
2970 i64 i;
2971 i64 pos1 = 0;
2972 i64 pos = pos1;
2974 de_dbg(c, "header at %"I64_FMT, pos1);
2975 de_dbg_indent(c, 1);
2976 pos += 8;
2978 bits_per_pixel = (UI)dbuf_getu16x(c->infile, pos, d->is_le);
2979 pos += 2;
2980 de_dbg(c, "bits per pixel: %u", bits_per_pixel);
2982 w = dbuf_getu16x(c->infile, pos, d->is_le);
2983 pos += 2;
2984 h = dbuf_getu16x(c->infile, pos, d->is_le);
2985 pos += 2;
2986 de_dbg_dimensions(c, w, h);
2988 num_icons = dbuf_getu16x(c->infile, pos, d->is_le);
2989 //pos += 2;
2990 de_dbg(c, "num icons: %"I64_FMT, num_icons);
2992 de_dbg_indent(c, -1);
2994 if(w!=32 || h!=32 || bits_per_pixel!=4) {
2995 d->need_errmsg = 1;
2996 goto done;
2998 rowspan = 16;
2999 icon_size = 2+rowspan*h;
3001 if(c->infile->len<16 ||
3002 ((c->infile->len-16) % icon_size)!=0)
3004 d->need_errmsg = 1;
3005 goto done;
3008 num_icons_capacity = (c->infile->len-16) / icon_size;
3009 if(num_icons_capacity < num_icons) {
3010 de_warn(c, "Expected %"I64_FMT" icons, only found %"I64_FMT,
3011 num_icons, num_icons_capacity);
3012 num_icons = num_icons_capacity;
3015 for(i=0; i<num_icons; i++) {
3016 de_bitmap *img;
3017 UI id;
3019 pos = 16+i*icon_size;
3020 de_dbg(c, "icon at %"I64_FMT, pos);
3021 de_dbg_indent(c, 1);
3022 id = (UI)dbuf_getu16x(c->infile, pos, d->is_le);
3023 de_dbg(c, "id: 0x%04x", id);
3025 img = de_bitmap_create(c, w, h, 3);
3026 de_convert_image_paletted(c->infile, pos+2, 4, rowspan,
3027 d->pal16, img, 0x01);
3028 de_bitmap_write_to_file(img, NULL, DE_CREATEFLAG_OPT_IMAGE);
3029 de_bitmap_destroy(img);
3030 de_dbg_indent(c, -1);
3032 done:
3036 static void de_run_fmtowns_icn(deark *c, de_module_params *mparams)
3038 struct fmtownsicn_ctx *d = NULL;
3039 u8 b;
3041 d = de_malloc(c, sizeof(struct fmtownsicn_ctx));
3042 fmtownsicn_make_palettes(c, d);
3044 b = de_getbyte(6);
3045 if(b=='E') {
3046 do_fmtownsicn_ICNFILE(c, d);
3048 else if(b=='2') {
3049 d->is_le = 1;
3050 do_fmtownsicn_FJ(c, d);
3052 else if(b=='J') {
3053 d->is_le = 0;
3054 do_fmtownsicn_FJ(c, d);
3056 else {
3057 d->need_errmsg = 1;
3058 goto done;
3061 done:
3062 if(d) {
3063 if(d->need_errmsg) {
3064 de_err(c, "Bad or unsupported file");
3066 de_free(c, d);
3070 static int de_identify_fmtowns_icn(deark *c)
3072 u8 buf[10];
3074 de_read(buf, 0, sizeof(buf));
3075 if(!de_memcmp(buf, (const void*)"ICNFILE\0\0\x1a", 10)) {
3076 return 100;
3078 if(!de_memcmp(buf, (const void*)"CRI-FJ2 ", 8)) {
3079 return 100;
3081 if(!de_memcmp(buf, (const void*)"CRI-FUJI", 8)) {
3082 return 100;
3084 return 0;
3087 void de_module_fmtowns_icn(deark *c, struct deark_module_info *mi)
3089 mi->id = "fmtowns_icn";
3090 mi->desc = "FM Towns icons";
3091 mi->run_fn = de_run_fmtowns_icn;
3092 mi->identify_fn = de_identify_fmtowns_icn;
3095 // **************************************************************************
3096 // PixFolio catalog (Allen C. Kempe) (Win3.x version)
3097 // **************************************************************************
3099 struct pixfolio_ctx {
3100 de_encoding input_encoding;
3101 u8 opt_undelete;
3102 u8 fatalerrflag;
3103 u8 need_errmsg;
3104 UI deleted_count;
3105 de_ucstring *tmpstr;
3108 struct pixfolio_item_ctx {
3109 i64 pos;
3110 i64 total_len;
3111 struct de_stringreaderdata *basefn_srd;
3112 u8 blank_basefn;
3113 struct de_bmpinfo bi;
3116 static void pixfolio_item_destroy(deark *c, struct pixfolio_item_ctx *md)
3118 if(!md) return;
3119 de_destroy_stringreaderdata(c, md->basefn_srd);
3120 de_free(c, md);
3123 static void read_pixfolio_timestamp(deark *c, struct pixfolio_ctx *d,
3124 struct pixfolio_item_ctx *md)
3126 de_ucstring *dtstr = NULL;
3127 de_ucstring *tmstr = NULL;
3129 dtstr = ucstring_create(c);
3130 tmstr = ucstring_create(c);
3132 dbuf_read_to_ucstring(c->infile, md->pos+343, 10, dtstr, DE_CONVFLAG_STOP_AT_NUL,
3133 DE_ENCODING_LATIN1);
3134 dbuf_read_to_ucstring(c->infile, md->pos+354, 8, tmstr, DE_CONVFLAG_STOP_AT_NUL,
3135 DE_ENCODING_LATIN1);
3136 de_dbg(c, "timestamp: \"%s %s\"", ucstring_getpsz_d(dtstr),
3137 ucstring_getpsz_d(tmstr));
3139 // We don't do anything with the timestamp, because:
3140 // * There are at least 3 different date formats ("MM/DD/YYYY", "DD/MM/YYYY",
3141 // "MM-DD-YYYY") and seemingly no way to tell which was used.
3142 // * The time of day seems to be a 12-hour clock with no AM/PM flag.
3144 ucstring_destroy(tmstr);
3145 ucstring_destroy(dtstr);
3148 static void pixfolio_check_blank_name(deark *c, struct pixfolio_ctx *d,
3149 struct pixfolio_item_ctx *md)
3151 size_t k;
3153 if(!md->basefn_srd) return;
3154 if(md->basefn_srd->sz_strlen!=12) return;
3156 for(k=0; k<12; k++) {
3157 if(md->basefn_srd->sz[k]!=0x20) return;
3159 md->blank_basefn = 1;
3162 // If successfully parsed, sets md->total_len
3163 static void do_pixfolio_item(deark *c, struct pixfolio_ctx *d,
3164 struct pixfolio_item_ctx *md)
3166 i64 pos;
3167 i64 dibpos;
3168 i64 dib_len1, dib_len2, dib_len;
3169 i64 descr_len;
3170 i64 xtra_len;
3171 i64 amt_to_copy1, amt_to_copy2;
3172 dbuf *outf = NULL;
3173 de_finfo *fi = NULL;
3174 int ret;
3175 int errflag = 0;
3176 int saved_indent_level;
3178 de_dbg_indent_save(c, &saved_indent_level);
3180 de_dbg(c, "item at %"I64_FMT, md->pos);
3181 de_dbg_indent(c, 1);
3183 fi = de_finfo_create(c);
3184 md->basefn_srd = dbuf_read_string(c->infile, md->pos, 12, 12, DE_CONVFLAG_STOP_AT_NUL,
3185 d->input_encoding);
3186 de_dbg(c, "name: \"%s\"", ucstring_getpsz_d(md->basefn_srd->str));
3187 pixfolio_check_blank_name(c, d, md);
3189 ucstring_empty(d->tmpstr);
3190 dbuf_read_to_ucstring(c->infile, md->pos+25, 64, d->tmpstr, DE_CONVFLAG_STOP_AT_NUL,
3191 d->input_encoding);
3192 de_dbg(c, "path: \"%s\"", ucstring_getpsz_d(d->tmpstr));
3194 read_pixfolio_timestamp(c, d, md);
3196 pos = md->pos + 363;
3197 // TODO: The "dib_len" fields need more research. They are usually equal.
3198 // Sometimes, one of them is 0, so we use the other one.
3199 dib_len1 = de_getu32le_p(&pos); // Is this 32 or 16 bit?
3200 de_dbg(c, "dib len1: %"I64_FMT, dib_len1);
3201 dib_len2 = de_getu16le_p(&pos);
3202 de_dbg(c, "dib len2: %"I64_FMT, dib_len2);
3203 if(dib_len1 && dib_len2 && (dib_len1 != dib_len2)) {
3204 d->fatalerrflag = 1;
3205 d->need_errmsg = 1;
3206 goto done;
3208 dib_len = dib_len2 ? dib_len2 : dib_len1;
3210 descr_len = de_getu16le_p(&pos);
3211 de_dbg(c, "descr len: %"I64_FMT, descr_len);
3212 xtra_len = de_getu16le_p(&pos); // TODO: What is this segment
3213 de_dbg(c, "xtra len: %"I64_FMT, xtra_len);
3215 md->total_len = 373 + descr_len + 1 + dib_len + xtra_len;
3216 pos += descr_len + 1;
3217 dibpos = pos;
3218 de_dbg(c, "dib pos: %"I64_FMT, dibpos);
3219 if(dibpos+dib_len > c->infile->len) {
3220 errflag = 1;
3221 goto done;
3224 if(dib_len==0) {
3225 de_dbg(c, "[no image]");
3226 goto done;
3229 if(md->blank_basefn) {
3230 de_dbg(c, "[deleted]");
3231 d->deleted_count++;
3232 if(!d->opt_undelete) goto done;
3235 // Expecting a 40-byte BITMAPINFOHEADER here. If it's not, assume
3236 // we've gone off the rails.
3237 if((UI)de_getu32le(dibpos) != 40) {
3238 d->fatalerrflag = 1;
3239 d->need_errmsg = 1;
3240 goto done;
3243 ret = fmtutil_get_bmpinfo(c, c->infile, &md->bi, dibpos,
3244 c->infile->len - dibpos, 0);
3245 if(!ret) {
3246 errflag = 1;
3247 goto done;
3250 amt_to_copy1 = dib_len;
3251 amt_to_copy2 = md->bi.size_of_headers_and_pal + md->bi.sizeImage_field;
3252 amt_to_copy1 = de_min_int(amt_to_copy1, amt_to_copy2);
3254 if(md->blank_basefn) {
3255 de_finfo_set_name_from_sz(c, fi, "deleted", 0, DE_ENCODING_LATIN1);
3257 else if(c->filenames_from_file) {
3258 de_finfo_set_name_from_ucstring(c, fi, md->basefn_srd->str, 0);
3261 outf = dbuf_create_output_file(c, "bmp", fi, 0);
3262 fmtutil_generate_bmpfileheader(c, outf, &md->bi, 14+amt_to_copy1);
3263 dbuf_copy(c->infile, dibpos, amt_to_copy1, outf);
3265 done:
3266 if(md->total_len<=0) {
3267 d->fatalerrflag = 1;
3269 if(errflag) {
3270 de_err(c, "Failed to decode item at %"I64_FMT, md->pos);
3272 dbuf_close(outf);
3273 de_finfo_destroy(c, fi);
3274 de_dbg_indent_restore(c, saved_indent_level);
3277 static void de_run_pixfolio(deark *c, de_module_params *mparams)
3279 struct pixfolio_ctx *d = NULL;
3280 struct pixfolio_item_ctx *md = NULL;
3281 i64 pos;
3283 d = de_malloc(c, sizeof(struct pixfolio_ctx));
3284 d->input_encoding = de_get_input_encoding(c, NULL, DE_ENCODING_WINDOWS1252);
3285 d->opt_undelete = (u8)de_get_ext_option_bool(c, "pixfolio:undelete", 0);
3286 d->tmpstr = ucstring_create(c);
3288 pos = 0;
3289 while(1) {
3290 if(d->fatalerrflag) goto done;
3291 if(pos+373 > c->infile->len) goto done;
3292 if(md) {
3293 pixfolio_item_destroy(c, md);
3294 md = NULL;
3296 md = de_malloc(c, sizeof(struct pixfolio_item_ctx));
3297 md->pos = pos;
3298 do_pixfolio_item(c, d, md);
3299 if(md->total_len<=0) goto done;
3300 pos += md->total_len;
3303 done:
3304 pixfolio_item_destroy(c, md);
3305 if(d) {
3306 if(d->deleted_count!=0 && !d->opt_undelete) {
3307 de_info(c, "Note: Deleted items found. Use \"-opt pixfolio:undelete\" "
3308 "to extract them.");
3310 if(d->need_errmsg) {
3311 de_err(c, "Bad or unsupported file");
3313 ucstring_destroy(d->tmpstr);
3314 de_free(c, d);
3318 static int de_identify_pixfolio(deark *c)
3320 u8 buf[20];
3321 i64 n1, n2;
3323 // This probably doesn't identify *every* PixFolio CAT file.
3324 // It assumes the first item contains an image, which is quite possibly not
3325 // always true.
3326 if(de_getbyte(0)<0x20) return 0;
3327 if(!de_input_file_has_ext(c, "cat")) return 0;
3328 de_read(buf, 343, 20);
3329 if(buf[2]!='/' && buf[2]!='-') return 0;
3330 if(buf[13]!=':') return 0;
3331 n1 = de_getu16le(369); // Descr len
3332 n2 = de_getu32le(373+n1+1); // DIB header size
3333 if(n2 != 40) return 0;
3334 n2 = de_getu16le(373+n1+1+12); // #planes
3335 if(n2 != 1) return 0;
3336 return 80;
3339 static void de_help_pixfolio(deark *c)
3341 de_msg(c, "-opt pixfolio:undelete : Also extract deleted images");
3344 void de_module_pixfolio(deark *c, struct deark_module_info *mi)
3346 mi->id = "pixfolio";
3347 mi->desc = "PixFolio catalog";
3348 mi->run_fn = de_run_pixfolio;
3349 mi->identify_fn = de_identify_pixfolio;
3350 mi->help_fn = de_help_pixfolio;
3353 // **************************************************************************
3354 // Apple II icons archive
3355 // **************************************************************************
3357 struct a2icons_ctx {
3358 de_color pal[16];
3359 de_color maskpal[16];
3361 i64 group_startpos;
3362 i64 group_len;
3363 i64 group_endpos;
3365 i64 last_icon_len;
3368 static void do_a2i_one_icon(deark *c, struct a2icons_ctx *d, i64 pos1)
3370 de_bitmap *img = NULL;
3371 de_bitmap *mask = NULL;
3372 int saved_indent_level;
3373 UI icon_type;
3374 i64 w, h;
3375 i64 rowspan;
3377 de_dbg_indent_save(c, &saved_indent_level);
3378 de_dbg(c, "icon at %"I64_FMT, pos1);
3379 de_dbg_indent(c, 1);
3380 icon_type = (UI)de_getu16le(pos1);
3381 de_dbg(c, "icon type: 0x%04x", icon_type);
3382 d->last_icon_len = de_getu16le(pos1+2);
3383 de_dbg(c, "icon size: %"I64_FMT, d->last_icon_len);
3384 h = de_getu16le(pos1+4);
3385 w = de_getu16le(pos1+6);
3386 de_dbg_dimensions(c, w, h);
3387 if(!de_good_image_dimensions(c, w, h)) goto done;
3388 rowspan = de_pad_to_n(w*4, 8)/8;
3390 img = de_bitmap_create(c, w, h, 4);
3391 de_convert_image_paletted(c->infile, pos1+8, 4, rowspan, d->pal, img, 0);
3393 mask = de_bitmap_create(c, w, h, 1);
3394 de_convert_image_paletted(c->infile, pos1+8+d->last_icon_len, 4,
3395 rowspan, d->maskpal, mask, 0);
3397 de_bitmap_apply_mask(img, mask, 0);
3398 de_bitmap_write_to_file(img, NULL, DE_CREATEFLAG_OPT_IMAGE);
3400 done:
3401 de_bitmap_destroy(img);
3402 de_bitmap_destroy(mask);
3403 de_dbg_indent_restore(c, saved_indent_level);
3406 #define A2I_GROUP_HDR_SIZE 86
3408 static void do_a2i_icon_group(deark *c, struct a2icons_ctx *d)
3410 int saved_indent_level;
3411 i64 curpos;
3413 de_dbg_indent_save(c, &saved_indent_level);
3414 de_dbg(c, "icon group at %"I64_FMT, d->group_startpos);
3415 de_dbg_indent(c, 1);
3416 de_dbg(c, "len: %"I64_FMT, d->group_len);
3418 curpos = d->group_startpos+A2I_GROUP_HDR_SIZE;
3419 while(1) {
3420 if(curpos >= d->group_endpos) goto done;
3421 d->last_icon_len = 0;
3422 do_a2i_one_icon(c, d, curpos);
3423 if(d->last_icon_len==0) goto done;
3424 curpos = curpos + 8 + d->last_icon_len*2;
3427 done:
3428 de_dbg_indent_restore(c, saved_indent_level);
3431 static void de_run_apple2icons(deark *c, de_module_params *mparams)
3433 struct a2icons_ctx *d = NULL;
3434 i64 curpos;
3435 i64 i;
3436 // Some colors here are just educated guesses.
3437 static const u8 dflt_pal[16*3] = {
3438 0,0,0, 0,0,128, 128,128,0, 128,128,128,
3439 128,0,0, 128,0,128, 255,128,0, 255,128,128,
3440 0,128,0, 0,128,128, 128,255,0, 128,255,128,
3441 192,192,192, 128,128,255, 255,255,128, 255,255,255 };
3443 d = de_malloc(c, sizeof(struct a2icons_ctx));
3444 de_copy_palette_from_rgb24(dflt_pal, d->pal, 16);
3446 d->maskpal[0] = DE_STOCKCOLOR_BLACK;
3447 for(i=1; i<16; i++) {
3448 d->maskpal[i] = DE_STOCKCOLOR_WHITE;
3451 curpos = 26;
3452 while(1) {
3453 if(curpos+A2I_GROUP_HDR_SIZE > c->infile->len) goto done;
3454 d->group_startpos = curpos;
3455 d->group_len = de_getu16le(curpos);
3456 if(d->group_len<A2I_GROUP_HDR_SIZE) goto done;
3457 d->group_endpos = d->group_startpos+d->group_len;
3458 if(d->group_endpos > c->infile->len) goto done;
3460 do_a2i_icon_group(c, d);
3461 curpos = d->group_endpos;
3464 done:
3465 de_free(c, d);
3468 void de_module_apple2icons(deark *c, struct deark_module_info *mi)
3470 mi->id = "apple2icons";
3471 mi->desc = "Apple II icons archive";
3472 mi->run_fn = de_run_apple2icons;
3473 mi->identify_fn = NULL;