bool zip_seek_to_compressed_data(ar_archive_zip *zip) { struct zip_entry entry; if (!ar_seek(zip->super.stream, zip->entry.offset, SEEK_SET)) return false; if (!zip_parse_local_file_entry(zip, &entry)) return false; if (zip->entry.method != entry.method) { warn("Compression methods don't match: %d != %d", zip->entry.method, entry.method); if (!zip->entry.method) zip->entry.method = entry.method; } if (zip->entry.dosdate != entry.dosdate) { warn("Timestamps don't match"); if (!zip->entry.dosdate) { zip->entry.dosdate = entry.dosdate; zip->super.entry_filetime = ar_conv_dosdate_to_filetime(zip->entry.dosdate); } } return ar_seek(zip->super.stream, zip->entry.offset + ZIP_LOCAL_ENTRY_FIXED_SIZE + entry.namelen + entry.extralen, SEEK_SET); }
static bool rar_parse_entry(ar_archive *ar, off64_t offset) { ar_archive_rar *rar = (ar_archive_rar *)ar; struct rar_header header; struct rar_entry entry; bool out_of_order = offset != ar->entry_offset_next; if (!ar_seek(ar->stream, offset, SEEK_SET)) { warn("Couldn't seek to offset %" PRIi64, offset); return false; } for (;;) { ar->entry_offset = ar_tell(ar->stream); ar->entry_size_uncompressed = 0; if (!rar_parse_header(ar, &header)) return false; ar->entry_offset_next = ar->entry_offset + header.size + header.datasize; if (ar->entry_offset_next < ar->entry_offset + header.size) { warn("Integer overflow due to overly large data size"); return false; } switch (header.type) { case TYPE_MAIN_HEADER: if ((header.flags & MHD_PASSWORD)) { warn("Encrypted archives aren't supported"); return false; } ar_skip(ar->stream, 6 /* reserved data */); if ((header.flags & MHD_ENCRYPTVER)) { log("MHD_ENCRYPTVER is set"); ar_skip(ar->stream, 1); } if ((header.flags & MHD_COMMENT)) log("MHD_COMMENT is set"); if (ar_tell(ar->stream) - ar->entry_offset > header.size) { warn("Invalid RAR header size: %d", header.size); return false; } rar->archive_flags = header.flags; break; case TYPE_FILE_ENTRY: if (!rar_parse_header_entry(rar, &header, &entry)) return false; if ((header.flags & LHD_PASSWORD)) warn("Encrypted entries will fail to uncompress"); if ((header.flags & LHD_DIRECTORY) == LHD_DIRECTORY) { if (header.datasize == 0) { log("Skipping directory entry \"%s\"", rar_get_name(ar)); break; } warn("Can't skip directory entries containing data"); } if ((header.flags & (LHD_SPLIT_BEFORE | LHD_SPLIT_AFTER))) warn("Splitting files isn't really supported"); ar->entry_size_uncompressed = (size_t)entry.size; ar->entry_filetime = ar_conv_dosdate_to_filetime(entry.dosdate); if (!rar->entry.solid || rar->entry.method == METHOD_STORE || out_of_order) { rar_clear_uncompress(&rar->uncomp); memset(&rar->solid, 0, sizeof(rar->solid)); } else { br_clear_leftover_bits(&rar->uncomp); } rar->solid.restart = rar->entry.solid && (out_of_order || !rar->solid.part_done); rar->solid.part_done = !ar->entry_size_uncompressed; rar->progress.data_left = (size_t)header.datasize; rar->progress.bytes_done = 0; rar->progress.crc = 0; /* TODO: CRC checks don't always hold (claim in XADRARParser.m @readBlockHeader) */ if (!rar_check_header_crc(ar)) warn("Invalid header checksum @%" PRIi64, ar->entry_offset); if (ar_tell(ar->stream) != ar->entry_offset + rar->entry.header_size) { warn("Couldn't seek to offset %" PRIi64, ar->entry_offset + rar->entry.header_size); return false; } return true; case TYPE_NEWSUB: log("Skipping newsub header @%" PRIi64, ar->entry_offset); break; case TYPE_END_OF_ARCHIVE: ar->at_eof = true; return false; default: log("Unknown RAR header type %02x", header.type); break; } /* TODO: CRC checks don't always hold (claim in XADRARParser.m @readBlockHeader) */ if (!rar_check_header_crc(ar)) warn("Invalid header checksum @%" PRIi64, ar->entry_offset); if (!ar_seek(ar->stream, ar->entry_offset_next, SEEK_SET)) { warn("Couldn't seek to offset %" PRIi64, ar->entry_offset_next); return false; } } }