From 22266dee182a8a7b23dca3765d406a669a03b260 Mon Sep 17 00:00:00 2001 From: Amos Wenger Date: Tue, 30 Jan 2024 17:02:09 +0100 Subject: [PATCH] Tests almost pass! --- crates/rc-zip/src/format/extra_field.rs | 2 +- crates/rc-zip/src/format/local.rs | 50 ++++++++++--------- crates/rc-zip/src/reader/archive_reader.rs | 2 +- .../src/reader/sync/entry_reader/mod.rs | 36 ++++++------- 4 files changed, 46 insertions(+), 44 deletions(-) diff --git a/crates/rc-zip/src/format/extra_field.rs b/crates/rc-zip/src/format/extra_field.rs index 0b4db75..0f6fb7a 100644 --- a/crates/rc-zip/src/format/extra_field.rs +++ b/crates/rc-zip/src/format/extra_field.rs @@ -14,7 +14,7 @@ pub(crate) struct ExtraFieldRecord<'a> { } impl<'a> ExtraFieldRecord<'a> { - pub(crate) fn parser(i: &mut Partial<&'_ [u8]>) -> PResult { + pub(crate) fn parser(i: &mut Partial<&'a [u8]>) -> PResult { seq! {Self { tag: le_u16, payload: length_take(le_u16), diff --git a/crates/rc-zip/src/format/local.rs b/crates/rc-zip/src/format/local.rs index 4fc42ed..553b3e1 100644 --- a/crates/rc-zip/src/format/local.rs +++ b/crates/rc-zip/src/format/local.rs @@ -84,31 +84,33 @@ pub struct DataDescriptorRecord { impl DataDescriptorRecord { const SIGNATURE: &'static str = "PK\x07\x08"; - pub fn parser(i: &mut Partial<&'_ [u8]>, is_zip64: bool) -> PResult { - // From appnote.txt: - // - // 4.3.9.3 Although not originally assigned a signature, the value - // 0x08074b50 has commonly been adopted as a signature value for the - // data descriptor record. Implementers SHOULD be aware that ZIP files - // MAY be encountered with or without this signature marking data - // descriptors and SHOULD account for either case when reading ZIP files - // to ensure compatibility. - let _ = opt(tag(Self::SIGNATURE)).parse_next(i)?; + pub fn mk_parser(is_zip64: bool) -> impl FnMut(&mut Partial<&'_ [u8]>) -> PResult { + move |i| { + // From appnote.txt: + // + // 4.3.9.3 Although not originally assigned a signature, the value + // 0x08074b50 has commonly been adopted as a signature value for the + // data descriptor record. Implementers SHOULD be aware that ZIP files + // MAY be encountered with or without this signature marking data + // descriptors and SHOULD account for either case when reading ZIP files + // to ensure compatibility. + let _ = opt(tag(Self::SIGNATURE)).parse_next(i)?; - if is_zip64 { - seq! {Self { - crc32: le_u32, - compressed_size: le_u64, - uncompressed_size: le_u64, - }} - .parse_next(i) - } else { - seq! {Self { - crc32: le_u32, - compressed_size: le_u32.map(|x| x as u64), - uncompressed_size: le_u32.map(|x| x as u64), - }} - .parse_next(i) + if is_zip64 { + seq! {Self { + crc32: le_u32, + compressed_size: le_u64, + uncompressed_size: le_u64, + }} + .parse_next(i) + } else { + seq! {Self { + crc32: le_u32, + compressed_size: le_u32.map(|x| x as u64), + uncompressed_size: le_u32.map(|x| x as u64), + }} + .parse_next(i) + } } } } diff --git a/crates/rc-zip/src/reader/archive_reader.rs b/crates/rc-zip/src/reader/archive_reader.rs index 16ca6ea..f576892 100644 --- a/crates/rc-zip/src/reader/archive_reader.rs +++ b/crates/rc-zip/src/reader/archive_reader.rs @@ -213,7 +213,7 @@ impl ArchiveReader { } } S::ReadEocd64Locator { ref mut buffer, .. } => { - let mut input = Partial::new(buffer.data()); + let input = Partial::new(buffer.data()); match EndOfCentralDirectory64Locator::parser.parse_peek(input) { Err(ErrMode::Incomplete(_)) => { // need more data diff --git a/crates/rc-zip/src/reader/sync/entry_reader/mod.rs b/crates/rc-zip/src/reader/sync/entry_reader/mod.rs index cb5da72..a12495d 100644 --- a/crates/rc-zip/src/reader/sync/entry_reader/mod.rs +++ b/crates/rc-zip/src/reader/sync/entry_reader/mod.rs @@ -23,7 +23,11 @@ use cfg_if::cfg_if; use oval::Buffer; use std::io; use tracing::trace; -use winnow::stream::Offset; +use winnow::{ + error::ErrMode, + stream::{AsBytes, Offset}, + Parser, Partial, +}; struct EntryReadMetrics { uncompressed_size: u64, @@ -77,10 +81,10 @@ where let read_bytes = self.rd.read(buffer.space())?; buffer.fill(read_bytes); - match LocalFileHeaderRecord::parser(buffer.data()) { - Ok((remaining, header)) => { - let consumed = buffer.data().offset(remaining); - buffer.consume(consumed); + let mut input = Partial::new(buffer.data()); + match LocalFileHeaderRecord::parser.parse_next(&mut input) { + Ok(header) => { + buffer.consume(input.as_bytes().offset_from(&buffer.data())); trace!("local file header: {:#?}", header); transition!(self.state => (S::ReadLocalHeader { buffer }) { @@ -98,6 +102,10 @@ where }); self.read(buf) } + Err(ErrMode::Incomplete(_)) => { + buffer.shift(); + self.read(buf) + } Err(_e) => Err(Error::Format(FormatError::InvalidLocalHeader).into()), } } @@ -168,26 +176,18 @@ where buffer.available_space() ); - match DataDescriptorRecord::parser(buffer.data(), self.inner.is_zip64) { - Ok((_remaining, descriptor)) => { + let mut input = Partial::new(buffer.data()); + match DataDescriptorRecord::mk_parser(self.inner.is_zip64).parse_next(&mut input) { + Ok(descriptor) => { + buffer.consume(input.as_bytes().offset_from(&buffer.data())); trace!("data descriptor = {:#?}", descriptor); transition!(self.state => (S::ReadDataDescriptor { metrics, header, .. }) { S::Validate { metrics, header, descriptor: Some(descriptor) } }); self.read(buf) } - Err(winnow::Err::Incomplete(_)) => { - trace!( - "incomplete! before shift, data {} / space {}", - buffer.available_data(), - buffer.available_space() - ); + Err(ErrMode::Incomplete(_)) => { buffer.shift(); - trace!( - " after shift, data {} / space {}", - buffer.available_data(), - buffer.available_space() - ); let n = self.rd.read(buffer.space())?; if n == 0 { return Err(io::ErrorKind::UnexpectedEof.into());