LCOV - code coverage report
Current view: top level - gcore - gdaldefaultoverviews.cpp (source / functions) Hit Total Coverage
Test: gdal_filtered.info Lines: 677 751 90.1 %
Date: 2026-06-23 23:27:26 Functions: 31 33 93.9 %

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

Generated by: LCOV version 1.14