LCOV - code coverage report
Current view: top level - gcore - gdalrasterband.cpp (source / functions) Hit Total Coverage
Test: gdal_filtered.info Lines: 2404 3089 77.8 %
Date: 2025-02-20 10:14:44 Functions: 219 244 89.8 %

          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     1065300 : GDALRasterBand::GDALRasterBand()
      51             :     : GDALRasterBand(
      52     1065300 :           CPLTestBool(CPLGetConfigOption("GDAL_FORCE_CACHING", "NO")))
      53             : {
      54     1065140 : }
      55             : 
      56             : /** Constructor. Applications should never create GDALRasterBands directly.
      57             :  * @param bForceCachedIOIn Whether cached IO should be forced.
      58             :  */
      59     1201220 : GDALRasterBand::GDALRasterBand(int bForceCachedIOIn)
      60     1201220 :     : bForceCachedIO(bForceCachedIOIn)
      61             : 
      62             : {
      63     1200960 : }
      64             : 
      65             : /************************************************************************/
      66             : /*                          ~GDALRasterBand()                           */
      67             : /************************************************************************/
      68             : 
      69             : /*! Destructor. Applications should never destroy GDALRasterBands directly,
      70             :     instead destroy the GDALDataset. */
      71             : 
      72     1201190 : GDALRasterBand::~GDALRasterBand()
      73             : 
      74             : {
      75     1201220 :     if (poDS && poDS->IsMarkedSuppressOnClose())
      76             :     {
      77         433 :         if (poBandBlockCache)
      78         384 :             poBandBlockCache->DisableDirtyBlockWriting();
      79             :     }
      80     1201220 :     GDALRasterBand::FlushCache(true);
      81             : 
      82     1201210 :     delete poBandBlockCache;
      83             : 
      84     1201220 :     if (static_cast<GIntBig>(nBlockReads) >
      85     1201220 :             static_cast<GIntBig>(nBlocksPerRow) * nBlocksPerColumn &&
      86         214 :         nBand == 1 && poDS != nullptr)
      87             :     {
      88         302 :         CPLDebug(
      89             :             "GDAL", "%d block reads on " CPL_FRMT_GIB " block band 1 of %s.",
      90         151 :             nBlockReads, static_cast<GIntBig>(nBlocksPerRow) * nBlocksPerColumn,
      91         151 :             poDS->GetDescription());
      92             :     }
      93             : 
      94     1201220 :     InvalidateMaskBand();
      95     1201190 :     nBand = -nBand;
      96             : 
      97     1201190 :     delete m_poPointsCache;
      98     1201200 : }
      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     3752100 : 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     3752100 :     if (psExtraArg == nullptr)
     331             :     {
     332     3668390 :         INIT_RASTERIO_EXTRA_ARG(sExtraArg);
     333     3668390 :         psExtraArg = &sExtraArg;
     334             :     }
     335       83717 :     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     3752100 :     GDALRasterIOExtraArgSetResampleAlg(psExtraArg, nXSize, nYSize, nBufXSize,
     344             :                                        nBufYSize);
     345             : 
     346     3751880 :     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     3751880 :     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     3751880 :     if (eRWFlag == GF_Write)
     370             :     {
     371      213378 :         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      213378 :         if (CPL_UNLIKELY(eAccess != GA_Update))
     381             :         {
     382           3 :             ReportError(CE_Failure, CPLE_AppDefined,
     383             :                         "Write operation not permitted on dataset opened "
     384             :                         "in read-only mode");
     385           3 :             return CE_Failure;
     386             :         }
     387             :     }
     388             : 
     389             :     /* -------------------------------------------------------------------- */
     390             :     /*      If pixel and line spacing are defaulted assign reasonable      */
     391             :     /*      value assuming a packed buffer.                                 */
     392             :     /* -------------------------------------------------------------------- */
     393     3751880 :     if (nPixelSpace == 0)
     394             :     {
     395     3662010 :         nPixelSpace = GDALGetDataTypeSizeBytes(eBufType);
     396             :     }
     397             : 
     398     3751690 :     if (nLineSpace == 0)
     399             :     {
     400     3656320 :         nLineSpace = nPixelSpace * nBufXSize;
     401             :     }
     402             : 
     403             :     /* -------------------------------------------------------------------- */
     404             :     /*      Do some validation of parameters.                               */
     405             :     /* -------------------------------------------------------------------- */
     406     3751690 :     if (CPL_UNLIKELY(nXOff < 0 || nXOff > INT_MAX - nXSize ||
     407             :                      nXOff + nXSize > nRasterXSize || nYOff < 0 ||
     408             :                      nYOff > INT_MAX - nYSize || nYOff + nYSize > nRasterYSize))
     409             :     {
     410          14 :         ReportError(CE_Failure, CPLE_IllegalArg,
     411             :                     "Access window out of range in RasterIO().  Requested\n"
     412             :                     "(%d,%d) of size %dx%d on raster of %dx%d.",
     413             :                     nXOff, nYOff, nXSize, nYSize, nRasterXSize, nRasterYSize);
     414          14 :         return CE_Failure;
     415             :     }
     416             : 
     417     3751670 :     if (CPL_UNLIKELY(eRWFlag != GF_Read && eRWFlag != GF_Write))
     418             :     {
     419           0 :         ReportError(
     420             :             CE_Failure, CPLE_IllegalArg,
     421             :             "eRWFlag = %d, only GF_Read (0) and GF_Write (1) are legal.",
     422             :             eRWFlag);
     423           0 :         return CE_Failure;
     424             :     }
     425     3751670 :     if (CPL_UNLIKELY(eBufType == GDT_Unknown || eBufType == GDT_TypeCount))
     426             :     {
     427           2 :         ReportError(CE_Failure, CPLE_IllegalArg,
     428             :                     "Illegal GDT_Unknown/GDT_TypeCount argument");
     429           2 :         return CE_Failure;
     430             :     }
     431             : 
     432             :     /* -------------------------------------------------------------------- */
     433             :     /*      Call the format specific function.                              */
     434             :     /* -------------------------------------------------------------------- */
     435             : 
     436     3751670 :     const bool bCallLeaveReadWrite = CPL_TO_BOOL(EnterReadWrite(eRWFlag));
     437             : 
     438             :     CPLErr eErr;
     439     3747480 :     if (bForceCachedIO)
     440          23 :         eErr = GDALRasterBand::IRasterIO(eRWFlag, nXOff, nYOff, nXSize, nYSize,
     441             :                                          pData, nBufXSize, nBufYSize, eBufType,
     442             :                                          nPixelSpace, nLineSpace, psExtraArg);
     443             :     else
     444             :         eErr =
     445     3748390 :             IRasterIO(eRWFlag, nXOff, nYOff, nXSize, nYSize, pData, nBufXSize,
     446     3747460 :                       nBufYSize, eBufType, nPixelSpace, nLineSpace, psExtraArg);
     447             : 
     448     3748410 :     if (bCallLeaveReadWrite)
     449      220768 :         LeaveReadWrite();
     450             : 
     451     3745270 :     return eErr;
     452             : }
     453             : 
     454             : /************************************************************************/
     455             : /*                            GDALRasterIO()                            */
     456             : /************************************************************************/
     457             : 
     458             : /**
     459             :  * \brief Read/write a region of image data for this band.
     460             :  *
     461             :  * Use GDALRasterIOEx() if 64 bit spacings or extra arguments (resampling
     462             :  * resolution, progress callback, etc. are needed)
     463             :  *
     464             :  * @see GDALRasterBand::RasterIO()
     465             :  */
     466             : 
     467     3445180 : CPLErr CPL_STDCALL GDALRasterIO(GDALRasterBandH hBand, GDALRWFlag eRWFlag,
     468             :                                 int nXOff, int nYOff, int nXSize, int nYSize,
     469             :                                 void *pData, int nBufXSize, int nBufYSize,
     470             :                                 GDALDataType eBufType, int nPixelSpace,
     471             :                                 int nLineSpace)
     472             : 
     473             : {
     474     3445180 :     VALIDATE_POINTER1(hBand, "GDALRasterIO", CE_Failure);
     475             : 
     476     3445180 :     GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
     477             : 
     478     3444160 :     return (poBand->RasterIO(eRWFlag, nXOff, nYOff, nXSize, nYSize, pData,
     479             :                              nBufXSize, nBufYSize, eBufType, nPixelSpace,
     480     3437100 :                              nLineSpace, nullptr));
     481             : }
     482             : 
     483             : /************************************************************************/
     484             : /*                            GDALRasterIOEx()                          */
     485             : /************************************************************************/
     486             : 
     487             : /**
     488             :  * \brief Read/write a region of image data for this band.
     489             :  *
     490             :  * @see GDALRasterBand::RasterIO()
     491             :  * @since GDAL 2.0
     492             :  */
     493             : 
     494       35159 : CPLErr CPL_STDCALL GDALRasterIOEx(GDALRasterBandH hBand, GDALRWFlag eRWFlag,
     495             :                                   int nXOff, int nYOff, int nXSize, int nYSize,
     496             :                                   void *pData, int nBufXSize, int nBufYSize,
     497             :                                   GDALDataType eBufType, GSpacing nPixelSpace,
     498             :                                   GSpacing nLineSpace,
     499             :                                   GDALRasterIOExtraArg *psExtraArg)
     500             : 
     501             : {
     502       35159 :     VALIDATE_POINTER1(hBand, "GDALRasterIOEx", CE_Failure);
     503             : 
     504       35159 :     GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
     505             : 
     506       35159 :     return (poBand->RasterIO(eRWFlag, nXOff, nYOff, nXSize, nYSize, pData,
     507             :                              nBufXSize, nBufYSize, eBufType, nPixelSpace,
     508       35158 :                              nLineSpace, psExtraArg));
     509             : }
     510             : 
     511             : /************************************************************************/
     512             : /*                           GetGDTFromCppType()                        */
     513             : /************************************************************************/
     514             : 
     515             : namespace
     516             : {
     517             : template <class T> struct GetGDTFromCppType;
     518             : 
     519             : #define DEFINE_GetGDTFromCppType(T, eDT)                                       \
     520             :     template <> struct GetGDTFromCppType<T>                                    \
     521             :     {                                                                          \
     522             :         static constexpr GDALDataType GDT = eDT;                               \
     523             :     }
     524             : 
     525             : DEFINE_GetGDTFromCppType(uint8_t, GDT_Byte);
     526             : DEFINE_GetGDTFromCppType(int8_t, GDT_Int8);
     527             : DEFINE_GetGDTFromCppType(uint16_t, GDT_UInt16);
     528             : DEFINE_GetGDTFromCppType(int16_t, GDT_Int16);
     529             : DEFINE_GetGDTFromCppType(uint32_t, GDT_UInt32);
     530             : DEFINE_GetGDTFromCppType(int32_t, GDT_Int32);
     531             : DEFINE_GetGDTFromCppType(uint64_t, GDT_UInt64);
     532             : DEFINE_GetGDTFromCppType(int64_t, GDT_Int64);
     533             : DEFINE_GetGDTFromCppType(float, GDT_Float32);
     534             : DEFINE_GetGDTFromCppType(double, GDT_Float64);
     535             : // Not allowed by C++ standard
     536             : //DEFINE_GetGDTFromCppType(std::complex<int16_t>, GDT_CInt16);
     537             : //DEFINE_GetGDTFromCppType(std::complex<int32_t>, GDT_CInt32);
     538             : DEFINE_GetGDTFromCppType(std::complex<float>, GDT_CFloat32);
     539             : DEFINE_GetGDTFromCppType(std::complex<double>, GDT_CFloat64);
     540             : }  // namespace
     541             : 
     542             : /************************************************************************/
     543             : /*                           ReadRaster()                               */
     544             : /************************************************************************/
     545             : 
     546             : // clang-format off
     547             : /** Read a region of image data for this band.
     548             :  *
     549             :  * This is a slightly more convenient alternative to GDALRasterBand::RasterIO()
     550             :  * for common use cases, like reading a whole band.
     551             :  * It infers the GDAL data type of the buffer from the C/C++ type of the buffer.
     552             :  * This template is instantiated for the following types: [u?]int[8|16|32|64]_t,
     553             :  * float, double, std::complex<float|double>.
     554             :  *
     555             :  * 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>&,
     556             :  * and can allocate memory automatically.
     557             :  *
     558             :  * To read a whole band (assuming it fits into memory), as an array of double:
     559             :  *
     560             : \code{.cpp}
     561             :  double* myArray = static_cast<double*>(
     562             :      VSI_MALLOC3_VERBOSE(sizeof(double), poBand->GetXSize(), poBand->GetYSize()));
     563             :  // TODO: check here that myArray != nullptr
     564             :  const size_t nArrayEltCount =
     565             :      static_cast<size_t>(poBand->GetXSize()) * poBand->GetYSize());
     566             :  if (poBand->ReadRaster(myArray, nArrayEltCount) == CE_None)
     567             :  {
     568             :      // do something
     569             :  }
     570             :  VSIFree(myArray)
     571             : \endcode
     572             :  *
     573             :  * To read 128x128 pixels starting at (col=12, line=24) as an array of double:
     574             :  *
     575             : \code{.cpp}
     576             :  double* myArray = static_cast<double*>(
     577             :      VSI_MALLOC3_VERBOSE(sizeof(double), 128, 128));
     578             :  // TODO: check here that myArray != nullptr
     579             :  const size_t nArrayEltCount = 128 * 128;
     580             :  if (poBand->ReadRaster(myArray, nArrayEltCount, 12, 24, 128, 128) == CE_None)
     581             :  {
     582             :      // do something
     583             :  }
     584             :  VSIFree(myArray)
     585             : \endcode
     586             :  *
     587             :  * As nearly all GDAL methods, this method is *NOT* thread-safe, that is it cannot
     588             :  * be called on the same GDALRasterBand instance (or another GDALRasterBand
     589             :  * instance of this dataset) concurrently from several threads.
     590             :  *
     591             :  * The window of interest expressed by (dfXOff, dfYOff, dfXSize, dfYSize) should be
     592             :  * fully within the raster space, that is dfXOff >= 0, dfYOff >= 0,
     593             :  * dfXOff + dfXSize <= GetXSize() and dfYOff + dfYSize <= GetYSize().
     594             :  * If reads larger than the raster space are wished, GDALTranslate() might be used.
     595             :  * Or use nLineSpace and a possibly shifted pData value.
     596             :  *
     597             :  * @param[out] pData The buffer into which the data should be written.
     598             :  * This buffer must contain at least nBufXSize *
     599             :  * nBufYSize words of type T. It is organized in left to right,
     600             :  * top to bottom pixel order, and fully packed.
     601             :  * The type of the buffer does not need to be the one of GetDataType(). The
     602             :  * method will perform data type translation (with potential rounding, clamping)
     603             :  * if needed.
     604             :  *
     605             :  * @param nArrayEltCount Number of values of pData. If non zero, the method will
     606             :  * check that it is at least greater or equal to nBufXSize * nBufYSize, and
     607             :  * return in error if it is not. If set to zero, then pData is trusted to be
     608             :  * large enough.
     609             :  *
     610             :  * @param dfXOff The pixel offset to the top left corner of the region
     611             :  * of the band to be accessed. This would be zero to start from the left side.
     612             :  * Defaults to 0.
     613             :  *
     614             :  * @param dfYOff The line offset to the top left corner of the region
     615             :  * of the band to be accessed. This would be zero to start from the top.
     616             :  * Defaults to 0.
     617             :  *
     618             :  * @param dfXSize The width of the region of the band to be accessed in pixels.
     619             :  * If all of dfXOff, dfYOff, dfXSize and dfYSize are left to their zero default value,
     620             :  * dfXSize is set to the band width.
     621             :  *
     622             :  * @param dfYSize The height of the region of the band to be accessed in lines.
     623             :  * If all of dfXOff, dfYOff, dfXSize and dfYSize are left to their zero default value,
     624             :  * dfYSize is set to the band height.
     625             :  *
     626             :  * @param nBufXSize the width of the buffer image into which the desired region
     627             :  * is to be read. If set to zero, and both dfXSize and dfYSize are integer values,
     628             :  * then nBufXSize is initialized with dfXSize.
     629             :  *
     630             :  * @param nBufYSize the height of the buffer image into which the desired region
     631             :  * is to be read. If set to zero, and both dfXSize and dfYSize are integer values,
     632             :  * then nBufYSize is initialized with dfYSize.
     633             :  *
     634             :  * @param eResampleAlg Resampling algorithm. Defaults to GRIORA_NearestNeighbour.
     635             :  *
     636             :  * @param pfnProgress Progress function. May be nullptr.
     637             :  *
     638             :  * @param pProgressData User data of pfnProgress. May be nullptr.
     639             :  *
     640             :  * @return CE_Failure if the access fails, otherwise CE_None.
     641             :  *
     642             :  * @see GDALRasterBand::RasterIO()
     643             :  * @since GDAL 3.10
     644             :  */
     645             : // clang-format on
     646             : 
     647             : template <class T>
     648          19 : CPLErr GDALRasterBand::ReadRaster(T *pData, size_t nArrayEltCount,
     649             :                                   double dfXOff, double dfYOff, double dfXSize,
     650             :                                   double dfYSize, size_t nBufXSize,
     651             :                                   size_t nBufYSize,
     652             :                                   GDALRIOResampleAlg eResampleAlg,
     653             :                                   GDALProgressFunc pfnProgress,
     654             :                                   void *pProgressData) const
     655             : {
     656          19 :     if (((nBufXSize | nBufYSize) >> 31) != 0)
     657             :     {
     658           2 :         return CE_Failure;
     659             :     }
     660             : 
     661          17 :     if (dfXOff == 0 && dfYOff == 0 && dfXSize == 0 && dfYSize == 0)
     662             :     {
     663          15 :         dfXSize = nRasterXSize;
     664          15 :         dfYSize = nRasterYSize;
     665             :     }
     666           2 :     else if (!(dfXOff >= 0 && dfXOff <= INT_MAX) ||
     667           2 :              !(dfYOff >= 0 && dfYOff <= INT_MAX) || !(dfXSize >= 0) ||
     668           2 :              !(dfYSize >= 0) || dfXOff + dfXSize > INT_MAX ||
     669           2 :              dfYOff + dfYSize > INT_MAX)
     670             :     {
     671           0 :         return CE_Failure;
     672             :     }
     673             : 
     674             :     GDALRasterIOExtraArg sExtraArg;
     675          17 :     sExtraArg.nVersion = 1;
     676          17 :     sExtraArg.eResampleAlg = eResampleAlg;
     677          17 :     sExtraArg.pfnProgress = pfnProgress;
     678          17 :     sExtraArg.pProgressData = pProgressData;
     679          17 :     sExtraArg.bFloatingPointWindowValidity = true;
     680          17 :     sExtraArg.dfXOff = dfXOff;
     681          17 :     sExtraArg.dfYOff = dfYOff;
     682          17 :     sExtraArg.dfXSize = dfXSize;
     683          17 :     sExtraArg.dfYSize = dfYSize;
     684          17 :     const int nXOff = static_cast<int>(dfXOff);
     685          17 :     const int nYOff = static_cast<int>(dfYOff);
     686          17 :     const int nXSize = std::max(1, static_cast<int>(dfXSize + 0.5));
     687          17 :     const int nYSize = std::max(1, static_cast<int>(dfYSize + 0.5));
     688          17 :     if (nBufXSize == 0 && nBufYSize == 0)
     689             :     {
     690          16 :         if (static_cast<int>(dfXSize) == dfXSize &&
     691          16 :             static_cast<int>(dfYSize) == dfYSize)
     692             :         {
     693          16 :             nBufXSize = static_cast<int>(dfXSize);
     694          16 :             nBufYSize = static_cast<int>(dfYSize);
     695             :         }
     696             :         else
     697             :         {
     698           0 :             CPLError(CE_Failure, CPLE_AppDefined,
     699             :                      "nBufXSize and nBufYSize must be provided if dfXSize or "
     700             :                      "dfYSize is not an integer value");
     701           0 :             return CE_Failure;
     702             :         }
     703             :     }
     704          17 :     if (nBufXSize == 0 || nBufYSize == 0)
     705             :     {
     706           0 :         CPLDebug("GDAL",
     707             :                  "RasterIO() skipped for odd window or buffer size.\n"
     708             :                  "  Window = (%d,%d)x%dx%d\n"
     709             :                  "  Buffer = %dx%d\n",
     710             :                  nXOff, nYOff, nXSize, nYSize, static_cast<int>(nBufXSize),
     711             :                  static_cast<int>(nBufYSize));
     712             : 
     713           0 :         return CE_None;
     714             :     }
     715             : 
     716          17 :     if (nArrayEltCount > 0 && nBufXSize > nArrayEltCount / nBufYSize)
     717             :     {
     718           1 :         CPLError(CE_Failure, CPLE_AppDefined,
     719             :                  "Provided array is not large enough");
     720           1 :         return CE_Failure;
     721             :     }
     722             : 
     723          16 :     constexpr GSpacing nPixelSpace = sizeof(T);
     724          16 :     const GSpacing nLineSpace = nPixelSpace * nBufXSize;
     725          16 :     constexpr GDALDataType eBufType = GetGDTFromCppType<T>::GDT;
     726             : 
     727          16 :     GDALRasterBand *pThis = const_cast<GDALRasterBand *>(this);
     728             : 
     729             :     const bool bCallLeaveReadWrite =
     730          16 :         CPL_TO_BOOL(pThis->EnterReadWrite(GF_Read));
     731             :     CPLErr eErr;
     732             :     // coverity[identical_branches]
     733          16 :     if (bForceCachedIO)
     734           0 :         eErr = pThis->GDALRasterBand::IRasterIO(
     735             :             GF_Read, nXOff, nYOff, nXSize, nYSize, pData,
     736             :             static_cast<int>(nBufXSize), static_cast<int>(nBufYSize), eBufType,
     737             :             nPixelSpace, nLineSpace, &sExtraArg);
     738             :     else
     739          16 :         eErr = pThis->IRasterIO(GF_Read, nXOff, nYOff, nXSize, nYSize, pData,
     740             :                                 static_cast<int>(nBufXSize),
     741             :                                 static_cast<int>(nBufYSize), eBufType,
     742             :                                 nPixelSpace, nLineSpace, &sExtraArg);
     743             : 
     744          16 :     if (bCallLeaveReadWrite)
     745           0 :         pThis->LeaveReadWrite();
     746             : 
     747          16 :     return eErr;
     748             : }
     749             : 
     750             : //! @cond Doxygen_Suppress
     751             : 
     752             : #define INSTANTIATE_READ_RASTER(T)                                             \
     753             :     template CPLErr CPL_DLL GDALRasterBand::ReadRaster(                        \
     754             :         T *vData, size_t nArrayEltCount, double dfXOff, double dfYOff,         \
     755             :         double dfXSize, double dfYSize, size_t nBufXSize, size_t nBufYSize,    \
     756             :         GDALRIOResampleAlg eResampleAlg, GDALProgressFunc pfnProgress,         \
     757             :         void *pProgressData) const;
     758             : 
     759             : INSTANTIATE_READ_RASTER(uint8_t)
     760             : INSTANTIATE_READ_RASTER(int8_t)
     761             : INSTANTIATE_READ_RASTER(uint16_t)
     762             : INSTANTIATE_READ_RASTER(int16_t)
     763             : INSTANTIATE_READ_RASTER(uint32_t)
     764             : INSTANTIATE_READ_RASTER(int32_t)
     765             : INSTANTIATE_READ_RASTER(uint64_t)
     766             : INSTANTIATE_READ_RASTER(int64_t)
     767             : INSTANTIATE_READ_RASTER(float)
     768             : INSTANTIATE_READ_RASTER(double)
     769             : // Not allowed by C++ standard
     770             : // INSTANTIATE_READ_RASTER(std::complex<int16_t>)
     771             : // INSTANTIATE_READ_RASTER(std::complex<int32_t>)
     772             : INSTANTIATE_READ_RASTER(std::complex<float>)
     773             : INSTANTIATE_READ_RASTER(std::complex<double>)
     774             : 
     775             : //! @endcond
     776             : 
     777             : /************************************************************************/
     778             : /*                           ReadRaster()                               */
     779             : /************************************************************************/
     780             : 
     781             : /** Read a region of image data for this band.
     782             :  *
     783             :  * This is a slightly more convenient alternative to GDALRasterBand::RasterIO()
     784             :  * for common use cases, like reading a whole band.
     785             :  * It infers the GDAL data type of the buffer from the C/C++ type of the buffer.
     786             :  * This template is instantiated for the following types: [u?]int[8|16|32|64]_t,
     787             :  * float, double, std::complex<float|double>.
     788             :  *
     789             :  * To read a whole band (assuming it fits into memory), as a vector of double:
     790             :  *
     791             : \code
     792             :  std::vector<double> myArray;
     793             :  if (poBand->ReadRaster(myArray) == CE_None)
     794             :  {
     795             :      // do something
     796             :  }
     797             : \endcode
     798             :  *
     799             :  * To read 128x128 pixels starting at (col=12, line=24) as a vector of double:
     800             :  *
     801             : \code{.cpp}
     802             :  std::vector<double> myArray;
     803             :  if (poBand->ReadRaster(myArray, 12, 24, 128, 128) == CE_None)
     804             :  {
     805             :      // do something
     806             :  }
     807             : \endcode
     808             :  *
     809             :  * As nearly all GDAL methods, this method is *NOT* thread-safe, that is it cannot
     810             :  * be called on the same GDALRasterBand instance (or another GDALRasterBand
     811             :  * instance of this dataset) concurrently from several threads.
     812             :  *
     813             :  * The window of interest expressed by (dfXOff, dfYOff, dfXSize, dfYSize) should be
     814             :  * fully within the raster space, that is dfXOff >= 0, dfYOff >= 0,
     815             :  * dfXOff + dfXSize <= GetXSize() and dfYOff + dfYSize <= GetYSize().
     816             :  * If reads larger than the raster space are wished, GDALTranslate() might be used.
     817             :  * Or use nLineSpace and a possibly shifted pData value.
     818             :  *
     819             :  * @param[out] vData The vector into which the data should be written.
     820             :  * The vector will be resized, if needed, to contain at least nBufXSize *
     821             :  * nBufYSize values. The values in the vector are organized in left to right,
     822             :  * top to bottom pixel order, and fully packed.
     823             :  * The type of the vector does not need to be the one of GetDataType(). The
     824             :  * method will perform data type translation (with potential rounding, clamping)
     825             :  * if needed.
     826             :  *
     827             :  * @param dfXOff The pixel offset to the top left corner of the region
     828             :  * of the band to be accessed. This would be zero to start from the left side.
     829             :  * Defaults to 0.
     830             :  *
     831             :  * @param dfYOff The line offset to the top left corner of the region
     832             :  * of the band to be accessed. This would be zero to start from the top.
     833             :  * Defaults to 0.
     834             :  *
     835             :  * @param dfXSize The width of the region of the band to be accessed in pixels.
     836             :  * If all of dfXOff, dfYOff, dfXSize and dfYSize are left to their zero default value,
     837             :  * dfXSize is set to the band width.
     838             :  *
     839             :  * @param dfYSize The height of the region of the band to be accessed in lines.
     840             :  * If all of dfXOff, dfYOff, dfXSize and dfYSize are left to their zero default value,
     841             :  * dfYSize is set to the band height.
     842             :  *
     843             :  * @param nBufXSize the width of the buffer image into which the desired region
     844             :  * is to be read. If set to zero, and both dfXSize and dfYSize are integer values,
     845             :  * then nBufXSize is initialized with dfXSize.
     846             :  *
     847             :  * @param nBufYSize the height of the buffer image into which the desired region
     848             :  * is to be read. If set to zero, and both dfXSize and dfYSize are integer values,
     849             :  * then nBufYSize is initialized with dfYSize.
     850             :  *
     851             :  * @param eResampleAlg Resampling algorithm. Defaults to GRIORA_NearestNeighbour.
     852             :  *
     853             :  * @param pfnProgress Progress function. May be nullptr.
     854             :  *
     855             :  * @param pProgressData User data of pfnProgress. May be nullptr.
     856             :  *
     857             :  * @return CE_Failure if the access fails, otherwise CE_None.
     858             :  *
     859             :  * @see GDALRasterBand::RasterIO()
     860             :  * @since GDAL 3.10
     861             :  */
     862             : template <class T>
     863          21 : CPLErr GDALRasterBand::ReadRaster(std::vector<T> &vData, double dfXOff,
     864             :                                   double dfYOff, double dfXSize, double dfYSize,
     865             :                                   size_t nBufXSize, size_t nBufYSize,
     866             :                                   GDALRIOResampleAlg eResampleAlg,
     867             :                                   GDALProgressFunc pfnProgress,
     868             :                                   void *pProgressData) const
     869             : {
     870          21 :     if (((nBufXSize | nBufYSize) >> 31) != 0)
     871             :     {
     872           2 :         return CE_Failure;
     873             :     }
     874             : 
     875          19 :     if (dfXOff == 0 && dfYOff == 0 && dfXSize == 0 && dfYSize == 0)
     876             :     {
     877          12 :         dfXSize = nRasterXSize;
     878          12 :         dfYSize = nRasterYSize;
     879             :     }
     880           7 :     else if (!(dfXOff >= 0 && dfXOff <= INT_MAX) ||
     881           7 :              !(dfYOff >= 0 && dfYOff <= INT_MAX) || !(dfXSize >= 0) ||
     882           7 :              !(dfYSize >= 0) || dfXOff + dfXSize > INT_MAX ||
     883           7 :              dfYOff + dfYSize > INT_MAX)
     884             :     {
     885           0 :         return CE_Failure;
     886             :     }
     887             : 
     888             :     GDALRasterIOExtraArg sExtraArg;
     889          19 :     sExtraArg.nVersion = 1;
     890          19 :     sExtraArg.eResampleAlg = eResampleAlg;
     891          19 :     sExtraArg.pfnProgress = pfnProgress;
     892          19 :     sExtraArg.pProgressData = pProgressData;
     893          19 :     sExtraArg.bFloatingPointWindowValidity = true;
     894          19 :     sExtraArg.dfXOff = dfXOff;
     895          19 :     sExtraArg.dfYOff = dfYOff;
     896          19 :     sExtraArg.dfXSize = dfXSize;
     897          19 :     sExtraArg.dfYSize = dfYSize;
     898          19 :     const int nXOff = static_cast<int>(dfXOff);
     899          19 :     const int nYOff = static_cast<int>(dfYOff);
     900          19 :     const int nXSize = std::max(1, static_cast<int>(dfXSize + 0.5));
     901          19 :     const int nYSize = std::max(1, static_cast<int>(dfYSize + 0.5));
     902          19 :     if (nBufXSize == 0 && nBufYSize == 0)
     903             :     {
     904          15 :         if (static_cast<int>(dfXSize) == dfXSize &&
     905          14 :             static_cast<int>(dfYSize) == dfYSize)
     906             :         {
     907          14 :             nBufXSize = static_cast<int>(dfXSize);
     908          14 :             nBufYSize = static_cast<int>(dfYSize);
     909             :         }
     910             :         else
     911             :         {
     912           1 :             CPLError(CE_Failure, CPLE_AppDefined,
     913             :                      "nBufXSize and nBufYSize must be provided if "
     914             :                      "dfXSize or dfYSize is not an integer value");
     915           1 :             return CE_Failure;
     916             :         }
     917             :     }
     918          18 :     if (nBufXSize == 0 || nBufYSize == 0)
     919             :     {
     920           0 :         CPLDebug("GDAL",
     921             :                  "RasterIO() skipped for odd window or buffer size.\n"
     922             :                  "  Window = (%d,%d)x%dx%d\n"
     923             :                  "  Buffer = %dx%d\n",
     924             :                  nXOff, nYOff, nXSize, nYSize, static_cast<int>(nBufXSize),
     925             :                  static_cast<int>(nBufYSize));
     926             : 
     927           0 :         return CE_None;
     928             :     }
     929             : 
     930             :     if constexpr (SIZEOF_VOIDP < 8)
     931             :     {
     932             :         if (nBufXSize > std::numeric_limits<size_t>::max() / nBufYSize)
     933             :         {
     934             :             CPLError(CE_Failure, CPLE_OutOfMemory, "Too large buffer");
     935             :             return CE_Failure;
     936             :         }
     937             :     }
     938             : 
     939          18 :     if (vData.size() < nBufXSize * nBufYSize)
     940             :     {
     941             :         try
     942             :         {
     943          16 :             vData.resize(nBufXSize * nBufYSize);
     944             :         }
     945           1 :         catch (const std::exception &)
     946             :         {
     947           1 :             CPLError(CE_Failure, CPLE_OutOfMemory, "Cannot resize array");
     948           1 :             return CE_Failure;
     949             :         }
     950             :     }
     951             : 
     952          17 :     constexpr GSpacing nPixelSpace = sizeof(T);
     953          17 :     const GSpacing nLineSpace = nPixelSpace * nBufXSize;
     954          17 :     constexpr GDALDataType eBufType = GetGDTFromCppType<T>::GDT;
     955             : 
     956          17 :     GDALRasterBand *pThis = const_cast<GDALRasterBand *>(this);
     957             : 
     958             :     const bool bCallLeaveReadWrite =
     959          17 :         CPL_TO_BOOL(pThis->EnterReadWrite(GF_Read));
     960             : 
     961             :     CPLErr eErr;
     962             :     // coverity[identical_branches]
     963          17 :     if (bForceCachedIO)
     964           0 :         eErr = pThis->GDALRasterBand::IRasterIO(
     965             :             GF_Read, nXOff, nYOff, nXSize, nYSize, vData.data(),
     966             :             static_cast<int>(nBufXSize), static_cast<int>(nBufYSize), eBufType,
     967             :             nPixelSpace, nLineSpace, &sExtraArg);
     968             :     else
     969          17 :         eErr = pThis->IRasterIO(GF_Read, nXOff, nYOff, nXSize, nYSize,
     970             :                                 vData.data(), static_cast<int>(nBufXSize),
     971             :                                 static_cast<int>(nBufYSize), eBufType,
     972             :                                 nPixelSpace, nLineSpace, &sExtraArg);
     973             : 
     974          17 :     if (bCallLeaveReadWrite)
     975           0 :         pThis->LeaveReadWrite();
     976             : 
     977          17 :     return eErr;
     978             : }
     979             : 
     980             : //! @cond Doxygen_Suppress
     981             : 
     982             : #define INSTANTIATE_READ_RASTER_VECTOR(T)                                      \
     983             :     template CPLErr CPL_DLL GDALRasterBand::ReadRaster(                        \
     984             :         std::vector<T> &vData, double dfXOff, double dfYOff, double dfXSize,   \
     985             :         double dfYSize, size_t nBufXSize, size_t nBufYSize,                    \
     986             :         GDALRIOResampleAlg eResampleAlg, GDALProgressFunc pfnProgress,         \
     987             :         void *pProgressData) const;
     988             : 
     989             : INSTANTIATE_READ_RASTER_VECTOR(uint8_t)
     990             : INSTANTIATE_READ_RASTER_VECTOR(int8_t)
     991             : INSTANTIATE_READ_RASTER_VECTOR(uint16_t)
     992             : INSTANTIATE_READ_RASTER_VECTOR(int16_t)
     993             : INSTANTIATE_READ_RASTER_VECTOR(uint32_t)
     994             : INSTANTIATE_READ_RASTER_VECTOR(int32_t)
     995             : INSTANTIATE_READ_RASTER_VECTOR(uint64_t)
     996             : INSTANTIATE_READ_RASTER_VECTOR(int64_t)
     997             : INSTANTIATE_READ_RASTER_VECTOR(float)
     998             : INSTANTIATE_READ_RASTER_VECTOR(double)
     999             : // Not allowed by C++ standard
    1000             : // INSTANTIATE_READ_RASTER_VECTOR(std::complex<int16_t>)
    1001             : // INSTANTIATE_READ_RASTER_VECTOR(std::complex<int32_t>)
    1002             : INSTANTIATE_READ_RASTER_VECTOR(std::complex<float>)
    1003             : INSTANTIATE_READ_RASTER_VECTOR(std::complex<double>)
    1004             : 
    1005             : //! @endcond
    1006             : 
    1007             : /************************************************************************/
    1008             : /*                             ReadBlock()                              */
    1009             : /************************************************************************/
    1010             : 
    1011             : /**
    1012             :  * \brief Read a block of image data efficiently.
    1013             :  *
    1014             :  * This method accesses a "natural" block from the raster band without
    1015             :  * resampling, or data type conversion.  For a more generalized, but
    1016             :  * potentially less efficient access use RasterIO().
    1017             :  *
    1018             :  * This method is the same as the C GDALReadBlock() function.
    1019             :  *
    1020             :  * See the GetLockedBlockRef() method for a way of accessing internally cached
    1021             :  * block oriented data without an extra copy into an application buffer.
    1022             :  *
    1023             :  * The following code would efficiently compute a histogram of eight bit
    1024             :  * raster data.  Note that the final block may be partial ... data beyond
    1025             :  * the edge of the underlying raster band in these edge blocks is of an
    1026             :  * undetermined value.
    1027             :  *
    1028             : \code{.cpp}
    1029             :  CPLErr GetHistogram( GDALRasterBand *poBand, GUIntBig *panHistogram )
    1030             : 
    1031             :  {
    1032             :      memset( panHistogram, 0, sizeof(GUIntBig) * 256 );
    1033             : 
    1034             :      CPLAssert( poBand->GetRasterDataType() == GDT_Byte );
    1035             : 
    1036             :      int nXBlockSize, nYBlockSize;
    1037             : 
    1038             :      poBand->GetBlockSize( &nXBlockSize, &nYBlockSize );
    1039             :      int nXBlocks = (poBand->GetXSize() + nXBlockSize - 1) / nXBlockSize;
    1040             :      int nYBlocks = (poBand->GetYSize() + nYBlockSize - 1) / nYBlockSize;
    1041             : 
    1042             :      GByte *pabyData = (GByte *) CPLMalloc(nXBlockSize * nYBlockSize);
    1043             : 
    1044             :      for( int iYBlock = 0; iYBlock < nYBlocks; iYBlock++ )
    1045             :      {
    1046             :          for( int iXBlock = 0; iXBlock < nXBlocks; iXBlock++ )
    1047             :          {
    1048             :              int        nXValid, nYValid;
    1049             : 
    1050             :              poBand->ReadBlock( iXBlock, iYBlock, pabyData );
    1051             : 
    1052             :              // Compute the portion of the block that is valid
    1053             :              // for partial edge blocks.
    1054             :              poBand->GetActualBlockSize(iXBlock, iYBlock, &nXValid, &nYValid)
    1055             : 
    1056             :              // Collect the histogram counts.
    1057             :              for( int iY = 0; iY < nYValid; iY++ )
    1058             :              {
    1059             :                  for( int iX = 0; iX < nXValid; iX++ )
    1060             :                  {
    1061             :                      panHistogram[pabyData[iX + iY * nXBlockSize]] += 1;
    1062             :                  }
    1063             :              }
    1064             :          }
    1065             :      }
    1066             :  }
    1067             : \endcode
    1068             :  *
    1069             :  * @param nXBlockOff the horizontal block offset, with zero indicating
    1070             :  * the left most block, 1 the next block and so forth.
    1071             :  *
    1072             :  * @param nYBlockOff the vertical block offset, with zero indicating
    1073             :  * the top most block, 1 the next block and so forth.
    1074             :  *
    1075             :  * @param pImage the buffer into which the data will be read.  The buffer
    1076             :  * must be large enough to hold GetBlockXSize()*GetBlockYSize() words
    1077             :  * of type GetRasterDataType().
    1078             :  *
    1079             :  * @return CE_None on success or CE_Failure on an error.
    1080             :  */
    1081             : 
    1082         644 : CPLErr GDALRasterBand::ReadBlock(int nXBlockOff, int nYBlockOff, void *pImage)
    1083             : 
    1084             : {
    1085             :     /* -------------------------------------------------------------------- */
    1086             :     /*      Validate arguments.                                             */
    1087             :     /* -------------------------------------------------------------------- */
    1088         644 :     CPLAssert(pImage != nullptr);
    1089             : 
    1090         644 :     if (!InitBlockInfo())
    1091           0 :         return CE_Failure;
    1092             : 
    1093         644 :     if (nXBlockOff < 0 || nXBlockOff >= nBlocksPerRow)
    1094             :     {
    1095           0 :         ReportError(CE_Failure, CPLE_IllegalArg,
    1096             :                     "Illegal nXBlockOff value (%d) in "
    1097             :                     "GDALRasterBand::ReadBlock()\n",
    1098             :                     nXBlockOff);
    1099             : 
    1100           0 :         return (CE_Failure);
    1101             :     }
    1102             : 
    1103         644 :     if (nYBlockOff < 0 || nYBlockOff >= nBlocksPerColumn)
    1104             :     {
    1105           0 :         ReportError(CE_Failure, CPLE_IllegalArg,
    1106             :                     "Illegal nYBlockOff value (%d) in "
    1107             :                     "GDALRasterBand::ReadBlock()\n",
    1108             :                     nYBlockOff);
    1109             : 
    1110           0 :         return (CE_Failure);
    1111             :     }
    1112             : 
    1113             :     /* -------------------------------------------------------------------- */
    1114             :     /*      Invoke underlying implementation method.                        */
    1115             :     /* -------------------------------------------------------------------- */
    1116             : 
    1117         644 :     int bCallLeaveReadWrite = EnterReadWrite(GF_Read);
    1118         644 :     CPLErr eErr = IReadBlock(nXBlockOff, nYBlockOff, pImage);
    1119         644 :     if (bCallLeaveReadWrite)
    1120           4 :         LeaveReadWrite();
    1121         644 :     return eErr;
    1122             : }
    1123             : 
    1124             : /************************************************************************/
    1125             : /*                           GDALReadBlock()                            */
    1126             : /************************************************************************/
    1127             : 
    1128             : /**
    1129             :  * \brief Read a block of image data efficiently.
    1130             :  *
    1131             :  * @see GDALRasterBand::ReadBlock()
    1132             :  */
    1133             : 
    1134          67 : CPLErr CPL_STDCALL GDALReadBlock(GDALRasterBandH hBand, int nXOff, int nYOff,
    1135             :                                  void *pData)
    1136             : 
    1137             : {
    1138          67 :     VALIDATE_POINTER1(hBand, "GDALReadBlock", CE_Failure);
    1139             : 
    1140          67 :     GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
    1141          67 :     return (poBand->ReadBlock(nXOff, nYOff, pData));
    1142             : }
    1143             : 
    1144             : /************************************************************************/
    1145             : /*                            IReadBlock()                             */
    1146             : /************************************************************************/
    1147             : 
    1148             : /** \fn GDALRasterBand::IReadBlock( int nBlockXOff, int nBlockYOff, void *pData
    1149             :  * ) \brief Read a block of data.
    1150             :  *
    1151             :  * Default internal implementation ... to be overridden by
    1152             :  * subclasses that support reading.
    1153             :  * @param nBlockXOff Block X Offset
    1154             :  * @param nBlockYOff Block Y Offset
    1155             :  * @param pData Pixel buffer into which to place read data.
    1156             :  * @return CE_None on success or CE_Failure on an error.
    1157             :  */
    1158             : 
    1159             : /************************************************************************/
    1160             : /*                            IWriteBlock()                             */
    1161             : /************************************************************************/
    1162             : 
    1163             : /**
    1164             :  * \fn GDALRasterBand::IWriteBlock(int, int, void*)
    1165             :  * Write a block of data.
    1166             :  *
    1167             :  * Default internal implementation ... to be overridden by
    1168             :  * subclasses that support writing.
    1169             :  * @param nBlockXOff Block X Offset
    1170             :  * @param nBlockYOff Block Y Offset
    1171             :  * @param pData Pixel buffer to write
    1172             :  * @return CE_None on success or CE_Failure on an error.
    1173             :  */
    1174             : 
    1175             : /**/
    1176             : /**/
    1177             : 
    1178           0 : CPLErr GDALRasterBand::IWriteBlock(int /*nBlockXOff*/, int /*nBlockYOff*/,
    1179             :                                    void * /*pData*/)
    1180             : 
    1181             : {
    1182           0 :     if (!(GetMOFlags() & GMO_IGNORE_UNIMPLEMENTED))
    1183           0 :         ReportError(CE_Failure, CPLE_NotSupported,
    1184             :                     "WriteBlock() not supported for this dataset.");
    1185             : 
    1186           0 :     return (CE_Failure);
    1187             : }
    1188             : 
    1189             : /************************************************************************/
    1190             : /*                             WriteBlock()                             */
    1191             : /************************************************************************/
    1192             : 
    1193             : /**
    1194             :  * \brief Write a block of image data efficiently.
    1195             :  *
    1196             :  * This method accesses a "natural" block from the raster band without
    1197             :  * resampling, or data type conversion.  For a more generalized, but
    1198             :  * potentially less efficient access use RasterIO().
    1199             :  *
    1200             :  * This method is the same as the C GDALWriteBlock() function.
    1201             :  *
    1202             :  * See ReadBlock() for an example of block oriented data access.
    1203             :  *
    1204             :  * @param nXBlockOff the horizontal block offset, with zero indicating
    1205             :  * the left most block, 1 the next block and so forth.
    1206             :  *
    1207             :  * @param nYBlockOff the vertical block offset, with zero indicating
    1208             :  * the left most block, 1 the next block and so forth.
    1209             :  *
    1210             :  * @param pImage the buffer from which the data will be written.  The buffer
    1211             :  * must be large enough to hold GetBlockXSize()*GetBlockYSize() words
    1212             :  * of type GetRasterDataType(). Note that the content of the buffer might be
    1213             :  * temporarily modified during the execution of this method (and eventually
    1214             :  * restored back to its original content), so it is not safe to use a buffer
    1215             :  * stored in a read-only section of the calling program.
    1216             :  *
    1217             :  * @return CE_None on success or CE_Failure on an error.
    1218             :  */
    1219             : 
    1220        4888 : CPLErr GDALRasterBand::WriteBlock(int nXBlockOff, int nYBlockOff, void *pImage)
    1221             : 
    1222             : {
    1223             :     /* -------------------------------------------------------------------- */
    1224             :     /*      Validate arguments.                                             */
    1225             :     /* -------------------------------------------------------------------- */
    1226        4888 :     CPLAssert(pImage != nullptr);
    1227             : 
    1228        4888 :     if (!InitBlockInfo())
    1229           0 :         return CE_Failure;
    1230             : 
    1231        4888 :     if (nXBlockOff < 0 || nXBlockOff >= nBlocksPerRow)
    1232             :     {
    1233           0 :         ReportError(CE_Failure, CPLE_IllegalArg,
    1234             :                     "Illegal nXBlockOff value (%d) in "
    1235             :                     "GDALRasterBand::WriteBlock()\n",
    1236             :                     nXBlockOff);
    1237             : 
    1238           0 :         return (CE_Failure);
    1239             :     }
    1240             : 
    1241        4888 :     if (nYBlockOff < 0 || nYBlockOff >= nBlocksPerColumn)
    1242             :     {
    1243           0 :         ReportError(CE_Failure, CPLE_IllegalArg,
    1244             :                     "Illegal nYBlockOff value (%d) in "
    1245             :                     "GDALRasterBand::WriteBlock()\n",
    1246             :                     nYBlockOff);
    1247             : 
    1248           0 :         return (CE_Failure);
    1249             :     }
    1250             : 
    1251        4888 :     if (eAccess == GA_ReadOnly)
    1252             :     {
    1253           0 :         ReportError(CE_Failure, CPLE_NoWriteAccess,
    1254             :                     "Attempt to write to read only dataset in"
    1255             :                     "GDALRasterBand::WriteBlock().\n");
    1256             : 
    1257           0 :         return (CE_Failure);
    1258             :     }
    1259             : 
    1260        4888 :     if (eFlushBlockErr != CE_None)
    1261             :     {
    1262           0 :         ReportError(eFlushBlockErr, CPLE_AppDefined,
    1263             :                     "An error occurred while writing a dirty block "
    1264             :                     "from GDALRasterBand::WriteBlock");
    1265           0 :         CPLErr eErr = eFlushBlockErr;
    1266           0 :         eFlushBlockErr = CE_None;
    1267           0 :         return eErr;
    1268             :     }
    1269             : 
    1270             :     /* -------------------------------------------------------------------- */
    1271             :     /*      Invoke underlying implementation method.                        */
    1272             :     /* -------------------------------------------------------------------- */
    1273             : 
    1274        4888 :     const bool bCallLeaveReadWrite = CPL_TO_BOOL(EnterReadWrite(GF_Write));
    1275        4888 :     CPLErr eErr = IWriteBlock(nXBlockOff, nYBlockOff, pImage);
    1276        4888 :     if (bCallLeaveReadWrite)
    1277        4888 :         LeaveReadWrite();
    1278             : 
    1279        4888 :     return eErr;
    1280             : }
    1281             : 
    1282             : /************************************************************************/
    1283             : /*                           GDALWriteBlock()                           */
    1284             : /************************************************************************/
    1285             : 
    1286             : /**
    1287             :  * \brief Write a block of image data efficiently.
    1288             :  *
    1289             :  * @see GDALRasterBand::WriteBlock()
    1290             :  */
    1291             : 
    1292           0 : CPLErr CPL_STDCALL GDALWriteBlock(GDALRasterBandH hBand, int nXOff, int nYOff,
    1293             :                                   void *pData)
    1294             : 
    1295             : {
    1296           0 :     VALIDATE_POINTER1(hBand, "GDALWriteBlock", CE_Failure);
    1297             : 
    1298           0 :     GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
    1299           0 :     return (poBand->WriteBlock(nXOff, nYOff, pData));
    1300             : }
    1301             : 
    1302             : /************************************************************************/
    1303             : /*                         GetActualBlockSize()                         */
    1304             : /************************************************************************/
    1305             : /**
    1306             :  * \brief Fetch the actual block size for a given block offset.
    1307             :  *
    1308             :  * Handles partial blocks at the edges of the raster and returns the true
    1309             :  * number of pixels
    1310             :  *
    1311             :  * @param nXBlockOff the horizontal block offset for which to calculate the
    1312             :  * number of valid pixels, with zero indicating the left most block, 1 the next
    1313             :  * block and so forth.
    1314             :  *
    1315             :  * @param nYBlockOff the vertical block offset, with zero indicating
    1316             :  * the top most block, 1 the next block and so forth.
    1317             :  *
    1318             :  * @param pnXValid pointer to an integer in which the number of valid pixels in
    1319             :  * the x direction will be stored
    1320             :  *
    1321             :  * @param pnYValid pointer to an integer in which the number of valid pixels in
    1322             :  * the y direction will be stored
    1323             :  *
    1324             :  * @return CE_None if the input parameters are valid, CE_Failure otherwise
    1325             :  *
    1326             :  * @since GDAL 2.2
    1327             :  */
    1328       47969 : CPLErr GDALRasterBand::GetActualBlockSize(int nXBlockOff, int nYBlockOff,
    1329             :                                           int *pnXValid, int *pnYValid) const
    1330             : {
    1331       95937 :     if (nXBlockOff < 0 || nBlockXSize == 0 ||
    1332       95935 :         nXBlockOff >= DIV_ROUND_UP(nRasterXSize, nBlockXSize) ||
    1333       95931 :         nYBlockOff < 0 || nBlockYSize == 0 ||
    1334       47965 :         nYBlockOff >= DIV_ROUND_UP(nRasterYSize, nBlockYSize))
    1335             :     {
    1336           3 :         return CE_Failure;
    1337             :     }
    1338             : 
    1339       47966 :     const int nXPixelOff = nXBlockOff * nBlockXSize;
    1340       47966 :     const int nYPixelOff = nYBlockOff * nBlockYSize;
    1341             : 
    1342       47966 :     *pnXValid = nBlockXSize;
    1343       47966 :     *pnYValid = nBlockYSize;
    1344             : 
    1345       47966 :     if (nXPixelOff >= nRasterXSize - nBlockXSize)
    1346             :     {
    1347       46356 :         *pnXValid = nRasterXSize - nXPixelOff;
    1348             :     }
    1349             : 
    1350       47966 :     if (nYPixelOff >= nRasterYSize - nBlockYSize)
    1351             :     {
    1352        3435 :         *pnYValid = nRasterYSize - nYPixelOff;
    1353             :     }
    1354             : 
    1355       47966 :     return CE_None;
    1356             : }
    1357             : 
    1358             : /************************************************************************/
    1359             : /*                           GDALGetActualBlockSize()                   */
    1360             : /************************************************************************/
    1361             : 
    1362             : /**
    1363             :  * \brief Retrieve the actual block size for a given block offset.
    1364             :  *
    1365             :  * @see GDALRasterBand::GetActualBlockSize()
    1366             :  */
    1367             : 
    1368           6 : CPLErr CPL_STDCALL GDALGetActualBlockSize(GDALRasterBandH hBand, int nXBlockOff,
    1369             :                                           int nYBlockOff, int *pnXValid,
    1370             :                                           int *pnYValid)
    1371             : 
    1372             : {
    1373           6 :     VALIDATE_POINTER1(hBand, "GDALGetActualBlockSize", CE_Failure);
    1374             : 
    1375           6 :     GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
    1376             :     return (
    1377           6 :         poBand->GetActualBlockSize(nXBlockOff, nYBlockOff, pnXValid, pnYValid));
    1378             : }
    1379             : 
    1380             : /************************************************************************/
    1381             : /*                     GetSuggestedBlockAccessPattern()                 */
    1382             : /************************************************************************/
    1383             : 
    1384             : /**
    1385             :  * \brief Return the suggested/most efficient access pattern to blocks
    1386             :  *        (for read operations).
    1387             :  *
    1388             :  * While all GDAL drivers have to expose a block size, not all can guarantee
    1389             :  * efficient random access (GSBAP_RANDOM) to any block.
    1390             :  * Some drivers for example decompress sequentially a compressed stream from
    1391             :  * top raster to bottom (GSBAP_TOP_TO_BOTTOM), in which
    1392             :  * case best performance will be achieved while reading blocks in that order.
    1393             :  * (accessing blocks in random access in such rasters typically causes the
    1394             :  * decoding to be re-initialized from the start if accessing blocks in
    1395             :  * a non-sequential order)
    1396             :  *
    1397             :  * The base implementation returns GSBAP_UNKNOWN, which can also be explicitly
    1398             :  * returned by drivers that expose a somewhat artificial block size, because
    1399             :  * they can extract any part of a raster, but in a rather inefficient way.
    1400             :  *
    1401             :  * The GSBAP_LARGEST_CHUNK_POSSIBLE value can be combined as a logical bitmask
    1402             :  * with other enumeration values (GSBAP_UNKNOWN, GSBAP_RANDOM,
    1403             :  * GSBAP_TOP_TO_BOTTOM, GSBAP_BOTTOM_TO_TOP). When a driver sets this flag, the
    1404             :  * most efficient strategy is to read as many pixels as possible in the less
    1405             :  * RasterIO() operations.
    1406             :  *
    1407             :  * The return of this method is for example used to determine the swath size
    1408             :  * used by GDALDatasetCopyWholeRaster() and GDALRasterBandCopyWholeRaster().
    1409             :  *
    1410             :  * @since GDAL 3.6
    1411             :  */
    1412             : 
    1413             : GDALSuggestedBlockAccessPattern
    1414        2198 : GDALRasterBand::GetSuggestedBlockAccessPattern() const
    1415             : {
    1416        2198 :     return GSBAP_UNKNOWN;
    1417             : }
    1418             : 
    1419             : /************************************************************************/
    1420             : /*                         GetRasterDataType()                          */
    1421             : /************************************************************************/
    1422             : 
    1423             : /**
    1424             :  * \brief Fetch the pixel data type for this band.
    1425             :  *
    1426             :  * This method is the same as the C function GDALGetRasterDataType().
    1427             :  *
    1428             :  * @return the data type of pixels for this band.
    1429             :  */
    1430             : 
    1431     7659680 : GDALDataType GDALRasterBand::GetRasterDataType() const
    1432             : 
    1433             : {
    1434     7659680 :     return eDataType;
    1435             : }
    1436             : 
    1437             : /************************************************************************/
    1438             : /*                       GDALGetRasterDataType()                        */
    1439             : /************************************************************************/
    1440             : 
    1441             : /**
    1442             :  * \brief Fetch the pixel data type for this band.
    1443             :  *
    1444             :  * @see GDALRasterBand::GetRasterDataType()
    1445             :  */
    1446             : 
    1447      899692 : GDALDataType CPL_STDCALL GDALGetRasterDataType(GDALRasterBandH hBand)
    1448             : 
    1449             : {
    1450      899692 :     VALIDATE_POINTER1(hBand, "GDALGetRasterDataType", GDT_Unknown);
    1451             : 
    1452      899692 :     GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
    1453      899692 :     return poBand->GetRasterDataType();
    1454             : }
    1455             : 
    1456             : /************************************************************************/
    1457             : /*                            GetBlockSize()                            */
    1458             : /************************************************************************/
    1459             : 
    1460             : /**
    1461             :  * \brief Fetch the "natural" block size of this band.
    1462             :  *
    1463             :  * GDAL contains a concept of the natural block size of rasters so that
    1464             :  * applications can organized data access efficiently for some file formats.
    1465             :  * The natural block size is the block size that is most efficient for
    1466             :  * accessing the format.  For many formats this is simple a whole scanline
    1467             :  * in which case *pnXSize is set to GetXSize(), and *pnYSize is set to 1.
    1468             :  *
    1469             :  * However, for tiled images this will typically be the tile size.
    1470             :  *
    1471             :  * Note that the X and Y block sizes don't have to divide the image size
    1472             :  * evenly, meaning that right and bottom edge blocks may be incomplete.
    1473             :  * See ReadBlock() for an example of code dealing with these issues.
    1474             :  *
    1475             :  * This method is the same as the C function GDALGetBlockSize().
    1476             :  *
    1477             :  * @param pnXSize integer to put the X block size into or NULL.
    1478             :  *
    1479             :  * @param pnYSize integer to put the Y block size into or NULL.
    1480             :  */
    1481             : 
    1482     5075260 : void GDALRasterBand::GetBlockSize(int *pnXSize, int *pnYSize) const
    1483             : 
    1484             : {
    1485     5075260 :     if (nBlockXSize <= 0 || nBlockYSize <= 0)
    1486             :     {
    1487        5055 :         ReportError(CE_Failure, CPLE_AppDefined,
    1488        5055 :                     "Invalid block dimension : %d * %d", nBlockXSize,
    1489        5055 :                     nBlockYSize);
    1490           0 :         if (pnXSize != nullptr)
    1491           0 :             *pnXSize = 0;
    1492           0 :         if (pnYSize != nullptr)
    1493           0 :             *pnYSize = 0;
    1494             :     }
    1495             :     else
    1496             :     {
    1497     5070200 :         if (pnXSize != nullptr)
    1498     5070070 :             *pnXSize = nBlockXSize;
    1499     5070200 :         if (pnYSize != nullptr)
    1500     5071950 :             *pnYSize = nBlockYSize;
    1501             :     }
    1502     5070200 : }
    1503             : 
    1504             : /************************************************************************/
    1505             : /*                          GDALGetBlockSize()                          */
    1506             : /************************************************************************/
    1507             : 
    1508             : /**
    1509             :  * \brief Fetch the "natural" block size of this band.
    1510             :  *
    1511             :  * @see GDALRasterBand::GetBlockSize()
    1512             :  */
    1513             : 
    1514       40413 : void CPL_STDCALL GDALGetBlockSize(GDALRasterBandH hBand, int *pnXSize,
    1515             :                                   int *pnYSize)
    1516             : 
    1517             : {
    1518       40413 :     VALIDATE_POINTER0(hBand, "GDALGetBlockSize");
    1519             : 
    1520       40413 :     GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
    1521       40413 :     poBand->GetBlockSize(pnXSize, pnYSize);
    1522             : }
    1523             : 
    1524             : /************************************************************************/
    1525             : /*                           InitBlockInfo()                            */
    1526             : /************************************************************************/
    1527             : 
    1528             : //! @cond Doxygen_Suppress
    1529     3335680 : int GDALRasterBand::InitBlockInfo()
    1530             : 
    1531             : {
    1532     3335680 :     if (poBandBlockCache != nullptr)
    1533     3301570 :         return poBandBlockCache->IsInitOK();
    1534             : 
    1535             :     /* Do some validation of raster and block dimensions in case the driver */
    1536             :     /* would have neglected to do it itself */
    1537       34109 :     if (nBlockXSize <= 0 || nBlockYSize <= 0)
    1538             :     {
    1539          66 :         ReportError(CE_Failure, CPLE_AppDefined,
    1540             :                     "Invalid block dimension : %d * %d", nBlockXSize,
    1541             :                     nBlockYSize);
    1542           0 :         return FALSE;
    1543             :     }
    1544             : 
    1545       34043 :     if (nRasterXSize <= 0 || nRasterYSize <= 0)
    1546             :     {
    1547           0 :         ReportError(CE_Failure, CPLE_AppDefined,
    1548             :                     "Invalid raster dimension : %d * %d", nRasterXSize,
    1549             :                     nRasterYSize);
    1550           0 :         return FALSE;
    1551             :     }
    1552             : 
    1553       34046 :     const int nDataTypeSize = GDALGetDataTypeSizeBytes(eDataType);
    1554       34077 :     if (nDataTypeSize == 0)
    1555             :     {
    1556          26 :         ReportError(CE_Failure, CPLE_AppDefined, "Invalid data type");
    1557           0 :         return FALSE;
    1558             :     }
    1559             : 
    1560             : #if SIZEOF_VOIDP == 4
    1561             :     if (nBlockXSize >= 10000 || nBlockYSize >= 10000)
    1562             :     {
    1563             :         /* As 10000 * 10000 * 16 < INT_MAX, we don't need to do the
    1564             :          * multiplication in other cases */
    1565             :         if (nBlockXSize > INT_MAX / nDataTypeSize ||
    1566             :             nBlockYSize > INT_MAX / (nDataTypeSize * nBlockXSize))
    1567             :         {
    1568             :             ReportError(CE_Failure, CPLE_NotSupported,
    1569             :                         "Too big block : %d * %d for 32-bit build", nBlockXSize,
    1570             :                         nBlockYSize);
    1571             :             return FALSE;
    1572             :         }
    1573             :     }
    1574             : #endif
    1575             : 
    1576       34051 :     nBlocksPerRow = DIV_ROUND_UP(nRasterXSize, nBlockXSize);
    1577       34051 :     nBlocksPerColumn = DIV_ROUND_UP(nRasterYSize, nBlockYSize);
    1578             : 
    1579             :     const char *pszBlockStrategy =
    1580       34051 :         CPLGetConfigOption("GDAL_BAND_BLOCK_CACHE", nullptr);
    1581       34114 :     bool bUseArray = true;
    1582       34114 :     if (pszBlockStrategy == nullptr || EQUAL(pszBlockStrategy, "AUTO"))
    1583             :     {
    1584       34074 :         if (poDS == nullptr || (poDS->nOpenFlags & GDAL_OF_BLOCK_ACCESS_MASK) ==
    1585             :                                    GDAL_OF_DEFAULT_BLOCK_ACCESS)
    1586             :         {
    1587       34055 :             GUIntBig nBlockCount =
    1588       34055 :                 static_cast<GIntBig>(nBlocksPerRow) * nBlocksPerColumn;
    1589       34055 :             if (poDS != nullptr)
    1590       33867 :                 nBlockCount *= poDS->GetRasterCount();
    1591       34055 :             bUseArray = (nBlockCount < 1024 * 1024);
    1592             :         }
    1593          19 :         else if ((poDS->nOpenFlags & GDAL_OF_BLOCK_ACCESS_MASK) ==
    1594             :                  GDAL_OF_HASHSET_BLOCK_ACCESS)
    1595             :         {
    1596           0 :             bUseArray = false;
    1597       34074 :         }
    1598             :     }
    1599          40 :     else if (EQUAL(pszBlockStrategy, "HASHSET"))
    1600          40 :         bUseArray = false;
    1601           0 :     else if (!EQUAL(pszBlockStrategy, "ARRAY"))
    1602           0 :         CPLError(CE_Warning, CPLE_AppDefined, "Unknown block cache method: %s",
    1603             :                  pszBlockStrategy);
    1604             : 
    1605       34112 :     if (bUseArray)
    1606       34042 :         poBandBlockCache = GDALArrayBandBlockCacheCreate(this);
    1607             :     else
    1608             :     {
    1609          70 :         if (nBand == 1)
    1610          25 :             CPLDebug("GDAL", "Use hashset band block cache");
    1611          70 :         poBandBlockCache = GDALHashSetBandBlockCacheCreate(this);
    1612             :     }
    1613       34102 :     if (poBandBlockCache == nullptr)
    1614           0 :         return FALSE;
    1615       34102 :     return poBandBlockCache->Init();
    1616             : }
    1617             : 
    1618             : //! @endcond
    1619             : 
    1620             : /************************************************************************/
    1621             : /*                             FlushCache()                             */
    1622             : /************************************************************************/
    1623             : 
    1624             : /**
    1625             :  * \brief Flush raster data cache.
    1626             :  *
    1627             :  * This call will recover memory used to cache data blocks for this raster
    1628             :  * band, and ensure that new requests are referred to the underlying driver.
    1629             :  *
    1630             :  * This method is the same as the C function GDALFlushRasterCache().
    1631             :  *
    1632             :  * @param bAtClosing Whether this is called from a GDALDataset destructor
    1633             :  * @return CE_None on success.
    1634             :  */
    1635             : 
    1636     3873290 : CPLErr GDALRasterBand::FlushCache(bool bAtClosing)
    1637             : 
    1638             : {
    1639     3917960 :     if (bAtClosing && poDS && poDS->IsMarkedSuppressOnClose() &&
    1640       44666 :         poBandBlockCache)
    1641        2102 :         poBandBlockCache->DisableDirtyBlockWriting();
    1642             : 
    1643     3873490 :     CPLErr eGlobalErr = eFlushBlockErr;
    1644             : 
    1645     3873490 :     if (eFlushBlockErr != CE_None)
    1646             :     {
    1647           0 :         ReportError(
    1648             :             eFlushBlockErr, CPLE_AppDefined,
    1649             :             "An error occurred while writing a dirty block from FlushCache");
    1650           0 :         eFlushBlockErr = CE_None;
    1651             :     }
    1652             : 
    1653     3873490 :     if (poBandBlockCache == nullptr || !poBandBlockCache->IsInitOK())
    1654     3722060 :         return eGlobalErr;
    1655             : 
    1656      151424 :     return poBandBlockCache->FlushCache();
    1657             : }
    1658             : 
    1659             : /************************************************************************/
    1660             : /*                        GDALFlushRasterCache()                        */
    1661             : /************************************************************************/
    1662             : 
    1663             : /**
    1664             :  * \brief Flush raster data cache.
    1665             :  *
    1666             :  * @see GDALRasterBand::FlushCache()
    1667             :  */
    1668             : 
    1669         130 : CPLErr CPL_STDCALL GDALFlushRasterCache(GDALRasterBandH hBand)
    1670             : 
    1671             : {
    1672         130 :     VALIDATE_POINTER1(hBand, "GDALFlushRasterCache", CE_Failure);
    1673             : 
    1674         130 :     return GDALRasterBand::FromHandle(hBand)->FlushCache(false);
    1675             : }
    1676             : 
    1677             : /************************************************************************/
    1678             : /*                             DropCache()                              */
    1679             : /************************************************************************/
    1680             : 
    1681             : /**
    1682             : * \brief Drop raster data cache : data in cache will be lost.
    1683             : *
    1684             : * This call will recover memory used to cache data blocks for this raster
    1685             : * band, and ensure that new requests are referred to the underlying driver.
    1686             : *
    1687             : * This method is the same as the C function GDALDropRasterCache().
    1688             : *
    1689             : * @return CE_None on success.
    1690             : * @since 3.9
    1691             : */
    1692             : 
    1693           1 : CPLErr GDALRasterBand::DropCache()
    1694             : 
    1695             : {
    1696           1 :     CPLErr result = CE_None;
    1697             : 
    1698           1 :     if (poBandBlockCache)
    1699           1 :         poBandBlockCache->DisableDirtyBlockWriting();
    1700             : 
    1701           1 :     CPLErr eGlobalErr = eFlushBlockErr;
    1702             : 
    1703           1 :     if (eFlushBlockErr != CE_None)
    1704             :     {
    1705           0 :         ReportError(
    1706             :             eFlushBlockErr, CPLE_AppDefined,
    1707             :             "An error occurred while writing a dirty block from DropCache");
    1708           0 :         eFlushBlockErr = CE_None;
    1709             :     }
    1710             : 
    1711           1 :     if (poBandBlockCache == nullptr || !poBandBlockCache->IsInitOK())
    1712           0 :         result = eGlobalErr;
    1713             :     else
    1714           1 :         result = poBandBlockCache->FlushCache();
    1715             : 
    1716           1 :     if (poBandBlockCache)
    1717           1 :         poBandBlockCache->EnableDirtyBlockWriting();
    1718             : 
    1719           1 :     return result;
    1720             : }
    1721             : 
    1722             : /************************************************************************/
    1723             : /*                        GDALDropRasterCache()                         */
    1724             : /************************************************************************/
    1725             : 
    1726             : /**
    1727             : * \brief Drop raster data cache.
    1728             : *
    1729             : * @see GDALRasterBand::DropCache()
    1730             : * @since 3.9
    1731             : */
    1732             : 
    1733           0 : CPLErr CPL_STDCALL GDALDropRasterCache(GDALRasterBandH hBand)
    1734             : 
    1735             : {
    1736           0 :     VALIDATE_POINTER1(hBand, "GDALDropRasterCache", CE_Failure);
    1737             : 
    1738           0 :     return GDALRasterBand::FromHandle(hBand)->DropCache();
    1739             : }
    1740             : 
    1741             : /************************************************************************/
    1742             : /*                        UnreferenceBlock()                            */
    1743             : /*                                                                      */
    1744             : /*      Unreference the block from our array of blocks                  */
    1745             : /*      This method should only be called by                            */
    1746             : /*      GDALRasterBlock::Internalize() and FlushCacheBlock() (and under */
    1747             : /*      the block cache mutex)                                          */
    1748             : /************************************************************************/
    1749             : 
    1750       29617 : CPLErr GDALRasterBand::UnreferenceBlock(GDALRasterBlock *poBlock)
    1751             : {
    1752             : #ifdef notdef
    1753             :     if (poBandBlockCache == nullptr || !poBandBlockCache->IsInitOK())
    1754             :     {
    1755             :         if (poBandBlockCache == nullptr)
    1756             :             printf("poBandBlockCache == NULL\n"); /*ok*/
    1757             :         else
    1758             :             printf("!poBandBlockCache->IsInitOK()\n"); /*ok*/
    1759             :         printf("caller = %s\n", pszCaller);            /*ok*/
    1760             :         printf("GDALRasterBand: %p\n", this);          /*ok*/
    1761             :         printf("GDALRasterBand: nBand=%d\n", nBand);   /*ok*/
    1762             :         printf("nRasterXSize = %d\n", nRasterXSize);   /*ok*/
    1763             :         printf("nRasterYSize = %d\n", nRasterYSize);   /*ok*/
    1764             :         printf("nBlockXSize = %d\n", nBlockXSize);     /*ok*/
    1765             :         printf("nBlockYSize = %d\n", nBlockYSize);     /*ok*/
    1766             :         poBlock->DumpBlock();
    1767             :         if (GetDataset() != nullptr)
    1768             :             printf("Dataset: %s\n", GetDataset()->GetDescription()); /*ok*/
    1769             :         GDALRasterBlock::Verify();
    1770             :         abort();
    1771             :     }
    1772             : #endif
    1773       29617 :     CPLAssert(poBandBlockCache && poBandBlockCache->IsInitOK());
    1774       29617 :     return poBandBlockCache->UnreferenceBlock(poBlock);
    1775             : }
    1776             : 
    1777             : /************************************************************************/
    1778             : /*                        AddBlockToFreeList()                          */
    1779             : /*                                                                      */
    1780             : /*      When GDALRasterBlock::Internalize() or FlushCacheBlock() are    */
    1781             : /*      finished with a block about to be free'd, they pass it to that  */
    1782             : /*      method.                                                         */
    1783             : /************************************************************************/
    1784             : 
    1785             : //! @cond Doxygen_Suppress
    1786       29617 : void GDALRasterBand::AddBlockToFreeList(GDALRasterBlock *poBlock)
    1787             : {
    1788       29617 :     CPLAssert(poBandBlockCache && poBandBlockCache->IsInitOK());
    1789       29617 :     return poBandBlockCache->AddBlockToFreeList(poBlock);
    1790             : }
    1791             : 
    1792             : //! @endcond
    1793             : 
    1794             : /************************************************************************/
    1795             : /*                             FlushBlock()                             */
    1796             : /************************************************************************/
    1797             : 
    1798             : /** Flush a block out of the block cache.
    1799             :  * @param nXBlockOff block x offset
    1800             :  * @param nYBlockOff blocky offset
    1801             :  * @param bWriteDirtyBlock whether the block should be written to disk if dirty.
    1802             :  * @return CE_None in case of success, an error code otherwise.
    1803             :  */
    1804        2302 : CPLErr GDALRasterBand::FlushBlock(int nXBlockOff, int nYBlockOff,
    1805             :                                   int bWriteDirtyBlock)
    1806             : 
    1807             : {
    1808        2302 :     if (poBandBlockCache == nullptr || !poBandBlockCache->IsInitOK())
    1809           0 :         return (CE_Failure);
    1810             : 
    1811             :     /* -------------------------------------------------------------------- */
    1812             :     /*      Validate the request                                            */
    1813             :     /* -------------------------------------------------------------------- */
    1814        2302 :     if (nXBlockOff < 0 || nXBlockOff >= nBlocksPerRow)
    1815             :     {
    1816           0 :         ReportError(CE_Failure, CPLE_IllegalArg,
    1817             :                     "Illegal nBlockXOff value (%d) in "
    1818             :                     "GDALRasterBand::FlushBlock()\n",
    1819             :                     nXBlockOff);
    1820             : 
    1821           0 :         return (CE_Failure);
    1822             :     }
    1823             : 
    1824        2302 :     if (nYBlockOff < 0 || nYBlockOff >= nBlocksPerColumn)
    1825             :     {
    1826           0 :         ReportError(CE_Failure, CPLE_IllegalArg,
    1827             :                     "Illegal nBlockYOff value (%d) in "
    1828             :                     "GDALRasterBand::FlushBlock()\n",
    1829             :                     nYBlockOff);
    1830             : 
    1831           0 :         return (CE_Failure);
    1832             :     }
    1833             : 
    1834        2302 :     return poBandBlockCache->FlushBlock(nXBlockOff, nYBlockOff,
    1835        2302 :                                         bWriteDirtyBlock);
    1836             : }
    1837             : 
    1838             : /************************************************************************/
    1839             : /*                        TryGetLockedBlockRef()                        */
    1840             : /************************************************************************/
    1841             : 
    1842             : /**
    1843             :  * \brief Try fetching block ref.
    1844             :  *
    1845             :  * This method will returned the requested block (locked) if it is already
    1846             :  * in the block cache for the layer.  If not, nullptr is returned.
    1847             :  *
    1848             :  * If a non-NULL value is returned, then a lock for the block will have been
    1849             :  * acquired on behalf of the caller.  It is absolutely imperative that the
    1850             :  * caller release this lock (with GDALRasterBlock::DropLock()) or else
    1851             :  * severe problems may result.
    1852             :  *
    1853             :  * @param nXBlockOff the horizontal block offset, with zero indicating
    1854             :  * the left most block, 1 the next block and so forth.
    1855             :  *
    1856             :  * @param nYBlockOff the vertical block offset, with zero indicating
    1857             :  * the top most block, 1 the next block and so forth.
    1858             :  *
    1859             :  * @return NULL if block not available, or locked block pointer.
    1860             :  */
    1861             : 
    1862     9991420 : GDALRasterBlock *GDALRasterBand::TryGetLockedBlockRef(int nXBlockOff,
    1863             :                                                       int nYBlockOff)
    1864             : 
    1865             : {
    1866     9991420 :     if (poBandBlockCache == nullptr || !poBandBlockCache->IsInitOK())
    1867       66499 :         return nullptr;
    1868             : 
    1869             :     /* -------------------------------------------------------------------- */
    1870             :     /*      Validate the request                                            */
    1871             :     /* -------------------------------------------------------------------- */
    1872     9925520 :     if (nXBlockOff < 0 || nXBlockOff >= nBlocksPerRow)
    1873             :     {
    1874        1893 :         ReportError(CE_Failure, CPLE_IllegalArg,
    1875             :                     "Illegal nBlockXOff value (%d) in "
    1876             :                     "GDALRasterBand::TryGetLockedBlockRef()\n",
    1877             :                     nXBlockOff);
    1878             : 
    1879           0 :         return (nullptr);
    1880             :     }
    1881             : 
    1882     9923630 :     if (nYBlockOff < 0 || nYBlockOff >= nBlocksPerColumn)
    1883             :     {
    1884           0 :         ReportError(CE_Failure, CPLE_IllegalArg,
    1885             :                     "Illegal nBlockYOff value (%d) in "
    1886             :                     "GDALRasterBand::TryGetLockedBlockRef()\n",
    1887             :                     nYBlockOff);
    1888             : 
    1889           0 :         return (nullptr);
    1890             :     }
    1891             : 
    1892     9923740 :     return poBandBlockCache->TryGetLockedBlockRef(nXBlockOff, nYBlockOff);
    1893             : }
    1894             : 
    1895             : /************************************************************************/
    1896             : /*                         GetLockedBlockRef()                          */
    1897             : /************************************************************************/
    1898             : 
    1899             : /**
    1900             :  * \brief Fetch a pointer to an internally cached raster block.
    1901             :  *
    1902             :  * This method will returned the requested block (locked) if it is already
    1903             :  * in the block cache for the layer.  If not, the block will be read from
    1904             :  * the driver, and placed in the layer block cached, then returned.  If an
    1905             :  * error occurs reading the block from the driver, a NULL value will be
    1906             :  * returned.
    1907             :  *
    1908             :  * If a non-NULL value is returned, then a lock for the block will have been
    1909             :  * acquired on behalf of the caller.  It is absolutely imperative that the
    1910             :  * caller release this lock (with GDALRasterBlock::DropLock()) or else
    1911             :  * severe problems may result.
    1912             :  *
    1913             :  * Note that calling GetLockedBlockRef() on a previously uncached band will
    1914             :  * enable caching.
    1915             :  *
    1916             :  * @param nXBlockOff the horizontal block offset, with zero indicating
    1917             :  * the left most block, 1 the next block and so forth.
    1918             :  *
    1919             :  * @param nYBlockOff the vertical block offset, with zero indicating
    1920             :  * the top most block, 1 the next block and so forth.
    1921             :  *
    1922             :  * @param bJustInitialize If TRUE the block will be allocated and initialized,
    1923             :  * but not actually read from the source.  This is useful when it will just
    1924             :  * be completely set and written back.
    1925             :  *
    1926             :  * @return pointer to the block object, or NULL on failure.
    1927             :  */
    1928             : 
    1929     9788520 : GDALRasterBlock *GDALRasterBand::GetLockedBlockRef(int nXBlockOff,
    1930             :                                                    int nYBlockOff,
    1931             :                                                    int bJustInitialize)
    1932             : 
    1933             : {
    1934             :     /* -------------------------------------------------------------------- */
    1935             :     /*      Try and fetch from cache.                                       */
    1936             :     /* -------------------------------------------------------------------- */
    1937     9788520 :     GDALRasterBlock *poBlock = TryGetLockedBlockRef(nXBlockOff, nYBlockOff);
    1938             : 
    1939             :     /* -------------------------------------------------------------------- */
    1940             :     /*      If we didn't find it in our memory cache, instantiate a         */
    1941             :     /*      block (potentially load from disk) and "adopt" it into the      */
    1942             :     /*      cache.                                                          */
    1943             :     /* -------------------------------------------------------------------- */
    1944     9791930 :     if (poBlock == nullptr)
    1945             :     {
    1946     3158810 :         if (!InitBlockInfo())
    1947           0 :             return (nullptr);
    1948             : 
    1949             :         /* --------------------------------------------------------------------
    1950             :          */
    1951             :         /*      Validate the request */
    1952             :         /* --------------------------------------------------------------------
    1953             :          */
    1954     3158840 :         if (nXBlockOff < 0 || nXBlockOff >= nBlocksPerRow)
    1955             :         {
    1956          44 :             ReportError(CE_Failure, CPLE_IllegalArg,
    1957             :                         "Illegal nBlockXOff value (%d) in "
    1958             :                         "GDALRasterBand::GetLockedBlockRef()\n",
    1959             :                         nXBlockOff);
    1960             : 
    1961           0 :             return (nullptr);
    1962             :         }
    1963             : 
    1964     3158800 :         if (nYBlockOff < 0 || nYBlockOff >= nBlocksPerColumn)
    1965             :         {
    1966          46 :             ReportError(CE_Failure, CPLE_IllegalArg,
    1967             :                         "Illegal nBlockYOff value (%d) in "
    1968             :                         "GDALRasterBand::GetLockedBlockRef()\n",
    1969             :                         nYBlockOff);
    1970             : 
    1971           0 :             return (nullptr);
    1972             :         }
    1973             : 
    1974     3158750 :         poBlock = poBandBlockCache->CreateBlock(nXBlockOff, nYBlockOff);
    1975     3158860 :         if (poBlock == nullptr)
    1976           0 :             return nullptr;
    1977             : 
    1978     3158860 :         poBlock->AddLock();
    1979             : 
    1980             :         /* We need to temporarily drop the read-write lock in the following */
    1981             :         /*scenario. Imagine 2 threads T1 and T2 that respectively write dataset
    1982             :          */
    1983             :         /* D1 and D2. T1 will take the mutex on D1 and T2 on D2. Now when the */
    1984             :         /* block cache fills, T1 might need to flush dirty blocks of D2 in the
    1985             :          */
    1986             :         /* below Internalize(), which will cause GDALRasterBlock::Write() to be
    1987             :          */
    1988             :         /* called and attempt at taking the lock on T2 (already taken).
    1989             :          * Similarly */
    1990             :         /* for T2 with D1, hence a deadlock situation (#6163) */
    1991             :         /* But this may open the door to other problems... */
    1992     3158860 :         if (poDS)
    1993     3158140 :             poDS->TemporarilyDropReadWriteLock();
    1994             :         /* allocate data space */
    1995     3158840 :         CPLErr eErr = poBlock->Internalize();
    1996     3158960 :         if (poDS)
    1997     3158200 :             poDS->ReacquireReadWriteLock();
    1998     3158930 :         if (eErr != CE_None)
    1999             :         {
    2000           0 :             poBlock->DropLock();
    2001           0 :             delete poBlock;
    2002           0 :             return nullptr;
    2003             :         }
    2004             : 
    2005     3158930 :         if (poBandBlockCache->AdoptBlock(poBlock) != CE_None)
    2006             :         {
    2007           0 :             poBlock->DropLock();
    2008           0 :             delete poBlock;
    2009           0 :             return nullptr;
    2010             :         }
    2011             : 
    2012     3158900 :         if (!bJustInitialize)
    2013             :         {
    2014     2796270 :             const GUInt32 nErrorCounter = CPLGetErrorCounter();
    2015     2796240 :             int bCallLeaveReadWrite = EnterReadWrite(GF_Read);
    2016     2796220 :             eErr = IReadBlock(nXBlockOff, nYBlockOff, poBlock->GetDataRef());
    2017     2796270 :             if (bCallLeaveReadWrite)
    2018      130282 :                 LeaveReadWrite();
    2019     2796250 :             if (eErr != CE_None)
    2020             :             {
    2021        1152 :                 poBlock->DropLock();
    2022        1152 :                 FlushBlock(nXBlockOff, nYBlockOff);
    2023        1152 :                 ReportError(CE_Failure, CPLE_AppDefined,
    2024             :                             "IReadBlock failed at X offset %d, Y offset %d%s",
    2025             :                             nXBlockOff, nYBlockOff,
    2026        1152 :                             (nErrorCounter != CPLGetErrorCounter())
    2027        1150 :                                 ? CPLSPrintf(": %s", CPLGetLastErrorMsg())
    2028             :                                 : "");
    2029        1152 :                 return nullptr;
    2030             :             }
    2031             : 
    2032     2795100 :             nBlockReads++;
    2033     2795100 :             if (static_cast<GIntBig>(nBlockReads) ==
    2034     2795100 :                     static_cast<GIntBig>(nBlocksPerRow) * nBlocksPerColumn +
    2035         214 :                         1 &&
    2036         214 :                 nBand == 1 && poDS != nullptr)
    2037             :             {
    2038         151 :                 CPLDebug("GDAL", "Potential thrashing on band %d of %s.", nBand,
    2039         151 :                          poDS->GetDescription());
    2040             :             }
    2041             :         }
    2042             :     }
    2043             : 
    2044     9790870 :     return poBlock;
    2045             : }
    2046             : 
    2047             : /************************************************************************/
    2048             : /*                               Fill()                                 */
    2049             : /************************************************************************/
    2050             : 
    2051             : /**
    2052             :  * \brief Fill this band with a constant value.
    2053             :  *
    2054             :  * GDAL makes no guarantees
    2055             :  * about what values pixels in newly created files are set to, so this
    2056             :  * method can be used to clear a band to a specified "default" value.
    2057             :  * The fill value is passed in as a double but this will be converted
    2058             :  * to the underlying type before writing to the file. An optional
    2059             :  * second argument allows the imaginary component of a complex
    2060             :  * constant value to be specified.
    2061             :  *
    2062             :  * This method is the same as the C function GDALFillRaster().
    2063             :  *
    2064             :  * @param dfRealValue Real component of fill value
    2065             :  * @param dfImaginaryValue Imaginary component of fill value, defaults to zero
    2066             :  *
    2067             :  * @return CE_Failure if the write fails, otherwise CE_None
    2068             :  */
    2069      169236 : CPLErr GDALRasterBand::Fill(double dfRealValue, double dfImaginaryValue)
    2070             : {
    2071             : 
    2072             :     // General approach is to construct a source block of the file's
    2073             :     // native type containing the appropriate value and then copy this
    2074             :     // to each block in the image via the RasterBlock cache. Using
    2075             :     // the cache means we avoid file I/O if it is not necessary, at the
    2076             :     // expense of some extra memcpy's (since we write to the
    2077             :     // RasterBlock cache, which is then at some point written to the
    2078             :     // underlying file, rather than simply directly to the underlying
    2079             :     // file.)
    2080             : 
    2081             :     // Check we can write to the file.
    2082      169236 :     if (eAccess == GA_ReadOnly)
    2083             :     {
    2084           2 :         ReportError(CE_Failure, CPLE_NoWriteAccess,
    2085             :                     "Attempt to write to read only dataset in "
    2086             :                     "GDALRasterBand::Fill().");
    2087           2 :         return CE_Failure;
    2088             :     }
    2089             : 
    2090             :     // Make sure block parameters are set.
    2091      169234 :     if (!InitBlockInfo())
    2092           0 :         return CE_Failure;
    2093             : 
    2094             :     // Allocate the source block.
    2095      169234 :     auto blockSize = static_cast<GPtrDiff_t>(nBlockXSize) * nBlockYSize;
    2096      169234 :     int elementSize = GDALGetDataTypeSizeBytes(eDataType);
    2097      169234 :     auto blockByteSize = blockSize * elementSize;
    2098             :     unsigned char *srcBlock =
    2099      169234 :         static_cast<unsigned char *>(VSIMalloc(blockByteSize));
    2100      169234 :     if (srcBlock == nullptr)
    2101             :     {
    2102           0 :         ReportError(CE_Failure, CPLE_OutOfMemory,
    2103             :                     "GDALRasterBand::Fill(): Out of memory "
    2104             :                     "allocating " CPL_FRMT_GUIB " bytes.\n",
    2105             :                     static_cast<GUIntBig>(blockByteSize));
    2106           0 :         return CE_Failure;
    2107             :     }
    2108             : 
    2109             :     // Initialize the source block.
    2110      169234 :     double complexSrc[2] = {dfRealValue, dfImaginaryValue};
    2111      169234 :     GDALCopyWords64(complexSrc, GDT_CFloat64, 0, srcBlock, eDataType,
    2112             :                     elementSize, blockSize);
    2113             : 
    2114      169234 :     const bool bCallLeaveReadWrite = CPL_TO_BOOL(EnterReadWrite(GF_Write));
    2115             : 
    2116             :     // Write block to block cache
    2117      637463 :     for (int j = 0; j < nBlocksPerColumn; ++j)
    2118             :     {
    2119     1230790 :         for (int i = 0; i < nBlocksPerRow; ++i)
    2120             :         {
    2121      762562 :             GDALRasterBlock *destBlock = GetLockedBlockRef(i, j, TRUE);
    2122      762562 :             if (destBlock == nullptr)
    2123             :             {
    2124           0 :                 ReportError(CE_Failure, CPLE_OutOfMemory,
    2125             :                             "GDALRasterBand::Fill(): Error "
    2126             :                             "while retrieving cache block.");
    2127           0 :                 VSIFree(srcBlock);
    2128           0 :                 return CE_Failure;
    2129             :             }
    2130      762562 :             memcpy(destBlock->GetDataRef(), srcBlock, blockByteSize);
    2131      762562 :             destBlock->MarkDirty();
    2132      762562 :             destBlock->DropLock();
    2133             :         }
    2134             :     }
    2135             : 
    2136      169234 :     if (bCallLeaveReadWrite)
    2137      168757 :         LeaveReadWrite();
    2138             : 
    2139             :     // Free up the source block
    2140      169234 :     VSIFree(srcBlock);
    2141             : 
    2142      169234 :     return CE_None;
    2143             : }
    2144             : 
    2145             : /************************************************************************/
    2146             : /*                         GDALFillRaster()                             */
    2147             : /************************************************************************/
    2148             : 
    2149             : /**
    2150             :  * \brief Fill this band with a constant value.
    2151             :  *
    2152             :  * @see GDALRasterBand::Fill()
    2153             :  */
    2154      169202 : CPLErr CPL_STDCALL GDALFillRaster(GDALRasterBandH hBand, double dfRealValue,
    2155             :                                   double dfImaginaryValue)
    2156             : {
    2157      169202 :     VALIDATE_POINTER1(hBand, "GDALFillRaster", CE_Failure);
    2158             : 
    2159      169202 :     GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
    2160      169202 :     return poBand->Fill(dfRealValue, dfImaginaryValue);
    2161             : }
    2162             : 
    2163             : /************************************************************************/
    2164             : /*                             GetAccess()                              */
    2165             : /************************************************************************/
    2166             : 
    2167             : /**
    2168             :  * \brief Find out if we have update permission for this band.
    2169             :  *
    2170             :  * This method is the same as the C function GDALGetRasterAccess().
    2171             :  *
    2172             :  * @return Either GA_Update or GA_ReadOnly.
    2173             :  */
    2174             : 
    2175        2524 : GDALAccess GDALRasterBand::GetAccess()
    2176             : 
    2177             : {
    2178        2524 :     return eAccess;
    2179             : }
    2180             : 
    2181             : /************************************************************************/
    2182             : /*                        GDALGetRasterAccess()                         */
    2183             : /************************************************************************/
    2184             : 
    2185             : /**
    2186             :  * \brief Find out if we have update permission for this band.
    2187             :  *
    2188             :  * @see GDALRasterBand::GetAccess()
    2189             :  */
    2190             : 
    2191        1878 : GDALAccess CPL_STDCALL GDALGetRasterAccess(GDALRasterBandH hBand)
    2192             : 
    2193             : {
    2194        1878 :     VALIDATE_POINTER1(hBand, "GDALGetRasterAccess", GA_ReadOnly);
    2195             : 
    2196        1878 :     GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
    2197        1878 :     return poBand->GetAccess();
    2198             : }
    2199             : 
    2200             : /************************************************************************/
    2201             : /*                          GetCategoryNames()                          */
    2202             : /************************************************************************/
    2203             : 
    2204             : /**
    2205             :  * \brief Fetch the list of category names for this raster.
    2206             :  *
    2207             :  * The return list is a "StringList" in the sense of the CPL functions.
    2208             :  * That is a NULL terminated array of strings.  Raster values without
    2209             :  * associated names will have an empty string in the returned list.  The
    2210             :  * first entry in the list is for raster values of zero, and so on.
    2211             :  *
    2212             :  * The returned stringlist should not be altered or freed by the application.
    2213             :  * It may change on the next GDAL call, so please copy it if it is needed
    2214             :  * for any period of time.
    2215             :  *
    2216             :  * This method is the same as the C function GDALGetRasterCategoryNames().
    2217             :  *
    2218             :  * @return list of names, or NULL if none.
    2219             :  */
    2220             : 
    2221         234 : char **GDALRasterBand::GetCategoryNames()
    2222             : 
    2223             : {
    2224         234 :     return nullptr;
    2225             : }
    2226             : 
    2227             : /************************************************************************/
    2228             : /*                     GDALGetRasterCategoryNames()                     */
    2229             : /************************************************************************/
    2230             : 
    2231             : /**
    2232             :  * \brief Fetch the list of category names for this raster.
    2233             :  *
    2234             :  * @see GDALRasterBand::GetCategoryNames()
    2235             :  */
    2236             : 
    2237         175 : char **CPL_STDCALL GDALGetRasterCategoryNames(GDALRasterBandH hBand)
    2238             : 
    2239             : {
    2240         175 :     VALIDATE_POINTER1(hBand, "GDALGetRasterCategoryNames", nullptr);
    2241             : 
    2242         175 :     GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
    2243         175 :     return poBand->GetCategoryNames();
    2244             : }
    2245             : 
    2246             : /************************************************************************/
    2247             : /*                          SetCategoryNames()                          */
    2248             : /************************************************************************/
    2249             : 
    2250             : /**
    2251             :  * \fn GDALRasterBand::SetCategoryNames(char**)
    2252             :  * \brief Set the category names for this band.
    2253             :  *
    2254             :  * See the GetCategoryNames() method for more on the interpretation of
    2255             :  * category names.
    2256             :  *
    2257             :  * This method is the same as the C function GDALSetRasterCategoryNames().
    2258             :  *
    2259             :  * @param papszNames the NULL terminated StringList of category names.  May
    2260             :  * be NULL to just clear the existing list.
    2261             :  *
    2262             :  * @return CE_None on success of CE_Failure on failure.  If unsupported
    2263             :  * by the driver CE_Failure is returned, but no error message is reported.
    2264             :  */
    2265             : 
    2266             : /**/
    2267             : /**/
    2268             : 
    2269           0 : CPLErr GDALRasterBand::SetCategoryNames(char ** /*papszNames*/)
    2270             : {
    2271           0 :     if (!(GetMOFlags() & GMO_IGNORE_UNIMPLEMENTED))
    2272           0 :         ReportError(CE_Failure, CPLE_NotSupported,
    2273             :                     "SetCategoryNames() not supported for this dataset.");
    2274             : 
    2275           0 :     return CE_Failure;
    2276             : }
    2277             : 
    2278             : /************************************************************************/
    2279             : /*                        GDALSetCategoryNames()                        */
    2280             : /************************************************************************/
    2281             : 
    2282             : /**
    2283             :  * \brief Set the category names for this band.
    2284             :  *
    2285             :  * @see GDALRasterBand::SetCategoryNames()
    2286             :  */
    2287             : 
    2288           2 : CPLErr CPL_STDCALL GDALSetRasterCategoryNames(GDALRasterBandH hBand,
    2289             :                                               CSLConstList papszNames)
    2290             : 
    2291             : {
    2292           2 :     VALIDATE_POINTER1(hBand, "GDALSetRasterCategoryNames", CE_Failure);
    2293             : 
    2294           2 :     GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
    2295           2 :     return poBand->SetCategoryNames(const_cast<char **>(papszNames));
    2296             : }
    2297             : 
    2298             : /************************************************************************/
    2299             : /*                           GetNoDataValue()                           */
    2300             : /************************************************************************/
    2301             : 
    2302             : /**
    2303             :  * \brief Fetch the no data value for this band.
    2304             :  *
    2305             :  * If there is no out of data value, an out of range value will generally
    2306             :  * be returned.  The no data value for a band is generally a special marker
    2307             :  * value used to mark pixels that are not valid data.  Such pixels should
    2308             :  * generally not be displayed, nor contribute to analysis operations.
    2309             :  *
    2310             :  * The no data value returned is 'raw', meaning that it has no offset and
    2311             :  * scale applied.
    2312             :  *
    2313             :  * For rasters of type GDT_Int64 or GDT_UInt64, using this method might be
    2314             :  * lossy if the nodata value cannot exactly been represented by a double.
    2315             :  * Use GetNoDataValueAsInt64() or GetNoDataValueAsUInt64() instead.
    2316             :  *
    2317             :  * This method is the same as the C function GDALGetRasterNoDataValue().
    2318             :  *
    2319             :  * @param pbSuccess pointer to a boolean to use to indicate if a value
    2320             :  * is actually associated with this layer.  May be NULL (default).
    2321             :  *
    2322             :  * @return the nodata value for this band.
    2323             :  */
    2324             : 
    2325       31410 : double GDALRasterBand::GetNoDataValue(int *pbSuccess)
    2326             : 
    2327             : {
    2328       31410 :     if (pbSuccess != nullptr)
    2329       31410 :         *pbSuccess = FALSE;
    2330             : 
    2331       31410 :     return -1e10;
    2332             : }
    2333             : 
    2334             : /************************************************************************/
    2335             : /*                      GDALGetRasterNoDataValue()                      */
    2336             : /************************************************************************/
    2337             : 
    2338             : /**
    2339             :  * \brief Fetch the no data value for this band.
    2340             :  *
    2341             :  * @see GDALRasterBand::GetNoDataValue()
    2342             :  */
    2343             : 
    2344      413821 : double CPL_STDCALL GDALGetRasterNoDataValue(GDALRasterBandH hBand,
    2345             :                                             int *pbSuccess)
    2346             : 
    2347             : {
    2348      413821 :     VALIDATE_POINTER1(hBand, "GDALGetRasterNoDataValue", 0);
    2349             : 
    2350      413821 :     GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
    2351      413821 :     return poBand->GetNoDataValue(pbSuccess);
    2352             : }
    2353             : 
    2354             : /************************************************************************/
    2355             : /*                       GetNoDataValueAsInt64()                        */
    2356             : /************************************************************************/
    2357             : 
    2358             : /**
    2359             :  * \brief Fetch the no data value for this band.
    2360             :  *
    2361             :  * This method should ONLY be called on rasters whose data type is GDT_Int64.
    2362             :  *
    2363             :  * If there is no out of data value, an out of range value will generally
    2364             :  * be returned.  The no data value for a band is generally a special marker
    2365             :  * value used to mark pixels that are not valid data.  Such pixels should
    2366             :  * generally not be displayed, nor contribute to analysis operations.
    2367             :  *
    2368             :  * The no data value returned is 'raw', meaning that it has no offset and
    2369             :  * scale applied.
    2370             :  *
    2371             :  * This method is the same as the C function GDALGetRasterNoDataValueAsInt64().
    2372             :  *
    2373             :  * @param pbSuccess pointer to a boolean to use to indicate if a value
    2374             :  * is actually associated with this layer.  May be NULL (default).
    2375             :  *
    2376             :  * @return the nodata value for this band.
    2377             :  *
    2378             :  * @since GDAL 3.5
    2379             :  */
    2380             : 
    2381           4 : int64_t GDALRasterBand::GetNoDataValueAsInt64(int *pbSuccess)
    2382             : 
    2383             : {
    2384           4 :     if (pbSuccess != nullptr)
    2385           4 :         *pbSuccess = FALSE;
    2386             : 
    2387           4 :     return std::numeric_limits<int64_t>::min();
    2388             : }
    2389             : 
    2390             : /************************************************************************/
    2391             : /*                   GDALGetRasterNoDataValueAsInt64()                  */
    2392             : /************************************************************************/
    2393             : 
    2394             : /**
    2395             :  * \brief Fetch the no data value for this band.
    2396             :  *
    2397             :  * This function should ONLY be called on rasters whose data type is GDT_Int64.
    2398             :  *
    2399             :  * @see GDALRasterBand::GetNoDataValueAsInt64()
    2400             :  *
    2401             :  * @since GDAL 3.5
    2402             :  */
    2403             : 
    2404          23 : int64_t CPL_STDCALL GDALGetRasterNoDataValueAsInt64(GDALRasterBandH hBand,
    2405             :                                                     int *pbSuccess)
    2406             : 
    2407             : {
    2408          23 :     VALIDATE_POINTER1(hBand, "GDALGetRasterNoDataValueAsInt64",
    2409             :                       std::numeric_limits<int64_t>::min());
    2410             : 
    2411          23 :     GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
    2412          23 :     return poBand->GetNoDataValueAsInt64(pbSuccess);
    2413             : }
    2414             : 
    2415             : /************************************************************************/
    2416             : /*                       GetNoDataValueAsUInt64()                        */
    2417             : /************************************************************************/
    2418             : 
    2419             : /**
    2420             :  * \brief Fetch the no data value for this band.
    2421             :  *
    2422             :  * This method should ONLY be called on rasters whose data type is GDT_UInt64.
    2423             :  *
    2424             :  * If there is no out of data value, an out of range value will generally
    2425             :  * be returned.  The no data value for a band is generally a special marker
    2426             :  * value used to mark pixels that are not valid data.  Such pixels should
    2427             :  * generally not be displayed, nor contribute to analysis operations.
    2428             :  *
    2429             :  * The no data value returned is 'raw', meaning that it has no offset and
    2430             :  * scale applied.
    2431             :  *
    2432             :  * This method is the same as the C function GDALGetRasterNoDataValueAsUInt64().
    2433             :  *
    2434             :  * @param pbSuccess pointer to a boolean to use to indicate if a value
    2435             :  * is actually associated with this layer.  May be NULL (default).
    2436             :  *
    2437             :  * @return the nodata value for this band.
    2438             :  *
    2439             :  * @since GDAL 3.5
    2440             :  */
    2441             : 
    2442           3 : uint64_t GDALRasterBand::GetNoDataValueAsUInt64(int *pbSuccess)
    2443             : 
    2444             : {
    2445           3 :     if (pbSuccess != nullptr)
    2446           3 :         *pbSuccess = FALSE;
    2447             : 
    2448           3 :     return std::numeric_limits<uint64_t>::max();
    2449             : }
    2450             : 
    2451             : /************************************************************************/
    2452             : /*                   GDALGetRasterNoDataValueAsUInt64()                  */
    2453             : /************************************************************************/
    2454             : 
    2455             : /**
    2456             :  * \brief Fetch the no data value for this band.
    2457             :  *
    2458             :  * This function should ONLY be called on rasters whose data type is GDT_UInt64.
    2459             :  *
    2460             :  * @see GDALRasterBand::GetNoDataValueAsUInt64()
    2461             :  *
    2462             :  * @since GDAL 3.5
    2463             :  */
    2464             : 
    2465          18 : uint64_t CPL_STDCALL GDALGetRasterNoDataValueAsUInt64(GDALRasterBandH hBand,
    2466             :                                                       int *pbSuccess)
    2467             : 
    2468             : {
    2469          18 :     VALIDATE_POINTER1(hBand, "GDALGetRasterNoDataValueAsUInt64",
    2470             :                       std::numeric_limits<uint64_t>::max());
    2471             : 
    2472          18 :     GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
    2473          18 :     return poBand->GetNoDataValueAsUInt64(pbSuccess);
    2474             : }
    2475             : 
    2476             : /************************************************************************/
    2477             : /*                           SetNoDataValue()                           */
    2478             : /************************************************************************/
    2479             : 
    2480             : /**
    2481             :  * \fn GDALRasterBand::SetNoDataValue(double)
    2482             :  * \brief Set the no data value for this band.
    2483             :  *
    2484             :  * Depending on drivers, changing the no data value may or may not have an
    2485             :  * effect on the pixel values of a raster that has just been created. It is
    2486             :  * thus advised to explicitly called Fill() if the intent is to initialize
    2487             :  * the raster to the nodata value.
    2488             :  * In any case, changing an existing no data value, when one already exists and
    2489             :  * the dataset exists or has been initialized, has no effect on the pixel whose
    2490             :  * value matched the previous nodata value.
    2491             :  *
    2492             :  * For rasters of type GDT_Int64 or GDT_UInt64, whose nodata value cannot always
    2493             :  * be represented by a double, use SetNoDataValueAsInt64() or
    2494             :  * SetNoDataValueAsUInt64() instead.
    2495             :  *
    2496             :  * To clear the nodata value, use DeleteNoDataValue().
    2497             :  *
    2498             :  * This method is the same as the C function GDALSetRasterNoDataValue().
    2499             :  *
    2500             :  * @param dfNoData the value to set.
    2501             :  *
    2502             :  * @return CE_None on success, or CE_Failure on failure.  If unsupported
    2503             :  * by the driver, CE_Failure is returned by no error message will have
    2504             :  * been emitted.
    2505             :  */
    2506             : 
    2507             : /**/
    2508             : /**/
    2509             : 
    2510           0 : CPLErr GDALRasterBand::SetNoDataValue(double /*dfNoData*/)
    2511             : 
    2512             : {
    2513           0 :     if (!(GetMOFlags() & GMO_IGNORE_UNIMPLEMENTED))
    2514           0 :         ReportError(CE_Failure, CPLE_NotSupported,
    2515             :                     "SetNoDataValue() not supported for this dataset.");
    2516             : 
    2517           0 :     return CE_Failure;
    2518             : }
    2519             : 
    2520             : /************************************************************************/
    2521             : /*                         GDALSetRasterNoDataValue()                   */
    2522             : /************************************************************************/
    2523             : 
    2524             : /**
    2525             :  * \brief Set the no data value for this band.
    2526             :  *
    2527             :  * Depending on drivers, changing the no data value may or may not have an
    2528             :  * effect on the pixel values of a raster that has just been created. It is
    2529             :  * thus advised to explicitly called Fill() if the intent is to initialize
    2530             :  * the raster to the nodata value.
    2531             :  * In any case, changing an existing no data value, when one already exists and
    2532             :  * the dataset exists or has been initialized, has no effect on the pixel whose
    2533             :  * value matched the previous nodata value.
    2534             :  *
    2535             :  * For rasters of type GDT_Int64 or GDT_UInt64, whose nodata value cannot always
    2536             :  * be represented by a double, use GDALSetRasterNoDataValueAsInt64() or
    2537             :  * GDALSetRasterNoDataValueAsUInt64() instead.
    2538             :  *
    2539             :  * @see GDALRasterBand::SetNoDataValue()
    2540             :  */
    2541             : 
    2542         712 : CPLErr CPL_STDCALL GDALSetRasterNoDataValue(GDALRasterBandH hBand,
    2543             :                                             double dfValue)
    2544             : 
    2545             : {
    2546         712 :     VALIDATE_POINTER1(hBand, "GDALSetRasterNoDataValue", CE_Failure);
    2547             : 
    2548         712 :     GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
    2549         712 :     return poBand->SetNoDataValue(dfValue);
    2550             : }
    2551             : 
    2552             : /************************************************************************/
    2553             : /*                       SetNoDataValueAsInt64()                        */
    2554             : /************************************************************************/
    2555             : 
    2556             : /**
    2557             :  * \brief Set the no data value for this band.
    2558             :  *
    2559             :  * This method should ONLY be called on rasters whose data type is GDT_Int64.
    2560             :  *
    2561             :  * Depending on drivers, changing the no data value may or may not have an
    2562             :  * effect on the pixel values of a raster that has just been created. It is
    2563             :  * thus advised to explicitly called Fill() if the intent is to initialize
    2564             :  * the raster to the nodata value.
    2565             :  * In ay case, changing an existing no data value, when one already exists and
    2566             :  * the dataset exists or has been initialized, has no effect on the pixel whose
    2567             :  * value matched the previous nodata value.
    2568             :  *
    2569             :  * To clear the nodata value, use DeleteNoDataValue().
    2570             :  *
    2571             :  * This method is the same as the C function GDALSetRasterNoDataValueAsInt64().
    2572             :  *
    2573             :  * @param nNoDataValue the value to set.
    2574             :  *
    2575             :  * @return CE_None on success, or CE_Failure on failure.  If unsupported
    2576             :  * by the driver, CE_Failure is returned by no error message will have
    2577             :  * been emitted.
    2578             :  *
    2579             :  * @since GDAL 3.5
    2580             :  */
    2581             : 
    2582           0 : CPLErr GDALRasterBand::SetNoDataValueAsInt64(CPL_UNUSED int64_t nNoDataValue)
    2583             : 
    2584             : {
    2585           0 :     if (!(GetMOFlags() & GMO_IGNORE_UNIMPLEMENTED))
    2586           0 :         ReportError(CE_Failure, CPLE_NotSupported,
    2587             :                     "SetNoDataValueAsInt64() not supported for this dataset.");
    2588             : 
    2589           0 :     return CE_Failure;
    2590             : }
    2591             : 
    2592             : /************************************************************************/
    2593             : /*                 GDALSetRasterNoDataValueAsInt64()                    */
    2594             : /************************************************************************/
    2595             : 
    2596             : /**
    2597             :  * \brief Set the no data value for this band.
    2598             :  *
    2599             :  * This function should ONLY be called on rasters whose data type is GDT_Int64.
    2600             :  *
    2601             :  * Depending on drivers, changing the no data value may or may not have an
    2602             :  * effect on the pixel values of a raster that has just been created. It is
    2603             :  * thus advised to explicitly called Fill() if the intent is to initialize
    2604             :  * the raster to the nodata value.
    2605             :  * In ay case, changing an existing no data value, when one already exists and
    2606             :  * the dataset exists or has been initialized, has no effect on the pixel whose
    2607             :  * value matched the previous nodata value.
    2608             :  *
    2609             :  * @see GDALRasterBand::SetNoDataValueAsInt64()
    2610             :  *
    2611             :  * @since GDAL 3.5
    2612             :  */
    2613             : 
    2614          18 : CPLErr CPL_STDCALL GDALSetRasterNoDataValueAsInt64(GDALRasterBandH hBand,
    2615             :                                                    int64_t nValue)
    2616             : 
    2617             : {
    2618          18 :     VALIDATE_POINTER1(hBand, "GDALSetRasterNoDataValueAsInt64", CE_Failure);
    2619             : 
    2620          18 :     GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
    2621          18 :     return poBand->SetNoDataValueAsInt64(nValue);
    2622             : }
    2623             : 
    2624             : /************************************************************************/
    2625             : /*                       SetNoDataValueAsUInt64()                       */
    2626             : /************************************************************************/
    2627             : 
    2628             : /**
    2629             :  * \brief Set the no data value for this band.
    2630             :  *
    2631             :  * This method should ONLY be called on rasters whose data type is GDT_UInt64.
    2632             :  *
    2633             :  * Depending on drivers, changing the no data value may or may not have an
    2634             :  * effect on the pixel values of a raster that has just been created. It is
    2635             :  * thus advised to explicitly called Fill() if the intent is to initialize
    2636             :  * the raster to the nodata value.
    2637             :  * In ay case, changing an existing no data value, when one already exists and
    2638             :  * the dataset exists or has been initialized, has no effect on the pixel whose
    2639             :  * value matched the previous nodata value.
    2640             :  *
    2641             :  * To clear the nodata value, use DeleteNoDataValue().
    2642             :  *
    2643             :  * This method is the same as the C function GDALSetRasterNoDataValueAsUInt64().
    2644             :  *
    2645             :  * @param nNoDataValue the value to set.
    2646             :  *
    2647             :  * @return CE_None on success, or CE_Failure on failure.  If unsupported
    2648             :  * by the driver, CE_Failure is returned by no error message will have
    2649             :  * been emitted.
    2650             :  *
    2651             :  * @since GDAL 3.5
    2652             :  */
    2653             : 
    2654           0 : CPLErr GDALRasterBand::SetNoDataValueAsUInt64(CPL_UNUSED uint64_t nNoDataValue)
    2655             : 
    2656             : {
    2657           0 :     if (!(GetMOFlags() & GMO_IGNORE_UNIMPLEMENTED))
    2658           0 :         ReportError(CE_Failure, CPLE_NotSupported,
    2659             :                     "SetNoDataValueAsUInt64() not supported for this dataset.");
    2660             : 
    2661           0 :     return CE_Failure;
    2662             : }
    2663             : 
    2664             : /************************************************************************/
    2665             : /*                 GDALSetRasterNoDataValueAsUInt64()                    */
    2666             : /************************************************************************/
    2667             : 
    2668             : /**
    2669             :  * \brief Set the no data value for this band.
    2670             :  *
    2671             :  * This function should ONLY be called on rasters whose data type is GDT_UInt64.
    2672             :  *
    2673             :  * Depending on drivers, changing the no data value may or may not have an
    2674             :  * effect on the pixel values of a raster that has just been created. It is
    2675             :  * thus advised to explicitly called Fill() if the intent is to initialize
    2676             :  * the raster to the nodata value.
    2677             :  * In ay case, changing an existing no data value, when one already exists and
    2678             :  * the dataset exists or has been initialized, has no effect on the pixel whose
    2679             :  * value matched the previous nodata value.
    2680             :  *
    2681             :  * @see GDALRasterBand::SetNoDataValueAsUInt64()
    2682             :  *
    2683             :  * @since GDAL 3.5
    2684             :  */
    2685             : 
    2686          16 : CPLErr CPL_STDCALL GDALSetRasterNoDataValueAsUInt64(GDALRasterBandH hBand,
    2687             :                                                     uint64_t nValue)
    2688             : 
    2689             : {
    2690          16 :     VALIDATE_POINTER1(hBand, "GDALSetRasterNoDataValueAsUInt64", CE_Failure);
    2691             : 
    2692          16 :     GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
    2693          16 :     return poBand->SetNoDataValueAsUInt64(nValue);
    2694             : }
    2695             : 
    2696             : /************************************************************************/
    2697             : /*                        DeleteNoDataValue()                           */
    2698             : /************************************************************************/
    2699             : 
    2700             : /**
    2701             :  * \brief Remove the no data value for this band.
    2702             :  *
    2703             :  * This method is the same as the C function GDALDeleteRasterNoDataValue().
    2704             :  *
    2705             :  * @return CE_None on success, or CE_Failure on failure.  If unsupported
    2706             :  * by the driver, CE_Failure is returned by no error message will have
    2707             :  * been emitted.
    2708             :  *
    2709             :  * @since GDAL 2.1
    2710             :  */
    2711             : 
    2712           0 : CPLErr GDALRasterBand::DeleteNoDataValue()
    2713             : 
    2714             : {
    2715           0 :     if (!(GetMOFlags() & GMO_IGNORE_UNIMPLEMENTED))
    2716           0 :         ReportError(CE_Failure, CPLE_NotSupported,
    2717             :                     "DeleteNoDataValue() not supported for this dataset.");
    2718             : 
    2719           0 :     return CE_Failure;
    2720             : }
    2721             : 
    2722             : /************************************************************************/
    2723             : /*                       GDALDeleteRasterNoDataValue()                  */
    2724             : /************************************************************************/
    2725             : 
    2726             : /**
    2727             :  * \brief Remove the no data value for this band.
    2728             :  *
    2729             :  * @see GDALRasterBand::DeleteNoDataValue()
    2730             :  *
    2731             :  * @since GDAL 2.1
    2732             :  */
    2733             : 
    2734          41 : CPLErr CPL_STDCALL GDALDeleteRasterNoDataValue(GDALRasterBandH hBand)
    2735             : 
    2736             : {
    2737          41 :     VALIDATE_POINTER1(hBand, "GDALDeleteRasterNoDataValue", CE_Failure);
    2738             : 
    2739          41 :     GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
    2740          41 :     return poBand->DeleteNoDataValue();
    2741             : }
    2742             : 
    2743             : /************************************************************************/
    2744             : /*                             GetMaximum()                             */
    2745             : /************************************************************************/
    2746             : 
    2747             : /**
    2748             :  * \brief Fetch the maximum value for this band.
    2749             :  *
    2750             :  * For file formats that don't know this intrinsically, the maximum supported
    2751             :  * value for the data type will generally be returned.
    2752             :  *
    2753             :  * This method is the same as the C function GDALGetRasterMaximum().
    2754             :  *
    2755             :  * @param pbSuccess pointer to a boolean to use to indicate if the
    2756             :  * returned value is a tight maximum or not.  May be NULL (default).
    2757             :  *
    2758             :  * @return the maximum raster value (excluding no data pixels)
    2759             :  */
    2760             : 
    2761         492 : double GDALRasterBand::GetMaximum(int *pbSuccess)
    2762             : 
    2763             : {
    2764         492 :     const char *pszValue = nullptr;
    2765             : 
    2766         492 :     if ((pszValue = GetMetadataItem("STATISTICS_MAXIMUM")) != nullptr)
    2767             :     {
    2768          46 :         if (pbSuccess != nullptr)
    2769          41 :             *pbSuccess = TRUE;
    2770             : 
    2771          46 :         return CPLAtofM(pszValue);
    2772             :     }
    2773             : 
    2774         446 :     if (pbSuccess != nullptr)
    2775         414 :         *pbSuccess = FALSE;
    2776             : 
    2777         446 :     switch (eDataType)
    2778             :     {
    2779         317 :         case GDT_Byte:
    2780             :         {
    2781         317 :             EnablePixelTypeSignedByteWarning(false);
    2782             :             const char *pszPixelType =
    2783         317 :                 GetMetadataItem("PIXELTYPE", "IMAGE_STRUCTURE");
    2784         317 :             EnablePixelTypeSignedByteWarning(true);
    2785         317 :             if (pszPixelType != nullptr && EQUAL(pszPixelType, "SIGNEDBYTE"))
    2786           0 :                 return 127;
    2787             : 
    2788         317 :             return 255;
    2789             :         }
    2790             : 
    2791           0 :         case GDT_Int8:
    2792           0 :             return 127;
    2793             : 
    2794          19 :         case GDT_UInt16:
    2795          19 :             return 65535;
    2796             : 
    2797          24 :         case GDT_Int16:
    2798             :         case GDT_CInt16:
    2799          24 :             return 32767;
    2800             : 
    2801          17 :         case GDT_Int32:
    2802             :         case GDT_CInt32:
    2803          17 :             return 2147483647.0;
    2804             : 
    2805          13 :         case GDT_UInt32:
    2806          13 :             return 4294967295.0;
    2807             : 
    2808           0 :         case GDT_Int64:
    2809           0 :             return static_cast<double>(std::numeric_limits<GInt64>::max());
    2810             : 
    2811           0 :         case GDT_UInt64:
    2812           0 :             return static_cast<double>(std::numeric_limits<GUInt64>::max());
    2813             : 
    2814           0 :         case GDT_Float16:
    2815             :         case GDT_CFloat16:
    2816           0 :             return 65504.0;
    2817             : 
    2818          32 :         case GDT_Float32:
    2819             :         case GDT_CFloat32:
    2820          32 :             return 4294967295.0;  // Not actually accurate.
    2821             : 
    2822          24 :         case GDT_Float64:
    2823             :         case GDT_CFloat64:
    2824          24 :             return 4294967295.0;  // Not actually accurate.
    2825             : 
    2826           0 :         case GDT_Unknown:
    2827             :         case GDT_TypeCount:
    2828           0 :             break;
    2829             :     }
    2830           0 :     return 4294967295.0;  // Not actually accurate.
    2831             : }
    2832             : 
    2833             : /************************************************************************/
    2834             : /*                        GDALGetRasterMaximum()                        */
    2835             : /************************************************************************/
    2836             : 
    2837             : /**
    2838             :  * \brief Fetch the maximum value for this band.
    2839             :  *
    2840             :  * @see GDALRasterBand::GetMaximum()
    2841             :  */
    2842             : 
    2843         248 : double CPL_STDCALL GDALGetRasterMaximum(GDALRasterBandH hBand, int *pbSuccess)
    2844             : 
    2845             : {
    2846         248 :     VALIDATE_POINTER1(hBand, "GDALGetRasterMaximum", 0);
    2847             : 
    2848         248 :     GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
    2849         248 :     return poBand->GetMaximum(pbSuccess);
    2850             : }
    2851             : 
    2852             : /************************************************************************/
    2853             : /*                             GetMinimum()                             */
    2854             : /************************************************************************/
    2855             : 
    2856             : /**
    2857             :  * \brief Fetch the minimum value for this band.
    2858             :  *
    2859             :  * For file formats that don't know this intrinsically, the minimum supported
    2860             :  * value for the data type will generally be returned.
    2861             :  *
    2862             :  * This method is the same as the C function GDALGetRasterMinimum().
    2863             :  *
    2864             :  * @param pbSuccess pointer to a boolean to use to indicate if the
    2865             :  * returned value is a tight minimum or not.  May be NULL (default).
    2866             :  *
    2867             :  * @return the minimum raster value (excluding no data pixels)
    2868             :  */
    2869             : 
    2870         500 : double GDALRasterBand::GetMinimum(int *pbSuccess)
    2871             : 
    2872             : {
    2873         500 :     const char *pszValue = nullptr;
    2874             : 
    2875         500 :     if ((pszValue = GetMetadataItem("STATISTICS_MINIMUM")) != nullptr)
    2876             :     {
    2877          51 :         if (pbSuccess != nullptr)
    2878          46 :             *pbSuccess = TRUE;
    2879             : 
    2880          51 :         return CPLAtofM(pszValue);
    2881             :     }
    2882             : 
    2883         449 :     if (pbSuccess != nullptr)
    2884         417 :         *pbSuccess = FALSE;
    2885             : 
    2886         449 :     switch (eDataType)
    2887             :     {
    2888         320 :         case GDT_Byte:
    2889             :         {
    2890         320 :             EnablePixelTypeSignedByteWarning(false);
    2891             :             const char *pszPixelType =
    2892         320 :                 GetMetadataItem("PIXELTYPE", "IMAGE_STRUCTURE");
    2893         320 :             EnablePixelTypeSignedByteWarning(true);
    2894         320 :             if (pszPixelType != nullptr && EQUAL(pszPixelType, "SIGNEDBYTE"))
    2895           0 :                 return -128;
    2896             : 
    2897         320 :             return 0;
    2898             :         }
    2899             : 
    2900           0 :         case GDT_Int8:
    2901           0 :             return -128;
    2902             :             break;
    2903             : 
    2904          19 :         case GDT_UInt16:
    2905          19 :             return 0;
    2906             : 
    2907          24 :         case GDT_Int16:
    2908             :         case GDT_CInt16:
    2909          24 :             return -32768;
    2910             : 
    2911          17 :         case GDT_Int32:
    2912             :         case GDT_CInt32:
    2913          17 :             return -2147483648.0;
    2914             : 
    2915          13 :         case GDT_UInt32:
    2916          13 :             return 0;
    2917             : 
    2918           0 :         case GDT_Int64:
    2919           0 :             return static_cast<double>(std::numeric_limits<GInt64>::lowest());
    2920             : 
    2921           0 :         case GDT_UInt64:
    2922           0 :             return 0;
    2923             : 
    2924           0 :         case GDT_Float16:
    2925             :         case GDT_CFloat16:
    2926           0 :             return -65504.0;
    2927             : 
    2928          32 :         case GDT_Float32:
    2929             :         case GDT_CFloat32:
    2930          32 :             return -4294967295.0;  // Not actually accurate.
    2931             : 
    2932          24 :         case GDT_Float64:
    2933             :         case GDT_CFloat64:
    2934          24 :             return -4294967295.0;  // Not actually accurate.
    2935             : 
    2936           0 :         case GDT_Unknown:
    2937             :         case GDT_TypeCount:
    2938           0 :             break;
    2939             :     }
    2940           0 :     return -4294967295.0;  // Not actually accurate.
    2941             : }
    2942             : 
    2943             : /************************************************************************/
    2944             : /*                        GDALGetRasterMinimum()                        */
    2945             : /************************************************************************/
    2946             : 
    2947             : /**
    2948             :  * \brief Fetch the minimum value for this band.
    2949             :  *
    2950             :  * @see GDALRasterBand::GetMinimum()
    2951             :  */
    2952             : 
    2953         258 : double CPL_STDCALL GDALGetRasterMinimum(GDALRasterBandH hBand, int *pbSuccess)
    2954             : 
    2955             : {
    2956         258 :     VALIDATE_POINTER1(hBand, "GDALGetRasterMinimum", 0);
    2957             : 
    2958         258 :     GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
    2959         258 :     return poBand->GetMinimum(pbSuccess);
    2960             : }
    2961             : 
    2962             : /************************************************************************/
    2963             : /*                       GetColorInterpretation()                       */
    2964             : /************************************************************************/
    2965             : 
    2966             : /**
    2967             :  * \brief How should this band be interpreted as color?
    2968             :  *
    2969             :  * GCI_Undefined is returned when the format doesn't know anything
    2970             :  * about the color interpretation.
    2971             :  *
    2972             :  * This method is the same as the C function
    2973             :  * GDALGetRasterColorInterpretation().
    2974             :  *
    2975             :  * @return color interpretation value for band.
    2976             :  */
    2977             : 
    2978         115 : GDALColorInterp GDALRasterBand::GetColorInterpretation()
    2979             : 
    2980             : {
    2981         115 :     return GCI_Undefined;
    2982             : }
    2983             : 
    2984             : /************************************************************************/
    2985             : /*                  GDALGetRasterColorInterpretation()                  */
    2986             : /************************************************************************/
    2987             : 
    2988             : /**
    2989             :  * \brief How should this band be interpreted as color?
    2990             :  *
    2991             :  * @see GDALRasterBand::GetColorInterpretation()
    2992             :  */
    2993             : 
    2994             : GDALColorInterp CPL_STDCALL
    2995        5128 : GDALGetRasterColorInterpretation(GDALRasterBandH hBand)
    2996             : 
    2997             : {
    2998        5128 :     VALIDATE_POINTER1(hBand, "GDALGetRasterColorInterpretation", GCI_Undefined);
    2999             : 
    3000        5128 :     GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
    3001        5128 :     return poBand->GetColorInterpretation();
    3002             : }
    3003             : 
    3004             : /************************************************************************/
    3005             : /*                       SetColorInterpretation()                       */
    3006             : /************************************************************************/
    3007             : 
    3008             : /**
    3009             :  * \fn GDALRasterBand::SetColorInterpretation(GDALColorInterp)
    3010             :  * \brief Set color interpretation of a band.
    3011             :  *
    3012             :  * This method is the same as the C function GDALSetRasterColorInterpretation().
    3013             :  *
    3014             :  * @param eColorInterp the new color interpretation to apply to this band.
    3015             :  *
    3016             :  * @return CE_None on success or CE_Failure if method is unsupported by format.
    3017             :  */
    3018             : 
    3019             : /**/
    3020             : /**/
    3021             : 
    3022           3 : CPLErr GDALRasterBand::SetColorInterpretation(GDALColorInterp /*eColorInterp*/)
    3023             : 
    3024             : {
    3025           3 :     if (!(GetMOFlags() & GMO_IGNORE_UNIMPLEMENTED))
    3026           3 :         ReportError(CE_Failure, CPLE_NotSupported,
    3027             :                     "SetColorInterpretation() not supported for this dataset.");
    3028           3 :     return CE_Failure;
    3029             : }
    3030             : 
    3031             : /************************************************************************/
    3032             : /*                  GDALSetRasterColorInterpretation()                  */
    3033             : /************************************************************************/
    3034             : 
    3035             : /**
    3036             :  * \brief Set color interpretation of a band.
    3037             :  *
    3038             :  * @see GDALRasterBand::SetColorInterpretation()
    3039             :  */
    3040             : 
    3041        1765 : CPLErr CPL_STDCALL GDALSetRasterColorInterpretation(
    3042             :     GDALRasterBandH hBand, GDALColorInterp eColorInterp)
    3043             : 
    3044             : {
    3045        1765 :     VALIDATE_POINTER1(hBand, "GDALSetRasterColorInterpretation", CE_Failure);
    3046             : 
    3047        1765 :     GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
    3048        1765 :     return poBand->SetColorInterpretation(eColorInterp);
    3049             : }
    3050             : 
    3051             : /************************************************************************/
    3052             : /*                           GetColorTable()                            */
    3053             : /************************************************************************/
    3054             : 
    3055             : /**
    3056             :  * \brief Fetch the color table associated with band.
    3057             :  *
    3058             :  * If there is no associated color table, the return result is NULL.  The
    3059             :  * returned color table remains owned by the GDALRasterBand, and can't
    3060             :  * be depended on for long, nor should it ever be modified by the caller.
    3061             :  *
    3062             :  * This method is the same as the C function GDALGetRasterColorTable().
    3063             :  *
    3064             :  * @return internal color table, or NULL.
    3065             :  */
    3066             : 
    3067         212 : GDALColorTable *GDALRasterBand::GetColorTable()
    3068             : 
    3069             : {
    3070         212 :     return nullptr;
    3071             : }
    3072             : 
    3073             : /************************************************************************/
    3074             : /*                      GDALGetRasterColorTable()                       */
    3075             : /************************************************************************/
    3076             : 
    3077             : /**
    3078             :  * \brief Fetch the color table associated with band.
    3079             :  *
    3080             :  * @see GDALRasterBand::GetColorTable()
    3081             :  */
    3082             : 
    3083        1849 : GDALColorTableH CPL_STDCALL GDALGetRasterColorTable(GDALRasterBandH hBand)
    3084             : 
    3085             : {
    3086        1849 :     VALIDATE_POINTER1(hBand, "GDALGetRasterColorTable", nullptr);
    3087             : 
    3088        1849 :     GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
    3089        1849 :     return GDALColorTable::ToHandle(poBand->GetColorTable());
    3090             : }
    3091             : 
    3092             : /************************************************************************/
    3093             : /*                           SetColorTable()                            */
    3094             : /************************************************************************/
    3095             : 
    3096             : /**
    3097             :  * \fn GDALRasterBand::SetColorTable(GDALColorTable*)
    3098             :  * \brief Set the raster color table.
    3099             :  *
    3100             :  * The driver will make a copy of all desired data in the colortable.  It
    3101             :  * remains owned by the caller after the call.
    3102             :  *
    3103             :  * This method is the same as the C function GDALSetRasterColorTable().
    3104             :  *
    3105             :  * @param poCT the color table to apply.  This may be NULL to clear the color
    3106             :  * table (where supported).
    3107             :  *
    3108             :  * @return CE_None on success, or CE_Failure on failure.  If the action is
    3109             :  * unsupported by the driver, a value of CE_Failure is returned, but no
    3110             :  * error is issued.
    3111             :  */
    3112             : 
    3113             : /**/
    3114             : /**/
    3115             : 
    3116           0 : CPLErr GDALRasterBand::SetColorTable(GDALColorTable * /*poCT*/)
    3117             : 
    3118             : {
    3119           0 :     if (!(GetMOFlags() & GMO_IGNORE_UNIMPLEMENTED))
    3120           0 :         ReportError(CE_Failure, CPLE_NotSupported,
    3121             :                     "SetColorTable() not supported for this dataset.");
    3122           0 :     return CE_Failure;
    3123             : }
    3124             : 
    3125             : /************************************************************************/
    3126             : /*                      GDALSetRasterColorTable()                       */
    3127             : /************************************************************************/
    3128             : 
    3129             : /**
    3130             :  * \brief Set the raster color table.
    3131             :  *
    3132             :  * @see GDALRasterBand::SetColorTable()
    3133             :  */
    3134             : 
    3135          76 : CPLErr CPL_STDCALL GDALSetRasterColorTable(GDALRasterBandH hBand,
    3136             :                                            GDALColorTableH hCT)
    3137             : 
    3138             : {
    3139          76 :     VALIDATE_POINTER1(hBand, "GDALSetRasterColorTable", CE_Failure);
    3140             : 
    3141          76 :     GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
    3142          76 :     return poBand->SetColorTable(GDALColorTable::FromHandle(hCT));
    3143             : }
    3144             : 
    3145             : /************************************************************************/
    3146             : /*                       HasArbitraryOverviews()                        */
    3147             : /************************************************************************/
    3148             : 
    3149             : /**
    3150             :  * \brief Check for arbitrary overviews.
    3151             :  *
    3152             :  * This returns TRUE if the underlying datastore can compute arbitrary
    3153             :  * overviews efficiently, such as is the case with OGDI over a network.
    3154             :  * Datastores with arbitrary overviews don't generally have any fixed
    3155             :  * overviews, but the RasterIO() method can be used in downsampling mode
    3156             :  * to get overview data efficiently.
    3157             :  *
    3158             :  * This method is the same as the C function GDALHasArbitraryOverviews(),
    3159             :  *
    3160             :  * @return TRUE if arbitrary overviews available (efficiently), otherwise
    3161             :  * FALSE.
    3162             :  */
    3163             : 
    3164         231 : int GDALRasterBand::HasArbitraryOverviews()
    3165             : 
    3166             : {
    3167         231 :     return FALSE;
    3168             : }
    3169             : 
    3170             : /************************************************************************/
    3171             : /*                     GDALHasArbitraryOverviews()                      */
    3172             : /************************************************************************/
    3173             : 
    3174             : /**
    3175             :  * \brief Check for arbitrary overviews.
    3176             :  *
    3177             :  * @see GDALRasterBand::HasArbitraryOverviews()
    3178             :  */
    3179             : 
    3180         165 : int CPL_STDCALL GDALHasArbitraryOverviews(GDALRasterBandH hBand)
    3181             : 
    3182             : {
    3183         165 :     VALIDATE_POINTER1(hBand, "GDALHasArbitraryOverviews", 0);
    3184             : 
    3185         165 :     GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
    3186         165 :     return poBand->HasArbitraryOverviews();
    3187             : }
    3188             : 
    3189             : /************************************************************************/
    3190             : /*                          GetOverviewCount()                          */
    3191             : /************************************************************************/
    3192             : 
    3193             : /**
    3194             :  * \brief Return the number of overview layers available.
    3195             :  *
    3196             :  * This method is the same as the C function GDALGetOverviewCount().
    3197             :  *
    3198             :  * @return overview count, zero if none.
    3199             :  */
    3200             : 
    3201      660510 : int GDALRasterBand::GetOverviewCount()
    3202             : 
    3203             : {
    3204     1316130 :     if (poDS != nullptr && poDS->oOvManager.IsInitialized() &&
    3205      655616 :         poDS->AreOverviewsEnabled())
    3206      655616 :         return poDS->oOvManager.GetOverviewCount(nBand);
    3207             : 
    3208        4894 :     return 0;
    3209             : }
    3210             : 
    3211             : /************************************************************************/
    3212             : /*                        GDALGetOverviewCount()                        */
    3213             : /************************************************************************/
    3214             : 
    3215             : /**
    3216             :  * \brief Return the number of overview layers available.
    3217             :  *
    3218             :  * @see GDALRasterBand::GetOverviewCount()
    3219             :  */
    3220             : 
    3221        3189 : int CPL_STDCALL GDALGetOverviewCount(GDALRasterBandH hBand)
    3222             : 
    3223             : {
    3224        3189 :     VALIDATE_POINTER1(hBand, "GDALGetOverviewCount", 0);
    3225             : 
    3226        3189 :     GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
    3227        3189 :     return poBand->GetOverviewCount();
    3228             : }
    3229             : 
    3230             : /************************************************************************/
    3231             : /*                            GetOverview()                             */
    3232             : /************************************************************************/
    3233             : 
    3234             : /**
    3235             :  * \brief Fetch overview raster band object.
    3236             :  *
    3237             :  * This method is the same as the C function GDALGetOverview().
    3238             :  *
    3239             :  * @param i overview index between 0 and GetOverviewCount()-1.
    3240             :  *
    3241             :  * @return overview GDALRasterBand.
    3242             :  */
    3243             : 
    3244         791 : GDALRasterBand *GDALRasterBand::GetOverview(int i)
    3245             : 
    3246             : {
    3247        1527 :     if (poDS != nullptr && poDS->oOvManager.IsInitialized() &&
    3248         736 :         poDS->AreOverviewsEnabled())
    3249         736 :         return poDS->oOvManager.GetOverview(nBand, i);
    3250             : 
    3251          55 :     return nullptr;
    3252             : }
    3253             : 
    3254             : /************************************************************************/
    3255             : /*                          GDALGetOverview()                           */
    3256             : /************************************************************************/
    3257             : 
    3258             : /**
    3259             :  * \brief Fetch overview raster band object.
    3260             :  *
    3261             :  * @see GDALRasterBand::GetOverview()
    3262             :  */
    3263             : 
    3264        5587 : GDALRasterBandH CPL_STDCALL GDALGetOverview(GDALRasterBandH hBand, int i)
    3265             : 
    3266             : {
    3267        5587 :     VALIDATE_POINTER1(hBand, "GDALGetOverview", nullptr);
    3268             : 
    3269        5587 :     GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
    3270        5587 :     return GDALRasterBand::ToHandle(poBand->GetOverview(i));
    3271             : }
    3272             : 
    3273             : /************************************************************************/
    3274             : /*                      GetRasterSampleOverview()                       */
    3275             : /************************************************************************/
    3276             : 
    3277             : /**
    3278             :  * \brief Fetch best sampling overview.
    3279             :  *
    3280             :  * Returns the most reduced overview of the given band that still satisfies
    3281             :  * the desired number of samples.  This function can be used with zero
    3282             :  * as the number of desired samples to fetch the most reduced overview.
    3283             :  * The same band as was passed in will be returned if it has not overviews,
    3284             :  * or if none of the overviews have enough samples.
    3285             :  *
    3286             :  * This method is the same as the C functions GDALGetRasterSampleOverview()
    3287             :  * and GDALGetRasterSampleOverviewEx().
    3288             :  *
    3289             :  * @param nDesiredSamples the returned band will have at least this many
    3290             :  * pixels.
    3291             :  *
    3292             :  * @return optimal overview or the band itself.
    3293             :  */
    3294             : 
    3295             : GDALRasterBand *
    3296        2006 : GDALRasterBand::GetRasterSampleOverview(GUIntBig nDesiredSamples)
    3297             : 
    3298             : {
    3299        2006 :     GDALRasterBand *poBestBand = this;
    3300             : 
    3301        2006 :     double dfBestSamples = GetXSize() * static_cast<double>(GetYSize());
    3302             : 
    3303        4023 :     for (int iOverview = 0; iOverview < GetOverviewCount(); iOverview++)
    3304             :     {
    3305        2017 :         GDALRasterBand *poOBand = GetOverview(iOverview);
    3306             : 
    3307        2017 :         if (poOBand == nullptr)
    3308           0 :             continue;
    3309             : 
    3310             :         const double dfOSamples =
    3311        2017 :             poOBand->GetXSize() * static_cast<double>(poOBand->GetYSize());
    3312             : 
    3313        2017 :         if (dfOSamples < dfBestSamples && dfOSamples > nDesiredSamples)
    3314             :         {
    3315        2014 :             dfBestSamples = dfOSamples;
    3316        2014 :             poBestBand = poOBand;
    3317             :         }
    3318             :     }
    3319             : 
    3320        2006 :     return poBestBand;
    3321             : }
    3322             : 
    3323             : /************************************************************************/
    3324             : /*                    GDALGetRasterSampleOverview()                     */
    3325             : /************************************************************************/
    3326             : 
    3327             : /**
    3328             :  * \brief Fetch best sampling overview.
    3329             :  *
    3330             :  * Use GDALGetRasterSampleOverviewEx() to be able to specify more than 2
    3331             :  * billion samples.
    3332             :  *
    3333             :  * @see GDALRasterBand::GetRasterSampleOverview()
    3334             :  * @see GDALGetRasterSampleOverviewEx()
    3335             :  */
    3336             : 
    3337        2000 : GDALRasterBandH CPL_STDCALL GDALGetRasterSampleOverview(GDALRasterBandH hBand,
    3338             :                                                         int nDesiredSamples)
    3339             : 
    3340             : {
    3341        2000 :     VALIDATE_POINTER1(hBand, "GDALGetRasterSampleOverview", nullptr);
    3342             : 
    3343        2000 :     GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
    3344        2000 :     return GDALRasterBand::ToHandle(poBand->GetRasterSampleOverview(
    3345        4000 :         nDesiredSamples < 0 ? 0 : static_cast<GUIntBig>(nDesiredSamples)));
    3346             : }
    3347             : 
    3348             : /************************************************************************/
    3349             : /*                    GDALGetRasterSampleOverviewEx()                   */
    3350             : /************************************************************************/
    3351             : 
    3352             : /**
    3353             :  * \brief Fetch best sampling overview.
    3354             :  *
    3355             :  * @see GDALRasterBand::GetRasterSampleOverview()
    3356             :  * @since GDAL 2.0
    3357             :  */
    3358             : 
    3359             : GDALRasterBandH CPL_STDCALL
    3360           0 : GDALGetRasterSampleOverviewEx(GDALRasterBandH hBand, GUIntBig nDesiredSamples)
    3361             : 
    3362             : {
    3363           0 :     VALIDATE_POINTER1(hBand, "GDALGetRasterSampleOverviewEx", nullptr);
    3364             : 
    3365           0 :     GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
    3366           0 :     return GDALRasterBand::ToHandle(
    3367           0 :         poBand->GetRasterSampleOverview(nDesiredSamples));
    3368             : }
    3369             : 
    3370             : /************************************************************************/
    3371             : /*                           BuildOverviews()                           */
    3372             : /************************************************************************/
    3373             : 
    3374             : /**
    3375             :  * \fn GDALRasterBand::BuildOverviews(const char*, int, const int*,
    3376             :  * GDALProgressFunc, void*) \brief Build raster overview(s)
    3377             :  *
    3378             :  * If the operation is unsupported for the indicated dataset, then
    3379             :  * CE_Failure is returned, and CPLGetLastErrorNo() will return
    3380             :  * CPLE_NotSupported.
    3381             :  *
    3382             :  * WARNING: Most formats don't support per-band overview computation, but
    3383             :  * require that overviews are computed for all bands of a dataset, using
    3384             :  * GDALDataset::BuildOverviews(). The only exception for official GDAL drivers
    3385             :  * is the HFA driver which supports this method.
    3386             :  *
    3387             :  * @param pszResampling one of "NEAREST", "GAUSS", "CUBIC", "AVERAGE", "MODE",
    3388             :  * "AVERAGE_MAGPHASE" "RMS" or "NONE" controlling the downsampling method
    3389             :  * applied.
    3390             :  * @param nOverviews number of overviews to build.
    3391             :  * @param panOverviewList the list of overview decimation factors to build.
    3392             :  * @param pfnProgress a function to call to report progress, or NULL.
    3393             :  * @param pProgressData application data to pass to the progress function.
    3394             :  * @param papszOptions (GDAL >= 3.6) NULL terminated list of options as
    3395             :  *                     key=value pairs, or NULL
    3396             :  *
    3397             :  * @return CE_None on success or CE_Failure if the operation doesn't work.
    3398             :  */
    3399             : 
    3400             : /**/
    3401             : /**/
    3402             : 
    3403           0 : CPLErr GDALRasterBand::BuildOverviews(const char * /*pszResampling*/,
    3404             :                                       int /*nOverviews*/,
    3405             :                                       const int * /*panOverviewList*/,
    3406             :                                       GDALProgressFunc /*pfnProgress*/,
    3407             :                                       void * /*pProgressData*/,
    3408             :                                       CSLConstList /* papszOptions */)
    3409             : 
    3410             : {
    3411           0 :     ReportError(CE_Failure, CPLE_NotSupported,
    3412             :                 "BuildOverviews() not supported for this dataset.");
    3413             : 
    3414           0 :     return (CE_Failure);
    3415             : }
    3416             : 
    3417             : /************************************************************************/
    3418             : /*                             GetOffset()                              */
    3419             : /************************************************************************/
    3420             : 
    3421             : /**
    3422             :  * \brief Fetch the raster value offset.
    3423             :  *
    3424             :  * This value (in combination with the GetScale() value) can be used to
    3425             :  * transform raw pixel values into the units returned by GetUnitType().
    3426             :  * For example this might be used to store elevations in GUInt16 bands
    3427             :  * with a precision of 0.1, and starting from -100.
    3428             :  *
    3429             :  * Units value = (raw value * scale) + offset
    3430             :  *
    3431             :  * Note that applying scale and offset is of the responsibility of the user,
    3432             :  * and is not done by methods such as RasterIO() or ReadBlock().
    3433             :  *
    3434             :  * For file formats that don't know this intrinsically a value of zero
    3435             :  * is returned.
    3436             :  *
    3437             :  * This method is the same as the C function GDALGetRasterOffset().
    3438             :  *
    3439             :  * @param pbSuccess pointer to a boolean to use to indicate if the
    3440             :  * returned value is meaningful or not.  May be NULL (default).
    3441             :  *
    3442             :  * @return the raster offset.
    3443             :  */
    3444             : 
    3445         390 : double GDALRasterBand::GetOffset(int *pbSuccess)
    3446             : 
    3447             : {
    3448         390 :     if (pbSuccess != nullptr)
    3449         322 :         *pbSuccess = FALSE;
    3450             : 
    3451         390 :     return 0.0;
    3452             : }
    3453             : 
    3454             : /************************************************************************/
    3455             : /*                        GDALGetRasterOffset()                         */
    3456             : /************************************************************************/
    3457             : 
    3458             : /**
    3459             :  * \brief Fetch the raster value offset.
    3460             :  *
    3461             :  * @see GDALRasterBand::GetOffset()
    3462             :  */
    3463             : 
    3464         343 : double CPL_STDCALL GDALGetRasterOffset(GDALRasterBandH hBand, int *pbSuccess)
    3465             : 
    3466             : {
    3467         343 :     VALIDATE_POINTER1(hBand, "GDALGetRasterOffset", 0);
    3468             : 
    3469         343 :     GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
    3470         343 :     return poBand->GetOffset(pbSuccess);
    3471             : }
    3472             : 
    3473             : /************************************************************************/
    3474             : /*                             SetOffset()                              */
    3475             : /************************************************************************/
    3476             : 
    3477             : /**
    3478             :  * \fn GDALRasterBand::SetOffset(double)
    3479             :  * \brief Set scaling offset.
    3480             :  *
    3481             :  * Very few formats implement this method.   When not implemented it will
    3482             :  * issue a CPLE_NotSupported error and return CE_Failure.
    3483             :  *
    3484             :  * This method is the same as the C function GDALSetRasterOffset().
    3485             :  *
    3486             :  * @param dfNewOffset the new offset.
    3487             :  *
    3488             :  * @return CE_None or success or CE_Failure on failure.
    3489             :  */
    3490             : 
    3491             : /**/
    3492             : /**/
    3493             : 
    3494           0 : CPLErr GDALRasterBand::SetOffset(double /*dfNewOffset*/)
    3495             : {
    3496           0 :     if (!(GetMOFlags() & GMO_IGNORE_UNIMPLEMENTED))
    3497           0 :         ReportError(CE_Failure, CPLE_NotSupported,
    3498             :                     "SetOffset() not supported on this raster band.");
    3499             : 
    3500           0 :     return CE_Failure;
    3501             : }
    3502             : 
    3503             : /************************************************************************/
    3504             : /*                        GDALSetRasterOffset()                         */
    3505             : /************************************************************************/
    3506             : 
    3507             : /**
    3508             :  * \brief Set scaling offset.
    3509             :  *
    3510             :  * @see GDALRasterBand::SetOffset()
    3511             :  */
    3512             : 
    3513          65 : CPLErr CPL_STDCALL GDALSetRasterOffset(GDALRasterBandH hBand,
    3514             :                                        double dfNewOffset)
    3515             : 
    3516             : {
    3517          65 :     VALIDATE_POINTER1(hBand, "GDALSetRasterOffset", CE_Failure);
    3518             : 
    3519          65 :     GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
    3520          65 :     return poBand->SetOffset(dfNewOffset);
    3521             : }
    3522             : 
    3523             : /************************************************************************/
    3524             : /*                              GetScale()                              */
    3525             : /************************************************************************/
    3526             : 
    3527             : /**
    3528             :  * \brief Fetch the raster value scale.
    3529             :  *
    3530             :  * This value (in combination with the GetOffset() value) can be used to
    3531             :  * transform raw pixel values into the units returned by GetUnitType().
    3532             :  * For example this might be used to store elevations in GUInt16 bands
    3533             :  * with a precision of 0.1, and starting from -100.
    3534             :  *
    3535             :  * Units value = (raw value * scale) + offset
    3536             :  *
    3537             :  * Note that applying scale and offset is of the responsibility of the user,
    3538             :  * and is not done by methods such as RasterIO() or ReadBlock().
    3539             :  *
    3540             :  * For file formats that don't know this intrinsically a value of one
    3541             :  * is returned.
    3542             :  *
    3543             :  * This method is the same as the C function GDALGetRasterScale().
    3544             :  *
    3545             :  * @param pbSuccess pointer to a boolean to use to indicate if the
    3546             :  * returned value is meaningful or not.  May be NULL (default).
    3547             :  *
    3548             :  * @return the raster scale.
    3549             :  */
    3550             : 
    3551         390 : double GDALRasterBand::GetScale(int *pbSuccess)
    3552             : 
    3553             : {
    3554         390 :     if (pbSuccess != nullptr)
    3555         322 :         *pbSuccess = FALSE;
    3556             : 
    3557         390 :     return 1.0;
    3558             : }
    3559             : 
    3560             : /************************************************************************/
    3561             : /*                         GDALGetRasterScale()                         */
    3562             : /************************************************************************/
    3563             : 
    3564             : /**
    3565             :  * \brief Fetch the raster value scale.
    3566             :  *
    3567             :  * @see GDALRasterBand::GetScale()
    3568             :  */
    3569             : 
    3570         341 : double CPL_STDCALL GDALGetRasterScale(GDALRasterBandH hBand, int *pbSuccess)
    3571             : 
    3572             : {
    3573         341 :     VALIDATE_POINTER1(hBand, "GDALGetRasterScale", 0);
    3574             : 
    3575         341 :     GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
    3576         341 :     return poBand->GetScale(pbSuccess);
    3577             : }
    3578             : 
    3579             : /************************************************************************/
    3580             : /*                              SetScale()                              */
    3581             : /************************************************************************/
    3582             : 
    3583             : /**
    3584             :  * \fn GDALRasterBand::SetScale(double)
    3585             :  * \brief Set scaling ratio.
    3586             :  *
    3587             :  * Very few formats implement this method.   When not implemented it will
    3588             :  * issue a CPLE_NotSupported error and return CE_Failure.
    3589             :  *
    3590             :  * This method is the same as the C function GDALSetRasterScale().
    3591             :  *
    3592             :  * @param dfNewScale the new scale.
    3593             :  *
    3594             :  * @return CE_None or success or CE_Failure on failure.
    3595             :  */
    3596             : 
    3597             : /**/
    3598             : /**/
    3599             : 
    3600           0 : CPLErr GDALRasterBand::SetScale(double /*dfNewScale*/)
    3601             : 
    3602             : {
    3603           0 :     if (!(GetMOFlags() & GMO_IGNORE_UNIMPLEMENTED))
    3604           0 :         ReportError(CE_Failure, CPLE_NotSupported,
    3605             :                     "SetScale() not supported on this raster band.");
    3606             : 
    3607           0 :     return CE_Failure;
    3608             : }
    3609             : 
    3610             : /************************************************************************/
    3611             : /*                        GDALSetRasterScale()                          */
    3612             : /************************************************************************/
    3613             : 
    3614             : /**
    3615             :  * \brief Set scaling ratio.
    3616             :  *
    3617             :  * @see GDALRasterBand::SetScale()
    3618             :  */
    3619             : 
    3620          66 : CPLErr CPL_STDCALL GDALSetRasterScale(GDALRasterBandH hBand, double dfNewOffset)
    3621             : 
    3622             : {
    3623          66 :     VALIDATE_POINTER1(hBand, "GDALSetRasterScale", CE_Failure);
    3624             : 
    3625          66 :     GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
    3626          66 :     return poBand->SetScale(dfNewOffset);
    3627             : }
    3628             : 
    3629             : /************************************************************************/
    3630             : /*                            GetUnitType()                             */
    3631             : /************************************************************************/
    3632             : 
    3633             : /**
    3634             :  * \brief Return raster unit type.
    3635             :  *
    3636             :  * Return a name for the units of this raster's values.  For instance, it
    3637             :  * might be "m" for an elevation model in meters, or "ft" for feet.  If no
    3638             :  * units are available, a value of "" will be returned.  The returned string
    3639             :  * should not be modified, nor freed by the calling application.
    3640             :  *
    3641             :  * This method is the same as the C function GDALGetRasterUnitType().
    3642             :  *
    3643             :  * @return unit name string.
    3644             :  */
    3645             : 
    3646         155 : const char *GDALRasterBand::GetUnitType()
    3647             : 
    3648             : {
    3649         155 :     return "";
    3650             : }
    3651             : 
    3652             : /************************************************************************/
    3653             : /*                       GDALGetRasterUnitType()                        */
    3654             : /************************************************************************/
    3655             : 
    3656             : /**
    3657             :  * \brief Return raster unit type.
    3658             :  *
    3659             :  * @see GDALRasterBand::GetUnitType()
    3660             :  */
    3661             : 
    3662        1344 : const char *CPL_STDCALL GDALGetRasterUnitType(GDALRasterBandH hBand)
    3663             : 
    3664             : {
    3665        1344 :     VALIDATE_POINTER1(hBand, "GDALGetRasterUnitType", nullptr);
    3666             : 
    3667        1344 :     GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
    3668        1344 :     return poBand->GetUnitType();
    3669             : }
    3670             : 
    3671             : /************************************************************************/
    3672             : /*                            SetUnitType()                             */
    3673             : /************************************************************************/
    3674             : 
    3675             : /**
    3676             :  * \fn GDALRasterBand::SetUnitType(const char*)
    3677             :  * \brief Set unit type.
    3678             :  *
    3679             :  * Set the unit type for a raster band.  Values should be one of
    3680             :  * "" (the default indicating it is unknown), "m" indicating meters,
    3681             :  * or "ft" indicating feet, though other nonstandard values are allowed.
    3682             :  *
    3683             :  * This method is the same as the C function GDALSetRasterUnitType().
    3684             :  *
    3685             :  * @param pszNewValue the new unit type value.
    3686             :  *
    3687             :  * @return CE_None on success or CE_Failure if not successful, or
    3688             :  * unsupported.
    3689             :  */
    3690             : 
    3691             : /**/
    3692             : /**/
    3693             : 
    3694           0 : CPLErr GDALRasterBand::SetUnitType(const char * /*pszNewValue*/)
    3695             : 
    3696             : {
    3697           0 :     if (!(GetMOFlags() & GMO_IGNORE_UNIMPLEMENTED))
    3698           0 :         ReportError(CE_Failure, CPLE_NotSupported,
    3699             :                     "SetUnitType() not supported on this raster band.");
    3700           0 :     return CE_Failure;
    3701             : }
    3702             : 
    3703             : /************************************************************************/
    3704             : /*                       GDALSetRasterUnitType()                        */
    3705             : /************************************************************************/
    3706             : 
    3707             : /**
    3708             :  * \brief Set unit type.
    3709             :  *
    3710             :  * @see GDALRasterBand::SetUnitType()
    3711             :  *
    3712             :  * @since GDAL 1.8.0
    3713             :  */
    3714             : 
    3715          60 : CPLErr CPL_STDCALL GDALSetRasterUnitType(GDALRasterBandH hBand,
    3716             :                                          const char *pszNewValue)
    3717             : 
    3718             : {
    3719          60 :     VALIDATE_POINTER1(hBand, "GDALSetRasterUnitType", CE_Failure);
    3720             : 
    3721          60 :     GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
    3722          60 :     return poBand->SetUnitType(pszNewValue);
    3723             : }
    3724             : 
    3725             : /************************************************************************/
    3726             : /*                              GetXSize()                              */
    3727             : /************************************************************************/
    3728             : 
    3729             : /**
    3730             :  * \brief Fetch XSize of raster.
    3731             :  *
    3732             :  * This method is the same as the C function GDALGetRasterBandXSize().
    3733             :  *
    3734             :  * @return the width in pixels of this band.
    3735             :  */
    3736             : 
    3737     6787130 : int GDALRasterBand::GetXSize() const
    3738             : 
    3739             : {
    3740     6787130 :     return nRasterXSize;
    3741             : }
    3742             : 
    3743             : /************************************************************************/
    3744             : /*                       GDALGetRasterBandXSize()                       */
    3745             : /************************************************************************/
    3746             : 
    3747             : /**
    3748             :  * \brief Fetch XSize of raster.
    3749             :  *
    3750             :  * @see GDALRasterBand::GetXSize()
    3751             :  */
    3752             : 
    3753       54250 : int CPL_STDCALL GDALGetRasterBandXSize(GDALRasterBandH hBand)
    3754             : 
    3755             : {
    3756       54250 :     VALIDATE_POINTER1(hBand, "GDALGetRasterBandXSize", 0);
    3757             : 
    3758       54250 :     GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
    3759       54250 :     return poBand->GetXSize();
    3760             : }
    3761             : 
    3762             : /************************************************************************/
    3763             : /*                              GetYSize()                              */
    3764             : /************************************************************************/
    3765             : 
    3766             : /**
    3767             :  * \brief Fetch YSize of raster.
    3768             :  *
    3769             :  * This method is the same as the C function GDALGetRasterBandYSize().
    3770             :  *
    3771             :  * @return the height in pixels of this band.
    3772             :  */
    3773             : 
    3774     3306210 : int GDALRasterBand::GetYSize() const
    3775             : 
    3776             : {
    3777     3306210 :     return nRasterYSize;
    3778             : }
    3779             : 
    3780             : /************************************************************************/
    3781             : /*                       GDALGetRasterBandYSize()                       */
    3782             : /************************************************************************/
    3783             : 
    3784             : /**
    3785             :  * \brief Fetch YSize of raster.
    3786             :  *
    3787             :  * @see GDALRasterBand::GetYSize()
    3788             :  */
    3789             : 
    3790       53616 : int CPL_STDCALL GDALGetRasterBandYSize(GDALRasterBandH hBand)
    3791             : 
    3792             : {
    3793       53616 :     VALIDATE_POINTER1(hBand, "GDALGetRasterBandYSize", 0);
    3794             : 
    3795       53616 :     GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
    3796       53616 :     return poBand->GetYSize();
    3797             : }
    3798             : 
    3799             : /************************************************************************/
    3800             : /*                              GetBand()                               */
    3801             : /************************************************************************/
    3802             : 
    3803             : /**
    3804             :  * \brief Fetch the band number.
    3805             :  *
    3806             :  * This method returns the band that this GDALRasterBand objects represents
    3807             :  * within its dataset.  This method may return a value of 0 to indicate
    3808             :  * GDALRasterBand objects without an apparently relationship to a dataset,
    3809             :  * such as GDALRasterBands serving as overviews.
    3810             :  *
    3811             :  * This method is the same as the C function GDALGetBandNumber().
    3812             :  *
    3813             :  * @return band number (1+) or 0 if the band number isn't known.
    3814             :  */
    3815             : 
    3816       19352 : int GDALRasterBand::GetBand() const
    3817             : 
    3818             : {
    3819       19352 :     return nBand;
    3820             : }
    3821             : 
    3822             : /************************************************************************/
    3823             : /*                         GDALGetBandNumber()                          */
    3824             : /************************************************************************/
    3825             : 
    3826             : /**
    3827             :  * \brief Fetch the band number.
    3828             :  *
    3829             :  * @see GDALRasterBand::GetBand()
    3830             :  */
    3831             : 
    3832         147 : int CPL_STDCALL GDALGetBandNumber(GDALRasterBandH hBand)
    3833             : 
    3834             : {
    3835         147 :     VALIDATE_POINTER1(hBand, "GDALGetBandNumber", 0);
    3836             : 
    3837         147 :     GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
    3838         147 :     return poBand->GetBand();
    3839             : }
    3840             : 
    3841             : /************************************************************************/
    3842             : /*                             GetDataset()                             */
    3843             : /************************************************************************/
    3844             : 
    3845             : /**
    3846             :  * \brief Fetch the owning dataset handle.
    3847             :  *
    3848             :  * Note that some GDALRasterBands are not considered to be a part of a dataset,
    3849             :  * such as overviews or other "freestanding" bands.
    3850             :  *
    3851             :  * This method is the same as the C function GDALGetBandDataset().
    3852             :  *
    3853             :  * @return the pointer to the GDALDataset to which this band belongs, or
    3854             :  * NULL if this cannot be determined.
    3855             :  */
    3856             : 
    3857     3895100 : GDALDataset *GDALRasterBand::GetDataset() const
    3858             : 
    3859             : {
    3860     3895100 :     return poDS;
    3861             : }
    3862             : 
    3863             : /************************************************************************/
    3864             : /*                         GDALGetBandDataset()                         */
    3865             : /************************************************************************/
    3866             : 
    3867             : /**
    3868             :  * \brief Fetch the owning dataset handle.
    3869             :  *
    3870             :  * @see GDALRasterBand::GetDataset()
    3871             :  */
    3872             : 
    3873         316 : GDALDatasetH CPL_STDCALL GDALGetBandDataset(GDALRasterBandH hBand)
    3874             : 
    3875             : {
    3876         316 :     VALIDATE_POINTER1(hBand, "GDALGetBandDataset", nullptr);
    3877             : 
    3878         316 :     GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
    3879         316 :     return GDALDataset::ToHandle(poBand->GetDataset());
    3880             : }
    3881             : 
    3882             : /************************************************************************/
    3883             : /*                        ComputeFloat16NoDataValue()                     */
    3884             : /************************************************************************/
    3885             : 
    3886        2038 : static inline void ComputeFloat16NoDataValue(GDALDataType eDataType,
    3887             :                                              double dfNoDataValue,
    3888             :                                              int &bGotNoDataValue,
    3889             :                                              GFloat16 &fNoDataValue,
    3890             :                                              bool &bGotFloat16NoDataValue)
    3891             : {
    3892        2038 :     if (eDataType == GDT_Float16 && bGotNoDataValue)
    3893             :     {
    3894           0 :         dfNoDataValue = GDALAdjustNoDataCloseToFloatMax(dfNoDataValue);
    3895           0 :         if (GDALIsValueInRange<GFloat16>(dfNoDataValue))
    3896             :         {
    3897           0 :             fNoDataValue = static_cast<GFloat16>(dfNoDataValue);
    3898           0 :             bGotFloat16NoDataValue = true;
    3899           0 :             bGotNoDataValue = false;
    3900             :         }
    3901             :     }
    3902        2038 : }
    3903             : 
    3904             : /************************************************************************/
    3905             : /*                        ComputeFloatNoDataValue()                     */
    3906             : /************************************************************************/
    3907             : 
    3908        2038 : static inline void ComputeFloatNoDataValue(GDALDataType eDataType,
    3909             :                                            double dfNoDataValue,
    3910             :                                            int &bGotNoDataValue,
    3911             :                                            float &fNoDataValue,
    3912             :                                            bool &bGotFloatNoDataValue)
    3913             : {
    3914        2038 :     if (eDataType == GDT_Float32 && bGotNoDataValue)
    3915             :     {
    3916          81 :         dfNoDataValue = GDALAdjustNoDataCloseToFloatMax(dfNoDataValue);
    3917          81 :         if (GDALIsValueInRange<float>(dfNoDataValue))
    3918             :         {
    3919          81 :             fNoDataValue = static_cast<float>(dfNoDataValue);
    3920          81 :             bGotFloatNoDataValue = true;
    3921          81 :             bGotNoDataValue = false;
    3922             :         }
    3923             :     }
    3924        2038 : }
    3925             : 
    3926             : /************************************************************************/
    3927             : /*                        struct GDALNoDataValues                       */
    3928             : /************************************************************************/
    3929             : 
    3930             : /**
    3931             :  * \brief No-data-values for all types
    3932             :  *
    3933             :  * The functions below pass various no-data-values around. To avoid
    3934             :  * long argument lists, this struct collects the no-data-values for
    3935             :  * all types into a single, convenient place.
    3936             :  **/
    3937             : 
    3938             : struct GDALNoDataValues
    3939             : {
    3940             :     int bGotNoDataValue;
    3941             :     double dfNoDataValue;
    3942             : 
    3943             :     bool bGotFloatNoDataValue;
    3944             :     float fNoDataValue;
    3945             : 
    3946             :     bool bGotFloat16NoDataValue;
    3947             :     GFloat16 hfNoDataValue;
    3948             : 
    3949        2038 :     GDALNoDataValues(GDALRasterBand *poRasterBand, GDALDataType eDataType)
    3950        2038 :         : bGotNoDataValue(FALSE), dfNoDataValue(0.0),
    3951             :           bGotFloatNoDataValue(false), fNoDataValue(0.0f),
    3952        2038 :           bGotFloat16NoDataValue(false), hfNoDataValue(GFloat16(0.0f))
    3953             :     {
    3954        2038 :         dfNoDataValue = poRasterBand->GetNoDataValue(&bGotNoDataValue);
    3955        2038 :         bGotNoDataValue = bGotNoDataValue && !CPLIsNan(dfNoDataValue);
    3956             : 
    3957        2038 :         ComputeFloatNoDataValue(eDataType, dfNoDataValue, bGotNoDataValue,
    3958        2038 :                                 fNoDataValue, bGotFloatNoDataValue);
    3959             : 
    3960        2038 :         ComputeFloat16NoDataValue(eDataType, dfNoDataValue, bGotNoDataValue,
    3961        2038 :                                   hfNoDataValue, bGotFloat16NoDataValue);
    3962        2038 :     }
    3963             : };
    3964             : 
    3965             : /************************************************************************/
    3966             : /*                            GetHistogram()                            */
    3967             : /************************************************************************/
    3968             : 
    3969             : /**
    3970             :  * \brief Compute raster histogram.
    3971             :  *
    3972             :  * Note that the bucket size is (dfMax-dfMin) / nBuckets.
    3973             :  *
    3974             :  * For example to compute a simple 256 entry histogram of eight bit data,
    3975             :  * the following would be suitable.  The unusual bounds are to ensure that
    3976             :  * bucket boundaries don't fall right on integer values causing possible errors
    3977             :  * due to rounding after scaling.
    3978             : \code{.cpp}
    3979             :     GUIntBig anHistogram[256];
    3980             : 
    3981             :     poBand->GetHistogram( -0.5, 255.5, 256, anHistogram, FALSE, FALSE,
    3982             :                           GDALDummyProgress, nullptr );
    3983             : \endcode
    3984             :  *
    3985             :  * Note that setting bApproxOK will generally result in a subsampling of the
    3986             :  * file, and will utilize overviews if available.  It should generally
    3987             :  * produce a representative histogram for the data that is suitable for use
    3988             :  * in generating histogram based luts for instance.  Generally bApproxOK is
    3989             :  * much faster than an exactly computed histogram.
    3990             :  *
    3991             :  * This method is the same as the C functions GDALGetRasterHistogram() and
    3992             :  * GDALGetRasterHistogramEx().
    3993             :  *
    3994             :  * @param dfMin the lower bound of the histogram.
    3995             :  * @param dfMax the upper bound of the histogram.
    3996             :  * @param nBuckets the number of buckets in panHistogram.
    3997             :  * @param panHistogram array into which the histogram totals are placed.
    3998             :  * @param bIncludeOutOfRange if TRUE values below the histogram range will
    3999             :  * mapped into panHistogram[0], and values above will be mapped into
    4000             :  * panHistogram[nBuckets-1] otherwise out of range values are discarded.
    4001             :  * @param bApproxOK TRUE if an approximate, or incomplete histogram OK.
    4002             :  * @param pfnProgress function to report progress to completion.
    4003             :  * @param pProgressData application data to pass to pfnProgress.
    4004             :  *
    4005             :  * @return CE_None on success, or CE_Failure if something goes wrong.
    4006             :  */
    4007             : 
    4008          39 : CPLErr GDALRasterBand::GetHistogram(double dfMin, double dfMax, int nBuckets,
    4009             :                                     GUIntBig *panHistogram,
    4010             :                                     int bIncludeOutOfRange, int bApproxOK,
    4011             :                                     GDALProgressFunc pfnProgress,
    4012             :                                     void *pProgressData)
    4013             : 
    4014             : {
    4015          39 :     CPLAssert(nullptr != panHistogram);
    4016             : 
    4017          39 :     if (pfnProgress == nullptr)
    4018          26 :         pfnProgress = GDALDummyProgress;
    4019             : 
    4020             :     /* -------------------------------------------------------------------- */
    4021             :     /*      If we have overviews, use them for the histogram.               */
    4022             :     /* -------------------------------------------------------------------- */
    4023          39 :     if (bApproxOK && GetOverviewCount() > 0 && !HasArbitraryOverviews())
    4024             :     {
    4025             :         // FIXME: should we use the most reduced overview here or use some
    4026             :         // minimum number of samples like GDALRasterBand::ComputeStatistics()
    4027             :         // does?
    4028           0 :         GDALRasterBand *poBestOverview = GetRasterSampleOverview(0);
    4029             : 
    4030           0 :         if (poBestOverview != this)
    4031             :         {
    4032           0 :             return poBestOverview->GetHistogram(
    4033             :                 dfMin, dfMax, nBuckets, panHistogram, bIncludeOutOfRange,
    4034           0 :                 bApproxOK, pfnProgress, pProgressData);
    4035             :         }
    4036             :     }
    4037             : 
    4038             :     /* -------------------------------------------------------------------- */
    4039             :     /*      Read actual data and build histogram.                           */
    4040             :     /* -------------------------------------------------------------------- */
    4041          39 :     if (!pfnProgress(0.0, "Compute Histogram", pProgressData))
    4042             :     {
    4043           0 :         ReportError(CE_Failure, CPLE_UserInterrupt, "User terminated");
    4044           0 :         return CE_Failure;
    4045             :     }
    4046             : 
    4047             :     // Written this way to deal with NaN
    4048          39 :     if (!(dfMax > dfMin))
    4049             :     {
    4050           5 :         ReportError(CE_Failure, CPLE_IllegalArg,
    4051             :                     "dfMax should be strictly greater than dfMin");
    4052           5 :         return CE_Failure;
    4053             :     }
    4054             : 
    4055             :     GDALRasterIOExtraArg sExtraArg;
    4056          34 :     INIT_RASTERIO_EXTRA_ARG(sExtraArg);
    4057             : 
    4058          34 :     const double dfScale = nBuckets / (dfMax - dfMin);
    4059          34 :     if (dfScale == 0 || !std::isfinite(dfScale))
    4060             :     {
    4061           5 :         ReportError(CE_Failure, CPLE_IllegalArg,
    4062             :                     "dfMin and dfMax should be finite values such that "
    4063             :                     "nBuckets / (dfMax - dfMin) is non-zero");
    4064           5 :         return CE_Failure;
    4065             :     }
    4066          29 :     memset(panHistogram, 0, sizeof(GUIntBig) * nBuckets);
    4067             : 
    4068          29 :     GDALNoDataValues sNoDataValues(this, eDataType);
    4069          29 :     GDALRasterBand *poMaskBand = nullptr;
    4070          29 :     if (!sNoDataValues.bGotNoDataValue)
    4071             :     {
    4072          28 :         const int l_nMaskFlags = GetMaskFlags();
    4073          29 :         if (l_nMaskFlags != GMF_ALL_VALID && l_nMaskFlags != GMF_NODATA &&
    4074           1 :             GetColorInterpretation() != GCI_AlphaBand)
    4075             :         {
    4076           1 :             poMaskBand = GetMaskBand();
    4077             :         }
    4078             :     }
    4079             : 
    4080          29 :     bool bSignedByte = false;
    4081          29 :     if (eDataType == GDT_Byte)
    4082             :     {
    4083          22 :         EnablePixelTypeSignedByteWarning(false);
    4084             :         const char *pszPixelType =
    4085          22 :             GetMetadataItem("PIXELTYPE", "IMAGE_STRUCTURE");
    4086          22 :         EnablePixelTypeSignedByteWarning(true);
    4087          22 :         bSignedByte =
    4088          22 :             pszPixelType != nullptr && EQUAL(pszPixelType, "SIGNEDBYTE");
    4089             :     }
    4090             : 
    4091          29 :     if (bApproxOK && HasArbitraryOverviews())
    4092             :     {
    4093             :         /* --------------------------------------------------------------------
    4094             :          */
    4095             :         /*      Figure out how much the image should be reduced to get an */
    4096             :         /*      approximate value. */
    4097             :         /* --------------------------------------------------------------------
    4098             :          */
    4099             :         const double dfReduction =
    4100           0 :             sqrt(static_cast<double>(nRasterXSize) * nRasterYSize /
    4101             :                  GDALSTAT_APPROX_NUMSAMPLES);
    4102             : 
    4103           0 :         int nXReduced = nRasterXSize;
    4104           0 :         int nYReduced = nRasterYSize;
    4105           0 :         if (dfReduction > 1.0)
    4106             :         {
    4107           0 :             nXReduced = static_cast<int>(nRasterXSize / dfReduction);
    4108           0 :             nYReduced = static_cast<int>(nRasterYSize / dfReduction);
    4109             : 
    4110             :             // Catch the case of huge resizing ratios here
    4111           0 :             if (nXReduced == 0)
    4112           0 :                 nXReduced = 1;
    4113           0 :             if (nYReduced == 0)
    4114           0 :                 nYReduced = 1;
    4115             :         }
    4116             : 
    4117           0 :         void *pData = VSI_MALLOC3_VERBOSE(GDALGetDataTypeSizeBytes(eDataType),
    4118             :                                           nXReduced, nYReduced);
    4119           0 :         if (!pData)
    4120           0 :             return CE_Failure;
    4121             : 
    4122             :         const CPLErr eErr =
    4123           0 :             IRasterIO(GF_Read, 0, 0, nRasterXSize, nRasterYSize, pData,
    4124           0 :                       nXReduced, nYReduced, eDataType, 0, 0, &sExtraArg);
    4125           0 :         if (eErr != CE_None)
    4126             :         {
    4127           0 :             CPLFree(pData);
    4128           0 :             return eErr;
    4129             :         }
    4130             : 
    4131           0 :         GByte *pabyMaskData = nullptr;
    4132           0 :         if (poMaskBand)
    4133             :         {
    4134             :             pabyMaskData =
    4135           0 :                 static_cast<GByte *>(VSI_MALLOC2_VERBOSE(nXReduced, nYReduced));
    4136           0 :             if (!pabyMaskData)
    4137             :             {
    4138           0 :                 CPLFree(pData);
    4139           0 :                 return CE_Failure;
    4140             :             }
    4141             : 
    4142           0 :             if (poMaskBand->RasterIO(GF_Read, 0, 0, nRasterXSize, nRasterYSize,
    4143             :                                      pabyMaskData, nXReduced, nYReduced,
    4144           0 :                                      GDT_Byte, 0, 0, nullptr) != CE_None)
    4145             :             {
    4146           0 :                 CPLFree(pData);
    4147           0 :                 CPLFree(pabyMaskData);
    4148           0 :                 return CE_Failure;
    4149             :             }
    4150             :         }
    4151             : 
    4152             :         // This isn't the fastest way to do this, but is easier for now.
    4153           0 :         for (int iY = 0; iY < nYReduced; iY++)
    4154             :         {
    4155           0 :             for (int iX = 0; iX < nXReduced; iX++)
    4156             :             {
    4157           0 :                 const int iOffset = iX + iY * nXReduced;
    4158           0 :                 double dfValue = 0.0;
    4159             : 
    4160           0 :                 if (pabyMaskData && pabyMaskData[iOffset] == 0)
    4161           0 :                     continue;
    4162             : 
    4163           0 :                 switch (eDataType)
    4164             :                 {
    4165           0 :                     case GDT_Byte:
    4166             :                     {
    4167           0 :                         if (bSignedByte)
    4168           0 :                             dfValue =
    4169           0 :                                 static_cast<signed char *>(pData)[iOffset];
    4170             :                         else
    4171           0 :                             dfValue = static_cast<GByte *>(pData)[iOffset];
    4172           0 :                         break;
    4173             :                     }
    4174           0 :                     case GDT_Int8:
    4175           0 :                         dfValue = static_cast<GInt8 *>(pData)[iOffset];
    4176           0 :                         break;
    4177           0 :                     case GDT_UInt16:
    4178           0 :                         dfValue = static_cast<GUInt16 *>(pData)[iOffset];
    4179           0 :                         break;
    4180           0 :                     case GDT_Int16:
    4181           0 :                         dfValue = static_cast<GInt16 *>(pData)[iOffset];
    4182           0 :                         break;
    4183           0 :                     case GDT_UInt32:
    4184           0 :                         dfValue = static_cast<GUInt32 *>(pData)[iOffset];
    4185           0 :                         break;
    4186           0 :                     case GDT_Int32:
    4187           0 :                         dfValue = static_cast<GInt32 *>(pData)[iOffset];
    4188           0 :                         break;
    4189           0 :                     case GDT_UInt64:
    4190           0 :                         dfValue = static_cast<double>(
    4191           0 :                             static_cast<GUInt64 *>(pData)[iOffset]);
    4192           0 :                         break;
    4193           0 :                     case GDT_Int64:
    4194           0 :                         dfValue = static_cast<double>(
    4195           0 :                             static_cast<GInt64 *>(pData)[iOffset]);
    4196           0 :                         break;
    4197           0 :                     case GDT_Float16:
    4198             :                     {
    4199           0 :                         const GFloat16 hfValue =
    4200           0 :                             static_cast<GFloat16 *>(pData)[iOffset];
    4201           0 :                         if (CPLIsNan(hfValue) ||
    4202           0 :                             (sNoDataValues.bGotFloat16NoDataValue &&
    4203           0 :                              ARE_REAL_EQUAL(hfValue,
    4204             :                                             sNoDataValues.hfNoDataValue)))
    4205           0 :                             continue;
    4206           0 :                         dfValue = hfValue;
    4207           0 :                         break;
    4208             :                     }
    4209           0 :                     case GDT_Float32:
    4210             :                     {
    4211           0 :                         const float fValue =
    4212           0 :                             static_cast<float *>(pData)[iOffset];
    4213           0 :                         if (CPLIsNan(fValue) ||
    4214           0 :                             (sNoDataValues.bGotFloatNoDataValue &&
    4215           0 :                              ARE_REAL_EQUAL(fValue,
    4216             :                                             sNoDataValues.fNoDataValue)))
    4217           0 :                             continue;
    4218           0 :                         dfValue = fValue;
    4219           0 :                         break;
    4220             :                     }
    4221           0 :                     case GDT_Float64:
    4222           0 :                         dfValue = static_cast<double *>(pData)[iOffset];
    4223           0 :                         if (std::isnan(dfValue))
    4224           0 :                             continue;
    4225           0 :                         break;
    4226           0 :                     case GDT_CInt16:
    4227             :                     {
    4228           0 :                         const double dfReal =
    4229           0 :                             static_cast<GInt16 *>(pData)[iOffset * 2];
    4230           0 :                         const double dfImag =
    4231           0 :                             static_cast<GInt16 *>(pData)[iOffset * 2 + 1];
    4232           0 :                         if (std::isnan(dfReal) || std::isnan(dfImag))
    4233           0 :                             continue;
    4234           0 :                         dfValue = sqrt(dfReal * dfReal + dfImag * dfImag);
    4235             :                     }
    4236           0 :                     break;
    4237           0 :                     case GDT_CInt32:
    4238             :                     {
    4239           0 :                         const double dfReal =
    4240           0 :                             static_cast<GInt32 *>(pData)[iOffset * 2];
    4241           0 :                         const double dfImag =
    4242           0 :                             static_cast<GInt32 *>(pData)[iOffset * 2 + 1];
    4243           0 :                         if (std::isnan(dfReal) || std::isnan(dfImag))
    4244           0 :                             continue;
    4245           0 :                         dfValue = sqrt(dfReal * dfReal + dfImag * dfImag);
    4246             :                     }
    4247           0 :                     break;
    4248           0 :                     case GDT_CFloat16:
    4249             :                     {
    4250             :                         const double dfReal =
    4251           0 :                             static_cast<GFloat16 *>(pData)[iOffset * 2];
    4252             :                         const double dfImag =
    4253           0 :                             static_cast<GFloat16 *>(pData)[iOffset * 2 + 1];
    4254           0 :                         if (CPLIsNan(dfReal) || CPLIsNan(dfImag))
    4255           0 :                             continue;
    4256           0 :                         dfValue = sqrt(dfReal * dfReal + dfImag * dfImag);
    4257           0 :                         break;
    4258             :                     }
    4259           0 :                     case GDT_CFloat32:
    4260             :                     {
    4261           0 :                         const double dfReal =
    4262           0 :                             static_cast<float *>(pData)[iOffset * 2];
    4263           0 :                         const double dfImag =
    4264           0 :                             static_cast<float *>(pData)[iOffset * 2 + 1];
    4265           0 :                         if (std::isnan(dfReal) || std::isnan(dfImag))
    4266           0 :                             continue;
    4267           0 :                         dfValue = sqrt(dfReal * dfReal + dfImag * dfImag);
    4268           0 :                         break;
    4269             :                     }
    4270           0 :                     case GDT_CFloat64:
    4271             :                     {
    4272           0 :                         const double dfReal =
    4273           0 :                             static_cast<double *>(pData)[iOffset * 2];
    4274           0 :                         const double dfImag =
    4275           0 :                             static_cast<double *>(pData)[iOffset * 2 + 1];
    4276           0 :                         if (std::isnan(dfReal) || std::isnan(dfImag))
    4277           0 :                             continue;
    4278           0 :                         dfValue = sqrt(dfReal * dfReal + dfImag * dfImag);
    4279           0 :                         break;
    4280             :                     }
    4281           0 :                     case GDT_Unknown:
    4282             :                     case GDT_TypeCount:
    4283           0 :                         CPLAssert(false);
    4284             :                 }
    4285             : 
    4286           0 :                 if (eDataType != GDT_Float16 && eDataType != GDT_Float32 &&
    4287           0 :                     sNoDataValues.bGotNoDataValue &&
    4288           0 :                     ARE_REAL_EQUAL(dfValue, sNoDataValues.dfNoDataValue))
    4289           0 :                     continue;
    4290             : 
    4291             :                 // Given that dfValue and dfMin are not NaN, and dfScale > 0 and
    4292             :                 // finite, the result of the multiplication cannot be NaN
    4293           0 :                 const double dfIndex = floor((dfValue - dfMin) * dfScale);
    4294             : 
    4295           0 :                 if (dfIndex < 0)
    4296             :                 {
    4297           0 :                     if (bIncludeOutOfRange)
    4298           0 :                         panHistogram[0]++;
    4299             :                 }
    4300           0 :                 else if (dfIndex >= nBuckets)
    4301             :                 {
    4302           0 :                     if (bIncludeOutOfRange)
    4303           0 :                         ++panHistogram[nBuckets - 1];
    4304             :                 }
    4305             :                 else
    4306             :                 {
    4307           0 :                     ++panHistogram[static_cast<int>(dfIndex)];
    4308             :                 }
    4309             :             }
    4310             :         }
    4311             : 
    4312           0 :         CPLFree(pData);
    4313           0 :         CPLFree(pabyMaskData);
    4314             :     }
    4315             :     else  // No arbitrary overviews.
    4316             :     {
    4317          29 :         if (!InitBlockInfo())
    4318           0 :             return CE_Failure;
    4319             : 
    4320             :         /* --------------------------------------------------------------------
    4321             :          */
    4322             :         /*      Figure out the ratio of blocks we will read to get an */
    4323             :         /*      approximate value. */
    4324             :         /* --------------------------------------------------------------------
    4325             :          */
    4326             : 
    4327          29 :         int nSampleRate = 1;
    4328          29 :         if (bApproxOK)
    4329             :         {
    4330           8 :             nSampleRate = static_cast<int>(std::max(
    4331          16 :                 1.0,
    4332           8 :                 sqrt(static_cast<double>(nBlocksPerRow) * nBlocksPerColumn)));
    4333             :             // We want to avoid probing only the first column of blocks for
    4334             :             // a square shaped raster, because it is not unlikely that it may
    4335             :             // be padding only (#6378).
    4336           8 :             if (nSampleRate == nBlocksPerRow && nBlocksPerRow > 1)
    4337           2 :                 nSampleRate += 1;
    4338             :         }
    4339             : 
    4340          29 :         GByte *pabyMaskData = nullptr;
    4341          29 :         if (poMaskBand)
    4342             :         {
    4343             :             pabyMaskData = static_cast<GByte *>(
    4344           1 :                 VSI_MALLOC2_VERBOSE(nBlockXSize, nBlockYSize));
    4345           1 :             if (!pabyMaskData)
    4346             :             {
    4347           0 :                 return CE_Failure;
    4348             :             }
    4349             :         }
    4350             : 
    4351             :         /* --------------------------------------------------------------------
    4352             :          */
    4353             :         /*      Read the blocks, and add to histogram. */
    4354             :         /* --------------------------------------------------------------------
    4355             :          */
    4356          29 :         for (GIntBig iSampleBlock = 0;
    4357         136 :              iSampleBlock <
    4358         136 :              static_cast<GIntBig>(nBlocksPerRow) * nBlocksPerColumn;
    4359         107 :              iSampleBlock += nSampleRate)
    4360             :         {
    4361         107 :             if (!pfnProgress(
    4362         107 :                     static_cast<double>(iSampleBlock) /
    4363         107 :                         (static_cast<double>(nBlocksPerRow) * nBlocksPerColumn),
    4364             :                     "Compute Histogram", pProgressData))
    4365             :             {
    4366           0 :                 CPLFree(pabyMaskData);
    4367           0 :                 return CE_Failure;
    4368             :             }
    4369             : 
    4370         107 :             const int iYBlock = static_cast<int>(iSampleBlock / nBlocksPerRow);
    4371         107 :             const int iXBlock = static_cast<int>(iSampleBlock % nBlocksPerRow);
    4372             : 
    4373         107 :             GDALRasterBlock *poBlock = GetLockedBlockRef(iXBlock, iYBlock);
    4374         107 :             if (poBlock == nullptr)
    4375             :             {
    4376           0 :                 CPLFree(pabyMaskData);
    4377           0 :                 return CE_Failure;
    4378             :             }
    4379             : 
    4380         107 :             void *pData = poBlock->GetDataRef();
    4381             : 
    4382         107 :             int nXCheck = 0, nYCheck = 0;
    4383         107 :             GetActualBlockSize(iXBlock, iYBlock, &nXCheck, &nYCheck);
    4384             : 
    4385         108 :             if (poMaskBand &&
    4386           1 :                 poMaskBand->RasterIO(GF_Read, iXBlock * nBlockXSize,
    4387           1 :                                      iYBlock * nBlockYSize, nXCheck, nYCheck,
    4388             :                                      pabyMaskData, nXCheck, nYCheck, GDT_Byte,
    4389           1 :                                      0, nBlockXSize, nullptr) != CE_None)
    4390             :             {
    4391           0 :                 CPLFree(pabyMaskData);
    4392           0 :                 poBlock->DropLock();
    4393           0 :                 return CE_Failure;
    4394             :             }
    4395             : 
    4396             :             // this is a special case for a common situation.
    4397         107 :             if (eDataType == GDT_Byte && !bSignedByte && dfScale == 1.0 &&
    4398          85 :                 (dfMin >= -0.5 && dfMin <= 0.5) && nYCheck == nBlockYSize &&
    4399          82 :                 nXCheck == nBlockXSize && nBuckets == 256)
    4400             :             {
    4401          82 :                 const GPtrDiff_t nPixels =
    4402          82 :                     static_cast<GPtrDiff_t>(nXCheck) * nYCheck;
    4403          82 :                 GByte *pabyData = static_cast<GByte *>(pData);
    4404             : 
    4405       72134 :                 for (GPtrDiff_t i = 0; i < nPixels; i++)
    4406             :                 {
    4407       72052 :                     if (pabyMaskData && pabyMaskData[i] == 0)
    4408           0 :                         continue;
    4409       72052 :                     if (!(sNoDataValues.bGotNoDataValue &&
    4410         512 :                           (pabyData[i] ==
    4411         512 :                            static_cast<GByte>(sNoDataValues.dfNoDataValue))))
    4412             :                     {
    4413       71796 :                         panHistogram[pabyData[i]]++;
    4414             :                     }
    4415             :                 }
    4416             : 
    4417          82 :                 poBlock->DropLock();
    4418          82 :                 continue;  // To next sample block.
    4419             :             }
    4420             : 
    4421             :             // This isn't the fastest way to do this, but is easier for now.
    4422         721 :             for (int iY = 0; iY < nYCheck; iY++)
    4423             :             {
    4424       86017 :                 for (int iX = 0; iX < nXCheck; iX++)
    4425             :                 {
    4426       85321 :                     const GPtrDiff_t iOffset =
    4427       85321 :                         iX + static_cast<GPtrDiff_t>(iY) * nBlockXSize;
    4428             : 
    4429       85321 :                     if (pabyMaskData && pabyMaskData[iOffset] == 0)
    4430           1 :                         continue;
    4431             : 
    4432       85320 :                     double dfValue = 0.0;
    4433             : 
    4434       85320 :                     switch (eDataType)
    4435             :                     {
    4436       19716 :                         case GDT_Byte:
    4437             :                         {
    4438       19716 :                             if (bSignedByte)
    4439           0 :                                 dfValue =
    4440           0 :                                     static_cast<signed char *>(pData)[iOffset];
    4441             :                             else
    4442       19716 :                                 dfValue = static_cast<GByte *>(pData)[iOffset];
    4443       19716 :                             break;
    4444             :                         }
    4445           0 :                         case GDT_Int8:
    4446           0 :                             dfValue = static_cast<GInt8 *>(pData)[iOffset];
    4447           0 :                             break;
    4448       65536 :                         case GDT_UInt16:
    4449       65536 :                             dfValue = static_cast<GUInt16 *>(pData)[iOffset];
    4450       65536 :                             break;
    4451           2 :                         case GDT_Int16:
    4452           2 :                             dfValue = static_cast<GInt16 *>(pData)[iOffset];
    4453           2 :                             break;
    4454           0 :                         case GDT_UInt32:
    4455           0 :                             dfValue = static_cast<GUInt32 *>(pData)[iOffset];
    4456           0 :                             break;
    4457          60 :                         case GDT_Int32:
    4458          60 :                             dfValue = static_cast<GInt32 *>(pData)[iOffset];
    4459          60 :                             break;
    4460           0 :                         case GDT_UInt64:
    4461           0 :                             dfValue = static_cast<double>(
    4462           0 :                                 static_cast<GUInt64 *>(pData)[iOffset]);
    4463           0 :                             break;
    4464           0 :                         case GDT_Int64:
    4465           0 :                             dfValue = static_cast<double>(
    4466           0 :                                 static_cast<GInt64 *>(pData)[iOffset]);
    4467           0 :                             break;
    4468           0 :                         case GDT_Float16:
    4469             :                         {
    4470           0 :                             const GFloat16 hfValue =
    4471           0 :                                 static_cast<GFloat16 *>(pData)[iOffset];
    4472           0 :                             if (CPLIsNan(hfValue) ||
    4473           0 :                                 (sNoDataValues.bGotFloat16NoDataValue &&
    4474           0 :                                  ARE_REAL_EQUAL(hfValue,
    4475             :                                                 sNoDataValues.hfNoDataValue)))
    4476           0 :                                 continue;
    4477           0 :                             dfValue = hfValue;
    4478           0 :                             break;
    4479             :                         }
    4480           4 :                         case GDT_Float32:
    4481             :                         {
    4482           4 :                             const float fValue =
    4483           4 :                                 static_cast<float *>(pData)[iOffset];
    4484           8 :                             if (CPLIsNan(fValue) ||
    4485           8 :                                 (sNoDataValues.bGotFloatNoDataValue &&
    4486           4 :                                  ARE_REAL_EQUAL(fValue,
    4487             :                                                 sNoDataValues.fNoDataValue)))
    4488           1 :                                 continue;
    4489           3 :                             dfValue = fValue;
    4490           3 :                             break;
    4491             :                         }
    4492           2 :                         case GDT_Float64:
    4493           2 :                             dfValue = static_cast<double *>(pData)[iOffset];
    4494           2 :                             if (std::isnan(dfValue))
    4495           0 :                                 continue;
    4496           2 :                             break;
    4497           0 :                         case GDT_CInt16:
    4498             :                         {
    4499           0 :                             double dfReal =
    4500           0 :                                 static_cast<GInt16 *>(pData)[iOffset * 2];
    4501           0 :                             double dfImag =
    4502           0 :                                 static_cast<GInt16 *>(pData)[iOffset * 2 + 1];
    4503           0 :                             dfValue = sqrt(dfReal * dfReal + dfImag * dfImag);
    4504           0 :                             break;
    4505             :                         }
    4506           0 :                         case GDT_CInt32:
    4507             :                         {
    4508           0 :                             double dfReal =
    4509           0 :                                 static_cast<GInt32 *>(pData)[iOffset * 2];
    4510           0 :                             double dfImag =
    4511           0 :                                 static_cast<GInt32 *>(pData)[iOffset * 2 + 1];
    4512           0 :                             dfValue = sqrt(dfReal * dfReal + dfImag * dfImag);
    4513           0 :                             break;
    4514             :                         }
    4515           0 :                         case GDT_CFloat16:
    4516             :                         {
    4517             :                             double dfReal =
    4518           0 :                                 static_cast<GFloat16 *>(pData)[iOffset * 2];
    4519             :                             double dfImag =
    4520           0 :                                 static_cast<GFloat16 *>(pData)[iOffset * 2 + 1];
    4521           0 :                             if (CPLIsNan(dfReal) || CPLIsNan(dfImag))
    4522           0 :                                 continue;
    4523           0 :                             dfValue = sqrt(dfReal * dfReal + dfImag * dfImag);
    4524           0 :                             break;
    4525             :                         }
    4526           0 :                         case GDT_CFloat32:
    4527             :                         {
    4528           0 :                             double dfReal =
    4529           0 :                                 static_cast<float *>(pData)[iOffset * 2];
    4530           0 :                             double dfImag =
    4531           0 :                                 static_cast<float *>(pData)[iOffset * 2 + 1];
    4532           0 :                             if (std::isnan(dfReal) || std::isnan(dfImag))
    4533           0 :                                 continue;
    4534           0 :                             dfValue = sqrt(dfReal * dfReal + dfImag * dfImag);
    4535           0 :                             break;
    4536             :                         }
    4537           0 :                         case GDT_CFloat64:
    4538             :                         {
    4539           0 :                             double dfReal =
    4540           0 :                                 static_cast<double *>(pData)[iOffset * 2];
    4541           0 :                             double dfImag =
    4542           0 :                                 static_cast<double *>(pData)[iOffset * 2 + 1];
    4543           0 :                             if (std::isnan(dfReal) || std::isnan(dfImag))
    4544           0 :                                 continue;
    4545           0 :                             dfValue = sqrt(dfReal * dfReal + dfImag * dfImag);
    4546           0 :                             break;
    4547             :                         }
    4548           0 :                         case GDT_Unknown:
    4549             :                         case GDT_TypeCount:
    4550           0 :                             CPLAssert(false);
    4551             :                             CPLFree(pabyMaskData);
    4552             :                             return CE_Failure;
    4553             :                     }
    4554             : 
    4555       85319 :                     if (eDataType != GDT_Float16 && eDataType != GDT_Float32 &&
    4556      170638 :                         sNoDataValues.bGotNoDataValue &&
    4557           0 :                         ARE_REAL_EQUAL(dfValue, sNoDataValues.dfNoDataValue))
    4558           0 :                         continue;
    4559             : 
    4560             :                     // Given that dfValue and dfMin are not NaN, and dfScale > 0
    4561             :                     // and finite, the result of the multiplication cannot be
    4562             :                     // NaN
    4563       85319 :                     const double dfIndex = floor((dfValue - dfMin) * dfScale);
    4564             : 
    4565       85319 :                     if (dfIndex < 0)
    4566             :                     {
    4567           1 :                         if (bIncludeOutOfRange)
    4568           1 :                             panHistogram[0]++;
    4569             :                     }
    4570       85318 :                     else if (dfIndex >= nBuckets)
    4571             :                     {
    4572           7 :                         if (bIncludeOutOfRange)
    4573           4 :                             ++panHistogram[nBuckets - 1];
    4574             :                     }
    4575             :                     else
    4576             :                     {
    4577       85311 :                         ++panHistogram[static_cast<int>(dfIndex)];
    4578             :                     }
    4579             :                 }
    4580             :             }
    4581             : 
    4582          25 :             poBlock->DropLock();
    4583             :         }
    4584             : 
    4585          29 :         CPLFree(pabyMaskData);
    4586             :     }
    4587             : 
    4588          29 :     pfnProgress(1.0, "Compute Histogram", pProgressData);
    4589             : 
    4590          29 :     return CE_None;
    4591             : }
    4592             : 
    4593             : /************************************************************************/
    4594             : /*                       GDALGetRasterHistogram()                       */
    4595             : /************************************************************************/
    4596             : 
    4597             : /**
    4598             :  * \brief Compute raster histogram.
    4599             :  *
    4600             :  * Use GDALGetRasterHistogramEx() instead to get correct counts for values
    4601             :  * exceeding 2 billion.
    4602             :  *
    4603             :  * @see GDALRasterBand::GetHistogram()
    4604             :  * @see GDALGetRasterHistogramEx()
    4605             :  */
    4606             : 
    4607           0 : CPLErr CPL_STDCALL GDALGetRasterHistogram(GDALRasterBandH hBand, double dfMin,
    4608             :                                           double dfMax, int nBuckets,
    4609             :                                           int *panHistogram,
    4610             :                                           int bIncludeOutOfRange, int bApproxOK,
    4611             :                                           GDALProgressFunc pfnProgress,
    4612             :                                           void *pProgressData)
    4613             : 
    4614             : {
    4615           0 :     VALIDATE_POINTER1(hBand, "GDALGetRasterHistogram", CE_Failure);
    4616           0 :     VALIDATE_POINTER1(panHistogram, "GDALGetRasterHistogram", CE_Failure);
    4617             : 
    4618           0 :     GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
    4619             : 
    4620             :     GUIntBig *panHistogramTemp =
    4621           0 :         static_cast<GUIntBig *>(VSIMalloc2(sizeof(GUIntBig), nBuckets));
    4622           0 :     if (panHistogramTemp == nullptr)
    4623             :     {
    4624           0 :         poBand->ReportError(CE_Failure, CPLE_OutOfMemory,
    4625             :                             "Out of memory in GDALGetRasterHistogram().");
    4626           0 :         return CE_Failure;
    4627             :     }
    4628             : 
    4629           0 :     CPLErr eErr = poBand->GetHistogram(dfMin, dfMax, nBuckets, panHistogramTemp,
    4630             :                                        bIncludeOutOfRange, bApproxOK,
    4631           0 :                                        pfnProgress, pProgressData);
    4632             : 
    4633           0 :     if (eErr == CE_None)
    4634             :     {
    4635           0 :         for (int i = 0; i < nBuckets; i++)
    4636             :         {
    4637           0 :             if (panHistogramTemp[i] > INT_MAX)
    4638             :             {
    4639           0 :                 CPLError(CE_Warning, CPLE_AppDefined,
    4640             :                          "Count for bucket %d, which is " CPL_FRMT_GUIB
    4641             :                          " exceeds maximum 32 bit value",
    4642           0 :                          i, panHistogramTemp[i]);
    4643           0 :                 panHistogram[i] = INT_MAX;
    4644             :             }
    4645             :             else
    4646             :             {
    4647           0 :                 panHistogram[i] = static_cast<int>(panHistogramTemp[i]);
    4648             :             }
    4649             :         }
    4650             :     }
    4651             : 
    4652           0 :     CPLFree(panHistogramTemp);
    4653             : 
    4654           0 :     return eErr;
    4655             : }
    4656             : 
    4657             : /************************************************************************/
    4658             : /*                      GDALGetRasterHistogramEx()                      */
    4659             : /************************************************************************/
    4660             : 
    4661             : /**
    4662             :  * \brief Compute raster histogram.
    4663             :  *
    4664             :  * @see GDALRasterBand::GetHistogram()
    4665             :  *
    4666             :  * @since GDAL 2.0
    4667             :  */
    4668             : 
    4669          26 : CPLErr CPL_STDCALL GDALGetRasterHistogramEx(
    4670             :     GDALRasterBandH hBand, double dfMin, double dfMax, int nBuckets,
    4671             :     GUIntBig *panHistogram, int bIncludeOutOfRange, int bApproxOK,
    4672             :     GDALProgressFunc pfnProgress, void *pProgressData)
    4673             : 
    4674             : {
    4675          26 :     VALIDATE_POINTER1(hBand, "GDALGetRasterHistogramEx", CE_Failure);
    4676          26 :     VALIDATE_POINTER1(panHistogram, "GDALGetRasterHistogramEx", CE_Failure);
    4677             : 
    4678          26 :     GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
    4679             : 
    4680          26 :     return poBand->GetHistogram(dfMin, dfMax, nBuckets, panHistogram,
    4681             :                                 bIncludeOutOfRange, bApproxOK, pfnProgress,
    4682          26 :                                 pProgressData);
    4683             : }
    4684             : 
    4685             : /************************************************************************/
    4686             : /*                        GetDefaultHistogram()                         */
    4687             : /************************************************************************/
    4688             : 
    4689             : /**
    4690             :  * \brief Fetch default raster histogram.
    4691             :  *
    4692             :  * The default method in GDALRasterBand will compute a default histogram. This
    4693             :  * method is overridden by derived classes (such as GDALPamRasterBand,
    4694             :  * VRTDataset, HFADataset...) that may be able to fetch efficiently an already
    4695             :  * stored histogram.
    4696             :  *
    4697             :  * This method is the same as the C functions GDALGetDefaultHistogram() and
    4698             :  * GDALGetDefaultHistogramEx().
    4699             :  *
    4700             :  * @param pdfMin pointer to double value that will contain the lower bound of
    4701             :  * the histogram.
    4702             :  * @param pdfMax pointer to double value that will contain the upper bound of
    4703             :  * the histogram.
    4704             :  * @param pnBuckets pointer to int value that will contain the number of buckets
    4705             :  * in *ppanHistogram.
    4706             :  * @param ppanHistogram pointer to array into which the histogram totals are
    4707             :  * placed. To be freed with VSIFree
    4708             :  * @param bForce TRUE to force the computation. If FALSE and no default
    4709             :  * histogram is available, the method will return CE_Warning
    4710             :  * @param pfnProgress function to report progress to completion.
    4711             :  * @param pProgressData application data to pass to pfnProgress.
    4712             :  *
    4713             :  * @return CE_None on success, CE_Failure if something goes wrong, or
    4714             :  * CE_Warning if no default histogram is available.
    4715             :  */
    4716             : 
    4717          22 : CPLErr GDALRasterBand::GetDefaultHistogram(double *pdfMin, double *pdfMax,
    4718             :                                            int *pnBuckets,
    4719             :                                            GUIntBig **ppanHistogram, int bForce,
    4720             :                                            GDALProgressFunc pfnProgress,
    4721             :                                            void *pProgressData)
    4722             : 
    4723             : {
    4724          22 :     CPLAssert(nullptr != pnBuckets);
    4725          22 :     CPLAssert(nullptr != ppanHistogram);
    4726          22 :     CPLAssert(nullptr != pdfMin);
    4727          22 :     CPLAssert(nullptr != pdfMax);
    4728             : 
    4729          22 :     *pnBuckets = 0;
    4730          22 :     *ppanHistogram = nullptr;
    4731             : 
    4732          22 :     if (!bForce)
    4733           6 :         return CE_Warning;
    4734             : 
    4735          16 :     const int nBuckets = 256;
    4736             : 
    4737          16 :     bool bSignedByte = false;
    4738          16 :     if (eDataType == GDT_Byte)
    4739             :     {
    4740          16 :         EnablePixelTypeSignedByteWarning(false);
    4741             :         const char *pszPixelType =
    4742          16 :             GetMetadataItem("PIXELTYPE", "IMAGE_STRUCTURE");
    4743          16 :         EnablePixelTypeSignedByteWarning(true);
    4744          16 :         bSignedByte =
    4745          16 :             pszPixelType != nullptr && EQUAL(pszPixelType, "SIGNEDBYTE");
    4746             :     }
    4747             : 
    4748          16 :     if (GetRasterDataType() == GDT_Byte && !bSignedByte)
    4749             :     {
    4750          16 :         *pdfMin = -0.5;
    4751          16 :         *pdfMax = 255.5;
    4752             :     }
    4753             :     else
    4754             :     {
    4755             : 
    4756             :         const CPLErr eErr =
    4757           0 :             GetStatistics(TRUE, TRUE, pdfMin, pdfMax, nullptr, nullptr);
    4758           0 :         const double dfHalfBucket = (*pdfMax - *pdfMin) / (2 * (nBuckets - 1));
    4759           0 :         *pdfMin -= dfHalfBucket;
    4760           0 :         *pdfMax += dfHalfBucket;
    4761             : 
    4762           0 :         if (eErr != CE_None)
    4763           0 :             return eErr;
    4764             :     }
    4765             : 
    4766          16 :     *ppanHistogram =
    4767          16 :         static_cast<GUIntBig *>(VSICalloc(sizeof(GUIntBig), nBuckets));
    4768          16 :     if (*ppanHistogram == nullptr)
    4769             :     {
    4770           0 :         ReportError(CE_Failure, CPLE_OutOfMemory,
    4771             :                     "Out of memory in InitBlockInfo().");
    4772           0 :         return CE_Failure;
    4773             :     }
    4774             : 
    4775          16 :     *pnBuckets = nBuckets;
    4776          32 :     CPLErr eErr = GetHistogram(*pdfMin, *pdfMax, *pnBuckets, *ppanHistogram,
    4777          16 :                                TRUE, FALSE, pfnProgress, pProgressData);
    4778          16 :     if (eErr != CE_None)
    4779             :     {
    4780           0 :         *pnBuckets = 0;
    4781             :     }
    4782          16 :     return eErr;
    4783             : }
    4784             : 
    4785             : /************************************************************************/
    4786             : /*                      GDALGetDefaultHistogram()                       */
    4787             : /************************************************************************/
    4788             : 
    4789             : /**
    4790             :  * \brief Fetch default raster histogram.
    4791             :  *
    4792             :  * Use GDALGetRasterHistogramEx() instead to get correct counts for values
    4793             :  * exceeding 2 billion.
    4794             :  *
    4795             :  * @see GDALRasterBand::GDALGetDefaultHistogram()
    4796             :  * @see GDALGetRasterHistogramEx()
    4797             :  */
    4798             : 
    4799           0 : CPLErr CPL_STDCALL GDALGetDefaultHistogram(GDALRasterBandH hBand,
    4800             :                                            double *pdfMin, double *pdfMax,
    4801             :                                            int *pnBuckets, int **ppanHistogram,
    4802             :                                            int bForce,
    4803             :                                            GDALProgressFunc pfnProgress,
    4804             :                                            void *pProgressData)
    4805             : 
    4806             : {
    4807           0 :     VALIDATE_POINTER1(hBand, "GDALGetDefaultHistogram", CE_Failure);
    4808           0 :     VALIDATE_POINTER1(pdfMin, "GDALGetDefaultHistogram", CE_Failure);
    4809           0 :     VALIDATE_POINTER1(pdfMax, "GDALGetDefaultHistogram", CE_Failure);
    4810           0 :     VALIDATE_POINTER1(pnBuckets, "GDALGetDefaultHistogram", CE_Failure);
    4811           0 :     VALIDATE_POINTER1(ppanHistogram, "GDALGetDefaultHistogram", CE_Failure);
    4812             : 
    4813           0 :     GDALRasterBand *const poBand = GDALRasterBand::FromHandle(hBand);
    4814           0 :     GUIntBig *panHistogramTemp = nullptr;
    4815           0 :     CPLErr eErr = poBand->GetDefaultHistogram(pdfMin, pdfMax, pnBuckets,
    4816             :                                               &panHistogramTemp, bForce,
    4817           0 :                                               pfnProgress, pProgressData);
    4818           0 :     if (eErr == CE_None)
    4819             :     {
    4820           0 :         const int nBuckets = *pnBuckets;
    4821           0 :         *ppanHistogram = static_cast<int *>(VSIMalloc2(sizeof(int), nBuckets));
    4822           0 :         if (*ppanHistogram == nullptr)
    4823             :         {
    4824           0 :             poBand->ReportError(CE_Failure, CPLE_OutOfMemory,
    4825             :                                 "Out of memory in GDALGetDefaultHistogram().");
    4826           0 :             VSIFree(panHistogramTemp);
    4827           0 :             return CE_Failure;
    4828             :         }
    4829             : 
    4830           0 :         for (int i = 0; i < nBuckets; ++i)
    4831             :         {
    4832           0 :             if (panHistogramTemp[i] > INT_MAX)
    4833             :             {
    4834           0 :                 CPLError(CE_Warning, CPLE_AppDefined,
    4835             :                          "Count for bucket %d, which is " CPL_FRMT_GUIB
    4836             :                          " exceeds maximum 32 bit value",
    4837           0 :                          i, panHistogramTemp[i]);
    4838           0 :                 (*ppanHistogram)[i] = INT_MAX;
    4839             :             }
    4840             :             else
    4841             :             {
    4842           0 :                 (*ppanHistogram)[i] = static_cast<int>(panHistogramTemp[i]);
    4843             :             }
    4844             :         }
    4845             : 
    4846           0 :         CPLFree(panHistogramTemp);
    4847             :     }
    4848             :     else
    4849             :     {
    4850           0 :         *ppanHistogram = nullptr;
    4851             :     }
    4852             : 
    4853           0 :     return eErr;
    4854             : }
    4855             : 
    4856             : /************************************************************************/
    4857             : /*                      GDALGetDefaultHistogramEx()                     */
    4858             : /************************************************************************/
    4859             : 
    4860             : /**
    4861             :  * \brief Fetch default raster histogram.
    4862             :  *
    4863             :  * @see GDALRasterBand::GetDefaultHistogram()
    4864             :  *
    4865             :  * @since GDAL 2.0
    4866             :  */
    4867             : 
    4868             : CPLErr CPL_STDCALL
    4869          28 : GDALGetDefaultHistogramEx(GDALRasterBandH hBand, double *pdfMin, double *pdfMax,
    4870             :                           int *pnBuckets, GUIntBig **ppanHistogram, int bForce,
    4871             :                           GDALProgressFunc pfnProgress, void *pProgressData)
    4872             : 
    4873             : {
    4874          28 :     VALIDATE_POINTER1(hBand, "GDALGetDefaultHistogram", CE_Failure);
    4875          28 :     VALIDATE_POINTER1(pdfMin, "GDALGetDefaultHistogram", CE_Failure);
    4876          28 :     VALIDATE_POINTER1(pdfMax, "GDALGetDefaultHistogram", CE_Failure);
    4877          28 :     VALIDATE_POINTER1(pnBuckets, "GDALGetDefaultHistogram", CE_Failure);
    4878          28 :     VALIDATE_POINTER1(ppanHistogram, "GDALGetDefaultHistogram", CE_Failure);
    4879             : 
    4880          28 :     GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
    4881          28 :     return poBand->GetDefaultHistogram(pdfMin, pdfMax, pnBuckets, ppanHistogram,
    4882          28 :                                        bForce, pfnProgress, pProgressData);
    4883             : }
    4884             : 
    4885             : /************************************************************************/
    4886             : /*                             AdviseRead()                             */
    4887             : /************************************************************************/
    4888             : 
    4889             : /**
    4890             :  * \fn GDALRasterBand::AdviseRead(int,int,int,int,int,int,GDALDataType,char**)
    4891             :  * \brief Advise driver of upcoming read requests.
    4892             :  *
    4893             :  * Some GDAL drivers operate more efficiently if they know in advance what
    4894             :  * set of upcoming read requests will be made.  The AdviseRead() method allows
    4895             :  * an application to notify the driver of the region of interest,
    4896             :  * and at what resolution the region will be read.
    4897             :  *
    4898             :  * Many drivers just ignore the AdviseRead() call, but it can dramatically
    4899             :  * accelerate access via some drivers.
    4900             :  *
    4901             :  * Depending on call paths, drivers might receive several calls to
    4902             :  * AdviseRead() with the same parameters.
    4903             :  *
    4904             :  * @param nXOff The pixel offset to the top left corner of the region
    4905             :  * of the band to be accessed.  This would be zero to start from the left side.
    4906             :  *
    4907             :  * @param nYOff The line offset to the top left corner of the region
    4908             :  * of the band to be accessed.  This would be zero to start from the top.
    4909             :  *
    4910             :  * @param nXSize The width of the region of the band to be accessed in pixels.
    4911             :  *
    4912             :  * @param nYSize The height of the region of the band to be accessed in lines.
    4913             :  *
    4914             :  * @param nBufXSize the width of the buffer image into which the desired region
    4915             :  * is to be read, or from which it is to be written.
    4916             :  *
    4917             :  * @param nBufYSize the height of the buffer image into which the desired
    4918             :  * region is to be read, or from which it is to be written.
    4919             :  *
    4920             :  * @param eBufType the type of the pixel values in the pData data buffer.  The
    4921             :  * pixel values will automatically be translated to/from the GDALRasterBand
    4922             :  * data type as needed.
    4923             :  *
    4924             :  * @param papszOptions a list of name=value strings with special control
    4925             :  * options.  Normally this is NULL.
    4926             :  *
    4927             :  * @return CE_Failure if the request is invalid and CE_None if it works or
    4928             :  * is ignored.
    4929             :  */
    4930             : 
    4931             : /**/
    4932             : /**/
    4933             : 
    4934       42316 : CPLErr GDALRasterBand::AdviseRead(int /*nXOff*/, int /*nYOff*/, int /*nXSize*/,
    4935             :                                   int /*nYSize*/, int /*nBufXSize*/,
    4936             :                                   int /*nBufYSize*/, GDALDataType /*eBufType*/,
    4937             :                                   char ** /*papszOptions*/)
    4938             : {
    4939       42316 :     return CE_None;
    4940             : }
    4941             : 
    4942             : /************************************************************************/
    4943             : /*                        GDALRasterAdviseRead()                        */
    4944             : /************************************************************************/
    4945             : 
    4946             : /**
    4947             :  * \brief Advise driver of upcoming read requests.
    4948             :  *
    4949             :  * @see GDALRasterBand::AdviseRead()
    4950             :  */
    4951             : 
    4952           2 : CPLErr CPL_STDCALL GDALRasterAdviseRead(GDALRasterBandH hBand, int nXOff,
    4953             :                                         int nYOff, int nXSize, int nYSize,
    4954             :                                         int nBufXSize, int nBufYSize,
    4955             :                                         GDALDataType eDT,
    4956             :                                         CSLConstList papszOptions)
    4957             : 
    4958             : {
    4959           2 :     VALIDATE_POINTER1(hBand, "GDALRasterAdviseRead", CE_Failure);
    4960             : 
    4961           2 :     GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
    4962           2 :     return poBand->AdviseRead(nXOff, nYOff, nXSize, nYSize, nBufXSize,
    4963             :                               nBufYSize, eDT,
    4964           2 :                               const_cast<char **>(papszOptions));
    4965             : }
    4966             : 
    4967             : /************************************************************************/
    4968             : /*                           GetStatistics()                            */
    4969             : /************************************************************************/
    4970             : 
    4971             : /**
    4972             :  * \brief Fetch image statistics.
    4973             :  *
    4974             :  * Returns the minimum, maximum, mean and standard deviation of all
    4975             :  * pixel values in this band.  If approximate statistics are sufficient,
    4976             :  * the bApproxOK flag can be set to true in which case overviews, or a
    4977             :  * subset of image tiles may be used in computing the statistics.
    4978             :  *
    4979             :  * If bForce is FALSE results will only be returned if it can be done
    4980             :  * quickly (i.e. without scanning the image, typically by using pre-existing
    4981             :  * STATISTICS_xxx metadata items). If bForce is FALSE and results cannot be
    4982             :  * returned efficiently, the method will return CE_Warning but no warning will
    4983             :  * be issued. This is a non-standard use of the CE_Warning return value
    4984             :  * to indicate "nothing done".
    4985             :  *
    4986             :  * If bForce is TRUE, and results are quickly available without scanning the
    4987             :  * image, they will be used. If bForce is TRUE and results are not quickly
    4988             :  * available, GetStatistics() forwards the computation to ComputeStatistics(),
    4989             :  * which will scan the image.
    4990             :  *
    4991             :  * To always force recomputation of statistics, use ComputeStatistics() instead
    4992             :  * of this method.
    4993             :  *
    4994             :  * Note that file formats using PAM (Persistent Auxiliary Metadata) services
    4995             :  * will generally cache statistics in the .pam file allowing fast fetch
    4996             :  * after the first request.
    4997             :  *
    4998             :  * This method is the same as the C function GDALGetRasterStatistics().
    4999             :  *
    5000             :  * @param bApproxOK If TRUE statistics may be computed based on overviews
    5001             :  * or a subset of all tiles.
    5002             :  *
    5003             :  * @param bForce If FALSE statistics will only be returned if it can
    5004             :  * be done without rescanning the image. If TRUE, statistics computation will
    5005             :  * be forced if pre-existing values are not quickly available.
    5006             :  *
    5007             :  * @param pdfMin Location into which to load image minimum (may be NULL).
    5008             :  *
    5009             :  * @param pdfMax Location into which to load image maximum (may be NULL).-
    5010             :  *
    5011             :  * @param pdfMean Location into which to load image mean (may be NULL).
    5012             :  *
    5013             :  * @param pdfStdDev Location into which to load image standard deviation
    5014             :  * (may be NULL).
    5015             :  *
    5016             :  * @return CE_None on success, CE_Warning if no values returned,
    5017             :  * CE_Failure if an error occurs.
    5018             :  */
    5019             : 
    5020         611 : CPLErr GDALRasterBand::GetStatistics(int bApproxOK, int bForce, double *pdfMin,
    5021             :                                      double *pdfMax, double *pdfMean,
    5022             :                                      double *pdfStdDev)
    5023             : 
    5024             : {
    5025             :     /* -------------------------------------------------------------------- */
    5026             :     /*      Do we already have metadata items for the requested values?     */
    5027             :     /* -------------------------------------------------------------------- */
    5028        1222 :     if ((pdfMin == nullptr ||
    5029         611 :          GetMetadataItem("STATISTICS_MINIMUM") != nullptr) &&
    5030         202 :         (pdfMax == nullptr ||
    5031         202 :          GetMetadataItem("STATISTICS_MAXIMUM") != nullptr) &&
    5032        1424 :         (pdfMean == nullptr || GetMetadataItem("STATISTICS_MEAN") != nullptr) &&
    5033         202 :         (pdfStdDev == nullptr ||
    5034         202 :          GetMetadataItem("STATISTICS_STDDEV") != nullptr))
    5035             :     {
    5036         202 :         if (!(GetMetadataItem("STATISTICS_APPROXIMATE") && !bApproxOK))
    5037             :         {
    5038         195 :             if (pdfMin != nullptr)
    5039         195 :                 *pdfMin = CPLAtofM(GetMetadataItem("STATISTICS_MINIMUM"));
    5040         195 :             if (pdfMax != nullptr)
    5041         195 :                 *pdfMax = CPLAtofM(GetMetadataItem("STATISTICS_MAXIMUM"));
    5042         195 :             if (pdfMean != nullptr)
    5043         195 :                 *pdfMean = CPLAtofM(GetMetadataItem("STATISTICS_MEAN"));
    5044         195 :             if (pdfStdDev != nullptr)
    5045         195 :                 *pdfStdDev = CPLAtofM(GetMetadataItem("STATISTICS_STDDEV"));
    5046             : 
    5047         195 :             return CE_None;
    5048             :         }
    5049             :     }
    5050             : 
    5051             :     /* -------------------------------------------------------------------- */
    5052             :     /*      Does the driver already know the min/max?                       */
    5053             :     /* -------------------------------------------------------------------- */
    5054         416 :     if (bApproxOK && pdfMean == nullptr && pdfStdDev == nullptr)
    5055             :     {
    5056           0 :         int bSuccessMin = FALSE;
    5057           0 :         int bSuccessMax = FALSE;
    5058             : 
    5059           0 :         const double dfMin = GetMinimum(&bSuccessMin);
    5060           0 :         const double dfMax = GetMaximum(&bSuccessMax);
    5061             : 
    5062           0 :         if (bSuccessMin && bSuccessMax)
    5063             :         {
    5064           0 :             if (pdfMin != nullptr)
    5065           0 :                 *pdfMin = dfMin;
    5066           0 :             if (pdfMax != nullptr)
    5067           0 :                 *pdfMax = dfMax;
    5068           0 :             return CE_None;
    5069             :         }
    5070             :     }
    5071             : 
    5072             :     /* -------------------------------------------------------------------- */
    5073             :     /*      Either return without results, or force computation.            */
    5074             :     /* -------------------------------------------------------------------- */
    5075         416 :     if (!bForce)
    5076         161 :         return CE_Warning;
    5077             :     else
    5078         255 :         return ComputeStatistics(bApproxOK, pdfMin, pdfMax, pdfMean, pdfStdDev,
    5079         255 :                                  GDALDummyProgress, nullptr);
    5080             : }
    5081             : 
    5082             : /************************************************************************/
    5083             : /*                      GDALGetRasterStatistics()                       */
    5084             : /************************************************************************/
    5085             : 
    5086             : /**
    5087             :  * \brief Fetch image statistics.
    5088             :  *
    5089             :  * @see GDALRasterBand::GetStatistics()
    5090             :  */
    5091             : 
    5092         260 : CPLErr CPL_STDCALL GDALGetRasterStatistics(GDALRasterBandH hBand, int bApproxOK,
    5093             :                                            int bForce, double *pdfMin,
    5094             :                                            double *pdfMax, double *pdfMean,
    5095             :                                            double *pdfStdDev)
    5096             : 
    5097             : {
    5098         260 :     VALIDATE_POINTER1(hBand, "GDALGetRasterStatistics", CE_Failure);
    5099             : 
    5100         260 :     GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
    5101         260 :     return poBand->GetStatistics(bApproxOK, bForce, pdfMin, pdfMax, pdfMean,
    5102         260 :                                  pdfStdDev);
    5103             : }
    5104             : 
    5105             : /************************************************************************/
    5106             : /*                         GDALUInt128                                  */
    5107             : /************************************************************************/
    5108             : 
    5109             : #ifdef HAVE_UINT128_T
    5110             : class GDALUInt128
    5111             : {
    5112             :     __uint128_t val;
    5113             : 
    5114         630 :     explicit GDALUInt128(__uint128_t valIn) : val(valIn)
    5115             :     {
    5116         630 :     }
    5117             : 
    5118             :   public:
    5119         420 :     static GDALUInt128 Mul(GUIntBig first, GUIntBig second)
    5120             :     {
    5121             :         // Evaluates to just a single mul on x86_64
    5122         420 :         return GDALUInt128(static_cast<__uint128_t>(first) * second);
    5123             :     }
    5124             : 
    5125         210 :     GDALUInt128 operator-(const GDALUInt128 &other) const
    5126             :     {
    5127         210 :         return GDALUInt128(val - other.val);
    5128             :     }
    5129             : 
    5130         201 :     operator double() const
    5131             :     {
    5132         201 :         return static_cast<double>(val);
    5133             :     }
    5134             : };
    5135             : #else
    5136             : 
    5137             : #if defined(_MSC_VER) && defined(_M_X64)
    5138             : #include <intrin.h>
    5139             : #endif
    5140             : 
    5141             : class GDALUInt128
    5142             : {
    5143             :     GUIntBig low, high;
    5144             : 
    5145             :     GDALUInt128(GUIntBig lowIn, GUIntBig highIn) : low(lowIn), high(highIn)
    5146             :     {
    5147             :     }
    5148             : 
    5149             :   public:
    5150             :     static GDALUInt128 Mul(GUIntBig first, GUIntBig second)
    5151             :     {
    5152             : #if defined(_MSC_VER) && defined(_M_X64)
    5153             :         GUIntBig highRes;
    5154             :         GUIntBig lowRes = _umul128(first, second, &highRes);
    5155             :         return GDALUInt128(lowRes, highRes);
    5156             : #else
    5157             :         const GUInt32 firstLow = static_cast<GUInt32>(first);
    5158             :         const GUInt32 firstHigh = static_cast<GUInt32>(first >> 32);
    5159             :         const GUInt32 secondLow = static_cast<GUInt32>(second);
    5160             :         const GUInt32 secondHigh = static_cast<GUInt32>(second >> 32);
    5161             :         GUIntBig highRes = 0;
    5162             :         const GUIntBig firstLowSecondHigh =
    5163             :             static_cast<GUIntBig>(firstLow) * secondHigh;
    5164             :         const GUIntBig firstHighSecondLow =
    5165             :             static_cast<GUIntBig>(firstHigh) * secondLow;
    5166             :         const GUIntBig middleTerm = firstLowSecondHigh + firstHighSecondLow;
    5167             :         if (middleTerm < firstLowSecondHigh)  // check for overflow
    5168             :             highRes += static_cast<GUIntBig>(1) << 32;
    5169             :         const GUIntBig firstLowSecondLow =
    5170             :             static_cast<GUIntBig>(firstLow) * secondLow;
    5171             :         GUIntBig lowRes = firstLowSecondLow + (middleTerm << 32);
    5172             :         if (lowRes < firstLowSecondLow)  // check for overflow
    5173             :             highRes++;
    5174             :         highRes +=
    5175             :             (middleTerm >> 32) + static_cast<GUIntBig>(firstHigh) * secondHigh;
    5176             :         return GDALUInt128(lowRes, highRes);
    5177             : #endif
    5178             :     }
    5179             : 
    5180             :     GDALUInt128 operator-(const GDALUInt128 &other) const
    5181             :     {
    5182             :         GUIntBig highRes = high - other.high;
    5183             :         GUIntBig lowRes = low - other.low;
    5184             :         if (lowRes > low)  // check for underflow
    5185             :             --highRes;
    5186             :         return GDALUInt128(lowRes, highRes);
    5187             :     }
    5188             : 
    5189             :     operator double() const
    5190             :     {
    5191             :         const double twoPow64 = 18446744073709551616.0;
    5192             :         return high * twoPow64 + low;
    5193             :     }
    5194             : };
    5195             : #endif
    5196             : 
    5197             : /************************************************************************/
    5198             : /*                    ComputeStatisticsInternal()                       */
    5199             : /************************************************************************/
    5200             : 
    5201             : // Just to make coverity scan happy w.r.t overflow_before_widen, but otherwise
    5202             : // not needed.
    5203             : #define static_cast_for_coverity_scan static_cast
    5204             : 
    5205             : // The rationale for below optimizations is detailed in statistics.txt
    5206             : 
    5207             : // Use with T = GByte or GUInt16 only !
    5208             : template <class T, bool COMPUTE_OTHER_STATS>
    5209             : struct ComputeStatisticsInternalGeneric
    5210             : {
    5211         182 :     static void f(int nXCheck, int nBlockXSize, int nYCheck, const T *pData,
    5212             :                   bool bHasNoData, GUInt32 nNoDataValue, GUInt32 &nMin,
    5213             :                   GUInt32 &nMax, GUIntBig &nSum, GUIntBig &nSumSquare,
    5214             :                   GUIntBig &nSampleCount, GUIntBig &nValidCount)
    5215             :     {
    5216             :         static_assert(std::is_same<T, GByte>::value ||
    5217             :                           std::is_same<T, GUInt16>::value,
    5218             :                       "bad type for T");
    5219         182 :         if (bHasNoData)
    5220             :         {
    5221             :             // General case
    5222         386 :             for (int iY = 0; iY < nYCheck; iY++)
    5223             :             {
    5224       81751 :                 for (int iX = 0; iX < nXCheck; iX++)
    5225             :                 {
    5226       81468 :                     const GPtrDiff_t iOffset =
    5227       81468 :                         iX + static_cast<GPtrDiff_t>(iY) * nBlockXSize;
    5228       81468 :                     const GUInt32 nValue = pData[iOffset];
    5229       81468 :                     if (nValue == nNoDataValue)
    5230         175 :                         continue;
    5231       81293 :                     if (nValue < nMin)
    5232          26 :                         nMin = nValue;
    5233       81293 :                     if (nValue > nMax)
    5234          57 :                         nMax = nValue;
    5235             :                     if constexpr (COMPUTE_OTHER_STATS)
    5236             :                     {
    5237       79657 :                         nValidCount++;
    5238       79657 :                         nSum += nValue;
    5239       79657 :                         nSumSquare +=
    5240       79657 :                             static_cast_for_coverity_scan<GUIntBig>(nValue) *
    5241       79657 :                             nValue;
    5242             :                     }
    5243             :                 }
    5244             :             }
    5245             :             if constexpr (COMPUTE_OTHER_STATS)
    5246             :             {
    5247          20 :                 nSampleCount += static_cast<GUIntBig>(nXCheck) * nYCheck;
    5248             :             }
    5249             :         }
    5250          88 :         else if (nMin == std::numeric_limits<T>::lowest() &&
    5251           9 :                  nMax == std::numeric_limits<T>::max())
    5252             :         {
    5253             :             if constexpr (COMPUTE_OTHER_STATS)
    5254             :             {
    5255             :                 // Optimization when there is no nodata and we know we have already
    5256             :                 // reached the min and max
    5257         208 :                 for (int iY = 0; iY < nYCheck; iY++)
    5258             :                 {
    5259             :                     int iX;
    5260        1002 :                     for (iX = 0; iX + 3 < nXCheck; iX += 4)
    5261             :                     {
    5262         800 :                         const GPtrDiff_t iOffset =
    5263         800 :                             iX + static_cast<GPtrDiff_t>(iY) * nBlockXSize;
    5264         800 :                         const GUIntBig nValue = pData[iOffset];
    5265         800 :                         const GUIntBig nValue2 = pData[iOffset + 1];
    5266         800 :                         const GUIntBig nValue3 = pData[iOffset + 2];
    5267         800 :                         const GUIntBig nValue4 = pData[iOffset + 3];
    5268         800 :                         nSum += nValue;
    5269         800 :                         nSumSquare += nValue * nValue;
    5270         800 :                         nSum += nValue2;
    5271         800 :                         nSumSquare += nValue2 * nValue2;
    5272         800 :                         nSum += nValue3;
    5273         800 :                         nSumSquare += nValue3 * nValue3;
    5274         800 :                         nSum += nValue4;
    5275         800 :                         nSumSquare += nValue4 * nValue4;
    5276             :                     }
    5277         207 :                     for (; iX < nXCheck; ++iX)
    5278             :                     {
    5279           5 :                         const GPtrDiff_t iOffset =
    5280           5 :                             iX + static_cast<GPtrDiff_t>(iY) * nBlockXSize;
    5281           5 :                         const GUIntBig nValue = pData[iOffset];
    5282           5 :                         nSum += nValue;
    5283           5 :                         nSumSquare += nValue * nValue;
    5284             :                     }
    5285             :                 }
    5286           6 :                 nSampleCount += static_cast<GUIntBig>(nXCheck) * nYCheck;
    5287           6 :                 nValidCount += static_cast<GUIntBig>(nXCheck) * nYCheck;
    5288             :             }
    5289             :         }
    5290             :         else
    5291             :         {
    5292        3366 :             for (int iY = 0; iY < nYCheck; iY++)
    5293             :             {
    5294             :                 int iX;
    5295      635062 :                 for (iX = 0; iX + 1 < nXCheck; iX += 2)
    5296             :                 {
    5297      631769 :                     const GPtrDiff_t iOffset =
    5298      631769 :                         iX + static_cast<GPtrDiff_t>(iY) * nBlockXSize;
    5299      631769 :                     const GUInt32 nValue = pData[iOffset];
    5300      631769 :                     const GUInt32 nValue2 = pData[iOffset + 1];
    5301      631769 :                     if (nValue < nValue2)
    5302             :                     {
    5303        2160 :                         if (nValue < nMin)
    5304          48 :                             nMin = nValue;
    5305        2160 :                         if (nValue2 > nMax)
    5306         108 :                             nMax = nValue2;
    5307             :                     }
    5308             :                     else
    5309             :                     {
    5310      629609 :                         if (nValue2 < nMin)
    5311          61 :                             nMin = nValue2;
    5312      629609 :                         if (nValue > nMax)
    5313         212 :                             nMax = nValue;
    5314             :                     }
    5315             :                     if constexpr (COMPUTE_OTHER_STATS)
    5316             :                     {
    5317      624719 :                         nSum += nValue;
    5318      624719 :                         nSumSquare +=
    5319      624719 :                             static_cast_for_coverity_scan<GUIntBig>(nValue) *
    5320      624719 :                             nValue;
    5321      624719 :                         nSum += nValue2;
    5322      624719 :                         nSumSquare +=
    5323      624719 :                             static_cast_for_coverity_scan<GUIntBig>(nValue2) *
    5324      624719 :                             nValue2;
    5325             :                     }
    5326             :                 }
    5327        3293 :                 if (iX < nXCheck)
    5328             :                 {
    5329           9 :                     const GPtrDiff_t iOffset =
    5330           9 :                         iX + static_cast<GPtrDiff_t>(iY) * nBlockXSize;
    5331           9 :                     const GUInt32 nValue = pData[iOffset];
    5332           9 :                     if (nValue < nMin)
    5333           6 :                         nMin = nValue;
    5334           9 :                     if (nValue > nMax)
    5335           6 :                         nMax = nValue;
    5336             :                     if (COMPUTE_OTHER_STATS)
    5337             :                     {
    5338           9 :                         nSum += nValue;
    5339           9 :                         nSumSquare +=
    5340           9 :                             static_cast_for_coverity_scan<GUIntBig>(nValue) *
    5341           9 :                             nValue;
    5342             :                     }
    5343             :                 }
    5344             :             }
    5345             :             if constexpr (COMPUTE_OTHER_STATS)
    5346             :             {
    5347          28 :                 nSampleCount += static_cast<GUIntBig>(nXCheck) * nYCheck;
    5348          28 :                 nValidCount += static_cast<GUIntBig>(nXCheck) * nYCheck;
    5349             :             }
    5350             :         }
    5351         182 :     }
    5352             : };
    5353             : 
    5354             : // Specialization for Byte that is mostly 32 bit friendly as it avoids
    5355             : // using 64bit accumulators in internal loops. This also slightly helps in
    5356             : // 64bit mode.
    5357             : template <bool COMPUTE_OTHER_STATS>
    5358             : struct ComputeStatisticsInternalGeneric<GByte, COMPUTE_OTHER_STATS>
    5359             : {
    5360       11771 :     static void f(int nXCheck, int nBlockXSize, int nYCheck, const GByte *pData,
    5361             :                   bool bHasNoData, GUInt32 nNoDataValue, GUInt32 &nMin,
    5362             :                   GUInt32 &nMax, GUIntBig &nSum, GUIntBig &nSumSquare,
    5363             :                   GUIntBig &nSampleCount, GUIntBig &nValidCount)
    5364             :     {
    5365       11771 :         int nOuterLoops = nXCheck / 65536;
    5366       11771 :         if (nXCheck % 65536)
    5367       11771 :             nOuterLoops++;
    5368             : 
    5369       11771 :         if (bHasNoData)
    5370             :         {
    5371             :             // General case
    5372       19547 :             for (int iY = 0; iY < nYCheck; iY++)
    5373             :             {
    5374       10937 :                 int iX = 0;
    5375       21874 :                 for (int k = 0; k < nOuterLoops; k++)
    5376             :                 {
    5377       10937 :                     int iMax = iX + 65536;
    5378       10937 :                     if (iMax > nXCheck)
    5379       10937 :                         iMax = nXCheck;
    5380       10937 :                     GUInt32 nSum32bit = 0;
    5381       10937 :                     GUInt32 nSumSquare32bit = 0;
    5382       10937 :                     GUInt32 nValidCount32bit = 0;
    5383       10937 :                     GUInt32 nSampleCount32bit = 0;
    5384    16705735 :                     for (; iX < iMax; iX++)
    5385             :                     {
    5386    16694886 :                         const GPtrDiff_t iOffset =
    5387    16694886 :                             iX + static_cast<GPtrDiff_t>(iY) * nBlockXSize;
    5388    16694886 :                         const GUInt32 nValue = pData[iOffset];
    5389             : 
    5390    16694886 :                         nSampleCount32bit++;
    5391    16694886 :                         if (nValue == nNoDataValue)
    5392    16353432 :                             continue;
    5393      341399 :                         if (nValue < nMin)
    5394         343 :                             nMin = nValue;
    5395      341399 :                         if (nValue > nMax)
    5396         828 :                             nMax = nValue;
    5397             :                         if constexpr (COMPUTE_OTHER_STATS)
    5398             :                         {
    5399       16954 :                             nValidCount32bit++;
    5400       16954 :                             nSum32bit += nValue;
    5401       16954 :                             nSumSquare32bit += nValue * nValue;
    5402             :                         }
    5403             :                     }
    5404             :                     if constexpr (COMPUTE_OTHER_STATS)
    5405             :                     {
    5406         649 :                         nSampleCount += nSampleCount32bit;
    5407         649 :                         nValidCount += nValidCount32bit;
    5408         649 :                         nSum += nSum32bit;
    5409         649 :                         nSumSquare += nSumSquare32bit;
    5410             :                     }
    5411             :                 }
    5412             :             }
    5413             :         }
    5414        3161 :         else if (nMin == 0 && nMax == 255)
    5415             :         {
    5416             :             if constexpr (COMPUTE_OTHER_STATS)
    5417             :             {
    5418             :                 // Optimization when there is no nodata and we know we have already
    5419             :                 // reached the min and max
    5420        2644 :                 for (int iY = 0; iY < nYCheck; iY++)
    5421             :                 {
    5422        2617 :                     int iX = 0;
    5423        5234 :                     for (int k = 0; k < nOuterLoops; k++)
    5424             :                     {
    5425        2617 :                         int iMax = iX + 65536;
    5426        2617 :                         if (iMax > nXCheck)
    5427        2617 :                             iMax = nXCheck;
    5428        2617 :                         GUInt32 nSum32bit = 0;
    5429        2617 :                         GUInt32 nSumSquare32bit = 0;
    5430      176297 :                         for (; iX + 3 < iMax; iX += 4)
    5431             :                         {
    5432      173680 :                             const GPtrDiff_t iOffset =
    5433      173680 :                                 iX + static_cast<GPtrDiff_t>(iY) * nBlockXSize;
    5434      173680 :                             const GUInt32 nValue = pData[iOffset];
    5435      173680 :                             const GUInt32 nValue2 = pData[iOffset + 1];
    5436      173680 :                             const GUInt32 nValue3 = pData[iOffset + 2];
    5437      173680 :                             const GUInt32 nValue4 = pData[iOffset + 3];
    5438      173680 :                             nSum32bit += nValue;
    5439      173680 :                             nSumSquare32bit += nValue * nValue;
    5440      173680 :                             nSum32bit += nValue2;
    5441      173680 :                             nSumSquare32bit += nValue2 * nValue2;
    5442      173680 :                             nSum32bit += nValue3;
    5443      173680 :                             nSumSquare32bit += nValue3 * nValue3;
    5444      173680 :                             nSum32bit += nValue4;
    5445      173680 :                             nSumSquare32bit += nValue4 * nValue4;
    5446             :                         }
    5447        2617 :                         nSum += nSum32bit;
    5448        2617 :                         nSumSquare += nSumSquare32bit;
    5449             :                     }
    5450        2620 :                     for (; iX < nXCheck; ++iX)
    5451             :                     {
    5452           3 :                         const GPtrDiff_t iOffset =
    5453           3 :                             iX + static_cast<GPtrDiff_t>(iY) * nBlockXSize;
    5454           3 :                         const GUIntBig nValue = pData[iOffset];
    5455           3 :                         nSum += nValue;
    5456           3 :                         nSumSquare += nValue * nValue;
    5457             :                     }
    5458             :                 }
    5459          27 :                 nSampleCount += static_cast<GUIntBig>(nXCheck) * nYCheck;
    5460          27 :                 nValidCount += static_cast<GUIntBig>(nXCheck) * nYCheck;
    5461          27 :             }
    5462             :         }
    5463             :         else
    5464             :         {
    5465        7930 :             for (int iY = 0; iY < nYCheck; iY++)
    5466             :             {
    5467        4796 :                 int iX = 0;
    5468        9592 :                 for (int k = 0; k < nOuterLoops; k++)
    5469             :                 {
    5470        4796 :                     int iMax = iX + 65536;
    5471        4796 :                     if (iMax > nXCheck)
    5472        4796 :                         iMax = nXCheck;
    5473        4796 :                     GUInt32 nSum32bit = 0;
    5474        4796 :                     GUInt32 nSumSquare32bit = 0;
    5475      161815 :                     for (; iX + 1 < iMax; iX += 2)
    5476             :                     {
    5477      157019 :                         const GPtrDiff_t iOffset =
    5478      157019 :                             iX + static_cast<GPtrDiff_t>(iY) * nBlockXSize;
    5479      157019 :                         const GUInt32 nValue = pData[iOffset];
    5480      157019 :                         const GUInt32 nValue2 = pData[iOffset + 1];
    5481      157019 :                         if (nValue < nValue2)
    5482             :                         {
    5483        9010 :                             if (nValue < nMin)
    5484         254 :                                 nMin = nValue;
    5485        9010 :                             if (nValue2 > nMax)
    5486         241 :                                 nMax = nValue2;
    5487             :                         }
    5488             :                         else
    5489             :                         {
    5490      148009 :                             if (nValue2 < nMin)
    5491         301 :                                 nMin = nValue2;
    5492      148009 :                             if (nValue > nMax)
    5493         863 :                                 nMax = nValue;
    5494             :                         }
    5495             :                         if constexpr (COMPUTE_OTHER_STATS)
    5496             :                         {
    5497      132599 :                             nSum32bit += nValue;
    5498      132599 :                             nSumSquare32bit += nValue * nValue;
    5499      132599 :                             nSum32bit += nValue2;
    5500      132599 :                             nSumSquare32bit += nValue2 * nValue2;
    5501             :                         }
    5502             :                     }
    5503             :                     if constexpr (COMPUTE_OTHER_STATS)
    5504             :                     {
    5505        1626 :                         nSum += nSum32bit;
    5506        1626 :                         nSumSquare += nSumSquare32bit;
    5507             :                     }
    5508             :                 }
    5509        4796 :                 if (iX < nXCheck)
    5510             :                 {
    5511        1384 :                     const GPtrDiff_t iOffset =
    5512        1384 :                         iX + static_cast<GPtrDiff_t>(iY) * nBlockXSize;
    5513        1384 :                     const GUInt32 nValue = pData[iOffset];
    5514        1384 :                     if (nValue < nMin)
    5515          39 :                         nMin = nValue;
    5516        1384 :                     if (nValue > nMax)
    5517          48 :                         nMax = nValue;
    5518             :                     if constexpr (COMPUTE_OTHER_STATS)
    5519             :                     {
    5520         312 :                         nSum += nValue;
    5521         312 :                         nSumSquare +=
    5522         312 :                             static_cast_for_coverity_scan<GUIntBig>(nValue) *
    5523         312 :                             nValue;
    5524             :                     }
    5525             :                 }
    5526             :             }
    5527             :             if constexpr (COMPUTE_OTHER_STATS)
    5528             :             {
    5529         922 :                 nSampleCount += static_cast<GUIntBig>(nXCheck) * nYCheck;
    5530         922 :                 nValidCount += static_cast<GUIntBig>(nXCheck) * nYCheck;
    5531             :             }
    5532             :         }
    5533       11771 :     }
    5534             : };
    5535             : 
    5536             : template <class T, bool COMPUTE_OTHER_STATS> struct ComputeStatisticsInternal
    5537             : {
    5538             :     static void f(int nXCheck, int nBlockXSize, int nYCheck, const T *pData,
    5539             :                   bool bHasNoData, GUInt32 nNoDataValue, GUInt32 &nMin,
    5540             :                   GUInt32 &nMax, GUIntBig &nSum, GUIntBig &nSumSquare,
    5541             :                   GUIntBig &nSampleCount, GUIntBig &nValidCount)
    5542             :     {
    5543             :         ComputeStatisticsInternalGeneric<T, COMPUTE_OTHER_STATS>::f(
    5544             :             nXCheck, nBlockXSize, nYCheck, pData, bHasNoData, nNoDataValue,
    5545             :             nMin, nMax, nSum, nSumSquare, nSampleCount, nValidCount);
    5546             :     }
    5547             : };
    5548             : 
    5549             : #if (defined(__x86_64__) || defined(_M_X64)) &&                                \
    5550             :     (defined(__GNUC__) || defined(_MSC_VER))
    5551             : 
    5552             : #include "gdal_avx2_emulation.hpp"
    5553             : 
    5554             : #define ZERO256 GDALmm256_setzero_si256()
    5555             : 
    5556             : template <bool COMPUTE_MIN, bool COMPUTE_MAX, bool COMPUTE_OTHER_STATS>
    5557             : static void
    5558       19033 : ComputeStatisticsByteNoNodata(GPtrDiff_t nBlockPixels,
    5559             :                               // assumed to be aligned on 256 bits
    5560             :                               const GByte *pData, GUInt32 &nMin, GUInt32 &nMax,
    5561             :                               GUIntBig &nSum, GUIntBig &nSumSquare,
    5562             :                               GUIntBig &nSampleCount, GUIntBig &nValidCount)
    5563             : {
    5564             :     // 32-byte alignment may not be enforced by linker, so do it at hand
    5565             :     GByte
    5566             :         aby32ByteUnaligned[32 + 32 + 32 + (COMPUTE_OTHER_STATS ? 32 + 32 : 0)];
    5567       19033 :     GByte *paby32ByteAligned =
    5568             :         aby32ByteUnaligned +
    5569       19033 :         (32 - (reinterpret_cast<GUIntptr_t>(aby32ByteUnaligned) % 32));
    5570       19033 :     GByte *pabyMin = paby32ByteAligned;
    5571       19033 :     GByte *pabyMax = paby32ByteAligned + 32;
    5572       19033 :     GUInt32 *panSum =
    5573             :         COMPUTE_OTHER_STATS
    5574             :             ? reinterpret_cast<GUInt32 *>(paby32ByteAligned + 32 * 2)
    5575             :             : nullptr;
    5576       19033 :     GUInt32 *panSumSquare =
    5577             :         COMPUTE_OTHER_STATS
    5578             :             ? reinterpret_cast<GUInt32 *>(paby32ByteAligned + 32 * 3)
    5579             :             : nullptr;
    5580             : 
    5581       19033 :     CPLAssert((reinterpret_cast<uintptr_t>(pData) % 32) == 0);
    5582             : 
    5583       19033 :     GPtrDiff_t i = 0;
    5584             :     // Make sure that sumSquare can fit on uint32
    5585             :     // * 8 since we can hold 8 sums per vector register
    5586       19033 :     const int nMaxIterationsPerInnerLoop =
    5587             :         8 * ((std::numeric_limits<GUInt32>::max() / (255 * 255)) & ~31);
    5588       19033 :     GPtrDiff_t nOuterLoops = nBlockPixels / nMaxIterationsPerInnerLoop;
    5589       19033 :     if ((nBlockPixels % nMaxIterationsPerInnerLoop) != 0)
    5590       19033 :         nOuterLoops++;
    5591             : 
    5592             :     GDALm256i ymm_min =
    5593       19033 :         GDALmm256_load_si256(reinterpret_cast<const GDALm256i *>(pData + i));
    5594       19033 :     GDALm256i ymm_max = ymm_min;
    5595       19033 :     [[maybe_unused]] const auto ymm_mask_8bits = GDALmm256_set1_epi16(0xFF);
    5596             : 
    5597       38066 :     for (GPtrDiff_t k = 0; k < nOuterLoops; k++)
    5598             :     {
    5599       19033 :         const auto iMax =
    5600       19033 :             std::min(nBlockPixels, i + nMaxIterationsPerInnerLoop);
    5601             : 
    5602             :         // holds 4 uint32 sums in [0], [2], [4] and [6]
    5603       19033 :         [[maybe_unused]] GDALm256i ymm_sum = ZERO256;
    5604             :         [[maybe_unused]] GDALm256i ymm_sumsquare =
    5605       19033 :             ZERO256;  // holds 8 uint32 sums
    5606      641852 :         for (; i + 31 < iMax; i += 32)
    5607             :         {
    5608      622819 :             const GDALm256i ymm = GDALmm256_load_si256(
    5609      622819 :                 reinterpret_cast<const GDALm256i *>(pData + i));
    5610             :             if (COMPUTE_MIN)
    5611             :             {
    5612      164884 :                 ymm_min = GDALmm256_min_epu8(ymm_min, ymm);
    5613             :             }
    5614             :             if (COMPUTE_MAX)
    5615             :             {
    5616      531878 :                 ymm_max = GDALmm256_max_epu8(ymm_max, ymm);
    5617             :             }
    5618             : 
    5619             :             if constexpr (COMPUTE_OTHER_STATS)
    5620             :             {
    5621             :                 // Extract even-8bit values
    5622             :                 const GDALm256i ymm_even =
    5623      493495 :                     GDALmm256_and_si256(ymm, ymm_mask_8bits);
    5624             :                 // Compute square of those 16 values as 32 bit result
    5625             :                 // and add adjacent pairs
    5626             :                 const GDALm256i ymm_even_square =
    5627      493495 :                     GDALmm256_madd_epi16(ymm_even, ymm_even);
    5628             :                 // Add to the sumsquare accumulator
    5629             :                 ymm_sumsquare =
    5630      493495 :                     GDALmm256_add_epi32(ymm_sumsquare, ymm_even_square);
    5631             : 
    5632             :                 // Extract odd-8bit values
    5633      493495 :                 const GDALm256i ymm_odd = GDALmm256_srli_epi16(ymm, 8);
    5634             :                 const GDALm256i ymm_odd_square =
    5635      493495 :                     GDALmm256_madd_epi16(ymm_odd, ymm_odd);
    5636             :                 ymm_sumsquare =
    5637      493495 :                     GDALmm256_add_epi32(ymm_sumsquare, ymm_odd_square);
    5638             : 
    5639             :                 // Now compute the sums
    5640      493495 :                 ymm_sum = GDALmm256_add_epi32(ymm_sum,
    5641             :                                               GDALmm256_sad_epu8(ymm, ZERO256));
    5642             :             }
    5643             :         }
    5644             : 
    5645             :         if constexpr (COMPUTE_OTHER_STATS)
    5646             :         {
    5647       10649 :             GDALmm256_store_si256(reinterpret_cast<GDALm256i *>(panSum),
    5648             :                                   ymm_sum);
    5649       10649 :             GDALmm256_store_si256(reinterpret_cast<GDALm256i *>(panSumSquare),
    5650             :                                   ymm_sumsquare);
    5651             : 
    5652       10649 :             nSum += panSum[0] + panSum[2] + panSum[4] + panSum[6];
    5653       10649 :             nSumSquare += static_cast<GUIntBig>(panSumSquare[0]) +
    5654       10649 :                           panSumSquare[1] + panSumSquare[2] + panSumSquare[3] +
    5655       10649 :                           panSumSquare[4] + panSumSquare[5] + panSumSquare[6] +
    5656             :                           panSumSquare[7];
    5657             :         }
    5658             :     }
    5659             : 
    5660             :     if constexpr (COMPUTE_MIN)
    5661             :     {
    5662        6061 :         GDALmm256_store_si256(reinterpret_cast<GDALm256i *>(pabyMin), ymm_min);
    5663             :     }
    5664             :     if constexpr (COMPUTE_MAX)
    5665             :     {
    5666       15036 :         GDALmm256_store_si256(reinterpret_cast<GDALm256i *>(pabyMax), ymm_max);
    5667             :     }
    5668             :     if constexpr (COMPUTE_MIN || COMPUTE_MAX)
    5669             :     {
    5670      513678 :         for (int j = 0; j < 32; j++)
    5671             :         {
    5672             :             if constexpr (COMPUTE_MIN)
    5673             :             {
    5674      193952 :                 if (pabyMin[j] < nMin)
    5675        1264 :                     nMin = pabyMin[j];
    5676             :             }
    5677             :             if constexpr (COMPUTE_MAX)
    5678             :             {
    5679      481152 :                 if (pabyMax[j] > nMax)
    5680        1817 :                     nMax = pabyMax[j];
    5681             :             }
    5682             :         }
    5683             :     }
    5684             : 
    5685      211583 :     for (; i < nBlockPixels; i++)
    5686             :     {
    5687      192550 :         const GUInt32 nValue = pData[i];
    5688             :         if constexpr (COMPUTE_MIN)
    5689             :         {
    5690       66110 :             if (nValue < nMin)
    5691           1 :                 nMin = nValue;
    5692             :         }
    5693             :         if constexpr (COMPUTE_MAX)
    5694             :         {
    5695      189775 :             if (nValue > nMax)
    5696        1167 :                 nMax = nValue;
    5697             :         }
    5698             :         if constexpr (COMPUTE_OTHER_STATS)
    5699             :         {
    5700       77195 :             nSum += nValue;
    5701       77195 :             nSumSquare +=
    5702       77195 :                 static_cast_for_coverity_scan<GUIntBig>(nValue) * nValue;
    5703             :         }
    5704             :     }
    5705             : 
    5706             :     if constexpr (COMPUTE_OTHER_STATS)
    5707             :     {
    5708       10649 :         nSampleCount += static_cast<GUIntBig>(nBlockPixels);
    5709       10649 :         nValidCount += static_cast<GUIntBig>(nBlockPixels);
    5710             :     }
    5711       19033 : }
    5712             : 
    5713             : // SSE2/AVX2 optimization for GByte case
    5714             : // In pure SSE2, this relies on gdal_avx2_emulation.hpp. There is no
    5715             : // penaly in using the emulation, because, given the mm256 intrinsics used here,
    5716             : // there are strictly equivalent to 2 parallel SSE2 streams.
    5717             : template <bool COMPUTE_OTHER_STATS>
    5718             : struct ComputeStatisticsInternal<GByte, COMPUTE_OTHER_STATS>
    5719             : {
    5720       28117 :     static void f(int nXCheck, int nBlockXSize, int nYCheck,
    5721             :                   // assumed to be aligned on 256 bits
    5722             :                   const GByte *pData, bool bHasNoData, GUInt32 nNoDataValue,
    5723             :                   GUInt32 &nMin, GUInt32 &nMax, GUIntBig &nSum,
    5724             :                   GUIntBig &nSumSquare, GUIntBig &nSampleCount,
    5725             :                   GUIntBig &nValidCount)
    5726             :     {
    5727       28117 :         const auto nBlockPixels = static_cast<GPtrDiff_t>(nXCheck) * nYCheck;
    5728       28117 :         if (bHasNoData && nXCheck == nBlockXSize && nBlockPixels >= 32 &&
    5729        9352 :             nMin <= nMax)
    5730             :         {
    5731             :             // 32-byte alignment may not be enforced by linker, so do it at hand
    5732             :             GByte aby32ByteUnaligned[32 + 32 + 32 + 32 + 32];
    5733        1240 :             GByte *paby32ByteAligned =
    5734             :                 aby32ByteUnaligned +
    5735        1240 :                 (32 - (reinterpret_cast<GUIntptr_t>(aby32ByteUnaligned) % 32));
    5736        1240 :             GByte *pabyMin = paby32ByteAligned;
    5737        1240 :             GByte *pabyMax = paby32ByteAligned + 32;
    5738        1240 :             GUInt32 *panSum =
    5739             :                 reinterpret_cast<GUInt32 *>(paby32ByteAligned + 32 * 2);
    5740        1240 :             GUInt32 *panSumSquare =
    5741             :                 reinterpret_cast<GUInt32 *>(paby32ByteAligned + 32 * 3);
    5742             : 
    5743        1240 :             CPLAssert((reinterpret_cast<uintptr_t>(pData) % 32) == 0);
    5744             : 
    5745        1240 :             GPtrDiff_t i = 0;
    5746             :             // Make sure that sumSquare can fit on uint32
    5747             :             // * 8 since we can hold 8 sums per vector register
    5748        1240 :             const int nMaxIterationsPerInnerLoop =
    5749             :                 8 * ((std::numeric_limits<GUInt32>::max() / (255 * 255)) & ~31);
    5750        1240 :             auto nOuterLoops = nBlockPixels / nMaxIterationsPerInnerLoop;
    5751        1240 :             if ((nBlockPixels % nMaxIterationsPerInnerLoop) != 0)
    5752        1240 :                 nOuterLoops++;
    5753             : 
    5754             :             const GDALm256i ymm_nodata =
    5755        1240 :                 GDALmm256_set1_epi8(static_cast<GByte>(nNoDataValue));
    5756             :             // any non noData value in [min,max] would do.
    5757             :             const GDALm256i ymm_neutral =
    5758        1240 :                 GDALmm256_set1_epi8(static_cast<GByte>(nMin));
    5759        1240 :             GDALm256i ymm_min = ymm_neutral;
    5760        1240 :             GDALm256i ymm_max = ymm_neutral;
    5761             :             [[maybe_unused]] const auto ymm_mask_8bits =
    5762        1240 :                 GDALmm256_set1_epi16(0xFF);
    5763             : 
    5764        1240 :             const GUInt32 nMinThreshold = (nNoDataValue == 0) ? 1 : 0;
    5765        1240 :             const GUInt32 nMaxThreshold = (nNoDataValue == 255) ? 254 : 255;
    5766        1240 :             const bool bComputeMinMax =
    5767        1240 :                 nMin > nMinThreshold || nMax < nMaxThreshold;
    5768             : 
    5769        2480 :             for (GPtrDiff_t k = 0; k < nOuterLoops; k++)
    5770             :             {
    5771        1240 :                 const auto iMax =
    5772        1240 :                     std::min(nBlockPixels, i + nMaxIterationsPerInnerLoop);
    5773             : 
    5774             :                 // holds 4 uint32 sums in [0], [2], [4] and [6]
    5775        1240 :                 [[maybe_unused]] GDALm256i ymm_sum = ZERO256;
    5776             :                 // holds 8 uint32 sums
    5777        1240 :                 [[maybe_unused]] GDALm256i ymm_sumsquare = ZERO256;
    5778             :                 // holds 4 uint32 sums in [0], [2], [4] and [6]
    5779        1240 :                 [[maybe_unused]] GDALm256i ymm_count_nodata_mul_255 = ZERO256;
    5780        1240 :                 const auto iInit = i;
    5781       13799 :                 for (; i + 31 < iMax; i += 32)
    5782             :                 {
    5783       12559 :                     const GDALm256i ymm = GDALmm256_load_si256(
    5784       12559 :                         reinterpret_cast<const GDALm256i *>(pData + i));
    5785             : 
    5786             :                     // Check which values are nodata
    5787             :                     const GDALm256i ymm_eq_nodata =
    5788       12559 :                         GDALmm256_cmpeq_epi8(ymm, ymm_nodata);
    5789             :                     if constexpr (COMPUTE_OTHER_STATS)
    5790             :                     {
    5791             :                         // Count how many values are nodata (due to cmpeq
    5792             :                         // putting 255 when condition is met, this will actually
    5793             :                         // be 255 times the number of nodata value, spread in 4
    5794             :                         // 64 bits words). We can use add_epi32 as the counter
    5795             :                         // will not overflow uint32
    5796        4514 :                         ymm_count_nodata_mul_255 = GDALmm256_add_epi32(
    5797             :                             ymm_count_nodata_mul_255,
    5798             :                             GDALmm256_sad_epu8(ymm_eq_nodata, ZERO256));
    5799             :                     }
    5800             :                     // Replace all nodata values by zero for the purpose of sum
    5801             :                     // and sumquare.
    5802             :                     const GDALm256i ymm_nodata_by_zero =
    5803       12559 :                         GDALmm256_andnot_si256(ymm_eq_nodata, ymm);
    5804       12559 :                     if (bComputeMinMax)
    5805             :                     {
    5806             :                         // Replace all nodata values by a neutral value for the
    5807             :                         // purpose of min and max.
    5808             :                         const GDALm256i ymm_nodata_by_neutral =
    5809        8174 :                             GDALmm256_or_si256(
    5810             :                                 GDALmm256_and_si256(ymm_eq_nodata, ymm_neutral),
    5811             :                                 ymm_nodata_by_zero);
    5812             : 
    5813             :                         ymm_min =
    5814        8174 :                             GDALmm256_min_epu8(ymm_min, ymm_nodata_by_neutral);
    5815             :                         ymm_max =
    5816        8174 :                             GDALmm256_max_epu8(ymm_max, ymm_nodata_by_neutral);
    5817             :                     }
    5818             : 
    5819             :                     if constexpr (COMPUTE_OTHER_STATS)
    5820             :                     {
    5821             :                         // Extract even-8bit values
    5822        4514 :                         const GDALm256i ymm_even = GDALmm256_and_si256(
    5823             :                             ymm_nodata_by_zero, ymm_mask_8bits);
    5824             :                         // Compute square of those 16 values as 32 bit result
    5825             :                         // and add adjacent pairs
    5826             :                         const GDALm256i ymm_even_square =
    5827        4514 :                             GDALmm256_madd_epi16(ymm_even, ymm_even);
    5828             :                         // Add to the sumsquare accumulator
    5829             :                         ymm_sumsquare =
    5830        4514 :                             GDALmm256_add_epi32(ymm_sumsquare, ymm_even_square);
    5831             : 
    5832             :                         // Extract odd-8bit values
    5833             :                         const GDALm256i ymm_odd =
    5834        4514 :                             GDALmm256_srli_epi16(ymm_nodata_by_zero, 8);
    5835             :                         const GDALm256i ymm_odd_square =
    5836        4514 :                             GDALmm256_madd_epi16(ymm_odd, ymm_odd);
    5837             :                         ymm_sumsquare =
    5838        4514 :                             GDALmm256_add_epi32(ymm_sumsquare, ymm_odd_square);
    5839             : 
    5840             :                         // Now compute the sums
    5841        4514 :                         ymm_sum = GDALmm256_add_epi32(
    5842             :                             ymm_sum,
    5843             :                             GDALmm256_sad_epu8(ymm_nodata_by_zero, ZERO256));
    5844             :                     }
    5845             :                 }
    5846             : 
    5847             :                 if constexpr (COMPUTE_OTHER_STATS)
    5848             :                 {
    5849          33 :                     GUInt32 *panCoutNoDataMul255 = panSum;
    5850          33 :                     GDALmm256_store_si256(
    5851             :                         reinterpret_cast<GDALm256i *>(panCoutNoDataMul255),
    5852             :                         ymm_count_nodata_mul_255);
    5853             : 
    5854          33 :                     nSampleCount += (i - iInit);
    5855             : 
    5856          33 :                     nValidCount +=
    5857          33 :                         (i - iInit) -
    5858          33 :                         (panCoutNoDataMul255[0] + panCoutNoDataMul255[2] +
    5859          33 :                          panCoutNoDataMul255[4] + panCoutNoDataMul255[6]) /
    5860             :                             255;
    5861             : 
    5862          33 :                     GDALmm256_store_si256(reinterpret_cast<GDALm256i *>(panSum),
    5863             :                                           ymm_sum);
    5864          33 :                     GDALmm256_store_si256(
    5865             :                         reinterpret_cast<GDALm256i *>(panSumSquare),
    5866             :                         ymm_sumsquare);
    5867          33 :                     nSum += panSum[0] + panSum[2] + panSum[4] + panSum[6];
    5868          33 :                     nSumSquare += static_cast<GUIntBig>(panSumSquare[0]) +
    5869          33 :                                   panSumSquare[1] + panSumSquare[2] +
    5870          33 :                                   panSumSquare[3] + panSumSquare[4] +
    5871          33 :                                   panSumSquare[5] + panSumSquare[6] +
    5872             :                                   panSumSquare[7];
    5873             :                 }
    5874             :             }
    5875             : 
    5876        1240 :             if (bComputeMinMax)
    5877             :             {
    5878        1209 :                 GDALmm256_store_si256(reinterpret_cast<GDALm256i *>(pabyMin),
    5879             :                                       ymm_min);
    5880        1209 :                 GDALmm256_store_si256(reinterpret_cast<GDALm256i *>(pabyMax),
    5881             :                                       ymm_max);
    5882       39897 :                 for (int j = 0; j < 32; j++)
    5883             :                 {
    5884       38688 :                     if (pabyMin[j] < nMin)
    5885          32 :                         nMin = pabyMin[j];
    5886       38688 :                     if (pabyMax[j] > nMax)
    5887         157 :                         nMax = pabyMax[j];
    5888             :                 }
    5889             :             }
    5890             : 
    5891             :             if constexpr (COMPUTE_OTHER_STATS)
    5892             :             {
    5893          33 :                 nSampleCount += nBlockPixels - i;
    5894             :             }
    5895       29810 :             for (; i < nBlockPixels; i++)
    5896             :             {
    5897       28570 :                 const GUInt32 nValue = pData[i];
    5898       28570 :                 if (nValue == nNoDataValue)
    5899       24923 :                     continue;
    5900        3647 :                 if (nValue < nMin)
    5901           1 :                     nMin = nValue;
    5902        3647 :                 if (nValue > nMax)
    5903          13 :                     nMax = nValue;
    5904             :                 if constexpr (COMPUTE_OTHER_STATS)
    5905             :                 {
    5906         110 :                     nValidCount++;
    5907         110 :                     nSum += nValue;
    5908         110 :                     nSumSquare +=
    5909         110 :                         static_cast_for_coverity_scan<GUIntBig>(nValue) *
    5910         110 :                         nValue;
    5911             :                 }
    5912        1240 :             }
    5913             :         }
    5914       26877 :         else if (!bHasNoData && nXCheck == nBlockXSize && nBlockPixels >= 32)
    5915             :         {
    5916       15077 :             if (nMin > 0)
    5917             :             {
    5918        2105 :                 if (nMax < 255)
    5919             :                 {
    5920             :                     ComputeStatisticsByteNoNodata<true, true,
    5921        1575 :                                                   COMPUTE_OTHER_STATS>(
    5922             :                         nBlockPixels, pData, nMin, nMax, nSum, nSumSquare,
    5923             :                         nSampleCount, nValidCount);
    5924             :                 }
    5925             :                 else
    5926             :                 {
    5927             :                     ComputeStatisticsByteNoNodata<true, false,
    5928         530 :                                                   COMPUTE_OTHER_STATS>(
    5929             :                         nBlockPixels, pData, nMin, nMax, nSum, nSumSquare,
    5930             :                         nSampleCount, nValidCount);
    5931             :                 }
    5932             :             }
    5933             :             else
    5934             :             {
    5935       12972 :                 if (nMax < 255)
    5936             :                 {
    5937             :                     ComputeStatisticsByteNoNodata<false, true,
    5938        9505 :                                                   COMPUTE_OTHER_STATS>(
    5939             :                         nBlockPixels, pData, nMin, nMax, nSum, nSumSquare,
    5940             :                         nSampleCount, nValidCount);
    5941             :                 }
    5942             :                 else
    5943             :                 {
    5944             :                     ComputeStatisticsByteNoNodata<false, false,
    5945        3467 :                                                   COMPUTE_OTHER_STATS>(
    5946             :                         nBlockPixels, pData, nMin, nMax, nSum, nSumSquare,
    5947             :                         nSampleCount, nValidCount);
    5948             :                 }
    5949             :             }
    5950             :         }
    5951       10533 :         else if (!COMPUTE_OTHER_STATS && !bHasNoData && nXCheck >= 32 &&
    5952          27 :                  (nBlockXSize % 32) == 0)
    5953             :         {
    5954        3983 :             for (int iY = 0; iY < nYCheck; iY++)
    5955             :             {
    5956        3956 :                 ComputeStatisticsByteNoNodata<true, true, COMPUTE_OTHER_STATS>(
    5957        3956 :                     nXCheck, pData + static_cast<size_t>(iY) * nBlockXSize,
    5958             :                     nMin, nMax, nSum, nSumSquare, nSampleCount, nValidCount);
    5959          27 :             }
    5960             :         }
    5961             :         else
    5962             :         {
    5963       11773 :             ComputeStatisticsInternalGeneric<GByte, COMPUTE_OTHER_STATS>::f(
    5964             :                 nXCheck, nBlockXSize, nYCheck, pData, bHasNoData, nNoDataValue,
    5965             :                 nMin, nMax, nSum, nSumSquare, nSampleCount, nValidCount);
    5966             :         }
    5967       28119 :     }
    5968             : };
    5969             : 
    5970             : CPL_NOSANITIZE_UNSIGNED_INT_OVERFLOW
    5971         404 : static void UnshiftSumSquare(GUIntBig &nSumSquare, GUIntBig nSumThis,
    5972             :                              GUIntBig i)
    5973             : {
    5974         404 :     nSumSquare += 32768 * (2 * nSumThis - i * 32768);
    5975         404 : }
    5976             : 
    5977             : // AVX2/SSE2 optimization for GUInt16 case
    5978             : template <bool COMPUTE_OTHER_STATS>
    5979             : struct ComputeStatisticsInternal<GUInt16, COMPUTE_OTHER_STATS>
    5980             : {
    5981        1348 :     static void f(int nXCheck, int nBlockXSize, int nYCheck,
    5982             :                   // assumed to be aligned on 128 bits
    5983             :                   const GUInt16 *pData, bool bHasNoData, GUInt32 nNoDataValue,
    5984             :                   GUInt32 &nMin, GUInt32 &nMax, GUIntBig &nSum,
    5985             :                   GUIntBig &nSumSquare, GUIntBig &nSampleCount,
    5986             :                   GUIntBig &nValidCount)
    5987             :     {
    5988        1348 :         const auto nBlockPixels = static_cast<GPtrDiff_t>(nXCheck) * nYCheck;
    5989        1348 :         if (!bHasNoData && nXCheck == nBlockXSize && nBlockPixels >= 16)
    5990             :         {
    5991        1166 :             CPLAssert((reinterpret_cast<uintptr_t>(pData) % 16) == 0);
    5992             : 
    5993        1166 :             GPtrDiff_t i = 0;
    5994             :             // In SSE2, min_epu16 and max_epu16 do not exist, so shift from
    5995             :             // UInt16 to SInt16 to be able to use min_epi16 and max_epi16.
    5996             :             // Furthermore the shift is also needed to use madd_epi16
    5997        1166 :             const GDALm256i ymm_m32768 = GDALmm256_set1_epi16(-32768);
    5998        1166 :             GDALm256i ymm_min = GDALmm256_load_si256(
    5999        1166 :                 reinterpret_cast<const GDALm256i *>(pData + i));
    6000        1166 :             ymm_min = GDALmm256_add_epi16(ymm_min, ymm_m32768);
    6001        1166 :             GDALm256i ymm_max = ymm_min;
    6002             :             [[maybe_unused]] GDALm256i ymm_sumsquare =
    6003        1166 :                 ZERO256;  // holds 4 uint64 sums
    6004             : 
    6005             :             // Make sure that sum can fit on uint32
    6006             :             // * 8 since we can hold 8 sums per vector register
    6007        1166 :             const int nMaxIterationsPerInnerLoop =
    6008             :                 8 * ((std::numeric_limits<GUInt32>::max() / 65535) & ~15);
    6009        1166 :             GPtrDiff_t nOuterLoops = nBlockPixels / nMaxIterationsPerInnerLoop;
    6010        1166 :             if ((nBlockPixels % nMaxIterationsPerInnerLoop) != 0)
    6011        1166 :                 nOuterLoops++;
    6012             : 
    6013        1166 :             const bool bComputeMinMax = nMin > 0 || nMax < 65535;
    6014             :             [[maybe_unused]] const auto ymm_mask_16bits =
    6015        1166 :                 GDALmm256_set1_epi32(0xFFFF);
    6016             :             [[maybe_unused]] const auto ymm_mask_32bits =
    6017        1166 :                 GDALmm256_set1_epi64x(0xFFFFFFFF);
    6018             : 
    6019        1166 :             GUIntBig nSumThis = 0;
    6020        2356 :             for (int k = 0; k < nOuterLoops; k++)
    6021             :             {
    6022        1190 :                 const auto iMax =
    6023        1190 :                     std::min(nBlockPixels, i + nMaxIterationsPerInnerLoop);
    6024             : 
    6025             :                 [[maybe_unused]] GDALm256i ymm_sum =
    6026        1190 :                     ZERO256;  // holds 8 uint32 sums
    6027      959522 :                 for (; i + 15 < iMax; i += 16)
    6028             :                 {
    6029      958332 :                     const GDALm256i ymm = GDALmm256_load_si256(
    6030      958332 :                         reinterpret_cast<const GDALm256i *>(pData + i));
    6031             :                     const GDALm256i ymm_shifted =
    6032      958332 :                         GDALmm256_add_epi16(ymm, ymm_m32768);
    6033      958332 :                     if (bComputeMinMax)
    6034             :                     {
    6035      949313 :                         ymm_min = GDALmm256_min_epi16(ymm_min, ymm_shifted);
    6036      949313 :                         ymm_max = GDALmm256_max_epi16(ymm_max, ymm_shifted);
    6037             :                     }
    6038             : 
    6039             :                     if constexpr (COMPUTE_OTHER_STATS)
    6040             :                     {
    6041             :                         // Note: the int32 range can overflow for (0-32768)^2 +
    6042             :                         // (0-32768)^2 = 0x80000000, but as we know the result
    6043             :                         // is positive, this is OK as we interpret is a uint32.
    6044             :                         const GDALm256i ymm_square =
    6045       99506 :                             GDALmm256_madd_epi16(ymm_shifted, ymm_shifted);
    6046       99506 :                         ymm_sumsquare = GDALmm256_add_epi64(
    6047             :                             ymm_sumsquare,
    6048             :                             GDALmm256_and_si256(ymm_square, ymm_mask_32bits));
    6049       99506 :                         ymm_sumsquare = GDALmm256_add_epi64(
    6050             :                             ymm_sumsquare,
    6051             :                             GDALmm256_srli_epi64(ymm_square, 32));
    6052             : 
    6053             :                         // Now compute the sums
    6054       99506 :                         ymm_sum = GDALmm256_add_epi32(
    6055             :                             ymm_sum, GDALmm256_and_si256(ymm, ymm_mask_16bits));
    6056       99506 :                         ymm_sum = GDALmm256_add_epi32(
    6057             :                             ymm_sum, GDALmm256_srli_epi32(ymm, 16));
    6058             :                     }
    6059             :                 }
    6060             : 
    6061             :                 if constexpr (COMPUTE_OTHER_STATS)
    6062             :                 {
    6063             :                     GUInt32 anSum[8];
    6064         404 :                     GDALmm256_storeu_si256(reinterpret_cast<GDALm256i *>(anSum),
    6065             :                                            ymm_sum);
    6066         404 :                     nSumThis += static_cast<GUIntBig>(anSum[0]) + anSum[1] +
    6067         404 :                                 anSum[2] + anSum[3] + anSum[4] + anSum[5] +
    6068         404 :                                 anSum[6] + anSum[7];
    6069             :                 }
    6070             :             }
    6071             : 
    6072        1166 :             if (bComputeMinMax)
    6073             :             {
    6074             :                 GUInt16 anMin[16];
    6075             :                 GUInt16 anMax[16];
    6076             : 
    6077             :                 // Unshift the result
    6078        1125 :                 ymm_min = GDALmm256_sub_epi16(ymm_min, ymm_m32768);
    6079        1125 :                 ymm_max = GDALmm256_sub_epi16(ymm_max, ymm_m32768);
    6080        1125 :                 GDALmm256_storeu_si256(reinterpret_cast<GDALm256i *>(anMin),
    6081             :                                        ymm_min);
    6082        1125 :                 GDALmm256_storeu_si256(reinterpret_cast<GDALm256i *>(anMax),
    6083             :                                        ymm_max);
    6084       19125 :                 for (int j = 0; j < 16; j++)
    6085             :                 {
    6086       18000 :                     if (anMin[j] < nMin)
    6087         344 :                         nMin = anMin[j];
    6088       18000 :                     if (anMax[j] > nMax)
    6089         482 :                         nMax = anMax[j];
    6090             :                 }
    6091             :             }
    6092             : 
    6093             :             if constexpr (COMPUTE_OTHER_STATS)
    6094             :             {
    6095             :                 GUIntBig anSumSquare[4];
    6096         404 :                 GDALmm256_storeu_si256(
    6097             :                     reinterpret_cast<GDALm256i *>(anSumSquare), ymm_sumsquare);
    6098         404 :                 nSumSquare += anSumSquare[0] + anSumSquare[1] + anSumSquare[2] +
    6099             :                               anSumSquare[3];
    6100             : 
    6101             :                 // Unshift the sum of squares
    6102         404 :                 UnshiftSumSquare(nSumSquare, nSumThis,
    6103             :                                  static_cast<GUIntBig>(i));
    6104             : 
    6105         404 :                 nSum += nSumThis;
    6106             : 
    6107         726 :                 for (; i < nBlockPixels; i++)
    6108             :                 {
    6109         322 :                     const GUInt32 nValue = pData[i];
    6110         322 :                     if (nValue < nMin)
    6111           1 :                         nMin = nValue;
    6112         322 :                     if (nValue > nMax)
    6113           1 :                         nMax = nValue;
    6114         322 :                     nSum += nValue;
    6115         322 :                     nSumSquare +=
    6116         322 :                         static_cast_for_coverity_scan<GUIntBig>(nValue) *
    6117         322 :                         nValue;
    6118             :                 }
    6119             : 
    6120         404 :                 nSampleCount += static_cast<GUIntBig>(nXCheck) * nYCheck;
    6121         404 :                 nValidCount += static_cast<GUIntBig>(nXCheck) * nYCheck;
    6122        1166 :             }
    6123             :         }
    6124             :         else
    6125             :         {
    6126         182 :             ComputeStatisticsInternalGeneric<GUInt16, COMPUTE_OTHER_STATS>::f(
    6127             :                 nXCheck, nBlockXSize, nYCheck, pData, bHasNoData, nNoDataValue,
    6128             :                 nMin, nMax, nSum, nSumSquare, nSampleCount, nValidCount);
    6129             :         }
    6130        1348 :     }
    6131             : };
    6132             : 
    6133             : #endif
    6134             : // (defined(__x86_64__) || defined(_M_X64)) && (defined(__GNUC__) ||
    6135             : // defined(_MSC_VER))
    6136             : 
    6137             : /************************************************************************/
    6138             : /*                          GetPixelValue()                             */
    6139             : /************************************************************************/
    6140             : 
    6141    23166200 : static inline double GetPixelValue(GDALDataType eDataType, bool bSignedByte,
    6142             :                                    const void *pData, GPtrDiff_t iOffset,
    6143             :                                    const GDALNoDataValues &sNoDataValues,
    6144             :                                    bool &bValid)
    6145             : {
    6146    23166200 :     bValid = true;
    6147    23166200 :     double dfValue = 0;
    6148    23166200 :     switch (eDataType)
    6149             :     {
    6150     1413680 :         case GDT_Byte:
    6151             :         {
    6152     1413680 :             if (bSignedByte)
    6153         192 :                 dfValue = static_cast<const signed char *>(pData)[iOffset];
    6154             :             else
    6155     1413490 :                 dfValue = static_cast<const GByte *>(pData)[iOffset];
    6156     1413680 :             break;
    6157             :         }
    6158       10405 :         case GDT_Int8:
    6159       10405 :             dfValue = static_cast<const GInt8 *>(pData)[iOffset];
    6160       10405 :             break;
    6161        4000 :         case GDT_UInt16:
    6162        4000 :             dfValue = static_cast<const GUInt16 *>(pData)[iOffset];
    6163        4000 :             break;
    6164       60192 :         case GDT_Int16:
    6165       60192 :             dfValue = static_cast<const GInt16 *>(pData)[iOffset];
    6166       60192 :             break;
    6167       27596 :         case GDT_UInt32:
    6168       27596 :             dfValue = static_cast<const GUInt32 *>(pData)[iOffset];
    6169       27596 :             break;
    6170      460170 :         case GDT_Int32:
    6171      460170 :             dfValue = static_cast<const GInt32 *>(pData)[iOffset];
    6172      460170 :             break;
    6173        2598 :         case GDT_UInt64:
    6174        2598 :             dfValue = static_cast<double>(
    6175        2598 :                 static_cast<const std::uint64_t *>(pData)[iOffset]);
    6176        2598 :             break;
    6177        7398 :         case GDT_Int64:
    6178        7398 :             dfValue = static_cast<double>(
    6179        7398 :                 static_cast<const std::int64_t *>(pData)[iOffset]);
    6180        7398 :             break;
    6181           0 :         case GDT_Float16:
    6182             :         {
    6183           0 :             const GFloat16 hfValue =
    6184           0 :                 static_cast<const GFloat16 *>(pData)[iOffset];
    6185           0 :             if (CPLIsNan(hfValue) ||
    6186           0 :                 (sNoDataValues.bGotFloat16NoDataValue &&
    6187           0 :                  ARE_REAL_EQUAL(hfValue, sNoDataValues.hfNoDataValue)))
    6188             :             {
    6189           0 :                 bValid = false;
    6190           0 :                 return 0.0;
    6191             :             }
    6192           0 :             dfValue = hfValue;
    6193           0 :             return dfValue;
    6194             :         }
    6195    17483400 :         case GDT_Float32:
    6196             :         {
    6197    17483400 :             const float fValue = static_cast<const float *>(pData)[iOffset];
    6198    34939900 :             if (CPLIsNan(fValue) ||
    6199    30666600 :                 (sNoDataValues.bGotFloatNoDataValue &&
    6200    13210000 :                  ARE_REAL_EQUAL(fValue, sNoDataValues.fNoDataValue)))
    6201             :             {
    6202      119863 :                 bValid = false;
    6203      119863 :                 return 0.0;
    6204             :             }
    6205    17363500 :             dfValue = fValue;
    6206    17363500 :             return dfValue;
    6207             :         }
    6208     3679660 :         case GDT_Float64:
    6209     3679660 :             dfValue = static_cast<const double *>(pData)[iOffset];
    6210     3679660 :             if (std::isnan(dfValue))
    6211             :             {
    6212          52 :                 bValid = false;
    6213          52 :                 return 0.0;
    6214             :             }
    6215     3679600 :             break;
    6216        2692 :         case GDT_CInt16:
    6217        2692 :             dfValue = static_cast<const GInt16 *>(pData)[iOffset * 2];
    6218        2692 :             break;
    6219        2692 :         case GDT_CInt32:
    6220        2692 :             dfValue = static_cast<const GInt32 *>(pData)[iOffset * 2];
    6221        2692 :             break;
    6222           0 :         case GDT_CFloat16:
    6223           0 :             dfValue = static_cast<const GFloat16 *>(pData)[iOffset * 2];
    6224           0 :             if (isnan(dfValue))
    6225             :             {
    6226           0 :                 bValid = false;
    6227           0 :                 return 0.0;
    6228             :             }
    6229           0 :             break;
    6230        5812 :         case GDT_CFloat32:
    6231        5812 :             dfValue = static_cast<const float *>(pData)[iOffset * 2];
    6232        5812 :             if (std::isnan(dfValue))
    6233             :             {
    6234           0 :                 bValid = false;
    6235           0 :                 return 0.0;
    6236             :             }
    6237        5812 :             break;
    6238        5892 :         case GDT_CFloat64:
    6239        5892 :             dfValue = static_cast<const double *>(pData)[iOffset * 2];
    6240        5892 :             if (std::isnan(dfValue))
    6241             :             {
    6242           0 :                 bValid = false;
    6243           0 :                 return 0.0;
    6244             :             }
    6245        5892 :             break;
    6246           0 :         case GDT_Unknown:
    6247             :         case GDT_TypeCount:
    6248           0 :             CPLAssert(false);
    6249             :             break;
    6250             :     }
    6251             : 
    6252     9427180 :     if (sNoDataValues.bGotNoDataValue &&
    6253     3744450 :         ARE_REAL_EQUAL(dfValue, sNoDataValues.dfNoDataValue))
    6254             :     {
    6255     3346220 :         bValid = false;
    6256     3346220 :         return 0.0;
    6257             :     }
    6258     2336510 :     return dfValue;
    6259             : }
    6260             : 
    6261             : /************************************************************************/
    6262             : /*                         SetValidPercent()                            */
    6263             : /************************************************************************/
    6264             : 
    6265             : //! @cond Doxygen_Suppress
    6266             : /**
    6267             :  * \brief Set percentage of valid (not nodata) pixels.
    6268             :  *
    6269             :  * Stores the percentage of valid pixels in the metadata item
    6270             :  * STATISTICS_VALID_PERCENT
    6271             :  *
    6272             :  * @param nSampleCount Number of sampled pixels.
    6273             :  *
    6274             :  * @param nValidCount Number of valid pixels.
    6275             :  */
    6276             : 
    6277         467 : void GDALRasterBand::SetValidPercent(GUIntBig nSampleCount,
    6278             :                                      GUIntBig nValidCount)
    6279             : {
    6280         467 :     if (nValidCount == 0)
    6281             :     {
    6282          12 :         SetMetadataItem("STATISTICS_VALID_PERCENT", "0");
    6283             :     }
    6284         455 :     else if (nValidCount == nSampleCount)
    6285             :     {
    6286         412 :         SetMetadataItem("STATISTICS_VALID_PERCENT", "100");
    6287             :     }
    6288             :     else /* nValidCount < nSampleCount */
    6289             :     {
    6290          43 :         char szValue[128] = {0};
    6291             : 
    6292             :         /* percentage is only an indicator: limit precision */
    6293          43 :         CPLsnprintf(szValue, sizeof(szValue), "%.4g",
    6294          43 :                     100. * static_cast<double>(nValidCount) / nSampleCount);
    6295             : 
    6296          43 :         if (EQUAL(szValue, "100"))
    6297             :         {
    6298             :             /* don't set 100 percent valid
    6299             :              * because some of the sampled pixels were nodata */
    6300           0 :             SetMetadataItem("STATISTICS_VALID_PERCENT", "99.999");
    6301             :         }
    6302             :         else
    6303             :         {
    6304          43 :             SetMetadataItem("STATISTICS_VALID_PERCENT", szValue);
    6305             :         }
    6306             :     }
    6307         468 : }
    6308             : 
    6309             : //! @endcond
    6310             : 
    6311             : /************************************************************************/
    6312             : /*                         ComputeStatistics()                          */
    6313             : /************************************************************************/
    6314             : 
    6315             : /**
    6316             :  * \brief Compute image statistics.
    6317             :  *
    6318             :  * Returns the minimum, maximum, mean and standard deviation of all
    6319             :  * pixel values in this band.  If approximate statistics are sufficient,
    6320             :  * the bApproxOK flag can be set to true in which case overviews, or a
    6321             :  * subset of image tiles may be used in computing the statistics.
    6322             :  *
    6323             :  * Once computed, the statistics will generally be "set" back on the
    6324             :  * raster band using SetStatistics().
    6325             :  *
    6326             :  * Cached statistics can be cleared with GDALDataset::ClearStatistics().
    6327             :  *
    6328             :  * This method is the same as the C function GDALComputeRasterStatistics().
    6329             :  *
    6330             :  * @param bApproxOK If TRUE statistics may be computed based on overviews
    6331             :  * or a subset of all tiles.
    6332             :  *
    6333             :  * @param pdfMin Location into which to load image minimum (may be NULL).
    6334             :  *
    6335             :  * @param pdfMax Location into which to load image maximum (may be NULL).-
    6336             :  *
    6337             :  * @param pdfMean Location into which to load image mean (may be NULL).
    6338             :  *
    6339             :  * @param pdfStdDev Location into which to load image standard deviation
    6340             :  * (may be NULL).
    6341             :  *
    6342             :  * @param pfnProgress a function to call to report progress, or NULL.
    6343             :  *
    6344             :  * @param pProgressData application data to pass to the progress function.
    6345             :  *
    6346             :  * @return CE_None on success, or CE_Failure if an error occurs or processing
    6347             :  * is terminated by the user.
    6348             :  */
    6349             : 
    6350         451 : CPLErr GDALRasterBand::ComputeStatistics(int bApproxOK, double *pdfMin,
    6351             :                                          double *pdfMax, double *pdfMean,
    6352             :                                          double *pdfStdDev,
    6353             :                                          GDALProgressFunc pfnProgress,
    6354             :                                          void *pProgressData)
    6355             : 
    6356             : {
    6357         451 :     if (pfnProgress == nullptr)
    6358         155 :         pfnProgress = GDALDummyProgress;
    6359             : 
    6360             :     /* -------------------------------------------------------------------- */
    6361             :     /*      If we have overview bands, use them for statistics.             */
    6362             :     /* -------------------------------------------------------------------- */
    6363         451 :     if (bApproxOK && GetOverviewCount() > 0 && !HasArbitraryOverviews())
    6364             :     {
    6365             :         GDALRasterBand *poBand =
    6366           3 :             GetRasterSampleOverview(GDALSTAT_APPROX_NUMSAMPLES);
    6367             : 
    6368           3 :         if (poBand != this)
    6369             :         {
    6370           6 :             CPLErr eErr = poBand->ComputeStatistics(FALSE, pdfMin, pdfMax,
    6371             :                                                     pdfMean, pdfStdDev,
    6372           3 :                                                     pfnProgress, pProgressData);
    6373           3 :             if (eErr == CE_None)
    6374             :             {
    6375           3 :                 if (pdfMin && pdfMax && pdfMean && pdfStdDev)
    6376             :                 {
    6377           3 :                     SetMetadataItem("STATISTICS_APPROXIMATE", "YES");
    6378           3 :                     SetStatistics(*pdfMin, *pdfMax, *pdfMean, *pdfStdDev);
    6379             :                 }
    6380             : 
    6381             :                 /* transfer metadata from overview band to this */
    6382             :                 const char *pszPercentValid =
    6383           3 :                     poBand->GetMetadataItem("STATISTICS_VALID_PERCENT");
    6384             : 
    6385           3 :                 if (pszPercentValid != nullptr)
    6386             :                 {
    6387           3 :                     SetMetadataItem("STATISTICS_VALID_PERCENT",
    6388           3 :                                     pszPercentValid);
    6389             :                 }
    6390             :             }
    6391           3 :             return eErr;
    6392             :         }
    6393             :     }
    6394             : 
    6395         448 :     if (!pfnProgress(0.0, "Compute Statistics", pProgressData))
    6396             :     {
    6397           0 :         ReportError(CE_Failure, CPLE_UserInterrupt, "User terminated");
    6398           0 :         return CE_Failure;
    6399             :     }
    6400             : 
    6401             :     /* -------------------------------------------------------------------- */
    6402             :     /*      Read actual data and compute statistics.                        */
    6403             :     /* -------------------------------------------------------------------- */
    6404             :     // Using Welford algorithm:
    6405             :     // http://en.wikipedia.org/wiki/Algorithms_for_calculating_variance
    6406             :     // to compute standard deviation in a more numerically robust way than
    6407             :     // the difference of the sum of square values with the square of the sum.
    6408             :     // dfMean and dfM2 are updated at each sample.
    6409             :     // dfM2 is the sum of square of differences to the current mean.
    6410         448 :     double dfMin = std::numeric_limits<double>::max();
    6411         448 :     double dfMax = -std::numeric_limits<double>::max();
    6412         448 :     double dfMean = 0.0;
    6413         448 :     double dfM2 = 0.0;
    6414             : 
    6415             :     GDALRasterIOExtraArg sExtraArg;
    6416         448 :     INIT_RASTERIO_EXTRA_ARG(sExtraArg);
    6417             : 
    6418         448 :     GDALNoDataValues sNoDataValues(this, eDataType);
    6419         448 :     GDALRasterBand *poMaskBand = nullptr;
    6420         448 :     if (!sNoDataValues.bGotNoDataValue)
    6421             :     {
    6422         423 :         const int l_nMaskFlags = GetMaskFlags();
    6423         439 :         if (l_nMaskFlags != GMF_ALL_VALID && l_nMaskFlags != GMF_NODATA &&
    6424          16 :             GetColorInterpretation() != GCI_AlphaBand)
    6425             :         {
    6426          16 :             poMaskBand = GetMaskBand();
    6427             :         }
    6428             :     }
    6429             : 
    6430         448 :     bool bSignedByte = false;
    6431         448 :     if (eDataType == GDT_Byte)
    6432             :     {
    6433         196 :         EnablePixelTypeSignedByteWarning(false);
    6434             :         const char *pszPixelType =
    6435         196 :             GetMetadataItem("PIXELTYPE", "IMAGE_STRUCTURE");
    6436         196 :         EnablePixelTypeSignedByteWarning(true);
    6437         196 :         bSignedByte =
    6438         196 :             pszPixelType != nullptr && EQUAL(pszPixelType, "SIGNEDBYTE");
    6439             :     }
    6440             : 
    6441         448 :     GUIntBig nSampleCount = 0;
    6442         448 :     GUIntBig nValidCount = 0;
    6443             : 
    6444         448 :     if (bApproxOK && HasArbitraryOverviews())
    6445             :     {
    6446             :         /* --------------------------------------------------------------------
    6447             :          */
    6448             :         /*      Figure out how much the image should be reduced to get an */
    6449             :         /*      approximate value. */
    6450             :         /* --------------------------------------------------------------------
    6451             :          */
    6452           0 :         double dfReduction = sqrt(static_cast<double>(nRasterXSize) *
    6453           0 :                                   nRasterYSize / GDALSTAT_APPROX_NUMSAMPLES);
    6454             : 
    6455           0 :         int nXReduced = nRasterXSize;
    6456           0 :         int nYReduced = nRasterYSize;
    6457           0 :         if (dfReduction > 1.0)
    6458             :         {
    6459           0 :             nXReduced = static_cast<int>(nRasterXSize / dfReduction);
    6460           0 :             nYReduced = static_cast<int>(nRasterYSize / dfReduction);
    6461             : 
    6462             :             // Catch the case of huge resizing ratios here
    6463           0 :             if (nXReduced == 0)
    6464           0 :                 nXReduced = 1;
    6465           0 :             if (nYReduced == 0)
    6466           0 :                 nYReduced = 1;
    6467             :         }
    6468             : 
    6469           0 :         void *pData = CPLMalloc(cpl::fits_on<int>(
    6470           0 :             GDALGetDataTypeSizeBytes(eDataType) * nXReduced * nYReduced));
    6471             : 
    6472             :         const CPLErr eErr =
    6473           0 :             IRasterIO(GF_Read, 0, 0, nRasterXSize, nRasterYSize, pData,
    6474           0 :                       nXReduced, nYReduced, eDataType, 0, 0, &sExtraArg);
    6475           0 :         if (eErr != CE_None)
    6476             :         {
    6477           0 :             CPLFree(pData);
    6478           0 :             return eErr;
    6479             :         }
    6480             : 
    6481           0 :         GByte *pabyMaskData = nullptr;
    6482           0 :         if (poMaskBand)
    6483             :         {
    6484             :             pabyMaskData =
    6485           0 :                 static_cast<GByte *>(VSI_MALLOC2_VERBOSE(nXReduced, nYReduced));
    6486           0 :             if (!pabyMaskData)
    6487             :             {
    6488           0 :                 CPLFree(pData);
    6489           0 :                 return CE_Failure;
    6490             :             }
    6491             : 
    6492           0 :             if (poMaskBand->RasterIO(GF_Read, 0, 0, nRasterXSize, nRasterYSize,
    6493             :                                      pabyMaskData, nXReduced, nYReduced,
    6494           0 :                                      GDT_Byte, 0, 0, nullptr) != CE_None)
    6495             :             {
    6496           0 :                 CPLFree(pData);
    6497           0 :                 CPLFree(pabyMaskData);
    6498           0 :                 return CE_Failure;
    6499             :             }
    6500             :         }
    6501             : 
    6502             :         /* this isn't the fastest way to do this, but is easier for now */
    6503           0 :         for (int iY = 0; iY < nYReduced; iY++)
    6504             :         {
    6505           0 :             for (int iX = 0; iX < nXReduced; iX++)
    6506             :             {
    6507           0 :                 const int iOffset = iX + iY * nXReduced;
    6508           0 :                 if (pabyMaskData && pabyMaskData[iOffset] == 0)
    6509           0 :                     continue;
    6510             : 
    6511           0 :                 bool bValid = true;
    6512           0 :                 double dfValue = GetPixelValue(eDataType, bSignedByte, pData,
    6513           0 :                                                iOffset, sNoDataValues, bValid);
    6514           0 :                 if (!bValid)
    6515           0 :                     continue;
    6516             : 
    6517           0 :                 dfMin = std::min(dfMin, dfValue);
    6518           0 :                 dfMax = std::max(dfMax, dfValue);
    6519             : 
    6520           0 :                 nValidCount++;
    6521           0 :                 const double dfDelta = dfValue - dfMean;
    6522           0 :                 dfMean += dfDelta / nValidCount;
    6523           0 :                 dfM2 += dfDelta * (dfValue - dfMean);
    6524             :             }
    6525             :         }
    6526             : 
    6527           0 :         nSampleCount = static_cast<GUIntBig>(nXReduced) * nYReduced;
    6528             : 
    6529           0 :         CPLFree(pData);
    6530           0 :         CPLFree(pabyMaskData);
    6531             :     }
    6532             : 
    6533             :     else  // No arbitrary overviews.
    6534             :     {
    6535         448 :         if (!InitBlockInfo())
    6536           0 :             return CE_Failure;
    6537             : 
    6538             :         /* --------------------------------------------------------------------
    6539             :          */
    6540             :         /*      Figure out the ratio of blocks we will read to get an */
    6541             :         /*      approximate value. */
    6542             :         /* --------------------------------------------------------------------
    6543             :          */
    6544         448 :         int nSampleRate = 1;
    6545         448 :         if (bApproxOK)
    6546             :         {
    6547          41 :             nSampleRate = static_cast<int>(std::max(
    6548          82 :                 1.0,
    6549          41 :                 sqrt(static_cast<double>(nBlocksPerRow) * nBlocksPerColumn)));
    6550             :             // We want to avoid probing only the first column of blocks for
    6551             :             // a square shaped raster, because it is not unlikely that it may
    6552             :             // be padding only (#6378)
    6553          41 :             if (nSampleRate == nBlocksPerRow && nBlocksPerRow > 1)
    6554           2 :                 nSampleRate += 1;
    6555             :         }
    6556         448 :         if (nSampleRate == 1)
    6557         414 :             bApproxOK = false;
    6558             : 
    6559             :         // Particular case for GDT_Byte that only use integral types for all
    6560             :         // intermediate computations. Only possible if the number of pixels
    6561             :         // explored is lower than GUINTBIG_MAX / (255*255), so that nSumSquare
    6562             :         // can fit on a uint64. Should be 99.99999% of cases.
    6563             :         // For GUInt16, this limits to raster of 4 giga pixels
    6564         448 :         if ((!poMaskBand && eDataType == GDT_Byte && !bSignedByte &&
    6565         181 :              static_cast<GUIntBig>(nBlocksPerRow) * nBlocksPerColumn /
    6566         181 :                      nSampleRate <
    6567         181 :                  GUINTBIG_MAX / (255U * 255U) /
    6568         181 :                      (static_cast<GUInt64>(nBlockXSize) *
    6569         181 :                       static_cast<GUInt64>(nBlockYSize))) ||
    6570         267 :             (eDataType == GDT_UInt16 &&
    6571          29 :              static_cast<GUIntBig>(nBlocksPerRow) * nBlocksPerColumn /
    6572          29 :                      nSampleRate <
    6573          29 :                  GUINTBIG_MAX / (65535U * 65535U) /
    6574          29 :                      (static_cast<GUInt64>(nBlockXSize) *
    6575          29 :                       static_cast<GUInt64>(nBlockYSize))))
    6576             :         {
    6577         210 :             const GUInt32 nMaxValueType = (eDataType == GDT_Byte) ? 255 : 65535;
    6578         210 :             GUInt32 nMin = nMaxValueType;
    6579         210 :             GUInt32 nMax = 0;
    6580         210 :             GUIntBig nSum = 0;
    6581         210 :             GUIntBig nSumSquare = 0;
    6582             :             // If no valid nodata, map to invalid value (256 for Byte)
    6583         210 :             const GUInt32 nNoDataValue =
    6584         231 :                 (sNoDataValues.bGotNoDataValue &&
    6585          21 :                  sNoDataValues.dfNoDataValue >= 0 &&
    6586          21 :                  sNoDataValues.dfNoDataValue <= nMaxValueType &&
    6587          21 :                  fabs(sNoDataValues.dfNoDataValue -
    6588          21 :                       static_cast<GUInt32>(sNoDataValues.dfNoDataValue +
    6589             :                                            1e-10)) < 1e-10)
    6590         231 :                     ? static_cast<GUInt32>(sNoDataValues.dfNoDataValue + 1e-10)
    6591             :                     : nMaxValueType + 1;
    6592             : 
    6593         210 :             for (GIntBig iSampleBlock = 0;
    6594       12615 :                  iSampleBlock <
    6595       12615 :                  static_cast<GIntBig>(nBlocksPerRow) * nBlocksPerColumn;
    6596       12405 :                  iSampleBlock += nSampleRate)
    6597             :             {
    6598       12405 :                 const int iYBlock =
    6599       12405 :                     static_cast<int>(iSampleBlock / nBlocksPerRow);
    6600       12405 :                 const int iXBlock =
    6601       12405 :                     static_cast<int>(iSampleBlock % nBlocksPerRow);
    6602             : 
    6603             :                 GDALRasterBlock *const poBlock =
    6604       12405 :                     GetLockedBlockRef(iXBlock, iYBlock);
    6605       12407 :                 if (poBlock == nullptr)
    6606           0 :                     return CE_Failure;
    6607             : 
    6608       12407 :                 void *const pData = poBlock->GetDataRef();
    6609             : 
    6610       12406 :                 int nXCheck = 0, nYCheck = 0;
    6611       12406 :                 GetActualBlockSize(iXBlock, iYBlock, &nXCheck, &nYCheck);
    6612             : 
    6613       12405 :                 if (eDataType == GDT_Byte)
    6614             :                 {
    6615             :                     ComputeStatisticsInternal<
    6616             :                         GByte, /* COMPUTE_OTHER_STATS = */ true>::
    6617       11947 :                         f(nXCheck, nBlockXSize, nYCheck,
    6618             :                           static_cast<const GByte *>(pData),
    6619             :                           nNoDataValue <= nMaxValueType, nNoDataValue, nMin,
    6620             :                           nMax, nSum, nSumSquare, nSampleCount, nValidCount);
    6621             :                 }
    6622             :                 else
    6623             :                 {
    6624             :                     ComputeStatisticsInternal<
    6625             :                         GUInt16, /* COMPUTE_OTHER_STATS = */ true>::
    6626         458 :                         f(nXCheck, nBlockXSize, nYCheck,
    6627             :                           static_cast<const GUInt16 *>(pData),
    6628             :                           nNoDataValue <= nMaxValueType, nNoDataValue, nMin,
    6629             :                           nMax, nSum, nSumSquare, nSampleCount, nValidCount);
    6630             :                 }
    6631             : 
    6632       12409 :                 poBlock->DropLock();
    6633             : 
    6634       12406 :                 if (!pfnProgress(static_cast<double>(iSampleBlock) /
    6635       12408 :                                      (static_cast<double>(nBlocksPerRow) *
    6636       12408 :                                       nBlocksPerColumn),
    6637             :                                  "Compute Statistics", pProgressData))
    6638             :                 {
    6639           1 :                     ReportError(CE_Failure, CPLE_UserInterrupt,
    6640             :                                 "User terminated");
    6641           0 :                     return CE_Failure;
    6642             :                 }
    6643             :             }
    6644             : 
    6645         210 :             if (!pfnProgress(1.0, "Compute Statistics", pProgressData))
    6646             :             {
    6647           0 :                 ReportError(CE_Failure, CPLE_UserInterrupt, "User terminated");
    6648           0 :                 return CE_Failure;
    6649             :             }
    6650             : 
    6651             :             /* --------------------------------------------------------------------
    6652             :              */
    6653             :             /*      Save computed information. */
    6654             :             /* --------------------------------------------------------------------
    6655             :              */
    6656         210 :             if (nValidCount)
    6657         201 :                 dfMean = static_cast<double>(nSum) / nValidCount;
    6658             : 
    6659             :             // To avoid potential precision issues when doing the difference,
    6660             :             // we need to do that computation on 128 bit rather than casting
    6661             :             // to double
    6662             :             const GDALUInt128 nTmpForStdDev(
    6663         210 :                 GDALUInt128::Mul(nSumSquare, nValidCount) -
    6664         420 :                 GDALUInt128::Mul(nSum, nSum));
    6665             :             const double dfStdDev =
    6666         210 :                 nValidCount > 0
    6667         210 :                     ? sqrt(static_cast<double>(nTmpForStdDev)) / nValidCount
    6668         210 :                     : 0.0;
    6669             : 
    6670         210 :             if (nValidCount > 0)
    6671             :             {
    6672         200 :                 if (bApproxOK)
    6673             :                 {
    6674          24 :                     SetMetadataItem("STATISTICS_APPROXIMATE", "YES");
    6675             :                 }
    6676         176 :                 else if (GetMetadataItem("STATISTICS_APPROXIMATE"))
    6677             :                 {
    6678           3 :                     SetMetadataItem("STATISTICS_APPROXIMATE", nullptr);
    6679             :                 }
    6680         201 :                 SetStatistics(nMin, nMax, dfMean, dfStdDev);
    6681             :             }
    6682             : 
    6683         211 :             SetValidPercent(nSampleCount, nValidCount);
    6684             : 
    6685             :             /* --------------------------------------------------------------------
    6686             :              */
    6687             :             /*      Record results. */
    6688             :             /* --------------------------------------------------------------------
    6689             :              */
    6690         210 :             if (pdfMin != nullptr)
    6691         207 :                 *pdfMin = nValidCount ? nMin : 0;
    6692         210 :             if (pdfMax != nullptr)
    6693         207 :                 *pdfMax = nValidCount ? nMax : 0;
    6694             : 
    6695         210 :             if (pdfMean != nullptr)
    6696         203 :                 *pdfMean = dfMean;
    6697             : 
    6698         210 :             if (pdfStdDev != nullptr)
    6699         203 :                 *pdfStdDev = dfStdDev;
    6700             : 
    6701         210 :             if (nValidCount > 0)
    6702         201 :                 return CE_None;
    6703             : 
    6704           9 :             ReportError(CE_Failure, CPLE_AppDefined,
    6705             :                         "Failed to compute statistics, no valid pixels found "
    6706             :                         "in sampling.");
    6707           9 :             return CE_Failure;
    6708             :         }
    6709             : 
    6710         238 :         GByte *pabyMaskData = nullptr;
    6711         238 :         if (poMaskBand)
    6712             :         {
    6713             :             pabyMaskData = static_cast<GByte *>(
    6714          16 :                 VSI_MALLOC2_VERBOSE(nBlockXSize, nBlockYSize));
    6715          16 :             if (!pabyMaskData)
    6716             :             {
    6717           0 :                 return CE_Failure;
    6718             :             }
    6719             :         }
    6720             : 
    6721         238 :         for (GIntBig iSampleBlock = 0;
    6722        5489 :              iSampleBlock <
    6723        5489 :              static_cast<GIntBig>(nBlocksPerRow) * nBlocksPerColumn;
    6724        5251 :              iSampleBlock += nSampleRate)
    6725             :         {
    6726        5251 :             const int iYBlock = static_cast<int>(iSampleBlock / nBlocksPerRow);
    6727        5251 :             const int iXBlock = static_cast<int>(iSampleBlock % nBlocksPerRow);
    6728             : 
    6729             :             GDALRasterBlock *const poBlock =
    6730        5251 :                 GetLockedBlockRef(iXBlock, iYBlock);
    6731        5251 :             if (poBlock == nullptr)
    6732             :             {
    6733           0 :                 CPLFree(pabyMaskData);
    6734           0 :                 return CE_Failure;
    6735             :             }
    6736             : 
    6737        5251 :             void *const pData = poBlock->GetDataRef();
    6738             : 
    6739        5251 :             int nXCheck = 0, nYCheck = 0;
    6740        5251 :             GetActualBlockSize(iXBlock, iYBlock, &nXCheck, &nYCheck);
    6741             : 
    6742        5352 :             if (poMaskBand &&
    6743         101 :                 poMaskBand->RasterIO(GF_Read, iXBlock * nBlockXSize,
    6744         101 :                                      iYBlock * nBlockYSize, nXCheck, nYCheck,
    6745             :                                      pabyMaskData, nXCheck, nYCheck, GDT_Byte,
    6746         101 :                                      0, nBlockXSize, nullptr) != CE_None)
    6747             :             {
    6748           0 :                 CPLFree(pabyMaskData);
    6749           0 :                 poBlock->DropLock();
    6750           0 :                 return CE_Failure;
    6751             :             }
    6752             : 
    6753             :             // This isn't the fastest way to do this, but is easier for now.
    6754       10686 :             for (int iY = 0; iY < nYCheck; iY++)
    6755             :             {
    6756     4342140 :                 for (int iX = 0; iX < nXCheck; iX++)
    6757             :                 {
    6758     4336710 :                     const GPtrDiff_t iOffset =
    6759     4336710 :                         iX + static_cast<GPtrDiff_t>(iY) * nBlockXSize;
    6760     4336710 :                     if (pabyMaskData && pabyMaskData[iOffset] == 0)
    6761      109941 :                         continue;
    6762             : 
    6763     4326840 :                     bool bValid = true;
    6764             :                     double dfValue =
    6765     4326840 :                         GetPixelValue(eDataType, bSignedByte, pData, iOffset,
    6766     4326840 :                                       sNoDataValues, bValid);
    6767             : 
    6768     4326840 :                     if (!bValid)
    6769      100070 :                         continue;
    6770             : 
    6771     4226770 :                     dfMin = std::min(dfMin, dfValue);
    6772     4226770 :                     dfMax = std::max(dfMax, dfValue);
    6773             : 
    6774     4226770 :                     nValidCount++;
    6775     4226770 :                     const double dfDelta = dfValue - dfMean;
    6776     4226770 :                     dfMean += dfDelta / nValidCount;
    6777     4226770 :                     dfM2 += dfDelta * (dfValue - dfMean);
    6778             :                 }
    6779             :             }
    6780             : 
    6781        5251 :             nSampleCount += static_cast<GUIntBig>(nXCheck) * nYCheck;
    6782             : 
    6783        5251 :             poBlock->DropLock();
    6784             : 
    6785        5251 :             if (!pfnProgress(
    6786        5251 :                     static_cast<double>(iSampleBlock) /
    6787        5251 :                         (static_cast<double>(nBlocksPerRow) * nBlocksPerColumn),
    6788             :                     "Compute Statistics", pProgressData))
    6789             :             {
    6790           0 :                 ReportError(CE_Failure, CPLE_UserInterrupt, "User terminated");
    6791           0 :                 CPLFree(pabyMaskData);
    6792           0 :                 return CE_Failure;
    6793             :             }
    6794             :         }
    6795             : 
    6796         238 :         CPLFree(pabyMaskData);
    6797             :     }
    6798             : 
    6799         238 :     if (!pfnProgress(1.0, "Compute Statistics", pProgressData))
    6800             :     {
    6801           0 :         ReportError(CE_Failure, CPLE_UserInterrupt, "User terminated");
    6802           0 :         return CE_Failure;
    6803             :     }
    6804             : 
    6805             :     /* -------------------------------------------------------------------- */
    6806             :     /*      Save computed information.                                      */
    6807             :     /* -------------------------------------------------------------------- */
    6808         238 :     const double dfStdDev = nValidCount > 0 ? sqrt(dfM2 / nValidCount) : 0.0;
    6809             : 
    6810         238 :     if (nValidCount > 0)
    6811             :     {
    6812         237 :         if (bApproxOK)
    6813             :         {
    6814           8 :             SetMetadataItem("STATISTICS_APPROXIMATE", "YES");
    6815             :         }
    6816         229 :         else if (GetMetadataItem("STATISTICS_APPROXIMATE"))
    6817             :         {
    6818           2 :             SetMetadataItem("STATISTICS_APPROXIMATE", nullptr);
    6819             :         }
    6820         237 :         SetStatistics(dfMin, dfMax, dfMean, dfStdDev);
    6821             :     }
    6822             :     else
    6823             :     {
    6824           1 :         dfMin = 0.0;
    6825           1 :         dfMax = 0.0;
    6826             :     }
    6827             : 
    6828         238 :     SetValidPercent(nSampleCount, nValidCount);
    6829             : 
    6830             :     /* -------------------------------------------------------------------- */
    6831             :     /*      Record results.                                                 */
    6832             :     /* -------------------------------------------------------------------- */
    6833         238 :     if (pdfMin != nullptr)
    6834         235 :         *pdfMin = dfMin;
    6835         238 :     if (pdfMax != nullptr)
    6836         235 :         *pdfMax = dfMax;
    6837             : 
    6838         238 :     if (pdfMean != nullptr)
    6839         233 :         *pdfMean = dfMean;
    6840             : 
    6841         238 :     if (pdfStdDev != nullptr)
    6842         233 :         *pdfStdDev = dfStdDev;
    6843             : 
    6844         238 :     if (nValidCount > 0)
    6845         237 :         return CE_None;
    6846             : 
    6847           1 :     ReportError(
    6848             :         CE_Failure, CPLE_AppDefined,
    6849             :         "Failed to compute statistics, no valid pixels found in sampling.");
    6850           1 :     return CE_Failure;
    6851             : }
    6852             : 
    6853             : /************************************************************************/
    6854             : /*                    GDALComputeRasterStatistics()                     */
    6855             : /************************************************************************/
    6856             : 
    6857             : /**
    6858             :  * \brief Compute image statistics.
    6859             :  *
    6860             :  * @see GDALRasterBand::ComputeStatistics()
    6861             :  */
    6862             : 
    6863         142 : CPLErr CPL_STDCALL GDALComputeRasterStatistics(GDALRasterBandH hBand,
    6864             :                                                int bApproxOK, double *pdfMin,
    6865             :                                                double *pdfMax, double *pdfMean,
    6866             :                                                double *pdfStdDev,
    6867             :                                                GDALProgressFunc pfnProgress,
    6868             :                                                void *pProgressData)
    6869             : 
    6870             : {
    6871         142 :     VALIDATE_POINTER1(hBand, "GDALComputeRasterStatistics", CE_Failure);
    6872             : 
    6873         142 :     GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
    6874             : 
    6875         142 :     return poBand->ComputeStatistics(bApproxOK, pdfMin, pdfMax, pdfMean,
    6876         142 :                                      pdfStdDev, pfnProgress, pProgressData);
    6877             : }
    6878             : 
    6879             : /************************************************************************/
    6880             : /*                           SetStatistics()                            */
    6881             : /************************************************************************/
    6882             : 
    6883             : /**
    6884             :  * \brief Set statistics on band.
    6885             :  *
    6886             :  * This method can be used to store min/max/mean/standard deviation
    6887             :  * statistics on a raster band.
    6888             :  *
    6889             :  * The default implementation stores them as metadata, and will only work
    6890             :  * on formats that can save arbitrary metadata.  This method cannot detect
    6891             :  * whether metadata will be properly saved and so may return CE_None even
    6892             :  * if the statistics will never be saved.
    6893             :  *
    6894             :  * This method is the same as the C function GDALSetRasterStatistics().
    6895             :  *
    6896             :  * @param dfMin minimum pixel value.
    6897             :  *
    6898             :  * @param dfMax maximum pixel value.
    6899             :  *
    6900             :  * @param dfMean mean (average) of all pixel values.
    6901             :  *
    6902             :  * @param dfStdDev Standard deviation of all pixel values.
    6903             :  *
    6904             :  * @return CE_None on success or CE_Failure on failure.
    6905             :  */
    6906             : 
    6907         466 : CPLErr GDALRasterBand::SetStatistics(double dfMin, double dfMax, double dfMean,
    6908             :                                      double dfStdDev)
    6909             : 
    6910             : {
    6911         466 :     char szValue[128] = {0};
    6912             : 
    6913         466 :     CPLsnprintf(szValue, sizeof(szValue), "%.14g", dfMin);
    6914         465 :     SetMetadataItem("STATISTICS_MINIMUM", szValue);
    6915             : 
    6916         466 :     CPLsnprintf(szValue, sizeof(szValue), "%.14g", dfMax);
    6917         466 :     SetMetadataItem("STATISTICS_MAXIMUM", szValue);
    6918             : 
    6919         465 :     CPLsnprintf(szValue, sizeof(szValue), "%.14g", dfMean);
    6920         466 :     SetMetadataItem("STATISTICS_MEAN", szValue);
    6921             : 
    6922         466 :     CPLsnprintf(szValue, sizeof(szValue), "%.14g", dfStdDev);
    6923         466 :     SetMetadataItem("STATISTICS_STDDEV", szValue);
    6924             : 
    6925         466 :     return CE_None;
    6926             : }
    6927             : 
    6928             : /************************************************************************/
    6929             : /*                      GDALSetRasterStatistics()                       */
    6930             : /************************************************************************/
    6931             : 
    6932             : /**
    6933             :  * \brief Set statistics on band.
    6934             :  *
    6935             :  * @see GDALRasterBand::SetStatistics()
    6936             :  */
    6937             : 
    6938           2 : CPLErr CPL_STDCALL GDALSetRasterStatistics(GDALRasterBandH hBand, double dfMin,
    6939             :                                            double dfMax, double dfMean,
    6940             :                                            double dfStdDev)
    6941             : 
    6942             : {
    6943           2 :     VALIDATE_POINTER1(hBand, "GDALSetRasterStatistics", CE_Failure);
    6944             : 
    6945           2 :     GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
    6946           2 :     return poBand->SetStatistics(dfMin, dfMax, dfMean, dfStdDev);
    6947             : }
    6948             : 
    6949             : /************************************************************************/
    6950             : /*                        ComputeRasterMinMax()                         */
    6951             : /************************************************************************/
    6952             : 
    6953             : template <class T, bool HAS_NODATA>
    6954      134689 : static void ComputeMinMax(const T *buffer, size_t nElts, T nodataValue, T *pMin,
    6955             :                           T *pMax)
    6956             : {
    6957      134689 :     T min0 = *pMin;
    6958      134689 :     T max0 = *pMax;
    6959      134689 :     T min1 = *pMin;
    6960      134689 :     T max1 = *pMax;
    6961             :     size_t i;
    6962     1017014 :     for (i = 0; i + 1 < nElts; i += 2)
    6963             :     {
    6964      869734 :         if (!HAS_NODATA || buffer[i] != nodataValue)
    6965             :         {
    6966      881141 :             min0 = std::min(min0, buffer[i]);
    6967      881141 :             max0 = std::max(max0, buffer[i]);
    6968             :         }
    6969      869734 :         if (!HAS_NODATA || buffer[i + 1] != nodataValue)
    6970             :         {
    6971      881354 :             min1 = std::min(min1, buffer[i + 1]);
    6972      881354 :             max1 = std::max(max1, buffer[i + 1]);
    6973             :         }
    6974             :     }
    6975      134689 :     T min = std::min(min0, min1);
    6976      134689 :     T max = std::max(max0, max1);
    6977      134689 :     if (i < nElts)
    6978             :     {
    6979      119260 :         if (!HAS_NODATA || buffer[i] != nodataValue)
    6980             :         {
    6981      119276 :             min = std::min(min, buffer[i]);
    6982      119276 :             max = std::max(max, buffer[i]);
    6983             :         }
    6984             :     }
    6985      134689 :     *pMin = min;
    6986      134689 :     *pMax = max;
    6987      134689 : }
    6988             : 
    6989             : template <GDALDataType eDataType, bool bSignedByte>
    6990             : static void
    6991       11512 : ComputeMinMaxGeneric(const void *pData, int nXCheck, int nYCheck,
    6992             :                      int nBlockXSize, const GDALNoDataValues &sNoDataValues,
    6993             :                      const GByte *pabyMaskData, double &dfMin, double &dfMax)
    6994             : {
    6995       11512 :     double dfLocalMin = dfMin;
    6996       11512 :     double dfLocalMax = dfMax;
    6997             : 
    6998       43491 :     for (int iY = 0; iY < nYCheck; iY++)
    6999             :     {
    7000    18965527 :         for (int iX = 0; iX < nXCheck; iX++)
    7001             :         {
    7002    18933565 :             const GPtrDiff_t iOffset =
    7003    18933565 :                 iX + static_cast<GPtrDiff_t>(iY) * nBlockXSize;
    7004    18933565 :             if (pabyMaskData && pabyMaskData[iOffset] == 0)
    7005     3460307 :                 continue;
    7006    18839324 :             bool bValid = true;
    7007    18839324 :             double dfValue = GetPixelValue(eDataType, bSignedByte, pData,
    7008             :                                            iOffset, sNoDataValues, bValid);
    7009    18839324 :             if (!bValid)
    7010     3366066 :                 continue;
    7011             : 
    7012    15473217 :             dfLocalMin = std::min(dfLocalMin, dfValue);
    7013    15473217 :             dfLocalMax = std::max(dfLocalMax, dfValue);
    7014             :         }
    7015             :     }
    7016             : 
    7017       11512 :     dfMin = dfLocalMin;
    7018       11512 :     dfMax = dfLocalMax;
    7019       11512 : }
    7020             : 
    7021       11512 : static void ComputeMinMaxGeneric(const void *pData, GDALDataType eDataType,
    7022             :                                  bool bSignedByte, int nXCheck, int nYCheck,
    7023             :                                  int nBlockXSize,
    7024             :                                  const GDALNoDataValues &sNoDataValues,
    7025             :                                  const GByte *pabyMaskData, double &dfMin,
    7026             :                                  double &dfMax)
    7027             : {
    7028       11512 :     switch (eDataType)
    7029             :     {
    7030           0 :         case GDT_Unknown:
    7031           0 :             CPLAssert(false);
    7032             :             break;
    7033         672 :         case GDT_Byte:
    7034         672 :             if (bSignedByte)
    7035             :             {
    7036           3 :                 ComputeMinMaxGeneric<GDT_Byte, true>(
    7037             :                     pData, nXCheck, nYCheck, nBlockXSize, sNoDataValues,
    7038             :                     pabyMaskData, dfMin, dfMax);
    7039             :             }
    7040             :             else
    7041             :             {
    7042         669 :                 ComputeMinMaxGeneric<GDT_Byte, false>(
    7043             :                     pData, nXCheck, nYCheck, nBlockXSize, sNoDataValues,
    7044             :                     pabyMaskData, dfMin, dfMax);
    7045             :             }
    7046         672 :             break;
    7047         102 :         case GDT_Int8:
    7048         102 :             ComputeMinMaxGeneric<GDT_Int8, false>(pData, nXCheck, nYCheck,
    7049             :                                                   nBlockXSize, sNoDataValues,
    7050             :                                                   pabyMaskData, dfMin, dfMax);
    7051         102 :             break;
    7052         200 :         case GDT_UInt16:
    7053         200 :             ComputeMinMaxGeneric<GDT_UInt16, false>(pData, nXCheck, nYCheck,
    7054             :                                                     nBlockXSize, sNoDataValues,
    7055             :                                                     pabyMaskData, dfMin, dfMax);
    7056         200 :             break;
    7057           1 :         case GDT_Int16:
    7058           1 :             ComputeMinMaxGeneric<GDT_Int16, false>(pData, nXCheck, nYCheck,
    7059             :                                                    nBlockXSize, sNoDataValues,
    7060             :                                                    pabyMaskData, dfMin, dfMax);
    7061           1 :             break;
    7062         197 :         case GDT_UInt32:
    7063         197 :             ComputeMinMaxGeneric<GDT_UInt32, false>(pData, nXCheck, nYCheck,
    7064             :                                                     nBlockXSize, sNoDataValues,
    7065             :                                                     pabyMaskData, dfMin, dfMax);
    7066         197 :             break;
    7067        1111 :         case GDT_Int32:
    7068        1111 :             ComputeMinMaxGeneric<GDT_Int32, false>(pData, nXCheck, nYCheck,
    7069             :                                                    nBlockXSize, sNoDataValues,
    7070             :                                                    pabyMaskData, dfMin, dfMax);
    7071        1111 :             break;
    7072          12 :         case GDT_UInt64:
    7073          12 :             ComputeMinMaxGeneric<GDT_UInt64, false>(pData, nXCheck, nYCheck,
    7074             :                                                     nBlockXSize, sNoDataValues,
    7075             :                                                     pabyMaskData, dfMin, dfMax);
    7076          12 :             break;
    7077          24 :         case GDT_Int64:
    7078          24 :             ComputeMinMaxGeneric<GDT_Int64, false>(pData, nXCheck, nYCheck,
    7079             :                                                    nBlockXSize, sNoDataValues,
    7080             :                                                    pabyMaskData, dfMin, dfMax);
    7081          24 :             break;
    7082           0 :         case GDT_Float16:
    7083           0 :             ComputeMinMaxGeneric<GDT_Float16, false>(
    7084             :                 pData, nXCheck, nYCheck, nBlockXSize, sNoDataValues,
    7085             :                 pabyMaskData, dfMin, dfMax);
    7086           0 :             break;
    7087        5675 :         case GDT_Float32:
    7088        5675 :             ComputeMinMaxGeneric<GDT_Float32, false>(
    7089             :                 pData, nXCheck, nYCheck, nBlockXSize, sNoDataValues,
    7090             :                 pabyMaskData, dfMin, dfMax);
    7091        5675 :             break;
    7092        3408 :         case GDT_Float64:
    7093        3408 :             ComputeMinMaxGeneric<GDT_Float64, false>(
    7094             :                 pData, nXCheck, nYCheck, nBlockXSize, sNoDataValues,
    7095             :                 pabyMaskData, dfMin, dfMax);
    7096        3408 :             break;
    7097           9 :         case GDT_CInt16:
    7098           9 :             ComputeMinMaxGeneric<GDT_CInt16, false>(pData, nXCheck, nYCheck,
    7099             :                                                     nBlockXSize, sNoDataValues,
    7100             :                                                     pabyMaskData, dfMin, dfMax);
    7101           9 :             break;
    7102           9 :         case GDT_CInt32:
    7103           9 :             ComputeMinMaxGeneric<GDT_CInt32, false>(pData, nXCheck, nYCheck,
    7104             :                                                     nBlockXSize, sNoDataValues,
    7105             :                                                     pabyMaskData, dfMin, dfMax);
    7106           9 :             break;
    7107           0 :         case GDT_CFloat16:
    7108           0 :             ComputeMinMaxGeneric<GDT_CFloat16, false>(
    7109             :                 pData, nXCheck, nYCheck, nBlockXSize, sNoDataValues,
    7110             :                 pabyMaskData, dfMin, dfMax);
    7111           0 :             break;
    7112          75 :         case GDT_CFloat32:
    7113          75 :             ComputeMinMaxGeneric<GDT_CFloat32, false>(
    7114             :                 pData, nXCheck, nYCheck, nBlockXSize, sNoDataValues,
    7115             :                 pabyMaskData, dfMin, dfMax);
    7116          75 :             break;
    7117          17 :         case GDT_CFloat64:
    7118          17 :             ComputeMinMaxGeneric<GDT_CFloat64, false>(
    7119             :                 pData, nXCheck, nYCheck, nBlockXSize, sNoDataValues,
    7120             :                 pabyMaskData, dfMin, dfMax);
    7121          17 :             break;
    7122           0 :         case GDT_TypeCount:
    7123           0 :             CPLAssert(false);
    7124             :             break;
    7125             :     }
    7126       11512 : }
    7127             : 
    7128         704 : static bool ComputeMinMaxGenericIterBlocks(
    7129             :     GDALRasterBand *poBand, GDALDataType eDataType, bool bSignedByte,
    7130             :     GIntBig nTotalBlocks, int nSampleRate, int nBlocksPerRow,
    7131             :     const GDALNoDataValues &sNoDataValues, GDALRasterBand *poMaskBand,
    7132             :     double &dfMin, double &dfMax)
    7133             : 
    7134             : {
    7135         704 :     GByte *pabyMaskData = nullptr;
    7136             :     int nBlockXSize, nBlockYSize;
    7137         704 :     poBand->GetBlockSize(&nBlockXSize, &nBlockYSize);
    7138             : 
    7139         704 :     if (poMaskBand)
    7140             :     {
    7141             :         pabyMaskData =
    7142          40 :             static_cast<GByte *>(VSI_MALLOC2_VERBOSE(nBlockXSize, nBlockYSize));
    7143          40 :         if (!pabyMaskData)
    7144             :         {
    7145           0 :             return false;
    7146             :         }
    7147             :     }
    7148             : 
    7149       12216 :     for (GIntBig iSampleBlock = 0; iSampleBlock < nTotalBlocks;
    7150       11512 :          iSampleBlock += nSampleRate)
    7151             :     {
    7152       11512 :         const int iYBlock = static_cast<int>(iSampleBlock / nBlocksPerRow);
    7153       11512 :         const int iXBlock = static_cast<int>(iSampleBlock % nBlocksPerRow);
    7154             : 
    7155       11512 :         GDALRasterBlock *poBlock = poBand->GetLockedBlockRef(iXBlock, iYBlock);
    7156       11512 :         if (poBlock == nullptr)
    7157             :         {
    7158           0 :             CPLFree(pabyMaskData);
    7159           0 :             return false;
    7160             :         }
    7161             : 
    7162       11512 :         void *const pData = poBlock->GetDataRef();
    7163             : 
    7164       11512 :         int nXCheck = 0, nYCheck = 0;
    7165       11512 :         poBand->GetActualBlockSize(iXBlock, iYBlock, &nXCheck, &nYCheck);
    7166             : 
    7167       12383 :         if (poMaskBand &&
    7168         871 :             poMaskBand->RasterIO(GF_Read, iXBlock * nBlockXSize,
    7169             :                                  iYBlock * nBlockYSize, nXCheck, nYCheck,
    7170             :                                  pabyMaskData, nXCheck, nYCheck, GDT_Byte, 0,
    7171             :                                  nBlockXSize, nullptr) != CE_None)
    7172             :         {
    7173           0 :             poBlock->DropLock();
    7174           0 :             CPLFree(pabyMaskData);
    7175           0 :             return false;
    7176             :         }
    7177             : 
    7178       11512 :         ComputeMinMaxGeneric(pData, eDataType, bSignedByte, nXCheck, nYCheck,
    7179             :                              nBlockXSize, sNoDataValues, pabyMaskData, dfMin,
    7180             :                              dfMax);
    7181             : 
    7182       11512 :         poBlock->DropLock();
    7183             :     }
    7184             : 
    7185         704 :     CPLFree(pabyMaskData);
    7186         704 :     return true;
    7187             : }
    7188             : 
    7189             : /**
    7190             :  * \brief Compute the min/max values for a band.
    7191             :  *
    7192             :  * If approximate is OK, then the band's GetMinimum()/GetMaximum() will
    7193             :  * be trusted.  If it doesn't work, a subsample of blocks will be read to
    7194             :  * get an approximate min/max.  If the band has a nodata value it will
    7195             :  * be excluded from the minimum and maximum.
    7196             :  *
    7197             :  * If bApprox is FALSE, then all pixels will be read and used to compute
    7198             :  * an exact range.
    7199             :  *
    7200             :  * This method is the same as the C function GDALComputeRasterMinMax().
    7201             :  *
    7202             :  * @param bApproxOK TRUE if an approximate (faster) answer is OK, otherwise
    7203             :  * FALSE.
    7204             :  * @param adfMinMax the array in which the minimum (adfMinMax[0]) and the
    7205             :  * maximum (adfMinMax[1]) are returned.
    7206             :  *
    7207             :  * @return CE_None on success or CE_Failure on failure.
    7208             :  */
    7209             : 
    7210        1554 : CPLErr GDALRasterBand::ComputeRasterMinMax(int bApproxOK, double *adfMinMax)
    7211             : {
    7212             :     /* -------------------------------------------------------------------- */
    7213             :     /*      Does the driver already know the min/max?                       */
    7214             :     /* -------------------------------------------------------------------- */
    7215        1554 :     if (bApproxOK)
    7216             :     {
    7217          12 :         int bSuccessMin = FALSE;
    7218          12 :         int bSuccessMax = FALSE;
    7219             : 
    7220          12 :         double dfMin = GetMinimum(&bSuccessMin);
    7221          12 :         double dfMax = GetMaximum(&bSuccessMax);
    7222             : 
    7223          12 :         if (bSuccessMin && bSuccessMax)
    7224             :         {
    7225           1 :             adfMinMax[0] = dfMin;
    7226           1 :             adfMinMax[1] = dfMax;
    7227           1 :             return CE_None;
    7228             :         }
    7229             :     }
    7230             : 
    7231             :     /* -------------------------------------------------------------------- */
    7232             :     /*      If we have overview bands, use them for min/max.                */
    7233             :     /* -------------------------------------------------------------------- */
    7234             :     // cppcheck-suppress knownConditionTrueFalse
    7235        1553 :     if (bApproxOK && GetOverviewCount() > 0 && !HasArbitraryOverviews())
    7236             :     {
    7237             :         GDALRasterBand *poBand =
    7238           0 :             GetRasterSampleOverview(GDALSTAT_APPROX_NUMSAMPLES);
    7239             : 
    7240           0 :         if (poBand != this)
    7241           0 :             return poBand->ComputeRasterMinMax(FALSE, adfMinMax);
    7242             :     }
    7243             : 
    7244             :     /* -------------------------------------------------------------------- */
    7245             :     /*      Read actual data and compute minimum and maximum.               */
    7246             :     /* -------------------------------------------------------------------- */
    7247        1553 :     GDALNoDataValues sNoDataValues(this, eDataType);
    7248        1553 :     GDALRasterBand *poMaskBand = nullptr;
    7249        1553 :     if (!sNoDataValues.bGotNoDataValue)
    7250             :     {
    7251        1289 :         const int l_nMaskFlags = GetMaskFlags();
    7252        1329 :         if (l_nMaskFlags != GMF_ALL_VALID && l_nMaskFlags != GMF_NODATA &&
    7253          40 :             GetColorInterpretation() != GCI_AlphaBand)
    7254             :         {
    7255          40 :             poMaskBand = GetMaskBand();
    7256             :         }
    7257             :     }
    7258             : 
    7259        1553 :     bool bSignedByte = false;
    7260        1553 :     if (eDataType == GDT_Byte)
    7261             :     {
    7262         638 :         EnablePixelTypeSignedByteWarning(false);
    7263             :         const char *pszPixelType =
    7264         638 :             GetMetadataItem("PIXELTYPE", "IMAGE_STRUCTURE");
    7265         638 :         EnablePixelTypeSignedByteWarning(true);
    7266         638 :         bSignedByte =
    7267         638 :             pszPixelType != nullptr && EQUAL(pszPixelType, "SIGNEDBYTE");
    7268             :     }
    7269             : 
    7270             :     GDALRasterIOExtraArg sExtraArg;
    7271        1553 :     INIT_RASTERIO_EXTRA_ARG(sExtraArg);
    7272             : 
    7273        3106 :     GUInt32 nMin = (eDataType == GDT_Byte)
    7274        1553 :                        ? 255
    7275             :                        : 65535;  // used for GByte & GUInt16 cases
    7276        1553 :     GUInt32 nMax = 0;            // used for GByte & GUInt16 cases
    7277        1553 :     GInt16 nMinInt16 =
    7278             :         std::numeric_limits<GInt16>::max();  // used for GInt16 case
    7279        1553 :     GInt16 nMaxInt16 =
    7280             :         std::numeric_limits<GInt16>::lowest();  // used for GInt16 case
    7281        1553 :     double dfMin =
    7282             :         std::numeric_limits<double>::max();  // used for generic code path
    7283        1553 :     double dfMax =
    7284             :         std::numeric_limits<double>::lowest();  // used for generic code path
    7285        1553 :     const bool bUseOptimizedPath =
    7286        2459 :         !poMaskBand && ((eDataType == GDT_Byte && !bSignedByte) ||
    7287         906 :                         eDataType == GDT_Int16 || eDataType == GDT_UInt16);
    7288             : 
    7289             :     const auto ComputeMinMaxForBlock =
    7290       18582 :         [this, bSignedByte, &sNoDataValues, &nMin, &nMax, &nMinInt16,
    7291             :          &nMaxInt16](const void *pData, int nXCheck, int nBufferWidth,
    7292      241828 :                      int nYCheck)
    7293             :     {
    7294       18582 :         if (eDataType == GDT_Byte && !bSignedByte)
    7295             :         {
    7296             :             const bool bHasNoData =
    7297        9501 :                 sNoDataValues.bGotNoDataValue &&
    7298       25669 :                 GDALIsValueInRange<GByte>(sNoDataValues.dfNoDataValue) &&
    7299        9501 :                 static_cast<GByte>(sNoDataValues.dfNoDataValue) ==
    7300        9501 :                     sNoDataValues.dfNoDataValue;
    7301       16168 :             const GUInt32 nNoDataValue =
    7302       16168 :                 bHasNoData ? static_cast<GByte>(sNoDataValues.dfNoDataValue)
    7303             :                            : 0;
    7304             :             GUIntBig nSum, nSumSquare, nSampleCount, nValidCount;  // unused
    7305             :             ComputeStatisticsInternal<GByte,
    7306             :                                       /* COMPUTE_OTHER_STATS = */ false>::
    7307       16168 :                 f(nXCheck, nBufferWidth, nYCheck,
    7308             :                   static_cast<const GByte *>(pData), bHasNoData, nNoDataValue,
    7309       16168 :                   nMin, nMax, nSum, nSumSquare, nSampleCount, nValidCount);
    7310             :         }
    7311        2414 :         else if (eDataType == GDT_UInt16)
    7312             :         {
    7313             :             const bool bHasNoData =
    7314          83 :                 sNoDataValues.bGotNoDataValue &&
    7315         973 :                 GDALIsValueInRange<GUInt16>(sNoDataValues.dfNoDataValue) &&
    7316          83 :                 static_cast<GUInt16>(sNoDataValues.dfNoDataValue) ==
    7317          83 :                     sNoDataValues.dfNoDataValue;
    7318         890 :             const GUInt32 nNoDataValue =
    7319         890 :                 bHasNoData ? static_cast<GUInt16>(sNoDataValues.dfNoDataValue)
    7320             :                            : 0;
    7321             :             GUIntBig nSum, nSumSquare, nSampleCount, nValidCount;  // unused
    7322             :             ComputeStatisticsInternal<GUInt16,
    7323             :                                       /* COMPUTE_OTHER_STATS = */ false>::
    7324         890 :                 f(nXCheck, nBufferWidth, nYCheck,
    7325             :                   static_cast<const GUInt16 *>(pData), bHasNoData, nNoDataValue,
    7326             :                   nMin, nMax, nSum, nSumSquare, nSampleCount, nValidCount);
    7327             :         }
    7328        1524 :         else if (eDataType == GDT_Int16)
    7329             :         {
    7330             :             const bool bHasNoData =
    7331        1353 :                 sNoDataValues.bGotNoDataValue &&
    7332        2877 :                 GDALIsValueInRange<int16_t>(sNoDataValues.dfNoDataValue) &&
    7333        1353 :                 static_cast<int16_t>(sNoDataValues.dfNoDataValue) ==
    7334        1353 :                     sNoDataValues.dfNoDataValue;
    7335        1524 :             if (bHasNoData)
    7336             :             {
    7337        1353 :                 const int16_t nNoDataValue =
    7338        1353 :                     static_cast<int16_t>(sNoDataValues.dfNoDataValue);
    7339      134754 :                 for (int iY = 0; iY < nYCheck; iY++)
    7340             :                 {
    7341      133401 :                     ComputeMinMax<int16_t, true>(
    7342      133401 :                         static_cast<const int16_t *>(pData) +
    7343      133401 :                             static_cast<size_t>(iY) * nBufferWidth,
    7344             :                         nXCheck, nNoDataValue, &nMinInt16, &nMaxInt16);
    7345             :                 }
    7346             :             }
    7347             :             else
    7348             :             {
    7349        1459 :                 for (int iY = 0; iY < nYCheck; iY++)
    7350             :                 {
    7351        1288 :                     ComputeMinMax<int16_t, false>(
    7352        1288 :                         static_cast<const int16_t *>(pData) +
    7353        1288 :                             static_cast<size_t>(iY) * nBufferWidth,
    7354             :                         nXCheck, 0, &nMinInt16, &nMaxInt16);
    7355             :                 }
    7356             :             }
    7357             :         }
    7358       18582 :     };
    7359             : 
    7360        1553 :     if (bApproxOK && HasArbitraryOverviews())
    7361             :     {
    7362             :         /* --------------------------------------------------------------------
    7363             :          */
    7364             :         /*      Figure out how much the image should be reduced to get an */
    7365             :         /*      approximate value. */
    7366             :         /* --------------------------------------------------------------------
    7367             :          */
    7368           0 :         double dfReduction = sqrt(static_cast<double>(nRasterXSize) *
    7369           0 :                                   nRasterYSize / GDALSTAT_APPROX_NUMSAMPLES);
    7370             : 
    7371           0 :         int nXReduced = nRasterXSize;
    7372           0 :         int nYReduced = nRasterYSize;
    7373           0 :         if (dfReduction > 1.0)
    7374             :         {
    7375           0 :             nXReduced = static_cast<int>(nRasterXSize / dfReduction);
    7376           0 :             nYReduced = static_cast<int>(nRasterYSize / dfReduction);
    7377             : 
    7378             :             // Catch the case of huge resizing ratios here
    7379           0 :             if (nXReduced == 0)
    7380           0 :                 nXReduced = 1;
    7381           0 :             if (nYReduced == 0)
    7382           0 :                 nYReduced = 1;
    7383             :         }
    7384             : 
    7385           0 :         void *const pData = CPLMalloc(cpl::fits_on<int>(
    7386           0 :             GDALGetDataTypeSizeBytes(eDataType) * nXReduced * nYReduced));
    7387             : 
    7388             :         const CPLErr eErr =
    7389           0 :             IRasterIO(GF_Read, 0, 0, nRasterXSize, nRasterYSize, pData,
    7390           0 :                       nXReduced, nYReduced, eDataType, 0, 0, &sExtraArg);
    7391           0 :         if (eErr != CE_None)
    7392             :         {
    7393           0 :             CPLFree(pData);
    7394           0 :             return eErr;
    7395             :         }
    7396             : 
    7397           0 :         GByte *pabyMaskData = nullptr;
    7398           0 :         if (poMaskBand)
    7399             :         {
    7400             :             pabyMaskData =
    7401           0 :                 static_cast<GByte *>(VSI_MALLOC2_VERBOSE(nXReduced, nYReduced));
    7402           0 :             if (!pabyMaskData)
    7403             :             {
    7404           0 :                 CPLFree(pData);
    7405           0 :                 return CE_Failure;
    7406             :             }
    7407             : 
    7408           0 :             if (poMaskBand->RasterIO(GF_Read, 0, 0, nRasterXSize, nRasterYSize,
    7409             :                                      pabyMaskData, nXReduced, nYReduced,
    7410           0 :                                      GDT_Byte, 0, 0, nullptr) != CE_None)
    7411             :             {
    7412           0 :                 CPLFree(pData);
    7413           0 :                 CPLFree(pabyMaskData);
    7414           0 :                 return CE_Failure;
    7415             :             }
    7416             :         }
    7417             : 
    7418           0 :         if (bUseOptimizedPath)
    7419             :         {
    7420           0 :             ComputeMinMaxForBlock(pData, nXReduced, nXReduced, nYReduced);
    7421             :         }
    7422             :         else
    7423             :         {
    7424           0 :             ComputeMinMaxGeneric(pData, eDataType, bSignedByte, nXReduced,
    7425             :                                  nYReduced, nXReduced, sNoDataValues,
    7426             :                                  pabyMaskData, dfMin, dfMax);
    7427             :         }
    7428             : 
    7429           0 :         CPLFree(pData);
    7430           0 :         CPLFree(pabyMaskData);
    7431             :     }
    7432             : 
    7433             :     else  // No arbitrary overviews
    7434             :     {
    7435        1553 :         if (!InitBlockInfo())
    7436           0 :             return CE_Failure;
    7437             : 
    7438             :         /* --------------------------------------------------------------------
    7439             :          */
    7440             :         /*      Figure out the ratio of blocks we will read to get an */
    7441             :         /*      approximate value. */
    7442             :         /* --------------------------------------------------------------------
    7443             :          */
    7444        1553 :         int nSampleRate = 1;
    7445             : 
    7446        1553 :         if (bApproxOK)
    7447             :         {
    7448          11 :             nSampleRate = static_cast<int>(std::max(
    7449          22 :                 1.0,
    7450          11 :                 sqrt(static_cast<double>(nBlocksPerRow) * nBlocksPerColumn)));
    7451             :             // We want to avoid probing only the first column of blocks for
    7452             :             // a square shaped raster, because it is not unlikely that it may
    7453             :             // be padding only (#6378).
    7454          11 :             if (nSampleRate == nBlocksPerRow && nBlocksPerRow > 1)
    7455           0 :                 nSampleRate += 1;
    7456             :         }
    7457             : 
    7458        1553 :         if (bUseOptimizedPath)
    7459             :         {
    7460         849 :             for (GIntBig iSampleBlock = 0;
    7461       19357 :                  iSampleBlock <
    7462       19357 :                  static_cast<GIntBig>(nBlocksPerRow) * nBlocksPerColumn;
    7463       18508 :                  iSampleBlock += nSampleRate)
    7464             :             {
    7465       18583 :                 const int iYBlock =
    7466       18583 :                     static_cast<int>(iSampleBlock / nBlocksPerRow);
    7467       18583 :                 const int iXBlock =
    7468       18583 :                     static_cast<int>(iSampleBlock % nBlocksPerRow);
    7469             : 
    7470       18583 :                 GDALRasterBlock *poBlock = GetLockedBlockRef(iXBlock, iYBlock);
    7471       18583 :                 if (poBlock == nullptr)
    7472           1 :                     return CE_Failure;
    7473             : 
    7474       18582 :                 void *const pData = poBlock->GetDataRef();
    7475             : 
    7476       18582 :                 int nXCheck = 0, nYCheck = 0;
    7477       18582 :                 GetActualBlockSize(iXBlock, iYBlock, &nXCheck, &nYCheck);
    7478             : 
    7479       18582 :                 ComputeMinMaxForBlock(pData, nXCheck, nBlockXSize, nYCheck);
    7480             : 
    7481       18582 :                 poBlock->DropLock();
    7482             : 
    7483       18582 :                 if (eDataType == GDT_Byte && !bSignedByte && nMin == 0 &&
    7484        4120 :                     nMax == 255)
    7485          74 :                     break;
    7486             :             }
    7487             :         }
    7488             :         else
    7489             :         {
    7490         704 :             const GIntBig nTotalBlocks =
    7491         704 :                 static_cast<GIntBig>(nBlocksPerRow) * nBlocksPerColumn;
    7492         704 :             if (!ComputeMinMaxGenericIterBlocks(
    7493             :                     this, eDataType, bSignedByte, nTotalBlocks, nSampleRate,
    7494             :                     nBlocksPerRow, sNoDataValues, poMaskBand, dfMin, dfMax))
    7495             :             {
    7496           0 :                 return CE_Failure;
    7497             :             }
    7498             :         }
    7499             :     }
    7500             : 
    7501        1552 :     if (bUseOptimizedPath)
    7502             :     {
    7503         848 :         if ((eDataType == GDT_Byte && !bSignedByte) || eDataType == GDT_UInt16)
    7504             :         {
    7505         736 :             dfMin = nMin;
    7506         736 :             dfMax = nMax;
    7507             :         }
    7508         112 :         else if (eDataType == GDT_Int16)
    7509             :         {
    7510         112 :             dfMin = nMinInt16;
    7511         112 :             dfMax = nMaxInt16;
    7512             :         }
    7513             :     }
    7514             : 
    7515        1552 :     if (dfMin > dfMax)
    7516             :     {
    7517           4 :         adfMinMax[0] = 0;
    7518           4 :         adfMinMax[1] = 0;
    7519           4 :         ReportError(
    7520             :             CE_Failure, CPLE_AppDefined,
    7521             :             "Failed to compute min/max, no valid pixels found in sampling.");
    7522           4 :         return CE_Failure;
    7523             :     }
    7524             : 
    7525        1548 :     adfMinMax[0] = dfMin;
    7526        1548 :     adfMinMax[1] = dfMax;
    7527             : 
    7528        1548 :     return CE_None;
    7529             : }
    7530             : 
    7531             : /************************************************************************/
    7532             : /*                      GDALComputeRasterMinMax()                       */
    7533             : /************************************************************************/
    7534             : 
    7535             : /**
    7536             :  * \brief Compute the min/max values for a band.
    7537             :  *
    7538             :  * @see GDALRasterBand::ComputeRasterMinMax()
    7539             :  *
    7540             :  * @note Prior to GDAL 3.6, this function returned void
    7541             :  */
    7542             : 
    7543        1476 : CPLErr CPL_STDCALL GDALComputeRasterMinMax(GDALRasterBandH hBand, int bApproxOK,
    7544             :                                            double adfMinMax[2])
    7545             : 
    7546             : {
    7547        1476 :     VALIDATE_POINTER1(hBand, "GDALComputeRasterMinMax", CE_Failure);
    7548             : 
    7549        1476 :     GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
    7550        1476 :     return poBand->ComputeRasterMinMax(bApproxOK, adfMinMax);
    7551             : }
    7552             : 
    7553             : /************************************************************************/
    7554             : /*                    ComputeRasterMinMaxLocation()                     */
    7555             : /************************************************************************/
    7556             : 
    7557             : /**
    7558             :  * \brief Compute the min/max values for a band, and their location.
    7559             :  *
    7560             :  * Pixels whose value matches the nodata value or are masked by the mask
    7561             :  * band are ignored.
    7562             :  *
    7563             :  * If the minimum or maximum value is hit in several locations, it is not
    7564             :  * specified which one will be returned.
    7565             :  *
    7566             :  * @param[out] pdfMin Pointer to the minimum value.
    7567             :  * @param[out] pdfMax Pointer to the maximum value.
    7568             :  * @param[out] pnMinX Pointer to the column where the minimum value is hit.
    7569             :  * @param[out] pnMinY Pointer to the line where the minimum value is hit.
    7570             :  * @param[out] pnMaxX Pointer to the column where the maximum value is hit.
    7571             :  * @param[out] pnMaxY Pointer to the line where the maximum value is hit.
    7572             :  *
    7573             :  * @return CE_None in case of success, CE_Warning if there are no valid values,
    7574             :  *         CE_Failure in case of error.
    7575             :  *
    7576             :  * @since GDAL 3.11
    7577             :  */
    7578             : 
    7579           8 : CPLErr GDALRasterBand::ComputeRasterMinMaxLocation(double *pdfMin,
    7580             :                                                    double *pdfMax, int *pnMinX,
    7581             :                                                    int *pnMinY, int *pnMaxX,
    7582             :                                                    int *pnMaxY)
    7583             : {
    7584           8 :     int nMinX = -1;
    7585           8 :     int nMinY = -1;
    7586           8 :     int nMaxX = -1;
    7587           8 :     int nMaxY = -1;
    7588           8 :     double dfMin = std::numeric_limits<double>::infinity();
    7589           8 :     double dfMax = -std::numeric_limits<double>::infinity();
    7590           8 :     if (pdfMin)
    7591           5 :         *pdfMin = dfMin;
    7592           8 :     if (pdfMax)
    7593           5 :         *pdfMax = dfMax;
    7594           8 :     if (pnMinX)
    7595           6 :         *pnMinX = nMinX;
    7596           8 :     if (pnMinY)
    7597           6 :         *pnMinY = nMinY;
    7598           8 :     if (pnMaxX)
    7599           6 :         *pnMaxX = nMaxX;
    7600           8 :     if (pnMaxY)
    7601           6 :         *pnMaxY = nMaxY;
    7602             : 
    7603           8 :     if (GDALDataTypeIsComplex(eDataType))
    7604             :     {
    7605           0 :         CPLError(CE_Failure, CPLE_NotSupported,
    7606             :                  "Complex data type not supported");
    7607           0 :         return CE_Failure;
    7608             :     }
    7609             : 
    7610           8 :     if (!InitBlockInfo())
    7611           0 :         return CE_Failure;
    7612             : 
    7613           8 :     GDALNoDataValues sNoDataValues(this, eDataType);
    7614           8 :     GDALRasterBand *poMaskBand = nullptr;
    7615           8 :     if (!sNoDataValues.bGotNoDataValue)
    7616             :     {
    7617           8 :         const int l_nMaskFlags = GetMaskFlags();
    7618           9 :         if (l_nMaskFlags != GMF_ALL_VALID && l_nMaskFlags != GMF_NODATA &&
    7619           1 :             GetColorInterpretation() != GCI_AlphaBand)
    7620             :         {
    7621           1 :             poMaskBand = GetMaskBand();
    7622             :         }
    7623             :     }
    7624             : 
    7625           8 :     bool bSignedByte = false;
    7626           8 :     if (eDataType == GDT_Byte)
    7627             :     {
    7628           7 :         EnablePixelTypeSignedByteWarning(false);
    7629             :         const char *pszPixelType =
    7630           7 :             GetMetadataItem("PIXELTYPE", "IMAGE_STRUCTURE");
    7631           7 :         EnablePixelTypeSignedByteWarning(true);
    7632           7 :         bSignedByte =
    7633           7 :             pszPixelType != nullptr && EQUAL(pszPixelType, "SIGNEDBYTE");
    7634             :     }
    7635             : 
    7636           8 :     GByte *pabyMaskData = nullptr;
    7637           8 :     if (poMaskBand)
    7638             :     {
    7639             :         pabyMaskData =
    7640           1 :             static_cast<GByte *>(VSI_MALLOC2_VERBOSE(nBlockXSize, nBlockYSize));
    7641           1 :         if (!pabyMaskData)
    7642             :         {
    7643           0 :             return CE_Failure;
    7644             :         }
    7645             :     }
    7646             : 
    7647           8 :     const GIntBig nTotalBlocks =
    7648           8 :         static_cast<GIntBig>(nBlocksPerRow) * nBlocksPerColumn;
    7649           8 :     bool bNeedsMin = pdfMin || pnMinX || pnMinY;
    7650           8 :     bool bNeedsMax = pdfMax || pnMaxX || pnMaxY;
    7651          16 :     for (GIntBig iBlock = 0; iBlock < nTotalBlocks; ++iBlock)
    7652             :     {
    7653          11 :         const int iYBlock = static_cast<int>(iBlock / nBlocksPerRow);
    7654          11 :         const int iXBlock = static_cast<int>(iBlock % nBlocksPerRow);
    7655             : 
    7656          11 :         GDALRasterBlock *poBlock = GetLockedBlockRef(iXBlock, iYBlock);
    7657          11 :         if (poBlock == nullptr)
    7658             :         {
    7659           0 :             CPLFree(pabyMaskData);
    7660           0 :             return CE_Failure;
    7661             :         }
    7662             : 
    7663          11 :         void *const pData = poBlock->GetDataRef();
    7664             : 
    7665          11 :         int nXCheck = 0, nYCheck = 0;
    7666          11 :         GetActualBlockSize(iXBlock, iYBlock, &nXCheck, &nYCheck);
    7667             : 
    7668          13 :         if (poMaskBand &&
    7669           2 :             poMaskBand->RasterIO(GF_Read, iXBlock * nBlockXSize,
    7670           2 :                                  iYBlock * nBlockYSize, nXCheck, nYCheck,
    7671             :                                  pabyMaskData, nXCheck, nYCheck, GDT_Byte, 0,
    7672           2 :                                  nBlockXSize, nullptr) != CE_None)
    7673             :         {
    7674           0 :             poBlock->DropLock();
    7675           0 :             CPLFree(pabyMaskData);
    7676           0 :             return CE_Failure;
    7677             :         }
    7678             : 
    7679          11 :         if (poMaskBand || nYCheck < nBlockYSize || nXCheck < nBlockXSize)
    7680             :         {
    7681           4 :             for (int iY = 0; iY < nYCheck; ++iY)
    7682             :             {
    7683           6 :                 for (int iX = 0; iX < nXCheck; ++iX)
    7684             :                 {
    7685           4 :                     const GPtrDiff_t iOffset =
    7686           4 :                         iX + static_cast<GPtrDiff_t>(iY) * nBlockXSize;
    7687           4 :                     if (pabyMaskData && pabyMaskData[iOffset] == 0)
    7688           2 :                         continue;
    7689           2 :                     bool bValid = true;
    7690             :                     double dfValue =
    7691           2 :                         GetPixelValue(eDataType, bSignedByte, pData, iOffset,
    7692             :                                       sNoDataValues, bValid);
    7693           2 :                     if (!bValid)
    7694           0 :                         continue;
    7695           2 :                     if (dfValue < dfMin)
    7696             :                     {
    7697           2 :                         dfMin = dfValue;
    7698           2 :                         nMinX = iXBlock * nBlockXSize + iX;
    7699           2 :                         nMinY = iYBlock * nBlockYSize + iY;
    7700             :                     }
    7701           2 :                     if (dfValue > dfMax)
    7702             :                     {
    7703           1 :                         dfMax = dfValue;
    7704           1 :                         nMaxX = iXBlock * nBlockXSize + iX;
    7705           1 :                         nMaxY = iYBlock * nBlockYSize + iY;
    7706             :                     }
    7707             :                 }
    7708           2 :             }
    7709             :         }
    7710             :         else
    7711             :         {
    7712           9 :             size_t pos_min = 0;
    7713           9 :             size_t pos_max = 0;
    7714           9 :             const auto eEffectiveDT = bSignedByte ? GDT_Int8 : eDataType;
    7715           9 :             if (bNeedsMin && bNeedsMax)
    7716             :             {
    7717          10 :                 std::tie(pos_min, pos_max) = gdal::minmax_element(
    7718           5 :                     pData, static_cast<size_t>(nBlockXSize) * nBlockYSize,
    7719           5 :                     eEffectiveDT, sNoDataValues.bGotNoDataValue,
    7720          10 :                     sNoDataValues.dfNoDataValue);
    7721             :             }
    7722           4 :             else if (bNeedsMin)
    7723             :             {
    7724           1 :                 pos_min = gdal::min_element(
    7725           1 :                     pData, static_cast<size_t>(nBlockXSize) * nBlockYSize,
    7726           1 :                     eEffectiveDT, sNoDataValues.bGotNoDataValue,
    7727             :                     sNoDataValues.dfNoDataValue);
    7728             :             }
    7729           3 :             else if (bNeedsMax)
    7730             :             {
    7731           2 :                 pos_max = gdal::max_element(
    7732           2 :                     pData, static_cast<size_t>(nBlockXSize) * nBlockYSize,
    7733           2 :                     eEffectiveDT, sNoDataValues.bGotNoDataValue,
    7734             :                     sNoDataValues.dfNoDataValue);
    7735             :             }
    7736             : 
    7737           9 :             if (bNeedsMin)
    7738             :             {
    7739           6 :                 const int nMinXBlock = static_cast<int>(pos_min % nBlockXSize);
    7740           6 :                 const int nMinYBlock = static_cast<int>(pos_min / nBlockXSize);
    7741           6 :                 bool bValid = true;
    7742             :                 const double dfMinValueBlock =
    7743           6 :                     GetPixelValue(eDataType, bSignedByte, pData, pos_min,
    7744             :                                   sNoDataValues, bValid);
    7745           6 :                 if (bValid && dfMinValueBlock < dfMin)
    7746             :                 {
    7747           5 :                     dfMin = dfMinValueBlock;
    7748           5 :                     nMinX = iXBlock * nBlockXSize + nMinXBlock;
    7749           5 :                     nMinY = iYBlock * nBlockYSize + nMinYBlock;
    7750             :                 }
    7751             :             }
    7752             : 
    7753           9 :             if (bNeedsMax)
    7754             :             {
    7755           7 :                 const int nMaxXBlock = static_cast<int>(pos_max % nBlockXSize);
    7756           7 :                 const int nMaxYBlock = static_cast<int>(pos_max / nBlockXSize);
    7757           7 :                 bool bValid = true;
    7758             :                 const double dfMaxValueBlock =
    7759           7 :                     GetPixelValue(eDataType, bSignedByte, pData, pos_max,
    7760             :                                   sNoDataValues, bValid);
    7761           7 :                 if (bValid && dfMaxValueBlock > dfMax)
    7762             :                 {
    7763           5 :                     dfMax = dfMaxValueBlock;
    7764           5 :                     nMaxX = iXBlock * nBlockXSize + nMaxXBlock;
    7765           5 :                     nMaxY = iYBlock * nBlockYSize + nMaxYBlock;
    7766             :                 }
    7767             :             }
    7768             :         }
    7769             : 
    7770          11 :         poBlock->DropLock();
    7771             : 
    7772          11 :         if (eDataType == GDT_Byte)
    7773             :         {
    7774          10 :             if (bNeedsMin && dfMin == 0)
    7775             :             {
    7776           1 :                 bNeedsMin = false;
    7777             :             }
    7778          10 :             if (bNeedsMax && dfMax == 255)
    7779             :             {
    7780           4 :                 bNeedsMax = false;
    7781             :             }
    7782          10 :             if (!bNeedsMin && !bNeedsMax)
    7783             :             {
    7784           3 :                 break;
    7785             :             }
    7786             :         }
    7787             :     }
    7788             : 
    7789           8 :     CPLFree(pabyMaskData);
    7790             : 
    7791           8 :     if (pdfMin)
    7792           5 :         *pdfMin = dfMin;
    7793           8 :     if (pdfMax)
    7794           5 :         *pdfMax = dfMax;
    7795           8 :     if (pnMinX)
    7796           6 :         *pnMinX = nMinX;
    7797           8 :     if (pnMinY)
    7798           6 :         *pnMinY = nMinY;
    7799           8 :     if (pnMaxX)
    7800           6 :         *pnMaxX = nMaxX;
    7801           8 :     if (pnMaxY)
    7802           6 :         *pnMaxY = nMaxY;
    7803           8 :     return ((bNeedsMin && nMinX < 0) || (bNeedsMax && nMaxX < 0)) ? CE_Warning
    7804           8 :                                                                   : CE_None;
    7805             : }
    7806             : 
    7807             : /************************************************************************/
    7808             : /*                    GDALComputeRasterMinMaxLocation()                 */
    7809             : /************************************************************************/
    7810             : 
    7811             : /**
    7812             :  * \brief Compute the min/max values for a band, and their location.
    7813             :  *
    7814             :  * @see GDALRasterBand::ComputeRasterMinMax()
    7815             :  * @since GDAL 3.11
    7816             :  */
    7817             : 
    7818           6 : CPLErr GDALComputeRasterMinMaxLocation(GDALRasterBandH hBand, double *pdfMin,
    7819             :                                        double *pdfMax, int *pnMinX, int *pnMinY,
    7820             :                                        int *pnMaxX, int *pnMaxY)
    7821             : 
    7822             : {
    7823           6 :     VALIDATE_POINTER1(hBand, "GDALComputeRasterMinMaxLocation", CE_Failure);
    7824             : 
    7825           6 :     GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
    7826           6 :     return poBand->ComputeRasterMinMaxLocation(pdfMin, pdfMax, pnMinX, pnMinY,
    7827           6 :                                                pnMaxX, pnMaxY);
    7828             : }
    7829             : 
    7830             : /************************************************************************/
    7831             : /*                        SetDefaultHistogram()                         */
    7832             : /************************************************************************/
    7833             : 
    7834             : /* FIXME : add proper documentation */
    7835             : /**
    7836             :  * \brief Set default histogram.
    7837             :  *
    7838             :  * This method is the same as the C function GDALSetDefaultHistogram() and
    7839             :  * GDALSetDefaultHistogramEx()
    7840             :  */
    7841           0 : CPLErr GDALRasterBand::SetDefaultHistogram(double /* dfMin */,
    7842             :                                            double /* dfMax */,
    7843             :                                            int /* nBuckets */,
    7844             :                                            GUIntBig * /* panHistogram */)
    7845             : 
    7846             : {
    7847           0 :     if (!(GetMOFlags() & GMO_IGNORE_UNIMPLEMENTED))
    7848           0 :         ReportError(CE_Failure, CPLE_NotSupported,
    7849             :                     "SetDefaultHistogram() not implemented for this format.");
    7850             : 
    7851           0 :     return CE_Failure;
    7852             : }
    7853             : 
    7854             : /************************************************************************/
    7855             : /*                      GDALSetDefaultHistogram()                       */
    7856             : /************************************************************************/
    7857             : 
    7858             : /**
    7859             :  * \brief Set default histogram.
    7860             :  *
    7861             :  * Use GDALSetRasterHistogramEx() instead to be able to set counts exceeding
    7862             :  * 2 billion.
    7863             :  *
    7864             :  * @see GDALRasterBand::SetDefaultHistogram()
    7865             :  * @see GDALSetRasterHistogramEx()
    7866             :  */
    7867             : 
    7868           0 : CPLErr CPL_STDCALL GDALSetDefaultHistogram(GDALRasterBandH hBand, double dfMin,
    7869             :                                            double dfMax, int nBuckets,
    7870             :                                            int *panHistogram)
    7871             : 
    7872             : {
    7873           0 :     VALIDATE_POINTER1(hBand, "GDALSetDefaultHistogram", CE_Failure);
    7874             : 
    7875           0 :     GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
    7876             : 
    7877             :     GUIntBig *panHistogramTemp =
    7878           0 :         static_cast<GUIntBig *>(VSIMalloc2(sizeof(GUIntBig), nBuckets));
    7879           0 :     if (panHistogramTemp == nullptr)
    7880             :     {
    7881           0 :         poBand->ReportError(CE_Failure, CPLE_OutOfMemory,
    7882             :                             "Out of memory in GDALSetDefaultHistogram().");
    7883           0 :         return CE_Failure;
    7884             :     }
    7885             : 
    7886           0 :     for (int i = 0; i < nBuckets; ++i)
    7887             :     {
    7888           0 :         panHistogramTemp[i] = static_cast<GUIntBig>(panHistogram[i]);
    7889             :     }
    7890             : 
    7891             :     const CPLErr eErr =
    7892           0 :         poBand->SetDefaultHistogram(dfMin, dfMax, nBuckets, panHistogramTemp);
    7893             : 
    7894           0 :     CPLFree(panHistogramTemp);
    7895             : 
    7896           0 :     return eErr;
    7897             : }
    7898             : 
    7899             : /************************************************************************/
    7900             : /*                     GDALSetDefaultHistogramEx()                      */
    7901             : /************************************************************************/
    7902             : 
    7903             : /**
    7904             :  * \brief Set default histogram.
    7905             :  *
    7906             :  * @see GDALRasterBand::SetDefaultHistogram()
    7907             :  *
    7908             :  * @since GDAL 2.0
    7909             :  */
    7910             : 
    7911           5 : CPLErr CPL_STDCALL GDALSetDefaultHistogramEx(GDALRasterBandH hBand,
    7912             :                                              double dfMin, double dfMax,
    7913             :                                              int nBuckets,
    7914             :                                              GUIntBig *panHistogram)
    7915             : 
    7916             : {
    7917           5 :     VALIDATE_POINTER1(hBand, "GDALSetDefaultHistogramEx", CE_Failure);
    7918             : 
    7919           5 :     GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
    7920           5 :     return poBand->SetDefaultHistogram(dfMin, dfMax, nBuckets, panHistogram);
    7921             : }
    7922             : 
    7923             : /************************************************************************/
    7924             : /*                           GetDefaultRAT()                            */
    7925             : /************************************************************************/
    7926             : 
    7927             : /**
    7928             :  * \brief Fetch default Raster Attribute Table.
    7929             :  *
    7930             :  * A RAT will be returned if there is a default one associated with the
    7931             :  * band, otherwise NULL is returned.  The returned RAT is owned by the
    7932             :  * band and should not be deleted by the application.
    7933             :  *
    7934             :  * This method is the same as the C function GDALGetDefaultRAT().
    7935             :  *
    7936             :  * @return NULL, or a pointer to an internal RAT owned by the band.
    7937             :  */
    7938             : 
    7939         112 : GDALRasterAttributeTable *GDALRasterBand::GetDefaultRAT()
    7940             : 
    7941             : {
    7942         112 :     return nullptr;
    7943             : }
    7944             : 
    7945             : /************************************************************************/
    7946             : /*                         GDALGetDefaultRAT()                          */
    7947             : /************************************************************************/
    7948             : 
    7949             : /**
    7950             :  * \brief Fetch default Raster Attribute Table.
    7951             :  *
    7952             :  * @see GDALRasterBand::GetDefaultRAT()
    7953             :  */
    7954             : 
    7955        1000 : GDALRasterAttributeTableH CPL_STDCALL GDALGetDefaultRAT(GDALRasterBandH hBand)
    7956             : 
    7957             : {
    7958        1000 :     VALIDATE_POINTER1(hBand, "GDALGetDefaultRAT", nullptr);
    7959             : 
    7960        1000 :     GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
    7961        1000 :     return GDALRasterAttributeTable::ToHandle(poBand->GetDefaultRAT());
    7962             : }
    7963             : 
    7964             : /************************************************************************/
    7965             : /*                           SetDefaultRAT()                            */
    7966             : /************************************************************************/
    7967             : 
    7968             : /**
    7969             :  * \fn GDALRasterBand::SetDefaultRAT(const GDALRasterAttributeTable*)
    7970             :  * \brief Set default Raster Attribute Table.
    7971             :  *
    7972             :  * Associates a default RAT with the band.  If not implemented for the
    7973             :  * format a CPLE_NotSupported error will be issued.  If successful a copy
    7974             :  * of the RAT is made, the original remains owned by the caller.
    7975             :  *
    7976             :  * This method is the same as the C function GDALSetDefaultRAT().
    7977             :  *
    7978             :  * @param poRAT the RAT to assign to the band.
    7979             :  *
    7980             :  * @return CE_None on success or CE_Failure if unsupported or otherwise
    7981             :  * failing.
    7982             :  */
    7983             : 
    7984             : /**/
    7985             : /**/
    7986             : 
    7987             : CPLErr
    7988           0 : GDALRasterBand::SetDefaultRAT(const GDALRasterAttributeTable * /* poRAT */)
    7989             : {
    7990           0 :     if (!(GetMOFlags() & GMO_IGNORE_UNIMPLEMENTED))
    7991             :     {
    7992           0 :         CPLPushErrorHandler(CPLQuietErrorHandler);
    7993           0 :         ReportError(CE_Failure, CPLE_NotSupported,
    7994             :                     "SetDefaultRAT() not implemented for this format.");
    7995           0 :         CPLPopErrorHandler();
    7996             :     }
    7997           0 :     return CE_Failure;
    7998             : }
    7999             : 
    8000             : /************************************************************************/
    8001             : /*                         GDALSetDefaultRAT()                          */
    8002             : /************************************************************************/
    8003             : 
    8004             : /**
    8005             :  * \brief Set default Raster Attribute Table.
    8006             :  *
    8007             :  * @see GDALRasterBand::GDALSetDefaultRAT()
    8008             :  */
    8009             : 
    8010          18 : CPLErr CPL_STDCALL GDALSetDefaultRAT(GDALRasterBandH hBand,
    8011             :                                      GDALRasterAttributeTableH hRAT)
    8012             : 
    8013             : {
    8014          18 :     VALIDATE_POINTER1(hBand, "GDALSetDefaultRAT", CE_Failure);
    8015             : 
    8016          18 :     GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
    8017             : 
    8018          18 :     return poBand->SetDefaultRAT(GDALRasterAttributeTable::FromHandle(hRAT));
    8019             : }
    8020             : 
    8021             : /************************************************************************/
    8022             : /*                            GetMaskBand()                             */
    8023             : /************************************************************************/
    8024             : 
    8025             : /**
    8026             :  * \brief Return the mask band associated with the band.
    8027             :  *
    8028             :  * The GDALRasterBand class includes a default implementation of GetMaskBand()
    8029             :  * that returns one of four default implementations :
    8030             :  * <ul>
    8031             :  * <li>If a corresponding .msk file exists it will be used for the mask band.
    8032             :  * </li>
    8033             :  * <li>If the dataset has a NODATA_VALUES metadata item, an instance of the new
    8034             :  * GDALNoDataValuesMaskBand class will be returned. GetMaskFlags() will return
    8035             :  * GMF_NODATA | GMF_PER_DATASET.
    8036             :  * </li>
    8037             :  * <li>If the band has a nodata value set, an instance of the new
    8038             :  * GDALNodataMaskRasterBand class will be returned. GetMaskFlags() will return
    8039             :  * GMF_NODATA.
    8040             :  * </li>
    8041             :  * <li>If there is no nodata value, but the dataset has an alpha band that seems
    8042             :  * to apply to this band (specific rules yet to be determined) and that is of
    8043             :  * type GDT_Byte then that alpha band will be returned, and the flags
    8044             :  * GMF_PER_DATASET and GMF_ALPHA will be returned in the flags.
    8045             :  * </li>
    8046             :  * <li>If neither of the above apply, an instance of the new
    8047             :  * GDALAllValidRasterBand class will be returned that has 255 values for all
    8048             :  * pixels. The null flags will return GMF_ALL_VALID.
    8049             :  * </li>
    8050             :  * </ul>
    8051             :  *
    8052             :  * Note that the GetMaskBand() should always return a GDALRasterBand mask, even
    8053             :  * if it is only an all 255 mask with the flags indicating GMF_ALL_VALID.
    8054             :  *
    8055             :  * For an external .msk file to be recognized by GDAL, it must be a valid GDAL
    8056             :  * dataset, with the same name as the main dataset and suffixed with .msk,
    8057             :  * with either one band (in the GMF_PER_DATASET case), or as many bands as the
    8058             :  * main dataset.
    8059             :  * It must have INTERNAL_MASK_FLAGS_xx metadata items set at the dataset
    8060             :  * level, where xx matches the band number of a band of the main dataset. The
    8061             :  * value of those items is a combination of the flags GMF_ALL_VALID,
    8062             :  * GMF_PER_DATASET, GMF_ALPHA and GMF_NODATA. If a metadata item is missing for
    8063             :  * a band, then the other rules explained above will be used to generate a
    8064             :  * on-the-fly mask band.
    8065             :  * \see CreateMaskBand() for the characteristics of .msk files created by GDAL.
    8066             :  *
    8067             :  * This method is the same as the C function GDALGetMaskBand().
    8068             :  *
    8069             :  * @return a valid mask band.
    8070             :  *
    8071             :  * @since GDAL 1.5.0
    8072             :  *
    8073             :  * @see https://gdal.org/development/rfc/rfc15_nodatabitmask.html
    8074             :  *
    8075             :  */
    8076      743315 : GDALRasterBand *GDALRasterBand::GetMaskBand()
    8077             : 
    8078             : {
    8079      179013 :     const auto HasNoData = [this]()
    8080             :     {
    8081       59408 :         int bHaveNoDataRaw = FALSE;
    8082       59408 :         bool bHaveNoData = false;
    8083       59408 :         if (eDataType == GDT_Int64)
    8084             :         {
    8085          56 :             CPL_IGNORE_RET_VAL(GetNoDataValueAsInt64(&bHaveNoDataRaw));
    8086          56 :             bHaveNoData = CPL_TO_BOOL(bHaveNoDataRaw);
    8087             :         }
    8088       59352 :         else if (eDataType == GDT_UInt64)
    8089             :         {
    8090          43 :             CPL_IGNORE_RET_VAL(GetNoDataValueAsUInt64(&bHaveNoDataRaw));
    8091          43 :             bHaveNoData = CPL_TO_BOOL(bHaveNoDataRaw);
    8092             :         }
    8093             :         else
    8094             :         {
    8095       59309 :             const double dfNoDataValue = GetNoDataValue(&bHaveNoDataRaw);
    8096       59240 :             if (bHaveNoDataRaw &&
    8097       59240 :                 GDALNoDataMaskBand::IsNoDataInRange(dfNoDataValue, eDataType))
    8098             :             {
    8099         816 :                 bHaveNoData = true;
    8100             :             }
    8101             :         }
    8102       59173 :         return bHaveNoData;
    8103      743315 :     };
    8104             : 
    8105      743315 :     if (poMask != nullptr)
    8106             :     {
    8107      705473 :         if (poMask.IsOwned())
    8108             :         {
    8109      327554 :             if (dynamic_cast<GDALAllValidMaskBand *>(poMask.get()) != nullptr)
    8110             :             {
    8111       31677 :                 if (HasNoData())
    8112             :                 {
    8113           9 :                     InvalidateMaskBand();
    8114             :                 }
    8115             :             }
    8116      297368 :             else if (auto poNoDataMaskBand =
    8117      297411 :                          dynamic_cast<GDALNoDataMaskBand *>(poMask.get()))
    8118             :             {
    8119         182 :                 int bHaveNoDataRaw = FALSE;
    8120         182 :                 bool bIsSame = false;
    8121         182 :                 if (eDataType == GDT_Int64)
    8122           9 :                     bIsSame = poNoDataMaskBand->m_nNoDataValueInt64 ==
    8123          11 :                                   GetNoDataValueAsInt64(&bHaveNoDataRaw) &&
    8124           2 :                               bHaveNoDataRaw;
    8125         173 :                 else if (eDataType == GDT_UInt64)
    8126           9 :                     bIsSame = poNoDataMaskBand->m_nNoDataValueUInt64 ==
    8127          11 :                                   GetNoDataValueAsUInt64(&bHaveNoDataRaw) &&
    8128           2 :                               bHaveNoDataRaw;
    8129             :                 else
    8130             :                 {
    8131             :                     const double dfNoDataValue =
    8132         164 :                         GetNoDataValue(&bHaveNoDataRaw);
    8133         164 :                     if (bHaveNoDataRaw)
    8134             :                     {
    8135         161 :                         bIsSame =
    8136         161 :                             std::isnan(dfNoDataValue)
    8137         161 :                                 ? std::isnan(poNoDataMaskBand->m_dfNoDataValue)
    8138         135 :                                 : poNoDataMaskBand->m_dfNoDataValue ==
    8139             :                                       dfNoDataValue;
    8140             :                     }
    8141             :                 }
    8142         182 :                 if (!bIsSame)
    8143          23 :                     InvalidateMaskBand();
    8144             :             }
    8145             :         }
    8146             : 
    8147      710853 :         if (poMask)
    8148      712500 :             return poMask.get();
    8149             :     }
    8150             : 
    8151             :     /* -------------------------------------------------------------------- */
    8152             :     /*      Check for a mask in a .msk file.                                */
    8153             :     /* -------------------------------------------------------------------- */
    8154       27837 :     if (poDS != nullptr && poDS->oOvManager.HaveMaskFile())
    8155             :     {
    8156          46 :         poMask.reset(poDS->oOvManager.GetMaskBand(nBand), false);
    8157          46 :         if (poMask != nullptr)
    8158             :         {
    8159          44 :             nMaskFlags = poDS->oOvManager.GetMaskFlags(nBand);
    8160          44 :             return poMask.get();
    8161             :         }
    8162             :     }
    8163             : 
    8164             :     /* -------------------------------------------------------------------- */
    8165             :     /*      Check for NODATA_VALUES metadata.                               */
    8166             :     /* -------------------------------------------------------------------- */
    8167       27792 :     if (poDS != nullptr)
    8168             :     {
    8169             :         const char *pszGDALNoDataValues =
    8170       27777 :             poDS->GetMetadataItem("NODATA_VALUES");
    8171       27777 :         if (pszGDALNoDataValues != nullptr)
    8172             :         {
    8173          56 :             char **papszGDALNoDataValues = CSLTokenizeStringComplex(
    8174             :                 pszGDALNoDataValues, " ", FALSE, FALSE);
    8175             : 
    8176             :             // Make sure we have as many values as bands.
    8177         112 :             if (CSLCount(papszGDALNoDataValues) == poDS->GetRasterCount() &&
    8178          56 :                 poDS->GetRasterCount() != 0)
    8179             :             {
    8180             :                 // Make sure that all bands have the same data type
    8181             :                 // This is clearly not a fundamental condition, just a
    8182             :                 // condition to make implementation easier.
    8183          56 :                 GDALDataType eDT = GDT_Unknown;
    8184          56 :                 int i = 0;  // Used after for.
    8185         224 :                 for (; i < poDS->GetRasterCount(); ++i)
    8186             :                 {
    8187         168 :                     if (i == 0)
    8188          56 :                         eDT = poDS->GetRasterBand(1)->GetRasterDataType();
    8189         112 :                     else if (eDT !=
    8190         112 :                              poDS->GetRasterBand(i + 1)->GetRasterDataType())
    8191             :                     {
    8192           0 :                         break;
    8193             :                     }
    8194             :                 }
    8195          56 :                 if (i == poDS->GetRasterCount())
    8196             :                 {
    8197          56 :                     nMaskFlags = GMF_NODATA | GMF_PER_DATASET;
    8198             :                     try
    8199             :                     {
    8200          56 :                         poMask.reset(new GDALNoDataValuesMaskBand(poDS), true);
    8201             :                     }
    8202           0 :                     catch (const std::bad_alloc &)
    8203             :                     {
    8204           0 :                         CPLError(CE_Failure, CPLE_OutOfMemory, "Out of memory");
    8205           0 :                         poMask.reset();
    8206             :                     }
    8207          56 :                     CSLDestroy(papszGDALNoDataValues);
    8208          56 :                     return poMask.get();
    8209             :                 }
    8210             :                 else
    8211             :                 {
    8212           0 :                     ReportError(CE_Warning, CPLE_AppDefined,
    8213             :                                 "All bands should have the same type in "
    8214             :                                 "order the NODATA_VALUES metadata item "
    8215             :                                 "to be used as a mask.");
    8216             :                 }
    8217             :             }
    8218             :             else
    8219             :             {
    8220           0 :                 ReportError(
    8221             :                     CE_Warning, CPLE_AppDefined,
    8222             :                     "NODATA_VALUES metadata item doesn't have the same number "
    8223             :                     "of values as the number of bands.  "
    8224             :                     "Ignoring it for mask.");
    8225             :             }
    8226             : 
    8227           0 :             CSLDestroy(papszGDALNoDataValues);
    8228             :         }
    8229             :     }
    8230             : 
    8231             :     /* -------------------------------------------------------------------- */
    8232             :     /*      Check for nodata case.                                          */
    8233             :     /* -------------------------------------------------------------------- */
    8234       27736 :     if (HasNoData())
    8235             :     {
    8236         838 :         nMaskFlags = GMF_NODATA;
    8237             :         try
    8238             :         {
    8239         838 :             poMask.reset(new GDALNoDataMaskBand(this), true);
    8240             :         }
    8241           0 :         catch (const std::bad_alloc &)
    8242             :         {
    8243           0 :             CPLError(CE_Failure, CPLE_OutOfMemory, "Out of memory");
    8244           0 :             poMask.reset();
    8245             :         }
    8246         838 :         return poMask.get();
    8247             :     }
    8248             : 
    8249             :     /* -------------------------------------------------------------------- */
    8250             :     /*      Check for alpha case.                                           */
    8251             :     /* -------------------------------------------------------------------- */
    8252       26883 :     if (poDS != nullptr && poDS->GetRasterCount() == 2 &&
    8253       54318 :         this == poDS->GetRasterBand(1) &&
    8254         535 :         poDS->GetRasterBand(2)->GetColorInterpretation() == GCI_AlphaBand)
    8255             :     {
    8256         196 :         if (poDS->GetRasterBand(2)->GetRasterDataType() == GDT_Byte)
    8257             :         {
    8258         152 :             nMaskFlags = GMF_ALPHA | GMF_PER_DATASET;
    8259         152 :             poMask.reset(poDS->GetRasterBand(2), false);
    8260         152 :             return poMask.get();
    8261             :         }
    8262          44 :         else if (poDS->GetRasterBand(2)->GetRasterDataType() == GDT_UInt16)
    8263             :         {
    8264          23 :             nMaskFlags = GMF_ALPHA | GMF_PER_DATASET;
    8265             :             try
    8266             :             {
    8267          23 :                 poMask.reset(new GDALRescaledAlphaBand(poDS->GetRasterBand(2)),
    8268             :                              true);
    8269             :             }
    8270           0 :             catch (const std::bad_alloc &)
    8271             :             {
    8272           0 :                 CPLError(CE_Failure, CPLE_OutOfMemory, "Out of memory");
    8273           0 :                 poMask.reset();
    8274             :             }
    8275          23 :             return poMask.get();
    8276             :         }
    8277             :     }
    8278             : 
    8279       26708 :     if (poDS != nullptr && poDS->GetRasterCount() == 4 &&
    8280        2701 :         (this == poDS->GetRasterBand(1) || this == poDS->GetRasterBand(2) ||
    8281       54073 :          this == poDS->GetRasterBand(3)) &&
    8282        2110 :         poDS->GetRasterBand(4)->GetColorInterpretation() == GCI_AlphaBand)
    8283             :     {
    8284        1224 :         if (poDS->GetRasterBand(4)->GetRasterDataType() == GDT_Byte)
    8285             :         {
    8286        1177 :             nMaskFlags = GMF_ALPHA | GMF_PER_DATASET;
    8287        1177 :             poMask.reset(poDS->GetRasterBand(4), false);
    8288        1177 :             return poMask.get();
    8289             :         }
    8290          47 :         else if (poDS->GetRasterBand(4)->GetRasterDataType() == GDT_UInt16)
    8291             :         {
    8292          35 :             nMaskFlags = GMF_ALPHA | GMF_PER_DATASET;
    8293             :             try
    8294             :             {
    8295          35 :                 poMask.reset(new GDALRescaledAlphaBand(poDS->GetRasterBand(4)),
    8296             :                              true);
    8297             :             }
    8298           0 :             catch (const std::bad_alloc &)
    8299             :             {
    8300           0 :                 CPLError(CE_Failure, CPLE_OutOfMemory, "Out of memory");
    8301           0 :                 poMask.reset();
    8302             :             }
    8303          35 :             return poMask.get();
    8304             :         }
    8305             :     }
    8306             : 
    8307             :     /* -------------------------------------------------------------------- */
    8308             :     /*      Fallback to all valid case.                                     */
    8309             :     /* -------------------------------------------------------------------- */
    8310       25512 :     nMaskFlags = GMF_ALL_VALID;
    8311             :     try
    8312             :     {
    8313       25512 :         poMask.reset(new GDALAllValidMaskBand(this), true);
    8314             :     }
    8315           0 :     catch (const std::bad_alloc &)
    8316             :     {
    8317           0 :         CPLError(CE_Failure, CPLE_OutOfMemory, "Out of memory");
    8318           0 :         poMask.reset();
    8319             :     }
    8320             : 
    8321       25511 :     return poMask.get();
    8322             : }
    8323             : 
    8324             : /************************************************************************/
    8325             : /*                          GDALGetMaskBand()                           */
    8326             : /************************************************************************/
    8327             : 
    8328             : /**
    8329             :  * \brief Return the mask band associated with the band.
    8330             :  *
    8331             :  * @see GDALRasterBand::GetMaskBand()
    8332             :  */
    8333             : 
    8334       10935 : GDALRasterBandH CPL_STDCALL GDALGetMaskBand(GDALRasterBandH hBand)
    8335             : 
    8336             : {
    8337       10935 :     VALIDATE_POINTER1(hBand, "GDALGetMaskBand", nullptr);
    8338             : 
    8339       10935 :     GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
    8340       10935 :     return poBand->GetMaskBand();
    8341             : }
    8342             : 
    8343             : /************************************************************************/
    8344             : /*                            GetMaskFlags()                            */
    8345             : /************************************************************************/
    8346             : 
    8347             : /**
    8348             :  * \brief Return the status flags of the mask band associated with the band.
    8349             :  *
    8350             :  * The GetMaskFlags() method returns an bitwise OR-ed set of status flags with
    8351             :  * the following available definitions that may be extended in the future:
    8352             :  * <ul>
    8353             :  * <li>GMF_ALL_VALID(0x01): There are no invalid pixels, all mask values will be
    8354             :  * 255. When used this will normally be the only flag set.
    8355             :  * </li>
    8356             :  * <li>GMF_PER_DATASET(0x02): The mask band is shared between all bands on the
    8357             :  * dataset.
    8358             :  * </li>
    8359             :  * <li>GMF_ALPHA(0x04): The mask band is actually an alpha band
    8360             :  * and may have values other than 0 and 255.
    8361             :  * </li>
    8362             :  * <li>GMF_NODATA(0x08): Indicates the mask is actually being generated from
    8363             :  * nodata values. (mutually exclusive of GMF_ALPHA)
    8364             :  * </li>
    8365             :  * </ul>
    8366             :  *
    8367             :  * The GDALRasterBand class includes a default implementation of GetMaskBand()
    8368             :  * that returns one of four default implementations:
    8369             :  * <ul>
    8370             :  * <li>If a corresponding .msk file exists it will be used for the mask band.
    8371             :  * </li>
    8372             :  * <li>If the dataset has a NODATA_VALUES metadata item, an instance of the new
    8373             :  * GDALNoDataValuesMaskBand class will be returned. GetMaskFlags() will return
    8374             :  * GMF_NODATA | GMF_PER_DATASET.
    8375             :  * </li>
    8376             :  * <li>If the band has a nodata value set, an instance of the new
    8377             :  * GDALNodataMaskRasterBand class will be returned. GetMaskFlags() will return
    8378             :  * GMF_NODATA.
    8379             :  * </li>
    8380             :  * <li>If there is no nodata value, but the dataset has an alpha band that
    8381             :  * seems to apply to this band (specific rules yet to be determined) and that is
    8382             :  * of type GDT_Byte then that alpha band will be returned, and the flags
    8383             :  * GMF_PER_DATASET and GMF_ALPHA will be returned in the flags.
    8384             :  * </li>
    8385             :  * <li>If neither of the above apply, an instance of the new
    8386             :  * GDALAllValidRasterBand class will be returned that has 255 values for all
    8387             :  * pixels. The null flags will return GMF_ALL_VALID.
    8388             :  * </li>
    8389             :  * </ul>
    8390             :  *
    8391             :  * For an external .msk file to be recognized by GDAL, it must be a valid GDAL
    8392             :  * dataset, with the same name as the main dataset and suffixed with .msk,
    8393             :  * with either one band (in the GMF_PER_DATASET case), or as many bands as the
    8394             :  * main dataset.
    8395             :  * It must have INTERNAL_MASK_FLAGS_xx metadata items set at the dataset
    8396             :  * level, where xx matches the band number of a band of the main dataset. The
    8397             :  * value of those items is a combination of the flags GMF_ALL_VALID,
    8398             :  * GMF_PER_DATASET, GMF_ALPHA and GMF_NODATA. If a metadata item is missing for
    8399             :  * a band, then the other rules explained above will be used to generate a
    8400             :  * on-the-fly mask band.
    8401             :  * \see CreateMaskBand() for the characteristics of .msk files created by GDAL.
    8402             :  *
    8403             :  * This method is the same as the C function GDALGetMaskFlags().
    8404             :  *
    8405             :  * @since GDAL 1.5.0
    8406             :  *
    8407             :  * @return a valid mask band.
    8408             :  *
    8409             :  * @see https://gdal.org/development/rfc/rfc15_nodatabitmask.html
    8410             :  *
    8411             :  */
    8412       79295 : int GDALRasterBand::GetMaskFlags()
    8413             : 
    8414             : {
    8415             :     // If we don't have a band yet, force this now so that the masks value
    8416             :     // will be initialized.
    8417             : 
    8418       79295 :     if (poMask == nullptr)
    8419       26610 :         GetMaskBand();
    8420             : 
    8421       79296 :     return nMaskFlags;
    8422             : }
    8423             : 
    8424             : /************************************************************************/
    8425             : /*                          GDALGetMaskFlags()                          */
    8426             : /************************************************************************/
    8427             : 
    8428             : /**
    8429             :  * \brief Return the status flags of the mask band associated with the band.
    8430             :  *
    8431             :  * @see GDALRasterBand::GetMaskFlags()
    8432             :  */
    8433             : 
    8434        6155 : int CPL_STDCALL GDALGetMaskFlags(GDALRasterBandH hBand)
    8435             : 
    8436             : {
    8437        6155 :     VALIDATE_POINTER1(hBand, "GDALGetMaskFlags", GMF_ALL_VALID);
    8438             : 
    8439        6155 :     GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
    8440        6155 :     return poBand->GetMaskFlags();
    8441             : }
    8442             : 
    8443             : /************************************************************************/
    8444             : /*                         InvalidateMaskBand()                         */
    8445             : /************************************************************************/
    8446             : 
    8447             : //! @cond Doxygen_Suppress
    8448     1201350 : void GDALRasterBand::InvalidateMaskBand()
    8449             : {
    8450     1201350 :     poMask.reset();
    8451     1201320 :     nMaskFlags = 0;
    8452     1201320 : }
    8453             : 
    8454             : //! @endcond
    8455             : 
    8456             : /************************************************************************/
    8457             : /*                           CreateMaskBand()                           */
    8458             : /************************************************************************/
    8459             : 
    8460             : /**
    8461             :  * \brief Adds a mask band to the current band
    8462             :  *
    8463             :  * The default implementation of the CreateMaskBand() method is implemented
    8464             :  * based on similar rules to the .ovr handling implemented using the
    8465             :  * GDALDefaultOverviews object. A TIFF file with the extension .msk will
    8466             :  * be created with the same basename as the original file, and it will have
    8467             :  * as many bands as the original image (or just one for GMF_PER_DATASET).
    8468             :  * The mask images will be deflate compressed tiled images with the same
    8469             :  * block size as the original image if possible.
    8470             :  * It will have INTERNAL_MASK_FLAGS_xx metadata items set at the dataset
    8471             :  * level, where xx matches the band number of a band of the main dataset. The
    8472             :  * value of those items will be the one of the nFlagsIn parameter.
    8473             :  *
    8474             :  * Note that if you got a mask band with a previous call to GetMaskBand(),
    8475             :  * it might be invalidated by CreateMaskBand(). So you have to call
    8476             :  * GetMaskBand() again.
    8477             :  *
    8478             :  * This method is the same as the C function GDALCreateMaskBand().
    8479             :  *
    8480             :  * @since GDAL 1.5.0
    8481             :  *
    8482             :  * @param nFlagsIn 0 or combination of GMF_PER_DATASET / GMF_ALPHA.
    8483             :  *
    8484             :  * @return CE_None on success or CE_Failure on an error.
    8485             :  *
    8486             :  * @see https://gdal.org/development/rfc/rfc15_nodatabitmask.html
    8487             :  * @see GDALDataset::CreateMaskBand()
    8488             :  *
    8489             :  */
    8490             : 
    8491           9 : CPLErr GDALRasterBand::CreateMaskBand(int nFlagsIn)
    8492             : 
    8493             : {
    8494           9 :     if (poDS != nullptr && poDS->oOvManager.IsInitialized())
    8495             :     {
    8496           9 :         const CPLErr eErr = poDS->oOvManager.CreateMaskBand(nFlagsIn, nBand);
    8497           9 :         if (eErr != CE_None)
    8498           1 :             return eErr;
    8499             : 
    8500           8 :         InvalidateMaskBand();
    8501             : 
    8502           8 :         return CE_None;
    8503             :     }
    8504             : 
    8505           0 :     ReportError(CE_Failure, CPLE_NotSupported,
    8506             :                 "CreateMaskBand() not supported for this band.");
    8507             : 
    8508           0 :     return CE_Failure;
    8509             : }
    8510             : 
    8511             : /************************************************************************/
    8512             : /*                         GDALCreateMaskBand()                         */
    8513             : /************************************************************************/
    8514             : 
    8515             : /**
    8516             :  * \brief Adds a mask band to the current band
    8517             :  *
    8518             :  * @see GDALRasterBand::CreateMaskBand()
    8519             :  */
    8520             : 
    8521          33 : CPLErr CPL_STDCALL GDALCreateMaskBand(GDALRasterBandH hBand, int nFlags)
    8522             : 
    8523             : {
    8524          33 :     VALIDATE_POINTER1(hBand, "GDALCreateMaskBand", CE_Failure);
    8525             : 
    8526          33 :     GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
    8527          33 :     return poBand->CreateMaskBand(nFlags);
    8528             : }
    8529             : 
    8530             : /************************************************************************/
    8531             : /*                            IsMaskBand()                              */
    8532             : /************************************************************************/
    8533             : 
    8534             : /**
    8535             :  * \brief Returns whether a band is a mask band.
    8536             :  *
    8537             :  * Mask band must be understood in the broad term: it can be a per-dataset
    8538             :  * mask band, an alpha band, or an implicit mask band.
    8539             :  * Typically the return of GetMaskBand()->IsMaskBand() should be true.
    8540             :  *
    8541             :  * This method is the same as the C function GDALIsMaskBand().
    8542             :  *
    8543             :  * @return true if the band is a mask band.
    8544             :  *
    8545             :  * @see GDALDataset::CreateMaskBand()
    8546             :  *
    8547             :  * @since GDAL 3.5.0
    8548             :  *
    8549             :  */
    8550             : 
    8551         411 : bool GDALRasterBand::IsMaskBand() const
    8552             : {
    8553             :     // The GeoTIFF driver, among others, override this method to
    8554             :     // also handle external .msk bands.
    8555         411 :     return const_cast<GDALRasterBand *>(this)->GetColorInterpretation() ==
    8556         411 :            GCI_AlphaBand;
    8557             : }
    8558             : 
    8559             : /************************************************************************/
    8560             : /*                            GDALIsMaskBand()                          */
    8561             : /************************************************************************/
    8562             : 
    8563             : /**
    8564             :  * \brief Returns whether a band is a mask band.
    8565             :  *
    8566             :  * Mask band must be understood in the broad term: it can be a per-dataset
    8567             :  * mask band, an alpha band, or an implicit mask band.
    8568             :  * Typically the return of GetMaskBand()->IsMaskBand() should be true.
    8569             :  *
    8570             :  * This function is the same as the C++ method GDALRasterBand::IsMaskBand()
    8571             :  *
    8572             :  * @return true if the band is a mask band.
    8573             :  *
    8574             :  * @see GDALRasterBand::IsMaskBand()
    8575             :  *
    8576             :  * @since GDAL 3.5.0
    8577             :  *
    8578             :  */
    8579             : 
    8580          37 : bool GDALIsMaskBand(GDALRasterBandH hBand)
    8581             : 
    8582             : {
    8583          37 :     VALIDATE_POINTER1(hBand, "GDALIsMaskBand", false);
    8584             : 
    8585          37 :     const GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
    8586          37 :     return poBand->IsMaskBand();
    8587             : }
    8588             : 
    8589             : /************************************************************************/
    8590             : /*                         GetMaskValueRange()                          */
    8591             : /************************************************************************/
    8592             : 
    8593             : /**
    8594             :  * \brief Returns the range of values that a mask band can take.
    8595             :  *
    8596             :  * @return the range of values that a mask band can take.
    8597             :  *
    8598             :  * @since GDAL 3.5.0
    8599             :  *
    8600             :  */
    8601             : 
    8602           0 : GDALMaskValueRange GDALRasterBand::GetMaskValueRange() const
    8603             : {
    8604           0 :     return GMVR_UNKNOWN;
    8605             : }
    8606             : 
    8607             : /************************************************************************/
    8608             : /*                    GetIndexColorTranslationTo()                      */
    8609             : /************************************************************************/
    8610             : 
    8611             : /**
    8612             :  * \brief Compute translation table for color tables.
    8613             :  *
    8614             :  * When the raster band has a palette index, it may be useful to compute
    8615             :  * the "translation" of this palette to the palette of another band.
    8616             :  * The translation tries to do exact matching first, and then approximate
    8617             :  * matching if no exact matching is possible.
    8618             :  * This method returns a table such that table[i] = j where i is an index
    8619             :  * of the 'this' rasterband and j the corresponding index for the reference
    8620             :  * rasterband.
    8621             :  *
    8622             :  * This method is thought as internal to GDAL and is used for drivers
    8623             :  * like RPFTOC.
    8624             :  *
    8625             :  * The implementation only supports 1-byte palette rasterbands.
    8626             :  *
    8627             :  * @param poReferenceBand the raster band
    8628             :  * @param pTranslationTable an already allocated translation table (at least 256
    8629             :  * bytes), or NULL to let the method allocate it
    8630             :  * @param pApproximateMatching a pointer to a flag that is set if the matching
    8631             :  *                              is approximate. May be NULL.
    8632             :  *
    8633             :  * @return a translation table if the two bands are palette index and that they
    8634             :  * do not match or NULL in other cases. The table must be freed with CPLFree if
    8635             :  * NULL was passed for pTranslationTable.
    8636             :  */
    8637             : 
    8638             : unsigned char *
    8639           5 : GDALRasterBand::GetIndexColorTranslationTo(GDALRasterBand *poReferenceBand,
    8640             :                                            unsigned char *pTranslationTable,
    8641             :                                            int *pApproximateMatching)
    8642             : {
    8643           5 :     if (poReferenceBand == nullptr)
    8644           0 :         return nullptr;
    8645             : 
    8646             :     // cppcheck-suppress knownConditionTrueFalse
    8647           5 :     if (poReferenceBand->GetColorInterpretation() == GCI_PaletteIndex &&
    8648             :         // cppcheck-suppress knownConditionTrueFalse
    8649           5 :         GetColorInterpretation() == GCI_PaletteIndex &&
    8650          15 :         poReferenceBand->GetRasterDataType() == GDT_Byte &&
    8651           5 :         GetRasterDataType() == GDT_Byte)
    8652             :     {
    8653           5 :         const GDALColorTable *srcColorTable = GetColorTable();
    8654           5 :         GDALColorTable *destColorTable = poReferenceBand->GetColorTable();
    8655           5 :         if (srcColorTable != nullptr && destColorTable != nullptr)
    8656             :         {
    8657           5 :             const int nEntries = srcColorTable->GetColorEntryCount();
    8658           5 :             const int nRefEntries = destColorTable->GetColorEntryCount();
    8659             : 
    8660           5 :             int bHasNoDataValueSrc = FALSE;
    8661           5 :             double dfNoDataValueSrc = GetNoDataValue(&bHasNoDataValueSrc);
    8662           5 :             if (!(bHasNoDataValueSrc && dfNoDataValueSrc >= 0 &&
    8663           4 :                   dfNoDataValueSrc <= 255 &&
    8664           4 :                   dfNoDataValueSrc == static_cast<int>(dfNoDataValueSrc)))
    8665           1 :                 bHasNoDataValueSrc = FALSE;
    8666           5 :             const int noDataValueSrc =
    8667           5 :                 bHasNoDataValueSrc ? static_cast<int>(dfNoDataValueSrc) : 0;
    8668             : 
    8669           5 :             int bHasNoDataValueRef = FALSE;
    8670             :             const double dfNoDataValueRef =
    8671           5 :                 poReferenceBand->GetNoDataValue(&bHasNoDataValueRef);
    8672           5 :             if (!(bHasNoDataValueRef && dfNoDataValueRef >= 0 &&
    8673           3 :                   dfNoDataValueRef <= 255 &&
    8674           3 :                   dfNoDataValueRef == static_cast<int>(dfNoDataValueRef)))
    8675           2 :                 bHasNoDataValueRef = FALSE;
    8676           5 :             const int noDataValueRef =
    8677           5 :                 bHasNoDataValueRef ? static_cast<int>(dfNoDataValueRef) : 0;
    8678             : 
    8679           5 :             bool samePalette = false;
    8680             : 
    8681           5 :             if (pApproximateMatching)
    8682           3 :                 *pApproximateMatching = FALSE;
    8683             : 
    8684           5 :             if (nEntries == nRefEntries &&
    8685           4 :                 bHasNoDataValueSrc == bHasNoDataValueRef &&
    8686           4 :                 (bHasNoDataValueSrc == FALSE ||
    8687             :                  noDataValueSrc == noDataValueRef))
    8688             :             {
    8689           4 :                 samePalette = true;
    8690         911 :                 for (int i = 0; i < nEntries; ++i)
    8691             :                 {
    8692         907 :                     if (noDataValueSrc == i)
    8693           4 :                         continue;
    8694             :                     const GDALColorEntry *entry =
    8695         903 :                         srcColorTable->GetColorEntry(i);
    8696             :                     const GDALColorEntry *entryRef =
    8697         903 :                         destColorTable->GetColorEntry(i);
    8698         903 :                     if (entry->c1 != entryRef->c1 ||
    8699         903 :                         entry->c2 != entryRef->c2 || entry->c3 != entryRef->c3)
    8700             :                     {
    8701           0 :                         samePalette = false;
    8702             :                     }
    8703             :                 }
    8704             :             }
    8705             : 
    8706           5 :             if (!samePalette)
    8707             :             {
    8708           1 :                 if (pTranslationTable == nullptr)
    8709             :                 {
    8710             :                     pTranslationTable = static_cast<unsigned char *>(
    8711           1 :                         VSI_CALLOC_VERBOSE(1, std::max(256, nEntries)));
    8712           1 :                     if (pTranslationTable == nullptr)
    8713           1 :                         return nullptr;
    8714             :                 }
    8715             : 
    8716             :                 // Trying to remap the product palette on the subdataset
    8717             :                 // palette.
    8718           5 :                 for (int i = 0; i < nEntries; ++i)
    8719             :                 {
    8720           4 :                     if (bHasNoDataValueSrc && bHasNoDataValueRef &&
    8721             :                         noDataValueSrc == i)
    8722           0 :                         continue;
    8723             :                     const GDALColorEntry *entry =
    8724           4 :                         srcColorTable->GetColorEntry(i);
    8725           4 :                     bool bMatchFound = false;
    8726          13 :                     for (int j = 0; j < nRefEntries; ++j)
    8727             :                     {
    8728          10 :                         if (bHasNoDataValueRef && noDataValueRef == j)
    8729           0 :                             continue;
    8730             :                         const GDALColorEntry *entryRef =
    8731          10 :                             destColorTable->GetColorEntry(j);
    8732          10 :                         if (entry->c1 == entryRef->c1 &&
    8733           2 :                             entry->c2 == entryRef->c2 &&
    8734           2 :                             entry->c3 == entryRef->c3)
    8735             :                         {
    8736           1 :                             pTranslationTable[i] =
    8737             :                                 static_cast<unsigned char>(j);
    8738           1 :                             bMatchFound = true;
    8739           1 :                             break;
    8740             :                         }
    8741             :                     }
    8742           4 :                     if (!bMatchFound)
    8743             :                     {
    8744             :                         // No exact match. Looking for closest color now.
    8745           3 :                         int best_j = 0;
    8746           3 :                         int best_distance = 0;
    8747           3 :                         if (pApproximateMatching)
    8748           0 :                             *pApproximateMatching = TRUE;
    8749          12 :                         for (int j = 0; j < nRefEntries; ++j)
    8750             :                         {
    8751             :                             const GDALColorEntry *entryRef =
    8752           9 :                                 destColorTable->GetColorEntry(j);
    8753           9 :                             int distance = (entry->c1 - entryRef->c1) *
    8754           9 :                                                (entry->c1 - entryRef->c1) +
    8755           9 :                                            (entry->c2 - entryRef->c2) *
    8756           9 :                                                (entry->c2 - entryRef->c2) +
    8757           9 :                                            (entry->c3 - entryRef->c3) *
    8758           9 :                                                (entry->c3 - entryRef->c3);
    8759           9 :                             if (j == 0 || distance < best_distance)
    8760             :                             {
    8761           7 :                                 best_j = j;
    8762           7 :                                 best_distance = distance;
    8763             :                             }
    8764             :                         }
    8765           3 :                         pTranslationTable[i] =
    8766             :                             static_cast<unsigned char>(best_j);
    8767             :                     }
    8768             :                 }
    8769           1 :                 if (bHasNoDataValueRef && bHasNoDataValueSrc)
    8770           0 :                     pTranslationTable[noDataValueSrc] =
    8771             :                         static_cast<unsigned char>(noDataValueRef);
    8772             : 
    8773           1 :                 return pTranslationTable;
    8774             :             }
    8775             :         }
    8776             :     }
    8777           4 :     return nullptr;
    8778             : }
    8779             : 
    8780             : /************************************************************************/
    8781             : /*                         SetFlushBlockErr()                           */
    8782             : /************************************************************************/
    8783             : 
    8784             : /**
    8785             :  * \brief Store that an error occurred while writing a dirty block.
    8786             :  *
    8787             :  * This function stores the fact that an error occurred while writing a dirty
    8788             :  * block from GDALRasterBlock::FlushCacheBlock(). Indeed when dirty blocks are
    8789             :  * flushed when the block cache get full, it is not convenient/possible to
    8790             :  * report that a dirty block could not be written correctly. This function
    8791             :  * remembers the error and re-issue it from GDALRasterBand::FlushCache(),
    8792             :  * GDALRasterBand::WriteBlock() and GDALRasterBand::RasterIO(), which are
    8793             :  * places where the user can easily match the error with the relevant dataset.
    8794             :  */
    8795             : 
    8796           0 : void GDALRasterBand::SetFlushBlockErr(CPLErr eErr)
    8797             : {
    8798           0 :     eFlushBlockErr = eErr;
    8799           0 : }
    8800             : 
    8801             : /************************************************************************/
    8802             : /*                         IncDirtyBlocks()                             */
    8803             : /************************************************************************/
    8804             : 
    8805             : /**
    8806             :  * \brief Increment/decrement the number of dirty blocks
    8807             :  */
    8808             : 
    8809      520416 : void GDALRasterBand::IncDirtyBlocks(int nInc)
    8810             : {
    8811      520416 :     if (poBandBlockCache)
    8812      520415 :         poBandBlockCache->IncDirtyBlocks(nInc);
    8813      520434 : }
    8814             : 
    8815             : /************************************************************************/
    8816             : /*                            ReportError()                             */
    8817             : /************************************************************************/
    8818             : 
    8819             : #ifndef DOXYGEN_XML
    8820             : /**
    8821             :  * \brief Emits an error related to a raster band.
    8822             :  *
    8823             :  * This function is a wrapper for regular CPLError(). The only difference
    8824             :  * with CPLError() is that it prepends the error message with the dataset
    8825             :  * name and the band number.
    8826             :  *
    8827             :  * @param eErrClass one of CE_Warning, CE_Failure or CE_Fatal.
    8828             :  * @param err_no the error number (CPLE_*) from cpl_error.h.
    8829             :  * @param fmt a printf() style format string.  Any additional arguments
    8830             :  * will be treated as arguments to fill in this format in a manner
    8831             :  * similar to printf().
    8832             :  *
    8833             :  * @since GDAL 1.9.0
    8834             :  */
    8835             : 
    8836        2448 : void GDALRasterBand::ReportError(CPLErr eErrClass, CPLErrorNum err_no,
    8837             :                                  const char *fmt, ...) const
    8838             : {
    8839             :     va_list args;
    8840             : 
    8841        2448 :     va_start(args, fmt);
    8842             : 
    8843        2448 :     const char *pszDSName = poDS ? poDS->GetDescription() : "";
    8844        2448 :     pszDSName = CPLGetFilename(pszDSName);
    8845        2448 :     if (pszDSName[0] != '\0')
    8846             :     {
    8847        2392 :         CPLError(eErrClass, err_no, "%s",
    8848        4784 :                  CPLString()
    8849        2392 :                      .Printf("%s, band %d: ", pszDSName, GetBand())
    8850        4784 :                      .append(CPLString().vPrintf(fmt, args))
    8851             :                      .c_str());
    8852             :     }
    8853             :     else
    8854             :     {
    8855          56 :         CPLErrorV(eErrClass, err_no, fmt, args);
    8856             :     }
    8857             : 
    8858        2448 :     va_end(args);
    8859        2448 : }
    8860             : #endif
    8861             : 
    8862             : /************************************************************************/
    8863             : /*                           GetVirtualMemAuto()                        */
    8864             : /************************************************************************/
    8865             : 
    8866             : /** \brief Create a CPLVirtualMem object from a GDAL raster band object.
    8867             :  *
    8868             :  * Only supported on Linux and Unix systems with mmap() for now.
    8869             :  *
    8870             :  * This method allows creating a virtual memory object for a GDALRasterBand,
    8871             :  * that exposes the whole image data as a virtual array.
    8872             :  *
    8873             :  * The default implementation relies on GDALRasterBandGetVirtualMem(), but
    8874             :  * specialized implementation, such as for raw files, may also directly use
    8875             :  * mechanisms of the operating system to create a view of the underlying file
    8876             :  * into virtual memory ( CPLVirtualMemFileMapNew() )
    8877             :  *
    8878             :  * At the time of writing, the GeoTIFF driver and "raw" drivers (EHdr, ...)
    8879             :  * offer a specialized implementation with direct file mapping, provided that
    8880             :  * some requirements are met :
    8881             :  *   - for all drivers, the dataset must be backed by a "real" file in the file
    8882             :  *     system, and the byte ordering of multi-byte datatypes (Int16, etc.)
    8883             :  *     must match the native ordering of the CPU.
    8884             :  *   - in addition, for the GeoTIFF driver, the GeoTIFF file must be
    8885             :  * uncompressed, scanline oriented (i.e. not tiled). Strips must be organized in
    8886             :  * the file in sequential order, and be equally spaced (which is generally the
    8887             :  * case). Only power-of-two bit depths are supported (8 for GDT_Bye, 16 for
    8888             :  * GDT_Int16/GDT_UInt16/GDT_Float16, 32 for GDT_Float32 and 64 for GDT_Float64)
    8889             :  *
    8890             :  * The pointer returned remains valid until CPLVirtualMemFree() is called.
    8891             :  * CPLVirtualMemFree() must be called before the raster band object is
    8892             :  * destroyed.
    8893             :  *
    8894             :  * If p is such a pointer and base_type the type matching
    8895             :  * GDALGetRasterDataType(), the element of image coordinates (x, y) can be
    8896             :  * accessed with
    8897             :  * *(base_type*) ((GByte*)p + x * *pnPixelSpace + y * *pnLineSpace)
    8898             :  *
    8899             :  * This method is the same as the C GDALGetVirtualMemAuto() function.
    8900             :  *
    8901             :  * @param eRWFlag Either GF_Read to read the band, or GF_Write to
    8902             :  * read/write the band.
    8903             :  *
    8904             :  * @param pnPixelSpace Output parameter giving the byte offset from the start of
    8905             :  * one pixel value in the buffer to the start of the next pixel value within a
    8906             :  * scanline.
    8907             :  *
    8908             :  * @param pnLineSpace Output parameter giving the byte offset from the start of
    8909             :  * one scanline in the buffer to the start of the next.
    8910             :  *
    8911             :  * @param papszOptions NULL terminated list of options.
    8912             :  *                     If a specialized implementation exists, defining
    8913             :  * USE_DEFAULT_IMPLEMENTATION=YES will cause the default implementation to be
    8914             :  * used. On the contrary, starting with GDAL 2.2, defining
    8915             :  * USE_DEFAULT_IMPLEMENTATION=NO will prevent the default implementation from
    8916             :  * being used (thus only allowing efficient implementations to be used). When
    8917             :  * requiring or falling back to the default implementation, the following
    8918             :  *                     options are available : CACHE_SIZE (in bytes, defaults to
    8919             :  * 40 MB), PAGE_SIZE_HINT (in bytes), SINGLE_THREAD ("FALSE" / "TRUE", defaults
    8920             :  * to FALSE)
    8921             :  *
    8922             :  * @return a virtual memory object that must be unreferenced by
    8923             :  * CPLVirtualMemFree(), or NULL in case of failure.
    8924             :  *
    8925             :  * @since GDAL 1.11
    8926             :  */
    8927             : 
    8928           9 : CPLVirtualMem *GDALRasterBand::GetVirtualMemAuto(GDALRWFlag eRWFlag,
    8929             :                                                  int *pnPixelSpace,
    8930             :                                                  GIntBig *pnLineSpace,
    8931             :                                                  char **papszOptions)
    8932             : {
    8933           9 :     const char *pszImpl = CSLFetchNameValueDef(
    8934             :         papszOptions, "USE_DEFAULT_IMPLEMENTATION", "AUTO");
    8935           9 :     if (EQUAL(pszImpl, "NO") || EQUAL(pszImpl, "OFF") || EQUAL(pszImpl, "0") ||
    8936           8 :         EQUAL(pszImpl, "FALSE"))
    8937             :     {
    8938           1 :         return nullptr;
    8939             :     }
    8940             : 
    8941           8 :     const int nPixelSpace = GDALGetDataTypeSizeBytes(eDataType);
    8942           8 :     const GIntBig nLineSpace = static_cast<GIntBig>(nRasterXSize) * nPixelSpace;
    8943           8 :     if (pnPixelSpace)
    8944           8 :         *pnPixelSpace = nPixelSpace;
    8945           8 :     if (pnLineSpace)
    8946           8 :         *pnLineSpace = nLineSpace;
    8947             :     const size_t nCacheSize =
    8948           8 :         atoi(CSLFetchNameValueDef(papszOptions, "CACHE_SIZE", "40000000"));
    8949             :     const size_t nPageSizeHint =
    8950           8 :         atoi(CSLFetchNameValueDef(papszOptions, "PAGE_SIZE_HINT", "0"));
    8951           8 :     const bool bSingleThreadUsage = CPLTestBool(
    8952             :         CSLFetchNameValueDef(papszOptions, "SINGLE_THREAD", "FALSE"));
    8953           8 :     return GDALRasterBandGetVirtualMem(
    8954             :         GDALRasterBand::ToHandle(this), eRWFlag, 0, 0, nRasterXSize,
    8955             :         nRasterYSize, nRasterXSize, nRasterYSize, eDataType, nPixelSpace,
    8956             :         nLineSpace, nCacheSize, nPageSizeHint, bSingleThreadUsage,
    8957           8 :         papszOptions);
    8958             : }
    8959             : 
    8960             : /************************************************************************/
    8961             : /*                         GDALGetVirtualMemAuto()                      */
    8962             : /************************************************************************/
    8963             : 
    8964             : /**
    8965             :  * \brief Create a CPLVirtualMem object from a GDAL raster band object.
    8966             :  *
    8967             :  * @see GDALRasterBand::GetVirtualMemAuto()
    8968             :  */
    8969             : 
    8970          31 : CPLVirtualMem *GDALGetVirtualMemAuto(GDALRasterBandH hBand, GDALRWFlag eRWFlag,
    8971             :                                      int *pnPixelSpace, GIntBig *pnLineSpace,
    8972             :                                      CSLConstList papszOptions)
    8973             : {
    8974          31 :     VALIDATE_POINTER1(hBand, "GDALGetVirtualMemAuto", nullptr);
    8975             : 
    8976          31 :     GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
    8977             : 
    8978          31 :     return poBand->GetVirtualMemAuto(eRWFlag, pnPixelSpace, pnLineSpace,
    8979          31 :                                      const_cast<char **>(papszOptions));
    8980             : }
    8981             : 
    8982             : /************************************************************************/
    8983             : /*                        GDALGetDataCoverageStatus()                   */
    8984             : /************************************************************************/
    8985             : 
    8986             : /**
    8987             :  * \brief Get the coverage status of a sub-window of the raster.
    8988             :  *
    8989             :  * Returns whether a sub-window of the raster contains only data, only empty
    8990             :  * blocks or a mix of both. This function can be used to determine quickly
    8991             :  * if it is worth issuing RasterIO / ReadBlock requests in datasets that may
    8992             :  * be sparse.
    8993             :  *
    8994             :  * Empty blocks are blocks that are generally not physically present in the
    8995             :  * file, and when read through GDAL, contain only pixels whose value is the
    8996             :  * nodata value when it is set, or whose value is 0 when the nodata value is
    8997             :  * not set.
    8998             :  *
    8999             :  * The query is done in an efficient way without reading the actual pixel
    9000             :  * values. If not possible, or not implemented at all by the driver,
    9001             :  * GDAL_DATA_COVERAGE_STATUS_UNIMPLEMENTED | GDAL_DATA_COVERAGE_STATUS_DATA will
    9002             :  * be returned.
    9003             :  *
    9004             :  * The values that can be returned by the function are the following,
    9005             :  * potentially combined with the binary or operator :
    9006             :  * <ul>
    9007             :  * <li>GDAL_DATA_COVERAGE_STATUS_UNIMPLEMENTED : the driver does not implement
    9008             :  * GetDataCoverageStatus(). This flag should be returned together with
    9009             :  * GDAL_DATA_COVERAGE_STATUS_DATA.</li>
    9010             :  * <li>GDAL_DATA_COVERAGE_STATUS_DATA: There is (potentially) data in the
    9011             :  * queried window.</li> <li>GDAL_DATA_COVERAGE_STATUS_EMPTY: There is nodata in
    9012             :  * the queried window. This is typically identified by the concept of missing
    9013             :  * block in formats that supports it.
    9014             :  * </li>
    9015             :  * </ul>
    9016             :  *
    9017             :  * Note that GDAL_DATA_COVERAGE_STATUS_DATA might have false positives and
    9018             :  * should be interpreted more as hint of potential presence of data. For example
    9019             :  * if a GeoTIFF file is created with blocks filled with zeroes (or set to the
    9020             :  * nodata value), instead of using the missing block mechanism,
    9021             :  * GDAL_DATA_COVERAGE_STATUS_DATA will be returned. On the contrary,
    9022             :  * GDAL_DATA_COVERAGE_STATUS_EMPTY should have no false positives.
    9023             :  *
    9024             :  * The nMaskFlagStop should be generally set to 0. It can be set to a
    9025             :  * binary-or'ed mask of the above mentioned values to enable a quick exiting of
    9026             :  * the function as soon as the computed mask matches the nMaskFlagStop. For
    9027             :  * example, you can issue a request on the whole raster with nMaskFlagStop =
    9028             :  * GDAL_DATA_COVERAGE_STATUS_EMPTY. As soon as one missing block is encountered,
    9029             :  * the function will exit, so that you can potentially refine the requested area
    9030             :  * to find which particular region(s) have missing blocks.
    9031             :  *
    9032             :  * @see GDALRasterBand::GetDataCoverageStatus()
    9033             :  *
    9034             :  * @param hBand raster band
    9035             :  *
    9036             :  * @param nXOff The pixel offset to the top left corner of the region
    9037             :  * of the band to be queried. This would be zero to start from the left side.
    9038             :  *
    9039             :  * @param nYOff The line offset to the top left corner of the region
    9040             :  * of the band to be queried. This would be zero to start from the top.
    9041             :  *
    9042             :  * @param nXSize The width of the region of the band to be queried in pixels.
    9043             :  *
    9044             :  * @param nYSize The height of the region of the band to be queried in lines.
    9045             :  *
    9046             :  * @param nMaskFlagStop 0, or a binary-or'ed mask of possible values
    9047             :  * GDAL_DATA_COVERAGE_STATUS_UNIMPLEMENTED,
    9048             :  * GDAL_DATA_COVERAGE_STATUS_DATA and GDAL_DATA_COVERAGE_STATUS_EMPTY. As soon
    9049             :  * as the computation of the coverage matches the mask, the computation will be
    9050             :  * stopped. *pdfDataPct will not be valid in that case.
    9051             :  *
    9052             :  * @param pdfDataPct Optional output parameter whose pointed value will be set
    9053             :  * to the (approximate) percentage in [0,100] of pixels in the queried
    9054             :  * sub-window that have valid values. The implementation might not always be
    9055             :  * able to compute it, in which case it will be set to a negative value.
    9056             :  *
    9057             :  * @return a binary-or'ed combination of possible values
    9058             :  * GDAL_DATA_COVERAGE_STATUS_UNIMPLEMENTED,
    9059             :  * GDAL_DATA_COVERAGE_STATUS_DATA and GDAL_DATA_COVERAGE_STATUS_EMPTY
    9060             :  *
    9061             :  * @note Added in GDAL 2.2
    9062             :  */
    9063             : 
    9064          26 : int CPL_STDCALL GDALGetDataCoverageStatus(GDALRasterBandH hBand, int nXOff,
    9065             :                                           int nYOff, int nXSize, int nYSize,
    9066             :                                           int nMaskFlagStop, double *pdfDataPct)
    9067             : {
    9068          26 :     VALIDATE_POINTER1(hBand, "GDALGetDataCoverageStatus",
    9069             :                       GDAL_DATA_COVERAGE_STATUS_UNIMPLEMENTED);
    9070             : 
    9071          26 :     GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
    9072             : 
    9073          26 :     return poBand->GetDataCoverageStatus(nXOff, nYOff, nXSize, nYSize,
    9074          26 :                                          nMaskFlagStop, pdfDataPct);
    9075             : }
    9076             : 
    9077             : /************************************************************************/
    9078             : /*                          GetDataCoverageStatus()                     */
    9079             : /************************************************************************/
    9080             : 
    9081             : /**
    9082             :  * \fn GDALRasterBand::IGetDataCoverageStatus( int nXOff,
    9083             :  *                                           int nYOff,
    9084             :  *                                           int nXSize,
    9085             :  *                                           int nYSize,
    9086             :  *                                           int nMaskFlagStop,
    9087             :  *                                           double* pdfDataPct)
    9088             :  * \brief Get the coverage status of a sub-window of the raster.
    9089             :  *
    9090             :  * Returns whether a sub-window of the raster contains only data, only empty
    9091             :  * blocks or a mix of both. This function can be used to determine quickly
    9092             :  * if it is worth issuing RasterIO / ReadBlock requests in datasets that may
    9093             :  * be sparse.
    9094             :  *
    9095             :  * Empty blocks are blocks that contain only pixels whose value is the nodata
    9096             :  * value when it is set, or whose value is 0 when the nodata value is not set.
    9097             :  *
    9098             :  * The query is done in an efficient way without reading the actual pixel
    9099             :  * values. If not possible, or not implemented at all by the driver,
    9100             :  * GDAL_DATA_COVERAGE_STATUS_UNIMPLEMENTED | GDAL_DATA_COVERAGE_STATUS_DATA will
    9101             :  * be returned.
    9102             :  *
    9103             :  * The values that can be returned by the function are the following,
    9104             :  * potentially combined with the binary or operator :
    9105             :  * <ul>
    9106             :  * <li>GDAL_DATA_COVERAGE_STATUS_UNIMPLEMENTED : the driver does not implement
    9107             :  * GetDataCoverageStatus(). This flag should be returned together with
    9108             :  * GDAL_DATA_COVERAGE_STATUS_DATA.</li>
    9109             :  * <li>GDAL_DATA_COVERAGE_STATUS_DATA: There is (potentially) data in the
    9110             :  * queried window.</li> <li>GDAL_DATA_COVERAGE_STATUS_EMPTY: There is nodata in
    9111             :  * the queried window. This is typically identified by the concept of missing
    9112             :  * block in formats that supports it.
    9113             :  * </li>
    9114             :  * </ul>
    9115             :  *
    9116             :  * Note that GDAL_DATA_COVERAGE_STATUS_DATA might have false positives and
    9117             :  * should be interpreted more as hint of potential presence of data. For example
    9118             :  * if a GeoTIFF file is created with blocks filled with zeroes (or set to the
    9119             :  * nodata value), instead of using the missing block mechanism,
    9120             :  * GDAL_DATA_COVERAGE_STATUS_DATA will be returned. On the contrary,
    9121             :  * GDAL_DATA_COVERAGE_STATUS_EMPTY should have no false positives.
    9122             :  *
    9123             :  * The nMaskFlagStop should be generally set to 0. It can be set to a
    9124             :  * binary-or'ed mask of the above mentioned values to enable a quick exiting of
    9125             :  * the function as soon as the computed mask matches the nMaskFlagStop. For
    9126             :  * example, you can issue a request on the whole raster with nMaskFlagStop =
    9127             :  * GDAL_DATA_COVERAGE_STATUS_EMPTY. As soon as one missing block is encountered,
    9128             :  * the function will exit, so that you can potentially refine the requested area
    9129             :  * to find which particular region(s) have missing blocks.
    9130             :  *
    9131             :  * @see GDALGetDataCoverageStatus()
    9132             :  *
    9133             :  * @param nXOff The pixel offset to the top left corner of the region
    9134             :  * of the band to be queried. This would be zero to start from the left side.
    9135             :  *
    9136             :  * @param nYOff The line offset to the top left corner of the region
    9137             :  * of the band to be queried. This would be zero to start from the top.
    9138             :  *
    9139             :  * @param nXSize The width of the region of the band to be queried in pixels.
    9140             :  *
    9141             :  * @param nYSize The height of the region of the band to be queried in lines.
    9142             :  *
    9143             :  * @param nMaskFlagStop 0, or a binary-or'ed mask of possible values
    9144             :  * GDAL_DATA_COVERAGE_STATUS_UNIMPLEMENTED,
    9145             :  * GDAL_DATA_COVERAGE_STATUS_DATA and GDAL_DATA_COVERAGE_STATUS_EMPTY. As soon
    9146             :  * as the computation of the coverage matches the mask, the computation will be
    9147             :  * stopped. *pdfDataPct will not be valid in that case.
    9148             :  *
    9149             :  * @param pdfDataPct Optional output parameter whose pointed value will be set
    9150             :  * to the (approximate) percentage in [0,100] of pixels in the queried
    9151             :  * sub-window that have valid values. The implementation might not always be
    9152             :  * able to compute it, in which case it will be set to a negative value.
    9153             :  *
    9154             :  * @return a binary-or'ed combination of possible values
    9155             :  * GDAL_DATA_COVERAGE_STATUS_UNIMPLEMENTED,
    9156             :  * GDAL_DATA_COVERAGE_STATUS_DATA and GDAL_DATA_COVERAGE_STATUS_EMPTY
    9157             :  *
    9158             :  * @note Added in GDAL 2.2
    9159             :  */
    9160             : 
    9161             : /**
    9162             :  * \brief Get the coverage status of a sub-window of the raster.
    9163             :  *
    9164             :  * Returns whether a sub-window of the raster contains only data, only empty
    9165             :  * blocks or a mix of both. This function can be used to determine quickly
    9166             :  * if it is worth issuing RasterIO / ReadBlock requests in datasets that may
    9167             :  * be sparse.
    9168             :  *
    9169             :  * Empty blocks are blocks that contain only pixels whose value is the nodata
    9170             :  * value when it is set, or whose value is 0 when the nodata value is not set.
    9171             :  *
    9172             :  * The query is done in an efficient way without reading the actual pixel
    9173             :  * values. If not possible, or not implemented at all by the driver,
    9174             :  * GDAL_DATA_COVERAGE_STATUS_UNIMPLEMENTED | GDAL_DATA_COVERAGE_STATUS_DATA will
    9175             :  * be returned.
    9176             :  *
    9177             :  * The values that can be returned by the function are the following,
    9178             :  * potentially combined with the binary or operator :
    9179             :  * <ul>
    9180             :  * <li>GDAL_DATA_COVERAGE_STATUS_UNIMPLEMENTED : the driver does not implement
    9181             :  * GetDataCoverageStatus(). This flag should be returned together with
    9182             :  * GDAL_DATA_COVERAGE_STATUS_DATA.</li>
    9183             :  * <li>GDAL_DATA_COVERAGE_STATUS_DATA: There is (potentially) data in the
    9184             :  * queried window.</li> <li>GDAL_DATA_COVERAGE_STATUS_EMPTY: There is nodata in
    9185             :  * the queried window. This is typically identified by the concept of missing
    9186             :  * block in formats that supports it.
    9187             :  * </li>
    9188             :  * </ul>
    9189             :  *
    9190             :  * Note that GDAL_DATA_COVERAGE_STATUS_DATA might have false positives and
    9191             :  * should be interpreted more as hint of potential presence of data. For example
    9192             :  * if a GeoTIFF file is created with blocks filled with zeroes (or set to the
    9193             :  * nodata value), instead of using the missing block mechanism,
    9194             :  * GDAL_DATA_COVERAGE_STATUS_DATA will be returned. On the contrary,
    9195             :  * GDAL_DATA_COVERAGE_STATUS_EMPTY should have no false positives.
    9196             :  *
    9197             :  * The nMaskFlagStop should be generally set to 0. It can be set to a
    9198             :  * binary-or'ed mask of the above mentioned values to enable a quick exiting of
    9199             :  * the function as soon as the computed mask matches the nMaskFlagStop. For
    9200             :  * example, you can issue a request on the whole raster with nMaskFlagStop =
    9201             :  * GDAL_DATA_COVERAGE_STATUS_EMPTY. As soon as one missing block is encountered,
    9202             :  * the function will exit, so that you can potentially refine the requested area
    9203             :  * to find which particular region(s) have missing blocks.
    9204             :  *
    9205             :  * @see GDALGetDataCoverageStatus()
    9206             :  *
    9207             :  * @param nXOff The pixel offset to the top left corner of the region
    9208             :  * of the band to be queried. This would be zero to start from the left side.
    9209             :  *
    9210             :  * @param nYOff The line offset to the top left corner of the region
    9211             :  * of the band to be queried. This would be zero to start from the top.
    9212             :  *
    9213             :  * @param nXSize The width of the region of the band to be queried in pixels.
    9214             :  *
    9215             :  * @param nYSize The height of the region of the band to be queried in lines.
    9216             :  *
    9217             :  * @param nMaskFlagStop 0, or a binary-or'ed mask of possible values
    9218             :  * GDAL_DATA_COVERAGE_STATUS_UNIMPLEMENTED,
    9219             :  * GDAL_DATA_COVERAGE_STATUS_DATA and GDAL_DATA_COVERAGE_STATUS_EMPTY. As soon
    9220             :  * as the computation of the coverage matches the mask, the computation will be
    9221             :  * stopped. *pdfDataPct will not be valid in that case.
    9222             :  *
    9223             :  * @param pdfDataPct Optional output parameter whose pointed value will be set
    9224             :  * to the (approximate) percentage in [0,100] of pixels in the queried
    9225             :  * sub-window that have valid values. The implementation might not always be
    9226             :  * able to compute it, in which case it will be set to a negative value.
    9227             :  *
    9228             :  * @return a binary-or'ed combination of possible values
    9229             :  * GDAL_DATA_COVERAGE_STATUS_UNIMPLEMENTED,
    9230             :  * GDAL_DATA_COVERAGE_STATUS_DATA and GDAL_DATA_COVERAGE_STATUS_EMPTY
    9231             :  *
    9232             :  * @note Added in GDAL 2.2
    9233             :  */
    9234             : 
    9235        2745 : int GDALRasterBand::GetDataCoverageStatus(int nXOff, int nYOff, int nXSize,
    9236             :                                           int nYSize, int nMaskFlagStop,
    9237             :                                           double *pdfDataPct)
    9238             : {
    9239        2745 :     if (nXOff < 0 || nYOff < 0 || nXSize > INT_MAX - nXOff ||
    9240        2745 :         nYSize > INT_MAX - nYOff || nXOff + nXSize > nRasterXSize ||
    9241        2745 :         nYOff + nYSize > nRasterYSize)
    9242             :     {
    9243           0 :         CPLError(CE_Failure, CPLE_AppDefined, "Bad window");
    9244           0 :         if (pdfDataPct)
    9245           0 :             *pdfDataPct = 0.0;
    9246             :         return GDAL_DATA_COVERAGE_STATUS_UNIMPLEMENTED |
    9247           0 :                GDAL_DATA_COVERAGE_STATUS_EMPTY;
    9248             :     }
    9249        2745 :     return IGetDataCoverageStatus(nXOff, nYOff, nXSize, nYSize, nMaskFlagStop,
    9250        2745 :                                   pdfDataPct);
    9251             : }
    9252             : 
    9253             : /************************************************************************/
    9254             : /*                         IGetDataCoverageStatus()                     */
    9255             : /************************************************************************/
    9256             : 
    9257         510 : int GDALRasterBand::IGetDataCoverageStatus(int /*nXOff*/, int /*nYOff*/,
    9258             :                                            int /*nXSize*/, int /*nYSize*/,
    9259             :                                            int /*nMaskFlagStop*/,
    9260             :                                            double *pdfDataPct)
    9261             : {
    9262         510 :     if (pdfDataPct != nullptr)
    9263           0 :         *pdfDataPct = 100.0;
    9264             :     return GDAL_DATA_COVERAGE_STATUS_UNIMPLEMENTED |
    9265         510 :            GDAL_DATA_COVERAGE_STATUS_DATA;
    9266             : }
    9267             : 
    9268             : //! @cond Doxygen_Suppress
    9269             : /************************************************************************/
    9270             : /*                          EnterReadWrite()                            */
    9271             : /************************************************************************/
    9272             : 
    9273     6914140 : int GDALRasterBand::EnterReadWrite(GDALRWFlag eRWFlag)
    9274             : {
    9275     6914140 :     if (poDS != nullptr)
    9276     6157240 :         return poDS->EnterReadWrite(eRWFlag);
    9277      756903 :     return FALSE;
    9278             : }
    9279             : 
    9280             : /************************************************************************/
    9281             : /*                         LeaveReadWrite()                             */
    9282             : /************************************************************************/
    9283             : 
    9284      646523 : void GDALRasterBand::LeaveReadWrite()
    9285             : {
    9286      646523 :     if (poDS != nullptr)
    9287      646523 :         poDS->LeaveReadWrite();
    9288      646515 : }
    9289             : 
    9290             : /************************************************************************/
    9291             : /*                           InitRWLock()                               */
    9292             : /************************************************************************/
    9293             : 
    9294     3647580 : void GDALRasterBand::InitRWLock()
    9295             : {
    9296     3647580 :     if (poDS != nullptr)
    9297     3647180 :         poDS->InitRWLock();
    9298     3647580 : }
    9299             : 
    9300             : //! @endcond
    9301             : 
    9302             : // clang-format off
    9303             : 
    9304             : /**
    9305             :  * \fn GDALRasterBand::SetMetadata( char ** papszMetadata, const char * pszDomain)
    9306             :  * \brief Set metadata.
    9307             :  *
    9308             :  * CAUTION: depending on the format, older values of the updated information
    9309             :  * might still be found in the file in a "ghost" state, even if no longer
    9310             :  * accessible through the GDAL API. This is for example the case of the GTiff
    9311             :  * format (this is not a exhaustive list)
    9312             :  *
    9313             :  * The C function GDALSetMetadata() does the same thing as this method.
    9314             :  *
    9315             :  * @param papszMetadata the metadata in name=value string list format to
    9316             :  * apply.
    9317             :  * @param pszDomain the domain of interest.  Use "" or NULL for the default
    9318             :  * domain.
    9319             :  * @return CE_None on success, CE_Failure on failure and CE_Warning if the
    9320             :  * metadata has been accepted, but is likely not maintained persistently
    9321             :  * by the underlying object between sessions.
    9322             :  */
    9323             : 
    9324             : /**
    9325             :  * \fn GDALRasterBand::SetMetadataItem( const char * pszName, const char * pszValue, const char * pszDomain)
    9326             :  * \brief Set single metadata item.
    9327             :  *
    9328             :  * CAUTION: depending on the format, older values of the updated information
    9329             :  * might still be found in the file in a "ghost" state, even if no longer
    9330             :  * accessible through the GDAL API. This is for example the case of the GTiff
    9331             :  * format (this is not a exhaustive list)
    9332             :  *
    9333             :  * The C function GDALSetMetadataItem() does the same thing as this method.
    9334             :  *
    9335             :  * @param pszName the key for the metadata item to fetch.
    9336             :  * @param pszValue the value to assign to the key.
    9337             :  * @param pszDomain the domain to set within, use NULL for the default domain.
    9338             :  *
    9339             :  * @return CE_None on success, or an error code on failure.
    9340             :  */
    9341             : 
    9342             : // clang-format on
    9343             : 
    9344             : //! @cond Doxygen_Suppress
    9345             : /************************************************************************/
    9346             : /*                    EnablePixelTypeSignedByteWarning()                */
    9347             : /************************************************************************/
    9348             : 
    9349       28064 : void GDALRasterBand::EnablePixelTypeSignedByteWarning(bool b)
    9350             : {
    9351       28064 :     m_bEnablePixelTypeSignedByteWarning = b;
    9352       28064 : }
    9353             : 
    9354        8416 : void GDALEnablePixelTypeSignedByteWarning(GDALRasterBandH hBand, bool b)
    9355             : {
    9356        8416 :     GDALRasterBand::FromHandle(hBand)->EnablePixelTypeSignedByteWarning(b);
    9357        8416 : }
    9358             : 
    9359             : //! @endcond
    9360             : 
    9361             : /************************************************************************/
    9362             : /*                           GetMetadataItem()                          */
    9363             : /************************************************************************/
    9364             : 
    9365       61713 : const char *GDALRasterBand::GetMetadataItem(const char *pszName,
    9366             :                                             const char *pszDomain)
    9367             : {
    9368             :     // TODO (GDAL 4.0?): remove this when GDAL 3.7 has been widely adopted.
    9369       61713 :     if (m_bEnablePixelTypeSignedByteWarning && eDataType == GDT_Byte &&
    9370       36976 :         pszDomain != nullptr && EQUAL(pszDomain, "IMAGE_STRUCTURE") &&
    9371       28059 :         EQUAL(pszName, "PIXELTYPE"))
    9372             :     {
    9373           2 :         CPLError(CE_Warning, CPLE_AppDefined,
    9374             :                  "Starting with GDAL 3.7, PIXELTYPE=SIGNEDBYTE is no longer "
    9375             :                  "used to signal signed 8-bit raster. Change your code to "
    9376             :                  "test for the new GDT_Int8 data type instead.");
    9377             :     }
    9378       61713 :     return GDALMajorObject::GetMetadataItem(pszName, pszDomain);
    9379             : }
    9380             : 
    9381             : /************************************************************************/
    9382             : /*                     GDALMDArrayFromRasterBand                        */
    9383             : /************************************************************************/
    9384             : 
    9385             : class GDALMDArrayFromRasterBand final : public GDALMDArray
    9386             : {
    9387             :     CPL_DISALLOW_COPY_ASSIGN(GDALMDArrayFromRasterBand)
    9388             : 
    9389             :     GDALDataset *m_poDS;
    9390             :     GDALRasterBand *m_poBand;
    9391             :     GDALExtendedDataType m_dt;
    9392             :     std::vector<std::shared_ptr<GDALDimension>> m_dims{};
    9393             :     std::string m_osUnit;
    9394             :     std::vector<GByte> m_pabyNoData{};
    9395             :     std::shared_ptr<GDALMDArray> m_varX{};
    9396             :     std::shared_ptr<GDALMDArray> m_varY{};
    9397             :     std::string m_osFilename{};
    9398             : 
    9399             :     bool ReadWrite(GDALRWFlag eRWFlag, const GUInt64 *arrayStartIdx,
    9400             :                    const size_t *count, const GInt64 *arrayStep,
    9401             :                    const GPtrDiff_t *bufferStride,
    9402             :                    const GDALExtendedDataType &bufferDataType,
    9403             :                    void *pBuffer) const;
    9404             : 
    9405             :   protected:
    9406          23 :     GDALMDArrayFromRasterBand(GDALDataset *poDS, GDALRasterBand *poBand)
    9407          46 :         : GDALAbstractMDArray(std::string(),
    9408          46 :                               std::string(poDS->GetDescription()) +
    9409             :                                   CPLSPrintf(" band %d", poBand->GetBand())),
    9410          46 :           GDALMDArray(std::string(),
    9411          46 :                       std::string(poDS->GetDescription()) +
    9412             :                           CPLSPrintf(" band %d", poBand->GetBand())),
    9413             :           m_poDS(poDS), m_poBand(poBand),
    9414             :           m_dt(GDALExtendedDataType::Create(poBand->GetRasterDataType())),
    9415         115 :           m_osUnit(poBand->GetUnitType()), m_osFilename(poDS->GetDescription())
    9416             :     {
    9417          23 :         m_poDS->Reference();
    9418             : 
    9419          23 :         int bHasNoData = false;
    9420          23 :         if (m_poBand->GetRasterDataType() == GDT_Int64)
    9421             :         {
    9422           0 :             const auto nNoData = m_poBand->GetNoDataValueAsInt64(&bHasNoData);
    9423           0 :             if (bHasNoData)
    9424             :             {
    9425           0 :                 m_pabyNoData.resize(m_dt.GetSize());
    9426           0 :                 GDALCopyWords64(&nNoData, GDT_Int64, 0, &m_pabyNoData[0],
    9427             :                                 m_dt.GetNumericDataType(), 0, 1);
    9428             :             }
    9429             :         }
    9430          23 :         else if (m_poBand->GetRasterDataType() == GDT_UInt64)
    9431             :         {
    9432           0 :             const auto nNoData = m_poBand->GetNoDataValueAsUInt64(&bHasNoData);
    9433           0 :             if (bHasNoData)
    9434             :             {
    9435           0 :                 m_pabyNoData.resize(m_dt.GetSize());
    9436           0 :                 GDALCopyWords64(&nNoData, GDT_UInt64, 0, &m_pabyNoData[0],
    9437             :                                 m_dt.GetNumericDataType(), 0, 1);
    9438             :             }
    9439             :         }
    9440             :         else
    9441             :         {
    9442          23 :             const auto dfNoData = m_poBand->GetNoDataValue(&bHasNoData);
    9443          23 :             if (bHasNoData)
    9444             :             {
    9445           1 :                 m_pabyNoData.resize(m_dt.GetSize());
    9446           1 :                 GDALCopyWords64(&dfNoData, GDT_Float64, 0, &m_pabyNoData[0],
    9447             :                                 m_dt.GetNumericDataType(), 0, 1);
    9448             :             }
    9449             :         }
    9450             : 
    9451          23 :         const int nXSize = poBand->GetXSize();
    9452          23 :         const int nYSize = poBand->GetYSize();
    9453             : 
    9454          23 :         auto poSRS = m_poDS->GetSpatialRef();
    9455          46 :         std::string osTypeY;
    9456          46 :         std::string osTypeX;
    9457          46 :         std::string osDirectionY;
    9458          46 :         std::string osDirectionX;
    9459          23 :         if (poSRS && poSRS->GetAxesCount() == 2)
    9460             :         {
    9461          21 :             const auto &mapping = poSRS->GetDataAxisToSRSAxisMapping();
    9462          21 :             OGRAxisOrientation eOrientation1 = OAO_Other;
    9463          21 :             poSRS->GetAxis(nullptr, 0, &eOrientation1);
    9464          21 :             OGRAxisOrientation eOrientation2 = OAO_Other;
    9465          21 :             poSRS->GetAxis(nullptr, 1, &eOrientation2);
    9466          21 :             if (eOrientation1 == OAO_East && eOrientation2 == OAO_North)
    9467             :             {
    9468           5 :                 if (mapping == std::vector<int>{1, 2})
    9469             :                 {
    9470           5 :                     osTypeY = GDAL_DIM_TYPE_HORIZONTAL_Y;
    9471           5 :                     osDirectionY = "NORTH";
    9472           5 :                     osTypeX = GDAL_DIM_TYPE_HORIZONTAL_X;
    9473           5 :                     osDirectionX = "EAST";
    9474             :                 }
    9475             :             }
    9476          16 :             else if (eOrientation1 == OAO_North && eOrientation2 == OAO_East)
    9477             :             {
    9478          16 :                 if (mapping == std::vector<int>{2, 1})
    9479             :                 {
    9480          16 :                     osTypeY = GDAL_DIM_TYPE_HORIZONTAL_Y;
    9481          16 :                     osDirectionY = "NORTH";
    9482          16 :                     osTypeX = GDAL_DIM_TYPE_HORIZONTAL_X;
    9483          16 :                     osDirectionX = "EAST";
    9484             :                 }
    9485             :             }
    9486             :         }
    9487             : 
    9488         115 :         m_dims = {std::make_shared<GDALDimensionWeakIndexingVar>(
    9489             :                       "/", "Y", osTypeY, osDirectionY, nYSize),
    9490          46 :                   std::make_shared<GDALDimensionWeakIndexingVar>(
    9491          69 :                       "/", "X", osTypeX, osDirectionX, nXSize)};
    9492             : 
    9493             :         double adfGeoTransform[6];
    9494          23 :         if (m_poDS->GetGeoTransform(adfGeoTransform) == CE_None &&
    9495          23 :             adfGeoTransform[2] == 0 && adfGeoTransform[4] == 0)
    9496             :         {
    9497          44 :             m_varX = GDALMDArrayRegularlySpaced::Create(
    9498          22 :                 "/", "X", m_dims[1], adfGeoTransform[0], adfGeoTransform[1],
    9499          22 :                 0.5);
    9500          22 :             m_dims[1]->SetIndexingVariable(m_varX);
    9501             : 
    9502          44 :             m_varY = GDALMDArrayRegularlySpaced::Create(
    9503          22 :                 "/", "Y", m_dims[0], adfGeoTransform[3], adfGeoTransform[5],
    9504          22 :                 0.5);
    9505          22 :             m_dims[0]->SetIndexingVariable(m_varY);
    9506             :         }
    9507          23 :     }
    9508             : 
    9509          31 :     bool IRead(const GUInt64 *arrayStartIdx, const size_t *count,
    9510             :                const GInt64 *arrayStep, const GPtrDiff_t *bufferStride,
    9511             :                const GDALExtendedDataType &bufferDataType,
    9512             :                void *pDstBuffer) const override
    9513             :     {
    9514          31 :         return ReadWrite(GF_Read, arrayStartIdx, count, arrayStep, bufferStride,
    9515          31 :                          bufferDataType, pDstBuffer);
    9516             :     }
    9517             : 
    9518           1 :     bool IWrite(const GUInt64 *arrayStartIdx, const size_t *count,
    9519             :                 const GInt64 *arrayStep, const GPtrDiff_t *bufferStride,
    9520             :                 const GDALExtendedDataType &bufferDataType,
    9521             :                 const void *pSrcBuffer) override
    9522             :     {
    9523           1 :         return ReadWrite(GF_Write, arrayStartIdx, count, arrayStep,
    9524             :                          bufferStride, bufferDataType,
    9525           1 :                          const_cast<void *>(pSrcBuffer));
    9526             :     }
    9527             : 
    9528             :   public:
    9529          46 :     ~GDALMDArrayFromRasterBand()
    9530          23 :     {
    9531          23 :         m_poDS->ReleaseRef();
    9532          46 :     }
    9533             : 
    9534          23 :     static std::shared_ptr<GDALMDArray> Create(GDALDataset *poDS,
    9535             :                                                GDALRasterBand *poBand)
    9536             :     {
    9537             :         auto array(std::shared_ptr<GDALMDArrayFromRasterBand>(
    9538          46 :             new GDALMDArrayFromRasterBand(poDS, poBand)));
    9539          23 :         array->SetSelf(array);
    9540          46 :         return array;
    9541             :     }
    9542             : 
    9543           2 :     bool IsWritable() const override
    9544             :     {
    9545           2 :         return m_poDS->GetAccess() == GA_Update;
    9546             :     }
    9547             : 
    9548          97 :     const std::string &GetFilename() const override
    9549             :     {
    9550          97 :         return m_osFilename;
    9551             :     }
    9552             : 
    9553             :     const std::vector<std::shared_ptr<GDALDimension>> &
    9554         299 :     GetDimensions() const override
    9555             :     {
    9556         299 :         return m_dims;
    9557             :     }
    9558             : 
    9559         138 :     const GDALExtendedDataType &GetDataType() const override
    9560             :     {
    9561         138 :         return m_dt;
    9562             :     }
    9563             : 
    9564           3 :     const std::string &GetUnit() const override
    9565             :     {
    9566           3 :         return m_osUnit;
    9567             :     }
    9568             : 
    9569          29 :     const void *GetRawNoDataValue() const override
    9570             :     {
    9571          29 :         return m_pabyNoData.empty() ? nullptr : m_pabyNoData.data();
    9572             :     }
    9573             : 
    9574           2 :     double GetOffset(bool *pbHasOffset,
    9575             :                      GDALDataType *peStorageType) const override
    9576             :     {
    9577           2 :         int bHasOffset = false;
    9578           2 :         double dfRes = m_poBand->GetOffset(&bHasOffset);
    9579           2 :         if (pbHasOffset)
    9580           2 :             *pbHasOffset = CPL_TO_BOOL(bHasOffset);
    9581           2 :         if (peStorageType)
    9582           1 :             *peStorageType = GDT_Unknown;
    9583           2 :         return dfRes;
    9584             :     }
    9585             : 
    9586           2 :     double GetScale(bool *pbHasScale,
    9587             :                     GDALDataType *peStorageType) const override
    9588             :     {
    9589           2 :         int bHasScale = false;
    9590           2 :         double dfRes = m_poBand->GetScale(&bHasScale);
    9591           2 :         if (pbHasScale)
    9592           2 :             *pbHasScale = CPL_TO_BOOL(bHasScale);
    9593           2 :         if (peStorageType)
    9594           1 :             *peStorageType = GDT_Unknown;
    9595           2 :         return dfRes;
    9596             :     }
    9597             : 
    9598          84 :     std::shared_ptr<OGRSpatialReference> GetSpatialRef() const override
    9599             :     {
    9600          84 :         auto poSrcSRS = m_poDS->GetSpatialRef();
    9601          84 :         if (!poSrcSRS)
    9602           2 :             return nullptr;
    9603         164 :         auto poSRS = std::shared_ptr<OGRSpatialReference>(poSrcSRS->Clone());
    9604             : 
    9605         164 :         auto axisMapping = poSRS->GetDataAxisToSRSAxisMapping();
    9606          82 :         constexpr int iYDim = 0;
    9607          82 :         constexpr int iXDim = 1;
    9608         246 :         for (auto &m : axisMapping)
    9609             :         {
    9610         164 :             if (m == 1)
    9611          82 :                 m = iXDim + 1;
    9612          82 :             else if (m == 2)
    9613          82 :                 m = iYDim + 1;
    9614             :             else
    9615           0 :                 m = 0;
    9616             :         }
    9617          82 :         poSRS->SetDataAxisToSRSAxisMapping(axisMapping);
    9618          82 :         return poSRS;
    9619             :     }
    9620             : 
    9621          29 :     std::vector<GUInt64> GetBlockSize() const override
    9622             :     {
    9623          29 :         int nBlockXSize = 0;
    9624          29 :         int nBlockYSize = 0;
    9625          29 :         m_poBand->GetBlockSize(&nBlockXSize, &nBlockYSize);
    9626          29 :         return std::vector<GUInt64>{static_cast<GUInt64>(nBlockYSize),
    9627          29 :                                     static_cast<GUInt64>(nBlockXSize)};
    9628             :     }
    9629             : 
    9630             :     class MDIAsAttribute : public GDALAttribute
    9631             :     {
    9632             :         std::vector<std::shared_ptr<GDALDimension>> m_dims{};
    9633             :         const GDALExtendedDataType m_dt = GDALExtendedDataType::CreateString();
    9634             :         std::string m_osValue;
    9635             : 
    9636             :       public:
    9637           2 :         MDIAsAttribute(const std::string &name, const std::string &value)
    9638           2 :             : GDALAbstractMDArray(std::string(), name),
    9639           4 :               GDALAttribute(std::string(), name), m_osValue(value)
    9640             :         {
    9641           2 :         }
    9642             : 
    9643             :         const std::vector<std::shared_ptr<GDALDimension>> &
    9644           3 :         GetDimensions() const override
    9645             :         {
    9646           3 :             return m_dims;
    9647             :         }
    9648             : 
    9649           2 :         const GDALExtendedDataType &GetDataType() const override
    9650             :         {
    9651           2 :             return m_dt;
    9652             :         }
    9653             : 
    9654           1 :         bool IRead(const GUInt64 *, const size_t *, const GInt64 *,
    9655             :                    const GPtrDiff_t *,
    9656             :                    const GDALExtendedDataType &bufferDataType,
    9657             :                    void *pDstBuffer) const override
    9658             :         {
    9659           1 :             const char *pszStr = m_osValue.c_str();
    9660           1 :             GDALExtendedDataType::CopyValue(&pszStr, m_dt, pDstBuffer,
    9661             :                                             bufferDataType);
    9662           1 :             return true;
    9663             :         }
    9664             :     };
    9665             : 
    9666             :     std::vector<std::shared_ptr<GDALAttribute>>
    9667          14 :     GetAttributes(CSLConstList) const override
    9668             :     {
    9669          14 :         std::vector<std::shared_ptr<GDALAttribute>> res;
    9670          14 :         auto papszMD = m_poBand->GetMetadata();
    9671          16 :         for (auto iter = papszMD; iter && iter[0]; ++iter)
    9672             :         {
    9673           2 :             char *pszKey = nullptr;
    9674           2 :             const char *pszValue = CPLParseNameValue(*iter, &pszKey);
    9675           2 :             if (pszKey && pszValue)
    9676             :             {
    9677             :                 res.emplace_back(
    9678           2 :                     std::make_shared<MDIAsAttribute>(pszKey, pszValue));
    9679             :             }
    9680           2 :             CPLFree(pszKey);
    9681             :         }
    9682          14 :         return res;
    9683             :     }
    9684             : };
    9685             : 
    9686             : /************************************************************************/
    9687             : /*                            ReadWrite()                               */
    9688             : /************************************************************************/
    9689             : 
    9690          32 : bool GDALMDArrayFromRasterBand::ReadWrite(
    9691             :     GDALRWFlag eRWFlag, const GUInt64 *arrayStartIdx, const size_t *count,
    9692             :     const GInt64 *arrayStep, const GPtrDiff_t *bufferStride,
    9693             :     const GDALExtendedDataType &bufferDataType, void *pBuffer) const
    9694             : {
    9695          32 :     constexpr size_t iDimX = 1;
    9696          32 :     constexpr size_t iDimY = 0;
    9697          32 :     return GDALMDRasterIOFromBand(m_poBand, eRWFlag, iDimX, iDimY,
    9698             :                                   arrayStartIdx, count, arrayStep, bufferStride,
    9699          32 :                                   bufferDataType, pBuffer);
    9700             : }
    9701             : 
    9702             : /************************************************************************/
    9703             : /*                       GDALMDRasterIOFromBand()                       */
    9704             : /************************************************************************/
    9705             : 
    9706          65 : bool GDALMDRasterIOFromBand(GDALRasterBand *poBand, GDALRWFlag eRWFlag,
    9707             :                             size_t iDimX, size_t iDimY,
    9708             :                             const GUInt64 *arrayStartIdx, const size_t *count,
    9709             :                             const GInt64 *arrayStep,
    9710             :                             const GPtrDiff_t *bufferStride,
    9711             :                             const GDALExtendedDataType &bufferDataType,
    9712             :                             void *pBuffer)
    9713             : {
    9714          65 :     const auto eDT(bufferDataType.GetNumericDataType());
    9715          65 :     const auto nDTSize(GDALGetDataTypeSizeBytes(eDT));
    9716          65 :     const int nX =
    9717          65 :         arrayStep[iDimX] > 0
    9718          65 :             ? static_cast<int>(arrayStartIdx[iDimX])
    9719           2 :             : static_cast<int>(arrayStartIdx[iDimX] -
    9720           2 :                                (count[iDimX] - 1) * -arrayStep[iDimX]);
    9721          65 :     const int nY =
    9722          65 :         arrayStep[iDimY] > 0
    9723          65 :             ? static_cast<int>(arrayStartIdx[iDimY])
    9724           2 :             : static_cast<int>(arrayStartIdx[iDimY] -
    9725           2 :                                (count[iDimY] - 1) * -arrayStep[iDimY]);
    9726          65 :     const int nSizeX = static_cast<int>(count[iDimX] * ABS(arrayStep[iDimX]));
    9727          65 :     const int nSizeY = static_cast<int>(count[iDimY] * ABS(arrayStep[iDimY]));
    9728          65 :     GByte *pabyBuffer = static_cast<GByte *>(pBuffer);
    9729          65 :     int nStrideXSign = 1;
    9730          65 :     if (arrayStep[iDimX] < 0)
    9731             :     {
    9732           2 :         pabyBuffer += (count[iDimX] - 1) * bufferStride[iDimX] * nDTSize;
    9733           2 :         nStrideXSign = -1;
    9734             :     }
    9735          65 :     int nStrideYSign = 1;
    9736          65 :     if (arrayStep[iDimY] < 0)
    9737             :     {
    9738           2 :         pabyBuffer += (count[iDimY] - 1) * bufferStride[iDimY] * nDTSize;
    9739           2 :         nStrideYSign = -1;
    9740             :     }
    9741             : 
    9742         130 :     return poBand->RasterIO(eRWFlag, nX, nY, nSizeX, nSizeY, pabyBuffer,
    9743          65 :                             static_cast<int>(count[iDimX]),
    9744          65 :                             static_cast<int>(count[iDimY]), eDT,
    9745             :                             static_cast<GSpacing>(
    9746          65 :                                 nStrideXSign * bufferStride[iDimX] * nDTSize),
    9747             :                             static_cast<GSpacing>(
    9748          65 :                                 nStrideYSign * bufferStride[iDimY] * nDTSize),
    9749          65 :                             nullptr) == CE_None;
    9750             : }
    9751             : 
    9752             : /************************************************************************/
    9753             : /*                            AsMDArray()                               */
    9754             : /************************************************************************/
    9755             : 
    9756             : /** Return a view of this raster band as a 2D multidimensional GDALMDArray.
    9757             :  *
    9758             :  * The band must be linked to a GDALDataset. If this dataset is not already
    9759             :  * marked as shared, it will be, so that the returned array holds a reference
    9760             :  * to it.
    9761             :  *
    9762             :  * If the dataset has a geotransform attached, the X and Y dimensions of the
    9763             :  * returned array will have an associated indexing variable.
    9764             :  *
    9765             :  * This is the same as the C function GDALRasterBandAsMDArray().
    9766             :  *
    9767             :  * The "reverse" method is GDALMDArray::AsClassicDataset().
    9768             :  *
    9769             :  * @return a new array, or nullptr.
    9770             :  *
    9771             :  * @since GDAL 3.1
    9772             :  */
    9773          23 : std::shared_ptr<GDALMDArray> GDALRasterBand::AsMDArray() const
    9774             : {
    9775          23 :     if (!poDS)
    9776             :     {
    9777           0 :         CPLError(CE_Failure, CPLE_AppDefined, "Band not attached to a dataset");
    9778           0 :         return nullptr;
    9779             :     }
    9780          23 :     if (!poDS->GetShared())
    9781             :     {
    9782          23 :         poDS->MarkAsShared();
    9783             :     }
    9784             :     return GDALMDArrayFromRasterBand::Create(
    9785          23 :         poDS, const_cast<GDALRasterBand *>(this));
    9786             : }
    9787             : 
    9788             : /************************************************************************/
    9789             : /*                             InterpolateAtPoint()                     */
    9790             : /************************************************************************/
    9791             : 
    9792             : /**
    9793             :  * \brief Interpolates the value between pixels using a resampling algorithm,
    9794             :  * taking pixel/line coordinates as input.
    9795             :  *
    9796             :  * @param dfPixel pixel coordinate as a double, where interpolation should be done.
    9797             :  * @param dfLine line coordinate as a double, where interpolation should be done.
    9798             :  * @param eInterpolation interpolation type. Only near, bilinear, cubic and cubicspline are allowed.
    9799             :  * @param pdfRealValue pointer to real part of interpolated value
    9800             :  * @param pdfImagValue pointer to imaginary part of interpolated value (may be null if not needed)
    9801             :  *
    9802             :  * @return CE_None on success, or an error code on failure.
    9803             :  * @since GDAL 3.10
    9804             :  */
    9805             : 
    9806         124 : CPLErr GDALRasterBand::InterpolateAtPoint(double dfPixel, double dfLine,
    9807             :                                           GDALRIOResampleAlg eInterpolation,
    9808             :                                           double *pdfRealValue,
    9809             :                                           double *pdfImagValue) const
    9810             : {
    9811         124 :     if (eInterpolation != GRIORA_NearestNeighbour &&
    9812          33 :         eInterpolation != GRIORA_Bilinear && eInterpolation != GRIORA_Cubic &&
    9813             :         eInterpolation != GRIORA_CubicSpline)
    9814             :     {
    9815           2 :         CPLError(CE_Failure, CPLE_AppDefined,
    9816             :                  "Only nearest, bilinear, cubic and cubicspline interpolation "
    9817             :                  "methods "
    9818             :                  "allowed");
    9819             : 
    9820           2 :         return CE_Failure;
    9821             :     }
    9822             : 
    9823         122 :     GDALRasterBand *pBand = const_cast<GDALRasterBand *>(this);
    9824         122 :     if (!m_poPointsCache)
    9825          52 :         m_poPointsCache = new GDALDoublePointsCache();
    9826             : 
    9827             :     const bool res =
    9828         122 :         GDALInterpolateAtPoint(pBand, eInterpolation, m_poPointsCache->cache,
    9829             :                                dfPixel, dfLine, pdfRealValue, pdfImagValue);
    9830             : 
    9831         122 :     return res ? CE_None : CE_Failure;
    9832             : }
    9833             : 
    9834             : /************************************************************************/
    9835             : /*                        GDALRasterInterpolateAtPoint()                */
    9836             : /************************************************************************/
    9837             : 
    9838             : /**
    9839             :  * \brief Interpolates the value between pixels using
    9840             :  * a resampling algorithm
    9841             :  *
    9842             :  * @see GDALRasterBand::InterpolateAtPoint()
    9843             :  * @since GDAL 3.10
    9844             :  */
    9845             : 
    9846         106 : CPLErr GDALRasterInterpolateAtPoint(GDALRasterBandH hBand, double dfPixel,
    9847             :                                     double dfLine,
    9848             :                                     GDALRIOResampleAlg eInterpolation,
    9849             :                                     double *pdfRealValue, double *pdfImagValue)
    9850             : {
    9851         106 :     VALIDATE_POINTER1(hBand, "GDALRasterInterpolateAtPoint", CE_Failure);
    9852             : 
    9853         106 :     GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
    9854         106 :     return poBand->InterpolateAtPoint(dfPixel, dfLine, eInterpolation,
    9855         106 :                                       pdfRealValue, pdfImagValue);
    9856             : }
    9857             : 
    9858             : /************************************************************************/
    9859             : /*                    InterpolateAtGeolocation()                        */
    9860             : /************************************************************************/
    9861             : 
    9862             : /**
    9863             :  * \brief Interpolates the value between pixels using a resampling algorithm,
    9864             :  * taking georeferenced coordinates as input.
    9865             :  *
    9866             :  * When poSRS is null, those georeferenced coordinates (dfGeolocX, dfGeolocY)
    9867             :  * must be in the "natural" SRS of the dataset, that is the one returned by
    9868             :  * GetSpatialRef() if there is a geotransform, GetGCPSpatialRef() if there are
    9869             :  * GCPs, WGS 84 if there are RPC coefficients, or the SRS of the geolocation
    9870             :  * array (generally WGS 84) if there is a geolocation array.
    9871             :  * If that natural SRS is a geographic one, dfGeolocX must be a longitude, and
    9872             :  * dfGeolocY a latitude. If that natural SRS is a projected one, dfGeolocX must
    9873             :  * be a easting, and dfGeolocY a northing.
    9874             :  *
    9875             :  * When poSRS is set to a non-null value, (dfGeolocX, dfGeolocY) must be
    9876             :  * expressed in that CRS, and that tuple must be conformant with the
    9877             :  * data-axis-to-crs-axis setting of poSRS, that is the one returned by
    9878             :  * the OGRSpatialReference::GetDataAxisToSRSAxisMapping(). If you want to be sure
    9879             :  * of the axis order, then make sure to call poSRS->SetAxisMappingStrategy(OAMS_TRADITIONAL_GIS_ORDER)
    9880             :  * before calling this method, and in that case, dfGeolocX must be a longitude
    9881             :  * or an easting value, and dfGeolocX a latitude or a northing value.
    9882             :  *
    9883             :  * The GDALDataset::GeolocationToPixelLine() will be used to transform from
    9884             :  * (dfGeolocX,dfGeolocY) georeferenced coordinates to (pixel, line). Refer to
    9885             :  * it for details on how that transformation is done.
    9886             :  *
    9887             :  * @param dfGeolocX X coordinate of the position (longitude or easting if poSRS
    9888             :  * is null, otherwise consistent with poSRS data-axis-to-crs-axis mapping),
    9889             :  * where interpolation should be done.
    9890             :  * @param dfGeolocY Y coordinate of the position (latitude or northing if poSRS
    9891             :  * is null, otherwise consistent with poSRS data-axis-to-crs-axis mapping),
    9892             :  * where interpolation should be done.
    9893             :  * @param poSRS If set, override the natural CRS in which dfGeolocX, dfGeolocY are expressed
    9894             :  * @param eInterpolation interpolation type. Only near, bilinear, cubic and cubicspline are allowed.
    9895             :  * @param pdfRealValue pointer to real part of interpolated value
    9896             :  * @param pdfImagValue pointer to imaginary part of interpolated value (may be null if not needed)
    9897             :  * @param papszTransformerOptions Options accepted by GDALDataset::GeolocationToPixelLine() (GDALCreateGenImgProjTransformer2()), or nullptr.
    9898             :  *
    9899             :  * @return CE_None on success, or an error code on failure.
    9900             :  * @since GDAL 3.11
    9901             :  */
    9902             : 
    9903          10 : CPLErr GDALRasterBand::InterpolateAtGeolocation(
    9904             :     double dfGeolocX, double dfGeolocY, const OGRSpatialReference *poSRS,
    9905             :     GDALRIOResampleAlg eInterpolation, double *pdfRealValue,
    9906             :     double *pdfImagValue, CSLConstList papszTransformerOptions) const
    9907             : {
    9908             :     double dfPixel;
    9909             :     double dfLine;
    9910          10 :     if (poDS->GeolocationToPixelLine(dfGeolocX, dfGeolocY, poSRS, &dfPixel,
    9911             :                                      &dfLine,
    9912          10 :                                      papszTransformerOptions) != CE_None)
    9913             :     {
    9914           1 :         return CE_Failure;
    9915             :     }
    9916           9 :     return InterpolateAtPoint(dfPixel, dfLine, eInterpolation, pdfRealValue,
    9917           9 :                               pdfImagValue);
    9918             : }
    9919             : 
    9920             : /************************************************************************/
    9921             : /*                  GDALRasterInterpolateAtGeolocation()                */
    9922             : /************************************************************************/
    9923             : 
    9924             : /**
    9925             :  * \brief Interpolates the value between pixels using a resampling algorithm,
    9926             :  * taking georeferenced coordinates as input.
    9927             :  *
    9928             :  * @see GDALRasterBand::InterpolateAtGeolocation()
    9929             :  * @since GDAL 3.11
    9930             :  */
    9931             : 
    9932          10 : CPLErr GDALRasterInterpolateAtGeolocation(GDALRasterBandH hBand,
    9933             :                                           double dfGeolocX, double dfGeolocY,
    9934             :                                           OGRSpatialReferenceH hSRS,
    9935             :                                           GDALRIOResampleAlg eInterpolation,
    9936             :                                           double *pdfRealValue,
    9937             :                                           double *pdfImagValue,
    9938             :                                           CSLConstList papszTransformerOptions)
    9939             : {
    9940          10 :     VALIDATE_POINTER1(hBand, "GDALRasterInterpolateAtGeolocation", CE_Failure);
    9941             : 
    9942          10 :     GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
    9943          10 :     return poBand->InterpolateAtGeolocation(
    9944          10 :         dfGeolocX, dfGeolocY, OGRSpatialReference::FromHandle(hSRS),
    9945          10 :         eInterpolation, pdfRealValue, pdfImagValue, papszTransformerOptions);
    9946             : }

Generated by: LCOV version 1.14