From: Dirk Lemstra Date: Fri, 28 Jun 2019 22:24:55 +0000 (+0200) Subject: Use a buffer instead of reading byte per byte. X-Git-Tag: 7.0.8-51~10 X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=41a2c8b1d1f07e77f4cdadb4601f8e206283666a;p=imagemagick Use a buffer instead of reading byte per byte. --- diff --git a/coders/pdf.c b/coders/pdf.c index f59c75e96..82e7d3b04 100644 --- a/coders/pdf.c +++ b/coders/pdf.c @@ -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; /* 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 "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 "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