LCOV - code coverage report
Current view: top level - gcore - gdaldefaultoverviews.cpp (source / functions) Hit Total Coverage
Test: gdal_filtered.info Lines: 626 692 90.5 %
Date: 2025-09-10 17:48:50 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      150003 : 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      150003 :       papszInitSiblingFiles(nullptr)
      45             : {
      46      149945 : }
      47             : 
      48             : /************************************************************************/
      49             : /*                       ~GDALDefaultOverviews()                        */
      50             : /************************************************************************/
      51             : 
      52      149927 : GDALDefaultOverviews::~GDALDefaultOverviews()
      53             : 
      54             : {
      55      149936 :     CPLFree(pszInitName);
      56      149933 :     CSLDestroy(papszInitSiblingFiles);
      57             : 
      58      149933 :     CloseDependentDatasets();
      59      149921 : }
      60             : 
      61             : /************************************************************************/
      62             : /*                       CloseDependentDatasets()                       */
      63             : /************************************************************************/
      64             : 
      65      168848 : int GDALDefaultOverviews::CloseDependentDatasets()
      66             : {
      67      168848 :     bool bHasDroppedRef = false;
      68      168848 :     if (poODS != nullptr)
      69             :     {
      70         397 :         bHasDroppedRef = true;
      71         397 :         poODS->FlushCache(true);
      72         397 :         GDALClose(poODS);
      73         380 :         poODS = nullptr;
      74             :     }
      75             : 
      76      168831 :     if (poMaskDS != nullptr)
      77             :     {
      78          56 :         if (bOwnMaskDS)
      79             :         {
      80          52 :             bHasDroppedRef = true;
      81          52 :             poMaskDS->FlushCache(true);
      82          52 :             GDALClose(poMaskDS);
      83             :         }
      84          56 :         poMaskDS = nullptr;
      85             :     }
      86             : 
      87      168831 :     return bHasDroppedRef;
      88             : }
      89             : 
      90             : /************************************************************************/
      91             : /*                           IsInitialized()                            */
      92             : /*                                                                      */
      93             : /*      Returns TRUE if we are initialized.                             */
      94             : /************************************************************************/
      95             : 
      96     1072090 : int GDALDefaultOverviews::IsInitialized()
      97             : 
      98             : {
      99     1072090 :     OverviewScan();
     100     1072090 :     return poDS != nullptr;
     101             : }
     102             : 
     103             : /************************************************************************/
     104             : /*                             Initialize()                             */
     105             : /************************************************************************/
     106             : 
     107       52363 : void GDALDefaultOverviews::Initialize(GDALDataset *poDSIn,
     108             :                                       const char *pszBasename,
     109             :                                       CSLConstList papszSiblingFiles,
     110             :                                       bool bNameIsOVR)
     111             : 
     112             : {
     113       52363 :     poDS = poDSIn;
     114             : 
     115             :     /* -------------------------------------------------------------------- */
     116             :     /*      If we were already initialized, destroy the old overview        */
     117             :     /*      file handle.                                                    */
     118             :     /* -------------------------------------------------------------------- */
     119       52363 :     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       52363 :     bCheckedForOverviews = FALSE;
     133             : 
     134       52363 :     CPLFree(pszInitName);
     135       52633 :     pszInitName = nullptr;
     136       52633 :     if (pszBasename != nullptr)
     137       52387 :         pszInitName = CPLStrdup(pszBasename);
     138       52616 :     bInitNameIsOVR = bNameIsOVR;
     139             : 
     140       52616 :     CSLDestroy(papszInitSiblingFiles);
     141       52489 :     papszInitSiblingFiles = nullptr;
     142       52489 :     if (papszSiblingFiles != nullptr)
     143        5665 :         papszInitSiblingFiles = CSLDuplicate(papszSiblingFiles);
     144       52487 : }
     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       32952 : void GDALDefaultOverviews::Initialize(GDALDataset *poDSIn,
     163             :                                       GDALOpenInfo *poOpenInfo,
     164             :                                       const char *pszName,
     165             :                                       bool bTransferSiblingFilesIfLoaded)
     166             : {
     167       32952 :     Initialize(poDSIn, pszName ? pszName : poOpenInfo->pszFilename);
     168             : 
     169       32757 :     if (bTransferSiblingFilesIfLoaded && poOpenInfo->AreSiblingFilesLoaded())
     170        9715 :         TransferSiblingFiles(poOpenInfo->StealSiblingFiles());
     171       32754 : }
     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       26678 : void GDALDefaultOverviews::TransferSiblingFiles(char **papszSiblingFiles)
     182             : {
     183       26678 :     CSLDestroy(papszInitSiblingFiles);
     184       26674 :     papszInitSiblingFiles = papszSiblingFiles;
     185       26674 : }
     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       11774 : static AntiRecursionStructDefaultOvr &GetAntiRecursionDefaultOvr()
     203             : {
     204       11774 :     static AntiRecursionStructDefaultOvr dummy;
     205       11774 :     int bMemoryErrorOccurred = false;
     206             :     void *pData =
     207       11774 :         CPLGetTLSEx(CTLS_GDALDEFAULTOVR_ANTIREC, &bMemoryErrorOccurred);
     208       11774 :     if (bMemoryErrorOccurred)
     209             :     {
     210           0 :         return dummy;
     211             :     }
     212       11774 :     if (pData == nullptr)
     213             :     {
     214         459 :         auto pAntiRecursion = new AntiRecursionStructDefaultOvr();
     215         459 :         CPLSetTLSWithFreeFuncEx(CTLS_GDALDEFAULTOVR_ANTIREC, pAntiRecursion,
     216             :                                 FreeAntiRecursionDefaultOvr,
     217             :                                 &bMemoryErrorOccurred);
     218         459 :         if (bMemoryErrorOccurred)
     219             :         {
     220           0 :             delete pAntiRecursion;
     221           0 :             return dummy;
     222             :         }
     223         459 :         return *pAntiRecursion;
     224             :     }
     225       11315 :     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     1072090 : void GDALDefaultOverviews::OverviewScan()
     238             : 
     239             : {
     240     1072090 :     if (bCheckedForOverviews || poDS == nullptr)
     241     1060310 :         return;
     242             : 
     243       11774 :     bCheckedForOverviews = true;
     244       11774 :     if (pszInitName == nullptr)
     245          14 :         pszInitName = CPLStrdup(poDS->GetDescription());
     246             : 
     247       11774 :     AntiRecursionStructDefaultOvr &antiRec = GetAntiRecursionDefaultOvr();
     248             :     // 32 should be enough to handle a .ovr.ovr.ovr...
     249       11774 :     if (antiRec.nRecLevel == 32)
     250           0 :         return;
     251       11774 :     if (antiRec.oSetFiles.find(pszInitName) != antiRec.oSetFiles.end())
     252           0 :         return;
     253       11774 :     antiRec.oSetFiles.insert(pszInitName);
     254       11774 :     ++antiRec.nRecLevel;
     255             : 
     256       11774 :     CPLDebug("GDAL", "GDALDefaultOverviews::OverviewScan()");
     257             : 
     258             :     /* -------------------------------------------------------------------- */
     259             :     /*      Open overview dataset if it exists.                             */
     260             :     /* -------------------------------------------------------------------- */
     261       23365 :     if (!EQUAL(pszInitName, ":::VIRTUAL:::") &&
     262       11592 :         GDALCanFileAcceptSidecarFile(pszInitName))
     263             :     {
     264       11590 :         if (bInitNameIsOVR)
     265           0 :             osOvrFilename = pszInitName;
     266             :         else
     267       11590 :             osOvrFilename.Printf("%s.ovr", pszInitName);
     268             : 
     269       23182 :         std::vector<char> achOvrFilename;
     270       11590 :         achOvrFilename.resize(osOvrFilename.size() + 1);
     271       11591 :         memcpy(&(achOvrFilename[0]), osOvrFilename.c_str(),
     272       11591 :                osOvrFilename.size() + 1);
     273       11591 :         bool bExists = CPL_TO_BOOL(
     274       11591 :             CPLCheckForFile(&achOvrFilename[0], papszInitSiblingFiles));
     275       11590 :         osOvrFilename = &achOvrFilename[0];
     276             : 
     277             : #if !defined(_WIN32)
     278       11591 :         if (!bInitNameIsOVR && !bExists && !papszInitSiblingFiles)
     279             :         {
     280        2945 :             osOvrFilename.Printf("%s.OVR", pszInitName);
     281        2945 :             memcpy(&(achOvrFilename[0]), osOvrFilename.c_str(),
     282        2945 :                    osOvrFilename.size() + 1);
     283        2945 :             bExists = CPL_TO_BOOL(
     284        2945 :                 CPLCheckForFile(&achOvrFilename[0], papszInitSiblingFiles));
     285        2945 :             osOvrFilename = &achOvrFilename[0];
     286        2945 :             if (!bExists)
     287        2945 :                 osOvrFilename.Printf("%s.ovr", pszInitName);
     288             :         }
     289             : #endif
     290             : 
     291       11591 :         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       23167 :     if (!poODS && !EQUAL(pszInitName, ":::VIRTUAL:::") &&
     310       11392 :         GDALCanFileAcceptSidecarFile(pszInitName))
     311             :     {
     312       11390 :         bool bTryFindAssociatedAuxFile = true;
     313       11390 :         if (papszInitSiblingFiles)
     314             :         {
     315       16891 :             CPLString osAuxFilename = CPLResetExtensionSafe(pszInitName, "aux");
     316        8446 :             int iSibling = CSLFindString(papszInitSiblingFiles,
     317             :                                          CPLGetFilename(osAuxFilename));
     318        8445 :             if (iSibling < 0)
     319             :             {
     320        8441 :                 osAuxFilename = pszInitName;
     321        8442 :                 osAuxFilename += ".aux";
     322        8441 :                 iSibling = CSLFindString(papszInitSiblingFiles,
     323             :                                          CPLGetFilename(osAuxFilename));
     324        8441 :                 if (iSibling < 0)
     325        8441 :                     bTryFindAssociatedAuxFile = false;
     326             :             }
     327             :         }
     328             : 
     329       11390 :         if (bTryFindAssociatedAuxFile)
     330             :         {
     331        2949 :             poODS =
     332        2949 :                 GDALFindAssociatedAuxFile(pszInitName, poDS->GetAccess(), poDS);
     333             :         }
     334             : 
     335       11390 :         if (poODS)
     336             :         {
     337             :             const bool bUseRRD =
     338           8 :                 CPLTestBool(CPLGetConfigOption("USE_RRD", "NO"));
     339             : 
     340           8 :             bOvrIsAux = true;
     341           8 :             if (GetOverviewCount(1) == 0 && !bUseRRD)
     342             :             {
     343           1 :                 bOvrIsAux = false;
     344           1 :                 GDALClose(poODS);
     345           1 :                 poODS = nullptr;
     346             :             }
     347             :             else
     348             :             {
     349           7 :                 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       11775 :     if (poODS == nullptr)
     360             :     {
     361             :         const char *pszProxyOvrFilename =
     362       11567 :             poDS->GetMetadataItem("OVERVIEW_FILE", "OVERVIEWS");
     363             : 
     364       11566 :         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       11773 :     if (poODS)
     393             :     {
     394         225 :         const int nOverviewCount = GetOverviewCount(1);
     395             : 
     396         536 :         for (int iOver = 0; iOver < nOverviewCount; iOver++)
     397             :         {
     398         311 :             GDALRasterBand *const poBand = GetOverview(1, iOver);
     399             :             GDALDataset *const poOverDS =
     400         311 :                 poBand != nullptr ? poBand->GetDataset() : nullptr;
     401             : 
     402         311 :             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       11773 :     antiRec.oSetFiles.erase(pszInitName);
     412       11773 :     --antiRec.nRecLevel;
     413             : }
     414             : 
     415             : /************************************************************************/
     416             : /*                          GetOverviewCount()                          */
     417             : /************************************************************************/
     418             : 
     419      657162 : int GDALDefaultOverviews::GetOverviewCount(int nBand)
     420             : 
     421             : {
     422      657162 :     if (poODS == nullptr || nBand < 1 || nBand > poODS->GetRasterCount())
     423      656126 :         return 0;
     424             : 
     425        1036 :     GDALRasterBand *poBand = poODS->GetRasterBand(nBand);
     426        1036 :     if (poBand == nullptr)
     427           0 :         return 0;
     428             : 
     429        1036 :     if (bOvrIsAux)
     430          79 :         return poBand->GetOverviewCount();
     431             : 
     432         957 :     return poBand->GetOverviewCount() + 1;
     433             : }
     434             : 
     435             : /************************************************************************/
     436             : /*                            GetOverview()                             */
     437             : /************************************************************************/
     438             : 
     439        1373 : GDALRasterBand *GDALDefaultOverviews::GetOverview(int nBand, int iOverview)
     440             : 
     441             : {
     442        1373 :     if (poODS == nullptr || nBand < 1 || nBand > poODS->GetRasterCount())
     443         262 :         return nullptr;
     444             : 
     445        1111 :     GDALRasterBand *const poBand = poODS->GetRasterBand(nBand);
     446        1111 :     if (poBand == nullptr)
     447           0 :         return nullptr;
     448             : 
     449        1111 :     if (bOvrIsAux)
     450          63 :         return poBand->GetOverview(iOverview);
     451             : 
     452             :     // TIFF case, base is overview 0.
     453        1048 :     if (iOverview == 0)
     454         797 :         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         473 : 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         473 :     if (nXSize >= nYSize / 2 && !(nXSize < nYSize && nXSize < nOvLevel))
     492             :     {
     493         398 :         const int nOXSize = DIV_ROUND_UP(nXSize, nOvLevel);
     494             : 
     495         398 :         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       67460 : static int GetFloorPowerOfTwo(int n)
     508             : {
     509       67460 :     int p2 = 1;
     510      136118 :     while ((n = n >> 1) > 0)
     511             :     {
     512       68658 :         p2 <<= 1;
     513             :     }
     514       67460 :     return p2;
     515             : }
     516             : 
     517             : /************************************************************************/
     518             : /*                         GDALComputeOvFactor()                        */
     519             : /************************************************************************/
     520             : 
     521       67460 : 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       67460 :     if (nRasterXSize != 1 && nRasterXSize >= nRasterYSize / 2)
     528             :     {
     529       67346 :         const int nVal = static_cast<int>(
     530       67346 :             0.5 + nRasterXSize / static_cast<double>(nOvrXSize));
     531             :         // Try to return a power-of-two value
     532       67346 :         const int nValPowerOfTwo = GetFloorPowerOfTwo(nVal);
     533       67534 :         for (int fact = 1; fact <= 2 && nValPowerOfTwo <= INT_MAX / fact;
     534             :              ++fact)
     535             :         {
     536       67501 :             if (DIV_ROUND_UP(nRasterXSize, fact * nValPowerOfTwo) == nOvrXSize)
     537       67313 :                 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         193 : static const char *GetOptionValue(CSLConstList papszOptions,
     656             :                                   const char *pszOptionKey,
     657             :                                   const char *pszConfigOptionKey)
     658             : {
     659             :     const char *pszVal =
     660         193 :         pszOptionKey ? CSLFetchNameValue(papszOptions, pszOptionKey) : nullptr;
     661         193 :     if (pszVal)
     662             :     {
     663           0 :         return pszVal;
     664             :     }
     665         193 :     pszVal = CSLFetchNameValue(papszOptions, pszConfigOptionKey);
     666         193 :     if (pszVal)
     667             :     {
     668           3 :         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         200 : 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         200 :     if (poODS == nullptr)
     934             :     {
     935             :         const char *pszUseRRD =
     936         185 :             GetOptionValue(papszOptions, nullptr, "USE_RRD");
     937         185 :         bOvrIsAux = pszUseRRD && CPLTestBool(pszUseRRD);
     938         185 :         if (bOvrIsAux)
     939             :         {
     940             :             osOvrFilename =
     941           5 :                 CPLResetExtensionSafe(poDS->GetDescription(), "aux");
     942             : 
     943             :             VSIStatBufL sStatBuf;
     944           5 :             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         200 :     if (pszBasename == nullptr && osOvrFilename.length() == 0)
     966           0 :         pszBasename = poDS->GetDescription();
     967             : 
     968         200 :     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         200 :     return CE_None;
     977             : }
     978             : 
     979             : /************************************************************************/
     980             : /*                           BuildOverviews()                           */
     981             : /************************************************************************/
     982             : 
     983         205 : 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         205 :     if (pfnProgress == nullptr)
     991           0 :         pfnProgress = GDALDummyProgress;
     992             : 
     993         205 :     if (nOverviews == 0)
     994           9 :         return CleanOverviews();
     995             : 
     996         196 :     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         196 :     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         196 :     GDALRasterBand *poBand = poDS->GetRasterBand(1);
    1018             : 
    1019         196 :     int nNewOverviews = 0;
    1020             :     int *panNewOverviewList =
    1021         196 :         static_cast<int *>(CPLCalloc(sizeof(int), nOverviews));
    1022         196 :     double dfAreaNewOverviews = 0;
    1023         196 :     double dfAreaRefreshedOverviews = 0;
    1024         392 :     std::vector<bool> abValidLevel(nOverviews, true);
    1025         196 :     std::vector<bool> abRequireRefresh(nOverviews, false);
    1026         196 :     bool bFoundSinglePixelOverview = false;
    1027         482 :     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         302 :             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         291 :         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         270 :         if (abValidLevel[i])
    1080             :         {
    1081         270 :             const double dfArea =
    1082             :                 1.0 /
    1083         270 :                 (static_cast<double>(panOverviewList[i]) * panOverviewList[i]);
    1084         270 :             dfAreaRefreshedOverviews += dfArea;
    1085         270 :             if (!abRequireRefresh[i])
    1086             :             {
    1087         253 :                 dfAreaNewOverviews += dfArea;
    1088         253 :                 panNewOverviewList[nNewOverviews++] = panOverviewList[i];
    1089             :             }
    1090             : 
    1091         291 :             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         196 :         CPLCalloc(sizeof(GDALRasterBand *), nBands));
    1104         504 :     for (int i = 0; i < nBands; i++)
    1105         308 :         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         196 :     CPLErr eErr = CE_None;
    1115             : 
    1116         196 :     void *pScaledOverviewWithoutMask = GDALCreateScaledProgress(
    1117         196 :         0, (HaveMaskFile() && poMaskDS) ? double(nBands) / (nBands + 1) : 1,
    1118             :         pfnProgress, pProgressData);
    1119             : 
    1120         216 :     const auto AvoidZero = [](double x)
    1121             :     {
    1122         216 :         if (x == 0)
    1123           0 :             return 1.0;
    1124         216 :         return x;
    1125             :     };
    1126             : 
    1127         196 :     void *pScaledProgress = GDALCreateScaledProgress(
    1128         196 :         0, dfAreaNewOverviews / AvoidZero(dfAreaRefreshedOverviews),
    1129             :         GDALScaledProgress, pScaledOverviewWithoutMask);
    1130         196 :     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           9 :         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           6 :             CPLStringList aosOptions(papszOptions);
    1147           6 :             aosOptions.SetNameValue("LOCATION", nullptr);
    1148           6 :             aosOptions.SetNameValue("USE_RRD", nullptr);
    1149           6 :             eErr = HFAAuxBuildOverviews(
    1150             :                 osOvrFilename, poDS, &poODS, nBands, panBandList, nNewOverviews,
    1151             :                 panNewOverviewList, pszResampling, GDALScaledProgress,
    1152           6 :                 pScaledProgress, aosOptions.List());
    1153             :         }
    1154             : 
    1155             :         // HFAAuxBuildOverviews doesn't actually generate overviews
    1156           9 :         dfAreaNewOverviews = 0.0;
    1157          22 :         for (int j = 0; j < nOverviews; j++)
    1158             :         {
    1159          13 :             if (abValidLevel[j])
    1160          13 :                 abRequireRefresh[j] = true;
    1161             :         }
    1162             : #endif
    1163             :     }
    1164             : 
    1165             :     /* -------------------------------------------------------------------- */
    1166             :     /*      Build new overviews - TIFF.  Close TIFF files while we          */
    1167             :     /*      operate on it.                                                  */
    1168             :     /* -------------------------------------------------------------------- */
    1169             :     else
    1170             :     {
    1171         187 :         if (poODS != nullptr)
    1172             :         {
    1173           9 :             delete poODS;
    1174           9 :             poODS = nullptr;
    1175             :         }
    1176             : 
    1177             : #ifdef HAVE_TIFF
    1178         187 :         eErr = GTIFFBuildOverviews(
    1179             :             osOvrFilename, nBands, pahBands, nNewOverviews, panNewOverviewList,
    1180             :             pszResampling, GDALScaledProgress, pScaledProgress, papszOptions);
    1181             : 
    1182             :         // Probe for proxy overview filename.
    1183         187 :         if (eErr == CE_Failure)
    1184             :         {
    1185             :             const char *pszProxyOvrFilename =
    1186           5 :                 poDS->GetMetadataItem("FILENAME", "ProxyOverviewRequest");
    1187             : 
    1188           5 :             if (pszProxyOvrFilename != nullptr)
    1189             :             {
    1190           1 :                 osOvrFilename = pszProxyOvrFilename;
    1191           1 :                 eErr = GTIFFBuildOverviews(osOvrFilename, nBands, pahBands,
    1192             :                                            nNewOverviews, panNewOverviewList,
    1193             :                                            pszResampling, GDALScaledProgress,
    1194             :                                            pScaledProgress, papszOptions);
    1195             :             }
    1196             :         }
    1197             : 
    1198         187 :         if (eErr == CE_None)
    1199             :         {
    1200         183 :             poODS = GDALDataset::Open(osOvrFilename,
    1201             :                                       GDAL_OF_RASTER | GDAL_OF_UPDATE);
    1202         183 :             if (poODS == nullptr)
    1203           0 :                 eErr = CE_Failure;
    1204             :         }
    1205             : #else
    1206             :         CPLError(CE_Failure, CPLE_NotSupported,
    1207             :                  "Cannot build TIFF overviews due to GeoTIFF driver missing");
    1208             :         eErr = CE_Failure;
    1209             : #endif
    1210             :     }
    1211             : 
    1212         196 :     GDALDestroyScaledProgress(pScaledProgress);
    1213             : 
    1214             :     /* -------------------------------------------------------------------- */
    1215             :     /*      Refresh old overviews that were listed.                         */
    1216             :     /* -------------------------------------------------------------------- */
    1217             :     GDALRasterBand **papoOverviewBands =
    1218         196 :         static_cast<GDALRasterBand **>(CPLCalloc(sizeof(void *), nOverviews));
    1219             : 
    1220         500 :     for (int iBand = 0; iBand < nBands && eErr == CE_None; iBand++)
    1221             :     {
    1222         304 :         poBand = poDS->GetRasterBand(panBandList[iBand]);
    1223         304 :         if (poBand == nullptr)
    1224             :         {
    1225           0 :             eErr = CE_Failure;
    1226           0 :             break;
    1227             :         }
    1228             : 
    1229         304 :         nNewOverviews = 0;
    1230         608 :         std::vector<bool> abAlreadyUsedOverviewBand(poBand->GetOverviewCount(),
    1231         608 :                                                     false);
    1232             : 
    1233         765 :         for (int i = 0; i < nOverviews; i++)
    1234             :         {
    1235         461 :             if (!abValidLevel[i] || !abRequireRefresh[i])
    1236         431 :                 continue;
    1237             : 
    1238          48 :             for (int j = 0; j < poBand->GetOverviewCount(); j++)
    1239             :             {
    1240          48 :                 if (abAlreadyUsedOverviewBand[j])
    1241          16 :                     continue;
    1242             : 
    1243          32 :                 GDALRasterBand *poOverview = poBand->GetOverview(j);
    1244          32 :                 if (poOverview == nullptr)
    1245           0 :                     continue;
    1246             : 
    1247          32 :                 int bHasNoData = FALSE;
    1248          32 :                 double noDataValue = poBand->GetNoDataValue(&bHasNoData);
    1249             : 
    1250          32 :                 if (bHasNoData)
    1251           2 :                     poOverview->SetNoDataValue(noDataValue);
    1252             : 
    1253          32 :                 const int nOvFactor = GDALComputeOvFactor(
    1254             :                     poOverview->GetXSize(), poBand->GetXSize(),
    1255             :                     poOverview->GetYSize(), poBand->GetYSize());
    1256             : 
    1257          34 :                 if (nOvFactor == panOverviewList[i] ||
    1258           2 :                     nOvFactor == GDALOvLevelAdjust2(panOverviewList[i],
    1259             :                                                     poBand->GetXSize(),
    1260             :                                                     poBand->GetYSize()))
    1261             :                 {
    1262          30 :                     abAlreadyUsedOverviewBand[j] = true;
    1263          30 :                     CPLAssert(nNewOverviews < poBand->GetOverviewCount());
    1264          30 :                     papoOverviewBands[nNewOverviews++] = poOverview;
    1265          30 :                     break;
    1266             :                 }
    1267             :             }
    1268             :         }
    1269             : 
    1270         304 :         if (nNewOverviews > 0)
    1271             :         {
    1272             :             const double dfOffset =
    1273          20 :                 dfAreaNewOverviews / AvoidZero(dfAreaRefreshedOverviews);
    1274          20 :             const double dfScale = 1.0 - dfOffset;
    1275          40 :             pScaledProgress = GDALCreateScaledProgress(
    1276          20 :                 dfOffset + dfScale * iBand / nBands,
    1277          20 :                 dfOffset + dfScale * (iBand + 1) / nBands, GDALScaledProgress,
    1278             :                 pScaledOverviewWithoutMask);
    1279          20 :             eErr = GDALRegenerateOverviewsEx(
    1280             :                 GDALRasterBand::ToHandle(poBand), nNewOverviews,
    1281             :                 reinterpret_cast<GDALRasterBandH *>(papoOverviewBands),
    1282             :                 pszResampling, GDALScaledProgress, pScaledProgress,
    1283             :                 papszOptions);
    1284          20 :             GDALDestroyScaledProgress(pScaledProgress);
    1285             :         }
    1286             :     }
    1287             : 
    1288             :     /* -------------------------------------------------------------------- */
    1289             :     /*      Cleanup                                                         */
    1290             :     /* -------------------------------------------------------------------- */
    1291         196 :     CPLFree(papoOverviewBands);
    1292         196 :     CPLFree(panNewOverviewList);
    1293         196 :     CPLFree(pahBands);
    1294         196 :     GDALDestroyScaledProgress(pScaledOverviewWithoutMask);
    1295             : 
    1296             :     /* -------------------------------------------------------------------- */
    1297             :     /*      If we have a mask file, we need to build its overviews too.     */
    1298             :     /* -------------------------------------------------------------------- */
    1299         196 :     if (HaveMaskFile() && eErr == CE_None)
    1300             :     {
    1301           4 :         pScaledProgress = GDALCreateScaledProgress(
    1302           2 :             double(nBands) / (nBands + 1), 1.0, pfnProgress, pProgressData);
    1303           2 :         eErr = BuildOverviewsMask(pszResampling, nOverviews, panOverviewList,
    1304             :                                   GDALScaledProgress, pScaledProgress,
    1305             :                                   papszOptions);
    1306           2 :         GDALDestroyScaledProgress(pScaledProgress);
    1307             :     }
    1308             : 
    1309             :     /* -------------------------------------------------------------------- */
    1310             :     /*      If we have an overview dataset, then mark all the overviews     */
    1311             :     /*      with the base dataset  Used later for finding overviews         */
    1312             :     /*      masks.  Uggg.                                                   */
    1313             :     /* -------------------------------------------------------------------- */
    1314         196 :     if (poODS)
    1315             :     {
    1316         192 :         const int nOverviewCount = GetOverviewCount(1);
    1317             : 
    1318         464 :         for (int iOver = 0; iOver < nOverviewCount; iOver++)
    1319             :         {
    1320         272 :             GDALRasterBand *poOtherBand = GetOverview(1, iOver);
    1321             :             GDALDataset *poOverDS =
    1322         272 :                 poOtherBand != nullptr ? poOtherBand->GetDataset() : nullptr;
    1323             : 
    1324         272 :             if (poOverDS != nullptr)
    1325             :             {
    1326         257 :                 poOverDS->oOvManager.poBaseDS = poDS;
    1327         257 :                 poOverDS->oOvManager.poDS = poOverDS;
    1328             :             }
    1329             :         }
    1330             :     }
    1331             : 
    1332         196 :     return eErr;
    1333             : }
    1334             : 
    1335             : /************************************************************************/
    1336             : /*                          BuildOverviewsMask()                        */
    1337             : /************************************************************************/
    1338             : 
    1339           4 : CPLErr GDALDefaultOverviews::BuildOverviewsMask(const char *pszResampling,
    1340             :                                                 int nOverviews,
    1341             :                                                 const int *panOverviewList,
    1342             :                                                 GDALProgressFunc pfnProgress,
    1343             :                                                 void *pProgressData,
    1344             :                                                 CSLConstList papszOptions)
    1345             : {
    1346           4 :     CPLErr eErr = CE_None;
    1347           4 :     if (HaveMaskFile() && poMaskDS)
    1348             :     {
    1349             :         // Some options are not compatible with mask overviews
    1350             :         // so unset them, and define more sensible values.
    1351           4 :         CPLStringList aosMaskOptions(papszOptions);
    1352             :         const char *pszCompress =
    1353           4 :             GetOptionValue(papszOptions, "COMPRESS", "COMPRESS_OVERVIEW");
    1354           4 :         const bool bJPEG = pszCompress && EQUAL(pszCompress, "JPEG");
    1355             :         const char *pszPhotometric =
    1356           4 :             GetOptionValue(papszOptions, "PHOTOMETRIC", "PHOTOMETRIC_OVERVIEW");
    1357           4 :         const bool bPHOTOMETRIC_YCBCR =
    1358           4 :             pszPhotometric && EQUAL(pszPhotometric, "YCBCR");
    1359           4 :         if (bJPEG)
    1360           0 :             aosMaskOptions.SetNameValue("COMPRESS", "DEFLATE");
    1361           4 :         if (bPHOTOMETRIC_YCBCR)
    1362           0 :             aosMaskOptions.SetNameValue("PHOTOMETRIC", "MINISBLACK");
    1363             : 
    1364           4 :         eErr = poMaskDS->BuildOverviews(
    1365             :             pszResampling, nOverviews, panOverviewList, 0, nullptr, pfnProgress,
    1366           4 :             pProgressData, aosMaskOptions.List());
    1367             : 
    1368           4 :         if (bOwnMaskDS)
    1369             :         {
    1370             :             // Reset the poMask member of main dataset bands, since it
    1371             :             // will become invalid after poMaskDS closing.
    1372          10 :             for (int iBand = 1; iBand <= poDS->GetRasterCount(); iBand++)
    1373             :             {
    1374           6 :                 GDALRasterBand *poOtherBand = poDS->GetRasterBand(iBand);
    1375           6 :                 if (poOtherBand != nullptr)
    1376           6 :                     poOtherBand->InvalidateMaskBand();
    1377             :             }
    1378             : 
    1379           4 :             GDALClose(poMaskDS);
    1380             :         }
    1381             : 
    1382             :         // force next request to reread mask file.
    1383           4 :         poMaskDS = nullptr;
    1384           4 :         bOwnMaskDS = false;
    1385           4 :         bCheckedForMask = false;
    1386             :     }
    1387             : 
    1388           4 :     return eErr;
    1389             : }
    1390             : 
    1391             : /************************************************************************/
    1392             : /*                           CreateMaskBand()                           */
    1393             : /************************************************************************/
    1394             : 
    1395          27 : CPLErr GDALDefaultOverviews::CreateMaskBand(int nFlags, int nBand)
    1396             : 
    1397             : {
    1398          27 :     if (nBand < 1)
    1399          17 :         nFlags |= GMF_PER_DATASET;
    1400             : 
    1401             :     /* -------------------------------------------------------------------- */
    1402             :     /*      ensure existing file gets opened if there is one.               */
    1403             :     /* -------------------------------------------------------------------- */
    1404          27 :     CPL_IGNORE_RET_VAL(HaveMaskFile());
    1405             : 
    1406             :     /* -------------------------------------------------------------------- */
    1407             :     /*      Try creating the mask file.                                     */
    1408             :     /* -------------------------------------------------------------------- */
    1409          27 :     if (poMaskDS == nullptr)
    1410             :     {
    1411             :         GDALDriver *const poDr =
    1412          22 :             static_cast<GDALDriver *>(GDALGetDriverByName("GTiff"));
    1413             : 
    1414          22 :         if (poDr == nullptr)
    1415           0 :             return CE_Failure;
    1416             : 
    1417          22 :         GDALRasterBand *const poTBand = poDS->GetRasterBand(1);
    1418          22 :         if (poTBand == nullptr)
    1419           0 :             return CE_Failure;
    1420             : 
    1421             :         const int nBands =
    1422          22 :             (nFlags & GMF_PER_DATASET) ? 1 : poDS->GetRasterCount();
    1423             : 
    1424          22 :         char **papszOpt = CSLSetNameValue(nullptr, "COMPRESS", "DEFLATE");
    1425          22 :         papszOpt = CSLSetNameValue(papszOpt, "INTERLEAVE", "BAND");
    1426             : 
    1427          22 :         int nBX = 0;
    1428          22 :         int nBY = 0;
    1429          22 :         poTBand->GetBlockSize(&nBX, &nBY);
    1430             : 
    1431             :         // Try to create matching tile size if legal in TIFF.
    1432          22 :         if ((nBX % 16) == 0 && (nBY % 16) == 0)
    1433             :         {
    1434           2 :             papszOpt = CSLSetNameValue(papszOpt, "TILED", "YES");
    1435           2 :             papszOpt = CSLSetNameValue(papszOpt, "BLOCKXSIZE",
    1436           4 :                                        CPLString().Printf("%d", nBX));
    1437           2 :             papszOpt = CSLSetNameValue(papszOpt, "BLOCKYSIZE",
    1438           4 :                                        CPLString().Printf("%d", nBY));
    1439             :         }
    1440             : 
    1441          22 :         CPLString osMskFilename;
    1442          22 :         osMskFilename.Printf("%s.msk", poDS->GetDescription());
    1443          22 :         poMaskDS =
    1444          22 :             poDr->Create(osMskFilename, poDS->GetRasterXSize(),
    1445          22 :                          poDS->GetRasterYSize(), nBands, GDT_Byte, papszOpt);
    1446          22 :         CSLDestroy(papszOpt);
    1447             : 
    1448          22 :         if (poMaskDS == nullptr)  // Presumably error already issued.
    1449           0 :             return CE_Failure;
    1450             : 
    1451          22 :         bOwnMaskDS = true;
    1452             :     }
    1453             : 
    1454             :     /* -------------------------------------------------------------------- */
    1455             :     /*      Save the mask flags for this band.                              */
    1456             :     /* -------------------------------------------------------------------- */
    1457          27 :     if (nBand > poMaskDS->GetRasterCount())
    1458             :     {
    1459           1 :         CPLError(CE_Failure, CPLE_AppDefined,
    1460             :                  "Attempt to create a mask band for band %d of %s, "
    1461             :                  "but the .msk file has a PER_DATASET mask.",
    1462           1 :                  nBand, poDS->GetDescription());
    1463           1 :         return CE_Failure;
    1464             :     }
    1465             : 
    1466          69 :     for (int iBand = 0; iBand < poDS->GetRasterCount(); iBand++)
    1467             :     {
    1468             :         // we write only the info for this band, unless we are
    1469             :         // using PER_DATASET in which case we write for all.
    1470          43 :         if (nBand != iBand + 1 && !(nFlags & GMF_PER_DATASET))
    1471           6 :             continue;
    1472             : 
    1473          37 :         poMaskDS->SetMetadataItem(
    1474          74 :             CPLString().Printf("INTERNAL_MASK_FLAGS_%d", iBand + 1),
    1475          74 :             CPLString().Printf("%d", nFlags));
    1476             :     }
    1477             : 
    1478          26 :     return CE_None;
    1479             : }
    1480             : 
    1481             : /************************************************************************/
    1482             : /*                            GetMaskBand()                             */
    1483             : /************************************************************************/
    1484             : 
    1485             : // Secret code meaning we don't handle this band.
    1486             : constexpr int MISSING_FLAGS = 0x8000;
    1487             : 
    1488          47 : GDALRasterBand *GDALDefaultOverviews::GetMaskBand(int nBand)
    1489             : 
    1490             : {
    1491          47 :     const int nFlags = GetMaskFlags(nBand);
    1492             : 
    1493          47 :     if (poMaskDS == nullptr || nFlags == MISSING_FLAGS)
    1494           1 :         return nullptr;
    1495             : 
    1496          46 :     if (nFlags & GMF_PER_DATASET)
    1497          36 :         return poMaskDS->GetRasterBand(1);
    1498             : 
    1499          10 :     if (nBand > 0)
    1500          10 :         return poMaskDS->GetRasterBand(nBand);
    1501             : 
    1502           0 :     return nullptr;
    1503             : }
    1504             : 
    1505             : /************************************************************************/
    1506             : /*                            GetMaskFlags()                            */
    1507             : /************************************************************************/
    1508             : 
    1509          92 : int GDALDefaultOverviews::GetMaskFlags(int nBand)
    1510             : 
    1511             : {
    1512             :     /* -------------------------------------------------------------------- */
    1513             :     /*      Fetch this band's metadata entry.  They are of the form:        */
    1514             :     /*        INTERNAL_MASK_FLAGS_n: flags                                  */
    1515             :     /* -------------------------------------------------------------------- */
    1516          92 :     if (!HaveMaskFile())
    1517           0 :         return 0;
    1518             : 
    1519          92 :     const char *pszValue = poMaskDS->GetMetadataItem(
    1520         184 :         CPLString().Printf("INTERNAL_MASK_FLAGS_%d", std::max(nBand, 1)));
    1521             : 
    1522          92 :     if (pszValue == nullptr)
    1523           1 :         return MISSING_FLAGS;
    1524             : 
    1525          91 :     return atoi(pszValue);
    1526             : }
    1527             : 
    1528             : /************************************************************************/
    1529             : /*                            HaveMaskFile()                            */
    1530             : /*                                                                      */
    1531             : /*      Check for a mask file if we haven't already done so.            */
    1532             : /*      Returns TRUE if we have one, otherwise FALSE.                   */
    1533             : /************************************************************************/
    1534             : 
    1535      103253 : int GDALDefaultOverviews::HaveMaskFile(char **papszSiblingFiles,
    1536             :                                        const char *pszBasename)
    1537             : 
    1538             : {
    1539             :     /* -------------------------------------------------------------------- */
    1540             :     /*      Have we already checked for masks?                              */
    1541             :     /* -------------------------------------------------------------------- */
    1542      103253 :     if (bCheckedForMask)
    1543        3918 :         return poMaskDS != nullptr;
    1544             : 
    1545       99335 :     if (papszSiblingFiles == nullptr)
    1546       99336 :         papszSiblingFiles = papszInitSiblingFiles;
    1547             : 
    1548             :     /* -------------------------------------------------------------------- */
    1549             :     /*      Are we an overview?  If so we need to find the corresponding    */
    1550             :     /*      overview in the base files mask file (if there is one).         */
    1551             :     /* -------------------------------------------------------------------- */
    1552       99335 :     if (poBaseDS != nullptr && poBaseDS->oOvManager.HaveMaskFile())
    1553             :     {
    1554           4 :         GDALRasterBand *const poBaseBand = poBaseDS->GetRasterBand(1);
    1555           4 :         GDALDataset *poMaskDSTemp = nullptr;
    1556           4 :         if (poBaseBand != nullptr)
    1557             :         {
    1558           4 :             GDALRasterBand *poBaseMask = poBaseBand->GetMaskBand();
    1559           4 :             if (poBaseMask != nullptr)
    1560             :             {
    1561           4 :                 const int nOverviewCount = poBaseMask->GetOverviewCount();
    1562           6 :                 for (int iOver = 0; iOver < nOverviewCount; iOver++)
    1563             :                 {
    1564             :                     GDALRasterBand *const poOverBand =
    1565           6 :                         poBaseMask->GetOverview(iOver);
    1566           6 :                     if (poOverBand == nullptr)
    1567           0 :                         continue;
    1568             : 
    1569          10 :                     if (poOverBand->GetXSize() == poDS->GetRasterXSize() &&
    1570           4 :                         poOverBand->GetYSize() == poDS->GetRasterYSize())
    1571             :                     {
    1572           4 :                         poMaskDSTemp = poOverBand->GetDataset();
    1573           4 :                         break;
    1574             :                     }
    1575             :                 }
    1576             :             }
    1577             :         }
    1578             : 
    1579           4 :         if (poMaskDSTemp != poDS)
    1580             :         {
    1581           4 :             poMaskDS = poMaskDSTemp;
    1582           4 :             bCheckedForMask = true;
    1583           4 :             bOwnMaskDS = false;
    1584             : 
    1585           4 :             return poMaskDS != nullptr;
    1586             :         }
    1587             :     }
    1588             : 
    1589             :     /* -------------------------------------------------------------------- */
    1590             :     /*      Are we even initialized?  If not, we apparently don't want      */
    1591             :     /*      to support overviews and masks.                                 */
    1592             :     /* -------------------------------------------------------------------- */
    1593       99331 :     if (poDS == nullptr)
    1594       88878 :         return FALSE;
    1595             : 
    1596             :     /* -------------------------------------------------------------------- */
    1597             :     /*      Check for .msk file.                                            */
    1598             :     /* -------------------------------------------------------------------- */
    1599       10453 :     bCheckedForMask = true;
    1600             : 
    1601       10453 :     if (pszBasename == nullptr)
    1602       10454 :         pszBasename = poDS->GetDescription();
    1603             : 
    1604             :     // Don't bother checking for masks of masks.
    1605       10453 :     if (EQUAL(CPLGetExtensionSafe(pszBasename).c_str(), "msk"))
    1606          18 :         return FALSE;
    1607             : 
    1608       10435 :     if (!GDALCanFileAcceptSidecarFile(pszBasename))
    1609           1 :         return FALSE;
    1610       20870 :     CPLString osMskFilename;
    1611       10435 :     osMskFilename.Printf("%s.msk", pszBasename);
    1612             : 
    1613       20869 :     std::vector<char> achMskFilename;
    1614       10435 :     achMskFilename.resize(osMskFilename.size() + 1);
    1615       10434 :     memcpy(&(achMskFilename[0]), osMskFilename.c_str(),
    1616       10435 :            osMskFilename.size() + 1);
    1617             :     bool bExists =
    1618       10434 :         CPL_TO_BOOL(CPLCheckForFile(&achMskFilename[0], papszSiblingFiles));
    1619       10434 :     osMskFilename = &achMskFilename[0];
    1620             : 
    1621             : #if !defined(_WIN32)
    1622       10435 :     if (!bExists && !papszSiblingFiles)
    1623             :     {
    1624        2249 :         osMskFilename.Printf("%s.MSK", pszBasename);
    1625        2249 :         memcpy(&(achMskFilename[0]), osMskFilename.c_str(),
    1626        2249 :                osMskFilename.size() + 1);
    1627             :         bExists =
    1628        2249 :             CPL_TO_BOOL(CPLCheckForFile(&achMskFilename[0], papszSiblingFiles));
    1629        2249 :         osMskFilename = &achMskFilename[0];
    1630             :     }
    1631             : #endif
    1632             : 
    1633       10434 :     if (!bExists)
    1634       10399 :         return FALSE;
    1635             : 
    1636             :     /* -------------------------------------------------------------------- */
    1637             :     /*      Open the file.                                                  */
    1638             :     /* -------------------------------------------------------------------- */
    1639          35 :     poMaskDS = GDALDataset::Open(
    1640             :         osMskFilename,
    1641          35 :         GDAL_OF_RASTER | (poDS->GetAccess() == GA_Update ? GDAL_OF_UPDATE : 0),
    1642          35 :         nullptr, nullptr, papszInitSiblingFiles);
    1643          35 :     CPLAssert(poMaskDS != poDS);
    1644             : 
    1645          35 :     if (poMaskDS == nullptr)
    1646           1 :         return FALSE;
    1647             : 
    1648          34 :     bOwnMaskDS = true;
    1649             : 
    1650          34 :     return TRUE;
    1651             : }
    1652             : 
    1653             : /************************************************************************/
    1654             : /*                    GDALGetNormalizedOvrResampling()                  */
    1655             : /************************************************************************/
    1656             : 
    1657         982 : std::string GDALGetNormalizedOvrResampling(const char *pszResampling)
    1658             : {
    1659         982 :     if (pszResampling &&
    1660         982 :         EQUAL(pszResampling, "AVERAGE_BIT2GRAYSCALE_MINISWHITE"))
    1661           0 :         return "AVERAGE_BIT2GRAYSCALE_MINISWHITE";
    1662         982 :     else if (pszResampling && STARTS_WITH_CI(pszResampling, "AVERAGE_BIT2"))
    1663           8 :         return "AVERAGE_BIT2GRAYSCALE";
    1664         974 :     else if (pszResampling && STARTS_WITH_CI(pszResampling, "NEAR"))
    1665         419 :         return "NEAREST";
    1666         555 :     else if (pszResampling && EQUAL(pszResampling, "AVERAGE_MAGPHASE"))
    1667           0 :         return "AVERAGE_MAGPHASE";
    1668         555 :     else if (pszResampling && STARTS_WITH_CI(pszResampling, "AVER"))
    1669         258 :         return "AVERAGE";
    1670         297 :     else if (pszResampling && !EQUAL(pszResampling, "NONE"))
    1671             :     {
    1672         334 :         return CPLString(pszResampling).toupper();
    1673             :     }
    1674         130 :     return std::string();
    1675             : }
    1676             : 
    1677             : //! @endcond

Generated by: LCOV version 1.14