LCOV - code coverage report
Current view: directory - frmts/bmp - bmpdataset.cpp (source / functions) Found Hit Coverage
Test: gdal_filtered.info Lines: 524 358 68.3 %
Date: 2010-01-09 Functions: 24 22 91.7 %

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

Generated by: LCOV version 1.7