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