+ int ret;
+ size_t num_entries;
+ void *buf = NULL;
+ struct wim_lookup_table *table = NULL;
+ struct wim_lookup_table_entry *cur_entry = NULL;
+ struct wim_resource_spec *cur_rspec = NULL;
+ size_t num_duplicate_entries = 0;
+ size_t num_wrong_part_entries = 0;
+ u32 image_index = 0;
+
+ DEBUG("Reading lookup table.");
+
+ /* Sanity check: lookup table entries are 50 bytes each. */
+ BUILD_BUG_ON(sizeof(struct wim_lookup_table_entry_disk) !=
+ WIM_LOOKUP_TABLE_ENTRY_DISK_SIZE);
+
+ /* Calculate the number of entries in the lookup table. */
+ num_entries = wim->hdr.lookup_table_reshdr.uncompressed_size /
+ sizeof(struct wim_lookup_table_entry_disk);
+
+ /* Read the lookup table into a buffer. */
+ ret = wim_reshdr_to_data(&wim->hdr.lookup_table_reshdr, wim, &buf);
+ if (ret)
+ goto out;
+
+ /* Allocate a hash table to map SHA1 message digests into stream
+ * specifications. This is the in-memory "lookup table". */
+ table = new_lookup_table(num_entries * 2 + 1);
+ if (!table)
+ goto oom;
+
+ /* Allocate and initalize stream entries ('struct
+ * wim_lookup_table_entry's) from the raw lookup table buffer. Each of
+ * these entries will point to a 'struct wim_resource_spec' that
+ * describes the underlying resource. In WIMs with version number
+ * WIM_VERSION_PACKED_STREAMS, a resource may contain multiple streams.
+ */
+ for (size_t i = 0; i < num_entries; i++) {
+ const struct wim_lookup_table_entry_disk *disk_entry =
+ &((const struct wim_lookup_table_entry_disk*)buf)[i];
+ struct wim_reshdr reshdr;
+ u16 part_number;
+
+ /* Get the resource header */
+ get_wim_reshdr(&disk_entry->reshdr, &reshdr);
+
+ DEBUG("reshdr: size_in_wim=%"PRIu64", "
+ "uncompressed_size=%"PRIu64", "
+ "offset_in_wim=%"PRIu64", "
+ "flags=0x%02x\n",
+ reshdr.size_in_wim, reshdr.uncompressed_size,
+ reshdr.offset_in_wim, reshdr.flags);
+
+ /* Ignore PACKED_STREAMS flag if it isn't supposed to be used in
+ * this WIM version */
+ if (wim->hdr.wim_version == WIM_VERSION_DEFAULT)
+ reshdr.flags &= ~WIM_RESHDR_FLAG_PACKED_STREAMS;
+
+ /* Allocate a 'struct wim_lookup_table_entry' */
+ cur_entry = new_lookup_table_entry();
+ if (!cur_entry)
+ goto oom;
+
+ /* Get the part number, reference count, and hash. */
+ part_number = le16_to_cpu(disk_entry->part_number);
+ cur_entry->refcnt = le32_to_cpu(disk_entry->refcnt);
+ copy_hash(cur_entry->hash, disk_entry->hash);
+
+ /* Verify that the part number matches that of the underlying
+ * WIM file. */
+ if (part_number != wim->hdr.part_number) {
+ num_wrong_part_entries++;
+ goto free_cur_entry_and_continue;
+ }
+
+ /* If resource is uncompressed, check for (unexpected) size
+ * mismatch. */
+ if (!(reshdr.flags & (WIM_RESHDR_FLAG_PACKED_STREAMS |
+ WIM_RESHDR_FLAG_COMPRESSED))) {
+ if (reshdr.uncompressed_size != reshdr.size_in_wim) {
+ /* So ... This is an uncompressed resource, but
+ * its uncompressed size is NOT the same as its
+ * "compressed" size (size_in_wim). What to do
+ * with it?
+ *
+ * Based on a simple test, WIMGAPI seems to
+ * handle this as follows:
+ *
+ * if (size_in_wim > uncompressed_size) {
+ * Ignore uncompressed_size; use
+ * size_in_wim instead.
+ * } else {
+ * Honor uncompressed_size, but treat the
+ * part of the file data above size_in_wim
+ * as all zeros.
+ * }
+ *
+ * So we will do the same.
+ */
+ if (reshdr.size_in_wim > reshdr.uncompressed_size)
+ reshdr.uncompressed_size = reshdr.size_in_wim;
+ }