static void do_read_bitmap(deark *c, lctx *d, de_int64 pos) { de_int64 ver_num; dbuf *unc_pixels = NULL; ver_num = de_getui32be(pos); de_dbg(c, "version number: %u\n", (unsigned int)ver_num); if(ver_num!=0 && ver_num!=2 && ver_num!=3) { de_warn(c, "Unrecognized version number: %u\n", (unsigned int)ver_num); } pos += 512; unc_pixels = dbuf_create_membuf(c, MACPAINT_IMAGE_BYTES, 1); de_fmtutil_uncompress_packbits(c->infile, pos, c->infile->len - pos, unc_pixels, NULL); if(unc_pixels->len < MACPAINT_IMAGE_BYTES) { de_warn(c, "Image decompressed to %d bytes, expected %d.\n", (int)unc_pixels->len, (int)MACPAINT_IMAGE_BYTES); } de_convert_and_write_image_bilevel(unc_pixels, 0, MACPAINT_WIDTH, MACPAINT_HEIGHT, MACPAINT_WIDTH/8, DE_CVTF_WHITEISZERO, NULL, 0); dbuf_close(unc_pixels); }
static void de_run_macpaint(deark *c, de_module_params *mparams) { lctx *d; de_int64 pos; const char *s; d = de_malloc(c, sizeof(lctx)); d->has_macbinary_header = -1; s = de_get_ext_option(c, "macpaint:macbinary"); if(s) d->has_macbinary_header = de_atoi(s); if(d->has_macbinary_header == -1) { int v512; int v640; de_dbg(c, "trying to determine if file has a MacBinary header\n"); v512 = valid_file_at(c, d, 0); v640 = valid_file_at(c, d, 128); if(v512 > v640) { de_dbg(c, "assuming it has no MacBinary header\n"); d->has_macbinary_header = 0; } else if(v640 > v512) { de_dbg(c, "assuming it has a MacBinary header\n"); d->has_macbinary_header = 1; } else if(v512 && v640) { de_warn(c, "Can't determine if this file has a MacBinary header. " "Try \"-opt macpaint:macbinary=0\".\n"); d->has_macbinary_header = 1; } else { de_warn(c, "This is probably not a MacPaint file.\n"); d->has_macbinary_header = 1; } } if(d->has_macbinary_header) de_declare_fmt(c, "MacPaint with MacBinary header"); else de_declare_fmt(c, "MacPaint without MacBinary header"); pos = d->has_macbinary_header ? 128 : 0; do_read_bitmap(c, d, pos); do_read_patterns(c, d, pos); de_free(c, d); }
// Some OS/2v2 files exist with bad (3-bytes/color) palettes. // Try to detect them. static void do_os2v2_bad_palette(deark *c, lctx *d) { de_int64 pal_space_avail; de_int64 pal_bytes_if_3bpc; de_int64 pal_bytes_if_4bpc; int nonzero_rsvd; int i; if(d->version!=DE_BMPVER_OS2V2) return; if(d->pal_entries<1) return; pal_space_avail = d->bits_offset - d->pal_pos; pal_bytes_if_4bpc = 4*d->pal_entries; pal_bytes_if_3bpc = 3*d->pal_entries; if(pal_space_avail>=pal_bytes_if_4bpc) return; if(pal_space_avail<pal_bytes_if_3bpc || pal_space_avail>(pal_bytes_if_3bpc+1)) return; // Look for nonzero 'reserved' bytes nonzero_rsvd = 0; for(i=0; i<pal_bytes_if_3bpc; i+=4) { if(de_getbyte(d->pal_pos + i + 3) != 0) { nonzero_rsvd = 1; break; } } if(!nonzero_rsvd) return; de_warn(c, "Assuming palette has 3 bytes per entry, instead of 4\n"); d->bytes_per_pal_entry = 3; }
static void do_read_developer_area(deark *c, lctx *d, i64 pos) { i64 num_tags; i64 i; i64 tag_id, tag_data_pos, tag_data_size; de_dbg(c, "developer area at %d", (int)pos); if(pos > c->infile->len - 2) { de_warn(c, "Bad developer area offset: %u", (unsigned int)pos); return; } de_dbg_indent(c, 1); num_tags = de_getu16le(pos); de_dbg(c, "number of tags: %d", (int)num_tags); for(i=0; i<num_tags; i++) { if(i>=200) break; tag_id = de_getu16le(pos + 2 + 10*i); tag_data_pos = de_getu32le(pos + 2 + 10*i + 2); tag_data_size = de_getu32le(pos + 2 + 10*i + 6); de_dbg(c, "tag #%d: id=%d, pos=%d, size=%d", (int)i, (int)tag_id, (int)tag_data_pos, (int)tag_data_size); if(tag_id==20) { // Tag 20 seems to contain Photoshop resources, though this is unconfirmed. de_dbg_indent(c, 1); // TODO: We could retrieve the pixel density settings from the Photoshop data, // but it's not clear whether they are ever useful. de_fmtutil_handle_photoshop_rsrc(c, c->infile, tag_data_pos, tag_data_size, 0x0); de_dbg_indent(c, -1); } } de_dbg_indent(c, -1); }
static void de_run_t64(deark *c, de_module_params *mparams) { lctx *d = NULL; de_int64 pos; de_int64 i; d = de_malloc(c, sizeof(lctx)); pos = 32; d->version = de_getui16le(pos); de_dbg(c, "version: 0x%04x\n", (int)d->version); if(d->version!=0x100 && d->version!=0x101) { de_warn(c, "Unexpected version number. This might not be a T64 file.\n"); } d->max_dir_entries = de_getui16le(pos+2); d->used_dir_entries = de_getui16le(pos+4); de_dbg(c, "max dir entries = %d, files = %d\n", (int)d->max_dir_entries, (int)d->used_dir_entries); pos += 32; for(i=0; i<d->max_dir_entries; i++) { do_dir_entry(c, d, i, pos+32*i); } de_free(c, d); }
static void do_psf2_header(deark *c, lctx *d) { de_int64 pos = 0; de_dbg(c, "PFXv2 header at %d\n", (int)pos); de_dbg_indent(c, 1); d->psf2_version = (de_uint32)de_getui32le(pos+4); de_dbg(c, "PSFv2 version number: %d\n", (int)d->psf2_version); if(d->psf2_version!=0) { de_warn(c, "Unknown PSFv2 version number: %d\n", (int)d->psf2_version); } d->headersize = de_getui32le(pos+8); de_dbg(c, "header size: %d\n", (int)d->headersize); d->flags = (de_uint32)de_getui32le(pos+12); de_dbg(c, "flags: 0x%08x\n", (unsigned int)d->flags); de_dbg_indent(c, 1); d->has_unicode_table = (d->flags & 0x01) ? 1 : 0; de_dbg(c, "has Unicode table: %s\n", d->has_unicode_table?"yes":"no"); de_dbg_indent(c, -1); d->num_glyphs = de_getui32le(pos+16); de_dbg(c, "number of glyphs: %d\n", (int)d->num_glyphs); d->bytes_per_glyph = de_getui32le(pos+20); de_dbg(c, "bytes per glyph: %d\n", (int)d->bytes_per_glyph); d->glyph_height = de_getui32le(pos+24); d->glyph_width = de_getui32le(pos+28); de_dbg(c, "glyph dimensions: %dx%d\n", (int)d->glyph_width, (int)d->glyph_height); de_dbg_indent(c, -1); }
static void do_psf1_unicode_table(deark *c, lctx *d, struct de_bitmap_font *font) { de_int64 cur_idx; de_int64 pos; int got_cp; int found_fffe; de_int32 n; de_dbg(c, "Unicode table at %d\n", (int)d->unicode_table_pos); de_dbg_indent(c, 1); pos = d->unicode_table_pos; cur_idx = 0; got_cp = 0; // Have we set the codepoint for glyph[cur_idx]? found_fffe = 0; while(1) { if(cur_idx >= d->num_glyphs) break; if(pos+1 >= c->infile->len) break; n = (de_int32)de_getui16le(pos); pos+=2; if(n==0xffff) { if(!got_cp) { de_warn(c, "Missing codepoint for char #%d\n", (int)cur_idx); } cur_idx++; got_cp = 0; found_fffe = 0; continue; } else if(n==0xfffe) { found_fffe = 1; } if(found_fffe) { // Anything after 0xfffe is a multi-codepoint character, which we // don't support. continue; } if(!got_cp) { de_dbg2(c, "char[%d] = U+%04x\n", (int)cur_idx, (unsigned int)n); font->char_array[cur_idx].codepoint_unicode = n; got_cp = 1; continue; } // This is an "extra" codepoint for the current glyph. do_extra_codepoint(c, d, font, cur_idx, n); } font->has_unicode_codepoints = 1; font->prefer_unicode = 1; de_dbg_indent(c, -1); }
// 16-color 160x100 (maybe up to 160x102) mode. // This is really a text mode, and can be processed by do_char() as well. static int do_cga16(deark *c, lctx *d) { de_bitmap *img = NULL; i64 max_possible_height; i64 i, j; int retval = 0; u8 charcode, colorcode; i64 src_rowspan; u8 color0, color1; int charwarning = 0; de_declare_fmt(c, "BSAVE-PC 16-color CGA pseudo-graphics"); img = de_bitmap_create_noinit(c); img->width = get_width(c, d, 160); img->height = get_height(c, d, 100); img->bytes_per_pixel = 3; // Every pair of bytes codes for two pixels; i.e. one byte per pixel. src_rowspan = img->width; max_possible_height = (d->data_size+src_rowspan-1)/src_rowspan; if(img->height > max_possible_height) img->height = max_possible_height; if(img->height < 1) { de_err(c, "Not enough data for this format"); goto done; } for(j=0; j<img->height; j++) { for(i=0; i<img->width; i+=2) { charcode = de_getbyte(BSAVE_HDRSIZE + j*src_rowspan + i); colorcode = de_getbyte(BSAVE_HDRSIZE + j*src_rowspan + i+1); if(charwarning==0 && charcode!=0xdd && charcode!=0xde) { // TODO: We could also handle space characters and full-block characters, // at least. But maybe not worth the trouble. de_warn(c, "Unexpected code found (0x%02x). Format may not be correct.", (int)charcode); charwarning=1; } if(charcode==0xde) { color0 = colorcode>>4; color1 = colorcode&0x0f; } else { color1 = colorcode>>4; color0 = colorcode&0x0f; } de_bitmap_setpixel_rgb(img, i+0, j, de_palette_pc16(color0)); de_bitmap_setpixel_rgb(img, i+1, j, de_palette_pc16(color1)); }
static void read_palette_ximg(deark *c, lctx *d) { i64 pal_entries_in_file; i64 pal_entries_to_read; i64 i; i64 cr1, cg1, cb1; u8 cr, cg, cb; int range_warned = 0; char tmps[64]; pal_entries_in_file = (d->header_size_in_bytes-22)/3; if(pal_entries_in_file<1) return; if(d->nplanes<=8) pal_entries_to_read = (i64)(1<<((unsigned int)d->nplanes)); else pal_entries_to_read = 0; if(pal_entries_to_read>pal_entries_in_file) pal_entries_to_read = pal_entries_in_file; if(pal_entries_to_read>256) pal_entries_to_read = 256; if(pal_entries_in_file<1) return; de_dbg(c, "palette at %d", 22); de_dbg_indent(c, 1); for(i=0; i<pal_entries_to_read; i++) { cr1 = de_getu16be(22 + 6*i); cg1 = de_getu16be(22 + 6*i + 2); cb1 = de_getu16be(22 + 6*i + 4); cr = de_scale_1000_to_255(cr1); cg = de_scale_1000_to_255(cg1); cb = de_scale_1000_to_255(cb1); d->pal[i] = DE_MAKE_RGB(cr, cg, cb); de_snprintf(tmps, sizeof(tmps), "(%4d,%4d,%4d) "DE_CHAR_RIGHTARROW" ", (int)cr1, (int)cg1, (int)cb1); de_dbg_pal_entry2(c, (int)i, d->pal[i], tmps, NULL, NULL); // TODO: Maybe some out-of-range colors have special meaning? if(!range_warned && (cr1>1000 || cg1>1000 || cb1>1000)) { de_warn(c, "Bad palette color #%d: is (%d,%d,%d), max=(1000,1000,1000).", (int)i, (int)cr1, (int)cg1, (int)cb1); range_warned=1; } } de_dbg_indent(c, -1); }
static int do_picture_ole_static_rendition(deark *c, lctx *d, struct para_info *pinfo, int rendition_idx, i64 pos1, i64 *bytes_consumed) { i64 pos = pos1; i64 stringlen; struct de_stringreaderdata *srd_typename = NULL; pos += 4; // 0x00000501 pos += 4; // "type" (probably already read by caller) stringlen = de_getu32le_p(&pos); srd_typename = dbuf_read_string(c->infile, pos, stringlen, 260, DE_CONVFLAG_STOP_AT_NUL, DE_ENCODING_ASCII); de_dbg(c, "typename: \"%s\"", ucstring_getpsz(srd_typename->str)); pos += stringlen; if(!de_strcmp(srd_typename->sz, "DIB")) { pos += 12; de_dbg_indent(c, 1); de_run_module_by_id_on_slice(c, "dib", NULL, c->infile, pos, pinfo->thisparapos+pinfo->thisparalen-pos); de_dbg_indent(c, -1); } else if(!de_strcmp(srd_typename->sz, "METAFILEPICT")) { i64 dlen; pos += 8; // ?? dlen = de_getu32le_p(&pos); de_dbg(c, "metafile size: %d", (int)dlen); // Includes "mfp", apparently pos += 8; // "mfp" struct dbuf_create_file_from_slice(c->infile, pos, dlen-8, "wmf", NULL, 0); } else if(!de_strcmp(srd_typename->sz, "BITMAP")) { do_static_bitmap(c, d, pinfo, pos); } else { de_warn(c, "Static OLE picture type \"%s\" is not supported", ucstring_getpsz(srd_typename->str)); } de_destroy_stringreaderdata(c, srd_typename); return 0; }
static void do_decode_thumbnail(deark *c, lctx *d) { dbuf *unc_pixels = NULL; i64 hdrsize = 2; de_dbg(c, "thumbnail image at %d", (int)d->thumbnail_offset); de_dbg_indent(c, 1); // The thumbnail image is supposed to use the same format as the main image, // except without compression. (And the dimensions are obviously different.) // Presumably this means the origin, palette, etc. will be the same. // But based on the few TGA thumbnails we've seen, nobody reads the spec, and // it's anybody's guess what format the thumbnail will use. // TGA 2.0 spec says the dimensions are one *byte* each. d->thumbnail_image.width = (i64)de_getbyte(d->thumbnail_offset); d->thumbnail_image.height = (i64)de_getbyte(d->thumbnail_offset+1); de_dbg(c, "thumbnail dimensions: %d"DE_CHAR_TIMES"%d", (int)d->thumbnail_image.width, (int)d->thumbnail_image.height); if(d->thumbnail_image.width!=0 && d->thumbnail_image.height==0) { de_warn(c, "Thumbnail image height is 0. Assuming the file incorrectly uses " "16-bit thumbnail dimensions, instead of 8."); d->thumbnail_image.width = de_getu16le(d->thumbnail_offset); d->thumbnail_image.height = de_getu16le(d->thumbnail_offset+2); de_dbg(c, "revised thumbnail dimensions: %d"DE_CHAR_TIMES"%d", (int)d->thumbnail_image.width, (int)d->thumbnail_image.height); hdrsize = 4; } if(!de_good_image_dimensions(c, d->thumbnail_image.width, d->thumbnail_image.height)) goto done; d->thumbnail_image.img_size_in_bytes = d->thumbnail_image.height * d->thumbnail_image.width * d->bytes_per_pixel; unc_pixels = dbuf_open_input_subfile(c->infile, d->thumbnail_offset+hdrsize, d->thumbnail_image.img_size_in_bytes); do_decode_image(c, d, &d->thumbnail_image, unc_pixels, "thumb", DE_CREATEFLAG_IS_AUX); done: dbuf_close(unc_pixels); de_dbg_indent(c, -1); }
static void wri_convert_image_pal8(deark *c, i64 fpos, i64 rowspan, de_bitmap *img) { i64 i, j; int badcolorflag = 0; // Palette is from libwps (except I might have red/blue swapped it). // I haven't confirmed that it's correct. static const u32 pal_part1[8] = { 0x000000,0x800000,0x008000,0x808000,0x000080,0x800080,0x008080,0xc0c0c0 }; static const u32 pal_part2[8] = { 0x808080,0xff0000,0x00ff00,0xffff00,0x0000ff,0xff00ff,0x00ffff,0xffffff }; for(j=0; j<img->height; j++) { for(i=0; i<img->width; i++) { unsigned int palent; u32 clr; palent = de_getbyte(fpos+j*rowspan+i); if(palent<8) { clr = pal_part1[palent]; } else if(palent>=248) { clr = pal_part2[palent-248]; } else { clr = DE_MAKE_RGB(254,palent,254); // Just an arbitrary color badcolorflag = 1; } de_bitmap_setpixel_rgb(img, i, j, clr); } } if(badcolorflag) { de_warn(c, "Image uses nonportable colors"); } }
static void do_read_palette(deark *c, lctx *d) { de_int64 pal_size_in_bytes; if(d->pal_entries<1) return; pal_size_in_bytes = d->pal_entries*d->bytes_per_pal_entry; if(d->pal_pos+pal_size_in_bytes > d->bits_offset) { de_warn(c, "Palette at %d (size %d) overlaps bitmap at %d\n", (int)d->pal_pos, (int)pal_size_in_bytes, (int)d->bits_offset); if(d->version==DE_BMPVER_OS2V2) { do_os2v2_bad_palette(c, d); } } de_dbg(c, "color table at %d, %d entries\n", (int)d->pal_pos, (int)d->pal_entries); de_dbg_indent(c, 1); de_read_palette_rgb(c->infile, d->pal_pos, d->pal_entries, d->bytes_per_pal_entry, d->pal, 256, DE_GETRGBFLAG_BGR); d->pal_is_grayscale = de_is_grayscale_palette(d->pal, d->pal_entries); de_dbg_indent(c, -1); }
void de_run(deark *c) { dbuf *orig_ifile = NULL; dbuf *subfile = NULL; de_int64 subfile_size; struct deark_module_info *module_to_use = NULL; const char *friendly_infn; if(c->modhelp_req && c->input_format_req) { do_modhelp(c); goto done; } if(c->input_style==DE_INPUTSTYLE_STDIN) { friendly_infn = "[stdin]"; } else { friendly_infn = c->input_filename; } if(!friendly_infn) { de_err(c, "Input file not set\n"); de_fatalerror(c); return; } de_register_modules(c); if(c->input_format_req) { module_to_use = de_get_module_by_id(c, c->input_format_req); if(!module_to_use) { de_err(c, "Unknown module \"%s\"\n", c->input_format_req); goto done; } } if(c->slice_size_req_valid) { de_dbg(c, "Input file: %s[%d,%d]\n", friendly_infn, (int)c->slice_start_req, (int)c->slice_size_req); } else if(c->slice_start_req) { de_dbg(c, "Input file: %s[%d]\n", friendly_infn, (int)c->slice_start_req); } else { de_dbg(c, "Input file: %s\n", friendly_infn); } if(c->input_style==DE_INPUTSTYLE_STDIN) { orig_ifile = dbuf_open_input_stdin(c, c->input_filename); } else { orig_ifile = dbuf_open_input_file(c, c->input_filename); } if(!orig_ifile) { goto done; } c->infile = orig_ifile; // If we are only supposed to look at a segment of the original file, // do that by creating a child dbuf, using dbuf_open_input_subfile(). if(c->slice_start_req>0 || c->slice_size_req_valid) { if(c->slice_size_req_valid) subfile_size = c->slice_size_req; else subfile_size = dbuf_get_length(c->infile) - c->slice_start_req; subfile = dbuf_open_input_subfile(c->infile, c->slice_start_req, subfile_size); c->infile = subfile; } if(!module_to_use) { module_to_use = detect_module_for_file(c); } if(!module_to_use) { if(c->infile->len==0) de_err(c, "Unknown or unsupported file format (empty file)\n"); else de_err(c, "Unknown or unsupported file format\n"); goto done; } de_msg(c, "Module: %s\n", module_to_use->id); if(module_to_use->flags&DE_MODFLAG_NONWORKING) { de_warn(c, "The %s module is considered to be incomplete, and may " "not work properly. Caveat emptor.\n", module_to_use->id); } de_dbg2(c, "file size: %" INT64_FMT "\n", c->infile->len); if(!de_run_module(c, module_to_use, NULL)) { goto done; } // The DE_MODFLAG_NOEXTRACT flag means the module is not expected to extract // any files. if(c->num_files_extracted==0 && c->error_count==0 && !(module_to_use->flags&DE_MODFLAG_NOEXTRACT)) { de_msg(c, "No files found to extract!\n"); } done: if(subfile) dbuf_close(subfile); if(orig_ifile) dbuf_close(orig_ifile); }
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 void do_icon(deark *c, lctx *d, struct page_ctx *pg) { de_int64 expected_image_size; int is_compressed; if(!pg->type_info) return; // Shouldn't happen. de_strlcpy(pg->filename_token, "", sizeof(pg->filename_token)); if(pg->type_info->image_type==IMGTYPE_MASK) { de_dbg(c, "transparency mask\n"); return; } if(pg->type_info->image_type==IMGTYPE_EMBEDDED_FILE) { de_snprintf(pg->filename_token, sizeof(pg->filename_token), "%dx%d", (int)pg->type_info->width, (int)pg->type_info->height); do_extract_png_or_jp2(c, d, pg); return; } if(pg->type_info->image_type!=IMGTYPE_IMAGE && pg->type_info->image_type!=IMGTYPE_IMAGE_AND_MASK) { return; } // At this point we know it's a regular image (or an image+mask) // Note - This pg->rowspan is arguably incorrect for 24-bit images, since // rows aren't stored contiguously. pg->rowspan = ((pg->type_info->bpp * pg->type_info->width)+7)/8; expected_image_size = pg->rowspan * pg->type_info->height; if(pg->type_info->image_type==IMGTYPE_IMAGE_AND_MASK) { expected_image_size *= 2; } is_compressed = (pg->type_info->bpp==24) ? 1 : 0; if(!is_compressed) { if(pg->image_len < expected_image_size) { de_err(c, "(Image #%d) Premature end of image (expected %d bytes, found %d)\n", pg->image_num, (int)expected_image_size, (int)pg->image_len); return; } if(pg->image_len > expected_image_size) { de_warn(c, "(Image #%d) Extra image data found (expected %d bytes, found %d)\n", pg->image_num, (int)expected_image_size, (int)pg->image_len); } } find_mask(c, d, pg); de_snprintf(pg->filename_token, sizeof(pg->filename_token), "%dx%dx%d", (int)pg->type_info->width, (int)pg->type_info->height, (int)pg->type_info->bpp); de_dbg(c, "image dimensions: %dx%d, bpp: %d\n", pg->type_info->width, pg->type_info->height, pg->type_info->bpp); if(pg->type_info->bpp==1 || pg->type_info->bpp==4 || pg->type_info->bpp==8) { do_decode_1_4_8bit(c, d, pg); return; } else if(pg->type_info->bpp==24) { do_decode_24bit(c, d, pg); return; } de_warn(c, "(Image #%d) Image type '%s' is not supported\n", pg->image_num, pg->code4cc.id_printable); }
static int do_gzip_read_member(deark *c, lctx *d, i64 pos1, i64 *member_size) { u8 b0, b1; i64 pos; i64 n; i64 foundpos; i64 string_len; i64 cmpr_data_len; i64 mod_time_unix; u32 crc_calculated; de_ucstring *member_name = NULL; int saved_indent_level; int ret; struct member_data *md = NULL; int retval = 0; md = de_malloc(c, sizeof(struct member_data)); de_dbg_indent_save(c, &saved_indent_level); de_dbg(c, "gzip member at %d", (int)pos1); de_dbg_indent(c, 1); pos = pos1; b0 = de_getbyte(pos+0); b1 = de_getbyte(pos+1); if(b0!=0x1f || b1!=0x8b) { de_err(c, "Invalid gzip signature at %d. This is not a valid gzip file.", (int)pos1); goto done; } md->cmpr_code = de_getbyte(pos+2); if(md->cmpr_code!=0x08) { de_err(c, "Unsupported compression type (%d)", (int)md->cmpr_code); goto done; } md->flags = de_getbyte(pos+3); de_dbg(c, "flags: 0x%02x", (unsigned int)md->flags); pos += 4; mod_time_unix = de_getu32le(pos); de_unix_time_to_timestamp(mod_time_unix, &md->mod_time_ts, 0x1); if(md->mod_time_ts.is_valid) { char timestamp_buf[64]; de_timestamp_to_string(&md->mod_time_ts, timestamp_buf, sizeof(timestamp_buf), 0); de_dbg(c, "mod time: %" I64_FMT " (%s)", mod_time_unix, timestamp_buf); } pos += 4; b0 = de_getbyte(pos++); de_dbg(c, "extra flags: 0x%02x", (unsigned int)b0); b0 = de_getbyte(pos++); de_dbg(c, "OS or filesystem: %d (%s)", (int)b0, get_os_name(b0)); if(md->flags & GZIPFLAG_FEXTRA) { n = de_getu16le(pos); // XLEN // TODO: It might be interesting to dissect these extra fields, but it's // hard to find even a single file that uses them. de_dbg(c, "[extra fields at %d, dpos=%d, dlen=%d]", (int)pos, (int)(pos+2), (int)n); pos += 2; pos += n; } if(md->flags & GZIPFLAG_FNAME) { ret = dbuf_search_byte(c->infile, 0x00, pos, c->infile->len - pos, &foundpos); if(!ret) { de_err(c, "Invalid NAME field"); goto done; } string_len = foundpos - pos; member_name = ucstring_create(c); #define DE_GZIP_MAX_FNLEN 300 dbuf_read_to_ucstring_n(c->infile, pos, string_len, DE_GZIP_MAX_FNLEN, member_name, 0, DE_ENCODING_LATIN1); de_dbg(c, "file name at %d, len=%d: \"%s\"", (int)pos, (int)string_len, ucstring_getpsz_d(member_name)); pos = foundpos + 1; } if(md->flags & GZIPFLAG_FCOMMENT) { ret = dbuf_search_byte(c->infile, 0x00, pos, c->infile->len - pos, &foundpos); if(!ret) { de_err(c, "Invalid COMMENT field"); goto done; } pos = foundpos + 1; } if(md->flags & GZIPFLAG_FHCRC) { md->crc16_reported = (u32)de_getu16le(pos); de_dbg(c, "crc16 (reported): 0x%04x", (unsigned int)md->crc16_reported); pos += 2; } de_dbg(c, "compressed blocks at %d", (int)pos); if(!d->output_file) { // Although any member can have a name and mod time, this metadata // is ignored for members after the first one. de_finfo *fi = NULL; fi = de_finfo_create(c); if(member_name && c->filenames_from_file) { de_finfo_set_name_from_ucstring(c, fi, member_name, 0); fi->original_filename_flag = 1; } if(md->mod_time_ts.is_valid) { fi->mod_time = md->mod_time_ts; } d->output_file = dbuf_create_output_file(c, member_name?NULL:"bin", fi, 0); de_finfo_destroy(c, fi); } d->output_file->writecallback_fn = our_writecallback; d->output_file->userdata = (void*)md; md->crco = d->crco; de_crcobj_reset(md->crco); ret = de_decompress_deflate(c->infile, pos, c->infile->len - pos, d->output_file, 0, &cmpr_data_len, 0); crc_calculated = de_crcobj_getval(md->crco); d->output_file->writecallback_fn = NULL; d->output_file->userdata = NULL; if(!ret) goto done; pos += cmpr_data_len; de_dbg(c, "crc32 (calculated): 0x%08x", (unsigned int)crc_calculated); md->crc32_reported = (u32)de_getu32le(pos); de_dbg(c, "crc32 (reported) : 0x%08x", (unsigned int)md->crc32_reported); pos += 4; if(crc_calculated != md->crc32_reported) { de_warn(c, "CRC check failed: Expected 0x%08x, got 0x%08x", (unsigned int)md->crc32_reported, (unsigned int)crc_calculated); } md->isize = de_getu32le(pos); de_dbg(c, "uncompressed size (mod 2^32): %u", (unsigned int)md->isize); pos += 4; retval = 1; done: if(retval) *member_size = pos - pos1; else *member_size = 0; ucstring_destroy(member_name); de_free(c, md); de_dbg_indent_restore(c, saved_indent_level); return retval; }
static void do_decode_image_default(deark *c, lctx *d, struct tgaimginfo *imginfo, dbuf *unc_pixels, de_finfo *fi, unsigned int createflags) { de_bitmap *img = NULL; i64 i, j; u8 b; u32 clr; u8 a; i64 rowspan; int output_bypp; unsigned int getrgbflags; i64 interleave_stride; i64 interleave_pass; i64 cur_rownum; // 0-based, does not account for bottom-up orientation if(d->pixel_depth==1) { de_warn(c, "1-bit TGA images are not portable, and may not be decoded correctly"); rowspan = (imginfo->width+7)/8; } else { rowspan = imginfo->width*d->bytes_per_pixel; } if(d->color_type==TGA_CLRTYPE_GRAYSCALE || d->pixel_depth==1) output_bypp=1; else output_bypp=3; if(d->has_alpha_channel) output_bypp++; if(d->file_format==FMT_VST) getrgbflags = 0; else getrgbflags = DE_GETRGBFLAG_BGR; img = de_bitmap_create(c, imginfo->width, imginfo->height, output_bypp); switch(d->interleave_mode) { case 1: interleave_stride = 2; break; case 2: interleave_stride = 4; break; default: interleave_stride = 1; } cur_rownum = 0; interleave_pass = 0; for(j=0; j<imginfo->height; j++) { i64 j_adj; if(d->top_down) j_adj = cur_rownum; else j_adj = imginfo->height-1-cur_rownum; // Update the row number for next time cur_rownum += interleave_stride; if(cur_rownum >= imginfo->height) { // Went past the end of the image; move back to near the start. interleave_pass++; cur_rownum = interleave_pass; } for(i=0; i<imginfo->width; i++) { i64 i_adj; if(d->right_to_left) i_adj = imginfo->width-1-i; else i_adj = i; if(d->pixel_depth==1) { de_convert_row_bilevel(unc_pixels, j*rowspan, img, j_adj, 0); } else if(d->color_type==TGA_CLRTYPE_TRUECOLOR && (d->pixel_depth==15 || d->pixel_depth==16)) { clr = (u32)dbuf_getu16le(unc_pixels, j*rowspan + i*d->bytes_per_pixel); clr = de_rgb555_to_888(clr); de_bitmap_setpixel_rgb(img, i_adj, j_adj, clr); } else if(d->color_type==TGA_CLRTYPE_TRUECOLOR) { clr = dbuf_getRGB(unc_pixels, j*rowspan + i*d->bytes_per_pixel, getrgbflags); if(d->has_alpha_channel) { a = dbuf_getbyte(unc_pixels, j*rowspan + i*d->bytes_per_pixel+3); de_bitmap_setpixel_rgba(img, i_adj, j_adj, DE_SET_ALPHA(clr, a)); } else { de_bitmap_setpixel_rgb(img, i_adj, j_adj, clr); } } else if(d->color_type==TGA_CLRTYPE_GRAYSCALE) { b = dbuf_getbyte(unc_pixels, j*rowspan + i*d->bytes_per_pixel); de_bitmap_setpixel_gray(img, i_adj, j_adj, b); } else if(d->color_type==TGA_CLRTYPE_PALETTE) { b = dbuf_getbyte(unc_pixels, j*rowspan + i*d->bytes_per_pixel); de_bitmap_setpixel_rgb(img, i_adj, j_adj, d->pal[(unsigned int)b]); } } } de_bitmap_write_to_file_finfo(img, fi, createflags); de_bitmap_destroy(img); }
// pos1 points to the ole_id field (should be 0x00000501). // Caller must have looked ahead to check the type. static int do_picture_ole_embedded_rendition(deark *c, lctx *d, struct para_info *pinfo, int rendition_idx, i64 pos1, i64 *bytes_consumed) { i64 pos = pos1; i64 stringlen; i64 data_len; u8 buf[16]; struct de_stringreaderdata *srd_typename = NULL; struct de_stringreaderdata *srd_filename = NULL; struct de_stringreaderdata *srd_params = NULL; pos += 4; // 0x00000501 pos += 4; // "type" (probably already read by caller) stringlen = de_getu32le_p(&pos); srd_typename = dbuf_read_string(c->infile, pos, stringlen, 260, DE_CONVFLAG_STOP_AT_NUL, DE_ENCODING_ASCII); de_dbg(c, "typename: \"%s\"", ucstring_getpsz(srd_typename->str)); pos += stringlen; stringlen = de_getu32le_p(&pos); srd_filename = dbuf_read_string(c->infile, pos, stringlen, 260, DE_CONVFLAG_STOP_AT_NUL, DE_ENCODING_ASCII); de_dbg(c, "filename: \"%s\"", ucstring_getpsz(srd_filename->str)); pos += stringlen; stringlen = de_getu32le_p(&pos); srd_params = dbuf_read_string(c->infile, pos, stringlen, 260, DE_CONVFLAG_STOP_AT_NUL, DE_ENCODING_ASCII); de_dbg(c, "params: \"%s\"", ucstring_getpsz(srd_params->str)); pos += stringlen; data_len = de_getu32le_p(&pos); de_dbg(c, "embedded ole rendition data: pos=%d, len=%d", (int)pos, (int)data_len); // TODO: I don't know the extent to which it's better to sniff the data, or // rely on the typename. de_read(buf, pos, sizeof(buf)); if(!de_strcmp(srd_typename->sz, "CDraw") && !de_memcmp(&buf[0], (const void*)"RIFF", 4) && !de_memcmp(&buf[8], (const void*)"CDR", 3) ) { // Looks like CorelDRAW dbuf_create_file_from_slice(c->infile, pos, data_len, "cdr", NULL, 0); } else if(buf[0]=='B' && buf[1]=='M') { // TODO: Detect true length of data dbuf_create_file_from_slice(c->infile, pos, data_len, "bmp", NULL, 0); } else { if(d->extract_ole) { extract_unknown_ole_obj(c, d, pos, data_len, srd_typename); } else { de_warn(c, "Unknown/unsupported type of OLE object (\"%s\") at %d", ucstring_getpsz(srd_typename->str), (int)pos1); } } pos += data_len; *bytes_consumed = pos - pos1; de_destroy_stringreaderdata(c, srd_typename); de_destroy_stringreaderdata(c, srd_filename); de_destroy_stringreaderdata(c, srd_params); return 1; }
static void do_read_extension_area(deark *c, lctx *d, i64 pos) { i64 ext_area_size; i64 k; int has_date; de_ucstring *s = NULL; i64 val[6]; de_dbg(c, "extension area at %d", (int)pos); if(pos > c->infile->len - 2) { de_warn(c, "Bad extension area offset: %u", (unsigned int)pos); return; } de_dbg_indent(c, 1); s = ucstring_create(c); ext_area_size = de_getu16le(pos); de_dbg(c, "extension area size: %d", (int)ext_area_size); if(ext_area_size<495) goto done; d->has_extension_area = 1; ucstring_empty(s); dbuf_read_to_ucstring(c->infile, pos+2, 41, s, DE_CONVFLAG_STOP_AT_NUL, DE_ENCODING_ASCII); ucstring_strip_trailing_spaces(s); de_dbg(c, "author: \"%s\"", ucstring_getpsz_d(s)); for(k=0; k<4; k++) { ucstring_empty(s); dbuf_read_to_ucstring(c->infile, pos+43+81*k, 81, s, DE_CONVFLAG_STOP_AT_NUL, DE_ENCODING_ASCII); ucstring_strip_trailing_spaces(s); de_dbg(c, "comment line %d: \"%s\"", (int)k, ucstring_getpsz_d(s)); } // date/time: pos=367, size=12 has_date = 0; for(k=0; k<6; k++) { val[k] = de_getu16le(pos+367+2*k); if(val[k]!=0) has_date = 1; } if(has_date) { char timestamp_buf[64]; de_make_timestamp(&d->mod_time, val[2], val[0], val[1], val[3], val[4], val[5]); d->mod_time.tzcode = DE_TZCODE_LOCAL; de_timestamp_to_string(&d->mod_time, timestamp_buf, sizeof(timestamp_buf), 0); de_dbg(c, "timestamp: %s", timestamp_buf); } // Job name: pos=379, size=41 (not implemented) // Job time: pos=420, size=6 (not implemented) ucstring_empty(s); dbuf_read_to_ucstring(c->infile, pos+426, 41, s, DE_CONVFLAG_STOP_AT_NUL, DE_ENCODING_ASCII); ucstring_strip_trailing_spaces(s); de_dbg(c, "software id: \"%s\"", ucstring_getpsz_d(s)); val[0] = de_getu16le(pos+467); val[1] = (i64)de_getbyte(pos+469); if(val[0]!=0 || val[1]!=32) { de_dbg(c, "software version: %u,%u,%u", (unsigned int)(val[0]/100), (unsigned int)(val[0]%100), (unsigned int)val[1]); } val[0] = de_getu32le(pos+470); if(val[0]!=0) { de_dbg(c, "background color: 0x%08x", (unsigned int)val[0]); } // TODO: Retain the aspect ratio. (Need sample files. Nobody seems to use this field.) d->aspect_ratio_num = de_getu16le(pos+474); d->aspect_ratio_den = de_getu16le(pos+476); if(d->aspect_ratio_den!=0) { de_dbg(c, "aspect ratio: %d/%d", (int)d->aspect_ratio_num, (int)d->aspect_ratio_den); } // Gamma: pos=478, size=4 (not implemented) // Color correction table offset: pos=482, size=4 (not implemented) d->thumbnail_offset = de_getu32le(pos+486); de_dbg(c, "thumbnail image offset: %d", (int)d->thumbnail_offset); val[0] = de_getu32le(pos+490); de_dbg(c, "scan line table offset: %"I64_FMT, val[0]); d->attributes_type = de_getbyte(pos+494); de_dbg(c, "attributes type: %d", (int)d->attributes_type); if(d->attributes_type==0 && d->num_attribute_bits!=0) { de_warn(c, "Incompatible \"number of attribute bits\" (%d) and \"attributes type\" " "(%d) fields. Transparency may not be handled correctly.", (int)d->num_attribute_bits, (int)d->attributes_type); } done: de_dbg_indent(c, -1); ucstring_destroy(s); }
static void de_run_rpm(deark *c, de_module_params *mparams) { lctx *d = NULL; i64 pos; u8 buf[8]; const char *ext; i64 section_size = 0; de_finfo *fi = NULL; char filename[128]; d = de_malloc(c, sizeof(lctx)); if(!do_lead_section(c, d)) { goto done; } pos = 96; if(!do_header_structure(c, d, 1, pos, §ion_size)) { goto done; } pos += section_size; // Header structures are 8-byte aligned. The first one always starts at // offset 96, so we don't have to worry about it. But we need to make // sure the second one is aligned. pos = ((pos + 7)/8)*8; if(!do_header_structure(c, d, 0, pos, §ion_size)) { goto done; } pos += section_size; de_dbg(c, "data pos: %d", (int)pos); if(pos > c->infile->len) goto done; // There is usually a tag that indicates the compression format, but we // primarily figure out the format by sniffing its magic number, on the // theory that that's more reliable. // TODO: I think it's also theoretically possible that it could use an archive // format other than cpio. de_read(buf, pos, 8); if(buf[0]==0x1f && buf[1]==0x8b) { ext = "cpio.gz"; } else if(buf[0]==0x42 && buf[1]==0x5a && buf[2]==0x68) { ext = "cpio.bz2"; } else if(buf[0]==0xfd && buf[1]==0x37 && buf[2]==0x7a) { ext = "cpio.xz"; } else if(d->cmpr_type==DE_RPM_CMPR_LZMA || buf[0]==0x5d) { ext = "cpio.lzma"; } else { de_warn(c, "Unidentified compression or archive format"); ext = "cpio.bin"; } if(d->name_srd && c->filenames_from_file) { const char *version2 = "x"; const char *release2 = "x"; if(d->version_srd) version2 = d->version_srd->sz; if(d->release_srd) release2 = d->release_srd->sz; fi = de_finfo_create(c); de_snprintf(filename, sizeof(filename), "%s-%s.%s", d->name_srd->sz, version2, release2); de_finfo_set_name_from_sz(c, fi, filename, 0, DE_ENCODING_ASCII); } dbuf_create_file_from_slice(c->infile, pos, c->infile->len - pos, ext, fi, 0); done: de_finfo_destroy(c, fi); if(d) { de_destroy_stringreaderdata(c, d->name_srd); de_destroy_stringreaderdata(c, d->release_srd); de_destroy_stringreaderdata(c, d->version_srd); de_free(c, d); } }
// TGA transparency is kind of a mess. Multiple ways of labeling it, some of // which are ambiguous... Files that have inconsistent labels... Files that // claim to have transparency but don't, or that claim not to but do... static void do_prescan_image(deark *c, lctx *d, dbuf *unc_pixels) { i64 num_pixels; i64 i; u8 b[4]; int has_alpha_0 = 0; int has_alpha_partial = 0; int has_alpha_255 = 0; if(d->pixel_depth!=32 || d->color_type!=TGA_CLRTYPE_TRUECOLOR) { return; } if(d->num_attribute_bits!=0 && d->num_attribute_bits!=8) { de_warn(c, "%d-bit attribute channel not supported. Transparency disabled.", (int)d->num_attribute_bits); return; } if(d->has_extension_area) { if(d->attributes_type==0) { // attributes_type==0 technically also means there is no transparency, // but this cannot be trusted. ; } if(d->attributes_type==1 || d->attributes_type==2) { // Indicates that attribute data can be ignored. return; } else if(d->attributes_type==3 && d->num_attribute_bits==8) { // Alpha channel seems to be labeled correctly. // Trust it, and don't scan the image. d->has_alpha_channel = 1; return; } else if(d->attributes_type==4) { // Sigh. The spec shows that Field 24 (Attributes Type) == 4 is for // pre-multiplied alpha. Then the discussion section says that // Field *23* ("Attributes Type") == *3* is for premultiplied alpha. // I have to guess that the "23" and "3" are clerical errors, but that // doesn't do me much good unless all TGA developers made the same guess. de_warn(c, "Pre-multiplied alpha is not supported. Disabling transparency."); return; } } de_dbg(c, "pre-scanning image"); num_pixels = d->main_image.width * d->main_image.height; for(i=0; i<num_pixels; i++) { // TODO: This may run a lot slower than it ought to. dbuf_read(unc_pixels, b, i*4, 4); // BGRA order if(b[3]==0x00) { has_alpha_0 = 1; } else if(b[3]==0xff) { has_alpha_255 = 1; } else { has_alpha_partial = 1; break; } if(has_alpha_0 && has_alpha_255) { break; } } // Note that the has_alpha_* variables may not all be accurate at this point, // because we stop scanning when we have the info we need. if(has_alpha_partial || (has_alpha_0 && has_alpha_255)) { if(d->num_attribute_bits==0) { de_warn(c, "Detected likely alpha channel. Enabling transparency, even though " "the image is labeled as non-transparent."); } d->has_alpha_channel = 1; return; } else if(has_alpha_0) { // All 0x00 if(d->num_attribute_bits!=0) { de_warn(c, "Non-visible image detected. Disabling transparency."); } else { de_dbg(c, "potential alpha channel ignored: all 0 bits"); } return; } else { // All 0xff de_dbg(c, "potential alpha channel is moot: all 1 bits"); return; } }
// 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; }
static int do_read_header(deark *c, lctx *d) { de_int64 dfType; de_int64 dfPixWidth; de_int64 dfPixHeight; de_int64 dfMaxWidth; int is_vector = 0; int retval = 0; d->fnt_version = de_getui16le(0); de_dbg(c, "dfVersion: 0x%04x\n", (int)d->fnt_version); if(d->fnt_version==0x0300) d->hdrsize = 148; else d->hdrsize = 118; dfType = de_getui16le(66); de_dbg(c, "dfType: 0x%04x\n", (int)dfType); is_vector = (dfType&0x1)?1:0; de_dbg(c, "Font type: %s\n", is_vector?"vector":"bitmap"); d->dfPoints = de_getui16le(68); de_dbg(c, "dfPoints: %d\n", (int)d->dfPoints); dfPixWidth = de_getui16le(86); de_dbg(c, "dfPixWidth: %d\n", (int)dfPixWidth); dfPixHeight = de_getui16le(88); de_dbg(c, "dfPixHeight: %d\n", (int)dfPixHeight); d->dfCharSet = de_getbyte(85); de_dbg(c, "charset: 0x%02x\n", (int)d->dfCharSet); if(d->dfCharSet==0x00) { // "ANSI" d->encoding = DE_ENCODING_WINDOWS1252; // Guess } else if(d->dfCharSet==0xff) { // "OEM" d->encoding = DE_ENCODING_CP437_G; // Guess } else { d->encoding = DE_ENCODING_UNKNOWN; } dfMaxWidth = de_getui16le(93); de_dbg(c, "dfMaxWidth: %d\n", (int)dfMaxWidth); if(dfPixWidth!=dfMaxWidth && dfPixWidth!=0) { de_warn(c, "dfMaxWidth (%d) does not equal dfPixWidth (%d)\n", (int)dfMaxWidth, (int)dfPixWidth); } d->first_char = de_getbyte(95); d->last_char = de_getbyte(96); de_dbg(c, "first char: %d, last char: %d\n", (int)d->first_char, (int)d->last_char); if(is_vector) { de_err(c, "This is a vector font. Not supported.\n"); goto done; } // Apparently, the first 117 bytes (through the dfBitsOffset field) are // common to all versions if(d->fnt_version<0x0200) { de_err(c, "This version of FNT is not supported\n"); goto done; } if(d->fnt_version >= 0x0200) { d->dfFace = de_getui32le(105); } // There is an extra character at the end of the table that is an // "absolute-space" character, and is guaranteed to be blank. d->num_chars_stored = (de_int64)d->last_char - d->first_char + 1 + 1; if(d->fnt_version==0x0300) { d->char_entry_size = 6; } else { d->char_entry_size = 4; } d->char_table_size = d->char_entry_size * d->num_chars_stored; de_dbg(c, "character index at %d, size %d, %d bytes/entry\n", (int)d->hdrsize, (int)d->char_table_size, (int)d->char_entry_size); do_prescan_chars(c, d); if(d->detected_max_width<1) goto done; d->nominal_char_width = d->detected_max_width; d->char_height = dfPixHeight; retval = 1; done: return retval; }
static void de_run_gemraster(deark *c, de_module_params *mparams) { i64 ver; i64 ext_word0 = 0; lctx *d = NULL; int need_format_warning = 0; int saved_indent_level; de_dbg_indent_save(c, &saved_indent_level); d = de_malloc(c, sizeof(lctx)); de_dbg(c, "header (base part) at %d", 0); de_dbg_indent(c, 1); ver = de_getu16be(0); de_dbg(c, "version: %d", (int)ver); d->header_size_in_words = de_getu16be(2); d->header_size_in_bytes = d->header_size_in_words*2; de_dbg(c, "header size: %d words (%d bytes)", (int)d->header_size_in_words, (int)d->header_size_in_bytes); d->nplanes = de_getu16be(4); de_dbg(c, "planes: %d", (int)d->nplanes); if(d->header_size_in_words>=11) { d->is_ximg = !dbuf_memcmp(c->infile, 16, "XIMG", 4); } d->patlen = de_getu16be(6); de_dbg(c, "pattern def len: %d", (int)d->patlen); d->pixwidth = de_getu16be(8); d->pixheight = de_getu16be(10); de_dbg(c, "pixel size: %d"DE_CHAR_TIMES"%d microns", (int)d->pixwidth, (int)d->pixheight); d->w = de_getu16be(12); d->h = de_getu16be(14); de_dbg_dimensions(c, d->w, d->h); de_dbg_indent(c, -1); if(d->header_size_in_words>=9) { // This may help to detect the image format. ext_word0 = de_getu16be(16); } if(ver>2) { de_err(c, "This version of GEM Raster (%d) is not supported.", (int)ver); goto done; } if(d->is_ximg) { de_declare_fmt(c, "GEM VDI Bit Image, XIMG extension"); } else if(d->header_size_in_words==25 && d->patlen==2 && ext_word0==0x0080) { de_declare_fmt(c, "GEM VDI Bit Image, Hyperpaint extension"); } else if(d->header_size_in_words==8 && d->nplanes==1) { ; } else if(d->header_size_in_words==8 && (d->nplanes>=2 && d->nplanes<=8)) { need_format_warning = 1; } else if(d->header_size_in_words==9 && (d->nplanes>=1 && d->nplanes<=8)) { need_format_warning = 1; } else { if(d->header_size_in_words==27 && ext_word0==0x5354) { de_declare_fmt(c, "GEM VDI Bit Image, STTT extension"); } de_err(c, "This version of GEM Raster is not supported."); goto done; } if(need_format_warning) { de_warn(c, "This type of GEM Raster image is not very portable, and might " "not be handled correctly."); } if(!de_good_image_dimensions(c, d->w, d->h)) goto done; d->rowspan_per_plane = (d->w+7)/8; d->rowspan_total = d->rowspan_per_plane * d->nplanes; // If we haven't declared the format yet, do so. de_declare_fmt(c, "GEM VDI Bit Image"); if(d->is_ximg) { do_gem_ximg(c, d); } else if(d->header_size_in_words==25) { do_gem_ximg(c, d); } else { do_gem_img(c, d); } done: de_dbg_indent_restore(c, saved_indent_level); de_free(c, d); }
static int do_dataset(deark *c, lctx *d, de_int64 ds_idx, de_int64 pos1, de_int64 *bytes_consumed) { de_byte b; de_byte recnum, dsnum; int retval = 0; de_int64 pos = pos1; de_int64 dflen; de_int64 dflen_bytes_consumed; struct ds_info dsi; int ds_known; *bytes_consumed = 0; b = de_getbyte(pos); if(b!=0x1c) { if(b==0x00 && ds_idx>0) { // Extraneous padding at the end of data? de_warn(c, "Expected %d bytes of IPTC data, only found %d\n", (int)c->infile->len, (int)pos); } else { de_err(c, "Bad IPTC tag marker (0x%02x) at %d\n", (int)b, (int)pos); } goto done; } pos++; recnum = de_getbyte(pos++); dsnum = de_getbyte(pos++); ds_known = lookup_ds_info(recnum, dsnum, &dsi); if(!read_dflen(c, c->infile, pos, &dflen, &dflen_bytes_consumed)) goto done; pos += dflen_bytes_consumed; de_dbg(c, "IPTC dataset %d:%02d (%s) dpos=%" INT64_FMT " dlen=%" INT64_FMT "\n", (int)recnum, (int)dsnum, dsi.dsname, pos, dflen); // Decode the value de_dbg_indent(c, 1); if(dsi.hfn) { dsi.hfn(c, d, &dsi, pos, dflen); } else if(dsi.flags&0x1) { handle_text(c, d, &dsi, pos, dflen); } else if(dsi.recnum==2 && !ds_known) { // Unknown record-2 datasets often contain readable text. handle_text(c, d, &dsi, pos, dflen); } pos += dflen; de_dbg_indent(c, -1); // *bytes_consumed = pos - pos1; retval = 1; done: return retval; }
static void do_psf2_unicode_table(deark *c, lctx *d, struct de_bitmap_font *font) { de_int64 cur_idx; de_int64 pos; int ret; de_int64 foundpos; de_int64 char_data_len; de_byte char_data_buf[200]; de_int32 ch; de_int64 utf8len; de_dbg(c, "Unicode table at %d\n", (int)d->unicode_table_pos); de_dbg_indent(c, 1); pos = d->unicode_table_pos; cur_idx = 0; while(1) { de_int64 pos_in_char_data; de_int64 cp_idx; if(cur_idx >= d->num_glyphs) break; if(pos >= c->infile->len) break; // Figure out the size of the data for this glyph ret = dbuf_search_byte(c->infile, 0xff, pos, c->infile->len - pos, &foundpos); if(!ret) break; char_data_len = foundpos - pos; if(char_data_len<0) char_data_len=0; else if(char_data_len>(de_int64)sizeof(char_data_buf)) char_data_len=(de_int64)sizeof(char_data_buf); // Read all the data for this glyph de_read(char_data_buf, pos, char_data_len); // Read the codepoints for this glyph cp_idx = 0; pos_in_char_data = 0; while(1) { if(pos_in_char_data >= char_data_len) break; ret = de_utf8_to_uchar(&char_data_buf[pos_in_char_data], char_data_len-pos_in_char_data, &ch, &utf8len); if(!ret) { // If there are any multi-codepoint aliases for this glyph, we // expect de_utf8_to_uchar() to fail when it hits the 0xfe byte. // So, this is not necessarily an error. break; } if(cp_idx==0) { // This is the primary Unicode codepoint for this glyph de_dbg2(c, "char[%d] = U+%04x\n", (int)cur_idx, (unsigned int)ch); font->char_array[cur_idx].codepoint_unicode = ch; } else { do_extra_codepoint(c, d, font, cur_idx, ch); } cp_idx++; pos_in_char_data += utf8len; } if(cp_idx==0) { de_warn(c, "Missing codepoint for char #%d\n", (int)cur_idx); } // Advance to the next glyph pos = foundpos+1; cur_idx++; } font->has_unicode_codepoints = 1; font->prefer_unicode = 1; de_dbg_indent(c, -1); }
static void handler_text(deark *c, lctx *d, struct handler_params *hp) { i64 pos; i64 endpos; i64 field_bytes_consumed; int is_compressed = 0; int encoding; int ret; struct text_chunk_ctx tcc; de_zeromem(&tcc, sizeof(struct text_chunk_ctx)); endpos = hp->dpos+hp->dlen; pos = hp->dpos; // Keyword ret = do_text_field(c, d, &tcc, FIELD_KEYWORD, pos, endpos-pos, 1, 0, DE_ENCODING_LATIN1, &field_bytes_consumed); if(!ret) goto done; pos += field_bytes_consumed; pos += 1; // Compression flag if(hp->chunk4cc->id==CODE_iTXt) { is_compressed = (int)de_getbyte(pos++); de_dbg(c, "compression flag: %d", (int)is_compressed); } else if(hp->chunk4cc->id==CODE_zTXt) { is_compressed = 1; } // Compression method if(hp->chunk4cc->id==CODE_zTXt || hp->chunk4cc->id==CODE_iTXt) { u8 cmpr_method; cmpr_method = de_getbyte(pos++); if(is_compressed && cmpr_method!=0) { de_warn(c, "Unsupported text compression type: %d", (int)cmpr_method); goto done; } } if(hp->chunk4cc->id==CODE_iTXt) { // Language tag ret = do_text_field(c, d, &tcc, FIELD_LANG, pos, endpos-pos, 1, 0, DE_ENCODING_ASCII, &field_bytes_consumed); if(!ret) goto done; pos += field_bytes_consumed; pos += 1; // Translated keyword ret = do_text_field(c, d, &tcc, FIELD_XKEYWORD, pos, endpos-pos, 1, 0, DE_ENCODING_UTF8, &field_bytes_consumed); if(!ret) goto done; pos += field_bytes_consumed; pos += 1; } if(hp->chunk4cc->id==CODE_iTXt) encoding = DE_ENCODING_UTF8; else encoding = DE_ENCODING_LATIN1; do_text_field(c, d, &tcc, FIELD_MAIN, pos, endpos-pos, 0, is_compressed, encoding, &field_bytes_consumed); done: ; }