+
+ for (cur = stream_list->next, next = cur->next;
+ cur != stream_list;
+ cur = next, next = cur->next)
+ {
+ lte = (struct wim_lookup_table_entry*)((u8*)cur - list_head_offset);
+
+ if (lte->flags & WIM_RESHDR_FLAG_PACKED_STREAMS &&
+ lte->size != lte->rspec->uncompressed_size)
+ {
+
+ struct wim_lookup_table_entry *lte_next, *lte_last;
+ struct list_head *next2;
+ u64 stream_count;
+
+ /* The next stream is a proper sub-sequence of a WIM
+ * resource. See if there are other streams in the same
+ * resource that need to be read. Since
+ * sort_stream_list_by_sequential_order() sorted the
+ * streams by offset in the WIM, this can be determined
+ * by simply scanning forward in the list. */
+
+ lte_last = lte;
+ stream_count = 1;
+ for (next2 = next;
+ next2 != stream_list
+ && (lte_next = (struct wim_lookup_table_entry*)
+ ((u8*)next2 - list_head_offset),
+ lte_next->resource_location == RESOURCE_IN_WIM
+ && lte_next->rspec == lte->rspec);
+ next2 = next2->next)
+ {
+ lte_last = lte_next;
+ stream_count++;
+ }
+ if (stream_count > 1) {
+ /* Reading multiple streams combined into a
+ * single WIM resource. They are in the stream
+ * list, sorted by offset; @lte specifies the
+ * first stream in the resource that needs to be
+ * read and @lte_last specifies the last stream
+ * in the resource that needs to be read. */
+ next = next2;
+ ret = read_packed_streams(lte, lte_last,
+ stream_count,
+ list_head_offset,
+ sink_cbs);
+ if (ret)
+ return ret;
+ continue;
+ }
+ }
+
+ ret = read_full_stream_with_cbs(lte, sink_cbs);
+ if (ret && ret != BEGIN_STREAM_STATUS_SKIP_STREAM)
+ return ret;
+ }
+ return 0;
+}
+
+/* Extract the first @size bytes of the specified stream.
+ *
+ * If @size specifies the full uncompressed size of the stream, then the SHA1
+ * message digest of the uncompressed stream is checked while being extracted.
+ *
+ * The uncompressed data of the resource is passed in chunks of unspecified size
+ * to the @extract_chunk function, passing it @extract_chunk_arg. */
+int
+extract_stream(struct wim_lookup_table_entry *lte, u64 size,
+ consume_data_callback_t extract_chunk, void *extract_chunk_arg)
+{
+ wimlib_assert(size <= lte->size);
+ if (size == lte->size) {
+ /* Do SHA1. */
+ struct read_stream_list_callbacks cbs = {
+ .consume_chunk = extract_chunk,
+ .consume_chunk_ctx = extract_chunk_arg,
+ };
+ return read_full_stream_with_sha1(lte, &cbs);
+ } else {
+ /* Don't do SHA1. */
+ return read_stream_prefix(lte, size, extract_chunk,
+ extract_chunk_arg);
+ }
+}
+
+/* A consume_data_callback_t implementation that writes the chunk of data to a
+ * file descriptor. */
+int
+extract_chunk_to_fd(const void *chunk, size_t size, void *_fd_p)
+{
+ struct filedes *fd = _fd_p;
+
+ int ret = full_write(fd, chunk, size);
+ if (ret) {
+ ERROR_WITH_ERRNO("Error writing to file descriptor");
+ return ret;
+ }
+ return 0;
+}
+
+/* Extract the first @size bytes of the specified stream to the specified file
+ * descriptor. */
+int
+extract_stream_to_fd(struct wim_lookup_table_entry *lte,
+ struct filedes *fd, u64 size)
+{
+ 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)
+{
+ wimlib_assert(lte->unhashed);
+ struct read_stream_list_callbacks cbs = {
+ };
+ return read_full_stream_with_sha1(lte, &cbs);
+}
+
+/* Convert a short WIM resource header to a stand-alone WIM resource
+ * specification.
+ *
+ * Note: for packed resources some fields still need to be overridden.
+ */
+void
+wim_res_hdr_to_spec(const struct wim_reshdr *reshdr, WIMStruct *wim,
+ struct wim_resource_spec *rspec)
+{
+ rspec->wim = wim;
+ rspec->offset_in_wim = reshdr->offset_in_wim;
+ rspec->size_in_wim = reshdr->size_in_wim;
+ rspec->uncompressed_size = reshdr->uncompressed_size;
+ INIT_LIST_HEAD(&rspec->stream_list);
+ rspec->flags = reshdr->flags;
+ rspec->is_pipable = wim_is_pipable(wim);
+ if (rspec->flags & WIM_RESHDR_FLAG_COMPRESSED) {
+ rspec->compression_type = wim->compression_type;
+ rspec->chunk_size = wim->chunk_size;
+ } else {
+ rspec->compression_type = WIMLIB_COMPRESSION_TYPE_NONE;
+ rspec->chunk_size = 0;
+ }
+}
+
+/* Convert a stand-alone resource specification to a WIM resource header. */
+void
+wim_res_spec_to_hdr(const struct wim_resource_spec *rspec,
+ struct wim_reshdr *reshdr)
+{
+ reshdr->offset_in_wim = rspec->offset_in_wim;
+ reshdr->size_in_wim = rspec->size_in_wim;
+ reshdr->flags = rspec->flags;
+ reshdr->uncompressed_size = rspec->uncompressed_size;
+}
+
+/* Translates a WIM resource header from the on-disk format into an in-memory
+ * format. */
+void
+get_wim_reshdr(const struct wim_reshdr_disk *disk_reshdr,
+ struct wim_reshdr *reshdr)
+{
+ reshdr->offset_in_wim = le64_to_cpu(disk_reshdr->offset_in_wim);
+ reshdr->size_in_wim = (((u64)disk_reshdr->size_in_wim[0] << 0) |
+ ((u64)disk_reshdr->size_in_wim[1] << 8) |
+ ((u64)disk_reshdr->size_in_wim[2] << 16) |
+ ((u64)disk_reshdr->size_in_wim[3] << 24) |
+ ((u64)disk_reshdr->size_in_wim[4] << 32) |
+ ((u64)disk_reshdr->size_in_wim[5] << 40) |
+ ((u64)disk_reshdr->size_in_wim[6] << 48));
+ reshdr->uncompressed_size = le64_to_cpu(disk_reshdr->uncompressed_size);
+ reshdr->flags = disk_reshdr->flags;
+}
+
+/* Translates a WIM resource header from an in-memory format into the on-disk
+ * format. */
+void
+put_wim_reshdr(const struct wim_reshdr *reshdr,
+ struct wim_reshdr_disk *disk_reshdr)
+{
+ disk_reshdr->size_in_wim[0] = reshdr->size_in_wim >> 0;
+ disk_reshdr->size_in_wim[1] = reshdr->size_in_wim >> 8;
+ disk_reshdr->size_in_wim[2] = reshdr->size_in_wim >> 16;
+ disk_reshdr->size_in_wim[3] = reshdr->size_in_wim >> 24;
+ disk_reshdr->size_in_wim[4] = reshdr->size_in_wim >> 32;
+ disk_reshdr->size_in_wim[5] = reshdr->size_in_wim >> 40;
+ disk_reshdr->size_in_wim[6] = reshdr->size_in_wim >> 48;
+ disk_reshdr->flags = reshdr->flags;
+ disk_reshdr->offset_in_wim = cpu_to_le64(reshdr->offset_in_wim);
+ disk_reshdr->uncompressed_size = cpu_to_le64(reshdr->uncompressed_size);