[librsvg] (#344): Don't let a viewBox with overflowing numbers pass through
- From: Federico Mena Quintero <federico src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [librsvg] (#344): Don't let a viewBox with overflowing numbers pass through
- Date: Mon, 24 Sep 2018 15:32:00 +0000 (UTC)
commit 7b4403034e9fa52aff2ac1bc21cb3a63990cd40b
Author: Federico Mena Quintero <federico gnome org>
Date: Mon Sep 24 09:48:27 2018 -0500
(#344): Don't let a viewBox with overflowing numbers pass through
This commit adds expect_finite_number() and finite_f32() to parsers.rs.
Part of issue #344 is that we need to validate parsed numbers, as
cssparser can give us back -inf or inf when it overflows. These
values ripple down the code and end up creating a NaN inside a
cairo::Matrix, which makes it invalid.
This commit introduces a CssParserExt trait to have an
expect_finite_number() method for cssparser::Parser, and the
corresponding, low-level finite_f32() validation function.
Those functions return a Result<f32, ValueErrorKind>. This commit
makes the following return a ValueErrorKind for the error case as
well:
* impl Parse for f64
* parsers::number()
* parsers::number_optional_number()
* parsers:;integer()
* parsers::integer_optional_integer()
This has implications in all the callers, since they used to expect a
ParseError, but must now expect ValueErrorKind.
The biggest change is in transform.rs. For simplicity, the individual
parsers for transform functions now have two sections: the first
extracts f32 from cssparser::Parser, and the second validates those
numbers and computes the final result --- instead of doing everything
at the same time.
https://gitlab.gnome.org/GNOME/librsvg/issues/344
rsvg_internals/src/filters/color_matrix.rs | 4 +-
rsvg_internals/src/filters/component_transfer.rs | 30 +++---
rsvg_internals/src/filters/composite.rs | 24 ++---
rsvg_internals/src/filters/convolve_matrix.rs | 16 +--
rsvg_internals/src/filters/displacement_map.rs | 6 +-
rsvg_internals/src/filters/gaussian_blur.rs | 2 +-
rsvg_internals/src/filters/light/light_source.rs | 39 +++++---
rsvg_internals/src/filters/light/lighting.rs | 14 +--
rsvg_internals/src/filters/morphology.rs | 2 +-
rsvg_internals/src/filters/offset.rs | 12 +--
rsvg_internals/src/filters/turbulence.rs | 10 +-
rsvg_internals/src/parsers.rs | 44 ++++++---
rsvg_internals/src/shapes.rs | 2 +-
rsvg_internals/src/transform.rs | 107 ++++++++++++++-------
rsvg_internals/src/unitinterval.rs | 4 +-
rsvg_internals/src/viewbox.rs | 3 +
.../render-crash/344-too-large-viewbox.svg | 1 +
17 files changed, 199 insertions(+), 121 deletions(-)
---
diff --git a/rsvg_internals/src/filters/color_matrix.rs b/rsvg_internals/src/filters/color_matrix.rs
index 8da52bac..ec06e230 100644
--- a/rsvg_internals/src/filters/color_matrix.rs
+++ b/rsvg_internals/src/filters/color_matrix.rs
@@ -107,7 +107,7 @@ impl NodeTrait for ColorMatrix {
}
OperationType::Saturate => {
let s = parsers::number(value)
- .map_err(|err| NodeError::parse_error(attr, err))?;
+ .map_err(|err| NodeError::attribute_error(attr, err))?;
if s < 0.0 || s > 1.0 {
return Err(NodeError::value_error(attr, "expected value from 0 to 1"));
}
@@ -123,7 +123,7 @@ impl NodeTrait for ColorMatrix {
}
OperationType::HueRotate => {
let degrees = parsers::number(value)
- .map_err(|err| NodeError::parse_error(attr, err))?;
+ .map_err(|err| NodeError::attribute_error(attr, err))?;
let (sin, cos) = degrees.to_radians().sin_cos();
diff --git a/rsvg_internals/src/filters/component_transfer.rs
b/rsvg_internals/src/filters/component_transfer.rs
index 899dadce..7dc7c10b 100644
--- a/rsvg_internals/src/filters/component_transfer.rs
+++ b/rsvg_internals/src/filters/component_transfer.rs
@@ -237,21 +237,21 @@ impl NodeTrait for FuncX {
)?,
);
}
- Attribute::Slope => self
- .slope
- .set(parsers::number(value).map_err(|err| NodeError::parse_error(attr, err))?),
- Attribute::Intercept => self
- .intercept
- .set(parsers::number(value).map_err(|err| NodeError::parse_error(attr, err))?),
- Attribute::Amplitude => self
- .amplitude
- .set(parsers::number(value).map_err(|err| NodeError::parse_error(attr, err))?),
- Attribute::Exponent => self
- .exponent
- .set(parsers::number(value).map_err(|err| NodeError::parse_error(attr, err))?),
- Attribute::Offset => self
- .offset
- .set(parsers::number(value).map_err(|err| NodeError::parse_error(attr, err))?),
+ Attribute::Slope => self.slope.set(
+ parsers::number(value).map_err(|err| NodeError::attribute_error(attr, err))?,
+ ),
+ Attribute::Intercept => self.intercept.set(
+ parsers::number(value).map_err(|err| NodeError::attribute_error(attr, err))?,
+ ),
+ Attribute::Amplitude => self.amplitude.set(
+ parsers::number(value).map_err(|err| NodeError::attribute_error(attr, err))?,
+ ),
+ Attribute::Exponent => self.exponent.set(
+ parsers::number(value).map_err(|err| NodeError::attribute_error(attr, err))?,
+ ),
+ Attribute::Offset => self.offset.set(
+ parsers::number(value).map_err(|err| NodeError::attribute_error(attr, err))?,
+ ),
_ => (),
}
}
diff --git a/rsvg_internals/src/filters/composite.rs b/rsvg_internals/src/filters/composite.rs
index d8586740..c95e4edf 100644
--- a/rsvg_internals/src/filters/composite.rs
+++ b/rsvg_internals/src/filters/composite.rs
@@ -75,18 +75,18 @@ impl NodeTrait for Composite {
self.in2.replace(Some(Input::parse(Attribute::In2, value)?));
}
Attribute::Operator => self.operator.set(parse("operator", value, ())?),
- Attribute::K1 => self
- .k1
- .set(parsers::number(value).map_err(|err| NodeError::parse_error(attr, err))?),
- Attribute::K2 => self
- .k2
- .set(parsers::number(value).map_err(|err| NodeError::parse_error(attr, err))?),
- Attribute::K3 => self
- .k3
- .set(parsers::number(value).map_err(|err| NodeError::parse_error(attr, err))?),
- Attribute::K4 => self
- .k4
- .set(parsers::number(value).map_err(|err| NodeError::parse_error(attr, err))?),
+ Attribute::K1 => self.k1.set(
+ parsers::number(value).map_err(|err| NodeError::attribute_error(attr, err))?,
+ ),
+ Attribute::K2 => self.k2.set(
+ parsers::number(value).map_err(|err| NodeError::attribute_error(attr, err))?,
+ ),
+ Attribute::K3 => self.k3.set(
+ parsers::number(value).map_err(|err| NodeError::attribute_error(attr, err))?,
+ ),
+ Attribute::K4 => self.k4.set(
+ parsers::number(value).map_err(|err| NodeError::attribute_error(attr, err))?,
+ ),
_ => (),
}
}
diff --git a/rsvg_internals/src/filters/convolve_matrix.rs b/rsvg_internals/src/filters/convolve_matrix.rs
index 186fa397..d99f13ce 100644
--- a/rsvg_internals/src/filters/convolve_matrix.rs
+++ b/rsvg_internals/src/filters/convolve_matrix.rs
@@ -68,7 +68,7 @@ impl NodeTrait for ConvolveMatrix {
match attr {
Attribute::Order => self.order.set(
parsers::integer_optional_integer(value)
- .map_err(|err| NodeError::parse_error(attr, err))
+ .map_err(|err| NodeError::attribute_error(attr, err))
.and_then(|(x, y)| {
if x > 0 && y > 0 {
Ok((x as u32, y as u32))
@@ -82,7 +82,7 @@ impl NodeTrait for ConvolveMatrix {
),
Attribute::Divisor => self.divisor.set(Some(
parsers::number(value)
- .map_err(|err| NodeError::parse_error(attr, err))
+ .map_err(|err| NodeError::attribute_error(attr, err))
.and_then(|x| {
if x != 0.0 {
Ok(x)
@@ -91,13 +91,13 @@ impl NodeTrait for ConvolveMatrix {
}
})?,
)),
- Attribute::Bias => self
- .bias
- .set(parsers::number(value).map_err(|err| NodeError::parse_error(attr, err))?),
+ Attribute::Bias => self.bias.set(
+ parsers::number(value).map_err(|err| NodeError::attribute_error(attr, err))?,
+ ),
Attribute::EdgeMode => self.edge_mode.set(EdgeMode::parse(attr, value)?),
Attribute::KernelUnitLength => self.kernel_unit_length.set(Some(
parsers::number_optional_number(value)
- .map_err(|err| NodeError::parse_error(attr, err))
+ .map_err(|err| NodeError::attribute_error(attr, err))
.and_then(|(x, y)| {
if x > 0.0 && y > 0.0 {
Ok((x, y))
@@ -128,7 +128,7 @@ impl NodeTrait for ConvolveMatrix {
match attr {
Attribute::TargetX => self.target_x.set(Some(
parsers::integer(value)
- .map_err(|err| NodeError::parse_error(attr, err))
+ .map_err(|err| NodeError::attribute_error(attr, err))
.and_then(|x| {
if x >= 0 && x < self.order.get().0 as i32 {
Ok(x as u32)
@@ -142,7 +142,7 @@ impl NodeTrait for ConvolveMatrix {
)),
Attribute::TargetY => self.target_y.set(Some(
parsers::integer(value)
- .map_err(|err| NodeError::parse_error(attr, err))
+ .map_err(|err| NodeError::attribute_error(attr, err))
.and_then(|x| {
if x >= 0 && x < self.order.get().1 as i32 {
Ok(x as u32)
diff --git a/rsvg_internals/src/filters/displacement_map.rs b/rsvg_internals/src/filters/displacement_map.rs
index 91e2457a..41ac3944 100644
--- a/rsvg_internals/src/filters/displacement_map.rs
+++ b/rsvg_internals/src/filters/displacement_map.rs
@@ -60,9 +60,9 @@ impl NodeTrait for DisplacementMap {
Attribute::In2 => {
self.in2.replace(Some(Input::parse(Attribute::In2, value)?));
}
- Attribute::Scale => self
- .scale
- .set(parsers::number(value).map_err(|err| NodeError::parse_error(attr, err))?),
+ Attribute::Scale => self.scale.set(
+ parsers::number(value).map_err(|err| NodeError::attribute_error(attr, err))?,
+ ),
Attribute::XChannelSelector => self
.x_channel_selector
.set(ColorChannel::parse(attr, value)?),
diff --git a/rsvg_internals/src/filters/gaussian_blur.rs b/rsvg_internals/src/filters/gaussian_blur.rs
index 448c2553..c66e7948 100644
--- a/rsvg_internals/src/filters/gaussian_blur.rs
+++ b/rsvg_internals/src/filters/gaussian_blur.rs
@@ -55,7 +55,7 @@ impl NodeTrait for GaussianBlur {
match attr {
Attribute::StdDeviation => self.std_deviation.set(
parsers::number_optional_number(value)
- .map_err(|err| NodeError::parse_error(attr, err))
+ .map_err(|err| NodeError::attribute_error(attr, err))
.and_then(|(x, y)| {
if x >= 0.0 && y >= 0.0 {
Ok((x, y))
diff --git a/rsvg_internals/src/filters/light/light_source.rs
b/rsvg_internals/src/filters/light/light_source.rs
index f6baf80a..943d4b07 100644
--- a/rsvg_internals/src/filters/light/light_source.rs
+++ b/rsvg_internals/src/filters/light/light_source.rs
@@ -214,10 +214,12 @@ impl NodeTrait for LightSource {
ref elevation,
} => match attr {
Attribute::Azimuth => azimuth.set(
- parsers::number(value).map_err(|err| NodeError::parse_error(attr, err))?,
+ parsers::number(value)
+ .map_err(|err| NodeError::attribute_error(attr, err))?,
),
Attribute::Elevation => elevation.set(
- parsers::number(value).map_err(|err| NodeError::parse_error(attr, err))?,
+ parsers::number(value)
+ .map_err(|err| NodeError::attribute_error(attr, err))?,
),
_ => (),
},
@@ -227,13 +229,16 @@ impl NodeTrait for LightSource {
ref z,
} => match attr {
Attribute::X => x.set(
- parsers::number(value).map_err(|err| NodeError::parse_error(attr, err))?,
+ parsers::number(value)
+ .map_err(|err| NodeError::attribute_error(attr, err))?,
),
Attribute::Y => y.set(
- parsers::number(value).map_err(|err| NodeError::parse_error(attr, err))?,
+ parsers::number(value)
+ .map_err(|err| NodeError::attribute_error(attr, err))?,
),
Attribute::Z => z.set(
- parsers::number(value).map_err(|err| NodeError::parse_error(attr, err))?,
+ parsers::number(value)
+ .map_err(|err| NodeError::attribute_error(attr, err))?,
),
_ => (),
},
@@ -248,28 +253,36 @@ impl NodeTrait for LightSource {
ref limiting_cone_angle,
} => match attr {
Attribute::X => x.set(
- parsers::number(value).map_err(|err| NodeError::parse_error(attr, err))?,
+ parsers::number(value)
+ .map_err(|err| NodeError::attribute_error(attr, err))?,
),
Attribute::Y => y.set(
- parsers::number(value).map_err(|err| NodeError::parse_error(attr, err))?,
+ parsers::number(value)
+ .map_err(|err| NodeError::attribute_error(attr, err))?,
),
Attribute::Z => z.set(
- parsers::number(value).map_err(|err| NodeError::parse_error(attr, err))?,
+ parsers::number(value)
+ .map_err(|err| NodeError::attribute_error(attr, err))?,
),
Attribute::PointsAtX => points_at_x.set(
- parsers::number(value).map_err(|err| NodeError::parse_error(attr, err))?,
+ parsers::number(value)
+ .map_err(|err| NodeError::attribute_error(attr, err))?,
),
Attribute::PointsAtY => points_at_y.set(
- parsers::number(value).map_err(|err| NodeError::parse_error(attr, err))?,
+ parsers::number(value)
+ .map_err(|err| NodeError::attribute_error(attr, err))?,
),
Attribute::PointsAtZ => points_at_z.set(
- parsers::number(value).map_err(|err| NodeError::parse_error(attr, err))?,
+ parsers::number(value)
+ .map_err(|err| NodeError::attribute_error(attr, err))?,
),
Attribute::SpecularExponent => specular_exponent.set(
- parsers::number(value).map_err(|err| NodeError::parse_error(attr, err))?,
+ parsers::number(value)
+ .map_err(|err| NodeError::attribute_error(attr, err))?,
),
Attribute::LimitingConeAngle => limiting_cone_angle.set(Some(
- parsers::number(value).map_err(|err| NodeError::parse_error(attr, err))?,
+ parsers::number(value)
+ .map_err(|err| NodeError::attribute_error(attr, err))?,
)),
_ => (),
},
diff --git a/rsvg_internals/src/filters/light/lighting.rs b/rsvg_internals/src/filters/light/lighting.rs
index 2afbec73..33ab1fd5 100644
--- a/rsvg_internals/src/filters/light/lighting.rs
+++ b/rsvg_internals/src/filters/light/lighting.rs
@@ -108,12 +108,12 @@ impl NodeTrait for Lighting {
for (_key, attr, value) in pbag.iter() {
match attr {
- Attribute::SurfaceScale => self
- .surface_scale
- .set(parsers::number(value).map_err(|err| NodeError::parse_error(attr, err))?),
+ Attribute::SurfaceScale => self.surface_scale.set(
+ parsers::number(value).map_err(|err| NodeError::attribute_error(attr, err))?,
+ ),
Attribute::KernelUnitLength => self.kernel_unit_length.set(Some(
parsers::number_optional_number(value)
- .map_err(|err| NodeError::parse_error(attr, err))
+ .map_err(|err| NodeError::attribute_error(attr, err))
.and_then(|(x, y)| {
if x > 0.0 && y > 0.0 {
Ok((x, y))
@@ -137,7 +137,7 @@ impl NodeTrait for Lighting {
match attr {
Attribute::DiffuseConstant => diffuse_constant.set(
parsers::number(value)
- .map_err(|err| NodeError::parse_error(attr, err))
+ .map_err(|err| NodeError::attribute_error(attr, err))
.and_then(|x| {
if x >= 0.0 {
Ok(x)
@@ -161,7 +161,7 @@ impl NodeTrait for Lighting {
match attr {
Attribute::SpecularConstant => specular_constant.set(
parsers::number(value)
- .map_err(|err| NodeError::parse_error(attr, err))
+ .map_err(|err| NodeError::attribute_error(attr, err))
.and_then(|x| {
if x >= 0.0 {
Ok(x)
@@ -175,7 +175,7 @@ impl NodeTrait for Lighting {
),
Attribute::SpecularExponent => specular_exponent.set(
parsers::number(value)
- .map_err(|err| NodeError::parse_error(attr, err))
+ .map_err(|err| NodeError::attribute_error(attr, err))
.and_then(|x| {
if x >= 1.0 && x <= 128.0 {
Ok(x)
diff --git a/rsvg_internals/src/filters/morphology.rs b/rsvg_internals/src/filters/morphology.rs
index 892a7ad3..60fbcef0 100644
--- a/rsvg_internals/src/filters/morphology.rs
+++ b/rsvg_internals/src/filters/morphology.rs
@@ -61,7 +61,7 @@ impl NodeTrait for Morphology {
Attribute::Operator => self.operator.set(Operator::parse(attr, value)?),
Attribute::Radius => self.radius.set(
parsers::number_optional_number(value)
- .map_err(|err| NodeError::parse_error(attr, err))
+ .map_err(|err| NodeError::attribute_error(attr, err))
.and_then(|(x, y)| {
if x >= 0.0 && y >= 0.0 {
Ok((x, y))
diff --git a/rsvg_internals/src/filters/offset.rs b/rsvg_internals/src/filters/offset.rs
index 66caff87..f9f8a524 100644
--- a/rsvg_internals/src/filters/offset.rs
+++ b/rsvg_internals/src/filters/offset.rs
@@ -45,12 +45,12 @@ impl NodeTrait for Offset {
for (_key, attr, value) in pbag.iter() {
match attr {
- Attribute::Dx => self
- .dx
- .set(parsers::number(value).map_err(|err| NodeError::parse_error(attr, err))?),
- Attribute::Dy => self
- .dy
- .set(parsers::number(value).map_err(|err| NodeError::parse_error(attr, err))?),
+ Attribute::Dx => self.dx.set(
+ parsers::number(value).map_err(|err| NodeError::attribute_error(attr, err))?,
+ ),
+ Attribute::Dy => self.dy.set(
+ parsers::number(value).map_err(|err| NodeError::attribute_error(attr, err))?,
+ ),
_ => (),
}
}
diff --git a/rsvg_internals/src/filters/turbulence.rs b/rsvg_internals/src/filters/turbulence.rs
index 74883639..1425ed54 100644
--- a/rsvg_internals/src/filters/turbulence.rs
+++ b/rsvg_internals/src/filters/turbulence.rs
@@ -73,7 +73,7 @@ impl NodeTrait for Turbulence {
match attr {
Attribute::BaseFrequency => self.base_frequency.set(
parsers::number_optional_number(value)
- .map_err(|err| NodeError::parse_error(attr, err))
+ .map_err(|err| NodeError::attribute_error(attr, err))
.and_then(|(x, y)| {
if x >= 0.0 && y >= 0.0 {
Ok((x, y))
@@ -82,9 +82,9 @@ impl NodeTrait for Turbulence {
}
})?,
),
- Attribute::NumOctaves => self
- .num_octaves
- .set(parsers::integer(value).map_err(|err| NodeError::parse_error(attr, err))?),
+ Attribute::NumOctaves => self.num_octaves.set(
+ parsers::integer(value).map_err(|err| NodeError::attribute_error(attr, err))?,
+ ),
// Yes, seed needs to be parsed as a number and then truncated.
Attribute::Seed => self.seed.set(
parsers::number(value)
@@ -94,7 +94,7 @@ impl NodeTrait for Turbulence {
f64::from(i32::min_value()),
f64::from(i32::max_value()),
) as i32
- }).map_err(|err| NodeError::parse_error(attr, err))?,
+ }).map_err(|err| NodeError::attribute_error(attr, err))?,
),
Attribute::StitchTiles => self.stitch_tiles.set(StitchTiles::parse(attr, value)?),
Attribute::Type => self.type_.set(NoiseType::parse(attr, value)?),
diff --git a/rsvg_internals/src/parsers.rs b/rsvg_internals/src/parsers.rs
index 03efd310..064a6c21 100644
--- a/rsvg_internals/src/parsers.rs
+++ b/rsvg_internals/src/parsers.rs
@@ -46,12 +46,32 @@ pub trait Parse: Sized {
}
}
+/// Extend `cssparser::Parser` with a `expect_finite_number` method,
+/// to avoid infinities.
+pub trait CssParserExt {
+ fn expect_finite_number(&mut self) -> Result<f32, ValueErrorKind>;
+}
+
+impl<'i, 't> CssParserExt for Parser<'i, 't> {
+ fn expect_finite_number(&mut self) -> Result<f32, ValueErrorKind> {
+ finite_f32(self.expect_number()?)
+ }
+}
+
+pub fn finite_f32(n: f32) -> Result<f32, ValueErrorKind> {
+ if n.is_finite() {
+ Ok(n)
+ } else {
+ Err(ValueErrorKind::Value("expected finite number".to_string()))
+ }
+}
+
impl Parse for f64 {
type Data = ();
type Err = ValueErrorKind;
fn parse(parser: &mut Parser<'_, '_>, _: ()) -> Result<f64, ValueErrorKind> {
- Ok(f64::from(parser.expect_number().map_err(|_| {
+ Ok(f64::from(parser.expect_finite_number().map_err(|_| {
ValueErrorKind::Parse(ParseError::new("expected number"))
})?))
}
@@ -161,22 +181,22 @@ pub fn optional_comma(parser: &mut Parser<'_, '_>) {
// number
//
// https://www.w3.org/TR/SVG11/types.html#DataTypeNumber
-pub fn number(s: &str) -> Result<f64, ParseError> {
+pub fn number(s: &str) -> Result<f64, ValueErrorKind> {
let mut input = ParserInput::new(s);
let mut parser = Parser::new(&mut input);
- Ok(f64::from(parser.expect_number()?))
+ Ok(f64::from(parser.expect_finite_number()?))
}
// number-optional-number
//
// https://www.w3.org/TR/SVG/types.html#DataTypeNumberOptionalNumber
-pub fn number_optional_number(s: &str) -> Result<(f64, f64), ParseError> {
+pub fn number_optional_number(s: &str) -> Result<(f64, f64), ValueErrorKind> {
let mut input = ParserInput::new(s);
let mut parser = Parser::new(&mut input);
- let x = f64::from(parser.expect_number()?);
+ let x = f64::from(parser.expect_finite_number()?);
if !parser.is_exhausted() {
let state = parser.state();
@@ -186,7 +206,7 @@ pub fn number_optional_number(s: &str) -> Result<(f64, f64), ParseError> {
_ => parser.reset(&state),
};
- let y = f64::from(parser.expect_number()?);
+ let y = f64::from(parser.expect_finite_number()?);
parser.expect_exhausted()?;
@@ -199,7 +219,7 @@ pub fn number_optional_number(s: &str) -> Result<(f64, f64), ParseError> {
// integer
//
// https://www.w3.org/TR/SVG11/types.html#DataTypeInteger
-pub fn integer(s: &str) -> Result<i32, ParseError> {
+pub fn integer(s: &str) -> Result<i32, ValueErrorKind> {
let mut input = ParserInput::new(s);
let mut parser = Parser::new(&mut input);
@@ -209,7 +229,7 @@ pub fn integer(s: &str) -> Result<i32, ParseError> {
// integer-optional-integer
//
// Like number-optional-number but with integers.
-pub fn integer_optional_integer(s: &str) -> Result<(i32, i32), ParseError> {
+pub fn integer_optional_integer(s: &str) -> Result<(i32, i32), ValueErrorKind> {
let mut input = ParserInput::new(s);
let mut parser = Parser::new(&mut input);
@@ -267,18 +287,18 @@ pub extern "C" fn rsvg_css_parse_number_optional_number(
// Parse a list-of-points as for polyline and polygon elements
// https://www.w3.org/TR/SVG/shapes.html#PointsBNF
-pub fn list_of_points(string: &str) -> Result<Vec<(f64, f64)>, ParseError> {
+pub fn list_of_points(string: &str) -> Result<Vec<(f64, f64)>, ValueErrorKind> {
let mut input = ParserInput::new(string);
let mut parser = Parser::new(&mut input);
let mut v = Vec::new();
loop {
- let x = f64::from(parser.expect_number()?);
+ let x = f64::from(parser.expect_finite_number()?);
optional_comma(&mut parser);
- let y = f64::from(parser.expect_number()?);
+ let y = f64::from(parser.expect_finite_number()?);
v.push((x, y));
@@ -336,7 +356,7 @@ pub fn number_list(
optional_comma(parser);
}
- v.push(f64::from(parser.expect_number().map_err(|_| {
+ v.push(f64::from(parser.expect_finite_number().map_err(|_| {
NumberListError::Parse(ParseError::new("expected number"))
})?));
diff --git a/rsvg_internals/src/shapes.rs b/rsvg_internals/src/shapes.rs
index 87e40ae8..03a626c1 100644
--- a/rsvg_internals/src/shapes.rs
+++ b/rsvg_internals/src/shapes.rs
@@ -198,7 +198,7 @@ impl NodeTrait for NodePoly {
}
Err(e) => {
- return Err(NodeError::parse_error(attr, e));
+ return Err(NodeError::attribute_error(attr, e));
}
}
}
diff --git a/rsvg_internals/src/transform.rs b/rsvg_internals/src/transform.rs
index 01c572a6..886dd967 100644
--- a/rsvg_internals/src/transform.rs
+++ b/rsvg_internals/src/transform.rs
@@ -6,7 +6,7 @@ use cairo::MatrixTrait;
use cssparser::{ParseError as CssParseError, Parser, Token};
use error::*;
-use parsers::{optional_comma, Parse, ParseError};
+use parsers::{finite_f32, optional_comma, Parse, ParseError};
impl Parse for cairo::Matrix {
type Data = ();
@@ -80,104 +80,145 @@ fn parse_transform_function(
fn parse_matrix_args(parser: &mut Parser<'_, '_>) -> Result<cairo::Matrix, ValueErrorKind> {
parser
.parse_nested_block(|p| {
- let xx = f64::from(p.expect_number()?);
+ let xx = p.expect_number()?;
optional_comma(p);
- let yx = f64::from(p.expect_number()?);
+ let yx = p.expect_number()?;
optional_comma(p);
- let xy = f64::from(p.expect_number()?);
+ let xy = p.expect_number()?;
optional_comma(p);
- let yy = f64::from(p.expect_number()?);
+ let yy = p.expect_number()?;
optional_comma(p);
- let x0 = f64::from(p.expect_number()?);
+ let x0 = p.expect_number()?;
optional_comma(p);
- let y0 = f64::from(p.expect_number()?);
+ let y0 = p.expect_number()?;
- Ok(cairo::Matrix::new(xx, yx, xy, yy, x0, y0))
+ Ok((xx, yx, xy, yy, x0, y0))
}).map_err(CssParseError::<()>::basic)
- .map_err(ValueErrorKind::from)
+ .map_err(|e| ValueErrorKind::from(e))
+ .and_then(|(xx, yx, xy, yy, x0, y0)| {
+ let xx = f64::from(finite_f32(xx)?);
+ let yx = f64::from(finite_f32(yx)?);
+ let xy = f64::from(finite_f32(xy)?);
+ let yy = f64::from(finite_f32(yy)?);
+ let x0 = f64::from(finite_f32(x0)?);
+ let y0 = f64::from(finite_f32(y0)?);
+
+ Ok(cairo::Matrix::new(xx, yx, xy, yy, x0, y0))
+ })
}
fn parse_translate_args(parser: &mut Parser<'_, '_>) -> Result<cairo::Matrix, ValueErrorKind> {
parser
.parse_nested_block(|p| {
- let tx = f64::from(p.expect_number()?);
+ let tx = p.expect_number()?;
- let ty = f64::from(
- p.try(|p| -> Result<f32, CssParseError<'_, ()>> {
+ let ty = p
+ .try(|p| -> Result<f32, CssParseError<'_, ()>> {
optional_comma(p);
Ok(p.expect_number()?)
- }).unwrap_or(0.0),
- );
+ }).unwrap_or(0.0);
- Ok(cairo::Matrix::new(1.0, 0.0, 0.0, 1.0, tx, ty))
+ Ok((tx, ty))
}).map_err(CssParseError::<()>::basic)
- .map_err(ValueErrorKind::from)
+ .map_err(|e| ValueErrorKind::from(e))
+ .and_then(|(tx, ty)| {
+ let tx = f64::from(finite_f32(tx)?);
+ let ty = f64::from(finite_f32(ty)?);
+
+ Ok(cairo::Matrix::new(1.0, 0.0, 0.0, 1.0, tx, ty))
+ })
}
fn parse_scale_args(parser: &mut Parser<'_, '_>) -> Result<cairo::Matrix, ValueErrorKind> {
parser
.parse_nested_block(|p| {
- let x = f64::from(p.expect_number()?);
+ let x = p.expect_number()?;
let y = p
.try(|p| -> Result<f32, CssParseError<'_, ()>> {
optional_comma(p);
Ok(p.expect_number()?)
- }).map(f64::from)
- .unwrap_or(x);
+ }).unwrap_or(x);
- Ok(cairo::Matrix::new(x, 0.0, 0.0, y, 0.0, 0.0))
+ Ok((x, y))
}).map_err(CssParseError::<()>::basic)
- .map_err(ValueErrorKind::from)
+ .map_err(|e| ValueErrorKind::from(e))
+ .and_then(|(x, y)| {
+ let x = f64::from(finite_f32(x)?);
+ let y = f64::from(finite_f32(y)?);
+
+ Ok(cairo::Matrix::new(x, 0.0, 0.0, y, 0.0, 0.0))
+ })
}
fn parse_rotate_args(parser: &mut Parser<'_, '_>) -> Result<cairo::Matrix, ValueErrorKind> {
parser
.parse_nested_block(|p| {
- let angle = f64::from(p.expect_number()?) * PI / 180.0;
- let (s, c) = angle.sin_cos();
+ let angle = p.expect_number()?;
let (tx, ty) = p
.try(|p| -> Result<_, CssParseError<'_, ()>> {
optional_comma(p);
- let tx = f64::from(p.expect_number()?);
+ let tx = p.expect_number()?;
optional_comma(p);
- let ty = f64::from(p.expect_number()?);
+ let ty = p.expect_number()?;
Ok((tx, ty))
}).unwrap_or((0.0, 0.0));
+ Ok((angle, tx, ty))
+ }).map_err(CssParseError::<()>::basic)
+ .map_err(|e| ValueErrorKind::from(e))
+ .and_then(|(angle, tx, ty)| {
+ let angle = f64::from(finite_f32(angle)?);
+ let tx = f64::from(finite_f32(tx)?);
+ let ty = f64::from(finite_f32(ty)?);
+
+ let angle = angle * PI / 180.0;
+ let (s, c) = angle.sin_cos();
+
let mut m = cairo::Matrix::new(1.0, 0.0, 0.0, 1.0, tx, ty);
m = cairo::Matrix::multiply(&cairo::Matrix::new(c, s, -s, c, 0.0, 0.0), &m);
m = cairo::Matrix::multiply(&cairo::Matrix::new(1.0, 0.0, 0.0, 1.0, -tx, -ty), &m);
Ok(m)
- }).map_err(CssParseError::<()>::basic)
- .map_err(ValueErrorKind::from)
+ })
}
fn parse_skewx_args(parser: &mut Parser<'_, '_>) -> Result<cairo::Matrix, ValueErrorKind> {
parser
.parse_nested_block(|p| {
- let a = f64::from(p.expect_number()?) * PI / 180.0;
- Ok(cairo::Matrix::new(1.0, 0.0, a.tan(), 1.0, 0.0, 0.0))
+ let a = p.expect_number()?;
+ Ok(a)
}).map_err(CssParseError::<()>::basic)
- .map_err(ValueErrorKind::from)
+ .map_err(|e| ValueErrorKind::from(e))
+ .and_then(|a| {
+ let a = f64::from(finite_f32(a)?);
+
+ let a = a * PI / 180.0;
+ Ok(cairo::Matrix::new(1.0, 0.0, a.tan(), 1.0, 0.0, 0.0))
+ })
}
fn parse_skewy_args(parser: &mut Parser<'_, '_>) -> Result<cairo::Matrix, ValueErrorKind> {
parser
.parse_nested_block(|p| {
- let a = f64::from(p.expect_number()?) * PI / 180.0;
- Ok(cairo::Matrix::new(1.0, a.tan(), 0.0, 1.0, 0.0, 0.0))
+ let a = p.expect_number()?;
+ Ok(a)
}).map_err(CssParseError::<()>::basic)
- .map_err(ValueErrorKind::from)
+ .map_err(|e| ValueErrorKind::from(e))
+ .and_then(|a| {
+ let a = f64::from(finite_f32(a)?);
+
+ let a = a * PI / 180.0;
+ Ok(cairo::Matrix::new(1.0, a.tan(), 0.0, 1.0, 0.0, 0.0))
+ })
}
#[cfg(test)]
diff --git a/rsvg_internals/src/unitinterval.rs b/rsvg_internals/src/unitinterval.rs
index a0ff916d..a4973044 100644
--- a/rsvg_internals/src/unitinterval.rs
+++ b/rsvg_internals/src/unitinterval.rs
@@ -1,7 +1,7 @@
use cssparser::Parser;
use error::*;
-use parsers::{Parse, ParseError};
+use parsers::{CssParserExt, Parse, ParseError};
#[derive(Debug, Copy, Clone, PartialEq)]
pub struct UnitInterval(pub f64);
@@ -19,7 +19,7 @@ impl Parse for UnitInterval {
fn parse(parser: &mut Parser<'_, '_>, _: ()) -> Result<UnitInterval, ValueErrorKind> {
let x = f64::from(
parser
- .expect_number()
+ .expect_finite_number()
.map_err(|_| ValueErrorKind::Parse(ParseError::new("expected number")))?,
);
diff --git a/rsvg_internals/src/viewbox.rs b/rsvg_internals/src/viewbox.rs
index cc7d7bc3..a26f8239 100644
--- a/rsvg_internals/src/viewbox.rs
+++ b/rsvg_internals/src/viewbox.rs
@@ -86,5 +86,8 @@ mod tests {
assert!(is_parse_error(&ViewBox::parse_str(" 1 2 3 4 5", ())));
assert!(is_parse_error(&ViewBox::parse_str(" 1 2 foo 3 4", ())));
+
+ // https://gitlab.gnome.org/GNOME/librsvg/issues/344
+ assert!(is_parse_error(&ViewBox::parse_str("0 0 9E80.7", ())));
}
}
diff --git a/tests/fixtures/render-crash/344-too-large-viewbox.svg
b/tests/fixtures/render-crash/344-too-large-viewbox.svg
new file mode 100644
index 00000000..ff89b5a0
--- /dev/null
+++ b/tests/fixtures/render-crash/344-too-large-viewbox.svg
@@ -0,0 +1 @@
+<svg width="8" viewBox="0 0 9E80.7"></svg>
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]