From f953b33d4e8e2bc038ff6b0845d540fbcb23c254 Mon Sep 17 00:00:00 2001 From: ldm0 Date: Tue, 1 Sep 2026 09:20:10 +0800 Subject: [PATCH] fix(svg): reject trailing decimal path numbers --- moli-svg/src/path.rs | 55 +++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 54 insertions(+), 1 deletion(-) diff --git a/moli-svg/src/path.rs b/moli-svg/src/path.rs index 452f101f0c..3c2065a649 100644 --- a/moli-svg/src/path.rs +++ b/moli-svg/src/path.rs @@ -3,7 +3,7 @@ use svgtypes::{SimplePathSegment, SimplifyingPathParser}; pub(crate) fn path_geometry(raw: &str) -> Option { let mut path = BezPath::new(); - for segment in SimplifyingPathParser::from(raw) { + for segment in SimplifyingPathParser::from(path_data_before_invalid_number(raw)) { let Ok(segment) = segment else { break; }; @@ -26,3 +26,56 @@ pub(crate) fn path_geometry(raw: &str) -> Option { } Some(path) } + +fn path_data_before_invalid_number(raw: &str) -> &str { + let bytes = raw.as_bytes(); + let mut position = 0; + while let Some(&byte) = bytes.get(position) { + match byte { + b'\t' | b'\n' | b'\x0c' | b'\r' | b' ' | b',' | b'A' | b'C' | b'H' | b'L' | b'M' + | b'Q' | b'S' | b'T' | b'V' | b'Z' | b'a' | b'c' | b'h' | b'l' | b'm' | b'q' | b's' + | b't' | b'v' | b'z' => position += 1, + b'+' | b'-' | b'.' | b'0'..=b'9' => { + let number_start = position; + if matches!(bytes[position], b'+' | b'-') { + position += 1; + } + + let integer_start = position; + while bytes.get(position).is_some_and(u8::is_ascii_digit) { + position += 1; + } + let has_integer = position != integer_start; + + if bytes.get(position) == Some(&b'.') { + position += 1; + let fraction_start = position; + while bytes.get(position).is_some_and(u8::is_ascii_digit) { + position += 1; + } + if position == fraction_start { + return &raw[..number_start]; + } + } else if !has_integer { + return &raw[..number_start]; + } + + if matches!(bytes.get(position), Some(b'e' | b'E')) { + position += 1; + if matches!(bytes.get(position), Some(b'+' | b'-')) { + position += 1; + } + let exponent_start = position; + while bytes.get(position).is_some_and(u8::is_ascii_digit) { + position += 1; + } + if position == exponent_start { + return &raw[..number_start]; + } + } + } + _ => return raw, + } + } + raw +}