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

Generated by: LCOV version 1.14