X-Git-Url: https://wimlib.net/git/?a=blobdiff_plain;f=src%2Fresource.c;h=f61ecd5ac209c457fbb6d59b1324b62557d15fca;hb=1dbfb8e36f81ced8474ce048c2d0e18ac07de60d;hp=3256a2b8e54625590cfcda7c4a098102af62e31a;hpb=31aabd89accc03ec6e307620ee911f50ba05b0e8;p=wimlib diff --git a/src/resource.c b/src/resource.c index 3256a2b8..f61ecd5a 100644 --- a/src/resource.c +++ b/src/resource.c @@ -90,29 +90,6 @@ */ -/* Decompress the specified chunk that uses the specified compression type - * @ctype, part of a WIM with default chunk size @wim_chunk_size. For LZX the - * separate @wim_chunk_size is needed because it determines the window size used - * for LZX compression. */ -static int -decompress(const void *cchunk, unsigned clen, void *uchunk, unsigned ulen, - int ctype, u32 wim_chunk_size) -{ - switch (ctype) { - case WIMLIB_COMPRESSION_TYPE_LZX: - return wimlib_lzx_decompress2(cchunk, clen, - uchunk, ulen, wim_chunk_size); - case WIMLIB_COMPRESSION_TYPE_XPRESS: - return wimlib_xpress_decompress(cchunk, clen, - uchunk, ulen); - case WIMLIB_COMPRESSION_TYPE_LZMS: - return wimlib_lzms_decompress(cchunk, clen, uchunk, ulen); - default: - ERROR("Invalid compression format (%d)", ctype); - return -1; - } -} - struct data_range { u64 offset; u64 size; @@ -164,6 +141,7 @@ read_compressed_wim_resource(const struct wim_resource_spec * const rspec, bool chunk_offsets_malloced = false; bool ubuf_malloced = false; bool cbuf_malloced = false; + struct wimlib_decompressor *decompressor = NULL; /* Sanity checks */ wimlib_assert(rspec != NULL); @@ -197,9 +175,9 @@ read_compressed_wim_resource(const struct wim_resource_spec * const rspec, /* Get the maximum size of uncompressed chunks in this resource, which * we require be a power of 2. */ - u32 chunk_size; + u32 chunk_size = 0; u64 cur_read_offset = rspec->offset_in_wim; - int ctype; + int ctype = WIMLIB_COMPRESSION_TYPE_NONE; if (alt_chunk_table) { /* Alternate chunk table format. Its header specifies the chunk * size and compression format. */ @@ -232,6 +210,21 @@ read_compressed_wim_resource(const struct wim_resource_spec * const rspec, goto out_free_memory; } + /* Get valid decompressor. */ + if (ctype == rspec->wim->decompressor_ctype && + chunk_size == rspec->wim->decompressor_max_block_size) + { + /* Cached decompressor. */ + decompressor = rspec->wim->decompressor; + rspec->wim->decompressor_ctype = WIMLIB_COMPRESSION_TYPE_NONE; + rspec->wim->decompressor = NULL; + } else { + ret = wimlib_create_decompressor(ctype, chunk_size, NULL, + &decompressor); + if (ret) + goto out_free_memory; + } + const u32 chunk_order = bsr32(chunk_size); /* Calculate the total number of chunks the resource is divided into. */ @@ -494,12 +487,11 @@ read_compressed_wim_resource(const struct wim_resource_spec * const rspec, DEBUG("Decompressing chunk %"PRIu64" " "(csize=%"PRIu32" usize=%"PRIu32")", i, chunk_csize, chunk_usize); - ret = decompress(cbuf, - chunk_csize, - ubuf, - chunk_usize, - ctype, - chunk_size); + ret = wimlib_decompress(cbuf, + chunk_csize, + ubuf, + chunk_usize, + decompressor); if (ret) { ERROR("Failed to decompress data!"); ret = WIMLIB_ERR_DECOMPRESSION; @@ -556,8 +548,15 @@ read_compressed_wim_resource(const struct wim_resource_spec * const rspec, goto read_error; } ret = 0; + out_free_memory: errno_save = errno; + if (decompressor) { + wimlib_free_decompressor(rspec->wim->decompressor); + rspec->wim->decompressor = decompressor; + rspec->wim->decompressor_ctype = ctype; + rspec->wim->decompressor_max_block_size = chunk_size; + } if (chunk_offsets_malloced) FREE(chunk_offsets); if (ubuf_malloced) @@ -898,11 +897,22 @@ wim_reshdr_to_data(const struct wim_reshdr *reshdr, WIMStruct *wim, void **buf_r struct streamifier_context { struct read_stream_list_callbacks cbs; struct wim_lookup_table_entry *cur_stream; + struct wim_lookup_table_entry *next_stream; u64 cur_stream_offset; struct wim_lookup_table_entry *final_stream; size_t list_head_offset; }; +static struct wim_lookup_table_entry * +next_stream(struct wim_lookup_table_entry *lte, size_t list_head_offset) +{ + struct list_head *cur; + + cur = (struct list_head*)((u8*)lte + list_head_offset); + + return (struct wim_lookup_table_entry*)((u8*)cur->next - list_head_offset); +} + /* A consume_data_callback_t implementation that translates raw resource data * into streams, calling the begin_stream, consume_chunk, and end_stream * callback functions as appropriate. */ @@ -937,11 +947,7 @@ streamifier_cb(const void *chunk, size_t size, void *_ctx) if (ctx->cur_stream_offset == ctx->cur_stream->size) { /* Finished reading all the data for a stream. */ - struct list_head *cur, *next; - - cur = (struct list_head *) - ((u8*)ctx->cur_stream + ctx->list_head_offset); - next = cur->next; + ctx->cur_stream_offset = 0; DEBUG("End stream (size=%"PRIu64").", ctx->cur_stream->size); ret = (*ctx->cbs.end_stream)(ctx->cur_stream, 0, @@ -949,15 +955,14 @@ streamifier_cb(const void *chunk, size_t size, void *_ctx) if (ret) return ret; - if (ctx->cur_stream != ctx->final_stream) { - /* Advance to next stream. */ - ctx->cur_stream = (struct wim_lookup_table_entry *) - ((u8*)next - ctx->list_head_offset); - - ctx->cur_stream_offset = 0; - } else { - /* No more streams. */ - ctx->cur_stream = NULL; + /* Advance to next stream. */ + ctx->cur_stream = ctx->next_stream; + if (ctx->cur_stream != NULL) { + if (ctx->cur_stream != ctx->final_stream) + ctx->next_stream = next_stream(ctx->cur_stream, + ctx->list_head_offset); + else + ctx->next_stream = NULL; } } return 0; @@ -1125,6 +1130,9 @@ read_full_stream_with_sha1(struct wim_lookup_table_entry *lte, * STREAM_LIST_ALREADY_SORTED * @stream_list is already sorted in sequential order for reading. * + * The callback functions are allowed to delete the current stream from the list + * if necessary. + * * Returns 0 on success; a nonzero error code on failure. Failure can occur due * to an error reading the data or due to an error status being returned by any * of the callback functions. @@ -1233,6 +1241,7 @@ read_stream_list(struct list_head *stream_list, struct streamifier_context streamifier_ctx = { .cbs = *sink_cbs, .cur_stream = lte, + .next_stream = next_stream(lte, list_head_offset), .cur_stream_offset = 0, .final_stream = lte_last, .list_head_offset = list_head_offset, @@ -1314,6 +1323,15 @@ extract_stream_to_fd(struct wim_lookup_table_entry *lte, return extract_stream(lte, size, extract_chunk_to_fd, fd); } +/* Extract the full uncompressed contents of the specified stream to the + * specified file descriptor. */ +int +extract_full_stream_to_fd(struct wim_lookup_table_entry *lte, + struct filedes *fd) +{ + return extract_stream_to_fd(lte, fd, lte->size); +} + /* Calculate the SHA1 message digest of a stream and store it in @lte->hash. */ int sha1_stream(struct wim_lookup_table_entry *lte)