LCOV - code coverage report
Current view: top level - gcore - gdaldefaultoverviews.cpp (source / functions) Hit Total Coverage
Test: gdal_filtered.info Lines: 622 688 90.4 %
Date: 2025-07-09 17:50:03 Functions: 29 31 93.5 %

          Line data    Source code
       1             : /******************************************************************************
       2             :  *
       3             :  * Project:  GDAL Core
       4             :  * Purpose:  Helper code to implement overview and mask support for many
       5             :  *           drivers with no inherent format support.
       6             :  * Author:   Frank Warmerdam, warmerdam@pobox.com
       7             :  *
       8             :  ******************************************************************************
       9             :  * Copyright (c) 2000, 2007, Frank Warmerdam
      10             :  * Copyright (c) 2007-2013, Even Rouault <even dot rouault at spatialys.com>
      11             :  *
      12             :  * SPDX-License-Identifier: MIT
      13             :  ****************************************************************************/
      14             : 
      15             : #include "cpl_port.h"
      16             : #include "cpl_multiproc.h"
      17             : #include "gdal_priv.h"
      18             : 
      19             : #include <cstdlib>
      20             : #include <cstring>
      21             : 
      22             : #include <algorithm>
      23             : #include <limits>
      24             : #include <set>
      25             : #include <string>
      26             : #include <vector>
      27             : 
      28             : #include "cpl_conv.h"
      29             : #include "cpl_error.h"
      30             : #include "cpl_progress.h"
      31             : #include "cpl_string.h"
      32             : #include "cpl_vsi.h"
      33             : #include "gdal.h"
      34             : 
      35             : //! @cond Doxygen_Suppress
      36             : /************************************************************************/
      37             : /*                        GDALDefaultOverviews()                        */
      38             : /************************************************************************/
      39             : 
      40      147113 : GDALDefaultOverviews::GDALDefaultOverviews()
      41             :     : poDS(nullptr), poODS(nullptr), bOvrIsAux(false), bCheckedForMask(false),
      42             :       bOwnMaskDS(false), poMaskDS(nullptr), poBaseDS(nullptr),
      43             :       bCheckedForOverviews(FALSE), pszInitName(nullptr), bInitNameIsOVR(false),
      44      147113 :       papszInitSiblingFiles(nullptr)
      45             : {
      46      147039 : }
      47             : 
      48             : /************************************************************************/
      49             : /*                       ~GDALDefaultOverviews()                        */
      50             : /************************************************************************/
      51             : 
      52      147117 : GDALDefaultOverviews::~GDALDefaultOverviews()
      53             : 
      54             : {
      55      147132 :     CPLFree(pszInitName);
      56      147129 :     CSLDestroy(papszInitSiblingFiles);
      57             : 
      58      147124 :     CloseDependentDatasets();
      59      147118 : }
      60             : 
      61             : /************************************************************************/
      62             : /*                       CloseDependentDatasets()                       */
      63             : /************************************************************************/
      64             : 
      65      166003 : int GDALDefaultOverviews::CloseDependentDatasets()
      66             : {
      67      166003 :     bool bHasDroppedRef = false;
      68      166003 :     if (poODS != nullptr)
      69             :     {
      70         395 :         bHasDroppedRef = true;
      71         395 :         poODS->FlushCache(true);
      72         395 :         GDALClose(poODS);
      73         389 :         poODS = nullptr;
      74             :     }
      75             : 
      76      165997 :     if (poMaskDS != nullptr)
      77             :     {
      78          55 :         if (bOwnMaskDS)
      79             :         {
      80          51 :             bHasDroppedRef = true;
      81          51 :             poMaskDS->FlushCache(true);
      82          51 :             GDALClose(poMaskDS);
      83             :         }
      84          55 :         poMaskDS = nullptr;
      85             :     }
      86             : 
      87      165997 :     return bHasDroppedRef;
      88             : }
      89             : 
      90             : /************************************************************************/
      91             : /*                           IsInitialized()                            */
      92             : /*                                                                      */
      93             : /*      Returns TRUE if we are initialized.                             */
      94             : /************************************************************************/
      95             : 
      96     1071380 : int GDALDefaultOverviews::IsInitialized()
      97             : 
      98             : {
      99     1071380 :     OverviewScan();
     100     1071380 :     return poDS != nullptr;
     101             : }
     102             : 
     103             : /************************************************************************/
     104             : /*                             Initialize()                             */
     105             : /************************************************************************/
     106             : 
     107       51868 : void GDALDefaultOverviews::Initialize(GDALDataset *poDSIn,
     108             :                                       const char *pszBasename,
     109             :                                       CSLConstList papszSiblingFiles,
     110             :                                       bool bNameIsOVR)
     111             : 
     112             : {
     113       51868 :     poDS = poDSIn;
     114             : 
     115             :     /* -------------------------------------------------------------------- */
     116             :     /*      If we were already initialized, destroy the old overview        */
     117             :     /*      file handle.                                                    */
     118             :     /* -------------------------------------------------------------------- */
     119       51868 :     if (poODS != nullptr)
     120             :     {
     121           0 :         GDALClose(poODS);
     122           0 :         poODS = nullptr;
     123             : 
     124           0 :         CPLDebug("GDAL", "GDALDefaultOverviews::Initialize() called twice - "
     125             :                          "this is odd and perhaps dangerous!");
     126             :     }
     127             : 
     128             :     /* -------------------------------------------------------------------- */
     129             :     /*      Store the initialization information for later use in           */
     130             :     /*      OverviewScan()                                                  */
     131             :     /* -------------------------------------------------------------------- */
     132       51868 :     bCheckedForOverviews = FALSE;
     133             : 
     134       51868 :     CPLFree(pszInitName);
     135       51725 :     pszInitName = nullptr;
     136       51725 :     if (pszBasename != nullptr)
     137       51439 :         pszInitName = CPLStrdup(pszBasename);
     138       51936 :     bInitNameIsOVR = bNameIsOVR;
     139             : 
     140       51936 :     CSLDestroy(papszInitSiblingFiles);
     141       51702 :     papszInitSiblingFiles = nullptr;
     142       51702 :     if (papszSiblingFiles != nullptr)
     143        5683 :         papszInitSiblingFiles = CSLDuplicate(papszSiblingFiles);
     144       51702 : }
     145             : 
     146             : /************************************************************************/
     147             : /*                             Initialize()                             */
     148             : /************************************************************************/
     149             : 
     150             : /** Initialize the GDALDefaultOverviews instance.
     151             :  *
     152             :  * @param poDSIn Base dataset.
     153             :  * @param poOpenInfo Open info instance. Must not be NULL.
     154             :  * @param pszName Base dataset name. If set to NULL, poOpenInfo->pszFilename is
     155             :  *                used.
     156             :  * @param bTransferSiblingFilesIfLoaded Whether sibling files of poOpenInfo
     157             :  *                                      should be transferred to this
     158             :  *                                      GDALDefaultOverviews instance, if they
     159             :  *                                      have bean already loaded.
     160             :  * @since 3.10
     161             :  */
     162       32192 : void GDALDefaultOverviews::Initialize(GDALDataset *poDSIn,
     163             :                                       GDALOpenInfo *poOpenInfo,
     164             :                                       const char *pszName,
     165             :                                       bool bTransferSiblingFilesIfLoaded)
     166             : {
     167       32192 :     Initialize(poDSIn, pszName ? pszName : poOpenInfo->pszFilename);
     168             : 
     169       31932 :     if (bTransferSiblingFilesIfLoaded && poOpenInfo->AreSiblingFilesLoaded())
     170        9141 :         TransferSiblingFiles(poOpenInfo->StealSiblingFiles());
     171       31955 : }
     172             : 
     173             : /************************************************************************/
     174             : /*                         TransferSiblingFiles()                       */
     175             : /*                                                                      */
     176             : /*      Contrary to Initialize(), this sets papszInitSiblingFiles but   */
     177             : /*      without duplicating the passed list. Which must be              */
     178             : /*      "de-allocatable" with CSLDestroy()                              */
     179             : /************************************************************************/
     180             : 
     181       25899 : void GDALDefaultOverviews::TransferSiblingFiles(char **papszSiblingFiles)
     182             : {
     183       25899 :     CSLDestroy(papszInitSiblingFiles);
     184       25896 :     papszInitSiblingFiles = papszSiblingFiles;
     185       25896 : }
     186             : 
     187             : namespace
     188             : {
     189             : // Prevent infinite recursion.
     190             : struct AntiRecursionStructDefaultOvr
     191             : {
     192             :     int nRecLevel = 0;
     193             :     std::set<CPLString> oSetFiles{};
     194             : };
     195             : }  // namespace
     196             : 
     197         337 : static void FreeAntiRecursionDefaultOvr(void *pData)
     198             : {
     199         337 :     delete static_cast<AntiRecursionStructDefaultOvr *>(pData);
     200         337 : }
     201             : 
     202       11649 : static AntiRecursionStructDefaultOvr &GetAntiRecursionDefaultOvr()
     203             : {
     204       11649 :     static AntiRecursionStructDefaultOvr dummy;
     205       11649 :     int bMemoryErrorOccurred = false;
     206             :     void *pData =
     207       11649 :         CPLGetTLSEx(CTLS_GDALDEFAULTOVR_ANTIREC, &bMemoryErrorOccurred);
     208       11649 :     if (bMemoryErrorOccurred)
     209             :     {
     210           0 :         return dummy;
     211             :     }
     212       11649 :     if (pData == nullptr)
     213             :     {
     214         425 :         auto pAntiRecursion = new AntiRecursionStructDefaultOvr();
     215         425 :         CPLSetTLSWithFreeFuncEx(CTLS_GDALDEFAULTOVR_ANTIREC, pAntiRecursion,
     216             :                                 FreeAntiRecursionDefaultOvr,
     217             :                                 &bMemoryErrorOccurred);
     218         425 :         if (bMemoryErrorOccurred)
     219             :         {
     220           0 :             delete pAntiRecursion;
     221           0 :             return dummy;
     222             :         }
     223         425 :         return *pAntiRecursion;
     224             :     }
     225       11224 :     return *static_cast<AntiRecursionStructDefaultOvr *>(pData);
     226             : }
     227             : 
     228             : /************************************************************************/
     229             : /*                            OverviewScan()                            */
     230             : /*                                                                      */
     231             : /*      This is called to scan for overview files when a first          */
     232             : /*      request is made with regard to overviews.  It uses the          */
     233             : /*      pszInitName, bInitNameIsOVR and papszInitSiblingFiles           */
     234             : /*      information that was stored at Initialization() time.           */
     235             : /************************************************************************/
     236             : 
     237     1071380 : void GDALDefaultOverviews::OverviewScan()
     238             : 
     239             : {
     240     1071380 :     if (bCheckedForOverviews || poDS == nullptr)
     241     1059730 :         return;
     242             : 
     243       11649 :     bCheckedForOverviews = true;
     244       11649 :     if (pszInitName == nullptr)
     245          14 :         pszInitName = CPLStrdup(poDS->GetDescription());
     246             : 
     247       11649 :     AntiRecursionStructDefaultOvr &antiRec = GetAntiRecursionDefaultOvr();
     248             :     // 32 should be enough to handle a .ovr.ovr.ovr...
     249       11649 :     if (antiRec.nRecLevel == 32)
     250           0 :         return;
     251       11649 :     if (antiRec.oSetFiles.find(pszInitName) != antiRec.oSetFiles.end())
     252           0 :         return;
     253       11649 :     antiRec.oSetFiles.insert(pszInitName);
     254       11649 :     ++antiRec.nRecLevel;
     255             : 
     256       11649 :     CPLDebug("GDAL", "GDALDefaultOverviews::OverviewScan()");
     257             : 
     258             :     /* -------------------------------------------------------------------- */
     259             :     /*      Open overview dataset if it exists.                             */
     260             :     /* -------------------------------------------------------------------- */
     261       23118 :     if (!EQUAL(pszInitName, ":::VIRTUAL:::") &&
     262       11469 :         GDALCanFileAcceptSidecarFile(pszInitName))
     263             :     {
     264       11467 :         if (bInitNameIsOVR)
     265           0 :             osOvrFilename = pszInitName;
     266             :         else
     267       11467 :             osOvrFilename.Printf("%s.ovr", pszInitName);
     268             : 
     269       22934 :         std::vector<char> achOvrFilename;
     270       11467 :         achOvrFilename.resize(osOvrFilename.size() + 1);
     271       11467 :         memcpy(&(achOvrFilename[0]), osOvrFilename.c_str(),
     272       11467 :                osOvrFilename.size() + 1);
     273       11467 :         bool bExists = CPL_TO_BOOL(
     274       11467 :             CPLCheckForFile(&achOvrFilename[0], papszInitSiblingFiles));
     275       11467 :         osOvrFilename = &achOvrFilename[0];
     276             : 
     277             : #if !defined(_WIN32)
     278       11467 :         if (!bInitNameIsOVR && !bExists && !papszInitSiblingFiles)
     279             :         {
     280        2902 :             osOvrFilename.Printf("%s.OVR", pszInitName);
     281        2902 :             memcpy(&(achOvrFilename[0]), osOvrFilename.c_str(),
     282        2902 :                    osOvrFilename.size() + 1);
     283        2902 :             bExists = CPL_TO_BOOL(
     284        2902 :                 CPLCheckForFile(&achOvrFilename[0], papszInitSiblingFiles));
     285        2902 :             osOvrFilename = &achOvrFilename[0];
     286        2902 :             if (!bExists)
     287        2902 :                 osOvrFilename.Printf("%s.ovr", pszInitName);
     288             :         }
     289             : #endif
     290             : 
     291       11467 :         if (bExists)
     292             :         {
     293         201 :             poODS = GDALDataset::Open(
     294             :                 osOvrFilename,
     295             :                 GDAL_OF_RASTER |
     296         201 :                     (poDS->GetAccess() == GA_Update ? GDAL_OF_UPDATE : 0),
     297         201 :                 nullptr, nullptr, papszInitSiblingFiles);
     298             :         }
     299             :     }
     300             : 
     301             :     /* -------------------------------------------------------------------- */
     302             :     /*      We didn't find that, so try and find a corresponding aux        */
     303             :     /*      file.  Check that we are the dependent file of the aux          */
     304             :     /*      file.                                                           */
     305             :     /*                                                                      */
     306             :     /*      We only use the .aux file for overviews if they already have    */
     307             :     /*      overviews existing, or if USE_RRD is set true.                  */
     308             :     /* -------------------------------------------------------------------- */
     309       22918 :     if (!poODS && !EQUAL(pszInitName, ":::VIRTUAL:::") &&
     310       11269 :         GDALCanFileAcceptSidecarFile(pszInitName))
     311             :     {
     312       11267 :         bool bTryFindAssociatedAuxFile = true;
     313       11267 :         if (papszInitSiblingFiles)
     314             :         {
     315       16730 :             CPLString osAuxFilename = CPLResetExtensionSafe(pszInitName, "aux");
     316        8365 :             int iSibling = CSLFindString(papszInitSiblingFiles,
     317             :                                          CPLGetFilename(osAuxFilename));
     318        8365 :             if (iSibling < 0)
     319             :             {
     320        8361 :                 osAuxFilename = pszInitName;
     321        8361 :                 osAuxFilename += ".aux";
     322        8361 :                 iSibling = CSLFindString(papszInitSiblingFiles,
     323             :                                          CPLGetFilename(osAuxFilename));
     324        8361 :                 if (iSibling < 0)
     325        8361 :                     bTryFindAssociatedAuxFile = false;
     326             :             }
     327             :         }
     328             : 
     329       11267 :         if (bTryFindAssociatedAuxFile)
     330             :         {
     331        2906 :             poODS =
     332        2906 :                 GDALFindAssociatedAuxFile(pszInitName, poDS->GetAccess(), poDS);
     333             :         }
     334             : 
     335       11267 :         if (poODS)
     336             :         {
     337             :             const bool bUseRRD =
     338           7 :                 CPLTestBool(CPLGetConfigOption("USE_RRD", "NO"));
     339             : 
     340           7 :             bOvrIsAux = true;
     341           7 :             if (GetOverviewCount(1) == 0 && !bUseRRD)
     342             :             {
     343           1 :                 bOvrIsAux = false;
     344           1 :                 GDALClose(poODS);
     345           1 :                 poODS = nullptr;
     346             :             }
     347             :             else
     348             :             {
     349           6 :                 osOvrFilename = poODS->GetDescription();
     350             :             }
     351             :         }
     352             :     }
     353             : 
     354             :     /* -------------------------------------------------------------------- */
     355             :     /*      If we still don't have an overview, check to see if we have     */
     356             :     /*      overview metadata referencing a remote (i.e. proxy) or local    */
     357             :     /*      subdataset overview dataset.                                    */
     358             :     /* -------------------------------------------------------------------- */
     359       11649 :     if (poODS == nullptr)
     360             :     {
     361             :         const char *pszProxyOvrFilename =
     362       11443 :             poDS->GetMetadataItem("OVERVIEW_FILE", "OVERVIEWS");
     363             : 
     364       11443 :         if (pszProxyOvrFilename != nullptr)
     365             :         {
     366          33 :             if (STARTS_WITH_CI(pszProxyOvrFilename, ":::BASE:::"))
     367             :             {
     368           0 :                 const CPLString osPath = CPLGetPathSafe(poDS->GetDescription());
     369             : 
     370           0 :                 osOvrFilename = CPLFormFilenameSafe(
     371           0 :                     osPath, pszProxyOvrFilename + 10, nullptr);
     372             :             }
     373             :             else
     374             :             {
     375          33 :                 osOvrFilename = pszProxyOvrFilename;
     376             :             }
     377             : 
     378          33 :             CPLPushErrorHandler(CPLQuietErrorHandler);
     379          33 :             poODS = GDALDataset::Open(
     380             :                 osOvrFilename,
     381             :                 GDAL_OF_RASTER |
     382          33 :                     (poDS->GetAccess() == GA_Update ? GDAL_OF_UPDATE : 0));
     383          33 :             CPLPopErrorHandler();
     384             :         }
     385             :     }
     386             : 
     387             :     /* -------------------------------------------------------------------- */
     388             :     /*      If we have an overview dataset, then mark all the overviews     */
     389             :     /*      with the base dataset  Used later for finding overviews         */
     390             :     /*      masks.  Uggg.                                                   */
     391             :     /* -------------------------------------------------------------------- */
     392       11649 :     if (poODS)
     393             :     {
     394         224 :         const int nOverviewCount = GetOverviewCount(1);
     395             : 
     396         534 :         for (int iOver = 0; iOver < nOverviewCount; iOver++)
     397             :         {
     398         310 :             GDALRasterBand *const poBand = GetOverview(1, iOver);
     399             :             GDALDataset *const poOverDS =
     400         310 :                 poBand != nullptr ? poBand->GetDataset() : nullptr;
     401             : 
     402         310 :             if (poOverDS != nullptr)
     403             :             {
     404         299 :                 poOverDS->oOvManager.poBaseDS = poDS;
     405         299 :                 poOverDS->oOvManager.poDS = poOverDS;
     406             :             }
     407             :         }
     408             :     }
     409             : 
     410             :     // Undo anti recursion protection
     411       11649 :     antiRec.oSetFiles.erase(pszInitName);
     412       11649 :     --antiRec.nRecLevel;
     413             : }
     414             : 
     415             : /************************************************************************/
     416             : /*                          GetOverviewCount()                          */
     417             : /************************************************************************/
     418             : 
     419      656836 : int GDALDefaultOverviews::GetOverviewCount(int nBand)
     420             : 
     421             : {
     422      656836 :     if (poODS == nullptr || nBand < 1 || nBand > poODS->GetRasterCount())
     423      655798 :         return 0;
     424             : 
     425        1038 :     GDALRasterBand *poBand = poODS->GetRasterBand(nBand);
     426        1038 :     if (poBand == nullptr)
     427           0 :         return 0;
     428             : 
     429        1038 :     if (bOvrIsAux)
     430          72 :         return poBand->GetOverviewCount();
     431             : 
     432         966 :     return poBand->GetOverviewCount() + 1;
     433             : }
     434             : 
     435             : /************************************************************************/
     436             : /*                            GetOverview()                             */
     437             : /************************************************************************/
     438             : 
     439        1370 : GDALRasterBand *GDALDefaultOverviews::GetOverview(int nBand, int iOverview)
     440             : 
     441             : {
     442        1370 :     if (poODS == nullptr || nBand < 1 || nBand > poODS->GetRasterCount())
     443         261 :         return nullptr;
     444             : 
     445        1109 :     GDALRasterBand *const poBand = poODS->GetRasterBand(nBand);
     446        1109 :     if (poBand == nullptr)
     447           0 :         return nullptr;
     448             : 
     449        1109 :     if (bOvrIsAux)
     450          60 :         return poBand->GetOverview(iOverview);
     451             : 
     452             :     // TIFF case, base is overview 0.
     453        1049 :     if (iOverview == 0)
     454         798 :         return poBand;
     455             : 
     456         251 :     if (iOverview - 1 >= poBand->GetOverviewCount())
     457           0 :         return nullptr;
     458             : 
     459         251 :     return poBand->GetOverview(iOverview - 1);
     460             : }
     461             : 
     462             : /************************************************************************/
     463             : /*                         GDALOvLevelAdjust()                          */
     464             : /*                                                                      */
     465             : /*      Some overview levels cannot be achieved closely enough to be    */
     466             : /*      recognised as the desired overview level.  This function        */
     467             : /*      will adjust an overview level to one that is achievable on      */
     468             : /*      the given raster size.                                          */
     469             : /*                                                                      */
     470             : /*      For instance a 1200x1200 image on which a 256 level overview    */
     471             : /*      is request will end up generating a 5x5 overview.  However,     */
     472             : /*      this will appear to the system be a level 240 overview.         */
     473             : /*      This function will adjust 256 to 240 based on knowledge of      */
     474             : /*      the image size.                                                 */
     475             : /************************************************************************/
     476             : 
     477           0 : int GDALOvLevelAdjust(int nOvLevel, int nXSize)
     478             : 
     479             : {
     480           0 :     int nOXSize = DIV_ROUND_UP(nXSize, nOvLevel);
     481             : 
     482           0 :     return static_cast<int>(0.5 + nXSize / static_cast<double>(nOXSize));
     483             : }
     484             : 
     485         472 : int GDALOvLevelAdjust2(int nOvLevel, int nXSize, int nYSize)
     486             : 
     487             : {
     488             :     // Select the larger dimension to have increased accuracy, but
     489             :     // with a slight preference to x even if (a bit) smaller than y
     490             :     // in an attempt to behave closer as previous behavior.
     491         472 :     if (nXSize >= nYSize / 2 && !(nXSize < nYSize && nXSize < nOvLevel))
     492             :     {
     493         397 :         const int nOXSize = DIV_ROUND_UP(nXSize, nOvLevel);
     494             : 
     495         397 :         return static_cast<int>(0.5 + nXSize / static_cast<double>(nOXSize));
     496             :     }
     497             : 
     498          75 :     const int nOYSize = DIV_ROUND_UP(nYSize, nOvLevel);
     499             : 
     500          75 :     return static_cast<int>(0.5 + nYSize / static_cast<double>(nOYSize));
     501             : }
     502             : 
     503             : /************************************************************************/
     504             : /*                         GetFloorPowerOfTwo()                         */
     505             : /************************************************************************/
     506             : 
     507       67446 : static int GetFloorPowerOfTwo(int n)
     508             : {
     509       67446 :     int p2 = 1;
     510      136081 :     while ((n = n >> 1) > 0)
     511             :     {
     512       68635 :         p2 <<= 1;
     513             :     }
     514       67446 :     return p2;
     515             : }
     516             : 
     517             : /************************************************************************/
     518             : /*                         GDALComputeOvFactor()                        */
     519             : /************************************************************************/
     520             : 
     521       67446 : int GDALComputeOvFactor(int nOvrXSize, int nRasterXSize, int nOvrYSize,
     522             :                         int nRasterYSize)
     523             : {
     524             :     // Select the larger dimension to have increased accuracy, but
     525             :     // with a slight preference to x even if (a bit) smaller than y
     526             :     // in an attempt to behave closer as previous behavior.
     527       67446 :     if (nRasterXSize != 1 && nRasterXSize >= nRasterYSize / 2)
     528             :     {
     529       67332 :         const int nVal = static_cast<int>(
     530       67332 :             0.5 + nRasterXSize / static_cast<double>(nOvrXSize));
     531             :         // Try to return a power-of-two value
     532       67332 :         const int nValPowerOfTwo = GetFloorPowerOfTwo(nVal);
     533       67520 :         for (int fact = 1; fact <= 2 && nValPowerOfTwo <= INT_MAX / fact;
     534             :              ++fact)
     535             :         {
     536       67487 :             if (DIV_ROUND_UP(nRasterXSize, fact * nValPowerOfTwo) == nOvrXSize)
     537       67299 :                 return fact * nValPowerOfTwo;
     538             :         }
     539          33 :         return nVal;
     540             :     }
     541             : 
     542         114 :     const int nVal =
     543         114 :         static_cast<int>(0.5 + nRasterYSize / static_cast<double>(nOvrYSize));
     544             :     // Try to return a power-of-two value
     545         114 :     const int nValPowerOfTwo = GetFloorPowerOfTwo(nVal);
     546         116 :     for (int fact = 1; fact <= 2 && nValPowerOfTwo <= INT_MAX / fact; ++fact)
     547             :     {
     548         115 :         if (DIV_ROUND_UP(nRasterYSize, fact * nValPowerOfTwo) == nOvrYSize)
     549         113 :             return fact * nValPowerOfTwo;
     550             :     }
     551           1 :     return nVal;
     552             : }
     553             : 
     554             : /************************************************************************/
     555             : /*                           CleanOverviews()                           */
     556             : /*                                                                      */
     557             : /*      Remove all existing overviews.                                  */
     558             : /************************************************************************/
     559             : 
     560          10 : CPLErr GDALDefaultOverviews::CleanOverviews()
     561             : 
     562             : {
     563             :     // Anything to do?
     564          10 :     if (poODS == nullptr)
     565           1 :         return CE_None;
     566             : 
     567             :     // Delete the overview file(s).
     568           9 :     GDALDriver *poOvrDriver = poODS->GetDriver();
     569           9 :     GDALClose(poODS);
     570           9 :     poODS = nullptr;
     571             : 
     572             :     CPLErr eErr =
     573           9 :         poOvrDriver != nullptr ? poOvrDriver->Delete(osOvrFilename) : CE_None;
     574             : 
     575             :     // Reset the saved overview filename.
     576           9 :     if (!EQUAL(poDS->GetDescription(), ":::VIRTUAL:::"))
     577             :     {
     578           9 :         const bool bUseRRD = CPLTestBool(CPLGetConfigOption("USE_RRD", "NO"));
     579             : 
     580           9 :         if (bUseRRD)
     581             :             osOvrFilename =
     582           0 :                 CPLResetExtensionSafe(poDS->GetDescription(), "aux");
     583             :         else
     584           9 :             osOvrFilename = std::string(poDS->GetDescription()).append(".ovr");
     585             :     }
     586             :     else
     587             :     {
     588           0 :         osOvrFilename = "";
     589             :     }
     590             : 
     591           9 :     if (HaveMaskFile() && poMaskDS)
     592             :     {
     593           1 :         const CPLErr eErr2 = poMaskDS->BuildOverviews(
     594             :             nullptr, 0, nullptr, 0, nullptr, nullptr, nullptr, nullptr);
     595           1 :         if (eErr2 != CE_None)
     596           0 :             return eErr2;
     597             :     }
     598             : 
     599           9 :     return eErr;
     600             : }
     601             : 
     602             : /************************************************************************/
     603             : /*                      BuildOverviewsSubDataset()                      */
     604             : /************************************************************************/
     605             : 
     606           9 : CPLErr GDALDefaultOverviews::BuildOverviewsSubDataset(
     607             :     const char *pszPhysicalFile, const char *pszResampling, int nOverviews,
     608             :     const int *panOverviewList, int nBands, const int *panBandList,
     609             :     GDALProgressFunc pfnProgress, void *pProgressData,
     610             :     CSLConstList papszOptions)
     611             : 
     612             : {
     613           9 :     if (osOvrFilename.length() == 0 && nOverviews > 0)
     614             :     {
     615             :         VSIStatBufL sStatBuf;
     616             : 
     617           6 :         int iSequence = 0;  // Used after for.
     618           6 :         for (iSequence = 0; iSequence < 100; iSequence++)
     619             :         {
     620           6 :             osOvrFilename.Printf("%s_%d.ovr", pszPhysicalFile, iSequence);
     621           6 :             if (VSIStatExL(osOvrFilename, &sStatBuf, VSI_STAT_EXISTS_FLAG) != 0)
     622             :             {
     623          12 :                 CPLString osAdjustedOvrFilename;
     624             : 
     625           6 :                 if (poDS->GetMOFlags() & GMO_PAM_CLASS)
     626             :                 {
     627             :                     osAdjustedOvrFilename.Printf(
     628             :                         ":::BASE:::%s_%d.ovr", CPLGetFilename(pszPhysicalFile),
     629           6 :                         iSequence);
     630             :                 }
     631             :                 else
     632             :                 {
     633           0 :                     osAdjustedOvrFilename = osOvrFilename;
     634             :                 }
     635             : 
     636           6 :                 poDS->SetMetadataItem("OVERVIEW_FILE", osAdjustedOvrFilename,
     637           6 :                                       "OVERVIEWS");
     638           6 :                 break;
     639             :             }
     640             :         }
     641             : 
     642           6 :         if (iSequence == 100)
     643           0 :             osOvrFilename = "";
     644             :     }
     645             : 
     646           9 :     return BuildOverviews(nullptr, pszResampling, nOverviews, panOverviewList,
     647             :                           nBands, panBandList, pfnProgress, pProgressData,
     648           9 :                           papszOptions);
     649             : }
     650             : 
     651             : /************************************************************************/
     652             : /*                           GetOptionValue()                           */
     653             : /************************************************************************/
     654             : 
     655         192 : static const char *GetOptionValue(CSLConstList papszOptions,
     656             :                                   const char *pszOptionKey,
     657             :                                   const char *pszConfigOptionKey)
     658             : {
     659             :     const char *pszVal =
     660         192 :         pszOptionKey ? CSLFetchNameValue(papszOptions, pszOptionKey) : nullptr;
     661         192 :     if (pszVal)
     662             :     {
     663           0 :         return pszVal;
     664             :     }
     665         192 :     pszVal = CSLFetchNameValue(papszOptions, pszConfigOptionKey);
     666         192 :     if (pszVal)
     667             :     {
     668           2 :         return pszVal;
     669             :     }
     670         190 :     pszVal = CPLGetConfigOption(pszConfigOptionKey, nullptr);
     671         190 :     return pszVal;
     672             : }
     673             : 
     674             : /************************************************************************/
     675             : /*                CheckSrcOverviewsConsistencyWithBase()                */
     676             : /************************************************************************/
     677             : 
     678          13 : /*static */ bool GDALDefaultOverviews::CheckSrcOverviewsConsistencyWithBase(
     679             :     GDALDataset *poFullResDS, const std::vector<GDALDataset *> &apoSrcOvrDS)
     680             : {
     681          13 :     const auto poThisCRS = poFullResDS->GetSpatialRef();
     682          13 :     GDALGeoTransform thisGT;
     683          13 :     const bool bThisHasGT = poFullResDS->GetGeoTransform(thisGT) == CE_None;
     684          21 :     for (auto *poSrcOvrDS : apoSrcOvrDS)
     685             :     {
     686          25 :         if (poSrcOvrDS->GetRasterXSize() > poFullResDS->GetRasterXSize() ||
     687          12 :             poSrcOvrDS->GetRasterYSize() > poFullResDS->GetRasterYSize())
     688             :         {
     689           1 :             CPLError(
     690             :                 CE_Failure, CPLE_AppDefined,
     691             :                 "AddOverviews(): at least one input dataset has dimensions "
     692             :                 "larger than the full resolution dataset.");
     693           5 :             return false;
     694             :         }
     695          23 :         if (poSrcOvrDS->GetRasterXSize() == 0 ||
     696          11 :             poSrcOvrDS->GetRasterYSize() == 0)
     697             :         {
     698           1 :             CPLError(
     699             :                 CE_Failure, CPLE_AppDefined,
     700             :                 "AddOverviews(): at least one input dataset has one of its "
     701             :                 "dimensions equal to 0.");
     702           1 :             return false;
     703             :         }
     704          11 :         if (poSrcOvrDS->GetRasterCount() != poFullResDS->GetRasterCount())
     705             :         {
     706           1 :             CPLError(CE_Failure, CPLE_AppDefined,
     707             :                      "AddOverviews(): at least one input dataset not the same "
     708             :                      "number of bands than the full resolution dataset.");
     709           1 :             return false;
     710             :         }
     711          10 :         if (poThisCRS)
     712             :         {
     713           9 :             if (const auto poOvrCRS = poSrcOvrDS->GetSpatialRef())
     714             :             {
     715           9 :                 if (!poOvrCRS->IsSame(poThisCRS))
     716             :                 {
     717           1 :                     CPLError(CE_Failure, CPLE_AppDefined,
     718             :                              "AddOverviews(): at least one input dataset has "
     719             :                              "its CRS "
     720             :                              "different from the one of the full resolution "
     721             :                              "dataset.");
     722           1 :                     return false;
     723             :                 }
     724             :             }
     725             :         }
     726           9 :         if (bThisHasGT)
     727             :         {
     728           9 :             GDALGeoTransform ovrGT;
     729             :             const bool bOvrHasGT =
     730           9 :                 poSrcOvrDS->GetGeoTransform(ovrGT) == CE_None;
     731             :             const double dfOvrXRatio =
     732           9 :                 static_cast<double>(poFullResDS->GetRasterXSize()) /
     733           9 :                 poSrcOvrDS->GetRasterXSize();
     734             :             const double dfOvrYRatio =
     735           9 :                 static_cast<double>(poFullResDS->GetRasterYSize()) /
     736           9 :                 poSrcOvrDS->GetRasterYSize();
     737          18 :             if (bOvrHasGT && !(std::fabs(thisGT[0] - ovrGT[0]) <=
     738           9 :                                    0.5 * std::fabs(ovrGT[1]) &&
     739           9 :                                std::fabs(thisGT[1] - ovrGT[1] / dfOvrXRatio) <=
     740           9 :                                    0.1 * std::fabs(ovrGT[1]) &&
     741           8 :                                std::fabs(thisGT[2] - ovrGT[2] / dfOvrYRatio) <=
     742           8 :                                    0.1 * std::fabs(ovrGT[2]) &&
     743           8 :                                std::fabs(thisGT[3] - ovrGT[3]) <=
     744           8 :                                    0.5 * std::fabs(ovrGT[5]) &&
     745           8 :                                std::fabs(thisGT[4] - ovrGT[4] / dfOvrXRatio) <=
     746           8 :                                    0.1 * std::fabs(ovrGT[4]) &&
     747           8 :                                std::fabs(thisGT[5] - ovrGT[5] / dfOvrYRatio) <=
     748           8 :                                    0.1 * std::fabs(ovrGT[5])))
     749             :             {
     750           1 :                 CPLError(
     751             :                     CE_Failure, CPLE_AppDefined,
     752             :                     "AddOverviews(): at least one input dataset has its "
     753             :                     "geospatial extent "
     754             :                     "different from the one of the full resolution dataset.");
     755           1 :                 return false;
     756             :             }
     757             :         }
     758             :     }
     759           8 :     return true;
     760             : }
     761             : 
     762             : /************************************************************************/
     763             : /*                           AddOverviews()                             */
     764             : /************************************************************************/
     765             : 
     766           4 : CPLErr GDALDefaultOverviews::AddOverviews(
     767             :     [[maybe_unused]] const char *pszBasename,
     768             :     [[maybe_unused]] const std::vector<GDALDataset *> &apoSrcOvrDSIn,
     769             :     [[maybe_unused]] GDALProgressFunc pfnProgress,
     770             :     [[maybe_unused]] void *pProgressData,
     771             :     [[maybe_unused]] CSLConstList papszOptions)
     772             : {
     773             : #ifdef HAVE_TIFF
     774           4 :     if (pfnProgress == nullptr)
     775           2 :         pfnProgress = GDALDummyProgress;
     776             : 
     777           4 :     if (CreateOrOpenOverviewFile(pszBasename, papszOptions) != CE_None)
     778           0 :         return CE_Failure;
     779             : 
     780           4 :     if (bOvrIsAux)
     781             :     {
     782           0 :         CPLError(CE_Failure, CPLE_NotSupported,
     783             :                  "AddOverviews() not supported for .aux overviews");
     784           0 :         return CE_Failure;
     785             :     }
     786             : 
     787           4 :     if (!GDALDefaultOverviews::CheckSrcOverviewsConsistencyWithBase(
     788             :             poDS, apoSrcOvrDSIn))
     789           0 :         return CE_Failure;
     790             : 
     791           8 :     std::vector<GDALDataset *> apoSrcOvrDS = apoSrcOvrDSIn;
     792             :     // Sort overviews by descending size
     793           4 :     std::sort(apoSrcOvrDS.begin(), apoSrcOvrDS.end(),
     794           0 :               [](const GDALDataset *poDS1, const GDALDataset *poDS2)
     795           0 :               { return poDS1->GetRasterXSize() > poDS2->GetRasterXSize(); });
     796             : 
     797           4 :     auto poBand = poDS->GetRasterBand(1);
     798           4 :     if (!poBand)
     799           0 :         return CE_Failure;
     800             : 
     801             :     // Determine which overview levels must be created
     802           4 :     std::vector<std::pair<int, int>> anOverviewSizes;
     803           8 :     for (auto *poSrcOvrDS : apoSrcOvrDS)
     804             :     {
     805           4 :         bool bFound = false;
     806           4 :         for (int j = 0; j < poBand->GetOverviewCount(); j++)
     807             :         {
     808           2 :             GDALRasterBand *poOverview = poBand->GetOverview(j);
     809           2 :             if (poOverview && poOverview->GetDataset() &&
     810           2 :                 poOverview->GetDataset() != poDS &&
     811           6 :                 poOverview->GetXSize() == poSrcOvrDS->GetRasterXSize() &&
     812           2 :                 poOverview->GetYSize() == poSrcOvrDS->GetRasterYSize())
     813             :             {
     814           2 :                 bFound = true;
     815           2 :                 break;
     816             :             }
     817             :         }
     818           4 :         if (!bFound)
     819             :         {
     820           0 :             anOverviewSizes.emplace_back(poSrcOvrDS->GetRasterXSize(),
     821           2 :                                          poSrcOvrDS->GetRasterYSize());
     822             :         }
     823             :     }
     824             : 
     825           4 :     CPLErr eErr = CE_None;
     826             : 
     827           4 :     if (!anOverviewSizes.empty())
     828             :     {
     829           2 :         if (poODS != nullptr)
     830             :         {
     831           0 :             delete poODS;
     832           0 :             poODS = nullptr;
     833             :         }
     834             : 
     835           2 :         const int nBands = poDS->GetRasterCount();
     836           4 :         std::vector<GDALRasterBand *> apoBands;
     837           4 :         for (int i = 0; i < nBands; ++i)
     838           2 :             apoBands.push_back(poDS->GetRasterBand(i + 1));
     839             : 
     840           2 :         eErr = GTIFFBuildOverviewsEx(osOvrFilename, nBands, apoBands.data(),
     841           2 :                                      static_cast<int>(apoSrcOvrDS.size()),
     842           2 :                                      nullptr, anOverviewSizes.data(), "NONE",
     843             :                                      nullptr, GDALDummyProgress, nullptr);
     844             : 
     845             :         // Probe for proxy overview filename.
     846           2 :         if (eErr == CE_Failure)
     847             :         {
     848             :             const char *pszProxyOvrFilename =
     849           0 :                 poDS->GetMetadataItem("FILENAME", "ProxyOverviewRequest");
     850             : 
     851           0 :             if (pszProxyOvrFilename != nullptr)
     852             :             {
     853           0 :                 osOvrFilename = pszProxyOvrFilename;
     854           0 :                 eErr = GTIFFBuildOverviewsEx(
     855           0 :                     osOvrFilename, nBands, apoBands.data(),
     856           0 :                     static_cast<int>(apoSrcOvrDS.size()), nullptr,
     857           0 :                     anOverviewSizes.data(), "NONE", nullptr, GDALDummyProgress,
     858             :                     nullptr);
     859             :             }
     860             :         }
     861             : 
     862           2 :         if (eErr == CE_None)
     863             :         {
     864           2 :             poODS = GDALDataset::Open(osOvrFilename,
     865             :                                       GDAL_OF_RASTER | GDAL_OF_UPDATE);
     866           2 :             if (poODS == nullptr)
     867           0 :                 eErr = CE_Failure;
     868             :         }
     869             :     }
     870             : 
     871             :     // almost 0, but not 0 to please Coverity Scan
     872           4 :     double dfTotalPixels = std::numeric_limits<double>::min();
     873           8 :     for (const auto *poSrcOvrDS : apoSrcOvrDS)
     874             :     {
     875           4 :         dfTotalPixels += static_cast<double>(poSrcOvrDS->GetRasterXSize()) *
     876           4 :                          poSrcOvrDS->GetRasterYSize();
     877             :     }
     878             : 
     879             :     // Copy source datasets into target overview datasets
     880           4 :     double dfCurPixels = 0;
     881           8 :     for (auto *poSrcOvrDS : apoSrcOvrDS)
     882             :     {
     883           4 :         GDALDataset *poDstOvrDS = nullptr;
     884           4 :         for (int j = 0; eErr == CE_None && j < poBand->GetOverviewCount(); j++)
     885             :         {
     886           4 :             GDALRasterBand *poOverview = poBand->GetOverview(j);
     887           8 :             if (poOverview &&
     888           8 :                 poOverview->GetXSize() == poSrcOvrDS->GetRasterXSize() &&
     889           4 :                 poOverview->GetYSize() == poSrcOvrDS->GetRasterYSize())
     890             :             {
     891           4 :                 poDstOvrDS = poOverview->GetDataset();
     892           4 :                 break;
     893             :             }
     894             :         }
     895           4 :         if (poDstOvrDS)
     896             :         {
     897             :             const double dfThisPixels =
     898           4 :                 static_cast<double>(poSrcOvrDS->GetRasterXSize()) *
     899           4 :                 poSrcOvrDS->GetRasterYSize();
     900           8 :             void *pScaledProgressData = GDALCreateScaledProgress(
     901             :                 dfCurPixels / dfTotalPixels,
     902           4 :                 (dfCurPixels + dfThisPixels) / dfTotalPixels, pfnProgress,
     903             :                 pProgressData);
     904           4 :             dfCurPixels += dfThisPixels;
     905           4 :             eErr = GDALDatasetCopyWholeRaster(GDALDataset::ToHandle(poSrcOvrDS),
     906             :                                               GDALDataset::ToHandle(poDstOvrDS),
     907             :                                               nullptr, GDALScaledProgress,
     908             :                                               pScaledProgressData);
     909           4 :             GDALDestroyScaledProgress(pScaledProgressData);
     910             :         }
     911             :     }
     912             : 
     913           4 :     return eErr;
     914             : #else
     915             :     CPLError(CE_Failure, CPLE_NotSupported,
     916             :              "AddOverviews() not supported due to GeoTIFF driver missing");
     917             :     return CE_Failure;
     918             : #endif
     919             : }
     920             : 
     921             : /************************************************************************/
     922             : /*                      CreateOrOpenOverviewFile()                      */
     923             : /************************************************************************/
     924             : 
     925         199 : CPLErr GDALDefaultOverviews::CreateOrOpenOverviewFile(const char *pszBasename,
     926             :                                                       CSLConstList papszOptions)
     927             : {
     928             : 
     929             :     /* -------------------------------------------------------------------- */
     930             :     /*      If we don't already have an overview file, we need to decide    */
     931             :     /*      what format to use.                                             */
     932             :     /* -------------------------------------------------------------------- */
     933         199 :     if (poODS == nullptr)
     934             :     {
     935             :         const char *pszUseRRD =
     936         184 :             GetOptionValue(papszOptions, nullptr, "USE_RRD");
     937         184 :         bOvrIsAux = pszUseRRD && CPLTestBool(pszUseRRD);
     938         184 :         if (bOvrIsAux)
     939             :         {
     940             :             osOvrFilename =
     941           4 :                 CPLResetExtensionSafe(poDS->GetDescription(), "aux");
     942             : 
     943             :             VSIStatBufL sStatBuf;
     944           4 :             if (VSIStatExL(osOvrFilename, &sStatBuf, VSI_STAT_EXISTS_FLAG) == 0)
     945           0 :                 osOvrFilename.Printf("%s.aux", poDS->GetDescription());
     946             :         }
     947             :     }
     948             :     /* -------------------------------------------------------------------- */
     949             :     /*      If we already have the overviews open, but they are             */
     950             :     /*      read-only, then try and reopen them read-write.                 */
     951             :     /* -------------------------------------------------------------------- */
     952          15 :     else if (poODS->GetAccess() == GA_ReadOnly)
     953             :     {
     954          13 :         GDALClose(poODS);
     955          13 :         poODS =
     956          13 :             GDALDataset::Open(osOvrFilename, GDAL_OF_RASTER | GDAL_OF_UPDATE);
     957          13 :         if (poODS == nullptr)
     958           0 :             return CE_Failure;
     959             :     }
     960             : 
     961             :     /* -------------------------------------------------------------------- */
     962             :     /*      If a basename is provided, use it to override the internal      */
     963             :     /*      overview filename.                                              */
     964             :     /* -------------------------------------------------------------------- */
     965         199 :     if (pszBasename == nullptr && osOvrFilename.length() == 0)
     966           0 :         pszBasename = poDS->GetDescription();
     967             : 
     968         199 :     if (pszBasename != nullptr)
     969             :     {
     970           1 :         if (bOvrIsAux)
     971           0 :             osOvrFilename.Printf("%s.aux", pszBasename);
     972             :         else
     973           1 :             osOvrFilename.Printf("%s.ovr", pszBasename);
     974             :     }
     975             : 
     976         199 :     return CE_None;
     977             : }
     978             : 
     979             : /************************************************************************/
     980             : /*                           BuildOverviews()                           */
     981             : /************************************************************************/
     982             : 
     983         204 : CPLErr GDALDefaultOverviews::BuildOverviews(
     984             :     const char *pszBasename, const char *pszResampling, int nOverviews,
     985             :     const int *panOverviewList, int nBands, const int *panBandList,
     986             :     GDALProgressFunc pfnProgress, void *pProgressData,
     987             :     CSLConstList papszOptions)
     988             : 
     989             : {
     990         204 :     if (pfnProgress == nullptr)
     991           0 :         pfnProgress = GDALDummyProgress;
     992             : 
     993         204 :     if (nOverviews == 0)
     994           9 :         return CleanOverviews();
     995             : 
     996         195 :     if (CreateOrOpenOverviewFile(pszBasename, papszOptions) != CE_None)
     997           0 :         return CE_Failure;
     998             : 
     999             :     /* -------------------------------------------------------------------- */
    1000             :     /*      Our TIFF overview support currently only works safely if all    */
    1001             :     /*      bands are handled at the same time.                             */
    1002             :     /* -------------------------------------------------------------------- */
    1003         195 :     if (!bOvrIsAux && nBands != poDS->GetRasterCount())
    1004             :     {
    1005           0 :         CPLError(CE_Failure, CPLE_NotSupported,
    1006             :                  "Generation of overviews in external TIFF currently only "
    1007             :                  "supported when operating on all bands.  "
    1008             :                  "Operation failed.");
    1009           0 :         return CE_Failure;
    1010             :     }
    1011             : 
    1012             :     /* -------------------------------------------------------------------- */
    1013             :     /*      Establish which of the overview levels we already have, and     */
    1014             :     /*      which are new.  We assume that band 1 of the file is            */
    1015             :     /*      representative.                                                 */
    1016             :     /* -------------------------------------------------------------------- */
    1017         195 :     GDALRasterBand *poBand = poDS->GetRasterBand(1);
    1018             : 
    1019         195 :     int nNewOverviews = 0;
    1020             :     int *panNewOverviewList =
    1021         195 :         static_cast<int *>(CPLCalloc(sizeof(int), nOverviews));
    1022         195 :     double dfAreaNewOverviews = 0;
    1023         195 :     double dfAreaRefreshedOverviews = 0;
    1024         390 :     std::vector<bool> abValidLevel(nOverviews, true);
    1025         195 :     std::vector<bool> abRequireRefresh(nOverviews, false);
    1026         195 :     bool bFoundSinglePixelOverview = false;
    1027         480 :     for (int i = 0; i < nOverviews && poBand != nullptr; i++)
    1028             :     {
    1029             :         // If we already have a 1x1 overview and this new one would result
    1030             :         // in it too, then don't create it.
    1031          16 :         if (bFoundSinglePixelOverview &&
    1032         301 :             DIV_ROUND_UP(poBand->GetXSize(), panOverviewList[i]) == 1 &&
    1033          16 :             DIV_ROUND_UP(poBand->GetYSize(), panOverviewList[i]) == 1)
    1034             :         {
    1035          16 :             abValidLevel[i] = false;
    1036          16 :             continue;
    1037             :         }
    1038             : 
    1039         290 :         for (int j = 0; j < poBand->GetOverviewCount(); j++)
    1040             :         {
    1041          38 :             GDALRasterBand *poOverview = poBand->GetOverview(j);
    1042          38 :             if (poOverview == nullptr)
    1043           0 :                 continue;
    1044             : 
    1045             :             int nOvFactor =
    1046          38 :                 GDALComputeOvFactor(poOverview->GetXSize(), poBand->GetXSize(),
    1047             :                                     poOverview->GetYSize(), poBand->GetYSize());
    1048             : 
    1049          59 :             if (nOvFactor == panOverviewList[i] ||
    1050          21 :                 nOvFactor == GDALOvLevelAdjust2(panOverviewList[i],
    1051             :                                                 poBand->GetXSize(),
    1052             :                                                 poBand->GetYSize()))
    1053             :             {
    1054             :                 const auto osNewResampling =
    1055          34 :                     GDALGetNormalizedOvrResampling(pszResampling);
    1056             :                 const char *pszExistingResampling =
    1057          17 :                     poOverview->GetMetadataItem("RESAMPLING");
    1058          28 :                 if (pszExistingResampling &&
    1059          11 :                     pszExistingResampling != osNewResampling)
    1060             :                 {
    1061           3 :                     if (auto l_poODS = poOverview->GetDataset())
    1062             :                     {
    1063           3 :                         if (auto poDriver = l_poODS->GetDriver())
    1064             :                         {
    1065           1 :                             if (EQUAL(poDriver->GetDescription(), "GTiff"))
    1066             :                             {
    1067           1 :                                 poOverview->SetMetadataItem(
    1068           1 :                                     "RESAMPLING", osNewResampling.c_str());
    1069             :                             }
    1070             :                         }
    1071             :                     }
    1072             :                 }
    1073             : 
    1074          17 :                 abRequireRefresh[i] = true;
    1075          17 :                 break;
    1076             :             }
    1077             :         }
    1078             : 
    1079         269 :         if (abValidLevel[i])
    1080             :         {
    1081         269 :             const double dfArea =
    1082             :                 1.0 /
    1083         269 :                 (static_cast<double>(panOverviewList[i]) * panOverviewList[i]);
    1084         269 :             dfAreaRefreshedOverviews += dfArea;
    1085         269 :             if (!abRequireRefresh[i])
    1086             :             {
    1087         252 :                 dfAreaNewOverviews += dfArea;
    1088         252 :                 panNewOverviewList[nNewOverviews++] = panOverviewList[i];
    1089             :             }
    1090             : 
    1091         290 :             if (DIV_ROUND_UP(poBand->GetXSize(), panOverviewList[i]) == 1 &&
    1092          21 :                 DIV_ROUND_UP(poBand->GetYSize(), panOverviewList[i]) == 1)
    1093             :             {
    1094          19 :                 bFoundSinglePixelOverview = true;
    1095             :             }
    1096             :         }
    1097             :     }
    1098             : 
    1099             :     /* -------------------------------------------------------------------- */
    1100             :     /*      Build band list.                                                */
    1101             :     /* -------------------------------------------------------------------- */
    1102             :     GDALRasterBand **pahBands = static_cast<GDALRasterBand **>(
    1103         195 :         CPLCalloc(sizeof(GDALRasterBand *), nBands));
    1104         505 :     for (int i = 0; i < nBands; i++)
    1105         310 :         pahBands[i] = poDS->GetRasterBand(panBandList[i]);
    1106             : 
    1107             :     /* -------------------------------------------------------------------- */
    1108             :     /*      Build new overviews - Imagine.  Keep existing file open if      */
    1109             :     /*      we have it.  But mark all overviews as in need of               */
    1110             :     /*      regeneration, since HFAAuxBuildOverviews() doesn't actually     */
    1111             :     /*      produce the imagery.                                            */
    1112             :     /* -------------------------------------------------------------------- */
    1113             : 
    1114         195 :     CPLErr eErr = CE_None;
    1115             : 
    1116         195 :     void *pScaledOverviewWithoutMask = GDALCreateScaledProgress(
    1117         195 :         0, (HaveMaskFile() && poMaskDS) ? double(nBands) / (nBands + 1) : 1,
    1118             :         pfnProgress, pProgressData);
    1119             : 
    1120         214 :     const auto AvoidZero = [](double x)
    1121             :     {
    1122         214 :         if (x == 0)
    1123           0 :             return 1.0;
    1124         214 :         return x;
    1125             :     };
    1126             : 
    1127         195 :     void *pScaledProgress = GDALCreateScaledProgress(
    1128         195 :         0, dfAreaNewOverviews / AvoidZero(dfAreaRefreshedOverviews),
    1129             :         GDALScaledProgress, pScaledOverviewWithoutMask);
    1130         195 :     if (bOvrIsAux)
    1131             :     {
    1132             : #ifdef NO_HFA_SUPPORT
    1133             :         CPLError(CE_Failure, CPLE_NotSupported,
    1134             :                  "This build does not support creating .aux overviews");
    1135             :         eErr = CE_Failure;
    1136             : #else
    1137           8 :         if (nNewOverviews == 0)
    1138             :         {
    1139             :             /* if we call HFAAuxBuildOverviews() with nNewOverviews == 0 */
    1140             :             /* because that there's no new, this will wipe existing */
    1141             :             /* overviews (#4831) */
    1142             :             // eErr = CE_None;
    1143             :         }
    1144             :         else
    1145             :         {
    1146           5 :             eErr = HFAAuxBuildOverviews(
    1147             :                 osOvrFilename, poDS, &poODS, nBands, panBandList, nNewOverviews,
    1148             :                 panNewOverviewList, pszResampling, GDALScaledProgress,
    1149             :                 pScaledProgress, papszOptions);
    1150             :         }
    1151             : 
    1152             :         // HFAAuxBuildOverviews doesn't actually generate overviews
    1153           8 :         dfAreaNewOverviews = 0.0;
    1154          20 :         for (int j = 0; j < nOverviews; j++)
    1155             :         {
    1156          12 :             if (abValidLevel[j])
    1157          12 :                 abRequireRefresh[j] = true;
    1158             :         }
    1159             : #endif
    1160             :     }
    1161             : 
    1162             :     /* -------------------------------------------------------------------- */
    1163             :     /*      Build new overviews - TIFF.  Close TIFF files while we          */
    1164             :     /*      operate on it.                                                  */
    1165             :     /* -------------------------------------------------------------------- */
    1166             :     else
    1167             :     {
    1168         187 :         if (poODS != nullptr)
    1169             :         {
    1170           9 :             delete poODS;
    1171           9 :             poODS = nullptr;
    1172             :         }
    1173             : 
    1174             : #ifdef HAVE_TIFF
    1175         187 :         eErr = GTIFFBuildOverviews(
    1176             :             osOvrFilename, nBands, pahBands, nNewOverviews, panNewOverviewList,
    1177             :             pszResampling, GDALScaledProgress, pScaledProgress, papszOptions);
    1178             : 
    1179             :         // Probe for proxy overview filename.
    1180         187 :         if (eErr == CE_Failure)
    1181             :         {
    1182             :             const char *pszProxyOvrFilename =
    1183           5 :                 poDS->GetMetadataItem("FILENAME", "ProxyOverviewRequest");
    1184             : 
    1185           5 :             if (pszProxyOvrFilename != nullptr)
    1186             :             {
    1187           1 :                 osOvrFilename = pszProxyOvrFilename;
    1188           1 :                 eErr = GTIFFBuildOverviews(osOvrFilename, nBands, pahBands,
    1189             :                                            nNewOverviews, panNewOverviewList,
    1190             :                                            pszResampling, GDALScaledProgress,
    1191             :                                            pScaledProgress, papszOptions);
    1192             :             }
    1193             :         }
    1194             : 
    1195         187 :         if (eErr == CE_None)
    1196             :         {
    1197         183 :             poODS = GDALDataset::Open(osOvrFilename,
    1198             :                                       GDAL_OF_RASTER | GDAL_OF_UPDATE);
    1199         183 :             if (poODS == nullptr)
    1200           0 :                 eErr = CE_Failure;
    1201             :         }
    1202             : #else
    1203             :         CPLError(CE_Failure, CPLE_NotSupported,
    1204             :                  "Cannot build TIFF overviews due to GeoTIFF driver missing");
    1205             :         eErr = CE_Failure;
    1206             : #endif
    1207             :     }
    1208             : 
    1209         195 :     GDALDestroyScaledProgress(pScaledProgress);
    1210             : 
    1211             :     /* -------------------------------------------------------------------- */
    1212             :     /*      Refresh old overviews that were listed.                         */
    1213             :     /* -------------------------------------------------------------------- */
    1214             :     GDALRasterBand **papoOverviewBands =
    1215         195 :         static_cast<GDALRasterBand **>(CPLCalloc(sizeof(void *), nOverviews));
    1216             : 
    1217         501 :     for (int iBand = 0; iBand < nBands && eErr == CE_None; iBand++)
    1218             :     {
    1219         306 :         poBand = poDS->GetRasterBand(panBandList[iBand]);
    1220         306 :         if (poBand == nullptr)
    1221             :         {
    1222           0 :             eErr = CE_Failure;
    1223           0 :             break;
    1224             :         }
    1225             : 
    1226         306 :         nNewOverviews = 0;
    1227         612 :         std::vector<bool> abAlreadyUsedOverviewBand(poBand->GetOverviewCount(),
    1228         612 :                                                     false);
    1229             : 
    1230         769 :         for (int i = 0; i < nOverviews; i++)
    1231             :         {
    1232         463 :             if (!abValidLevel[i] || !abRequireRefresh[i])
    1233         434 :                 continue;
    1234             : 
    1235          47 :             for (int j = 0; j < poBand->GetOverviewCount(); j++)
    1236             :             {
    1237          47 :                 if (abAlreadyUsedOverviewBand[j])
    1238          16 :                     continue;
    1239             : 
    1240          31 :                 GDALRasterBand *poOverview = poBand->GetOverview(j);
    1241          31 :                 if (poOverview == nullptr)
    1242           0 :                     continue;
    1243             : 
    1244          31 :                 int bHasNoData = FALSE;
    1245          31 :                 double noDataValue = poBand->GetNoDataValue(&bHasNoData);
    1246             : 
    1247          31 :                 if (bHasNoData)
    1248           2 :                     poOverview->SetNoDataValue(noDataValue);
    1249             : 
    1250          31 :                 const int nOvFactor = GDALComputeOvFactor(
    1251             :                     poOverview->GetXSize(), poBand->GetXSize(),
    1252             :                     poOverview->GetYSize(), poBand->GetYSize());
    1253             : 
    1254          33 :                 if (nOvFactor == panOverviewList[i] ||
    1255           2 :                     nOvFactor == GDALOvLevelAdjust2(panOverviewList[i],
    1256             :                                                     poBand->GetXSize(),
    1257             :                                                     poBand->GetYSize()))
    1258             :                 {
    1259          29 :                     abAlreadyUsedOverviewBand[j] = true;
    1260          29 :                     CPLAssert(nNewOverviews < poBand->GetOverviewCount());
    1261          29 :                     papoOverviewBands[nNewOverviews++] = poOverview;
    1262          29 :                     break;
    1263             :                 }
    1264             :             }
    1265             :         }
    1266             : 
    1267         306 :         if (nNewOverviews > 0)
    1268             :         {
    1269             :             const double dfOffset =
    1270          19 :                 dfAreaNewOverviews / AvoidZero(dfAreaRefreshedOverviews);
    1271          19 :             const double dfScale = 1.0 - dfOffset;
    1272          38 :             pScaledProgress = GDALCreateScaledProgress(
    1273          19 :                 dfOffset + dfScale * iBand / nBands,
    1274          19 :                 dfOffset + dfScale * (iBand + 1) / nBands, GDALScaledProgress,
    1275             :                 pScaledOverviewWithoutMask);
    1276          19 :             eErr = GDALRegenerateOverviewsEx(
    1277             :                 GDALRasterBand::ToHandle(poBand), nNewOverviews,
    1278             :                 reinterpret_cast<GDALRasterBandH *>(papoOverviewBands),
    1279             :                 pszResampling, GDALScaledProgress, pScaledProgress,
    1280             :                 papszOptions);
    1281          19 :             GDALDestroyScaledProgress(pScaledProgress);
    1282             :         }
    1283             :     }
    1284             : 
    1285             :     /* -------------------------------------------------------------------- */
    1286             :     /*      Cleanup                                                         */
    1287             :     /* -------------------------------------------------------------------- */
    1288         195 :     CPLFree(papoOverviewBands);
    1289         195 :     CPLFree(panNewOverviewList);
    1290         195 :     CPLFree(pahBands);
    1291         195 :     GDALDestroyScaledProgress(pScaledOverviewWithoutMask);
    1292             : 
    1293             :     /* -------------------------------------------------------------------- */
    1294             :     /*      If we have a mask file, we need to build its overviews too.     */
    1295             :     /* -------------------------------------------------------------------- */
    1296         195 :     if (HaveMaskFile() && eErr == CE_None)
    1297             :     {
    1298           4 :         pScaledProgress = GDALCreateScaledProgress(
    1299           2 :             double(nBands) / (nBands + 1), 1.0, pfnProgress, pProgressData);
    1300           2 :         eErr = BuildOverviewsMask(pszResampling, nOverviews, panOverviewList,
    1301             :                                   GDALScaledProgress, pScaledProgress,
    1302             :                                   papszOptions);
    1303           2 :         GDALDestroyScaledProgress(pScaledProgress);
    1304             :     }
    1305             : 
    1306             :     /* -------------------------------------------------------------------- */
    1307             :     /*      If we have an overview dataset, then mark all the overviews     */
    1308             :     /*      with the base dataset  Used later for finding overviews         */
    1309             :     /*      masks.  Uggg.                                                   */
    1310             :     /* -------------------------------------------------------------------- */
    1311         195 :     if (poODS)
    1312             :     {
    1313         191 :         const int nOverviewCount = GetOverviewCount(1);
    1314             : 
    1315         462 :         for (int iOver = 0; iOver < nOverviewCount; iOver++)
    1316             :         {
    1317         271 :             GDALRasterBand *poOtherBand = GetOverview(1, iOver);
    1318             :             GDALDataset *poOverDS =
    1319         271 :                 poOtherBand != nullptr ? poOtherBand->GetDataset() : nullptr;
    1320             : 
    1321         271 :             if (poOverDS != nullptr)
    1322             :             {
    1323         257 :                 poOverDS->oOvManager.poBaseDS = poDS;
    1324         257 :                 poOverDS->oOvManager.poDS = poOverDS;
    1325             :             }
    1326             :         }
    1327             :     }
    1328             : 
    1329         195 :     return eErr;
    1330             : }
    1331             : 
    1332             : /************************************************************************/
    1333             : /*                          BuildOverviewsMask()                        */
    1334             : /************************************************************************/
    1335             : 
    1336           4 : CPLErr GDALDefaultOverviews::BuildOverviewsMask(const char *pszResampling,
    1337             :                                                 int nOverviews,
    1338             :                                                 const int *panOverviewList,
    1339             :                                                 GDALProgressFunc pfnProgress,
    1340             :                                                 void *pProgressData,
    1341             :                                                 CSLConstList papszOptions)
    1342             : {
    1343           4 :     CPLErr eErr = CE_None;
    1344           4 :     if (HaveMaskFile() && poMaskDS)
    1345             :     {
    1346             :         // Some options are not compatible with mask overviews
    1347             :         // so unset them, and define more sensible values.
    1348           4 :         CPLStringList aosMaskOptions(papszOptions);
    1349             :         const char *pszCompress =
    1350           4 :             GetOptionValue(papszOptions, "COMPRESS", "COMPRESS_OVERVIEW");
    1351           4 :         const bool bJPEG = pszCompress && EQUAL(pszCompress, "JPEG");
    1352             :         const char *pszPhotometric =
    1353           4 :             GetOptionValue(papszOptions, "PHOTOMETRIC", "PHOTOMETRIC_OVERVIEW");
    1354           4 :         const bool bPHOTOMETRIC_YCBCR =
    1355           4 :             pszPhotometric && EQUAL(pszPhotometric, "YCBCR");
    1356           4 :         if (bJPEG)
    1357           0 :             aosMaskOptions.SetNameValue("COMPRESS", "DEFLATE");
    1358           4 :         if (bPHOTOMETRIC_YCBCR)
    1359           0 :             aosMaskOptions.SetNameValue("PHOTOMETRIC", "MINISBLACK");
    1360             : 
    1361           4 :         eErr = poMaskDS->BuildOverviews(
    1362             :             pszResampling, nOverviews, panOverviewList, 0, nullptr, pfnProgress,
    1363           4 :             pProgressData, aosMaskOptions.List());
    1364             : 
    1365           4 :         if (bOwnMaskDS)
    1366             :         {
    1367             :             // Reset the poMask member of main dataset bands, since it
    1368             :             // will become invalid after poMaskDS closing.
    1369          10 :             for (int iBand = 1; iBand <= poDS->GetRasterCount(); iBand++)
    1370             :             {
    1371           6 :                 GDALRasterBand *poOtherBand = poDS->GetRasterBand(iBand);
    1372           6 :                 if (poOtherBand != nullptr)
    1373           6 :                     poOtherBand->InvalidateMaskBand();
    1374             :             }
    1375             : 
    1376           4 :             GDALClose(poMaskDS);
    1377             :         }
    1378             : 
    1379             :         // force next request to reread mask file.
    1380           4 :         poMaskDS = nullptr;
    1381           4 :         bOwnMaskDS = false;
    1382           4 :         bCheckedForMask = false;
    1383             :     }
    1384             : 
    1385           4 :     return eErr;
    1386             : }
    1387             : 
    1388             : /************************************************************************/
    1389             : /*                           CreateMaskBand()                           */
    1390             : /************************************************************************/
    1391             : 
    1392          26 : CPLErr GDALDefaultOverviews::CreateMaskBand(int nFlags, int nBand)
    1393             : 
    1394             : {
    1395          26 :     if (nBand < 1)
    1396          17 :         nFlags |= GMF_PER_DATASET;
    1397             : 
    1398             :     /* -------------------------------------------------------------------- */
    1399             :     /*      ensure existing file gets opened if there is one.               */
    1400             :     /* -------------------------------------------------------------------- */
    1401          26 :     CPL_IGNORE_RET_VAL(HaveMaskFile());
    1402             : 
    1403             :     /* -------------------------------------------------------------------- */
    1404             :     /*      Try creating the mask file.                                     */
    1405             :     /* -------------------------------------------------------------------- */
    1406          26 :     if (poMaskDS == nullptr)
    1407             :     {
    1408             :         GDALDriver *const poDr =
    1409          21 :             static_cast<GDALDriver *>(GDALGetDriverByName("GTiff"));
    1410             : 
    1411          21 :         if (poDr == nullptr)
    1412           0 :             return CE_Failure;
    1413             : 
    1414          21 :         GDALRasterBand *const poTBand = poDS->GetRasterBand(1);
    1415          21 :         if (poTBand == nullptr)
    1416           0 :             return CE_Failure;
    1417             : 
    1418             :         const int nBands =
    1419          21 :             (nFlags & GMF_PER_DATASET) ? 1 : poDS->GetRasterCount();
    1420             : 
    1421          21 :         char **papszOpt = CSLSetNameValue(nullptr, "COMPRESS", "DEFLATE");
    1422          21 :         papszOpt = CSLSetNameValue(papszOpt, "INTERLEAVE", "BAND");
    1423             : 
    1424          21 :         int nBX = 0;
    1425          21 :         int nBY = 0;
    1426          21 :         poTBand->GetBlockSize(&nBX, &nBY);
    1427             : 
    1428             :         // Try to create matching tile size if legal in TIFF.
    1429          21 :         if ((nBX % 16) == 0 && (nBY % 16) == 0)
    1430             :         {
    1431           2 :             papszOpt = CSLSetNameValue(papszOpt, "TILED", "YES");
    1432           2 :             papszOpt = CSLSetNameValue(papszOpt, "BLOCKXSIZE",
    1433           4 :                                        CPLString().Printf("%d", nBX));
    1434           2 :             papszOpt = CSLSetNameValue(papszOpt, "BLOCKYSIZE",
    1435           4 :                                        CPLString().Printf("%d", nBY));
    1436             :         }
    1437             : 
    1438          21 :         CPLString osMskFilename;
    1439          21 :         osMskFilename.Printf("%s.msk", poDS->GetDescription());
    1440          21 :         poMaskDS =
    1441          21 :             poDr->Create(osMskFilename, poDS->GetRasterXSize(),
    1442          21 :                          poDS->GetRasterYSize(), nBands, GDT_Byte, papszOpt);
    1443          21 :         CSLDestroy(papszOpt);
    1444             : 
    1445          21 :         if (poMaskDS == nullptr)  // Presumably error already issued.
    1446           0 :             return CE_Failure;
    1447             : 
    1448          21 :         bOwnMaskDS = true;
    1449             :     }
    1450             : 
    1451             :     /* -------------------------------------------------------------------- */
    1452             :     /*      Save the mask flags for this band.                              */
    1453             :     /* -------------------------------------------------------------------- */
    1454          26 :     if (nBand > poMaskDS->GetRasterCount())
    1455             :     {
    1456           1 :         CPLError(CE_Failure, CPLE_AppDefined,
    1457             :                  "Attempt to create a mask band for band %d of %s, "
    1458             :                  "but the .msk file has a PER_DATASET mask.",
    1459           1 :                  nBand, poDS->GetDescription());
    1460           1 :         return CE_Failure;
    1461             :     }
    1462             : 
    1463          67 :     for (int iBand = 0; iBand < poDS->GetRasterCount(); iBand++)
    1464             :     {
    1465             :         // we write only the info for this band, unless we are
    1466             :         // using PER_DATASET in which case we write for all.
    1467          42 :         if (nBand != iBand + 1 && !(nFlags & GMF_PER_DATASET))
    1468           6 :             continue;
    1469             : 
    1470          36 :         poMaskDS->SetMetadataItem(
    1471          72 :             CPLString().Printf("INTERNAL_MASK_FLAGS_%d", iBand + 1),
    1472          72 :             CPLString().Printf("%d", nFlags));
    1473             :     }
    1474             : 
    1475          25 :     return CE_None;
    1476             : }
    1477             : 
    1478             : /************************************************************************/
    1479             : /*                            GetMaskBand()                             */
    1480             : /************************************************************************/
    1481             : 
    1482             : // Secret code meaning we don't handle this band.
    1483             : constexpr int MISSING_FLAGS = 0x8000;
    1484             : 
    1485          46 : GDALRasterBand *GDALDefaultOverviews::GetMaskBand(int nBand)
    1486             : 
    1487             : {
    1488          46 :     const int nFlags = GetMaskFlags(nBand);
    1489             : 
    1490          46 :     if (poMaskDS == nullptr || nFlags == MISSING_FLAGS)
    1491           1 :         return nullptr;
    1492             : 
    1493          45 :     if (nFlags & GMF_PER_DATASET)
    1494          36 :         return poMaskDS->GetRasterBand(1);
    1495             : 
    1496           9 :     if (nBand > 0)
    1497           9 :         return poMaskDS->GetRasterBand(nBand);
    1498             : 
    1499           0 :     return nullptr;
    1500             : }
    1501             : 
    1502             : /************************************************************************/
    1503             : /*                            GetMaskFlags()                            */
    1504             : /************************************************************************/
    1505             : 
    1506          90 : int GDALDefaultOverviews::GetMaskFlags(int nBand)
    1507             : 
    1508             : {
    1509             :     /* -------------------------------------------------------------------- */
    1510             :     /*      Fetch this band's metadata entry.  They are of the form:        */
    1511             :     /*        INTERNAL_MASK_FLAGS_n: flags                                  */
    1512             :     /* -------------------------------------------------------------------- */
    1513          90 :     if (!HaveMaskFile())
    1514           0 :         return 0;
    1515             : 
    1516          90 :     const char *pszValue = poMaskDS->GetMetadataItem(
    1517         180 :         CPLString().Printf("INTERNAL_MASK_FLAGS_%d", std::max(nBand, 1)));
    1518             : 
    1519          90 :     if (pszValue == nullptr)
    1520           1 :         return MISSING_FLAGS;
    1521             : 
    1522          89 :     return atoi(pszValue);
    1523             : }
    1524             : 
    1525             : /************************************************************************/
    1526             : /*                            HaveMaskFile()                            */
    1527             : /*                                                                      */
    1528             : /*      Check for a mask file if we haven't already done so.            */
    1529             : /*      Returns TRUE if we have one, otherwise FALSE.                   */
    1530             : /************************************************************************/
    1531             : 
    1532      100280 : int GDALDefaultOverviews::HaveMaskFile(char **papszSiblingFiles,
    1533             :                                        const char *pszBasename)
    1534             : 
    1535             : {
    1536             :     /* -------------------------------------------------------------------- */
    1537             :     /*      Have we already checked for masks?                              */
    1538             :     /* -------------------------------------------------------------------- */
    1539      100280 :     if (bCheckedForMask)
    1540        3792 :         return poMaskDS != nullptr;
    1541             : 
    1542       96488 :     if (papszSiblingFiles == nullptr)
    1543       96487 :         papszSiblingFiles = papszInitSiblingFiles;
    1544             : 
    1545             :     /* -------------------------------------------------------------------- */
    1546             :     /*      Are we an overview?  If so we need to find the corresponding    */
    1547             :     /*      overview in the base files mask file (if there is one).         */
    1548             :     /* -------------------------------------------------------------------- */
    1549       96488 :     if (poBaseDS != nullptr && poBaseDS->oOvManager.HaveMaskFile())
    1550             :     {
    1551           4 :         GDALRasterBand *const poBaseBand = poBaseDS->GetRasterBand(1);
    1552           4 :         GDALDataset *poMaskDSTemp = nullptr;
    1553           4 :         if (poBaseBand != nullptr)
    1554             :         {
    1555           4 :             GDALRasterBand *poBaseMask = poBaseBand->GetMaskBand();
    1556           4 :             if (poBaseMask != nullptr)
    1557             :             {
    1558           4 :                 const int nOverviewCount = poBaseMask->GetOverviewCount();
    1559           6 :                 for (int iOver = 0; iOver < nOverviewCount; iOver++)
    1560             :                 {
    1561             :                     GDALRasterBand *const poOverBand =
    1562           6 :                         poBaseMask->GetOverview(iOver);
    1563           6 :                     if (poOverBand == nullptr)
    1564           0 :                         continue;
    1565             : 
    1566          10 :                     if (poOverBand->GetXSize() == poDS->GetRasterXSize() &&
    1567           4 :                         poOverBand->GetYSize() == poDS->GetRasterYSize())
    1568             :                     {
    1569           4 :                         poMaskDSTemp = poOverBand->GetDataset();
    1570           4 :                         break;
    1571             :                     }
    1572             :                 }
    1573             :             }
    1574             :         }
    1575             : 
    1576           4 :         if (poMaskDSTemp != poDS)
    1577             :         {
    1578           4 :             poMaskDS = poMaskDSTemp;
    1579           4 :             bCheckedForMask = true;
    1580           4 :             bOwnMaskDS = false;
    1581             : 
    1582           4 :             return poMaskDS != nullptr;
    1583             :         }
    1584             :     }
    1585             : 
    1586             :     /* -------------------------------------------------------------------- */
    1587             :     /*      Are we even initialized?  If not, we apparently don't want      */
    1588             :     /*      to support overviews and masks.                                 */
    1589             :     /* -------------------------------------------------------------------- */
    1590       96484 :     if (poDS == nullptr)
    1591       86161 :         return FALSE;
    1592             : 
    1593             :     /* -------------------------------------------------------------------- */
    1594             :     /*      Check for .msk file.                                            */
    1595             :     /* -------------------------------------------------------------------- */
    1596       10323 :     bCheckedForMask = true;
    1597             : 
    1598       10323 :     if (pszBasename == nullptr)
    1599       10323 :         pszBasename = poDS->GetDescription();
    1600             : 
    1601             :     // Don't bother checking for masks of masks.
    1602       10323 :     if (EQUAL(CPLGetExtensionSafe(pszBasename).c_str(), "msk"))
    1603          18 :         return FALSE;
    1604             : 
    1605       10305 :     if (!GDALCanFileAcceptSidecarFile(pszBasename))
    1606           1 :         return FALSE;
    1607       20608 :     CPLString osMskFilename;
    1608       10304 :     osMskFilename.Printf("%s.msk", pszBasename);
    1609             : 
    1610       20608 :     std::vector<char> achMskFilename;
    1611       10304 :     achMskFilename.resize(osMskFilename.size() + 1);
    1612       10304 :     memcpy(&(achMskFilename[0]), osMskFilename.c_str(),
    1613       10304 :            osMskFilename.size() + 1);
    1614             :     bool bExists =
    1615       10304 :         CPL_TO_BOOL(CPLCheckForFile(&achMskFilename[0], papszSiblingFiles));
    1616       10304 :     osMskFilename = &achMskFilename[0];
    1617             : 
    1618             : #if !defined(_WIN32)
    1619       10304 :     if (!bExists && !papszSiblingFiles)
    1620             :     {
    1621        2246 :         osMskFilename.Printf("%s.MSK", pszBasename);
    1622        2246 :         memcpy(&(achMskFilename[0]), osMskFilename.c_str(),
    1623        2246 :                osMskFilename.size() + 1);
    1624             :         bExists =
    1625        2246 :             CPL_TO_BOOL(CPLCheckForFile(&achMskFilename[0], papszSiblingFiles));
    1626        2246 :         osMskFilename = &achMskFilename[0];
    1627             :     }
    1628             : #endif
    1629             : 
    1630       10304 :     if (!bExists)
    1631       10269 :         return FALSE;
    1632             : 
    1633             :     /* -------------------------------------------------------------------- */
    1634             :     /*      Open the file.                                                  */
    1635             :     /* -------------------------------------------------------------------- */
    1636          35 :     poMaskDS = GDALDataset::Open(
    1637             :         osMskFilename,
    1638          35 :         GDAL_OF_RASTER | (poDS->GetAccess() == GA_Update ? GDAL_OF_UPDATE : 0),
    1639          35 :         nullptr, nullptr, papszInitSiblingFiles);
    1640          35 :     CPLAssert(poMaskDS != poDS);
    1641             : 
    1642          35 :     if (poMaskDS == nullptr)
    1643           1 :         return FALSE;
    1644             : 
    1645          34 :     bOwnMaskDS = true;
    1646             : 
    1647          34 :     return TRUE;
    1648             : }
    1649             : 
    1650             : /************************************************************************/
    1651             : /*                    GDALGetNormalizedOvrResampling()                  */
    1652             : /************************************************************************/
    1653             : 
    1654         979 : std::string GDALGetNormalizedOvrResampling(const char *pszResampling)
    1655             : {
    1656         979 :     if (pszResampling &&
    1657         979 :         EQUAL(pszResampling, "AVERAGE_BIT2GRAYSCALE_MINISWHITE"))
    1658           0 :         return "AVERAGE_BIT2GRAYSCALE_MINISWHITE";
    1659         979 :     else if (pszResampling && STARTS_WITH_CI(pszResampling, "AVERAGE_BIT2"))
    1660           8 :         return "AVERAGE_BIT2GRAYSCALE";
    1661         971 :     else if (pszResampling && STARTS_WITH_CI(pszResampling, "NEAR"))
    1662         417 :         return "NEAREST";
    1663         554 :     else if (pszResampling && EQUAL(pszResampling, "AVERAGE_MAGPHASE"))
    1664           0 :         return "AVERAGE_MAGPHASE";
    1665         554 :     else if (pszResampling && STARTS_WITH_CI(pszResampling, "AVER"))
    1666         254 :         return "AVERAGE";
    1667         300 :     else if (pszResampling && !EQUAL(pszResampling, "NONE"))
    1668             :     {
    1669         342 :         return CPLString(pszResampling).toupper();
    1670             :     }
    1671         129 :     return std::string();
    1672             : }
    1673             : 
    1674             : //! @endcond

Generated by: LCOV version 1.14