static int do_element_sequence(deark *c, lctx *d, i64 pos1, i64 len) { int ret; int retval = 0; i64 pos = pos1; int saved_indent_level; // TODO: // From the EBML spec: // "data that is not part of an EBML Element is permitted to be present // within a Master Element if unknownsizeallowed is enabled within the // definition for that Master Element. In this case, the EBML Reader // should skip data until a valid Element ID of the same EBMLParentPath or // the next upper level Element Path of the Master Element is found." // // We do not support this. We can't even detect it, so our parser will go // off the rails. How do you even support it efficiently? What kind of // psychopath designs a format like this? It's incredibly fragile (a new // format version that defines a new optional element will completely // break backward compatibility), and its abstractions are leaking all // over the place. d->level++; de_dbg_indent_save(c, &saved_indent_level); if(d->level > 16) goto done; if(len==0) { retval = 1; goto done; } de_dbg(c, "element sequence at %"I64_FMT", max_len=%"I64_FMT, pos1, len); de_dbg_indent(c, 1); while(1) { i64 ele_len = 0; if(pos >= pos1+len) { break; } ret = do_element(c, d, pos, pos1+len-pos, &ele_len); if(!ret) goto done; if(ele_len<1) goto done; pos += ele_len; } retval = 1; done: de_dbg_indent_restore(c, saved_indent_level); d->level--; return retval; }
static void do_theora_vorbis_after_headers(deark *c, lctx *d, struct stream_info *si) { i64 pos = 0; int saved_indent_level; dbuf *f = NULL; de_dbg_indent_save(c, &saved_indent_level); if(si->stream_state!=0) goto done; if(!si->header_stream) goto done; if(!si->sti) goto done; f = si->header_stream; de_dbg(c, "[decoding %s comment/setup headers, %d bytes]", si->sti->name, (int)si->header_stream->len); de_dbg_indent(c, 1); // Make sure the comment header signature is present. if(si->stream_type==STREAMTYPE_VORBIS) { if(dbuf_memcmp(f, 0, "\x03" "vorbis", 7)) { goto done; } pos += 7; } else if(si->stream_type==STREAMTYPE_THEORA) { if(dbuf_memcmp(f, 0, "\x81" "theora", 7)) { goto done; } pos += 7; } do_vorbis_comment_block(c, d, f, pos); // TODO: "Setup" header done: si->stream_state = 1; dbuf_close(si->header_stream); si->header_stream = NULL; de_dbg_indent_restore(c, saved_indent_level); }
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 de_run_tga(deark *c, de_module_params *mparams) { lctx *d = NULL; i64 pos; dbuf *unc_pixels = NULL; int saved_indent_level; i64 rowspan_tmp; de_dbg_indent_save(c, &saved_indent_level); d = de_malloc(c, sizeof(lctx)); detect_file_format(c, d); if(d->file_format==FMT_VST) { de_declare_fmt(c, "TrueVista"); } else { de_declare_fmt(c, "TGA"); } pos = 0; if(d->file_format==FMT_VST) { if(!do_read_vst_headers(c, d)) goto done; } else { if(!do_read_tga_headers(c, d)) goto done; } pos += 18; if(d->id_field_len>0) { de_dbg(c, "image ID at %d (len=%d)", (int)pos, (int)d->id_field_len); pos += d->id_field_len; } if(d->color_map_type!=0) { d->bytes_per_pal_entry = (d->cmap_depth+7)/8; d->pal_size_in_bytes = d->cmap_length * d->bytes_per_pal_entry; de_dbg(c, "color map at %d (%d colors, %d bytes)", (int)pos, (int)d->cmap_length, (int)d->pal_size_in_bytes); de_dbg_indent(c, 1); if(!do_read_palette(c, d, pos)) goto done; de_dbg_indent(c, -1); pos += d->pal_size_in_bytes; } de_dbg(c, "bitmap at %d", (int)pos); de_dbg_indent(c, 1); d->bytes_per_pixel = ((d->pixel_depth+7)/8); if(d->pixel_depth==1) { rowspan_tmp = (d->main_image.width+7)/8; } else { rowspan_tmp = d->main_image.width * d->bytes_per_pixel; } d->main_image.img_size_in_bytes = d->main_image.height * rowspan_tmp; if(d->color_type!=TGA_CLRTYPE_PALETTE && d->color_type!=TGA_CLRTYPE_TRUECOLOR && d->color_type!=TGA_CLRTYPE_GRAYSCALE) { de_err(c, "Unsupported color type (%d: %s)", (int)d->color_type, d->clrtype_name); goto done; } if( (d->color_type==TGA_CLRTYPE_PALETTE && d->pixel_depth==8) || (d->color_type==TGA_CLRTYPE_TRUECOLOR && d->pixel_depth==15) || (d->color_type==TGA_CLRTYPE_TRUECOLOR && d->pixel_depth==16) || (d->color_type==TGA_CLRTYPE_TRUECOLOR && d->pixel_depth==24) || (d->color_type==TGA_CLRTYPE_TRUECOLOR && d->pixel_depth==32) || (d->color_type==TGA_CLRTYPE_GRAYSCALE && d->pixel_depth==1) || (d->color_type==TGA_CLRTYPE_GRAYSCALE && d->pixel_depth==8) ) { ; } else { de_err(c, "Unsupported TGA image type (%s, depth=%d)", d->clrtype_name, (int)d->pixel_depth); goto done; } if(d->cmpr_type==TGA_CMPR_RLE) { if(d->pixel_depth<8) { de_err(c, "RLE compression not supported when depth (%d) is less than 8", (int)d->pixel_depth); goto done; } unc_pixels = dbuf_create_membuf(c, d->main_image.img_size_in_bytes, 1); if(!do_decode_rle(c, d, pos, unc_pixels)) goto done; } else if(d->cmpr_type==TGA_CMPR_NONE) { unc_pixels = dbuf_open_input_subfile(c->infile, pos, d->main_image.img_size_in_bytes); } else { de_err(c, "Unsupported compression type (%d, %s)", (int)d->cmpr_type, d->cmpr_name); goto done; } // Maybe scan the image, to help detect transparency. do_prescan_image(c, d, unc_pixels); if(d->pixel_depth==32) { de_dbg(c, "using alpha channel: %s", d->has_alpha_channel?"yes":"no"); } // TODO: 16-bit images could theoretically have a transparency bit, but I don't // know how to detect that. do_decode_image(c, d, &d->main_image, unc_pixels, NULL, 0); de_dbg_indent(c, -1); if(d->thumbnail_offset!=0) { do_decode_thumbnail(c, d); } done: dbuf_close(unc_pixels); de_dbg_indent_restore(c, saved_indent_level); de_free(c, d); }
static int do_gzip_read_member(deark *c, lctx *d, de_int64 pos1, de_int64 *member_size) { de_byte b0, b1; de_int64 cmpr_code; de_int64 pos; de_int64 n; de_int64 foundpos; de_int64 string_len; de_int64 cmpr_data_len; de_int64 isize; de_int64 mod_time_unix; struct de_timestamp mod_time_ts; de_uint32 crc32_field; de_ucstring *member_name = NULL; de_finfo *fi = NULL; int saved_indent_level; int ret; int retval = 0; mod_time_ts.is_valid = 0; de_dbg_indent_save(c, &saved_indent_level); de_dbg(c, "gzip member at %d\n", (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.\n", (int)pos1); goto done; } cmpr_code=de_getbyte(pos+2); if(cmpr_code!=0x08) { de_err(c, "Unsupported compression type (%d)\n", (int)cmpr_code); goto done; } d->flags = de_getbyte(pos+3); de_dbg(c, "flags: 0x%02x\n", (unsigned int)d->flags); pos += 4; mod_time_unix = de_getui32le(pos); de_unix_time_to_timestamp(mod_time_unix, &mod_time_ts); if(mod_time_ts.is_valid) { char timestamp_buf[64]; de_timestamp_to_string(&mod_time_ts, timestamp_buf, sizeof(timestamp_buf), 1); de_dbg(c, "mod time: %" INT64_FMT " (%s)\n", mod_time_unix, timestamp_buf); } pos += 4; b0 = de_getbyte(pos++); de_dbg(c, "extra flags: 0x%02x\n", (unsigned int)b0); b0 = de_getbyte(pos++); de_dbg(c, "OS or filesystem: %d (%s)\n", (int)b0, get_os_name(b0)); if(d->flags & GZIPFLAG_FEXTRA) { n = de_getui16le(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]\n", (int)pos, (int)(pos+2), (int)n); pos += 2; pos += n; } if(d->flags & GZIPFLAG_FNAME) { ret = dbuf_search_byte(c->infile, 0x00, pos, c->infile->len - pos, &foundpos); if(!ret) { de_err(c, "Invalid NAME field\n"); goto done; } string_len = foundpos - pos; member_name = ucstring_create(c); dbuf_read_to_ucstring_n(c->infile, pos, string_len, 300, member_name, 0, DE_ENCODING_LATIN1); de_dbg(c, "file name at %d, len=%d: \"%s\"\n", (int)pos, (int)string_len, ucstring_get_printable_sz(member_name)); pos = foundpos + 1; } if(d->flags & GZIPFLAG_FCOMMENT) { ret = dbuf_search_byte(c->infile, 0x00, pos, c->infile->len - pos, &foundpos); if(!ret) { de_err(c, "Invalid COMMENT field\n"); goto done; } pos = foundpos + 1; } if(d->flags & GZIPFLAG_FHCRC) { pos += 2; } de_dbg(c, "compressed blocks at %d\n", (int)pos); if(!d->output_file) { fi = de_finfo_create(c); if(member_name && c->filenames_from_file) { de_finfo_set_name_from_ucstring(c, fi, member_name); fi->original_filename_flag = 1; } if(mod_time_ts.is_valid) { fi->mod_time = mod_time_ts; } d->output_file = dbuf_create_output_file(c, member_name?NULL:"bin", fi, 0); } ret = de_uncompress_deflate(c->infile, pos, c->infile->len - pos, d->output_file, &cmpr_data_len); if(!ret) goto done; pos += cmpr_data_len; crc32_field = (de_uint32)de_getui32le(pos); de_dbg(c, "crc32: 0x%08x\n", (unsigned int)crc32_field); pos += 4; // TODO: Validate CRCs isize = de_getui32le(pos); de_dbg(c, "uncompressed size (mod 2^32): %u\n", (unsigned int)isize); pos += 4; retval = 1; done: if(retval) *member_size = pos - pos1; else *member_size = 0; ucstring_destroy(member_name); de_finfo_destroy(c, fi); de_dbg_indent_restore(c, saved_indent_level); return retval; }
static void de_run_alphabmp(deark *c, de_module_params *mparams) { unsigned int flags; lctx *d = NULL; i64 pos; i64 palsize; dbuf *unc_pixels = NULL; int saved_indent_level; de_dbg_indent_save(c, &saved_indent_level); d = de_malloc(c, sizeof(lctx)); de_declare_fmt(c, "Alpha Microsystems BMP"); pos = 10; de_dbg(c, "bitmap image definition block at %d", (int)pos); de_dbg_indent(c, 1); d->w = de_getu16le(pos); d->h = de_getu16le(pos+2); de_dbg_dimensions(c, d->w, d->h); if(!de_good_image_dimensions(c, d->w, d->h)) goto done; d->bpp = de_getu16le(pos+4); de_dbg(c, "bits/pixel: %d", (int)d->bpp); flags = (unsigned int)de_getu16le(pos+6); d->has_palette = flags & 0x01; d->palette_is_hls = (flags>>1) & 0x01; de_dbg(c, "has-palette: %d", (int)d->has_palette); if(d->has_palette) de_dbg(c, "palette-is-HLS: %d", (int)d->palette_is_hls); d->compression = de_getu16le(pos+8); de_dbg(c, "compression: %d", (int)d->compression); de_dbg_indent(c, -1); pos += 70; if(d->has_palette) { if(d->palette_is_hls && d->bpp<=8) { de_err(c, "HLS palettes are not supported"); goto done; } if(!do_read_palette(c, d, pos, &palsize)) goto done; pos += palsize; } else if(d->bpp<=8) { de_err(c, "Paletted images without an embedded palette are not supported"); goto done; } de_dbg(c, "bitmap at %d", (int)pos); de_dbg_indent(c, 1); if(d->compression) { unc_pixels = dbuf_create_membuf(c, 32768, 0); if(!do_uncompress_image(c, d, pos, unc_pixels)) goto done; } else { unc_pixels = dbuf_open_input_subfile(c->infile, pos, c->infile->len - pos); } if(d->bpp!=1 && d->bpp!=4 && d->bpp!=8 && d->bpp!=24) { de_err(c, "%d bits/pixel is not supported", (int)d->bpp); goto done; } do_bitmap(c, d, unc_pixels); de_dbg_indent(c, -1); done: de_dbg_indent_restore(c, saved_indent_level); dbuf_close(unc_pixels); de_free(c, d); }
static void do_card_index(deark *c, lctx *d, de_int64 cardnum, de_int64 pos) { de_int64 datapos; de_int64 bitmap_len; de_int64 w, h; de_int64 src_rowspan; de_int64 text_len; de_int64 text_pos; struct deark_bitmap *img = NULL; de_finfo *fi_bitmap = NULL; de_finfo *fi_text = NULL; const char *cardtype; de_ucstring *name = NULL; int saved_indent_level; de_dbg_indent_save(c, &saved_indent_level); datapos = de_getui32le(pos+6); de_dbg(c, "card #%d at %d, dpos=%d\n", (int)cardnum, (int)pos, (int)datapos); de_dbg_indent(c, 1); if(datapos>=c->infile->len) goto done; bitmap_len = de_getui16le(datapos); de_dbg(c, "bitmap length: %d\n", (int)bitmap_len); if(bitmap_len==0) { text_len = de_getui16le(datapos+2); text_pos = datapos+4; } else { text_len = de_getui16le(datapos + bitmap_len + 10); text_pos = datapos + bitmap_len + 10; } de_dbg(c, "text length: %d\n", (int)text_len); if(bitmap_len==0 && text_len==0) { cardtype = "empty"; } else if(bitmap_len==0) { cardtype = "text-only"; } else if(text_len==0) { cardtype = "graphics-only"; } else { cardtype = "graphics+text"; } de_dbg(c, "card type: %s\n", cardtype); if(bitmap_len==0 && text_len==0) { goto done; } name = ucstring_create(c); dbuf_read_to_ucstring(c->infile, pos+11, 40, name, DE_CONVFLAG_STOP_AT_NUL, DE_ENCODING_ASCII); de_dbg(c, "name: \"%s\"\n", ucstring_get_printable_sz(name)); // Text if(text_len!=0 && c->extract_level>=2) { fi_text = de_finfo_create(c); if(c->filenames_from_file) de_finfo_set_name_from_ucstring(c, fi_text, name); do_text_data(c, d, fi_text, text_pos, text_len); } // Bitmap if(bitmap_len==0) goto done; fi_bitmap = de_finfo_create(c); if(c->filenames_from_file) de_finfo_set_name_from_ucstring(c, fi_bitmap, name); w = de_getui16le(datapos+2); h = de_getui16le(datapos+4); de_dbg(c, "bitmap dimensions: %dx%d\n", (int)w, (int)h); img = de_bitmap_create(c, w, h, 1); src_rowspan = ((w+15)/16)*2; de_convert_and_write_image_bilevel(c->infile, datapos+10, w, h, src_rowspan, 0, fi_bitmap, 0); done: ucstring_destroy(name); de_bitmap_destroy(img); de_finfo_destroy(c, fi_bitmap); de_finfo_destroy(c, fi_text); de_dbg_indent_restore(c, saved_indent_level); }
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); }
// XIMG and similar formats. // TODO: Should this function be merged with do_gem_img()? static int do_gem_ximg(deark *c, lctx *d) { dbuf *unc_pixels = NULL; de_bitmap *img = NULL; de_finfo *fi = NULL; int retval = 0; int saved_indent_level; de_dbg_indent_save(c, &saved_indent_level); de_dbg(c, "header (continued) at %d", 8*2); de_dbg_indent(c, 1); if((d->nplanes>=1 && d->nplanes<=8) /* || d->nplanes==24 */) { ; } else { if(d->is_ximg) de_err(c, "%d-plane XIMG images are not supported", (int)d->nplanes); else de_err(c, "This type of %d-plane image is not supported", (int)d->nplanes); goto done; } if(d->header_size_in_words==25 && !d->is_ximg) { i64 pal_pos = d->header_size_in_bytes-32; de_dbg(c, "palette at %d", (int)pal_pos); de_dbg_indent(c, 1); de_fmtutil_read_atari_palette(c, c->infile, pal_pos, d->pal, 16, ((i64)1)<<d->nplanes, 0); de_dbg_indent(c, -1); } else { read_palette_ximg(c, d); } if(d->nplanes==1 && d->pal[0]==d->pal[1]) { de_dbg(c, "Palette doesn't seem to be present. Using a default palette."); d->pal[0] = DE_STOCKCOLOR_WHITE; d->pal[1] = DE_STOCKCOLOR_BLACK; } de_dbg_indent(c, -1); de_dbg(c, "image at %d", (int)d->header_size_in_bytes); unc_pixels = dbuf_create_membuf(c, d->rowspan_total*d->h, 0); uncompress_pixels(c, d, unc_pixels, d->header_size_in_bytes, c->infile->len-d->header_size_in_bytes); img = de_bitmap_create(c, d->w, d->h, 3); fi = de_finfo_create(c); set_density(c, d, fi); if(d->nplanes>8) { read_rgb_image(c, d, unc_pixels, img); } else { read_paletted_image(c, d, unc_pixels, img); } de_bitmap_write_to_file_finfo(img, fi, 0); retval = 1; done: de_bitmap_destroy(img); de_finfo_destroy(c, fi); dbuf_close(unc_pixels); de_dbg_indent_restore(c, saved_indent_level); return retval; }
static int do_element(deark *c, lctx *d, i64 pos1, i64 nbytes_avail, i64 *bytes_used) { i64 ele_id; i64 ele_dlen; i64 pos = pos1; int retval = 0; const struct ele_id_info *einfo; const char *ele_name; int saved_indent_level; unsigned int dtype; int should_call_start_handler = 0; int should_decode_default = 0; int should_print_NOT_DECODING_msg = 0; int should_call_end_handler = 0; int len_ret; char tmpbuf[80]; de_dbg_indent_save(c, &saved_indent_level); de_dbg(c, "element at %"I64_FMT", max_len=%"I64_FMT, pos1, nbytes_avail); de_dbg_indent(c, 1); if(1!=get_var_size_int(c->infile, &ele_id, &pos, nbytes_avail)) { de_err(c, "Failed to read ID of element at %"I64_FMT, pos1); goto done; } einfo = find_ele_id_info(ele_id); if(einfo && einfo->name) ele_name = einfo->name; else ele_name = "?"; if(einfo) dtype = einfo->flags & 0xff; else dtype = 0; de_dbg(c, "id: 0x%"U64_FMTx" (%s)", (u64)ele_id, ele_name); if(d->show_encoded_id) { print_encoded_id(c, d, pos1, pos-pos1); } len_ret = get_var_size_int(c->infile, &ele_dlen, &pos, pos1+nbytes_avail-pos); if(len_ret==1) { de_snprintf(tmpbuf, sizeof(tmpbuf), "%"I64_FMT, ele_dlen); } else if(len_ret==2) { ele_dlen = c->infile->len - pos; de_strlcpy(tmpbuf, "unknown", sizeof(tmpbuf)); } else { de_err(c, "Failed to read length of element at %"I64_FMT, pos1); goto done; } de_dbg(c, "data at %"I64_FMT", dlen=%s, type=%s", pos, tmpbuf, get_type_name(dtype)); if(len_ret==2) { // EBML does not have any sort of end-of-master-element marker, which // presents a problem when a master element has an unknown length. // // EBML's "solution" is this: // "The end of an Unknown-Sized Element is determined by whichever // comes first: the end of the file or the beginning of the next EBML // Element, defined by this document or the corresponding EBML Schema, // that is not independently valid as Descendant Element of the // Unknown-Sized Element." // // This would appear to require a sophisticated, high-level algorithm // with 100% complete knowledge of the latest version of the specific // application format. We do not have such an algorithm. de_err(c, "EBML files with unknown-length elements are not supported"); goto done; } if(pos + ele_dlen > c->infile->len) { de_err(c, "Element at %"I64_FMT" goes beyond end of file", pos1); goto done; } if(einfo) { should_decode_default = 1; if(einfo->flags & 0x0200) { should_decode_default = 0; } else if((einfo->flags & 0x0100) && c->debug_level<2) { should_decode_default = 0; should_print_NOT_DECODING_msg = 1; } } if(should_decode_default && einfo && einfo->hfn) { should_call_start_handler = 1; } if(should_decode_default && einfo && einfo->hfn && (einfo->flags & 0x0800)) { should_call_end_handler = 1; } if(should_call_start_handler) { struct handler_params hp; de_zeromem(&hp, sizeof(struct handler_params)); hp.dpos = pos; hp.dlen = ele_dlen; einfo->hfn(c, d, &hp); } if(should_decode_default) { switch(dtype) { case TY_m: do_element_sequence(c, d, pos, ele_dlen); break; case TY_u: decode_uint(c, d, einfo, pos, ele_dlen); break; case TY_f: decode_float(c, d, einfo, pos, ele_dlen); break; case TY_8: decode_string(c, d, einfo, pos, ele_dlen, DE_ENCODING_UTF8); break; case TY_s: decode_string(c, d, einfo, pos, ele_dlen, DE_ENCODING_PRINTABLEASCII); break; case TY_d: decode_date(c, d, einfo, pos, ele_dlen); break; } } else { if(should_print_NOT_DECODING_msg) { de_dbg(c, "[not decoding this element]"); } } if(should_call_end_handler) { struct handler_params hp; de_zeromem(&hp, sizeof(struct handler_params)); hp.dpos = pos; hp.dlen = ele_dlen; hp.end_flag = 1; einfo->hfn(c, d, &hp); } pos += ele_dlen; *bytes_used = pos - pos1; retval = 1; done: de_dbg_indent_restore(c, saved_indent_level); return retval; }