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