LCOV - code coverage report
Current view: top level - frmts/vrt - vrtsources.cpp (source / functions) Hit Total Coverage
Test: gdal_filtered.info Lines: 1552 1798 86.3 %
Date: 2025-10-25 23:36:32 Functions: 81 98 82.7 %

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

Generated by: LCOV version 1.14