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

Generated by: LCOV version 1.14