LCOV - code coverage report
Current view: top level - gcore - gdalrasterband.cpp (source / functions) Hit Total Coverage
Test: gdal_filtered.info Lines: 2452 3139 78.1 %
Date: 2025-05-31 00:00:17 Functions: 221 247 89.5 %

          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_float.h"
      34             : #include "cpl_progress.h"
      35             : #include "cpl_string.h"
      36             : #include "cpl_virtualmem.h"
      37             : #include "cpl_vsi.h"
      38             : #include "gdal.h"
      39             : #include "gdal_rat.h"
      40             : #include "gdal_priv_templates.hpp"
      41             : #include "gdal_interpolateatpoint.h"
      42             : #include "gdal_minmax_element.hpp"
      43             : 
      44             : /************************************************************************/
      45             : /*                           GDALRasterBand()                           */
      46             : /************************************************************************/
      47             : 
      48             : /*! Constructor. Applications should never create GDALRasterBands directly. */
      49             : 
      50     1340590 : GDALRasterBand::GDALRasterBand()
      51             :     : GDALRasterBand(
      52     1340590 :           CPLTestBool(CPLGetConfigOption("GDAL_FORCE_CACHING", "NO")))
      53             : {
      54     1340500 : }
      55             : 
      56             : /** Constructor. Applications should never create GDALRasterBands directly.
      57             :  * @param bForceCachedIOIn Whether cached IO should be forced.
      58             :  */
      59     1611450 : GDALRasterBand::GDALRasterBand(int bForceCachedIOIn)
      60     1611450 :     : bForceCachedIO(bForceCachedIOIn)
      61             : 
      62             : {
      63     1611280 : }
      64             : 
      65             : /************************************************************************/
      66             : /*                          ~GDALRasterBand()                           */
      67             : /************************************************************************/
      68             : 
      69             : /*! Destructor. Applications should never destroy GDALRasterBands directly,
      70             :     instead destroy the GDALDataset. */
      71             : 
      72     1611450 : GDALRasterBand::~GDALRasterBand()
      73             : 
      74             : {
      75     1611460 :     if (poDS && poDS->IsMarkedSuppressOnClose())
      76             :     {
      77         516 :         if (poBandBlockCache)
      78         452 :             poBandBlockCache->DisableDirtyBlockWriting();
      79             :     }
      80     1611450 :     GDALRasterBand::FlushCache(true);
      81             : 
      82     1611460 :     delete poBandBlockCache;
      83             : 
      84     1611460 :     if (static_cast<GIntBig>(nBlockReads) >
      85     1611460 :             static_cast<GIntBig>(nBlocksPerRow) * nBlocksPerColumn &&
      86         216 :         nBand == 1 && poDS != nullptr)
      87             :     {
      88         312 :         CPLDebug(
      89             :             "GDAL", "%d block reads on " CPL_FRMT_GIB " block band 1 of %s.",
      90         156 :             nBlockReads, static_cast<GIntBig>(nBlocksPerRow) * nBlocksPerColumn,
      91         156 :             poDS->GetDescription());
      92             :     }
      93             : 
      94     1611460 :     InvalidateMaskBand();
      95     1611450 :     nBand = -nBand;
      96             : 
      97     1611450 :     delete m_poPointsCache;
      98     1611450 : }
      99             : 
     100             : /************************************************************************/
     101             : /*                              RasterIO()                              */
     102             : /************************************************************************/
     103             : 
     104             : /**
     105             :  * \fn GDALRasterBand::IRasterIO( GDALRWFlag eRWFlag,
     106             :  *                                int nXOff, int nYOff, int nXSize, int nYSize,
     107             :  *                                void * pData, int nBufXSize, int nBufYSize,
     108             :  *                                GDALDataType eBufType,
     109             :  *                                GSpacing nPixelSpace,
     110             :  *                                GSpacing nLineSpace,
     111             :  *                                GDALRasterIOExtraArg* psExtraArg )
     112             :  * \brief Read/write a region of image data for this band.
     113             :  *
     114             :  * This method allows reading a region of a GDALRasterBand into a buffer,
     115             :  * or writing data from a buffer into a region of a GDALRasterBand. It
     116             :  * automatically takes care of data type translation if the data type
     117             :  * (eBufType) of the buffer is different than that of the GDALRasterBand.
     118             :  * The method also takes care of image decimation / replication if the
     119             :  * buffer size (nBufXSize x nBufYSize) is different than the size of the
     120             :  * region being accessed (nXSize x nYSize).
     121             :  *
     122             :  * The window of interest expressed by (nXOff, nYOff, nXSize, nYSize) should be
     123             :  * fully within the raster space, that is nXOff >= 0, nYOff >= 0,
     124             :  * nXOff + nXSize <= GetXSize() and nYOff + nYSize <= GetYSize().
     125             :  * If reads larger than the raster space are wished, GDALTranslate() might be used.
     126             :  * Or use nLineSpace and a possibly shifted pData value.
     127             :  *
     128             :  * The nPixelSpace and nLineSpace parameters allow reading into or
     129             :  * writing from unusually organized buffers. This is primarily used
     130             :  * for buffers containing more than one bands raster data in interleaved
     131             :  * format.
     132             :  *
     133             :  * Some formats may efficiently implement decimation into a buffer by
     134             :  * reading from lower resolution overview images. The logic of the default
     135             :  * implementation in the base class GDALRasterBand is the following one. It
     136             :  * computes a target_downscaling_factor from the window of interest and buffer
     137             :  * size which is min(nXSize/nBufXSize, nYSize/nBufYSize).
     138             :  * It then walks through overviews and will select the first one whose
     139             :  * downscaling factor is greater than target_downscaling_factor / 1.2.
     140             :  *
     141             :  * Let's assume we have overviews at downscaling factors 2, 4 and 8.
     142             :  * The relationship between target_downscaling_factor and the select overview
     143             :  * level is the following one:
     144             :  *
     145             :  * target_downscaling_factor  | selected_overview
     146             :  * -------------------------  | -----------------
     147             :  * ]0,       2 / 1.2]         | full resolution band
     148             :  * ]2 / 1.2, 4 / 1.2]         | 2x downsampled band
     149             :  * ]4 / 1.2, 8 / 1.2]         | 4x downsampled band
     150             :  * ]8 / 1.2, infinity[        | 8x downsampled band
     151             :  *
     152             :  * Note that starting with GDAL 3.9, this 1.2 oversampling factor can be
     153             :  * modified by setting the GDAL_OVERVIEW_OVERSAMPLING_THRESHOLD configuration
     154             :  * option. Also note that starting with GDAL 3.9, when the resampling algorithm
     155             :  * specified in psExtraArg->eResampleAlg is different from GRIORA_NearestNeighbour,
     156             :  * this oversampling threshold defaults to 1. Consequently if there are overviews
     157             :  * of downscaling factor 2, 4 and 8, and the desired downscaling factor is
     158             :  * 7.99, the overview of factor 4 will be selected for a non nearest resampling.
     159             :  *
     160             :  * For highest performance full resolution data access, read and write
     161             :  * on "block boundaries" as returned by GetBlockSize(), or use the
     162             :  * ReadBlock() and WriteBlock() methods.
     163             :  *
     164             :  * This method is the same as the C GDALRasterIO() or GDALRasterIOEx()
     165             :  * functions.
     166             :  *
     167             :  * @param eRWFlag Either GF_Read to read a region of data, or GF_Write to
     168             :  * write a region of data.
     169             :  *
     170             :  * @param nXOff The pixel offset to the top left corner of the region
     171             :  * of the band to be accessed. This would be zero to start from the left side.
     172             :  *
     173             :  * @param nYOff The line offset to the top left corner of the region
     174             :  * of the band to be accessed. This would be zero to start from the top.
     175             :  *
     176             :  * @param nXSize The width of the region of the band to be accessed in pixels.
     177             :  *
     178             :  * @param nYSize The height of the region of the band to be accessed in lines.
     179             :  *
     180             :  * @param pData The buffer into which the data should be read, or from which
     181             :  * it should be written. This buffer must contain at least nBufXSize *
     182             :  * nBufYSize words of type eBufType. It is organized in left to right,
     183             :  * top to bottom pixel order. Spacing is controlled by the nPixelSpace,
     184             :  * and nLineSpace parameters.
     185             :  * Note that even with eRWFlag==GF_Write, the content of the buffer might be
     186             :  * temporarily modified during the execution of this method (and eventually
     187             :  * restored back to its original content), so it is not safe to use a buffer
     188             :  * stored in a read-only section of the calling program.
     189             :  *
     190             :  * @param nBufXSize the width of the buffer image into which the desired region
     191             :  * is to be read, or from which it is to be written.
     192             :  *
     193             :  * @param nBufYSize the height of the buffer image into which the desired region
     194             :  * is to be read, or from which it is to be written.
     195             :  *
     196             :  * @param eBufType the type of the pixel values in the pData data buffer. The
     197             :  * pixel values will automatically be translated to/from the GDALRasterBand
     198             :  * data type as needed. Most driver implementations will use GDALCopyWords64()
     199             :  * to perform data type translation.
     200             :  *
     201             :  * @param nPixelSpace The byte offset from the start of one pixel value in
     202             :  * pData to the start of the next pixel value within a scanline. If defaulted
     203             :  * (0) the size of the datatype eBufType is used.
     204             :  *
     205             :  * @param nLineSpace The byte offset from the start of one scanline in
     206             :  * pData to the start of the next. If defaulted (0) the size of the datatype
     207             :  * eBufType * nBufXSize is used.
     208             :  *
     209             :  * @param psExtraArg (new in GDAL 2.0) pointer to a GDALRasterIOExtraArg
     210             :  * structure with additional arguments to specify resampling and progress
     211             :  * callback, or NULL for default behavior. The GDAL_RASTERIO_RESAMPLING
     212             :  * configuration option can also be defined to override the default resampling
     213             :  * to one of BILINEAR, CUBIC, CUBICSPLINE, LANCZOS, AVERAGE or MODE.
     214             :  *
     215             :  * @return CE_Failure if the access fails, otherwise CE_None.
     216             :  */
     217             : 
     218             : /**
     219             :  * \brief Read/write a region of image data for this band.
     220             :  *
     221             :  * This method allows reading a region of a GDALRasterBand into a buffer,
     222             :  * or writing data from a buffer into a region of a GDALRasterBand. It
     223             :  * automatically takes care of data type translation if the data type
     224             :  * (eBufType) of the buffer is different than that of the GDALRasterBand.
     225             :  * The method also takes care of image decimation / replication if the
     226             :  * buffer size (nBufXSize x nBufYSize) is different than the size of the
     227             :  * region being accessed (nXSize x nYSize).
     228             :  *
     229             :  * The window of interest expressed by (nXOff, nYOff, nXSize, nYSize) should be
     230             :  * fully within the raster space, that is nXOff >= 0, nYOff >= 0,
     231             :  * nXOff + nXSize <= GetXSize() and nYOff + nYSize <= GetYSize().
     232             :  * If reads larger than the raster space are wished, GDALTranslate() might be used.
     233             :  * Or use nLineSpace and a possibly shifted pData value.
     234             :  *
     235             :  * The nPixelSpace and nLineSpace parameters allow reading into or
     236             :  * writing from unusually organized buffers. This is primarily used
     237             :  * for buffers containing more than one bands raster data in interleaved
     238             :  * format.
     239             :  *
     240             :  * Some formats may efficiently implement decimation into a buffer by
     241             :  * reading from lower resolution overview images. The logic of the default
     242             :  * implementation in the base class GDALRasterBand is the following one. It
     243             :  * computes a target_downscaling_factor from the window of interest and buffer
     244             :  * size which is min(nXSize/nBufXSize, nYSize/nBufYSize).
     245             :  * It then walks through overviews and will select the first one whose
     246             :  * downscaling factor is greater than target_downscaling_factor / 1.2.
     247             :  *
     248             :  * Let's assume we have overviews at downscaling factors 2, 4 and 8.
     249             :  * The relationship between target_downscaling_factor and the select overview
     250             :  * level is the following one:
     251             :  *
     252             :  * target_downscaling_factor  | selected_overview
     253             :  * -------------------------  | -----------------
     254             :  * ]0,       2 / 1.2]         | full resolution band
     255             :  * ]2 / 1.2, 4 / 1.2]         | 2x downsampled band
     256             :  * ]4 / 1.2, 8 / 1.2]         | 4x downsampled band
     257             :  * ]8 / 1.2, infinity[        | 8x downsampled band
     258             :  *
     259             :  * For highest performance full resolution data access, read and write
     260             :  * on "block boundaries" as returned by GetBlockSize(), or use the
     261             :  * ReadBlock() and WriteBlock() methods.
     262             :  *
     263             :  * This method is the same as the C GDALRasterIO() or GDALRasterIOEx()
     264             :  * functions.
     265             :  *
     266             :  * Starting with GDAL 3.10, the GDALRasterBand::ReadRaster() methods may be
     267             :  * more convenient to use for most common use cases.
     268             :  *
     269             :  * As nearly all GDAL methods, this method is *NOT* thread-safe, that is it cannot
     270             :  * be called on the same GDALRasterBand instance (or another GDALRasterBand
     271             :  * instance of this dataset) concurrently from several threads.
     272             :  *
     273             :  * @param eRWFlag Either GF_Read to read a region of data, or GF_Write to
     274             :  * write a region of data.
     275             :  *
     276             :  * @param nXOff The pixel offset to the top left corner of the region
     277             :  * of the band to be accessed. This would be zero to start from the left side.
     278             :  *
     279             :  * @param nYOff The line offset to the top left corner of the region
     280             :  * of the band to be accessed. This would be zero to start from the top.
     281             :  *
     282             :  * @param nXSize The width of the region of the band to be accessed in pixels.
     283             :  *
     284             :  * @param nYSize The height of the region of the band to be accessed in lines.
     285             :  *
     286             :  * @param[in,out] pData The buffer into which the data should be read, or from
     287             :  * which it should be written. This buffer must contain at least nBufXSize *
     288             :  * nBufYSize words of type eBufType. It is organized in left to right,
     289             :  * top to bottom pixel order. Spacing is controlled by the nPixelSpace,
     290             :  * and nLineSpace parameters.
     291             :  *
     292             :  * @param nBufXSize the width of the buffer image into which the desired region
     293             :  * is to be read, or from which it is to be written.
     294             :  *
     295             :  * @param nBufYSize the height of the buffer image into which the desired region
     296             :  * is to be read, or from which it is to be written.
     297             :  *
     298             :  * @param eBufType the type of the pixel values in the pData data buffer. The
     299             :  * pixel values will automatically be translated to/from the GDALRasterBand
     300             :  * data type as needed.
     301             :  *
     302             :  * @param nPixelSpace The byte offset from the start of one pixel value in
     303             :  * pData to the start of the next pixel value within a scanline. If defaulted
     304             :  * (0) the size of the datatype eBufType is used.
     305             :  *
     306             :  * @param nLineSpace The byte offset from the start of one scanline in
     307             :  * pData to the start of the next. If defaulted (0) the size of the datatype
     308             :  * eBufType * nBufXSize is used.
     309             :  *
     310             :  * @param[in] psExtraArg (new in GDAL 2.0) pointer to a GDALRasterIOExtraArg
     311             :  * structure with additional arguments to specify resampling and progress
     312             :  * callback, or NULL for default behavior. The GDAL_RASTERIO_RESAMPLING
     313             :  * configuration option can also be defined to override the default resampling
     314             :  * to one of BILINEAR, CUBIC, CUBICSPLINE, LANCZOS, AVERAGE or MODE.
     315             :  *
     316             :  * @return CE_Failure if the access fails, otherwise CE_None.
     317             :  *
     318             :  * @see GDALRasterBand::ReadRaster()
     319             :  */
     320             : 
     321     4288500 : CPLErr GDALRasterBand::RasterIO(GDALRWFlag eRWFlag, int nXOff, int nYOff,
     322             :                                 int nXSize, int nYSize, void *pData,
     323             :                                 int nBufXSize, int nBufYSize,
     324             :                                 GDALDataType eBufType, GSpacing nPixelSpace,
     325             :                                 GSpacing nLineSpace,
     326             :                                 GDALRasterIOExtraArg *psExtraArg)
     327             : 
     328             : {
     329             :     GDALRasterIOExtraArg sExtraArg;
     330     4288500 :     if (psExtraArg == nullptr)
     331             :     {
     332     3799700 :         INIT_RASTERIO_EXTRA_ARG(sExtraArg);
     333     3799700 :         psExtraArg = &sExtraArg;
     334             :     }
     335      488805 :     else if (CPL_UNLIKELY(psExtraArg->nVersion >
     336             :                           RASTERIO_EXTRA_ARG_CURRENT_VERSION))
     337             :     {
     338           0 :         ReportError(CE_Failure, CPLE_AppDefined,
     339             :                     "Unhandled version of GDALRasterIOExtraArg");
     340           0 :         return CE_Failure;
     341             :     }
     342             : 
     343     4288500 :     GDALRasterIOExtraArgSetResampleAlg(psExtraArg, nXSize, nYSize, nBufXSize,
     344             :                                        nBufYSize);
     345             : 
     346     4291640 :     if (CPL_UNLIKELY(nullptr == pData))
     347             :     {
     348           0 :         ReportError(CE_Failure, CPLE_AppDefined,
     349             :                     "The buffer into which the data should be read is null");
     350           0 :         return CE_Failure;
     351             :     }
     352             : 
     353             :     /* -------------------------------------------------------------------- */
     354             :     /*      Some size values are "noop".  Lets just return to avoid         */
     355             :     /*      stressing lower level functions.                                */
     356             :     /* -------------------------------------------------------------------- */
     357     4291640 :     if (CPL_UNLIKELY(nXSize < 1 || nYSize < 1 || nBufXSize < 1 ||
     358             :                      nBufYSize < 1))
     359             :     {
     360           2 :         CPLDebug("GDAL",
     361             :                  "RasterIO() skipped for odd window or buffer size.\n"
     362             :                  "  Window = (%d,%d)x%dx%d\n"
     363             :                  "  Buffer = %dx%d\n",
     364             :                  nXOff, nYOff, nXSize, nYSize, nBufXSize, nBufYSize);
     365             : 
     366           2 :         return CE_None;
     367             :     }
     368             : 
     369     4291640 :     if (eRWFlag == GF_Write)
     370             :     {
     371      361643 :         if (CPL_UNLIKELY(eFlushBlockErr != CE_None))
     372             :         {
     373           0 :             ReportError(eFlushBlockErr, CPLE_AppDefined,
     374             :                         "An error occurred while writing a dirty block "
     375             :                         "from GDALRasterBand::RasterIO");
     376           0 :             CPLErr eErr = eFlushBlockErr;
     377           0 :             eFlushBlockErr = CE_None;
     378           0 :             return eErr;
     379             :         }
     380      361643 :         if (EmitErrorMessageIfWriteNotSupported("GDALRasterBand::RasterIO()"))
     381             :         {
     382           7 :             return CE_Failure;
     383             :         }
     384             :     }
     385             : 
     386             :     /* -------------------------------------------------------------------- */
     387             :     /*      If pixel and line spacing are defaulted assign reasonable      */
     388             :     /*      value assuming a packed buffer.                                 */
     389             :     /* -------------------------------------------------------------------- */
     390     4291660 :     if (nPixelSpace == 0)
     391             :     {
     392     3995770 :         nPixelSpace = GDALGetDataTypeSizeBytes(eBufType);
     393             :     }
     394             : 
     395     4289330 :     if (nLineSpace == 0)
     396             :     {
     397     3988720 :         nLineSpace = nPixelSpace * nBufXSize;
     398             :     }
     399             : 
     400             :     /* -------------------------------------------------------------------- */
     401             :     /*      Do some validation of parameters.                               */
     402             :     /* -------------------------------------------------------------------- */
     403     4289330 :     if (CPL_UNLIKELY(nXOff < 0 || nXOff > INT_MAX - nXSize ||
     404             :                      nXOff + nXSize > nRasterXSize || nYOff < 0 ||
     405             :                      nYOff > INT_MAX - nYSize || nYOff + nYSize > nRasterYSize))
     406             :     {
     407          14 :         ReportError(CE_Failure, CPLE_IllegalArg,
     408             :                     "Access window out of range in RasterIO().  Requested\n"
     409             :                     "(%d,%d) of size %dx%d on raster of %dx%d.",
     410             :                     nXOff, nYOff, nXSize, nYSize, nRasterXSize, nRasterYSize);
     411          14 :         return CE_Failure;
     412             :     }
     413             : 
     414     4289320 :     if (CPL_UNLIKELY(eRWFlag != GF_Read && eRWFlag != GF_Write))
     415             :     {
     416           0 :         ReportError(
     417             :             CE_Failure, CPLE_IllegalArg,
     418             :             "eRWFlag = %d, only GF_Read (0) and GF_Write (1) are legal.",
     419             :             eRWFlag);
     420           0 :         return CE_Failure;
     421             :     }
     422     4289320 :     if (CPL_UNLIKELY(eBufType == GDT_Unknown || eBufType == GDT_TypeCount))
     423             :     {
     424           2 :         ReportError(CE_Failure, CPLE_IllegalArg,
     425             :                     "Illegal GDT_Unknown/GDT_TypeCount argument");
     426           2 :         return CE_Failure;
     427             :     }
     428             : 
     429             :     /* -------------------------------------------------------------------- */
     430             :     /*      Call the format specific function.                              */
     431             :     /* -------------------------------------------------------------------- */
     432             : 
     433     4289320 :     const bool bCallLeaveReadWrite = CPL_TO_BOOL(EnterReadWrite(eRWFlag));
     434             : 
     435             :     CPLErr eErr;
     436     4284780 :     if (bForceCachedIO)
     437          23 :         eErr = GDALRasterBand::IRasterIO(eRWFlag, nXOff, nYOff, nXSize, nYSize,
     438             :                                          pData, nBufXSize, nBufYSize, eBufType,
     439             :                                          nPixelSpace, nLineSpace, psExtraArg);
     440             :     else
     441             :         eErr =
     442     4290990 :             IRasterIO(eRWFlag, nXOff, nYOff, nXSize, nYSize, pData, nBufXSize,
     443     4284760 :                       nBufYSize, eBufType, nPixelSpace, nLineSpace, psExtraArg);
     444             : 
     445     4291020 :     if (bCallLeaveReadWrite)
     446      599281 :         LeaveReadWrite();
     447             : 
     448     4283900 :     return eErr;
     449             : }
     450             : 
     451             : /************************************************************************/
     452             : /*                            GDALRasterIO()                            */
     453             : /************************************************************************/
     454             : 
     455             : /**
     456             :  * \brief Read/write a region of image data for this band.
     457             :  *
     458             :  * Use GDALRasterIOEx() if 64 bit spacings or extra arguments (resampling
     459             :  * resolution, progress callback, etc. are needed)
     460             :  *
     461             :  * @see GDALRasterBand::RasterIO()
     462             :  */
     463             : 
     464     3402240 : CPLErr CPL_STDCALL GDALRasterIO(GDALRasterBandH hBand, GDALRWFlag eRWFlag,
     465             :                                 int nXOff, int nYOff, int nXSize, int nYSize,
     466             :                                 void *pData, int nBufXSize, int nBufYSize,
     467             :                                 GDALDataType eBufType, int nPixelSpace,
     468             :                                 int nLineSpace)
     469             : 
     470             : {
     471     3402240 :     VALIDATE_POINTER1(hBand, "GDALRasterIO", CE_Failure);
     472             : 
     473     3402240 :     GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
     474             : 
     475     3396890 :     return (poBand->RasterIO(eRWFlag, nXOff, nYOff, nXSize, nYSize, pData,
     476             :                              nBufXSize, nBufYSize, eBufType, nPixelSpace,
     477     3397540 :                              nLineSpace, nullptr));
     478             : }
     479             : 
     480             : /************************************************************************/
     481             : /*                            GDALRasterIOEx()                          */
     482             : /************************************************************************/
     483             : 
     484             : /**
     485             :  * \brief Read/write a region of image data for this band.
     486             :  *
     487             :  * @see GDALRasterBand::RasterIO()
     488             :  * @since GDAL 2.0
     489             :  */
     490             : 
     491       38770 : CPLErr CPL_STDCALL GDALRasterIOEx(GDALRasterBandH hBand, GDALRWFlag eRWFlag,
     492             :                                   int nXOff, int nYOff, int nXSize, int nYSize,
     493             :                                   void *pData, int nBufXSize, int nBufYSize,
     494             :                                   GDALDataType eBufType, GSpacing nPixelSpace,
     495             :                                   GSpacing nLineSpace,
     496             :                                   GDALRasterIOExtraArg *psExtraArg)
     497             : 
     498             : {
     499       38770 :     VALIDATE_POINTER1(hBand, "GDALRasterIOEx", CE_Failure);
     500             : 
     501       38770 :     GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
     502             : 
     503       38770 :     return (poBand->RasterIO(eRWFlag, nXOff, nYOff, nXSize, nYSize, pData,
     504             :                              nBufXSize, nBufYSize, eBufType, nPixelSpace,
     505       38768 :                              nLineSpace, psExtraArg));
     506             : }
     507             : 
     508             : /************************************************************************/
     509             : /*                           GetGDTFromCppType()                        */
     510             : /************************************************************************/
     511             : 
     512             : namespace
     513             : {
     514             : template <class T> struct GetGDTFromCppType;
     515             : 
     516             : #define DEFINE_GetGDTFromCppType(T, eDT)                                       \
     517             :     template <> struct GetGDTFromCppType<T>                                    \
     518             :     {                                                                          \
     519             :         static constexpr GDALDataType GDT = eDT;                               \
     520             :     }
     521             : 
     522             : DEFINE_GetGDTFromCppType(uint8_t, GDT_Byte);
     523             : DEFINE_GetGDTFromCppType(int8_t, GDT_Int8);
     524             : DEFINE_GetGDTFromCppType(uint16_t, GDT_UInt16);
     525             : DEFINE_GetGDTFromCppType(int16_t, GDT_Int16);
     526             : DEFINE_GetGDTFromCppType(uint32_t, GDT_UInt32);
     527             : DEFINE_GetGDTFromCppType(int32_t, GDT_Int32);
     528             : DEFINE_GetGDTFromCppType(uint64_t, GDT_UInt64);
     529             : DEFINE_GetGDTFromCppType(int64_t, GDT_Int64);
     530             : DEFINE_GetGDTFromCppType(float, GDT_Float32);
     531             : DEFINE_GetGDTFromCppType(double, GDT_Float64);
     532             : // Not allowed by C++ standard
     533             : //DEFINE_GetGDTFromCppType(std::complex<int16_t>, GDT_CInt16);
     534             : //DEFINE_GetGDTFromCppType(std::complex<int32_t>, GDT_CInt32);
     535             : DEFINE_GetGDTFromCppType(std::complex<float>, GDT_CFloat32);
     536             : DEFINE_GetGDTFromCppType(std::complex<double>, GDT_CFloat64);
     537             : }  // namespace
     538             : 
     539             : /************************************************************************/
     540             : /*                           ReadRaster()                               */
     541             : /************************************************************************/
     542             : 
     543             : // clang-format off
     544             : /** Read a region of image data for this band.
     545             :  *
     546             :  * This is a slightly more convenient alternative to GDALRasterBand::RasterIO()
     547             :  * for common use cases, like reading a whole band.
     548             :  * It infers the GDAL data type of the buffer from the C/C++ type of the buffer.
     549             :  * This template is instantiated for the following types: [u?]int[8|16|32|64]_t,
     550             :  * float, double, std::complex<float|double>.
     551             :  *
     552             :  * 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>&,
     553             :  * and can allocate memory automatically.
     554             :  *
     555             :  * To read a whole band (assuming it fits into memory), as an array of double:
     556             :  *
     557             : \code{.cpp}
     558             :  double* myArray = static_cast<double*>(
     559             :      VSI_MALLOC3_VERBOSE(sizeof(double), poBand->GetXSize(), poBand->GetYSize()));
     560             :  // TODO: check here that myArray != nullptr
     561             :  const size_t nArrayEltCount =
     562             :      static_cast<size_t>(poBand->GetXSize()) * poBand->GetYSize());
     563             :  if (poBand->ReadRaster(myArray, nArrayEltCount) == CE_None)
     564             :  {
     565             :      // do something
     566             :  }
     567             :  VSIFree(myArray)
     568             : \endcode
     569             :  *
     570             :  * To read 128x128 pixels starting at (col=12, line=24) as an array of double:
     571             :  *
     572             : \code{.cpp}
     573             :  double* myArray = static_cast<double*>(
     574             :      VSI_MALLOC3_VERBOSE(sizeof(double), 128, 128));
     575             :  // TODO: check here that myArray != nullptr
     576             :  const size_t nArrayEltCount = 128 * 128;
     577             :  if (poBand->ReadRaster(myArray, nArrayEltCount, 12, 24, 128, 128) == CE_None)
     578             :  {
     579             :      // do something
     580             :  }
     581             :  VSIFree(myArray)
     582             : \endcode
     583             :  *
     584             :  * As nearly all GDAL methods, this method is *NOT* thread-safe, that is it cannot
     585             :  * be called on the same GDALRasterBand instance (or another GDALRasterBand
     586             :  * instance of this dataset) concurrently from several threads.
     587             :  *
     588             :  * The window of interest expressed by (dfXOff, dfYOff, dfXSize, dfYSize) should be
     589             :  * fully within the raster space, that is dfXOff >= 0, dfYOff >= 0,
     590             :  * dfXOff + dfXSize <= GetXSize() and dfYOff + dfYSize <= GetYSize().
     591             :  * If reads larger than the raster space are wished, GDALTranslate() might be used.
     592             :  * Or use nLineSpace and a possibly shifted pData value.
     593             :  *
     594             :  * @param[out] pData The buffer into which the data should be written.
     595             :  * This buffer must contain at least nBufXSize *
     596             :  * nBufYSize words of type T. It is organized in left to right,
     597             :  * top to bottom pixel order, and fully packed.
     598             :  * The type of the buffer does not need to be the one of GetDataType(). The
     599             :  * method will perform data type translation (with potential rounding, clamping)
     600             :  * if needed.
     601             :  *
     602             :  * @param nArrayEltCount Number of values of pData. If non zero, the method will
     603             :  * check that it is at least greater or equal to nBufXSize * nBufYSize, and
     604             :  * return in error if it is not. If set to zero, then pData is trusted to be
     605             :  * large enough.
     606             :  *
     607             :  * @param dfXOff The pixel offset to the top left corner of the region
     608             :  * of the band to be accessed. This would be zero to start from the left side.
     609             :  * Defaults to 0.
     610             :  *
     611             :  * @param dfYOff The line offset to the top left corner of the region
     612             :  * of the band to be accessed. This would be zero to start from the top.
     613             :  * Defaults to 0.
     614             :  *
     615             :  * @param dfXSize The width of the region of the band to be accessed in pixels.
     616             :  * If all of dfXOff, dfYOff, dfXSize and dfYSize are left to their zero default value,
     617             :  * dfXSize is set to the band width.
     618             :  *
     619             :  * @param dfYSize The height of the region of the band to be accessed in lines.
     620             :  * If all of dfXOff, dfYOff, dfXSize and dfYSize are left to their zero default value,
     621             :  * dfYSize is set to the band height.
     622             :  *
     623             :  * @param nBufXSize the width of the buffer image into which the desired region
     624             :  * is to be read. If set to zero, and both dfXSize and dfYSize are integer values,
     625             :  * then nBufXSize is initialized with dfXSize.
     626             :  *
     627             :  * @param nBufYSize the height of the buffer image into which the desired region
     628             :  * is to be read. If set to zero, and both dfXSize and dfYSize are integer values,
     629             :  * then nBufYSize is initialized with dfYSize.
     630             :  *
     631             :  * @param eResampleAlg Resampling algorithm. Defaults to GRIORA_NearestNeighbour.
     632             :  *
     633             :  * @param pfnProgress Progress function. May be nullptr.
     634             :  *
     635             :  * @param pProgressData User data of pfnProgress. May be nullptr.
     636             :  *
     637             :  * @return CE_Failure if the access fails, otherwise CE_None.
     638             :  *
     639             :  * @see GDALRasterBand::RasterIO()
     640             :  * @since GDAL 3.10
     641             :  */
     642             : // clang-format on
     643             : 
     644             : template <class T>
     645          19 : CPLErr GDALRasterBand::ReadRaster(T *pData, size_t nArrayEltCount,
     646             :                                   double dfXOff, double dfYOff, double dfXSize,
     647             :                                   double dfYSize, size_t nBufXSize,
     648             :                                   size_t nBufYSize,
     649             :                                   GDALRIOResampleAlg eResampleAlg,
     650             :                                   GDALProgressFunc pfnProgress,
     651             :                                   void *pProgressData) const
     652             : {
     653          19 :     if (((nBufXSize | nBufYSize) >> 31) != 0)
     654             :     {
     655           2 :         return CE_Failure;
     656             :     }
     657             : 
     658          17 :     if (dfXOff == 0 && dfYOff == 0 && dfXSize == 0 && dfYSize == 0)
     659             :     {
     660          15 :         dfXSize = nRasterXSize;
     661          15 :         dfYSize = nRasterYSize;
     662             :     }
     663           2 :     else if (!(dfXOff >= 0 && dfXOff <= INT_MAX) ||
     664           2 :              !(dfYOff >= 0 && dfYOff <= INT_MAX) || !(dfXSize >= 0) ||
     665           2 :              !(dfYSize >= 0) || dfXOff + dfXSize > INT_MAX ||
     666           2 :              dfYOff + dfYSize > INT_MAX)
     667             :     {
     668           0 :         return CE_Failure;
     669             :     }
     670             : 
     671             :     GDALRasterIOExtraArg sExtraArg;
     672          17 :     sExtraArg.nVersion = 1;
     673          17 :     sExtraArg.eResampleAlg = eResampleAlg;
     674          17 :     sExtraArg.pfnProgress = pfnProgress;
     675          17 :     sExtraArg.pProgressData = pProgressData;
     676          17 :     sExtraArg.bFloatingPointWindowValidity = true;
     677          17 :     sExtraArg.dfXOff = dfXOff;
     678          17 :     sExtraArg.dfYOff = dfYOff;
     679          17 :     sExtraArg.dfXSize = dfXSize;
     680          17 :     sExtraArg.dfYSize = dfYSize;
     681          17 :     const int nXOff = static_cast<int>(dfXOff);
     682          17 :     const int nYOff = static_cast<int>(dfYOff);
     683          17 :     const int nXSize = std::max(1, static_cast<int>(dfXSize + 0.5));
     684          17 :     const int nYSize = std::max(1, static_cast<int>(dfYSize + 0.5));
     685          17 :     if (nBufXSize == 0 && nBufYSize == 0)
     686             :     {
     687          16 :         if (static_cast<int>(dfXSize) == dfXSize &&
     688          16 :             static_cast<int>(dfYSize) == dfYSize)
     689             :         {
     690          16 :             nBufXSize = static_cast<int>(dfXSize);
     691          16 :             nBufYSize = static_cast<int>(dfYSize);
     692             :         }
     693             :         else
     694             :         {
     695           0 :             CPLError(CE_Failure, CPLE_AppDefined,
     696             :                      "nBufXSize and nBufYSize must be provided if dfXSize or "
     697             :                      "dfYSize is not an integer value");
     698           0 :             return CE_Failure;
     699             :         }
     700             :     }
     701          17 :     if (nBufXSize == 0 || nBufYSize == 0)
     702             :     {
     703           0 :         CPLDebug("GDAL",
     704             :                  "RasterIO() skipped for odd window or buffer size.\n"
     705             :                  "  Window = (%d,%d)x%dx%d\n"
     706             :                  "  Buffer = %dx%d\n",
     707             :                  nXOff, nYOff, nXSize, nYSize, static_cast<int>(nBufXSize),
     708             :                  static_cast<int>(nBufYSize));
     709             : 
     710           0 :         return CE_None;
     711             :     }
     712             : 
     713          17 :     if (nArrayEltCount > 0 && nBufXSize > nArrayEltCount / nBufYSize)
     714             :     {
     715           1 :         CPLError(CE_Failure, CPLE_AppDefined,
     716             :                  "Provided array is not large enough");
     717           1 :         return CE_Failure;
     718             :     }
     719             : 
     720          16 :     constexpr GSpacing nPixelSpace = sizeof(T);
     721          16 :     const GSpacing nLineSpace = nPixelSpace * nBufXSize;
     722          16 :     constexpr GDALDataType eBufType = GetGDTFromCppType<T>::GDT;
     723             : 
     724          16 :     GDALRasterBand *pThis = const_cast<GDALRasterBand *>(this);
     725             : 
     726             :     const bool bCallLeaveReadWrite =
     727          16 :         CPL_TO_BOOL(pThis->EnterReadWrite(GF_Read));
     728             :     CPLErr eErr;
     729             :     // coverity[identical_branches]
     730          16 :     if (bForceCachedIO)
     731           0 :         eErr = pThis->GDALRasterBand::IRasterIO(
     732             :             GF_Read, nXOff, nYOff, nXSize, nYSize, pData,
     733             :             static_cast<int>(nBufXSize), static_cast<int>(nBufYSize), eBufType,
     734             :             nPixelSpace, nLineSpace, &sExtraArg);
     735             :     else
     736          16 :         eErr = pThis->IRasterIO(GF_Read, nXOff, nYOff, nXSize, nYSize, pData,
     737             :                                 static_cast<int>(nBufXSize),
     738             :                                 static_cast<int>(nBufYSize), eBufType,
     739             :                                 nPixelSpace, nLineSpace, &sExtraArg);
     740             : 
     741          16 :     if (bCallLeaveReadWrite)
     742           0 :         pThis->LeaveReadWrite();
     743             : 
     744          16 :     return eErr;
     745             : }
     746             : 
     747             : //! @cond Doxygen_Suppress
     748             : 
     749             : #define INSTANTIATE_READ_RASTER(T)                                             \
     750             :     template CPLErr CPL_DLL GDALRasterBand::ReadRaster(                        \
     751             :         T *vData, size_t nArrayEltCount, double dfXOff, double dfYOff,         \
     752             :         double dfXSize, double dfYSize, size_t nBufXSize, size_t nBufYSize,    \
     753             :         GDALRIOResampleAlg eResampleAlg, GDALProgressFunc pfnProgress,         \
     754             :         void *pProgressData) const;
     755             : 
     756             : INSTANTIATE_READ_RASTER(uint8_t)
     757             : INSTANTIATE_READ_RASTER(int8_t)
     758             : INSTANTIATE_READ_RASTER(uint16_t)
     759             : INSTANTIATE_READ_RASTER(int16_t)
     760             : INSTANTIATE_READ_RASTER(uint32_t)
     761             : INSTANTIATE_READ_RASTER(int32_t)
     762             : INSTANTIATE_READ_RASTER(uint64_t)
     763             : INSTANTIATE_READ_RASTER(int64_t)
     764             : INSTANTIATE_READ_RASTER(float)
     765             : INSTANTIATE_READ_RASTER(double)
     766             : // Not allowed by C++ standard
     767             : // INSTANTIATE_READ_RASTER(std::complex<int16_t>)
     768             : // INSTANTIATE_READ_RASTER(std::complex<int32_t>)
     769             : INSTANTIATE_READ_RASTER(std::complex<float>)
     770             : INSTANTIATE_READ_RASTER(std::complex<double>)
     771             : 
     772             : //! @endcond
     773             : 
     774             : /************************************************************************/
     775             : /*                           ReadRaster()                               */
     776             : /************************************************************************/
     777             : 
     778             : /** Read a region of image data for this band.
     779             :  *
     780             :  * This is a slightly more convenient alternative to GDALRasterBand::RasterIO()
     781             :  * for common use cases, like reading a whole band.
     782             :  * It infers the GDAL data type of the buffer from the C/C++ type of the buffer.
     783             :  * This template is instantiated for the following types: [u?]int[8|16|32|64]_t,
     784             :  * float, double, std::complex<float|double>.
     785             :  *
     786             :  * To read a whole band (assuming it fits into memory), as a vector of double:
     787             :  *
     788             : \code
     789             :  std::vector<double> myArray;
     790             :  if (poBand->ReadRaster(myArray) == CE_None)
     791             :  {
     792             :      // do something
     793             :  }
     794             : \endcode
     795             :  *
     796             :  * To read 128x128 pixels starting at (col=12, line=24) as a vector of double:
     797             :  *
     798             : \code{.cpp}
     799             :  std::vector<double> myArray;
     800             :  if (poBand->ReadRaster(myArray, 12, 24, 128, 128) == CE_None)
     801             :  {
     802             :      // do something
     803             :  }
     804             : \endcode
     805             :  *
     806             :  * As nearly all GDAL methods, this method is *NOT* thread-safe, that is it cannot
     807             :  * be called on the same GDALRasterBand instance (or another GDALRasterBand
     808             :  * instance of this dataset) concurrently from several threads.
     809             :  *
     810             :  * The window of interest expressed by (dfXOff, dfYOff, dfXSize, dfYSize) should be
     811             :  * fully within the raster space, that is dfXOff >= 0, dfYOff >= 0,
     812             :  * dfXOff + dfXSize <= GetXSize() and dfYOff + dfYSize <= GetYSize().
     813             :  * If reads larger than the raster space are wished, GDALTranslate() might be used.
     814             :  * Or use nLineSpace and a possibly shifted pData value.
     815             :  *
     816             :  * @param[out] vData The vector into which the data should be written.
     817             :  * The vector will be resized, if needed, to contain at least nBufXSize *
     818             :  * nBufYSize values. The values in the vector are organized in left to right,
     819             :  * top to bottom pixel order, and fully packed.
     820             :  * The type of the vector does not need to be the one of GetDataType(). The
     821             :  * method will perform data type translation (with potential rounding, clamping)
     822             :  * if needed.
     823             :  *
     824             :  * @param dfXOff The pixel offset to the top left corner of the region
     825             :  * of the band to be accessed. This would be zero to start from the left side.
     826             :  * Defaults to 0.
     827             :  *
     828             :  * @param dfYOff The line offset to the top left corner of the region
     829             :  * of the band to be accessed. This would be zero to start from the top.
     830             :  * Defaults to 0.
     831             :  *
     832             :  * @param dfXSize The width of the region of the band to be accessed in pixels.
     833             :  * If all of dfXOff, dfYOff, dfXSize and dfYSize are left to their zero default value,
     834             :  * dfXSize is set to the band width.
     835             :  *
     836             :  * @param dfYSize The height of the region of the band to be accessed in lines.
     837             :  * If all of dfXOff, dfYOff, dfXSize and dfYSize are left to their zero default value,
     838             :  * dfYSize is set to the band height.
     839             :  *
     840             :  * @param nBufXSize the width of the buffer image into which the desired region
     841             :  * is to be read. If set to zero, and both dfXSize and dfYSize are integer values,
     842             :  * then nBufXSize is initialized with dfXSize.
     843             :  *
     844             :  * @param nBufYSize the height of the buffer image into which the desired region
     845             :  * is to be read. If set to zero, and both dfXSize and dfYSize are integer values,
     846             :  * then nBufYSize is initialized with dfYSize.
     847             :  *
     848             :  * @param eResampleAlg Resampling algorithm. Defaults to GRIORA_NearestNeighbour.
     849             :  *
     850             :  * @param pfnProgress Progress function. May be nullptr.
     851             :  *
     852             :  * @param pProgressData User data of pfnProgress. May be nullptr.
     853             :  *
     854             :  * @return CE_Failure if the access fails, otherwise CE_None.
     855             :  *
     856             :  * @see GDALRasterBand::RasterIO()
     857             :  * @since GDAL 3.10
     858             :  */
     859             : template <class T>
     860          21 : CPLErr GDALRasterBand::ReadRaster(std::vector<T> &vData, double dfXOff,
     861             :                                   double dfYOff, double dfXSize, double dfYSize,
     862             :                                   size_t nBufXSize, size_t nBufYSize,
     863             :                                   GDALRIOResampleAlg eResampleAlg,
     864             :                                   GDALProgressFunc pfnProgress,
     865             :                                   void *pProgressData) const
     866             : {
     867          21 :     if (((nBufXSize | nBufYSize) >> 31) != 0)
     868             :     {
     869           2 :         return CE_Failure;
     870             :     }
     871             : 
     872          19 :     if (dfXOff == 0 && dfYOff == 0 && dfXSize == 0 && dfYSize == 0)
     873             :     {
     874          12 :         dfXSize = nRasterXSize;
     875          12 :         dfYSize = nRasterYSize;
     876             :     }
     877           7 :     else if (!(dfXOff >= 0 && dfXOff <= INT_MAX) ||
     878           7 :              !(dfYOff >= 0 && dfYOff <= INT_MAX) || !(dfXSize >= 0) ||
     879           7 :              !(dfYSize >= 0) || dfXOff + dfXSize > INT_MAX ||
     880           7 :              dfYOff + dfYSize > INT_MAX)
     881             :     {
     882           0 :         return CE_Failure;
     883             :     }
     884             : 
     885             :     GDALRasterIOExtraArg sExtraArg;
     886          19 :     sExtraArg.nVersion = 1;
     887          19 :     sExtraArg.eResampleAlg = eResampleAlg;
     888          19 :     sExtraArg.pfnProgress = pfnProgress;
     889          19 :     sExtraArg.pProgressData = pProgressData;
     890          19 :     sExtraArg.bFloatingPointWindowValidity = true;
     891          19 :     sExtraArg.dfXOff = dfXOff;
     892          19 :     sExtraArg.dfYOff = dfYOff;
     893          19 :     sExtraArg.dfXSize = dfXSize;
     894          19 :     sExtraArg.dfYSize = dfYSize;
     895          19 :     const int nXOff = static_cast<int>(dfXOff);
     896          19 :     const int nYOff = static_cast<int>(dfYOff);
     897          19 :     const int nXSize = std::max(1, static_cast<int>(dfXSize + 0.5));
     898          19 :     const int nYSize = std::max(1, static_cast<int>(dfYSize + 0.5));
     899          19 :     if (nBufXSize == 0 && nBufYSize == 0)
     900             :     {
     901          15 :         if (static_cast<int>(dfXSize) == dfXSize &&
     902          14 :             static_cast<int>(dfYSize) == dfYSize)
     903             :         {
     904          14 :             nBufXSize = static_cast<int>(dfXSize);
     905          14 :             nBufYSize = static_cast<int>(dfYSize);
     906             :         }
     907             :         else
     908             :         {
     909           1 :             CPLError(CE_Failure, CPLE_AppDefined,
     910             :                      "nBufXSize and nBufYSize must be provided if "
     911             :                      "dfXSize or dfYSize is not an integer value");
     912           1 :             return CE_Failure;
     913             :         }
     914             :     }
     915          18 :     if (nBufXSize == 0 || nBufYSize == 0)
     916             :     {
     917           0 :         CPLDebug("GDAL",
     918             :                  "RasterIO() skipped for odd window or buffer size.\n"
     919             :                  "  Window = (%d,%d)x%dx%d\n"
     920             :                  "  Buffer = %dx%d\n",
     921             :                  nXOff, nYOff, nXSize, nYSize, static_cast<int>(nBufXSize),
     922             :                  static_cast<int>(nBufYSize));
     923             : 
     924           0 :         return CE_None;
     925             :     }
     926             : 
     927             :     if constexpr (SIZEOF_VOIDP < 8)
     928             :     {
     929             :         if (nBufXSize > std::numeric_limits<size_t>::max() / nBufYSize)
     930             :         {
     931             :             CPLError(CE_Failure, CPLE_OutOfMemory, "Too large buffer");
     932             :             return CE_Failure;
     933             :         }
     934             :     }
     935             : 
     936          18 :     if (vData.size() < nBufXSize * nBufYSize)
     937             :     {
     938             :         try
     939             :         {
     940          16 :             vData.resize(nBufXSize * nBufYSize);
     941             :         }
     942           1 :         catch (const std::exception &)
     943             :         {
     944           1 :             CPLError(CE_Failure, CPLE_OutOfMemory, "Cannot resize array");
     945           1 :             return CE_Failure;
     946             :         }
     947             :     }
     948             : 
     949          17 :     constexpr GSpacing nPixelSpace = sizeof(T);
     950          17 :     const GSpacing nLineSpace = nPixelSpace * nBufXSize;
     951          17 :     constexpr GDALDataType eBufType = GetGDTFromCppType<T>::GDT;
     952             : 
     953          17 :     GDALRasterBand *pThis = const_cast<GDALRasterBand *>(this);
     954             : 
     955             :     const bool bCallLeaveReadWrite =
     956          17 :         CPL_TO_BOOL(pThis->EnterReadWrite(GF_Read));
     957             : 
     958             :     CPLErr eErr;
     959             :     // coverity[identical_branches]
     960          17 :     if (bForceCachedIO)
     961           0 :         eErr = pThis->GDALRasterBand::IRasterIO(
     962             :             GF_Read, nXOff, nYOff, nXSize, nYSize, vData.data(),
     963             :             static_cast<int>(nBufXSize), static_cast<int>(nBufYSize), eBufType,
     964             :             nPixelSpace, nLineSpace, &sExtraArg);
     965             :     else
     966          17 :         eErr = pThis->IRasterIO(GF_Read, nXOff, nYOff, nXSize, nYSize,
     967             :                                 vData.data(), static_cast<int>(nBufXSize),
     968             :                                 static_cast<int>(nBufYSize), eBufType,
     969             :                                 nPixelSpace, nLineSpace, &sExtraArg);
     970             : 
     971          17 :     if (bCallLeaveReadWrite)
     972           0 :         pThis->LeaveReadWrite();
     973             : 
     974          17 :     return eErr;
     975             : }
     976             : 
     977             : //! @cond Doxygen_Suppress
     978             : 
     979             : #define INSTANTIATE_READ_RASTER_VECTOR(T)                                      \
     980             :     template CPLErr CPL_DLL GDALRasterBand::ReadRaster(                        \
     981             :         std::vector<T> &vData, double dfXOff, double dfYOff, double dfXSize,   \
     982             :         double dfYSize, size_t nBufXSize, size_t nBufYSize,                    \
     983             :         GDALRIOResampleAlg eResampleAlg, GDALProgressFunc pfnProgress,         \
     984             :         void *pProgressData) const;
     985             : 
     986             : INSTANTIATE_READ_RASTER_VECTOR(uint8_t)
     987             : INSTANTIATE_READ_RASTER_VECTOR(int8_t)
     988             : INSTANTIATE_READ_RASTER_VECTOR(uint16_t)
     989             : INSTANTIATE_READ_RASTER_VECTOR(int16_t)
     990             : INSTANTIATE_READ_RASTER_VECTOR(uint32_t)
     991             : INSTANTIATE_READ_RASTER_VECTOR(int32_t)
     992             : INSTANTIATE_READ_RASTER_VECTOR(uint64_t)
     993             : INSTANTIATE_READ_RASTER_VECTOR(int64_t)
     994             : INSTANTIATE_READ_RASTER_VECTOR(float)
     995             : INSTANTIATE_READ_RASTER_VECTOR(double)
     996             : // Not allowed by C++ standard
     997             : // INSTANTIATE_READ_RASTER_VECTOR(std::complex<int16_t>)
     998             : // INSTANTIATE_READ_RASTER_VECTOR(std::complex<int32_t>)
     999             : INSTANTIATE_READ_RASTER_VECTOR(std::complex<float>)
    1000             : INSTANTIATE_READ_RASTER_VECTOR(std::complex<double>)
    1001             : 
    1002             : //! @endcond
    1003             : 
    1004             : /************************************************************************/
    1005             : /*                             ReadBlock()                              */
    1006             : /************************************************************************/
    1007             : 
    1008             : /**
    1009             :  * \brief Read a block of image data efficiently.
    1010             :  *
    1011             :  * This method accesses a "natural" block from the raster band without
    1012             :  * resampling, or data type conversion.  For a more generalized, but
    1013             :  * potentially less efficient access use RasterIO().
    1014             :  *
    1015             :  * This method is the same as the C GDALReadBlock() function.
    1016             :  *
    1017             :  * See the GetLockedBlockRef() method for a way of accessing internally cached
    1018             :  * block oriented data without an extra copy into an application buffer.
    1019             :  *
    1020             :  * The following code would efficiently compute a histogram of eight bit
    1021             :  * raster data.  Note that the final block may be partial ... data beyond
    1022             :  * the edge of the underlying raster band in these edge blocks is of an
    1023             :  * undetermined value.
    1024             :  *
    1025             : \code{.cpp}
    1026             :  CPLErr GetHistogram( GDALRasterBand *poBand, GUIntBig *panHistogram )
    1027             : 
    1028             :  {
    1029             :      memset( panHistogram, 0, sizeof(GUIntBig) * 256 );
    1030             : 
    1031             :      CPLAssert( poBand->GetRasterDataType() == GDT_Byte );
    1032             : 
    1033             :      int nXBlockSize, nYBlockSize;
    1034             : 
    1035             :      poBand->GetBlockSize( &nXBlockSize, &nYBlockSize );
    1036             :      int nXBlocks = (poBand->GetXSize() + nXBlockSize - 1) / nXBlockSize;
    1037             :      int nYBlocks = (poBand->GetYSize() + nYBlockSize - 1) / nYBlockSize;
    1038             : 
    1039             :      GByte *pabyData = (GByte *) CPLMalloc(nXBlockSize * nYBlockSize);
    1040             : 
    1041             :      for( int iYBlock = 0; iYBlock < nYBlocks; iYBlock++ )
    1042             :      {
    1043             :          for( int iXBlock = 0; iXBlock < nXBlocks; iXBlock++ )
    1044             :          {
    1045             :              int        nXValid, nYValid;
    1046             : 
    1047             :              poBand->ReadBlock( iXBlock, iYBlock, pabyData );
    1048             : 
    1049             :              // Compute the portion of the block that is valid
    1050             :              // for partial edge blocks.
    1051             :              poBand->GetActualBlockSize(iXBlock, iYBlock, &nXValid, &nYValid)
    1052             : 
    1053             :              // Collect the histogram counts.
    1054             :              for( int iY = 0; iY < nYValid; iY++ )
    1055             :              {
    1056             :                  for( int iX = 0; iX < nXValid; iX++ )
    1057             :                  {
    1058             :                      panHistogram[pabyData[iX + iY * nXBlockSize]] += 1;
    1059             :                  }
    1060             :              }
    1061             :          }
    1062             :      }
    1063             :  }
    1064             : \endcode
    1065             :  *
    1066             :  * @param nXBlockOff the horizontal block offset, with zero indicating
    1067             :  * the left most block, 1 the next block and so forth.
    1068             :  *
    1069             :  * @param nYBlockOff the vertical block offset, with zero indicating
    1070             :  * the top most block, 1 the next block and so forth.
    1071             :  *
    1072             :  * @param pImage the buffer into which the data will be read.  The buffer
    1073             :  * must be large enough to hold GetBlockXSize()*GetBlockYSize() words
    1074             :  * of type GetRasterDataType().
    1075             :  *
    1076             :  * @return CE_None on success or CE_Failure on an error.
    1077             :  */
    1078             : 
    1079         646 : CPLErr GDALRasterBand::ReadBlock(int nXBlockOff, int nYBlockOff, void *pImage)
    1080             : 
    1081             : {
    1082             :     /* -------------------------------------------------------------------- */
    1083             :     /*      Validate arguments.                                             */
    1084             :     /* -------------------------------------------------------------------- */
    1085         646 :     CPLAssert(pImage != nullptr);
    1086             : 
    1087         646 :     if (!InitBlockInfo())
    1088           0 :         return CE_Failure;
    1089             : 
    1090         646 :     if (nXBlockOff < 0 || nXBlockOff >= nBlocksPerRow)
    1091             :     {
    1092           0 :         ReportError(CE_Failure, CPLE_IllegalArg,
    1093             :                     "Illegal nXBlockOff value (%d) in "
    1094             :                     "GDALRasterBand::ReadBlock()\n",
    1095             :                     nXBlockOff);
    1096             : 
    1097           0 :         return (CE_Failure);
    1098             :     }
    1099             : 
    1100         646 :     if (nYBlockOff < 0 || nYBlockOff >= nBlocksPerColumn)
    1101             :     {
    1102           0 :         ReportError(CE_Failure, CPLE_IllegalArg,
    1103             :                     "Illegal nYBlockOff value (%d) in "
    1104             :                     "GDALRasterBand::ReadBlock()\n",
    1105             :                     nYBlockOff);
    1106             : 
    1107           0 :         return (CE_Failure);
    1108             :     }
    1109             : 
    1110             :     /* -------------------------------------------------------------------- */
    1111             :     /*      Invoke underlying implementation method.                        */
    1112             :     /* -------------------------------------------------------------------- */
    1113             : 
    1114         646 :     int bCallLeaveReadWrite = EnterReadWrite(GF_Read);
    1115         646 :     CPLErr eErr = IReadBlock(nXBlockOff, nYBlockOff, pImage);
    1116         646 :     if (bCallLeaveReadWrite)
    1117           4 :         LeaveReadWrite();
    1118         646 :     return eErr;
    1119             : }
    1120             : 
    1121             : /************************************************************************/
    1122             : /*                           GDALReadBlock()                            */
    1123             : /************************************************************************/
    1124             : 
    1125             : /**
    1126             :  * \brief Read a block of image data efficiently.
    1127             :  *
    1128             :  * @see GDALRasterBand::ReadBlock()
    1129             :  */
    1130             : 
    1131          69 : CPLErr CPL_STDCALL GDALReadBlock(GDALRasterBandH hBand, int nXOff, int nYOff,
    1132             :                                  void *pData)
    1133             : 
    1134             : {
    1135          69 :     VALIDATE_POINTER1(hBand, "GDALReadBlock", CE_Failure);
    1136             : 
    1137          69 :     GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
    1138          69 :     return (poBand->ReadBlock(nXOff, nYOff, pData));
    1139             : }
    1140             : 
    1141             : /************************************************************************/
    1142             : /*                            IReadBlock()                             */
    1143             : /************************************************************************/
    1144             : 
    1145             : /** \fn GDALRasterBand::IReadBlock( int nBlockXOff, int nBlockYOff, void *pData
    1146             :  * ) \brief Read a block of data.
    1147             :  *
    1148             :  * Default internal implementation ... to be overridden by
    1149             :  * subclasses that support reading.
    1150             :  * @param nBlockXOff Block X Offset
    1151             :  * @param nBlockYOff Block Y Offset
    1152             :  * @param pData Pixel buffer into which to place read data.
    1153             :  * @return CE_None on success or CE_Failure on an error.
    1154             :  */
    1155             : 
    1156             : /************************************************************************/
    1157             : /*                            IWriteBlock()                             */
    1158             : /************************************************************************/
    1159             : 
    1160             : /**
    1161             :  * \fn GDALRasterBand::IWriteBlock(int, int, void*)
    1162             :  * Write a block of data.
    1163             :  *
    1164             :  * Default internal implementation ... to be overridden by
    1165             :  * subclasses that support writing.
    1166             :  * @param nBlockXOff Block X Offset
    1167             :  * @param nBlockYOff Block Y Offset
    1168             :  * @param pData Pixel buffer to write
    1169             :  * @return CE_None on success or CE_Failure on an error.
    1170             :  */
    1171             : 
    1172             : /**/
    1173             : /**/
    1174             : 
    1175           0 : CPLErr GDALRasterBand::IWriteBlock(int /*nBlockXOff*/, int /*nBlockYOff*/,
    1176             :                                    void * /*pData*/)
    1177             : 
    1178             : {
    1179           0 :     if (!(GetMOFlags() & GMO_IGNORE_UNIMPLEMENTED))
    1180           0 :         ReportError(CE_Failure, CPLE_NotSupported,
    1181             :                     "WriteBlock() not supported for this dataset.");
    1182             : 
    1183           0 :     return (CE_Failure);
    1184             : }
    1185             : 
    1186             : /************************************************************************/
    1187             : /*                             WriteBlock()                             */
    1188             : /************************************************************************/
    1189             : 
    1190             : /**
    1191             :  * \brief Write a block of image data efficiently.
    1192             :  *
    1193             :  * This method accesses a "natural" block from the raster band without
    1194             :  * resampling, or data type conversion.  For a more generalized, but
    1195             :  * potentially less efficient access use RasterIO().
    1196             :  *
    1197             :  * This method is the same as the C GDALWriteBlock() function.
    1198             :  *
    1199             :  * See ReadBlock() for an example of block oriented data access.
    1200             :  *
    1201             :  * @param nXBlockOff the horizontal block offset, with zero indicating
    1202             :  * the left most block, 1 the next block and so forth.
    1203             :  *
    1204             :  * @param nYBlockOff the vertical block offset, with zero indicating
    1205             :  * the left most block, 1 the next block and so forth.
    1206             :  *
    1207             :  * @param pImage the buffer from which the data will be written.  The buffer
    1208             :  * must be large enough to hold GetBlockXSize()*GetBlockYSize() words
    1209             :  * of type GetRasterDataType(). Note that the content of the buffer might be
    1210             :  * temporarily modified during the execution of this method (and eventually
    1211             :  * restored back to its original content), so it is not safe to use a buffer
    1212             :  * stored in a read-only section of the calling program.
    1213             :  *
    1214             :  * @return CE_None on success or CE_Failure on an error.
    1215             :  */
    1216             : 
    1217        4888 : CPLErr GDALRasterBand::WriteBlock(int nXBlockOff, int nYBlockOff, void *pImage)
    1218             : 
    1219             : {
    1220             :     /* -------------------------------------------------------------------- */
    1221             :     /*      Validate arguments.                                             */
    1222             :     /* -------------------------------------------------------------------- */
    1223        4888 :     CPLAssert(pImage != nullptr);
    1224             : 
    1225        4888 :     if (!InitBlockInfo())
    1226           0 :         return CE_Failure;
    1227             : 
    1228        4888 :     if (nXBlockOff < 0 || nXBlockOff >= nBlocksPerRow)
    1229             :     {
    1230           0 :         ReportError(CE_Failure, CPLE_IllegalArg,
    1231             :                     "Illegal nXBlockOff value (%d) in "
    1232             :                     "GDALRasterBand::WriteBlock()\n",
    1233             :                     nXBlockOff);
    1234             : 
    1235           0 :         return (CE_Failure);
    1236             :     }
    1237             : 
    1238        4888 :     if (nYBlockOff < 0 || nYBlockOff >= nBlocksPerColumn)
    1239             :     {
    1240           0 :         ReportError(CE_Failure, CPLE_IllegalArg,
    1241             :                     "Illegal nYBlockOff value (%d) in "
    1242             :                     "GDALRasterBand::WriteBlock()\n",
    1243             :                     nYBlockOff);
    1244             : 
    1245           0 :         return (CE_Failure);
    1246             :     }
    1247             : 
    1248        4888 :     if (EmitErrorMessageIfWriteNotSupported("GDALRasterBand::WriteBlock()"))
    1249             :     {
    1250           0 :         return CE_Failure;
    1251             :     }
    1252             : 
    1253        4888 :     if (eFlushBlockErr != CE_None)
    1254             :     {
    1255           0 :         ReportError(eFlushBlockErr, CPLE_AppDefined,
    1256             :                     "An error occurred while writing a dirty block "
    1257             :                     "from GDALRasterBand::WriteBlock");
    1258           0 :         CPLErr eErr = eFlushBlockErr;
    1259           0 :         eFlushBlockErr = CE_None;
    1260           0 :         return eErr;
    1261             :     }
    1262             : 
    1263             :     /* -------------------------------------------------------------------- */
    1264             :     /*      Invoke underlying implementation method.                        */
    1265             :     /* -------------------------------------------------------------------- */
    1266             : 
    1267        4888 :     const bool bCallLeaveReadWrite = CPL_TO_BOOL(EnterReadWrite(GF_Write));
    1268        4888 :     CPLErr eErr = IWriteBlock(nXBlockOff, nYBlockOff, pImage);
    1269        4888 :     if (bCallLeaveReadWrite)
    1270        4888 :         LeaveReadWrite();
    1271             : 
    1272        4888 :     return eErr;
    1273             : }
    1274             : 
    1275             : /************************************************************************/
    1276             : /*                           GDALWriteBlock()                           */
    1277             : /************************************************************************/
    1278             : 
    1279             : /**
    1280             :  * \brief Write a block of image data efficiently.
    1281             :  *
    1282             :  * @see GDALRasterBand::WriteBlock()
    1283             :  */
    1284             : 
    1285           0 : CPLErr CPL_STDCALL GDALWriteBlock(GDALRasterBandH hBand, int nXOff, int nYOff,
    1286             :                                   void *pData)
    1287             : 
    1288             : {
    1289           0 :     VALIDATE_POINTER1(hBand, "GDALWriteBlock", CE_Failure);
    1290             : 
    1291           0 :     GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
    1292           0 :     return (poBand->WriteBlock(nXOff, nYOff, pData));
    1293             : }
    1294             : 
    1295             : /************************************************************************/
    1296             : /*                   EmitErrorMessageIfWriteNotSupported()              */
    1297             : /************************************************************************/
    1298             : 
    1299             : /**
    1300             :  * Emit an error message if a write operation to this band is not supported.
    1301             :  *
    1302             :  * The base implementation will emit an error message if the access mode is
    1303             :  * read-only. Derived classes may implement it to provide a custom message.
    1304             :  *
    1305             :  * @param pszCaller Calling function.
    1306             :  * @return true if an error message has been emitted.
    1307             :  */
    1308      536181 : bool GDALRasterBand::EmitErrorMessageIfWriteNotSupported(
    1309             :     const char *pszCaller) const
    1310             : {
    1311      536181 :     if (eAccess == GA_ReadOnly)
    1312             :     {
    1313           4 :         ReportError(CE_Failure, CPLE_NoWriteAccess,
    1314             :                     "%s: attempt to write to dataset opened in read-only mode.",
    1315             :                     pszCaller);
    1316             : 
    1317           4 :         return true;
    1318             :     }
    1319      536177 :     return false;
    1320             : }
    1321             : 
    1322             : /************************************************************************/
    1323             : /*                         GetActualBlockSize()                         */
    1324             : /************************************************************************/
    1325             : /**
    1326             :  * \brief Fetch the actual block size for a given block offset.
    1327             :  *
    1328             :  * Handles partial blocks at the edges of the raster and returns the true
    1329             :  * number of pixels
    1330             :  *
    1331             :  * @param nXBlockOff the horizontal block offset for which to calculate the
    1332             :  * number of valid pixels, with zero indicating the left most block, 1 the next
    1333             :  * block and so forth.
    1334             :  *
    1335             :  * @param nYBlockOff the vertical block offset, with zero indicating
    1336             :  * the top most block, 1 the next block and so forth.
    1337             :  *
    1338             :  * @param pnXValid pointer to an integer in which the number of valid pixels in
    1339             :  * the x direction will be stored
    1340             :  *
    1341             :  * @param pnYValid pointer to an integer in which the number of valid pixels in
    1342             :  * the y direction will be stored
    1343             :  *
    1344             :  * @return CE_None if the input parameters are valid, CE_Failure otherwise
    1345             :  *
    1346             :  * @since GDAL 2.2
    1347             :  */
    1348       50145 : CPLErr GDALRasterBand::GetActualBlockSize(int nXBlockOff, int nYBlockOff,
    1349             :                                           int *pnXValid, int *pnYValid) const
    1350             : {
    1351      100289 :     if (nXBlockOff < 0 || nBlockXSize == 0 ||
    1352      100287 :         nXBlockOff >= DIV_ROUND_UP(nRasterXSize, nBlockXSize) ||
    1353      100284 :         nYBlockOff < 0 || nBlockYSize == 0 ||
    1354       50142 :         nYBlockOff >= DIV_ROUND_UP(nRasterYSize, nBlockYSize))
    1355             :     {
    1356           5 :         return CE_Failure;
    1357             :     }
    1358             : 
    1359       50140 :     const int nXPixelOff = nXBlockOff * nBlockXSize;
    1360       50140 :     const int nYPixelOff = nYBlockOff * nBlockYSize;
    1361             : 
    1362       50140 :     *pnXValid = nBlockXSize;
    1363       50140 :     *pnYValid = nBlockYSize;
    1364             : 
    1365       50140 :     if (nXPixelOff >= nRasterXSize - nBlockXSize)
    1366             :     {
    1367       48756 :         *pnXValid = nRasterXSize - nXPixelOff;
    1368             :     }
    1369             : 
    1370       50140 :     if (nYPixelOff >= nRasterYSize - nBlockYSize)
    1371             :     {
    1372        3297 :         *pnYValid = nRasterYSize - nYPixelOff;
    1373             :     }
    1374             : 
    1375       50140 :     return CE_None;
    1376             : }
    1377             : 
    1378             : /************************************************************************/
    1379             : /*                           GDALGetActualBlockSize()                   */
    1380             : /************************************************************************/
    1381             : 
    1382             : /**
    1383             :  * \brief Retrieve the actual block size for a given block offset.
    1384             :  *
    1385             :  * @see GDALRasterBand::GetActualBlockSize()
    1386             :  */
    1387             : 
    1388           6 : CPLErr CPL_STDCALL GDALGetActualBlockSize(GDALRasterBandH hBand, int nXBlockOff,
    1389             :                                           int nYBlockOff, int *pnXValid,
    1390             :                                           int *pnYValid)
    1391             : 
    1392             : {
    1393           6 :     VALIDATE_POINTER1(hBand, "GDALGetActualBlockSize", CE_Failure);
    1394             : 
    1395           6 :     GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
    1396             :     return (
    1397           6 :         poBand->GetActualBlockSize(nXBlockOff, nYBlockOff, pnXValid, pnYValid));
    1398             : }
    1399             : 
    1400             : /************************************************************************/
    1401             : /*                     GetSuggestedBlockAccessPattern()                 */
    1402             : /************************************************************************/
    1403             : 
    1404             : /**
    1405             :  * \brief Return the suggested/most efficient access pattern to blocks
    1406             :  *        (for read operations).
    1407             :  *
    1408             :  * While all GDAL drivers have to expose a block size, not all can guarantee
    1409             :  * efficient random access (GSBAP_RANDOM) to any block.
    1410             :  * Some drivers for example decompress sequentially a compressed stream from
    1411             :  * top raster to bottom (GSBAP_TOP_TO_BOTTOM), in which
    1412             :  * case best performance will be achieved while reading blocks in that order.
    1413             :  * (accessing blocks in random access in such rasters typically causes the
    1414             :  * decoding to be re-initialized from the start if accessing blocks in
    1415             :  * a non-sequential order)
    1416             :  *
    1417             :  * The base implementation returns GSBAP_UNKNOWN, which can also be explicitly
    1418             :  * returned by drivers that expose a somewhat artificial block size, because
    1419             :  * they can extract any part of a raster, but in a rather inefficient way.
    1420             :  *
    1421             :  * The GSBAP_LARGEST_CHUNK_POSSIBLE value can be combined as a logical bitmask
    1422             :  * with other enumeration values (GSBAP_UNKNOWN, GSBAP_RANDOM,
    1423             :  * GSBAP_TOP_TO_BOTTOM, GSBAP_BOTTOM_TO_TOP). When a driver sets this flag, the
    1424             :  * most efficient strategy is to read as many pixels as possible in the less
    1425             :  * RasterIO() operations.
    1426             :  *
    1427             :  * The return of this method is for example used to determine the swath size
    1428             :  * used by GDALDatasetCopyWholeRaster() and GDALRasterBandCopyWholeRaster().
    1429             :  *
    1430             :  * @since GDAL 3.6
    1431             :  */
    1432             : 
    1433             : GDALSuggestedBlockAccessPattern
    1434        2344 : GDALRasterBand::GetSuggestedBlockAccessPattern() const
    1435             : {
    1436        2344 :     return GSBAP_UNKNOWN;
    1437             : }
    1438             : 
    1439             : /************************************************************************/
    1440             : /*                         GetRasterDataType()                          */
    1441             : /************************************************************************/
    1442             : 
    1443             : /**
    1444             :  * \brief Fetch the pixel data type for this band.
    1445             :  *
    1446             :  * This method is the same as the C function GDALGetRasterDataType().
    1447             :  *
    1448             :  * @return the data type of pixels for this band.
    1449             :  */
    1450             : 
    1451     8431420 : GDALDataType GDALRasterBand::GetRasterDataType() const
    1452             : 
    1453             : {
    1454     8431420 :     return eDataType;
    1455             : }
    1456             : 
    1457             : /************************************************************************/
    1458             : /*                       GDALGetRasterDataType()                        */
    1459             : /************************************************************************/
    1460             : 
    1461             : /**
    1462             :  * \brief Fetch the pixel data type for this band.
    1463             :  *
    1464             :  * @see GDALRasterBand::GetRasterDataType()
    1465             :  */
    1466             : 
    1467      903205 : GDALDataType CPL_STDCALL GDALGetRasterDataType(GDALRasterBandH hBand)
    1468             : 
    1469             : {
    1470      903205 :     VALIDATE_POINTER1(hBand, "GDALGetRasterDataType", GDT_Unknown);
    1471             : 
    1472      903205 :     GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
    1473      903205 :     return poBand->GetRasterDataType();
    1474             : }
    1475             : 
    1476             : /************************************************************************/
    1477             : /*                            GetBlockSize()                            */
    1478             : /************************************************************************/
    1479             : 
    1480             : /**
    1481             :  * \brief Fetch the "natural" block size of this band.
    1482             :  *
    1483             :  * GDAL contains a concept of the natural block size of rasters so that
    1484             :  * applications can organized data access efficiently for some file formats.
    1485             :  * The natural block size is the block size that is most efficient for
    1486             :  * accessing the format.  For many formats this is simple a whole scanline
    1487             :  * in which case *pnXSize is set to GetXSize(), and *pnYSize is set to 1.
    1488             :  *
    1489             :  * However, for tiled images this will typically be the tile size.
    1490             :  *
    1491             :  * Note that the X and Y block sizes don't have to divide the image size
    1492             :  * evenly, meaning that right and bottom edge blocks may be incomplete.
    1493             :  * See ReadBlock() for an example of code dealing with these issues.
    1494             :  *
    1495             :  * This method is the same as the C function GDALGetBlockSize().
    1496             :  *
    1497             :  * @param pnXSize integer to put the X block size into or NULL.
    1498             :  *
    1499             :  * @param pnYSize integer to put the Y block size into or NULL.
    1500             :  */
    1501             : 
    1502     5211750 : void GDALRasterBand::GetBlockSize(int *pnXSize, int *pnYSize) const
    1503             : 
    1504             : {
    1505     5211750 :     if (nBlockXSize <= 0 || nBlockYSize <= 0)
    1506             :     {
    1507       13668 :         ReportError(CE_Failure, CPLE_AppDefined,
    1508       13668 :                     "Invalid block dimension : %d * %d", nBlockXSize,
    1509       13668 :                     nBlockYSize);
    1510           0 :         if (pnXSize != nullptr)
    1511           0 :             *pnXSize = 0;
    1512           0 :         if (pnYSize != nullptr)
    1513           0 :             *pnYSize = 0;
    1514             :     }
    1515             :     else
    1516             :     {
    1517     5198080 :         if (pnXSize != nullptr)
    1518     5202180 :             *pnXSize = nBlockXSize;
    1519     5198080 :         if (pnYSize != nullptr)
    1520     5202610 :             *pnYSize = nBlockYSize;
    1521             :     }
    1522     5198080 : }
    1523             : 
    1524             : /************************************************************************/
    1525             : /*                          GDALGetBlockSize()                          */
    1526             : /************************************************************************/
    1527             : 
    1528             : /**
    1529             :  * \brief Fetch the "natural" block size of this band.
    1530             :  *
    1531             :  * @see GDALRasterBand::GetBlockSize()
    1532             :  */
    1533             : 
    1534       40982 : void CPL_STDCALL GDALGetBlockSize(GDALRasterBandH hBand, int *pnXSize,
    1535             :                                   int *pnYSize)
    1536             : 
    1537             : {
    1538       40982 :     VALIDATE_POINTER0(hBand, "GDALGetBlockSize");
    1539             : 
    1540       40982 :     GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
    1541       40982 :     poBand->GetBlockSize(pnXSize, pnYSize);
    1542             : }
    1543             : 
    1544             : /************************************************************************/
    1545             : /*                           InitBlockInfo()                            */
    1546             : /************************************************************************/
    1547             : 
    1548             : //! @cond Doxygen_Suppress
    1549     3340480 : int GDALRasterBand::InitBlockInfo()
    1550             : 
    1551             : {
    1552     3340480 :     if (poBandBlockCache != nullptr)
    1553     3302260 :         return poBandBlockCache->IsInitOK();
    1554             : 
    1555             :     /* Do some validation of raster and block dimensions in case the driver */
    1556             :     /* would have neglected to do it itself */
    1557       38226 :     if (nBlockXSize <= 0 || nBlockYSize <= 0)
    1558             :     {
    1559           4 :         ReportError(CE_Failure, CPLE_AppDefined,
    1560             :                     "Invalid block dimension : %d * %d", nBlockXSize,
    1561             :                     nBlockYSize);
    1562           0 :         return FALSE;
    1563             :     }
    1564             : 
    1565       38222 :     if (nRasterXSize <= 0 || nRasterYSize <= 0)
    1566             :     {
    1567           6 :         ReportError(CE_Failure, CPLE_AppDefined,
    1568             :                     "Invalid raster dimension : %d * %d", nRasterXSize,
    1569             :                     nRasterYSize);
    1570           0 :         return FALSE;
    1571             :     }
    1572             : 
    1573       38216 :     const int nDataTypeSize = GDALGetDataTypeSizeBytes(eDataType);
    1574       38224 :     if (nDataTypeSize == 0)
    1575             :     {
    1576           0 :         ReportError(CE_Failure, CPLE_AppDefined, "Invalid data type");
    1577           0 :         return FALSE;
    1578             :     }
    1579             : 
    1580             : #if SIZEOF_VOIDP == 4
    1581             :     if (nBlockXSize >= 10000 || nBlockYSize >= 10000)
    1582             :     {
    1583             :         /* As 10000 * 10000 * 16 < INT_MAX, we don't need to do the
    1584             :          * multiplication in other cases */
    1585             :         if (nBlockXSize > INT_MAX / nDataTypeSize ||
    1586             :             nBlockYSize > INT_MAX / (nDataTypeSize * nBlockXSize))
    1587             :         {
    1588             :             ReportError(CE_Failure, CPLE_NotSupported,
    1589             :                         "Too big block : %d * %d for 32-bit build", nBlockXSize,
    1590             :                         nBlockYSize);
    1591             :             return FALSE;
    1592             :         }
    1593             :     }
    1594             : #endif
    1595             : 
    1596       38224 :     nBlocksPerRow = DIV_ROUND_UP(nRasterXSize, nBlockXSize);
    1597       38224 :     nBlocksPerColumn = DIV_ROUND_UP(nRasterYSize, nBlockYSize);
    1598             : 
    1599             :     const char *pszBlockStrategy =
    1600       38224 :         CPLGetConfigOption("GDAL_BAND_BLOCK_CACHE", nullptr);
    1601       38228 :     bool bUseArray = true;
    1602       38228 :     if (pszBlockStrategy == nullptr || EQUAL(pszBlockStrategy, "AUTO"))
    1603             :     {
    1604       38188 :         if (poDS == nullptr || (poDS->nOpenFlags & GDAL_OF_BLOCK_ACCESS_MASK) ==
    1605             :                                    GDAL_OF_DEFAULT_BLOCK_ACCESS)
    1606             :         {
    1607       38169 :             GUIntBig nBlockCount =
    1608       38169 :                 static_cast<GIntBig>(nBlocksPerRow) * nBlocksPerColumn;
    1609       38169 :             if (poDS != nullptr)
    1610       37974 :                 nBlockCount *= poDS->GetRasterCount();
    1611       38169 :             bUseArray = (nBlockCount < 1024 * 1024);
    1612             :         }
    1613          19 :         else if ((poDS->nOpenFlags & GDAL_OF_BLOCK_ACCESS_MASK) ==
    1614             :                  GDAL_OF_HASHSET_BLOCK_ACCESS)
    1615             :         {
    1616           0 :             bUseArray = false;
    1617       38188 :         }
    1618             :     }
    1619          40 :     else if (EQUAL(pszBlockStrategy, "HASHSET"))
    1620          40 :         bUseArray = false;
    1621           0 :     else if (!EQUAL(pszBlockStrategy, "ARRAY"))
    1622           0 :         CPLError(CE_Warning, CPLE_AppDefined, "Unknown block cache method: %s",
    1623             :                  pszBlockStrategy);
    1624             : 
    1625       38228 :     if (bUseArray)
    1626       38157 :         poBandBlockCache = GDALArrayBandBlockCacheCreate(this);
    1627             :     else
    1628             :     {
    1629          71 :         if (nBand == 1)
    1630          26 :             CPLDebug("GDAL", "Use hashset band block cache");
    1631          71 :         poBandBlockCache = GDALHashSetBandBlockCacheCreate(this);
    1632             :     }
    1633       38226 :     if (poBandBlockCache == nullptr)
    1634           0 :         return FALSE;
    1635       38226 :     return poBandBlockCache->Init();
    1636             : }
    1637             : 
    1638             : //! @endcond
    1639             : 
    1640             : /************************************************************************/
    1641             : /*                             FlushCache()                             */
    1642             : /************************************************************************/
    1643             : 
    1644             : /**
    1645             :  * \brief Flush raster data cache.
    1646             :  *
    1647             :  * This call will recover memory used to cache data blocks for this raster
    1648             :  * band, and ensure that new requests are referred to the underlying driver.
    1649             :  *
    1650             :  * This method is the same as the C function GDALFlushRasterCache().
    1651             :  *
    1652             :  * @param bAtClosing Whether this is called from a GDALDataset destructor
    1653             :  * @return CE_None on success.
    1654             :  */
    1655             : 
    1656     5098820 : CPLErr GDALRasterBand::FlushCache(bool bAtClosing)
    1657             : 
    1658             : {
    1659     5211740 :     if (bAtClosing && poDS && poDS->IsMarkedSuppressOnClose() &&
    1660      112922 :         poBandBlockCache)
    1661        2446 :         poBandBlockCache->DisableDirtyBlockWriting();
    1662             : 
    1663     5098090 :     CPLErr eGlobalErr = eFlushBlockErr;
    1664             : 
    1665     5098090 :     if (eFlushBlockErr != CE_None)
    1666             :     {
    1667           0 :         ReportError(
    1668             :             eFlushBlockErr, CPLE_AppDefined,
    1669             :             "An error occurred while writing a dirty block from FlushCache");
    1670           0 :         eFlushBlockErr = CE_None;
    1671             :     }
    1672             : 
    1673     5098090 :     if (poBandBlockCache == nullptr || !poBandBlockCache->IsInitOK())
    1674     4932400 :         return eGlobalErr;
    1675             : 
    1676      165684 :     return poBandBlockCache->FlushCache();
    1677             : }
    1678             : 
    1679             : /************************************************************************/
    1680             : /*                        GDALFlushRasterCache()                        */
    1681             : /************************************************************************/
    1682             : 
    1683             : /**
    1684             :  * \brief Flush raster data cache.
    1685             :  *
    1686             :  * @see GDALRasterBand::FlushCache()
    1687             :  */
    1688             : 
    1689         131 : CPLErr CPL_STDCALL GDALFlushRasterCache(GDALRasterBandH hBand)
    1690             : 
    1691             : {
    1692         131 :     VALIDATE_POINTER1(hBand, "GDALFlushRasterCache", CE_Failure);
    1693             : 
    1694         131 :     return GDALRasterBand::FromHandle(hBand)->FlushCache(false);
    1695             : }
    1696             : 
    1697             : /************************************************************************/
    1698             : /*                             DropCache()                              */
    1699             : /************************************************************************/
    1700             : 
    1701             : /**
    1702             : * \brief Drop raster data cache : data in cache will be lost.
    1703             : *
    1704             : * This call will recover memory used to cache data blocks for this raster
    1705             : * band, and ensure that new requests are referred to the underlying driver.
    1706             : *
    1707             : * This method is the same as the C function GDALDropRasterCache().
    1708             : *
    1709             : * @return CE_None on success.
    1710             : * @since 3.9
    1711             : */
    1712             : 
    1713           1 : CPLErr GDALRasterBand::DropCache()
    1714             : 
    1715             : {
    1716           1 :     CPLErr result = CE_None;
    1717             : 
    1718           1 :     if (poBandBlockCache)
    1719           1 :         poBandBlockCache->DisableDirtyBlockWriting();
    1720             : 
    1721           1 :     CPLErr eGlobalErr = eFlushBlockErr;
    1722             : 
    1723           1 :     if (eFlushBlockErr != CE_None)
    1724             :     {
    1725           0 :         ReportError(
    1726             :             eFlushBlockErr, CPLE_AppDefined,
    1727             :             "An error occurred while writing a dirty block from DropCache");
    1728           0 :         eFlushBlockErr = CE_None;
    1729             :     }
    1730             : 
    1731           1 :     if (poBandBlockCache == nullptr || !poBandBlockCache->IsInitOK())
    1732           0 :         result = eGlobalErr;
    1733             :     else
    1734           1 :         result = poBandBlockCache->FlushCache();
    1735             : 
    1736           1 :     if (poBandBlockCache)
    1737           1 :         poBandBlockCache->EnableDirtyBlockWriting();
    1738             : 
    1739           1 :     return result;
    1740             : }
    1741             : 
    1742             : /************************************************************************/
    1743             : /*                        GDALDropRasterCache()                         */
    1744             : /************************************************************************/
    1745             : 
    1746             : /**
    1747             : * \brief Drop raster data cache.
    1748             : *
    1749             : * @see GDALRasterBand::DropCache()
    1750             : * @since 3.9
    1751             : */
    1752             : 
    1753           0 : CPLErr CPL_STDCALL GDALDropRasterCache(GDALRasterBandH hBand)
    1754             : 
    1755             : {
    1756           0 :     VALIDATE_POINTER1(hBand, "GDALDropRasterCache", CE_Failure);
    1757             : 
    1758           0 :     return GDALRasterBand::FromHandle(hBand)->DropCache();
    1759             : }
    1760             : 
    1761             : /************************************************************************/
    1762             : /*                        UnreferenceBlock()                            */
    1763             : /*                                                                      */
    1764             : /*      Unreference the block from our array of blocks                  */
    1765             : /*      This method should only be called by                            */
    1766             : /*      GDALRasterBlock::Internalize() and FlushCacheBlock() (and under */
    1767             : /*      the block cache mutex)                                          */
    1768             : /************************************************************************/
    1769             : 
    1770       29624 : CPLErr GDALRasterBand::UnreferenceBlock(GDALRasterBlock *poBlock)
    1771             : {
    1772             : #ifdef notdef
    1773             :     if (poBandBlockCache == nullptr || !poBandBlockCache->IsInitOK())
    1774             :     {
    1775             :         if (poBandBlockCache == nullptr)
    1776             :             printf("poBandBlockCache == NULL\n"); /*ok*/
    1777             :         else
    1778             :             printf("!poBandBlockCache->IsInitOK()\n"); /*ok*/
    1779             :         printf("caller = %s\n", pszCaller);            /*ok*/
    1780             :         printf("GDALRasterBand: %p\n", this);          /*ok*/
    1781             :         printf("GDALRasterBand: nBand=%d\n", nBand);   /*ok*/
    1782             :         printf("nRasterXSize = %d\n", nRasterXSize);   /*ok*/
    1783             :         printf("nRasterYSize = %d\n", nRasterYSize);   /*ok*/
    1784             :         printf("nBlockXSize = %d\n", nBlockXSize);     /*ok*/
    1785             :         printf("nBlockYSize = %d\n", nBlockYSize);     /*ok*/
    1786             :         poBlock->DumpBlock();
    1787             :         if (GetDataset() != nullptr)
    1788             :             printf("Dataset: %s\n", GetDataset()->GetDescription()); /*ok*/
    1789             :         GDALRasterBlock::Verify();
    1790             :         abort();
    1791             :     }
    1792             : #endif
    1793       29624 :     CPLAssert(poBandBlockCache && poBandBlockCache->IsInitOK());
    1794       29624 :     return poBandBlockCache->UnreferenceBlock(poBlock);
    1795             : }
    1796             : 
    1797             : /************************************************************************/
    1798             : /*                        AddBlockToFreeList()                          */
    1799             : /*                                                                      */
    1800             : /*      When GDALRasterBlock::Internalize() or FlushCacheBlock() are    */
    1801             : /*      finished with a block about to be free'd, they pass it to that  */
    1802             : /*      method.                                                         */
    1803             : /************************************************************************/
    1804             : 
    1805             : //! @cond Doxygen_Suppress
    1806       29624 : void GDALRasterBand::AddBlockToFreeList(GDALRasterBlock *poBlock)
    1807             : {
    1808       29624 :     CPLAssert(poBandBlockCache && poBandBlockCache->IsInitOK());
    1809       29624 :     return poBandBlockCache->AddBlockToFreeList(poBlock);
    1810             : }
    1811             : 
    1812             : //! @endcond
    1813             : 
    1814             : /************************************************************************/
    1815             : /*                             FlushBlock()                             */
    1816             : /************************************************************************/
    1817             : 
    1818             : /** Flush a block out of the block cache.
    1819             :  * @param nXBlockOff block x offset
    1820             :  * @param nYBlockOff blocky offset
    1821             :  * @param bWriteDirtyBlock whether the block should be written to disk if dirty.
    1822             :  * @return CE_None in case of success, an error code otherwise.
    1823             :  */
    1824        2302 : CPLErr GDALRasterBand::FlushBlock(int nXBlockOff, int nYBlockOff,
    1825             :                                   int bWriteDirtyBlock)
    1826             : 
    1827             : {
    1828        2302 :     if (poBandBlockCache == nullptr || !poBandBlockCache->IsInitOK())
    1829           0 :         return (CE_Failure);
    1830             : 
    1831             :     /* -------------------------------------------------------------------- */
    1832             :     /*      Validate the request                                            */
    1833             :     /* -------------------------------------------------------------------- */
    1834        2302 :     if (nXBlockOff < 0 || nXBlockOff >= nBlocksPerRow)
    1835             :     {
    1836           0 :         ReportError(CE_Failure, CPLE_IllegalArg,
    1837             :                     "Illegal nBlockXOff value (%d) in "
    1838             :                     "GDALRasterBand::FlushBlock()\n",
    1839             :                     nXBlockOff);
    1840             : 
    1841           0 :         return (CE_Failure);
    1842             :     }
    1843             : 
    1844        2302 :     if (nYBlockOff < 0 || nYBlockOff >= nBlocksPerColumn)
    1845             :     {
    1846           0 :         ReportError(CE_Failure, CPLE_IllegalArg,
    1847             :                     "Illegal nBlockYOff value (%d) in "
    1848             :                     "GDALRasterBand::FlushBlock()\n",
    1849             :                     nYBlockOff);
    1850             : 
    1851           0 :         return (CE_Failure);
    1852             :     }
    1853             : 
    1854        2302 :     return poBandBlockCache->FlushBlock(nXBlockOff, nYBlockOff,
    1855        2302 :                                         bWriteDirtyBlock);
    1856             : }
    1857             : 
    1858             : /************************************************************************/
    1859             : /*                        TryGetLockedBlockRef()                        */
    1860             : /************************************************************************/
    1861             : 
    1862             : /**
    1863             :  * \brief Try fetching block ref.
    1864             :  *
    1865             :  * This method will returned the requested block (locked) if it is already
    1866             :  * in the block cache for the layer.  If not, nullptr is returned.
    1867             :  *
    1868             :  * If a non-NULL value is returned, then a lock for the block will have been
    1869             :  * acquired on behalf of the caller.  It is absolutely imperative that the
    1870             :  * caller release this lock (with GDALRasterBlock::DropLock()) or else
    1871             :  * severe problems may result.
    1872             :  *
    1873             :  * @param nXBlockOff the horizontal block offset, with zero indicating
    1874             :  * the left most block, 1 the next block and so forth.
    1875             :  *
    1876             :  * @param nYBlockOff the vertical block offset, with zero indicating
    1877             :  * the top most block, 1 the next block and so forth.
    1878             :  *
    1879             :  * @return NULL if block not available, or locked block pointer.
    1880             :  */
    1881             : 
    1882    10328000 : GDALRasterBlock *GDALRasterBand::TryGetLockedBlockRef(int nXBlockOff,
    1883             :                                                       int nYBlockOff)
    1884             : 
    1885             : {
    1886    10328000 :     if (poBandBlockCache == nullptr || !poBandBlockCache->IsInitOK())
    1887       70766 :         return nullptr;
    1888             : 
    1889             :     /* -------------------------------------------------------------------- */
    1890             :     /*      Validate the request                                            */
    1891             :     /* -------------------------------------------------------------------- */
    1892    10257200 :     if (nXBlockOff < 0 || nXBlockOff >= nBlocksPerRow)
    1893             :     {
    1894          21 :         ReportError(CE_Failure, CPLE_IllegalArg,
    1895             :                     "Illegal nBlockXOff value (%d) in "
    1896             :                     "GDALRasterBand::TryGetLockedBlockRef()\n",
    1897             :                     nXBlockOff);
    1898             : 
    1899           0 :         return (nullptr);
    1900             :     }
    1901             : 
    1902    10257200 :     if (nYBlockOff < 0 || nYBlockOff >= nBlocksPerColumn)
    1903             :     {
    1904           0 :         ReportError(CE_Failure, CPLE_IllegalArg,
    1905             :                     "Illegal nBlockYOff value (%d) in "
    1906             :                     "GDALRasterBand::TryGetLockedBlockRef()\n",
    1907             :                     nYBlockOff);
    1908             : 
    1909           0 :         return (nullptr);
    1910             :     }
    1911             : 
    1912    10257200 :     return poBandBlockCache->TryGetLockedBlockRef(nXBlockOff, nYBlockOff);
    1913             : }
    1914             : 
    1915             : /************************************************************************/
    1916             : /*                         GetLockedBlockRef()                          */
    1917             : /************************************************************************/
    1918             : 
    1919             : /**
    1920             :  * \brief Fetch a pointer to an internally cached raster block.
    1921             :  *
    1922             :  * This method will returned the requested block (locked) if it is already
    1923             :  * in the block cache for the layer.  If not, the block will be read from
    1924             :  * the driver, and placed in the layer block cached, then returned.  If an
    1925             :  * error occurs reading the block from the driver, a NULL value will be
    1926             :  * returned.
    1927             :  *
    1928             :  * If a non-NULL value is returned, then a lock for the block will have been
    1929             :  * acquired on behalf of the caller.  It is absolutely imperative that the
    1930             :  * caller release this lock (with GDALRasterBlock::DropLock()) or else
    1931             :  * severe problems may result.
    1932             :  *
    1933             :  * Note that calling GetLockedBlockRef() on a previously uncached band will
    1934             :  * enable caching.
    1935             :  *
    1936             :  * @param nXBlockOff the horizontal block offset, with zero indicating
    1937             :  * the left most block, 1 the next block and so forth.
    1938             :  *
    1939             :  * @param nYBlockOff the vertical block offset, with zero indicating
    1940             :  * the top most block, 1 the next block and so forth.
    1941             :  *
    1942             :  * @param bJustInitialize If TRUE the block will be allocated and initialized,
    1943             :  * but not actually read from the source.  This is useful when it will just
    1944             :  * be completely set and written back.
    1945             :  *
    1946             :  * @return pointer to the block object, or NULL on failure.
    1947             :  */
    1948             : 
    1949    10125100 : GDALRasterBlock *GDALRasterBand::GetLockedBlockRef(int nXBlockOff,
    1950             :                                                    int nYBlockOff,
    1951             :                                                    int bJustInitialize)
    1952             : 
    1953             : {
    1954             :     /* -------------------------------------------------------------------- */
    1955             :     /*      Try and fetch from cache.                                       */
    1956             :     /* -------------------------------------------------------------------- */
    1957    10125100 :     GDALRasterBlock *poBlock = TryGetLockedBlockRef(nXBlockOff, nYBlockOff);
    1958             : 
    1959             :     /* -------------------------------------------------------------------- */
    1960             :     /*      If we didn't find it in our memory cache, instantiate a         */
    1961             :     /*      block (potentially load from disk) and "adopt" it into the      */
    1962             :     /*      cache.                                                          */
    1963             :     /* -------------------------------------------------------------------- */
    1964    10125200 :     if (poBlock == nullptr)
    1965             :     {
    1966     3163330 :         if (!InitBlockInfo())
    1967           0 :             return (nullptr);
    1968             : 
    1969             :         /* --------------------------------------------------------------------
    1970             :          */
    1971             :         /*      Validate the request */
    1972             :         /* --------------------------------------------------------------------
    1973             :          */
    1974     3163330 :         if (nXBlockOff < 0 || nXBlockOff >= nBlocksPerRow)
    1975             :         {
    1976           7 :             ReportError(CE_Failure, CPLE_IllegalArg,
    1977             :                         "Illegal nBlockXOff value (%d) in "
    1978             :                         "GDALRasterBand::GetLockedBlockRef()\n",
    1979             :                         nXBlockOff);
    1980             : 
    1981           0 :             return (nullptr);
    1982             :         }
    1983             : 
    1984     3163330 :         if (nYBlockOff < 0 || nYBlockOff >= nBlocksPerColumn)
    1985             :         {
    1986           5 :             ReportError(CE_Failure, CPLE_IllegalArg,
    1987             :                         "Illegal nBlockYOff value (%d) in "
    1988             :                         "GDALRasterBand::GetLockedBlockRef()\n",
    1989             :                         nYBlockOff);
    1990             : 
    1991           0 :             return (nullptr);
    1992             :         }
    1993             : 
    1994     3163320 :         poBlock = poBandBlockCache->CreateBlock(nXBlockOff, nYBlockOff);
    1995     3163320 :         if (poBlock == nullptr)
    1996           0 :             return nullptr;
    1997             : 
    1998     3163320 :         poBlock->AddLock();
    1999             : 
    2000             :         /* We need to temporarily drop the read-write lock in the following */
    2001             :         /*scenario. Imagine 2 threads T1 and T2 that respectively write dataset
    2002             :          */
    2003             :         /* D1 and D2. T1 will take the mutex on D1 and T2 on D2. Now when the */
    2004             :         /* block cache fills, T1 might need to flush dirty blocks of D2 in the
    2005             :          */
    2006             :         /* below Internalize(), which will cause GDALRasterBlock::Write() to be
    2007             :          */
    2008             :         /* called and attempt at taking the lock on T2 (already taken).
    2009             :          * Similarly */
    2010             :         /* for T2 with D1, hence a deadlock situation (#6163) */
    2011             :         /* But this may open the door to other problems... */
    2012     3163330 :         if (poDS)
    2013     3162590 :             poDS->TemporarilyDropReadWriteLock();
    2014             :         /* allocate data space */
    2015     3163330 :         CPLErr eErr = poBlock->Internalize();
    2016     3163350 :         if (poDS)
    2017     3162610 :             poDS->ReacquireReadWriteLock();
    2018     3163340 :         if (eErr != CE_None)
    2019             :         {
    2020           0 :             poBlock->DropLock();
    2021           0 :             delete poBlock;
    2022           0 :             return nullptr;
    2023             :         }
    2024             : 
    2025     3163340 :         if (poBandBlockCache->AdoptBlock(poBlock) != CE_None)
    2026             :         {
    2027           0 :             poBlock->DropLock();
    2028           0 :             delete poBlock;
    2029           0 :             return nullptr;
    2030             :         }
    2031             : 
    2032     3163330 :         if (!bJustInitialize)
    2033             :         {
    2034     2807260 :             const GUInt32 nErrorCounter = CPLGetErrorCounter();
    2035     2807260 :             int bCallLeaveReadWrite = EnterReadWrite(GF_Read);
    2036     2807270 :             eErr = IReadBlock(nXBlockOff, nYBlockOff, poBlock->GetDataRef());
    2037     2807280 :             if (bCallLeaveReadWrite)
    2038      129950 :                 LeaveReadWrite();
    2039     2807270 :             if (eErr != CE_None)
    2040             :             {
    2041        1152 :                 poBlock->DropLock();
    2042        1152 :                 FlushBlock(nXBlockOff, nYBlockOff);
    2043        1152 :                 ReportError(CE_Failure, CPLE_AppDefined,
    2044             :                             "IReadBlock failed at X offset %d, Y offset %d%s",
    2045             :                             nXBlockOff, nYBlockOff,
    2046        1152 :                             (nErrorCounter != CPLGetErrorCounter())
    2047        1150 :                                 ? CPLSPrintf(": %s", CPLGetLastErrorMsg())
    2048             :                                 : "");
    2049        1152 :                 return nullptr;
    2050             :             }
    2051             : 
    2052     2806120 :             nBlockReads++;
    2053     2806120 :             if (static_cast<GIntBig>(nBlockReads) ==
    2054     2806120 :                     static_cast<GIntBig>(nBlocksPerRow) * nBlocksPerColumn +
    2055         216 :                         1 &&
    2056         216 :                 nBand == 1 && poDS != nullptr)
    2057             :             {
    2058         156 :                 CPLDebug("GDAL", "Potential thrashing on band %d of %s.", nBand,
    2059         156 :                          poDS->GetDescription());
    2060             :             }
    2061             :         }
    2062             :     }
    2063             : 
    2064    10124100 :     return poBlock;
    2065             : }
    2066             : 
    2067             : /************************************************************************/
    2068             : /*                               Fill()                                 */
    2069             : /************************************************************************/
    2070             : 
    2071             : /**
    2072             :  * \brief Fill this band with a constant value.
    2073             :  *
    2074             :  * GDAL makes no guarantees
    2075             :  * about what values pixels in newly created files are set to, so this
    2076             :  * method can be used to clear a band to a specified "default" value.
    2077             :  * The fill value is passed in as a double but this will be converted
    2078             :  * to the underlying type before writing to the file. An optional
    2079             :  * second argument allows the imaginary component of a complex
    2080             :  * constant value to be specified.
    2081             :  *
    2082             :  * This method is the same as the C function GDALFillRaster().
    2083             :  *
    2084             :  * @param dfRealValue Real component of fill value
    2085             :  * @param dfImaginaryValue Imaginary component of fill value, defaults to zero
    2086             :  *
    2087             :  * @return CE_Failure if the write fails, otherwise CE_None
    2088             :  */
    2089      169562 : CPLErr GDALRasterBand::Fill(double dfRealValue, double dfImaginaryValue)
    2090             : {
    2091             : 
    2092             :     // General approach is to construct a source block of the file's
    2093             :     // native type containing the appropriate value and then copy this
    2094             :     // to each block in the image via the RasterBlock cache. Using
    2095             :     // the cache means we avoid file I/O if it is not necessary, at the
    2096             :     // expense of some extra memcpy's (since we write to the
    2097             :     // RasterBlock cache, which is then at some point written to the
    2098             :     // underlying file, rather than simply directly to the underlying
    2099             :     // file.)
    2100             : 
    2101             :     // Check we can write to the file.
    2102      169562 :     if (EmitErrorMessageIfWriteNotSupported("GDALRasterBand::Fill()"))
    2103             :     {
    2104           6 :         return CE_Failure;
    2105             :     }
    2106             : 
    2107             :     // Make sure block parameters are set.
    2108      169556 :     if (!InitBlockInfo())
    2109           0 :         return CE_Failure;
    2110             : 
    2111             :     // Allocate the source block.
    2112      169556 :     auto blockSize = static_cast<GPtrDiff_t>(nBlockXSize) * nBlockYSize;
    2113      169556 :     int elementSize = GDALGetDataTypeSizeBytes(eDataType);
    2114      169556 :     auto blockByteSize = blockSize * elementSize;
    2115             :     unsigned char *srcBlock =
    2116      169556 :         static_cast<unsigned char *>(VSIMalloc(blockByteSize));
    2117      169556 :     if (srcBlock == nullptr)
    2118             :     {
    2119           0 :         ReportError(CE_Failure, CPLE_OutOfMemory,
    2120             :                     "GDALRasterBand::Fill(): Out of memory "
    2121             :                     "allocating " CPL_FRMT_GUIB " bytes.\n",
    2122             :                     static_cast<GUIntBig>(blockByteSize));
    2123           0 :         return CE_Failure;
    2124             :     }
    2125             : 
    2126             :     // Initialize the source block.
    2127      169556 :     double complexSrc[2] = {dfRealValue, dfImaginaryValue};
    2128      169556 :     GDALCopyWords64(complexSrc, GDT_CFloat64, 0, srcBlock, eDataType,
    2129             :                     elementSize, blockSize);
    2130             : 
    2131      169556 :     const bool bCallLeaveReadWrite = CPL_TO_BOOL(EnterReadWrite(GF_Write));
    2132             : 
    2133             :     // Write block to block cache
    2134      651159 :     for (int j = 0; j < nBlocksPerColumn; ++j)
    2135             :     {
    2136     1257540 :         for (int i = 0; i < nBlocksPerRow; ++i)
    2137             :         {
    2138      775936 :             GDALRasterBlock *destBlock = GetLockedBlockRef(i, j, TRUE);
    2139      775936 :             if (destBlock == nullptr)
    2140             :             {
    2141           0 :                 ReportError(CE_Failure, CPLE_OutOfMemory,
    2142             :                             "GDALRasterBand::Fill(): Error "
    2143             :                             "while retrieving cache block.");
    2144           0 :                 VSIFree(srcBlock);
    2145           0 :                 return CE_Failure;
    2146             :             }
    2147      775936 :             memcpy(destBlock->GetDataRef(), srcBlock, blockByteSize);
    2148      775936 :             destBlock->MarkDirty();
    2149      775936 :             destBlock->DropLock();
    2150             :         }
    2151             :     }
    2152             : 
    2153      169556 :     if (bCallLeaveReadWrite)
    2154      168981 :         LeaveReadWrite();
    2155             : 
    2156             :     // Free up the source block
    2157      169556 :     VSIFree(srcBlock);
    2158             : 
    2159      169556 :     return CE_None;
    2160             : }
    2161             : 
    2162             : /************************************************************************/
    2163             : /*                         GDALFillRaster()                             */
    2164             : /************************************************************************/
    2165             : 
    2166             : /**
    2167             :  * \brief Fill this band with a constant value.
    2168             :  *
    2169             :  * @see GDALRasterBand::Fill()
    2170             :  */
    2171      169504 : CPLErr CPL_STDCALL GDALFillRaster(GDALRasterBandH hBand, double dfRealValue,
    2172             :                                   double dfImaginaryValue)
    2173             : {
    2174      169504 :     VALIDATE_POINTER1(hBand, "GDALFillRaster", CE_Failure);
    2175             : 
    2176      169504 :     GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
    2177      169504 :     return poBand->Fill(dfRealValue, dfImaginaryValue);
    2178             : }
    2179             : 
    2180             : /************************************************************************/
    2181             : /*                             GetAccess()                              */
    2182             : /************************************************************************/
    2183             : 
    2184             : /**
    2185             :  * \brief Find out if we have update permission for this band.
    2186             :  *
    2187             :  * This method is the same as the C function GDALGetRasterAccess().
    2188             :  *
    2189             :  * @return Either GA_Update or GA_ReadOnly.
    2190             :  */
    2191             : 
    2192        3000 : GDALAccess GDALRasterBand::GetAccess()
    2193             : 
    2194             : {
    2195        3000 :     return eAccess;
    2196             : }
    2197             : 
    2198             : /************************************************************************/
    2199             : /*                        GDALGetRasterAccess()                         */
    2200             : /************************************************************************/
    2201             : 
    2202             : /**
    2203             :  * \brief Find out if we have update permission for this band.
    2204             :  *
    2205             :  * @see GDALRasterBand::GetAccess()
    2206             :  */
    2207             : 
    2208        2352 : GDALAccess CPL_STDCALL GDALGetRasterAccess(GDALRasterBandH hBand)
    2209             : 
    2210             : {
    2211        2352 :     VALIDATE_POINTER1(hBand, "GDALGetRasterAccess", GA_ReadOnly);
    2212             : 
    2213        2352 :     GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
    2214        2352 :     return poBand->GetAccess();
    2215             : }
    2216             : 
    2217             : /************************************************************************/
    2218             : /*                          GetCategoryNames()                          */
    2219             : /************************************************************************/
    2220             : 
    2221             : /**
    2222             :  * \brief Fetch the list of category names for this raster.
    2223             :  *
    2224             :  * The return list is a "StringList" in the sense of the CPL functions.
    2225             :  * That is a NULL terminated array of strings.  Raster values without
    2226             :  * associated names will have an empty string in the returned list.  The
    2227             :  * first entry in the list is for raster values of zero, and so on.
    2228             :  *
    2229             :  * The returned stringlist should not be altered or freed by the application.
    2230             :  * It may change on the next GDAL call, so please copy it if it is needed
    2231             :  * for any period of time.
    2232             :  *
    2233             :  * This method is the same as the C function GDALGetRasterCategoryNames().
    2234             :  *
    2235             :  * @return list of names, or NULL if none.
    2236             :  */
    2237             : 
    2238         294 : char **GDALRasterBand::GetCategoryNames()
    2239             : 
    2240             : {
    2241         294 :     return nullptr;
    2242             : }
    2243             : 
    2244             : /************************************************************************/
    2245             : /*                     GDALGetRasterCategoryNames()                     */
    2246             : /************************************************************************/
    2247             : 
    2248             : /**
    2249             :  * \brief Fetch the list of category names for this raster.
    2250             :  *
    2251             :  * @see GDALRasterBand::GetCategoryNames()
    2252             :  */
    2253             : 
    2254         183 : char **CPL_STDCALL GDALGetRasterCategoryNames(GDALRasterBandH hBand)
    2255             : 
    2256             : {
    2257         183 :     VALIDATE_POINTER1(hBand, "GDALGetRasterCategoryNames", nullptr);
    2258             : 
    2259         183 :     GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
    2260         183 :     return poBand->GetCategoryNames();
    2261             : }
    2262             : 
    2263             : /************************************************************************/
    2264             : /*                          SetCategoryNames()                          */
    2265             : /************************************************************************/
    2266             : 
    2267             : /**
    2268             :  * \fn GDALRasterBand::SetCategoryNames(char**)
    2269             :  * \brief Set the category names for this band.
    2270             :  *
    2271             :  * See the GetCategoryNames() method for more on the interpretation of
    2272             :  * category names.
    2273             :  *
    2274             :  * This method is the same as the C function GDALSetRasterCategoryNames().
    2275             :  *
    2276             :  * @param papszNames the NULL terminated StringList of category names.  May
    2277             :  * be NULL to just clear the existing list.
    2278             :  *
    2279             :  * @return CE_None on success of CE_Failure on failure.  If unsupported
    2280             :  * by the driver CE_Failure is returned, but no error message is reported.
    2281             :  */
    2282             : 
    2283             : /**/
    2284             : /**/
    2285             : 
    2286           0 : CPLErr GDALRasterBand::SetCategoryNames(char ** /*papszNames*/)
    2287             : {
    2288           0 :     if (!(GetMOFlags() & GMO_IGNORE_UNIMPLEMENTED))
    2289           0 :         ReportError(CE_Failure, CPLE_NotSupported,
    2290             :                     "SetCategoryNames() not supported for this dataset.");
    2291             : 
    2292           0 :     return CE_Failure;
    2293             : }
    2294             : 
    2295             : /************************************************************************/
    2296             : /*                        GDALSetCategoryNames()                        */
    2297             : /************************************************************************/
    2298             : 
    2299             : /**
    2300             :  * \brief Set the category names for this band.
    2301             :  *
    2302             :  * @see GDALRasterBand::SetCategoryNames()
    2303             :  */
    2304             : 
    2305           2 : CPLErr CPL_STDCALL GDALSetRasterCategoryNames(GDALRasterBandH hBand,
    2306             :                                               CSLConstList papszNames)
    2307             : 
    2308             : {
    2309           2 :     VALIDATE_POINTER1(hBand, "GDALSetRasterCategoryNames", CE_Failure);
    2310             : 
    2311           2 :     GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
    2312           2 :     return poBand->SetCategoryNames(const_cast<char **>(papszNames));
    2313             : }
    2314             : 
    2315             : /************************************************************************/
    2316             : /*                           GetNoDataValue()                           */
    2317             : /************************************************************************/
    2318             : 
    2319             : /**
    2320             :  * \brief Fetch the no data value for this band.
    2321             :  *
    2322             :  * If there is no out of data value, an out of range value will generally
    2323             :  * be returned.  The no data value for a band is generally a special marker
    2324             :  * value used to mark pixels that are not valid data.  Such pixels should
    2325             :  * generally not be displayed, nor contribute to analysis operations.
    2326             :  *
    2327             :  * The no data value returned is 'raw', meaning that it has no offset and
    2328             :  * scale applied.
    2329             :  *
    2330             :  * For rasters of type GDT_Int64 or GDT_UInt64, using this method might be
    2331             :  * lossy if the nodata value cannot exactly been represented by a double.
    2332             :  * Use GetNoDataValueAsInt64() or GetNoDataValueAsUInt64() instead.
    2333             :  *
    2334             :  * This method is the same as the C function GDALGetRasterNoDataValue().
    2335             :  *
    2336             :  * @param pbSuccess pointer to a boolean to use to indicate if a value
    2337             :  * is actually associated with this layer.  May be NULL (default).
    2338             :  *
    2339             :  * @return the nodata value for this band.
    2340             :  */
    2341             : 
    2342       31580 : double GDALRasterBand::GetNoDataValue(int *pbSuccess)
    2343             : 
    2344             : {
    2345       31580 :     if (pbSuccess != nullptr)
    2346       31580 :         *pbSuccess = FALSE;
    2347             : 
    2348       31580 :     return -1e10;
    2349             : }
    2350             : 
    2351             : /************************************************************************/
    2352             : /*                      GDALGetRasterNoDataValue()                      */
    2353             : /************************************************************************/
    2354             : 
    2355             : /**
    2356             :  * \brief Fetch the no data value for this band.
    2357             :  *
    2358             :  * @see GDALRasterBand::GetNoDataValue()
    2359             :  */
    2360             : 
    2361      414194 : double CPL_STDCALL GDALGetRasterNoDataValue(GDALRasterBandH hBand,
    2362             :                                             int *pbSuccess)
    2363             : 
    2364             : {
    2365      414194 :     VALIDATE_POINTER1(hBand, "GDALGetRasterNoDataValue", 0);
    2366             : 
    2367      414194 :     GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
    2368      414194 :     return poBand->GetNoDataValue(pbSuccess);
    2369             : }
    2370             : 
    2371             : /************************************************************************/
    2372             : /*                       GetNoDataValueAsInt64()                        */
    2373             : /************************************************************************/
    2374             : 
    2375             : /**
    2376             :  * \brief Fetch the no data value for this band.
    2377             :  *
    2378             :  * This method should ONLY be called on rasters whose data type is GDT_Int64.
    2379             :  *
    2380             :  * If there is no out of data value, an out of range value will generally
    2381             :  * be returned.  The no data value for a band is generally a special marker
    2382             :  * value used to mark pixels that are not valid data.  Such pixels should
    2383             :  * generally not be displayed, nor contribute to analysis operations.
    2384             :  *
    2385             :  * The no data value returned is 'raw', meaning that it has no offset and
    2386             :  * scale applied.
    2387             :  *
    2388             :  * This method is the same as the C function GDALGetRasterNoDataValueAsInt64().
    2389             :  *
    2390             :  * @param pbSuccess pointer to a boolean to use to indicate if a value
    2391             :  * is actually associated with this layer.  May be NULL (default).
    2392             :  *
    2393             :  * @return the nodata value for this band.
    2394             :  *
    2395             :  * @since GDAL 3.5
    2396             :  */
    2397             : 
    2398           4 : int64_t GDALRasterBand::GetNoDataValueAsInt64(int *pbSuccess)
    2399             : 
    2400             : {
    2401           4 :     if (pbSuccess != nullptr)
    2402           4 :         *pbSuccess = FALSE;
    2403             : 
    2404           4 :     return std::numeric_limits<int64_t>::min();
    2405             : }
    2406             : 
    2407             : /************************************************************************/
    2408             : /*                   GDALGetRasterNoDataValueAsInt64()                  */
    2409             : /************************************************************************/
    2410             : 
    2411             : /**
    2412             :  * \brief Fetch the no data value for this band.
    2413             :  *
    2414             :  * This function should ONLY be called on rasters whose data type is GDT_Int64.
    2415             :  *
    2416             :  * @see GDALRasterBand::GetNoDataValueAsInt64()
    2417             :  *
    2418             :  * @since GDAL 3.5
    2419             :  */
    2420             : 
    2421          27 : int64_t CPL_STDCALL GDALGetRasterNoDataValueAsInt64(GDALRasterBandH hBand,
    2422             :                                                     int *pbSuccess)
    2423             : 
    2424             : {
    2425          27 :     VALIDATE_POINTER1(hBand, "GDALGetRasterNoDataValueAsInt64",
    2426             :                       std::numeric_limits<int64_t>::min());
    2427             : 
    2428          27 :     GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
    2429          27 :     return poBand->GetNoDataValueAsInt64(pbSuccess);
    2430             : }
    2431             : 
    2432             : /************************************************************************/
    2433             : /*                       GetNoDataValueAsUInt64()                        */
    2434             : /************************************************************************/
    2435             : 
    2436             : /**
    2437             :  * \brief Fetch the no data value for this band.
    2438             :  *
    2439             :  * This method should ONLY be called on rasters whose data type is GDT_UInt64.
    2440             :  *
    2441             :  * If there is no out of data value, an out of range value will generally
    2442             :  * be returned.  The no data value for a band is generally a special marker
    2443             :  * value used to mark pixels that are not valid data.  Such pixels should
    2444             :  * generally not be displayed, nor contribute to analysis operations.
    2445             :  *
    2446             :  * The no data value returned is 'raw', meaning that it has no offset and
    2447             :  * scale applied.
    2448             :  *
    2449             :  * This method is the same as the C function GDALGetRasterNoDataValueAsUInt64().
    2450             :  *
    2451             :  * @param pbSuccess pointer to a boolean to use to indicate if a value
    2452             :  * is actually associated with this layer.  May be NULL (default).
    2453             :  *
    2454             :  * @return the nodata value for this band.
    2455             :  *
    2456             :  * @since GDAL 3.5
    2457             :  */
    2458             : 
    2459           3 : uint64_t GDALRasterBand::GetNoDataValueAsUInt64(int *pbSuccess)
    2460             : 
    2461             : {
    2462           3 :     if (pbSuccess != nullptr)
    2463           3 :         *pbSuccess = FALSE;
    2464             : 
    2465           3 :     return std::numeric_limits<uint64_t>::max();
    2466             : }
    2467             : 
    2468             : /************************************************************************/
    2469             : /*                   GDALGetRasterNoDataValueAsUInt64()                  */
    2470             : /************************************************************************/
    2471             : 
    2472             : /**
    2473             :  * \brief Fetch the no data value for this band.
    2474             :  *
    2475             :  * This function should ONLY be called on rasters whose data type is GDT_UInt64.
    2476             :  *
    2477             :  * @see GDALRasterBand::GetNoDataValueAsUInt64()
    2478             :  *
    2479             :  * @since GDAL 3.5
    2480             :  */
    2481             : 
    2482          18 : uint64_t CPL_STDCALL GDALGetRasterNoDataValueAsUInt64(GDALRasterBandH hBand,
    2483             :                                                       int *pbSuccess)
    2484             : 
    2485             : {
    2486          18 :     VALIDATE_POINTER1(hBand, "GDALGetRasterNoDataValueAsUInt64",
    2487             :                       std::numeric_limits<uint64_t>::max());
    2488             : 
    2489          18 :     GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
    2490          18 :     return poBand->GetNoDataValueAsUInt64(pbSuccess);
    2491             : }
    2492             : 
    2493             : /************************************************************************/
    2494             : /*                        SetNoDataValueAsString()                      */
    2495             : /************************************************************************/
    2496             : 
    2497             : /**
    2498             :  * \brief Set the no data value for this band.
    2499             :  *
    2500             :  * Depending on drivers, changing the no data value may or may not have an
    2501             :  * effect on the pixel values of a raster that has just been created. It is
    2502             :  * thus advised to explicitly called Fill() if the intent is to initialize
    2503             :  * the raster to the nodata value.
    2504             :  * In any case, changing an existing no data value, when one already exists and
    2505             :  * the dataset exists or has been initialized, has no effect on the pixel whose
    2506             :  * value matched the previous nodata value.
    2507             :  *
    2508             :  * To clear the nodata value, use DeleteNoDataValue().
    2509             :  *
    2510             :  * @param pszNoData the value to set.
    2511             :  * @param[out] pbCannotBeExactlyRepresented Pointer to a boolean, or nullptr.
    2512             :  *             If the value cannot be exactly represented on the output data
    2513             :  *             type, *pbCannotBeExactlyRepresented will be set to true.
    2514             :  *
    2515             :  * @return CE_None on success, or CE_Failure on failure.  If unsupported
    2516             :  * by the driver, CE_Failure is returned but no error message will have
    2517             :  * been emitted.
    2518             :  *
    2519             :  * @since 3.11
    2520             :  */
    2521             : 
    2522             : CPLErr
    2523         122 : GDALRasterBand::SetNoDataValueAsString(const char *pszNoData,
    2524             :                                        bool *pbCannotBeExactlyRepresented)
    2525             : {
    2526         122 :     if (pbCannotBeExactlyRepresented)
    2527         122 :         *pbCannotBeExactlyRepresented = false;
    2528         122 :     if (eDataType == GDT_Int64)
    2529             :     {
    2530           8 :         if (strchr(pszNoData, '.') ||
    2531           3 :             CPLGetValueType(pszNoData) == CPL_VALUE_STRING)
    2532             :         {
    2533           2 :             char *endptr = nullptr;
    2534           2 :             const double dfVal = CPLStrtod(pszNoData, &endptr);
    2535           4 :             if (endptr == pszNoData + strlen(pszNoData) &&
    2536           2 :                 GDALIsValueExactAs<int64_t>(dfVal))
    2537             :             {
    2538           0 :                 return SetNoDataValueAsInt64(static_cast<int64_t>(dfVal));
    2539             :             }
    2540             :         }
    2541             :         else
    2542             :         {
    2543             :             try
    2544             :             {
    2545           7 :                 const auto val = std::stoll(pszNoData);
    2546           1 :                 return SetNoDataValueAsInt64(static_cast<int64_t>(val));
    2547             :             }
    2548           2 :             catch (const std::exception &)
    2549             :             {
    2550             :             }
    2551             :         }
    2552             :     }
    2553         117 :     else if (eDataType == GDT_UInt64)
    2554             :     {
    2555           2 :         if (strchr(pszNoData, '.') ||
    2556           1 :             CPLGetValueType(pszNoData) == CPL_VALUE_STRING)
    2557             :         {
    2558           0 :             char *endptr = nullptr;
    2559           0 :             const double dfVal = CPLStrtod(pszNoData, &endptr);
    2560           0 :             if (endptr == pszNoData + strlen(pszNoData) &&
    2561           0 :                 GDALIsValueExactAs<uint64_t>(dfVal))
    2562             :             {
    2563           0 :                 return SetNoDataValueAsUInt64(static_cast<uint64_t>(dfVal));
    2564             :             }
    2565             :         }
    2566             :         else
    2567             :         {
    2568             :             try
    2569             :             {
    2570           1 :                 const auto val = std::stoull(pszNoData);
    2571           1 :                 return SetNoDataValueAsUInt64(static_cast<uint64_t>(val));
    2572             :             }
    2573           0 :             catch (const std::exception &)
    2574             :             {
    2575             :             }
    2576             :         }
    2577             :     }
    2578         116 :     else if (eDataType == GDT_Float32)
    2579             :     {
    2580          10 :         char *endptr = nullptr;
    2581          10 :         const float fVal = CPLStrtof(pszNoData, &endptr);
    2582          10 :         if (endptr == pszNoData + strlen(pszNoData))
    2583             :         {
    2584          10 :             return SetNoDataValue(fVal);
    2585             :         }
    2586             :     }
    2587             :     else
    2588             :     {
    2589         106 :         char *endptr = nullptr;
    2590         106 :         const double dfVal = CPLStrtod(pszNoData, &endptr);
    2591         212 :         if (endptr == pszNoData + strlen(pszNoData) &&
    2592         106 :             GDALIsValueExactAs(dfVal, eDataType))
    2593             :         {
    2594         105 :             return SetNoDataValue(dfVal);
    2595             :         }
    2596             :     }
    2597           5 :     if (pbCannotBeExactlyRepresented)
    2598           5 :         *pbCannotBeExactlyRepresented = true;
    2599           5 :     return CE_Failure;
    2600             : }
    2601             : 
    2602             : /************************************************************************/
    2603             : /*                           SetNoDataValue()                           */
    2604             : /************************************************************************/
    2605             : 
    2606             : /**
    2607             :  * \fn GDALRasterBand::SetNoDataValue(double)
    2608             :  * \brief Set the no data value for this band.
    2609             :  *
    2610             :  * Depending on drivers, changing the no data value may or may not have an
    2611             :  * effect on the pixel values of a raster that has just been created. It is
    2612             :  * thus advised to explicitly called Fill() if the intent is to initialize
    2613             :  * the raster to the nodata value.
    2614             :  * In any case, changing an existing no data value, when one already exists and
    2615             :  * the dataset exists or has been initialized, has no effect on the pixel whose
    2616             :  * value matched the previous nodata value.
    2617             :  *
    2618             :  * For rasters of type GDT_Int64 or GDT_UInt64, whose nodata value cannot always
    2619             :  * be represented by a double, use SetNoDataValueAsInt64() or
    2620             :  * SetNoDataValueAsUInt64() instead.
    2621             :  *
    2622             :  * To clear the nodata value, use DeleteNoDataValue().
    2623             :  *
    2624             :  * This method is the same as the C function GDALSetRasterNoDataValue().
    2625             :  *
    2626             :  * @param dfNoData the value to set.
    2627             :  *
    2628             :  * @return CE_None on success, or CE_Failure on failure.  If unsupported
    2629             :  * by the driver, CE_Failure is returned but no error message will have
    2630             :  * been emitted.
    2631             :  */
    2632             : 
    2633             : /**/
    2634             : /**/
    2635             : 
    2636           0 : CPLErr GDALRasterBand::SetNoDataValue(double /*dfNoData*/)
    2637             : 
    2638             : {
    2639           0 :     if (!(GetMOFlags() & GMO_IGNORE_UNIMPLEMENTED))
    2640           0 :         ReportError(CE_Failure, CPLE_NotSupported,
    2641             :                     "SetNoDataValue() not supported for this dataset.");
    2642             : 
    2643           0 :     return CE_Failure;
    2644             : }
    2645             : 
    2646             : /************************************************************************/
    2647             : /*                         GDALSetRasterNoDataValue()                   */
    2648             : /************************************************************************/
    2649             : 
    2650             : /**
    2651             :  * \brief Set the no data value for this band.
    2652             :  *
    2653             :  * Depending on drivers, changing the no data value may or may not have an
    2654             :  * effect on the pixel values of a raster that has just been created. It is
    2655             :  * thus advised to explicitly called Fill() if the intent is to initialize
    2656             :  * the raster to the nodata value.
    2657             :  * In any case, changing an existing no data value, when one already exists and
    2658             :  * the dataset exists or has been initialized, has no effect on the pixel whose
    2659             :  * value matched the previous nodata value.
    2660             :  *
    2661             :  * For rasters of type GDT_Int64 or GDT_UInt64, whose nodata value cannot always
    2662             :  * be represented by a double, use GDALSetRasterNoDataValueAsInt64() or
    2663             :  * GDALSetRasterNoDataValueAsUInt64() instead.
    2664             :  *
    2665             :  * @see GDALRasterBand::SetNoDataValue()
    2666             :  */
    2667             : 
    2668         825 : CPLErr CPL_STDCALL GDALSetRasterNoDataValue(GDALRasterBandH hBand,
    2669             :                                             double dfValue)
    2670             : 
    2671             : {
    2672         825 :     VALIDATE_POINTER1(hBand, "GDALSetRasterNoDataValue", CE_Failure);
    2673             : 
    2674         825 :     GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
    2675         825 :     return poBand->SetNoDataValue(dfValue);
    2676             : }
    2677             : 
    2678             : /************************************************************************/
    2679             : /*                       SetNoDataValueAsInt64()                        */
    2680             : /************************************************************************/
    2681             : 
    2682             : /**
    2683             :  * \brief Set the no data value for this band.
    2684             :  *
    2685             :  * This method should ONLY be called on rasters whose data type is GDT_Int64.
    2686             :  *
    2687             :  * Depending on drivers, changing the no data value may or may not have an
    2688             :  * effect on the pixel values of a raster that has just been created. It is
    2689             :  * thus advised to explicitly called Fill() if the intent is to initialize
    2690             :  * the raster to the nodata value.
    2691             :  * In ay case, changing an existing no data value, when one already exists and
    2692             :  * the dataset exists or has been initialized, has no effect on the pixel whose
    2693             :  * value matched the previous nodata value.
    2694             :  *
    2695             :  * To clear the nodata value, use DeleteNoDataValue().
    2696             :  *
    2697             :  * This method is the same as the C function GDALSetRasterNoDataValueAsInt64().
    2698             :  *
    2699             :  * @param nNoDataValue the value to set.
    2700             :  *
    2701             :  * @return CE_None on success, or CE_Failure on failure.  If unsupported
    2702             :  * by the driver, CE_Failure is returned but no error message will have
    2703             :  * been emitted.
    2704             :  *
    2705             :  * @since GDAL 3.5
    2706             :  */
    2707             : 
    2708           0 : CPLErr GDALRasterBand::SetNoDataValueAsInt64(CPL_UNUSED int64_t nNoDataValue)
    2709             : 
    2710             : {
    2711           0 :     if (!(GetMOFlags() & GMO_IGNORE_UNIMPLEMENTED))
    2712           0 :         ReportError(CE_Failure, CPLE_NotSupported,
    2713             :                     "SetNoDataValueAsInt64() not supported for this dataset.");
    2714             : 
    2715           0 :     return CE_Failure;
    2716             : }
    2717             : 
    2718             : /************************************************************************/
    2719             : /*                 GDALSetRasterNoDataValueAsInt64()                    */
    2720             : /************************************************************************/
    2721             : 
    2722             : /**
    2723             :  * \brief Set the no data value for this band.
    2724             :  *
    2725             :  * This function should ONLY be called on rasters whose data type is GDT_Int64.
    2726             :  *
    2727             :  * Depending on drivers, changing the no data value may or may not have an
    2728             :  * effect on the pixel values of a raster that has just been created. It is
    2729             :  * thus advised to explicitly called Fill() if the intent is to initialize
    2730             :  * the raster to the nodata value.
    2731             :  * In ay case, changing an existing no data value, when one already exists and
    2732             :  * the dataset exists or has been initialized, has no effect on the pixel whose
    2733             :  * value matched the previous nodata value.
    2734             :  *
    2735             :  * @see GDALRasterBand::SetNoDataValueAsInt64()
    2736             :  *
    2737             :  * @since GDAL 3.5
    2738             :  */
    2739             : 
    2740          18 : CPLErr CPL_STDCALL GDALSetRasterNoDataValueAsInt64(GDALRasterBandH hBand,
    2741             :                                                    int64_t nValue)
    2742             : 
    2743             : {
    2744          18 :     VALIDATE_POINTER1(hBand, "GDALSetRasterNoDataValueAsInt64", CE_Failure);
    2745             : 
    2746          18 :     GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
    2747          18 :     return poBand->SetNoDataValueAsInt64(nValue);
    2748             : }
    2749             : 
    2750             : /************************************************************************/
    2751             : /*                       SetNoDataValueAsUInt64()                       */
    2752             : /************************************************************************/
    2753             : 
    2754             : /**
    2755             :  * \brief Set the no data value for this band.
    2756             :  *
    2757             :  * This method should ONLY be called on rasters whose data type is GDT_UInt64.
    2758             :  *
    2759             :  * Depending on drivers, changing the no data value may or may not have an
    2760             :  * effect on the pixel values of a raster that has just been created. It is
    2761             :  * thus advised to explicitly called Fill() if the intent is to initialize
    2762             :  * the raster to the nodata value.
    2763             :  * In ay case, changing an existing no data value, when one already exists and
    2764             :  * the dataset exists or has been initialized, has no effect on the pixel whose
    2765             :  * value matched the previous nodata value.
    2766             :  *
    2767             :  * To clear the nodata value, use DeleteNoDataValue().
    2768             :  *
    2769             :  * This method is the same as the C function GDALSetRasterNoDataValueAsUInt64().
    2770             :  *
    2771             :  * @param nNoDataValue the value to set.
    2772             :  *
    2773             :  * @return CE_None on success, or CE_Failure on failure.  If unsupported
    2774             :  * by the driver, CE_Failure is returned but no error message will have
    2775             :  * been emitted.
    2776             :  *
    2777             :  * @since GDAL 3.5
    2778             :  */
    2779             : 
    2780           0 : CPLErr GDALRasterBand::SetNoDataValueAsUInt64(CPL_UNUSED uint64_t nNoDataValue)
    2781             : 
    2782             : {
    2783           0 :     if (!(GetMOFlags() & GMO_IGNORE_UNIMPLEMENTED))
    2784           0 :         ReportError(CE_Failure, CPLE_NotSupported,
    2785             :                     "SetNoDataValueAsUInt64() not supported for this dataset.");
    2786             : 
    2787           0 :     return CE_Failure;
    2788             : }
    2789             : 
    2790             : /************************************************************************/
    2791             : /*                 GDALSetRasterNoDataValueAsUInt64()                    */
    2792             : /************************************************************************/
    2793             : 
    2794             : /**
    2795             :  * \brief Set the no data value for this band.
    2796             :  *
    2797             :  * This function should ONLY be called on rasters whose data type is GDT_UInt64.
    2798             :  *
    2799             :  * Depending on drivers, changing the no data value may or may not have an
    2800             :  * effect on the pixel values of a raster that has just been created. It is
    2801             :  * thus advised to explicitly called Fill() if the intent is to initialize
    2802             :  * the raster to the nodata value.
    2803             :  * In ay case, changing an existing no data value, when one already exists and
    2804             :  * the dataset exists or has been initialized, has no effect on the pixel whose
    2805             :  * value matched the previous nodata value.
    2806             :  *
    2807             :  * @see GDALRasterBand::SetNoDataValueAsUInt64()
    2808             :  *
    2809             :  * @since GDAL 3.5
    2810             :  */
    2811             : 
    2812          16 : CPLErr CPL_STDCALL GDALSetRasterNoDataValueAsUInt64(GDALRasterBandH hBand,
    2813             :                                                     uint64_t nValue)
    2814             : 
    2815             : {
    2816          16 :     VALIDATE_POINTER1(hBand, "GDALSetRasterNoDataValueAsUInt64", CE_Failure);
    2817             : 
    2818          16 :     GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
    2819          16 :     return poBand->SetNoDataValueAsUInt64(nValue);
    2820             : }
    2821             : 
    2822             : /************************************************************************/
    2823             : /*                        DeleteNoDataValue()                           */
    2824             : /************************************************************************/
    2825             : 
    2826             : /**
    2827             :  * \brief Remove the no data value for this band.
    2828             :  *
    2829             :  * This method is the same as the C function GDALDeleteRasterNoDataValue().
    2830             :  *
    2831             :  * @return CE_None on success, or CE_Failure on failure.  If unsupported
    2832             :  * by the driver, CE_Failure is returned but no error message will have
    2833             :  * been emitted.
    2834             :  *
    2835             :  * @since GDAL 2.1
    2836             :  */
    2837             : 
    2838           0 : CPLErr GDALRasterBand::DeleteNoDataValue()
    2839             : 
    2840             : {
    2841           0 :     if (!(GetMOFlags() & GMO_IGNORE_UNIMPLEMENTED))
    2842           0 :         ReportError(CE_Failure, CPLE_NotSupported,
    2843             :                     "DeleteNoDataValue() not supported for this dataset.");
    2844             : 
    2845           0 :     return CE_Failure;
    2846             : }
    2847             : 
    2848             : /************************************************************************/
    2849             : /*                       GDALDeleteRasterNoDataValue()                  */
    2850             : /************************************************************************/
    2851             : 
    2852             : /**
    2853             :  * \brief Remove the no data value for this band.
    2854             :  *
    2855             :  * @see GDALRasterBand::DeleteNoDataValue()
    2856             :  *
    2857             :  * @since GDAL 2.1
    2858             :  */
    2859             : 
    2860          53 : CPLErr CPL_STDCALL GDALDeleteRasterNoDataValue(GDALRasterBandH hBand)
    2861             : 
    2862             : {
    2863          53 :     VALIDATE_POINTER1(hBand, "GDALDeleteRasterNoDataValue", CE_Failure);
    2864             : 
    2865          53 :     GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
    2866          53 :     return poBand->DeleteNoDataValue();
    2867             : }
    2868             : 
    2869             : /************************************************************************/
    2870             : /*                             GetMaximum()                             */
    2871             : /************************************************************************/
    2872             : 
    2873             : /**
    2874             :  * \brief Fetch the maximum value for this band.
    2875             :  *
    2876             :  * For file formats that don't know this intrinsically, the maximum supported
    2877             :  * value for the data type will generally be returned.
    2878             :  *
    2879             :  * This method is the same as the C function GDALGetRasterMaximum().
    2880             :  *
    2881             :  * @param pbSuccess pointer to a boolean to use to indicate if the
    2882             :  * returned value is a tight maximum or not.  May be NULL (default).
    2883             :  *
    2884             :  * @return the maximum raster value (excluding no data pixels)
    2885             :  */
    2886             : 
    2887         512 : double GDALRasterBand::GetMaximum(int *pbSuccess)
    2888             : 
    2889             : {
    2890         512 :     const char *pszValue = nullptr;
    2891             : 
    2892         512 :     if ((pszValue = GetMetadataItem("STATISTICS_MAXIMUM")) != nullptr)
    2893             :     {
    2894          46 :         if (pbSuccess != nullptr)
    2895          41 :             *pbSuccess = TRUE;
    2896             : 
    2897          46 :         return CPLAtofM(pszValue);
    2898             :     }
    2899             : 
    2900         466 :     if (pbSuccess != nullptr)
    2901         462 :         *pbSuccess = FALSE;
    2902             : 
    2903         466 :     switch (eDataType)
    2904             :     {
    2905         317 :         case GDT_Byte:
    2906             :         {
    2907         317 :             EnablePixelTypeSignedByteWarning(false);
    2908             :             const char *pszPixelType =
    2909         317 :                 GetMetadataItem("PIXELTYPE", "IMAGE_STRUCTURE");
    2910         317 :             EnablePixelTypeSignedByteWarning(true);
    2911         317 :             if (pszPixelType != nullptr && EQUAL(pszPixelType, "SIGNEDBYTE"))
    2912           0 :                 return 127;
    2913             : 
    2914         317 :             return 255;
    2915             :         }
    2916             : 
    2917           1 :         case GDT_Int8:
    2918           1 :             return 127;
    2919             : 
    2920          20 :         case GDT_UInt16:
    2921          20 :             return 65535;
    2922             : 
    2923          23 :         case GDT_Int16:
    2924             :         case GDT_CInt16:
    2925          23 :             return 32767;
    2926             : 
    2927          39 :         case GDT_Int32:
    2928             :         case GDT_CInt32:
    2929          39 :             return 2147483647.0;
    2930             : 
    2931          12 :         case GDT_UInt32:
    2932          12 :             return 4294967295.0;
    2933             : 
    2934           1 :         case GDT_Int64:
    2935           1 :             return static_cast<double>(std::numeric_limits<GInt64>::max());
    2936             : 
    2937           1 :         case GDT_UInt64:
    2938           1 :             return static_cast<double>(std::numeric_limits<GUInt64>::max());
    2939             : 
    2940           0 :         case GDT_Float16:
    2941             :         case GDT_CFloat16:
    2942           0 :             return 65504.0;
    2943             : 
    2944          30 :         case GDT_Float32:
    2945             :         case GDT_CFloat32:
    2946          30 :             return 4294967295.0;  // Not actually accurate.
    2947             : 
    2948          22 :         case GDT_Float64:
    2949             :         case GDT_CFloat64:
    2950          22 :             return 4294967295.0;  // Not actually accurate.
    2951             : 
    2952           0 :         case GDT_Unknown:
    2953             :         case GDT_TypeCount:
    2954           0 :             break;
    2955             :     }
    2956           0 :     return 4294967295.0;  // Not actually accurate.
    2957             : }
    2958             : 
    2959             : /************************************************************************/
    2960             : /*                        GDALGetRasterMaximum()                        */
    2961             : /************************************************************************/
    2962             : 
    2963             : /**
    2964             :  * \brief Fetch the maximum value for this band.
    2965             :  *
    2966             :  * @see GDALRasterBand::GetMaximum()
    2967             :  */
    2968             : 
    2969         280 : double CPL_STDCALL GDALGetRasterMaximum(GDALRasterBandH hBand, int *pbSuccess)
    2970             : 
    2971             : {
    2972         280 :     VALIDATE_POINTER1(hBand, "GDALGetRasterMaximum", 0);
    2973             : 
    2974         280 :     GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
    2975         280 :     return poBand->GetMaximum(pbSuccess);
    2976             : }
    2977             : 
    2978             : /************************************************************************/
    2979             : /*                             GetMinimum()                             */
    2980             : /************************************************************************/
    2981             : 
    2982             : /**
    2983             :  * \brief Fetch the minimum value for this band.
    2984             :  *
    2985             :  * For file formats that don't know this intrinsically, the minimum supported
    2986             :  * value for the data type will generally be returned.
    2987             :  *
    2988             :  * This method is the same as the C function GDALGetRasterMinimum().
    2989             :  *
    2990             :  * @param pbSuccess pointer to a boolean to use to indicate if the
    2991             :  * returned value is a tight minimum or not.  May be NULL (default).
    2992             :  *
    2993             :  * @return the minimum raster value (excluding no data pixels)
    2994             :  */
    2995             : 
    2996         520 : double GDALRasterBand::GetMinimum(int *pbSuccess)
    2997             : 
    2998             : {
    2999         520 :     const char *pszValue = nullptr;
    3000             : 
    3001         520 :     if ((pszValue = GetMetadataItem("STATISTICS_MINIMUM")) != nullptr)
    3002             :     {
    3003          51 :         if (pbSuccess != nullptr)
    3004          46 :             *pbSuccess = TRUE;
    3005             : 
    3006          51 :         return CPLAtofM(pszValue);
    3007             :     }
    3008             : 
    3009         469 :     if (pbSuccess != nullptr)
    3010         465 :         *pbSuccess = FALSE;
    3011             : 
    3012         469 :     switch (eDataType)
    3013             :     {
    3014         320 :         case GDT_Byte:
    3015             :         {
    3016         320 :             EnablePixelTypeSignedByteWarning(false);
    3017             :             const char *pszPixelType =
    3018         320 :                 GetMetadataItem("PIXELTYPE", "IMAGE_STRUCTURE");
    3019         320 :             EnablePixelTypeSignedByteWarning(true);
    3020         320 :             if (pszPixelType != nullptr && EQUAL(pszPixelType, "SIGNEDBYTE"))
    3021           0 :                 return -128;
    3022             : 
    3023         320 :             return 0;
    3024             :         }
    3025             : 
    3026           1 :         case GDT_Int8:
    3027           1 :             return -128;
    3028             :             break;
    3029             : 
    3030          20 :         case GDT_UInt16:
    3031          20 :             return 0;
    3032             : 
    3033          23 :         case GDT_Int16:
    3034             :         case GDT_CInt16:
    3035          23 :             return -32768;
    3036             : 
    3037          39 :         case GDT_Int32:
    3038             :         case GDT_CInt32:
    3039          39 :             return -2147483648.0;
    3040             : 
    3041          12 :         case GDT_UInt32:
    3042          12 :             return 0;
    3043             : 
    3044           1 :         case GDT_Int64:
    3045           1 :             return static_cast<double>(std::numeric_limits<GInt64>::lowest());
    3046             : 
    3047           1 :         case GDT_UInt64:
    3048           1 :             return 0;
    3049             : 
    3050           0 :         case GDT_Float16:
    3051             :         case GDT_CFloat16:
    3052           0 :             return -65504.0;
    3053             : 
    3054          30 :         case GDT_Float32:
    3055             :         case GDT_CFloat32:
    3056          30 :             return -4294967295.0;  // Not actually accurate.
    3057             : 
    3058          22 :         case GDT_Float64:
    3059             :         case GDT_CFloat64:
    3060          22 :             return -4294967295.0;  // Not actually accurate.
    3061             : 
    3062           0 :         case GDT_Unknown:
    3063             :         case GDT_TypeCount:
    3064           0 :             break;
    3065             :     }
    3066           0 :     return -4294967295.0;  // Not actually accurate.
    3067             : }
    3068             : 
    3069             : /************************************************************************/
    3070             : /*                        GDALGetRasterMinimum()                        */
    3071             : /************************************************************************/
    3072             : 
    3073             : /**
    3074             :  * \brief Fetch the minimum value for this band.
    3075             :  *
    3076             :  * @see GDALRasterBand::GetMinimum()
    3077             :  */
    3078             : 
    3079         290 : double CPL_STDCALL GDALGetRasterMinimum(GDALRasterBandH hBand, int *pbSuccess)
    3080             : 
    3081             : {
    3082         290 :     VALIDATE_POINTER1(hBand, "GDALGetRasterMinimum", 0);
    3083             : 
    3084         290 :     GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
    3085         290 :     return poBand->GetMinimum(pbSuccess);
    3086             : }
    3087             : 
    3088             : /************************************************************************/
    3089             : /*                       GetColorInterpretation()                       */
    3090             : /************************************************************************/
    3091             : 
    3092             : /**
    3093             :  * \brief How should this band be interpreted as color?
    3094             :  *
    3095             :  * GCI_Undefined is returned when the format doesn't know anything
    3096             :  * about the color interpretation.
    3097             :  *
    3098             :  * This method is the same as the C function
    3099             :  * GDALGetRasterColorInterpretation().
    3100             :  *
    3101             :  * @return color interpretation value for band.
    3102             :  */
    3103             : 
    3104         149 : GDALColorInterp GDALRasterBand::GetColorInterpretation()
    3105             : 
    3106             : {
    3107         149 :     return GCI_Undefined;
    3108             : }
    3109             : 
    3110             : /************************************************************************/
    3111             : /*                  GDALGetRasterColorInterpretation()                  */
    3112             : /************************************************************************/
    3113             : 
    3114             : /**
    3115             :  * \brief How should this band be interpreted as color?
    3116             :  *
    3117             :  * @see GDALRasterBand::GetColorInterpretation()
    3118             :  */
    3119             : 
    3120             : GDALColorInterp CPL_STDCALL
    3121        5402 : GDALGetRasterColorInterpretation(GDALRasterBandH hBand)
    3122             : 
    3123             : {
    3124        5402 :     VALIDATE_POINTER1(hBand, "GDALGetRasterColorInterpretation", GCI_Undefined);
    3125             : 
    3126        5402 :     GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
    3127        5402 :     return poBand->GetColorInterpretation();
    3128             : }
    3129             : 
    3130             : /************************************************************************/
    3131             : /*                       SetColorInterpretation()                       */
    3132             : /************************************************************************/
    3133             : 
    3134             : /**
    3135             :  * \fn GDALRasterBand::SetColorInterpretation(GDALColorInterp)
    3136             :  * \brief Set color interpretation of a band.
    3137             :  *
    3138             :  * This method is the same as the C function GDALSetRasterColorInterpretation().
    3139             :  *
    3140             :  * @param eColorInterp the new color interpretation to apply to this band.
    3141             :  *
    3142             :  * @return CE_None on success or CE_Failure if method is unsupported by format.
    3143             :  */
    3144             : 
    3145             : /**/
    3146             : /**/
    3147             : 
    3148           3 : CPLErr GDALRasterBand::SetColorInterpretation(GDALColorInterp /*eColorInterp*/)
    3149             : 
    3150             : {
    3151           3 :     if (!(GetMOFlags() & GMO_IGNORE_UNIMPLEMENTED))
    3152           3 :         ReportError(CE_Failure, CPLE_NotSupported,
    3153             :                     "SetColorInterpretation() not supported for this dataset.");
    3154           3 :     return CE_Failure;
    3155             : }
    3156             : 
    3157             : /************************************************************************/
    3158             : /*                  GDALSetRasterColorInterpretation()                  */
    3159             : /************************************************************************/
    3160             : 
    3161             : /**
    3162             :  * \brief Set color interpretation of a band.
    3163             :  *
    3164             :  * @see GDALRasterBand::SetColorInterpretation()
    3165             :  */
    3166             : 
    3167        1815 : CPLErr CPL_STDCALL GDALSetRasterColorInterpretation(
    3168             :     GDALRasterBandH hBand, GDALColorInterp eColorInterp)
    3169             : 
    3170             : {
    3171        1815 :     VALIDATE_POINTER1(hBand, "GDALSetRasterColorInterpretation", CE_Failure);
    3172             : 
    3173        1815 :     GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
    3174        1815 :     return poBand->SetColorInterpretation(eColorInterp);
    3175             : }
    3176             : 
    3177             : /************************************************************************/
    3178             : /*                           GetColorTable()                            */
    3179             : /************************************************************************/
    3180             : 
    3181             : /**
    3182             :  * \brief Fetch the color table associated with band.
    3183             :  *
    3184             :  * If there is no associated color table, the return result is NULL.  The
    3185             :  * returned color table remains owned by the GDALRasterBand, and can't
    3186             :  * be depended on for long, nor should it ever be modified by the caller.
    3187             :  *
    3188             :  * This method is the same as the C function GDALGetRasterColorTable().
    3189             :  *
    3190             :  * @return internal color table, or NULL.
    3191             :  */
    3192             : 
    3193         231 : GDALColorTable *GDALRasterBand::GetColorTable()
    3194             : 
    3195             : {
    3196         231 :     return nullptr;
    3197             : }
    3198             : 
    3199             : /************************************************************************/
    3200             : /*                      GDALGetRasterColorTable()                       */
    3201             : /************************************************************************/
    3202             : 
    3203             : /**
    3204             :  * \brief Fetch the color table associated with band.
    3205             :  *
    3206             :  * @see GDALRasterBand::GetColorTable()
    3207             :  */
    3208             : 
    3209        1882 : GDALColorTableH CPL_STDCALL GDALGetRasterColorTable(GDALRasterBandH hBand)
    3210             : 
    3211             : {
    3212        1882 :     VALIDATE_POINTER1(hBand, "GDALGetRasterColorTable", nullptr);
    3213             : 
    3214        1882 :     GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
    3215        1882 :     return GDALColorTable::ToHandle(poBand->GetColorTable());
    3216             : }
    3217             : 
    3218             : /************************************************************************/
    3219             : /*                           SetColorTable()                            */
    3220             : /************************************************************************/
    3221             : 
    3222             : /**
    3223             :  * \fn GDALRasterBand::SetColorTable(GDALColorTable*)
    3224             :  * \brief Set the raster color table.
    3225             :  *
    3226             :  * The driver will make a copy of all desired data in the colortable.  It
    3227             :  * remains owned by the caller after the call.
    3228             :  *
    3229             :  * This method is the same as the C function GDALSetRasterColorTable().
    3230             :  *
    3231             :  * @param poCT the color table to apply.  This may be NULL to clear the color
    3232             :  * table (where supported).
    3233             :  *
    3234             :  * @return CE_None on success, or CE_Failure on failure.  If the action is
    3235             :  * unsupported by the driver, a value of CE_Failure is returned, but no
    3236             :  * error is issued.
    3237             :  */
    3238             : 
    3239             : /**/
    3240             : /**/
    3241             : 
    3242           0 : CPLErr GDALRasterBand::SetColorTable(GDALColorTable * /*poCT*/)
    3243             : 
    3244             : {
    3245           0 :     if (!(GetMOFlags() & GMO_IGNORE_UNIMPLEMENTED))
    3246           0 :         ReportError(CE_Failure, CPLE_NotSupported,
    3247             :                     "SetColorTable() not supported for this dataset.");
    3248           0 :     return CE_Failure;
    3249             : }
    3250             : 
    3251             : /************************************************************************/
    3252             : /*                      GDALSetRasterColorTable()                       */
    3253             : /************************************************************************/
    3254             : 
    3255             : /**
    3256             :  * \brief Set the raster color table.
    3257             :  *
    3258             :  * @see GDALRasterBand::SetColorTable()
    3259             :  */
    3260             : 
    3261          77 : CPLErr CPL_STDCALL GDALSetRasterColorTable(GDALRasterBandH hBand,
    3262             :                                            GDALColorTableH hCT)
    3263             : 
    3264             : {
    3265          77 :     VALIDATE_POINTER1(hBand, "GDALSetRasterColorTable", CE_Failure);
    3266             : 
    3267          77 :     GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
    3268          77 :     return poBand->SetColorTable(GDALColorTable::FromHandle(hCT));
    3269             : }
    3270             : 
    3271             : /************************************************************************/
    3272             : /*                       HasArbitraryOverviews()                        */
    3273             : /************************************************************************/
    3274             : 
    3275             : /**
    3276             :  * \brief Check for arbitrary overviews.
    3277             :  *
    3278             :  * This returns TRUE if the underlying datastore can compute arbitrary
    3279             :  * overviews efficiently, such as is the case with OGDI over a network.
    3280             :  * Datastores with arbitrary overviews don't generally have any fixed
    3281             :  * overviews, but the RasterIO() method can be used in downsampling mode
    3282             :  * to get overview data efficiently.
    3283             :  *
    3284             :  * This method is the same as the C function GDALHasArbitraryOverviews(),
    3285             :  *
    3286             :  * @return TRUE if arbitrary overviews available (efficiently), otherwise
    3287             :  * FALSE.
    3288             :  */
    3289             : 
    3290         251 : int GDALRasterBand::HasArbitraryOverviews()
    3291             : 
    3292             : {
    3293         251 :     return FALSE;
    3294             : }
    3295             : 
    3296             : /************************************************************************/
    3297             : /*                     GDALHasArbitraryOverviews()                      */
    3298             : /************************************************************************/
    3299             : 
    3300             : /**
    3301             :  * \brief Check for arbitrary overviews.
    3302             :  *
    3303             :  * @see GDALRasterBand::HasArbitraryOverviews()
    3304             :  */
    3305             : 
    3306         173 : int CPL_STDCALL GDALHasArbitraryOverviews(GDALRasterBandH hBand)
    3307             : 
    3308             : {
    3309         173 :     VALIDATE_POINTER1(hBand, "GDALHasArbitraryOverviews", 0);
    3310             : 
    3311         173 :     GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
    3312         173 :     return poBand->HasArbitraryOverviews();
    3313             : }
    3314             : 
    3315             : /************************************************************************/
    3316             : /*                          GetOverviewCount()                          */
    3317             : /************************************************************************/
    3318             : 
    3319             : /**
    3320             :  * \brief Return the number of overview layers available.
    3321             :  *
    3322             :  * This method is the same as the C function GDALGetOverviewCount().
    3323             :  *
    3324             :  * @return overview count, zero if none.
    3325             :  */
    3326             : 
    3327     1065390 : int GDALRasterBand::GetOverviewCount()
    3328             : 
    3329             : {
    3330     1721890 :     if (poDS != nullptr && poDS->oOvManager.IsInitialized() &&
    3331      656499 :         poDS->AreOverviewsEnabled())
    3332      656499 :         return poDS->oOvManager.GetOverviewCount(nBand);
    3333             : 
    3334      408893 :     return 0;
    3335             : }
    3336             : 
    3337             : /************************************************************************/
    3338             : /*                        GDALGetOverviewCount()                        */
    3339             : /************************************************************************/
    3340             : 
    3341             : /**
    3342             :  * \brief Return the number of overview layers available.
    3343             :  *
    3344             :  * @see GDALRasterBand::GetOverviewCount()
    3345             :  */
    3346             : 
    3347        3267 : int CPL_STDCALL GDALGetOverviewCount(GDALRasterBandH hBand)
    3348             : 
    3349             : {
    3350        3267 :     VALIDATE_POINTER1(hBand, "GDALGetOverviewCount", 0);
    3351             : 
    3352        3267 :     GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
    3353        3267 :     return poBand->GetOverviewCount();
    3354             : }
    3355             : 
    3356             : /************************************************************************/
    3357             : /*                            GetOverview()                             */
    3358             : /************************************************************************/
    3359             : 
    3360             : /**
    3361             :  * \brief Fetch overview raster band object.
    3362             :  *
    3363             :  * This method is the same as the C function GDALGetOverview().
    3364             :  *
    3365             :  * @param i overview index between 0 and GetOverviewCount()-1.
    3366             :  *
    3367             :  * @return overview GDALRasterBand.
    3368             :  */
    3369             : 
    3370         826 : GDALRasterBand *GDALRasterBand::GetOverview(int i)
    3371             : 
    3372             : {
    3373        1597 :     if (poDS != nullptr && poDS->oOvManager.IsInitialized() &&
    3374         771 :         poDS->AreOverviewsEnabled())
    3375         771 :         return poDS->oOvManager.GetOverview(nBand, i);
    3376             : 
    3377          55 :     return nullptr;
    3378             : }
    3379             : 
    3380             : /************************************************************************/
    3381             : /*                          GDALGetOverview()                           */
    3382             : /************************************************************************/
    3383             : 
    3384             : /**
    3385             :  * \brief Fetch overview raster band object.
    3386             :  *
    3387             :  * @see GDALRasterBand::GetOverview()
    3388             :  */
    3389             : 
    3390        5646 : GDALRasterBandH CPL_STDCALL GDALGetOverview(GDALRasterBandH hBand, int i)
    3391             : 
    3392             : {
    3393        5646 :     VALIDATE_POINTER1(hBand, "GDALGetOverview", nullptr);
    3394             : 
    3395        5646 :     GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
    3396        5646 :     return GDALRasterBand::ToHandle(poBand->GetOverview(i));
    3397             : }
    3398             : 
    3399             : /************************************************************************/
    3400             : /*                      GetRasterSampleOverview()                       */
    3401             : /************************************************************************/
    3402             : 
    3403             : /**
    3404             :  * \brief Fetch best sampling overview.
    3405             :  *
    3406             :  * Returns the most reduced overview of the given band that still satisfies
    3407             :  * the desired number of samples.  This function can be used with zero
    3408             :  * as the number of desired samples to fetch the most reduced overview.
    3409             :  * The same band as was passed in will be returned if it has not overviews,
    3410             :  * or if none of the overviews have enough samples.
    3411             :  *
    3412             :  * This method is the same as the C functions GDALGetRasterSampleOverview()
    3413             :  * and GDALGetRasterSampleOverviewEx().
    3414             :  *
    3415             :  * @param nDesiredSamples the returned band will have at least this many
    3416             :  * pixels.
    3417             :  *
    3418             :  * @return optimal overview or the band itself.
    3419             :  */
    3420             : 
    3421             : GDALRasterBand *
    3422        2006 : GDALRasterBand::GetRasterSampleOverview(GUIntBig nDesiredSamples)
    3423             : 
    3424             : {
    3425        2006 :     GDALRasterBand *poBestBand = this;
    3426             : 
    3427        2006 :     double dfBestSamples = GetXSize() * static_cast<double>(GetYSize());
    3428             : 
    3429        4023 :     for (int iOverview = 0; iOverview < GetOverviewCount(); iOverview++)
    3430             :     {
    3431        2017 :         GDALRasterBand *poOBand = GetOverview(iOverview);
    3432             : 
    3433        2017 :         if (poOBand == nullptr)
    3434           0 :             continue;
    3435             : 
    3436             :         const double dfOSamples =
    3437        2017 :             poOBand->GetXSize() * static_cast<double>(poOBand->GetYSize());
    3438             : 
    3439        2017 :         if (dfOSamples < dfBestSamples && dfOSamples > nDesiredSamples)
    3440             :         {
    3441        2014 :             dfBestSamples = dfOSamples;
    3442        2014 :             poBestBand = poOBand;
    3443             :         }
    3444             :     }
    3445             : 
    3446        2006 :     return poBestBand;
    3447             : }
    3448             : 
    3449             : /************************************************************************/
    3450             : /*                    GDALGetRasterSampleOverview()                     */
    3451             : /************************************************************************/
    3452             : 
    3453             : /**
    3454             :  * \brief Fetch best sampling overview.
    3455             :  *
    3456             :  * Use GDALGetRasterSampleOverviewEx() to be able to specify more than 2
    3457             :  * billion samples.
    3458             :  *
    3459             :  * @see GDALRasterBand::GetRasterSampleOverview()
    3460             :  * @see GDALGetRasterSampleOverviewEx()
    3461             :  */
    3462             : 
    3463           0 : GDALRasterBandH CPL_STDCALL GDALGetRasterSampleOverview(GDALRasterBandH hBand,
    3464             :                                                         int nDesiredSamples)
    3465             : 
    3466             : {
    3467           0 :     VALIDATE_POINTER1(hBand, "GDALGetRasterSampleOverview", nullptr);
    3468             : 
    3469           0 :     GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
    3470           0 :     return GDALRasterBand::ToHandle(poBand->GetRasterSampleOverview(
    3471           0 :         nDesiredSamples < 0 ? 0 : static_cast<GUIntBig>(nDesiredSamples)));
    3472             : }
    3473             : 
    3474             : /************************************************************************/
    3475             : /*                    GDALGetRasterSampleOverviewEx()                   */
    3476             : /************************************************************************/
    3477             : 
    3478             : /**
    3479             :  * \brief Fetch best sampling overview.
    3480             :  *
    3481             :  * @see GDALRasterBand::GetRasterSampleOverview()
    3482             :  * @since GDAL 2.0
    3483             :  */
    3484             : 
    3485             : GDALRasterBandH CPL_STDCALL
    3486        2000 : GDALGetRasterSampleOverviewEx(GDALRasterBandH hBand, GUIntBig nDesiredSamples)
    3487             : 
    3488             : {
    3489        2000 :     VALIDATE_POINTER1(hBand, "GDALGetRasterSampleOverviewEx", nullptr);
    3490             : 
    3491        2000 :     GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
    3492        2000 :     return GDALRasterBand::ToHandle(
    3493        4000 :         poBand->GetRasterSampleOverview(nDesiredSamples));
    3494             : }
    3495             : 
    3496             : /************************************************************************/
    3497             : /*                           BuildOverviews()                           */
    3498             : /************************************************************************/
    3499             : 
    3500             : /**
    3501             :  * \fn GDALRasterBand::BuildOverviews(const char*, int, const int*,
    3502             :  * GDALProgressFunc, void*) \brief Build raster overview(s)
    3503             :  *
    3504             :  * If the operation is unsupported for the indicated dataset, then
    3505             :  * CE_Failure is returned, and CPLGetLastErrorNo() will return
    3506             :  * CPLE_NotSupported.
    3507             :  *
    3508             :  * WARNING: Most formats don't support per-band overview computation, but
    3509             :  * require that overviews are computed for all bands of a dataset, using
    3510             :  * GDALDataset::BuildOverviews(). The only exception for official GDAL drivers
    3511             :  * is the HFA driver which supports this method.
    3512             :  *
    3513             :  * @param pszResampling one of "NEAREST", "GAUSS", "CUBIC", "AVERAGE", "MODE",
    3514             :  * "AVERAGE_MAGPHASE" "RMS" or "NONE" controlling the downsampling method
    3515             :  * applied.
    3516             :  * @param nOverviews number of overviews to build.
    3517             :  * @param panOverviewList the list of overview decimation factors to build.
    3518             :  * @param pfnProgress a function to call to report progress, or NULL.
    3519             :  * @param pProgressData application data to pass to the progress function.
    3520             :  * @param papszOptions (GDAL >= 3.6) NULL terminated list of options as
    3521             :  *                     key=value pairs, or NULL
    3522             :  *
    3523             :  * @return CE_None on success or CE_Failure if the operation doesn't work.
    3524             :  */
    3525             : 
    3526             : /**/
    3527             : /**/
    3528             : 
    3529           0 : CPLErr GDALRasterBand::BuildOverviews(const char * /*pszResampling*/,
    3530             :                                       int /*nOverviews*/,
    3531             :                                       const int * /*panOverviewList*/,
    3532             :                                       GDALProgressFunc /*pfnProgress*/,
    3533             :                                       void * /*pProgressData*/,
    3534             :                                       CSLConstList /* papszOptions */)
    3535             : 
    3536             : {
    3537           0 :     ReportError(CE_Failure, CPLE_NotSupported,
    3538             :                 "BuildOverviews() not supported for this dataset.");
    3539             : 
    3540           0 :     return (CE_Failure);
    3541             : }
    3542             : 
    3543             : /************************************************************************/
    3544             : /*                             GetOffset()                              */
    3545             : /************************************************************************/
    3546             : 
    3547             : /**
    3548             :  * \brief Fetch the raster value offset.
    3549             :  *
    3550             :  * This value (in combination with the GetScale() value) can be used to
    3551             :  * transform raw pixel values into the units returned by GetUnitType().
    3552             :  * For example this might be used to store elevations in GUInt16 bands
    3553             :  * with a precision of 0.1, and starting from -100.
    3554             :  *
    3555             :  * Units value = (raw value * scale) + offset
    3556             :  *
    3557             :  * Note that applying scale and offset is of the responsibility of the user,
    3558             :  * and is not done by methods such as RasterIO() or ReadBlock().
    3559             :  *
    3560             :  * For file formats that don't know this intrinsically a value of zero
    3561             :  * is returned.
    3562             :  *
    3563             :  * This method is the same as the C function GDALGetRasterOffset().
    3564             :  *
    3565             :  * @param pbSuccess pointer to a boolean to use to indicate if the
    3566             :  * returned value is meaningful or not.  May be NULL (default).
    3567             :  *
    3568             :  * @return the raster offset.
    3569             :  */
    3570             : 
    3571         460 : double GDALRasterBand::GetOffset(int *pbSuccess)
    3572             : 
    3573             : {
    3574         460 :     if (pbSuccess != nullptr)
    3575         351 :         *pbSuccess = FALSE;
    3576             : 
    3577         460 :     return 0.0;
    3578             : }
    3579             : 
    3580             : /************************************************************************/
    3581             : /*                        GDALGetRasterOffset()                         */
    3582             : /************************************************************************/
    3583             : 
    3584             : /**
    3585             :  * \brief Fetch the raster value offset.
    3586             :  *
    3587             :  * @see GDALRasterBand::GetOffset()
    3588             :  */
    3589             : 
    3590         368 : double CPL_STDCALL GDALGetRasterOffset(GDALRasterBandH hBand, int *pbSuccess)
    3591             : 
    3592             : {
    3593         368 :     VALIDATE_POINTER1(hBand, "GDALGetRasterOffset", 0);
    3594             : 
    3595         368 :     GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
    3596         368 :     return poBand->GetOffset(pbSuccess);
    3597             : }
    3598             : 
    3599             : /************************************************************************/
    3600             : /*                             SetOffset()                              */
    3601             : /************************************************************************/
    3602             : 
    3603             : /**
    3604             :  * \fn GDALRasterBand::SetOffset(double)
    3605             :  * \brief Set scaling offset.
    3606             :  *
    3607             :  * Very few formats implement this method.   When not implemented it will
    3608             :  * issue a CPLE_NotSupported error and return CE_Failure.
    3609             :  *
    3610             :  * This method is the same as the C function GDALSetRasterOffset().
    3611             :  *
    3612             :  * @param dfNewOffset the new offset.
    3613             :  *
    3614             :  * @return CE_None or success or CE_Failure on failure.
    3615             :  */
    3616             : 
    3617             : /**/
    3618             : /**/
    3619             : 
    3620           0 : CPLErr GDALRasterBand::SetOffset(double /*dfNewOffset*/)
    3621             : {
    3622           0 :     if (!(GetMOFlags() & GMO_IGNORE_UNIMPLEMENTED))
    3623           0 :         ReportError(CE_Failure, CPLE_NotSupported,
    3624             :                     "SetOffset() not supported on this raster band.");
    3625             : 
    3626           0 :     return CE_Failure;
    3627             : }
    3628             : 
    3629             : /************************************************************************/
    3630             : /*                        GDALSetRasterOffset()                         */
    3631             : /************************************************************************/
    3632             : 
    3633             : /**
    3634             :  * \brief Set scaling offset.
    3635             :  *
    3636             :  * @see GDALRasterBand::SetOffset()
    3637             :  */
    3638             : 
    3639          75 : CPLErr CPL_STDCALL GDALSetRasterOffset(GDALRasterBandH hBand,
    3640             :                                        double dfNewOffset)
    3641             : 
    3642             : {
    3643          75 :     VALIDATE_POINTER1(hBand, "GDALSetRasterOffset", CE_Failure);
    3644             : 
    3645          75 :     GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
    3646          75 :     return poBand->SetOffset(dfNewOffset);
    3647             : }
    3648             : 
    3649             : /************************************************************************/
    3650             : /*                              GetScale()                              */
    3651             : /************************************************************************/
    3652             : 
    3653             : /**
    3654             :  * \brief Fetch the raster value scale.
    3655             :  *
    3656             :  * This value (in combination with the GetOffset() value) can be used to
    3657             :  * transform raw pixel values into the units returned by GetUnitType().
    3658             :  * For example this might be used to store elevations in GUInt16 bands
    3659             :  * with a precision of 0.1, and starting from -100.
    3660             :  *
    3661             :  * Units value = (raw value * scale) + offset
    3662             :  *
    3663             :  * Note that applying scale and offset is of the responsibility of the user,
    3664             :  * and is not done by methods such as RasterIO() or ReadBlock().
    3665             :  *
    3666             :  * For file formats that don't know this intrinsically a value of one
    3667             :  * is returned.
    3668             :  *
    3669             :  * This method is the same as the C function GDALGetRasterScale().
    3670             :  *
    3671             :  * @param pbSuccess pointer to a boolean to use to indicate if the
    3672             :  * returned value is meaningful or not.  May be NULL (default).
    3673             :  *
    3674             :  * @return the raster scale.
    3675             :  */
    3676             : 
    3677         460 : double GDALRasterBand::GetScale(int *pbSuccess)
    3678             : 
    3679             : {
    3680         460 :     if (pbSuccess != nullptr)
    3681         351 :         *pbSuccess = FALSE;
    3682             : 
    3683         460 :     return 1.0;
    3684             : }
    3685             : 
    3686             : /************************************************************************/
    3687             : /*                         GDALGetRasterScale()                         */
    3688             : /************************************************************************/
    3689             : 
    3690             : /**
    3691             :  * \brief Fetch the raster value scale.
    3692             :  *
    3693             :  * @see GDALRasterBand::GetScale()
    3694             :  */
    3695             : 
    3696         366 : double CPL_STDCALL GDALGetRasterScale(GDALRasterBandH hBand, int *pbSuccess)
    3697             : 
    3698             : {
    3699         366 :     VALIDATE_POINTER1(hBand, "GDALGetRasterScale", 0);
    3700             : 
    3701         366 :     GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
    3702         366 :     return poBand->GetScale(pbSuccess);
    3703             : }
    3704             : 
    3705             : /************************************************************************/
    3706             : /*                              SetScale()                              */
    3707             : /************************************************************************/
    3708             : 
    3709             : /**
    3710             :  * \fn GDALRasterBand::SetScale(double)
    3711             :  * \brief Set scaling ratio.
    3712             :  *
    3713             :  * Very few formats implement this method.   When not implemented it will
    3714             :  * issue a CPLE_NotSupported error and return CE_Failure.
    3715             :  *
    3716             :  * This method is the same as the C function GDALSetRasterScale().
    3717             :  *
    3718             :  * @param dfNewScale the new scale.
    3719             :  *
    3720             :  * @return CE_None or success or CE_Failure on failure.
    3721             :  */
    3722             : 
    3723             : /**/
    3724             : /**/
    3725             : 
    3726           0 : CPLErr GDALRasterBand::SetScale(double /*dfNewScale*/)
    3727             : 
    3728             : {
    3729           0 :     if (!(GetMOFlags() & GMO_IGNORE_UNIMPLEMENTED))
    3730           0 :         ReportError(CE_Failure, CPLE_NotSupported,
    3731             :                     "SetScale() not supported on this raster band.");
    3732             : 
    3733           0 :     return CE_Failure;
    3734             : }
    3735             : 
    3736             : /************************************************************************/
    3737             : /*                        GDALSetRasterScale()                          */
    3738             : /************************************************************************/
    3739             : 
    3740             : /**
    3741             :  * \brief Set scaling ratio.
    3742             :  *
    3743             :  * @see GDALRasterBand::SetScale()
    3744             :  */
    3745             : 
    3746          76 : CPLErr CPL_STDCALL GDALSetRasterScale(GDALRasterBandH hBand, double dfNewOffset)
    3747             : 
    3748             : {
    3749          76 :     VALIDATE_POINTER1(hBand, "GDALSetRasterScale", CE_Failure);
    3750             : 
    3751          76 :     GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
    3752          76 :     return poBand->SetScale(dfNewOffset);
    3753             : }
    3754             : 
    3755             : /************************************************************************/
    3756             : /*                            GetUnitType()                             */
    3757             : /************************************************************************/
    3758             : 
    3759             : /**
    3760             :  * \brief Return raster unit type.
    3761             :  *
    3762             :  * Return a name for the units of this raster's values.  For instance, it
    3763             :  * might be "m" for an elevation model in meters, or "ft" for feet.  If no
    3764             :  * units are available, a value of "" will be returned.  The returned string
    3765             :  * should not be modified, nor freed by the calling application.
    3766             :  *
    3767             :  * This method is the same as the C function GDALGetRasterUnitType().
    3768             :  *
    3769             :  * @return unit name string.
    3770             :  */
    3771             : 
    3772         183 : const char *GDALRasterBand::GetUnitType()
    3773             : 
    3774             : {
    3775         183 :     return "";
    3776             : }
    3777             : 
    3778             : /************************************************************************/
    3779             : /*                       GDALGetRasterUnitType()                        */
    3780             : /************************************************************************/
    3781             : 
    3782             : /**
    3783             :  * \brief Return raster unit type.
    3784             :  *
    3785             :  * @see GDALRasterBand::GetUnitType()
    3786             :  */
    3787             : 
    3788        1412 : const char *CPL_STDCALL GDALGetRasterUnitType(GDALRasterBandH hBand)
    3789             : 
    3790             : {
    3791        1412 :     VALIDATE_POINTER1(hBand, "GDALGetRasterUnitType", nullptr);
    3792             : 
    3793        1412 :     GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
    3794        1412 :     return poBand->GetUnitType();
    3795             : }
    3796             : 
    3797             : /************************************************************************/
    3798             : /*                            SetUnitType()                             */
    3799             : /************************************************************************/
    3800             : 
    3801             : /**
    3802             :  * \fn GDALRasterBand::SetUnitType(const char*)
    3803             :  * \brief Set unit type.
    3804             :  *
    3805             :  * Set the unit type for a raster band.  Values should be one of
    3806             :  * "" (the default indicating it is unknown), "m" indicating meters,
    3807             :  * or "ft" indicating feet, though other nonstandard values are allowed.
    3808             :  *
    3809             :  * This method is the same as the C function GDALSetRasterUnitType().
    3810             :  *
    3811             :  * @param pszNewValue the new unit type value.
    3812             :  *
    3813             :  * @return CE_None on success or CE_Failure if not successful, or
    3814             :  * unsupported.
    3815             :  */
    3816             : 
    3817             : /**/
    3818             : /**/
    3819             : 
    3820           0 : CPLErr GDALRasterBand::SetUnitType(const char * /*pszNewValue*/)
    3821             : 
    3822             : {
    3823           0 :     if (!(GetMOFlags() & GMO_IGNORE_UNIMPLEMENTED))
    3824           0 :         ReportError(CE_Failure, CPLE_NotSupported,
    3825             :                     "SetUnitType() not supported on this raster band.");
    3826           0 :     return CE_Failure;
    3827             : }
    3828             : 
    3829             : /************************************************************************/
    3830             : /*                       GDALSetRasterUnitType()                        */
    3831             : /************************************************************************/
    3832             : 
    3833             : /**
    3834             :  * \brief Set unit type.
    3835             :  *
    3836             :  * @see GDALRasterBand::SetUnitType()
    3837             :  *
    3838             :  * @since GDAL 1.8.0
    3839             :  */
    3840             : 
    3841          75 : CPLErr CPL_STDCALL GDALSetRasterUnitType(GDALRasterBandH hBand,
    3842             :                                          const char *pszNewValue)
    3843             : 
    3844             : {
    3845          75 :     VALIDATE_POINTER1(hBand, "GDALSetRasterUnitType", CE_Failure);
    3846             : 
    3847          75 :     GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
    3848          75 :     return poBand->SetUnitType(pszNewValue);
    3849             : }
    3850             : 
    3851             : /************************************************************************/
    3852             : /*                              GetXSize()                              */
    3853             : /************************************************************************/
    3854             : 
    3855             : /**
    3856             :  * \brief Fetch XSize of raster.
    3857             :  *
    3858             :  * This method is the same as the C function GDALGetRasterBandXSize().
    3859             :  *
    3860             :  * @return the width in pixels of this band.
    3861             :  */
    3862             : 
    3863     7949630 : int GDALRasterBand::GetXSize() const
    3864             : 
    3865             : {
    3866     7949630 :     return nRasterXSize;
    3867             : }
    3868             : 
    3869             : /************************************************************************/
    3870             : /*                       GDALGetRasterBandXSize()                       */
    3871             : /************************************************************************/
    3872             : 
    3873             : /**
    3874             :  * \brief Fetch XSize of raster.
    3875             :  *
    3876             :  * @see GDALRasterBand::GetXSize()
    3877             :  */
    3878             : 
    3879       57379 : int CPL_STDCALL GDALGetRasterBandXSize(GDALRasterBandH hBand)
    3880             : 
    3881             : {
    3882       57379 :     VALIDATE_POINTER1(hBand, "GDALGetRasterBandXSize", 0);
    3883             : 
    3884       57379 :     GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
    3885       57379 :     return poBand->GetXSize();
    3886             : }
    3887             : 
    3888             : /************************************************************************/
    3889             : /*                              GetYSize()                              */
    3890             : /************************************************************************/
    3891             : 
    3892             : /**
    3893             :  * \brief Fetch YSize of raster.
    3894             :  *
    3895             :  * This method is the same as the C function GDALGetRasterBandYSize().
    3896             :  *
    3897             :  * @return the height in pixels of this band.
    3898             :  */
    3899             : 
    3900     4250390 : int GDALRasterBand::GetYSize() const
    3901             : 
    3902             : {
    3903     4250390 :     return nRasterYSize;
    3904             : }
    3905             : 
    3906             : /************************************************************************/
    3907             : /*                       GDALGetRasterBandYSize()                       */
    3908             : /************************************************************************/
    3909             : 
    3910             : /**
    3911             :  * \brief Fetch YSize of raster.
    3912             :  *
    3913             :  * @see GDALRasterBand::GetYSize()
    3914             :  */
    3915             : 
    3916       56244 : int CPL_STDCALL GDALGetRasterBandYSize(GDALRasterBandH hBand)
    3917             : 
    3918             : {
    3919       56244 :     VALIDATE_POINTER1(hBand, "GDALGetRasterBandYSize", 0);
    3920             : 
    3921       56244 :     GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
    3922       56244 :     return poBand->GetYSize();
    3923             : }
    3924             : 
    3925             : /************************************************************************/
    3926             : /*                              GetBand()                               */
    3927             : /************************************************************************/
    3928             : 
    3929             : /**
    3930             :  * \brief Fetch the band number.
    3931             :  *
    3932             :  * This method returns the band that this GDALRasterBand objects represents
    3933             :  * within its dataset.  This method may return a value of 0 to indicate
    3934             :  * GDALRasterBand objects without an apparently relationship to a dataset,
    3935             :  * such as GDALRasterBands serving as overviews.
    3936             :  *
    3937             :  * This method is the same as the C function GDALGetBandNumber().
    3938             :  *
    3939             :  * @return band number (1+) or 0 if the band number isn't known.
    3940             :  */
    3941             : 
    3942      150411 : int GDALRasterBand::GetBand() const
    3943             : 
    3944             : {
    3945      150411 :     return nBand;
    3946             : }
    3947             : 
    3948             : /************************************************************************/
    3949             : /*                         GDALGetBandNumber()                          */
    3950             : /************************************************************************/
    3951             : 
    3952             : /**
    3953             :  * \brief Fetch the band number.
    3954             :  *
    3955             :  * @see GDALRasterBand::GetBand()
    3956             :  */
    3957             : 
    3958         202 : int CPL_STDCALL GDALGetBandNumber(GDALRasterBandH hBand)
    3959             : 
    3960             : {
    3961         202 :     VALIDATE_POINTER1(hBand, "GDALGetBandNumber", 0);
    3962             : 
    3963         202 :     GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
    3964         202 :     return poBand->GetBand();
    3965             : }
    3966             : 
    3967             : /************************************************************************/
    3968             : /*                             GetDataset()                             */
    3969             : /************************************************************************/
    3970             : 
    3971             : /**
    3972             :  * \brief Fetch the owning dataset handle.
    3973             :  *
    3974             :  * Note that some GDALRasterBands are not considered to be a part of a dataset,
    3975             :  * such as overviews or other "freestanding" bands.
    3976             :  *
    3977             :  * This method is the same as the C function GDALGetBandDataset().
    3978             :  *
    3979             :  * @return the pointer to the GDALDataset to which this band belongs, or
    3980             :  * NULL if this cannot be determined.
    3981             :  */
    3982             : 
    3983     4550510 : GDALDataset *GDALRasterBand::GetDataset() const
    3984             : 
    3985             : {
    3986     4550510 :     return poDS;
    3987             : }
    3988             : 
    3989             : /************************************************************************/
    3990             : /*                         GDALGetBandDataset()                         */
    3991             : /************************************************************************/
    3992             : 
    3993             : /**
    3994             :  * \brief Fetch the owning dataset handle.
    3995             :  *
    3996             :  * @see GDALRasterBand::GetDataset()
    3997             :  */
    3998             : 
    3999         440 : GDALDatasetH CPL_STDCALL GDALGetBandDataset(GDALRasterBandH hBand)
    4000             : 
    4001             : {
    4002         440 :     VALIDATE_POINTER1(hBand, "GDALGetBandDataset", nullptr);
    4003             : 
    4004         440 :     GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
    4005         440 :     return GDALDataset::ToHandle(poBand->GetDataset());
    4006             : }
    4007             : 
    4008             : /************************************************************************/
    4009             : /*                        ComputeFloat16NoDataValue()                     */
    4010             : /************************************************************************/
    4011             : 
    4012        2057 : static inline void ComputeFloat16NoDataValue(GDALDataType eDataType,
    4013             :                                              double dfNoDataValue,
    4014             :                                              int &bGotNoDataValue,
    4015             :                                              GFloat16 &fNoDataValue,
    4016             :                                              bool &bGotFloat16NoDataValue)
    4017             : {
    4018        2057 :     if (eDataType == GDT_Float16 && bGotNoDataValue)
    4019             :     {
    4020           0 :         dfNoDataValue = GDALAdjustNoDataCloseToFloatMax(dfNoDataValue);
    4021           0 :         if (GDALIsValueInRange<GFloat16>(dfNoDataValue))
    4022             :         {
    4023           0 :             fNoDataValue = static_cast<GFloat16>(dfNoDataValue);
    4024           0 :             bGotFloat16NoDataValue = true;
    4025           0 :             bGotNoDataValue = false;
    4026             :         }
    4027             :     }
    4028        2057 : }
    4029             : 
    4030             : /************************************************************************/
    4031             : /*                        ComputeFloatNoDataValue()                     */
    4032             : /************************************************************************/
    4033             : 
    4034        2057 : static inline void ComputeFloatNoDataValue(GDALDataType eDataType,
    4035             :                                            double dfNoDataValue,
    4036             :                                            int &bGotNoDataValue,
    4037             :                                            float &fNoDataValue,
    4038             :                                            bool &bGotFloatNoDataValue)
    4039             : {
    4040        2057 :     if (eDataType == GDT_Float32 && bGotNoDataValue)
    4041             :     {
    4042          84 :         dfNoDataValue = GDALAdjustNoDataCloseToFloatMax(dfNoDataValue);
    4043          84 :         if (GDALIsValueInRange<float>(dfNoDataValue))
    4044             :         {
    4045          84 :             fNoDataValue = static_cast<float>(dfNoDataValue);
    4046          84 :             bGotFloatNoDataValue = true;
    4047          84 :             bGotNoDataValue = false;
    4048             :         }
    4049             :     }
    4050        2057 : }
    4051             : 
    4052             : /************************************************************************/
    4053             : /*                        struct GDALNoDataValues                       */
    4054             : /************************************************************************/
    4055             : 
    4056             : /**
    4057             :  * \brief No-data-values for all types
    4058             :  *
    4059             :  * The functions below pass various no-data-values around. To avoid
    4060             :  * long argument lists, this struct collects the no-data-values for
    4061             :  * all types into a single, convenient place.
    4062             :  **/
    4063             : 
    4064             : struct GDALNoDataValues
    4065             : {
    4066             :     int bGotNoDataValue;
    4067             :     double dfNoDataValue;
    4068             : 
    4069             :     bool bGotFloatNoDataValue;
    4070             :     float fNoDataValue;
    4071             : 
    4072             :     bool bGotFloat16NoDataValue;
    4073             :     GFloat16 hfNoDataValue;
    4074             : 
    4075        2057 :     GDALNoDataValues(GDALRasterBand *poRasterBand, GDALDataType eDataType)
    4076        2057 :         : bGotNoDataValue(FALSE), dfNoDataValue(0.0),
    4077             :           bGotFloatNoDataValue(false), fNoDataValue(0.0f),
    4078        2057 :           bGotFloat16NoDataValue(false), hfNoDataValue(GFloat16(0.0f))
    4079             :     {
    4080        2057 :         dfNoDataValue = poRasterBand->GetNoDataValue(&bGotNoDataValue);
    4081        2057 :         bGotNoDataValue = bGotNoDataValue && !std::isnan(dfNoDataValue);
    4082             : 
    4083        2057 :         ComputeFloatNoDataValue(eDataType, dfNoDataValue, bGotNoDataValue,
    4084        2057 :                                 fNoDataValue, bGotFloatNoDataValue);
    4085             : 
    4086        2057 :         ComputeFloat16NoDataValue(eDataType, dfNoDataValue, bGotNoDataValue,
    4087        2057 :                                   hfNoDataValue, bGotFloat16NoDataValue);
    4088        2057 :     }
    4089             : };
    4090             : 
    4091             : /************************************************************************/
    4092             : /*                            ARE_REAL_EQUAL()                          */
    4093             : /************************************************************************/
    4094             : 
    4095           0 : inline bool ARE_REAL_EQUAL(GFloat16 dfVal1, GFloat16 dfVal2, int ulp = 2)
    4096             : {
    4097             :     using std::abs;
    4098           0 :     return dfVal1 == dfVal2 || /* Should cover infinity */
    4099           0 :            abs(dfVal1 - dfVal2) < cpl::NumericLimits<GFloat16>::epsilon() *
    4100           0 :                                       abs(dfVal1 + dfVal2) * ulp;
    4101             : }
    4102             : 
    4103             : /************************************************************************/
    4104             : /*                            GetHistogram()                            */
    4105             : /************************************************************************/
    4106             : 
    4107             : /**
    4108             :  * \brief Compute raster histogram.
    4109             :  *
    4110             :  * Note that the bucket size is (dfMax-dfMin) / nBuckets.
    4111             :  *
    4112             :  * For example to compute a simple 256 entry histogram of eight bit data,
    4113             :  * the following would be suitable.  The unusual bounds are to ensure that
    4114             :  * bucket boundaries don't fall right on integer values causing possible errors
    4115             :  * due to rounding after scaling.
    4116             : \code{.cpp}
    4117             :     GUIntBig anHistogram[256];
    4118             : 
    4119             :     poBand->GetHistogram( -0.5, 255.5, 256, anHistogram, FALSE, FALSE,
    4120             :                           GDALDummyProgress, nullptr );
    4121             : \endcode
    4122             :  *
    4123             :  * Note that setting bApproxOK will generally result in a subsampling of the
    4124             :  * file, and will utilize overviews if available.  It should generally
    4125             :  * produce a representative histogram for the data that is suitable for use
    4126             :  * in generating histogram based luts for instance.  Generally bApproxOK is
    4127             :  * much faster than an exactly computed histogram.
    4128             :  *
    4129             :  * This method is the same as the C functions GDALGetRasterHistogram() and
    4130             :  * GDALGetRasterHistogramEx().
    4131             :  *
    4132             :  * @param dfMin the lower bound of the histogram.
    4133             :  * @param dfMax the upper bound of the histogram.
    4134             :  * @param nBuckets the number of buckets in panHistogram.
    4135             :  * @param panHistogram array into which the histogram totals are placed.
    4136             :  * @param bIncludeOutOfRange if TRUE values below the histogram range will
    4137             :  * mapped into panHistogram[0], and values above will be mapped into
    4138             :  * panHistogram[nBuckets-1] otherwise out of range values are discarded.
    4139             :  * @param bApproxOK TRUE if an approximate, or incomplete histogram OK.
    4140             :  * @param pfnProgress function to report progress to completion.
    4141             :  * @param pProgressData application data to pass to pfnProgress.
    4142             :  *
    4143             :  * @return CE_None on success, or CE_Failure if something goes wrong.
    4144             :  */
    4145             : 
    4146          40 : CPLErr GDALRasterBand::GetHistogram(double dfMin, double dfMax, int nBuckets,
    4147             :                                     GUIntBig *panHistogram,
    4148             :                                     int bIncludeOutOfRange, int bApproxOK,
    4149             :                                     GDALProgressFunc pfnProgress,
    4150             :                                     void *pProgressData)
    4151             : 
    4152             : {
    4153          40 :     CPLAssert(nullptr != panHistogram);
    4154             : 
    4155          40 :     if (pfnProgress == nullptr)
    4156          27 :         pfnProgress = GDALDummyProgress;
    4157             : 
    4158             :     /* -------------------------------------------------------------------- */
    4159             :     /*      If we have overviews, use them for the histogram.               */
    4160             :     /* -------------------------------------------------------------------- */
    4161          40 :     if (bApproxOK && GetOverviewCount() > 0 && !HasArbitraryOverviews())
    4162             :     {
    4163             :         // FIXME: should we use the most reduced overview here or use some
    4164             :         // minimum number of samples like GDALRasterBand::ComputeStatistics()
    4165             :         // does?
    4166           0 :         GDALRasterBand *poBestOverview = GetRasterSampleOverview(0);
    4167             : 
    4168           0 :         if (poBestOverview != this)
    4169             :         {
    4170           0 :             return poBestOverview->GetHistogram(
    4171             :                 dfMin, dfMax, nBuckets, panHistogram, bIncludeOutOfRange,
    4172           0 :                 bApproxOK, pfnProgress, pProgressData);
    4173             :         }
    4174             :     }
    4175             : 
    4176             :     /* -------------------------------------------------------------------- */
    4177             :     /*      Read actual data and build histogram.                           */
    4178             :     /* -------------------------------------------------------------------- */
    4179          40 :     if (!pfnProgress(0.0, "Compute Histogram", pProgressData))
    4180             :     {
    4181           0 :         ReportError(CE_Failure, CPLE_UserInterrupt, "User terminated");
    4182           0 :         return CE_Failure;
    4183             :     }
    4184             : 
    4185             :     // Written this way to deal with NaN
    4186          40 :     if (!(dfMax > dfMin))
    4187             :     {
    4188           5 :         ReportError(CE_Failure, CPLE_IllegalArg,
    4189             :                     "dfMax should be strictly greater than dfMin");
    4190           5 :         return CE_Failure;
    4191             :     }
    4192             : 
    4193             :     GDALRasterIOExtraArg sExtraArg;
    4194          35 :     INIT_RASTERIO_EXTRA_ARG(sExtraArg);
    4195             : 
    4196          35 :     const double dfScale = nBuckets / (dfMax - dfMin);
    4197          35 :     if (dfScale == 0 || !std::isfinite(dfScale))
    4198             :     {
    4199           5 :         ReportError(CE_Failure, CPLE_IllegalArg,
    4200             :                     "dfMin and dfMax should be finite values such that "
    4201             :                     "nBuckets / (dfMax - dfMin) is non-zero");
    4202           5 :         return CE_Failure;
    4203             :     }
    4204          30 :     memset(panHistogram, 0, sizeof(GUIntBig) * nBuckets);
    4205             : 
    4206          30 :     GDALNoDataValues sNoDataValues(this, eDataType);
    4207          30 :     GDALRasterBand *poMaskBand = nullptr;
    4208          30 :     if (!sNoDataValues.bGotNoDataValue)
    4209             :     {
    4210          29 :         const int l_nMaskFlags = GetMaskFlags();
    4211          30 :         if (l_nMaskFlags != GMF_ALL_VALID && l_nMaskFlags != GMF_NODATA &&
    4212           1 :             GetColorInterpretation() != GCI_AlphaBand)
    4213             :         {
    4214           1 :             poMaskBand = GetMaskBand();
    4215             :         }
    4216             :     }
    4217             : 
    4218          30 :     bool bSignedByte = false;
    4219          30 :     if (eDataType == GDT_Byte)
    4220             :     {
    4221          23 :         EnablePixelTypeSignedByteWarning(false);
    4222             :         const char *pszPixelType =
    4223          23 :             GetMetadataItem("PIXELTYPE", "IMAGE_STRUCTURE");
    4224          23 :         EnablePixelTypeSignedByteWarning(true);
    4225          23 :         bSignedByte =
    4226          23 :             pszPixelType != nullptr && EQUAL(pszPixelType, "SIGNEDBYTE");
    4227             :     }
    4228             : 
    4229          30 :     if (bApproxOK && HasArbitraryOverviews())
    4230             :     {
    4231             :         /* --------------------------------------------------------------------
    4232             :          */
    4233             :         /*      Figure out how much the image should be reduced to get an */
    4234             :         /*      approximate value. */
    4235             :         /* --------------------------------------------------------------------
    4236             :          */
    4237             :         const double dfReduction =
    4238           0 :             sqrt(static_cast<double>(nRasterXSize) * nRasterYSize /
    4239             :                  GDALSTAT_APPROX_NUMSAMPLES);
    4240             : 
    4241           0 :         int nXReduced = nRasterXSize;
    4242           0 :         int nYReduced = nRasterYSize;
    4243           0 :         if (dfReduction > 1.0)
    4244             :         {
    4245           0 :             nXReduced = static_cast<int>(nRasterXSize / dfReduction);
    4246           0 :             nYReduced = static_cast<int>(nRasterYSize / dfReduction);
    4247             : 
    4248             :             // Catch the case of huge resizing ratios here
    4249           0 :             if (nXReduced == 0)
    4250           0 :                 nXReduced = 1;
    4251           0 :             if (nYReduced == 0)
    4252           0 :                 nYReduced = 1;
    4253             :         }
    4254             : 
    4255           0 :         void *pData = VSI_MALLOC3_VERBOSE(GDALGetDataTypeSizeBytes(eDataType),
    4256             :                                           nXReduced, nYReduced);
    4257           0 :         if (!pData)
    4258           0 :             return CE_Failure;
    4259             : 
    4260             :         const CPLErr eErr =
    4261           0 :             IRasterIO(GF_Read, 0, 0, nRasterXSize, nRasterYSize, pData,
    4262           0 :                       nXReduced, nYReduced, eDataType, 0, 0, &sExtraArg);
    4263           0 :         if (eErr != CE_None)
    4264             :         {
    4265           0 :             CPLFree(pData);
    4266           0 :             return eErr;
    4267             :         }
    4268             : 
    4269           0 :         GByte *pabyMaskData = nullptr;
    4270           0 :         if (poMaskBand)
    4271             :         {
    4272             :             pabyMaskData =
    4273           0 :                 static_cast<GByte *>(VSI_MALLOC2_VERBOSE(nXReduced, nYReduced));
    4274           0 :             if (!pabyMaskData)
    4275             :             {
    4276           0 :                 CPLFree(pData);
    4277           0 :                 return CE_Failure;
    4278             :             }
    4279             : 
    4280           0 :             if (poMaskBand->RasterIO(GF_Read, 0, 0, nRasterXSize, nRasterYSize,
    4281             :                                      pabyMaskData, nXReduced, nYReduced,
    4282           0 :                                      GDT_Byte, 0, 0, nullptr) != CE_None)
    4283             :             {
    4284           0 :                 CPLFree(pData);
    4285           0 :                 CPLFree(pabyMaskData);
    4286           0 :                 return CE_Failure;
    4287             :             }
    4288             :         }
    4289             : 
    4290             :         // This isn't the fastest way to do this, but is easier for now.
    4291           0 :         for (int iY = 0; iY < nYReduced; iY++)
    4292             :         {
    4293           0 :             for (int iX = 0; iX < nXReduced; iX++)
    4294             :             {
    4295           0 :                 const int iOffset = iX + iY * nXReduced;
    4296           0 :                 double dfValue = 0.0;
    4297             : 
    4298           0 :                 if (pabyMaskData && pabyMaskData[iOffset] == 0)
    4299           0 :                     continue;
    4300             : 
    4301           0 :                 switch (eDataType)
    4302             :                 {
    4303           0 :                     case GDT_Byte:
    4304             :                     {
    4305           0 :                         if (bSignedByte)
    4306           0 :                             dfValue =
    4307           0 :                                 static_cast<signed char *>(pData)[iOffset];
    4308             :                         else
    4309           0 :                             dfValue = static_cast<GByte *>(pData)[iOffset];
    4310           0 :                         break;
    4311             :                     }
    4312           0 :                     case GDT_Int8:
    4313           0 :                         dfValue = static_cast<GInt8 *>(pData)[iOffset];
    4314           0 :                         break;
    4315           0 :                     case GDT_UInt16:
    4316           0 :                         dfValue = static_cast<GUInt16 *>(pData)[iOffset];
    4317           0 :                         break;
    4318           0 :                     case GDT_Int16:
    4319           0 :                         dfValue = static_cast<GInt16 *>(pData)[iOffset];
    4320           0 :                         break;
    4321           0 :                     case GDT_UInt32:
    4322           0 :                         dfValue = static_cast<GUInt32 *>(pData)[iOffset];
    4323           0 :                         break;
    4324           0 :                     case GDT_Int32:
    4325           0 :                         dfValue = static_cast<GInt32 *>(pData)[iOffset];
    4326           0 :                         break;
    4327           0 :                     case GDT_UInt64:
    4328           0 :                         dfValue = static_cast<double>(
    4329           0 :                             static_cast<GUInt64 *>(pData)[iOffset]);
    4330           0 :                         break;
    4331           0 :                     case GDT_Int64:
    4332           0 :                         dfValue = static_cast<double>(
    4333           0 :                             static_cast<GInt64 *>(pData)[iOffset]);
    4334           0 :                         break;
    4335           0 :                     case GDT_Float16:
    4336             :                     {
    4337             :                         using namespace std;
    4338           0 :                         const GFloat16 hfValue =
    4339           0 :                             static_cast<GFloat16 *>(pData)[iOffset];
    4340           0 :                         if (isnan(hfValue) ||
    4341           0 :                             (sNoDataValues.bGotFloat16NoDataValue &&
    4342           0 :                              ARE_REAL_EQUAL(hfValue,
    4343             :                                             sNoDataValues.hfNoDataValue)))
    4344           0 :                             continue;
    4345           0 :                         dfValue = hfValue;
    4346           0 :                         break;
    4347             :                     }
    4348           0 :                     case GDT_Float32:
    4349             :                     {
    4350           0 :                         const float fValue =
    4351           0 :                             static_cast<float *>(pData)[iOffset];
    4352           0 :                         if (std::isnan(fValue) ||
    4353           0 :                             (sNoDataValues.bGotFloatNoDataValue &&
    4354           0 :                              ARE_REAL_EQUAL(fValue,
    4355             :                                             sNoDataValues.fNoDataValue)))
    4356           0 :                             continue;
    4357           0 :                         dfValue = fValue;
    4358           0 :                         break;
    4359             :                     }
    4360           0 :                     case GDT_Float64:
    4361           0 :                         dfValue = static_cast<double *>(pData)[iOffset];
    4362           0 :                         if (std::isnan(dfValue))
    4363           0 :                             continue;
    4364           0 :                         break;
    4365           0 :                     case GDT_CInt16:
    4366             :                     {
    4367           0 :                         const double dfReal =
    4368           0 :                             static_cast<GInt16 *>(pData)[iOffset * 2];
    4369           0 :                         const double dfImag =
    4370           0 :                             static_cast<GInt16 *>(pData)[iOffset * 2 + 1];
    4371           0 :                         if (std::isnan(dfReal) || std::isnan(dfImag))
    4372           0 :                             continue;
    4373           0 :                         dfValue = sqrt(dfReal * dfReal + dfImag * dfImag);
    4374             :                     }
    4375           0 :                     break;
    4376           0 :                     case GDT_CInt32:
    4377             :                     {
    4378           0 :                         const double dfReal =
    4379           0 :                             static_cast<GInt32 *>(pData)[iOffset * 2];
    4380           0 :                         const double dfImag =
    4381           0 :                             static_cast<GInt32 *>(pData)[iOffset * 2 + 1];
    4382           0 :                         if (std::isnan(dfReal) || std::isnan(dfImag))
    4383           0 :                             continue;
    4384           0 :                         dfValue = sqrt(dfReal * dfReal + dfImag * dfImag);
    4385             :                     }
    4386           0 :                     break;
    4387           0 :                     case GDT_CFloat16:
    4388             :                     {
    4389             :                         const double dfReal =
    4390           0 :                             static_cast<GFloat16 *>(pData)[iOffset * 2];
    4391             :                         const double dfImag =
    4392           0 :                             static_cast<GFloat16 *>(pData)[iOffset * 2 + 1];
    4393           0 :                         if (std::isnan(dfReal) || std::isnan(dfImag))
    4394           0 :                             continue;
    4395           0 :                         dfValue = sqrt(dfReal * dfReal + dfImag * dfImag);
    4396           0 :                         break;
    4397             :                     }
    4398           0 :                     case GDT_CFloat32:
    4399             :                     {
    4400           0 :                         const double dfReal =
    4401           0 :                             static_cast<float *>(pData)[iOffset * 2];
    4402           0 :                         const double dfImag =
    4403           0 :                             static_cast<float *>(pData)[iOffset * 2 + 1];
    4404           0 :                         if (std::isnan(dfReal) || std::isnan(dfImag))
    4405           0 :                             continue;
    4406           0 :                         dfValue = sqrt(dfReal * dfReal + dfImag * dfImag);
    4407           0 :                         break;
    4408             :                     }
    4409           0 :                     case GDT_CFloat64:
    4410             :                     {
    4411           0 :                         const double dfReal =
    4412           0 :                             static_cast<double *>(pData)[iOffset * 2];
    4413           0 :                         const double dfImag =
    4414           0 :                             static_cast<double *>(pData)[iOffset * 2 + 1];
    4415           0 :                         if (std::isnan(dfReal) || std::isnan(dfImag))
    4416           0 :                             continue;
    4417           0 :                         dfValue = sqrt(dfReal * dfReal + dfImag * dfImag);
    4418           0 :                         break;
    4419             :                     }
    4420           0 :                     case GDT_Unknown:
    4421             :                     case GDT_TypeCount:
    4422           0 :                         CPLAssert(false);
    4423             :                 }
    4424             : 
    4425           0 :                 if (eDataType != GDT_Float16 && eDataType != GDT_Float32 &&
    4426           0 :                     sNoDataValues.bGotNoDataValue &&
    4427           0 :                     ARE_REAL_EQUAL(dfValue, sNoDataValues.dfNoDataValue))
    4428           0 :                     continue;
    4429             : 
    4430             :                 // Given that dfValue and dfMin are not NaN, and dfScale > 0 and
    4431             :                 // finite, the result of the multiplication cannot be NaN
    4432           0 :                 const double dfIndex = floor((dfValue - dfMin) * dfScale);
    4433             : 
    4434           0 :                 if (dfIndex < 0)
    4435             :                 {
    4436           0 :                     if (bIncludeOutOfRange)
    4437           0 :                         panHistogram[0]++;
    4438             :                 }
    4439           0 :                 else if (dfIndex >= nBuckets)
    4440             :                 {
    4441           0 :                     if (bIncludeOutOfRange)
    4442           0 :                         ++panHistogram[nBuckets - 1];
    4443             :                 }
    4444             :                 else
    4445             :                 {
    4446           0 :                     ++panHistogram[static_cast<int>(dfIndex)];
    4447             :                 }
    4448             :             }
    4449             :         }
    4450             : 
    4451           0 :         CPLFree(pData);
    4452           0 :         CPLFree(pabyMaskData);
    4453             :     }
    4454             :     else  // No arbitrary overviews.
    4455             :     {
    4456          30 :         if (!InitBlockInfo())
    4457           0 :             return CE_Failure;
    4458             : 
    4459             :         /* --------------------------------------------------------------------
    4460             :          */
    4461             :         /*      Figure out the ratio of blocks we will read to get an */
    4462             :         /*      approximate value. */
    4463             :         /* --------------------------------------------------------------------
    4464             :          */
    4465             : 
    4466          30 :         int nSampleRate = 1;
    4467          30 :         if (bApproxOK)
    4468             :         {
    4469           8 :             nSampleRate = static_cast<int>(std::max(
    4470          16 :                 1.0,
    4471           8 :                 sqrt(static_cast<double>(nBlocksPerRow) * nBlocksPerColumn)));
    4472             :             // We want to avoid probing only the first column of blocks for
    4473             :             // a square shaped raster, because it is not unlikely that it may
    4474             :             // be padding only (#6378).
    4475           8 :             if (nSampleRate == nBlocksPerRow && nBlocksPerRow > 1)
    4476           1 :                 nSampleRate += 1;
    4477             :         }
    4478             : 
    4479          30 :         GByte *pabyMaskData = nullptr;
    4480          30 :         if (poMaskBand)
    4481             :         {
    4482             :             pabyMaskData = static_cast<GByte *>(
    4483           1 :                 VSI_MALLOC2_VERBOSE(nBlockXSize, nBlockYSize));
    4484           1 :             if (!pabyMaskData)
    4485             :             {
    4486           0 :                 return CE_Failure;
    4487             :             }
    4488             :         }
    4489             : 
    4490             :         /* --------------------------------------------------------------------
    4491             :          */
    4492             :         /*      Read the blocks, and add to histogram. */
    4493             :         /* --------------------------------------------------------------------
    4494             :          */
    4495          30 :         for (GIntBig iSampleBlock = 0;
    4496         150 :              iSampleBlock <
    4497         150 :              static_cast<GIntBig>(nBlocksPerRow) * nBlocksPerColumn;
    4498         120 :              iSampleBlock += nSampleRate)
    4499             :         {
    4500         120 :             if (!pfnProgress(
    4501         120 :                     static_cast<double>(iSampleBlock) /
    4502         120 :                         (static_cast<double>(nBlocksPerRow) * nBlocksPerColumn),
    4503             :                     "Compute Histogram", pProgressData))
    4504             :             {
    4505           0 :                 CPLFree(pabyMaskData);
    4506           0 :                 return CE_Failure;
    4507             :             }
    4508             : 
    4509         120 :             const int iYBlock = static_cast<int>(iSampleBlock / nBlocksPerRow);
    4510         120 :             const int iXBlock = static_cast<int>(iSampleBlock % nBlocksPerRow);
    4511             : 
    4512         120 :             GDALRasterBlock *poBlock = GetLockedBlockRef(iXBlock, iYBlock);
    4513         120 :             if (poBlock == nullptr)
    4514             :             {
    4515           0 :                 CPLFree(pabyMaskData);
    4516           0 :                 return CE_Failure;
    4517             :             }
    4518             : 
    4519         120 :             void *pData = poBlock->GetDataRef();
    4520             : 
    4521         120 :             int nXCheck = 0, nYCheck = 0;
    4522         120 :             GetActualBlockSize(iXBlock, iYBlock, &nXCheck, &nYCheck);
    4523             : 
    4524         121 :             if (poMaskBand &&
    4525           1 :                 poMaskBand->RasterIO(GF_Read, iXBlock * nBlockXSize,
    4526           1 :                                      iYBlock * nBlockYSize, nXCheck, nYCheck,
    4527             :                                      pabyMaskData, nXCheck, nYCheck, GDT_Byte,
    4528           1 :                                      0, nBlockXSize, nullptr) != CE_None)
    4529             :             {
    4530           0 :                 CPLFree(pabyMaskData);
    4531           0 :                 poBlock->DropLock();
    4532           0 :                 return CE_Failure;
    4533             :             }
    4534             : 
    4535             :             // this is a special case for a common situation.
    4536         120 :             if (eDataType == GDT_Byte && !bSignedByte && dfScale == 1.0 &&
    4537          86 :                 (dfMin >= -0.5 && dfMin <= 0.5) && nYCheck == nBlockYSize &&
    4538          83 :                 nXCheck == nBlockXSize && nBuckets == 256)
    4539             :             {
    4540          83 :                 const GPtrDiff_t nPixels =
    4541          83 :                     static_cast<GPtrDiff_t>(nXCheck) * nYCheck;
    4542          83 :                 GByte *pabyData = static_cast<GByte *>(pData);
    4543             : 
    4544       72137 :                 for (GPtrDiff_t i = 0; i < nPixels; i++)
    4545             :                 {
    4546       72054 :                     if (pabyMaskData && pabyMaskData[i] == 0)
    4547           0 :                         continue;
    4548       72054 :                     if (!(sNoDataValues.bGotNoDataValue &&
    4549         512 :                           (pabyData[i] ==
    4550         512 :                            static_cast<GByte>(sNoDataValues.dfNoDataValue))))
    4551             :                     {
    4552       71798 :                         panHistogram[pabyData[i]]++;
    4553             :                     }
    4554             :                 }
    4555             : 
    4556          83 :                 poBlock->DropLock();
    4557          83 :                 continue;  // To next sample block.
    4558             :             }
    4559             : 
    4560             :             // This isn't the fastest way to do this, but is easier for now.
    4561         253 :             for (int iY = 0; iY < nYCheck; iY++)
    4562             :             {
    4563       36385 :                 for (int iX = 0; iX < nXCheck; iX++)
    4564             :                 {
    4565       36169 :                     const GPtrDiff_t iOffset =
    4566       36169 :                         iX + static_cast<GPtrDiff_t>(iY) * nBlockXSize;
    4567             : 
    4568       36169 :                     if (pabyMaskData && pabyMaskData[iOffset] == 0)
    4569           1 :                         continue;
    4570             : 
    4571       36168 :                     double dfValue = 0.0;
    4572             : 
    4573       36168 :                     switch (eDataType)
    4574             :                     {
    4575       19716 :                         case GDT_Byte:
    4576             :                         {
    4577       19716 :                             if (bSignedByte)
    4578           0 :                                 dfValue =
    4579           0 :                                     static_cast<signed char *>(pData)[iOffset];
    4580             :                             else
    4581       19716 :                                 dfValue = static_cast<GByte *>(pData)[iOffset];
    4582       19716 :                             break;
    4583             :                         }
    4584           0 :                         case GDT_Int8:
    4585           0 :                             dfValue = static_cast<GInt8 *>(pData)[iOffset];
    4586           0 :                             break;
    4587       16384 :                         case GDT_UInt16:
    4588       16384 :                             dfValue = static_cast<GUInt16 *>(pData)[iOffset];
    4589       16384 :                             break;
    4590           2 :                         case GDT_Int16:
    4591           2 :                             dfValue = static_cast<GInt16 *>(pData)[iOffset];
    4592           2 :                             break;
    4593           0 :                         case GDT_UInt32:
    4594           0 :                             dfValue = static_cast<GUInt32 *>(pData)[iOffset];
    4595           0 :                             break;
    4596          60 :                         case GDT_Int32:
    4597          60 :                             dfValue = static_cast<GInt32 *>(pData)[iOffset];
    4598          60 :                             break;
    4599           0 :                         case GDT_UInt64:
    4600           0 :                             dfValue = static_cast<double>(
    4601           0 :                                 static_cast<GUInt64 *>(pData)[iOffset]);
    4602           0 :                             break;
    4603           0 :                         case GDT_Int64:
    4604           0 :                             dfValue = static_cast<double>(
    4605           0 :                                 static_cast<GInt64 *>(pData)[iOffset]);
    4606           0 :                             break;
    4607           0 :                         case GDT_Float16:
    4608             :                         {
    4609             :                             using namespace std;
    4610           0 :                             const GFloat16 hfValue =
    4611           0 :                                 static_cast<GFloat16 *>(pData)[iOffset];
    4612           0 :                             if (isnan(hfValue) ||
    4613           0 :                                 (sNoDataValues.bGotFloat16NoDataValue &&
    4614           0 :                                  ARE_REAL_EQUAL(hfValue,
    4615             :                                                 sNoDataValues.hfNoDataValue)))
    4616           0 :                                 continue;
    4617           0 :                             dfValue = hfValue;
    4618           0 :                             break;
    4619             :                         }
    4620           4 :                         case GDT_Float32:
    4621             :                         {
    4622           4 :                             const float fValue =
    4623           4 :                                 static_cast<float *>(pData)[iOffset];
    4624           8 :                             if (std::isnan(fValue) ||
    4625           8 :                                 (sNoDataValues.bGotFloatNoDataValue &&
    4626           4 :                                  ARE_REAL_EQUAL(fValue,
    4627             :                                                 sNoDataValues.fNoDataValue)))
    4628           1 :                                 continue;
    4629           3 :                             dfValue = fValue;
    4630           3 :                             break;
    4631             :                         }
    4632           2 :                         case GDT_Float64:
    4633           2 :                             dfValue = static_cast<double *>(pData)[iOffset];
    4634           2 :                             if (std::isnan(dfValue))
    4635           0 :                                 continue;
    4636           2 :                             break;
    4637           0 :                         case GDT_CInt16:
    4638             :                         {
    4639           0 :                             double dfReal =
    4640           0 :                                 static_cast<GInt16 *>(pData)[iOffset * 2];
    4641           0 :                             double dfImag =
    4642           0 :                                 static_cast<GInt16 *>(pData)[iOffset * 2 + 1];
    4643           0 :                             dfValue = sqrt(dfReal * dfReal + dfImag * dfImag);
    4644           0 :                             break;
    4645             :                         }
    4646           0 :                         case GDT_CInt32:
    4647             :                         {
    4648           0 :                             double dfReal =
    4649           0 :                                 static_cast<GInt32 *>(pData)[iOffset * 2];
    4650           0 :                             double dfImag =
    4651           0 :                                 static_cast<GInt32 *>(pData)[iOffset * 2 + 1];
    4652           0 :                             dfValue = sqrt(dfReal * dfReal + dfImag * dfImag);
    4653           0 :                             break;
    4654             :                         }
    4655           0 :                         case GDT_CFloat16:
    4656             :                         {
    4657             :                             double dfReal =
    4658           0 :                                 static_cast<GFloat16 *>(pData)[iOffset * 2];
    4659             :                             double dfImag =
    4660           0 :                                 static_cast<GFloat16 *>(pData)[iOffset * 2 + 1];
    4661           0 :                             if (std::isnan(dfReal) || std::isnan(dfImag))
    4662           0 :                                 continue;
    4663           0 :                             dfValue = sqrt(dfReal * dfReal + dfImag * dfImag);
    4664           0 :                             break;
    4665             :                         }
    4666           0 :                         case GDT_CFloat32:
    4667             :                         {
    4668           0 :                             double dfReal =
    4669           0 :                                 static_cast<float *>(pData)[iOffset * 2];
    4670           0 :                             double dfImag =
    4671           0 :                                 static_cast<float *>(pData)[iOffset * 2 + 1];
    4672           0 :                             if (std::isnan(dfReal) || std::isnan(dfImag))
    4673           0 :                                 continue;
    4674           0 :                             dfValue = sqrt(dfReal * dfReal + dfImag * dfImag);
    4675           0 :                             break;
    4676             :                         }
    4677           0 :                         case GDT_CFloat64:
    4678             :                         {
    4679           0 :                             double dfReal =
    4680           0 :                                 static_cast<double *>(pData)[iOffset * 2];
    4681           0 :                             double dfImag =
    4682           0 :                                 static_cast<double *>(pData)[iOffset * 2 + 1];
    4683           0 :                             if (std::isnan(dfReal) || std::isnan(dfImag))
    4684           0 :                                 continue;
    4685           0 :                             dfValue = sqrt(dfReal * dfReal + dfImag * dfImag);
    4686           0 :                             break;
    4687             :                         }
    4688           0 :                         case GDT_Unknown:
    4689             :                         case GDT_TypeCount:
    4690           0 :                             CPLAssert(false);
    4691             :                             CPLFree(pabyMaskData);
    4692             :                             return CE_Failure;
    4693             :                     }
    4694             : 
    4695       36167 :                     if (eDataType != GDT_Float16 && eDataType != GDT_Float32 &&
    4696       72334 :                         sNoDataValues.bGotNoDataValue &&
    4697           0 :                         ARE_REAL_EQUAL(dfValue, sNoDataValues.dfNoDataValue))
    4698           0 :                         continue;
    4699             : 
    4700             :                     // Given that dfValue and dfMin are not NaN, and dfScale > 0
    4701             :                     // and finite, the result of the multiplication cannot be
    4702             :                     // NaN
    4703       36167 :                     const double dfIndex = floor((dfValue - dfMin) * dfScale);
    4704             : 
    4705       36167 :                     if (dfIndex < 0)
    4706             :                     {
    4707           1 :                         if (bIncludeOutOfRange)
    4708           1 :                             panHistogram[0]++;
    4709             :                     }
    4710       36166 :                     else if (dfIndex >= nBuckets)
    4711             :                     {
    4712           7 :                         if (bIncludeOutOfRange)
    4713           4 :                             ++panHistogram[nBuckets - 1];
    4714             :                     }
    4715             :                     else
    4716             :                     {
    4717       36159 :                         ++panHistogram[static_cast<int>(dfIndex)];
    4718             :                     }
    4719             :                 }
    4720             :             }
    4721             : 
    4722          37 :             poBlock->DropLock();
    4723             :         }
    4724             : 
    4725          30 :         CPLFree(pabyMaskData);
    4726             :     }
    4727             : 
    4728          30 :     pfnProgress(1.0, "Compute Histogram", pProgressData);
    4729             : 
    4730          30 :     return CE_None;
    4731             : }
    4732             : 
    4733             : /************************************************************************/
    4734             : /*                       GDALGetRasterHistogram()                       */
    4735             : /************************************************************************/
    4736             : 
    4737             : /**
    4738             :  * \brief Compute raster histogram.
    4739             :  *
    4740             :  * Use GDALGetRasterHistogramEx() instead to get correct counts for values
    4741             :  * exceeding 2 billion.
    4742             :  *
    4743             :  * @see GDALRasterBand::GetHistogram()
    4744             :  * @see GDALGetRasterHistogramEx()
    4745             :  */
    4746             : 
    4747           0 : CPLErr CPL_STDCALL GDALGetRasterHistogram(GDALRasterBandH hBand, double dfMin,
    4748             :                                           double dfMax, int nBuckets,
    4749             :                                           int *panHistogram,
    4750             :                                           int bIncludeOutOfRange, int bApproxOK,
    4751             :                                           GDALProgressFunc pfnProgress,
    4752             :                                           void *pProgressData)
    4753             : 
    4754             : {
    4755           0 :     VALIDATE_POINTER1(hBand, "GDALGetRasterHistogram", CE_Failure);
    4756           0 :     VALIDATE_POINTER1(panHistogram, "GDALGetRasterHistogram", CE_Failure);
    4757             : 
    4758           0 :     GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
    4759             : 
    4760             :     GUIntBig *panHistogramTemp =
    4761           0 :         static_cast<GUIntBig *>(VSIMalloc2(sizeof(GUIntBig), nBuckets));
    4762           0 :     if (panHistogramTemp == nullptr)
    4763             :     {
    4764           0 :         poBand->ReportError(CE_Failure, CPLE_OutOfMemory,
    4765             :                             "Out of memory in GDALGetRasterHistogram().");
    4766           0 :         return CE_Failure;
    4767             :     }
    4768             : 
    4769           0 :     CPLErr eErr = poBand->GetHistogram(dfMin, dfMax, nBuckets, panHistogramTemp,
    4770             :                                        bIncludeOutOfRange, bApproxOK,
    4771           0 :                                        pfnProgress, pProgressData);
    4772             : 
    4773           0 :     if (eErr == CE_None)
    4774             :     {
    4775           0 :         for (int i = 0; i < nBuckets; i++)
    4776             :         {
    4777           0 :             if (panHistogramTemp[i] > INT_MAX)
    4778             :             {
    4779           0 :                 CPLError(CE_Warning, CPLE_AppDefined,
    4780             :                          "Count for bucket %d, which is " CPL_FRMT_GUIB
    4781             :                          " exceeds maximum 32 bit value",
    4782           0 :                          i, panHistogramTemp[i]);
    4783           0 :                 panHistogram[i] = INT_MAX;
    4784             :             }
    4785             :             else
    4786             :             {
    4787           0 :                 panHistogram[i] = static_cast<int>(panHistogramTemp[i]);
    4788             :             }
    4789             :         }
    4790             :     }
    4791             : 
    4792           0 :     CPLFree(panHistogramTemp);
    4793             : 
    4794           0 :     return eErr;
    4795             : }
    4796             : 
    4797             : /************************************************************************/
    4798             : /*                      GDALGetRasterHistogramEx()                      */
    4799             : /************************************************************************/
    4800             : 
    4801             : /**
    4802             :  * \brief Compute raster histogram.
    4803             :  *
    4804             :  * @see GDALRasterBand::GetHistogram()
    4805             :  *
    4806             :  * @since GDAL 2.0
    4807             :  */
    4808             : 
    4809          26 : CPLErr CPL_STDCALL GDALGetRasterHistogramEx(
    4810             :     GDALRasterBandH hBand, double dfMin, double dfMax, int nBuckets,
    4811             :     GUIntBig *panHistogram, int bIncludeOutOfRange, int bApproxOK,
    4812             :     GDALProgressFunc pfnProgress, void *pProgressData)
    4813             : 
    4814             : {
    4815          26 :     VALIDATE_POINTER1(hBand, "GDALGetRasterHistogramEx", CE_Failure);
    4816          26 :     VALIDATE_POINTER1(panHistogram, "GDALGetRasterHistogramEx", CE_Failure);
    4817             : 
    4818          26 :     GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
    4819             : 
    4820          26 :     return poBand->GetHistogram(dfMin, dfMax, nBuckets, panHistogram,
    4821             :                                 bIncludeOutOfRange, bApproxOK, pfnProgress,
    4822          26 :                                 pProgressData);
    4823             : }
    4824             : 
    4825             : /************************************************************************/
    4826             : /*                        GetDefaultHistogram()                         */
    4827             : /************************************************************************/
    4828             : 
    4829             : /**
    4830             :  * \brief Fetch default raster histogram.
    4831             :  *
    4832             :  * The default method in GDALRasterBand will compute a default histogram. This
    4833             :  * method is overridden by derived classes (such as GDALPamRasterBand,
    4834             :  * VRTDataset, HFADataset...) that may be able to fetch efficiently an already
    4835             :  * stored histogram.
    4836             :  *
    4837             :  * This method is the same as the C functions GDALGetDefaultHistogram() and
    4838             :  * GDALGetDefaultHistogramEx().
    4839             :  *
    4840             :  * @param pdfMin pointer to double value that will contain the lower bound of
    4841             :  * the histogram.
    4842             :  * @param pdfMax pointer to double value that will contain the upper bound of
    4843             :  * the histogram.
    4844             :  * @param pnBuckets pointer to int value that will contain the number of buckets
    4845             :  * in *ppanHistogram.
    4846             :  * @param ppanHistogram pointer to array into which the histogram totals are
    4847             :  * placed. To be freed with VSIFree
    4848             :  * @param bForce TRUE to force the computation. If FALSE and no default
    4849             :  * histogram is available, the method will return CE_Warning
    4850             :  * @param pfnProgress function to report progress to completion.
    4851             :  * @param pProgressData application data to pass to pfnProgress.
    4852             :  *
    4853             :  * @return CE_None on success, CE_Failure if something goes wrong, or
    4854             :  * CE_Warning if no default histogram is available.
    4855             :  */
    4856             : 
    4857          22 : CPLErr GDALRasterBand::GetDefaultHistogram(double *pdfMin, double *pdfMax,
    4858             :                                            int *pnBuckets,
    4859             :                                            GUIntBig **ppanHistogram, int bForce,
    4860             :                                            GDALProgressFunc pfnProgress,
    4861             :                                            void *pProgressData)
    4862             : 
    4863             : {
    4864          22 :     CPLAssert(nullptr != pnBuckets);
    4865          22 :     CPLAssert(nullptr != ppanHistogram);
    4866          22 :     CPLAssert(nullptr != pdfMin);
    4867          22 :     CPLAssert(nullptr != pdfMax);
    4868             : 
    4869          22 :     *pnBuckets = 0;
    4870          22 :     *ppanHistogram = nullptr;
    4871             : 
    4872          22 :     if (!bForce)
    4873           5 :         return CE_Warning;
    4874             : 
    4875          17 :     const int nBuckets = 256;
    4876             : 
    4877          17 :     bool bSignedByte = false;
    4878          17 :     if (eDataType == GDT_Byte)
    4879             :     {
    4880          17 :         EnablePixelTypeSignedByteWarning(false);
    4881             :         const char *pszPixelType =
    4882          17 :             GetMetadataItem("PIXELTYPE", "IMAGE_STRUCTURE");
    4883          17 :         EnablePixelTypeSignedByteWarning(true);
    4884          17 :         bSignedByte =
    4885          17 :             pszPixelType != nullptr && EQUAL(pszPixelType, "SIGNEDBYTE");
    4886             :     }
    4887             : 
    4888          17 :     if (GetRasterDataType() == GDT_Byte && !bSignedByte)
    4889             :     {
    4890          17 :         *pdfMin = -0.5;
    4891          17 :         *pdfMax = 255.5;
    4892             :     }
    4893             :     else
    4894             :     {
    4895             : 
    4896             :         const CPLErr eErr =
    4897           0 :             GetStatistics(TRUE, TRUE, pdfMin, pdfMax, nullptr, nullptr);
    4898           0 :         const double dfHalfBucket = (*pdfMax - *pdfMin) / (2 * (nBuckets - 1));
    4899           0 :         *pdfMin -= dfHalfBucket;
    4900           0 :         *pdfMax += dfHalfBucket;
    4901             : 
    4902           0 :         if (eErr != CE_None)
    4903           0 :             return eErr;
    4904             :     }
    4905             : 
    4906          17 :     *ppanHistogram =
    4907          17 :         static_cast<GUIntBig *>(VSICalloc(sizeof(GUIntBig), nBuckets));
    4908          17 :     if (*ppanHistogram == nullptr)
    4909             :     {
    4910           0 :         ReportError(CE_Failure, CPLE_OutOfMemory,
    4911             :                     "Out of memory in InitBlockInfo().");
    4912           0 :         return CE_Failure;
    4913             :     }
    4914             : 
    4915          17 :     *pnBuckets = nBuckets;
    4916          34 :     CPLErr eErr = GetHistogram(*pdfMin, *pdfMax, *pnBuckets, *ppanHistogram,
    4917          17 :                                TRUE, FALSE, pfnProgress, pProgressData);
    4918          17 :     if (eErr != CE_None)
    4919             :     {
    4920           0 :         *pnBuckets = 0;
    4921             :     }
    4922          17 :     return eErr;
    4923             : }
    4924             : 
    4925             : /************************************************************************/
    4926             : /*                      GDALGetDefaultHistogram()                       */
    4927             : /************************************************************************/
    4928             : 
    4929             : /**
    4930             :  * \brief Fetch default raster histogram.
    4931             :  *
    4932             :  * Use GDALGetRasterHistogramEx() instead to get correct counts for values
    4933             :  * exceeding 2 billion.
    4934             :  *
    4935             :  * @see GDALRasterBand::GDALGetDefaultHistogram()
    4936             :  * @see GDALGetRasterHistogramEx()
    4937             :  */
    4938             : 
    4939           0 : CPLErr CPL_STDCALL GDALGetDefaultHistogram(GDALRasterBandH hBand,
    4940             :                                            double *pdfMin, double *pdfMax,
    4941             :                                            int *pnBuckets, int **ppanHistogram,
    4942             :                                            int bForce,
    4943             :                                            GDALProgressFunc pfnProgress,
    4944             :                                            void *pProgressData)
    4945             : 
    4946             : {
    4947           0 :     VALIDATE_POINTER1(hBand, "GDALGetDefaultHistogram", CE_Failure);
    4948           0 :     VALIDATE_POINTER1(pdfMin, "GDALGetDefaultHistogram", CE_Failure);
    4949           0 :     VALIDATE_POINTER1(pdfMax, "GDALGetDefaultHistogram", CE_Failure);
    4950           0 :     VALIDATE_POINTER1(pnBuckets, "GDALGetDefaultHistogram", CE_Failure);
    4951           0 :     VALIDATE_POINTER1(ppanHistogram, "GDALGetDefaultHistogram", CE_Failure);
    4952             : 
    4953           0 :     GDALRasterBand *const poBand = GDALRasterBand::FromHandle(hBand);
    4954           0 :     GUIntBig *panHistogramTemp = nullptr;
    4955           0 :     CPLErr eErr = poBand->GetDefaultHistogram(pdfMin, pdfMax, pnBuckets,
    4956             :                                               &panHistogramTemp, bForce,
    4957           0 :                                               pfnProgress, pProgressData);
    4958           0 :     if (eErr == CE_None)
    4959             :     {
    4960           0 :         const int nBuckets = *pnBuckets;
    4961           0 :         *ppanHistogram = static_cast<int *>(VSIMalloc2(sizeof(int), nBuckets));
    4962           0 :         if (*ppanHistogram == nullptr)
    4963             :         {
    4964           0 :             poBand->ReportError(CE_Failure, CPLE_OutOfMemory,
    4965             :                                 "Out of memory in GDALGetDefaultHistogram().");
    4966           0 :             VSIFree(panHistogramTemp);
    4967           0 :             return CE_Failure;
    4968             :         }
    4969             : 
    4970           0 :         for (int i = 0; i < nBuckets; ++i)
    4971             :         {
    4972           0 :             if (panHistogramTemp[i] > INT_MAX)
    4973             :             {
    4974           0 :                 CPLError(CE_Warning, CPLE_AppDefined,
    4975             :                          "Count for bucket %d, which is " CPL_FRMT_GUIB
    4976             :                          " exceeds maximum 32 bit value",
    4977           0 :                          i, panHistogramTemp[i]);
    4978           0 :                 (*ppanHistogram)[i] = INT_MAX;
    4979             :             }
    4980             :             else
    4981             :             {
    4982           0 :                 (*ppanHistogram)[i] = static_cast<int>(panHistogramTemp[i]);
    4983             :             }
    4984             :         }
    4985             : 
    4986           0 :         CPLFree(panHistogramTemp);
    4987             :     }
    4988             :     else
    4989             :     {
    4990           0 :         *ppanHistogram = nullptr;
    4991             :     }
    4992             : 
    4993           0 :     return eErr;
    4994             : }
    4995             : 
    4996             : /************************************************************************/
    4997             : /*                      GDALGetDefaultHistogramEx()                     */
    4998             : /************************************************************************/
    4999             : 
    5000             : /**
    5001             :  * \brief Fetch default raster histogram.
    5002             :  *
    5003             :  * @see GDALRasterBand::GetDefaultHistogram()
    5004             :  *
    5005             :  * @since GDAL 2.0
    5006             :  */
    5007             : 
    5008             : CPLErr CPL_STDCALL
    5009          28 : GDALGetDefaultHistogramEx(GDALRasterBandH hBand, double *pdfMin, double *pdfMax,
    5010             :                           int *pnBuckets, GUIntBig **ppanHistogram, int bForce,
    5011             :                           GDALProgressFunc pfnProgress, void *pProgressData)
    5012             : 
    5013             : {
    5014          28 :     VALIDATE_POINTER1(hBand, "GDALGetDefaultHistogram", CE_Failure);
    5015          28 :     VALIDATE_POINTER1(pdfMin, "GDALGetDefaultHistogram", CE_Failure);
    5016          28 :     VALIDATE_POINTER1(pdfMax, "GDALGetDefaultHistogram", CE_Failure);
    5017          28 :     VALIDATE_POINTER1(pnBuckets, "GDALGetDefaultHistogram", CE_Failure);
    5018          28 :     VALIDATE_POINTER1(ppanHistogram, "GDALGetDefaultHistogram", CE_Failure);
    5019             : 
    5020          28 :     GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
    5021          28 :     return poBand->GetDefaultHistogram(pdfMin, pdfMax, pnBuckets, ppanHistogram,
    5022          28 :                                        bForce, pfnProgress, pProgressData);
    5023             : }
    5024             : 
    5025             : /************************************************************************/
    5026             : /*                             AdviseRead()                             */
    5027             : /************************************************************************/
    5028             : 
    5029             : /**
    5030             :  * \fn GDALRasterBand::AdviseRead(int,int,int,int,int,int,GDALDataType,char**)
    5031             :  * \brief Advise driver of upcoming read requests.
    5032             :  *
    5033             :  * Some GDAL drivers operate more efficiently if they know in advance what
    5034             :  * set of upcoming read requests will be made.  The AdviseRead() method allows
    5035             :  * an application to notify the driver of the region of interest,
    5036             :  * and at what resolution the region will be read.
    5037             :  *
    5038             :  * Many drivers just ignore the AdviseRead() call, but it can dramatically
    5039             :  * accelerate access via some drivers.
    5040             :  *
    5041             :  * Depending on call paths, drivers might receive several calls to
    5042             :  * AdviseRead() with the same parameters.
    5043             :  *
    5044             :  * @param nXOff The pixel offset to the top left corner of the region
    5045             :  * of the band to be accessed.  This would be zero to start from the left side.
    5046             :  *
    5047             :  * @param nYOff The line offset to the top left corner of the region
    5048             :  * of the band to be accessed.  This would be zero to start from the top.
    5049             :  *
    5050             :  * @param nXSize The width of the region of the band to be accessed in pixels.
    5051             :  *
    5052             :  * @param nYSize The height of the region of the band to be accessed in lines.
    5053             :  *
    5054             :  * @param nBufXSize the width of the buffer image into which the desired region
    5055             :  * is to be read, or from which it is to be written.
    5056             :  *
    5057             :  * @param nBufYSize the height of the buffer image into which the desired
    5058             :  * region is to be read, or from which it is to be written.
    5059             :  *
    5060             :  * @param eBufType the type of the pixel values in the pData data buffer.  The
    5061             :  * pixel values will automatically be translated to/from the GDALRasterBand
    5062             :  * data type as needed.
    5063             :  *
    5064             :  * @param papszOptions a list of name=value strings with special control
    5065             :  * options.  Normally this is NULL.
    5066             :  *
    5067             :  * @return CE_Failure if the request is invalid and CE_None if it works or
    5068             :  * is ignored.
    5069             :  */
    5070             : 
    5071             : /**/
    5072             : /**/
    5073             : 
    5074      113773 : CPLErr GDALRasterBand::AdviseRead(int /*nXOff*/, int /*nYOff*/, int /*nXSize*/,
    5075             :                                   int /*nYSize*/, int /*nBufXSize*/,
    5076             :                                   int /*nBufYSize*/, GDALDataType /*eBufType*/,
    5077             :                                   char ** /*papszOptions*/)
    5078             : {
    5079      113773 :     return CE_None;
    5080             : }
    5081             : 
    5082             : /************************************************************************/
    5083             : /*                        GDALRasterAdviseRead()                        */
    5084             : /************************************************************************/
    5085             : 
    5086             : /**
    5087             :  * \brief Advise driver of upcoming read requests.
    5088             :  *
    5089             :  * @see GDALRasterBand::AdviseRead()
    5090             :  */
    5091             : 
    5092           2 : CPLErr CPL_STDCALL GDALRasterAdviseRead(GDALRasterBandH hBand, int nXOff,
    5093             :                                         int nYOff, int nXSize, int nYSize,
    5094             :                                         int nBufXSize, int nBufYSize,
    5095             :                                         GDALDataType eDT,
    5096             :                                         CSLConstList papszOptions)
    5097             : 
    5098             : {
    5099           2 :     VALIDATE_POINTER1(hBand, "GDALRasterAdviseRead", CE_Failure);
    5100             : 
    5101           2 :     GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
    5102           2 :     return poBand->AdviseRead(nXOff, nYOff, nXSize, nYSize, nBufXSize,
    5103             :                               nBufYSize, eDT,
    5104           2 :                               const_cast<char **>(papszOptions));
    5105             : }
    5106             : 
    5107             : /************************************************************************/
    5108             : /*                           GetStatistics()                            */
    5109             : /************************************************************************/
    5110             : 
    5111             : /**
    5112             :  * \brief Fetch image statistics.
    5113             :  *
    5114             :  * Returns the minimum, maximum, mean and standard deviation of all
    5115             :  * pixel values in this band.  If approximate statistics are sufficient,
    5116             :  * the bApproxOK flag can be set to true in which case overviews, or a
    5117             :  * subset of image tiles may be used in computing the statistics.
    5118             :  *
    5119             :  * If bForce is FALSE results will only be returned if it can be done
    5120             :  * quickly (i.e. without scanning the image, typically by using pre-existing
    5121             :  * STATISTICS_xxx metadata items). If bForce is FALSE and results cannot be
    5122             :  * returned efficiently, the method will return CE_Warning but no warning will
    5123             :  * be issued. This is a non-standard use of the CE_Warning return value
    5124             :  * to indicate "nothing done".
    5125             :  *
    5126             :  * If bForce is TRUE, and results are quickly available without scanning the
    5127             :  * image, they will be used. If bForce is TRUE and results are not quickly
    5128             :  * available, GetStatistics() forwards the computation to ComputeStatistics(),
    5129             :  * which will scan the image.
    5130             :  *
    5131             :  * To always force recomputation of statistics, use ComputeStatistics() instead
    5132             :  * of this method.
    5133             :  *
    5134             :  * Note that file formats using PAM (Persistent Auxiliary Metadata) services
    5135             :  * will generally cache statistics in the .pam file allowing fast fetch
    5136             :  * after the first request.
    5137             :  *
    5138             :  * This method is the same as the C function GDALGetRasterStatistics().
    5139             :  *
    5140             :  * @param bApproxOK If TRUE statistics may be computed based on overviews
    5141             :  * or a subset of all tiles.
    5142             :  *
    5143             :  * @param bForce If FALSE statistics will only be returned if it can
    5144             :  * be done without rescanning the image. If TRUE, statistics computation will
    5145             :  * be forced if pre-existing values are not quickly available.
    5146             :  *
    5147             :  * @param pdfMin Location into which to load image minimum (may be NULL).
    5148             :  *
    5149             :  * @param pdfMax Location into which to load image maximum (may be NULL).-
    5150             :  *
    5151             :  * @param pdfMean Location into which to load image mean (may be NULL).
    5152             :  *
    5153             :  * @param pdfStdDev Location into which to load image standard deviation
    5154             :  * (may be NULL).
    5155             :  *
    5156             :  * @return CE_None on success, CE_Warning if no values returned,
    5157             :  * CE_Failure if an error occurs.
    5158             :  */
    5159             : 
    5160         619 : CPLErr GDALRasterBand::GetStatistics(int bApproxOK, int bForce, double *pdfMin,
    5161             :                                      double *pdfMax, double *pdfMean,
    5162             :                                      double *pdfStdDev)
    5163             : 
    5164             : {
    5165             :     /* -------------------------------------------------------------------- */
    5166             :     /*      Do we already have metadata items for the requested values?     */
    5167             :     /* -------------------------------------------------------------------- */
    5168        1238 :     if ((pdfMin == nullptr ||
    5169         619 :          GetMetadataItem("STATISTICS_MINIMUM") != nullptr) &&
    5170         202 :         (pdfMax == nullptr ||
    5171         202 :          GetMetadataItem("STATISTICS_MAXIMUM") != nullptr) &&
    5172        1440 :         (pdfMean == nullptr || GetMetadataItem("STATISTICS_MEAN") != nullptr) &&
    5173         202 :         (pdfStdDev == nullptr ||
    5174         202 :          GetMetadataItem("STATISTICS_STDDEV") != nullptr))
    5175             :     {
    5176         202 :         if (!(GetMetadataItem("STATISTICS_APPROXIMATE") && !bApproxOK))
    5177             :         {
    5178         195 :             if (pdfMin != nullptr)
    5179         195 :                 *pdfMin = CPLAtofM(GetMetadataItem("STATISTICS_MINIMUM"));
    5180         195 :             if (pdfMax != nullptr)
    5181         195 :                 *pdfMax = CPLAtofM(GetMetadataItem("STATISTICS_MAXIMUM"));
    5182         195 :             if (pdfMean != nullptr)
    5183         195 :                 *pdfMean = CPLAtofM(GetMetadataItem("STATISTICS_MEAN"));
    5184         195 :             if (pdfStdDev != nullptr)
    5185         195 :                 *pdfStdDev = CPLAtofM(GetMetadataItem("STATISTICS_STDDEV"));
    5186             : 
    5187         195 :             return CE_None;
    5188             :         }
    5189             :     }
    5190             : 
    5191             :     /* -------------------------------------------------------------------- */
    5192             :     /*      Does the driver already know the min/max?                       */
    5193             :     /* -------------------------------------------------------------------- */
    5194         424 :     if (bApproxOK && pdfMean == nullptr && pdfStdDev == nullptr)
    5195             :     {
    5196           0 :         int bSuccessMin = FALSE;
    5197           0 :         int bSuccessMax = FALSE;
    5198             : 
    5199           0 :         const double dfMin = GetMinimum(&bSuccessMin);
    5200           0 :         const double dfMax = GetMaximum(&bSuccessMax);
    5201             : 
    5202           0 :         if (bSuccessMin && bSuccessMax)
    5203             :         {
    5204           0 :             if (pdfMin != nullptr)
    5205           0 :                 *pdfMin = dfMin;
    5206           0 :             if (pdfMax != nullptr)
    5207           0 :                 *pdfMax = dfMax;
    5208           0 :             return CE_None;
    5209             :         }
    5210             :     }
    5211             : 
    5212             :     /* -------------------------------------------------------------------- */
    5213             :     /*      Either return without results, or force computation.            */
    5214             :     /* -------------------------------------------------------------------- */
    5215         424 :     if (!bForce)
    5216         169 :         return CE_Warning;
    5217             :     else
    5218         255 :         return ComputeStatistics(bApproxOK, pdfMin, pdfMax, pdfMean, pdfStdDev,
    5219         255 :                                  GDALDummyProgress, nullptr);
    5220             : }
    5221             : 
    5222             : /************************************************************************/
    5223             : /*                      GDALGetRasterStatistics()                       */
    5224             : /************************************************************************/
    5225             : 
    5226             : /**
    5227             :  * \brief Fetch image statistics.
    5228             :  *
    5229             :  * @see GDALRasterBand::GetStatistics()
    5230             :  */
    5231             : 
    5232         268 : CPLErr CPL_STDCALL GDALGetRasterStatistics(GDALRasterBandH hBand, int bApproxOK,
    5233             :                                            int bForce, double *pdfMin,
    5234             :                                            double *pdfMax, double *pdfMean,
    5235             :                                            double *pdfStdDev)
    5236             : 
    5237             : {
    5238         268 :     VALIDATE_POINTER1(hBand, "GDALGetRasterStatistics", CE_Failure);
    5239             : 
    5240         268 :     GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
    5241         268 :     return poBand->GetStatistics(bApproxOK, bForce, pdfMin, pdfMax, pdfMean,
    5242         268 :                                  pdfStdDev);
    5243             : }
    5244             : 
    5245             : /************************************************************************/
    5246             : /*                         GDALUInt128                                  */
    5247             : /************************************************************************/
    5248             : 
    5249             : #ifdef HAVE_UINT128_T
    5250             : class GDALUInt128
    5251             : {
    5252             :     __uint128_t val;
    5253             : 
    5254         639 :     explicit GDALUInt128(__uint128_t valIn) : val(valIn)
    5255             :     {
    5256         639 :     }
    5257             : 
    5258             :   public:
    5259         426 :     static GDALUInt128 Mul(GUIntBig first, GUIntBig second)
    5260             :     {
    5261             :         // Evaluates to just a single mul on x86_64
    5262         426 :         return GDALUInt128(static_cast<__uint128_t>(first) * second);
    5263             :     }
    5264             : 
    5265         213 :     GDALUInt128 operator-(const GDALUInt128 &other) const
    5266             :     {
    5267         213 :         return GDALUInt128(val - other.val);
    5268             :     }
    5269             : 
    5270         204 :     operator double() const
    5271             :     {
    5272         204 :         return static_cast<double>(val);
    5273             :     }
    5274             : };
    5275             : #else
    5276             : 
    5277             : #if defined(_MSC_VER) && defined(_M_X64)
    5278             : #include <intrin.h>
    5279             : #endif
    5280             : 
    5281             : class GDALUInt128
    5282             : {
    5283             :     GUIntBig low, high;
    5284             : 
    5285             :     GDALUInt128(GUIntBig lowIn, GUIntBig highIn) : low(lowIn), high(highIn)
    5286             :     {
    5287             :     }
    5288             : 
    5289             :   public:
    5290             :     static GDALUInt128 Mul(GUIntBig first, GUIntBig second)
    5291             :     {
    5292             : #if defined(_MSC_VER) && defined(_M_X64)
    5293             :         GUIntBig highRes;
    5294             :         GUIntBig lowRes = _umul128(first, second, &highRes);
    5295             :         return GDALUInt128(lowRes, highRes);
    5296             : #else
    5297             :         const GUInt32 firstLow = static_cast<GUInt32>(first);
    5298             :         const GUInt32 firstHigh = static_cast<GUInt32>(first >> 32);
    5299             :         const GUInt32 secondLow = static_cast<GUInt32>(second);
    5300             :         const GUInt32 secondHigh = static_cast<GUInt32>(second >> 32);
    5301             :         GUIntBig highRes = 0;
    5302             :         const GUIntBig firstLowSecondHigh =
    5303             :             static_cast<GUIntBig>(firstLow) * secondHigh;
    5304             :         const GUIntBig firstHighSecondLow =
    5305             :             static_cast<GUIntBig>(firstHigh) * secondLow;
    5306             :         const GUIntBig middleTerm = firstLowSecondHigh + firstHighSecondLow;
    5307             :         if (middleTerm < firstLowSecondHigh)  // check for overflow
    5308             :             highRes += static_cast<GUIntBig>(1) << 32;
    5309             :         const GUIntBig firstLowSecondLow =
    5310             :             static_cast<GUIntBig>(firstLow) * secondLow;
    5311             :         GUIntBig lowRes = firstLowSecondLow + (middleTerm << 32);
    5312             :         if (lowRes < firstLowSecondLow)  // check for overflow
    5313             :             highRes++;
    5314             :         highRes +=
    5315             :             (middleTerm >> 32) + static_cast<GUIntBig>(firstHigh) * secondHigh;
    5316             :         return GDALUInt128(lowRes, highRes);
    5317             : #endif
    5318             :     }
    5319             : 
    5320             :     GDALUInt128 operator-(const GDALUInt128 &other) const
    5321             :     {
    5322             :         GUIntBig highRes = high - other.high;
    5323             :         GUIntBig lowRes = low - other.low;
    5324             :         if (lowRes > low)  // check for underflow
    5325             :             --highRes;
    5326             :         return GDALUInt128(lowRes, highRes);
    5327             :     }
    5328             : 
    5329             :     operator double() const
    5330             :     {
    5331             :         const double twoPow64 = 18446744073709551616.0;
    5332             :         return high * twoPow64 + low;
    5333             :     }
    5334             : };
    5335             : #endif
    5336             : 
    5337             : /************************************************************************/
    5338             : /*                    ComputeStatisticsInternal()                       */
    5339             : /************************************************************************/
    5340             : 
    5341             : // Just to make coverity scan happy w.r.t overflow_before_widen, but otherwise
    5342             : // not needed.
    5343             : #define static_cast_for_coverity_scan static_cast
    5344             : 
    5345             : // The rationale for below optimizations is detailed in statistics.txt
    5346             : 
    5347             : // Use with T = GByte or GUInt16 only !
    5348             : template <class T, bool COMPUTE_OTHER_STATS>
    5349             : struct ComputeStatisticsInternalGeneric
    5350             : {
    5351         206 :     static void f(int nXCheck, int nBlockXSize, int nYCheck, const T *pData,
    5352             :                   bool bHasNoData, GUInt32 nNoDataValue, GUInt32 &nMin,
    5353             :                   GUInt32 &nMax, GUIntBig &nSum, GUIntBig &nSumSquare,
    5354             :                   GUIntBig &nSampleCount, GUIntBig &nValidCount)
    5355             :     {
    5356             :         static_assert(std::is_same<T, GByte>::value ||
    5357             :                           std::is_same<T, GUInt16>::value,
    5358             :                       "bad type for T");
    5359         206 :         if (bHasNoData)
    5360             :         {
    5361             :             // General case
    5362         386 :             for (int iY = 0; iY < nYCheck; iY++)
    5363             :             {
    5364       81751 :                 for (int iX = 0; iX < nXCheck; iX++)
    5365             :                 {
    5366       81468 :                     const GPtrDiff_t iOffset =
    5367       81468 :                         iX + static_cast<GPtrDiff_t>(iY) * nBlockXSize;
    5368       81468 :                     const GUInt32 nValue = pData[iOffset];
    5369       81468 :                     if (nValue == nNoDataValue)
    5370         175 :                         continue;
    5371       81293 :                     if (nValue < nMin)
    5372          26 :                         nMin = nValue;
    5373       81293 :                     if (nValue > nMax)
    5374          57 :                         nMax = nValue;
    5375             :                     if constexpr (COMPUTE_OTHER_STATS)
    5376             :                     {
    5377       79657 :                         nValidCount++;
    5378       79657 :                         nSum += nValue;
    5379       79657 :                         nSumSquare +=
    5380       79657 :                             static_cast_for_coverity_scan<GUIntBig>(nValue) *
    5381       79657 :                             nValue;
    5382             :                     }
    5383             :                 }
    5384             :             }
    5385             :             if constexpr (COMPUTE_OTHER_STATS)
    5386             :             {
    5387          20 :                 nSampleCount += static_cast<GUIntBig>(nXCheck) * nYCheck;
    5388             :             }
    5389             :         }
    5390         113 :         else if (nMin == std::numeric_limits<T>::lowest() &&
    5391          10 :                  nMax == std::numeric_limits<T>::max())
    5392             :         {
    5393             :             if constexpr (COMPUTE_OTHER_STATS)
    5394             :             {
    5395             :                 // Optimization when there is no nodata and we know we have already
    5396             :                 // reached the min and max
    5397         208 :                 for (int iY = 0; iY < nYCheck; iY++)
    5398             :                 {
    5399             :                     int iX;
    5400        1002 :                     for (iX = 0; iX + 3 < nXCheck; iX += 4)
    5401             :                     {
    5402         800 :                         const GPtrDiff_t iOffset =
    5403         800 :                             iX + static_cast<GPtrDiff_t>(iY) * nBlockXSize;
    5404         800 :                         const GUIntBig nValue = pData[iOffset];
    5405         800 :                         const GUIntBig nValue2 = pData[iOffset + 1];
    5406         800 :                         const GUIntBig nValue3 = pData[iOffset + 2];
    5407         800 :                         const GUIntBig nValue4 = pData[iOffset + 3];
    5408         800 :                         nSum += nValue;
    5409         800 :                         nSumSquare += nValue * nValue;
    5410         800 :                         nSum += nValue2;
    5411         800 :                         nSumSquare += nValue2 * nValue2;
    5412         800 :                         nSum += nValue3;
    5413         800 :                         nSumSquare += nValue3 * nValue3;
    5414         800 :                         nSum += nValue4;
    5415         800 :                         nSumSquare += nValue4 * nValue4;
    5416             :                     }
    5417         207 :                     for (; iX < nXCheck; ++iX)
    5418             :                     {
    5419           5 :                         const GPtrDiff_t iOffset =
    5420           5 :                             iX + static_cast<GPtrDiff_t>(iY) * nBlockXSize;
    5421           5 :                         const GUIntBig nValue = pData[iOffset];
    5422           5 :                         nSum += nValue;
    5423           5 :                         nSumSquare += nValue * nValue;
    5424             :                     }
    5425             :                 }
    5426           6 :                 nSampleCount += static_cast<GUIntBig>(nXCheck) * nYCheck;
    5427           6 :                 nValidCount += static_cast<GUIntBig>(nXCheck) * nYCheck;
    5428             :             }
    5429             :         }
    5430             :         else
    5431             :         {
    5432        3430 :             for (int iY = 0; iY < nYCheck; iY++)
    5433             :             {
    5434             :                 int iX;
    5435      643294 :                 for (iX = 0; iX + 1 < nXCheck; iX += 2)
    5436             :                 {
    5437      639961 :                     const GPtrDiff_t iOffset =
    5438      639961 :                         iX + static_cast<GPtrDiff_t>(iY) * nBlockXSize;
    5439      639961 :                     const GUInt32 nValue = pData[iOffset];
    5440      639961 :                     const GUInt32 nValue2 = pData[iOffset + 1];
    5441      639961 :                     if (nValue < nValue2)
    5442             :                     {
    5443        2320 :                         if (nValue < nMin)
    5444          48 :                             nMin = nValue;
    5445        2320 :                         if (nValue2 > nMax)
    5446         116 :                             nMax = nValue2;
    5447             :                     }
    5448             :                     else
    5449             :                     {
    5450      637641 :                         if (nValue2 < nMin)
    5451          65 :                             nMin = nValue2;
    5452      637641 :                         if (nValue > nMax)
    5453         214 :                             nMax = nValue;
    5454             :                     }
    5455             :                     if constexpr (COMPUTE_OTHER_STATS)
    5456             :                     {
    5457      632911 :                         nSum += nValue;
    5458      632911 :                         nSumSquare +=
    5459      632911 :                             static_cast_for_coverity_scan<GUIntBig>(nValue) *
    5460      632911 :                             nValue;
    5461      632911 :                         nSum += nValue2;
    5462      632911 :                         nSumSquare +=
    5463      632911 :                             static_cast_for_coverity_scan<GUIntBig>(nValue2) *
    5464      632911 :                             nValue2;
    5465             :                     }
    5466             :                 }
    5467        3333 :                 if (iX < nXCheck)
    5468             :                 {
    5469          17 :                     const GPtrDiff_t iOffset =
    5470          17 :                         iX + static_cast<GPtrDiff_t>(iY) * nBlockXSize;
    5471          17 :                     const GUInt32 nValue = pData[iOffset];
    5472          17 :                     if (nValue < nMin)
    5473          12 :                         nMin = nValue;
    5474          17 :                     if (nValue > nMax)
    5475          13 :                         nMax = nValue;
    5476             :                     if (COMPUTE_OTHER_STATS)
    5477             :                     {
    5478           9 :                         nSum += nValue;
    5479           9 :                         nSumSquare +=
    5480           9 :                             static_cast_for_coverity_scan<GUIntBig>(nValue) *
    5481           9 :                             nValue;
    5482             :                     }
    5483             :                 }
    5484             :             }
    5485             :             if constexpr (COMPUTE_OTHER_STATS)
    5486             :             {
    5487          44 :                 nSampleCount += static_cast<GUIntBig>(nXCheck) * nYCheck;
    5488          44 :                 nValidCount += static_cast<GUIntBig>(nXCheck) * nYCheck;
    5489             :             }
    5490             :         }
    5491         206 :     }
    5492             : };
    5493             : 
    5494             : // Specialization for Byte that is mostly 32 bit friendly as it avoids
    5495             : // using 64bit accumulators in internal loops. This also slightly helps in
    5496             : // 64bit mode.
    5497             : template <bool COMPUTE_OTHER_STATS>
    5498             : struct ComputeStatisticsInternalGeneric<GByte, COMPUTE_OTHER_STATS>
    5499             : {
    5500       13497 :     static void f(int nXCheck, int nBlockXSize, int nYCheck, const GByte *pData,
    5501             :                   bool bHasNoData, GUInt32 nNoDataValue, GUInt32 &nMin,
    5502             :                   GUInt32 &nMax, GUIntBig &nSum, GUIntBig &nSumSquare,
    5503             :                   GUIntBig &nSampleCount, GUIntBig &nValidCount)
    5504             :     {
    5505       13497 :         int nOuterLoops = nXCheck / 65536;
    5506       13497 :         if (nXCheck % 65536)
    5507       13497 :             nOuterLoops++;
    5508             : 
    5509       13497 :         if (bHasNoData)
    5510             :         {
    5511             :             // General case
    5512       23475 :             for (int iY = 0; iY < nYCheck; iY++)
    5513             :             {
    5514       12901 :                 int iX = 0;
    5515       25802 :                 for (int k = 0; k < nOuterLoops; k++)
    5516             :                 {
    5517       12901 :                     int iMax = iX + 65536;
    5518       12901 :                     if (iMax > nXCheck)
    5519       12901 :                         iMax = nXCheck;
    5520       12901 :                     GUInt32 nSum32bit = 0;
    5521       12901 :                     GUInt32 nSumSquare32bit = 0;
    5522       12901 :                     GUInt32 nValidCount32bit = 0;
    5523       12901 :                     GUInt32 nSampleCount32bit = 0;
    5524    20707168 :                     for (; iX < iMax; iX++)
    5525             :                     {
    5526    20694316 :                         const GPtrDiff_t iOffset =
    5527    20694316 :                             iX + static_cast<GPtrDiff_t>(iY) * nBlockXSize;
    5528    20694316 :                         const GUInt32 nValue = pData[iOffset];
    5529             : 
    5530    20694316 :                         nSampleCount32bit++;
    5531    20694316 :                         if (nValue == nNoDataValue)
    5532    20353458 :                             continue;
    5533      340803 :                         if (nValue < nMin)
    5534         357 :                             nMin = nValue;
    5535      340803 :                         if (nValue > nMax)
    5536         813 :                             nMax = nValue;
    5537             :                         if constexpr (COMPUTE_OTHER_STATS)
    5538             :                         {
    5539       17058 :                             nValidCount32bit++;
    5540       17058 :                             nSum32bit += nValue;
    5541       17058 :                             nSumSquare32bit += nValue * nValue;
    5542             :                         }
    5543             :                     }
    5544             :                     if constexpr (COMPUTE_OTHER_STATS)
    5545             :                     {
    5546         652 :                         nSampleCount += nSampleCount32bit;
    5547         652 :                         nValidCount += nValidCount32bit;
    5548         652 :                         nSum += nSum32bit;
    5549         652 :                         nSumSquare += nSumSquare32bit;
    5550             :                     }
    5551             :                 }
    5552             :             }
    5553             :         }
    5554        2923 :         else if (nMin == 0 && nMax == 255)
    5555             :         {
    5556             :             if constexpr (COMPUTE_OTHER_STATS)
    5557             :             {
    5558             :                 // Optimization when there is no nodata and we know we have already
    5559             :                 // reached the min and max
    5560        2644 :                 for (int iY = 0; iY < nYCheck; iY++)
    5561             :                 {
    5562        2617 :                     int iX = 0;
    5563        5234 :                     for (int k = 0; k < nOuterLoops; k++)
    5564             :                     {
    5565        2617 :                         int iMax = iX + 65536;
    5566        2617 :                         if (iMax > nXCheck)
    5567        2617 :                             iMax = nXCheck;
    5568        2617 :                         GUInt32 nSum32bit = 0;
    5569        2617 :                         GUInt32 nSumSquare32bit = 0;
    5570      176297 :                         for (; iX + 3 < iMax; iX += 4)
    5571             :                         {
    5572      173680 :                             const GPtrDiff_t iOffset =
    5573      173680 :                                 iX + static_cast<GPtrDiff_t>(iY) * nBlockXSize;
    5574      173680 :                             const GUInt32 nValue = pData[iOffset];
    5575      173680 :                             const GUInt32 nValue2 = pData[iOffset + 1];
    5576      173680 :                             const GUInt32 nValue3 = pData[iOffset + 2];
    5577      173680 :                             const GUInt32 nValue4 = pData[iOffset + 3];
    5578      173680 :                             nSum32bit += nValue;
    5579      173680 :                             nSumSquare32bit += nValue * nValue;
    5580      173680 :                             nSum32bit += nValue2;
    5581      173680 :                             nSumSquare32bit += nValue2 * nValue2;
    5582      173680 :                             nSum32bit += nValue3;
    5583      173680 :                             nSumSquare32bit += nValue3 * nValue3;
    5584      173680 :                             nSum32bit += nValue4;
    5585      173680 :                             nSumSquare32bit += nValue4 * nValue4;
    5586             :                         }
    5587        2617 :                         nSum += nSum32bit;
    5588        2617 :                         nSumSquare += nSumSquare32bit;
    5589             :                     }
    5590        2620 :                     for (; iX < nXCheck; ++iX)
    5591             :                     {
    5592           3 :                         const GPtrDiff_t iOffset =
    5593           3 :                             iX + static_cast<GPtrDiff_t>(iY) * nBlockXSize;
    5594           3 :                         const GUIntBig nValue = pData[iOffset];
    5595           3 :                         nSum += nValue;
    5596           3 :                         nSumSquare += nValue * nValue;
    5597             :                     }
    5598             :                 }
    5599          27 :                 nSampleCount += static_cast<GUIntBig>(nXCheck) * nYCheck;
    5600          27 :                 nValidCount += static_cast<GUIntBig>(nXCheck) * nYCheck;
    5601          27 :             }
    5602             :         }
    5603             :         else
    5604             :         {
    5605        7451 :             for (int iY = 0; iY < nYCheck; iY++)
    5606             :             {
    5607        4555 :                 int iX = 0;
    5608        9110 :                 for (int k = 0; k < nOuterLoops; k++)
    5609             :                 {
    5610        4555 :                     int iMax = iX + 65536;
    5611        4555 :                     if (iMax > nXCheck)
    5612        4555 :                         iMax = nXCheck;
    5613        4555 :                     GUInt32 nSum32bit = 0;
    5614        4555 :                     GUInt32 nSumSquare32bit = 0;
    5615      159064 :                     for (; iX + 1 < iMax; iX += 2)
    5616             :                     {
    5617      154509 :                         const GPtrDiff_t iOffset =
    5618      154509 :                             iX + static_cast<GPtrDiff_t>(iY) * nBlockXSize;
    5619      154509 :                         const GUInt32 nValue = pData[iOffset];
    5620      154509 :                         const GUInt32 nValue2 = pData[iOffset + 1];
    5621      154509 :                         if (nValue < nValue2)
    5622             :                         {
    5623        8047 :                             if (nValue < nMin)
    5624         230 :                                 nMin = nValue;
    5625        8047 :                             if (nValue2 > nMax)
    5626         219 :                                 nMax = nValue2;
    5627             :                         }
    5628             :                         else
    5629             :                         {
    5630      146462 :                             if (nValue2 < nMin)
    5631         274 :                                 nMin = nValue2;
    5632      146462 :                             if (nValue > nMax)
    5633         775 :                                 nMax = nValue;
    5634             :                         }
    5635             :                         if constexpr (COMPUTE_OTHER_STATS)
    5636             :                         {
    5637      132489 :                             nSum32bit += nValue;
    5638      132489 :                             nSumSquare32bit += nValue * nValue;
    5639      132489 :                             nSum32bit += nValue2;
    5640      132489 :                             nSumSquare32bit += nValue2 * nValue2;
    5641             :                         }
    5642             :                     }
    5643             :                     if constexpr (COMPUTE_OTHER_STATS)
    5644             :                     {
    5645        1609 :                         nSum += nSum32bit;
    5646        1609 :                         nSumSquare += nSumSquare32bit;
    5647             :                     }
    5648             :                 }
    5649        4555 :                 if (iX < nXCheck)
    5650             :                 {
    5651        1400 :                     const GPtrDiff_t iOffset =
    5652        1400 :                         iX + static_cast<GPtrDiff_t>(iY) * nBlockXSize;
    5653        1400 :                     const GUInt32 nValue = pData[iOffset];
    5654        1400 :                     if (nValue < nMin)
    5655          50 :                         nMin = nValue;
    5656        1400 :                     if (nValue > nMax)
    5657          62 :                         nMax = nValue;
    5658             :                     if constexpr (COMPUTE_OTHER_STATS)
    5659             :                     {
    5660         312 :                         nSum += nValue;
    5661         312 :                         nSumSquare +=
    5662         312 :                             static_cast_for_coverity_scan<GUIntBig>(nValue) *
    5663         312 :                             nValue;
    5664             :                     }
    5665             :                 }
    5666             :             }
    5667             :             if constexpr (COMPUTE_OTHER_STATS)
    5668             :             {
    5669         908 :                 nSampleCount += static_cast<GUIntBig>(nXCheck) * nYCheck;
    5670         908 :                 nValidCount += static_cast<GUIntBig>(nXCheck) * nYCheck;
    5671             :             }
    5672             :         }
    5673       13497 :     }
    5674             : };
    5675             : 
    5676             : template <class T, bool COMPUTE_OTHER_STATS> struct ComputeStatisticsInternal
    5677             : {
    5678             :     static void f(int nXCheck, int nBlockXSize, int nYCheck, const T *pData,
    5679             :                   bool bHasNoData, GUInt32 nNoDataValue, GUInt32 &nMin,
    5680             :                   GUInt32 &nMax, GUIntBig &nSum, GUIntBig &nSumSquare,
    5681             :                   GUIntBig &nSampleCount, GUIntBig &nValidCount)
    5682             :     {
    5683             :         ComputeStatisticsInternalGeneric<T, COMPUTE_OTHER_STATS>::f(
    5684             :             nXCheck, nBlockXSize, nYCheck, pData, bHasNoData, nNoDataValue,
    5685             :             nMin, nMax, nSum, nSumSquare, nSampleCount, nValidCount);
    5686             :     }
    5687             : };
    5688             : 
    5689             : #if (defined(__x86_64__) || defined(_M_X64)) &&                                \
    5690             :     (defined(__GNUC__) || defined(_MSC_VER))
    5691             : 
    5692             : #include "gdal_avx2_emulation.hpp"
    5693             : 
    5694             : #define ZERO256 GDALmm256_setzero_si256()
    5695             : 
    5696             : template <bool COMPUTE_MIN, bool COMPUTE_MAX, bool COMPUTE_OTHER_STATS>
    5697             : static void
    5698       20930 : ComputeStatisticsByteNoNodata(GPtrDiff_t nBlockPixels,
    5699             :                               // assumed to be aligned on 256 bits
    5700             :                               const GByte *pData, GUInt32 &nMin, GUInt32 &nMax,
    5701             :                               GUIntBig &nSum, GUIntBig &nSumSquare,
    5702             :                               GUIntBig &nSampleCount, GUIntBig &nValidCount)
    5703             : {
    5704             :     // 32-byte alignment may not be enforced by linker, so do it at hand
    5705             :     GByte
    5706             :         aby32ByteUnaligned[32 + 32 + 32 + (COMPUTE_OTHER_STATS ? 32 + 32 : 0)];
    5707       20930 :     GByte *paby32ByteAligned =
    5708             :         aby32ByteUnaligned +
    5709       20930 :         (32 - (reinterpret_cast<GUIntptr_t>(aby32ByteUnaligned) % 32));
    5710       20930 :     GByte *pabyMin = paby32ByteAligned;
    5711       20930 :     GByte *pabyMax = paby32ByteAligned + 32;
    5712       20930 :     GUInt32 *panSum =
    5713             :         COMPUTE_OTHER_STATS
    5714             :             ? reinterpret_cast<GUInt32 *>(paby32ByteAligned + 32 * 2)
    5715             :             : nullptr;
    5716       20930 :     GUInt32 *panSumSquare =
    5717             :         COMPUTE_OTHER_STATS
    5718             :             ? reinterpret_cast<GUInt32 *>(paby32ByteAligned + 32 * 3)
    5719             :             : nullptr;
    5720             : 
    5721       20930 :     CPLAssert((reinterpret_cast<uintptr_t>(pData) % 32) == 0);
    5722             : 
    5723       20930 :     GPtrDiff_t i = 0;
    5724             :     // Make sure that sumSquare can fit on uint32
    5725             :     // * 8 since we can hold 8 sums per vector register
    5726       20930 :     const int nMaxIterationsPerInnerLoop =
    5727             :         8 * ((std::numeric_limits<GUInt32>::max() / (255 * 255)) & ~31);
    5728       20930 :     GPtrDiff_t nOuterLoops = nBlockPixels / nMaxIterationsPerInnerLoop;
    5729       20930 :     if ((nBlockPixels % nMaxIterationsPerInnerLoop) != 0)
    5730       20930 :         nOuterLoops++;
    5731             : 
    5732             :     GDALm256i ymm_min =
    5733       20930 :         GDALmm256_load_si256(reinterpret_cast<const GDALm256i *>(pData + i));
    5734       20930 :     GDALm256i ymm_max = ymm_min;
    5735       20930 :     [[maybe_unused]] const auto ymm_mask_8bits = GDALmm256_set1_epi16(0xFF);
    5736             : 
    5737       41860 :     for (GPtrDiff_t k = 0; k < nOuterLoops; k++)
    5738             :     {
    5739       20930 :         const auto iMax =
    5740       20930 :             std::min(nBlockPixels, i + nMaxIterationsPerInnerLoop);
    5741             : 
    5742             :         // holds 4 uint32 sums in [0], [2], [4] and [6]
    5743       20930 :         [[maybe_unused]] GDALm256i ymm_sum = ZERO256;
    5744             :         [[maybe_unused]] GDALm256i ymm_sumsquare =
    5745       20930 :             ZERO256;  // holds 8 uint32 sums
    5746      705499 :         for (; i + 31 < iMax; i += 32)
    5747             :         {
    5748      684569 :             const GDALm256i ymm = GDALmm256_load_si256(
    5749      684569 :                 reinterpret_cast<const GDALm256i *>(pData + i));
    5750             :             if (COMPUTE_MIN)
    5751             :             {
    5752      226732 :                 ymm_min = GDALmm256_min_epu8(ymm_min, ymm);
    5753             :             }
    5754             :             if (COMPUTE_MAX)
    5755             :             {
    5756      593628 :                 ymm_max = GDALmm256_max_epu8(ymm_max, ymm);
    5757             :             }
    5758             : 
    5759             :             if constexpr (COMPUTE_OTHER_STATS)
    5760             :             {
    5761             :                 // Extract even-8bit values
    5762             :                 const GDALm256i ymm_even =
    5763      493495 :                     GDALmm256_and_si256(ymm, ymm_mask_8bits);
    5764             :                 // Compute square of those 16 values as 32 bit result
    5765             :                 // and add adjacent pairs
    5766             :                 const GDALm256i ymm_even_square =
    5767      493495 :                     GDALmm256_madd_epi16(ymm_even, ymm_even);
    5768             :                 // Add to the sumsquare accumulator
    5769             :                 ymm_sumsquare =
    5770      493495 :                     GDALmm256_add_epi32(ymm_sumsquare, ymm_even_square);
    5771             : 
    5772             :                 // Extract odd-8bit values
    5773      493495 :                 const GDALm256i ymm_odd = GDALmm256_srli_epi16(ymm, 8);
    5774             :                 const GDALm256i ymm_odd_square =
    5775      493495 :                     GDALmm256_madd_epi16(ymm_odd, ymm_odd);
    5776             :                 ymm_sumsquare =
    5777      493495 :                     GDALmm256_add_epi32(ymm_sumsquare, ymm_odd_square);
    5778             : 
    5779             :                 // Now compute the sums
    5780      493495 :                 ymm_sum = GDALmm256_add_epi32(ymm_sum,
    5781             :                                               GDALmm256_sad_epu8(ymm, ZERO256));
    5782             :             }
    5783             :         }
    5784             : 
    5785             :         if constexpr (COMPUTE_OTHER_STATS)
    5786             :         {
    5787       10649 :             GDALmm256_store_si256(reinterpret_cast<GDALm256i *>(panSum),
    5788             :                                   ymm_sum);
    5789       10649 :             GDALmm256_store_si256(reinterpret_cast<GDALm256i *>(panSumSquare),
    5790             :                                   ymm_sumsquare);
    5791             : 
    5792       10649 :             nSum += panSum[0] + panSum[2] + panSum[4] + panSum[6];
    5793       10649 :             nSumSquare += static_cast<GUIntBig>(panSumSquare[0]) +
    5794       10649 :                           panSumSquare[1] + panSumSquare[2] + panSumSquare[3] +
    5795       10649 :                           panSumSquare[4] + panSumSquare[5] + panSumSquare[6] +
    5796             :                           panSumSquare[7];
    5797             :         }
    5798             :     }
    5799             : 
    5800             :     if constexpr (COMPUTE_MIN)
    5801             :     {
    5802        8056 :         GDALmm256_store_si256(reinterpret_cast<GDALm256i *>(pabyMin), ymm_min);
    5803             :     }
    5804             :     if constexpr (COMPUTE_MAX)
    5805             :     {
    5806       16933 :         GDALmm256_store_si256(reinterpret_cast<GDALm256i *>(pabyMax), ymm_max);
    5807             :     }
    5808             :     if constexpr (COMPUTE_MIN || COMPUTE_MAX)
    5809             :     {
    5810      576279 :         for (int j = 0; j < 32; j++)
    5811             :         {
    5812             :             if constexpr (COMPUTE_MIN)
    5813             :             {
    5814      257792 :                 if (pabyMin[j] < nMin)
    5815        1245 :                     nMin = pabyMin[j];
    5816             :             }
    5817             :             if constexpr (COMPUTE_MAX)
    5818             :             {
    5819      541856 :                 if (pabyMax[j] > nMax)
    5820        1793 :                     nMax = pabyMax[j];
    5821             :             }
    5822             :         }
    5823             :     }
    5824             : 
    5825      227580 :     for (; i < nBlockPixels; i++)
    5826             :     {
    5827      206650 :         const GUInt32 nValue = pData[i];
    5828             :         if constexpr (COMPUTE_MIN)
    5829             :         {
    5830       81974 :             if (nValue < nMin)
    5831           1 :                 nMin = nValue;
    5832             :         }
    5833             :         if constexpr (COMPUTE_MAX)
    5834             :         {
    5835      203875 :             if (nValue > nMax)
    5836        1149 :                 nMax = nValue;
    5837             :         }
    5838             :         if constexpr (COMPUTE_OTHER_STATS)
    5839             :         {
    5840       77195 :             nSum += nValue;
    5841       77195 :             nSumSquare +=
    5842       77195 :                 static_cast_for_coverity_scan<GUIntBig>(nValue) * nValue;
    5843             :         }
    5844             :     }
    5845             : 
    5846             :     if constexpr (COMPUTE_OTHER_STATS)
    5847             :     {
    5848       10649 :         nSampleCount += static_cast<GUIntBig>(nBlockPixels);
    5849       10649 :         nValidCount += static_cast<GUIntBig>(nBlockPixels);
    5850             :     }
    5851       20930 : }
    5852             : 
    5853             : // SSE2/AVX2 optimization for GByte case
    5854             : // In pure SSE2, this relies on gdal_avx2_emulation.hpp. There is no
    5855             : // penaly in using the emulation, because, given the mm256 intrinsics used here,
    5856             : // there are strictly equivalent to 2 parallel SSE2 streams.
    5857             : template <bool COMPUTE_OTHER_STATS>
    5858             : struct ComputeStatisticsInternal<GByte, COMPUTE_OTHER_STATS>
    5859             : {
    5860       29961 :     static void f(int nXCheck, int nBlockXSize, int nYCheck,
    5861             :                   // assumed to be aligned on 256 bits
    5862             :                   const GByte *pData, bool bHasNoData, GUInt32 nNoDataValue,
    5863             :                   GUInt32 &nMin, GUInt32 &nMax, GUIntBig &nSum,
    5864             :                   GUIntBig &nSumSquare, GUIntBig &nSampleCount,
    5865             :                   GUIntBig &nValidCount)
    5866             :     {
    5867       29961 :         const auto nBlockPixels = static_cast<GPtrDiff_t>(nXCheck) * nYCheck;
    5868       29961 :         if (bHasNoData && nXCheck == nBlockXSize && nBlockPixels >= 32 &&
    5869       11574 :             nMin <= nMax)
    5870             :         {
    5871             :             // 32-byte alignment may not be enforced by linker, so do it at hand
    5872             :             GByte aby32ByteUnaligned[32 + 32 + 32 + 32 + 32];
    5873        1459 :             GByte *paby32ByteAligned =
    5874             :                 aby32ByteUnaligned +
    5875        1459 :                 (32 - (reinterpret_cast<GUIntptr_t>(aby32ByteUnaligned) % 32));
    5876        1459 :             GByte *pabyMin = paby32ByteAligned;
    5877        1459 :             GByte *pabyMax = paby32ByteAligned + 32;
    5878        1459 :             GUInt32 *panSum =
    5879             :                 reinterpret_cast<GUInt32 *>(paby32ByteAligned + 32 * 2);
    5880        1459 :             GUInt32 *panSumSquare =
    5881             :                 reinterpret_cast<GUInt32 *>(paby32ByteAligned + 32 * 3);
    5882             : 
    5883        1459 :             CPLAssert((reinterpret_cast<uintptr_t>(pData) % 32) == 0);
    5884             : 
    5885        1459 :             GPtrDiff_t i = 0;
    5886             :             // Make sure that sumSquare can fit on uint32
    5887             :             // * 8 since we can hold 8 sums per vector register
    5888        1459 :             const int nMaxIterationsPerInnerLoop =
    5889             :                 8 * ((std::numeric_limits<GUInt32>::max() / (255 * 255)) & ~31);
    5890        1459 :             auto nOuterLoops = nBlockPixels / nMaxIterationsPerInnerLoop;
    5891        1459 :             if ((nBlockPixels % nMaxIterationsPerInnerLoop) != 0)
    5892        1459 :                 nOuterLoops++;
    5893             : 
    5894             :             const GDALm256i ymm_nodata =
    5895        1459 :                 GDALmm256_set1_epi8(static_cast<GByte>(nNoDataValue));
    5896             :             // any non noData value in [min,max] would do.
    5897             :             const GDALm256i ymm_neutral =
    5898        1459 :                 GDALmm256_set1_epi8(static_cast<GByte>(nMin));
    5899        1459 :             GDALm256i ymm_min = ymm_neutral;
    5900        1459 :             GDALm256i ymm_max = ymm_neutral;
    5901             :             [[maybe_unused]] const auto ymm_mask_8bits =
    5902        1459 :                 GDALmm256_set1_epi16(0xFF);
    5903             : 
    5904        1459 :             const GUInt32 nMinThreshold = (nNoDataValue == 0) ? 1 : 0;
    5905        1459 :             const GUInt32 nMaxThreshold = (nNoDataValue == 255) ? 254 : 255;
    5906        1459 :             const bool bComputeMinMax =
    5907        1459 :                 nMin > nMinThreshold || nMax < nMaxThreshold;
    5908             : 
    5909        2918 :             for (GPtrDiff_t k = 0; k < nOuterLoops; k++)
    5910             :             {
    5911        1459 :                 const auto iMax =
    5912        1459 :                     std::min(nBlockPixels, i + nMaxIterationsPerInnerLoop);
    5913             : 
    5914             :                 // holds 4 uint32 sums in [0], [2], [4] and [6]
    5915        1459 :                 [[maybe_unused]] GDALm256i ymm_sum = ZERO256;
    5916             :                 // holds 8 uint32 sums
    5917        1459 :                 [[maybe_unused]] GDALm256i ymm_sumsquare = ZERO256;
    5918             :                 // holds 4 uint32 sums in [0], [2], [4] and [6]
    5919        1459 :                 [[maybe_unused]] GDALm256i ymm_count_nodata_mul_255 = ZERO256;
    5920        1459 :                 const auto iInit = i;
    5921       14435 :                 for (; i + 31 < iMax; i += 32)
    5922             :                 {
    5923       12976 :                     const GDALm256i ymm = GDALmm256_load_si256(
    5924       12976 :                         reinterpret_cast<const GDALm256i *>(pData + i));
    5925             : 
    5926             :                     // Check which values are nodata
    5927             :                     const GDALm256i ymm_eq_nodata =
    5928       12976 :                         GDALmm256_cmpeq_epi8(ymm, ymm_nodata);
    5929             :                     if constexpr (COMPUTE_OTHER_STATS)
    5930             :                     {
    5931             :                         // Count how many values are nodata (due to cmpeq
    5932             :                         // putting 255 when condition is met, this will actually
    5933             :                         // be 255 times the number of nodata value, spread in 4
    5934             :                         // 64 bits words). We can use add_epi32 as the counter
    5935             :                         // will not overflow uint32
    5936        4634 :                         ymm_count_nodata_mul_255 = GDALmm256_add_epi32(
    5937             :                             ymm_count_nodata_mul_255,
    5938             :                             GDALmm256_sad_epu8(ymm_eq_nodata, ZERO256));
    5939             :                     }
    5940             :                     // Replace all nodata values by zero for the purpose of sum
    5941             :                     // and sumquare.
    5942             :                     const GDALm256i ymm_nodata_by_zero =
    5943       12976 :                         GDALmm256_andnot_si256(ymm_eq_nodata, ymm);
    5944       12976 :                     if (bComputeMinMax)
    5945             :                     {
    5946             :                         // Replace all nodata values by a neutral value for the
    5947             :                         // purpose of min and max.
    5948             :                         const GDALm256i ymm_nodata_by_neutral =
    5949        8591 :                             GDALmm256_or_si256(
    5950             :                                 GDALmm256_and_si256(ymm_eq_nodata, ymm_neutral),
    5951             :                                 ymm_nodata_by_zero);
    5952             : 
    5953             :                         ymm_min =
    5954        8591 :                             GDALmm256_min_epu8(ymm_min, ymm_nodata_by_neutral);
    5955             :                         ymm_max =
    5956        8591 :                             GDALmm256_max_epu8(ymm_max, ymm_nodata_by_neutral);
    5957             :                     }
    5958             : 
    5959             :                     if constexpr (COMPUTE_OTHER_STATS)
    5960             :                     {
    5961             :                         // Extract even-8bit values
    5962        4634 :                         const GDALm256i ymm_even = GDALmm256_and_si256(
    5963             :                             ymm_nodata_by_zero, ymm_mask_8bits);
    5964             :                         // Compute square of those 16 values as 32 bit result
    5965             :                         // and add adjacent pairs
    5966             :                         const GDALm256i ymm_even_square =
    5967        4634 :                             GDALmm256_madd_epi16(ymm_even, ymm_even);
    5968             :                         // Add to the sumsquare accumulator
    5969             :                         ymm_sumsquare =
    5970        4634 :                             GDALmm256_add_epi32(ymm_sumsquare, ymm_even_square);
    5971             : 
    5972             :                         // Extract odd-8bit values
    5973             :                         const GDALm256i ymm_odd =
    5974        4634 :                             GDALmm256_srli_epi16(ymm_nodata_by_zero, 8);
    5975             :                         const GDALm256i ymm_odd_square =
    5976        4634 :                             GDALmm256_madd_epi16(ymm_odd, ymm_odd);
    5977             :                         ymm_sumsquare =
    5978        4634 :                             GDALmm256_add_epi32(ymm_sumsquare, ymm_odd_square);
    5979             : 
    5980             :                         // Now compute the sums
    5981        4634 :                         ymm_sum = GDALmm256_add_epi32(
    5982             :                             ymm_sum,
    5983             :                             GDALmm256_sad_epu8(ymm_nodata_by_zero, ZERO256));
    5984             :                     }
    5985             :                 }
    5986             : 
    5987             :                 if constexpr (COMPUTE_OTHER_STATS)
    5988             :                 {
    5989         153 :                     GUInt32 *panCoutNoDataMul255 = panSum;
    5990         153 :                     GDALmm256_store_si256(
    5991             :                         reinterpret_cast<GDALm256i *>(panCoutNoDataMul255),
    5992             :                         ymm_count_nodata_mul_255);
    5993             : 
    5994         153 :                     nSampleCount += (i - iInit);
    5995             : 
    5996         153 :                     nValidCount +=
    5997         153 :                         (i - iInit) -
    5998         153 :                         (panCoutNoDataMul255[0] + panCoutNoDataMul255[2] +
    5999         153 :                          panCoutNoDataMul255[4] + panCoutNoDataMul255[6]) /
    6000             :                             255;
    6001             : 
    6002         153 :                     GDALmm256_store_si256(reinterpret_cast<GDALm256i *>(panSum),
    6003             :                                           ymm_sum);
    6004         153 :                     GDALmm256_store_si256(
    6005             :                         reinterpret_cast<GDALm256i *>(panSumSquare),
    6006             :                         ymm_sumsquare);
    6007         153 :                     nSum += panSum[0] + panSum[2] + panSum[4] + panSum[6];
    6008         153 :                     nSumSquare += static_cast<GUIntBig>(panSumSquare[0]) +
    6009         153 :                                   panSumSquare[1] + panSumSquare[2] +
    6010         153 :                                   panSumSquare[3] + panSumSquare[4] +
    6011         153 :                                   panSumSquare[5] + panSumSquare[6] +
    6012             :                                   panSumSquare[7];
    6013             :                 }
    6014             :             }
    6015             : 
    6016        1459 :             if (bComputeMinMax)
    6017             :             {
    6018        1428 :                 GDALmm256_store_si256(reinterpret_cast<GDALm256i *>(pabyMin),
    6019             :                                       ymm_min);
    6020        1428 :                 GDALmm256_store_si256(reinterpret_cast<GDALm256i *>(pabyMax),
    6021             :                                       ymm_max);
    6022       47124 :                 for (int j = 0; j < 32; j++)
    6023             :                 {
    6024       45696 :                     if (pabyMin[j] < nMin)
    6025          40 :                         nMin = pabyMin[j];
    6026       45696 :                     if (pabyMax[j] > nMax)
    6027         159 :                         nMax = pabyMax[j];
    6028             :                 }
    6029             :             }
    6030             : 
    6031             :             if constexpr (COMPUTE_OTHER_STATS)
    6032             :             {
    6033         153 :                 nSampleCount += nBlockPixels - i;
    6034             :             }
    6035       33905 :             for (; i < nBlockPixels; i++)
    6036             :             {
    6037       32446 :                 const GUInt32 nValue = pData[i];
    6038       32446 :                 if (nValue == nNoDataValue)
    6039       24923 :                     continue;
    6040        7523 :                 if (nValue < nMin)
    6041           1 :                     nMin = nValue;
    6042        7523 :                 if (nValue > nMax)
    6043          13 :                     nMax = nValue;
    6044             :                 if constexpr (COMPUTE_OTHER_STATS)
    6045             :                 {
    6046        3590 :                     nValidCount++;
    6047        3590 :                     nSum += nValue;
    6048        3590 :                     nSumSquare +=
    6049        3590 :                         static_cast_for_coverity_scan<GUIntBig>(nValue) *
    6050        3590 :                         nValue;
    6051             :                 }
    6052        1459 :             }
    6053             :         }
    6054       28502 :         else if (!bHasNoData && nXCheck == nBlockXSize && nBlockPixels >= 32)
    6055             :         {
    6056       14974 :             if (nMin > 0)
    6057             :             {
    6058        2100 :                 if (nMax < 255)
    6059             :                 {
    6060             :                     ComputeStatisticsByteNoNodata<true, true,
    6061        1570 :                                                   COMPUTE_OTHER_STATS>(
    6062             :                         nBlockPixels, pData, nMin, nMax, nSum, nSumSquare,
    6063             :                         nSampleCount, nValidCount);
    6064             :                 }
    6065             :                 else
    6066             :                 {
    6067             :                     ComputeStatisticsByteNoNodata<true, false,
    6068         530 :                                                   COMPUTE_OTHER_STATS>(
    6069             :                         nBlockPixels, pData, nMin, nMax, nSum, nSumSquare,
    6070             :                         nSampleCount, nValidCount);
    6071             :                 }
    6072             :             }
    6073             :             else
    6074             :             {
    6075       12874 :                 if (nMax < 255)
    6076             :                 {
    6077             :                     ComputeStatisticsByteNoNodata<false, true,
    6078        9407 :                                                   COMPUTE_OTHER_STATS>(
    6079             :                         nBlockPixels, pData, nMin, nMax, nSum, nSumSquare,
    6080             :                         nSampleCount, nValidCount);
    6081             :                 }
    6082             :                 else
    6083             :                 {
    6084             :                     ComputeStatisticsByteNoNodata<false, false,
    6085        3467 :                                                   COMPUTE_OTHER_STATS>(
    6086             :                         nBlockPixels, pData, nMin, nMax, nSum, nSumSquare,
    6087             :                         nSampleCount, nValidCount);
    6088             :                 }
    6089             :             }
    6090             :         }
    6091       12274 :         else if (!COMPUTE_OTHER_STATS && !bHasNoData && nXCheck >= 32 &&
    6092          31 :                  (nBlockXSize % 32) == 0)
    6093             :         {
    6094        5987 :             for (int iY = 0; iY < nYCheck; iY++)
    6095             :             {
    6096        5956 :                 ComputeStatisticsByteNoNodata<true, true, COMPUTE_OTHER_STATS>(
    6097        5956 :                     nXCheck, pData + static_cast<size_t>(iY) * nBlockXSize,
    6098             :                     nMin, nMax, nSum, nSumSquare, nSampleCount, nValidCount);
    6099          31 :             }
    6100             :         }
    6101             :         else
    6102             :         {
    6103       13497 :             ComputeStatisticsInternalGeneric<GByte, COMPUTE_OTHER_STATS>::f(
    6104             :                 nXCheck, nBlockXSize, nYCheck, pData, bHasNoData, nNoDataValue,
    6105             :                 nMin, nMax, nSum, nSumSquare, nSampleCount, nValidCount);
    6106             :         }
    6107       29959 :     }
    6108             : };
    6109             : 
    6110             : CPL_NOSANITIZE_UNSIGNED_INT_OVERFLOW
    6111         400 : static void UnshiftSumSquare(GUIntBig &nSumSquare, GUIntBig nSumThis,
    6112             :                              GUIntBig i)
    6113             : {
    6114         400 :     nSumSquare += 32768 * (2 * nSumThis - i * 32768);
    6115         400 : }
    6116             : 
    6117             : // AVX2/SSE2 optimization for GUInt16 case
    6118             : template <bool COMPUTE_OTHER_STATS>
    6119             : struct ComputeStatisticsInternal<GUInt16, COMPUTE_OTHER_STATS>
    6120             : {
    6121        1624 :     static void f(int nXCheck, int nBlockXSize, int nYCheck,
    6122             :                   // assumed to be aligned on 128 bits
    6123             :                   const GUInt16 *pData, bool bHasNoData, GUInt32 nNoDataValue,
    6124             :                   GUInt32 &nMin, GUInt32 &nMax, GUIntBig &nSum,
    6125             :                   GUIntBig &nSumSquare, GUIntBig &nSampleCount,
    6126             :                   GUIntBig &nValidCount)
    6127             :     {
    6128        1624 :         const auto nBlockPixels = static_cast<GPtrDiff_t>(nXCheck) * nYCheck;
    6129        1624 :         if (!bHasNoData && nXCheck == nBlockXSize && nBlockPixels >= 16)
    6130             :         {
    6131        1418 :             CPLAssert((reinterpret_cast<uintptr_t>(pData) % 16) == 0);
    6132             : 
    6133        1418 :             GPtrDiff_t i = 0;
    6134             :             // In SSE2, min_epu16 and max_epu16 do not exist, so shift from
    6135             :             // UInt16 to SInt16 to be able to use min_epi16 and max_epi16.
    6136             :             // Furthermore the shift is also needed to use madd_epi16
    6137        1418 :             const GDALm256i ymm_m32768 = GDALmm256_set1_epi16(-32768);
    6138        1418 :             GDALm256i ymm_min = GDALmm256_load_si256(
    6139        1418 :                 reinterpret_cast<const GDALm256i *>(pData + i));
    6140        1418 :             ymm_min = GDALmm256_add_epi16(ymm_min, ymm_m32768);
    6141        1418 :             GDALm256i ymm_max = ymm_min;
    6142             :             [[maybe_unused]] GDALm256i ymm_sumsquare =
    6143        1418 :                 ZERO256;  // holds 4 uint64 sums
    6144             : 
    6145             :             // Make sure that sum can fit on uint32
    6146             :             // * 8 since we can hold 8 sums per vector register
    6147        1418 :             const int nMaxIterationsPerInnerLoop =
    6148             :                 8 * ((std::numeric_limits<GUInt32>::max() / 65535) & ~15);
    6149        1418 :             GPtrDiff_t nOuterLoops = nBlockPixels / nMaxIterationsPerInnerLoop;
    6150        1418 :             if ((nBlockPixels % nMaxIterationsPerInnerLoop) != 0)
    6151        1418 :                 nOuterLoops++;
    6152             : 
    6153        1418 :             const bool bComputeMinMax = nMin > 0 || nMax < 65535;
    6154             :             [[maybe_unused]] const auto ymm_mask_16bits =
    6155        1418 :                 GDALmm256_set1_epi32(0xFFFF);
    6156             :             [[maybe_unused]] const auto ymm_mask_32bits =
    6157        1418 :                 GDALmm256_set1_epi64x(0xFFFFFFFF);
    6158             : 
    6159        1418 :             GUIntBig nSumThis = 0;
    6160        2860 :             for (int k = 0; k < nOuterLoops; k++)
    6161             :             {
    6162        1442 :                 const auto iMax =
    6163        1442 :                     std::min(nBlockPixels, i + nMaxIterationsPerInnerLoop);
    6164             : 
    6165             :                 [[maybe_unused]] GDALm256i ymm_sum =
    6166        1442 :                     ZERO256;  // holds 8 uint32 sums
    6167      959774 :                 for (; i + 15 < iMax; i += 16)
    6168             :                 {
    6169      958332 :                     const GDALm256i ymm = GDALmm256_load_si256(
    6170      958332 :                         reinterpret_cast<const GDALm256i *>(pData + i));
    6171             :                     const GDALm256i ymm_shifted =
    6172      958332 :                         GDALmm256_add_epi16(ymm, ymm_m32768);
    6173      958332 :                     if (bComputeMinMax)
    6174             :                     {
    6175      949313 :                         ymm_min = GDALmm256_min_epi16(ymm_min, ymm_shifted);
    6176      949313 :                         ymm_max = GDALmm256_max_epi16(ymm_max, ymm_shifted);
    6177             :                     }
    6178             : 
    6179             :                     if constexpr (COMPUTE_OTHER_STATS)
    6180             :                     {
    6181             :                         // Note: the int32 range can overflow for (0-32768)^2 +
    6182             :                         // (0-32768)^2 = 0x80000000, but as we know the result
    6183             :                         // is positive, this is OK as we interpret is a uint32.
    6184             :                         const GDALm256i ymm_square =
    6185       95410 :                             GDALmm256_madd_epi16(ymm_shifted, ymm_shifted);
    6186       95410 :                         ymm_sumsquare = GDALmm256_add_epi64(
    6187             :                             ymm_sumsquare,
    6188             :                             GDALmm256_and_si256(ymm_square, ymm_mask_32bits));
    6189       95410 :                         ymm_sumsquare = GDALmm256_add_epi64(
    6190             :                             ymm_sumsquare,
    6191             :                             GDALmm256_srli_epi64(ymm_square, 32));
    6192             : 
    6193             :                         // Now compute the sums
    6194       95410 :                         ymm_sum = GDALmm256_add_epi32(
    6195             :                             ymm_sum, GDALmm256_and_si256(ymm, ymm_mask_16bits));
    6196       95410 :                         ymm_sum = GDALmm256_add_epi32(
    6197             :                             ymm_sum, GDALmm256_srli_epi32(ymm, 16));
    6198             :                     }
    6199             :                 }
    6200             : 
    6201             :                 if constexpr (COMPUTE_OTHER_STATS)
    6202             :                 {
    6203             :                     GUInt32 anSum[8];
    6204         400 :                     GDALmm256_storeu_si256(reinterpret_cast<GDALm256i *>(anSum),
    6205             :                                            ymm_sum);
    6206         400 :                     nSumThis += static_cast<GUIntBig>(anSum[0]) + anSum[1] +
    6207         400 :                                 anSum[2] + anSum[3] + anSum[4] + anSum[5] +
    6208         400 :                                 anSum[6] + anSum[7];
    6209             :                 }
    6210             :             }
    6211             : 
    6212        1418 :             if (bComputeMinMax)
    6213             :             {
    6214             :                 GUInt16 anMin[16];
    6215             :                 GUInt16 anMax[16];
    6216             : 
    6217             :                 // Unshift the result
    6218        1377 :                 ymm_min = GDALmm256_sub_epi16(ymm_min, ymm_m32768);
    6219        1377 :                 ymm_max = GDALmm256_sub_epi16(ymm_max, ymm_m32768);
    6220        1377 :                 GDALmm256_storeu_si256(reinterpret_cast<GDALm256i *>(anMin),
    6221             :                                        ymm_min);
    6222        1377 :                 GDALmm256_storeu_si256(reinterpret_cast<GDALm256i *>(anMax),
    6223             :                                        ymm_max);
    6224       23409 :                 for (int j = 0; j < 16; j++)
    6225             :                 {
    6226       22032 :                     if (anMin[j] < nMin)
    6227         342 :                         nMin = anMin[j];
    6228       22032 :                     if (anMax[j] > nMax)
    6229         481 :                         nMax = anMax[j];
    6230             :                 }
    6231             :             }
    6232             : 
    6233             :             if constexpr (COMPUTE_OTHER_STATS)
    6234             :             {
    6235             :                 GUIntBig anSumSquare[4];
    6236         400 :                 GDALmm256_storeu_si256(
    6237             :                     reinterpret_cast<GDALm256i *>(anSumSquare), ymm_sumsquare);
    6238         400 :                 nSumSquare += anSumSquare[0] + anSumSquare[1] + anSumSquare[2] +
    6239             :                               anSumSquare[3];
    6240             : 
    6241             :                 // Unshift the sum of squares
    6242         400 :                 UnshiftSumSquare(nSumSquare, nSumThis,
    6243             :                                  static_cast<GUIntBig>(i));
    6244             : 
    6245         400 :                 nSum += nSumThis;
    6246             : 
    6247         722 :                 for (; i < nBlockPixels; i++)
    6248             :                 {
    6249         322 :                     const GUInt32 nValue = pData[i];
    6250         322 :                     if (nValue < nMin)
    6251           1 :                         nMin = nValue;
    6252         322 :                     if (nValue > nMax)
    6253           1 :                         nMax = nValue;
    6254         322 :                     nSum += nValue;
    6255         322 :                     nSumSquare +=
    6256         322 :                         static_cast_for_coverity_scan<GUIntBig>(nValue) *
    6257         322 :                         nValue;
    6258             :                 }
    6259             : 
    6260         400 :                 nSampleCount += static_cast<GUIntBig>(nXCheck) * nYCheck;
    6261         400 :                 nValidCount += static_cast<GUIntBig>(nXCheck) * nYCheck;
    6262        1418 :             }
    6263             :         }
    6264             :         else
    6265             :         {
    6266         206 :             ComputeStatisticsInternalGeneric<GUInt16, COMPUTE_OTHER_STATS>::f(
    6267             :                 nXCheck, nBlockXSize, nYCheck, pData, bHasNoData, nNoDataValue,
    6268             :                 nMin, nMax, nSum, nSumSquare, nSampleCount, nValidCount);
    6269             :         }
    6270        1624 :     }
    6271             : };
    6272             : 
    6273             : #endif
    6274             : // (defined(__x86_64__) || defined(_M_X64)) && (defined(__GNUC__) ||
    6275             : // defined(_MSC_VER))
    6276             : 
    6277             : /************************************************************************/
    6278             : /*                          GetPixelValue()                             */
    6279             : /************************************************************************/
    6280             : 
    6281    23187600 : static inline double GetPixelValue(GDALDataType eDataType, bool bSignedByte,
    6282             :                                    const void *pData, GPtrDiff_t iOffset,
    6283             :                                    const GDALNoDataValues &sNoDataValues,
    6284             :                                    bool &bValid)
    6285             : {
    6286    23187600 :     bValid = true;
    6287    23187600 :     double dfValue = 0;
    6288    23187600 :     switch (eDataType)
    6289             :     {
    6290     1413680 :         case GDT_Byte:
    6291             :         {
    6292     1413680 :             if (bSignedByte)
    6293         192 :                 dfValue = static_cast<const signed char *>(pData)[iOffset];
    6294             :             else
    6295     1413490 :                 dfValue = static_cast<const GByte *>(pData)[iOffset];
    6296     1413680 :             break;
    6297             :         }
    6298       10409 :         case GDT_Int8:
    6299       10409 :             dfValue = static_cast<const GInt8 *>(pData)[iOffset];
    6300       10409 :             break;
    6301        4000 :         case GDT_UInt16:
    6302        4000 :             dfValue = static_cast<const GUInt16 *>(pData)[iOffset];
    6303        4000 :             break;
    6304       60192 :         case GDT_Int16:
    6305       60192 :             dfValue = static_cast<const GInt16 *>(pData)[iOffset];
    6306       60192 :             break;
    6307       27600 :         case GDT_UInt32:
    6308       27600 :             dfValue = static_cast<const GUInt32 *>(pData)[iOffset];
    6309       27600 :             break;
    6310      455610 :         case GDT_Int32:
    6311      455610 :             dfValue = static_cast<const GInt32 *>(pData)[iOffset];
    6312      455610 :             break;
    6313        2602 :         case GDT_UInt64:
    6314        2602 :             dfValue = static_cast<double>(
    6315        2602 :                 static_cast<const std::uint64_t *>(pData)[iOffset]);
    6316        2602 :             break;
    6317        7402 :         case GDT_Int64:
    6318        7402 :             dfValue = static_cast<double>(
    6319        7402 :                 static_cast<const std::int64_t *>(pData)[iOffset]);
    6320        7402 :             break;
    6321           0 :         case GDT_Float16:
    6322             :         {
    6323             :             using namespace std;
    6324           0 :             const GFloat16 hfValue =
    6325           0 :                 static_cast<const GFloat16 *>(pData)[iOffset];
    6326           0 :             if (isnan(hfValue) ||
    6327           0 :                 (sNoDataValues.bGotFloat16NoDataValue &&
    6328           0 :                  ARE_REAL_EQUAL(hfValue, sNoDataValues.hfNoDataValue)))
    6329             :             {
    6330           0 :                 bValid = false;
    6331           0 :                 return 0.0;
    6332             :             }
    6333           0 :             dfValue = hfValue;
    6334           0 :             return dfValue;
    6335             :         }
    6336    17502100 :         case GDT_Float32:
    6337             :         {
    6338    17502100 :             const float fValue = static_cast<const float *>(pData)[iOffset];
    6339    34977300 :             if (std::isnan(fValue) ||
    6340    30705200 :                 (sNoDataValues.bGotFloatNoDataValue &&
    6341    13230000 :                  ARE_REAL_EQUAL(fValue, sNoDataValues.fNoDataValue)))
    6342             :             {
    6343      121752 :                 bValid = false;
    6344      121752 :                 return 0.0;
    6345             :             }
    6346    17380400 :             dfValue = fValue;
    6347    17380400 :             return dfValue;
    6348             :         }
    6349     3686870 :         case GDT_Float64:
    6350     3686870 :             dfValue = static_cast<const double *>(pData)[iOffset];
    6351     3686870 :             if (std::isnan(dfValue))
    6352             :             {
    6353          52 :                 bValid = false;
    6354          52 :                 return 0.0;
    6355             :             }
    6356     3686820 :             break;
    6357        2692 :         case GDT_CInt16:
    6358        2692 :             dfValue = static_cast<const GInt16 *>(pData)[iOffset * 2];
    6359        2692 :             break;
    6360        2692 :         case GDT_CInt32:
    6361        2692 :             dfValue = static_cast<const GInt32 *>(pData)[iOffset * 2];
    6362        2692 :             break;
    6363           0 :         case GDT_CFloat16:
    6364           0 :             dfValue = static_cast<const GFloat16 *>(pData)[iOffset * 2];
    6365           0 :             if (std::isnan(dfValue))
    6366             :             {
    6367           0 :                 bValid = false;
    6368           0 :                 return 0.0;
    6369             :             }
    6370           0 :             break;
    6371        5812 :         case GDT_CFloat32:
    6372        5812 :             dfValue = static_cast<const float *>(pData)[iOffset * 2];
    6373        5812 :             if (std::isnan(dfValue))
    6374             :             {
    6375           0 :                 bValid = false;
    6376           0 :                 return 0.0;
    6377             :             }
    6378        5812 :             break;
    6379        5892 :         case GDT_CFloat64:
    6380        5892 :             dfValue = static_cast<const double *>(pData)[iOffset * 2];
    6381        5892 :             if (std::isnan(dfValue))
    6382             :             {
    6383           0 :                 bValid = false;
    6384           0 :                 return 0.0;
    6385             :             }
    6386        5892 :             break;
    6387           0 :         case GDT_Unknown:
    6388             :         case GDT_TypeCount:
    6389           0 :             CPLAssert(false);
    6390             :             break;
    6391             :     }
    6392             : 
    6393     9424400 :     if (sNoDataValues.bGotNoDataValue &&
    6394     3738990 :         ARE_REAL_EQUAL(dfValue, sNoDataValues.dfNoDataValue))
    6395             :     {
    6396     3346220 :         bValid = false;
    6397     3346220 :         return 0.0;
    6398             :     }
    6399     2339180 :     return dfValue;
    6400             : }
    6401             : 
    6402             : /************************************************************************/
    6403             : /*                         SetValidPercent()                            */
    6404             : /************************************************************************/
    6405             : 
    6406             : //! @cond Doxygen_Suppress
    6407             : /**
    6408             :  * \brief Set percentage of valid (not nodata) pixels.
    6409             :  *
    6410             :  * Stores the percentage of valid pixels in the metadata item
    6411             :  * STATISTICS_VALID_PERCENT
    6412             :  *
    6413             :  * @param nSampleCount Number of sampled pixels.
    6414             :  *
    6415             :  * @param nValidCount Number of valid pixels.
    6416             :  */
    6417             : 
    6418         481 : void GDALRasterBand::SetValidPercent(GUIntBig nSampleCount,
    6419             :                                      GUIntBig nValidCount)
    6420             : {
    6421         481 :     if (nValidCount == 0)
    6422             :     {
    6423          12 :         SetMetadataItem("STATISTICS_VALID_PERCENT", "0");
    6424             :     }
    6425         469 :     else if (nValidCount == nSampleCount)
    6426             :     {
    6427         424 :         SetMetadataItem("STATISTICS_VALID_PERCENT", "100");
    6428             :     }
    6429             :     else /* nValidCount < nSampleCount */
    6430             :     {
    6431          45 :         char szValue[128] = {0};
    6432             : 
    6433             :         /* percentage is only an indicator: limit precision */
    6434          45 :         CPLsnprintf(szValue, sizeof(szValue), "%.4g",
    6435          45 :                     100. * static_cast<double>(nValidCount) / nSampleCount);
    6436             : 
    6437          45 :         if (EQUAL(szValue, "100"))
    6438             :         {
    6439             :             /* don't set 100 percent valid
    6440             :              * because some of the sampled pixels were nodata */
    6441           0 :             SetMetadataItem("STATISTICS_VALID_PERCENT", "99.999");
    6442             :         }
    6443             :         else
    6444             :         {
    6445          45 :             SetMetadataItem("STATISTICS_VALID_PERCENT", szValue);
    6446             :         }
    6447             :     }
    6448         481 : }
    6449             : 
    6450             : //! @endcond
    6451             : 
    6452             : /************************************************************************/
    6453             : /*                         ComputeStatistics()                          */
    6454             : /************************************************************************/
    6455             : 
    6456             : /**
    6457             :  * \brief Compute image statistics.
    6458             :  *
    6459             :  * Returns the minimum, maximum, mean and standard deviation of all
    6460             :  * pixel values in this band.  If approximate statistics are sufficient,
    6461             :  * the bApproxOK flag can be set to true in which case overviews, or a
    6462             :  * subset of image tiles may be used in computing the statistics.
    6463             :  *
    6464             :  * Once computed, the statistics will generally be "set" back on the
    6465             :  * raster band using SetStatistics().
    6466             :  *
    6467             :  * Cached statistics can be cleared with GDALDataset::ClearStatistics().
    6468             :  *
    6469             :  * This method is the same as the C function GDALComputeRasterStatistics().
    6470             :  *
    6471             :  * @param bApproxOK If TRUE statistics may be computed based on overviews
    6472             :  * or a subset of all tiles.
    6473             :  *
    6474             :  * @param pdfMin Location into which to load image minimum (may be NULL).
    6475             :  *
    6476             :  * @param pdfMax Location into which to load image maximum (may be NULL).-
    6477             :  *
    6478             :  * @param pdfMean Location into which to load image mean (may be NULL).
    6479             :  *
    6480             :  * @param pdfStdDev Location into which to load image standard deviation
    6481             :  * (may be NULL).
    6482             :  *
    6483             :  * @param pfnProgress a function to call to report progress, or NULL.
    6484             :  *
    6485             :  * @param pProgressData application data to pass to the progress function.
    6486             :  *
    6487             :  * @return CE_None on success, or CE_Failure if an error occurs or processing
    6488             :  * is terminated by the user.
    6489             :  */
    6490             : 
    6491         464 : CPLErr GDALRasterBand::ComputeStatistics(int bApproxOK, double *pdfMin,
    6492             :                                          double *pdfMax, double *pdfMean,
    6493             :                                          double *pdfStdDev,
    6494             :                                          GDALProgressFunc pfnProgress,
    6495             :                                          void *pProgressData)
    6496             : 
    6497             : {
    6498         464 :     if (pfnProgress == nullptr)
    6499         169 :         pfnProgress = GDALDummyProgress;
    6500             : 
    6501             :     /* -------------------------------------------------------------------- */
    6502             :     /*      If we have overview bands, use them for statistics.             */
    6503             :     /* -------------------------------------------------------------------- */
    6504         464 :     if (bApproxOK && GetOverviewCount() > 0 && !HasArbitraryOverviews())
    6505             :     {
    6506             :         GDALRasterBand *poBand =
    6507           3 :             GetRasterSampleOverview(GDALSTAT_APPROX_NUMSAMPLES);
    6508             : 
    6509           3 :         if (poBand != this)
    6510             :         {
    6511           6 :             CPLErr eErr = poBand->ComputeStatistics(FALSE, pdfMin, pdfMax,
    6512             :                                                     pdfMean, pdfStdDev,
    6513           3 :                                                     pfnProgress, pProgressData);
    6514           3 :             if (eErr == CE_None)
    6515             :             {
    6516           3 :                 if (pdfMin && pdfMax && pdfMean && pdfStdDev)
    6517             :                 {
    6518           3 :                     SetMetadataItem("STATISTICS_APPROXIMATE", "YES");
    6519           3 :                     SetStatistics(*pdfMin, *pdfMax, *pdfMean, *pdfStdDev);
    6520             :                 }
    6521             : 
    6522             :                 /* transfer metadata from overview band to this */
    6523             :                 const char *pszPercentValid =
    6524           3 :                     poBand->GetMetadataItem("STATISTICS_VALID_PERCENT");
    6525             : 
    6526           3 :                 if (pszPercentValid != nullptr)
    6527             :                 {
    6528           3 :                     SetMetadataItem("STATISTICS_VALID_PERCENT",
    6529           3 :                                     pszPercentValid);
    6530             :                 }
    6531             :             }
    6532           3 :             return eErr;
    6533             :         }
    6534             :     }
    6535             : 
    6536         461 :     if (!pfnProgress(0.0, "Compute Statistics", pProgressData))
    6537             :     {
    6538           0 :         ReportError(CE_Failure, CPLE_UserInterrupt, "User terminated");
    6539           0 :         return CE_Failure;
    6540             :     }
    6541             : 
    6542             :     /* -------------------------------------------------------------------- */
    6543             :     /*      Read actual data and compute statistics.                        */
    6544             :     /* -------------------------------------------------------------------- */
    6545             :     // Using Welford algorithm:
    6546             :     // http://en.wikipedia.org/wiki/Algorithms_for_calculating_variance
    6547             :     // to compute standard deviation in a more numerically robust way than
    6548             :     // the difference of the sum of square values with the square of the sum.
    6549             :     // dfMean and dfM2 are updated at each sample.
    6550             :     // dfM2 is the sum of square of differences to the current mean.
    6551         461 :     double dfMin = std::numeric_limits<double>::infinity();
    6552         461 :     double dfMax = -std::numeric_limits<double>::infinity();
    6553         461 :     double dfMean = 0.0;
    6554         461 :     double dfM2 = 0.0;
    6555             : 
    6556             :     GDALRasterIOExtraArg sExtraArg;
    6557         461 :     INIT_RASTERIO_EXTRA_ARG(sExtraArg);
    6558             : 
    6559         461 :     GDALNoDataValues sNoDataValues(this, eDataType);
    6560         461 :     GDALRasterBand *poMaskBand = nullptr;
    6561         461 :     if (!sNoDataValues.bGotNoDataValue)
    6562             :     {
    6563         434 :         const int l_nMaskFlags = GetMaskFlags();
    6564         450 :         if (l_nMaskFlags != GMF_ALL_VALID && l_nMaskFlags != GMF_NODATA &&
    6565          16 :             GetColorInterpretation() != GCI_AlphaBand)
    6566             :         {
    6567          16 :             poMaskBand = GetMaskBand();
    6568             :         }
    6569             :     }
    6570             : 
    6571         461 :     bool bSignedByte = false;
    6572         461 :     if (eDataType == GDT_Byte)
    6573             :     {
    6574         199 :         EnablePixelTypeSignedByteWarning(false);
    6575             :         const char *pszPixelType =
    6576         199 :             GetMetadataItem("PIXELTYPE", "IMAGE_STRUCTURE");
    6577         199 :         EnablePixelTypeSignedByteWarning(true);
    6578         199 :         bSignedByte =
    6579         199 :             pszPixelType != nullptr && EQUAL(pszPixelType, "SIGNEDBYTE");
    6580             :     }
    6581             : 
    6582         461 :     GUIntBig nSampleCount = 0;
    6583         461 :     GUIntBig nValidCount = 0;
    6584             : 
    6585         461 :     if (bApproxOK && HasArbitraryOverviews())
    6586             :     {
    6587             :         /* --------------------------------------------------------------------
    6588             :          */
    6589             :         /*      Figure out how much the image should be reduced to get an */
    6590             :         /*      approximate value. */
    6591             :         /* --------------------------------------------------------------------
    6592             :          */
    6593           0 :         double dfReduction = sqrt(static_cast<double>(nRasterXSize) *
    6594           0 :                                   nRasterYSize / GDALSTAT_APPROX_NUMSAMPLES);
    6595             : 
    6596           0 :         int nXReduced = nRasterXSize;
    6597           0 :         int nYReduced = nRasterYSize;
    6598           0 :         if (dfReduction > 1.0)
    6599             :         {
    6600           0 :             nXReduced = static_cast<int>(nRasterXSize / dfReduction);
    6601           0 :             nYReduced = static_cast<int>(nRasterYSize / dfReduction);
    6602             : 
    6603             :             // Catch the case of huge resizing ratios here
    6604           0 :             if (nXReduced == 0)
    6605           0 :                 nXReduced = 1;
    6606           0 :             if (nYReduced == 0)
    6607           0 :                 nYReduced = 1;
    6608             :         }
    6609             : 
    6610           0 :         void *pData = CPLMalloc(cpl::fits_on<int>(
    6611           0 :             GDALGetDataTypeSizeBytes(eDataType) * nXReduced * nYReduced));
    6612             : 
    6613             :         const CPLErr eErr =
    6614           0 :             IRasterIO(GF_Read, 0, 0, nRasterXSize, nRasterYSize, pData,
    6615           0 :                       nXReduced, nYReduced, eDataType, 0, 0, &sExtraArg);
    6616           0 :         if (eErr != CE_None)
    6617             :         {
    6618           0 :             CPLFree(pData);
    6619           0 :             return eErr;
    6620             :         }
    6621             : 
    6622           0 :         GByte *pabyMaskData = nullptr;
    6623           0 :         if (poMaskBand)
    6624             :         {
    6625             :             pabyMaskData =
    6626           0 :                 static_cast<GByte *>(VSI_MALLOC2_VERBOSE(nXReduced, nYReduced));
    6627           0 :             if (!pabyMaskData)
    6628             :             {
    6629           0 :                 CPLFree(pData);
    6630           0 :                 return CE_Failure;
    6631             :             }
    6632             : 
    6633           0 :             if (poMaskBand->RasterIO(GF_Read, 0, 0, nRasterXSize, nRasterYSize,
    6634             :                                      pabyMaskData, nXReduced, nYReduced,
    6635           0 :                                      GDT_Byte, 0, 0, nullptr) != CE_None)
    6636             :             {
    6637           0 :                 CPLFree(pData);
    6638           0 :                 CPLFree(pabyMaskData);
    6639           0 :                 return CE_Failure;
    6640             :             }
    6641             :         }
    6642             : 
    6643             :         /* this isn't the fastest way to do this, but is easier for now */
    6644           0 :         for (int iY = 0; iY < nYReduced; iY++)
    6645             :         {
    6646           0 :             for (int iX = 0; iX < nXReduced; iX++)
    6647             :             {
    6648           0 :                 const int iOffset = iX + iY * nXReduced;
    6649           0 :                 if (pabyMaskData && pabyMaskData[iOffset] == 0)
    6650           0 :                     continue;
    6651             : 
    6652           0 :                 bool bValid = true;
    6653           0 :                 double dfValue = GetPixelValue(eDataType, bSignedByte, pData,
    6654           0 :                                                iOffset, sNoDataValues, bValid);
    6655           0 :                 if (!bValid)
    6656           0 :                     continue;
    6657             : 
    6658           0 :                 dfMin = std::min(dfMin, dfValue);
    6659           0 :                 dfMax = std::max(dfMax, dfValue);
    6660             : 
    6661           0 :                 nValidCount++;
    6662           0 :                 if (dfMin == dfMax)
    6663             :                 {
    6664           0 :                     if (nValidCount == 1)
    6665           0 :                         dfMean = dfMin;
    6666             :                 }
    6667             :                 else
    6668             :                 {
    6669           0 :                     const double dfDelta = dfValue - dfMean;
    6670           0 :                     dfMean += dfDelta / nValidCount;
    6671           0 :                     dfM2 += dfDelta * (dfValue - dfMean);
    6672             :                 }
    6673             :             }
    6674             :         }
    6675             : 
    6676           0 :         nSampleCount = static_cast<GUIntBig>(nXReduced) * nYReduced;
    6677             : 
    6678           0 :         CPLFree(pData);
    6679           0 :         CPLFree(pabyMaskData);
    6680             :     }
    6681             : 
    6682             :     else  // No arbitrary overviews.
    6683             :     {
    6684         461 :         if (!InitBlockInfo())
    6685           0 :             return CE_Failure;
    6686             : 
    6687             :         /* --------------------------------------------------------------------
    6688             :          */
    6689             :         /*      Figure out the ratio of blocks we will read to get an */
    6690             :         /*      approximate value. */
    6691             :         /* --------------------------------------------------------------------
    6692             :          */
    6693         461 :         int nSampleRate = 1;
    6694         461 :         if (bApproxOK)
    6695             :         {
    6696          42 :             nSampleRate = static_cast<int>(std::max(
    6697          84 :                 1.0,
    6698          42 :                 sqrt(static_cast<double>(nBlocksPerRow) * nBlocksPerColumn)));
    6699             :             // We want to avoid probing only the first column of blocks for
    6700             :             // a square shaped raster, because it is not unlikely that it may
    6701             :             // be padding only (#6378)
    6702          42 :             if (nSampleRate == nBlocksPerRow && nBlocksPerRow > 1)
    6703           1 :                 nSampleRate += 1;
    6704             :         }
    6705         461 :         if (nSampleRate == 1)
    6706         427 :             bApproxOK = false;
    6707             : 
    6708             :         // Particular case for GDT_Byte that only use integral types for all
    6709             :         // intermediate computations. Only possible if the number of pixels
    6710             :         // explored is lower than GUINTBIG_MAX / (255*255), so that nSumSquare
    6711             :         // can fit on a uint64. Should be 99.99999% of cases.
    6712             :         // For GUInt16, this limits to raster of 4 giga pixels
    6713         461 :         if ((!poMaskBand && eDataType == GDT_Byte && !bSignedByte &&
    6714         184 :              static_cast<GUIntBig>(nBlocksPerRow) * nBlocksPerColumn /
    6715         184 :                      nSampleRate <
    6716         184 :                  GUINTBIG_MAX / (255U * 255U) /
    6717         184 :                      (static_cast<GUInt64>(nBlockXSize) *
    6718         184 :                       static_cast<GUInt64>(nBlockYSize))) ||
    6719         277 :             (eDataType == GDT_UInt16 &&
    6720          29 :              static_cast<GUIntBig>(nBlocksPerRow) * nBlocksPerColumn /
    6721          29 :                      nSampleRate <
    6722          29 :                  GUINTBIG_MAX / (65535U * 65535U) /
    6723          29 :                      (static_cast<GUInt64>(nBlockXSize) *
    6724          29 :                       static_cast<GUInt64>(nBlockYSize))))
    6725             :         {
    6726         213 :             const GUInt32 nMaxValueType = (eDataType == GDT_Byte) ? 255 : 65535;
    6727         213 :             GUInt32 nMin = nMaxValueType;
    6728         213 :             GUInt32 nMax = 0;
    6729         213 :             GUIntBig nSum = 0;
    6730         213 :             GUIntBig nSumSquare = 0;
    6731             :             // If no valid nodata, map to invalid value (256 for Byte)
    6732         213 :             const GUInt32 nNoDataValue =
    6733         236 :                 (sNoDataValues.bGotNoDataValue &&
    6734          23 :                  sNoDataValues.dfNoDataValue >= 0 &&
    6735          23 :                  sNoDataValues.dfNoDataValue <= nMaxValueType &&
    6736          23 :                  fabs(sNoDataValues.dfNoDataValue -
    6737          23 :                       static_cast<GUInt32>(sNoDataValues.dfNoDataValue +
    6738             :                                            1e-10)) < 1e-10)
    6739         236 :                     ? static_cast<GUInt32>(sNoDataValues.dfNoDataValue + 1e-10)
    6740             :                     : nMaxValueType + 1;
    6741             : 
    6742         213 :             for (GIntBig iSampleBlock = 0;
    6743       12737 :                  iSampleBlock <
    6744       12737 :                  static_cast<GIntBig>(nBlocksPerRow) * nBlocksPerColumn;
    6745       12524 :                  iSampleBlock += nSampleRate)
    6746             :             {
    6747       12524 :                 const int iYBlock =
    6748       12524 :                     static_cast<int>(iSampleBlock / nBlocksPerRow);
    6749       12524 :                 const int iXBlock =
    6750       12524 :                     static_cast<int>(iSampleBlock % nBlocksPerRow);
    6751             : 
    6752             :                 GDALRasterBlock *const poBlock =
    6753       12524 :                     GetLockedBlockRef(iXBlock, iYBlock);
    6754       12526 :                 if (poBlock == nullptr)
    6755           0 :                     return CE_Failure;
    6756             : 
    6757       12526 :                 void *const pData = poBlock->GetDataRef();
    6758             : 
    6759       12526 :                 int nXCheck = 0, nYCheck = 0;
    6760       12526 :                 GetActualBlockSize(iXBlock, iYBlock, &nXCheck, &nYCheck);
    6761             : 
    6762       12525 :                 if (eDataType == GDT_Byte)
    6763             :                 {
    6764             :                     ComputeStatisticsInternal<
    6765             :                         GByte, /* COMPUTE_OTHER_STATS = */ true>::
    6766       12055 :                         f(nXCheck, nBlockXSize, nYCheck,
    6767             :                           static_cast<const GByte *>(pData),
    6768             :                           nNoDataValue <= nMaxValueType, nNoDataValue, nMin,
    6769             :                           nMax, nSum, nSumSquare, nSampleCount, nValidCount);
    6770             :                 }
    6771             :                 else
    6772             :                 {
    6773             :                     ComputeStatisticsInternal<
    6774             :                         GUInt16, /* COMPUTE_OTHER_STATS = */ true>::
    6775         470 :                         f(nXCheck, nBlockXSize, nYCheck,
    6776             :                           static_cast<const GUInt16 *>(pData),
    6777             :                           nNoDataValue <= nMaxValueType, nNoDataValue, nMin,
    6778             :                           nMax, nSum, nSumSquare, nSampleCount, nValidCount);
    6779             :                 }
    6780             : 
    6781       12525 :                 poBlock->DropLock();
    6782             : 
    6783       12525 :                 if (!pfnProgress(static_cast<double>(iSampleBlock) /
    6784       12526 :                                      (static_cast<double>(nBlocksPerRow) *
    6785       12526 :                                       nBlocksPerColumn),
    6786             :                                  "Compute Statistics", pProgressData))
    6787             :                 {
    6788           1 :                     ReportError(CE_Failure, CPLE_UserInterrupt,
    6789             :                                 "User terminated");
    6790           0 :                     return CE_Failure;
    6791             :                 }
    6792             :             }
    6793             : 
    6794         213 :             if (!pfnProgress(1.0, "Compute Statistics", pProgressData))
    6795             :             {
    6796           0 :                 ReportError(CE_Failure, CPLE_UserInterrupt, "User terminated");
    6797           0 :                 return CE_Failure;
    6798             :             }
    6799             : 
    6800             :             /* --------------------------------------------------------------------
    6801             :              */
    6802             :             /*      Save computed information. */
    6803             :             /* --------------------------------------------------------------------
    6804             :              */
    6805         213 :             if (nValidCount)
    6806         204 :                 dfMean = static_cast<double>(nSum) / nValidCount;
    6807             : 
    6808             :             // To avoid potential precision issues when doing the difference,
    6809             :             // we need to do that computation on 128 bit rather than casting
    6810             :             // to double
    6811             :             const GDALUInt128 nTmpForStdDev(
    6812         213 :                 GDALUInt128::Mul(nSumSquare, nValidCount) -
    6813         426 :                 GDALUInt128::Mul(nSum, nSum));
    6814             :             const double dfStdDev =
    6815         213 :                 nValidCount > 0
    6816         213 :                     ? sqrt(static_cast<double>(nTmpForStdDev)) / nValidCount
    6817         213 :                     : 0.0;
    6818             : 
    6819         213 :             if (nValidCount > 0)
    6820             :             {
    6821         204 :                 if (bApproxOK)
    6822             :                 {
    6823          24 :                     SetMetadataItem("STATISTICS_APPROXIMATE", "YES");
    6824             :                 }
    6825         180 :                 else if (GetMetadataItem("STATISTICS_APPROXIMATE"))
    6826             :                 {
    6827           3 :                     SetMetadataItem("STATISTICS_APPROXIMATE", nullptr);
    6828             :                 }
    6829         204 :                 SetStatistics(nMin, nMax, dfMean, dfStdDev);
    6830             :             }
    6831             : 
    6832         213 :             SetValidPercent(nSampleCount, nValidCount);
    6833             : 
    6834             :             /* --------------------------------------------------------------------
    6835             :              */
    6836             :             /*      Record results. */
    6837             :             /* --------------------------------------------------------------------
    6838             :              */
    6839         213 :             if (pdfMin != nullptr)
    6840         210 :                 *pdfMin = nValidCount ? nMin : 0;
    6841         213 :             if (pdfMax != nullptr)
    6842         210 :                 *pdfMax = nValidCount ? nMax : 0;
    6843             : 
    6844         213 :             if (pdfMean != nullptr)
    6845         206 :                 *pdfMean = dfMean;
    6846             : 
    6847         213 :             if (pdfStdDev != nullptr)
    6848         206 :                 *pdfStdDev = dfStdDev;
    6849             : 
    6850         213 :             if (nValidCount > 0)
    6851         204 :                 return CE_None;
    6852             : 
    6853           9 :             ReportError(CE_Failure, CPLE_AppDefined,
    6854             :                         "Failed to compute statistics, no valid pixels found "
    6855             :                         "in sampling.");
    6856           9 :             return CE_Failure;
    6857             :         }
    6858             : 
    6859         248 :         GByte *pabyMaskData = nullptr;
    6860         248 :         if (poMaskBand)
    6861             :         {
    6862             :             pabyMaskData = static_cast<GByte *>(
    6863          16 :                 VSI_MALLOC2_VERBOSE(nBlockXSize, nBlockYSize));
    6864          16 :             if (!pabyMaskData)
    6865             :             {
    6866           0 :                 return CE_Failure;
    6867             :             }
    6868             :         }
    6869             : 
    6870         248 :         for (GIntBig iSampleBlock = 0;
    6871        5869 :              iSampleBlock <
    6872        5869 :              static_cast<GIntBig>(nBlocksPerRow) * nBlocksPerColumn;
    6873        5621 :              iSampleBlock += nSampleRate)
    6874             :         {
    6875        5621 :             const int iYBlock = static_cast<int>(iSampleBlock / nBlocksPerRow);
    6876        5621 :             const int iXBlock = static_cast<int>(iSampleBlock % nBlocksPerRow);
    6877             : 
    6878             :             GDALRasterBlock *const poBlock =
    6879        5621 :                 GetLockedBlockRef(iXBlock, iYBlock);
    6880        5621 :             if (poBlock == nullptr)
    6881             :             {
    6882           0 :                 CPLFree(pabyMaskData);
    6883           0 :                 return CE_Failure;
    6884             :             }
    6885             : 
    6886        5621 :             void *const pData = poBlock->GetDataRef();
    6887             : 
    6888        5621 :             int nXCheck = 0, nYCheck = 0;
    6889        5621 :             GetActualBlockSize(iXBlock, iYBlock, &nXCheck, &nYCheck);
    6890             : 
    6891        5722 :             if (poMaskBand &&
    6892         101 :                 poMaskBand->RasterIO(GF_Read, iXBlock * nBlockXSize,
    6893         101 :                                      iYBlock * nBlockYSize, nXCheck, nYCheck,
    6894             :                                      pabyMaskData, nXCheck, nYCheck, GDT_Byte,
    6895         101 :                                      0, nBlockXSize, nullptr) != CE_None)
    6896             :             {
    6897           0 :                 CPLFree(pabyMaskData);
    6898           0 :                 poBlock->DropLock();
    6899           0 :                 return CE_Failure;
    6900             :             }
    6901             : 
    6902             :             // This isn't the fastest way to do this, but is easier for now.
    6903       11426 :             for (int iY = 0; iY < nYCheck; iY++)
    6904             :             {
    6905     4364850 :                 for (int iX = 0; iX < nXCheck; iX++)
    6906             :                 {
    6907     4359040 :                     const GPtrDiff_t iOffset =
    6908     4359040 :                         iX + static_cast<GPtrDiff_t>(iY) * nBlockXSize;
    6909     4359040 :                     if (pabyMaskData && pabyMaskData[iOffset] == 0)
    6910      111827 :                         continue;
    6911             : 
    6912     4349170 :                     bool bValid = true;
    6913             :                     double dfValue =
    6914     4349170 :                         GetPixelValue(eDataType, bSignedByte, pData, iOffset,
    6915     4349170 :                                       sNoDataValues, bValid);
    6916             : 
    6917     4349170 :                     if (!bValid)
    6918      101956 :                         continue;
    6919             : 
    6920     4247220 :                     dfMin = std::min(dfMin, dfValue);
    6921     4247220 :                     dfMax = std::max(dfMax, dfValue);
    6922             : 
    6923     4247220 :                     nValidCount++;
    6924     4247220 :                     if (dfMin == dfMax)
    6925             :                     {
    6926     2173320 :                         if (nValidCount == 1)
    6927         247 :                             dfMean = dfMin;
    6928             :                     }
    6929             :                     else
    6930             :                     {
    6931     2073900 :                         const double dfDelta = dfValue - dfMean;
    6932     2073900 :                         dfMean += dfDelta / nValidCount;
    6933     2073900 :                         dfM2 += dfDelta * (dfValue - dfMean);
    6934             :                     }
    6935             :                 }
    6936             :             }
    6937             : 
    6938        5621 :             nSampleCount += static_cast<GUIntBig>(nXCheck) * nYCheck;
    6939             : 
    6940        5621 :             poBlock->DropLock();
    6941             : 
    6942        5621 :             if (!pfnProgress(
    6943        5621 :                     static_cast<double>(iSampleBlock) /
    6944        5621 :                         (static_cast<double>(nBlocksPerRow) * nBlocksPerColumn),
    6945             :                     "Compute Statistics", pProgressData))
    6946             :             {
    6947           0 :                 ReportError(CE_Failure, CPLE_UserInterrupt, "User terminated");
    6948           0 :                 CPLFree(pabyMaskData);
    6949           0 :                 return CE_Failure;
    6950             :             }
    6951             :         }
    6952             : 
    6953         248 :         CPLFree(pabyMaskData);
    6954             :     }
    6955             : 
    6956         248 :     if (!pfnProgress(1.0, "Compute Statistics", pProgressData))
    6957             :     {
    6958           0 :         ReportError(CE_Failure, CPLE_UserInterrupt, "User terminated");
    6959           0 :         return CE_Failure;
    6960             :     }
    6961             : 
    6962             :     /* -------------------------------------------------------------------- */
    6963             :     /*      Save computed information.                                      */
    6964             :     /* -------------------------------------------------------------------- */
    6965         248 :     const double dfStdDev = nValidCount > 0 ? sqrt(dfM2 / nValidCount) : 0.0;
    6966             : 
    6967         248 :     if (nValidCount > 0)
    6968             :     {
    6969         247 :         if (bApproxOK)
    6970             :         {
    6971           8 :             SetMetadataItem("STATISTICS_APPROXIMATE", "YES");
    6972             :         }
    6973         239 :         else if (GetMetadataItem("STATISTICS_APPROXIMATE"))
    6974             :         {
    6975           2 :             SetMetadataItem("STATISTICS_APPROXIMATE", nullptr);
    6976             :         }
    6977         247 :         SetStatistics(dfMin, dfMax, dfMean, dfStdDev);
    6978             :     }
    6979             :     else
    6980             :     {
    6981           1 :         dfMin = 0.0;
    6982           1 :         dfMax = 0.0;
    6983             :     }
    6984             : 
    6985         248 :     SetValidPercent(nSampleCount, nValidCount);
    6986             : 
    6987             :     /* -------------------------------------------------------------------- */
    6988             :     /*      Record results.                                                 */
    6989             :     /* -------------------------------------------------------------------- */
    6990         248 :     if (pdfMin != nullptr)
    6991         245 :         *pdfMin = dfMin;
    6992         248 :     if (pdfMax != nullptr)
    6993         245 :         *pdfMax = dfMax;
    6994             : 
    6995         248 :     if (pdfMean != nullptr)
    6996         243 :         *pdfMean = dfMean;
    6997             : 
    6998         248 :     if (pdfStdDev != nullptr)
    6999         243 :         *pdfStdDev = dfStdDev;
    7000             : 
    7001         248 :     if (nValidCount > 0)
    7002         247 :         return CE_None;
    7003             : 
    7004           1 :     ReportError(
    7005             :         CE_Failure, CPLE_AppDefined,
    7006             :         "Failed to compute statistics, no valid pixels found in sampling.");
    7007           1 :     return CE_Failure;
    7008             : }
    7009             : 
    7010             : /************************************************************************/
    7011             : /*                    GDALComputeRasterStatistics()                     */
    7012             : /************************************************************************/
    7013             : 
    7014             : /**
    7015             :  * \brief Compute image statistics.
    7016             :  *
    7017             :  * @see GDALRasterBand::ComputeStatistics()
    7018             :  */
    7019             : 
    7020         154 : CPLErr CPL_STDCALL GDALComputeRasterStatistics(GDALRasterBandH hBand,
    7021             :                                                int bApproxOK, double *pdfMin,
    7022             :                                                double *pdfMax, double *pdfMean,
    7023             :                                                double *pdfStdDev,
    7024             :                                                GDALProgressFunc pfnProgress,
    7025             :                                                void *pProgressData)
    7026             : 
    7027             : {
    7028         154 :     VALIDATE_POINTER1(hBand, "GDALComputeRasterStatistics", CE_Failure);
    7029             : 
    7030         154 :     GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
    7031             : 
    7032         154 :     return poBand->ComputeStatistics(bApproxOK, pdfMin, pdfMax, pdfMean,
    7033         154 :                                      pdfStdDev, pfnProgress, pProgressData);
    7034             : }
    7035             : 
    7036             : /************************************************************************/
    7037             : /*                           SetStatistics()                            */
    7038             : /************************************************************************/
    7039             : 
    7040             : /**
    7041             :  * \brief Set statistics on band.
    7042             :  *
    7043             :  * This method can be used to store min/max/mean/standard deviation
    7044             :  * statistics on a raster band.
    7045             :  *
    7046             :  * The default implementation stores them as metadata, and will only work
    7047             :  * on formats that can save arbitrary metadata.  This method cannot detect
    7048             :  * whether metadata will be properly saved and so may return CE_None even
    7049             :  * if the statistics will never be saved.
    7050             :  *
    7051             :  * This method is the same as the C function GDALSetRasterStatistics().
    7052             :  *
    7053             :  * @param dfMin minimum pixel value.
    7054             :  *
    7055             :  * @param dfMax maximum pixel value.
    7056             :  *
    7057             :  * @param dfMean mean (average) of all pixel values.
    7058             :  *
    7059             :  * @param dfStdDev Standard deviation of all pixel values.
    7060             :  *
    7061             :  * @return CE_None on success or CE_Failure on failure.
    7062             :  */
    7063             : 
    7064         479 : CPLErr GDALRasterBand::SetStatistics(double dfMin, double dfMax, double dfMean,
    7065             :                                      double dfStdDev)
    7066             : 
    7067             : {
    7068         479 :     char szValue[128] = {0};
    7069             : 
    7070         479 :     CPLsnprintf(szValue, sizeof(szValue), "%.14g", dfMin);
    7071         479 :     SetMetadataItem("STATISTICS_MINIMUM", szValue);
    7072             : 
    7073         479 :     CPLsnprintf(szValue, sizeof(szValue), "%.14g", dfMax);
    7074         479 :     SetMetadataItem("STATISTICS_MAXIMUM", szValue);
    7075             : 
    7076         479 :     CPLsnprintf(szValue, sizeof(szValue), "%.14g", dfMean);
    7077         479 :     SetMetadataItem("STATISTICS_MEAN", szValue);
    7078             : 
    7079         479 :     CPLsnprintf(szValue, sizeof(szValue), "%.14g", dfStdDev);
    7080         479 :     SetMetadataItem("STATISTICS_STDDEV", szValue);
    7081             : 
    7082         479 :     return CE_None;
    7083             : }
    7084             : 
    7085             : /************************************************************************/
    7086             : /*                      GDALSetRasterStatistics()                       */
    7087             : /************************************************************************/
    7088             : 
    7089             : /**
    7090             :  * \brief Set statistics on band.
    7091             :  *
    7092             :  * @see GDALRasterBand::SetStatistics()
    7093             :  */
    7094             : 
    7095           2 : CPLErr CPL_STDCALL GDALSetRasterStatistics(GDALRasterBandH hBand, double dfMin,
    7096             :                                            double dfMax, double dfMean,
    7097             :                                            double dfStdDev)
    7098             : 
    7099             : {
    7100           2 :     VALIDATE_POINTER1(hBand, "GDALSetRasterStatistics", CE_Failure);
    7101             : 
    7102           2 :     GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
    7103           2 :     return poBand->SetStatistics(dfMin, dfMax, dfMean, dfStdDev);
    7104             : }
    7105             : 
    7106             : /************************************************************************/
    7107             : /*                        ComputeRasterMinMax()                         */
    7108             : /************************************************************************/
    7109             : 
    7110             : template <class T, bool HAS_NODATA>
    7111      120175 : static void ComputeMinMax(const T *buffer, size_t nElts, T nodataValue, T *pMin,
    7112             :                           T *pMax)
    7113             : {
    7114      120175 :     T min0 = *pMin;
    7115      120175 :     T max0 = *pMax;
    7116      120175 :     T min1 = *pMin;
    7117      120175 :     T max1 = *pMax;
    7118             :     size_t i;
    7119      214453 :     for (i = 0; i + 1 < nElts; i += 2)
    7120             :     {
    7121       81892 :         if (!HAS_NODATA || buffer[i] != nodataValue)
    7122             :         {
    7123       94278 :             min0 = std::min(min0, buffer[i]);
    7124       94278 :             max0 = std::max(max0, buffer[i]);
    7125             :         }
    7126       81892 :         if (!HAS_NODATA || buffer[i + 1] != nodataValue)
    7127             :         {
    7128       94278 :             min1 = std::min(min1, buffer[i + 1]);
    7129       94278 :             max1 = std::max(max1, buffer[i + 1]);
    7130             :         }
    7131             :     }
    7132      120175 :     T min = std::min(min0, min1);
    7133      120175 :     T max = std::max(max0, max1);
    7134      120175 :     if (i < nElts)
    7135             :     {
    7136      118460 :         if (!HAS_NODATA || buffer[i] != nodataValue)
    7137             :         {
    7138      118480 :             min = std::min(min, buffer[i]);
    7139      118480 :             max = std::max(max, buffer[i]);
    7140             :         }
    7141             :     }
    7142      120175 :     *pMin = min;
    7143      120175 :     *pMax = max;
    7144      120175 : }
    7145             : 
    7146             : template <GDALDataType eDataType, bool bSignedByte>
    7147             : static void
    7148       11300 : ComputeMinMaxGeneric(const void *pData, int nXCheck, int nYCheck,
    7149             :                      int nBlockXSize, const GDALNoDataValues &sNoDataValues,
    7150             :                      const GByte *pabyMaskData, double &dfMin, double &dfMax)
    7151             : {
    7152       11300 :     double dfLocalMin = dfMin;
    7153       11300 :     double dfLocalMax = dfMax;
    7154             : 
    7155       40711 :     for (int iY = 0; iY < nYCheck; iY++)
    7156             :     {
    7157    18962027 :         for (int iX = 0; iX < nXCheck; iX++)
    7158             :         {
    7159    18932631 :             const GPtrDiff_t iOffset =
    7160    18932631 :                 iX + static_cast<GPtrDiff_t>(iY) * nBlockXSize;
    7161    18932631 :             if (pabyMaskData && pabyMaskData[iOffset] == 0)
    7162     3460310 :                 continue;
    7163    18838390 :             bool bValid = true;
    7164    18838390 :             double dfValue = GetPixelValue(eDataType, bSignedByte, pData,
    7165             :                                            iOffset, sNoDataValues, bValid);
    7166    18838390 :             if (!bValid)
    7167     3366069 :                 continue;
    7168             : 
    7169    15472282 :             dfLocalMin = std::min(dfLocalMin, dfValue);
    7170    15472282 :             dfLocalMax = std::max(dfLocalMax, dfValue);
    7171             :         }
    7172             :     }
    7173             : 
    7174       11300 :     dfMin = dfLocalMin;
    7175       11300 :     dfMax = dfLocalMax;
    7176       11300 : }
    7177             : 
    7178       11300 : static void ComputeMinMaxGeneric(const void *pData, GDALDataType eDataType,
    7179             :                                  bool bSignedByte, int nXCheck, int nYCheck,
    7180             :                                  int nBlockXSize,
    7181             :                                  const GDALNoDataValues &sNoDataValues,
    7182             :                                  const GByte *pabyMaskData, double &dfMin,
    7183             :                                  double &dfMax)
    7184             : {
    7185       11300 :     switch (eDataType)
    7186             :     {
    7187           0 :         case GDT_Unknown:
    7188           0 :             CPLAssert(false);
    7189             :             break;
    7190         672 :         case GDT_Byte:
    7191         672 :             if (bSignedByte)
    7192             :             {
    7193           3 :                 ComputeMinMaxGeneric<GDT_Byte, true>(
    7194             :                     pData, nXCheck, nYCheck, nBlockXSize, sNoDataValues,
    7195             :                     pabyMaskData, dfMin, dfMax);
    7196             :             }
    7197             :             else
    7198             :             {
    7199         669 :                 ComputeMinMaxGeneric<GDT_Byte, false>(
    7200             :                     pData, nXCheck, nYCheck, nBlockXSize, sNoDataValues,
    7201             :                     pabyMaskData, dfMin, dfMax);
    7202             :             }
    7203         672 :             break;
    7204         106 :         case GDT_Int8:
    7205         106 :             ComputeMinMaxGeneric<GDT_Int8, false>(pData, nXCheck, nYCheck,
    7206             :                                                   nBlockXSize, sNoDataValues,
    7207             :                                                   pabyMaskData, dfMin, dfMax);
    7208         106 :             break;
    7209         200 :         case GDT_UInt16:
    7210         200 :             ComputeMinMaxGeneric<GDT_UInt16, false>(pData, nXCheck, nYCheck,
    7211             :                                                     nBlockXSize, sNoDataValues,
    7212             :                                                     pabyMaskData, dfMin, dfMax);
    7213         200 :             break;
    7214           1 :         case GDT_Int16:
    7215           1 :             ComputeMinMaxGeneric<GDT_Int16, false>(pData, nXCheck, nYCheck,
    7216             :                                                    nBlockXSize, sNoDataValues,
    7217             :                                                    pabyMaskData, dfMin, dfMax);
    7218           1 :             break;
    7219         201 :         case GDT_UInt32:
    7220         201 :             ComputeMinMaxGeneric<GDT_UInt32, false>(pData, nXCheck, nYCheck,
    7221             :                                                     nBlockXSize, sNoDataValues,
    7222             :                                                     pabyMaskData, dfMin, dfMax);
    7223         201 :             break;
    7224        1048 :         case GDT_Int32:
    7225        1048 :             ComputeMinMaxGeneric<GDT_Int32, false>(pData, nXCheck, nYCheck,
    7226             :                                                    nBlockXSize, sNoDataValues,
    7227             :                                                    pabyMaskData, dfMin, dfMax);
    7228        1048 :             break;
    7229          16 :         case GDT_UInt64:
    7230          16 :             ComputeMinMaxGeneric<GDT_UInt64, false>(pData, nXCheck, nYCheck,
    7231             :                                                     nBlockXSize, sNoDataValues,
    7232             :                                                     pabyMaskData, dfMin, dfMax);
    7233          16 :             break;
    7234          28 :         case GDT_Int64:
    7235          28 :             ComputeMinMaxGeneric<GDT_Int64, false>(pData, nXCheck, nYCheck,
    7236             :                                                    nBlockXSize, sNoDataValues,
    7237             :                                                    pabyMaskData, dfMin, dfMax);
    7238          28 :             break;
    7239           0 :         case GDT_Float16:
    7240           0 :             ComputeMinMaxGeneric<GDT_Float16, false>(
    7241             :                 pData, nXCheck, nYCheck, nBlockXSize, sNoDataValues,
    7242             :                 pabyMaskData, dfMin, dfMax);
    7243           0 :             break;
    7244        5545 :         case GDT_Float32:
    7245        5545 :             ComputeMinMaxGeneric<GDT_Float32, false>(
    7246             :                 pData, nXCheck, nYCheck, nBlockXSize, sNoDataValues,
    7247             :                 pabyMaskData, dfMin, dfMax);
    7248        5545 :             break;
    7249        3373 :         case GDT_Float64:
    7250        3373 :             ComputeMinMaxGeneric<GDT_Float64, false>(
    7251             :                 pData, nXCheck, nYCheck, nBlockXSize, sNoDataValues,
    7252             :                 pabyMaskData, dfMin, dfMax);
    7253        3373 :             break;
    7254           9 :         case GDT_CInt16:
    7255           9 :             ComputeMinMaxGeneric<GDT_CInt16, false>(pData, nXCheck, nYCheck,
    7256             :                                                     nBlockXSize, sNoDataValues,
    7257             :                                                     pabyMaskData, dfMin, dfMax);
    7258           9 :             break;
    7259           9 :         case GDT_CInt32:
    7260           9 :             ComputeMinMaxGeneric<GDT_CInt32, false>(pData, nXCheck, nYCheck,
    7261             :                                                     nBlockXSize, sNoDataValues,
    7262             :                                                     pabyMaskData, dfMin, dfMax);
    7263           9 :             break;
    7264           0 :         case GDT_CFloat16:
    7265           0 :             ComputeMinMaxGeneric<GDT_CFloat16, false>(
    7266             :                 pData, nXCheck, nYCheck, nBlockXSize, sNoDataValues,
    7267             :                 pabyMaskData, dfMin, dfMax);
    7268           0 :             break;
    7269          75 :         case GDT_CFloat32:
    7270          75 :             ComputeMinMaxGeneric<GDT_CFloat32, false>(
    7271             :                 pData, nXCheck, nYCheck, nBlockXSize, sNoDataValues,
    7272             :                 pabyMaskData, dfMin, dfMax);
    7273          75 :             break;
    7274          17 :         case GDT_CFloat64:
    7275          17 :             ComputeMinMaxGeneric<GDT_CFloat64, false>(
    7276             :                 pData, nXCheck, nYCheck, nBlockXSize, sNoDataValues,
    7277             :                 pabyMaskData, dfMin, dfMax);
    7278          17 :             break;
    7279           0 :         case GDT_TypeCount:
    7280           0 :             CPLAssert(false);
    7281             :             break;
    7282             :     }
    7283       11300 : }
    7284             : 
    7285         720 : static bool ComputeMinMaxGenericIterBlocks(
    7286             :     GDALRasterBand *poBand, GDALDataType eDataType, bool bSignedByte,
    7287             :     GIntBig nTotalBlocks, int nSampleRate, int nBlocksPerRow,
    7288             :     const GDALNoDataValues &sNoDataValues, GDALRasterBand *poMaskBand,
    7289             :     double &dfMin, double &dfMax)
    7290             : 
    7291             : {
    7292         720 :     GByte *pabyMaskData = nullptr;
    7293             :     int nBlockXSize, nBlockYSize;
    7294         720 :     poBand->GetBlockSize(&nBlockXSize, &nBlockYSize);
    7295             : 
    7296         720 :     if (poMaskBand)
    7297             :     {
    7298             :         pabyMaskData =
    7299          40 :             static_cast<GByte *>(VSI_MALLOC2_VERBOSE(nBlockXSize, nBlockYSize));
    7300          40 :         if (!pabyMaskData)
    7301             :         {
    7302           0 :             return false;
    7303             :         }
    7304             :     }
    7305             : 
    7306       12020 :     for (GIntBig iSampleBlock = 0; iSampleBlock < nTotalBlocks;
    7307       11300 :          iSampleBlock += nSampleRate)
    7308             :     {
    7309       11300 :         const int iYBlock = static_cast<int>(iSampleBlock / nBlocksPerRow);
    7310       11300 :         const int iXBlock = static_cast<int>(iSampleBlock % nBlocksPerRow);
    7311             : 
    7312       11300 :         GDALRasterBlock *poBlock = poBand->GetLockedBlockRef(iXBlock, iYBlock);
    7313       11300 :         if (poBlock == nullptr)
    7314             :         {
    7315           0 :             CPLFree(pabyMaskData);
    7316           0 :             return false;
    7317             :         }
    7318             : 
    7319       11300 :         void *const pData = poBlock->GetDataRef();
    7320             : 
    7321       11300 :         int nXCheck = 0, nYCheck = 0;
    7322       11300 :         poBand->GetActualBlockSize(iXBlock, iYBlock, &nXCheck, &nYCheck);
    7323             : 
    7324       12171 :         if (poMaskBand &&
    7325         871 :             poMaskBand->RasterIO(GF_Read, iXBlock * nBlockXSize,
    7326             :                                  iYBlock * nBlockYSize, nXCheck, nYCheck,
    7327             :                                  pabyMaskData, nXCheck, nYCheck, GDT_Byte, 0,
    7328             :                                  nBlockXSize, nullptr) != CE_None)
    7329             :         {
    7330           0 :             poBlock->DropLock();
    7331           0 :             CPLFree(pabyMaskData);
    7332           0 :             return false;
    7333             :         }
    7334             : 
    7335       11300 :         ComputeMinMaxGeneric(pData, eDataType, bSignedByte, nXCheck, nYCheck,
    7336             :                              nBlockXSize, sNoDataValues, pabyMaskData, dfMin,
    7337             :                              dfMax);
    7338             : 
    7339       11300 :         poBlock->DropLock();
    7340             :     }
    7341             : 
    7342         720 :     CPLFree(pabyMaskData);
    7343         720 :     return true;
    7344             : }
    7345             : 
    7346             : /**
    7347             :  * \brief Compute the min/max values for a band.
    7348             :  *
    7349             :  * If approximate is OK, then the band's GetMinimum()/GetMaximum() will
    7350             :  * be trusted.  If it doesn't work, a subsample of blocks will be read to
    7351             :  * get an approximate min/max.  If the band has a nodata value it will
    7352             :  * be excluded from the minimum and maximum.
    7353             :  *
    7354             :  * If bApprox is FALSE, then all pixels will be read and used to compute
    7355             :  * an exact range.
    7356             :  *
    7357             :  * This method is the same as the C function GDALComputeRasterMinMax().
    7358             :  *
    7359             :  * @param bApproxOK TRUE if an approximate (faster) answer is OK, otherwise
    7360             :  * FALSE.
    7361             :  * @param adfMinMax the array in which the minimum (adfMinMax[0]) and the
    7362             :  * maximum (adfMinMax[1]) are returned.
    7363             :  *
    7364             :  * @return CE_None on success or CE_Failure on failure.
    7365             :  */
    7366             : 
    7367        1559 : CPLErr GDALRasterBand::ComputeRasterMinMax(int bApproxOK, double *adfMinMax)
    7368             : {
    7369             :     /* -------------------------------------------------------------------- */
    7370             :     /*      Does the driver already know the min/max?                       */
    7371             :     /* -------------------------------------------------------------------- */
    7372        1559 :     if (bApproxOK)
    7373             :     {
    7374          23 :         int bSuccessMin = FALSE;
    7375          23 :         int bSuccessMax = FALSE;
    7376             : 
    7377          23 :         double dfMin = GetMinimum(&bSuccessMin);
    7378          23 :         double dfMax = GetMaximum(&bSuccessMax);
    7379             : 
    7380          23 :         if (bSuccessMin && bSuccessMax)
    7381             :         {
    7382           1 :             adfMinMax[0] = dfMin;
    7383           1 :             adfMinMax[1] = dfMax;
    7384           1 :             return CE_None;
    7385             :         }
    7386             :     }
    7387             : 
    7388             :     /* -------------------------------------------------------------------- */
    7389             :     /*      If we have overview bands, use them for min/max.                */
    7390             :     /* -------------------------------------------------------------------- */
    7391             :     // cppcheck-suppress knownConditionTrueFalse
    7392        1558 :     if (bApproxOK && GetOverviewCount() > 0 && !HasArbitraryOverviews())
    7393             :     {
    7394             :         GDALRasterBand *poBand =
    7395           0 :             GetRasterSampleOverview(GDALSTAT_APPROX_NUMSAMPLES);
    7396             : 
    7397           0 :         if (poBand != this)
    7398           0 :             return poBand->ComputeRasterMinMax(FALSE, adfMinMax);
    7399             :     }
    7400             : 
    7401             :     /* -------------------------------------------------------------------- */
    7402             :     /*      Read actual data and compute minimum and maximum.               */
    7403             :     /* -------------------------------------------------------------------- */
    7404        1558 :     GDALNoDataValues sNoDataValues(this, eDataType);
    7405        1558 :     GDALRasterBand *poMaskBand = nullptr;
    7406        1558 :     if (!sNoDataValues.bGotNoDataValue)
    7407             :     {
    7408        1313 :         const int l_nMaskFlags = GetMaskFlags();
    7409        1353 :         if (l_nMaskFlags != GMF_ALL_VALID && l_nMaskFlags != GMF_NODATA &&
    7410          40 :             GetColorInterpretation() != GCI_AlphaBand)
    7411             :         {
    7412          40 :             poMaskBand = GetMaskBand();
    7413             :         }
    7414             :     }
    7415             : 
    7416        1558 :     bool bSignedByte = false;
    7417        1558 :     if (eDataType == GDT_Byte)
    7418             :     {
    7419         630 :         EnablePixelTypeSignedByteWarning(false);
    7420             :         const char *pszPixelType =
    7421         630 :             GetMetadataItem("PIXELTYPE", "IMAGE_STRUCTURE");
    7422         630 :         EnablePixelTypeSignedByteWarning(true);
    7423         630 :         bSignedByte =
    7424         630 :             pszPixelType != nullptr && EQUAL(pszPixelType, "SIGNEDBYTE");
    7425             :     }
    7426             : 
    7427             :     GDALRasterIOExtraArg sExtraArg;
    7428        1558 :     INIT_RASTERIO_EXTRA_ARG(sExtraArg);
    7429             : 
    7430        3116 :     GUInt32 nMin = (eDataType == GDT_Byte)
    7431        1558 :                        ? 255
    7432             :                        : 65535;  // used for GByte & GUInt16 cases
    7433        1558 :     GUInt32 nMax = 0;            // used for GByte & GUInt16 cases
    7434        1558 :     GInt16 nMinInt16 =
    7435             :         std::numeric_limits<GInt16>::max();  // used for GInt16 case
    7436        1558 :     GInt16 nMaxInt16 =
    7437             :         std::numeric_limits<GInt16>::lowest();  // used for GInt16 case
    7438        1558 :     double dfMin =
    7439             :         std::numeric_limits<double>::infinity();  // used for generic code path
    7440        1558 :     double dfMax =
    7441             :         -std::numeric_limits<double>::infinity();  // used for generic code path
    7442        1558 :     const bool bUseOptimizedPath =
    7443        2477 :         !poMaskBand && ((eDataType == GDT_Byte && !bSignedByte) ||
    7444         919 :                         eDataType == GDT_Int16 || eDataType == GDT_UInt16);
    7445             : 
    7446             :     const auto ComputeMinMaxForBlock =
    7447       20447 :         [this, bSignedByte, &sNoDataValues, &nMin, &nMax, &nMinInt16,
    7448             :          &nMaxInt16](const void *pData, int nXCheck, int nBufferWidth,
    7449      240537 :                      int nYCheck)
    7450             :     {
    7451       20447 :         if (eDataType == GDT_Byte && !bSignedByte)
    7452             :         {
    7453             :             const bool bHasNoData =
    7454       11561 :                 sNoDataValues.bGotNoDataValue &&
    7455       29466 :                 GDALIsValueInRange<GByte>(sNoDataValues.dfNoDataValue) &&
    7456       11561 :                 static_cast<GByte>(sNoDataValues.dfNoDataValue) ==
    7457       11561 :                     sNoDataValues.dfNoDataValue;
    7458       17905 :             const GUInt32 nNoDataValue =
    7459       17905 :                 bHasNoData ? static_cast<GByte>(sNoDataValues.dfNoDataValue)
    7460             :                            : 0;
    7461             :             GUIntBig nSum, nSumSquare, nSampleCount, nValidCount;  // unused
    7462             :             ComputeStatisticsInternal<GByte,
    7463             :                                       /* COMPUTE_OTHER_STATS = */ false>::
    7464       17905 :                 f(nXCheck, nBufferWidth, nYCheck,
    7465             :                   static_cast<const GByte *>(pData), bHasNoData, nNoDataValue,
    7466       17905 :                   nMin, nMax, nSum, nSumSquare, nSampleCount, nValidCount);
    7467             :         }
    7468        2542 :         else if (eDataType == GDT_UInt16)
    7469             :         {
    7470             :             const bool bHasNoData =
    7471          83 :                 sNoDataValues.bGotNoDataValue &&
    7472        1237 :                 GDALIsValueInRange<GUInt16>(sNoDataValues.dfNoDataValue) &&
    7473          83 :                 static_cast<GUInt16>(sNoDataValues.dfNoDataValue) ==
    7474          83 :                     sNoDataValues.dfNoDataValue;
    7475        1154 :             const GUInt32 nNoDataValue =
    7476        1154 :                 bHasNoData ? static_cast<GUInt16>(sNoDataValues.dfNoDataValue)
    7477             :                            : 0;
    7478             :             GUIntBig nSum, nSumSquare, nSampleCount, nValidCount;  // unused
    7479             :             ComputeStatisticsInternal<GUInt16,
    7480             :                                       /* COMPUTE_OTHER_STATS = */ false>::
    7481        1154 :                 f(nXCheck, nBufferWidth, nYCheck,
    7482             :                   static_cast<const GUInt16 *>(pData), bHasNoData, nNoDataValue,
    7483             :                   nMin, nMax, nSum, nSumSquare, nSampleCount, nValidCount);
    7484             :         }
    7485        1388 :         else if (eDataType == GDT_Int16)
    7486             :         {
    7487             :             const bool bHasNoData =
    7488        1214 :                 sNoDataValues.bGotNoDataValue &&
    7489        2602 :                 GDALIsValueInRange<int16_t>(sNoDataValues.dfNoDataValue) &&
    7490        1214 :                 static_cast<int16_t>(sNoDataValues.dfNoDataValue) ==
    7491        1214 :                     sNoDataValues.dfNoDataValue;
    7492        1388 :             if (bHasNoData)
    7493             :             {
    7494        1214 :                 const int16_t nNoDataValue =
    7495        1214 :                     static_cast<int16_t>(sNoDataValues.dfNoDataValue);
    7496      120117 :                 for (int iY = 0; iY < nYCheck; iY++)
    7497             :                 {
    7498      118903 :                     ComputeMinMax<int16_t, true>(
    7499      118903 :                         static_cast<const int16_t *>(pData) +
    7500      118903 :                             static_cast<size_t>(iY) * nBufferWidth,
    7501             :                         nXCheck, nNoDataValue, &nMinInt16, &nMaxInt16);
    7502             :                 }
    7503             :             }
    7504             :             else
    7505             :             {
    7506        1446 :                 for (int iY = 0; iY < nYCheck; iY++)
    7507             :                 {
    7508        1272 :                     ComputeMinMax<int16_t, false>(
    7509        1272 :                         static_cast<const int16_t *>(pData) +
    7510        1272 :                             static_cast<size_t>(iY) * nBufferWidth,
    7511             :                         nXCheck, 0, &nMinInt16, &nMaxInt16);
    7512             :                 }
    7513             :             }
    7514             :         }
    7515       20447 :     };
    7516             : 
    7517        1558 :     if (bApproxOK && HasArbitraryOverviews())
    7518             :     {
    7519             :         /* --------------------------------------------------------------------
    7520             :          */
    7521             :         /*      Figure out how much the image should be reduced to get an */
    7522             :         /*      approximate value. */
    7523             :         /* --------------------------------------------------------------------
    7524             :          */
    7525           0 :         double dfReduction = sqrt(static_cast<double>(nRasterXSize) *
    7526           0 :                                   nRasterYSize / GDALSTAT_APPROX_NUMSAMPLES);
    7527             : 
    7528           0 :         int nXReduced = nRasterXSize;
    7529           0 :         int nYReduced = nRasterYSize;
    7530           0 :         if (dfReduction > 1.0)
    7531             :         {
    7532           0 :             nXReduced = static_cast<int>(nRasterXSize / dfReduction);
    7533           0 :             nYReduced = static_cast<int>(nRasterYSize / dfReduction);
    7534             : 
    7535             :             // Catch the case of huge resizing ratios here
    7536           0 :             if (nXReduced == 0)
    7537           0 :                 nXReduced = 1;
    7538           0 :             if (nYReduced == 0)
    7539           0 :                 nYReduced = 1;
    7540             :         }
    7541             : 
    7542           0 :         void *const pData = CPLMalloc(cpl::fits_on<int>(
    7543           0 :             GDALGetDataTypeSizeBytes(eDataType) * nXReduced * nYReduced));
    7544             : 
    7545             :         const CPLErr eErr =
    7546           0 :             IRasterIO(GF_Read, 0, 0, nRasterXSize, nRasterYSize, pData,
    7547           0 :                       nXReduced, nYReduced, eDataType, 0, 0, &sExtraArg);
    7548           0 :         if (eErr != CE_None)
    7549             :         {
    7550           0 :             CPLFree(pData);
    7551           0 :             return eErr;
    7552             :         }
    7553             : 
    7554           0 :         GByte *pabyMaskData = nullptr;
    7555           0 :         if (poMaskBand)
    7556             :         {
    7557             :             pabyMaskData =
    7558           0 :                 static_cast<GByte *>(VSI_MALLOC2_VERBOSE(nXReduced, nYReduced));
    7559           0 :             if (!pabyMaskData)
    7560             :             {
    7561           0 :                 CPLFree(pData);
    7562           0 :                 return CE_Failure;
    7563             :             }
    7564             : 
    7565           0 :             if (poMaskBand->RasterIO(GF_Read, 0, 0, nRasterXSize, nRasterYSize,
    7566             :                                      pabyMaskData, nXReduced, nYReduced,
    7567           0 :                                      GDT_Byte, 0, 0, nullptr) != CE_None)
    7568             :             {
    7569           0 :                 CPLFree(pData);
    7570           0 :                 CPLFree(pabyMaskData);
    7571           0 :                 return CE_Failure;
    7572             :             }
    7573             :         }
    7574             : 
    7575           0 :         if (bUseOptimizedPath)
    7576             :         {
    7577           0 :             ComputeMinMaxForBlock(pData, nXReduced, nXReduced, nYReduced);
    7578             :         }
    7579             :         else
    7580             :         {
    7581           0 :             ComputeMinMaxGeneric(pData, eDataType, bSignedByte, nXReduced,
    7582             :                                  nYReduced, nXReduced, sNoDataValues,
    7583             :                                  pabyMaskData, dfMin, dfMax);
    7584             :         }
    7585             : 
    7586           0 :         CPLFree(pData);
    7587           0 :         CPLFree(pabyMaskData);
    7588             :     }
    7589             : 
    7590             :     else  // No arbitrary overviews
    7591             :     {
    7592        1558 :         if (!InitBlockInfo())
    7593           0 :             return CE_Failure;
    7594             : 
    7595             :         /* --------------------------------------------------------------------
    7596             :          */
    7597             :         /*      Figure out the ratio of blocks we will read to get an */
    7598             :         /*      approximate value. */
    7599             :         /* --------------------------------------------------------------------
    7600             :          */
    7601        1558 :         int nSampleRate = 1;
    7602             : 
    7603        1558 :         if (bApproxOK)
    7604             :         {
    7605          22 :             nSampleRate = static_cast<int>(std::max(
    7606          44 :                 1.0,
    7607          22 :                 sqrt(static_cast<double>(nBlocksPerRow) * nBlocksPerColumn)));
    7608             :             // We want to avoid probing only the first column of blocks for
    7609             :             // a square shaped raster, because it is not unlikely that it may
    7610             :             // be padding only (#6378).
    7611          22 :             if (nSampleRate == nBlocksPerRow && nBlocksPerRow > 1)
    7612           0 :                 nSampleRate += 1;
    7613             :         }
    7614             : 
    7615        1558 :         if (bUseOptimizedPath)
    7616             :         {
    7617         838 :             for (GIntBig iSampleBlock = 0;
    7618       21210 :                  iSampleBlock <
    7619       21210 :                  static_cast<GIntBig>(nBlocksPerRow) * nBlocksPerColumn;
    7620       20372 :                  iSampleBlock += nSampleRate)
    7621             :             {
    7622       20448 :                 const int iYBlock =
    7623       20448 :                     static_cast<int>(iSampleBlock / nBlocksPerRow);
    7624       20448 :                 const int iXBlock =
    7625       20448 :                     static_cast<int>(iSampleBlock % nBlocksPerRow);
    7626             : 
    7627       20448 :                 GDALRasterBlock *poBlock = GetLockedBlockRef(iXBlock, iYBlock);
    7628       20448 :                 if (poBlock == nullptr)
    7629           1 :                     return CE_Failure;
    7630             : 
    7631       20447 :                 void *const pData = poBlock->GetDataRef();
    7632             : 
    7633       20447 :                 int nXCheck = 0, nYCheck = 0;
    7634       20447 :                 GetActualBlockSize(iXBlock, iYBlock, &nXCheck, &nYCheck);
    7635             : 
    7636       20447 :                 ComputeMinMaxForBlock(pData, nXCheck, nBlockXSize, nYCheck);
    7637             : 
    7638       20447 :                 poBlock->DropLock();
    7639             : 
    7640       20447 :                 if (eDataType == GDT_Byte && !bSignedByte && nMin == 0 &&
    7641        4023 :                     nMax == 255)
    7642          75 :                     break;
    7643             :             }
    7644             :         }
    7645             :         else
    7646             :         {
    7647         720 :             const GIntBig nTotalBlocks =
    7648         720 :                 static_cast<GIntBig>(nBlocksPerRow) * nBlocksPerColumn;
    7649         720 :             if (!ComputeMinMaxGenericIterBlocks(
    7650             :                     this, eDataType, bSignedByte, nTotalBlocks, nSampleRate,
    7651             :                     nBlocksPerRow, sNoDataValues, poMaskBand, dfMin, dfMax))
    7652             :             {
    7653           0 :                 return CE_Failure;
    7654             :             }
    7655             :         }
    7656             :     }
    7657             : 
    7658        1557 :     if (bUseOptimizedPath)
    7659             :     {
    7660         837 :         if ((eDataType == GDT_Byte && !bSignedByte) || eDataType == GDT_UInt16)
    7661             :         {
    7662         735 :             dfMin = nMin;
    7663         735 :             dfMax = nMax;
    7664             :         }
    7665         102 :         else if (eDataType == GDT_Int16)
    7666             :         {
    7667         102 :             dfMin = nMinInt16;
    7668         102 :             dfMax = nMaxInt16;
    7669             :         }
    7670             :     }
    7671             : 
    7672        1557 :     if (dfMin > dfMax)
    7673             :     {
    7674           8 :         adfMinMax[0] = 0;
    7675           8 :         adfMinMax[1] = 0;
    7676           8 :         ReportError(
    7677             :             CE_Failure, CPLE_AppDefined,
    7678             :             "Failed to compute min/max, no valid pixels found in sampling.");
    7679           8 :         return CE_Failure;
    7680             :     }
    7681             : 
    7682        1549 :     adfMinMax[0] = dfMin;
    7683        1549 :     adfMinMax[1] = dfMax;
    7684             : 
    7685        1549 :     return CE_None;
    7686             : }
    7687             : 
    7688             : /************************************************************************/
    7689             : /*                      GDALComputeRasterMinMax()                       */
    7690             : /************************************************************************/
    7691             : 
    7692             : /**
    7693             :  * \brief Compute the min/max values for a band.
    7694             :  *
    7695             :  * @see GDALRasterBand::ComputeRasterMinMax()
    7696             :  *
    7697             :  * @note Prior to GDAL 3.6, this function returned void
    7698             :  */
    7699             : 
    7700        1479 : CPLErr CPL_STDCALL GDALComputeRasterMinMax(GDALRasterBandH hBand, int bApproxOK,
    7701             :                                            double adfMinMax[2])
    7702             : 
    7703             : {
    7704        1479 :     VALIDATE_POINTER1(hBand, "GDALComputeRasterMinMax", CE_Failure);
    7705             : 
    7706        1479 :     GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
    7707        1479 :     return poBand->ComputeRasterMinMax(bApproxOK, adfMinMax);
    7708             : }
    7709             : 
    7710             : /************************************************************************/
    7711             : /*                    ComputeRasterMinMaxLocation()                     */
    7712             : /************************************************************************/
    7713             : 
    7714             : /**
    7715             :  * \brief Compute the min/max values for a band, and their location.
    7716             :  *
    7717             :  * Pixels whose value matches the nodata value or are masked by the mask
    7718             :  * band are ignored.
    7719             :  *
    7720             :  * If the minimum or maximum value is hit in several locations, it is not
    7721             :  * specified which one will be returned.
    7722             :  *
    7723             :  * @param[out] pdfMin Pointer to the minimum value.
    7724             :  * @param[out] pdfMax Pointer to the maximum value.
    7725             :  * @param[out] pnMinX Pointer to the column where the minimum value is hit.
    7726             :  * @param[out] pnMinY Pointer to the line where the minimum value is hit.
    7727             :  * @param[out] pnMaxX Pointer to the column where the maximum value is hit.
    7728             :  * @param[out] pnMaxY Pointer to the line where the maximum value is hit.
    7729             :  *
    7730             :  * @return CE_None in case of success, CE_Warning if there are no valid values,
    7731             :  *         CE_Failure in case of error.
    7732             :  *
    7733             :  * @since GDAL 3.11
    7734             :  */
    7735             : 
    7736           8 : CPLErr GDALRasterBand::ComputeRasterMinMaxLocation(double *pdfMin,
    7737             :                                                    double *pdfMax, int *pnMinX,
    7738             :                                                    int *pnMinY, int *pnMaxX,
    7739             :                                                    int *pnMaxY)
    7740             : {
    7741           8 :     int nMinX = -1;
    7742           8 :     int nMinY = -1;
    7743           8 :     int nMaxX = -1;
    7744           8 :     int nMaxY = -1;
    7745           8 :     double dfMin = std::numeric_limits<double>::infinity();
    7746           8 :     double dfMax = -std::numeric_limits<double>::infinity();
    7747           8 :     if (pdfMin)
    7748           5 :         *pdfMin = dfMin;
    7749           8 :     if (pdfMax)
    7750           5 :         *pdfMax = dfMax;
    7751           8 :     if (pnMinX)
    7752           6 :         *pnMinX = nMinX;
    7753           8 :     if (pnMinY)
    7754           6 :         *pnMinY = nMinY;
    7755           8 :     if (pnMaxX)
    7756           6 :         *pnMaxX = nMaxX;
    7757           8 :     if (pnMaxY)
    7758           6 :         *pnMaxY = nMaxY;
    7759             : 
    7760           8 :     if (GDALDataTypeIsComplex(eDataType))
    7761             :     {
    7762           0 :         CPLError(CE_Failure, CPLE_NotSupported,
    7763             :                  "Complex data type not supported");
    7764           0 :         return CE_Failure;
    7765             :     }
    7766             : 
    7767           8 :     if (!InitBlockInfo())
    7768           0 :         return CE_Failure;
    7769             : 
    7770           8 :     GDALNoDataValues sNoDataValues(this, eDataType);
    7771           8 :     GDALRasterBand *poMaskBand = nullptr;
    7772           8 :     if (!sNoDataValues.bGotNoDataValue)
    7773             :     {
    7774           8 :         const int l_nMaskFlags = GetMaskFlags();
    7775           9 :         if (l_nMaskFlags != GMF_ALL_VALID && l_nMaskFlags != GMF_NODATA &&
    7776           1 :             GetColorInterpretation() != GCI_AlphaBand)
    7777             :         {
    7778           1 :             poMaskBand = GetMaskBand();
    7779             :         }
    7780             :     }
    7781             : 
    7782           8 :     bool bSignedByte = false;
    7783           8 :     if (eDataType == GDT_Byte)
    7784             :     {
    7785           7 :         EnablePixelTypeSignedByteWarning(false);
    7786             :         const char *pszPixelType =
    7787           7 :             GetMetadataItem("PIXELTYPE", "IMAGE_STRUCTURE");
    7788           7 :         EnablePixelTypeSignedByteWarning(true);
    7789           7 :         bSignedByte =
    7790           7 :             pszPixelType != nullptr && EQUAL(pszPixelType, "SIGNEDBYTE");
    7791             :     }
    7792             : 
    7793           8 :     GByte *pabyMaskData = nullptr;
    7794           8 :     if (poMaskBand)
    7795             :     {
    7796             :         pabyMaskData =
    7797           1 :             static_cast<GByte *>(VSI_MALLOC2_VERBOSE(nBlockXSize, nBlockYSize));
    7798           1 :         if (!pabyMaskData)
    7799             :         {
    7800           0 :             return CE_Failure;
    7801             :         }
    7802             :     }
    7803             : 
    7804           8 :     const GIntBig nTotalBlocks =
    7805           8 :         static_cast<GIntBig>(nBlocksPerRow) * nBlocksPerColumn;
    7806           8 :     bool bNeedsMin = pdfMin || pnMinX || pnMinY;
    7807           8 :     bool bNeedsMax = pdfMax || pnMaxX || pnMaxY;
    7808          16 :     for (GIntBig iBlock = 0; iBlock < nTotalBlocks; ++iBlock)
    7809             :     {
    7810          11 :         const int iYBlock = static_cast<int>(iBlock / nBlocksPerRow);
    7811          11 :         const int iXBlock = static_cast<int>(iBlock % nBlocksPerRow);
    7812             : 
    7813          11 :         GDALRasterBlock *poBlock = GetLockedBlockRef(iXBlock, iYBlock);
    7814          11 :         if (poBlock == nullptr)
    7815             :         {
    7816           0 :             CPLFree(pabyMaskData);
    7817           0 :             return CE_Failure;
    7818             :         }
    7819             : 
    7820          11 :         void *const pData = poBlock->GetDataRef();
    7821             : 
    7822          11 :         int nXCheck = 0, nYCheck = 0;
    7823          11 :         GetActualBlockSize(iXBlock, iYBlock, &nXCheck, &nYCheck);
    7824             : 
    7825          13 :         if (poMaskBand &&
    7826           2 :             poMaskBand->RasterIO(GF_Read, iXBlock * nBlockXSize,
    7827           2 :                                  iYBlock * nBlockYSize, nXCheck, nYCheck,
    7828             :                                  pabyMaskData, nXCheck, nYCheck, GDT_Byte, 0,
    7829           2 :                                  nBlockXSize, nullptr) != CE_None)
    7830             :         {
    7831           0 :             poBlock->DropLock();
    7832           0 :             CPLFree(pabyMaskData);
    7833           0 :             return CE_Failure;
    7834             :         }
    7835             : 
    7836          11 :         if (poMaskBand || nYCheck < nBlockYSize || nXCheck < nBlockXSize)
    7837             :         {
    7838           4 :             for (int iY = 0; iY < nYCheck; ++iY)
    7839             :             {
    7840           6 :                 for (int iX = 0; iX < nXCheck; ++iX)
    7841             :                 {
    7842           4 :                     const GPtrDiff_t iOffset =
    7843           4 :                         iX + static_cast<GPtrDiff_t>(iY) * nBlockXSize;
    7844           4 :                     if (pabyMaskData && pabyMaskData[iOffset] == 0)
    7845           2 :                         continue;
    7846           2 :                     bool bValid = true;
    7847             :                     double dfValue =
    7848           2 :                         GetPixelValue(eDataType, bSignedByte, pData, iOffset,
    7849             :                                       sNoDataValues, bValid);
    7850           2 :                     if (!bValid)
    7851           0 :                         continue;
    7852           2 :                     if (dfValue < dfMin)
    7853             :                     {
    7854           2 :                         dfMin = dfValue;
    7855           2 :                         nMinX = iXBlock * nBlockXSize + iX;
    7856           2 :                         nMinY = iYBlock * nBlockYSize + iY;
    7857             :                     }
    7858           2 :                     if (dfValue > dfMax)
    7859             :                     {
    7860           1 :                         dfMax = dfValue;
    7861           1 :                         nMaxX = iXBlock * nBlockXSize + iX;
    7862           1 :                         nMaxY = iYBlock * nBlockYSize + iY;
    7863             :                     }
    7864             :                 }
    7865           2 :             }
    7866             :         }
    7867             :         else
    7868             :         {
    7869           9 :             size_t pos_min = 0;
    7870           9 :             size_t pos_max = 0;
    7871           9 :             const auto eEffectiveDT = bSignedByte ? GDT_Int8 : eDataType;
    7872           9 :             if (bNeedsMin && bNeedsMax)
    7873             :             {
    7874          10 :                 std::tie(pos_min, pos_max) = gdal::minmax_element(
    7875           5 :                     pData, static_cast<size_t>(nBlockXSize) * nBlockYSize,
    7876           5 :                     eEffectiveDT, sNoDataValues.bGotNoDataValue,
    7877          10 :                     sNoDataValues.dfNoDataValue);
    7878             :             }
    7879           4 :             else if (bNeedsMin)
    7880             :             {
    7881           1 :                 pos_min = gdal::min_element(
    7882           1 :                     pData, static_cast<size_t>(nBlockXSize) * nBlockYSize,
    7883           1 :                     eEffectiveDT, sNoDataValues.bGotNoDataValue,
    7884             :                     sNoDataValues.dfNoDataValue);
    7885             :             }
    7886           3 :             else if (bNeedsMax)
    7887             :             {
    7888           2 :                 pos_max = gdal::max_element(
    7889           2 :                     pData, static_cast<size_t>(nBlockXSize) * nBlockYSize,
    7890           2 :                     eEffectiveDT, sNoDataValues.bGotNoDataValue,
    7891             :                     sNoDataValues.dfNoDataValue);
    7892             :             }
    7893             : 
    7894           9 :             if (bNeedsMin)
    7895             :             {
    7896           6 :                 const int nMinXBlock = static_cast<int>(pos_min % nBlockXSize);
    7897           6 :                 const int nMinYBlock = static_cast<int>(pos_min / nBlockXSize);
    7898           6 :                 bool bValid = true;
    7899             :                 const double dfMinValueBlock =
    7900           6 :                     GetPixelValue(eDataType, bSignedByte, pData, pos_min,
    7901             :                                   sNoDataValues, bValid);
    7902           6 :                 if (bValid && dfMinValueBlock < dfMin)
    7903             :                 {
    7904           5 :                     dfMin = dfMinValueBlock;
    7905           5 :                     nMinX = iXBlock * nBlockXSize + nMinXBlock;
    7906           5 :                     nMinY = iYBlock * nBlockYSize + nMinYBlock;
    7907             :                 }
    7908             :             }
    7909             : 
    7910           9 :             if (bNeedsMax)
    7911             :             {
    7912           7 :                 const int nMaxXBlock = static_cast<int>(pos_max % nBlockXSize);
    7913           7 :                 const int nMaxYBlock = static_cast<int>(pos_max / nBlockXSize);
    7914           7 :                 bool bValid = true;
    7915             :                 const double dfMaxValueBlock =
    7916           7 :                     GetPixelValue(eDataType, bSignedByte, pData, pos_max,
    7917             :                                   sNoDataValues, bValid);
    7918           7 :                 if (bValid && dfMaxValueBlock > dfMax)
    7919             :                 {
    7920           5 :                     dfMax = dfMaxValueBlock;
    7921           5 :                     nMaxX = iXBlock * nBlockXSize + nMaxXBlock;
    7922           5 :                     nMaxY = iYBlock * nBlockYSize + nMaxYBlock;
    7923             :                 }
    7924             :             }
    7925             :         }
    7926             : 
    7927          11 :         poBlock->DropLock();
    7928             : 
    7929          11 :         if (eDataType == GDT_Byte)
    7930             :         {
    7931          10 :             if (bNeedsMin && dfMin == 0)
    7932             :             {
    7933           1 :                 bNeedsMin = false;
    7934             :             }
    7935          10 :             if (bNeedsMax && dfMax == 255)
    7936             :             {
    7937           4 :                 bNeedsMax = false;
    7938             :             }
    7939          10 :             if (!bNeedsMin && !bNeedsMax)
    7940             :             {
    7941           3 :                 break;
    7942             :             }
    7943             :         }
    7944             :     }
    7945             : 
    7946           8 :     CPLFree(pabyMaskData);
    7947             : 
    7948           8 :     if (pdfMin)
    7949           5 :         *pdfMin = dfMin;
    7950           8 :     if (pdfMax)
    7951           5 :         *pdfMax = dfMax;
    7952           8 :     if (pnMinX)
    7953           6 :         *pnMinX = nMinX;
    7954           8 :     if (pnMinY)
    7955           6 :         *pnMinY = nMinY;
    7956           8 :     if (pnMaxX)
    7957           6 :         *pnMaxX = nMaxX;
    7958           8 :     if (pnMaxY)
    7959           6 :         *pnMaxY = nMaxY;
    7960           8 :     return ((bNeedsMin && nMinX < 0) || (bNeedsMax && nMaxX < 0)) ? CE_Warning
    7961           8 :                                                                   : CE_None;
    7962             : }
    7963             : 
    7964             : /************************************************************************/
    7965             : /*                    GDALComputeRasterMinMaxLocation()                 */
    7966             : /************************************************************************/
    7967             : 
    7968             : /**
    7969             :  * \brief Compute the min/max values for a band, and their location.
    7970             :  *
    7971             :  * @see GDALRasterBand::ComputeRasterMinMax()
    7972             :  * @since GDAL 3.11
    7973             :  */
    7974             : 
    7975           6 : CPLErr GDALComputeRasterMinMaxLocation(GDALRasterBandH hBand, double *pdfMin,
    7976             :                                        double *pdfMax, int *pnMinX, int *pnMinY,
    7977             :                                        int *pnMaxX, int *pnMaxY)
    7978             : 
    7979             : {
    7980           6 :     VALIDATE_POINTER1(hBand, "GDALComputeRasterMinMaxLocation", CE_Failure);
    7981             : 
    7982           6 :     GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
    7983           6 :     return poBand->ComputeRasterMinMaxLocation(pdfMin, pdfMax, pnMinX, pnMinY,
    7984           6 :                                                pnMaxX, pnMaxY);
    7985             : }
    7986             : 
    7987             : /************************************************************************/
    7988             : /*                        SetDefaultHistogram()                         */
    7989             : /************************************************************************/
    7990             : 
    7991             : /* FIXME : add proper documentation */
    7992             : /**
    7993             :  * \brief Set default histogram.
    7994             :  *
    7995             :  * This method is the same as the C function GDALSetDefaultHistogram() and
    7996             :  * GDALSetDefaultHistogramEx()
    7997             :  */
    7998           0 : CPLErr GDALRasterBand::SetDefaultHistogram(double /* dfMin */,
    7999             :                                            double /* dfMax */,
    8000             :                                            int /* nBuckets */,
    8001             :                                            GUIntBig * /* panHistogram */)
    8002             : 
    8003             : {
    8004           0 :     if (!(GetMOFlags() & GMO_IGNORE_UNIMPLEMENTED))
    8005           0 :         ReportError(CE_Failure, CPLE_NotSupported,
    8006             :                     "SetDefaultHistogram() not implemented for this format.");
    8007             : 
    8008           0 :     return CE_Failure;
    8009             : }
    8010             : 
    8011             : /************************************************************************/
    8012             : /*                      GDALSetDefaultHistogram()                       */
    8013             : /************************************************************************/
    8014             : 
    8015             : /**
    8016             :  * \brief Set default histogram.
    8017             :  *
    8018             :  * Use GDALSetRasterHistogramEx() instead to be able to set counts exceeding
    8019             :  * 2 billion.
    8020             :  *
    8021             :  * @see GDALRasterBand::SetDefaultHistogram()
    8022             :  * @see GDALSetRasterHistogramEx()
    8023             :  */
    8024             : 
    8025           0 : CPLErr CPL_STDCALL GDALSetDefaultHistogram(GDALRasterBandH hBand, double dfMin,
    8026             :                                            double dfMax, int nBuckets,
    8027             :                                            int *panHistogram)
    8028             : 
    8029             : {
    8030           0 :     VALIDATE_POINTER1(hBand, "GDALSetDefaultHistogram", CE_Failure);
    8031             : 
    8032           0 :     GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
    8033             : 
    8034             :     GUIntBig *panHistogramTemp =
    8035           0 :         static_cast<GUIntBig *>(VSIMalloc2(sizeof(GUIntBig), nBuckets));
    8036           0 :     if (panHistogramTemp == nullptr)
    8037             :     {
    8038           0 :         poBand->ReportError(CE_Failure, CPLE_OutOfMemory,
    8039             :                             "Out of memory in GDALSetDefaultHistogram().");
    8040           0 :         return CE_Failure;
    8041             :     }
    8042             : 
    8043           0 :     for (int i = 0; i < nBuckets; ++i)
    8044             :     {
    8045           0 :         panHistogramTemp[i] = static_cast<GUIntBig>(panHistogram[i]);
    8046             :     }
    8047             : 
    8048             :     const CPLErr eErr =
    8049           0 :         poBand->SetDefaultHistogram(dfMin, dfMax, nBuckets, panHistogramTemp);
    8050             : 
    8051           0 :     CPLFree(panHistogramTemp);
    8052             : 
    8053           0 :     return eErr;
    8054             : }
    8055             : 
    8056             : /************************************************************************/
    8057             : /*                     GDALSetDefaultHistogramEx()                      */
    8058             : /************************************************************************/
    8059             : 
    8060             : /**
    8061             :  * \brief Set default histogram.
    8062             :  *
    8063             :  * @see GDALRasterBand::SetDefaultHistogram()
    8064             :  *
    8065             :  * @since GDAL 2.0
    8066             :  */
    8067             : 
    8068           5 : CPLErr CPL_STDCALL GDALSetDefaultHistogramEx(GDALRasterBandH hBand,
    8069             :                                              double dfMin, double dfMax,
    8070             :                                              int nBuckets,
    8071             :                                              GUIntBig *panHistogram)
    8072             : 
    8073             : {
    8074           5 :     VALIDATE_POINTER1(hBand, "GDALSetDefaultHistogramEx", CE_Failure);
    8075             : 
    8076           5 :     GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
    8077           5 :     return poBand->SetDefaultHistogram(dfMin, dfMax, nBuckets, panHistogram);
    8078             : }
    8079             : 
    8080             : /************************************************************************/
    8081             : /*                           GetDefaultRAT()                            */
    8082             : /************************************************************************/
    8083             : 
    8084             : /**
    8085             :  * \brief Fetch default Raster Attribute Table.
    8086             :  *
    8087             :  * A RAT will be returned if there is a default one associated with the
    8088             :  * band, otherwise NULL is returned.  The returned RAT is owned by the
    8089             :  * band and should not be deleted by the application.
    8090             :  *
    8091             :  * This method is the same as the C function GDALGetDefaultRAT().
    8092             :  *
    8093             :  * @return NULL, or a pointer to an internal RAT owned by the band.
    8094             :  */
    8095             : 
    8096         173 : GDALRasterAttributeTable *GDALRasterBand::GetDefaultRAT()
    8097             : 
    8098             : {
    8099         173 :     return nullptr;
    8100             : }
    8101             : 
    8102             : /************************************************************************/
    8103             : /*                         GDALGetDefaultRAT()                          */
    8104             : /************************************************************************/
    8105             : 
    8106             : /**
    8107             :  * \brief Fetch default Raster Attribute Table.
    8108             :  *
    8109             :  * @see GDALRasterBand::GetDefaultRAT()
    8110             :  */
    8111             : 
    8112        1058 : GDALRasterAttributeTableH CPL_STDCALL GDALGetDefaultRAT(GDALRasterBandH hBand)
    8113             : 
    8114             : {
    8115        1058 :     VALIDATE_POINTER1(hBand, "GDALGetDefaultRAT", nullptr);
    8116             : 
    8117        1058 :     GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
    8118        1058 :     return GDALRasterAttributeTable::ToHandle(poBand->GetDefaultRAT());
    8119             : }
    8120             : 
    8121             : /************************************************************************/
    8122             : /*                           SetDefaultRAT()                            */
    8123             : /************************************************************************/
    8124             : 
    8125             : /**
    8126             :  * \fn GDALRasterBand::SetDefaultRAT(const GDALRasterAttributeTable*)
    8127             :  * \brief Set default Raster Attribute Table.
    8128             :  *
    8129             :  * Associates a default RAT with the band.  If not implemented for the
    8130             :  * format a CPLE_NotSupported error will be issued.  If successful a copy
    8131             :  * of the RAT is made, the original remains owned by the caller.
    8132             :  *
    8133             :  * This method is the same as the C function GDALSetDefaultRAT().
    8134             :  *
    8135             :  * @param poRAT the RAT to assign to the band.
    8136             :  *
    8137             :  * @return CE_None on success or CE_Failure if unsupported or otherwise
    8138             :  * failing.
    8139             :  */
    8140             : 
    8141             : /**/
    8142             : /**/
    8143             : 
    8144             : CPLErr
    8145           0 : GDALRasterBand::SetDefaultRAT(const GDALRasterAttributeTable * /* poRAT */)
    8146             : {
    8147           0 :     if (!(GetMOFlags() & GMO_IGNORE_UNIMPLEMENTED))
    8148             :     {
    8149           0 :         CPLPushErrorHandler(CPLQuietErrorHandler);
    8150           0 :         ReportError(CE_Failure, CPLE_NotSupported,
    8151             :                     "SetDefaultRAT() not implemented for this format.");
    8152           0 :         CPLPopErrorHandler();
    8153             :     }
    8154           0 :     return CE_Failure;
    8155             : }
    8156             : 
    8157             : /************************************************************************/
    8158             : /*                         GDALSetDefaultRAT()                          */
    8159             : /************************************************************************/
    8160             : 
    8161             : /**
    8162             :  * \brief Set default Raster Attribute Table.
    8163             :  *
    8164             :  * @see GDALRasterBand::GDALSetDefaultRAT()
    8165             :  */
    8166             : 
    8167          18 : CPLErr CPL_STDCALL GDALSetDefaultRAT(GDALRasterBandH hBand,
    8168             :                                      GDALRasterAttributeTableH hRAT)
    8169             : 
    8170             : {
    8171          18 :     VALIDATE_POINTER1(hBand, "GDALSetDefaultRAT", CE_Failure);
    8172             : 
    8173          18 :     GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
    8174             : 
    8175          18 :     return poBand->SetDefaultRAT(GDALRasterAttributeTable::FromHandle(hRAT));
    8176             : }
    8177             : 
    8178             : /************************************************************************/
    8179             : /*                            GetMaskBand()                             */
    8180             : /************************************************************************/
    8181             : 
    8182             : /**
    8183             :  * \brief Return the mask band associated with the band.
    8184             :  *
    8185             :  * The GDALRasterBand class includes a default implementation of GetMaskBand()
    8186             :  * that returns one of four default implementations :
    8187             :  * <ul>
    8188             :  * <li>If a corresponding .msk file exists it will be used for the mask band.
    8189             :  * </li>
    8190             :  * <li>If the dataset has a NODATA_VALUES metadata item, an instance of the new
    8191             :  * GDALNoDataValuesMaskBand class will be returned. GetMaskFlags() will return
    8192             :  * GMF_NODATA | GMF_PER_DATASET.
    8193             :  * </li>
    8194             :  * <li>If the band has a nodata value set, an instance of the new
    8195             :  * GDALNodataMaskRasterBand class will be returned. GetMaskFlags() will return
    8196             :  * GMF_NODATA.
    8197             :  * </li>
    8198             :  * <li>If there is no nodata value, but the dataset has an alpha band that seems
    8199             :  * to apply to this band (specific rules yet to be determined) and that is of
    8200             :  * type GDT_Byte then that alpha band will be returned, and the flags
    8201             :  * GMF_PER_DATASET and GMF_ALPHA will be returned in the flags.
    8202             :  * </li>
    8203             :  * <li>If neither of the above apply, an instance of the new
    8204             :  * GDALAllValidRasterBand class will be returned that has 255 values for all
    8205             :  * pixels. The null flags will return GMF_ALL_VALID.
    8206             :  * </li>
    8207             :  * </ul>
    8208             :  *
    8209             :  * Note that the GetMaskBand() should always return a GDALRasterBand mask, even
    8210             :  * if it is only an all 255 mask with the flags indicating GMF_ALL_VALID.
    8211             :  *
    8212             :  * For an external .msk file to be recognized by GDAL, it must be a valid GDAL
    8213             :  * dataset, with the same name as the main dataset and suffixed with .msk,
    8214             :  * with either one band (in the GMF_PER_DATASET case), or as many bands as the
    8215             :  * main dataset.
    8216             :  * It must have INTERNAL_MASK_FLAGS_xx metadata items set at the dataset
    8217             :  * level, where xx matches the band number of a band of the main dataset. The
    8218             :  * value of those items is a combination of the flags GMF_ALL_VALID,
    8219             :  * GMF_PER_DATASET, GMF_ALPHA and GMF_NODATA. If a metadata item is missing for
    8220             :  * a band, then the other rules explained above will be used to generate a
    8221             :  * on-the-fly mask band.
    8222             :  * \see CreateMaskBand() for the characteristics of .msk files created by GDAL.
    8223             :  *
    8224             :  * This method is the same as the C function GDALGetMaskBand().
    8225             :  *
    8226             :  * @return a valid mask band.
    8227             :  *
    8228             :  * @since GDAL 1.5.0
    8229             :  *
    8230             :  * @see https://gdal.org/development/rfc/rfc15_nodatabitmask.html
    8231             :  *
    8232             :  */
    8233      801472 : GDALRasterBand *GDALRasterBand::GetMaskBand()
    8234             : 
    8235             : {
    8236      386636 :     const auto HasNoData = [this]()
    8237             :     {
    8238      128553 :         int bHaveNoDataRaw = FALSE;
    8239      128553 :         bool bHaveNoData = false;
    8240      128553 :         if (eDataType == GDT_Int64)
    8241             :         {
    8242          64 :             CPL_IGNORE_RET_VAL(GetNoDataValueAsInt64(&bHaveNoDataRaw));
    8243          64 :             bHaveNoData = CPL_TO_BOOL(bHaveNoDataRaw);
    8244             :         }
    8245      128489 :         else if (eDataType == GDT_UInt64)
    8246             :         {
    8247          46 :             CPL_IGNORE_RET_VAL(GetNoDataValueAsUInt64(&bHaveNoDataRaw));
    8248          46 :             bHaveNoData = CPL_TO_BOOL(bHaveNoDataRaw);
    8249             :         }
    8250             :         else
    8251             :         {
    8252      128443 :             const double dfNoDataValue = GetNoDataValue(&bHaveNoDataRaw);
    8253      128427 :             if (bHaveNoDataRaw &&
    8254      128427 :                 GDALNoDataMaskBand::IsNoDataInRange(dfNoDataValue, eDataType))
    8255             :             {
    8256        1000 :                 bHaveNoData = true;
    8257             :             }
    8258             :         }
    8259      128531 :         return bHaveNoData;
    8260      801472 :     };
    8261             : 
    8262      801472 :     if (poMask != nullptr)
    8263             :     {
    8264      703826 :         if (poMask.IsOwned())
    8265             :         {
    8266      332795 :             if (dynamic_cast<GDALAllValidMaskBand *>(poMask.get()) != nullptr)
    8267             :             {
    8268       33368 :                 if (HasNoData())
    8269             :                 {
    8270           9 :                     InvalidateMaskBand();
    8271             :                 }
    8272             :             }
    8273      299832 :             else if (auto poNoDataMaskBand =
    8274      299656 :                          dynamic_cast<GDALNoDataMaskBand *>(poMask.get()))
    8275             :             {
    8276         280 :                 int bHaveNoDataRaw = FALSE;
    8277         280 :                 bool bIsSame = false;
    8278         280 :                 if (eDataType == GDT_Int64)
    8279           9 :                     bIsSame = poNoDataMaskBand->m_nNoDataValueInt64 ==
    8280          11 :                                   GetNoDataValueAsInt64(&bHaveNoDataRaw) &&
    8281           2 :                               bHaveNoDataRaw;
    8282         271 :                 else if (eDataType == GDT_UInt64)
    8283           9 :                     bIsSame = poNoDataMaskBand->m_nNoDataValueUInt64 ==
    8284          11 :                                   GetNoDataValueAsUInt64(&bHaveNoDataRaw) &&
    8285           2 :                               bHaveNoDataRaw;
    8286             :                 else
    8287             :                 {
    8288             :                     const double dfNoDataValue =
    8289         262 :                         GetNoDataValue(&bHaveNoDataRaw);
    8290         261 :                     if (bHaveNoDataRaw)
    8291             :                     {
    8292         259 :                         bIsSame =
    8293         258 :                             std::isnan(dfNoDataValue)
    8294         258 :                                 ? std::isnan(poNoDataMaskBand->m_dfNoDataValue)
    8295         233 :                                 : poNoDataMaskBand->m_dfNoDataValue ==
    8296             :                                       dfNoDataValue;
    8297             :                     }
    8298             :                 }
    8299         280 :                 if (!bIsSame)
    8300          23 :                     InvalidateMaskBand();
    8301             :             }
    8302             :         }
    8303             : 
    8304      706918 :         if (poMask)
    8305      708605 :             return poMask.get();
    8306             :     }
    8307             : 
    8308             :     /* -------------------------------------------------------------------- */
    8309             :     /*      Check for a mask in a .msk file.                                */
    8310             :     /* -------------------------------------------------------------------- */
    8311       95288 :     if (poDS != nullptr && poDS->oOvManager.HaveMaskFile())
    8312             :     {
    8313          46 :         poMask.reset(poDS->oOvManager.GetMaskBand(nBand), false);
    8314          46 :         if (poMask != nullptr)
    8315             :         {
    8316          44 :             nMaskFlags = poDS->oOvManager.GetMaskFlags(nBand);
    8317          44 :             return poMask.get();
    8318             :         }
    8319             :     }
    8320             : 
    8321             :     /* -------------------------------------------------------------------- */
    8322             :     /*      Check for NODATA_VALUES metadata.                               */
    8323             :     /* -------------------------------------------------------------------- */
    8324       95243 :     if (poDS != nullptr)
    8325             :     {
    8326             :         const char *pszGDALNoDataValues =
    8327       95229 :             poDS->GetMetadataItem("NODATA_VALUES");
    8328       95228 :         if (pszGDALNoDataValues != nullptr)
    8329             :         {
    8330          66 :             char **papszGDALNoDataValues = CSLTokenizeStringComplex(
    8331             :                 pszGDALNoDataValues, " ", FALSE, FALSE);
    8332             : 
    8333             :             // Make sure we have as many values as bands.
    8334         132 :             if (CSLCount(papszGDALNoDataValues) == poDS->GetRasterCount() &&
    8335          66 :                 poDS->GetRasterCount() != 0)
    8336             :             {
    8337             :                 // Make sure that all bands have the same data type
    8338             :                 // This is clearly not a fundamental condition, just a
    8339             :                 // condition to make implementation easier.
    8340          66 :                 GDALDataType eDT = GDT_Unknown;
    8341          66 :                 int i = 0;  // Used after for.
    8342         263 :                 for (; i < poDS->GetRasterCount(); ++i)
    8343             :                 {
    8344         197 :                     if (i == 0)
    8345          66 :                         eDT = poDS->GetRasterBand(1)->GetRasterDataType();
    8346         131 :                     else if (eDT !=
    8347         131 :                              poDS->GetRasterBand(i + 1)->GetRasterDataType())
    8348             :                     {
    8349           0 :                         break;
    8350             :                     }
    8351             :                 }
    8352          66 :                 if (i == poDS->GetRasterCount())
    8353             :                 {
    8354          66 :                     nMaskFlags = GMF_NODATA | GMF_PER_DATASET;
    8355             :                     try
    8356             :                     {
    8357          66 :                         poMask.reset(new GDALNoDataValuesMaskBand(poDS), true);
    8358             :                     }
    8359           0 :                     catch (const std::bad_alloc &)
    8360             :                     {
    8361           0 :                         CPLError(CE_Failure, CPLE_OutOfMemory, "Out of memory");
    8362           0 :                         poMask.reset();
    8363             :                     }
    8364          66 :                     CSLDestroy(papszGDALNoDataValues);
    8365          66 :                     return poMask.get();
    8366             :                 }
    8367             :                 else
    8368             :                 {
    8369           0 :                     ReportError(CE_Warning, CPLE_AppDefined,
    8370             :                                 "All bands should have the same type in "
    8371             :                                 "order the NODATA_VALUES metadata item "
    8372             :                                 "to be used as a mask.");
    8373             :                 }
    8374             :             }
    8375             :             else
    8376             :             {
    8377           0 :                 ReportError(
    8378             :                     CE_Warning, CPLE_AppDefined,
    8379             :                     "NODATA_VALUES metadata item doesn't have the same number "
    8380             :                     "of values as the number of bands.  "
    8381             :                     "Ignoring it for mask.");
    8382             :             }
    8383             : 
    8384           0 :             CSLDestroy(papszGDALNoDataValues);
    8385             :         }
    8386             :     }
    8387             : 
    8388             :     /* -------------------------------------------------------------------- */
    8389             :     /*      Check for nodata case.                                          */
    8390             :     /* -------------------------------------------------------------------- */
    8391       95176 :     if (HasNoData())
    8392             :     {
    8393        1022 :         nMaskFlags = GMF_NODATA;
    8394             :         try
    8395             :         {
    8396        1022 :             poMask.reset(new GDALNoDataMaskBand(this), true);
    8397             :         }
    8398           0 :         catch (const std::bad_alloc &)
    8399             :         {
    8400           0 :             CPLError(CE_Failure, CPLE_OutOfMemory, "Out of memory");
    8401           0 :             poMask.reset();
    8402             :         }
    8403        1022 :         return poMask.get();
    8404             :     }
    8405             : 
    8406             :     /* -------------------------------------------------------------------- */
    8407             :     /*      Check for alpha case.                                           */
    8408             :     /* -------------------------------------------------------------------- */
    8409       94139 :     if (poDS != nullptr && poDS->GetRasterCount() == 2 &&
    8410      188886 :         this == poDS->GetRasterBand(1) &&
    8411         590 :         poDS->GetRasterBand(2)->GetColorInterpretation() == GCI_AlphaBand)
    8412             :     {
    8413         233 :         if (poDS->GetRasterBand(2)->GetRasterDataType() == GDT_Byte)
    8414             :         {
    8415         189 :             nMaskFlags = GMF_ALPHA | GMF_PER_DATASET;
    8416         189 :             poMask.reset(poDS->GetRasterBand(2), false);
    8417         189 :             return poMask.get();
    8418             :         }
    8419          44 :         else if (poDS->GetRasterBand(2)->GetRasterDataType() == GDT_UInt16)
    8420             :         {
    8421          23 :             nMaskFlags = GMF_ALPHA | GMF_PER_DATASET;
    8422             :             try
    8423             :             {
    8424          23 :                 poMask.reset(new GDALRescaledAlphaBand(poDS->GetRasterBand(2)),
    8425             :                              true);
    8426             :             }
    8427           0 :             catch (const std::bad_alloc &)
    8428             :             {
    8429           0 :                 CPLError(CE_Failure, CPLE_OutOfMemory, "Out of memory");
    8430           0 :                 poMask.reset();
    8431             :             }
    8432          23 :             return poMask.get();
    8433             :         }
    8434             :     }
    8435             : 
    8436       93929 :     if (poDS != nullptr && poDS->GetRasterCount() == 4 &&
    8437        3110 :         (this == poDS->GetRasterBand(1) || this == poDS->GetRasterBand(2) ||
    8438      188617 :          this == poDS->GetRasterBand(3)) &&
    8439        2414 :         poDS->GetRasterBand(4)->GetColorInterpretation() == GCI_AlphaBand)
    8440             :     {
    8441        1541 :         if (poDS->GetRasterBand(4)->GetRasterDataType() == GDT_Byte)
    8442             :         {
    8443        1494 :             nMaskFlags = GMF_ALPHA | GMF_PER_DATASET;
    8444        1494 :             poMask.reset(poDS->GetRasterBand(4), false);
    8445        1494 :             return poMask.get();
    8446             :         }
    8447          47 :         else if (poDS->GetRasterBand(4)->GetRasterDataType() == GDT_UInt16)
    8448             :         {
    8449          35 :             nMaskFlags = GMF_ALPHA | GMF_PER_DATASET;
    8450             :             try
    8451             :             {
    8452          35 :                 poMask.reset(new GDALRescaledAlphaBand(poDS->GetRasterBand(4)),
    8453             :                              true);
    8454             :             }
    8455           0 :             catch (const std::bad_alloc &)
    8456             :             {
    8457           0 :                 CPLError(CE_Failure, CPLE_OutOfMemory, "Out of memory");
    8458           0 :                 poMask.reset();
    8459             :             }
    8460          35 :             return poMask.get();
    8461             :         }
    8462             :     }
    8463             : 
    8464             :     /* -------------------------------------------------------------------- */
    8465             :     /*      Fallback to all valid case.                                     */
    8466             :     /* -------------------------------------------------------------------- */
    8467       92415 :     nMaskFlags = GMF_ALL_VALID;
    8468             :     try
    8469             :     {
    8470       92415 :         poMask.reset(new GDALAllValidMaskBand(this), true);
    8471             :     }
    8472           0 :     catch (const std::bad_alloc &)
    8473             :     {
    8474           0 :         CPLError(CE_Failure, CPLE_OutOfMemory, "Out of memory");
    8475           0 :         poMask.reset();
    8476             :     }
    8477             : 
    8478       92415 :     return poMask.get();
    8479             : }
    8480             : 
    8481             : /************************************************************************/
    8482             : /*                          GDALGetMaskBand()                           */
    8483             : /************************************************************************/
    8484             : 
    8485             : /**
    8486             :  * \brief Return the mask band associated with the band.
    8487             :  *
    8488             :  * @see GDALRasterBand::GetMaskBand()
    8489             :  */
    8490             : 
    8491       10990 : GDALRasterBandH CPL_STDCALL GDALGetMaskBand(GDALRasterBandH hBand)
    8492             : 
    8493             : {
    8494       10990 :     VALIDATE_POINTER1(hBand, "GDALGetMaskBand", nullptr);
    8495             : 
    8496       10990 :     GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
    8497       10990 :     return poBand->GetMaskBand();
    8498             : }
    8499             : 
    8500             : /************************************************************************/
    8501             : /*                            GetMaskFlags()                            */
    8502             : /************************************************************************/
    8503             : 
    8504             : /**
    8505             :  * \brief Return the status flags of the mask band associated with the band.
    8506             :  *
    8507             :  * The GetMaskFlags() method returns an bitwise OR-ed set of status flags with
    8508             :  * the following available definitions that may be extended in the future:
    8509             :  * <ul>
    8510             :  * <li>GMF_ALL_VALID(0x01): There are no invalid pixels, all mask values will be
    8511             :  * 255. When used this will normally be the only flag set.
    8512             :  * </li>
    8513             :  * <li>GMF_PER_DATASET(0x02): The mask band is shared between all bands on the
    8514             :  * dataset.
    8515             :  * </li>
    8516             :  * <li>GMF_ALPHA(0x04): The mask band is actually an alpha band
    8517             :  * and may have values other than 0 and 255.
    8518             :  * </li>
    8519             :  * <li>GMF_NODATA(0x08): Indicates the mask is actually being generated from
    8520             :  * nodata values. (mutually exclusive of GMF_ALPHA)
    8521             :  * </li>
    8522             :  * </ul>
    8523             :  *
    8524             :  * The GDALRasterBand class includes a default implementation of GetMaskBand()
    8525             :  * that returns one of four default implementations:
    8526             :  * <ul>
    8527             :  * <li>If a corresponding .msk file exists it will be used for the mask band.
    8528             :  * </li>
    8529             :  * <li>If the dataset has a NODATA_VALUES metadata item, an instance of the new
    8530             :  * GDALNoDataValuesMaskBand class will be returned. GetMaskFlags() will return
    8531             :  * GMF_NODATA | GMF_PER_DATASET.
    8532             :  * </li>
    8533             :  * <li>If the band has a nodata value set, an instance of the new
    8534             :  * GDALNodataMaskRasterBand class will be returned. GetMaskFlags() will return
    8535             :  * GMF_NODATA.
    8536             :  * </li>
    8537             :  * <li>If there is no nodata value, but the dataset has an alpha band that
    8538             :  * seems to apply to this band (specific rules yet to be determined) and that is
    8539             :  * of type GDT_Byte then that alpha band will be returned, and the flags
    8540             :  * GMF_PER_DATASET and GMF_ALPHA will be returned in the flags.
    8541             :  * </li>
    8542             :  * <li>If neither of the above apply, an instance of the new
    8543             :  * GDALAllValidRasterBand class will be returned that has 255 values for all
    8544             :  * pixels. The null flags will return GMF_ALL_VALID.
    8545             :  * </li>
    8546             :  * </ul>
    8547             :  *
    8548             :  * For an external .msk file to be recognized by GDAL, it must be a valid GDAL
    8549             :  * dataset, with the same name as the main dataset and suffixed with .msk,
    8550             :  * with either one band (in the GMF_PER_DATASET case), or as many bands as the
    8551             :  * main dataset.
    8552             :  * It must have INTERNAL_MASK_FLAGS_xx metadata items set at the dataset
    8553             :  * level, where xx matches the band number of a band of the main dataset. The
    8554             :  * value of those items is a combination of the flags GMF_ALL_VALID,
    8555             :  * GMF_PER_DATASET, GMF_ALPHA and GMF_NODATA. If a metadata item is missing for
    8556             :  * a band, then the other rules explained above will be used to generate a
    8557             :  * on-the-fly mask band.
    8558             :  * \see CreateMaskBand() for the characteristics of .msk files created by GDAL.
    8559             :  *
    8560             :  * This method is the same as the C function GDALGetMaskFlags().
    8561             :  *
    8562             :  * @since GDAL 1.5.0
    8563             :  *
    8564             :  * @return a valid mask band.
    8565             :  *
    8566             :  * @see https://gdal.org/development/rfc/rfc15_nodatabitmask.html
    8567             :  *
    8568             :  */
    8569      150604 : int GDALRasterBand::GetMaskFlags()
    8570             : 
    8571             : {
    8572             :     // If we don't have a band yet, force this now so that the masks value
    8573             :     // will be initialized.
    8574             : 
    8575      150604 :     if (poMask == nullptr)
    8576       93936 :         GetMaskBand();
    8577             : 
    8578      150598 :     return nMaskFlags;
    8579             : }
    8580             : 
    8581             : /************************************************************************/
    8582             : /*                          GDALGetMaskFlags()                          */
    8583             : /************************************************************************/
    8584             : 
    8585             : /**
    8586             :  * \brief Return the status flags of the mask band associated with the band.
    8587             :  *
    8588             :  * @see GDALRasterBand::GetMaskFlags()
    8589             :  */
    8590             : 
    8591        6651 : int CPL_STDCALL GDALGetMaskFlags(GDALRasterBandH hBand)
    8592             : 
    8593             : {
    8594        6651 :     VALIDATE_POINTER1(hBand, "GDALGetMaskFlags", GMF_ALL_VALID);
    8595             : 
    8596        6651 :     GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
    8597        6651 :     return poBand->GetMaskFlags();
    8598             : }
    8599             : 
    8600             : /************************************************************************/
    8601             : /*                         InvalidateMaskBand()                         */
    8602             : /************************************************************************/
    8603             : 
    8604             : //! @cond Doxygen_Suppress
    8605     1611580 : void GDALRasterBand::InvalidateMaskBand()
    8606             : {
    8607     1611580 :     poMask.reset();
    8608     1611580 :     nMaskFlags = 0;
    8609     1611580 : }
    8610             : 
    8611             : //! @endcond
    8612             : 
    8613             : /************************************************************************/
    8614             : /*                           CreateMaskBand()                           */
    8615             : /************************************************************************/
    8616             : 
    8617             : /**
    8618             :  * \brief Adds a mask band to the current band
    8619             :  *
    8620             :  * The default implementation of the CreateMaskBand() method is implemented
    8621             :  * based on similar rules to the .ovr handling implemented using the
    8622             :  * GDALDefaultOverviews object. A TIFF file with the extension .msk will
    8623             :  * be created with the same basename as the original file, and it will have
    8624             :  * as many bands as the original image (or just one for GMF_PER_DATASET).
    8625             :  * The mask images will be deflate compressed tiled images with the same
    8626             :  * block size as the original image if possible.
    8627             :  * It will have INTERNAL_MASK_FLAGS_xx metadata items set at the dataset
    8628             :  * level, where xx matches the band number of a band of the main dataset. The
    8629             :  * value of those items will be the one of the nFlagsIn parameter.
    8630             :  *
    8631             :  * Note that if you got a mask band with a previous call to GetMaskBand(),
    8632             :  * it might be invalidated by CreateMaskBand(). So you have to call
    8633             :  * GetMaskBand() again.
    8634             :  *
    8635             :  * This method is the same as the C function GDALCreateMaskBand().
    8636             :  *
    8637             :  * @since GDAL 1.5.0
    8638             :  *
    8639             :  * @param nFlagsIn 0 or combination of GMF_PER_DATASET / GMF_ALPHA.
    8640             :  *
    8641             :  * @return CE_None on success or CE_Failure on an error.
    8642             :  *
    8643             :  * @see https://gdal.org/development/rfc/rfc15_nodatabitmask.html
    8644             :  * @see GDALDataset::CreateMaskBand()
    8645             :  *
    8646             :  */
    8647             : 
    8648           9 : CPLErr GDALRasterBand::CreateMaskBand(int nFlagsIn)
    8649             : 
    8650             : {
    8651           9 :     if (poDS != nullptr && poDS->oOvManager.IsInitialized())
    8652             :     {
    8653           9 :         const CPLErr eErr = poDS->oOvManager.CreateMaskBand(nFlagsIn, nBand);
    8654           9 :         if (eErr != CE_None)
    8655           1 :             return eErr;
    8656             : 
    8657           8 :         InvalidateMaskBand();
    8658             : 
    8659           8 :         return CE_None;
    8660             :     }
    8661             : 
    8662           0 :     ReportError(CE_Failure, CPLE_NotSupported,
    8663             :                 "CreateMaskBand() not supported for this band.");
    8664             : 
    8665           0 :     return CE_Failure;
    8666             : }
    8667             : 
    8668             : /************************************************************************/
    8669             : /*                         GDALCreateMaskBand()                         */
    8670             : /************************************************************************/
    8671             : 
    8672             : /**
    8673             :  * \brief Adds a mask band to the current band
    8674             :  *
    8675             :  * @see GDALRasterBand::CreateMaskBand()
    8676             :  */
    8677             : 
    8678          33 : CPLErr CPL_STDCALL GDALCreateMaskBand(GDALRasterBandH hBand, int nFlags)
    8679             : 
    8680             : {
    8681          33 :     VALIDATE_POINTER1(hBand, "GDALCreateMaskBand", CE_Failure);
    8682             : 
    8683          33 :     GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
    8684          33 :     return poBand->CreateMaskBand(nFlags);
    8685             : }
    8686             : 
    8687             : /************************************************************************/
    8688             : /*                            IsMaskBand()                              */
    8689             : /************************************************************************/
    8690             : 
    8691             : /**
    8692             :  * \brief Returns whether a band is a mask band.
    8693             :  *
    8694             :  * Mask band must be understood in the broad term: it can be a per-dataset
    8695             :  * mask band, an alpha band, or an implicit mask band.
    8696             :  * Typically the return of GetMaskBand()->IsMaskBand() should be true.
    8697             :  *
    8698             :  * This method is the same as the C function GDALIsMaskBand().
    8699             :  *
    8700             :  * @return true if the band is a mask band.
    8701             :  *
    8702             :  * @see GDALDataset::CreateMaskBand()
    8703             :  *
    8704             :  * @since GDAL 3.5.0
    8705             :  *
    8706             :  */
    8707             : 
    8708         439 : bool GDALRasterBand::IsMaskBand() const
    8709             : {
    8710             :     // The GeoTIFF driver, among others, override this method to
    8711             :     // also handle external .msk bands.
    8712         439 :     return const_cast<GDALRasterBand *>(this)->GetColorInterpretation() ==
    8713         439 :            GCI_AlphaBand;
    8714             : }
    8715             : 
    8716             : /************************************************************************/
    8717             : /*                            GDALIsMaskBand()                          */
    8718             : /************************************************************************/
    8719             : 
    8720             : /**
    8721             :  * \brief Returns whether a band is a mask band.
    8722             :  *
    8723             :  * Mask band must be understood in the broad term: it can be a per-dataset
    8724             :  * mask band, an alpha band, or an implicit mask band.
    8725             :  * Typically the return of GetMaskBand()->IsMaskBand() should be true.
    8726             :  *
    8727             :  * This function is the same as the C++ method GDALRasterBand::IsMaskBand()
    8728             :  *
    8729             :  * @return true if the band is a mask band.
    8730             :  *
    8731             :  * @see GDALRasterBand::IsMaskBand()
    8732             :  *
    8733             :  * @since GDAL 3.5.0
    8734             :  *
    8735             :  */
    8736             : 
    8737          37 : bool GDALIsMaskBand(GDALRasterBandH hBand)
    8738             : 
    8739             : {
    8740          37 :     VALIDATE_POINTER1(hBand, "GDALIsMaskBand", false);
    8741             : 
    8742          37 :     const GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
    8743          37 :     return poBand->IsMaskBand();
    8744             : }
    8745             : 
    8746             : /************************************************************************/
    8747             : /*                         GetMaskValueRange()                          */
    8748             : /************************************************************************/
    8749             : 
    8750             : /**
    8751             :  * \brief Returns the range of values that a mask band can take.
    8752             :  *
    8753             :  * @return the range of values that a mask band can take.
    8754             :  *
    8755             :  * @since GDAL 3.5.0
    8756             :  *
    8757             :  */
    8758             : 
    8759           0 : GDALMaskValueRange GDALRasterBand::GetMaskValueRange() const
    8760             : {
    8761           0 :     return GMVR_UNKNOWN;
    8762             : }
    8763             : 
    8764             : /************************************************************************/
    8765             : /*                    GetIndexColorTranslationTo()                      */
    8766             : /************************************************************************/
    8767             : 
    8768             : /**
    8769             :  * \brief Compute translation table for color tables.
    8770             :  *
    8771             :  * When the raster band has a palette index, it may be useful to compute
    8772             :  * the "translation" of this palette to the palette of another band.
    8773             :  * The translation tries to do exact matching first, and then approximate
    8774             :  * matching if no exact matching is possible.
    8775             :  * This method returns a table such that table[i] = j where i is an index
    8776             :  * of the 'this' rasterband and j the corresponding index for the reference
    8777             :  * rasterband.
    8778             :  *
    8779             :  * This method is thought as internal to GDAL and is used for drivers
    8780             :  * like RPFTOC.
    8781             :  *
    8782             :  * The implementation only supports 1-byte palette rasterbands.
    8783             :  *
    8784             :  * @param poReferenceBand the raster band
    8785             :  * @param pTranslationTable an already allocated translation table (at least 256
    8786             :  * bytes), or NULL to let the method allocate it
    8787             :  * @param pApproximateMatching a pointer to a flag that is set if the matching
    8788             :  *                              is approximate. May be NULL.
    8789             :  *
    8790             :  * @return a translation table if the two bands are palette index and that they
    8791             :  * do not match or NULL in other cases. The table must be freed with CPLFree if
    8792             :  * NULL was passed for pTranslationTable.
    8793             :  */
    8794             : 
    8795             : unsigned char *
    8796           4 : GDALRasterBand::GetIndexColorTranslationTo(GDALRasterBand *poReferenceBand,
    8797             :                                            unsigned char *pTranslationTable,
    8798             :                                            int *pApproximateMatching)
    8799             : {
    8800           4 :     if (poReferenceBand == nullptr)
    8801           0 :         return nullptr;
    8802             : 
    8803             :     // cppcheck-suppress knownConditionTrueFalse
    8804           4 :     if (poReferenceBand->GetColorInterpretation() == GCI_PaletteIndex &&
    8805             :         // cppcheck-suppress knownConditionTrueFalse
    8806           4 :         GetColorInterpretation() == GCI_PaletteIndex &&
    8807          12 :         poReferenceBand->GetRasterDataType() == GDT_Byte &&
    8808           4 :         GetRasterDataType() == GDT_Byte)
    8809             :     {
    8810           4 :         const GDALColorTable *srcColorTable = GetColorTable();
    8811           4 :         GDALColorTable *destColorTable = poReferenceBand->GetColorTable();
    8812           4 :         if (srcColorTable != nullptr && destColorTable != nullptr)
    8813             :         {
    8814           4 :             const int nEntries = srcColorTable->GetColorEntryCount();
    8815           4 :             const int nRefEntries = destColorTable->GetColorEntryCount();
    8816             : 
    8817           4 :             int bHasNoDataValueSrc = FALSE;
    8818           4 :             double dfNoDataValueSrc = GetNoDataValue(&bHasNoDataValueSrc);
    8819           4 :             if (!(bHasNoDataValueSrc && dfNoDataValueSrc >= 0 &&
    8820           4 :                   dfNoDataValueSrc <= 255 &&
    8821           4 :                   dfNoDataValueSrc == static_cast<int>(dfNoDataValueSrc)))
    8822           0 :                 bHasNoDataValueSrc = FALSE;
    8823           4 :             const int noDataValueSrc =
    8824           4 :                 bHasNoDataValueSrc ? static_cast<int>(dfNoDataValueSrc) : 0;
    8825             : 
    8826           4 :             int bHasNoDataValueRef = FALSE;
    8827             :             const double dfNoDataValueRef =
    8828           4 :                 poReferenceBand->GetNoDataValue(&bHasNoDataValueRef);
    8829           4 :             if (!(bHasNoDataValueRef && dfNoDataValueRef >= 0 &&
    8830           3 :                   dfNoDataValueRef <= 255 &&
    8831           3 :                   dfNoDataValueRef == static_cast<int>(dfNoDataValueRef)))
    8832           1 :                 bHasNoDataValueRef = FALSE;
    8833           4 :             const int noDataValueRef =
    8834           4 :                 bHasNoDataValueRef ? static_cast<int>(dfNoDataValueRef) : 0;
    8835             : 
    8836           4 :             bool samePalette = false;
    8837             : 
    8838           4 :             if (pApproximateMatching)
    8839           3 :                 *pApproximateMatching = FALSE;
    8840             : 
    8841           4 :             if (nEntries == nRefEntries &&
    8842           3 :                 bHasNoDataValueSrc == bHasNoDataValueRef &&
    8843           3 :                 (bHasNoDataValueSrc == FALSE ||
    8844             :                  noDataValueSrc == noDataValueRef))
    8845             :             {
    8846           3 :                 samePalette = true;
    8847         654 :                 for (int i = 0; i < nEntries; ++i)
    8848             :                 {
    8849         651 :                     if (noDataValueSrc == i)
    8850           3 :                         continue;
    8851             :                     const GDALColorEntry *entry =
    8852         648 :                         srcColorTable->GetColorEntry(i);
    8853             :                     const GDALColorEntry *entryRef =
    8854         648 :                         destColorTable->GetColorEntry(i);
    8855         648 :                     if (entry->c1 != entryRef->c1 ||
    8856         648 :                         entry->c2 != entryRef->c2 || entry->c3 != entryRef->c3)
    8857             :                     {
    8858           0 :                         samePalette = false;
    8859             :                     }
    8860             :                 }
    8861             :             }
    8862             : 
    8863           4 :             if (!samePalette)
    8864             :             {
    8865           1 :                 if (pTranslationTable == nullptr)
    8866             :                 {
    8867             :                     pTranslationTable = static_cast<unsigned char *>(
    8868           1 :                         VSI_CALLOC_VERBOSE(1, std::max(256, nEntries)));
    8869           1 :                     if (pTranslationTable == nullptr)
    8870           1 :                         return nullptr;
    8871             :                 }
    8872             : 
    8873             :                 // Trying to remap the product palette on the subdataset
    8874             :                 // palette.
    8875           5 :                 for (int i = 0; i < nEntries; ++i)
    8876             :                 {
    8877           4 :                     if (bHasNoDataValueSrc && bHasNoDataValueRef &&
    8878             :                         noDataValueSrc == i)
    8879           0 :                         continue;
    8880             :                     const GDALColorEntry *entry =
    8881           4 :                         srcColorTable->GetColorEntry(i);
    8882           4 :                     bool bMatchFound = false;
    8883          13 :                     for (int j = 0; j < nRefEntries; ++j)
    8884             :                     {
    8885          10 :                         if (bHasNoDataValueRef && noDataValueRef == j)
    8886           0 :                             continue;
    8887             :                         const GDALColorEntry *entryRef =
    8888          10 :                             destColorTable->GetColorEntry(j);
    8889          10 :                         if (entry->c1 == entryRef->c1 &&
    8890           2 :                             entry->c2 == entryRef->c2 &&
    8891           2 :                             entry->c3 == entryRef->c3)
    8892             :                         {
    8893           1 :                             pTranslationTable[i] =
    8894             :                                 static_cast<unsigned char>(j);
    8895           1 :                             bMatchFound = true;
    8896           1 :                             break;
    8897             :                         }
    8898             :                     }
    8899           4 :                     if (!bMatchFound)
    8900             :                     {
    8901             :                         // No exact match. Looking for closest color now.
    8902           3 :                         int best_j = 0;
    8903           3 :                         int best_distance = 0;
    8904           3 :                         if (pApproximateMatching)
    8905           0 :                             *pApproximateMatching = TRUE;
    8906          12 :                         for (int j = 0; j < nRefEntries; ++j)
    8907             :                         {
    8908             :                             const GDALColorEntry *entryRef =
    8909           9 :                                 destColorTable->GetColorEntry(j);
    8910           9 :                             int distance = (entry->c1 - entryRef->c1) *
    8911           9 :                                                (entry->c1 - entryRef->c1) +
    8912           9 :                                            (entry->c2 - entryRef->c2) *
    8913           9 :                                                (entry->c2 - entryRef->c2) +
    8914           9 :                                            (entry->c3 - entryRef->c3) *
    8915           9 :                                                (entry->c3 - entryRef->c3);
    8916           9 :                             if (j == 0 || distance < best_distance)
    8917             :                             {
    8918           7 :                                 best_j = j;
    8919           7 :                                 best_distance = distance;
    8920             :                             }
    8921             :                         }
    8922           3 :                         pTranslationTable[i] =
    8923             :                             static_cast<unsigned char>(best_j);
    8924             :                     }
    8925             :                 }
    8926           1 :                 if (bHasNoDataValueRef && bHasNoDataValueSrc)
    8927           0 :                     pTranslationTable[noDataValueSrc] =
    8928             :                         static_cast<unsigned char>(noDataValueRef);
    8929             : 
    8930           1 :                 return pTranslationTable;
    8931             :             }
    8932             :         }
    8933             :     }
    8934           3 :     return nullptr;
    8935             : }
    8936             : 
    8937             : /************************************************************************/
    8938             : /*                         SetFlushBlockErr()                           */
    8939             : /************************************************************************/
    8940             : 
    8941             : /**
    8942             :  * \brief Store that an error occurred while writing a dirty block.
    8943             :  *
    8944             :  * This function stores the fact that an error occurred while writing a dirty
    8945             :  * block from GDALRasterBlock::FlushCacheBlock(). Indeed when dirty blocks are
    8946             :  * flushed when the block cache get full, it is not convenient/possible to
    8947             :  * report that a dirty block could not be written correctly. This function
    8948             :  * remembers the error and re-issue it from GDALRasterBand::FlushCache(),
    8949             :  * GDALRasterBand::WriteBlock() and GDALRasterBand::RasterIO(), which are
    8950             :  * places where the user can easily match the error with the relevant dataset.
    8951             :  */
    8952             : 
    8953           0 : void GDALRasterBand::SetFlushBlockErr(CPLErr eErr)
    8954             : {
    8955           0 :     eFlushBlockErr = eErr;
    8956           0 : }
    8957             : 
    8958             : /************************************************************************/
    8959             : /*                         IncDirtyBlocks()                             */
    8960             : /************************************************************************/
    8961             : 
    8962             : /**
    8963             :  * \brief Increment/decrement the number of dirty blocks
    8964             :  */
    8965             : 
    8966      552608 : void GDALRasterBand::IncDirtyBlocks(int nInc)
    8967             : {
    8968      552608 :     if (poBandBlockCache)
    8969      552607 :         poBandBlockCache->IncDirtyBlocks(nInc);
    8970      552607 : }
    8971             : 
    8972             : /************************************************************************/
    8973             : /*                            ReportError()                             */
    8974             : /************************************************************************/
    8975             : 
    8976             : #ifndef DOXYGEN_XML
    8977             : /**
    8978             :  * \brief Emits an error related to a raster band.
    8979             :  *
    8980             :  * This function is a wrapper for regular CPLError(). The only difference
    8981             :  * with CPLError() is that it prepends the error message with the dataset
    8982             :  * name and the band number.
    8983             :  *
    8984             :  * @param eErrClass one of CE_Warning, CE_Failure or CE_Fatal.
    8985             :  * @param err_no the error number (CPLE_*) from cpl_error.h.
    8986             :  * @param fmt a printf() style format string.  Any additional arguments
    8987             :  * will be treated as arguments to fill in this format in a manner
    8988             :  * similar to printf().
    8989             :  *
    8990             :  * @since GDAL 1.9.0
    8991             :  */
    8992             : 
    8993        2459 : void GDALRasterBand::ReportError(CPLErr eErrClass, CPLErrorNum err_no,
    8994             :                                  const char *fmt, ...) const
    8995             : {
    8996             :     va_list args;
    8997             : 
    8998        2459 :     va_start(args, fmt);
    8999             : 
    9000        2459 :     const char *pszDSName = poDS ? poDS->GetDescription() : "";
    9001        2459 :     pszDSName = CPLGetFilename(pszDSName);
    9002        2459 :     if (pszDSName[0] != '\0')
    9003             :     {
    9004        2394 :         CPLError(eErrClass, err_no, "%s",
    9005        4788 :                  CPLString()
    9006        2394 :                      .Printf("%s, band %d: ", pszDSName, GetBand())
    9007        4788 :                      .append(CPLString().vPrintf(fmt, args))
    9008             :                      .c_str());
    9009             :     }
    9010             :     else
    9011             :     {
    9012          65 :         CPLErrorV(eErrClass, err_no, fmt, args);
    9013             :     }
    9014             : 
    9015        2459 :     va_end(args);
    9016        2459 : }
    9017             : #endif
    9018             : 
    9019             : /************************************************************************/
    9020             : /*                           GetVirtualMemAuto()                        */
    9021             : /************************************************************************/
    9022             : 
    9023             : /** \brief Create a CPLVirtualMem object from a GDAL raster band object.
    9024             :  *
    9025             :  * Only supported on Linux and Unix systems with mmap() for now.
    9026             :  *
    9027             :  * This method allows creating a virtual memory object for a GDALRasterBand,
    9028             :  * that exposes the whole image data as a virtual array.
    9029             :  *
    9030             :  * The default implementation relies on GDALRasterBandGetVirtualMem(), but
    9031             :  * specialized implementation, such as for raw files, may also directly use
    9032             :  * mechanisms of the operating system to create a view of the underlying file
    9033             :  * into virtual memory ( CPLVirtualMemFileMapNew() )
    9034             :  *
    9035             :  * At the time of writing, the GeoTIFF driver and "raw" drivers (EHdr, ...)
    9036             :  * offer a specialized implementation with direct file mapping, provided that
    9037             :  * some requirements are met :
    9038             :  *   - for all drivers, the dataset must be backed by a "real" file in the file
    9039             :  *     system, and the byte ordering of multi-byte datatypes (Int16, etc.)
    9040             :  *     must match the native ordering of the CPU.
    9041             :  *   - in addition, for the GeoTIFF driver, the GeoTIFF file must be
    9042             :  * uncompressed, scanline oriented (i.e. not tiled). Strips must be organized in
    9043             :  * the file in sequential order, and be equally spaced (which is generally the
    9044             :  * case). Only power-of-two bit depths are supported (8 for GDT_Bye, 16 for
    9045             :  * GDT_Int16/GDT_UInt16/GDT_Float16, 32 for GDT_Float32 and 64 for GDT_Float64)
    9046             :  *
    9047             :  * The pointer returned remains valid until CPLVirtualMemFree() is called.
    9048             :  * CPLVirtualMemFree() must be called before the raster band object is
    9049             :  * destroyed.
    9050             :  *
    9051             :  * If p is such a pointer and base_type the type matching
    9052             :  * GDALGetRasterDataType(), the element of image coordinates (x, y) can be
    9053             :  * accessed with
    9054             :  * *(base_type*) ((GByte*)p + x * *pnPixelSpace + y * *pnLineSpace)
    9055             :  *
    9056             :  * This method is the same as the C GDALGetVirtualMemAuto() function.
    9057             :  *
    9058             :  * @param eRWFlag Either GF_Read to read the band, or GF_Write to
    9059             :  * read/write the band.
    9060             :  *
    9061             :  * @param pnPixelSpace Output parameter giving the byte offset from the start of
    9062             :  * one pixel value in the buffer to the start of the next pixel value within a
    9063             :  * scanline.
    9064             :  *
    9065             :  * @param pnLineSpace Output parameter giving the byte offset from the start of
    9066             :  * one scanline in the buffer to the start of the next.
    9067             :  *
    9068             :  * @param papszOptions NULL terminated list of options.
    9069             :  *                     If a specialized implementation exists, defining
    9070             :  * USE_DEFAULT_IMPLEMENTATION=YES will cause the default implementation to be
    9071             :  * used. On the contrary, starting with GDAL 2.2, defining
    9072             :  * USE_DEFAULT_IMPLEMENTATION=NO will prevent the default implementation from
    9073             :  * being used (thus only allowing efficient implementations to be used). When
    9074             :  * requiring or falling back to the default implementation, the following
    9075             :  *                     options are available : CACHE_SIZE (in bytes, defaults to
    9076             :  * 40 MB), PAGE_SIZE_HINT (in bytes), SINGLE_THREAD ("FALSE" / "TRUE", defaults
    9077             :  * to FALSE)
    9078             :  *
    9079             :  * @return a virtual memory object that must be unreferenced by
    9080             :  * CPLVirtualMemFree(), or NULL in case of failure.
    9081             :  *
    9082             :  * @since GDAL 1.11
    9083             :  */
    9084             : 
    9085           9 : CPLVirtualMem *GDALRasterBand::GetVirtualMemAuto(GDALRWFlag eRWFlag,
    9086             :                                                  int *pnPixelSpace,
    9087             :                                                  GIntBig *pnLineSpace,
    9088             :                                                  char **papszOptions)
    9089             : {
    9090           9 :     const char *pszImpl = CSLFetchNameValueDef(
    9091             :         papszOptions, "USE_DEFAULT_IMPLEMENTATION", "AUTO");
    9092           9 :     if (EQUAL(pszImpl, "NO") || EQUAL(pszImpl, "OFF") || EQUAL(pszImpl, "0") ||
    9093           8 :         EQUAL(pszImpl, "FALSE"))
    9094             :     {
    9095           1 :         return nullptr;
    9096             :     }
    9097             : 
    9098           8 :     const int nPixelSpace = GDALGetDataTypeSizeBytes(eDataType);
    9099           8 :     const GIntBig nLineSpace = static_cast<GIntBig>(nRasterXSize) * nPixelSpace;
    9100           8 :     if (pnPixelSpace)
    9101           8 :         *pnPixelSpace = nPixelSpace;
    9102           8 :     if (pnLineSpace)
    9103           8 :         *pnLineSpace = nLineSpace;
    9104             :     const size_t nCacheSize =
    9105           8 :         atoi(CSLFetchNameValueDef(papszOptions, "CACHE_SIZE", "40000000"));
    9106             :     const size_t nPageSizeHint =
    9107           8 :         atoi(CSLFetchNameValueDef(papszOptions, "PAGE_SIZE_HINT", "0"));
    9108           8 :     const bool bSingleThreadUsage = CPLTestBool(
    9109             :         CSLFetchNameValueDef(papszOptions, "SINGLE_THREAD", "FALSE"));
    9110           8 :     return GDALRasterBandGetVirtualMem(
    9111             :         GDALRasterBand::ToHandle(this), eRWFlag, 0, 0, nRasterXSize,
    9112             :         nRasterYSize, nRasterXSize, nRasterYSize, eDataType, nPixelSpace,
    9113             :         nLineSpace, nCacheSize, nPageSizeHint, bSingleThreadUsage,
    9114           8 :         papszOptions);
    9115             : }
    9116             : 
    9117             : /************************************************************************/
    9118             : /*                         GDALGetVirtualMemAuto()                      */
    9119             : /************************************************************************/
    9120             : 
    9121             : /**
    9122             :  * \brief Create a CPLVirtualMem object from a GDAL raster band object.
    9123             :  *
    9124             :  * @see GDALRasterBand::GetVirtualMemAuto()
    9125             :  */
    9126             : 
    9127          31 : CPLVirtualMem *GDALGetVirtualMemAuto(GDALRasterBandH hBand, GDALRWFlag eRWFlag,
    9128             :                                      int *pnPixelSpace, GIntBig *pnLineSpace,
    9129             :                                      CSLConstList papszOptions)
    9130             : {
    9131          31 :     VALIDATE_POINTER1(hBand, "GDALGetVirtualMemAuto", nullptr);
    9132             : 
    9133          31 :     GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
    9134             : 
    9135          31 :     return poBand->GetVirtualMemAuto(eRWFlag, pnPixelSpace, pnLineSpace,
    9136          31 :                                      const_cast<char **>(papszOptions));
    9137             : }
    9138             : 
    9139             : /************************************************************************/
    9140             : /*                        GDALGetDataCoverageStatus()                   */
    9141             : /************************************************************************/
    9142             : 
    9143             : /**
    9144             :  * \brief Get the coverage status of a sub-window of the raster.
    9145             :  *
    9146             :  * Returns whether a sub-window of the raster contains only data, only empty
    9147             :  * blocks or a mix of both. This function can be used to determine quickly
    9148             :  * if it is worth issuing RasterIO / ReadBlock requests in datasets that may
    9149             :  * be sparse.
    9150             :  *
    9151             :  * Empty blocks are blocks that are generally not physically present in the
    9152             :  * file, and when read through GDAL, contain only pixels whose value is the
    9153             :  * nodata value when it is set, or whose value is 0 when the nodata value is
    9154             :  * not set.
    9155             :  *
    9156             :  * The query is done in an efficient way without reading the actual pixel
    9157             :  * values. If not possible, or not implemented at all by the driver,
    9158             :  * GDAL_DATA_COVERAGE_STATUS_UNIMPLEMENTED | GDAL_DATA_COVERAGE_STATUS_DATA will
    9159             :  * be returned.
    9160             :  *
    9161             :  * The values that can be returned by the function are the following,
    9162             :  * potentially combined with the binary or operator :
    9163             :  * <ul>
    9164             :  * <li>GDAL_DATA_COVERAGE_STATUS_UNIMPLEMENTED : the driver does not implement
    9165             :  * GetDataCoverageStatus(). This flag should be returned together with
    9166             :  * GDAL_DATA_COVERAGE_STATUS_DATA.</li>
    9167             :  * <li>GDAL_DATA_COVERAGE_STATUS_DATA: There is (potentially) data in the
    9168             :  * queried window.</li> <li>GDAL_DATA_COVERAGE_STATUS_EMPTY: There is nodata in
    9169             :  * the queried window. This is typically identified by the concept of missing
    9170             :  * block in formats that supports it.
    9171             :  * </li>
    9172             :  * </ul>
    9173             :  *
    9174             :  * Note that GDAL_DATA_COVERAGE_STATUS_DATA might have false positives and
    9175             :  * should be interpreted more as hint of potential presence of data. For example
    9176             :  * if a GeoTIFF file is created with blocks filled with zeroes (or set to the
    9177             :  * nodata value), instead of using the missing block mechanism,
    9178             :  * GDAL_DATA_COVERAGE_STATUS_DATA will be returned. On the contrary,
    9179             :  * GDAL_DATA_COVERAGE_STATUS_EMPTY should have no false positives.
    9180             :  *
    9181             :  * The nMaskFlagStop should be generally set to 0. It can be set to a
    9182             :  * binary-or'ed mask of the above mentioned values to enable a quick exiting of
    9183             :  * the function as soon as the computed mask matches the nMaskFlagStop. For
    9184             :  * example, you can issue a request on the whole raster with nMaskFlagStop =
    9185             :  * GDAL_DATA_COVERAGE_STATUS_EMPTY. As soon as one missing block is encountered,
    9186             :  * the function will exit, so that you can potentially refine the requested area
    9187             :  * to find which particular region(s) have missing blocks.
    9188             :  *
    9189             :  * @see GDALRasterBand::GetDataCoverageStatus()
    9190             :  *
    9191             :  * @param hBand raster band
    9192             :  *
    9193             :  * @param nXOff The pixel offset to the top left corner of the region
    9194             :  * of the band to be queried. This would be zero to start from the left side.
    9195             :  *
    9196             :  * @param nYOff The line offset to the top left corner of the region
    9197             :  * of the band to be queried. This would be zero to start from the top.
    9198             :  *
    9199             :  * @param nXSize The width of the region of the band to be queried in pixels.
    9200             :  *
    9201             :  * @param nYSize The height of the region of the band to be queried in lines.
    9202             :  *
    9203             :  * @param nMaskFlagStop 0, or a binary-or'ed mask of possible values
    9204             :  * GDAL_DATA_COVERAGE_STATUS_UNIMPLEMENTED,
    9205             :  * GDAL_DATA_COVERAGE_STATUS_DATA and GDAL_DATA_COVERAGE_STATUS_EMPTY. As soon
    9206             :  * as the computation of the coverage matches the mask, the computation will be
    9207             :  * stopped. *pdfDataPct will not be valid in that case.
    9208             :  *
    9209             :  * @param pdfDataPct Optional output parameter whose pointed value will be set
    9210             :  * to the (approximate) percentage in [0,100] of pixels in the queried
    9211             :  * sub-window that have valid values. The implementation might not always be
    9212             :  * able to compute it, in which case it will be set to a negative value.
    9213             :  *
    9214             :  * @return a binary-or'ed combination of possible values
    9215             :  * GDAL_DATA_COVERAGE_STATUS_UNIMPLEMENTED,
    9216             :  * GDAL_DATA_COVERAGE_STATUS_DATA and GDAL_DATA_COVERAGE_STATUS_EMPTY
    9217             :  *
    9218             :  * @note Added in GDAL 2.2
    9219             :  */
    9220             : 
    9221          26 : int CPL_STDCALL GDALGetDataCoverageStatus(GDALRasterBandH hBand, int nXOff,
    9222             :                                           int nYOff, int nXSize, int nYSize,
    9223             :                                           int nMaskFlagStop, double *pdfDataPct)
    9224             : {
    9225          26 :     VALIDATE_POINTER1(hBand, "GDALGetDataCoverageStatus",
    9226             :                       GDAL_DATA_COVERAGE_STATUS_UNIMPLEMENTED);
    9227             : 
    9228          26 :     GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
    9229             : 
    9230          26 :     return poBand->GetDataCoverageStatus(nXOff, nYOff, nXSize, nYSize,
    9231          26 :                                          nMaskFlagStop, pdfDataPct);
    9232             : }
    9233             : 
    9234             : /************************************************************************/
    9235             : /*                          GetDataCoverageStatus()                     */
    9236             : /************************************************************************/
    9237             : 
    9238             : /**
    9239             :  * \fn GDALRasterBand::IGetDataCoverageStatus( int nXOff,
    9240             :  *                                           int nYOff,
    9241             :  *                                           int nXSize,
    9242             :  *                                           int nYSize,
    9243             :  *                                           int nMaskFlagStop,
    9244             :  *                                           double* pdfDataPct)
    9245             :  * \brief Get the coverage status of a sub-window of the raster.
    9246             :  *
    9247             :  * Returns whether a sub-window of the raster contains only data, only empty
    9248             :  * blocks or a mix of both. This function can be used to determine quickly
    9249             :  * if it is worth issuing RasterIO / ReadBlock requests in datasets that may
    9250             :  * be sparse.
    9251             :  *
    9252             :  * Empty blocks are blocks that contain only pixels whose value is the nodata
    9253             :  * value when it is set, or whose value is 0 when the nodata value is not set.
    9254             :  *
    9255             :  * The query is done in an efficient way without reading the actual pixel
    9256             :  * values. If not possible, or not implemented at all by the driver,
    9257             :  * GDAL_DATA_COVERAGE_STATUS_UNIMPLEMENTED | GDAL_DATA_COVERAGE_STATUS_DATA will
    9258             :  * be returned.
    9259             :  *
    9260             :  * The values that can be returned by the function are the following,
    9261             :  * potentially combined with the binary or operator :
    9262             :  * <ul>
    9263             :  * <li>GDAL_DATA_COVERAGE_STATUS_UNIMPLEMENTED : the driver does not implement
    9264             :  * GetDataCoverageStatus(). This flag should be returned together with
    9265             :  * GDAL_DATA_COVERAGE_STATUS_DATA.</li>
    9266             :  * <li>GDAL_DATA_COVERAGE_STATUS_DATA: There is (potentially) data in the
    9267             :  * queried window.</li> <li>GDAL_DATA_COVERAGE_STATUS_EMPTY: There is nodata in
    9268             :  * the queried window. This is typically identified by the concept of missing
    9269             :  * block in formats that supports it.
    9270             :  * </li>
    9271             :  * </ul>
    9272             :  *
    9273             :  * Note that GDAL_DATA_COVERAGE_STATUS_DATA might have false positives and
    9274             :  * should be interpreted more as hint of potential presence of data. For example
    9275             :  * if a GeoTIFF file is created with blocks filled with zeroes (or set to the
    9276             :  * nodata value), instead of using the missing block mechanism,
    9277             :  * GDAL_DATA_COVERAGE_STATUS_DATA will be returned. On the contrary,
    9278             :  * GDAL_DATA_COVERAGE_STATUS_EMPTY should have no false positives.
    9279             :  *
    9280             :  * The nMaskFlagStop should be generally set to 0. It can be set to a
    9281             :  * binary-or'ed mask of the above mentioned values to enable a quick exiting of
    9282             :  * the function as soon as the computed mask matches the nMaskFlagStop. For
    9283             :  * example, you can issue a request on the whole raster with nMaskFlagStop =
    9284             :  * GDAL_DATA_COVERAGE_STATUS_EMPTY. As soon as one missing block is encountered,
    9285             :  * the function will exit, so that you can potentially refine the requested area
    9286             :  * to find which particular region(s) have missing blocks.
    9287             :  *
    9288             :  * @see GDALGetDataCoverageStatus()
    9289             :  *
    9290             :  * @param nXOff The pixel offset to the top left corner of the region
    9291             :  * of the band to be queried. This would be zero to start from the left side.
    9292             :  *
    9293             :  * @param nYOff The line offset to the top left corner of the region
    9294             :  * of the band to be queried. This would be zero to start from the top.
    9295             :  *
    9296             :  * @param nXSize The width of the region of the band to be queried in pixels.
    9297             :  *
    9298             :  * @param nYSize The height of the region of the band to be queried in lines.
    9299             :  *
    9300             :  * @param nMaskFlagStop 0, or a binary-or'ed mask of possible values
    9301             :  * GDAL_DATA_COVERAGE_STATUS_UNIMPLEMENTED,
    9302             :  * GDAL_DATA_COVERAGE_STATUS_DATA and GDAL_DATA_COVERAGE_STATUS_EMPTY. As soon
    9303             :  * as the computation of the coverage matches the mask, the computation will be
    9304             :  * stopped. *pdfDataPct will not be valid in that case.
    9305             :  *
    9306             :  * @param pdfDataPct Optional output parameter whose pointed value will be set
    9307             :  * to the (approximate) percentage in [0,100] of pixels in the queried
    9308             :  * sub-window that have valid values. The implementation might not always be
    9309             :  * able to compute it, in which case it will be set to a negative value.
    9310             :  *
    9311             :  * @return a binary-or'ed combination of possible values
    9312             :  * GDAL_DATA_COVERAGE_STATUS_UNIMPLEMENTED,
    9313             :  * GDAL_DATA_COVERAGE_STATUS_DATA and GDAL_DATA_COVERAGE_STATUS_EMPTY
    9314             :  *
    9315             :  * @note Added in GDAL 2.2
    9316             :  */
    9317             : 
    9318             : /**
    9319             :  * \brief Get the coverage status of a sub-window of the raster.
    9320             :  *
    9321             :  * Returns whether a sub-window of the raster contains only data, only empty
    9322             :  * blocks or a mix of both. This function can be used to determine quickly
    9323             :  * if it is worth issuing RasterIO / ReadBlock requests in datasets that may
    9324             :  * be sparse.
    9325             :  *
    9326             :  * Empty blocks are blocks that contain only pixels whose value is the nodata
    9327             :  * value when it is set, or whose value is 0 when the nodata value is not set.
    9328             :  *
    9329             :  * The query is done in an efficient way without reading the actual pixel
    9330             :  * values. If not possible, or not implemented at all by the driver,
    9331             :  * GDAL_DATA_COVERAGE_STATUS_UNIMPLEMENTED | GDAL_DATA_COVERAGE_STATUS_DATA will
    9332             :  * be returned.
    9333             :  *
    9334             :  * The values that can be returned by the function are the following,
    9335             :  * potentially combined with the binary or operator :
    9336             :  * <ul>
    9337             :  * <li>GDAL_DATA_COVERAGE_STATUS_UNIMPLEMENTED : the driver does not implement
    9338             :  * GetDataCoverageStatus(). This flag should be returned together with
    9339             :  * GDAL_DATA_COVERAGE_STATUS_DATA.</li>
    9340             :  * <li>GDAL_DATA_COVERAGE_STATUS_DATA: There is (potentially) data in the
    9341             :  * queried window.</li> <li>GDAL_DATA_COVERAGE_STATUS_EMPTY: There is nodata in
    9342             :  * the queried window. This is typically identified by the concept of missing
    9343             :  * block in formats that supports it.
    9344             :  * </li>
    9345             :  * </ul>
    9346             :  *
    9347             :  * Note that GDAL_DATA_COVERAGE_STATUS_DATA might have false positives and
    9348             :  * should be interpreted more as hint of potential presence of data. For example
    9349             :  * if a GeoTIFF file is created with blocks filled with zeroes (or set to the
    9350             :  * nodata value), instead of using the missing block mechanism,
    9351             :  * GDAL_DATA_COVERAGE_STATUS_DATA will be returned. On the contrary,
    9352             :  * GDAL_DATA_COVERAGE_STATUS_EMPTY should have no false positives.
    9353             :  *
    9354             :  * The nMaskFlagStop should be generally set to 0. It can be set to a
    9355             :  * binary-or'ed mask of the above mentioned values to enable a quick exiting of
    9356             :  * the function as soon as the computed mask matches the nMaskFlagStop. For
    9357             :  * example, you can issue a request on the whole raster with nMaskFlagStop =
    9358             :  * GDAL_DATA_COVERAGE_STATUS_EMPTY. As soon as one missing block is encountered,
    9359             :  * the function will exit, so that you can potentially refine the requested area
    9360             :  * to find which particular region(s) have missing blocks.
    9361             :  *
    9362             :  * @see GDALGetDataCoverageStatus()
    9363             :  *
    9364             :  * @param nXOff The pixel offset to the top left corner of the region
    9365             :  * of the band to be queried. This would be zero to start from the left side.
    9366             :  *
    9367             :  * @param nYOff The line offset to the top left corner of the region
    9368             :  * of the band to be queried. This would be zero to start from the top.
    9369             :  *
    9370             :  * @param nXSize The width of the region of the band to be queried in pixels.
    9371             :  *
    9372             :  * @param nYSize The height of the region of the band to be queried in lines.
    9373             :  *
    9374             :  * @param nMaskFlagStop 0, or a binary-or'ed mask of possible values
    9375             :  * GDAL_DATA_COVERAGE_STATUS_UNIMPLEMENTED,
    9376             :  * GDAL_DATA_COVERAGE_STATUS_DATA and GDAL_DATA_COVERAGE_STATUS_EMPTY. As soon
    9377             :  * as the computation of the coverage matches the mask, the computation will be
    9378             :  * stopped. *pdfDataPct will not be valid in that case.
    9379             :  *
    9380             :  * @param pdfDataPct Optional output parameter whose pointed value will be set
    9381             :  * to the (approximate) percentage in [0,100] of pixels in the queried
    9382             :  * sub-window that have valid values. The implementation might not always be
    9383             :  * able to compute it, in which case it will be set to a negative value.
    9384             :  *
    9385             :  * @return a binary-or'ed combination of possible values
    9386             :  * GDAL_DATA_COVERAGE_STATUS_UNIMPLEMENTED,
    9387             :  * GDAL_DATA_COVERAGE_STATUS_DATA and GDAL_DATA_COVERAGE_STATUS_EMPTY
    9388             :  *
    9389             :  * @note Added in GDAL 2.2
    9390             :  */
    9391             : 
    9392        4603 : int GDALRasterBand::GetDataCoverageStatus(int nXOff, int nYOff, int nXSize,
    9393             :                                           int nYSize, int nMaskFlagStop,
    9394             :                                           double *pdfDataPct)
    9395             : {
    9396        4603 :     if (nXOff < 0 || nYOff < 0 || nXSize > INT_MAX - nXOff ||
    9397        4603 :         nYSize > INT_MAX - nYOff || nXOff + nXSize > nRasterXSize ||
    9398        4603 :         nYOff + nYSize > nRasterYSize)
    9399             :     {
    9400           0 :         CPLError(CE_Failure, CPLE_AppDefined, "Bad window");
    9401           0 :         if (pdfDataPct)
    9402           0 :             *pdfDataPct = 0.0;
    9403             :         return GDAL_DATA_COVERAGE_STATUS_UNIMPLEMENTED |
    9404           0 :                GDAL_DATA_COVERAGE_STATUS_EMPTY;
    9405             :     }
    9406        4603 :     return IGetDataCoverageStatus(nXOff, nYOff, nXSize, nYSize, nMaskFlagStop,
    9407        4603 :                                   pdfDataPct);
    9408             : }
    9409             : 
    9410             : /************************************************************************/
    9411             : /*                         IGetDataCoverageStatus()                     */
    9412             : /************************************************************************/
    9413             : 
    9414         683 : int GDALRasterBand::IGetDataCoverageStatus(int /*nXOff*/, int /*nYOff*/,
    9415             :                                            int /*nXSize*/, int /*nYSize*/,
    9416             :                                            int /*nMaskFlagStop*/,
    9417             :                                            double *pdfDataPct)
    9418             : {
    9419         683 :     if (pdfDataPct != nullptr)
    9420           0 :         *pdfDataPct = 100.0;
    9421             :     return GDAL_DATA_COVERAGE_STATUS_UNIMPLEMENTED |
    9422         683 :            GDAL_DATA_COVERAGE_STATUS_DATA;
    9423             : }
    9424             : 
    9425             : //! @cond Doxygen_Suppress
    9426             : /************************************************************************/
    9427             : /*                          EnterReadWrite()                            */
    9428             : /************************************************************************/
    9429             : 
    9430     7481830 : int GDALRasterBand::EnterReadWrite(GDALRWFlag eRWFlag)
    9431             : {
    9432     7481830 :     if (poDS != nullptr)
    9433     6722650 :         return poDS->EnterReadWrite(eRWFlag);
    9434      759186 :     return FALSE;
    9435             : }
    9436             : 
    9437             : /************************************************************************/
    9438             : /*                         LeaveReadWrite()                             */
    9439             : /************************************************************************/
    9440             : 
    9441     1028260 : void GDALRasterBand::LeaveReadWrite()
    9442             : {
    9443     1028260 :     if (poDS != nullptr)
    9444     1028240 :         poDS->LeaveReadWrite();
    9445     1028230 : }
    9446             : 
    9447             : /************************************************************************/
    9448             : /*                           InitRWLock()                               */
    9449             : /************************************************************************/
    9450             : 
    9451     3856150 : void GDALRasterBand::InitRWLock()
    9452             : {
    9453     3856150 :     if (poDS != nullptr)
    9454     3855750 :         poDS->InitRWLock();
    9455     3856150 : }
    9456             : 
    9457             : //! @endcond
    9458             : 
    9459             : // clang-format off
    9460             : 
    9461             : /**
    9462             :  * \fn GDALRasterBand::SetMetadata( char ** papszMetadata, const char * pszDomain)
    9463             :  * \brief Set metadata.
    9464             :  *
    9465             :  * CAUTION: depending on the format, older values of the updated information
    9466             :  * might still be found in the file in a "ghost" state, even if no longer
    9467             :  * accessible through the GDAL API. This is for example the case of the GTiff
    9468             :  * format (this is not a exhaustive list)
    9469             :  *
    9470             :  * The C function GDALSetMetadata() does the same thing as this method.
    9471             :  *
    9472             :  * @param papszMetadata the metadata in name=value string list format to
    9473             :  * apply.
    9474             :  * @param pszDomain the domain of interest.  Use "" or NULL for the default
    9475             :  * domain.
    9476             :  * @return CE_None on success, CE_Failure on failure and CE_Warning if the
    9477             :  * metadata has been accepted, but is likely not maintained persistently
    9478             :  * by the underlying object between sessions.
    9479             :  */
    9480             : 
    9481             : /**
    9482             :  * \fn GDALRasterBand::SetMetadataItem( const char * pszName, const char * pszValue, const char * pszDomain)
    9483             :  * \brief Set single metadata item.
    9484             :  *
    9485             :  * CAUTION: depending on the format, older values of the updated information
    9486             :  * might still be found in the file in a "ghost" state, even if no longer
    9487             :  * accessible through the GDAL API. This is for example the case of the GTiff
    9488             :  * format (this is not a exhaustive list)
    9489             :  *
    9490             :  * The C function GDALSetMetadataItem() does the same thing as this method.
    9491             :  *
    9492             :  * @param pszName the key for the metadata item to fetch.
    9493             :  * @param pszValue the value to assign to the key.
    9494             :  * @param pszDomain the domain to set within, use NULL for the default domain.
    9495             :  *
    9496             :  * @return CE_None on success, or an error code on failure.
    9497             :  */
    9498             : 
    9499             : // clang-format on
    9500             : 
    9501             : //! @cond Doxygen_Suppress
    9502             : /************************************************************************/
    9503             : /*                    EnablePixelTypeSignedByteWarning()                */
    9504             : /************************************************************************/
    9505             : 
    9506      155554 : void GDALRasterBand::EnablePixelTypeSignedByteWarning(bool b)
    9507             : {
    9508      155554 :     m_bEnablePixelTypeSignedByteWarning = b;
    9509      155554 : }
    9510             : 
    9511        4866 : void GDALEnablePixelTypeSignedByteWarning(GDALRasterBandH hBand, bool b)
    9512             : {
    9513        4866 :     GDALRasterBand::FromHandle(hBand)->EnablePixelTypeSignedByteWarning(b);
    9514        4866 : }
    9515             : 
    9516             : //! @endcond
    9517             : 
    9518             : /************************************************************************/
    9519             : /*                           GetMetadataItem()                          */
    9520             : /************************************************************************/
    9521             : 
    9522      387111 : const char *GDALRasterBand::GetMetadataItem(const char *pszName,
    9523             :                                             const char *pszDomain)
    9524             : {
    9525             :     // TODO (GDAL 4.0?): remove this when GDAL 3.7 has been widely adopted.
    9526      387111 :     if (m_bEnablePixelTypeSignedByteWarning && eDataType == GDT_Byte &&
    9527      296602 :         pszDomain != nullptr && EQUAL(pszDomain, "IMAGE_STRUCTURE") &&
    9528      287615 :         EQUAL(pszName, "PIXELTYPE"))
    9529             :     {
    9530           2 :         CPLError(CE_Warning, CPLE_AppDefined,
    9531             :                  "Starting with GDAL 3.7, PIXELTYPE=SIGNEDBYTE is no longer "
    9532             :                  "used to signal signed 8-bit raster. Change your code to "
    9533             :                  "test for the new GDT_Int8 data type instead.");
    9534             :     }
    9535      387111 :     return GDALMajorObject::GetMetadataItem(pszName, pszDomain);
    9536             : }
    9537             : 
    9538             : /************************************************************************/
    9539             : /*                     GDALMDArrayFromRasterBand                        */
    9540             : /************************************************************************/
    9541             : 
    9542             : class GDALMDArrayFromRasterBand final : public GDALMDArray
    9543             : {
    9544             :     CPL_DISALLOW_COPY_ASSIGN(GDALMDArrayFromRasterBand)
    9545             : 
    9546             :     GDALDataset *m_poDS;
    9547             :     GDALRasterBand *m_poBand;
    9548             :     GDALExtendedDataType m_dt;
    9549             :     std::vector<std::shared_ptr<GDALDimension>> m_dims{};
    9550             :     std::string m_osUnit;
    9551             :     std::vector<GByte> m_pabyNoData{};
    9552             :     std::shared_ptr<GDALMDArray> m_varX{};
    9553             :     std::shared_ptr<GDALMDArray> m_varY{};
    9554             :     std::string m_osFilename{};
    9555             : 
    9556             :     bool ReadWrite(GDALRWFlag eRWFlag, const GUInt64 *arrayStartIdx,
    9557             :                    const size_t *count, const GInt64 *arrayStep,
    9558             :                    const GPtrDiff_t *bufferStride,
    9559             :                    const GDALExtendedDataType &bufferDataType,
    9560             :                    void *pBuffer) const;
    9561             : 
    9562             :   protected:
    9563          23 :     GDALMDArrayFromRasterBand(GDALDataset *poDS, GDALRasterBand *poBand)
    9564          46 :         : GDALAbstractMDArray(std::string(),
    9565          46 :                               std::string(poDS->GetDescription()) +
    9566             :                                   CPLSPrintf(" band %d", poBand->GetBand())),
    9567          46 :           GDALMDArray(std::string(),
    9568          46 :                       std::string(poDS->GetDescription()) +
    9569             :                           CPLSPrintf(" band %d", poBand->GetBand())),
    9570             :           m_poDS(poDS), m_poBand(poBand),
    9571             :           m_dt(GDALExtendedDataType::Create(poBand->GetRasterDataType())),
    9572         115 :           m_osUnit(poBand->GetUnitType()), m_osFilename(poDS->GetDescription())
    9573             :     {
    9574          23 :         m_poDS->Reference();
    9575             : 
    9576          23 :         int bHasNoData = false;
    9577          23 :         if (m_poBand->GetRasterDataType() == GDT_Int64)
    9578             :         {
    9579           0 :             const auto nNoData = m_poBand->GetNoDataValueAsInt64(&bHasNoData);
    9580           0 :             if (bHasNoData)
    9581             :             {
    9582           0 :                 m_pabyNoData.resize(m_dt.GetSize());
    9583           0 :                 GDALCopyWords64(&nNoData, GDT_Int64, 0, &m_pabyNoData[0],
    9584             :                                 m_dt.GetNumericDataType(), 0, 1);
    9585             :             }
    9586             :         }
    9587          23 :         else if (m_poBand->GetRasterDataType() == GDT_UInt64)
    9588             :         {
    9589           0 :             const auto nNoData = m_poBand->GetNoDataValueAsUInt64(&bHasNoData);
    9590           0 :             if (bHasNoData)
    9591             :             {
    9592           0 :                 m_pabyNoData.resize(m_dt.GetSize());
    9593           0 :                 GDALCopyWords64(&nNoData, GDT_UInt64, 0, &m_pabyNoData[0],
    9594             :                                 m_dt.GetNumericDataType(), 0, 1);
    9595             :             }
    9596             :         }
    9597             :         else
    9598             :         {
    9599          23 :             const auto dfNoData = m_poBand->GetNoDataValue(&bHasNoData);
    9600          23 :             if (bHasNoData)
    9601             :             {
    9602           1 :                 m_pabyNoData.resize(m_dt.GetSize());
    9603           1 :                 GDALCopyWords64(&dfNoData, GDT_Float64, 0, &m_pabyNoData[0],
    9604             :                                 m_dt.GetNumericDataType(), 0, 1);
    9605             :             }
    9606             :         }
    9607             : 
    9608          23 :         const int nXSize = poBand->GetXSize();
    9609          23 :         const int nYSize = poBand->GetYSize();
    9610             : 
    9611          23 :         auto poSRS = m_poDS->GetSpatialRef();
    9612          46 :         std::string osTypeY;
    9613          46 :         std::string osTypeX;
    9614          46 :         std::string osDirectionY;
    9615          46 :         std::string osDirectionX;
    9616          23 :         if (poSRS && poSRS->GetAxesCount() == 2)
    9617             :         {
    9618          21 :             const auto &mapping = poSRS->GetDataAxisToSRSAxisMapping();
    9619          21 :             OGRAxisOrientation eOrientation1 = OAO_Other;
    9620          21 :             poSRS->GetAxis(nullptr, 0, &eOrientation1);
    9621          21 :             OGRAxisOrientation eOrientation2 = OAO_Other;
    9622          21 :             poSRS->GetAxis(nullptr, 1, &eOrientation2);
    9623          21 :             if (eOrientation1 == OAO_East && eOrientation2 == OAO_North)
    9624             :             {
    9625           5 :                 if (mapping == std::vector<int>{1, 2})
    9626             :                 {
    9627           5 :                     osTypeY = GDAL_DIM_TYPE_HORIZONTAL_Y;
    9628           5 :                     osDirectionY = "NORTH";
    9629           5 :                     osTypeX = GDAL_DIM_TYPE_HORIZONTAL_X;
    9630           5 :                     osDirectionX = "EAST";
    9631             :                 }
    9632             :             }
    9633          16 :             else if (eOrientation1 == OAO_North && eOrientation2 == OAO_East)
    9634             :             {
    9635          16 :                 if (mapping == std::vector<int>{2, 1})
    9636             :                 {
    9637          16 :                     osTypeY = GDAL_DIM_TYPE_HORIZONTAL_Y;
    9638          16 :                     osDirectionY = "NORTH";
    9639          16 :                     osTypeX = GDAL_DIM_TYPE_HORIZONTAL_X;
    9640          16 :                     osDirectionX = "EAST";
    9641             :                 }
    9642             :             }
    9643             :         }
    9644             : 
    9645         115 :         m_dims = {std::make_shared<GDALDimensionWeakIndexingVar>(
    9646             :                       "/", "Y", osTypeY, osDirectionY, nYSize),
    9647          46 :                   std::make_shared<GDALDimensionWeakIndexingVar>(
    9648          69 :                       "/", "X", osTypeX, osDirectionX, nXSize)};
    9649             : 
    9650             :         double adfGeoTransform[6];
    9651          23 :         if (m_poDS->GetGeoTransform(adfGeoTransform) == CE_None &&
    9652          23 :             adfGeoTransform[2] == 0 && adfGeoTransform[4] == 0)
    9653             :         {
    9654          44 :             m_varX = GDALMDArrayRegularlySpaced::Create(
    9655          22 :                 "/", "X", m_dims[1], adfGeoTransform[0], adfGeoTransform[1],
    9656          22 :                 0.5);
    9657          22 :             m_dims[1]->SetIndexingVariable(m_varX);
    9658             : 
    9659          44 :             m_varY = GDALMDArrayRegularlySpaced::Create(
    9660          22 :                 "/", "Y", m_dims[0], adfGeoTransform[3], adfGeoTransform[5],
    9661          22 :                 0.5);
    9662          22 :             m_dims[0]->SetIndexingVariable(m_varY);
    9663             :         }
    9664          23 :     }
    9665             : 
    9666          31 :     bool IRead(const GUInt64 *arrayStartIdx, const size_t *count,
    9667             :                const GInt64 *arrayStep, const GPtrDiff_t *bufferStride,
    9668             :                const GDALExtendedDataType &bufferDataType,
    9669             :                void *pDstBuffer) const override
    9670             :     {
    9671          31 :         return ReadWrite(GF_Read, arrayStartIdx, count, arrayStep, bufferStride,
    9672          31 :                          bufferDataType, pDstBuffer);
    9673             :     }
    9674             : 
    9675           1 :     bool IWrite(const GUInt64 *arrayStartIdx, const size_t *count,
    9676             :                 const GInt64 *arrayStep, const GPtrDiff_t *bufferStride,
    9677             :                 const GDALExtendedDataType &bufferDataType,
    9678             :                 const void *pSrcBuffer) override
    9679             :     {
    9680           1 :         return ReadWrite(GF_Write, arrayStartIdx, count, arrayStep,
    9681             :                          bufferStride, bufferDataType,
    9682           1 :                          const_cast<void *>(pSrcBuffer));
    9683             :     }
    9684             : 
    9685             :   public:
    9686          46 :     ~GDALMDArrayFromRasterBand()
    9687          23 :     {
    9688          23 :         m_poDS->ReleaseRef();
    9689          46 :     }
    9690             : 
    9691          23 :     static std::shared_ptr<GDALMDArray> Create(GDALDataset *poDS,
    9692             :                                                GDALRasterBand *poBand)
    9693             :     {
    9694             :         auto array(std::shared_ptr<GDALMDArrayFromRasterBand>(
    9695          46 :             new GDALMDArrayFromRasterBand(poDS, poBand)));
    9696          23 :         array->SetSelf(array);
    9697          46 :         return array;
    9698             :     }
    9699             : 
    9700           2 :     bool IsWritable() const override
    9701             :     {
    9702           2 :         return m_poDS->GetAccess() == GA_Update;
    9703             :     }
    9704             : 
    9705          97 :     const std::string &GetFilename() const override
    9706             :     {
    9707          97 :         return m_osFilename;
    9708             :     }
    9709             : 
    9710             :     const std::vector<std::shared_ptr<GDALDimension>> &
    9711         299 :     GetDimensions() const override
    9712             :     {
    9713         299 :         return m_dims;
    9714             :     }
    9715             : 
    9716         138 :     const GDALExtendedDataType &GetDataType() const override
    9717             :     {
    9718         138 :         return m_dt;
    9719             :     }
    9720             : 
    9721           3 :     const std::string &GetUnit() const override
    9722             :     {
    9723           3 :         return m_osUnit;
    9724             :     }
    9725             : 
    9726          29 :     const void *GetRawNoDataValue() const override
    9727             :     {
    9728          29 :         return m_pabyNoData.empty() ? nullptr : m_pabyNoData.data();
    9729             :     }
    9730             : 
    9731           2 :     double GetOffset(bool *pbHasOffset,
    9732             :                      GDALDataType *peStorageType) const override
    9733             :     {
    9734           2 :         int bHasOffset = false;
    9735           2 :         double dfRes = m_poBand->GetOffset(&bHasOffset);
    9736           2 :         if (pbHasOffset)
    9737           2 :             *pbHasOffset = CPL_TO_BOOL(bHasOffset);
    9738           2 :         if (peStorageType)
    9739           1 :             *peStorageType = GDT_Unknown;
    9740           2 :         return dfRes;
    9741             :     }
    9742             : 
    9743           2 :     double GetScale(bool *pbHasScale,
    9744             :                     GDALDataType *peStorageType) const override
    9745             :     {
    9746           2 :         int bHasScale = false;
    9747           2 :         double dfRes = m_poBand->GetScale(&bHasScale);
    9748           2 :         if (pbHasScale)
    9749           2 :             *pbHasScale = CPL_TO_BOOL(bHasScale);
    9750           2 :         if (peStorageType)
    9751           1 :             *peStorageType = GDT_Unknown;
    9752           2 :         return dfRes;
    9753             :     }
    9754             : 
    9755          84 :     std::shared_ptr<OGRSpatialReference> GetSpatialRef() const override
    9756             :     {
    9757          84 :         auto poSrcSRS = m_poDS->GetSpatialRef();
    9758          84 :         if (!poSrcSRS)
    9759           2 :             return nullptr;
    9760         164 :         auto poSRS = std::shared_ptr<OGRSpatialReference>(poSrcSRS->Clone());
    9761             : 
    9762         164 :         auto axisMapping = poSRS->GetDataAxisToSRSAxisMapping();
    9763          82 :         constexpr int iYDim = 0;
    9764          82 :         constexpr int iXDim = 1;
    9765         246 :         for (auto &m : axisMapping)
    9766             :         {
    9767         164 :             if (m == 1)
    9768          82 :                 m = iXDim + 1;
    9769          82 :             else if (m == 2)
    9770          82 :                 m = iYDim + 1;
    9771             :             else
    9772           0 :                 m = 0;
    9773             :         }
    9774          82 :         poSRS->SetDataAxisToSRSAxisMapping(axisMapping);
    9775          82 :         return poSRS;
    9776             :     }
    9777             : 
    9778          29 :     std::vector<GUInt64> GetBlockSize() const override
    9779             :     {
    9780          29 :         int nBlockXSize = 0;
    9781          29 :         int nBlockYSize = 0;
    9782          29 :         m_poBand->GetBlockSize(&nBlockXSize, &nBlockYSize);
    9783          29 :         return std::vector<GUInt64>{static_cast<GUInt64>(nBlockYSize),
    9784          29 :                                     static_cast<GUInt64>(nBlockXSize)};
    9785             :     }
    9786             : 
    9787             :     class MDIAsAttribute : public GDALAttribute
    9788             :     {
    9789             :         std::vector<std::shared_ptr<GDALDimension>> m_dims{};
    9790             :         const GDALExtendedDataType m_dt = GDALExtendedDataType::CreateString();
    9791             :         std::string m_osValue;
    9792             : 
    9793             :       public:
    9794           2 :         MDIAsAttribute(const std::string &name, const std::string &value)
    9795           2 :             : GDALAbstractMDArray(std::string(), name),
    9796           4 :               GDALAttribute(std::string(), name), m_osValue(value)
    9797             :         {
    9798           2 :         }
    9799             : 
    9800             :         const std::vector<std::shared_ptr<GDALDimension>> &
    9801           3 :         GetDimensions() const override
    9802             :         {
    9803           3 :             return m_dims;
    9804             :         }
    9805             : 
    9806           2 :         const GDALExtendedDataType &GetDataType() const override
    9807             :         {
    9808           2 :             return m_dt;
    9809             :         }
    9810             : 
    9811           1 :         bool IRead(const GUInt64 *, const size_t *, const GInt64 *,
    9812             :                    const GPtrDiff_t *,
    9813             :                    const GDALExtendedDataType &bufferDataType,
    9814             :                    void *pDstBuffer) const override
    9815             :         {
    9816           1 :             const char *pszStr = m_osValue.c_str();
    9817           1 :             GDALExtendedDataType::CopyValue(&pszStr, m_dt, pDstBuffer,
    9818             :                                             bufferDataType);
    9819           1 :             return true;
    9820             :         }
    9821             :     };
    9822             : 
    9823             :     std::vector<std::shared_ptr<GDALAttribute>>
    9824          14 :     GetAttributes(CSLConstList) const override
    9825             :     {
    9826          14 :         std::vector<std::shared_ptr<GDALAttribute>> res;
    9827          14 :         auto papszMD = m_poBand->GetMetadata();
    9828          16 :         for (auto iter = papszMD; iter && iter[0]; ++iter)
    9829             :         {
    9830           2 :             char *pszKey = nullptr;
    9831           2 :             const char *pszValue = CPLParseNameValue(*iter, &pszKey);
    9832           2 :             if (pszKey && pszValue)
    9833             :             {
    9834             :                 res.emplace_back(
    9835           2 :                     std::make_shared<MDIAsAttribute>(pszKey, pszValue));
    9836             :             }
    9837           2 :             CPLFree(pszKey);
    9838             :         }
    9839          14 :         return res;
    9840             :     }
    9841             : };
    9842             : 
    9843             : /************************************************************************/
    9844             : /*                            ReadWrite()                               */
    9845             : /************************************************************************/
    9846             : 
    9847          32 : bool GDALMDArrayFromRasterBand::ReadWrite(
    9848             :     GDALRWFlag eRWFlag, const GUInt64 *arrayStartIdx, const size_t *count,
    9849             :     const GInt64 *arrayStep, const GPtrDiff_t *bufferStride,
    9850             :     const GDALExtendedDataType &bufferDataType, void *pBuffer) const
    9851             : {
    9852          32 :     constexpr size_t iDimX = 1;
    9853          32 :     constexpr size_t iDimY = 0;
    9854          32 :     return GDALMDRasterIOFromBand(m_poBand, eRWFlag, iDimX, iDimY,
    9855             :                                   arrayStartIdx, count, arrayStep, bufferStride,
    9856          32 :                                   bufferDataType, pBuffer);
    9857             : }
    9858             : 
    9859             : /************************************************************************/
    9860             : /*                       GDALMDRasterIOFromBand()                       */
    9861             : /************************************************************************/
    9862             : 
    9863          65 : bool GDALMDRasterIOFromBand(GDALRasterBand *poBand, GDALRWFlag eRWFlag,
    9864             :                             size_t iDimX, size_t iDimY,
    9865             :                             const GUInt64 *arrayStartIdx, const size_t *count,
    9866             :                             const GInt64 *arrayStep,
    9867             :                             const GPtrDiff_t *bufferStride,
    9868             :                             const GDALExtendedDataType &bufferDataType,
    9869             :                             void *pBuffer)
    9870             : {
    9871          65 :     const auto eDT(bufferDataType.GetNumericDataType());
    9872          65 :     const auto nDTSize(GDALGetDataTypeSizeBytes(eDT));
    9873          65 :     const int nX =
    9874          65 :         arrayStep[iDimX] > 0
    9875          65 :             ? static_cast<int>(arrayStartIdx[iDimX])
    9876           2 :             : static_cast<int>(arrayStartIdx[iDimX] -
    9877           2 :                                (count[iDimX] - 1) * -arrayStep[iDimX]);
    9878          65 :     const int nY =
    9879          65 :         arrayStep[iDimY] > 0
    9880          65 :             ? static_cast<int>(arrayStartIdx[iDimY])
    9881           2 :             : static_cast<int>(arrayStartIdx[iDimY] -
    9882           2 :                                (count[iDimY] - 1) * -arrayStep[iDimY]);
    9883          65 :     const int nSizeX = static_cast<int>(count[iDimX] * ABS(arrayStep[iDimX]));
    9884          65 :     const int nSizeY = static_cast<int>(count[iDimY] * ABS(arrayStep[iDimY]));
    9885          65 :     GByte *pabyBuffer = static_cast<GByte *>(pBuffer);
    9886          65 :     int nStrideXSign = 1;
    9887          65 :     if (arrayStep[iDimX] < 0)
    9888             :     {
    9889           2 :         pabyBuffer += (count[iDimX] - 1) * bufferStride[iDimX] * nDTSize;
    9890           2 :         nStrideXSign = -1;
    9891             :     }
    9892          65 :     int nStrideYSign = 1;
    9893          65 :     if (arrayStep[iDimY] < 0)
    9894             :     {
    9895           2 :         pabyBuffer += (count[iDimY] - 1) * bufferStride[iDimY] * nDTSize;
    9896           2 :         nStrideYSign = -1;
    9897             :     }
    9898             : 
    9899         130 :     return poBand->RasterIO(eRWFlag, nX, nY, nSizeX, nSizeY, pabyBuffer,
    9900          65 :                             static_cast<int>(count[iDimX]),
    9901          65 :                             static_cast<int>(count[iDimY]), eDT,
    9902             :                             static_cast<GSpacing>(
    9903          65 :                                 nStrideXSign * bufferStride[iDimX] * nDTSize),
    9904             :                             static_cast<GSpacing>(
    9905          65 :                                 nStrideYSign * bufferStride[iDimY] * nDTSize),
    9906          65 :                             nullptr) == CE_None;
    9907             : }
    9908             : 
    9909             : /************************************************************************/
    9910             : /*                            AsMDArray()                               */
    9911             : /************************************************************************/
    9912             : 
    9913             : /** Return a view of this raster band as a 2D multidimensional GDALMDArray.
    9914             :  *
    9915             :  * The band must be linked to a GDALDataset. If this dataset is not already
    9916             :  * marked as shared, it will be, so that the returned array holds a reference
    9917             :  * to it.
    9918             :  *
    9919             :  * If the dataset has a geotransform attached, the X and Y dimensions of the
    9920             :  * returned array will have an associated indexing variable.
    9921             :  *
    9922             :  * This is the same as the C function GDALRasterBandAsMDArray().
    9923             :  *
    9924             :  * The "reverse" method is GDALMDArray::AsClassicDataset().
    9925             :  *
    9926             :  * @return a new array, or nullptr.
    9927             :  *
    9928             :  * @since GDAL 3.1
    9929             :  */
    9930          23 : std::shared_ptr<GDALMDArray> GDALRasterBand::AsMDArray() const
    9931             : {
    9932          23 :     if (!poDS)
    9933             :     {
    9934           0 :         CPLError(CE_Failure, CPLE_AppDefined, "Band not attached to a dataset");
    9935           0 :         return nullptr;
    9936             :     }
    9937          23 :     if (!poDS->GetShared())
    9938             :     {
    9939          23 :         poDS->MarkAsShared();
    9940             :     }
    9941             :     return GDALMDArrayFromRasterBand::Create(
    9942          23 :         poDS, const_cast<GDALRasterBand *>(this));
    9943             : }
    9944             : 
    9945             : /************************************************************************/
    9946             : /*                             InterpolateAtPoint()                     */
    9947             : /************************************************************************/
    9948             : 
    9949             : /**
    9950             :  * \brief Interpolates the value between pixels using a resampling algorithm,
    9951             :  * taking pixel/line coordinates as input.
    9952             :  *
    9953             :  * @param dfPixel pixel coordinate as a double, where interpolation should be done.
    9954             :  * @param dfLine line coordinate as a double, where interpolation should be done.
    9955             :  * @param eInterpolation interpolation type. Only near, bilinear, cubic and cubicspline are allowed.
    9956             :  * @param pdfRealValue pointer to real part of interpolated value
    9957             :  * @param pdfImagValue pointer to imaginary part of interpolated value (may be null if not needed)
    9958             :  *
    9959             :  * @return CE_None on success, or an error code on failure.
    9960             :  * @since GDAL 3.10
    9961             :  */
    9962             : 
    9963         153 : CPLErr GDALRasterBand::InterpolateAtPoint(double dfPixel, double dfLine,
    9964             :                                           GDALRIOResampleAlg eInterpolation,
    9965             :                                           double *pdfRealValue,
    9966             :                                           double *pdfImagValue) const
    9967             : {
    9968         153 :     if (eInterpolation != GRIORA_NearestNeighbour &&
    9969          33 :         eInterpolation != GRIORA_Bilinear && eInterpolation != GRIORA_Cubic &&
    9970             :         eInterpolation != GRIORA_CubicSpline)
    9971             :     {
    9972           2 :         CPLError(CE_Failure, CPLE_AppDefined,
    9973             :                  "Only nearest, bilinear, cubic and cubicspline interpolation "
    9974             :                  "methods "
    9975             :                  "allowed");
    9976             : 
    9977           2 :         return CE_Failure;
    9978             :     }
    9979             : 
    9980         151 :     GDALRasterBand *pBand = const_cast<GDALRasterBand *>(this);
    9981         151 :     if (!m_poPointsCache)
    9982          71 :         m_poPointsCache = new GDALDoublePointsCache();
    9983             : 
    9984             :     const bool res =
    9985         151 :         GDALInterpolateAtPoint(pBand, eInterpolation, m_poPointsCache->cache,
    9986             :                                dfPixel, dfLine, pdfRealValue, pdfImagValue);
    9987             : 
    9988         151 :     return res ? CE_None : CE_Failure;
    9989             : }
    9990             : 
    9991             : /************************************************************************/
    9992             : /*                        GDALRasterInterpolateAtPoint()                */
    9993             : /************************************************************************/
    9994             : 
    9995             : /**
    9996             :  * \brief Interpolates the value between pixels using
    9997             :  * a resampling algorithm
    9998             :  *
    9999             :  * @see GDALRasterBand::InterpolateAtPoint()
   10000             :  * @since GDAL 3.10
   10001             :  */
   10002             : 
   10003         130 : CPLErr GDALRasterInterpolateAtPoint(GDALRasterBandH hBand, double dfPixel,
   10004             :                                     double dfLine,
   10005             :                                     GDALRIOResampleAlg eInterpolation,
   10006             :                                     double *pdfRealValue, double *pdfImagValue)
   10007             : {
   10008         130 :     VALIDATE_POINTER1(hBand, "GDALRasterInterpolateAtPoint", CE_Failure);
   10009             : 
   10010         130 :     GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
   10011         130 :     return poBand->InterpolateAtPoint(dfPixel, dfLine, eInterpolation,
   10012         130 :                                       pdfRealValue, pdfImagValue);
   10013             : }
   10014             : 
   10015             : /************************************************************************/
   10016             : /*                    InterpolateAtGeolocation()                        */
   10017             : /************************************************************************/
   10018             : 
   10019             : /**
   10020             :  * \brief Interpolates the value between pixels using a resampling algorithm,
   10021             :  * taking georeferenced coordinates as input.
   10022             :  *
   10023             :  * When poSRS is null, those georeferenced coordinates (dfGeolocX, dfGeolocY)
   10024             :  * must be in the "natural" SRS of the dataset, that is the one returned by
   10025             :  * GetSpatialRef() if there is a geotransform, GetGCPSpatialRef() if there are
   10026             :  * GCPs, WGS 84 if there are RPC coefficients, or the SRS of the geolocation
   10027             :  * array (generally WGS 84) if there is a geolocation array.
   10028             :  * If that natural SRS is a geographic one, dfGeolocX must be a longitude, and
   10029             :  * dfGeolocY a latitude. If that natural SRS is a projected one, dfGeolocX must
   10030             :  * be a easting, and dfGeolocY a northing.
   10031             :  *
   10032             :  * When poSRS is set to a non-null value, (dfGeolocX, dfGeolocY) must be
   10033             :  * expressed in that CRS, and that tuple must be conformant with the
   10034             :  * data-axis-to-crs-axis setting of poSRS, that is the one returned by
   10035             :  * the OGRSpatialReference::GetDataAxisToSRSAxisMapping(). If you want to be sure
   10036             :  * of the axis order, then make sure to call poSRS->SetAxisMappingStrategy(OAMS_TRADITIONAL_GIS_ORDER)
   10037             :  * before calling this method, and in that case, dfGeolocX must be a longitude
   10038             :  * or an easting value, and dfGeolocX a latitude or a northing value.
   10039             :  *
   10040             :  * The GDALDataset::GeolocationToPixelLine() will be used to transform from
   10041             :  * (dfGeolocX,dfGeolocY) georeferenced coordinates to (pixel, line). Refer to
   10042             :  * it for details on how that transformation is done.
   10043             :  *
   10044             :  * @param dfGeolocX X coordinate of the position (longitude or easting if poSRS
   10045             :  * is null, otherwise consistent with poSRS data-axis-to-crs-axis mapping),
   10046             :  * where interpolation should be done.
   10047             :  * @param dfGeolocY Y coordinate of the position (latitude or northing if poSRS
   10048             :  * is null, otherwise consistent with poSRS data-axis-to-crs-axis mapping),
   10049             :  * where interpolation should be done.
   10050             :  * @param poSRS If set, override the natural CRS in which dfGeolocX, dfGeolocY are expressed
   10051             :  * @param eInterpolation interpolation type. Only near, bilinear, cubic and cubicspline are allowed.
   10052             :  * @param pdfRealValue pointer to real part of interpolated value
   10053             :  * @param pdfImagValue pointer to imaginary part of interpolated value (may be null if not needed)
   10054             :  * @param papszTransformerOptions Options accepted by GDALDataset::GeolocationToPixelLine() (GDALCreateGenImgProjTransformer2()), or nullptr.
   10055             :  *
   10056             :  * @return CE_None on success, or an error code on failure.
   10057             :  * @since GDAL 3.11
   10058             :  */
   10059             : 
   10060          15 : CPLErr GDALRasterBand::InterpolateAtGeolocation(
   10061             :     double dfGeolocX, double dfGeolocY, const OGRSpatialReference *poSRS,
   10062             :     GDALRIOResampleAlg eInterpolation, double *pdfRealValue,
   10063             :     double *pdfImagValue, CSLConstList papszTransformerOptions) const
   10064             : {
   10065             :     double dfPixel;
   10066             :     double dfLine;
   10067          15 :     if (poDS->GeolocationToPixelLine(dfGeolocX, dfGeolocY, poSRS, &dfPixel,
   10068             :                                      &dfLine,
   10069          15 :                                      papszTransformerOptions) != CE_None)
   10070             :     {
   10071           1 :         return CE_Failure;
   10072             :     }
   10073          14 :     return InterpolateAtPoint(dfPixel, dfLine, eInterpolation, pdfRealValue,
   10074          14 :                               pdfImagValue);
   10075             : }
   10076             : 
   10077             : /************************************************************************/
   10078             : /*                  GDALRasterInterpolateAtGeolocation()                */
   10079             : /************************************************************************/
   10080             : 
   10081             : /**
   10082             :  * \brief Interpolates the value between pixels using a resampling algorithm,
   10083             :  * taking georeferenced coordinates as input.
   10084             :  *
   10085             :  * @see GDALRasterBand::InterpolateAtGeolocation()
   10086             :  * @since GDAL 3.11
   10087             :  */
   10088             : 
   10089          15 : CPLErr GDALRasterInterpolateAtGeolocation(GDALRasterBandH hBand,
   10090             :                                           double dfGeolocX, double dfGeolocY,
   10091             :                                           OGRSpatialReferenceH hSRS,
   10092             :                                           GDALRIOResampleAlg eInterpolation,
   10093             :                                           double *pdfRealValue,
   10094             :                                           double *pdfImagValue,
   10095             :                                           CSLConstList papszTransformerOptions)
   10096             : {
   10097          15 :     VALIDATE_POINTER1(hBand, "GDALRasterInterpolateAtGeolocation", CE_Failure);
   10098             : 
   10099          15 :     GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
   10100          15 :     return poBand->InterpolateAtGeolocation(
   10101          15 :         dfGeolocX, dfGeolocY, OGRSpatialReference::FromHandle(hSRS),
   10102          15 :         eInterpolation, pdfRealValue, pdfImagValue, papszTransformerOptions);
   10103             : }

Generated by: LCOV version 1.14