From 64b9e9f841491564507bfbc5c7201988f09ff772 Mon Sep 17 00:00:00 2001 From: Jason Summers Date: Sat, 27 Mar 2021 15:14:22 -0400 Subject: [PATCH] zip: Initial support for OS/2 extended attribs. --- modules/fat.c | 128 +++++++++++++++++++++++++++++++++++++++++++++------------- modules/zip.c | 77 +++++++++++++++++++++++++---------- 2 files changed, 156 insertions(+), 49 deletions(-) diff --git a/modules/fat.c b/modules/fat.c index 2bff8b57..f1c96c93 100644 --- a/modules/fat.c +++ b/modules/fat.c @@ -1243,6 +1243,8 @@ static const char *eadata_get_data_type_name(UI t) { const char *name = NULL; switch(t) { + case 0xffde: name ="multi-val/single-type"; break; + case 0xffdf: name ="multi-val/multi-type"; break; case 0xfffe: name ="binary"; break; case 0xfffd: name ="text"; break; case 0xfff9: name ="icon"; break; @@ -1251,7 +1253,7 @@ static const char *eadata_get_data_type_name(UI t) return name?name:"?"; } -static int eadata_extract_icon(deark *c, struct eadata_ctx *d, struct easector_ctx *md, +static int eadata_extract_icon(deark *c, struct eadata_ctx *d, i64 pos1, i64 nbytes_avail) { i64 ipos, ilen; @@ -1268,6 +1270,48 @@ done: return retval; } +// FEA2 structure, starting at the 'fEA' field (1 byte before the name-length byte). +static int eadata_do_attribute(deark *c, struct eadata_ctx *d, i64 pos1, i64 maxlen, + de_ucstring *tmps, i64 *pbytes_consumed) +{ + i64 namelen; + i64 attr_dpos; + i64 attr_dlen; + UI attr_dtype; + int handled = 0; + i64 pos = pos1; + int retval = 0; + + pos++; // fEA + namelen = (i64)de_getbyte_p(&pos); + + attr_dlen = (i64)de_getu16le_p(&pos); + ucstring_empty(tmps); + dbuf_read_to_ucstring(c->infile, pos, namelen, tmps, 0, DE_ENCODING_ASCII); + de_dbg(c, "name: \"%s\"", ucstring_getpsz_d(tmps)); + pos += namelen + 1; + attr_dpos = pos; + de_dbg(c, "outer data len: %"I64_FMT, attr_dlen); + if(attr_dpos + attr_dlen > pos1+maxlen) goto done; + + attr_dtype = (UI)de_getu16le_p(&pos); + de_dbg(c, "data type: 0x%04x (%s)", attr_dtype, eadata_get_data_type_name(attr_dtype)); + + if(attr_dtype==0xfff9) { + handled = eadata_extract_icon(c, d, attr_dpos+2, attr_dlen-2); + } + + if(!handled) { + de_dbg_hexdump(c, c->infile, attr_dpos+2, attr_dlen-2, 256, NULL, 0x1); + } + + pos = attr_dpos + attr_dlen; + *pbytes_consumed = pos - pos1; + retval = 1; +done: + return retval; +} + // Sets md->ea_data_len. static void eadata_do_ea_data(deark *c, struct eadata_ctx *d, struct easector_ctx *md, i64 pos1) @@ -1289,40 +1333,64 @@ static void eadata_do_ea_data(deark *c, struct eadata_ctx *d, struct easector_ct s = ucstring_create(c); while(pos < endpos-4) { - i64 namelen; - i64 attr_dpos; - i64 attr_dlen; - UI attr_dtype; - int handled = 0; + int ret; + i64 bytes_consumed = 0; de_dbg(c, "attribute at %"I64_FMT, pos); de_dbg_indent(c, 1); - pos++; // ? - namelen = (i64)de_getbyte_p(&pos); - - attr_dlen = (i64)de_getu16le_p(&pos); - ucstring_empty(s); - dbuf_read_to_ucstring(c->infile, pos, namelen, s, 0, DE_ENCODING_ASCII); - de_dbg(c, "name: \"%s\"", ucstring_getpsz_d(s)); - pos += namelen + 1; - attr_dpos = pos; - de_dbg(c, "outer data len: %"I64_FMT, attr_dlen); - attr_dtype = (UI)de_getu16le_p(&pos); - de_dbg(c, "data type: 0x%04x (%s)", attr_dtype, eadata_get_data_type_name(attr_dtype)); - - if(attr_dtype==0xfff9) { - handled = eadata_extract_icon(c, d, md, attr_dpos+2, attr_dlen-2); - } + ret = eadata_do_attribute(c, d, pos, endpos-pos, s, &bytes_consumed); + de_dbg_indent(c, -1); + if(!ret || bytes_consumed<1) goto done; + pos += bytes_consumed; + } - if(!handled) { - de_dbg_hexdump(c, c->infile, attr_dpos+2, attr_dlen-2, 256, NULL, 0x1); - } +done: + ucstring_destroy(s); + de_dbg_indent_restore(c, saved_indent_level); +} + +static void eadata_do_FEA2LIST(deark *c, struct eadata_ctx *d) +{ + i64 fea2list_len; + i64 pos1 = 0; + i64 pos = pos1; + i64 endpos; + de_ucstring *tmps = NULL; + int saved_indent_level; + + de_dbg_indent_save(c, &saved_indent_level); + tmps = ucstring_create(c); + + de_dbg(c, "FEA2LIST at %"I64_FMT, pos1); + de_dbg_indent(c, 1); - pos = attr_dpos + attr_dlen; + fea2list_len = de_getu32le_p(&pos); + endpos = pos1 + fea2list_len; + + de_dbg(c, "list len: %"I64_FMT, fea2list_len); + while(1) { + int ret; + i64 bytes_consumed = 0; + i64 offset_to_next_attr; + i64 attr_pos; + + if(pos >= endpos) goto done; + + attr_pos = pos; + de_dbg(c, "attribute at %"I64_FMT, attr_pos); + de_dbg_indent(c, 1); + offset_to_next_attr = de_getu32le_p(&pos); + de_dbg(c, "offset to next attr: %"I64_FMT, offset_to_next_attr); + + ret = eadata_do_attribute(c, d, pos, endpos-pos, tmps, &bytes_consumed); + if(!ret || bytes_consumed<1) goto done; + if(offset_to_next_attr==0) goto done; + pos = attr_pos + offset_to_next_attr; de_dbg_indent(c, -1); } - ucstring_destroy(s); +done: + ucstring_destroy(tmps); de_dbg_indent_restore(c, saved_indent_level); } @@ -1429,7 +1497,11 @@ static void de_run_eadata(deark *c, de_module_params *mparams) struct eadata_ctx *d = de_malloc(c, sizeof(struct eadata_ctx)); - if(mparams && (mparams->in_params.flags & 0x1)) { + if(de_havemodcode(c, mparams, 'L')) { + d->createflags_for_icons = DE_CREATEFLAG_IS_AUX; + eadata_do_FEA2LIST(c, d); + } + else if(mparams && (mparams->in_params.flags & 0x1)) { // We're being used by another module, to handle a specific ea_id. ea_id = (UI)mparams->in_params.uint1; if(ea_id==0) goto done; diff --git a/modules/zip.c b/modules/zip.c index 7bc48cb5..4e002508 100644 --- a/modules/zip.c +++ b/modules/zip.c @@ -292,13 +292,14 @@ done: return retval; } -// A variation of do_decompress_member(). +// A variation of do_decompress_member() - +// works for Finder attribute data, and OS/2 extended attributes. // Only call this if the compression method is supported -- Call // is_compression_method_supported() first. // outf is assumed to be a membuf. -static int do_decompress_finder_attrib_data(deark *c, lctx *d, +static int do_decompress_attrib_data(deark *c, lctx *d, i64 dpos, i64 dlen, dbuf *outf, i64 uncmprsize, u32 crc_reported, - int cmpr_meth, const struct cmpr_meth_info *cmi) + int cmpr_meth, const struct cmpr_meth_info *cmi, const char *name) { struct de_dfilter_in_params dcmpri; struct de_dfilter_out_params dcmpro; @@ -323,7 +324,7 @@ static int do_decompress_finder_attrib_data(deark *c, lctx *d, de_crcobj_reset(d->crco); de_crcobj_addslice(d->crco, outf, 0, outf->len); crc_calculated = de_crcobj_getval(d->crco); - de_dbg(c, "finder attr. data crc (calculated): 0x%08x", (UI)crc_calculated); + de_dbg(c, "%s crc (calculated): 0x%08x", name, (UI)crc_calculated); if(crc_calculated != crc_reported) goto done; } @@ -641,26 +642,60 @@ static void ef_os2(deark *c, lctx *d, struct extra_item_info_struct *eii) { i64 pos = eii->dpos; i64 endpos; - i64 unc_size; - i64 cmpr_type; - i64 crc; + i64 ulen; + i64 cmpr_attr_size; + int cmpr_meth; + u32 crc_reported; + const struct cmpr_meth_info *cmi = NULL; + const char *name = "OS/2 ext. attr. data"; + dbuf *attr_data = NULL; + de_module_params *mparams = NULL; + int ret; endpos = pos+eii->dlen; - if(pos+4>endpos) return; - unc_size = de_getu32le_p(&pos); - de_dbg(c, "uncmpr ext attr data size: %d", (int)unc_size); - if(eii->is_central) return; + if(pos+4>endpos) goto done; + ulen = de_getu32le_p(&pos); + de_dbg(c, "uncmpr ext attr data size: %"I64_FMT, ulen); + if(eii->is_central) goto done; - if(pos+2>endpos) return; - cmpr_type = de_getu16le_p(&pos); - de_dbg(c, "ext attr cmpr method: %d", (int)cmpr_type); + if(pos+2>endpos) goto done; + cmpr_meth = (int)de_getu16le_p(&pos); + de_dbg(c, "ext attr cmpr method: %d", cmpr_meth); - if(pos+4>endpos) return; - crc = de_getu32le_p(&pos); - de_dbg(c, "ext attr crc: 0x%08x", (unsigned int)crc); + if(pos+4>endpos) goto done; + crc_reported = (u32)de_getu32le_p(&pos); + de_dbg(c, "ext attr crc (reported): 0x%08x", (unsigned int)crc_reported); - de_dbg(c, "cmpr ext attr data at %"I64_FMT", len=%d", pos, (int)(endpos-pos)); - // TODO: Uncompress and decode OS/2 extended attribute structure (FEA2LIST) + cmpr_attr_size = endpos-pos; + de_dbg(c, "cmpr ext attr data at %"I64_FMT", len=%"I64_FMT, pos, cmpr_attr_size); + if(pos + cmpr_attr_size > endpos) goto done; + + cmi = get_cmpr_meth_info(cmpr_meth); + if(cmpr_meth==6 || !is_compression_method_supported(d, cmi)) { + de_warn(c, "%s: Unsupported compression method: %d (%s)", + name, cmpr_meth, (cmi ? cmi->name : "?")); + goto done; + } + + attr_data = dbuf_create_membuf(c, ulen, 0x1); + ret = do_decompress_attrib_data(c, d, pos, cmpr_attr_size, + attr_data, ulen, crc_reported, cmpr_meth, cmi, name); + if(!ret) { + de_warn(c, "Failed to decompress %s", name); + goto done; + } + + // attr_data contains an OS/2 extended attribute structure (FEA2LIST) + mparams = de_malloc(c, sizeof(de_module_params)); + mparams->in_params.codes = "L"; + de_dbg(c, "decoding OS/2 ext. attribs., unc. len=%"I64_FMT, attr_data->len); + de_dbg_indent(c, 1); + de_run_module_by_id_on_slice(c, "ea_data", mparams, attr_data, 0, attr_data->len); + de_dbg_indent(c, -1); + +done: + dbuf_close(attr_data); + de_free(c, mparams); } // Extra field 0x2705 (ZipIt Macintosh 1.3.5+) @@ -774,8 +809,8 @@ static void ef_infozipmac(deark *c, lctx *d, struct extra_item_info_struct *eii) // Decompress and decode the Finder attribute data attr_data = dbuf_create_membuf(c, ulen, 0x1); - ret = do_decompress_finder_attrib_data(c, d, pos, cmpr_attr_size, - attr_data, ulen, crc_reported, cmpr_meth, cmi); + ret = do_decompress_attrib_data(c, d, pos, cmpr_attr_size, + attr_data, ulen, crc_reported, cmpr_meth, cmi, "finder attr. data"); if(!ret) { de_warn(c, "Failed to decompress finder attribute data"); goto done; -- 2.11.4.GIT