+invalid_due_to_overlap:
+ ERROR("Invalid resource entry (streams in packed resource overlap)");
+ return WIMLIB_ERR_INVALID_LOOKUP_TABLE_ENTRY;
+}
+
+/* Validate the resource, or free it if unused. */
+static int
+finish_resource(struct wim_resource_spec *rspec)
+{
+ if (!list_empty(&rspec->stream_list)) {
+ /* This resource contains at least one stream. */
+ return validate_resource(rspec);
+ } else {
+ /* No streams are in this resource. Get rid of it. */
+ FREE(rspec);
+ return 0;
+ }
+}
+
+/*
+ * Reads the lookup table from a WIM file. Usually, each entry specifies a
+ * stream that the WIM file contains, along with its location and SHA1 message
+ * digest.
+ *
+ * Saves lookup table entries for non-metadata streams in a hash table (set to
+ * wim->lookup_table), and saves the metadata entry for each image in a special
+ * per-image location (the wim->image_metadata array).
+ *
+ * This works for both version WIM_VERSION_DEFAULT (68864) and version
+ * WIM_VERSION_PACKED_STREAMS (3584) WIMs.
+ *
+ * Possible return values:
+ * WIMLIB_ERR_SUCCESS (0)
+ * WIMLIB_ERR_INVALID_LOOKUP_TABLE_ENTRY
+ * WIMLIB_ERR_NOMEM
+ *
+ * Or an error code caused by failure to read the lookup table from the WIM
+ * file.
+ */
+int
+read_wim_lookup_table(WIMStruct *wim)
+{
+ 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' */