+ int ret;
+ void *buf;
+
+ if ((size_t)blob->size != blob->size) {
+ ERROR("Can't read %"PRIu64" byte blob into memory", blob->size);
+ return WIMLIB_ERR_NOMEM;
+ }
+
+ buf = MALLOC(blob->size);
+ if (buf == NULL)
+ return WIMLIB_ERR_NOMEM;
+
+ ret = read_full_blob_into_buf(blob, buf);
+ if (ret) {
+ FREE(buf);
+ return ret;
+ }
+
+ *buf_ret = buf;
+ return 0;
+}
+
+/* Retrieve the full uncompressed data of a WIM resource specified as a raw
+ * `wim_reshdr' and the corresponding WIM file. A buffer 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)
+{
+ struct wim_resource_descriptor rdesc;
+ struct blob_descriptor blob;
+
+ wim_res_hdr_to_desc(reshdr, wim, &rdesc);
+ blob_set_is_located_in_nonsolid_wim_resource(&blob, &rdesc);
+
+ return read_full_blob_into_alloc_buf(&blob, buf_ret);
+}
+
+int
+wim_reshdr_to_hash(const struct wim_reshdr *reshdr, WIMStruct *wim,
+ u8 hash[SHA1_HASH_SIZE])
+{
+ struct wim_resource_descriptor rdesc;
+ struct blob_descriptor blob;
+ int ret;
+
+ wim_res_hdr_to_desc(reshdr, wim, &rdesc);
+ blob_set_is_located_in_nonsolid_wim_resource(&blob, &rdesc);
+ blob.unhashed = 1;
+
+ ret = sha1_blob(&blob);
+ if (ret)
+ return ret;
+ copy_hash(hash, blob.hash);
+ return 0;
+}
+
+struct blobifier_context {
+ struct read_blob_list_callbacks cbs;
+ struct blob_descriptor *cur_blob;
+ struct blob_descriptor *next_blob;
+ u64 cur_blob_offset;
+ struct blob_descriptor *final_blob;
+ size_t list_head_offset;
+};
+
+static struct blob_descriptor *
+next_blob(struct blob_descriptor *blob, size_t list_head_offset)
+{
+ struct list_head *cur;
+
+ cur = (struct list_head*)((u8*)blob + list_head_offset);
+
+ return (struct blob_descriptor*)((u8*)cur->next - list_head_offset);
+}
+
+/* A consume_data_callback_t implementation that translates raw resource data
+ * into blobs, calling the begin_blob, consume_chunk, and end_blob callback
+ * functions as appropriate. */
+static int
+blobifier_cb(const void *chunk, size_t size, void *_ctx)
+{
+ struct blobifier_context *ctx = _ctx;
+ int ret;
+
+ DEBUG("%zu bytes passed to blobifier", size);
+
+ wimlib_assert(ctx->cur_blob != NULL);
+ wimlib_assert(size <= ctx->cur_blob->size - ctx->cur_blob_offset);
+
+ if (ctx->cur_blob_offset == 0) {
+
+ /* Starting a new blob. */
+ DEBUG("Begin new blob (size=%"PRIu64").", ctx->cur_blob->size);
+
+ ret = (*ctx->cbs.begin_blob)(ctx->cur_blob,
+ ctx->cbs.begin_blob_ctx);
+ if (ret)
+ return ret;
+ }
+
+ /* Consume the chunk. */
+ ret = (*ctx->cbs.consume_chunk)(chunk, size,
+ ctx->cbs.consume_chunk_ctx);
+ ctx->cur_blob_offset += size;
+ if (ret)
+ return ret;
+
+ if (ctx->cur_blob_offset == ctx->cur_blob->size) {
+ /* Finished reading all the data for a blob. */
+
+ ctx->cur_blob_offset = 0;
+
+ DEBUG("End blob (size=%"PRIu64").", ctx->cur_blob->size);
+ ret = (*ctx->cbs.end_blob)(ctx->cur_blob, 0,
+ ctx->cbs.end_blob_ctx);
+ if (ret)
+ return ret;
+
+ /* Advance to next blob. */
+ ctx->cur_blob = ctx->next_blob;
+ if (ctx->cur_blob != NULL) {
+ if (ctx->cur_blob != ctx->final_blob)
+ ctx->next_blob = next_blob(ctx->cur_blob,
+ ctx->list_head_offset);
+ else
+ ctx->next_blob = NULL;
+ }
+ }
+ return 0;