LCOV - code coverage report
Current view: top level - gcore - gdaldefaultoverviews.cpp (source / functions) Hit Total Coverage
Test: gdal_filtered.info Lines: 497 543 91.5 %
Date: 2024-05-03 15:49:35 Functions: 23 24 95.8 %

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

Generated by: LCOV version 1.14