Index: GraphicsMagick-1.2.5/coders/bmp.c
===================================================================
--- GraphicsMagick-1.2.5.orig/coders/bmp.c	2019-01-03 11:12:24.672843453 +0100
+++ GraphicsMagick-1.2.5/coders/bmp.c	2019-01-03 11:20:51.379229019 +0100
@@ -1,5 +1,5 @@
 /*
-% Copyright (C) 2003 GraphicsMagick Group
+% Copyright (C) 2003 - 2018 GraphicsMagick Group
 % Copyright (C) 2002 ImageMagick Studio
 % Copyright 1991-1999 E. I. du Pont de Nemours and Company
 %
@@ -38,12 +38,12 @@
 */
 #include "magick/studio.h"
 #include "magick/blob.h"
-#include "magick/constitute.h"
-#include "magick/pixel_cache.h"
 #include "magick/color.h"
+#include "magick/constitute.h"
 #include "magick/log.h"
 #include "magick/magick.h"
 #include "magick/monitor.h"
+#include "magick/pixel_cache.h"
 #include "magick/profile.h"
 #include "magick/transform.h"
 #include "magick/utility.h"
@@ -57,20 +57,33 @@
 #undef BI_PNG
 #define BI_PNG  5
 #if !defined(MSWINDOWS) || defined(__MINGW32__)
+#undef BI_RGB
 #define BI_RGB  0
+#undef BI_RLE8
 #define BI_RLE8  1
+#undef BI_RLE4
 #define BI_RLE4  2
+#undef BI_BITFIELDS
 #define BI_BITFIELDS  3
 
+#undef LCS_CALIBRATED_RBG
 #define LCS_CALIBRATED_RBG  0
+#undef LCS_sRGB
 #define LCS_sRGB  1
+#undef LCS_WINDOWS_COLOR_SPACE
 #define LCS_WINDOWS_COLOR_SPACE  2
+#undef PROFILE_LINKED
 #define PROFILE_LINKED  3
+#undef PROFILE_EMBEDDED
 #define PROFILE_EMBEDDED  4
 
+#undef LCS_GM_BUSINESS
 #define LCS_GM_BUSINESS  1  /* Saturation */
+#undef LCS_GM_GRAPHICS
 #define LCS_GM_GRAPHICS  2  /* Relative */
+#undef LCS_GM_IMAGES
 #define LCS_GM_IMAGES  4  /* Perceptual */
+#undef LCS_GM_ABS_COLORIMETRIC
 #define LCS_GM_ABS_COLORIMETRIC  8  /* Absolute */
 #endif
 
