LCOV - code coverage report
Current view: top level - gcore - gdaloverviewdataset.cpp (source / functions) Hit Total Coverage
Test: gdal_filtered.info Lines: 224 246 91.1 %
Date: 2025-08-01 10:10:57 Functions: 25 25 100.0 %

          Line data    Source code
       1             : /******************************************************************************
       2             :  *
       3             :  * Project:  GDAL Core
       4             :  * Purpose:  Implementation of a dataset overview warping class
       5             :  * Author:   Even Rouault, <even dot rouault at spatialys dot com>
       6             :  *
       7             :  ******************************************************************************
       8             :  * Copyright (c) 2014, Even Rouault, <even dot rouault at spatialys dot com>
       9             :  *
      10             :  * SPDX-License-Identifier: MIT
      11             :  ****************************************************************************/
      12             : 
      13             : #include "cpl_port.h"
      14             : #include "gdal_priv.h"
      15             : 
      16             : #include <cstring>
      17             : 
      18             : #include "cpl_conv.h"
      19             : #include "cpl_error.h"
      20             : #include "cpl_progress.h"
      21             : #include "cpl_string.h"
      22             : #include "gdal.h"
      23             : #include "gdal_mdreader.h"
      24             : #include "gdal_proxy.h"
      25             : 
      26             : /** In GDAL, GDALRasterBand::GetOverview() returns a stand-alone band, that may
      27             :     have no parent dataset. This can be inconvenient in certain contexts, where
      28             :     cross-band processing must be done, or when API expect a fully fledged
      29             :     dataset.  Furthermore even if overview band has a container dataset, that
      30             :     one often fails to declare its projection, geotransform, etc... which make
      31             :     it somehow useless. GDALOverviewDataset remedies to those deficiencies.
      32             : */
      33             : 
      34             : class GDALOverviewBand;
      35             : 
      36             : /* ******************************************************************** */
      37             : /*                          GDALOverviewDataset                         */
      38             : /* ******************************************************************** */
      39             : 
      40             : class GDALOverviewDataset final : public GDALDataset
      41             : {
      42             :   private:
      43             :     friend class GDALOverviewBand;
      44             : 
      45             :     GDALDataset *poMainDS = nullptr;
      46             : 
      47             :     GDALDataset *poOvrDS = nullptr;  // Will be often NULL.
      48             :     int nOvrLevel = 0;
      49             :     bool bThisLevelOnly = false;
      50             : 
      51             :     int nGCPCount = 0;
      52             :     GDAL_GCP *pasGCPList = nullptr;
      53             :     char **papszMD_RPC = nullptr;
      54             :     char **papszMD_GEOLOCATION = nullptr;
      55             :     GDALOverviewBand *m_poMaskBand = nullptr;
      56             : 
      57             :     static void Rescale(char **&papszMD, const char *pszItem, double dfRatio,
      58             :                         double dfDefaultVal, double dfPreShift = 0,
      59             :                         double dfPostShift = 0);
      60             : 
      61             :   protected:
      62             :     CPLErr IRasterIO(GDALRWFlag, int, int, int, int, void *, int, int,
      63             :                      GDALDataType, int, BANDMAP_TYPE, GSpacing, GSpacing,
      64             :                      GSpacing, GDALRasterIOExtraArg *psExtraArg) override;
      65             : 
      66             :   public:
      67             :     GDALOverviewDataset(GDALDataset *poMainDS, int nOvrLevel,
      68             :                         bool bThisLevelOnly);
      69             :     ~GDALOverviewDataset() override;
      70             : 
      71             :     const OGRSpatialReference *GetSpatialRef() const override;
      72             :     CPLErr GetGeoTransform(GDALGeoTransform &gt) const override;
      73             : 
      74             :     int GetGCPCount() override;
      75             :     const OGRSpatialReference *GetGCPSpatialRef() const override;
      76             :     const GDAL_GCP *GetGCPs() override;
      77             : 
      78             :     char **GetMetadata(const char *pszDomain = "") override;
      79             :     const char *GetMetadataItem(const char *pszName,
      80             :                                 const char *pszDomain = "") override;
      81             : 
      82             :     int CloseDependentDatasets() override;
      83             : 
      84             :   private:
      85             :     CPL_DISALLOW_COPY_ASSIGN(GDALOverviewDataset)
      86             : };
      87             : 
      88             : /* ******************************************************************** */
      89             : /*                           GDALOverviewBand                           */
      90             : /* ******************************************************************** */
      91             : 
      92             : class GDALOverviewBand final : public GDALProxyRasterBand
      93             : {
      94             :   protected:
      95             :     friend class GDALOverviewDataset;
      96             : 
      97             :     GDALRasterBand *poUnderlyingBand = nullptr;
      98             :     GDALRasterBand *RefUnderlyingRasterBand(bool bForceOpen) const override;
      99             : 
     100             :     CPLErr IRasterIO(GDALRWFlag, int, int, int, int, void *, int, int,
     101             :                      GDALDataType, GSpacing, GSpacing,
     102             :                      GDALRasterIOExtraArg *psExtraArg) override;
     103             : 
     104             :   public:
     105             :     GDALOverviewBand(GDALOverviewDataset *poDS, int nBand);
     106             :     ~GDALOverviewBand() override;
     107             : 
     108             :     CPLErr FlushCache(bool bAtClosing) override;
     109             : 
     110             :     int GetOverviewCount() override;
     111             :     GDALRasterBand *GetOverview(int) override;
     112             : 
     113             :     int GetMaskFlags() override;
     114             :     GDALRasterBand *GetMaskBand() override;
     115             : 
     116             :   private:
     117             :     CPL_DISALLOW_COPY_ASSIGN(GDALOverviewBand)
     118             : };
     119             : 
     120             : /************************************************************************/
     121             : /*                           GetOverviewEx()                            */
     122             : /************************************************************************/
     123             : 
     124        1316 : static GDALRasterBand *GetOverviewEx(GDALRasterBand *poBand, int nLevel)
     125             : {
     126        1316 :     if (nLevel == -1)
     127          64 :         return poBand;
     128        1252 :     return poBand->GetOverview(nLevel);
     129             : }
     130             : 
     131             : /************************************************************************/
     132             : /*                       GDALCreateOverviewDataset()                    */
     133             : /************************************************************************/
     134             : 
     135             : // Takes a reference on poMainDS in case of success.
     136             : // nOvrLevel=-1 means the full resolution dataset (only useful if
     137             : // bThisLevelOnly = false to expose a dataset without its overviews)
     138         193 : GDALDataset *GDALCreateOverviewDataset(GDALDataset *poMainDS, int nOvrLevel,
     139             :                                        bool bThisLevelOnly)
     140             : {
     141             :     // Sanity checks.
     142         193 :     const int nBands = poMainDS->GetRasterCount();
     143         193 :     if (nBands == 0)
     144           0 :         return nullptr;
     145             : 
     146         193 :     auto poFirstBand = GetOverviewEx(poMainDS->GetRasterBand(1), nOvrLevel);
     147         498 :     for (int i = 1; i <= nBands; ++i)
     148             :     {
     149         311 :         auto poBand = GetOverviewEx(poMainDS->GetRasterBand(i), nOvrLevel);
     150         311 :         if (poBand == nullptr)
     151             :         {
     152           6 :             return nullptr;
     153             :         }
     154         610 :         if (poBand->GetXSize() != poFirstBand->GetXSize() ||
     155         305 :             poBand->GetYSize() != poFirstBand->GetYSize())
     156             :         {
     157           0 :             return nullptr;
     158             :         }
     159             :     }
     160             : 
     161         187 :     return new GDALOverviewDataset(poMainDS, nOvrLevel, bThisLevelOnly);
     162             : }
     163             : 
     164             : /************************************************************************/
     165             : /*                        GDALOverviewDataset()                         */
     166             : /************************************************************************/
     167             : 
     168         187 : GDALOverviewDataset::GDALOverviewDataset(GDALDataset *poMainDSIn,
     169         187 :                                          int nOvrLevelIn, bool bThisLevelOnlyIn)
     170             :     : poMainDS(poMainDSIn), nOvrLevel(nOvrLevelIn),
     171         187 :       bThisLevelOnly(bThisLevelOnlyIn)
     172             : {
     173         187 :     poMainDSIn->Reference();
     174         187 :     eAccess = poMainDS->GetAccess();
     175         187 :     auto poFirstBand = GetOverviewEx(poMainDS->GetRasterBand(1), nOvrLevel);
     176         187 :     nRasterXSize = poFirstBand->GetXSize();
     177         187 :     nRasterYSize = poFirstBand->GetYSize();
     178         187 :     poOvrDS = poFirstBand->GetDataset();
     179         187 :     if (nOvrLevel != -1 && poOvrDS != nullptr && poOvrDS == poMainDS)
     180             :     {
     181           0 :         CPLDebug("GDAL", "Dataset of overview is the same as the main band. "
     182             :                          "This is not expected");
     183           0 :         poOvrDS = nullptr;
     184             :     }
     185         187 :     nBands = poMainDS->GetRasterCount();
     186         492 :     for (int i = 0; i < nBands; ++i)
     187             :     {
     188         305 :         if (poOvrDS)
     189             :         {
     190             :             // Check that all overview bands belong to the same dataset
     191             :             auto poOvrBand =
     192         305 :                 GetOverviewEx(poMainDS->GetRasterBand(i + 1), nOvrLevel);
     193         305 :             if (poOvrBand->GetDataset() != poOvrDS)
     194           0 :                 poOvrDS = nullptr;
     195             :         }
     196         305 :         SetBand(i + 1, new GDALOverviewBand(this, i + 1));
     197             :     }
     198             : 
     199         187 :     if (poFirstBand->GetMaskFlags() == GMF_PER_DATASET)
     200             :     {
     201          15 :         auto poOvrMaskBand = poFirstBand->GetMaskBand();
     202          30 :         if (poOvrMaskBand && poOvrMaskBand->GetXSize() == nRasterXSize &&
     203          15 :             poOvrMaskBand->GetYSize() == nRasterYSize)
     204             :         {
     205          15 :             m_poMaskBand = new GDALOverviewBand(this, 0);
     206             :         }
     207             :     }
     208             : 
     209             :     // We create a fake driver that has the same name as the original
     210             :     // one, but we cannot use the real driver object, so that code
     211             :     // doesn't try to cast the GDALOverviewDataset* as a native dataset
     212             :     // object.
     213         187 :     if (poMainDS->GetDriver() != nullptr)
     214             :     {
     215         187 :         poDriver = new GDALDriver();
     216         187 :         poDriver->SetDescription(poMainDS->GetDriver()->GetDescription());
     217         187 :         poDriver->SetMetadata(poMainDS->GetDriver()->GetMetadata());
     218             :     }
     219             : 
     220         187 :     SetDescription(poMainDS->GetDescription());
     221             : 
     222         187 :     CPLDebug("GDAL", "GDALOverviewDataset(%s, this=%p) creation.",
     223         187 :              poMainDS->GetDescription(), this);
     224             : 
     225         187 :     papszOpenOptions = CSLDuplicate(poMainDS->GetOpenOptions());
     226             :     // Add OVERVIEW_LEVEL if not called from GDALOpenEx(), but directly.
     227         187 :     papszOpenOptions = CSLSetNameValue(
     228             :         papszOpenOptions, "OVERVIEW_LEVEL",
     229         187 :         nOvrLevel == -1
     230             :             ? "NONE"
     231         179 :             : CPLSPrintf("%d%s", nOvrLevel, bThisLevelOnly ? " only" : ""));
     232         187 : }
     233             : 
     234             : /************************************************************************/
     235             : /*                       ~GDALOverviewDataset()                         */
     236             : /************************************************************************/
     237             : 
     238         374 : GDALOverviewDataset::~GDALOverviewDataset()
     239             : {
     240         187 :     GDALOverviewDataset::FlushCache(true);
     241             : 
     242         187 :     GDALOverviewDataset::CloseDependentDatasets();
     243             : 
     244         187 :     if (nGCPCount > 0)
     245             :     {
     246           1 :         GDALDeinitGCPs(nGCPCount, pasGCPList);
     247           1 :         CPLFree(pasGCPList);
     248             :     }
     249         187 :     CSLDestroy(papszMD_RPC);
     250             : 
     251         187 :     CSLDestroy(papszMD_GEOLOCATION);
     252             : 
     253         187 :     delete poDriver;
     254         374 : }
     255             : 
     256             : /************************************************************************/
     257             : /*                      CloseDependentDatasets()                        */
     258             : /************************************************************************/
     259             : 
     260         187 : int GDALOverviewDataset::CloseDependentDatasets()
     261             : {
     262         187 :     bool bRet = false;
     263             : 
     264         187 :     if (poMainDS)
     265             :     {
     266         492 :         for (int i = 0; i < nBands; ++i)
     267             :         {
     268             :             GDALOverviewBand *const band =
     269         305 :                 cpl::down_cast<GDALOverviewBand *>(papoBands[i]);
     270         305 :             band->poUnderlyingBand = nullptr;
     271             :         }
     272         187 :         if (poMainDS->ReleaseRef())
     273          39 :             bRet = true;
     274         187 :         poMainDS = nullptr;
     275             :     }
     276             : 
     277         187 :     if (m_poMaskBand)
     278             :     {
     279          15 :         m_poMaskBand->poUnderlyingBand = nullptr;
     280          15 :         delete m_poMaskBand;
     281          15 :         m_poMaskBand = nullptr;
     282             :     }
     283             : 
     284         187 :     return bRet;
     285             : }
     286             : 
     287             : /************************************************************************/
     288             : /*                             IRasterIO()                              */
     289             : /*                                                                      */
     290             : /*      The default implementation of IRasterIO() is to pass the        */
     291             : /*      request off to each band objects rasterio methods with          */
     292             : /*      appropriate arguments.                                          */
     293             : /************************************************************************/
     294             : 
     295        3631 : CPLErr GDALOverviewDataset::IRasterIO(
     296             :     GDALRWFlag eRWFlag, int nXOff, int nYOff, int nXSize, int nYSize,
     297             :     void *pData, int nBufXSize, int nBufYSize, GDALDataType eBufType,
     298             :     int nBandCount, BANDMAP_TYPE panBandMap, GSpacing nPixelSpace,
     299             :     GSpacing nLineSpace, GSpacing nBandSpace, GDALRasterIOExtraArg *psExtraArg)
     300             : 
     301             : {
     302             :     // Try to pass the request to the most appropriate overview dataset.
     303        3631 :     if (nBufXSize < nXSize && nBufYSize < nYSize)
     304             :     {
     305           6 :         int bTried = FALSE;
     306           6 :         const CPLErr eErr = TryOverviewRasterIO(
     307             :             eRWFlag, nXOff, nYOff, nXSize, nYSize, pData, nBufXSize, nBufYSize,
     308             :             eBufType, nBandCount, panBandMap, nPixelSpace, nLineSpace,
     309             :             nBandSpace, psExtraArg, &bTried);
     310           6 :         if (bTried)
     311           2 :             return eErr;
     312             :     }
     313             : 
     314             :     // In case the overview bands are really linked to a dataset, then issue
     315             :     // the request to that dataset.
     316        3629 :     if (poOvrDS != nullptr)
     317             :     {
     318        3629 :         const bool bEnabledOverviews = poOvrDS->AreOverviewsEnabled();
     319        3629 :         poOvrDS->SetEnableOverviews(false);
     320        3629 :         CPLErr eErr = poOvrDS->RasterIO(eRWFlag, nXOff, nYOff, nXSize, nYSize,
     321             :                                         pData, nBufXSize, nBufYSize, eBufType,
     322             :                                         nBandCount, panBandMap, nPixelSpace,
     323             :                                         nLineSpace, nBandSpace, psExtraArg);
     324        3629 :         poOvrDS->SetEnableOverviews(bEnabledOverviews);
     325        3629 :         return eErr;
     326             :     }
     327             : 
     328           0 :     GDALProgressFunc pfnProgressGlobal = psExtraArg->pfnProgress;
     329           0 :     void *pProgressDataGlobal = psExtraArg->pProgressData;
     330           0 :     CPLErr eErr = CE_None;
     331             : 
     332           0 :     for (int iBandIndex = 0; iBandIndex < nBandCount && eErr == CE_None;
     333             :          ++iBandIndex)
     334             :     {
     335           0 :         GDALOverviewBand *poBand = cpl::down_cast<GDALOverviewBand *>(
     336           0 :             GetRasterBand(panBandMap[iBandIndex]));
     337           0 :         GByte *pabyBandData =
     338           0 :             static_cast<GByte *>(pData) + iBandIndex * nBandSpace;
     339             : 
     340           0 :         psExtraArg->pfnProgress = GDALScaledProgress;
     341           0 :         psExtraArg->pProgressData = GDALCreateScaledProgress(
     342           0 :             1.0 * iBandIndex / nBandCount, 1.0 * (iBandIndex + 1) / nBandCount,
     343             :             pfnProgressGlobal, pProgressDataGlobal);
     344             : 
     345           0 :         eErr = poBand->IRasterIO(eRWFlag, nXOff, nYOff, nXSize, nYSize,
     346             :                                  pabyBandData, nBufXSize, nBufYSize, eBufType,
     347             :                                  nPixelSpace, nLineSpace, psExtraArg);
     348             : 
     349           0 :         GDALDestroyScaledProgress(psExtraArg->pProgressData);
     350             :     }
     351             : 
     352           0 :     psExtraArg->pfnProgress = pfnProgressGlobal;
     353           0 :     psExtraArg->pProgressData = pProgressDataGlobal;
     354             : 
     355           0 :     return eErr;
     356             : }
     357             : 
     358             : /************************************************************************/
     359             : /*                           GetSpatialRef()                            */
     360             : /************************************************************************/
     361             : 
     362          82 : const OGRSpatialReference *GDALOverviewDataset::GetSpatialRef() const
     363             : 
     364             : {
     365          82 :     return poMainDS->GetSpatialRef();
     366             : }
     367             : 
     368             : /************************************************************************/
     369             : /*                          GetGeoTransform()                           */
     370             : /************************************************************************/
     371             : 
     372          51 : CPLErr GDALOverviewDataset::GetGeoTransform(GDALGeoTransform &gt) const
     373             : 
     374             : {
     375          51 :     if (poMainDS->GetGeoTransform(gt) != CE_None)
     376           3 :         return CE_Failure;
     377             : 
     378             :     const double dfOvrXRatio =
     379          48 :         static_cast<double>(poMainDS->GetRasterXSize()) / nRasterXSize;
     380             :     const double dfOvrYRatio =
     381          48 :         static_cast<double>(poMainDS->GetRasterYSize()) / nRasterYSize;
     382          48 :     gt.Rescale(dfOvrXRatio, dfOvrYRatio);
     383             : 
     384          48 :     return CE_None;
     385             : }
     386             : 
     387             : /************************************************************************/
     388             : /*                            GetGCPCount()                             */
     389             : /************************************************************************/
     390             : 
     391          17 : int GDALOverviewDataset::GetGCPCount()
     392             : 
     393             : {
     394          17 :     return poMainDS->GetGCPCount();
     395             : }
     396             : 
     397             : /************************************************************************/
     398             : /*                          GetGCPSpatialRef()                          */
     399             : /************************************************************************/
     400             : 
     401           3 : const OGRSpatialReference *GDALOverviewDataset::GetGCPSpatialRef() const
     402             : 
     403             : {
     404           3 :     return poMainDS->GetGCPSpatialRef();
     405             : }
     406             : 
     407             : /************************************************************************/
     408             : /*                               GetGCPs()                              */
     409             : /************************************************************************/
     410             : 
     411           4 : const GDAL_GCP *GDALOverviewDataset::GetGCPs()
     412             : 
     413             : {
     414           4 :     if (pasGCPList != nullptr)
     415           1 :         return pasGCPList;
     416             : 
     417           3 :     const GDAL_GCP *pasGCPsMain = poMainDS->GetGCPs();
     418           3 :     if (pasGCPsMain == nullptr)
     419           2 :         return nullptr;
     420           1 :     nGCPCount = poMainDS->GetGCPCount();
     421             : 
     422           1 :     pasGCPList = GDALDuplicateGCPs(nGCPCount, pasGCPsMain);
     423           4 :     for (int i = 0; i < nGCPCount; ++i)
     424             :     {
     425           3 :         pasGCPList[i].dfGCPPixel *=
     426           3 :             static_cast<double>(nRasterXSize) / poMainDS->GetRasterXSize();
     427           3 :         pasGCPList[i].dfGCPLine *=
     428           3 :             static_cast<double>(nRasterYSize) / poMainDS->GetRasterYSize();
     429             :     }
     430           1 :     return pasGCPList;
     431             : }
     432             : 
     433             : /************************************************************************/
     434             : /*                             Rescale()                                */
     435             : /************************************************************************/
     436             : 
     437             : /* static */
     438          12 : void GDALOverviewDataset::Rescale(char **&papszMD, const char *pszItem,
     439             :                                   double dfRatio, double dfDefaultVal,
     440             :                                   double dfPreShift /*= 0*/,
     441             :                                   double dfPostShift /*= 0*/)
     442             : {
     443          12 :     double dfVal = CPLAtofM(CSLFetchNameValueDef(
     444             :         papszMD, pszItem, CPLSPrintf("%.17g", dfDefaultVal)));
     445          12 :     dfVal += dfPreShift;
     446          12 :     dfVal *= dfRatio;
     447          12 :     dfVal += dfPostShift;
     448          12 :     papszMD = CSLSetNameValue(papszMD, pszItem, CPLSPrintf("%.17g", dfVal));
     449          12 : }
     450             : 
     451             : /************************************************************************/
     452             : /*                            GetMetadata()                             */
     453             : /************************************************************************/
     454             : 
     455         135 : char **GDALOverviewDataset::GetMetadata(const char *pszDomain)
     456             : {
     457         135 :     if (poOvrDS != nullptr)
     458             :     {
     459         135 :         char **papszMD = poOvrDS->GetMetadata(pszDomain);
     460         135 :         if (papszMD != nullptr)
     461           1 :             return papszMD;
     462             :     }
     463             : 
     464         134 :     char **papszMD = poMainDS->GetMetadata(pszDomain);
     465             : 
     466             :     // We may need to rescale some values from the RPC metadata domain.
     467         134 :     if (pszDomain != nullptr && EQUAL(pszDomain, MD_DOMAIN_RPC) &&
     468             :         papszMD != nullptr)
     469             :     {
     470          19 :         if (papszMD_RPC)
     471          17 :             return papszMD_RPC;
     472           2 :         papszMD_RPC = CSLDuplicate(papszMD);
     473             : 
     474             :         const double dfXRatio =
     475           2 :             static_cast<double>(nRasterXSize) / poMainDS->GetRasterXSize();
     476             :         const double dfYRatio =
     477           2 :             static_cast<double>(nRasterYSize) / poMainDS->GetRasterYSize();
     478             : 
     479             :         // For line offset and pixel offset, we need to convert from RPC
     480             :         // pixel center registration convention to GDAL pixel top-left corner
     481             :         // registration convention by adding an initial 0.5 shift, and un-apply
     482             :         // it after scaling.
     483             : 
     484           2 :         Rescale(papszMD_RPC, RPC_LINE_OFF, dfYRatio, 0.0, 0.5, -0.5);
     485           2 :         Rescale(papszMD_RPC, RPC_LINE_SCALE, dfYRatio, 1.0);
     486           2 :         Rescale(papszMD_RPC, RPC_SAMP_OFF, dfXRatio, 0.0, 0.5, -0.5);
     487           2 :         Rescale(papszMD_RPC, RPC_SAMP_SCALE, dfXRatio, 1.0);
     488             : 
     489           2 :         papszMD = papszMD_RPC;
     490             :     }
     491             : 
     492             :     // We may need to rescale some values from the GEOLOCATION metadata domain.
     493         117 :     if (pszDomain != nullptr && EQUAL(pszDomain, "GEOLOCATION") &&
     494             :         papszMD != nullptr)
     495             :     {
     496          13 :         if (papszMD_GEOLOCATION)
     497          12 :             return papszMD_GEOLOCATION;
     498           1 :         papszMD_GEOLOCATION = CSLDuplicate(papszMD);
     499             : 
     500           1 :         Rescale(papszMD_GEOLOCATION, "PIXEL_OFFSET",
     501           1 :                 static_cast<double>(poMainDS->GetRasterXSize()) / nRasterXSize,
     502             :                 0.0);
     503           1 :         Rescale(papszMD_GEOLOCATION, "LINE_OFFSET",
     504           1 :                 static_cast<double>(poMainDS->GetRasterYSize()) / nRasterYSize,
     505             :                 0.0);
     506             : 
     507           1 :         Rescale(papszMD_GEOLOCATION, "PIXEL_STEP",
     508           1 :                 static_cast<double>(nRasterXSize) / poMainDS->GetRasterXSize(),
     509             :                 1.0);
     510           1 :         Rescale(papszMD_GEOLOCATION, "LINE_STEP",
     511           1 :                 static_cast<double>(nRasterYSize) / poMainDS->GetRasterYSize(),
     512             :                 1.0);
     513             : 
     514           1 :         papszMD = papszMD_GEOLOCATION;
     515             :     }
     516             : 
     517         105 :     return papszMD;
     518             : }
     519             : 
     520             : /************************************************************************/
     521             : /*                          GetMetadataItem()                           */
     522             : /************************************************************************/
     523             : 
     524          84 : const char *GDALOverviewDataset::GetMetadataItem(const char *pszName,
     525             :                                                  const char *pszDomain)
     526             : {
     527          84 :     if (poOvrDS != nullptr)
     528             :     {
     529          84 :         const char *pszValue = poOvrDS->GetMetadataItem(pszName, pszDomain);
     530          84 :         if (pszValue != nullptr)
     531          23 :             return pszValue;
     532             :     }
     533             : 
     534          61 :     if (pszDomain != nullptr &&
     535          61 :         (EQUAL(pszDomain, "RPC") || EQUAL(pszDomain, "GEOLOCATION")))
     536             :     {
     537          27 :         char **papszMD = GetMetadata(pszDomain);
     538          27 :         return CSLFetchNameValue(papszMD, pszName);
     539             :     }
     540             : 
     541          34 :     return poMainDS->GetMetadataItem(pszName, pszDomain);
     542             : }
     543             : 
     544             : /************************************************************************/
     545             : /*                          GDALOverviewBand()                          */
     546             : /************************************************************************/
     547             : 
     548         320 : GDALOverviewBand::GDALOverviewBand(GDALOverviewDataset *poDSIn, int nBandIn)
     549             : {
     550         320 :     poDS = poDSIn;
     551         320 :     nBand = nBandIn;
     552         320 :     nRasterXSize = poDSIn->nRasterXSize;
     553         320 :     nRasterYSize = poDSIn->nRasterYSize;
     554         320 :     if (nBandIn == 0)
     555             :     {
     556          15 :         poUnderlyingBand =
     557          15 :             GetOverviewEx(poDSIn->poMainDS->GetRasterBand(1), poDSIn->nOvrLevel)
     558          15 :                 ->GetMaskBand();
     559             :     }
     560             :     else
     561             :     {
     562         305 :         poUnderlyingBand = GetOverviewEx(
     563         305 :             poDSIn->poMainDS->GetRasterBand(nBandIn), poDSIn->nOvrLevel);
     564             :     }
     565         320 :     eDataType = poUnderlyingBand->GetRasterDataType();
     566         320 :     poUnderlyingBand->GetBlockSize(&nBlockXSize, &nBlockYSize);
     567         320 : }
     568             : 
     569             : /************************************************************************/
     570             : /*                         ~GDALOverviewBand()                          */
     571             : /************************************************************************/
     572             : 
     573         640 : GDALOverviewBand::~GDALOverviewBand()
     574             : {
     575         320 :     GDALOverviewBand::FlushCache(true);
     576         640 : }
     577             : 
     578             : /************************************************************************/
     579             : /*                              FlushCache()                            */
     580             : /************************************************************************/
     581             : 
     582         644 : CPLErr GDALOverviewBand::FlushCache(bool bAtClosing)
     583             : {
     584         644 :     if (poUnderlyingBand)
     585         324 :         return poUnderlyingBand->FlushCache(bAtClosing);
     586         320 :     return CE_None;
     587             : }
     588             : 
     589             : /************************************************************************/
     590             : /*                        RefUnderlyingRasterBand()                     */
     591             : /************************************************************************/
     592             : 
     593             : GDALRasterBand *
     594        3064 : GDALOverviewBand::RefUnderlyingRasterBand(bool /*bForceOpen */) const
     595             : {
     596        3064 :     return poUnderlyingBand;
     597             : }
     598             : 
     599             : /************************************************************************/
     600             : /*                         GetOverviewCount()                           */
     601             : /************************************************************************/
     602             : 
     603          38 : int GDALOverviewBand::GetOverviewCount()
     604             : {
     605             :     GDALOverviewDataset *const poOvrDS =
     606          38 :         cpl::down_cast<GDALOverviewDataset *>(poDS);
     607          38 :     if (poOvrDS->bThisLevelOnly)
     608           8 :         return 0;
     609          30 :     GDALDataset *const poMainDS = poOvrDS->poMainDS;
     610          30 :     GDALRasterBand *poMainBand = (nBand == 0)
     611          30 :                                      ? poMainDS->GetRasterBand(1)->GetMaskBand()
     612          28 :                                      : poMainDS->GetRasterBand(nBand);
     613          30 :     return poMainBand->GetOverviewCount() - poOvrDS->nOvrLevel - 1;
     614             :     ;
     615             : }
     616             : 
     617             : /************************************************************************/
     618             : /*                           GetOverview()                              */
     619             : /************************************************************************/
     620             : 
     621          16 : GDALRasterBand *GDALOverviewBand::GetOverview(int iOvr)
     622             : {
     623          16 :     if (iOvr < 0 || iOvr >= GetOverviewCount())
     624           0 :         return nullptr;
     625             :     GDALOverviewDataset *const poOvrDS =
     626          16 :         cpl::down_cast<GDALOverviewDataset *>(poDS);
     627          16 :     GDALDataset *const poMainDS = poOvrDS->poMainDS;
     628          16 :     GDALRasterBand *poMainBand = (nBand == 0)
     629          16 :                                      ? poMainDS->GetRasterBand(1)->GetMaskBand()
     630          15 :                                      : poMainDS->GetRasterBand(nBand);
     631          16 :     return poMainBand->GetOverview(iOvr + poOvrDS->nOvrLevel + 1);
     632             : }
     633             : 
     634             : /************************************************************************/
     635             : /*                           GetMaskFlags()                             */
     636             : /************************************************************************/
     637             : 
     638         135 : int GDALOverviewBand::GetMaskFlags()
     639             : {
     640             :     GDALOverviewDataset *const poOvrDS =
     641         135 :         cpl::down_cast<GDALOverviewDataset *>(poDS);
     642         135 :     if (nBand != 0 && poOvrDS->m_poMaskBand)
     643           1 :         return GMF_PER_DATASET;
     644         134 :     return GDALProxyRasterBand::GetMaskFlags();
     645             : }
     646             : 
     647             : /************************************************************************/
     648             : /*                           GetMaskBand()                              */
     649             : /************************************************************************/
     650             : 
     651           5 : GDALRasterBand *GDALOverviewBand::GetMaskBand()
     652             : {
     653             :     GDALOverviewDataset *const poOvrDS =
     654           5 :         cpl::down_cast<GDALOverviewDataset *>(poDS);
     655           5 :     if (nBand != 0 && poOvrDS->m_poMaskBand)
     656           1 :         return poOvrDS->m_poMaskBand;
     657           4 :     return GDALProxyRasterBand::GetMaskBand();
     658             : }
     659             : 
     660             : /************************************************************************/
     661             : /*                            IRasterIO()                               */
     662             : /************************************************************************/
     663             : 
     664        2150 : CPLErr GDALOverviewBand::IRasterIO(GDALRWFlag eRWFlag, int nXOff, int nYOff,
     665             :                                    int nXSize, int nYSize, void *pData,
     666             :                                    int nBufXSize, int nBufYSize,
     667             :                                    GDALDataType eBufType, GSpacing nPixelSpace,
     668             :                                    GSpacing nLineSpace,
     669             :                                    GDALRasterIOExtraArg *psExtraArg)
     670             : {
     671             :     GDALOverviewDataset *const poOvrDS =
     672        2150 :         cpl::down_cast<GDALOverviewDataset *>(poDS);
     673        2150 :     if (poOvrDS->bThisLevelOnly && poOvrDS->poOvrDS)
     674             :     {
     675         109 :         const bool bEnabledOverviews = poOvrDS->poOvrDS->AreOverviewsEnabled();
     676         109 :         poOvrDS->poOvrDS->SetEnableOverviews(false);
     677         109 :         CPLErr eErr = GDALProxyRasterBand::IRasterIO(
     678             :             eRWFlag, nXOff, nYOff, nXSize, nYSize, pData, nBufXSize, nBufYSize,
     679             :             eBufType, nPixelSpace, nLineSpace, psExtraArg);
     680         109 :         poOvrDS->poOvrDS->SetEnableOverviews(bEnabledOverviews);
     681         109 :         return eErr;
     682             :     }
     683             : 
     684             :     // Try to pass the request to the most appropriate overview.
     685        2041 :     if (nBufXSize < nXSize && nBufYSize < nYSize)
     686             :     {
     687           2 :         int bTried = FALSE;
     688           2 :         const CPLErr eErr = TryOverviewRasterIO(
     689             :             eRWFlag, nXOff, nYOff, nXSize, nYSize, pData, nBufXSize, nBufYSize,
     690             :             eBufType, nPixelSpace, nLineSpace, psExtraArg, &bTried);
     691           2 :         if (bTried)
     692           2 :             return eErr;
     693             :     }
     694             : 
     695        2039 :     return GDALProxyRasterBand::IRasterIO(eRWFlag, nXOff, nYOff, nXSize, nYSize,
     696             :                                           pData, nBufXSize, nBufYSize, eBufType,
     697        2039 :                                           nPixelSpace, nLineSpace, psExtraArg);
     698             : }

Generated by: LCOV version 1.14