]> granicus.if.org Git - imagemagick/commitdiff
Use a buffer instead of reading byte per byte.
authorDirk Lemstra <dirk@lemstra.org>
Fri, 28 Jun 2019 22:24:55 +0000 (00:24 +0200)
committerDirk Lemstra <dirk@lemstra.org>
Fri, 28 Jun 2019 22:25:21 +0000 (00:25 +0200)
coders/pdf.c

index f59c75e960f7a92b7f7d8bc5f66c5fee6466d14b..82e7d3b049dd1f4aab52eb1ee688586702366277 100644 (file)
@@ -105,13 +105,27 @@ typedef struct _PDFInfo
     trimbox;
 
   SegmentInfo
-    bounds,
-    hires_bounds;
+    bounds;
 
   StringInfo
     *profile;
 
 } PDFInfo;
+
+typedef struct _PDFBuffer
+{
+  Image
+    *image;
+
+  size_t
+    offset;
+
+  ssize_t
+    count;
+
+  unsigned char
+    data[MagickPathExtent];
+} PDFBuffer;
 \f
 /*
   Forward declarations.
@@ -393,15 +407,119 @@ static MagickBooleanType IsPDFRendered(const char *path)
   return(MagickFalse);
 }
 
-static void ReadPDFInfo(const ImageInfo *image_info,Image *image,PDFInfo *info,
+static inline int ReadPDFByte(PDFBuffer *buffer)
+{
+  if (((ssize_t)buffer->offset == buffer->count) && (buffer->offset > 0))
+    {
+      if (buffer->count != sizeof(buffer->data))
+        return(EOF);
+      buffer->offset=0;
+    }
+  if (buffer->offset == 0)
+    {
+      buffer->count=ReadBlob(buffer->image,sizeof(buffer->data),buffer->data);
+      if (buffer->count < 1)
+        return(EOF);
+    }
+  return(buffer->data[buffer->offset++]);
+}
+
+static char *MovePDFBuffer(PDFBuffer *buffer)
+{
+  ssize_t
+    i;
+
+  i=1; // Skip first to avoid reload of buffer;
+  while ((ssize_t)buffer->offset != buffer->count)
+    buffer->data[i++] = buffer->data[buffer->offset++];
+  buffer->count=ReadBlob(buffer->image,sizeof(buffer->data)-i,
+    buffer->data+i);
+  buffer->count+=i;
+  buffer->offset=1;
+  return((char *) buffer->data+1);
+}
+
+static inline void CheckRemainingPDFBuffer(PDFBuffer *buffer,size_t length)
+{
+  if (buffer->offset + length > sizeof(buffer->data))
+    (void)MovePDFBuffer(buffer);
+}
+
+static inline void SkipPDFBytes(PDFBuffer *buffer,size_t count)
+{
+  CheckRemainingPDFBuffer(buffer,count);
+  buffer->offset+=count;
+}
+
+static inline MagickBooleanType ComparePDFBuffer(const char *p,
+  PDFBuffer *buffer,const size_t length)
+{
+  const char
+    *q;
+
+  CheckRemainingPDFBuffer(buffer,length);
+  q=(const char *) buffer->data+buffer->offset;
+  if (LocaleNCompare(p,q,length) != 0)
+    return(MagickFalse);
+  return(MagickTrue);
+}
+
+static void ReadPDFXMPProfile(PDFInfo *pdf_info,PDFBuffer *buffer)
+{
+#define BeginXMPPacket  "?xpacket begin="
+#define EndXMPPacket  "<?xpacket end="
+
+  int
+    c;
+
+  MagickBooleanType
+    found_end;
+
+  register char
+    *p;
+
+  size_t
+    length,
+    count;
+
+  if (pdf_info->profile != (StringInfo *) NULL)
+    return;
+  if (ComparePDFBuffer(BeginXMPPacket,buffer,strlen(BeginXMPPacket)) == MagickFalse)
+    return;
+  length=MagickPathExtent;
+  pdf_info->profile=AcquireStringInfo(length);
+  found_end=MagickFalse;
+  p=(char *) GetStringInfoDatum(pdf_info->profile);
+  *p++='<';
+  count=1;
+  for (c=ReadPDFByte(buffer); c != EOF; c=ReadPDFByte(buffer))
+  {
+    if (count == length)
+      {
+        length+=MagickPathExtent;
+        SetStringInfoLength(pdf_info->profile,length);
+        p=(char *) GetStringInfoDatum(pdf_info->profile)+count;
+      }
+    count++;
+    *p++=(char) c;
+    if (found_end == MagickFalse)
+      found_end=ComparePDFBuffer(EndXMPPacket,buffer,strlen(EndXMPPacket));
+    else
+      {
+        if (c == (int)'>')
+          break;
+      }
+  }
+  SetStringInfoLength(pdf_info->profile,count);
+}
+
+static void ReadPDFInfo(const ImageInfo *image_info,Image *image,PDFInfo *pdf_info,
   ExceptionInfo *exception)
 {
-#define BeginXMPPacket  "<?xpacket begin="
 #define CMYKProcessColor  "CMYKProcessColor"
 #define CropBox  "CropBox"
 #define DefaultCMYK  "DefaultCMYK"
 #define DeviceCMYK  "DeviceCMYK"
-#define EndXMPPacket  "<?xpacket end="
 #define MediaBox  "MediaBox"
 #define PDFRotate  "Rotate"
 #define SpotColor  "Separation"
@@ -409,60 +527,80 @@ static void ReadPDFInfo(const ImageInfo *image_info,Image *image,PDFInfo *info,
 #define PDFVersion  "PDF-"
 
   char
-    buffer[MagickPathExtent];
+    version[MagickPathExtent];
 
   int
     c;
 
+  PDFBuffer
+    buffer;
+
   register char
     *p;
 
   register ssize_t
     i;
 
+  SegmentInfo
+    bounds;
+
   size_t
     spotcolor;
 
   ssize_t
     count;
 
-  (void) memset(info,0,sizeof(*info));
-  info->cmyk=image_info->colorspace == CMYKColorspace ? MagickTrue : MagickFalse;
-  info->cropbox=IsStringTrue(GetImageOption(image_info,"pdf:use-cropbox"));
-  info->trimbox=IsStringTrue(GetImageOption(image_info,"pdf:use-trimbox"));
+  (void) memset(&bounds,0,sizeof(bounds));
+  (void) memset(pdf_info,0,sizeof(*pdf_info));
+  pdf_info->cmyk=image_info->colorspace == CMYKColorspace ? MagickTrue : MagickFalse;
+  pdf_info->cropbox=IsStringTrue(GetImageOption(image_info,"pdf:use-cropbox"));
+  pdf_info->trimbox=IsStringTrue(GetImageOption(image_info,"pdf:use-trimbox"));
 
+  version[0]='\0';
   spotcolor=0;
-  (void) memset(buffer,0,sizeof(buffer));
-  p=buffer;
-  for (c=ReadBlobByte(image); c != EOF; c=ReadBlobByte(image))
+  (void) memset(&buffer,0,sizeof(buffer));
+  buffer.image=image;
+  for (c=ReadPDFByte(&buffer); c != EOF; c=ReadPDFByte(&buffer))
   {
-    /*
-      Note PDF elements.
-    */
-    if (c == '\n')
-      c=' ';
-    *p++=(char) c;
-    if ((c != (int) '/') && (c != (int) '%') &&
-        ((size_t) (p-buffer) < (MagickPathExtent-1)))
-      continue;
-    *(--p)='\0';
-    p=buffer;
-    if (LocaleNCompare(PDFRotate,buffer,strlen(PDFRotate)) == 0)
-      (void) sscanf(buffer,"Rotate %lf",&info->angle);
-    /*
-      Is this a CMYK document?
-    */
-    if (info->cmyk == MagickFalse)
+    switch(c)
     {
-      if ((LocaleNCompare(DefaultCMYK,buffer,strlen(DefaultCMYK)) == 0) ||
-          (LocaleNCompare(DeviceCMYK,buffer,strlen(DeviceCMYK)) == 0) ||
-          (LocaleNCompare(CMYKProcessColor,buffer,strlen(CMYKProcessColor)) == 0))
-        {
-          info->cmyk=MagickTrue;
-          continue;
-        }
+      case '%':
+        if (version[0] == '\0')
+          {
+            i=0;
+            for (c=ReadPDFByte(&buffer); c != EOF; c=ReadPDFByte(&buffer))
+            {
+              if ((c == '\r') || (c == '\n') || ((i+1) == MagickPathExtent))
+                break;
+              version[i++]=(char) c;
+            }
+            version[i]='\0';
+          }
+        continue;
+      case '<':
+        ReadPDFXMPProfile(pdf_info,&buffer);
+        continue;
+      case '/':
+        break;
+      default:
+        continue;
     }
