i64 dbuf_getint_ext(dbuf *f, i64 pos, unsigned int nbytes, int is_le, int is_signed) { if(is_signed) { // TODO: Extend this to any number of bytes, 1-8. switch(nbytes) { case 1: return (i64)(signed char)dbuf_getbyte(f, pos); break; case 2: return dbuf_geti16x(f, pos, is_le); break; case 4: return dbuf_geti32x(f, pos, is_le); break; case 8: return dbuf_geti64x(f, pos, is_le); break; default: return dbuf_getint_ext_x(f, pos, nbytes, is_le); } } else { switch(nbytes) { case 1: return (i64)dbuf_getbyte(f, pos); break; case 2: return dbuf_getu16x(f, pos, is_le); break; case 4: return dbuf_getu32x(f, pos, is_le); break; case 8: return dbuf_geti64x(f, pos, is_le); break; default: return dbuf_getuint_ext_x(f, pos, nbytes, is_le); } } return 0; }
// RLE algorithm occasionally called "RLE90". Variants of this are used by // BinHex, ARC, StuffIt, and others. int de_fmtutil_decompress_rle90(dbuf *inf, i64 pos1, i64 len, dbuf *outf, unsigned int has_maxlen, i64 max_out_len, unsigned int flags) { i64 pos = pos1; u8 b; u8 lastbyte = 0x00; u8 countcode; i64 count; i64 nbytes_written = 0; while(pos < pos1+len) { if(has_maxlen && nbytes_written>=max_out_len) break; b = dbuf_getbyte(inf, pos); pos++; if(b!=0x90) { dbuf_writebyte(outf, b); nbytes_written++; lastbyte = b; continue; } // b = 0x90, which is a special code. countcode = dbuf_getbyte(inf, pos); pos++; if(countcode==0x00) { // Not RLE, just an escaped 0x90 byte. dbuf_writebyte(outf, 0x90); nbytes_written++; // Here there is an inconsistency between different RLE90 // implementations. // Some of them can compress a run of 0x90 bytes, because the byte // to repeat is defined to be the "last byte emitted". // Others do not allow this. If the "0x90 0x00 0x90 0xNN" sequence // (with 0xNN>0) is encountered, they may (by accident?) repeat the // last non-0x90 byte emitted, or do something else. // Hopefully, valid files in such formats never contain this byte // sequence, so it shouldn't matter what we do here. But maybe not. // We might need to add an option to do something else. lastbyte = 0x90; continue; } // RLE. We already emitted one byte (because the byte to repeat // comes before the repeat count), so write countcode-1 bytes. count = (i64)(countcode-1); if(has_maxlen && (nbytes_written+count > max_out_len)) { count = max_out_len - nbytes_written; } dbuf_write_run(outf, lastbyte, count); nbytes_written += count; } return 1; }
// Caller allocates sdd. It does not need to be initialized. // flags: 0x1 = Print a debug message if signature is found. int de_fmtutil_detect_SAUCE(deark *c, dbuf *f, struct de_SAUCE_detection_data *sdd, unsigned int flags) { de_zeromem(sdd, sizeof(struct de_SAUCE_detection_data)); if(f->len<128) return 0; if(dbuf_memcmp(f, f->len-128, "SAUCE00", 7)) return 0; if(flags & 0x1) { de_dbg(c, "SAUCE metadata, signature at %"I64_FMT, f->len-128); } sdd->has_SAUCE = 1; sdd->data_type = dbuf_getbyte(f, f->len-128+94); sdd->file_type = dbuf_getbyte(f, f->len-128+95); return (int)sdd->has_SAUCE; }
static int read_dflen(deark *c, dbuf *f, de_int64 pos, de_int64 *dflen, de_int64 *bytes_consumed) { de_int64 x; x = dbuf_getui16be(f, pos); if(x<32768) { // "Standard DataSet" format *dflen = x; *bytes_consumed = 2; } else { // "Extended DataSet" format de_int64 length_of_length; de_int64 i; length_of_length = x - 32768; *dflen = 0; *bytes_consumed = 2 + length_of_length; for(i=0; i<length_of_length; i++) { *dflen = ((*dflen)<<8) | dbuf_getbyte(f, pos+2+i); // IPTC seems to support fields up to (2^262136)-1 bytes. // We arbitrarily limit it (2^48)-1. if((*dflen)>=0x1000000000000LL) { de_err(c, "Bad or unsupported IPTC data field length\n"); return 0; } } } return 1; }
u8 dbuf_getbyte_p(dbuf *f, i64 *ppos) { u8 b; b = dbuf_getbyte(f, *ppos); (*ppos)++; return b; }
i64 dbuf_geti8(dbuf *f, i64 pos) { u8 b; b = dbuf_getbyte(f, pos); return de_geti8_direct(&b); }
static void do_decode_24bit(deark *c, lctx *d, struct page_ctx *pg) { dbuf *unc_pixels = NULL; struct deark_bitmap *img = NULL; de_int64 i, j; de_byte cr, cg, cb, ca; de_int64 w, h; de_int64 skip; w = pg->type_info->width; h = pg->type_info->height; // TODO: Try to support uncompressed 24-bit images, assuming they exist. // Apparently, some 'it32' icons begin with four extra 0x00 bytes. // Skip over the first four bytes if they are 0x00. // (I don't know the reason for these bytes, but this is the same // logic libicns uses.) skip = 0; if(pg->code4cc.id==0x69743332) { // 'it32' (128x128) if(!dbuf_memcmp(c->infile, pg->image_pos, "\0\0\0\0", 4)) { skip = 4; } } unc_pixels = dbuf_create_membuf(c, w*h*3, 1); do_uncompress_24(c, d, pg, unc_pixels, skip); img = de_bitmap_create(c, w, h, 4); for(j=0; j<pg->type_info->height; j++) { for(i=0; i<pg->type_info->width; i++) { cr = dbuf_getbyte(unc_pixels, j*w + i); cg = dbuf_getbyte(unc_pixels, (h+j)*w + i); cb = dbuf_getbyte(unc_pixels, (2*h+j)*w + i); if(pg->mask_pos) ca = de_getbyte(pg->mask_pos + j*w + i); else ca = 0xff; de_bitmap_setpixel_rgba(img, i, j, DE_MAKE_RGBA(cr,cg,cb,ca)); } } de_bitmap_write_to_file(img, pg->filename_token, 0); de_bitmap_destroy(img); if(unc_pixels) dbuf_close(unc_pixels); }
// A 16-bit variant of de_fmtutil_uncompress_packbits(). int de_fmtutil_uncompress_packbits16(dbuf *f, i64 pos1, i64 len, dbuf *unc_pixels, i64 *cmpr_bytes_consumed) { i64 pos; u8 b, b1, b2; i64 k; i64 count; i64 endpos; pos = pos1; endpos = pos1+len; while(1) { if(unc_pixels->has_len_limit && unc_pixels->len>=unc_pixels->len_limit) { break; // Decompressed the requested amount of dst data. } if(pos>=endpos) { break; // Reached the end of source data } b = dbuf_getbyte(f, pos++); if(b>128) { // A compressed run count = 257 - (i64)b; b1 = dbuf_getbyte(f, pos++); b2 = dbuf_getbyte(f, pos++); for(k=0; k<count; k++) { dbuf_writebyte(unc_pixels, b1); dbuf_writebyte(unc_pixels, b2); } } else if(b<128) { // An uncompressed run count = 1 + (i64)b; dbuf_copy(f, pos, count*2, unc_pixels); pos += count*2; } // Else b==128. No-op. } if(cmpr_bytes_consumed) *cmpr_bytes_consumed = pos - pos1; return 1; }
// Returns 0 on failure (currently impossible). int de_fmtutil_uncompress_packbits(dbuf *f, i64 pos1, i64 len, dbuf *unc_pixels, i64 *cmpr_bytes_consumed) { i64 pos; u8 b, b2; i64 count; i64 endpos; pos = pos1; endpos = pos1+len; while(1) { if(unc_pixels->has_len_limit && unc_pixels->len>=unc_pixels->len_limit) { break; // Decompressed the requested amount of dst data. } if(pos>=endpos) { break; // Reached the end of source data } b = dbuf_getbyte(f, pos++); if(b>128) { // A compressed run count = 257 - (i64)b; b2 = dbuf_getbyte(f, pos++); dbuf_write_run(unc_pixels, b2, count); } else if(b<128) { // An uncompressed run count = 1 + (i64)b; dbuf_copy(f, pos, count, unc_pixels); pos += count; } // Else b==128. No-op. // TODO: Some (but not most) ILBM specs say that code 128 is used to // mark the end of compressed data, so maybe there should be options to // tell us what to do when code 128 is encountered. } if(cmpr_bytes_consumed) *cmpr_bytes_consumed = pos - pos1; return 1; }
static void do_decode_image_default(deark *c, lctx *d, struct tgaimginfo *imginfo, dbuf *unc_pixels, de_finfo *fi, unsigned int createflags) { de_bitmap *img = NULL; i64 i, j; u8 b; u32 clr; u8 a; i64 rowspan; int output_bypp; unsigned int getrgbflags; i64 interleave_stride; i64 interleave_pass; i64 cur_rownum; // 0-based, does not account for bottom-up orientation if(d->pixel_depth==1) { de_warn(c, "1-bit TGA images are not portable, and may not be decoded correctly"); rowspan = (imginfo->width+7)/8; } else { rowspan = imginfo->width*d->bytes_per_pixel; } if(d->color_type==TGA_CLRTYPE_GRAYSCALE || d->pixel_depth==1) output_bypp=1; else output_bypp=3; if(d->has_alpha_channel) output_bypp++; if(d->file_format==FMT_VST) getrgbflags = 0; else getrgbflags = DE_GETRGBFLAG_BGR; img = de_bitmap_create(c, imginfo->width, imginfo->height, output_bypp); switch(d->interleave_mode) { case 1: interleave_stride = 2; break; case 2: interleave_stride = 4; break; default: interleave_stride = 1; } cur_rownum = 0; interleave_pass = 0; for(j=0; j<imginfo->height; j++) { i64 j_adj; if(d->top_down) j_adj = cur_rownum; else j_adj = imginfo->height-1-cur_rownum; // Update the row number for next time cur_rownum += interleave_stride; if(cur_rownum >= imginfo->height) { // Went past the end of the image; move back to near the start. interleave_pass++; cur_rownum = interleave_pass; } for(i=0; i<imginfo->width; i++) { i64 i_adj; if(d->right_to_left) i_adj = imginfo->width-1-i; else i_adj = i; if(d->pixel_depth==1) { de_convert_row_bilevel(unc_pixels, j*rowspan, img, j_adj, 0); } else if(d->color_type==TGA_CLRTYPE_TRUECOLOR && (d->pixel_depth==15 || d->pixel_depth==16)) { clr = (u32)dbuf_getu16le(unc_pixels, j*rowspan + i*d->bytes_per_pixel); clr = de_rgb555_to_888(clr); de_bitmap_setpixel_rgb(img, i_adj, j_adj, clr); } else if(d->color_type==TGA_CLRTYPE_TRUECOLOR) { clr = dbuf_getRGB(unc_pixels, j*rowspan + i*d->bytes_per_pixel, getrgbflags); if(d->has_alpha_channel) { a = dbuf_getbyte(unc_pixels, j*rowspan + i*d->bytes_per_pixel+3); de_bitmap_setpixel_rgba(img, i_adj, j_adj, DE_SET_ALPHA(clr, a)); } else { de_bitmap_setpixel_rgb(img, i_adj, j_adj, clr); } } else if(d->color_type==TGA_CLRTYPE_GRAYSCALE) { b = dbuf_getbyte(unc_pixels, j*rowspan + i*d->bytes_per_pixel); de_bitmap_setpixel_gray(img, i_adj, j_adj, b); } else if(d->color_type==TGA_CLRTYPE_PALETTE) { b = dbuf_getbyte(unc_pixels, j*rowspan + i*d->bytes_per_pixel); de_bitmap_setpixel_rgb(img, i_adj, j_adj, d->pal[(unsigned int)b]); } } } de_bitmap_write_to_file_finfo(img, fi, createflags); de_bitmap_destroy(img); }
// Read a "Variable Size Integer". // Updates *pos. // Returns: // 0 on failure // 1 on success // 2 for a special "reserved" value static int get_var_size_int(dbuf *f, i64 *val, i64 *pos, i64 nbytes_avail) { i64 pos1; u8 b; u8 mask; unsigned int k; int retval = 0; u8 test_bit; unsigned int initial_zero_bits; pos1 = *pos; if(nbytes_avail<1) goto done; // This is an unsigned int. In a i64, we can support up to 63 // bits. // For now we'll hope that 8 octets is the most we'll have to support, // but it's possible we'll have to support 9 or even more, which will // require additional logic. // // 1xxxxxxx width_nbits=0, octets=1, data_bits=7 // 01xxxxxx width_nbits=1, octets=2, data_bits=14 // ... // 00000001 width_nbits=7, octets=8, data_bits=56 // 00000000 1xxxxxxx width_nbits=8, octets=9, data_bits=63 b = dbuf_getbyte(f, *pos); (*pos)++; test_bit = 0x80; initial_zero_bits = 0; while(1) { if(b>=test_bit) { break; } // "Not it". Try the next-larger number of initial 0 bits. initial_zero_bits++; test_bit >>= 1; if(test_bit==0) { goto done; } } mask = 0x7f >> initial_zero_bits; *val = (i64)(b & mask); // Read remaining bytes, if any. for(k=0; k<initial_zero_bits; k++) { if(*pos >= pos1+nbytes_avail) goto done; b = dbuf_getbyte(f, *pos); (*pos)++; if(*val > 0x07ffffffffffffffLL) { goto done; } *val = ((*val)<<8) | ((i64)b); } if(initial_zero_bits==0 && (*val)==0x7f) { // TODO: Fully handle "reserved" element value of all 1 bits. retval = 2; goto done; } retval = 1; done: if(retval!=1) { *val = 0; } return retval; }