LCOV - code coverage report
Current view: top level - frmts/vrt - vrtsources.cpp (source / functions) Hit Total Coverage
Test: gdal_filtered.info Lines: 1545 1791 86.3 %
Date: 2025-07-13 09:04:35 Functions: 80 97 82.5 %

          Line data    Source code
       1             : /******************************************************************************
       2             :  *
       3             :  * Project:  Virtual GDAL Datasets
       4             :  * Purpose:  Implementation of VRTSimpleSource, VRTFuncSource and
       5             :  *           VRTAveragedSource.
       6             :  * Author:   Frank Warmerdam <warmerdam@pobox.com>
       7             :  *
       8             :  ******************************************************************************
       9             :  * Copyright (c) 2001, Frank Warmerdam <warmerdam@pobox.com>
      10             :  * Copyright (c) 2008-2013, Even Rouault <even dot rouault at spatialys.com>
      11             :  *
      12             :  * SPDX-License-Identifier: MIT
      13             :  ****************************************************************************/
      14             : 
      15             : #include "gdal_vrt.h"
      16             : #include "vrtdataset.h"
      17             : 
      18             : #include <cassert>
      19             : #include <climits>
      20             : #include <cmath>
      21             : #include <cstddef>
      22             : #include <cstdio>
      23             : #include <cstdlib>
      24             : #include <cstring>
      25             : #include <algorithm>
      26             : #include <limits>
      27             : #include <string>
      28             : 
      29             : #include "cpl_conv.h"
      30             : #include "cpl_error.h"
      31             : #include "cpl_hash_set.h"
      32             : #include "cpl_minixml.h"
      33             : #include "cpl_progress.h"
      34             : #include "cpl_string.h"
      35             : #include "cpl_vsi.h"
      36             : #include "gdal.h"
      37             : #include "gdal_priv.h"
      38             : #include "gdal_proxy.h"
      39             : #include "gdal_priv_templates.hpp"
      40             : 
      41             : /*! @cond Doxygen_Suppress */
      42             : 
      43             : // #define DEBUG_VERBOSE 1
      44             : 
      45             : /************************************************************************/
      46             : /* ==================================================================== */
      47             : /*                             VRTSource                                */
      48             : /* ==================================================================== */
      49             : /************************************************************************/
      50             : 
      51      246696 : VRTSource::~VRTSource()
      52             : {
      53      246696 : }
      54             : 
      55             : /************************************************************************/
      56             : /*                             GetFileList()                            */
      57             : /************************************************************************/
      58             : 
      59           0 : void VRTSource::GetFileList(char *** /* ppapszFileList */, int * /* pnSize */,
      60             :                             int * /* pnMaxSize */, CPLHashSet * /* hSetFiles */)
      61             : {
      62           0 : }
      63             : 
      64             : /************************************************************************/
      65             : /* ==================================================================== */
      66             : /*                          VRTSimpleSource                             */
      67             : /* ==================================================================== */
      68             : /************************************************************************/
      69             : 
      70             : /************************************************************************/
      71             : /*                          VRTSimpleSource()                           */
      72             : /************************************************************************/
      73             : 
      74             : VRTSimpleSource::VRTSimpleSource() = default;
      75             : 
      76             : /************************************************************************/
      77             : /*                          VRTSimpleSource()                           */
      78             : /************************************************************************/
      79             : 
      80          82 : VRTSimpleSource::VRTSimpleSource(const VRTSimpleSource *poSrcSource,
      81          82 :                                  double dfXDstRatio, double dfYDstRatio)
      82          82 :     : m_poMapSharedSources(poSrcSource->m_poMapSharedSources),
      83          82 :       m_poRasterBand(poSrcSource->m_poRasterBand),
      84          82 :       m_poMaskBandMainBand(poSrcSource->m_poMaskBandMainBand),
      85          82 :       m_aosOpenOptionsOri(poSrcSource->m_aosOpenOptionsOri),
      86          82 :       m_aosOpenOptions(poSrcSource->m_aosOpenOptions),
      87          82 :       m_bSrcDSNameFromVRT(poSrcSource->m_bSrcDSNameFromVRT),
      88          82 :       m_nBand(poSrcSource->m_nBand),
      89          82 :       m_bGetMaskBand(poSrcSource->m_bGetMaskBand),
      90          82 :       m_dfSrcXOff(poSrcSource->m_dfSrcXOff),
      91          82 :       m_dfSrcYOff(poSrcSource->m_dfSrcYOff),
      92          82 :       m_dfSrcXSize(poSrcSource->m_dfSrcXSize),
      93          82 :       m_dfSrcYSize(poSrcSource->m_dfSrcYSize),
      94          82 :       m_nMaxValue(poSrcSource->m_nMaxValue), m_bRelativeToVRTOri(-1),
      95          82 :       m_nExplicitSharedStatus(poSrcSource->m_nExplicitSharedStatus),
      96          82 :       m_osSrcDSName(poSrcSource->m_osSrcDSName),
      97          82 :       m_bDropRefOnSrcBand(poSrcSource->m_bDropRefOnSrcBand)
      98             : {
      99          82 :     if (!poSrcSource->IsSrcWinSet() && !poSrcSource->IsDstWinSet() &&
     100           0 :         (dfXDstRatio != 1.0 || dfYDstRatio != 1.0))
     101             :     {
     102           1 :         auto l_band = GetRasterBand();
     103           1 :         if (l_band)
     104             :         {
     105           1 :             m_dfSrcXOff = 0;
     106           1 :             m_dfSrcYOff = 0;
     107           1 :             m_dfSrcXSize = l_band->GetXSize();
     108           1 :             m_dfSrcYSize = l_band->GetYSize();
     109           1 :             m_dfDstXOff = 0;
     110           1 :             m_dfDstYOff = 0;
     111           1 :             m_dfDstXSize = l_band->GetXSize() * dfXDstRatio;
     112           1 :             m_dfDstYSize = l_band->GetYSize() * dfYDstRatio;
     113             :         }
     114             :     }
     115          81 :     else if (poSrcSource->IsDstWinSet())
     116             :     {
     117          81 :         m_dfDstXOff = poSrcSource->m_dfDstXOff * dfXDstRatio;
     118          81 :         m_dfDstYOff = poSrcSource->m_dfDstYOff * dfYDstRatio;
     119          81 :         m_dfDstXSize = poSrcSource->m_dfDstXSize * dfXDstRatio;
     120          81 :         m_dfDstYSize = poSrcSource->m_dfDstYSize * dfYDstRatio;
     121             :     }
     122          82 : }
     123             : 
     124             : /************************************************************************/
     125             : /*                          ~VRTSimpleSource()                          */
     126             : /************************************************************************/
     127             : 
     128      494596 : VRTSimpleSource::~VRTSimpleSource()
     129             : 
     130             : {
     131      246652 :     if (!m_bDropRefOnSrcBand)
     132         402 :         return;
     133             : 
     134      246250 :     if (m_poMaskBandMainBand != nullptr)
     135             :     {
     136          62 :         if (m_poMaskBandMainBand->GetDataset() != nullptr)
     137             :         {
     138          62 :             m_poMaskBandMainBand->GetDataset()->ReleaseRef();
     139             :         }
     140             :     }
     141      489762 :     else if (m_poRasterBand != nullptr &&
     142      243574 :              m_poRasterBand->GetDataset() != nullptr)
     143             :     {
     144      243574 :         m_poRasterBand->GetDataset()->ReleaseRef();
     145             :     }
     146      492586 : }
     147             : 
     148             : /************************************************************************/
     149             : /*                           GetTypeStatic()                            */
     150             : /************************************************************************/
     151             : 
     152      458207 : const char *VRTSimpleSource::GetTypeStatic()
     153             : {
     154             :     static const char *TYPE = "SimpleSource";
     155      458207 :     return TYPE;
     156             : }
     157             : 
     158             : /************************************************************************/
     159             : /*                            GetType()                                 */
     160             : /************************************************************************/
     161             : 
     162      126386 : const char *VRTSimpleSource::GetType() const
     163             : {
     164      126386 :     return GetTypeStatic();
     165             : }
     166             : 
     167             : /************************************************************************/
     168             : /*                           FlushCache()                               */
     169             : /************************************************************************/
     170             : 
     171      312301 : CPLErr VRTSimpleSource::FlushCache(bool bAtClosing)
     172             : 
     173             : {
     174      312301 :     if (m_poMaskBandMainBand != nullptr)
     175             :     {
     176          14 :         return m_poMaskBandMainBand->FlushCache(bAtClosing);
     177             :     }
     178      312287 :     else if (m_poRasterBand != nullptr)
     179             :     {
     180      309640 :         return m_poRasterBand->FlushCache(bAtClosing);
     181             :     }
     182        2647 :     return CE_None;
     183             : }
     184             : 
     185             : /************************************************************************/
     186             : /*                    UnsetPreservedRelativeFilenames()                 */
     187             : /************************************************************************/
     188             : 
     189          78 : void VRTSimpleSource::UnsetPreservedRelativeFilenames()
     190             : {
     191         206 :     if (m_bRelativeToVRTOri &&
     192         128 :         !STARTS_WITH(m_osSourceFileNameOri.c_str(), "http://") &&
     193          50 :         !STARTS_WITH(m_osSourceFileNameOri.c_str(), "https://"))
     194             :     {
     195          50 :         m_bRelativeToVRTOri = -1;
     196          50 :         m_osSourceFileNameOri = "";
     197             :     }
     198          78 : }
     199             : 
     200             : /************************************************************************/
     201             : /*                             SetSrcBand()                             */
     202             : /************************************************************************/
     203             : 
     204         463 : void VRTSimpleSource::SetSrcBand(const char *pszFilename, int nBand)
     205             : 
     206             : {
     207         463 :     m_nBand = nBand;
     208         463 :     m_osSrcDSName = pszFilename;
     209         463 : }
     210             : 
     211             : /************************************************************************/
     212             : /*                             SetSrcBand()                             */
     213             : /************************************************************************/
     214             : 
     215      141595 : void VRTSimpleSource::SetSrcBand(GDALRasterBand *poNewSrcBand)
     216             : 
     217             : {
     218      141595 :     m_poRasterBand = poNewSrcBand;
     219      141595 :     m_nBand = m_poRasterBand->GetBand();
     220      141595 :     auto poDS = poNewSrcBand->GetDataset();
     221      141595 :     if (poDS != nullptr)
     222             :     {
     223      141595 :         m_osSrcDSName = poDS->GetDescription();
     224      141595 :         m_aosOpenOptions = CSLDuplicate(poDS->GetOpenOptions());
     225      141595 :         m_aosOpenOptionsOri = m_aosOpenOptions;
     226             :     }
     227      141595 : }
     228             : 
     229             : /************************************************************************/
     230             : /*                      SetSourceDatasetName()                          */
     231             : /************************************************************************/
     232             : 
     233           7 : void VRTSimpleSource::SetSourceDatasetName(const char *pszFilename,
     234             :                                            bool bRelativeToVRT)
     235             : {
     236           7 :     CPLAssert(m_nBand >= 0);
     237           7 :     m_osSrcDSName = pszFilename;
     238           7 :     m_osSourceFileNameOri = pszFilename;
     239           7 :     m_bRelativeToVRTOri = bRelativeToVRT;
     240           7 : }
     241             : 
     242             : /************************************************************************/
     243             : /*                          SetSrcMaskBand()                            */
     244             : /************************************************************************/
     245             : 
     246             : // poSrcBand is not the mask band, but the band from which the mask band is
     247             : // taken.
     248          43 : void VRTSimpleSource::SetSrcMaskBand(GDALRasterBand *poNewSrcBand)
     249             : 
     250             : {
     251          43 :     m_poRasterBand = poNewSrcBand->GetMaskBand();
     252          43 :     m_poMaskBandMainBand = poNewSrcBand;
     253          43 :     m_nBand = poNewSrcBand->GetBand();
     254          43 :     auto poDS = poNewSrcBand->GetDataset();
     255          43 :     if (poDS != nullptr)
     256             :     {
     257          43 :         m_osSrcDSName = poDS->GetDescription();
     258          43 :         m_aosOpenOptions = CSLDuplicate(poDS->GetOpenOptions());
     259          43 :         m_aosOpenOptionsOri = m_aosOpenOptions;
     260             :     }
     261          43 :     m_bGetMaskBand = true;
     262          43 : }
     263             : 
     264             : /************************************************************************/
     265             : /*                         RoundIfCloseToInt()                          */
     266             : /************************************************************************/
     267             : 
     268     2599650 : static double RoundIfCloseToInt(double dfValue)
     269             : {
     270     2599650 :     double dfClosestInt = floor(dfValue + 0.5);
     271     2599650 :     return (fabs(dfValue - dfClosestInt) < 1e-3) ? dfClosestInt : dfValue;
     272             : }
     273             : 
     274             : /************************************************************************/
     275             : /*                            SetSrcWindow()                            */
     276             : /************************************************************************/
     277             : 
     278      145243 : void VRTSimpleSource::SetSrcWindow(double dfNewXOff, double dfNewYOff,
     279             :                                    double dfNewXSize, double dfNewYSize)
     280             : 
     281             : {
     282      145243 :     m_dfSrcXOff = RoundIfCloseToInt(dfNewXOff);
     283      145243 :     m_dfSrcYOff = RoundIfCloseToInt(dfNewYOff);
     284      145243 :     m_dfSrcXSize = RoundIfCloseToInt(dfNewXSize);
     285      145243 :     m_dfSrcYSize = RoundIfCloseToInt(dfNewYSize);
     286      145243 : }
     287             : 
     288             : /************************************************************************/
     289             : /*                            SetDstWindow()                            */
     290             : /************************************************************************/
     291             : 
     292      145242 : void VRTSimpleSource::SetDstWindow(double dfNewXOff, double dfNewYOff,
     293             :                                    double dfNewXSize, double dfNewYSize)
     294             : 
     295             : {
     296      145242 :     m_dfDstXOff = RoundIfCloseToInt(dfNewXOff);
     297      145242 :     m_dfDstYOff = RoundIfCloseToInt(dfNewYOff);
     298      145242 :     m_dfDstXSize = RoundIfCloseToInt(dfNewXSize);
     299      145242 :     m_dfDstYSize = RoundIfCloseToInt(dfNewYSize);
     300      145242 : }
     301             : 
     302             : /************************************************************************/
     303             : /*                            GetDstWindow()                            */
     304             : /************************************************************************/
     305             : 
     306         526 : void VRTSimpleSource::GetDstWindow(double &dfDstXOff, double &dfDstYOff,
     307             :                                    double &dfDstXSize, double &dfDstYSize) const
     308             : {
     309         526 :     dfDstXOff = m_dfDstXOff;
     310         526 :     dfDstYOff = m_dfDstYOff;
     311         526 :     dfDstXSize = m_dfDstXSize;
     312         526 :     dfDstYSize = m_dfDstYSize;
     313         526 : }
     314             : 
     315             : /************************************************************************/
     316             : /*                        DstWindowIntersects()                         */
     317             : /************************************************************************/
     318             : 
     319        1127 : bool VRTSimpleSource::DstWindowIntersects(double dfXOff, double dfYOff,
     320             :                                           double dfXSize, double dfYSize) const
     321             : {
     322        2245 :     return IsDstWinSet() && m_dfDstXOff + m_dfDstXSize > dfXOff &&
     323        1118 :            m_dfDstYOff + m_dfDstYSize > dfYOff &&
     324        2245 :            m_dfDstXOff < dfXOff + dfXSize && m_dfDstYOff < dfYOff + dfYSize;
     325             : }
     326             : 
     327             : /************************************************************************/
     328             : /*                            IsSlowSource()                            */
     329             : /************************************************************************/
     330             : 
     331        2512 : static bool IsSlowSource(const char *pszSrcName)
     332             : {
     333        5024 :     return strstr(pszSrcName, "/vsicurl/http") != nullptr ||
     334        5024 :            strstr(pszSrcName, "/vsicurl/ftp") != nullptr ||
     335        2512 :            (strstr(pszSrcName, "/vsicurl?") != nullptr &&
     336        2512 :             strstr(pszSrcName, "&url=http") != nullptr);
     337             : }
     338             : 
     339             : /************************************************************************/
     340             : /*                         AddSourceFilenameNode()                      */
     341             : /************************************************************************/
     342             : 
     343        2578 : void VRTSimpleSource::AddSourceFilenameNode(const char *pszVRTPath,
     344             :                                             CPLXMLNode *psSrc)
     345             : {
     346             : 
     347             :     VSIStatBufL sStat;
     348        2578 :     int bRelativeToVRT = FALSE;  // TODO(schwehr): Make this a bool?
     349        5156 :     std::string osSourceFilename;
     350             : 
     351        2578 :     if (m_bRelativeToVRTOri >= 0)
     352             :     {
     353          66 :         osSourceFilename = m_osSourceFileNameOri;
     354          66 :         bRelativeToVRT = m_bRelativeToVRTOri;
     355             :     }
     356        2512 :     else if (IsSlowSource(m_osSrcDSName))
     357             :     {
     358             :         // Testing the existence of remote resources can be excruciating
     359             :         // slow, so let's just suppose they exist.
     360           0 :         osSourceFilename = m_osSrcDSName;
     361           0 :         bRelativeToVRT = FALSE;
     362             :     }
     363             :     // If this isn't actually a file, don't even try to know if it is a
     364             :     // relative path. It can't be !, and unfortunately CPLIsFilenameRelative()
     365             :     // can only work with strings that are filenames To be clear
     366             :     // NITF_TOC_ENTRY:CADRG_JOG-A_250K_1_0:some_path isn't a relative file
     367             :     // path.
     368        2512 :     else if (VSIStatExL(m_osSrcDSName, &sStat, VSI_STAT_EXISTS_FLAG) != 0)
     369             :     {
     370          64 :         osSourceFilename = m_osSrcDSName;
     371          64 :         bRelativeToVRT = FALSE;
     372             : 
     373             :         // Try subdatasetinfo API first
     374             :         // Note: this will become the only branch when subdatasetinfo will become
     375             :         //       available for NITF_IM, RASTERLITE and TILEDB
     376          64 :         const auto oSubDSInfo{GDALGetSubdatasetInfo(osSourceFilename.c_str())};
     377          64 :         if (oSubDSInfo && !oSubDSInfo->GetPathComponent().empty())
     378             :         {
     379           8 :             auto path{oSubDSInfo->GetPathComponent()};
     380             :             std::string relPath{CPLExtractRelativePath(pszVRTPath, path.c_str(),
     381           8 :                                                        &bRelativeToVRT)};
     382           4 :             osSourceFilename = oSubDSInfo->ModifyPathComponent(relPath);
     383           4 :             GDALDestroySubdatasetInfo(oSubDSInfo);
     384             :         }
     385             :         else
     386             :         {
     387         285 :             for (const char *pszSyntax :
     388         345 :                  GDALDataset::apszSpecialSubDatasetSyntax)
     389             :             {
     390         288 :                 CPLString osPrefix(pszSyntax);
     391         288 :                 osPrefix.resize(strchr(pszSyntax, ':') - pszSyntax + 1);
     392         288 :                 if (pszSyntax[osPrefix.size()] == '"')
     393          57 :                     osPrefix += '"';
     394         288 :                 if (EQUALN(osSourceFilename.c_str(), osPrefix, osPrefix.size()))
     395             :                 {
     396           3 :                     if (STARTS_WITH_CI(pszSyntax + osPrefix.size(), "{ANY}"))
     397             :                     {
     398             :                         const char *pszLastPart =
     399           3 :                             strrchr(osSourceFilename.c_str(), ':') + 1;
     400             :                         // CSV:z:/foo.xyz
     401           1 :                         if ((pszLastPart[0] == '/' || pszLastPart[0] == '\\') &&
     402           6 :                             pszLastPart - osSourceFilename.c_str() >= 3 &&
     403           2 :                             pszLastPart[-3] == ':')
     404           0 :                             pszLastPart -= 2;
     405           3 :                         CPLString osPrefixFilename(osSourceFilename);
     406           3 :                         osPrefixFilename.resize(pszLastPart -
     407           3 :                                                 osSourceFilename.c_str());
     408             :                         osSourceFilename = CPLExtractRelativePath(
     409           3 :                             pszVRTPath, pszLastPart, &bRelativeToVRT);
     410           3 :                         osSourceFilename = osPrefixFilename + osSourceFilename;
     411             :                     }
     412           0 :                     else if (STARTS_WITH_CI(pszSyntax + osPrefix.size(),
     413             :                                             "{FILENAME}"))
     414             :                     {
     415           0 :                         CPLString osFilename(osSourceFilename.c_str() +
     416           0 :                                              osPrefix.size());
     417           0 :                         size_t nPos = 0;
     418           0 :                         if (osFilename.size() >= 3 && osFilename[1] == ':' &&
     419           0 :                             (osFilename[2] == '\\' || osFilename[2] == '/'))
     420           0 :                             nPos = 2;
     421           0 :                         nPos = osFilename.find(
     422           0 :                             pszSyntax[osPrefix.size() + strlen("{FILENAME}")],
     423             :                             nPos);
     424           0 :                         if (nPos != std::string::npos)
     425             :                         {
     426           0 :                             const CPLString osSuffix = osFilename.substr(nPos);
     427           0 :                             osFilename.resize(nPos);
     428             :                             osSourceFilename = CPLExtractRelativePath(
     429           0 :                                 pszVRTPath, osFilename, &bRelativeToVRT);
     430             :                             osSourceFilename =
     431           0 :                                 osPrefix + osSourceFilename + osSuffix;
     432             :                         }
     433             :                     }
     434           3 :                     break;
     435             :                 }
     436             :             }
     437             :         }
     438             :     }
     439             :     else
     440             :     {
     441        4896 :         std::string osVRTFilename = pszVRTPath;
     442        4896 :         std::string osSourceDataset = m_osSrcDSName;
     443        2448 :         char *pszCurDir = CPLGetCurrentDir();
     444        2448 :         if (CPLIsFilenameRelative(osSourceDataset.c_str()) &&
     445        2448 :             !CPLIsFilenameRelative(osVRTFilename.c_str()) &&
     446             :             pszCurDir != nullptr)
     447             :         {
     448         184 :             osSourceDataset = CPLFormFilenameSafe(
     449          92 :                 pszCurDir, osSourceDataset.c_str(), nullptr);
     450             :         }
     451        2356 :         else if (!CPLIsFilenameRelative(osSourceDataset.c_str()) &&
     452        2356 :                  CPLIsFilenameRelative(osVRTFilename.c_str()) &&
     453             :                  pszCurDir != nullptr)
     454             :         {
     455             :             osVRTFilename =
     456          83 :                 CPLFormFilenameSafe(pszCurDir, osVRTFilename.c_str(), nullptr);
     457             :         }
     458        2448 :         CPLFree(pszCurDir);
     459             :         osSourceFilename = CPLExtractRelativePath(
     460        2448 :             osVRTFilename.c_str(), osSourceDataset.c_str(), &bRelativeToVRT);
     461             :     }
     462             : 
     463        2578 :     CPLSetXMLValue(psSrc, "SourceFilename", osSourceFilename.c_str());
     464             : 
     465        2578 :     CPLCreateXMLNode(CPLCreateXMLNode(CPLGetXMLNode(psSrc, "SourceFilename"),
     466             :                                       CXT_Attribute, "relativeToVRT"),
     467        2578 :                      CXT_Text, bRelativeToVRT ? "1" : "0");
     468             : 
     469             :     // Determine if we must write the shared attribute. The config option
     470             :     // will override the m_nExplicitSharedStatus value
     471        2578 :     const char *pszShared = CPLGetConfigOption("VRT_SHARED_SOURCE", nullptr);
     472        2578 :     if ((pszShared == nullptr && m_nExplicitSharedStatus == 0) ||
     473           0 :         (pszShared != nullptr && !CPLTestBool(pszShared)))
     474             :     {
     475           0 :         CPLCreateXMLNode(
     476             :             CPLCreateXMLNode(CPLGetXMLNode(psSrc, "SourceFilename"),
     477             :                              CXT_Attribute, "shared"),
     478             :             CXT_Text, "0");
     479             :     }
     480        2578 : }
     481             : 
     482             : /************************************************************************/
     483             : /*                           SerializeToXML()                           */
     484             : /************************************************************************/
     485             : 
     486        2600 : CPLXMLNode *VRTSimpleSource::SerializeToXML(const char *pszVRTPath)
     487             : 
     488             : {
     489             :     CPLXMLNode *const psSrc =
     490        2600 :         CPLCreateXMLNode(nullptr, CXT_Element, GetTypeStatic());
     491             : 
     492        2600 :     if (!m_osResampling.empty())
     493             :     {
     494          24 :         CPLCreateXMLNode(CPLCreateXMLNode(psSrc, CXT_Attribute, "resampling"),
     495             :                          CXT_Text, m_osResampling.c_str());
     496             :     }
     497             : 
     498        2600 :     if (!m_osName.empty())
     499             :     {
     500          45 :         CPLAddXMLAttributeAndValue(psSrc, "name", m_osName.c_str());
     501             :     }
     502             : 
     503        2600 :     if (m_bSrcDSNameFromVRT)
     504             :     {
     505           1 :         CPLAddXMLChild(psSrc, CPLParseXMLString(m_osSrcDSName.c_str()));
     506             :     }
     507             :     else
     508             :     {
     509        2599 :         bool bDone = false;
     510        2599 :         if (m_osSrcDSName.empty() && m_poRasterBand)
     511             :         {
     512          72 :             auto poSrcDS = m_poRasterBand->GetDataset();
     513          72 :             if (poSrcDS)
     514             :             {
     515          72 :                 VRTDataset *poSrcVRTDS = nullptr;
     516             :                 // For GDALComputedDataset
     517          72 :                 void *pHandle = poSrcDS->GetInternalHandle("VRT_DATASET");
     518          72 :                 if (pHandle && poSrcDS->GetInternalHandle(nullptr) == nullptr)
     519             :                 {
     520          21 :                     poSrcVRTDS = static_cast<VRTDataset *>(pHandle);
     521             :                 }
     522             :                 else
     523             :                 {
     524          51 :                     poSrcVRTDS = dynamic_cast<VRTDataset *>(poSrcDS);
     525             :                 }
     526          72 :                 if (poSrcVRTDS)
     527             :                 {
     528          21 :                     poSrcVRTDS->UnsetPreservedRelativeFilenames();
     529          21 :                     CPLAddXMLChild(psSrc,
     530          21 :                                    poSrcVRTDS->SerializeToXML(pszVRTPath));
     531          21 :                     bDone = true;
     532             :                 }
     533             :             }
     534             :         }
     535        2599 :         if (!bDone)
     536             :         {
     537        2578 :             AddSourceFilenameNode(pszVRTPath, psSrc);
     538             :         }
     539             :     }
     540             : 
     541        2600 :     GDALSerializeOpenOptionsToXML(psSrc, m_aosOpenOptionsOri.List());
     542             : 
     543        2600 :     if (m_bGetMaskBand)
     544          19 :         CPLSetXMLValue(psSrc, "SourceBand", CPLSPrintf("mask,%d", m_nBand));
     545             :     else
     546        2581 :         CPLSetXMLValue(psSrc, "SourceBand", CPLSPrintf("%d", m_nBand));
     547             : 
     548             :     // TODO: in a later version, no longer emit SourceProperties, which
     549             :     // is no longer used by GDAL 3.4
     550        2600 :     if (m_poRasterBand)
     551             :     {
     552             :         /* Write a few additional useful properties of the dataset */
     553             :         /* so that we can use a proxy dataset when re-opening. See XMLInit() */
     554             :         /* below */
     555        2481 :         CPLSetXMLValue(psSrc, "SourceProperties.#RasterXSize",
     556        2481 :                        CPLSPrintf("%d", m_poRasterBand->GetXSize()));
     557        2481 :         CPLSetXMLValue(psSrc, "SourceProperties.#RasterYSize",
     558        2481 :                        CPLSPrintf("%d", m_poRasterBand->GetYSize()));
     559        2481 :         CPLSetXMLValue(
     560             :             psSrc, "SourceProperties.#DataType",
     561        2481 :             GDALGetDataTypeName(m_poRasterBand->GetRasterDataType()));
     562             : 
     563        2481 :         int nBlockXSize = 0;
     564        2481 :         int nBlockYSize = 0;
     565        2481 :         m_poRasterBand->GetBlockSize(&nBlockXSize, &nBlockYSize);
     566             : 
     567        2481 :         CPLSetXMLValue(psSrc, "SourceProperties.#BlockXSize",
     568             :                        CPLSPrintf("%d", nBlockXSize));
     569        2481 :         CPLSetXMLValue(psSrc, "SourceProperties.#BlockYSize",
     570             :                        CPLSPrintf("%d", nBlockYSize));
     571             :     }
     572             : 
     573        2600 :     if (IsSrcWinSet())
     574             :     {
     575        2586 :         CPLSetXMLValue(psSrc, "SrcRect.#xOff",
     576             :                        CPLSPrintf("%.15g", m_dfSrcXOff));
     577        2586 :         CPLSetXMLValue(psSrc, "SrcRect.#yOff",
     578             :                        CPLSPrintf("%.15g", m_dfSrcYOff));
     579        2586 :         CPLSetXMLValue(psSrc, "SrcRect.#xSize",
     580             :                        CPLSPrintf("%.15g", m_dfSrcXSize));
     581        2586 :         CPLSetXMLValue(psSrc, "SrcRect.#ySize",
     582             :                        CPLSPrintf("%.15g", m_dfSrcYSize));
     583             :     }
     584             : 
     585        2600 :     if (IsDstWinSet())
     586             :     {
     587        2586 :         CPLSetXMLValue(psSrc, "DstRect.#xOff",
     588             :                        CPLSPrintf("%.15g", m_dfDstXOff));
     589        2586 :         CPLSetXMLValue(psSrc, "DstRect.#yOff",
     590             :                        CPLSPrintf("%.15g", m_dfDstYOff));
     591        2586 :         CPLSetXMLValue(psSrc, "DstRect.#xSize",
     592             :                        CPLSPrintf("%.15g", m_dfDstXSize));
     593        2586 :         CPLSetXMLValue(psSrc, "DstRect.#ySize",
     594             :                        CPLSPrintf("%.15g", m_dfDstYSize));
     595             :     }
     596             : 
     597        2600 :     return psSrc;
     598             : }
     599             : 
     600             : /************************************************************************/
     601             : /*                              XMLInit()                               */
     602             : /************************************************************************/
     603             : 
     604      104119 : CPLErr VRTSimpleSource::XMLInit(const CPLXMLNode *psSrc, const char *pszVRTPath,
     605             :                                 VRTMapSharedResources &oMapSharedSources)
     606             : 
     607             : {
     608      104119 :     m_poMapSharedSources = &oMapSharedSources;
     609             : 
     610      104119 :     m_osResampling = CPLGetXMLValue(psSrc, "resampling", "");
     611      104119 :     m_osName = CPLGetXMLValue(psSrc, "name", "");
     612             : 
     613             :     /* -------------------------------------------------------------------- */
     614             :     /*      Prepare filename.                                               */
     615             :     /* -------------------------------------------------------------------- */
     616             :     const CPLXMLNode *psSourceFileNameNode =
     617      104119 :         CPLGetXMLNode(psSrc, "SourceFilename");
     618      104119 :     const CPLXMLNode *psSourceVRTDataset = CPLGetXMLNode(psSrc, "VRTDataset");
     619             :     const char *pszFilename =
     620      104119 :         psSourceFileNameNode ? CPLGetXMLValue(psSourceFileNameNode, nullptr, "")
     621      104119 :                              : "";
     622             : 
     623      104119 :     if (pszFilename[0] == '\0' && !psSourceVRTDataset)
     624             :     {
     625           1 :         CPLError(CE_Warning, CPLE_AppDefined,
     626             :                  "Missing <SourceFilename> or <VRTDataset> element in <%s>.",
     627           1 :                  psSrc->pszValue);
     628           1 :         return CE_Failure;
     629             :     }
     630             : 
     631             :     // Backup original filename and relativeToVRT so as to be able to
     632             :     // serialize them identically again (#5985)
     633      104118 :     m_osSourceFileNameOri = pszFilename;
     634      104118 :     if (pszFilename[0])
     635             :     {
     636      104109 :         m_bRelativeToVRTOri =
     637      104109 :             atoi(CPLGetXMLValue(psSourceFileNameNode, "relativetoVRT", "0"));
     638             :         const char *pszShared =
     639      104109 :             CPLGetXMLValue(psSourceFileNameNode, "shared", nullptr);
     640      104109 :         if (pszShared == nullptr)
     641             :         {
     642      104107 :             pszShared = CPLGetConfigOption("VRT_SHARED_SOURCE", nullptr);
     643             :         }
     644      104109 :         if (pszShared != nullptr)
     645             :         {
     646           8 :             m_nExplicitSharedStatus = CPLTestBool(pszShared);
     647             :         }
     648             : 
     649      208218 :         m_osSrcDSName = GDALDataset::BuildFilename(
     650      208218 :             pszFilename, pszVRTPath, CPL_TO_BOOL(m_bRelativeToVRTOri));
     651             :     }
     652           9 :     else if (psSourceVRTDataset)
     653             :     {
     654             :         CPLXMLNode sNode;
     655           9 :         sNode.eType = psSourceVRTDataset->eType;
     656           9 :         sNode.pszValue = psSourceVRTDataset->pszValue;
     657           9 :         sNode.psNext = nullptr;
     658           9 :         sNode.psChild = psSourceVRTDataset->psChild;
     659           9 :         char *pszXML = CPLSerializeXMLTree(&sNode);
     660           9 :         if (pszXML)
     661             :         {
     662           9 :             m_bSrcDSNameFromVRT = true;
     663           9 :             m_osSrcDSName = pszXML;
     664           9 :             CPLFree(pszXML);
     665             :         }
     666             :     }
     667             : 
     668      104118 :     const char *pszSourceBand = CPLGetXMLValue(psSrc, "SourceBand", "1");
     669      104118 :     m_bGetMaskBand = false;
     670      104118 :     if (STARTS_WITH_CI(pszSourceBand, "mask"))
     671             :     {
     672          23 :         m_bGetMaskBand = true;
     673          23 :         if (pszSourceBand[4] == ',')
     674          23 :             m_nBand = atoi(pszSourceBand + 5);
     675             :         else
     676           0 :             m_nBand = 1;
     677             :     }
     678             :     else
     679             :     {
     680      104095 :         m_nBand = atoi(pszSourceBand);
     681             :     }
     682      104118 :     if (!GDALCheckBandCount(m_nBand, 0))
     683             :     {
     684           0 :         CPLError(CE_Warning, CPLE_AppDefined,
     685             :                  "Invalid <SourceBand> element in VRTRasterBand.");
     686           0 :         return CE_Failure;
     687             :     }
     688             : 
     689      104118 :     m_aosOpenOptions = GDALDeserializeOpenOptionsFromXML(psSrc);
     690      104118 :     m_aosOpenOptionsOri = m_aosOpenOptions;
     691      104118 :     if (strstr(m_osSrcDSName.c_str(), "<VRTDataset") != nullptr)
     692          11 :         m_aosOpenOptions.SetNameValue("ROOT_PATH", pszVRTPath);
     693             : 
     694      104118 :     return ParseSrcRectAndDstRect(psSrc);
     695             : }
     696             : 
     697             : /************************************************************************/
     698             : /*                        ParseSrcRectAndDstRect()                      */
     699             : /************************************************************************/
     700             : 
     701      104132 : CPLErr VRTSimpleSource::ParseSrcRectAndDstRect(const CPLXMLNode *psSrc)
     702             : {
     703       25148 :     const auto GetAttrValue = [](const CPLXMLNode *psNode,
     704             :                                  const char *pszAttrName, double dfDefaultVal)
     705             :     {
     706       25148 :         if (const char *pszVal = CPLGetXMLValue(psNode, pszAttrName, nullptr))
     707       25148 :             return CPLAtof(pszVal);
     708             :         else
     709           0 :             return dfDefaultVal;
     710             :     };
     711             : 
     712             :     /* -------------------------------------------------------------------- */
     713             :     /*      Set characteristics.                                            */
     714             :     /* -------------------------------------------------------------------- */
     715      104132 :     const CPLXMLNode *const psSrcRect = CPLGetXMLNode(psSrc, "SrcRect");
     716      104132 :     if (psSrcRect)
     717             :     {
     718        3144 :         double xOff = GetAttrValue(psSrcRect, "xOff", UNINIT_WINDOW);
     719        3144 :         double yOff = GetAttrValue(psSrcRect, "yOff", UNINIT_WINDOW);
     720        3144 :         double xSize = GetAttrValue(psSrcRect, "xSize", UNINIT_WINDOW);
     721        3144 :         double ySize = GetAttrValue(psSrcRect, "ySize", UNINIT_WINDOW);
     722             :         // Test written that way to catch NaN values
     723        3144 :         if (!(xOff >= INT_MIN && xOff <= INT_MAX) ||
     724        3144 :             !(yOff >= INT_MIN && yOff <= INT_MAX) ||
     725        3144 :             !(xSize > 0 || xSize == UNINIT_WINDOW) || xSize > INT_MAX ||
     726        3143 :             !(ySize > 0 || ySize == UNINIT_WINDOW) || ySize > INT_MAX)
     727             :         {
     728           1 :             CPLError(CE_Failure, CPLE_AppDefined, "Wrong values in SrcRect");
     729           1 :             return CE_Failure;
     730             :         }
     731        3143 :         SetSrcWindow(xOff, yOff, xSize, ySize);
     732             :     }
     733             :     else
     734             :     {
     735      100988 :         m_dfSrcXOff = UNINIT_WINDOW;
     736      100988 :         m_dfSrcYOff = UNINIT_WINDOW;
     737      100988 :         m_dfSrcXSize = UNINIT_WINDOW;
     738      100988 :         m_dfSrcYSize = UNINIT_WINDOW;
     739             :     }
     740             : 
     741      104131 :     const CPLXMLNode *const psDstRect = CPLGetXMLNode(psSrc, "DstRect");
     742      104131 :     if (psDstRect)
     743             :     {
     744        3143 :         double xOff = GetAttrValue(psDstRect, "xOff", UNINIT_WINDOW);
     745             :         ;
     746        3143 :         double yOff = GetAttrValue(psDstRect, "yOff", UNINIT_WINDOW);
     747        3143 :         double xSize = GetAttrValue(psDstRect, "xSize", UNINIT_WINDOW);
     748             :         ;
     749        3143 :         double ySize = GetAttrValue(psDstRect, "ySize", UNINIT_WINDOW);
     750             :         // Test written that way to catch NaN values
     751        3143 :         if (!(xOff >= INT_MIN && xOff <= INT_MAX) ||
     752        3143 :             !(yOff >= INT_MIN && yOff <= INT_MAX) ||
     753        3143 :             !(xSize > 0 || xSize == UNINIT_WINDOW) || xSize > INT_MAX ||
     754        3143 :             !(ySize > 0 || ySize == UNINIT_WINDOW) || ySize > INT_MAX)
     755             :         {
     756           1 :             CPLError(CE_Failure, CPLE_AppDefined, "Wrong values in DstRect");
     757           1 :             return CE_Failure;
     758             :         }
     759        3142 :         SetDstWindow(xOff, yOff, xSize, ySize);
     760             :     }
     761             :     else
     762             :     {
     763      100988 :         m_dfDstXOff = UNINIT_WINDOW;
     764      100988 :         m_dfDstYOff = UNINIT_WINDOW;
     765      100988 :         m_dfDstXSize = UNINIT_WINDOW;
     766      100988 :         m_dfDstYSize = UNINIT_WINDOW;
     767             :     }
     768             : 
     769      104130 :     return CE_None;
     770             : }
     771             : 
     772             : /************************************************************************/
     773             : /*                             GetFileList()                            */
     774             : /************************************************************************/
     775             : 
     776         113 : void VRTSimpleSource::GetFileList(char ***ppapszFileList, int *pnSize,
     777             :                                   int *pnMaxSize, CPLHashSet *hSetFiles)
     778             : {
     779         113 :     if (!m_osSrcDSName.empty() && !m_bSrcDSNameFromVRT)
     780             :     {
     781         113 :         const char *pszFilename = m_osSrcDSName.c_str();
     782             : 
     783             :         /* --------------------------------------------------------------------
     784             :          */
     785             :         /*      Is it already in the list ? */
     786             :         /* --------------------------------------------------------------------
     787             :          */
     788         113 :         if (CPLHashSetLookup(hSetFiles, pszFilename) != nullptr)
     789          15 :             return;
     790             : 
     791             :         /* --------------------------------------------------------------------
     792             :          */
     793             :         /*      Grow array if necessary */
     794             :         /* --------------------------------------------------------------------
     795             :          */
     796          98 :         if (*pnSize + 1 >= *pnMaxSize)
     797             :         {
     798          67 :             *pnMaxSize = std::max(*pnSize + 2, 2 + 2 * (*pnMaxSize));
     799          67 :             *ppapszFileList = static_cast<char **>(
     800          67 :                 CPLRealloc(*ppapszFileList, sizeof(char *) * (*pnMaxSize)));
     801             :         }
     802             : 
     803             :         /* --------------------------------------------------------------------
     804             :          */
     805             :         /*      Add the string to the list */
     806             :         /* --------------------------------------------------------------------
     807             :          */
     808          98 :         (*ppapszFileList)[*pnSize] = CPLStrdup(pszFilename);
     809          98 :         (*ppapszFileList)[(*pnSize + 1)] = nullptr;
     810          98 :         CPLHashSetInsert(hSetFiles, (*ppapszFileList)[*pnSize]);
     811             : 
     812          98 :         (*pnSize)++;
     813             :     }
     814             : }
     815             : 
     816             : /************************************************************************/
     817             : /*                           OpenSource()                               */
     818             : /************************************************************************/
     819             : 
     820      102156 : void VRTSimpleSource::OpenSource() const
     821             : {
     822      102156 :     CPLAssert(m_poRasterBand == nullptr);
     823             : 
     824             :     /* ----------------------------------------------------------------- */
     825             :     /*      Create a proxy dataset                                       */
     826             :     /* ----------------------------------------------------------------- */
     827      102156 :     GDALProxyPoolDataset *proxyDS = nullptr;
     828      102156 :     std::string osKeyMapSharedSources;
     829      102156 :     if (m_poMapSharedSources)
     830             :     {
     831      102108 :         osKeyMapSharedSources = m_osSrcDSName;
     832      102122 :         for (int i = 0; i < m_aosOpenOptions.size(); ++i)
     833             :         {
     834          14 :             osKeyMapSharedSources += "||";
     835          14 :             osKeyMapSharedSources += m_aosOpenOptions[i];
     836             :         }
     837             : 
     838      102108 :         proxyDS = cpl::down_cast<GDALProxyPoolDataset *>(
     839      102108 :             m_poMapSharedSources->Get(osKeyMapSharedSources));
     840             :     }
     841             : 
     842      102156 :     if (proxyDS == nullptr)
     843             :     {
     844        3184 :         int bShared = true;
     845        3184 :         if (m_nExplicitSharedStatus != -1)
     846           8 :             bShared = m_nExplicitSharedStatus;
     847             : 
     848        3184 :         const CPLString osUniqueHandle(CPLSPrintf("%p", m_poMapSharedSources));
     849        3184 :         proxyDS = GDALProxyPoolDataset::Create(
     850             :             m_osSrcDSName, m_aosOpenOptions.List(), GA_ReadOnly, bShared,
     851             :             osUniqueHandle.c_str());
     852        3184 :         if (proxyDS == nullptr)
     853         175 :             return;
     854             :     }
     855             :     else
     856             :     {
     857       98972 :         proxyDS->Reference();
     858             :     }
     859             : 
     860      101981 :     if (m_bGetMaskBand)
     861             :     {
     862             :         GDALProxyPoolRasterBand *poMaskBand =
     863          15 :             cpl::down_cast<GDALProxyPoolRasterBand *>(
     864          15 :                 proxyDS->GetRasterBand(m_nBand));
     865          15 :         poMaskBand->AddSrcMaskBandDescriptionFromUnderlying();
     866             :     }
     867             : 
     868             :     /* -------------------------------------------------------------------- */
     869             :     /*      Get the raster band.                                            */
     870             :     /* -------------------------------------------------------------------- */
     871             : 
     872      101981 :     m_poRasterBand = proxyDS->GetRasterBand(m_nBand);
     873      101981 :     if (m_poRasterBand == nullptr || !ValidateOpenedBand(m_poRasterBand))
     874             :     {
     875           2 :         proxyDS->ReleaseRef();
     876           2 :         return;
     877             :     }
     878             : 
     879      101979 :     if (m_bGetMaskBand)
     880             :     {
     881          15 :         m_poRasterBand = m_poRasterBand->GetMaskBand();
     882          15 :         if (m_poRasterBand == nullptr)
     883             :         {
     884           0 :             proxyDS->ReleaseRef();
     885           0 :             return;
     886             :         }
     887          15 :         m_poMaskBandMainBand = m_poRasterBand;
     888             :     }
     889             : 
     890      101979 :     if (m_poMapSharedSources)
     891             :     {
     892      101931 :         m_poMapSharedSources->Insert(osKeyMapSharedSources, proxyDS);
     893             :     }
     894             : }
     895             : 
     896             : /************************************************************************/
     897             : /*                         GetRasterBand()                              */
     898             : /************************************************************************/
     899             : 
     900      934748 : GDALRasterBand *VRTSimpleSource::GetRasterBand() const
     901             : {
     902      934748 :     if (m_poRasterBand == nullptr)
     903      102154 :         OpenSource();
     904      934748 :     return m_poRasterBand;
     905             : }
     906             : 
     907             : /************************************************************************/
     908             : /*                        GetMaskBandMainBand()                         */
     909             : /************************************************************************/
     910             : 
     911        4218 : GDALRasterBand *VRTSimpleSource::GetMaskBandMainBand()
     912             : {
     913        4218 :     if (m_poRasterBand == nullptr)
     914           2 :         OpenSource();
     915        4218 :     return m_poMaskBandMainBand;
     916             : }
     917             : 
     918             : /************************************************************************/
     919             : /*                       IsSameExceptBandNumber()                       */
     920             : /************************************************************************/
     921             : 
     922        2853 : bool VRTSimpleSource::IsSameExceptBandNumber(
     923             :     const VRTSimpleSource *poOtherSource) const
     924             : {
     925        5706 :     return m_dfSrcXOff == poOtherSource->m_dfSrcXOff &&
     926        2853 :            m_dfSrcYOff == poOtherSource->m_dfSrcYOff &&
     927        2853 :            m_dfSrcXSize == poOtherSource->m_dfSrcXSize &&
     928        2853 :            m_dfSrcYSize == poOtherSource->m_dfSrcYSize &&
     929        2853 :            m_dfDstXOff == poOtherSource->m_dfDstXOff &&
     930        2853 :            m_dfDstYOff == poOtherSource->m_dfDstYOff &&
     931        2853 :            m_dfDstXSize == poOtherSource->m_dfDstXSize &&
     932        8559 :            m_dfDstYSize == poOtherSource->m_dfDstYSize &&
     933        5706 :            m_osSrcDSName == poOtherSource->m_osSrcDSName;
     934             : }
     935             : 
     936             : /************************************************************************/
     937             : /*                              SrcToDst()                              */
     938             : /*                                                                      */
     939             : /*      Note: this is a no-op if the both src and dst windows are unset */
     940             : /************************************************************************/
     941             : 
     942       10243 : void VRTSimpleSource::SrcToDst(double dfX, double dfY, double &dfXOut,
     943             :                                double &dfYOut) const
     944             : 
     945             : {
     946       10243 :     dfXOut = ((dfX - m_dfSrcXOff) / m_dfSrcXSize) * m_dfDstXSize + m_dfDstXOff;
     947       10243 :     dfYOut = ((dfY - m_dfSrcYOff) / m_dfSrcYSize) * m_dfDstYSize + m_dfDstYOff;
     948       10243 : }
     949             : 
     950             : /************************************************************************/
     951             : /*                              DstToSrc()                              */
     952             : /*                                                                      */
     953             : /*      Note: this is a no-op if the both src and dst windows are unset */
     954             : /************************************************************************/
     955             : 
     956     4022310 : void VRTSimpleSource::DstToSrc(double dfX, double dfY, double &dfXOut,
     957             :                                double &dfYOut) const
     958             : 
     959             : {
     960     4022310 :     dfXOut = ((dfX - m_dfDstXOff) / m_dfDstXSize) * m_dfSrcXSize + m_dfSrcXOff;
     961     4022310 :     dfYOut = ((dfY - m_dfDstYOff) / m_dfDstYSize) * m_dfSrcYSize + m_dfSrcYOff;
     962     4022310 : }
     963             : 
     964             : /************************************************************************/
     965             : /*                          GetSrcDstWindow()                           */
     966             : /************************************************************************/
     967             : 
     968      380781 : int VRTSimpleSource::GetSrcDstWindow(
     969             :     double dfXOff, double dfYOff, double dfXSize, double dfYSize, int nBufXSize,
     970             :     int nBufYSize, double *pdfReqXOff, double *pdfReqYOff, double *pdfReqXSize,
     971             :     double *pdfReqYSize, int *pnReqXOff, int *pnReqYOff, int *pnReqXSize,
     972             :     int *pnReqYSize, int *pnOutXOff, int *pnOutYOff, int *pnOutXSize,
     973             :     int *pnOutYSize, bool &bErrorOut)
     974             : 
     975             : {
     976      380781 :     bErrorOut = false;
     977             : 
     978      380781 :     if (m_dfSrcXSize == 0.0 || m_dfSrcYSize == 0.0 || m_dfDstXSize == 0.0 ||
     979      380781 :         m_dfDstYSize == 0.0)
     980             :     {
     981           0 :         return FALSE;
     982             :     }
     983             : 
     984      380781 :     const bool bDstWinSet = IsDstWinSet();
     985             : 
     986             : #ifdef DEBUG
     987      380781 :     const bool bSrcWinSet = IsSrcWinSet();
     988             : 
     989      380781 :     if (bSrcWinSet != bDstWinSet)
     990             :     {
     991           0 :         return FALSE;
     992             :     }
     993             : #endif
     994             : 
     995             :     /* -------------------------------------------------------------------- */
     996             :     /*      If the input window completely misses the portion of the        */
     997             :     /*      virtual dataset provided by this source we have nothing to do.  */
     998             :     /* -------------------------------------------------------------------- */
     999      380781 :     if (bDstWinSet)
    1000             :     {
    1001      277728 :         if (dfXOff >= m_dfDstXOff + m_dfDstXSize ||
    1002      267300 :             dfYOff >= m_dfDstYOff + m_dfDstYSize ||
    1003      265822 :             dfXOff + dfXSize <= m_dfDstXOff || dfYOff + dfYSize <= m_dfDstYOff)
    1004       21253 :             return FALSE;
    1005             :     }
    1006             : 
    1007             :     /* -------------------------------------------------------------------- */
    1008             :     /*      This request window corresponds to the whole output buffer.     */
    1009             :     /* -------------------------------------------------------------------- */
    1010      359528 :     *pnOutXOff = 0;
    1011      359528 :     *pnOutYOff = 0;
    1012      359528 :     *pnOutXSize = nBufXSize;
    1013      359528 :     *pnOutYSize = nBufYSize;
    1014             : 
    1015             :     /* -------------------------------------------------------------------- */
    1016             :     /*      If the input window extents outside the portion of the on       */
    1017             :     /*      the virtual file that this source can set, then clip down       */
    1018             :     /*      the requested window.                                           */
    1019             :     /* -------------------------------------------------------------------- */
    1020      359528 :     bool bModifiedX = false;
    1021      359528 :     bool bModifiedY = false;
    1022      359528 :     double dfRXOff = dfXOff;
    1023      359528 :     double dfRYOff = dfYOff;
    1024      359528 :     double dfRXSize = dfXSize;
    1025      359528 :     double dfRYSize = dfYSize;
    1026             : 
    1027      359528 :     if (bDstWinSet)
    1028             :     {
    1029      256475 :         if (dfRXOff < m_dfDstXOff)
    1030             :         {
    1031        1880 :             dfRXSize = dfRXSize + dfRXOff - m_dfDstXOff;
    1032        1880 :             dfRXOff = m_dfDstXOff;
    1033        1880 :             bModifiedX = true;
    1034             :         }
    1035             : 
    1036      256475 :         if (dfRYOff < m_dfDstYOff)
    1037             :         {
    1038         166 :             dfRYSize = dfRYSize + dfRYOff - m_dfDstYOff;
    1039         166 :             dfRYOff = m_dfDstYOff;
    1040         166 :             bModifiedY = true;
    1041             :         }
    1042             : 
    1043      256475 :         if (dfRXOff + dfRXSize > m_dfDstXOff + m_dfDstXSize)
    1044             :         {
    1045        3572 :             dfRXSize = m_dfDstXOff + m_dfDstXSize - dfRXOff;
    1046        3572 :             bModifiedX = true;
    1047             :         }
    1048             : 
    1049      256475 :         if (dfRYOff + dfRYSize > m_dfDstYOff + m_dfDstYSize)
    1050             :         {
    1051         324 :             dfRYSize = m_dfDstYOff + m_dfDstYSize - dfRYOff;
    1052         324 :             bModifiedY = true;
    1053             :         }
    1054             :     }
    1055             : 
    1056             :     /* -------------------------------------------------------------------- */
    1057             :     /*      Translate requested region in virtual file into the source      */
    1058             :     /*      band coordinates.                                               */
    1059             :     /* -------------------------------------------------------------------- */
    1060      359528 :     const double dfScaleX = m_dfSrcXSize / m_dfDstXSize;
    1061      359528 :     const double dfScaleY = m_dfSrcYSize / m_dfDstYSize;
    1062             : 
    1063      359528 :     *pdfReqXOff = (dfRXOff - m_dfDstXOff) * dfScaleX + m_dfSrcXOff;
    1064      359528 :     *pdfReqYOff = (dfRYOff - m_dfDstYOff) * dfScaleY + m_dfSrcYOff;
    1065      359528 :     *pdfReqXSize = dfRXSize * dfScaleX;
    1066      359528 :     *pdfReqYSize = dfRYSize * dfScaleY;
    1067             : 
    1068      719056 :     if (!std::isfinite(*pdfReqXOff) || !std::isfinite(*pdfReqYOff) ||
    1069      359528 :         !std::isfinite(*pdfReqXSize) || !std::isfinite(*pdfReqYSize) ||
    1070     1078580 :         *pdfReqXOff > INT_MAX || *pdfReqYOff > INT_MAX || *pdfReqXSize < 0 ||
    1071      359528 :         *pdfReqYSize < 0)
    1072             :     {
    1073           0 :         return FALSE;
    1074             :     }
    1075             : 
    1076             :     /* -------------------------------------------------------------------- */
    1077             :     /*      Clamp within the bounds of the available source data.           */
    1078             :     /* -------------------------------------------------------------------- */
    1079      359528 :     if (*pdfReqXOff < 0)
    1080             :     {
    1081           9 :         *pdfReqXSize += *pdfReqXOff;
    1082           9 :         *pdfReqXOff = 0;
    1083           9 :         bModifiedX = true;
    1084             :     }
    1085      359528 :     if (*pdfReqYOff < 0)
    1086             :     {
    1087           6 :         *pdfReqYSize += *pdfReqYOff;
    1088           6 :         *pdfReqYOff = 0;
    1089           6 :         bModifiedY = true;
    1090             :     }
    1091             : 
    1092      359528 :     *pnReqXOff = static_cast<int>(floor(*pdfReqXOff));
    1093      359528 :     *pnReqYOff = static_cast<int>(floor(*pdfReqYOff));
    1094             : 
    1095      359528 :     constexpr double EPS = 1e-3;
    1096      359528 :     constexpr double ONE_MINUS_EPS = 1.0 - EPS;
    1097      359528 :     if (*pdfReqXOff - *pnReqXOff > ONE_MINUS_EPS)
    1098             :     {
    1099           2 :         (*pnReqXOff)++;
    1100           2 :         *pdfReqXOff = *pnReqXOff;
    1101             :     }
    1102      359528 :     if (*pdfReqYOff - *pnReqYOff > ONE_MINUS_EPS)
    1103             :     {
    1104          18 :         (*pnReqYOff)++;
    1105          18 :         *pdfReqYOff = *pnReqYOff;
    1106             :     }
    1107             : 
    1108      359528 :     if (*pdfReqXSize > INT_MAX)
    1109           0 :         *pnReqXSize = INT_MAX;
    1110             :     else
    1111      359528 :         *pnReqXSize = static_cast<int>(floor(*pdfReqXSize + 0.5));
    1112             : 
    1113      359528 :     if (*pdfReqYSize > INT_MAX)
    1114           0 :         *pnReqYSize = INT_MAX;
    1115             :     else
    1116      359528 :         *pnReqYSize = static_cast<int>(floor(*pdfReqYSize + 0.5));
    1117             : 
    1118             :     /* -------------------------------------------------------------------- */
    1119             :     /*      Clamp within the bounds of the available source data.           */
    1120             :     /* -------------------------------------------------------------------- */
    1121             : 
    1122      359528 :     if (*pnReqXSize == 0)
    1123         675 :         *pnReqXSize = 1;
    1124      359528 :     if (*pnReqYSize == 0)
    1125       22678 :         *pnReqYSize = 1;
    1126             : 
    1127      359528 :     auto l_band = GetRasterBand();
    1128      359528 :     if (!l_band)
    1129             :     {
    1130          88 :         bErrorOut = true;
    1131          88 :         return FALSE;
    1132             :     }
    1133      718880 :     if (*pnReqXSize > INT_MAX - *pnReqXOff ||
    1134      359439 :         *pnReqXOff + *pnReqXSize > l_band->GetXSize())
    1135             :     {
    1136         248 :         *pnReqXSize = l_band->GetXSize() - *pnReqXOff;
    1137         248 :         bModifiedX = true;
    1138             :     }
    1139      359441 :     if (*pdfReqXOff + *pdfReqXSize > l_band->GetXSize())
    1140             :     {
    1141         248 :         *pdfReqXSize = l_band->GetXSize() - *pdfReqXOff;
    1142         248 :         bModifiedX = true;
    1143             :     }
    1144             : 
    1145      718879 :     if (*pnReqYSize > INT_MAX - *pnReqYOff ||
    1146      359440 :         *pnReqYOff + *pnReqYSize > l_band->GetYSize())
    1147             :     {
    1148          48 :         *pnReqYSize = l_band->GetYSize() - *pnReqYOff;
    1149          48 :         bModifiedY = true;
    1150             :     }
    1151      359439 :     if (*pdfReqYOff + *pdfReqYSize > l_band->GetYSize())
    1152             :     {
    1153          66 :         *pdfReqYSize = l_band->GetYSize() - *pdfReqYOff;
    1154          66 :         bModifiedY = true;
    1155             :     }
    1156             : 
    1157             :     /* -------------------------------------------------------------------- */
    1158             :     /*      Don't do anything if the requesting region is completely off    */
    1159             :     /*      the source image.                                               */
    1160             :     /* -------------------------------------------------------------------- */
    1161      718876 :     if (*pnReqXOff >= l_band->GetXSize() || *pnReqYOff >= l_band->GetYSize() ||
    1162      718876 :         *pnReqXSize <= 0 || *pnReqYSize <= 0)
    1163             :     {
    1164          12 :         return FALSE;
    1165             :     }
    1166             : 
    1167             :     /* -------------------------------------------------------------------- */
    1168             :     /*      If we haven't had to modify the source rectangle, then the      */
    1169             :     /*      destination rectangle must be the whole region.                 */
    1170             :     /* -------------------------------------------------------------------- */
    1171      359427 :     if (bModifiedX || bModifiedY)
    1172             :     {
    1173             :         /* --------------------------------------------------------------------
    1174             :          */
    1175             :         /*      Now transform this possibly reduced request back into the */
    1176             :         /*      destination buffer coordinates in case the output region is */
    1177             :         /*      less than the whole buffer. */
    1178             :         /* --------------------------------------------------------------------
    1179             :          */
    1180        5121 :         double dfDstULX = 0.0;
    1181        5121 :         double dfDstULY = 0.0;
    1182        5121 :         double dfDstLRX = 0.0;
    1183        5121 :         double dfDstLRY = 0.0;
    1184             : 
    1185        5121 :         SrcToDst(*pdfReqXOff, *pdfReqYOff, dfDstULX, dfDstULY);
    1186        5122 :         SrcToDst(*pdfReqXOff + *pdfReqXSize, *pdfReqYOff + *pdfReqYSize,
    1187             :                  dfDstLRX, dfDstLRY);
    1188             : #if DEBUG_VERBOSE
    1189             :         CPLDebug("VRT", "dfDstULX=%g dfDstULY=%g dfDstLRX=%g dfDstLRY=%g",
    1190             :                  dfDstULX, dfDstULY, dfDstLRX, dfDstLRY);
    1191             : #endif
    1192             : 
    1193        5122 :         if (bModifiedX)
    1194             :         {
    1195        5070 :             const double dfScaleWinToBufX = nBufXSize / dfXSize;
    1196             : 
    1197        5070 :             const double dfOutXOff = (dfDstULX - dfXOff) * dfScaleWinToBufX;
    1198        5070 :             if (dfOutXOff <= 0)
    1199        3193 :                 *pnOutXOff = 0;
    1200        1877 :             else if (dfOutXOff > INT_MAX)
    1201           0 :                 *pnOutXOff = INT_MAX;
    1202             :             else
    1203        1877 :                 *pnOutXOff = static_cast<int>(dfOutXOff + EPS);
    1204             : 
    1205             :             // Apply correction on floating-point source window
    1206             :             {
    1207        5070 :                 double dfDstDeltaX =
    1208        5070 :                     (dfOutXOff - *pnOutXOff) / dfScaleWinToBufX;
    1209        5070 :                 double dfSrcDeltaX = dfDstDeltaX / m_dfDstXSize * m_dfSrcXSize;
    1210        5070 :                 *pdfReqXOff -= dfSrcDeltaX;
    1211       10141 :                 *pdfReqXSize = std::min(*pdfReqXSize + dfSrcDeltaX,
    1212        5070 :                                         static_cast<double>(INT_MAX));
    1213             :             }
    1214             : 
    1215        5071 :             double dfOutRightXOff = (dfDstLRX - dfXOff) * dfScaleWinToBufX;
    1216        5071 :             if (dfOutRightXOff < dfOutXOff)
    1217           1 :                 return FALSE;
    1218        5071 :             if (dfOutRightXOff > INT_MAX)
    1219           0 :                 dfOutRightXOff = INT_MAX;
    1220        5071 :             const int nOutRightXOff =
    1221        5071 :                 static_cast<int>(ceil(dfOutRightXOff - EPS));
    1222        5071 :             *pnOutXSize = nOutRightXOff - *pnOutXOff;
    1223             : 
    1224        5071 :             if (*pnOutXSize > INT_MAX - *pnOutXOff ||
    1225        5070 :                 *pnOutXOff + *pnOutXSize > nBufXSize)
    1226           0 :                 *pnOutXSize = nBufXSize - *pnOutXOff;
    1227             : 
    1228             :             // Apply correction on floating-point source window
    1229             :             {
    1230        5071 :                 double dfDstDeltaX =
    1231        5071 :                     (nOutRightXOff - dfOutRightXOff) / dfScaleWinToBufX;
    1232        5071 :                 double dfSrcDeltaX = dfDstDeltaX / m_dfDstXSize * m_dfSrcXSize;
    1233       10141 :                 *pdfReqXSize = std::min(*pdfReqXSize + dfSrcDeltaX,
    1234        5071 :                                         static_cast<double>(INT_MAX));
    1235             :             }
    1236             :         }
    1237             : 
    1238        5122 :         if (bModifiedY)
    1239             :         {
    1240         435 :             const double dfScaleWinToBufY = nBufYSize / dfYSize;
    1241             : 
    1242         435 :             const double dfOutYOff = (dfDstULY - dfYOff) * dfScaleWinToBufY;
    1243         435 :             if (dfOutYOff <= 0)
    1244         252 :                 *pnOutYOff = 0;
    1245         183 :             else if (dfOutYOff > INT_MAX)
    1246           0 :                 *pnOutYOff = INT_MAX;
    1247             :             else
    1248         183 :                 *pnOutYOff = static_cast<int>(dfOutYOff + EPS);
    1249             : 
    1250             :             // Apply correction on floating-point source window
    1251             :             {
    1252         435 :                 double dfDstDeltaY =
    1253         435 :                     (dfOutYOff - *pnOutYOff) / dfScaleWinToBufY;
    1254         435 :                 double dfSrcDeltaY = dfDstDeltaY / m_dfDstYSize * m_dfSrcYSize;
    1255         435 :                 *pdfReqYOff -= dfSrcDeltaY;
    1256         870 :                 *pdfReqYSize = std::min(*pdfReqYSize + dfSrcDeltaY,
    1257         435 :                                         static_cast<double>(INT_MAX));
    1258             :             }
    1259             : 
    1260         435 :             double dfOutTopYOff = (dfDstLRY - dfYOff) * dfScaleWinToBufY;
    1261         435 :             if (dfOutTopYOff < dfOutYOff)
    1262           0 :                 return FALSE;
    1263         435 :             if (dfOutTopYOff > INT_MAX)
    1264           0 :                 dfOutTopYOff = INT_MAX;
    1265         435 :             const int nOutTopYOff = static_cast<int>(ceil(dfOutTopYOff - EPS));
    1266         435 :             *pnOutYSize = nOutTopYOff - *pnOutYOff;
    1267             : 
    1268         435 :             if (*pnOutYSize > INT_MAX - *pnOutYOff ||
    1269         435 :                 *pnOutYOff + *pnOutYSize > nBufYSize)
    1270           0 :                 *pnOutYSize = nBufYSize - *pnOutYOff;
    1271             : 
    1272             :             // Apply correction on floating-point source window
    1273             :             {
    1274         435 :                 double dfDstDeltaY =
    1275         435 :                     (nOutTopYOff - dfOutTopYOff) / dfScaleWinToBufY;
    1276         435 :                 double dfSrcDeltaY = dfDstDeltaY / m_dfDstYSize * m_dfSrcYSize;
    1277         870 :                 *pdfReqYSize = std::min(*pdfReqYSize + dfSrcDeltaY,
    1278         435 :                                         static_cast<double>(INT_MAX));
    1279             :             }
    1280             :         }
    1281             : 
    1282        5122 :         if (*pnOutXSize < 1 || *pnOutYSize < 1)
    1283           1 :             return FALSE;
    1284             :     }
    1285             : 
    1286      359427 :     *pdfReqXOff = RoundIfCloseToInt(*pdfReqXOff);
    1287      359428 :     *pdfReqYOff = RoundIfCloseToInt(*pdfReqYOff);
    1288      359428 :     *pdfReqXSize = RoundIfCloseToInt(*pdfReqXSize);
    1289      359428 :     *pdfReqYSize = RoundIfCloseToInt(*pdfReqYSize);
    1290             : 
    1291      359428 :     return TRUE;
    1292             : }
    1293             : 
    1294             : /************************************************************************/
    1295             : /*                          NeedMaxValAdjustment()                      */
    1296             : /************************************************************************/
    1297             : 
    1298      347205 : int VRTSimpleSource::NeedMaxValAdjustment() const
    1299             : {
    1300      347205 :     if (!m_nMaxValue)
    1301      347183 :         return FALSE;
    1302             : 
    1303          22 :     auto l_band = GetRasterBand();
    1304          22 :     if (!l_band)
    1305           0 :         return FALSE;
    1306          22 :     const char *pszNBITS = l_band->GetMetadataItem("NBITS", "IMAGE_STRUCTURE");
    1307          22 :     const int nBits = (pszNBITS) ? atoi(pszNBITS) : 0;
    1308          22 :     if (nBits >= 1 && nBits <= 31)
    1309             :     {
    1310           0 :         const int nBandMaxValue = static_cast<int>((1U << nBits) - 1);
    1311           0 :         return nBandMaxValue > m_nMaxValue;
    1312             :     }
    1313          22 :     return TRUE;
    1314             : }
    1315             : 
    1316             : /************************************************************************/
    1317             : /*                              RasterIO()                              */
    1318             : /************************************************************************/
    1319             : 
    1320      352143 : CPLErr VRTSimpleSource::RasterIO(GDALDataType eVRTBandDataType, int nXOff,
    1321             :                                  int nYOff, int nXSize, int nYSize, void *pData,
    1322             :                                  int nBufXSize, int nBufYSize,
    1323             :                                  GDALDataType eBufType, GSpacing nPixelSpace,
    1324             :                                  GSpacing nLineSpace,
    1325             :                                  GDALRasterIOExtraArg *psExtraArgIn,
    1326             :                                  WorkingState & /*oWorkingState*/)
    1327             : 
    1328             : {
    1329             :     GDALRasterIOExtraArg sExtraArg;
    1330      352143 :     INIT_RASTERIO_EXTRA_ARG(sExtraArg);
    1331      352143 :     GDALRasterIOExtraArg *psExtraArg = &sExtraArg;
    1332             : 
    1333      352143 :     double dfXOff = nXOff;
    1334      352143 :     double dfYOff = nYOff;
    1335      352143 :     double dfXSize = nXSize;
    1336      352143 :     double dfYSize = nYSize;
    1337      352143 :     if (psExtraArgIn != nullptr && psExtraArgIn->bFloatingPointWindowValidity)
    1338             :     {
    1339         260 :         dfXOff = psExtraArgIn->dfXOff;
    1340         260 :         dfYOff = psExtraArgIn->dfYOff;
    1341         260 :         dfXSize = psExtraArgIn->dfXSize;
    1342         260 :         dfYSize = psExtraArgIn->dfYSize;
    1343             :     }
    1344             : 
    1345             :     // The window we will actually request from the source raster band.
    1346      352143 :     double dfReqXOff = 0.0;
    1347      352143 :     double dfReqYOff = 0.0;
    1348      352143 :     double dfReqXSize = 0.0;
    1349      352143 :     double dfReqYSize = 0.0;
    1350      352143 :     int nReqXOff = 0;
    1351      352143 :     int nReqYOff = 0;
    1352      352143 :     int nReqXSize = 0;
    1353      352143 :     int nReqYSize = 0;
    1354             : 
    1355             :     // The window we will actual set _within_ the pData buffer.
    1356      352143 :     int nOutXOff = 0;
    1357      352143 :     int nOutYOff = 0;
    1358      352143 :     int nOutXSize = 0;
    1359      352143 :     int nOutYSize = 0;
    1360             : 
    1361      352143 :     bool bError = false;
    1362      352143 :     if (!GetSrcDstWindow(dfXOff, dfYOff, dfXSize, dfYSize, nBufXSize, nBufYSize,
    1363             :                          &dfReqXOff, &dfReqYOff, &dfReqXSize, &dfReqYSize,
    1364             :                          &nReqXOff, &nReqYOff, &nReqXSize, &nReqYSize,
    1365             :                          &nOutXOff, &nOutYOff, &nOutXSize, &nOutYSize, bError))
    1366             :     {
    1367        9489 :         return bError ? CE_Failure : CE_None;
    1368             :     }
    1369             : #if DEBUG_VERBOSE
    1370             :     CPLDebug("VRT",
    1371             :              "nXOff=%d, nYOff=%d, nXSize=%d, nYSize=%d, nBufXSize=%d, "
    1372             :              "nBufYSize=%d,\n"
    1373             :              "dfReqXOff=%g, dfReqYOff=%g, dfReqXSize=%g, dfReqYSize=%g,\n"
    1374             :              "nReqXOff=%d, nReqYOff=%d, nReqXSize=%d, nReqYSize=%d,\n"
    1375             :              "nOutXOff=%d, nOutYOff=%d, nOutXSize=%d, nOutYSize=%d",
    1376             :              nXOff, nYOff, nXSize, nYSize, nBufXSize, nBufYSize, dfReqXOff,
    1377             :              dfReqYOff, dfReqXSize, dfReqYSize, nReqXOff, nReqYOff, nReqXSize,
    1378             :              nReqYSize, nOutXOff, nOutYOff, nOutXSize, nOutYSize);
    1379             : #endif
    1380             : 
    1381             :     /* -------------------------------------------------------------------- */
    1382             :     /*      Actually perform the IO request.                                */
    1383             :     /* -------------------------------------------------------------------- */
    1384      342654 :     if (!m_osResampling.empty())
    1385             :     {
    1386      202606 :         psExtraArg->eResampleAlg = GDALRasterIOGetResampleAlg(m_osResampling);
    1387             :     }
    1388      140048 :     else if (psExtraArgIn != nullptr)
    1389             :     {
    1390      140048 :         psExtraArg->eResampleAlg = psExtraArgIn->eResampleAlg;
    1391             :     }
    1392      342654 :     psExtraArg->bFloatingPointWindowValidity = TRUE;
    1393      342654 :     psExtraArg->dfXOff = dfReqXOff;
    1394      342654 :     psExtraArg->dfYOff = dfReqYOff;
    1395      342654 :     psExtraArg->dfXSize = dfReqXSize;
    1396      342654 :     psExtraArg->dfYSize = dfReqYSize;
    1397      342654 :     if (psExtraArgIn)
    1398             :     {
    1399      342654 :         psExtraArg->pfnProgress = psExtraArgIn->pfnProgress;
    1400      342654 :         psExtraArg->pProgressData = psExtraArgIn->pProgressData;
    1401      342654 :         if (psExtraArgIn->nVersion >= 2)
    1402             :         {
    1403      342654 :             psExtraArg->bUseOnlyThisScale = psExtraArgIn->bUseOnlyThisScale;
    1404             :         }
    1405             :     }
    1406             : 
    1407      342654 :     GByte *pabyOut = static_cast<unsigned char *>(pData) +
    1408      342654 :                      nOutXOff * nPixelSpace +
    1409      342654 :                      static_cast<GPtrDiff_t>(nOutYOff) * nLineSpace;
    1410             : 
    1411      342654 :     auto l_band = GetRasterBand();
    1412      342654 :     if (!l_band)
    1413           0 :         return CE_Failure;
    1414             : 
    1415      342654 :     CPLErr eErr = CE_Failure;
    1416      342654 :     if (GDALDataTypeIsConversionLossy(l_band->GetRasterDataType(),
    1417      342653 :                                       eVRTBandDataType))
    1418             :     {
    1419        1218 :         const int nBandDTSize = GDALGetDataTypeSizeBytes(eVRTBandDataType);
    1420        1218 :         void *pTemp = VSI_MALLOC3_VERBOSE(nOutXSize, nOutYSize, nBandDTSize);
    1421        1218 :         if (pTemp)
    1422             :         {
    1423        1218 :             eErr = l_band->RasterIO(GF_Read, nReqXOff, nReqYOff, nReqXSize,
    1424             :                                     nReqYSize, pTemp, nOutXSize, nOutYSize,
    1425             :                                     eVRTBandDataType, 0, 0, psExtraArg);
    1426        1218 :             if (eErr == CE_None)
    1427             :             {
    1428        1218 :                 GByte *pabyTemp = static_cast<GByte *>(pTemp);
    1429        4350 :                 for (int iY = 0; iY < nOutYSize; iY++)
    1430             :                 {
    1431        3132 :                     GDALCopyWords(
    1432        3132 :                         pabyTemp +
    1433        3132 :                             static_cast<size_t>(iY) * nBandDTSize * nOutXSize,
    1434             :                         eVRTBandDataType, nBandDTSize,
    1435        3132 :                         pabyOut + static_cast<GPtrDiff_t>(iY * nLineSpace),
    1436             :                         eBufType, static_cast<int>(nPixelSpace), nOutXSize);
    1437             :                 }
    1438             :             }
    1439        1218 :             VSIFree(pTemp);
    1440             :         }
    1441             :     }
    1442             :     else
    1443             :     {
    1444      341435 :         eErr = l_band->RasterIO(GF_Read, nReqXOff, nReqYOff, nReqXSize,
    1445             :                                 nReqYSize, pabyOut, nOutXSize, nOutYSize,
    1446             :                                 eBufType, nPixelSpace, nLineSpace, psExtraArg);
    1447             :     }
    1448             : 
    1449      342654 :     if (NeedMaxValAdjustment())
    1450             :     {
    1451         234 :         for (int j = 0; j < nOutYSize; j++)
    1452             :         {
    1453        4620 :             for (int i = 0; i < nOutXSize; i++)
    1454             :             {
    1455        4400 :                 int nVal = 0;
    1456        4400 :                 GDALCopyWords(pabyOut + j * nLineSpace + i * nPixelSpace,
    1457             :                               eBufType, 0, &nVal, GDT_Int32, 0, 1);
    1458        4400 :                 if (nVal > m_nMaxValue)
    1459         800 :                     nVal = m_nMaxValue;
    1460        4400 :                 GDALCopyWords(&nVal, GDT_Int32, 0,
    1461        4400 :                               pabyOut + j * nLineSpace + i * nPixelSpace,
    1462             :                               eBufType, 0, 1);
    1463             :             }
    1464             :         }
    1465             :     }
    1466             : 
    1467      342654 :     if (psExtraArg->pfnProgress)
    1468         492 :         psExtraArg->pfnProgress(1.0, "", psExtraArg->pProgressData);
    1469             : 
    1470      342654 :     return eErr;
    1471             : }
    1472             : 
    1473             : /************************************************************************/
    1474             : /*                             GetMinimum()                             */
    1475             : /************************************************************************/
    1476             : 
    1477          52 : double VRTSimpleSource::GetMinimum(int nXSize, int nYSize, int *pbSuccess)
    1478             : {
    1479             :     // The window we will actually request from the source raster band.
    1480          52 :     double dfReqXOff = 0.0;
    1481          52 :     double dfReqYOff = 0.0;
    1482          52 :     double dfReqXSize = 0.0;
    1483          52 :     double dfReqYSize = 0.0;
    1484          52 :     int nReqXOff = 0;
    1485          52 :     int nReqYOff = 0;
    1486          52 :     int nReqXSize = 0;
    1487          52 :     int nReqYSize = 0;
    1488             : 
    1489             :     // The window we will actual set _within_ the pData buffer.
    1490          52 :     int nOutXOff = 0;
    1491          52 :     int nOutYOff = 0;
    1492          52 :     int nOutXSize = 0;
    1493          52 :     int nOutYSize = 0;
    1494             : 
    1495          52 :     bool bError = false;
    1496          52 :     auto l_band = GetRasterBand();
    1497         104 :     if (!l_band ||
    1498          52 :         !GetSrcDstWindow(0, 0, nXSize, nYSize, nXSize, nYSize, &dfReqXOff,
    1499             :                          &dfReqYOff, &dfReqXSize, &dfReqYSize, &nReqXOff,
    1500             :                          &nReqYOff, &nReqXSize, &nReqYSize, &nOutXOff,
    1501          52 :                          &nOutYOff, &nOutXSize, &nOutYSize, bError) ||
    1502         156 :         nReqXOff != 0 || nReqYOff != 0 || nReqXSize != l_band->GetXSize() ||
    1503          52 :         nReqYSize != l_band->GetYSize())
    1504             :     {
    1505           0 :         *pbSuccess = FALSE;
    1506           0 :         return 0;
    1507             :     }
    1508             : 
    1509          52 :     const double dfVal = l_band->GetMinimum(pbSuccess);
    1510          52 :     if (NeedMaxValAdjustment() && dfVal > m_nMaxValue)
    1511           2 :         return m_nMaxValue;
    1512          50 :     return dfVal;
    1513             : }
    1514             : 
    1515             : /************************************************************************/
    1516             : /*                             GetMaximum()                             */
    1517             : /************************************************************************/
    1518             : 
    1519          51 : double VRTSimpleSource::GetMaximum(int nXSize, int nYSize, int *pbSuccess)
    1520             : {
    1521             :     // The window we will actually request from the source raster band.
    1522          51 :     double dfReqXOff = 0.0;
    1523          51 :     double dfReqYOff = 0.0;
    1524          51 :     double dfReqXSize = 0.0;
    1525          51 :     double dfReqYSize = 0.0;
    1526          51 :     int nReqXOff = 0;
    1527          51 :     int nReqYOff = 0;
    1528          51 :     int nReqXSize = 0;
    1529          51 :     int nReqYSize = 0;
    1530             : 
    1531             :     // The window we will actual set _within_ the pData buffer.
    1532          51 :     int nOutXOff = 0;
    1533          51 :     int nOutYOff = 0;
    1534          51 :     int nOutXSize = 0;
    1535          51 :     int nOutYSize = 0;
    1536             : 
    1537          51 :     bool bError = false;
    1538          51 :     auto l_band = GetRasterBand();
    1539         102 :     if (!l_band ||
    1540          51 :         !GetSrcDstWindow(0, 0, nXSize, nYSize, nXSize, nYSize, &dfReqXOff,
    1541             :                          &dfReqYOff, &dfReqXSize, &dfReqYSize, &nReqXOff,
    1542             :                          &nReqYOff, &nReqXSize, &nReqYSize, &nOutXOff,
    1543          51 :                          &nOutYOff, &nOutXSize, &nOutYSize, bError) ||
    1544         153 :         nReqXOff != 0 || nReqYOff != 0 || nReqXSize != l_band->GetXSize() ||
    1545          51 :         nReqYSize != l_band->GetYSize())
    1546             :     {
    1547           0 :         *pbSuccess = FALSE;
    1548           0 :         return 0;
    1549             :     }
    1550             : 
    1551          51 :     const double dfVal = l_band->GetMaximum(pbSuccess);
    1552          51 :     if (NeedMaxValAdjustment() && dfVal > m_nMaxValue)
    1553           2 :         return m_nMaxValue;
    1554          49 :     return dfVal;
    1555             : }
    1556             : 
    1557             : /************************************************************************/
    1558             : /*                            GetHistogram()                            */
    1559             : /************************************************************************/
    1560             : 
    1561           4 : CPLErr VRTSimpleSource::GetHistogram(int nXSize, int nYSize, double dfMin,
    1562             :                                      double dfMax, int nBuckets,
    1563             :                                      GUIntBig *panHistogram,
    1564             :                                      int bIncludeOutOfRange, int bApproxOK,
    1565             :                                      GDALProgressFunc pfnProgress,
    1566             :                                      void *pProgressData)
    1567             : {
    1568             :     // The window we will actually request from the source raster band.
    1569           4 :     double dfReqXOff = 0.0;
    1570           4 :     double dfReqYOff = 0.0;
    1571           4 :     double dfReqXSize = 0.0;
    1572           4 :     double dfReqYSize = 0.0;
    1573           4 :     int nReqXOff = 0;
    1574           4 :     int nReqYOff = 0;
    1575           4 :     int nReqXSize = 0;
    1576           4 :     int nReqYSize = 0;
    1577             : 
    1578             :     // The window we will actual set _within_ the pData buffer.
    1579           4 :     int nOutXOff = 0;
    1580           4 :     int nOutYOff = 0;
    1581           4 :     int nOutXSize = 0;
    1582           4 :     int nOutYSize = 0;
    1583             : 
    1584           4 :     bool bError = false;
    1585           4 :     auto l_band = GetRasterBand();
    1586           4 :     if (!l_band || NeedMaxValAdjustment() ||
    1587           4 :         !GetSrcDstWindow(0, 0, nXSize, nYSize, nXSize, nYSize, &dfReqXOff,
    1588             :                          &dfReqYOff, &dfReqXSize, &dfReqYSize, &nReqXOff,
    1589             :                          &nReqYOff, &nReqXSize, &nReqYSize, &nOutXOff,
    1590           4 :                          &nOutYOff, &nOutXSize, &nOutYSize, bError) ||
    1591          12 :         nReqXOff != 0 || nReqYOff != 0 || nReqXSize != l_band->GetXSize() ||
    1592           4 :         nReqYSize != l_band->GetYSize())
    1593             :     {
    1594           0 :         return CE_Failure;
    1595             :     }
    1596             : 
    1597           4 :     return l_band->GetHistogram(dfMin, dfMax, nBuckets, panHistogram,
    1598             :                                 bIncludeOutOfRange, bApproxOK, pfnProgress,
    1599           4 :                                 pProgressData);
    1600             : }
    1601             : 
    1602             : /************************************************************************/
    1603             : /*                          DatasetRasterIO()                           */
    1604             : /************************************************************************/
    1605             : 
    1606        5220 : CPLErr VRTSimpleSource::DatasetRasterIO(
    1607             :     GDALDataType eVRTBandDataType, int nXOff, int nYOff, int nXSize, int nYSize,
    1608             :     void *pData, int nBufXSize, int nBufYSize, GDALDataType eBufType,
    1609             :     int nBandCount, const int *panBandMap, GSpacing nPixelSpace,
    1610             :     GSpacing nLineSpace, GSpacing nBandSpace,
    1611             :     GDALRasterIOExtraArg *psExtraArgIn)
    1612             : {
    1613        5220 :     if (GetType() != VRTSimpleSource::GetTypeStatic())
    1614             :     {
    1615           0 :         CPLError(CE_Failure, CPLE_NotSupported,
    1616           0 :                  "DatasetRasterIO() not implemented for %s", GetType());
    1617           0 :         return CE_Failure;
    1618             :     }
    1619             : 
    1620             :     GDALRasterIOExtraArg sExtraArg;
    1621        5220 :     INIT_RASTERIO_EXTRA_ARG(sExtraArg);
    1622        5220 :     GDALRasterIOExtraArg *psExtraArg = &sExtraArg;
    1623             : 
    1624        5220 :     double dfXOff = nXOff;
    1625        5220 :     double dfYOff = nYOff;
    1626        5220 :     double dfXSize = nXSize;
    1627        5220 :     double dfYSize = nYSize;
    1628        5220 :     if (psExtraArgIn != nullptr && psExtraArgIn->bFloatingPointWindowValidity)
    1629             :     {
    1630          11 :         dfXOff = psExtraArgIn->dfXOff;
    1631          11 :         dfYOff = psExtraArgIn->dfYOff;
    1632          11 :         dfXSize = psExtraArgIn->dfXSize;
    1633          11 :         dfYSize = psExtraArgIn->dfYSize;
    1634             :     }
    1635             : 
    1636             :     // The window we will actually request from the source raster band.
    1637        5220 :     double dfReqXOff = 0.0;
    1638        5220 :     double dfReqYOff = 0.0;
    1639        5220 :     double dfReqXSize = 0.0;
    1640        5220 :     double dfReqYSize = 0.0;
    1641        5220 :     int nReqXOff = 0;
    1642        5220 :     int nReqYOff = 0;
    1643        5220 :     int nReqXSize = 0;
    1644        5220 :     int nReqYSize = 0;
    1645             : 
    1646             :     // The window we will actual set _within_ the pData buffer.
    1647        5220 :     int nOutXOff = 0;
    1648        5220 :     int nOutYOff = 0;
    1649        5220 :     int nOutXSize = 0;
    1650        5220 :     int nOutYSize = 0;
    1651             : 
    1652        5220 :     bool bError = false;
    1653        5220 :     if (!GetSrcDstWindow(dfXOff, dfYOff, dfXSize, dfYSize, nBufXSize, nBufYSize,
    1654             :                          &dfReqXOff, &dfReqYOff, &dfReqXSize, &dfReqYSize,
    1655             :                          &nReqXOff, &nReqYOff, &nReqXSize, &nReqYSize,
    1656             :                          &nOutXOff, &nOutYOff, &nOutXSize, &nOutYSize, bError))
    1657             :     {
    1658         839 :         return bError ? CE_Failure : CE_None;
    1659             :     }
    1660             : 
    1661        4381 :     auto l_band = GetRasterBand();
    1662        4381 :     if (!l_band)
    1663           0 :         return CE_Failure;
    1664             : 
    1665        4381 :     GDALDataset *poDS = l_band->GetDataset();
    1666        4381 :     if (poDS == nullptr)
    1667           0 :         return CE_Failure;
    1668             : 
    1669        4381 :     if (!m_osResampling.empty())
    1670             :     {
    1671         788 :         psExtraArg->eResampleAlg = GDALRasterIOGetResampleAlg(m_osResampling);
    1672             :     }
    1673        3593 :     else if (psExtraArgIn != nullptr)
    1674             :     {
    1675        3593 :         psExtraArg->eResampleAlg = psExtraArgIn->eResampleAlg;
    1676             :     }
    1677        4381 :     psExtraArg->bFloatingPointWindowValidity = TRUE;
    1678        4381 :     psExtraArg->dfXOff = dfReqXOff;
    1679        4381 :     psExtraArg->dfYOff = dfReqYOff;
    1680        4381 :     psExtraArg->dfXSize = dfReqXSize;
    1681        4381 :     psExtraArg->dfYSize = dfReqYSize;
    1682        4381 :     if (psExtraArgIn)
    1683             :     {
    1684        4381 :         psExtraArg->pfnProgress = psExtraArgIn->pfnProgress;
    1685        4381 :         psExtraArg->pProgressData = psExtraArgIn->pProgressData;
    1686             :     }
    1687             : 
    1688        4381 :     GByte *pabyOut = static_cast<unsigned char *>(pData) +
    1689        4381 :                      nOutXOff * nPixelSpace +
    1690        4381 :                      static_cast<GPtrDiff_t>(nOutYOff) * nLineSpace;
    1691             : 
    1692        4381 :     CPLErr eErr = CE_Failure;
    1693             : 
    1694        4381 :     if (GDALDataTypeIsConversionLossy(l_band->GetRasterDataType(),
    1695        4380 :                                       eVRTBandDataType))
    1696             :     {
    1697           1 :         const int nBandDTSize = GDALGetDataTypeSizeBytes(eVRTBandDataType);
    1698           1 :         void *pTemp = VSI_MALLOC3_VERBOSE(
    1699             :             nOutXSize, nOutYSize, cpl::fits_on<int>(nBandDTSize * nBandCount));
    1700           1 :         if (pTemp)
    1701             :         {
    1702           1 :             eErr = poDS->RasterIO(GF_Read, nReqXOff, nReqYOff, nReqXSize,
    1703             :                                   nReqYSize, pTemp, nOutXSize, nOutYSize,
    1704             :                                   eVRTBandDataType, nBandCount, panBandMap, 0,
    1705             :                                   0, 0, psExtraArg);
    1706           1 :             if (eErr == CE_None)
    1707             :             {
    1708           1 :                 GByte *pabyTemp = static_cast<GByte *>(pTemp);
    1709           1 :                 const size_t nSrcBandSpace =
    1710           1 :                     static_cast<size_t>(nOutYSize) * nOutXSize * nBandDTSize;
    1711           2 :                 for (int iBand = 0; iBand < nBandCount; iBand++)
    1712             :                 {
    1713          21 :                     for (int iY = 0; iY < nOutYSize; iY++)
    1714             :                     {
    1715          20 :                         GDALCopyWords(
    1716          20 :                             pabyTemp + iBand * nSrcBandSpace +
    1717          20 :                                 static_cast<size_t>(iY) * nBandDTSize *
    1718          20 :                                     nOutXSize,
    1719             :                             eVRTBandDataType, nBandDTSize,
    1720          20 :                             pabyOut + static_cast<GPtrDiff_t>(
    1721          20 :                                           iY * nLineSpace + iBand * nBandSpace),
    1722             :                             eBufType, static_cast<int>(nPixelSpace), nOutXSize);
    1723             :                     }
    1724             :                 }
    1725             :             }
    1726           1 :             VSIFree(pTemp);
    1727             :         }
    1728             :     }
    1729             :     else
    1730             :     {
    1731        4379 :         eErr = poDS->RasterIO(GF_Read, nReqXOff, nReqYOff, nReqXSize, nReqYSize,
    1732             :                               pabyOut, nOutXSize, nOutYSize, eBufType,
    1733             :                               nBandCount, panBandMap, nPixelSpace, nLineSpace,
    1734             :                               nBandSpace, psExtraArg);
    1735             :     }
    1736             : 
    1737        4381 :     if (NeedMaxValAdjustment())
    1738             :     {
    1739           0 :         for (int k = 0; k < nBandCount; k++)
    1740             :         {
    1741           0 :             for (int j = 0; j < nOutYSize; j++)
    1742             :             {
    1743           0 :                 for (int i = 0; i < nOutXSize; i++)
    1744             :                 {
    1745           0 :                     int nVal = 0;
    1746           0 :                     GDALCopyWords(pabyOut + k * nBandSpace + j * nLineSpace +
    1747           0 :                                       i * nPixelSpace,
    1748             :                                   eBufType, 0, &nVal, GDT_Int32, 0, 1);
    1749             : 
    1750           0 :                     if (nVal > m_nMaxValue)
    1751           0 :                         nVal = m_nMaxValue;
    1752             : 
    1753           0 :                     GDALCopyWords(&nVal, GDT_Int32, 0,
    1754           0 :                                   pabyOut + k * nBandSpace + j * nLineSpace +
    1755           0 :                                       i * nPixelSpace,
    1756             :                                   eBufType, 0, 1);
    1757             :                 }
    1758             :             }
    1759             :         }
    1760             :     }
    1761             : 
    1762        4381 :     if (psExtraArg->pfnProgress)
    1763        3916 :         psExtraArg->pfnProgress(1.0, "", psExtraArg->pProgressData);
    1764             : 
    1765        4381 :     return eErr;
    1766             : }
    1767             : 
    1768             : /************************************************************************/
    1769             : /*                          SetResampling()                             */
    1770             : /************************************************************************/
    1771             : 
    1772       69957 : void VRTSimpleSource::SetResampling(const char *pszResampling)
    1773             : {
    1774       69957 :     m_osResampling = (pszResampling) ? pszResampling : "";
    1775       69957 : }
    1776             : 
    1777             : /************************************************************************/
    1778             : /* ==================================================================== */
    1779             : /*                         VRTAveragedSource                            */
    1780             : /* ==================================================================== */
    1781             : /************************************************************************/
    1782             : 
    1783             : /************************************************************************/
    1784             : /*                         VRTAveragedSource()                          */
    1785             : /************************************************************************/
    1786             : 
    1787          16 : VRTAveragedSource::VRTAveragedSource()
    1788             : {
    1789          16 : }
    1790             : 
    1791             : /************************************************************************/
    1792             : /*                           GetTypeStatic()                            */
    1793             : /************************************************************************/
    1794             : 
    1795      104116 : const char *VRTAveragedSource::GetTypeStatic()
    1796             : {
    1797             :     static const char *TYPE = "AveragedSource";
    1798      104116 :     return TYPE;
    1799             : }
    1800             : 
    1801             : /************************************************************************/
    1802             : /*                            GetType()                                 */
    1803             : /************************************************************************/
    1804             : 
    1805          11 : const char *VRTAveragedSource::GetType() const
    1806             : {
    1807          11 :     return GetTypeStatic();
    1808             : }
    1809             : 
    1810             : /************************************************************************/
    1811             : /*                           SerializeToXML()                           */
    1812             : /************************************************************************/
    1813             : 
    1814           0 : CPLXMLNode *VRTAveragedSource::SerializeToXML(const char *pszVRTPath)
    1815             : 
    1816             : {
    1817           0 :     CPLXMLNode *const psSrc = VRTSimpleSource::SerializeToXML(pszVRTPath);
    1818             : 
    1819           0 :     if (psSrc == nullptr)
    1820           0 :         return nullptr;
    1821             : 
    1822           0 :     CPLFree(psSrc->pszValue);
    1823           0 :     psSrc->pszValue = CPLStrdup(GetTypeStatic());
    1824             : 
    1825           0 :     return psSrc;
    1826             : }
    1827             : 
    1828             : /************************************************************************/
    1829             : /*                           SetNoDataValue()                           */
    1830             : /************************************************************************/
    1831             : 
    1832           0 : void VRTAveragedSource::SetNoDataValue(double dfNewNoDataValue)
    1833             : 
    1834             : {
    1835           0 :     if (dfNewNoDataValue == VRT_NODATA_UNSET)
    1836             :     {
    1837           0 :         m_bNoDataSet = FALSE;
    1838           0 :         m_dfNoDataValue = VRT_NODATA_UNSET;
    1839           0 :         return;
    1840             :     }
    1841             : 
    1842           0 :     m_bNoDataSet = TRUE;
    1843           0 :     m_dfNoDataValue = dfNewNoDataValue;
    1844             : }
    1845             : 
    1846             : /************************************************************************/
    1847             : /*                              RasterIO()                              */
    1848             : /************************************************************************/
    1849             : 
    1850          33 : CPLErr VRTAveragedSource::RasterIO(GDALDataType /*eVRTBandDataType*/, int nXOff,
    1851             :                                    int nYOff, int nXSize, int nYSize,
    1852             :                                    void *pData, int nBufXSize, int nBufYSize,
    1853             :                                    GDALDataType eBufType, GSpacing nPixelSpace,
    1854             :                                    GSpacing nLineSpace,
    1855             :                                    GDALRasterIOExtraArg *psExtraArgIn,
    1856             :                                    WorkingState & /*oWorkingState*/)
    1857             : 
    1858             : {
    1859             :     GDALRasterIOExtraArg sExtraArg;
    1860          33 :     INIT_RASTERIO_EXTRA_ARG(sExtraArg);
    1861          33 :     GDALRasterIOExtraArg *psExtraArg = &sExtraArg;
    1862             : 
    1863          33 :     double dfXOff = nXOff;
    1864          33 :     double dfYOff = nYOff;
    1865          33 :     double dfXSize = nXSize;
    1866          33 :     double dfYSize = nYSize;
    1867          33 :     if (psExtraArgIn != nullptr && psExtraArgIn->bFloatingPointWindowValidity)
    1868             :     {
    1869           0 :         dfXOff = psExtraArgIn->dfXOff;
    1870           0 :         dfYOff = psExtraArgIn->dfYOff;
    1871           0 :         dfXSize = psExtraArgIn->dfXSize;
    1872           0 :         dfYSize = psExtraArgIn->dfYSize;
    1873             :     }
    1874             : 
    1875             :     // The window we will actually request from the source raster band.
    1876          33 :     double dfReqXOff = 0.0;
    1877          33 :     double dfReqYOff = 0.0;
    1878          33 :     double dfReqXSize = 0.0;
    1879          33 :     double dfReqYSize = 0.0;
    1880          33 :     int nReqXOff = 0;
    1881          33 :     int nReqYOff = 0;
    1882          33 :     int nReqXSize = 0;
    1883          33 :     int nReqYSize = 0;
    1884             : 
    1885             :     // The window we will actual set _within_ the pData buffer.
    1886          33 :     int nOutXOff = 0;
    1887          33 :     int nOutYOff = 0;
    1888          33 :     int nOutXSize = 0;
    1889          33 :     int nOutYSize = 0;
    1890             : 
    1891          33 :     bool bError = false;
    1892          33 :     if (!GetSrcDstWindow(dfXOff, dfYOff, dfXSize, dfYSize, nBufXSize, nBufYSize,
    1893             :                          &dfReqXOff, &dfReqYOff, &dfReqXSize, &dfReqYSize,
    1894             :                          &nReqXOff, &nReqYOff, &nReqXSize, &nReqYSize,
    1895             :                          &nOutXOff, &nOutYOff, &nOutXSize, &nOutYSize, bError))
    1896             :     {
    1897           0 :         return bError ? CE_Failure : CE_None;
    1898             :     }
    1899             : 
    1900          33 :     auto l_band = GetRasterBand();
    1901          33 :     if (!l_band)
    1902           0 :         return CE_Failure;
    1903             : 
    1904             :     /* -------------------------------------------------------------------- */
    1905             :     /*      Allocate a temporary buffer to whole the full resolution        */
    1906             :     /*      data from the area of interest.                                 */
    1907             :     /* -------------------------------------------------------------------- */
    1908             :     float *const pafSrc = static_cast<float *>(
    1909          33 :         VSI_MALLOC3_VERBOSE(sizeof(float), nReqXSize, nReqYSize));
    1910          33 :     if (pafSrc == nullptr)
    1911             :     {
    1912           0 :         return CE_Failure;
    1913             :     }
    1914             : 
    1915             :     /* -------------------------------------------------------------------- */
    1916             :     /*      Load it.                                                        */
    1917             :     /* -------------------------------------------------------------------- */
    1918          33 :     if (!m_osResampling.empty())
    1919             :     {
    1920          28 :         psExtraArg->eResampleAlg = GDALRasterIOGetResampleAlg(m_osResampling);
    1921             :     }
    1922           5 :     else if (psExtraArgIn != nullptr)
    1923             :     {
    1924           5 :         psExtraArg->eResampleAlg = psExtraArgIn->eResampleAlg;
    1925             :     }
    1926             : 
    1927          33 :     psExtraArg->bFloatingPointWindowValidity = TRUE;
    1928          33 :     psExtraArg->dfXOff = dfReqXOff;
    1929          33 :     psExtraArg->dfYOff = dfReqYOff;
    1930          33 :     psExtraArg->dfXSize = dfReqXSize;
    1931          33 :     psExtraArg->dfYSize = dfReqYSize;
    1932          33 :     if (psExtraArgIn)
    1933             :     {
    1934          33 :         psExtraArg->pfnProgress = psExtraArgIn->pfnProgress;
    1935          33 :         psExtraArg->pProgressData = psExtraArgIn->pProgressData;
    1936             :     }
    1937             : 
    1938          33 :     const CPLErr eErr = l_band->RasterIO(
    1939             :         GF_Read, nReqXOff, nReqYOff, nReqXSize, nReqYSize, pafSrc, nReqXSize,
    1940             :         nReqYSize, GDT_Float32, 0, 0, psExtraArg);
    1941             : 
    1942          33 :     if (eErr != CE_None)
    1943             :     {
    1944           0 :         VSIFree(pafSrc);
    1945           0 :         return eErr;
    1946             :     }
    1947             : 
    1948             :     /* -------------------------------------------------------------------- */
    1949             :     /*      Do the averaging.                                               */
    1950             :     /* -------------------------------------------------------------------- */
    1951        5956 :     for (int iBufLine = nOutYOff; iBufLine < nOutYOff + nOutYSize; iBufLine++)
    1952             :     {
    1953        5923 :         const double dfYDst =
    1954        5923 :             (iBufLine / static_cast<double>(nBufYSize)) * nYSize + nYOff;
    1955             : 
    1956     2017080 :         for (int iBufPixel = nOutXOff; iBufPixel < nOutXOff + nOutXSize;
    1957             :              iBufPixel++)
    1958             :         {
    1959             :             double dfXSrcStart, dfXSrcEnd, dfYSrcStart, dfYSrcEnd;
    1960             :             int iXSrcStart, iYSrcStart, iXSrcEnd, iYSrcEnd;
    1961             : 
    1962     2011160 :             const double dfXDst =
    1963     2011160 :                 (iBufPixel / static_cast<double>(nBufXSize)) * nXSize + nXOff;
    1964             : 
    1965             :             // Compute the source image rectangle needed for this pixel.
    1966     2011160 :             DstToSrc(dfXDst, dfYDst, dfXSrcStart, dfYSrcStart);
    1967     2011160 :             DstToSrc(dfXDst + 1.0, dfYDst + 1.0, dfXSrcEnd, dfYSrcEnd);
    1968             : 
    1969             :             // Convert to integers, assuming that the center of the source
    1970             :             // pixel must be in our rect to get included.
    1971     2011160 :             if (dfXSrcEnd >= dfXSrcStart + 1)
    1972             :             {
    1973     1049560 :                 iXSrcStart = static_cast<int>(floor(dfXSrcStart + 0.5));
    1974     1049560 :                 iXSrcEnd = static_cast<int>(floor(dfXSrcEnd + 0.5));
    1975             :             }
    1976             :             else
    1977             :             {
    1978             :                 /* If the resampling factor is less than 100%, the distance */
    1979             :                 /* between the source pixel is < 1, so we stick to nearest */
    1980             :                 /* neighbour */
    1981      961600 :                 iXSrcStart = static_cast<int>(floor(dfXSrcStart));
    1982      961600 :                 iXSrcEnd = iXSrcStart + 1;
    1983             :             }
    1984     2011160 :             if (dfYSrcEnd >= dfYSrcStart + 1)
    1985             :             {
    1986     1049560 :                 iYSrcStart = static_cast<int>(floor(dfYSrcStart + 0.5));
    1987     1049560 :                 iYSrcEnd = static_cast<int>(floor(dfYSrcEnd + 0.5));
    1988             :             }
    1989             :             else
    1990             :             {
    1991      961600 :                 iYSrcStart = static_cast<int>(floor(dfYSrcStart));
    1992      961600 :                 iYSrcEnd = iYSrcStart + 1;
    1993             :             }
    1994             : 
    1995             :             // Transform into the coordinate system of the source *buffer*
    1996     2011160 :             iXSrcStart -= nReqXOff;
    1997     2011160 :             iYSrcStart -= nReqYOff;
    1998     2011160 :             iXSrcEnd -= nReqXOff;
    1999     2011160 :             iYSrcEnd -= nReqYOff;
    2000             : 
    2001     2011160 :             double dfSum = 0.0;
    2002     2011160 :             int nPixelCount = 0;
    2003             : 
    2004     4022510 :             for (int iY = iYSrcStart; iY < iYSrcEnd; iY++)
    2005             :             {
    2006     2011360 :                 if (iY < 0 || iY >= nReqYSize)
    2007           0 :                     continue;
    2008             : 
    2009     4023130 :                 for (int iX = iXSrcStart; iX < iXSrcEnd; iX++)
    2010             :                 {
    2011     2011780 :                     if (iX < 0 || iX >= nReqXSize)
    2012           0 :                         continue;
    2013             : 
    2014     2011780 :                     const float fSampledValue =
    2015     2011780 :                         pafSrc[iX + static_cast<size_t>(iY) * nReqXSize];
    2016     2011780 :                     if (std::isnan(fSampledValue))
    2017           0 :                         continue;
    2018             : 
    2019     4023550 :                     if (m_bNoDataSet &&
    2020     2011780 :                         GDALIsValueInRange<float>(m_dfNoDataValue) &&
    2021           0 :                         ARE_REAL_EQUAL(fSampledValue,
    2022           0 :                                        static_cast<float>(m_dfNoDataValue)))
    2023           0 :                         continue;
    2024             : 
    2025     2011780 :                     nPixelCount++;
    2026     2011780 :                     dfSum += pafSrc[iX + static_cast<size_t>(iY) * nReqXSize];
    2027             :                 }
    2028             :             }
    2029             : 
    2030     2011160 :             if (nPixelCount == 0)
    2031           0 :                 continue;
    2032             : 
    2033             :             // Compute output value.
    2034     2011160 :             const float dfOutputValue = static_cast<float>(dfSum / nPixelCount);
    2035             : 
    2036             :             // Put it in the output buffer.
    2037     2011160 :             GByte *pDstLocation =
    2038     2011160 :                 static_cast<GByte *>(pData) + nPixelSpace * iBufPixel +
    2039     2011160 :                 static_cast<GPtrDiff_t>(nLineSpace) * iBufLine;
    2040             : 
    2041     2011160 :             if (eBufType == GDT_Byte)
    2042     2008660 :                 *pDstLocation = static_cast<GByte>(
    2043     2008660 :                     std::min(255.0, std::max(0.0, dfOutputValue + 0.5)));
    2044             :             else
    2045        2500 :                 GDALCopyWords(&dfOutputValue, GDT_Float32, 4, pDstLocation,
    2046             :                               eBufType, 8, 1);
    2047             :         }
    2048             :     }
    2049             : 
    2050          33 :     VSIFree(pafSrc);
    2051             : 
    2052          33 :     if (psExtraArg->pfnProgress)
    2053           0 :         psExtraArg->pfnProgress(1.0, "", psExtraArg->pProgressData);
    2054             : 
    2055          33 :     return CE_None;
    2056             : }
    2057             : 
    2058             : /************************************************************************/
    2059             : /*                             GetMinimum()                             */
    2060             : /************************************************************************/
    2061             : 
    2062           0 : double VRTAveragedSource::GetMinimum(int /* nXSize */, int /* nYSize */,
    2063             :                                      int *pbSuccess)
    2064             : {
    2065           0 :     *pbSuccess = FALSE;
    2066           0 :     return 0.0;
    2067             : }
    2068             : 
    2069             : /************************************************************************/
    2070             : /*                             GetMaximum()                             */
    2071             : /************************************************************************/
    2072             : 
    2073           0 : double VRTAveragedSource::GetMaximum(int /* nXSize */, int /* nYSize */,
    2074             :                                      int *pbSuccess)
    2075             : {
    2076           0 :     *pbSuccess = FALSE;
    2077           0 :     return 0.0;
    2078             : }
    2079             : 
    2080             : /************************************************************************/
    2081             : /*                            GetHistogram()                            */
    2082             : /************************************************************************/
    2083             : 
    2084           0 : CPLErr VRTAveragedSource::GetHistogram(
    2085             :     int /* nXSize */, int /* nYSize */, double /* dfMin */, double /* dfMax */,
    2086             :     int /* nBuckets */, GUIntBig * /* panHistogram */,
    2087             :     int /* bIncludeOutOfRange */, int /* bApproxOK */,
    2088             :     GDALProgressFunc /* pfnProgress */, void * /* pProgressData */)
    2089             : {
    2090           0 :     return CE_Failure;
    2091             : }
    2092             : 
    2093             : /************************************************************************/
    2094             : /* ==================================================================== */
    2095             : /*                     VRTNoDataFromMaskSource                          */
    2096             : /* ==================================================================== */
    2097             : /************************************************************************/
    2098             : 
    2099             : /************************************************************************/
    2100             : /*                     VRTNoDataFromMaskSource()                        */
    2101             : /************************************************************************/
    2102             : 
    2103          23 : VRTNoDataFromMaskSource::VRTNoDataFromMaskSource()
    2104             : {
    2105          23 : }
    2106             : 
    2107             : /************************************************************************/
    2108             : /*                              XMLInit()                               */
    2109             : /************************************************************************/
    2110             : 
    2111             : CPLErr
    2112           8 : VRTNoDataFromMaskSource::XMLInit(const CPLXMLNode *psSrc,
    2113             :                                  const char *pszVRTPath,
    2114             :                                  VRTMapSharedResources &oMapSharedSources)
    2115             : 
    2116             : {
    2117             :     /* -------------------------------------------------------------------- */
    2118             :     /*      Do base initialization.                                         */
    2119             :     /* -------------------------------------------------------------------- */
    2120             :     {
    2121             :         const CPLErr eErr =
    2122           8 :             VRTSimpleSource::XMLInit(psSrc, pszVRTPath, oMapSharedSources);
    2123           8 :         if (eErr != CE_None)
    2124           0 :             return eErr;
    2125             :     }
    2126             : 
    2127           8 :     if (const char *pszNODATA = CPLGetXMLValue(psSrc, "NODATA", nullptr))
    2128             :     {
    2129           8 :         m_bNoDataSet = true;
    2130           8 :         m_dfNoDataValue = CPLAtofM(pszNODATA);
    2131             :     }
    2132             : 
    2133           8 :     m_dfMaskValueThreshold =
    2134           8 :         CPLAtofM(CPLGetXMLValue(psSrc, "MaskValueThreshold", "0"));
    2135             : 
    2136           8 :     if (const char *pszRemappedValue =
    2137           8 :             CPLGetXMLValue(psSrc, "RemappedValue", nullptr))
    2138             :     {
    2139           0 :         m_bHasRemappedValue = true;
    2140           0 :         m_dfRemappedValue = CPLAtofM(pszRemappedValue);
    2141             :     }
    2142             : 
    2143           8 :     return CE_None;
    2144             : }
    2145             : 
    2146             : /************************************************************************/
    2147             : /*                           GetTypeStatic()                            */
    2148             : /************************************************************************/
    2149             : 
    2150          27 : const char *VRTNoDataFromMaskSource::GetTypeStatic()
    2151             : {
    2152             :     static const char *TYPE = "NoDataFromMaskSource";
    2153          27 :     return TYPE;
    2154             : }
    2155             : 
    2156             : /************************************************************************/
    2157             : /*                            GetType()                                 */
    2158             : /************************************************************************/
    2159             : 
    2160          11 : const char *VRTNoDataFromMaskSource::GetType() const
    2161             : {
    2162          11 :     return GetTypeStatic();
    2163             : }
    2164             : 
    2165             : /************************************************************************/
    2166             : /*                           SerializeToXML()                           */
    2167             : /************************************************************************/
    2168             : 
    2169           8 : CPLXMLNode *VRTNoDataFromMaskSource::SerializeToXML(const char *pszVRTPath)
    2170             : 
    2171             : {
    2172           8 :     CPLXMLNode *const psSrc = VRTSimpleSource::SerializeToXML(pszVRTPath);
    2173             : 
    2174           8 :     if (psSrc == nullptr)
    2175           0 :         return nullptr;
    2176             : 
    2177           8 :     CPLFree(psSrc->pszValue);
    2178           8 :     psSrc->pszValue = CPLStrdup(GetTypeStatic());
    2179             : 
    2180           8 :     if (m_bNoDataSet)
    2181             :     {
    2182           8 :         CPLSetXMLValue(psSrc, "MaskValueThreshold",
    2183             :                        CPLSPrintf("%.17g", m_dfMaskValueThreshold));
    2184             : 
    2185           8 :         GDALDataType eBandDT = GDT_Unknown;
    2186           8 :         double dfNoDataValue = m_dfNoDataValue;
    2187           8 :         const auto kMaxFloat = std::numeric_limits<float>::max();
    2188           8 :         if (std::fabs(std::fabs(m_dfNoDataValue) - kMaxFloat) <
    2189             :             1e-10 * kMaxFloat)
    2190             :         {
    2191           0 :             auto l_band = GetRasterBand();
    2192           0 :             if (l_band)
    2193             :             {
    2194           0 :                 eBandDT = l_band->GetRasterDataType();
    2195           0 :                 if (eBandDT == GDT_Float32)
    2196             :                 {
    2197             :                     dfNoDataValue =
    2198           0 :                         GDALAdjustNoDataCloseToFloatMax(m_dfNoDataValue);
    2199             :                 }
    2200             :             }
    2201             :         }
    2202           8 :         CPLSetXMLValue(psSrc, "NODATA",
    2203          16 :                        VRTSerializeNoData(dfNoDataValue, eBandDT, 18).c_str());
    2204             :     }
    2205             : 
    2206           8 :     if (m_bHasRemappedValue)
    2207             :     {
    2208           0 :         CPLSetXMLValue(psSrc, "RemappedValue",
    2209             :                        CPLSPrintf("%.17g", m_dfRemappedValue));
    2210             :     }
    2211             : 
    2212           8 :     return psSrc;
    2213             : }
    2214             : 
    2215             : /************************************************************************/
    2216             : /*                           SetParameters()                            */
    2217             : /************************************************************************/
    2218             : 
    2219          15 : void VRTNoDataFromMaskSource::SetParameters(double dfNoDataValue,
    2220             :                                             double dfMaskValueThreshold)
    2221             : {
    2222          15 :     m_bNoDataSet = true;
    2223          15 :     m_dfNoDataValue = dfNoDataValue;
    2224          15 :     m_dfMaskValueThreshold = dfMaskValueThreshold;
    2225          15 :     if (!m_bHasRemappedValue)
    2226          15 :         m_dfRemappedValue = m_dfNoDataValue;
    2227          15 : }
    2228             : 
    2229             : /************************************************************************/
    2230             : /*                           SetParameters()                            */
    2231             : /************************************************************************/
    2232             : 
    2233           0 : void VRTNoDataFromMaskSource::SetParameters(double dfNoDataValue,
    2234             :                                             double dfMaskValueThreshold,
    2235             :                                             double dfRemappedValue)
    2236             : {
    2237           0 :     SetParameters(dfNoDataValue, dfMaskValueThreshold);
    2238           0 :     m_bHasRemappedValue = true;
    2239           0 :     m_dfRemappedValue = dfRemappedValue;
    2240           0 : }
    2241             : 
    2242             : /************************************************************************/
    2243             : /*                              RasterIO()                              */
    2244             : /************************************************************************/
    2245             : 
    2246          13 : CPLErr VRTNoDataFromMaskSource::RasterIO(
    2247             :     GDALDataType eVRTBandDataType, int nXOff, int nYOff, int nXSize, int nYSize,
    2248             :     void *pData, int nBufXSize, int nBufYSize, GDALDataType eBufType,
    2249             :     GSpacing nPixelSpace, GSpacing nLineSpace,
    2250             :     GDALRasterIOExtraArg *psExtraArgIn, WorkingState &oWorkingState)
    2251             : 
    2252             : {
    2253          13 :     if (!m_bNoDataSet)
    2254             :     {
    2255           0 :         return VRTSimpleSource::RasterIO(eVRTBandDataType, nXOff, nYOff, nXSize,
    2256             :                                          nYSize, pData, nBufXSize, nBufYSize,
    2257             :                                          eBufType, nPixelSpace, nLineSpace,
    2258           0 :                                          psExtraArgIn, oWorkingState);
    2259             :     }
    2260             : 
    2261             :     GDALRasterIOExtraArg sExtraArg;
    2262          13 :     INIT_RASTERIO_EXTRA_ARG(sExtraArg);
    2263          13 :     GDALRasterIOExtraArg *psExtraArg = &sExtraArg;
    2264             : 
    2265          13 :     double dfXOff = nXOff;
    2266          13 :     double dfYOff = nYOff;
    2267          13 :     double dfXSize = nXSize;
    2268          13 :     double dfYSize = nYSize;
    2269          13 :     if (psExtraArgIn != nullptr && psExtraArgIn->bFloatingPointWindowValidity)
    2270             :     {
    2271           0 :         dfXOff = psExtraArgIn->dfXOff;
    2272           0 :         dfYOff = psExtraArgIn->dfYOff;
    2273           0 :         dfXSize = psExtraArgIn->dfXSize;
    2274           0 :         dfYSize = psExtraArgIn->dfYSize;
    2275             :     }
    2276             : 
    2277             :     // The window we will actually request from the source raster band.
    2278          13 :     double dfReqXOff = 0.0;
    2279          13 :     double dfReqYOff = 0.0;
    2280          13 :     double dfReqXSize = 0.0;
    2281          13 :     double dfReqYSize = 0.0;
    2282          13 :     int nReqXOff = 0;
    2283          13 :     int nReqYOff = 0;
    2284          13 :     int nReqXSize = 0;
    2285          13 :     int nReqYSize = 0;
    2286             : 
    2287             :     // The window we will actual set _within_ the pData buffer.
    2288          13 :     int nOutXOff = 0;
    2289          13 :     int nOutYOff = 0;
    2290          13 :     int nOutXSize = 0;
    2291          13 :     int nOutYSize = 0;
    2292             : 
    2293          13 :     bool bError = false;
    2294          13 :     if (!GetSrcDstWindow(dfXOff, dfYOff, dfXSize, dfYSize, nBufXSize, nBufYSize,
    2295             :                          &dfReqXOff, &dfReqYOff, &dfReqXSize, &dfReqYSize,
    2296             :                          &nReqXOff, &nReqYOff, &nReqXSize, &nReqYSize,
    2297             :                          &nOutXOff, &nOutYOff, &nOutXSize, &nOutYSize, bError))
    2298             :     {
    2299           0 :         return bError ? CE_Failure : CE_None;
    2300             :     }
    2301             : 
    2302          13 :     auto l_band = GetRasterBand();
    2303          13 :     if (!l_band)
    2304           0 :         return CE_Failure;
    2305             : 
    2306             :     /* -------------------------------------------------------------------- */
    2307             :     /*      Allocate temporary buffer(s).                                   */
    2308             :     /* -------------------------------------------------------------------- */
    2309          13 :     const auto eSrcBandDT = l_band->GetRasterDataType();
    2310          13 :     const int nSrcBandDTSize = GDALGetDataTypeSizeBytes(eSrcBandDT);
    2311          13 :     const auto eSrcMaskBandDT = l_band->GetMaskBand()->GetRasterDataType();
    2312          13 :     const int nSrcMaskBandDTSize = GDALGetDataTypeSizeBytes(eSrcMaskBandDT);
    2313          13 :     double dfRemappedValue = m_dfRemappedValue;
    2314          13 :     if (!m_bHasRemappedValue)
    2315             :     {
    2316          19 :         if (eSrcBandDT == GDT_Byte &&
    2317           6 :             m_dfNoDataValue >= std::numeric_limits<GByte>::min() &&
    2318          25 :             m_dfNoDataValue <= std::numeric_limits<GByte>::max() &&
    2319           6 :             static_cast<int>(m_dfNoDataValue) == m_dfNoDataValue)
    2320             :         {
    2321           6 :             if (m_dfNoDataValue == std::numeric_limits<GByte>::max())
    2322           1 :                 dfRemappedValue = m_dfNoDataValue - 1;
    2323             :             else
    2324           5 :                 dfRemappedValue = m_dfNoDataValue + 1;
    2325             :         }
    2326          10 :         else if (eSrcBandDT == GDT_UInt16 &&
    2327           3 :                  m_dfNoDataValue >= std::numeric_limits<uint16_t>::min() &&
    2328          13 :                  m_dfNoDataValue <= std::numeric_limits<uint16_t>::max() &&
    2329           3 :                  static_cast<int>(m_dfNoDataValue) == m_dfNoDataValue)
    2330             :         {
    2331           3 :             if (m_dfNoDataValue == std::numeric_limits<uint16_t>::max())
    2332           1 :                 dfRemappedValue = m_dfNoDataValue - 1;
    2333             :             else
    2334           2 :                 dfRemappedValue = m_dfNoDataValue + 1;
    2335             :         }
    2336           6 :         else if (eSrcBandDT == GDT_Int16 &&
    2337           2 :                  m_dfNoDataValue >= std::numeric_limits<int16_t>::min() &&
    2338           8 :                  m_dfNoDataValue <= std::numeric_limits<int16_t>::max() &&
    2339           2 :                  static_cast<int>(m_dfNoDataValue) == m_dfNoDataValue)
    2340             :         {
    2341           2 :             if (m_dfNoDataValue == std::numeric_limits<int16_t>::max())
    2342           1 :                 dfRemappedValue = m_dfNoDataValue - 1;
    2343             :             else
    2344           1 :                 dfRemappedValue = m_dfNoDataValue + 1;
    2345             :         }
    2346             :         else
    2347             :         {
    2348           2 :             constexpr double EPS = 1e-3;
    2349           2 :             if (m_dfNoDataValue == 0)
    2350           1 :                 dfRemappedValue = EPS;
    2351             :             else
    2352           1 :                 dfRemappedValue = m_dfNoDataValue * (1 + EPS);
    2353             :         }
    2354             :     }
    2355          13 :     const bool bByteOptim =
    2356           6 :         (eSrcBandDT == GDT_Byte && eBufType == GDT_Byte &&
    2357           5 :          eSrcMaskBandDT == GDT_Byte && m_dfMaskValueThreshold >= 0 &&
    2358           5 :          m_dfMaskValueThreshold <= 255 &&
    2359           5 :          static_cast<int>(m_dfMaskValueThreshold) == m_dfMaskValueThreshold &&
    2360           4 :          m_dfNoDataValue >= 0 && m_dfNoDataValue <= 255 &&
    2361           4 :          static_cast<int>(m_dfNoDataValue) == m_dfNoDataValue &&
    2362          23 :          dfRemappedValue >= 0 && dfRemappedValue <= 255 &&
    2363           4 :          static_cast<int>(dfRemappedValue) == dfRemappedValue);
    2364             :     GByte *pabyWrkBuffer;
    2365             :     try
    2366             :     {
    2367          13 :         if (bByteOptim && nOutXOff == 0 && nOutYOff == 0 &&
    2368           4 :             nOutXSize == nBufXSize && nOutYSize == nBufYSize &&
    2369           4 :             eSrcBandDT == eBufType && nPixelSpace == nSrcBandDTSize &&
    2370           4 :             nLineSpace == nPixelSpace * nBufXSize)
    2371             :         {
    2372           4 :             pabyWrkBuffer = static_cast<GByte *>(pData);
    2373             :         }
    2374             :         else
    2375             :         {
    2376           9 :             oWorkingState.m_abyWrkBuffer.resize(static_cast<size_t>(nOutXSize) *
    2377           9 :                                                 nOutYSize * nSrcBandDTSize);
    2378             :             pabyWrkBuffer =
    2379           9 :                 reinterpret_cast<GByte *>(oWorkingState.m_abyWrkBuffer.data());
    2380             :         }
    2381          13 :         oWorkingState.m_abyWrkBufferMask.resize(static_cast<size_t>(nOutXSize) *
    2382          13 :                                                 nOutYSize * nSrcMaskBandDTSize);
    2383             :     }
    2384           0 :     catch (const std::exception &)
    2385             :     {
    2386           0 :         CPLError(CE_Failure, CPLE_OutOfMemory,
    2387             :                  "Out of memory when allocating buffers");
    2388           0 :         return CE_Failure;
    2389             :     }
    2390             : 
    2391             :     /* -------------------------------------------------------------------- */
    2392             :     /*      Load data.                                                      */
    2393             :     /* -------------------------------------------------------------------- */
    2394          13 :     if (!m_osResampling.empty())
    2395             :     {
    2396           0 :         psExtraArg->eResampleAlg = GDALRasterIOGetResampleAlg(m_osResampling);
    2397             :     }
    2398          13 :     else if (psExtraArgIn != nullptr)
    2399             :     {
    2400          13 :         psExtraArg->eResampleAlg = psExtraArgIn->eResampleAlg;
    2401             :     }
    2402             : 
    2403          13 :     psExtraArg->bFloatingPointWindowValidity = TRUE;
    2404          13 :     psExtraArg->dfXOff = dfReqXOff;
    2405          13 :     psExtraArg->dfYOff = dfReqYOff;
    2406          13 :     psExtraArg->dfXSize = dfReqXSize;
    2407          13 :     psExtraArg->dfYSize = dfReqYSize;
    2408          13 :     if (psExtraArgIn)
    2409             :     {
    2410          13 :         psExtraArg->pfnProgress = psExtraArgIn->pfnProgress;
    2411          13 :         psExtraArg->pProgressData = psExtraArgIn->pProgressData;
    2412             :     }
    2413             : 
    2414          13 :     if (l_band->RasterIO(GF_Read, nReqXOff, nReqYOff, nReqXSize, nReqYSize,
    2415             :                          pabyWrkBuffer, nOutXSize, nOutYSize, eSrcBandDT, 0, 0,
    2416          13 :                          psExtraArg) != CE_None)
    2417             :     {
    2418           0 :         return CE_Failure;
    2419             :     }
    2420             : 
    2421          26 :     if (l_band->GetMaskBand()->RasterIO(
    2422             :             GF_Read, nReqXOff, nReqYOff, nReqXSize, nReqYSize,
    2423          13 :             oWorkingState.m_abyWrkBufferMask.data(), nOutXSize, nOutYSize,
    2424          13 :             eSrcMaskBandDT, 0, 0, psExtraArg) != CE_None)
    2425             :     {
    2426           0 :         return CE_Failure;
    2427             :     }
    2428             : 
    2429             :     /* -------------------------------------------------------------------- */
    2430             :     /*      Do the processing.                                              */
    2431             :     /* -------------------------------------------------------------------- */
    2432             : 
    2433          13 :     GByte *const pabyOut = static_cast<GByte *>(pData) +
    2434          13 :                            nPixelSpace * nOutXOff +
    2435          13 :                            static_cast<GPtrDiff_t>(nLineSpace) * nOutYOff;
    2436          13 :     if (bByteOptim)
    2437             :     {
    2438             :         // Special case when everything fits on Byte
    2439           4 :         const GByte nMaskValueThreshold =
    2440           4 :             static_cast<GByte>(m_dfMaskValueThreshold);
    2441           4 :         const GByte nNoDataValue = static_cast<GByte>(m_dfNoDataValue);
    2442           4 :         const GByte nRemappedValue = static_cast<GByte>(dfRemappedValue);
    2443           4 :         size_t nSrcIdx = 0;
    2444           8 :         for (int iY = 0; iY < nOutYSize; iY++)
    2445             :         {
    2446           4 :             GSpacing nDstOffset = iY * nLineSpace;
    2447          12 :             for (int iX = 0; iX < nOutXSize; iX++)
    2448             :             {
    2449             :                 const GByte nMaskVal =
    2450           8 :                     oWorkingState.m_abyWrkBufferMask[nSrcIdx];
    2451           8 :                 if (nMaskVal <= nMaskValueThreshold)
    2452             :                 {
    2453           4 :                     pabyOut[static_cast<GPtrDiff_t>(nDstOffset)] = nNoDataValue;
    2454             :                 }
    2455             :                 else
    2456             :                 {
    2457           4 :                     if (pabyWrkBuffer[nSrcIdx] == nNoDataValue)
    2458             :                     {
    2459           2 :                         pabyOut[static_cast<GPtrDiff_t>(nDstOffset)] =
    2460             :                             nRemappedValue;
    2461             :                     }
    2462             :                     else
    2463             :                     {
    2464           2 :                         pabyOut[static_cast<GPtrDiff_t>(nDstOffset)] =
    2465           2 :                             pabyWrkBuffer[nSrcIdx];
    2466             :                     }
    2467             :                 }
    2468           8 :                 nDstOffset += nPixelSpace;
    2469           8 :                 nSrcIdx++;
    2470             :             }
    2471             :         }
    2472             :     }
    2473             :     else
    2474             :     {
    2475           9 :         size_t nSrcIdx = 0;
    2476           9 :         double dfMaskVal = 0;
    2477           9 :         const int nBufDTSize = GDALGetDataTypeSizeBytes(eBufType);
    2478          18 :         std::vector<GByte> abyDstNoData(nBufDTSize);
    2479           9 :         GDALCopyWords(&m_dfNoDataValue, GDT_Float64, 0, abyDstNoData.data(),
    2480             :                       eBufType, 0, 1);
    2481          18 :         std::vector<GByte> abyRemappedValue(nBufDTSize);
    2482           9 :         GDALCopyWords(&dfRemappedValue, GDT_Float64, 0, abyRemappedValue.data(),
    2483             :                       eBufType, 0, 1);
    2484          18 :         for (int iY = 0; iY < nOutYSize; iY++)
    2485             :         {
    2486           9 :             GSpacing nDstOffset = iY * nLineSpace;
    2487          28 :             for (int iX = 0; iX < nOutXSize; iX++)
    2488             :             {
    2489          19 :                 if (eSrcMaskBandDT == GDT_Byte)
    2490             :                 {
    2491          19 :                     dfMaskVal = oWorkingState.m_abyWrkBufferMask[nSrcIdx];
    2492             :                 }
    2493             :                 else
    2494             :                 {
    2495           0 :                     GDALCopyWords(oWorkingState.m_abyWrkBufferMask.data() +
    2496           0 :                                       nSrcIdx * nSrcMaskBandDTSize,
    2497             :                                   eSrcMaskBandDT, 0, &dfMaskVal, GDT_Float64, 0,
    2498             :                                   1);
    2499             :                 }
    2500          19 :                 void *const pDst =
    2501          19 :                     pabyOut + static_cast<GPtrDiff_t>(nDstOffset);
    2502          19 :                 if (!(dfMaskVal > m_dfMaskValueThreshold))
    2503             :                 {
    2504           9 :                     memcpy(pDst, abyDstNoData.data(), nBufDTSize);
    2505             :                 }
    2506             :                 else
    2507             :                 {
    2508          10 :                     const void *const pSrc =
    2509          10 :                         pabyWrkBuffer + nSrcIdx * nSrcBandDTSize;
    2510          10 :                     if (eSrcBandDT == eBufType)
    2511             :                     {
    2512             :                         // coverity[overrun-buffer-arg]
    2513           8 :                         memcpy(pDst, pSrc, nBufDTSize);
    2514             :                     }
    2515             :                     else
    2516             :                     {
    2517           2 :                         GDALCopyWords(pSrc, eSrcBandDT, 0, pDst, eBufType, 0,
    2518             :                                       1);
    2519             :                     }
    2520          10 :                     if (memcmp(pDst, abyDstNoData.data(), nBufDTSize) == 0)
    2521           9 :                         memcpy(pDst, abyRemappedValue.data(), nBufDTSize);
    2522             :                 }
    2523          19 :                 nDstOffset += nPixelSpace;
    2524          19 :                 nSrcIdx++;
    2525             :             }
    2526             :         }
    2527             :     }
    2528             : 
    2529          13 :     if (psExtraArg->pfnProgress)
    2530           0 :         psExtraArg->pfnProgress(1.0, "", psExtraArg->pProgressData);
    2531             : 
    2532          13 :     return CE_None;
    2533             : }
    2534             : 
    2535             : /************************************************************************/
    2536             : /*                             GetMinimum()                             */
    2537             : /************************************************************************/
    2538             : 
    2539           0 : double VRTNoDataFromMaskSource::GetMinimum(int /* nXSize */, int /* nYSize */,
    2540             :                                            int *pbSuccess)
    2541             : {
    2542           0 :     *pbSuccess = FALSE;
    2543           0 :     return 0.0;
    2544             : }
    2545             : 
    2546             : /************************************************************************/
    2547             : /*                             GetMaximum()                             */
    2548             : /************************************************************************/
    2549             : 
    2550           0 : double VRTNoDataFromMaskSource::GetMaximum(int /* nXSize */, int /* nYSize */,
    2551             :                                            int *pbSuccess)
    2552             : {
    2553           0 :     *pbSuccess = FALSE;
    2554           0 :     return 0.0;
    2555             : }
    2556             : 
    2557             : /************************************************************************/
    2558             : /*                            GetHistogram()                            */
    2559             : /************************************************************************/
    2560             : 
    2561           0 : CPLErr VRTNoDataFromMaskSource::GetHistogram(
    2562             :     int /* nXSize */, int /* nYSize */, double /* dfMin */, double /* dfMax */,
    2563             :     int /* nBuckets */, GUIntBig * /* panHistogram */,
    2564             :     int /* bIncludeOutOfRange */, int /* bApproxOK */,
    2565             :     GDALProgressFunc /* pfnProgress */, void * /* pProgressData */)
    2566             : {
    2567           0 :     return CE_Failure;
    2568             : }
    2569             : 
    2570             : /************************************************************************/
    2571             : /* ==================================================================== */
    2572             : /*                          VRTComplexSource                            */
    2573             : /* ==================================================================== */
    2574             : /************************************************************************/
    2575             : 
    2576             : /************************************************************************/
    2577             : /*                          VRTComplexSource()                          */
    2578             : /************************************************************************/
    2579             : 
    2580           5 : VRTComplexSource::VRTComplexSource(const VRTComplexSource *poSrcSource,
    2581           5 :                                    double dfXDstRatio, double dfYDstRatio)
    2582             :     : VRTSimpleSource(poSrcSource, dfXDstRatio, dfYDstRatio),
    2583           5 :       m_nProcessingFlags(poSrcSource->m_nProcessingFlags),
    2584           5 :       m_dfNoDataValue(poSrcSource->m_dfNoDataValue),
    2585           5 :       m_osNoDataValueOri(poSrcSource->m_osNoDataValueOri),
    2586           5 :       m_dfScaleOff(poSrcSource->m_dfScaleOff),
    2587           5 :       m_dfScaleRatio(poSrcSource->m_dfScaleRatio),
    2588           5 :       m_bSrcMinMaxDefined(poSrcSource->m_bSrcMinMaxDefined),
    2589           5 :       m_dfSrcMin(poSrcSource->m_dfSrcMin), m_dfSrcMax(poSrcSource->m_dfSrcMax),
    2590           5 :       m_dfDstMin(poSrcSource->m_dfDstMin), m_dfDstMax(poSrcSource->m_dfDstMax),
    2591           5 :       m_dfExponent(poSrcSource->m_dfExponent), m_bClip(poSrcSource->m_bClip),
    2592           5 :       m_nColorTableComponent(poSrcSource->m_nColorTableComponent),
    2593           5 :       m_adfLUTInputs(poSrcSource->m_adfLUTInputs),
    2594           5 :       m_adfLUTOutputs(poSrcSource->m_adfLUTOutputs)
    2595             : {
    2596           5 : }
    2597             : 
    2598             : /************************************************************************/
    2599             : /*                           GetTypeStatic()                            */
    2600             : /************************************************************************/
    2601             : 
    2602       13743 : const char *VRTComplexSource::GetTypeStatic()
    2603             : {
    2604             :     static const char *TYPE = "ComplexSource";
    2605       13743 :     return TYPE;
    2606             : }
    2607             : 
    2608             : /************************************************************************/
    2609             : /*                            GetType()                                 */
    2610             : /************************************************************************/
    2611             : 
    2612        3989 : const char *VRTComplexSource::GetType() const
    2613             : {
    2614        3989 :     return GetTypeStatic();
    2615             : }
    2616             : 
    2617             : /************************************************************************/
    2618             : /*                           SetNoDataValue()                           */
    2619             : /************************************************************************/
    2620             : 
    2621          76 : void VRTComplexSource::SetNoDataValue(double dfNewNoDataValue)
    2622             : 
    2623             : {
    2624          76 :     if (dfNewNoDataValue == VRT_NODATA_UNSET)
    2625             :     {
    2626           0 :         m_nProcessingFlags &= ~PROCESSING_FLAG_NODATA;
    2627           0 :         m_dfNoDataValue = VRT_NODATA_UNSET;
    2628           0 :         return;
    2629             :     }
    2630             : 
    2631          76 :     m_nProcessingFlags |= PROCESSING_FLAG_NODATA;
    2632          76 :     m_dfNoDataValue = dfNewNoDataValue;
    2633             : }
    2634             : 
    2635             : /************************************************************************/
    2636             : /*                      GetAdjustedNoDataValue()                        */
    2637             : /************************************************************************/
    2638             : 
    2639        5003 : double VRTComplexSource::GetAdjustedNoDataValue() const
    2640             : {
    2641        5003 :     if ((m_nProcessingFlags & PROCESSING_FLAG_NODATA) != 0)
    2642             :     {
    2643          47 :         auto l_band = GetRasterBand();
    2644          47 :         if (l_band && l_band->GetRasterDataType() == GDT_Float32)
    2645             :         {
    2646          21 :             return GDALAdjustNoDataCloseToFloatMax(m_dfNoDataValue);
    2647             :         }
    2648             :     }
    2649        4982 :     return m_dfNoDataValue;
    2650             : }
    2651             : 
    2652             : /************************************************************************/
    2653             : /*                           SerializeToXML()                           */
    2654             : /************************************************************************/
    2655             : 
    2656          67 : CPLXMLNode *VRTComplexSource::SerializeToXML(const char *pszVRTPath)
    2657             : 
    2658             : {
    2659          67 :     CPLXMLNode *psSrc = VRTSimpleSource::SerializeToXML(pszVRTPath);
    2660             : 
    2661          67 :     if (psSrc == nullptr)
    2662           0 :         return nullptr;
    2663             : 
    2664          67 :     CPLFree(psSrc->pszValue);
    2665          67 :     psSrc->pszValue = CPLStrdup(GetTypeStatic());
    2666             : 
    2667          67 :     if ((m_nProcessingFlags & PROCESSING_FLAG_USE_MASK_BAND) != 0)
    2668             :     {
    2669          33 :         CPLSetXMLValue(psSrc, "UseMaskBand", "true");
    2670             :     }
    2671             : 
    2672          67 :     if ((m_nProcessingFlags & PROCESSING_FLAG_NODATA) != 0)
    2673             :     {
    2674          24 :         if (!m_osNoDataValueOri.empty() && GetRasterBandNoOpen() == nullptr)
    2675             :         {
    2676           1 :             CPLSetXMLValue(psSrc, "NODATA", m_osNoDataValueOri.c_str());
    2677             :         }
    2678             :         else
    2679             :         {
    2680          23 :             GDALDataType eBandDT = GDT_Unknown;
    2681          23 :             double dfNoDataValue = m_dfNoDataValue;
    2682          23 :             const auto kMaxFloat = std::numeric_limits<float>::max();
    2683          23 :             if (std::fabs(std::fabs(m_dfNoDataValue) - kMaxFloat) <
    2684             :                 1e-10 * kMaxFloat)
    2685             :             {
    2686           1 :                 auto l_band = GetRasterBand();
    2687           1 :                 if (l_band)
    2688             :                 {
    2689           1 :                     dfNoDataValue = GetAdjustedNoDataValue();
    2690           1 :                     eBandDT = l_band->GetRasterDataType();
    2691             :                 }
    2692             :             }
    2693          23 :             CPLSetXMLValue(
    2694             :                 psSrc, "NODATA",
    2695          46 :                 VRTSerializeNoData(dfNoDataValue, eBandDT, 18).c_str());
    2696             :         }
    2697             :     }
    2698             : 
    2699          67 :     if ((m_nProcessingFlags & PROCESSING_FLAG_SCALING_LINEAR) != 0)
    2700             :     {
    2701           1 :         CPLSetXMLValue(psSrc, "ScaleOffset", CPLSPrintf("%g", m_dfScaleOff));
    2702           1 :         CPLSetXMLValue(psSrc, "ScaleRatio", CPLSPrintf("%g", m_dfScaleRatio));
    2703             :     }
    2704          66 :     else if ((m_nProcessingFlags & PROCESSING_FLAG_SCALING_EXPONENTIAL) != 0)
    2705             :     {
    2706           0 :         CPLSetXMLValue(psSrc, "Exponent", CPLSPrintf("%g", m_dfExponent));
    2707           0 :         if (m_bSrcMinMaxDefined)
    2708             :         {
    2709           0 :             CPLSetXMLValue(psSrc, "SrcMin", CPLSPrintf("%g", m_dfSrcMin));
    2710           0 :             CPLSetXMLValue(psSrc, "SrcMax", CPLSPrintf("%g", m_dfSrcMax));
    2711             :         }
    2712           0 :         CPLSetXMLValue(psSrc, "DstMin", CPLSPrintf("%g", m_dfDstMin));
    2713           0 :         CPLSetXMLValue(psSrc, "DstMax", CPLSPrintf("%g", m_dfDstMax));
    2714           0 :         CPLSetXMLValue(psSrc, "Clip", m_bClip ? "true" : "false");
    2715             :     }
    2716             : 
    2717          67 :     if (!m_adfLUTInputs.empty())
    2718             :     {
    2719             :         // Make sure we print with sufficient precision to address really close
    2720             :         // entries (#6422).
    2721           0 :         CPLString osLUT;
    2722           0 :         if (m_adfLUTInputs.size() >= 2 &&
    2723           0 :             CPLString().Printf("%g", m_adfLUTInputs[0]) ==
    2724           0 :                 CPLString().Printf("%g", m_adfLUTInputs[1]))
    2725             :         {
    2726           0 :             osLUT = CPLString().Printf("%.17g:%g", m_adfLUTInputs[0],
    2727           0 :                                        m_adfLUTOutputs[0]);
    2728             :         }
    2729             :         else
    2730             :         {
    2731           0 :             osLUT = CPLString().Printf("%g:%g", m_adfLUTInputs[0],
    2732           0 :                                        m_adfLUTOutputs[0]);
    2733             :         }
    2734           0 :         for (size_t i = 1; i < m_adfLUTInputs.size(); i++)
    2735             :         {
    2736           0 :             if (CPLString().Printf("%g", m_adfLUTInputs[i]) ==
    2737           0 :                     CPLString().Printf("%g", m_adfLUTInputs[i - 1]) ||
    2738           0 :                 (i + 1 < m_adfLUTInputs.size() &&
    2739           0 :                  CPLString().Printf("%g", m_adfLUTInputs[i]) ==
    2740           0 :                      CPLString().Printf("%g", m_adfLUTInputs[i + 1])))
    2741             :             {
    2742             :                 // TODO(schwehr): An explanation of the 18 would be helpful.
    2743             :                 // Can someone distill the issue down to a quick comment?
    2744             :                 // https://trac.osgeo.org/gdal/ticket/6422
    2745           0 :                 osLUT += CPLString().Printf(",%.17g:%g", m_adfLUTInputs[i],
    2746           0 :                                             m_adfLUTOutputs[i]);
    2747             :             }
    2748             :             else
    2749             :             {
    2750           0 :                 osLUT += CPLString().Printf(",%g:%g", m_adfLUTInputs[i],
    2751           0 :                                             m_adfLUTOutputs[i]);
    2752             :             }
    2753             :         }
    2754           0 :         CPLSetXMLValue(psSrc, "LUT", osLUT);
    2755             :     }
    2756             : 
    2757          67 :     if (m_nColorTableComponent)
    2758             :     {
    2759           7 :         CPLSetXMLValue(psSrc, "ColorTableComponent",
    2760             :                        CPLSPrintf("%d", m_nColorTableComponent));
    2761             :     }
    2762             : 
    2763          67 :     return psSrc;
    2764             : }
    2765             : 
    2766             : /************************************************************************/
    2767             : /*                              XMLInit()                               */
    2768             : /************************************************************************/
    2769             : 
    2770         259 : CPLErr VRTComplexSource::XMLInit(const CPLXMLNode *psSrc,
    2771             :                                  const char *pszVRTPath,
    2772             :                                  VRTMapSharedResources &oMapSharedSources)
    2773             : 
    2774             : {
    2775             :     /* -------------------------------------------------------------------- */
    2776             :     /*      Do base initialization.                                         */
    2777             :     /* -------------------------------------------------------------------- */
    2778             :     {
    2779             :         const CPLErr eErr =
    2780         259 :             VRTSimpleSource::XMLInit(psSrc, pszVRTPath, oMapSharedSources);
    2781         259 :         if (eErr != CE_None)
    2782           0 :             return eErr;
    2783             :     }
    2784             : 
    2785             :     /* -------------------------------------------------------------------- */
    2786             :     /*      Complex parameters.                                             */
    2787             :     /* -------------------------------------------------------------------- */
    2788         259 :     const char *pszScaleOffset = CPLGetXMLValue(psSrc, "ScaleOffset", nullptr);
    2789         259 :     const char *pszScaleRatio = CPLGetXMLValue(psSrc, "ScaleRatio", nullptr);
    2790         259 :     if (pszScaleOffset || pszScaleRatio)
    2791             :     {
    2792          28 :         m_nProcessingFlags |= PROCESSING_FLAG_SCALING_LINEAR;
    2793          28 :         if (pszScaleOffset)
    2794          28 :             m_dfScaleOff = CPLAtof(pszScaleOffset);
    2795          28 :         if (pszScaleRatio)
    2796          25 :             m_dfScaleRatio = CPLAtof(pszScaleRatio);
    2797             :     }
    2798         231 :     else if (CPLGetXMLValue(psSrc, "Exponent", nullptr) != nullptr &&
    2799         232 :              CPLGetXMLValue(psSrc, "DstMin", nullptr) != nullptr &&
    2800           1 :              CPLGetXMLValue(psSrc, "DstMax", nullptr) != nullptr)
    2801             :     {
    2802           1 :         m_nProcessingFlags |= PROCESSING_FLAG_SCALING_EXPONENTIAL;
    2803           1 :         m_dfExponent = CPLAtof(CPLGetXMLValue(psSrc, "Exponent", "1.0"));
    2804             : 
    2805           1 :         const char *pszSrcMin = CPLGetXMLValue(psSrc, "SrcMin", nullptr);
    2806           1 :         const char *pszSrcMax = CPLGetXMLValue(psSrc, "SrcMax", nullptr);
    2807           1 :         if (pszSrcMin && pszSrcMax)
    2808             :         {
    2809           0 :             m_dfSrcMin = CPLAtof(pszSrcMin);
    2810           0 :             m_dfSrcMax = CPLAtof(pszSrcMax);
    2811           0 :             m_bSrcMinMaxDefined = true;
    2812             :         }
    2813             : 
    2814           1 :         m_dfDstMin = CPLAtof(CPLGetXMLValue(psSrc, "DstMin", "0.0"));
    2815           1 :         m_dfDstMax = CPLAtof(CPLGetXMLValue(psSrc, "DstMax", "0.0"));
    2816           1 :         m_bClip = CPLTestBool(CPLGetXMLValue(psSrc, "Clip", "true"));
    2817             :     }
    2818             : 
    2819         259 :     if (const char *pszNODATA = CPLGetXMLValue(psSrc, "NODATA", nullptr))
    2820             :     {
    2821          63 :         m_nProcessingFlags |= PROCESSING_FLAG_NODATA;
    2822          63 :         m_osNoDataValueOri = pszNODATA;
    2823          63 :         m_dfNoDataValue = CPLAtofM(m_osNoDataValueOri.c_str());
    2824             :     }
    2825             : 
    2826         259 :     const char *pszUseMaskBand = CPLGetXMLValue(psSrc, "UseMaskBand", nullptr);
    2827         259 :     if (pszUseMaskBand && CPLTestBool(pszUseMaskBand))
    2828             :     {
    2829          41 :         m_nProcessingFlags |= PROCESSING_FLAG_USE_MASK_BAND;
    2830             :     }
    2831             : 
    2832         259 :     const char *pszLUT = CPLGetXMLValue(psSrc, "LUT", nullptr);
    2833         259 :     if (pszLUT)
    2834             :     {
    2835             :         const CPLStringList aosValues(
    2836          75 :             CSLTokenizeString2(pszLUT, ",:", CSLT_ALLOWEMPTYTOKENS));
    2837             : 
    2838          75 :         const int nLUTItemCount = aosValues.size() / 2;
    2839             :         try
    2840             :         {
    2841          75 :             m_adfLUTInputs.resize(nLUTItemCount);
    2842          75 :             m_adfLUTOutputs.resize(nLUTItemCount);
    2843             :         }
    2844           0 :         catch (const std::bad_alloc &e)
    2845             :         {
    2846           0 :             CPLError(CE_Failure, CPLE_OutOfMemory, "%s", e.what());
    2847           0 :             m_adfLUTInputs.clear();
    2848           0 :             m_adfLUTOutputs.clear();
    2849           0 :             return CE_Failure;
    2850             :         }
    2851             : 
    2852         732 :         for (int nIndex = 0; nIndex < nLUTItemCount; nIndex++)
    2853             :         {
    2854         657 :             m_adfLUTInputs[nIndex] = CPLAtof(aosValues[nIndex * 2]);
    2855         657 :             m_adfLUTOutputs[nIndex] = CPLAtof(aosValues[nIndex * 2 + 1]);
    2856             : 
    2857             :             // Enforce the requirement that the LUT input array is
    2858             :             // monotonically non-decreasing.
    2859         657 :             if (std::isnan(m_adfLUTInputs[nIndex]) && nIndex != 0)
    2860             :             {
    2861           0 :                 CPLError(CE_Failure, CPLE_AppDefined,
    2862             :                          "A Not-A-Number (NaN) source value should be the "
    2863             :                          "first one of the LUT.");
    2864           0 :                 m_adfLUTInputs.clear();
    2865           0 :                 m_adfLUTOutputs.clear();
    2866           0 :                 return CE_Failure;
    2867             :             }
    2868        1239 :             else if (nIndex > 0 &&
    2869         582 :                      m_adfLUTInputs[nIndex] < m_adfLUTInputs[nIndex - 1])
    2870             :             {
    2871           0 :                 CPLError(CE_Failure, CPLE_AppDefined,
    2872             :                          "Source values of the LUT are not listed in a "
    2873             :                          "monotonically non-decreasing order");
    2874           0 :                 m_adfLUTInputs.clear();
    2875           0 :                 m_adfLUTOutputs.clear();
    2876           0 :                 return CE_Failure;
    2877             :             }
    2878             :         }
    2879             : 
    2880          75 :         m_nProcessingFlags |= PROCESSING_FLAG_LUT;
    2881             :     }
    2882             : 
    2883             :     const char *pszColorTableComponent =
    2884         259 :         CPLGetXMLValue(psSrc, "ColorTableComponent", nullptr);
    2885         259 :     if (pszColorTableComponent)
    2886             :     {
    2887          15 :         m_nColorTableComponent = atoi(pszColorTableComponent);
    2888          15 :         m_nProcessingFlags |= PROCESSING_FLAG_COLOR_TABLE_EXPANSION;
    2889             :     }
    2890             : 
    2891         259 :     return CE_None;
    2892             : }
    2893             : 
    2894             : /************************************************************************/
    2895             : /*                              LookupValue()                           */
    2896             : /************************************************************************/
    2897             : 
    2898      817592 : double VRTComplexSource::LookupValue(double dfInput)
    2899             : {
    2900      817592 :     auto beginIter = m_adfLUTInputs.begin();
    2901      817592 :     auto endIter = m_adfLUTInputs.end();
    2902      817592 :     size_t offset = 0;
    2903      817592 :     if (std::isnan(m_adfLUTInputs[0]))
    2904             :     {
    2905           6 :         if (std::isnan(dfInput) || m_adfLUTInputs.size() == 1)
    2906           1 :             return m_adfLUTOutputs[0];
    2907           5 :         ++beginIter;
    2908           5 :         offset = 1;
    2909             :     }
    2910             : 
    2911             :     // Find the index of the first element in the LUT input array that
    2912             :     // is not smaller than the input value.
    2913             :     const size_t i =
    2914             :         offset +
    2915      817591 :         std::distance(beginIter, std::lower_bound(beginIter, endIter, dfInput));
    2916             : 
    2917      817591 :     if (i == offset)
    2918      129039 :         return m_adfLUTOutputs[offset];
    2919             : 
    2920             :     // If the index is beyond the end of the LUT input array, the input
    2921             :     // value is larger than all the values in the array.
    2922      688552 :     if (i == m_adfLUTInputs.size())
    2923           8 :         return m_adfLUTOutputs.back();
    2924             : 
    2925      688544 :     if (m_adfLUTInputs[i] == dfInput)
    2926      240268 :         return m_adfLUTOutputs[i];
    2927             : 
    2928             :     // Otherwise, interpolate.
    2929      448276 :     return m_adfLUTOutputs[i - 1] +
    2930      448276 :            (dfInput - m_adfLUTInputs[i - 1]) *
    2931      448276 :                ((m_adfLUTOutputs[i] - m_adfLUTOutputs[i - 1]) /
    2932      448276 :                 (m_adfLUTInputs[i] - m_adfLUTInputs[i - 1]));
    2933             : }
    2934             : 
    2935             : /************************************************************************/
    2936             : /*                         SetLinearScaling()                           */
    2937             : /************************************************************************/
    2938             : 
    2939         106 : void VRTComplexSource::SetLinearScaling(double dfOffset, double dfScale)
    2940             : {
    2941         106 :     m_nProcessingFlags &= ~PROCESSING_FLAG_SCALING_EXPONENTIAL;
    2942         106 :     m_nProcessingFlags |= PROCESSING_FLAG_SCALING_LINEAR;
    2943         106 :     m_dfScaleOff = dfOffset;
    2944         106 :     m_dfScaleRatio = dfScale;
    2945         106 : }
    2946             : 
    2947             : /************************************************************************/
    2948             : /*                         SetPowerScaling()                           */
    2949             : /************************************************************************/
    2950             : 
    2951          26 : void VRTComplexSource::SetPowerScaling(double dfExponentIn, double dfSrcMinIn,
    2952             :                                        double dfSrcMaxIn, double dfDstMinIn,
    2953             :                                        double dfDstMaxIn, bool bClip)
    2954             : {
    2955          26 :     m_nProcessingFlags &= ~PROCESSING_FLAG_SCALING_LINEAR;
    2956          26 :     m_nProcessingFlags |= PROCESSING_FLAG_SCALING_EXPONENTIAL;
    2957          26 :     m_dfExponent = dfExponentIn;
    2958          26 :     m_dfSrcMin = dfSrcMinIn;
    2959          26 :     m_dfSrcMax = dfSrcMaxIn;
    2960          26 :     m_dfDstMin = dfDstMinIn;
    2961          26 :     m_dfDstMax = dfDstMaxIn;
    2962          26 :     m_bSrcMinMaxDefined = true;
    2963          26 :     m_bClip = bClip;
    2964          26 : }
    2965             : 
    2966             : /************************************************************************/
    2967             : /*                    SetColorTableComponent()                          */
    2968             : /************************************************************************/
    2969             : 
    2970         245 : void VRTComplexSource::SetColorTableComponent(int nComponent)
    2971             : {
    2972         245 :     m_nProcessingFlags |= PROCESSING_FLAG_COLOR_TABLE_EXPANSION;
    2973         245 :     m_nColorTableComponent = nComponent;
    2974         245 : }
    2975             : 
    2976             : /************************************************************************/
    2977             : /*                              RasterIO()                              */
    2978             : /************************************************************************/
    2979             : 
    2980       15993 : CPLErr VRTComplexSource::RasterIO(GDALDataType eVRTBandDataType, int nXOff,
    2981             :                                   int nYOff, int nXSize, int nYSize,
    2982             :                                   void *pData, int nBufXSize, int nBufYSize,
    2983             :                                   GDALDataType eBufType, GSpacing nPixelSpace,
    2984             :                                   GSpacing nLineSpace,
    2985             :                                   GDALRasterIOExtraArg *psExtraArgIn,
    2986             :                                   WorkingState &oWorkingState)
    2987             : 
    2988             : {
    2989             :     GDALRasterIOExtraArg sExtraArg;
    2990       15993 :     INIT_RASTERIO_EXTRA_ARG(sExtraArg);
    2991       15993 :     GDALRasterIOExtraArg *psExtraArg = &sExtraArg;
    2992             : 
    2993       15993 :     double dfXOff = nXOff;
    2994       15993 :     double dfYOff = nYOff;
    2995       15993 :     double dfXSize = nXSize;
    2996       15993 :     double dfYSize = nYSize;
    2997       15993 :     if (psExtraArgIn != nullptr && psExtraArgIn->bFloatingPointWindowValidity)
    2998             :     {
    2999          87 :         dfXOff = psExtraArgIn->dfXOff;
    3000          87 :         dfYOff = psExtraArgIn->dfYOff;
    3001          87 :         dfXSize = psExtraArgIn->dfXSize;
    3002          87 :         dfYSize = psExtraArgIn->dfYSize;
    3003             :     }
    3004             : 
    3005             :     // The window we will actually request from the source raster band.
    3006       15993 :     double dfReqXOff = 0.0;
    3007       15993 :     double dfReqYOff = 0.0;
    3008       15993 :     double dfReqXSize = 0.0;
    3009       15993 :     double dfReqYSize = 0.0;
    3010       15993 :     int nReqXOff = 0;
    3011       15993 :     int nReqYOff = 0;
    3012       15993 :     int nReqXSize = 0;
    3013       15993 :     int nReqYSize = 0;
    3014             : 
    3015             :     // The window we will actual set _within_ the pData buffer.
    3016       15993 :     int nOutXOff = 0;
    3017       15993 :     int nOutYOff = 0;
    3018       15993 :     int nOutXSize = 0;
    3019       15993 :     int nOutYSize = 0;
    3020             : 
    3021       15993 :     bool bError = false;
    3022       15993 :     if (!GetSrcDstWindow(dfXOff, dfYOff, dfXSize, dfYSize, nBufXSize, nBufYSize,
    3023             :                          &dfReqXOff, &dfReqYOff, &dfReqXSize, &dfReqYSize,
    3024             :                          &nReqXOff, &nReqYOff, &nReqXSize, &nReqYSize,
    3025             :                          &nOutXOff, &nOutYOff, &nOutXSize, &nOutYSize, bError))
    3026             :     {
    3027       10946 :         return bError ? CE_Failure : CE_None;
    3028             :     }
    3029             : #if DEBUG_VERBOSE
    3030             :     CPLDebug("VRT",
    3031             :              "nXOff=%d, nYOff=%d, nXSize=%d, nYSize=%d, nBufXSize=%d, "
    3032             :              "nBufYSize=%d,\n"
    3033             :              "dfReqXOff=%g, dfReqYOff=%g, dfReqXSize=%g, dfReqYSize=%g,\n"
    3034             :              "nReqXOff=%d, nReqYOff=%d, nReqXSize=%d, nReqYSize=%d,\n"
    3035             :              "nOutXOff=%d, nOutYOff=%d, nOutXSize=%d, nOutYSize=%d",
    3036             :              nXOff, nYOff, nXSize, nYSize, nBufXSize, nBufYSize, dfReqXOff,
    3037             :              dfReqYOff, dfReqXSize, dfReqYSize, nReqXOff, nReqYOff, nReqXSize,
    3038             :              nReqYSize, nOutXOff, nOutYOff, nOutXSize, nOutYSize);
    3039             : #endif
    3040             : 
    3041        5047 :     auto poSourceBand = GetRasterBand();
    3042        5047 :     if (!poSourceBand)
    3043           0 :         return CE_Failure;
    3044             : 
    3045        5047 :     if (!m_osResampling.empty())
    3046             :     {
    3047          28 :         psExtraArg->eResampleAlg = GDALRasterIOGetResampleAlg(m_osResampling);
    3048             :     }
    3049        5019 :     else if (psExtraArgIn != nullptr)
    3050             :     {
    3051        5019 :         psExtraArg->eResampleAlg = psExtraArgIn->eResampleAlg;
    3052             :     }
    3053        5047 :     psExtraArg->bFloatingPointWindowValidity = TRUE;
    3054        5047 :     psExtraArg->dfXOff = dfReqXOff;
    3055        5047 :     psExtraArg->dfYOff = dfReqYOff;
    3056        5047 :     psExtraArg->dfXSize = dfReqXSize;
    3057        5047 :     psExtraArg->dfYSize = dfReqYSize;
    3058        5047 :     if (psExtraArgIn)
    3059             :     {
    3060        5047 :         psExtraArg->pfnProgress = psExtraArgIn->pfnProgress;
    3061        5047 :         psExtraArg->pProgressData = psExtraArgIn->pProgressData;
    3062             :     }
    3063             : 
    3064        5047 :     GByte *const pabyOut = static_cast<GByte *>(pData) +
    3065        5047 :                            nPixelSpace * nOutXOff +
    3066        5047 :                            static_cast<GPtrDiff_t>(nLineSpace) * nOutYOff;
    3067        5047 :     const auto eSourceType = poSourceBand->GetRasterDataType();
    3068        5047 :     if (m_nProcessingFlags == PROCESSING_FLAG_NODATA)
    3069             :     {
    3070             :         // Optimization if doing only nodata processing
    3071          82 :         if (eSourceType == GDT_Byte)
    3072             :         {
    3073          45 :             if (!GDALIsValueInRange<GByte>(m_dfNoDataValue))
    3074             :             {
    3075           7 :                 return VRTSimpleSource::RasterIO(
    3076             :                     eVRTBandDataType, nXOff, nYOff, nXSize, nYSize, pData,
    3077             :                     nBufXSize, nBufYSize, eBufType, nPixelSpace, nLineSpace,
    3078           7 :                     psExtraArgIn, oWorkingState);
    3079             :             }
    3080             : 
    3081          38 :             return RasterIOProcessNoData<GByte, GDT_Byte>(
    3082             :                 poSourceBand, eVRTBandDataType, nReqXOff, nReqYOff, nReqXSize,
    3083             :                 nReqYSize, pabyOut, nOutXSize, nOutYSize, eBufType, nPixelSpace,
    3084          38 :                 nLineSpace, psExtraArg, oWorkingState);
    3085             :         }
    3086          37 :         else if (eSourceType == GDT_Int16)
    3087             :         {
    3088           6 :             if (!GDALIsValueInRange<int16_t>(m_dfNoDataValue))
    3089             :             {
    3090           1 :                 return VRTSimpleSource::RasterIO(
    3091             :                     eVRTBandDataType, nXOff, nYOff, nXSize, nYSize, pData,
    3092             :                     nBufXSize, nBufYSize, eBufType, nPixelSpace, nLineSpace,
    3093           1 :                     psExtraArgIn, oWorkingState);
    3094             :             }
    3095             : 
    3096           5 :             return RasterIOProcessNoData<int16_t, GDT_Int16>(
    3097             :                 poSourceBand, eVRTBandDataType, nReqXOff, nReqYOff, nReqXSize,
    3098             :                 nReqYSize, pabyOut, nOutXSize, nOutYSize, eBufType, nPixelSpace,
    3099           5 :                 nLineSpace, psExtraArg, oWorkingState);
    3100             :         }
    3101          31 :         else if (eSourceType == GDT_UInt16)
    3102             :         {
    3103           8 :             if (!GDALIsValueInRange<uint16_t>(m_dfNoDataValue))
    3104             :             {
    3105           1 :                 return VRTSimpleSource::RasterIO(
    3106             :                     eVRTBandDataType, nXOff, nYOff, nXSize, nYSize, pData,
    3107             :                     nBufXSize, nBufYSize, eBufType, nPixelSpace, nLineSpace,
    3108           1 :                     psExtraArgIn, oWorkingState);
    3109             :             }
    3110             : 
    3111           7 :             return RasterIOProcessNoData<uint16_t, GDT_UInt16>(
    3112             :                 poSourceBand, eVRTBandDataType, nReqXOff, nReqYOff, nReqXSize,
    3113             :                 nReqYSize, pabyOut, nOutXSize, nOutYSize, eBufType, nPixelSpace,
    3114           7 :                 nLineSpace, psExtraArg, oWorkingState);
    3115             :         }
    3116             :     }
    3117             : 
    3118        4988 :     const bool bIsComplex = CPL_TO_BOOL(GDALDataTypeIsComplex(eBufType));
    3119             :     CPLErr eErr;
    3120             :     // For Int32, float32 isn't sufficiently precise as working data type
    3121        4988 :     if (eVRTBandDataType == GDT_CInt32 || eVRTBandDataType == GDT_CFloat64 ||
    3122        4984 :         eVRTBandDataType == GDT_Int32 || eVRTBandDataType == GDT_UInt32 ||
    3123        4980 :         eVRTBandDataType == GDT_Int64 || eVRTBandDataType == GDT_UInt64 ||
    3124        4956 :         eVRTBandDataType == GDT_Float64 || eSourceType == GDT_Int32 ||
    3125        4955 :         eSourceType == GDT_UInt32 || eSourceType == GDT_Int64 ||
    3126             :         eSourceType == GDT_UInt64)
    3127             :     {
    3128          34 :         eErr = RasterIOInternal<double>(
    3129             :             poSourceBand, eVRTBandDataType, nReqXOff, nReqYOff, nReqXSize,
    3130             :             nReqYSize, pabyOut, nOutXSize, nOutYSize, eBufType, nPixelSpace,
    3131             :             nLineSpace, psExtraArg, bIsComplex ? GDT_CFloat64 : GDT_Float64,
    3132             :             oWorkingState);
    3133             :     }
    3134             :     else
    3135             :     {
    3136        4954 :         eErr = RasterIOInternal<float>(
    3137             :             poSourceBand, eVRTBandDataType, nReqXOff, nReqYOff, nReqXSize,
    3138             :             nReqYSize, pabyOut, nOutXSize, nOutYSize, eBufType, nPixelSpace,
    3139             :             nLineSpace, psExtraArg, bIsComplex ? GDT_CFloat32 : GDT_Float32,
    3140             :             oWorkingState);
    3141             :     }
    3142             : 
    3143        4988 :     if (psExtraArg->pfnProgress)
    3144          43 :         psExtraArg->pfnProgress(1.0, "", psExtraArg->pProgressData);
    3145             : 
    3146        4988 :     return eErr;
    3147             : }
    3148             : 
    3149             : /************************************************************************/
    3150             : /*                              hasZeroByte()                           */
    3151             : /************************************************************************/
    3152             : 
    3153             : CPL_NOSANITIZE_UNSIGNED_INT_OVERFLOW
    3154     3522930 : static inline bool hasZeroByte(uint32_t v)
    3155             : {
    3156             :     // Cf https://graphics.stanford.edu/~seander/bithacks.html#ZeroInWord
    3157     3522930 :     return (((v)-0x01010101U) & ~(v)&0x80808080U) != 0;
    3158             : }
    3159             : 
    3160             : /************************************************************************/
    3161             : /*                                CopyWord()                            */
    3162             : /************************************************************************/
    3163             : 
    3164             : template <class SrcType>
    3165     6677648 : static void CopyWord(const SrcType *pSrcVal, GDALDataType eSrcType,
    3166             :                      void *pDstVal, GDALDataType eDstType)
    3167             : {
    3168     6677648 :     switch (eDstType)
    3169             :     {
    3170     2383720 :         case GDT_Byte:
    3171     2383720 :             GDALCopyWord(*pSrcVal, *static_cast<uint8_t *>(pDstVal));
    3172     2383720 :             break;
    3173          82 :         case GDT_Int8:
    3174          82 :             GDALCopyWord(*pSrcVal, *static_cast<int8_t *>(pDstVal));
    3175          82 :             break;
    3176     1353720 :         case GDT_UInt16:
    3177     1353720 :             GDALCopyWord(*pSrcVal, *static_cast<uint16_t *>(pDstVal));
    3178     1353720 :             break;
    3179     2925180 :         case GDT_Int16:
    3180     2925180 :             GDALCopyWord(*pSrcVal, *static_cast<int16_t *>(pDstVal));
    3181     2925180 :             break;
    3182          22 :         case GDT_UInt32:
    3183          22 :             GDALCopyWord(*pSrcVal, *static_cast<uint32_t *>(pDstVal));
    3184          22 :             break;
    3185         641 :         case GDT_Int32:
    3186         641 :             GDALCopyWord(*pSrcVal, *static_cast<int32_t *>(pDstVal));
    3187         641 :             break;
    3188          22 :         case GDT_UInt64:
    3189          22 :             GDALCopyWord(*pSrcVal, *static_cast<uint64_t *>(pDstVal));
    3190          22 :             break;
    3191          42 :         case GDT_Int64:
    3192          42 :             GDALCopyWord(*pSrcVal, *static_cast<int64_t *>(pDstVal));
    3193          42 :             break;
    3194        6660 :         case GDT_Float32:
    3195        6660 :             GDALCopyWord(*pSrcVal, *static_cast<float *>(pDstVal));
    3196        6660 :             break;
    3197        6539 :         case GDT_Float64:
    3198        6539 :             GDALCopyWord(*pSrcVal, *static_cast<double *>(pDstVal));
    3199        6539 :             break;
    3200        1019 :         default:
    3201        1019 :             GDALCopyWords(pSrcVal, eSrcType, 0, pDstVal, eDstType, 0, 1);
    3202        1019 :             break;
    3203             :     }
    3204     6677648 : }
    3205             : 
    3206             : /************************************************************************/
    3207             : /*                       RasterIOProcessNoData()                        */
    3208             : /************************************************************************/
    3209             : 
    3210             : // This method is an optimization of the generic RasterIOInternal()
    3211             : // that deals with a VRTComplexSource with only a NODATA value in it, and
    3212             : // no other processing flags.
    3213             : 
    3214             : // nReqXOff, nReqYOff, nReqXSize, nReqYSize are expressed in source band
    3215             : // referential.
    3216             : template <class SourceDT, GDALDataType eSourceType>
    3217          50 : CPLErr VRTComplexSource::RasterIOProcessNoData(
    3218             :     GDALRasterBand *poSourceBand, GDALDataType eVRTBandDataType, int nReqXOff,
    3219             :     int nReqYOff, int nReqXSize, int nReqYSize, void *pData, int nOutXSize,
    3220             :     int nOutYSize, GDALDataType eBufType, GSpacing nPixelSpace,
    3221             :     GSpacing nLineSpace, GDALRasterIOExtraArg *psExtraArg,
    3222             :     WorkingState &oWorkingState)
    3223             : {
    3224          50 :     CPLAssert(m_nProcessingFlags == PROCESSING_FLAG_NODATA);
    3225          50 :     CPLAssert(GDALIsValueInRange<SourceDT>(m_dfNoDataValue));
    3226             : 
    3227             :     /* -------------------------------------------------------------------- */
    3228             :     /*      Read into a temporary buffer.                                   */
    3229             :     /* -------------------------------------------------------------------- */
    3230             :     try
    3231             :     {
    3232             :         // Cannot overflow since pData should at least have that number of
    3233             :         // elements
    3234          50 :         const size_t nPixelCount = static_cast<size_t>(nOutXSize) * nOutYSize;
    3235          50 :         if (nPixelCount >
    3236          50 :             static_cast<size_t>(std::numeric_limits<ptrdiff_t>::max()) /
    3237             :                 sizeof(SourceDT))
    3238             :         {
    3239           0 :             CPLError(CE_Failure, CPLE_OutOfMemory,
    3240             :                      "Too large temporary buffer");
    3241           0 :             return CE_Failure;
    3242             :         }
    3243          50 :         oWorkingState.m_abyWrkBuffer.resize(sizeof(SourceDT) * nPixelCount);
    3244             :     }
    3245           0 :     catch (const std::bad_alloc &e)
    3246             :     {
    3247           0 :         CPLError(CE_Failure, CPLE_OutOfMemory, "%s", e.what());
    3248           0 :         return CE_Failure;
    3249             :     }
    3250             :     const auto paSrcData =
    3251          50 :         reinterpret_cast<const SourceDT *>(oWorkingState.m_abyWrkBuffer.data());
    3252             : 
    3253          50 :     const GDALRIOResampleAlg eResampleAlgBack = psExtraArg->eResampleAlg;
    3254          50 :     if (!m_osResampling.empty())
    3255             :     {
    3256           0 :         psExtraArg->eResampleAlg = GDALRasterIOGetResampleAlg(m_osResampling);
    3257             :     }
    3258             : 
    3259          50 :     const CPLErr eErr = poSourceBand->RasterIO(
    3260             :         GF_Read, nReqXOff, nReqYOff, nReqXSize, nReqYSize,
    3261          50 :         oWorkingState.m_abyWrkBuffer.data(), nOutXSize, nOutYSize, eSourceType,
    3262          12 :         sizeof(SourceDT), sizeof(SourceDT) * static_cast<GSpacing>(nOutXSize),
    3263             :         psExtraArg);
    3264          50 :     if (!m_osResampling.empty())
    3265           0 :         psExtraArg->eResampleAlg = eResampleAlgBack;
    3266             : 
    3267          50 :     if (eErr != CE_None)
    3268             :     {
    3269           0 :         return eErr;
    3270             :     }
    3271             : 
    3272          50 :     const auto nNoDataValue = static_cast<SourceDT>(m_dfNoDataValue);
    3273          50 :     size_t idxBuffer = 0;
    3274          82 :     if (eSourceType == eBufType &&
    3275          32 :         !GDALDataTypeIsConversionLossy(eSourceType, eVRTBandDataType))
    3276             :     {
    3277             :         // Most optimized case: the output type is the same as the source type,
    3278             :         // and conversion from the source type to the VRT band data type is
    3279             :         // not lossy
    3280          14 :         for (int iY = 0; iY < nOutYSize; iY++)
    3281             :         {
    3282       19591 :             GByte *pDstLocation = static_cast<GByte *>(pData) +
    3283       19591 :                                   static_cast<GPtrDiff_t>(nLineSpace) * iY;
    3284             : 
    3285       19591 :             int iX = 0;
    3286       19579 :             if (sizeof(SourceDT) == 1 && nPixelSpace == 1)
    3287             :             {
    3288             :                 // Optimization to detect more quickly if source pixels are
    3289             :                 // at nodata.
    3290       19575 :                 const GByte byNoDataValue = static_cast<GByte>(nNoDataValue);
    3291       19575 :                 const uint32_t wordNoData =
    3292       19575 :                     (static_cast<uint32_t>(byNoDataValue) << 24) |
    3293       19575 :                     (byNoDataValue << 16) | (byNoDataValue << 8) |
    3294       19575 :                     byNoDataValue;
    3295             : 
    3296             :                 // Warning: hasZeroByte() assumes WORD_SIZE = 4
    3297       19575 :                 constexpr int WORD_SIZE = 4;
    3298     3556040 :                 for (; iX < nOutXSize - (WORD_SIZE - 1); iX += WORD_SIZE)
    3299             :                 {
    3300             :                     uint32_t v;
    3301             :                     static_assert(sizeof(v) == WORD_SIZE,
    3302             :                                   "sizeof(v) == WORD_SIZE");
    3303     3720740 :                     memcpy(&v, paSrcData + idxBuffer, sizeof(v));
    3304             :                     // Cf https://graphics.stanford.edu/~seander/bithacks.html#ValueInWord
    3305     3720740 :                     if (!hasZeroByte(v ^ wordNoData))
    3306             :                     {
    3307             :                         // No bytes are at nodata
    3308     3610320 :                         memcpy(pDstLocation, &v, WORD_SIZE);
    3309     3610320 :                         idxBuffer += WORD_SIZE;
    3310     3610320 :                         pDstLocation += WORD_SIZE;
    3311             :                     }
    3312           0 :                     else if (v == wordNoData)
    3313             :                     {
    3314             :                         // All bytes are at nodata
    3315      131075 :                         idxBuffer += WORD_SIZE;
    3316      131075 :                         pDstLocation += WORD_SIZE;
    3317             :                     }
    3318             :                     else
    3319             :                     {
    3320             :                         // There are both bytes at nodata and valid bytes
    3321           0 :                         for (int k = 0; k < WORD_SIZE; ++k)
    3322             :                         {
    3323          48 :                             if (paSrcData[idxBuffer] != nNoDataValue)
    3324             :                             {
    3325          36 :                                 memcpy(pDstLocation, &paSrcData[idxBuffer],
    3326             :                                        sizeof(SourceDT));
    3327             :                             }
    3328          48 :                             idxBuffer++;
    3329          48 :                             pDstLocation += nPixelSpace;
    3330             :                         }
    3331             :                     }
    3332             :                 }
    3333             :             }
    3334             : 
    3335          72 :             for (; iX < nOutXSize;
    3336        3710 :                  iX++, pDstLocation += nPixelSpace, idxBuffer++)
    3337             :             {
    3338        3710 :                 if (paSrcData[idxBuffer] != nNoDataValue)
    3339             :                 {
    3340        3680 :                     memcpy(pDstLocation, &paSrcData[idxBuffer],
    3341             :                            sizeof(SourceDT));
    3342             :                 }
    3343             :             }
    3344             :         }
    3345             :     }
    3346          19 :     else if (!GDALDataTypeIsConversionLossy(eSourceType, eVRTBandDataType))
    3347             :     {
    3348             :         // Conversion from the source type to the VRT band data type is
    3349             :         // not lossy, so we can directly convert from the source type to
    3350             :         // the the output type
    3351         122 :         for (int iY = 0; iY < nOutYSize; iY++)
    3352             :         {
    3353         104 :             GByte *pDstLocation = static_cast<GByte *>(pData) +
    3354         104 :                                   static_cast<GPtrDiff_t>(nLineSpace) * iY;
    3355             : 
    3356        1584 :             for (int iX = 0; iX < nOutXSize;
    3357        1480 :                  iX++, pDstLocation += nPixelSpace, idxBuffer++)
    3358             :             {
    3359        1480 :                 if (paSrcData[idxBuffer] != nNoDataValue)
    3360             :                 {
    3361         671 :                     CopyWord(&paSrcData[idxBuffer], eSourceType, pDstLocation,
    3362             :                              eBufType);
    3363             :                 }
    3364             :             }
    3365             :         }
    3366             :     }
    3367             :     else
    3368             :     {
    3369             :         GByte abyTemp[2 * sizeof(double)];
    3370           7 :         for (int iY = 0; iY < nOutYSize; iY++)
    3371             :         {
    3372           6 :             GByte *pDstLocation = static_cast<GByte *>(pData) +
    3373           6 :                                   static_cast<GPtrDiff_t>(nLineSpace) * iY;
    3374             : 
    3375          36 :             for (int iX = 0; iX < nOutXSize;
    3376          30 :                  iX++, pDstLocation += nPixelSpace, idxBuffer++)
    3377             :             {
    3378          30 :                 if (paSrcData[idxBuffer] != nNoDataValue)
    3379             :                 {
    3380             :                     // Convert first to the VRTRasterBand data type
    3381             :                     // to get its clamping, before outputting to buffer data type
    3382          20 :                     CopyWord(&paSrcData[idxBuffer], eSourceType, abyTemp,
    3383             :                              eVRTBandDataType);
    3384          20 :                     GDALCopyWords(abyTemp, eVRTBandDataType, 0, pDstLocation,
    3385             :                                   eBufType, 0, 1);
    3386             :                 }
    3387             :             }
    3388             :         }
    3389             :     }
    3390             : 
    3391          12 :     return CE_None;
    3392             : }
    3393             : 
    3394             : /************************************************************************/
    3395             : /*                          RasterIOInternal()                          */
    3396             : /************************************************************************/
    3397             : 
    3398             : // nReqXOff, nReqYOff, nReqXSize, nReqYSize are expressed in source band
    3399             : // referential.
    3400             : template <class WorkingDT>
    3401        5002 : CPLErr VRTComplexSource::RasterIOInternal(
    3402             :     GDALRasterBand *poSourceBand, GDALDataType eVRTBandDataType, int nReqXOff,
    3403             :     int nReqYOff, int nReqXSize, int nReqYSize, void *pData, int nOutXSize,
    3404             :     int nOutYSize, GDALDataType eBufType, GSpacing nPixelSpace,
    3405             :     GSpacing nLineSpace, GDALRasterIOExtraArg *psExtraArg,
    3406             :     GDALDataType eWrkDataType, WorkingState &oWorkingState)
    3407             : {
    3408        5002 :     const GDALColorTable *poColorTable = nullptr;
    3409        5002 :     const bool bIsComplex = CPL_TO_BOOL(GDALDataTypeIsComplex(eBufType));
    3410        5002 :     const int nWordSize = GDALGetDataTypeSizeBytes(eWrkDataType);
    3411        5002 :     assert(nWordSize != 0);
    3412             : 
    3413             :     // If no explicit <NODATA> is set, but UseMaskBand is set, and the band
    3414             :     // has a nodata value, then use it as if it was set as <NODATA>
    3415        5002 :     int bNoDataSet = (m_nProcessingFlags & PROCESSING_FLAG_NODATA) != 0;
    3416        5002 :     double dfNoDataValue = GetAdjustedNoDataValue();
    3417             : 
    3418        5107 :     if ((m_nProcessingFlags & PROCESSING_FLAG_USE_MASK_BAND) != 0 &&
    3419         105 :         poSourceBand->GetMaskFlags() == GMF_NODATA)
    3420             :     {
    3421           0 :         dfNoDataValue = poSourceBand->GetNoDataValue(&bNoDataSet);
    3422             :     }
    3423             : 
    3424        5002 :     const bool bNoDataSetIsNan = bNoDataSet && std::isnan(dfNoDataValue);
    3425        5002 :     const bool bNoDataSetAndNotNan =
    3426        5039 :         bNoDataSet && !std::isnan(dfNoDataValue) &&
    3427          37 :         GDALIsValueInRange<WorkingDT>(dfNoDataValue);
    3428        5002 :     const auto fWorkingDataTypeNoData = static_cast<WorkingDT>(dfNoDataValue);
    3429             : 
    3430        5002 :     const GByte *pabyMask = nullptr;
    3431        5002 :     const WorkingDT *pafData = nullptr;
    3432        5002 :     if ((m_nProcessingFlags & PROCESSING_FLAG_SCALING_LINEAR) != 0 &&
    3433        4449 :         m_dfScaleRatio == 0 && bNoDataSet == FALSE &&
    3434        4051 :         (m_nProcessingFlags & PROCESSING_FLAG_USE_MASK_BAND) == 0)
    3435             :     {
    3436             :         /* ------------------------------------------------------------------ */
    3437             :         /*      Optimization when writing a constant value */
    3438             :         /*      (used by the -addalpha option of gdalbuildvrt) */
    3439             :         /* ------------------------------------------------------------------ */
    3440             :         // Already set to NULL when defined.
    3441             :         // pafData = NULL;
    3442             :     }
    3443             :     else
    3444             :     {
    3445             :         /* ---------------------------------------------------------------- */
    3446             :         /*      Read into a temporary buffer.                               */
    3447             :         /* ---------------------------------------------------------------- */
    3448         951 :         const size_t nPixelCount = static_cast<size_t>(nOutXSize) * nOutYSize;
    3449             :         try
    3450             :         {
    3451             :             // Cannot overflow since pData should at least have that number of
    3452             :             // elements
    3453         951 :             if (nPixelCount >
    3454         951 :                 static_cast<size_t>(std::numeric_limits<ptrdiff_t>::max()) /
    3455         951 :                     static_cast<size_t>(nWordSize))
    3456             :             {
    3457           0 :                 CPLError(CE_Failure, CPLE_OutOfMemory,
    3458             :                          "Too large temporary buffer");
    3459           0 :                 return CE_Failure;
    3460             :             }
    3461         951 :             oWorkingState.m_abyWrkBuffer.resize(nWordSize * nPixelCount);
    3462             :         }
    3463           0 :         catch (const std::bad_alloc &e)
    3464             :         {
    3465           0 :             CPLError(CE_Failure, CPLE_OutOfMemory, "%s", e.what());
    3466           0 :             return CE_Failure;
    3467             :         }
    3468             :         pafData = reinterpret_cast<const WorkingDT *>(
    3469         951 :             oWorkingState.m_abyWrkBuffer.data());
    3470             : 
    3471         951 :         const GDALRIOResampleAlg eResampleAlgBack = psExtraArg->eResampleAlg;
    3472         951 :         if (!m_osResampling.empty())
    3473             :         {
    3474          28 :             psExtraArg->eResampleAlg =
    3475          28 :                 GDALRasterIOGetResampleAlg(m_osResampling);
    3476             :         }
    3477             : 
    3478         951 :         const CPLErr eErr = poSourceBand->RasterIO(
    3479             :             GF_Read, nReqXOff, nReqYOff, nReqXSize, nReqYSize,
    3480         951 :             oWorkingState.m_abyWrkBuffer.data(), nOutXSize, nOutYSize,
    3481             :             eWrkDataType, nWordSize,
    3482         951 :             nWordSize * static_cast<GSpacing>(nOutXSize), psExtraArg);
    3483         951 :         if (!m_osResampling.empty())
    3484          28 :             psExtraArg->eResampleAlg = eResampleAlgBack;
    3485             : 
    3486         951 :         if (eErr != CE_None)
    3487             :         {
    3488           0 :             return eErr;
    3489             :         }
    3490             : 
    3491             :         // Allocate and read mask band if needed
    3492        2807 :         if (!bNoDataSet &&
    3493        1056 :             (m_nProcessingFlags & PROCESSING_FLAG_USE_MASK_BAND) != 0 &&
    3494         105 :             (poSourceBand->GetMaskFlags() != GMF_ALL_VALID ||
    3495          51 :              poSourceBand->GetColorInterpretation() == GCI_AlphaBand ||
    3496          31 :              GetMaskBandMainBand() != nullptr))
    3497             :         {
    3498             :             try
    3499             :             {
    3500         105 :                 oWorkingState.m_abyWrkBufferMask.resize(nPixelCount);
    3501             :             }
    3502           0 :             catch (const std::exception &)
    3503             :             {
    3504           0 :                 CPLError(CE_Failure, CPLE_OutOfMemory,
    3505             :                          "Out of memory when allocating mask buffer");
    3506           0 :                 return CE_Failure;
    3507             :             }
    3508             :             pabyMask = reinterpret_cast<const GByte *>(
    3509         105 :                 oWorkingState.m_abyWrkBufferMask.data());
    3510          51 :             auto poMaskBand =
    3511         105 :                 (poSourceBand->GetColorInterpretation() == GCI_AlphaBand ||
    3512          85 :                  GetMaskBandMainBand() != nullptr)
    3513             :                     ? poSourceBand
    3514          54 :                     : poSourceBand->GetMaskBand();
    3515         105 :             if (poMaskBand->RasterIO(
    3516             :                     GF_Read, nReqXOff, nReqYOff, nReqXSize, nReqYSize,
    3517         105 :                     oWorkingState.m_abyWrkBufferMask.data(), nOutXSize,
    3518             :                     nOutYSize, GDT_Byte, 1, static_cast<GSpacing>(nOutXSize),
    3519         105 :                     psExtraArg) != CE_None)
    3520             :             {
    3521           0 :                 return CE_Failure;
    3522             :             }
    3523             :         }
    3524             : 
    3525         951 :         if (m_nColorTableComponent != 0)
    3526             :         {
    3527         274 :             poColorTable = poSourceBand->GetColorTable();
    3528         274 :             if (poColorTable == nullptr)
    3529             :             {
    3530           0 :                 CPLError(CE_Failure, CPLE_AppDefined,
    3531             :                          "Source band has no color table.");
    3532           0 :                 return CE_Failure;
    3533             :             }
    3534             :         }
    3535             :     }
    3536             : 
    3537             :     /* -------------------------------------------------------------------- */
    3538             :     /*      Selectively copy into output buffer with nodata masking,        */
    3539             :     /*      and/or scaling.                                                 */
    3540             :     /* -------------------------------------------------------------------- */
    3541             : 
    3542        5002 :     const bool bTwoStepDataTypeConversion =
    3543        5002 :         CPL_TO_BOOL(
    3544        9928 :             GDALDataTypeIsConversionLossy(eWrkDataType, eVRTBandDataType)) &&
    3545        4926 :         !CPL_TO_BOOL(GDALDataTypeIsConversionLossy(eVRTBandDataType, eBufType));
    3546             : 
    3547        5002 :     size_t idxBuffer = 0;
    3548       78375 :     for (int iY = 0; iY < nOutYSize; iY++)
    3549             :     {
    3550       73373 :         GByte *pDstLocation = static_cast<GByte *>(pData) +
    3551       73373 :                               static_cast<GPtrDiff_t>(nLineSpace) * iY;
    3552             : 
    3553    12247864 :         for (int iX = 0; iX < nOutXSize;
    3554    12174559 :              iX++, pDstLocation += nPixelSpace, idxBuffer++)
    3555             :         {
    3556             :             WorkingDT afResult[2];
    3557    12174559 :             if (pafData && !bIsComplex)
    3558             :             {
    3559     6539866 :                 WorkingDT fResult = pafData[idxBuffer];
    3560     6539866 :                 if (bNoDataSetIsNan && std::isnan(fResult))
    3561     1188642 :                     continue;
    3562     6541126 :                 if (bNoDataSetAndNotNan &&
    3563        1284 :                     ARE_REAL_EQUAL(fResult, fWorkingDataTypeNoData))
    3564         269 :                     continue;
    3565     6539574 :                 if (pabyMask && pabyMask[idxBuffer] == 0)
    3566     1188350 :                     continue;
    3567             : 
    3568     5351224 :                 if (poColorTable)
    3569             :                 {
    3570             :                     const GDALColorEntry *poEntry =
    3571     1933900 :                         poColorTable->GetColorEntry(static_cast<int>(fResult));
    3572     1933900 :                     if (poEntry)
    3573             :                     {
    3574     1933900 :                         if (m_nColorTableComponent == 1)
    3575      685985 :                             fResult = poEntry->c1;
    3576     1247920 :                         else if (m_nColorTableComponent == 2)
    3577      531408 :                             fResult = poEntry->c2;
    3578      716509 :                         else if (m_nColorTableComponent == 3)
    3579      531408 :                             fResult = poEntry->c3;
    3580      185101 :                         else if (m_nColorTableComponent == 4)
    3581      185101 :                             fResult = poEntry->c4;
    3582             :                     }
    3583             :                     else
    3584             :                     {
    3585           0 :                         CPLErrorOnce(CE_Failure, CPLE_AppDefined,
    3586             :                                      "No entry %d.", static_cast<int>(fResult));
    3587           0 :                         continue;
    3588             :                     }
    3589             :                 }
    3590             : 
    3591     5351224 :                 if ((m_nProcessingFlags & PROCESSING_FLAG_SCALING_LINEAR) != 0)
    3592             :                 {
    3593     1649622 :                     fResult = static_cast<WorkingDT>(fResult * m_dfScaleRatio +
    3594     1649622 :                                                      m_dfScaleOff);
    3595             :                 }
    3596     3701602 :                 else if ((m_nProcessingFlags &
    3597             :                           PROCESSING_FLAG_SCALING_EXPONENTIAL) != 0)
    3598             :                 {
    3599        3579 :                     if (!m_bSrcMinMaxDefined)
    3600             :                     {
    3601           1 :                         int bSuccessMin = FALSE;
    3602           1 :                         int bSuccessMax = FALSE;
    3603           2 :                         double adfMinMax[2] = {
    3604           1 :                             poSourceBand->GetMinimum(&bSuccessMin),
    3605           1 :                             poSourceBand->GetMaximum(&bSuccessMax)};
    3606           2 :                         if ((bSuccessMin && bSuccessMax) ||
    3607           1 :                             poSourceBand->ComputeRasterMinMax(
    3608             :                                 TRUE, adfMinMax) == CE_None)
    3609             :                         {
    3610           1 :                             m_dfSrcMin = adfMinMax[0];
    3611           1 :                             m_dfSrcMax = adfMinMax[1];
    3612           1 :                             m_bSrcMinMaxDefined = true;
    3613             :                         }
    3614             :                         else
    3615             :                         {
    3616           0 :                             CPLError(CE_Failure, CPLE_AppDefined,
    3617             :                                      "Cannot determine source min/max value");
    3618           0 :                             return CE_Failure;
    3619             :                         }
    3620             :                     }
    3621             : 
    3622        7158 :                     double dfPowVal = (m_dfSrcMin == m_dfSrcMax)
    3623        3579 :                                           ? 0
    3624        3579 :                                           : (fResult - m_dfSrcMin) /
    3625        3579 :                                                 (m_dfSrcMax - m_dfSrcMin);
    3626        3579 :                     if (m_bClip)
    3627             :                     {
    3628        3574 :                         if (dfPowVal < 0.0)
    3629           1 :                             dfPowVal = 0.0;
    3630        3573 :                         else if (dfPowVal > 1.0)
    3631         700 :                             dfPowVal = 1.0;
    3632             :                     }
    3633        3579 :                     fResult =
    3634        3579 :                         static_cast<WorkingDT>((m_dfDstMax - m_dfDstMin) *
    3635        3579 :                                                    pow(dfPowVal, m_dfExponent) +
    3636        3579 :                                                m_dfDstMin);
    3637             :                 }
    3638             : 
    3639     5351224 :                 if (!m_adfLUTInputs.empty())
    3640      817592 :                     fResult = static_cast<WorkingDT>(LookupValue(fResult));
    3641             : 
    3642     5351224 :                 if (m_nMaxValue != 0 && fResult > m_nMaxValue)
    3643         800 :                     fResult = static_cast<WorkingDT>(m_nMaxValue);
    3644             : 
    3645     5351224 :                 afResult[0] = fResult;
    3646     5351224 :                 afResult[1] = 0;
    3647             :             }
    3648     5634663 :             else if (pafData && bIsComplex)
    3649             :             {
    3650        1018 :                 afResult[0] = pafData[2 * idxBuffer];
    3651        1018 :                 afResult[1] = pafData[2 * idxBuffer + 1];
    3652             : 
    3653             :                 // Do not use color table.
    3654        1018 :                 if ((m_nProcessingFlags & PROCESSING_FLAG_SCALING_LINEAR) != 0)
    3655             :                 {
    3656           4 :                     afResult[0] = static_cast<WorkingDT>(
    3657           4 :                         afResult[0] * m_dfScaleRatio + m_dfScaleOff);
    3658           4 :                     afResult[1] = static_cast<WorkingDT>(
    3659           4 :                         afResult[1] * m_dfScaleRatio + m_dfScaleOff);
    3660             :                 }
    3661             : 
    3662             :                 /* Do not use LUT */
    3663             :             }
    3664             :             else
    3665             :             {
    3666     5633642 :                 afResult[0] = static_cast<WorkingDT>(m_dfScaleOff);
    3667     5633642 :                 afResult[1] = 0;
    3668             : 
    3669     5633642 :                 if (!m_adfLUTInputs.empty())
    3670           0 :                     afResult[0] =
    3671           0 :                         static_cast<WorkingDT>(LookupValue(afResult[0]));
    3672             : 
    3673     5633642 :                 if (m_nMaxValue != 0 && afResult[0] > m_nMaxValue)
    3674           0 :                     afResult[0] = static_cast<WorkingDT>(m_nMaxValue);
    3675             :             }
    3676             : 
    3677    10985857 :             if (eBufType == GDT_Byte && eVRTBandDataType == GDT_Byte)
    3678             :             {
    3679     4308910 :                 *pDstLocation = static_cast<GByte>(std::min(
    3680     8617820 :                     255.0f,
    3681     4308910 :                     std::max(0.0f, static_cast<float>(afResult[0]) + 0.5f)));
    3682             :             }
    3683     6676977 :             else if (!bTwoStepDataTypeConversion)
    3684             :             {
    3685       14036 :                 CopyWord<WorkingDT>(afResult, eWrkDataType, pDstLocation,
    3686             :                                     eBufType);
    3687             :             }
    3688     6662938 :             else if (eVRTBandDataType == GDT_Float32 && eBufType == GDT_Float64)
    3689             :             {
    3690             :                 // Particular case of the below 2-step conversion.
    3691             :                 // Helps a bit for some geolocation based warping with Sentinel3
    3692             :                 // data where the longitude/latitude arrays are Int32 bands,
    3693             :                 // rescaled in VRT as Float32 and requested as Float64
    3694             :                 float fVal;
    3695          20 :                 GDALCopyWord(afResult[0], fVal);
    3696          20 :                 *reinterpret_cast<double *>(pDstLocation) = fVal;
    3697             :             }
    3698             :             else
    3699             :             {
    3700             :                 GByte abyTemp[2 * sizeof(double)];
    3701             :                 // Convert first to the VRTRasterBand data type
    3702             :                 // to get its clamping, before outputting to buffer data type
    3703     6662918 :                 CopyWord<WorkingDT>(afResult, eWrkDataType, abyTemp,
    3704             :                                     eVRTBandDataType);
    3705     6662918 :                 GDALCopyWords(abyTemp, eVRTBandDataType, 0, pDstLocation,
    3706             :                               eBufType, 0, 1);
    3707             :             }
    3708             :         }
    3709             :     }
    3710             : 
    3711        5002 :     return CE_None;
    3712             : }
    3713             : 
    3714             : // Explicitly instantiate template method, as it is used in another file.
    3715             : template CPLErr VRTComplexSource::RasterIOInternal<float>(
    3716             :     GDALRasterBand *poSourceBand, GDALDataType eVRTBandDataType, int nReqXOff,
    3717             :     int nReqYOff, int nReqXSize, int nReqYSize, void *pData, int nOutXSize,
    3718             :     int nOutYSize, GDALDataType eBufType, GSpacing nPixelSpace,
    3719             :     GSpacing nLineSpace, GDALRasterIOExtraArg *psExtraArg,
    3720             :     GDALDataType eWrkDataType, WorkingState &oWorkingState);
    3721             : 
    3722             : /************************************************************************/
    3723             : /*                        AreValuesUnchanged()                          */
    3724             : /************************************************************************/
    3725             : 
    3726           9 : bool VRTComplexSource::AreValuesUnchanged() const
    3727             : {
    3728          10 :     return m_dfScaleOff == 0.0 && m_dfScaleRatio == 1.0 &&
    3729          24 :            m_adfLUTInputs.empty() && m_nColorTableComponent == 0 &&
    3730          14 :            (m_nProcessingFlags & PROCESSING_FLAG_SCALING_EXPONENTIAL) == 0;
    3731             : }
    3732             : 
    3733             : /************************************************************************/
    3734             : /*                             GetMinimum()                             */
    3735             : /************************************************************************/
    3736             : 
    3737           2 : double VRTComplexSource::GetMinimum(int nXSize, int nYSize, int *pbSuccess)
    3738             : {
    3739           2 :     if (AreValuesUnchanged())
    3740             :     {
    3741           1 :         return VRTSimpleSource::GetMinimum(nXSize, nYSize, pbSuccess);
    3742             :     }
    3743             : 
    3744           1 :     *pbSuccess = FALSE;
    3745           1 :     return 0;
    3746             : }
    3747             : 
    3748             : /************************************************************************/
    3749             : /*                             GetMaximum()                             */
    3750             : /************************************************************************/
    3751             : 
    3752           2 : double VRTComplexSource::GetMaximum(int nXSize, int nYSize, int *pbSuccess)
    3753             : {
    3754           2 :     if (AreValuesUnchanged())
    3755             :     {
    3756           1 :         return VRTSimpleSource::GetMaximum(nXSize, nYSize, pbSuccess);
    3757             :     }
    3758             : 
    3759           1 :     *pbSuccess = FALSE;
    3760           1 :     return 0;
    3761             : }
    3762             : 
    3763             : /************************************************************************/
    3764             : /*                            GetHistogram()                            */
    3765             : /************************************************************************/
    3766             : 
    3767           0 : CPLErr VRTComplexSource::GetHistogram(int nXSize, int nYSize, double dfMin,
    3768             :                                       double dfMax, int nBuckets,
    3769             :                                       GUIntBig *panHistogram,
    3770             :                                       int bIncludeOutOfRange, int bApproxOK,
    3771             :                                       GDALProgressFunc pfnProgress,
    3772             :                                       void *pProgressData)
    3773             : {
    3774           0 :     if (AreValuesUnchanged())
    3775             :     {
    3776           0 :         return VRTSimpleSource::GetHistogram(
    3777             :             nXSize, nYSize, dfMin, dfMax, nBuckets, panHistogram,
    3778           0 :             bIncludeOutOfRange, bApproxOK, pfnProgress, pProgressData);
    3779             :     }
    3780             : 
    3781           0 :     return CE_Failure;
    3782             : }
    3783             : 
    3784             : /************************************************************************/
    3785             : /* ==================================================================== */
    3786             : /*                          VRTFuncSource                               */
    3787             : /* ==================================================================== */
    3788             : /************************************************************************/
    3789             : 
    3790             : /************************************************************************/
    3791             : /*                           VRTFuncSource()                            */
    3792             : /************************************************************************/
    3793             : 
    3794          12 : VRTFuncSource::VRTFuncSource()
    3795             :     : pfnReadFunc(nullptr), pCBData(nullptr), eType(GDT_Byte),
    3796          12 :       fNoDataValue(static_cast<float>(VRT_NODATA_UNSET))
    3797             : {
    3798          12 : }
    3799             : 
    3800             : /************************************************************************/
    3801             : /*                           ~VRTFuncSource()                           */
    3802             : /************************************************************************/
    3803             : 
    3804          24 : VRTFuncSource::~VRTFuncSource()
    3805             : {
    3806          24 : }
    3807             : 
    3808             : /************************************************************************/
    3809             : /*                            GetType()                                 */
    3810             : /************************************************************************/
    3811             : 
    3812           0 : const char *VRTFuncSource::GetType() const
    3813             : {
    3814             :     static const char *TYPE = "FuncSource";
    3815           0 :     return TYPE;
    3816             : }
    3817             : 
    3818             : /************************************************************************/
    3819             : /*                           SerializeToXML()                           */
    3820             : /************************************************************************/
    3821             : 
    3822           0 : CPLXMLNode *VRTFuncSource::SerializeToXML(CPL_UNUSED const char *pszVRTPath)
    3823             : {
    3824           0 :     return nullptr;
    3825             : }
    3826             : 
    3827             : /************************************************************************/
    3828             : /*                              RasterIO()                              */
    3829             : /************************************************************************/
    3830             : 
    3831          10 : CPLErr VRTFuncSource::RasterIO(GDALDataType /*eVRTBandDataType*/, int nXOff,
    3832             :                                int nYOff, int nXSize, int nYSize, void *pData,
    3833             :                                int nBufXSize, int nBufYSize,
    3834             :                                GDALDataType eBufType, GSpacing nPixelSpace,
    3835             :                                GSpacing nLineSpace,
    3836             :                                GDALRasterIOExtraArg * /* psExtraArg */,
    3837             :                                WorkingState & /* oWorkingState */)
    3838             : {
    3839          10 :     if (nPixelSpace == GDALGetDataTypeSizeBytes(eBufType) &&
    3840          10 :         nLineSpace == nPixelSpace * nXSize && nBufXSize == nXSize &&
    3841          20 :         nBufYSize == nYSize && eBufType == eType)
    3842             :     {
    3843          10 :         return pfnReadFunc(pCBData, nXOff, nYOff, nXSize, nYSize, pData);
    3844             :     }
    3845             :     else
    3846             :     {
    3847           0 :         CPLError(CE_Failure, CPLE_AppDefined,
    3848             :                  "VRTFuncSource::RasterIO() - Irregular request.");
    3849           0 :         CPLDebug("VRT", "Irregular request: %d,%d  %d,%d, %d,%d %d,%d %d,%d",
    3850             :                  static_cast<int>(nPixelSpace),
    3851             :                  GDALGetDataTypeSizeBytes(eBufType),
    3852             :                  static_cast<int>(nLineSpace),
    3853             :                  static_cast<int>(nPixelSpace) * nXSize, nBufXSize, nXSize,
    3854             :                  nBufYSize, nYSize, static_cast<int>(eBufType),
    3855           0 :                  static_cast<int>(eType));
    3856             : 
    3857           0 :         return CE_Failure;
    3858             :     }
    3859             : }
    3860             : 
    3861             : /************************************************************************/
    3862             : /*                             GetMinimum()                             */
    3863             : /************************************************************************/
    3864             : 
    3865           0 : double VRTFuncSource::GetMinimum(int /* nXSize */, int /* nYSize */,
    3866             :                                  int *pbSuccess)
    3867             : {
    3868           0 :     *pbSuccess = FALSE;
    3869           0 :     return 0;
    3870             : }
    3871             : 
    3872             : /************************************************************************/
    3873             : /*                             GetMaximum()                             */
    3874             : /************************************************************************/
    3875             : 
    3876           0 : double VRTFuncSource::GetMaximum(int /* nXSize */, int /* nYSize */,
    3877             :                                  int *pbSuccess)
    3878             : {
    3879           0 :     *pbSuccess = FALSE;
    3880           0 :     return 0;
    3881             : }
    3882             : 
    3883             : /************************************************************************/
    3884             : /*                            GetHistogram()                            */
    3885             : /************************************************************************/
    3886             : 
    3887           0 : CPLErr VRTFuncSource::GetHistogram(
    3888             :     int /* nXSize */, int /* nYSize */, double /* dfMin */, double /* dfMax */,
    3889             :     int /* nBuckets */, GUIntBig * /* panHistogram */,
    3890             :     int /* bIncludeOutOfRange */, int /* bApproxOK */,
    3891             :     GDALProgressFunc /* pfnProgress */, void * /* pProgressData */)
    3892             : {
    3893           0 :     return CE_Failure;
    3894             : }
    3895             : 
    3896             : /************************************************************************/
    3897             : /*                        VRTParseCoreSources()                         */
    3898             : /************************************************************************/
    3899             : 
    3900      104105 : VRTSource *VRTParseCoreSources(const CPLXMLNode *psChild,
    3901             :                                const char *pszVRTPath,
    3902             :                                VRTMapSharedResources &oMapSharedSources)
    3903             : 
    3904             : {
    3905      104105 :     VRTSource *poSource = nullptr;
    3906             : 
    3907      208203 :     if (EQUAL(psChild->pszValue, VRTAveragedSource::GetTypeStatic()) ||
    3908      104098 :         (EQUAL(psChild->pszValue, VRTSimpleSource::GetTypeStatic()) &&
    3909      103845 :          STARTS_WITH_CI(CPLGetXMLValue(psChild, "Resampling", "Nearest"),
    3910             :                         "Aver")))
    3911             :     {
    3912          16 :         poSource = new VRTAveragedSource();
    3913             :     }
    3914      104089 :     else if (EQUAL(psChild->pszValue, VRTSimpleSource::GetTypeStatic()))
    3915             :     {
    3916      103836 :         poSource = new VRTSimpleSource();
    3917             :     }
    3918         253 :     else if (EQUAL(psChild->pszValue, VRTComplexSource::GetTypeStatic()))
    3919             :     {
    3920         245 :         poSource = new VRTComplexSource();
    3921             :     }
    3922           8 :     else if (EQUAL(psChild->pszValue, VRTNoDataFromMaskSource::GetTypeStatic()))
    3923             :     {
    3924           8 :         poSource = new VRTNoDataFromMaskSource();
    3925             :     }
    3926             :     else
    3927             :     {
    3928           0 :         CPLError(CE_Failure, CPLE_AppDefined,
    3929             :                  "VRTParseCoreSources() - Unknown source : %s",
    3930           0 :                  psChild->pszValue);
    3931           0 :         return nullptr;
    3932             :     }
    3933             : 
    3934      104105 :     if (poSource->XMLInit(psChild, pszVRTPath, oMapSharedSources) == CE_None)
    3935      104102 :         return poSource;
    3936             : 
    3937           3 :     delete poSource;
    3938           3 :     return nullptr;
    3939             : }
    3940             : 
    3941             : /*! @endcond */

Generated by: LCOV version 1.14