Skip to content

Commit

Permalink
webpsan: use dyn in ChunkReader to prevent multiple instantiations
Browse files Browse the repository at this point in the history
  • Loading branch information
jessa0 committed Oct 22, 2023
1 parent d467ff6 commit cdf2717
Show file tree
Hide file tree
Showing 2 changed files with 24 additions and 20 deletions.
34 changes: 18 additions & 16 deletions webpsan/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,10 @@ pub const MAX_FILE_LEN: u32 = u32::MAX - 2;
// private types
//

trait ReadSkip: Read + Skip {}

type DynChunkReader<'a> = ChunkReader<dyn ReadSkip + 'a>;

#[derive(Clone, Copy, Debug, Display)]
#[display(fmt = "frame dimensions `{_0}`x`{_1}` do not match canvas dimensions `{_2}`x`{_3}`")]
struct FrameDimensionsMismatch(NonZeroU16, NonZeroU16, NonZeroU32, NonZeroU32);
Expand Down Expand Up @@ -101,8 +105,8 @@ pub fn sanitize<R: Read + Skip>(input: R) -> Result<(), Error> {
/// If the input cannot be parsed, or an IO error occurs, an [`Error`] is returned.
///
/// [`Seek`]: std::io::Seek
pub fn sanitize_with_config<R: Read + Skip>(input: R, config: Config) -> Result<(), Error> {
let mut file_reader = ChunkReader::new(input, RIFF);
pub fn sanitize_with_config<R: Read + Skip>(mut input: R, config: Config) -> Result<(), Error> {
let file_reader: &mut DynChunkReader<'_> = &mut ChunkReader::new(&mut input, RIFF);
let InputSpan { offset, len } = file_reader.read_header(RIFF)?;
let WebpChunk = file_reader.parse_data()?;

Expand All @@ -112,7 +116,7 @@ pub fn sanitize_with_config<R: Read + Skip>(input: R, config: Config) -> Result<
WhileParsingChunk(RIFF)
);

let mut reader = file_reader.child_reader();
let reader: &mut DynChunkReader<'_> = &mut file_reader.child_reader();

log::info!("{name} @ 0x{offset:08x}: {len} bytes", name = RIFF);

Expand All @@ -134,7 +138,7 @@ pub fn sanitize_with_config<R: Read + Skip>(input: R, config: Config) -> Result<
let (width, height) = (vp8x.canvas_width(), vp8x.canvas_height());
log::info!("{name} @ 0x{offset:08x}: {width}x{height}, flags {flags:08b}");

sanitize_extended(&mut reader, &vp8x, &config)?
sanitize_extended(reader, &vp8x, &config)?
}
_ => {
log::info!("{name} @ 0x{offset:08x}: {len} bytes");
Expand Down Expand Up @@ -172,11 +176,7 @@ pub fn sanitize_with_config<R: Read + Skip>(input: R, config: Config) -> Result<
Ok(())
}

fn sanitize_extended<R: Read + Skip>(
reader: &mut ChunkReader<R>,
vp8x: &Vp8xChunk,
config: &Config,
) -> Result<(), Error> {
fn sanitize_extended(reader: &mut DynChunkReader<'_>, vp8x: &Vp8xChunk, config: &Config) -> Result<(), Error> {
if vp8x.flags.contains(Vp8xFlags::HAS_ICCP_CHUNK) {
let InputSpan { offset, len } = reader.read_header(ICCP)?;
reader.skip_data()?;
Expand Down Expand Up @@ -204,7 +204,7 @@ fn sanitize_extended<R: Read + Skip>(
Ok(())
}

fn sanitize_still<R: Read + Skip>(reader: &mut ChunkReader<R>, vp8x: &Vp8xChunk) -> Result<(), Error> {
fn sanitize_still(reader: &mut DynChunkReader<'_>, vp8x: &Vp8xChunk) -> Result<(), Error> {
let mut alph = None;
if vp8x.flags.contains(Vp8xFlags::HAS_ALPH_CHUNK) {
let InputSpan { offset, len } = reader.read_header(ALPH)?;
Expand Down Expand Up @@ -246,11 +246,7 @@ fn sanitize_still<R: Read + Skip>(reader: &mut ChunkReader<R>, vp8x: &Vp8xChunk)
Ok(())
}

fn sanitize_animated<R: Read + Skip>(
reader: &mut ChunkReader<R>,
vp8x: &Vp8xChunk,
config: &Config,
) -> Result<(), Error> {
fn sanitize_animated(reader: &mut DynChunkReader<'_>, vp8x: &Vp8xChunk, config: &Config) -> Result<(), Error> {
let InputSpan { offset, len } = reader.read_header(ANIM)?;
let AnimChunk { .. } = reader.parse_data()?;
log::info!("{name} @ 0x{offset:08x}: {len} bytes", name = ANIM);
Expand All @@ -270,7 +266,7 @@ fn sanitize_animated<R: Read + Skip>(
name = ANMF
);

let mut anmf_reader = reader.child_reader();
let anmf_reader: &mut DynChunkReader<'_> = &mut reader.child_reader();

let mut alph = None;
if vp8x.flags.contains(Vp8xFlags::HAS_ALPH_CHUNK) {
Expand Down Expand Up @@ -367,6 +363,12 @@ impl ConfigBuilder {
}
}

//
// ReadSkip impls
//

impl<T: Read + Skip> ReadSkip for T {}

#[cfg(doctest)]
#[doc = include_str!("../README.md")]
pub mod readme {}
Expand Down
10 changes: 6 additions & 4 deletions webpsan/src/reader.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,12 +13,12 @@ use crate::parse::error::{ExpectedChunk, ParseResultExt, WhileParsingChunk};
use crate::parse::{ChunkHeader, ParseChunk, ParseError, WebmPrim};
use crate::Error;

pub struct ChunkReader<R> {
pub struct ChunkReader<R: ?Sized> {
state: State,
inner: BufReader<R>,
}

pub struct ChunkDataReader<'a, R> {
pub struct ChunkDataReader<'a, R: ?Sized> {
reader: &'a mut ChunkReader<R>,
}

Expand All @@ -40,7 +40,9 @@ impl<R: Read + Skip> ChunkReader<R> {
let inner = BufReader::with_capacity(ChunkHeader::ENCODED_LEN as usize, input);
Self { state: State::Idle { last: chunk_name }, inner }
}
}

impl<R: Read + Skip + ?Sized> ChunkReader<R> {
pub fn has_remaining(&mut self) -> Result<bool, Error> {
match self.read_padding()? {
State::Idle { .. } => (),
Expand Down Expand Up @@ -240,7 +242,7 @@ impl<R: Read + Skip> ChunkReader<R> {
// ChunkDataReader impls
//

impl<R: Read> Read for ChunkDataReader<'_, R> {
impl<R: Read + ?Sized> Read for ChunkDataReader<'_, R> {
fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
let (header, remaining) = match &self.reader.state {
State::Idle { .. } | State::ReadingPadding { .. } => return Ok(0),
Expand All @@ -260,7 +262,7 @@ impl<R: Read> Read for ChunkDataReader<'_, R> {
}
}

impl<R: Read + Skip> Skip for ChunkDataReader<'_, R> {
impl<R: Read + Skip + ?Sized> Skip for ChunkDataReader<'_, R> {
fn skip(&mut self, skip_amount: u64) -> io::Result<()> {
let (header, remaining) = match &self.reader.state {
State::Idle { .. } | State::ReadingPadding { .. } if skip_amount == 0 => return Ok(()),
Expand Down

0 comments on commit cdf2717

Please sign in to comment.