+ ret = 0;
+out_free_chunk_offsets:
+ if (chunk_offsets_malloced)
+ FREE(chunk_offsets);
+ return ret;
+
+read_error:
+ ERROR_WITH_ERRNO("Error reading compressed file resource");
+ goto out_free_chunk_offsets;
+}
+
+/* Skip over the chunk table at the end of pipable, compressed resource being
+ * read from a pipe. */
+static int
+skip_chunk_table(const struct wim_lookup_table_entry *lte,
+ struct filedes *in_fd)
+{
+ u64 num_chunk_entries = wim_resource_chunks(lte) - 1;
+ u64 chunk_entry_size = (wim_resource_size(lte) > ((u64)1 << 32)) ? 8 : 4;
+ u64 chunk_table_size = num_chunk_entries * chunk_entry_size;
+ int ret;
+
+ if (num_chunk_entries != 0) {
+ u8 dummy;
+ ret = full_pread(in_fd, &dummy, 1,
+ in_fd->offset + chunk_table_size - 1);
+ if (ret)
+ return ret;
+ }
+ return 0;
+}
+
+/* Read and decompress data from a compressed, pipable resource being read from
+ * a pipe. */
+static int
+read_pipable_resource(const struct wim_lookup_table_entry *lte,
+ u64 size, consume_data_callback_t cb,
+ void *ctx_or_buf, int flags, u64 offset)
+{
+ struct filedes *in_fd;
+ decompress_func_t decompress;
+ int ret;
+ u8 chunk[WIM_CHUNK_SIZE];
+ u8 cchunk[WIM_CHUNK_SIZE - 1];
+
+ /* Get pointers to appropriate decompression function and the input file
+ * descriptor. */
+ decompress = get_decompress_func(wim_resource_compression_type(lte));
+ in_fd = <e->wim->in_fd;
+
+ /* This function currently assumes the entire resource is being read at
+ * once and that the raw compressed data isn't being requested. This is
+ * based on the fact that this function currently only gets called
+ * during the operation of wimlib_extract_image_from_pipe(). */
+ wimlib_assert(!(flags & WIMLIB_READ_RESOURCE_FLAG_RAW));
+ wimlib_assert(offset == 0);
+ wimlib_assert(size == wim_resource_size(lte));
+ wimlib_assert(in_fd->offset == lte->resource_entry.offset);
+
+ for (offset = 0; offset < size; offset += WIM_CHUNK_SIZE) {
+ struct pwm_chunk_hdr chunk_hdr;
+ u32 chunk_size;
+ u32 cchunk_size;
+ u8 *res_chunk;
+ u32 res_chunk_size;
+
+ /* Calculate uncompressed size of next chunk. */
+ chunk_size = min(WIM_CHUNK_SIZE, size - offset);
+
+ /* Read the compressed size of the next chunk from the chunk
+ * header. */
+ ret = full_read(in_fd, &chunk_hdr, sizeof(chunk_hdr));
+ if (ret)
+ goto read_error;
+
+ cchunk_size = le32_to_cpu(chunk_hdr.compressed_size);
+
+ if (cchunk_size > WIM_CHUNK_SIZE) {
+ errno = EINVAL;
+ ret = WIMLIB_ERR_INVALID_PIPABLE_WIM;
+ goto invalid;
+ }
+
+ /* Read chunk data. */
+ ret = full_read(in_fd, cchunk, cchunk_size);
+ if (ret)
+ goto read_error;
+
+ if (flags & WIMLIB_READ_RESOURCE_FLAG_SEEK_ONLY)
+ continue;
+
+ /* Decompress chunk if needed. Uncompressed size same
+ * as compressed size means the chunk is uncompressed.
+ */
+ res_chunk_size = chunk_size;
+ if (cchunk_size == chunk_size) {
+ res_chunk = cchunk;
+ } else {
+ ret = (*decompress)(cchunk, cchunk_size,
+ chunk, chunk_size);
+ if (ret) {
+ errno = EINVAL;
+ ret = WIMLIB_ERR_DECOMPRESSION;
+ goto invalid;
+ }
+ res_chunk = chunk;
+ }
+
+ /* Feed the uncompressed data into the callback function or copy
+ * it into the provided buffer. */
+ if (cb) {
+ ret = cb(res_chunk, res_chunk_size, ctx_or_buf);
+ if (ret)
+ return ret;
+ } else {
+ ctx_or_buf = mempcpy(ctx_or_buf, res_chunk,
+ res_chunk_size);
+ }