@@ -79,33 +92,37 @@
 */
 typedef struct _BMPInfo
 {
-  unsigned long
-    file_size,
+  size_t
+    file_size,  /* 0 or size of file in bytes */
+    image_size; /* bytes_per_line*image->rows or uint32_t from file */
+
+  magick_uint32_t
     ba_offset,
-    offset_bits,
-    size;
+    offset_bits,/* Starting position of image data in bytes */
+    size;       /* Header size 12 = v2, 12-64 OS/2 v2, 40 = v3, 108 = v4, 124 = v5 */
 
-  long
-    width,
-    height;
+  magick_int32_t
+    width,      /* BMP width */
+    height;     /* BMP height (negative means bottom-up) */
 
-  unsigned short
+  magick_uint16_t
     planes,
     bits_per_pixel;
 
-  unsigned long
+  magick_uint32_t
     compression,
-    image_size,
     x_pixels,
     y_pixels,
     number_colors,
+    colors_important;
+
+  magick_uint32_t
     red_mask,
     green_mask,
     blue_mask,
-    alpha_mask,
-    colors_important;
+    alpha_mask;
 
-  long
+  magick_int32_t
     colorspace;
 
   PrimaryInfo
@@ -120,6 +137,17 @@ typedef struct _BMPInfo
 */
 static unsigned int
   WriteBMPImage(const ImageInfo *,Image *);
+static size_t MagickArraySize(const size_t count, const size_t size)
+{
+  size_t
+    allocation_size;
+
+  allocation_size = size * count;
+  if ((count != 0) && (size != allocation_size/count))
+    allocation_size = 0;
+
+  return allocation_size;
+}
 
 /*
 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
@@ -137,13 +165,13 @@ static unsigned int
 %
 %  The format of the DecodeImage method is:
 %
-%      unsigned int DecodeImage(Image *image,const unsigned long compression,
+%      MagickPassFail DecodeImage(Image *image,const unsigned long compression,
 %        unsigned char *pixels)
 %
 %  A description of each parameter follows:
 %
-%    o status:  Method DecodeImage returns True if all the pixels are
-%      uncompressed without error, otherwise False.
+%    o status:  Method DecodeImage returns MagickPass if all the pixels are
+%      uncompressed without error, otherwise MagickFail.
 %
 %    o image: The address of a structure of type Image.
 %
@@ -155,19 +183,22 @@ static unsigned int
 %    o pixels:  The address of a byte (8 bits) array of pixel data created by
 %      the decoding process.
 %
+%    o pixels_size: The size of the allocated buffer array.
 %
 */
-static unsigned int DecodeImage(Image *image,const unsigned long compression,
-  unsigned char *pixels)
+static MagickPassFail DecodeImage(Image *image,const unsigned long compression,
+                                  unsigned char *pixels, const size_t pixels_size)
 {
-  long
-    byte,
-    count,
+  unsigned long
+    x,
     y;
 
-  register long
-    i,
-    x;
+  unsigned int
+    i;
+
+  int
+    byte,
+    count;
 
   register unsigned char
     *q;
@@ -177,113 +208,161 @@ static unsigned int DecodeImage(Image *i
 
   assert(image != (Image *) NULL);
   assert(pixels != (unsigned char *) NULL);
-  (void) LogMagickEvent(CoderEvent,GetMagickModule(),"  Decoding RLE pixels");
-  (void) memset(pixels,0,image->columns*image->rows);
+
+  (void) memset(pixels,0,pixels_size);
   byte=0;
   x=0;
   q=pixels;
-  end=pixels + (size_t) image->columns*image->rows;
-  for (y=0; y < (long) image->rows; )
-  {
-    if (q < pixels || q  >= end)
-      break;
-    count=ReadBlobByte(image);
-    if (count == EOF)
-      break;
-    if (count != 0)
-      {
-        count=Min(count, end - q);
-        /*
-          Encoded mode.
-        */
-        byte=ReadBlobByte(image);
-        if (compression == BI_RLE8)
-          {
-            for ( i=count; i != 0; --i )
+  end=pixels + pixels_size;
+  /*
+    Decompress sufficient data to support the number of pixels (or
+    rows) in the image and then return.
+
+    Do not wait to read the final EOL and EOI markers (if not yet
+    encountered) since we always read this marker just before we
+    return.
+  */
+  for (y=0; y < image->rows; )
+    {
+      if (q < pixels || q >= end)
+        {
+          break;
+        }
+      count=ReadBlobByte(image);
+      if (count == EOF)
+        return MagickFail;
+      if (count > 0)
+        {
+          count=Min(count, end - q);
+          /*
+            Encoded mode.
+          */
+          byte=ReadBlobByte(image);
+          if (byte == EOF)
+            return MagickFail;
+          if (compression == BI_RLE8)
+            {
+              for ( i=count; i != 0; --i )
+                {
+                  *q++=(unsigned char) byte;
+                }
+            }
+          else
+            {
+              for ( i=0; i < (unsigned int) count; i++ )
+                {
+                  *q++=(unsigned char)
+                    ((i & 0x01) ? (byte & 0x0f) : ((byte >> 4) & 0x0f));
+                }
+            }
+          x+=count;
+        }
+      else
+        {
+          /*
+            Escape mode.
+          */
+          count=ReadBlobByte(image);
+          if (count == EOF)
+            return MagickFail;
+          if (count == 0x01)
+            {
+              if (image->logging)
+                (void) LogMagickEvent(CoderEvent,GetMagickModule(),
+                                      "  RLE Escape code encountered");
+              goto rle_decode_done;
+            }
+          switch (count)
+            {
+            case 0x00:
               {
-                *q++=(unsigned char) byte;
+                /*
+                  End of line.
+                */
+                x=0;
+                y++;
+                q=pixels+y*image->columns;
+                break;
               }
-          }
-        else
-          {
-            for ( i=0; i < count; i++ )
+            case 0x02:
               {
-                *q++=(unsigned char)
-                  ((i & 0x01) ? (byte & 0x0f) : ((byte >> 4) & 0x0f));
-              }
-          }
-        x+=count;
-      }
-    else
-      {
-        /*
-          Escape mode.
-        */
-        count=ReadBlobByte(image);
-        if (count == 0x01)
-          return(True);
-        switch ((int) count)
-        {
-          case 0x00:
-          {
-            /*
-              End of line.
-            */
-            x=0;
-            y++;
-            q=pixels+y*image->columns;
-            break;
-          }
-          case 0x02:
-          {
-            /*
-              Delta mode.
-            */
-            x+=ReadBlobByte(image);
-            y+=ReadBlobByte(image);
-            q=pixels+y*image->columns+x;
-            break;
-          }
-          default:
-          {
-            /*
-              Absolute mode.
-            */
-    	    count=Min(count, end - q);
-            if (compression == BI_RLE8)
-              for (i=count; i != 0; --i)
-                *q++=ReadBlobByte(image);
-            else
-              for (i=0; i < count; i++)
-              {
-                if ((i & 0x01) == 0)
-                  byte=ReadBlobByte(image);
-                *q++=(unsigned char)
-                  ((i & 0x01) ? (byte & 0x0f) : ((byte >> 4) & 0x0f));
+                /*
+                  Delta mode.
+                */
+                byte=ReadBlobByte(image);
+                if (byte == EOF)
+                  return MagickFail;
+                x+=byte;
+                byte=ReadBlobByte(image);
+                if (byte == EOF)
+                  return MagickFail;
+                y+=byte;
+                q=pixels+y*image->columns+x;
+                break;
               }
-            x+=count;
-            /*
-              Read pad byte.
-            */
-            if (compression == BI_RLE8)
+            default:
               {
-                if (count & 0x01)
-                  (void) ReadBlobByte(image);
+                /*
+                  Absolute mode.
+                */
+                count=Min(count, end - q);
+                if (count < 0)
+                  return MagickFail;
+                if (compression == BI_RLE8)
+                  for (i=count; i != 0; --i)
+                    {
+                      byte=ReadBlobByte(image);
+                      if (byte == EOF)
+                        return MagickFail;
+                      *q++=byte;
+                    }
+                else
+                  for (i=0; i < (unsigned int) count; i++)
+                    {
+                      if ((i & 0x01) == 0)
+                        {
+                          byte=ReadBlobByte(image);
+                          if (byte == EOF)
+                            return MagickFail;
+                        }
+                      *q++=(unsigned char)
+                        ((i & 0x01) ? (byte & 0x0f) : ((byte >> 4) & 0x0f));
+                    }
+                x+=count;
+                /*
+                  Read pad byte.
+                */
+                if (compression == BI_RLE8)
+                  {
+                    if (count & 0x01)
+                      if (ReadBlobByte(image) == EOF)
+                        return MagickFail;
+                  }
+                else
+                  if (((count & 0x03) == 1) || ((count & 0x03) == 2))
+                    if (ReadBlobByte(image) == EOF)
+                      return MagickFail;
+                break;
               }
-            else
-              if (((count & 0x03) == 1) || ((count & 0x03) == 2))
-                (void) ReadBlobByte(image);
-            break;
-          }
+            }
         }
-      }
-    if (QuantumTick(y,image->rows))
-      if (!MagickMonitor(LoadImageText,y,image->rows,&image->exception))
-        break;
-  }
+      if (QuantumTick(y,image->rows))
+        if (!MagickMonitor(LoadImageText,y,
+                           image->rows,
+                           &image->exception))
+          break;
+    }
   (void) ReadBlobByte(image);  /* end of line */
   (void) ReadBlobByte(image);
-  return(True);
+ rle_decode_done:
+  if ((size_t) (q-pixels) < pixels_size)
+    {
+      if (image->logging)
+        (void) LogMagickEvent(CoderEvent,GetMagickModule(),
+                              "  RLE decoded output is truncated");
+      return MagickFail;
+    }
+  return(MagickPass);
 }
 
 /*
@@ -453,6 +532,13 @@ static unsigned int IsBMP(const unsigned
 %
 %
 */
+#define ThrowBMPReaderException(code_,reason_,image_) \
+do { \
+  MagickFreeMemory(bmp_colormap); \
+  MagickFreeMemory(pixels); \
+  ThrowReaderException(code_,reason_,image_); \
+} while (0);
+
 static Image *ReadBMPImage(const ImageInfo *image_info,ExceptionInfo *exception)
 {
   BMPInfo
@@ -467,7 +553,7 @@ static Image *ReadBMPImage(const ImageIn
   long
     y;
 
-  unsigned long
+  magick_uint32_t
     blue,
     green,
     opacity,
@@ -489,18 +575,23 @@ static Image *ReadBMPImage(const ImageIn
     *p;
 
   size_t
+    bytes_per_line,
     count,
-    length;
+    length,
+    pixels_size;
 
   unsigned char
+    *bmp_colormap,
     magick[12],
     *pixels;
 
   unsigned int
     status;
 
-  unsigned long
-    bytes_per_line;
+  magick_off_t
+    file_remaining,
+    file_size,
+    offset;
 
   /*
     Open image file.
@@ -509,17 +600,21 @@ static Image *ReadBMPImage(const ImageIn
   assert(image_info->signature == MagickSignature);
   assert(exception != (ExceptionInfo *) NULL);
   assert(exception->signature == MagickSignature);
+  bmp_colormap=(unsigned char *) NULL;
+  pixels=(unsigned char *) NULL;
   logging=LogMagickEvent(CoderEvent,GetMagickModule(),"enter");
   image=AllocateImage(image_info);
   status=OpenBlob(image_info,image,ReadBinaryBlobMode,exception);
   if (status == False)
-    ThrowReaderException(FileOpenError,UnableToOpenFile,image);
+    ThrowBMPReaderException(FileOpenError,UnableToOpenFile,image);
+  file_size=GetBlobSize(image);
   /*
     Determine if this is a BMP file.
   */
   (void) memset(&bmp_info,0,sizeof(BMPInfo));
   bmp_info.ba_offset=0;
   start_position=0;
+  magick[0]=magick[1]=0;
   count=ReadBlob(image,2,(char *) magick);
   do
   {
@@ -534,38 +629,56 @@ static Image *ReadBMPImage(const ImageIn
     /*
       Verify BMP identifier.
     */
+    /* if (bmp_info.ba_offset == 0) */ /* FIXME: Investigate. Start position needs to always advance! */
     start_position=TellBlob(image)-2;
     bmp_info.ba_offset=0;
+     /* "BA" is OS/2 bitmap array file */
     while (LocaleNCompare((char *) magick,"BA",2) == 0)
     {
       bmp_info.file_size=ReadBlobLSBLong(image);
       bmp_info.ba_offset=ReadBlobLSBLong(image);
       bmp_info.offset_bits=ReadBlobLSBLong(image);
-      count=ReadBlob(image,2,(char *) magick);
+      if ((count=ReadBlob(image,2,(char *) magick)) != 2)
+        break;
     }
-    if (logging)
+    if (logging && count == 2)
       (void) LogMagickEvent(CoderEvent,GetMagickModule(),"  Magick: %c%c",
         magick[0],magick[1]);
-    if ((count == 0) || ((LocaleNCompare((char *) magick,"BM",2) != 0) &&
-        (LocaleNCompare((char *) magick,"CI",2) != 0)))
-      ThrowReaderException(CorruptImageError,ImproperImageHeader,image);
-    bmp_info.file_size=ReadBlobLSBLong(image);
-    (void) ReadBlobLSBLong(image);
-    bmp_info.offset_bits=ReadBlobLSBLong(image);
-    bmp_info.size=ReadBlobLSBLong(image);
+    if ((count != 2) || /* Found "BA" header from above above */
+        ((LocaleNCompare((char *) magick,"BM",2) != 0) && /* "BM" is Windows or OS/2 file. */
+         (LocaleNCompare((char *) magick,"CI",2) != 0)))  /* "CI" is OS/2 Color Icon */
+      ThrowBMPReaderException(CorruptImageError,ImproperImageHeader,image);
+    bmp_info.file_size=ReadBlobLSBLong(image); /* File size in bytes */
+    (void) ReadBlobLSBLong(image); /* Reserved */
+    bmp_info.offset_bits=ReadBlobLSBLong(image); /* Bit map offset from start of file */
+    bmp_info.size=ReadBlobLSBLong(image);  /* BMP Header size */
     if (logging)
       (void) LogMagickEvent(CoderEvent,GetMagickModule(),
-        "  BMP size: %lu, File size: %lu",
-        bmp_info.size, (unsigned long) GetBlobSize(image));
+                            "  Header size: %u\n"
+                            "    Offset bits: %u\n"
+                            "    Image data offset: %u",
+                            bmp_info.size,
+                            bmp_info.offset_bits,
+                            bmp_info.ba_offset);
+
+    if ((bmp_info.file_size != 0) && ((magick_off_t) bmp_info.file_size > file_size))
+      ThrowBMPReaderException(CorruptImageError,ImproperImageHeader,image);
+    if ((bmp_info.size != 12) && (bmp_info.size != 40) && (bmp_info.size != 108)
+        && (bmp_info.size != 124) &&
+        (!(bmp_info.size >= 12 && bmp_info.size <= 64)))
+      ThrowBMPReaderException(CorruptImageError,ImproperImageHeader,image);
+    if (bmp_info.offset_bits < bmp_info.size)
+      ThrowBMPReaderException(CorruptImageError,ImproperImageHeader,image);
+
     if (bmp_info.size == 12)
       {
         /*
           Windows 2.X or OS/2 BMP image file.
         */
-        bmp_info.width=(magick_int16_t) ReadBlobLSBShort(image);
-        bmp_info.height=(magick_int16_t) ReadBlobLSBShort(image);
-        bmp_info.planes=ReadBlobLSBShort(image);
-        bmp_info.bits_per_pixel=ReadBlobLSBShort(image);
+        bmp_info.width=(magick_int16_t) ReadBlobLSBShort(image); /* Width */
+        bmp_info.height=(magick_int16_t) ReadBlobLSBShort(image); /* Height */
+        bmp_info.planes=ReadBlobLSBShort(image); /* # of color planes */
+        bmp_info.bits_per_pixel=ReadBlobLSBShort(image); /* Bits per pixel */
         bmp_info.x_pixels=0;
         bmp_info.y_pixels=0;
         bmp_info.number_colors=0;
@@ -577,9 +690,11 @@ static Image *ReadBMPImage(const ImageIn
             (void) LogMagickEvent(CoderEvent,GetMagickModule(),
               "  Format: Windows 2.X or OS/2 Bitmap");
             (void) LogMagickEvent(CoderEvent,GetMagickModule(),
-              "  Geometry: %ldx%ld",bmp_info.width,bmp_info.height);
+              "  Geometry: %dx%d",bmp_info.width,bmp_info.height);
             (void) LogMagickEvent(CoderEvent,GetMagickModule(),
-              "  Bits per pixel: %d",bmp_info.bits_per_pixel);
+              "  Planes: %u",bmp_info.planes);
+            (void) LogMagickEvent(CoderEvent,GetMagickModule(),
+              "  Bits per pixel: %u",bmp_info.bits_per_pixel);
           }
       }
     else
@@ -588,7 +703,7 @@ static Image *ReadBMPImage(const ImageIn
           Microsoft Windows 3.X or later BMP image file.
         */
         if (bmp_info.size < 40)
-          ThrowReaderException(CorruptImageWarning,NonOS2HeaderSizeError,
+          ThrowBMPReaderException(CorruptImageError,NonOS2HeaderSizeError,
             image);
 
         /*
@@ -599,44 +714,47 @@ static Image *ReadBMPImage(const ImageIn
           origin in the upper-left corner.  The meaning of negative values
           is not defined for width.
         */
-        bmp_info.width=(magick_int32_t) ReadBlobLSBLong(image);
-        bmp_info.height=(magick_int32_t) ReadBlobLSBLong(image);
-        bmp_info.planes=ReadBlobLSBShort(image);
-        bmp_info.bits_per_pixel=ReadBlobLSBShort(image);
-        bmp_info.compression=ReadBlobLSBLong(image);
-        bmp_info.image_size=ReadBlobLSBLong(image);
-        bmp_info.x_pixels=ReadBlobLSBLong(image);
-        bmp_info.y_pixels=ReadBlobLSBLong(image);
-        bmp_info.number_colors=ReadBlobLSBLong(image);
-        bmp_info.colors_important=ReadBlobLSBLong(image);
-        if (bmp_info.number_colors > GetBlobSize(image))
-          ThrowReaderException(CorruptImageError,InsufficientImageDataInFile,image);
+        bmp_info.width=(magick_int32_t) ReadBlobLSBLong(image); /* Width */
+        bmp_info.height=(magick_int32_t) ReadBlobLSBLong(image); /* Height */
+        bmp_info.planes=ReadBlobLSBShort(image); /* # of color planes */
+        bmp_info.bits_per_pixel=ReadBlobLSBShort(image); /* Bits per pixel (1/4/8/16/24/32) */
+        bmp_info.compression=ReadBlobLSBLong(image); /* Compression method */
+        bmp_info.image_size=ReadBlobLSBLong(image); /* Bitmap size (bytes) */
+        bmp_info.x_pixels=ReadBlobLSBLong(image); /* Horizontal resolution (pixels/meter) */
+        bmp_info.y_pixels=ReadBlobLSBLong(image); /* Vertical resolution (pixels/meter) */
+        bmp_info.number_colors=ReadBlobLSBLong(image); /* Number of colors */
+        bmp_info.colors_important=ReadBlobLSBLong(image); /* Minimum important colors */
         profile_data=0;
         profile_size=0;
         if (logging)
           {
             (void) LogMagickEvent(CoderEvent,GetMagickModule(),
-              "  Format: MS Windows bitmap");
+              "  Format: MS Windows bitmap 3.X");
+            (void) LogMagickEvent(CoderEvent,GetMagickModule(),
+              "  Geometry: %dx%d",bmp_info.width,bmp_info.height);
             (void) LogMagickEvent(CoderEvent,GetMagickModule(),
-              "  Geometry: %ldx%ld",bmp_info.width,bmp_info.height);
+              "  Planes: %u",bmp_info.planes);
             (void) LogMagickEvent(CoderEvent,GetMagickModule(),
-              "  Bits per pixel: %d",bmp_info.bits_per_pixel);
+              "  Bits per pixel: %u",bmp_info.bits_per_pixel);
             switch ((int) bmp_info.compression)
             {
               case BI_RGB:
               {
+                /* uncompressed */
                 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
                   "  Compression: BI_RGB");
                 break;
               }
               case BI_RLE4:
               {
+                /* 4 bit RLE */
                 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
                   "  Compression: BI_RLE4");
                 break;
               }
               case BI_RLE8:
               {
+                /* 8 bit RLE */
                 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
                   "  Compression: BI_RLE8");
                 break;
@@ -662,11 +780,13 @@ static Image *ReadBMPImage(const ImageIn
               default:
               {
                 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
-                  "  Compression: UNKNOWN (%lu)",bmp_info.compression);
+                  "  Compression: UNKNOWN (%u)",bmp_info.compression);
               }
             }
             (void) LogMagickEvent(CoderEvent,GetMagickModule(),
-              "  Number of colors: %lu",bmp_info.number_colors);
+              "  Number of colors: %u",bmp_info.number_colors);
+            (void) LogMagickEvent(CoderEvent,GetMagickModule(),
+              "  Important colors: %u",bmp_info.colors_important);
           }
 
         bmp_info.red_mask=ReadBlobLSBLong(image);
