Coverage Report

Created: 2026-07-14 06:21

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