static void handler_attachedfile_end(deark *c, lctx *d) { de_finfo *fi = NULL; if(!d->attachmentctx) goto done; if(d->attachmentctx->data_pos==0) goto done; fi = de_finfo_create(c); // TODO: We could do a better job of constructing filenames in various // situations. if(d->attachmentctx->filename && (d->attachmentctx->filename->len > 0) && c->filenames_from_file) { de_finfo_set_name_from_ucstring(c, fi, d->attachmentctx->filename, 0); } else { de_finfo_set_name_from_sz(c, fi, "bin", 0, DE_ENCODING_UTF8); } dbuf_create_file_from_slice(c->infile, d->attachmentctx->data_pos, d->attachmentctx->data_len, NULL, fi, DE_CREATEFLAG_IS_AUX); done: de_finfo_destroy(c, fi); destroy_attachment_data(c, d); }
static void do_extract_png_or_jp2(deark *c, lctx *d, struct page_ctx *pg) { de_byte buf[8]; de_finfo *fi = NULL; de_dbg(c, "Trying to extract file at %d\n", (int)pg->image_pos); // Detect the format de_read(buf, pg->image_pos, sizeof(buf)); fi = de_finfo_create(c); de_finfo_set_name_from_sz(c, fi, pg->filename_token, DE_ENCODING_ASCII); if(buf[4]=='j' && buf[5]=='P') { dbuf_create_file_from_slice(c->infile, pg->image_pos, pg->image_len, "jp2", fi, 0); } else if(buf[0]==0x89 && buf[1]==0x50) { dbuf_create_file_from_slice(c->infile, pg->image_pos, pg->image_len, "png", fi, 0); } else { de_err(c, "(Image #%d) Unidentified file format\n", pg->image_num); } de_finfo_destroy(c, fi); }
static void do_extract_file(deark *c, lctx *d, de_int64 dir_pos, de_byte filetype_c64s, de_byte filetype) { de_int64 load_addr; de_int64 end_addr; de_int64 offset; dbuf *f = NULL; de_int64 payload_size; // = file_size-2 de_ucstring *fname = NULL; de_int64 fname_len; de_int64 i; de_int64 fnpos; de_finfo *fi = NULL; load_addr = de_getui16le(dir_pos+2); end_addr = de_getui16le(dir_pos+4); offset = de_getui32le(dir_pos+8); de_dbg(c, "load_addr=%d end_addr=%d offset=%d\n", (int)load_addr, (int)end_addr, (int)offset); // File name at pos+16 fnpos = dir_pos+16; // Find the length of the (space-padded) filename. fname_len = 0; for(i=15; i>=0; i--) { if(de_getbyte(fnpos+i)!=' ') { fname_len = i+1; break; } } de_dbg2(c, "filename length: %d\n", (int)fname_len); fname = ucstring_create(c); dbuf_read_to_ucstring(c->infile, fnpos, fname_len, fname, 0, DE_ENCODING_PETSCII); de_dbg(c, "filename: \"%s\"\n", ucstring_get_printable_sz(fname)); ucstring_append_sz(fname, ".prg", DE_ENCODING_ASCII); fi = de_finfo_create(c); de_finfo_set_name_from_ucstring(c, fi, fname); fi->original_filename_flag = 1; payload_size = end_addr - load_addr; if(payload_size < 0) { // TODO: Try to support files that don't have end_addr set properly. de_err(c, "This type of T64 file is not supported.\n"); goto done; } f = dbuf_create_output_file(c, NULL, fi, 0); dbuf_copy(c->infile, dir_pos+2, 2, f); dbuf_copy(c->infile, offset, payload_size, f); done: dbuf_close(f); de_finfo_destroy(c, fi); ucstring_destroy(fname); }
static int do_gem_img(deark *c, lctx *d) { dbuf *unc_pixels = NULL; de_bitmap *img = NULL; de_finfo *fi = NULL; int is_color = 0; i64 k; if(d->header_size_in_words==9 && (d->nplanes==3 || d->nplanes==4)) { i64 x; x = de_getu16be(8*2); if(x==0) { is_color = 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, is_color?3:1); fi = de_finfo_create(c); set_density(c, d, fi); if(d->nplanes==1) { de_convert_image_bilevel(unc_pixels, 0, d->rowspan_per_plane, img, DE_CVTF_WHITEISZERO); } else if(is_color && d->nplanes==3) { for(k=0; k<8; k++) { d->pal[k] = pal3bit[k]; } read_paletted_image(c, d, unc_pixels, img); } else if(is_color && d->nplanes==4) { for(k=0; k<16; k++) { d->pal[k] = pal4bit[k]; } read_paletted_image(c, d, unc_pixels, img); } else { de_make_grayscale_palette(d->pal, ((i64)1)<<((unsigned int)d->nplanes), 1); read_paletted_image(c, d, unc_pixels, img); } de_bitmap_write_to_file_finfo(img, fi, 0); de_bitmap_destroy(img); de_finfo_destroy(c, fi); dbuf_close(unc_pixels); return 1; }
static void do_lump_extract(deark *c, lctx *d, i64 dpos, i64 dlen, struct de_stringreaderdata *srd) { de_finfo *fi = NULL; // 0-length lumps are assumed to be special "virtual" lumps. if(dlen<=0) return; if(dpos<0 || dpos>=c->infile->len || dpos+dlen>c->infile->len) return; fi = de_finfo_create(c); de_finfo_set_name_from_ucstring(c, fi, srd->str, 0); fi->original_filename_flag = 1; dbuf_create_file_from_slice(c->infile, dpos, dlen, NULL, fi, 0); de_finfo_destroy(c, fi); }
static void handler_iccp(deark *c, lctx *d, struct handler_params *hp) { u8 cmpr_type; dbuf *f = NULL; struct de_stringreaderdata *prof_name_srd = NULL; de_finfo *fi = NULL; char prof_name2[100]; size_t prof_name2_strlen; i64 pos = hp->dpos; prof_name_srd = dbuf_read_string(c->infile, pos, 80, 80, DE_CONVFLAG_STOP_AT_NUL, DE_ENCODING_LATIN1); if(!prof_name_srd->found_nul) goto done; de_dbg(c, "profile name: \"%s\"", ucstring_getpsz_d(prof_name_srd->str)); pos += prof_name_srd->bytes_consumed; // Our working copy, to use as part of the filename. de_strlcpy(prof_name2, prof_name_srd->sz, sizeof(prof_name2)); if(!de_strcasecmp(prof_name2, "icc") || !de_strcasecmp(prof_name2, "icc profile")) { prof_name2[0] = '\0'; // Ignore generic name. } prof_name2_strlen = de_strlen(prof_name2); if(prof_name2_strlen>=5) { if(de_sz_has_ext(prof_name2, "icc")) { // If the name already ends in ".icc", chop it off so that we don't end // up with a double ".icc.icc" file extension. prof_name2[prof_name2_strlen-4] = '\0'; } } cmpr_type = de_getbyte_p(&pos); if(cmpr_type!=0) return; fi = de_finfo_create(c); if(c->filenames_from_file && prof_name2[0]) de_finfo_set_name_from_sz(c, fi, prof_name2, 0, DE_ENCODING_LATIN1); f = dbuf_create_output_file(c, "icc", fi, DE_CREATEFLAG_IS_AUX); de_decompress_deflate(c->infile, pos, hp->dlen - pos, f, 0, NULL, d->is_CgBI ? 0 : DE_DEFLATEFLAG_ISZLIB); done: dbuf_close(f); de_finfo_destroy(c, fi); de_destroy_stringreaderdata(c, prof_name_srd); }
static void read_face_name(deark *c, lctx *d) { char buf[50]; char buf2[50]; if(d->dfFace<1) return; if(!c->filenames_from_file) return; // The facename is terminated with a NUL byte. // There seems to be no defined limit to its length, but Windows font face // names traditionally have to be quite short. dbuf_read_sz(c->infile, d->dfFace, buf, sizeof(buf)); de_snprintf(buf2, sizeof(buf2), "%s-%d", buf, (int)d->dfPoints); d->fi = de_finfo_create(c); de_finfo_set_name_from_sz(c, d->fi, buf2, DE_ENCODING_ASCII); }
static void do_decode_image(deark *c, lctx *d, struct tgaimginfo *imginfo, dbuf *unc_pixels, const char *token, unsigned int createflags) { de_finfo *fi = NULL; fi = de_finfo_create(c); if(token) { de_finfo_set_name_from_sz(c, fi, token, 0, DE_ENCODING_LATIN1); } if(d->mod_time.is_valid) { fi->image_mod_time = d->mod_time; } do_decode_image_default(c, d, imginfo, unc_pixels, fi, createflags); de_finfo_destroy(c, fi); }
static void extract_unknown_ole_obj(deark *c, lctx *d, i64 pos, i64 len, struct de_stringreaderdata *srd_typename) { de_finfo *fi = NULL; de_ucstring *s = NULL; fi = de_finfo_create(c); s = ucstring_create(c); ucstring_append_sz(s, "oleobj", DE_ENCODING_LATIN1); if(ucstring_isnonempty(srd_typename->str)) { ucstring_append_sz(s, ".", DE_ENCODING_LATIN1); ucstring_append_ucstring(s, srd_typename->str); } de_finfo_set_name_from_ucstring(c, fi, s, 0); dbuf_create_file_from_slice(c->infile, pos, len, "bin", fi, 0); ucstring_destroy(s); de_finfo_destroy(c, fi); }
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 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 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); }
// 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; }
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; }
static void de_run_rpm(deark *c, de_module_params *mparams) { lctx *d = NULL; i64 pos; u8 buf[8]; const char *ext; i64 section_size = 0; de_finfo *fi = NULL; char filename[128]; d = de_malloc(c, sizeof(lctx)); if(!do_lead_section(c, d)) { goto done; } pos = 96; if(!do_header_structure(c, d, 1, pos, §ion_size)) { goto done; } pos += section_size; // Header structures are 8-byte aligned. The first one always starts at // offset 96, so we don't have to worry about it. But we need to make // sure the second one is aligned. pos = ((pos + 7)/8)*8; if(!do_header_structure(c, d, 0, pos, §ion_size)) { goto done; } pos += section_size; de_dbg(c, "data pos: %d", (int)pos); if(pos > c->infile->len) goto done; // There is usually a tag that indicates the compression format, but we // primarily figure out the format by sniffing its magic number, on the // theory that that's more reliable. // TODO: I think it's also theoretically possible that it could use an archive // format other than cpio. de_read(buf, pos, 8); if(buf[0]==0x1f && buf[1]==0x8b) { ext = "cpio.gz"; } else if(buf[0]==0x42 && buf[1]==0x5a && buf[2]==0x68) { ext = "cpio.bz2"; } else if(buf[0]==0xfd && buf[1]==0x37 && buf[2]==0x7a) { ext = "cpio.xz"; } else if(d->cmpr_type==DE_RPM_CMPR_LZMA || buf[0]==0x5d) { ext = "cpio.lzma"; } else { de_warn(c, "Unidentified compression or archive format"); ext = "cpio.bin"; } if(d->name_srd && c->filenames_from_file) { const char *version2 = "x"; const char *release2 = "x"; if(d->version_srd) version2 = d->version_srd->sz; if(d->release_srd) release2 = d->release_srd->sz; fi = de_finfo_create(c); de_snprintf(filename, sizeof(filename), "%s-%s.%s", d->name_srd->sz, version2, release2); de_finfo_set_name_from_sz(c, fi, filename, 0, DE_ENCODING_ASCII); } dbuf_create_file_from_slice(c->infile, pos, c->infile->len - pos, ext, fi, 0); done: de_finfo_destroy(c, fi); if(d) { de_destroy_stringreaderdata(c, d->name_srd); de_destroy_stringreaderdata(c, d->release_srd); de_destroy_stringreaderdata(c, d->version_srd); de_free(c, d); } }