New "videomaster" module
[deark.git] / modules / amigaicon.c
blob8ccc2ca7587378bb7513af37675543dcda9519ec
1 // This file is part of Deark.
2 // Copyright (C) 2016 Jason Summers
3 // See the file COPYING for terms of use.
5 // Amiga Workbench icons, including "Newicons" and "Glowicons" formats
7 #include <deark-config.h>
8 #include <deark-private.h>
9 #include <deark-fmtutil.h>
10 DE_DECLARE_MODULE(de_module_amigaicon);
12 typedef struct localctx_struct {
13 i64 icon_revision;
14 u8 icon_type;
15 int has_drawerdata;
16 int has_toolwindow;
17 int has_defaulttool;
18 int has_tooltypes;
20 i64 num_main_icons;
21 i64 main_icon_pos[2];
23 // Newicons-specific data
24 int has_newicons;
25 dbuf *newicons_data[2];
26 u8 pending_data;
27 int pending_data_bits_used;
28 int newicons_bits_per_pixel;
29 int newicons_line_count;
31 // Glowicons-specific data
32 int has_glowicons;
33 i64 glowicons_pos;
34 i64 glowicons_width, glowicons_height;
35 u32 glowicons_palette[256];
36 } lctx;
38 static const u32 rev1pal[4] = { 0x55aaff,0x000000,0xffffff,0xff8800 }; // http://krashan.ppa.pl/articles/amigaicons/
39 //static const u32 rev1pal[4] = { 0x0055aa,0x000020,0xffffff,0xff8a00 }; // Netpbm
41 static const u32 rev2pal[4] = { 0x959595,0xffffff,0x000000,0x3b67a2 }; // http://krashan.ppa.pl/articles/amigaicons/
42 //static const u32 rev2pal[4] = { 0xaaaaaa,0xffffff,0x000000,0x556699 }; // XnView
44 static const u32 magicwbpal[8] = {
45 0x959595,0x7b7b7b,0xffffff,0xaa907c,0x000000,0xafafaf,0x3b67a2,0xffa997 // http://krashan.ppa.pl/articles/amigaicons/ fixed? (& Wikipedia)
46 //0xaaaaaa,0x999999,0xffffff,0xbbaa99,0x000000,0xbbbbbb,0x556699,0xffbbaa // XnView
49 static void do_newicons_append_bit(deark *c, lctx *d, dbuf *f, u8 b)
51 if(d->pending_data_bits_used==0) {
52 d->pending_data = 0;
54 d->pending_data = (d->pending_data<<1) | (b & 0x1);
55 d->pending_data_bits_used++;
57 if(d->newicons_line_count==0) {
58 // We're still reading palette samples, which are always 8 bits.
59 if(d->pending_data_bits_used==8) {
60 dbuf_writebyte(f, d->pending_data);
61 d->pending_data_bits_used=0;
63 return;
66 if(d->pending_data_bits_used >= d->newicons_bits_per_pixel) {
67 dbuf_writebyte(f, d->pending_data);
68 d->pending_data_bits_used=0;
72 // Decode one NewIcons image. (There are usually two such images per file.)
73 // The raw data from the relevant ToolTypes table items must first be
74 // written to 'f'.
75 static void do_decode_newicons(deark *c, lctx *d,
76 dbuf *f, int newicons_num)
78 u8 trns_code, width_code, height_code;
79 u8 b0, b1, tmpb;
80 de_bitmap *img = NULL;
81 int has_trns;
82 i64 width, height;
83 i64 ncolors;
84 dbuf *decoded = NULL;
85 i64 srcpos;
86 i64 bitmap_start_pos = 0;
87 i64 i;
88 i64 rle_len;
89 int saved_indent_level;
90 u32 pal[256];
92 de_dbg_indent_save(c, &saved_indent_level);
93 de_dbg(c, "decoding NewIcons[%d], len=%"I64_FMT, newicons_num, f->len);
94 de_dbg_indent(c, 1);
96 trns_code = dbuf_getbyte(f, 0);
97 has_trns = (trns_code=='B');
98 width_code = dbuf_getbyte(f, 1);
99 height_code = dbuf_getbyte(f, 2);
101 b0 = dbuf_getbyte(f, 3);
102 b1 = dbuf_getbyte(f, 4);
103 ncolors = ((((i64)b0)-0x21)<<6) + (((i64)b1)-0x21);
104 if(ncolors<1) ncolors=1;
105 if(ncolors>256) ncolors=256;
107 width = (i64)width_code - 0x21;
108 height = (i64)height_code - 0x21;
110 de_dbg_dimensions(c, width, height);
111 if(!de_good_image_dimensions(c, width, height)) goto done;
112 de_dbg(c, "transparency: %d", has_trns);
113 de_dbg(c, "colors: %d", (int)ncolors);
115 decoded = dbuf_create_membuf(c, 2048, 0);
117 d->pending_data = 0;
118 d->pending_data_bits_used = 0;
120 d->newicons_bits_per_pixel = (int)de_log2_rounded_up(ncolors);
122 // We decode both the palette and the bitmap into the same buffer, and
123 // keep track of where in the buffer the bitmap starts.
125 // Count the number of lines (EOL represented by 0x00 byte).
126 // This is only needed because the bitmap starts on the second line.
127 d->newicons_line_count=0;
129 for(srcpos=5; srcpos<f->len; srcpos++) {
130 b0 = dbuf_getbyte(f, srcpos);
131 if((b0>=0x20 && b0<=0x6f) || (b0>=0xa1 && b0<=0xd0)) {
132 if(b0<=0x6f) b1 = b0-0x20;
133 else b1 = 0x50 + (b0-0xa1);
135 for(i=0; i<7; i++) {
136 tmpb = (b1>>(6-i))&0x01;
137 do_newicons_append_bit(c, d, decoded, tmpb);
140 else if(b0>=0xd1) {
141 // RLE compression for "0" bits
142 tmpb = 0;
143 rle_len = 7*(i64)(b0-0xd0);
144 for(i=0; i<rle_len; i++) {
145 do_newicons_append_bit(c, d, decoded, tmpb);
148 else if(b0==0x00) {
149 // End of a line.
150 // Throw away any bits we've decoded that haven't been used yet.
151 d->pending_data_bits_used = 0;
153 if(d->newicons_line_count==0) {
154 // The bitmap will start at this position. Remember that.
155 bitmap_start_pos = decoded->len;
157 d->newicons_line_count++;
161 de_dbg(c, "decompressed to %d bytes", (int)decoded->len);
163 // The first ncolors*3 bytes are the palette
164 de_dbg2(c, "NewIcons palette");
165 de_dbg_indent(c, 1);
166 for(i=0; i<ncolors; i++) {
167 if(i>255) break;
168 pal[i] = dbuf_getRGB(decoded, i*3, 0);
170 // Educated guess: If the transparency flag is set, it means
171 // palette entry 0 is transparent.
172 if(i==0 && has_trns)
173 pal[i] = DE_SET_ALPHA(pal[i], 0x00);
175 de_dbg_pal_entry(c, i, pal[i]);
177 de_dbg_indent(c, -1);
179 img = de_bitmap_create(c, width, height, 4);
180 de_convert_image_paletted(decoded, bitmap_start_pos,
181 8, width, pal, img, 0);
182 de_bitmap_write_to_file(img, c->filenames_from_file?"n":NULL,
183 d->has_glowicons?DE_CREATEFLAG_IS_AUX:0);
185 done:
186 dbuf_close(decoded);
187 de_bitmap_destroy(img);
188 de_dbg_indent_restore(c, saved_indent_level);
191 // Read enough of a main icon's header to determine how many bytes it uses.
192 static void get_main_icon_size(deark *c, lctx *d, i64 pos, i64 *pbytesused)
194 i64 width, height;
195 i64 depth;
196 i64 src_rowspan, src_planespan;
198 width = de_getu16be(pos+4);
199 height = de_getu16be(pos+6);
200 depth = de_getu16be(pos+8);
201 src_rowspan = ((width+15)/16)*2;
202 src_planespan = src_rowspan * height;
204 *pbytesused = 20 + src_planespan * depth;
207 static int do_read_main_icon(deark *c, lctx *d,
208 i64 pos, i64 icon_index)
210 i64 npwidth, height;
211 i64 pdwidth;
212 i64 depth;
213 i64 src_rowspan, src_planespan;
214 i64 i, j, plane;
215 int retval = 0;
216 de_bitmap *img = NULL;
217 u8 b, b1;
218 u32 pal[256];
220 de_dbg(c, "main icon #%d at %"I64_FMT, (int)icon_index, pos);
221 de_dbg_indent(c, 1);
223 // 20-byte header, followed by one or more bitmap "planes".
224 npwidth = de_getu16be(pos+4);
225 height = de_getu16be(pos+6);
226 depth = de_getu16be(pos+8);
227 de_dbg_dimensions(c, npwidth, height);
228 de_dbg(c, "depth: %d", (int)depth);
230 if(depth<1 || depth>8) {
231 de_err(c, "Unsupported bit depth (%d)", (int)depth);
232 goto done;
235 pdwidth = de_pad_to_n(npwidth, 16);
236 src_rowspan = pdwidth/8;
237 src_planespan = src_rowspan * height;
239 img = de_bitmap_create2(c, npwidth, pdwidth, height, 3);
241 // Figure out what palette to use
243 // Start with a meaningless grayscale palette.
244 de_make_grayscale_palette(pal, 256, 0x0);
246 if(depth==1) {
247 // The only 1-bit images I've seen are dummy images.
248 // I don't know how they're supposed to be handled, but this should do.
249 pal[0] = DE_STOCKCOLOR_BLACK;
250 pal[1] = DE_STOCKCOLOR_WHITE;
251 if(!d->has_newicons && !d->has_glowicons) {
252 de_warn(c, "Don't know how to handle 1-bit images");
255 else if(d->icon_revision==0 && depth==2) {
256 for(i=0; i<4; i++) pal[i] = rev1pal[i];
258 else if(depth==2) {
259 for(i=0; i<4; i++) pal[i] = rev2pal[i];
261 else if(depth==3) {
262 for(i=0; i<8; i++) pal[i] = magicwbpal[i];
264 else if(depth==4) {
265 // ???
266 for(i=0; i<16; i++) pal[i] = magicwbpal[i>>1];
268 else if(depth==8) {
269 // Don't ask me. Just doing what other apps seem to do.
270 for(i=0; i<256; i++) pal[i] = magicwbpal[i>>5];
272 else {
273 de_warn(c, "Don't know how to handle images with bit depth %d", (int)depth);
276 pos += 20;
278 for(j=0; j<height; j++) {
279 for(i=0; i<pdwidth; i++) {
280 b = 0x00;
281 for(plane=0; plane<depth; plane++) {
282 b1 = de_get_bits_symbol(c->infile, 1, pos+plane*src_planespan + j*src_rowspan, i);
283 b = (b<<1) | (b1 & 0x1);
285 de_bitmap_setpixel_rgb(img, i, j, pal[b]);
289 de_bitmap_write_to_file(img, NULL, (d->has_newicons||d->has_glowicons)?DE_CREATEFLAG_IS_AUX:0);
291 retval = 1;
293 done:
294 de_bitmap_destroy(img);
295 de_dbg_indent(c, -1);
296 return retval;
299 static void do_one_tooltype(deark *c, lctx *d, i64 tpos, i64 tlen)
301 int newicons_num;
302 i64 n;
303 struct de_stringreaderdata *ttstr = NULL;
305 n = de_min_int(tlen, 64);
306 ttstr = dbuf_read_string(c->infile, tpos, n, n, 0, DE_ENCODING_ASCII);
307 de_dbg(c, "data: \"%s\"", ucstring_getpsz_d(ttstr->str));
309 // The rest of this function is for identifying and recording NewIcons data.
311 if(tlen<5) {
312 // Too small to contain NewIcons data.
313 goto done;
316 newicons_num = -1;
318 if(ttstr->sz[0]=='I' && ttstr->sz[1]=='M' && ttstr->sz[3]=='=') {
319 if(ttstr->sz[2]=='1') newicons_num = 0;
320 else if(ttstr->sz[2]=='2') newicons_num = 1;
322 if(newicons_num == -1) {
323 goto done;
326 d->has_newicons = 1;
328 // Write NewIcons data to membufs, for later decoding.
330 if(!d->newicons_data[newicons_num]) {
331 de_dbg(c, "NewIcons data [%d] starts at %"I64_FMT, newicons_num, tpos);
332 d->newicons_data[newicons_num] = dbuf_create_membuf(c, 2048, 0);
333 // The data we copy includes the terminating NUL.
335 else {
336 de_dbg2(c, "NewIcons data [%d] continues at %"I64_FMT, newicons_num, tpos);
338 dbuf_copy(c->infile, tpos+4, tlen-4, d->newicons_data[newicons_num]);
340 done:
341 de_destroy_stringreaderdata(c, ttstr);
344 static int do_read_tooltypes_table(deark *c, lctx *d,
345 i64 pos1, i64 *pbytesused)
347 i64 num_entries_raw;
348 i64 num_entries;
349 int retval = 0;
350 i64 i;
351 i64 pos = pos1;
352 int saved_indent_level;
354 de_dbg_indent_save(c, &saved_indent_level);
356 de_dbg(c, "tool types table at %"I64_FMT, pos);
357 de_dbg_indent(c, 1);
359 num_entries_raw = de_getu32be_p(&pos);
360 num_entries = num_entries_raw/4 - 1;
361 de_dbg(c, "number of tool types: %d", (int)num_entries);
362 if(num_entries<0 || num_entries>1000) {
363 goto done;
366 for(i=0; i<num_entries; i++) {
367 i64 entry_pos;
368 i64 tpos;
369 i64 tlen;
371 entry_pos = pos;
372 tlen = de_getu32be_p(&pos);
373 tpos = pos;
374 de_dbg(c, "tooltype[%d] at %"I64_FMT", dpos=%"I64_FMT", dlen=%"I64_FMT,
375 (int)i, entry_pos, tpos, tlen);
376 if(tlen>10000) {
377 de_err(c, "Bad ToolTypes data");
378 goto done;
381 de_dbg_indent(c, 1);
382 do_one_tooltype(c, d, tpos, tlen);
383 de_dbg_indent(c, -1);
385 pos += tlen;
388 retval = 1;
389 done:
390 *pbytesused = pos - pos1;
391 de_dbg_indent_restore(c, saved_indent_level);
392 return retval;
395 // Uncompress a slice of f, and append to outf.
396 // The algorithm is the same as PackBits, except that the data elements may
397 // be less than 8 bits.
398 static void glowdata_uncompress(dbuf *f, i64 pos, i64 len,
399 dbuf *outf, int bits_per_pixel)
401 i64 x;
402 i64 i;
403 u8 b, b2;
404 i64 bitpos;
406 bitpos = 0;
408 // Continue as long as at least 8 bits remain.
409 while(bitpos <= (len-1)*8) {
410 b = de_get_bits_symbol2(f, 8, pos, bitpos);
411 bitpos+=8;
413 if(b<=127) {
414 // 1+b literal pixels
415 x = 1+(i64)b;
416 for(i=0; i<x; i++) {
417 b2 = de_get_bits_symbol2(f, bits_per_pixel, pos, bitpos);
418 bitpos += bits_per_pixel;
419 dbuf_writebyte(outf, b2);
422 else if(b>=129) {
423 // 257-b repeated pixels
424 x = 257 - (i64)b;
425 b2 = de_get_bits_symbol2(f, bits_per_pixel, pos, bitpos);
426 bitpos += bits_per_pixel;
427 for(i=0; i<x; i++) {
428 dbuf_writebyte(outf, b2);
434 static void do_glowicons_IMAG(deark *c, lctx *d,
435 i64 pos, i64 len)
437 de_bitmap *img = NULL;
438 u8 trns_color;
439 i64 num_colors;
440 u8 flags;
441 int has_trns;
442 int has_palette;
443 u8 cmpr_type;
444 u8 pal_cmpr_type = 0;
445 i64 bits_per_pixel;
446 i64 image_size_in_bytes;
447 i64 pal_size_in_bytes;
448 i64 image_pos;
449 i64 pal_pos;
450 i64 k;
451 dbuf *tmpbuf = NULL;
453 if(d->glowicons_width<1) {
454 // We must not have found a FACE chunk yet.
455 de_err(c, "Invalid GlowIcons data");
456 goto done;
459 trns_color = de_getbyte(pos);
460 de_dbg(c, "transparent color: 0x%02x", (int)trns_color);
461 num_colors = 1+(i64)de_getbyte(pos+1);
462 de_dbg(c, "number of colors: %d", (int)num_colors);
463 flags = de_getbyte(pos+2);
464 has_trns = (flags & 0x01)?1:0;
465 has_palette = (flags & 0x02)?1:0;
466 de_dbg(c, "has transparency: %d", has_trns);
467 de_dbg(c, "has palette: %d", has_palette);
469 cmpr_type = de_getbyte(pos+3);
470 de_dbg(c, "compression type: %d", cmpr_type);
471 if(cmpr_type!=0 && cmpr_type!=1) {
472 de_err(c, "Unsupported compression type");
473 goto done;
476 if(cmpr_type!=1) {
477 // TODO uncompressed images (Need sample files. I don't know how
478 // they are structured.)
479 de_err(c, "Uncompressed images are not supported");
480 goto done;
483 if(has_palette) {
484 pal_cmpr_type = de_getbyte(pos+4);
485 de_dbg(c, "palette compression type: %d", pal_cmpr_type);
486 if(pal_cmpr_type!=0 && pal_cmpr_type!=1) {
487 de_err(c, "Unsupported palette compression type");
488 goto done;
492 bits_per_pixel = (i64)de_getbyte(pos+5);
493 de_dbg(c, "bits per pixel: %d", (int)bits_per_pixel);
495 if(bits_per_pixel<1 || bits_per_pixel>8) {
496 de_err(c, "Invalid or unsupported bits per pixel (%d)", (int)bits_per_pixel);
497 goto done;
500 image_size_in_bytes = 1+de_getu16be(pos+6);
501 pal_size_in_bytes = 1+de_getu16be(pos+8);
502 pos+=10;
504 tmpbuf = dbuf_create_membuf(c, 10240, 0);
506 image_pos = pos;
507 pal_pos = image_pos+image_size_in_bytes;
508 de_dbg(c, "image data at %d, len=%d", (int)image_pos, (int)image_size_in_bytes);
510 if(has_palette) {
511 de_dbg(c, "palette data at %d, len=%d", (int)pal_pos, (int)pal_size_in_bytes);
512 de_dbg_indent(c, 1);
514 if(pal_cmpr_type==1) {
515 glowdata_uncompress(c->infile, pal_pos, pal_size_in_bytes, tmpbuf, 8);
517 else {
518 dbuf_copy(c->infile, pal_pos, pal_size_in_bytes, tmpbuf);
521 for(k=0; k<256; k++) {
522 if(k<num_colors) {
523 d->glowicons_palette[k] = dbuf_getRGB(tmpbuf, k*3, 0);
524 if(has_trns && k==(i64)trns_color) {
525 d->glowicons_palette[k] = DE_SET_ALPHA(d->glowicons_palette[k], 0x00);
527 de_dbg_pal_entry(c, k, d->glowicons_palette[k]);
529 else {
530 d->glowicons_palette[k] = DE_STOCKCOLOR_BLACK;
534 de_dbg_indent(c, -1);
537 // Uncompress the pixels
538 dbuf_empty(tmpbuf);
539 glowdata_uncompress(c->infile, image_pos, image_size_in_bytes, tmpbuf, (int)bits_per_pixel);
541 img = de_bitmap_create(c, d->glowicons_width, d->glowicons_height, has_trns?4:3);
543 de_convert_image_paletted(tmpbuf, 0,
544 8, d->glowicons_width, d->glowicons_palette, img, 0);
546 de_bitmap_write_to_file(img, c->filenames_from_file?"g":NULL, 0);
548 done:
549 if(tmpbuf) dbuf_close(tmpbuf);
550 if(img) de_bitmap_destroy(img);
553 // GlowIcons chunk types:
554 #define CODE_FORM 0x464f524dU
555 #define CODE_FACE 0x46414345U
556 #define CODE_IMAG 0x494d4147U
557 // FORM types:
558 #define CODE_ICON 0x49434f4eU
560 static int do_detect_glowicons(deark *c, lctx *d, i64 pos)
562 i64 gsize;
563 u32 chunk_id;
564 u32 form_type;
566 gsize = c->infile->len - pos;
567 if(gsize<=0) return 0;
569 if(gsize>=24) {
570 chunk_id = (u32)de_getu32be(pos);
571 form_type = (u32)de_getu32be(pos+8);
572 if(chunk_id==CODE_FORM && form_type==CODE_ICON) {
573 de_dbg(c, "GlowIcons data found at %d", (int)pos);
574 return 1;
578 de_warn(c, "Extra data found at end of file, but not identified as GlowIcons format.");
579 return 0;
582 static int my_iff_chunk_handler(struct de_iffctx *ictx)
584 deark *c = ictx->c;
585 lctx *d = (lctx*)ictx->userdata;
586 i64 dpos, dlen;
588 if(ictx->chunkctx->chunk4cc.id == CODE_FORM) {
589 ictx->is_std_container = 1;
590 return 1;
593 if(ictx->level!=1) {
594 return 1;
597 if(ictx->curr_container_contentstype4cc.id != CODE_ICON) {
598 return 1;
601 dpos = ictx->chunkctx->dpos;
602 dlen = ictx->chunkctx->dlen;
604 switch(ictx->chunkctx->chunk4cc.id) {
605 case CODE_FACE: // FACE (parameters)
606 ictx->handled = 1;
607 d->glowicons_width = 1+(i64)dbuf_getbyte(ictx->f, dpos);
608 d->glowicons_height = 1+(i64)dbuf_getbyte(ictx->f, dpos+1);
609 de_dbg_dimensions(c, d->glowicons_width, d->glowicons_height);
610 break;
611 case CODE_IMAG: // IMAG (one of the images that make up this icon)
612 ictx->handled = 1;
613 do_glowicons_IMAG(c, d, dpos, dlen);
614 break;
617 return 1;
620 static void do_glowicons(deark *c, lctx *d, i64 pos1)
622 struct de_iffctx *ictx = NULL;
623 int saved_indent_level;
625 ictx = fmtutil_create_iff_decoder(c);
626 de_dbg_indent_save(c, &saved_indent_level);
628 de_dbg(c, "GlowIcons data at offset %d", (int)pos1);
629 de_dbg_indent(c, 1);
631 ictx->userdata = (void*)d;
632 ictx->handle_chunk_fn = my_iff_chunk_handler;
633 ictx->f = c->infile;
634 fmtutil_read_iff_format(ictx, pos1, c->infile->len - pos1);
636 de_dbg_indent_restore(c, saved_indent_level);
637 fmtutil_destroy_iff_decoder(ictx);
640 static const char *get_icon_type_name(u8 t)
642 const char *tn = NULL;
644 switch(t) {
645 case 1: tn="disk"; break;
646 case 2: tn="drawer"; break;
647 case 3: tn="tool"; break;
648 case 4: tn="project"; break;
649 case 6: tn="device"; break;
650 case 7: tn="kick"; break;
652 return tn?tn:"?";
655 static void do_scan_file(deark *c, lctx *d)
657 i64 main_width;
658 i64 main_height;
659 i64 pos;
660 i64 i;
661 i64 x;
662 i64 bytesused;
663 i64 version;
664 int saved_indent_level;
666 de_dbg_indent_save(c, &saved_indent_level);
667 de_dbg(c, "DiskObject at %d, len=%d", 0, 78);
668 de_dbg_indent(c, 1);
670 version = de_getu16be(2);
671 de_dbg(c, "version: %d", (int)version);
673 de_dbg(c, "Gadget at %d, len=%d", 4, 44);
674 de_dbg_indent(c, 1);
676 main_width = de_getu16be(12);
677 main_height = de_getu16be(14);
678 de_dbg(c, "main canvas size: %d"DE_CHAR_TIMES"%d", (int)main_width, (int)main_height);
680 x = de_getu32be(26);
681 de_dbg(c, "SelectRender: 0x%08x", (unsigned int)x);
682 d->num_main_icons = (x==0) ? 1 : 2;
683 de_dbg_indent(c, 1);
684 de_dbg(c, "number of (original) icons: %d", (int)d->num_main_icons);
685 de_dbg_indent(c, -1);
687 d->icon_revision = de_getu32be(44) & 0xff;
688 de_dbg(c, "icon revision: %d", (int)d->icon_revision);
690 de_dbg_indent(c, -1); // end of embedded "Gadget" object
692 d->icon_type = de_getbyte(48);
693 de_dbg(c, "icon type: %d (%s)", (int)d->icon_type, get_icon_type_name(d->icon_type));
695 x = de_getu32be(50);
696 d->has_defaulttool = (x!=0);
697 de_dbg(c, "defaulttool: 0x%08x", (unsigned int)x);
699 x = de_getu32be(54);
700 d->has_tooltypes = (x!=0);
701 de_dbg(c, "tooltypes: 0x%08x", (unsigned int)x);
703 x = de_getu32be(66);
704 d->has_drawerdata = (x!=0);
705 de_dbg(c, "drawerdata: 0x%08x", (unsigned int)x);
707 x = de_getu32be(70);
708 d->has_toolwindow = (x!=0);
709 de_dbg(c, "toolwindow: 0x%08x", (unsigned int)x);
711 de_dbg_indent(c, -1);
713 pos = 78;
715 // DrawerData segment
716 if(d->has_drawerdata) {
717 const i64 ddlen = 56;
718 de_dbg(c, "DrawerData at %"I64_FMT", len=%"I64_FMT, pos, ddlen);
719 if(c->debug_level>=2) {
720 de_dbg_indent(c, 1);
721 de_dbg_hexdump(c, c->infile, pos, ddlen, 256, NULL, 0x1);
722 de_dbg_indent(c, -1);
724 pos += ddlen;
727 // Record the location of the main (original-style) icons
728 for(i=0; i<d->num_main_icons; i++) {
729 d->main_icon_pos[i] = pos;
730 get_main_icon_size(c, d, pos, &bytesused);
731 de_dbg(c, "main icon #%d data at %"I64_FMT", len=%"I64_FMT, (int)i,
732 d->main_icon_pos[i], bytesused);
733 pos += bytesused;
736 // DefaultTool segment
737 if(d->has_defaulttool) {
738 x = de_getu32be(pos);
739 de_dbg(c, "DefaultTool at %"I64_FMT", dpos=%"I64_FMT", dlen=%"I64_FMT,
740 pos, pos+4, x);
741 pos += 4;
742 if(c->debug_level>=2) {
743 de_dbg_indent(c, 1);
744 de_dbg_hexdump(c, c->infile, pos, x, 256, NULL, 0x1);
745 de_dbg_indent(c, -1);
747 pos += x;
750 if(d->has_tooltypes) {
751 // This will also read NewIcons-style icons.
752 if(!do_read_tooltypes_table(c, d, pos, &bytesused))
753 goto done;
754 pos += bytesused;
757 // Skip the ToolWindow segment (untested)
758 if(d->has_toolwindow) {
759 x = de_getu32be(pos);
760 de_dbg(c, "ToolWindow: %d bytes at %d", (int)(4+x), (int)pos);
761 pos += 4+x;
764 // DrawerData2
765 if(d->has_drawerdata && d->icon_revision==1) {
766 const i64 dd2len = 6;
767 de_dbg(c, "DrawerData2 at %"I64_FMT", len=%"I64_FMT, pos, dd2len);
768 if(c->debug_level>=2) {
769 de_dbg_indent(c, 1);
770 de_dbg_hexdump(c, c->infile, pos, dd2len, 256, NULL, 0x1);
771 de_dbg_indent(c, -1);
773 pos += dd2len;
776 if(do_detect_glowicons(c, d, pos)) {
777 d->has_glowicons = 1;
778 d->glowicons_pos = pos;
781 done:
782 de_dbg_indent_restore(c, saved_indent_level);
785 static void de_run_amigaicon(deark *c, de_module_params *mparams)
787 lctx *d;
788 i64 i;
790 d = de_malloc(c, sizeof(lctx));
792 do_scan_file(c, d);
794 if(d->has_glowicons) {
795 de_declare_fmt(c, "Amiga Workbench Icon, GlowIcons");
797 else if(d->has_newicons) {
798 de_declare_fmt(c, "Amiga Workbench Icon, NewIcons");
800 else {
801 de_declare_fmt(c, "Amiga Workbench Icon");
804 de_dbg(c, "finished scanning file, now extracting icons");
806 // Original format icons
807 for(i=0; i<d->num_main_icons; i++) {
808 do_read_main_icon(c, d, d->main_icon_pos[i], i);
811 // NewIcons
812 for(i=0; i<2; i++) {
813 if(d->newicons_data[i]) {
814 do_decode_newicons(c, d, d->newicons_data[i], (int)i);
818 // GlowIcons
819 if(d->has_glowicons) {
820 do_glowicons(c, d, d->glowicons_pos);
823 if(d->newicons_data[0]) dbuf_close(d->newicons_data[0]);
824 if(d->newicons_data[1]) dbuf_close(d->newicons_data[1]);
825 de_free(c, d);
828 static int de_identify_amigaicon(deark *c)
830 if(!dbuf_memcmp(c->infile, 0, "\xe3\x10", 2))
831 return 90;
832 return 0;
835 void de_module_amigaicon(deark *c, struct deark_module_info *mi)
837 mi->id = "amigaicon";
838 mi->desc = "Amiga Workbench icon (.info), NewIcons, GlowIcons";
839 mi->run_fn = de_run_amigaicon;
840 mi->identify_fn = de_identify_amigaicon;