Commit 435cddf43 for imagemagick.org

commit 435cddf43011ca48c328ccf7c6d9e492cc05d442
Author: Wei-Lun Li <b84330808@gmail.com>
Date:   Thu Nov 5 01:46:20 2026 +0900

    Parse SVG path arc flags as single digits (#9096)

    The large-arc and sweep flags of an elliptical arc were read as numbers,
    so compact path data such as "a4 4 0 010 8" (flags 0 and 1, then x=0)
    was read as a single flag value of 10 and the rest of the path failed
    to parse. The SVG grammar defines each flag as a single 0 or 1 that
    does not need a separator, as written by many SVG minifiers.

    Fixes #9092

diff --git a/MagickCore/draw.c b/MagickCore/draw.c
index ccb0fe295..70936545f 100644
--- a/MagickCore/draw.c
+++ b/MagickCore/draw.c
@@ -6764,6 +6764,29 @@ static MagickBooleanType TraceLine(PrimitiveInfo *primitive_info,
   return(MagickTrue);
 }

+static MagickBooleanType GetArcFlag(const char **path,MagickBooleanType *flag)
+{
+  const char
+    *p;
+
+  /*
+    An arc flag is a single 0 or 1 and need not be separated from the next
+    value, e.g. "a4 4 0 010 8".
+  */
+  p=(*path);
+  while (isspace((int) ((unsigned char) *p)) != 0)
+    p++;
+  if (*p == ',')
+    p++;
+  while (isspace((int) ((unsigned char) *p)) != 0)
+    p++;
+  if ((*p != '0') && (*p != '1'))
+    return(MagickFalse);
+  *flag=(*p == '1') ? MagickTrue : MagickFalse;
+  *path=p+1;
+  return(MagickTrue);
+}
+
 static ssize_t TracePath(MVGInfo *mvg_info,const char *path,
   ExceptionInfo *exception)
 {
@@ -6872,22 +6895,10 @@ static ssize_t TracePath(MVGInfo *mvg_info,const char *path,
           angle=GetDrawValue(token,&next_token);
           if (token == next_token)
             ThrowPointExpectedException(token,exception);
-          (void) GetNextToken(p,&p,MagickPathExtent,token);
-          if (IsValidListChar((int) ((unsigned char) *token)) == MagickFalse)
-            ThrowPointExpectedException(token,exception);
-          if (*token == ',')
-            (void) GetNextToken(p,&p,MagickPathExtent,token);
-          large_arc=StringToLong(token) != 0 ? MagickTrue : MagickFalse;
-          (void) GetNextToken(p,&p,MagickPathExtent,token);
-          if (IsValidListChar((int) ((unsigned char) *token)) == MagickFalse)
-            ThrowPointExpectedException(token,exception);
-          if (*token == ',')
-            (void) GetNextToken(p,&p,MagickPathExtent,token);
-          sweep=StringToLong(token) != 0 ? MagickTrue : MagickFalse;
-          if (IsValidListChar((int) ((unsigned char) *token)) == MagickFalse)
-            ThrowPointExpectedException(token,exception);
-          if (*token == ',')
-            (void) GetNextToken(p,&p,MagickPathExtent,token);
+          if (GetArcFlag(&p,&large_arc) == MagickFalse)
+            ThrowPointExpectedException(p,exception);
+          if (GetArcFlag(&p,&sweep) == MagickFalse)
+            ThrowPointExpectedException(p,exception);
           (void) GetNextToken(p,&p,MagickPathExtent,token);
           if (IsValidListChar((int) ((unsigned char) *token)) == MagickFalse)
             ThrowPointExpectedException(token,exception);
diff --git a/tests/cli-svg.tap b/tests/cli-svg.tap
index 2baad8d4d..173f4f24a 100755
--- a/tests/cli-svg.tap
+++ b/tests/cli-svg.tap
@@ -18,7 +18,7 @@
 #
 . ./common.shi
 . ${srcdir}/tests/common.shi
-echo "1..3"
+echo "1..4"

 # gradientTransform should not cause a double-free / SIGABRT (#8582)
 ${MAGICK} ${SRCDIR}/input_svg_gradient_transform.svg null: && echo "ok" || echo "not ok"
@@ -41,4 +41,13 @@ case "$svg" in
   *'<desc>x(&lt;script&gt;)</desc>'*) echo "ok" ;;
   *) echo "not ok" ;;
 esac
+
+# Arc flags are single digits and need not be followed by a separator (#9092).
+compact=`${MAGICK} -size 24x24 xc:white -fill none -stroke black \
+  -draw "path 'M6 12h9a4 4 0 010 8H7a1 1 0 01-1-1V5a1 1 0 011-1h7a4 4 0 010 8'" \
+  -format '%#' info:- 2>/dev/null`
+spaced=`${MAGICK} -size 24x24 xc:white -fill none -stroke black \
+  -draw "path 'M6 12 h9 a4 4 0 0 1 0 8 H7 a1 1 0 0 1 -1 -1 V5 a1 1 0 0 1 1 -1 h7 a4 4 0 0 1 0 8'" \
+  -format '%#' info:- 2>/dev/null`
+[ "X$compact" != "X" ] && [ "X$compact" = "X$spaced" ] && echo "ok" || echo "not ok"
 :