// 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)); }
// TODO: Consolidate this withe do_static_bitmap()? static void do_picture_bitmap(deark *c, lctx *d, struct para_info *pinfo) { i64 pos1 = pinfo->thisparapos; i64 pos; i64 cbHeader, cbSize; i64 bmWidth, bmHeight; i64 bmPlanes; i64 bmBitsPixel; i64 rowspan; pos = pos1; pos += 16; pos += 2; bmWidth = de_getu16le_p(&pos); // pos1+16+2 bmHeight = de_getu16le_p(&pos); // pos1+16+4 de_dbg_dimensions(c, bmWidth, bmHeight); rowspan = de_getu16le_p(&pos); // pos1+16+6 de_dbg(c, "bytes/row: %d", (int)rowspan); bmPlanes = (i64)de_getbyte_p(&pos); de_dbg(c, "planes: %d", (int)bmPlanes); bmBitsPixel = (i64)de_getbyte_p(&pos); // pos1+16+9 de_dbg(c, "bmBitsPixel: %d", (int)bmBitsPixel); pos += 4; cbHeader = de_getu16le_p(&pos); // pos1+30 de_dbg(c, "cbHeader: %d", (int)cbHeader); cbSize = de_getu32le_p(&pos); // pos1+32 de_dbg(c, "cbSize: %d", (int)cbSize); if(bmBitsPixel!=1 || bmPlanes!=1) { de_err(c, "This type of bitmap is not supported (bmBitsPixel=%d, planes=%d)", (int)bmBitsPixel, (int)bmPlanes); goto done; } pos = pos1 + cbHeader; de_convert_and_write_image_bilevel(c->infile, pos, bmWidth, bmHeight, rowspan, 0, NULL, 0); done: ; }
static int de_identify_ogg(deark *c) { i64 pos = 0; if(!c->detection_data.id3.detection_attempted) { de_err(c, "ogg detection requires id3 module"); return 0; } if(c->detection_data.id3.has_id3v2) { pos = (i64)c->detection_data.id3.bytes_at_start; } if(!dbuf_memcmp(c->infile, pos, "OggS", 4)) return 100; return 0; }
// pos1 points to the ole_id field (should be 0x00000501). // Returns nonzero if there may be additional renditions. static int do_picture_ole_rendition(deark *c, lctx *d, struct para_info *pinfo, unsigned int objectType, int rendition_idx, i64 pos1, i64 *bytes_consumed) { unsigned int ole_id; unsigned int objectType2; int retval = 0; de_dbg(c, "OLE rendition[%d] at %d", rendition_idx, (int)pos1); de_dbg_indent(c, 1); ole_id = (unsigned int)de_getu32le(pos1); de_dbg(c, "ole id: 0x%08x", ole_id); if(ole_id!=0x00000501U) { de_err(c, "Unexpected ole_id: 0x%08x", ole_id); goto done; } objectType2 = (unsigned int)de_getu32le(pos1+4); de_dbg(c, "type: %u", objectType2); if(objectType==1) { if(objectType2==3) { do_picture_ole_static_rendition(c, d, pinfo, rendition_idx, pos1, bytes_consumed); } } else if(objectType==2) { if(objectType2==0) { goto done; } else if(objectType2==2) { do_picture_ole_embedded_rendition(c, d, pinfo, rendition_idx, pos1, bytes_consumed); retval = 1; } else if(objectType2==5) { // replacement do_picture_ole_static_rendition(c, d, pinfo, rendition_idx, pos1, bytes_consumed); } } done: de_dbg_indent(c, -1); return retval; }
// Decode the base-64 data, and write to d->decoded. // Returns 0 if there was an error. static int do_decode_main(deark *c, lctx *d, de_int64 pos) { de_byte b; de_byte x; de_byte pending_byte = 0; unsigned int pending_bits_used = 0; while(1) { if(pos >= c->infile->len) return 0; // unexpected end of file b = de_getbyte(pos); pos++; if(b==':') { break; } else if(b=='\x0a' || b=='\x0d' || b==' ' || b=='\t') { // Ignore whitespace continue; } x = get_char_value(b); if(x>=64) { de_err(c, "Invalid BinHex data at %d\n", (int)(pos-1)); return 0; } // TODO: Simplify this code if(pending_bits_used==0) { pending_byte = x; pending_bits_used = 6; } else if(pending_bits_used==2) { pending_byte = (pending_byte<<(8-pending_bits_used))|x; dbuf_writebyte(d->decoded, pending_byte); pending_bits_used -= 2; } else if(pending_bits_used==4) { pending_byte = (pending_byte<<(8-pending_bits_used))|(x>>(pending_bits_used-2)); dbuf_writebyte(d->decoded, pending_byte); pending_byte = x&0x03; pending_bits_used -= 2; } else if(pending_bits_used==6) {
static int do_lead_section(deark *c, lctx *d) { int retval = 0; de_dbg(c, "lead section at %d", 0); de_dbg_indent(c, 1); d->ver_major = de_getbyte(4); d->ver_minor = de_getbyte(5); de_dbg(c, "RPM format version: %d.%d", (int)d->ver_major, (int)d->ver_minor); if(d->ver_major < 3) { de_err(c, "Unsupported RPM version (%d.%d)", (int)d->ver_major, (int)d->ver_minor); goto done; } retval = 1; done: de_dbg_indent(c, -1); return retval; }
static void de_run_woz(deark *c, de_module_params *mparams) { lctx *d = NULL; struct de_iffctx *ictx = NULL; u32 crc; i64 pos = 0; // WOZ has a 12-byte header, then sequence of chunks that are basically the // same format as RIFF. d = de_malloc(c, sizeof(lctx)); ictx = de_malloc(c, sizeof(struct de_iffctx)); ictx->userdata = (void*)d; ictx->preprocess_chunk_fn = my_preprocess_woz_chunk_fn; ictx->handle_chunk_fn = my_woz_chunk_handler; ictx->f = c->infile; ictx->is_le = 1; ictx->reversed_4cc = 0; if(ictx->f->len<12) goto done; de_dbg(c, "header at %d", (int)pos); de_dbg_indent(c, 1); pos += 3; // "WOZ" part of signature d->wozver = dbuf_getbyte_p(ictx->f, &pos); de_dbg(c, "format version: '%c'", de_byte_to_printable_char(d->wozver)); if(d->wozver<'1' || d->wozver>'2') { de_err(c, "Unsupported WOZ format version"); goto done; } pos += 4; // rest of signature crc = (u32)dbuf_getu32le_p(ictx->f, &pos); de_dbg(c, "crc: 0x%08x", (unsigned int)crc); de_dbg_indent(c, -1); de_fmtutil_read_iff_format(c, ictx, pos, ictx->f->len-pos); done: de_free(c, ictx); de_free(c, d); }
static void do_modhelp(deark *c) { struct deark_module_info *module_to_use = NULL; de_register_modules(c); 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(!module_to_use->help_fn) { de_msg(c, "No help available for module \"%s\"\n", c->input_format_req); goto done; } de_msg(c, "Help for module \"%s\":\n", c->input_format_req); module_to_use->help_fn(c); done: ; }
void dbuf_write(dbuf *f, const u8 *m, i64 len) { if(f->len + len > f->max_len_hard) { do_on_dbuf_size_exceeded(f); } if(f->writecallback_fn) { f->writecallback_fn(f, m, len); } if(f->btype==DBUF_TYPE_NULL) { f->len += len; return; } else if(f->btype==DBUF_TYPE_OFILE || f->btype==DBUF_TYPE_STDOUT) { if(!f->fp) return; if(f->c->debug_level>=3) { de_dbg3(f->c, "writing %d bytes to %s", (int)len, f->name); } fwrite(m, 1, (size_t)len, f->fp); f->len += len; return; } else if(f->btype==DBUF_TYPE_MEMBUF) { if(f->c->debug_level>=3 && f->name) { de_dbg3(f->c, "appending %d bytes to membuf %s", (int)len, f->name); } membuf_append(f, m, len); return; } else if(f->btype==DBUF_TYPE_ODBUF) { dbuf_write(f->parent_dbuf, m, len); f->len += len; return; } de_err(f->c, "Internal: Invalid output file type (%d)", f->btype); de_fatalerror(f->c); }
// Create or open a file for writing, that is *not* one of the usual // "output.000.ext" files we extract from the input file. // // overwrite_mode, flags: Same as for de_fopen_for_write(). // // On failure, prints an error message, and sets f->btype to DBUF_TYPE_NULL. dbuf *dbuf_create_unmanaged_file(deark *c, const char *fname, int overwrite_mode, unsigned int flags) { dbuf *f; char msgbuf[200]; f = de_malloc(c, sizeof(dbuf)); f->c = c; f->is_managed = 0; f->name = de_strdup(c, fname); f->btype = DBUF_TYPE_OFILE; f->max_len_hard = c->max_output_file_size; f->fp = de_fopen_for_write(c, f->name, msgbuf, sizeof(msgbuf), c->overwrite_mode, flags); if(!f->fp) { de_err(c, "Failed to write %s: %s", f->name, msgbuf); f->btype = DBUF_TYPE_NULL; } return f; }
static int do_page(deark *c, lctx *d, int pagenum, de_int64 pos1) { struct page_ctx *pg = NULL; int retval = 0; pg = de_malloc(c, sizeof(struct page_ctx)); pg->fmt = identify_fmt(c, pos1); d->last_fmt = pg->fmt; pg->fmt_name = get_fmt_name(pg->fmt); if(pg->fmt==0) { de_err(c, "Not PNM/PAM format\n"); goto done; } if(pagenum==0) { de_declare_fmt(c, pg->fmt_name); } if(pg->fmt==FMT_PAM) { if(!read_pam_header(c, d, pg, pos1)) goto done; } else { if(!read_pnm_header(c, d, pg, pos1)) goto done; } if(!do_image(c, d, pg, pg->hdr_parse_pos)) { goto done; } d->last_bytesused = (pg->hdr_parse_pos + pg->image_data_len) - pos1; retval = 1; done: de_free(c, pg); return retval; }
static void run_ogg_internal(deark *c, lctx *d) { i64 pos; i64 ogg_end; struct de_id3info id3i; d->always_hexdump = de_get_ext_option(c, "ogg:hexdump")?1:0; d->streamtable = de_inthashtable_create(c); de_fmtutil_handle_id3(c, c->infile, &id3i, 0); pos = id3i.main_start; ogg_end = id3i.main_end; while(1) { u32 sig; int ret; i64 bytes_consumed = 0; if(pos >= ogg_end) break; sig = (u32)de_getu32be(pos); if(sig!=0x04f676753U) { de_err(c, "Ogg page signature not found at %"I64_FMT, pos); break; } de_dbg(c, "page at %"I64_FMT, pos); de_dbg_indent(c, 1); ret = do_ogg_page(c, d, pos, &bytes_consumed); de_dbg_indent(c, -1); if(!ret || bytes_consumed<=4) break; pos += bytes_consumed; d->total_page_count++; } if(!d->format_declared) declare_ogg_format(c, d); de_dbg(c, "number of bitstreams: %d", (int)d->bitstream_count); }
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 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 de_run_unifont_hex(deark *c, de_module_params *mparams) { struct de_bitmap_font *font = NULL; i64 char_array_numalloc = 0; char linebuf[256]; struct de_linereader *lr = NULL; int ok = 0; font = de_create_bitmap_font(c); font->has_unicode_codepoints = 1; font->prefer_unicode = 1; font->nominal_height = 16; char_array_numalloc = 1024; font->char_array = de_mallocarray(c, char_array_numalloc, sizeof(struct de_bitmap_font_char)); lr = de_linereader_create(c, c->infile); while(de_linereader_readnextline(c, lr, linebuf, sizeof(linebuf), 0)) { i64 idx; struct de_bitmap_font_char *ch; i64 fdata_len; char *dptr; // Pointer into linebuf, to the char after the ":" if(font->num_chars>=17*65536) goto done; idx = font->num_chars; if(idx >= char_array_numalloc) { i64 new_numalloc = char_array_numalloc*2; font->char_array = de_reallocarray(c, font->char_array, char_array_numalloc, sizeof(struct de_bitmap_font_char), new_numalloc); char_array_numalloc = new_numalloc; } ch = &font->char_array[idx]; dptr = de_strchr(linebuf, ':'); if(!dptr) goto done; *dptr = '\0'; dptr++; fdata_len = (i64)de_strlen(dptr); ch->codepoint_unicode = (i32)de_strtoll(linebuf, NULL, 16); if(ch->codepoint_unicode<0 || ch->codepoint_unicode>=17*65536) goto done; ch->width = (int)((fdata_len/32)*8); ch->height = 16; de_dbg2(c, "char[%d] U+%04X %d"DE_CHAR_TIMES"%d", (int)font->num_chars, (unsigned int)ch->codepoint_unicode, ch->width, ch->height); if(ch->width<8 || ch->width>32) goto done; ch->rowspan = (ch->width+7)/8; ch->bitmap = de_malloc(c, ch->rowspan * ch->height); decode_fontdata(c, dptr, ch); font->num_chars++; if(ch->width > font->nominal_width) { font->nominal_width = ch->width; } } de_dbg(c, "number of characters: %d", (int)font->num_chars); if(font->num_chars<1) goto done; if(font->nominal_width<1) goto done; de_font_bitmap_font_to_image(c, font, NULL, 0); ok = 1; done: if(!ok) { de_err(c, "Error parsing HEX font file (offset %"I64_FMT")", lr->f_pos); } de_linereader_destroy(c, lr); if(font) { if(font->char_array) { i64 k; for(k=0; k<font->num_chars; k++) { de_free(c, font->char_array[k].bitmap); } de_free(c, font->char_array); } font->char_array = NULL; de_destroy_bitmap_font(c, font); } }
// 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; }
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 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 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); }
// Note that a header *structure* is distinct from the header *section*. // Both the signature section and the header section use a header structure. static int do_header_structure(deark *c, lctx *d, int is_sig, i64 pos1, i64 *section_size) { i64 pos; i64 indexcount; i64 storesize; u8 buf[4]; u8 header_ver; i64 i; i64 tag_id, tag_type, tag_offset, tag_count; i64 data_store_pos; const char *hdrname; int retval = 0; hdrname = is_sig?"sig":"hdr"; pos = pos1; de_dbg(c, "%s section at %d", hdrname, (int)pos1); de_dbg_indent(c, 1); de_read(buf, pos, 4); if(buf[0]!=0x8e || buf[1]!=0xad || buf[2]!=0xe8) { de_err(c, "Bad header signature at %d", (int)pos); goto done; } header_ver = buf[3]; if(header_ver != 1) { de_err(c, "Unsupported header version"); goto done; } pos += 8; indexcount = de_getu32be(pos); storesize = de_getu32be(pos+4); de_dbg(c, "%s: pos=%d indexcount=%d storesize=%d", hdrname, (int)pos, (int)indexcount, (int)storesize); pos += 8; if(indexcount>1000) goto done; data_store_pos = pos + 16*indexcount; de_dbg(c, "%s: tag table at %d", hdrname, (int)pos); de_dbg_indent(c, 1); for(i=0; i<indexcount; i++) { tag_id = de_getu32be(pos); tag_type = de_getu32be(pos+4); tag_offset = de_getu32be(pos+8); tag_count = de_getu32be(pos+12); de_dbg2(c, "tag #%d type=%d offset=%d count=%d", (int)tag_id, (int)tag_type, (int)tag_offset, (int)tag_count); if(is_sig==0 && tag_id==DE_RPMTAG_PAYLOADCOMPRESSOR && tag_type==DE_RPM_STRING_TYPE) { read_compression_type(c, d, data_store_pos+tag_offset); } else if(is_sig==0 && tag_id==DE_RPMTAG_NAME && tag_type==DE_RPM_STRING_TYPE) { if(!d->name_srd) { d->name_srd = dbuf_read_string(c->infile, data_store_pos+tag_offset, DE_DBG_MAX_STRLEN, DE_DBG_MAX_STRLEN, DE_CONVFLAG_STOP_AT_NUL, DE_ENCODING_ASCII); de_dbg(c, "name: \"%s\"", ucstring_getpsz(d->name_srd->str)); } } else if(is_sig==0 && tag_id==DE_RPMTAG_VERSION && tag_type==DE_RPM_STRING_TYPE) { if(!d->version_srd) { d->version_srd = dbuf_read_string(c->infile, data_store_pos+tag_offset, DE_DBG_MAX_STRLEN, DE_DBG_MAX_STRLEN, DE_CONVFLAG_STOP_AT_NUL, DE_ENCODING_ASCII); de_dbg(c, "version: \"%s\"", ucstring_getpsz(d->version_srd->str)); } } else if(is_sig==0 && tag_id==DE_RPMTAG_RELEASE && tag_type==DE_RPM_STRING_TYPE) { if(!d->release_srd) { d->release_srd = dbuf_read_string(c->infile, data_store_pos+tag_offset, DE_DBG_MAX_STRLEN, DE_DBG_MAX_STRLEN, DE_CONVFLAG_STOP_AT_NUL, DE_ENCODING_ASCII); de_dbg(c, "release: \"%s\"", ucstring_getpsz(d->release_srd->str)); } } pos += 16; } de_dbg_indent(c, -1); pos = data_store_pos; de_dbg(c, "%s: data store at %d", hdrname, (int)pos); pos += storesize; *section_size = pos - pos1; retval = 1; done: de_dbg_indent(c, -1); return retval; }
dbuf *dbuf_create_output_file(deark *c, const char *ext, de_finfo *fi, unsigned int createflags) { char nbuf[500]; char msgbuf[200]; dbuf *f; const char *basefn; int file_index; u8 is_directory = 0; char *name_from_finfo = NULL; i64 name_from_finfo_len = 0; if(ext && fi && fi->original_filename_flag) { de_dbg(c, "[internal warning: Incorrect use of create_output_file]"); } f = de_malloc(c, sizeof(dbuf)); f->c = c; f->max_len_hard = c->max_output_file_size; f->is_managed = 1; if(fi && fi->is_directory) { is_directory = 1; } if(is_directory && !c->keep_dir_entries) { de_dbg(c, "skipping 'directory' file"); f->btype = DBUF_TYPE_NULL; goto done; } if(c->extract_policy==DE_EXTRACTPOLICY_MAINONLY) { if(createflags&DE_CREATEFLAG_IS_AUX) { de_dbg(c, "skipping 'auxiliary' file"); f->btype = DBUF_TYPE_NULL; goto done; } } else if(c->extract_policy==DE_EXTRACTPOLICY_AUXONLY) { if(!(createflags&DE_CREATEFLAG_IS_AUX)) { de_dbg(c, "skipping 'main' file"); f->btype = DBUF_TYPE_NULL; goto done; } } file_index = c->file_count; c->file_count++; basefn = c->base_output_filename ? c->base_output_filename : "output"; if(fi && ucstring_isnonempty(fi->file_name_internal)) { name_from_finfo_len = 1 + ucstring_count_utf8_bytes(fi->file_name_internal); name_from_finfo = de_malloc(c, name_from_finfo_len); ucstring_to_sz(fi->file_name_internal, name_from_finfo, (size_t)name_from_finfo_len, 0, DE_ENCODING_UTF8); } if(c->output_style==DE_OUTPUTSTYLE_ARCHIVE && !c->base_output_filename && fi && fi->is_directory && (fi->is_root_dir || (fi->detect_root_dot_dir && fi->orig_name_was_dot))) { de_strlcpy(nbuf, ".", sizeof(nbuf)); } else if(c->output_style==DE_OUTPUTSTYLE_ARCHIVE && !c->base_output_filename && fi && fi->original_filename_flag && name_from_finfo) { // TODO: This is a "temporary" hack to allow us to, when both reading from // and writing to an archive format, use some semblance of the correct // filename (instead of "output.xxx.yyy"). // There are some things that we don't handle optimally, such as // subdirectories. // A major redesign of the file naming logic would be good. de_strlcpy(nbuf, name_from_finfo, sizeof(nbuf)); } else { char fn_suffix[256]; if(ext && name_from_finfo) { de_snprintf(fn_suffix, sizeof(fn_suffix), "%s.%s", name_from_finfo, ext); } else if(ext) { de_strlcpy(fn_suffix, ext, sizeof(fn_suffix)); } else if(is_directory && name_from_finfo) { de_snprintf(fn_suffix, sizeof(fn_suffix), "%s.dir", name_from_finfo); } else if(name_from_finfo) { de_strlcpy(fn_suffix, name_from_finfo, sizeof(fn_suffix)); } else if(is_directory) { de_strlcpy(fn_suffix, "dir", sizeof(fn_suffix)); } else { de_strlcpy(fn_suffix, "bin", sizeof(fn_suffix)); } de_snprintf(nbuf, sizeof(nbuf), "%s.%03d.%s", basefn, file_index, fn_suffix); } f->name = de_strdup(c, nbuf); if(fi) { // The finfo object passed to us at file creation is not required to // remain valid, so make a copy of anything in it that we might need // later. f->fi_copy = de_finfo_create(c); finfo_shallow_copy(c, fi, f->fi_copy); // Here's where we respect the -intz option, by using it to convert to // UTC in some cases. if(f->fi_copy->mod_time.is_valid && f->fi_copy->mod_time.tzcode==DE_TZCODE_LOCAL && c->input_tz_offs_seconds!=0) { de_timestamp_cvt_to_utc(&f->fi_copy->mod_time, -c->input_tz_offs_seconds); } if(f->fi_copy->image_mod_time.is_valid && f->fi_copy->image_mod_time.tzcode==DE_TZCODE_LOCAL && c->input_tz_offs_seconds!=0) { de_timestamp_cvt_to_utc(&f->fi_copy->image_mod_time, -c->input_tz_offs_seconds); } } if(file_index < c->first_output_file) { f->btype = DBUF_TYPE_NULL; goto done; } if(c->max_output_files>=0 && file_index >= c->first_output_file + c->max_output_files) { f->btype = DBUF_TYPE_NULL; goto done; } c->num_files_extracted++; if(c->extrlist_dbuf) { dbuf_printf(c->extrlist_dbuf, "%s\n", f->name); dbuf_flush(c->extrlist_dbuf); } if(c->list_mode) { f->btype = DBUF_TYPE_NULL; if(c->list_mode_include_file_id) { de_msg(c, "%d:%s", file_index, f->name); } else { de_msg(c, "%s", f->name); } goto done; } if(c->output_style==DE_OUTPUTSTYLE_ARCHIVE && c->archive_fmt==DE_ARCHIVEFMT_TAR) { de_info(c, "Adding %s to TAR file", f->name); f->btype = DBUF_TYPE_ODBUF; // A dummy max_len_hard value. The parent will do the checking. f->max_len_hard = DE_DUMMY_MAX_FILE_SIZE; f->writing_to_tar_archive = 1; de_tar_start_member_file(c, f); } else if(c->output_style==DE_OUTPUTSTYLE_ARCHIVE) { // ZIP i64 initial_alloc; de_info(c, "Adding %s to ZIP file", f->name); f->btype = DBUF_TYPE_MEMBUF; f->max_len_hard = DE_MAX_MEMBUF_SIZE; if(is_directory) { // A directory entry is not expected to have any data associated // with it (besides the files it contains). initial_alloc = 16; } else { initial_alloc = 65536; } f->membuf_buf = de_malloc(c, initial_alloc); f->membuf_alloc = initial_alloc; f->write_memfile_to_zip_archive = 1; } else if(c->output_style==DE_OUTPUTSTYLE_STDOUT) { de_info(c, "Writing %s to [stdout]", f->name); f->btype = DBUF_TYPE_STDOUT; // TODO: Should we increase f->max_len_hard? f->fp = stdout; } else { de_info(c, "Writing %s", f->name); f->btype = DBUF_TYPE_OFILE; f->fp = de_fopen_for_write(c, f->name, msgbuf, sizeof(msgbuf), c->overwrite_mode, 0); if(!f->fp) { de_err(c, "Failed to write %s: %s", f->name, msgbuf); f->btype = DBUF_TYPE_NULL; } } done: de_free(c, name_from_finfo); return f; }
// Read len bytes, starting at file position pos, into buf. // Unread bytes will be set to 0. void dbuf_read(dbuf *f, u8 *buf, i64 pos, i64 len) { i64 bytes_read = 0; i64 bytes_to_read; deark *c; c = f->c; bytes_to_read = len; if(pos >= f->len) { bytes_to_read = 0; } else if(pos + bytes_to_read > f->len) { bytes_to_read = f->len - pos; } if(bytes_to_read<1) { goto done_read; } if(!f->cache && f->cache_policy==DE_CACHE_POLICY_ENABLED) { populate_cache(f); } // If the data we need is all cached, get it from cache. if(f->cache && pos >= f->cache_start_pos && pos + bytes_to_read <= f->cache_start_pos + f->cache_bytes_used) { de_memcpy(buf, &f->cache[pos - f->cache_start_pos], (size_t)bytes_to_read); bytes_read = bytes_to_read; goto done_read; } switch(f->btype) { case DBUF_TYPE_IFILE: if(!f->fp) { de_err(c, "Internal: File not open"); de_fatalerror(c); return; } // For performance reasons, don't call fseek if we're already at the // right position. if(!f->file_pos_known || f->file_pos!=pos) { de_fseek(f->fp, pos, SEEK_SET); } bytes_read = fread(buf, 1, (size_t)bytes_to_read, f->fp); f->file_pos = pos + bytes_read; f->file_pos_known = 1; break; case DBUF_TYPE_IDBUF: // Recursive call to the parent dbuf. dbuf_read(f->parent_dbuf, buf, f->offset_into_parent_dbuf+pos, bytes_to_read); // The parent dbuf always writes 'bytes_to_read' bytes. bytes_read = bytes_to_read; break; case DBUF_TYPE_MEMBUF: de_memcpy(buf, &f->membuf_buf[pos], (size_t)bytes_to_read); bytes_read = bytes_to_read; break; default: de_err(c, "Internal: getbytes from this I/O type not implemented"); de_fatalerror(c); return; } done_read: // Zero out any requested bytes that were not read. if(bytes_read < len) { de_zeromem(buf+bytes_read, (size_t)(len - bytes_read)); } }
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, 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; }
void de_font_bitmap_font_to_image(deark *c, struct de_bitmap_font *font1, de_finfo *fi, unsigned int createflags) { struct font_render_ctx *fctx = NULL; i64 i, j, k; de_bitmap *img = NULL; i64 xpos, ypos; i64 img_leftmargin, img_topmargin; i64 img_rightmargin, img_bottommargin; i64 img_vpixelsperchar; i64 img_width, img_height; i64 num_table_rows_to_display; i64 num_table_rows_total; i64 last_valid_row; struct de_bitmap_font *dfont = NULL; i64 chars_per_row = 32; const char *s; struct row_info_struct *row_info = NULL; struct col_info_struct *col_info = NULL; int unicode_req = 0; i64 label_stride; i64 rownum, colnum; i64 curpos; unsigned int dnflags; fctx = de_malloc(c, sizeof(struct font_render_ctx)); fctx->font = font1; if(fctx->font->num_chars<1) goto done; if(fctx->font->num_chars>17*65536) goto done; if(fctx->font->nominal_width>512 || fctx->font->nominal_height>512) { de_err(c, "Font size too big (%d"DE_CHAR_TIMES"%d). Not supported.", (int)fctx->font->nominal_width, (int)fctx->font->nominal_height); goto done; } // -1 = "no preference" unicode_req = de_get_ext_option_bool(c, "font:tounicode", -1); if(unicode_req==0 && (fctx->font->has_nonunicode_codepoints || !fctx->font->has_unicode_codepoints)) { ; // Render as nonunicode. } else if(fctx->font->has_unicode_codepoints && (unicode_req>0 || fctx->font->prefer_unicode || !fctx->font->has_nonunicode_codepoints)) { fctx->render_as_unicode = 1; } s = de_get_ext_option(c, "font:charsperrow"); if(s) { chars_per_row = de_atoi64(s); if(chars_per_row<1) chars_per_row=1; } dfont = make_digit_font(c); fctx->codepoint_tmp = de_mallocarray(c, fctx->font->num_chars, sizeof(i32)); fixup_codepoints(c, fctx); get_min_max_codepoint(fctx); if(fctx->num_valid_chars<1) goto done; num_table_rows_total = fctx->max_codepoint/chars_per_row+1; // TODO: Clean up these margin calculations, and make it more general. if(fctx->render_as_unicode) { img_leftmargin = dfont->nominal_width * 5 + 6; } else { if(fctx->max_codepoint >= 1000) img_leftmargin = dfont->nominal_width * 5 + 6; else img_leftmargin = dfont->nominal_width * 3 + 6; } img_topmargin = dfont->nominal_height + 6; img_rightmargin = 1; img_bottommargin = 1; // Scan the characters, and record relevant information. row_info = de_mallocarray(c, num_table_rows_total, sizeof(struct row_info_struct)); col_info = de_mallocarray(c, chars_per_row, sizeof(struct col_info_struct)); for(i=0; i<chars_per_row; i++) { #define MIN_CHAR_CELL_WIDTH 5 col_info[i].display_width = MIN_CHAR_CELL_WIDTH; } for(k=0; k<fctx->font->num_chars; k++) { i64 char_display_width; if(fctx->codepoint_tmp[k] == DE_CODEPOINT_INVALID) continue; if(!is_valid_char(&fctx->font->char_array[k])) continue; rownum = fctx->codepoint_tmp[k] / chars_per_row; colnum = fctx->codepoint_tmp[k] % chars_per_row; if(rownum<0 || rownum>=num_table_rows_total) { de_err(c, "internal: bad rownum"); de_fatalerror(c); } // Remember that there is at least one valid character in this character's row. row_info[rownum].is_visible = 1; // Track the maximum width of any character in this character's column. char_display_width = (i64)(fctx->font->char_array[k].width + (int)fctx->font->char_array[k].extraspace_l + (int)fctx->font->char_array[k].extraspace_r); if(char_display_width > col_info[colnum].display_width) { col_info[colnum].display_width = char_display_width; } } img_vpixelsperchar = fctx->font->nominal_height + 1; // Figure out how many rows are used, and where to draw them. num_table_rows_to_display = 0; last_valid_row = -1; curpos = img_topmargin; for(j=0; j<num_table_rows_total; j++) { if(!row_info[j].is_visible) continue; // If we skipped one or more rows, leave some extra vertical space. if(num_table_rows_to_display>0 && !row_info[j-1].is_visible) curpos+=3; last_valid_row = j; row_info[j].display_pos = curpos; curpos += img_vpixelsperchar; num_table_rows_to_display++; } if(num_table_rows_to_display<1) goto done; // Figure out the positions of the columns. curpos = img_leftmargin; for(i=0; i<chars_per_row; i++) { col_info[i].display_pos = curpos; curpos += col_info[i].display_width + 1; } img_width = col_info[chars_per_row-1].display_pos + col_info[chars_per_row-1].display_width + img_rightmargin; img_height = row_info[last_valid_row].display_pos + img_vpixelsperchar -1 + img_bottommargin; img = de_bitmap_create(c, img_width, img_height, 1); // Clear the image for(j=0; j<img->height; j++) { for(i=0; i<img->width; i++) { de_bitmap_setpixel_gray(img, i, j, 128); } } // Draw/clear the cell backgrounds for(j=0; j<num_table_rows_total; j++) { if(!row_info[j].is_visible) continue; ypos = row_info[j].display_pos; for(i=0; i<chars_per_row; i++) { i64 ii, jj; xpos = col_info[i].display_pos; for(jj=0; jj<img_vpixelsperchar-1; jj++) { for(ii=0; ii<col_info[i].display_width; ii++) { de_bitmap_setpixel_gray(img, xpos+ii, ypos+jj, (ii/2+jj/2)%2 ? 176 : 192); } } } } // Draw the labels in the top margin. // TODO: Better label spacing logic. if(fctx->font->nominal_width <= 12) label_stride = 2; else label_stride = 1; for(i=0; i<chars_per_row; i++) { if(i%label_stride != 0) continue; xpos = col_info[i].display_pos + col_info[i].display_width/2; ypos = img_topmargin - 3; dnflags = DNFLAG_HCENTER; if(fctx->render_as_unicode) dnflags |= DNFLAG_HEX; draw_number(c, img, dfont, i, xpos, ypos, dnflags); } // Draw the labels in the left margin. for(j=0; j<num_table_rows_total; j++) { if(!row_info[j].is_visible) continue; xpos = img_leftmargin - 3; ypos = row_info[j].display_pos + (img_vpixelsperchar + dfont->nominal_height + 1)/2; dnflags = 0; if(fctx->render_as_unicode) dnflags |= DNFLAG_HEX | DNFLAG_LEADING_ZEROES; draw_number(c, img, dfont, j*chars_per_row, xpos, ypos, dnflags); } // Render the glyphs. for(k=0; k<fctx->font->num_chars; k++) { if(fctx->codepoint_tmp[k] == DE_CODEPOINT_INVALID) continue; if(!is_valid_char(&fctx->font->char_array[k])) continue; rownum = fctx->codepoint_tmp[k] / chars_per_row; colnum = fctx->codepoint_tmp[k] % chars_per_row; if(rownum<0 || rownum>=num_table_rows_total) { de_err(c, "internal: bad rownum"); de_fatalerror(c); } xpos = col_info[colnum].display_pos; ypos = row_info[rownum].display_pos; de_font_paint_character_idx(c, img, fctx->font, k, xpos, ypos, DE_STOCKCOLOR_BLACK, DE_STOCKCOLOR_WHITE, 0); } de_bitmap_write_to_file_finfo(img, fi, createflags); done: if(dfont) { de_free(c, dfont->char_array); de_destroy_bitmap_font(c, dfont); } de_bitmap_destroy(img); de_free(c, row_info); de_free(c, col_info); if(fctx) { de_free(c, fctx->codepoint_tmp); de_free(c, fctx); } }
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_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; }
// 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_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; }