Index: GraphicsMagick-1.2.5/coders/rgb.c
===================================================================
--- GraphicsMagick-1.2.5.orig/coders/rgb.c	2018-02-20 13:51:38.644102348 +0100
+++ GraphicsMagick-1.2.5/coders/rgb.c	2018-02-20 14:02:07.810775847 +0100
@@ -1,5 +1,5 @@
 /*
-% Copyright (C) 2003 GraphicsMagick Group
+% Copyright (C) 2003 - 2017 GraphicsMagick Group
 % Copyright (C) 2002 ImageMagick Studio
 % Copyright 1991-1999 E. I. du Pont de Nemours and Company
 %
@@ -49,6 +50,12 @@
 static unsigned int
   WriteRGBImage(const ImageInfo *,Image *);
 
+#define ThrowRGBReaderException(code_,reason_,image_) \
+{ \
+  MagickFreeMemory(scanline);                 \
+  ThrowReaderException(code_,reason_,image_); \
+}
+
 static size_t MagickArraySize(const size_t count, const size_t size)
 {
   size_t
@@ -100,17 +107,18 @@ static Image *ReadRGBImage(const ImageIn
     y;
 
   register long
-    i,
-    x;
+    i;
 
   register PixelPacket
     *q;
 
   size_t
-    count;
+    count,
+    tile_packets,
+    x;
 
   unsigned char
-    *scanline;
+    *scanline = (unsigned char *) NULL;
 
   unsigned int
     status;
@@ -119,13 +127,37 @@ static Image *ReadRGBImage(const ImageIn
     packet_size,
     quantum_size;
 
+  ImportPixelAreaOptions
+    import_options;
+
   assert(image_info != (const ImageInfo *) NULL);
   assert(image_info->signature == MagickSignature);
   assert(exception != (ExceptionInfo *) NULL);
   assert(exception->signature == MagickSignature);
   image=AllocateImage(image_info);
   if ((image->columns == 0) || (image->rows == 0))
-    ThrowReaderException(OptionError,MustSpecifyImageSize,image);
+    ThrowRGBReaderException(OptionError,MustSpecifyImageSize,image);
+  if (image->logging)
+    (void) LogMagickEvent(CoderEvent,GetMagickModule(),
+                          "Tile %lux%lu%+ld%+ld, Offset %lu",
+                          image->tile_info.width,image->tile_info.height,
+                          image->tile_info.x,image->tile_info.y,
+                          image->offset);
+  /*
+    There is the option to either require that the tile be within the
+    image bounds or to return only the portion of the tile which is
+    within the image bounds (returned image is smaller than requested
+    tile size).  For the moment we choose the former.
+  */
+  if ((image->tile_info.width > image->columns) ||
+      (image->tile_info.x < 0) ||
+      (image->tile_info.width+image->tile_info.x > image->columns) ||
+      (image->tile_info.height > image->rows) ||
+      (image->tile_info.y < 0) ||
+      (image->tile_info.height+image->tile_info.y > image->rows)
+      )
+    ThrowReaderException(CorruptImageError,ImproperImageHeader,image);
+
   if (image_info->interlace != PartitionInterlace)
     {
       /*
@@ -133,7 +165,7 @@ static Image *ReadRGBImage(const ImageIn
       */
       status=OpenBlob(image_info,image,ReadBinaryBlobMode,exception);
       if (status == False)
-        ThrowReaderException(FileOpenError,UnableToOpenFile,image);
+        ThrowRGBReaderException(FileOpenError,UnableToOpenFile,image);
       for (i=0; i < image->offset; i++)
         {
           if (EOF == ReadBlobByte(image))
@@ -141,6 +173,13 @@ static Image *ReadRGBImage(const ImageIn
                            image->filename);
         }
     }
+
+  if (image->logging)
+    (void) LogMagickEvent(CoderEvent,GetMagickModule(),
+                          "Tile %lux%lu%+ld%+ld",
+                          image->tile_info.width,image->tile_info.height,
+                          image->tile_info.x,image->tile_info.y);
+
   /*
     Allocate memory for a scanline.
   */
@@ -157,10 +196,23 @@ static Image *ReadRGBImage(const ImageIn
       image->matte=True;
       packet_size=(quantum_size*4)/8;
     }
