1 /******************************************************************************
2  *
3  * Project:  GDAL Core
4  * Purpose:  Base class for format specific band class implementation.  This
5  *           base class provides default implementation for many methods.
6  * Author:   Frank Warmerdam, warmerdam@pobox.com
7  *
8  ******************************************************************************
9  * Copyright (c) 1998, Frank Warmerdam
10  * Copyright (c) 2007-2016, Even Rouault <even dot rouault at spatialys dot 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_port.h"
32 #include "gdal_priv.h"
33 
34 #include <climits>
35 #include <cmath>
36 #include <cstdarg>
37 #include <cstddef>
38 #include <cstdio>
39 #include <cstdlib>
40 #include <cstring>
41 #include <algorithm>
42 #include <limits>
43 #include <memory>
44 #include <new>
45 
46 #include "cpl_conv.h"
47 #include "cpl_error.h"
48 #include "cpl_progress.h"
49 #include "cpl_string.h"
50 #include "cpl_virtualmem.h"
51 #include "cpl_vsi.h"
52 #include "gdal.h"
53 #include "gdal_rat.h"
54 #include "gdal_priv_templates.hpp"
55 
56 CPL_CVSID("$Id: gdalrasterband.cpp 0daa4251466091d6d8acbd64a17dec0fe27d6b34 2021-08-04 12:01:30 +0200 Even Rouault $")
57 
58 /************************************************************************/
59 /*                           GDALRasterBand()                           */
60 /************************************************************************/
61 
62 /*! Constructor. Applications should never create GDALRasterBands directly. */
63 
GDALRasterBand()64 GDALRasterBand::GDALRasterBand() :
65     GDALRasterBand(CPLTestBool( CPLGetConfigOption( "GDAL_FORCE_CACHING", "NO") ) )
66 {
67 }
68 
69 /** Constructor. Applications should never create GDALRasterBands directly.
70  * @param bForceCachedIOIn Whether cached IO should be forced.
71  */
GDALRasterBand(int bForceCachedIOIn)72 GDALRasterBand::GDALRasterBand(int bForceCachedIOIn):
73     bForceCachedIO(bForceCachedIOIn)
74 
75 {
76 }
77 
78 /************************************************************************/
79 /*                          ~GDALRasterBand()                           */
80 /************************************************************************/
81 
82 /*! Destructor. Applications should never destroy GDALRasterBands directly,
83     instead destroy the GDALDataset. */
84 
~GDALRasterBand()85 GDALRasterBand::~GDALRasterBand()
86 
87 {
88     GDALRasterBand::FlushCache();
89 
90     delete poBandBlockCache;
91 
92     if( static_cast<GIntBig>(nBlockReads) > static_cast<GIntBig>(nBlocksPerRow) * nBlocksPerColumn
93         && nBand == 1 && poDS != nullptr )
94     {
95         CPLDebug( "GDAL", "%d block reads on %d block band 1 of %s.",
96                   nBlockReads, nBlocksPerRow * nBlocksPerColumn,
97                   poDS->GetDescription() );
98     }
99 
100     InvalidateMaskBand();
101     nBand = -nBand;
102 }
103 
104 /************************************************************************/
105 /*                              RasterIO()                              */
106 /************************************************************************/
107 
108 /**
109  * \fn GDALRasterBand::IRasterIO( GDALRWFlag eRWFlag,
110  *                                int nXOff, int nYOff, int nXSize, int nYSize,
111  *                                void * pData, int nBufXSize, int nBufYSize,
112  *                                GDALDataType eBufType,
113  *                                GSpacing nPixelSpace,
114  *                                GSpacing nLineSpace,
115  *                                GDALRasterIOExtraArg* psExtraArg )
116  * \brief Read/write a region of image data for this band.
117  *
118  * This method allows reading a region of a GDALRasterBand into a buffer,
119  * or writing data from a buffer into a region of a GDALRasterBand. It
120  * automatically takes care of data type translation if the data type
121  * (eBufType) of the buffer is different than that of the GDALRasterBand.
122  * The method also takes care of image decimation / replication if the
123  * buffer size (nBufXSize x nBufYSize) is different than the size of the
124  * region being accessed (nXSize x nYSize).
125  *
126  * The nPixelSpace and nLineSpace parameters allow reading into or
127  * writing from unusually organized buffers. This is primarily used
128  * for buffers containing more than one bands raster data in interleaved
129  * format.
130  *
131  * Some formats may efficiently implement decimation into a buffer by
132  * reading from lower resolution overview images.
133  *
134  * For highest performance full resolution data access, read and write
135  * on "block boundaries" as returned by GetBlockSize(), or use the
136  * ReadBlock() and WriteBlock() methods.
137  *
138  * This method is the same as the C GDALRasterIO() or GDALRasterIOEx() functions.
139  *
140  * @param eRWFlag Either GF_Read to read a region of data, or GF_Write to
141  * write a region of data.
142  *
143  * @param nXOff The pixel offset to the top left corner of the region
144  * of the band to be accessed. This would be zero to start from the left side.
145  *
146  * @param nYOff The line offset to the top left corner of the region
147  * of the band to be accessed. This would be zero to start from the top.
148  *
149  * @param nXSize The width of the region of the band to be accessed in pixels.
150  *
151  * @param nYSize The height of the region of the band to be accessed in lines.
152  *
153  * @param pData The buffer into which the data should be read, or from which
154  * it should be written. This buffer must contain at least nBufXSize *
155  * nBufYSize words of type eBufType. It is organized in left to right,
156  * top to bottom pixel order. Spacing is controlled by the nPixelSpace,
157  * and nLineSpace parameters.
158  *
159  * @param nBufXSize the width of the buffer image into which the desired region is
160  * to be read, or from which it is to be written.
161  *
162  * @param nBufYSize the height of the buffer image into which the desired region is
163  * to be read, or from which it is to be written.
164  *
165  * @param eBufType the type of the pixel values in the pData data buffer. The
166  * pixel values will automatically be translated to/from the GDALRasterBand
167  * data type as needed.
168  *
169  * @param nPixelSpace The byte offset from the start of one pixel value in
170  * pData to the start of the next pixel value within a scanline. If defaulted
171  * (0) the size of the datatype eBufType is used.
172  *
173  * @param nLineSpace The byte offset from the start of one scanline in
174  * pData to the start of the next. If defaulted (0) the size of the datatype
175  * eBufType * nBufXSize is used.
176  *
177  * @param psExtraArg (new in GDAL 2.0) pointer to a GDALRasterIOExtraArg structure with additional
178  * arguments to specify resampling and progress callback, or NULL for default
179  * behavior. The GDAL_RASTERIO_RESAMPLING configuration option can also be defined
180  * to override the default resampling to one of BILINEAR, CUBIC, CUBICSPLINE,
181  * LANCZOS, AVERAGE or MODE.
182  *
183  * @return CE_Failure if the access fails, otherwise CE_None.
184  */
185 
186 /**
187  * \brief Read/write a region of image data for this band.
188  *
189  * This method allows reading a region of a GDALRasterBand into a buffer,
190  * or writing data from a buffer into a region of a GDALRasterBand. It
191  * automatically takes care of data type translation if the data type
192  * (eBufType) of the buffer is different than that of the GDALRasterBand.
193  * The method also takes care of image decimation / replication if the
194  * buffer size (nBufXSize x nBufYSize) is different than the size of the
195  * region being accessed (nXSize x nYSize).
196  *
197  * The nPixelSpace and nLineSpace parameters allow reading into or
198  * writing from unusually organized buffers. This is primarily used
199  * for buffers containing more than one bands raster data in interleaved
200  * format.
201  *
202  * Some formats may efficiently implement decimation into a buffer by
203  * reading from lower resolution overview images.
204  *
205  * For highest performance full resolution data access, read and write
206  * on "block boundaries" as returned by GetBlockSize(), or use the
207  * ReadBlock() and WriteBlock() methods.
208  *
209  * This method is the same as the C GDALRasterIO() or GDALRasterIOEx() functions.
210  *
211  * @param eRWFlag Either GF_Read to read a region of data, or GF_Write to
212  * write a region of data.
213  *
214  * @param nXOff The pixel offset to the top left corner of the region
215  * of the band to be accessed. This would be zero to start from the left side.
216  *
217  * @param nYOff The line offset to the top left corner of the region
218  * of the band to be accessed. This would be zero to start from the top.
219  *
220  * @param nXSize The width of the region of the band to be accessed in pixels.
221  *
222  * @param nYSize The height of the region of the band to be accessed in lines.
223  *
224  * @param[in,out] pData The buffer into which the data should be read, or from which
225  * it should be written. This buffer must contain at least nBufXSize *
226  * nBufYSize words of type eBufType. It is organized in left to right,
227  * top to bottom pixel order. Spacing is controlled by the nPixelSpace,
228  * and nLineSpace parameters.
229  *
230  * @param nBufXSize the width of the buffer image into which the desired region is
231  * to be read, or from which it is to be written.
232  *
233  * @param nBufYSize the height of the buffer image into which the desired region is
234  * to be read, or from which it is to be written.
235  *
236  * @param eBufType the type of the pixel values in the pData data buffer. The
237  * pixel values will automatically be translated to/from the GDALRasterBand
238  * data type as needed.
239  *
240  * @param nPixelSpace The byte offset from the start of one pixel value in
241  * pData to the start of the next pixel value within a scanline. If defaulted
242  * (0) the size of the datatype eBufType is used.
243  *
244  * @param nLineSpace The byte offset from the start of one scanline in
245  * pData to the start of the next. If defaulted (0) the size of the datatype
246  * eBufType * nBufXSize is used.
247  *
248  * @param[in] psExtraArg (new in GDAL 2.0) pointer to a GDALRasterIOExtraArg structure with additional
249  * arguments to specify resampling and progress callback, or NULL for default
250  * behavior. The GDAL_RASTERIO_RESAMPLING configuration option can also be defined
251  * to override the default resampling to one of BILINEAR, CUBIC, CUBICSPLINE,
252  * LANCZOS, AVERAGE or MODE.
253  *
254  * @return CE_Failure if the access fails, otherwise CE_None.
255  */
256 
RasterIO(GDALRWFlag eRWFlag,int nXOff,int nYOff,int nXSize,int nYSize,void * pData,int nBufXSize,int nBufYSize,GDALDataType eBufType,GSpacing nPixelSpace,GSpacing nLineSpace,GDALRasterIOExtraArg * psExtraArg)257 CPLErr GDALRasterBand::RasterIO( GDALRWFlag eRWFlag,
258                                  int nXOff, int nYOff, int nXSize, int nYSize,
259                                  void * pData, int nBufXSize, int nBufYSize,
260                                  GDALDataType eBufType,
261                                  GSpacing nPixelSpace,
262                                  GSpacing nLineSpace,
263                                  GDALRasterIOExtraArg* psExtraArg )
264 
265 {
266     GDALRasterIOExtraArg sExtraArg;
267     if( psExtraArg == nullptr )
268     {
269         INIT_RASTERIO_EXTRA_ARG(sExtraArg);
270         psExtraArg = &sExtraArg;
271     }
272     else if( psExtraArg->nVersion != RASTERIO_EXTRA_ARG_CURRENT_VERSION )
273     {
274         ReportError( CE_Failure, CPLE_AppDefined,
275                      "Unhandled version of GDALRasterIOExtraArg" );
276         return CE_Failure;
277     }
278 
279     GDALRasterIOExtraArgSetResampleAlg(psExtraArg, nXSize, nYSize,
280                                        nBufXSize, nBufYSize);
281 
282     if( nullptr == pData )
283     {
284         ReportError( CE_Failure, CPLE_AppDefined,
285                   "The buffer into which the data should be read is null" );
286         return CE_Failure;
287     }
288 
289 /* -------------------------------------------------------------------- */
290 /*      Some size values are "noop".  Lets just return to avoid         */
291 /*      stressing lower level functions.                                */
292 /* -------------------------------------------------------------------- */
293     if( nXSize < 1 || nYSize < 1 || nBufXSize < 1 || nBufYSize < 1 )
294     {
295         CPLDebug( "GDAL",
296                   "RasterIO() skipped for odd window or buffer size.\n"
297                   "  Window = (%d,%d)x%dx%d\n"
298                   "  Buffer = %dx%d\n",
299                   nXOff, nYOff, nXSize, nYSize,
300                   nBufXSize, nBufYSize );
301 
302         return CE_None;
303     }
304 
305     if( eRWFlag == GF_Write )
306     {
307         if( eFlushBlockErr != CE_None )
308         {
309             ReportError(eFlushBlockErr, CPLE_AppDefined,
310                         "An error occurred while writing a dirty block "
311                         "from GDALRasterBand::RasterIO");
312             CPLErr eErr = eFlushBlockErr;
313             eFlushBlockErr = CE_None;
314             return eErr;
315         }
316         if( eAccess != GA_Update )
317         {
318             ReportError( CE_Failure, CPLE_AppDefined,
319                         "Write operation not permitted on dataset opened "
320                         "in read-only mode" );
321             return CE_Failure;
322         }
323     }
324 
325 /* -------------------------------------------------------------------- */
326 /*      If pixel and line spacing are defaulted assign reasonable      */
327 /*      value assuming a packed buffer.                                 */
328 /* -------------------------------------------------------------------- */
329     if( nPixelSpace == 0 )
330     {
331         nPixelSpace = GDALGetDataTypeSizeBytes( eBufType );
332     }
333 
334     if( nLineSpace == 0 )
335     {
336         nLineSpace = nPixelSpace * nBufXSize;
337     }
338 
339 /* -------------------------------------------------------------------- */
340 /*      Do some validation of parameters.                               */
341 /* -------------------------------------------------------------------- */
342     if( nXOff < 0 || nXOff > INT_MAX - nXSize || nXOff + nXSize > nRasterXSize
343         || nYOff < 0 || nYOff > INT_MAX - nYSize || nYOff + nYSize > nRasterYSize )
344     {
345         ReportError( CE_Failure, CPLE_IllegalArg,
346                   "Access window out of range in RasterIO().  Requested\n"
347                   "(%d,%d) of size %dx%d on raster of %dx%d.",
348                   nXOff, nYOff, nXSize, nYSize, nRasterXSize, nRasterYSize );
349         return CE_Failure;
350     }
351 
352     if( eRWFlag != GF_Read && eRWFlag != GF_Write )
353     {
354         ReportError( CE_Failure, CPLE_IllegalArg,
355                   "eRWFlag = %d, only GF_Read (0) and GF_Write (1) are legal.",
356                   eRWFlag );
357         return CE_Failure;
358     }
359 
360 /* -------------------------------------------------------------------- */
361 /*      Call the format specific function.                              */
362 /* -------------------------------------------------------------------- */
363 
364     const bool bCallLeaveReadWrite = CPL_TO_BOOL(EnterReadWrite(eRWFlag));
365 
366     CPLErr eErr;
367     if( bForceCachedIO )
368         eErr = GDALRasterBand::IRasterIO(eRWFlag, nXOff, nYOff, nXSize, nYSize,
369                                          pData, nBufXSize, nBufYSize, eBufType,
370                                          nPixelSpace, nLineSpace, psExtraArg );
371     else
372         eErr = IRasterIO( eRWFlag, nXOff, nYOff, nXSize, nYSize,
373                           pData, nBufXSize, nBufYSize, eBufType,
374                           nPixelSpace, nLineSpace, psExtraArg ) ;
375 
376     if( bCallLeaveReadWrite) LeaveReadWrite();
377 
378     return eErr;
379 }
380 
381 /************************************************************************/
382 /*                            GDALRasterIO()                            */
383 /************************************************************************/
384 
385 /**
386  * \brief Read/write a region of image data for this band.
387  *
388  * Use GDALRasterIOEx() if 64 bit spacings or extra arguments (resampling
389  * resolution, progress callback, etc. are needed)
390  *
391  * @see GDALRasterBand::RasterIO()
392  */
393 
394 CPLErr CPL_STDCALL
GDALRasterIO(GDALRasterBandH hBand,GDALRWFlag eRWFlag,int nXOff,int nYOff,int nXSize,int nYSize,void * pData,int nBufXSize,int nBufYSize,GDALDataType eBufType,int nPixelSpace,int nLineSpace)395 GDALRasterIO( GDALRasterBandH hBand, GDALRWFlag eRWFlag,
396               int nXOff, int nYOff, int nXSize, int nYSize,
397               void * pData, int nBufXSize, int nBufYSize,
398               GDALDataType eBufType,
399               int nPixelSpace, int nLineSpace )
400 
401 {
402     VALIDATE_POINTER1( hBand, "GDALRasterIO", CE_Failure );
403 
404     GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
405 
406     return( poBand->RasterIO( eRWFlag, nXOff, nYOff, nXSize, nYSize,
407                               pData, nBufXSize, nBufYSize, eBufType,
408                               nPixelSpace, nLineSpace, nullptr) );
409 }
410 
411 /************************************************************************/
412 /*                            GDALRasterIOEx()                          */
413 /************************************************************************/
414 
415 /**
416  * \brief Read/write a region of image data for this band.
417  *
418  * @see GDALRasterBand::RasterIO()
419  * @since GDAL 2.0
420  */
421 
422 CPLErr CPL_STDCALL
GDALRasterIOEx(GDALRasterBandH hBand,GDALRWFlag eRWFlag,int nXOff,int nYOff,int nXSize,int nYSize,void * pData,int nBufXSize,int nBufYSize,GDALDataType eBufType,GSpacing nPixelSpace,GSpacing nLineSpace,GDALRasterIOExtraArg * psExtraArg)423 GDALRasterIOEx( GDALRasterBandH hBand, GDALRWFlag eRWFlag,
424               int nXOff, int nYOff, int nXSize, int nYSize,
425               void * pData, int nBufXSize, int nBufYSize,
426               GDALDataType eBufType,
427               GSpacing nPixelSpace, GSpacing nLineSpace,
428               GDALRasterIOExtraArg* psExtraArg )
429 
430 {
431     VALIDATE_POINTER1( hBand, "GDALRasterIOEx", CE_Failure );
432 
433     GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
434 
435     return( poBand->RasterIO( eRWFlag, nXOff, nYOff, nXSize, nYSize,
436                               pData, nBufXSize, nBufYSize, eBufType,
437                               nPixelSpace, nLineSpace, psExtraArg) );
438 }
439 /************************************************************************/
440 /*                             ReadBlock()                              */
441 /************************************************************************/
442 
443 /**
444  * \brief Read a block of image data efficiently.
445  *
446  * This method accesses a "natural" block from the raster band without
447  * resampling, or data type conversion.  For a more generalized, but
448  * potentially less efficient access use RasterIO().
449  *
450  * This method is the same as the C GDALReadBlock() function.
451  *
452  * See the GetLockedBlockRef() method for a way of accessing internally cached
453  * block oriented data without an extra copy into an application buffer.
454  *
455  * The following code would efficiently compute a histogram of eight bit
456  * raster data.  Note that the final block may be partial ... data beyond
457  * the edge of the underlying raster band in these edge blocks is of an
458  * undetermined value.
459  *
460 \code{.cpp}
461  CPLErr GetHistogram( GDALRasterBand *poBand, GUIntBig *panHistogram )
462 
463  {
464      memset( panHistogram, 0, sizeof(GUIntBig) * 256 );
465 
466      CPLAssert( poBand->GetRasterDataType() == GDT_Byte );
467 
468      int nXBlockSize, nYBlockSize;
469 
470      poBand->GetBlockSize( &nXBlockSize, &nYBlockSize );
471      int nXBlocks = (poBand->GetXSize() + nXBlockSize - 1) / nXBlockSize;
472      int nYBlocks = (poBand->GetYSize() + nYBlockSize - 1) / nYBlockSize;
473 
474      GByte *pabyData = (GByte *) CPLMalloc(nXBlockSize * nYBlockSize);
475 
476      for( int iYBlock = 0; iYBlock < nYBlocks; iYBlock++ )
477      {
478          for( int iXBlock = 0; iXBlock < nXBlocks; iXBlock++ )
479          {
480              int        nXValid, nYValid;
481 
482              poBand->ReadBlock( iXBlock, iYBlock, pabyData );
483 
484              // Compute the portion of the block that is valid
485              // for partial edge blocks.
486              poBand->GetActualBlockSize(iXBlock, iYBlock, &nXValid, &nYValid)
487 
488              // Collect the histogram counts.
489              for( int iY = 0; iY < nYValid; iY++ )
490              {
491                  for( int iX = 0; iX < nXValid; iX++ )
492                  {
493                      panHistogram[pabyData[iX + iY * nXBlockSize]] += 1;
494                  }
495              }
496          }
497      }
498  }
499 \endcode
500  *
501  * @param nXBlockOff the horizontal block offset, with zero indicating
502  * the left most block, 1 the next block and so forth.
503  *
504  * @param nYBlockOff the vertical block offset, with zero indicating
505  * the top most block, 1 the next block and so forth.
506  *
507  * @param pImage the buffer into which the data will be read.  The buffer
508  * must be large enough to hold GetBlockXSize()*GetBlockYSize() words
509  * of type GetRasterDataType().
510  *
511  * @return CE_None on success or CE_Failure on an error.
512  */
513 
ReadBlock(int nXBlockOff,int nYBlockOff,void * pImage)514 CPLErr GDALRasterBand::ReadBlock( int nXBlockOff, int nYBlockOff,
515                                    void * pImage )
516 
517 {
518 /* -------------------------------------------------------------------- */
519 /*      Validate arguments.                                             */
520 /* -------------------------------------------------------------------- */
521     CPLAssert( pImage != nullptr );
522 
523     if( !InitBlockInfo() )
524         return CE_Failure;
525 
526     if( nXBlockOff < 0 || nXBlockOff >= nBlocksPerRow )
527     {
528         ReportError( CE_Failure, CPLE_IllegalArg,
529                   "Illegal nXBlockOff value (%d) in "
530                         "GDALRasterBand::ReadBlock()\n",
531                   nXBlockOff );
532 
533         return( CE_Failure );
534     }
535 
536     if( nYBlockOff < 0 || nYBlockOff >= nBlocksPerColumn )
537     {
538         ReportError( CE_Failure, CPLE_IllegalArg,
539                   "Illegal nYBlockOff value (%d) in "
540                         "GDALRasterBand::ReadBlock()\n",
541                   nYBlockOff );
542 
543         return( CE_Failure );
544     }
545 
546 /* -------------------------------------------------------------------- */
547 /*      Invoke underlying implementation method.                        */
548 /* -------------------------------------------------------------------- */
549 
550     int bCallLeaveReadWrite = EnterReadWrite(GF_Read);
551     CPLErr eErr = IReadBlock( nXBlockOff, nYBlockOff, pImage );
552     if( bCallLeaveReadWrite) LeaveReadWrite();
553     return eErr;
554 }
555 
556 /************************************************************************/
557 /*                           GDALReadBlock()                            */
558 /************************************************************************/
559 
560 /**
561  * \brief Read a block of image data efficiently.
562  *
563  * @see GDALRasterBand::ReadBlock()
564  */
565 
GDALReadBlock(GDALRasterBandH hBand,int nXOff,int nYOff,void * pData)566 CPLErr CPL_STDCALL GDALReadBlock( GDALRasterBandH hBand, int nXOff, int nYOff,
567                       void * pData )
568 
569 {
570     VALIDATE_POINTER1( hBand, "GDALReadBlock", CE_Failure );
571 
572     GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
573     return( poBand->ReadBlock( nXOff, nYOff, pData ) );
574 }
575 
576 /************************************************************************/
577 /*                            IReadBlock()                             */
578 /************************************************************************/
579 
580 /** \fn GDALRasterBand::IReadBlock( int nBlockXOff, int nBlockYOff, void *pData )
581  * \brief Read a block of data.
582  *
583  * Default internal implementation ... to be overridden by
584  * subclasses that support reading.
585  * @param nBlockXOff Block X Offset
586  * @param nBlockYOff Block Y Offset
587  * @param pData Pixel buffer into which to place read data.
588  * @return CE_None on success or CE_Failure on an error.
589  */
590 
591 /************************************************************************/
592 /*                            IWriteBlock()                             */
593 /************************************************************************/
594 
595 /**
596  * \fn GDALRasterBand::IWriteBlock(int, int, void*)
597  * Write a block of data.
598  *
599  * Default internal implementation ... to be overridden by
600  * subclasses that support writing.
601  * @param nBlockXOff Block X Offset
602  * @param nBlockYOff Block Y Offset
603  * @param pData Pixel buffer to write
604  * @return CE_None on success or CE_Failure on an error.
605  */
606 
607 /**/
608 /**/
609 
IWriteBlock(int,int,void *)610 CPLErr GDALRasterBand::IWriteBlock( int /*nBlockXOff*/,
611                                     int /*nBlockYOff*/,
612                                     void * /*pData*/ )
613 
614 {
615     if( !(GetMOFlags() & GMO_IGNORE_UNIMPLEMENTED) )
616         ReportError( CE_Failure, CPLE_NotSupported,
617                   "WriteBlock() not supported for this dataset." );
618 
619     return( CE_Failure );
620 }
621 
622 /************************************************************************/
623 /*                             WriteBlock()                             */
624 /************************************************************************/
625 
626 /**
627  * \brief Write a block of image data efficiently.
628  *
629  * This method accesses a "natural" block from the raster band without
630  * resampling, or data type conversion.  For a more generalized, but
631  * potentially less efficient access use RasterIO().
632  *
633  * This method is the same as the C GDALWriteBlock() function.
634  *
635  * See ReadBlock() for an example of block oriented data access.
636  *
637  * @param nXBlockOff the horizontal block offset, with zero indicating
638  * the left most block, 1 the next block and so forth.
639  *
640  * @param nYBlockOff the vertical block offset, with zero indicating
641  * the left most block, 1 the next block and so forth.
642  *
643  * @param pImage the buffer from which the data will be written.  The buffer
644  * must be large enough to hold GetBlockXSize()*GetBlockYSize() words
645  * of type GetRasterDataType().
646  *
647  * @return CE_None on success or CE_Failure on an error.
648  */
649 
WriteBlock(int nXBlockOff,int nYBlockOff,void * pImage)650 CPLErr GDALRasterBand::WriteBlock( int nXBlockOff, int nYBlockOff,
651                                    void * pImage )
652 
653 {
654 /* -------------------------------------------------------------------- */
655 /*      Validate arguments.                                             */
656 /* -------------------------------------------------------------------- */
657     CPLAssert( pImage != nullptr );
658 
659     if( !InitBlockInfo() )
660         return CE_Failure;
661 
662     if( nXBlockOff < 0 || nXBlockOff >= nBlocksPerRow )
663     {
664         ReportError( CE_Failure, CPLE_IllegalArg,
665                   "Illegal nXBlockOff value (%d) in "
666                         "GDALRasterBand::WriteBlock()\n",
667                   nXBlockOff );
668 
669         return( CE_Failure );
670     }
671 
672     if( nYBlockOff < 0 || nYBlockOff >= nBlocksPerColumn )
673     {
674         ReportError( CE_Failure, CPLE_IllegalArg,
675                   "Illegal nYBlockOff value (%d) in "
676                         "GDALRasterBand::WriteBlock()\n",
677                   nYBlockOff );
678 
679         return( CE_Failure );
680     }
681 
682     if( eAccess == GA_ReadOnly )
683     {
684         ReportError( CE_Failure, CPLE_NoWriteAccess,
685                   "Attempt to write to read only dataset in"
686                   "GDALRasterBand::WriteBlock().\n" );
687 
688         return( CE_Failure );
689     }
690 
691     if( eFlushBlockErr != CE_None )
692     {
693         ReportError(eFlushBlockErr, CPLE_AppDefined,
694                     "An error occurred while writing a dirty block "
695                     "from GDALRasterBand::WriteBlock");
696         CPLErr eErr = eFlushBlockErr;
697         eFlushBlockErr = CE_None;
698         return eErr;
699     }
700 
701 /* -------------------------------------------------------------------- */
702 /*      Invoke underlying implementation method.                        */
703 /* -------------------------------------------------------------------- */
704 
705     const bool bCallLeaveReadWrite = CPL_TO_BOOL(EnterReadWrite(GF_Write));
706     CPLErr eErr = IWriteBlock( nXBlockOff, nYBlockOff, pImage );
707     if( bCallLeaveReadWrite ) LeaveReadWrite();
708 
709     return eErr;
710 }
711 
712 /************************************************************************/
713 /*                           GDALWriteBlock()                           */
714 /************************************************************************/
715 
716 /**
717  * \brief Write a block of image data efficiently.
718  *
719  * @see GDALRasterBand::WriteBlock()
720  */
721 
GDALWriteBlock(GDALRasterBandH hBand,int nXOff,int nYOff,void * pData)722 CPLErr CPL_STDCALL GDALWriteBlock( GDALRasterBandH hBand, int nXOff, int nYOff,
723                        void * pData )
724 
725 {
726     VALIDATE_POINTER1( hBand, "GDALWriteBlock", CE_Failure );
727 
728     GDALRasterBand *poBand = GDALRasterBand::FromHandle( hBand );
729     return( poBand->WriteBlock( nXOff, nYOff, pData ) );
730 }
731 
732 /************************************************************************/
733 /*                         GetActualBlockSize()                         */
734 /************************************************************************/
735 /**
736 * \brief Fetch the actual block size for a given block offset.
737 *
738 * Handles partial blocks at the edges of the raster and returns the true
739 * number of pixels
740 *
741 * @param nXBlockOff the horizontal block offset for which to calculate the number of
742 * valid pixels, with zero indicating the left most block, 1 the next block and so forth.
743 *
744 * @param nYBlockOff the vertical block offset, with zero indicating
745 * the left most block, 1 the next block and so forth.
746 *
747 * @param pnXValid pointer to an integer in which the number of valid pixels in the x
748 * direction will be stored
749 *
750 * @param pnYValid pointer to an integer in which the number of valid pixels in the y
751 * direction will be stored
752 *
753 * @return CE_None if the input parameter are valid, CE_Failure otherwise
754 *
755 * @since GDAL 2.2
756 */
GetActualBlockSize(int nXBlockOff,int nYBlockOff,int * pnXValid,int * pnYValid)757 CPLErr GDALRasterBand::GetActualBlockSize(int nXBlockOff, int nYBlockOff,
758                                           int *pnXValid, int *pnYValid)
759 {
760     if( nXBlockOff < 0 || nBlockXSize == 0 ||
761         nXBlockOff >= nRasterXSize / nBlockXSize + ((nRasterXSize % nBlockXSize) ? 1 : 0) ||
762         nYBlockOff < 0 || nBlockYSize == 0 ||
763         nYBlockOff >= nRasterYSize / nBlockYSize + ((nRasterYSize % nBlockYSize) ? 1 : 0) )
764     {
765         return CE_Failure;
766     }
767 
768     int nXPixelOff = nXBlockOff * nBlockXSize;
769     int nYPixelOff = nYBlockOff * nBlockYSize;
770 
771     *pnXValid = nBlockXSize;
772     *pnYValid = nBlockYSize;
773 
774     if( nXPixelOff + nBlockXSize >= nRasterXSize)
775     {
776         *pnXValid = nRasterXSize - nXPixelOff;
777     }
778 
779     if( nYPixelOff + nBlockYSize >= nRasterYSize)
780     {
781         *pnYValid = nRasterYSize - nYPixelOff;
782     }
783 
784     return CE_None;
785 }
786 
787 /************************************************************************/
788 /*                           GDALGetActualBlockSize()                   */
789 /************************************************************************/
790 
791 /**
792  * \brief Retrieve the actual block size for a given block offset.
793  *
794  * @see GDALRasterBand::GetActualBlockSize()
795  */
796 
GDALGetActualBlockSize(GDALRasterBandH hBand,int nXBlockOff,int nYBlockOff,int * pnXValid,int * pnYValid)797 CPLErr CPL_STDCALL GDALGetActualBlockSize( GDALRasterBandH hBand,
798                                            int nXBlockOff,
799                                            int nYBlockOff,
800                                            int *pnXValid,
801                                            int *pnYValid )
802 
803 {
804     VALIDATE_POINTER1( hBand, "GDALGetActualBlockSize", CE_Failure );
805 
806     GDALRasterBand *poBand = GDALRasterBand::FromHandle( hBand );
807     return( poBand->GetActualBlockSize( nXBlockOff, nYBlockOff, pnXValid, pnYValid ) );
808 }
809 
810 /************************************************************************/
811 /*                         GetRasterDataType()                          */
812 /************************************************************************/
813 
814 /**
815  * \brief Fetch the pixel data type for this band.
816  *
817  * This method is the same as the C function GDALGetRasterDataType().
818  *
819  * @return the data type of pixels for this band.
820  */
821 
GetRasterDataType()822 GDALDataType GDALRasterBand::GetRasterDataType()
823 
824 {
825     return eDataType;
826 }
827 
828 /************************************************************************/
829 /*                       GDALGetRasterDataType()                        */
830 /************************************************************************/
831 
832 /**
833  * \brief Fetch the pixel data type for this band.
834  *
835  * @see GDALRasterBand::GetRasterDataType()
836  */
837 
GDALGetRasterDataType(GDALRasterBandH hBand)838 GDALDataType CPL_STDCALL GDALGetRasterDataType( GDALRasterBandH hBand )
839 
840 {
841     VALIDATE_POINTER1( hBand, "GDALGetRasterDataType", GDT_Unknown );
842 
843     GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
844     return poBand->GetRasterDataType();
845 }
846 
847 /************************************************************************/
848 /*                            GetBlockSize()                            */
849 /************************************************************************/
850 
851 /**
852  * \brief Fetch the "natural" block size of this band.
853  *
854  * GDAL contains a concept of the natural block size of rasters so that
855  * applications can organized data access efficiently for some file formats.
856  * The natural block size is the block size that is most efficient for
857  * accessing the format.  For many formats this is simple a whole scanline
858  * in which case *pnXSize is set to GetXSize(), and *pnYSize is set to 1.
859  *
860  * However, for tiled images this will typically be the tile size.
861  *
862  * Note that the X and Y block sizes don't have to divide the image size
863  * evenly, meaning that right and bottom edge blocks may be incomplete.
864  * See ReadBlock() for an example of code dealing with these issues.
865  *
866  * This method is the same as the C function GDALGetBlockSize().
867  *
868  * @param pnXSize integer to put the X block size into or NULL.
869  *
870  * @param pnYSize integer to put the Y block size into or NULL.
871  */
872 
GetBlockSize(int * pnXSize,int * pnYSize)873 void GDALRasterBand::GetBlockSize( int * pnXSize, int *pnYSize )
874 
875 {
876     if( nBlockXSize <= 0 || nBlockYSize <= 0 )
877     {
878         ReportError( CE_Failure, CPLE_AppDefined, "Invalid block dimension : %d * %d",
879                  nBlockXSize, nBlockYSize );
880         if( pnXSize != nullptr )
881             *pnXSize = 0;
882         if( pnYSize != nullptr )
883             *pnYSize = 0;
884     }
885     else
886     {
887         if( pnXSize != nullptr )
888             *pnXSize = nBlockXSize;
889         if( pnYSize != nullptr )
890             *pnYSize = nBlockYSize;
891     }
892 }
893 
894 /************************************************************************/
895 /*                          GDALGetBlockSize()                          */
896 /************************************************************************/
897 
898 /**
899  * \brief Fetch the "natural" block size of this band.
900  *
901  * @see GDALRasterBand::GetBlockSize()
902  */
903 
904 void CPL_STDCALL
GDALGetBlockSize(GDALRasterBandH hBand,int * pnXSize,int * pnYSize)905 GDALGetBlockSize( GDALRasterBandH hBand, int * pnXSize, int * pnYSize )
906 
907 {
908     VALIDATE_POINTER0( hBand, "GDALGetBlockSize" );
909 
910     GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
911     poBand->GetBlockSize( pnXSize, pnYSize );
912 }
913 
914 /************************************************************************/
915 /*                           InitBlockInfo()                            */
916 /************************************************************************/
917 
918 //! @cond Doxygen_Suppress
InitBlockInfo()919 int GDALRasterBand::InitBlockInfo()
920 
921 {
922     if( poBandBlockCache != nullptr )
923         return poBandBlockCache->IsInitOK();
924 
925     /* Do some validation of raster and block dimensions in case the driver */
926     /* would have neglected to do it itself */
927     if( nBlockXSize <= 0 || nBlockYSize <= 0 )
928     {
929         ReportError( CE_Failure, CPLE_AppDefined, "Invalid block dimension : %d * %d",
930                   nBlockXSize, nBlockYSize );
931         return FALSE;
932     }
933 
934     if( nRasterXSize <= 0 || nRasterYSize <= 0 )
935     {
936         ReportError( CE_Failure, CPLE_AppDefined, "Invalid raster dimension : %d * %d",
937                   nRasterXSize, nRasterYSize );
938         return FALSE;
939     }
940 
941     const int nDataTypeSize = GDALGetDataTypeSizeBytes(eDataType);
942     if( nDataTypeSize == 0 )
943     {
944         ReportError( CE_Failure, CPLE_AppDefined, "Invalid data type" );
945         return FALSE;
946     }
947 
948 #if SIZEOF_VOIDP == 4
949     if (nBlockXSize >= 10000 || nBlockYSize >= 10000)
950     {
951         /* As 10000 * 10000 * 16 < INT_MAX, we don't need to do the multiplication in other cases */
952         if( nBlockXSize > INT_MAX / nDataTypeSize ||
953             nBlockYSize > INT_MAX / (nDataTypeSize * nBlockXSize) )
954         {
955             ReportError( CE_Failure, CPLE_NotSupported, "Too big block : %d * %d for 32-bit build",
956                         nBlockXSize, nBlockYSize );
957             return FALSE;
958         }
959     }
960 #endif
961 
962     nBlocksPerRow = DIV_ROUND_UP(nRasterXSize, nBlockXSize);
963     nBlocksPerColumn = DIV_ROUND_UP(nRasterYSize, nBlockYSize);
964 
965     const char* pszBlockStrategy = CPLGetConfigOption("GDAL_BAND_BLOCK_CACHE", nullptr);
966     bool bUseArray = true;
967     if( pszBlockStrategy == nullptr )
968     {
969         if( poDS == nullptr ||
970             (poDS->nOpenFlags & GDAL_OF_BLOCK_ACCESS_MASK) ==
971                                             GDAL_OF_DEFAULT_BLOCK_ACCESS )
972         {
973             GUIntBig nBlockCount = static_cast<GIntBig>(nBlocksPerRow) * nBlocksPerColumn;
974             if( poDS != nullptr )
975                 nBlockCount *= poDS->GetRasterCount();
976             bUseArray = ( nBlockCount  < 1024 * 1024  );
977         }
978         else if( (poDS->nOpenFlags & GDAL_OF_BLOCK_ACCESS_MASK) ==
979                                             GDAL_OF_HASHSET_BLOCK_ACCESS )
980         {
981             bUseArray = false;
982         }
983     }
984     else if( EQUAL(pszBlockStrategy, "HASHSET") )
985         bUseArray = false;
986     if( bUseArray )
987         poBandBlockCache = GDALArrayBandBlockCacheCreate(this);
988     else
989     {
990         if( nBand == 1)
991             CPLDebug("GDAL", "Use hashset band block cache");
992         poBandBlockCache = GDALHashSetBandBlockCacheCreate(this);
993     }
994     if( poBandBlockCache == nullptr )
995         return FALSE;
996     return poBandBlockCache->Init();
997 }
998 //! @endcond
999 
1000 /************************************************************************/
1001 /*                             FlushCache()                             */
1002 /************************************************************************/
1003 
1004 /**
1005  * \brief Flush raster data cache.
1006  *
1007  * This call will recover memory used to cache data blocks for this raster
1008  * band, and ensure that new requests are referred to the underlying driver.
1009  *
1010  * This method is the same as the C function GDALFlushRasterCache().
1011  *
1012  * @return CE_None on success.
1013  */
1014 
FlushCache()1015 CPLErr GDALRasterBand::FlushCache()
1016 
1017 {
1018     CPLErr eGlobalErr = eFlushBlockErr;
1019 
1020     if (eFlushBlockErr != CE_None)
1021     {
1022         ReportError(
1023             eFlushBlockErr, CPLE_AppDefined,
1024             "An error occurred while writing a dirty block from FlushCache");
1025         eFlushBlockErr = CE_None;
1026     }
1027 
1028     if (poBandBlockCache == nullptr || !poBandBlockCache->IsInitOK())
1029         return eGlobalErr;
1030 
1031     return poBandBlockCache->FlushCache();
1032 }
1033 
1034 /************************************************************************/
1035 /*                        GDALFlushRasterCache()                        */
1036 /************************************************************************/
1037 
1038 /**
1039  * \brief Flush raster data cache.
1040  *
1041  * @see GDALRasterBand::FlushCache()
1042  */
1043 
GDALFlushRasterCache(GDALRasterBandH hBand)1044 CPLErr CPL_STDCALL GDALFlushRasterCache( GDALRasterBandH hBand )
1045 
1046 {
1047     VALIDATE_POINTER1( hBand, "GDALFlushRasterCache", CE_Failure );
1048 
1049     return GDALRasterBand::FromHandle(hBand)->FlushCache();
1050 }
1051 
1052 /************************************************************************/
1053 /*                        UnreferenceBlock()                            */
1054 /*                                                                      */
1055 /*      Unreference the block from our array of blocks                  */
1056 /*      This method should only be called by                            */
1057 /*      GDALRasterBlock::Internalize() and FlushCacheBlock() (and under */
1058 /*      the block cache mutex)                                          */
1059 /************************************************************************/
1060 
UnreferenceBlock(GDALRasterBlock * poBlock)1061 CPLErr GDALRasterBand::UnreferenceBlock( GDALRasterBlock* poBlock )
1062 {
1063 #ifdef notdef
1064     if( poBandBlockCache == nullptr || !poBandBlockCache->IsInitOK() )
1065     {
1066         if( poBandBlockCache == nullptr )
1067             printf("poBandBlockCache == NULL\n");/*ok*/
1068         else
1069             printf("!poBandBlockCache->IsInitOK()\n");/*ok*/
1070         printf("caller = %s\n", pszCaller);/*ok*/
1071         printf("GDALRasterBand: %p\n", this);/*ok*/
1072         printf("GDALRasterBand: nBand=%d\n", nBand);/*ok*/
1073         printf("nRasterXSize = %d\n", nRasterXSize);/*ok*/
1074         printf("nRasterYSize = %d\n", nRasterYSize);/*ok*/
1075         printf("nBlockXSize = %d\n", nBlockXSize);/*ok*/
1076         printf("nBlockYSize = %d\n", nBlockYSize);/*ok*/
1077         poBlock->DumpBlock();
1078         if( GetDataset() != nullptr )
1079             printf("Dataset: %s\n", GetDataset()->GetDescription());/*ok*/
1080         GDALRasterBlock::Verify();
1081         abort();
1082     }
1083 #endif
1084     CPLAssert(poBandBlockCache && poBandBlockCache->IsInitOK());
1085     return poBandBlockCache->UnreferenceBlock( poBlock );
1086 }
1087 
1088 /************************************************************************/
1089 /*                        AddBlockToFreeList()                          */
1090 /*                                                                      */
1091 /*      When GDALRasterBlock::Internalize() or FlushCacheBlock() are    */
1092 /*      finished with a block about to be free'd, they pass it to that  */
1093 /*      method.                                                         */
1094 /************************************************************************/
1095 
1096 //! @cond Doxygen_Suppress
AddBlockToFreeList(GDALRasterBlock * poBlock)1097 void GDALRasterBand::AddBlockToFreeList( GDALRasterBlock * poBlock )
1098 {
1099     CPLAssert(poBandBlockCache && poBandBlockCache->IsInitOK());
1100     return poBandBlockCache->AddBlockToFreeList( poBlock );
1101 }
1102 //! @endcond
1103 
1104 /************************************************************************/
1105 /*                             FlushBlock()                             */
1106 /************************************************************************/
1107 
1108 /** Flush a block out of the block cache.
1109  * @param nXBlockOff block x offset
1110  * @param nYBlockOff blocky offset
1111  * @param bWriteDirtyBlock whether the block should be written to disk if dirty.
1112  * @return CE_None in case of success, an error code otherwise.
1113  */
FlushBlock(int nXBlockOff,int nYBlockOff,int bWriteDirtyBlock)1114 CPLErr GDALRasterBand::FlushBlock( int nXBlockOff, int nYBlockOff,
1115                                    int bWriteDirtyBlock )
1116 
1117 {
1118     if( poBandBlockCache == nullptr || !poBandBlockCache->IsInitOK() )
1119         return( CE_Failure );
1120 
1121 /* -------------------------------------------------------------------- */
1122 /*      Validate the request                                            */
1123 /* -------------------------------------------------------------------- */
1124     if( nXBlockOff < 0 || nXBlockOff >= nBlocksPerRow )
1125     {
1126         ReportError( CE_Failure, CPLE_IllegalArg,
1127                     "Illegal nBlockXOff value (%d) in "
1128                     "GDALRasterBand::FlushBlock()\n",
1129                     nXBlockOff );
1130 
1131         return( CE_Failure );
1132     }
1133 
1134     if( nYBlockOff < 0 || nYBlockOff >= nBlocksPerColumn )
1135     {
1136         ReportError( CE_Failure, CPLE_IllegalArg,
1137                     "Illegal nBlockYOff value (%d) in "
1138                     "GDALRasterBand::FlushBlock()\n",
1139                     nYBlockOff );
1140 
1141         return( CE_Failure );
1142     }
1143 
1144     return poBandBlockCache->FlushBlock( nXBlockOff, nYBlockOff, bWriteDirtyBlock );
1145 }
1146 
1147 /************************************************************************/
1148 /*                        TryGetLockedBlockRef()                        */
1149 /************************************************************************/
1150 
1151 /**
1152  * \brief Try fetching block ref.
1153  *
1154  * This method will returned the requested block (locked) if it is already
1155  * in the block cache for the layer.  If not, nullptr is returned.
1156  *
1157  * If a non-NULL value is returned, then a lock for the block will have been
1158  * acquired on behalf of the caller.  It is absolutely imperative that the
1159  * caller release this lock (with GDALRasterBlock::DropLock()) or else
1160  * severe problems may result.
1161  *
1162  * @param nXBlockOff the horizontal block offset, with zero indicating
1163  * the left most block, 1 the next block and so forth.
1164  *
1165  * @param nYBlockOff the vertical block offset, with zero indicating
1166  * the top most block, 1 the next block and so forth.
1167  *
1168  * @return NULL if block not available, or locked block pointer.
1169  */
1170 
TryGetLockedBlockRef(int nXBlockOff,int nYBlockOff)1171 GDALRasterBlock *GDALRasterBand::TryGetLockedBlockRef( int nXBlockOff,
1172                                                        int nYBlockOff )
1173 
1174 {
1175     if( poBandBlockCache == nullptr || !poBandBlockCache->IsInitOK() )
1176         return nullptr;
1177 
1178 /* -------------------------------------------------------------------- */
1179 /*      Validate the request                                            */
1180 /* -------------------------------------------------------------------- */
1181     if( nXBlockOff < 0 || nXBlockOff >= nBlocksPerRow )
1182     {
1183         ReportError( CE_Failure, CPLE_IllegalArg,
1184                     "Illegal nBlockXOff value (%d) in "
1185                     "GDALRasterBand::TryGetLockedBlockRef()\n",
1186                     nXBlockOff );
1187 
1188         return( nullptr );
1189     }
1190 
1191     if( nYBlockOff < 0 || nYBlockOff >= nBlocksPerColumn )
1192     {
1193         ReportError( CE_Failure, CPLE_IllegalArg,
1194                     "Illegal nBlockYOff value (%d) in "
1195                     "GDALRasterBand::TryGetLockedBlockRef()\n",
1196                     nYBlockOff );
1197 
1198         return( nullptr );
1199     }
1200 
1201     return poBandBlockCache->TryGetLockedBlockRef(nXBlockOff, nYBlockOff);
1202 }
1203 
1204 /************************************************************************/
1205 /*                         GetLockedBlockRef()                          */
1206 /************************************************************************/
1207 
1208 /**
1209  * \brief Fetch a pointer to an internally cached raster block.
1210  *
1211  * This method will returned the requested block (locked) if it is already
1212  * in the block cache for the layer.  If not, the block will be read from
1213  * the driver, and placed in the layer block cached, then returned.  If an
1214  * error occurs reading the block from the driver, a NULL value will be
1215  * returned.
1216  *
1217  * If a non-NULL value is returned, then a lock for the block will have been
1218  * acquired on behalf of the caller.  It is absolutely imperative that the
1219  * caller release this lock (with GDALRasterBlock::DropLock()) or else
1220  * severe problems may result.
1221  *
1222  * Note that calling GetLockedBlockRef() on a previously uncached band will
1223  * enable caching.
1224  *
1225  * @param nXBlockOff the horizontal block offset, with zero indicating
1226  * the left most block, 1 the next block and so forth.
1227  *
1228  * @param nYBlockOff the vertical block offset, with zero indicating
1229  * the top most block, 1 the next block and so forth.
1230  *
1231  * @param bJustInitialize If TRUE the block will be allocated and initialized,
1232  * but not actually read from the source.  This is useful when it will just
1233  * be completely set and written back.
1234  *
1235  * @return pointer to the block object, or NULL on failure.
1236  */
1237 
GetLockedBlockRef(int nXBlockOff,int nYBlockOff,int bJustInitialize)1238 GDALRasterBlock * GDALRasterBand::GetLockedBlockRef( int nXBlockOff,
1239                                                      int nYBlockOff,
1240                                                      int bJustInitialize )
1241 
1242 {
1243 /* -------------------------------------------------------------------- */
1244 /*      Try and fetch from cache.                                       */
1245 /* -------------------------------------------------------------------- */
1246     GDALRasterBlock *poBlock = TryGetLockedBlockRef( nXBlockOff, nYBlockOff );
1247 
1248 /* -------------------------------------------------------------------- */
1249 /*      If we didn't find it in our memory cache, instantiate a         */
1250 /*      block (potentially load from disk) and "adopt" it into the      */
1251 /*      cache.                                                          */
1252 /* -------------------------------------------------------------------- */
1253     if( poBlock == nullptr )
1254     {
1255         if( !InitBlockInfo() )
1256             return( nullptr );
1257 
1258     /* -------------------------------------------------------------------- */
1259     /*      Validate the request                                            */
1260     /* -------------------------------------------------------------------- */
1261         if( nXBlockOff < 0 || nXBlockOff >= nBlocksPerRow )
1262         {
1263             ReportError( CE_Failure, CPLE_IllegalArg,
1264                       "Illegal nBlockXOff value (%d) in "
1265                       "GDALRasterBand::GetLockedBlockRef()\n",
1266                       nXBlockOff );
1267 
1268             return( nullptr );
1269         }
1270 
1271         if( nYBlockOff < 0 || nYBlockOff >= nBlocksPerColumn )
1272         {
1273             ReportError( CE_Failure, CPLE_IllegalArg,
1274                       "Illegal nBlockYOff value (%d) in "
1275                       "GDALRasterBand::GetLockedBlockRef()\n",
1276                       nYBlockOff );
1277 
1278             return( nullptr );
1279         }
1280 
1281         poBlock = poBandBlockCache->CreateBlock( nXBlockOff, nYBlockOff );
1282         if( poBlock == nullptr )
1283             return nullptr;
1284 
1285         poBlock->AddLock();
1286 
1287         /* We need to temporarily drop the read-write lock in the following */
1288         /*scenario. Imagine 2 threads T1 and T2 that respectively write dataset */
1289         /* D1 and D2. T1 will take the mutex on D1 and T2 on D2. Now when the */
1290         /* block cache fills, T1 might need to flush dirty blocks of D2 in the */
1291         /* below Internalize(), which will cause GDALRasterBlock::Write() to be */
1292         /* called and attempt at taking the lock on T2 (already taken). Similarly */
1293         /* for T2 with D1, hence a deadlock situation (#6163) */
1294         /* But this may open the door to other problems... */
1295         if( poDS )
1296             poDS->TemporarilyDropReadWriteLock();
1297         /* allocate data space */
1298         CPLErr eErr = poBlock->Internalize();
1299         if( poDS )
1300             poDS->ReacquireReadWriteLock();
1301         if( eErr != CE_None )
1302         {
1303             poBlock->DropLock();
1304             delete poBlock;
1305             return nullptr;
1306         }
1307 
1308         if ( poBandBlockCache->AdoptBlock(poBlock) != CE_None )
1309         {
1310             poBlock->DropLock();
1311             delete poBlock;
1312             return nullptr;
1313         }
1314 
1315         if( !bJustInitialize )
1316         {
1317             const GUInt32 nErrorCounter = CPLGetErrorCounter();
1318             int bCallLeaveReadWrite = EnterReadWrite(GF_Read);
1319             eErr = IReadBlock(nXBlockOff,nYBlockOff,poBlock->GetDataRef());
1320             if( bCallLeaveReadWrite) LeaveReadWrite();
1321             if( eErr != CE_None )
1322             {
1323                 poBlock->DropLock();
1324                 FlushBlock( nXBlockOff, nYBlockOff );
1325                 ReportError( CE_Failure, CPLE_AppDefined,
1326                     "IReadBlock failed at X offset %d, Y offset %d%s",
1327                     nXBlockOff, nYBlockOff,
1328                     (nErrorCounter != CPLGetErrorCounter()) ?
1329                         CPLSPrintf(": %s", CPLGetLastErrorMsg()) : "");
1330                 return nullptr;
1331             }
1332 
1333             nBlockReads++;
1334             if( static_cast<GIntBig>(nBlockReads) ==
1335                 static_cast<GIntBig>(nBlocksPerRow) * nBlocksPerColumn + 1
1336                 && nBand == 1 && poDS != nullptr )
1337             {
1338                 CPLDebug( "GDAL", "Potential thrashing on band %d of %s.",
1339                           nBand, poDS->GetDescription() );
1340             }
1341         }
1342     }
1343 
1344     return poBlock;
1345 }
1346 
1347 /************************************************************************/
1348 /*                               Fill()                                 */
1349 /************************************************************************/
1350 
1351 /**
1352  * \brief Fill this band with a constant value.
1353  *
1354  * GDAL makes no guarantees
1355  * about what values pixels in newly created files are set to, so this
1356  * method can be used to clear a band to a specified "default" value.
1357  * The fill value is passed in as a double but this will be converted
1358  * to the underlying type before writing to the file. An optional
1359  * second argument allows the imaginary component of a complex
1360  * constant value to be specified.
1361  *
1362  * This method is the same as the C function GDALFillRaster().
1363  *
1364  * @param dfRealValue Real component of fill value
1365  * @param dfImaginaryValue Imaginary component of fill value, defaults to zero
1366  *
1367  * @return CE_Failure if the write fails, otherwise CE_None
1368  */
Fill(double dfRealValue,double dfImaginaryValue)1369 CPLErr GDALRasterBand::Fill( double dfRealValue, double dfImaginaryValue ) {
1370 
1371     // General approach is to construct a source block of the file's
1372     // native type containing the appropriate value and then copy this
1373     // to each block in the image via the RasterBlock cache. Using
1374     // the cache means we avoid file I/O if it is not necessary, at the
1375     // expense of some extra memcpy's (since we write to the
1376     // RasterBlock cache, which is then at some point written to the
1377     // underlying file, rather than simply directly to the underlying
1378     // file.)
1379 
1380     // Check we can write to the file.
1381     if( eAccess == GA_ReadOnly ) {
1382         ReportError( CE_Failure, CPLE_NoWriteAccess,
1383                      "Attempt to write to read only dataset in "
1384                      "GDALRasterBand::Fill()." );
1385         return CE_Failure;
1386     }
1387 
1388     // Make sure block parameters are set.
1389     if( !InitBlockInfo() )
1390         return CE_Failure;
1391 
1392     // Allocate the source block.
1393     auto blockSize = static_cast<GPtrDiff_t>(nBlockXSize) * nBlockYSize;
1394     int elementSize = GDALGetDataTypeSizeBytes(eDataType);
1395     auto blockByteSize = blockSize * elementSize;
1396     unsigned char* srcBlock =
1397         static_cast<unsigned char*>( VSIMalloc(blockByteSize) );
1398     if (srcBlock == nullptr) {
1399         ReportError( CE_Failure, CPLE_OutOfMemory,
1400                      "GDALRasterBand::Fill(): Out of memory "
1401                      "allocating " CPL_FRMT_GUIB " bytes.\n",
1402                      static_cast<GUIntBig>(blockByteSize) );
1403         return CE_Failure;
1404     }
1405 
1406     // Initialize the source block.
1407     double complexSrc[2] = { dfRealValue, dfImaginaryValue };
1408     GDALCopyWords64(complexSrc, GDT_CFloat64, 0,
1409                   srcBlock, eDataType, elementSize, blockSize);
1410 
1411     const bool bCallLeaveReadWrite = CPL_TO_BOOL(EnterReadWrite(GF_Write));
1412 
1413     // Write block to block cache
1414     for (int j = 0; j < nBlocksPerColumn; ++j) {
1415         for (int i = 0; i < nBlocksPerRow; ++i) {
1416             GDALRasterBlock* destBlock = GetLockedBlockRef(i, j, TRUE);
1417             if (destBlock == nullptr)
1418             {
1419                 ReportError( CE_Failure, CPLE_OutOfMemory,
1420                              "GDALRasterBand::Fill(): Error "
1421                              "while retrieving cache block.");
1422                 VSIFree(srcBlock);
1423                 return CE_Failure;
1424             }
1425             memcpy(destBlock->GetDataRef(), srcBlock, blockByteSize);
1426             destBlock->MarkDirty();
1427             destBlock->DropLock();
1428         }
1429     }
1430 
1431     if( bCallLeaveReadWrite ) LeaveReadWrite();
1432 
1433     // Free up the source block
1434     VSIFree(srcBlock);
1435 
1436     return CE_None;
1437 }
1438 
1439 /************************************************************************/
1440 /*                         GDALFillRaster()                             */
1441 /************************************************************************/
1442 
1443 /**
1444  * \brief Fill this band with a constant value.
1445  *
1446  * @see GDALRasterBand::Fill()
1447  */
GDALFillRaster(GDALRasterBandH hBand,double dfRealValue,double dfImaginaryValue)1448 CPLErr CPL_STDCALL GDALFillRaster(
1449     GDALRasterBandH hBand, double dfRealValue, double dfImaginaryValue )
1450 {
1451     VALIDATE_POINTER1( hBand, "GDALFillRaster", CE_Failure );
1452 
1453     GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
1454     return poBand->Fill(dfRealValue, dfImaginaryValue);
1455 }
1456 
1457 /************************************************************************/
1458 /*                             GetAccess()                              */
1459 /************************************************************************/
1460 
1461 /**
1462  * \brief Find out if we have update permission for this band.
1463  *
1464  * This method is the same as the C function GDALGetRasterAccess().
1465  *
1466  * @return Either GA_Update or GA_ReadOnly.
1467  */
1468 
GetAccess()1469 GDALAccess GDALRasterBand::GetAccess()
1470 
1471 {
1472     return eAccess;
1473 }
1474 
1475 /************************************************************************/
1476 /*                        GDALGetRasterAccess()                         */
1477 /************************************************************************/
1478 
1479 /**
1480  * \brief Find out if we have update permission for this band.
1481  *
1482  * @see GDALRasterBand::GetAccess()
1483  */
1484 
GDALGetRasterAccess(GDALRasterBandH hBand)1485 GDALAccess CPL_STDCALL GDALGetRasterAccess( GDALRasterBandH hBand )
1486 
1487 {
1488     VALIDATE_POINTER1( hBand, "GDALGetRasterAccess", GA_ReadOnly );
1489 
1490     GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
1491     return poBand->GetAccess();
1492 }
1493 
1494 /************************************************************************/
1495 /*                          GetCategoryNames()                          */
1496 /************************************************************************/
1497 
1498 /**
1499  * \brief Fetch the list of category names for this raster.
1500  *
1501  * The return list is a "StringList" in the sense of the CPL functions.
1502  * That is a NULL terminated array of strings.  Raster values without
1503  * associated names will have an empty string in the returned list.  The
1504  * first entry in the list is for raster values of zero, and so on.
1505  *
1506  * The returned stringlist should not be altered or freed by the application.
1507  * It may change on the next GDAL call, so please copy it if it is needed
1508  * for any period of time.
1509  *
1510  * This method is the same as the C function GDALGetRasterCategoryNames().
1511  *
1512  * @return list of names, or NULL if none.
1513  */
1514 
GetCategoryNames()1515 char **GDALRasterBand::GetCategoryNames()
1516 
1517 {
1518     return nullptr;
1519 }
1520 
1521 /************************************************************************/
1522 /*                     GDALGetRasterCategoryNames()                     */
1523 /************************************************************************/
1524 
1525 /**
1526  * \brief Fetch the list of category names for this raster.
1527  *
1528  * @see GDALRasterBand::GetCategoryNames()
1529  */
1530 
GDALGetRasterCategoryNames(GDALRasterBandH hBand)1531 char ** CPL_STDCALL GDALGetRasterCategoryNames( GDALRasterBandH hBand )
1532 
1533 {
1534     VALIDATE_POINTER1( hBand, "GDALGetRasterCategoryNames", nullptr );
1535 
1536     GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
1537     return poBand->GetCategoryNames();
1538 }
1539 
1540 /************************************************************************/
1541 /*                          SetCategoryNames()                          */
1542 /************************************************************************/
1543 
1544 /**
1545  * \fn GDALRasterBand::SetCategoryNames(char**)
1546  * \brief Set the category names for this band.
1547  *
1548  * See the GetCategoryNames() method for more on the interpretation of
1549  * category names.
1550  *
1551  * This method is the same as the C function GDALSetRasterCategoryNames().
1552  *
1553  * @param papszNames the NULL terminated StringList of category names.  May
1554  * be NULL to just clear the existing list.
1555  *
1556  * @return CE_None on success of CE_Failure on failure.  If unsupported
1557  * by the driver CE_Failure is returned, but no error message is reported.
1558  */
1559 
1560 /**/
1561 /**/
1562 
SetCategoryNames(char **)1563 CPLErr GDALRasterBand::SetCategoryNames( char ** /*papszNames*/ )
1564 {
1565     if( !(GetMOFlags() & GMO_IGNORE_UNIMPLEMENTED) )
1566         ReportError( CE_Failure, CPLE_NotSupported,
1567                      "SetCategoryNames() not supported for this dataset." );
1568 
1569     return CE_Failure;
1570 }
1571 
1572 /************************************************************************/
1573 /*                        GDALSetCategoryNames()                        */
1574 /************************************************************************/
1575 
1576 /**
1577  * \brief Set the category names for this band.
1578  *
1579  * @see GDALRasterBand::SetCategoryNames()
1580  */
1581 
1582 CPLErr CPL_STDCALL
GDALSetRasterCategoryNames(GDALRasterBandH hBand,CSLConstList papszNames)1583 GDALSetRasterCategoryNames( GDALRasterBandH hBand, CSLConstList papszNames )
1584 
1585 {
1586     VALIDATE_POINTER1( hBand, "GDALSetRasterCategoryNames", CE_Failure );
1587 
1588     GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
1589     return poBand->SetCategoryNames( const_cast<char**>(papszNames) );
1590 }
1591 
1592 /************************************************************************/
1593 /*                           GetNoDataValue()                           */
1594 /************************************************************************/
1595 
1596 /**
1597  * \brief Fetch the no data value for this band.
1598  *
1599  * If there is no out of data value, an out of range value will generally
1600  * be returned.  The no data value for a band is generally a special marker
1601  * value used to mark pixels that are not valid data.  Such pixels should
1602  * generally not be displayed, nor contribute to analysis operations.
1603  *
1604  * The no data value returned is 'raw', meaning that it has no offset and
1605  * scale applied.
1606  *
1607  * This method is the same as the C function GDALGetRasterNoDataValue().
1608  *
1609  * @param pbSuccess pointer to a boolean to use to indicate if a value
1610  * is actually associated with this layer.  May be NULL (default).
1611  *
1612  * @return the nodata value for this band.
1613  */
1614 
GetNoDataValue(int * pbSuccess)1615 double GDALRasterBand::GetNoDataValue( int *pbSuccess )
1616 
1617 {
1618     if( pbSuccess != nullptr )
1619         *pbSuccess = FALSE;
1620 
1621     return -1e10;
1622 }
1623 
1624 /************************************************************************/
1625 /*                      GDALGetRasterNoDataValue()                      */
1626 /************************************************************************/
1627 
1628 /**
1629  * \brief Fetch the no data value for this band.
1630  *
1631  * @see GDALRasterBand::GetNoDataValue()
1632  */
1633 
1634 double CPL_STDCALL
GDALGetRasterNoDataValue(GDALRasterBandH hBand,int * pbSuccess)1635 GDALGetRasterNoDataValue( GDALRasterBandH hBand, int *pbSuccess )
1636 
1637 {
1638     VALIDATE_POINTER1( hBand, "GDALGetRasterNoDataValue", 0 );
1639 
1640     GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
1641     return poBand->GetNoDataValue( pbSuccess );
1642 }
1643 
1644 /************************************************************************/
1645 /*                           SetNoDataValue()                           */
1646 /************************************************************************/
1647 
1648 /**
1649  * \fn GDALRasterBand::SetNoDataValue(double)
1650  * \brief Set the no data value for this band.
1651  *
1652  * Depending on drivers, changing the no data value may or may not have an
1653  * effect on the pixel values of a raster that has just been created. It is
1654  * thus advised to explicitly called Fill() if the intent is to initialize
1655  * the raster to the nodata value.
1656  * In ay case, changing an existing no data value, when one already exists and
1657  * the dataset exists or has been initialized, has no effect on the pixel whose
1658  * value matched the previous nodata value.
1659  *
1660  * To clear the nodata value, use DeleteNoDataValue().
1661  *
1662  * This method is the same as the C function GDALSetRasterNoDataValue().
1663  *
1664  * @param dfNoData the value to set.
1665  *
1666  * @return CE_None on success, or CE_Failure on failure.  If unsupported
1667  * by the driver, CE_Failure is returned by no error message will have
1668  * been emitted.
1669  */
1670 
1671 /**/
1672 /**/
1673 
SetNoDataValue(double)1674 CPLErr GDALRasterBand::SetNoDataValue( double /*dfNoData*/ )
1675 
1676 {
1677     if( !(GetMOFlags() & GMO_IGNORE_UNIMPLEMENTED) )
1678         ReportError( CE_Failure, CPLE_NotSupported,
1679                      "SetNoDataValue() not supported for this dataset." );
1680 
1681     return CE_Failure;
1682 }
1683 
1684 /************************************************************************/
1685 /*                         GDALSetRasterNoDataValue()                   */
1686 /************************************************************************/
1687 
1688 /**
1689  * \brief Set the no data value for this band.
1690  *
1691  * Depending on drivers, changing the no data value may or may not have an
1692  * effect on the pixel values of a raster that has just been created. It is
1693  * thus advised to explicitly called Fill() if the intent is to initialize
1694  * the raster to the nodata value.
1695  * In ay case, changing an existing no data value, when one already exists and
1696  * the dataset exists or has been initialized, has no effect on the pixel whose
1697  * value matched the previous nodata value.
1698  *
1699  * @see GDALRasterBand::SetNoDataValue()
1700  */
1701 
1702 CPLErr CPL_STDCALL
GDALSetRasterNoDataValue(GDALRasterBandH hBand,double dfValue)1703 GDALSetRasterNoDataValue( GDALRasterBandH hBand, double dfValue )
1704 
1705 {
1706     VALIDATE_POINTER1( hBand, "GDALSetRasterNoDataValue", CE_Failure );
1707 
1708     GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
1709     return poBand->SetNoDataValue( dfValue );
1710 }
1711 
1712 /************************************************************************/
1713 /*                        DeleteNoDataValue()                           */
1714 /************************************************************************/
1715 
1716 /**
1717  * \brief Remove the no data value for this band.
1718  *
1719  * This method is the same as the C function GDALDeleteRasterNoDataValue().
1720  *
1721  * @return CE_None on success, or CE_Failure on failure.  If unsupported
1722  * by the driver, CE_Failure is returned by no error message will have
1723  * been emitted.
1724  *
1725  * @since GDAL 2.1
1726  */
1727 
DeleteNoDataValue()1728 CPLErr GDALRasterBand::DeleteNoDataValue()
1729 
1730 {
1731     if( !(GetMOFlags() & GMO_IGNORE_UNIMPLEMENTED) )
1732         ReportError( CE_Failure, CPLE_NotSupported,
1733                      "DeleteNoDataValue() not supported for this dataset." );
1734 
1735     return CE_Failure;
1736 }
1737 
1738 /************************************************************************/
1739 /*                       GDALDeleteRasterNoDataValue()                  */
1740 /************************************************************************/
1741 
1742 /**
1743  * \brief Remove the no data value for this band.
1744  *
1745  * @see GDALRasterBand::DeleteNoDataValue()
1746  *
1747  * @since GDAL 2.1
1748  */
1749 
1750 CPLErr CPL_STDCALL
GDALDeleteRasterNoDataValue(GDALRasterBandH hBand)1751 GDALDeleteRasterNoDataValue( GDALRasterBandH hBand )
1752 
1753 {
1754     VALIDATE_POINTER1( hBand, "GDALDeleteRasterNoDataValue", CE_Failure );
1755 
1756     GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
1757     return poBand->DeleteNoDataValue();
1758 }
1759 
1760 /************************************************************************/
1761 /*                             GetMaximum()                             */
1762 /************************************************************************/
1763 
1764 /**
1765  * \brief Fetch the maximum value for this band.
1766  *
1767  * For file formats that don't know this intrinsically, the maximum supported
1768  * value for the data type will generally be returned.
1769  *
1770  * This method is the same as the C function GDALGetRasterMaximum().
1771  *
1772  * @param pbSuccess pointer to a boolean to use to indicate if the
1773  * returned value is a tight maximum or not.  May be NULL (default).
1774  *
1775  * @return the maximum raster value (excluding no data pixels)
1776  */
1777 
GetMaximum(int * pbSuccess)1778 double GDALRasterBand::GetMaximum( int *pbSuccess )
1779 
1780 {
1781     const char *pszValue = nullptr;
1782 
1783     if( (pszValue = GetMetadataItem("STATISTICS_MAXIMUM")) != nullptr )
1784     {
1785         if( pbSuccess != nullptr )
1786             *pbSuccess = TRUE;
1787 
1788         return CPLAtofM(pszValue);
1789     }
1790 
1791     if( pbSuccess != nullptr )
1792         *pbSuccess = FALSE;
1793 
1794     switch( eDataType )
1795     {
1796       case GDT_Byte:
1797       {
1798         const char* pszPixelType =
1799             GetMetadataItem("PIXELTYPE", "IMAGE_STRUCTURE");
1800         if (pszPixelType != nullptr && EQUAL(pszPixelType, "SIGNEDBYTE"))
1801             return 127;
1802 
1803         return 255;
1804       }
1805 
1806       case GDT_UInt16:
1807         return 65535;
1808 
1809       case GDT_Int16:
1810       case GDT_CInt16:
1811         return 32767;
1812 
1813       case GDT_Int32:
1814       case GDT_CInt32:
1815         return 2147483647.0;
1816 
1817       case GDT_UInt32:
1818         return 4294967295.0;
1819 
1820       case GDT_Float32:
1821       case GDT_CFloat32:
1822         return 4294967295.0;  // Not actually accurate.
1823 
1824       case GDT_Float64:
1825       case GDT_CFloat64:
1826         return 4294967295.0;  // Not actually accurate.
1827 
1828       default:
1829         return 4294967295.0;  // Not actually accurate.
1830     }
1831 }
1832 
1833 /************************************************************************/
1834 /*                        GDALGetRasterMaximum()                        */
1835 /************************************************************************/
1836 
1837 /**
1838  * \brief Fetch the maximum value for this band.
1839  *
1840  * @see GDALRasterBand::GetMaximum()
1841  */
1842 
1843 double CPL_STDCALL
GDALGetRasterMaximum(GDALRasterBandH hBand,int * pbSuccess)1844 GDALGetRasterMaximum( GDALRasterBandH hBand, int *pbSuccess )
1845 
1846 {
1847     VALIDATE_POINTER1( hBand, "GDALGetRasterMaximum", 0 );
1848 
1849     GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
1850     return poBand->GetMaximum( pbSuccess );
1851 }
1852 
1853 /************************************************************************/
1854 /*                             GetMinimum()                             */
1855 /************************************************************************/
1856 
1857 /**
1858  * \brief Fetch the minimum value for this band.
1859  *
1860  * For file formats that don't know this intrinsically, the minimum supported
1861  * value for the data type will generally be returned.
1862  *
1863  * This method is the same as the C function GDALGetRasterMinimum().
1864  *
1865  * @param pbSuccess pointer to a boolean to use to indicate if the
1866  * returned value is a tight minimum or not.  May be NULL (default).
1867  *
1868  * @return the minimum raster value (excluding no data pixels)
1869  */
1870 
GetMinimum(int * pbSuccess)1871 double GDALRasterBand::GetMinimum( int *pbSuccess )
1872 
1873 {
1874     const char *pszValue = nullptr;
1875 
1876     if( (pszValue = GetMetadataItem("STATISTICS_MINIMUM")) != nullptr )
1877     {
1878         if( pbSuccess != nullptr )
1879             *pbSuccess = TRUE;
1880 
1881         return CPLAtofM(pszValue);
1882     }
1883 
1884     if( pbSuccess != nullptr )
1885         *pbSuccess = FALSE;
1886 
1887     switch( eDataType )
1888     {
1889       case GDT_Byte:
1890       {
1891         const char* pszPixelType =
1892             GetMetadataItem("PIXELTYPE", "IMAGE_STRUCTURE");
1893         if (pszPixelType != nullptr && EQUAL(pszPixelType, "SIGNEDBYTE"))
1894             return -128;
1895 
1896         return 0;
1897       }
1898 
1899       case GDT_UInt16:
1900         return 0;
1901 
1902       case GDT_Int16:
1903         return -32768;
1904 
1905       case GDT_Int32:
1906         return -2147483648.0;
1907 
1908       case GDT_UInt32:
1909         return 0;
1910 
1911       case GDT_Float32:
1912         return -4294967295.0;  // Not actually accurate.
1913 
1914       case GDT_Float64:
1915         return -4294967295.0;  // Not actually accurate.
1916 
1917       default:
1918         return -4294967295.0;  // Not actually accurate.
1919     }
1920 }
1921 
1922 /************************************************************************/
1923 /*                        GDALGetRasterMinimum()                        */
1924 /************************************************************************/
1925 
1926 /**
1927  * \brief Fetch the minimum value for this band.
1928  *
1929  * @see GDALRasterBand::GetMinimum()
1930  */
1931 
1932 double CPL_STDCALL
GDALGetRasterMinimum(GDALRasterBandH hBand,int * pbSuccess)1933 GDALGetRasterMinimum( GDALRasterBandH hBand, int *pbSuccess )
1934 
1935 {
1936     VALIDATE_POINTER1( hBand, "GDALGetRasterMinimum", 0 );
1937 
1938     GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
1939     return poBand->GetMinimum( pbSuccess );
1940 }
1941 
1942 /************************************************************************/
1943 /*                       GetColorInterpretation()                       */
1944 /************************************************************************/
1945 
1946 /**
1947  * \brief How should this band be interpreted as color?
1948  *
1949  * GCI_Undefined is returned when the format doesn't know anything
1950  * about the color interpretation.
1951  *
1952  * This method is the same as the C function
1953  * GDALGetRasterColorInterpretation().
1954  *
1955  * @return color interpretation value for band.
1956  */
1957 
GetColorInterpretation()1958 GDALColorInterp GDALRasterBand::GetColorInterpretation()
1959 
1960 {
1961     return GCI_Undefined;
1962 }
1963 
1964 /************************************************************************/
1965 /*                  GDALGetRasterColorInterpretation()                  */
1966 /************************************************************************/
1967 
1968 /**
1969  * \brief How should this band be interpreted as color?
1970  *
1971  * @see GDALRasterBand::GetColorInterpretation()
1972  */
1973 
1974 GDALColorInterp CPL_STDCALL
GDALGetRasterColorInterpretation(GDALRasterBandH hBand)1975 GDALGetRasterColorInterpretation( GDALRasterBandH hBand )
1976 
1977 {
1978     VALIDATE_POINTER1( hBand, "GDALGetRasterColorInterpretation",
1979                        GCI_Undefined );
1980 
1981     GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
1982     return poBand->GetColorInterpretation();
1983 }
1984 
1985 /************************************************************************/
1986 /*                       SetColorInterpretation()                       */
1987 /************************************************************************/
1988 
1989 /**
1990  * \fn GDALRasterBand::SetColorInterpretation(GDALColorInterp)
1991  * \brief Set color interpretation of a band.
1992  *
1993  * This method is the same as the C function GDALSetRasterColorInterpretation().
1994  *
1995  * @param eColorInterp the new color interpretation to apply to this band.
1996  *
1997  * @return CE_None on success or CE_Failure if method is unsupported by format.
1998  */
1999 
2000 /**/
2001 /**/
2002 
SetColorInterpretation(GDALColorInterp)2003 CPLErr GDALRasterBand::SetColorInterpretation(
2004     GDALColorInterp /*eColorInterp*/ )
2005 
2006 {
2007     if( !(GetMOFlags() & GMO_IGNORE_UNIMPLEMENTED) )
2008         ReportError( CE_Failure, CPLE_NotSupported,
2009                   "SetColorInterpretation() not supported for this dataset." );
2010     return CE_Failure;
2011 }
2012 
2013 /************************************************************************/
2014 /*                  GDALSetRasterColorInterpretation()                  */
2015 /************************************************************************/
2016 
2017 /**
2018  * \brief Set color interpretation of a band.
2019  *
2020  * @see GDALRasterBand::SetColorInterpretation()
2021  */
2022 
2023 CPLErr CPL_STDCALL
GDALSetRasterColorInterpretation(GDALRasterBandH hBand,GDALColorInterp eColorInterp)2024 GDALSetRasterColorInterpretation( GDALRasterBandH hBand,
2025                                   GDALColorInterp eColorInterp )
2026 
2027 {
2028     VALIDATE_POINTER1( hBand, "GDALSetRasterColorInterpretation", CE_Failure );
2029 
2030     GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
2031     return poBand->SetColorInterpretation(eColorInterp);
2032 }
2033 
2034 /************************************************************************/
2035 /*                           GetColorTable()                            */
2036 /************************************************************************/
2037 
2038 /**
2039  * \brief Fetch the color table associated with band.
2040  *
2041  * If there is no associated color table, the return result is NULL.  The
2042  * returned color table remains owned by the GDALRasterBand, and can't
2043  * be depended on for long, nor should it ever be modified by the caller.
2044  *
2045  * This method is the same as the C function GDALGetRasterColorTable().
2046  *
2047  * @return internal color table, or NULL.
2048  */
2049 
GetColorTable()2050 GDALColorTable *GDALRasterBand::GetColorTable()
2051 
2052 {
2053     return nullptr;
2054 }
2055 
2056 /************************************************************************/
2057 /*                      GDALGetRasterColorTable()                       */
2058 /************************************************************************/
2059 
2060 /**
2061  * \brief Fetch the color table associated with band.
2062  *
2063  * @see GDALRasterBand::GetColorTable()
2064  */
2065 
GDALGetRasterColorTable(GDALRasterBandH hBand)2066 GDALColorTableH CPL_STDCALL GDALGetRasterColorTable( GDALRasterBandH hBand )
2067 
2068 {
2069     VALIDATE_POINTER1( hBand, "GDALGetRasterColorTable", nullptr );
2070 
2071     GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
2072     return GDALColorTable::ToHandle(poBand->GetColorTable());
2073 }
2074 
2075 /************************************************************************/
2076 /*                           SetColorTable()                            */
2077 /************************************************************************/
2078 
2079 /**
2080  * \fn GDALRasterBand::SetColorTable(GDALColorTable*)
2081  * \brief Set the raster color table.
2082  *
2083  * The driver will make a copy of all desired data in the colortable.  It
2084  * remains owned by the caller after the call.
2085  *
2086  * This method is the same as the C function GDALSetRasterColorTable().
2087  *
2088  * @param poCT the color table to apply.  This may be NULL to clear the color
2089  * table (where supported).
2090  *
2091  * @return CE_None on success, or CE_Failure on failure.  If the action is
2092  * unsupported by the driver, a value of CE_Failure is returned, but no
2093  * error is issued.
2094  */
2095 
2096 /**/
2097 /**/
2098 
SetColorTable(GDALColorTable *)2099 CPLErr GDALRasterBand::SetColorTable( GDALColorTable * /*poCT*/ )
2100 
2101 {
2102     if( !(GetMOFlags() & GMO_IGNORE_UNIMPLEMENTED) )
2103         ReportError( CE_Failure, CPLE_NotSupported,
2104                   "SetColorTable() not supported for this dataset." );
2105     return CE_Failure;
2106 }
2107 
2108 /************************************************************************/
2109 /*                      GDALSetRasterColorTable()                       */
2110 /************************************************************************/
2111 
2112 /**
2113  * \brief Set the raster color table.
2114  *
2115  * @see GDALRasterBand::SetColorTable()
2116  */
2117 
2118 CPLErr CPL_STDCALL
GDALSetRasterColorTable(GDALRasterBandH hBand,GDALColorTableH hCT)2119 GDALSetRasterColorTable( GDALRasterBandH hBand, GDALColorTableH hCT )
2120 
2121 {
2122     VALIDATE_POINTER1( hBand, "GDALSetRasterColorTable", CE_Failure );
2123 
2124     GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
2125     return poBand->SetColorTable( GDALColorTable::FromHandle(hCT) );
2126 }
2127 
2128 /************************************************************************/
2129 /*                       HasArbitraryOverviews()                        */
2130 /************************************************************************/
2131 
2132 /**
2133  * \brief Check for arbitrary overviews.
2134  *
2135  * This returns TRUE if the underlying datastore can compute arbitrary
2136  * overviews efficiently, such as is the case with OGDI over a network.
2137  * Datastores with arbitrary overviews don't generally have any fixed
2138  * overviews, but the RasterIO() method can be used in downsampling mode
2139  * to get overview data efficiently.
2140  *
2141  * This method is the same as the C function GDALHasArbitraryOverviews(),
2142  *
2143  * @return TRUE if arbitrary overviews available (efficiently), otherwise
2144  * FALSE.
2145  */
2146 
HasArbitraryOverviews()2147 int GDALRasterBand::HasArbitraryOverviews()
2148 
2149 {
2150     return FALSE;
2151 }
2152 
2153 /************************************************************************/
2154 /*                     GDALHasArbitraryOverviews()                      */
2155 /************************************************************************/
2156 
2157 /**
2158  * \brief Check for arbitrary overviews.
2159  *
2160  * @see GDALRasterBand::HasArbitraryOverviews()
2161  */
2162 
GDALHasArbitraryOverviews(GDALRasterBandH hBand)2163 int CPL_STDCALL GDALHasArbitraryOverviews( GDALRasterBandH hBand )
2164 
2165 {
2166     VALIDATE_POINTER1( hBand, "GDALHasArbitraryOverviews", 0 );
2167 
2168     GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
2169     return poBand->HasArbitraryOverviews();
2170 }
2171 
2172 /************************************************************************/
2173 /*                          GetOverviewCount()                          */
2174 /************************************************************************/
2175 
2176 /**
2177  * \brief Return the number of overview layers available.
2178  *
2179  * This method is the same as the C function GDALGetOverviewCount().
2180  *
2181  * @return overview count, zero if none.
2182  */
2183 
GetOverviewCount()2184 int GDALRasterBand::GetOverviewCount()
2185 
2186 {
2187     if( poDS != nullptr && poDS->oOvManager.IsInitialized() && poDS->AreOverviewsEnabled() )
2188         return poDS->oOvManager.GetOverviewCount( nBand );
2189 
2190     return 0;
2191 }
2192 
2193 /************************************************************************/
2194 /*                        GDALGetOverviewCount()                        */
2195 /************************************************************************/
2196 
2197 /**
2198  * \brief Return the number of overview layers available.
2199  *
2200  * @see GDALRasterBand::GetOverviewCount()
2201  */
2202 
GDALGetOverviewCount(GDALRasterBandH hBand)2203 int CPL_STDCALL GDALGetOverviewCount( GDALRasterBandH hBand )
2204 
2205 {
2206     VALIDATE_POINTER1( hBand, "GDALGetOverviewCount", 0 );
2207 
2208     GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
2209     return poBand->GetOverviewCount();
2210 }
2211 
2212 /************************************************************************/
2213 /*                            GetOverview()                             */
2214 /************************************************************************/
2215 
2216 /**
2217  * \brief Fetch overview raster band object.
2218  *
2219  * This method is the same as the C function GDALGetOverview().
2220  *
2221  * @param i overview index between 0 and GetOverviewCount()-1.
2222  *
2223  * @return overview GDALRasterBand.
2224  */
2225 
GetOverview(int i)2226 GDALRasterBand * GDALRasterBand::GetOverview( int i )
2227 
2228 {
2229     if( poDS != nullptr && poDS->oOvManager.IsInitialized() && poDS->AreOverviewsEnabled() )
2230         return poDS->oOvManager.GetOverview( nBand, i );
2231 
2232     return nullptr;
2233 }
2234 
2235 /************************************************************************/
2236 /*                          GDALGetOverview()                           */
2237 /************************************************************************/
2238 
2239 /**
2240  * \brief Fetch overview raster band object.
2241  *
2242  * @see GDALRasterBand::GetOverview()
2243  */
2244 
GDALGetOverview(GDALRasterBandH hBand,int i)2245 GDALRasterBandH CPL_STDCALL GDALGetOverview( GDALRasterBandH hBand, int i )
2246 
2247 {
2248     VALIDATE_POINTER1( hBand, "GDALGetOverview", nullptr );
2249 
2250     GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
2251     return GDALRasterBand::ToHandle(poBand->GetOverview(i));
2252 }
2253 
2254 /************************************************************************/
2255 /*                      GetRasterSampleOverview()                       */
2256 /************************************************************************/
2257 
2258 /**
2259  * \brief Fetch best sampling overview.
2260  *
2261  * Returns the most reduced overview of the given band that still satisfies
2262  * the desired number of samples.  This function can be used with zero
2263  * as the number of desired samples to fetch the most reduced overview.
2264  * The same band as was passed in will be returned if it has not overviews,
2265  * or if none of the overviews have enough samples.
2266  *
2267  * This method is the same as the C functions GDALGetRasterSampleOverview()
2268  * and GDALGetRasterSampleOverviewEx().
2269  *
2270  * @param nDesiredSamples the returned band will have at least this many
2271  * pixels.
2272  *
2273  * @return optimal overview or the band itself.
2274  */
2275 
GetRasterSampleOverview(GUIntBig nDesiredSamples)2276 GDALRasterBand *GDALRasterBand::GetRasterSampleOverview(
2277     GUIntBig nDesiredSamples )
2278 
2279 {
2280     GDALRasterBand *poBestBand = this;
2281 
2282     double dfBestSamples = GetXSize() * static_cast<double>(GetYSize());
2283 
2284     for( int iOverview = 0; iOverview < GetOverviewCount(); iOverview++ )
2285     {
2286         GDALRasterBand  *poOBand = GetOverview( iOverview );
2287 
2288         if (poOBand == nullptr)
2289             continue;
2290 
2291         const double dfOSamples =
2292             poOBand->GetXSize() * static_cast<double>(poOBand->GetYSize());
2293 
2294         if( dfOSamples < dfBestSamples && dfOSamples > nDesiredSamples )
2295         {
2296             dfBestSamples = dfOSamples;
2297             poBestBand = poOBand;
2298         }
2299     }
2300 
2301     return poBestBand;
2302 }
2303 
2304 /************************************************************************/
2305 /*                    GDALGetRasterSampleOverview()                     */
2306 /************************************************************************/
2307 
2308 /**
2309  * \brief Fetch best sampling overview.
2310  *
2311  * Use GDALGetRasterSampleOverviewEx() to be able to specify more than 2
2312  * billion samples.
2313  *
2314  * @see GDALRasterBand::GetRasterSampleOverview()
2315  * @see GDALGetRasterSampleOverviewEx()
2316  */
2317 
2318 GDALRasterBandH CPL_STDCALL
GDALGetRasterSampleOverview(GDALRasterBandH hBand,int nDesiredSamples)2319 GDALGetRasterSampleOverview( GDALRasterBandH hBand, int nDesiredSamples )
2320 
2321 {
2322     VALIDATE_POINTER1( hBand, "GDALGetRasterSampleOverview", nullptr );
2323 
2324     GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
2325     return GDALRasterBand::ToHandle(
2326         poBand->GetRasterSampleOverview(
2327             nDesiredSamples < 0 ? 0 : static_cast<GUIntBig>(nDesiredSamples) ));
2328 }
2329 
2330 /************************************************************************/
2331 /*                    GDALGetRasterSampleOverviewEx()                   */
2332 /************************************************************************/
2333 
2334 /**
2335  * \brief Fetch best sampling overview.
2336  *
2337  * @see GDALRasterBand::GetRasterSampleOverview()
2338  * @since GDAL 2.0
2339  */
2340 
2341 GDALRasterBandH CPL_STDCALL
GDALGetRasterSampleOverviewEx(GDALRasterBandH hBand,GUIntBig nDesiredSamples)2342 GDALGetRasterSampleOverviewEx( GDALRasterBandH hBand, GUIntBig nDesiredSamples )
2343 
2344 {
2345     VALIDATE_POINTER1( hBand, "GDALGetRasterSampleOverviewEx", nullptr );
2346 
2347     GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
2348     return GDALRasterBand::ToHandle(
2349         poBand->GetRasterSampleOverview( nDesiredSamples ));
2350 }
2351 
2352 /************************************************************************/
2353 /*                           BuildOverviews()                           */
2354 /************************************************************************/
2355 
2356 /**
2357  * \fn GDALRasterBand::BuildOverviews(const char*, int, int*, GDALProgressFunc, void*)
2358  * \brief Build raster overview(s)
2359  *
2360  * If the operation is unsupported for the indicated dataset, then
2361  * CE_Failure is returned, and CPLGetLastErrorNo() will return
2362  * CPLE_NotSupported.
2363  *
2364  * WARNING:  It is not possible to build overviews for a single band in
2365  * TIFF format, and thus this method does not work for TIFF format, or any
2366  * formats that use the default overview building in TIFF format.  Instead
2367  * it is necessary to build overviews on the dataset as a whole using
2368  * GDALDataset::BuildOverviews().  That makes this method pretty useless
2369  * from a practical point of view.
2370  *
2371  * @param pszResampling one of "NEAREST", "GAUSS", "CUBIC", "AVERAGE", "MODE",
2372  * "AVERAGE_MAGPHASE" "RMS" or "NONE" controlling the downsampling method applied.
2373  * @param nOverviews number of overviews to build.
2374  * @param panOverviewList the list of overview decimation factors to build.
2375  * @param pfnProgress a function to call to report progress, or NULL.
2376  * @param pProgressData application data to pass to the progress function.
2377  *
2378  * @return CE_None on success or CE_Failure if the operation doesn't work.
2379  */
2380 
2381 /**/
2382 /**/
2383 
BuildOverviews(const char *,int,int *,GDALProgressFunc,void *)2384 CPLErr GDALRasterBand::BuildOverviews( const char* /*pszResampling*/,
2385                                        int /*nOverviews*/,
2386                                        int* /*panOverviewList*/,
2387                                        GDALProgressFunc /*pfnProgress*/,
2388                                        void * /*pProgressData*/ )
2389 
2390 {
2391     ReportError( CE_Failure, CPLE_NotSupported,
2392                  "BuildOverviews() not supported for this dataset." );
2393 
2394     return( CE_Failure );
2395 }
2396 
2397 /************************************************************************/
2398 /*                             GetOffset()                              */
2399 /************************************************************************/
2400 
2401 /**
2402  * \brief Fetch the raster value offset.
2403  *
2404  * This value (in combination with the GetScale() value) can be used to
2405  * transform raw pixel values into the units returned by GetUnitType().
2406  * For example this might be used to store elevations in GUInt16 bands
2407  * with a precision of 0.1, and starting from -100.
2408  *
2409  * Units value = (raw value * scale) + offset
2410  *
2411  * Note that applying scale and offset is of the responsibility of the user,
2412  * and is not done by methods such as RasterIO() or ReadBlock().
2413  *
2414  * For file formats that don't know this intrinsically a value of zero
2415  * is returned.
2416  *
2417  * This method is the same as the C function GDALGetRasterOffset().
2418  *
2419  * @param pbSuccess pointer to a boolean to use to indicate if the
2420  * returned value is meaningful or not.  May be NULL (default).
2421  *
2422  * @return the raster offset.
2423  */
2424 
GetOffset(int * pbSuccess)2425 double GDALRasterBand::GetOffset( int *pbSuccess )
2426 
2427 {
2428     if( pbSuccess != nullptr )
2429         *pbSuccess = FALSE;
2430 
2431     return 0.0;
2432 }
2433 
2434 /************************************************************************/
2435 /*                        GDALGetRasterOffset()                         */
2436 /************************************************************************/
2437 
2438 /**
2439  * \brief Fetch the raster value offset.
2440  *
2441  * @see GDALRasterBand::GetOffset()
2442  */
2443 
GDALGetRasterOffset(GDALRasterBandH hBand,int * pbSuccess)2444 double CPL_STDCALL GDALGetRasterOffset( GDALRasterBandH hBand, int *pbSuccess )
2445 
2446 {
2447     VALIDATE_POINTER1( hBand, "GDALGetRasterOffset", 0 );
2448 
2449     GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
2450     return poBand->GetOffset( pbSuccess );
2451 }
2452 
2453 /************************************************************************/
2454 /*                             SetOffset()                              */
2455 /************************************************************************/
2456 
2457 /**
2458  * \fn GDALRasterBand::SetOffset(double)
2459  * \brief Set scaling offset.
2460  *
2461  * Very few formats implement this method.   When not implemented it will
2462  * issue a CPLE_NotSupported error and return CE_Failure.
2463  *
2464  * This method is the same as the C function GDALSetRasterOffset().
2465  *
2466  * @param dfNewOffset the new offset.
2467  *
2468  * @return CE_None or success or CE_Failure on failure.
2469  */
2470 
2471 /**/
2472 /**/
2473 
SetOffset(double)2474 CPLErr GDALRasterBand::SetOffset( double /*dfNewOffset*/ )
2475 {
2476     if( !(GetMOFlags() & GMO_IGNORE_UNIMPLEMENTED) )
2477         ReportError( CE_Failure, CPLE_NotSupported,
2478                      "SetOffset() not supported on this raster band." );
2479 
2480     return CE_Failure;
2481 }
2482 
2483 /************************************************************************/
2484 /*                        GDALSetRasterOffset()                         */
2485 /************************************************************************/
2486 
2487 /**
2488  * \brief Set scaling offset.
2489  *
2490  * @see GDALRasterBand::SetOffset()
2491  */
2492 
2493 CPLErr CPL_STDCALL
GDALSetRasterOffset(GDALRasterBandH hBand,double dfNewOffset)2494 GDALSetRasterOffset( GDALRasterBandH hBand, double dfNewOffset )
2495 
2496 {
2497     VALIDATE_POINTER1( hBand, "GDALSetRasterOffset", CE_Failure );
2498 
2499     GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
2500     return poBand->SetOffset( dfNewOffset );
2501 }
2502 
2503 /************************************************************************/
2504 /*                              GetScale()                              */
2505 /************************************************************************/
2506 
2507 /**
2508  * \brief Fetch the raster value scale.
2509  *
2510  * This value (in combination with the GetOffset() value) can be used to
2511  * transform raw pixel values into the units returned by GetUnitType().
2512  * For example this might be used to store elevations in GUInt16 bands
2513  * with a precision of 0.1, and starting from -100.
2514  *
2515  * Units value = (raw value * scale) + offset
2516  *
2517  * Note that applying scale and offset is of the responsibility of the user,
2518  * and is not done by methods such as RasterIO() or ReadBlock().
2519  *
2520  * For file formats that don't know this intrinsically a value of one
2521  * is returned.
2522  *
2523  * This method is the same as the C function GDALGetRasterScale().
2524  *
2525  * @param pbSuccess pointer to a boolean to use to indicate if the
2526  * returned value is meaningful or not.  May be NULL (default).
2527  *
2528  * @return the raster scale.
2529  */
2530 
GetScale(int * pbSuccess)2531 double GDALRasterBand::GetScale( int *pbSuccess )
2532 
2533 {
2534     if( pbSuccess != nullptr )
2535         *pbSuccess = FALSE;
2536 
2537     return 1.0;
2538 }
2539 
2540 /************************************************************************/
2541 /*                         GDALGetRasterScale()                         */
2542 /************************************************************************/
2543 
2544 /**
2545  * \brief Fetch the raster value scale.
2546  *
2547  * @see GDALRasterBand::GetScale()
2548  */
2549 
GDALGetRasterScale(GDALRasterBandH hBand,int * pbSuccess)2550 double CPL_STDCALL GDALGetRasterScale( GDALRasterBandH hBand, int *pbSuccess )
2551 
2552 {
2553     VALIDATE_POINTER1( hBand, "GDALGetRasterScale", 0 );
2554 
2555     GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
2556     return poBand->GetScale( pbSuccess );
2557 }
2558 
2559 /************************************************************************/
2560 /*                              SetScale()                              */
2561 /************************************************************************/
2562 
2563 /**
2564  * \fn GDALRasterBand::SetScale(double)
2565  * \brief Set scaling ratio.
2566  *
2567  * Very few formats implement this method.   When not implemented it will
2568  * issue a CPLE_NotSupported error and return CE_Failure.
2569  *
2570  * This method is the same as the C function GDALSetRasterScale().
2571  *
2572  * @param dfNewScale the new scale.
2573  *
2574  * @return CE_None or success or CE_Failure on failure.
2575  */
2576 
2577 /**/
2578 /**/
2579 
SetScale(double)2580 CPLErr GDALRasterBand::SetScale( double /*dfNewScale*/ )
2581 
2582 {
2583     if( !(GetMOFlags() & GMO_IGNORE_UNIMPLEMENTED) )
2584         ReportError( CE_Failure, CPLE_NotSupported,
2585                      "SetScale() not supported on this raster band." );
2586 
2587     return CE_Failure;
2588 }
2589 
2590 /************************************************************************/
2591 /*                        GDALSetRasterScale()                          */
2592 /************************************************************************/
2593 
2594 /**
2595  * \brief Set scaling ratio.
2596  *
2597  * @see GDALRasterBand::SetScale()
2598  */
2599 
2600 CPLErr CPL_STDCALL
GDALSetRasterScale(GDALRasterBandH hBand,double dfNewOffset)2601 GDALSetRasterScale( GDALRasterBandH hBand, double dfNewOffset )
2602 
2603 {
2604     VALIDATE_POINTER1( hBand, "GDALSetRasterScale", CE_Failure );
2605 
2606     GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
2607     return poBand->SetScale( dfNewOffset );
2608 }
2609 
2610 /************************************************************************/
2611 /*                            GetUnitType()                             */
2612 /************************************************************************/
2613 
2614 /**
2615  * \brief Return raster unit type.
2616  *
2617  * Return a name for the units of this raster's values.  For instance, it
2618  * might be "m" for an elevation model in meters, or "ft" for feet.  If no
2619  * units are available, a value of "" will be returned.  The returned string
2620  * should not be modified, nor freed by the calling application.
2621  *
2622  * This method is the same as the C function GDALGetRasterUnitType().
2623  *
2624  * @return unit name string.
2625  */
2626 
GetUnitType()2627 const char *GDALRasterBand::GetUnitType()
2628 
2629 {
2630     return "";
2631 }
2632 
2633 /************************************************************************/
2634 /*                       GDALGetRasterUnitType()                        */
2635 /************************************************************************/
2636 
2637 /**
2638  * \brief Return raster unit type.
2639  *
2640  * @see GDALRasterBand::GetUnitType()
2641  */
2642 
GDALGetRasterUnitType(GDALRasterBandH hBand)2643 const char * CPL_STDCALL GDALGetRasterUnitType( GDALRasterBandH hBand )
2644 
2645 {
2646     VALIDATE_POINTER1( hBand, "GDALGetRasterUnitType", nullptr );
2647 
2648     GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
2649     return poBand->GetUnitType();
2650 }
2651 
2652 /************************************************************************/
2653 /*                            SetUnitType()                             */
2654 /************************************************************************/
2655 
2656 /**
2657  * \fn GDALRasterBand::SetUnitType(const char*)
2658  * \brief Set unit type.
2659  *
2660  * Set the unit type for a raster band.  Values should be one of
2661  * "" (the default indicating it is unknown), "m" indicating meters,
2662  * or "ft" indicating feet, though other nonstandard values are allowed.
2663  *
2664  * This method is the same as the C function GDALSetRasterUnitType().
2665  *
2666  * @param pszNewValue the new unit type value.
2667  *
2668  * @return CE_None on success or CE_Failure if not successful, or
2669  * unsupported.
2670  */
2671 
2672 /**/
2673 /**/
2674 
SetUnitType(const char *)2675 CPLErr GDALRasterBand::SetUnitType( const char * /*pszNewValue*/ )
2676 
2677 {
2678     if( !(GetMOFlags() & GMO_IGNORE_UNIMPLEMENTED) )
2679         ReportError( CE_Failure, CPLE_NotSupported,
2680                      "SetUnitType() not supported on this raster band." );
2681     return CE_Failure;
2682 }
2683 
2684 /************************************************************************/
2685 /*                       GDALSetRasterUnitType()                        */
2686 /************************************************************************/
2687 
2688 /**
2689  * \brief Set unit type.
2690  *
2691  * @see GDALRasterBand::SetUnitType()
2692  *
2693  * @since GDAL 1.8.0
2694  */
2695 
GDALSetRasterUnitType(GDALRasterBandH hBand,const char * pszNewValue)2696 CPLErr CPL_STDCALL GDALSetRasterUnitType( GDALRasterBandH hBand, const char *pszNewValue )
2697 
2698 {
2699     VALIDATE_POINTER1( hBand, "GDALSetRasterUnitType", CE_Failure );
2700 
2701     GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
2702     return poBand->SetUnitType(pszNewValue);
2703 }
2704 
2705 /************************************************************************/
2706 /*                              GetXSize()                              */
2707 /************************************************************************/
2708 
2709 /**
2710  * \brief Fetch XSize of raster.
2711  *
2712  * This method is the same as the C function GDALGetRasterBandXSize().
2713  *
2714  * @return the width in pixels of this band.
2715  */
2716 
GetXSize()2717 int GDALRasterBand::GetXSize()
2718 
2719 {
2720     return nRasterXSize;
2721 }
2722 
2723 /************************************************************************/
2724 /*                       GDALGetRasterBandXSize()                       */
2725 /************************************************************************/
2726 
2727 /**
2728  * \brief Fetch XSize of raster.
2729  *
2730  * @see GDALRasterBand::GetXSize()
2731  */
2732 
GDALGetRasterBandXSize(GDALRasterBandH hBand)2733 int CPL_STDCALL GDALGetRasterBandXSize( GDALRasterBandH hBand )
2734 
2735 {
2736     VALIDATE_POINTER1( hBand, "GDALGetRasterBandXSize", 0 );
2737 
2738     GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
2739     return poBand->GetXSize();
2740 }
2741 
2742 /************************************************************************/
2743 /*                              GetYSize()                              */
2744 /************************************************************************/
2745 
2746 /**
2747  * \brief Fetch YSize of raster.
2748  *
2749  * This method is the same as the C function GDALGetRasterBandYSize().
2750  *
2751  * @return the height in pixels of this band.
2752  */
2753 
GetYSize()2754 int GDALRasterBand::GetYSize()
2755 
2756 {
2757     return nRasterYSize;
2758 }
2759 
2760 /************************************************************************/
2761 /*                       GDALGetRasterBandYSize()                       */
2762 /************************************************************************/
2763 
2764 /**
2765  * \brief Fetch YSize of raster.
2766  *
2767  * @see GDALRasterBand::GetYSize()
2768  */
2769 
GDALGetRasterBandYSize(GDALRasterBandH hBand)2770 int CPL_STDCALL GDALGetRasterBandYSize( GDALRasterBandH hBand )
2771 
2772 {
2773     VALIDATE_POINTER1( hBand, "GDALGetRasterBandYSize", 0 );
2774 
2775     GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
2776     return poBand->GetYSize();
2777 }
2778 
2779 /************************************************************************/
2780 /*                              GetBand()                               */
2781 /************************************************************************/
2782 
2783 /**
2784  * \brief Fetch the band number.
2785  *
2786  * This method returns the band that this GDALRasterBand objects represents
2787  * within its dataset.  This method may return a value of 0 to indicate
2788  * GDALRasterBand objects without an apparently relationship to a dataset,
2789  * such as GDALRasterBands serving as overviews.
2790  *
2791  * This method is the same as the C function GDALGetBandNumber().
2792  *
2793  * @return band number (1+) or 0 if the band number isn't known.
2794  */
2795 
GetBand()2796 int GDALRasterBand::GetBand()
2797 
2798 {
2799     return nBand;
2800 }
2801 
2802 /************************************************************************/
2803 /*                         GDALGetBandNumber()                          */
2804 /************************************************************************/
2805 
2806 /**
2807  * \brief Fetch the band number.
2808  *
2809  * @see GDALRasterBand::GetBand()
2810  */
2811 
GDALGetBandNumber(GDALRasterBandH hBand)2812 int CPL_STDCALL GDALGetBandNumber( GDALRasterBandH hBand )
2813 
2814 {
2815     VALIDATE_POINTER1( hBand, "GDALGetBandNumber", 0 );
2816 
2817     GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
2818     return poBand->GetBand();
2819 }
2820 
2821 /************************************************************************/
2822 /*                             GetDataset()                             */
2823 /************************************************************************/
2824 
2825 /**
2826  * \brief Fetch the owning dataset handle.
2827  *
2828  * Note that some GDALRasterBands are not considered to be a part of a dataset,
2829  * such as overviews or other "freestanding" bands.
2830  *
2831  * This method is the same as the C function GDALGetBandDataset().
2832  *
2833  * @return the pointer to the GDALDataset to which this band belongs, or
2834  * NULL if this cannot be determined.
2835  */
2836 
GetDataset()2837 GDALDataset *GDALRasterBand::GetDataset()
2838 
2839 {
2840     return poDS;
2841 }
2842 
2843 /************************************************************************/
2844 /*                         GDALGetBandDataset()                         */
2845 /************************************************************************/
2846 
2847 /**
2848  * \brief Fetch the owning dataset handle.
2849  *
2850  * @see GDALRasterBand::GetDataset()
2851  */
2852 
GDALGetBandDataset(GDALRasterBandH hBand)2853 GDALDatasetH CPL_STDCALL GDALGetBandDataset( GDALRasterBandH hBand )
2854 
2855 {
2856     VALIDATE_POINTER1( hBand, "GDALGetBandDataset", nullptr );
2857 
2858     GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
2859     return GDALDataset::ToHandle(poBand->GetDataset());
2860 }
2861 
2862 /************************************************************************/
2863 /*                        ComputeFloatNoDataValue()                     */
2864 /************************************************************************/
2865 
ComputeFloatNoDataValue(GDALDataType eDataType,double dfNoDataValue,int & bGotNoDataValue,float & fNoDataValue,bool & bGotFloatNoDataValue)2866 static inline void ComputeFloatNoDataValue( GDALDataType eDataType,
2867                                             double dfNoDataValue,
2868                                             int& bGotNoDataValue,
2869                                             float& fNoDataValue,
2870                                             bool& bGotFloatNoDataValue )
2871 {
2872     if( eDataType == GDT_Float32 && bGotNoDataValue )
2873     {
2874         dfNoDataValue = GDALAdjustNoDataCloseToFloatMax(dfNoDataValue);
2875         if (GDALIsValueInRange<float>(dfNoDataValue) )
2876         {
2877             fNoDataValue = static_cast<float>(dfNoDataValue);
2878             bGotFloatNoDataValue = true;
2879             bGotNoDataValue = false;
2880         }
2881     }
2882 }
2883 
2884 /************************************************************************/
2885 /*                            GetHistogram()                            */
2886 /************************************************************************/
2887 
2888 /**
2889  * \brief Compute raster histogram.
2890  *
2891  * Note that the bucket size is (dfMax-dfMin) / nBuckets.
2892  *
2893  * For example to compute a simple 256 entry histogram of eight bit data,
2894  * the following would be suitable.  The unusual bounds are to ensure that
2895  * bucket boundaries don't fall right on integer values causing possible errors
2896  * due to rounding after scaling.
2897 \code{.cpp}
2898     GUIntBig anHistogram[256];
2899 
2900     poBand->GetHistogram( -0.5, 255.5, 256, anHistogram, FALSE, FALSE,
2901                           GDALDummyProgress, nullptr );
2902 \endcode
2903  *
2904  * Note that setting bApproxOK will generally result in a subsampling of the
2905  * file, and will utilize overviews if available.  It should generally
2906  * produce a representative histogram for the data that is suitable for use
2907  * in generating histogram based luts for instance.  Generally bApproxOK is
2908  * much faster than an exactly computed histogram.
2909  *
2910  * This method is the same as the C functions GDALGetRasterHistogram() and
2911  * GDALGetRasterHistogramEx().
2912  *
2913  * @param dfMin the lower bound of the histogram.
2914  * @param dfMax the upper bound of the histogram.
2915  * @param nBuckets the number of buckets in panHistogram.
2916  * @param panHistogram array into which the histogram totals are placed.
2917  * @param bIncludeOutOfRange if TRUE values below the histogram range will
2918  * mapped into panHistogram[0], and values above will be mapped into
2919  * panHistogram[nBuckets-1] otherwise out of range values are discarded.
2920  * @param bApproxOK TRUE if an approximate, or incomplete histogram OK.
2921  * @param pfnProgress function to report progress to completion.
2922  * @param pProgressData application data to pass to pfnProgress.
2923  *
2924  * @return CE_None on success, or CE_Failure if something goes wrong.
2925  */
2926 
GetHistogram(double dfMin,double dfMax,int nBuckets,GUIntBig * panHistogram,int bIncludeOutOfRange,int bApproxOK,GDALProgressFunc pfnProgress,void * pProgressData)2927 CPLErr GDALRasterBand::GetHistogram( double dfMin, double dfMax,
2928                                      int nBuckets, GUIntBig *panHistogram,
2929                                      int bIncludeOutOfRange, int bApproxOK,
2930                                      GDALProgressFunc pfnProgress,
2931                                      void *pProgressData )
2932 
2933 {
2934     CPLAssert( nullptr != panHistogram );
2935 
2936     if( pfnProgress == nullptr )
2937         pfnProgress = GDALDummyProgress;
2938 
2939 /* -------------------------------------------------------------------- */
2940 /*      If we have overviews, use them for the histogram.               */
2941 /* -------------------------------------------------------------------- */
2942     if( bApproxOK && GetOverviewCount() > 0 && !HasArbitraryOverviews() )
2943     {
2944         // FIXME: should we use the most reduced overview here or use some
2945         // minimum number of samples like GDALRasterBand::ComputeStatistics()
2946         // does?
2947         GDALRasterBand *poBestOverview = GetRasterSampleOverview( 0 );
2948 
2949         if( poBestOverview != this )
2950         {
2951             return poBestOverview->GetHistogram( dfMin, dfMax, nBuckets,
2952                                                  panHistogram,
2953                                                  bIncludeOutOfRange, bApproxOK,
2954                                                  pfnProgress, pProgressData );
2955         }
2956     }
2957 
2958 /* -------------------------------------------------------------------- */
2959 /*      Read actual data and build histogram.                           */
2960 /* -------------------------------------------------------------------- */
2961     if( !pfnProgress( 0.0, "Compute Histogram", pProgressData ) )
2962     {
2963         ReportError( CE_Failure, CPLE_UserInterrupt, "User terminated" );
2964         return CE_Failure;
2965     }
2966 
2967     GDALRasterIOExtraArg sExtraArg;
2968     INIT_RASTERIO_EXTRA_ARG(sExtraArg);
2969 
2970     const double dfScale = (dfMax > dfMin) ? nBuckets / (dfMax - dfMin) : 0.0;
2971     memset( panHistogram, 0, sizeof(GUIntBig) * nBuckets );
2972 
2973     int bGotNoDataValue = FALSE;
2974     const double dfNoDataValue = GetNoDataValue( &bGotNoDataValue );
2975     bGotNoDataValue = bGotNoDataValue && !CPLIsNan(dfNoDataValue);
2976     // Not advertized. May be removed at any time. Just as a provision if the
2977     // old behavior made sense sometimes.
2978     bGotNoDataValue = bGotNoDataValue &&
2979         !CPLTestBool(CPLGetConfigOption("GDAL_NODATA_IN_HISTOGRAM", "NO"));
2980     bool bGotFloatNoDataValue = false;
2981     float fNoDataValue = 0.0f;
2982     ComputeFloatNoDataValue( eDataType, dfNoDataValue, bGotNoDataValue,
2983                             fNoDataValue, bGotFloatNoDataValue );
2984 
2985     const char* pszPixelType = GetMetadataItem("PIXELTYPE", "IMAGE_STRUCTURE");
2986     const bool bSignedByte =
2987         pszPixelType != nullptr && EQUAL(pszPixelType, "SIGNEDBYTE");
2988 
2989     if ( bApproxOK && HasArbitraryOverviews() )
2990     {
2991 /* -------------------------------------------------------------------- */
2992 /*      Figure out how much the image should be reduced to get an       */
2993 /*      approximate value.                                              */
2994 /* -------------------------------------------------------------------- */
2995         const double dfReduction = sqrt(
2996             static_cast<double>(nRasterXSize) * nRasterYSize /
2997             GDALSTAT_APPROX_NUMSAMPLES );
2998 
2999         int nXReduced = nRasterXSize;
3000         int nYReduced = nRasterYSize;
3001         if ( dfReduction > 1.0 )
3002         {
3003             nXReduced = static_cast<int>( nRasterXSize / dfReduction );
3004             nYReduced = static_cast<int>( nRasterYSize / dfReduction );
3005 
3006             // Catch the case of huge resizing ratios here
3007             if ( nXReduced == 0 )
3008                 nXReduced = 1;
3009             if ( nYReduced == 0 )
3010                 nYReduced = 1;
3011         }
3012 
3013         void *pData =
3014             CPLMalloc(
3015                 GDALGetDataTypeSizeBytes(eDataType) * nXReduced * nYReduced );
3016 
3017         const CPLErr eErr =
3018             IRasterIO(
3019                 GF_Read, 0, 0, nRasterXSize, nRasterYSize, pData,
3020                 nXReduced, nYReduced, eDataType, 0, 0, &sExtraArg );
3021         if ( eErr != CE_None )
3022         {
3023             CPLFree(pData);
3024             return eErr;
3025         }
3026 
3027         // This isn't the fastest way to do this, but is easier for now.
3028         for( int iY = 0; iY < nYReduced; iY++ )
3029         {
3030             for( int iX = 0; iX < nXReduced; iX++ )
3031             {
3032                 const int iOffset = iX + iY * nXReduced;
3033                 double dfValue = 0.0;
3034 
3035                 switch( eDataType )
3036                 {
3037                   case GDT_Byte:
3038                   {
3039                     if( bSignedByte )
3040                         dfValue = static_cast<signed char *>(pData)[iOffset];
3041                     else
3042                         dfValue = static_cast<GByte *>(pData)[iOffset];
3043                     break;
3044                   }
3045                   case GDT_UInt16:
3046                     dfValue = static_cast<GUInt16 *>(pData)[iOffset];
3047                     break;
3048                   case GDT_Int16:
3049                     dfValue = static_cast<GInt16 *>(pData)[iOffset];
3050                     break;
3051                   case GDT_UInt32:
3052                     dfValue = static_cast<GUInt32 *>(pData)[iOffset];
3053                     break;
3054                   case GDT_Int32:
3055                     dfValue = static_cast<GInt32 *>(pData)[iOffset];
3056                     break;
3057                   case GDT_Float32:
3058                   {
3059                     const float fValue = static_cast<float *>(pData)[iOffset];
3060                     if( CPLIsNan(fValue) ||
3061                         (bGotFloatNoDataValue && ARE_REAL_EQUAL(fValue, fNoDataValue)) )
3062                         continue;
3063                     dfValue = fValue;
3064                     break;
3065                   }
3066                   case GDT_Float64:
3067                     dfValue = static_cast<double *>(pData)[iOffset];
3068                     if( CPLIsNan(dfValue) )
3069                         continue;
3070                     break;
3071                   case GDT_CInt16:
3072                     {
3073                         const double dfReal =
3074                             static_cast<GInt16 *>(pData)[iOffset*2];
3075                         const double dfImag =
3076                             static_cast<GInt16 *>(pData)[iOffset*2+1];
3077                         if ( CPLIsNan(dfReal) || CPLIsNan(dfImag) )
3078                             continue;
3079                         dfValue = sqrt( dfReal * dfReal + dfImag * dfImag );
3080                     }
3081                     break;
3082                   case GDT_CInt32:
3083                     {
3084                         const double dfReal =
3085                             static_cast<GInt32 *>(pData)[iOffset*2];
3086                         const double dfImag =
3087                             static_cast<GInt32 *>(pData)[iOffset*2+1];
3088                         if ( CPLIsNan(dfReal) || CPLIsNan(dfImag) )
3089                             continue;
3090                         dfValue = sqrt( dfReal * dfReal + dfImag * dfImag );
3091                     }
3092                     break;
3093                   case GDT_CFloat32:
3094                     {
3095                         const double dfReal =
3096                             static_cast<float *>(pData)[iOffset*2];
3097                         const double dfImag =
3098                             static_cast<float *>(pData)[iOffset*2+1];
3099                         if ( CPLIsNan(dfReal) || CPLIsNan(dfImag) )
3100                             continue;
3101                         dfValue = sqrt( dfReal * dfReal + dfImag * dfImag );
3102                     }
3103                     break;
3104                   case GDT_CFloat64:
3105                     {
3106                         const double dfReal =
3107                             static_cast<double *>(pData)[iOffset*2];
3108                         const double dfImag =
3109                             static_cast<double *>(pData)[iOffset*2+1];
3110                         if ( CPLIsNan(dfReal) || CPLIsNan(dfImag) )
3111                             continue;
3112                         dfValue = sqrt( dfReal * dfReal + dfImag * dfImag );
3113                     }
3114                     break;
3115                   default:
3116                     CPLAssert( false );
3117                 }
3118 
3119                 if( eDataType != GDT_Float32 &&
3120                     bGotNoDataValue && ARE_REAL_EQUAL(dfValue, dfNoDataValue) )
3121                     continue;
3122 
3123                 const int nIndex =
3124                     static_cast<int>(floor((dfValue - dfMin) * dfScale));
3125 
3126                 if( nIndex < 0 )
3127                 {
3128                     if( bIncludeOutOfRange )
3129                         panHistogram[0]++;
3130                 }
3131                 else if( nIndex >= nBuckets )
3132                 {
3133                     if( bIncludeOutOfRange )
3134                         ++panHistogram[nBuckets-1];
3135                 }
3136                 else
3137                 {
3138                     ++panHistogram[nIndex];
3139                 }
3140             }
3141         }
3142 
3143         CPLFree( pData );
3144     }
3145     else  // No arbitrary overviews.
3146     {
3147         if( !InitBlockInfo() )
3148             return CE_Failure;
3149 
3150 /* -------------------------------------------------------------------- */
3151 /*      Figure out the ratio of blocks we will read to get an           */
3152 /*      approximate value.                                              */
3153 /* -------------------------------------------------------------------- */
3154 
3155         int nSampleRate = 1;
3156         if ( bApproxOK )
3157         {
3158             nSampleRate = static_cast<int>(
3159                 std::max(1.0,
3160                          sqrt(static_cast<double>(nBlocksPerRow) *
3161                               nBlocksPerColumn)));
3162             // We want to avoid probing only the first column of blocks for
3163             // a square shaped raster, because it is not unlikely that it may
3164             // be padding only (#6378).
3165             if( nSampleRate == nBlocksPerRow && nBlocksPerRow > 1 )
3166               nSampleRate += 1;
3167         }
3168 
3169 /* -------------------------------------------------------------------- */
3170 /*      Read the blocks, and add to histogram.                          */
3171 /* -------------------------------------------------------------------- */
3172         for( int iSampleBlock = 0;
3173              iSampleBlock < nBlocksPerRow * nBlocksPerColumn;
3174              iSampleBlock += nSampleRate )
3175         {
3176             if( !pfnProgress(
3177                     iSampleBlock /
3178                         (static_cast<double>(nBlocksPerRow) * nBlocksPerColumn),
3179                     "Compute Histogram", pProgressData ) )
3180                 return CE_Failure;
3181 
3182             const int iYBlock = iSampleBlock / nBlocksPerRow;
3183             const int iXBlock = iSampleBlock - nBlocksPerRow * iYBlock;
3184 
3185             GDALRasterBlock *poBlock = GetLockedBlockRef( iXBlock, iYBlock );
3186             if( poBlock == nullptr )
3187                 return CE_Failure;
3188 
3189             void *pData = poBlock->GetDataRef();
3190 
3191             int nXCheck = 0, nYCheck = 0;
3192             GetActualBlockSize(iXBlock, iYBlock, &nXCheck, &nYCheck);
3193 
3194             // this is a special case for a common situation.
3195             if( eDataType == GDT_Byte && !bSignedByte
3196                 && dfScale == 1.0 && (dfMin >= -0.5 && dfMin <= 0.5)
3197                 && nYCheck == nBlockYSize && nXCheck == nBlockXSize
3198                 && nBuckets == 256 )
3199             {
3200                 const GPtrDiff_t nPixels = static_cast<GPtrDiff_t>(nXCheck) * nYCheck;
3201                 GByte *pabyData = static_cast<GByte *>(pData);
3202 
3203                 for( GPtrDiff_t i = 0; i < nPixels; i++ )
3204                     if( ! (bGotNoDataValue &&
3205                            (pabyData[i] == static_cast<GByte>(dfNoDataValue))))
3206                     {
3207                         panHistogram[pabyData[i]]++;
3208                     }
3209 
3210                 poBlock->DropLock();
3211                 continue;  // To next sample block.
3212             }
3213 
3214             // This isn't the fastest way to do this, but is easier for now.
3215             for( int iY = 0; iY < nYCheck; iY++ )
3216             {
3217                 for( int iX = 0; iX < nXCheck; iX++ )
3218                 {
3219                     const GPtrDiff_t iOffset = iX + static_cast<GPtrDiff_t>(iY) * nBlockXSize;
3220                     double dfValue = 0.0;
3221 
3222                     switch( eDataType )
3223                     {
3224                       case GDT_Byte:
3225                       {
3226                         if( bSignedByte )
3227                             dfValue =
3228                                 static_cast<signed char *>(pData)[iOffset];
3229                         else
3230                             dfValue = static_cast<GByte *>(pData)[iOffset];
3231                         break;
3232                       }
3233                       case GDT_UInt16:
3234                         dfValue = static_cast<GUInt16 *>(pData)[iOffset];
3235                         break;
3236                       case GDT_Int16:
3237                         dfValue = static_cast<GInt16 *>(pData)[iOffset];
3238                         break;
3239                       case GDT_UInt32:
3240                         dfValue = static_cast<GUInt32 *>(pData)[iOffset];
3241                         break;
3242                       case GDT_Int32:
3243                         dfValue = static_cast<GInt32 *>(pData)[iOffset];
3244                         break;
3245                       case GDT_Float32:
3246                       {
3247                         const float fValue = static_cast<float *>(pData)[iOffset];
3248                         if( CPLIsNan(fValue) ||
3249                             (bGotFloatNoDataValue && ARE_REAL_EQUAL(fValue, fNoDataValue)) )
3250                             continue;
3251                         dfValue = fValue;
3252                         break;
3253                       }
3254                       case GDT_Float64:
3255                         dfValue = static_cast<double *>(pData)[iOffset];
3256                         if( CPLIsNan(dfValue) )
3257                             continue;
3258                         break;
3259                       case GDT_CInt16:
3260                         {
3261                             double  dfReal =
3262                                 static_cast<GInt16 *>(pData)[iOffset*2];
3263                             double  dfImag =
3264                                 static_cast<GInt16 *>(pData)[iOffset*2+1];
3265                             dfValue = sqrt( dfReal * dfReal + dfImag * dfImag );
3266                         }
3267                         break;
3268                       case GDT_CInt32:
3269                         {
3270                             double  dfReal =
3271                                 static_cast<GInt32 *>(pData)[iOffset*2];
3272                             double  dfImag =
3273                                 static_cast<GInt32 *>(pData)[iOffset*2+1];
3274                             dfValue = sqrt( dfReal * dfReal + dfImag * dfImag );
3275                         }
3276                         break;
3277                       case GDT_CFloat32:
3278                         {
3279                             double  dfReal =
3280                                 static_cast<float *>(pData)[iOffset*2];
3281                             double  dfImag =
3282                                 static_cast<float *>(pData)[iOffset*2+1];
3283                             if ( CPLIsNan(dfReal) || CPLIsNan(dfImag) )
3284                                 continue;
3285                             dfValue = sqrt( dfReal * dfReal + dfImag * dfImag );
3286                         }
3287                         break;
3288                       case GDT_CFloat64:
3289                         {
3290                             double  dfReal =
3291                                 static_cast<double *>(pData)[iOffset*2];
3292                             double  dfImag =
3293                                 static_cast<double *>(pData)[iOffset*2+1];
3294                             if ( CPLIsNan(dfReal) || CPLIsNan(dfImag) )
3295                                 continue;
3296                             dfValue = sqrt( dfReal * dfReal + dfImag * dfImag );
3297                         }
3298                         break;
3299                       default:
3300                         CPLAssert( false );
3301                         return CE_Failure;
3302                     }
3303 
3304                     if( eDataType != GDT_Float32 && bGotNoDataValue &&
3305                         ARE_REAL_EQUAL(dfValue, dfNoDataValue) )
3306                         continue;
3307 
3308                     const int nIndex =
3309                         static_cast<int>(floor((dfValue - dfMin) * dfScale));
3310 
3311                     if( nIndex < 0 )
3312                     {
3313                         if( bIncludeOutOfRange )
3314                             ++panHistogram[0];
3315                     }
3316                     else if( nIndex >= nBuckets )
3317                     {
3318                         if( bIncludeOutOfRange )
3319                             ++panHistogram[nBuckets-1];
3320                     }
3321                     else
3322                     {
3323                         panHistogram[nIndex]++;
3324                     }
3325                 }
3326             }
3327 
3328             poBlock->DropLock();
3329         }
3330     }
3331 
3332     pfnProgress( 1.0, "Compute Histogram", pProgressData );
3333 
3334     return CE_None;
3335 }
3336 
3337 /************************************************************************/
3338 /*                       GDALGetRasterHistogram()                       */
3339 /************************************************************************/
3340 
3341 /**
3342  * \brief Compute raster histogram.
3343  *
3344  * Use GDALGetRasterHistogramEx() instead to get correct counts for values
3345  * exceeding 2 billion.
3346  *
3347  * @see GDALRasterBand::GetHistogram()
3348  * @see GDALGetRasterHistogramEx()
3349  */
3350 
3351 CPLErr CPL_STDCALL
GDALGetRasterHistogram(GDALRasterBandH hBand,double dfMin,double dfMax,int nBuckets,int * panHistogram,int bIncludeOutOfRange,int bApproxOK,GDALProgressFunc pfnProgress,void * pProgressData)3352 GDALGetRasterHistogram( GDALRasterBandH hBand,
3353                         double dfMin, double dfMax,
3354                         int nBuckets, int *panHistogram,
3355                         int bIncludeOutOfRange, int bApproxOK,
3356                         GDALProgressFunc pfnProgress,
3357                         void *pProgressData )
3358 
3359 {
3360     VALIDATE_POINTER1( hBand, "GDALGetRasterHistogram", CE_Failure );
3361     VALIDATE_POINTER1( panHistogram, "GDALGetRasterHistogram", CE_Failure );
3362 
3363     GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
3364 
3365     GUIntBig* panHistogramTemp = static_cast<GUIntBig *>(
3366         VSIMalloc2(sizeof(GUIntBig), nBuckets) );
3367     if( panHistogramTemp == nullptr )
3368     {
3369         poBand->ReportError(
3370             CE_Failure, CPLE_OutOfMemory,
3371             "Out of memory in GDALGetRasterHistogram()." );
3372         return CE_Failure;
3373     }
3374 
3375     CPLErr eErr = poBand->GetHistogram(
3376         dfMin, dfMax, nBuckets, panHistogramTemp,
3377         bIncludeOutOfRange, bApproxOK,
3378         pfnProgress, pProgressData );
3379 
3380     if( eErr == CE_None )
3381     {
3382         for(int i=0;i<nBuckets;i++)
3383         {
3384             if( panHistogramTemp[i] > INT_MAX )
3385             {
3386                 CPLError(
3387                     CE_Warning, CPLE_AppDefined,
3388                     "Count for bucket %d, which is " CPL_FRMT_GUIB
3389                     " exceeds maximum 32 bit value",
3390                     i, panHistogramTemp[i] );
3391                 panHistogram[i] = INT_MAX;
3392             }
3393             else
3394             {
3395                 panHistogram[i] = static_cast<int>(panHistogramTemp[i]);
3396             }
3397         }
3398     }
3399 
3400     CPLFree(panHistogramTemp);
3401 
3402     return eErr;
3403 }
3404 
3405 /************************************************************************/
3406 /*                      GDALGetRasterHistogramEx()                      */
3407 /************************************************************************/
3408 
3409 /**
3410  * \brief Compute raster histogram.
3411  *
3412  * @see GDALRasterBand::GetHistogram()
3413  *
3414  * @since GDAL 2.0
3415  */
3416 
3417 CPLErr CPL_STDCALL
GDALGetRasterHistogramEx(GDALRasterBandH hBand,double dfMin,double dfMax,int nBuckets,GUIntBig * panHistogram,int bIncludeOutOfRange,int bApproxOK,GDALProgressFunc pfnProgress,void * pProgressData)3418 GDALGetRasterHistogramEx( GDALRasterBandH hBand,
3419                           double dfMin, double dfMax,
3420                           int nBuckets, GUIntBig *panHistogram,
3421                           int bIncludeOutOfRange, int bApproxOK,
3422                           GDALProgressFunc pfnProgress,
3423                           void *pProgressData )
3424 
3425 {
3426     VALIDATE_POINTER1( hBand, "GDALGetRasterHistogramEx", CE_Failure );
3427     VALIDATE_POINTER1( panHistogram, "GDALGetRasterHistogramEx", CE_Failure );
3428 
3429     GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
3430 
3431     return poBand->GetHistogram( dfMin, dfMax, nBuckets, panHistogram,
3432                                  bIncludeOutOfRange, bApproxOK,
3433                                  pfnProgress, pProgressData );
3434 }
3435 
3436 /************************************************************************/
3437 /*                        GetDefaultHistogram()                         */
3438 /************************************************************************/
3439 
3440 /**
3441  * \brief Fetch default raster histogram.
3442  *
3443  * The default method in GDALRasterBand will compute a default histogram. This
3444  * method is overridden by derived classes (such as GDALPamRasterBand,
3445  * VRTDataset, HFADataset...) that may be able to fetch efficiently an already
3446  * stored histogram.
3447  *
3448  * This method is the same as the C functions GDALGetDefaultHistogram() and
3449  * GDALGetDefaultHistogramEx().
3450  *
3451  * @param pdfMin pointer to double value that will contain the lower bound of
3452  * the histogram.
3453  * @param pdfMax pointer to double value that will contain the upper bound of
3454  * the histogram.
3455  * @param pnBuckets pointer to int value that will contain the number of buckets
3456  * in *ppanHistogram.
3457  * @param ppanHistogram pointer to array into which the histogram totals are
3458  * placed. To be freed with VSIFree
3459  * @param bForce TRUE to force the computation. If FALSE and no default
3460  * histogram is available, the method will return CE_Warning
3461  * @param pfnProgress function to report progress to completion.
3462  * @param pProgressData application data to pass to pfnProgress.
3463  *
3464  * @return CE_None on success, CE_Failure if something goes wrong, or
3465  * CE_Warning if no default histogram is available.
3466  */
3467 
3468 CPLErr
GetDefaultHistogram(double * pdfMin,double * pdfMax,int * pnBuckets,GUIntBig ** ppanHistogram,int bForce,GDALProgressFunc pfnProgress,void * pProgressData)3469     GDALRasterBand::GetDefaultHistogram( double *pdfMin, double *pdfMax,
3470                                          int *pnBuckets,
3471                                          GUIntBig **ppanHistogram,
3472                                          int bForce,
3473                                          GDALProgressFunc pfnProgress,
3474                                          void *pProgressData )
3475 
3476 {
3477     CPLAssert( nullptr != pnBuckets );
3478     CPLAssert( nullptr != ppanHistogram );
3479     CPLAssert( nullptr != pdfMin );
3480     CPLAssert( nullptr != pdfMax );
3481 
3482     *pnBuckets = 0;
3483     *ppanHistogram = nullptr;
3484 
3485     if( !bForce )
3486         return CE_Warning;
3487 
3488     const int nBuckets = 256;
3489 
3490     const char* pszPixelType = GetMetadataItem("PIXELTYPE", "IMAGE_STRUCTURE");
3491     const int bSignedByte =
3492         pszPixelType != nullptr && EQUAL(pszPixelType, "SIGNEDBYTE");
3493 
3494     if( GetRasterDataType() == GDT_Byte && !bSignedByte)
3495     {
3496         *pdfMin = -0.5;
3497         *pdfMax = 255.5;
3498     }
3499     else
3500     {
3501 
3502         const CPLErr eErr =
3503             GetStatistics( TRUE, TRUE, pdfMin, pdfMax, nullptr, nullptr );
3504         const double dfHalfBucket = (*pdfMax - *pdfMin) / (2 * (nBuckets - 1));
3505         *pdfMin -= dfHalfBucket;
3506         *pdfMax += dfHalfBucket;
3507 
3508         if( eErr != CE_None )
3509             return eErr;
3510     }
3511 
3512     *ppanHistogram = static_cast<GUIntBig *>(
3513         VSICalloc(sizeof(GUIntBig), nBuckets) );
3514     if( *ppanHistogram == nullptr )
3515     {
3516         ReportError( CE_Failure, CPLE_OutOfMemory,
3517                   "Out of memory in InitBlockInfo()." );
3518         return CE_Failure;
3519     }
3520 
3521     *pnBuckets = nBuckets;
3522     CPLErr eErr = GetHistogram( *pdfMin, *pdfMax, *pnBuckets, *ppanHistogram,
3523                          TRUE, FALSE, pfnProgress, pProgressData );
3524     if( eErr != CE_None )
3525     {
3526         *pnBuckets = 0;
3527     }
3528     return eErr;
3529 }
3530 
3531 /************************************************************************/
3532 /*                      GDALGetDefaultHistogram()                       */
3533 /************************************************************************/
3534 
3535 /**
3536   * \brief Fetch default raster histogram.
3537   *
3538   * Use GDALGetRasterHistogramEx() instead to get correct counts for values
3539   * exceeding 2 billion.
3540   *
3541   * @see GDALRasterBand::GDALGetDefaultHistogram()
3542   * @see GDALGetRasterHistogramEx()
3543   */
3544 
GDALGetDefaultHistogram(GDALRasterBandH hBand,double * pdfMin,double * pdfMax,int * pnBuckets,int ** ppanHistogram,int bForce,GDALProgressFunc pfnProgress,void * pProgressData)3545 CPLErr CPL_STDCALL GDALGetDefaultHistogram(
3546     GDALRasterBandH hBand,
3547     double *pdfMin, double *pdfMax,
3548     int *pnBuckets, int **ppanHistogram,
3549     int bForce,
3550     GDALProgressFunc pfnProgress,
3551     void *pProgressData )
3552 
3553 {
3554     VALIDATE_POINTER1( hBand, "GDALGetDefaultHistogram", CE_Failure );
3555     VALIDATE_POINTER1( pdfMin, "GDALGetDefaultHistogram", CE_Failure );
3556     VALIDATE_POINTER1( pdfMax, "GDALGetDefaultHistogram", CE_Failure );
3557     VALIDATE_POINTER1( pnBuckets, "GDALGetDefaultHistogram", CE_Failure );
3558     VALIDATE_POINTER1( ppanHistogram, "GDALGetDefaultHistogram", CE_Failure );
3559 
3560     GDALRasterBand * const poBand = GDALRasterBand::FromHandle(hBand);
3561     GUIntBig* panHistogramTemp = nullptr;
3562     CPLErr eErr = poBand->GetDefaultHistogram( pdfMin, pdfMax,
3563         pnBuckets, &panHistogramTemp, bForce, pfnProgress, pProgressData );
3564     if( eErr == CE_None )
3565     {
3566         const int nBuckets = *pnBuckets;
3567         *ppanHistogram = static_cast<int *>(VSIMalloc2(sizeof(int), nBuckets));
3568         if( *ppanHistogram == nullptr )
3569         {
3570             poBand->ReportError(
3571                 CE_Failure, CPLE_OutOfMemory,
3572                 "Out of memory in GDALGetDefaultHistogram()." );
3573             VSIFree(panHistogramTemp);
3574             return CE_Failure;
3575         }
3576 
3577         for( int i = 0; i < nBuckets; ++i )
3578         {
3579             if( panHistogramTemp[i] > INT_MAX )
3580             {
3581                 CPLError(
3582                     CE_Warning, CPLE_AppDefined,
3583                     "Count for bucket %d, which is " CPL_FRMT_GUIB
3584                     " exceeds maximum 32 bit value",
3585                     i, panHistogramTemp[i] );
3586                 (*ppanHistogram)[i] = INT_MAX;
3587             }
3588             else
3589             {
3590                 (*ppanHistogram)[i] = static_cast<int>(panHistogramTemp[i]);
3591             }
3592         }
3593 
3594         CPLFree(panHistogramTemp);
3595     }
3596     else
3597     {
3598         *ppanHistogram = nullptr;
3599     }
3600 
3601     return eErr;
3602 }
3603 
3604 /************************************************************************/
3605 /*                      GDALGetDefaultHistogramEx()                     */
3606 /************************************************************************/
3607 
3608 /**
3609   * \brief Fetch default raster histogram.
3610   *
3611   * @see GDALRasterBand::GetDefaultHistogram()
3612   *
3613   * @since GDAL 2.0
3614   */
3615 
GDALGetDefaultHistogramEx(GDALRasterBandH hBand,double * pdfMin,double * pdfMax,int * pnBuckets,GUIntBig ** ppanHistogram,int bForce,GDALProgressFunc pfnProgress,void * pProgressData)3616 CPLErr CPL_STDCALL GDALGetDefaultHistogramEx(
3617     GDALRasterBandH hBand,
3618     double *pdfMin, double *pdfMax,
3619     int *pnBuckets, GUIntBig **ppanHistogram,
3620     int bForce,
3621     GDALProgressFunc pfnProgress,
3622     void *pProgressData )
3623 
3624 {
3625     VALIDATE_POINTER1( hBand, "GDALGetDefaultHistogram", CE_Failure );
3626     VALIDATE_POINTER1( pdfMin, "GDALGetDefaultHistogram", CE_Failure );
3627     VALIDATE_POINTER1( pdfMax, "GDALGetDefaultHistogram", CE_Failure );
3628     VALIDATE_POINTER1( pnBuckets, "GDALGetDefaultHistogram", CE_Failure );
3629     VALIDATE_POINTER1( ppanHistogram, "GDALGetDefaultHistogram", CE_Failure );
3630 
3631     GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
3632     return poBand->GetDefaultHistogram( pdfMin, pdfMax,
3633         pnBuckets, ppanHistogram, bForce, pfnProgress, pProgressData );
3634 }
3635 /************************************************************************/
3636 /*                             AdviseRead()                             */
3637 /************************************************************************/
3638 
3639 /**
3640  * \fn GDALRasterBand::AdviseRead(int,int,int,int,int,int,GDALDataType,char**)
3641  * \brief Advise driver of upcoming read requests.
3642  *
3643  * Some GDAL drivers operate more efficiently if they know in advance what
3644  * set of upcoming read requests will be made.  The AdviseRead() method allows
3645  * an application to notify the driver of the region of interest,
3646  * and at what resolution the region will be read.
3647  *
3648  * Many drivers just ignore the AdviseRead() call, but it can dramatically
3649  * accelerate access via some drivers.
3650  *
3651  * Depending on call paths, drivers might receive several calls to
3652  * AdviseRead() with the same parameters.
3653  *
3654  * @param nXOff The pixel offset to the top left corner of the region
3655  * of the band to be accessed.  This would be zero to start from the left side.
3656  *
3657  * @param nYOff The line offset to the top left corner of the region
3658  * of the band to be accessed.  This would be zero to start from the top.
3659  *
3660  * @param nXSize The width of the region of the band to be accessed in pixels.
3661  *
3662  * @param nYSize The height of the region of the band to be accessed in lines.
3663  *
3664  * @param nBufXSize the width of the buffer image into which the desired region
3665  * is to be read, or from which it is to be written.
3666  *
3667  * @param nBufYSize the height of the buffer image into which the desired
3668  * region is to be read, or from which it is to be written.
3669  *
3670  * @param eBufType the type of the pixel values in the pData data buffer.  The
3671  * pixel values will automatically be translated to/from the GDALRasterBand
3672  * data type as needed.
3673  *
3674  * @param papszOptions a list of name=value strings with special control
3675  * options.  Normally this is NULL.
3676  *
3677  * @return CE_Failure if the request is invalid and CE_None if it works or
3678  * is ignored.
3679  */
3680 
3681 /**/
3682 /**/
3683 
AdviseRead(int,int,int,int,int,int,GDALDataType,char **)3684 CPLErr GDALRasterBand::AdviseRead(
3685     int /*nXOff*/,
3686     int /*nYOff*/,
3687     int /*nXSize*/,
3688     int /*nYSize*/,
3689     int /*nBufXSize*/,
3690     int /*nBufYSize*/,
3691     GDALDataType /*eBufType*/,
3692     char ** /*papszOptions*/ )
3693 {
3694     return CE_None;
3695 }
3696 
3697 /************************************************************************/
3698 /*                        GDALRasterAdviseRead()                        */
3699 /************************************************************************/
3700 
3701 /**
3702  * \brief Advise driver of upcoming read requests.
3703  *
3704  * @see GDALRasterBand::AdviseRead()
3705  */
3706 
3707 CPLErr CPL_STDCALL
GDALRasterAdviseRead(GDALRasterBandH hBand,int nXOff,int nYOff,int nXSize,int nYSize,int nBufXSize,int nBufYSize,GDALDataType eDT,CSLConstList papszOptions)3708 GDALRasterAdviseRead( GDALRasterBandH hBand,
3709                       int nXOff, int nYOff, int nXSize, int nYSize,
3710                       int nBufXSize, int nBufYSize,
3711                       GDALDataType eDT, CSLConstList papszOptions )
3712 
3713 {
3714     VALIDATE_POINTER1( hBand, "GDALRasterAdviseRead", CE_Failure );
3715 
3716     GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
3717     return poBand->AdviseRead( nXOff, nYOff, nXSize, nYSize,
3718         nBufXSize, nBufYSize, eDT, const_cast<char**>(papszOptions) );
3719 }
3720 
3721 /************************************************************************/
3722 /*                           GetStatistics()                            */
3723 /************************************************************************/
3724 
3725 /**
3726  * \brief Fetch image statistics.
3727  *
3728  * Returns the minimum, maximum, mean and standard deviation of all
3729  * pixel values in this band.  If approximate statistics are sufficient,
3730  * the bApproxOK flag can be set to true in which case overviews, or a
3731  * subset of image tiles may be used in computing the statistics.
3732  *
3733  * If bForce is FALSE results will only be returned if it can be done
3734  * quickly (i.e. without scanning the data).  If bForce is FALSE and
3735  * results cannot be returned efficiently, the method will return CE_Warning
3736  * but no warning will have been issued.   This is a non-standard use of
3737  * the CE_Warning return value to indicate "nothing done".
3738  *
3739  * Note that file formats using PAM (Persistent Auxiliary Metadata) services
3740  * will generally cache statistics in the .pam file allowing fast fetch
3741  * after the first request.
3742  *
3743  * This method is the same as the C function GDALGetRasterStatistics().
3744  *
3745  * @param bApproxOK If TRUE statistics may be computed based on overviews
3746  * or a subset of all tiles.
3747  *
3748  * @param bForce If FALSE statistics will only be returned if it can
3749  * be done without rescanning the image.
3750  *
3751  * @param pdfMin Location into which to load image minimum (may be NULL).
3752  *
3753  * @param pdfMax Location into which to load image maximum (may be NULL).-
3754  *
3755  * @param pdfMean Location into which to load image mean (may be NULL).
3756  *
3757  * @param pdfStdDev Location into which to load image standard deviation
3758  * (may be NULL).
3759  *
3760  * @return CE_None on success, CE_Warning if no values returned,
3761  * CE_Failure if an error occurs.
3762  */
3763 
GetStatistics(int bApproxOK,int bForce,double * pdfMin,double * pdfMax,double * pdfMean,double * pdfStdDev)3764 CPLErr GDALRasterBand::GetStatistics( int bApproxOK, int bForce,
3765                                       double *pdfMin, double *pdfMax,
3766                                       double *pdfMean, double *pdfStdDev )
3767 
3768 {
3769 /* -------------------------------------------------------------------- */
3770 /*      Do we already have metadata items for the requested values?     */
3771 /* -------------------------------------------------------------------- */
3772     if( (pdfMin == nullptr || GetMetadataItem("STATISTICS_MINIMUM") != nullptr)
3773      && (pdfMax == nullptr || GetMetadataItem("STATISTICS_MAXIMUM") != nullptr)
3774      && (pdfMean == nullptr || GetMetadataItem("STATISTICS_MEAN") != nullptr)
3775      && (pdfStdDev == nullptr || GetMetadataItem("STATISTICS_STDDEV") != nullptr) )
3776     {
3777         if( !(GetMetadataItem("STATISTICS_APPROXIMATE") && !bApproxOK) )
3778         {
3779             if( pdfMin != nullptr )
3780                 *pdfMin = CPLAtofM(GetMetadataItem("STATISTICS_MINIMUM"));
3781             if( pdfMax != nullptr )
3782                 *pdfMax = CPLAtofM(GetMetadataItem("STATISTICS_MAXIMUM"));
3783             if( pdfMean != nullptr )
3784                 *pdfMean = CPLAtofM(GetMetadataItem("STATISTICS_MEAN"));
3785             if( pdfStdDev != nullptr )
3786                 *pdfStdDev = CPLAtofM(GetMetadataItem("STATISTICS_STDDEV"));
3787 
3788             return CE_None;
3789         }
3790     }
3791 
3792 /* -------------------------------------------------------------------- */
3793 /*      Does the driver already know the min/max?                       */
3794 /* -------------------------------------------------------------------- */
3795     if( bApproxOK && pdfMean == nullptr && pdfStdDev == nullptr )
3796     {
3797         int bSuccessMin = FALSE;
3798         int bSuccessMax = FALSE;
3799 
3800         const double dfMin = GetMinimum( &bSuccessMin );
3801         const double dfMax = GetMaximum( &bSuccessMax );
3802 
3803         if( bSuccessMin && bSuccessMax )
3804         {
3805             if( pdfMin != nullptr )
3806                 *pdfMin = dfMin;
3807             if( pdfMax != nullptr )
3808                 *pdfMax = dfMax;
3809             return CE_None;
3810         }
3811     }
3812 
3813 /* -------------------------------------------------------------------- */
3814 /*      Either return without results, or force computation.            */
3815 /* -------------------------------------------------------------------- */
3816     if( !bForce )
3817         return CE_Warning;
3818     else
3819         return ComputeStatistics( bApproxOK,
3820                                   pdfMin, pdfMax, pdfMean, pdfStdDev,
3821                                   GDALDummyProgress, nullptr );
3822 }
3823 
3824 /************************************************************************/
3825 /*                      GDALGetRasterStatistics()                       */
3826 /************************************************************************/
3827 
3828 /**
3829  * \brief Fetch image statistics.
3830  *
3831  * @see GDALRasterBand::GetStatistics()
3832  */
3833 
GDALGetRasterStatistics(GDALRasterBandH hBand,int bApproxOK,int bForce,double * pdfMin,double * pdfMax,double * pdfMean,double * pdfStdDev)3834 CPLErr CPL_STDCALL GDALGetRasterStatistics(
3835     GDALRasterBandH hBand, int bApproxOK, int bForce,
3836     double *pdfMin, double *pdfMax, double *pdfMean, double *pdfStdDev )
3837 
3838 {
3839     VALIDATE_POINTER1( hBand, "GDALGetRasterStatistics", CE_Failure );
3840 
3841     GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
3842     return poBand->GetStatistics(
3843         bApproxOK, bForce, pdfMin, pdfMax, pdfMean, pdfStdDev );
3844 }
3845 
3846 #ifdef CPL_HAS_GINT64
3847 
3848 /************************************************************************/
3849 /*                         GDALUInt128                                  */
3850 /************************************************************************/
3851 
3852 #ifdef HAVE_UINT128_T
3853 class GDALUInt128
3854 {
3855         __uint128_t val;
3856 
GDALUInt128(__uint128_t valIn)3857         explicit GDALUInt128(__uint128_t valIn) : val(valIn) {}
3858 
3859     public:
Mul(GUIntBig first,GUIntBig second)3860         static GDALUInt128 Mul(GUIntBig first, GUIntBig second)
3861         {
3862             // Evaluates to just a single mul on x86_64
3863             return GDALUInt128(static_cast<__uint128_t>(first) * second);
3864         }
3865 
operator -(const GDALUInt128 & other) const3866         GDALUInt128 operator- (const GDALUInt128& other) const
3867         {
3868             return GDALUInt128(val - other.val);
3869         }
3870 
operator double() const3871         operator double() const
3872         {
3873             return static_cast<double>(val);
3874         }
3875 };
3876 #else
3877 
3878 #if defined(_MSC_VER) && defined(_M_X64)
3879 #include <intrin.h>
3880 #endif
3881 
3882 class GDALUInt128
3883 {
3884         GUIntBig low, high;
3885 
GDALUInt128(GUIntBig lowIn,GUIntBig highIn)3886         GDALUInt128(GUIntBig lowIn, GUIntBig highIn):
3887                                         low(lowIn), high(highIn) {}
3888 
3889     public:
Mul(GUIntBig first,GUIntBig second)3890         static GDALUInt128 Mul(GUIntBig first, GUIntBig second)
3891         {
3892 #if defined(_MSC_VER) && defined(_M_X64)
3893             GUIntBig highRes;
3894             GUIntBig lowRes = _umul128(first, second, &highRes);
3895             return GDALUInt128(lowRes, highRes);
3896 #else
3897             const GUInt32 firstLow = static_cast<GUInt32>(first);
3898             const GUInt32 firstHigh = static_cast<GUInt32>(first >> 32);
3899             const GUInt32 secondLow = static_cast<GUInt32>(second);
3900             const GUInt32 secondHigh = static_cast<GUInt32>(second >> 32);
3901             GUIntBig highRes = 0;
3902             const GUIntBig firstLowSecondHigh =
3903                     static_cast<GUIntBig>(firstLow) * secondHigh;
3904             const GUIntBig firstHighSecondLow =
3905                     static_cast<GUIntBig>(firstHigh) * secondLow;
3906             const GUIntBig middleTerm = firstLowSecondHigh + firstHighSecondLow;
3907             if( middleTerm < firstLowSecondHigh ) // check for overflow
3908                 highRes += static_cast<GUIntBig>(1) << 32;
3909             const GUIntBig firstLowSecondLow =
3910                     static_cast<GUIntBig>(firstLow) * secondLow;
3911             GUIntBig lowRes = firstLowSecondLow + (middleTerm << 32);
3912             if( lowRes < firstLowSecondLow ) // check for overflow
3913                 highRes ++;
3914             highRes += (middleTerm >> 32) +
3915                             static_cast<GUIntBig>(firstHigh) * secondHigh;
3916             return GDALUInt128(lowRes, highRes);
3917 #endif
3918         }
3919 
operator -(const GDALUInt128 & other) const3920         GDALUInt128 operator- (const GDALUInt128& other) const
3921         {
3922             GUIntBig highRes = high - other.high;
3923             GUIntBig lowRes = low - other.low;
3924             if (lowRes > low) // check for underflow
3925                 --highRes;
3926             return GDALUInt128(lowRes, highRes);
3927         }
3928 
operator double() const3929         operator double() const
3930         {
3931             const double twoPow64 = 18446744073709551616.0;
3932             return high * twoPow64 + low;
3933         }
3934 };
3935 #endif
3936 
3937 /************************************************************************/
3938 /*                    ComputeStatisticsInternal()                       */
3939 /************************************************************************/
3940 
3941 // The rationale for below optimizations is detailed in statistics.txt
3942 
3943 // Use with T = GDT_Byte or GDT_UInt16 only !
3944 template<class T>
ComputeStatisticsInternalGeneric(int nXCheck,int nBlockXSize,int nYCheck,const T * pData,bool bHasNoData,GUInt32 nNoDataValue,GUInt32 & nMin,GUInt32 & nMax,GUIntBig & nSum,GUIntBig & nSumSquare,GUIntBig & nSampleCount,GUIntBig & nValidCount)3945 static void ComputeStatisticsInternalGeneric( int nXCheck,
3946                                        int nBlockXSize,
3947                                        int nYCheck,
3948                                        const T* pData,
3949                                        bool bHasNoData,
3950                                        GUInt32 nNoDataValue,
3951                                        GUInt32& nMin,
3952                                        GUInt32& nMax,
3953                                        GUIntBig& nSum,
3954                                        GUIntBig& nSumSquare,
3955                                        GUIntBig& nSampleCount,
3956                                        GUIntBig& nValidCount )
3957 {
3958     if( bHasNoData )
3959     {
3960         // General case
3961         for( int iY = 0; iY < nYCheck; iY++ )
3962         {
3963             for( int iX = 0; iX < nXCheck; iX++ )
3964             {
3965                 const GPtrDiff_t iOffset = iX + static_cast<GPtrDiff_t>(iY) * nBlockXSize;
3966                 const GUInt32 nValue = pData[iOffset];
3967                 if( nValue == nNoDataValue )
3968                     continue;
3969                 nValidCount ++;
3970                 if( nValue < nMin )
3971                     nMin = nValue;
3972                 if( nValue > nMax )
3973                     nMax = nValue;
3974                 nSum += nValue;
3975                 nSumSquare += nValue * nValue;
3976             }
3977         }
3978         nSampleCount += static_cast<GUIntBig>(nXCheck) * nYCheck;
3979     }
3980     else if( nMin == std::numeric_limits<T>::min() &&
3981              nMax == std::numeric_limits<T>::max() )
3982     {
3983         // Optimization when there is no nodata and we know we have already
3984         // reached the min and max
3985         for( int iY = 0; iY < nYCheck; iY++ )
3986         {
3987             int iX;
3988             for( iX = 0; iX + 3 < nXCheck; iX+=4 )
3989             {
3990                 const GPtrDiff_t iOffset = iX + static_cast<GPtrDiff_t>(iY) * nBlockXSize;
3991                 const GUInt32 nValue = pData[iOffset];
3992                 const GUInt32 nValue2 = pData[iOffset+1];
3993                 const GUInt32 nValue3 = pData[iOffset+2];
3994                 const GUInt32 nValue4 = pData[iOffset+3];
3995                 nSum += nValue;
3996                 nSumSquare += nValue * nValue;
3997                 nSum += nValue2;
3998                 nSumSquare += nValue2 * nValue2;
3999                 nSum += nValue3;
4000                 nSumSquare += nValue3 * nValue3;
4001                 nSum += nValue4;
4002                 nSumSquare += nValue4 * nValue4;
4003             }
4004             for( ; iX < nXCheck; ++iX )
4005             {
4006                 const GPtrDiff_t iOffset = iX + static_cast<GPtrDiff_t>(iY) * nBlockXSize;
4007                 const GUInt32 nValue = pData[iOffset];
4008                 nSum += nValue;
4009                 nSumSquare += nValue * nValue;
4010             }
4011         }
4012         nSampleCount += static_cast<GUIntBig>(nXCheck) * nYCheck;
4013         nValidCount += static_cast<GUIntBig>(nXCheck) * nYCheck;
4014     }
4015     else
4016     {
4017         for( int iY = 0; iY < nYCheck; iY++ )
4018         {
4019             int iX;
4020             for( iX = 0; iX + 1 < nXCheck; iX+=2 )
4021             {
4022                 const GPtrDiff_t iOffset = iX + static_cast<GPtrDiff_t>(iY) * nBlockXSize;
4023                 const GUInt32 nValue = pData[iOffset];
4024                 const GUInt32 nValue2 = pData[iOffset+1];
4025                 if( nValue < nValue2 )
4026                 {
4027                     if( nValue < nMin )
4028                         nMin = nValue;
4029                     if( nValue2 > nMax )
4030                         nMax = nValue2;
4031                 }
4032                 else
4033                 {
4034                     if( nValue2 < nMin )
4035                         nMin = nValue2;
4036                     if( nValue > nMax )
4037                         nMax = nValue;
4038                 }
4039                 nSum += nValue;
4040                 nSumSquare += nValue * nValue;
4041                 nSum += nValue2;
4042                 nSumSquare += nValue2 * nValue2;
4043             }
4044             if( iX < nXCheck )
4045             {
4046                 const GPtrDiff_t iOffset = iX + static_cast<GPtrDiff_t>(iY) * nBlockXSize;
4047                 const GUInt32 nValue = pData[iOffset];
4048                 if( nValue < nMin )
4049                     nMin = nValue;
4050                 if( nValue > nMax )
4051                     nMax = nValue;
4052                 nSum += nValue;
4053                 nSumSquare += nValue * nValue;
4054             }
4055         }
4056         nSampleCount += static_cast<GUIntBig>(nXCheck) * nYCheck;
4057         nValidCount += static_cast<GUIntBig>(nXCheck) * nYCheck;
4058     }
4059 }
4060 
4061 // Specialization for Byte that is mostly 32 bit friendly as it avoids
4062 // using 64bit accumulators in internal loops. This also slightly helps in
4063 // 64bit mode.
4064 template<>
ComputeStatisticsInternalGeneric(int nXCheck,int nBlockXSize,int nYCheck,const GByte * pData,bool bHasNoData,GUInt32 nNoDataValue,GUInt32 & nMin,GUInt32 & nMax,GUIntBig & nSum,GUIntBig & nSumSquare,GUIntBig & nSampleCount,GUIntBig & nValidCount)4065 void ComputeStatisticsInternalGeneric<GByte>( int nXCheck,
4066                                        int nBlockXSize,
4067                                        int nYCheck,
4068                                        const GByte* pData,
4069                                        bool bHasNoData,
4070                                        GUInt32 nNoDataValue,
4071                                        GUInt32& nMin,
4072                                        GUInt32& nMax,
4073                                        GUIntBig& nSum,
4074                                        GUIntBig& nSumSquare,
4075                                        GUIntBig& nSampleCount,
4076                                        GUIntBig& nValidCount )
4077 {
4078     int nOuterLoops = nXCheck / 65536;
4079     if( nXCheck % 65536 )
4080         nOuterLoops ++;
4081 
4082     if( bHasNoData )
4083     {
4084         // General case
4085         for( int iY = 0; iY < nYCheck; iY++ )
4086         {
4087             int iX = 0;
4088             for( int k=0; k< nOuterLoops; k++ )
4089             {
4090                 int iMax = iX + 65536;
4091                 if (iMax > nXCheck )
4092                     iMax = nXCheck;
4093                 GUInt32 nSum32bit = 0;
4094                 GUInt32 nSumSquare32bit = 0;
4095                 GUInt32 nValidCount32bit = 0;
4096                 GUInt32 nSampleCount32bit = 0;
4097                 for( ; iX < iMax; iX++)
4098                 {
4099                     const GPtrDiff_t iOffset = iX + static_cast<GPtrDiff_t>(iY) * nBlockXSize;
4100                     const GUInt32 nValue = pData[iOffset];
4101 
4102                     nSampleCount32bit ++;
4103                     if( nValue == nNoDataValue )
4104                         continue;
4105                     nValidCount32bit ++;
4106                     if( nValue < nMin )
4107                         nMin = nValue;
4108                     if( nValue > nMax )
4109                         nMax = nValue;
4110                     nSum32bit += nValue;
4111                     nSumSquare32bit += nValue * nValue;
4112                 }
4113                 nSampleCount += nSampleCount32bit;
4114                 nValidCount += nValidCount32bit;
4115                 nSum += nSum32bit;
4116                 nSumSquare += nSumSquare32bit;
4117             }
4118         }
4119     }
4120     else if( nMin == 0 &&
4121              nMax == 255 )
4122     {
4123         // Optimization when there is no nodata and we know we have already
4124         // reached the min and max
4125         for( int iY = 0; iY < nYCheck; iY++ )
4126         {
4127             int iX = 0;
4128             for( int k=0; k< nOuterLoops; k++ )
4129             {
4130                 int iMax = iX + 65536;
4131                 if (iMax > nXCheck )
4132                     iMax = nXCheck;
4133                 GUInt32 nSum32bit = 0;
4134                 GUInt32 nSumSquare32bit = 0;
4135                 for( ; iX + 3 < iMax; iX+=4 )
4136                 {
4137                     const GPtrDiff_t iOffset = iX + static_cast<GPtrDiff_t>(iY) * nBlockXSize;
4138                     const GUInt32 nValue = pData[iOffset];
4139                     const GUInt32 nValue2 = pData[iOffset+1];
4140                     const GUInt32 nValue3 = pData[iOffset+2];
4141                     const GUInt32 nValue4 = pData[iOffset+3];
4142                     nSum32bit += nValue;
4143                     nSumSquare32bit += nValue * nValue;
4144                     nSum32bit += nValue2;
4145                     nSumSquare32bit += nValue2 * nValue2;
4146                     nSum32bit += nValue3;
4147                     nSumSquare32bit += nValue3 * nValue3;
4148                     nSum32bit += nValue4;
4149                     nSumSquare32bit += nValue4 * nValue4;
4150                 }
4151                 nSum += nSum32bit;
4152                 nSumSquare += nSumSquare32bit;
4153             }
4154             for( ; iX < nXCheck; ++iX )
4155             {
4156                 const GPtrDiff_t iOffset = iX + static_cast<GPtrDiff_t>(iY) * nBlockXSize;
4157                 const GUInt32 nValue = pData[iOffset];
4158                 nSum += nValue;
4159                 nSumSquare += nValue * nValue;
4160             }
4161         }
4162         nSampleCount += static_cast<GUIntBig>(nXCheck) * nYCheck;
4163         nValidCount += static_cast<GUIntBig>(nXCheck) * nYCheck;
4164     }
4165     else
4166     {
4167         for( int iY = 0; iY < nYCheck; iY++ )
4168         {
4169             int iX = 0;
4170             for( int k=0; k< nOuterLoops; k++ )
4171             {
4172                 int iMax = iX + 65536;
4173                 if (iMax > nXCheck )
4174                     iMax = nXCheck;
4175                 GUInt32 nSum32bit = 0;
4176                 GUInt32 nSumSquare32bit = 0;
4177                 for( ; iX + 1 < iMax; iX+=2 )
4178                 {
4179                     const GPtrDiff_t iOffset = iX + static_cast<GPtrDiff_t>(iY) * nBlockXSize;
4180                     const GUInt32 nValue = pData[iOffset];
4181                     const GUInt32 nValue2 = pData[iOffset+1];
4182                     if( nValue < nValue2 )
4183                     {
4184                         if( nValue < nMin )
4185                             nMin = nValue;
4186                         if( nValue2 > nMax )
4187                             nMax = nValue2;
4188                     }
4189                     else
4190                     {
4191                         if( nValue2 < nMin )
4192                             nMin = nValue2;
4193                         if( nValue > nMax )
4194                             nMax = nValue;
4195                     }
4196                     nSum32bit += nValue;
4197                     nSumSquare32bit += nValue * nValue;
4198                     nSum32bit += nValue2;
4199                     nSumSquare32bit += nValue2 * nValue2;
4200                 }
4201                 nSum += nSum32bit;
4202                 nSumSquare += nSumSquare32bit;
4203             }
4204             if( iX < nXCheck )
4205             {
4206                 const GPtrDiff_t iOffset = iX + static_cast<GPtrDiff_t>(iY) * nBlockXSize;
4207                 const GUInt32 nValue = pData[iOffset];
4208                 if( nValue < nMin )
4209                     nMin = nValue;
4210                 if( nValue > nMax )
4211                     nMax = nValue;
4212                 nSum += nValue;
4213                 nSumSquare += nValue * nValue;
4214             }
4215         }
4216         nSampleCount += static_cast<GUIntBig>(nXCheck) * nYCheck;
4217         nValidCount += static_cast<GUIntBig>(nXCheck) * nYCheck;
4218     }
4219 }
4220 
4221 template<class T>
ComputeStatisticsInternal(int nXCheck,int nBlockXSize,int nYCheck,const T * pData,bool bHasNoData,GUInt32 nNoDataValue,GUInt32 & nMin,GUInt32 & nMax,GUIntBig & nSum,GUIntBig & nSumSquare,GUIntBig & nSampleCount,GUIntBig & nValidCount)4222 static void ComputeStatisticsInternal( int nXCheck,
4223                                        int nBlockXSize,
4224                                        int nYCheck,
4225                                        const T* pData,
4226                                        bool bHasNoData,
4227                                        GUInt32 nNoDataValue,
4228                                        GUInt32& nMin,
4229                                        GUInt32& nMax,
4230                                        GUIntBig& nSum,
4231                                        GUIntBig& nSumSquare,
4232                                        GUIntBig& nSampleCount,
4233                                        GUIntBig& nValidCount )
4234 {
4235     ComputeStatisticsInternalGeneric( nXCheck, nBlockXSize, nYCheck,
4236                                       pData,
4237                                       bHasNoData, nNoDataValue,
4238                                       nMin, nMax, nSum, nSumSquare,
4239                                       nSampleCount, nValidCount );
4240 }
4241 
4242 #if (defined(__x86_64__) || defined(_M_X64)) && (defined(__GNUC__) || defined(_MSC_VER))
4243 
4244 #include <emmintrin.h>
4245 
4246 #ifdef __SSE4_1__
4247 #include <smmintrin.h>
4248 #endif
4249 
4250 #if defined(__GNUC__)
4251 #define ALIGNED_16(x) x __attribute__ ((aligned (16)))
4252 #else
4253 #define ALIGNED_16(x) __declspec(align(16)) x
4254 #endif
4255 
4256 // Some convenience macros
4257 #define ZERO128                      _mm_setzero_si128()
4258 #ifdef __SSE4_1__
4259 #define EXTEND_UINT16_TO_UINT32(reg) _mm_cvtepu16_epi32(reg)
4260 #else
4261 #define EXTEND_UINT16_TO_UINT32(reg) _mm_unpacklo_epi16(reg, ZERO128)
4262 #endif
4263 #define GET_HIGH_64BIT(reg)          _mm_shuffle_epi32(reg, 2 | (3 << 2))
4264 
4265 #include "gdal_avx2_emulation.hpp"
4266 
4267 #define ZERO256                      GDALmm256_setzero_si256()
4268 
4269 // SSE2/AVX2 optimization for GByte case
4270 // In pure SSE2, this relies on gdal_avx2_emulation.hpp. There is no
4271 // penaly in using the emulation, because, given the mm256 intrinsics used here,
4272 // there are strictly equivalent to 2 parallel SSE2 streams.
4273 template<>
ComputeStatisticsInternal(int nXCheck,int nBlockXSize,int nYCheck,const GByte * pData,bool bHasNoData,GUInt32 nNoDataValue,GUInt32 & nMin,GUInt32 & nMax,GUIntBig & nSum,GUIntBig & nSumSquare,GUIntBig & nSampleCount,GUIntBig & nValidCount)4274 void ComputeStatisticsInternal<GByte>( int nXCheck,
4275                                        int nBlockXSize,
4276                                        int nYCheck,
4277                                        // assumed to be aligned on 256 bits
4278                                        const GByte* pData,
4279                                        bool bHasNoData,
4280                                        GUInt32 nNoDataValue,
4281                                        GUInt32& nMin,
4282                                        GUInt32& nMax,
4283                                        GUIntBig& nSum,
4284                                        GUIntBig& nSumSquare,
4285                                        GUIntBig& nSampleCount,
4286                                        GUIntBig& nValidCount )
4287 {
4288     const auto nBlockPixels = static_cast<GPtrDiff_t>(nXCheck) * nYCheck;
4289     if( bHasNoData && nXCheck == nBlockXSize && nBlockPixels >= 32 &&
4290         nMin <= nMax )
4291     {
4292         // 32-byte alignment may not be enforced by linker, so do it at hand
4293         GByte aby32ByteUnaligned[32+32+32+32+32];
4294         GByte* paby32ByteAligned = aby32ByteUnaligned +
4295                                     (32 - (reinterpret_cast<GUIntptr_t>(aby32ByteUnaligned) % 32));
4296         GByte* pabyMin = paby32ByteAligned;
4297         GByte* pabyMax = paby32ByteAligned + 32;
4298         GUInt32* panSum = reinterpret_cast<GUInt32*>(paby32ByteAligned + 32*2);
4299         GUInt32* panSumSquare = reinterpret_cast<GUInt32*>(paby32ByteAligned + 32*3);
4300 
4301         GPtrDiff_t i = 0;
4302         // Make sure that sumSquare can fit on uint32
4303         // * 8 since we can hold 8 sums per vector register
4304         const int nMaxIterationsPerInnerLoop = 8 *
4305                 ((std::numeric_limits<GUInt32>::max() / (255 * 255)) & ~31);
4306         auto nOuterLoops = nBlockPixels / nMaxIterationsPerInnerLoop;
4307         if( (nBlockPixels % nMaxIterationsPerInnerLoop) != 0 )
4308             nOuterLoops ++;
4309 
4310         const GDALm256i ymm_nodata = GDALmm256_set1_epi8(
4311                                         static_cast<GByte>(nNoDataValue) );
4312         // any non noData value in [min,max] would do.
4313         const GDALm256i ymm_neutral = GDALmm256_set1_epi8(
4314                                         static_cast<GByte>(nMin) );
4315         GDALm256i ymm_min = ymm_neutral;
4316         GDALm256i ymm_max = ymm_neutral;
4317 
4318         const bool bComputeMinMax = nMin > 0 || nMax < 255;
4319 
4320         for( GPtrDiff_t k=0; k< nOuterLoops; k++ )
4321         {
4322             const auto iMax = std::min(nBlockPixels, i + nMaxIterationsPerInnerLoop);
4323 
4324             // holds 4 uint32 sums in [0], [2], [4] and [6]
4325             GDALm256i ymm_sum = ZERO256;
4326             // holds 8 uint32 sums
4327             GDALm256i ymm_sumsquare = ZERO256;
4328             // holds 4 uint32 sums in [0], [2], [4] and [6]
4329             GDALm256i ymm_count_nodata_mul_255 = ZERO256;
4330             const auto iInit = i;
4331             for( ;i+31<iMax; i+=32 )
4332             {
4333                 const GDALm256i ymm = GDALmm256_load_si256(reinterpret_cast<const GDALm256i*>(pData + i));
4334 
4335                 // Check which values are nodata
4336                 const GDALm256i ymm_eq_nodata =
4337                                         GDALmm256_cmpeq_epi8( ymm, ymm_nodata );
4338                 // Count how many values are nodata (due to cmpeq putting 255
4339                 // when condition is met, this will actually be 255 times
4340                 // the number of nodata value, spread in 4 64 bits words).
4341                 // We can use add_epi32 as the counter will not overflow uint32
4342                 ymm_count_nodata_mul_255 = GDALmm256_add_epi32 (
4343                                     ymm_count_nodata_mul_255,
4344                                     GDALmm256_sad_epu8(ymm_eq_nodata, ZERO256) );
4345                 // Replace all nodata values by zero for the purpose of sum
4346                 // and sumquare.
4347                 const GDALm256i ymm_nodata_by_zero =
4348                                 GDALmm256_andnot_si256(ymm_eq_nodata, ymm);
4349                 if( bComputeMinMax )
4350                 {
4351                     // Replace all nodata values by a neutral value for the
4352                     // purpose of min and max.
4353                     const GDALm256i ymm_nodata_by_neutral = GDALmm256_or_si256(
4354                                 GDALmm256_and_si256(ymm_eq_nodata, ymm_neutral),
4355                                 ymm_nodata_by_zero);
4356 
4357                     ymm_min = GDALmm256_min_epu8 (ymm_min,
4358                                                   ymm_nodata_by_neutral);
4359                     ymm_max = GDALmm256_max_epu8 (ymm_max,
4360                                                   ymm_nodata_by_neutral);
4361                 }
4362 
4363                 // Extend lower 128 bits of ymm from uint8 to uint16
4364                 const GDALm256i ymm_low = GDALmm256_cvtepu8_epi16(
4365                             GDALmm256_extracti128_si256(ymm_nodata_by_zero, 0));
4366                 // Compute square of those 16 values as 32 bit result
4367                 // and add adjacent pairs
4368                 const GDALm256i ymm_low_square =
4369                                             GDALmm256_madd_epi16(ymm_low, ymm_low);
4370                 // Add to the sumsquare accumulator
4371                 ymm_sumsquare = GDALmm256_add_epi32(ymm_sumsquare, ymm_low_square);
4372 
4373                 // Same as before with high 128bits of ymm
4374                 const GDALm256i ymm_high = GDALmm256_cvtepu8_epi16(
4375                             GDALmm256_extracti128_si256(ymm_nodata_by_zero, 1));
4376                 const GDALm256i ymm_high_square =
4377                                         GDALmm256_madd_epi16(ymm_high, ymm_high);
4378                 ymm_sumsquare = GDALmm256_add_epi32(ymm_sumsquare, ymm_high_square);
4379 
4380                 // Now compute the sums
4381                 ymm_sum = GDALmm256_add_epi32(ymm_sum,
4382                                 GDALmm256_sad_epu8(ymm_nodata_by_zero, ZERO256));
4383             }
4384 
4385             GUInt32* panCoutNoDataMul255 = panSum;
4386             GDALmm256_store_si256(reinterpret_cast<GDALm256i*>(panCoutNoDataMul255),
4387                                ymm_count_nodata_mul_255);
4388 
4389             nSampleCount += (i - iInit);
4390 
4391             nValidCount += (i - iInit) -
4392                         (panCoutNoDataMul255[0] + panCoutNoDataMul255[2] +
4393                          panCoutNoDataMul255[4] + panCoutNoDataMul255[6]) / 255;
4394 
4395             GDALmm256_store_si256(reinterpret_cast<GDALm256i*>(panSum), ymm_sum);
4396             GDALmm256_store_si256(reinterpret_cast<GDALm256i*>(panSumSquare), ymm_sumsquare);
4397             nSum += panSum[0] + panSum[2] + panSum[4] + panSum[6];
4398             nSumSquare += static_cast<GUIntBig>(panSumSquare[0]) +
4399                           panSumSquare[1] + panSumSquare[2] + panSumSquare[3] +
4400                           panSumSquare[4] + panSumSquare[5] + panSumSquare[6] +
4401                           panSumSquare[7];
4402         }
4403 
4404         if( bComputeMinMax )
4405         {
4406             GDALmm256_store_si256(reinterpret_cast<GDALm256i*>(pabyMin), ymm_min);
4407             GDALmm256_store_si256(reinterpret_cast<GDALm256i*>(pabyMax), ymm_max);
4408             for(int j=0;j<32;j++)
4409             {
4410                 if( pabyMin[j] < nMin ) nMin = pabyMin[j];
4411                 if( pabyMax[j] > nMax ) nMax = pabyMax[j];
4412             }
4413         }
4414 
4415         for( ; i<nBlockPixels; i++)
4416         {
4417             const GUInt32 nValue = pData[i];
4418             nSampleCount ++;
4419             if( nValue == nNoDataValue )
4420                 continue;
4421             nValidCount ++;
4422             if( nValue < nMin )
4423                 nMin = nValue;
4424             if( nValue > nMax )
4425                 nMax = nValue;
4426             nSum += nValue;
4427             nSumSquare += nValue * nValue;
4428         }
4429     }
4430     else if( !bHasNoData && nXCheck == nBlockXSize && nBlockPixels >= 32 )
4431     {
4432         // 32-byte alignment may not be enforced by linker, so do it at hand
4433         GByte aby32ByteUnaligned[32+32+32+32+32];
4434         GByte* paby32ByteAligned = aby32ByteUnaligned +
4435                                     (32 - (reinterpret_cast<GUIntptr_t>(aby32ByteUnaligned) % 32));
4436         GByte* pabyMin = paby32ByteAligned;
4437         GByte* pabyMax = paby32ByteAligned + 32;
4438         GUInt32* panSum = reinterpret_cast<GUInt32*>(paby32ByteAligned + 32*2);
4439         GUInt32* panSumSquare = reinterpret_cast<GUInt32*>(paby32ByteAligned + 32*3);
4440 
4441         GPtrDiff_t i = 0;
4442         // Make sure that sumSquare can fit on uint32
4443         // * 8 since we can hold 8 sums per vector register
4444         const int nMaxIterationsPerInnerLoop = 8 *
4445                 ((std::numeric_limits<GUInt32>::max() / (255 * 255)) & ~31);
4446         GPtrDiff_t nOuterLoops = nBlockPixels / nMaxIterationsPerInnerLoop;
4447         if( (nBlockPixels % nMaxIterationsPerInnerLoop) != 0 )
4448             nOuterLoops ++;
4449 
4450         GDALm256i ymm_min = GDALmm256_load_si256(reinterpret_cast<const GDALm256i*>(pData + i));
4451         GDALm256i ymm_max = ymm_min;
4452 
4453         const bool bComputeMinMax = nMin > 0 || nMax < 255;
4454 
4455         for( GPtrDiff_t k=0; k< nOuterLoops; k++ )
4456         {
4457             const auto iMax = std::min(nBlockPixels, i + nMaxIterationsPerInnerLoop);
4458 
4459             // holds 4 uint32 sums in [0], [2], [4] and [6]
4460             GDALm256i ymm_sum = ZERO256;
4461             GDALm256i ymm_sumsquare = ZERO256; // holds 8 uint32 sums
4462             for( ;i+31<iMax; i+=32 )
4463             {
4464                 const GDALm256i ymm = GDALmm256_load_si256(reinterpret_cast<const GDALm256i*>(pData + i));
4465                 if( bComputeMinMax )
4466                 {
4467                     ymm_min = GDALmm256_min_epu8 (ymm_min, ymm);
4468                     ymm_max = GDALmm256_max_epu8 (ymm_max, ymm);
4469                 }
4470 
4471                 // Extend lower 128 bits of ymm from uint8 to uint16
4472                 const GDALm256i ymm_low = GDALmm256_cvtepu8_epi16(
4473                                             GDALmm256_extracti128_si256(ymm, 0));
4474                 // Compute square of those 16 values as 32 bit result
4475                 // and add adjacent pairs
4476                 const GDALm256i ymm_low_square =
4477                                             GDALmm256_madd_epi16(ymm_low, ymm_low);
4478                 // Add to the sumsquare accumulator
4479                 ymm_sumsquare = GDALmm256_add_epi32(ymm_sumsquare, ymm_low_square);
4480 
4481                 // Same as before with high 128bits of ymm
4482                 const GDALm256i ymm_high = GDALmm256_cvtepu8_epi16(
4483                                             GDALmm256_extracti128_si256(ymm, 1));
4484                 const GDALm256i ymm_high_square =
4485                                         GDALmm256_madd_epi16(ymm_high, ymm_high);
4486                 ymm_sumsquare = GDALmm256_add_epi32(ymm_sumsquare, ymm_high_square);
4487 
4488                 // Now compute the sums
4489                 ymm_sum = GDALmm256_add_epi32(ymm_sum,
4490                                            GDALmm256_sad_epu8(ymm, ZERO256));
4491             }
4492 
4493             GDALmm256_store_si256(reinterpret_cast<GDALm256i*>(panSum), ymm_sum);
4494             GDALmm256_store_si256(reinterpret_cast<GDALm256i*>(panSumSquare), ymm_sumsquare);
4495 
4496             nSum += panSum[0] + panSum[2] + panSum[4] + panSum[6];
4497             nSumSquare += static_cast<GUIntBig>(panSumSquare[0]) +
4498                           panSumSquare[1] + panSumSquare[2] + panSumSquare[3] +
4499                           panSumSquare[4] + panSumSquare[5] + panSumSquare[6] +
4500                           panSumSquare[7];
4501         }
4502 
4503         if( bComputeMinMax )
4504         {
4505             GDALmm256_store_si256(reinterpret_cast<GDALm256i*>(pabyMin), ymm_min);
4506             GDALmm256_store_si256(reinterpret_cast<GDALm256i*>(pabyMax), ymm_max);
4507             for(int j=0;j<32;j++)
4508             {
4509                 if( pabyMin[j] < nMin ) nMin = pabyMin[j];
4510                 if( pabyMax[j] > nMax ) nMax = pabyMax[j];
4511             }
4512         }
4513 
4514         for( ; i<nBlockPixels; i++)
4515         {
4516             const GUInt32 nValue = pData[i];
4517             if( nValue < nMin )
4518                 nMin = nValue;
4519             if( nValue > nMax )
4520                 nMax = nValue;
4521             nSum += nValue;
4522             nSumSquare += nValue * nValue;
4523         }
4524 
4525         nSampleCount += static_cast<GUIntBig>(nXCheck) * nYCheck;
4526         nValidCount += static_cast<GUIntBig>(nXCheck) * nYCheck;
4527     }
4528     else
4529     {
4530         ComputeStatisticsInternalGeneric( nXCheck, nBlockXSize, nYCheck,
4531                                           pData,
4532                                           bHasNoData, nNoDataValue,
4533                                           nMin, nMax, nSum, nSumSquare,
4534                                           nSampleCount, nValidCount );
4535     }
4536 }
4537 
4538 CPL_NOSANITIZE_UNSIGNED_INT_OVERFLOW
UnshiftSumSquare(GUIntBig & nSumSquare,GUIntBig nSumThis,GUIntBig i)4539 static void UnshiftSumSquare( GUIntBig& nSumSquare,
4540                               GUIntBig  nSumThis,
4541                               GUIntBig  i )
4542 {
4543     nSumSquare += 32768 * (2 * nSumThis - i * 32768);
4544 }
4545 
4546 // AVX2/SSE2 optimization for GUInt16 case
4547 template<>
ComputeStatisticsInternal(int nXCheck,int nBlockXSize,int nYCheck,const GUInt16 * pData,bool bHasNoData,GUInt32 nNoDataValue,GUInt32 & nMin,GUInt32 & nMax,GUIntBig & nSum,GUIntBig & nSumSquare,GUIntBig & nSampleCount,GUIntBig & nValidCount)4548 void ComputeStatisticsInternal<GUInt16>( int nXCheck,
4549                                        int nBlockXSize,
4550                                        int nYCheck,
4551                                        // assumed to be aligned on 128 bits
4552                                        const GUInt16* pData,
4553                                        bool bHasNoData,
4554                                        GUInt32 nNoDataValue,
4555                                        GUInt32& nMin,
4556                                        GUInt32& nMax,
4557                                        GUIntBig& nSum,
4558                                        GUIntBig& nSumSquare,
4559                                        GUIntBig& nSampleCount,
4560                                        GUIntBig& nValidCount )
4561 {
4562     const auto nBlockPixels = static_cast<GPtrDiff_t>(nXCheck) * nYCheck;
4563     if( !bHasNoData && nXCheck == nBlockXSize && nBlockPixels >= 16 )
4564     {
4565         GPtrDiff_t i = 0;
4566         // In SSE2, min_epu16 and max_epu16 do not exist, so shift from
4567         // UInt16 to SInt16 to be able to use min_epi16 and max_epi16.
4568         // Furthermore the shift is also needed to use madd_epi16
4569         const GDALm256i ymm_m32768 = GDALmm256_set1_epi16(-32768);
4570         GDALm256i ymm_min = GDALmm256_load_si256(reinterpret_cast<const GDALm256i*>(pData + i));
4571         ymm_min = GDALmm256_add_epi16(ymm_min, ymm_m32768);
4572         GDALm256i ymm_max = ymm_min;
4573         GDALm256i ymm_sumsquare = ZERO256; // holds 4 uint64 sums
4574 
4575         // Make sure that sum can fit on uint32
4576         // * 8 since we can hold 8 sums per vector register
4577         const int nMaxIterationsPerInnerLoop = 8 *
4578                 ((std::numeric_limits<GUInt32>::max() / 65535) & ~15);
4579         GPtrDiff_t nOuterLoops = nBlockPixels / nMaxIterationsPerInnerLoop;
4580         if( (nBlockPixels % nMaxIterationsPerInnerLoop) != 0 )
4581             nOuterLoops ++;
4582 
4583         const bool bComputeMinMax = nMin > 0 || nMax < 65535;
4584 
4585         GUIntBig nSumThis = 0;
4586         for( int k=0; k< nOuterLoops; k++ )
4587         {
4588             const auto iMax = std::min(nBlockPixels, i + nMaxIterationsPerInnerLoop);
4589 
4590             GDALm256i ymm_sum = ZERO256; // holds 8 uint32 sums
4591             for( ;i+15<iMax ; i+=16 )
4592             {
4593                 const GDALm256i ymm = GDALmm256_load_si256(reinterpret_cast<const GDALm256i*>(pData + i));
4594                 const GDALm256i ymm_shifted = GDALmm256_add_epi16(ymm, ymm_m32768);
4595                 if( bComputeMinMax )
4596                 {
4597                     ymm_min = GDALmm256_min_epi16 (ymm_min, ymm_shifted);
4598                     ymm_max = GDALmm256_max_epi16 (ymm_max, ymm_shifted);
4599                 }
4600 
4601                 // Extend the 8 lower uint16 to uint32
4602                 const GDALm256i ymm_low = GDALmm256_cvtepu16_epi32(
4603                                             GDALmm256_extracti128_si256(ymm, 0));
4604                 const GDALm256i ymm_high = GDALmm256_cvtepu16_epi32(
4605                                             GDALmm256_extracti128_si256(ymm, 1));
4606 
4607 #ifndef naive_version
4608                 // Note: the int32 range can overflow for (0-32768)^2 +
4609                 // (0-32768)^2 = 0x80000000, but as we know the result is
4610                 // positive, this is OK as we interpret is a uint32.
4611                 const GDALm256i ymm_square = GDALmm256_madd_epi16(ymm_shifted,
4612                                                                   ymm_shifted);
4613                 const GDALm256i ymm_square_low = GDALmm256_cvtepu32_epi64(
4614                                     GDALmm256_extracti128_si256(ymm_square, 0));
4615                 ymm_sumsquare = GDALmm256_add_epi64(ymm_sumsquare,
4616                                                     ymm_square_low);
4617                 const GDALm256i ymm_square_high = GDALmm256_cvtepu32_epi64(
4618                                     GDALmm256_extracti128_si256(ymm_square, 1));
4619                 ymm_sumsquare = GDALmm256_add_epi64(ymm_sumsquare,
4620                                                     ymm_square_high);
4621 #else
4622                 // Compute square of those 8 values
4623                 const GDALm256i ymm_low2 = GDALmm256_mullo_epi32(ymm_low, ymm_low);
4624                 // Extract 4 low uint32 and extend them to uint64
4625                 const GDALm256i ymm_low2_low = GDALmm256_cvtepu32_epi64(
4626                                             GDALmm256_extracti128_si256(ymm_low2, 0));
4627                 // Extract 4 high uint32 and extend them to uint64
4628                 const GDALm256i ymm_low2_high = GDALmm256_cvtepu32_epi64(
4629                                             GDALmm256_extracti128_si256(ymm_low2, 1));
4630                 // Add to the sumsquare accumulator
4631                 ymm_sumsquare = GDALmm256_add_epi64(ymm_sumsquare, ymm_low2_low);
4632                 ymm_sumsquare = GDALmm256_add_epi64(ymm_sumsquare, ymm_low2_high);
4633 
4634                 // Same with the 8 upper uint16
4635                 const GDALm256i ymm_high2 = GDALmm256_mullo_epi32(ymm_high, ymm_high);
4636                 const GDALm256i ymm_high2_low = GDALmm256_cvtepu32_epi64(
4637                                             GDALmm256_extracti128_si256(ymm_high2, 0));
4638                 const GDALm256i ymm_high2_high = GDALmm256_cvtepu32_epi64(
4639                                             GDALmm256_extracti128_si256(ymm_high2, 1));
4640                 ymm_sumsquare = GDALmm256_add_epi64(ymm_sumsquare, ymm_high2_low);
4641                 ymm_sumsquare = GDALmm256_add_epi64(ymm_sumsquare, ymm_high2_high);
4642 #endif
4643 
4644                 // Now compute the sums
4645                 ymm_sum = GDALmm256_add_epi32(ymm_sum, ymm_low);
4646                 ymm_sum = GDALmm256_add_epi32(ymm_sum, ymm_high);
4647             }
4648 
4649             GUInt32 anSum[8];
4650             GDALmm256_storeu_si256(reinterpret_cast<GDALm256i*>(anSum), ymm_sum);
4651             nSumThis += static_cast<GUIntBig>(anSum[0]) + anSum[1] +
4652                     anSum[2] + anSum[3] + anSum[4] + anSum[5] +
4653                     anSum[6] + anSum[7];
4654         }
4655 
4656         if( bComputeMinMax )
4657         {
4658             GUInt16 anMin[16];
4659             GUInt16 anMax[16];
4660 
4661             // Unshift the result
4662             ymm_min = GDALmm256_sub_epi16(ymm_min, ymm_m32768);
4663             ymm_max = GDALmm256_sub_epi16(ymm_max, ymm_m32768);
4664             GDALmm256_storeu_si256(reinterpret_cast<GDALm256i*>(anMin), ymm_min);
4665             GDALmm256_storeu_si256(reinterpret_cast<GDALm256i*>(anMax), ymm_max);
4666             for(int j=0;j<16;j++)
4667             {
4668                 if( anMin[j] < nMin ) nMin = anMin[j];
4669                 if( anMax[j] > nMax ) nMax = anMax[j];
4670             }
4671         }
4672 
4673         GUIntBig anSumSquare[4];
4674         GDALmm256_storeu_si256(reinterpret_cast<GDALm256i*>(anSumSquare), ymm_sumsquare);
4675         nSumSquare += anSumSquare[0] +
4676                         anSumSquare[1] + anSumSquare[2] + anSumSquare[3];
4677 #ifndef naive_version
4678         // Unshift the sum of squares
4679         UnshiftSumSquare(nSumSquare, nSumThis, static_cast<GUIntBig>(i));
4680 #endif
4681         nSum += nSumThis;
4682 
4683         for( ; i<nBlockPixels; i++)
4684         {
4685             const GUInt32 nValue = pData[i];
4686             if( nValue < nMin )
4687                 nMin = nValue;
4688             if( nValue > nMax )
4689                 nMax = nValue;
4690             nSum += nValue;
4691             nSumSquare += nValue * nValue;
4692         }
4693 
4694         nSampleCount += static_cast<GUIntBig>(nXCheck) * nYCheck;
4695         nValidCount += static_cast<GUIntBig>(nXCheck) * nYCheck;
4696     }
4697     else
4698     {
4699         ComputeStatisticsInternalGeneric( nXCheck, nBlockXSize, nYCheck,
4700                                           pData,
4701                                           bHasNoData, nNoDataValue,
4702                                           nMin, nMax, nSum, nSumSquare,
4703                                           nSampleCount, nValidCount );
4704     }
4705 }
4706 
4707 #endif // (defined(__x86_64__) || defined(_M_X64)) && (defined(__GNUC__) || defined(_MSC_VER))
4708 
4709 #endif // CPL_HAS_GINT64
4710 
4711 
4712 /************************************************************************/
4713 /*                          GetPixelValue()                             */
4714 /************************************************************************/
4715 
4716 static
GetPixelValue(GDALDataType eDataType,bool bSignedByte,const void * pData,GPtrDiff_t iOffset,bool bGotNoDataValue,double dfNoDataValue,bool bGotFloatNoDataValue,float fNoDataValue,bool & bValid)4717 inline double GetPixelValue( GDALDataType eDataType,
4718                              bool bSignedByte,
4719                              const void* pData,
4720                              GPtrDiff_t iOffset,
4721                              bool bGotNoDataValue,
4722                              double dfNoDataValue,
4723                              bool bGotFloatNoDataValue,
4724                              float fNoDataValue,
4725                              bool& bValid )
4726 {
4727     bValid = true;
4728     double dfValue;
4729     switch( eDataType )
4730     {
4731         case GDT_Byte:
4732         {
4733             if( bSignedByte )
4734                 dfValue = static_cast<const signed char *>(pData)[iOffset];
4735             else
4736                 dfValue = static_cast<const GByte *>(pData)[iOffset];
4737             break;
4738         }
4739         case GDT_UInt16:
4740             dfValue = static_cast<const GUInt16 *>(pData)[iOffset];
4741             break;
4742         case GDT_Int16:
4743             dfValue = static_cast<const GInt16 *>(pData)[iOffset];
4744             break;
4745         case GDT_UInt32:
4746             dfValue = static_cast<const GUInt32 *>(pData)[iOffset];
4747             break;
4748         case GDT_Int32:
4749             dfValue = static_cast<const GInt32 *>(pData)[iOffset];
4750             break;
4751         case GDT_Float32:
4752         {
4753             const float fValue = static_cast<const float *>(pData)[iOffset];
4754             if( CPLIsNan(fValue) ||
4755                 (bGotFloatNoDataValue && ARE_REAL_EQUAL(fValue, fNoDataValue)) )
4756             {
4757                 bValid = false;
4758                 return 0.0;
4759             }
4760             dfValue = fValue;
4761             return dfValue;
4762         }
4763         case GDT_Float64:
4764             dfValue = static_cast<const double *>(pData)[iOffset];
4765             if( CPLIsNan(dfValue) )
4766             {
4767                 bValid = false;
4768                 return 0.0;
4769             }
4770             break;
4771         case GDT_CInt16:
4772             dfValue = static_cast<const GInt16 *>(pData)[iOffset*2];
4773             break;
4774         case GDT_CInt32:
4775             dfValue = static_cast<const GInt32 *>(pData)[iOffset*2];
4776             break;
4777         case GDT_CFloat32:
4778             dfValue = static_cast<const float *>(pData)[iOffset*2];
4779             if( CPLIsNan(dfValue) )
4780             {
4781                 bValid = false;
4782                 return 0.0;
4783             }
4784             break;
4785         case GDT_CFloat64:
4786             dfValue = static_cast<const double *>(pData)[iOffset*2];
4787             if( CPLIsNan(dfValue) )
4788             {
4789                 bValid = false;
4790                 return 0.0;
4791             }
4792             break;
4793         default:
4794 #ifndef CSA_BUILD
4795             dfValue = 0.0;
4796 #endif
4797             CPLAssert( false );
4798     }
4799 
4800     if( bGotNoDataValue && ARE_REAL_EQUAL(dfValue, dfNoDataValue) )
4801     {
4802         bValid = false;
4803         return 0.0;
4804     }
4805     return dfValue;
4806 }
4807 
4808 /************************************************************************/
4809 /*                         SetValidPercent()                            */
4810 /************************************************************************/
4811 
4812 /**
4813  * \brief Set percentage of valid (not nodata) pixels.
4814  *
4815  * Stores the percentage of valid pixels in the metadata item
4816  * STATISTICS_VALID_PERCENT
4817  *
4818  * @param nSampleCount Number of sampled pixels.
4819  *
4820  * @param nValidCount Number of valid pixels.
4821  */
4822 
SetValidPercent(GUIntBig nSampleCount,GUIntBig nValidCount)4823 void GDALRasterBand::SetValidPercent(GUIntBig nSampleCount, GUIntBig nValidCount)
4824 {
4825     if( nValidCount == 0 )
4826     {
4827         SetMetadataItem( "STATISTICS_VALID_PERCENT", "0" );
4828     }
4829     else if( nValidCount == nSampleCount )
4830     {
4831         SetMetadataItem( "STATISTICS_VALID_PERCENT", "100" );
4832     }
4833     else /* nValidCount < nSampleCount */
4834     {
4835         char szValue[128] = { 0 };
4836 
4837         /* percentage is only an indicator: limit precision */
4838         CPLsnprintf( szValue, sizeof(szValue), "%.4g",
4839                  100. * static_cast<double>(nValidCount) / nSampleCount );
4840 
4841         if (EQUAL(szValue, "100"))
4842         {
4843             /* don't set 100 percent valid
4844              * because some of the sampled pixels were nodata */
4845             SetMetadataItem( "STATISTICS_VALID_PERCENT", "99.999" );
4846         }
4847         else
4848         {
4849             SetMetadataItem( "STATISTICS_VALID_PERCENT", szValue );
4850         }
4851     }
4852 }
4853 
4854 /************************************************************************/
4855 /*                         ComputeStatistics()                          */
4856 /************************************************************************/
4857 
4858 /**
4859  * \brief Compute image statistics.
4860  *
4861  * Returns the minimum, maximum, mean and standard deviation of all
4862  * pixel values in this band.  If approximate statistics are sufficient,
4863  * the bApproxOK flag can be set to true in which case overviews, or a
4864  * subset of image tiles may be used in computing the statistics.
4865  *
4866  * Once computed, the statistics will generally be "set" back on the
4867  * raster band using SetStatistics().
4868  *
4869  * Cached statistics can be cleared with GDALDataset::ClearStatistics().
4870  *
4871  * This method is the same as the C function GDALComputeRasterStatistics().
4872  *
4873  * @param bApproxOK If TRUE statistics may be computed based on overviews
4874  * or a subset of all tiles.
4875  *
4876  * @param pdfMin Location into which to load image minimum (may be NULL).
4877  *
4878  * @param pdfMax Location into which to load image maximum (may be NULL).-
4879  *
4880  * @param pdfMean Location into which to load image mean (may be NULL).
4881  *
4882  * @param pdfStdDev Location into which to load image standard deviation
4883  * (may be NULL).
4884  *
4885  * @param pfnProgress a function to call to report progress, or NULL.
4886  *
4887  * @param pProgressData application data to pass to the progress function.
4888  *
4889  * @return CE_None on success, or CE_Failure if an error occurs or processing
4890  * is terminated by the user.
4891  */
4892 
4893 CPLErr
ComputeStatistics(int bApproxOK,double * pdfMin,double * pdfMax,double * pdfMean,double * pdfStdDev,GDALProgressFunc pfnProgress,void * pProgressData)4894 GDALRasterBand::ComputeStatistics( int bApproxOK,
4895                                    double *pdfMin, double *pdfMax,
4896                                    double *pdfMean, double *pdfStdDev,
4897                                    GDALProgressFunc pfnProgress,
4898                                    void *pProgressData )
4899 
4900 {
4901     if( pfnProgress == nullptr )
4902         pfnProgress = GDALDummyProgress;
4903 
4904 /* -------------------------------------------------------------------- */
4905 /*      If we have overview bands, use them for statistics.             */
4906 /* -------------------------------------------------------------------- */
4907     if( bApproxOK && GetOverviewCount() > 0 && !HasArbitraryOverviews() )
4908     {
4909         GDALRasterBand *poBand
4910             = GetRasterSampleOverview( GDALSTAT_APPROX_NUMSAMPLES );
4911 
4912         if( poBand != this )
4913         {
4914             CPLErr eErr = poBand->ComputeStatistics( FALSE,
4915                                               pdfMin, pdfMax,
4916                                               pdfMean, pdfStdDev,
4917                                               pfnProgress, pProgressData );
4918             if( eErr == CE_None )
4919             {
4920                 if( pdfMin && pdfMax && pdfMean && pdfStdDev )
4921                 {
4922                     SetMetadataItem( "STATISTICS_APPROXIMATE", "YES" );
4923                     SetStatistics( *pdfMin,*pdfMax, *pdfMean, *pdfStdDev );
4924                 }
4925 
4926                 /* transfer metadata from overview band to this */
4927                 const char *pszPercentValid = poBand->GetMetadataItem("STATISTICS_VALID_PERCENT");
4928 
4929                 if ( pszPercentValid != nullptr )
4930                 {
4931                     SetMetadataItem( "STATISTICS_VALID_PERCENT", pszPercentValid );
4932                 }
4933             }
4934             return eErr;
4935         }
4936     }
4937 
4938     if( !pfnProgress( 0.0, "Compute Statistics", pProgressData ) )
4939     {
4940         ReportError( CE_Failure, CPLE_UserInterrupt, "User terminated" );
4941         return CE_Failure;
4942     }
4943 
4944 /* -------------------------------------------------------------------- */
4945 /*      Read actual data and compute statistics.                        */
4946 /* -------------------------------------------------------------------- */
4947     bool bFirstValue = true;
4948     // Using Welford algorithm:
4949     // http://en.wikipedia.org/wiki/Algorithms_for_calculating_variance
4950     // to compute standard deviation in a more numerically robust way than
4951     // the difference of the sum of square values with the square of the sum.
4952     // dfMean and dfM2 are updated at each sample.
4953     // dfM2 is the sum of square of differences to the current mean.
4954     double dfMin = 0.0;
4955     double dfMax = 0.0;
4956     double dfMean = 0.0;
4957     double dfM2 = 0.0;
4958 
4959     GDALRasterIOExtraArg sExtraArg;
4960     INIT_RASTERIO_EXTRA_ARG(sExtraArg);
4961 
4962     int bGotNoDataValue = FALSE;
4963     const double dfNoDataValue = GetNoDataValue( &bGotNoDataValue );
4964     bGotNoDataValue = bGotNoDataValue && !CPLIsNan(dfNoDataValue);
4965     bool bGotFloatNoDataValue = false;
4966     float fNoDataValue = 0.0f;
4967     ComputeFloatNoDataValue( eDataType, dfNoDataValue, bGotNoDataValue,
4968                             fNoDataValue, bGotFloatNoDataValue );
4969 
4970     const char* pszPixelType =
4971         GetMetadataItem("PIXELTYPE", "IMAGE_STRUCTURE");
4972     const bool bSignedByte =
4973         pszPixelType != nullptr && EQUAL(pszPixelType, "SIGNEDBYTE");
4974 
4975     GUIntBig nSampleCount = 0;
4976     GUIntBig nValidCount = 0;
4977 
4978     if ( bApproxOK && HasArbitraryOverviews() )
4979     {
4980 /* -------------------------------------------------------------------- */
4981 /*      Figure out how much the image should be reduced to get an       */
4982 /*      approximate value.                                              */
4983 /* -------------------------------------------------------------------- */
4984         double  dfReduction = sqrt(
4985             static_cast<double>(nRasterXSize) * nRasterYSize /
4986             GDALSTAT_APPROX_NUMSAMPLES );
4987 
4988         int nXReduced = nRasterXSize;
4989         int nYReduced = nRasterYSize;
4990         if ( dfReduction > 1.0 )
4991         {
4992             nXReduced = static_cast<int>( nRasterXSize / dfReduction );
4993             nYReduced = static_cast<int>( nRasterYSize / dfReduction );
4994 
4995             // Catch the case of huge resizing ratios here
4996             if ( nXReduced == 0 )
4997                 nXReduced = 1;
4998             if ( nYReduced == 0 )
4999                 nYReduced = 1;
5000         }
5001 
5002         void *pData =
5003             CPLMalloc(
5004                 GDALGetDataTypeSizeBytes(eDataType) * nXReduced * nYReduced );
5005 
5006         const CPLErr eErr = IRasterIO(
5007             GF_Read, 0, 0, nRasterXSize, nRasterYSize, pData,
5008             nXReduced, nYReduced, eDataType, 0, 0, &sExtraArg );
5009         if ( eErr != CE_None )
5010         {
5011             CPLFree(pData);
5012             return eErr;
5013         }
5014 
5015         /* this isn't the fastest way to do this, but is easier for now */
5016         for( int iY = 0; iY < nYReduced; iY++ )
5017         {
5018             for( int iX = 0; iX < nXReduced; iX++ )
5019             {
5020                 const int iOffset = iX + iY * nXReduced;
5021                 bool bValid = true;
5022                 double dfValue = GetPixelValue( eDataType,
5023                                                 bSignedByte,
5024                                                 pData,
5025                                                 iOffset,
5026                                                 CPL_TO_BOOL(bGotNoDataValue),
5027                                                 dfNoDataValue,
5028                                                 bGotFloatNoDataValue,
5029                                                 fNoDataValue,
5030                                                 bValid );
5031                 nSampleCount++;
5032                 if( !bValid )
5033                     continue;
5034 
5035                 if( bFirstValue )
5036                 {
5037                     dfMin = dfValue;
5038                     dfMax = dfValue;
5039                     bFirstValue = false;
5040                 }
5041                 else
5042                 {
5043                     dfMin = std::min(dfMin, dfValue);
5044                     dfMax = std::max(dfMax, dfValue);
5045                 }
5046 
5047                 nValidCount++;
5048                 const double dfDelta = dfValue - dfMean;
5049                 dfMean += dfDelta / nValidCount;
5050                 dfM2 += dfDelta * (dfValue - dfMean);
5051             }
5052         }
5053 
5054         CPLFree( pData );
5055     }
5056 
5057     else  // No arbitrary overviews.
5058     {
5059         if( !InitBlockInfo() )
5060             return CE_Failure;
5061 
5062 /* -------------------------------------------------------------------- */
5063 /*      Figure out the ratio of blocks we will read to get an           */
5064 /*      approximate value.                                              */
5065 /* -------------------------------------------------------------------- */
5066         int nSampleRate = 1;
5067         if ( bApproxOK )
5068         {
5069             nSampleRate = static_cast<int>(
5070                 std::max(1.0,
5071                          sqrt(static_cast<double>(nBlocksPerRow) *
5072                               nBlocksPerColumn)));
5073             // We want to avoid probing only the first column of blocks for
5074             // a square shaped raster, because it is not unlikely that it may
5075             // be padding only (#6378)
5076             if( nSampleRate == nBlocksPerRow && nBlocksPerRow > 1 )
5077               nSampleRate += 1;
5078         }
5079         if( nSampleRate == 1 )
5080             bApproxOK = false;
5081 
5082 #ifdef CPL_HAS_GINT64
5083         // Particular case for GDT_Byte that only use integral types for all
5084         // intermediate computations. Only possible if the number of pixels
5085         // explored is lower than GUINTBIG_MAX / (255*255), so that nSumSquare
5086         // can fit on a uint64. Should be 99.99999% of cases.
5087         // For GUInt16, this limits to raster of 4 giga pixels
5088         if( (eDataType == GDT_Byte && !bSignedByte &&
5089              static_cast<GUIntBig>(nBlocksPerRow)*nBlocksPerColumn/nSampleRate <
5090                 GUINTBIG_MAX / (255U * 255U) /
5091                         (static_cast<GUInt64>(nBlockXSize) * static_cast<GUInt64>(nBlockYSize))) ||
5092             (eDataType == GDT_UInt16 &&
5093              static_cast<GUIntBig>(nBlocksPerRow)*nBlocksPerColumn/nSampleRate <
5094                 GUINTBIG_MAX / (65535U * 65535U) /
5095                         (static_cast<GUInt64>(nBlockXSize) * static_cast<GUInt64>(nBlockYSize))) )
5096         {
5097             const GUInt32 nMaxValueType = (eDataType == GDT_Byte) ? 255 : 65535;
5098             GUInt32 nMin = nMaxValueType;
5099             GUInt32 nMax = 0;
5100             GUIntBig nSum = 0;
5101             GUIntBig nSumSquare = 0;
5102             // If no valid nodata, map to invalid value (256 for Byte)
5103             const GUInt32 nNoDataValue =
5104                 (bGotNoDataValue && dfNoDataValue >= 0 &&
5105                  dfNoDataValue <= nMaxValueType &&
5106                  fabs(dfNoDataValue -
5107                       static_cast<GUInt32>(dfNoDataValue + 1e-10)) < 1e-10 ) ?
5108                             static_cast<GUInt32>(dfNoDataValue + 1e-10) :
5109                             nMaxValueType+1;
5110 
5111             for( int iSampleBlock = 0;
5112                 iSampleBlock < nBlocksPerRow * nBlocksPerColumn;
5113                 iSampleBlock += nSampleRate )
5114             {
5115                 const int iYBlock = iSampleBlock / nBlocksPerRow;
5116                 const int iXBlock = iSampleBlock - nBlocksPerRow * iYBlock;
5117 
5118                 GDALRasterBlock * const poBlock =
5119                     GetLockedBlockRef( iXBlock, iYBlock );
5120                 if( poBlock == nullptr )
5121                     return CE_Failure;
5122 
5123                 void* const pData = poBlock->GetDataRef();
5124 
5125                 int nXCheck = 0, nYCheck = 0;
5126                 GetActualBlockSize(iXBlock, iYBlock, &nXCheck, &nYCheck);
5127 
5128                 if( eDataType == GDT_Byte )
5129                 {
5130                     ComputeStatisticsInternal( nXCheck,
5131                                                nBlockXSize,
5132                                                nYCheck,
5133                                                static_cast<const GByte*>(pData),
5134                                                nNoDataValue <= nMaxValueType,
5135                                                nNoDataValue,
5136                                                nMin, nMax, nSum,
5137                                                nSumSquare,
5138                                                nSampleCount,
5139                                                nValidCount );
5140                 }
5141                 else
5142                 {
5143                     ComputeStatisticsInternal( nXCheck,
5144                                                nBlockXSize,
5145                                                nYCheck,
5146                                                static_cast<const GUInt16*>(pData),
5147                                                nNoDataValue <= nMaxValueType,
5148                                                nNoDataValue,
5149                                                nMin, nMax, nSum,
5150                                                nSumSquare,
5151                                                nSampleCount,
5152                                                nValidCount );
5153                 }
5154 
5155                 poBlock->DropLock();
5156 
5157                 if ( !pfnProgress( iSampleBlock
5158                         / static_cast<double>(nBlocksPerRow*nBlocksPerColumn),
5159                         "Compute Statistics", pProgressData) )
5160                 {
5161                     ReportError( CE_Failure, CPLE_UserInterrupt,
5162                                  "User terminated" );
5163                     return CE_Failure;
5164                 }
5165             }
5166 
5167             if( !pfnProgress( 1.0, "Compute Statistics", pProgressData ) )
5168             {
5169                 ReportError( CE_Failure, CPLE_UserInterrupt,
5170                              "User terminated" );
5171                 return CE_Failure;
5172             }
5173 
5174 /* -------------------------------------------------------------------- */
5175 /*      Save computed information.                                      */
5176 /* -------------------------------------------------------------------- */
5177             if( nValidCount )
5178                 dfMean = static_cast<double>(nSum) / nValidCount;
5179 
5180             // To avoid potential precision issues when doing the difference,
5181             // we need to do that computation on 128 bit rather than casting
5182             // to double
5183             const GDALUInt128 nTmpForStdDev(
5184                     GDALUInt128::Mul(nSumSquare,nValidCount) -
5185                     GDALUInt128::Mul(nSum,nSum));
5186             const double dfStdDev =
5187                 nValidCount > 0 ?
5188                     sqrt(static_cast<double>(nTmpForStdDev)) / nValidCount :
5189                     0.0;
5190 
5191             if( nValidCount > 0 )
5192             {
5193                 if( bApproxOK )
5194                 {
5195                     SetMetadataItem( "STATISTICS_APPROXIMATE", "YES" );
5196                 }
5197                 else if( GetMetadataItem( "STATISTICS_APPROXIMATE" ) )
5198                 {
5199                     SetMetadataItem( "STATISTICS_APPROXIMATE",  nullptr );
5200                 }
5201                 SetStatistics( nMin, nMax, dfMean, dfStdDev );
5202             }
5203 
5204         SetValidPercent( nSampleCount, nValidCount );
5205 
5206 /* -------------------------------------------------------------------- */
5207 /*      Record results.                                                 */
5208 /* -------------------------------------------------------------------- */
5209             if( pdfMin != nullptr )
5210                 *pdfMin = nValidCount ? nMin : 0;
5211             if( pdfMax != nullptr )
5212                 *pdfMax = nValidCount ? nMax : 0;
5213 
5214             if( pdfMean != nullptr )
5215                 *pdfMean = dfMean;
5216 
5217             if( pdfStdDev != nullptr )
5218                 *pdfStdDev = dfStdDev;
5219 
5220             if( nValidCount > 0 )
5221                 return CE_None;
5222 
5223             ReportError(
5224                 CE_Failure, CPLE_AppDefined,
5225                 "Failed to compute statistics, no valid pixels found in sampling." );
5226             return CE_Failure;
5227         }
5228 #endif
5229 
5230         for( int iSampleBlock = 0;
5231              iSampleBlock < nBlocksPerRow * nBlocksPerColumn;
5232              iSampleBlock += nSampleRate )
5233         {
5234             const int iYBlock = iSampleBlock / nBlocksPerRow;
5235             const int iXBlock = iSampleBlock - nBlocksPerRow * iYBlock;
5236 
5237             GDALRasterBlock * const poBlock = GetLockedBlockRef( iXBlock, iYBlock );
5238             if( poBlock == nullptr )
5239                 return CE_Failure;
5240 
5241             void* const pData = poBlock->GetDataRef();
5242 
5243             int nXCheck = 0, nYCheck = 0;
5244             GetActualBlockSize(iXBlock, iYBlock, &nXCheck, &nYCheck);
5245 
5246             // This isn't the fastest way to do this, but is easier for now.
5247             for( int iY = 0; iY < nYCheck; iY++ )
5248             {
5249                 for( int iX = 0; iX < nXCheck; iX++ )
5250                 {
5251                     const GPtrDiff_t iOffset = iX + static_cast<GPtrDiff_t>(iY) * nBlockXSize;
5252                     bool bValid = true;
5253                     double dfValue = GetPixelValue( eDataType,
5254                                                     bSignedByte,
5255                                                     pData,
5256                                                     iOffset,
5257                                                     CPL_TO_BOOL(bGotNoDataValue),
5258                                                     dfNoDataValue,
5259                                                     bGotFloatNoDataValue,
5260                                                     fNoDataValue,
5261                                                     bValid );
5262 
5263                     nSampleCount++;
5264                     if( !bValid )
5265                         continue;
5266 
5267                     if( bFirstValue )
5268                     {
5269                         dfMin = dfValue;
5270                         dfMax = dfValue;
5271                         bFirstValue = false;
5272                     }
5273                     else
5274                     {
5275                         dfMin = std::min(dfMin, dfValue);
5276                         dfMax = std::max(dfMax, dfValue);
5277                     }
5278 
5279                     nValidCount++;
5280                     const double dfDelta = dfValue - dfMean;
5281                     dfMean += dfDelta / nValidCount;
5282                     dfM2 += dfDelta * (dfValue - dfMean);
5283                 }
5284             }
5285 
5286             poBlock->DropLock();
5287 
5288             if ( !pfnProgress(
5289                      iSampleBlock
5290                          / static_cast<double>(nBlocksPerRow*nBlocksPerColumn),
5291                      "Compute Statistics", pProgressData) )
5292             {
5293                 ReportError( CE_Failure, CPLE_UserInterrupt, "User terminated" );
5294                 return CE_Failure;
5295             }
5296         }
5297     }
5298 
5299     if( !pfnProgress( 1.0, "Compute Statistics", pProgressData ) )
5300     {
5301         ReportError( CE_Failure, CPLE_UserInterrupt, "User terminated" );
5302         return CE_Failure;
5303     }
5304 
5305 /* -------------------------------------------------------------------- */
5306 /*      Save computed information.                                      */
5307 /* -------------------------------------------------------------------- */
5308     const double dfStdDev =
5309         nValidCount > 0 ? sqrt(dfM2 / nValidCount) : 0.0;
5310 
5311     if( nValidCount > 0 )
5312     {
5313         if( bApproxOK )
5314         {
5315             SetMetadataItem( "STATISTICS_APPROXIMATE", "YES" );
5316         }
5317         else if( GetMetadataItem( "STATISTICS_APPROXIMATE" ) )
5318         {
5319             SetMetadataItem( "STATISTICS_APPROXIMATE",  nullptr );
5320         }
5321         SetStatistics( dfMin, dfMax, dfMean, dfStdDev );
5322     }
5323 
5324     SetValidPercent( nSampleCount, nValidCount );
5325 
5326 /* -------------------------------------------------------------------- */
5327 /*      Record results.                                                 */
5328 /* -------------------------------------------------------------------- */
5329     if( pdfMin != nullptr )
5330         *pdfMin = dfMin;
5331     if( pdfMax != nullptr )
5332         *pdfMax = dfMax;
5333 
5334     if( pdfMean != nullptr )
5335         *pdfMean = dfMean;
5336 
5337     if( pdfStdDev != nullptr )
5338         *pdfStdDev = dfStdDev;
5339 
5340     if( nValidCount > 0 )
5341         return CE_None;
5342 
5343     ReportError(
5344         CE_Failure, CPLE_AppDefined,
5345         "Failed to compute statistics, no valid pixels found in sampling." );
5346     return CE_Failure;
5347 }
5348 
5349 /************************************************************************/
5350 /*                    GDALComputeRasterStatistics()                     */
5351 /************************************************************************/
5352 
5353 /**
5354   * \brief Compute image statistics.
5355   *
5356   * @see GDALRasterBand::ComputeStatistics()
5357   */
5358 
GDALComputeRasterStatistics(GDALRasterBandH hBand,int bApproxOK,double * pdfMin,double * pdfMax,double * pdfMean,double * pdfStdDev,GDALProgressFunc pfnProgress,void * pProgressData)5359 CPLErr CPL_STDCALL GDALComputeRasterStatistics(
5360         GDALRasterBandH hBand, int bApproxOK,
5361         double *pdfMin, double *pdfMax, double *pdfMean, double *pdfStdDev,
5362         GDALProgressFunc pfnProgress, void *pProgressData )
5363 
5364 {
5365     VALIDATE_POINTER1( hBand, "GDALComputeRasterStatistics", CE_Failure );
5366 
5367     GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
5368 
5369     return poBand->ComputeStatistics(
5370         bApproxOK, pdfMin, pdfMax, pdfMean, pdfStdDev,
5371         pfnProgress, pProgressData );
5372 }
5373 
5374 /************************************************************************/
5375 /*                           SetStatistics()                            */
5376 /************************************************************************/
5377 
5378 /**
5379  * \brief Set statistics on band.
5380  *
5381  * This method can be used to store min/max/mean/standard deviation
5382  * statistics on a raster band.
5383  *
5384  * The default implementation stores them as metadata, and will only work
5385  * on formats that can save arbitrary metadata.  This method cannot detect
5386  * whether metadata will be properly saved and so may return CE_None even
5387  * if the statistics will never be saved.
5388  *
5389  * This method is the same as the C function GDALSetRasterStatistics().
5390  *
5391  * @param dfMin minimum pixel value.
5392  *
5393  * @param dfMax maximum pixel value.
5394  *
5395  * @param dfMean mean (average) of all pixel values.
5396  *
5397  * @param dfStdDev Standard deviation of all pixel values.
5398  *
5399  * @return CE_None on success or CE_Failure on failure.
5400  */
5401 
SetStatistics(double dfMin,double dfMax,double dfMean,double dfStdDev)5402 CPLErr GDALRasterBand::SetStatistics( double dfMin, double dfMax,
5403                                       double dfMean, double dfStdDev )
5404 
5405 {
5406     char szValue[128] = { 0 };
5407 
5408     CPLsnprintf( szValue, sizeof(szValue), "%.14g", dfMin );
5409     SetMetadataItem( "STATISTICS_MINIMUM", szValue );
5410 
5411     CPLsnprintf( szValue, sizeof(szValue), "%.14g", dfMax );
5412     SetMetadataItem( "STATISTICS_MAXIMUM", szValue );
5413 
5414     CPLsnprintf( szValue, sizeof(szValue), "%.14g", dfMean );
5415     SetMetadataItem( "STATISTICS_MEAN", szValue );
5416 
5417     CPLsnprintf( szValue, sizeof(szValue), "%.14g", dfStdDev );
5418     SetMetadataItem( "STATISTICS_STDDEV", szValue );
5419 
5420     return CE_None;
5421 }
5422 
5423 /************************************************************************/
5424 /*                      GDALSetRasterStatistics()                       */
5425 /************************************************************************/
5426 
5427 /**
5428  * \brief Set statistics on band.
5429  *
5430  * @see GDALRasterBand::SetStatistics()
5431  */
5432 
GDALSetRasterStatistics(GDALRasterBandH hBand,double dfMin,double dfMax,double dfMean,double dfStdDev)5433 CPLErr CPL_STDCALL GDALSetRasterStatistics(
5434         GDALRasterBandH hBand,
5435         double dfMin, double dfMax, double dfMean, double dfStdDev )
5436 
5437 {
5438     VALIDATE_POINTER1( hBand, "GDALSetRasterStatistics", CE_Failure );
5439 
5440     GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
5441     return poBand->SetStatistics( dfMin, dfMax, dfMean, dfStdDev );
5442 }
5443 
5444 /************************************************************************/
5445 /*                        ComputeRasterMinMax()                         */
5446 /************************************************************************/
5447 
5448 /**
5449  * \brief Compute the min/max values for a band.
5450  *
5451  * If approximate is OK, then the band's GetMinimum()/GetMaximum() will
5452  * be trusted.  If it doesn't work, a subsample of blocks will be read to
5453  * get an approximate min/max.  If the band has a nodata value it will
5454  * be excluded from the minimum and maximum.
5455  *
5456  * If bApprox is FALSE, then all pixels will be read and used to compute
5457  * an exact range.
5458  *
5459  * This method is the same as the C function GDALComputeRasterMinMax().
5460  *
5461  * @param bApproxOK TRUE if an approximate (faster) answer is OK, otherwise
5462  * FALSE.
5463  * @param adfMinMax the array in which the minimum (adfMinMax[0]) and the
5464  * maximum (adfMinMax[1]) are returned.
5465  *
5466  * @return CE_None on success or CE_Failure on failure.
5467  */
5468 
ComputeRasterMinMax(int bApproxOK,double * adfMinMax)5469 CPLErr GDALRasterBand::ComputeRasterMinMax( int bApproxOK,
5470                                             double* adfMinMax )
5471 {
5472     double dfMin = 0.0;
5473     double dfMax = 0.0;
5474 
5475 /* -------------------------------------------------------------------- */
5476 /*      Does the driver already know the min/max?                       */
5477 /* -------------------------------------------------------------------- */
5478     if( bApproxOK )
5479     {
5480         int bSuccessMin = FALSE;
5481         int bSuccessMax = FALSE;
5482 
5483         dfMin = GetMinimum( &bSuccessMin );
5484         dfMax = GetMaximum( &bSuccessMax );
5485 
5486         if( bSuccessMin && bSuccessMax )
5487         {
5488             adfMinMax[0] = dfMin;
5489             adfMinMax[1] = dfMax;
5490             return CE_None;
5491         }
5492     }
5493 
5494 /* -------------------------------------------------------------------- */
5495 /*      If we have overview bands, use them for min/max.                */
5496 /* -------------------------------------------------------------------- */
5497     // cppcheck-suppress knownConditionTrueFalse
5498     if ( bApproxOK && GetOverviewCount() > 0 && !HasArbitraryOverviews() )
5499     {
5500         GDALRasterBand *poBand =
5501           GetRasterSampleOverview( GDALSTAT_APPROX_NUMSAMPLES );
5502 
5503         if ( poBand != this )
5504             return poBand->ComputeRasterMinMax( FALSE, adfMinMax );
5505     }
5506 
5507 /* -------------------------------------------------------------------- */
5508 /*      Read actual data and compute minimum and maximum.               */
5509 /* -------------------------------------------------------------------- */
5510     int bGotNoDataValue = FALSE;
5511     const double dfNoDataValue = GetNoDataValue( &bGotNoDataValue );
5512     bGotNoDataValue = bGotNoDataValue && !CPLIsNan(dfNoDataValue);
5513     bool bGotFloatNoDataValue = false;
5514     float fNoDataValue = 0.0f;
5515     ComputeFloatNoDataValue( eDataType, dfNoDataValue, bGotNoDataValue,
5516                             fNoDataValue, bGotFloatNoDataValue );
5517 
5518     const char* pszPixelType = GetMetadataItem("PIXELTYPE", "IMAGE_STRUCTURE");
5519     const bool bSignedByte =
5520         pszPixelType != nullptr && EQUAL(pszPixelType, "SIGNEDBYTE");
5521 
5522     GDALRasterIOExtraArg sExtraArg;
5523     INIT_RASTERIO_EXTRA_ARG(sExtraArg);
5524 
5525     bool bFirstValue = true;
5526     if ( bApproxOK && HasArbitraryOverviews() )
5527     {
5528 /* -------------------------------------------------------------------- */
5529 /*      Figure out how much the image should be reduced to get an       */
5530 /*      approximate value.                                              */
5531 /* -------------------------------------------------------------------- */
5532         double  dfReduction = sqrt(
5533             static_cast<double>(nRasterXSize) * nRasterYSize /
5534             GDALSTAT_APPROX_NUMSAMPLES );
5535 
5536         int nXReduced = nRasterXSize;
5537         int nYReduced = nRasterYSize;
5538         if ( dfReduction > 1.0 )
5539         {
5540             nXReduced = static_cast<int>( nRasterXSize / dfReduction );
5541             nYReduced = static_cast<int>( nRasterYSize / dfReduction );
5542 
5543             // Catch the case of huge resizing ratios here
5544             if ( nXReduced == 0 )
5545                 nXReduced = 1;
5546             if ( nYReduced == 0 )
5547                 nYReduced = 1;
5548         }
5549 
5550         void * const pData =
5551             CPLMalloc(
5552                 GDALGetDataTypeSizeBytes(eDataType) * nXReduced * nYReduced );
5553 
5554         const CPLErr eErr = IRasterIO(
5555             GF_Read, 0, 0, nRasterXSize, nRasterYSize, pData,
5556             nXReduced, nYReduced, eDataType, 0, 0, &sExtraArg );
5557         if ( eErr != CE_None )
5558         {
5559             CPLFree(pData);
5560             return eErr;
5561         }
5562 
5563         /* this isn't the fastest way to do this, but is easier for now */
5564         for( int iY = 0; iY < nYReduced; iY++ )
5565         {
5566             for( int iX = 0; iX < nXReduced; iX++ )
5567             {
5568                 const int iOffset = iX + iY * nXReduced;
5569                 bool bValid = true;
5570                 double dfValue = GetPixelValue( eDataType,
5571                                                 bSignedByte,
5572                                                 pData,
5573                                                 iOffset,
5574                                                 CPL_TO_BOOL(bGotNoDataValue),
5575                                                 dfNoDataValue,
5576                                                 bGotFloatNoDataValue,
5577                                                 fNoDataValue,
5578                                                 bValid );
5579                 if( !bValid )
5580                     continue;
5581 
5582                 if( bFirstValue )
5583                 {
5584                     dfMin = dfValue;
5585                     dfMax = dfValue;
5586                     bFirstValue = false;
5587                 }
5588                 else
5589                 {
5590                     dfMin = std::min(dfMin, dfValue);
5591                     dfMax = std::max(dfMax, dfValue);
5592                 }
5593             }
5594         }
5595 
5596         CPLFree( pData );
5597     }
5598 
5599     else  // No arbitrary overviews
5600     {
5601         if( !InitBlockInfo() )
5602             return CE_Failure;
5603 
5604 /* -------------------------------------------------------------------- */
5605 /*      Figure out the ratio of blocks we will read to get an           */
5606 /*      approximate value.                                              */
5607 /* -------------------------------------------------------------------- */
5608         int nSampleRate = 1;
5609 
5610         if ( bApproxOK )
5611         {
5612             nSampleRate = static_cast<int>(
5613                 std::max(1.0,
5614                          sqrt(static_cast<double>(nBlocksPerRow) *
5615                               nBlocksPerColumn)));
5616             // We want to avoid probing only the first column of blocks for
5617             // a square shaped raster, because it is not unlikely that it may
5618             // be padding only (#6378).
5619             if( nSampleRate == nBlocksPerRow && nBlocksPerRow > 1 )
5620               nSampleRate += 1;
5621         }
5622 
5623         for( int iSampleBlock = 0;
5624              iSampleBlock < nBlocksPerRow * nBlocksPerColumn;
5625              iSampleBlock += nSampleRate )
5626         {
5627             const int iYBlock = iSampleBlock / nBlocksPerRow;
5628             const int iXBlock = iSampleBlock - nBlocksPerRow * iYBlock;
5629 
5630             GDALRasterBlock *poBlock = GetLockedBlockRef( iXBlock, iYBlock );
5631             if( poBlock == nullptr )
5632                 return CE_Failure;
5633 
5634             void * const pData = poBlock->GetDataRef();
5635 
5636             int nXCheck = 0, nYCheck = 0;
5637             GetActualBlockSize(iXBlock, iYBlock, &nXCheck, &nYCheck);
5638 
5639             // This isn't the fastest way to do this, but is easier for now.
5640             for( int iY = 0; iY < nYCheck; iY++ )
5641             {
5642                 for( int iX = 0; iX < nXCheck; iX++ )
5643                 {
5644                     const GPtrDiff_t iOffset = iX + static_cast<GPtrDiff_t>(iY) * nBlockXSize;
5645                     bool bValid = true;
5646                     double dfValue = GetPixelValue( eDataType,
5647                                                     bSignedByte,
5648                                                     pData,
5649                                                     iOffset,
5650                                                     CPL_TO_BOOL(bGotNoDataValue),
5651                                                     dfNoDataValue,
5652                                                     bGotFloatNoDataValue,
5653                                                     fNoDataValue,
5654                                                     bValid );
5655                     if( !bValid )
5656                         continue;
5657 
5658                     if( bFirstValue )
5659                     {
5660                         dfMin = dfValue;
5661                         dfMax = dfValue;
5662                         bFirstValue = false;
5663                     }
5664                     else
5665                     {
5666                         dfMin = std::min(dfMin, dfValue);
5667                         dfMax = std::max(dfMax, dfValue);
5668                     }
5669                 }
5670             }
5671 
5672             poBlock->DropLock();
5673         }
5674     }
5675 
5676     adfMinMax[0] = dfMin;
5677     adfMinMax[1] = dfMax;
5678 
5679     if (bFirstValue)
5680     {
5681         ReportError(
5682             CE_Failure, CPLE_AppDefined,
5683             "Failed to compute min/max, no valid pixels found in sampling." );
5684         return CE_Failure;
5685     }
5686 
5687     return CE_None;
5688 }
5689 
5690 /************************************************************************/
5691 /*                      GDALComputeRasterMinMax()                       */
5692 /************************************************************************/
5693 
5694 /**
5695  * \brief Compute the min/max values for a band.
5696  *
5697  * @see GDALRasterBand::ComputeRasterMinMax()
5698  */
5699 
5700 void CPL_STDCALL
GDALComputeRasterMinMax(GDALRasterBandH hBand,int bApproxOK,double adfMinMax[2])5701 GDALComputeRasterMinMax( GDALRasterBandH hBand, int bApproxOK,
5702                          double adfMinMax[2] )
5703 
5704 {
5705     VALIDATE_POINTER0( hBand, "GDALComputeRasterMinMax" );
5706 
5707     GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
5708     poBand->ComputeRasterMinMax( bApproxOK, adfMinMax );
5709 }
5710 
5711 /************************************************************************/
5712 /*                        SetDefaultHistogram()                         */
5713 /************************************************************************/
5714 
5715 /* FIXME : add proper documentation */
5716 /**
5717  * \brief Set default histogram.
5718  *
5719  * This method is the same as the C function GDALSetDefaultHistogram() and
5720  * GDALSetDefaultHistogramEx()
5721  */
SetDefaultHistogram(double,double,int,GUIntBig *)5722 CPLErr GDALRasterBand::SetDefaultHistogram( double /* dfMin */,
5723                                             double /* dfMax */,
5724                                             int /* nBuckets */,
5725                                             GUIntBig * /* panHistogram */)
5726 
5727 {
5728     if( !(GetMOFlags() & GMO_IGNORE_UNIMPLEMENTED) )
5729         ReportError( CE_Failure, CPLE_NotSupported,
5730                      "SetDefaultHistogram() not implemented for this format." );
5731 
5732     return CE_Failure;
5733 }
5734 
5735 /************************************************************************/
5736 /*                      GDALSetDefaultHistogram()                       */
5737 /************************************************************************/
5738 
5739 /**
5740  * \brief Set default histogram.
5741  *
5742  * Use GDALSetRasterHistogramEx() instead to be able to set counts exceeding
5743  * 2 billion.
5744  *
5745  * @see GDALRasterBand::SetDefaultHistogram()
5746  * @see GDALSetRasterHistogramEx()
5747  */
5748 
GDALSetDefaultHistogram(GDALRasterBandH hBand,double dfMin,double dfMax,int nBuckets,int * panHistogram)5749 CPLErr CPL_STDCALL GDALSetDefaultHistogram( GDALRasterBandH hBand,
5750                                             double dfMin, double dfMax,
5751                                             int nBuckets, int *panHistogram )
5752 
5753 {
5754     VALIDATE_POINTER1( hBand, "GDALSetDefaultHistogram", CE_Failure );
5755 
5756     GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
5757 
5758     GUIntBig* panHistogramTemp = static_cast<GUIntBig *>(
5759         VSIMalloc2(sizeof(GUIntBig), nBuckets) );
5760     if( panHistogramTemp == nullptr )
5761     {
5762         poBand->ReportError(
5763             CE_Failure, CPLE_OutOfMemory,
5764             "Out of memory in GDALSetDefaultHistogram()." );
5765         return CE_Failure;
5766     }
5767 
5768     for( int i = 0; i < nBuckets; ++i )
5769     {
5770         panHistogramTemp[i] = static_cast<GUIntBig>(panHistogram[i]);
5771     }
5772 
5773     const CPLErr eErr =
5774         poBand->SetDefaultHistogram( dfMin, dfMax, nBuckets, panHistogramTemp );
5775 
5776     CPLFree(panHistogramTemp);
5777 
5778     return eErr;
5779 }
5780 
5781 /************************************************************************/
5782 /*                     GDALSetDefaultHistogramEx()                      */
5783 /************************************************************************/
5784 
5785 /**
5786  * \brief Set default histogram.
5787  *
5788  * @see GDALRasterBand::SetDefaultHistogram()
5789  *
5790  * @since GDAL 2.0
5791  */
5792 
GDALSetDefaultHistogramEx(GDALRasterBandH hBand,double dfMin,double dfMax,int nBuckets,GUIntBig * panHistogram)5793 CPLErr CPL_STDCALL GDALSetDefaultHistogramEx( GDALRasterBandH hBand,
5794                                               double dfMin, double dfMax,
5795                                               int nBuckets,
5796                                               GUIntBig *panHistogram )
5797 
5798 {
5799     VALIDATE_POINTER1( hBand, "GDALSetDefaultHistogramEx", CE_Failure );
5800 
5801     GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
5802     return poBand->SetDefaultHistogram( dfMin, dfMax, nBuckets, panHistogram );
5803 }
5804 
5805 /************************************************************************/
5806 /*                           GetDefaultRAT()                            */
5807 /************************************************************************/
5808 
5809 /**
5810  * \brief Fetch default Raster Attribute Table.
5811  *
5812  * A RAT will be returned if there is a default one associated with the
5813  * band, otherwise NULL is returned.  The returned RAT is owned by the
5814  * band and should not be deleted by the application.
5815  *
5816  * This method is the same as the C function GDALGetDefaultRAT().
5817  *
5818  * @return NULL, or a pointer to an internal RAT owned by the band.
5819  */
5820 
GetDefaultRAT()5821 GDALRasterAttributeTable *GDALRasterBand::GetDefaultRAT()
5822 
5823 {
5824     return nullptr;
5825 }
5826 
5827 /************************************************************************/
5828 /*                         GDALGetDefaultRAT()                          */
5829 /************************************************************************/
5830 
5831 /**
5832  * \brief Fetch default Raster Attribute Table.
5833  *
5834  * @see GDALRasterBand::GetDefaultRAT()
5835  */
5836 
GDALGetDefaultRAT(GDALRasterBandH hBand)5837 GDALRasterAttributeTableH CPL_STDCALL GDALGetDefaultRAT( GDALRasterBandH hBand)
5838 
5839 {
5840     VALIDATE_POINTER1( hBand, "GDALGetDefaultRAT", nullptr );
5841 
5842     GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
5843     return GDALRasterAttributeTable::ToHandle(poBand->GetDefaultRAT());
5844 }
5845 
5846 /************************************************************************/
5847 /*                           SetDefaultRAT()                            */
5848 /************************************************************************/
5849 
5850 /**
5851  * \fn GDALRasterBand::SetDefaultRAT(const GDALRasterAttributeTable*)
5852  * \brief Set default Raster Attribute Table.
5853  *
5854  * Associates a default RAT with the band.  If not implemented for the
5855  * format a CPLE_NotSupported error will be issued.  If successful a copy
5856  * of the RAT is made, the original remains owned by the caller.
5857  *
5858  * This method is the same as the C function GDALSetDefaultRAT().
5859  *
5860  * @param poRAT the RAT to assign to the band.
5861  *
5862  * @return CE_None on success or CE_Failure if unsupported or otherwise
5863  * failing.
5864  */
5865 
5866 /**/
5867 /**/
5868 
SetDefaultRAT(const GDALRasterAttributeTable *)5869 CPLErr GDALRasterBand::SetDefaultRAT(
5870     const GDALRasterAttributeTable * /* poRAT */ )
5871 {
5872     if( !(GetMOFlags() & GMO_IGNORE_UNIMPLEMENTED) )
5873     {
5874         CPLPushErrorHandler(CPLQuietErrorHandler);
5875         ReportError( CE_Failure, CPLE_NotSupported,
5876                      "SetDefaultRAT() not implemented for this format." );
5877         CPLPopErrorHandler();
5878     }
5879     return CE_Failure;
5880 }
5881 
5882 /************************************************************************/
5883 /*                         GDALSetDefaultRAT()                          */
5884 /************************************************************************/
5885 
5886 /**
5887  * \brief Set default Raster Attribute Table.
5888  *
5889  * @see GDALRasterBand::GDALSetDefaultRAT()
5890  */
5891 
GDALSetDefaultRAT(GDALRasterBandH hBand,GDALRasterAttributeTableH hRAT)5892 CPLErr CPL_STDCALL GDALSetDefaultRAT( GDALRasterBandH hBand,
5893                                       GDALRasterAttributeTableH hRAT )
5894 
5895 {
5896     VALIDATE_POINTER1( hBand, "GDALSetDefaultRAT", CE_Failure );
5897 
5898     GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
5899 
5900     return poBand->SetDefaultRAT(
5901         GDALRasterAttributeTable::FromHandle(hRAT) );
5902 }
5903 
5904 /************************************************************************/
5905 /*                            GetMaskBand()                             */
5906 /************************************************************************/
5907 
5908 /**
5909  * \brief Return the mask band associated with the band.
5910  *
5911  * The GDALRasterBand class includes a default implementation of GetMaskBand() that
5912  * returns one of four default implementations :
5913  * <ul>
5914  * <li>If a corresponding .msk file exists it will be used for the mask band.</li>
5915  * <li>If the dataset has a NODATA_VALUES metadata item, an instance of the
5916  *     new GDALNoDataValuesMaskBand class will be returned.
5917  *     GetMaskFlags() will return GMF_NODATA | GMF_PER_DATASET. @since GDAL 1.6.0</li>
5918  * <li>If the band has a nodata value set, an instance of the new
5919  *     GDALNodataMaskRasterBand class will be returned.
5920  *     GetMaskFlags() will return GMF_NODATA.</li>
5921  * <li>If there is no nodata value, but the dataset has an alpha band that seems
5922  *     to apply to this band (specific rules yet to be determined) and that is
5923  *     of type GDT_Byte then that alpha band will be returned, and the flags
5924  *     GMF_PER_DATASET and GMF_ALPHA will be returned in the flags.</li>
5925  * <li>If neither of the above apply, an instance of the new GDALAllValidRasterBand
5926  *     class will be returned that has 255 values for all pixels.
5927  *     The null flags will return GMF_ALL_VALID.</li>
5928  * </ul>
5929  *
5930  * Note that the GetMaskBand() should always return a GDALRasterBand mask, even
5931  * if it is only an all 255 mask with the flags indicating GMF_ALL_VALID.
5932  *
5933  * For an external .msk file to be recognized by GDAL, it must be a valid GDAL
5934  * dataset, with the same name as the main dataset and suffixed with .msk,
5935  * with either one band (in the GMF_PER_DATASET case), or as many bands as the
5936  * main dataset.
5937  * It must have INTERNAL_MASK_FLAGS_xx metadata items set at the dataset
5938  * level, where xx matches the band number of a band of the main dataset. The
5939  * value of those items is a combination of the flags GMF_ALL_VALID,
5940  * GMF_PER_DATASET, GMF_ALPHA and GMF_NODATA. If a metadata item is missing for
5941  * a band, then the other rules explained above will be used to generate a
5942  * on-the-fly mask band.
5943  * \see CreateMaskBand() for the characteristics of .msk files created by GDAL.
5944  *
5945  * This method is the same as the C function GDALGetMaskBand().
5946  *
5947  * @return a valid mask band.
5948  *
5949  * @since GDAL 1.5.0
5950  *
5951  * @see https://gdal.org/development/rfc/rfc15_nodatabitmask.html
5952  *
5953  */
GetMaskBand()5954 GDALRasterBand *GDALRasterBand::GetMaskBand()
5955 
5956 {
5957     if( poMask != nullptr )
5958         return poMask;
5959 
5960 /* -------------------------------------------------------------------- */
5961 /*      Check for a mask in a .msk file.                                */
5962 /* -------------------------------------------------------------------- */
5963     if( poDS != nullptr && poDS->oOvManager.HaveMaskFile() )
5964     {
5965         poMask = poDS->oOvManager.GetMaskBand( nBand );
5966         if( poMask != nullptr )
5967         {
5968             nMaskFlags = poDS->oOvManager.GetMaskFlags( nBand );
5969             return poMask;
5970         }
5971     }
5972 
5973 /* -------------------------------------------------------------------- */
5974 /*      Check for NODATA_VALUES metadata.                               */
5975 /* -------------------------------------------------------------------- */
5976     if( poDS != nullptr )
5977     {
5978         const char* pszNoDataValues = poDS->GetMetadataItem("NODATA_VALUES");
5979         if( pszNoDataValues != nullptr )
5980         {
5981             char** papszNoDataValues
5982                 = CSLTokenizeStringComplex(pszNoDataValues, " ", FALSE, FALSE);
5983 
5984             // Make sure we have as many values as bands.
5985             if (CSLCount(papszNoDataValues) == poDS->GetRasterCount()
5986                 && poDS->GetRasterCount() != 0)
5987             {
5988                 // Make sure that all bands have the same data type
5989                 // This is clearly not a fundamental condition, just a
5990                 // condition to make implementation easier.
5991                 GDALDataType eDT = GDT_Unknown;
5992                 int i = 0;  // Used after for.
5993                 for( ; i < poDS->GetRasterCount(); ++i )
5994                 {
5995                     if( i == 0 )
5996                         eDT = poDS->GetRasterBand(1)->GetRasterDataType();
5997                     else if (eDT != poDS->GetRasterBand(i + 1)->GetRasterDataType())
5998                     {
5999                         break;
6000                     }
6001                 }
6002                 if( i == poDS->GetRasterCount() )
6003                 {
6004                     nMaskFlags = GMF_NODATA | GMF_PER_DATASET;
6005                     try
6006                     {
6007                         poMask = new GDALNoDataValuesMaskBand ( poDS );
6008                     }
6009                     catch( const std::bad_alloc& )
6010                     {
6011                         CPLError(CE_Failure, CPLE_OutOfMemory, "Out of memory");
6012                         poMask = nullptr;
6013                     }
6014                     bOwnMask = true;
6015                     CSLDestroy(papszNoDataValues);
6016                     return poMask;
6017                 }
6018                 else
6019                 {
6020                     ReportError( CE_Warning, CPLE_AppDefined,
6021                                  "All bands should have the same type in "
6022                                  "order the NODATA_VALUES metadata item "
6023                                  "to be used as a mask." );
6024                 }
6025             }
6026             else
6027             {
6028                 ReportError(
6029                     CE_Warning, CPLE_AppDefined,
6030                     "NODATA_VALUES metadata item doesn't have the same number "
6031                     "of values as the number of bands.  "
6032                     "Ignoring it for mask.");
6033             }
6034 
6035             CSLDestroy(papszNoDataValues);
6036         }
6037     }
6038 
6039 /* -------------------------------------------------------------------- */
6040 /*      Check for nodata case.                                          */
6041 /* -------------------------------------------------------------------- */
6042     int bHaveNoData = FALSE;
6043     const double dfNoDataValue = GetNoDataValue( &bHaveNoData );
6044 
6045     if( bHaveNoData &&
6046         GDALNoDataMaskBand::IsNoDataInRange(dfNoDataValue, eDataType) )
6047     {
6048         nMaskFlags = GMF_NODATA;
6049         try
6050         {
6051             poMask = new GDALNoDataMaskBand( this );
6052         }
6053         catch( const std::bad_alloc& )
6054         {
6055             CPLError(CE_Failure, CPLE_OutOfMemory, "Out of memory");
6056             poMask = nullptr;
6057         }
6058         bOwnMask = true;
6059         return poMask;
6060     }
6061 
6062 /* -------------------------------------------------------------------- */
6063 /*      Check for alpha case.                                           */
6064 /* -------------------------------------------------------------------- */
6065     if( poDS != nullptr
6066         && poDS->GetRasterCount() == 2
6067         && this == poDS->GetRasterBand(1)
6068         && poDS->GetRasterBand(2)->GetColorInterpretation() == GCI_AlphaBand )
6069     {
6070         if( poDS->GetRasterBand(2)->GetRasterDataType() == GDT_Byte )
6071         {
6072             nMaskFlags = GMF_ALPHA | GMF_PER_DATASET;
6073             poMask = poDS->GetRasterBand(2);
6074             return poMask;
6075         }
6076         else if( poDS->GetRasterBand(2)->GetRasterDataType() == GDT_UInt16 )
6077         {
6078             nMaskFlags = GMF_ALPHA | GMF_PER_DATASET;
6079             try
6080             {
6081                 poMask = new GDALRescaledAlphaBand( poDS->GetRasterBand(2) );
6082             }
6083             catch( const std::bad_alloc& )
6084             {
6085                 CPLError(CE_Failure, CPLE_OutOfMemory, "Out of memory");
6086                 poMask = nullptr;
6087             }
6088             bOwnMask = true;
6089             return poMask;
6090         }
6091     }
6092 
6093     if( poDS != nullptr
6094         && poDS->GetRasterCount() == 4
6095         && (this == poDS->GetRasterBand(1)
6096             || this == poDS->GetRasterBand(2)
6097             || this == poDS->GetRasterBand(3))
6098         && poDS->GetRasterBand(4)->GetColorInterpretation() == GCI_AlphaBand )
6099     {
6100         if( poDS->GetRasterBand(4)->GetRasterDataType() == GDT_Byte )
6101         {
6102             nMaskFlags = GMF_ALPHA | GMF_PER_DATASET;
6103             poMask = poDS->GetRasterBand(4);
6104             return poMask;
6105         }
6106         else if( poDS->GetRasterBand(4)->GetRasterDataType() == GDT_UInt16 )
6107         {
6108             nMaskFlags = GMF_ALPHA | GMF_PER_DATASET;
6109             try
6110             {
6111                 poMask = new GDALRescaledAlphaBand( poDS->GetRasterBand(4) );
6112             }
6113             catch( const std::bad_alloc& )
6114             {
6115                 CPLError(CE_Failure, CPLE_OutOfMemory, "Out of memory");
6116                 poMask = nullptr;
6117             }
6118             bOwnMask = true;
6119             return poMask;
6120         }
6121     }
6122 
6123 /* -------------------------------------------------------------------- */
6124 /*      Fallback to all valid case.                                     */
6125 /* -------------------------------------------------------------------- */
6126     nMaskFlags = GMF_ALL_VALID;
6127     try
6128     {
6129         poMask = new GDALAllValidMaskBand( this );
6130     }
6131     catch( const std::bad_alloc& )
6132     {
6133         CPLError(CE_Failure, CPLE_OutOfMemory, "Out of memory");
6134         poMask = nullptr;
6135     }
6136     bOwnMask = true;
6137 
6138     return poMask;
6139 }
6140 
6141 /************************************************************************/
6142 /*                          GDALGetMaskBand()                           */
6143 /************************************************************************/
6144 
6145 /**
6146  * \brief Return the mask band associated with the band.
6147  *
6148  * @see GDALRasterBand::GetMaskBand()
6149  */
6150 
GDALGetMaskBand(GDALRasterBandH hBand)6151 GDALRasterBandH CPL_STDCALL GDALGetMaskBand( GDALRasterBandH hBand )
6152 
6153 {
6154     VALIDATE_POINTER1( hBand, "GDALGetMaskBand", nullptr );
6155 
6156     GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
6157     return poBand->GetMaskBand();
6158 }
6159 
6160 /************************************************************************/
6161 /*                            GetMaskFlags()                            */
6162 /************************************************************************/
6163 
6164 /**
6165  * \brief Return the status flags of the mask band associated with the band.
6166  *
6167  * The GetMaskFlags() method returns an bitwise OR-ed set of status flags with
6168  * the following available definitions that may be extended in the future:
6169  * <ul>
6170  * <li>GMF_ALL_VALID(0x01): There are no invalid pixels, all mask values will be 255.
6171  *     When used this will normally be the only flag set.</li>
6172  * <li>GMF_PER_DATASET(0x02): The mask band is shared between all bands on the dataset.</li>
6173  * <li>GMF_ALPHA(0x04): The mask band is actually an alpha band and may have values
6174  *     other than 0 and 255.</li>
6175  * <li>GMF_NODATA(0x08): Indicates the mask is actually being generated from nodata values.
6176  *     (mutually exclusive of GMF_ALPHA)</li>
6177  * </ul>
6178  *
6179  * The GDALRasterBand class includes a default implementation of GetMaskBand() that
6180  * returns one of four default implementations :
6181  * <ul>
6182  * <li>If a corresponding .msk file exists it will be used for the mask band.</li>
6183  * <li>If the dataset has a NODATA_VALUES metadata item, an instance of the
6184  *     new GDALNoDataValuesMaskBand class will be returned.
6185  *     GetMaskFlags() will return GMF_NODATA | GMF_PER_DATASET. @since GDAL 1.6.0</li>
6186  * <li>If the band has a nodata value set, an instance of the new
6187  *     GDALNodataMaskRasterBand class will be returned.
6188  *     GetMaskFlags() will return GMF_NODATA.</li>
6189  * <li>If there is no nodata value, but the dataset has an alpha band that seems
6190  *     to apply to this band (specific rules yet to be determined) and that is
6191  *     of type GDT_Byte then that alpha band will be returned, and the flags
6192  *     GMF_PER_DATASET and GMF_ALPHA will be returned in the flags.</li>
6193  * <li>If neither of the above apply, an instance of the new GDALAllValidRasterBand
6194  *     class will be returned that has 255 values for all pixels.
6195  *     The null flags will return GMF_ALL_VALID.</li>
6196  * </ul>
6197  *
6198  * For an external .msk file to be recognized by GDAL, it must be a valid GDAL
6199  * dataset, with the same name as the main dataset and suffixed with .msk,
6200  * with either one band (in the GMF_PER_DATASET case), or as many bands as the
6201  * main dataset.
6202  * It must have INTERNAL_MASK_FLAGS_xx metadata items set at the dataset
6203  * level, where xx matches the band number of a band of the main dataset. The
6204  * value of those items is a combination of the flags GMF_ALL_VALID,
6205  * GMF_PER_DATASET, GMF_ALPHA and GMF_NODATA. If a metadata item is missing for
6206  * a band, then the other rules explained above will be used to generate a
6207  * on-the-fly mask band.
6208  * \see CreateMaskBand() for the characteristics of .msk files created by GDAL.
6209  *
6210  * This method is the same as the C function GDALGetMaskFlags().
6211  *
6212  * @since GDAL 1.5.0
6213  *
6214  * @return a valid mask band.
6215  *
6216  * @see https://gdal.org/development/rfc/rfc15_nodatabitmask.html
6217  *
6218  */
GetMaskFlags()6219 int GDALRasterBand::GetMaskFlags()
6220 
6221 {
6222     // If we don't have a band yet, force this now so that the masks value
6223     // will be initialized.
6224 
6225     if( poMask == nullptr )
6226         GetMaskBand();
6227 
6228     return nMaskFlags;
6229 }
6230 
6231 /************************************************************************/
6232 /*                          GDALGetMaskFlags()                          */
6233 /************************************************************************/
6234 
6235 /**
6236  * \brief Return the status flags of the mask band associated with the band.
6237  *
6238  * @see GDALRasterBand::GetMaskFlags()
6239  */
6240 
GDALGetMaskFlags(GDALRasterBandH hBand)6241 int CPL_STDCALL GDALGetMaskFlags( GDALRasterBandH hBand )
6242 
6243 {
6244     VALIDATE_POINTER1( hBand, "GDALGetMaskFlags", GMF_ALL_VALID );
6245 
6246     GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
6247     return poBand->GetMaskFlags();
6248 }
6249 
6250 /************************************************************************/
6251 /*                         InvalidateMaskBand()                         */
6252 /************************************************************************/
6253 
6254 //! @cond Doxygen_Suppress
InvalidateMaskBand()6255 void GDALRasterBand::InvalidateMaskBand()
6256 {
6257     if (bOwnMask)
6258         delete poMask;
6259     bOwnMask = false;
6260     nMaskFlags = 0;
6261     poMask = nullptr;
6262 }
6263 //! @endcond
6264 
6265 /************************************************************************/
6266 /*                           CreateMaskBand()                           */
6267 /************************************************************************/
6268 
6269 /**
6270  * \brief Adds a mask band to the current band
6271  *
6272  * The default implementation of the CreateMaskBand() method is implemented
6273  * based on similar rules to the .ovr handling implemented using the
6274  * GDALDefaultOverviews object. A TIFF file with the extension .msk will
6275  * be created with the same basename as the original file, and it will have
6276  * as many bands as the original image (or just one for GMF_PER_DATASET).
6277  * The mask images will be deflate compressed tiled images with the same
6278  * block size as the original image if possible.
6279  * It will have INTERNAL_MASK_FLAGS_xx metadata items set at the dataset
6280  * level, where xx matches the band number of a band of the main dataset. The
6281  * value of those items will be the one of the nFlagsIn parameter.
6282  *
6283  * Note that if you got a mask band with a previous call to GetMaskBand(),
6284  * it might be invalidated by CreateMaskBand(). So you have to call GetMaskBand()
6285  * again.
6286  *
6287  * This method is the same as the C function GDALCreateMaskBand().
6288  *
6289  * @since GDAL 1.5.0
6290  *
6291  * @param nFlagsIn 0 or combination of GMF_PER_DATASET / GMF_ALPHA.
6292  *
6293  * @return CE_None on success or CE_Failure on an error.
6294  *
6295  * @see https://gdal.org/development/rfc/rfc15_nodatabitmask.html
6296  * @see GDALDataset::CreateMaskBand()
6297  *
6298  */
6299 
CreateMaskBand(int nFlagsIn)6300 CPLErr GDALRasterBand::CreateMaskBand( int nFlagsIn )
6301 
6302 {
6303     if( poDS != nullptr && poDS->oOvManager.IsInitialized() )
6304     {
6305         const CPLErr eErr = poDS->oOvManager.CreateMaskBand( nFlagsIn, nBand );
6306         if (eErr != CE_None)
6307             return eErr;
6308 
6309         InvalidateMaskBand();
6310 
6311         return CE_None;
6312     }
6313 
6314     ReportError( CE_Failure, CPLE_NotSupported,
6315                  "CreateMaskBand() not supported for this band." );
6316 
6317     return CE_Failure;
6318 }
6319 
6320 /************************************************************************/
6321 /*                         GDALCreateMaskBand()                         */
6322 /************************************************************************/
6323 
6324 /**
6325  * \brief Adds a mask band to the current band
6326  *
6327  * @see GDALRasterBand::CreateMaskBand()
6328  */
6329 
GDALCreateMaskBand(GDALRasterBandH hBand,int nFlags)6330 CPLErr CPL_STDCALL GDALCreateMaskBand( GDALRasterBandH hBand, int nFlags )
6331 
6332 {
6333     VALIDATE_POINTER1( hBand, "GDALCreateMaskBand", CE_Failure );
6334 
6335     GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
6336     return poBand->CreateMaskBand( nFlags );
6337 }
6338 
6339 /************************************************************************/
6340 /*                    GetIndexColorTranslationTo()                      */
6341 /************************************************************************/
6342 
6343 /**
6344  * \brief Compute translation table for color tables.
6345  *
6346  * When the raster band has a palette index, it may be useful to compute
6347  * the "translation" of this palette to the palette of another band.
6348  * The translation tries to do exact matching first, and then approximate
6349  * matching if no exact matching is possible.
6350  * This method returns a table such that table[i] = j where i is an index
6351  * of the 'this' rasterband and j the corresponding index for the reference
6352  * rasterband.
6353  *
6354  * This method is thought as internal to GDAL and is used for drivers
6355  * like RPFTOC.
6356  *
6357  * The implementation only supports 1-byte palette rasterbands.
6358  *
6359  * @param poReferenceBand the raster band
6360  * @param pTranslationTable an already allocated translation table (at least 256 bytes),
6361  *                          or NULL to let the method allocate it
6362  * @param pApproximateMatching a pointer to a flag that is set if the matching
6363  *                              is approximate. May be NULL.
6364  *
6365  * @return a translation table if the two bands are palette index and that they do
6366  *         not match or NULL in other cases.
6367  *         The table must be freed with CPLFree if NULL was passed for pTranslationTable.
6368  */
6369 
GetIndexColorTranslationTo(GDALRasterBand * poReferenceBand,unsigned char * pTranslationTable,int * pApproximateMatching)6370 unsigned char* GDALRasterBand::GetIndexColorTranslationTo(
6371     GDALRasterBand* poReferenceBand,
6372     unsigned char* pTranslationTable,
6373     int* pApproximateMatching )
6374 {
6375     if (poReferenceBand == nullptr)
6376         return nullptr;
6377 
6378     // cppcheck-suppress knownConditionTrueFalse
6379     if (poReferenceBand->GetColorInterpretation() == GCI_PaletteIndex &&
6380         // cppcheck-suppress knownConditionTrueFalse
6381         GetColorInterpretation() == GCI_PaletteIndex &&
6382         poReferenceBand->GetRasterDataType() == GDT_Byte &&
6383         GetRasterDataType() == GDT_Byte)
6384     {
6385         const GDALColorTable* srcColorTable = GetColorTable();
6386         GDALColorTable* destColorTable = poReferenceBand->GetColorTable();
6387         if (srcColorTable != nullptr && destColorTable != nullptr)
6388         {
6389             const int nEntries = srcColorTable->GetColorEntryCount();
6390             const int nRefEntries = destColorTable->GetColorEntryCount();
6391 
6392             int bHasNoDataValueSrc = FALSE;
6393             double dfNoDataValueSrc = GetNoDataValue(&bHasNoDataValueSrc);
6394             if( !(bHasNoDataValueSrc &&
6395                   dfNoDataValueSrc >= 0 && dfNoDataValueSrc <= 255 &&
6396                   dfNoDataValueSrc == static_cast<int>(dfNoDataValueSrc)) )
6397                 bHasNoDataValueSrc = FALSE;
6398             const int noDataValueSrc =
6399                 bHasNoDataValueSrc ? static_cast<int>(dfNoDataValueSrc) : 0;
6400 
6401             int bHasNoDataValueRef = FALSE;
6402             const double dfNoDataValueRef =
6403                 poReferenceBand->GetNoDataValue(&bHasNoDataValueRef);
6404             if( !(bHasNoDataValueRef &&
6405                   dfNoDataValueRef >= 0 && dfNoDataValueRef <= 255 &&
6406                   dfNoDataValueRef == static_cast<int>(dfNoDataValueRef)) )
6407                 bHasNoDataValueRef = FALSE;
6408             const int noDataValueRef =
6409                 bHasNoDataValueRef ? static_cast<int>(dfNoDataValueRef) : 0;
6410 
6411             bool samePalette = false;
6412 
6413             if (pApproximateMatching)
6414                 *pApproximateMatching = FALSE;
6415 
6416             if (nEntries == nRefEntries && bHasNoDataValueSrc == bHasNoDataValueRef &&
6417                 (bHasNoDataValueSrc == FALSE || noDataValueSrc == noDataValueRef))
6418             {
6419                 samePalette = true;
6420                 for( int i = 0; i < nEntries; ++i )
6421                 {
6422                     if (noDataValueSrc == i)
6423                         continue;
6424                     const GDALColorEntry* entry = srcColorTable->GetColorEntry(i);
6425                     const GDALColorEntry* entryRef = destColorTable->GetColorEntry(i);
6426                     if (entry->c1 != entryRef->c1 ||
6427                         entry->c2 != entryRef->c2 ||
6428                         entry->c3 != entryRef->c3)
6429                     {
6430                         samePalette = false;
6431                     }
6432                 }
6433             }
6434 
6435             if( !samePalette )
6436             {
6437                 if (pTranslationTable == nullptr)
6438                 {
6439                     pTranslationTable = static_cast<unsigned char *>(
6440                         VSI_CALLOC_VERBOSE(1, std::max(256, nEntries)) );
6441                     if( pTranslationTable == nullptr )
6442                         return nullptr;
6443                 }
6444 
6445                 // Trying to remap the product palette on the subdataset
6446                 // palette.
6447                 for( int i = 0; i < nEntries; ++i )
6448                 {
6449                     if( bHasNoDataValueSrc && bHasNoDataValueRef &&
6450                         noDataValueSrc == i )
6451                         continue;
6452                     const GDALColorEntry* entry =
6453                         srcColorTable->GetColorEntry(i);
6454                     bool bMatchFound = false;
6455                     for( int j = 0; j < nRefEntries; ++j )
6456                     {
6457                         if (bHasNoDataValueRef && noDataValueRef == j)
6458                             continue;
6459                         const GDALColorEntry* entryRef =
6460                             destColorTable->GetColorEntry(j);
6461                         if( entry->c1 == entryRef->c1 &&
6462                             entry->c2 == entryRef->c2 &&
6463                             entry->c3 == entryRef->c3 )
6464                         {
6465                             pTranslationTable[i] =
6466                                 static_cast<unsigned char>(j);
6467                             bMatchFound = true;
6468                             break;
6469                         }
6470                     }
6471                     if( !bMatchFound )
6472                     {
6473                         // No exact match. Looking for closest color now.
6474                         int best_j = 0;
6475                         int best_distance = 0;
6476                         if( pApproximateMatching )
6477                             *pApproximateMatching = TRUE;
6478                         for( int j = 0; j < nRefEntries; ++j )
6479                         {
6480                             const GDALColorEntry* entryRef =
6481                                 destColorTable->GetColorEntry(j);
6482                             int distance =
6483                                 (entry->c1 - entryRef->c1) *
6484                                     (entry->c1 - entryRef->c1) +
6485                                 (entry->c2 - entryRef->c2) *
6486                                     (entry->c2 - entryRef->c2) +
6487                                 (entry->c3 - entryRef->c3) *
6488                                     (entry->c3 - entryRef->c3);
6489                             if( j == 0 || distance < best_distance )
6490                             {
6491                                 best_j = j;
6492                                 best_distance = distance;
6493                             }
6494                         }
6495                         pTranslationTable[i] =
6496                             static_cast<unsigned char>(best_j);
6497                     }
6498                 }
6499                 if( bHasNoDataValueRef && bHasNoDataValueSrc )
6500                     pTranslationTable[noDataValueSrc] =
6501                         static_cast<unsigned char>( noDataValueRef );
6502 
6503                 return pTranslationTable;
6504             }
6505         }
6506     }
6507     return nullptr;
6508 }
6509 
6510 /************************************************************************/
6511 /*                         SetFlushBlockErr()                           */
6512 /************************************************************************/
6513 
6514 /**
6515  * \brief Store that an error occurred while writing a dirty block.
6516  *
6517  * This function stores the fact that an error occurred while writing a dirty
6518  * block from GDALRasterBlock::FlushCacheBlock(). Indeed when dirty blocks are
6519  * flushed when the block cache get full, it is not convenient/possible to
6520  * report that a dirty block could not be written correctly. This function
6521  * remembers the error and re-issue it from GDALRasterBand::FlushCache(),
6522  * GDALRasterBand::WriteBlock() and GDALRasterBand::RasterIO(), which are
6523  * places where the user can easily match the error with the relevant dataset.
6524  */
6525 
SetFlushBlockErr(CPLErr eErr)6526 void GDALRasterBand::SetFlushBlockErr( CPLErr eErr )
6527 {
6528     eFlushBlockErr = eErr;
6529 }
6530 
6531 /************************************************************************/
6532 /*                         IncDirtyBlocks()                             */
6533 /************************************************************************/
6534 
6535 /**
6536  * \brief Increment/decrement the number of dirty blocks
6537  */
6538 
IncDirtyBlocks(int nInc)6539 void GDALRasterBand::IncDirtyBlocks( int nInc )
6540 {
6541     if( poBandBlockCache )
6542         poBandBlockCache->IncDirtyBlocks(nInc);
6543 }
6544 
6545 /************************************************************************/
6546 /*                            ReportError()                             */
6547 /************************************************************************/
6548 
6549 #ifndef DOXYGEN_XML
6550 /**
6551  * \brief Emits an error related to a raster band.
6552  *
6553  * This function is a wrapper for regular CPLError(). The only difference
6554  * with CPLError() is that it prepends the error message with the dataset
6555  * name and the band number.
6556  *
6557  * @param eErrClass one of CE_Warning, CE_Failure or CE_Fatal.
6558  * @param err_no the error number (CPLE_*) from cpl_error.h.
6559  * @param fmt a printf() style format string.  Any additional arguments
6560  * will be treated as arguments to fill in this format in a manner
6561  * similar to printf().
6562  *
6563  * @since GDAL 1.9.0
6564  */
6565 
ReportError(CPLErr eErrClass,CPLErrorNum err_no,const char * fmt,...)6566 void GDALRasterBand::ReportError( CPLErr eErrClass, CPLErrorNum err_no,
6567                                   const char *fmt, ... )
6568 {
6569     va_list args;
6570 
6571     va_start(args, fmt);
6572 
6573     char szNewFmt[256] = { '\0' };
6574     const char* pszDSName = poDS ? poDS->GetDescription() : "";
6575     if( strlen(fmt) + strlen(pszDSName) + 20 >= sizeof(szNewFmt) - 1 )
6576         pszDSName = CPLGetFilename(pszDSName);
6577     if( pszDSName[0] != '\0' && strchr(pszDSName, '%') == nullptr &&
6578         strlen(fmt) + strlen(pszDSName) + 20 < sizeof(szNewFmt) - 1 )
6579     {
6580         snprintf(szNewFmt, sizeof(szNewFmt), "%s, band %d: %s",
6581                  pszDSName, GetBand(), fmt);
6582         CPLErrorV( eErrClass, err_no, szNewFmt, args );
6583     }
6584     else
6585     {
6586         CPLErrorV( eErrClass, err_no, fmt, args );
6587     }
6588     va_end(args);
6589 }
6590 #endif
6591 
6592 /************************************************************************/
6593 /*                           GetVirtualMemAuto()                        */
6594 /************************************************************************/
6595 
6596 /** \brief Create a CPLVirtualMem object from a GDAL raster band object.
6597  *
6598  * Only supported on Linux and Unix systems with mmap() for now.
6599  *
6600  * This method allows creating a virtual memory object for a GDALRasterBand,
6601  * that exposes the whole image data as a virtual array.
6602  *
6603  * The default implementation relies on GDALRasterBandGetVirtualMem(), but specialized
6604  * implementation, such as for raw files, may also directly use mechanisms of the
6605  * operating system to create a view of the underlying file into virtual memory
6606  * ( CPLVirtualMemFileMapNew() )
6607  *
6608  * At the time of writing, the GeoTIFF driver and "raw" drivers (EHdr, ...) offer
6609  * a specialized implementation with direct file mapping, provided that some
6610  * requirements are met :
6611  *   - for all drivers, the dataset must be backed by a "real" file in the file
6612  *     system, and the byte ordering of multi-byte datatypes (Int16, etc.)
6613  *     must match the native ordering of the CPU.
6614  *   - in addition, for the GeoTIFF driver, the GeoTIFF file must be uncompressed, scanline
6615  *     oriented (i.e. not tiled). Strips must be organized in the file in sequential
6616  *     order, and be equally spaced (which is generally the case). Only power-of-two
6617  *     bit depths are supported (8 for GDT_Bye, 16 for GDT_Int16/GDT_UInt16,
6618  *     32 for GDT_Float32 and 64 for GDT_Float64)
6619  *
6620  * The pointer returned remains valid until CPLVirtualMemFree() is called.
6621  * CPLVirtualMemFree() must be called before the raster band object is destroyed.
6622  *
6623  * If p is such a pointer and base_type the type matching GDALGetRasterDataType(),
6624  * the element of image coordinates (x, y) can be accessed with
6625  * *(base_type*) ((GByte*)p + x * *pnPixelSpace + y * *pnLineSpace)
6626  *
6627  * This method is the same as the C GDALGetVirtualMemAuto() function.
6628  *
6629  * @param eRWFlag Either GF_Read to read the band, or GF_Write to
6630  * read/write the band.
6631  *
6632  * @param pnPixelSpace Output parameter giving the byte offset from the start of one pixel value in
6633  * the buffer to the start of the next pixel value within a scanline.
6634  *
6635  * @param pnLineSpace Output parameter giving the byte offset from the start of one scanline in
6636  * the buffer to the start of the next.
6637  *
6638  * @param papszOptions NULL terminated list of options.
6639  *                     If a specialized implementation exists, defining USE_DEFAULT_IMPLEMENTATION=YES
6640  *                     will cause the default implementation to be used.
6641  *                     On the contrary, starting with GDAL 2.2, defining USE_DEFAULT_IMPLEMENTATION=NO
6642  *                     will prevent the default implementation from being used (thus only allowing
6643  *                     efficient implementations to be used).
6644  *                     When requiring or falling back to the default implementation, the following
6645  *                     options are available : CACHE_SIZE (in bytes, defaults to 40 MB),
6646  *                     PAGE_SIZE_HINT (in bytes),
6647  *                     SINGLE_THREAD ("FALSE" / "TRUE", defaults to FALSE)
6648  *
6649  * @return a virtual memory object that must be unreferenced by CPLVirtualMemFree(),
6650  *         or NULL in case of failure.
6651  *
6652  * @since GDAL 1.11
6653  */
6654 
GetVirtualMemAuto(GDALRWFlag eRWFlag,int * pnPixelSpace,GIntBig * pnLineSpace,char ** papszOptions)6655 CPLVirtualMem  *GDALRasterBand::GetVirtualMemAuto( GDALRWFlag eRWFlag,
6656                                                    int *pnPixelSpace,
6657                                                    GIntBig *pnLineSpace,
6658                                                    char **papszOptions )
6659 {
6660     const char* pszImpl = CSLFetchNameValueDef(
6661             papszOptions, "USE_DEFAULT_IMPLEMENTATION", "AUTO");
6662     if( EQUAL(pszImpl, "NO") || EQUAL(pszImpl, "OFF") ||
6663         EQUAL(pszImpl, "0") || EQUAL(pszImpl, "FALSE") )
6664     {
6665         return nullptr;
6666     }
6667 
6668     const int nPixelSpace = GDALGetDataTypeSizeBytes(eDataType);
6669     const GIntBig nLineSpace = static_cast<GIntBig>(nRasterXSize) * nPixelSpace;
6670     if( pnPixelSpace )
6671         *pnPixelSpace = nPixelSpace;
6672     if( pnLineSpace )
6673         *pnLineSpace = nLineSpace;
6674     const size_t nCacheSize = atoi(
6675         CSLFetchNameValueDef(papszOptions, "CACHE_SIZE", "40000000"));
6676     const size_t nPageSizeHint = atoi(
6677         CSLFetchNameValueDef(papszOptions, "PAGE_SIZE_HINT", "0") );
6678     const bool bSingleThreadUsage =
6679         CPLTestBool( CSLFetchNameValueDef( papszOptions,
6680                                            "SINGLE_THREAD", "FALSE" ) );
6681     return GDALRasterBandGetVirtualMem( GDALRasterBand::ToHandle(this),
6682                                         eRWFlag,
6683                                         0, 0, nRasterXSize, nRasterYSize,
6684                                         nRasterXSize, nRasterYSize,
6685                                         eDataType,
6686                                         nPixelSpace, nLineSpace,
6687                                         nCacheSize,
6688                                         nPageSizeHint,
6689                                         bSingleThreadUsage,
6690                                         papszOptions );
6691 }
6692 
6693 /************************************************************************/
6694 /*                         GDALGetVirtualMemAuto()                      */
6695 /************************************************************************/
6696 
6697 /**
6698  * \brief Create a CPLVirtualMem object from a GDAL raster band object.
6699  *
6700  * @see GDALRasterBand::GetVirtualMemAuto()
6701  */
6702 
GDALGetVirtualMemAuto(GDALRasterBandH hBand,GDALRWFlag eRWFlag,int * pnPixelSpace,GIntBig * pnLineSpace,CSLConstList papszOptions)6703 CPLVirtualMem * GDALGetVirtualMemAuto( GDALRasterBandH hBand,
6704                                        GDALRWFlag eRWFlag,
6705                                        int *pnPixelSpace,
6706                                        GIntBig *pnLineSpace,
6707                                        CSLConstList papszOptions )
6708 {
6709     VALIDATE_POINTER1( hBand, "GDALGetVirtualMemAuto", nullptr );
6710 
6711     GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
6712 
6713     return poBand->GetVirtualMemAuto( eRWFlag, pnPixelSpace,
6714                                       pnLineSpace,
6715                                       const_cast<char**>(papszOptions) );
6716 }
6717 
6718 /************************************************************************/
6719 /*                        GDALGetDataCoverageStatus()                   */
6720 /************************************************************************/
6721 
6722 /**
6723  * \brief Get the coverage status of a sub-window of the raster.
6724  *
6725  * Returns whether a sub-window of the raster contains only data, only empty
6726  * blocks or a mix of both. This function can be used to determine quickly
6727  * if it is worth issuing RasterIO / ReadBlock requests in datasets that may
6728  * be sparse.
6729  *
6730  * Empty blocks are blocks that are generally not physically present in the
6731  * file, and when read through GDAL, contain only pixels whose value is the
6732  * nodata value when it is set, or whose value is 0 when the nodata value is
6733  * not set.
6734  *
6735  * The query is done in an efficient way without reading the actual pixel
6736  * values. If not possible, or not implemented at all by the driver,
6737  * GDAL_DATA_COVERAGE_STATUS_UNIMPLEMENTED | GDAL_DATA_COVERAGE_STATUS_DATA will
6738  * be returned.
6739  *
6740  * The values that can be returned by the function are the following,
6741  * potentially combined with the binary or operator :
6742  * <ul>
6743  * <li>GDAL_DATA_COVERAGE_STATUS_UNIMPLEMENTED : the driver does not implement
6744  * GetDataCoverageStatus(). This flag should be returned together with
6745  * GDAL_DATA_COVERAGE_STATUS_DATA.</li>
6746  * <li>GDAL_DATA_COVERAGE_STATUS_DATA: There is (potentially) data in the queried
6747  * window.</li>
6748  * <li>GDAL_DATA_COVERAGE_STATUS_EMPTY: There is nodata in the queried window.
6749  * This is typically identified by the concept of missing block in formats that
6750  * supports it.
6751  * </li>
6752  * </ul>
6753  *
6754  * Note that GDAL_DATA_COVERAGE_STATUS_DATA might have false positives and
6755  * should be interpreted more as hint of potential presence of data. For example
6756  * if a GeoTIFF file is created with blocks filled with zeroes (or set to the
6757  * nodata value), instead of using the missing block mechanism,
6758  * GDAL_DATA_COVERAGE_STATUS_DATA will be returned. On the contrary,
6759  * GDAL_DATA_COVERAGE_STATUS_EMPTY should have no false positives.
6760  *
6761  * The nMaskFlagStop should be generally set to 0. It can be set to a
6762  * binary-or'ed mask of the above mentioned values to enable a quick exiting of
6763  * the function as soon as the computed mask matches the nMaskFlagStop. For
6764  * example, you can issue a request on the whole raster with nMaskFlagStop =
6765  * GDAL_DATA_COVERAGE_STATUS_EMPTY. As soon as one missing block is encountered,
6766  * the function will exit, so that you can potentially refine the requested area
6767  * to find which particular region(s) have missing blocks.
6768  *
6769  * @see GDALRasterBand::GetDataCoverageStatus()
6770  *
6771  * @param hBand raster band
6772  *
6773  * @param nXOff The pixel offset to the top left corner of the region
6774  * of the band to be queried. This would be zero to start from the left side.
6775  *
6776  * @param nYOff The line offset to the top left corner of the region
6777  * of the band to be queried. This would be zero to start from the top.
6778  *
6779  * @param nXSize The width of the region of the band to be queried in pixels.
6780  *
6781  * @param nYSize The height of the region of the band to be queried in lines.
6782  *
6783  * @param nMaskFlagStop 0, or a binary-or'ed mask of possible values
6784  * GDAL_DATA_COVERAGE_STATUS_UNIMPLEMENTED,
6785  * GDAL_DATA_COVERAGE_STATUS_DATA and GDAL_DATA_COVERAGE_STATUS_EMPTY. As soon
6786  * as the computation of the coverage matches the mask, the computation will be
6787  * stopped. *pdfDataPct will not be valid in that case.
6788  *
6789  * @param pdfDataPct Optional output parameter whose pointed value will be set
6790  * to the (approximate) percentage in [0,100] of pixels in the queried
6791  * sub-window that have valid values. The implementation might not always be
6792  * able to compute it, in which case it will be set to a negative value.
6793  *
6794  * @return a binary-or'ed combination of possible values
6795  * GDAL_DATA_COVERAGE_STATUS_UNIMPLEMENTED,
6796  * GDAL_DATA_COVERAGE_STATUS_DATA and GDAL_DATA_COVERAGE_STATUS_EMPTY
6797  *
6798  * @note Added in GDAL 2.2
6799  */
6800 
GDALGetDataCoverageStatus(GDALRasterBandH hBand,int nXOff,int nYOff,int nXSize,int nYSize,int nMaskFlagStop,double * pdfDataPct)6801 int CPL_STDCALL GDALGetDataCoverageStatus( GDALRasterBandH hBand,
6802                                int nXOff, int nYOff,
6803                                int nXSize,
6804                                int nYSize,
6805                                int nMaskFlagStop,
6806                                double* pdfDataPct)
6807 {
6808     VALIDATE_POINTER1( hBand, "GDALGetDataCoverageStatus",
6809                        GDAL_DATA_COVERAGE_STATUS_UNIMPLEMENTED );
6810 
6811     GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
6812 
6813     return poBand->GetDataCoverageStatus( nXOff, nYOff, nXSize, nYSize,
6814                                           nMaskFlagStop, pdfDataPct );
6815 }
6816 
6817 /************************************************************************/
6818 /*                          GetDataCoverageStatus()                     */
6819 /************************************************************************/
6820 
6821 /**
6822  * \fn GDALRasterBand::IGetDataCoverageStatus( int nXOff,
6823  *                                           int nYOff,
6824  *                                           int nXSize,
6825  *                                           int nYSize,
6826  *                                           int nMaskFlagStop,
6827  *                                           double* pdfDataPct)
6828  * \brief Get the coverage status of a sub-window of the raster.
6829  *
6830  * Returns whether a sub-window of the raster contains only data, only empty
6831  * blocks or a mix of both. This function can be used to determine quickly
6832  * if it is worth issuing RasterIO / ReadBlock requests in datasets that may
6833  * be sparse.
6834  *
6835  * Empty blocks are blocks that contain only pixels whose value is the nodata
6836  * value when it is set, or whose value is 0 when the nodata value is not set.
6837  *
6838  * The query is done in an efficient way without reading the actual pixel
6839  * values. If not possible, or not implemented at all by the driver,
6840  * GDAL_DATA_COVERAGE_STATUS_UNIMPLEMENTED | GDAL_DATA_COVERAGE_STATUS_DATA will
6841  * be returned.
6842  *
6843  * The values that can be returned by the function are the following,
6844  * potentially combined with the binary or operator :
6845  * <ul>
6846  * <li>GDAL_DATA_COVERAGE_STATUS_UNIMPLEMENTED : the driver does not implement
6847  * GetDataCoverageStatus(). This flag should be returned together with
6848  * GDAL_DATA_COVERAGE_STATUS_DATA.</li>
6849  * <li>GDAL_DATA_COVERAGE_STATUS_DATA: There is (potentially) data in the queried
6850  * window.</li>
6851  * <li>GDAL_DATA_COVERAGE_STATUS_EMPTY: There is nodata in the queried window.
6852  * This is typically identified by the concept of missing block in formats that
6853  * supports it.
6854  * </li>
6855  * </ul>
6856  *
6857  * Note that GDAL_DATA_COVERAGE_STATUS_DATA might have false positives and
6858  * should be interpreted more as hint of potential presence of data. For example
6859  * if a GeoTIFF file is created with blocks filled with zeroes (or set to the
6860  * nodata value), instead of using the missing block mechanism,
6861  * GDAL_DATA_COVERAGE_STATUS_DATA will be returned. On the contrary,
6862  * GDAL_DATA_COVERAGE_STATUS_EMPTY should have no false positives.
6863  *
6864  * The nMaskFlagStop should be generally set to 0. It can be set to a
6865  * binary-or'ed mask of the above mentioned values to enable a quick exiting of
6866  * the function as soon as the computed mask matches the nMaskFlagStop. For
6867  * example, you can issue a request on the whole raster with nMaskFlagStop =
6868  * GDAL_DATA_COVERAGE_STATUS_EMPTY. As soon as one missing block is encountered,
6869  * the function will exit, so that you can potentially refine the requested area
6870  * to find which particular region(s) have missing blocks.
6871  *
6872  * @see GDALGetDataCoverageStatus()
6873  *
6874  * @param nXOff The pixel offset to the top left corner of the region
6875  * of the band to be queried. This would be zero to start from the left side.
6876  *
6877  * @param nYOff The line offset to the top left corner of the region
6878  * of the band to be queried. This would be zero to start from the top.
6879  *
6880  * @param nXSize The width of the region of the band to be queried in pixels.
6881  *
6882  * @param nYSize The height of the region of the band to be queried in lines.
6883  *
6884  * @param nMaskFlagStop 0, or a binary-or'ed mask of possible values
6885  * GDAL_DATA_COVERAGE_STATUS_UNIMPLEMENTED,
6886  * GDAL_DATA_COVERAGE_STATUS_DATA and GDAL_DATA_COVERAGE_STATUS_EMPTY. As soon
6887  * as the computation of the coverage matches the mask, the computation will be
6888  * stopped. *pdfDataPct will not be valid in that case.
6889  *
6890  * @param pdfDataPct Optional output parameter whose pointed value will be set
6891  * to the (approximate) percentage in [0,100] of pixels in the queried
6892  * sub-window that have valid values. The implementation might not always be
6893  * able to compute it, in which case it will be set to a negative value.
6894  *
6895  * @return a binary-or'ed combination of possible values
6896  * GDAL_DATA_COVERAGE_STATUS_UNIMPLEMENTED,
6897  * GDAL_DATA_COVERAGE_STATUS_DATA and GDAL_DATA_COVERAGE_STATUS_EMPTY
6898  *
6899  * @note Added in GDAL 2.2
6900  */
6901 
6902 /**
6903  * \brief Get the coverage status of a sub-window of the raster.
6904  *
6905  * Returns whether a sub-window of the raster contains only data, only empty
6906  * blocks or a mix of both. This function can be used to determine quickly
6907  * if it is worth issuing RasterIO / ReadBlock requests in datasets that may
6908  * be sparse.
6909  *
6910  * Empty blocks are blocks that contain only pixels whose value is the nodata
6911  * value when it is set, or whose value is 0 when the nodata value is not set.
6912  *
6913  * The query is done in an efficient way without reading the actual pixel
6914  * values. If not possible, or not implemented at all by the driver,
6915  * GDAL_DATA_COVERAGE_STATUS_UNIMPLEMENTED | GDAL_DATA_COVERAGE_STATUS_DATA will
6916  * be returned.
6917  *
6918  * The values that can be returned by the function are the following,
6919  * potentially combined with the binary or operator :
6920  * <ul>
6921  * <li>GDAL_DATA_COVERAGE_STATUS_UNIMPLEMENTED : the driver does not implement
6922  * GetDataCoverageStatus(). This flag should be returned together with
6923  * GDAL_DATA_COVERAGE_STATUS_DATA.</li>
6924  * <li>GDAL_DATA_COVERAGE_STATUS_DATA: There is (potentially) data in the queried
6925  * window.</li>
6926  * <li>GDAL_DATA_COVERAGE_STATUS_EMPTY: There is nodata in the queried window.
6927  * This is typically identified by the concept of missing block in formats that
6928  * supports it.
6929  * </li>
6930  * </ul>
6931  *
6932  * Note that GDAL_DATA_COVERAGE_STATUS_DATA might have false positives and
6933  * should be interpreted more as hint of potential presence of data. For example
6934  * if a GeoTIFF file is created with blocks filled with zeroes (or set to the
6935  * nodata value), instead of using the missing block mechanism,
6936  * GDAL_DATA_COVERAGE_STATUS_DATA will be returned. On the contrary,
6937  * GDAL_DATA_COVERAGE_STATUS_EMPTY should have no false positives.
6938  *
6939  * The nMaskFlagStop should be generally set to 0. It can be set to a
6940  * binary-or'ed mask of the above mentioned values to enable a quick exiting of
6941  * the function as soon as the computed mask matches the nMaskFlagStop. For
6942  * example, you can issue a request on the whole raster with nMaskFlagStop =
6943  * GDAL_DATA_COVERAGE_STATUS_EMPTY. As soon as one missing block is encountered,
6944  * the function will exit, so that you can potentially refine the requested area
6945  * to find which particular region(s) have missing blocks.
6946  *
6947  * @see GDALGetDataCoverageStatus()
6948  *
6949  * @param nXOff The pixel offset to the top left corner of the region
6950  * of the band to be queried. This would be zero to start from the left side.
6951  *
6952  * @param nYOff The line offset to the top left corner of the region
6953  * of the band to be queried. This would be zero to start from the top.
6954  *
6955  * @param nXSize The width of the region of the band to be queried in pixels.
6956  *
6957  * @param nYSize The height of the region of the band to be queried in lines.
6958  *
6959  * @param nMaskFlagStop 0, or a binary-or'ed mask of possible values
6960  * GDAL_DATA_COVERAGE_STATUS_UNIMPLEMENTED,
6961  * GDAL_DATA_COVERAGE_STATUS_DATA and GDAL_DATA_COVERAGE_STATUS_EMPTY. As soon
6962  * as the computation of the coverage matches the mask, the computation will be
6963  * stopped. *pdfDataPct will not be valid in that case.
6964  *
6965  * @param pdfDataPct Optional output parameter whose pointed value will be set
6966  * to the (approximate) percentage in [0,100] of pixels in the queried
6967  * sub-window that have valid values. The implementation might not always be
6968  * able to compute it, in which case it will be set to a negative value.
6969  *
6970  * @return a binary-or'ed combination of possible values
6971  * GDAL_DATA_COVERAGE_STATUS_UNIMPLEMENTED,
6972  * GDAL_DATA_COVERAGE_STATUS_DATA and GDAL_DATA_COVERAGE_STATUS_EMPTY
6973  *
6974  * @note Added in GDAL 2.2
6975  */
6976 
GetDataCoverageStatus(int nXOff,int nYOff,int nXSize,int nYSize,int nMaskFlagStop,double * pdfDataPct)6977 int  GDALRasterBand::GetDataCoverageStatus( int nXOff,
6978                                             int nYOff,
6979                                             int nXSize,
6980                                             int nYSize,
6981                                             int nMaskFlagStop,
6982                                             double* pdfDataPct)
6983 {
6984     if( nXOff < 0 || nYOff < 0 ||
6985         nXSize > INT_MAX - nXOff ||
6986         nYSize > INT_MAX - nYOff ||
6987         nXOff + nXSize > nRasterXSize ||
6988         nYOff + nYSize > nRasterYSize )
6989     {
6990         CPLError(CE_Failure, CPLE_AppDefined, "Bad window");
6991         if( pdfDataPct )
6992             *pdfDataPct = 0.0;
6993         return GDAL_DATA_COVERAGE_STATUS_UNIMPLEMENTED |
6994                GDAL_DATA_COVERAGE_STATUS_EMPTY;
6995     }
6996     return IGetDataCoverageStatus(nXOff, nYOff, nXSize, nYSize,
6997                                   nMaskFlagStop, pdfDataPct);
6998 }
6999 
7000 /************************************************************************/
7001 /*                         IGetDataCoverageStatus()                     */
7002 /************************************************************************/
7003 
IGetDataCoverageStatus(int,int,int,int,int,double * pdfDataPct)7004 int  GDALRasterBand::IGetDataCoverageStatus( int /*nXOff*/,
7005                                              int /*nYOff*/,
7006                                              int /*nXSize*/,
7007                                              int /*nYSize*/,
7008                                              int /*nMaskFlagStop*/,
7009                                              double* pdfDataPct)
7010 {
7011     if( pdfDataPct != nullptr )
7012         *pdfDataPct = 100.0;
7013     return GDAL_DATA_COVERAGE_STATUS_UNIMPLEMENTED |
7014            GDAL_DATA_COVERAGE_STATUS_DATA;
7015 }
7016 
7017 //! @cond Doxygen_Suppress
7018 /************************************************************************/
7019 /*                          EnterReadWrite()                            */
7020 /************************************************************************/
7021 
EnterReadWrite(GDALRWFlag eRWFlag)7022 int GDALRasterBand::EnterReadWrite( GDALRWFlag eRWFlag )
7023 {
7024     if( poDS != nullptr )
7025         return poDS->EnterReadWrite(eRWFlag);
7026     return FALSE;
7027 }
7028 
7029 /************************************************************************/
7030 /*                         LeaveReadWrite()                             */
7031 /************************************************************************/
7032 
LeaveReadWrite()7033 void GDALRasterBand::LeaveReadWrite()
7034 {
7035     if( poDS != nullptr )
7036         poDS->LeaveReadWrite();
7037 }
7038 
7039 /************************************************************************/
7040 /*                           InitRWLock()                               */
7041 /************************************************************************/
7042 
InitRWLock()7043 void GDALRasterBand::InitRWLock()
7044 {
7045     if( poDS != nullptr )
7046         poDS->InitRWLock();
7047 }
7048 
7049 //! @endcond
7050 
7051 /**
7052  * \fn GDALRasterBand::SetMetadata( char ** papszMetadata, const char * pszDomain)
7053  * \brief Set metadata.
7054  *
7055  * CAUTION: depending on the format, older values of the updated information might
7056  * still be found in the file in a "ghost" state, even if no longer accessible
7057  * through the GDAL API. This is for example the case of the GTiff format (this is
7058  * not a exhaustive list)
7059  *
7060  * The C function GDALSetMetadata() does the same thing as this method.
7061  *
7062  * @param papszMetadata the metadata in name=value string list format to
7063  * apply.
7064  * @param pszDomain the domain of interest.  Use "" or NULL for the default
7065  * domain.
7066  * @return CE_None on success, CE_Failure on failure and CE_Warning if the
7067  * metadata has been accepted, but is likely not maintained persistently
7068  * by the underlying object between sessions.
7069  */
7070 
7071 /**
7072  * \fn GDALRasterBand::SetMetadataItem( const char * pszName, const char * pszValue, const char * pszDomain)
7073  * \brief Set single metadata item.
7074  *
7075  * CAUTION: depending on the format, older values of the updated information might
7076  * still be found in the file in a "ghost" state, even if no longer accessible
7077  * through the GDAL API. This is for example the case of the GTiff format (this is
7078  * not a exhaustive list)
7079  *
7080  * The C function GDALSetMetadataItem() does the same thing as this method.
7081  *
7082  * @param pszName the key for the metadata item to fetch.
7083  * @param pszValue the value to assign to the key.
7084  * @param pszDomain the domain to set within, use NULL for the default domain.
7085  *
7086  * @return CE_None on success, or an error code on failure.
7087  */
7088 
7089 /************************************************************************/
7090 /*                     GDALMDArrayFromRasterBand                        */
7091 /************************************************************************/
7092 
7093 class GDALMDArrayFromRasterBand final: public GDALMDArray
7094 {
7095     CPL_DISALLOW_COPY_ASSIGN(GDALMDArrayFromRasterBand)
7096 
7097     GDALDataset* m_poDS;
7098     GDALRasterBand* m_poBand;
7099     GDALExtendedDataType m_dt;
7100     std::vector<std::shared_ptr<GDALDimension>> m_dims{};
7101     std::string m_osUnit;
7102     std::vector<GByte> m_pabyNoData{};
7103     std::shared_ptr<GDALMDArray> m_varX{};
7104     std::shared_ptr<GDALMDArray> m_varY{};
7105 
7106     bool ReadWrite(GDALRWFlag eRWFlag,
7107                     const GUInt64* arrayStartIdx,
7108                     const size_t* count,
7109                     const GInt64* arrayStep,
7110                     const GPtrDiff_t* bufferStride,
7111                     const GDALExtendedDataType& bufferDataType,
7112                     void* pBuffer) const;
7113 
7114 protected:
GDALMDArrayFromRasterBand(GDALDataset * poDS,GDALRasterBand * poBand)7115     GDALMDArrayFromRasterBand(GDALDataset* poDS,
7116                               GDALRasterBand* poBand):
7117         GDALAbstractMDArray( std::string(),
7118                              std::string(poDS->GetDescription()) +
7119                                 CPLSPrintf(" band %d", poBand->GetBand()) ),
7120         GDALMDArray( std::string(),
7121                      std::string(poDS->GetDescription()) +
7122                         CPLSPrintf(" band %d", poBand->GetBand()) ),
7123         m_poDS(poDS),
7124         m_poBand(poBand),
7125         m_dt(GDALExtendedDataType::Create(poBand->GetRasterDataType())),
7126         m_osUnit( poBand->GetUnitType() )
7127     {
7128         m_poDS->Reference();
7129 
7130         int bHasNoData = false;
7131         double dfNoData = m_poBand->GetNoDataValue(&bHasNoData);
7132         if( bHasNoData )
7133         {
7134             m_pabyNoData.resize(m_dt.GetSize());
7135             GDALCopyWords(&dfNoData, GDT_Float64, 0,
7136                           &m_pabyNoData[0], m_dt.GetNumericDataType(), 0,
7137                           1);
7138         }
7139 
7140         const int nXSize = poBand->GetXSize();
7141         const int nYSize = poBand->GetYSize();
7142 
7143         auto poSRS = m_poDS->GetSpatialRef();
7144         std::string osTypeY;
7145         std::string osTypeX;
7146         std::string osDirectionY;
7147         std::string osDirectionX;
7148         if( poSRS && poSRS->GetAxesCount() == 2 )
7149         {
7150             const auto mapping = poSRS->GetDataAxisToSRSAxisMapping();
7151             OGRAxisOrientation eOrientation1 = OAO_Other;
7152             poSRS->GetAxis(nullptr, 0,  &eOrientation1 );
7153             OGRAxisOrientation eOrientation2 = OAO_Other;
7154             poSRS->GetAxis(nullptr, 1,  &eOrientation2 );
7155             if( eOrientation1 == OAO_East && eOrientation2 == OAO_North )
7156             {
7157                 if( mapping == std::vector<int>{1,2} )
7158                 {
7159                     osTypeY = GDAL_DIM_TYPE_HORIZONTAL_Y;
7160                     osDirectionY = "NORTH";
7161                     osTypeX = GDAL_DIM_TYPE_HORIZONTAL_X;
7162                     osDirectionX = "EAST";
7163                 }
7164             }
7165             else if( eOrientation1 == OAO_North && eOrientation2 == OAO_East )
7166             {
7167                 if( mapping == std::vector<int>{2,1} )
7168                 {
7169                     osTypeY = GDAL_DIM_TYPE_HORIZONTAL_Y;
7170                     osDirectionY = "NORTH";
7171                     osTypeX = GDAL_DIM_TYPE_HORIZONTAL_X;
7172                     osDirectionX = "EAST";
7173                 }
7174             }
7175         }
7176 
7177         m_dims = {
7178             std::make_shared<GDALDimensionWeakIndexingVar>(
7179                 "/", "Y", osTypeY, osDirectionY, nYSize),
7180             std::make_shared<GDALDimensionWeakIndexingVar>(
7181                 "/", "X", osTypeX, osDirectionX, nXSize)
7182         };
7183 
7184         double adfGeoTransform[6];
7185         if( m_poDS->GetGeoTransform(adfGeoTransform) == CE_None &&
7186             adfGeoTransform[2] == 0 && adfGeoTransform[4] == 0 )
7187         {
7188             m_varX = std::make_shared<GDALMDArrayRegularlySpaced>(
7189                 "/", "X", m_dims[1],
7190                 adfGeoTransform[0],
7191                 adfGeoTransform[1], 0.5);
7192             m_dims[1]->SetIndexingVariable(m_varX);
7193 
7194             m_varY = std::make_shared<GDALMDArrayRegularlySpaced>(
7195                 "/", "Y", m_dims[0],
7196                 adfGeoTransform[3],
7197                 adfGeoTransform[5], 0.5);
7198             m_dims[0]->SetIndexingVariable(m_varY);
7199         }
7200     }
7201 
IRead(const GUInt64 * arrayStartIdx,const size_t * count,const GInt64 * arrayStep,const GPtrDiff_t * bufferStride,const GDALExtendedDataType & bufferDataType,void * pDstBuffer) const7202     bool IRead(const GUInt64* arrayStartIdx,
7203                       const size_t* count,
7204                       const GInt64* arrayStep,
7205                       const GPtrDiff_t* bufferStride,
7206                       const GDALExtendedDataType& bufferDataType,
7207                       void* pDstBuffer) const override
7208     {
7209         return ReadWrite(GF_Read, arrayStartIdx, count, arrayStep, bufferStride,
7210                          bufferDataType, pDstBuffer);
7211     }
7212 
IWrite(const GUInt64 * arrayStartIdx,const size_t * count,const GInt64 * arrayStep,const GPtrDiff_t * bufferStride,const GDALExtendedDataType & bufferDataType,const void * pSrcBuffer)7213     bool IWrite(const GUInt64* arrayStartIdx,
7214                       const size_t* count,
7215                       const GInt64* arrayStep,
7216                       const GPtrDiff_t* bufferStride,
7217                       const GDALExtendedDataType& bufferDataType,
7218                       const void* pSrcBuffer) override
7219     {
7220         return ReadWrite(GF_Write, arrayStartIdx, count, arrayStep, bufferStride,
7221                          bufferDataType, const_cast<void*>(pSrcBuffer));
7222     }
7223 
7224 public:
~GDALMDArrayFromRasterBand()7225     ~GDALMDArrayFromRasterBand()
7226     {
7227         m_poDS->ReleaseRef();
7228     }
7229 
Create(GDALDataset * poDS,GDALRasterBand * poBand)7230     static std::shared_ptr<GDALMDArray> Create(GDALDataset* poDS,
7231                                                GDALRasterBand* poBand)
7232     {
7233         auto array(std::shared_ptr<GDALMDArrayFromRasterBand>(
7234             new GDALMDArrayFromRasterBand(poDS, poBand)));
7235         array->SetSelf(array);
7236         return array;
7237     }
7238 
IsWritable() const7239     bool IsWritable() const override { return m_poDS->GetAccess() == GA_Update; }
7240 
GetDimensions() const7241     const std::vector<std::shared_ptr<GDALDimension>>& GetDimensions() const override { return m_dims; }
7242 
GetDataType() const7243     const GDALExtendedDataType &GetDataType() const override { return m_dt; }
7244 
GetUnit() const7245     const std::string& GetUnit() const override { return m_osUnit; }
7246 
GetRawNoDataValue() const7247     const void* GetRawNoDataValue() const override
7248     { return m_pabyNoData.empty() ? nullptr: m_pabyNoData.data(); }
7249 
GetOffset(bool * pbHasOffset,GDALDataType * peStorageType) const7250     double GetOffset(bool* pbHasOffset, GDALDataType* peStorageType) const override
7251     {
7252         int bHasOffset = false;
7253         double dfRes = m_poBand->GetOffset(&bHasOffset);
7254         if( pbHasOffset )
7255             *pbHasOffset = CPL_TO_BOOL(bHasOffset);
7256         if( peStorageType )
7257             *peStorageType = GDT_Unknown;
7258         return dfRes;
7259     }
7260 
GetScale(bool * pbHasScale,GDALDataType * peStorageType) const7261     double GetScale(bool* pbHasScale, GDALDataType* peStorageType) const override
7262     {
7263         int bHasScale = false;
7264         double dfRes = m_poBand->GetScale(&bHasScale);
7265         if( pbHasScale )
7266             *pbHasScale = CPL_TO_BOOL(bHasScale);
7267         if( peStorageType )
7268             *peStorageType = GDT_Unknown;
7269         return dfRes;
7270     }
7271 
GetSpatialRef() const7272     std::shared_ptr<OGRSpatialReference> GetSpatialRef() const override
7273     {
7274         auto poSrcSRS = m_poDS->GetSpatialRef();
7275         if( !poSrcSRS )
7276             return nullptr;
7277         auto poSRS = std::shared_ptr<OGRSpatialReference>(poSrcSRS->Clone());
7278 
7279         auto axisMapping = poSRS->GetDataAxisToSRSAxisMapping();
7280         constexpr int iYDim = 0;
7281         constexpr int iXDim = 1;
7282         for( auto& m: axisMapping )
7283         {
7284             if( m == 1 )
7285                 m = iXDim + 1;
7286             else if( m == 2 )
7287                 m = iYDim + 1;
7288             else
7289                 m = 0;
7290         }
7291         poSRS->SetDataAxisToSRSAxisMapping(axisMapping);
7292         return poSRS;
7293     }
7294 
GetBlockSize() const7295     std::vector<GUInt64> GetBlockSize() const override
7296     {
7297         int nBlockXSize = 0;
7298         int nBlockYSize = 0;
7299         m_poBand->GetBlockSize(&nBlockXSize, &nBlockYSize);
7300         return std::vector<GUInt64>{ static_cast<GUInt64>(nBlockYSize),
7301                                      static_cast<GUInt64>(nBlockXSize) };
7302     }
7303 
7304     class MDIAsAttribute: public GDALAttribute
7305     {
7306         std::vector<std::shared_ptr<GDALDimension>> m_dims{};
7307         const GDALExtendedDataType m_dt = GDALExtendedDataType::CreateString();
7308         std::string m_osValue;
7309 
7310     public:
MDIAsAttribute(const std::string & name,const std::string & value)7311         MDIAsAttribute(const std::string& name, const std::string& value):
7312             GDALAbstractMDArray(std::string(), name),
7313             GDALAttribute(std::string(), name),
7314             m_osValue(value)
7315         {
7316         }
7317 
GetDimensions() const7318         const std::vector<std::shared_ptr<GDALDimension>>& GetDimensions() const override { return m_dims; }
7319 
GetDataType() const7320         const GDALExtendedDataType &GetDataType() const override { return m_dt; }
7321 
IRead(const GUInt64 *,const size_t *,const GInt64 *,const GPtrDiff_t *,const GDALExtendedDataType & bufferDataType,void * pDstBuffer) const7322         bool IRead(const GUInt64*, const size_t*,
7323                    const GInt64*, const GPtrDiff_t*,
7324                    const GDALExtendedDataType& bufferDataType,
7325                    void* pDstBuffer) const override
7326         {
7327             const char* pszStr = m_osValue.c_str();
7328             GDALExtendedDataType::CopyValue(&pszStr, m_dt,
7329                                             pDstBuffer, bufferDataType);
7330             return true;
7331         }
7332     };
7333 
GetAttributes(CSLConstList) const7334     std::vector<std::shared_ptr<GDALAttribute>> GetAttributes(CSLConstList) const override
7335     {
7336         std::vector<std::shared_ptr<GDALAttribute>> res;
7337         auto papszMD = m_poBand->GetMetadata();
7338         for( auto iter = papszMD; iter && iter[0]; ++iter )
7339         {
7340             char* pszKey = nullptr;
7341             const char* pszValue = CPLParseNameValue(*iter, &pszKey);
7342             if( pszKey && pszValue )
7343             {
7344                 res.emplace_back(std::make_shared<MDIAsAttribute>(pszKey, pszValue));
7345             }
7346             CPLFree(pszKey);
7347         }
7348         return res;
7349     }
7350 };
7351 
7352 /************************************************************************/
7353 /*                            ReadWrite()                               */
7354 /************************************************************************/
7355 
ReadWrite(GDALRWFlag eRWFlag,const GUInt64 * arrayStartIdx,const size_t * count,const GInt64 * arrayStep,const GPtrDiff_t * bufferStride,const GDALExtendedDataType & bufferDataType,void * pBuffer) const7356 bool GDALMDArrayFromRasterBand::ReadWrite(GDALRWFlag eRWFlag,
7357                                           const GUInt64* arrayStartIdx,
7358                                           const size_t* count,
7359                                           const GInt64* arrayStep,
7360                                           const GPtrDiff_t* bufferStride,
7361                                           const GDALExtendedDataType& bufferDataType,
7362                                           void* pBuffer) const
7363 {
7364     if( bufferDataType.GetClass() != GEDTC_NUMERIC )
7365         return false;
7366     const auto eDT(bufferDataType.GetNumericDataType());
7367     const auto nDTSize(GDALGetDataTypeSizeBytes(eDT));
7368     constexpr int kX = 1;
7369     constexpr int kY = 0;
7370     const int nX = arrayStep[kX] > 0  ?
7371         static_cast<int>(arrayStartIdx[kX]) :
7372         static_cast<int>(arrayStartIdx[kX] - (count[kX]-1) * -arrayStep[kX]);
7373     const int nY = arrayStep[kY] > 0  ?
7374         static_cast<int>(arrayStartIdx[kY]) :
7375         static_cast<int>(arrayStartIdx[kY] - (count[kY]-1) * -arrayStep[kY]);
7376     const int nSizeX = static_cast<int>(count[kX] * ABS(arrayStep[kX]));
7377     const int nSizeY = static_cast<int>(count[kY] * ABS(arrayStep[kY]));
7378     GByte* pabyBuffer = static_cast<GByte*>(pBuffer);
7379     int nStrideXSign = 1;
7380     if( arrayStep[kX] < 0 )
7381     {
7382         pabyBuffer += (count[kX]-1) * bufferStride[kX] * nDTSize;
7383         nStrideXSign = -1;
7384     }
7385     int nStrideYSign = 1;
7386     if( arrayStep[kY] < 0 )
7387     {
7388         pabyBuffer += (count[kY]-1) * bufferStride[kY] * nDTSize;
7389         nStrideYSign = -1;
7390     }
7391 
7392     return m_poBand->RasterIO(eRWFlag,
7393             nX, nY, nSizeX, nSizeY,
7394             pabyBuffer,
7395             static_cast<int>(count[kX]),
7396             static_cast<int>(count[kY]),
7397             eDT,
7398             static_cast<GSpacing>(nStrideXSign * bufferStride[kX] * nDTSize),
7399             static_cast<GSpacing>(nStrideYSign * bufferStride[kY] * nDTSize),
7400             nullptr) == CE_None;
7401 }
7402 
7403 /************************************************************************/
7404 /*                            AsMDArray()                               */
7405 /************************************************************************/
7406 
7407 /** Return a view of this raster band as a 2D multidimensional GDALMDArray.
7408  *
7409  * The band must be linked to a GDALDataset. If this dataset is not already
7410  * marked as shared, it will be, so that the returned array holds a reference
7411  * to it.
7412  *
7413  * If the dataset has a geotransform attached, the X and Y dimensions of the
7414  * returned array will have an associated indexing variable.
7415  *
7416  * This is the same as the C function GDALRasterBandAsMDArray().
7417  *
7418  * The "reverse" method is GDALMDArray::AsClassicDataset().
7419  *
7420  * @return a new array, or nullptr.
7421  *
7422  * @since GDAL 3.1
7423  */
AsMDArray() const7424 std::shared_ptr<GDALMDArray> GDALRasterBand::AsMDArray() const
7425 {
7426     if( !poDS )
7427     {
7428         CPLError(CE_Failure, CPLE_AppDefined, "Band not attached to a dataset");
7429         return nullptr;
7430     }
7431     if( !poDS->GetShared() )
7432     {
7433         poDS->MarkAsShared();
7434     }
7435     return GDALMDArrayFromRasterBand::Create(poDS,
7436                                              const_cast<GDALRasterBand*>(this));
7437 }
7438