LCOV - code coverage report
Current view: top level - frmts/vrt - vrtsources.cpp (source / functions) Hit Total Coverage
Test: gdal_filtered.info Lines: 1694 2010 84.3 %
Date: 2026-06-14 03:17:32 Functions: 94 117 80.3 %

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

Generated by: LCOV version 1.14