@@ -682,7 +802,7 @@ static Image *ReadBMPImage(const ImageIn
               Read color management information.
             */
             bmp_info.alpha_mask=ReadBlobLSBLong(image);
-            bmp_info.colorspace=(long) ReadBlobLSBLong(image);
+            bmp_info.colorspace=(magick_int32_t) ReadBlobLSBLong(image);
             /*
               Decode 2^30 fixed point formatted CIE primaries.
             */
@@ -704,18 +824,31 @@ static Image *ReadBMPImage(const ImageIn
               ReadBlobLSBLong(image)/0x3ffffff;
             bmp_info.blue_primary.z=(double)
               ReadBlobLSBLong(image)/0x3ffffff;
-            sum=bmp_info.red_primary.x+bmp_info.red_primary.x+
+
+            sum=bmp_info.red_primary.x+bmp_info.red_primary.y+
               bmp_info.red_primary.z;
-            image->chromaticity.red_primary.x/=sum;
-            image->chromaticity.red_primary.y/=sum;
-            sum=bmp_info.green_primary.x+bmp_info.green_primary.x+
+            sum=Max(MagickEpsilon,sum);
+            bmp_info.red_primary.x/=sum;
+            bmp_info.red_primary.y/=sum;
+            image->chromaticity.red_primary.x=bmp_info.red_primary.x;
+            image->chromaticity.red_primary.y=bmp_info.red_primary.y;
+
+            sum=bmp_info.green_primary.x+bmp_info.green_primary.y+
               bmp_info.green_primary.z;
-            image->chromaticity.green_primary.x/=sum;
-            image->chromaticity.green_primary.y/=sum;
-            sum=bmp_info.blue_primary.x+bmp_info.blue_primary.x+
+            sum=Max(MagickEpsilon,sum);
+            bmp_info.green_primary.x/=sum;
+            bmp_info.green_primary.y/=sum;
+            image->chromaticity.green_primary.x=bmp_info.green_primary.x;
+            image->chromaticity.green_primary.y=bmp_info.green_primary.y;
+
+            sum=bmp_info.blue_primary.x+bmp_info.blue_primary.y+
               bmp_info.blue_primary.z;
-            image->chromaticity.blue_primary.x/=sum;
-            image->chromaticity.blue_primary.y/=sum;
+            sum=Max(MagickEpsilon,sum);
+            bmp_info.blue_primary.x/=sum;
+            bmp_info.blue_primary.y/=sum;
+            image->chromaticity.blue_primary.x=bmp_info.blue_primary.x;
+            image->chromaticity.blue_primary.y=bmp_info.blue_primary.y;
+
             /*
               Decode 16^16 fixed point formatted gamma_scales.
             */
@@ -761,44 +894,53 @@ static Image *ReadBMPImage(const ImageIn
               }
             }
             profile_data=ReadBlobLSBLong(image);
-            profile_data=profile_data;
             profile_size=ReadBlobLSBLong(image);
-            profile_size=profile_size;
+            (void) LogMagickEvent(CoderEvent,GetMagickModule(),
+                                  "  Profile: size %lu data %lu",
+                                  profile_size,profile_data);
             (void) ReadBlobLSBLong(image);  /* Reserved byte */
           }
       }
 
