]> wimlib.net Git - wimlib/blobdiff - src/resource.c
streamifier_cb(): Fix update of cur_stream_offset
[wimlib] / src / resource.c
index 6bc6fbf7078af416feb5cdbae0e712e672486216..192ffb2e988470252f92fda501a226664ee3f04c 100644 (file)
  */
 
 
-/* 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);
@@ -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.  */
@@ -338,7 +331,7 @@ read_compressed_wim_resource(const struct wim_resource_spec * const rspec,
                        chunk_offsets_alloc_size -
                        chunk_table_size_to_read;
 
-               ret = full_pread(in_fd, chunk_table_data, chunk_table_size,
+               ret = full_pread(in_fd, chunk_table_data, chunk_table_size_to_read,
                                 file_offset_of_needed_chunk_entries);
                if (ret)
                        goto read_error;
@@ -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,