- /* Number of entries we need to actually read from the chunk
- * table (excludes the implicit first chunk). */
- u64 num_needed_chunk_entries = (start_chunk == 0) ?
- num_needed_chunks - 1 : num_needed_chunks;
-
- /* Skip over unneeded chunk table entries. */
- u64 file_offset_of_needed_chunk_entries = resource_offset +
- start_table_idx * chunk_entry_size;
- if (fseeko(fp, file_offset_of_needed_chunk_entries, SEEK_SET) != 0) {
- ERROR_WITH_ERRNO("Failed to seek to byte %"PRIu64" to read "
- "chunk table of compressed resource",
- file_offset_of_needed_chunk_entries);
- return WIMLIB_ERR_READ;
+ /* Calculate the offset, within the start chunk, of the first byte of
+ * the read. */
+ u64 start_offset_in_chunk = offset % WIM_CHUNK_SIZE;
+
+ /* Calculate the index of the chunk that contains the last byte of the
+ * read. */
+ u64 end_chunk = (offset + size - 1) / WIM_CHUNK_SIZE;
+
+ /* Calculate the offset, within the end chunk, of the last byte of the
+ * read. */
+ u64 end_offset_in_chunk = (offset + size - 1) % WIM_CHUNK_SIZE;
+
+ /* Calculate the number of chunk entries are actually needed to read the
+ * requested part of the resource. Include an entry for the first chunk
+ * even though that doesn't exist in the on-disk table, but take into
+ * account that if the last chunk required for the read is not the last
+ * chunk of the resource, an extra chunk entry is needed so that the
+ * compressed size of the last chunk of the read can be determined. */
+ u64 num_alloc_chunk_entries = end_chunk - start_chunk + 1;
+ if (end_chunk != num_chunks - 1)
+ num_alloc_chunk_entries++;
+
+ /* Set the size of each chunk table entry based on the resource's
+ * uncompressed size. */
+ u64 chunk_entry_size = (wim_resource_size(lte) > ((u64)1 << 32)) ? 8 : 4;
+
+ /* Calculate the size, in bytes, of the full chunk table. */
+ u64 chunk_table_size = num_chunk_entries * chunk_entry_size;
+
+ /* Allocate a buffer to hold a subset of the chunk table. It will only
+ * contain offsets for the chunks that are actually needed for this
+ * read. For speed, allocate the buffer on the stack unless it's too
+ * large. */
+ u64 *chunk_offsets;
+ bool chunk_offsets_malloced;
+ if (num_alloc_chunk_entries < 1024) {
+ chunk_offsets = alloca(num_alloc_chunk_entries * sizeof(u64));
+ chunk_offsets_malloced = false;
+ } else {
+ chunk_offsets = malloc(num_alloc_chunk_entries * sizeof(u64));
+ if (!chunk_offsets) {
+ ERROR("Failed to allocate chunk table "
+ "with %"PRIu64" entries", num_alloc_chunk_entries);
+ return WIMLIB_ERR_NOMEM;
+ }
+ chunk_offsets_malloced = true;