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

Generated by: LCOV version 1.14