From 5abfef15e1e1d45c5dd3a374839e288ec10a4f63 Mon Sep 17 00:00:00 2001 From: Thomas Shinnick Date: Tue, 3 May 2022 17:48:14 -0500 Subject: [PATCH] Handle one more valid real number format in svgLib parse_path() Using svg.draw(pen) and parse_path() from svgLib threw exception ValueError: could not convert string to float: 'a' on a SVG string generated by Inkscape. Altering the path string might object to other string bits like 'Z' or 'v', or give even stranger exceptions. Finally tracked it down to the path containing particular valid numbers like "-4e-5" or "1e-4". Changing these to "-4.0e-5" or "1.0e-4" would stop the exceptions. The parse_path() was not accepting valid SVG real numbers. The specification for real number formats is a bit of a mess in CSS land right now, but the reassuringly concrete spec is: https://www.w3.org/TR/css-syntax-3/#number-token-diagram which allows a real number having an exponent but without having a fractional part, such as the number "1e3". This change updates an RE to make fractional parts optional, and adds a test for this valid SVG number format. --- Lib/fontTools/svgLib/path/parser.py | 5 ++++- Tests/svgLib/path/parser_test.py | 9 +++++++++ 2 files changed, 13 insertions(+), 1 deletion(-) diff --git a/Lib/fontTools/svgLib/path/parser.py b/Lib/fontTools/svgLib/path/parser.py index 1fcf8998c..b3218c8a7 100644 --- a/Lib/fontTools/svgLib/path/parser.py +++ b/Lib/fontTools/svgLib/path/parser.py @@ -16,10 +16,13 @@ ARC_COMMANDS = set("Aa") UPPERCASE = set('MZLHVCSQTA') COMMAND_RE = re.compile("([MmZzLlHhVvCcSsQqTtAa])") + +# https://www.w3.org/TR/css-syntax-3/#number-token-diagram +# but -6.e-5 will be tokenized as "-6" then "-5" and confuse parsing FLOAT_RE = re.compile( r"[-+]?" # optional sign r"(?:" - r"(?:0|[1-9][0-9]*)(?:\.[0-9]+(?:[eE][-+]?[0-9]+)?)?" # int/float + r"(?:0|[1-9][0-9]*)(?:\.[0-9]+)?(?:[eE][-+]?[0-9]+)?" # int/float r"|" r"(?:\.[0-9]+(?:[eE][-+]?[0-9]+)?)" # float with leading dot (e.g. '.42') r")" diff --git a/Tests/svgLib/path/parser_test.py b/Tests/svgLib/path/parser_test.py index b533dd8e8..1bcd30dd5 100644 --- a/Tests/svgLib/path/parser_test.py +++ b/Tests/svgLib/path/parser_test.py @@ -280,6 +280,15 @@ def test_exponents(): assert pen.value == expected + pen = RecordingPen() + parse_path("M-3e38 3E+38L-3E-38,3e-38", pen) + expected = [ + ("moveTo", ((-3e+38, 3e+38),)), + ("lineTo", ((-3e-38, 3e-38),)), + ("endPath", ()), + ] + + assert pen.value == expected def test_invalid_implicit_command(): with pytest.raises(ValueError) as exc_info: