Skip to content

Commit

Permalink
svg2tvgt: fix ParseNumberGeneric
Browse files Browse the repository at this point in the history
This fixes a regression in recent commit b8e82bc.

That commit added the characters `eE+-` to the list of accepted characters
within the middle of a float string.  However, the `+-` characters are only
valid immediately after the `eE` characters.  This broke SVGS that don't
use whitespace between floats with negative numbers.  Consider the
following snippet from a real SVG:

```
<path d="M0 9.913V.487c0-.435.514-.651.812-.34l6.551 ...
```

With the commit referenced above, the string `0-.435` gets interpreted as a
single float value which fails to parse as a float.  I've fixed this
by splitting the function to parse floats into 3 parts:

1) before the decimal point

    char first = AcceptChar("0123456789." + (allow_sign ? "+-" : ""));
    ScanWhile(char.IsDigit);

2) after the decimal point

    if (first != '.' && ScanOne(".")) {
        ScanWhile(char.IsDigit);
    }

3) the exponent

    if (ScanOne("eE")) {
        ScanOne("+-");
        ScanWhile(char.IsDigit);
    }

This fixes the parser so that it only includes the `+-` characters if they
properly appear immediately after the `eE` characters.
  • Loading branch information
marler8997 authored and ikskuh committed Jul 10, 2024
1 parent 24abddf commit 17894e7
Showing 1 changed file with 29 additions and 18 deletions.
47 changes: 29 additions & 18 deletions src/tools/svg2tvgt/svg2tvgt.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2190,29 +2190,40 @@ float ParseNumber()
return ParseNumberGeneric(false);
}

bool ScanOne(string s)
{
if (char_offset < path_text.Length && s.Contains(path_text[char_offset])) {
char_offset++;
return true;
}
return false;
}

delegate bool IncludeCallback(char c);

void ScanWhile(IncludeCallback cb)
{
while (char_offset < path_text.Length) {
if (!cb(path_text[char_offset]))
return;
char_offset++;
}
}

float ParseNumberGeneric(bool allow_sign)
{
var begin = Save();
char? c = AcceptChar("0123456789." + (allow_sign ? "+-" : ""));
if (c != '.')
{
while (true)
{
c = PeekAny("0123456789.eE+-");
if (c == null)
return ParseFloat(begin.Slice());
AcceptChar("0123456789.eE+-");
if (c.Value == '.')
break;
}

char first = AcceptChar("0123456789." + (allow_sign ? "+-" : ""));
ScanWhile(char.IsDigit);
if (first != '.' && ScanOne(".")) {
ScanWhile(char.IsDigit);
}
while (true)
{
c = PeekAny("0123456789eE+-");
if (c == null)
return ParseFloat(begin.Slice());
AcceptChar("0123456789eE+-");
if (ScanOne("eE")) {
ScanOne("+-");
ScanWhile(char.IsDigit);
}
return ParseFloat(begin.Slice());
}

static float ParseFloat(string str)
Expand Down

0 comments on commit 17894e7

Please sign in to comment.