diff options
Diffstat (limited to 'coders/xpm.c')
-rw-r--r-- | coders/xpm.c | 414 |
1 files changed, 267 insertions, 147 deletions
diff --git a/coders/xpm.c b/coders/xpm.c index 7f471b7..347c22b 100644 --- a/coders/xpm.c +++ b/coders/xpm.c @@ -1,5 +1,5 @@ /* -% Copyright (C) 2003-2020 GraphicsMagick Group +% Copyright (C) 2003-2022 GraphicsMagick Group % Copyright (C) 2002 ImageMagick Studio % Copyright 1991-1999 E. I. du Pont de Nemours and Company % @@ -50,12 +50,39 @@ #include "magick/utility.h" +#define MAX_XPM_SUPPORTED_COLORS Max(0x20000,MaxColormapSize) + /* Forward declarations. */ static unsigned int WritePICONImage(const ImageInfo *,Image *), WriteXPMImage(const ImageInfo *,Image *); + +typedef magick_uint32_t xpmkeyval_t; + +typedef struct xpmkey +{ + magick_uint32_t index; /* Colormap index */ + xpmkeyval_t keyval; /* Encoded XPM key value */ +} xpmkey_t; + + +static int XPMKeyCompare(const void *l, const void *r) +{ + const xpmkey_t * restrict lp = l; + const xpmkey_t * restrict rp = r; + int sense; + + if (lp->keyval > rp->keyval) + sense = 1; + else if (lp->keyval < rp->keyval) + sense = -1; + else + sense = 0; + + return sense; +} /* %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% @@ -199,32 +226,29 @@ static char *ParseColor(char *data) i; for (i=0; i < NumberTargets; i++) - { - r=data; - for (q=targets[i]; *r != '\0'; r++) { - if (*r != *q) - continue; - if (!isspace((int) (*(r-1)))) - continue; - p=r; - for ( ; ; ) - { - if (*q == '\0') - return(r); - if (*p++ != *q++) - break; - } - q=targets[i]; + r=data; + for (q=targets[i]; *r != '\0'; r++) + { + if (*r != *q) + continue; + if (!isspace((int) (*(r-1)))) + continue; + p=r; + for ( ; ; ) + { + if (*q == '\0') + return(r); + if (*p++ != *q++) + break; + } + q=targets[i]; + } } - } return((char *) NULL); } #define ThrowXPMReaderException(code_,reason_,image_) \ do { \ - if (keys) \ - for (i=0; i < (long) image->colors; i++) \ - MagickFreeResourceLimitedMemory(keys[i]); \ MagickFreeResourceLimitedMemory(keys); \ MagickFreeResourceLimitedMemory(textlist); \ MagickFreeResourceLimitedMemory(xpm_buffer); \ @@ -233,9 +257,10 @@ do { \ static Image *ReadXPMImage(const ImageInfo *image_info,ExceptionInfo *exception) { + xpmkey_t + *keys = (xpmkey_t *) NULL; + char - key[MaxTextExtent], - **keys = (char **) NULL, target[MaxTextExtent], **textlist = (char **) NULL, *xpm_buffer = (char *) NULL; @@ -246,12 +271,13 @@ static Image *ReadXPMImage(const ImageInfo *image_info,ExceptionInfo *exception) int count; - unsigned long + unsigned int + i, j, + k, none; long - k, y; register char @@ -267,9 +293,6 @@ static Image *ReadXPMImage(const ImageInfo *image_info,ExceptionInfo *exception) register PixelPacket *r; - register long - i; - MagickPassFail status; @@ -279,7 +302,7 @@ static Image *ReadXPMImage(const ImageInfo *image_info,ExceptionInfo *exception) size_t length; - unsigned long + unsigned int width; /* characters per pixel */ /* @@ -320,35 +343,42 @@ static Image *ReadXPMImage(const ImageInfo *image_info,ExceptionInfo *exception) MagickFreeResourceLimitedMemory(xpm_buffer); break; } - xpm_buffer=new_xpm_buffer; - p=xpm_buffer+strlen(xpm_buffer); + if (xpm_buffer != new_xpm_buffer) + { + p=(p-xpm_buffer)+new_xpm_buffer; + xpm_buffer=new_xpm_buffer; + } } } if (xpm_buffer == (char *) NULL) ThrowXPMReaderException(ResourceLimitError,MemoryAllocationFailed,image); + /* Parse image properties from file header while skipping over comment markers. */ count=0; for (p=xpm_buffer; ((p - xpm_buffer) < 512) && (*p != '\0'); p++) - { - if ((*p != '"') || !isdigit((int) *(p+1))) - continue; - count=sscanf(p+1,"%lu %lu %u %lu",&image->columns,&image->rows, - &image->colors,&width); - if (count == 4) - { - (void) LogMagickEvent(CoderEvent,GetMagickModule(), - "Columns: %lu, Rows: %lu, Colors: %u, Char Per Pixel: %lu", - image->columns, image->rows, image->colors, width); - break; - } - } - if ((count != 4) || (width == 0) || (width > 2) || + { + if ((*p != '"') || !isdigit((int) *(p+1))) + continue; + count=sscanf(p+1,"%lu %lu %u %u",&image->columns,&image->rows, + &image->colors,&width); + if (count == 4) + { + (void) LogMagickEvent(CoderEvent,GetMagickModule(), + "Columns: %lu, Rows: %lu, Colors: %u, Char Per Pixel: %u", + image->columns, image->rows, image->colors, width); + break; + } + } + if ((count != 4) || (width == 0) || (width > 3) || (image->columns == 0) || (image->rows == 0) || - (image->colors == 0) || (image->colors > MaxColormapSize)) + (image->colors == 0)) ThrowXPMReaderException(CorruptImageError,ImproperImageHeader,image); + if (image->colors > MAX_XPM_SUPPORTED_COLORS) + ThrowXPMReaderException(CoderError,ColormapTooLarge,image); image->depth=16; + /* Remove unquoted characters. */ @@ -374,6 +404,7 @@ static Image *ReadXPMImage(const ImageInfo *image_info,ExceptionInfo *exception) ThrowXPMReaderException(CorruptImageError,CorruptImage,image); } } + /* Scan for non-white space binary control codes and reject file if they are present. @@ -384,8 +415,8 @@ static Image *ReadXPMImage(const ImageInfo *image_info,ExceptionInfo *exception) if (*p != '\0') { (void) LogMagickEvent(CoderEvent,GetMagickModule(), - "Binary control codes error"); - ThrowXPMReaderException(CorruptImageError,CorruptImage,image); + "Binary control codes error"); + ThrowXPMReaderException(CorruptImageError,CorruptImage,image); } textlist=StringToListMod(xpm_buffer); if (textlist == (char **) NULL) @@ -396,25 +427,40 @@ static Image *ReadXPMImage(const ImageInfo *image_info,ExceptionInfo *exception) for (i=0; textlist[i] != (char *) NULL; i++) { }; (void) LogMagickEvent(CoderEvent,GetMagickModule(), - "TextList has %lu entries", i); + "TextList has %u entries", i); (void) LogMagickEvent(CoderEvent,GetMagickModule(), "TextList"); for (i=0; textlist[i] != (char *) NULL; i++) (void) LogMagickEvent(CoderEvent,GetMagickModule(), - " %lu: \"%s\"", i, textlist[i]); + " %u: \"%s\"", i, textlist[i]); } #endif /* Initialize image structure. */ - keys=MagickAllocateResourceLimitedArray(char **,image->colors,sizeof(char *)); - if (keys == (char **) NULL) - ThrowXPMReaderException(ResourceLimitError,MemoryAllocationFailed,image); - for (i=0; i < (long) image->colors; i++) - keys[i]=(char *) NULL; - if (!AllocateImageColormap(image,image->colors)) + keys=MagickAllocateResourceLimitedArray(xpmkey_t *,image->colors,sizeof(xpmkey_t)); + if (keys == (xpmkey_t *) NULL) ThrowXPMReaderException(ResourceLimitError,MemoryAllocationFailed,image); + for (i=0; i < image->colors; i++) + { + keys[i].index=0; + keys[i].keyval=0; + } + if (image->colors <= MaxColormapSize) + { + if (!AllocateImageColormap(image,image->colors)) + ThrowXPMReaderException(ResourceLimitError,MemoryAllocationFailed,image); + } + else + { + /* Allocate temporary palette. */ + if (image->colormap != (PixelPacket *)NULL) + MagickFreeMemory(image->colormap); + image->colormap=MagickAllocateMemory(PixelPacket *,MagickArraySize((size_t) image->colors,sizeof(PixelPacket))); + if (image->colormap==NULL) + ThrowXPMReaderException(ResourceLimitError,MemoryAllocationFailed,image); + } /* Read image colormap. @@ -425,121 +471,195 @@ static Image *ReadXPMImage(const ImageInfo *image_info,ExceptionInfo *exception) "Parsing colormap..."); colormap_initialized=MagickFalse; for (j=0; j < image->colors; j++) - { - p=textlist[i++]; - if ((p == (char *) NULL) || (p[0] == '\0')) - break; - if (image->logging) - (void) LogMagickEvent(CoderEvent,GetMagickModule(), - " %lu: %s", i-1, textlist[i-1]); - if (strlen(p) < width) - break; - keys[j]=MagickAllocateResourceLimitedMemory(char *,(size_t) width+1); - if (keys[j] == (char *) NULL) - ThrowXPMReaderException(ResourceLimitError,MemoryAllocationFailed,image); - keys[j][width]='\0'; - (void) strncpy(keys[j],p,width); - /* - Parse color. - */ - (void) strcpy(target,"gray"); - q=ParseColor(p+width); - if (q != (char *) NULL) - { - while (!isspace((int) (*q)) && (*q != '\0')) - q++; - (void) strlcpy(target,q,MaxTextExtent); - q=ParseColor(target); - if (q != (char *) NULL) - *q='\0'; - } - (void) MagickStripString(target); - if (LocaleCompare(target,"none") == 0) - { - image->storage_class=DirectClass; - image->matte=True; - none=j; - (void) strcpy(target,"black"); - } - if (!QueryColorDatabase(target,&image->colormap[j],exception)) - { - /* Promote warning to error */ - exception->severity = CorruptImageError; + { + p=textlist[i++]; + if ((p == (char *) NULL) || (p[0] == '\0')) break; - } - /* We are going to be done now */ - if (j+1 == image->colors) - colormap_initialized=MagickTrue; - } + if (image->logging) + (void) LogMagickEvent(CoderEvent,GetMagickModule(), + " %u: %s", i-1, textlist[i-1]); + if (strlen(p) < width) + break; + + keys[j].index = j; + keys[j].keyval = 0; + for (k=0; k < width; k++) + keys[j].keyval |= ((xpmkeyval_t) p[k]) << (k * 8); + + /* printf("Key[%03u] =\"%s\" (0x%04X)\n", keys[j].index, p, (unsigned int) keys[j].keyval); */ + /* + Parse color. + */ + (void) strlcpy(target,"gray",sizeof(target)); + q=ParseColor(p+width); + if (q != (char *) NULL) + { + while (!isspace((int) (*q)) && (*q != '\0')) + q++; + (void) strlcpy(target,q,MaxTextExtent); + q=ParseColor(target); + if (q != (char *) NULL) + *q='\0'; + } + (void) MagickStripString(target); + if (LocaleCompare(target,"none") == 0) + { + image->storage_class=DirectClass; + image->matte=True; + none=j; + (void) strlcpy(target,"black",sizeof(target)); + } + if (!QueryColorDatabase(target,&image->colormap[j],exception)) + { + /* Promote warning to error */ + exception->severity = CorruptImageError; + break; + } + /* We are going to be done now */ + if (j+1 == image->colors) + colormap_initialized=MagickTrue; + } if (!colormap_initialized) ThrowXPMReaderException(CorruptImageError,CorruptImage,image); + + /* + Log the XPM Colormap if logging is enabled. + */ + if (image->logging) + { + char + name[MaxTextExtent]; + + unsigned int + ii; + + register PixelPacket + *p; + + /* + Display image colormap. + */ + (void) LogMagickEvent(CoderEvent,GetMagickModule(), + "XPM Colormap (Depth %u):", image->depth); + p=image->colormap; + for (ii=0; ii < image->colors; ii++) + { + char + tuple[MaxTextExtent]; + + GetColorTuple(p,image->depth,image->matte,False,tuple); + (void) QueryColorname(image,p,X11Compliance,name,&image->exception); + (void) LogMagickEvent(CoderEvent,GetMagickModule(), + " %" MAGICK_SIZE_T_F "u: %.1024s\t %.1024s", + (MAGICK_SIZE_T) ii,tuple,name); + p++; + } + } + image->depth=GetImageDepth(image,&image->exception); image->depth=NormalizeDepthToOctet(image->depth); - j=0; - key[width]='\0'; + if (!image_info->ping) { + xpmkey_t + key = { 0, 0 }, + *keyp; + + xpmkeyval_t + keyval; + + j = 0; + + /* + Sort keys by kval + */ + qsort((void *) keys,image->colors, sizeof(keys[0]), XPMKeyCompare); + +#if 0 + for (j=0; j < image->colors; j++) + printf("Key[%03u] = (0x%04X)\n", keys[j].index, (unsigned int) keys[j].keyval); +#endif + /* Read image pixels. */ (void) LogMagickEvent(CoderEvent,GetMagickModule(), - "Parsing pixels..."); + "Parsing pixels..."); for (y=0; y < (long) image->rows; y++) - { - p=textlist[i++]; - if ((p == (char *) NULL) || (p[0] == '\0')) - break; - if (image->logging) - (void) LogMagickEvent(CoderEvent,GetMagickModule(), - " %lu: %s", i-1, textlist[i-1]); - r=SetImagePixelsEx(image,0,y,image->columns,1,exception); - if (r == (PixelPacket *) NULL) - break; - indexes=AccessMutableIndexes(image); - for (x=0; x < (long) image->columns; x++) { - /* (void) strncpy(key,p,width); */ - for (k=0; k < (long) width; k++) + p=textlist[i++]; + if ((p == (char *) NULL) || (p[0] == '\0')) + break; + if (image->logging) + (void) LogMagickEvent(CoderEvent,GetMagickModule(), + " %u: %s", i-1, textlist[i-1]); + r=SetImagePixelsEx(image,0,y,image->columns,1,exception); + if (r == (PixelPacket *) NULL) + break; + indexes=AccessMutableIndexes(image); + for (x=0; x < (long) image->columns; x++) { - key[k]=p[k]; - if (p[k] == '\0') + keyval=0; + for (k=0; k < width; k++) { - status=MagickFail; - break; + if (p[k] == '\0') + { + (void) LogMagickEvent(CoderEvent,GetMagickModule(), + "Unexpected end of row %ld! (k=%u)", y, k); + ThrowXPMReaderException(CorruptImageError,UnexpectedEndOfFile, + image); + break; + } + keyval |= ((xpmkeyval_t) p[k]) << (k * 8); } + if (keyval != key.keyval) + { + key.keyval = keyval; + keyp=(void *) bsearch((const void *) &key,(void *) keys,image->colors, + sizeof(keys[0]),XPMKeyCompare); + if (keyp != (void *) NULL) + { + key.index = keyp->index; + } + else + { + (void) LogMagickEvent(CoderEvent,GetMagickModule(), + "Failed to find key! (0x%04X)", + key.keyval); + ThrowXPMReaderException(CorruptImageError,CorruptImage, + image); + break; + } + } + + VerifyColormapIndex(image,key.index); + if (image->storage_class == PseudoClass) + indexes[x]=(IndexPacket) key.index; + *r=image->colormap[key.index]; + r->opacity=(Quantum) + (key.index == none ? TransparentOpacity : OpaqueOpacity); + r++; + p+=width; } - if (MagickFail == status) + if (!SyncImagePixelsEx(image,exception)) break; - key[k]='\0'; - if (strcmp(key,keys[j]) != 0) - for (j=0; j < Max(image->colors-1,1); j++) - if (strcmp(key,keys[j]) == 0) - break; - VerifyColormapIndex(image,j); - if (image->storage_class == PseudoClass) - indexes[x]=(IndexPacket) j; - *r=image->colormap[j]; - r->opacity=(Quantum) - (j == none ? TransparentOpacity : OpaqueOpacity); - r++; - p+=width; } - if (MagickFail == status) - break; - if (!SyncImagePixelsEx(image,exception)) - break; - } if (y < (long) image->rows) ThrowXPMReaderException(CorruptImageError,InsufficientImageDataInFile,image); } /* Free resources. */ - for (i=0; i < (long) image->colors; i++) - MagickFreeResourceLimitedMemory(keys[i]); MagickFreeResourceLimitedMemory(keys); MagickFreeResourceLimitedMemory(textlist); MagickFreeResourceLimitedMemory(xpm_buffer); + if (image->colors > MaxColormapSize) + { + /* Release temporary palette. */ + MagickFreeMemory(image->colormap); + image->colors = 0; + image->storage_class = DirectClass; + } CloseBlob(image); StopTimer(&image->timer); return(image); @@ -735,8 +855,8 @@ static unsigned int WritePICONImage(const ImageInfo *image_info,Image *image) characters_per_pixel, colors; - ImageCharacteristics - characteristics; + ImageCharacteristics + characteristics; assert(image_info != (const ImageInfo *) NULL); assert(image_info->signature == MagickSignature); @@ -867,7 +987,7 @@ static unsigned int WritePICONImage(const ImageInfo *image_info,Image *image) if (transparent) { if (i == (long) (colors-1)) - (void) strcpy(name,"grey75"); + (void) strlcpy(name,"grey75",sizeof(name)); } /* Write XPM color. @@ -1101,7 +1221,7 @@ static unsigned int WriteXPMImage(const ImageInfo *image_info,Image *image) if (transparent) { if (i == (long) (colors-1)) - (void) strcpy(name,"None"); + (void) strlcpy(name,"None",sizeof(name)); } /* Write XPM color. |