-    if ((bmp_info.compression != BI_RGB) &&
-        ((magick_off_t) bmp_info.file_size != GetBlobSize(image)))
-      ThrowReaderException(CorruptImageError,LengthAndFilesizeDoNotMatch,
-        image);
+    /*
+      It seems that some BMPs claim a file size two bytes larger than
+      they actually are so allow some slop before warning about file
+      size.
+    */
+    if ((magick_off_t) bmp_info.file_size > file_size+2)
+      {
+        ThrowException(exception,CorruptImageError,
+                       ImproperImageHeader,image->filename);
+      }
+    if (logging && (magick_off_t) bmp_info.file_size < file_size)
+      (void) LogMagickEvent(CoderEvent,GetMagickModule(),
+                              "  Discarding all data beyond bmp_info.file_size");
     if (bmp_info.width <= 0)
-      ThrowReaderException(CorruptImageWarning,NegativeOrZeroImageSize,image);
-    if (bmp_info.height == 0)
-      ThrowReaderException(CorruptImageWarning,NegativeOrZeroImageSize,image);
+      ThrowBMPReaderException(CorruptImageError,NegativeOrZeroImageSize,image);
+    if ((bmp_info.height) == 0 || (bmp_info.height < -2147483647))
+      ThrowBMPReaderException(CorruptImageError,NegativeOrZeroImageSize,image);
     if ((bmp_info.height < 0) && (bmp_info.compression !=0))
