mirror of
https://github.com/storytold/effectcraft.git
synced 2026-10-29 20:47:18 -06:00
Merge pull request #16 from storytold/pr/never-crash-pdf
Never crash: PDF/EPS close-path, CFF outlines and PostScript radix numbers
This commit is contained in:
@@ -646,12 +646,21 @@ impl T2<'_> {
|
||||
self.path.move_to((self.x, self.y));
|
||||
self.open = true;
|
||||
}
|
||||
/// A segment before the first moveto starts at the current point.
|
||||
fn ensure_open(&mut self) {
|
||||
if !self.open {
|
||||
self.path.move_to((self.x, self.y));
|
||||
self.open = true;
|
||||
}
|
||||
}
|
||||
fn line_to(&mut self, dx: f64, dy: f64) {
|
||||
self.ensure_open();
|
||||
self.x += dx;
|
||||
self.y += dy;
|
||||
self.path.line_to((self.x, self.y));
|
||||
}
|
||||
fn curve(&mut self, d: [f64; 6]) {
|
||||
self.ensure_open();
|
||||
let (x1, y1) = (self.x + d[0], self.y + d[1]);
|
||||
let (x2, y2) = (x1 + d[2], y1 + d[3]);
|
||||
self.x = x2 + d[4];
|
||||
|
||||
@@ -7,6 +7,8 @@
|
||||
//! children are the document's **layers**: one group per top-level optional-content group
|
||||
//! (Illustrator layers), with content outside them gathered into groups of its own.
|
||||
|
||||
#![deny(clippy::unwrap_used, clippy::expect_used, clippy::panic, clippy::unimplemented, clippy::todo, clippy::unreachable)]
|
||||
|
||||
mod build;
|
||||
mod ccitt;
|
||||
mod cff;
|
||||
|
||||
+10
-3
@@ -332,7 +332,7 @@ impl<'a> Interp<'a> {
|
||||
// Painting.
|
||||
"S" => self.paint(false, None, true, depth),
|
||||
"s" => {
|
||||
self.path.close_path();
|
||||
self.close_subpath();
|
||||
self.paint(false, None, true, depth)
|
||||
}
|
||||
"f" | "F" => self.paint(true, Some(FillRule::NonZero), false, depth),
|
||||
@@ -340,11 +340,11 @@ impl<'a> Interp<'a> {
|
||||
"B" => self.paint(true, Some(FillRule::NonZero), true, depth),
|
||||
"B*" => self.paint(true, Some(FillRule::EvenOdd), true, depth),
|
||||
"b" => {
|
||||
self.path.close_path();
|
||||
self.close_subpath();
|
||||
self.paint(true, Some(FillRule::NonZero), true, depth)
|
||||
}
|
||||
"b*" => {
|
||||
self.path.close_path();
|
||||
self.close_subpath();
|
||||
self.paint(true, Some(FillRule::EvenOdd), true, depth)
|
||||
}
|
||||
"n" => self.paint(false, None, false, depth),
|
||||
@@ -549,6 +549,13 @@ impl<'a> Interp<'a> {
|
||||
}
|
||||
}
|
||||
|
||||
/// Close the current subpath; nothing to close without a current point.
|
||||
fn close_subpath(&mut self) {
|
||||
if self.cur.is_some() {
|
||||
self.path.close_path();
|
||||
}
|
||||
}
|
||||
|
||||
fn ensure_start(&mut self) {
|
||||
if self.cur.is_none() {
|
||||
self.path.move_to((0.0, 0.0));
|
||||
|
||||
@@ -278,7 +278,7 @@ impl Src<'_> {
|
||||
None => {
|
||||
// Radix numbers (16#FF).
|
||||
let s = String::from_utf8_lossy(w).into_owned();
|
||||
match s.split_once('#').and_then(|(r, v)| i64::from_str_radix(v, r.parse().ok()?).ok()) {
|
||||
match s.split_once('#').and_then(|(r, v)| i64::from_str_radix(v, r.parse::<u32>().ok().filter(|r| (2..=36).contains(r))?).ok()) {
|
||||
Some(n) => V::Num(n as f64),
|
||||
None => V::Name(s.into()),
|
||||
}
|
||||
|
||||
@@ -295,3 +295,21 @@ fn truncated_and_corrupt_eps_never_panic() {
|
||||
assert!(r.is_ok(), "{}", String::from_utf8_lossy(prog));
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn closing_an_empty_path_is_a_no_op() {
|
||||
// "s", "b" and "b*" closed the path without a current point (kurbo asserts on that).
|
||||
for ops in ["s", "b", "b*", "0 0 m 50 0 l 50 50 l b s b*", "f s 10 10 m 20 20 l s"] {
|
||||
let doc = parse(&page_pdf(ops, "", vec![])).unwrap();
|
||||
let _ = render(&doc);
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn postscript_radix_numbers_outside_2_to_36_are_not_numbers() {
|
||||
// `0#7` asked `i64::from_str_radix` for radix 0, which panics (found by fuzzing).
|
||||
for n in ["0#7", "1#1", "37#1", "99999999999#1", "16#FF"] {
|
||||
let src = format!("%!PS-Adobe-3.0 EPSF-3.0\n%%BoundingBox: 0 0 100 100\n{n} pop 0 0 moveto 10 10 lineto stroke\n");
|
||||
let _ = parse(src.as_bytes());
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user