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

Generated by: LCOV version 1.14