From 38008d6a84457afad717e4524adcf963305fb0b7 Mon Sep 17 00:00:00 2001 From: Micha White Date: Mon, 13 Feb 2023 00:53:32 -0500 Subject: check for non-zero padding --- tvg/src/lib.rs | 16 +++++++++------- tvg/src/path.rs | 54 ++++++++++++++++++++++++++++++++++++++++-------------- 2 files changed, 49 insertions(+), 21 deletions(-) diff --git a/tvg/src/lib.rs b/tvg/src/lib.rs index 3b585d7..6b07ff0 100644 --- a/tvg/src/lib.rs +++ b/tvg/src/lib.rs @@ -77,19 +77,21 @@ impl TvgFile { pub enum TvgError { #[error("Not a valid TVG file. The magic number was invalid.")] InvalidFile, - #[error("Expected version 1, but found version {}", .0)] + #[error("Expected version 1, but found version {}.", .0)] UnsupportedVersion(u8), - #[error("Found a coordinate range with an index of 3, which is invalid")] + #[error("Found a coordinate range with an index of 3, which is invalid.")] InvalidCoordinateRange, - #[error("Found a Custom color encoding, which is unsupported")] + #[error("Found a Custom color encoding, which is unsupported.")] UnsupportedColorEncoding, - #[error("Found a command with an index of {}, which is invalid", .0)] + #[error("Found a command with an index of {}, which is invalid.", .0)] InvalidCommand(u8), - #[error("Found a style kind with an index of 3, which is invalid")] + #[error("Found a style kind with an index of 3, which is invalid.")] InvalidStyleKind, - #[error("Polygons must have at least 3 points, found {}", .0)] + #[error("Polygons must have at least 3 points, found {}.", .0)] InvalidPolygon(u32), - #[error("The end of the document must have a `prim_style_kind` value of 0. Found {}", .0)] + #[error("All padding bits must be zero. Found {}.", .0)] + NonZeroPadding(u8), + #[error("The end of the document must have a `prim_style_kind` value of 0. Found {}.", .0)] InvalidEndOfDocument(u8), #[error("{}", .0)] IoError(#[from] io::Error), diff --git a/tvg/src/path.rs b/tvg/src/path.rs index d2bf4fb..2bc0448 100644 --- a/tvg/src/path.rs +++ b/tvg/src/path.rs @@ -1,9 +1,19 @@ -use std::io::{self, Read}; +use std::io::Read; use byteorder::ReadBytesExt; use num_enum::TryFromPrimitive; +use raise::yeet; -use crate::{header::TvgHeader, read_unit, read_varuint, Decode, Point}; +use crate::{header::TvgHeader, read_unit, read_varuint, Decode, Point, TvgError}; + +/// Returns an error if the padding isn't zero +fn check_padding(padding: u8) -> Result<(), TvgError> { + if padding != 0 { + yeet!(TvgError::NonZeroPadding(padding)) + } + + Ok(()) +} #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, TryFromPrimitive)] #[repr(u8)] @@ -122,7 +132,11 @@ enum InstructionData { } impl InstructionData { - fn read(reader: &mut impl Read, header: &TvgHeader, kind: InstructionKind) -> io::Result { + fn read( + reader: &mut impl Read, + header: &TvgHeader, + kind: InstructionKind, + ) -> Result { match kind { InstructionKind::Line => Self::read_line(reader, header), InstructionKind::HorizontalLine => Self::read_horizontal_line(reader, header), @@ -135,25 +149,25 @@ impl InstructionData { } } - fn read_line(reader: &mut impl Read, header: &TvgHeader) -> io::Result { + fn read_line(reader: &mut impl Read, header: &TvgHeader) -> Result { Ok(Self::Line { position: Point::read(reader, header)?, }) } - fn read_horizontal_line(reader: &mut impl Read, header: &TvgHeader) -> io::Result { + fn read_horizontal_line(reader: &mut impl Read, header: &TvgHeader) -> Result { Ok(Self::HorizontalLine { x: read_unit(reader, header)?, }) } - fn read_vertical_line(reader: &mut impl Read, header: &TvgHeader) -> io::Result { + fn read_vertical_line(reader: &mut impl Read, header: &TvgHeader) -> Result { Ok(Self::VerticalLine { y: read_unit(reader, header)?, }) } - fn read_cubic_bezier(reader: &mut impl Read, header: &TvgHeader) -> io::Result { + fn read_cubic_bezier(reader: &mut impl Read, header: &TvgHeader) -> Result { Ok(Self::CubicBezier { control_0: Point::read(reader, header)?, control_1: Point::read(reader, header)?, @@ -161,7 +175,10 @@ impl InstructionData { }) } - fn read_arc_header(reader: &mut impl Read, header: &TvgHeader) -> io::Result<(bool, Sweep)> { + fn read_arc_header( + reader: &mut impl Read, + header: &TvgHeader, + ) -> Result<(bool, Sweep), TvgError> { // large_arc and sweep are stored in the same byte let byte = reader.read_u8()?; let large_arc = (byte & 1) != 0; @@ -170,10 +187,12 @@ impl InstructionData { _ => Sweep::Right, }; + check_padding((byte & 0b1111_1100) >> 2)?; + Ok((large_arc, sweep)) } - fn read_arc_circle(reader: &mut impl Read, header: &TvgHeader) -> io::Result { + fn read_arc_circle(reader: &mut impl Read, header: &TvgHeader) -> Result { let (large_arc, sweep) = Self::read_arc_header(reader, header)?; let radius = read_unit(reader, header)?; let target = Point::read(reader, header)?; @@ -186,7 +205,7 @@ impl InstructionData { }) } - fn read_arc_ellipse(reader: &mut impl Read, header: &TvgHeader) -> io::Result { + fn read_arc_ellipse(reader: &mut impl Read, header: &TvgHeader) -> Result { let (large_arc, sweep) = Self::read_arc_header(reader, header)?; let radius_x = read_unit(reader, header)?; let radius_y = read_unit(reader, header)?; @@ -203,7 +222,7 @@ impl InstructionData { }) } - fn read_quadratic_bezier(reader: &mut impl Read, header: &TvgHeader) -> io::Result { + fn read_quadratic_bezier(reader: &mut impl Read, header: &TvgHeader) -> Result { Ok(Self::QuadraticBezier { control: Point::read(reader, header)?, target: Point::read(reader, header)?, @@ -220,12 +239,15 @@ struct Instruction { } impl Instruction { - fn read(reader: &mut impl Read, header: &TvgHeader) -> io::Result { + fn read(reader: &mut impl Read, header: &TvgHeader) -> Result { let byte = reader.read_u8()?; let instruction_kind = InstructionKind::try_from_primitive(byte & 0b0000_0111).expect("invalid instruction"); let has_line_width = (byte & 0b0001_0000) != 0; + check_padding((byte & 0b0000_1000) >> 3)?; + check_padding((byte & 0b1110_0000) >> 5)?; + let line_width = has_line_width .then(|| read_unit(reader, header)) .transpose()?; @@ -244,7 +266,11 @@ struct Segment { } impl Segment { - fn read(reader: &mut impl Read, header: &TvgHeader, segment_length: u32) -> io::Result { + fn read( + reader: &mut impl Read, + header: &TvgHeader, + segment_length: u32, + ) -> Result { let start = Point::read(reader, header)?; let mut instructions = Vec::with_capacity(segment_length as usize); @@ -276,7 +302,7 @@ impl Path { reader: &mut impl Read, header: &TvgHeader, segment_count: u32, - ) -> io::Result { + ) -> Result { let mut segment_lengths = Vec::with_capacity(segment_count as usize); for _ in 0..segment_count { segment_lengths.push(read_varuint(reader)? + 1); -- cgit v1.2.3