summaryrefslogtreecommitdiff
path: root/coders/pict.c
diff options
context:
space:
mode:
Diffstat (limited to 'coders/pict.c')
-rw-r--r--coders/pict.c258
1 files changed, 155 insertions, 103 deletions
diff --git a/coders/pict.c b/coders/pict.c
index ccaa117..3e15ea9 100644
--- a/coders/pict.c
+++ b/coders/pict.c
@@ -1,5 +1,5 @@
/*
-% Copyright (C) 2003-2019 GraphicsMagick Group
+% Copyright (C) 2003-2020 GraphicsMagick Group
% Copyright (C) 2002 ImageMagick Studio
% Copyright 1991-1999 E. I. du Pont de Nemours and Company
%
@@ -90,8 +90,9 @@
*/
#define ValidateRectangle(rectangle) \
((!EOFBlob(image) && \
- (rectangle.bottom - rectangle.top > 0) && \
- (rectangle.right - rectangle.left > 0)))
+ !((rectangle.bottom | rectangle.top | rectangle.right | rectangle.left ) & 0x8000) && \
+ !(rectangle.bottom < rectangle.top) && \
+ !(rectangle.right < rectangle.left)))
/*
Issue a trace message with rectangle dimensions.
@@ -112,22 +113,22 @@
typedef struct _PICTPixmap
{
- short
+ magick_uint16_t
version,
pack_type;
- unsigned long
+ magick_uint32_t
pack_size,
horizontal_resolution,
vertical_resolution;
- short
+ magick_uint16_t
pixel_type,
bits_per_pixel,
component_count,
component_size;
- unsigned long
+ magick_uint32_t
plane_bytes,
table,
reserved;
@@ -135,7 +136,7 @@ typedef struct _PICTPixmap
typedef struct _PICTRectangle
{
- short
+ magick_uint16_t
top,
left,
bottom,
@@ -769,12 +770,8 @@ static unsigned char *DecodeImage(const ImageInfo *image_info,
const unsigned int bits_per_pixel)
{
unsigned long
- j,
y;
- register unsigned long
- i;
-
register const unsigned char
*p;
@@ -783,6 +780,7 @@ static unsigned char *DecodeImage(const ImageInfo *image_info,
size_t
allocated_pixels,
+ scanline_alloc,
row_bytes;
unsigned char
@@ -791,15 +789,19 @@ static unsigned char *DecodeImage(const ImageInfo *image_info,
*scanline = NULL;
unsigned long
- bytes_per_pixel,
- length,
number_pixels,
- scanline_length,
width;
magick_off_t
file_size;
+ unsigned int
+ bytes_per_pixel,
+ i,
+ j,
+ length,
+ scanline_length;
+
ARG_NOT_USED(image_info);
if (image->logging)
@@ -878,17 +880,23 @@ static unsigned char *DecodeImage(const ImageInfo *image_info,
/*
Allocate pixel and scanline buffer.
*/
- pixels=MagickAllocateArray(unsigned char *,image->rows,row_bytes);
+ allocated_pixels=MagickArraySize(image->rows,row_bytes);
+ pixels=MagickAllocateClearedMemory(unsigned char *,allocated_pixels);
if (pixels == (unsigned char *) NULL)
{
ThrowException(&image->exception,ResourceLimitError,MemoryAllocationFailed,
image->filename);
goto decode_error_exit;
}
- allocated_pixels=image->rows*row_bytes;
- (void) memset(pixels,0,allocated_pixels);
- /* FIXME: Extra +1 avoids heap read overflow (oss-fuzz 12019) */
- scanline=MagickAllocateMemory(unsigned char *,row_bytes+1);
+ /* Use a worst-case allocation policy (because we can afford to) */
+ if (bytes_per_line < 8)
+ scanline_alloc = bytes_per_line;
+ else if (bytes_per_line <= 200)
+ scanline_alloc = 256U+256U; /* Allocate extra for RLE over-run */
+ else
+ scanline_alloc = 65536U+256U; /* Allocate extra for RLE over-run */
+
+ scanline=MagickAllocateClearedMemory(unsigned char *,scanline_alloc);
if (scanline == (unsigned char *) NULL)
{
ThrowException(&image->exception,ResourceLimitError,MemoryAllocationFailed,
@@ -903,7 +911,7 @@ static unsigned char *DecodeImage(const ImageInfo *image_info,
*/
for (y=0; y < image->rows; y++)
{
- q=pixels+y*width;
+ q=pixels+(size_t)y*width;
number_pixels=bytes_per_line;
if (ReadBlob(blob,number_pixels,(char *) scanline) != number_pixels)
{
@@ -922,45 +930,44 @@ static unsigned char *DecodeImage(const ImageInfo *image_info,
*/
for (y=0; y < image->rows; y++)
{
- q=pixels+y*width;
+ q=pixels+(size_t)y*width;
if (bytes_per_line > 200)
scanline_length=ReadBlobMSBShort(blob);
else
scanline_length=ReadBlobByte(blob);
- if (scanline_length >= row_bytes)
+ if (image->logging)
+ (void) LogMagickEvent(CoderEvent,GetMagickModule(),
+ "scanline_length = %u, "
+ "scanline_alloc = %"MAGICK_SIZE_T_F"u",
+ scanline_length, (MAGICK_SIZE_T)scanline_alloc);
+ if (scanline_length < 2)
{
ThrowException(&image->exception,CorruptImageError,UnableToUncompressImage,
- "scanline length exceeds row bytes");
+ image->filename);
goto decode_error_exit;
}
if (ReadBlob(blob,scanline_length,(char *) scanline) != scanline_length)
{
ThrowException(&image->exception,CorruptImageError,UnexpectedEndOfFile,
- image->filename);
+ "Scanline length too small!");
goto decode_error_exit;
}
- (void) memset(scanline+scanline_length,0,row_bytes-scanline_length); /* Zero */
+ #if 0
+ (void) memset(scanline+scanline_length,0,scanline_alloc-scanline_length); /* Zero remainder */
+ #endif
for (j=0; j < scanline_length; )
if ((scanline[j] & 0x80) == 0)
{
length=(scanline[j] & 0xff)+1;
number_pixels=length*bytes_per_pixel;
p=ExpandBuffer(expand_buffer,scanline+j+1,&number_pixels,bits_per_pixel);
- if (j+number_pixels >= scanline_length)
- {
- errno=0;
- ThrowException(&image->exception,CorruptImageError,UnableToUncompressImage,
- "Decoded RLE pixels exceeds allocation!");
- goto decode_error_exit;
- }
- if ((q+number_pixels > pixels+allocated_pixels))
+ if (!((pixels+allocated_pixels)-number_pixels > q))
{
ThrowException(&image->exception,CorruptImageError,UnableToUncompressImage,
"Decoded RLE pixels exceeds allocation!");
goto decode_error_exit;
}
-
- (void) memcpy(q,p,number_pixels); /* ASAN report */
+ (void) memcpy(q,p,number_pixels);
q+=number_pixels;
j+=length*bytes_per_pixel+1;
}
@@ -971,7 +978,7 @@ static unsigned char *DecodeImage(const ImageInfo *image_info,
p=ExpandBuffer(expand_buffer,scanline+j+1,&number_pixels,bits_per_pixel);
for (i=0; i < length; i++)
{
- if ((q+number_pixels > pixels+allocated_pixels))
+ if (!((pixels+allocated_pixels)-number_pixels > q))
{
ThrowException(&image->exception,CorruptImageError,UnableToUncompressImage,
"Decoded RLE pixels exceeds allocation!");
@@ -1244,6 +1251,9 @@ static Image *ReadPICTImage(const ImageInfo *image_info,
size_t
length;
+ magick_off_t
+ file_size;
+
unsigned int
jpeg,
status;
@@ -1259,6 +1269,7 @@ static Image *ReadPICTImage(const ImageInfo *image_info,
status=OpenBlob(image_info,image,ReadBinaryBlobMode,exception);
if (status == False)
ThrowPICTReaderException(FileOpenError,UnableToOpenFile,image);
+ file_size=GetBlobSize(image);
pixmap.bits_per_pixel=0;
pixmap.component_count=0;
/*
@@ -1287,25 +1298,11 @@ static Image *ReadPICTImage(const ImageInfo *image_info,
if (version != 1)
ThrowPICTReaderException(CorruptImageError,ImproperImageHeader,image);
/*
- Validate dimensions
- */
- if ((frame.left < 0) || (frame.right < 0) || (frame.top < 0) || (frame.bottom < 0) ||
- (frame.left >= frame.right) || (frame.top >= frame.bottom))
- {
- ThrowPICTReaderException(CorruptImageError,ImproperImageHeader,image);
- }
-
- /*
Create black canvas.
*/
flags=0;
image->columns=frame.right-frame.left;
image->rows=frame.bottom-frame.top;
- SetRedSample(&image->background_color,0);
- SetGreenSample(&image->background_color,0);
- SetBlueSample(&image->background_color,0);
- SetOpacitySample(&image->background_color,OpaqueOpacity);
- SetImage(image,OpaqueOpacity);
if (IsEventLogging())
(void) LogMagickEvent(CoderEvent,GetMagickModule(),
@@ -1314,6 +1311,17 @@ static Image *ReadPICTImage(const ImageInfo *image_info,
if (CheckImagePixelLimits(image, exception) != MagickPass)
ThrowPICTReaderException(ResourceLimitError,ImagePixelLimitExceeded,image);
+ SetRedSample(&image->background_color,0);
+ SetGreenSample(&image->background_color,0);
+ SetBlueSample(&image->background_color,0);
+ SetOpacitySample(&image->background_color,OpaqueOpacity);
+ if (SetImageEx(image,OpaqueOpacity,exception) != MagickPass)
+ {
+ CloseBlob(image);
+ DestroyImage(image);
+ return (Image *) NULL;
+ }
+
/*
Interpret PICT opcodes.
*/
@@ -1645,8 +1653,8 @@ static Image *ReadPICTImage(const ImageInfo *image_info,
i=(*p++);
j=(*p);
q->red=ScaleCharToQuantum((i & 0x7c) << 1);
- q->green=ScaleCharToQuantum(((i & 0x03) << 6) |
- ((j & 0xe0) >> 2));
+ q->green=ScaleCharToQuantum((((size_t)i & 0x03) << 6) |
+ (((size_t) j & 0xe0) >> 2));
q->blue=ScaleCharToQuantum((j & 0x1f) << 3);
}
else
@@ -1655,16 +1663,16 @@ static Image *ReadPICTImage(const ImageInfo *image_info,
q->red=ScaleCharToQuantum(*p);
q->green=
ScaleCharToQuantum(*(p+tile_image->columns));
- q->blue=ScaleCharToQuantum(*(p+2*tile_image->columns));
+ q->blue=ScaleCharToQuantum(*(p+ (size_t)2*tile_image->columns));
}
else
{
q->opacity=(Quantum) (MaxRGB-ScaleCharToQuantum(*p));
q->red=ScaleCharToQuantum(*(p+tile_image->columns));
q->green=(Quantum)
- ScaleCharToQuantum(*(p+2*tile_image->columns));
+ ScaleCharToQuantum(*(p+ (size_t)2*tile_image->columns));
q->blue=
- ScaleCharToQuantum(*(p+3*tile_image->columns));
+ ScaleCharToQuantum(*(p+ (size_t)3*tile_image->columns));
}
}
p++;
@@ -1674,7 +1682,7 @@ static Image *ReadPICTImage(const ImageInfo *image_info,
break;
if ((tile_image->storage_class == DirectClass) &&
(pixmap.bits_per_pixel != 16))
- p+=(pixmap.component_count-1)*tile_image->columns;
+ p+=((size_t) pixmap.component_count-1)*tile_image->columns;
if (destination.bottom == (long) image->rows)
if (QuantumTick(y,tile_image->rows))
if (!MagickMonitorFormatted(y,tile_image->rows,&image->exception,
@@ -1783,61 +1791,93 @@ static Image *ReadPICTImage(const ImageInfo *image_info,
continue;
if (code == 0x8200)
{
- FILE
- *file;
-
- char
- tmpfile[MaxTextExtent];
-
/*
Embedded JPEG.
*/
jpeg=True;
- clone_info=CloneImageInfo(image_info);
- clone_info->blob=(void *) NULL;
- clone_info->length=0;
- file=AcquireTemporaryFileStream(tmpfile,BinaryFileIOMode);
- if (file == (FILE *) NULL)
- {
- DestroyImageInfo(clone_info);
- ThrowReaderTemporaryFileException(image_info->filename);
- }
- (void) strlcpy(clone_info->filename,"JPEG:",sizeof(clone_info->filename));
- (void) strlcat(clone_info->filename,tmpfile,sizeof(clone_info->filename));
length=ReadBlobMSBLong(image);
- if (length > 154)
+ if ((length > 154) && ((file_size <= 0) || ((size_t) (file_size-TellBlob(image)) > length)))
{
+ void
+ *blob,
+ *blob_alloc;
+
+ const size_t
+ blob_alloc_size = length-154;
+
for (i=0; i < 6; i++)
(void) ReadBlobMSBLong(image);
ReadRectangle(frame);
TraceRectangle(image,frame);
if (!ValidateRectangle(frame))
- {
- (void) fclose(file);
- ThrowPICTReaderException(CorruptImageError,ImproperImageHeader,image);
- }
+ ThrowPICTReaderException(CorruptImageError,ImproperImageHeader,image);
for (i=0; i < 122; i++)
if (ReadBlobByte(image) == EOF)
- break;
- for (i=0; i < (long) (length-154); i++)
+ ThrowPICTReaderException(CorruptImageError,UnexpectedEndOfFile,image);
+ if ((blob_alloc=MagickAllocateMemory(void *,blob_alloc_size)) == (void *) NULL)
+ ThrowPICTReaderException(ResourceLimitError,MemoryAllocationFailed,image);
+ blob=blob_alloc;
+ clone_info=CloneImageInfo(image_info);
+ clone_info->blob=(void *) NULL;
+ clone_info->length=0;
+ (void) strlcpy(clone_info->filename,"JPEG:",sizeof(clone_info->filename));
+ if (ReadBlobZC(image,blob_alloc_size,&blob) != blob_alloc_size)
{
- if ((c=ReadBlobByte(image)) == EOF)
- break;
- (void) fputc(c,file);
+ MagickFreeMemory(blob_alloc);
+ ThrowPICTReaderException(CorruptImageError,UnexpectedEndOfFile,image);
+ }
+ if (blob != blob_alloc)
+ {
+ if (image->logging)
+ (void) LogMagickEvent(CoderEvent,GetMagickModule(),
+ "Tile Zero copy read.");
}
+ tile_image=BlobToImage(clone_info, blob, blob_alloc_size, &image->exception );
+ DestroyImageInfo(clone_info);
+ clone_info=(ImageInfo *) NULL;
+ MagickFreeMemory(blob_alloc);
}
- (void) fclose(file);
- tile_image=ReadImage(clone_info,exception);
- (void) LiberateTemporaryFile(clone_info->filename);
- DestroyImageInfo(clone_info);
- clone_info=(ImageInfo *) NULL;
if (tile_image == (Image *) NULL)
continue;
+ if (IsEventLogging())
+ (void) LogMagickEvent(CoderEvent,GetMagickModule(),
+ "Tile Dimensions: %lux%lu",
+ tile_image->columns,tile_image->rows);
+ if (IsEventLogging())
+ (void) LogMagickEvent(CoderEvent,GetMagickModule(),
+ "Tile Resolution: %gx%g %s",
+ tile_image->x_resolution,
+ tile_image->y_resolution,
+ tile_image->units == PixelsPerInchResolution ?
+ "pixels/inch" :
+ (tile_image->units == PixelsPerCentimeterResolution ?
+ "pixels/centimeter" :
+ "pixels"));
FormatString(geometry,"%lux%lu",Max(image->columns,tile_image->columns),
Max(image->rows,tile_image->rows));
- (void) TransformImage(&image,(char *) NULL,geometry);
- (void) CompositeImage(image,CopyCompositeOp,tile_image,frame.left,
- frame.right);
+ if (IsEventLogging())
+ (void) LogMagickEvent(CoderEvent,GetMagickModule(),
+ "Tile Transform %lux%lu ==> %s",
+ tile_image->columns,tile_image->rows,
+ geometry);
+ if (TransformImage(&tile_image,(char *) NULL,geometry) != MagickPass)
+ {
+ if (IsEventLogging())
+ (void) LogMagickEvent(CoderEvent,GetMagickModule(),
+ "Tile transform failed!");
+ }
+ if (IsEventLogging())
+ (void) LogMagickEvent(CoderEvent,GetMagickModule(),
+ "Tile Composite of %lux%lu on canvas %lux%lu at +%u,+%u",
+ tile_image->columns,tile_image->rows,
+ image->columns,image->rows,frame.left,frame.right);
+ if (CompositeImage(image,CopyCompositeOp,tile_image,frame.left,
+ frame.right) != MagickPass)
+ {
+ if (IsEventLogging())
+ (void) LogMagickEvent(CoderEvent,GetMagickModule(),
+ "Tile composite failed!");
+ }
image->compression=tile_image->compression;
DestroyImage(tile_image);
tile_image=(Image *) NULL;
@@ -1873,6 +1913,7 @@ static Image *ReadPICTImage(const ImageInfo *image_info,
ThrowException(exception,CorruptImageError,UnexpectedEndOfFile,
image->filename);
CloseBlob(image);
+ StopTimer(&image->timer);
return(image);
}
@@ -2002,8 +2043,8 @@ static unsigned int WritePICTImage(const ImageInfo *image_info,Image *image)
#define PictVersion 0x11
double
- x_resolution,
- y_resolution;
+ x_resolution = 72.0,
+ y_resolution = 72.0;
long
y;
@@ -2099,8 +2140,19 @@ static unsigned int WritePICTImage(const ImageInfo *image_info,Image *image)
pixmap.table=0;
pixmap.reserved=0;
transfer_mode=0;
- x_resolution=image->x_resolution ? image->x_resolution : 72.0;
- y_resolution=image->y_resolution ? image->y_resolution : 72.0;
+ if ((image->x_resolution > MagickEpsilon) &&
+ (image->y_resolution > MagickEpsilon))
+ {
+ x_resolution=image->x_resolution;
+ y_resolution=image->y_resolution;
+ if (image->units == PixelsPerCentimeterResolution)
+ {
+ x_resolution *= 2.54;
+ y_resolution *= 2.54;
+ }
+ x_resolution=ConstrainToRange(0.0,(double) 0xffff,x_resolution);
+ y_resolution=ConstrainToRange(0.0,(double) 0xffff,y_resolution);
+ }
storage_class=image->storage_class;
if (image->compression == JPEGCompression)
storage_class=DirectClass;
@@ -2121,7 +2173,7 @@ static unsigned int WritePICTImage(const ImageInfo *image_info,Image *image)
bytes_per_line=(size_t) image->columns;
if (storage_class == DirectClass)
bytes_per_line = MagickArraySize(bytes_per_line, image->matte ? 4 : 3);
- if ((bytes_per_line == 0) || (bytes_per_line > 0x7FFF))
+ if ((bytes_per_line == 0) || (bytes_per_line > 0x7FFFU) || ((row_bytes+MaxCount*2U) >= 0x7FFFU))
ThrowPICTWriterException(CoderError,UnsupportedNumberOfColumns,image);
#if defined(PTRDIFF_MAX)
/*
@@ -2133,7 +2185,7 @@ static unsigned int WritePICTImage(const ImageInfo *image_info,Image *image)
ThrowPICTWriterException(ResourceLimitError,MemoryAllocationFailed,image);
#endif /* if defined(PTRDIFF_MAX) */
buffer=MagickAllocateMemory(unsigned char *,PictInfoSize);
- packed_scanline=MagickAllocateMemory(unsigned char *,row_bytes+MaxCount);
+ packed_scanline=MagickAllocateMemory(unsigned char *,row_bytes+MaxCount*2U);
scanline=MagickAllocateMemory(unsigned char *,row_bytes);
if ((buffer == (unsigned char *) NULL) ||
(packed_scanline == (unsigned char *) NULL) ||
@@ -2389,8 +2441,8 @@ static unsigned int WritePICTImage(const ImageInfo *image_info,Image *image)
red=scanline;
green=scanline+image->columns;
- blue=scanline+2*image->columns;
- opacity=scanline+3*image->columns;
+ blue=scanline+ (size_t)2*image->columns;
+ opacity=scanline+ (size_t)3*image->columns;
for (y=0; y < (long) image->rows; y++)
{
p=AcquireImagePixels(image,0,y,image->columns,1,&image->exception);
@@ -2398,13 +2450,13 @@ static unsigned int WritePICTImage(const ImageInfo *image_info,Image *image)
break;
red=scanline;
green=scanline+image->columns;
- blue=scanline+2*image->columns;
+ blue=scanline+ (size_t)2*image->columns;
if (image->matte)
{
opacity=scanline;
red=scanline+image->columns;
- green=scanline+2*image->columns;
- blue=scanline+3*image->columns;
+ green=scanline+ (size_t)2*image->columns;
+ blue=scanline+ (size_t)3*image->columns;
}
for (x=0; x < (long) image->columns; x++)
{