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 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; } } }
static int do_decode_rle(deark *c, lctx *d, i64 pos1, dbuf *unc_pixels) { u8 b; i64 count; i64 k; u8 buf[8]; i64 pos = pos1; while(1) { if(pos >= c->infile->len) break; if(unc_pixels->len >= d->main_image.img_size_in_bytes) break; b = de_getbyte(pos); pos++; if(b & 0x80) { // RLE block count = (i64)(b - 0x80) + 1; de_read(buf, pos, d->bytes_per_pixel); pos += d->bytes_per_pixel; for(k=0; k<count; k++) { dbuf_write(unc_pixels, buf, d->bytes_per_pixel); } } else { // uncompressed block count = (i64)(b) + 1; dbuf_copy(c->infile, pos, count * d->bytes_per_pixel, unc_pixels); pos += count * d->bytes_per_pixel; } } de_dbg(c, "decompressed %d bytes to %d bytes", (int)(pos-pos1), (int)unc_pixels->len); return 1; }
int dbuf_create_file_from_slice(dbuf *inf, i64 pos, i64 data_size, const char *ext, de_finfo *fi, unsigned int createflags) { dbuf *f; f = dbuf_create_output_file(inf->c, ext, fi, createflags); if(!f) return 0; dbuf_copy(inf, pos, data_size, f); dbuf_close(f); return 1; }
static void do_vorbis_page(deark *c, lctx *d, struct page_info *pgi, struct stream_info *si) { u8 firstbyte; if(pgi->is_first_page) { // The first Ogg page of a bitstream usually contains enough data to be // useful. So, we'll try to process it directly, without reconstructing // the codec bitstream. do_vorbis_id_header(c, d, pgi, si); } // We want to save a copy of the Comment and Setup header data, // but not the Identification header which is handled elsewhere. if(si->stream_state!=0) { // We've already handled the Comment & Setup headers. goto done; } if(pgi->dlen<1) goto done; firstbyte = de_getbyte(pgi->dpos); if(si->page_count==0 || pgi->page_seq_num==0 || (pgi->hdr_type&0x02)) { // This appears to be the Identification header page. Skip it. goto done; } if(pgi->page_seq_num>=1 && (firstbyte&0x01)) { // This appears to be one of the pages we care about. // Save its data for later. if(!si->header_stream) { si->header_stream = dbuf_create_membuf(c, 1048576, 1); } dbuf_copy(c->infile, pgi->dpos, pgi->dlen, si->header_stream); } else if((firstbyte&0x01)==0) { // Reached the end of headers (by encountering a non-header page). // (There is required to be an Ogg page break immediately after the // Vorbis headers, so the start of the first data *page* must correspond // to the start of the first data *packet*. A Vorbis data packet always // begins with a byte whose low bit is 0.) do_theora_vorbis_after_headers(c, d, si); } done: ; }
// 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; }
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; }
// 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; }