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

Generated by: LCOV version 1.14