LCOV - code coverage report
Current view: top level - frmts/bmp - bmpdataset.cpp (source / functions) Hit Total Coverage
Test: gdal_filtered.info Lines: 448 671 66.8 %
Date: 2024-05-04 12:52:34 Functions: 22 24 91.7 %

          Line data    Source code
       1             : /******************************************************************************
       2             :  *
       3             :  * Project:  Microsoft Windows Bitmap
       4             :  * Purpose:  Read/write MS Windows Device Independent Bitmap (DIB) files
       5             :  *           and OS/2 Presentation Manager bitmaps v. 1.x and v. 2.x
       6             :  * Author:   Andrey Kiselev, dron@remotesensing.org
       7             :  *
       8             :  ******************************************************************************
       9             :  * Copyright (c) 2002, Andrey Kiselev <dron@remotesensing.org>
      10             :  * Copyright (c) 2007-2010, Even Rouault <even dot rouault at spatialys.com>
      11             :  *
      12             :  * Permission is hereby granted, free of charge, to any person obtaining a
      13             :  * copy of this software and associated documentation files (the "Software"),
      14             :  * to deal in the Software without restriction, including without limitation
      15             :  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
      16             :  * and/or sell copies of the Software, and to permit persons to whom the
      17             :  * Software is furnished to do so, subject to the following conditions:
      18             :  *
      19             :  * The above copyright notice and this permission notice shall be included
      20             :  * in all copies or substantial portions of the Software.
      21             :  *
      22             :  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
      23             :  * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
      24             :  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
      25             :  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
      26             :  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
      27             :  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
      28             :  * DEALINGS IN THE SOFTWARE.
      29             :  ****************************************************************************/
      30             : 
      31             : #include "cpl_string.h"
      32             : #include "gdal_frmts.h"
      33             : #include "gdal_pam.h"
      34             : 
      35             : #include <limits>
      36             : 
      37             : // Enable if you want to see lots of BMP debugging output.
      38             : // #define BMP_DEBUG
      39             : 
      40             : enum BMPType
      41             : {
      42             :     BMPT_WIN4,  // BMP used in Windows 3.0/NT 3.51/95
      43             :     BMPT_WIN5,  // BMP used in Windows NT 4.0/98/Me/2000/XP
      44             :     BMPT_OS21,  // BMP used in OS/2 PM 1.x
      45             :     BMPT_OS22   // BMP used in OS/2 PM 2.x
      46             : };
      47             : 
      48             : // Bitmap file consists of a BMPFileHeader structure followed by a
      49             : // BMPInfoHeader structure. An array of BMPColorEntry structures (also called
      50             : // a colour table) follows the bitmap information header structure. The colour
      51             : // table is followed by a second array of indexes into the colour table (the
      52             : // actual bitmap data). Data may be compressed, for 4-bpp and 8-bpp used RLE
      53             : // compression.
      54             : //
      55             : // +---------------------+
      56             : // | BMPFileHeader       |
      57             : // +---------------------+
      58             : // | BMPInfoHeader       |
      59             : // +---------------------+
      60             : // | BMPColorEntry array |
      61             : // +---------------------+
      62             : // | Colour-index array  |
      63             : // +---------------------+
      64             : //
      65             : // All numbers stored in Intel order with least significant byte first.
      66             : 
      67             : enum BMPComprMethod
      68             : {
      69             :     BMPC_RGB = 0L,        // Uncompressed
      70             :     BMPC_RLE8 = 1L,       // RLE for 8 bpp images
      71             :     BMPC_RLE4 = 2L,       // RLE for 4 bpp images
      72             :     BMPC_BITFIELDS = 3L,  // Bitmap is not compressed and the colour table
      73             :                           // consists of three DWORD color masks that specify
      74             :                           // the red, green, and blue components of each pixel.
      75             :     // This is valid when used with 16- and 32-bpp bitmaps.
      76             :     BMPC_JPEG = 4L,  // Indicates that the image is a JPEG image.
      77             :     BMPC_PNG = 5L    // Indicates that the image is a PNG image.
      78             : };
      79             : 
      80             : enum BMPLCSType  // Type of logical color space.
      81             : {
      82             :     BMPLT_CALIBRATED_RGB = 0,  // This value indicates that endpoints and gamma
      83             :                                // values are given in the appropriate fields.
      84             :     BMPLT_DEVICE_RGB = 1,
      85             :     BMPLT_DEVICE_CMYK = 2
      86             : };
      87             : 
      88             : typedef struct
      89             : {
      90             :     // cppcheck-suppress unusedStructMember
      91             :     GInt32 iCIEX;
      92             :     // cppcheck-suppress unusedStructMember
      93             :     GInt32 iCIEY;
      94             :     // cppcheck-suppress unusedStructMember
      95             :     GInt32 iCIEZ;
      96             : } BMPCIEXYZ;
      97             : 
      98             : typedef struct  // This structure contains the x, y, and z
      99             : {               // coordinates of the three colors that correspond
     100             :     // cppcheck-suppress unusedStructMember
     101             :     BMPCIEXYZ iCIERed;  // to the red, green, and blue endpoints for
     102             :     // cppcheck-suppress unusedStructMember
     103             :     BMPCIEXYZ iCIEGreen;  // a specified logical color space.
     104             :     // cppcheck-suppress unusedStructMember
     105             :     BMPCIEXYZ iCIEBlue;
     106             : } BMPCIEXYZTriple;
     107             : 
     108             : typedef struct
     109             : {
     110             :     GByte bType[2];      // Signature "BM"
     111             :     GUInt32 iSize;       // Size in bytes of the bitmap file. Should always
     112             :                          // be ignored while reading because of error
     113             :                          // in Windows 3.0 SDK's description of this field
     114             :     GUInt16 iReserved1;  // Reserved, set as 0
     115             :     GUInt16 iReserved2;  // Reserved, set as 0
     116             :     GUInt32 iOffBits;    // Offset of the image from file start in bytes
     117             : } BMPFileHeader;
     118             : 
     119             : // File header size in bytes:
     120             : constexpr int BFH_SIZE = 14;
     121             : 
     122             : // Size of sInfoHeader.iSize in bytes
     123             : constexpr int SIZE_OF_INFOHEADER_SIZE = 4;
     124             : 
     125             : typedef struct
     126             : {
     127             :     GUInt32 iSize;      // Size of BMPInfoHeader structure in bytes.
     128             :                         // Should be used to determine start of the
     129             :                         // colour table
     130             :     GInt32 iWidth;      // Image width
     131             :     GInt32 iHeight;     // Image height. If positive, image has bottom left
     132             :                         // origin, if negative --- top left.
     133             :     GUInt16 iPlanes;    // Number of image planes (must be set to 1)
     134             :     GUInt16 iBitCount;  // Number of bits per pixel (1, 4, 8, 16, 24 or 32).
     135             :                         // If 0 then the number of bits per pixel is
     136             :                         // specified or is implied by the JPEG or PNG format.
     137             :     BMPComprMethod iCompression;  // Compression method
     138             :     GUInt32 iSizeImage;     // Size of uncompressed image in bytes. May be 0
     139             :                             // for BMPC_RGB bitmaps. If iCompression is BI_JPEG
     140             :                             // or BI_PNG, iSizeImage indicates the size
     141             :                             // of the JPEG or PNG image buffer.
     142             :     GInt32 iXPelsPerMeter;  // X resolution, pixels per meter (0 if not used)
     143             :     GInt32 iYPelsPerMeter;  // Y resolution, pixels per meter (0 if not used)
     144             :     GUInt32 iClrUsed;       // Size of colour table. If 0, iBitCount should
     145             :                             // be used to calculate this value (1<<iBitCount)
     146             :     GUInt32 iClrImportant;  // Number of important colours. If 0, all
     147             :                             // colours are required
     148             : 
     149             :     // Fields above should be used for bitmaps, compatible with Windows NT 3.51
     150             :     // and earlier. Windows 98/Me, Windows 2000/XP introduces additional fields:
     151             : 
     152             :     GUInt32 iRedMask;    // Colour mask that specifies the red component
     153             :                          // of each pixel, valid only if iCompression
     154             :                          // is set to BI_BITFIELDS.
     155             :     GUInt32 iGreenMask;  // The same for green component
     156             :     GUInt32 iBlueMask;   // The same for blue component
     157             :     // cppcheck-suppress unusedStructMember
     158             :     GUInt32 iAlphaMask;  // Colour mask that specifies the alpha
     159             :                          // component of each pixel.
     160             :     // cppcheck-suppress unusedStructMember
     161             :     BMPLCSType iCSType;  // Colour space of the DIB.
     162             :     // cppcheck-suppress unusedStructMember
     163             :     BMPCIEXYZTriple sEndpoints;  // This member is ignored unless the iCSType
     164             :                                  // member specifies BMPLT_CALIBRATED_RGB.
     165             :     // cppcheck-suppress unusedStructMember
     166             :     GUInt32 iGammaRed;  // Toned response curve for red. This member
     167             :                         // is ignored unless color values are calibrated
     168             :                         // RGB values and iCSType is set to
     169             :                         // BMPLT_CALIBRATED_RGB. Specified in 16^16 format.
     170             :     // cppcheck-suppress unusedStructMember
     171             :     GUInt32 iGammaGreen;  // Toned response curve for green.
     172             :     // cppcheck-suppress unusedStructMember
     173             :     GUInt32 iGammaBlue;  // Toned response curve for blue.
     174             : } BMPInfoHeader;
     175             : 
     176             : // Info header size in bytes:
     177             : const unsigned int BIH_WIN4SIZE = 40;  // for BMPT_WIN4
     178             : #if 0                                  /* Unused */
     179             : const unsigned int  BIH_WIN5SIZE = 57; // for BMPT_WIN5
     180             : #endif
     181             : const unsigned int BIH_OS21SIZE = 12;  // for BMPT_OS21
     182             : const unsigned int BIH_OS22SIZE = 64;  // for BMPT_OS22
     183             : 
     184             : // We will use plain byte array instead of this structure, but declaration
     185             : // provided for reference
     186             : typedef struct
     187             : {
     188             :     // cppcheck-suppress unusedStructMember
     189             :     GByte bBlue;
     190             :     // cppcheck-suppress unusedStructMember
     191             :     GByte bGreen;
     192             :     // cppcheck-suppress unusedStructMember
     193             :     GByte bRed;
     194             :     // cppcheck-suppress unusedStructMember
     195             :     GByte bReserved;  // Must be 0
     196             : } BMPColorEntry;
     197             : 
     198             : /*****************************************************************/
     199             : 
     200           0 : static int countonbits(GUInt32 dw)
     201             : {
     202           0 :     int r = 0;
     203           0 :     for (int x = 0; x < 32; x++)
     204             :     {
     205           0 :         if ((dw & (1U << x)) != 0)
     206           0 :             r++;
     207             :     }
     208           0 :     return r;
     209             : }
     210             : 
     211           0 : static int findfirstonbit(GUInt32 n)
     212             : {
     213           0 :     for (int x = 0; x < 32; x++)
     214             :     {
     215           0 :         if ((n & (1U << x)) != 0)
     216           0 :             return x;
     217             :     }
     218           0 :     return -1;
     219             : }
     220             : 
     221             : /************************************************************************/
     222             : /* ==================================================================== */
     223             : /*                              BMPDataset                              */
     224             : /* ==================================================================== */
     225             : /************************************************************************/
     226             : 
     227             : class BMPDataset final : public GDALPamDataset
     228             : {
     229             :     friend class BMPRasterBand;
     230             :     friend class BMPComprRasterBand;
     231             : 
     232             :     BMPFileHeader sFileHeader;
     233             :     BMPInfoHeader sInfoHeader;
     234             :     int nColorElems;
     235             :     GByte *pabyColorTable;
     236             :     GDALColorTable *poColorTable;
     237             :     double adfGeoTransform[6];
     238             :     int bGeoTransformValid;
     239             :     bool m_bNewFile = false;
     240             :     vsi_l_offset m_nFileSize = 0;
     241             : 
     242             :     char *pszFilename;
     243             :     VSILFILE *fp;
     244             : 
     245             :   protected:
     246             :     CPLErr IRasterIO(GDALRWFlag, int, int, int, int, void *, int, int,
     247             :                      GDALDataType, int, int *, GSpacing nPixelSpace,
     248             :                      GSpacing nLineSpace, GSpacing nBandSpace,
     249             :                      GDALRasterIOExtraArg *psExtraArg) override;
     250             : 
     251             :   public:
     252             :     BMPDataset();
     253             :     ~BMPDataset() override;
     254             : 
     255             :     static int Identify(GDALOpenInfo *);
     256             :     static GDALDataset *Open(GDALOpenInfo *);
     257             :     static GDALDataset *Create(const char *pszFilename, int nXSize, int nYSize,
     258             :                                int nBandsIn, GDALDataType eType,
     259             :                                char **papszParamList);
     260             : 
     261             :     CPLErr GetGeoTransform(double *padfTransform) override;
     262             :     CPLErr SetGeoTransform(double *) override;
     263             : };
     264             : 
     265             : /************************************************************************/
     266             : /* ==================================================================== */
     267             : /*                            BMPRasterBand                             */
     268             : /* ==================================================================== */
     269             : /************************************************************************/
     270             : 
     271             : class BMPRasterBand CPL_NON_FINAL : public GDALPamRasterBand
     272             : {
     273             :     friend class BMPDataset;
     274             : 
     275             :   protected:
     276             :     GUInt32 nScanSize;
     277             :     unsigned int iBytesPerPixel;
     278             :     GByte *pabyScan;
     279             : 
     280             :   public:
     281             :     BMPRasterBand(BMPDataset *, int);
     282             :     ~BMPRasterBand() override;
     283             : 
     284             :     CPLErr IReadBlock(int, int, void *) override;
     285             :     CPLErr IWriteBlock(int, int, void *) override;
     286             :     GDALColorInterp GetColorInterpretation() override;
     287             :     GDALColorTable *GetColorTable() override;
     288             :     CPLErr SetColorTable(GDALColorTable *) override;
     289             : };
     290             : 
     291             : /************************************************************************/
     292             : /*                           BMPRasterBand()                            */
     293             : /************************************************************************/
     294             : 
     295          62 : BMPRasterBand::BMPRasterBand(BMPDataset *poDSIn, int nBandIn)
     296          62 :     : nScanSize(0), iBytesPerPixel(poDSIn->sInfoHeader.iBitCount / 8),
     297          62 :       pabyScan(nullptr)
     298             : {
     299          62 :     poDS = poDSIn;
     300          62 :     nBand = nBandIn;
     301          62 :     eDataType = GDT_Byte;
     302             : 
     303             :     // We will read one scanline per time. Scanlines in BMP aligned at 4-byte
     304             :     // boundary
     305          62 :     nBlockXSize = poDS->GetRasterXSize();
     306          62 :     nBlockYSize = 1;
     307             : 
     308          62 :     const auto knIntMax = std::numeric_limits<int>::max();
     309          62 :     if (nBlockXSize < (knIntMax - 31) / poDSIn->sInfoHeader.iBitCount)
     310             :     {
     311          62 :         nScanSize =
     312          62 :             ((poDS->GetRasterXSize() * poDSIn->sInfoHeader.iBitCount + 31) &
     313          62 :              ~31) /
     314             :             8;
     315             :     }
     316             :     else
     317             :     {
     318             :         // pabyScan = NULL;
     319           0 :         return;
     320             :     }
     321             : 
     322             : #ifdef BMP_DEBUG
     323             :     CPLDebug("BMP", "Band %d: set nBlockXSize=%d, nBlockYSize=%d, nScanSize=%d",
     324             :              nBand, nBlockXSize, nBlockYSize, nScanSize);
     325             : #endif
     326             : 
     327          62 :     pabyScan = static_cast<GByte *>(VSIMalloc(nScanSize));
     328             : }
     329             : 
     330             : /************************************************************************/
     331             : /*                           ~BMPRasterBand()                           */
     332             : /************************************************************************/
     333             : 
     334         122 : BMPRasterBand::~BMPRasterBand()
     335             : {
     336          62 :     CPLFree(pabyScan);
     337         122 : }
     338             : 
     339             : /************************************************************************/
     340             : /*                             IReadBlock()                             */
     341             : /************************************************************************/
     342             : 
     343         895 : CPLErr BMPRasterBand::IReadBlock(int /* nBlockXOff */, int nBlockYOff,
     344             :                                  void *pImage)
     345             : {
     346         895 :     BMPDataset *poGDS = (BMPDataset *)poDS;
     347         895 :     vsi_l_offset iScanOffset = 0;
     348             : 
     349         895 :     if (poGDS->sInfoHeader.iHeight > 0)
     350        1790 :         iScanOffset = poGDS->sFileHeader.iOffBits +
     351         895 :                       (poGDS->GetRasterYSize() - nBlockYOff - 1) *
     352         895 :                           static_cast<vsi_l_offset>(nScanSize);
     353             :     else
     354           0 :         iScanOffset = poGDS->sFileHeader.iOffBits +
     355           0 :                       nBlockYOff * static_cast<vsi_l_offset>(nScanSize);
     356             : 
     357         895 :     if (VSIFSeekL(poGDS->fp, iScanOffset, SEEK_SET) < 0)
     358             :     {
     359             :         // XXX: We will not report error here, because file just may be
     360             :         // in update state and data for this block will be available later.
     361           0 :         if (poGDS->eAccess == GA_Update)
     362             :         {
     363           0 :             memset(pImage, 0, nBlockXSize);
     364           0 :             return CE_None;
     365             :         }
     366             :         else
     367             :         {
     368           0 :             CPLError(CE_Failure, CPLE_FileIO,
     369             :                      "Can't seek to offset " CPL_FRMT_GUIB
     370             :                      " in input file to read data.",
     371             :                      iScanOffset);
     372           0 :             return CE_Failure;
     373             :         }
     374             :     }
     375         895 :     if (VSIFReadL(pabyScan, 1, nScanSize, poGDS->fp) < nScanSize)
     376             :     {
     377             :         // XXX
     378           0 :         if (poGDS->eAccess == GA_Update)
     379             :         {
     380           0 :             memset(pImage, 0, nBlockXSize);
     381           0 :             return CE_None;
     382             :         }
     383             :         else
     384             :         {
     385           0 :             CPLError(CE_Failure, CPLE_FileIO,
     386             :                      "Can't read from offset " CPL_FRMT_GUIB " in input file.",
     387             :                      iScanOffset);
     388           0 :             return CE_Failure;
     389             :         }
     390             :     }
     391             : 
     392         895 :     if (poGDS->sInfoHeader.iBitCount == 24 ||
     393         894 :         poGDS->sInfoHeader.iBitCount == 32)
     394             :     {
     395           1 :         GByte *pabyTemp = pabyScan + 3 - nBand;
     396             : 
     397       65537 :         for (int i = 0; i < nBlockXSize; i++)
     398             :         {
     399             :             // Colour triplets in BMP file organized in reverse order:
     400             :             // blue, green, red. When we have 32-bit BMP the forth byte
     401             :             // in quadruplet should be discarded as it has no meaning.
     402             :             // That is why we always use 3 byte count in the following
     403             :             // pabyTemp index.
     404       65536 :             ((GByte *)pImage)[i] = *pabyTemp;
     405       65536 :             pabyTemp += iBytesPerPixel;
     406           1 :         }
     407             :     }
     408         894 :     else if (poGDS->sInfoHeader.iBitCount == 8)
     409             :     {
     410         810 :         memcpy(pImage, pabyScan, nBlockXSize);
     411             :     }
     412          84 :     else if (poGDS->sInfoHeader.iBitCount == 16)
     413             :     {
     414             :         // rcg, oct 7/06: Byteswap if necessary, use int16
     415             :         // references to file pixels, expand samples to
     416             :         // 8-bit, support BMPC_BITFIELDS channel mask indicators,
     417             :         // and generalize band handling.
     418             : 
     419           0 :         GUInt16 *pScan16 = (GUInt16 *)pabyScan;
     420             : #ifdef CPL_MSB
     421             :         GDALSwapWords(pScan16, sizeof(GUInt16), nBlockXSize, 0);
     422             : #endif
     423             : 
     424             :         // todo: make these band members and precompute.
     425             :         int mask[3], shift[3], size[3];
     426             :         float fTo8bit[3];
     427             : 
     428           0 :         if (poGDS->sInfoHeader.iCompression == BMPC_RGB)
     429             :         {
     430           0 :             mask[0] = 0x7c00;
     431           0 :             mask[1] = 0x03e0;
     432           0 :             mask[2] = 0x001f;
     433             :         }
     434           0 :         else if (poGDS->sInfoHeader.iCompression == BMPC_BITFIELDS)
     435             :         {
     436           0 :             mask[0] = poGDS->sInfoHeader.iRedMask;
     437           0 :             mask[1] = poGDS->sInfoHeader.iGreenMask;
     438           0 :             mask[2] = poGDS->sInfoHeader.iBlueMask;
     439             :         }
     440             :         else
     441             :         {
     442           0 :             CPLError(CE_Failure, CPLE_FileIO, "Unknown 16-bit compression %d.",
     443           0 :                      poGDS->sInfoHeader.iCompression);
     444           0 :             return CE_Failure;
     445             :         }
     446             : 
     447           0 :         for (int i = 0; i < 3; i++)
     448             :         {
     449           0 :             shift[i] = findfirstonbit(mask[i]);
     450           0 :             size[i] = countonbits(mask[i]);
     451           0 :             if (size[i] > 14 || size[i] == 0)
     452             :             {
     453           0 :                 CPLError(CE_Failure, CPLE_FileIO,
     454             :                          "Bad 16-bit channel mask %8x.", mask[i]);
     455           0 :                 return CE_Failure;
     456             :             }
     457           0 :             fTo8bit[i] = 255.0f / ((1 << size[i]) - 1);
     458             :         }
     459             : 
     460           0 :         for (int i = 0; i < nBlockXSize; i++)
     461             :         {
     462           0 :             ((GByte *)pImage)[i] =
     463           0 :                 (GByte)(0.5f +
     464           0 :                         fTo8bit[nBand - 1] * ((pScan16[i] & mask[nBand - 1]) >>
     465           0 :                                               shift[nBand - 1]));
     466             : #if 0
     467             :         // original code
     468             :             switch ( nBand )
     469             :             {
     470             :                 case 1: // Red
     471             :                 ((GByte *) pImage)[i] = pabyScan[i + 1] & 0x1F;
     472             :                 break;
     473             : 
     474             :                 case 2: // Green
     475             :                 ((GByte *) pImage)[i] =
     476             :                     ((pabyScan[i] & 0x03) << 3) |
     477             :                     ((pabyScan[i + 1] & 0xE0) >> 5);
     478             :                 break;
     479             : 
     480             :                 case 3: // Blue
     481             :                 ((GByte *) pImage)[i] = (pabyScan[i] & 0x7c) >> 2;
     482             :                 break;
     483             :                 default:
     484             :                 break;
     485             :             }
     486             : #endif  // 0
     487             :         }
     488             :     }
     489          84 :     else if (poGDS->sInfoHeader.iBitCount == 4)
     490             :     {
     491          20 :         GByte *pabyTemp = pabyScan;
     492             : 
     493         420 :         for (int i = 0; i < nBlockXSize; i++)
     494             :         {
     495             :             // Most significant part of the byte represents leftmost pixel
     496         400 :             if (i & 0x01)
     497         200 :                 ((GByte *)pImage)[i] = *pabyTemp++ & 0x0F;
     498             :             else
     499         200 :                 ((GByte *)pImage)[i] = (*pabyTemp & 0xF0) >> 4;
     500             :         }
     501             :     }
     502          64 :     else if (poGDS->sInfoHeader.iBitCount == 1)
     503             :     {
     504          64 :         GByte *pabyTemp = pabyScan;
     505             : 
     506        2112 :         for (int i = 0; i < nBlockXSize; i++)
     507             :         {
     508        2048 :             switch (i & 0x7)
     509             :             {
     510         256 :                 case 0:
     511         256 :                     ((GByte *)pImage)[i] = (*pabyTemp & 0x80) >> 7;
     512         256 :                     break;
     513         256 :                 case 1:
     514         256 :                     ((GByte *)pImage)[i] = (*pabyTemp & 0x40) >> 6;
     515         256 :                     break;
     516         256 :                 case 2:
     517         256 :                     ((GByte *)pImage)[i] = (*pabyTemp & 0x20) >> 5;
     518         256 :                     break;
     519         256 :                 case 3:
     520         256 :                     ((GByte *)pImage)[i] = (*pabyTemp & 0x10) >> 4;
     521         256 :                     break;
     522         256 :                 case 4:
     523         256 :                     ((GByte *)pImage)[i] = (*pabyTemp & 0x08) >> 3;
     524         256 :                     break;
     525         256 :                 case 5:
     526         256 :                     ((GByte *)pImage)[i] = (*pabyTemp & 0x04) >> 2;
     527         256 :                     break;
     528         256 :                 case 6:
     529         256 :                     ((GByte *)pImage)[i] = (*pabyTemp & 0x02) >> 1;
     530         256 :                     break;
     531         256 :                 case 7:
     532         256 :                     ((GByte *)pImage)[i] = *pabyTemp++ & 0x01;
     533         256 :                     break;
     534           0 :                 default:
     535           0 :                     break;
     536             :             }
     537             :         }
     538             :     }
     539             : 
     540         895 :     return CE_None;
     541             : }
     542             : 
     543             : /************************************************************************/
     544             : /*                            IWriteBlock()                             */
     545             : /************************************************************************/
     546             : 
     547         441 : CPLErr BMPRasterBand::IWriteBlock(int nBlockXOff, int nBlockYOff, void *pImage)
     548             : {
     549         441 :     BMPDataset *poGDS = (BMPDataset *)poDS;
     550             : 
     551         441 :     CPLAssert(poGDS != nullptr && nBlockXOff >= 0 && nBlockYOff >= 0 &&
     552             :               pImage != nullptr);
     553             : 
     554         441 :     vsi_l_offset iScanOffset = poGDS->sFileHeader.iOffBits +
     555         441 :                                (poGDS->GetRasterYSize() - nBlockYOff - 1) *
     556         441 :                                    static_cast<vsi_l_offset>(nScanSize);
     557         441 :     if (VSIFSeekL(poGDS->fp, iScanOffset, SEEK_SET) < 0)
     558             :     {
     559           0 :         CPLError(CE_Failure, CPLE_FileIO,
     560             :                  "Can't seek to offset " CPL_FRMT_GUIB
     561             :                  " in output file to write data.\n%s",
     562           0 :                  iScanOffset, VSIStrerror(errno));
     563           0 :         return CE_Failure;
     564             :     }
     565             : 
     566         441 :     if (poGDS->nBands != 1)
     567             :     {
     568          30 :         memset(pabyScan, 0, nScanSize);
     569          30 :         VSIFReadL(pabyScan, 1, nScanSize, poGDS->fp);
     570          30 :         VSIFSeekL(poGDS->fp, iScanOffset, SEEK_SET);
     571             :     }
     572             : 
     573         441 :     for (int iInPixel = 0, iOutPixel = iBytesPerPixel - nBand;
     574       32851 :          iInPixel < nBlockXSize; iInPixel++, iOutPixel += poGDS->nBands)
     575             :     {
     576       32410 :         pabyScan[iOutPixel] = ((GByte *)pImage)[iInPixel];
     577             :     }
     578             : 
     579         441 :     if (VSIFWriteL(pabyScan, 1, nScanSize, poGDS->fp) < nScanSize)
     580             :     {
     581           1 :         CPLError(CE_Failure, CPLE_FileIO,
     582             :                  "Can't write block with X offset %d and Y offset %d.\n%s",
     583           1 :                  nBlockXOff, nBlockYOff, VSIStrerror(errno));
     584           1 :         return CE_Failure;
     585             :     }
     586             : 
     587         440 :     return CE_None;
     588             : }
     589             : 
     590             : /************************************************************************/
     591             : /*                           GetColorTable()                            */
     592             : /************************************************************************/
     593             : 
     594           6 : GDALColorTable *BMPRasterBand::GetColorTable()
     595             : {
     596           6 :     BMPDataset *poGDS = (BMPDataset *)poDS;
     597             : 
     598           6 :     return poGDS->poColorTable;
     599             : }
     600             : 
     601             : /************************************************************************/
     602             : /*                           SetColorTable()                            */
     603             : /************************************************************************/
     604             : 
     605           1 : CPLErr BMPRasterBand::SetColorTable(GDALColorTable *poColorTable)
     606             : {
     607           1 :     BMPDataset *poGDS = (BMPDataset *)poDS;
     608             : 
     609           1 :     if (poColorTable)
     610             :     {
     611           1 :         poGDS->sInfoHeader.iClrUsed = poColorTable->GetColorEntryCount();
     612           1 :         if (poGDS->sInfoHeader.iClrUsed < 1 ||
     613           1 :             poGDS->sInfoHeader.iClrUsed > (1U << poGDS->sInfoHeader.iBitCount))
     614           0 :             return CE_Failure;
     615             : 
     616           1 :         VSIFSeekL(poGDS->fp, BFH_SIZE + 32, SEEK_SET);
     617             : 
     618           1 :         GUInt32 iULong = CPL_LSBWORD32(poGDS->sInfoHeader.iClrUsed);
     619           1 :         VSIFWriteL(&iULong, 4, 1, poGDS->fp);
     620           2 :         poGDS->pabyColorTable = (GByte *)CPLRealloc(
     621           1 :             poGDS->pabyColorTable, static_cast<size_t>(poGDS->nColorElems) *
     622           1 :                                        poGDS->sInfoHeader.iClrUsed);
     623           1 :         if (!poGDS->pabyColorTable)
     624           0 :             return CE_Failure;
     625             : 
     626         257 :         for (unsigned int i = 0; i < poGDS->sInfoHeader.iClrUsed; i++)
     627             :         {
     628             :             GDALColorEntry oEntry;
     629             : 
     630         256 :             poColorTable->GetColorEntryAsRGB(i, &oEntry);
     631         256 :             poGDS->pabyColorTable[i * poGDS->nColorElems + 3] = 0;
     632         256 :             poGDS->pabyColorTable[i * poGDS->nColorElems + 2] =
     633         256 :                 (GByte)oEntry.c1;  // Red
     634         256 :             poGDS->pabyColorTable[i * poGDS->nColorElems + 1] =
     635         256 :                 (GByte)oEntry.c2;  // Green
     636         256 :             poGDS->pabyColorTable[i * poGDS->nColorElems] =
     637         256 :                 (GByte)oEntry.c3;  // Blue
     638             :         }
     639             : 
     640           1 :         VSIFSeekL(poGDS->fp, BFH_SIZE + poGDS->sInfoHeader.iSize, SEEK_SET);
     641           2 :         if (VSIFWriteL(poGDS->pabyColorTable, 1,
     642           1 :                        static_cast<size_t>(poGDS->nColorElems) *
     643           1 :                            poGDS->sInfoHeader.iClrUsed,
     644           1 :                        poGDS->fp) < static_cast<size_t>(poGDS->nColorElems) *
     645           1 :                                         poGDS->sInfoHeader.iClrUsed)
     646             :         {
     647           0 :             return CE_Failure;
     648             :         }
     649             :     }
     650             :     else
     651           0 :         return CE_Failure;
     652             : 
     653           1 :     return CE_None;
     654             : }
     655             : 
     656             : /************************************************************************/
     657             : /*                       GetColorInterpretation()                       */
     658             : /************************************************************************/
     659             : 
     660          12 : GDALColorInterp BMPRasterBand::GetColorInterpretation()
     661             : {
     662          12 :     BMPDataset *poGDS = (BMPDataset *)poDS;
     663             : 
     664          12 :     if (poGDS->sInfoHeader.iBitCount == 24 ||
     665          12 :         poGDS->sInfoHeader.iBitCount == 32 ||
     666          12 :         poGDS->sInfoHeader.iBitCount == 16)
     667             :     {
     668           0 :         if (nBand == 1)
     669           0 :             return GCI_RedBand;
     670           0 :         else if (nBand == 2)
     671           0 :             return GCI_GreenBand;
     672           0 :         else if (nBand == 3)
     673           0 :             return GCI_BlueBand;
     674             :         else
     675           0 :             return GCI_Undefined;
     676             :     }
     677             :     else
     678             :     {
     679          12 :         return GCI_PaletteIndex;
     680             :     }
     681             : }
     682             : 
     683             : /************************************************************************/
     684             : /* ==================================================================== */
     685             : /*                       BMPComprRasterBand                             */
     686             : /* ==================================================================== */
     687             : /************************************************************************/
     688             : 
     689             : class BMPComprRasterBand final : public BMPRasterBand
     690             : {
     691             :     friend class BMPDataset;
     692             : 
     693             :     GByte *pabyComprBuf;
     694             :     GByte *pabyUncomprBuf;
     695             : 
     696             :   public:
     697             :     BMPComprRasterBand(BMPDataset *, int);
     698             :     ~BMPComprRasterBand() override;
     699             : 
     700             :     CPLErr IReadBlock(int, int, void *) override;
     701             :     // virtual CPLErr IWriteBlock( int, int, void * );
     702             : };
     703             : 
     704             : /************************************************************************/
     705             : /*                           BMPComprRasterBand()                       */
     706             : /************************************************************************/
     707             : 
     708           2 : BMPComprRasterBand::BMPComprRasterBand(BMPDataset *poDSIn, int nBandIn)
     709             :     : BMPRasterBand(poDSIn, nBandIn), pabyComprBuf(nullptr),
     710           2 :       pabyUncomprBuf(nullptr)
     711             : {
     712             :     /* TODO: it might be interesting to avoid uncompressing the whole data */
     713             :     /* in a single pass, especially if nXSize * nYSize is big */
     714             :     /* We could read incrementally one row at a time */
     715           2 :     const auto knIntMax = std::numeric_limits<int>::max();
     716           2 :     if (poDS->GetRasterXSize() > knIntMax / poDS->GetRasterYSize())
     717             :     {
     718           0 :         CPLError(CE_Failure, CPLE_NotSupported, "Too big dimensions : %d x %d",
     719           0 :                  poDS->GetRasterXSize(), poDS->GetRasterYSize());
     720           0 :         return;
     721             :     }
     722             : 
     723           2 :     if (poDSIn->m_nFileSize <= poDSIn->sFileHeader.iOffBits ||
     724           2 :         poDSIn->m_nFileSize - poDSIn->sFileHeader.iOffBits > knIntMax)
     725             :     {
     726           0 :         CPLError(CE_Failure, CPLE_NotSupported, "Invalid header");
     727           0 :         return;
     728             :     }
     729             : 
     730           2 :     const GUInt32 iComprSize = static_cast<GUInt32>(
     731           2 :         poDSIn->m_nFileSize - poDSIn->sFileHeader.iOffBits);
     732             :     const GUInt32 iUncomprSize =
     733           2 :         poDS->GetRasterXSize() * poDS->GetRasterYSize();
     734             : 
     735             : #ifdef DEBUG
     736           2 :     CPLDebug("BMP", "RLE compression detected.");
     737           2 :     CPLDebug("BMP",
     738             :              "Size of compressed buffer %ld bytes,"
     739             :              " size of uncompressed buffer %ld bytes.",
     740             :              (long)iComprSize, (long)iUncomprSize);
     741             : #endif
     742             : 
     743           2 :     pabyComprBuf = (GByte *)VSIMalloc(iComprSize);
     744           2 :     pabyUncomprBuf = (GByte *)VSIMalloc(iUncomprSize);
     745           2 :     if (pabyComprBuf == nullptr || pabyUncomprBuf == nullptr)
     746             :     {
     747           0 :         CPLFree(pabyComprBuf);
     748           0 :         pabyComprBuf = nullptr;
     749           0 :         CPLFree(pabyUncomprBuf);
     750           0 :         pabyUncomprBuf = nullptr;
     751           0 :         return;
     752             :     }
     753             : 
     754           4 :     if (VSIFSeekL(poDSIn->fp, poDSIn->sFileHeader.iOffBits, SEEK_SET) != 0 ||
     755           2 :         VSIFReadL(pabyComprBuf, 1, iComprSize, poDSIn->fp) < iComprSize)
     756             :     {
     757           0 :         CPLError(CE_Failure, CPLE_FileIO,
     758             :                  "Can't read from offset %ld in input file.",
     759           0 :                  (long)poDSIn->sFileHeader.iOffBits);
     760           0 :         CPLFree(pabyComprBuf);
     761           0 :         pabyComprBuf = nullptr;
     762           0 :         CPLFree(pabyUncomprBuf);
     763           0 :         pabyUncomprBuf = nullptr;
     764           0 :         return;
     765             :     }
     766             : 
     767           2 :     unsigned int i = 0;
     768           2 :     unsigned int j = 0;
     769           2 :     if (poDSIn->sInfoHeader.iBitCount == 8)  // RLE8
     770             :     {
     771         122 :         while (i < iComprSize)
     772             :         {
     773         122 :             if (pabyComprBuf[i])
     774             :             {
     775          28 :                 unsigned int iLength = pabyComprBuf[i++];
     776          28 :                 if (j == iUncomprSize)
     777           0 :                     break;
     778         106 :                 while (iLength > 0 && j < iUncomprSize && i < iComprSize)
     779             :                 {
     780          78 :                     pabyUncomprBuf[j++] = pabyComprBuf[i];
     781          78 :                     iLength--;
     782             :                 }
     783          28 :                 i++;
     784             :             }
     785             :             else
     786             :             {
     787          94 :                 i++;
     788          94 :                 if (i == iComprSize)
     789           0 :                     break;
     790          94 :                 if (pabyComprBuf[i] == 0)  // Next scanline
     791             :                 {
     792          38 :                     i++;
     793             :                 }
     794          56 :                 else if (pabyComprBuf[i] == 1)  // End of image
     795             :                 {
     796           2 :                     break;
     797             :                 }
     798          54 :                 else if (pabyComprBuf[i] == 2)  // Move to...
     799             :                 {
     800           0 :                     if (j == iUncomprSize)
     801           0 :                         break;
     802           0 :                     i++;
     803           0 :                     if (i < iComprSize - 1)
     804             :                     {
     805           0 :                         if (pabyComprBuf[i + 1] >
     806           0 :                                 knIntMax / poDS->GetRasterXSize() ||
     807           0 :                             static_cast<int>(pabyComprBuf[i + 1]) *
     808           0 :                                     poDS->GetRasterXSize() >
     809           0 :                                 knIntMax -
     810           0 :                                     static_cast<int>(j + pabyComprBuf[i]))
     811           0 :                             break;
     812           0 :                         j += pabyComprBuf[i] +
     813           0 :                              pabyComprBuf[i + 1] * poDS->GetRasterXSize();
     814           0 :                         i += 2;
     815             :                     }
     816             :                     else
     817           0 :                         break;
     818             :                 }
     819             :                 else  // Absolute mode
     820             :                 {
     821          54 :                     CPLAssert(i < iComprSize);
     822          54 :                     unsigned int iLength = pabyComprBuf[i++];
     823          54 :                     if (j == iUncomprSize)
     824           0 :                         break;
     825          54 :                     for (unsigned k = 0;
     826         776 :                          k < iLength && j < iUncomprSize && i < iComprSize; k++)
     827         722 :                         pabyUncomprBuf[j++] = pabyComprBuf[i++];
     828          54 :                     if (i & 0x01)
     829          18 :                         i++;
     830             :                 }
     831             :             }
     832             :         }
     833             :     }
     834             :     else  // RLE4
     835             :     {
     836           0 :         while (i < iComprSize)
     837             :         {
     838           0 :             if (pabyComprBuf[i])
     839             :             {
     840           0 :                 unsigned int iLength = pabyComprBuf[i++];
     841           0 :                 if (j == iUncomprSize)
     842           0 :                     break;
     843           0 :                 while (iLength > 0 && j < iUncomprSize && i < iComprSize)
     844             :                 {
     845           0 :                     if (iLength & 0x01)
     846           0 :                         pabyUncomprBuf[j++] = (pabyComprBuf[i] & 0xF0) >> 4;
     847             :                     else
     848           0 :                         pabyUncomprBuf[j++] = pabyComprBuf[i] & 0x0F;
     849           0 :                     iLength--;
     850             :                 }
     851           0 :                 i++;
     852             :             }
     853             :             else
     854             :             {
     855           0 :                 i++;
     856           0 :                 if (i == iComprSize)
     857           0 :                     break;
     858           0 :                 if (pabyComprBuf[i] == 0)  // Next scanline
     859             :                 {
     860           0 :                     i++;
     861             :                 }
     862           0 :                 else if (pabyComprBuf[i] == 1)  // End of image
     863             :                 {
     864           0 :                     break;
     865             :                 }
     866           0 :                 else if (pabyComprBuf[i] == 2)  // Move to...
     867             :                 {
     868           0 :                     if (j == iUncomprSize)
     869           0 :                         break;
     870           0 :                     i++;
     871           0 :                     if (i < iComprSize - 1)
     872             :                     {
     873           0 :                         if (pabyComprBuf[i + 1] >
     874           0 :                                 knIntMax / poDS->GetRasterXSize() ||
     875           0 :                             static_cast<int>(pabyComprBuf[i + 1]) *
     876           0 :                                     poDS->GetRasterXSize() >
     877           0 :                                 knIntMax -
     878           0 :                                     static_cast<int>(j + pabyComprBuf[i]))
     879           0 :                             break;
     880           0 :                         j += pabyComprBuf[i] +
     881           0 :                              pabyComprBuf[i + 1] * poDS->GetRasterXSize();
     882           0 :                         i += 2;
     883             :                     }
     884             :                     else
     885           0 :                         break;
     886             :                 }
     887             :                 else  // Absolute mode
     888             :                 {
     889           0 :                     CPLAssert(i < iComprSize);
     890           0 :                     unsigned int iLength = pabyComprBuf[i++];
     891           0 :                     if (j == iUncomprSize)
     892           0 :                         break;
     893           0 :                     for (unsigned k = 0;
     894           0 :                          k < iLength && j < iUncomprSize && i < iComprSize; k++)
     895             :                     {
     896           0 :                         if (k & 0x01)
     897           0 :                             pabyUncomprBuf[j++] = pabyComprBuf[i++] & 0x0F;
     898             :                         else
     899           0 :                             pabyUncomprBuf[j++] = (pabyComprBuf[i] & 0xF0) >> 4;
     900             :                     }
     901           0 :                     if (i & 0x01)
     902           0 :                         i++;
     903             :                 }
     904             :             }
     905             :         }
     906             :     }
     907             :     /* Validate that we have read all compressed data (we tolerate missing */
     908             :     /* end of image marker) and that we have filled all uncompressed data */
     909           2 :     if (j < iUncomprSize || (i + 1 != iComprSize && i + 2 != iComprSize))
     910             :     {
     911           0 :         CPLFree(pabyUncomprBuf);
     912           0 :         pabyUncomprBuf = nullptr;
     913             :     }
     914             :     // rcg, release compressed buffer here.
     915           2 :     CPLFree(pabyComprBuf);
     916           2 :     pabyComprBuf = nullptr;
     917             : }
     918             : 
     919             : /************************************************************************/
     920             : /*                           ~BMPComprRasterBand()                      */
     921             : /************************************************************************/
     922             : 
     923           4 : BMPComprRasterBand::~BMPComprRasterBand()
     924             : {
     925           2 :     CPLFree(pabyComprBuf);
     926           2 :     CPLFree(pabyUncomprBuf);
     927           4 : }
     928             : 
     929             : /************************************************************************/
     930             : /*                             IReadBlock()                             */
     931             : /************************************************************************/
     932             : 
     933          20 : CPLErr BMPComprRasterBand::IReadBlock(CPL_UNUSED int nBlockXOff, int nBlockYOff,
     934             :                                       void *pImage)
     935             : {
     936          40 :     memcpy(pImage,
     937          60 :            pabyUncomprBuf + (poDS->GetRasterYSize() - nBlockYOff - 1) *
     938          20 :                                 poDS->GetRasterXSize(),
     939          20 :            nBlockXSize);
     940             : 
     941          20 :     return CE_None;
     942             : }
     943             : 
     944             : /************************************************************************/
     945             : /*                           BMPDataset()                               */
     946             : /************************************************************************/
     947             : 
     948          66 : BMPDataset::BMPDataset()
     949             :     : nColorElems(0), pabyColorTable(nullptr), poColorTable(nullptr),
     950          66 :       bGeoTransformValid(FALSE), pszFilename(nullptr), fp(nullptr)
     951             : {
     952          66 :     nBands = 0;
     953             : 
     954          66 :     memset(&sFileHeader, 0, sizeof(sFileHeader));
     955          66 :     memset(&sInfoHeader, 0, sizeof(sInfoHeader));
     956             : 
     957          66 :     adfGeoTransform[0] = 0.0;
     958          66 :     adfGeoTransform[1] = 1.0;
     959          66 :     adfGeoTransform[2] = 0.0;
     960          66 :     adfGeoTransform[3] = 0.0;
     961          66 :     adfGeoTransform[4] = 0.0;
     962          66 :     adfGeoTransform[5] = 1.0;
     963          66 : }
     964             : 
     965             : /************************************************************************/
     966             : /*                            ~BMPDataset()                             */
     967             : /************************************************************************/
     968             : 
     969         132 : BMPDataset::~BMPDataset()
     970             : {
     971          66 :     FlushCache(true);
     972             : 
     973          66 :     if (m_bNewFile && fp)
     974             :     {
     975             :         // Extend the file with zeroes if needed
     976          23 :         VSIFSeekL(fp, 0, SEEK_END);
     977             : 
     978          23 :         if (VSIFTellL(fp) < m_nFileSize)
     979             :         {
     980          13 :             VSIFTruncateL(fp, m_nFileSize);
     981             :         }
     982             :     }
     983             : 
     984          66 :     CPLFree(pabyColorTable);
     985          66 :     if (poColorTable)
     986          38 :         delete poColorTable;
     987          66 :     CPLFree(pszFilename);
     988          66 :     if (fp)
     989          63 :         VSIFCloseL(fp);
     990         132 : }
     991             : 
     992             : /************************************************************************/
     993             : /*                          GetGeoTransform()                           */
     994             : /************************************************************************/
     995             : 
     996          11 : CPLErr BMPDataset::GetGeoTransform(double *padfTransform)
     997             : {
     998          11 :     if (bGeoTransformValid)
     999             :     {
    1000           0 :         memcpy(padfTransform, adfGeoTransform, sizeof(adfGeoTransform[0]) * 6);
    1001           0 :         return CE_None;
    1002             :     }
    1003             : 
    1004          11 :     if (GDALPamDataset::GetGeoTransform(padfTransform) == CE_None)
    1005           2 :         return CE_None;
    1006             : 
    1007             : #ifdef notdef
    1008             :     // See http://trac.osgeo.org/gdal/ticket/3578
    1009             :     if (sInfoHeader.iXPelsPerMeter > 0 && sInfoHeader.iYPelsPerMeter > 0)
    1010             :     {
    1011             :         padfTransform[1] = sInfoHeader.iXPelsPerMeter;
    1012             :         padfTransform[5] = -sInfoHeader.iYPelsPerMeter;
    1013             :         padfTransform[0] = -0.5 * padfTransform[1];
    1014             :         padfTransform[3] = -0.5 * padfTransform[5];
    1015             :         return CE_None;
    1016             :     }
    1017             : #endif
    1018             : 
    1019           9 :     return CE_Failure;
    1020             : }
    1021             : 
    1022             : /************************************************************************/
    1023             : /*                          SetGeoTransform()                           */
    1024             : /************************************************************************/
    1025             : 
    1026           8 : CPLErr BMPDataset::SetGeoTransform(double *padfTransform)
    1027             : {
    1028           8 :     if (pszFilename && bGeoTransformValid)
    1029             :     {
    1030           0 :         memcpy(adfGeoTransform, padfTransform, sizeof(double) * 6);
    1031             : 
    1032           0 :         CPLErr eErr = CE_None;
    1033           0 :         if (GDALWriteWorldFile(pszFilename, "wld", adfGeoTransform) == FALSE)
    1034             :         {
    1035           0 :             CPLError(CE_Failure, CPLE_FileIO, "Can't write world file.");
    1036           0 :             eErr = CE_Failure;
    1037             :         }
    1038           0 :         return eErr;
    1039             :     }
    1040             : 
    1041           8 :     return GDALPamDataset::SetGeoTransform(padfTransform);
    1042             : }
    1043             : 
    1044             : /************************************************************************/
    1045             : /*                             IRasterIO()                              */
    1046             : /*                                                                      */
    1047             : /*      Multi-band raster io handler.  We will use  block based         */
    1048             : /*      loading is used for multiband BMPs.  That is because they       */
    1049             : /*      are effectively pixel interleaved, so processing all bands      */
    1050             : /*      for a given block together avoid extra seeks.                   */
    1051             : /************************************************************************/
    1052             : 
    1053          13 : CPLErr BMPDataset::IRasterIO(GDALRWFlag eRWFlag, int nXOff, int nYOff,
    1054             :                              int nXSize, int nYSize, void *pData, int nBufXSize,
    1055             :                              int nBufYSize, GDALDataType eBufType,
    1056             :                              int nBandCount, int *panBandMap,
    1057             :                              GSpacing nPixelSpace, GSpacing nLineSpace,
    1058             :                              GSpacing nBandSpace,
    1059             :                              GDALRasterIOExtraArg *psExtraArg)
    1060             : 
    1061             : {
    1062          13 :     if (nBandCount > 1)
    1063           0 :         return GDALDataset::BlockBasedRasterIO(
    1064             :             eRWFlag, nXOff, nYOff, nXSize, nYSize, pData, nBufXSize, nBufYSize,
    1065             :             eBufType, nBandCount, panBandMap, nPixelSpace, nLineSpace,
    1066           0 :             nBandSpace, psExtraArg);
    1067             :     else
    1068          13 :         return GDALDataset::IRasterIO(eRWFlag, nXOff, nYOff, nXSize, nYSize,
    1069             :                                       pData, nBufXSize, nBufYSize, eBufType,
    1070             :                                       nBandCount, panBandMap, nPixelSpace,
    1071          13 :                                       nLineSpace, nBandSpace, psExtraArg);
    1072             : }
    1073             : 
    1074             : /************************************************************************/
    1075             : /*                              Identify()                              */
    1076             : /************************************************************************/
    1077             : 
    1078       52962 : int BMPDataset::Identify(GDALOpenInfo *poOpenInfo)
    1079             : 
    1080             : {
    1081       52962 :     if (poOpenInfo->nHeaderBytes < BFH_SIZE + SIZE_OF_INFOHEADER_SIZE ||
    1082        6204 :         poOpenInfo->pabyHeader[0] != 'B' || poOpenInfo->pabyHeader[1] != 'M' ||
    1083          80 :         poOpenInfo->pabyHeader[6] != 0 || poOpenInfo->pabyHeader[7] != 0 ||
    1084          80 :         poOpenInfo->pabyHeader[8] != 0 || poOpenInfo->pabyHeader[9] != 0)
    1085       52882 :         return FALSE;
    1086             : 
    1087             :     uint32_t nInfoHeaderSize;
    1088          80 :     memcpy(&nInfoHeaderSize, poOpenInfo->pabyHeader + BFH_SIZE,
    1089             :            sizeof(uint32_t));
    1090          80 :     CPL_LSBPTR32(&nInfoHeaderSize);
    1091             :     // Check against the maximum known size
    1092          80 :     if (nInfoHeaderSize > BIH_OS22SIZE)
    1093           0 :         return FALSE;
    1094             : 
    1095          80 :     return TRUE;
    1096             : }
    1097             : 
    1098             : /************************************************************************/
    1099             : /*                                Open()                                */
    1100             : /************************************************************************/
    1101             : 
    1102          40 : GDALDataset *BMPDataset::Open(GDALOpenInfo *poOpenInfo)
    1103             : {
    1104          40 :     if (!Identify(poOpenInfo) || poOpenInfo->fpL == nullptr)
    1105           0 :         return nullptr;
    1106             : 
    1107             :     /* -------------------------------------------------------------------- */
    1108             :     /*      Create a corresponding GDALDataset.                             */
    1109             :     /* -------------------------------------------------------------------- */
    1110          40 :     BMPDataset *poDS = new BMPDataset();
    1111          40 :     poDS->eAccess = poOpenInfo->eAccess;
    1112             : 
    1113             :     VSIStatBufL sStat;
    1114          40 :     if (VSIStatL(poOpenInfo->pszFilename, &sStat) != 0)
    1115             :     {
    1116           0 :         delete poDS;
    1117           0 :         return nullptr;
    1118             :     }
    1119             : 
    1120             :     /* -------------------------------------------------------------------- */
    1121             :     /*      Read the BMPFileHeader. We need iOffBits value only             */
    1122             :     /* -------------------------------------------------------------------- */
    1123          40 :     memcpy(&poDS->sFileHeader.iOffBits, poOpenInfo->pabyHeader + 10, 4);
    1124             : #ifdef CPL_MSB
    1125             :     CPL_SWAP32PTR(&poDS->sFileHeader.iOffBits);
    1126             : #endif
    1127          40 :     poDS->m_nFileSize = sStat.st_size;
    1128             : 
    1129             : #ifdef BMP_DEBUG
    1130             :     CPLDebug("BMP", "File size " CPL_FRMT_GUIB " bytes.",
    1131             :              static_cast<GUIntBig>(poDS->m_nFileSize));
    1132             :     CPLDebug("BMP", "Image offset 0x%x bytes from file start.",
    1133             :              poDS->sFileHeader.iOffBits);
    1134             : #endif
    1135             : 
    1136             :     // Validatate iOffBits
    1137          40 :     if (poDS->sFileHeader.iOffBits <= BFH_SIZE + SIZE_OF_INFOHEADER_SIZE ||
    1138          40 :         poDS->sFileHeader.iOffBits >= poDS->m_nFileSize)
    1139             :     {
    1140           0 :         delete poDS;
    1141           0 :         return nullptr;
    1142             :     }
    1143             : 
    1144             :     /* -------------------------------------------------------------------- */
    1145             :     /*      Read the BMPInfoHeader.                                         */
    1146             :     /* -------------------------------------------------------------------- */
    1147          40 :     poDS->fp = poOpenInfo->fpL;
    1148          40 :     poOpenInfo->fpL = nullptr;
    1149             : 
    1150          40 :     VSIFSeekL(poDS->fp, BFH_SIZE, SEEK_SET);
    1151          40 :     VSIFReadL(&poDS->sInfoHeader.iSize, 1, 4, poDS->fp);
    1152             : #ifdef CPL_MSB
    1153             :     CPL_SWAP32PTR(&poDS->sInfoHeader.iSize);
    1154             : #endif
    1155             : 
    1156             :     BMPType eBMPType;
    1157          40 :     if (poDS->sInfoHeader.iSize == BIH_WIN4SIZE)
    1158          40 :         eBMPType = BMPT_WIN4;
    1159           0 :     else if (poDS->sInfoHeader.iSize == BIH_OS21SIZE)
    1160           0 :         eBMPType = BMPT_OS21;
    1161           0 :     else if (poDS->sInfoHeader.iSize == BIH_OS22SIZE ||
    1162           0 :              poDS->sInfoHeader.iSize == 16)
    1163           0 :         eBMPType = BMPT_OS22;
    1164             :     else
    1165           0 :         eBMPType = BMPT_WIN5;
    1166             : 
    1167          40 :     if (eBMPType == BMPT_WIN4 || eBMPType == BMPT_WIN5 || eBMPType == BMPT_OS22)
    1168             :     {
    1169          40 :         VSIFReadL(&poDS->sInfoHeader.iWidth, 1, 4, poDS->fp);
    1170          40 :         VSIFReadL(&poDS->sInfoHeader.iHeight, 1, 4, poDS->fp);
    1171          40 :         VSIFReadL(&poDS->sInfoHeader.iPlanes, 1, 2, poDS->fp);
    1172          40 :         VSIFReadL(&poDS->sInfoHeader.iBitCount, 1, 2, poDS->fp);
    1173             :         unsigned int iCompression;
    1174          40 :         VSIFReadL(&iCompression, 1, 4, poDS->fp);
    1175             : #ifdef CPL_MSB
    1176             :         CPL_SWAP32PTR(&iCompression);
    1177             : #endif
    1178          40 :         if (iCompression > BMPC_PNG)
    1179             :         {
    1180           0 :             CPLError(CE_Failure, CPLE_NotSupported, "Unsupported compression");
    1181           0 :             delete poDS;
    1182           0 :             return nullptr;
    1183             :         }
    1184          40 :         poDS->sInfoHeader.iCompression =
    1185             :             static_cast<BMPComprMethod>(iCompression);
    1186          40 :         VSIFReadL(&poDS->sInfoHeader.iSizeImage, 1, 4, poDS->fp);
    1187          40 :         VSIFReadL(&poDS->sInfoHeader.iXPelsPerMeter, 1, 4, poDS->fp);
    1188          40 :         VSIFReadL(&poDS->sInfoHeader.iYPelsPerMeter, 1, 4, poDS->fp);
    1189          40 :         VSIFReadL(&poDS->sInfoHeader.iClrUsed, 1, 4, poDS->fp);
    1190          40 :         VSIFReadL(&poDS->sInfoHeader.iClrImportant, 1, 4, poDS->fp);
    1191             : 
    1192             :         // rcg, read win4/5 fields. If we're reading a
    1193             :         // legacy header that ends at iClrImportant, it turns
    1194             :         // out that the three DWORD color table entries used
    1195             :         // by the channel masks start here anyway.
    1196          40 :         if (poDS->sInfoHeader.iCompression == BMPC_BITFIELDS)
    1197             :         {
    1198           0 :             VSIFReadL(&poDS->sInfoHeader.iRedMask, 1, 4, poDS->fp);
    1199           0 :             VSIFReadL(&poDS->sInfoHeader.iGreenMask, 1, 4, poDS->fp);
    1200           0 :             VSIFReadL(&poDS->sInfoHeader.iBlueMask, 1, 4, poDS->fp);
    1201             :         }
    1202             : #ifdef CPL_MSB
    1203             :         CPL_SWAP32PTR(&poDS->sInfoHeader.iWidth);
    1204             :         CPL_SWAP32PTR(&poDS->sInfoHeader.iHeight);
    1205             :         CPL_SWAP16PTR(&poDS->sInfoHeader.iPlanes);
    1206             :         CPL_SWAP16PTR(&poDS->sInfoHeader.iBitCount);
    1207             :         CPL_SWAP32PTR(&poDS->sInfoHeader.iSizeImage);
    1208             :         CPL_SWAP32PTR(&poDS->sInfoHeader.iXPelsPerMeter);
    1209             :         CPL_SWAP32PTR(&poDS->sInfoHeader.iYPelsPerMeter);
    1210             :         CPL_SWAP32PTR(&poDS->sInfoHeader.iClrUsed);
    1211             :         CPL_SWAP32PTR(&poDS->sInfoHeader.iClrImportant);
    1212             :         // rcg, swap win4/5 fields.
    1213             :         CPL_SWAP32PTR(&poDS->sInfoHeader.iRedMask);
    1214             :         CPL_SWAP32PTR(&poDS->sInfoHeader.iGreenMask);
    1215             :         CPL_SWAP32PTR(&poDS->sInfoHeader.iBlueMask);
    1216             : #endif
    1217          40 :         poDS->nColorElems = 4;
    1218             :     }
    1219             : 
    1220          40 :     if (eBMPType == BMPT_OS22)
    1221             :     {
    1222           0 :         poDS->nColorElems =
    1223             :             3;  // FIXME: different info in different documents regarding this!
    1224             :     }
    1225             : 
    1226          40 :     if (eBMPType == BMPT_OS21)
    1227             :     {
    1228             :         GInt16 iShort;
    1229             : 
    1230           0 :         VSIFReadL(&iShort, 1, 2, poDS->fp);
    1231           0 :         poDS->sInfoHeader.iWidth = CPL_LSBWORD16(iShort);
    1232           0 :         VSIFReadL(&iShort, 1, 2, poDS->fp);
    1233           0 :         poDS->sInfoHeader.iHeight = CPL_LSBWORD16(iShort);
    1234           0 :         VSIFReadL(&iShort, 1, 2, poDS->fp);
    1235           0 :         poDS->sInfoHeader.iPlanes = CPL_LSBWORD16(iShort);
    1236           0 :         VSIFReadL(&iShort, 1, 2, poDS->fp);
    1237           0 :         poDS->sInfoHeader.iBitCount = CPL_LSBWORD16(iShort);
    1238           0 :         poDS->sInfoHeader.iCompression = BMPC_RGB;
    1239           0 :         poDS->nColorElems = 3;
    1240             :     }
    1241             : 
    1242          40 :     if (poDS->sInfoHeader.iBitCount != 1 && poDS->sInfoHeader.iBitCount != 4 &&
    1243          35 :         poDS->sInfoHeader.iBitCount != 8 && poDS->sInfoHeader.iBitCount != 16 &&
    1244           2 :         poDS->sInfoHeader.iBitCount != 24 && poDS->sInfoHeader.iBitCount != 32)
    1245             :     {
    1246           0 :         delete poDS;
    1247           0 :         return nullptr;
    1248             :     }
    1249             : 
    1250             : #ifdef BMP_DEBUG
    1251             :     CPLDebug("BMP",
    1252             :              "Windows Device Independent Bitmap parameters:\n"
    1253             :              " info header size: %d bytes\n"
    1254             :              " width: %d\n height: %d\n planes: %d\n bpp: %d\n"
    1255             :              " compression: %d\n image size: %d bytes\n X resolution: %d\n"
    1256             :              " Y resolution: %d\n colours used: %d\n colours important: %d",
    1257             :              poDS->sInfoHeader.iSize, poDS->sInfoHeader.iWidth,
    1258             :              poDS->sInfoHeader.iHeight, poDS->sInfoHeader.iPlanes,
    1259             :              poDS->sInfoHeader.iBitCount, poDS->sInfoHeader.iCompression,
    1260             :              poDS->sInfoHeader.iSizeImage, poDS->sInfoHeader.iXPelsPerMeter,
    1261             :              poDS->sInfoHeader.iYPelsPerMeter, poDS->sInfoHeader.iClrUsed,
    1262             :              poDS->sInfoHeader.iClrImportant);
    1263             : #endif
    1264             : 
    1265          40 :     if (poDS->sInfoHeader.iHeight == INT_MIN)
    1266             :     {
    1267           0 :         delete poDS;
    1268           0 :         return nullptr;
    1269             :     }
    1270             : 
    1271          40 :     poDS->nRasterXSize = poDS->sInfoHeader.iWidth;
    1272          40 :     poDS->nRasterYSize = (poDS->sInfoHeader.iHeight > 0)
    1273          40 :                              ? poDS->sInfoHeader.iHeight
    1274             :                              : -poDS->sInfoHeader.iHeight;
    1275             : 
    1276          40 :     if (poDS->nRasterXSize <= 0 || poDS->nRasterYSize <= 0)
    1277             :     {
    1278           0 :         CPLError(CE_Failure, CPLE_AppDefined, "Invalid dimensions : %d x %d",
    1279             :                  poDS->nRasterXSize, poDS->nRasterYSize);
    1280           0 :         delete poDS;
    1281           0 :         return nullptr;
    1282             :     }
    1283             : 
    1284          40 :     switch (poDS->sInfoHeader.iBitCount)
    1285             :     {
    1286          38 :         case 1:
    1287             :         case 4:
    1288             :         case 8:
    1289             :         {
    1290          38 :             poDS->nBands = 1;
    1291             :             int nColorTableSize;
    1292          38 :             int nMaxColorTableSize = 1 << poDS->sInfoHeader.iBitCount;
    1293             :             // Allocate memory for colour table and read it
    1294          38 :             if (poDS->sInfoHeader.iClrUsed)
    1295             :             {
    1296          27 :                 if (poDS->sInfoHeader.iClrUsed > (GUInt32)nMaxColorTableSize)
    1297             :                 {
    1298           0 :                     CPLError(CE_Failure, CPLE_NotSupported,
    1299             :                              "Wrong value for iClrUsed: %u",
    1300             :                              poDS->sInfoHeader.iClrUsed);
    1301           0 :                     delete poDS;
    1302           0 :                     return nullptr;
    1303             :                 }
    1304          27 :                 nColorTableSize = poDS->sInfoHeader.iClrUsed;
    1305             :             }
    1306             :             else
    1307          11 :                 nColorTableSize = nMaxColorTableSize;
    1308             : 
    1309          38 :             poDS->pabyColorTable = (GByte *)VSI_MALLOC2_VERBOSE(
    1310             :                 poDS->nColorElems, nColorTableSize);
    1311          38 :             if (poDS->pabyColorTable == nullptr)
    1312             :             {
    1313           0 :                 break;
    1314             :             }
    1315             : 
    1316         114 :             if (VSIFSeekL(poDS->fp,
    1317          38 :                           BFH_SIZE + static_cast<vsi_l_offset>(
    1318          38 :                                          poDS->sInfoHeader.iSize),
    1319          76 :                           SEEK_SET) != 0 ||
    1320          38 :                 VSIFReadL(poDS->pabyColorTable, poDS->nColorElems,
    1321          38 :                           nColorTableSize, poDS->fp) != (size_t)nColorTableSize)
    1322             :             {
    1323           0 :                 CPLError(CE_Failure, CPLE_FileIO, "Cannot read color table");
    1324           0 :                 delete poDS;
    1325           0 :                 return nullptr;
    1326             :             }
    1327             : 
    1328             :             GDALColorEntry oEntry;
    1329          38 :             poDS->poColorTable = new GDALColorTable();
    1330        8524 :             for (int i = 0; i < nColorTableSize; i++)
    1331             :             {
    1332        8486 :                 oEntry.c1 =
    1333        8486 :                     poDS->pabyColorTable[i * poDS->nColorElems + 2];  // Red
    1334        8486 :                 oEntry.c2 =
    1335        8486 :                     poDS->pabyColorTable[i * poDS->nColorElems + 1];  // Green
    1336        8486 :                 oEntry.c3 =
    1337        8486 :                     poDS->pabyColorTable[i * poDS->nColorElems];  // Blue
    1338        8486 :                 oEntry.c4 = 255;
    1339             : 
    1340        8486 :                 poDS->poColorTable->SetColorEntry(i, &oEntry);
    1341             :             }
    1342             :         }
    1343          38 :         break;
    1344           2 :         case 16:
    1345             :         case 24:
    1346             :         case 32:
    1347           2 :             poDS->nBands = 3;
    1348           2 :             break;
    1349           0 :         default:
    1350           0 :             delete poDS;
    1351           0 :             return nullptr;
    1352             :     }
    1353             : 
    1354             :     /* -------------------------------------------------------------------- */
    1355             :     /*      Create band information objects.                                */
    1356             :     /* -------------------------------------------------------------------- */
    1357          40 :     if (poDS->sInfoHeader.iCompression == BMPC_RGB ||
    1358           2 :         poDS->sInfoHeader.iCompression == BMPC_BITFIELDS)
    1359             :     {
    1360          80 :         for (int iBand = 1; iBand <= poDS->nBands; iBand++)
    1361             :         {
    1362          42 :             BMPRasterBand *band = new BMPRasterBand(poDS, iBand);
    1363          42 :             poDS->SetBand(iBand, band);
    1364          42 :             if (band->pabyScan == nullptr)
    1365             :             {
    1366           0 :                 CPLError(CE_Failure, CPLE_AppDefined,
    1367             :                          "The BMP file is probably corrupted or too large. "
    1368             :                          "Image width = %d",
    1369             :                          poDS->nRasterXSize);
    1370           0 :                 delete poDS;
    1371           0 :                 return nullptr;
    1372             :             }
    1373          38 :         }
    1374             :     }
    1375           2 :     else if (poDS->sInfoHeader.iCompression == BMPC_RLE8 ||
    1376           0 :              poDS->sInfoHeader.iCompression == BMPC_RLE4)
    1377             :     {
    1378           4 :         for (int iBand = 1; iBand <= poDS->nBands; iBand++)
    1379             :         {
    1380           2 :             BMPComprRasterBand *band = new BMPComprRasterBand(poDS, iBand);
    1381           2 :             poDS->SetBand(iBand, band);
    1382           2 :             if (band->pabyUncomprBuf == nullptr)
    1383             :             {
    1384           0 :                 CPLError(CE_Failure, CPLE_AppDefined,
    1385             :                          "The BMP file is probably corrupted or too large. "
    1386             :                          "Image width = %d",
    1387             :                          poDS->nRasterXSize);
    1388           0 :                 delete poDS;
    1389           0 :                 return nullptr;
    1390             :             }
    1391           2 :         }
    1392             :     }
    1393             :     else
    1394             :     {
    1395           0 :         delete poDS;
    1396           0 :         return nullptr;
    1397             :     }
    1398             : 
    1399             :     /* -------------------------------------------------------------------- */
    1400             :     /*      Check for world file.                                           */
    1401             :     /* -------------------------------------------------------------------- */
    1402          80 :     poDS->bGeoTransformValid = GDALReadWorldFile(
    1403          40 :         poOpenInfo->pszFilename, nullptr, poDS->adfGeoTransform);
    1404             : 
    1405          40 :     if (!poDS->bGeoTransformValid)
    1406          40 :         poDS->bGeoTransformValid = GDALReadWorldFile(
    1407          40 :             poOpenInfo->pszFilename, ".wld", poDS->adfGeoTransform);
    1408             : 
    1409             :     /* -------------------------------------------------------------------- */
    1410             :     /*      Initialize any PAM information.                                 */
    1411             :     /* -------------------------------------------------------------------- */
    1412          40 :     poDS->SetDescription(poOpenInfo->pszFilename);
    1413          40 :     poDS->TryLoadXML();
    1414             : 
    1415             :     /* -------------------------------------------------------------------- */
    1416             :     /*      Check for overviews.                                            */
    1417             :     /* -------------------------------------------------------------------- */
    1418          40 :     poDS->oOvManager.Initialize(poDS, poOpenInfo->pszFilename);
    1419             : 
    1420          40 :     return poDS;
    1421             : }
    1422             : 
    1423             : /************************************************************************/
    1424             : /*                               Create()                               */
    1425             : /************************************************************************/
    1426             : 
    1427          69 : GDALDataset *BMPDataset::Create(const char *pszFilename, int nXSize, int nYSize,
    1428             :                                 int nBandsIn, GDALDataType eType,
    1429             :                                 char **papszOptions)
    1430             : 
    1431             : {
    1432          69 :     if (eType != GDT_Byte)
    1433             :     {
    1434          36 :         CPLError(CE_Failure, CPLE_AppDefined,
    1435             :                  "Attempt to create BMP dataset with an illegal\n"
    1436             :                  "data type (%s), only Byte supported by the format.\n",
    1437             :                  GDALGetDataTypeName(eType));
    1438             : 
    1439          36 :         return nullptr;
    1440             :     }
    1441             : 
    1442          33 :     if (nBandsIn != 1 && nBandsIn != 3)
    1443             :     {
    1444           7 :         CPLError(CE_Failure, CPLE_NotSupported,
    1445             :                  "BMP driver doesn't support %d bands. Must be 1 or 3.\n",
    1446             :                  nBandsIn);
    1447             : 
    1448           7 :         return nullptr;
    1449             :     }
    1450             : 
    1451             :     /* -------------------------------------------------------------------- */
    1452             :     /*      Create the dataset.                                             */
    1453             :     /* -------------------------------------------------------------------- */
    1454          26 :     BMPDataset *poDS = new BMPDataset();
    1455          26 :     poDS->m_bNewFile = true;
    1456             : 
    1457          26 :     poDS->fp = VSIFOpenL(pszFilename, "wb+");
    1458          26 :     if (poDS->fp == nullptr)
    1459             :     {
    1460           3 :         CPLError(CE_Failure, CPLE_OpenFailed, "Unable to create file %s.\n",
    1461             :                  pszFilename);
    1462           3 :         delete poDS;
    1463           3 :         return nullptr;
    1464             :     }
    1465             : 
    1466          23 :     poDS->pszFilename = CPLStrdup(pszFilename);
    1467             : 
    1468             :     /* -------------------------------------------------------------------- */
    1469             :     /*      Fill the BMPInfoHeader                                          */
    1470             :     /* -------------------------------------------------------------------- */
    1471          23 :     poDS->sInfoHeader.iSize = 40;
    1472          23 :     poDS->sInfoHeader.iWidth = nXSize;
    1473          23 :     poDS->sInfoHeader.iHeight = nYSize;
    1474          23 :     poDS->sInfoHeader.iPlanes = 1;
    1475          23 :     poDS->sInfoHeader.iBitCount = (nBandsIn == 3) ? 24 : 8;
    1476          23 :     poDS->sInfoHeader.iCompression = BMPC_RGB;
    1477             : 
    1478             :     /* XXX: Avoid integer overflow. We can calculate size in one
    1479             :      * step using
    1480             :      *
    1481             :      *   nScanSize = ((poDS->sInfoHeader.iWidth *
    1482             :      *            poDS->sInfoHeader.iBitCount + 31) & ~31) / 8
    1483             :      *
    1484             :      * formula, but we should check for overflow conditions
    1485             :      * during calculation.
    1486             :      */
    1487          23 :     GUInt32 nScanSize =
    1488          23 :         (GUInt32)poDS->sInfoHeader.iWidth * poDS->sInfoHeader.iBitCount + 31;
    1489          23 :     if (!poDS->sInfoHeader.iWidth || !poDS->sInfoHeader.iBitCount ||
    1490          23 :         (nScanSize - 31) / poDS->sInfoHeader.iBitCount !=
    1491          23 :             (GUInt32)poDS->sInfoHeader.iWidth)
    1492             :     {
    1493           0 :         CPLError(CE_Failure, CPLE_FileIO,
    1494             :                  "Wrong image parameters; "
    1495             :                  "can't allocate space for scanline buffer");
    1496           0 :         delete poDS;
    1497             : 
    1498           0 :         return nullptr;
    1499             :     }
    1500          23 :     nScanSize = (nScanSize & ~31U) / 8;
    1501             : 
    1502          23 :     poDS->sInfoHeader.iXPelsPerMeter = 0;
    1503          23 :     poDS->sInfoHeader.iYPelsPerMeter = 0;
    1504          23 :     poDS->nColorElems = 4;
    1505             : 
    1506             :     /* -------------------------------------------------------------------- */
    1507             :     /*      Do we need colour table?                                        */
    1508             :     /* -------------------------------------------------------------------- */
    1509          23 :     if (nBandsIn == 1)
    1510             :     {
    1511          21 :         poDS->sInfoHeader.iClrUsed = 1 << poDS->sInfoHeader.iBitCount;
    1512          21 :         poDS->pabyColorTable =
    1513          42 :             (GByte *)CPLMalloc(static_cast<size_t>(poDS->nColorElems) *
    1514          21 :                                poDS->sInfoHeader.iClrUsed);
    1515        5397 :         for (unsigned int i = 0; i < poDS->sInfoHeader.iClrUsed; i++)
    1516             :         {
    1517        5376 :             poDS->pabyColorTable[i * poDS->nColorElems] =
    1518        5376 :                 poDS->pabyColorTable[i * poDS->nColorElems + 1] =
    1519        5376 :                     poDS->pabyColorTable[i * poDS->nColorElems + 2] =
    1520        5376 :                         poDS->pabyColorTable[i * poDS->nColorElems + 3] =
    1521             :                             (GByte)i;
    1522             :         }
    1523             :     }
    1524             :     else
    1525             :     {
    1526           2 :         poDS->sInfoHeader.iClrUsed = 0;
    1527             :     }
    1528          23 :     poDS->sInfoHeader.iClrImportant = 0;
    1529             : 
    1530             :     /* -------------------------------------------------------------------- */
    1531             :     /*      Fill the BMPFileHeader                                          */
    1532             :     /* -------------------------------------------------------------------- */
    1533             : 
    1534          23 :     poDS->sFileHeader.iOffBits = BFH_SIZE + poDS->sInfoHeader.iSize +
    1535          23 :                                  poDS->sInfoHeader.iClrUsed * poDS->nColorElems;
    1536             : 
    1537             :     // From https://medium.com/@chiaracoetzee/maximum-resolution-of-bmp-image-file-8c729b3f833a
    1538          23 :     if (nXSize > 30000 || nYSize > 30000)
    1539             :     {
    1540           0 :         CPLDebug("BMP", "Dimensions of BMP file exceed maximum supported by "
    1541             :                         "Adobe Photoshop CC 2014.2.2");
    1542             :     }
    1543          23 :     if (nXSize > 2147483647 / (nYSize + 1))
    1544             :     {
    1545           0 :         CPLDebug("BMP", "Dimensions of BMP file exceed maximum supported by "
    1546             :                         "Windows Photo Viewer");
    1547             :     }
    1548             : 
    1549          23 :     const vsi_l_offset nLargeImageSize =
    1550          23 :         static_cast<vsi_l_offset>(nScanSize) * poDS->sInfoHeader.iHeight;
    1551          23 :     poDS->m_nFileSize = poDS->sFileHeader.iOffBits + nLargeImageSize;
    1552          23 :     if (nLargeImageSize > std::numeric_limits<uint32_t>::max())
    1553             :     {
    1554           0 :         CPLError(CE_Warning, CPLE_AppDefined,
    1555             :                  "Image too big for its size to fit in a 32 bit integer! "
    1556             :                  "Writing 0xFFFFFFFF in it, but that could cause compatibility "
    1557             :                  "problems with other readers.");
    1558           0 :         poDS->sFileHeader.iSize = std::numeric_limits<uint32_t>::max();
    1559           0 :         poDS->sInfoHeader.iSizeImage = std::numeric_limits<uint32_t>::max();
    1560             :     }
    1561          23 :     else if (poDS->m_nFileSize > std::numeric_limits<uint32_t>::max())
    1562             :     {
    1563           0 :         CPLError(CE_Warning, CPLE_AppDefined,
    1564             :                  "File too big for its size to fit in a 32 bit integer! "
    1565             :                  "Writing 0xFFFFFFFF in it, but that could cause compatibility "
    1566             :                  "problems with other readers.");
    1567           0 :         poDS->sFileHeader.iSize = std::numeric_limits<uint32_t>::max();
    1568           0 :         poDS->sInfoHeader.iSizeImage = static_cast<uint32_t>(nLargeImageSize);
    1569             :     }
    1570             :     else
    1571             :     {
    1572          23 :         poDS->sFileHeader.iSize = static_cast<uint32_t>(poDS->m_nFileSize);
    1573          23 :         poDS->sInfoHeader.iSizeImage = static_cast<uint32_t>(nLargeImageSize);
    1574             :     }
    1575             : 
    1576          23 :     poDS->sFileHeader.bType[0] = 'B';
    1577          23 :     poDS->sFileHeader.bType[1] = 'M';
    1578          23 :     poDS->sFileHeader.iReserved1 = 0;
    1579          23 :     poDS->sFileHeader.iReserved2 = 0;
    1580             : 
    1581             :     /* -------------------------------------------------------------------- */
    1582             :     /*      Write all structures to the file                                */
    1583             :     /* -------------------------------------------------------------------- */
    1584          23 :     if (VSIFWriteL(&poDS->sFileHeader.bType, 1, 2, poDS->fp) != 2)
    1585             :     {
    1586           1 :         CPLError(CE_Failure, CPLE_FileIO,
    1587             :                  "Write of first 2 bytes to BMP file %s failed.\n"
    1588             :                  "Is file system full?",
    1589             :                  pszFilename);
    1590           1 :         delete poDS;
    1591             : 
    1592           1 :         return nullptr;
    1593             :     }
    1594             : 
    1595             :     GInt32 iLong;
    1596             :     GUInt32 iULong;
    1597             :     GUInt16 iUShort;
    1598             : 
    1599          22 :     iULong = CPL_LSBWORD32(poDS->sFileHeader.iSize);
    1600          22 :     VSIFWriteL(&iULong, 4, 1, poDS->fp);
    1601          22 :     iUShort = CPL_LSBWORD16(poDS->sFileHeader.iReserved1);
    1602          22 :     VSIFWriteL(&iUShort, 2, 1, poDS->fp);
    1603          22 :     iUShort = CPL_LSBWORD16(poDS->sFileHeader.iReserved2);
    1604          22 :     VSIFWriteL(&iUShort, 2, 1, poDS->fp);
    1605          22 :     iULong = CPL_LSBWORD32(poDS->sFileHeader.iOffBits);
    1606          22 :     VSIFWriteL(&iULong, 4, 1, poDS->fp);
    1607             : 
    1608          22 :     iULong = CPL_LSBWORD32(poDS->sInfoHeader.iSize);
    1609          22 :     VSIFWriteL(&iULong, 4, 1, poDS->fp);
    1610          22 :     iLong = CPL_LSBWORD32(poDS->sInfoHeader.iWidth);
    1611          22 :     VSIFWriteL(&iLong, 4, 1, poDS->fp);
    1612          22 :     iLong = CPL_LSBWORD32(poDS->sInfoHeader.iHeight);
    1613          22 :     VSIFWriteL(&iLong, 4, 1, poDS->fp);
    1614          22 :     iUShort = CPL_LSBWORD16(poDS->sInfoHeader.iPlanes);
    1615          22 :     VSIFWriteL(&iUShort, 2, 1, poDS->fp);
    1616          22 :     iUShort = CPL_LSBWORD16(poDS->sInfoHeader.iBitCount);
    1617          22 :     VSIFWriteL(&iUShort, 2, 1, poDS->fp);
    1618          22 :     iULong = CPL_LSBWORD32(poDS->sInfoHeader.iCompression);
    1619          22 :     VSIFWriteL(&iULong, 4, 1, poDS->fp);
    1620          22 :     iULong = CPL_LSBWORD32(poDS->sInfoHeader.iSizeImage);
    1621          22 :     VSIFWriteL(&iULong, 4, 1, poDS->fp);
    1622          22 :     iLong = CPL_LSBWORD32(poDS->sInfoHeader.iXPelsPerMeter);
    1623          22 :     VSIFWriteL(&iLong, 4, 1, poDS->fp);
    1624          22 :     iLong = CPL_LSBWORD32(poDS->sInfoHeader.iYPelsPerMeter);
    1625          22 :     VSIFWriteL(&iLong, 4, 1, poDS->fp);
    1626          22 :     iULong = CPL_LSBWORD32(poDS->sInfoHeader.iClrUsed);
    1627          22 :     VSIFWriteL(&iULong, 4, 1, poDS->fp);
    1628          22 :     iULong = CPL_LSBWORD32(poDS->sInfoHeader.iClrImportant);
    1629          22 :     VSIFWriteL(&iULong, 4, 1, poDS->fp);
    1630             : 
    1631          22 :     if (poDS->sInfoHeader.iClrUsed)
    1632             :     {
    1633          40 :         if (VSIFWriteL(poDS->pabyColorTable, 1,
    1634          20 :                        static_cast<size_t>(poDS->nColorElems) *
    1635          20 :                            poDS->sInfoHeader.iClrUsed,
    1636          20 :                        poDS->fp) !=
    1637          20 :             static_cast<size_t>(poDS->nColorElems) * poDS->sInfoHeader.iClrUsed)
    1638             :         {
    1639           8 :             CPLError(CE_Failure, CPLE_FileIO,
    1640             :                      "Error writing color table.  Is disk full?");
    1641           8 :             delete poDS;
    1642             : 
    1643           8 :             return nullptr;
    1644             :         }
    1645             :     }
    1646             : 
    1647          14 :     poDS->nRasterXSize = nXSize;
    1648          14 :     poDS->nRasterYSize = nYSize;
    1649          14 :     poDS->eAccess = GA_Update;
    1650          14 :     poDS->nBands = nBandsIn;
    1651             : 
    1652             :     /* -------------------------------------------------------------------- */
    1653             :     /*      Create band information objects.                                */
    1654             :     /* -------------------------------------------------------------------- */
    1655          32 :     for (int iBand = 1; iBand <= poDS->nBands; iBand++)
    1656             :     {
    1657          18 :         poDS->SetBand(iBand, new BMPRasterBand(poDS, iBand));
    1658             :     }
    1659             : 
    1660             :     /* -------------------------------------------------------------------- */
    1661             :     /*      Do we need a world file?                                        */
    1662             :     /* -------------------------------------------------------------------- */
    1663          14 :     if (CPLFetchBool(papszOptions, "WORLDFILE", false))
    1664           0 :         poDS->bGeoTransformValid = TRUE;
    1665             : 
    1666          14 :     return (GDALDataset *)poDS;
    1667             : }
    1668             : 
    1669             : /************************************************************************/
    1670             : /*                        GDALRegister_BMP()                            */
    1671             : /************************************************************************/
    1672             : 
    1673        1520 : void GDALRegister_BMP()
    1674             : 
    1675             : {
    1676        1520 :     if (GDALGetDriverByName("BMP") != nullptr)
    1677         301 :         return;
    1678             : 
    1679        1219 :     GDALDriver *poDriver = new GDALDriver();
    1680             : 
    1681        1219 :     poDriver->SetDescription("BMP");
    1682        1219 :     poDriver->SetMetadataItem(GDAL_DCAP_RASTER, "YES");
    1683        1219 :     poDriver->SetMetadataItem(GDAL_DMD_LONGNAME,
    1684        1219 :                               "MS Windows Device Independent Bitmap");
    1685        1219 :     poDriver->SetMetadataItem(GDAL_DMD_HELPTOPIC, "drivers/raster/bmp.html");
    1686        1219 :     poDriver->SetMetadataItem(GDAL_DMD_EXTENSION, "bmp");
    1687        1219 :     poDriver->SetMetadataItem(GDAL_DMD_CREATIONDATATYPES, "Byte");
    1688        1219 :     poDriver->SetMetadataItem(GDAL_DMD_CREATIONOPTIONLIST,
    1689             :                               "<CreationOptionList>"
    1690             :                               "   <Option name='WORLDFILE' type='boolean' "
    1691             :                               "description='Write out world file'/>"
    1692        1219 :                               "</CreationOptionList>");
    1693             : 
    1694        1219 :     poDriver->SetMetadataItem(GDAL_DCAP_VIRTUALIO, "YES");
    1695             : 
    1696        1219 :     poDriver->pfnOpen = BMPDataset::Open;
    1697        1219 :     poDriver->pfnCreate = BMPDataset::Create;
    1698        1219 :     poDriver->pfnIdentify = BMPDataset::Identify;
    1699             : 
    1700        1219 :     GetGDALDriverManager()->RegisterDriver(poDriver);
    1701             : }

Generated by: LCOV version 1.14