/// A utility for finding magic symbols from the end of a seekable reader. /// /// Can be repurposed to recycle the internal buffer. pubstruct MagicFinder<Direction> {
buffer: Box<[u8]>, pub(self) finder: Direction,
cursor: u64,
mid_buffer_offset: Option<usize>,
bounds: (u64, u64),
}
impl<'a, T: FinderDirection<'a>> MagicFinder<T> { /// Create a new magic bytes finder to look within specific bounds. pubfn new(magic_bytes: &'a [u8], start_inclusive: u64, end_exclusive: u64) -> Self { const BUFFER_SIZE: usize = 2048;
// Smaller buffer size would be unable to locate bytes. // Equal buffer size would stall (the window could not be moved).
debug_assert!(BUFFER_SIZE >= magic_bytes.len());
/// Repurpose the finder for different bytes or bounds. pubfn repurpose(&mutself, magic_bytes: &'a [u8], bounds: (u64, u64)) -> &mut Self {
debug_assert!(self.buffer.len() >= magic_bytes.len());
// Reset the mid-buffer offset, to invalidate buffer content. self.mid_buffer_offset = None;
self
}
/// Find the next magic bytes in the direction specified in the type. pubfn next<R: Read + Seek>(&mutself, reader: &mut R) -> ZipResult<Option<u64>> { loop { ifself.cursor < self.bounds.0 || self.cursor >= self.bounds.1 { // The finder is consumed break;
}
/* Position the window and ensure correct length */ let window_start = self.cursor; let window_end = self
.cursor
.saturating_add(self.buffer.len() as u64)
.min(self.bounds.1);
if window_end <= window_start { // Short-circuit on zero-sized windows to prevent loop break;
}
let window = &mutself.buffer[..(window_end - window_start) as usize];
matchself
.finder
.move_cursor(self.cursor, self.bounds, self.buffer.len())
{
Some(new_cursor) => { self.cursor = new_cursor;
}
None => { // Destroy the finder when we've reached the end of the bounds. self.bounds.0 = self.bounds.1; break;
}
}
}
Ok(None)
}
}
/// A magic bytes finder with an optimistic guess that is tried before /// the inner finder begins searching from end. This enables much faster /// lookup in files without appended junk, because the magic bytes will be /// found directly. /// /// The guess can be marked as mandatory to produce an error. This is useful /// if the ArchiveOffset is known and auto-detection is not desired. pubstruct OptimisticMagicFinder<Direction> {
inner: MagicFinder<Direction>,
initial_guess: Option<(u64, bool)>,
}
/// This is a temporary restriction, to avoid heap allocation in [`Self::next_back`]. /// /// We only use magic bytes of size 4 at the moment. const STACK_BUFFER_SIZE: usize = 8;
/// Equivalent to `next_back`, with an optional initial guess attempted before /// proceeding with reading from the back of the reader. pubfn next<R: Read + Seek>(&mutself, reader: &mut R) -> ZipResult<Option<u64>> { iflet Some((v, mandatory)) = self.initial_guess {
reader.seek(SeekFrom::Start(v))?;
letmut buffer = [0; STACK_BUFFER_SIZE]; let buffer = &mut buffer[..self.inner.finder.needle().len()];
// Attempt to match only if there's enough space for the needle if v.saturating_add(buffer.len() as u64) <= self.inner.bounds.1 {
reader.read_exact(buffer)?;
// If a match is found, yield it. ifself.inner.finder.needle() == buffer { self.initial_guess.take();
reader.seek(SeekFrom::Start(v))?; return Ok(Some(v));
}
}
// If a match is not found, but the initial guess was mandatory, return an error. if mandatory { return Ok(None);
}
// If the initial guess was not mandatory, remove it, as it was not found. self.initial_guess.take();
}
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.