LCOV - code coverage report
Current view: top level - gcore - gdaldefaultoverviews.cpp (source / functions) Hit Total Coverage
Test: gdal_filtered.info Lines: 503 548 91.8 %
Date: 2024-11-21 22:18:42 Functions: 24 25 96.0 %

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

Generated by: LCOV version 1.14