Coverage Report

Created: 2026-02-14 06:52

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