+ goto out_free_lookup_table;
+ }
+
+ 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);
+
+ if (part_number != wim->hdr.part_number) {
+ WARNING("A lookup table entry in part %hu of the WIM "
+ "points to part %hu (ignoring it)",
+ wim->hdr.part_number, part_number);
+ free_lookup_table_entry(cur_entry);
+ continue;
+ }
+
+ if (cur_rspec == NULL ||
+ !(reshdr.flags & WIM_RESHDR_FLAG_CONCAT))
+ {
+ /* Starting new run of stream entries that all share the
+ * same WIM resource (streams concatenated together); or
+ * simply a single normal entry by itself. */
+
+ if (cur_rspec != NULL) {
+ ret = validate_resource(cur_rspec);
+ if (ret)
+ goto out_free_cur_entry;
+ }
+
+ cur_rspec = MALLOC(sizeof(struct wim_resource_spec));
+ if (cur_rspec == NULL) {
+ ERROR("Not enough memory to read lookup table!");
+ ret = WIMLIB_ERR_NOMEM;
+ goto out_free_cur_entry;
+ }
+ wim_res_hdr_to_spec(&reshdr, wim, cur_rspec);
+ if (reshdr.flags & WIM_RESHDR_FLAG_CONCAT) {
+ cur_rspec->size_in_wim = 0;
+ cur_rspec->uncompressed_size = 0;
+ }
+ } else if (is_zero_hash(cur_entry->hash)) {
+ /* Found the resource specification for the run. */
+ cur_rspec->offset_in_wim = reshdr.offset_in_wim;
+ cur_rspec->size_in_wim = reshdr.size_in_wim;
+ cur_rspec->flags = reshdr.flags;
+ DEBUG("Full run is %"PRIu64" compressed bytes "
+ "at file offset %"PRIu64" (flags 0x%02x)",
+ cur_rspec->size_in_wim,
+ cur_rspec->offset_in_wim,
+ cur_rspec->flags);
+ free_lookup_table_entry(cur_entry);
+ continue;
+ }
+
+ if (reshdr.flags & WIM_RESHDR_FLAG_CONCAT) {
+ /* Continuing the run with another stream. */
+ DEBUG("Continuing concat run with stream: "
+ "%"PRIu64" uncompressed bytes @ resource offset %"PRIu64")",
+ reshdr.size_in_wim, reshdr.offset_in_wim);
+ cur_rspec->uncompressed_size += reshdr.size_in_wim;
+ }
+
+ lte_bind_wim_resource_spec(cur_entry, cur_rspec);
+ if (reshdr.flags & WIM_RESHDR_FLAG_CONCAT) {
+ /* In concatenation runs, the offset field is used for
+ * in-resource offset, not the in-WIM offset, and the
+ * size field is used for the uncompressed size, not the
+ * compressed size. */
+ cur_entry->offset_in_res = reshdr.offset_in_wim;
+ cur_entry->size = reshdr.size_in_wim;
+ cur_entry->flags = reshdr.flags;
+ } else {
+ cur_entry->offset_in_res = 0;
+ cur_entry->size = reshdr.uncompressed_size;
+ cur_entry->flags = reshdr.flags;
+ cur_rspec = NULL;
+ }
+
+ if (is_zero_hash(cur_entry->hash)) {
+ WARNING("The WIM lookup table contains an entry with a "
+ "SHA1 message digest of all 0's (ignoring it)");
+ free_lookup_table_entry(cur_entry);
+ continue;
+ }
+
+ if (cur_entry->flags & WIM_RESHDR_FLAG_METADATA) {
+ /* Lookup table entry for a metadata resource */
+ if (cur_entry->refcnt != 1) {
+ /* Metadata entries with no references must be
+ * ignored. See for example the WinPE WIMs from
+ * WAIK v2.1. */
+ if (cur_entry->refcnt == 0) {
+ free_lookup_table_entry(cur_entry);
+ continue;
+ }
+ if (wimlib_print_errors) {
+ ERROR("Found metadata resource with refcnt != 1:");
+ print_lookup_table_entry(cur_entry, stderr);
+ }
+ ret = WIMLIB_ERR_INVALID_LOOKUP_TABLE_ENTRY;
+ goto out_free_cur_entry;
+ }
+
+ if (wim->hdr.part_number != 1) {
+ WARNING("Ignoring metadata resource found in a "
+ "non-first part of the split WIM");
+ free_lookup_table_entry(cur_entry);
+ continue;
+ }
+ if (wim->current_image == wim->hdr.image_count) {
+ WARNING("The WIM header says there are %u images "
+ "in the WIM, but we found more metadata "
+ "resources than this (ignoring the extra)",
+ wim->hdr.image_count);
+ free_lookup_table_entry(cur_entry);
+ continue;
+ }
+
+ /* Notice very carefully: We are assigning the metadata
+ * resources in the exact order mirrored by their lookup
+ * table entries on disk, which is the behavior of
+ * Microsoft's software. In particular, this overrides
+ * the actual locations of the metadata resources
+ * themselves in the WIM file as well as any information
+ * written in the XML data. */
+ DEBUG("Found metadata resource for image %u at "
+ "offset %"PRIu64".",
+ wim->current_image + 1,
+ cur_entry->rspec->offset_in_wim);
+ wim->image_metadata[
+ wim->current_image++]->metadata_lte = cur_entry;
+ } else {
+ /* Lookup table entry for a stream that is not a
+ * metadata resource */
+ duplicate_entry = lookup_resource(table, cur_entry->hash);
+ if (duplicate_entry) {
+ if (wimlib_print_errors) {
+ WARNING("The WIM lookup table contains two entries with the "
+ "same SHA1 message digest!");
+ WARNING("The first entry is:");
+ print_lookup_table_entry(duplicate_entry, stderr);
+ WARNING("The second entry is:");
+ print_lookup_table_entry(cur_entry, stderr);
+ }
+ free_lookup_table_entry(cur_entry);
+ continue;
+ } else {
+ lookup_table_insert(table, cur_entry);
+ }