-  scanline=MagickAllocateMemory(unsigned char *,
-    packet_size*image->tile_info.width);
+
+  scanline=MagickAllocateArray(unsigned char *,
+                               packet_size,image->tile_info.width);
   if (scanline == (unsigned char *) NULL)
-    ThrowReaderException(ResourceLimitError,MemoryAllocationFailed,image);
+    ThrowRGBReaderException(ResourceLimitError,MemoryAllocationFailed,image);
+  tile_packets=(size_t) packet_size*image->tile_info.width;
+  x=(size_t) (packet_size*image->tile_info.x);
+  /*
+    Initialize import options.
+  */
+  ImportPixelAreaOptionsInit(&import_options);
+  if (image_info->endian != UndefinedEndian)
+    import_options.endian=image_info->endian;
+
+  /*
+    Support starting at intermediate image frame.
+  */
   if (image_info->subrange != 0)
     while (image->scene < image_info->subimage)
     {
@@ -169,9 +221,9 @@ static Image *ReadRGBImage(const ImageIn
       */
       image->scene++;
       for (y=0; y < (long) image->rows; y++)
-        (void) ReadBlob(image,packet_size*image->tile_info.width,scanline);
+        if (ReadBlob(image,tile_packets,scanline) != tile_packets)
+          break;
     }
-  x=(long) (packet_size*image->tile_info.x);
   do
   {
     /*
@@ -185,22 +237,26 @@ static Image *ReadRGBImage(const ImageIn
       case NoInterlace:
       default:
       {
+        QuantumType
+          quantum_type;
+
         /*
           No interlacing:  RGBRGBRGBRGBRGBRGB...
         */
+        quantum_type=(image->matte ? RGBAQuantum : RGBQuantum);
         for (y=0; y < image->tile_info.y; y++)
-          (void) ReadBlob(image,packet_size*image->tile_info.width,scanline);
+          if (ReadBlob(image,tile_packets,scanline) != tile_packets)
+            break;
         for (y=0; y < (long) image->rows; y++)
         {
           if ((y > 0) || (image->previous == (Image *) NULL))
-            (void) ReadBlob(image,packet_size*image->tile_info.width,scanline);
+            if (ReadBlob(image,tile_packets,scanline) != tile_packets)
+              break;
           q=SetImagePixels(image,0,y,image->columns,1);
           if (q == (PixelPacket *) NULL)
             break;
-          if (!image->matte)
-            (void) ImportImagePixelArea(image,RGBQuantum,quantum_size,scanline+x,0,0);
-          else
-            (void) ImportImagePixelArea(image,RGBAQuantum,quantum_size,scanline+x,0,0);
+          (void) ImportImagePixelArea(image,quantum_type,quantum_size,scanline+x,
+                                      &import_options,0);
           if (!SyncImagePixels(image))
             break;
           if (image->previous == (Image *) NULL)
@@ -210,7 +266,8 @@ static Image *ReadRGBImage(const ImageIn
         }
         count=image->tile_info.height-image->rows-image->tile_info.y;
         for (i=0; i < (long) count; i++)
-          (void) ReadBlob(image,packet_size*image->tile_info.width,scanline);
+          if (ReadBlob(image,tile_packets,scanline) != tile_packets)
+            break;
         break;
       }
       case LineInterlace:
@@ -220,24 +277,32 @@ static Image *ReadRGBImage(const ImageIn
         */
         packet_size=(quantum_size)/8;
         for (y=0; y < image->tile_info.y; y++)
-          (void) ReadBlob(image,packet_size*image->tile_info.width,scanline);
+          if (ReadBlob(image,tile_packets,scanline) != tile_packets)
+            break;
         for (y=0; y < (long) image->rows; y++)
         {
           if ((y > 0) || (image->previous == (Image *) NULL))
-            (void) ReadBlob(image,packet_size*image->tile_info.width,scanline);
+            if (ReadBlob(image,tile_packets,scanline) != tile_packets)
+              break;
           q=SetImagePixels(image,0,y,image->columns,1);
           if (q == (PixelPacket *) NULL)
             break;
-          (void) ImportImagePixelArea(image,RedQuantum,quantum_size,scanline+x,0,0);
-          (void) ReadBlob(image,packet_size*image->tile_info.width,scanline);
-          (void) ImportImagePixelArea(image,GreenQuantum,quantum_size,scanline+x,0,0);
-          (void) ReadBlob(image,packet_size*image->tile_info.width,scanline);
-          (void) ImportImagePixelArea(image,BlueQuantum,quantum_size,scanline+x,0,0);
+          (void) ImportImagePixelArea(image,RedQuantum,quantum_size,scanline+x,
+                                      &import_options,0);
+          if (ReadBlob(image,tile_packets,scanline) != tile_packets)
+            break;
+          (void) ImportImagePixelArea(image,GreenQuantum,quantum_size,scanline+x,
+                                      &import_options,0);
+          if (ReadBlob(image,tile_packets,scanline) != tile_packets)
+            break;
+          (void) ImportImagePixelArea(image,BlueQuantum,quantum_size,scanline+x,
+                                      &import_options,0);
           if (image->matte)
             {
-              (void) ReadBlob(image,packet_size*image->tile_info.width,
-                scanline);
-              (void) ImportImagePixelArea(image,AlphaQuantum,quantum_size,scanline+x,0,0);
+              if (ReadBlob(image,tile_packets,scanline) != tile_packets)
+                break;
+              (void) ImportImagePixelArea(image,AlphaQuantum,quantum_size,scanline+x,
+                                          &import_options,0);
             }
           if (!SyncImagePixels(image))
             break;
@@ -248,7 +313,8 @@ static Image *ReadRGBImage(const ImageIn
         }
         count=image->tile_info.height-image->rows-image->tile_info.y;
         for (i=0; i < (long) count; i++)
-          (void) ReadBlob(image,packet_size*image->tile_info.width,scanline);
+          if (ReadBlob(image,tile_packets,scanline) != tile_packets)
+            break;
         break;
       }
       case PlaneInterlace:
@@ -265,21 +331,24 @@ static Image *ReadRGBImage(const ImageIn
             AppendImageFormat("R",image->filename);
             status=OpenBlob(image_info,image,ReadBinaryBlobMode,exception);
             if (status == False)
-              ThrowReaderException(FileOpenError,UnableToOpenFile,image);
+              ThrowRGBReaderException(FileOpenError,UnableToOpenFile,image);
           }
         packet_size=(quantum_size)/8;
         for (y=0; y < image->tile_info.y; y++)
-          (void) ReadBlob(image,packet_size*image->tile_info.width,scanline);
+          if (ReadBlob(image,tile_packets,scanline) != tile_packets)
+            break;
         i=0;
         span=image->rows*(image->matte ? 4 : 3);
         for (y=0; y < (long) image->rows; y++)
         {
           if ((y > 0) || (image->previous == (Image *) NULL))
-            (void) ReadBlob(image,packet_size*image->tile_info.width,scanline);
+            if (ReadBlob(image,tile_packets,scanline) != tile_packets)
+              break;
           q=SetImagePixels(image,0,y,image->columns,1);
           if (q == (PixelPacket *) NULL)
             break;
-          (void) ImportImagePixelArea(image,RedQuantum,quantum_size,scanline+x,0,0);
+          (void) ImportImagePixelArea(image,RedQuantum,quantum_size,scanline+x,
+                                      &import_options,0);
           if (!SyncImagePixels(image))
             break;
           if (image->previous == (Image *) NULL)
@@ -290,24 +359,28 @@ static Image *ReadRGBImage(const ImageIn
         }
         count=image->tile_info.height-image->rows-image->tile_info.y;
         for (i=0; i < (long) count; i++)
-          (void) ReadBlob(image,packet_size*image->tile_info.width,scanline);
+          if (ReadBlob(image,tile_packets,scanline) != tile_packets)
+            break;
         if (image_info->interlace == PartitionInterlace)
           {
             CloseBlob(image);
             AppendImageFormat("G",image->filename);
             status=OpenBlob(image_info,image,ReadBinaryBlobMode,exception);
             if (status == False)
-              ThrowReaderException(FileOpenError,UnableToOpenFile,image);
+              ThrowRGBReaderException(FileOpenError,UnableToOpenFile,image);
           }
         for (y=0; y < image->tile_info.y; y++)
-          (void) ReadBlob(image,packet_size*image->tile_info.width,scanline);
+          if (ReadBlob(image,tile_packets,scanline) != tile_packets)
+            break;
         for (y=0; y < (long) image->rows; y++)
         {
-          (void) ReadBlob(image,packet_size*image->tile_info.width,scanline);
+          if (ReadBlob(image,tile_packets,scanline) != tile_packets)
+            break;
           q=GetImagePixels(image,0,y,image->columns,1);
           if (q == (PixelPacket *) NULL)
             break;
-          (void) ImportImagePixelArea(image,GreenQuantum,quantum_size,scanline+x,0,0);
+          (void) ImportImagePixelArea(image,GreenQuantum,quantum_size,scanline+x,
+                                      &import_options,0);
           if (!SyncImagePixels(image))
             break;
           if (image->previous == (Image *) NULL)
@@ -318,24 +391,28 @@ static Image *ReadRGBImage(const ImageIn
         }
         count=image->tile_info.height-image->rows-image->tile_info.y;
         for (i=0; i < (long) count; i++)
-          (void) ReadBlob(image,packet_size*image->tile_info.width,scanline);
+          if (ReadBlob(image,tile_packets,scanline) != tile_packets)
+            break;
         if (image_info->interlace == PartitionInterlace)
           {
             CloseBlob(image);
             AppendImageFormat("B",image->filename);
             status=OpenBlob(image_info,image,ReadBinaryBlobMode,exception);
             if (status == False)
-              ThrowReaderException(FileOpenError,UnableToOpenFile,image);
+              ThrowRGBReaderException(FileOpenError,UnableToOpenFile,image);
           }
         for (y=0; y < image->tile_info.y; y++)
-          (void) ReadBlob(image,packet_size*image->tile_info.width,scanline);
+          if (ReadBlob(image,tile_packets,scanline) != tile_packets)
+            break;
         for (y=0; y < (long) image->rows; y++)
         {
-          (void) ReadBlob(image,packet_size*image->tile_info.width,scanline);
+          if (ReadBlob(image,tile_packets,scanline) != tile_packets)
+            break;
           q=GetImagePixels(image,0,y,image->columns,1);
           if (q == (PixelPacket *) NULL)
             break;
-          (void) ImportImagePixelArea(image,BlueQuantum,quantum_size,scanline+x,0,0);
+          (void) ImportImagePixelArea(image,BlueQuantum,quantum_size,scanline+x,
+                                      &import_options,0);
           if (!SyncImagePixels(image))
             break;
           if (image->previous == (Image *) NULL)
@@ -346,7 +423,8 @@ static Image *ReadRGBImage(const ImageIn
         }
         count=image->tile_info.height-image->rows-image->tile_info.y;
         for (i=0; i < (long) count; i++)
-          (void) ReadBlob(image,packet_size*image->tile_info.width,scanline);
+          if (ReadBlob(image,tile_packets,scanline) != tile_packets)
+            break;
         if (image->matte)
           {
             /*
@@ -358,19 +436,20 @@ static Image *ReadRGBImage(const ImageIn
                 AppendImageFormat("A",image->filename);
                 status=OpenBlob(image_info,image,ReadBinaryBlobMode,exception);
                 if (status == False)
-                  ThrowReaderException(FileOpenError,UnableToOpenFile,image);
+                  ThrowRGBReaderException(FileOpenError,UnableToOpenFile,image);
               }
             for (y=0; y < image->tile_info.y; y++)
-              (void) ReadBlob(image,packet_size*image->tile_info.width,
-                scanline);
+              if (ReadBlob(image,tile_packets,scanline) != tile_packets)
+                break;
             for (y=0; y < (long) image->rows; y++)
             {
-              (void) ReadBlob(image,packet_size*image->tile_info.width,
-                scanline);
+              if (ReadBlob(image,tile_packets,scanline) != tile_packets)
+                break;
               q=GetImagePixels(image,0,y,image->columns,1);
               if (q == (PixelPacket *) NULL)
                 break;
-              (void) ImportImagePixelArea(image,AlphaQuantum,quantum_size,scanline+x,0,0);
+              (void) ImportImagePixelArea(image,AlphaQuantum,quantum_size,scanline+x,
+                                          &import_options,0);
               if (!SyncImagePixels(image))
                 break;
               if (image->previous == (Image *) NULL)
@@ -381,8 +460,8 @@ static Image *ReadRGBImage(const ImageIn
             }
             count=image->tile_info.height-image->rows-image->tile_info.y;
             for (i=0; i < (long) count; i++)
-              (void) ReadBlob(image,packet_size*image->tile_info.width,
-                scanline);
+              if (ReadBlob(image,tile_packets,scanline) != tile_packets)
+                break;
           }
         if (image_info->interlace == PartitionInterlace)
           (void) strlcpy(image->filename,image_info->filename,MaxTextExtent);
@@ -403,8 +482,8 @@ static Image *ReadRGBImage(const ImageIn
         break;
     if (image_info->interlace == PartitionInterlace)
       break;
-    count=ReadBlob(image,packet_size*image->tile_info.width,scanline);
-    if (count != 0)
+    count=ReadBlob(image,tile_packets,scanline);
+    if (count == tile_packets)
       {
         /*
           Allocate next image structure.
@@ -546,6 +626,12 @@ static unsigned int WriteRGBImage(const
     quantum_size,
     scene;
 
+  ExportPixelAreaOptions
+    export_options;
+
+  ExportPixelAreaInfo
+    export_info;
+
   assert(image_info != (const ImageInfo *) NULL);
   assert(image_info->signature == MagickSignature);
   assert(image != (Image *) NULL);
@@ -594,35 +680,44 @@ static unsigned int WriteRGBImage(const
       ThrowWriterException(ResourceLimitError,MemoryAllocationFailed,image);
 
     /*
+      Initialize export options.
+    */
+    ExportPixelAreaOptionsInit(&export_options);
+    if (image->endian != UndefinedEndian)
+      export_options.endian=image->endian;
+    else if (image_info->endian != UndefinedEndian)
+      export_options.endian=image_info->endian;
+
+    /*
       Convert MIFF to RGB raster pixels.
     */
     (void) TransformColorspace(image,RGBColorspace);
     if (LocaleCompare(image_info->magick,"RGBA") == 0)
       if (!image->matte)
         SetImageOpacity(image,OpaqueOpacity);
+
     switch (image_info->interlace)
     {
       case NoInterlace:
       default:
       {
+        QuantumType
+          quantum_type;
+
         /*
           No interlacing:  RGBRGBRGBRGBRGBRGB...
         */
+        quantum_type=RGBQuantum;
+        if (LocaleCompare(image_info->magick,"RGBA") == 0)
+          quantum_type=RGBAQuantum;
         for (y=0; y < (long) image->rows; y++)
         {
           p=AcquireImagePixels(image,0,y,image->columns,1,&image->exception);
           if (p == (const PixelPacket *) NULL)
             break;
-          if (LocaleCompare(image_info->magick,"RGBA") != 0)
-            {
-              (void) ExportImagePixelArea(image,RGBQuantum,quantum_size,pixels,0,0);
-              (void) WriteBlob(image,packet_size*image->columns,pixels);
-            }
-          else
-            {
-              (void) ExportImagePixelArea(image,RGBAQuantum,quantum_size,pixels,0,0);
-              (void) WriteBlob(image,packet_size*image->columns,pixels);
-            }
+          (void) ExportImagePixelArea(image,quantum_type,quantum_size,pixels,
+                                      &export_options,&export_info);
+          (void) WriteBlob(image,export_info.bytes_exported,pixels);
           if (image->previous == (Image *) NULL)
             if (QuantumTick(y,image->rows))
               if (!MagickMonitor(SaveImageText,y,image->rows,&image->exception))
@@ -640,16 +735,20 @@ static unsigned int WriteRGBImage(const
           p=AcquireImagePixels(image,0,y,image->columns,1,&image->exception);
           if (p == (const PixelPacket *) NULL)
             break;
-          (void) ExportImagePixelArea(image,RedQuantum,quantum_size,pixels,0,0);
-          (void) WriteBlob(image,image->columns,pixels);
-          (void) ExportImagePixelArea(image,GreenQuantum,quantum_size,pixels,0,0);
-          (void) WriteBlob(image,image->columns,pixels);
-          (void) ExportImagePixelArea(image,BlueQuantum,quantum_size,pixels,0,0);
-          (void) WriteBlob(image,image->columns,pixels);
+          (void) ExportImagePixelArea(image,RedQuantum,quantum_size,pixels,
+                                      &export_options,&export_info);
+          (void) WriteBlob(image,export_info.bytes_exported,pixels);
+          (void) ExportImagePixelArea(image,GreenQuantum,quantum_size,pixels,
+                                      &export_options,&export_info);
+          (void) WriteBlob(image,export_info.bytes_exported,pixels);
+          (void) ExportImagePixelArea(image,BlueQuantum,quantum_size,pixels,
+                                      &export_options,&export_info);
+          (void) WriteBlob(image,export_info.bytes_exported,pixels);
           if (LocaleCompare(image_info->magick,"RGBA") == 0)
             {
-              (void) ExportImagePixelArea(image,AlphaQuantum,quantum_size,pixels,0,0);
-              (void) WriteBlob(image,image->columns,pixels);
+              (void) ExportImagePixelArea(image,AlphaQuantum,quantum_size,pixels,
+                                          &export_options,&export_info);
+              (void) WriteBlob(image,export_info.bytes_exported,pixels);
             }
           if (QuantumTick(y,image->rows))
             if (!MagickMonitor(SaveImageText,y,image->rows,&image->exception))
@@ -675,8 +774,9 @@ static unsigned int WriteRGBImage(const
           p=AcquireImagePixels(image,0,y,image->columns,1,&image->exception);
           if (p == (const PixelPacket *) NULL)
             break;
-          (void) ExportImagePixelArea(image,RedQuantum,quantum_size,pixels,0,0);
-          (void) WriteBlob(image,image->columns,pixels);
+          (void) ExportImagePixelArea(image,RedQuantum,quantum_size,pixels,
+                                      &export_options,&export_info);
+          (void) WriteBlob(image,export_info.bytes_exported,pixels);
         }
         if (image_info->interlace == PartitionInterlace)
           {
@@ -693,8 +793,9 @@ static unsigned int WriteRGBImage(const
           p=AcquireImagePixels(image,0,y,image->columns,1,&image->exception);
           if (p == (const PixelPacket *) NULL)
             break;
-          (void) ExportImagePixelArea(image,GreenQuantum,quantum_size,pixels,0,0);
-          (void) WriteBlob(image,image->columns,pixels);
+          (void) ExportImagePixelArea(image,GreenQuantum,quantum_size,pixels,
+                                      &export_options,&export_info);
+          (void) WriteBlob(image,export_info.bytes_exported,pixels);
         }
         if (image_info->interlace == PartitionInterlace)
           {
@@ -711,8 +812,9 @@ static unsigned int WriteRGBImage(const
           p=AcquireImagePixels(image,0,y,image->columns,1,&image->exception);
           if (p == (const PixelPacket *) NULL)
             break;
-          (void) ExportImagePixelArea(image,BlueQuantum,quantum_size,pixels,0,0);
-          (void) WriteBlob(image,image->columns,pixels);
+          (void) ExportImagePixelArea(image,BlueQuantum,quantum_size,pixels,
+                                      &export_options,&export_info);
+          (void) WriteBlob(image,export_info.bytes_exported,pixels);
         }
         if (LocaleCompare(image_info->magick,"RGBA") == 0)
           {
@@ -733,8 +835,9 @@ static unsigned int WriteRGBImage(const
                 &image->exception);
               if (p == (const PixelPacket *) NULL)
                 break;
-              (void) ExportImagePixelArea(image,AlphaQuantum,quantum_size,pixels,0,0);
-              (void) WriteBlob(image,image->columns,pixels);
+              (void) ExportImagePixelArea(image,AlphaQuantum,quantum_size,pixels,
+                                          &export_options,&export_info);
+              (void) WriteBlob(image,export_info.bytes_exported,pixels);
             }
           }
         if (image_info->interlace == PartitionInterlace)