-    if (LocaleNCompare(SpotColor,buffer,strlen(SpotColor)) == 0)
+    if (ComparePDFBuffer(PDFRotate,&buffer,strlen(PDFRotate)) != MagickFalse)
+      {
+        p=MovePDFBuffer(&buffer);
+        (void) sscanf(p,PDFRotate" %lf",&pdf_info->angle);
+      }
+    if (pdf_info->cmyk == MagickFalse)
+      {
+        if ((ComparePDFBuffer(DefaultCMYK,&buffer,strlen(DefaultCMYK)) != MagickFalse) ||
+            (ComparePDFBuffer(DeviceCMYK,&buffer,strlen(DeviceCMYK)) != MagickFalse) ||
+            (ComparePDFBuffer(CMYKProcessColor,&buffer,strlen(CMYKProcessColor)) != MagickFalse))
+          {
+            pdf_info->cmyk=MagickTrue;
+            continue;
+          }
+      }
+    if (ComparePDFBuffer(SpotColor,&buffer,strlen(SpotColor)) != MagickFalse)
       {
         char
           name[MagickPathExtent],
@@ -475,7 +613,8 @@ static void ReadPDFInfo(const ImageInfo *image_info,Image *image,PDFInfo *info,
         (void) FormatLocaleString(property,MagickPathExtent,
           "pdf:SpotColor-%.20g",(double) spotcolor++);
         i=0;
-        for (c=ReadBlobByte(image); c != EOF; c=ReadBlobByte(image))
+        SkipPDFBytes(&buffer,strlen(SpotColor)+1);
+        for (c=ReadPDFByte(&buffer); c != EOF; c=ReadPDFByte(&buffer))
         {
           if ((isspace(c) != 0) || (c == '/') || ((i+1) == MagickPathExtent))
             break;
@@ -489,99 +628,68 @@ static void ReadPDFInfo(const ImageInfo *image_info,Image *image,PDFInfo *info,
         value=DestroyString(value);
         continue;
       }
-    if (LocaleNCompare(PDFVersion,buffer,strlen(PDFVersion)) == 0)
-      {
-        (void) SetImageProperty(image,"pdf:Version",buffer,exception);
-        continue;
-      }
-    if ((info->profile == (StringInfo *) NULL) &&
-        (LocaleNCompare(BeginXMPPacket,buffer,strlen(BeginXMPPacket)) == 0))
-      {
-        /*
-          Read XMP profile.
-        */
-        p=buffer;
-        info->profile=StringToStringInfo(buffer);
-        for (i=(ssize_t) GetStringInfoLength(info->profile)-1; c != EOF; i++)
-        {
-          SetStringInfoLength(info->profile,(size_t) (i+1));
-          c=ReadBlobByte(image);
-          GetStringInfoDatum(info->profile)[i]=(unsigned char) c;
-          *p++=(char) c;
-          if ((strchr("\n\r%",c) == (char *) NULL) &&
-              ((size_t) (p-buffer) < (MagickPathExtent-1)))
-            continue;
-          *p='\0';
-          p=buffer;
-          if (LocaleNCompare(EndXMPPacket,buffer,strlen(EndXMPPacket)) == 0)
-            break;
-        }
-        SetStringInfoLength(info->profile,(size_t) i);
-        continue;
-      }
     if (image_info->page != (char *) NULL)
       continue;
     count=0;
-    if (info->cropbox != MagickFalse)
+    if (pdf_info->cropbox != MagickFalse)
       {
-        if (LocaleNCompare(CropBox,buffer,strlen(CropBox)) == 0)
+        if (ComparePDFBuffer(CropBox,&buffer,strlen(CropBox)) != MagickFalse)
           {
             /*
               Note region defined by crop box.
             */
-            count=(ssize_t) sscanf(buffer,"CropBox [%lf %lf %lf %lf",
-              &info->bounds.x1,&info->bounds.y1,&info->bounds.x2,
-              &info->bounds.y2);
+            p=MovePDFBuffer(&buffer);
+            count=(ssize_t) sscanf(p,"CropBox [%lf %lf %lf %lf",
+              &bounds.x1,&bounds.y1,&bounds.x2,&bounds.y2);
             if (count != 4)
-              count=(ssize_t) sscanf(buffer,"CropBox[%lf %lf %lf %lf",
-                &info->bounds.x1,&info->bounds.y1,&info->bounds.x2,
-                &info->bounds.y2);
+              count=(ssize_t) sscanf(p,"CropBox[%lf %lf %lf %lf",
+                &bounds.x1,&bounds.y1,&bounds.x2,&bounds.y2);
           }
       }
     else
-      if (info->trimbox != MagickFalse)
+      if (pdf_info->trimbox != MagickFalse)
         {
-          if (LocaleNCompare(TrimBox,buffer,strlen(TrimBox)) == 0)
+          if (ComparePDFBuffer(TrimBox,&buffer,strlen(TrimBox)) != MagickFalse)
             {
               /*
                 Note region defined by trim box.
               */
-              count=(ssize_t) sscanf(buffer,"TrimBox [%lf %lf %lf %lf",
-                &info->bounds.x1,&info->bounds.y1,&info->bounds.x2,
-                &info->bounds.y2);
+              p=MovePDFBuffer(&buffer);
+              count=(ssize_t) sscanf(p,"TrimBox [%lf %lf %lf %lf",
+                &bounds.x1,&bounds.y1,&bounds.x2,&bounds.y2);
               if (count != 4)
-                count=(ssize_t) sscanf(buffer,"TrimBox[%lf %lf %lf %lf",
-                  &info->bounds.x1,&info->bounds.y1,&info->bounds.x2,
-                  &info->bounds.y2);
+                count=(ssize_t) sscanf(p,"TrimBox[%lf %lf %lf %lf",
+                  &bounds.x1,&bounds.y1,&bounds.x2,&bounds.y2);
             }
         }
       else
-        if (LocaleNCompare(MediaBox,buffer,strlen(MediaBox)) == 0)
+        if (ComparePDFBuffer(MediaBox,&buffer,strlen(MediaBox)) != MagickFalse)
           {
             /*
               Note region defined by media box.
             */
-            count=(ssize_t) sscanf(buffer,"MediaBox [%lf %lf %lf %lf",
-              &info->bounds.x1,&info->bounds.y1,&info->bounds.x2,
-              &info->bounds.y2);
+            p=MovePDFBuffer(&buffer);
+            count=(ssize_t) sscanf(p,"MediaBox [%lf %lf %lf %lf",
+              &bounds.x1,&bounds.y1,&bounds.x2,&bounds.y2);
             if (count != 4)
-              count=(ssize_t) sscanf(buffer,"MediaBox[%lf %lf %lf %lf",
-                &info->bounds.x1,&info->bounds.y1,&info->bounds.x2,
-                &info->bounds.y2);
+              count=(ssize_t) sscanf(p,"MediaBox[%lf %lf %lf %lf",
+                &bounds.x1,&bounds.y1,&bounds.x2,&bounds.y2);
           }
     if (count != 4)
       continue;
-    if ((fabs(info->bounds.x2-info->bounds.x1) <= fabs(info->hires_bounds.x2-info->hires_bounds.x1)) ||
-        (fabs(info->bounds.y2-info->bounds.y1) <= fabs(info->hires_bounds.y2-info->hires_bounds.y1)))
+    if ((fabs(bounds.x2-bounds.x1) <= fabs(pdf_info->bounds.x2-pdf_info->bounds.x1)) ||
+        (fabs(bounds.y2-bounds.y1) <= fabs(pdf_info->bounds.y2-pdf_info->bounds.y1)))
       continue;
-    info->hires_bounds=info->bounds;
+    pdf_info->bounds=bounds;
   }
+  if (version[0] != '\0')
+    (void) SetImageProperty(image,"pdf:Version",version,exception);
 }
 
-static inline void CleanupPDFInfo(PDFInfo *info)
+static inline void CleanupPDFInfo(PDFInfo *pdf_info)
 {
-  if (info->profile != (StringInfo *) NULL)
-    info->profile=DestroyStringInfo(info->profile);
+  if (pdf_info->profile != (StringInfo *) NULL)
+    pdf_info->profile=DestroyStringInfo(pdf_info->profile);
 }
 
 static Image *ReadPDFImage(const ImageInfo *image_info,ExceptionInfo *exception)
@@ -625,7 +733,7 @@ static Image *ReadPDFImage(const ImageInfo *image_info,ExceptionInfo *exception)
     flags;
 
   PDFInfo
-    info;
+    pdf_info;
 
   PointInfo
     delta;
@@ -696,22 +804,22 @@ static Image *ReadPDFImage(const ImageInfo *image_info,ExceptionInfo *exception)
   /*
     Determine page geometry from the PDF media box.
   */
-  ReadPDFInfo(image_info,image,&info,exception);
+  ReadPDFInfo(image_info,image,&pdf_info,exception);
   (void) CloseBlob(image);
   /*
     Set PDF render geometry.
   */
-  if ((fabs(info.hires_bounds.x2-info.hires_bounds.x1) >= MagickEpsilon) &&
-      (fabs(info.hires_bounds.y2-info.hires_bounds.y1) >= MagickEpsilon))
+  if ((fabs(pdf_info.bounds.x2-pdf_info.bounds.x1) >= MagickEpsilon) &&
+      (fabs(pdf_info.bounds.y2-pdf_info.bounds.y1) >= MagickEpsilon))
     {
       (void) FormatLocaleString(geometry,MagickPathExtent,"%gx%g%+.15g%+.15g",
-        info.hires_bounds.x2-info.bounds.x1,info.hires_bounds.y2-
-        info.hires_bounds.y1,info.hires_bounds.x1,info.hires_bounds.y1);
+        pdf_info.bounds.x2-pdf_info.bounds.x1,pdf_info.bounds.y2-
+        pdf_info.bounds.y1,pdf_info.bounds.x1,pdf_info.bounds.y1);
       (void) SetImageProperty(image,"pdf:HiResBoundingBox",geometry,exception);
-      page.width=(size_t) ceil((double) ((info.hires_bounds.x2-info.hires_bounds.x1)*
-        image->resolution.x/delta.x)-0.5);
-      page.height=(size_t) ceil((double) ((info.hires_bounds.y2-info.hires_bounds.y1)*
-        image->resolution.y/delta.y)-0.5);
+      page.width=(size_t) ceil((double) ((pdf_info.bounds.x2-
+        pdf_info.bounds.x1)*image->resolution.x/delta.x)-0.5);
+      page.height=(size_t) ceil((double) ((pdf_info.bounds.y2-
+        pdf_info.bounds.y1)*image->resolution.y/delta.y)-0.5);
     }
   fitPage=MagickFalse;
   option=GetImageOption(image_info,"pdf:fit-page");
