static void de_run_icns_pass(deark *c, lctx *d, int pass) { de_int64 i; de_int64 segment_pos; struct page_ctx *pg = NULL; int image_count; segment_pos = 8; image_count = 0; while(1) { de_int64 segment_len; if(pg) { de_free(c, pg); pg=NULL; } if(segment_pos+8 > d->file_size) break; pg = de_malloc(c, sizeof(struct page_ctx)); pg->image_num = image_count; dbuf_read_fourcc(c->infile, segment_pos, &pg->code4cc, 0); segment_len = de_getui32be(segment_pos+4); pg->image_pos = segment_pos + 8; pg->image_len = segment_len - 8; if(pass==2) { de_dbg(c, "image #%d, type '%s', at %d, size=%d\n", pg->image_num, pg->code4cc.id_printable, (int)pg->image_pos, (int)pg->image_len); } if(segment_len<8 || segment_pos+segment_len > d->file_size) { if(pass==2) { de_err(c, "Invalid length for segment '%s' (%u)\n", pg->code4cc.id_printable, (unsigned int)segment_len); } break; } if(pass==2) { // Find this type code in the image_type_info array pg->type_info = NULL; for(i=0; image_type_info_arr[i].code!=0; i++) { if(image_type_info_arr[i].code==pg->code4cc.id) { pg->type_info = &image_type_info_arr[i]; break; } } if(!pg->type_info) { de_warn(c, "(Image #%d) Unknown image type '%s'\n", pg->image_num, pg->code4cc.id_printable); } } if(pass==1) { switch(pg->code4cc.id) { case 0x69636d23: // icm# 16x12x1 d->mkpos_16_16_1 = pg->image_pos + (16*12)/8; break; case 0x69637323: // ics# 16x16x1 d->mkpos_16_16_1 = pg->image_pos + 16*16/8; break; case 0x49434e23: // ICN# 32x32x1 d->mkpos_32_32_1 = pg->image_pos + 32*32/8; break; case 0x69636823: // ich# 48x48x1 d->mkpos_48_48_1 = pg->image_pos + 48*48/8; break; case 0x73386d6b: // s8mk 16x16x8 d->mkpos_16_16_8 = pg->image_pos; break; case 0x6c386d6b: // l8mk 32x32x8 d->mkpos_32_32_8 = pg->image_pos; break; case 0x68386d6b: // h8mk 48x48x8 d->mkpos_48_48_8 = pg->image_pos; break; case 0x74386d6b: // t8mk 128x128x8 d->mkpos_128_128_8 = pg->image_pos; break; } } else if(pass==2) { de_dbg_indent(c, 1); do_icon(c, d, pg); de_dbg_indent(c, -1); } image_count++; segment_pos += segment_len; } if(pg) de_free(c, pg); }
static int do_box(deark *c, struct de_boxesctx *bctx, i64 pos, i64 len, int level, i64 *pbytes_consumed) { i64 size32, size64; i64 header_len; // Not including UUIDs i64 payload_len; // Including UUIDs i64 total_len; struct de_fourcc box4cc; char uuid_string[50]; int ret; int retval = 0; struct de_boxdata *parentbox; struct de_boxdata *curbox; parentbox = bctx->curbox; bctx->curbox = de_malloc(c, sizeof(struct de_boxdata)); curbox = bctx->curbox; curbox->parent = parentbox; if(len<8) { de_dbg(c, "(ignoring %d extra bytes at %"I64_FMT")", (int)len, pos); goto done; } size32 = dbuf_getu32be(bctx->f, pos); dbuf_read_fourcc(bctx->f, pos+4, &box4cc, 4, 0x0); curbox->boxtype = box4cc.id; if(size32>=8) { header_len = 8; payload_len = size32-8; } else if(size32==0) { header_len = 8; payload_len = len-8; } else if(size32==1) { if(len<16) { de_dbg(c, "(ignoring %d extra bytes at %"I64_FMT")", (int)len, pos); goto done; } header_len = 16; size64 = dbuf_geti64be(bctx->f, pos+8); if(size64<16) goto done; payload_len = size64-16; } else { de_err(c, "Invalid or unsupported box format"); goto done; } total_len = header_len + payload_len; if(curbox->boxtype==DE_BOX_uuid && payload_len>=16) { curbox->is_uuid = 1; dbuf_read(bctx->f, curbox->uuid, pos+header_len, 16); } curbox->level = level; curbox->box_pos = pos; curbox->box_len = total_len; curbox->payload_pos = pos+header_len; curbox->payload_len = payload_len; if(curbox->is_uuid) { curbox->payload_pos += 16; curbox->payload_len -= 16; } if(bctx->identify_box_fn) { bctx->identify_box_fn(c, bctx); } if(c->debug_level>0) { char name_str[80]; if(curbox->box_name) { de_snprintf(name_str, sizeof(name_str), " (%s)", curbox->box_name); } else { name_str[0] = '\0'; } if(curbox->is_uuid) { de_fmtutil_render_uuid(c, curbox->uuid, uuid_string, sizeof(uuid_string)); de_dbg(c, "box '%s'{%s}%s at %"I64_FMT", len=%"I64_FMT, box4cc.id_dbgstr, uuid_string, name_str, pos, total_len); } else { de_dbg(c, "box '%s'%s at %"I64_FMT", len=%"I64_FMT", dlen=%"I64_FMT, box4cc.id_dbgstr, name_str, pos, total_len, payload_len); } } if(total_len > len) { de_err(c, "Invalid oversized box, or unexpected end of file " "(box at %"I64_FMT" ends at %"I64_FMT", " "parent ends at %"I64_FMT")", pos, pos+total_len, pos+len); goto done; } de_dbg_indent(c, 1); ret = bctx->handle_box_fn(c, bctx); de_dbg_indent(c, -1); if(!ret) goto done; if(curbox->is_superbox) { i64 children_pos, children_len; i64 max_nchildren; de_dbg_indent(c, 1); children_pos = pos+header_len + curbox->extra_bytes_before_children; children_len = payload_len - curbox->extra_bytes_before_children; max_nchildren = (curbox->num_children_is_known) ? curbox->num_children : -1; do_box_sequence(c, bctx, children_pos, children_len, max_nchildren, level+1); de_dbg_indent(c, -1); } *pbytes_consumed = total_len; retval = 1; done: de_free(c, bctx->curbox); bctx->curbox = parentbox; // Restore the curbox pointer return retval; }
static void de_run_png(deark *c, de_module_params *mparams) { lctx *d = NULL; i64 pos; i32 prev_chunk_id = 0; int suppress_idat_dbg = 0; d = de_malloc(c, sizeof(lctx)); de_dbg(c, "signature at %d", 0); de_dbg_indent(c, 1); d->fmt = do_identify_png_internal(c); switch(d->fmt) { case DE_PNGFMT_PNG: d->fmt_name = "PNG"; break; case DE_PNGFMT_JNG: d->fmt_name = "JNG"; break; case DE_PNGFMT_MNG: d->fmt_name = "MNG"; break; default: d->fmt_name = "?"; } de_dbg(c, "format: %s", d->fmt_name); if(d->fmt>0) { de_declare_fmt(c, d->fmt_name); } de_dbg_indent(c, -1); pos = 8; while(pos < c->infile->len) { struct de_fourcc chunk4cc; struct handler_params hp; u32 crc; char nbuf[80]; de_zeromem(&hp, sizeof(struct handler_params)); hp.dlen = de_getu32be(pos); if(pos + 8 + hp.dlen + 4 > c->infile->len) break; dbuf_read_fourcc(c->infile, pos+4, &chunk4cc, 4, 0x0); hp.cti = get_chunk_type_info(chunk4cc.id); if(chunk4cc.id==CODE_IDAT && suppress_idat_dbg) { ; } else if(chunk4cc.id==CODE_IDAT && prev_chunk_id==CODE_IDAT && c->debug_level<2) { de_dbg(c, "(more IDAT chunks follow)"); suppress_idat_dbg = 1; } else { if(hp.cti) { if(hp.cti->name) { de_snprintf(nbuf, sizeof(nbuf), " (%s)", hp.cti->name); } else { de_strlcpy(nbuf, "", sizeof(nbuf)); } } else { de_strlcpy(nbuf, " (?)", sizeof(nbuf)); } de_dbg(c, "chunk '%s'%s at %d dpos=%d dlen=%d", chunk4cc.id_dbgstr, nbuf, (int)pos, (int)(pos+8), (int)hp.dlen); if(chunk4cc.id!=CODE_IDAT) suppress_idat_dbg = 0; } pos += 8; de_dbg_indent(c, 1); hp.dpos = pos; hp.chunk4cc = &chunk4cc; if(hp.cti) { if(hp.cti->handler_fn) { hp.cti->handler_fn(c, d, &hp); } } else { if(c->debug_level>=2) { handler_hexdump(c, d, &hp); } } pos += hp.dlen; crc = (u32)de_getu32be(pos); de_dbg2(c, "crc32 (reported): 0x%08x", (unsigned int)crc); pos += 4; de_dbg_indent(c, -1); prev_chunk_id = chunk4cc.id; } de_free(c, d); }
// Gathers information about a DIB. // If DE_BMPINFO_HAS_FILEHEADER flag is set, pos points to the BITMAPFILEHEADER. // Otherwise, it points to the BITMAPINFOHEADER. // Caller allocates bi. // Returns 0 if BMP is invalid. int de_fmtutil_get_bmpinfo(deark *c, dbuf *f, struct de_bmpinfo *bi, i64 pos, i64 len, unsigned int flags) { i64 fhs; // file header size i64 bmih_pos; struct de_fourcc cmpr4cc; char cmprname_dbgstr[80]; de_zeromem(bi, sizeof(struct de_bmpinfo)); de_zeromem(&cmpr4cc, sizeof(struct de_fourcc)); fhs = (flags & DE_BMPINFO_HAS_FILEHEADER) ? 14 : 0; if(fhs+len < 16) return 0; if(fhs) { if(flags & DE_BMPINFO_HAS_HOTSPOT) { bi->hotspot_x = dbuf_getu16le(f, pos+6); bi->hotspot_y = dbuf_getu16le(f, pos+8); de_dbg(c, "hotspot: (%d,%d)", (int)bi->hotspot_x, (int)bi->hotspot_y); } bi->bitsoffset = dbuf_getu32le(f, pos+10); de_dbg(c, "bits offset: %d", (int)bi->bitsoffset); } bmih_pos = pos + fhs; bi->infohdrsize = dbuf_getu32le(f, bmih_pos); if(bi->infohdrsize==0x474e5089 && (flags & DE_BMPINFO_ICO_FORMAT)) { // We don't examine PNG-formatted icons, but we can identify them. bi->infohdrsize = 0; bi->file_format = DE_BMPINFO_FMT_PNG; return 1; } de_dbg(c, "info header size: %d", (int)bi->infohdrsize); if(bi->infohdrsize==12) { bi->bytes_per_pal_entry = 3; bi->width = dbuf_getu16le(f, bmih_pos+4); bi->height = dbuf_getu16le(f, bmih_pos+6); bi->bitcount = dbuf_getu16le(f, bmih_pos+10); } else if(bi->infohdrsize>=16 && bi->infohdrsize<=124) { bi->bytes_per_pal_entry = 4; bi->width = dbuf_getu32le(f, bmih_pos+4); bi->height = dbuf_geti32le(f, bmih_pos+8); if(bi->height<0) { bi->is_topdown = 1; bi->height = -bi->height; } bi->bitcount = dbuf_getu16le(f, bmih_pos+14); if(bi->infohdrsize>=20) { bi->compression_field = (u32)dbuf_getu32le(f, bmih_pos+16); if(flags & DE_BMPINFO_CMPR_IS_4CC) { dbuf_read_fourcc(f, bmih_pos+16, &cmpr4cc, 4, 0x0); } } if(bi->infohdrsize>=24) { bi->sizeImage_field = dbuf_getu32le(f, bmih_pos+20); } if(bi->infohdrsize>=36) { bi->pal_entries = dbuf_getu32le(f, bmih_pos+32); } } else { return 0; } if(flags & DE_BMPINFO_ICO_FORMAT) bi->height /= 2; if(bi->bitcount>=1 && bi->bitcount<=8) { if(bi->pal_entries==0) { bi->pal_entries = (i64)(1<<(unsigned int)bi->bitcount); } // I think the NumColors field (in icons) is supposed to be the maximum number of // colors implied by the bit depth, not the number of colors in the palette. bi->num_colors = (i64)(1<<(unsigned int)bi->bitcount); } else { // An arbitrary value. All that matters is that it's >=256. bi->num_colors = 16777216; } de_dbg_dimensions(c, bi->width, bi->height); de_dbg(c, "bit count: %d", (int)bi->bitcount); if((flags & DE_BMPINFO_CMPR_IS_4CC) && (bi->compression_field>0xffff)) { de_snprintf(cmprname_dbgstr, sizeof(cmprname_dbgstr), "'%s'", cmpr4cc.id_dbgstr); } else { de_fmtutil_get_bmp_compression_name(bi->compression_field, cmprname_dbgstr, sizeof(cmprname_dbgstr), 0); } de_dbg(c, "compression: %u (%s)", (unsigned int)bi->compression_field, cmprname_dbgstr); if(bi->sizeImage_field!=0) { de_dbg(c, "sizeImage: %u", (unsigned int)bi->sizeImage_field); } de_dbg(c, "palette entries: %u", (unsigned int)bi->pal_entries); if(bi->pal_entries>256 && bi->bitcount>8) { de_warn(c, "Ignoring bad palette size (%u entries)", (unsigned int)bi->pal_entries); bi->pal_entries = 0; } bi->pal_bytes = bi->bytes_per_pal_entry*bi->pal_entries; bi->size_of_headers_and_pal = fhs + bi->infohdrsize + bi->pal_bytes; // FIXME: cmpr type 3 doesn't always mean BITFIELDS if(bi->compression_field==3) { bi->size_of_headers_and_pal += 12; // BITFIELDS } bi->is_compressed = !((bi->compression_field==0) || (bi->compression_field==3 && bi->bitcount>1)); if(!de_good_image_dimensions(c, bi->width, bi->height)) { return 0; } // TODO: This needs work, to decide how to handle compressed images. // TODO: What about BI_BITFIELDS images? if(bi->compression_field==0) { // Try to figure out the true size of the resource, minus any padding. bi->rowspan = ((bi->bitcount*bi->width +31)/32)*4; bi->foreground_size = bi->rowspan * bi->height; de_dbg(c, "foreground size: %d", (int)bi->foreground_size); if(flags & DE_BMPINFO_ICO_FORMAT) { bi->mask_rowspan = ((bi->width +31)/32)*4; bi->mask_size = bi->mask_rowspan * bi->height; de_dbg(c, "mask size: %d", (int)bi->mask_size); } else { bi->mask_size = 0; } bi->total_size = bi->size_of_headers_and_pal + bi->foreground_size + bi->mask_size; } else { // Don't try to figure out the true size of compressed or other unusual images. bi->total_size = len; } return 1; }
// Read any version of BITMAPINFOHEADER. // // Note: Some of this BMP parsing code is duplicated in the // de_fmtutil_get_bmpinfo() library function. The BMP module's needs are // not quite aligned with what that function is intended for, and it // would be too messy to try to add the necessary features to it. static int read_infoheader(deark *c, lctx *d, de_int64 pos) { de_int64 height_raw; de_int64 clr_used_raw; int cmpr_ok; int retval = 0; de_dbg(c, "info header at %d\n", (int)pos); de_dbg_indent(c, 1); de_dbg(c, "info header size: %d\n", (int)d->infohdrsize); if(d->version==DE_BMPVER_OS2V1) { d->width = de_getui16le(pos+4); d->height = de_getui16le(pos+6); } else { d->width = dbuf_geti32le(c->infile, pos+4); height_raw = dbuf_geti32le(c->infile, pos+8); if(height_raw<0) { d->top_down = 1; d->height = -height_raw; } else { d->height = height_raw; } } de_dbg(c, "dimensions: %dx%d\n", (int)d->width, (int)d->height); if(!de_good_image_dimensions(c, d->width, d->height)) { goto done; } if(d->top_down) { de_dbg(c, "orientation: top-down\n"); } // Already read, in detect_bmp_version() de_dbg(c, "bits/pixel: %d\n", (int)d->bitcount); if(d->bitcount!=0 && d->bitcount!=1 && d->bitcount!=2 && d->bitcount!=4 && d->bitcount!=8 && d->bitcount!=16 && d->bitcount!=24 && d->bitcount!=32) { de_err(c, "Bad bits/pixel: %d\n", (int)d->bitcount); goto done; } if(d->version==DE_BMPVER_OS2V1) { d->bytes_per_pal_entry = 3; } else { // Already read, in detect_bmp_version() de_dbg(c, "compression (etc.): %d\n", (int)d->compression_field); d->bytes_per_pal_entry = 4; } d->compression_type = CMPR_NONE; // Temporary default cmpr_ok = 0; switch(d->compression_field) { case 0: // BI_RGB if(d->bitcount==16 || d->bitcount==32) { d->bitfields_type = BF_DEFAULT; } d->compression_type = CMPR_NONE; cmpr_ok = 1; break; case 1: // BI_RLE8 d->compression_type=CMPR_RLE8; cmpr_ok = 1; break; case 2: // BI_RLE4 d->compression_type=CMPR_RLE4; cmpr_ok = 1; break; case 3: // BI_BITFIELDS or Huffman_1D if(d->version==DE_BMPVER_OS2V2) { if(d->bitcount==1) { d->compression_type=CMPR_HUFFMAN1D; cmpr_ok = 1; } } else if(d->bitcount==16 || d->bitcount==32) { d->compression_type = CMPR_NONE; cmpr_ok = 1; if(d->infohdrsize>=52) { d->bitfields_type = BF_IN_HEADER; } else { d->bitfields_type = BF_SEGMENT; d->bitfields_segment_len = 12; } } break; case 4: // BI_JPEG or RLE24 if(d->version==DE_BMPVER_OS2V2) { if(d->bitcount==24) { d->compression_type=CMPR_RLE24; cmpr_ok = 1; } } else { d->compression_type=CMPR_JPEG; cmpr_ok = 1; } break; case 5: // BI_PNG d->compression_type=CMPR_PNG; cmpr_ok = 1; break; case 6: // BI_ALPHABITFIELDS if(d->bitcount==16 || d->bitcount==32) { d->compression_type = CMPR_NONE; cmpr_ok = 1; if(d->infohdrsize>=56) { d->bitfields_type = BF_IN_HEADER; } else { d->bitfields_type = BF_SEGMENT; d->bitfields_segment_len = 16; } } break; } if(!cmpr_ok) { de_err(c, "Unsupported compression type: %d\n", (int)d->compression_field); goto done; } if(d->infohdrsize>=24) { d->size_image = de_getui32le(pos+20); de_dbg(c, "biSizeImage: %d\n", (int)d->size_image); } if(d->infohdrsize>=32) { d->xpelspermeter = dbuf_geti32le(c->infile, pos+24); d->ypelspermeter = dbuf_geti32le(c->infile, pos+28); de_dbg(c, "density: %dx%d pixels/meter\n", (int)d->xpelspermeter, (int)d->ypelspermeter); } if(d->infohdrsize>=36) clr_used_raw = de_getui32le(pos+32); else clr_used_raw = 0; if(d->bitcount>=1 && d->bitcount<=8 && clr_used_raw==0) { d->pal_entries = ((de_int64)1)<<d->bitcount; } else { d->pal_entries = clr_used_raw; } de_dbg(c, "number of palette colors: %d\n", (int)d->pal_entries); // Note that after 40 bytes, WINV345 and OS2V2 header fields are different, // so we have to pay more attention to the version. if(d->bitfields_type==BF_IN_HEADER) { do_read_bitfields(c, d, pos+40, d->infohdrsize>=56 ? 16 : 12); } if(d->bitfields_type==BF_DEFAULT) { set_default_bitfields(c, d); } if(d->version==DE_BMPVER_WINV345 && d->infohdrsize>=108) { dbuf_read_fourcc(c->infile, pos+56, &d->cstype4cc, 1); de_dbg(c, "CSType: 0x%08x ('%s')\n", (unsigned int)d->cstype4cc.id, d->cstype4cc.id_printable); } if(d->version==DE_BMPVER_WINV345 && d->infohdrsize>=124 && (d->cstype4cc.id==CODE_MBED || d->cstype4cc.id==CODE_LINK)) { d->profile_offset_raw = de_getui32le(pos+112); de_dbg(c, "profile offset: %d+%d\n", FILEHEADER_SIZE, (int)d->profile_offset_raw); d->profile_size = de_getui32le(pos+116); de_dbg(c, "profile size: %d\n", (int)d->profile_size); } retval = 1; done: de_dbg_indent(c, -1); return retval; }