LCOV - code coverage report
Current view: top level - gcore - gdalrasterband.cpp (source / functions) Hit Total Coverage
Test: gdal_filtered.info Lines: 2385 3010 79.2 %
Date: 2024-11-21 22:18:42 Functions: 215 238 90.3 %

          Line data    Source code
       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             :  * SPDX-License-Identifier: MIT
      13             :  ****************************************************************************/
      14             : 
      15             : #include "cpl_port.h"
      16             : #include "gdal_priv.h"
      17             : 
      18             : #include <climits>
      19             : #include <cmath>
      20             : #include <cstdarg>
      21             : #include <cstddef>
      22             : #include <cstdio>
      23             : #include <cstdlib>
      24             : #include <cstring>
      25             : #include <algorithm>
      26             : #include <limits>
      27             : #include <memory>
      28             : #include <new>
      29             : #include <type_traits>
      30             : 
      31             : #include "cpl_conv.h"
      32             : #include "cpl_error.h"
      33             : #include "cpl_progress.h"
      34             : #include "cpl_string.h"
      35             : #include "cpl_virtualmem.h"
      36             : #include "cpl_vsi.h"
      37             : #include "gdal.h"
      38             : #include "gdal_rat.h"
      39             : #include "gdal_priv_templates.hpp"
      40             : #include "gdal_interpolateatpoint.h"
      41             : #include "gdal_minmax_element.hpp"
      42             : 
      43             : /************************************************************************/
      44             : /*                           GDALRasterBand()                           */
      45             : /************************************************************************/
      46             : 
      47             : /*! Constructor. Applications should never create GDALRasterBands directly. */
      48             : 
      49      995277 : GDALRasterBand::GDALRasterBand()
      50             :     : GDALRasterBand(
      51      995277 :           CPLTestBool(CPLGetConfigOption("GDAL_FORCE_CACHING", "NO")))
      52             : {
      53      995176 : }
      54             : 
      55             : /** Constructor. Applications should never create GDALRasterBands directly.
      56             :  * @param bForceCachedIOIn Whether cached IO should be forced.
      57             :  */
      58     1063820 : GDALRasterBand::GDALRasterBand(int bForceCachedIOIn)
      59     1063820 :     : bForceCachedIO(bForceCachedIOIn)
      60             : 
      61             : {
      62     1063640 : }
      63             : 
      64             : /************************************************************************/
      65             : /*                          ~GDALRasterBand()                           */
      66             : /************************************************************************/
      67             : 
      68             : /*! Destructor. Applications should never destroy GDALRasterBands directly,
      69             :     instead destroy the GDALDataset. */
      70             : 
      71     1063800 : GDALRasterBand::~GDALRasterBand()
      72             : 
      73             : {
      74     1063820 :     if (poDS && poDS->IsMarkedSuppressOnClose())
      75             :     {
      76         433 :         if (poBandBlockCache)
      77         384 :             poBandBlockCache->DisableDirtyBlockWriting();
      78             :     }
      79     1063820 :     GDALRasterBand::FlushCache(true);
      80             : 
      81     1063820 :     delete poBandBlockCache;
      82             : 
      83     1063820 :     if (static_cast<GIntBig>(nBlockReads) >
      84     1063820 :             static_cast<GIntBig>(nBlocksPerRow) * nBlocksPerColumn &&
      85         204 :         nBand == 1 && poDS != nullptr)
      86             :     {
      87         288 :         CPLDebug(
      88             :             "GDAL", "%d block reads on " CPL_FRMT_GIB " block band 1 of %s.",
      89         144 :             nBlockReads, static_cast<GIntBig>(nBlocksPerRow) * nBlocksPerColumn,
      90         144 :             poDS->GetDescription());
      91             :     }
      92             : 
      93     1063820 :     InvalidateMaskBand();
      94     1063800 :     nBand = -nBand;
      95             : 
      96     1063800 :     delete m_poPointsCache;
      97     1063810 : }
      98             : 
      99             : /************************************************************************/
     100             : /*                              RasterIO()                              */
     101             : /************************************************************************/
     102             : 
     103             : /**
     104             :  * \fn GDALRasterBand::IRasterIO( GDALRWFlag eRWFlag,
     105             :  *                                int nXOff, int nYOff, int nXSize, int nYSize,
     106             :  *                                void * pData, int nBufXSize, int nBufYSize,
     107             :  *                                GDALDataType eBufType,
     108             :  *                                GSpacing nPixelSpace,
     109             :  *                                GSpacing nLineSpace,
     110             :  *                                GDALRasterIOExtraArg* psExtraArg )
     111             :  * \brief Read/write a region of image data for this band.
     112             :  *
     113             :  * This method allows reading a region of a GDALRasterBand into a buffer,
     114             :  * or writing data from a buffer into a region of a GDALRasterBand. It
     115             :  * automatically takes care of data type translation if the data type
     116             :  * (eBufType) of the buffer is different than that of the GDALRasterBand.
     117             :  * The method also takes care of image decimation / replication if the
     118             :  * buffer size (nBufXSize x nBufYSize) is different than the size of the
     119             :  * region being accessed (nXSize x nYSize).
     120             :  *
     121             :  * The window of interest expressed by (nXOff, nYOff, nXSize, nYSize) should be
     122             :  * fully within the raster space, that is nXOff >= 0, nYOff >= 0,
     123             :  * nXOff + nXSize <= GetXSize() and nYOff + nYSize <= GetYSize().
     124             :  * If reads larger than the raster space are wished, GDALTranslate() might be used.
     125             :  * Or use nLineSpace and a possibly shifted pData value.
     126             :  *
     127             :  * The nPixelSpace and nLineSpace parameters allow reading into or
     128             :  * writing from unusually organized buffers. This is primarily used
     129             :  * for buffers containing more than one bands raster data in interleaved
     130             :  * format.
     131             :  *
     132             :  * Some formats may efficiently implement decimation into a buffer by
     133             :  * reading from lower resolution overview images. The logic of the default
     134             :  * implementation in the base class GDALRasterBand is the following one. It
     135             :  * computes a target_downscaling_factor from the window of interest and buffer
     136             :  * size which is min(nXSize/nBufXSize, nYSize/nBufYSize).
     137             :  * It then walks through overviews and will select the first one whose
     138             :  * downscaling factor is greater than target_downscaling_factor / 1.2.
     139             :  *
     140             :  * Let's assume we have overviews at downscaling factors 2, 4 and 8.
     141             :  * The relationship between target_downscaling_factor and the select overview
     142             :  * level is the following one:
     143             :  *
     144             :  * target_downscaling_factor  | selected_overview
     145             :  * -------------------------  | -----------------
     146             :  * ]0,       2 / 1.2]         | full resolution band
     147             :  * ]2 / 1.2, 4 / 1.2]         | 2x downsampled band
     148             :  * ]4 / 1.2, 8 / 1.2]         | 4x downsampled band
     149             :  * ]8 / 1.2, infinity[        | 8x downsampled band
     150             :  *
     151             :  * Note that starting with GDAL 3.9, this 1.2 oversampling factor can be
     152             :  * modified by setting the GDAL_OVERVIEW_OVERSAMPLING_THRESHOLD configuration
     153             :  * option. Also note that starting with GDAL 3.9, when the resampling algorithm
     154             :  * specified in psExtraArg->eResampleAlg is different from GRIORA_NearestNeighbour,
     155             :  * this oversampling threshold defaults to 1. Consequently if there are overviews
     156             :  * of downscaling factor 2, 4 and 8, and the desired downscaling factor is
     157             :  * 7.99, the overview of factor 4 will be selected for a non nearest resampling.
     158             :  *
     159             :  * For highest performance full resolution data access, read and write
     160             :  * on "block boundaries" as returned by GetBlockSize(), or use the
     161             :  * ReadBlock() and WriteBlock() methods.
     162             :  *
     163             :  * This method is the same as the C GDALRasterIO() or GDALRasterIOEx()
     164             :  * functions.
     165             :  *
     166             :  * @param eRWFlag Either GF_Read to read a region of data, or GF_Write to
     167             :  * write a region of data.
     168             :  *
     169             :  * @param nXOff The pixel offset to the top left corner of the region
     170             :  * of the band to be accessed. This would be zero to start from the left side.
     171             :  *
     172             :  * @param nYOff The line offset to the top left corner of the region
     173             :  * of the band to be accessed. This would be zero to start from the top.
     174             :  *
     175             :  * @param nXSize The width of the region of the band to be accessed in pixels.
     176             :  *
     177             :  * @param nYSize The height of the region of the band to be accessed in lines.
     178             :  *
     179             :  * @param pData The buffer into which the data should be read, or from which
     180             :  * it should be written. This buffer must contain at least nBufXSize *
     181             :  * nBufYSize words of type eBufType. It is organized in left to right,
     182             :  * top to bottom pixel order. Spacing is controlled by the nPixelSpace,
     183             :  * and nLineSpace parameters.
     184             :  * Note that even with eRWFlag==GF_Write, the content of the buffer might be
     185             :  * temporarily modified during the execution of this method (and eventually
     186             :  * restored back to its original content), so it is not safe to use a buffer
     187             :  * stored in a read-only section of the calling program.
     188             :  *
     189             :  * @param nBufXSize the width of the buffer image into which the desired region
     190             :  * is to be read, or from which it is to be written.
     191             :  *
     192             :  * @param nBufYSize the height of the buffer image into which the desired region
     193             :  * is to be read, or from which it is to be written.
     194             :  *
     195             :  * @param eBufType the type of the pixel values in the pData data buffer. The
     196             :  * pixel values will automatically be translated to/from the GDALRasterBand
     197             :  * data type as needed. Most driver implementations will use GDALCopyWords64()
     198             :  * to perform data type translation.
     199             :  *
     200             :  * @param nPixelSpace The byte offset from the start of one pixel value in
     201             :  * pData to the start of the next pixel value within a scanline. If defaulted
     202             :  * (0) the size of the datatype eBufType is used.
     203             :  *
     204             :  * @param nLineSpace The byte offset from the start of one scanline in
     205             :  * pData to the start of the next. If defaulted (0) the size of the datatype
     206             :  * eBufType * nBufXSize is used.
     207             :  *
     208             :  * @param psExtraArg (new in GDAL 2.0) pointer to a GDALRasterIOExtraArg
     209             :  * structure with additional arguments to specify resampling and progress
     210             :  * callback, or NULL for default behavior. The GDAL_RASTERIO_RESAMPLING
     211             :  * configuration option can also be defined to override the default resampling
     212             :  * to one of BILINEAR, CUBIC, CUBICSPLINE, LANCZOS, AVERAGE or MODE.
     213             :  *
     214             :  * @return CE_Failure if the access fails, otherwise CE_None.
     215             :  */
     216             : 
     217             : /**
     218             :  * \brief Read/write a region of image data for this band.
     219             :  *
     220             :  * This method allows reading a region of a GDALRasterBand into a buffer,
     221             :  * or writing data from a buffer into a region of a GDALRasterBand. It
     222             :  * automatically takes care of data type translation if the data type
     223             :  * (eBufType) of the buffer is different than that of the GDALRasterBand.
     224             :  * The method also takes care of image decimation / replication if the
     225             :  * buffer size (nBufXSize x nBufYSize) is different than the size of the
     226             :  * region being accessed (nXSize x nYSize).
     227             :  *
     228             :  * The window of interest expressed by (nXOff, nYOff, nXSize, nYSize) should be
     229             :  * fully within the raster space, that is nXOff >= 0, nYOff >= 0,
     230             :  * nXOff + nXSize <= GetXSize() and nYOff + nYSize <= GetYSize().
     231             :  * If reads larger than the raster space are wished, GDALTranslate() might be used.
     232             :  * Or use nLineSpace and a possibly shifted pData value.
     233             :  *
     234             :  * The nPixelSpace and nLineSpace parameters allow reading into or
     235             :  * writing from unusually organized buffers. This is primarily used
     236             :  * for buffers containing more than one bands raster data in interleaved
     237             :  * format.
     238             :  *
     239             :  * Some formats may efficiently implement decimation into a buffer by
     240             :  * reading from lower resolution overview images. The logic of the default
     241             :  * implementation in the base class GDALRasterBand is the following one. It
     242             :  * computes a target_downscaling_factor from the window of interest and buffer
     243             :  * size which is min(nXSize/nBufXSize, nYSize/nBufYSize).
     244             :  * It then walks through overviews and will select the first one whose
     245             :  * downscaling factor is greater than target_downscaling_factor / 1.2.
     246             :  *
     247             :  * Let's assume we have overviews at downscaling factors 2, 4 and 8.
     248             :  * The relationship between target_downscaling_factor and the select overview
     249             :  * level is the following one:
     250             :  *
     251             :  * target_downscaling_factor  | selected_overview
     252             :  * -------------------------  | -----------------
     253             :  * ]0,       2 / 1.2]         | full resolution band
     254             :  * ]2 / 1.2, 4 / 1.2]         | 2x downsampled band
     255             :  * ]4 / 1.2, 8 / 1.2]         | 4x downsampled band
     256             :  * ]8 / 1.2, infinity[        | 8x downsampled band
     257             :  *
     258             :  * For highest performance full resolution data access, read and write
     259             :  * on "block boundaries" as returned by GetBlockSize(), or use the
     260             :  * ReadBlock() and WriteBlock() methods.
     261             :  *
     262             :  * This method is the same as the C GDALRasterIO() or GDALRasterIOEx()
     263             :  * functions.
     264             :  *
     265             :  * Starting with GDAL 3.10, the GDALRasterBand::ReadRaster() methods may be
     266             :  * more convenient to use for most common use cases.
     267             :  *
     268             :  * As nearly all GDAL methods, this method is *NOT* thread-safe, that is it cannot
     269             :  * be called on the same GDALRasterBand instance (or another GDALRasterBand
     270             :  * instance of this dataset) concurrently from several threads.
     271             :  *
     272             :  * @param eRWFlag Either GF_Read to read a region of data, or GF_Write to
     273             :  * write a region of data.
     274             :  *
     275             :  * @param nXOff The pixel offset to the top left corner of the region
     276             :  * of the band to be accessed. This would be zero to start from the left side.
     277             :  *
     278             :  * @param nYOff The line offset to the top left corner of the region
     279             :  * of the band to be accessed. This would be zero to start from the top.
     280             :  *
     281             :  * @param nXSize The width of the region of the band to be accessed in pixels.
     282             :  *
     283             :  * @param nYSize The height of the region of the band to be accessed in lines.
     284             :  *
     285             :  * @param[in,out] pData The buffer into which the data should be read, or from
     286             :  * which it should be written. This buffer must contain at least nBufXSize *
     287             :  * nBufYSize words of type eBufType. It is organized in left to right,
     288             :  * top to bottom pixel order. Spacing is controlled by the nPixelSpace,
     289             :  * and nLineSpace parameters.
     290             :  *
     291             :  * @param nBufXSize the width of the buffer image into which the desired region
     292             :  * is to be read, or from which it is to be written.
     293             :  *
     294             :  * @param nBufYSize the height of the buffer image into which the desired region
     295             :  * is to be read, or from which it is to be written.
     296             :  *
     297             :  * @param eBufType the type of the pixel values in the pData data buffer. The
     298             :  * pixel values will automatically be translated to/from the GDALRasterBand
     299             :  * data type as needed.
     300             :  *
     301             :  * @param nPixelSpace The byte offset from the start of one pixel value in
     302             :  * pData to the start of the next pixel value within a scanline. If defaulted
     303             :  * (0) the size of the datatype eBufType is used.
     304             :  *
     305             :  * @param nLineSpace The byte offset from the start of one scanline in
     306             :  * pData to the start of the next. If defaulted (0) the size of the datatype
     307             :  * eBufType * nBufXSize is used.
     308             :  *
     309             :  * @param[in] psExtraArg (new in GDAL 2.0) pointer to a GDALRasterIOExtraArg
     310             :  * structure with additional arguments to specify resampling and progress
     311             :  * callback, or NULL for default behavior. The GDAL_RASTERIO_RESAMPLING
     312             :  * configuration option can also be defined to override the default resampling
     313             :  * to one of BILINEAR, CUBIC, CUBICSPLINE, LANCZOS, AVERAGE or MODE.
     314             :  *
     315             :  * @return CE_Failure if the access fails, otherwise CE_None.
     316             :  *
     317             :  * @see GDALRasterBand::ReadRaster()
     318             :  */
     319             : 
     320     3661470 : CPLErr GDALRasterBand::RasterIO(GDALRWFlag eRWFlag, int nXOff, int nYOff,
     321             :                                 int nXSize, int nYSize, void *pData,
     322             :                                 int nBufXSize, int nBufYSize,
     323             :                                 GDALDataType eBufType, GSpacing nPixelSpace,
     324             :                                 GSpacing nLineSpace,
     325             :                                 GDALRasterIOExtraArg *psExtraArg)
     326             : 
     327             : {
     328             :     GDALRasterIOExtraArg sExtraArg;
     329     3661470 :     if (psExtraArg == nullptr)
     330             :     {
     331     3578820 :         INIT_RASTERIO_EXTRA_ARG(sExtraArg);
     332     3578820 :         psExtraArg = &sExtraArg;
     333             :     }
     334       82650 :     else if (CPL_UNLIKELY(psExtraArg->nVersion !=
     335             :                           RASTERIO_EXTRA_ARG_CURRENT_VERSION))
     336             :     {
     337           0 :         ReportError(CE_Failure, CPLE_AppDefined,
     338             :                     "Unhandled version of GDALRasterIOExtraArg");
     339           0 :         return CE_Failure;
     340             :     }
     341             : 
     342     3661470 :     GDALRasterIOExtraArgSetResampleAlg(psExtraArg, nXSize, nYSize, nBufXSize,
     343             :                                        nBufYSize);
     344             : 
     345     3658890 :     if (CPL_UNLIKELY(nullptr == pData))
     346             :     {
     347           0 :         ReportError(CE_Failure, CPLE_AppDefined,
     348             :                     "The buffer into which the data should be read is null");
     349           0 :         return CE_Failure;
     350             :     }
     351             : 
     352             :     /* -------------------------------------------------------------------- */
     353             :     /*      Some size values are "noop".  Lets just return to avoid         */
     354             :     /*      stressing lower level functions.                                */
     355             :     /* -------------------------------------------------------------------- */
     356     3658890 :     if (CPL_UNLIKELY(nXSize < 1 || nYSize < 1 || nBufXSize < 1 ||
     357             :                      nBufYSize < 1))
     358             :     {
     359           2 :         CPLDebug("GDAL",
     360             :                  "RasterIO() skipped for odd window or buffer size.\n"
     361             :                  "  Window = (%d,%d)x%dx%d\n"
     362             :                  "  Buffer = %dx%d\n",
     363             :                  nXOff, nYOff, nXSize, nYSize, nBufXSize, nBufYSize);
     364             : 
     365           2 :         return CE_None;
     366             :     }
     367             : 
     368     3658880 :     if (eRWFlag == GF_Write)
     369             :     {
     370      172032 :         if (CPL_UNLIKELY(eFlushBlockErr != CE_None))
     371             :         {
     372           0 :             ReportError(eFlushBlockErr, CPLE_AppDefined,
     373             :                         "An error occurred while writing a dirty block "
     374             :                         "from GDALRasterBand::RasterIO");
     375           0 :             CPLErr eErr = eFlushBlockErr;
     376           0 :             eFlushBlockErr = CE_None;
     377           0 :             return eErr;
     378             :         }
     379      172032 :         if (CPL_UNLIKELY(eAccess != GA_Update))
     380             :         {
     381           3 :             ReportError(CE_Failure, CPLE_AppDefined,
     382             :                         "Write operation not permitted on dataset opened "
     383             :                         "in read-only mode");
     384           3 :             return CE_Failure;
     385             :         }
     386             :     }
     387             : 
     388             :     /* -------------------------------------------------------------------- */
     389             :     /*      If pixel and line spacing are defaulted assign reasonable      */
     390             :     /*      value assuming a packed buffer.                                 */
     391             :     /* -------------------------------------------------------------------- */
     392     3658880 :     if (nPixelSpace == 0)
     393             :     {
     394     3575480 :         nPixelSpace = GDALGetDataTypeSizeBytes(eBufType);
     395             :     }
     396             : 
     397     3656220 :     if (nLineSpace == 0)
     398             :     {
     399     3567420 :         nLineSpace = nPixelSpace * nBufXSize;
     400             :     }
     401             : 
     402             :     /* -------------------------------------------------------------------- */
     403             :     /*      Do some validation of parameters.                               */
     404             :     /* -------------------------------------------------------------------- */
     405     3656220 :     if (CPL_UNLIKELY(nXOff < 0 || nXOff > INT_MAX - nXSize ||
     406             :                      nXOff + nXSize > nRasterXSize || nYOff < 0 ||
     407             :                      nYOff > INT_MAX - nYSize || nYOff + nYSize > nRasterYSize))
     408             :     {
     409          14 :         ReportError(CE_Failure, CPLE_IllegalArg,
     410             :                     "Access window out of range in RasterIO().  Requested\n"
     411             :                     "(%d,%d) of size %dx%d on raster of %dx%d.",
     412             :                     nXOff, nYOff, nXSize, nYSize, nRasterXSize, nRasterYSize);
     413          14 :         return CE_Failure;
     414             :     }
     415             : 
     416     3656200 :     if (CPL_UNLIKELY(eRWFlag != GF_Read && eRWFlag != GF_Write))
     417             :     {
     418           0 :         ReportError(
     419             :             CE_Failure, CPLE_IllegalArg,
     420             :             "eRWFlag = %d, only GF_Read (0) and GF_Write (1) are legal.",
     421             :             eRWFlag);
     422           0 :         return CE_Failure;
     423             :     }
     424     3656200 :     if (CPL_UNLIKELY(eBufType == GDT_Unknown || eBufType == GDT_TypeCount))
     425             :     {
     426           2 :         ReportError(CE_Failure, CPLE_IllegalArg,
     427             :                     "Illegal GDT_Unknown/GDT_TypeCount argument");
     428           2 :         return CE_Failure;
     429             :     }
     430             : 
     431             :     /* -------------------------------------------------------------------- */
     432             :     /*      Call the format specific function.                              */
     433             :     /* -------------------------------------------------------------------- */
     434             : 
     435     3656200 :     const bool bCallLeaveReadWrite = CPL_TO_BOOL(EnterReadWrite(eRWFlag));
     436             : 
     437             :     CPLErr eErr;
     438     3658390 :     if (bForceCachedIO)
     439          22 :         eErr = GDALRasterBand::IRasterIO(eRWFlag, nXOff, nYOff, nXSize, nYSize,
     440             :                                          pData, nBufXSize, nBufYSize, eBufType,
     441             :                                          nPixelSpace, nLineSpace, psExtraArg);
     442             :     else
     443             :         eErr =
     444     3661100 :             IRasterIO(eRWFlag, nXOff, nYOff, nXSize, nYSize, pData, nBufXSize,
     445     3658360 :                       nBufYSize, eBufType, nPixelSpace, nLineSpace, psExtraArg);
     446             : 
     447     3661120 :     if (bCallLeaveReadWrite)
     448      178828 :         LeaveReadWrite();
     449             : 
     450     3659480 :     return eErr;
     451             : }
     452             : 
     453             : /************************************************************************/
     454             : /*                            GDALRasterIO()                            */
     455             : /************************************************************************/
     456             : 
     457             : /**
     458             :  * \brief Read/write a region of image data for this band.
     459             :  *
     460             :  * Use GDALRasterIOEx() if 64 bit spacings or extra arguments (resampling
     461             :  * resolution, progress callback, etc. are needed)
     462             :  *
     463             :  * @see GDALRasterBand::RasterIO()
     464             :  */
     465             : 
     466     3358410 : CPLErr CPL_STDCALL GDALRasterIO(GDALRasterBandH hBand, GDALRWFlag eRWFlag,
     467             :                                 int nXOff, int nYOff, int nXSize, int nYSize,
     468             :                                 void *pData, int nBufXSize, int nBufYSize,
     469             :                                 GDALDataType eBufType, int nPixelSpace,
     470             :                                 int nLineSpace)
     471             : 
     472             : {
     473     3358410 :     VALIDATE_POINTER1(hBand, "GDALRasterIO", CE_Failure);
     474             : 
     475     3358410 :     GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
     476             : 
     477     3356480 :     return (poBand->RasterIO(eRWFlag, nXOff, nYOff, nXSize, nYSize, pData,
     478             :                              nBufXSize, nBufYSize, eBufType, nPixelSpace,
     479     3357520 :                              nLineSpace, nullptr));
     480             : }
     481             : 
     482             : /************************************************************************/
     483             : /*                            GDALRasterIOEx()                          */
     484             : /************************************************************************/
     485             : 
     486             : /**
     487             :  * \brief Read/write a region of image data for this band.
     488             :  *
     489             :  * @see GDALRasterBand::RasterIO()
     490             :  * @since GDAL 2.0
     491             :  */
     492             : 
     493       31573 : CPLErr CPL_STDCALL GDALRasterIOEx(GDALRasterBandH hBand, GDALRWFlag eRWFlag,
     494             :                                   int nXOff, int nYOff, int nXSize, int nYSize,
     495             :                                   void *pData, int nBufXSize, int nBufYSize,
     496             :                                   GDALDataType eBufType, GSpacing nPixelSpace,
     497             :                                   GSpacing nLineSpace,
     498             :                                   GDALRasterIOExtraArg *psExtraArg)
     499             : 
     500             : {
     501       31573 :     VALIDATE_POINTER1(hBand, "GDALRasterIOEx", CE_Failure);
     502             : 
     503       31573 :     GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
     504             : 
     505       31573 :     return (poBand->RasterIO(eRWFlag, nXOff, nYOff, nXSize, nYSize, pData,
     506             :                              nBufXSize, nBufYSize, eBufType, nPixelSpace,
     507       31572 :                              nLineSpace, psExtraArg));
     508             : }
     509             : 
     510             : /************************************************************************/
     511             : /*                           GetGDTFromCppType()                        */
     512             : /************************************************************************/
     513             : 
     514             : namespace
     515             : {
     516             : template <class T> struct GetGDTFromCppType;
     517             : 
     518             : #define DEFINE_GetGDTFromCppType(T, eDT)                                       \
     519             :     template <> struct GetGDTFromCppType<T>                                    \
     520             :     {                                                                          \
     521             :         static constexpr GDALDataType GDT = eDT;                               \
     522             :     }
     523             : 
     524             : DEFINE_GetGDTFromCppType(uint8_t, GDT_Byte);
     525             : DEFINE_GetGDTFromCppType(int8_t, GDT_Int8);
     526             : DEFINE_GetGDTFromCppType(uint16_t, GDT_UInt16);
     527             : DEFINE_GetGDTFromCppType(int16_t, GDT_Int16);
     528             : DEFINE_GetGDTFromCppType(uint32_t, GDT_UInt32);
     529             : DEFINE_GetGDTFromCppType(int32_t, GDT_Int32);
     530             : DEFINE_GetGDTFromCppType(uint64_t, GDT_UInt64);
     531             : DEFINE_GetGDTFromCppType(int64_t, GDT_Int64);
     532             : DEFINE_GetGDTFromCppType(float, GDT_Float32);
     533             : DEFINE_GetGDTFromCppType(double, GDT_Float64);
     534             : // Not allowed by C++ standard
     535             : //DEFINE_GetGDTFromCppType(std::complex<int16_t>, GDT_CInt16);
     536             : //DEFINE_GetGDTFromCppType(std::complex<int32_t>, GDT_CInt32);
     537             : DEFINE_GetGDTFromCppType(std::complex<float>, GDT_CFloat32);
     538             : DEFINE_GetGDTFromCppType(std::complex<double>, GDT_CFloat64);
     539             : }  // namespace
     540             : 
     541             : /************************************************************************/
     542             : /*                           ReadRaster()                               */
     543             : /************************************************************************/
     544             : 
     545             : // clang-format off
     546             : /** Read a region of image data for this band.
     547             :  *
     548             :  * This is a slightly more convenient alternative to GDALRasterBand::RasterIO()
     549             :  * for common use cases, like reading a whole band.
     550             :  * It infers the GDAL data type of the buffer from the C/C++ type of the buffer.
     551             :  * This template is instantiated for the following types: [u?]int[8|16|32|64]_t,
     552             :  * float, double, std::complex<float|double>.
     553             :  *
     554             :  * When possible prefer the ReadRaster(std::vector<T>& vData, double dfXOff, double dfYOff, double dfXSize, double dfYSize, size_t nBufXSize, size_t nBufYSize, GDALRIOResampleAlg eResampleAlg, GDALProgressFunc pfnProgress, void *pProgressData) const variant that takes a std::vector<T>&,
     555             :  * and can allocate memory automatically.
     556             :  *
     557             :  * To read a whole band (assuming it fits into memory), as an array of double:
     558             :  *
     559             : \code{.cpp}
     560             :  double* myArray = static_cast<double*>(
     561             :      VSI_MALLOC3_VERBOSE(sizeof(double), poBand->GetXSize(), poBand->GetYSize()));
     562             :  // TODO: check here that myArray != nullptr
     563             :  const size_t nArrayEltCount =
     564             :      static_cast<size_t>(poBand->GetXSize()) * poBand->GetYSize());
     565             :  if (poBand->ReadRaster(myArray, nArrayEltCount) == CE_None)
     566             :  {
     567             :      // do something
     568             :  }
     569             :  VSIFree(myArray)
     570             : \endcode
     571             :  *
     572             :  * To read 128x128 pixels starting at (col=12, line=24) as an array of double:
     573             :  *
     574             : \code{.cpp}
     575             :  double* myArray = static_cast<double*>(
     576             :      VSI_MALLOC3_VERBOSE(sizeof(double), 128, 128));
     577             :  // TODO: check here that myArray != nullptr
     578             :  const size_t nArrayEltCount = 128 * 128;
     579             :  if (poBand->ReadRaster(myArray, nArrayEltCount, 12, 24, 128, 128) == CE_None)
     580             :  {
     581             :      // do something
     582             :  }
     583             :  VSIFree(myArray)
     584             : \endcode
     585             :  *
     586             :  * As nearly all GDAL methods, this method is *NOT* thread-safe, that is it cannot
     587             :  * be called on the same GDALRasterBand instance (or another GDALRasterBand
     588             :  * instance of this dataset) concurrently from several threads.
     589             :  *
     590             :  * The window of interest expressed by (dfXOff, dfYOff, dfXSize, dfYSize) should be
     591             :  * fully within the raster space, that is dfXOff >= 0, dfYOff >= 0,
     592             :  * dfXOff + dfXSize <= GetXSize() and dfYOff + dfYSize <= GetYSize().
     593             :  * If reads larger than the raster space are wished, GDALTranslate() might be used.
     594             :  * Or use nLineSpace and a possibly shifted pData value.
     595             :  *
     596             :  * @param[out] pData The buffer into which the data should be written.
     597             :  * This buffer must contain at least nBufXSize *
     598             :  * nBufYSize words of type T. It is organized in left to right,
     599             :  * top to bottom pixel order, and fully packed.
     600             :  * The type of the buffer does not need to be the one of GetDataType(). The
     601             :  * method will perform data type translation (with potential rounding, clamping)
     602             :  * if needed.
     603             :  *
     604             :  * @param nArrayEltCount Number of values of pData. If non zero, the method will
     605             :  * check that it is at least greater or equal to nBufXSize * nBufYSize, and
     606             :  * return in error if it is not. If set to zero, then pData is trusted to be
     607             :  * large enough.
     608             :  *
     609             :  * @param dfXOff The pixel offset to the top left corner of the region
     610             :  * of the band to be accessed. This would be zero to start from the left side.
     611             :  * Defaults to 0.
     612             :  *
     613             :  * @param dfYOff The line offset to the top left corner of the region
     614             :  * of the band to be accessed. This would be zero to start from the top.
     615             :  * Defaults to 0.
     616             :  *
     617             :  * @param dfXSize The width of the region of the band to be accessed in pixels.
     618             :  * If all of dfXOff, dfYOff, dfXSize and dfYSize are left to their zero default value,
     619             :  * dfXSize is set to the band width.
     620             :  *
     621             :  * @param dfYSize The height of the region of the band to be accessed in lines.
     622             :  * If all of dfXOff, dfYOff, dfXSize and dfYSize are left to their zero default value,
     623             :  * dfYSize is set to the band height.
     624             :  *
     625             :  * @param nBufXSize the width of the buffer image into which the desired region
     626             :  * is to be read. If set to zero, and both dfXSize and dfYSize are integer values,
     627             :  * then nBufXSize is initialized with dfXSize.
     628             :  *
     629             :  * @param nBufYSize the height of the buffer image into which the desired region
     630             :  * is to be read. If set to zero, and both dfXSize and dfYSize are integer values,
     631             :  * then nBufYSize is initialized with dfYSize.
     632             :  *
     633             :  * @param eResampleAlg Resampling algorithm. Defaults to GRIORA_NearestNeighbour.
     634             :  *
     635             :  * @param pfnProgress Progress function. May be nullptr.
     636             :  *
     637             :  * @param pProgressData User data of pfnProgress. May be nullptr.
     638             :  *
     639             :  * @return CE_Failure if the access fails, otherwise CE_None.
     640             :  *
     641             :  * @see GDALRasterBand::RasterIO()
     642             :  * @since GDAL 3.10
     643             :  */
     644             : // clang-format on
     645             : 
     646             : template <class T>
     647          19 : CPLErr GDALRasterBand::ReadRaster(T *pData, size_t nArrayEltCount,
     648             :                                   double dfXOff, double dfYOff, double dfXSize,
     649             :                                   double dfYSize, size_t nBufXSize,
     650             :                                   size_t nBufYSize,
     651             :                                   GDALRIOResampleAlg eResampleAlg,
     652             :                                   GDALProgressFunc pfnProgress,
     653             :                                   void *pProgressData) const
     654             : {
     655          19 :     if (((nBufXSize | nBufYSize) >> 31) != 0)
     656             :     {
     657           2 :         return CE_Failure;
     658             :     }
     659             : 
     660          17 :     if (dfXOff == 0 && dfYOff == 0 && dfXSize == 0 && dfYSize == 0)
     661             :     {
     662          15 :         dfXSize = nRasterXSize;
     663          15 :         dfYSize = nRasterYSize;
     664             :     }
     665           2 :     else if (!(dfXOff >= 0 && dfXOff <= INT_MAX) ||
     666           2 :              !(dfYOff >= 0 && dfYOff <= INT_MAX) || !(dfXSize >= 0) ||
     667           2 :              !(dfYSize >= 0) || dfXOff + dfXSize > INT_MAX ||
     668           2 :              dfYOff + dfYSize > INT_MAX)
     669             :     {
     670           0 :         return CE_Failure;
     671             :     }
     672             : 
     673             :     GDALRasterIOExtraArg sExtraArg;
     674          17 :     sExtraArg.nVersion = 1;
     675          17 :     sExtraArg.eResampleAlg = eResampleAlg;
     676          17 :     sExtraArg.pfnProgress = pfnProgress;
     677          17 :     sExtraArg.pProgressData = pProgressData;
     678          17 :     sExtraArg.bFloatingPointWindowValidity = true;
     679          17 :     sExtraArg.dfXOff = dfXOff;
     680          17 :     sExtraArg.dfYOff = dfYOff;
     681          17 :     sExtraArg.dfXSize = dfXSize;
     682          17 :     sExtraArg.dfYSize = dfYSize;
     683          17 :     const int nXOff = static_cast<int>(dfXOff);
     684          17 :     const int nYOff = static_cast<int>(dfYOff);
     685          17 :     const int nXSize = std::max(1, static_cast<int>(dfXSize + 0.5));
     686          17 :     const int nYSize = std::max(1, static_cast<int>(dfYSize + 0.5));
     687          17 :     if (nBufXSize == 0 && nBufYSize == 0)
     688             :     {
     689          16 :         if (static_cast<int>(dfXSize) == dfXSize &&
     690          16 :             static_cast<int>(dfYSize) == dfYSize)
     691             :         {
     692          16 :             nBufXSize = static_cast<int>(dfXSize);
     693          16 :             nBufYSize = static_cast<int>(dfYSize);
     694             :         }
     695             :         else
     696             :         {
     697           0 :             CPLError(CE_Failure, CPLE_AppDefined,
     698             :                      "nBufXSize and nBufYSize must be provided if dfXSize or "
     699             :                      "dfYSize is not an integer value");
     700           0 :             return CE_Failure;
     701             :         }
     702             :     }
     703          17 :     if (nBufXSize == 0 || nBufYSize == 0)
     704             :     {
     705           0 :         CPLDebug("GDAL",
     706             :                  "RasterIO() skipped for odd window or buffer size.\n"
     707             :                  "  Window = (%d,%d)x%dx%d\n"
     708             :                  "  Buffer = %dx%d\n",
     709             :                  nXOff, nYOff, nXSize, nYSize, static_cast<int>(nBufXSize),
     710             :                  static_cast<int>(nBufYSize));
     711             : 
     712           0 :         return CE_None;
     713             :     }
     714             : 
     715          17 :     if (nArrayEltCount > 0 && nBufXSize > nArrayEltCount / nBufYSize)
     716             :     {
     717           1 :         CPLError(CE_Failure, CPLE_AppDefined,
     718             :                  "Provided array is not large enough");
     719           1 :         return CE_Failure;
     720             :     }
     721             : 
     722          16 :     constexpr GSpacing nPixelSpace = sizeof(T);
     723          16 :     const GSpacing nLineSpace = nPixelSpace * nBufXSize;
     724          16 :     constexpr GDALDataType eBufType = GetGDTFromCppType<T>::GDT;
     725             : 
     726          16 :     GDALRasterBand *pThis = const_cast<GDALRasterBand *>(this);
     727             : 
     728             :     const bool bCallLeaveReadWrite =
     729          16 :         CPL_TO_BOOL(pThis->EnterReadWrite(GF_Read));
     730             :     CPLErr eErr;
     731             :     // coverity[identical_branches]
     732          16 :     if (bForceCachedIO)
     733           0 :         eErr = pThis->GDALRasterBand::IRasterIO(
     734             :             GF_Read, nXOff, nYOff, nXSize, nYSize, pData,
     735             :             static_cast<int>(nBufXSize), static_cast<int>(nBufYSize), eBufType,
     736             :             nPixelSpace, nLineSpace, &sExtraArg);
     737             :     else
     738          16 :         eErr = pThis->IRasterIO(GF_Read, nXOff, nYOff, nXSize, nYSize, pData,
     739             :                                 static_cast<int>(nBufXSize),
     740             :                                 static_cast<int>(nBufYSize), eBufType,
     741             :                                 nPixelSpace, nLineSpace, &sExtraArg);
     742             : 
     743          16 :     if (bCallLeaveReadWrite)
     744           0 :         pThis->LeaveReadWrite();
     745             : 
     746          16 :     return eErr;
     747             : }
     748             : 
     749             : //! @cond Doxygen_Suppress
     750             : 
     751             : #define INSTANTIATE_READ_RASTER(T)                                             \
     752             :     template CPLErr CPL_DLL GDALRasterBand::ReadRaster(                        \
     753             :         T *vData, size_t nArrayEltCount, double dfXOff, double dfYOff,         \
     754             :         double dfXSize, double dfYSize, size_t nBufXSize, size_t nBufYSize,    \
     755             :         GDALRIOResampleAlg eResampleAlg, GDALProgressFunc pfnProgress,         \
     756             :         void *pProgressData) const;
     757             : 
     758             : INSTANTIATE_READ_RASTER(uint8_t)
     759             : INSTANTIATE_READ_RASTER(int8_t)
     760             : INSTANTIATE_READ_RASTER(uint16_t)
     761             : INSTANTIATE_READ_RASTER(int16_t)
     762             : INSTANTIATE_READ_RASTER(uint32_t)
     763             : INSTANTIATE_READ_RASTER(int32_t)
     764             : INSTANTIATE_READ_RASTER(uint64_t)
     765             : INSTANTIATE_READ_RASTER(int64_t)
     766             : INSTANTIATE_READ_RASTER(float)
     767             : INSTANTIATE_READ_RASTER(double)
     768             : // Not allowed by C++ standard
     769             : // INSTANTIATE_READ_RASTER(std::complex<int16_t>)
     770             : // INSTANTIATE_READ_RASTER(std::complex<int32_t>)
     771             : INSTANTIATE_READ_RASTER(std::complex<float>)
     772             : INSTANTIATE_READ_RASTER(std::complex<double>)
     773             : 
     774             : //! @endcond
     775             : 
     776             : /************************************************************************/
     777             : /*                           ReadRaster()                               */
     778             : /************************************************************************/
     779             : 
     780             : /** Read a region of image data for this band.
     781             :  *
     782             :  * This is a slightly more convenient alternative to GDALRasterBand::RasterIO()
     783             :  * for common use cases, like reading a whole band.
     784             :  * It infers the GDAL data type of the buffer from the C/C++ type of the buffer.
     785             :  * This template is instantiated for the following types: [u?]int[8|16|32|64]_t,
     786             :  * float, double, std::complex<float|double>.
     787             :  *
     788             :  * To read a whole band (assuming it fits into memory), as a vector of double:
     789             :  *
     790             : \code
     791             :  std::vector<double> myArray;
     792             :  if (poBand->ReadRaster(myArray) == CE_None)
     793             :  {
     794             :      // do something
     795             :  }
     796             : \endcode
     797             :  *
     798             :  * To read 128x128 pixels starting at (col=12, line=24) as a vector of double:
     799             :  *
     800             : \code{.cpp}
     801             :  std::vector<double> myArray;
     802             :  if (poBand->ReadRaster(myArray, 12, 24, 128, 128) == CE_None)
     803             :  {
     804             :      // do something
     805             :  }
     806             : \endcode
     807             :  *
     808             :  * As nearly all GDAL methods, this method is *NOT* thread-safe, that is it cannot
     809             :  * be called on the same GDALRasterBand instance (or another GDALRasterBand
     810             :  * instance of this dataset) concurrently from several threads.
     811             :  *
     812             :  * The window of interest expressed by (dfXOff, dfYOff, dfXSize, dfYSize) should be
     813             :  * fully within the raster space, that is dfXOff >= 0, dfYOff >= 0,
     814             :  * dfXOff + dfXSize <= GetXSize() and dfYOff + dfYSize <= GetYSize().
     815             :  * If reads larger than the raster space are wished, GDALTranslate() might be used.
     816             :  * Or use nLineSpace and a possibly shifted pData value.
     817             :  *
     818             :  * @param[out] vData The vector into which the data should be written.
     819             :  * The vector will be resized, if needed, to contain at least nBufXSize *
     820             :  * nBufYSize values. The values in the vector are organized in left to right,
     821             :  * top to bottom pixel order, and fully packed.
     822             :  * The type of the vector does not need to be the one of GetDataType(). The
     823             :  * method will perform data type translation (with potential rounding, clamping)
     824             :  * if needed.
     825             :  *
     826             :  * @param dfXOff The pixel offset to the top left corner of the region
     827             :  * of the band to be accessed. This would be zero to start from the left side.
     828             :  * Defaults to 0.
     829             :  *
     830             :  * @param dfYOff The line offset to the top left corner of the region
     831             :  * of the band to be accessed. This would be zero to start from the top.
     832             :  * Defaults to 0.
     833             :  *
     834             :  * @param dfXSize The width of the region of the band to be accessed in pixels.
     835             :  * If all of dfXOff, dfYOff, dfXSize and dfYSize are left to their zero default value,
     836             :  * dfXSize is set to the band width.
     837             :  *
     838             :  * @param dfYSize The height of the region of the band to be accessed in lines.
     839             :  * If all of dfXOff, dfYOff, dfXSize and dfYSize are left to their zero default value,
     840             :  * dfYSize is set to the band height.
     841             :  *
     842             :  * @param nBufXSize the width of the buffer image into which the desired region
     843             :  * is to be read. If set to zero, and both dfXSize and dfYSize are integer values,
     844             :  * then nBufXSize is initialized with dfXSize.
     845             :  *
     846             :  * @param nBufYSize the height of the buffer image into which the desired region
     847             :  * is to be read. If set to zero, and both dfXSize and dfYSize are integer values,
     848             :  * then nBufYSize is initialized with dfYSize.
     849             :  *
     850             :  * @param eResampleAlg Resampling algorithm. Defaults to GRIORA_NearestNeighbour.
     851             :  *
     852             :  * @param pfnProgress Progress function. May be nullptr.
     853             :  *
     854             :  * @param pProgressData User data of pfnProgress. May be nullptr.
     855             :  *
     856             :  * @return CE_Failure if the access fails, otherwise CE_None.
     857             :  *
     858             :  * @see GDALRasterBand::RasterIO()
     859             :  * @since GDAL 3.10
     860             :  */
     861             : template <class T>
     862          21 : CPLErr GDALRasterBand::ReadRaster(std::vector<T> &vData, double dfXOff,
     863             :                                   double dfYOff, double dfXSize, double dfYSize,
     864             :                                   size_t nBufXSize, size_t nBufYSize,
     865             :                                   GDALRIOResampleAlg eResampleAlg,
     866             :                                   GDALProgressFunc pfnProgress,
     867             :                                   void *pProgressData) const
     868             : {
     869          21 :     if (((nBufXSize | nBufYSize) >> 31) != 0)
     870             :     {
     871           2 :         return CE_Failure;
     872             :     }
     873             : 
     874          19 :     if (dfXOff == 0 && dfYOff == 0 && dfXSize == 0 && dfYSize == 0)
     875             :     {
     876          12 :         dfXSize = nRasterXSize;
     877          12 :         dfYSize = nRasterYSize;
     878             :     }
     879           7 :     else if (!(dfXOff >= 0 && dfXOff <= INT_MAX) ||
     880           7 :              !(dfYOff >= 0 && dfYOff <= INT_MAX) || !(dfXSize >= 0) ||
     881           7 :              !(dfYSize >= 0) || dfXOff + dfXSize > INT_MAX ||
     882           7 :              dfYOff + dfYSize > INT_MAX)
     883             :     {
     884           0 :         return CE_Failure;
     885             :     }
     886             : 
     887             :     GDALRasterIOExtraArg sExtraArg;
     888          19 :     sExtraArg.nVersion = 1;
     889          19 :     sExtraArg.eResampleAlg = eResampleAlg;
     890          19 :     sExtraArg.pfnProgress = pfnProgress;
     891          19 :     sExtraArg.pProgressData = pProgressData;
     892          19 :     sExtraArg.bFloatingPointWindowValidity = true;
     893          19 :     sExtraArg.dfXOff = dfXOff;
     894          19 :     sExtraArg.dfYOff = dfYOff;
     895          19 :     sExtraArg.dfXSize = dfXSize;
     896          19 :     sExtraArg.dfYSize = dfYSize;
     897          19 :     const int nXOff = static_cast<int>(dfXOff);
     898          19 :     const int nYOff = static_cast<int>(dfYOff);
     899          19 :     const int nXSize = std::max(1, static_cast<int>(dfXSize + 0.5));
     900          19 :     const int nYSize = std::max(1, static_cast<int>(dfYSize + 0.5));
     901          19 :     if (nBufXSize == 0 && nBufYSize == 0)
     902             :     {
     903          15 :         if (static_cast<int>(dfXSize) == dfXSize &&
     904          14 :             static_cast<int>(dfYSize) == dfYSize)
     905             :         {
     906          14 :             nBufXSize = static_cast<int>(dfXSize);
     907          14 :             nBufYSize = static_cast<int>(dfYSize);
     908             :         }
     909             :         else
     910             :         {
     911           1 :             CPLError(CE_Failure, CPLE_AppDefined,
     912             :                      "nBufXSize and nBufYSize must be provided if "
     913             :                      "dfXSize or dfYSize is not an integer value");
     914           1 :             return CE_Failure;
     915             :         }
     916             :     }
     917          18 :     if (nBufXSize == 0 || nBufYSize == 0)
     918             :     {
     919           0 :         CPLDebug("GDAL",
     920             :                  "RasterIO() skipped for odd window or buffer size.\n"
     921             :                  "  Window = (%d,%d)x%dx%d\n"
     922             :                  "  Buffer = %dx%d\n",
     923             :                  nXOff, nYOff, nXSize, nYSize, static_cast<int>(nBufXSize),
     924             :                  static_cast<int>(nBufYSize));
     925             : 
     926           0 :         return CE_None;
     927             :     }
     928             : 
     929             :     if constexpr (SIZEOF_VOIDP < 8)
     930             :     {
     931             :         if (nBufXSize > std::numeric_limits<size_t>::max() / nBufYSize)
     932             :         {
     933             :             CPLError(CE_Failure, CPLE_OutOfMemory, "Too large buffer");
     934             :             return CE_Failure;
     935             :         }
     936             :     }
     937             : 
     938          18 :     if (vData.size() < nBufXSize * nBufYSize)
     939             :     {
     940             :         try
     941             :         {
     942          16 :             vData.resize(nBufXSize * nBufYSize);
     943             :         }
     944           1 :         catch (const std::exception &)
     945             :         {
     946           1 :             CPLError(CE_Failure, CPLE_OutOfMemory, "Cannot resize array");
     947           1 :             return CE_Failure;
     948             :         }
     949             :     }
     950             : 
     951          17 :     constexpr GSpacing nPixelSpace = sizeof(T);
     952          17 :     const GSpacing nLineSpace = nPixelSpace * nBufXSize;
     953          17 :     constexpr GDALDataType eBufType = GetGDTFromCppType<T>::GDT;
     954             : 
     955          17 :     GDALRasterBand *pThis = const_cast<GDALRasterBand *>(this);
     956             : 
     957             :     const bool bCallLeaveReadWrite =
     958          17 :         CPL_TO_BOOL(pThis->EnterReadWrite(GF_Read));
     959             : 
     960             :     CPLErr eErr;
     961             :     // coverity[identical_branches]
     962          17 :     if (bForceCachedIO)
     963           0 :         eErr = pThis->GDALRasterBand::IRasterIO(
     964             :             GF_Read, nXOff, nYOff, nXSize, nYSize, vData.data(),
     965             :             static_cast<int>(nBufXSize), static_cast<int>(nBufYSize), eBufType,
     966             :             nPixelSpace, nLineSpace, &sExtraArg);
     967             :     else
     968          17 :         eErr = pThis->IRasterIO(GF_Read, nXOff, nYOff, nXSize, nYSize,
     969             :                                 vData.data(), static_cast<int>(nBufXSize),
     970             :                                 static_cast<int>(nBufYSize), eBufType,
     971             :                                 nPixelSpace, nLineSpace, &sExtraArg);
     972             : 
     973          17 :     if (bCallLeaveReadWrite)
     974           0 :         pThis->LeaveReadWrite();
     975             : 
     976          17 :     return eErr;
     977             : }
     978             : 
     979             : //! @cond Doxygen_Suppress
     980             : 
     981             : #define INSTANTIATE_READ_RASTER_VECTOR(T)                                      \
     982             :     template CPLErr CPL_DLL GDALRasterBand::ReadRaster(                        \
     983             :         std::vector<T> &vData, double dfXOff, double dfYOff, double dfXSize,   \
     984             :         double dfYSize, size_t nBufXSize, size_t nBufYSize,                    \
     985             :         GDALRIOResampleAlg eResampleAlg, GDALProgressFunc pfnProgress,         \
     986             :         void *pProgressData) const;
     987             : 
     988             : INSTANTIATE_READ_RASTER_VECTOR(uint8_t)
     989             : INSTANTIATE_READ_RASTER_VECTOR(int8_t)
     990             : INSTANTIATE_READ_RASTER_VECTOR(uint16_t)
     991             : INSTANTIATE_READ_RASTER_VECTOR(int16_t)
     992             : INSTANTIATE_READ_RASTER_VECTOR(uint32_t)
     993             : INSTANTIATE_READ_RASTER_VECTOR(int32_t)
     994             : INSTANTIATE_READ_RASTER_VECTOR(uint64_t)
     995             : INSTANTIATE_READ_RASTER_VECTOR(int64_t)
     996             : INSTANTIATE_READ_RASTER_VECTOR(float)
     997             : INSTANTIATE_READ_RASTER_VECTOR(double)
     998             : // Not allowed by C++ standard
     999             : // INSTANTIATE_READ_RASTER_VECTOR(std::complex<int16_t>)
    1000             : // INSTANTIATE_READ_RASTER_VECTOR(std::complex<int32_t>)
    1001             : INSTANTIATE_READ_RASTER_VECTOR(std::complex<float>)
    1002             : INSTANTIATE_READ_RASTER_VECTOR(std::complex<double>)
    1003             : 
    1004             : //! @endcond
    1005             : 
    1006             : /************************************************************************/
    1007             : /*                             ReadBlock()                              */
    1008             : /************************************************************************/
    1009             : 
    1010             : /**
    1011             :  * \brief Read a block of image data efficiently.
    1012             :  *
    1013             :  * This method accesses a "natural" block from the raster band without
    1014             :  * resampling, or data type conversion.  For a more generalized, but
    1015             :  * potentially less efficient access use RasterIO().
    1016             :  *
    1017             :  * This method is the same as the C GDALReadBlock() function.
    1018             :  *
    1019             :  * See the GetLockedBlockRef() method for a way of accessing internally cached
    1020             :  * block oriented data without an extra copy into an application buffer.
    1021             :  *
    1022             :  * The following code would efficiently compute a histogram of eight bit
    1023             :  * raster data.  Note that the final block may be partial ... data beyond
    1024             :  * the edge of the underlying raster band in these edge blocks is of an
    1025             :  * undetermined value.
    1026             :  *
    1027             : \code{.cpp}
    1028             :  CPLErr GetHistogram( GDALRasterBand *poBand, GUIntBig *panHistogram )
    1029             : 
    1030             :  {
    1031             :      memset( panHistogram, 0, sizeof(GUIntBig) * 256 );
    1032             : 
    1033             :      CPLAssert( poBand->GetRasterDataType() == GDT_Byte );
    1034             : 
    1035             :      int nXBlockSize, nYBlockSize;
    1036             : 
    1037             :      poBand->GetBlockSize( &nXBlockSize, &nYBlockSize );
    1038             :      int nXBlocks = (poBand->GetXSize() + nXBlockSize - 1) / nXBlockSize;
    1039             :      int nYBlocks = (poBand->GetYSize() + nYBlockSize - 1) / nYBlockSize;
    1040             : 
    1041             :      GByte *pabyData = (GByte *) CPLMalloc(nXBlockSize * nYBlockSize);
    1042             : 
    1043             :      for( int iYBlock = 0; iYBlock < nYBlocks; iYBlock++ )
    1044             :      {
    1045             :          for( int iXBlock = 0; iXBlock < nXBlocks; iXBlock++ )
    1046             :          {
    1047             :              int        nXValid, nYValid;
    1048             : 
    1049             :              poBand->ReadBlock( iXBlock, iYBlock, pabyData );
    1050             : 
    1051             :              // Compute the portion of the block that is valid
    1052             :              // for partial edge blocks.
    1053             :              poBand->GetActualBlockSize(iXBlock, iYBlock, &nXValid, &nYValid)
    1054             : 
    1055             :              // Collect the histogram counts.
    1056             :              for( int iY = 0; iY < nYValid; iY++ )
    1057             :              {
    1058             :                  for( int iX = 0; iX < nXValid; iX++ )
    1059             :                  {
    1060             :                      panHistogram[pabyData[iX + iY * nXBlockSize]] += 1;
    1061             :                  }
    1062             :              }
    1063             :          }
    1064             :      }
    1065             :  }
    1066             : \endcode
    1067             :  *
    1068             :  * @param nXBlockOff the horizontal block offset, with zero indicating
    1069             :  * the left most block, 1 the next block and so forth.
    1070             :  *
    1071             :  * @param nYBlockOff the vertical block offset, with zero indicating
    1072             :  * the top most block, 1 the next block and so forth.
    1073             :  *
    1074             :  * @param pImage the buffer into which the data will be read.  The buffer
    1075             :  * must be large enough to hold GetBlockXSize()*GetBlockYSize() words
    1076             :  * of type GetRasterDataType().
    1077             :  *
    1078             :  * @return CE_None on success or CE_Failure on an error.
    1079             :  */
    1080             : 
    1081         644 : CPLErr GDALRasterBand::ReadBlock(int nXBlockOff, int nYBlockOff, void *pImage)
    1082             : 
    1083             : {
    1084             :     /* -------------------------------------------------------------------- */
    1085             :     /*      Validate arguments.                                             */
    1086             :     /* -------------------------------------------------------------------- */
    1087         644 :     CPLAssert(pImage != nullptr);
    1088             : 
    1089         644 :     if (!InitBlockInfo())
    1090           0 :         return CE_Failure;
    1091             : 
    1092         644 :     if (nXBlockOff < 0 || nXBlockOff >= nBlocksPerRow)
    1093             :     {
    1094           0 :         ReportError(CE_Failure, CPLE_IllegalArg,
    1095             :                     "Illegal nXBlockOff value (%d) in "
    1096             :                     "GDALRasterBand::ReadBlock()\n",
    1097             :                     nXBlockOff);
    1098             : 
    1099           0 :         return (CE_Failure);
    1100             :     }
    1101             : 
    1102         644 :     if (nYBlockOff < 0 || nYBlockOff >= nBlocksPerColumn)
    1103             :     {
    1104           0 :         ReportError(CE_Failure, CPLE_IllegalArg,
    1105             :                     "Illegal nYBlockOff value (%d) in "
    1106             :                     "GDALRasterBand::ReadBlock()\n",
    1107             :                     nYBlockOff);
    1108             : 
    1109           0 :         return (CE_Failure);
    1110             :     }
    1111             : 
    1112             :     /* -------------------------------------------------------------------- */
    1113             :     /*      Invoke underlying implementation method.                        */
    1114             :     /* -------------------------------------------------------------------- */
    1115             : 
    1116         644 :     int bCallLeaveReadWrite = EnterReadWrite(GF_Read);
    1117         644 :     CPLErr eErr = IReadBlock(nXBlockOff, nYBlockOff, pImage);
    1118         644 :     if (bCallLeaveReadWrite)
    1119           4 :         LeaveReadWrite();
    1120         644 :     return eErr;
    1121             : }
    1122             : 
    1123             : /************************************************************************/
    1124             : /*                           GDALReadBlock()                            */
    1125             : /************************************************************************/
    1126             : 
    1127             : /**
    1128             :  * \brief Read a block of image data efficiently.
    1129             :  *
    1130             :  * @see GDALRasterBand::ReadBlock()
    1131             :  */
    1132             : 
    1133          67 : CPLErr CPL_STDCALL GDALReadBlock(GDALRasterBandH hBand, int nXOff, int nYOff,
    1134             :                                  void *pData)
    1135             : 
    1136             : {
    1137          67 :     VALIDATE_POINTER1(hBand, "GDALReadBlock", CE_Failure);
    1138             : 
    1139          67 :     GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
    1140          67 :     return (poBand->ReadBlock(nXOff, nYOff, pData));
    1141             : }
    1142             : 
    1143             : /************************************************************************/
    1144             : /*                            IReadBlock()                             */
    1145             : /************************************************************************/
    1146             : 
    1147             : /** \fn GDALRasterBand::IReadBlock( int nBlockXOff, int nBlockYOff, void *pData
    1148             :  * ) \brief Read a block of data.
    1149             :  *
    1150             :  * Default internal implementation ... to be overridden by
    1151             :  * subclasses that support reading.
    1152             :  * @param nBlockXOff Block X Offset
    1153             :  * @param nBlockYOff Block Y Offset
    1154             :  * @param pData Pixel buffer into which to place read data.
    1155             :  * @return CE_None on success or CE_Failure on an error.
    1156             :  */
    1157             : 
    1158             : /************************************************************************/
    1159             : /*                            IWriteBlock()                             */
    1160             : /************************************************************************/
    1161             : 
    1162             : /**
    1163             :  * \fn GDALRasterBand::IWriteBlock(int, int, void*)
    1164             :  * Write a block of data.
    1165             :  *
    1166             :  * Default internal implementation ... to be overridden by
    1167             :  * subclasses that support writing.
    1168             :  * @param nBlockXOff Block X Offset
    1169             :  * @param nBlockYOff Block Y Offset
    1170             :  * @param pData Pixel buffer to write
    1171             :  * @return CE_None on success or CE_Failure on an error.
    1172             :  */
    1173             : 
    1174             : /**/
    1175             : /**/
    1176             : 
    1177           0 : CPLErr GDALRasterBand::IWriteBlock(int /*nBlockXOff*/, int /*nBlockYOff*/,
    1178             :                                    void * /*pData*/)
    1179             : 
    1180             : {
    1181           0 :     if (!(GetMOFlags() & GMO_IGNORE_UNIMPLEMENTED))
    1182           0 :         ReportError(CE_Failure, CPLE_NotSupported,
    1183             :                     "WriteBlock() not supported for this dataset.");
    1184             : 
    1185           0 :     return (CE_Failure);
    1186             : }
    1187             : 
    1188             : /************************************************************************/
    1189             : /*                             WriteBlock()                             */
    1190             : /************************************************************************/
    1191             : 
    1192             : /**
    1193             :  * \brief Write a block of image data efficiently.
    1194             :  *
    1195             :  * This method accesses a "natural" block from the raster band without
    1196             :  * resampling, or data type conversion.  For a more generalized, but
    1197             :  * potentially less efficient access use RasterIO().
    1198             :  *
    1199             :  * This method is the same as the C GDALWriteBlock() function.
    1200             :  *
    1201             :  * See ReadBlock() for an example of block oriented data access.
    1202             :  *
    1203             :  * @param nXBlockOff the horizontal block offset, with zero indicating
    1204             :  * the left most block, 1 the next block and so forth.
    1205             :  *
    1206             :  * @param nYBlockOff the vertical block offset, with zero indicating
    1207             :  * the left most block, 1 the next block and so forth.
    1208             :  *
    1209             :  * @param pImage the buffer from which the data will be written.  The buffer
    1210             :  * must be large enough to hold GetBlockXSize()*GetBlockYSize() words
    1211             :  * of type GetRasterDataType(). Note that the content of the buffer might be
    1212             :  * temporarily modified during the execution of this method (and eventually
    1213             :  * restored back to its original content), so it is not safe to use a buffer
    1214             :  * stored in a read-only section of the calling program.
    1215             :  *
    1216             :  * @return CE_None on success or CE_Failure on an error.
    1217             :  */
    1218             : 
    1219        4807 : CPLErr GDALRasterBand::WriteBlock(int nXBlockOff, int nYBlockOff, void *pImage)
    1220             : 
    1221             : {
    1222             :     /* -------------------------------------------------------------------- */
    1223             :     /*      Validate arguments.                                             */
    1224             :     /* -------------------------------------------------------------------- */
    1225        4807 :     CPLAssert(pImage != nullptr);
    1226             : 
    1227        4807 :     if (!InitBlockInfo())
    1228           0 :         return CE_Failure;
    1229             : 
    1230        4807 :     if (nXBlockOff < 0 || nXBlockOff >= nBlocksPerRow)
    1231             :     {
    1232           0 :         ReportError(CE_Failure, CPLE_IllegalArg,
    1233             :                     "Illegal nXBlockOff value (%d) in "
    1234             :                     "GDALRasterBand::WriteBlock()\n",
    1235             :                     nXBlockOff);
    1236             : 
    1237           0 :         return (CE_Failure);
    1238             :     }
    1239             : 
    1240        4807 :     if (nYBlockOff < 0 || nYBlockOff >= nBlocksPerColumn)
    1241             :     {
    1242           0 :         ReportError(CE_Failure, CPLE_IllegalArg,
    1243             :                     "Illegal nYBlockOff value (%d) in "
    1244             :                     "GDALRasterBand::WriteBlock()\n",
    1245             :                     nYBlockOff);
    1246             : 
    1247           0 :         return (CE_Failure);
    1248             :     }
    1249             : 
    1250        4807 :     if (eAccess == GA_ReadOnly)
    1251             :     {
    1252           0 :         ReportError(CE_Failure, CPLE_NoWriteAccess,
    1253             :                     "Attempt to write to read only dataset in"
    1254             :                     "GDALRasterBand::WriteBlock().\n");
    1255             : 
    1256           0 :         return (CE_Failure);
    1257             :     }
    1258             : 
    1259        4807 :     if (eFlushBlockErr != CE_None)
    1260             :     {
    1261           0 :         ReportError(eFlushBlockErr, CPLE_AppDefined,
    1262             :                     "An error occurred while writing a dirty block "
    1263             :                     "from GDALRasterBand::WriteBlock");
    1264           0 :         CPLErr eErr = eFlushBlockErr;
    1265           0 :         eFlushBlockErr = CE_None;
    1266           0 :         return eErr;
    1267             :     }
    1268             : 
    1269             :     /* -------------------------------------------------------------------- */
    1270             :     /*      Invoke underlying implementation method.                        */
    1271             :     /* -------------------------------------------------------------------- */
    1272             : 
    1273        4807 :     const bool bCallLeaveReadWrite = CPL_TO_BOOL(EnterReadWrite(GF_Write));
    1274        4807 :     CPLErr eErr = IWriteBlock(nXBlockOff, nYBlockOff, pImage);
    1275        4807 :     if (bCallLeaveReadWrite)
    1276        4807 :         LeaveReadWrite();
    1277             : 
    1278        4807 :     return eErr;
    1279             : }
    1280             : 
    1281             : /************************************************************************/
    1282             : /*                           GDALWriteBlock()                           */
    1283             : /************************************************************************/
    1284             : 
    1285             : /**
    1286             :  * \brief Write a block of image data efficiently.
    1287             :  *
    1288             :  * @see GDALRasterBand::WriteBlock()
    1289             :  */
    1290             : 
    1291           0 : CPLErr CPL_STDCALL GDALWriteBlock(GDALRasterBandH hBand, int nXOff, int nYOff,
    1292             :                                   void *pData)
    1293             : 
    1294             : {
    1295           0 :     VALIDATE_POINTER1(hBand, "GDALWriteBlock", CE_Failure);
    1296             : 
    1297           0 :     GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
    1298           0 :     return (poBand->WriteBlock(nXOff, nYOff, pData));
    1299             : }
    1300             : 
    1301             : /************************************************************************/
    1302             : /*                         GetActualBlockSize()                         */
    1303             : /************************************************************************/
    1304             : /**
    1305             :  * \brief Fetch the actual block size for a given block offset.
    1306             :  *
    1307             :  * Handles partial blocks at the edges of the raster and returns the true
    1308             :  * number of pixels
    1309             :  *
    1310             :  * @param nXBlockOff the horizontal block offset for which to calculate the
    1311             :  * number of valid pixels, with zero indicating the left most block, 1 the next
    1312             :  * block and so forth.
    1313             :  *
    1314             :  * @param nYBlockOff the vertical block offset, with zero indicating
    1315             :  * the top most block, 1 the next block and so forth.
    1316             :  *
    1317             :  * @param pnXValid pointer to an integer in which the number of valid pixels in
    1318             :  * the x direction will be stored
    1319             :  *
    1320             :  * @param pnYValid pointer to an integer in which the number of valid pixels in
    1321             :  * the y direction will be stored
    1322             :  *
    1323             :  * @return CE_None if the input parameters are valid, CE_Failure otherwise
    1324             :  *
    1325             :  * @since GDAL 2.2
    1326             :  */
    1327       47863 : CPLErr GDALRasterBand::GetActualBlockSize(int nXBlockOff, int nYBlockOff,
    1328             :                                           int *pnXValid, int *pnYValid) const
    1329             : {
    1330       95723 :     if (nXBlockOff < 0 || nBlockXSize == 0 ||
    1331       95711 :         nXBlockOff >= DIV_ROUND_UP(nRasterXSize, nBlockXSize) ||
    1332       95705 :         nYBlockOff < 0 || nBlockYSize == 0 ||
    1333       47854 :         nYBlockOff >= DIV_ROUND_UP(nRasterYSize, nBlockYSize))
    1334             :     {
    1335          10 :         return CE_Failure;
    1336             :     }
    1337             : 
    1338       47853 :     const int nXPixelOff = nXBlockOff * nBlockXSize;
    1339       47853 :     const int nYPixelOff = nYBlockOff * nBlockYSize;
    1340             : 
    1341       47853 :     *pnXValid = nBlockXSize;
    1342       47853 :     *pnYValid = nBlockYSize;
    1343             : 
    1344       47853 :     if (nXPixelOff >= nRasterXSize - nBlockXSize)
    1345             :     {
    1346       46245 :         *pnXValid = nRasterXSize - nXPixelOff;
    1347             :     }
    1348             : 
    1349       47853 :     if (nYPixelOff >= nRasterYSize - nBlockYSize)
    1350             :     {
    1351        3392 :         *pnYValid = nRasterYSize - nYPixelOff;
    1352             :     }
    1353             : 
    1354       47853 :     return CE_None;
    1355             : }
    1356             : 
    1357             : /************************************************************************/
    1358             : /*                           GDALGetActualBlockSize()                   */
    1359             : /************************************************************************/
    1360             : 
    1361             : /**
    1362             :  * \brief Retrieve the actual block size for a given block offset.
    1363             :  *
    1364             :  * @see GDALRasterBand::GetActualBlockSize()
    1365             :  */
    1366             : 
    1367           6 : CPLErr CPL_STDCALL GDALGetActualBlockSize(GDALRasterBandH hBand, int nXBlockOff,
    1368             :                                           int nYBlockOff, int *pnXValid,
    1369             :                                           int *pnYValid)
    1370             : 
    1371             : {
    1372           6 :     VALIDATE_POINTER1(hBand, "GDALGetActualBlockSize", CE_Failure);
    1373             : 
    1374           6 :     GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
    1375             :     return (
    1376           6 :         poBand->GetActualBlockSize(nXBlockOff, nYBlockOff, pnXValid, pnYValid));
    1377             : }
    1378             : 
    1379             : /************************************************************************/
    1380             : /*                     GetSuggestedBlockAccessPattern()                 */
    1381             : /************************************************************************/
    1382             : 
    1383             : /**
    1384             :  * \brief Return the suggested/most efficient access pattern to blocks
    1385             :  *        (for read operations).
    1386             :  *
    1387             :  * While all GDAL drivers have to expose a block size, not all can guarantee
    1388             :  * efficient random access (GSBAP_RANDOM) to any block.
    1389             :  * Some drivers for example decompress sequentially a compressed stream from
    1390             :  * top raster to bottom (GSBAP_TOP_TO_BOTTOM), in which
    1391             :  * case best performance will be achieved while reading blocks in that order.
    1392             :  * (accessing blocks in random access in such rasters typically causes the
    1393             :  * decoding to be re-initialized from the start if accessing blocks in
    1394             :  * a non-sequential order)
    1395             :  *
    1396             :  * The base implementation returns GSBAP_UNKNOWN, which can also be explicitly
    1397             :  * returned by drivers that expose a somewhat artificial block size, because
    1398             :  * they can extract any part of a raster, but in a rather inefficient way.
    1399             :  *
    1400             :  * The GSBAP_LARGEST_CHUNK_POSSIBLE value can be combined as a logical bitmask
    1401             :  * with other enumeration values (GSBAP_UNKNOWN, GSBAP_RANDOM,
    1402             :  * GSBAP_TOP_TO_BOTTOM, GSBAP_BOTTOM_TO_TOP). When a driver sets this flag, the
    1403             :  * most efficient strategy is to read as many pixels as possible in the less
    1404             :  * RasterIO() operations.
    1405             :  *
    1406             :  * The return of this method is for example used to determine the swath size
    1407             :  * used by GDALDatasetCopyWholeRaster() and GDALRasterBandCopyWholeRaster().
    1408             :  *
    1409             :  * @since GDAL 3.6
    1410             :  */
    1411             : 
    1412             : GDALSuggestedBlockAccessPattern
    1413        2118 : GDALRasterBand::GetSuggestedBlockAccessPattern() const
    1414             : {
    1415        2118 :     return GSBAP_UNKNOWN;
    1416             : }
    1417             : 
    1418             : /************************************************************************/
    1419             : /*                         GetRasterDataType()                          */
    1420             : /************************************************************************/
    1421             : 
    1422             : /**
    1423             :  * \brief Fetch the pixel data type for this band.
    1424             :  *
    1425             :  * This method is the same as the C function GDALGetRasterDataType().
    1426             :  *
    1427             :  * @return the data type of pixels for this band.
    1428             :  */
    1429             : 
    1430     7551750 : GDALDataType GDALRasterBand::GetRasterDataType() const
    1431             : 
    1432             : {
    1433     7551750 :     return eDataType;
    1434             : }
    1435             : 
    1436             : /************************************************************************/
    1437             : /*                       GDALGetRasterDataType()                        */
    1438             : /************************************************************************/
    1439             : 
    1440             : /**
    1441             :  * \brief Fetch the pixel data type for this band.
    1442             :  *
    1443             :  * @see GDALRasterBand::GetRasterDataType()
    1444             :  */
    1445             : 
    1446      896181 : GDALDataType CPL_STDCALL GDALGetRasterDataType(GDALRasterBandH hBand)
    1447             : 
    1448             : {
    1449      896181 :     VALIDATE_POINTER1(hBand, "GDALGetRasterDataType", GDT_Unknown);
    1450             : 
    1451      896181 :     GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
    1452      896181 :     return poBand->GetRasterDataType();
    1453             : }
    1454             : 
    1455             : /************************************************************************/
    1456             : /*                            GetBlockSize()                            */
    1457             : /************************************************************************/
    1458             : 
    1459             : /**
    1460             :  * \brief Fetch the "natural" block size of this band.
    1461             :  *
    1462             :  * GDAL contains a concept of the natural block size of rasters so that
    1463             :  * applications can organized data access efficiently for some file formats.
    1464             :  * The natural block size is the block size that is most efficient for
    1465             :  * accessing the format.  For many formats this is simple a whole scanline
    1466             :  * in which case *pnXSize is set to GetXSize(), and *pnYSize is set to 1.
    1467             :  *
    1468             :  * However, for tiled images this will typically be the tile size.
    1469             :  *
    1470             :  * Note that the X and Y block sizes don't have to divide the image size
    1471             :  * evenly, meaning that right and bottom edge blocks may be incomplete.
    1472             :  * See ReadBlock() for an example of code dealing with these issues.
    1473             :  *
    1474             :  * This method is the same as the C function GDALGetBlockSize().
    1475             :  *
    1476             :  * @param pnXSize integer to put the X block size into or NULL.
    1477             :  *
    1478             :  * @param pnYSize integer to put the Y block size into or NULL.
    1479             :  */
    1480             : 
    1481     4962530 : void GDALRasterBand::GetBlockSize(int *pnXSize, int *pnYSize) const
    1482             : 
    1483             : {
    1484     4962530 :     if (nBlockXSize <= 0 || nBlockYSize <= 0)
    1485             :     {
    1486         728 :         ReportError(CE_Failure, CPLE_AppDefined,
    1487         728 :                     "Invalid block dimension : %d * %d", nBlockXSize,
    1488         728 :                     nBlockYSize);
    1489           0 :         if (pnXSize != nullptr)
    1490           0 :             *pnXSize = 0;
    1491           0 :         if (pnYSize != nullptr)
    1492           0 :             *pnYSize = 0;
    1493             :     }
    1494             :     else
    1495             :     {
    1496     4961800 :         if (pnXSize != nullptr)
    1497     4962610 :             *pnXSize = nBlockXSize;
    1498     4961800 :         if (pnYSize != nullptr)
    1499     4961340 :             *pnYSize = nBlockYSize;
    1500             :     }
    1501     4961800 : }
    1502             : 
    1503             : /************************************************************************/
    1504             : /*                          GDALGetBlockSize()                          */
    1505             : /************************************************************************/
    1506             : 
    1507             : /**
    1508             :  * \brief Fetch the "natural" block size of this band.
    1509             :  *
    1510             :  * @see GDALRasterBand::GetBlockSize()
    1511             :  */
    1512             : 
    1513       39010 : void CPL_STDCALL GDALGetBlockSize(GDALRasterBandH hBand, int *pnXSize,
    1514             :                                   int *pnYSize)
    1515             : 
    1516             : {
    1517       39010 :     VALIDATE_POINTER0(hBand, "GDALGetBlockSize");
    1518             : 
    1519       39010 :     GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
    1520       39010 :     poBand->GetBlockSize(pnXSize, pnYSize);
    1521             : }
    1522             : 
    1523             : /************************************************************************/
    1524             : /*                           InitBlockInfo()                            */
    1525             : /************************************************************************/
    1526             : 
    1527             : //! @cond Doxygen_Suppress
    1528     3305770 : int GDALRasterBand::InitBlockInfo()
    1529             : 
    1530             : {
    1531     3305770 :     if (poBandBlockCache != nullptr)
    1532     3272750 :         return poBandBlockCache->IsInitOK();
    1533             : 
    1534             :     /* Do some validation of raster and block dimensions in case the driver */
    1535             :     /* would have neglected to do it itself */
    1536       33019 :     if (nBlockXSize <= 0 || nBlockYSize <= 0)
    1537             :     {
    1538           0 :         ReportError(CE_Failure, CPLE_AppDefined,
    1539             :                     "Invalid block dimension : %d * %d", nBlockXSize,
    1540             :                     nBlockYSize);
    1541           0 :         return FALSE;
    1542             :     }
    1543             : 
    1544       33022 :     if (nRasterXSize <= 0 || nRasterYSize <= 0)
    1545             :     {
    1546           0 :         ReportError(CE_Failure, CPLE_AppDefined,
    1547             :                     "Invalid raster dimension : %d * %d", nRasterXSize,
    1548             :                     nRasterYSize);
    1549           0 :         return FALSE;
    1550             :     }
    1551             : 
    1552       33022 :     const int nDataTypeSize = GDALGetDataTypeSizeBytes(eDataType);
    1553       33023 :     if (nDataTypeSize == 0)
    1554             :     {
    1555           0 :         ReportError(CE_Failure, CPLE_AppDefined, "Invalid data type");
    1556           0 :         return FALSE;
    1557             :     }
    1558             : 
    1559             : #if SIZEOF_VOIDP == 4
    1560             :     if (nBlockXSize >= 10000 || nBlockYSize >= 10000)
    1561             :     {
    1562             :         /* As 10000 * 10000 * 16 < INT_MAX, we don't need to do the
    1563             :          * multiplication in other cases */
    1564             :         if (nBlockXSize > INT_MAX / nDataTypeSize ||
    1565             :             nBlockYSize > INT_MAX / (nDataTypeSize * nBlockXSize))
    1566             :         {
    1567             :             ReportError(CE_Failure, CPLE_NotSupported,
    1568             :                         "Too big block : %d * %d for 32-bit build", nBlockXSize,
    1569             :                         nBlockYSize);
    1570             :             return FALSE;
    1571             :         }
    1572             :     }
    1573             : #endif
    1574             : 
    1575       33023 :     nBlocksPerRow = DIV_ROUND_UP(nRasterXSize, nBlockXSize);
    1576       33023 :     nBlocksPerColumn = DIV_ROUND_UP(nRasterYSize, nBlockYSize);
    1577             : 
    1578             :     const char *pszBlockStrategy =
    1579       33023 :         CPLGetConfigOption("GDAL_BAND_BLOCK_CACHE", nullptr);
    1580       33023 :     bool bUseArray = true;
    1581       33023 :     if (pszBlockStrategy == nullptr || EQUAL(pszBlockStrategy, "AUTO"))
    1582             :     {
    1583       32983 :         if (poDS == nullptr || (poDS->nOpenFlags & GDAL_OF_BLOCK_ACCESS_MASK) ==
    1584             :                                    GDAL_OF_DEFAULT_BLOCK_ACCESS)
    1585             :         {
    1586       32964 :             GUIntBig nBlockCount =
    1587       32964 :                 static_cast<GIntBig>(nBlocksPerRow) * nBlocksPerColumn;
    1588       32964 :             if (poDS != nullptr)
    1589       32701 :                 nBlockCount *= poDS->GetRasterCount();
    1590       32964 :             bUseArray = (nBlockCount < 1024 * 1024);
    1591             :         }
    1592          19 :         else if ((poDS->nOpenFlags & GDAL_OF_BLOCK_ACCESS_MASK) ==
    1593             :                  GDAL_OF_HASHSET_BLOCK_ACCESS)
    1594             :         {
    1595           0 :             bUseArray = false;
    1596       32983 :         }
    1597             :     }
    1598          40 :     else if (EQUAL(pszBlockStrategy, "HASHSET"))
    1599          40 :         bUseArray = false;
    1600           0 :     else if (!EQUAL(pszBlockStrategy, "ARRAY"))
    1601           0 :         CPLError(CE_Warning, CPLE_AppDefined, "Unknown block cache method: %s",
    1602             :                  pszBlockStrategy);
    1603             : 
    1604       33023 :     if (bUseArray)
    1605       32953 :         poBandBlockCache = GDALArrayBandBlockCacheCreate(this);
    1606             :     else
    1607             :     {
    1608          70 :         if (nBand == 1)
    1609          25 :             CPLDebug("GDAL", "Use hashset band block cache");
    1610          70 :         poBandBlockCache = GDALHashSetBandBlockCacheCreate(this);
    1611             :     }
    1612       33023 :     if (poBandBlockCache == nullptr)
    1613           0 :         return FALSE;
    1614       33023 :     return poBandBlockCache->Init();
    1615             : }
    1616             : 
    1617             : //! @endcond
    1618             : 
    1619             : /************************************************************************/
    1620             : /*                             FlushCache()                             */
    1621             : /************************************************************************/
    1622             : 
    1623             : /**
    1624             :  * \brief Flush raster data cache.
    1625             :  *
    1626             :  * This call will recover memory used to cache data blocks for this raster
    1627             :  * band, and ensure that new requests are referred to the underlying driver.
    1628             :  *
    1629             :  * This method is the same as the C function GDALFlushRasterCache().
    1630             :  *
    1631             :  * @param bAtClosing Whether this is called from a GDALDataset destructor
    1632             :  * @return CE_None on success.
    1633             :  */
    1634             : 
    1635     3719800 : CPLErr GDALRasterBand::FlushCache(bool bAtClosing)
    1636             : 
    1637             : {
    1638     3764260 :     if (bAtClosing && poDS && poDS->IsMarkedSuppressOnClose() &&
    1639       44455 :         poBandBlockCache)
    1640        2089 :         poBandBlockCache->DisableDirtyBlockWriting();
    1641             : 
    1642     3720770 :     CPLErr eGlobalErr = eFlushBlockErr;
    1643             : 
    1644     3720770 :     if (eFlushBlockErr != CE_None)
    1645             :     {
    1646           0 :         ReportError(
    1647             :             eFlushBlockErr, CPLE_AppDefined,
    1648             :             "An error occurred while writing a dirty block from FlushCache");
    1649           0 :         eFlushBlockErr = CE_None;
    1650             :     }
    1651             : 
    1652     3720770 :     if (poBandBlockCache == nullptr || !poBandBlockCache->IsInitOK())
    1653     3571000 :         return eGlobalErr;
    1654             : 
    1655      149770 :     return poBandBlockCache->FlushCache();
    1656             : }
    1657             : 
    1658             : /************************************************************************/
    1659             : /*                        GDALFlushRasterCache()                        */
    1660             : /************************************************************************/
    1661             : 
    1662             : /**
    1663             :  * \brief Flush raster data cache.
    1664             :  *
    1665             :  * @see GDALRasterBand::FlushCache()
    1666             :  */
    1667             : 
    1668         129 : CPLErr CPL_STDCALL GDALFlushRasterCache(GDALRasterBandH hBand)
    1669             : 
    1670             : {
    1671         129 :     VALIDATE_POINTER1(hBand, "GDALFlushRasterCache", CE_Failure);
    1672             : 
    1673         129 :     return GDALRasterBand::FromHandle(hBand)->FlushCache(false);
    1674             : }
    1675             : 
    1676             : /************************************************************************/
    1677             : /*                             DropCache()                              */
    1678             : /************************************************************************/
    1679             : 
    1680             : /**
    1681             : * \brief Drop raster data cache : data in cache will be lost.
    1682             : *
    1683             : * This call will recover memory used to cache data blocks for this raster
    1684             : * band, and ensure that new requests are referred to the underlying driver.
    1685             : *
    1686             : * This method is the same as the C function GDALDropRasterCache().
    1687             : *
    1688             : * @return CE_None on success.
    1689             : * @since 3.9
    1690             : */
    1691             : 
    1692           1 : CPLErr GDALRasterBand::DropCache()
    1693             : 
    1694             : {
    1695           1 :     CPLErr result = CE_None;
    1696             : 
    1697           1 :     if (poBandBlockCache)
    1698           1 :         poBandBlockCache->DisableDirtyBlockWriting();
    1699             : 
    1700           1 :     CPLErr eGlobalErr = eFlushBlockErr;
    1701             : 
    1702           1 :     if (eFlushBlockErr != CE_None)
    1703             :     {
    1704           0 :         ReportError(
    1705             :             eFlushBlockErr, CPLE_AppDefined,
    1706             :             "An error occurred while writing a dirty block from DropCache");
    1707           0 :         eFlushBlockErr = CE_None;
    1708             :     }
    1709             : 
    1710           1 :     if (poBandBlockCache == nullptr || !poBandBlockCache->IsInitOK())
    1711           0 :         result = eGlobalErr;
    1712             :     else
    1713           1 :         result = poBandBlockCache->FlushCache();
    1714             : 
    1715           1 :     if (poBandBlockCache)
    1716           1 :         poBandBlockCache->EnableDirtyBlockWriting();
    1717             : 
    1718           1 :     return result;
    1719             : }
    1720             : 
    1721             : /************************************************************************/
    1722             : /*                        GDALDropRasterCache()                         */
    1723             : /************************************************************************/
    1724             : 
    1725             : /**
    1726             : * \brief Drop raster data cache.
    1727             : *
    1728             : * @see GDALRasterBand::DropCache()
    1729             : * @since 3.9
    1730             : */
    1731             : 
    1732           0 : CPLErr CPL_STDCALL GDALDropRasterCache(GDALRasterBandH hBand)
    1733             : 
    1734             : {
    1735           0 :     VALIDATE_POINTER1(hBand, "GDALDropRasterCache", CE_Failure);
    1736             : 
    1737           0 :     return GDALRasterBand::FromHandle(hBand)->DropCache();
    1738             : }
    1739             : 
    1740             : /************************************************************************/
    1741             : /*                        UnreferenceBlock()                            */
    1742             : /*                                                                      */
    1743             : /*      Unreference the block from our array of blocks                  */
    1744             : /*      This method should only be called by                            */
    1745             : /*      GDALRasterBlock::Internalize() and FlushCacheBlock() (and under */
    1746             : /*      the block cache mutex)                                          */
    1747             : /************************************************************************/
    1748             : 
    1749       29590 : CPLErr GDALRasterBand::UnreferenceBlock(GDALRasterBlock *poBlock)
    1750             : {
    1751             : #ifdef notdef
    1752             :     if (poBandBlockCache == nullptr || !poBandBlockCache->IsInitOK())
    1753             :     {
    1754             :         if (poBandBlockCache == nullptr)
    1755             :             printf("poBandBlockCache == NULL\n"); /*ok*/
    1756             :         else
    1757             :             printf("!poBandBlockCache->IsInitOK()\n"); /*ok*/
    1758             :         printf("caller = %s\n", pszCaller);            /*ok*/
    1759             :         printf("GDALRasterBand: %p\n", this);          /*ok*/
    1760             :         printf("GDALRasterBand: nBand=%d\n", nBand);   /*ok*/
    1761             :         printf("nRasterXSize = %d\n", nRasterXSize);   /*ok*/
    1762             :         printf("nRasterYSize = %d\n", nRasterYSize);   /*ok*/
    1763             :         printf("nBlockXSize = %d\n", nBlockXSize);     /*ok*/
    1764             :         printf("nBlockYSize = %d\n", nBlockYSize);     /*ok*/
    1765             :         poBlock->DumpBlock();
    1766             :         if (GetDataset() != nullptr)
    1767             :             printf("Dataset: %s\n", GetDataset()->GetDescription()); /*ok*/
    1768             :         GDALRasterBlock::Verify();
    1769             :         abort();
    1770             :     }
    1771             : #endif
    1772       29590 :     CPLAssert(poBandBlockCache && poBandBlockCache->IsInitOK());
    1773       29590 :     return poBandBlockCache->UnreferenceBlock(poBlock);
    1774             : }
    1775             : 
    1776             : /************************************************************************/
    1777             : /*                        AddBlockToFreeList()                          */
    1778             : /*                                                                      */
    1779             : /*      When GDALRasterBlock::Internalize() or FlushCacheBlock() are    */
    1780             : /*      finished with a block about to be free'd, they pass it to that  */
    1781             : /*      method.                                                         */
    1782             : /************************************************************************/
    1783             : 
    1784             : //! @cond Doxygen_Suppress
    1785       29590 : void GDALRasterBand::AddBlockToFreeList(GDALRasterBlock *poBlock)
    1786             : {
    1787       29590 :     CPLAssert(poBandBlockCache && poBandBlockCache->IsInitOK());
    1788       29590 :     return poBandBlockCache->AddBlockToFreeList(poBlock);
    1789             : }
    1790             : 
    1791             : //! @endcond
    1792             : 
    1793             : /************************************************************************/
    1794             : /*                             FlushBlock()                             */
    1795             : /************************************************************************/
    1796             : 
    1797             : /** Flush a block out of the block cache.
    1798             :  * @param nXBlockOff block x offset
    1799             :  * @param nYBlockOff blocky offset
    1800             :  * @param bWriteDirtyBlock whether the block should be written to disk if dirty.
    1801             :  * @return CE_None in case of success, an error code otherwise.
    1802             :  */
    1803        2298 : CPLErr GDALRasterBand::FlushBlock(int nXBlockOff, int nYBlockOff,
    1804             :                                   int bWriteDirtyBlock)
    1805             : 
    1806             : {
    1807        2298 :     if (poBandBlockCache == nullptr || !poBandBlockCache->IsInitOK())
    1808           0 :         return (CE_Failure);
    1809             : 
    1810             :     /* -------------------------------------------------------------------- */
    1811             :     /*      Validate the request                                            */
    1812             :     /* -------------------------------------------------------------------- */
    1813        2298 :     if (nXBlockOff < 0 || nXBlockOff >= nBlocksPerRow)
    1814             :     {
    1815           0 :         ReportError(CE_Failure, CPLE_IllegalArg,
    1816             :                     "Illegal nBlockXOff value (%d) in "
    1817             :                     "GDALRasterBand::FlushBlock()\n",
    1818             :                     nXBlockOff);
    1819             : 
    1820           0 :         return (CE_Failure);
    1821             :     }
    1822             : 
    1823        2298 :     if (nYBlockOff < 0 || nYBlockOff >= nBlocksPerColumn)
    1824             :     {
    1825           0 :         ReportError(CE_Failure, CPLE_IllegalArg,
    1826             :                     "Illegal nBlockYOff value (%d) in "
    1827             :                     "GDALRasterBand::FlushBlock()\n",
    1828             :                     nYBlockOff);
    1829             : 
    1830           0 :         return (CE_Failure);
    1831             :     }
    1832             : 
    1833        2298 :     return poBandBlockCache->FlushBlock(nXBlockOff, nYBlockOff,
    1834        2298 :                                         bWriteDirtyBlock);
    1835             : }
    1836             : 
    1837             : /************************************************************************/
    1838             : /*                        TryGetLockedBlockRef()                        */
    1839             : /************************************************************************/
    1840             : 
    1841             : /**
    1842             :  * \brief Try fetching block ref.
    1843             :  *
    1844             :  * This method will returned the requested block (locked) if it is already
    1845             :  * in the block cache for the layer.  If not, nullptr is returned.
    1846             :  *
    1847             :  * If a non-NULL value is returned, then a lock for the block will have been
    1848             :  * acquired on behalf of the caller.  It is absolutely imperative that the
    1849             :  * caller release this lock (with GDALRasterBlock::DropLock()) or else
    1850             :  * severe problems may result.
    1851             :  *
    1852             :  * @param nXBlockOff the horizontal block offset, with zero indicating
    1853             :  * the left most block, 1 the next block and so forth.
    1854             :  *
    1855             :  * @param nYBlockOff the vertical block offset, with zero indicating
    1856             :  * the top most block, 1 the next block and so forth.
    1857             :  *
    1858             :  * @return NULL if block not available, or locked block pointer.
    1859             :  */
    1860             : 
    1861     9919580 : GDALRasterBlock *GDALRasterBand::TryGetLockedBlockRef(int nXBlockOff,
    1862             :                                                       int nYBlockOff)
    1863             : 
    1864             : {
    1865     9919580 :     if (poBandBlockCache == nullptr || !poBandBlockCache->IsInitOK())
    1866       58289 :         return nullptr;
    1867             : 
    1868             :     /* -------------------------------------------------------------------- */
    1869             :     /*      Validate the request                                            */
    1870             :     /* -------------------------------------------------------------------- */
    1871     9863050 :     if (nXBlockOff < 0 || nXBlockOff >= nBlocksPerRow)
    1872             :     {
    1873        2404 :         ReportError(CE_Failure, CPLE_IllegalArg,
    1874             :                     "Illegal nBlockXOff value (%d) in "
    1875             :                     "GDALRasterBand::TryGetLockedBlockRef()\n",
    1876             :                     nXBlockOff);
    1877             : 
    1878           0 :         return (nullptr);
    1879             :     }
    1880             : 
    1881     9860650 :     if (nYBlockOff < 0 || nYBlockOff >= nBlocksPerColumn)
    1882             :     {
    1883         791 :         ReportError(CE_Failure, CPLE_IllegalArg,
    1884             :                     "Illegal nBlockYOff value (%d) in "
    1885             :                     "GDALRasterBand::TryGetLockedBlockRef()\n",
    1886             :                     nYBlockOff);
    1887             : 
    1888           0 :         return (nullptr);
    1889             :     }
    1890             : 
    1891     9859860 :     return poBandBlockCache->TryGetLockedBlockRef(nXBlockOff, nYBlockOff);
    1892             : }
    1893             : 
    1894             : /************************************************************************/
    1895             : /*                         GetLockedBlockRef()                          */
    1896             : /************************************************************************/
    1897             : 
    1898             : /**
    1899             :  * \brief Fetch a pointer to an internally cached raster block.
    1900             :  *
    1901             :  * This method will returned the requested block (locked) if it is already
    1902             :  * in the block cache for the layer.  If not, the block will be read from
    1903             :  * the driver, and placed in the layer block cached, then returned.  If an
    1904             :  * error occurs reading the block from the driver, a NULL value will be
    1905             :  * returned.
    1906             :  *
    1907             :  * If a non-NULL value is returned, then a lock for the block will have been
    1908             :  * acquired on behalf of the caller.  It is absolutely imperative that the
    1909             :  * caller release this lock (with GDALRasterBlock::DropLock()) or else
    1910             :  * severe problems may result.
    1911             :  *
    1912             :  * Note that calling GetLockedBlockRef() on a previously uncached band will
    1913             :  * enable caching.
    1914             :  *
    1915             :  * @param nXBlockOff the horizontal block offset, with zero indicating
    1916             :  * the left most block, 1 the next block and so forth.
    1917             :  *
    1918             :  * @param nYBlockOff the vertical block offset, with zero indicating
    1919             :  * the top most block, 1 the next block and so forth.
    1920             :  *
    1921             :  * @param bJustInitialize If TRUE the block will be allocated and initialized,
    1922             :  * but not actually read from the source.  This is useful when it will just
    1923             :  * be completely set and written back.
    1924             :  *
    1925             :  * @return pointer to the block object, or NULL on failure.
    1926             :  */
    1927             : 
    1928     9725580 : GDALRasterBlock *GDALRasterBand::GetLockedBlockRef(int nXBlockOff,
    1929             :                                                    int nYBlockOff,
    1930             :                                                    int bJustInitialize)
    1931             : 
    1932             : {
    1933             :     /* -------------------------------------------------------------------- */
    1934             :     /*      Try and fetch from cache.                                       */
    1935             :     /* -------------------------------------------------------------------- */
    1936     9725580 :     GDALRasterBlock *poBlock = TryGetLockedBlockRef(nXBlockOff, nYBlockOff);
    1937             : 
    1938             :     /* -------------------------------------------------------------------- */
    1939             :     /*      If we didn't find it in our memory cache, instantiate a         */
    1940             :     /*      block (potentially load from disk) and "adopt" it into the      */
    1941             :     /*      cache.                                                          */
    1942             :     /* -------------------------------------------------------------------- */
    1943     9729310 :     if (poBlock == nullptr)
    1944             :     {
    1945     3129140 :         if (!InitBlockInfo())
    1946           0 :             return (nullptr);
    1947             : 
    1948             :         /* --------------------------------------------------------------------
    1949             :          */
    1950             :         /*      Validate the request */
    1951             :         /* --------------------------------------------------------------------
    1952             :          */
    1953     3129100 :         if (nXBlockOff < 0 || nXBlockOff >= nBlocksPerRow)
    1954             :         {
    1955          64 :             ReportError(CE_Failure, CPLE_IllegalArg,
    1956             :                         "Illegal nBlockXOff value (%d) in "
    1957             :                         "GDALRasterBand::GetLockedBlockRef()\n",
    1958             :                         nXBlockOff);
    1959             : 
    1960           0 :             return (nullptr);
    1961             :         }
    1962             : 
    1963     3129040 :         if (nYBlockOff < 0 || nYBlockOff >= nBlocksPerColumn)
    1964             :         {
    1965          53 :             ReportError(CE_Failure, CPLE_IllegalArg,
    1966             :                         "Illegal nBlockYOff value (%d) in "
    1967             :                         "GDALRasterBand::GetLockedBlockRef()\n",
    1968             :                         nYBlockOff);
    1969             : 
    1970           0 :             return (nullptr);
    1971             :         }
    1972             : 
    1973     3128990 :         poBlock = poBandBlockCache->CreateBlock(nXBlockOff, nYBlockOff);
    1974     3129080 :         if (poBlock == nullptr)
    1975           0 :             return nullptr;
    1976             : 
    1977     3129080 :         poBlock->AddLock();
    1978             : 
    1979             :         /* We need to temporarily drop the read-write lock in the following */
    1980             :         /*scenario. Imagine 2 threads T1 and T2 that respectively write dataset
    1981             :          */
    1982             :         /* D1 and D2. T1 will take the mutex on D1 and T2 on D2. Now when the */
    1983             :         /* block cache fills, T1 might need to flush dirty blocks of D2 in the
    1984             :          */
    1985             :         /* below Internalize(), which will cause GDALRasterBlock::Write() to be
    1986             :          */
    1987             :         /* called and attempt at taking the lock on T2 (already taken).
    1988             :          * Similarly */
    1989             :         /* for T2 with D1, hence a deadlock situation (#6163) */
    1990             :         /* But this may open the door to other problems... */
    1991     3129140 :         if (poDS)
    1992     3128090 :             poDS->TemporarilyDropReadWriteLock();
    1993             :         /* allocate data space */
    1994     3129130 :         CPLErr eErr = poBlock->Internalize();
    1995     3129270 :         if (poDS)
    1996     3128200 :             poDS->ReacquireReadWriteLock();
    1997     3129260 :         if (eErr != CE_None)
    1998             :         {
    1999           0 :             poBlock->DropLock();
    2000           0 :             delete poBlock;
    2001           0 :             return nullptr;
    2002             :         }
    2003             : 
    2004     3129260 :         if (poBandBlockCache->AdoptBlock(poBlock) != CE_None)
    2005             :         {
    2006           0 :             poBlock->DropLock();
    2007           0 :             delete poBlock;
    2008           0 :             return nullptr;
    2009             :         }
    2010             : 
    2011     3129200 :         if (!bJustInitialize)
    2012             :         {
    2013     2782720 :             const GUInt32 nErrorCounter = CPLGetErrorCounter();
    2014     2782690 :             int bCallLeaveReadWrite = EnterReadWrite(GF_Read);
    2015     2782710 :             eErr = IReadBlock(nXBlockOff, nYBlockOff, poBlock->GetDataRef());
    2016     2782750 :             if (bCallLeaveReadWrite)
    2017      125797 :                 LeaveReadWrite();
    2018     2782740 :             if (eErr != CE_None)
    2019             :             {
    2020        1148 :                 poBlock->DropLock();
    2021        1148 :                 FlushBlock(nXBlockOff, nYBlockOff);
    2022        1148 :                 ReportError(CE_Failure, CPLE_AppDefined,
    2023             :                             "IReadBlock failed at X offset %d, Y offset %d%s",
    2024             :                             nXBlockOff, nYBlockOff,
    2025        1148 :                             (nErrorCounter != CPLGetErrorCounter())
    2026        1146 :                                 ? CPLSPrintf(": %s", CPLGetLastErrorMsg())
    2027             :                                 : "");
    2028        1148 :                 return nullptr;
    2029             :             }
    2030             : 
    2031     2781600 :             nBlockReads++;
    2032     2781600 :             if (static_cast<GIntBig>(nBlockReads) ==
    2033     2781600 :                     static_cast<GIntBig>(nBlocksPerRow) * nBlocksPerColumn +
    2034         204 :                         1 &&
    2035         204 :                 nBand == 1 && poDS != nullptr)
    2036             :             {
    2037         144 :                 CPLDebug("GDAL", "Potential thrashing on band %d of %s.", nBand,
    2038         144 :                          poDS->GetDescription());
    2039             :             }
    2040             :         }
    2041             :     }
    2042             : 
    2043     9728230 :     return poBlock;
    2044             : }
    2045             : 
    2046             : /************************************************************************/
    2047             : /*                               Fill()                                 */
    2048             : /************************************************************************/
    2049             : 
    2050             : /**
    2051             :  * \brief Fill this band with a constant value.
    2052             :  *
    2053             :  * GDAL makes no guarantees
    2054             :  * about what values pixels in newly created files are set to, so this
    2055             :  * method can be used to clear a band to a specified "default" value.
    2056             :  * The fill value is passed in as a double but this will be converted
    2057             :  * to the underlying type before writing to the file. An optional
    2058             :  * second argument allows the imaginary component of a complex
    2059             :  * constant value to be specified.
    2060             :  *
    2061             :  * This method is the same as the C function GDALFillRaster().
    2062             :  *
    2063             :  * @param dfRealValue Real component of fill value
    2064             :  * @param dfImaginaryValue Imaginary component of fill value, defaults to zero
    2065             :  *
    2066             :  * @return CE_Failure if the write fails, otherwise CE_None
    2067             :  */
    2068      169144 : CPLErr GDALRasterBand::Fill(double dfRealValue, double dfImaginaryValue)
    2069             : {
    2070             : 
    2071             :     // General approach is to construct a source block of the file's
    2072             :     // native type containing the appropriate value and then copy this
    2073             :     // to each block in the image via the RasterBlock cache. Using
    2074             :     // the cache means we avoid file I/O if it is not necessary, at the
    2075             :     // expense of some extra memcpy's (since we write to the
    2076             :     // RasterBlock cache, which is then at some point written to the
    2077             :     // underlying file, rather than simply directly to the underlying
    2078             :     // file.)
    2079             : 
    2080             :     // Check we can write to the file.
    2081      169144 :     if (eAccess == GA_ReadOnly)
    2082             :     {
    2083           1 :         ReportError(CE_Failure, CPLE_NoWriteAccess,
    2084             :                     "Attempt to write to read only dataset in "
    2085             :                     "GDALRasterBand::Fill().");
    2086           1 :         return CE_Failure;
    2087             :     }
    2088             : 
    2089             :     // Make sure block parameters are set.
    2090      169143 :     if (!InitBlockInfo())
    2091           0 :         return CE_Failure;
    2092             : 
    2093             :     // Allocate the source block.
    2094      169143 :     auto blockSize = static_cast<GPtrDiff_t>(nBlockXSize) * nBlockYSize;
    2095      169143 :     int elementSize = GDALGetDataTypeSizeBytes(eDataType);
    2096      169143 :     auto blockByteSize = blockSize * elementSize;
    2097             :     unsigned char *srcBlock =
    2098      169143 :         static_cast<unsigned char *>(VSIMalloc(blockByteSize));
    2099      169143 :     if (srcBlock == nullptr)
    2100             :     {
    2101           0 :         ReportError(CE_Failure, CPLE_OutOfMemory,
    2102             :                     "GDALRasterBand::Fill(): Out of memory "
    2103             :                     "allocating " CPL_FRMT_GUIB " bytes.\n",
    2104             :                     static_cast<GUIntBig>(blockByteSize));
    2105           0 :         return CE_Failure;
    2106             :     }
    2107             : 
    2108             :     // Initialize the source block.
    2109      169143 :     double complexSrc[2] = {dfRealValue, dfImaginaryValue};
    2110      169143 :     GDALCopyWords64(complexSrc, GDT_CFloat64, 0, srcBlock, eDataType,
    2111             :                     elementSize, blockSize);
    2112             : 
    2113      169143 :     const bool bCallLeaveReadWrite = CPL_TO_BOOL(EnterReadWrite(GF_Write));
    2114             : 
    2115             :     // Write block to block cache
    2116      627247 :     for (int j = 0; j < nBlocksPerColumn; ++j)
    2117             :     {
    2118     1210540 :         for (int i = 0; i < nBlocksPerRow; ++i)
    2119             :         {
    2120      752437 :             GDALRasterBlock *destBlock = GetLockedBlockRef(i, j, TRUE);
    2121      752437 :             if (destBlock == nullptr)
    2122             :             {
    2123           0 :                 ReportError(CE_Failure, CPLE_OutOfMemory,
    2124             :                             "GDALRasterBand::Fill(): Error "
    2125             :                             "while retrieving cache block.");
    2126           0 :                 VSIFree(srcBlock);
    2127           0 :                 return CE_Failure;
    2128             :             }
    2129      752437 :             memcpy(destBlock->GetDataRef(), srcBlock, blockByteSize);
    2130      752437 :             destBlock->MarkDirty();
    2131      752437 :             destBlock->DropLock();
    2132             :         }
    2133             :     }
    2134             : 
    2135      169143 :     if (bCallLeaveReadWrite)
    2136      168668 :         LeaveReadWrite();
    2137             : 
    2138             :     // Free up the source block
    2139      169143 :     VSIFree(srcBlock);
    2140             : 
    2141      169143 :     return CE_None;
    2142             : }
    2143             : 
    2144             : /************************************************************************/
    2145             : /*                         GDALFillRaster()                             */
    2146             : /************************************************************************/
    2147             : 
    2148             : /**
    2149             :  * \brief Fill this band with a constant value.
    2150             :  *
    2151             :  * @see GDALRasterBand::Fill()
    2152             :  */
    2153      169110 : CPLErr CPL_STDCALL GDALFillRaster(GDALRasterBandH hBand, double dfRealValue,
    2154             :                                   double dfImaginaryValue)
    2155             : {
    2156      169110 :     VALIDATE_POINTER1(hBand, "GDALFillRaster", CE_Failure);
    2157             : 
    2158      169110 :     GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
    2159      169110 :     return poBand->Fill(dfRealValue, dfImaginaryValue);
    2160             : }
    2161             : 
    2162             : /************************************************************************/
    2163             : /*                             GetAccess()                              */
    2164             : /************************************************************************/
    2165             : 
    2166             : /**
    2167             :  * \brief Find out if we have update permission for this band.
    2168             :  *
    2169             :  * This method is the same as the C function GDALGetRasterAccess().
    2170             :  *
    2171             :  * @return Either GA_Update or GA_ReadOnly.
    2172             :  */
    2173             : 
    2174        2473 : GDALAccess GDALRasterBand::GetAccess()
    2175             : 
    2176             : {
    2177        2473 :     return eAccess;
    2178             : }
    2179             : 
    2180             : /************************************************************************/
    2181             : /*                        GDALGetRasterAccess()                         */
    2182             : /************************************************************************/
    2183             : 
    2184             : /**
    2185             :  * \brief Find out if we have update permission for this band.
    2186             :  *
    2187             :  * @see GDALRasterBand::GetAccess()
    2188             :  */
    2189             : 
    2190        1835 : GDALAccess CPL_STDCALL GDALGetRasterAccess(GDALRasterBandH hBand)
    2191             : 
    2192             : {
    2193        1835 :     VALIDATE_POINTER1(hBand, "GDALGetRasterAccess", GA_ReadOnly);
    2194             : 
    2195        1835 :     GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
    2196        1835 :     return poBand->GetAccess();
    2197             : }
    2198             : 
    2199             : /************************************************************************/
    2200             : /*                          GetCategoryNames()                          */
    2201             : /************************************************************************/
    2202             : 
    2203             : /**
    2204             :  * \brief Fetch the list of category names for this raster.
    2205             :  *
    2206             :  * The return list is a "StringList" in the sense of the CPL functions.
    2207             :  * That is a NULL terminated array of strings.  Raster values without
    2208             :  * associated names will have an empty string in the returned list.  The
    2209             :  * first entry in the list is for raster values of zero, and so on.
    2210             :  *
    2211             :  * The returned stringlist should not be altered or freed by the application.
    2212             :  * It may change on the next GDAL call, so please copy it if it is needed
    2213             :  * for any period of time.
    2214             :  *
    2215             :  * This method is the same as the C function GDALGetRasterCategoryNames().
    2216             :  *
    2217             :  * @return list of names, or NULL if none.
    2218             :  */
    2219             : 
    2220         231 : char **GDALRasterBand::GetCategoryNames()
    2221             : 
    2222             : {
    2223         231 :     return nullptr;
    2224             : }
    2225             : 
    2226             : /************************************************************************/
    2227             : /*                     GDALGetRasterCategoryNames()                     */
    2228             : /************************************************************************/
    2229             : 
    2230             : /**
    2231             :  * \brief Fetch the list of category names for this raster.
    2232             :  *
    2233             :  * @see GDALRasterBand::GetCategoryNames()
    2234             :  */
    2235             : 
    2236         161 : char **CPL_STDCALL GDALGetRasterCategoryNames(GDALRasterBandH hBand)
    2237             : 
    2238             : {
    2239         161 :     VALIDATE_POINTER1(hBand, "GDALGetRasterCategoryNames", nullptr);
    2240             : 
    2241         161 :     GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
    2242         161 :     return poBand->GetCategoryNames();
    2243             : }
    2244             : 
    2245             : /************************************************************************/
    2246             : /*                          SetCategoryNames()                          */
    2247             : /************************************************************************/
    2248             : 
    2249             : /**
    2250             :  * \fn GDALRasterBand::SetCategoryNames(char**)
    2251             :  * \brief Set the category names for this band.
    2252             :  *
    2253             :  * See the GetCategoryNames() method for more on the interpretation of
    2254             :  * category names.
    2255             :  *
    2256             :  * This method is the same as the C function GDALSetRasterCategoryNames().
    2257             :  *
    2258             :  * @param papszNames the NULL terminated StringList of category names.  May
    2259             :  * be NULL to just clear the existing list.
    2260             :  *
    2261             :  * @return CE_None on success of CE_Failure on failure.  If unsupported
    2262             :  * by the driver CE_Failure is returned, but no error message is reported.
    2263             :  */
    2264             : 
    2265             : /**/
    2266             : /**/
    2267             : 
    2268           0 : CPLErr GDALRasterBand::SetCategoryNames(char ** /*papszNames*/)
    2269             : {
    2270           0 :     if (!(GetMOFlags() & GMO_IGNORE_UNIMPLEMENTED))
    2271           0 :         ReportError(CE_Failure, CPLE_NotSupported,
    2272             :                     "SetCategoryNames() not supported for this dataset.");
    2273             : 
    2274           0 :     return CE_Failure;
    2275             : }
    2276             : 
    2277             : /************************************************************************/
    2278             : /*                        GDALSetCategoryNames()                        */
    2279             : /************************************************************************/
    2280             : 
    2281             : /**
    2282             :  * \brief Set the category names for this band.
    2283             :  *
    2284             :  * @see GDALRasterBand::SetCategoryNames()
    2285             :  */
    2286             : 
    2287           2 : CPLErr CPL_STDCALL GDALSetRasterCategoryNames(GDALRasterBandH hBand,
    2288             :                                               CSLConstList papszNames)
    2289             : 
    2290             : {
    2291           2 :     VALIDATE_POINTER1(hBand, "GDALSetRasterCategoryNames", CE_Failure);
    2292             : 
    2293           2 :     GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
    2294           2 :     return poBand->SetCategoryNames(const_cast<char **>(papszNames));
    2295             : }
    2296             : 
    2297             : /************************************************************************/
    2298             : /*                           GetNoDataValue()                           */
    2299             : /************************************************************************/
    2300             : 
    2301             : /**
    2302             :  * \brief Fetch the no data value for this band.
    2303             :  *
    2304             :  * If there is no out of data value, an out of range value will generally
    2305             :  * be returned.  The no data value for a band is generally a special marker
    2306             :  * value used to mark pixels that are not valid data.  Such pixels should
    2307             :  * generally not be displayed, nor contribute to analysis operations.
    2308             :  *
    2309             :  * The no data value returned is 'raw', meaning that it has no offset and
    2310             :  * scale applied.
    2311             :  *
    2312             :  * For rasters of type GDT_Int64 or GDT_UInt64, using this method might be
    2313             :  * lossy if the nodata value cannot exactly been represented by a double.
    2314             :  * Use GetNoDataValueAsInt64() or GetNoDataValueAsUInt64() instead.
    2315             :  *
    2316             :  * This method is the same as the C function GDALGetRasterNoDataValue().
    2317             :  *
    2318             :  * @param pbSuccess pointer to a boolean to use to indicate if a value
    2319             :  * is actually associated with this layer.  May be NULL (default).
    2320             :  *
    2321             :  * @return the nodata value for this band.
    2322             :  */
    2323             : 
    2324       31328 : double GDALRasterBand::GetNoDataValue(int *pbSuccess)
    2325             : 
    2326             : {
    2327       31328 :     if (pbSuccess != nullptr)
    2328       31328 :         *pbSuccess = FALSE;
    2329             : 
    2330       31328 :     return -1e10;
    2331             : }
    2332             : 
    2333             : /************************************************************************/
    2334             : /*                      GDALGetRasterNoDataValue()                      */
    2335             : /************************************************************************/
    2336             : 
    2337             : /**
    2338             :  * \brief Fetch the no data value for this band.
    2339             :  *
    2340             :  * @see GDALRasterBand::GetNoDataValue()
    2341             :  */
    2342             : 
    2343      413650 : double CPL_STDCALL GDALGetRasterNoDataValue(GDALRasterBandH hBand,
    2344             :                                             int *pbSuccess)
    2345             : 
    2346             : {
    2347      413650 :     VALIDATE_POINTER1(hBand, "GDALGetRasterNoDataValue", 0);
    2348             : 
    2349      413650 :     GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
    2350      413650 :     return poBand->GetNoDataValue(pbSuccess);
    2351             : }
    2352             : 
    2353             : /************************************************************************/
    2354             : /*                       GetNoDataValueAsInt64()                        */
    2355             : /************************************************************************/
    2356             : 
    2357             : /**
    2358             :  * \brief Fetch the no data value for this band.
    2359             :  *
    2360             :  * This method should ONLY be called on rasters whose data type is GDT_Int64.
    2361             :  *
    2362             :  * If there is no out of data value, an out of range value will generally
    2363             :  * be returned.  The no data value for a band is generally a special marker
    2364             :  * value used to mark pixels that are not valid data.  Such pixels should
    2365             :  * generally not be displayed, nor contribute to analysis operations.
    2366             :  *
    2367             :  * The no data value returned is 'raw', meaning that it has no offset and
    2368             :  * scale applied.
    2369             :  *
    2370             :  * This method is the same as the C function GDALGetRasterNoDataValueAsInt64().
    2371             :  *
    2372             :  * @param pbSuccess pointer to a boolean to use to indicate if a value
    2373             :  * is actually associated with this layer.  May be NULL (default).
    2374             :  *
    2375             :  * @return the nodata value for this band.
    2376             :  *
    2377             :  * @since GDAL 3.5
    2378             :  */
    2379             : 
    2380           4 : int64_t GDALRasterBand::GetNoDataValueAsInt64(int *pbSuccess)
    2381             : 
    2382             : {
    2383           4 :     if (pbSuccess != nullptr)
    2384           4 :         *pbSuccess = FALSE;
    2385             : 
    2386           4 :     return std::numeric_limits<int64_t>::min();
    2387             : }
    2388             : 
    2389             : /************************************************************************/
    2390             : /*                   GDALGetRasterNoDataValueAsInt64()                  */
    2391             : /************************************************************************/
    2392             : 
    2393             : /**
    2394             :  * \brief Fetch the no data value for this band.
    2395             :  *
    2396             :  * This function should ONLY be called on rasters whose data type is GDT_Int64.
    2397             :  *
    2398             :  * @see GDALRasterBand::GetNoDataValueAsInt64()
    2399             :  *
    2400             :  * @since GDAL 3.5
    2401             :  */
    2402             : 
    2403          23 : int64_t CPL_STDCALL GDALGetRasterNoDataValueAsInt64(GDALRasterBandH hBand,
    2404             :                                                     int *pbSuccess)
    2405             : 
    2406             : {
    2407          23 :     VALIDATE_POINTER1(hBand, "GDALGetRasterNoDataValueAsInt64",
    2408             :                       std::numeric_limits<int64_t>::min());
    2409             : 
    2410          23 :     GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
    2411          23 :     return poBand->GetNoDataValueAsInt64(pbSuccess);
    2412             : }
    2413             : 
    2414             : /************************************************************************/
    2415             : /*                       GetNoDataValueAsUInt64()                        */
    2416             : /************************************************************************/
    2417             : 
    2418             : /**
    2419             :  * \brief Fetch the no data value for this band.
    2420             :  *
    2421             :  * This method should ONLY be called on rasters whose data type is GDT_UInt64.
    2422             :  *
    2423             :  * If there is no out of data value, an out of range value will generally
    2424             :  * be returned.  The no data value for a band is generally a special marker
    2425             :  * value used to mark pixels that are not valid data.  Such pixels should
    2426             :  * generally not be displayed, nor contribute to analysis operations.
    2427             :  *
    2428             :  * The no data value returned is 'raw', meaning that it has no offset and
    2429             :  * scale applied.
    2430             :  *
    2431             :  * This method is the same as the C function GDALGetRasterNoDataValueAsUInt64().
    2432             :  *
    2433             :  * @param pbSuccess pointer to a boolean to use to indicate if a value
    2434             :  * is actually associated with this layer.  May be NULL (default).
    2435             :  *
    2436             :  * @return the nodata value for this band.
    2437             :  *
    2438             :  * @since GDAL 3.5
    2439             :  */
    2440             : 
    2441           3 : uint64_t GDALRasterBand::GetNoDataValueAsUInt64(int *pbSuccess)
    2442             : 
    2443             : {
    2444           3 :     if (pbSuccess != nullptr)
    2445           3 :         *pbSuccess = FALSE;
    2446             : 
    2447           3 :     return std::numeric_limits<uint64_t>::max();
    2448             : }
    2449             : 
    2450             : /************************************************************************/
    2451             : /*                   GDALGetRasterNoDataValueAsUInt64()                  */
    2452             : /************************************************************************/
    2453             : 
    2454             : /**
    2455             :  * \brief Fetch the no data value for this band.
    2456             :  *
    2457             :  * This function should ONLY be called on rasters whose data type is GDT_UInt64.
    2458             :  *
    2459             :  * @see GDALRasterBand::GetNoDataValueAsUInt64()
    2460             :  *
    2461             :  * @since GDAL 3.5
    2462             :  */
    2463             : 
    2464          18 : uint64_t CPL_STDCALL GDALGetRasterNoDataValueAsUInt64(GDALRasterBandH hBand,
    2465             :                                                       int *pbSuccess)
    2466             : 
    2467             : {
    2468          18 :     VALIDATE_POINTER1(hBand, "GDALGetRasterNoDataValueAsUInt64",
    2469             :                       std::numeric_limits<uint64_t>::max());
    2470             : 
    2471          18 :     GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
    2472          18 :     return poBand->GetNoDataValueAsUInt64(pbSuccess);
    2473             : }
    2474             : 
    2475             : /************************************************************************/
    2476             : /*                           SetNoDataValue()                           */
    2477             : /************************************************************************/
    2478             : 
    2479             : /**
    2480             :  * \fn GDALRasterBand::SetNoDataValue(double)
    2481             :  * \brief Set the no data value for this band.
    2482             :  *
    2483             :  * Depending on drivers, changing the no data value may or may not have an
    2484             :  * effect on the pixel values of a raster that has just been created. It is
    2485             :  * thus advised to explicitly called Fill() if the intent is to initialize
    2486             :  * the raster to the nodata value.
    2487             :  * In any case, changing an existing no data value, when one already exists and
    2488             :  * the dataset exists or has been initialized, has no effect on the pixel whose
    2489             :  * value matched the previous nodata value.
    2490             :  *
    2491             :  * For rasters of type GDT_Int64 or GDT_UInt64, whose nodata value cannot always
    2492             :  * be represented by a double, use SetNoDataValueAsInt64() or
    2493             :  * SetNoDataValueAsUInt64() instead.
    2494             :  *
    2495             :  * To clear the nodata value, use DeleteNoDataValue().
    2496             :  *
    2497             :  * This method is the same as the C function GDALSetRasterNoDataValue().
    2498             :  *
    2499             :  * @param dfNoData the value to set.
    2500             :  *
    2501             :  * @return CE_None on success, or CE_Failure on failure.  If unsupported
    2502             :  * by the driver, CE_Failure is returned by no error message will have
    2503             :  * been emitted.
    2504             :  */
    2505             : 
    2506             : /**/
    2507             : /**/
    2508             : 
    2509           0 : CPLErr GDALRasterBand::SetNoDataValue(double /*dfNoData*/)
    2510             : 
    2511             : {
    2512           0 :     if (!(GetMOFlags() & GMO_IGNORE_UNIMPLEMENTED))
    2513           0 :         ReportError(CE_Failure, CPLE_NotSupported,
    2514             :                     "SetNoDataValue() not supported for this dataset.");
    2515             : 
    2516           0 :     return CE_Failure;
    2517             : }
    2518             : 
    2519             : /************************************************************************/
    2520             : /*                         GDALSetRasterNoDataValue()                   */
    2521             : /************************************************************************/
    2522             : 
    2523             : /**
    2524             :  * \brief Set the no data value for this band.
    2525             :  *
    2526             :  * Depending on drivers, changing the no data value may or may not have an
    2527             :  * effect on the pixel values of a raster that has just been created. It is
    2528             :  * thus advised to explicitly called Fill() if the intent is to initialize
    2529             :  * the raster to the nodata value.
    2530             :  * In any case, changing an existing no data value, when one already exists and
    2531             :  * the dataset exists or has been initialized, has no effect on the pixel whose
    2532             :  * value matched the previous nodata value.
    2533             :  *
    2534             :  * For rasters of type GDT_Int64 or GDT_UInt64, whose nodata value cannot always
    2535             :  * be represented by a double, use GDALSetRasterNoDataValueAsInt64() or
    2536             :  * GDALSetRasterNoDataValueAsUInt64() instead.
    2537             :  *
    2538             :  * @see GDALRasterBand::SetNoDataValue()
    2539             :  */
    2540             : 
    2541         649 : CPLErr CPL_STDCALL GDALSetRasterNoDataValue(GDALRasterBandH hBand,
    2542             :                                             double dfValue)
    2543             : 
    2544             : {
    2545         649 :     VALIDATE_POINTER1(hBand, "GDALSetRasterNoDataValue", CE_Failure);
    2546             : 
    2547         649 :     GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
    2548         649 :     return poBand->SetNoDataValue(dfValue);
    2549             : }
    2550             : 
    2551             : /************************************************************************/
    2552             : /*                       SetNoDataValueAsInt64()                        */
    2553             : /************************************************************************/
    2554             : 
    2555             : /**
    2556             :  * \brief Set the no data value for this band.
    2557             :  *
    2558             :  * This method should ONLY be called on rasters whose data type is GDT_Int64.
    2559             :  *
    2560             :  * Depending on drivers, changing the no data value may or may not have an
    2561             :  * effect on the pixel values of a raster that has just been created. It is
    2562             :  * thus advised to explicitly called Fill() if the intent is to initialize
    2563             :  * the raster to the nodata value.
    2564             :  * In ay case, changing an existing no data value, when one already exists and
    2565             :  * the dataset exists or has been initialized, has no effect on the pixel whose
    2566             :  * value matched the previous nodata value.
    2567             :  *
    2568             :  * To clear the nodata value, use DeleteNoDataValue().
    2569             :  *
    2570             :  * This method is the same as the C function GDALSetRasterNoDataValueAsInt64().
    2571             :  *
    2572             :  * @param nNoDataValue the value to set.
    2573             :  *
    2574             :  * @return CE_None on success, or CE_Failure on failure.  If unsupported
    2575             :  * by the driver, CE_Failure is returned by no error message will have
    2576             :  * been emitted.
    2577             :  *
    2578             :  * @since GDAL 3.5
    2579             :  */
    2580             : 
    2581           0 : CPLErr GDALRasterBand::SetNoDataValueAsInt64(CPL_UNUSED int64_t nNoDataValue)
    2582             : 
    2583             : {
    2584           0 :     if (!(GetMOFlags() & GMO_IGNORE_UNIMPLEMENTED))
    2585           0 :         ReportError(CE_Failure, CPLE_NotSupported,
    2586             :                     "SetNoDataValueAsInt64() not supported for this dataset.");
    2587             : 
    2588           0 :     return CE_Failure;
    2589             : }
    2590             : 
    2591             : /************************************************************************/
    2592             : /*                 GDALSetRasterNoDataValueAsInt64()                    */
    2593             : /************************************************************************/
    2594             : 
    2595             : /**
    2596             :  * \brief Set the no data value for this band.
    2597             :  *
    2598             :  * This function should ONLY be called on rasters whose data type is GDT_Int64.
    2599             :  *
    2600             :  * Depending on drivers, changing the no data value may or may not have an
    2601             :  * effect on the pixel values of a raster that has just been created. It is
    2602             :  * thus advised to explicitly called Fill() if the intent is to initialize
    2603             :  * the raster to the nodata value.
    2604             :  * In ay case, changing an existing no data value, when one already exists and
    2605             :  * the dataset exists or has been initialized, has no effect on the pixel whose
    2606             :  * value matched the previous nodata value.
    2607             :  *
    2608             :  * @see GDALRasterBand::SetNoDataValueAsInt64()
    2609             :  *
    2610             :  * @since GDAL 3.5
    2611             :  */
    2612             : 
    2613          18 : CPLErr CPL_STDCALL GDALSetRasterNoDataValueAsInt64(GDALRasterBandH hBand,
    2614             :                                                    int64_t nValue)
    2615             : 
    2616             : {
    2617          18 :     VALIDATE_POINTER1(hBand, "GDALSetRasterNoDataValueAsInt64", CE_Failure);
    2618             : 
    2619          18 :     GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
    2620          18 :     return poBand->SetNoDataValueAsInt64(nValue);
    2621             : }
    2622             : 
    2623             : /************************************************************************/
    2624             : /*                       SetNoDataValueAsUInt64()                       */
    2625             : /************************************************************************/
    2626             : 
    2627             : /**
    2628             :  * \brief Set the no data value for this band.
    2629             :  *
    2630             :  * This method should ONLY be called on rasters whose data type is GDT_UInt64.
    2631             :  *
    2632             :  * Depending on drivers, changing the no data value may or may not have an
    2633             :  * effect on the pixel values of a raster that has just been created. It is
    2634             :  * thus advised to explicitly called Fill() if the intent is to initialize
    2635             :  * the raster to the nodata value.
    2636             :  * In ay case, changing an existing no data value, when one already exists and
    2637             :  * the dataset exists or has been initialized, has no effect on the pixel whose
    2638             :  * value matched the previous nodata value.
    2639             :  *
    2640             :  * To clear the nodata value, use DeleteNoDataValue().
    2641             :  *
    2642             :  * This method is the same as the C function GDALSetRasterNoDataValueAsUInt64().
    2643             :  *
    2644             :  * @param nNoDataValue the value to set.
    2645             :  *
    2646             :  * @return CE_None on success, or CE_Failure on failure.  If unsupported
    2647             :  * by the driver, CE_Failure is returned by no error message will have
    2648             :  * been emitted.
    2649             :  *
    2650             :  * @since GDAL 3.5
    2651             :  */
    2652             : 
    2653           0 : CPLErr GDALRasterBand::SetNoDataValueAsUInt64(CPL_UNUSED uint64_t nNoDataValue)
    2654             : 
    2655             : {
    2656           0 :     if (!(GetMOFlags() & GMO_IGNORE_UNIMPLEMENTED))
    2657           0 :         ReportError(CE_Failure, CPLE_NotSupported,
    2658             :                     "SetNoDataValueAsUInt64() not supported for this dataset.");
    2659             : 
    2660           0 :     return CE_Failure;
    2661             : }
    2662             : 
    2663             : /************************************************************************/
    2664             : /*                 GDALSetRasterNoDataValueAsUInt64()                    */
    2665             : /************************************************************************/
    2666             : 
    2667             : /**
    2668             :  * \brief Set the no data value for this band.
    2669             :  *
    2670             :  * This function should ONLY be called on rasters whose data type is GDT_UInt64.
    2671             :  *
    2672             :  * Depending on drivers, changing the no data value may or may not have an
    2673             :  * effect on the pixel values of a raster that has just been created. It is
    2674             :  * thus advised to explicitly called Fill() if the intent is to initialize
    2675             :  * the raster to the nodata value.
    2676             :  * In ay case, changing an existing no data value, when one already exists and
    2677             :  * the dataset exists or has been initialized, has no effect on the pixel whose
    2678             :  * value matched the previous nodata value.
    2679             :  *
    2680             :  * @see GDALRasterBand::SetNoDataValueAsUInt64()
    2681             :  *
    2682             :  * @since GDAL 3.5
    2683             :  */
    2684             : 
    2685          16 : CPLErr CPL_STDCALL GDALSetRasterNoDataValueAsUInt64(GDALRasterBandH hBand,
    2686             :                                                     uint64_t nValue)
    2687             : 
    2688             : {
    2689          16 :     VALIDATE_POINTER1(hBand, "GDALSetRasterNoDataValueAsUInt64", CE_Failure);
    2690             : 
    2691          16 :     GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
    2692          16 :     return poBand->SetNoDataValueAsUInt64(nValue);
    2693             : }
    2694             : 
    2695             : /************************************************************************/
    2696             : /*                        DeleteNoDataValue()                           */
    2697             : /************************************************************************/
    2698             : 
    2699             : /**
    2700             :  * \brief Remove the no data value for this band.
    2701             :  *
    2702             :  * This method is the same as the C function GDALDeleteRasterNoDataValue().
    2703             :  *
    2704             :  * @return CE_None on success, or CE_Failure on failure.  If unsupported
    2705             :  * by the driver, CE_Failure is returned by no error message will have
    2706             :  * been emitted.
    2707             :  *
    2708             :  * @since GDAL 2.1
    2709             :  */
    2710             : 
    2711           0 : CPLErr GDALRasterBand::DeleteNoDataValue()
    2712             : 
    2713             : {
    2714           0 :     if (!(GetMOFlags() & GMO_IGNORE_UNIMPLEMENTED))
    2715           0 :         ReportError(CE_Failure, CPLE_NotSupported,
    2716             :                     "DeleteNoDataValue() not supported for this dataset.");
    2717             : 
    2718           0 :     return CE_Failure;
    2719             : }
    2720             : 
    2721             : /************************************************************************/
    2722             : /*                       GDALDeleteRasterNoDataValue()                  */
    2723             : /************************************************************************/
    2724             : 
    2725             : /**
    2726             :  * \brief Remove the no data value for this band.
    2727             :  *
    2728             :  * @see GDALRasterBand::DeleteNoDataValue()
    2729             :  *
    2730             :  * @since GDAL 2.1
    2731             :  */
    2732             : 
    2733          41 : CPLErr CPL_STDCALL GDALDeleteRasterNoDataValue(GDALRasterBandH hBand)
    2734             : 
    2735             : {
    2736          41 :     VALIDATE_POINTER1(hBand, "GDALDeleteRasterNoDataValue", CE_Failure);
    2737             : 
    2738          41 :     GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
    2739          41 :     return poBand->DeleteNoDataValue();
    2740             : }
    2741             : 
    2742             : /************************************************************************/
    2743             : /*                             GetMaximum()                             */
    2744             : /************************************************************************/
    2745             : 
    2746             : /**
    2747             :  * \brief Fetch the maximum value for this band.
    2748             :  *
    2749             :  * For file formats that don't know this intrinsically, the maximum supported
    2750             :  * value for the data type will generally be returned.
    2751             :  *
    2752             :  * This method is the same as the C function GDALGetRasterMaximum().
    2753             :  *
    2754             :  * @param pbSuccess pointer to a boolean to use to indicate if the
    2755             :  * returned value is a tight maximum or not.  May be NULL (default).
    2756             :  *
    2757             :  * @return the maximum raster value (excluding no data pixels)
    2758             :  */
    2759             : 
    2760         460 : double GDALRasterBand::GetMaximum(int *pbSuccess)
    2761             : 
    2762             : {
    2763         460 :     const char *pszValue = nullptr;
    2764             : 
    2765         460 :     if ((pszValue = GetMetadataItem("STATISTICS_MAXIMUM")) != nullptr)
    2766             :     {
    2767          38 :         if (pbSuccess != nullptr)
    2768          33 :             *pbSuccess = TRUE;
    2769             : 
    2770          38 :         return CPLAtofM(pszValue);
    2771             :     }
    2772             : 
    2773         422 :     if (pbSuccess != nullptr)
    2774         390 :         *pbSuccess = FALSE;
    2775             : 
    2776         422 :     switch (eDataType)
    2777             :     {
    2778         299 :         case GDT_Byte:
    2779             :         {
    2780         299 :             EnablePixelTypeSignedByteWarning(false);
    2781             :             const char *pszPixelType =
    2782         299 :                 GetMetadataItem("PIXELTYPE", "IMAGE_STRUCTURE");
    2783         299 :             EnablePixelTypeSignedByteWarning(true);
    2784         299 :             if (pszPixelType != nullptr && EQUAL(pszPixelType, "SIGNEDBYTE"))
    2785           0 :                 return 127;
    2786             : 
    2787         299 :             return 255;
    2788             :         }
    2789             : 
    2790           0 :         case GDT_Int8:
    2791           0 :             return 127;
    2792             : 
    2793          19 :         case GDT_UInt16:
    2794          19 :             return 65535;
    2795             : 
    2796          24 :         case GDT_Int16:
    2797             :         case GDT_CInt16:
    2798          24 :             return 32767;
    2799             : 
    2800          15 :         case GDT_Int32:
    2801             :         case GDT_CInt32:
    2802          15 :             return 2147483647.0;
    2803             : 
    2804          13 :         case GDT_UInt32:
    2805          13 :             return 4294967295.0;
    2806             : 
    2807           0 :         case GDT_Int64:
    2808           0 :             return static_cast<double>(std::numeric_limits<GInt64>::max());
    2809             : 
    2810           0 :         case GDT_UInt64:
    2811           0 :             return static_cast<double>(std::numeric_limits<GUInt64>::max());
    2812             : 
    2813          32 :         case GDT_Float32:
    2814             :         case GDT_CFloat32:
    2815          32 :             return 4294967295.0;  // Not actually accurate.
    2816             : 
    2817          20 :         case GDT_Float64:
    2818             :         case GDT_CFloat64:
    2819          20 :             return 4294967295.0;  // Not actually accurate.
    2820             : 
    2821           0 :         case GDT_Unknown:
    2822             :         case GDT_TypeCount:
    2823           0 :             break;
    2824             :     }
    2825           0 :     return 4294967295.0;  // Not actually accurate.
    2826             : }
    2827             : 
    2828             : /************************************************************************/
    2829             : /*                        GDALGetRasterMaximum()                        */
    2830             : /************************************************************************/
    2831             : 
    2832             : /**
    2833             :  * \brief Fetch the maximum value for this band.
    2834             :  *
    2835             :  * @see GDALRasterBand::GetMaximum()
    2836             :  */
    2837             : 
    2838         216 : double CPL_STDCALL GDALGetRasterMaximum(GDALRasterBandH hBand, int *pbSuccess)
    2839             : 
    2840             : {
    2841         216 :     VALIDATE_POINTER1(hBand, "GDALGetRasterMaximum", 0);
    2842             : 
    2843         216 :     GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
    2844         216 :     return poBand->GetMaximum(pbSuccess);
    2845             : }
    2846             : 
    2847             : /************************************************************************/
    2848             : /*                             GetMinimum()                             */
    2849             : /************************************************************************/
    2850             : 
    2851             : /**
    2852             :  * \brief Fetch the minimum value for this band.
    2853             :  *
    2854             :  * For file formats that don't know this intrinsically, the minimum supported
    2855             :  * value for the data type will generally be returned.
    2856             :  *
    2857             :  * This method is the same as the C function GDALGetRasterMinimum().
    2858             :  *
    2859             :  * @param pbSuccess pointer to a boolean to use to indicate if the
    2860             :  * returned value is a tight minimum or not.  May be NULL (default).
    2861             :  *
    2862             :  * @return the minimum raster value (excluding no data pixels)
    2863             :  */
    2864             : 
    2865         468 : double GDALRasterBand::GetMinimum(int *pbSuccess)
    2866             : 
    2867             : {
    2868         468 :     const char *pszValue = nullptr;
    2869             : 
    2870         468 :     if ((pszValue = GetMetadataItem("STATISTICS_MINIMUM")) != nullptr)
    2871             :     {
    2872          43 :         if (pbSuccess != nullptr)
    2873          38 :             *pbSuccess = TRUE;
    2874             : 
    2875          43 :         return CPLAtofM(pszValue);
    2876             :     }
    2877             : 
    2878         425 :     if (pbSuccess != nullptr)
    2879         393 :         *pbSuccess = FALSE;
    2880             : 
    2881         425 :     switch (eDataType)
    2882             :     {
    2883         302 :         case GDT_Byte:
    2884             :         {
    2885         302 :             EnablePixelTypeSignedByteWarning(false);
    2886             :             const char *pszPixelType =
    2887         302 :                 GetMetadataItem("PIXELTYPE", "IMAGE_STRUCTURE");
    2888         302 :             EnablePixelTypeSignedByteWarning(true);
    2889         302 :             if (pszPixelType != nullptr && EQUAL(pszPixelType, "SIGNEDBYTE"))
    2890           0 :                 return -128;
    2891             : 
    2892         302 :             return 0;
    2893             :         }
    2894             : 
    2895           0 :         case GDT_Int8:
    2896           0 :             return -128;
    2897             :             break;
    2898             : 
    2899          19 :         case GDT_UInt16:
    2900          19 :             return 0;
    2901             : 
    2902          24 :         case GDT_Int16:
    2903             :         case GDT_CInt16:
    2904          24 :             return -32768;
    2905             : 
    2906          15 :         case GDT_Int32:
    2907             :         case GDT_CInt32:
    2908          15 :             return -2147483648.0;
    2909             : 
    2910          13 :         case GDT_UInt32:
    2911          13 :             return 0;
    2912             : 
    2913           0 :         case GDT_Int64:
    2914           0 :             return static_cast<double>(std::numeric_limits<GInt64>::min());
    2915             : 
    2916           0 :         case GDT_UInt64:
    2917           0 :             return 0;
    2918             : 
    2919          32 :         case GDT_Float32:
    2920             :         case GDT_CFloat32:
    2921          32 :             return -4294967295.0;  // Not actually accurate.
    2922             : 
    2923          20 :         case GDT_Float64:
    2924             :         case GDT_CFloat64:
    2925          20 :             return -4294967295.0;  // Not actually accurate.
    2926             : 
    2927           0 :         case GDT_Unknown:
    2928             :         case GDT_TypeCount:
    2929           0 :             break;
    2930             :     }
    2931           0 :     return -4294967295.0;  // Not actually accurate.
    2932             : }
    2933             : 
    2934             : /************************************************************************/
    2935             : /*                        GDALGetRasterMinimum()                        */
    2936             : /************************************************************************/
    2937             : 
    2938             : /**
    2939             :  * \brief Fetch the minimum value for this band.
    2940             :  *
    2941             :  * @see GDALRasterBand::GetMinimum()
    2942             :  */
    2943             : 
    2944         226 : double CPL_STDCALL GDALGetRasterMinimum(GDALRasterBandH hBand, int *pbSuccess)
    2945             : 
    2946             : {
    2947         226 :     VALIDATE_POINTER1(hBand, "GDALGetRasterMinimum", 0);
    2948             : 
    2949         226 :     GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
    2950         226 :     return poBand->GetMinimum(pbSuccess);
    2951             : }
    2952             : 
    2953             : /************************************************************************/
    2954             : /*                       GetColorInterpretation()                       */
    2955             : /************************************************************************/
    2956             : 
    2957             : /**
    2958             :  * \brief How should this band be interpreted as color?
    2959             :  *
    2960             :  * GCI_Undefined is returned when the format doesn't know anything
    2961             :  * about the color interpretation.
    2962             :  *
    2963             :  * This method is the same as the C function
    2964             :  * GDALGetRasterColorInterpretation().
    2965             :  *
    2966             :  * @return color interpretation value for band.
    2967             :  */
    2968             : 
    2969         114 : GDALColorInterp GDALRasterBand::GetColorInterpretation()
    2970             : 
    2971             : {
    2972         114 :     return GCI_Undefined;
    2973             : }
    2974             : 
    2975             : /************************************************************************/
    2976             : /*                  GDALGetRasterColorInterpretation()                  */
    2977             : /************************************************************************/
    2978             : 
    2979             : /**
    2980             :  * \brief How should this band be interpreted as color?
    2981             :  *
    2982             :  * @see GDALRasterBand::GetColorInterpretation()
    2983             :  */
    2984             : 
    2985             : GDALColorInterp CPL_STDCALL
    2986        4894 : GDALGetRasterColorInterpretation(GDALRasterBandH hBand)
    2987             : 
    2988             : {
    2989        4894 :     VALIDATE_POINTER1(hBand, "GDALGetRasterColorInterpretation", GCI_Undefined);
    2990             : 
    2991        4894 :     GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
    2992        4894 :     return poBand->GetColorInterpretation();
    2993             : }
    2994             : 
    2995             : /************************************************************************/
    2996             : /*                       SetColorInterpretation()                       */
    2997             : /************************************************************************/
    2998             : 
    2999             : /**
    3000             :  * \fn GDALRasterBand::SetColorInterpretation(GDALColorInterp)
    3001             :  * \brief Set color interpretation of a band.
    3002             :  *
    3003             :  * This method is the same as the C function GDALSetRasterColorInterpretation().
    3004             :  *
    3005             :  * @param eColorInterp the new color interpretation to apply to this band.
    3006             :  *
    3007             :  * @return CE_None on success or CE_Failure if method is unsupported by format.
    3008             :  */
    3009             : 
    3010             : /**/
    3011             : /**/
    3012             : 
    3013           3 : CPLErr GDALRasterBand::SetColorInterpretation(GDALColorInterp /*eColorInterp*/)
    3014             : 
    3015             : {
    3016           3 :     if (!(GetMOFlags() & GMO_IGNORE_UNIMPLEMENTED))
    3017           3 :         ReportError(CE_Failure, CPLE_NotSupported,
    3018             :                     "SetColorInterpretation() not supported for this dataset.");
    3019           3 :     return CE_Failure;
    3020             : }
    3021             : 
    3022             : /************************************************************************/
    3023             : /*                  GDALSetRasterColorInterpretation()                  */
    3024             : /************************************************************************/
    3025             : 
    3026             : /**
    3027             :  * \brief Set color interpretation of a band.
    3028             :  *
    3029             :  * @see GDALRasterBand::SetColorInterpretation()
    3030             :  */
    3031             : 
    3032        1755 : CPLErr CPL_STDCALL GDALSetRasterColorInterpretation(
    3033             :     GDALRasterBandH hBand, GDALColorInterp eColorInterp)
    3034             : 
    3035             : {
    3036        1755 :     VALIDATE_POINTER1(hBand, "GDALSetRasterColorInterpretation", CE_Failure);
    3037             : 
    3038        1755 :     GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
    3039        1755 :     return poBand->SetColorInterpretation(eColorInterp);
    3040             : }
    3041             : 
    3042             : /************************************************************************/
    3043             : /*                           GetColorTable()                            */
    3044             : /************************************************************************/
    3045             : 
    3046             : /**
    3047             :  * \brief Fetch the color table associated with band.
    3048             :  *
    3049             :  * If there is no associated color table, the return result is NULL.  The
    3050             :  * returned color table remains owned by the GDALRasterBand, and can't
    3051             :  * be depended on for long, nor should it ever be modified by the caller.
    3052             :  *
    3053             :  * This method is the same as the C function GDALGetRasterColorTable().
    3054             :  *
    3055             :  * @return internal color table, or NULL.
    3056             :  */
    3057             : 
    3058         212 : GDALColorTable *GDALRasterBand::GetColorTable()
    3059             : 
    3060             : {
    3061         212 :     return nullptr;
    3062             : }
    3063             : 
    3064             : /************************************************************************/
    3065             : /*                      GDALGetRasterColorTable()                       */
    3066             : /************************************************************************/
    3067             : 
    3068             : /**
    3069             :  * \brief Fetch the color table associated with band.
    3070             :  *
    3071             :  * @see GDALRasterBand::GetColorTable()
    3072             :  */
    3073             : 
    3074        1791 : GDALColorTableH CPL_STDCALL GDALGetRasterColorTable(GDALRasterBandH hBand)
    3075             : 
    3076             : {
    3077        1791 :     VALIDATE_POINTER1(hBand, "GDALGetRasterColorTable", nullptr);
    3078             : 
    3079        1791 :     GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
    3080        1791 :     return GDALColorTable::ToHandle(poBand->GetColorTable());
    3081             : }
    3082             : 
    3083             : /************************************************************************/
    3084             : /*                           SetColorTable()                            */
    3085             : /************************************************************************/
    3086             : 
    3087             : /**
    3088             :  * \fn GDALRasterBand::SetColorTable(GDALColorTable*)
    3089             :  * \brief Set the raster color table.
    3090             :  *
    3091             :  * The driver will make a copy of all desired data in the colortable.  It
    3092             :  * remains owned by the caller after the call.
    3093             :  *
    3094             :  * This method is the same as the C function GDALSetRasterColorTable().
    3095             :  *
    3096             :  * @param poCT the color table to apply.  This may be NULL to clear the color
    3097             :  * table (where supported).
    3098             :  *
    3099             :  * @return CE_None on success, or CE_Failure on failure.  If the action is
    3100             :  * unsupported by the driver, a value of CE_Failure is returned, but no
    3101             :  * error is issued.
    3102             :  */
    3103             : 
    3104             : /**/
    3105             : /**/
    3106             : 
    3107           0 : CPLErr GDALRasterBand::SetColorTable(GDALColorTable * /*poCT*/)
    3108             : 
    3109             : {
    3110           0 :     if (!(GetMOFlags() & GMO_IGNORE_UNIMPLEMENTED))
    3111           0 :         ReportError(CE_Failure, CPLE_NotSupported,
    3112             :                     "SetColorTable() not supported for this dataset.");
    3113           0 :     return CE_Failure;
    3114             : }
    3115             : 
    3116             : /************************************************************************/
    3117             : /*                      GDALSetRasterColorTable()                       */
    3118             : /************************************************************************/
    3119             : 
    3120             : /**
    3121             :  * \brief Set the raster color table.
    3122             :  *
    3123             :  * @see GDALRasterBand::SetColorTable()
    3124             :  */
    3125             : 
    3126          76 : CPLErr CPL_STDCALL GDALSetRasterColorTable(GDALRasterBandH hBand,
    3127             :                                            GDALColorTableH hCT)
    3128             : 
    3129             : {
    3130          76 :     VALIDATE_POINTER1(hBand, "GDALSetRasterColorTable", CE_Failure);
    3131             : 
    3132          76 :     GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
    3133          76 :     return poBand->SetColorTable(GDALColorTable::FromHandle(hCT));
    3134             : }
    3135             : 
    3136             : /************************************************************************/
    3137             : /*                       HasArbitraryOverviews()                        */
    3138             : /************************************************************************/
    3139             : 
    3140             : /**
    3141             :  * \brief Check for arbitrary overviews.
    3142             :  *
    3143             :  * This returns TRUE if the underlying datastore can compute arbitrary
    3144             :  * overviews efficiently, such as is the case with OGDI over a network.
    3145             :  * Datastores with arbitrary overviews don't generally have any fixed
    3146             :  * overviews, but the RasterIO() method can be used in downsampling mode
    3147             :  * to get overview data efficiently.
    3148             :  *
    3149             :  * This method is the same as the C function GDALHasArbitraryOverviews(),
    3150             :  *
    3151             :  * @return TRUE if arbitrary overviews available (efficiently), otherwise
    3152             :  * FALSE.
    3153             :  */
    3154             : 
    3155         216 : int GDALRasterBand::HasArbitraryOverviews()
    3156             : 
    3157             : {
    3158         216 :     return FALSE;
    3159             : }
    3160             : 
    3161             : /************************************************************************/
    3162             : /*                     GDALHasArbitraryOverviews()                      */
    3163             : /************************************************************************/
    3164             : 
    3165             : /**
    3166             :  * \brief Check for arbitrary overviews.
    3167             :  *
    3168             :  * @see GDALRasterBand::HasArbitraryOverviews()
    3169             :  */
    3170             : 
    3171         151 : int CPL_STDCALL GDALHasArbitraryOverviews(GDALRasterBandH hBand)
    3172             : 
    3173             : {
    3174         151 :     VALIDATE_POINTER1(hBand, "GDALHasArbitraryOverviews", 0);
    3175             : 
    3176         151 :     GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
    3177         151 :     return poBand->HasArbitraryOverviews();
    3178             : }
    3179             : 
    3180             : /************************************************************************/
    3181             : /*                          GetOverviewCount()                          */
    3182             : /************************************************************************/
    3183             : 
    3184             : /**
    3185             :  * \brief Return the number of overview layers available.
    3186             :  *
    3187             :  * This method is the same as the C function GDALGetOverviewCount().
    3188             :  *
    3189             :  * @return overview count, zero if none.
    3190             :  */
    3191             : 
    3192      660127 : int GDALRasterBand::GetOverviewCount()
    3193             : 
    3194             : {
    3195     1315410 :     if (poDS != nullptr && poDS->oOvManager.IsInitialized() &&
    3196      655284 :         poDS->AreOverviewsEnabled())
    3197      655284 :         return poDS->oOvManager.GetOverviewCount(nBand);
    3198             : 
    3199        4843 :     return 0;
    3200             : }
    3201             : 
    3202             : /************************************************************************/
    3203             : /*                        GDALGetOverviewCount()                        */
    3204             : /************************************************************************/
    3205             : 
    3206             : /**
    3207             :  * \brief Return the number of overview layers available.
    3208             :  *
    3209             :  * @see GDALRasterBand::GetOverviewCount()
    3210             :  */
    3211             : 
    3212        3140 : int CPL_STDCALL GDALGetOverviewCount(GDALRasterBandH hBand)
    3213             : 
    3214             : {
    3215        3140 :     VALIDATE_POINTER1(hBand, "GDALGetOverviewCount", 0);
    3216             : 
    3217        3140 :     GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
    3218        3140 :     return poBand->GetOverviewCount();
    3219             : }
    3220             : 
    3221             : /************************************************************************/
    3222             : /*                            GetOverview()                             */
    3223             : /************************************************************************/
    3224             : 
    3225             : /**
    3226             :  * \brief Fetch overview raster band object.
    3227             :  *
    3228             :  * This method is the same as the C function GDALGetOverview().
    3229             :  *
    3230             :  * @param i overview index between 0 and GetOverviewCount()-1.
    3231             :  *
    3232             :  * @return overview GDALRasterBand.
    3233             :  */
    3234             : 
    3235         789 : GDALRasterBand *GDALRasterBand::GetOverview(int i)
    3236             : 
    3237             : {
    3238        1523 :     if (poDS != nullptr && poDS->oOvManager.IsInitialized() &&
    3239         734 :         poDS->AreOverviewsEnabled())
    3240         734 :         return poDS->oOvManager.GetOverview(nBand, i);
    3241             : 
    3242          55 :     return nullptr;
    3243             : }
    3244             : 
    3245             : /************************************************************************/
    3246             : /*                          GDALGetOverview()                           */
    3247             : /************************************************************************/
    3248             : 
    3249             : /**
    3250             :  * \brief Fetch overview raster band object.
    3251             :  *
    3252             :  * @see GDALRasterBand::GetOverview()
    3253             :  */
    3254             : 
    3255        5472 : GDALRasterBandH CPL_STDCALL GDALGetOverview(GDALRasterBandH hBand, int i)
    3256             : 
    3257             : {
    3258        5472 :     VALIDATE_POINTER1(hBand, "GDALGetOverview", nullptr);
    3259             : 
    3260        5472 :     GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
    3261        5472 :     return GDALRasterBand::ToHandle(poBand->GetOverview(i));
    3262             : }
    3263             : 
    3264             : /************************************************************************/
    3265             : /*                      GetRasterSampleOverview()                       */
    3266             : /************************************************************************/
    3267             : 
    3268             : /**
    3269             :  * \brief Fetch best sampling overview.
    3270             :  *
    3271             :  * Returns the most reduced overview of the given band that still satisfies
    3272             :  * the desired number of samples.  This function can be used with zero
    3273             :  * as the number of desired samples to fetch the most reduced overview.
    3274             :  * The same band as was passed in will be returned if it has not overviews,
    3275             :  * or if none of the overviews have enough samples.
    3276             :  *
    3277             :  * This method is the same as the C functions GDALGetRasterSampleOverview()
    3278             :  * and GDALGetRasterSampleOverviewEx().
    3279             :  *
    3280             :  * @param nDesiredSamples the returned band will have at least this many
    3281             :  * pixels.
    3282             :  *
    3283             :  * @return optimal overview or the band itself.
    3284             :  */
    3285             : 
    3286             : GDALRasterBand *
    3287        2006 : GDALRasterBand::GetRasterSampleOverview(GUIntBig nDesiredSamples)
    3288             : 
    3289             : {
    3290        2006 :     GDALRasterBand *poBestBand = this;
    3291             : 
    3292        2006 :     double dfBestSamples = GetXSize() * static_cast<double>(GetYSize());
    3293             : 
    3294        4023 :     for (int iOverview = 0; iOverview < GetOverviewCount(); iOverview++)
    3295             :     {
    3296        2017 :         GDALRasterBand *poOBand = GetOverview(iOverview);
    3297             : 
    3298        2017 :         if (poOBand == nullptr)
    3299           0 :             continue;
    3300             : 
    3301             :         const double dfOSamples =
    3302        2017 :             poOBand->GetXSize() * static_cast<double>(poOBand->GetYSize());
    3303             : 
    3304        2017 :         if (dfOSamples < dfBestSamples && dfOSamples > nDesiredSamples)
    3305             :         {
    3306        2014 :             dfBestSamples = dfOSamples;
    3307        2014 :             poBestBand = poOBand;
    3308             :         }
    3309             :     }
    3310             : 
    3311        2006 :     return poBestBand;
    3312             : }
    3313             : 
    3314             : /************************************************************************/
    3315             : /*                    GDALGetRasterSampleOverview()                     */
    3316             : /************************************************************************/
    3317             : 
    3318             : /**
    3319             :  * \brief Fetch best sampling overview.
    3320             :  *
    3321             :  * Use GDALGetRasterSampleOverviewEx() to be able to specify more than 2
    3322             :  * billion samples.
    3323             :  *
    3324             :  * @see GDALRasterBand::GetRasterSampleOverview()
    3325             :  * @see GDALGetRasterSampleOverviewEx()
    3326             :  */
    3327             : 
    3328        2000 : GDALRasterBandH CPL_STDCALL GDALGetRasterSampleOverview(GDALRasterBandH hBand,
    3329             :                                                         int nDesiredSamples)
    3330             : 
    3331             : {
    3332        2000 :     VALIDATE_POINTER1(hBand, "GDALGetRasterSampleOverview", nullptr);
    3333             : 
    3334        2000 :     GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
    3335        2000 :     return GDALRasterBand::ToHandle(poBand->GetRasterSampleOverview(
    3336        4000 :         nDesiredSamples < 0 ? 0 : static_cast<GUIntBig>(nDesiredSamples)));
    3337             : }
    3338             : 
    3339             : /************************************************************************/
    3340             : /*                    GDALGetRasterSampleOverviewEx()                   */
    3341             : /************************************************************************/
    3342             : 
    3343             : /**
    3344             :  * \brief Fetch best sampling overview.
    3345             :  *
    3346             :  * @see GDALRasterBand::GetRasterSampleOverview()
    3347             :  * @since GDAL 2.0
    3348             :  */
    3349             : 
    3350             : GDALRasterBandH CPL_STDCALL
    3351           0 : GDALGetRasterSampleOverviewEx(GDALRasterBandH hBand, GUIntBig nDesiredSamples)
    3352             : 
    3353             : {
    3354           0 :     VALIDATE_POINTER1(hBand, "GDALGetRasterSampleOverviewEx", nullptr);
    3355             : 
    3356           0 :     GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
    3357           0 :     return GDALRasterBand::ToHandle(
    3358           0 :         poBand->GetRasterSampleOverview(nDesiredSamples));
    3359             : }
    3360             : 
    3361             : /************************************************************************/
    3362             : /*                           BuildOverviews()                           */
    3363             : /************************************************************************/
    3364             : 
    3365             : /**
    3366             :  * \fn GDALRasterBand::BuildOverviews(const char*, int, const int*,
    3367             :  * GDALProgressFunc, void*) \brief Build raster overview(s)
    3368             :  *
    3369             :  * If the operation is unsupported for the indicated dataset, then
    3370             :  * CE_Failure is returned, and CPLGetLastErrorNo() will return
    3371             :  * CPLE_NotSupported.
    3372             :  *
    3373             :  * WARNING: Most formats don't support per-band overview computation, but
    3374             :  * require that overviews are computed for all bands of a dataset, using
    3375             :  * GDALDataset::BuildOverviews(). The only exception for official GDAL drivers
    3376             :  * is the HFA driver which supports this method.
    3377             :  *
    3378             :  * @param pszResampling one of "NEAREST", "GAUSS", "CUBIC", "AVERAGE", "MODE",
    3379             :  * "AVERAGE_MAGPHASE" "RMS" or "NONE" controlling the downsampling method
    3380             :  * applied.
    3381             :  * @param nOverviews number of overviews to build.
    3382             :  * @param panOverviewList the list of overview decimation factors to build.
    3383             :  * @param pfnProgress a function to call to report progress, or NULL.
    3384             :  * @param pProgressData application data to pass to the progress function.
    3385             :  * @param papszOptions (GDAL >= 3.6) NULL terminated list of options as
    3386             :  *                     key=value pairs, or NULL
    3387             :  *
    3388             :  * @return CE_None on success or CE_Failure if the operation doesn't work.
    3389             :  */
    3390             : 
    3391             : /**/
    3392             : /**/
    3393             : 
    3394           0 : CPLErr GDALRasterBand::BuildOverviews(const char * /*pszResampling*/,
    3395             :                                       int /*nOverviews*/,
    3396             :                                       const int * /*panOverviewList*/,
    3397             :                                       GDALProgressFunc /*pfnProgress*/,
    3398             :                                       void * /*pProgressData*/,
    3399             :                                       CSLConstList /* papszOptions */)
    3400             : 
    3401             : {
    3402           0 :     ReportError(CE_Failure, CPLE_NotSupported,
    3403             :                 "BuildOverviews() not supported for this dataset.");
    3404             : 
    3405           0 :     return (CE_Failure);
    3406             : }
    3407             : 
    3408             : /************************************************************************/
    3409             : /*                             GetOffset()                              */
    3410             : /************************************************************************/
    3411             : 
    3412             : /**
    3413             :  * \brief Fetch the raster value offset.
    3414             :  *
    3415             :  * This value (in combination with the GetScale() value) can be used to
    3416             :  * transform raw pixel values into the units returned by GetUnitType().
    3417             :  * For example this might be used to store elevations in GUInt16 bands
    3418             :  * with a precision of 0.1, and starting from -100.
    3419             :  *
    3420             :  * Units value = (raw value * scale) + offset
    3421             :  *
    3422             :  * Note that applying scale and offset is of the responsibility of the user,
    3423             :  * and is not done by methods such as RasterIO() or ReadBlock().
    3424             :  *
    3425             :  * For file formats that don't know this intrinsically a value of zero
    3426             :  * is returned.
    3427             :  *
    3428             :  * This method is the same as the C function GDALGetRasterOffset().
    3429             :  *
    3430             :  * @param pbSuccess pointer to a boolean to use to indicate if the
    3431             :  * returned value is meaningful or not.  May be NULL (default).
    3432             :  *
    3433             :  * @return the raster offset.
    3434             :  */
    3435             : 
    3436         389 : double GDALRasterBand::GetOffset(int *pbSuccess)
    3437             : 
    3438             : {
    3439         389 :     if (pbSuccess != nullptr)
    3440         321 :         *pbSuccess = FALSE;
    3441             : 
    3442         389 :     return 0.0;
    3443             : }
    3444             : 
    3445             : /************************************************************************/
    3446             : /*                        GDALGetRasterOffset()                         */
    3447             : /************************************************************************/
    3448             : 
    3449             : /**
    3450             :  * \brief Fetch the raster value offset.
    3451             :  *
    3452             :  * @see GDALRasterBand::GetOffset()
    3453             :  */
    3454             : 
    3455         299 : double CPL_STDCALL GDALGetRasterOffset(GDALRasterBandH hBand, int *pbSuccess)
    3456             : 
    3457             : {
    3458         299 :     VALIDATE_POINTER1(hBand, "GDALGetRasterOffset", 0);
    3459             : 
    3460         299 :     GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
    3461         299 :     return poBand->GetOffset(pbSuccess);
    3462             : }
    3463             : 
    3464             : /************************************************************************/
    3465             : /*                             SetOffset()                              */
    3466             : /************************************************************************/
    3467             : 
    3468             : /**
    3469             :  * \fn GDALRasterBand::SetOffset(double)
    3470             :  * \brief Set scaling offset.
    3471             :  *
    3472             :  * Very few formats implement this method.   When not implemented it will
    3473             :  * issue a CPLE_NotSupported error and return CE_Failure.
    3474             :  *
    3475             :  * This method is the same as the C function GDALSetRasterOffset().
    3476             :  *
    3477             :  * @param dfNewOffset the new offset.
    3478             :  *
    3479             :  * @return CE_None or success or CE_Failure on failure.
    3480             :  */
    3481             : 
    3482             : /**/
    3483             : /**/
    3484             : 
    3485           0 : CPLErr GDALRasterBand::SetOffset(double /*dfNewOffset*/)
    3486             : {
    3487           0 :     if (!(GetMOFlags() & GMO_IGNORE_UNIMPLEMENTED))
    3488           0 :         ReportError(CE_Failure, CPLE_NotSupported,
    3489             :                     "SetOffset() not supported on this raster band.");
    3490             : 
    3491           0 :     return CE_Failure;
    3492             : }
    3493             : 
    3494             : /************************************************************************/
    3495             : /*                        GDALSetRasterOffset()                         */
    3496             : /************************************************************************/
    3497             : 
    3498             : /**
    3499             :  * \brief Set scaling offset.
    3500             :  *
    3501             :  * @see GDALRasterBand::SetOffset()
    3502             :  */
    3503             : 
    3504          41 : CPLErr CPL_STDCALL GDALSetRasterOffset(GDALRasterBandH hBand,
    3505             :                                        double dfNewOffset)
    3506             : 
    3507             : {
    3508          41 :     VALIDATE_POINTER1(hBand, "GDALSetRasterOffset", CE_Failure);
    3509             : 
    3510          41 :     GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
    3511          41 :     return poBand->SetOffset(dfNewOffset);
    3512             : }
    3513             : 
    3514             : /************************************************************************/
    3515             : /*                              GetScale()                              */
    3516             : /************************************************************************/
    3517             : 
    3518             : /**
    3519             :  * \brief Fetch the raster value scale.
    3520             :  *
    3521             :  * This value (in combination with the GetOffset() value) can be used to
    3522             :  * transform raw pixel values into the units returned by GetUnitType().
    3523             :  * For example this might be used to store elevations in GUInt16 bands
    3524             :  * with a precision of 0.1, and starting from -100.
    3525             :  *
    3526             :  * Units value = (raw value * scale) + offset
    3527             :  *
    3528             :  * Note that applying scale and offset is of the responsibility of the user,
    3529             :  * and is not done by methods such as RasterIO() or ReadBlock().
    3530             :  *
    3531             :  * For file formats that don't know this intrinsically a value of one
    3532             :  * is returned.
    3533             :  *
    3534             :  * This method is the same as the C function GDALGetRasterScale().
    3535             :  *
    3536             :  * @param pbSuccess pointer to a boolean to use to indicate if the
    3537             :  * returned value is meaningful or not.  May be NULL (default).
    3538             :  *
    3539             :  * @return the raster scale.
    3540             :  */
    3541             : 
    3542         389 : double GDALRasterBand::GetScale(int *pbSuccess)
    3543             : 
    3544             : {
    3545         389 :     if (pbSuccess != nullptr)
    3546         321 :         *pbSuccess = FALSE;
    3547             : 
    3548         389 :     return 1.0;
    3549             : }
    3550             : 
    3551             : /************************************************************************/
    3552             : /*                         GDALGetRasterScale()                         */
    3553             : /************************************************************************/
    3554             : 
    3555             : /**
    3556             :  * \brief Fetch the raster value scale.
    3557             :  *
    3558             :  * @see GDALRasterBand::GetScale()
    3559             :  */
    3560             : 
    3561         297 : double CPL_STDCALL GDALGetRasterScale(GDALRasterBandH hBand, int *pbSuccess)
    3562             : 
    3563             : {
    3564         297 :     VALIDATE_POINTER1(hBand, "GDALGetRasterScale", 0);
    3565             : 
    3566         297 :     GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
    3567         297 :     return poBand->GetScale(pbSuccess);
    3568             : }
    3569             : 
    3570             : /************************************************************************/
    3571             : /*                              SetScale()                              */
    3572             : /************************************************************************/
    3573             : 
    3574             : /**
    3575             :  * \fn GDALRasterBand::SetScale(double)
    3576             :  * \brief Set scaling ratio.
    3577             :  *
    3578             :  * Very few formats implement this method.   When not implemented it will
    3579             :  * issue a CPLE_NotSupported error and return CE_Failure.
    3580             :  *
    3581             :  * This method is the same as the C function GDALSetRasterScale().
    3582             :  *
    3583             :  * @param dfNewScale the new scale.
    3584             :  *
    3585             :  * @return CE_None or success or CE_Failure on failure.
    3586             :  */
    3587             : 
    3588             : /**/
    3589             : /**/
    3590             : 
    3591           0 : CPLErr GDALRasterBand::SetScale(double /*dfNewScale*/)
    3592             : 
    3593             : {
    3594           0 :     if (!(GetMOFlags() & GMO_IGNORE_UNIMPLEMENTED))
    3595           0 :         ReportError(CE_Failure, CPLE_NotSupported,
    3596             :                     "SetScale() not supported on this raster band.");
    3597             : 
    3598           0 :     return CE_Failure;
    3599             : }
    3600             : 
    3601             : /************************************************************************/
    3602             : /*                        GDALSetRasterScale()                          */
    3603             : /************************************************************************/
    3604             : 
    3605             : /**
    3606             :  * \brief Set scaling ratio.
    3607             :  *
    3608             :  * @see GDALRasterBand::SetScale()
    3609             :  */
    3610             : 
    3611          42 : CPLErr CPL_STDCALL GDALSetRasterScale(GDALRasterBandH hBand, double dfNewOffset)
    3612             : 
    3613             : {
    3614          42 :     VALIDATE_POINTER1(hBand, "GDALSetRasterScale", CE_Failure);
    3615             : 
    3616          42 :     GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
    3617          42 :     return poBand->SetScale(dfNewOffset);
    3618             : }
    3619             : 
    3620             : /************************************************************************/
    3621             : /*                            GetUnitType()                             */
    3622             : /************************************************************************/
    3623             : 
    3624             : /**
    3625             :  * \brief Return raster unit type.
    3626             :  *
    3627             :  * Return a name for the units of this raster's values.  For instance, it
    3628             :  * might be "m" for an elevation model in meters, or "ft" for feet.  If no
    3629             :  * units are available, a value of "" will be returned.  The returned string
    3630             :  * should not be modified, nor freed by the calling application.
    3631             :  *
    3632             :  * This method is the same as the C function GDALGetRasterUnitType().
    3633             :  *
    3634             :  * @return unit name string.
    3635             :  */
    3636             : 
    3637         155 : const char *GDALRasterBand::GetUnitType()
    3638             : 
    3639             : {
    3640         155 :     return "";
    3641             : }
    3642             : 
    3643             : /************************************************************************/
    3644             : /*                       GDALGetRasterUnitType()                        */
    3645             : /************************************************************************/
    3646             : 
    3647             : /**
    3648             :  * \brief Return raster unit type.
    3649             :  *
    3650             :  * @see GDALRasterBand::GetUnitType()
    3651             :  */
    3652             : 
    3653        1284 : const char *CPL_STDCALL GDALGetRasterUnitType(GDALRasterBandH hBand)
    3654             : 
    3655             : {
    3656        1284 :     VALIDATE_POINTER1(hBand, "GDALGetRasterUnitType", nullptr);
    3657             : 
    3658        1284 :     GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
    3659        1284 :     return poBand->GetUnitType();
    3660             : }
    3661             : 
    3662             : /************************************************************************/
    3663             : /*                            SetUnitType()                             */
    3664             : /************************************************************************/
    3665             : 
    3666             : /**
    3667             :  * \fn GDALRasterBand::SetUnitType(const char*)
    3668             :  * \brief Set unit type.
    3669             :  *
    3670             :  * Set the unit type for a raster band.  Values should be one of
    3671             :  * "" (the default indicating it is unknown), "m" indicating meters,
    3672             :  * or "ft" indicating feet, though other nonstandard values are allowed.
    3673             :  *
    3674             :  * This method is the same as the C function GDALSetRasterUnitType().
    3675             :  *
    3676             :  * @param pszNewValue the new unit type value.
    3677             :  *
    3678             :  * @return CE_None on success or CE_Failure if not successful, or
    3679             :  * unsupported.
    3680             :  */
    3681             : 
    3682             : /**/
    3683             : /**/
    3684             : 
    3685           0 : CPLErr GDALRasterBand::SetUnitType(const char * /*pszNewValue*/)
    3686             : 
    3687             : {
    3688           0 :     if (!(GetMOFlags() & GMO_IGNORE_UNIMPLEMENTED))
    3689           0 :         ReportError(CE_Failure, CPLE_NotSupported,
    3690             :                     "SetUnitType() not supported on this raster band.");
    3691           0 :     return CE_Failure;
    3692             : }
    3693             : 
    3694             : /************************************************************************/
    3695             : /*                       GDALSetRasterUnitType()                        */
    3696             : /************************************************************************/
    3697             : 
    3698             : /**
    3699             :  * \brief Set unit type.
    3700             :  *
    3701             :  * @see GDALRasterBand::SetUnitType()
    3702             :  *
    3703             :  * @since GDAL 1.8.0
    3704             :  */
    3705             : 
    3706          60 : CPLErr CPL_STDCALL GDALSetRasterUnitType(GDALRasterBandH hBand,
    3707             :                                          const char *pszNewValue)
    3708             : 
    3709             : {
    3710          60 :     VALIDATE_POINTER1(hBand, "GDALSetRasterUnitType", CE_Failure);
    3711             : 
    3712          60 :     GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
    3713          60 :     return poBand->SetUnitType(pszNewValue);
    3714             : }
    3715             : 
    3716             : /************************************************************************/
    3717             : /*                              GetXSize()                              */
    3718             : /************************************************************************/
    3719             : 
    3720             : /**
    3721             :  * \brief Fetch XSize of raster.
    3722             :  *
    3723             :  * This method is the same as the C function GDALGetRasterBandXSize().
    3724             :  *
    3725             :  * @return the width in pixels of this band.
    3726             :  */
    3727             : 
    3728     6677230 : int GDALRasterBand::GetXSize() const
    3729             : 
    3730             : {
    3731     6677230 :     return nRasterXSize;
    3732             : }
    3733             : 
    3734             : /************************************************************************/
    3735             : /*                       GDALGetRasterBandXSize()                       */
    3736             : /************************************************************************/
    3737             : 
    3738             : /**
    3739             :  * \brief Fetch XSize of raster.
    3740             :  *
    3741             :  * @see GDALRasterBand::GetXSize()
    3742             :  */
    3743             : 
    3744       51913 : int CPL_STDCALL GDALGetRasterBandXSize(GDALRasterBandH hBand)
    3745             : 
    3746             : {
    3747       51913 :     VALIDATE_POINTER1(hBand, "GDALGetRasterBandXSize", 0);
    3748             : 
    3749       51913 :     GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
    3750       51913 :     return poBand->GetXSize();
    3751             : }
    3752             : 
    3753             : /************************************************************************/
    3754             : /*                              GetYSize()                              */
    3755             : /************************************************************************/
    3756             : 
    3757             : /**
    3758             :  * \brief Fetch YSize of raster.
    3759             :  *
    3760             :  * This method is the same as the C function GDALGetRasterBandYSize().
    3761             :  *
    3762             :  * @return the height in pixels of this band.
    3763             :  */
    3764             : 
    3765     3231310 : int GDALRasterBand::GetYSize() const
    3766             : 
    3767             : {
    3768     3231310 :     return nRasterYSize;
    3769             : }
    3770             : 
    3771             : /************************************************************************/
    3772             : /*                       GDALGetRasterBandYSize()                       */
    3773             : /************************************************************************/
    3774             : 
    3775             : /**
    3776             :  * \brief Fetch YSize of raster.
    3777             :  *
    3778             :  * @see GDALRasterBand::GetYSize()
    3779             :  */
    3780             : 
    3781       51290 : int CPL_STDCALL GDALGetRasterBandYSize(GDALRasterBandH hBand)
    3782             : 
    3783             : {
    3784       51290 :     VALIDATE_POINTER1(hBand, "GDALGetRasterBandYSize", 0);
    3785             : 
    3786       51290 :     GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
    3787       51290 :     return poBand->GetYSize();
    3788             : }
    3789             : 
    3790             : /************************************************************************/
    3791             : /*                              GetBand()                               */
    3792             : /************************************************************************/
    3793             : 
    3794             : /**
    3795             :  * \brief Fetch the band number.
    3796             :  *
    3797             :  * This method returns the band that this GDALRasterBand objects represents
    3798             :  * within its dataset.  This method may return a value of 0 to indicate
    3799             :  * GDALRasterBand objects without an apparently relationship to a dataset,
    3800             :  * such as GDALRasterBands serving as overviews.
    3801             :  *
    3802             :  * This method is the same as the C function GDALGetBandNumber().
    3803             :  *
    3804             :  * @return band number (1+) or 0 if the band number isn't known.
    3805             :  */
    3806             : 
    3807       19101 : int GDALRasterBand::GetBand() const
    3808             : 
    3809             : {
    3810       19101 :     return nBand;
    3811             : }
    3812             : 
    3813             : /************************************************************************/
    3814             : /*                         GDALGetBandNumber()                          */
    3815             : /************************************************************************/
    3816             : 
    3817             : /**
    3818             :  * \brief Fetch the band number.
    3819             :  *
    3820             :  * @see GDALRasterBand::GetBand()
    3821             :  */
    3822             : 
    3823         147 : int CPL_STDCALL GDALGetBandNumber(GDALRasterBandH hBand)
    3824             : 
    3825             : {
    3826         147 :     VALIDATE_POINTER1(hBand, "GDALGetBandNumber", 0);
    3827             : 
    3828         147 :     GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
    3829         147 :     return poBand->GetBand();
    3830             : }
    3831             : 
    3832             : /************************************************************************/
    3833             : /*                             GetDataset()                             */
    3834             : /************************************************************************/
    3835             : 
    3836             : /**
    3837             :  * \brief Fetch the owning dataset handle.
    3838             :  *
    3839             :  * Note that some GDALRasterBands are not considered to be a part of a dataset,
    3840             :  * such as overviews or other "freestanding" bands.
    3841             :  *
    3842             :  * This method is the same as the C function GDALGetBandDataset().
    3843             :  *
    3844             :  * @return the pointer to the GDALDataset to which this band belongs, or
    3845             :  * NULL if this cannot be determined.
    3846             :  */
    3847             : 
    3848     3792690 : GDALDataset *GDALRasterBand::GetDataset() const
    3849             : 
    3850             : {
    3851     3792690 :     return poDS;
    3852             : }
    3853             : 
    3854             : /************************************************************************/
    3855             : /*                         GDALGetBandDataset()                         */
    3856             : /************************************************************************/
    3857             : 
    3858             : /**
    3859             :  * \brief Fetch the owning dataset handle.
    3860             :  *
    3861             :  * @see GDALRasterBand::GetDataset()
    3862             :  */
    3863             : 
    3864         300 : GDALDatasetH CPL_STDCALL GDALGetBandDataset(GDALRasterBandH hBand)
    3865             : 
    3866             : {
    3867         300 :     VALIDATE_POINTER1(hBand, "GDALGetBandDataset", nullptr);
    3868             : 
    3869         300 :     GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
    3870         300 :     return GDALDataset::ToHandle(poBand->GetDataset());
    3871             : }
    3872             : 
    3873             : /************************************************************************/
    3874             : /*                        ComputeFloatNoDataValue()                     */
    3875             : /************************************************************************/
    3876             : 
    3877        2017 : static inline void ComputeFloatNoDataValue(GDALDataType eDataType,
    3878             :                                            double dfNoDataValue,
    3879             :                                            int &bGotNoDataValue,
    3880             :                                            float &fNoDataValue,
    3881             :                                            bool &bGotFloatNoDataValue)
    3882             : {
    3883        2017 :     if (eDataType == GDT_Float32 && bGotNoDataValue)
    3884             :     {
    3885          81 :         dfNoDataValue = GDALAdjustNoDataCloseToFloatMax(dfNoDataValue);
    3886          81 :         if (GDALIsValueInRange<float>(dfNoDataValue))
    3887             :         {
    3888          81 :             fNoDataValue = static_cast<float>(dfNoDataValue);
    3889          81 :             bGotFloatNoDataValue = true;
    3890          81 :             bGotNoDataValue = false;
    3891             :         }
    3892             :     }
    3893        2017 : }
    3894             : 
    3895             : /************************************************************************/
    3896             : /*                            GetHistogram()                            */
    3897             : /************************************************************************/
    3898             : 
    3899             : /**
    3900             :  * \brief Compute raster histogram.
    3901             :  *
    3902             :  * Note that the bucket size is (dfMax-dfMin) / nBuckets.
    3903             :  *
    3904             :  * For example to compute a simple 256 entry histogram of eight bit data,
    3905             :  * the following would be suitable.  The unusual bounds are to ensure that
    3906             :  * bucket boundaries don't fall right on integer values causing possible errors
    3907             :  * due to rounding after scaling.
    3908             : \code{.cpp}
    3909             :     GUIntBig anHistogram[256];
    3910             : 
    3911             :     poBand->GetHistogram( -0.5, 255.5, 256, anHistogram, FALSE, FALSE,
    3912             :                           GDALDummyProgress, nullptr );
    3913             : \endcode
    3914             :  *
    3915             :  * Note that setting bApproxOK will generally result in a subsampling of the
    3916             :  * file, and will utilize overviews if available.  It should generally
    3917             :  * produce a representative histogram for the data that is suitable for use
    3918             :  * in generating histogram based luts for instance.  Generally bApproxOK is
    3919             :  * much faster than an exactly computed histogram.
    3920             :  *
    3921             :  * This method is the same as the C functions GDALGetRasterHistogram() and
    3922             :  * GDALGetRasterHistogramEx().
    3923             :  *
    3924             :  * @param dfMin the lower bound of the histogram.
    3925             :  * @param dfMax the upper bound of the histogram.
    3926             :  * @param nBuckets the number of buckets in panHistogram.
    3927             :  * @param panHistogram array into which the histogram totals are placed.
    3928             :  * @param bIncludeOutOfRange if TRUE values below the histogram range will
    3929             :  * mapped into panHistogram[0], and values above will be mapped into
    3930             :  * panHistogram[nBuckets-1] otherwise out of range values are discarded.
    3931             :  * @param bApproxOK TRUE if an approximate, or incomplete histogram OK.
    3932             :  * @param pfnProgress function to report progress to completion.
    3933             :  * @param pProgressData application data to pass to pfnProgress.
    3934             :  *
    3935             :  * @return CE_None on success, or CE_Failure if something goes wrong.
    3936             :  */
    3937             : 
    3938          38 : CPLErr GDALRasterBand::GetHistogram(double dfMin, double dfMax, int nBuckets,
    3939             :                                     GUIntBig *panHistogram,
    3940             :                                     int bIncludeOutOfRange, int bApproxOK,
    3941             :                                     GDALProgressFunc pfnProgress,
    3942             :                                     void *pProgressData)
    3943             : 
    3944             : {
    3945          38 :     CPLAssert(nullptr != panHistogram);
    3946             : 
    3947          38 :     if (pfnProgress == nullptr)
    3948          26 :         pfnProgress = GDALDummyProgress;
    3949             : 
    3950             :     /* -------------------------------------------------------------------- */
    3951             :     /*      If we have overviews, use them for the histogram.               */
    3952             :     /* -------------------------------------------------------------------- */
    3953          38 :     if (bApproxOK && GetOverviewCount() > 0 && !HasArbitraryOverviews())
    3954             :     {
    3955             :         // FIXME: should we use the most reduced overview here or use some
    3956             :         // minimum number of samples like GDALRasterBand::ComputeStatistics()
    3957             :         // does?
    3958           0 :         GDALRasterBand *poBestOverview = GetRasterSampleOverview(0);
    3959             : 
    3960           0 :         if (poBestOverview != this)
    3961             :         {
    3962           0 :             return poBestOverview->GetHistogram(
    3963             :                 dfMin, dfMax, nBuckets, panHistogram, bIncludeOutOfRange,
    3964           0 :                 bApproxOK, pfnProgress, pProgressData);
    3965             :         }
    3966             :     }
    3967             : 
    3968             :     /* -------------------------------------------------------------------- */
    3969             :     /*      Read actual data and build histogram.                           */
    3970             :     /* -------------------------------------------------------------------- */
    3971          38 :     if (!pfnProgress(0.0, "Compute Histogram", pProgressData))
    3972             :     {
    3973           0 :         ReportError(CE_Failure, CPLE_UserInterrupt, "User terminated");
    3974           0 :         return CE_Failure;
    3975             :     }
    3976             : 
    3977             :     // Written this way to deal with NaN
    3978          38 :     if (!(dfMax > dfMin))
    3979             :     {
    3980           5 :         ReportError(CE_Failure, CPLE_IllegalArg,
    3981             :                     "dfMax should be strictly greater than dfMin");
    3982           5 :         return CE_Failure;
    3983             :     }
    3984             : 
    3985             :     GDALRasterIOExtraArg sExtraArg;
    3986          33 :     INIT_RASTERIO_EXTRA_ARG(sExtraArg);
    3987             : 
    3988          33 :     const double dfScale = nBuckets / (dfMax - dfMin);
    3989          33 :     if (dfScale == 0 || !std::isfinite(dfScale))
    3990             :     {
    3991           5 :         ReportError(CE_Failure, CPLE_IllegalArg,
    3992             :                     "dfMin and dfMax should be finite values such that "
    3993             :                     "nBuckets / (dfMax - dfMin) is non-zero");
    3994           5 :         return CE_Failure;
    3995             :     }
    3996          28 :     memset(panHistogram, 0, sizeof(GUIntBig) * nBuckets);
    3997             : 
    3998          28 :     int bGotNoDataValue = FALSE;
    3999          28 :     const double dfNoDataValue = GetNoDataValue(&bGotNoDataValue);
    4000          28 :     bGotNoDataValue = bGotNoDataValue && !std::isnan(dfNoDataValue);
    4001          28 :     bool bGotFloatNoDataValue = false;
    4002          28 :     float fNoDataValue = 0.0f;
    4003          28 :     ComputeFloatNoDataValue(eDataType, dfNoDataValue, bGotNoDataValue,
    4004             :                             fNoDataValue, bGotFloatNoDataValue);
    4005          28 :     GDALRasterBand *poMaskBand = nullptr;
    4006          28 :     if (!bGotNoDataValue)
    4007             :     {
    4008          27 :         const int l_nMaskFlags = GetMaskFlags();
    4009          28 :         if (l_nMaskFlags != GMF_ALL_VALID && l_nMaskFlags != GMF_NODATA &&
    4010           1 :             GetColorInterpretation() != GCI_AlphaBand)
    4011             :         {
    4012           1 :             poMaskBand = GetMaskBand();
    4013             :         }
    4014             :     }
    4015             : 
    4016          28 :     bool bSignedByte = false;
    4017          28 :     if (eDataType == GDT_Byte)
    4018             :     {
    4019          21 :         EnablePixelTypeSignedByteWarning(false);
    4020             :         const char *pszPixelType =
    4021          21 :             GetMetadataItem("PIXELTYPE", "IMAGE_STRUCTURE");
    4022          21 :         EnablePixelTypeSignedByteWarning(true);
    4023          21 :         bSignedByte =
    4024          21 :             pszPixelType != nullptr && EQUAL(pszPixelType, "SIGNEDBYTE");
    4025             :     }
    4026             : 
    4027          28 :     if (bApproxOK && HasArbitraryOverviews())
    4028             :     {
    4029             :         /* --------------------------------------------------------------------
    4030             :          */
    4031             :         /*      Figure out how much the image should be reduced to get an */
    4032             :         /*      approximate value. */
    4033             :         /* --------------------------------------------------------------------
    4034             :          */
    4035             :         const double dfReduction =
    4036           0 :             sqrt(static_cast<double>(nRasterXSize) * nRasterYSize /
    4037             :                  GDALSTAT_APPROX_NUMSAMPLES);
    4038             : 
    4039           0 :         int nXReduced = nRasterXSize;
    4040           0 :         int nYReduced = nRasterYSize;
    4041           0 :         if (dfReduction > 1.0)
    4042             :         {
    4043           0 :             nXReduced = static_cast<int>(nRasterXSize / dfReduction);
    4044           0 :             nYReduced = static_cast<int>(nRasterYSize / dfReduction);
    4045             : 
    4046             :             // Catch the case of huge resizing ratios here
    4047           0 :             if (nXReduced == 0)
    4048           0 :                 nXReduced = 1;
    4049           0 :             if (nYReduced == 0)
    4050           0 :                 nYReduced = 1;
    4051             :         }
    4052             : 
    4053           0 :         void *pData = VSI_MALLOC3_VERBOSE(GDALGetDataTypeSizeBytes(eDataType),
    4054             :                                           nXReduced, nYReduced);
    4055           0 :         if (!pData)
    4056           0 :             return CE_Failure;
    4057             : 
    4058             :         const CPLErr eErr =
    4059           0 :             IRasterIO(GF_Read, 0, 0, nRasterXSize, nRasterYSize, pData,
    4060           0 :                       nXReduced, nYReduced, eDataType, 0, 0, &sExtraArg);
    4061           0 :         if (eErr != CE_None)
    4062             :         {
    4063           0 :             CPLFree(pData);
    4064           0 :             return eErr;
    4065             :         }
    4066             : 
    4067           0 :         GByte *pabyMaskData = nullptr;
    4068           0 :         if (poMaskBand)
    4069             :         {
    4070             :             pabyMaskData =
    4071           0 :                 static_cast<GByte *>(VSI_MALLOC2_VERBOSE(nXReduced, nYReduced));
    4072           0 :             if (!pabyMaskData)
    4073             :             {
    4074           0 :                 CPLFree(pData);
    4075           0 :                 return CE_Failure;
    4076             :             }
    4077             : 
    4078           0 :             if (poMaskBand->RasterIO(GF_Read, 0, 0, nRasterXSize, nRasterYSize,
    4079             :                                      pabyMaskData, nXReduced, nYReduced,
    4080           0 :                                      GDT_Byte, 0, 0, nullptr) != CE_None)
    4081             :             {
    4082           0 :                 CPLFree(pData);
    4083           0 :                 CPLFree(pabyMaskData);
    4084           0 :                 return CE_Failure;
    4085             :             }
    4086             :         }
    4087             : 
    4088             :         // This isn't the fastest way to do this, but is easier for now.
    4089           0 :         for (int iY = 0; iY < nYReduced; iY++)
    4090             :         {
    4091           0 :             for (int iX = 0; iX < nXReduced; iX++)
    4092             :             {
    4093           0 :                 const int iOffset = iX + iY * nXReduced;
    4094           0 :                 double dfValue = 0.0;
    4095             : 
    4096           0 :                 if (pabyMaskData && pabyMaskData[iOffset] == 0)
    4097           0 :                     continue;
    4098             : 
    4099           0 :                 switch (eDataType)
    4100             :                 {
    4101           0 :                     case GDT_Byte:
    4102             :                     {
    4103           0 :                         if (bSignedByte)
    4104           0 :                             dfValue =
    4105           0 :                                 static_cast<signed char *>(pData)[iOffset];
    4106             :                         else
    4107           0 :                             dfValue = static_cast<GByte *>(pData)[iOffset];
    4108           0 :                         break;
    4109             :                     }
    4110           0 :                     case GDT_Int8:
    4111           0 :                         dfValue = static_cast<GInt8 *>(pData)[iOffset];
    4112           0 :                         break;
    4113           0 :                     case GDT_UInt16:
    4114           0 :                         dfValue = static_cast<GUInt16 *>(pData)[iOffset];
    4115           0 :                         break;
    4116           0 :                     case GDT_Int16:
    4117           0 :                         dfValue = static_cast<GInt16 *>(pData)[iOffset];
    4118           0 :                         break;
    4119           0 :                     case GDT_UInt32:
    4120           0 :                         dfValue = static_cast<GUInt32 *>(pData)[iOffset];
    4121           0 :                         break;
    4122           0 :                     case GDT_Int32:
    4123           0 :                         dfValue = static_cast<GInt32 *>(pData)[iOffset];
    4124           0 :                         break;
    4125           0 :                     case GDT_UInt64:
    4126           0 :                         dfValue = static_cast<double>(
    4127           0 :                             static_cast<GUInt64 *>(pData)[iOffset]);
    4128           0 :                         break;
    4129           0 :                     case GDT_Int64:
    4130           0 :                         dfValue = static_cast<double>(
    4131           0 :                             static_cast<GInt64 *>(pData)[iOffset]);
    4132           0 :                         break;
    4133           0 :                     case GDT_Float32:
    4134             :                     {
    4135           0 :                         const float fValue =
    4136           0 :                             static_cast<float *>(pData)[iOffset];
    4137           0 :                         if (std::isnan(fValue) ||
    4138           0 :                             (bGotFloatNoDataValue &&
    4139           0 :                              ARE_REAL_EQUAL(fValue, fNoDataValue)))
    4140           0 :                             continue;
    4141           0 :                         dfValue = fValue;
    4142           0 :                         break;
    4143             :                     }
    4144           0 :                     case GDT_Float64:
    4145           0 :                         dfValue = static_cast<double *>(pData)[iOffset];
    4146           0 :                         if (std::isnan(dfValue))
    4147           0 :                             continue;
    4148           0 :                         break;
    4149           0 :                     case GDT_CInt16:
    4150             :                     {
    4151           0 :                         const double dfReal =
    4152           0 :                             static_cast<GInt16 *>(pData)[iOffset * 2];
    4153           0 :                         const double dfImag =
    4154           0 :                             static_cast<GInt16 *>(pData)[iOffset * 2 + 1];
    4155           0 :                         if (std::isnan(dfReal) || std::isnan(dfImag))
    4156           0 :                             continue;
    4157           0 :                         dfValue = sqrt(dfReal * dfReal + dfImag * dfImag);
    4158             :                     }
    4159           0 :                     break;
    4160           0 :                     case GDT_CInt32:
    4161             :                     {
    4162           0 :                         const double dfReal =
    4163           0 :                             static_cast<GInt32 *>(pData)[iOffset * 2];
    4164           0 :                         const double dfImag =
    4165           0 :                             static_cast<GInt32 *>(pData)[iOffset * 2 + 1];
    4166           0 :                         if (std::isnan(dfReal) || std::isnan(dfImag))
    4167           0 :                             continue;
    4168           0 :                         dfValue = sqrt(dfReal * dfReal + dfImag * dfImag);
    4169             :                     }
    4170           0 :                     break;
    4171           0 :                     case GDT_CFloat32:
    4172             :                     {
    4173           0 :                         const double dfReal =
    4174           0 :                             static_cast<float *>(pData)[iOffset * 2];
    4175           0 :                         const double dfImag =
    4176           0 :                             static_cast<float *>(pData)[iOffset * 2 + 1];
    4177           0 :                         if (std::isnan(dfReal) || std::isnan(dfImag))
    4178           0 :                             continue;
    4179           0 :                         dfValue = sqrt(dfReal * dfReal + dfImag * dfImag);
    4180             :                     }
    4181           0 :                     break;
    4182           0 :                     case GDT_CFloat64:
    4183             :                     {
    4184           0 :                         const double dfReal =
    4185           0 :                             static_cast<double *>(pData)[iOffset * 2];
    4186           0 :                         const double dfImag =
    4187           0 :                             static_cast<double *>(pData)[iOffset * 2 + 1];
    4188           0 :                         if (std::isnan(dfReal) || std::isnan(dfImag))
    4189           0 :                             continue;
    4190           0 :                         dfValue = sqrt(dfReal * dfReal + dfImag * dfImag);
    4191             :                     }
    4192           0 :                     break;
    4193           0 :                     case GDT_Unknown:
    4194             :                     case GDT_TypeCount:
    4195           0 :                         CPLAssert(false);
    4196             :                 }
    4197             : 
    4198           0 :                 if (eDataType != GDT_Float32 && bGotNoDataValue &&
    4199           0 :                     ARE_REAL_EQUAL(dfValue, dfNoDataValue))
    4200           0 :                     continue;
    4201             : 
    4202             :                 // Given that dfValue and dfMin are not NaN, and dfScale > 0 and
    4203             :                 // finite, the result of the multiplication cannot be NaN
    4204           0 :                 const double dfIndex = floor((dfValue - dfMin) * dfScale);
    4205             : 
    4206           0 :                 if (dfIndex < 0)
    4207             :                 {
    4208           0 :                     if (bIncludeOutOfRange)
    4209           0 :                         panHistogram[0]++;
    4210             :                 }
    4211           0 :                 else if (dfIndex >= nBuckets)
    4212             :                 {
    4213           0 :                     if (bIncludeOutOfRange)
    4214           0 :                         ++panHistogram[nBuckets - 1];
    4215             :                 }
    4216             :                 else
    4217             :                 {
    4218           0 :                     ++panHistogram[static_cast<int>(dfIndex)];
    4219             :                 }
    4220             :             }
    4221             :         }
    4222             : 
    4223           0 :         CPLFree(pData);
    4224           0 :         CPLFree(pabyMaskData);
    4225             :     }
    4226             :     else  // No arbitrary overviews.
    4227             :     {
    4228          28 :         if (!InitBlockInfo())
    4229           0 :             return CE_Failure;
    4230             : 
    4231             :         /* --------------------------------------------------------------------
    4232             :          */
    4233             :         /*      Figure out the ratio of blocks we will read to get an */
    4234             :         /*      approximate value. */
    4235             :         /* --------------------------------------------------------------------
    4236             :          */
    4237             : 
    4238          28 :         int nSampleRate = 1;
    4239          28 :         if (bApproxOK)
    4240             :         {
    4241           8 :             nSampleRate = static_cast<int>(std::max(
    4242          16 :                 1.0,
    4243           8 :                 sqrt(static_cast<double>(nBlocksPerRow) * nBlocksPerColumn)));
    4244             :             // We want to avoid probing only the first column of blocks for
    4245             :             // a square shaped raster, because it is not unlikely that it may
    4246             :             // be padding only (#6378).
    4247           8 :             if (nSampleRate == nBlocksPerRow && nBlocksPerRow > 1)
    4248           2 :                 nSampleRate += 1;
    4249             :         }
    4250             : 
    4251          28 :         GByte *pabyMaskData = nullptr;
    4252          28 :         if (poMaskBand)
    4253             :         {
    4254             :             pabyMaskData = static_cast<GByte *>(
    4255           1 :                 VSI_MALLOC2_VERBOSE(nBlockXSize, nBlockYSize));
    4256           1 :             if (!pabyMaskData)
    4257             :             {
    4258           0 :                 return CE_Failure;
    4259             :             }
    4260             :         }
    4261             : 
    4262             :         /* --------------------------------------------------------------------
    4263             :          */
    4264             :         /*      Read the blocks, and add to histogram. */
    4265             :         /* --------------------------------------------------------------------
    4266             :          */
    4267          28 :         for (GIntBig iSampleBlock = 0;
    4268         115 :              iSampleBlock <
    4269         115 :              static_cast<GIntBig>(nBlocksPerRow) * nBlocksPerColumn;
    4270          87 :              iSampleBlock += nSampleRate)
    4271             :         {
    4272          87 :             if (!pfnProgress(
    4273          87 :                     static_cast<double>(iSampleBlock) /
    4274          87 :                         (static_cast<double>(nBlocksPerRow) * nBlocksPerColumn),
    4275             :                     "Compute Histogram", pProgressData))
    4276             :             {
    4277           0 :                 CPLFree(pabyMaskData);
    4278           0 :                 return CE_Failure;
    4279             :             }
    4280             : 
    4281          87 :             const int iYBlock = static_cast<int>(iSampleBlock / nBlocksPerRow);
    4282          87 :             const int iXBlock = static_cast<int>(iSampleBlock % nBlocksPerRow);
    4283             : 
    4284          87 :             GDALRasterBlock *poBlock = GetLockedBlockRef(iXBlock, iYBlock);
    4285          87 :             if (poBlock == nullptr)
    4286             :             {
    4287           0 :                 CPLFree(pabyMaskData);
    4288           0 :                 return CE_Failure;
    4289             :             }
    4290             : 
    4291          87 :             void *pData = poBlock->GetDataRef();
    4292             : 
    4293          87 :             int nXCheck = 0, nYCheck = 0;
    4294          87 :             GetActualBlockSize(iXBlock, iYBlock, &nXCheck, &nYCheck);
    4295             : 
    4296          88 :             if (poMaskBand &&
    4297           1 :                 poMaskBand->RasterIO(GF_Read, iXBlock * nBlockXSize,
    4298           1 :                                      iYBlock * nBlockYSize, nXCheck, nYCheck,
    4299             :                                      pabyMaskData, nXCheck, nYCheck, GDT_Byte,
    4300           1 :                                      0, nBlockXSize, nullptr) != CE_None)
    4301             :             {
    4302           0 :                 CPLFree(pabyMaskData);
    4303           0 :                 poBlock->DropLock();
    4304           0 :                 return CE_Failure;
    4305             :             }
    4306             : 
    4307             :             // this is a special case for a common situation.
    4308          87 :             if (eDataType == GDT_Byte && !bSignedByte && dfScale == 1.0 &&
    4309          65 :                 (dfMin >= -0.5 && dfMin <= 0.5) && nYCheck == nBlockYSize &&
    4310          62 :                 nXCheck == nBlockXSize && nBuckets == 256)
    4311             :             {
    4312          62 :                 const GPtrDiff_t nPixels =
    4313          62 :                     static_cast<GPtrDiff_t>(nXCheck) * nYCheck;
    4314          62 :                 GByte *pabyData = static_cast<GByte *>(pData);
    4315             : 
    4316       71714 :                 for (GPtrDiff_t i = 0; i < nPixels; i++)
    4317             :                 {
    4318       71652 :                     if (pabyMaskData && pabyMaskData[i] == 0)
    4319           0 :                         continue;
    4320       72164 :                     if (!(bGotNoDataValue &&
    4321       71652 :                           (pabyData[i] == static_cast<GByte>(dfNoDataValue))))
    4322             :                     {
    4323       71396 :                         panHistogram[pabyData[i]]++;
    4324             :                     }
    4325             :                 }
    4326             : 
    4327          62 :                 poBlock->DropLock();
    4328          62 :                 continue;  // To next sample block.
    4329             :             }
    4330             : 
    4331             :             // This isn't the fastest way to do this, but is easier for now.
    4332         721 :             for (int iY = 0; iY < nYCheck; iY++)
    4333             :             {
    4334       86017 :                 for (int iX = 0; iX < nXCheck; iX++)
    4335             :                 {
    4336       85321 :                     const GPtrDiff_t iOffset =
    4337       85321 :                         iX + static_cast<GPtrDiff_t>(iY) * nBlockXSize;
    4338             : 
    4339       85321 :                     if (pabyMaskData && pabyMaskData[iOffset] == 0)
    4340           1 :                         continue;
    4341             : 
    4342       85320 :                     double dfValue = 0.0;
    4343             : 
    4344       85320 :                     switch (eDataType)
    4345             :                     {
    4346       19716 :                         case GDT_Byte:
    4347             :                         {
    4348       19716 :                             if (bSignedByte)
    4349           0 :                                 dfValue =
    4350           0 :                                     static_cast<signed char *>(pData)[iOffset];
    4351             :                             else
    4352       19716 :                                 dfValue = static_cast<GByte *>(pData)[iOffset];
    4353       19716 :                             break;
    4354             :                         }
    4355           0 :                         case GDT_Int8:
    4356           0 :                             dfValue = static_cast<GInt8 *>(pData)[iOffset];
    4357           0 :                             break;
    4358       65536 :                         case GDT_UInt16:
    4359       65536 :                             dfValue = static_cast<GUInt16 *>(pData)[iOffset];
    4360       65536 :                             break;
    4361           2 :                         case GDT_Int16:
    4362           2 :                             dfValue = static_cast<GInt16 *>(pData)[iOffset];
    4363           2 :                             break;
    4364           0 :                         case GDT_UInt32:
    4365           0 :                             dfValue = static_cast<GUInt32 *>(pData)[iOffset];
    4366           0 :                             break;
    4367          60 :                         case GDT_Int32:
    4368          60 :                             dfValue = static_cast<GInt32 *>(pData)[iOffset];
    4369          60 :                             break;
    4370           0 :                         case GDT_UInt64:
    4371           0 :                             dfValue = static_cast<double>(
    4372           0 :                                 static_cast<GUInt64 *>(pData)[iOffset]);
    4373           0 :                             break;
    4374           0 :                         case GDT_Int64:
    4375           0 :                             dfValue = static_cast<double>(
    4376           0 :                                 static_cast<GInt64 *>(pData)[iOffset]);
    4377           0 :                             break;
    4378           4 :                         case GDT_Float32:
    4379             :                         {
    4380           4 :                             const float fValue =
    4381           4 :                                 static_cast<float *>(pData)[iOffset];
    4382           8 :                             if (std::isnan(fValue) ||
    4383           4 :                                 (bGotFloatNoDataValue &&
    4384           4 :                                  ARE_REAL_EQUAL(fValue, fNoDataValue)))
    4385           1 :                                 continue;
    4386           3 :                             dfValue = fValue;
    4387           3 :                             break;
    4388             :                         }
    4389           2 :                         case GDT_Float64:
    4390           2 :                             dfValue = static_cast<double *>(pData)[iOffset];
    4391           2 :                             if (std::isnan(dfValue))
    4392           0 :                                 continue;
    4393           2 :                             break;
    4394           0 :                         case GDT_CInt16:
    4395             :                         {
    4396           0 :                             double dfReal =
    4397           0 :                                 static_cast<GInt16 *>(pData)[iOffset * 2];
    4398           0 :                             double dfImag =
    4399           0 :                                 static_cast<GInt16 *>(pData)[iOffset * 2 + 1];
    4400           0 :                             dfValue = sqrt(dfReal * dfReal + dfImag * dfImag);
    4401             :                         }
    4402           0 :                         break;
    4403           0 :                         case GDT_CInt32:
    4404             :                         {
    4405           0 :                             double dfReal =
    4406           0 :                                 static_cast<GInt32 *>(pData)[iOffset * 2];
    4407           0 :                             double dfImag =
    4408           0 :                                 static_cast<GInt32 *>(pData)[iOffset * 2 + 1];
    4409           0 :                             dfValue = sqrt(dfReal * dfReal + dfImag * dfImag);
    4410             :                         }
    4411           0 :                         break;
    4412           0 :                         case GDT_CFloat32:
    4413             :                         {
    4414           0 :                             double dfReal =
    4415           0 :                                 static_cast<float *>(pData)[iOffset * 2];
    4416           0 :                             double dfImag =
    4417           0 :                                 static_cast<float *>(pData)[iOffset * 2 + 1];
    4418           0 :                             if (std::isnan(dfReal) || std::isnan(dfImag))
    4419           0 :                                 continue;
    4420           0 :                             dfValue = sqrt(dfReal * dfReal + dfImag * dfImag);
    4421             :                         }
    4422           0 :                         break;
    4423           0 :                         case GDT_CFloat64:
    4424             :                         {
    4425           0 :                             double dfReal =
    4426           0 :                                 static_cast<double *>(pData)[iOffset * 2];
    4427           0 :                             double dfImag =
    4428           0 :                                 static_cast<double *>(pData)[iOffset * 2 + 1];
    4429           0 :                             if (std::isnan(dfReal) || std::isnan(dfImag))
    4430           0 :                                 continue;
    4431           0 :                             dfValue = sqrt(dfReal * dfReal + dfImag * dfImag);
    4432             :                         }
    4433           0 :                         break;
    4434           0 :                         case GDT_Unknown:
    4435             :                         case GDT_TypeCount:
    4436           0 :                             CPLAssert(false);
    4437             :                             CPLFree(pabyMaskData);
    4438             :                             return CE_Failure;
    4439             :                     }
    4440             : 
    4441       85319 :                     if (eDataType != GDT_Float32 && bGotNoDataValue &&
    4442           0 :                         ARE_REAL_EQUAL(dfValue, dfNoDataValue))
    4443           0 :                         continue;
    4444             : 
    4445             :                     // Given that dfValue and dfMin are not NaN, and dfScale > 0
    4446             :                     // and finite, the result of the multiplication cannot be
    4447             :                     // NaN
    4448       85319 :                     const double dfIndex = floor((dfValue - dfMin) * dfScale);
    4449             : 
    4450       85319 :                     if (dfIndex < 0)
    4451             :                     {
    4452           1 :                         if (bIncludeOutOfRange)
    4453           1 :                             panHistogram[0]++;
    4454             :                     }
    4455       85318 :                     else if (dfIndex >= nBuckets)
    4456             :                     {
    4457           7 :                         if (bIncludeOutOfRange)
    4458           4 :                             ++panHistogram[nBuckets - 1];
    4459             :                     }
    4460             :                     else
    4461             :                     {
    4462       85311 :                         ++panHistogram[static_cast<int>(dfIndex)];
    4463             :                     }
    4464             :                 }
    4465             :             }
    4466             : 
    4467          25 :             poBlock->DropLock();
    4468             :         }
    4469             : 
    4470          28 :         CPLFree(pabyMaskData);
    4471             :     }
    4472             : 
    4473          28 :     pfnProgress(1.0, "Compute Histogram", pProgressData);
    4474             : 
    4475          28 :     return CE_None;
    4476             : }
    4477             : 
    4478             : /************************************************************************/
    4479             : /*                       GDALGetRasterHistogram()                       */
    4480             : /************************************************************************/
    4481             : 
    4482             : /**
    4483             :  * \brief Compute raster histogram.
    4484             :  *
    4485             :  * Use GDALGetRasterHistogramEx() instead to get correct counts for values
    4486             :  * exceeding 2 billion.
    4487             :  *
    4488             :  * @see GDALRasterBand::GetHistogram()
    4489             :  * @see GDALGetRasterHistogramEx()
    4490             :  */
    4491             : 
    4492           0 : CPLErr CPL_STDCALL GDALGetRasterHistogram(GDALRasterBandH hBand, double dfMin,
    4493             :                                           double dfMax, int nBuckets,
    4494             :                                           int *panHistogram,
    4495             :                                           int bIncludeOutOfRange, int bApproxOK,
    4496             :                                           GDALProgressFunc pfnProgress,
    4497             :                                           void *pProgressData)
    4498             : 
    4499             : {
    4500           0 :     VALIDATE_POINTER1(hBand, "GDALGetRasterHistogram", CE_Failure);
    4501           0 :     VALIDATE_POINTER1(panHistogram, "GDALGetRasterHistogram", CE_Failure);
    4502             : 
    4503           0 :     GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
    4504             : 
    4505             :     GUIntBig *panHistogramTemp =
    4506           0 :         static_cast<GUIntBig *>(VSIMalloc2(sizeof(GUIntBig), nBuckets));
    4507           0 :     if (panHistogramTemp == nullptr)
    4508             :     {
    4509           0 :         poBand->ReportError(CE_Failure, CPLE_OutOfMemory,
    4510             :                             "Out of memory in GDALGetRasterHistogram().");
    4511           0 :         return CE_Failure;
    4512             :     }
    4513             : 
    4514           0 :     CPLErr eErr = poBand->GetHistogram(dfMin, dfMax, nBuckets, panHistogramTemp,
    4515             :                                        bIncludeOutOfRange, bApproxOK,
    4516           0 :                                        pfnProgress, pProgressData);
    4517             : 
    4518           0 :     if (eErr == CE_None)
    4519             :     {
    4520           0 :         for (int i = 0; i < nBuckets; i++)
    4521             :         {
    4522           0 :             if (panHistogramTemp[i] > INT_MAX)
    4523             :             {
    4524           0 :                 CPLError(CE_Warning, CPLE_AppDefined,
    4525             :                          "Count for bucket %d, which is " CPL_FRMT_GUIB
    4526             :                          " exceeds maximum 32 bit value",
    4527           0 :                          i, panHistogramTemp[i]);
    4528           0 :                 panHistogram[i] = INT_MAX;
    4529             :             }
    4530             :             else
    4531             :             {
    4532           0 :                 panHistogram[i] = static_cast<int>(panHistogramTemp[i]);
    4533             :             }
    4534             :         }
    4535             :     }
    4536             : 
    4537           0 :     CPLFree(panHistogramTemp);
    4538             : 
    4539           0 :     return eErr;
    4540             : }
    4541             : 
    4542             : /************************************************************************/
    4543             : /*                      GDALGetRasterHistogramEx()                      */
    4544             : /************************************************************************/
    4545             : 
    4546             : /**
    4547             :  * \brief Compute raster histogram.
    4548             :  *
    4549             :  * @see GDALRasterBand::GetHistogram()
    4550             :  *
    4551             :  * @since GDAL 2.0
    4552             :  */
    4553             : 
    4554          26 : CPLErr CPL_STDCALL GDALGetRasterHistogramEx(
    4555             :     GDALRasterBandH hBand, double dfMin, double dfMax, int nBuckets,
    4556             :     GUIntBig *panHistogram, int bIncludeOutOfRange, int bApproxOK,
    4557             :     GDALProgressFunc pfnProgress, void *pProgressData)
    4558             : 
    4559             : {
    4560          26 :     VALIDATE_POINTER1(hBand, "GDALGetRasterHistogramEx", CE_Failure);
    4561          26 :     VALIDATE_POINTER1(panHistogram, "GDALGetRasterHistogramEx", CE_Failure);
    4562             : 
    4563          26 :     GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
    4564             : 
    4565          26 :     return poBand->GetHistogram(dfMin, dfMax, nBuckets, panHistogram,
    4566             :                                 bIncludeOutOfRange, bApproxOK, pfnProgress,
    4567          26 :                                 pProgressData);
    4568             : }
    4569             : 
    4570             : /************************************************************************/
    4571             : /*                        GetDefaultHistogram()                         */
    4572             : /************************************************************************/
    4573             : 
    4574             : /**
    4575             :  * \brief Fetch default raster histogram.
    4576             :  *
    4577             :  * The default method in GDALRasterBand will compute a default histogram. This
    4578             :  * method is overridden by derived classes (such as GDALPamRasterBand,
    4579             :  * VRTDataset, HFADataset...) that may be able to fetch efficiently an already
    4580             :  * stored histogram.
    4581             :  *
    4582             :  * This method is the same as the C functions GDALGetDefaultHistogram() and
    4583             :  * GDALGetDefaultHistogramEx().
    4584             :  *
    4585             :  * @param pdfMin pointer to double value that will contain the lower bound of
    4586             :  * the histogram.
    4587             :  * @param pdfMax pointer to double value that will contain the upper bound of
    4588             :  * the histogram.
    4589             :  * @param pnBuckets pointer to int value that will contain the number of buckets
    4590             :  * in *ppanHistogram.
    4591             :  * @param ppanHistogram pointer to array into which the histogram totals are
    4592             :  * placed. To be freed with VSIFree
    4593             :  * @param bForce TRUE to force the computation. If FALSE and no default
    4594             :  * histogram is available, the method will return CE_Warning
    4595             :  * @param pfnProgress function to report progress to completion.
    4596             :  * @param pProgressData application data to pass to pfnProgress.
    4597             :  *
    4598             :  * @return CE_None on success, CE_Failure if something goes wrong, or
    4599             :  * CE_Warning if no default histogram is available.
    4600             :  */
    4601             : 
    4602          21 : CPLErr GDALRasterBand::GetDefaultHistogram(double *pdfMin, double *pdfMax,
    4603             :                                            int *pnBuckets,
    4604             :                                            GUIntBig **ppanHistogram, int bForce,
    4605             :                                            GDALProgressFunc pfnProgress,
    4606             :                                            void *pProgressData)
    4607             : 
    4608             : {
    4609          21 :     CPLAssert(nullptr != pnBuckets);
    4610          21 :     CPLAssert(nullptr != ppanHistogram);
    4611          21 :     CPLAssert(nullptr != pdfMin);
    4612          21 :     CPLAssert(nullptr != pdfMax);
    4613             : 
    4614          21 :     *pnBuckets = 0;
    4615          21 :     *ppanHistogram = nullptr;
    4616             : 
    4617          21 :     if (!bForce)
    4618           6 :         return CE_Warning;
    4619             : 
    4620          15 :     const int nBuckets = 256;
    4621             : 
    4622          15 :     bool bSignedByte = false;
    4623          15 :     if (eDataType == GDT_Byte)
    4624             :     {
    4625          15 :         EnablePixelTypeSignedByteWarning(false);
    4626             :         const char *pszPixelType =
    4627          15 :             GetMetadataItem("PIXELTYPE", "IMAGE_STRUCTURE");
    4628          15 :         EnablePixelTypeSignedByteWarning(true);
    4629          15 :         bSignedByte =
    4630          15 :             pszPixelType != nullptr && EQUAL(pszPixelType, "SIGNEDBYTE");
    4631             :     }
    4632             : 
    4633          15 :     if (GetRasterDataType() == GDT_Byte && !bSignedByte)
    4634             :     {
    4635          15 :         *pdfMin = -0.5;
    4636          15 :         *pdfMax = 255.5;
    4637             :     }
    4638             :     else
    4639             :     {
    4640             : 
    4641             :         const CPLErr eErr =
    4642           0 :             GetStatistics(TRUE, TRUE, pdfMin, pdfMax, nullptr, nullptr);
    4643           0 :         const double dfHalfBucket = (*pdfMax - *pdfMin) / (2 * (nBuckets - 1));
    4644           0 :         *pdfMin -= dfHalfBucket;
    4645           0 :         *pdfMax += dfHalfBucket;
    4646             : 
    4647           0 :         if (eErr != CE_None)
    4648           0 :             return eErr;
    4649             :     }
    4650             : 
    4651          15 :     *ppanHistogram =
    4652          15 :         static_cast<GUIntBig *>(VSICalloc(sizeof(GUIntBig), nBuckets));
    4653          15 :     if (*ppanHistogram == nullptr)
    4654             :     {
    4655           0 :         ReportError(CE_Failure, CPLE_OutOfMemory,
    4656             :                     "Out of memory in InitBlockInfo().");
    4657           0 :         return CE_Failure;
    4658             :     }
    4659             : 
    4660          15 :     *pnBuckets = nBuckets;
    4661          30 :     CPLErr eErr = GetHistogram(*pdfMin, *pdfMax, *pnBuckets, *ppanHistogram,
    4662          15 :                                TRUE, FALSE, pfnProgress, pProgressData);
    4663          15 :     if (eErr != CE_None)
    4664             :     {
    4665           0 :         *pnBuckets = 0;
    4666             :     }
    4667          15 :     return eErr;
    4668             : }
    4669             : 
    4670             : /************************************************************************/
    4671             : /*                      GDALGetDefaultHistogram()                       */
    4672             : /************************************************************************/
    4673             : 
    4674             : /**
    4675             :  * \brief Fetch default raster histogram.
    4676             :  *
    4677             :  * Use GDALGetRasterHistogramEx() instead to get correct counts for values
    4678             :  * exceeding 2 billion.
    4679             :  *
    4680             :  * @see GDALRasterBand::GDALGetDefaultHistogram()
    4681             :  * @see GDALGetRasterHistogramEx()
    4682             :  */
    4683             : 
    4684           0 : CPLErr CPL_STDCALL GDALGetDefaultHistogram(GDALRasterBandH hBand,
    4685             :                                            double *pdfMin, double *pdfMax,
    4686             :                                            int *pnBuckets, int **ppanHistogram,
    4687             :                                            int bForce,
    4688             :                                            GDALProgressFunc pfnProgress,
    4689             :                                            void *pProgressData)
    4690             : 
    4691             : {
    4692           0 :     VALIDATE_POINTER1(hBand, "GDALGetDefaultHistogram", CE_Failure);
    4693           0 :     VALIDATE_POINTER1(pdfMin, "GDALGetDefaultHistogram", CE_Failure);
    4694           0 :     VALIDATE_POINTER1(pdfMax, "GDALGetDefaultHistogram", CE_Failure);
    4695           0 :     VALIDATE_POINTER1(pnBuckets, "GDALGetDefaultHistogram", CE_Failure);
    4696           0 :     VALIDATE_POINTER1(ppanHistogram, "GDALGetDefaultHistogram", CE_Failure);
    4697             : 
    4698           0 :     GDALRasterBand *const poBand = GDALRasterBand::FromHandle(hBand);
    4699           0 :     GUIntBig *panHistogramTemp = nullptr;
    4700           0 :     CPLErr eErr = poBand->GetDefaultHistogram(pdfMin, pdfMax, pnBuckets,
    4701             :                                               &panHistogramTemp, bForce,
    4702           0 :                                               pfnProgress, pProgressData);
    4703           0 :     if (eErr == CE_None)
    4704             :     {
    4705           0 :         const int nBuckets = *pnBuckets;
    4706           0 :         *ppanHistogram = static_cast<int *>(VSIMalloc2(sizeof(int), nBuckets));
    4707           0 :         if (*ppanHistogram == nullptr)
    4708             :         {
    4709           0 :             poBand->ReportError(CE_Failure, CPLE_OutOfMemory,
    4710             :                                 "Out of memory in GDALGetDefaultHistogram().");
    4711           0 :             VSIFree(panHistogramTemp);
    4712           0 :             return CE_Failure;
    4713             :         }
    4714             : 
    4715           0 :         for (int i = 0; i < nBuckets; ++i)
    4716             :         {
    4717           0 :             if (panHistogramTemp[i] > INT_MAX)
    4718             :             {
    4719           0 :                 CPLError(CE_Warning, CPLE_AppDefined,
    4720             :                          "Count for bucket %d, which is " CPL_FRMT_GUIB
    4721             :                          " exceeds maximum 32 bit value",
    4722           0 :                          i, panHistogramTemp[i]);
    4723           0 :                 (*ppanHistogram)[i] = INT_MAX;
    4724             :             }
    4725             :             else
    4726             :             {
    4727           0 :                 (*ppanHistogram)[i] = static_cast<int>(panHistogramTemp[i]);
    4728             :             }
    4729             :         }
    4730             : 
    4731           0 :         CPLFree(panHistogramTemp);
    4732             :     }
    4733             :     else
    4734             :     {
    4735           0 :         *ppanHistogram = nullptr;
    4736             :     }
    4737             : 
    4738           0 :     return eErr;
    4739             : }
    4740             : 
    4741             : /************************************************************************/
    4742             : /*                      GDALGetDefaultHistogramEx()                     */
    4743             : /************************************************************************/
    4744             : 
    4745             : /**
    4746             :  * \brief Fetch default raster histogram.
    4747             :  *
    4748             :  * @see GDALRasterBand::GetDefaultHistogram()
    4749             :  *
    4750             :  * @since GDAL 2.0
    4751             :  */
    4752             : 
    4753             : CPLErr CPL_STDCALL
    4754          27 : GDALGetDefaultHistogramEx(GDALRasterBandH hBand, double *pdfMin, double *pdfMax,
    4755             :                           int *pnBuckets, GUIntBig **ppanHistogram, int bForce,
    4756             :                           GDALProgressFunc pfnProgress, void *pProgressData)
    4757             : 
    4758             : {
    4759          27 :     VALIDATE_POINTER1(hBand, "GDALGetDefaultHistogram", CE_Failure);
    4760          27 :     VALIDATE_POINTER1(pdfMin, "GDALGetDefaultHistogram", CE_Failure);
    4761          27 :     VALIDATE_POINTER1(pdfMax, "GDALGetDefaultHistogram", CE_Failure);
    4762          27 :     VALIDATE_POINTER1(pnBuckets, "GDALGetDefaultHistogram", CE_Failure);
    4763          27 :     VALIDATE_POINTER1(ppanHistogram, "GDALGetDefaultHistogram", CE_Failure);
    4764             : 
    4765          27 :     GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
    4766          27 :     return poBand->GetDefaultHistogram(pdfMin, pdfMax, pnBuckets, ppanHistogram,
    4767          27 :                                        bForce, pfnProgress, pProgressData);
    4768             : }
    4769             : 
    4770             : /************************************************************************/
    4771             : /*                             AdviseRead()                             */
    4772             : /************************************************************************/
    4773             : 
    4774             : /**
    4775             :  * \fn GDALRasterBand::AdviseRead(int,int,int,int,int,int,GDALDataType,char**)
    4776             :  * \brief Advise driver of upcoming read requests.
    4777             :  *
    4778             :  * Some GDAL drivers operate more efficiently if they know in advance what
    4779             :  * set of upcoming read requests will be made.  The AdviseRead() method allows
    4780             :  * an application to notify the driver of the region of interest,
    4781             :  * and at what resolution the region will be read.
    4782             :  *
    4783             :  * Many drivers just ignore the AdviseRead() call, but it can dramatically
    4784             :  * accelerate access via some drivers.
    4785             :  *
    4786             :  * Depending on call paths, drivers might receive several calls to
    4787             :  * AdviseRead() with the same parameters.
    4788             :  *
    4789             :  * @param nXOff The pixel offset to the top left corner of the region
    4790             :  * of the band to be accessed.  This would be zero to start from the left side.
    4791             :  *
    4792             :  * @param nYOff The line offset to the top left corner of the region
    4793             :  * of the band to be accessed.  This would be zero to start from the top.
    4794             :  *
    4795             :  * @param nXSize The width of the region of the band to be accessed in pixels.
    4796             :  *
    4797             :  * @param nYSize The height of the region of the band to be accessed in lines.
    4798             :  *
    4799             :  * @param nBufXSize the width of the buffer image into which the desired region
    4800             :  * is to be read, or from which it is to be written.
    4801             :  *
    4802             :  * @param nBufYSize the height of the buffer image into which the desired
    4803             :  * region is to be read, or from which it is to be written.
    4804             :  *
    4805             :  * @param eBufType the type of the pixel values in the pData data buffer.  The
    4806             :  * pixel values will automatically be translated to/from the GDALRasterBand
    4807             :  * data type as needed.
    4808             :  *
    4809             :  * @param papszOptions a list of name=value strings with special control
    4810             :  * options.  Normally this is NULL.
    4811             :  *
    4812             :  * @return CE_Failure if the request is invalid and CE_None if it works or
    4813             :  * is ignored.
    4814             :  */
    4815             : 
    4816             : /**/
    4817             : /**/
    4818             : 
    4819       42000 : CPLErr GDALRasterBand::AdviseRead(int /*nXOff*/, int /*nYOff*/, int /*nXSize*/,
    4820             :                                   int /*nYSize*/, int /*nBufXSize*/,
    4821             :                                   int /*nBufYSize*/, GDALDataType /*eBufType*/,
    4822             :                                   char ** /*papszOptions*/)
    4823             : {
    4824       42000 :     return CE_None;
    4825             : }
    4826             : 
    4827             : /************************************************************************/
    4828             : /*                        GDALRasterAdviseRead()                        */
    4829             : /************************************************************************/
    4830             : 
    4831             : /**
    4832             :  * \brief Advise driver of upcoming read requests.
    4833             :  *
    4834             :  * @see GDALRasterBand::AdviseRead()
    4835             :  */
    4836             : 
    4837           2 : CPLErr CPL_STDCALL GDALRasterAdviseRead(GDALRasterBandH hBand, int nXOff,
    4838             :                                         int nYOff, int nXSize, int nYSize,
    4839             :                                         int nBufXSize, int nBufYSize,
    4840             :                                         GDALDataType eDT,
    4841             :                                         CSLConstList papszOptions)
    4842             : 
    4843             : {
    4844           2 :     VALIDATE_POINTER1(hBand, "GDALRasterAdviseRead", CE_Failure);
    4845             : 
    4846           2 :     GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
    4847           2 :     return poBand->AdviseRead(nXOff, nYOff, nXSize, nYSize, nBufXSize,
    4848             :                               nBufYSize, eDT,
    4849           2 :                               const_cast<char **>(papszOptions));
    4850             : }
    4851             : 
    4852             : /************************************************************************/
    4853             : /*                           GetStatistics()                            */
    4854             : /************************************************************************/
    4855             : 
    4856             : /**
    4857             :  * \brief Fetch image statistics.
    4858             :  *
    4859             :  * Returns the minimum, maximum, mean and standard deviation of all
    4860             :  * pixel values in this band.  If approximate statistics are sufficient,
    4861             :  * the bApproxOK flag can be set to true in which case overviews, or a
    4862             :  * subset of image tiles may be used in computing the statistics.
    4863             :  *
    4864             :  * If bForce is FALSE results will only be returned if it can be done
    4865             :  * quickly (i.e. without scanning the image, typically by using pre-existing
    4866             :  * STATISTICS_xxx metadata items). If bForce is FALSE and results cannot be
    4867             :  * returned efficiently, the method will return CE_Warning but no warning will
    4868             :  * be issued. This is a non-standard use of the CE_Warning return value
    4869             :  * to indicate "nothing done".
    4870             :  *
    4871             :  * If bForce is TRUE, and results are quickly available without scanning the
    4872             :  * image, they will be used. If bForce is TRUE and results are not quickly
    4873             :  * available, GetStatistics() forwards the computation to ComputeStatistics(),
    4874             :  * which will scan the image.
    4875             :  *
    4876             :  * To always force recomputation of statistics, use ComputeStatistics() instead
    4877             :  * of this method.
    4878             :  *
    4879             :  * Note that file formats using PAM (Persistent Auxiliary Metadata) services
    4880             :  * will generally cache statistics in the .pam file allowing fast fetch
    4881             :  * after the first request.
    4882             :  *
    4883             :  * This method is the same as the C function GDALGetRasterStatistics().
    4884             :  *
    4885             :  * @param bApproxOK If TRUE statistics may be computed based on overviews
    4886             :  * or a subset of all tiles.
    4887             :  *
    4888             :  * @param bForce If FALSE statistics will only be returned if it can
    4889             :  * be done without rescanning the image. If TRUE, statistics computation will
    4890             :  * be forced if pre-existing values are not quickly available.
    4891             :  *
    4892             :  * @param pdfMin Location into which to load image minimum (may be NULL).
    4893             :  *
    4894             :  * @param pdfMax Location into which to load image maximum (may be NULL).-
    4895             :  *
    4896             :  * @param pdfMean Location into which to load image mean (may be NULL).
    4897             :  *
    4898             :  * @param pdfStdDev Location into which to load image standard deviation
    4899             :  * (may be NULL).
    4900             :  *
    4901             :  * @return CE_None on success, CE_Warning if no values returned,
    4902             :  * CE_Failure if an error occurs.
    4903             :  */
    4904             : 
    4905         597 : CPLErr GDALRasterBand::GetStatistics(int bApproxOK, int bForce, double *pdfMin,
    4906             :                                      double *pdfMax, double *pdfMean,
    4907             :                                      double *pdfStdDev)
    4908             : 
    4909             : {
    4910             :     /* -------------------------------------------------------------------- */
    4911             :     /*      Do we already have metadata items for the requested values?     */
    4912             :     /* -------------------------------------------------------------------- */
    4913        1194 :     if ((pdfMin == nullptr ||
    4914         597 :          GetMetadataItem("STATISTICS_MINIMUM") != nullptr) &&
    4915         196 :         (pdfMax == nullptr ||
    4916         196 :          GetMetadataItem("STATISTICS_MAXIMUM") != nullptr) &&
    4917        1390 :         (pdfMean == nullptr || GetMetadataItem("STATISTICS_MEAN") != nullptr) &&
    4918         196 :         (pdfStdDev == nullptr ||
    4919         196 :          GetMetadataItem("STATISTICS_STDDEV") != nullptr))
    4920             :     {
    4921         196 :         if (!(GetMetadataItem("STATISTICS_APPROXIMATE") && !bApproxOK))
    4922             :         {
    4923         189 :             if (pdfMin != nullptr)
    4924         189 :                 *pdfMin = CPLAtofM(GetMetadataItem("STATISTICS_MINIMUM"));
    4925         189 :             if (pdfMax != nullptr)
    4926         189 :                 *pdfMax = CPLAtofM(GetMetadataItem("STATISTICS_MAXIMUM"));
    4927         189 :             if (pdfMean != nullptr)
    4928         189 :                 *pdfMean = CPLAtofM(GetMetadataItem("STATISTICS_MEAN"));
    4929         189 :             if (pdfStdDev != nullptr)
    4930         189 :                 *pdfStdDev = CPLAtofM(GetMetadataItem("STATISTICS_STDDEV"));
    4931             : 
    4932         189 :             return CE_None;
    4933             :         }
    4934             :     }
    4935             : 
    4936             :     /* -------------------------------------------------------------------- */
    4937             :     /*      Does the driver already know the min/max?                       */
    4938             :     /* -------------------------------------------------------------------- */
    4939         408 :     if (bApproxOK && pdfMean == nullptr && pdfStdDev == nullptr)
    4940             :     {
    4941           0 :         int bSuccessMin = FALSE;
    4942           0 :         int bSuccessMax = FALSE;
    4943             : 
    4944           0 :         const double dfMin = GetMinimum(&bSuccessMin);
    4945           0 :         const double dfMax = GetMaximum(&bSuccessMax);
    4946             : 
    4947           0 :         if (bSuccessMin && bSuccessMax)
    4948             :         {
    4949           0 :             if (pdfMin != nullptr)
    4950           0 :                 *pdfMin = dfMin;
    4951           0 :             if (pdfMax != nullptr)
    4952           0 :                 *pdfMax = dfMax;
    4953           0 :             return CE_None;
    4954             :         }
    4955             :     }
    4956             : 
    4957             :     /* -------------------------------------------------------------------- */
    4958             :     /*      Either return without results, or force computation.            */
    4959             :     /* -------------------------------------------------------------------- */
    4960         408 :     if (!bForce)
    4961         155 :         return CE_Warning;
    4962             :     else
    4963         253 :         return ComputeStatistics(bApproxOK, pdfMin, pdfMax, pdfMean, pdfStdDev,
    4964         253 :                                  GDALDummyProgress, nullptr);
    4965             : }
    4966             : 
    4967             : /************************************************************************/
    4968             : /*                      GDALGetRasterStatistics()                       */
    4969             : /************************************************************************/
    4970             : 
    4971             : /**
    4972             :  * \brief Fetch image statistics.
    4973             :  *
    4974             :  * @see GDALRasterBand::GetStatistics()
    4975             :  */
    4976             : 
    4977         246 : CPLErr CPL_STDCALL GDALGetRasterStatistics(GDALRasterBandH hBand, int bApproxOK,
    4978             :                                            int bForce, double *pdfMin,
    4979             :                                            double *pdfMax, double *pdfMean,
    4980             :                                            double *pdfStdDev)
    4981             : 
    4982             : {
    4983         246 :     VALIDATE_POINTER1(hBand, "GDALGetRasterStatistics", CE_Failure);
    4984             : 
    4985         246 :     GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
    4986         246 :     return poBand->GetStatistics(bApproxOK, bForce, pdfMin, pdfMax, pdfMean,
    4987         246 :                                  pdfStdDev);
    4988             : }
    4989             : 
    4990             : #ifdef CPL_HAS_GINT64
    4991             : 
    4992             : /************************************************************************/
    4993             : /*                         GDALUInt128                                  */
    4994             : /************************************************************************/
    4995             : 
    4996             : #ifdef HAVE_UINT128_T
    4997             : class GDALUInt128
    4998             : {
    4999             :     __uint128_t val;
    5000             : 
    5001         621 :     explicit GDALUInt128(__uint128_t valIn) : val(valIn)
    5002             :     {
    5003         621 :     }
    5004             : 
    5005             :   public:
    5006         414 :     static GDALUInt128 Mul(GUIntBig first, GUIntBig second)
    5007             :     {
    5008             :         // Evaluates to just a single mul on x86_64
    5009         414 :         return GDALUInt128(static_cast<__uint128_t>(first) * second);
    5010             :     }
    5011             : 
    5012         207 :     GDALUInt128 operator-(const GDALUInt128 &other) const
    5013             :     {
    5014         207 :         return GDALUInt128(val - other.val);
    5015             :     }
    5016             : 
    5017         198 :     operator double() const
    5018             :     {
    5019         198 :         return static_cast<double>(val);
    5020             :     }
    5021             : };
    5022             : #else
    5023             : 
    5024             : #if defined(_MSC_VER) && defined(_M_X64)
    5025             : #include <intrin.h>
    5026             : #endif
    5027             : 
    5028             : class GDALUInt128
    5029             : {
    5030             :     GUIntBig low, high;
    5031             : 
    5032             :     GDALUInt128(GUIntBig lowIn, GUIntBig highIn) : low(lowIn), high(highIn)
    5033             :     {
    5034             :     }
    5035             : 
    5036             :   public:
    5037             :     static GDALUInt128 Mul(GUIntBig first, GUIntBig second)
    5038             :     {
    5039             : #if defined(_MSC_VER) && defined(_M_X64)
    5040             :         GUIntBig highRes;
    5041             :         GUIntBig lowRes = _umul128(first, second, &highRes);
    5042             :         return GDALUInt128(lowRes, highRes);
    5043             : #else
    5044             :         const GUInt32 firstLow = static_cast<GUInt32>(first);
    5045             :         const GUInt32 firstHigh = static_cast<GUInt32>(first >> 32);
    5046             :         const GUInt32 secondLow = static_cast<GUInt32>(second);
    5047             :         const GUInt32 secondHigh = static_cast<GUInt32>(second >> 32);
    5048             :         GUIntBig highRes = 0;
    5049             :         const GUIntBig firstLowSecondHigh =
    5050             :             static_cast<GUIntBig>(firstLow) * secondHigh;
    5051             :         const GUIntBig firstHighSecondLow =
    5052             :             static_cast<GUIntBig>(firstHigh) * secondLow;
    5053             :         const GUIntBig middleTerm = firstLowSecondHigh + firstHighSecondLow;
    5054             :         if (middleTerm < firstLowSecondHigh)  // check for overflow
    5055             :             highRes += static_cast<GUIntBig>(1) << 32;
    5056             :         const GUIntBig firstLowSecondLow =
    5057             :             static_cast<GUIntBig>(firstLow) * secondLow;
    5058             :         GUIntBig lowRes = firstLowSecondLow + (middleTerm << 32);
    5059             :         if (lowRes < firstLowSecondLow)  // check for overflow
    5060             :             highRes++;
    5061             :         highRes +=
    5062             :             (middleTerm >> 32) + static_cast<GUIntBig>(firstHigh) * secondHigh;
    5063             :         return GDALUInt128(lowRes, highRes);
    5064             : #endif
    5065             :     }
    5066             : 
    5067             :     GDALUInt128 operator-(const GDALUInt128 &other) const
    5068             :     {
    5069             :         GUIntBig highRes = high - other.high;
    5070             :         GUIntBig lowRes = low - other.low;
    5071             :         if (lowRes > low)  // check for underflow
    5072             :             --highRes;
    5073             :         return GDALUInt128(lowRes, highRes);
    5074             :     }
    5075             : 
    5076             :     operator double() const
    5077             :     {
    5078             :         const double twoPow64 = 18446744073709551616.0;
    5079             :         return high * twoPow64 + low;
    5080             :     }
    5081             : };
    5082             : #endif
    5083             : 
    5084             : /************************************************************************/
    5085             : /*                    ComputeStatisticsInternal()                       */
    5086             : /************************************************************************/
    5087             : 
    5088             : // Just to make coverity scan happy w.r.t overflow_before_widen, but otherwise
    5089             : // not needed.
    5090             : #define static_cast_for_coverity_scan static_cast
    5091             : 
    5092             : // The rationale for below optimizations is detailed in statistics.txt
    5093             : 
    5094             : // Use with T = GByte or GUInt16 only !
    5095             : template <class T, bool COMPUTE_OTHER_STATS>
    5096             : struct ComputeStatisticsInternalGeneric
    5097             : {
    5098         182 :     static void f(int nXCheck, int nBlockXSize, int nYCheck, const T *pData,
    5099             :                   bool bHasNoData, GUInt32 nNoDataValue, GUInt32 &nMin,
    5100             :                   GUInt32 &nMax, GUIntBig &nSum, GUIntBig &nSumSquare,
    5101             :                   GUIntBig &nSampleCount, GUIntBig &nValidCount)
    5102             :     {
    5103             :         static_assert(std::is_same<T, GByte>::value ||
    5104             :                           std::is_same<T, GUInt16>::value,
    5105             :                       "bad type for T");
    5106         182 :         if (bHasNoData)
    5107             :         {
    5108             :             // General case
    5109         386 :             for (int iY = 0; iY < nYCheck; iY++)
    5110             :             {
    5111       81751 :                 for (int iX = 0; iX < nXCheck; iX++)
    5112             :                 {
    5113       81468 :                     const GPtrDiff_t iOffset =
    5114       81468 :                         iX + static_cast<GPtrDiff_t>(iY) * nBlockXSize;
    5115       81468 :                     const GUInt32 nValue = pData[iOffset];
    5116       81468 :                     if (nValue == nNoDataValue)
    5117         175 :                         continue;
    5118       81293 :                     if (nValue < nMin)
    5119          26 :                         nMin = nValue;
    5120       81293 :                     if (nValue > nMax)
    5121          57 :                         nMax = nValue;
    5122             :                     if constexpr (COMPUTE_OTHER_STATS)
    5123             :                     {
    5124       79657 :                         nValidCount++;
    5125       79657 :                         nSum += nValue;
    5126       79657 :                         nSumSquare +=
    5127       79657 :                             static_cast_for_coverity_scan<GUIntBig>(nValue) *
    5128       79657 :                             nValue;
    5129             :                     }
    5130             :                 }
    5131             :             }
    5132             :             if constexpr (COMPUTE_OTHER_STATS)
    5133             :             {
    5134          20 :                 nSampleCount += static_cast<GUIntBig>(nXCheck) * nYCheck;
    5135             :             }
    5136             :         }
    5137          88 :         else if (nMin == std::numeric_limits<T>::min() &&
    5138           9 :                  nMax == std::numeric_limits<T>::max())
    5139             :         {
    5140             :             if constexpr (COMPUTE_OTHER_STATS)
    5141             :             {
    5142             :                 // Optimization when there is no nodata and we know we have already
    5143             :                 // reached the min and max
    5144         208 :                 for (int iY = 0; iY < nYCheck; iY++)
    5145             :                 {
    5146             :                     int iX;
    5147        1002 :                     for (iX = 0; iX + 3 < nXCheck; iX += 4)
    5148             :                     {
    5149         800 :                         const GPtrDiff_t iOffset =
    5150         800 :                             iX + static_cast<GPtrDiff_t>(iY) * nBlockXSize;
    5151         800 :                         const GUIntBig nValue = pData[iOffset];
    5152         800 :                         const GUIntBig nValue2 = pData[iOffset + 1];
    5153         800 :                         const GUIntBig nValue3 = pData[iOffset + 2];
    5154         800 :                         const GUIntBig nValue4 = pData[iOffset + 3];
    5155         800 :                         nSum += nValue;
    5156         800 :                         nSumSquare += nValue * nValue;
    5157         800 :                         nSum += nValue2;
    5158         800 :                         nSumSquare += nValue2 * nValue2;
    5159         800 :                         nSum += nValue3;
    5160         800 :                         nSumSquare += nValue3 * nValue3;
    5161         800 :                         nSum += nValue4;
    5162         800 :                         nSumSquare += nValue4 * nValue4;
    5163             :                     }
    5164         207 :                     for (; iX < nXCheck; ++iX)
    5165             :                     {
    5166           5 :                         const GPtrDiff_t iOffset =
    5167           5 :                             iX + static_cast<GPtrDiff_t>(iY) * nBlockXSize;
    5168           5 :                         const GUIntBig nValue = pData[iOffset];
    5169           5 :                         nSum += nValue;
    5170           5 :                         nSumSquare += nValue * nValue;
    5171             :                     }
    5172             :                 }
    5173           6 :                 nSampleCount += static_cast<GUIntBig>(nXCheck) * nYCheck;
    5174           6 :                 nValidCount += static_cast<GUIntBig>(nXCheck) * nYCheck;
    5175             :             }
    5176             :         }
    5177             :         else
    5178             :         {
    5179        3366 :             for (int iY = 0; iY < nYCheck; iY++)
    5180             :             {
    5181             :                 int iX;
    5182      635062 :                 for (iX = 0; iX + 1 < nXCheck; iX += 2)
    5183             :                 {
    5184      631769 :                     const GPtrDiff_t iOffset =
    5185      631769 :                         iX + static_cast<GPtrDiff_t>(iY) * nBlockXSize;
    5186      631769 :                     const GUInt32 nValue = pData[iOffset];
    5187      631769 :                     const GUInt32 nValue2 = pData[iOffset + 1];
    5188      631769 :                     if (nValue < nValue2)
    5189             :                     {
    5190        2160 :                         if (nValue < nMin)
    5191          48 :                             nMin = nValue;
    5192        2160 :                         if (nValue2 > nMax)
    5193         108 :                             nMax = nValue2;
    5194             :                     }
    5195             :                     else
    5196             :                     {
    5197      629609 :                         if (nValue2 < nMin)
    5198          61 :                             nMin = nValue2;
    5199      629609 :                         if (nValue > nMax)
    5200         212 :                             nMax = nValue;
    5201             :                     }
    5202             :                     if constexpr (COMPUTE_OTHER_STATS)
    5203             :                     {
    5204      624719 :                         nSum += nValue;
    5205      624719 :                         nSumSquare +=
    5206      624719 :                             static_cast_for_coverity_scan<GUIntBig>(nValue) *
    5207      624719 :                             nValue;
    5208      624719 :                         nSum += nValue2;
    5209      624719 :                         nSumSquare +=
    5210      624719 :                             static_cast_for_coverity_scan<GUIntBig>(nValue2) *
    5211      624719 :                             nValue2;
    5212             :                     }
    5213             :                 }
    5214        3293 :                 if (iX < nXCheck)
    5215             :                 {
    5216           9 :                     const GPtrDiff_t iOffset =
    5217           9 :                         iX + static_cast<GPtrDiff_t>(iY) * nBlockXSize;
    5218           9 :                     const GUInt32 nValue = pData[iOffset];
    5219           9 :                     if (nValue < nMin)
    5220           6 :                         nMin = nValue;
    5221           9 :                     if (nValue > nMax)
    5222           6 :                         nMax = nValue;
    5223             :                     if (COMPUTE_OTHER_STATS)
    5224             :                     {
    5225           9 :                         nSum += nValue;
    5226           9 :                         nSumSquare +=
    5227           9 :                             static_cast_for_coverity_scan<GUIntBig>(nValue) *
    5228           9 :                             nValue;
    5229             :                     }
    5230             :                 }
    5231             :             }
    5232             :             if constexpr (COMPUTE_OTHER_STATS)
    5233             :             {
    5234          28 :                 nSampleCount += static_cast<GUIntBig>(nXCheck) * nYCheck;
    5235          28 :                 nValidCount += static_cast<GUIntBig>(nXCheck) * nYCheck;
    5236             :             }
    5237             :         }
    5238         182 :     }
    5239             : };
    5240             : 
    5241             : // Specialization for Byte that is mostly 32 bit friendly as it avoids
    5242             : // using 64bit accumulators in internal loops. This also slightly helps in
    5243             : // 64bit mode.
    5244             : template <bool COMPUTE_OTHER_STATS>
    5245             : struct ComputeStatisticsInternalGeneric<GByte, COMPUTE_OTHER_STATS>
    5246             : {
    5247       11746 :     static void f(int nXCheck, int nBlockXSize, int nYCheck, const GByte *pData,
    5248             :                   bool bHasNoData, GUInt32 nNoDataValue, GUInt32 &nMin,
    5249             :                   GUInt32 &nMax, GUIntBig &nSum, GUIntBig &nSumSquare,
    5250             :                   GUIntBig &nSampleCount, GUIntBig &nValidCount)
    5251             :     {
    5252       11746 :         int nOuterLoops = nXCheck / 65536;
    5253       11746 :         if (nXCheck % 65536)
    5254       11746 :             nOuterLoops++;
    5255             : 
    5256       11746 :         if (bHasNoData)
    5257             :         {
    5258             :             // General case
    5259       19544 :             for (int iY = 0; iY < nYCheck; iY++)
    5260             :             {
    5261       10936 :                 int iX = 0;
    5262       21872 :                 for (int k = 0; k < nOuterLoops; k++)
    5263             :                 {
    5264       10936 :                     int iMax = iX + 65536;
    5265       10936 :                     if (iMax > nXCheck)
    5266       10936 :                         iMax = nXCheck;
    5267       10936 :                     GUInt32 nSum32bit = 0;
    5268       10936 :                     GUInt32 nSumSquare32bit = 0;
    5269       10936 :                     GUInt32 nValidCount32bit = 0;
    5270       10936 :                     GUInt32 nSampleCount32bit = 0;
    5271    16705717 :                     for (; iX < iMax; iX++)
    5272             :                     {
    5273    16694869 :                         const GPtrDiff_t iOffset =
    5274    16694869 :                             iX + static_cast<GPtrDiff_t>(iY) * nBlockXSize;
    5275    16694869 :                         const GUInt32 nValue = pData[iOffset];
    5276             : 
    5277    16694869 :                         nSampleCount32bit++;
    5278    16694869 :                         if (nValue == nNoDataValue)
    5279    16353423 :                             continue;
    5280      341391 :                         if (nValue < nMin)
    5281         343 :                             nMin = nValue;
    5282      341391 :                         if (nValue > nMax)
    5283         828 :                             nMax = nValue;
    5284             :                         if constexpr (COMPUTE_OTHER_STATS)
    5285             :                         {
    5286       16946 :                             nValidCount32bit++;
    5287       16946 :                             nSum32bit += nValue;
    5288       16946 :                             nSumSquare32bit += nValue * nValue;
    5289             :                         }
    5290             :                     }
    5291             :                     if constexpr (COMPUTE_OTHER_STATS)
    5292             :                     {
    5293         648 :                         nSampleCount += nSampleCount32bit;
    5294         648 :                         nValidCount += nValidCount32bit;
    5295         648 :                         nSum += nSum32bit;
    5296         648 :                         nSumSquare += nSumSquare32bit;
    5297             :                     }
    5298             :                 }
    5299             :             }
    5300             :         }
    5301        3138 :         else if (nMin == 0 && nMax == 255)
    5302             :         {
    5303             :             if constexpr (COMPUTE_OTHER_STATS)
    5304             :             {
    5305             :                 // Optimization when there is no nodata and we know we have already
    5306             :                 // reached the min and max
    5307        2644 :                 for (int iY = 0; iY < nYCheck; iY++)
    5308             :                 {
    5309        2617 :                     int iX = 0;
    5310        5234 :                     for (int k = 0; k < nOuterLoops; k++)
    5311             :                     {
    5312        2617 :                         int iMax = iX + 65536;
    5313        2617 :                         if (iMax > nXCheck)
    5314        2617 :                             iMax = nXCheck;
    5315        2617 :                         GUInt32 nSum32bit = 0;
    5316        2617 :                         GUInt32 nSumSquare32bit = 0;
    5317      176297 :                         for (; iX + 3 < iMax; iX += 4)
    5318             :                         {
    5319      173680 :                             const GPtrDiff_t iOffset =
    5320      173680 :                                 iX + static_cast<GPtrDiff_t>(iY) * nBlockXSize;
    5321      173680 :                             const GUInt32 nValue = pData[iOffset];
    5322      173680 :                             const GUInt32 nValue2 = pData[iOffset + 1];
    5323      173680 :                             const GUInt32 nValue3 = pData[iOffset + 2];
    5324      173680 :                             const GUInt32 nValue4 = pData[iOffset + 3];
    5325      173680 :                             nSum32bit += nValue;
    5326      173680 :                             nSumSquare32bit += nValue * nValue;
    5327      173680 :                             nSum32bit += nValue2;
    5328      173680 :                             nSumSquare32bit += nValue2 * nValue2;
    5329      173680 :                             nSum32bit += nValue3;
    5330      173680 :                             nSumSquare32bit += nValue3 * nValue3;
    5331      173680 :                             nSum32bit += nValue4;
    5332      173680 :                             nSumSquare32bit += nValue4 * nValue4;
    5333             :                         }
    5334        2617 :                         nSum += nSum32bit;
    5335        2617 :                         nSumSquare += nSumSquare32bit;
    5336             :                     }
    5337        2620 :                     for (; iX < nXCheck; ++iX)
    5338             :                     {
    5339           3 :                         const GPtrDiff_t iOffset =
    5340           3 :                             iX + static_cast<GPtrDiff_t>(iY) * nBlockXSize;
    5341           3 :                         const GUIntBig nValue = pData[iOffset];
    5342           3 :                         nSum += nValue;
    5343           3 :                         nSumSquare += nValue * nValue;
    5344             :                     }
    5345             :                 }
    5346          27 :                 nSampleCount += static_cast<GUIntBig>(nXCheck) * nYCheck;
    5347          27 :                 nValidCount += static_cast<GUIntBig>(nXCheck) * nYCheck;
    5348          27 :             }
    5349             :         }
    5350             :         else
    5351             :         {
    5352        7877 :             for (int iY = 0; iY < nYCheck; iY++)
    5353             :             {
    5354        4766 :                 int iX = 0;
    5355        9531 :                 for (int k = 0; k < nOuterLoops; k++)
    5356             :                 {
    5357        4765 :                     int iMax = iX + 65536;
    5358        4765 :                     if (iMax > nXCheck)
    5359        4763 :                         iMax = nXCheck;
    5360        4765 :                     GUInt32 nSum32bit = 0;
    5361        4765 :                     GUInt32 nSumSquare32bit = 0;
    5362      161526 :                     for (; iX + 1 < iMax; iX += 2)
    5363             :                     {
    5364      156761 :                         const GPtrDiff_t iOffset =
    5365      156761 :                             iX + static_cast<GPtrDiff_t>(iY) * nBlockXSize;
    5366      156761 :                         const GUInt32 nValue = pData[iOffset];
    5367      156761 :                         const GUInt32 nValue2 = pData[iOffset + 1];
    5368      156761 :                         if (nValue < nValue2)
    5369             :                         {
    5370        8915 :                             if (nValue < nMin)
    5371         250 :                                 nMin = nValue;
    5372        8915 :                             if (nValue2 > nMax)
    5373         237 :                                 nMax = nValue2;
    5374             :                         }
    5375             :                         else
    5376             :                         {
    5377      147846 :                             if (nValue2 < nMin)
    5378         298 :                                 nMin = nValue2;
    5379      147846 :                             if (nValue > nMax)
    5380         850 :                                 nMax = nValue;
    5381             :                         }
    5382             :                         if constexpr (COMPUTE_OTHER_STATS)
    5383             :                         {
    5384      132349 :                             nSum32bit += nValue;
    5385      132349 :                             nSumSquare32bit += nValue * nValue;
    5386      132349 :                             nSum32bit += nValue2;
    5387      132349 :                             nSumSquare32bit += nValue2 * nValue2;
    5388             :                         }
    5389             :                     }
    5390             :                     if constexpr (COMPUTE_OTHER_STATS)
    5391             :                     {
    5392        1600 :                         nSum += nSum32bit;
    5393        1600 :                         nSumSquare += nSumSquare32bit;
    5394             :                     }
    5395             :                 }
    5396        4766 :                 if (iX < nXCheck)
    5397             :                 {
    5398        1383 :                     const GPtrDiff_t iOffset =
    5399        1383 :                         iX + static_cast<GPtrDiff_t>(iY) * nBlockXSize;
    5400        1383 :                     const GUInt32 nValue = pData[iOffset];
    5401        1383 :                     if (nValue < nMin)
    5402          38 :                         nMin = nValue;
    5403        1383 :                     if (nValue > nMax)
    5404          48 :                         nMax = nValue;
    5405             :                     if constexpr (COMPUTE_OTHER_STATS)
    5406             :                     {
    5407         312 :                         nSum += nValue;
    5408         312 :                         nSumSquare +=
    5409         312 :                             static_cast_for_coverity_scan<GUIntBig>(nValue) *
    5410         312 :                             nValue;
    5411             :                     }
    5412             :                 }
    5413             :             }
    5414             :             if constexpr (COMPUTE_OTHER_STATS)
    5415             :             {
    5416         901 :                 nSampleCount += static_cast<GUIntBig>(nXCheck) * nYCheck;
    5417         901 :                 nValidCount += static_cast<GUIntBig>(nXCheck) * nYCheck;
    5418             :             }
    5419             :         }
    5420       11746 :     }
    5421             : };
    5422             : 
    5423             : template <class T, bool COMPUTE_OTHER_STATS> struct ComputeStatisticsInternal
    5424             : {
    5425             :     static void f(int nXCheck, int nBlockXSize, int nYCheck, const T *pData,
    5426             :                   bool bHasNoData, GUInt32 nNoDataValue, GUInt32 &nMin,
    5427             :                   GUInt32 &nMax, GUIntBig &nSum, GUIntBig &nSumSquare,
    5428             :                   GUIntBig &nSampleCount, GUIntBig &nValidCount)
    5429             :     {
    5430             :         ComputeStatisticsInternalGeneric<T, COMPUTE_OTHER_STATS>::f(
    5431             :             nXCheck, nBlockXSize, nYCheck, pData, bHasNoData, nNoDataValue,
    5432             :             nMin, nMax, nSum, nSumSquare, nSampleCount, nValidCount);
    5433             :     }
    5434             : };
    5435             : 
    5436             : #if (defined(__x86_64__) || defined(_M_X64)) &&                                \
    5437             :     (defined(__GNUC__) || defined(_MSC_VER))
    5438             : 
    5439             : #include "gdal_avx2_emulation.hpp"
    5440             : 
    5441             : #define ZERO256 GDALmm256_setzero_si256()
    5442             : 
    5443             : template <bool COMPUTE_MIN, bool COMPUTE_MAX, bool COMPUTE_OTHER_STATS>
    5444             : static void
    5445       19004 : ComputeStatisticsByteNoNodata(GPtrDiff_t nBlockPixels,
    5446             :                               // assumed to be aligned on 256 bits
    5447             :                               const GByte *pData, GUInt32 &nMin, GUInt32 &nMax,
    5448             :                               GUIntBig &nSum, GUIntBig &nSumSquare,
    5449             :                               GUIntBig &nSampleCount, GUIntBig &nValidCount)
    5450             : {
    5451             :     // 32-byte alignment may not be enforced by linker, so do it at hand
    5452             :     GByte
    5453             :         aby32ByteUnaligned[32 + 32 + 32 + (COMPUTE_OTHER_STATS ? 32 + 32 : 0)];
    5454       19004 :     GByte *paby32ByteAligned =
    5455             :         aby32ByteUnaligned +
    5456       19004 :         (32 - (reinterpret_cast<GUIntptr_t>(aby32ByteUnaligned) % 32));
    5457       19004 :     GByte *pabyMin = paby32ByteAligned;
    5458       19004 :     GByte *pabyMax = paby32ByteAligned + 32;
    5459       19004 :     GUInt32 *panSum =
    5460             :         COMPUTE_OTHER_STATS
    5461             :             ? reinterpret_cast<GUInt32 *>(paby32ByteAligned + 32 * 2)
    5462             :             : nullptr;
    5463       19004 :     GUInt32 *panSumSquare =
    5464             :         COMPUTE_OTHER_STATS
    5465             :             ? reinterpret_cast<GUInt32 *>(paby32ByteAligned + 32 * 3)
    5466             :             : nullptr;
    5467             : 
    5468       19004 :     CPLAssert((reinterpret_cast<uintptr_t>(pData) % 32) == 0);
    5469             : 
    5470       19004 :     GPtrDiff_t i = 0;
    5471             :     // Make sure that sumSquare can fit on uint32
    5472             :     // * 8 since we can hold 8 sums per vector register
    5473       19004 :     const int nMaxIterationsPerInnerLoop =
    5474             :         8 * ((std::numeric_limits<GUInt32>::max() / (255 * 255)) & ~31);
    5475       19004 :     GPtrDiff_t nOuterLoops = nBlockPixels / nMaxIterationsPerInnerLoop;
    5476       19004 :     if ((nBlockPixels % nMaxIterationsPerInnerLoop) != 0)
    5477       19004 :         nOuterLoops++;
    5478             : 
    5479             :     GDALm256i ymm_min =
    5480       19004 :         GDALmm256_load_si256(reinterpret_cast<const GDALm256i *>(pData + i));
    5481       19004 :     GDALm256i ymm_max = ymm_min;
    5482       19004 :     [[maybe_unused]] const auto ymm_mask_8bits = GDALmm256_set1_epi16(0xFF);
    5483             : 
    5484       38008 :     for (GPtrDiff_t k = 0; k < nOuterLoops; k++)
    5485             :     {
    5486       19004 :         const auto iMax =
    5487       19004 :             std::min(nBlockPixels, i + nMaxIterationsPerInnerLoop);
    5488             : 
    5489             :         // holds 4 uint32 sums in [0], [2], [4] and [6]
    5490       19004 :         [[maybe_unused]] GDALm256i ymm_sum = ZERO256;
    5491             :         [[maybe_unused]] GDALm256i ymm_sumsquare =
    5492       19004 :             ZERO256;  // holds 8 uint32 sums
    5493      635923 :         for (; i + 31 < iMax; i += 32)
    5494             :         {
    5495      616919 :             const GDALm256i ymm = GDALmm256_load_si256(
    5496      616919 :                 reinterpret_cast<const GDALm256i *>(pData + i));
    5497             :             if (COMPUTE_MIN)
    5498             :             {
    5499      159529 :                 ymm_min = GDALmm256_min_epu8(ymm_min, ymm);
    5500             :             }
    5501             :             if (COMPUTE_MAX)
    5502             :             {
    5503      526037 :                 ymm_max = GDALmm256_max_epu8(ymm_max, ymm);
    5504             :             }
    5505             : 
    5506             :             if constexpr (COMPUTE_OTHER_STATS)
    5507             :             {
    5508             :                 // Extract even-8bit values
    5509             :                 const GDALm256i ymm_even =
    5510      493495 :                     GDALmm256_and_si256(ymm, ymm_mask_8bits);
    5511             :                 // Compute square of those 16 values as 32 bit result
    5512             :                 // and add adjacent pairs
    5513             :                 const GDALm256i ymm_even_square =
    5514      493495 :                     GDALmm256_madd_epi16(ymm_even, ymm_even);
    5515             :                 // Add to the sumsquare accumulator
    5516             :                 ymm_sumsquare =
    5517      493495 :                     GDALmm256_add_epi32(ymm_sumsquare, ymm_even_square);
    5518             : 
    5519             :                 // Extract odd-8bit values
    5520      493495 :                 const GDALm256i ymm_odd = GDALmm256_srli_epi16(ymm, 8);
    5521             :                 const GDALm256i ymm_odd_square =
    5522      493495 :                     GDALmm256_madd_epi16(ymm_odd, ymm_odd);
    5523             :                 ymm_sumsquare =
    5524      493495 :                     GDALmm256_add_epi32(ymm_sumsquare, ymm_odd_square);
    5525             : 
    5526             :                 // Now compute the sums
    5527      493495 :                 ymm_sum = GDALmm256_add_epi32(ymm_sum,
    5528             :                                               GDALmm256_sad_epu8(ymm, ZERO256));
    5529             :             }
    5530             :         }
    5531             : 
    5532             :         if constexpr (COMPUTE_OTHER_STATS)
    5533             :         {
    5534       10649 :             GDALmm256_store_si256(reinterpret_cast<GDALm256i *>(panSum),
    5535             :                                   ymm_sum);
    5536       10649 :             GDALmm256_store_si256(reinterpret_cast<GDALm256i *>(panSumSquare),
    5537             :                                   ymm_sumsquare);
    5538             : 
    5539       10649 :             nSum += panSum[0] + panSum[2] + panSum[4] + panSum[6];
    5540       10649 :             nSumSquare += static_cast<GUIntBig>(panSumSquare[0]) +
    5541       10649 :                           panSumSquare[1] + panSumSquare[2] + panSumSquare[3] +
    5542       10649 :                           panSumSquare[4] + panSumSquare[5] + panSumSquare[6] +
    5543             :                           panSumSquare[7];
    5544             :         }
    5545             :     }
    5546             : 
    5547             :     if constexpr (COMPUTE_MIN)
    5548             :     {
    5549        6035 :         GDALmm256_store_si256(reinterpret_cast<GDALm256i *>(pabyMin), ymm_min);
    5550             :     }
    5551             :     if constexpr (COMPUTE_MAX)
    5552             :     {
    5553       15008 :         GDALmm256_store_si256(reinterpret_cast<GDALm256i *>(pabyMax), ymm_max);
    5554             :     }
    5555             :     if constexpr (COMPUTE_MIN || COMPUTE_MAX)
    5556             :     {
    5557      512721 :         for (int j = 0; j < 32; j++)
    5558             :         {
    5559             :             if constexpr (COMPUTE_MIN)
    5560             :             {
    5561      193120 :                 if (pabyMin[j] < nMin)
    5562        1259 :                     nMin = pabyMin[j];
    5563             :             }
    5564             :             if constexpr (COMPUTE_MAX)
    5565             :             {
    5566      480256 :                 if (pabyMax[j] > nMax)
    5567        1801 :                     nMax = pabyMax[j];
    5568             :             }
    5569             :         }
    5570             :     }
    5571             : 
    5572      211554 :     for (; i < nBlockPixels; i++)
    5573             :     {
    5574      192550 :         const GUInt32 nValue = pData[i];
    5575             :         if constexpr (COMPUTE_MIN)
    5576             :         {
    5577       66110 :             if (nValue < nMin)
    5578           1 :                 nMin = nValue;
    5579             :         }
    5580             :         if constexpr (COMPUTE_MAX)
    5581             :         {
    5582      189787 :             if (nValue > nMax)
    5583        1167 :                 nMax = nValue;
    5584             :         }
    5585             :         if constexpr (COMPUTE_OTHER_STATS)
    5586             :         {
    5587       77195 :             nSum += nValue;
    5588       77195 :             nSumSquare +=
    5589       77195 :                 static_cast_for_coverity_scan<GUIntBig>(nValue) * nValue;
    5590             :         }
    5591             :     }
    5592             : 
    5593             :     if constexpr (COMPUTE_OTHER_STATS)
    5594             :     {
    5595       10649 :         nSampleCount += static_cast<GUIntBig>(nBlockPixels);
    5596       10649 :         nValidCount += static_cast<GUIntBig>(nBlockPixels);
    5597             :     }
    5598       19004 : }
    5599             : 
    5600             : // SSE2/AVX2 optimization for GByte case
    5601             : // In pure SSE2, this relies on gdal_avx2_emulation.hpp. There is no
    5602             : // penaly in using the emulation, because, given the mm256 intrinsics used here,
    5603             : // there are strictly equivalent to 2 parallel SSE2 streams.
    5604             : template <bool COMPUTE_OTHER_STATS>
    5605             : struct ComputeStatisticsInternal<GByte, COMPUTE_OTHER_STATS>
    5606             : {
    5607       28060 :     static void f(int nXCheck, int nBlockXSize, int nYCheck,
    5608             :                   // assumed to be aligned on 256 bits
    5609             :                   const GByte *pData, bool bHasNoData, GUInt32 nNoDataValue,
    5610             :                   GUInt32 &nMin, GUInt32 &nMax, GUIntBig &nSum,
    5611             :                   GUIntBig &nSumSquare, GUIntBig &nSampleCount,
    5612             :                   GUIntBig &nValidCount)
    5613             :     {
    5614       28060 :         const auto nBlockPixels = static_cast<GPtrDiff_t>(nXCheck) * nYCheck;
    5615       28060 :         if (bHasNoData && nXCheck == nBlockXSize && nBlockPixels >= 32 &&
    5616        9352 :             nMin <= nMax)
    5617             :         {
    5618             :             // 32-byte alignment may not be enforced by linker, so do it at hand
    5619             :             GByte aby32ByteUnaligned[32 + 32 + 32 + 32 + 32];
    5620        1240 :             GByte *paby32ByteAligned =
    5621             :                 aby32ByteUnaligned +
    5622        1240 :                 (32 - (reinterpret_cast<GUIntptr_t>(aby32ByteUnaligned) % 32));
    5623        1240 :             GByte *pabyMin = paby32ByteAligned;
    5624        1240 :             GByte *pabyMax = paby32ByteAligned + 32;
    5625        1240 :             GUInt32 *panSum =
    5626             :                 reinterpret_cast<GUInt32 *>(paby32ByteAligned + 32 * 2);
    5627        1240 :             GUInt32 *panSumSquare =
    5628             :                 reinterpret_cast<GUInt32 *>(paby32ByteAligned + 32 * 3);
    5629             : 
    5630        1240 :             CPLAssert((reinterpret_cast<uintptr_t>(pData) % 32) == 0);
    5631             : 
    5632        1240 :             GPtrDiff_t i = 0;
    5633             :             // Make sure that sumSquare can fit on uint32
    5634             :             // * 8 since we can hold 8 sums per vector register
    5635        1240 :             const int nMaxIterationsPerInnerLoop =
    5636             :                 8 * ((std::numeric_limits<GUInt32>::max() / (255 * 255)) & ~31);
    5637        1240 :             auto nOuterLoops = nBlockPixels / nMaxIterationsPerInnerLoop;
    5638        1240 :             if ((nBlockPixels % nMaxIterationsPerInnerLoop) != 0)
    5639        1240 :                 nOuterLoops++;
    5640             : 
    5641             :             const GDALm256i ymm_nodata =
    5642        1240 :                 GDALmm256_set1_epi8(static_cast<GByte>(nNoDataValue));
    5643             :             // any non noData value in [min,max] would do.
    5644             :             const GDALm256i ymm_neutral =
    5645        1240 :                 GDALmm256_set1_epi8(static_cast<GByte>(nMin));
    5646        1240 :             GDALm256i ymm_min = ymm_neutral;
    5647        1240 :             GDALm256i ymm_max = ymm_neutral;
    5648             :             [[maybe_unused]] const auto ymm_mask_8bits =
    5649        1240 :                 GDALmm256_set1_epi16(0xFF);
    5650             : 
    5651        1240 :             const GUInt32 nMinThreshold = (nNoDataValue == 0) ? 1 : 0;
    5652        1240 :             const GUInt32 nMaxThreshold = (nNoDataValue == 255) ? 254 : 255;
    5653        1240 :             const bool bComputeMinMax =
    5654        1240 :                 nMin > nMinThreshold || nMax < nMaxThreshold;
    5655             : 
    5656        2480 :             for (GPtrDiff_t k = 0; k < nOuterLoops; k++)
    5657             :             {
    5658        1240 :                 const auto iMax =
    5659        1240 :                     std::min(nBlockPixels, i + nMaxIterationsPerInnerLoop);
    5660             : 
    5661             :                 // holds 4 uint32 sums in [0], [2], [4] and [6]
    5662        1240 :                 [[maybe_unused]] GDALm256i ymm_sum = ZERO256;
    5663             :                 // holds 8 uint32 sums
    5664        1240 :                 [[maybe_unused]] GDALm256i ymm_sumsquare = ZERO256;
    5665             :                 // holds 4 uint32 sums in [0], [2], [4] and [6]
    5666        1240 :                 [[maybe_unused]] GDALm256i ymm_count_nodata_mul_255 = ZERO256;
    5667        1240 :                 const auto iInit = i;
    5668       13799 :                 for (; i + 31 < iMax; i += 32)
    5669             :                 {
    5670       12559 :                     const GDALm256i ymm = GDALmm256_load_si256(
    5671       12559 :                         reinterpret_cast<const GDALm256i *>(pData + i));
    5672             : 
    5673             :                     // Check which values are nodata
    5674             :                     const GDALm256i ymm_eq_nodata =
    5675       12559 :                         GDALmm256_cmpeq_epi8(ymm, ymm_nodata);
    5676             :                     if constexpr (COMPUTE_OTHER_STATS)
    5677             :                     {
    5678             :                         // Count how many values are nodata (due to cmpeq
    5679             :                         // putting 255 when condition is met, this will actually
    5680             :                         // be 255 times the number of nodata value, spread in 4
    5681             :                         // 64 bits words). We can use add_epi32 as the counter
    5682             :                         // will not overflow uint32
    5683        4514 :                         ymm_count_nodata_mul_255 = GDALmm256_add_epi32(
    5684             :                             ymm_count_nodata_mul_255,
    5685             :                             GDALmm256_sad_epu8(ymm_eq_nodata, ZERO256));
    5686             :                     }
    5687             :                     // Replace all nodata values by zero for the purpose of sum
    5688             :                     // and sumquare.
    5689             :                     const GDALm256i ymm_nodata_by_zero =
    5690       12559 :                         GDALmm256_andnot_si256(ymm_eq_nodata, ymm);
    5691       12559 :                     if (bComputeMinMax)
    5692             :                     {
    5693             :                         // Replace all nodata values by a neutral value for the
    5694             :                         // purpose of min and max.
    5695             :                         const GDALm256i ymm_nodata_by_neutral =
    5696        8174 :                             GDALmm256_or_si256(
    5697             :                                 GDALmm256_and_si256(ymm_eq_nodata, ymm_neutral),
    5698             :                                 ymm_nodata_by_zero);
    5699             : 
    5700             :                         ymm_min =
    5701        8174 :                             GDALmm256_min_epu8(ymm_min, ymm_nodata_by_neutral);
    5702             :                         ymm_max =
    5703        8174 :                             GDALmm256_max_epu8(ymm_max, ymm_nodata_by_neutral);
    5704             :                     }
    5705             : 
    5706             :                     if constexpr (COMPUTE_OTHER_STATS)
    5707             :                     {
    5708             :                         // Extract even-8bit values
    5709        4514 :                         const GDALm256i ymm_even = GDALmm256_and_si256(
    5710             :                             ymm_nodata_by_zero, ymm_mask_8bits);
    5711             :                         // Compute square of those 16 values as 32 bit result
    5712             :                         // and add adjacent pairs
    5713             :                         const GDALm256i ymm_even_square =
    5714        4514 :                             GDALmm256_madd_epi16(ymm_even, ymm_even);
    5715             :                         // Add to the sumsquare accumulator
    5716             :                         ymm_sumsquare =
    5717        4514 :                             GDALmm256_add_epi32(ymm_sumsquare, ymm_even_square);
    5718             : 
    5719             :                         // Extract odd-8bit values
    5720             :                         const GDALm256i ymm_odd =
    5721        4514 :                             GDALmm256_srli_epi16(ymm_nodata_by_zero, 8);
    5722             :                         const GDALm256i ymm_odd_square =
    5723        4514 :                             GDALmm256_madd_epi16(ymm_odd, ymm_odd);
    5724             :                         ymm_sumsquare =
    5725        4514 :                             GDALmm256_add_epi32(ymm_sumsquare, ymm_odd_square);
    5726             : 
    5727             :                         // Now compute the sums
    5728        4514 :                         ymm_sum = GDALmm256_add_epi32(
    5729             :                             ymm_sum,
    5730             :                             GDALmm256_sad_epu8(ymm_nodata_by_zero, ZERO256));
    5731             :                     }
    5732             :                 }
    5733             : 
    5734             :                 if constexpr (COMPUTE_OTHER_STATS)
    5735             :                 {
    5736          33 :                     GUInt32 *panCoutNoDataMul255 = panSum;
    5737          33 :                     GDALmm256_store_si256(
    5738             :                         reinterpret_cast<GDALm256i *>(panCoutNoDataMul255),
    5739             :                         ymm_count_nodata_mul_255);
    5740             : 
    5741          33 :                     nSampleCount += (i - iInit);
    5742             : 
    5743          33 :                     nValidCount +=
    5744          33 :                         (i - iInit) -
    5745          33 :                         (panCoutNoDataMul255[0] + panCoutNoDataMul255[2] +
    5746          33 :                          panCoutNoDataMul255[4] + panCoutNoDataMul255[6]) /
    5747             :                             255;
    5748             : 
    5749          33 :                     GDALmm256_store_si256(reinterpret_cast<GDALm256i *>(panSum),
    5750             :                                           ymm_sum);
    5751          33 :                     GDALmm256_store_si256(
    5752             :                         reinterpret_cast<GDALm256i *>(panSumSquare),
    5753             :                         ymm_sumsquare);
    5754          33 :                     nSum += panSum[0] + panSum[2] + panSum[4] + panSum[6];
    5755          33 :                     nSumSquare += static_cast<GUIntBig>(panSumSquare[0]) +
    5756          33 :                                   panSumSquare[1] + panSumSquare[2] +
    5757          33 :                                   panSumSquare[3] + panSumSquare[4] +
    5758          33 :                                   panSumSquare[5] + panSumSquare[6] +
    5759             :                                   panSumSquare[7];
    5760             :                 }
    5761             :             }
    5762             : 
    5763        1240 :             if (bComputeMinMax)
    5764             :             {
    5765        1209 :                 GDALmm256_store_si256(reinterpret_cast<GDALm256i *>(pabyMin),
    5766             :                                       ymm_min);
    5767        1209 :                 GDALmm256_store_si256(reinterpret_cast<GDALm256i *>(pabyMax),
    5768             :                                       ymm_max);
    5769       39897 :                 for (int j = 0; j < 32; j++)
    5770             :                 {
    5771       38688 :                     if (pabyMin[j] < nMin)
    5772          32 :                         nMin = pabyMin[j];
    5773       38688 :                     if (pabyMax[j] > nMax)
    5774         157 :                         nMax = pabyMax[j];
    5775             :                 }
    5776             :             }
    5777             : 
    5778             :             if constexpr (COMPUTE_OTHER_STATS)
    5779             :             {
    5780          33 :                 nSampleCount += nBlockPixels - i;
    5781             :             }
    5782       29810 :             for (; i < nBlockPixels; i++)
    5783             :             {
    5784       28570 :                 const GUInt32 nValue = pData[i];
    5785       28570 :                 if (nValue == nNoDataValue)
    5786       24923 :                     continue;
    5787        3647 :                 if (nValue < nMin)
    5788           1 :                     nMin = nValue;
    5789        3647 :                 if (nValue > nMax)
    5790          13 :                     nMax = nValue;
    5791             :                 if constexpr (COMPUTE_OTHER_STATS)
    5792             :                 {
    5793         110 :                     nValidCount++;
    5794         110 :                     nSum += nValue;
    5795         110 :                     nSumSquare +=
    5796         110 :                         static_cast_for_coverity_scan<GUIntBig>(nValue) *
    5797         110 :                         nValue;
    5798             :                 }
    5799        1240 :             }
    5800             :         }
    5801       26820 :         else if (!bHasNoData && nXCheck == nBlockXSize && nBlockPixels >= 32)
    5802             :         {
    5803       15048 :             if (nMin > 0)
    5804             :             {
    5805        2079 :                 if (nMax < 255)
    5806             :                 {
    5807             :                     ComputeStatisticsByteNoNodata<true, true,
    5808        1550 :                                                   COMPUTE_OTHER_STATS>(
    5809             :                         nBlockPixels, pData, nMin, nMax, nSum, nSumSquare,
    5810             :                         nSampleCount, nValidCount);
    5811             :                 }
    5812             :                 else
    5813             :                 {
    5814             :                     ComputeStatisticsByteNoNodata<true, false,
    5815         529 :                                                   COMPUTE_OTHER_STATS>(
    5816             :                         nBlockPixels, pData, nMin, nMax, nSum, nSumSquare,
    5817             :                         nSampleCount, nValidCount);
    5818             :                 }
    5819             :             }
    5820             :             else
    5821             :             {
    5822       12969 :                 if (nMax < 255)
    5823             :                 {
    5824             :                     ComputeStatisticsByteNoNodata<false, true,
    5825        9502 :                                                   COMPUTE_OTHER_STATS>(
    5826             :                         nBlockPixels, pData, nMin, nMax, nSum, nSumSquare,
    5827             :                         nSampleCount, nValidCount);
    5828             :                 }
    5829             :                 else
    5830             :                 {
    5831             :                     ComputeStatisticsByteNoNodata<false, false,
    5832        3467 :                                                   COMPUTE_OTHER_STATS>(
    5833             :                         nBlockPixels, pData, nMin, nMax, nSum, nSumSquare,
    5834             :                         nSampleCount, nValidCount);
    5835             :                 }
    5836             :             }
    5837             :         }
    5838       10531 :         else if (!COMPUTE_OTHER_STATS && !bHasNoData && nXCheck >= 32 &&
    5839          27 :                  (nBlockXSize % 32) == 0)
    5840             :         {
    5841        3983 :             for (int iY = 0; iY < nYCheck; iY++)
    5842             :             {
    5843        3956 :                 ComputeStatisticsByteNoNodata<true, true, COMPUTE_OTHER_STATS>(
    5844        3956 :                     nXCheck, pData + static_cast<size_t>(iY) * nBlockXSize,
    5845             :                     nMin, nMax, nSum, nSumSquare, nSampleCount, nValidCount);
    5846          27 :             }
    5847             :         }
    5848             :         else
    5849             :         {
    5850       11745 :             ComputeStatisticsInternalGeneric<GByte, COMPUTE_OTHER_STATS>::f(
    5851             :                 nXCheck, nBlockXSize, nYCheck, pData, bHasNoData, nNoDataValue,
    5852             :                 nMin, nMax, nSum, nSumSquare, nSampleCount, nValidCount);
    5853             :         }
    5854       28061 :     }
    5855             : };
    5856             : 
    5857             : CPL_NOSANITIZE_UNSIGNED_INT_OVERFLOW
    5858         403 : static void UnshiftSumSquare(GUIntBig &nSumSquare, GUIntBig nSumThis,
    5859             :                              GUIntBig i)
    5860             : {
    5861         403 :     nSumSquare += 32768 * (2 * nSumThis - i * 32768);
    5862         403 : }
    5863             : 
    5864             : // AVX2/SSE2 optimization for GUInt16 case
    5865             : template <bool COMPUTE_OTHER_STATS>
    5866             : struct ComputeStatisticsInternal<GUInt16, COMPUTE_OTHER_STATS>
    5867             : {
    5868        1347 :     static void f(int nXCheck, int nBlockXSize, int nYCheck,
    5869             :                   // assumed to be aligned on 128 bits
    5870             :                   const GUInt16 *pData, bool bHasNoData, GUInt32 nNoDataValue,
    5871             :                   GUInt32 &nMin, GUInt32 &nMax, GUIntBig &nSum,
    5872             :                   GUIntBig &nSumSquare, GUIntBig &nSampleCount,
    5873             :                   GUIntBig &nValidCount)
    5874             :     {
    5875        1347 :         const auto nBlockPixels = static_cast<GPtrDiff_t>(nXCheck) * nYCheck;
    5876        1347 :         if (!bHasNoData && nXCheck == nBlockXSize && nBlockPixels >= 16)
    5877             :         {
    5878        1165 :             CPLAssert((reinterpret_cast<uintptr_t>(pData) % 16) == 0);
    5879             : 
    5880        1165 :             GPtrDiff_t i = 0;
    5881             :             // In SSE2, min_epu16 and max_epu16 do not exist, so shift from
    5882             :             // UInt16 to SInt16 to be able to use min_epi16 and max_epi16.
    5883             :             // Furthermore the shift is also needed to use madd_epi16
    5884        1165 :             const GDALm256i ymm_m32768 = GDALmm256_set1_epi16(-32768);
    5885        1165 :             GDALm256i ymm_min = GDALmm256_load_si256(
    5886        1165 :                 reinterpret_cast<const GDALm256i *>(pData + i));
    5887        1165 :             ymm_min = GDALmm256_add_epi16(ymm_min, ymm_m32768);
    5888        1165 :             GDALm256i ymm_max = ymm_min;
    5889             :             [[maybe_unused]] GDALm256i ymm_sumsquare =
    5890        1165 :                 ZERO256;  // holds 4 uint64 sums
    5891             : 
    5892             :             // Make sure that sum can fit on uint32
    5893             :             // * 8 since we can hold 8 sums per vector register
    5894        1165 :             const int nMaxIterationsPerInnerLoop =
    5895             :                 8 * ((std::numeric_limits<GUInt32>::max() / 65535) & ~15);
    5896        1165 :             GPtrDiff_t nOuterLoops = nBlockPixels / nMaxIterationsPerInnerLoop;
    5897        1165 :             if ((nBlockPixels % nMaxIterationsPerInnerLoop) != 0)
    5898        1165 :                 nOuterLoops++;
    5899             : 
    5900        1165 :             const bool bComputeMinMax = nMin > 0 || nMax < 65535;
    5901             :             [[maybe_unused]] const auto ymm_mask_16bits =
    5902        1165 :                 GDALmm256_set1_epi32(0xFFFF);
    5903             :             [[maybe_unused]] const auto ymm_mask_32bits =
    5904        1165 :                 GDALmm256_set1_epi64x(0xFFFFFFFF);
    5905             : 
    5906        1165 :             GUIntBig nSumThis = 0;
    5907        2354 :             for (int k = 0; k < nOuterLoops; k++)
    5908             :             {
    5909        1189 :                 const auto iMax =
    5910        1189 :                     std::min(nBlockPixels, i + nMaxIterationsPerInnerLoop);
    5911             : 
    5912             :                 [[maybe_unused]] GDALm256i ymm_sum =
    5913        1189 :                     ZERO256;  // holds 8 uint32 sums
    5914      959265 :                 for (; i + 15 < iMax; i += 16)
    5915             :                 {
    5916      958076 :                     const GDALm256i ymm = GDALmm256_load_si256(
    5917      958076 :                         reinterpret_cast<const GDALm256i *>(pData + i));
    5918             :                     const GDALm256i ymm_shifted =
    5919      958076 :                         GDALmm256_add_epi16(ymm, ymm_m32768);
    5920      958076 :                     if (bComputeMinMax)
    5921             :                     {
    5922      949057 :                         ymm_min = GDALmm256_min_epi16(ymm_min, ymm_shifted);
    5923      949057 :                         ymm_max = GDALmm256_max_epi16(ymm_max, ymm_shifted);
    5924             :                     }
    5925             : 
    5926             :                     if constexpr (COMPUTE_OTHER_STATS)
    5927             :                     {
    5928             :                         // Note: the int32 range can overflow for (0-32768)^2 +
    5929             :                         // (0-32768)^2 = 0x80000000, but as we know the result
    5930             :                         // is positive, this is OK as we interpret is a uint32.
    5931             :                         const GDALm256i ymm_square =
    5932       99250 :                             GDALmm256_madd_epi16(ymm_shifted, ymm_shifted);
    5933       99250 :                         ymm_sumsquare = GDALmm256_add_epi64(
    5934             :                             ymm_sumsquare,
    5935             :                             GDALmm256_and_si256(ymm_square, ymm_mask_32bits));
    5936       99250 :                         ymm_sumsquare = GDALmm256_add_epi64(
    5937             :                             ymm_sumsquare,
    5938             :                             GDALmm256_srli_epi64(ymm_square, 32));
    5939             : 
    5940             :                         // Now compute the sums
    5941       99250 :                         ymm_sum = GDALmm256_add_epi32(
    5942             :                             ymm_sum, GDALmm256_and_si256(ymm, ymm_mask_16bits));
    5943       99250 :                         ymm_sum = GDALmm256_add_epi32(
    5944             :                             ymm_sum, GDALmm256_srli_epi32(ymm, 16));
    5945             :                     }
    5946             :                 }
    5947             : 
    5948             :                 if constexpr (COMPUTE_OTHER_STATS)
    5949             :                 {
    5950             :                     GUInt32 anSum[8];
    5951         403 :                     GDALmm256_storeu_si256(reinterpret_cast<GDALm256i *>(anSum),
    5952             :                                            ymm_sum);
    5953         403 :                     nSumThis += static_cast<GUIntBig>(anSum[0]) + anSum[1] +
    5954         403 :                                 anSum[2] + anSum[3] + anSum[4] + anSum[5] +
    5955         403 :                                 anSum[6] + anSum[7];
    5956             :                 }
    5957             :             }
    5958             : 
    5959        1165 :             if (bComputeMinMax)
    5960             :             {
    5961             :                 GUInt16 anMin[16];
    5962             :                 GUInt16 anMax[16];
    5963             : 
    5964             :                 // Unshift the result
    5965        1124 :                 ymm_min = GDALmm256_sub_epi16(ymm_min, ymm_m32768);
    5966        1124 :                 ymm_max = GDALmm256_sub_epi16(ymm_max, ymm_m32768);
    5967        1124 :                 GDALmm256_storeu_si256(reinterpret_cast<GDALm256i *>(anMin),
    5968             :                                        ymm_min);
    5969        1124 :                 GDALmm256_storeu_si256(reinterpret_cast<GDALm256i *>(anMax),
    5970             :                                        ymm_max);
    5971       19108 :                 for (int j = 0; j < 16; j++)
    5972             :                 {
    5973       17984 :                     if (anMin[j] < nMin)
    5974         342 :                         nMin = anMin[j];
    5975       17984 :                     if (anMax[j] > nMax)
    5976         481 :                         nMax = anMax[j];
    5977             :                 }
    5978             :             }
    5979             : 
    5980             :             if constexpr (COMPUTE_OTHER_STATS)
    5981             :             {
    5982             :                 GUIntBig anSumSquare[4];
    5983         403 :                 GDALmm256_storeu_si256(
    5984             :                     reinterpret_cast<GDALm256i *>(anSumSquare), ymm_sumsquare);
    5985         403 :                 nSumSquare += anSumSquare[0] + anSumSquare[1] + anSumSquare[2] +
    5986             :                               anSumSquare[3];
    5987             : 
    5988             :                 // Unshift the sum of squares
    5989         403 :                 UnshiftSumSquare(nSumSquare, nSumThis,
    5990             :                                  static_cast<GUIntBig>(i));
    5991             : 
    5992         403 :                 nSum += nSumThis;
    5993             : 
    5994         725 :                 for (; i < nBlockPixels; i++)
    5995             :                 {
    5996         322 :                     const GUInt32 nValue = pData[i];
    5997         322 :                     if (nValue < nMin)
    5998           1 :                         nMin = nValue;
    5999         322 :                     if (nValue > nMax)
    6000           1 :                         nMax = nValue;
    6001         322 :                     nSum += nValue;
    6002         322 :                     nSumSquare +=
    6003         322 :                         static_cast_for_coverity_scan<GUIntBig>(nValue) *
    6004         322 :                         nValue;
    6005             :                 }
    6006             : 
    6007         403 :                 nSampleCount += static_cast<GUIntBig>(nXCheck) * nYCheck;
    6008         403 :                 nValidCount += static_cast<GUIntBig>(nXCheck) * nYCheck;
    6009        1165 :             }
    6010             :         }
    6011             :         else
    6012             :         {
    6013         182 :             ComputeStatisticsInternalGeneric<GUInt16, COMPUTE_OTHER_STATS>::f(
    6014             :                 nXCheck, nBlockXSize, nYCheck, pData, bHasNoData, nNoDataValue,
    6015             :                 nMin, nMax, nSum, nSumSquare, nSampleCount, nValidCount);
    6016             :         }
    6017        1347 :     }
    6018             : };
    6019             : 
    6020             : #endif
    6021             : // (defined(__x86_64__) || defined(_M_X64)) && (defined(__GNUC__) ||
    6022             : // defined(_MSC_VER))
    6023             : 
    6024             : #endif  // CPL_HAS_GINT64
    6025             : 
    6026             : /************************************************************************/
    6027             : /*                          GetPixelValue()                             */
    6028             : /************************************************************************/
    6029             : 
    6030    23163800 : static inline double GetPixelValue(GDALDataType eDataType, bool bSignedByte,
    6031             :                                    const void *pData, GPtrDiff_t iOffset,
    6032             :                                    bool bGotNoDataValue, double dfNoDataValue,
    6033             :                                    bool bGotFloatNoDataValue,
    6034             :                                    float fNoDataValue, bool &bValid)
    6035             : {
    6036    23163800 :     bValid = true;
    6037    23163800 :     double dfValue = 0;
    6038    23163800 :     switch (eDataType)
    6039             :     {
    6040     1413680 :         case GDT_Byte:
    6041             :         {
    6042     1413680 :             if (bSignedByte)
    6043         192 :                 dfValue = static_cast<const signed char *>(pData)[iOffset];
    6044             :             else
    6045     1413490 :                 dfValue = static_cast<const GByte *>(pData)[iOffset];
    6046     1413680 :             break;
    6047             :         }
    6048       10405 :         case GDT_Int8:
    6049       10405 :             dfValue = static_cast<const GInt8 *>(pData)[iOffset];
    6050       10405 :             break;
    6051        4000 :         case GDT_UInt16:
    6052        4000 :             dfValue = static_cast<const GUInt16 *>(pData)[iOffset];
    6053        4000 :             break;
    6054       60192 :         case GDT_Int16:
    6055       60192 :             dfValue = static_cast<const GInt16 *>(pData)[iOffset];
    6056       60192 :             break;
    6057       27596 :         case GDT_UInt32:
    6058       27596 :             dfValue = static_cast<const GUInt32 *>(pData)[iOffset];
    6059       27596 :             break;
    6060      460162 :         case GDT_Int32:
    6061      460162 :             dfValue = static_cast<const GInt32 *>(pData)[iOffset];
    6062      460162 :             break;
    6063        2598 :         case GDT_UInt64:
    6064        2598 :             dfValue = static_cast<double>(
    6065        2598 :                 static_cast<const std::uint64_t *>(pData)[iOffset]);
    6066        2598 :             break;
    6067        7398 :         case GDT_Int64:
    6068        7398 :             dfValue = static_cast<double>(
    6069        7398 :                 static_cast<const std::int64_t *>(pData)[iOffset]);
    6070        7398 :             break;
    6071    17483000 :         case GDT_Float32:
    6072             :         {
    6073    17483000 :             const float fValue = static_cast<const float *>(pData)[iOffset];
    6074    30693000 :             if (std::isnan(fValue) ||
    6075    13210000 :                 (bGotFloatNoDataValue && ARE_REAL_EQUAL(fValue, fNoDataValue)))
    6076             :             {
    6077      119863 :                 bValid = false;
    6078      119863 :                 return 0.0;
    6079             :             }
    6080    17363100 :             dfValue = fValue;
    6081    17363100 :             return dfValue;
    6082             :         }
    6083     3677660 :         case GDT_Float64:
    6084     3677660 :             dfValue = static_cast<const double *>(pData)[iOffset];
    6085     3677660 :             if (std::isnan(dfValue))
    6086             :             {
    6087          52 :                 bValid = false;
    6088          52 :                 return 0.0;
    6089             :             }
    6090     3677600 :             break;
    6091        2692 :         case GDT_CInt16:
    6092        2692 :             dfValue = static_cast<const GInt16 *>(pData)[iOffset * 2];
    6093        2692 :             break;
    6094        2692 :         case GDT_CInt32:
    6095        2692 :             dfValue = static_cast<const GInt32 *>(pData)[iOffset * 2];
    6096        2692 :             break;
    6097        5812 :         case GDT_CFloat32:
    6098        5812 :             dfValue = static_cast<const float *>(pData)[iOffset * 2];
    6099        5812 :             if (std::isnan(dfValue))
    6100             :             {
    6101           0 :                 bValid = false;
    6102           0 :                 return 0.0;
    6103             :             }
    6104        5812 :             break;
    6105        5892 :         case GDT_CFloat64:
    6106        5892 :             dfValue = static_cast<const double *>(pData)[iOffset * 2];
    6107        5892 :             if (std::isnan(dfValue))
    6108             :             {
    6109           0 :                 bValid = false;
    6110           0 :                 return 0.0;
    6111             :             }
    6112        5892 :             break;
    6113           0 :         case GDT_Unknown:
    6114             :         case GDT_TypeCount:
    6115           0 :             CPLAssert(false);
    6116             :             break;
    6117             :     }
    6118             : 
    6119     5680730 :     if (bGotNoDataValue && ARE_REAL_EQUAL(dfValue, dfNoDataValue))
    6120             :     {
    6121     3346220 :         bValid = false;
    6122     3346220 :         return 0.0;
    6123             :     }
    6124     2334500 :     return dfValue;
    6125             : }
    6126             : 
    6127             : /************************************************************************/
    6128             : /*                         SetValidPercent()                            */
    6129             : /************************************************************************/
    6130             : 
    6131             : //! @cond Doxygen_Suppress
    6132             : /**
    6133             :  * \brief Set percentage of valid (not nodata) pixels.
    6134             :  *
    6135             :  * Stores the percentage of valid pixels in the metadata item
    6136             :  * STATISTICS_VALID_PERCENT
    6137             :  *
    6138             :  * @param nSampleCount Number of sampled pixels.
    6139             :  *
    6140             :  * @param nValidCount Number of valid pixels.
    6141             :  */
    6142             : 
    6143         465 : void GDALRasterBand::SetValidPercent(GUIntBig nSampleCount,
    6144             :                                      GUIntBig nValidCount)
    6145             : {
    6146         465 :     if (nValidCount == 0)
    6147             :     {
    6148          12 :         SetMetadataItem("STATISTICS_VALID_PERCENT", "0");
    6149             :     }
    6150         453 :     else if (nValidCount == nSampleCount)
    6151             :     {
    6152         410 :         SetMetadataItem("STATISTICS_VALID_PERCENT", "100");
    6153             :     }
    6154             :     else /* nValidCount < nSampleCount */
    6155             :     {
    6156          43 :         char szValue[128] = {0};
    6157             : 
    6158             :         /* percentage is only an indicator: limit precision */
    6159          43 :         CPLsnprintf(szValue, sizeof(szValue), "%.4g",
    6160          43 :                     100. * static_cast<double>(nValidCount) / nSampleCount);
    6161             : 
    6162          43 :         if (EQUAL(szValue, "100"))
    6163             :         {
    6164             :             /* don't set 100 percent valid
    6165             :              * because some of the sampled pixels were nodata */
    6166           0 :             SetMetadataItem("STATISTICS_VALID_PERCENT", "99.999");
    6167             :         }
    6168             :         else
    6169             :         {
    6170          43 :             SetMetadataItem("STATISTICS_VALID_PERCENT", szValue);
    6171             :         }
    6172             :     }
    6173         464 : }
    6174             : 
    6175             : //! @endcond
    6176             : 
    6177             : /************************************************************************/
    6178             : /*                         ComputeStatistics()                          */
    6179             : /************************************************************************/
    6180             : 
    6181             : /**
    6182             :  * \brief Compute image statistics.
    6183             :  *
    6184             :  * Returns the minimum, maximum, mean and standard deviation of all
    6185             :  * pixel values in this band.  If approximate statistics are sufficient,
    6186             :  * the bApproxOK flag can be set to true in which case overviews, or a
    6187             :  * subset of image tiles may be used in computing the statistics.
    6188             :  *
    6189             :  * Once computed, the statistics will generally be "set" back on the
    6190             :  * raster band using SetStatistics().
    6191             :  *
    6192             :  * Cached statistics can be cleared with GDALDataset::ClearStatistics().
    6193             :  *
    6194             :  * This method is the same as the C function GDALComputeRasterStatistics().
    6195             :  *
    6196             :  * @param bApproxOK If TRUE statistics may be computed based on overviews
    6197             :  * or a subset of all tiles.
    6198             :  *
    6199             :  * @param pdfMin Location into which to load image minimum (may be NULL).
    6200             :  *
    6201             :  * @param pdfMax Location into which to load image maximum (may be NULL).-
    6202             :  *
    6203             :  * @param pdfMean Location into which to load image mean (may be NULL).
    6204             :  *
    6205             :  * @param pdfStdDev Location into which to load image standard deviation
    6206             :  * (may be NULL).
    6207             :  *
    6208             :  * @param pfnProgress a function to call to report progress, or NULL.
    6209             :  *
    6210             :  * @param pProgressData application data to pass to the progress function.
    6211             :  *
    6212             :  * @return CE_None on success, or CE_Failure if an error occurs or processing
    6213             :  * is terminated by the user.
    6214             :  */
    6215             : 
    6216         448 : CPLErr GDALRasterBand::ComputeStatistics(int bApproxOK, double *pdfMin,
    6217             :                                          double *pdfMax, double *pdfMean,
    6218             :                                          double *pdfStdDev,
    6219             :                                          GDALProgressFunc pfnProgress,
    6220             :                                          void *pProgressData)
    6221             : 
    6222             : {
    6223         448 :     if (pfnProgress == nullptr)
    6224         154 :         pfnProgress = GDALDummyProgress;
    6225             : 
    6226             :     /* -------------------------------------------------------------------- */
    6227             :     /*      If we have overview bands, use them for statistics.             */
    6228             :     /* -------------------------------------------------------------------- */
    6229         448 :     if (bApproxOK && GetOverviewCount() > 0 && !HasArbitraryOverviews())
    6230             :     {
    6231             :         GDALRasterBand *poBand =
    6232           3 :             GetRasterSampleOverview(GDALSTAT_APPROX_NUMSAMPLES);
    6233             : 
    6234           3 :         if (poBand != this)
    6235             :         {
    6236           6 :             CPLErr eErr = poBand->ComputeStatistics(FALSE, pdfMin, pdfMax,
    6237             :                                                     pdfMean, pdfStdDev,
    6238           3 :                                                     pfnProgress, pProgressData);
    6239           3 :             if (eErr == CE_None)
    6240             :             {
    6241           3 :                 if (pdfMin && pdfMax && pdfMean && pdfStdDev)
    6242             :                 {
    6243           3 :                     SetMetadataItem("STATISTICS_APPROXIMATE", "YES");
    6244           3 :                     SetStatistics(*pdfMin, *pdfMax, *pdfMean, *pdfStdDev);
    6245             :                 }
    6246             : 
    6247             :                 /* transfer metadata from overview band to this */
    6248             :                 const char *pszPercentValid =
    6249           3 :                     poBand->GetMetadataItem("STATISTICS_VALID_PERCENT");
    6250             : 
    6251           3 :                 if (pszPercentValid != nullptr)
    6252             :                 {
    6253           3 :                     SetMetadataItem("STATISTICS_VALID_PERCENT",
    6254           3 :                                     pszPercentValid);
    6255             :                 }
    6256             :             }
    6257           3 :             return eErr;
    6258             :         }
    6259             :     }
    6260             : 
    6261         445 :     if (!pfnProgress(0.0, "Compute Statistics", pProgressData))
    6262             :     {
    6263           0 :         ReportError(CE_Failure, CPLE_UserInterrupt, "User terminated");
    6264           0 :         return CE_Failure;
    6265             :     }
    6266             : 
    6267             :     /* -------------------------------------------------------------------- */
    6268             :     /*      Read actual data and compute statistics.                        */
    6269             :     /* -------------------------------------------------------------------- */
    6270             :     // Using Welford algorithm:
    6271             :     // http://en.wikipedia.org/wiki/Algorithms_for_calculating_variance
    6272             :     // to compute standard deviation in a more numerically robust way than
    6273             :     // the difference of the sum of square values with the square of the sum.
    6274             :     // dfMean and dfM2 are updated at each sample.
    6275             :     // dfM2 is the sum of square of differences to the current mean.
    6276         445 :     double dfMin = std::numeric_limits<double>::max();
    6277         445 :     double dfMax = -std::numeric_limits<double>::max();
    6278         445 :     double dfMean = 0.0;
    6279         445 :     double dfM2 = 0.0;
    6280             : 
    6281             :     GDALRasterIOExtraArg sExtraArg;
    6282         445 :     INIT_RASTERIO_EXTRA_ARG(sExtraArg);
    6283             : 
    6284         445 :     int bGotNoDataValue = FALSE;
    6285         445 :     const double dfNoDataValue = GetNoDataValue(&bGotNoDataValue);
    6286         445 :     bGotNoDataValue = bGotNoDataValue && !std::isnan(dfNoDataValue);
    6287         445 :     bool bGotFloatNoDataValue = false;
    6288         445 :     float fNoDataValue = 0.0f;
    6289         445 :     ComputeFloatNoDataValue(eDataType, dfNoDataValue, bGotNoDataValue,
    6290             :                             fNoDataValue, bGotFloatNoDataValue);
    6291             : 
    6292         445 :     GDALRasterBand *poMaskBand = nullptr;
    6293         445 :     if (!bGotNoDataValue)
    6294             :     {
    6295         420 :         const int l_nMaskFlags = GetMaskFlags();
    6296         436 :         if (l_nMaskFlags != GMF_ALL_VALID && l_nMaskFlags != GMF_NODATA &&
    6297          16 :             GetColorInterpretation() != GCI_AlphaBand)
    6298             :         {
    6299          16 :             poMaskBand = GetMaskBand();
    6300             :         }
    6301             :     }
    6302             : 
    6303         445 :     bool bSignedByte = false;
    6304         445 :     if (eDataType == GDT_Byte)
    6305             :     {
    6306         194 :         EnablePixelTypeSignedByteWarning(false);
    6307             :         const char *pszPixelType =
    6308         194 :             GetMetadataItem("PIXELTYPE", "IMAGE_STRUCTURE");
    6309         194 :         EnablePixelTypeSignedByteWarning(true);
    6310         194 :         bSignedByte =
    6311         194 :             pszPixelType != nullptr && EQUAL(pszPixelType, "SIGNEDBYTE");
    6312             :     }
    6313             : 
    6314         445 :     GUIntBig nSampleCount = 0;
    6315         445 :     GUIntBig nValidCount = 0;
    6316             : 
    6317         445 :     if (bApproxOK && HasArbitraryOverviews())
    6318             :     {
    6319             :         /* --------------------------------------------------------------------
    6320             :          */
    6321             :         /*      Figure out how much the image should be reduced to get an */
    6322             :         /*      approximate value. */
    6323             :         /* --------------------------------------------------------------------
    6324             :          */
    6325           0 :         double dfReduction = sqrt(static_cast<double>(nRasterXSize) *
    6326           0 :                                   nRasterYSize / GDALSTAT_APPROX_NUMSAMPLES);
    6327             : 
    6328           0 :         int nXReduced = nRasterXSize;
    6329           0 :         int nYReduced = nRasterYSize;
    6330           0 :         if (dfReduction > 1.0)
    6331             :         {
    6332           0 :             nXReduced = static_cast<int>(nRasterXSize / dfReduction);
    6333           0 :             nYReduced = static_cast<int>(nRasterYSize / dfReduction);
    6334             : 
    6335             :             // Catch the case of huge resizing ratios here
    6336           0 :             if (nXReduced == 0)
    6337           0 :                 nXReduced = 1;
    6338           0 :             if (nYReduced == 0)
    6339           0 :                 nYReduced = 1;
    6340             :         }
    6341             : 
    6342           0 :         void *pData = CPLMalloc(cpl::fits_on<int>(
    6343           0 :             GDALGetDataTypeSizeBytes(eDataType) * nXReduced * nYReduced));
    6344             : 
    6345             :         const CPLErr eErr =
    6346           0 :             IRasterIO(GF_Read, 0, 0, nRasterXSize, nRasterYSize, pData,
    6347           0 :                       nXReduced, nYReduced, eDataType, 0, 0, &sExtraArg);
    6348           0 :         if (eErr != CE_None)
    6349             :         {
    6350           0 :             CPLFree(pData);
    6351           0 :             return eErr;
    6352             :         }
    6353             : 
    6354           0 :         GByte *pabyMaskData = nullptr;
    6355           0 :         if (poMaskBand)
    6356             :         {
    6357             :             pabyMaskData =
    6358           0 :                 static_cast<GByte *>(VSI_MALLOC2_VERBOSE(nXReduced, nYReduced));
    6359           0 :             if (!pabyMaskData)
    6360             :             {
    6361           0 :                 CPLFree(pData);
    6362           0 :                 return CE_Failure;
    6363             :             }
    6364             : 
    6365           0 :             if (poMaskBand->RasterIO(GF_Read, 0, 0, nRasterXSize, nRasterYSize,
    6366             :                                      pabyMaskData, nXReduced, nYReduced,
    6367           0 :                                      GDT_Byte, 0, 0, nullptr) != CE_None)
    6368             :             {
    6369           0 :                 CPLFree(pData);
    6370           0 :                 CPLFree(pabyMaskData);
    6371           0 :                 return CE_Failure;
    6372             :             }
    6373             :         }
    6374             : 
    6375             :         /* this isn't the fastest way to do this, but is easier for now */
    6376           0 :         for (int iY = 0; iY < nYReduced; iY++)
    6377             :         {
    6378           0 :             for (int iX = 0; iX < nXReduced; iX++)
    6379             :             {
    6380           0 :                 const int iOffset = iX + iY * nXReduced;
    6381           0 :                 if (pabyMaskData && pabyMaskData[iOffset] == 0)
    6382           0 :                     continue;
    6383             : 
    6384           0 :                 bool bValid = true;
    6385             :                 double dfValue =
    6386           0 :                     GetPixelValue(eDataType, bSignedByte, pData, iOffset,
    6387           0 :                                   CPL_TO_BOOL(bGotNoDataValue), dfNoDataValue,
    6388           0 :                                   bGotFloatNoDataValue, fNoDataValue, bValid);
    6389           0 :                 if (!bValid)
    6390           0 :                     continue;
    6391             : 
    6392           0 :                 dfMin = std::min(dfMin, dfValue);
    6393           0 :                 dfMax = std::max(dfMax, dfValue);
    6394             : 
    6395           0 :                 nValidCount++;
    6396           0 :                 const double dfDelta = dfValue - dfMean;
    6397           0 :                 dfMean += dfDelta / nValidCount;
    6398           0 :                 dfM2 += dfDelta * (dfValue - dfMean);
    6399             :             }
    6400             :         }
    6401             : 
    6402           0 :         nSampleCount = static_cast<GUIntBig>(nXReduced) * nYReduced;
    6403             : 
    6404           0 :         CPLFree(pData);
    6405           0 :         CPLFree(pabyMaskData);
    6406             :     }
    6407             : 
    6408             :     else  // No arbitrary overviews.
    6409             :     {
    6410         445 :         if (!InitBlockInfo())
    6411           0 :             return CE_Failure;
    6412             : 
    6413             :         /* --------------------------------------------------------------------
    6414             :          */
    6415             :         /*      Figure out the ratio of blocks we will read to get an */
    6416             :         /*      approximate value. */
    6417             :         /* --------------------------------------------------------------------
    6418             :          */
    6419         444 :         int nSampleRate = 1;
    6420         444 :         if (bApproxOK)
    6421             :         {
    6422          40 :             nSampleRate = static_cast<int>(std::max(
    6423          80 :                 1.0,
    6424          40 :                 sqrt(static_cast<double>(nBlocksPerRow) * nBlocksPerColumn)));
    6425             :             // We want to avoid probing only the first column of blocks for
    6426             :             // a square shaped raster, because it is not unlikely that it may
    6427             :             // be padding only (#6378)
    6428          40 :             if (nSampleRate == nBlocksPerRow && nBlocksPerRow > 1)
    6429           2 :                 nSampleRate += 1;
    6430             :         }
    6431         444 :         if (nSampleRate == 1)
    6432         412 :             bApproxOK = false;
    6433             : 
    6434             : #ifdef CPL_HAS_GINT64
    6435             :         // Particular case for GDT_Byte that only use integral types for all
    6436             :         // intermediate computations. Only possible if the number of pixels
    6437             :         // explored is lower than GUINTBIG_MAX / (255*255), so that nSumSquare
    6438             :         // can fit on a uint64. Should be 99.99999% of cases.
    6439             :         // For GUInt16, this limits to raster of 4 giga pixels
    6440         444 :         if ((!poMaskBand && eDataType == GDT_Byte && !bSignedByte &&
    6441         178 :              static_cast<GUIntBig>(nBlocksPerRow) * nBlocksPerColumn /
    6442         178 :                      nSampleRate <
    6443         178 :                  GUINTBIG_MAX / (255U * 255U) /
    6444         178 :                      (static_cast<GUInt64>(nBlockXSize) *
    6445         178 :                       static_cast<GUInt64>(nBlockYSize))) ||
    6446         266 :             (eDataType == GDT_UInt16 &&
    6447          28 :              static_cast<GUIntBig>(nBlocksPerRow) * nBlocksPerColumn /
    6448          28 :                      nSampleRate <
    6449          28 :                  GUINTBIG_MAX / (65535U * 65535U) /
    6450          28 :                      (static_cast<GUInt64>(nBlockXSize) *
    6451          28 :                       static_cast<GUInt64>(nBlockYSize))))
    6452             :         {
    6453         206 :             const GUInt32 nMaxValueType = (eDataType == GDT_Byte) ? 255 : 65535;
    6454         206 :             GUInt32 nMin = nMaxValueType;
    6455         206 :             GUInt32 nMax = 0;
    6456         206 :             GUIntBig nSum = 0;
    6457         206 :             GUIntBig nSumSquare = 0;
    6458             :             // If no valid nodata, map to invalid value (256 for Byte)
    6459         206 :             const GUInt32 nNoDataValue =
    6460          20 :                 (bGotNoDataValue && dfNoDataValue >= 0 &&
    6461          20 :                  dfNoDataValue <= nMaxValueType &&
    6462          20 :                  fabs(dfNoDataValue -
    6463          20 :                       static_cast<GUInt32>(dfNoDataValue + 1e-10)) < 1e-10)
    6464         226 :                     ? static_cast<GUInt32>(dfNoDataValue + 1e-10)
    6465             :                     : nMaxValueType + 1;
    6466             : 
    6467         206 :             for (GIntBig iSampleBlock = 0;
    6468       12589 :                  iSampleBlock <
    6469       12589 :                  static_cast<GIntBig>(nBlocksPerRow) * nBlocksPerColumn;
    6470       12383 :                  iSampleBlock += nSampleRate)
    6471             :             {
    6472       12382 :                 const int iYBlock =
    6473       12382 :                     static_cast<int>(iSampleBlock / nBlocksPerRow);
    6474       12382 :                 const int iXBlock =
    6475       12382 :                     static_cast<int>(iSampleBlock % nBlocksPerRow);
    6476             : 
    6477             :                 GDALRasterBlock *const poBlock =
    6478       12382 :                     GetLockedBlockRef(iXBlock, iYBlock);
    6479       12381 :                 if (poBlock == nullptr)
    6480           0 :                     return CE_Failure;
    6481             : 
    6482       12381 :                 void *const pData = poBlock->GetDataRef();
    6483             : 
    6484       12381 :                 int nXCheck = 0, nYCheck = 0;
    6485       12381 :                 GetActualBlockSize(iXBlock, iYBlock, &nXCheck, &nYCheck);
    6486             : 
    6487       12381 :                 if (eDataType == GDT_Byte)
    6488             :                 {
    6489             :                     ComputeStatisticsInternal<
    6490             :                         GByte, /* COMPUTE_OTHER_STATS = */ true>::
    6491       11924 :                         f(nXCheck, nBlockXSize, nYCheck,
    6492             :                           static_cast<const GByte *>(pData),
    6493             :                           nNoDataValue <= nMaxValueType, nNoDataValue, nMin,
    6494             :                           nMax, nSum, nSumSquare, nSampleCount, nValidCount);
    6495             :                 }
    6496             :                 else
    6497             :                 {
    6498             :                     ComputeStatisticsInternal<
    6499             :                         GUInt16, /* COMPUTE_OTHER_STATS = */ true>::
    6500         457 :                         f(nXCheck, nBlockXSize, nYCheck,
    6501             :                           static_cast<const GUInt16 *>(pData),
    6502             :                           nNoDataValue <= nMaxValueType, nNoDataValue, nMin,
    6503             :                           nMax, nSum, nSumSquare, nSampleCount, nValidCount);
    6504             :                 }
    6505             : 
    6506       12379 :                 poBlock->DropLock();
    6507             : 
    6508       12380 :                 if (!pfnProgress(static_cast<double>(iSampleBlock) /
    6509       12383 :                                      (static_cast<double>(nBlocksPerRow) *
    6510       12383 :                                       nBlocksPerColumn),
    6511             :                                  "Compute Statistics", pProgressData))
    6512             :                 {
    6513           0 :                     ReportError(CE_Failure, CPLE_UserInterrupt,
    6514             :                                 "User terminated");
    6515           0 :                     return CE_Failure;
    6516             :                 }
    6517             :             }
    6518             : 
    6519         207 :             if (!pfnProgress(1.0, "Compute Statistics", pProgressData))
    6520             :             {
    6521           0 :                 ReportError(CE_Failure, CPLE_UserInterrupt, "User terminated");
    6522           0 :                 return CE_Failure;
    6523             :             }
    6524             : 
    6525             :             /* --------------------------------------------------------------------
    6526             :              */
    6527             :             /*      Save computed information. */
    6528             :             /* --------------------------------------------------------------------
    6529             :              */
    6530         207 :             if (nValidCount)
    6531         198 :                 dfMean = static_cast<double>(nSum) / nValidCount;
    6532             : 
    6533             :             // To avoid potential precision issues when doing the difference,
    6534             :             // we need to do that computation on 128 bit rather than casting
    6535             :             // to double
    6536             :             const GDALUInt128 nTmpForStdDev(
    6537         207 :                 GDALUInt128::Mul(nSumSquare, nValidCount) -
    6538         414 :                 GDALUInt128::Mul(nSum, nSum));
    6539             :             const double dfStdDev =
    6540         207 :                 nValidCount > 0
    6541         207 :                     ? sqrt(static_cast<double>(nTmpForStdDev)) / nValidCount
    6542         207 :                     : 0.0;
    6543             : 
    6544         207 :             if (nValidCount > 0)
    6545             :             {
    6546         198 :                 if (bApproxOK)
    6547             :                 {
    6548          23 :                     SetMetadataItem("STATISTICS_APPROXIMATE", "YES");
    6549             :                 }
    6550         175 :                 else if (GetMetadataItem("STATISTICS_APPROXIMATE"))
    6551             :                 {
    6552           3 :                     SetMetadataItem("STATISTICS_APPROXIMATE", nullptr);
    6553             :                 }
    6554         198 :                 SetStatistics(nMin, nMax, dfMean, dfStdDev);
    6555             :             }
    6556             : 
    6557         207 :             SetValidPercent(nSampleCount, nValidCount);
    6558             : 
    6559             :             /* --------------------------------------------------------------------
    6560             :              */
    6561             :             /*      Record results. */
    6562             :             /* --------------------------------------------------------------------
    6563             :              */
    6564         206 :             if (pdfMin != nullptr)
    6565         203 :                 *pdfMin = nValidCount ? nMin : 0;
    6566         206 :             if (pdfMax != nullptr)
    6567         203 :                 *pdfMax = nValidCount ? nMax : 0;
    6568             : 
    6569         206 :             if (pdfMean != nullptr)
    6570         199 :                 *pdfMean = dfMean;
    6571             : 
    6572         206 :             if (pdfStdDev != nullptr)
    6573         199 :                 *pdfStdDev = dfStdDev;
    6574             : 
    6575         206 :             if (nValidCount > 0)
    6576         198 :                 return CE_None;
    6577             : 
    6578           8 :             ReportError(CE_Failure, CPLE_AppDefined,
    6579             :                         "Failed to compute statistics, no valid pixels found "
    6580             :                         "in sampling.");
    6581           9 :             return CE_Failure;
    6582             :         }
    6583             : #endif
    6584             : 
    6585         238 :         GByte *pabyMaskData = nullptr;
    6586         238 :         if (poMaskBand)
    6587             :         {
    6588             :             pabyMaskData = static_cast<GByte *>(
    6589          16 :                 VSI_MALLOC2_VERBOSE(nBlockXSize, nBlockYSize));
    6590          16 :             if (!pabyMaskData)
    6591             :             {
    6592           0 :                 return CE_Failure;
    6593             :             }
    6594             :         }
    6595             : 
    6596         238 :         for (GIntBig iSampleBlock = 0;
    6597        5489 :              iSampleBlock <
    6598        5489 :              static_cast<GIntBig>(nBlocksPerRow) * nBlocksPerColumn;
    6599        5251 :              iSampleBlock += nSampleRate)
    6600             :         {
    6601        5251 :             const int iYBlock = static_cast<int>(iSampleBlock / nBlocksPerRow);
    6602        5251 :             const int iXBlock = static_cast<int>(iSampleBlock % nBlocksPerRow);
    6603             : 
    6604             :             GDALRasterBlock *const poBlock =
    6605        5251 :                 GetLockedBlockRef(iXBlock, iYBlock);
    6606        5251 :             if (poBlock == nullptr)
    6607             :             {
    6608           0 :                 CPLFree(pabyMaskData);
    6609           0 :                 return CE_Failure;
    6610             :             }
    6611             : 
    6612        5251 :             void *const pData = poBlock->GetDataRef();
    6613             : 
    6614        5251 :             int nXCheck = 0, nYCheck = 0;
    6615        5251 :             GetActualBlockSize(iXBlock, iYBlock, &nXCheck, &nYCheck);
    6616             : 
    6617        5352 :             if (poMaskBand &&
    6618         101 :                 poMaskBand->RasterIO(GF_Read, iXBlock * nBlockXSize,
    6619         101 :                                      iYBlock * nBlockYSize, nXCheck, nYCheck,
    6620             :                                      pabyMaskData, nXCheck, nYCheck, GDT_Byte,
    6621         101 :                                      0, nBlockXSize, nullptr) != CE_None)
    6622             :             {
    6623           0 :                 CPLFree(pabyMaskData);
    6624           0 :                 poBlock->DropLock();
    6625           0 :                 return CE_Failure;
    6626             :             }
    6627             : 
    6628             :             // This isn't the fastest way to do this, but is easier for now.
    6629       10686 :             for (int iY = 0; iY < nYCheck; iY++)
    6630             :             {
    6631     4342140 :                 for (int iX = 0; iX < nXCheck; iX++)
    6632             :                 {
    6633     4336710 :                     const GPtrDiff_t iOffset =
    6634     4336710 :                         iX + static_cast<GPtrDiff_t>(iY) * nBlockXSize;
    6635     4336710 :                     if (pabyMaskData && pabyMaskData[iOffset] == 0)
    6636      109941 :                         continue;
    6637             : 
    6638     4326840 :                     bool bValid = true;
    6639     4326840 :                     double dfValue = GetPixelValue(
    6640             :                         eDataType, bSignedByte, pData, iOffset,
    6641     4326840 :                         CPL_TO_BOOL(bGotNoDataValue), dfNoDataValue,
    6642     4326840 :                         bGotFloatNoDataValue, fNoDataValue, bValid);
    6643             : 
    6644     4326840 :                     if (!bValid)
    6645      100070 :                         continue;
    6646             : 
    6647     4226770 :                     dfMin = std::min(dfMin, dfValue);
    6648     4226770 :                     dfMax = std::max(dfMax, dfValue);
    6649             : 
    6650     4226770 :                     nValidCount++;
    6651     4226770 :                     const double dfDelta = dfValue - dfMean;
    6652     4226770 :                     dfMean += dfDelta / nValidCount;
    6653     4226770 :                     dfM2 += dfDelta * (dfValue - dfMean);
    6654             :                 }
    6655             :             }
    6656             : 
    6657        5251 :             nSampleCount += static_cast<GUIntBig>(nXCheck) * nYCheck;
    6658             : 
    6659        5251 :             poBlock->DropLock();
    6660             : 
    6661        5251 :             if (!pfnProgress(
    6662        5251 :                     static_cast<double>(iSampleBlock) /
    6663        5251 :                         (static_cast<double>(nBlocksPerRow) * nBlocksPerColumn),
    6664             :                     "Compute Statistics", pProgressData))
    6665             :             {
    6666           0 :                 ReportError(CE_Failure, CPLE_UserInterrupt, "User terminated");
    6667           0 :                 CPLFree(pabyMaskData);
    6668           0 :                 return CE_Failure;
    6669             :             }
    6670             :         }
    6671             : 
    6672         238 :         CPLFree(pabyMaskData);
    6673             :     }
    6674             : 
    6675         238 :     if (!pfnProgress(1.0, "Compute Statistics", pProgressData))
    6676             :     {
    6677           0 :         ReportError(CE_Failure, CPLE_UserInterrupt, "User terminated");
    6678           0 :         return CE_Failure;
    6679             :     }
    6680             : 
    6681             :     /* -------------------------------------------------------------------- */
    6682             :     /*      Save computed information.                                      */
    6683             :     /* -------------------------------------------------------------------- */
    6684         238 :     const double dfStdDev = nValidCount > 0 ? sqrt(dfM2 / nValidCount) : 0.0;
    6685             : 
    6686         238 :     if (nValidCount > 0)
    6687             :     {
    6688         237 :         if (bApproxOK)
    6689             :         {
    6690           8 :             SetMetadataItem("STATISTICS_APPROXIMATE", "YES");
    6691             :         }
    6692         229 :         else if (GetMetadataItem("STATISTICS_APPROXIMATE"))
    6693             :         {
    6694           2 :             SetMetadataItem("STATISTICS_APPROXIMATE", nullptr);
    6695             :         }
    6696         237 :         SetStatistics(dfMin, dfMax, dfMean, dfStdDev);
    6697             :     }
    6698             :     else
    6699             :     {
    6700           1 :         dfMin = 0.0;
    6701           1 :         dfMax = 0.0;
    6702             :     }
    6703             : 
    6704         238 :     SetValidPercent(nSampleCount, nValidCount);
    6705             : 
    6706             :     /* -------------------------------------------------------------------- */
    6707             :     /*      Record results.                                                 */
    6708             :     /* -------------------------------------------------------------------- */
    6709         238 :     if (pdfMin != nullptr)
    6710         235 :         *pdfMin = dfMin;
    6711         238 :     if (pdfMax != nullptr)
    6712         235 :         *pdfMax = dfMax;
    6713             : 
    6714         238 :     if (pdfMean != nullptr)
    6715         233 :         *pdfMean = dfMean;
    6716             : 
    6717         238 :     if (pdfStdDev != nullptr)
    6718         233 :         *pdfStdDev = dfStdDev;
    6719             : 
    6720         238 :     if (nValidCount > 0)
    6721         237 :         return CE_None;
    6722             : 
    6723           1 :     ReportError(
    6724             :         CE_Failure, CPLE_AppDefined,
    6725             :         "Failed to compute statistics, no valid pixels found in sampling.");
    6726           1 :     return CE_Failure;
    6727             : }
    6728             : 
    6729             : /************************************************************************/
    6730             : /*                    GDALComputeRasterStatistics()                     */
    6731             : /************************************************************************/
    6732             : 
    6733             : /**
    6734             :  * \brief Compute image statistics.
    6735             :  *
    6736             :  * @see GDALRasterBand::ComputeStatistics()
    6737             :  */
    6738             : 
    6739         141 : CPLErr CPL_STDCALL GDALComputeRasterStatistics(GDALRasterBandH hBand,
    6740             :                                                int bApproxOK, double *pdfMin,
    6741             :                                                double *pdfMax, double *pdfMean,
    6742             :                                                double *pdfStdDev,
    6743             :                                                GDALProgressFunc pfnProgress,
    6744             :                                                void *pProgressData)
    6745             : 
    6746             : {
    6747         141 :     VALIDATE_POINTER1(hBand, "GDALComputeRasterStatistics", CE_Failure);
    6748             : 
    6749         141 :     GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
    6750             : 
    6751         141 :     return poBand->ComputeStatistics(bApproxOK, pdfMin, pdfMax, pdfMean,
    6752         141 :                                      pdfStdDev, pfnProgress, pProgressData);
    6753             : }
    6754             : 
    6755             : /************************************************************************/
    6756             : /*                           SetStatistics()                            */
    6757             : /************************************************************************/
    6758             : 
    6759             : /**
    6760             :  * \brief Set statistics on band.
    6761             :  *
    6762             :  * This method can be used to store min/max/mean/standard deviation
    6763             :  * statistics on a raster band.
    6764             :  *
    6765             :  * The default implementation stores them as metadata, and will only work
    6766             :  * on formats that can save arbitrary metadata.  This method cannot detect
    6767             :  * whether metadata will be properly saved and so may return CE_None even
    6768             :  * if the statistics will never be saved.
    6769             :  *
    6770             :  * This method is the same as the C function GDALSetRasterStatistics().
    6771             :  *
    6772             :  * @param dfMin minimum pixel value.
    6773             :  *
    6774             :  * @param dfMax maximum pixel value.
    6775             :  *
    6776             :  * @param dfMean mean (average) of all pixel values.
    6777             :  *
    6778             :  * @param dfStdDev Standard deviation of all pixel values.
    6779             :  *
    6780             :  * @return CE_None on success or CE_Failure on failure.
    6781             :  */
    6782             : 
    6783         463 : CPLErr GDALRasterBand::SetStatistics(double dfMin, double dfMax, double dfMean,
    6784             :                                      double dfStdDev)
    6785             : 
    6786             : {
    6787         463 :     char szValue[128] = {0};
    6788             : 
    6789         463 :     CPLsnprintf(szValue, sizeof(szValue), "%.14g", dfMin);
    6790         463 :     SetMetadataItem("STATISTICS_MINIMUM", szValue);
    6791             : 
    6792         463 :     CPLsnprintf(szValue, sizeof(szValue), "%.14g", dfMax);
    6793         463 :     SetMetadataItem("STATISTICS_MAXIMUM", szValue);
    6794             : 
    6795         463 :     CPLsnprintf(szValue, sizeof(szValue), "%.14g", dfMean);
    6796         463 :     SetMetadataItem("STATISTICS_MEAN", szValue);
    6797             : 
    6798         463 :     CPLsnprintf(szValue, sizeof(szValue), "%.14g", dfStdDev);
    6799         462 :     SetMetadataItem("STATISTICS_STDDEV", szValue);
    6800             : 
    6801         463 :     return CE_None;
    6802             : }
    6803             : 
    6804             : /************************************************************************/
    6805             : /*                      GDALSetRasterStatistics()                       */
    6806             : /************************************************************************/
    6807             : 
    6808             : /**
    6809             :  * \brief Set statistics on band.
    6810             :  *
    6811             :  * @see GDALRasterBand::SetStatistics()
    6812             :  */
    6813             : 
    6814           2 : CPLErr CPL_STDCALL GDALSetRasterStatistics(GDALRasterBandH hBand, double dfMin,
    6815             :                                            double dfMax, double dfMean,
    6816             :                                            double dfStdDev)
    6817             : 
    6818             : {
    6819           2 :     VALIDATE_POINTER1(hBand, "GDALSetRasterStatistics", CE_Failure);
    6820             : 
    6821           2 :     GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
    6822           2 :     return poBand->SetStatistics(dfMin, dfMax, dfMean, dfStdDev);
    6823             : }
    6824             : 
    6825             : /************************************************************************/
    6826             : /*                        ComputeRasterMinMax()                         */
    6827             : /************************************************************************/
    6828             : 
    6829             : template <class T, bool HAS_NODATA>
    6830      134689 : static void ComputeMinMax(const T *buffer, size_t nElts, T nodataValue, T *pMin,
    6831             :                           T *pMax)
    6832             : {
    6833      134689 :     T min0 = *pMin;
    6834      134689 :     T max0 = *pMax;
    6835      134689 :     T min1 = *pMin;
    6836      134689 :     T max1 = *pMax;
    6837             :     size_t i;
    6838     1017014 :     for (i = 0; i + 1 < nElts; i += 2)
    6839             :     {
    6840      869734 :         if (!HAS_NODATA || buffer[i] != nodataValue)
    6841             :         {
    6842      881141 :             min0 = std::min(min0, buffer[i]);
    6843      881141 :             max0 = std::max(max0, buffer[i]);
    6844             :         }
    6845      869734 :         if (!HAS_NODATA || buffer[i + 1] != nodataValue)
    6846             :         {
    6847      881354 :             min1 = std::min(min1, buffer[i + 1]);
    6848      881354 :             max1 = std::max(max1, buffer[i + 1]);
    6849             :         }
    6850             :     }
    6851      134689 :     T min = std::min(min0, min1);
    6852      134689 :     T max = std::max(max0, max1);
    6853      134689 :     if (i < nElts)
    6854             :     {
    6855      119260 :         if (!HAS_NODATA || buffer[i] != nodataValue)
    6856             :         {
    6857      119276 :             min = std::min(min, buffer[i]);
    6858      119276 :             max = std::max(max, buffer[i]);
    6859             :         }
    6860             :     }
    6861      134689 :     *pMin = min;
    6862      134689 :     *pMax = max;
    6863      134689 : }
    6864             : 
    6865             : template <GDALDataType eDataType, bool bSignedByte>
    6866       11502 : static void ComputeMinMaxGeneric(const void *pData, int nXCheck, int nYCheck,
    6867             :                                  int nBlockXSize, bool bGotNoDataValue,
    6868             :                                  double dfNoDataValue,
    6869             :                                  bool bGotFloatNoDataValue, float fNoDataValue,
    6870             :                                  const GByte *pabyMaskData, double &dfMin,
    6871             :                                  double &dfMax)
    6872             : {
    6873       11502 :     double dfLocalMin = dfMin;
    6874       11502 :     double dfLocalMax = dfMax;
    6875             : 
    6876       43357 :     for (int iY = 0; iY < nYCheck; iY++)
    6877             :     {
    6878    18963015 :         for (int iX = 0; iX < nXCheck; iX++)
    6879             :         {
    6880    18931157 :             const GPtrDiff_t iOffset =
    6881    18931157 :                 iX + static_cast<GPtrDiff_t>(iY) * nBlockXSize;
    6882    18931157 :             if (pabyMaskData && pabyMaskData[iOffset] == 0)
    6883     3460307 :                 continue;
    6884    18836916 :             bool bValid = true;
    6885    18836916 :             double dfValue = GetPixelValue(
    6886             :                 eDataType, bSignedByte, pData, iOffset, bGotNoDataValue,
    6887             :                 dfNoDataValue, bGotFloatNoDataValue, fNoDataValue, bValid);
    6888    18836916 :             if (!bValid)
    6889     3366066 :                 continue;
    6890             : 
    6891    15470809 :             dfLocalMin = std::min(dfLocalMin, dfValue);
    6892    15470809 :             dfLocalMax = std::max(dfLocalMax, dfValue);
    6893             :         }
    6894             :     }
    6895             : 
    6896       11502 :     dfMin = dfLocalMin;
    6897       11502 :     dfMax = dfLocalMax;
    6898       11502 : }
    6899             : 
    6900       11502 : static void ComputeMinMaxGeneric(const void *pData, GDALDataType eDataType,
    6901             :                                  bool bSignedByte, int nXCheck, int nYCheck,
    6902             :                                  int nBlockXSize, bool bGotNoDataValue,
    6903             :                                  double dfNoDataValue,
    6904             :                                  bool bGotFloatNoDataValue, float fNoDataValue,
    6905             :                                  const GByte *pabyMaskData, double &dfMin,
    6906             :                                  double &dfMax)
    6907             : {
    6908       11502 :     switch (eDataType)
    6909             :     {
    6910           0 :         case GDT_Unknown:
    6911           0 :             CPLAssert(false);
    6912             :             break;
    6913         672 :         case GDT_Byte:
    6914         672 :             if (bSignedByte)
    6915             :             {
    6916           3 :                 ComputeMinMaxGeneric<GDT_Byte, true>(
    6917             :                     pData, nXCheck, nYCheck, nBlockXSize, bGotNoDataValue,
    6918             :                     dfNoDataValue, false, 0, pabyMaskData, dfMin, dfMax);
    6919             :             }
    6920             :             else
    6921             :             {
    6922         669 :                 ComputeMinMaxGeneric<GDT_Byte, false>(
    6923             :                     pData, nXCheck, nYCheck, nBlockXSize, bGotNoDataValue,
    6924             :                     dfNoDataValue, false, 0, pabyMaskData, dfMin, dfMax);
    6925             :             }
    6926         672 :             break;
    6927         102 :         case GDT_Int8:
    6928         102 :             ComputeMinMaxGeneric<GDT_Int8, false>(
    6929             :                 pData, nXCheck, nYCheck, nBlockXSize, bGotNoDataValue,
    6930             :                 dfNoDataValue, false, 0, pabyMaskData, dfMin, dfMax);
    6931         102 :             break;
    6932         200 :         case GDT_UInt16:
    6933         200 :             ComputeMinMaxGeneric<GDT_UInt16, false>(
    6934             :                 pData, nXCheck, nYCheck, nBlockXSize, bGotNoDataValue,
    6935             :                 dfNoDataValue, false, 0, pabyMaskData, dfMin, dfMax);
    6936         200 :             break;
    6937           1 :         case GDT_Int16:
    6938           1 :             ComputeMinMaxGeneric<GDT_Int16, false>(
    6939             :                 pData, nXCheck, nYCheck, nBlockXSize, bGotNoDataValue,
    6940             :                 dfNoDataValue, false, 0, pabyMaskData, dfMin, dfMax);
    6941           1 :             break;
    6942         197 :         case GDT_UInt32:
    6943         197 :             ComputeMinMaxGeneric<GDT_UInt32, false>(
    6944             :                 pData, nXCheck, nYCheck, nBlockXSize, bGotNoDataValue,
    6945             :                 dfNoDataValue, false, 0, pabyMaskData, dfMin, dfMax);
    6946         197 :             break;
    6947        1107 :         case GDT_Int32:
    6948        1107 :             ComputeMinMaxGeneric<GDT_Int32, false>(
    6949             :                 pData, nXCheck, nYCheck, nBlockXSize, bGotNoDataValue,
    6950             :                 dfNoDataValue, false, 0, pabyMaskData, dfMin, dfMax);
    6951        1107 :             break;
    6952          12 :         case GDT_UInt64:
    6953          12 :             ComputeMinMaxGeneric<GDT_UInt64, false>(
    6954             :                 pData, nXCheck, nYCheck, nBlockXSize, bGotNoDataValue,
    6955             :                 dfNoDataValue, false, 0, pabyMaskData, dfMin, dfMax);
    6956          12 :             break;
    6957          24 :         case GDT_Int64:
    6958          24 :             ComputeMinMaxGeneric<GDT_Int64, false>(
    6959             :                 pData, nXCheck, nYCheck, nBlockXSize, bGotNoDataValue,
    6960             :                 dfNoDataValue, false, 0, pabyMaskData, dfMin, dfMax);
    6961          24 :             break;
    6962        5674 :         case GDT_Float32:
    6963        5674 :             ComputeMinMaxGeneric<GDT_Float32, false>(
    6964             :                 pData, nXCheck, nYCheck, nBlockXSize, false, 0,
    6965             :                 bGotFloatNoDataValue, fNoDataValue, pabyMaskData, dfMin, dfMax);
    6966        5674 :             break;
    6967        3403 :         case GDT_Float64:
    6968        3403 :             ComputeMinMaxGeneric<GDT_Float64, false>(
    6969             :                 pData, nXCheck, nYCheck, nBlockXSize, bGotNoDataValue,
    6970             :                 dfNoDataValue, false, 0, pabyMaskData, dfMin, dfMax);
    6971        3403 :             break;
    6972           9 :         case GDT_CInt16:
    6973           9 :             ComputeMinMaxGeneric<GDT_CInt16, false>(
    6974             :                 pData, nXCheck, nYCheck, nBlockXSize, bGotNoDataValue,
    6975             :                 dfNoDataValue, false, 0, pabyMaskData, dfMin, dfMax);
    6976           9 :             break;
    6977           9 :         case GDT_CInt32:
    6978           9 :             ComputeMinMaxGeneric<GDT_CInt32, false>(
    6979             :                 pData, nXCheck, nYCheck, nBlockXSize, bGotNoDataValue,
    6980             :                 dfNoDataValue, false, 0, pabyMaskData, dfMin, dfMax);
    6981           9 :             break;
    6982          75 :         case GDT_CFloat32:
    6983          75 :             ComputeMinMaxGeneric<GDT_CFloat32, false>(
    6984             :                 pData, nXCheck, nYCheck, nBlockXSize, bGotNoDataValue,
    6985             :                 dfNoDataValue, false, 0, pabyMaskData, dfMin, dfMax);
    6986          75 :             break;
    6987          17 :         case GDT_CFloat64:
    6988          17 :             ComputeMinMaxGeneric<GDT_CFloat64, false>(
    6989             :                 pData, nXCheck, nYCheck, nBlockXSize, bGotNoDataValue,
    6990             :                 dfNoDataValue, false, 0, pabyMaskData, dfMin, dfMax);
    6991          17 :             break;
    6992           0 :         case GDT_TypeCount:
    6993           0 :             CPLAssert(false);
    6994             :             break;
    6995             :     }
    6996       11502 : }
    6997             : 
    6998         696 : static bool ComputeMinMaxGenericIterBlocks(
    6999             :     GDALRasterBand *poBand, GDALDataType eDataType, bool bSignedByte,
    7000             :     GIntBig nTotalBlocks, int nSampleRate, int nBlocksPerRow,
    7001             :     bool bGotNoDataValue, double dfNoDataValue, bool bGotFloatNoDataValue,
    7002             :     float fNoDataValue, GDALRasterBand *poMaskBand, double &dfMin,
    7003             :     double &dfMax)
    7004             : 
    7005             : {
    7006         696 :     GByte *pabyMaskData = nullptr;
    7007             :     int nBlockXSize, nBlockYSize;
    7008         696 :     poBand->GetBlockSize(&nBlockXSize, &nBlockYSize);
    7009             : 
    7010         696 :     if (poMaskBand)
    7011             :     {
    7012             :         pabyMaskData =
    7013          40 :             static_cast<GByte *>(VSI_MALLOC2_VERBOSE(nBlockXSize, nBlockYSize));
    7014          40 :         if (!pabyMaskData)
    7015             :         {
    7016           0 :             return false;
    7017             :         }
    7018             :     }
    7019             : 
    7020       12198 :     for (GIntBig iSampleBlock = 0; iSampleBlock < nTotalBlocks;
    7021       11502 :          iSampleBlock += nSampleRate)
    7022             :     {
    7023       11502 :         const int iYBlock = static_cast<int>(iSampleBlock / nBlocksPerRow);
    7024       11502 :         const int iXBlock = static_cast<int>(iSampleBlock % nBlocksPerRow);
    7025             : 
    7026       11502 :         GDALRasterBlock *poBlock = poBand->GetLockedBlockRef(iXBlock, iYBlock);
    7027       11502 :         if (poBlock == nullptr)
    7028             :         {
    7029           0 :             CPLFree(pabyMaskData);
    7030           0 :             return false;
    7031             :         }
    7032             : 
    7033       11502 :         void *const pData = poBlock->GetDataRef();
    7034             : 
    7035       11502 :         int nXCheck = 0, nYCheck = 0;
    7036       11502 :         poBand->GetActualBlockSize(iXBlock, iYBlock, &nXCheck, &nYCheck);
    7037             : 
    7038       12373 :         if (poMaskBand &&
    7039         871 :             poMaskBand->RasterIO(GF_Read, iXBlock * nBlockXSize,
    7040             :                                  iYBlock * nBlockYSize, nXCheck, nYCheck,
    7041             :                                  pabyMaskData, nXCheck, nYCheck, GDT_Byte, 0,
    7042             :                                  nBlockXSize, nullptr) != CE_None)
    7043             :         {
    7044           0 :             poBlock->DropLock();
    7045           0 :             CPLFree(pabyMaskData);
    7046           0 :             return false;
    7047             :         }
    7048             : 
    7049       11502 :         ComputeMinMaxGeneric(pData, eDataType, bSignedByte, nXCheck, nYCheck,
    7050       11502 :                              nBlockXSize, CPL_TO_BOOL(bGotNoDataValue),
    7051             :                              dfNoDataValue, bGotFloatNoDataValue, fNoDataValue,
    7052             :                              pabyMaskData, dfMin, dfMax);
    7053             : 
    7054       11502 :         poBlock->DropLock();
    7055             :     }
    7056             : 
    7057         696 :     CPLFree(pabyMaskData);
    7058         696 :     return true;
    7059             : }
    7060             : 
    7061             : /**
    7062             :  * \brief Compute the min/max values for a band.
    7063             :  *
    7064             :  * If approximate is OK, then the band's GetMinimum()/GetMaximum() will
    7065             :  * be trusted.  If it doesn't work, a subsample of blocks will be read to
    7066             :  * get an approximate min/max.  If the band has a nodata value it will
    7067             :  * be excluded from the minimum and maximum.
    7068             :  *
    7069             :  * If bApprox is FALSE, then all pixels will be read and used to compute
    7070             :  * an exact range.
    7071             :  *
    7072             :  * This method is the same as the C function GDALComputeRasterMinMax().
    7073             :  *
    7074             :  * @param bApproxOK TRUE if an approximate (faster) answer is OK, otherwise
    7075             :  * FALSE.
    7076             :  * @param adfMinMax the array in which the minimum (adfMinMax[0]) and the
    7077             :  * maximum (adfMinMax[1]) are returned.
    7078             :  *
    7079             :  * @return CE_None on success or CE_Failure on failure.
    7080             :  */
    7081             : 
    7082        1537 : CPLErr GDALRasterBand::ComputeRasterMinMax(int bApproxOK, double *adfMinMax)
    7083             : {
    7084             :     /* -------------------------------------------------------------------- */
    7085             :     /*      Does the driver already know the min/max?                       */
    7086             :     /* -------------------------------------------------------------------- */
    7087        1537 :     if (bApproxOK)
    7088             :     {
    7089          12 :         int bSuccessMin = FALSE;
    7090          12 :         int bSuccessMax = FALSE;
    7091             : 
    7092          12 :         double dfMin = GetMinimum(&bSuccessMin);
    7093          12 :         double dfMax = GetMaximum(&bSuccessMax);
    7094             : 
    7095          12 :         if (bSuccessMin && bSuccessMax)
    7096             :         {
    7097           1 :             adfMinMax[0] = dfMin;
    7098           1 :             adfMinMax[1] = dfMax;
    7099           1 :             return CE_None;
    7100             :         }
    7101             :     }
    7102             : 
    7103             :     /* -------------------------------------------------------------------- */
    7104             :     /*      If we have overview bands, use them for min/max.                */
    7105             :     /* -------------------------------------------------------------------- */
    7106             :     // cppcheck-suppress knownConditionTrueFalse
    7107        1536 :     if (bApproxOK && GetOverviewCount() > 0 && !HasArbitraryOverviews())
    7108             :     {
    7109             :         GDALRasterBand *poBand =
    7110           0 :             GetRasterSampleOverview(GDALSTAT_APPROX_NUMSAMPLES);
    7111             : 
    7112           0 :         if (poBand != this)
    7113           0 :             return poBand->ComputeRasterMinMax(FALSE, adfMinMax);
    7114             :     }
    7115             : 
    7116             :     /* -------------------------------------------------------------------- */
    7117             :     /*      Read actual data and compute minimum and maximum.               */
    7118             :     /* -------------------------------------------------------------------- */
    7119        1536 :     int bGotNoDataValue = FALSE;
    7120        1536 :     const double dfNoDataValue = GetNoDataValue(&bGotNoDataValue);
    7121        1536 :     bGotNoDataValue = bGotNoDataValue && !std::isnan(dfNoDataValue);
    7122        1536 :     bool bGotFloatNoDataValue = false;
    7123        1536 :     float fNoDataValue = 0.0f;
    7124        1536 :     ComputeFloatNoDataValue(eDataType, dfNoDataValue, bGotNoDataValue,
    7125             :                             fNoDataValue, bGotFloatNoDataValue);
    7126             : 
    7127        1536 :     GDALRasterBand *poMaskBand = nullptr;
    7128        1536 :     if (!bGotNoDataValue)
    7129             :     {
    7130        1272 :         const int l_nMaskFlags = GetMaskFlags();
    7131        1312 :         if (l_nMaskFlags != GMF_ALL_VALID && l_nMaskFlags != GMF_NODATA &&
    7132          40 :             GetColorInterpretation() != GCI_AlphaBand)
    7133             :         {
    7134          40 :             poMaskBand = GetMaskBand();
    7135             :         }
    7136             :     }
    7137             : 
    7138        1536 :     bool bSignedByte = false;
    7139        1536 :     if (eDataType == GDT_Byte)
    7140             :     {
    7141         629 :         EnablePixelTypeSignedByteWarning(false);
    7142             :         const char *pszPixelType =
    7143         629 :             GetMetadataItem("PIXELTYPE", "IMAGE_STRUCTURE");
    7144         629 :         EnablePixelTypeSignedByteWarning(true);
    7145         629 :         bSignedByte =
    7146         629 :             pszPixelType != nullptr && EQUAL(pszPixelType, "SIGNEDBYTE");
    7147             :     }
    7148             : 
    7149             :     GDALRasterIOExtraArg sExtraArg;
    7150        1536 :     INIT_RASTERIO_EXTRA_ARG(sExtraArg);
    7151             : 
    7152        3072 :     GUInt32 nMin = (eDataType == GDT_Byte)
    7153        1536 :                        ? 255
    7154             :                        : 65535;  // used for GByte & GUInt16 cases
    7155        1536 :     GUInt32 nMax = 0;            // used for GByte & GUInt16 cases
    7156        1536 :     GInt16 nMinInt16 =
    7157             :         std::numeric_limits<GInt16>::max();  // used for GInt16 case
    7158        1536 :     GInt16 nMaxInt16 =
    7159             :         std::numeric_limits<GInt16>::lowest();  // used for GInt16 case
    7160        1536 :     double dfMin =
    7161             :         std::numeric_limits<double>::max();  // used for generic code path
    7162        1536 :     double dfMax =
    7163             :         -std::numeric_limits<double>::max();  // used for generic code path
    7164        1536 :     const bool bUseOptimizedPath =
    7165        2434 :         !poMaskBand && ((eDataType == GDT_Byte && !bSignedByte) ||
    7166         898 :                         eDataType == GDT_Int16 || eDataType == GDT_UInt16);
    7167             : 
    7168             :     const auto ComputeMinMaxForBlock =
    7169       18551 :         [this, bSignedByte, bGotNoDataValue, dfNoDataValue, &nMin, &nMax,
    7170             :          &nMinInt16, &nMaxInt16](const void *pData, int nXCheck,
    7171      241704 :                                  int nBufferWidth, int nYCheck)
    7172             :     {
    7173       18551 :         if (eDataType == GDT_Byte && !bSignedByte)
    7174             :         {
    7175             :             const bool bHasNoData =
    7176       25638 :                 bGotNoDataValue && GDALIsValueInRange<GByte>(dfNoDataValue) &&
    7177        9501 :                 static_cast<GByte>(dfNoDataValue) == dfNoDataValue;
    7178       16137 :             const GUInt32 nNoDataValue =
    7179       16137 :                 bHasNoData ? static_cast<GByte>(dfNoDataValue) : 0;
    7180             :             GUIntBig nSum, nSumSquare, nSampleCount, nValidCount;  // unused
    7181             :             ComputeStatisticsInternal<GByte,
    7182             :                                       /* COMPUTE_OTHER_STATS = */ false>::
    7183       16137 :                 f(nXCheck, nBufferWidth, nYCheck,
    7184             :                   static_cast<const GByte *>(pData), bHasNoData, nNoDataValue,
    7185       16137 :                   nMin, nMax, nSum, nSumSquare, nSampleCount, nValidCount);
    7186             :         }
    7187        2414 :         else if (eDataType == GDT_UInt16)
    7188             :         {
    7189             :             const bool bHasNoData =
    7190         973 :                 bGotNoDataValue && GDALIsValueInRange<GUInt16>(dfNoDataValue) &&
    7191          83 :                 static_cast<GUInt16>(dfNoDataValue) == dfNoDataValue;
    7192         890 :             const GUInt32 nNoDataValue =
    7193         890 :                 bHasNoData ? static_cast<GUInt16>(dfNoDataValue) : 0;
    7194             :             GUIntBig nSum, nSumSquare, nSampleCount, nValidCount;  // unused
    7195             :             ComputeStatisticsInternal<GUInt16,
    7196             :                                       /* COMPUTE_OTHER_STATS = */ false>::
    7197         890 :                 f(nXCheck, nBufferWidth, nYCheck,
    7198             :                   static_cast<const GUInt16 *>(pData), bHasNoData, nNoDataValue,
    7199             :                   nMin, nMax, nSum, nSumSquare, nSampleCount, nValidCount);
    7200             :         }
    7201        1524 :         else if (eDataType == GDT_Int16)
    7202             :         {
    7203             :             const bool bHasNoData =
    7204        2877 :                 bGotNoDataValue && GDALIsValueInRange<int16_t>(dfNoDataValue) &&
    7205        1353 :                 static_cast<int16_t>(dfNoDataValue) == dfNoDataValue;
    7206        1524 :             if (bHasNoData)
    7207             :             {
    7208        1353 :                 const int16_t nNoDataValue =
    7209             :                     static_cast<int16_t>(dfNoDataValue);
    7210      134754 :                 for (int iY = 0; iY < nYCheck; iY++)
    7211             :                 {
    7212      133401 :                     ComputeMinMax<int16_t, true>(
    7213      133401 :                         static_cast<const int16_t *>(pData) +
    7214      133401 :                             static_cast<size_t>(iY) * nBufferWidth,
    7215             :                         nXCheck, nNoDataValue, &nMinInt16, &nMaxInt16);
    7216             :                 }
    7217             :             }
    7218             :             else
    7219             :             {
    7220        1459 :                 for (int iY = 0; iY < nYCheck; iY++)
    7221             :                 {
    7222        1288 :                     ComputeMinMax<int16_t, false>(
    7223        1288 :                         static_cast<const int16_t *>(pData) +
    7224        1288 :                             static_cast<size_t>(iY) * nBufferWidth,
    7225             :                         nXCheck, 0, &nMinInt16, &nMaxInt16);
    7226             :                 }
    7227             :             }
    7228             :         }
    7229       18551 :     };
    7230             : 
    7231        1536 :     if (bApproxOK && HasArbitraryOverviews())
    7232             :     {
    7233             :         /* --------------------------------------------------------------------
    7234             :          */
    7235             :         /*      Figure out how much the image should be reduced to get an */
    7236             :         /*      approximate value. */
    7237             :         /* --------------------------------------------------------------------
    7238             :          */
    7239           0 :         double dfReduction = sqrt(static_cast<double>(nRasterXSize) *
    7240           0 :                                   nRasterYSize / GDALSTAT_APPROX_NUMSAMPLES);
    7241             : 
    7242           0 :         int nXReduced = nRasterXSize;
    7243           0 :         int nYReduced = nRasterYSize;
    7244           0 :         if (dfReduction > 1.0)
    7245             :         {
    7246           0 :             nXReduced = static_cast<int>(nRasterXSize / dfReduction);
    7247           0 :             nYReduced = static_cast<int>(nRasterYSize / dfReduction);
    7248             : 
    7249             :             // Catch the case of huge resizing ratios here
    7250           0 :             if (nXReduced == 0)
    7251           0 :                 nXReduced = 1;
    7252           0 :             if (nYReduced == 0)
    7253           0 :                 nYReduced = 1;
    7254             :         }
    7255             : 
    7256           0 :         void *const pData = CPLMalloc(cpl::fits_on<int>(
    7257           0 :             GDALGetDataTypeSizeBytes(eDataType) * nXReduced * nYReduced));
    7258             : 
    7259             :         const CPLErr eErr =
    7260           0 :             IRasterIO(GF_Read, 0, 0, nRasterXSize, nRasterYSize, pData,
    7261           0 :                       nXReduced, nYReduced, eDataType, 0, 0, &sExtraArg);
    7262           0 :         if (eErr != CE_None)
    7263             :         {
    7264           0 :             CPLFree(pData);
    7265           0 :             return eErr;
    7266             :         }
    7267             : 
    7268           0 :         GByte *pabyMaskData = nullptr;
    7269           0 :         if (poMaskBand)
    7270             :         {
    7271             :             pabyMaskData =
    7272           0 :                 static_cast<GByte *>(VSI_MALLOC2_VERBOSE(nXReduced, nYReduced));
    7273           0 :             if (!pabyMaskData)
    7274             :             {
    7275           0 :                 CPLFree(pData);
    7276           0 :                 return CE_Failure;
    7277             :             }
    7278             : 
    7279           0 :             if (poMaskBand->RasterIO(GF_Read, 0, 0, nRasterXSize, nRasterYSize,
    7280             :                                      pabyMaskData, nXReduced, nYReduced,
    7281           0 :                                      GDT_Byte, 0, 0, nullptr) != CE_None)
    7282             :             {
    7283           0 :                 CPLFree(pData);
    7284           0 :                 CPLFree(pabyMaskData);
    7285           0 :                 return CE_Failure;
    7286             :             }
    7287             :         }
    7288             : 
    7289           0 :         if (bUseOptimizedPath)
    7290             :         {
    7291           0 :             ComputeMinMaxForBlock(pData, nXReduced, nXReduced, nYReduced);
    7292             :         }
    7293             :         else
    7294             :         {
    7295           0 :             ComputeMinMaxGeneric(
    7296             :                 pData, eDataType, bSignedByte, nXReduced, nYReduced, nXReduced,
    7297           0 :                 CPL_TO_BOOL(bGotNoDataValue), dfNoDataValue,
    7298             :                 bGotFloatNoDataValue, fNoDataValue, pabyMaskData, dfMin, dfMax);
    7299             :         }
    7300             : 
    7301           0 :         CPLFree(pData);
    7302           0 :         CPLFree(pabyMaskData);
    7303             :     }
    7304             : 
    7305             :     else  // No arbitrary overviews
    7306             :     {
    7307        1536 :         if (!InitBlockInfo())
    7308           0 :             return CE_Failure;
    7309             : 
    7310             :         /* --------------------------------------------------------------------
    7311             :          */
    7312             :         /*      Figure out the ratio of blocks we will read to get an */
    7313             :         /*      approximate value. */
    7314             :         /* --------------------------------------------------------------------
    7315             :          */
    7316        1536 :         int nSampleRate = 1;
    7317             : 
    7318        1536 :         if (bApproxOK)
    7319             :         {
    7320          11 :             nSampleRate = static_cast<int>(std::max(
    7321          22 :                 1.0,
    7322          11 :                 sqrt(static_cast<double>(nBlocksPerRow) * nBlocksPerColumn)));
    7323             :             // We want to avoid probing only the first column of blocks for
    7324             :             // a square shaped raster, because it is not unlikely that it may
    7325             :             // be padding only (#6378).
    7326          11 :             if (nSampleRate == nBlocksPerRow && nBlocksPerRow > 1)
    7327           0 :                 nSampleRate += 1;
    7328             :         }
    7329             : 
    7330        1536 :         if (bUseOptimizedPath)
    7331             :         {
    7332         840 :             for (GIntBig iSampleBlock = 0;
    7333       19318 :                  iSampleBlock <
    7334       19318 :                  static_cast<GIntBig>(nBlocksPerRow) * nBlocksPerColumn;
    7335       18478 :                  iSampleBlock += nSampleRate)
    7336             :             {
    7337       18552 :                 const int iYBlock =
    7338       18552 :                     static_cast<int>(iSampleBlock / nBlocksPerRow);
    7339       18552 :                 const int iXBlock =
    7340       18552 :                     static_cast<int>(iSampleBlock % nBlocksPerRow);
    7341             : 
    7342       18552 :                 GDALRasterBlock *poBlock = GetLockedBlockRef(iXBlock, iYBlock);
    7343       18552 :                 if (poBlock == nullptr)
    7344           1 :                     return CE_Failure;
    7345             : 
    7346       18551 :                 void *const pData = poBlock->GetDataRef();
    7347             : 
    7348       18551 :                 int nXCheck = 0, nYCheck = 0;
    7349       18551 :                 GetActualBlockSize(iXBlock, iYBlock, &nXCheck, &nYCheck);
    7350             : 
    7351       18551 :                 ComputeMinMaxForBlock(pData, nXCheck, nBlockXSize, nYCheck);
    7352             : 
    7353       18551 :                 poBlock->DropLock();
    7354             : 
    7355       18551 :                 if (eDataType == GDT_Byte && !bSignedByte && nMin == 0 &&
    7356        4114 :                     nMax == 255)
    7357          73 :                     break;
    7358             :             }
    7359             :         }
    7360             :         else
    7361             :         {
    7362         696 :             const GIntBig nTotalBlocks =
    7363         696 :                 static_cast<GIntBig>(nBlocksPerRow) * nBlocksPerColumn;
    7364         696 :             if (!ComputeMinMaxGenericIterBlocks(
    7365             :                     this, eDataType, bSignedByte, nTotalBlocks, nSampleRate,
    7366         696 :                     nBlocksPerRow, CPL_TO_BOOL(bGotNoDataValue), dfNoDataValue,
    7367             :                     bGotFloatNoDataValue, fNoDataValue, poMaskBand, dfMin,
    7368             :                     dfMax))
    7369             :             {
    7370           0 :                 return CE_Failure;
    7371             :             }
    7372             :         }
    7373             :     }
    7374             : 
    7375        1535 :     if (bUseOptimizedPath)
    7376             :     {
    7377         839 :         if ((eDataType == GDT_Byte && !bSignedByte) || eDataType == GDT_UInt16)
    7378             :         {
    7379         727 :             dfMin = nMin;
    7380         727 :             dfMax = nMax;
    7381             :         }
    7382         112 :         else if (eDataType == GDT_Int16)
    7383             :         {
    7384         112 :             dfMin = nMinInt16;
    7385         112 :             dfMax = nMaxInt16;
    7386             :         }
    7387             :     }
    7388             : 
    7389        1535 :     if (dfMin > dfMax)
    7390             :     {
    7391           4 :         adfMinMax[0] = 0;
    7392           4 :         adfMinMax[1] = 0;
    7393           4 :         ReportError(
    7394             :             CE_Failure, CPLE_AppDefined,
    7395             :             "Failed to compute min/max, no valid pixels found in sampling.");
    7396           4 :         return CE_Failure;
    7397             :     }
    7398             : 
    7399        1531 :     adfMinMax[0] = dfMin;
    7400        1531 :     adfMinMax[1] = dfMax;
    7401             : 
    7402        1531 :     return CE_None;
    7403             : }
    7404             : 
    7405             : /************************************************************************/
    7406             : /*                      GDALComputeRasterMinMax()                       */
    7407             : /************************************************************************/
    7408             : 
    7409             : /**
    7410             :  * \brief Compute the min/max values for a band.
    7411             :  *
    7412             :  * @see GDALRasterBand::ComputeRasterMinMax()
    7413             :  *
    7414             :  * @note Prior to GDAL 3.6, this function returned void
    7415             :  */
    7416             : 
    7417        1459 : CPLErr CPL_STDCALL GDALComputeRasterMinMax(GDALRasterBandH hBand, int bApproxOK,
    7418             :                                            double adfMinMax[2])
    7419             : 
    7420             : {
    7421        1459 :     VALIDATE_POINTER1(hBand, "GDALComputeRasterMinMax", CE_Failure);
    7422             : 
    7423        1459 :     GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
    7424        1459 :     return poBand->ComputeRasterMinMax(bApproxOK, adfMinMax);
    7425             : }
    7426             : 
    7427             : /************************************************************************/
    7428             : /*                    ComputeRasterMinMaxLocation()                     */
    7429             : /************************************************************************/
    7430             : 
    7431             : /**
    7432             :  * \brief Compute the min/max values for a band, and their location.
    7433             :  *
    7434             :  * Pixels whose value matches the nodata value or are masked by the mask
    7435             :  * band are ignored.
    7436             :  *
    7437             :  * If the minimum or maximum value is hit in several locations, it is not
    7438             :  * specified which one will be returned.
    7439             :  *
    7440             :  * @param[out] pdfMin Pointer to the minimum value.
    7441             :  * @param[out] pdfMax Pointer to the maximum value.
    7442             :  * @param[out] pnMinX Pointer to the column where the minimum value is hit.
    7443             :  * @param[out] pnMinY Pointer to the line where the minimum value is hit.
    7444             :  * @param[out] pnMaxX Pointer to the column where the maximum value is hit.
    7445             :  * @param[out] pnMaxY Pointer to the line where the maximum value is hit.
    7446             :  *
    7447             :  * @return CE_None in case of success, CE_Warning if there are no valid values,
    7448             :  *         CE_Failure in case of error.
    7449             :  *
    7450             :  * @since GDAL 3.11
    7451             :  */
    7452             : 
    7453           8 : CPLErr GDALRasterBand::ComputeRasterMinMaxLocation(double *pdfMin,
    7454             :                                                    double *pdfMax, int *pnMinX,
    7455             :                                                    int *pnMinY, int *pnMaxX,
    7456             :                                                    int *pnMaxY)
    7457             : {
    7458           8 :     int nMinX = -1;
    7459           8 :     int nMinY = -1;
    7460           8 :     int nMaxX = -1;
    7461           8 :     int nMaxY = -1;
    7462           8 :     double dfMin = std::numeric_limits<double>::infinity();
    7463           8 :     double dfMax = -std::numeric_limits<double>::infinity();
    7464           8 :     if (pdfMin)
    7465           5 :         *pdfMin = dfMin;
    7466           8 :     if (pdfMax)
    7467           5 :         *pdfMax = dfMax;
    7468           8 :     if (pnMinX)
    7469           6 :         *pnMinX = nMinX;
    7470           8 :     if (pnMinY)
    7471           6 :         *pnMinY = nMinY;
    7472           8 :     if (pnMaxX)
    7473           6 :         *pnMaxX = nMaxX;
    7474           8 :     if (pnMaxY)
    7475           6 :         *pnMaxY = nMaxY;
    7476             : 
    7477           8 :     if (GDALDataTypeIsComplex(eDataType))
    7478             :     {
    7479           0 :         CPLError(CE_Failure, CPLE_NotSupported,
    7480             :                  "Complex data type not supported");
    7481           0 :         return CE_Failure;
    7482             :     }
    7483             : 
    7484           8 :     if (!InitBlockInfo())
    7485           0 :         return CE_Failure;
    7486             : 
    7487           8 :     int bGotNoDataValue = FALSE;
    7488           8 :     const double dfNoDataValue = GetNoDataValue(&bGotNoDataValue);
    7489           8 :     bGotNoDataValue = bGotNoDataValue && !std::isnan(dfNoDataValue);
    7490           8 :     bool bGotFloatNoDataValue = false;
    7491           8 :     float fNoDataValue = 0.0f;
    7492           8 :     ComputeFloatNoDataValue(eDataType, dfNoDataValue, bGotNoDataValue,
    7493             :                             fNoDataValue, bGotFloatNoDataValue);
    7494             : 
    7495           8 :     GDALRasterBand *poMaskBand = nullptr;
    7496           8 :     if (!bGotNoDataValue)
    7497             :     {
    7498           8 :         const int l_nMaskFlags = GetMaskFlags();
    7499           9 :         if (l_nMaskFlags != GMF_ALL_VALID && l_nMaskFlags != GMF_NODATA &&
    7500           1 :             GetColorInterpretation() != GCI_AlphaBand)
    7501             :         {
    7502           1 :             poMaskBand = GetMaskBand();
    7503             :         }
    7504             :     }
    7505             : 
    7506           8 :     bool bSignedByte = false;
    7507           8 :     if (eDataType == GDT_Byte)
    7508             :     {
    7509           7 :         EnablePixelTypeSignedByteWarning(false);
    7510             :         const char *pszPixelType =
    7511           7 :             GetMetadataItem("PIXELTYPE", "IMAGE_STRUCTURE");
    7512           7 :         EnablePixelTypeSignedByteWarning(true);
    7513           7 :         bSignedByte =
    7514           7 :             pszPixelType != nullptr && EQUAL(pszPixelType, "SIGNEDBYTE");
    7515             :     }
    7516             : 
    7517           8 :     GByte *pabyMaskData = nullptr;
    7518           8 :     if (poMaskBand)
    7519             :     {
    7520             :         pabyMaskData =
    7521           1 :             static_cast<GByte *>(VSI_MALLOC2_VERBOSE(nBlockXSize, nBlockYSize));
    7522           1 :         if (!pabyMaskData)
    7523             :         {
    7524           0 :             return CE_Failure;
    7525             :         }
    7526             :     }
    7527             : 
    7528           8 :     const GIntBig nTotalBlocks =
    7529           8 :         static_cast<GIntBig>(nBlocksPerRow) * nBlocksPerColumn;
    7530           8 :     bool bNeedsMin = pdfMin || pnMinX || pnMinY;
    7531           8 :     bool bNeedsMax = pdfMax || pnMaxX || pnMaxY;
    7532          16 :     for (GIntBig iBlock = 0; iBlock < nTotalBlocks; ++iBlock)
    7533             :     {
    7534          11 :         const int iYBlock = static_cast<int>(iBlock / nBlocksPerRow);
    7535          11 :         const int iXBlock = static_cast<int>(iBlock % nBlocksPerRow);
    7536             : 
    7537          11 :         GDALRasterBlock *poBlock = GetLockedBlockRef(iXBlock, iYBlock);
    7538          11 :         if (poBlock == nullptr)
    7539             :         {
    7540           0 :             CPLFree(pabyMaskData);
    7541           0 :             return CE_Failure;
    7542             :         }
    7543             : 
    7544          11 :         void *const pData = poBlock->GetDataRef();
    7545             : 
    7546          11 :         int nXCheck = 0, nYCheck = 0;
    7547          11 :         GetActualBlockSize(iXBlock, iYBlock, &nXCheck, &nYCheck);
    7548             : 
    7549          13 :         if (poMaskBand &&
    7550           2 :             poMaskBand->RasterIO(GF_Read, iXBlock * nBlockXSize,
    7551           2 :                                  iYBlock * nBlockYSize, nXCheck, nYCheck,
    7552             :                                  pabyMaskData, nXCheck, nYCheck, GDT_Byte, 0,
    7553           2 :                                  nBlockXSize, nullptr) != CE_None)
    7554             :         {
    7555           0 :             poBlock->DropLock();
    7556           0 :             CPLFree(pabyMaskData);
    7557           0 :             return CE_Failure;
    7558             :         }
    7559             : 
    7560          11 :         if (poMaskBand || nYCheck < nBlockYSize || nXCheck < nBlockXSize)
    7561             :         {
    7562           4 :             for (int iY = 0; iY < nYCheck; ++iY)
    7563             :             {
    7564           6 :                 for (int iX = 0; iX < nXCheck; ++iX)
    7565             :                 {
    7566           4 :                     const GPtrDiff_t iOffset =
    7567           4 :                         iX + static_cast<GPtrDiff_t>(iY) * nBlockXSize;
    7568           4 :                     if (pabyMaskData && pabyMaskData[iOffset] == 0)
    7569           2 :                         continue;
    7570           2 :                     bool bValid = true;
    7571           2 :                     double dfValue = GetPixelValue(
    7572             :                         eDataType, bSignedByte, pData, iOffset, bGotNoDataValue,
    7573             :                         dfNoDataValue, bGotFloatNoDataValue, fNoDataValue,
    7574             :                         bValid);
    7575           2 :                     if (!bValid)
    7576           0 :                         continue;
    7577           2 :                     if (dfValue < dfMin)
    7578             :                     {
    7579           2 :                         dfMin = dfValue;
    7580           2 :                         nMinX = iXBlock * nBlockXSize + iX;
    7581           2 :                         nMinY = iYBlock * nBlockYSize + iY;
    7582             :                     }
    7583           2 :                     if (dfValue > dfMax)
    7584             :                     {
    7585           1 :                         dfMax = dfValue;
    7586           1 :                         nMaxX = iXBlock * nBlockXSize + iX;
    7587           1 :                         nMaxY = iYBlock * nBlockYSize + iY;
    7588             :                     }
    7589             :                 }
    7590           2 :             }
    7591             :         }
    7592             :         else
    7593             :         {
    7594           9 :             size_t pos_min = 0;
    7595           9 :             size_t pos_max = 0;
    7596           9 :             const auto eEffectiveDT = bSignedByte ? GDT_Int8 : eDataType;
    7597           9 :             if (bNeedsMin && bNeedsMax)
    7598             :             {
    7599          10 :                 std::tie(pos_min, pos_max) = gdal::minmax_element(
    7600           5 :                     pData, static_cast<size_t>(nBlockXSize) * nBlockYSize,
    7601          10 :                     eEffectiveDT, bGotNoDataValue, dfNoDataValue);
    7602             :             }
    7603           4 :             else if (bNeedsMin)
    7604             :             {
    7605           1 :                 pos_min = gdal::min_element(
    7606           1 :                     pData, static_cast<size_t>(nBlockXSize) * nBlockYSize,
    7607             :                     eEffectiveDT, bGotNoDataValue, dfNoDataValue);
    7608             :             }
    7609           3 :             else if (bNeedsMax)
    7610             :             {
    7611           2 :                 pos_max = gdal::max_element(
    7612           2 :                     pData, static_cast<size_t>(nBlockXSize) * nBlockYSize,
    7613             :                     eEffectiveDT, bGotNoDataValue, dfNoDataValue);
    7614             :             }
    7615             : 
    7616           9 :             if (bNeedsMin)
    7617             :             {
    7618           6 :                 const int nMinXBlock = static_cast<int>(pos_min % nBlockXSize);
    7619           6 :                 const int nMinYBlock = static_cast<int>(pos_min / nBlockXSize);
    7620           6 :                 bool bValid = true;
    7621           6 :                 const double dfMinValueBlock = GetPixelValue(
    7622             :                     eDataType, bSignedByte, pData, pos_min, bGotNoDataValue,
    7623             :                     dfNoDataValue, bGotFloatNoDataValue, fNoDataValue, bValid);
    7624           6 :                 if (bValid && dfMinValueBlock < dfMin)
    7625             :                 {
    7626           5 :                     dfMin = dfMinValueBlock;
    7627           5 :                     nMinX = iXBlock * nBlockXSize + nMinXBlock;
    7628           5 :                     nMinY = iYBlock * nBlockYSize + nMinYBlock;
    7629             :                 }
    7630             :             }
    7631             : 
    7632           9 :             if (bNeedsMax)
    7633             :             {
    7634           7 :                 const int nMaxXBlock = static_cast<int>(pos_max % nBlockXSize);
    7635           7 :                 const int nMaxYBlock = static_cast<int>(pos_max / nBlockXSize);
    7636           7 :                 bool bValid = true;
    7637           7 :                 const double dfMaxValueBlock = GetPixelValue(
    7638             :                     eDataType, bSignedByte, pData, pos_max, bGotNoDataValue,
    7639             :                     dfNoDataValue, bGotFloatNoDataValue, fNoDataValue, bValid);
    7640           7 :                 if (bValid && dfMaxValueBlock > dfMax)
    7641             :                 {
    7642           5 :                     dfMax = dfMaxValueBlock;
    7643           5 :                     nMaxX = iXBlock * nBlockXSize + nMaxXBlock;
    7644           5 :                     nMaxY = iYBlock * nBlockYSize + nMaxYBlock;
    7645             :                 }
    7646             :             }
    7647             :         }
    7648             : 
    7649          11 :         poBlock->DropLock();
    7650             : 
    7651          11 :         if (eDataType == GDT_Byte)
    7652             :         {
    7653          10 :             if (bNeedsMin && dfMin == 0)
    7654             :             {
    7655           1 :                 bNeedsMin = false;
    7656             :             }
    7657          10 :             if (bNeedsMax && dfMax == 255)
    7658             :             {
    7659           4 :                 bNeedsMax = false;
    7660             :             }
    7661          10 :             if (!bNeedsMin && !bNeedsMax)
    7662             :             {
    7663           3 :                 break;
    7664             :             }
    7665             :         }
    7666             :     }
    7667             : 
    7668           8 :     CPLFree(pabyMaskData);
    7669             : 
    7670           8 :     if (pdfMin)
    7671           5 :         *pdfMin = dfMin;
    7672           8 :     if (pdfMax)
    7673           5 :         *pdfMax = dfMax;
    7674           8 :     if (pnMinX)
    7675           6 :         *pnMinX = nMinX;
    7676           8 :     if (pnMinY)
    7677           6 :         *pnMinY = nMinY;
    7678           8 :     if (pnMaxX)
    7679           6 :         *pnMaxX = nMaxX;
    7680           8 :     if (pnMaxY)
    7681           6 :         *pnMaxY = nMaxY;
    7682           8 :     return ((bNeedsMin && nMinX < 0) || (bNeedsMax && nMaxX < 0)) ? CE_Warning
    7683           8 :                                                                   : CE_None;
    7684             : }
    7685             : 
    7686             : /************************************************************************/
    7687             : /*                    GDALComputeRasterMinMaxLocation()                 */
    7688             : /************************************************************************/
    7689             : 
    7690             : /**
    7691             :  * \brief Compute the min/max values for a band, and their location.
    7692             :  *
    7693             :  * @see GDALRasterBand::ComputeRasterMinMax()
    7694             :  * @since GDAL 3.11
    7695             :  */
    7696             : 
    7697           6 : CPLErr GDALComputeRasterMinMaxLocation(GDALRasterBandH hBand, double *pdfMin,
    7698             :                                        double *pdfMax, int *pnMinX, int *pnMinY,
    7699             :                                        int *pnMaxX, int *pnMaxY)
    7700             : 
    7701             : {
    7702           6 :     VALIDATE_POINTER1(hBand, "GDALComputeRasterMinMaxLocation", CE_Failure);
    7703             : 
    7704           6 :     GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
    7705           6 :     return poBand->ComputeRasterMinMaxLocation(pdfMin, pdfMax, pnMinX, pnMinY,
    7706           6 :                                                pnMaxX, pnMaxY);
    7707             : }
    7708             : 
    7709             : /************************************************************************/
    7710             : /*                        SetDefaultHistogram()                         */
    7711             : /************************************************************************/
    7712             : 
    7713             : /* FIXME : add proper documentation */
    7714             : /**
    7715             :  * \brief Set default histogram.
    7716             :  *
    7717             :  * This method is the same as the C function GDALSetDefaultHistogram() and
    7718             :  * GDALSetDefaultHistogramEx()
    7719             :  */
    7720           0 : CPLErr GDALRasterBand::SetDefaultHistogram(double /* dfMin */,
    7721             :                                            double /* dfMax */,
    7722             :                                            int /* nBuckets */,
    7723             :                                            GUIntBig * /* panHistogram */)
    7724             : 
    7725             : {
    7726           0 :     if (!(GetMOFlags() & GMO_IGNORE_UNIMPLEMENTED))
    7727           0 :         ReportError(CE_Failure, CPLE_NotSupported,
    7728             :                     "SetDefaultHistogram() not implemented for this format.");
    7729             : 
    7730           0 :     return CE_Failure;
    7731             : }
    7732             : 
    7733             : /************************************************************************/
    7734             : /*                      GDALSetDefaultHistogram()                       */
    7735             : /************************************************************************/
    7736             : 
    7737             : /**
    7738             :  * \brief Set default histogram.
    7739             :  *
    7740             :  * Use GDALSetRasterHistogramEx() instead to be able to set counts exceeding
    7741             :  * 2 billion.
    7742             :  *
    7743             :  * @see GDALRasterBand::SetDefaultHistogram()
    7744             :  * @see GDALSetRasterHistogramEx()
    7745             :  */
    7746             : 
    7747           0 : CPLErr CPL_STDCALL GDALSetDefaultHistogram(GDALRasterBandH hBand, double dfMin,
    7748             :                                            double dfMax, int nBuckets,
    7749             :                                            int *panHistogram)
    7750             : 
    7751             : {
    7752           0 :     VALIDATE_POINTER1(hBand, "GDALSetDefaultHistogram", CE_Failure);
    7753             : 
    7754           0 :     GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
    7755             : 
    7756             :     GUIntBig *panHistogramTemp =
    7757           0 :         static_cast<GUIntBig *>(VSIMalloc2(sizeof(GUIntBig), nBuckets));
    7758           0 :     if (panHistogramTemp == nullptr)
    7759             :     {
    7760           0 :         poBand->ReportError(CE_Failure, CPLE_OutOfMemory,
    7761             :                             "Out of memory in GDALSetDefaultHistogram().");
    7762           0 :         return CE_Failure;
    7763             :     }
    7764             : 
    7765           0 :     for (int i = 0; i < nBuckets; ++i)
    7766             :     {
    7767           0 :         panHistogramTemp[i] = static_cast<GUIntBig>(panHistogram[i]);
    7768             :     }
    7769             : 
    7770             :     const CPLErr eErr =
    7771           0 :         poBand->SetDefaultHistogram(dfMin, dfMax, nBuckets, panHistogramTemp);
    7772             : 
    7773           0 :     CPLFree(panHistogramTemp);
    7774             : 
    7775           0 :     return eErr;
    7776             : }
    7777             : 
    7778             : /************************************************************************/
    7779             : /*                     GDALSetDefaultHistogramEx()                      */
    7780             : /************************************************************************/
    7781             : 
    7782             : /**
    7783             :  * \brief Set default histogram.
    7784             :  *
    7785             :  * @see GDALRasterBand::SetDefaultHistogram()
    7786             :  *
    7787             :  * @since GDAL 2.0
    7788             :  */
    7789             : 
    7790           5 : CPLErr CPL_STDCALL GDALSetDefaultHistogramEx(GDALRasterBandH hBand,
    7791             :                                              double dfMin, double dfMax,
    7792             :                                              int nBuckets,
    7793             :                                              GUIntBig *panHistogram)
    7794             : 
    7795             : {
    7796           5 :     VALIDATE_POINTER1(hBand, "GDALSetDefaultHistogramEx", CE_Failure);
    7797             : 
    7798           5 :     GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
    7799           5 :     return poBand->SetDefaultHistogram(dfMin, dfMax, nBuckets, panHistogram);
    7800             : }
    7801             : 
    7802             : /************************************************************************/
    7803             : /*                           GetDefaultRAT()                            */
    7804             : /************************************************************************/
    7805             : 
    7806             : /**
    7807             :  * \brief Fetch default Raster Attribute Table.
    7808             :  *
    7809             :  * A RAT will be returned if there is a default one associated with the
    7810             :  * band, otherwise NULL is returned.  The returned RAT is owned by the
    7811             :  * band and should not be deleted by the application.
    7812             :  *
    7813             :  * This method is the same as the C function GDALGetDefaultRAT().
    7814             :  *
    7815             :  * @return NULL, or a pointer to an internal RAT owned by the band.
    7816             :  */
    7817             : 
    7818         112 : GDALRasterAttributeTable *GDALRasterBand::GetDefaultRAT()
    7819             : 
    7820             : {
    7821         112 :     return nullptr;
    7822             : }
    7823             : 
    7824             : /************************************************************************/
    7825             : /*                         GDALGetDefaultRAT()                          */
    7826             : /************************************************************************/
    7827             : 
    7828             : /**
    7829             :  * \brief Fetch default Raster Attribute Table.
    7830             :  *
    7831             :  * @see GDALRasterBand::GetDefaultRAT()
    7832             :  */
    7833             : 
    7834         935 : GDALRasterAttributeTableH CPL_STDCALL GDALGetDefaultRAT(GDALRasterBandH hBand)
    7835             : 
    7836             : {
    7837         935 :     VALIDATE_POINTER1(hBand, "GDALGetDefaultRAT", nullptr);
    7838             : 
    7839         935 :     GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
    7840         935 :     return GDALRasterAttributeTable::ToHandle(poBand->GetDefaultRAT());
    7841             : }
    7842             : 
    7843             : /************************************************************************/
    7844             : /*                           SetDefaultRAT()                            */
    7845             : /************************************************************************/
    7846             : 
    7847             : /**
    7848             :  * \fn GDALRasterBand::SetDefaultRAT(const GDALRasterAttributeTable*)
    7849             :  * \brief Set default Raster Attribute Table.
    7850             :  *
    7851             :  * Associates a default RAT with the band.  If not implemented for the
    7852             :  * format a CPLE_NotSupported error will be issued.  If successful a copy
    7853             :  * of the RAT is made, the original remains owned by the caller.
    7854             :  *
    7855             :  * This method is the same as the C function GDALSetDefaultRAT().
    7856             :  *
    7857             :  * @param poRAT the RAT to assign to the band.
    7858             :  *
    7859             :  * @return CE_None on success or CE_Failure if unsupported or otherwise
    7860             :  * failing.
    7861             :  */
    7862             : 
    7863             : /**/
    7864             : /**/
    7865             : 
    7866             : CPLErr
    7867           0 : GDALRasterBand::SetDefaultRAT(const GDALRasterAttributeTable * /* poRAT */)
    7868             : {
    7869           0 :     if (!(GetMOFlags() & GMO_IGNORE_UNIMPLEMENTED))
    7870             :     {
    7871           0 :         CPLPushErrorHandler(CPLQuietErrorHandler);
    7872           0 :         ReportError(CE_Failure, CPLE_NotSupported,
    7873             :                     "SetDefaultRAT() not implemented for this format.");
    7874           0 :         CPLPopErrorHandler();
    7875             :     }
    7876           0 :     return CE_Failure;
    7877             : }
    7878             : 
    7879             : /************************************************************************/
    7880             : /*                         GDALSetDefaultRAT()                          */
    7881             : /************************************************************************/
    7882             : 
    7883             : /**
    7884             :  * \brief Set default Raster Attribute Table.
    7885             :  *
    7886             :  * @see GDALRasterBand::GDALSetDefaultRAT()
    7887             :  */
    7888             : 
    7889          18 : CPLErr CPL_STDCALL GDALSetDefaultRAT(GDALRasterBandH hBand,
    7890             :                                      GDALRasterAttributeTableH hRAT)
    7891             : 
    7892             : {
    7893          18 :     VALIDATE_POINTER1(hBand, "GDALSetDefaultRAT", CE_Failure);
    7894             : 
    7895          18 :     GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
    7896             : 
    7897          18 :     return poBand->SetDefaultRAT(GDALRasterAttributeTable::FromHandle(hRAT));
    7898             : }
    7899             : 
    7900             : /************************************************************************/
    7901             : /*                            GetMaskBand()                             */
    7902             : /************************************************************************/
    7903             : 
    7904             : /**
    7905             :  * \brief Return the mask band associated with the band.
    7906             :  *
    7907             :  * The GDALRasterBand class includes a default implementation of GetMaskBand()
    7908             :  * that returns one of four default implementations :
    7909             :  * <ul>
    7910             :  * <li>If a corresponding .msk file exists it will be used for the mask band.
    7911             :  * </li>
    7912             :  * <li>If the dataset has a NODATA_VALUES metadata item, an instance of the new
    7913             :  * GDALNoDataValuesMaskBand class will be returned. GetMaskFlags() will return
    7914             :  * GMF_NODATA | GMF_PER_DATASET.
    7915             :  * </li>
    7916             :  * <li>If the band has a nodata value set, an instance of the new
    7917             :  * GDALNodataMaskRasterBand class will be returned. GetMaskFlags() will return
    7918             :  * GMF_NODATA.
    7919             :  * </li>
    7920             :  * <li>If there is no nodata value, but the dataset has an alpha band that seems
    7921             :  * to apply to this band (specific rules yet to be determined) and that is of
    7922             :  * type GDT_Byte then that alpha band will be returned, and the flags
    7923             :  * GMF_PER_DATASET and GMF_ALPHA will be returned in the flags.
    7924             :  * </li>
    7925             :  * <li>If neither of the above apply, an instance of the new
    7926             :  * GDALAllValidRasterBand class will be returned that has 255 values for all
    7927             :  * pixels. The null flags will return GMF_ALL_VALID.
    7928             :  * </li>
    7929             :  * </ul>
    7930             :  *
    7931             :  * Note that the GetMaskBand() should always return a GDALRasterBand mask, even
    7932             :  * if it is only an all 255 mask with the flags indicating GMF_ALL_VALID.
    7933             :  *
    7934             :  * For an external .msk file to be recognized by GDAL, it must be a valid GDAL
    7935             :  * dataset, with the same name as the main dataset and suffixed with .msk,
    7936             :  * with either one band (in the GMF_PER_DATASET case), or as many bands as the
    7937             :  * main dataset.
    7938             :  * It must have INTERNAL_MASK_FLAGS_xx metadata items set at the dataset
    7939             :  * level, where xx matches the band number of a band of the main dataset. The
    7940             :  * value of those items is a combination of the flags GMF_ALL_VALID,
    7941             :  * GMF_PER_DATASET, GMF_ALPHA and GMF_NODATA. If a metadata item is missing for
    7942             :  * a band, then the other rules explained above will be used to generate a
    7943             :  * on-the-fly mask band.
    7944             :  * \see CreateMaskBand() for the characteristics of .msk files created by GDAL.
    7945             :  *
    7946             :  * This method is the same as the C function GDALGetMaskBand().
    7947             :  *
    7948             :  * @return a valid mask band.
    7949             :  *
    7950             :  * @since GDAL 1.5.0
    7951             :  *
    7952             :  * @see https://gdal.org/development/rfc/rfc15_nodatabitmask.html
    7953             :  *
    7954             :  */
    7955      741828 : GDALRasterBand *GDALRasterBand::GetMaskBand()
    7956             : 
    7957             : {
    7958      178011 :     const auto HasNoData = [this]()
    7959             :     {
    7960       59087 :         int bHaveNoDataRaw = FALSE;
    7961       59087 :         bool bHaveNoData = false;
    7962       59087 :         if (eDataType == GDT_Int64)
    7963             :         {
    7964          54 :             CPL_IGNORE_RET_VAL(GetNoDataValueAsInt64(&bHaveNoDataRaw));
    7965          54 :             bHaveNoData = CPL_TO_BOOL(bHaveNoDataRaw);
    7966             :         }
    7967       59033 :         else if (eDataType == GDT_UInt64)
    7968             :         {
    7969          41 :             CPL_IGNORE_RET_VAL(GetNoDataValueAsUInt64(&bHaveNoDataRaw));
    7970          41 :             bHaveNoData = CPL_TO_BOOL(bHaveNoDataRaw);
    7971             :         }
    7972             :         else
    7973             :         {
    7974       58992 :             const double dfNoDataValue = GetNoDataValue(&bHaveNoDataRaw);
    7975       57814 :             if (bHaveNoDataRaw &&
    7976       57814 :                 GDALNoDataMaskBand::IsNoDataInRange(dfNoDataValue, eDataType))
    7977             :             {
    7978         775 :                 bHaveNoData = true;
    7979             :             }
    7980             :         }
    7981       57196 :         return bHaveNoData;
    7982      741828 :     };
    7983             : 
    7984      741828 :     if (poMask != nullptr)
    7985             :     {
    7986      700202 :         if (poMask.IsOwned())
    7987             :         {
    7988      330309 :             if (dynamic_cast<GDALAllValidMaskBand *>(poMask.get()) != nullptr)
    7989             :             {
    7990       31810 :                 if (HasNoData())
    7991             :                 {
    7992           9 :                     InvalidateMaskBand();
    7993             :                 }
    7994             :             }
    7995      300047 :             else if (auto poNoDataMaskBand =
    7996      298982 :                          dynamic_cast<GDALNoDataMaskBand *>(poMask.get()))
    7997             :             {
    7998         157 :                 int bHaveNoDataRaw = FALSE;
    7999         157 :                 bool bIsSame = false;
    8000         157 :                 if (eDataType == GDT_Int64)
    8001           9 :                     bIsSame = poNoDataMaskBand->m_nNoDataValueInt64 ==
    8002          11 :                                   GetNoDataValueAsInt64(&bHaveNoDataRaw) &&
    8003           2 :                               bHaveNoDataRaw;
    8004         148 :                 else if (eDataType == GDT_UInt64)
    8005           9 :                     bIsSame = poNoDataMaskBand->m_nNoDataValueUInt64 ==
    8006          11 :                                   GetNoDataValueAsUInt64(&bHaveNoDataRaw) &&
    8007           2 :                               bHaveNoDataRaw;
    8008             :                 else
    8009             :                 {
    8010             :                     const double dfNoDataValue =
    8011         139 :                         GetNoDataValue(&bHaveNoDataRaw);
    8012         139 :                     if (bHaveNoDataRaw)
    8013             :                     {
    8014         136 :                         bIsSame =
    8015         136 :                             std::isnan(dfNoDataValue)
    8016         136 :                                 ? std::isnan(poNoDataMaskBand->m_dfNoDataValue)
    8017         128 :                                 : poNoDataMaskBand->m_dfNoDataValue ==
    8018             :                                       dfNoDataValue;
    8019             :                     }
    8020             :                 }
    8021         157 :                 if (!bIsSame)
    8022          23 :                     InvalidateMaskBand();
    8023             :             }
    8024             :         }
    8025             : 
    8026      702595 :         if (poMask)
    8027      707080 :             return poMask.get();
    8028             :     }
    8029             : 
    8030             :     /* -------------------------------------------------------------------- */
    8031             :     /*      Check for a mask in a .msk file.                                */
    8032             :     /* -------------------------------------------------------------------- */
    8033       27426 :     if (poDS != nullptr && poDS->oOvManager.HaveMaskFile())
    8034             :     {
    8035          46 :         poMask.reset(poDS->oOvManager.GetMaskBand(nBand), false);
    8036          46 :         if (poMask != nullptr)
    8037             :         {
    8038          44 :             nMaskFlags = poDS->oOvManager.GetMaskFlags(nBand);
    8039          44 :             return poMask.get();
    8040             :         }
    8041             :     }
    8042             : 
    8043             :     /* -------------------------------------------------------------------- */
    8044             :     /*      Check for NODATA_VALUES metadata.                               */
    8045             :     /* -------------------------------------------------------------------- */
    8046       27382 :     if (poDS != nullptr)
    8047             :     {
    8048       27366 :         const char *pszNoDataValues = poDS->GetMetadataItem("NODATA_VALUES");
    8049       27366 :         if (pszNoDataValues != nullptr)
    8050             :         {
    8051             :             char **papszNoDataValues =
    8052          56 :                 CSLTokenizeStringComplex(pszNoDataValues, " ", FALSE, FALSE);
    8053             : 
    8054             :             // Make sure we have as many values as bands.
    8055         112 :             if (CSLCount(papszNoDataValues) == poDS->GetRasterCount() &&
    8056          56 :                 poDS->GetRasterCount() != 0)
    8057             :             {
    8058             :                 // Make sure that all bands have the same data type
    8059             :                 // This is clearly not a fundamental condition, just a
    8060             :                 // condition to make implementation easier.
    8061          56 :                 GDALDataType eDT = GDT_Unknown;
    8062          56 :                 int i = 0;  // Used after for.
    8063         224 :                 for (; i < poDS->GetRasterCount(); ++i)
    8064             :                 {
    8065         168 :                     if (i == 0)
    8066          56 :                         eDT = poDS->GetRasterBand(1)->GetRasterDataType();
    8067         112 :                     else if (eDT !=
    8068         112 :                              poDS->GetRasterBand(i + 1)->GetRasterDataType())
    8069             :                     {
    8070           0 :                         break;
    8071             :                     }
    8072             :                 }
    8073          56 :                 if (i == poDS->GetRasterCount())
    8074             :                 {
    8075          56 :                     nMaskFlags = GMF_NODATA | GMF_PER_DATASET;
    8076             :                     try
    8077             :                     {
    8078          56 :                         poMask.reset(new GDALNoDataValuesMaskBand(poDS), true);
    8079             :                     }
    8080           0 :                     catch (const std::bad_alloc &)
    8081             :                     {
    8082           0 :                         CPLError(CE_Failure, CPLE_OutOfMemory, "Out of memory");
    8083           0 :                         poMask.reset();
    8084             :                     }
    8085          56 :                     CSLDestroy(papszNoDataValues);
    8086          56 :                     return poMask.get();
    8087             :                 }
    8088             :                 else
    8089             :                 {
    8090           0 :                     ReportError(CE_Warning, CPLE_AppDefined,
    8091             :                                 "All bands should have the same type in "
    8092             :                                 "order the NODATA_VALUES metadata item "
    8093             :                                 "to be used as a mask.");
    8094             :                 }
    8095             :             }
    8096             :             else
    8097             :             {
    8098           0 :                 ReportError(
    8099             :                     CE_Warning, CPLE_AppDefined,
    8100             :                     "NODATA_VALUES metadata item doesn't have the same number "
    8101             :                     "of values as the number of bands.  "
    8102             :                     "Ignoring it for mask.");
    8103             :             }
    8104             : 
    8105           0 :             CSLDestroy(papszNoDataValues);
    8106             :         }
    8107             :     }
    8108             : 
    8109             :     /* -------------------------------------------------------------------- */
    8110             :     /*      Check for nodata case.                                          */
    8111             :     /* -------------------------------------------------------------------- */
    8112       27326 :     if (HasNoData())
    8113             :     {
    8114         797 :         nMaskFlags = GMF_NODATA;
    8115             :         try
    8116             :         {
    8117         797 :             poMask.reset(new GDALNoDataMaskBand(this), true);
    8118             :         }
    8119           0 :         catch (const std::bad_alloc &)
    8120             :         {
    8121           0 :             CPLError(CE_Failure, CPLE_OutOfMemory, "Out of memory");
    8122           0 :             poMask.reset();
    8123             :         }
    8124         797 :         return poMask.get();
    8125             :     }
    8126             : 
    8127             :     /* -------------------------------------------------------------------- */
    8128             :     /*      Check for alpha case.                                           */
    8129             :     /* -------------------------------------------------------------------- */
    8130       26514 :     if (poDS != nullptr && poDS->GetRasterCount() == 2 &&
    8131       53550 :         this == poDS->GetRasterBand(1) &&
    8132         507 :         poDS->GetRasterBand(2)->GetColorInterpretation() == GCI_AlphaBand)
    8133             :     {
    8134         186 :         if (poDS->GetRasterBand(2)->GetRasterDataType() == GDT_Byte)
    8135             :         {
    8136         142 :             nMaskFlags = GMF_ALPHA | GMF_PER_DATASET;
    8137         142 :             poMask.reset(poDS->GetRasterBand(2), false);
    8138         142 :             return poMask.get();
    8139             :         }
    8140          44 :         else if (poDS->GetRasterBand(2)->GetRasterDataType() == GDT_UInt16)
    8141             :         {
    8142          23 :             nMaskFlags = GMF_ALPHA | GMF_PER_DATASET;
    8143             :             try
    8144             :             {
    8145          23 :                 poMask.reset(new GDALRescaledAlphaBand(poDS->GetRasterBand(2)),
    8146             :                              true);
    8147             :             }
    8148           0 :             catch (const std::bad_alloc &)
    8149             :             {
    8150           0 :                 CPLError(CE_Failure, CPLE_OutOfMemory, "Out of memory");
    8151           0 :                 poMask.reset();
    8152             :             }
    8153          23 :             return poMask.get();
    8154             :         }
    8155             :     }
    8156             : 
    8157       26349 :     if (poDS != nullptr && poDS->GetRasterCount() == 4 &&
    8158        2668 :         (this == poDS->GetRasterBand(1) || this == poDS->GetRasterBand(2) ||
    8159       53350 :          this == poDS->GetRasterBand(3)) &&
    8160        2079 :         poDS->GetRasterBand(4)->GetColorInterpretation() == GCI_AlphaBand)
    8161             :     {
    8162        1197 :         if (poDS->GetRasterBand(4)->GetRasterDataType() == GDT_Byte)
    8163             :         {
    8164        1150 :             nMaskFlags = GMF_ALPHA | GMF_PER_DATASET;
    8165        1150 :             poMask.reset(poDS->GetRasterBand(4), false);
    8166        1150 :             return poMask.get();
    8167             :         }
    8168          47 :         else if (poDS->GetRasterBand(4)->GetRasterDataType() == GDT_UInt16)
    8169             :         {
    8170          35 :             nMaskFlags = GMF_ALPHA | GMF_PER_DATASET;
    8171             :             try
    8172             :             {
    8173          35 :                 poMask.reset(new GDALRescaledAlphaBand(poDS->GetRasterBand(4)),
    8174             :                              true);
    8175             :             }
    8176           0 :             catch (const std::bad_alloc &)
    8177             :             {
    8178           0 :                 CPLError(CE_Failure, CPLE_OutOfMemory, "Out of memory");
    8179           0 :                 poMask.reset();
    8180             :             }
    8181          35 :             return poMask.get();
    8182             :         }
    8183             :     }
    8184             : 
    8185             :     /* -------------------------------------------------------------------- */
    8186             :     /*      Fallback to all valid case.                                     */
    8187             :     /* -------------------------------------------------------------------- */
    8188       25179 :     nMaskFlags = GMF_ALL_VALID;
    8189             :     try
    8190             :     {
    8191       25179 :         poMask.reset(new GDALAllValidMaskBand(this), true);
    8192             :     }
    8193           0 :     catch (const std::bad_alloc &)
    8194             :     {
    8195           0 :         CPLError(CE_Failure, CPLE_OutOfMemory, "Out of memory");
    8196           0 :         poMask.reset();
    8197             :     }
    8198             : 
    8199       25179 :     return poMask.get();
    8200             : }
    8201             : 
    8202             : /************************************************************************/
    8203             : /*                          GDALGetMaskBand()                           */
    8204             : /************************************************************************/
    8205             : 
    8206             : /**
    8207             :  * \brief Return the mask band associated with the band.
    8208             :  *
    8209             :  * @see GDALRasterBand::GetMaskBand()
    8210             :  */
    8211             : 
    8212       10879 : GDALRasterBandH CPL_STDCALL GDALGetMaskBand(GDALRasterBandH hBand)
    8213             : 
    8214             : {
    8215       10879 :     VALIDATE_POINTER1(hBand, "GDALGetMaskBand", nullptr);
    8216             : 
    8217       10879 :     GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
    8218       10879 :     return poBand->GetMaskBand();
    8219             : }
    8220             : 
    8221             : /************************************************************************/
    8222             : /*                            GetMaskFlags()                            */
    8223             : /************************************************************************/
    8224             : 
    8225             : /**
    8226             :  * \brief Return the status flags of the mask band associated with the band.
    8227             :  *
    8228             :  * The GetMaskFlags() method returns an bitwise OR-ed set of status flags with
    8229             :  * the following available definitions that may be extended in the future:
    8230             :  * <ul>
    8231             :  * <li>GMF_ALL_VALID(0x01): There are no invalid pixels, all mask values will be
    8232             :  * 255. When used this will normally be the only flag set.
    8233             :  * </li>
    8234             :  * <li>GMF_PER_DATASET(0x02): The mask band is shared between all bands on the
    8235             :  * dataset.
    8236             :  * </li>
    8237             :  * <li>GMF_ALPHA(0x04): The mask band is actually an alpha band
    8238             :  * and may have values other than 0 and 255.
    8239             :  * </li>
    8240             :  * <li>GMF_NODATA(0x08): Indicates the mask is actually being generated from
    8241             :  * nodata values. (mutually exclusive of GMF_ALPHA)
    8242             :  * </li>
    8243             :  * </ul>
    8244             :  *
    8245             :  * The GDALRasterBand class includes a default implementation of GetMaskBand()
    8246             :  * that returns one of four default implementations:
    8247             :  * <ul>
    8248             :  * <li>If a corresponding .msk file exists it will be used for the mask band.
    8249             :  * </li>
    8250             :  * <li>If the dataset has a NODATA_VALUES metadata item, an instance of the new
    8251             :  * GDALNoDataValuesMaskBand class will be returned. GetMaskFlags() will return
    8252             :  * GMF_NODATA | GMF_PER_DATASET.
    8253             :  * </li>
    8254             :  * <li>If the band has a nodata value set, an instance of the new
    8255             :  * GDALNodataMaskRasterBand class will be returned. GetMaskFlags() will return
    8256             :  * GMF_NODATA.
    8257             :  * </li>
    8258             :  * <li>If there is no nodata value, but the dataset has an alpha band that
    8259             :  * seems to apply to this band (specific rules yet to be determined) and that is
    8260             :  * of type GDT_Byte then that alpha band will be returned, and the flags
    8261             :  * GMF_PER_DATASET and GMF_ALPHA will be returned in the flags.
    8262             :  * </li>
    8263             :  * <li>If neither of the above apply, an instance of the new
    8264             :  * GDALAllValidRasterBand class will be returned that has 255 values for all
    8265             :  * pixels. The null flags will return GMF_ALL_VALID.
    8266             :  * </li>
    8267             :  * </ul>
    8268             :  *
    8269             :  * For an external .msk file to be recognized by GDAL, it must be a valid GDAL
    8270             :  * dataset, with the same name as the main dataset and suffixed with .msk,
    8271             :  * with either one band (in the GMF_PER_DATASET case), or as many bands as the
    8272             :  * main dataset.
    8273             :  * It must have INTERNAL_MASK_FLAGS_xx metadata items set at the dataset
    8274             :  * level, where xx matches the band number of a band of the main dataset. The
    8275             :  * value of those items is a combination of the flags GMF_ALL_VALID,
    8276             :  * GMF_PER_DATASET, GMF_ALPHA and GMF_NODATA. If a metadata item is missing for
    8277             :  * a band, then the other rules explained above will be used to generate a
    8278             :  * on-the-fly mask band.
    8279             :  * \see CreateMaskBand() for the characteristics of .msk files created by GDAL.
    8280             :  *
    8281             :  * This method is the same as the C function GDALGetMaskFlags().
    8282             :  *
    8283             :  * @since GDAL 1.5.0
    8284             :  *
    8285             :  * @return a valid mask band.
    8286             :  *
    8287             :  * @see https://gdal.org/development/rfc/rfc15_nodatabitmask.html
    8288             :  *
    8289             :  */
    8290       78259 : int GDALRasterBand::GetMaskFlags()
    8291             : 
    8292             : {
    8293             :     // If we don't have a band yet, force this now so that the masks value
    8294             :     // will be initialized.
    8295             : 
    8296       78259 :     if (poMask == nullptr)
    8297       26208 :         GetMaskBand();
    8298             : 
    8299       78255 :     return nMaskFlags;
    8300             : }
    8301             : 
    8302             : /************************************************************************/
    8303             : /*                          GDALGetMaskFlags()                          */
    8304             : /************************************************************************/
    8305             : 
    8306             : /**
    8307             :  * \brief Return the status flags of the mask band associated with the band.
    8308             :  *
    8309             :  * @see GDALRasterBand::GetMaskFlags()
    8310             :  */
    8311             : 
    8312        6028 : int CPL_STDCALL GDALGetMaskFlags(GDALRasterBandH hBand)
    8313             : 
    8314             : {
    8315        6028 :     VALIDATE_POINTER1(hBand, "GDALGetMaskFlags", GMF_ALL_VALID);
    8316             : 
    8317        6028 :     GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
    8318        6028 :     return poBand->GetMaskFlags();
    8319             : }
    8320             : 
    8321             : /************************************************************************/
    8322             : /*                         InvalidateMaskBand()                         */
    8323             : /************************************************************************/
    8324             : 
    8325             : //! @cond Doxygen_Suppress
    8326     1063940 : void GDALRasterBand::InvalidateMaskBand()
    8327             : {
    8328     1063940 :     poMask.reset();
    8329     1063930 :     nMaskFlags = 0;
    8330     1063930 : }
    8331             : 
    8332             : //! @endcond
    8333             : 
    8334             : /************************************************************************/
    8335             : /*                           CreateMaskBand()                           */
    8336             : /************************************************************************/
    8337             : 
    8338             : /**
    8339             :  * \brief Adds a mask band to the current band
    8340             :  *
    8341             :  * The default implementation of the CreateMaskBand() method is implemented
    8342             :  * based on similar rules to the .ovr handling implemented using the
    8343             :  * GDALDefaultOverviews object. A TIFF file with the extension .msk will
    8344             :  * be created with the same basename as the original file, and it will have
    8345             :  * as many bands as the original image (or just one for GMF_PER_DATASET).
    8346             :  * The mask images will be deflate compressed tiled images with the same
    8347             :  * block size as the original image if possible.
    8348             :  * It will have INTERNAL_MASK_FLAGS_xx metadata items set at the dataset
    8349             :  * level, where xx matches the band number of a band of the main dataset. The
    8350             :  * value of those items will be the one of the nFlagsIn parameter.
    8351             :  *
    8352             :  * Note that if you got a mask band with a previous call to GetMaskBand(),
    8353             :  * it might be invalidated by CreateMaskBand(). So you have to call
    8354             :  * GetMaskBand() again.
    8355             :  *
    8356             :  * This method is the same as the C function GDALCreateMaskBand().
    8357             :  *
    8358             :  * @since GDAL 1.5.0
    8359             :  *
    8360             :  * @param nFlagsIn 0 or combination of GMF_PER_DATASET / GMF_ALPHA.
    8361             :  *
    8362             :  * @return CE_None on success or CE_Failure on an error.
    8363             :  *
    8364             :  * @see https://gdal.org/development/rfc/rfc15_nodatabitmask.html
    8365             :  * @see GDALDataset::CreateMaskBand()
    8366             :  *
    8367             :  */
    8368             : 
    8369           9 : CPLErr GDALRasterBand::CreateMaskBand(int nFlagsIn)
    8370             : 
    8371             : {
    8372           9 :     if (poDS != nullptr && poDS->oOvManager.IsInitialized())
    8373             :     {
    8374           9 :         const CPLErr eErr = poDS->oOvManager.CreateMaskBand(nFlagsIn, nBand);
    8375           9 :         if (eErr != CE_None)
    8376           1 :             return eErr;
    8377             : 
    8378           8 :         InvalidateMaskBand();
    8379             : 
    8380           8 :         return CE_None;
    8381             :     }
    8382             : 
    8383           0 :     ReportError(CE_Failure, CPLE_NotSupported,
    8384             :                 "CreateMaskBand() not supported for this band.");
    8385             : 
    8386           0 :     return CE_Failure;
    8387             : }
    8388             : 
    8389             : /************************************************************************/
    8390             : /*                         GDALCreateMaskBand()                         */
    8391             : /************************************************************************/
    8392             : 
    8393             : /**
    8394             :  * \brief Adds a mask band to the current band
    8395             :  *
    8396             :  * @see GDALRasterBand::CreateMaskBand()
    8397             :  */
    8398             : 
    8399          33 : CPLErr CPL_STDCALL GDALCreateMaskBand(GDALRasterBandH hBand, int nFlags)
    8400             : 
    8401             : {
    8402          33 :     VALIDATE_POINTER1(hBand, "GDALCreateMaskBand", CE_Failure);
    8403             : 
    8404          33 :     GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
    8405          33 :     return poBand->CreateMaskBand(nFlags);
    8406             : }
    8407             : 
    8408             : /************************************************************************/
    8409             : /*                            IsMaskBand()                              */
    8410             : /************************************************************************/
    8411             : 
    8412             : /**
    8413             :  * \brief Returns whether a band is a mask band.
    8414             :  *
    8415             :  * Mask band must be understood in the broad term: it can be a per-dataset
    8416             :  * mask band, an alpha band, or an implicit mask band.
    8417             :  * Typically the return of GetMaskBand()->IsMaskBand() should be true.
    8418             :  *
    8419             :  * This method is the same as the C function GDALIsMaskBand().
    8420             :  *
    8421             :  * @return true if the band is a mask band.
    8422             :  *
    8423             :  * @see GDALDataset::CreateMaskBand()
    8424             :  *
    8425             :  * @since GDAL 3.5.0
    8426             :  *
    8427             :  */
    8428             : 
    8429         401 : bool GDALRasterBand::IsMaskBand() const
    8430             : {
    8431             :     // The GeoTIFF driver, among others, override this method to
    8432             :     // also handle external .msk bands.
    8433         401 :     return const_cast<GDALRasterBand *>(this)->GetColorInterpretation() ==
    8434         401 :            GCI_AlphaBand;
    8435             : }
    8436             : 
    8437             : /************************************************************************/
    8438             : /*                            GDALIsMaskBand()                          */
    8439             : /************************************************************************/
    8440             : 
    8441             : /**
    8442             :  * \brief Returns whether a band is a mask band.
    8443             :  *
    8444             :  * Mask band must be understood in the broad term: it can be a per-dataset
    8445             :  * mask band, an alpha band, or an implicit mask band.
    8446             :  * Typically the return of GetMaskBand()->IsMaskBand() should be true.
    8447             :  *
    8448             :  * This function is the same as the C++ method GDALRasterBand::IsMaskBand()
    8449             :  *
    8450             :  * @return true if the band is a mask band.
    8451             :  *
    8452             :  * @see GDALRasterBand::IsMaskBand()
    8453             :  *
    8454             :  * @since GDAL 3.5.0
    8455             :  *
    8456             :  */
    8457             : 
    8458          37 : bool GDALIsMaskBand(GDALRasterBandH hBand)
    8459             : 
    8460             : {
    8461          37 :     VALIDATE_POINTER1(hBand, "GDALIsMaskBand", false);
    8462             : 
    8463          37 :     const GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
    8464          37 :     return poBand->IsMaskBand();
    8465             : }
    8466             : 
    8467             : /************************************************************************/
    8468             : /*                         GetMaskValueRange()                          */
    8469             : /************************************************************************/
    8470             : 
    8471             : /**
    8472             :  * \brief Returns the range of values that a mask band can take.
    8473             :  *
    8474             :  * @return the range of values that a mask band can take.
    8475             :  *
    8476             :  * @since GDAL 3.5.0
    8477             :  *
    8478             :  */
    8479             : 
    8480           0 : GDALMaskValueRange GDALRasterBand::GetMaskValueRange() const
    8481             : {
    8482           0 :     return GMVR_UNKNOWN;
    8483             : }
    8484             : 
    8485             : /************************************************************************/
    8486             : /*                    GetIndexColorTranslationTo()                      */
    8487             : /************************************************************************/
    8488             : 
    8489             : /**
    8490             :  * \brief Compute translation table for color tables.
    8491             :  *
    8492             :  * When the raster band has a palette index, it may be useful to compute
    8493             :  * the "translation" of this palette to the palette of another band.
    8494             :  * The translation tries to do exact matching first, and then approximate
    8495             :  * matching if no exact matching is possible.
    8496             :  * This method returns a table such that table[i] = j where i is an index
    8497             :  * of the 'this' rasterband and j the corresponding index for the reference
    8498             :  * rasterband.
    8499             :  *
    8500             :  * This method is thought as internal to GDAL and is used for drivers
    8501             :  * like RPFTOC.
    8502             :  *
    8503             :  * The implementation only supports 1-byte palette rasterbands.
    8504             :  *
    8505             :  * @param poReferenceBand the raster band
    8506             :  * @param pTranslationTable an already allocated translation table (at least 256
    8507             :  * bytes), or NULL to let the method allocate it
    8508             :  * @param pApproximateMatching a pointer to a flag that is set if the matching
    8509             :  *                              is approximate. May be NULL.
    8510             :  *
    8511             :  * @return a translation table if the two bands are palette index and that they
    8512             :  * do not match or NULL in other cases. The table must be freed with CPLFree if
    8513             :  * NULL was passed for pTranslationTable.
    8514             :  */
    8515             : 
    8516             : unsigned char *
    8517           5 : GDALRasterBand::GetIndexColorTranslationTo(GDALRasterBand *poReferenceBand,
    8518             :                                            unsigned char *pTranslationTable,
    8519             :                                            int *pApproximateMatching)
    8520             : {
    8521           5 :     if (poReferenceBand == nullptr)
    8522           0 :         return nullptr;
    8523             : 
    8524             :     // cppcheck-suppress knownConditionTrueFalse
    8525           5 :     if (poReferenceBand->GetColorInterpretation() == GCI_PaletteIndex &&
    8526             :         // cppcheck-suppress knownConditionTrueFalse
    8527           5 :         GetColorInterpretation() == GCI_PaletteIndex &&
    8528          15 :         poReferenceBand->GetRasterDataType() == GDT_Byte &&
    8529           5 :         GetRasterDataType() == GDT_Byte)
    8530             :     {
    8531           5 :         const GDALColorTable *srcColorTable = GetColorTable();
    8532           5 :         GDALColorTable *destColorTable = poReferenceBand->GetColorTable();
    8533           5 :         if (srcColorTable != nullptr && destColorTable != nullptr)
    8534             :         {
    8535           5 :             const int nEntries = srcColorTable->GetColorEntryCount();
    8536           5 :             const int nRefEntries = destColorTable->GetColorEntryCount();
    8537             : 
    8538           5 :             int bHasNoDataValueSrc = FALSE;
    8539           5 :             double dfNoDataValueSrc = GetNoDataValue(&bHasNoDataValueSrc);
    8540           5 :             if (!(bHasNoDataValueSrc && dfNoDataValueSrc >= 0 &&
    8541           4 :                   dfNoDataValueSrc <= 255 &&
    8542           4 :                   dfNoDataValueSrc == static_cast<int>(dfNoDataValueSrc)))
    8543           1 :                 bHasNoDataValueSrc = FALSE;
    8544           5 :             const int noDataValueSrc =
    8545           5 :                 bHasNoDataValueSrc ? static_cast<int>(dfNoDataValueSrc) : 0;
    8546             : 
    8547           5 :             int bHasNoDataValueRef = FALSE;
    8548             :             const double dfNoDataValueRef =
    8549           5 :                 poReferenceBand->GetNoDataValue(&bHasNoDataValueRef);
    8550           5 :             if (!(bHasNoDataValueRef && dfNoDataValueRef >= 0 &&
    8551           3 :                   dfNoDataValueRef <= 255 &&
    8552           3 :                   dfNoDataValueRef == static_cast<int>(dfNoDataValueRef)))
    8553           2 :                 bHasNoDataValueRef = FALSE;
    8554           5 :             const int noDataValueRef =
    8555           5 :                 bHasNoDataValueRef ? static_cast<int>(dfNoDataValueRef) : 0;
    8556             : 
    8557           5 :             bool samePalette = false;
    8558             : 
    8559           5 :             if (pApproximateMatching)
    8560           3 :                 *pApproximateMatching = FALSE;
    8561             : 
    8562           5 :             if (nEntries == nRefEntries &&
    8563           4 :                 bHasNoDataValueSrc == bHasNoDataValueRef &&
    8564           4 :                 (bHasNoDataValueSrc == FALSE ||
    8565             :                  noDataValueSrc == noDataValueRef))
    8566             :             {
    8567           4 :                 samePalette = true;
    8568         911 :                 for (int i = 0; i < nEntries; ++i)
    8569             :                 {
    8570         907 :                     if (noDataValueSrc == i)
    8571           4 :                         continue;
    8572             :                     const GDALColorEntry *entry =
    8573         903 :                         srcColorTable->GetColorEntry(i);
    8574             :                     const GDALColorEntry *entryRef =
    8575         903 :                         destColorTable->GetColorEntry(i);
    8576         903 :                     if (entry->c1 != entryRef->c1 ||
    8577         903 :                         entry->c2 != entryRef->c2 || entry->c3 != entryRef->c3)
    8578             :                     {
    8579           0 :                         samePalette = false;
    8580             :                     }
    8581             :                 }
    8582             :             }
    8583             : 
    8584           5 :             if (!samePalette)
    8585             :             {
    8586           1 :                 if (pTranslationTable == nullptr)
    8587             :                 {
    8588             :                     pTranslationTable = static_cast<unsigned char *>(
    8589           1 :                         VSI_CALLOC_VERBOSE(1, std::max(256, nEntries)));
    8590           1 :                     if (pTranslationTable == nullptr)
    8591           1 :                         return nullptr;
    8592             :                 }
    8593             : 
    8594             :                 // Trying to remap the product palette on the subdataset
    8595             :                 // palette.
    8596           5 :                 for (int i = 0; i < nEntries; ++i)
    8597             :                 {
    8598           4 :                     if (bHasNoDataValueSrc && bHasNoDataValueRef &&
    8599             :                         noDataValueSrc == i)
    8600           0 :                         continue;
    8601             :                     const GDALColorEntry *entry =
    8602           4 :                         srcColorTable->GetColorEntry(i);
    8603           4 :                     bool bMatchFound = false;
    8604          13 :                     for (int j = 0; j < nRefEntries; ++j)
    8605             :                     {
    8606          10 :                         if (bHasNoDataValueRef && noDataValueRef == j)
    8607           0 :                             continue;
    8608             :                         const GDALColorEntry *entryRef =
    8609          10 :                             destColorTable->GetColorEntry(j);
    8610          10 :                         if (entry->c1 == entryRef->c1 &&
    8611           2 :                             entry->c2 == entryRef->c2 &&
    8612           2 :                             entry->c3 == entryRef->c3)
    8613             :                         {
    8614           1 :                             pTranslationTable[i] =
    8615             :                                 static_cast<unsigned char>(j);
    8616           1 :                             bMatchFound = true;
    8617           1 :                             break;
    8618             :                         }
    8619             :                     }
    8620           4 :                     if (!bMatchFound)
    8621             :                     {
    8622             :                         // No exact match. Looking for closest color now.
    8623           3 :                         int best_j = 0;
    8624           3 :                         int best_distance = 0;
    8625           3 :                         if (pApproximateMatching)
    8626           0 :                             *pApproximateMatching = TRUE;
    8627          12 :                         for (int j = 0; j < nRefEntries; ++j)
    8628             :                         {
    8629             :                             const GDALColorEntry *entryRef =
    8630           9 :                                 destColorTable->GetColorEntry(j);
    8631           9 :                             int distance = (entry->c1 - entryRef->c1) *
    8632           9 :                                                (entry->c1 - entryRef->c1) +
    8633           9 :                                            (entry->c2 - entryRef->c2) *
    8634           9 :                                                (entry->c2 - entryRef->c2) +
    8635           9 :                                            (entry->c3 - entryRef->c3) *
    8636           9 :                                                (entry->c3 - entryRef->c3);
    8637           9 :                             if (j == 0 || distance < best_distance)
    8638             :                             {
    8639           7 :                                 best_j = j;
    8640           7 :                                 best_distance = distance;
    8641             :                             }
    8642             :                         }
    8643           3 :                         pTranslationTable[i] =
    8644             :                             static_cast<unsigned char>(best_j);
    8645             :                     }
    8646             :                 }
    8647           1 :                 if (bHasNoDataValueRef && bHasNoDataValueSrc)
    8648           0 :                     pTranslationTable[noDataValueSrc] =
    8649             :                         static_cast<unsigned char>(noDataValueRef);
    8650             : 
    8651           1 :                 return pTranslationTable;
    8652             :             }
    8653             :         }
    8654             :     }
    8655           4 :     return nullptr;
    8656             : }
    8657             : 
    8658             : /************************************************************************/
    8659             : /*                         SetFlushBlockErr()                           */
    8660             : /************************************************************************/
    8661             : 
    8662             : /**
    8663             :  * \brief Store that an error occurred while writing a dirty block.
    8664             :  *
    8665             :  * This function stores the fact that an error occurred while writing a dirty
    8666             :  * block from GDALRasterBlock::FlushCacheBlock(). Indeed when dirty blocks are
    8667             :  * flushed when the block cache get full, it is not convenient/possible to
    8668             :  * report that a dirty block could not be written correctly. This function
    8669             :  * remembers the error and re-issue it from GDALRasterBand::FlushCache(),
    8670             :  * GDALRasterBand::WriteBlock() and GDALRasterBand::RasterIO(), which are
    8671             :  * places where the user can easily match the error with the relevant dataset.
    8672             :  */
    8673             : 
    8674           0 : void GDALRasterBand::SetFlushBlockErr(CPLErr eErr)
    8675             : {
    8676           0 :     eFlushBlockErr = eErr;
    8677           0 : }
    8678             : 
    8679             : /************************************************************************/
    8680             : /*                         IncDirtyBlocks()                             */
    8681             : /************************************************************************/
    8682             : 
    8683             : /**
    8684             :  * \brief Increment/decrement the number of dirty blocks
    8685             :  */
    8686             : 
    8687      494890 : void GDALRasterBand::IncDirtyBlocks(int nInc)
    8688             : {
    8689      494890 :     if (poBandBlockCache)
    8690      494889 :         poBandBlockCache->IncDirtyBlocks(nInc);
    8691      494891 : }
    8692             : 
    8693             : /************************************************************************/
    8694             : /*                            ReportError()                             */
    8695             : /************************************************************************/
    8696             : 
    8697             : #ifndef DOXYGEN_XML
    8698             : /**
    8699             :  * \brief Emits an error related to a raster band.
    8700             :  *
    8701             :  * This function is a wrapper for regular CPLError(). The only difference
    8702             :  * with CPLError() is that it prepends the error message with the dataset
    8703             :  * name and the band number.
    8704             :  *
    8705             :  * @param eErrClass one of CE_Warning, CE_Failure or CE_Fatal.
    8706             :  * @param err_no the error number (CPLE_*) from cpl_error.h.
    8707             :  * @param fmt a printf() style format string.  Any additional arguments
    8708             :  * will be treated as arguments to fill in this format in a manner
    8709             :  * similar to printf().
    8710             :  *
    8711             :  * @since GDAL 1.9.0
    8712             :  */
    8713             : 
    8714        2443 : void GDALRasterBand::ReportError(CPLErr eErrClass, CPLErrorNum err_no,
    8715             :                                  const char *fmt, ...) const
    8716             : {
    8717             :     va_list args;
    8718             : 
    8719        2443 :     va_start(args, fmt);
    8720             : 
    8721        2443 :     const char *pszDSName = poDS ? poDS->GetDescription() : "";
    8722        2442 :     pszDSName = CPLGetFilename(pszDSName);
    8723        2441 :     if (pszDSName[0] != '\0')
    8724             :     {
    8725        2387 :         CPLError(eErrClass, err_no, "%s",
    8726        4774 :                  CPLString()
    8727        2387 :                      .Printf("%s, band %d: ", pszDSName, GetBand())
    8728        4774 :                      .append(CPLString().vPrintf(fmt, args))
    8729             :                      .c_str());
    8730             :     }
    8731             :     else
    8732             :     {
    8733          54 :         CPLErrorV(eErrClass, err_no, fmt, args);
    8734             :     }
    8735             : 
    8736        2443 :     va_end(args);
    8737        2443 : }
    8738             : #endif
    8739             : 
    8740             : /************************************************************************/
    8741             : /*                           GetVirtualMemAuto()                        */
    8742             : /************************************************************************/
    8743             : 
    8744             : /** \brief Create a CPLVirtualMem object from a GDAL raster band object.
    8745             :  *
    8746             :  * Only supported on Linux and Unix systems with mmap() for now.
    8747             :  *
    8748             :  * This method allows creating a virtual memory object for a GDALRasterBand,
    8749             :  * that exposes the whole image data as a virtual array.
    8750             :  *
    8751             :  * The default implementation relies on GDALRasterBandGetVirtualMem(), but
    8752             :  * specialized implementation, such as for raw files, may also directly use
    8753             :  * mechanisms of the operating system to create a view of the underlying file
    8754             :  * into virtual memory ( CPLVirtualMemFileMapNew() )
    8755             :  *
    8756             :  * At the time of writing, the GeoTIFF driver and "raw" drivers (EHdr, ...)
    8757             :  * offer a specialized implementation with direct file mapping, provided that
    8758             :  * some requirements are met :
    8759             :  *   - for all drivers, the dataset must be backed by a "real" file in the file
    8760             :  *     system, and the byte ordering of multi-byte datatypes (Int16, etc.)
    8761             :  *     must match the native ordering of the CPU.
    8762             :  *   - in addition, for the GeoTIFF driver, the GeoTIFF file must be
    8763             :  * uncompressed, scanline oriented (i.e. not tiled). Strips must be organized in
    8764             :  * the file in sequential order, and be equally spaced (which is generally the
    8765             :  * case). Only power-of-two bit depths are supported (8 for GDT_Bye, 16 for
    8766             :  * GDT_Int16/GDT_UInt16, 32 for GDT_Float32 and 64 for GDT_Float64)
    8767             :  *
    8768             :  * The pointer returned remains valid until CPLVirtualMemFree() is called.
    8769             :  * CPLVirtualMemFree() must be called before the raster band object is
    8770             :  * destroyed.
    8771             :  *
    8772             :  * If p is such a pointer and base_type the type matching
    8773             :  * GDALGetRasterDataType(), the element of image coordinates (x, y) can be
    8774             :  * accessed with
    8775             :  * *(base_type*) ((GByte*)p + x * *pnPixelSpace + y * *pnLineSpace)
    8776             :  *
    8777             :  * This method is the same as the C GDALGetVirtualMemAuto() function.
    8778             :  *
    8779             :  * @param eRWFlag Either GF_Read to read the band, or GF_Write to
    8780             :  * read/write the band.
    8781             :  *
    8782             :  * @param pnPixelSpace Output parameter giving the byte offset from the start of
    8783             :  * one pixel value in the buffer to the start of the next pixel value within a
    8784             :  * scanline.
    8785             :  *
    8786             :  * @param pnLineSpace Output parameter giving the byte offset from the start of
    8787             :  * one scanline in the buffer to the start of the next.
    8788             :  *
    8789             :  * @param papszOptions NULL terminated list of options.
    8790             :  *                     If a specialized implementation exists, defining
    8791             :  * USE_DEFAULT_IMPLEMENTATION=YES will cause the default implementation to be
    8792             :  * used. On the contrary, starting with GDAL 2.2, defining
    8793             :  * USE_DEFAULT_IMPLEMENTATION=NO will prevent the default implementation from
    8794             :  * being used (thus only allowing efficient implementations to be used). When
    8795             :  * requiring or falling back to the default implementation, the following
    8796             :  *                     options are available : CACHE_SIZE (in bytes, defaults to
    8797             :  * 40 MB), PAGE_SIZE_HINT (in bytes), SINGLE_THREAD ("FALSE" / "TRUE", defaults
    8798             :  * to FALSE)
    8799             :  *
    8800             :  * @return a virtual memory object that must be unreferenced by
    8801             :  * CPLVirtualMemFree(), or NULL in case of failure.
    8802             :  *
    8803             :  * @since GDAL 1.11
    8804             :  */
    8805             : 
    8806           9 : CPLVirtualMem *GDALRasterBand::GetVirtualMemAuto(GDALRWFlag eRWFlag,
    8807             :                                                  int *pnPixelSpace,
    8808             :                                                  GIntBig *pnLineSpace,
    8809             :                                                  char **papszOptions)
    8810             : {
    8811           9 :     const char *pszImpl = CSLFetchNameValueDef(
    8812             :         papszOptions, "USE_DEFAULT_IMPLEMENTATION", "AUTO");
    8813           9 :     if (EQUAL(pszImpl, "NO") || EQUAL(pszImpl, "OFF") || EQUAL(pszImpl, "0") ||
    8814           8 :         EQUAL(pszImpl, "FALSE"))
    8815             :     {
    8816           1 :         return nullptr;
    8817             :     }
    8818             : 
    8819           8 :     const int nPixelSpace = GDALGetDataTypeSizeBytes(eDataType);
    8820           8 :     const GIntBig nLineSpace = static_cast<GIntBig>(nRasterXSize) * nPixelSpace;
    8821           8 :     if (pnPixelSpace)
    8822           8 :         *pnPixelSpace = nPixelSpace;
    8823           8 :     if (pnLineSpace)
    8824           8 :         *pnLineSpace = nLineSpace;
    8825             :     const size_t nCacheSize =
    8826           8 :         atoi(CSLFetchNameValueDef(papszOptions, "CACHE_SIZE", "40000000"));
    8827             :     const size_t nPageSizeHint =
    8828           8 :         atoi(CSLFetchNameValueDef(papszOptions, "PAGE_SIZE_HINT", "0"));
    8829           8 :     const bool bSingleThreadUsage = CPLTestBool(
    8830             :         CSLFetchNameValueDef(papszOptions, "SINGLE_THREAD", "FALSE"));
    8831           8 :     return GDALRasterBandGetVirtualMem(
    8832             :         GDALRasterBand::ToHandle(this), eRWFlag, 0, 0, nRasterXSize,
    8833             :         nRasterYSize, nRasterXSize, nRasterYSize, eDataType, nPixelSpace,
    8834             :         nLineSpace, nCacheSize, nPageSizeHint, bSingleThreadUsage,
    8835           8 :         papszOptions);
    8836             : }
    8837             : 
    8838             : /************************************************************************/
    8839             : /*                         GDALGetVirtualMemAuto()                      */
    8840             : /************************************************************************/
    8841             : 
    8842             : /**
    8843             :  * \brief Create a CPLVirtualMem object from a GDAL raster band object.
    8844             :  *
    8845             :  * @see GDALRasterBand::GetVirtualMemAuto()
    8846             :  */
    8847             : 
    8848          31 : CPLVirtualMem *GDALGetVirtualMemAuto(GDALRasterBandH hBand, GDALRWFlag eRWFlag,
    8849             :                                      int *pnPixelSpace, GIntBig *pnLineSpace,
    8850             :                                      CSLConstList papszOptions)
    8851             : {
    8852          31 :     VALIDATE_POINTER1(hBand, "GDALGetVirtualMemAuto", nullptr);
    8853             : 
    8854          31 :     GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
    8855             : 
    8856          31 :     return poBand->GetVirtualMemAuto(eRWFlag, pnPixelSpace, pnLineSpace,
    8857          31 :                                      const_cast<char **>(papszOptions));
    8858             : }
    8859             : 
    8860             : /************************************************************************/
    8861             : /*                        GDALGetDataCoverageStatus()                   */
    8862             : /************************************************************************/
    8863             : 
    8864             : /**
    8865             :  * \brief Get the coverage status of a sub-window of the raster.
    8866             :  *
    8867             :  * Returns whether a sub-window of the raster contains only data, only empty
    8868             :  * blocks or a mix of both. This function can be used to determine quickly
    8869             :  * if it is worth issuing RasterIO / ReadBlock requests in datasets that may
    8870             :  * be sparse.
    8871             :  *
    8872             :  * Empty blocks are blocks that are generally not physically present in the
    8873             :  * file, and when read through GDAL, contain only pixels whose value is the
    8874             :  * nodata value when it is set, or whose value is 0 when the nodata value is
    8875             :  * not set.
    8876             :  *
    8877             :  * The query is done in an efficient way without reading the actual pixel
    8878             :  * values. If not possible, or not implemented at all by the driver,
    8879             :  * GDAL_DATA_COVERAGE_STATUS_UNIMPLEMENTED | GDAL_DATA_COVERAGE_STATUS_DATA will
    8880             :  * be returned.
    8881             :  *
    8882             :  * The values that can be returned by the function are the following,
    8883             :  * potentially combined with the binary or operator :
    8884             :  * <ul>
    8885             :  * <li>GDAL_DATA_COVERAGE_STATUS_UNIMPLEMENTED : the driver does not implement
    8886             :  * GetDataCoverageStatus(). This flag should be returned together with
    8887             :  * GDAL_DATA_COVERAGE_STATUS_DATA.</li>
    8888             :  * <li>GDAL_DATA_COVERAGE_STATUS_DATA: There is (potentially) data in the
    8889             :  * queried window.</li> <li>GDAL_DATA_COVERAGE_STATUS_EMPTY: There is nodata in
    8890             :  * the queried window. This is typically identified by the concept of missing
    8891             :  * block in formats that supports it.
    8892             :  * </li>
    8893             :  * </ul>
    8894             :  *
    8895             :  * Note that GDAL_DATA_COVERAGE_STATUS_DATA might have false positives and
    8896             :  * should be interpreted more as hint of potential presence of data. For example
    8897             :  * if a GeoTIFF file is created with blocks filled with zeroes (or set to the
    8898             :  * nodata value), instead of using the missing block mechanism,
    8899             :  * GDAL_DATA_COVERAGE_STATUS_DATA will be returned. On the contrary,
    8900             :  * GDAL_DATA_COVERAGE_STATUS_EMPTY should have no false positives.
    8901             :  *
    8902             :  * The nMaskFlagStop should be generally set to 0. It can be set to a
    8903             :  * binary-or'ed mask of the above mentioned values to enable a quick exiting of
    8904             :  * the function as soon as the computed mask matches the nMaskFlagStop. For
    8905             :  * example, you can issue a request on the whole raster with nMaskFlagStop =
    8906             :  * GDAL_DATA_COVERAGE_STATUS_EMPTY. As soon as one missing block is encountered,
    8907             :  * the function will exit, so that you can potentially refine the requested area
    8908             :  * to find which particular region(s) have missing blocks.
    8909             :  *
    8910             :  * @see GDALRasterBand::GetDataCoverageStatus()
    8911             :  *
    8912             :  * @param hBand raster band
    8913             :  *
    8914             :  * @param nXOff The pixel offset to the top left corner of the region
    8915             :  * of the band to be queried. This would be zero to start from the left side.
    8916             :  *
    8917             :  * @param nYOff The line offset to the top left corner of the region
    8918             :  * of the band to be queried. This would be zero to start from the top.
    8919             :  *
    8920             :  * @param nXSize The width of the region of the band to be queried in pixels.
    8921             :  *
    8922             :  * @param nYSize The height of the region of the band to be queried in lines.
    8923             :  *
    8924             :  * @param nMaskFlagStop 0, or a binary-or'ed mask of possible values
    8925             :  * GDAL_DATA_COVERAGE_STATUS_UNIMPLEMENTED,
    8926             :  * GDAL_DATA_COVERAGE_STATUS_DATA and GDAL_DATA_COVERAGE_STATUS_EMPTY. As soon
    8927             :  * as the computation of the coverage matches the mask, the computation will be
    8928             :  * stopped. *pdfDataPct will not be valid in that case.
    8929             :  *
    8930             :  * @param pdfDataPct Optional output parameter whose pointed value will be set
    8931             :  * to the (approximate) percentage in [0,100] of pixels in the queried
    8932             :  * sub-window that have valid values. The implementation might not always be
    8933             :  * able to compute it, in which case it will be set to a negative value.
    8934             :  *
    8935             :  * @return a binary-or'ed combination of possible values
    8936             :  * GDAL_DATA_COVERAGE_STATUS_UNIMPLEMENTED,
    8937             :  * GDAL_DATA_COVERAGE_STATUS_DATA and GDAL_DATA_COVERAGE_STATUS_EMPTY
    8938             :  *
    8939             :  * @note Added in GDAL 2.2
    8940             :  */
    8941             : 
    8942          26 : int CPL_STDCALL GDALGetDataCoverageStatus(GDALRasterBandH hBand, int nXOff,
    8943             :                                           int nYOff, int nXSize, int nYSize,
    8944             :                                           int nMaskFlagStop, double *pdfDataPct)
    8945             : {
    8946          26 :     VALIDATE_POINTER1(hBand, "GDALGetDataCoverageStatus",
    8947             :                       GDAL_DATA_COVERAGE_STATUS_UNIMPLEMENTED);
    8948             : 
    8949          26 :     GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
    8950             : 
    8951          26 :     return poBand->GetDataCoverageStatus(nXOff, nYOff, nXSize, nYSize,
    8952          26 :                                          nMaskFlagStop, pdfDataPct);
    8953             : }
    8954             : 
    8955             : /************************************************************************/
    8956             : /*                          GetDataCoverageStatus()                     */
    8957             : /************************************************************************/
    8958             : 
    8959             : /**
    8960             :  * \fn GDALRasterBand::IGetDataCoverageStatus( int nXOff,
    8961             :  *                                           int nYOff,
    8962             :  *                                           int nXSize,
    8963             :  *                                           int nYSize,
    8964             :  *                                           int nMaskFlagStop,
    8965             :  *                                           double* pdfDataPct)
    8966             :  * \brief Get the coverage status of a sub-window of the raster.
    8967             :  *
    8968             :  * Returns whether a sub-window of the raster contains only data, only empty
    8969             :  * blocks or a mix of both. This function can be used to determine quickly
    8970             :  * if it is worth issuing RasterIO / ReadBlock requests in datasets that may
    8971             :  * be sparse.
    8972             :  *
    8973             :  * Empty blocks are blocks that contain only pixels whose value is the nodata
    8974             :  * value when it is set, or whose value is 0 when the nodata value is not set.
    8975             :  *
    8976             :  * The query is done in an efficient way without reading the actual pixel
    8977             :  * values. If not possible, or not implemented at all by the driver,
    8978             :  * GDAL_DATA_COVERAGE_STATUS_UNIMPLEMENTED | GDAL_DATA_COVERAGE_STATUS_DATA will
    8979             :  * be returned.
    8980             :  *
    8981             :  * The values that can be returned by the function are the following,
    8982             :  * potentially combined with the binary or operator :
    8983             :  * <ul>
    8984             :  * <li>GDAL_DATA_COVERAGE_STATUS_UNIMPLEMENTED : the driver does not implement
    8985             :  * GetDataCoverageStatus(). This flag should be returned together with
    8986             :  * GDAL_DATA_COVERAGE_STATUS_DATA.</li>
    8987             :  * <li>GDAL_DATA_COVERAGE_STATUS_DATA: There is (potentially) data in the
    8988             :  * queried window.</li> <li>GDAL_DATA_COVERAGE_STATUS_EMPTY: There is nodata in
    8989             :  * the queried window. This is typically identified by the concept of missing
    8990             :  * block in formats that supports it.
    8991             :  * </li>
    8992             :  * </ul>
    8993             :  *
    8994             :  * Note that GDAL_DATA_COVERAGE_STATUS_DATA might have false positives and
    8995             :  * should be interpreted more as hint of potential presence of data. For example
    8996             :  * if a GeoTIFF file is created with blocks filled with zeroes (or set to the
    8997             :  * nodata value), instead of using the missing block mechanism,
    8998             :  * GDAL_DATA_COVERAGE_STATUS_DATA will be returned. On the contrary,
    8999             :  * GDAL_DATA_COVERAGE_STATUS_EMPTY should have no false positives.
    9000             :  *
    9001             :  * The nMaskFlagStop should be generally set to 0. It can be set to a
    9002             :  * binary-or'ed mask of the above mentioned values to enable a quick exiting of
    9003             :  * the function as soon as the computed mask matches the nMaskFlagStop. For
    9004             :  * example, you can issue a request on the whole raster with nMaskFlagStop =
    9005             :  * GDAL_DATA_COVERAGE_STATUS_EMPTY. As soon as one missing block is encountered,
    9006             :  * the function will exit, so that you can potentially refine the requested area
    9007             :  * to find which particular region(s) have missing blocks.
    9008             :  *
    9009             :  * @see GDALGetDataCoverageStatus()
    9010             :  *
    9011             :  * @param nXOff The pixel offset to the top left corner of the region
    9012             :  * of the band to be queried. This would be zero to start from the left side.
    9013             :  *
    9014             :  * @param nYOff The line offset to the top left corner of the region
    9015             :  * of the band to be queried. This would be zero to start from the top.
    9016             :  *
    9017             :  * @param nXSize The width of the region of the band to be queried in pixels.
    9018             :  *
    9019             :  * @param nYSize The height of the region of the band to be queried in lines.
    9020             :  *
    9021             :  * @param nMaskFlagStop 0, or a binary-or'ed mask of possible values
    9022             :  * GDAL_DATA_COVERAGE_STATUS_UNIMPLEMENTED,
    9023             :  * GDAL_DATA_COVERAGE_STATUS_DATA and GDAL_DATA_COVERAGE_STATUS_EMPTY. As soon
    9024             :  * as the computation of the coverage matches the mask, the computation will be
    9025             :  * stopped. *pdfDataPct will not be valid in that case.
    9026             :  *
    9027             :  * @param pdfDataPct Optional output parameter whose pointed value will be set
    9028             :  * to the (approximate) percentage in [0,100] of pixels in the queried
    9029             :  * sub-window that have valid values. The implementation might not always be
    9030             :  * able to compute it, in which case it will be set to a negative value.
    9031             :  *
    9032             :  * @return a binary-or'ed combination of possible values
    9033             :  * GDAL_DATA_COVERAGE_STATUS_UNIMPLEMENTED,
    9034             :  * GDAL_DATA_COVERAGE_STATUS_DATA and GDAL_DATA_COVERAGE_STATUS_EMPTY
    9035             :  *
    9036             :  * @note Added in GDAL 2.2
    9037             :  */
    9038             : 
    9039             : /**
    9040             :  * \brief Get the coverage status of a sub-window of the raster.
    9041             :  *
    9042             :  * Returns whether a sub-window of the raster contains only data, only empty
    9043             :  * blocks or a mix of both. This function can be used to determine quickly
    9044             :  * if it is worth issuing RasterIO / ReadBlock requests in datasets that may
    9045             :  * be sparse.
    9046             :  *
    9047             :  * Empty blocks are blocks that contain only pixels whose value is the nodata
    9048             :  * value when it is set, or whose value is 0 when the nodata value is not set.
    9049             :  *
    9050             :  * The query is done in an efficient way without reading the actual pixel
    9051             :  * values. If not possible, or not implemented at all by the driver,
    9052             :  * GDAL_DATA_COVERAGE_STATUS_UNIMPLEMENTED | GDAL_DATA_COVERAGE_STATUS_DATA will
    9053             :  * be returned.
    9054             :  *
    9055             :  * The values that can be returned by the function are the following,
    9056             :  * potentially combined with the binary or operator :
    9057             :  * <ul>
    9058             :  * <li>GDAL_DATA_COVERAGE_STATUS_UNIMPLEMENTED : the driver does not implement
    9059             :  * GetDataCoverageStatus(). This flag should be returned together with
    9060             :  * GDAL_DATA_COVERAGE_STATUS_DATA.</li>
    9061             :  * <li>GDAL_DATA_COVERAGE_STATUS_DATA: There is (potentially) data in the
    9062             :  * queried window.</li> <li>GDAL_DATA_COVERAGE_STATUS_EMPTY: There is nodata in
    9063             :  * the queried window. This is typically identified by the concept of missing
    9064             :  * block in formats that supports it.
    9065             :  * </li>
    9066             :  * </ul>
    9067             :  *
    9068             :  * Note that GDAL_DATA_COVERAGE_STATUS_DATA might have false positives and
    9069             :  * should be interpreted more as hint of potential presence of data. For example
    9070             :  * if a GeoTIFF file is created with blocks filled with zeroes (or set to the
    9071             :  * nodata value), instead of using the missing block mechanism,
    9072             :  * GDAL_DATA_COVERAGE_STATUS_DATA will be returned. On the contrary,
    9073             :  * GDAL_DATA_COVERAGE_STATUS_EMPTY should have no false positives.
    9074             :  *
    9075             :  * The nMaskFlagStop should be generally set to 0. It can be set to a
    9076             :  * binary-or'ed mask of the above mentioned values to enable a quick exiting of
    9077             :  * the function as soon as the computed mask matches the nMaskFlagStop. For
    9078             :  * example, you can issue a request on the whole raster with nMaskFlagStop =
    9079             :  * GDAL_DATA_COVERAGE_STATUS_EMPTY. As soon as one missing block is encountered,
    9080             :  * the function will exit, so that you can potentially refine the requested area
    9081             :  * to find which particular region(s) have missing blocks.
    9082             :  *
    9083             :  * @see GDALGetDataCoverageStatus()
    9084             :  *
    9085             :  * @param nXOff The pixel offset to the top left corner of the region
    9086             :  * of the band to be queried. This would be zero to start from the left side.
    9087             :  *
    9088             :  * @param nYOff The line offset to the top left corner of the region
    9089             :  * of the band to be queried. This would be zero to start from the top.
    9090             :  *
    9091             :  * @param nXSize The width of the region of the band to be queried in pixels.
    9092             :  *
    9093             :  * @param nYSize The height of the region of the band to be queried in lines.
    9094             :  *
    9095             :  * @param nMaskFlagStop 0, or a binary-or'ed mask of possible values
    9096             :  * GDAL_DATA_COVERAGE_STATUS_UNIMPLEMENTED,
    9097             :  * GDAL_DATA_COVERAGE_STATUS_DATA and GDAL_DATA_COVERAGE_STATUS_EMPTY. As soon
    9098             :  * as the computation of the coverage matches the mask, the computation will be
    9099             :  * stopped. *pdfDataPct will not be valid in that case.
    9100             :  *
    9101             :  * @param pdfDataPct Optional output parameter whose pointed value will be set
    9102             :  * to the (approximate) percentage in [0,100] of pixels in the queried
    9103             :  * sub-window that have valid values. The implementation might not always be
    9104             :  * able to compute it, in which case it will be set to a negative value.
    9105             :  *
    9106             :  * @return a binary-or'ed combination of possible values
    9107             :  * GDAL_DATA_COVERAGE_STATUS_UNIMPLEMENTED,
    9108             :  * GDAL_DATA_COVERAGE_STATUS_DATA and GDAL_DATA_COVERAGE_STATUS_EMPTY
    9109             :  *
    9110             :  * @note Added in GDAL 2.2
    9111             :  */
    9112             : 
    9113        2655 : int GDALRasterBand::GetDataCoverageStatus(int nXOff, int nYOff, int nXSize,
    9114             :                                           int nYSize, int nMaskFlagStop,
    9115             :                                           double *pdfDataPct)
    9116             : {
    9117        2655 :     if (nXOff < 0 || nYOff < 0 || nXSize > INT_MAX - nXOff ||
    9118        2655 :         nYSize > INT_MAX - nYOff || nXOff + nXSize > nRasterXSize ||
    9119        2655 :         nYOff + nYSize > nRasterYSize)
    9120             :     {
    9121           0 :         CPLError(CE_Failure, CPLE_AppDefined, "Bad window");
    9122           0 :         if (pdfDataPct)
    9123           0 :             *pdfDataPct = 0.0;
    9124             :         return GDAL_DATA_COVERAGE_STATUS_UNIMPLEMENTED |
    9125           0 :                GDAL_DATA_COVERAGE_STATUS_EMPTY;
    9126             :     }
    9127        2655 :     return IGetDataCoverageStatus(nXOff, nYOff, nXSize, nYSize, nMaskFlagStop,
    9128        2655 :                                   pdfDataPct);
    9129             : }
    9130             : 
    9131             : /************************************************************************/
    9132             : /*                         IGetDataCoverageStatus()                     */
    9133             : /************************************************************************/
    9134             : 
    9135         497 : int GDALRasterBand::IGetDataCoverageStatus(int /*nXOff*/, int /*nYOff*/,
    9136             :                                            int /*nXSize*/, int /*nYSize*/,
    9137             :                                            int /*nMaskFlagStop*/,
    9138             :                                            double *pdfDataPct)
    9139             : {
    9140         497 :     if (pdfDataPct != nullptr)
    9141           0 :         *pdfDataPct = 100.0;
    9142             :     return GDAL_DATA_COVERAGE_STATUS_UNIMPLEMENTED |
    9143         497 :            GDAL_DATA_COVERAGE_STATUS_DATA;
    9144             : }
    9145             : 
    9146             : //! @cond Doxygen_Suppress
    9147             : /************************************************************************/
    9148             : /*                          EnterReadWrite()                            */
    9149             : /************************************************************************/
    9150             : 
    9151     6795120 : int GDALRasterBand::EnterReadWrite(GDALRWFlag eRWFlag)
    9152             : {
    9153     6795120 :     if (poDS != nullptr)
    9154     6039520 :         return poDS->EnterReadWrite(eRWFlag);
    9155      755592 :     return FALSE;
    9156             : }
    9157             : 
    9158             : /************************************************************************/
    9159             : /*                         LeaveReadWrite()                             */
    9160             : /************************************************************************/
    9161             : 
    9162      587291 : void GDALRasterBand::LeaveReadWrite()
    9163             : {
    9164      587291 :     if (poDS != nullptr)
    9165      587291 :         poDS->LeaveReadWrite();
    9166      587289 : }
    9167             : 
    9168             : /************************************************************************/
    9169             : /*                           InitRWLock()                               */
    9170             : /************************************************************************/
    9171             : 
    9172     3633040 : void GDALRasterBand::InitRWLock()
    9173             : {
    9174     3633040 :     if (poDS != nullptr)
    9175     3632640 :         poDS->InitRWLock();
    9176     3633040 : }
    9177             : 
    9178             : //! @endcond
    9179             : 
    9180             : // clang-format off
    9181             : 
    9182             : /**
    9183             :  * \fn GDALRasterBand::SetMetadata( char ** papszMetadata, const char * pszDomain)
    9184             :  * \brief Set metadata.
    9185             :  *
    9186             :  * CAUTION: depending on the format, older values of the updated information
    9187             :  * might still be found in the file in a "ghost" state, even if no longer
    9188             :  * accessible through the GDAL API. This is for example the case of the GTiff
    9189             :  * format (this is not a exhaustive list)
    9190             :  *
    9191             :  * The C function GDALSetMetadata() does the same thing as this method.
    9192             :  *
    9193             :  * @param papszMetadata the metadata in name=value string list format to
    9194             :  * apply.
    9195             :  * @param pszDomain the domain of interest.  Use "" or NULL for the default
    9196             :  * domain.
    9197             :  * @return CE_None on success, CE_Failure on failure and CE_Warning if the
    9198             :  * metadata has been accepted, but is likely not maintained persistently
    9199             :  * by the underlying object between sessions.
    9200             :  */
    9201             : 
    9202             : /**
    9203             :  * \fn GDALRasterBand::SetMetadataItem( const char * pszName, const char * pszValue, const char * pszDomain)
    9204             :  * \brief Set single metadata item.
    9205             :  *
    9206             :  * CAUTION: depending on the format, older values of the updated information
    9207             :  * might still be found in the file in a "ghost" state, even if no longer
    9208             :  * accessible through the GDAL API. This is for example the case of the GTiff
    9209             :  * format (this is not a exhaustive list)
    9210             :  *
    9211             :  * The C function GDALSetMetadataItem() does the same thing as this method.
    9212             :  *
    9213             :  * @param pszName the key for the metadata item to fetch.
    9214             :  * @param pszValue the value to assign to the key.
    9215             :  * @param pszDomain the domain to set within, use NULL for the default domain.
    9216             :  *
    9217             :  * @return CE_None on success, or an error code on failure.
    9218             :  */
    9219             : 
    9220             : // clang-format on
    9221             : 
    9222             : //! @cond Doxygen_Suppress
    9223             : /************************************************************************/
    9224             : /*                    EnablePixelTypeSignedByteWarning()                */
    9225             : /************************************************************************/
    9226             : 
    9227       25803 : void GDALRasterBand::EnablePixelTypeSignedByteWarning(bool b)
    9228             : {
    9229       25803 :     m_bEnablePixelTypeSignedByteWarning = b;
    9230       25803 : }
    9231             : 
    9232        6612 : void GDALEnablePixelTypeSignedByteWarning(GDALRasterBandH hBand, bool b)
    9233             : {
    9234        6612 :     GDALRasterBand::FromHandle(hBand)->EnablePixelTypeSignedByteWarning(b);
    9235        6612 : }
    9236             : 
    9237             : //! @endcond
    9238             : 
    9239             : /************************************************************************/
    9240             : /*                           GetMetadataItem()                          */
    9241             : /************************************************************************/
    9242             : 
    9243       59905 : const char *GDALRasterBand::GetMetadataItem(const char *pszName,
    9244             :                                             const char *pszDomain)
    9245             : {
    9246             :     // TODO (GDAL 4.0?): remove this when GDAL 3.7 has been widely adopted.
    9247       59905 :     if (m_bEnablePixelTypeSignedByteWarning && eDataType == GDT_Byte &&
    9248       36574 :         pszDomain != nullptr && EQUAL(pszDomain, "IMAGE_STRUCTURE") &&
    9249       27786 :         EQUAL(pszName, "PIXELTYPE"))
    9250             :     {
    9251           2 :         CPLError(CE_Warning, CPLE_AppDefined,
    9252             :                  "Starting with GDAL 3.7, PIXELTYPE=SIGNEDBYTE is no longer "
    9253             :                  "used to signal signed 8-bit raster. Change your code to "
    9254             :                  "test for the new GDT_Int8 data type instead.");
    9255             :     }
    9256       59905 :     return GDALMajorObject::GetMetadataItem(pszName, pszDomain);
    9257             : }
    9258             : 
    9259             : /************************************************************************/
    9260             : /*                     GDALMDArrayFromRasterBand                        */
    9261             : /************************************************************************/
    9262             : 
    9263             : class GDALMDArrayFromRasterBand final : public GDALMDArray
    9264             : {
    9265             :     CPL_DISALLOW_COPY_ASSIGN(GDALMDArrayFromRasterBand)
    9266             : 
    9267             :     GDALDataset *m_poDS;
    9268             :     GDALRasterBand *m_poBand;
    9269             :     GDALExtendedDataType m_dt;
    9270             :     std::vector<std::shared_ptr<GDALDimension>> m_dims{};
    9271             :     std::string m_osUnit;
    9272             :     std::vector<GByte> m_pabyNoData{};
    9273             :     std::shared_ptr<GDALMDArray> m_varX{};
    9274             :     std::shared_ptr<GDALMDArray> m_varY{};
    9275             :     std::string m_osFilename{};
    9276             : 
    9277             :     bool ReadWrite(GDALRWFlag eRWFlag, const GUInt64 *arrayStartIdx,
    9278             :                    const size_t *count, const GInt64 *arrayStep,
    9279             :                    const GPtrDiff_t *bufferStride,
    9280             :                    const GDALExtendedDataType &bufferDataType,
    9281             :                    void *pBuffer) const;
    9282             : 
    9283             :   protected:
    9284          23 :     GDALMDArrayFromRasterBand(GDALDataset *poDS, GDALRasterBand *poBand)
    9285          46 :         : GDALAbstractMDArray(std::string(),
    9286          46 :                               std::string(poDS->GetDescription()) +
    9287             :                                   CPLSPrintf(" band %d", poBand->GetBand())),
    9288          46 :           GDALMDArray(std::string(),
    9289          46 :                       std::string(poDS->GetDescription()) +
    9290             :                           CPLSPrintf(" band %d", poBand->GetBand())),
    9291             :           m_poDS(poDS), m_poBand(poBand),
    9292             :           m_dt(GDALExtendedDataType::Create(poBand->GetRasterDataType())),
    9293         115 :           m_osUnit(poBand->GetUnitType()), m_osFilename(poDS->GetDescription())
    9294             :     {
    9295          23 :         m_poDS->Reference();
    9296             : 
    9297          23 :         int bHasNoData = false;
    9298          23 :         if (m_poBand->GetRasterDataType() == GDT_Int64)
    9299             :         {
    9300           0 :             const auto nNoData = m_poBand->GetNoDataValueAsInt64(&bHasNoData);
    9301           0 :             if (bHasNoData)
    9302             :             {
    9303           0 :                 m_pabyNoData.resize(m_dt.GetSize());
    9304           0 :                 GDALCopyWords(&nNoData, GDT_Int64, 0, &m_pabyNoData[0],
    9305             :                               m_dt.GetNumericDataType(), 0, 1);
    9306             :             }
    9307             :         }
    9308          23 :         else if (m_poBand->GetRasterDataType() == GDT_UInt64)
    9309             :         {
    9310           0 :             const auto nNoData = m_poBand->GetNoDataValueAsUInt64(&bHasNoData);
    9311           0 :             if (bHasNoData)
    9312             :             {
    9313           0 :                 m_pabyNoData.resize(m_dt.GetSize());
    9314           0 :                 GDALCopyWords(&nNoData, GDT_UInt64, 0, &m_pabyNoData[0],
    9315             :                               m_dt.GetNumericDataType(), 0, 1);
    9316             :             }
    9317             :         }
    9318             :         else
    9319             :         {
    9320          23 :             const auto dfNoData = m_poBand->GetNoDataValue(&bHasNoData);
    9321          23 :             if (bHasNoData)
    9322             :             {
    9323           1 :                 m_pabyNoData.resize(m_dt.GetSize());
    9324           1 :                 GDALCopyWords(&dfNoData, GDT_Float64, 0, &m_pabyNoData[0],
    9325             :                               m_dt.GetNumericDataType(), 0, 1);
    9326             :             }
    9327             :         }
    9328             : 
    9329          23 :         const int nXSize = poBand->GetXSize();
    9330          23 :         const int nYSize = poBand->GetYSize();
    9331             : 
    9332          23 :         auto poSRS = m_poDS->GetSpatialRef();
    9333          46 :         std::string osTypeY;
    9334          46 :         std::string osTypeX;
    9335          46 :         std::string osDirectionY;
    9336          46 :         std::string osDirectionX;
    9337          23 :         if (poSRS && poSRS->GetAxesCount() == 2)
    9338             :         {
    9339          21 :             const auto &mapping = poSRS->GetDataAxisToSRSAxisMapping();
    9340          21 :             OGRAxisOrientation eOrientation1 = OAO_Other;
    9341          21 :             poSRS->GetAxis(nullptr, 0, &eOrientation1);
    9342          21 :             OGRAxisOrientation eOrientation2 = OAO_Other;
    9343          21 :             poSRS->GetAxis(nullptr, 1, &eOrientation2);
    9344          21 :             if (eOrientation1 == OAO_East && eOrientation2 == OAO_North)
    9345             :             {
    9346           5 :                 if (mapping == std::vector<int>{1, 2})
    9347             :                 {
    9348           5 :                     osTypeY = GDAL_DIM_TYPE_HORIZONTAL_Y;
    9349           5 :                     osDirectionY = "NORTH";
    9350           5 :                     osTypeX = GDAL_DIM_TYPE_HORIZONTAL_X;
    9351           5 :                     osDirectionX = "EAST";
    9352             :                 }
    9353             :             }
    9354          16 :             else if (eOrientation1 == OAO_North && eOrientation2 == OAO_East)
    9355             :             {
    9356          16 :                 if (mapping == std::vector<int>{2, 1})
    9357             :                 {
    9358          16 :                     osTypeY = GDAL_DIM_TYPE_HORIZONTAL_Y;
    9359          16 :                     osDirectionY = "NORTH";
    9360          16 :                     osTypeX = GDAL_DIM_TYPE_HORIZONTAL_X;
    9361          16 :                     osDirectionX = "EAST";
    9362             :                 }
    9363             :             }
    9364             :         }
    9365             : 
    9366         115 :         m_dims = {std::make_shared<GDALDimensionWeakIndexingVar>(
    9367             :                       "/", "Y", osTypeY, osDirectionY, nYSize),
    9368          46 :                   std::make_shared<GDALDimensionWeakIndexingVar>(
    9369          69 :                       "/", "X", osTypeX, osDirectionX, nXSize)};
    9370             : 
    9371             :         double adfGeoTransform[6];
    9372          23 :         if (m_poDS->GetGeoTransform(adfGeoTransform) == CE_None &&
    9373          23 :             adfGeoTransform[2] == 0 && adfGeoTransform[4] == 0)
    9374             :         {
    9375          44 :             m_varX = GDALMDArrayRegularlySpaced::Create(
    9376          22 :                 "/", "X", m_dims[1], adfGeoTransform[0], adfGeoTransform[1],
    9377          22 :                 0.5);
    9378          22 :             m_dims[1]->SetIndexingVariable(m_varX);
    9379             : 
    9380          44 :             m_varY = GDALMDArrayRegularlySpaced::Create(
    9381          22 :                 "/", "Y", m_dims[0], adfGeoTransform[3], adfGeoTransform[5],
    9382          22 :                 0.5);
    9383          22 :             m_dims[0]->SetIndexingVariable(m_varY);
    9384             :         }
    9385          23 :     }
    9386             : 
    9387          31 :     bool IRead(const GUInt64 *arrayStartIdx, const size_t *count,
    9388             :                const GInt64 *arrayStep, const GPtrDiff_t *bufferStride,
    9389             :                const GDALExtendedDataType &bufferDataType,
    9390             :                void *pDstBuffer) const override
    9391             :     {
    9392          31 :         return ReadWrite(GF_Read, arrayStartIdx, count, arrayStep, bufferStride,
    9393          31 :                          bufferDataType, pDstBuffer);
    9394             :     }
    9395             : 
    9396           1 :     bool IWrite(const GUInt64 *arrayStartIdx, const size_t *count,
    9397             :                 const GInt64 *arrayStep, const GPtrDiff_t *bufferStride,
    9398             :                 const GDALExtendedDataType &bufferDataType,
    9399             :                 const void *pSrcBuffer) override
    9400             :     {
    9401           1 :         return ReadWrite(GF_Write, arrayStartIdx, count, arrayStep,
    9402             :                          bufferStride, bufferDataType,
    9403           1 :                          const_cast<void *>(pSrcBuffer));
    9404             :     }
    9405             : 
    9406             :   public:
    9407          46 :     ~GDALMDArrayFromRasterBand()
    9408          23 :     {
    9409          23 :         m_poDS->ReleaseRef();
    9410          46 :     }
    9411             : 
    9412          23 :     static std::shared_ptr<GDALMDArray> Create(GDALDataset *poDS,
    9413             :                                                GDALRasterBand *poBand)
    9414             :     {
    9415             :         auto array(std::shared_ptr<GDALMDArrayFromRasterBand>(
    9416          46 :             new GDALMDArrayFromRasterBand(poDS, poBand)));
    9417          23 :         array->SetSelf(array);
    9418          46 :         return array;
    9419             :     }
    9420             : 
    9421           2 :     bool IsWritable() const override
    9422             :     {
    9423           2 :         return m_poDS->GetAccess() == GA_Update;
    9424             :     }
    9425             : 
    9426          97 :     const std::string &GetFilename() const override
    9427             :     {
    9428          97 :         return m_osFilename;
    9429             :     }
    9430             : 
    9431             :     const std::vector<std::shared_ptr<GDALDimension>> &
    9432         299 :     GetDimensions() const override
    9433             :     {
    9434         299 :         return m_dims;
    9435             :     }
    9436             : 
    9437         138 :     const GDALExtendedDataType &GetDataType() const override
    9438             :     {
    9439         138 :         return m_dt;
    9440             :     }
    9441             : 
    9442           3 :     const std::string &GetUnit() const override
    9443             :     {
    9444           3 :         return m_osUnit;
    9445             :     }
    9446             : 
    9447          29 :     const void *GetRawNoDataValue() const override
    9448             :     {
    9449          29 :         return m_pabyNoData.empty() ? nullptr : m_pabyNoData.data();
    9450             :     }
    9451             : 
    9452           2 :     double GetOffset(bool *pbHasOffset,
    9453             :                      GDALDataType *peStorageType) const override
    9454             :     {
    9455           2 :         int bHasOffset = false;
    9456           2 :         double dfRes = m_poBand->GetOffset(&bHasOffset);
    9457           2 :         if (pbHasOffset)
    9458           2 :             *pbHasOffset = CPL_TO_BOOL(bHasOffset);
    9459           2 :         if (peStorageType)
    9460           1 :             *peStorageType = GDT_Unknown;
    9461           2 :         return dfRes;
    9462             :     }
    9463             : 
    9464           2 :     double GetScale(bool *pbHasScale,
    9465             :                     GDALDataType *peStorageType) const override
    9466             :     {
    9467           2 :         int bHasScale = false;
    9468           2 :         double dfRes = m_poBand->GetScale(&bHasScale);
    9469           2 :         if (pbHasScale)
    9470           2 :             *pbHasScale = CPL_TO_BOOL(bHasScale);
    9471           2 :         if (peStorageType)
    9472           1 :             *peStorageType = GDT_Unknown;
    9473           2 :         return dfRes;
    9474             :     }
    9475             : 
    9476          84 :     std::shared_ptr<OGRSpatialReference> GetSpatialRef() const override
    9477             :     {
    9478          84 :         auto poSrcSRS = m_poDS->GetSpatialRef();
    9479          84 :         if (!poSrcSRS)
    9480           2 :             return nullptr;
    9481         164 :         auto poSRS = std::shared_ptr<OGRSpatialReference>(poSrcSRS->Clone());
    9482             : 
    9483         164 :         auto axisMapping = poSRS->GetDataAxisToSRSAxisMapping();
    9484          82 :         constexpr int iYDim = 0;
    9485          82 :         constexpr int iXDim = 1;
    9486         246 :         for (auto &m : axisMapping)
    9487             :         {
    9488         164 :             if (m == 1)
    9489          82 :                 m = iXDim + 1;
    9490          82 :             else if (m == 2)
    9491          82 :                 m = iYDim + 1;
    9492             :             else
    9493           0 :                 m = 0;
    9494             :         }
    9495          82 :         poSRS->SetDataAxisToSRSAxisMapping(axisMapping);
    9496          82 :         return poSRS;
    9497             :     }
    9498             : 
    9499          29 :     std::vector<GUInt64> GetBlockSize() const override
    9500             :     {
    9501          29 :         int nBlockXSize = 0;
    9502          29 :         int nBlockYSize = 0;
    9503          29 :         m_poBand->GetBlockSize(&nBlockXSize, &nBlockYSize);
    9504          29 :         return std::vector<GUInt64>{static_cast<GUInt64>(nBlockYSize),
    9505          29 :                                     static_cast<GUInt64>(nBlockXSize)};
    9506             :     }
    9507             : 
    9508             :     class MDIAsAttribute : public GDALAttribute
    9509             :     {
    9510             :         std::vector<std::shared_ptr<GDALDimension>> m_dims{};
    9511             :         const GDALExtendedDataType m_dt = GDALExtendedDataType::CreateString();
    9512             :         std::string m_osValue;
    9513             : 
    9514             :       public:
    9515           2 :         MDIAsAttribute(const std::string &name, const std::string &value)
    9516           2 :             : GDALAbstractMDArray(std::string(), name),
    9517           4 :               GDALAttribute(std::string(), name), m_osValue(value)
    9518             :         {
    9519           2 :         }
    9520             : 
    9521             :         const std::vector<std::shared_ptr<GDALDimension>> &
    9522           3 :         GetDimensions() const override
    9523             :         {
    9524           3 :             return m_dims;
    9525             :         }
    9526             : 
    9527           2 :         const GDALExtendedDataType &GetDataType() const override
    9528             :         {
    9529           2 :             return m_dt;
    9530             :         }
    9531             : 
    9532           1 :         bool IRead(const GUInt64 *, const size_t *, const GInt64 *,
    9533             :                    const GPtrDiff_t *,
    9534             :                    const GDALExtendedDataType &bufferDataType,
    9535             :                    void *pDstBuffer) const override
    9536             :         {
    9537           1 :             const char *pszStr = m_osValue.c_str();
    9538           1 :             GDALExtendedDataType::CopyValue(&pszStr, m_dt, pDstBuffer,
    9539             :                                             bufferDataType);
    9540           1 :             return true;
    9541             :         }
    9542             :     };
    9543             : 
    9544             :     std::vector<std::shared_ptr<GDALAttribute>>
    9545          14 :     GetAttributes(CSLConstList) const override
    9546             :     {
    9547          14 :         std::vector<std::shared_ptr<GDALAttribute>> res;
    9548          14 :         auto papszMD = m_poBand->GetMetadata();
    9549          16 :         for (auto iter = papszMD; iter && iter[0]; ++iter)
    9550             :         {
    9551           2 :             char *pszKey = nullptr;
    9552           2 :             const char *pszValue = CPLParseNameValue(*iter, &pszKey);
    9553           2 :             if (pszKey && pszValue)
    9554             :             {
    9555             :                 res.emplace_back(
    9556           2 :                     std::make_shared<MDIAsAttribute>(pszKey, pszValue));
    9557             :             }
    9558           2 :             CPLFree(pszKey);
    9559             :         }
    9560          14 :         return res;
    9561             :     }
    9562             : };
    9563             : 
    9564             : /************************************************************************/
    9565             : /*                            ReadWrite()                               */
    9566             : /************************************************************************/
    9567             : 
    9568          32 : bool GDALMDArrayFromRasterBand::ReadWrite(
    9569             :     GDALRWFlag eRWFlag, const GUInt64 *arrayStartIdx, const size_t *count,
    9570             :     const GInt64 *arrayStep, const GPtrDiff_t *bufferStride,
    9571             :     const GDALExtendedDataType &bufferDataType, void *pBuffer) const
    9572             : {
    9573          32 :     constexpr size_t iDimX = 1;
    9574          32 :     constexpr size_t iDimY = 0;
    9575          32 :     return GDALMDRasterIOFromBand(m_poBand, eRWFlag, iDimX, iDimY,
    9576             :                                   arrayStartIdx, count, arrayStep, bufferStride,
    9577          32 :                                   bufferDataType, pBuffer);
    9578             : }
    9579             : 
    9580             : /************************************************************************/
    9581             : /*                       GDALMDRasterIOFromBand()                       */
    9582             : /************************************************************************/
    9583             : 
    9584          65 : bool GDALMDRasterIOFromBand(GDALRasterBand *poBand, GDALRWFlag eRWFlag,
    9585             :                             size_t iDimX, size_t iDimY,
    9586             :                             const GUInt64 *arrayStartIdx, const size_t *count,
    9587             :                             const GInt64 *arrayStep,
    9588             :                             const GPtrDiff_t *bufferStride,
    9589             :                             const GDALExtendedDataType &bufferDataType,
    9590             :                             void *pBuffer)
    9591             : {
    9592          65 :     const auto eDT(bufferDataType.GetNumericDataType());
    9593          65 :     const auto nDTSize(GDALGetDataTypeSizeBytes(eDT));
    9594          65 :     const int nX =
    9595          65 :         arrayStep[iDimX] > 0
    9596          65 :             ? static_cast<int>(arrayStartIdx[iDimX])
    9597           2 :             : static_cast<int>(arrayStartIdx[iDimX] -
    9598           2 :                                (count[iDimX] - 1) * -arrayStep[iDimX]);
    9599          65 :     const int nY =
    9600          65 :         arrayStep[iDimY] > 0
    9601          65 :             ? static_cast<int>(arrayStartIdx[iDimY])
    9602           2 :             : static_cast<int>(arrayStartIdx[iDimY] -
    9603           2 :                                (count[iDimY] - 1) * -arrayStep[iDimY]);
    9604          65 :     const int nSizeX = static_cast<int>(count[iDimX] * ABS(arrayStep[iDimX]));
    9605          65 :     const int nSizeY = static_cast<int>(count[iDimY] * ABS(arrayStep[iDimY]));
    9606          65 :     GByte *pabyBuffer = static_cast<GByte *>(pBuffer);
    9607          65 :     int nStrideXSign = 1;
    9608          65 :     if (arrayStep[iDimX] < 0)
    9609             :     {
    9610           2 :         pabyBuffer += (count[iDimX] - 1) * bufferStride[iDimX] * nDTSize;
    9611           2 :         nStrideXSign = -1;
    9612             :     }
    9613          65 :     int nStrideYSign = 1;
    9614          65 :     if (arrayStep[iDimY] < 0)
    9615             :     {
    9616           2 :         pabyBuffer += (count[iDimY] - 1) * bufferStride[iDimY] * nDTSize;
    9617           2 :         nStrideYSign = -1;
    9618             :     }
    9619             : 
    9620         130 :     return poBand->RasterIO(eRWFlag, nX, nY, nSizeX, nSizeY, pabyBuffer,
    9621          65 :                             static_cast<int>(count[iDimX]),
    9622          65 :                             static_cast<int>(count[iDimY]), eDT,
    9623             :                             static_cast<GSpacing>(
    9624          65 :                                 nStrideXSign * bufferStride[iDimX] * nDTSize),
    9625             :                             static_cast<GSpacing>(
    9626          65 :                                 nStrideYSign * bufferStride[iDimY] * nDTSize),
    9627          65 :                             nullptr) == CE_None;
    9628             : }
    9629             : 
    9630             : /************************************************************************/
    9631             : /*                            AsMDArray()                               */
    9632             : /************************************************************************/
    9633             : 
    9634             : /** Return a view of this raster band as a 2D multidimensional GDALMDArray.
    9635             :  *
    9636             :  * The band must be linked to a GDALDataset. If this dataset is not already
    9637             :  * marked as shared, it will be, so that the returned array holds a reference
    9638             :  * to it.
    9639             :  *
    9640             :  * If the dataset has a geotransform attached, the X and Y dimensions of the
    9641             :  * returned array will have an associated indexing variable.
    9642             :  *
    9643             :  * This is the same as the C function GDALRasterBandAsMDArray().
    9644             :  *
    9645             :  * The "reverse" method is GDALMDArray::AsClassicDataset().
    9646             :  *
    9647             :  * @return a new array, or nullptr.
    9648             :  *
    9649             :  * @since GDAL 3.1
    9650             :  */
    9651          23 : std::shared_ptr<GDALMDArray> GDALRasterBand::AsMDArray() const
    9652             : {
    9653          23 :     if (!poDS)
    9654             :     {
    9655           0 :         CPLError(CE_Failure, CPLE_AppDefined, "Band not attached to a dataset");
    9656           0 :         return nullptr;
    9657             :     }
    9658          23 :     if (!poDS->GetShared())
    9659             :     {
    9660          23 :         poDS->MarkAsShared();
    9661             :     }
    9662             :     return GDALMDArrayFromRasterBand::Create(
    9663          23 :         poDS, const_cast<GDALRasterBand *>(this));
    9664             : }
    9665             : 
    9666             : /************************************************************************/
    9667             : /*                             InterpolateAtPoint()                     */
    9668             : /************************************************************************/
    9669             : 
    9670             : /**
    9671             :  * \brief Interpolates the value between pixels using
    9672             :  * a resampling algorithm
    9673             :  *
    9674             :  * @param dfPixel pixel coordinate as a double, where interpolation should be done.
    9675             :  * @param dfLine line coordinate as a double, where interpolation should be done.
    9676             :  * @param eInterpolation interpolation type. Only near, bilinear, cubic and cubicspline are allowed.
    9677             :  * @param pdfRealValue pointer to real part of interpolated value
    9678             :  * @param pdfImagValue pointer to imaginary part of interpolated value (may be null if not needed)
    9679             :  *
    9680             :  * @return CE_None on success, or an error code on failure.
    9681             :  * @since GDAL 3.10
    9682             :  */
    9683             : 
    9684         115 : CPLErr GDALRasterBand::InterpolateAtPoint(double dfPixel, double dfLine,
    9685             :                                           GDALRIOResampleAlg eInterpolation,
    9686             :                                           double *pdfRealValue,
    9687             :                                           double *pdfImagValue) const
    9688             : {
    9689         115 :     if (eInterpolation != GRIORA_NearestNeighbour &&
    9690          31 :         eInterpolation != GRIORA_Bilinear && eInterpolation != GRIORA_Cubic &&
    9691             :         eInterpolation != GRIORA_CubicSpline)
    9692             :     {
    9693           2 :         CPLError(CE_Failure, CPLE_AppDefined,
    9694             :                  "Only nearest, bilinear, cubic and cubicspline interpolation "
    9695             :                  "methods "
    9696             :                  "allowed");
    9697             : 
    9698           2 :         return CE_Failure;
    9699             :     }
    9700             : 
    9701         113 :     GDALRasterBand *pBand = const_cast<GDALRasterBand *>(this);
    9702         113 :     if (!m_poPointsCache)
    9703          51 :         m_poPointsCache = new GDALDoublePointsCache();
    9704             : 
    9705             :     const bool res =
    9706         113 :         GDALInterpolateAtPoint(pBand, eInterpolation, m_poPointsCache->cache,
    9707             :                                dfPixel, dfLine, pdfRealValue, pdfImagValue);
    9708             : 
    9709         113 :     return res ? CE_None : CE_Failure;
    9710             : }
    9711             : 
    9712             : /************************************************************************/
    9713             : /*                        GDALRasterInterpolateAtPoint()                */
    9714             : /************************************************************************/
    9715             : 
    9716             : /**
    9717             :  * \brief Interpolates the value between pixels using
    9718             :  * a resampling algorithm
    9719             :  *
    9720             :  * @see GDALRasterBand::InterpolateAtPoint()
    9721             :  * @since GDAL 3.10
    9722             :  */
    9723             : 
    9724         105 : CPLErr GDALRasterInterpolateAtPoint(GDALRasterBandH hBand, double dfPixel,
    9725             :                                     double dfLine,
    9726             :                                     GDALRIOResampleAlg eInterpolation,
    9727             :                                     double *pdfRealValue, double *pdfImagValue)
    9728             : {
    9729         105 :     VALIDATE_POINTER1(hBand, "GDALRasterInterpolateAtPoint", CE_Failure);
    9730             : 
    9731         105 :     GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
    9732         105 :     return poBand->InterpolateAtPoint(dfPixel, dfLine, eInterpolation,
    9733         105 :                                       pdfRealValue, pdfImagValue);
    9734             : }

Generated by: LCOV version 1.14