LCOV - code coverage report
Current view: top level - frmts/vrt - vrtrasterband.cpp (source / functions) Hit Total Coverage
Test: gdal_filtered.info Lines: 512 599 85.5 %
Date: 2026-03-28 17:24:44 Functions: 47 48 97.9 %

          Line data    Source code
       1             : /******************************************************************************
       2             :  *
       3             :  * Project:  Virtual GDAL Datasets
       4             :  * Purpose:  Implementation of VRTRasterBand
       5             :  * Author:   Frank Warmerdam <warmerdam@pobox.com>
       6             :  *
       7             :  ******************************************************************************
       8             :  * Copyright (c) 2001, Frank Warmerdam <warmerdam@pobox.com>
       9             :  * Copyright (c) 2008-2013, Even Rouault <even dot rouault at spatialys.com>
      10             :  *
      11             :  * SPDX-License-Identifier: MIT
      12             :  ****************************************************************************/
      13             : 
      14             : #include "cpl_port.h"
      15             : #include "vrtdataset.h"
      16             : 
      17             : #include <cmath>
      18             : #include <cstdlib>
      19             : #include <cstring>
      20             : #include <algorithm>
      21             : #include <limits>
      22             : #include <memory>
      23             : #include <vector>
      24             : 
      25             : #include "gdal.h"
      26             : #include "gdalantirecursion.h"
      27             : #include "gdal_pam.h"
      28             : #include "gdal_priv.h"
      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 "vrt_priv.h"
      37             : 
      38             : /*! @cond Doxygen_Suppress */
      39             : 
      40             : /************************************************************************/
      41             : /* ==================================================================== */
      42             : /*                          VRTRasterBand                               */
      43             : /* ==================================================================== */
      44             : /************************************************************************/
      45             : 
      46             : /************************************************************************/
      47             : /*                           VRTRasterBand()                            */
      48             : /************************************************************************/
      49             : 
      50      143120 : VRTRasterBand::VRTRasterBand()
      51             : {
      52      143120 :     VRTRasterBand::Initialize(0, 0);
      53      143120 : }
      54             : 
      55             : /************************************************************************/
      56             : /*                             Initialize()                             */
      57             : /************************************************************************/
      58             : 
      59      286240 : void VRTRasterBand::Initialize(int nXSize, int nYSize)
      60             : 
      61             : {
      62      286240 :     poDS = nullptr;
      63      286240 :     nBand = 0;
      64      286240 :     eAccess = GA_ReadOnly;
      65      286240 :     eDataType = GDT_UInt8;
      66             : 
      67      286240 :     nRasterXSize = nXSize;
      68      286240 :     nRasterYSize = nYSize;
      69             : 
      70      286240 :     nBlockXSize = std::min(128, nXSize);
      71      286240 :     nBlockYSize = std::min(128, nYSize);
      72      286240 : }
      73             : 
      74             : /************************************************************************/
      75             : /*                           ~VRTRasterBand()                           */
      76             : /************************************************************************/
      77             : 
      78             : VRTRasterBand::~VRTRasterBand() = default;
      79             : 
      80             : /************************************************************************/
      81             : /*                         CopyCommonInfoFrom()                         */
      82             : /*                                                                      */
      83             : /*      Copy common metadata, pixel descriptions, and color             */
      84             : /*      interpretation from the provided source band.                   */
      85             : /************************************************************************/
      86             : 
      87       66117 : CPLErr VRTRasterBand::CopyCommonInfoFrom(const GDALRasterBand *poSrcBand)
      88             : 
      89             : {
      90       66117 :     auto poSrcBandNonConst = const_cast<GDALRasterBand *>(poSrcBand);
      91       66117 :     SetMetadata(poSrcBandNonConst->GetMetadata());
      92             :     const char *pszNBits =
      93       66117 :         poSrcBandNonConst->GetMetadataItem("NBITS", "IMAGE_STRUCTURE");
      94       66117 :     SetMetadataItem("NBITS", pszNBits, "IMAGE_STRUCTURE");
      95       66117 :     if (poSrcBand->GetRasterDataType() == GDT_UInt8)
      96             :     {
      97       66066 :         poSrcBandNonConst->EnablePixelTypeSignedByteWarning(false);
      98             :         const char *pszPixelType =
      99       66066 :             poSrcBandNonConst->GetMetadataItem("PIXELTYPE", "IMAGE_STRUCTURE");
     100       66066 :         poSrcBandNonConst->EnablePixelTypeSignedByteWarning(true);
     101       66066 :         SetMetadataItem("PIXELTYPE", pszPixelType, "IMAGE_STRUCTURE");
     102             :     }
     103       66117 :     SetColorTable(poSrcBandNonConst->GetColorTable());
     104       66117 :     SetColorInterpretation(poSrcBandNonConst->GetColorInterpretation());
     105       66117 :     if (strlen(poSrcBand->GetDescription()) > 0)
     106           1 :         SetDescription(poSrcBand->GetDescription());
     107             : 
     108       66117 :     GDALCopyNoDataValue(this, poSrcBandNonConst);
     109       66117 :     SetOffset(poSrcBandNonConst->GetOffset());
     110       66117 :     SetScale(poSrcBandNonConst->GetScale());
     111       66117 :     SetCategoryNames(poSrcBandNonConst->GetCategoryNames());
     112       66117 :     if (!EQUAL(poSrcBandNonConst->GetUnitType(), ""))
     113           1 :         SetUnitType(poSrcBandNonConst->GetUnitType());
     114             : 
     115       66117 :     GDALRasterAttributeTable *poRAT = poSrcBandNonConst->GetDefaultRAT();
     116       66118 :     if (poRAT != nullptr &&
     117           1 :         static_cast<GIntBig>(poRAT->GetColumnCount()) * poRAT->GetRowCount() <
     118             :             1024 * 1024)
     119             :     {
     120           1 :         SetDefaultRAT(poRAT);
     121             :     }
     122             : 
     123       66117 :     return CE_None;
     124             : }
     125             : 
     126             : /************************************************************************/
     127             : /*                            SetMetadata()                             */
     128             : /************************************************************************/
     129             : 
     130       70930 : CPLErr VRTRasterBand::SetMetadata(CSLConstList papszMetadata,
     131             :                                   const char *pszDomain)
     132             : 
     133             : {
     134       70930 :     cpl::down_cast<VRTDataset *>(poDS)->SetNeedsFlush();
     135             : 
     136       70930 :     return GDALRasterBand::SetMetadata(papszMetadata, pszDomain);
     137             : }
     138             : 
     139             : /************************************************************************/
     140             : /*                          SetMetadataItem()                           */
     141             : /************************************************************************/
     142             : 
     143      133896 : CPLErr VRTRasterBand::SetMetadataItem(const char *pszName, const char *pszValue,
     144             :                                       const char *pszDomain)
     145             : 
     146             : {
     147      133896 :     cpl::down_cast<VRTDataset *>(poDS)->SetNeedsFlush();
     148             : 
     149      133896 :     if (EQUAL(pszName, "HideNoDataValue"))
     150             :     {
     151           2 :         m_bHideNoDataValue = CPLTestBool(pszValue);
     152           2 :         return CE_None;
     153             :     }
     154             : 
     155      133894 :     return GDALRasterBand::SetMetadataItem(pszName, pszValue, pszDomain);
     156             : }
     157             : 
     158             : /************************************************************************/
     159             : /*                            GetUnitType()                             */
     160             : /************************************************************************/
     161             : 
     162        7029 : const char *VRTRasterBand::GetUnitType()
     163             : 
     164             : {
     165        7029 :     return m_osUnitType.c_str();
     166             : }
     167             : 
     168             : /************************************************************************/
     169             : /*                            SetUnitType()                             */
     170             : /************************************************************************/
     171             : 
     172        2975 : CPLErr VRTRasterBand::SetUnitType(const char *pszNewValue)
     173             : 
     174             : {
     175        2975 :     cpl::down_cast<VRTDataset *>(poDS)->SetNeedsFlush();
     176             : 
     177        2975 :     m_osUnitType = pszNewValue ? pszNewValue : "";
     178             : 
     179        2975 :     return CE_None;
     180             : }
     181             : 
     182             : /************************************************************************/
     183             : /*                             GetOffset()                              */
     184             : /************************************************************************/
     185             : 
     186        9154 : double VRTRasterBand::GetOffset(int *pbSuccess)
     187             : 
     188             : {
     189        9154 :     if (pbSuccess != nullptr)
     190        5592 :         *pbSuccess = TRUE;
     191             : 
     192        9154 :     return m_dfOffset;
     193             : }
     194             : 
     195             : /************************************************************************/
     196             : /*                             SetOffset()                              */
     197             : /************************************************************************/
     198             : 
     199       73856 : CPLErr VRTRasterBand::SetOffset(double dfNewOffset)
     200             : 
     201             : {
     202       73856 :     cpl::down_cast<VRTDataset *>(poDS)->SetNeedsFlush();
     203             : 
     204       73856 :     m_dfOffset = dfNewOffset;
     205       73856 :     return CE_None;
     206             : }
     207             : 
     208             : /************************************************************************/
     209             : /*                              GetScale()                              */
     210             : /************************************************************************/
     211             : 
     212        9155 : double VRTRasterBand::GetScale(int *pbSuccess)
     213             : 
     214             : {
     215        9155 :     if (pbSuccess != nullptr)
     216        5593 :         *pbSuccess = TRUE;
     217             : 
     218        9155 :     return m_dfScale;
     219             : }
     220             : 
     221             : /************************************************************************/
     222             : /*                              SetScale()                              */
     223             : /************************************************************************/
     224             : 
     225       73852 : CPLErr VRTRasterBand::SetScale(double dfNewScale)
     226             : 
     227             : {
     228       73852 :     cpl::down_cast<VRTDataset *>(poDS)->SetNeedsFlush();
     229             : 
     230       73852 :     m_dfScale = dfNewScale;
     231       73852 :     return CE_None;
     232             : }
     233             : 
     234             : /************************************************************************/
     235             : /*                          GetCategoryNames()                          */
     236             : /************************************************************************/
     237             : 
     238        7903 : char **VRTRasterBand::GetCategoryNames()
     239             : 
     240             : {
     241        7903 :     return m_aosCategoryNames.List();
     242             : }
     243             : 
     244             : /************************************************************************/
     245             : /*                          SetCategoryNames()                          */
     246             : /************************************************************************/
     247             : 
     248       70922 : CPLErr VRTRasterBand::SetCategoryNames(char **papszNewNames)
     249             : 
     250             : {
     251       70922 :     cpl::down_cast<VRTDataset *>(poDS)->SetNeedsFlush();
     252             : 
     253       70922 :     m_aosCategoryNames = CSLDuplicate(papszNewNames);
     254             : 
     255       70922 :     return CE_None;
     256             : }
     257             : 
     258             : /************************************************************************/
     259             : /*                       VRTParseCategoryNames()                        */
     260             : /************************************************************************/
     261             : 
     262           3 : CPLStringList VRTParseCategoryNames(const CPLXMLNode *psCategoryNames)
     263             : {
     264           3 :     CPLStringList oCategoryNames;
     265             : 
     266           3 :     for (const CPLXMLNode *psEntry = psCategoryNames->psChild;
     267           7 :          psEntry != nullptr; psEntry = psEntry->psNext)
     268             :     {
     269           4 :         if (psEntry->eType != CXT_Element ||
     270           4 :             !EQUAL(psEntry->pszValue, "Category") ||
     271           4 :             (psEntry->psChild != nullptr &&
     272           4 :              psEntry->psChild->eType != CXT_Text))
     273           0 :             continue;
     274             : 
     275           8 :         oCategoryNames.AddString((psEntry->psChild) ? psEntry->psChild->pszValue
     276           4 :                                                     : "");
     277             :     }
     278             : 
     279           3 :     return oCategoryNames;
     280             : }
     281             : 
     282             : /************************************************************************/
     283             : /*                         VRTParseColorTable()                         */
     284             : /************************************************************************/
     285             : 
     286             : std::unique_ptr<GDALColorTable>
     287          11 : VRTParseColorTable(const CPLXMLNode *psColorTable)
     288             : {
     289          11 :     auto poColorTable = std::make_unique<GDALColorTable>();
     290          11 :     int iEntry = 0;
     291             : 
     292        1299 :     for (const CPLXMLNode *psEntry = psColorTable->psChild; psEntry != nullptr;
     293        1288 :          psEntry = psEntry->psNext)
     294             :     {
     295        1288 :         if (psEntry->eType != CXT_Element || !EQUAL(psEntry->pszValue, "Entry"))
     296             :         {
     297           0 :             continue;
     298             :         }
     299             : 
     300             :         const GDALColorEntry sCEntry = {
     301        1288 :             static_cast<short>(atoi(CPLGetXMLValue(psEntry, "c1", "0"))),
     302        2576 :             static_cast<short>(atoi(CPLGetXMLValue(psEntry, "c2", "0"))),
     303        2576 :             static_cast<short>(atoi(CPLGetXMLValue(psEntry, "c3", "0"))),
     304        1288 :             static_cast<short>(atoi(CPLGetXMLValue(psEntry, "c4", "255")))};
     305             : 
     306        1288 :         poColorTable->SetColorEntry(iEntry++, &sCEntry);
     307             :     }
     308             : 
     309          11 :     return poColorTable;
     310             : }
     311             : 
     312             : /************************************************************************/
     313             : /*                              XMLInit()                               */
     314             : /************************************************************************/
     315             : 
     316        2938 : CPLErr VRTRasterBand::XMLInit(const CPLXMLNode *psTree, const char *pszVRTPath,
     317             :                               VRTMapSharedResources &oMapSharedSources)
     318             : 
     319             : {
     320             :     /* -------------------------------------------------------------------- */
     321             :     /*      Validate a bit.                                                 */
     322             :     /* -------------------------------------------------------------------- */
     323        2938 :     if (psTree == nullptr || psTree->eType != CXT_Element ||
     324        2938 :         !EQUAL(psTree->pszValue, "VRTRasterBand"))
     325             :     {
     326           0 :         CPLError(CE_Failure, CPLE_AppDefined,
     327             :                  "Invalid node passed to VRTRasterBand::XMLInit().");
     328           0 :         return CE_Failure;
     329             :     }
     330             : 
     331             :     /* -------------------------------------------------------------------- */
     332             :     /*      Set the band if provided as an attribute.                       */
     333             :     /* -------------------------------------------------------------------- */
     334        2938 :     const char *pszBand = CPLGetXMLValue(psTree, "band", nullptr);
     335        2938 :     if (pszBand != nullptr)
     336             :     {
     337        2740 :         int nNewBand = atoi(pszBand);
     338        2740 :         if (nNewBand != nBand)
     339             :         {
     340           1 :             CPLError(CE_Warning, CPLE_AppDefined,
     341             :                      "Invalid band number. Got %s, expected %d. Ignoring "
     342             :                      "provided one, and using %d instead",
     343             :                      pszBand, nBand, nBand);
     344             :         }
     345             :     }
     346             : 
     347             :     /* -------------------------------------------------------------------- */
     348             :     /*      Set the band if provided as an attribute.                       */
     349             :     /* -------------------------------------------------------------------- */
     350        2938 :     const char *pszDataType = CPLGetXMLValue(psTree, "dataType", nullptr);
     351        2938 :     if (pszDataType != nullptr)
     352             :     {
     353        2916 :         eDataType = GDALGetDataTypeByName(pszDataType);
     354        2916 :         if (eDataType == GDT_Unknown)
     355             :         {
     356           0 :             CPLError(CE_Failure, CPLE_AppDefined, "Invalid dataType = %s",
     357             :                      pszDataType);
     358           0 :             return CE_Failure;
     359             :         }
     360             :     }
     361             : 
     362        2938 :     const char *pszBlockXSize = CPLGetXMLValue(psTree, "blockXSize", nullptr);
     363        2938 :     if (pszBlockXSize)
     364             :     {
     365         158 :         int nBlockXSizeIn = atoi(pszBlockXSize);
     366         158 :         if (nBlockXSizeIn >= 32 && nBlockXSizeIn <= 16384)
     367         155 :             nBlockXSize = nBlockXSizeIn;
     368             :     }
     369             : 
     370        2938 :     const char *pszBlockYSize = CPLGetXMLValue(psTree, "blockYSize", nullptr);
     371        2938 :     if (pszBlockYSize)
     372             :     {
     373         196 :         int nBlockYSizeIn = atoi(pszBlockYSize);
     374         196 :         if (nBlockYSizeIn >= 32 && nBlockYSizeIn <= 16384)
     375          64 :             nBlockYSize = nBlockYSizeIn;
     376             :     }
     377             : 
     378             :     /* -------------------------------------------------------------------- */
     379             :     /*      Apply any band level metadata.                                  */
     380             :     /* -------------------------------------------------------------------- */
     381        2938 :     oMDMD.XMLInit(psTree, TRUE);
     382             : 
     383             :     /* -------------------------------------------------------------------- */
     384             :     /*      Collect various other items of metadata.                        */
     385             :     /* -------------------------------------------------------------------- */
     386        2938 :     SetDescription(CPLGetXMLValue(psTree, "Description", ""));
     387             : 
     388        2938 :     const char *pszNoDataValue = CPLGetXMLValue(psTree, "NoDataValue", nullptr);
     389        2938 :     if (pszNoDataValue != nullptr)
     390             :     {
     391         294 :         if (eDataType == GDT_Int64)
     392             :         {
     393           2 :             SetNoDataValueAsInt64(static_cast<int64_t>(
     394           2 :                 std::strtoll(pszNoDataValue, nullptr, 10)));
     395             :         }
     396         292 :         else if (eDataType == GDT_UInt64)
     397             :         {
     398           2 :             SetNoDataValueAsUInt64(static_cast<uint64_t>(
     399           2 :                 std::strtoull(pszNoDataValue, nullptr, 10)));
     400             :         }
     401             :         else
     402             :         {
     403         290 :             SetNoDataValue(CPLAtofM(pszNoDataValue));
     404             :         }
     405             :     }
     406             : 
     407        2938 :     if (CPLGetXMLValue(psTree, "HideNoDataValue", nullptr) != nullptr)
     408           3 :         m_bHideNoDataValue =
     409           3 :             CPLTestBool(CPLGetXMLValue(psTree, "HideNoDataValue", "0"));
     410             : 
     411        2938 :     SetUnitType(CPLGetXMLValue(psTree, "UnitType", nullptr));
     412             : 
     413        2938 :     SetOffset(CPLAtof(CPLGetXMLValue(psTree, "Offset", "0.0")));
     414        2938 :     SetScale(CPLAtof(CPLGetXMLValue(psTree, "Scale", "1.0")));
     415             : 
     416        2938 :     if (CPLGetXMLValue(psTree, "ColorInterp", nullptr) != nullptr)
     417             :     {
     418         983 :         const char *pszInterp = CPLGetXMLValue(psTree, "ColorInterp", nullptr);
     419         983 :         SetColorInterpretation(GDALGetColorInterpretationByName(pszInterp));
     420             :     }
     421             : 
     422             :     /* -------------------------------------------------------------------- */
     423             :     /*      Category names.                                                 */
     424             :     /* -------------------------------------------------------------------- */
     425        2938 :     if (const CPLXMLNode *psCategoryNames =
     426        2938 :             CPLGetXMLNode(psTree, "CategoryNames"))
     427             :     {
     428           1 :         m_aosCategoryNames = VRTParseCategoryNames(psCategoryNames);
     429             :     }
     430             : 
     431             :     /* -------------------------------------------------------------------- */
     432             :     /*      Collect a color table.                                          */
     433             :     /* -------------------------------------------------------------------- */
     434        2938 :     if (const CPLXMLNode *psColorTable = CPLGetXMLNode(psTree, "ColorTable"))
     435             :     {
     436          18 :         auto poColorTable = VRTParseColorTable(psColorTable);
     437           9 :         if (poColorTable)
     438           9 :             SetColorTable(poColorTable.get());
     439             :     }
     440             : 
     441             :     /* -------------------------------------------------------------------- */
     442             :     /*      Raster Attribute Table                                          */
     443             :     /* -------------------------------------------------------------------- */
     444        2938 :     if (const CPLXMLNode *psRAT =
     445        2938 :             CPLGetXMLNode(psTree, "GDALRasterAttributeTable"))
     446             :     {
     447           3 :         m_poRAT = std::make_unique<GDALDefaultRasterAttributeTable>();
     448           3 :         m_poRAT->XMLInit(psRAT, "");
     449             :     }
     450             : 
     451             :     /* -------------------------------------------------------------------- */
     452             :     /*      Histograms                                                      */
     453             :     /* -------------------------------------------------------------------- */
     454        2938 :     const CPLXMLNode *psHist = CPLGetXMLNode(psTree, "Histograms");
     455        2938 :     if (psHist != nullptr)
     456             :     {
     457           2 :         CPLXMLNode sHistTemp = *psHist;
     458           2 :         sHistTemp.psNext = nullptr;
     459           2 :         m_psSavedHistograms.reset(CPLCloneXMLTree(&sHistTemp));
     460             :     }
     461             : 
     462             :     /* ==================================================================== */
     463             :     /*      Overviews                                                       */
     464             :     /* ==================================================================== */
     465        2938 :     const CPLXMLNode *psNode = psTree->psChild;
     466             : 
     467      120481 :     for (; psNode != nullptr; psNode = psNode->psNext)
     468             :     {
     469      117543 :         if (psNode->eType != CXT_Element ||
     470      109627 :             !EQUAL(psNode->pszValue, "Overview"))
     471      117527 :             continue;
     472             : 
     473             :         /* --------------------------------------------------------------------
     474             :          */
     475             :         /*      Prepare filename. */
     476             :         /* --------------------------------------------------------------------
     477             :          */
     478             :         const CPLXMLNode *psFileNameNode =
     479          16 :             CPLGetXMLNode(psNode, "SourceFilename");
     480             :         const char *pszFilename =
     481          16 :             psFileNameNode ? CPLGetXMLValue(psFileNameNode, nullptr, nullptr)
     482          16 :                            : nullptr;
     483             : 
     484          16 :         if (pszFilename == nullptr)
     485             :         {
     486           0 :             CPLError(CE_Warning, CPLE_AppDefined,
     487             :                      "Missing <SourceFilename> element in Overview.");
     488           0 :             return CE_Failure;
     489             :         }
     490             : 
     491          16 :         if (STARTS_WITH_CI(pszFilename, "MEM:::") && pszVRTPath != nullptr &&
     492           0 :             !CPLTestBool(CPLGetConfigOption("VRT_ALLOW_MEM_DRIVER", "NO")))
     493             :         {
     494           0 :             CPLError(CE_Failure, CPLE_AppDefined,
     495             :                      "<SourceFilename> points to a MEM dataset, which is "
     496             :                      "rather suspect! "
     497             :                      "If you know what you are doing, define the "
     498             :                      "VRT_ALLOW_MEM_DRIVER configuration option to YES");
     499           0 :             return CE_Failure;
     500             :         }
     501             : 
     502          16 :         char *pszSrcDSName = nullptr;
     503          20 :         if (pszVRTPath != nullptr &&
     504           4 :             atoi(CPLGetXMLValue(psFileNameNode, "relativetoVRT", "0")))
     505             :         {
     506           0 :             pszSrcDSName = CPLStrdup(
     507           0 :                 CPLProjectRelativeFilenameSafe(pszVRTPath, pszFilename)
     508             :                     .c_str());
     509             :         }
     510             :         else
     511          16 :             pszSrcDSName = CPLStrdup(pszFilename);
     512             : 
     513             :         /* --------------------------------------------------------------------
     514             :          */
     515             :         /*      Get the raster band. */
     516             :         /* --------------------------------------------------------------------
     517             :          */
     518          16 :         const int nSrcBand = atoi(CPLGetXMLValue(psNode, "SourceBand", "1"));
     519             : 
     520          16 :         m_aoOverviewInfos.resize(m_aoOverviewInfos.size() + 1);
     521          16 :         m_aoOverviewInfos.back().osFilename = pszSrcDSName;
     522          16 :         m_aoOverviewInfos.back().nBand = nSrcBand;
     523             : 
     524          16 :         CPLFree(pszSrcDSName);
     525             :     }
     526             : 
     527             :     /* ==================================================================== */
     528             :     /*      Mask band (specific to that raster band)                        */
     529             :     /* ==================================================================== */
     530        2938 :     const CPLXMLNode *psMaskBandNode = CPLGetXMLNode(psTree, "MaskBand");
     531        2938 :     if (psMaskBandNode)
     532           1 :         psNode = psMaskBandNode->psChild;
     533             :     else
     534        2937 :         psNode = nullptr;
     535        2938 :     for (; psNode != nullptr; psNode = psNode->psNext)
     536             :     {
     537           1 :         if (psNode->eType != CXT_Element ||
     538           1 :             !EQUAL(psNode->pszValue, "VRTRasterBand"))
     539           0 :             continue;
     540             : 
     541           1 :         if (cpl::down_cast<VRTDataset *>(poDS)->m_poMaskBand != nullptr)
     542             :         {
     543           0 :             CPLError(CE_Warning, CPLE_AppDefined,
     544             :                      "Illegal mask band at raster band level when a dataset "
     545             :                      "mask band already exists.");
     546           0 :             return CE_Failure;
     547             :         }
     548             : 
     549             :         const char *pszSubclass =
     550           1 :             CPLGetXMLValue(psNode, "subclass", "VRTSourcedRasterBand");
     551           0 :         std::unique_ptr<VRTRasterBand> poBand;
     552             : 
     553           1 :         if (EQUAL(pszSubclass, "VRTSourcedRasterBand"))
     554           1 :             poBand = std::make_unique<VRTSourcedRasterBand>(GetDataset(), 0);
     555           0 :         else if (EQUAL(pszSubclass, "VRTDerivedRasterBand"))
     556           0 :             poBand = std::make_unique<VRTDerivedRasterBand>(GetDataset(), 0);
     557           0 :         else if (EQUAL(pszSubclass, "VRTRawRasterBand"))
     558             :         {
     559             : #ifdef GDAL_VRT_ENABLE_RAWRASTERBAND
     560           0 :             if (!VRTDataset::IsRawRasterBandEnabled())
     561             :             {
     562           0 :                 return CE_Failure;
     563             :             }
     564           0 :             poBand = std::make_unique<VRTRawRasterBand>(GetDataset(), 0);
     565             : #else
     566             :             CPLError(CE_Failure, CPLE_NotSupported,
     567             :                      "VRTRasterBand::XMLInit(): cannot instantiate "
     568             :                      "VRTRawRasterBand, because disabled in this GDAL build");
     569             :             return CE_Failure;
     570             : #endif
     571             :         }
     572           0 :         else if (EQUAL(pszSubclass, "VRTWarpedRasterBand"))
     573           0 :             poBand = std::make_unique<VRTWarpedRasterBand>(GetDataset(), 0);
     574             :         else
     575             :         {
     576           0 :             CPLError(CE_Failure, CPLE_AppDefined,
     577             :                      "VRTRasterBand of unrecognized subclass '%s'.",
     578             :                      pszSubclass);
     579           0 :             return CE_Failure;
     580             :         }
     581             : 
     582           1 :         if (poBand->XMLInit(psNode, pszVRTPath, oMapSharedSources) == CE_None)
     583             :         {
     584           1 :             SetMaskBand(std::move(poBand));
     585             :         }
     586             :         else
     587             :         {
     588           0 :             return CE_Failure;
     589             :         }
     590             : 
     591           1 :         break;
     592             :     }
     593             : 
     594        2938 :     return CE_None;
     595             : }
     596             : 
     597             : /************************************************************************/
     598             : /*                         VRTSerializeNoData()                         */
     599             : /************************************************************************/
     600             : 
     601         107 : CPLString VRTSerializeNoData(double dfVal, GDALDataType eDataType,
     602             :                              int nPrecision)
     603             : {
     604         107 :     if (std::isnan(dfVal))
     605             :     {
     606           0 :         return "nan";
     607             :     }
     608         107 :     else if (eDataType == GDT_Float16 && dfVal == -6.55e4)
     609             :     {
     610             :         // To avoid rounding out of the range of GFloat16
     611           0 :         return "-6.55e4";
     612             :     }
     613         107 :     else if (eDataType == GDT_Float16 && dfVal == 6.55e4)
     614             :     {
     615             :         // To avoid rounding out of the range of GFloat16
     616           0 :         return "6.55e4";
     617             :     }
     618         128 :     else if (eDataType == GDT_Float32 &&
     619          21 :              dfVal == -static_cast<double>(std::numeric_limits<float>::max()))
     620             :     {
     621             :         // To avoid rounding out of the range of float
     622           8 :         return "-3.4028234663852886e+38";
     623             :     }
     624         112 :     else if (eDataType == GDT_Float32 &&
     625          13 :              dfVal == static_cast<double>(std::numeric_limits<float>::max()))
     626             :     {
     627             :         // To avoid rounding out of the range of float
     628           6 :         return "3.4028234663852886e+38";
     629             :     }
     630             :     else
     631             :     {
     632             :         char szFormat[16];
     633          93 :         snprintf(szFormat, sizeof(szFormat), "%%.%dg", nPrecision);
     634          93 :         return CPLSPrintf(szFormat, dfVal);
     635             :     }
     636             : }
     637             : 
     638             : /************************************************************************/
     639             : /*                           SerializeToXML()                           */
     640             : /************************************************************************/
     641             : 
     642         796 : CPLXMLNode *VRTRasterBand::SerializeToXML(const char *pszVRTPath,
     643             :                                           bool &bHasWarnedAboutRAMUsage,
     644             :                                           size_t &nAccRAMUsage)
     645             : 
     646             : {
     647             :     CPLXMLNode *psTree =
     648         796 :         CPLCreateXMLNode(nullptr, CXT_Element, "VRTRasterBand");
     649             : 
     650             :     /* -------------------------------------------------------------------- */
     651             :     /*      Various kinds of metadata.                                      */
     652             :     /* -------------------------------------------------------------------- */
     653         796 :     CPLSetXMLValue(psTree, "#dataType",
     654             :                    GDALGetDataTypeName(GetRasterDataType()));
     655             : 
     656         796 :     if (nBand > 0)
     657         777 :         CPLSetXMLValue(psTree, "#band", CPLSPrintf("%d", GetBand()));
     658             : 
     659             :     // Do not serialize block size of VRTWarpedRasterBand since it is already
     660             :     // serialized at the dataset level.
     661         796 :     if (dynamic_cast<VRTWarpedRasterBand *>(this) == nullptr)
     662             :     {
     663         724 :         if (!VRTDataset::IsDefaultBlockSize(nBlockXSize, nRasterXSize))
     664             :         {
     665         152 :             CPLSetXMLValue(psTree, "#blockXSize",
     666             :                            CPLSPrintf("%d", nBlockXSize));
     667             :         }
     668             : 
     669         724 :         if (!VRTDataset::IsDefaultBlockSize(nBlockYSize, nRasterYSize))
     670             :         {
     671         252 :             CPLSetXMLValue(psTree, "#blockYSize",
     672             :                            CPLSPrintf("%d", nBlockYSize));
     673             :         }
     674             :     }
     675             : 
     676         796 :     CPLXMLNode *psMD = oMDMD.Serialize();
     677         796 :     if (psMD != nullptr)
     678             :     {
     679         104 :         CPLAddXMLChild(psTree, psMD);
     680             :     }
     681             : 
     682         796 :     if (strlen(GetDescription()) > 0)
     683          71 :         CPLSetXMLValue(psTree, "Description", GetDescription());
     684             : 
     685         796 :     if (m_bNoDataValueSet)
     686             :     {
     687          49 :         CPLSetXMLValue(
     688             :             psTree, "NoDataValue",
     689          98 :             VRTSerializeNoData(m_dfNoDataValue, eDataType, 18).c_str());
     690             :     }
     691         747 :     else if (m_bNoDataSetAsInt64)
     692             :     {
     693           1 :         CPLSetXMLValue(psTree, "NoDataValue",
     694             :                        CPLSPrintf(CPL_FRMT_GIB,
     695           1 :                                   static_cast<GIntBig>(m_nNoDataValueInt64)));
     696             :     }
     697         746 :     else if (m_bNoDataSetAsUInt64)
     698             :     {
     699           1 :         CPLSetXMLValue(psTree, "NoDataValue",
     700             :                        CPLSPrintf(CPL_FRMT_GUIB,
     701           1 :                                   static_cast<GUIntBig>(m_nNoDataValueUInt64)));
     702             :     }
     703             : 
     704         796 :     if (m_bHideNoDataValue)
     705           0 :         CPLSetXMLValue(psTree, "HideNoDataValue",
     706           0 :                        CPLSPrintf("%d", static_cast<int>(m_bHideNoDataValue)));
     707             : 
     708         796 :     if (!m_osUnitType.empty())
     709           2 :         CPLSetXMLValue(psTree, "UnitType", m_osUnitType.c_str());
     710             : 
     711         796 :     if (m_dfOffset != 0.0)
     712           6 :         CPLSetXMLValue(psTree, "Offset", CPLSPrintf("%.16g", m_dfOffset));
     713             : 
     714         796 :     if (m_dfScale != 1.0)
     715           6 :         CPLSetXMLValue(psTree, "Scale", CPLSPrintf("%.16g", m_dfScale));
     716             : 
     717         796 :     if (m_eColorInterp != GCI_Undefined)
     718         509 :         CPLSetXMLValue(psTree, "ColorInterp",
     719             :                        GDALGetColorInterpretationName(m_eColorInterp));
     720             : 
     721             :     /* -------------------------------------------------------------------- */
     722             :     /*      Category names.                                                 */
     723             :     /* -------------------------------------------------------------------- */
     724         796 :     if (!m_aosCategoryNames.empty())
     725             :     {
     726             :         CPLXMLNode *psCT_XML =
     727           5 :             CPLCreateXMLNode(psTree, CXT_Element, "CategoryNames");
     728           5 :         CPLXMLNode *psLastChild = nullptr;
     729             : 
     730          45 :         for (const char *pszName : m_aosCategoryNames)
     731             :         {
     732             :             CPLXMLNode *psNode =
     733          40 :                 CPLCreateXMLElementAndValue(nullptr, "Category", pszName);
     734          40 :             if (psLastChild == nullptr)
     735           5 :                 psCT_XML->psChild = psNode;
     736             :             else
     737          35 :                 psLastChild->psNext = psNode;
     738          40 :             psLastChild = psNode;
     739             :         }
     740             :     }
     741             : 
     742             :     /* -------------------------------------------------------------------- */
     743             :     /*      Histograms.                                                     */
     744             :     /* -------------------------------------------------------------------- */
     745         796 :     if (m_psSavedHistograms != nullptr)
     746           8 :         CPLAddXMLChild(psTree, CPLCloneXMLTree(m_psSavedHistograms.get()));
     747             : 
     748             :     /* -------------------------------------------------------------------- */
     749             :     /*      Color Table.                                                    */
     750             :     /* -------------------------------------------------------------------- */
     751         796 :     if (m_poColorTable != nullptr)
     752             :     {
     753             :         CPLXMLNode *psCT_XML =
     754           8 :             CPLCreateXMLNode(psTree, CXT_Element, "ColorTable");
     755           8 :         CPLXMLNode *psLastChild = nullptr;
     756             : 
     757        1040 :         for (int iEntry = 0; iEntry < m_poColorTable->GetColorEntryCount();
     758             :              iEntry++)
     759             :         {
     760             :             CPLXMLNode *psEntry_XML =
     761        1032 :                 CPLCreateXMLNode(nullptr, CXT_Element, "Entry");
     762        1032 :             if (psLastChild == nullptr)
     763           8 :                 psCT_XML->psChild = psEntry_XML;
     764             :             else
     765        1024 :                 psLastChild->psNext = psEntry_XML;
     766        1032 :             psLastChild = psEntry_XML;
     767             : 
     768             :             GDALColorEntry sEntry;
     769        1032 :             m_poColorTable->GetColorEntryAsRGB(iEntry, &sEntry);
     770             : 
     771        1032 :             CPLSetXMLValue(psEntry_XML, "#c1", CPLSPrintf("%d", sEntry.c1));
     772        1032 :             CPLSetXMLValue(psEntry_XML, "#c2", CPLSPrintf("%d", sEntry.c2));
     773        1032 :             CPLSetXMLValue(psEntry_XML, "#c3", CPLSPrintf("%d", sEntry.c3));
     774        1032 :             CPLSetXMLValue(psEntry_XML, "#c4", CPLSPrintf("%d", sEntry.c4));
     775             :         }
     776             :     }
     777             : 
     778             :     /* -------------------------------------------------------------------- */
     779             :     /*      Raster Attribute Table                                          */
     780             :     /* -------------------------------------------------------------------- */
     781         796 :     if (m_poRAT != nullptr)
     782             :     {
     783           5 :         CPLXMLNode *psSerializedRAT = m_poRAT->Serialize();
     784           5 :         if (psSerializedRAT != nullptr)
     785           5 :             CPLAddXMLChild(psTree, psSerializedRAT);
     786             :     }
     787             : 
     788             :     /* ==================================================================== */
     789             :     /*      Overviews                                                       */
     790             :     /* ==================================================================== */
     791             : 
     792         797 :     for (const auto &ovrInfo : m_aoOverviewInfos)
     793             :     {
     794             :         CPLXMLNode *psOVR_XML =
     795           1 :             CPLCreateXMLNode(psTree, CXT_Element, "Overview");
     796             : 
     797           1 :         int bRelativeToVRT = FALSE;
     798           1 :         const char *pszRelativePath = nullptr;
     799             :         VSIStatBufL sStat;
     800             : 
     801           1 :         if (VSIStatExL(ovrInfo.osFilename, &sStat, VSI_STAT_EXISTS_FLAG) != 0)
     802             :         {
     803           0 :             pszRelativePath = ovrInfo.osFilename;
     804           0 :             bRelativeToVRT = FALSE;
     805             :         }
     806             :         else
     807             :         {
     808           1 :             pszRelativePath = CPLExtractRelativePath(
     809             :                 pszVRTPath, ovrInfo.osFilename, &bRelativeToVRT);
     810             :         }
     811             : 
     812           1 :         CPLSetXMLValue(psOVR_XML, "SourceFilename", pszRelativePath);
     813             : 
     814           1 :         CPLCreateXMLNode(
     815             :             CPLCreateXMLNode(CPLGetXMLNode(psOVR_XML, "SourceFilename"),
     816             :                              CXT_Attribute, "relativeToVRT"),
     817           1 :             CXT_Text, bRelativeToVRT ? "1" : "0");
     818             : 
     819           1 :         CPLSetXMLValue(psOVR_XML, "SourceBand",
     820           1 :                        CPLSPrintf("%d", ovrInfo.nBand));
     821             :     }
     822             : 
     823             :     /* ==================================================================== */
     824             :     /*      Mask band (specific to that raster band)                        */
     825             :     /* ==================================================================== */
     826             : 
     827         796 :     nAccRAMUsage += CPLXMLNodeGetRAMUsageEstimate(psTree);
     828             : 
     829         796 :     if (m_poMaskBand != nullptr)
     830             :     {
     831           0 :         CPLXMLNode *psBandTree = m_poMaskBand->SerializeToXML(
     832           0 :             pszVRTPath, bHasWarnedAboutRAMUsage, nAccRAMUsage);
     833             : 
     834           0 :         if (psBandTree != nullptr)
     835             :         {
     836             :             CPLXMLNode *psMaskBandElement =
     837           0 :                 CPLCreateXMLNode(psTree, CXT_Element, "MaskBand");
     838           0 :             CPLAddXMLChild(psMaskBandElement, psBandTree);
     839             :         }
     840             :     }
     841             : 
     842         796 :     return psTree;
     843             : }
     844             : 
     845             : /************************************************************************/
     846             : /*                         ResetNoDataValues()                          */
     847             : /************************************************************************/
     848             : 
     849         694 : void VRTRasterBand::ResetNoDataValues()
     850             : {
     851         694 :     m_bNoDataValueSet = false;
     852         694 :     m_dfNoDataValue = VRT_DEFAULT_NODATA_VALUE;
     853             : 
     854         694 :     m_bNoDataSetAsInt64 = false;
     855         694 :     m_nNoDataValueInt64 = GDAL_PAM_DEFAULT_NODATA_VALUE_INT64;
     856             : 
     857         694 :     m_bNoDataSetAsUInt64 = false;
     858         694 :     m_nNoDataValueUInt64 = GDAL_PAM_DEFAULT_NODATA_VALUE_UINT64;
     859         694 : }
     860             : 
     861             : /************************************************************************/
     862             : /*                           SetNoDataValue()                           */
     863             : /************************************************************************/
     864             : 
     865         684 : CPLErr VRTRasterBand::SetNoDataValue(double dfNewValue)
     866             : 
     867             : {
     868         684 :     if (eDataType == GDT_Float32)
     869             :     {
     870         166 :         dfNewValue = GDALAdjustNoDataCloseToFloatMax(dfNewValue);
     871             :     }
     872             : 
     873         684 :     ResetNoDataValues();
     874             : 
     875         684 :     m_bNoDataValueSet = true;
     876         684 :     m_dfNoDataValue = dfNewValue;
     877             : 
     878         684 :     cpl::down_cast<VRTDataset *>(poDS)->SetNeedsFlush();
     879             : 
     880         684 :     return CE_None;
     881             : }
     882             : 
     883             : /************************************************************************/
     884             : /*                    IsNoDataValueInDataTypeRange()                    */
     885             : /************************************************************************/
     886             : 
     887           2 : bool VRTRasterBand::IsNoDataValueInDataTypeRange() const
     888             : {
     889           2 :     if (m_bNoDataSetAsInt64)
     890           0 :         return eDataType == GDT_Int64;
     891           2 :     if (m_bNoDataSetAsUInt64)
     892           0 :         return eDataType == GDT_UInt64;
     893           2 :     if (!m_bNoDataValueSet)
     894           0 :         return true;
     895           2 :     if (!std::isfinite(m_dfNoDataValue))
     896           0 :         return eDataType == GDT_Float16 || eDataType == GDT_Float32 ||
     897           0 :                eDataType == GDT_Float64;
     898             :     GByte abyTempBuffer[2 * sizeof(double)];
     899           2 :     CPLAssert(GDALGetDataTypeSizeBytes(eDataType) <=
     900             :               static_cast<int>(sizeof(abyTempBuffer)));
     901           2 :     GDALCopyWords(&m_dfNoDataValue, GDT_Float64, 0, &abyTempBuffer[0],
     902           2 :                   eDataType, 0, 1);
     903           2 :     double dfNoDataValueAfter = 0;
     904           2 :     GDALCopyWords(&abyTempBuffer[0], eDataType, 0, &dfNoDataValueAfter,
     905             :                   GDT_Float64, 0, 1);
     906           2 :     return std::fabs(dfNoDataValueAfter - m_dfNoDataValue) < 1.0;
     907             : }
     908             : 
     909             : /************************************************************************/
     910             : /*                       SetNoDataValueAsInt64()                        */
     911             : /************************************************************************/
     912             : 
     913           4 : CPLErr VRTRasterBand::SetNoDataValueAsInt64(int64_t nNewValue)
     914             : 
     915             : {
     916           4 :     ResetNoDataValues();
     917             : 
     918           4 :     m_bNoDataSetAsInt64 = true;
     919           4 :     m_nNoDataValueInt64 = nNewValue;
     920             : 
     921           4 :     cpl::down_cast<VRTDataset *>(poDS)->SetNeedsFlush();
     922             : 
     923           4 :     return CE_None;
     924             : }
     925             : 
     926             : /************************************************************************/
     927             : /*                       SetNoDataValueAsUInt64()                       */
     928             : /************************************************************************/
     929             : 
     930           4 : CPLErr VRTRasterBand::SetNoDataValueAsUInt64(uint64_t nNewValue)
     931             : 
     932             : {
     933           4 :     ResetNoDataValues();
     934             : 
     935           4 :     m_bNoDataSetAsUInt64 = true;
     936           4 :     m_nNoDataValueUInt64 = nNewValue;
     937             : 
     938           4 :     cpl::down_cast<VRTDataset *>(poDS)->SetNeedsFlush();
     939             : 
     940           4 :     return CE_None;
     941             : }
     942             : 
     943             : /************************************************************************/
     944             : /*                         DeleteNoDataValue()                          */
     945             : /************************************************************************/
     946             : 
     947           2 : CPLErr VRTRasterBand::DeleteNoDataValue()
     948             : {
     949           2 :     ResetNoDataValues();
     950             : 
     951           2 :     cpl::down_cast<VRTDataset *>(poDS)->SetNeedsFlush();
     952             : 
     953           2 :     return CE_None;
     954             : }
     955             : 
     956             : /************************************************************************/
     957             : /*                          UnsetNoDataValue()                          */
     958             : /************************************************************************/
     959             : 
     960           0 : CPLErr VRTRasterBand::UnsetNoDataValue()
     961             : {
     962           0 :     return DeleteNoDataValue();
     963             : }
     964             : 
     965             : /************************************************************************/
     966             : /*                           GetNoDataValue()                           */
     967             : /************************************************************************/
     968             : 
     969       40429 : double VRTRasterBand::GetNoDataValue(int *pbSuccess)
     970             : 
     971             : {
     972       40429 :     if (m_bNoDataSetAsInt64)
     973             :     {
     974           0 :         if (pbSuccess)
     975           0 :             *pbSuccess = !m_bHideNoDataValue;
     976           0 :         return GDALGetNoDataValueCastToDouble(m_nNoDataValueInt64);
     977             :     }
     978             : 
     979       40429 :     if (m_bNoDataSetAsUInt64)
     980             :     {
     981           0 :         if (pbSuccess)
     982           0 :             *pbSuccess = !m_bHideNoDataValue;
     983           0 :         return GDALGetNoDataValueCastToDouble(m_nNoDataValueUInt64);
     984             :     }
     985             : 
     986       40429 :     if (pbSuccess)
     987       40182 :         *pbSuccess = m_bNoDataValueSet && !m_bHideNoDataValue;
     988             : 
     989       40429 :     return m_dfNoDataValue;
     990             : }
     991             : 
     992             : /************************************************************************/
     993             : /*                       GetNoDataValueAsInt64()                        */
     994             : /************************************************************************/
     995             : 
     996          16 : int64_t VRTRasterBand::GetNoDataValueAsInt64(int *pbSuccess)
     997             : 
     998             : {
     999          16 :     if (eDataType == GDT_UInt64)
    1000             :     {
    1001           0 :         CPLError(CE_Failure, CPLE_AppDefined,
    1002             :                  "GetNoDataValueAsUInt64() should be called instead");
    1003           0 :         if (pbSuccess)
    1004           0 :             *pbSuccess = FALSE;
    1005           0 :         return GDAL_PAM_DEFAULT_NODATA_VALUE_INT64;
    1006             :     }
    1007          16 :     if (eDataType != GDT_Int64)
    1008             :     {
    1009           0 :         CPLError(CE_Failure, CPLE_AppDefined,
    1010             :                  "GetNoDataValue() should be called instead");
    1011           0 :         if (pbSuccess)
    1012           0 :             *pbSuccess = FALSE;
    1013           0 :         return GDAL_PAM_DEFAULT_NODATA_VALUE_INT64;
    1014             :     }
    1015             : 
    1016          16 :     if (pbSuccess)
    1017          15 :         *pbSuccess = m_bNoDataSetAsInt64 && !m_bHideNoDataValue;
    1018             : 
    1019          16 :     return m_nNoDataValueInt64;
    1020             : }
    1021             : 
    1022             : /************************************************************************/
    1023             : /*                       GetNoDataValueAsUInt64()                       */
    1024             : /************************************************************************/
    1025             : 
    1026           8 : uint64_t VRTRasterBand::GetNoDataValueAsUInt64(int *pbSuccess)
    1027             : 
    1028             : {
    1029           8 :     if (eDataType == GDT_Int64)
    1030             :     {
    1031           0 :         CPLError(CE_Failure, CPLE_AppDefined,
    1032             :                  "GetNoDataValueAsInt64() should be called instead");
    1033           0 :         if (pbSuccess)
    1034           0 :             *pbSuccess = FALSE;
    1035           0 :         return GDAL_PAM_DEFAULT_NODATA_VALUE_UINT64;
    1036             :     }
    1037           8 :     if (eDataType != GDT_UInt64)
    1038             :     {
    1039           0 :         CPLError(CE_Failure, CPLE_AppDefined,
    1040             :                  "GetNoDataValue() should be called instead");
    1041           0 :         if (pbSuccess)
    1042           0 :             *pbSuccess = FALSE;
    1043           0 :         return GDAL_PAM_DEFAULT_NODATA_VALUE_UINT64;
    1044             :     }
    1045             : 
    1046           8 :     if (pbSuccess)
    1047           7 :         *pbSuccess = m_bNoDataSetAsUInt64 && !m_bHideNoDataValue;
    1048             : 
    1049           8 :     return m_nNoDataValueUInt64;
    1050             : }
    1051             : 
    1052             : /************************************************************************/
    1053             : /*                           SetColorTable()                            */
    1054             : /************************************************************************/
    1055             : 
    1056       70949 : CPLErr VRTRasterBand::SetColorTable(GDALColorTable *poTableIn)
    1057             : 
    1058             : {
    1059       70949 :     if (poTableIn == nullptr)
    1060       70896 :         m_poColorTable.reset();
    1061             :     else
    1062             :     {
    1063          53 :         m_poColorTable.reset(poTableIn->Clone());
    1064          53 :         m_eColorInterp = GCI_PaletteIndex;
    1065             :     }
    1066             : 
    1067       70949 :     cpl::down_cast<VRTDataset *>(poDS)->SetNeedsFlush();
    1068             : 
    1069       70949 :     return CE_None;
    1070             : }
    1071             : 
    1072             : /************************************************************************/
    1073             : /*                           GetColorTable()                            */
    1074             : /************************************************************************/
    1075             : 
    1076        6769 : GDALColorTable *VRTRasterBand::GetColorTable()
    1077             : 
    1078             : {
    1079        6769 :     return m_poColorTable.get();
    1080             : }
    1081             : 
    1082             : /************************************************************************/
    1083             : /*                       SetColorInterpretation()                       */
    1084             : /************************************************************************/
    1085             : 
    1086       73627 : CPLErr VRTRasterBand::SetColorInterpretation(GDALColorInterp eInterpIn)
    1087             : 
    1088             : {
    1089       73627 :     cpl::down_cast<VRTDataset *>(poDS)->SetNeedsFlush();
    1090             : 
    1091       73627 :     m_eColorInterp = eInterpIn;
    1092             : 
    1093       73627 :     return CE_None;
    1094             : }
    1095             : 
    1096             : /************************************************************************/
    1097             : /*                           GetDefaultRAT()                            */
    1098             : /************************************************************************/
    1099             : 
    1100        7937 : GDALRasterAttributeTable *VRTRasterBand::GetDefaultRAT()
    1101             : {
    1102        7937 :     return m_poRAT.get();
    1103             : }
    1104             : 
    1105             : /************************************************************************/
    1106             : /*                           SetDefaultRAT()                            */
    1107             : /************************************************************************/
    1108             : 
    1109         897 : CPLErr VRTRasterBand::SetDefaultRAT(const GDALRasterAttributeTable *poRAT)
    1110             : {
    1111         897 :     if (poRAT == nullptr)
    1112         893 :         m_poRAT.reset();
    1113             :     else
    1114           4 :         m_poRAT.reset(poRAT->Clone());
    1115             : 
    1116         897 :     cpl::down_cast<VRTDataset *>(poDS)->SetNeedsFlush();
    1117             : 
    1118         897 :     return CE_None;
    1119             : }
    1120             : 
    1121             : /************************************************************************/
    1122             : /*                       GetColorInterpretation()                       */
    1123             : /************************************************************************/
    1124             : 
    1125       18274 : GDALColorInterp VRTRasterBand::GetColorInterpretation()
    1126             : 
    1127             : {
    1128       18274 :     return m_eColorInterp;
    1129             : }
    1130             : 
    1131             : /************************************************************************/
    1132             : /*                            GetHistogram()                            */
    1133             : /************************************************************************/
    1134             : 
    1135           3 : CPLErr VRTRasterBand::GetHistogram(double dfMin, double dfMax, int nBuckets,
    1136             :                                    GUIntBig *panHistogram,
    1137             :                                    int bIncludeOutOfRange, int bApproxOK,
    1138             :                                    GDALProgressFunc pfnProgress,
    1139             :                                    void *pProgressData)
    1140             : 
    1141             : {
    1142             :     /* -------------------------------------------------------------------- */
    1143             :     /*      Check if we have a matching histogram.                          */
    1144             :     /* -------------------------------------------------------------------- */
    1145             :     CPLXMLNode *psHistItem =
    1146           3 :         PamFindMatchingHistogram(m_psSavedHistograms.get(), dfMin, dfMax,
    1147             :                                  nBuckets, bIncludeOutOfRange, bApproxOK);
    1148           3 :     if (psHistItem != nullptr)
    1149             :     {
    1150           0 :         GUIntBig *panTempHist = nullptr;
    1151             : 
    1152           0 :         if (PamParseHistogram(psHistItem, &dfMin, &dfMax, &nBuckets,
    1153           0 :                               &panTempHist, &bIncludeOutOfRange, &bApproxOK))
    1154             :         {
    1155           0 :             memcpy(panHistogram, panTempHist, sizeof(GUIntBig) * nBuckets);
    1156           0 :             CPLFree(panTempHist);
    1157           0 :             return CE_None;
    1158             :         }
    1159             :     }
    1160             : 
    1161             :     /* -------------------------------------------------------------------- */
    1162             :     /*      We don't have an existing histogram matching the request, so    */
    1163             :     /*      generate one manually.                                          */
    1164             :     /* -------------------------------------------------------------------- */
    1165           3 :     CPLErr eErr = GDALRasterBand::GetHistogram(
    1166             :         dfMin, dfMax, nBuckets, panHistogram, bIncludeOutOfRange, bApproxOK,
    1167             :         pfnProgress, pProgressData);
    1168             : 
    1169             :     /* -------------------------------------------------------------------- */
    1170             :     /*      Save an XML description of this histogram.                      */
    1171             :     /* -------------------------------------------------------------------- */
    1172           3 :     if (eErr == CE_None)
    1173             :     {
    1174             :         CPLXMLNode *psXMLHist =
    1175           3 :             PamHistogramToXMLTree(dfMin, dfMax, nBuckets, panHistogram,
    1176             :                                   bIncludeOutOfRange, bApproxOK);
    1177           3 :         if (psXMLHist != nullptr)
    1178             :         {
    1179           3 :             cpl::down_cast<VRTDataset *>(poDS)->SetNeedsFlush();
    1180             : 
    1181           3 :             if (m_psSavedHistograms == nullptr)
    1182           3 :                 m_psSavedHistograms.reset(
    1183             :                     CPLCreateXMLNode(nullptr, CXT_Element, "Histograms"));
    1184             : 
    1185           3 :             CPLAddXMLChild(m_psSavedHistograms.get(), psXMLHist);
    1186             :         }
    1187             :     }
    1188             : 
    1189           3 :     return eErr;
    1190             : }
    1191             : 
    1192             : /************************************************************************/
    1193             : /*                        SetDefaultHistogram()                         */
    1194             : /************************************************************************/
    1195             : 
    1196           5 : CPLErr VRTRasterBand::SetDefaultHistogram(double dfMin, double dfMax,
    1197             :                                           int nBuckets, GUIntBig *panHistogram)
    1198             : 
    1199             : {
    1200             :     /* -------------------------------------------------------------------- */
    1201             :     /*      Do we have a matching histogram we should replace?              */
    1202             :     /* -------------------------------------------------------------------- */
    1203           5 :     CPLXMLNode *psNode = PamFindMatchingHistogram(
    1204             :         m_psSavedHistograms.get(), dfMin, dfMax, nBuckets, TRUE, TRUE);
    1205           5 :     if (psNode != nullptr)
    1206             :     {
    1207             :         /* blow this one away */
    1208           0 :         CPLRemoveXMLChild(m_psSavedHistograms.get(), psNode);
    1209           0 :         CPLDestroyXMLNode(psNode);
    1210             :     }
    1211             : 
    1212             :     /* -------------------------------------------------------------------- */
    1213             :     /*      Translate into a histogram XML tree.                            */
    1214             :     /* -------------------------------------------------------------------- */
    1215           5 :     CPLXMLNode *psHistItem = PamHistogramToXMLTree(dfMin, dfMax, nBuckets,
    1216             :                                                    panHistogram, TRUE, FALSE);
    1217           5 :     if (psHistItem == nullptr)
    1218           0 :         return CE_Failure;
    1219             : 
    1220             :     /* -------------------------------------------------------------------- */
    1221             :     /*      Insert our new default histogram at the front of the            */
    1222             :     /*      histogram list so that it will be the default histogram.        */
    1223             :     /* -------------------------------------------------------------------- */
    1224           5 :     cpl::down_cast<VRTDataset *>(poDS)->SetNeedsFlush();
    1225             : 
    1226           5 :     if (m_psSavedHistograms == nullptr)
    1227           5 :         m_psSavedHistograms.reset(
    1228             :             CPLCreateXMLNode(nullptr, CXT_Element, "Histograms"));
    1229             : 
    1230           5 :     psHistItem->psNext = m_psSavedHistograms->psChild;
    1231           5 :     m_psSavedHistograms->psChild = psHistItem;
    1232             : 
    1233           5 :     return CE_None;
    1234             : }
    1235             : 
    1236             : /************************************************************************/
    1237             : /*                        GetDefaultHistogram()                         */
    1238             : /************************************************************************/
    1239             : 
    1240           4 : CPLErr VRTRasterBand::GetDefaultHistogram(double *pdfMin, double *pdfMax,
    1241             :                                           int *pnBuckets,
    1242             :                                           GUIntBig **ppanHistogram, int bForce,
    1243             :                                           GDALProgressFunc pfnProgress,
    1244             :                                           void *pProgressData)
    1245             : 
    1246             : {
    1247           4 :     if (m_psSavedHistograms != nullptr)
    1248             :     {
    1249           1 :         for (CPLXMLNode *psXMLHist = m_psSavedHistograms->psChild;
    1250           1 :              psXMLHist != nullptr; psXMLHist = psXMLHist->psNext)
    1251             :         {
    1252           1 :             if (psXMLHist->eType != CXT_Element ||
    1253           1 :                 !EQUAL(psXMLHist->pszValue, "HistItem"))
    1254           0 :                 continue;
    1255             : 
    1256             :             int bIncludeOutOfRange;
    1257             :             int bApprox;
    1258           1 :             if (PamParseHistogram(psXMLHist, pdfMin, pdfMax, pnBuckets,
    1259           1 :                                   ppanHistogram, &bIncludeOutOfRange, &bApprox))
    1260           1 :                 return CE_None;
    1261             : 
    1262           0 :             return CE_Failure;
    1263             :         }
    1264             :     }
    1265             : 
    1266           3 :     return GDALRasterBand::GetDefaultHistogram(pdfMin, pdfMax, pnBuckets,
    1267             :                                                ppanHistogram, bForce,
    1268           3 :                                                pfnProgress, pProgressData);
    1269             : }
    1270             : 
    1271             : /************************************************************************/
    1272             : /*                            GetFileList()                             */
    1273             : /************************************************************************/
    1274             : 
    1275          70 : void VRTRasterBand::GetFileList(char ***ppapszFileList, int *pnSize,
    1276             :                                 int *pnMaxSize, CPLHashSet *hSetFiles)
    1277             : {
    1278          71 :     for (unsigned int iOver = 0; iOver < m_aoOverviewInfos.size(); iOver++)
    1279             :     {
    1280           1 :         const CPLString &osFilename = m_aoOverviewInfos[iOver].osFilename;
    1281             : 
    1282             :         /* --------------------------------------------------------------------
    1283             :          */
    1284             :         /*      Is the filename even a real filesystem object? */
    1285             :         /* --------------------------------------------------------------------
    1286             :          */
    1287             :         VSIStatBufL sStat;
    1288           1 :         if (VSIStatL(osFilename, &sStat) != 0)
    1289           0 :             return;
    1290             : 
    1291             :         /* --------------------------------------------------------------------
    1292             :          */
    1293             :         /*      Is it already in the list ? */
    1294             :         /* --------------------------------------------------------------------
    1295             :          */
    1296           1 :         if (CPLHashSetLookup(hSetFiles, osFilename) != nullptr)
    1297           0 :             return;
    1298             : 
    1299             :         /* --------------------------------------------------------------------
    1300             :          */
    1301             :         /*      Grow array if necessary */
    1302             :         /* --------------------------------------------------------------------
    1303             :          */
    1304           1 :         if (*pnSize + 1 >= *pnMaxSize)
    1305             :         {
    1306           1 :             *pnMaxSize = 2 + 2 * (*pnMaxSize);
    1307           1 :             *ppapszFileList = static_cast<char **>(
    1308           1 :                 CPLRealloc(*ppapszFileList, sizeof(char *) * (*pnMaxSize)));
    1309             :         }
    1310             : 
    1311             :         /* --------------------------------------------------------------------
    1312             :          */
    1313             :         /*      Add the string to the list */
    1314             :         /* --------------------------------------------------------------------
    1315             :          */
    1316           1 :         (*ppapszFileList)[*pnSize] = CPLStrdup(osFilename);
    1317           1 :         (*ppapszFileList)[(*pnSize + 1)] = nullptr;
    1318           1 :         CPLHashSetInsert(hSetFiles, (*ppapszFileList)[*pnSize]);
    1319             : 
    1320           1 :         (*pnSize)++;
    1321             :     }
    1322             : }
    1323             : 
    1324             : /************************************************************************/
    1325             : /*                          GetOverviewCount()                          */
    1326             : /************************************************************************/
    1327             : 
    1328        5891 : int VRTRasterBand::GetOverviewCount()
    1329             : 
    1330             : {
    1331        5891 :     VRTDataset *poVRTDS = cpl::down_cast<VRTDataset *>(poDS);
    1332        5891 :     if (!poVRTDS->AreOverviewsEnabled())
    1333           1 :         return 0;
    1334             : 
    1335             :     // First: overviews declared in <Overview> element
    1336        5890 :     if (!m_aoOverviewInfos.empty())
    1337          22 :         return static_cast<int>(m_aoOverviewInfos.size());
    1338             : 
    1339             :     // If not found, external .ovr overviews
    1340        5868 :     const int nOverviewCount = poVRTDS->GetDescription()[0] == '\0'
    1341        5868 :                                    ? 0
    1342        5356 :                                    : GDALRasterBand::GetOverviewCount();
    1343        5868 :     if (nOverviewCount)
    1344          52 :         return nOverviewCount;
    1345             : 
    1346        5816 :     if (poVRTDS->m_apoOverviews.empty())
    1347             :     {
    1348             :         // If not found, implicit virtual overviews
    1349             : 
    1350        5679 :         const std::string osFctId("VRTRasterBand::GetOverviewCount");
    1351        5679 :         GDALAntiRecursionGuard oGuard(osFctId);
    1352        5679 :         if (oGuard.GetCallDepth() >= 32)
    1353             :         {
    1354           0 :             CPLError(CE_Failure, CPLE_AppDefined, "Recursion detected");
    1355           0 :             return 0;
    1356             :         }
    1357             : 
    1358       11358 :         GDALAntiRecursionGuard oGuard2(oGuard, poVRTDS->GetDescription());
    1359        5679 :         if (oGuard2.GetCallDepth() >= 2)
    1360             :         {
    1361           0 :             CPLError(CE_Failure, CPLE_AppDefined, "Recursion detected");
    1362           0 :             return 0;
    1363             :         }
    1364             : 
    1365        5679 :         poVRTDS->BuildVirtualOverviews();
    1366             :     }
    1367        5816 :     if (!poVRTDS->m_apoOverviews.empty() && poVRTDS->m_apoOverviews[0])
    1368          95 :         return static_cast<int>(poVRTDS->m_apoOverviews.size());
    1369             : 
    1370        5721 :     return 0;
    1371             : }
    1372             : 
    1373             : /************************************************************************/
    1374             : /*                            GetOverview()                             */
    1375             : /************************************************************************/
    1376             : 
    1377         212 : GDALRasterBand *VRTRasterBand::GetOverview(int iOverview)
    1378             : 
    1379             : {
    1380             :     // First: overviews declared in <Overview> element
    1381         212 :     if (!m_aoOverviewInfos.empty())
    1382             :     {
    1383          35 :         if (iOverview < 0 ||
    1384          17 :             iOverview >= static_cast<int>(m_aoOverviewInfos.size()))
    1385           2 :             return nullptr;
    1386             : 
    1387          28 :         if (m_aoOverviewInfos[iOverview].poBand == nullptr &&
    1388          12 :             !m_aoOverviewInfos[iOverview].bTriedToOpen)
    1389             :         {
    1390          12 :             m_aoOverviewInfos[iOverview].bTriedToOpen = TRUE;
    1391          12 :             CPLConfigOptionSetter oSetter("CPL_ALLOW_VSISTDIN", "NO", true);
    1392          12 :             GDALDataset *poSrcDS = GDALDataset::FromHandle(GDALOpenShared(
    1393          12 :                 m_aoOverviewInfos[iOverview].osFilename, GA_ReadOnly));
    1394             : 
    1395          12 :             if (poSrcDS == nullptr)
    1396           1 :                 return nullptr;
    1397          11 :             if (poSrcDS == poDS)
    1398             :             {
    1399           1 :                 CPLError(CE_Failure, CPLE_AppDefined,
    1400             :                          "Recursive opening attempt");
    1401           1 :                 GDALClose(GDALDataset::ToHandle(poSrcDS));
    1402           1 :                 return nullptr;
    1403             :             }
    1404             : 
    1405          20 :             m_aoOverviewInfos[iOverview].poBand =
    1406          10 :                 poSrcDS->GetRasterBand(m_aoOverviewInfos[iOverview].nBand);
    1407             : 
    1408          10 :             if (m_aoOverviewInfos[iOverview].poBand == nullptr)
    1409             :             {
    1410           1 :                 GDALClose(GDALDataset::ToHandle(poSrcDS));
    1411             :             }
    1412             :         }
    1413             : 
    1414          14 :         return m_aoOverviewInfos[iOverview].poBand;
    1415             :     }
    1416             : 
    1417             :     // If not found, external .ovr overviews
    1418         194 :     GDALRasterBand *poRet = GDALRasterBand::GetOverview(iOverview);
    1419         194 :     if (poRet)
    1420          56 :         return poRet;
    1421             : 
    1422             :     // If not found, implicit virtual overviews
    1423         138 :     VRTDataset *poVRTDS = cpl::down_cast<VRTDataset *>(poDS);
    1424         138 :     poVRTDS->BuildVirtualOverviews();
    1425         138 :     if (!poVRTDS->m_apoOverviews.empty() && poVRTDS->m_apoOverviews[0])
    1426             :     {
    1427         265 :         if (iOverview < 0 ||
    1428         132 :             iOverview >= static_cast<int>(poVRTDS->m_apoOverviews.size()))
    1429           2 :             return nullptr;
    1430             : 
    1431         262 :         auto poOvrBand = poVRTDS->m_apoOverviews[iOverview]->GetRasterBand(
    1432         131 :             nBand ? nBand : 1);
    1433         131 :         if (m_bIsMaskBand)
    1434           0 :             return poOvrBand->GetMaskBand();
    1435         131 :         return poOvrBand;
    1436             :     }
    1437             : 
    1438           5 :     return nullptr;
    1439             : }
    1440             : 
    1441             : /************************************************************************/
    1442             : /*                           SetDescription()                           */
    1443             : /************************************************************************/
    1444             : 
    1445        3751 : void VRTRasterBand::SetDescription(const char *pszDescription)
    1446             : 
    1447             : {
    1448        3751 :     cpl::down_cast<VRTDataset *>(poDS)->SetNeedsFlush();
    1449             : 
    1450        3751 :     GDALRasterBand::SetDescription(pszDescription);
    1451        3751 : }
    1452             : 
    1453             : /************************************************************************/
    1454             : /*                           CreateMaskBand()                           */
    1455             : /************************************************************************/
    1456             : 
    1457          11 : CPLErr VRTRasterBand::CreateMaskBand(int nFlagsIn)
    1458             : {
    1459          11 :     VRTDataset *poGDS = cpl::down_cast<VRTDataset *>(poDS);
    1460             : 
    1461          11 :     if (poGDS->m_poMaskBand)
    1462             :     {
    1463           1 :         CPLError(CE_Failure, CPLE_AppDefined,
    1464             :                  "Cannot create mask band at raster band level when a dataset "
    1465             :                  "mask band already exists.");
    1466           1 :         return CE_Failure;
    1467             :     }
    1468             : 
    1469          10 :     if (m_poMaskBand != nullptr)
    1470             :     {
    1471           1 :         CPLError(CE_Failure, CPLE_AppDefined,
    1472             :                  "This VRT band has already a mask band");
    1473           1 :         return CE_Failure;
    1474             :     }
    1475             : 
    1476           9 :     if ((nFlagsIn & GMF_PER_DATASET) != 0)
    1477           1 :         return poGDS->CreateMaskBand(nFlagsIn);
    1478             : 
    1479           8 :     SetMaskBand(std::make_unique<VRTSourcedRasterBand>(poGDS, 0));
    1480             : 
    1481           8 :     return CE_None;
    1482             : }
    1483             : 
    1484             : /************************************************************************/
    1485             : /*                            GetMaskBand()                             */
    1486             : /************************************************************************/
    1487             : 
    1488        4960 : GDALRasterBand *VRTRasterBand::GetMaskBand()
    1489             : {
    1490        4960 :     VRTDataset *poGDS = cpl::down_cast<VRTDataset *>(poDS);
    1491             : 
    1492        4960 :     if (poGDS->m_poMaskBand)
    1493         138 :         return poGDS->m_poMaskBand.get();
    1494        4822 :     else if (m_poMaskBand)
    1495          12 :         return m_poMaskBand.get();
    1496             :     else
    1497        4810 :         return GDALRasterBand::GetMaskBand();
    1498             : }
    1499             : 
    1500             : /************************************************************************/
    1501             : /*                            GetMaskFlags()                            */
    1502             : /************************************************************************/
    1503             : 
    1504       12762 : int VRTRasterBand::GetMaskFlags()
    1505             : {
    1506       12762 :     VRTDataset *poGDS = cpl::down_cast<VRTDataset *>(poDS);
    1507             : 
    1508       12762 :     if (poGDS->m_poMaskBand)
    1509          96 :         return GMF_PER_DATASET;
    1510       12666 :     else if (m_poMaskBand)
    1511          15 :         return 0;
    1512             :     else
    1513       12651 :         return GDALRasterBand::GetMaskFlags();
    1514             : }
    1515             : 
    1516             : /************************************************************************/
    1517             : /*                            SetMaskBand()                             */
    1518             : /************************************************************************/
    1519             : 
    1520           9 : void VRTRasterBand::SetMaskBand(std::unique_ptr<VRTRasterBand> poMaskBand)
    1521             : {
    1522           9 :     m_poMaskBand = std::move(poMaskBand);
    1523           9 :     m_poMaskBand->SetIsMaskBand();
    1524           9 : }
    1525             : 
    1526             : /************************************************************************/
    1527             : /*                           SetIsMaskBand()                            */
    1528             : /************************************************************************/
    1529             : 
    1530          88 : void VRTRasterBand::SetIsMaskBand()
    1531             : {
    1532          88 :     nBand = 0;
    1533          88 :     m_bIsMaskBand = true;
    1534          88 : }
    1535             : 
    1536             : /************************************************************************/
    1537             : /*                             IsMaskBand()                             */
    1538             : /************************************************************************/
    1539             : 
    1540          85 : bool VRTRasterBand::IsMaskBand() const
    1541             : {
    1542          85 :     return m_bIsMaskBand || m_eColorInterp == GCI_AlphaBand;
    1543             : }
    1544             : 
    1545             : /************************************************************************/
    1546             : /*                       CloseDependentDatasets()                       */
    1547             : /************************************************************************/
    1548             : 
    1549      143146 : int VRTRasterBand::CloseDependentDatasets()
    1550             : {
    1551      143146 :     int ret = FALSE;
    1552      143162 :     for (auto &oOverviewInfo : m_aoOverviewInfos)
    1553             :     {
    1554          16 :         if (oOverviewInfo.CloseDataset())
    1555             :         {
    1556           9 :             ret = TRUE;
    1557             :         }
    1558             :     }
    1559      143146 :     return ret;
    1560             : }
    1561             : 
    1562             : /*! @endcond */

Generated by: LCOV version 1.14