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

Generated by: LCOV version 1.14