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>
AutoLoadPythonDrivers()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 
64 GDALRasterBand::GDALRasterBand() :
65     GDALRasterBand(CPLTestBool( CPLGetConfigOption( "GDAL_FORCE_CACHING", "NO") ) )
66 {
67 }
68 
IncRefAndReturn(PyObject * obj)69 /** Constructor. Applications should never create GDALRasterBands directly.
70  * @param bForceCachedIOIn Whether cached IO should be forced.
71  */
72 GDALRasterBand::GDALRasterBand(int bForceCachedIOIn):
73     bForceCachedIO(bForceCachedIOIn)
74 
75 {
76 }
77 
78 /************************************************************************/
CallPython(PyObject * function)79 /*                          ~GDALRasterBand()                           */
80 /************************************************************************/
81 
82 /*! Destructor. Applications should never destroy GDALRasterBands directly,
83     instead destroy the GDALDataset. */
84 
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 
InitializePythonAndLoadGDALPythonDriverModule()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 
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
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) );
~PythonPluginLayer()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
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  *
SetAttributeFilter(const char * pszFilter)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 
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()                            */
TestCapability(const char * pszCap)558 /************************************************************************/
559 
560 /**
561  * \brief Read a block of image data efficiently.
562  *
563  * @see GDALRasterBand::ReadBlock()
564  */
565 
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 
GetFIDColumn()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 
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()                             */
layer_featureCount(PyObject *,PyObject * args,PyObject *)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 
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 
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.
TranslateToOGRFeature(PyObject * poObj)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 */
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 
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 
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 
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 
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
905 GDALGetBlockSize( GDALRasterBandH hBand, int * pnXSize, int * pnYSize )
906 
907 {
908     VALIDATE_POINTER0( hBand, "GDALGetBlockSize" );
GetFeature(GIntBig nFID)909 
910     GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
911     poBand->GetBlockSize( pnXSize, pnYSize );
912 }
913 
914 /************************************************************************/
915 /*                           InitBlockInfo()                            */
916 /************************************************************************/
917 
918 //! @cond Doxygen_Suppress
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;
ResetReading()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) )
GetNextFeature()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 /************************************************************************/
GetLayerDefn()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 
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 
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 
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
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  */
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 
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 
GetGeomFields()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 
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,
GetMetadata(PyObject * obj,const char * pszDomain)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
GetMetadata(const char * pszDomain)1366  *
1367  * @return CE_Failure if the write fails, otherwise CE_None
1368  */
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  */
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 }
GetLayerCount()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 
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 
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  */
GetMetadata(const char * pszDomain)1514 
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 
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
LoadPlugin()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 
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
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 
1615 double GDALRasterBand::GetNoDataValue( int *pbSuccess )
1616 
1617 {
1618     if( pbSuccess != nullptr )
1619         *pbSuccess = FALSE;
1620 
1621     return -1e10;
1622 }
BuildIdentifyOpenArgs(GDALOpenInfo * poOpenInfo,PyObject * & pyArgs,PyObject * & pyKwargs)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
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
Identify(GDALOpenInfo * poOpenInfo)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 
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
1703 GDALSetRasterNoDataValue( GDALRasterBandH hBand, double dfValue )
IdentifyEx(GDALDriver * poDrv,GDALOpenInfo * poOpenInfo)1704 
1705 {
1706     VALIDATE_POINTER1( hBand, "GDALSetRasterNoDataValue", CE_Failure );
1707 
1708     GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
1709     return poBand->SetNoDataValue( dfValue );
1710 }
1711 
1712 /************************************************************************/
Open(GDALOpenInfo * poOpenInfo)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 
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
1751 GDALDeleteRasterNoDataValue( GDALRasterBandH hBand )
1752 
1753 {
1754     VALIDATE_POINTER1( hBand, "GDALDeleteRasterNoDataValue", CE_Failure );
1755 
1756     GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
OpenEx(GDALDriver * poDrv,GDALOpenInfo * poOpenInfo)1757     return poBand->DeleteNoDataValue();
1758 }
1759 
1760 /************************************************************************/
1761 /*                             GetMaximum()                             */
1762 /************************************************************************/
1763 
1764 /**
1765  * \brief Fetch the maximum value for this band.
1766  *
PythonPluginDriver(const char * pszFilename,const char * pszPluginName,char ** papszMD)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 
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
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 
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:
AutoLoadPythonDrivers()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
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  */
CleanupPythonDrivers()1957 
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
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 
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
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 
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 
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 
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
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 
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 
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 
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 
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 
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 
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 
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
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
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 
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 
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 
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 
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
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 
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 
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 
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
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 
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 
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 
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 
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 
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 
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 
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 
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 
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 
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 
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 
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 
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 
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
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
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
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 
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 
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 
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
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 
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 
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 
3857         explicit GDALUInt128(__uint128_t valIn) : val(valIn) {}
3858 
3859     public:
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 
3866         GDALUInt128 operator- (const GDALUInt128& other) const
3867         {
3868             return GDALUInt128(val - other.val);
3869         }
3870 
3871         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 
3886         GDALUInt128(GUIntBig lowIn, GUIntBig highIn):
3887                                         low(lowIn), high(highIn) {}
3888 
3889     public:
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 
3920         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 
3929         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>
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<>
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>
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<>
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
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<>
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
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 
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
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 
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 
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 
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 
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
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  */
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 
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 
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 
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 
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 
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 
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  */
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 
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  */
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 
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
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 
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 
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 
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 
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 
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 
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 
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 
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 
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 
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 
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 
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 
7033 void GDALRasterBand::LeaveReadWrite()
7034 {
7035     if( poDS != nullptr )
7036         poDS->LeaveReadWrite();
7037 }
7038 
7039 /************************************************************************/
7040 /*                           InitRWLock()                               */
7041 /************************************************************************/
7042 
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:
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 
7202     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 
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:
7225     ~GDALMDArrayFromRasterBand()
7226     {
7227         m_poDS->ReleaseRef();
7228     }
7229 
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 
7239     bool IsWritable() const override { return m_poDS->GetAccess() == GA_Update; }
7240 
7241     const std::vector<std::shared_ptr<GDALDimension>>& GetDimensions() const override { return m_dims; }
7242 
7243     const GDALExtendedDataType &GetDataType() const override { return m_dt; }
7244 
7245     const std::string& GetUnit() const override { return m_osUnit; }
7246 
7247     const void* GetRawNoDataValue() const override
7248     { return m_pabyNoData.empty() ? nullptr: m_pabyNoData.data(); }
7249 
7250     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 
7261     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 
7272     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 
7295     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:
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 
7318         const std::vector<std::shared_ptr<GDALDimension>>& GetDimensions() const override { return m_dims; }
7319 
7320         const GDALExtendedDataType &GetDataType() const override { return m_dt; }
7321 
7322         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 
7334     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 
7356 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  */
7424 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