mirror of
https://github.com/storytold/craft-libs.git
synced 2026-11-14 22:42:46 +00:00
fix(xfl): honor the ZIP64 entry-count sentinel
This commit is contained in:
1 parent
a6b246ebef
commit
1c6ac2e086
2 files changed
+23
-3
No files matched your search
@@ -262,9 +262,10 @@ fn find_end(data: &[u8]) -> Result<(u64, u64, u64, usize), ZipError> {
|
||||
// consistent candidate is found. This preserves useful damaged-ZIP diagnostics.
|
||||
fallback = Some(candidate);
|
||||
|
||||
let count = u16_at(data, candidate + 10).unwrap_or(u16::MAX);
|
||||
let size = u32_at(data, candidate + 12).unwrap_or(u32::MAX);
|
||||
let offset = u32_at(data, candidate + 16).unwrap_or(u32::MAX);
|
||||
if size == u32::MAX || offset == u32::MAX {
|
||||
if count == u16::MAX || size == u32::MAX || offset == u32::MAX {
|
||||
let locator = candidate.checked_sub(20).filter(|&at| u32_at(data, at) == Some(LOCATOR64));
|
||||
let valid = locator.and_then(|locator| find_zip64_end(data, locator)).and_then(|at| {
|
||||
let count = u64_at(data, at + 32)?;
|
||||
@@ -280,8 +281,7 @@ fn find_end(data: &[u8]) -> Result<(u64, u64, u64, usize), ZipError> {
|
||||
continue;
|
||||
}
|
||||
} else {
|
||||
let count = u16_at(data, candidate + 10).map(u64::from).unwrap_or(u64::MAX);
|
||||
let Some((_, shift)) = locate_directory(data, count, size.into(), offset.into(), candidate) else {
|
||||
let Some((_, shift)) = locate_directory(data, count.into(), size.into(), offset.into(), candidate) else {
|
||||
continue;
|
||||
};
|
||||
if count == 0 && shift > 0 {
|
||||
|
||||
@@ -319,6 +319,26 @@ fn zip64_archives_open_and_their_damage_is_named() {
|
||||
assert_eq!(Archive::open(&t).err(), Some(ZipError::DamagedEntry("a.xml".into(), "has no ZIP64 sizes")));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn zip64_count_sentinel_keeps_a_comment_eocd_from_masking_the_archive() {
|
||||
let mut bytes = write(&[Raw::new("a.xml", b"x", false)], true);
|
||||
let end = bytes.len() - 22;
|
||||
let locator = end - 20;
|
||||
let zip64_end = locator - 56;
|
||||
let directory_size = u64_at(&bytes, zip64_end + 40).unwrap() as u32;
|
||||
let directory_offset = u64_at(&bytes, zip64_end + 48).unwrap() as u32;
|
||||
// Count requires ZIP64, while directory size and offset still fit in the classic fields.
|
||||
bytes[end + 12..end + 16].copy_from_slice(&directory_size.to_le_bytes());
|
||||
bytes[end + 16..end + 20].copy_from_slice(&directory_offset.to_le_bytes());
|
||||
bytes[end + 20..end + 22].copy_from_slice(&22u16.to_le_bytes());
|
||||
// This valid empty EOCD-shaped signature is inside the real end record's comment.
|
||||
bytes.extend_from_slice(&END.to_le_bytes());
|
||||
bytes.extend_from_slice(&[0; 18]);
|
||||
|
||||
let archive = Archive::open(&bytes).unwrap();
|
||||
assert_eq!(archive.read("a.xml").unwrap().unwrap(), b"x");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn self_extracting_archives_support_relative_and_adjusted_offsets() {
|
||||
let entries = [Raw::new("DOMDocument.xml", b"<DOMDocument/>", true), Raw::new("LIBRARY/a.xml", b"<DOMSymbolItem/>", false)];
|
||||
|
||||
Reference in new issue
Block a user