static void do_glyphs(deark *c, lctx *d) { struct de_bitmap_font *font = NULL; de_byte *font_data = NULL; de_int64 i; de_int64 glyph_rowspan; font = de_create_bitmap_font(c); font->has_nonunicode_codepoints = 1; font->nominal_width = (int)d->glyph_width; font->nominal_height = (int)d->glyph_height; font->num_chars = d->num_glyphs; // This may increase later glyph_rowspan = (d->glyph_width+7)/8; d->num_chars_alloc = d->num_glyphs; if(d->read_extra_codepoints) d->num_chars_alloc += MAX_EXTRA_CODEPOINTS; d->index_of_first_extra_codepoint = d->num_glyphs; d->num_extra_codepoints = 0; font->char_array = de_malloc(c, d->num_chars_alloc * sizeof(struct de_bitmap_font_char)); font_data = de_malloc(c, d->font_data_size); de_read(font_data, d->headersize, d->font_data_size); for(i=0; i<d->num_chars_alloc; i++) { font->char_array[i].width = font->nominal_width; font->char_array[i].height = font->nominal_height; font->char_array[i].rowspan = glyph_rowspan; if(i<d->num_glyphs) font->char_array[i].codepoint_nonunicode = (de_int32)i; else font->char_array[i].codepoint_nonunicode = DE_INVALID_CODEPOINT; font->char_array[i].codepoint_unicode = DE_INVALID_CODEPOINT; if(i<d->num_glyphs) font->char_array[i].bitmap = &font_data[i*d->bytes_per_glyph]; } if(d->has_unicode_table) { if(d->version==2) do_psf2_unicode_table(c, d, font); else do_psf1_unicode_table(c, d, font); } if(d->num_extra_codepoints>0) { font->num_chars = d->index_of_first_extra_codepoint + d->num_extra_codepoints; de_dbg(c, "codepoints aliases: %d\n", (int)d->num_extra_codepoints); de_dbg(c, "total characters: %d\n", (int)font->num_chars); } de_font_bitmap_font_to_image(c, font, NULL, 0); if(font) { de_free(c, font->char_array); de_destroy_bitmap_font(c, font); } de_free(c, font_data); }
void de_destroy_stringreaderdata(deark *c, struct de_stringreaderdata *srd) { if(!srd) return; de_free(c, srd->sz); de_free(c, srd->sz_utf8); ucstring_destroy(srd->str); de_free(c, srd); }
void ucstring_destroy(de_ucstring *s) { deark *c; if(s) { c = s->c; de_free(c, s->str); de_free(c, s->tmp_string); de_free(c, s); } }
void de_fmtutil_free_SAUCE(deark *c, struct de_SAUCE_info *si) { if(!si) return; ucstring_destroy(si->title); ucstring_destroy(si->artist); ucstring_destroy(si->organization); if(si->comments) { i64 k; for(k=0; k<si->num_comments; k++) { ucstring_destroy(si->comments[k].s); } de_free(c, si->comments); } de_free(c, si); }
static void de_run_wri(deark *c, de_module_params *mparams) { lctx *d = NULL; i64 pos; d = de_malloc(c, sizeof(lctx)); if(c->input_encoding==DE_ENCODING_UNKNOWN) d->input_encoding = DE_ENCODING_WINDOWS1252; else d->input_encoding = c->input_encoding; d->extract_text = de_get_ext_option_bool(c, "wri:extracttext", 1); d->extract_ole = de_get_ext_option_bool(c, "wri:extractole", (c->extract_level>=2)?1:0); pos = 0; if(!do_header(c, d, pos)) goto done; if(d->extract_text) { do_html_begin(c, d); } do_para_info(c, d); done: do_html_end(c, d); de_free(c, d); }
static void de_run_cardfile(deark *c, de_module_params *mparams) { lctx *d = NULL; de_byte b; de_int64 pos; de_int64 n; d = de_malloc(c, sizeof(lctx)); pos = 0; b = de_getbyte(pos); if(b=='R') d->fmt=DE_CRDFMT_RRG; else d->fmt=DE_CRDFMT_MGC; if(d->fmt==DE_CRDFMT_RRG) { de_err(c, "CardFile RRG format is not supported\n"); goto done; } pos+=3; d->numcards = de_getui16le(pos); de_dbg(c, "number of cards: %d\n", (int)d->numcards); pos+=2; for(n=0; n<d->numcards; n++) { do_card_index(c, d, n, pos); pos+=52; } done: de_free(c, d); }
static void de_run_pnm(deark *c, de_module_params *mparams) { lctx *d = NULL; de_int64 pos; int ret; int pagenum = 0; d = de_malloc(c, sizeof(lctx)); pos = 0; while(1) { if(c->infile->len - pos < 8) break; d->last_fmt = 0; d->last_bytesused = 0; ret = do_page(c, d, pagenum, pos); if(!ret) break; if(d->last_bytesused<8) break; if(!fmt_is_binary(d->last_fmt)) { break; // ASCII formats don't support multiple images } pos += d->last_bytesused; pagenum++; } de_free(c, d); }
static void de_run_gemmeta(deark *c, de_module_params *mparams) { lctx *d = NULL; de_int64 pos; de_int64 hdrlen_words; de_int64 version; de_int64 imgflag; de_int64 bytesused; d = de_malloc(c, sizeof(lctx)); de_msg(c, "Note: GEM VDI Metafiles can be parsed, but no files can be extracted from them.\n"); pos = 0; hdrlen_words = de_getui16le(pos+2); de_dbg(c, "header length: %d words\n", (int)hdrlen_words); version = de_getui16le(pos+4); de_dbg(c, "version number: %d\n", (int)version); // TODO: Read more header fields. imgflag = de_getui16le(pos+28); de_dbg(c, "image flag: %d\n", (int)imgflag); pos += hdrlen_words*2; while(1) { if(pos >= c->infile->len) break; if(!do_record(c, d, pos, &bytesused)) break; if(bytesused<=0) break; pos += bytesused; } de_free(c, d); }
static void destroy_attachment_data(deark *c, lctx *d) { if(!d->attachmentctx) return; ucstring_destroy(d->attachmentctx->filename); de_free(c, d->attachmentctx); d->attachmentctx = NULL; }
static void de_run_gzip(deark *c, de_module_params *mparams) { lctx *d = NULL; i64 pos; i64 member_size; d = de_malloc(c, sizeof(lctx)); d->crco = de_crcobj_create(c, DE_CRCOBJ_CRC32_IEEE); pos = 0; while(1) { if(pos >= c->infile->len) break; if(!do_gzip_read_member(c, d, pos, &member_size)) { break; } if(member_size<=0) break; pos += member_size; } dbuf_close(d->output_file); if(d) { de_crcobj_destroy(d->crco); de_free(c, d); } }
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); }
void de_print_module_list(deark *c) { int i, k; struct sort_data_struct *sort_data = NULL; de_register_modules(c); // An index to the modules. Will be sorted by name. sort_data = de_malloc(c, c->num_modules * sizeof(struct sort_data_struct)); for(k=0; k<c->num_modules; k++) { sort_data[k].c = c; sort_data[k].module_index = k; } qsort((void*)sort_data, (size_t)c->num_modules, sizeof(struct sort_data_struct), module_compare_fn); for(k=0; k<c->num_modules; k++) { i = sort_data[k].module_index; if(c->module_info[i].id && !(c->module_info[i].flags&DE_MODFLAG_HIDDEN) && !(c->module_info[i].flags&DE_MODFLAG_NONWORKING) ) { if(c->module_info[i].desc) de_printf(c, DE_MSGTYPE_MESSAGE, "%-14s %s\n", c->module_info[i].id, c->module_info[i].desc); else de_printf(c, DE_MSGTYPE_MESSAGE, "%s\n", c->module_info[i].id); } } de_free(c, sort_data); }
static void de_run_psf(deark *c, de_module_params *mparams) { lctx *d = NULL; de_byte b; const char *s; d = de_malloc(c, sizeof(lctx)); s = de_get_ext_option(c, "font:noaliases"); if(s) d->read_extra_codepoints = 0; else d->read_extra_codepoints = 1; b = de_getbyte(0); if(b==0x36) { d->version=1; } else if(b==0x72) { d->version=2; } else { de_err(c, "Not a PSF file\n"); goto done; } de_dbg(c, "PSF version: %d\n", (int)d->version); if(d->version==2) do_psf2_header(c, d); else do_psf1_header(c, d); d->font_data_size = d->bytes_per_glyph * d->num_glyphs; if(d->has_unicode_table) { d->unicode_table_pos = d->headersize + d->font_data_size; if(d->unicode_table_pos >= c->infile->len) { d->has_unicode_table = 0; } } if((d->headersize+d->font_data_size > c->infile->len) || d->bytes_per_glyph<1 || d->glyph_width<1 || d->glyph_width>256 || d->glyph_height<1 || d->glyph_height>256 || d->num_glyphs<1 || d->num_glyphs>2000000) { de_err(c, "Invalid or unsupported PSF file\n"); goto done; } do_glyphs(c, d); done: de_free(c, d); }
static de_uint32 x_dbuf_crc32(dbuf *f, de_int64 pos, de_int64 len) { de_uint32 crc; de_byte *buf; buf = de_malloc(f->c, len); dbuf_read(f, buf, pos, len); crc = de_crc32(buf, len); de_free(f->c, buf); return crc; }
// Put the actual codepont to use in the font->char_array[].codepoint_tmp field. static void fixup_codepoints(deark *c, struct font_render_ctx *fctx) { i64 i; i32 c1; i64 num_uncoded_chars = 0; u8 *used_codepoint_map = NULL; u8 codepoint_already_used; if(!fctx->render_as_unicode) { for(i=0; i<fctx->font->num_chars; i++) { fctx->codepoint_tmp[i] = fctx->font->char_array[i].codepoint_nonunicode; } goto done; } // An array of bits to remember if we've seen a codepoint before (BMP only). // A character with a duplicate codepoint will be moved to another // location, so that it doesn't get painted over the previous one. used_codepoint_map = de_malloc(c, 65536/8); for(i=0; i<fctx->font->num_chars; i++) { if(!is_valid_char(&fctx->font->char_array[i])) continue; c1 = fctx->font->char_array[i].codepoint_unicode; codepoint_already_used = 0; if(c1>=0 && c1<65536) { // Check if we've seen this codepoint before. codepoint_already_used = used_codepoint_map[c1/8] & (1<<(c1%8)); // Remember that we've seen this codepoint. used_codepoint_map[c1/8] |= 1<<(c1%8); } if(codepoint_already_used || c1==DE_CODEPOINT_INVALID) { if(codepoint_already_used) { de_dbg2(c, "moving duplicate codepoint U+%04x at index %d to private use area", (unsigned int)c1, (int)i); } // Move uncoded characters to a Private Use area. // (Supplementary Private Use Area-A = U+F0000 - U+FFFFD) if(DE_CODEPOINT_MOVED + num_uncoded_chars <= DE_CODEPOINT_MOVED_MAX) { fctx->codepoint_tmp[i] = (i32)(DE_CODEPOINT_MOVED + num_uncoded_chars); num_uncoded_chars++; } } else { fctx->codepoint_tmp[i] = c1; } } done: de_free(c, used_codepoint_map); }
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 de_run_fnt(deark *c, de_module_params *mparams) { lctx *d = NULL; d = de_malloc(c, sizeof(lctx)); if(!do_read_header(c, d)) goto done; read_face_name(c, d); do_make_image(c, d); done: de_finfo_destroy(c, d->fi); de_free(c, d); }
// Reduce the string's length to newlen, by deleting the characters after // that point. // 'newlen' is expected to be no larger than the string's current length. void ucstring_truncate(de_ucstring *s, de_int64 newlen) { if(!s) return; if(newlen<0) newlen=0; if(newlen<s->len) s->len = newlen; if(s->tmp_string) { // There's no requirement to free tmp_string here, but it's no // longer needed, and maybe it's nice to have a way to do it. de_free(s->c, s->tmp_string); s->tmp_string = NULL; } }
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); }
// If oparams is not NULL, if must be initialized by the caller. If the data is // decoded, oparams will be used by the submodule, and values may be returned in // it. // flags: // 0 = default behavior (currently: always decode) // 1 = always write to file // 2 = this came from our TIFF-encapsulated format void de_fmtutil_handle_photoshop_rsrc2(deark *c, dbuf *f, i64 pos, i64 len, unsigned int flags, struct de_module_out_params *oparams) { int should_decode; int should_extract; int extract_fmt = 1; // 0=raw, 1=TIFF-wrapped if(flags&0x1) { should_decode = 0; should_extract = 1; } else if(de_get_ext_option_bool(c, "extract8bim", 0)) { should_extract = 1; should_decode = 0; if(flags&0x2) { // Avoid "extracting" in a way that would just recreate the exact same file. extract_fmt = 0; } } else { should_decode = 1; should_extract = 0; } if(should_decode) { de_module_params *mparams = NULL; mparams = de_malloc(c, sizeof(de_module_params)); mparams->in_params.codes = "R"; if(oparams) { // Since mparams->out_params is an embedded struct, not a pointer, // we have to copy oparam's fields to and from it. mparams->out_params = *oparams; // struct copy } de_run_module_by_id_on_slice(c, "psd", mparams, f, pos, len); if(oparams) { *oparams = mparams->out_params; // struct copy } de_free(c, mparams); } if(should_extract && extract_fmt==0) { dbuf_create_file_from_slice(f, pos, len, "8bim", NULL, DE_CREATEFLAG_IS_AUX); } else if(should_extract && extract_fmt==1) { wrap_in_tiff(c, f, pos, len, "Deark extracted 8BIM", 34377, "8bimtiff", DE_CREATEFLAG_IS_AUX); } }
static void destroy_bitstream(deark *c, lctx *d, struct stream_info *si) { if(!si) return; if((si->stream_type==STREAMTYPE_VORBIS || si->stream_type==STREAMTYPE_THEORA) && si->stream_state==0) { do_theora_vorbis_after_headers(c, d, si); } if(si->header_stream) { dbuf_close(si->header_stream); } de_free(c, si); }
int ucstring_strcmp(de_ucstring *s, const char *s2, int encoding) { size_t s2len; char *tmpbuf; int ret; if(!s && !s2) return 0; if(!s || !s2) return 1; s2len = de_strlen(s2); tmpbuf = de_malloc(s->c, s2len+1); ucstring_to_sz(s, tmpbuf, s2len+1, encoding); ret = de_strcmp(tmpbuf, tmpbuf); de_free(s->c, tmpbuf); return ret; }
static void de_run_wad(deark *c, de_module_params *mparams) { lctx *d = NULL; i64 pos; d = de_malloc(c, sizeof(lctx)); pos = 0; if(!do_header(c, d, pos)) goto done; pos += 12; do_directory(c, d, d->dir_pos); done: de_free(c, d); }
static void wri_convert_image_pal4planar(deark *c, i64 fpos, i64 bytes_per_row_per_plane, de_bitmap *img) { const i64 nplanes = 4; i64 i, j, plane; i64 rowspan; u8 *rowbuf = NULL; static const u32 pal16[16] = { 0x000000,0x800000,0x008000,0x808000,0x000080,0x800080,0x008080,0x808080, 0xc0c0c0,0xff0000,0x00ff00,0xffff00,0x0000ff,0xff00ff,0x00ffff,0xffffff }; rowspan = bytes_per_row_per_plane * nplanes; rowbuf = de_malloc(c, rowspan); // The usual order seems to be // row0_plane0x1, row0_plane0x2, row0_plane0x4, row0_plane0x8, // row1_plane0x1, row1_plane0x2, row1_plane0x4, row1_plane0x8, // ... // But I have seen another, and I see no way to detect/support it. for(j=0; j<img->height; j++) { de_read(rowbuf, fpos+j*rowspan, rowspan); for(i=0; i<img->width; i++) { unsigned int palent = 0; u32 clr; for(plane=0; plane<nplanes; plane++) { unsigned int n = 0; i64 idx; idx = bytes_per_row_per_plane*plane + i/8; if(idx<rowspan) n = rowbuf[idx]; if(n & (1<<(7-i%8))) { palent |= (1<<plane); } } clr = DE_MAKE_OPAQUE(pal16[palent]); de_bitmap_setpixel_rgb(img, i, j, clr); } } de_free(c, rowbuf); }
static void de_run_icns(deark *c, de_module_params *mparams) { lctx *d = NULL; d = de_malloc(c, sizeof(lctx)); d->file_size = de_getui32be(4); de_dbg(c, "reported file size: %d\n", (int)d->file_size); if(d->file_size > c->infile->len) d->file_size = c->infile->len; de_dbg(c, "pass 1: recording mask locations\n"); de_run_icns_pass(c, d, 1); de_dbg(c, "pass 2: decoding/extracting icons\n"); de_run_icns_pass(c, d, 2); de_free(c, d); }
// Read (up to) len bytes from f, translate them to characters, and append // them to s. void dbuf_read_to_ucstring(dbuf *f, i64 pos, i64 len, de_ucstring *s, unsigned int conv_flags, int encoding) { u8 *buf = NULL; deark *c = f->c; if(conv_flags & DE_CONVFLAG_STOP_AT_NUL) { i64 foundpos = 0; if(dbuf_search_byte(f, 0x00, pos, len, &foundpos)) { len = foundpos - pos; } } buf = de_malloc(c, len); dbuf_read(f, buf, pos, len); ucstring_append_bytes(s, buf, len, 0, encoding); de_free(c, buf); }
static void de_run_ogg(deark *c, de_module_params *mparams) { lctx *d = NULL; d = de_malloc(c, sizeof(lctx)); if(de_havemodcode(c, mparams, 'C')) { do_vorbis_comment_block(c, d, c->infile, 0); goto done; } run_ogg_internal(c, d); done: if(d && d->streamtable) { destroy_streamtable(c, d); } de_free(c, d); }
static void de_run_ebml(deark *c, de_module_params *mparams) { lctx *d = NULL; i64 pos; d = de_malloc(c, sizeof(lctx)); if(de_get_ext_option(c, "ebml:encodedid")) { d->show_encoded_id = 1; } pos = 0; do_element_sequence(c, d, pos, c->infile->len); if(d) { destroy_attachment_data(c, d); de_free(c, d); } }
static void uncompress_pixels(deark *c, lctx *d, dbuf *unc_pixels, i64 pos1, i64 len) { i64 bytes_consumed; i64 pos; i64 ypos; i64 repeat_count; i64 k; i64 plane; dbuf *unc_line = NULL; d->pattern_buf = de_malloc(c, d->patlen); unc_line = dbuf_create_membuf(c, d->rowspan_total, 0); pos = pos1; ypos = 0; while(1) { if(ypos >= d->h) break; repeat_count = 1; dbuf_empty(unc_line); for(plane=0; plane<d->nplanes; plane++) { uncompress_line(c, d, unc_line, pos, ypos, &bytes_consumed, &repeat_count); pos+=bytes_consumed; if(bytes_consumed<1) goto done1; } for(k=0; k<repeat_count; k++) { if(ypos >= d->h) break; dbuf_copy(unc_line, 0, d->rowspan_total, unc_pixels); ypos++; } } done1: dbuf_close(unc_line); de_free(c, d->pattern_buf); d->pattern_buf = NULL; }
static const char *ucstring_get_printable_sz_internal(de_ucstring *s, int has_max, de_int64 max_chars) { de_int64 allocsize; if(!s) return "(null)"; if(s->tmp_string) de_free(s->c, s->tmp_string); if(has_max) allocsize = max_chars * 4 + 1; else allocsize = s->len * 4 + 1; s->tmp_string = de_malloc(s->c, allocsize); ucstring_to_printable_sz_internal(s, s->tmp_string, (size_t)allocsize, has_max, max_chars); return s->tmp_string; }