LCOV - code coverage report
Current view: top level - gcore - gdaldefaultoverviews.cpp (source / functions) Hit Total Coverage
Test: gdal_filtered.info Lines: 507 554 91.5 %
Date: 2025-01-18 12:42:00 Functions: 25 26 96.2 %

          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 <set>
      24             : #include <string>
      25             : #include <vector>
      26             : 
      27             : #include "cpl_conv.h"
      28             : #include "cpl_error.h"
      29             : #include "cpl_progress.h"
      30             : #include "cpl_string.h"
      31             : #include "cpl_vsi.h"
      32             : #include "gdal.h"
      33             : 
      34             : //! @cond Doxygen_Suppress
      35             : /************************************************************************/
      36             : /*                        GDALDefaultOverviews()                        */
      37             : /************************************************************************/
      38             : 
      39      130322 : GDALDefaultOverviews::GDALDefaultOverviews()
      40             :     : poDS(nullptr), poODS(nullptr), bOvrIsAux(false), bCheckedForMask(false),
      41             :       bOwnMaskDS(false), poMaskDS(nullptr), poBaseDS(nullptr),
      42             :       bCheckedForOverviews(FALSE), pszInitName(nullptr), bInitNameIsOVR(false),
      43      130322 :       papszInitSiblingFiles(nullptr)
      44             : {
      45      130253 : }
      46             : 
      47             : /************************************************************************/
      48             : /*                       ~GDALDefaultOverviews()                        */
      49             : /************************************************************************/
      50             : 
      51      130325 : GDALDefaultOverviews::~GDALDefaultOverviews()
      52             : 
      53             : {
      54      130332 :     CPLFree(pszInitName);
      55      130330 :     CSLDestroy(papszInitSiblingFiles);
      56             : 
      57      130327 :     CloseDependentDatasets();
      58      130323 : }
      59             : 
      60             : /************************************************************************/
      61             : /*                       CloseDependentDatasets()                       */
      62             : /************************************************************************/
      63             : 
      64      149272 : int GDALDefaultOverviews::CloseDependentDatasets()
      65             : {
      66      149272 :     bool bHasDroppedRef = false;
      67      149272 :     if (poODS != nullptr)
      68             :     {
      69         374 :         bHasDroppedRef = true;
      70         374 :         poODS->FlushCache(true);
      71         374 :         GDALClose(poODS);
      72         371 :         poODS = nullptr;
      73             :     }
      74             : 
      75      149269 :     if (poMaskDS != nullptr)
      76             :     {
      77          57 :         if (bOwnMaskDS)
      78             :         {
      79          53 :             bHasDroppedRef = true;
      80          53 :             poMaskDS->FlushCache(true);
      81          53 :             GDALClose(poMaskDS);
      82             :         }
      83          57 :         poMaskDS = nullptr;
      84             :     }
      85             : 
      86      149269 :     return bHasDroppedRef;
      87             : }
      88             : 
      89             : /************************************************************************/
      90             : /*                           IsInitialized()                            */
      91             : /*                                                                      */
      92             : /*      Returns TRUE if we are initialized.                             */
      93             : /************************************************************************/
      94             : 
      95      666158 : int GDALDefaultOverviews::IsInitialized()
      96             : 
      97             : {
      98      666158 :     OverviewScan();
      99      666158 :     return poDS != nullptr;
     100             : }
     101             : 
     102             : /************************************************************************/
     103             : /*                             Initialize()                             */
     104             : /************************************************************************/
     105             : 
     106       45590 : void GDALDefaultOverviews::Initialize(GDALDataset *poDSIn,
     107             :                                       const char *pszBasename,
     108             :                                       CSLConstList papszSiblingFiles,
     109             :                                       bool bNameIsOVR)
     110             : 
     111             : {
     112       45590 :     poDS = poDSIn;
     113             : 
     114             :     /* -------------------------------------------------------------------- */
     115             :     /*      If we were already initialized, destroy the old overview        */
     116             :     /*      file handle.                                                    */
     117             :     /* -------------------------------------------------------------------- */
     118       45590 :     if (poODS != nullptr)
     119             :     {
     120           0 :         GDALClose(poODS);
     121           0 :         poODS = nullptr;
     122             : 
     123           0 :         CPLDebug("GDAL", "GDALDefaultOverviews::Initialize() called twice - "
     124             :                          "this is odd and perhaps dangerous!");
     125             :     }
     126             : 
     127             :     /* -------------------------------------------------------------------- */
     128             :     /*      Store the initialization information for later use in           */
     129             :     /*      OverviewScan()                                                  */
     130             :     /* -------------------------------------------------------------------- */
     131       45590 :     bCheckedForOverviews = FALSE;
     132             : 
     133       45590 :     CPLFree(pszInitName);
     134       45517 :     pszInitName = nullptr;
     135       45517 :     if (pszBasename != nullptr)
     136       45296 :         pszInitName = CPLStrdup(pszBasename);
     137       45648 :     bInitNameIsOVR = bNameIsOVR;
     138             : 
     139       45648 :     CSLDestroy(papszInitSiblingFiles);
     140       45578 :     papszInitSiblingFiles = nullptr;
     141       45578 :     if (papszSiblingFiles != nullptr)
     142        5711 :         papszInitSiblingFiles = CSLDuplicate(papszSiblingFiles);
     143       45578 : }
     144             : 
     145             : /************************************************************************/
     146             : /*                             Initialize()                             */
     147             : /************************************************************************/
     148             : 
     149             : /** Initialize the GDALDefaultOverviews instance.
     150             :  *
     151             :  * @param poDSIn Base dataset.
     152             :  * @param poOpenInfo Open info instance. Must not be NULL.
     153             :  * @param pszName Base dataset name. If set to NULL, poOpenInfo->pszFilename is
     154             :  *                used.
     155             :  * @param bTransferSiblingFilesIfLoaded Whether sibling files of poOpenInfo
     156             :  *                                      should be transferred to this
     157             :  *                                      GDALDefaultOverviews instance, if they
     158             :  *                                      have bean already loaded.
     159             :  * @since 3.10
     160             :  */
     161       28133 : void GDALDefaultOverviews::Initialize(GDALDataset *poDSIn,
     162             :                                       GDALOpenInfo *poOpenInfo,
     163             :                                       const char *pszName,
     164             :                                       bool bTransferSiblingFilesIfLoaded)
     165             : {
     166       28133 :     Initialize(poDSIn, pszName ? pszName : poOpenInfo->pszFilename);
     167             : 
     168       28048 :     if (bTransferSiblingFilesIfLoaded && poOpenInfo->AreSiblingFilesLoaded())
     169        8432 :         TransferSiblingFiles(poOpenInfo->StealSiblingFiles());
     170       28048 : }
     171             : 
     172             : /************************************************************************/
     173             : /*                         TransferSiblingFiles()                       */
     174             : /*                                                                      */
     175             : /*      Contrary to Initialize(), this sets papszInitSiblingFiles but   */
     176             : /*      without duplicating the passed list. Which must be              */
     177             : /*      "de-allocatable" with CSLDestroy()                              */
     178             : /************************************************************************/
     179             : 
     180       21922 : void GDALDefaultOverviews::TransferSiblingFiles(char **papszSiblingFiles)
     181             : {
     182       21922 :     CSLDestroy(papszInitSiblingFiles);
     183       21922 :     papszInitSiblingFiles = papszSiblingFiles;
     184       21922 : }
     185             : 
     186             : namespace
     187             : {
     188             : // Prevent infinite recursion.
     189             : struct AntiRecursionStructDefaultOvr
     190             : {
     191             :     int nRecLevel = 0;
     192             :     std::set<CPLString> oSetFiles{};
     193             : };
     194             : }  // namespace
     195             : 
     196         361 : static void FreeAntiRecursionDefaultOvr(void *pData)
     197             : {
     198         361 :     delete static_cast<AntiRecursionStructDefaultOvr *>(pData);
     199         361 : }
     200             : 
     201       11182 : static AntiRecursionStructDefaultOvr &GetAntiRecursionDefaultOvr()
     202             : {
     203       11182 :     static AntiRecursionStructDefaultOvr dummy;
     204       11182 :     int bMemoryErrorOccurred = false;
     205             :     void *pData =
     206       11182 :         CPLGetTLSEx(CTLS_GDALDEFAULTOVR_ANTIREC, &bMemoryErrorOccurred);
     207       11182 :     if (bMemoryErrorOccurred)
     208             :     {
     209           0 :         return dummy;
     210             :     }
     211       11182 :     if (pData == nullptr)
     212             :     {
     213         430 :         auto pAntiRecursion = new AntiRecursionStructDefaultOvr();
     214         430 :         CPLSetTLSWithFreeFuncEx(CTLS_GDALDEFAULTOVR_ANTIREC, pAntiRecursion,
     215             :                                 FreeAntiRecursionDefaultOvr,
     216             :                                 &bMemoryErrorOccurred);
     217         430 :         if (bMemoryErrorOccurred)
     218             :         {
     219           0 :             delete pAntiRecursion;
     220           0 :             return dummy;
     221             :         }
     222         430 :         return *pAntiRecursion;
     223             :     }
     224       10752 :     return *static_cast<AntiRecursionStructDefaultOvr *>(pData);
     225             : }
     226             : 
     227             : /************************************************************************/
     228             : /*                            OverviewScan()                            */
     229             : /*                                                                      */
     230             : /*      This is called to scan for overview files when a first          */
     231             : /*      request is made with regard to overviews.  It uses the          */
     232             : /*      pszInitName, bInitNameIsOVR and papszInitSiblingFiles           */
     233             : /*      information that was stored at Initialization() time.           */
     234             : /************************************************************************/
     235             : 
     236      666158 : void GDALDefaultOverviews::OverviewScan()
     237             : 
     238             : {
     239      666158 :     if (bCheckedForOverviews || poDS == nullptr)
     240      654976 :         return;
     241             : 
     242       11182 :     bCheckedForOverviews = true;
     243       11182 :     if (pszInitName == nullptr)
     244          12 :         pszInitName = CPLStrdup(poDS->GetDescription());
     245             : 
     246       11182 :     AntiRecursionStructDefaultOvr &antiRec = GetAntiRecursionDefaultOvr();
     247             :     // 32 should be enough to handle a .ovr.ovr.ovr...
     248       11182 :     if (antiRec.nRecLevel == 32)
     249           0 :         return;
     250       11182 :     if (antiRec.oSetFiles.find(pszInitName) != antiRec.oSetFiles.end())
     251           0 :         return;
     252       11182 :     antiRec.oSetFiles.insert(pszInitName);
     253       11182 :     ++antiRec.nRecLevel;
     254             : 
     255       11182 :     CPLDebug("GDAL", "GDALDefaultOverviews::OverviewScan()");
     256             : 
     257             :     /* -------------------------------------------------------------------- */
     258             :     /*      Open overview dataset if it exists.                             */
     259             :     /* -------------------------------------------------------------------- */
     260       22182 :     if (!EQUAL(pszInitName, ":::VIRTUAL:::") &&
     261       11000 :         GDALCanFileAcceptSidecarFile(pszInitName))
     262             :     {
     263       10998 :         if (bInitNameIsOVR)
     264           0 :             osOvrFilename = pszInitName;
     265             :         else
     266       10998 :             osOvrFilename.Printf("%s.ovr", pszInitName);
     267             : 
     268       21996 :         std::vector<char> achOvrFilename;
     269       10998 :         achOvrFilename.resize(osOvrFilename.size() + 1);
     270       10998 :         memcpy(&(achOvrFilename[0]), osOvrFilename.c_str(),
     271       10998 :                osOvrFilename.size() + 1);
     272       10998 :         bool bExists = CPL_TO_BOOL(
     273       10998 :             CPLCheckForFile(&achOvrFilename[0], papszInitSiblingFiles));
     274       10998 :         osOvrFilename = &achOvrFilename[0];
     275             : 
     276             : #if !defined(_WIN32)
     277       10998 :         if (!bInitNameIsOVR && !bExists && !papszInitSiblingFiles)
     278             :         {
     279        2660 :             osOvrFilename.Printf("%s.OVR", pszInitName);
     280        2660 :             memcpy(&(achOvrFilename[0]), osOvrFilename.c_str(),
     281        2660 :                    osOvrFilename.size() + 1);
     282        2660 :             bExists = CPL_TO_BOOL(
     283        2660 :                 CPLCheckForFile(&achOvrFilename[0], papszInitSiblingFiles));
     284        2660 :             osOvrFilename = &achOvrFilename[0];
     285        2660 :             if (!bExists)
     286        2660 :                 osOvrFilename.Printf("%s.ovr", pszInitName);
     287             :         }
     288             : #endif
     289             : 
     290       10998 :         if (bExists)
     291             :         {
     292         188 :             poODS = GDALDataset::Open(
     293             :                 osOvrFilename,
     294             :                 GDAL_OF_RASTER |
     295         188 :                     (poDS->GetAccess() == GA_Update ? GDAL_OF_UPDATE : 0),
     296         188 :                 nullptr, nullptr, papszInitSiblingFiles);
     297             :         }
     298             :     }
     299             : 
     300             :     /* -------------------------------------------------------------------- */
     301             :     /*      We didn't find that, so try and find a corresponding aux        */
     302             :     /*      file.  Check that we are the dependent file of the aux          */
     303             :     /*      file.                                                           */
     304             :     /*                                                                      */
     305             :     /*      We only use the .aux file for overviews if they already have    */
     306             :     /*      overviews existing, or if USE_RRD is set true.                  */
     307             :     /* -------------------------------------------------------------------- */
     308       21995 :     if (!poODS && !EQUAL(pszInitName, ":::VIRTUAL:::") &&
     309       10813 :         GDALCanFileAcceptSidecarFile(pszInitName))
     310             :     {
     311       10811 :         bool bTryFindAssociatedAuxFile = true;
     312       10811 :         if (papszInitSiblingFiles)
     313             :         {
     314       16302 :             CPLString osAuxFilename = CPLResetExtensionSafe(pszInitName, "aux");
     315        8151 :             int iSibling = CSLFindString(papszInitSiblingFiles,
     316             :                                          CPLGetFilename(osAuxFilename));
     317        8151 :             if (iSibling < 0)
     318             :             {
     319        8147 :                 osAuxFilename = pszInitName;
     320        8147 :                 osAuxFilename += ".aux";
     321        8147 :                 iSibling = CSLFindString(papszInitSiblingFiles,
     322             :                                          CPLGetFilename(osAuxFilename));
     323        8147 :                 if (iSibling < 0)
     324        8147 :                     bTryFindAssociatedAuxFile = false;
     325             :             }
     326             :         }
     327             : 
     328       10811 :         if (bTryFindAssociatedAuxFile)
     329             :         {
     330        2664 :             poODS =
     331        2664 :                 GDALFindAssociatedAuxFile(pszInitName, poDS->GetAccess(), poDS);
     332             :         }
     333             : 
     334       10811 :         if (poODS)
     335             :         {
     336             :             const bool bUseRRD =
     337           8 :                 CPLTestBool(CPLGetConfigOption("USE_RRD", "NO"));
     338             : 
     339           8 :             bOvrIsAux = true;
     340           8 :             if (GetOverviewCount(1) == 0 && !bUseRRD)
     341             :             {
     342           1 :                 bOvrIsAux = false;
     343           1 :                 GDALClose(poODS);
     344           1 :                 poODS = nullptr;
     345             :             }
     346             :             else
     347             :             {
     348           7 :                 osOvrFilename = poODS->GetDescription();
     349             :             }
     350             :         }
     351             :     }
     352             : 
     353             :     /* -------------------------------------------------------------------- */
     354             :     /*      If we still don't have an overview, check to see if we have     */
     355             :     /*      overview metadata referencing a remote (i.e. proxy) or local    */
     356             :     /*      subdataset overview dataset.                                    */
     357             :     /* -------------------------------------------------------------------- */
     358       11182 :     if (poODS == nullptr)
     359             :     {
     360             :         const char *pszProxyOvrFilename =
     361       10988 :             poDS->GetMetadataItem("OVERVIEW_FILE", "OVERVIEWS");
     362             : 
     363       10988 :         if (pszProxyOvrFilename != nullptr)
     364             :         {
     365          31 :             if (STARTS_WITH_CI(pszProxyOvrFilename, ":::BASE:::"))
     366             :             {
     367           0 :                 const CPLString osPath = CPLGetPathSafe(poDS->GetDescription());
     368             : 
     369           0 :                 osOvrFilename = CPLFormFilenameSafe(
     370           0 :                     osPath, pszProxyOvrFilename + 10, nullptr);
     371             :             }
     372             :             else
     373             :             {
     374          31 :                 osOvrFilename = pszProxyOvrFilename;
     375             :             }
     376             : 
     377          31 :             CPLPushErrorHandler(CPLQuietErrorHandler);
     378          31 :             poODS = GDALDataset::Open(
     379             :                 osOvrFilename,
     380             :                 GDAL_OF_RASTER |
     381          31 :                     (poDS->GetAccess() == GA_Update ? GDAL_OF_UPDATE : 0));
     382          31 :             CPLPopErrorHandler();
     383             :         }
     384             :     }
     385             : 
     386             :     /* -------------------------------------------------------------------- */
     387             :     /*      If we have an overview dataset, then mark all the overviews     */
     388             :     /*      with the base dataset  Used later for finding overviews         */
     389             :     /*      masks.  Uggg.                                                   */
     390             :     /* -------------------------------------------------------------------- */
     391       11182 :     if (poODS)
     392             :     {
     393         212 :         const int nOverviewCount = GetOverviewCount(1);
     394             : 
     395         508 :         for (int iOver = 0; iOver < nOverviewCount; iOver++)
     396             :         {
     397         296 :             GDALRasterBand *const poBand = GetOverview(1, iOver);
     398             :             GDALDataset *const poOverDS =
     399         296 :                 poBand != nullptr ? poBand->GetDataset() : nullptr;
     400             : 
     401         296 :             if (poOverDS != nullptr)
     402             :             {
     403         282 :                 poOverDS->oOvManager.poBaseDS = poDS;
     404         282 :                 poOverDS->oOvManager.poDS = poOverDS;
     405             :             }
     406             :         }
     407             :     }
     408             : 
     409             :     // Undo anti recursion protection
     410       11182 :     antiRec.oSetFiles.erase(pszInitName);
     411       11182 :     --antiRec.nRecLevel;
     412             : }
     413             : 
     414             : /************************************************************************/
     415             : /*                          GetOverviewCount()                          */
     416             : /************************************************************************/
     417             : 
     418      655928 : int GDALDefaultOverviews::GetOverviewCount(int nBand)
     419             : 
     420             : {
     421      655928 :     if (poODS == nullptr || nBand < 1 || nBand > poODS->GetRasterCount())
     422      654955 :         return 0;
     423             : 
     424         973 :     GDALRasterBand *poBand = poODS->GetRasterBand(nBand);
     425         973 :     if (poBand == nullptr)
     426           0 :         return 0;
     427             : 
     428         973 :     if (bOvrIsAux)
     429          74 :         return poBand->GetOverviewCount();
     430             : 
     431         899 :     return poBand->GetOverviewCount() + 1;
     432             : }
     433             : 
     434             : /************************************************************************/
     435             : /*                            GetOverview()                             */
     436             : /************************************************************************/
     437             : 
     438        1292 : GDALRasterBand *GDALDefaultOverviews::GetOverview(int nBand, int iOverview)
     439             : 
     440             : {
     441        1292 :     if (poODS == nullptr || nBand < 1 || nBand > poODS->GetRasterCount())
     442         258 :         return nullptr;
     443             : 
     444        1034 :     GDALRasterBand *const poBand = poODS->GetRasterBand(nBand);
     445        1034 :     if (poBand == nullptr)
     446           0 :         return nullptr;
     447             : 
     448        1034 :     if (bOvrIsAux)
     449          63 :         return poBand->GetOverview(iOverview);
     450             : 
     451             :     // TIFF case, base is overview 0.
     452         971 :     if (iOverview == 0)
     453         732 :         return poBand;
     454             : 
     455         239 :     if (iOverview - 1 >= poBand->GetOverviewCount())
     456           0 :         return nullptr;
     457             : 
     458         239 :     return poBand->GetOverview(iOverview - 1);
     459             : }
     460             : 
     461             : /************************************************************************/
     462             : /*                         GDALOvLevelAdjust()                          */
     463             : /*                                                                      */
     464             : /*      Some overview levels cannot be achieved closely enough to be    */
     465             : /*      recognised as the desired overview level.  This function        */
     466             : /*      will adjust an overview level to one that is achievable on      */
     467             : /*      the given raster size.                                          */
     468             : /*                                                                      */
     469             : /*      For instance a 1200x1200 image on which a 256 level overview    */
     470             : /*      is request will end up generating a 5x5 overview.  However,     */
     471             : /*      this will appear to the system be a level 240 overview.         */
     472             : /*      This function will adjust 256 to 240 based on knowledge of      */
     473             : /*      the image size.                                                 */
     474             : /************************************************************************/
     475             : 
     476           0 : int GDALOvLevelAdjust(int nOvLevel, int nXSize)
     477             : 
     478             : {
     479           0 :     int nOXSize = (nXSize + nOvLevel - 1) / nOvLevel;
     480             : 
     481           0 :     return static_cast<int>(0.5 + nXSize / static_cast<double>(nOXSize));
     482             : }
     483             : 
     484         496 : int GDALOvLevelAdjust2(int nOvLevel, int nXSize, int nYSize)
     485             : 
     486             : {
     487             :     // Select the larger dimension to have increased accuracy, but
     488             :     // with a slight preference to x even if (a bit) smaller than y
     489             :     // in an attempt to behave closer as previous behavior.
     490         496 :     if (nXSize >= nYSize / 2 && !(nXSize < nYSize && nXSize < nOvLevel))
     491             :     {
     492         399 :         const int nOXSize = (nXSize + nOvLevel - 1) / nOvLevel;
     493             : 
     494         399 :         return static_cast<int>(0.5 + nXSize / static_cast<double>(nOXSize));
     495             :     }
     496             : 
     497          97 :     const int nOYSize = (nYSize + nOvLevel - 1) / nOvLevel;
     498             : 
     499          97 :     return static_cast<int>(0.5 + nYSize / static_cast<double>(nOYSize));
     500             : }
     501             : 
     502             : /************************************************************************/
     503             : /*                         GDALComputeOvFactor()                        */
     504             : /************************************************************************/
     505             : 
     506        1749 : int GDALComputeOvFactor(int nOvrXSize, int nRasterXSize, int nOvrYSize,
     507             :                         int nRasterYSize)
     508             : {
     509             :     // Select the larger dimension to have increased accuracy, but
     510             :     // with a slight preference to x even if (a bit) smaller than y
     511             :     // in an attempt to behave closer as previous behavior.
     512        1749 :     if (nRasterXSize != 1 && nRasterXSize >= nRasterYSize / 2)
     513             :     {
     514        1637 :         return static_cast<int>(0.5 +
     515        1637 :                                 nRasterXSize / static_cast<double>(nOvrXSize));
     516             :     }
     517             : 
     518         112 :     return static_cast<int>(0.5 +
     519         112 :                             nRasterYSize / static_cast<double>(nOvrYSize));
     520             : }
     521             : 
     522             : /************************************************************************/
     523             : /*                           CleanOverviews()                           */
     524             : /*                                                                      */
     525             : /*      Remove all existing overviews.                                  */
     526             : /************************************************************************/
     527             : 
     528          10 : CPLErr GDALDefaultOverviews::CleanOverviews()
     529             : 
     530             : {
     531             :     // Anything to do?
     532          10 :     if (poODS == nullptr)
     533           1 :         return CE_None;
     534             : 
     535             :     // Delete the overview file(s).
     536           9 :     GDALDriver *poOvrDriver = poODS->GetDriver();
     537           9 :     GDALClose(poODS);
     538           9 :     poODS = nullptr;
     539             : 
     540             :     CPLErr eErr =
     541           9 :         poOvrDriver != nullptr ? poOvrDriver->Delete(osOvrFilename) : CE_None;
     542             : 
     543             :     // Reset the saved overview filename.
     544           9 :     if (!EQUAL(poDS->GetDescription(), ":::VIRTUAL:::"))
     545             :     {
     546           9 :         const bool bUseRRD = CPLTestBool(CPLGetConfigOption("USE_RRD", "NO"));
     547             : 
     548           9 :         if (bUseRRD)
     549             :             osOvrFilename =
     550           0 :                 CPLResetExtensionSafe(poDS->GetDescription(), "aux");
     551             :         else
     552           9 :             osOvrFilename = std::string(poDS->GetDescription()).append(".ovr");
     553             :     }
     554             :     else
     555             :     {
     556           0 :         osOvrFilename = "";
     557             :     }
     558             : 
     559           9 :     if (HaveMaskFile() && poMaskDS)
     560             :     {
     561           1 :         const CPLErr eErr2 = poMaskDS->BuildOverviews(
     562             :             nullptr, 0, nullptr, 0, nullptr, nullptr, nullptr, nullptr);
     563           1 :         if (eErr2 != CE_None)
     564           0 :             return eErr2;
     565             :     }
     566             : 
     567           9 :     return eErr;
     568             : }
     569             : 
     570             : /************************************************************************/
     571             : /*                      BuildOverviewsSubDataset()                      */
     572             : /************************************************************************/
     573             : 
     574           9 : CPLErr GDALDefaultOverviews::BuildOverviewsSubDataset(
     575             :     const char *pszPhysicalFile, const char *pszResampling, int nOverviews,
     576             :     const int *panOverviewList, int nBands, const int *panBandList,
     577             :     GDALProgressFunc pfnProgress, void *pProgressData,
     578             :     CSLConstList papszOptions)
     579             : 
     580             : {
     581           9 :     if (osOvrFilename.length() == 0 && nOverviews > 0)
     582             :     {
     583             :         VSIStatBufL sStatBuf;
     584             : 
     585           6 :         int iSequence = 0;  // Used after for.
     586           6 :         for (iSequence = 0; iSequence < 100; iSequence++)
     587             :         {
     588           6 :             osOvrFilename.Printf("%s_%d.ovr", pszPhysicalFile, iSequence);
     589           6 :             if (VSIStatExL(osOvrFilename, &sStatBuf, VSI_STAT_EXISTS_FLAG) != 0)
     590             :             {
     591          12 :                 CPLString osAdjustedOvrFilename;
     592             : 
     593           6 :                 if (poDS->GetMOFlags() & GMO_PAM_CLASS)
     594             :                 {
     595             :                     osAdjustedOvrFilename.Printf(
     596             :                         ":::BASE:::%s_%d.ovr", CPLGetFilename(pszPhysicalFile),
     597           6 :                         iSequence);
     598             :                 }
     599             :                 else
     600             :                 {
     601           0 :                     osAdjustedOvrFilename = osOvrFilename;
     602             :                 }
     603             : 
     604           6 :                 poDS->SetMetadataItem("OVERVIEW_FILE", osAdjustedOvrFilename,
     605           6 :                                       "OVERVIEWS");
     606           6 :                 break;
     607             :             }
     608             :         }
     609             : 
     610           6 :         if (iSequence == 100)
     611           0 :             osOvrFilename = "";
     612             :     }
     613             : 
     614           9 :     return BuildOverviews(nullptr, pszResampling, nOverviews, panOverviewList,
     615             :                           nBands, panBandList, pfnProgress, pProgressData,
     616           9 :                           papszOptions);
     617             : }
     618             : 
     619             : /************************************************************************/
     620             : /*                           GetOptionValue()                           */
     621             : /************************************************************************/
     622             : 
     623         183 : static const char *GetOptionValue(CSLConstList papszOptions,
     624             :                                   const char *pszOptionKey,
     625             :                                   const char *pszConfigOptionKey)
     626             : {
     627             :     const char *pszVal =
     628         183 :         pszOptionKey ? CSLFetchNameValue(papszOptions, pszOptionKey) : nullptr;
     629         183 :     if (pszVal)
     630             :     {
     631           0 :         return pszVal;
     632             :     }
     633         183 :     pszVal = CSLFetchNameValue(papszOptions, pszConfigOptionKey);
     634         183 :     if (pszVal)
     635             :     {
     636           2 :         return pszVal;
     637             :     }
     638         181 :     pszVal = CPLGetConfigOption(pszConfigOptionKey, nullptr);
     639         181 :     return pszVal;
     640             : }
     641             : 
     642             : /************************************************************************/
     643             : /*                           BuildOverviews()                           */
     644             : /************************************************************************/
     645             : 
     646         197 : CPLErr GDALDefaultOverviews::BuildOverviews(
     647             :     const char *pszBasename, const char *pszResampling, int nOverviews,
     648             :     const int *panOverviewList, int nBands, const int *panBandList,
     649             :     GDALProgressFunc pfnProgress, void *pProgressData,
     650             :     CSLConstList papszOptions)
     651             : 
     652             : {
     653         197 :     if (pfnProgress == nullptr)
     654           0 :         pfnProgress = GDALDummyProgress;
     655             : 
     656         197 :     if (nOverviews == 0)
     657           9 :         return CleanOverviews();
     658             : 
     659             :     /* -------------------------------------------------------------------- */
     660             :     /*      If we don't already have an overview file, we need to decide    */
     661             :     /*      what format to use.                                             */
     662             :     /* -------------------------------------------------------------------- */
     663         188 :     if (poODS == nullptr)
     664             :     {
     665             :         const char *pszUseRRD =
     666         175 :             GetOptionValue(papszOptions, nullptr, "USE_RRD");
     667         175 :         bOvrIsAux = pszUseRRD && CPLTestBool(pszUseRRD);
     668         175 :         if (bOvrIsAux)
     669             :         {
     670             :             osOvrFilename =
     671           4 :                 CPLResetExtensionSafe(poDS->GetDescription(), "aux");
     672             : 
     673             :             VSIStatBufL sStatBuf;
     674           4 :             if (VSIStatExL(osOvrFilename, &sStatBuf, VSI_STAT_EXISTS_FLAG) == 0)
     675           0 :                 osOvrFilename.Printf("%s.aux", poDS->GetDescription());
     676             :         }
     677             :     }
     678             :     /* -------------------------------------------------------------------- */
     679             :     /*      If we already have the overviews open, but they are             */
     680             :     /*      read-only, then try and reopen them read-write.                 */
     681             :     /* -------------------------------------------------------------------- */
     682          13 :     else if (poODS->GetAccess() == GA_ReadOnly)
     683             :     {
     684          11 :         GDALClose(poODS);
     685          11 :         poODS =
     686          11 :             GDALDataset::Open(osOvrFilename, GDAL_OF_RASTER | GDAL_OF_UPDATE);
     687          11 :         if (poODS == nullptr)
     688           0 :             return CE_Failure;
     689             :     }
     690             : 
     691             :     /* -------------------------------------------------------------------- */
     692             :     /*      Our TIFF overview support currently only works safely if all    */
     693             :     /*      bands are handled at the same time.                             */
     694             :     /* -------------------------------------------------------------------- */
     695         188 :     if (!bOvrIsAux && nBands != poDS->GetRasterCount())
     696             :     {
     697           0 :         CPLError(CE_Failure, CPLE_NotSupported,
     698             :                  "Generation of overviews in external TIFF currently only "
     699             :                  "supported when operating on all bands.  "
     700             :                  "Operation failed.");
     701           0 :         return CE_Failure;
     702             :     }
     703             : 
     704             :     /* -------------------------------------------------------------------- */
     705             :     /*      If a basename is provided, use it to override the internal      */
     706             :     /*      overview filename.                                              */
     707             :     /* -------------------------------------------------------------------- */
     708         188 :     if (pszBasename == nullptr && osOvrFilename.length() == 0)
     709           0 :         pszBasename = poDS->GetDescription();
     710             : 
     711         188 :     if (pszBasename != nullptr)
     712             :     {
     713           1 :         if (bOvrIsAux)
     714           0 :             osOvrFilename.Printf("%s.aux", pszBasename);
     715             :         else
     716           1 :             osOvrFilename.Printf("%s.ovr", pszBasename);
     717             :     }
     718             : 
     719             :     /* -------------------------------------------------------------------- */
     720             :     /*      Establish which of the overview levels we already have, and     */
     721             :     /*      which are new.  We assume that band 1 of the file is            */
     722             :     /*      representative.                                                 */
     723             :     /* -------------------------------------------------------------------- */
     724         188 :     GDALRasterBand *poBand = poDS->GetRasterBand(1);
     725             : 
     726         188 :     int nNewOverviews = 0;
     727             :     int *panNewOverviewList =
     728         188 :         static_cast<int *>(CPLCalloc(sizeof(int), nOverviews));
     729         188 :     double dfAreaNewOverviews = 0;
     730         188 :     double dfAreaRefreshedOverviews = 0;
     731         376 :     std::vector<bool> abValidLevel(nOverviews, true);
     732         188 :     std::vector<bool> abRequireRefresh(nOverviews, false);
     733         188 :     bool bFoundSinglePixelOverview = false;
     734         464 :     for (int i = 0; i < nOverviews && poBand != nullptr; i++)
     735             :     {
     736             :         // If we already have a 1x1 overview and this new one would result
     737             :         // in it too, then don't create it.
     738         308 :         if (bFoundSinglePixelOverview &&
     739          16 :             (poBand->GetXSize() + panOverviewList[i] - 1) /
     740          16 :                     panOverviewList[i] ==
     741         292 :                 1 &&
     742          16 :             (poBand->GetYSize() + panOverviewList[i] - 1) /
     743          16 :                     panOverviewList[i] ==
     744             :                 1)
     745             :         {
     746          16 :             abValidLevel[i] = false;
     747          16 :             continue;
     748             :         }
     749             : 
     750         281 :         for (int j = 0; j < poBand->GetOverviewCount(); j++)
     751             :         {
     752          38 :             GDALRasterBand *poOverview = poBand->GetOverview(j);
     753          38 :             if (poOverview == nullptr)
     754           0 :                 continue;
     755             : 
     756             :             int nOvFactor =
     757          38 :                 GDALComputeOvFactor(poOverview->GetXSize(), poBand->GetXSize(),
     758             :                                     poOverview->GetYSize(), poBand->GetYSize());
     759             : 
     760          62 :             if (nOvFactor == panOverviewList[i] ||
     761          24 :                 nOvFactor == GDALOvLevelAdjust2(panOverviewList[i],
     762             :                                                 poBand->GetXSize(),
     763             :                                                 poBand->GetYSize()))
     764             :             {
     765             :                 const auto osNewResampling =
     766          34 :                     GDALGetNormalizedOvrResampling(pszResampling);
     767             :                 const char *pszExistingResampling =
     768          17 :                     poOverview->GetMetadataItem("RESAMPLING");
     769          28 :                 if (pszExistingResampling &&
     770          11 :                     pszExistingResampling != osNewResampling)
     771             :                 {
     772           3 :                     if (auto l_poODS = poOverview->GetDataset())
     773             :                     {
     774           3 :                         if (auto poDriver = l_poODS->GetDriver())
     775             :                         {
     776           1 :                             if (EQUAL(poDriver->GetDescription(), "GTiff"))
     777             :                             {
     778           1 :                                 poOverview->SetMetadataItem(
     779           1 :                                     "RESAMPLING", osNewResampling.c_str());
     780             :                             }
     781             :                         }
     782             :                     }
     783             :                 }
     784             : 
     785          17 :                 abRequireRefresh[i] = true;
     786          17 :                 break;
     787             :             }
     788             :         }
     789             : 
     790         260 :         if (abValidLevel[i])
     791             :         {
     792         260 :             const double dfArea =
     793             :                 1.0 /
     794         260 :                 (static_cast<double>(panOverviewList[i]) * panOverviewList[i]);
     795         260 :             dfAreaRefreshedOverviews += dfArea;
     796         260 :             if (!abRequireRefresh[i])
     797             :             {
     798         243 :                 dfAreaNewOverviews += dfArea;
     799         243 :                 panNewOverviewList[nNewOverviews++] = panOverviewList[i];
     800             :             }
     801             : 
     802         260 :             if ((poBand->GetXSize() + panOverviewList[i] - 1) /
     803         260 :                         panOverviewList[i] ==
     804         280 :                     1 &&
     805          20 :                 (poBand->GetYSize() + panOverviewList[i] - 1) /
     806          20 :                         panOverviewList[i] ==
     807             :                     1)
     808             :             {
     809          18 :                 bFoundSinglePixelOverview = true;
     810             :             }
     811             :         }
     812             :     }
     813             : 
     814             :     /* -------------------------------------------------------------------- */
     815             :     /*      Build band list.                                                */
     816             :     /* -------------------------------------------------------------------- */
     817             :     GDALRasterBand **pahBands = static_cast<GDALRasterBand **>(
     818         188 :         CPLCalloc(sizeof(GDALRasterBand *), nBands));
     819         491 :     for (int i = 0; i < nBands; i++)
     820         303 :         pahBands[i] = poDS->GetRasterBand(panBandList[i]);
     821             : 
     822             :     /* -------------------------------------------------------------------- */
     823             :     /*      Build new overviews - Imagine.  Keep existing file open if      */
     824             :     /*      we have it.  But mark all overviews as in need of               */
     825             :     /*      regeneration, since HFAAuxBuildOverviews() doesn't actually     */
     826             :     /*      produce the imagery.                                            */
     827             :     /* -------------------------------------------------------------------- */
     828             : 
     829         188 :     CPLErr eErr = CE_None;
     830             : 
     831         188 :     void *pScaledOverviewWithoutMask = GDALCreateScaledProgress(
     832         188 :         0, (HaveMaskFile() && poMaskDS) ? double(nBands) / (nBands + 1) : 1,
     833             :         pfnProgress, pProgressData);
     834             : 
     835         207 :     const auto AvoidZero = [](double x)
     836             :     {
     837         207 :         if (x == 0)
     838           0 :             return 1.0;
     839         207 :         return x;
     840             :     };
     841             : 
     842         188 :     void *pScaledProgress = GDALCreateScaledProgress(
     843         188 :         0, dfAreaNewOverviews / AvoidZero(dfAreaRefreshedOverviews),
     844             :         GDALScaledProgress, pScaledOverviewWithoutMask);
     845         188 :     if (bOvrIsAux)
     846             :     {
     847             : #ifdef NO_HFA_SUPPORT
     848             :         CPLError(CE_Failure, CPLE_NotSupported,
     849             :                  "This build does not support creating .aux overviews");
     850             :         eErr = CE_Failure;
     851             : #else
     852           8 :         if (nNewOverviews == 0)
     853             :         {
     854             :             /* if we call HFAAuxBuildOverviews() with nNewOverviews == 0 */
     855             :             /* because that there's no new, this will wipe existing */
     856             :             /* overviews (#4831) */
     857             :             // eErr = CE_None;
     858             :         }
     859             :         else
     860             :         {
     861           5 :             eErr = HFAAuxBuildOverviews(
     862             :                 osOvrFilename, poDS, &poODS, nBands, panBandList, nNewOverviews,
     863             :                 panNewOverviewList, pszResampling, GDALScaledProgress,
     864             :                 pScaledProgress, papszOptions);
     865             :         }
     866             : 
     867             :         // HFAAuxBuildOverviews doesn't actually generate overviews
     868           8 :         dfAreaNewOverviews = 0.0;
     869          20 :         for (int j = 0; j < nOverviews; j++)
     870             :         {
     871          12 :             if (abValidLevel[j])
     872          12 :                 abRequireRefresh[j] = true;
     873             :         }
     874             : #endif
     875             :     }
     876             : 
     877             :     /* -------------------------------------------------------------------- */
     878             :     /*      Build new overviews - TIFF.  Close TIFF files while we          */
     879             :     /*      operate on it.                                                  */
     880             :     /* -------------------------------------------------------------------- */
     881             :     else
     882             :     {
     883         180 :         if (poODS != nullptr)
     884             :         {
     885           9 :             delete poODS;
     886           9 :             poODS = nullptr;
     887             :         }
     888             : 
     889             : #ifdef HAVE_TIFF
     890         180 :         eErr = GTIFFBuildOverviews(
     891             :             osOvrFilename, nBands, pahBands, nNewOverviews, panNewOverviewList,
     892             :             pszResampling, GDALScaledProgress, pScaledProgress, papszOptions);
     893             : 
     894             :         // Probe for proxy overview filename.
     895         180 :         if (eErr == CE_Failure)
     896             :         {
     897             :             const char *pszProxyOvrFilename =
     898           5 :                 poDS->GetMetadataItem("FILENAME", "ProxyOverviewRequest");
     899             : 
     900           5 :             if (pszProxyOvrFilename != nullptr)
     901             :             {
     902           1 :                 osOvrFilename = pszProxyOvrFilename;
     903           1 :                 eErr = GTIFFBuildOverviews(osOvrFilename, nBands, pahBands,
     904             :                                            nNewOverviews, panNewOverviewList,
     905             :                                            pszResampling, GDALScaledProgress,
     906             :                                            pScaledProgress, papszOptions);
     907             :             }
     908             :         }
     909             : 
     910         180 :         if (eErr == CE_None)
     911             :         {
     912         176 :             poODS = GDALDataset::Open(osOvrFilename,
     913             :                                       GDAL_OF_RASTER | GDAL_OF_UPDATE);
     914         176 :             if (poODS == nullptr)
     915           0 :                 eErr = CE_Failure;
     916             :         }
     917             : #else
     918             :         CPLError(CE_Failure, CPLE_NotSupported,
     919             :                  "Cannot build TIFF overviews due to GeoTIFF driver missing");
     920             :         eErr = CE_Failure;
     921             : #endif
     922             :     }
     923             : 
     924         188 :     GDALDestroyScaledProgress(pScaledProgress);
     925             : 
     926             :     /* -------------------------------------------------------------------- */
     927             :     /*      Refresh old overviews that were listed.                         */
     928             :     /* -------------------------------------------------------------------- */
     929             :     GDALRasterBand **papoOverviewBands =
     930         188 :         static_cast<GDALRasterBand **>(CPLCalloc(sizeof(void *), nOverviews));
     931             : 
     932         487 :     for (int iBand = 0; iBand < nBands && eErr == CE_None; iBand++)
     933             :     {
     934         299 :         poBand = poDS->GetRasterBand(panBandList[iBand]);
     935         299 :         if (poBand == nullptr)
     936             :         {
     937           0 :             eErr = CE_Failure;
     938           0 :             break;
     939             :         }
     940             : 
     941         299 :         nNewOverviews = 0;
     942         598 :         std::vector<bool> abAlreadyUsedOverviewBand(poBand->GetOverviewCount(),
     943         598 :                                                     false);
     944             : 
     945         753 :         for (int i = 0; i < nOverviews; i++)
     946             :         {
     947         454 :             if (!abValidLevel[i] || !abRequireRefresh[i])
     948         425 :                 continue;
     949             : 
     950          47 :             for (int j = 0; j < poBand->GetOverviewCount(); j++)
     951             :             {
     952          47 :                 if (abAlreadyUsedOverviewBand[j])
     953          16 :                     continue;
     954             : 
     955          31 :                 GDALRasterBand *poOverview = poBand->GetOverview(j);
     956          31 :                 if (poOverview == nullptr)
     957           0 :                     continue;
     958             : 
     959          31 :                 int bHasNoData = FALSE;
     960          31 :                 double noDataValue = poBand->GetNoDataValue(&bHasNoData);
     961             : 
     962          31 :                 if (bHasNoData)
     963           2 :                     poOverview->SetNoDataValue(noDataValue);
     964             : 
     965          31 :                 const int nOvFactor = GDALComputeOvFactor(
     966             :                     poOverview->GetXSize(), poBand->GetXSize(),
     967             :                     poOverview->GetYSize(), poBand->GetYSize());
     968             : 
     969          36 :                 if (nOvFactor == panOverviewList[i] ||
     970           5 :                     nOvFactor == GDALOvLevelAdjust2(panOverviewList[i],
     971             :                                                     poBand->GetXSize(),
     972             :                                                     poBand->GetYSize()))
     973             :                 {
     974          29 :                     abAlreadyUsedOverviewBand[j] = true;
     975          29 :                     CPLAssert(nNewOverviews < poBand->GetOverviewCount());
     976          29 :                     papoOverviewBands[nNewOverviews++] = poOverview;
     977          29 :                     break;
     978             :                 }
     979             :             }
     980             :         }
     981             : 
     982         299 :         if (nNewOverviews > 0)
     983             :         {
     984             :             const double dfOffset =
     985          19 :                 dfAreaNewOverviews / AvoidZero(dfAreaRefreshedOverviews);
     986          19 :             const double dfScale = 1.0 - dfOffset;
     987          38 :             pScaledProgress = GDALCreateScaledProgress(
     988          19 :                 dfOffset + dfScale * iBand / nBands,
     989          19 :                 dfOffset + dfScale * (iBand + 1) / nBands, GDALScaledProgress,
     990             :                 pScaledOverviewWithoutMask);
     991          19 :             eErr = GDALRegenerateOverviewsEx(
     992             :                 GDALRasterBand::ToHandle(poBand), nNewOverviews,
     993             :                 reinterpret_cast<GDALRasterBandH *>(papoOverviewBands),
     994             :                 pszResampling, GDALScaledProgress, pScaledProgress,
     995             :                 papszOptions);
     996          19 :             GDALDestroyScaledProgress(pScaledProgress);
     997             :         }
     998             :     }
     999             : 
    1000             :     /* -------------------------------------------------------------------- */
    1001             :     /*      Cleanup                                                         */
    1002             :     /* -------------------------------------------------------------------- */
    1003         188 :     CPLFree(papoOverviewBands);
    1004         188 :     CPLFree(panNewOverviewList);
    1005         188 :     CPLFree(pahBands);
    1006         188 :     GDALDestroyScaledProgress(pScaledOverviewWithoutMask);
    1007             : 
    1008             :     /* -------------------------------------------------------------------- */
    1009             :     /*      If we have a mask file, we need to build its overviews too.     */
    1010             :     /* -------------------------------------------------------------------- */
    1011         188 :     if (HaveMaskFile() && eErr == CE_None)
    1012             :     {
    1013           4 :         pScaledProgress = GDALCreateScaledProgress(
    1014           2 :             double(nBands) / (nBands + 1), 1.0, pfnProgress, pProgressData);
    1015           2 :         eErr = BuildOverviewsMask(pszResampling, nOverviews, panOverviewList,
    1016             :                                   GDALScaledProgress, pScaledProgress,
    1017             :                                   papszOptions);
    1018           2 :         GDALDestroyScaledProgress(pScaledProgress);
    1019             :     }
    1020             : 
    1021             :     /* -------------------------------------------------------------------- */
    1022             :     /*      If we have an overview dataset, then mark all the overviews     */
    1023             :     /*      with the base dataset  Used later for finding overviews         */
    1024             :     /*      masks.  Uggg.                                                   */
    1025             :     /* -------------------------------------------------------------------- */
    1026         188 :     if (poODS)
    1027             :     {
    1028         184 :         const int nOverviewCount = GetOverviewCount(1);
    1029             : 
    1030         446 :         for (int iOver = 0; iOver < nOverviewCount; iOver++)
    1031             :         {
    1032         262 :             GDALRasterBand *poOtherBand = GetOverview(1, iOver);
    1033             :             GDALDataset *poOverDS =
    1034         262 :                 poOtherBand != nullptr ? poOtherBand->GetDataset() : nullptr;
    1035             : 
    1036         262 :             if (poOverDS != nullptr)
    1037             :             {
    1038         248 :                 poOverDS->oOvManager.poBaseDS = poDS;
    1039         248 :                 poOverDS->oOvManager.poDS = poOverDS;
    1040             :             }
    1041             :         }
    1042             :     }
    1043             : 
    1044         188 :     return eErr;
    1045             : }
    1046             : 
    1047             : /************************************************************************/
    1048             : /*                          BuildOverviewsMask()                        */
    1049             : /************************************************************************/
    1050             : 
    1051           4 : CPLErr GDALDefaultOverviews::BuildOverviewsMask(const char *pszResampling,
    1052             :                                                 int nOverviews,
    1053             :                                                 const int *panOverviewList,
    1054             :                                                 GDALProgressFunc pfnProgress,
    1055             :                                                 void *pProgressData,
    1056             :                                                 CSLConstList papszOptions)
    1057             : {
    1058           4 :     CPLErr eErr = CE_None;
    1059           4 :     if (HaveMaskFile() && poMaskDS)
    1060             :     {
    1061             :         // Some options are not compatible with mask overviews
    1062             :         // so unset them, and define more sensible values.
    1063           4 :         CPLStringList aosMaskOptions(papszOptions);
    1064             :         const char *pszCompress =
    1065           4 :             GetOptionValue(papszOptions, "COMPRESS", "COMPRESS_OVERVIEW");
    1066           4 :         const bool bJPEG = pszCompress && EQUAL(pszCompress, "JPEG");
    1067             :         const char *pszPhotometric =
    1068           4 :             GetOptionValue(papszOptions, "PHOTOMETRIC", "PHOTOMETRIC_OVERVIEW");
    1069           4 :         const bool bPHOTOMETRIC_YCBCR =
    1070           4 :             pszPhotometric && EQUAL(pszPhotometric, "YCBCR");
    1071           4 :         if (bJPEG)
    1072           0 :             aosMaskOptions.SetNameValue("COMPRESS", "DEFLATE");
    1073           4 :         if (bPHOTOMETRIC_YCBCR)
    1074           0 :             aosMaskOptions.SetNameValue("PHOTOMETRIC", "MINISBLACK");
    1075             : 
    1076           4 :         eErr = poMaskDS->BuildOverviews(
    1077             :             pszResampling, nOverviews, panOverviewList, 0, nullptr, pfnProgress,
    1078           4 :             pProgressData, aosMaskOptions.List());
    1079             : 
    1080           4 :         if (bOwnMaskDS)
    1081             :         {
    1082             :             // Reset the poMask member of main dataset bands, since it
    1083             :             // will become invalid after poMaskDS closing.
    1084          10 :             for (int iBand = 1; iBand <= poDS->GetRasterCount(); iBand++)
    1085             :             {
    1086           6 :                 GDALRasterBand *poOtherBand = poDS->GetRasterBand(iBand);
    1087           6 :                 if (poOtherBand != nullptr)
    1088           6 :                     poOtherBand->InvalidateMaskBand();
    1089             :             }
    1090             : 
    1091           4 :             GDALClose(poMaskDS);
    1092             :         }
    1093             : 
    1094             :         // force next request to reread mask file.
    1095           4 :         poMaskDS = nullptr;
    1096           4 :         bOwnMaskDS = false;
    1097           4 :         bCheckedForMask = false;
    1098             :     }
    1099             : 
    1100           4 :     return eErr;
    1101             : }
    1102             : 
    1103             : /************************************************************************/
    1104             : /*                           CreateMaskBand()                           */
    1105             : /************************************************************************/
    1106             : 
    1107          26 : CPLErr GDALDefaultOverviews::CreateMaskBand(int nFlags, int nBand)
    1108             : 
    1109             : {
    1110          26 :     if (nBand < 1)
    1111          17 :         nFlags |= GMF_PER_DATASET;
    1112             : 
    1113             :     /* -------------------------------------------------------------------- */
    1114             :     /*      ensure existing file gets opened if there is one.               */
    1115             :     /* -------------------------------------------------------------------- */
    1116          26 :     CPL_IGNORE_RET_VAL(HaveMaskFile());
    1117             : 
    1118             :     /* -------------------------------------------------------------------- */
    1119             :     /*      Try creating the mask file.                                     */
    1120             :     /* -------------------------------------------------------------------- */
    1121          26 :     if (poMaskDS == nullptr)
    1122             :     {
    1123             :         GDALDriver *const poDr =
    1124          21 :             static_cast<GDALDriver *>(GDALGetDriverByName("GTiff"));
    1125             : 
    1126          21 :         if (poDr == nullptr)
    1127           0 :             return CE_Failure;
    1128             : 
    1129          21 :         GDALRasterBand *const poTBand = poDS->GetRasterBand(1);
    1130          21 :         if (poTBand == nullptr)
    1131           0 :             return CE_Failure;
    1132             : 
    1133             :         const int nBands =
    1134          21 :             (nFlags & GMF_PER_DATASET) ? 1 : poDS->GetRasterCount();
    1135             : 
    1136          21 :         char **papszOpt = CSLSetNameValue(nullptr, "COMPRESS", "DEFLATE");
    1137          21 :         papszOpt = CSLSetNameValue(papszOpt, "INTERLEAVE", "BAND");
    1138             : 
    1139          21 :         int nBX = 0;
    1140          21 :         int nBY = 0;
    1141          21 :         poTBand->GetBlockSize(&nBX, &nBY);
    1142             : 
    1143             :         // Try to create matching tile size if legal in TIFF.
    1144          21 :         if ((nBX % 16) == 0 && (nBY % 16) == 0)
    1145             :         {
    1146           2 :             papszOpt = CSLSetNameValue(papszOpt, "TILED", "YES");
    1147           2 :             papszOpt = CSLSetNameValue(papszOpt, "BLOCKXSIZE",
    1148           4 :                                        CPLString().Printf("%d", nBX));
    1149           2 :             papszOpt = CSLSetNameValue(papszOpt, "BLOCKYSIZE",
    1150           4 :                                        CPLString().Printf("%d", nBY));
    1151             :         }
    1152             : 
    1153          21 :         CPLString osMskFilename;
    1154          21 :         osMskFilename.Printf("%s.msk", poDS->GetDescription());
    1155          21 :         poMaskDS =
    1156          21 :             poDr->Create(osMskFilename, poDS->GetRasterXSize(),
    1157          21 :                          poDS->GetRasterYSize(), nBands, GDT_Byte, papszOpt);
    1158          21 :         CSLDestroy(papszOpt);
    1159             : 
    1160          21 :         if (poMaskDS == nullptr)  // Presumably error already issued.
    1161           0 :             return CE_Failure;
    1162             : 
    1163          21 :         bOwnMaskDS = true;
    1164             :     }
    1165             : 
    1166             :     /* -------------------------------------------------------------------- */
    1167             :     /*      Save the mask flags for this band.                              */
    1168             :     /* -------------------------------------------------------------------- */
    1169          26 :     if (nBand > poMaskDS->GetRasterCount())
    1170             :     {
    1171           1 :         CPLError(CE_Failure, CPLE_AppDefined,
    1172             :                  "Attempt to create a mask band for band %d of %s, "
    1173             :                  "but the .msk file has a PER_DATASET mask.",
    1174           1 :                  nBand, poDS->GetDescription());
    1175           1 :         return CE_Failure;
    1176             :     }
    1177             : 
    1178          67 :     for (int iBand = 0; iBand < poDS->GetRasterCount(); iBand++)
    1179             :     {
    1180             :         // we write only the info for this band, unless we are
    1181             :         // using PER_DATASET in which case we write for all.
    1182          42 :         if (nBand != iBand + 1 && !(nFlags & GMF_PER_DATASET))
    1183           6 :             continue;
    1184             : 
    1185          36 :         poMaskDS->SetMetadataItem(
    1186          72 :             CPLString().Printf("INTERNAL_MASK_FLAGS_%d", iBand + 1),
    1187          72 :             CPLString().Printf("%d", nFlags));
    1188             :     }
    1189             : 
    1190          25 :     return CE_None;
    1191             : }
    1192             : 
    1193             : /************************************************************************/
    1194             : /*                            GetMaskBand()                             */
    1195             : /************************************************************************/
    1196             : 
    1197             : // Secret code meaning we don't handle this band.
    1198             : constexpr int MISSING_FLAGS = 0x8000;
    1199             : 
    1200          46 : GDALRasterBand *GDALDefaultOverviews::GetMaskBand(int nBand)
    1201             : 
    1202             : {
    1203          46 :     const int nFlags = GetMaskFlags(nBand);
    1204             : 
    1205          46 :     if (poMaskDS == nullptr || nFlags == MISSING_FLAGS)
    1206           1 :         return nullptr;
    1207             : 
    1208          45 :     if (nFlags & GMF_PER_DATASET)
    1209          36 :         return poMaskDS->GetRasterBand(1);
    1210             : 
    1211           9 :     if (nBand > 0)
    1212           9 :         return poMaskDS->GetRasterBand(nBand);
    1213             : 
    1214           0 :     return nullptr;
    1215             : }
    1216             : 
    1217             : /************************************************************************/
    1218             : /*                            GetMaskFlags()                            */
    1219             : /************************************************************************/
    1220             : 
    1221          90 : int GDALDefaultOverviews::GetMaskFlags(int nBand)
    1222             : 
    1223             : {
    1224             :     /* -------------------------------------------------------------------- */
    1225             :     /*      Fetch this band's metadata entry.  They are of the form:        */
    1226             :     /*        INTERNAL_MASK_FLAGS_n: flags                                  */
    1227             :     /* -------------------------------------------------------------------- */
    1228          90 :     if (!HaveMaskFile())
    1229           0 :         return 0;
    1230             : 
    1231          90 :     const char *pszValue = poMaskDS->GetMetadataItem(
    1232         180 :         CPLString().Printf("INTERNAL_MASK_FLAGS_%d", std::max(nBand, 1)));
    1233             : 
    1234          90 :     if (pszValue == nullptr)
    1235           1 :         return MISSING_FLAGS;
    1236             : 
    1237          89 :     return atoi(pszValue);
    1238             : }
    1239             : 
    1240             : /************************************************************************/
    1241             : /*                            HaveMaskFile()                            */
    1242             : /*                                                                      */
    1243             : /*      Check for a mask file if we haven't already done so.            */
    1244             : /*      Returns TRUE if we have one, otherwise FALSE.                   */
    1245             : /************************************************************************/
    1246             : 
    1247       33298 : int GDALDefaultOverviews::HaveMaskFile(char **papszSiblingFiles,
    1248             :                                        const char *pszBasename)
    1249             : 
    1250             : {
    1251             :     /* -------------------------------------------------------------------- */
    1252             :     /*      Have we already checked for masks?                              */
    1253             :     /* -------------------------------------------------------------------- */
    1254       33298 :     if (bCheckedForMask)
    1255        3657 :         return poMaskDS != nullptr;
    1256             : 
    1257       29641 :     if (papszSiblingFiles == nullptr)
    1258       29641 :         papszSiblingFiles = papszInitSiblingFiles;
    1259             : 
    1260             :     /* -------------------------------------------------------------------- */
    1261             :     /*      Are we an overview?  If so we need to find the corresponding    */
    1262             :     /*      overview in the base files mask file (if there is one).         */
    1263             :     /* -------------------------------------------------------------------- */
    1264       29641 :     if (poBaseDS != nullptr && poBaseDS->oOvManager.HaveMaskFile())
    1265             :     {
    1266           4 :         GDALRasterBand *const poBaseBand = poBaseDS->GetRasterBand(1);
    1267           4 :         GDALDataset *poMaskDSTemp = nullptr;
    1268           4 :         if (poBaseBand != nullptr)
    1269             :         {
    1270           4 :             GDALRasterBand *poBaseMask = poBaseBand->GetMaskBand();
    1271           4 :             if (poBaseMask != nullptr)
    1272             :             {
    1273           4 :                 const int nOverviewCount = poBaseMask->GetOverviewCount();
    1274           6 :                 for (int iOver = 0; iOver < nOverviewCount; iOver++)
    1275             :                 {
    1276             :                     GDALRasterBand *const poOverBand =
    1277           6 :                         poBaseMask->GetOverview(iOver);
    1278           6 :                     if (poOverBand == nullptr)
    1279           0 :                         continue;
    1280             : 
    1281          10 :                     if (poOverBand->GetXSize() == poDS->GetRasterXSize() &&
    1282           4 :                         poOverBand->GetYSize() == poDS->GetRasterYSize())
    1283             :                     {
    1284           4 :                         poMaskDSTemp = poOverBand->GetDataset();
    1285           4 :                         break;
    1286             :                     }
    1287             :                 }
    1288             :             }
    1289             :         }
    1290             : 
    1291           4 :         if (poMaskDSTemp != poDS)
    1292             :         {
    1293           4 :             poMaskDS = poMaskDSTemp;
    1294           4 :             bCheckedForMask = true;
    1295           4 :             bOwnMaskDS = false;
    1296             : 
    1297           4 :             return poMaskDS != nullptr;
    1298             :         }
    1299             :     }
    1300             : 
    1301             :     /* -------------------------------------------------------------------- */
    1302             :     /*      Are we even initialized?  If not, we apparently don't want      */
    1303             :     /*      to support overviews and masks.                                 */
    1304             :     /* -------------------------------------------------------------------- */
    1305       29637 :     if (poDS == nullptr)
    1306       19660 :         return FALSE;
    1307             : 
    1308             :     /* -------------------------------------------------------------------- */
    1309             :     /*      Check for .msk file.                                            */
    1310             :     /* -------------------------------------------------------------------- */
    1311        9977 :     bCheckedForMask = true;
    1312             : 
    1313        9977 :     if (pszBasename == nullptr)
    1314        9977 :         pszBasename = poDS->GetDescription();
    1315             : 
    1316             :     // Don't bother checking for masks of masks.
    1317        9977 :     if (EQUAL(CPLGetExtensionSafe(pszBasename).c_str(), "msk"))
    1318          20 :         return FALSE;
    1319             : 
    1320        9956 :     if (!GDALCanFileAcceptSidecarFile(pszBasename))
    1321           1 :         return FALSE;
    1322       19910 :     CPLString osMskFilename;
    1323        9956 :     osMskFilename.Printf("%s.msk", pszBasename);
    1324             : 
    1325       19912 :     std::vector<char> achMskFilename;
    1326        9955 :     achMskFilename.resize(osMskFilename.size() + 1);
    1327        9956 :     memcpy(&(achMskFilename[0]), osMskFilename.c_str(),
    1328        9956 :            osMskFilename.size() + 1);
    1329             :     bool bExists =
    1330        9955 :         CPL_TO_BOOL(CPLCheckForFile(&achMskFilename[0], papszSiblingFiles));
    1331        9956 :     osMskFilename = &achMskFilename[0];
    1332             : 
    1333             : #if !defined(_WIN32)
    1334        9956 :     if (!bExists && !papszSiblingFiles)
    1335             :     {
    1336        2248 :         osMskFilename.Printf("%s.MSK", pszBasename);
    1337        2248 :         memcpy(&(achMskFilename[0]), osMskFilename.c_str(),
    1338        2248 :                osMskFilename.size() + 1);
    1339             :         bExists =
    1340        2248 :             CPL_TO_BOOL(CPLCheckForFile(&achMskFilename[0], papszSiblingFiles));
    1341        2248 :         osMskFilename = &achMskFilename[0];
    1342             :     }
    1343             : #endif
    1344             : 
    1345        9956 :     if (!bExists)
    1346        9919 :         return FALSE;
    1347             : 
    1348             :     /* -------------------------------------------------------------------- */
    1349             :     /*      Open the file.                                                  */
    1350             :     /* -------------------------------------------------------------------- */
    1351          37 :     poMaskDS = GDALDataset::Open(
    1352             :         osMskFilename,
    1353          37 :         GDAL_OF_RASTER | (poDS->GetAccess() == GA_Update ? GDAL_OF_UPDATE : 0),
    1354          37 :         nullptr, nullptr, papszInitSiblingFiles);
    1355          37 :     CPLAssert(poMaskDS != poDS);
    1356             : 
    1357          37 :     if (poMaskDS == nullptr)
    1358           1 :         return FALSE;
    1359             : 
    1360          36 :     bOwnMaskDS = true;
    1361             : 
    1362          36 :     return TRUE;
    1363             : }
    1364             : 
    1365             : /************************************************************************/
    1366             : /*                    GDALGetNormalizedOvrResampling()                  */
    1367             : /************************************************************************/
    1368             : 
    1369         919 : std::string GDALGetNormalizedOvrResampling(const char *pszResampling)
    1370             : {
    1371         919 :     if (pszResampling &&
    1372         919 :         EQUAL(pszResampling, "AVERAGE_BIT2GRAYSCALE_MINISWHITE"))
    1373           0 :         return "AVERAGE_BIT2GRAYSCALE_MINISWHITE";
    1374         919 :     else if (pszResampling && STARTS_WITH_CI(pszResampling, "AVERAGE_BIT2"))
    1375           8 :         return "AVERAGE_BIT2GRAYSCALE";
    1376         911 :     else if (pszResampling && STARTS_WITH_CI(pszResampling, "NEAR"))
    1377         391 :         return "NEAREST";
    1378         520 :     else if (pszResampling && EQUAL(pszResampling, "AVERAGE_MAGPHASE"))
    1379           0 :         return "AVERAGE_MAGPHASE";
    1380         520 :     else if (pszResampling && STARTS_WITH_CI(pszResampling, "AVER"))
    1381         247 :         return "AVERAGE";
    1382         273 :     else if (pszResampling && !EQUAL(pszResampling, "NONE"))
    1383             :     {
    1384         310 :         return CPLString(pszResampling).toupper();
    1385             :     }
    1386         118 :     return std::string();
    1387             : }
    1388             : 
    1389             : //! @endcond

Generated by: LCOV version 1.14