-      ThrowReaderException(CorruptImageWarning,CompressionNotValid,image);
+      ThrowBMPReaderException(CorruptImageError,ImproperImageHeader,image);
     if (bmp_info.planes != 1)
-      ThrowReaderException(CorruptImageWarning,StaticPlanesValueNotEqualToOne,
+      ThrowBMPReaderException(CorruptImageError,StaticPlanesValueNotEqualToOne,
         image);
     if ((bmp_info.bits_per_pixel != 1) && (bmp_info.bits_per_pixel != 4) &&
         (bmp_info.bits_per_pixel != 8) && (bmp_info.bits_per_pixel != 16) &&
         (bmp_info.bits_per_pixel != 24) && (bmp_info.bits_per_pixel != 32))
-      ThrowReaderException(CorruptImageWarning,UnrecognizedBitsPerPixel,image);
-    if (bmp_info.number_colors > (1UL << bmp_info.bits_per_pixel))
-    {
-      if (bmp_info.bits_per_pixel<24)
-        ThrowReaderException(CorruptImageWarning,UnrecognizedNumberOfColors,image);
-      bmp_info.number_colors = 0;
-    }
+      ThrowBMPReaderException(CorruptImageError,UnrecognizedBitsPerPixel,image);
+    if (bmp_info.bits_per_pixel < 16)
+      {
+        if (bmp_info.number_colors > (1UL << bmp_info.bits_per_pixel))
+          ThrowBMPReaderException(CorruptImageError,ImproperImageHeader,image);
+      }
     if (bmp_info.compression > 3)
-      ThrowReaderException(CorruptImageWarning,UnrecognizedImageCompression,image);
+      ThrowBMPReaderException(CorruptImageError,UnrecognizedImageCompression,image);
     if ((bmp_info.compression == 1) && (bmp_info.bits_per_pixel != 8))
-      ThrowReaderException(CorruptImageWarning,UnrecognizedBitsPerPixel,image);
+      ThrowBMPReaderException(CorruptImageError,UnrecognizedBitsPerPixel,image);
     if ((bmp_info.compression == 2) && (bmp_info.bits_per_pixel != 4))
-      ThrowReaderException(CorruptImageWarning,UnrecognizedBitsPerPixel,image);
+      ThrowBMPReaderException(CorruptImageError,UnrecognizedBitsPerPixel,image);
     if ((bmp_info.compression == 3) && (bmp_info.bits_per_pixel < 16))
-      ThrowReaderException(CorruptImageWarning,UnrecognizedBitsPerPixel,image);
+      ThrowBMPReaderException(CorruptImageError,UnrecognizedBitsPerPixel,image);
     switch ((unsigned int) bmp_info.compression)
     {
       case BI_RGB:
@@ -807,29 +949,33 @@ static Image *ReadBMPImage(const ImageIn
       case BI_BITFIELDS:
         break;
       case BI_JPEG:
-        ThrowReaderException(CoderError,JPEGCompressionNotSupported,image)
+        ThrowBMPReaderException(CoderError,JPEGCompressionNotSupported,image)
       case BI_PNG:
-        ThrowReaderException(CoderError,PNGCompressionNotSupported,image)
+        ThrowBMPReaderException(CoderError,PNGCompressionNotSupported,image)
       default:
-        ThrowReaderException(CorruptImageError,UnrecognizedImageCompression,
+        ThrowBMPReaderException(CorruptImageError,UnrecognizedImageCompression,
           image)
     }
     image->columns=bmp_info.width;
     image->rows=AbsoluteValue(bmp_info.height);
     image->depth=8;
-    image->matte=bmp_info.alpha_mask != 0;
-    if ((bmp_info.number_colors != 0) || (bmp_info.bits_per_pixel < 16))
+    /*
+      Image has alpha channel if alpha mask is specified, or is
+      uncompressed and 32-bits per pixel
+    */
+    image->matte=((bmp_info.alpha_mask != 0)
+                  || ((bmp_info.compression == BI_RGB)
+                      && (bmp_info.bits_per_pixel == 32)));
+    if (bmp_info.bits_per_pixel < 16)
       {
-        image->storage_class=PseudoClass;
-        image->colors=bmp_info.number_colors;
-        if (image->colors == 0)
+        if (bmp_info.number_colors == 0)
           image->colors=1L << bmp_info.bits_per_pixel;
+        else
+          image->colors=bmp_info.number_colors;
+        image->storage_class=PseudoClass;
       }
     if (image->storage_class == PseudoClass)
       {
-        unsigned char
-          *bmp_colormap;
-
         unsigned int
           packet_size;
 
@@ -840,19 +986,23 @@ static Image *ReadBMPImage(const ImageIn
           (void) LogMagickEvent(CoderEvent,GetMagickModule(),
             "  Reading colormap of %u colors",image->colors);
         if (!AllocateImageColormap(image,image->colors))
-          ThrowReaderException(ResourceLimitError,MemoryAllocationFailed,
+          ThrowBMPReaderException(ResourceLimitError,MemoryAllocationFailed,
             image);
-        bmp_colormap=MagickAllocateMemory(unsigned char *,4*image->colors);
+        bmp_colormap=MagickAllocateArray(unsigned char *,4,image->colors);
         if (bmp_colormap == (unsigned char *) NULL)
-          ThrowReaderException(ResourceLimitError,MemoryAllocationFailed,
+          ThrowBMPReaderException(ResourceLimitError,MemoryAllocationFailed,
             image);
         if ((bmp_info.size == 12) || (bmp_info.size == 64))
           packet_size=3;
         else
           packet_size=4;
-        if (SeekBlob(image,start_position+14+bmp_info.size,SEEK_SET) == -1)
-	  ThrowReaderException(CorruptImageError,ImproperImageHeader,image)
-        (void) ReadBlob(image,packet_size*image->colors,(char *) bmp_colormap);
+        offset=start_position+14+bmp_info.size;
+        if ((offset < start_position) ||
+            (SeekBlob(image,offset,SEEK_SET) != (magick_off_t) offset))
+          ThrowBMPReaderException(CorruptImageError,ImproperImageHeader,image);
+        if (ReadBlob(image,packet_size*image->colors,(char *) bmp_colormap)
+            != (size_t) packet_size*image->colors)
+          ThrowBMPReaderException(CorruptImageError,UnexpectedEndOfFile,image);
         p=bmp_colormap;
         for (i=0; i < (long) image->colors; i++)
         {
@@ -864,40 +1014,75 @@ static Image *ReadBMPImage(const ImageIn
         }
         MagickFreeMemory(bmp_colormap);
       }
-    if (image_info->ping && (image_info->subrange != 0))
-      if (image->scene >= (image_info->subimage+image_info->subrange-1))
+
+    if (image_info->ping)
+      if ((image_info->subrange == 0) ||
+          ((image_info->subrange != 0) &&
+           (image->scene >= (image_info->subimage+image_info->subrange-1))))
         break;
+
     /*
       Read image data.
     */
-    if (SeekBlob(image,start_position+bmp_info.offset_bits,SEEK_SET) == -1)
-      ThrowReaderException(CorruptImageError,ImproperImageHeader,image)
+    offset=start_position+bmp_info.offset_bits;
+    if ((offset < start_position) ||
+        (SeekBlob(image,offset,SEEK_SET) != (magick_off_t) offset))
+      ThrowBMPReaderException(CorruptImageError,ImproperImageHeader,image);
     if (bmp_info.compression == BI_RLE4)
       bmp_info.bits_per_pixel<<=1;
     bytes_per_line=4*((image->columns*bmp_info.bits_per_pixel+31)/32);
-    length=bytes_per_line*image->rows;
-    if (length > GetBlobSize(image))
-      ThrowReaderException(CorruptImageError,InsufficientImageDataInFile,image);
-    pixels=MagickAllocateMemory(unsigned char *,
-      Max(bytes_per_line,image->columns+1)*(image->rows+1));
+
+    length=MagickArraySize(bytes_per_line,image->rows);
+    if (length/image->rows != bytes_per_line)
+      ThrowBMPReaderException(ResourceLimitError,MemoryAllocationFailed,image);
+
+    /*
+      Check that file data is reasonable given claims by file header.
+      We do this before allocating raster memory to avoid DOS.
+    */
+    if ((bmp_info.compression == BI_RGB) ||
+        (bmp_info.compression == BI_BITFIELDS))
+      {
+        /*
+          Not compressed.
+        */
+        file_remaining=file_size-TellBlob(image);
+        if (file_remaining < (magick_off_t) length)
+          ThrowBMPReaderException(CorruptImageError,InsufficientImageDataInFile,
+                                  image);
+      }
+    else if ((bmp_info.compression == BI_RLE4) ||
+             (bmp_info.compression == BI_RLE8))
+      {
+        /* RLE Compressed.  Assume a maximum compression ratio. */
+        file_remaining=file_size-TellBlob(image);
+        if ((file_remaining <= 0) || (((double) length/file_remaining) > 254.0))
+          ThrowBMPReaderException(CorruptImageError,InsufficientImageDataInFile,
+                                  image);
+      }
+
+    pixels_size=MagickArraySize(Max(bytes_per_line,image->columns+1),
+                                image->rows);
+    pixels=MagickAllocateMemory(unsigned char *, pixels_size);
     if (pixels == (unsigned char *) NULL)
-      ThrowReaderException(ResourceLimitError,MemoryAllocationFailed,image);
+      ThrowBMPReaderException(ResourceLimitError,MemoryAllocationFailed,image);
     if ((bmp_info.compression == BI_RGB) ||
         (bmp_info.compression == BI_BITFIELDS))
       {
-        if (logging)
-          (void) LogMagickEvent(CoderEvent,GetMagickModule(),
-            "  Reading pixels (%ld bytes)",(long) length);
-        (void) ReadBlob(image,length,(char *) pixels);
+        if (ReadBlob(image,length,(char *) pixels) != (size_t) length)
+          ThrowBMPReaderException(CorruptImageError,UnexpectedEndOfFile,image);
       }
     else
       {
         /*
           Convert run-length encoded raster pixels.
+
+          DecodeImage() normally decompresses to rows*columns bytes of data.
         */
-        status=DecodeImage(image,bmp_info.compression,pixels);
-        if (status == False)
-          ThrowReaderException(CorruptImageError,UnableToRunlengthDecodeImage,
+        status=DecodeImage(image,bmp_info.compression,pixels,
+                           image->rows*image->columns);
+        if (status == MagickFail)
+          ThrowBMPReaderException(CorruptImageError,UnableToRunlengthDecodeImage,
             image);
       }
     /*
@@ -911,23 +1096,23 @@ static Image *ReadBMPImage(const ImageIn
     */
     if (bmp_info.compression == BI_RGB)
       {
-        bmp_info.alpha_mask=0;
-        bmp_info.red_mask=0x00ff0000L;
-        bmp_info.green_mask=0x0000ff00L;
-        bmp_info.blue_mask=0x000000ffL;
+        bmp_info.alpha_mask=(image->matte ? 0xff000000U : 0U);
+        bmp_info.red_mask=0x00ff0000U;
+        bmp_info.green_mask=0x0000ff00U;
+        bmp_info.blue_mask=0x000000ffU;
         if (bmp_info.bits_per_pixel == 16)
           {
             /*
               RGB555.
             */
-            bmp_info.red_mask=0x00007c00L;
-            bmp_info.green_mask=0x000003e0L;
-            bmp_info.blue_mask=0x0000001fL;
+            bmp_info.red_mask=0x00007c00U;
+            bmp_info.green_mask=0x000003e0U;
+            bmp_info.blue_mask=0x0000001fU;
           }
       }
     if ((bmp_info.bits_per_pixel == 16) || (bmp_info.bits_per_pixel == 32))
       {
-        register unsigned long
+        register magick_uint32_t
           sample;
 
         /*
@@ -935,32 +1120,32 @@ static Image *ReadBMPImage(const ImageIn
         */
         (void) memset(&shift,0,sizeof(PixelPacket));
         (void) memset(&quantum_bits,0,sizeof(PixelPacket));
-        if (bmp_info.red_mask != 0)
-          while ((shift.red < 32U) && (((bmp_info.red_mask << shift.red) & 0x80000000UL) == 0))
+        if (bmp_info.red_mask != 0U)
+          while ((shift.red < 32U) && (((bmp_info.red_mask << shift.red) & 0x80000000U) == 0))
             shift.red++;
         if (bmp_info.green_mask != 0)
-          while ((shift.green < 32U) && (((bmp_info.green_mask << shift.green) & 0x80000000UL) == 0))
+          while ((shift.green < 32U) && (((bmp_info.green_mask << shift.green) & 0x80000000U) == 0))
             shift.green++;
         if (bmp_info.blue_mask != 0)
-          while ((shift.blue < 32U) && (((bmp_info.blue_mask << shift.blue) & 0x80000000UL) == 0))
+          while ((shift.blue < 32U) && (((bmp_info.blue_mask << shift.blue) & 0x80000000U) == 0))
             shift.blue++;
         if (bmp_info.alpha_mask != 0)
-          while ((shift.opacity < 32U) && (((bmp_info.alpha_mask << shift.opacity) & 0x80000000UL) == 0))
+          while ((shift.opacity < 32U) && (((bmp_info.alpha_mask << shift.opacity) & 0x80000000U) == 0))
             shift.opacity++;
         sample=shift.red;
-        while ((sample < 32U) && (((bmp_info.red_mask << sample) & 0x80000000UL) != 0))
+        while ((sample < 32U) && (((bmp_info.red_mask << sample) & 0x80000000U) != 0))
           sample++;
         quantum_bits.red=(Quantum) (sample-shift.red);
         sample=shift.green;
-        while ((sample < 32U) && (((bmp_info.green_mask << sample) & 0x80000000UL) != 0))
+        while ((sample < 32U) && (((bmp_info.green_mask << sample) & 0x80000000U) != 0))
           sample++;
         quantum_bits.green=(Quantum) (sample-shift.green);
         sample=shift.blue;
-        while ((sample < 32U) && (((bmp_info.blue_mask << sample) & 0x80000000UL) != 0))
+        while ((sample < 32U) && (((bmp_info.blue_mask << sample) & 0x80000000U) != 0))
           sample++;
         quantum_bits.blue=(Quantum) (sample-shift.blue);
         sample=shift.opacity;
-        while ((sample < 32U) && (((bmp_info.alpha_mask << sample) & 0x80000000UL) != 0))
+        while ((sample < 32U) && (((bmp_info.alpha_mask << sample) & 0x80000000U) != 0))
           sample++;
         quantum_bits.opacity=(Quantum) (sample-shift.opacity);
       }
@@ -1052,7 +1237,7 @@ static Image *ReadBMPImage(const ImageIn
       }
       case 16:
       {
-        unsigned long
+        magick_uint32_t
           pixel;
 
         /*
@@ -1060,7 +1245,7 @@ static Image *ReadBMPImage(const ImageIn
         */
         if (bmp_info.compression != BI_RGB &&
             bmp_info.compression != BI_BITFIELDS)
-          ThrowReaderException(CorruptImageError,UnrecognizedImageCompression,image)
+          ThrowBMPReaderException(CorruptImageError,UnrecognizedImageCompression,image)
         bytes_per_line=2*(image->columns+image->columns%2);
         image->storage_class=DirectClass;
         for (y=(long) image->rows-1; y >= 0; y--)
@@ -1087,7 +1272,7 @@ static Image *ReadBMPImage(const ImageIn
                 opacity=((pixel & bmp_info.alpha_mask) << shift.opacity) >> 16;
                 if (quantum_bits.opacity == 8)
                   opacity|=(opacity >> 8);
-                  q->opacity=ScaleShortToQuantum(opacity);
+                q->opacity=MaxRGB-ScaleShortToQuantum(opacity);
               }
             q->red=ScaleShortToQuantum(red);
             q->green=ScaleShortToQuantum(green);
@@ -1146,11 +1331,11 @@ static Image *ReadBMPImage(const ImageIn
         */
         if ((bmp_info.compression != BI_RGB) &&
             (bmp_info.compression != BI_BITFIELDS))
-          ThrowReaderException(CorruptImageError,UnrecognizedImageCompression,image)
+          ThrowBMPReaderException(CorruptImageError,UnrecognizedImageCompression,image)
         bytes_per_line=4*(image->columns);
         for (y=(long) image->rows-1; y >= 0; y--)
         {
-          unsigned long
+          magick_uint32_t
             pixel;
 
           p=pixels+(image->rows-y-1)*bytes_per_line;
@@ -1159,10 +1344,10 @@ static Image *ReadBMPImage(const ImageIn
             break;
           for (x=0; x < (long) image->columns; x++)
           {
-            pixel=(*p++);
-            pixel|=(*p++ << 8);
-            pixel|=(*p++ << 16);
-            pixel|=(*p++ << 24);
+            pixel =((magick_uint32_t) *p++);
+            pixel|=((magick_uint32_t) *p++ << 8);
+            pixel|=((magick_uint32_t) *p++ << 16);
+            pixel|=((magick_uint32_t) *p++ << 24);
             red=((pixel & bmp_info.red_mask) << shift.red) >> 16;
             if (quantum_bits.red == 8)
               red|=(red >> 8);
@@ -1177,7 +1362,7 @@ static Image *ReadBMPImage(const ImageIn
                 opacity=((pixel & bmp_info.alpha_mask) << shift.opacity) >> 16;
                 if (quantum_bits.opacity == 8)
                   opacity|=(opacity >> 8);
-                  q->opacity=ScaleShortToQuantum(opacity);
+                q->opacity=MaxRGB-ScaleShortToQuantum(opacity);
               }
             q->red=ScaleShortToQuantum(red);
             q->green=ScaleShortToQuantum(green);
@@ -1198,7 +1383,7 @@ static Image *ReadBMPImage(const ImageIn
         break;
       }
       default:
-        ThrowReaderException(CorruptImageError,ImproperImageHeader,image)
+        ThrowBMPReaderException(CorruptImageError,ImproperImageHeader,image)
     }
     MagickFreeMemory(pixels);
     if (EOFBlob(image))
@@ -1221,8 +1406,9 @@ static Image *ReadBMPImage(const ImageIn
             DestroyImageList(image);
             return((Image *) NULL);
           }
-        ReplaceImageInList(&image, flipped_image);
-        image=flipped_image;
+        DestroyBlob(flipped_image);
+        flipped_image->blob=ReferenceBlob(image->blob);
+        ReplaceImageInList(&image,flipped_image);
       }
     /*
       Proceed to next image.
@@ -1231,10 +1417,16 @@ static Image *ReadBMPImage(const ImageIn
       if (image->scene >= (image_info->subimage+image_info->subrange-1))
         break;
     *magick='\0';
-    if (bmp_info.ba_offset != 0)
-      if (SeekBlob(image,bmp_info.ba_offset,SEEK_SET) == -1)
-        ThrowReaderException(CorruptImageError,ImproperImageHeader,image)
-    (void) ReadBlob(image,2,(char *) magick);
+    file_remaining=file_size-TellBlob(image);
+    if (file_remaining == 0)
+      break;
+    offset=bmp_info.ba_offset;
+    if (offset > 0)
+      if ((offset < TellBlob(image)) ||
+          (SeekBlob(image,offset,SEEK_SET) != (magick_off_t) offset))
+      ThrowBMPReaderException(CorruptImageError,ImproperImageHeader,image);
+    if (ReadBlob(image,2,(char *) magick) != (size_t) 2)
+      break;
     if (IsBMP(magick,2))
       {
         /*
@@ -1409,12 +1601,15 @@ static unsigned int WriteBMPImage(const
     scene,
     type;
 
-  const unsigned char
-    *color_profile=0;
+/*   const unsigned char */
+/*     *color_profile=0; */
 
   size_t
     color_profile_length=0;
 
+  size_t
+    image_list_length;
+
   /*
     Open output image file.
   */
@@ -1422,6 +1617,7 @@ static unsigned int WriteBMPImage(const
   assert(image_info->signature == MagickSignature);
   assert(image != (Image *) NULL);
   assert(image->signature == MagickSignature);
+  image_list_length=GetImageListLength(image);
   logging=LogMagickEvent(CoderEvent,GetMagickModule(),"enter");
   status=OpenBlob(image_info,image,WriteBinaryBlobMode,&image->exception);
   if (status == False)
@@ -1436,8 +1632,9 @@ static unsigned int WriteBMPImage(const
 
   /*
     Retrieve color profile from Image (if any)
+    FIXME: is color profile support writing not properly implemented?
   */
-  color_profile=GetImageProfile(image,"ICM",&color_profile_length);
+  /* color_profile= */ (void) GetImageProfile(image,"ICM",&color_profile_length);
 
   do
   {
@@ -1449,7 +1646,7 @@ static unsigned int WriteBMPImage(const
     bmp_info.file_size=14+12;
     if (type > 2)
       bmp_info.file_size+=28;
-    bmp_info.offset_bits=bmp_info.file_size;
+    bmp_info.offset_bits=(magick_uint32_t) bmp_info.file_size;
     bmp_info.compression=BI_RGB;
     if ((image->storage_class != DirectClass) && (image->colors > 256))
       (void) SetImageType(image,TrueColorType);
@@ -1473,12 +1670,12 @@ static unsigned int WriteBMPImage(const
             (void) SetImageType(image,TrueColorType);
           else
             {
-              bmp_info.file_size+=3*(1 << bmp_info.bits_per_pixel);
-              bmp_info.offset_bits+=3*(1 << bmp_info.bits_per_pixel);
+              bmp_info.file_size+=3U*(1U << bmp_info.bits_per_pixel);
+              bmp_info.offset_bits+=3U*(1U << bmp_info.bits_per_pixel);
               if (type > 2)
                 {
-                  bmp_info.file_size+=(1 << bmp_info.bits_per_pixel);
-                  bmp_info.offset_bits+=(1 << bmp_info.bits_per_pixel);
+                  bmp_info.file_size+=(size_t) (1U << bmp_info.bits_per_pixel);
+                  bmp_info.offset_bits+=(1U << bmp_info.bits_per_pixel);
                 }
             }
       }
@@ -1520,13 +1717,28 @@ static unsigned int WriteBMPImage(const
           bmp_info.file_size+=extra_size;
           bmp_info.offset_bits+=extra_size;
         }
-    if ((image->columns != (signed int) image->columns) ||
-        (image->rows != (signed int) image->rows))
-      ThrowWriterException(ImageError,WidthOrHeightExceedsLimit,image);
-    bmp_info.width=(long) image->columns;
-    bmp_info.height=(long) image->rows;
+    /*
+      Verify and enforce that image dimensions do not exceed limit
+      imposed by file format.
+    */
+    if (type == 2)
+      {
+        bmp_info.width=(magick_int16_t) image->columns;
+        bmp_info.height=(magick_int16_t) image->rows;
+      }
+    else
+      {
+        bmp_info.width=(magick_int32_t) image->columns;
+        bmp_info.height=(magick_int32_t) image->rows;
+      }
+    if (((unsigned long) bmp_info.width != image->columns) ||
+        ((unsigned long) bmp_info.height != image->rows))
+      {
+        ThrowWriterException(CoderError,ImageColumnOrRowSizeIsNotSupported,image);
+      }
+
     bmp_info.planes=1;
-    bmp_info.image_size=(unsigned long) bytes_per_line*image->rows;
+    bmp_info.image_size=MagickArraySize(bytes_per_line,image->rows);
     bmp_info.file_size+=bmp_info.image_size;
     bmp_info.x_pixels=75*39;
     bmp_info.y_pixels=75*39;
@@ -1653,7 +1865,7 @@ static unsigned int WriteBMPImage(const
             *q++=ScaleQuantumToChar(p->green);
             *q++=ScaleQuantumToChar(p->red);
             if (bmp_info.bits_per_pixel == 32)
-              *q++=ScaleQuantumToChar(p->opacity);
+              *q++=ScaleQuantumToChar(MaxRGB-p->opacity);
             p++;
           }
           if (bmp_info.bits_per_pixel == 24)
@@ -1688,7 +1900,7 @@ static unsigned int WriteBMPImage(const
                 image)
             }
           bmp_info.file_size-=bmp_info.image_size;
-          bmp_info.image_size=EncodeImage(image,bytes_per_line,pixels,
+          bmp_info.image_size=(unsigned long) EncodeImage(image,bytes_per_line,pixels,
               bmp_data);
           bmp_info.file_size+=bmp_info.image_size;
           MagickFreeMemory(pixels);
@@ -1718,7 +1930,7 @@ static unsigned int WriteBMPImage(const
             "   Matte=False");
         (void) LogMagickEvent(CoderEvent,GetMagickModule(),
           "   BMP bits_per_pixel=%d",bmp_info.bits_per_pixel);
-        switch ((int) bmp_info.compression)
+        switch (bmp_info.compression)
         {
            case BI_RGB:
            {
@@ -1741,7 +1953,7 @@ static unsigned int WriteBMPImage(const
            default:
            {
              (void) LogMagickEvent(CoderEvent,GetMagickModule(),
-               "   Compression=UNKNOWN (%lu)",bmp_info.compression);
+               "   Compression=UNKNOWN (%u)",bmp_info.compression);
              break;
            }
         }
@@ -1750,10 +1962,10 @@ static unsigned int WriteBMPImage(const
             "   Number_colors=unspecified");
         else
           (void) LogMagickEvent(CoderEvent,GetMagickModule(),
-            "   Number_colors=%lu",bmp_info.number_colors);
+            "   Number_colors=%u",bmp_info.number_colors);
       }
     (void) WriteBlob(image,2,"BM");
-    (void) WriteBlobLSBLong(image,bmp_info.file_size);
+    (void) WriteBlobLSBLong(image,(magick_uint32_t) bmp_info.file_size);
     (void) WriteBlobLSBLong(image,bmp_info.ba_offset);  /* always 0 */
     (void) WriteBlobLSBLong(image,bmp_info.offset_bits);
     if (type == 2)
@@ -1778,7 +1990,7 @@ static unsigned int WriteBMPImage(const
         (void) WriteBlobLSBShort(image,bmp_info.planes);
         (void) WriteBlobLSBShort(image,bmp_info.bits_per_pixel);
         (void) WriteBlobLSBLong(image,bmp_info.compression);
-        (void) WriteBlobLSBLong(image,bmp_info.image_size);
+        (void) WriteBlobLSBLong(image,(magick_uint32_t) bmp_info.image_size);
         (void) WriteBlobLSBLong(image,bmp_info.x_pixels);
         (void) WriteBlobLSBLong(image,bmp_info.y_pixels);
         (void) WriteBlobLSBLong(image,bmp_info.number_colors);
@@ -1870,8 +2082,8 @@ static unsigned int WriteBMPImage(const
         if (logging)
           (void) LogMagickEvent(CoderEvent,GetMagickModule(),
             "  Colormap: %u entries",image->colors);
-        bmp_colormap=MagickAllocateMemory(unsigned char *,
-          (size_t) (4*(1L << bmp_info.bits_per_pixel)));
+        bmp_colormap=MagickAllocateArray(unsigned char *,4,
+          (size_t) (1L << bmp_info.bits_per_pixel));
         if (bmp_colormap == (unsigned char *) NULL)
           {
             MagickFreeMemory(pixels);
