Commit afa2497cf for imagemagick.org

commit afa2497cf8af3eddff5b560f7acbf8eb57c2a518
Author: Cristy <urban-warrior@imagemagick.org>
Date:   Thu Nov 12 12:20:36 2026 -0500

    https://github.com/ImageMagick/ImageMagick/issues/9115

diff --git a/MagickCore/image-private.h b/MagickCore/image-private.h
index 94bcccdae..6e6d98e90 100644
--- a/MagickCore/image-private.h
+++ b/MagickCore/image-private.h
@@ -236,6 +236,42 @@ static inline double DegreesToRadians(const double degrees)
   return((double) (MagickPI*degrees/180.0));
 }

+static inline MagickBooleanType IsValidFormatSpecifier(const char *start,
+  const char *end)
+{
+  char
+    specifier = end[-1];
+
+  size_t
+    length = (size_t) (end-start);
+
+  /*
+    Is this a valid format specifier?
+  */
+  if ((specifier != 'd') && (specifier != 'x') && (specifier != 'o'))
+    return(MagickFalse);
+  if ((length == 1) && (*start == specifier))
+    return(MagickTrue);
+  if (length >= 2)
+    {
+      size_t
+        i = 0;
+
+      if (*start == '0')
+        {
+          if ((length >= 3) && (start[1] == '0'))
+            return(MagickFalse);
+          i=1;
+        }
+      for ( ; i < (length-1); i++)
+        if (isdigit((int) ((unsigned char) start[i])) == 0)
+          return(MagickFalse);
+      return(MagickTrue);
+    }
+  return(MagickFalse);
+}
+
+
 static inline double RadiansToDegrees(const double radians)
 {
   return((double) (180.0*radians/MagickPI));
diff --git a/MagickCore/image.c b/MagickCore/image.c
index de2f9b744..e3f68127b 100644
--- a/MagickCore/image.c
+++ b/MagickCore/image.c
@@ -1662,42 +1662,6 @@ MagickExport VirtualPixelMethod GetImageVirtualPixelMethod(const Image *image)
 %    o exception: return any errors or warnings in this structure.
 %
 */
-
-static inline MagickBooleanType IsValidFormatSpecifier(const char *start,
-  const char *end)
-{
-  char
-    specifier = end[-1];
-
-  size_t
-    length = (size_t) (end-start);
-
-  /*
-    Is this a valid format specifier?
-  */
-  if ((specifier != 'd') && (specifier != 'x') && (specifier != 'o'))
-    return(MagickFalse);
-  if ((length == 1) && (*start == specifier))
-    return(MagickTrue);
-  if (length >= 2)
-    {
-      size_t
-        i = 0;
-
-      if (*start == '0')
-        {
-          if ((length >= 3) && (start[1] == '0'))
-            return(MagickFalse);
-          i=1;
-        }
-      for ( ; i < (length-1); i++)
-        if (isdigit((int) ((unsigned char) start[i])) == 0)
-          return(MagickFalse);
-      return(MagickTrue);
-    }
-  return(MagickFalse);
-}
-
 MagickExport size_t InterpretImageFilename(const ImageInfo *image_info,
   Image *image,const char *format,int value,char *filename,
   ExceptionInfo *exception)
diff --git a/coders/ghostscript-private.h b/coders/ghostscript-private.h
index 01fb763d8..a5c907cb1 100644
--- a/coders/ghostscript-private.h
+++ b/coders/ghostscript-private.h
@@ -19,9 +19,97 @@
 #include "MagickCore/delegate.h"
 #include "MagickCore/delegate-private.h"
 #include "MagickCore/exception-private.h"
+#include "MagickCore/image-private.h"
 #include "MagickCore/profile-private.h"
 #include "coders/bytebuffer-private.h"

+static inline size_t AppendImageFilenameScene(const char *format,int value,
+  char *filename)
+{
+  char
+    *p = filename,
+    pattern[MagickPathExtent];
+
+  const char
+    *cursor = format;
+
+  assert(format != (const char *) NULL);
+  assert(filename != (char *) NULL);
+  while ((*cursor != '\0') && ((p-filename) < ((ssize_t) MagickPathExtent-1)))
+  {
+    const char
+      *specifier_start,
+      *start;
+
+    if (*cursor != '%')
+      {
+        *p++=(*cursor++);
+        continue;
+      }
+    start=cursor++;  /* Skip '%' */
+    if (*cursor == '%')
+      {
+        *p++='%';
+        cursor++;
+        continue;
+      }
+    specifier_start=cursor;
+    while (isdigit((int) ((unsigned char) *cursor)) != 0)
+      cursor++;
+    if ((*cursor == 'd') || (*cursor == 'o') || (*cursor == 'x'))
+      {
+        const char
+          *specifier_end = cursor+1;
+
+        if (IsValidFormatSpecifier(specifier_start,specifier_end) != MagickFalse)
+          {
+            char
+              format_specifier[MagickPathExtent];
+
+            size_t
+              length = (size_t) (cursor-specifier_start),
+              pattern_length;
+
+            ssize_t
+              count;
+
+            (void) snprintf(format_specifier,sizeof(format_specifier),
+              "%%%.*s%c",(int) length,specifier_start,*cursor);
+            count=FormatLocaleString(pattern,sizeof(pattern),format_specifier,
+              value);
+            pattern_length=strlen(pattern);
+            if ((count <= 0) || ((size_t) count != pattern_length))
+              return(0);
+            if ((p-filename+(ssize_t) pattern_length) >= MagickPathExtent)
+              return(0);
+            (void) CopyMagickString(p,pattern,(size_t) (MagickPathExtent-
+              (p-filename)));
+            p+=pattern_length;
+            cursor++;
+            continue;
+          }
+        else
+          {
+            /*
+              Invalid specifier — treat as literal.
+            */
+            cursor=start;
+            *p++=(*cursor++);
+            continue;
+          }
+      }
+    /*
+      Invalid or unsupported specifier — treat as literal.
+    */
+    cursor=start;
+    if ((p-filename+1) >= MagickPathExtent)
+      return(0);
+    *p++=(*cursor++);
+  }
+  *p='\0';
+  return(strlen(filename));
+}
+
 #if defined(MAGICKCORE_GS_DELEGATE) || defined(MAGICKCORE_WINDOWS_SUPPORT)
 static int MagickDLLCall GhostscriptDelegateMessage(void *handle,
   const char *message,int length)
diff --git a/coders/pdf.c b/coders/pdf.c
index 480d445a2..e0b7b7c75 100644
--- a/coders/pdf.c
+++ b/coders/pdf.c
@@ -648,7 +648,6 @@ static Image *ReadPDFImage(const ImageInfo *image_info,ExceptionInfo *exception)
   (void) CopyMagickString(filename,read_info->filename,MagickPathExtent);
   (void) AcquireUniqueFilename(filename);
   (void) RelinquishUniqueFileResource(filename);
-  (void) ConcatenateMagickString(filename,"%d",MagickPathExtent);
   (void) FormatLocaleString(command,MagickPathExtent,
     GetDelegateCommands(delegate_info),
     read_info->antialias != MagickFalse ? 4 : 1,
@@ -665,8 +664,7 @@ static Image *ReadPDFImage(const ImageInfo *image_info,ExceptionInfo *exception)
   if (status == MagickFalse)
     for (i=1; ; i++)
     {
-      (void) InterpretImageFilename(image_info,image,filename,(int) i,
-        read_info->filename,exception);
+      (void) AppendImageFilenameScene(filename,(int) i,read_info->filename);
       if (IsGhostscriptRendered(read_info->filename) == MagickFalse)
         break;
       (void) RelinquishUniqueFileResource(read_info->filename);
@@ -676,8 +674,7 @@ static Image *ReadPDFImage(const ImageInfo *image_info,ExceptionInfo *exception)
       next=(Image *) NULL;
       for (i=1; ; i++)
       {
-        (void) InterpretImageFilename(image_info,image,filename,(int) i,
-          read_info->filename,exception);
+        (void) AppendImageFilenameScene(filename,(int) i,read_info->filename);
         if (IsGhostscriptRendered(read_info->filename) == MagickFalse)
           break;
         read_info->blob=NULL;
@@ -696,8 +693,7 @@ static Image *ReadPDFImage(const ImageInfo *image_info,ExceptionInfo *exception)

           for (j=i+1; ; j++)
             {
-              (void) InterpretImageFilename(image_info,image,filename,(int) j,
-                read_info->filename,exception);
+              (void) AppendImageFilenameScene(filename,(int) j,read_info->filename);
               if (IsGhostscriptRendered(read_info->filename) == MagickFalse)
                 break;
               (void) RelinquishUniqueFileResource(read_info->filename);
diff --git a/coders/ps.c b/coders/ps.c
index 2b36cceab..9932e4d21 100644
--- a/coders/ps.c
+++ b/coders/ps.c
@@ -814,7 +814,6 @@ static Image *ReadPSImage(const ImageInfo *image_info,ExceptionInfo *exception)
   (void) CopyMagickString(filename,read_info->filename,MagickPathExtent);
   (void) AcquireUniqueFilename(filename);
   (void) RelinquishUniqueFileResource(filename);
-  (void) ConcatenateMagickString(filename,"%d",MagickPathExtent);
   (void) FormatLocaleString(command,MagickPathExtent,
     GetDelegateCommands(delegate_info),
     read_info->antialias != MagickFalse ? 4 : 1,
@@ -825,8 +824,7 @@ static Image *ReadPSImage(const ImageInfo *image_info,ExceptionInfo *exception)
   *message='\0';
   status=InvokeGhostscriptDelegate(read_info->verbose,command,message,
     exception);
-  (void) InterpretImageFilename(image_info,image,filename,1,
-    read_info->filename,exception);
+  (void) AppendImageFilenameScene(filename,1,read_info->filename);
   if ((status == MagickFalse) ||
       (IsGhostscriptRendered(read_info->filename) == MagickFalse))
     {
@@ -840,8 +838,7 @@ static Image *ReadPSImage(const ImageInfo *image_info,ExceptionInfo *exception)
   if (status == MagickFalse)
     for (i=1; ; i++)
     {
-      (void) InterpretImageFilename(image_info,image,filename,(int) i,
-        read_info->filename,exception);
+      (void) AppendImageFilenameScene(filename,(int) i,read_info->filename);
       if (IsGhostscriptRendered(read_info->filename) == MagickFalse)
         break;
       (void) RelinquishUniqueFileResource(read_info->filename);
@@ -849,8 +846,7 @@ static Image *ReadPSImage(const ImageInfo *image_info,ExceptionInfo *exception)
   else
     for (i=1; ; i++)
     {
-      (void) InterpretImageFilename(image_info,image,filename,(int) i,
-        read_info->filename,exception);
+      (void) AppendImageFilenameScene(filename,(int) i,read_info->filename);
       if (IsGhostscriptRendered(read_info->filename) == MagickFalse)
         break;
       read_info->blob=NULL;
diff --git a/coders/xps.c b/coders/xps.c
index 1d8dd7cd2..2aa5bdac2 100644
--- a/coders/xps.c
+++ b/coders/xps.c
@@ -303,7 +303,6 @@ static Image *ReadXPSImage(const ImageInfo *image_info,ExceptionInfo *exception)
     }
   (void) AcquireUniqueFilename(read_info->filename);
   (void) RelinquishUniqueFileResource(read_info->filename);
-  (void) ConcatenateMagickString(read_info->filename,"%d",MagickPathExtent);
   (void) CopyMagickString(filename,read_info->filename,MagickPathExtent);
   (void) FormatLocaleString(command,MagickPathExtent,
     GetDelegateCommands(delegate_info),
@@ -320,8 +319,7 @@ static Image *ReadXPSImage(const ImageInfo *image_info,ExceptionInfo *exception)
   if (status == MagickFalse)
     for (i=1; ; i++)
     {
-      (void) InterpretImageFilename(image_info,image,filename,(int) i,
-        read_info->filename,exception);
+      (void) AppendImageFilenameScene(filename,(int) i,read_info->filename);
       if (IsGhostscriptRendered(read_info->filename) == MagickFalse)
         break;
       read_info->blob=NULL;