LCOV - code coverage report
Current view: top level - gcore - gdalrasterband.cpp (source / functions) Hit Total Coverage
Test: gdal_filtered.info Lines: 2131 2734 77.9 %
Date: 2024-05-03 15:49:35 Functions: 188 210 89.5 %

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

Generated by: LCOV version 1.14