+ if ((size_t)lte->size != lte->size) {
+ ERROR("Can't read %"PRIu64" byte stream into "
+ "memory", lte->size);
+ return WIMLIB_ERR_NOMEM;
+ }
+
+ buf = MALLOC(lte->size);
+ if (buf == NULL)
+ return WIMLIB_ERR_NOMEM;
+
+ ret = read_full_stream_into_buf(lte, buf);
+ if (ret) {
+ FREE(buf);
+ return ret;
+ }
+
+ *buf_ret = buf;
+ return 0;
+}
+
+/* Retrieve the full uncompressed data of the specified WIM resource. A buffer
+ * large enough hold the data is allocated and returned in @buf_ret. */
+static int
+wim_resource_spec_to_data(struct wim_resource_spec *rspec, void **buf_ret)
+{
+ int ret;
+ struct wim_lookup_table_entry *lte;
+
+ lte = new_lookup_table_entry();
+ if (lte == NULL)
+ return WIMLIB_ERR_NOMEM;
+
+ lte_bind_wim_resource_spec(lte, rspec);
+ lte->flags = rspec->flags;
+ lte->size = rspec->uncompressed_size;
+ lte->offset_in_res = 0;
+
+ ret = read_full_stream_into_alloc_buf(lte, buf_ret);
+
+ lte_unbind_wim_resource_spec(lte);
+ free_lookup_table_entry(lte);
+ return ret;
+}
+
+/* Retrieve the full uncompressed data of a WIM resource specified as a raw
+ * `wim_reshdr' and the corresponding WIM file. A large enough hold the data is
+ * allocated and returned in @buf_ret. */
+int
+wim_reshdr_to_data(const struct wim_reshdr *reshdr, WIMStruct *wim, void **buf_ret)
+{
+ DEBUG("offset_in_wim=%"PRIu64", size_in_wim=%"PRIu64", "
+ "uncompressed_size=%"PRIu64,
+ reshdr->offset_in_wim, reshdr->size_in_wim,
+ reshdr->uncompressed_size);
+
+ struct wim_resource_spec rspec;
+ wim_res_hdr_to_spec(reshdr, wim, &rspec);
+ return wim_resource_spec_to_data(&rspec, buf_ret);
+}
+
+int
+wim_reshdr_to_hash(const struct wim_reshdr *reshdr, WIMStruct *wim,
+ u8 hash[SHA1_HASH_SIZE])
+{
+ struct wim_resource_spec rspec;
+ int ret;
+ struct wim_lookup_table_entry *lte;
+
+ wim_res_hdr_to_spec(reshdr, wim, &rspec);
+
+ lte = new_lookup_table_entry();
+ if (lte == NULL)
+ return WIMLIB_ERR_NOMEM;
+
+ lte_bind_wim_resource_spec(lte, &rspec);
+ lte->flags = rspec.flags;
+ lte->size = rspec.uncompressed_size;
+ lte->offset_in_res = 0;
+ lte->unhashed = 1;
+
+ ret = sha1_stream(lte);
+
+ lte_unbind_wim_resource_spec(lte);
+ copy_hash(hash, lte->hash);
+ free_lookup_table_entry(lte);
+ return ret;
+}
+
+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. */
+static int
+streamifier_cb(const void *chunk, size_t size, void *_ctx)
+{
+ struct streamifier_context *ctx = _ctx;
+ int ret;
+
+ DEBUG("%zu bytes passed to streamifier", size);
+
+ wimlib_assert(ctx->cur_stream != NULL);
+ wimlib_assert(size <= ctx->cur_stream->size - ctx->cur_stream_offset);
+
+ if (ctx->cur_stream_offset == 0) {
+ /* Starting a new stream. */
+ DEBUG("Begin new stream (size=%"PRIu64").",
+ ctx->cur_stream->size);
+ ret = (*ctx->cbs.begin_stream)(ctx->cur_stream, true,
+ ctx->cbs.begin_stream_ctx);
+ if (ret)