Coverage Report

Created: 2025-08-28 06:57

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