static void do_uncompress_24(deark *c, lctx *d, struct page_ctx *pg, dbuf *unc_pixels, de_int64 skip) { de_int64 pos; de_byte b; de_int64 count; de_byte n; pos = pg->image_pos; if(skip) pos+=4; while(1) { if(pos >= pg->image_pos + pg->image_len) break; b = de_getbyte(pos); pos++; if(b>=128) { // Compressed run count = (de_int64)b - 125; n = de_getbyte(pos); pos++; dbuf_write_run(unc_pixels, n, count); } else { // An uncompressed run count = 1 + (de_int64)b; dbuf_copy(c->infile, pos, count, unc_pixels); pos += count; } } }
// 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; }
// 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; }
// Caller must initialize *repeat_count. static void uncompress_line(deark *c, lctx *d, dbuf *unc_line, i64 pos1, i64 rownum, i64 *bytes_consumed, i64 *repeat_count) { i64 pos; u8 b0, b1; u8 val; i64 count; i64 k; i64 tmp_repeat_count; i64 unc_line_len_orig; *bytes_consumed = 0; pos = pos1; unc_line_len_orig = unc_line->len; while(1) { if(pos >= c->infile->len) break; if(unc_line->len - unc_line_len_orig >= d->rowspan_per_plane) break; b0 = de_getbyte(pos++); if(b0==0) { // Pattern run or scanline run b1 = de_getbyte(pos++); if(b1>0) { // pattern run de_read(d->pattern_buf, pos, d->patlen); pos += d->patlen; count = (i64)b1; for(k=0; k<count; k++) { dbuf_write(unc_line, d->pattern_buf, d->patlen); } } else { // (b1==0) scanline run u8 flagbyte; flagbyte = de_getbyte(pos); if(flagbyte==0xff) { pos++; tmp_repeat_count = (i64)de_getbyte(pos++); if(tmp_repeat_count == 0) { de_dbg(c, "row %d: bad repeat count", (int)rownum); } else { *repeat_count = tmp_repeat_count; } } else { de_dbg(c, "row %d: bad scanline run marker: 0x%02x", (int)rownum, (unsigned int)flagbyte); } } } else if(b0==0x80) { // "Uncompressed bit string" count = (i64)de_getbyte(pos++); dbuf_copy(c->infile, pos, count, unc_line); pos += count; } else { // "solid run" val = (b0&0x80) ? 0xff : 0x00; count = (i64)(b0 & 0x7f); dbuf_write_run(unc_line, val, count); } } *bytes_consumed = pos - pos1; }
void dbuf_write_zeroes(dbuf *f, i64 len) { dbuf_write_run(f, 0, len); }