usecrate::result::{ZipError, ZipResult}; use memchr::memmem::FinderRev; use std::borrow::Cow; use std::io; use std::io::prelude::*; use std::mem; use std::path::{Component, Path, MAIN_SEPARATOR};
/// "Magic" header values used in the zip spec to locate metadata records. /// /// These values currently always take up a fixed four bytes, so we can parse and wrap them in this /// struct to enforce some small amount of type safety. #[derive(Copy, Clone, Debug, PartialOrd, Ord, PartialEq, Eq, Hash)] #[repr(transparent)] pub(crate) struct Magic(u32);
/// Similar to [`Magic`], but used for extra field tags as per section 4.5.3 of APPNOTE.TXT. #[derive(Copy, Clone, Debug, PartialOrd, Ord, PartialEq, Eq, Hash)] #[repr(transparent)] pub(crate) struct ExtraFieldMagic(u16);
/* TODO: maybe try to use this for parsing extra fields as well as writing them? */ #[allow(dead_code)] impl ExtraFieldMagic { pubconstfn literal(x: u16) -> Self { Self(x)
}
const SIG_BYTES: [u8; mem::size_of::<Magic>()] =
Magic::CENTRAL_DIRECTORY_END_SIGNATURE.to_le_bytes(); let finder = FinderRev::new(&SIG_BYTES);
letmut window_start: u64 = file_length.saturating_sub(END_WINDOW_SIZE as u64); letmut window = [0u8; END_WINDOW_SIZE]; while window_start >= search_lower_bound { /* Go to the start of the window in the file. */
reader.seek(io::SeekFrom::Start(window_start))?;
/* Identify how many bytes to read (this may be less than the window size for files
* smaller than END_WINDOW_SIZE). */ let end = (window_start + END_WINDOW_SIZE as u64).min(file_length); let cur_len = (end - window_start) as usize;
debug_assert!(cur_len > 0);
debug_assert!(cur_len <= END_WINDOW_SIZE); let cur_window: &mut [u8] = &mut window[..cur_len]; /* Read the window into the bytes! */
reader.read_exact(cur_window)?;
/* Find instances of the magic signature. */ for offset in finder.rfind_iter(cur_window) { let cde_start_pos = window_start + offset as u64;
reader.seek(io::SeekFrom::Start(cde_start_pos))?; /* Drop any headers that don't parse. */ iflet Ok(cde) = Self::parse(reader) { return Ok((cde, cde_start_pos));
}
}
/* We always want to make sure we go allllll the way back to the start of the file if *wecan'tfinditelsewhere.However,our`while`conditiondoesn'tcheckthat.Sowe
* avoid infinite looping by checking at the end of the loop. */ if window_start == search_lower_bound { break;
} /* Shift the window by END_WINDOW_SIZE bytes, but make sure to cover matches that
* overlap our nice neat window boundaries! */
window_start = (window_start /* NB: To catch matches across window boundaries, we need to make our blocks overlap
* by the width of the pattern to match. */
+ mem::size_of::<Magic>() as u64) /* This should never happen, but make sure we don't go past the end of the file. */
.min(file_length);
window_start = window_start
.saturating_sub( /* Shift the window upon each iteration so we search END_WINDOW_SIZE bytes at
* once (unless limited by file_length). */
END_WINDOW_SIZE as u64,
) /* This will never go below the value of `search_lower_bound`, so we have a special
* `if window_start == search_lower_bound` check above. */
.max(search_lower_bound);
}
Err(ZipError::InvalidArchive( "Could not find central directory end",
))
}
const SIG_BYTES: [u8; mem::size_of::<Magic>()] =
Magic::ZIP64_CENTRAL_DIRECTORY_END_SIGNATURE.to_le_bytes(); let finder = FinderRev::new(&SIG_BYTES);
letmut window_start: u64 = search_upper_bound
.saturating_sub(END_WINDOW_SIZE as u64)
.max(search_lower_bound); letmut window = [0u8; END_WINDOW_SIZE]; while window_start >= search_lower_bound {
reader.seek(io::SeekFrom::Start(window_start))?;
/* Identify how many bytes to read (this may be less than the window size for files
* smaller than END_WINDOW_SIZE). */ let end = (window_start + END_WINDOW_SIZE as u64).min(search_upper_bound);
debug_assert!(end >= window_start); let cur_len = (end - window_start) as usize; if cur_len == 0 { break;
}
debug_assert!(cur_len <= END_WINDOW_SIZE); let cur_window: &mut [u8] = &mut window[..cur_len]; /* Read the window into the bytes! */
reader.read_exact(cur_window)?;
/* Find instances of the magic signature. */ for offset in finder.rfind_iter(cur_window) { let cde_start_pos = window_start + offset as u64;
reader.seek(io::SeekFrom::Start(cde_start_pos))?;
debug_assert!(cde_start_pos >= search_lower_bound); let archive_offset = cde_start_pos - search_lower_bound; let cde = Self::parse(reader)?;
results.push((cde, archive_offset));
}
/* We always want to make sure we go allllll the way back to the start of the file if *wecan'tfinditelsewhere.However,our`while`conditiondoesn'tcheckthat.Sowe
* avoid infinite looping by checking at the end of the loop. */ if window_start == search_lower_bound { break;
} /* Shift the window by END_WINDOW_SIZE bytes, but make sure to cover matches that
* overlap our nice neat window boundaries! */
window_start = (window_start /* NB: To catch matches across window boundaries, we need to make our blocks overlap
* by the width of the pattern to match. */
+ mem::size_of::<Magic>() as u64) /* This may never happen, but make sure we don't go past the end of the specified
* range. */
.min(search_upper_bound);
window_start = window_start
.saturating_sub( /* Shift the window upon each iteration so we search END_WINDOW_SIZE bytes at
* once (unless limited by search_upper_bound). */
END_WINDOW_SIZE as u64,
) /* This will never go below the value of `search_lower_bound`, so we have a special
* `if window_start == search_lower_bound` check above. */
.max(search_lower_bound);
}
if results.is_empty() {
Err(ZipError::InvalidArchive( "Could not find ZIP64 central directory end",
))
} else {
Ok(results)
}
}
/// Demonstrate that a block object can be safely written to memory and deserialized back out. #[test] fn block_serde() { let block = TestBlock {
magic: TestBlock::MAGIC,
file_name_length: 3,
}; letmut c = Cursor::new(Vec::new());
block.write(&mut c).unwrap();
c.set_position(0); let block2 = TestBlock::parse(&mut c).unwrap();
assert_eq!(block, block2);
}
}
Messung V0.5 in Prozent
¤ Dauer der Verarbeitung: 0.18 Sekunden
(vorverarbeitet am 2026-06-17)
¤
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.