@@ -728,7 +836,7 @@ static Image *ReadPDFImage(const ImageInfo *image_info,ExceptionInfo *exception)
         {
           (void) ThrowMagickException(exception,GetMagickModule(),OptionError,
             "InvalidGeometry","`%s'",option);
-          CleanupPDFInfo(&info);
+          CleanupPDFInfo(&pdf_info);
           image=DestroyImage(image);
           return((Image *) NULL);
         }
@@ -738,7 +846,7 @@ static Image *ReadPDFImage(const ImageInfo *image_info,ExceptionInfo *exception)
         delta.y) -0.5);
       fitPage=MagickTrue;
     }
-  if ((fabs(info.angle) == 90.0) || (fabs(info.angle) == 270.0))
+  if ((fabs(pdf_info.angle) == 90.0) || (fabs(pdf_info.angle) == 270.0))
     {
       size_t
         swap;
@@ -748,7 +856,7 @@ static Image *ReadPDFImage(const ImageInfo *image_info,ExceptionInfo *exception)
       page.height=swap;
     }
   if (IssRGBCompatibleColorspace(image_info->colorspace) != MagickFalse)
-    info.cmyk=MagickFalse;
+    pdf_info.cmyk=MagickFalse;
   stop_on_error=IsStringTrue(GetImageOption(image_info,"pdf:stop-on-error"));
   /*
     Create Ghostscript control file.
@@ -758,7 +866,7 @@ static Image *ReadPDFImage(const ImageInfo *image_info,ExceptionInfo *exception)
     {
       ThrowFileException(exception,FileOpenError,"UnableToCreateTemporaryFile",
         image_info->filename);
-      CleanupPDFInfo(&info);
+      CleanupPDFInfo(&pdf_info);
       image=DestroyImage(image);
       return((Image *) NULL);
     }
@@ -770,14 +878,14 @@ static Image *ReadPDFImage(const ImageInfo *image_info,ExceptionInfo *exception)
   if (image_info->monochrome != MagickFalse)
     delegate_info=GetDelegateInfo("ps:mono",(char *) NULL,exception);
   else
-     if (info.cmyk != MagickFalse)
+     if (pdf_info.cmyk != MagickFalse)
        delegate_info=GetDelegateInfo("ps:cmyk",(char *) NULL,exception);
      else
        delegate_info=GetDelegateInfo("ps:alpha",(char *) NULL,exception);
   if (delegate_info == (const DelegateInfo *) NULL)
     {
       (void) RelinquishUniqueFileResource(postscript_filename);
-      CleanupPDFInfo(&info);
+      CleanupPDFInfo(&pdf_info);
       image=DestroyImage(image);
       return((Image *) NULL);
     }
@@ -790,14 +898,14 @@ static Image *ReadPDFImage(const ImageInfo *image_info,ExceptionInfo *exception)
       page.width,(double) page.height);
   if (fitPage != MagickFalse)
     (void) ConcatenateMagickString(options,"-dPSFitPage ",MagickPathExtent);
-  if (info.cmyk != MagickFalse)
+  if (pdf_info.cmyk != MagickFalse)
     (void) ConcatenateMagickString(options,"-dUseCIEColor ",MagickPathExtent);
-  if (info.cropbox != MagickFalse)
+  if (pdf_info.cropbox != MagickFalse)
     (void) ConcatenateMagickString(options,"-dUseCropBox ",MagickPathExtent);
   if (stop_on_error != MagickFalse)
     (void) ConcatenateMagickString(options,"-dPDFSTOPONERROR ",
       MagickPathExtent);
-  if (info.trimbox != MagickFalse)
+  if (pdf_info.trimbox != MagickFalse)
     (void) ConcatenateMagickString(options,"-dUseTrimBox ",MagickPathExtent);
   option=GetImageOption(image_info,"authenticate");
   if (option != (char *) NULL)
@@ -870,7 +978,7 @@ static Image *ReadPDFImage(const ImageInfo *image_info,ExceptionInfo *exception)
       if (*message != '\0')
         (void) ThrowMagickException(exception,GetMagickModule(),DelegateError,
           "PDFDelegateFailed","`%s'",message);
-      CleanupPDFInfo(&info);
+      CleanupPDFInfo(&pdf_info);
       image=DestroyImage(image);
       return((Image *) NULL);
     }
@@ -886,9 +994,9 @@ static Image *ReadPDFImage(const ImageInfo *image_info,ExceptionInfo *exception)
           pdf_image=cmyk_image;
         }
     }
-  if (info.profile != (StringInfo *) NULL)
-    (void) SetImageProfile(image,"xmp",info.profile,exception);
-  CleanupPDFInfo(&info);
+  if (pdf_info.profile != (StringInfo *) NULL)
+    (void) SetImageProfile(image,"xmp",pdf_info.profile,exception);
+  CleanupPDFInfo(&pdf_info);
   if (image_info->number_scenes != 0)
     {
       Image