Coverage Report

Created: 2025-11-16 06:25

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
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
            CPLStringList aosOptions(papszOptions);
1147
            aosOptions.SetNameValue("LOCATION", nullptr);
1148
            aosOptions.SetNameValue("USE_RRD", nullptr);
1149
            eErr = HFAAuxBuildOverviews(
1150
                osOvrFilename, poDS, &poODS, nBands, panBandList, nNewOverviews,
1151
                panNewOverviewList, pszResampling, GDALScaledProgress,
1152
                pScaledProgress, aosOptions.List());
1153
        }
1154
1155
        // HFAAuxBuildOverviews doesn't actually generate overviews
1156
        dfAreaNewOverviews = 0.0;
1157
        for (int j = 0; j < nOverviews; j++)
1158
        {
1159
            if (abValidLevel[j])
1160
                abRequireRefresh[j] = true;
1161
        }
1162
#endif
1163
0
    }
1164
1165
    /* -------------------------------------------------------------------- */
1166
    /*      Build new overviews - TIFF.  Close TIFF files while we          */
1167
    /*      operate on it.                                                  */
1168
    /* -------------------------------------------------------------------- */
1169
0
    else
1170
0
    {
1171
0
        if (poODS != nullptr)
1172
0
        {
1173
0
            delete poODS;
1174
0
            poODS = nullptr;
1175
0
        }
1176
1177
0
#ifdef HAVE_TIFF
1178
0
        eErr = GTIFFBuildOverviews(
1179
0
            osOvrFilename, nBands, pahBands, nNewOverviews, panNewOverviewList,
1180
0
            pszResampling, GDALScaledProgress, pScaledProgress, papszOptions);
1181
1182
        // Probe for proxy overview filename.
1183
0
        if (eErr == CE_Failure)
1184
0
        {
1185
0
            const char *pszProxyOvrFilename =
1186
0
                poDS->GetMetadataItem("FILENAME", "ProxyOverviewRequest");
1187
1188
0
            if (pszProxyOvrFilename != nullptr)
1189
0
            {
1190
0
                osOvrFilename = pszProxyOvrFilename;
1191
0
                eErr = GTIFFBuildOverviews(osOvrFilename, nBands, pahBands,
1192
0
                                           nNewOverviews, panNewOverviewList,
1193
0
                                           pszResampling, GDALScaledProgress,
1194
0
                                           pScaledProgress, papszOptions);
1195
0
            }
1196
0
        }
1197
1198
0
        if (eErr == CE_None)
1199
0
        {
1200
0
            poODS = GDALDataset::Open(osOvrFilename,
1201
0
                                      GDAL_OF_RASTER | GDAL_OF_UPDATE);
1202
0
            if (poODS == nullptr)
1203
0
                eErr = CE_Failure;
1204
0
        }
1205
#else
1206
        CPLError(CE_Failure, CPLE_NotSupported,
1207
                 "Cannot build TIFF overviews due to GeoTIFF driver missing");
1208
        eErr = CE_Failure;
1209
#endif
1210
0
    }
1211
1212
0
    GDALDestroyScaledProgress(pScaledProgress);
1213
1214
    /* -------------------------------------------------------------------- */
1215
    /*      Refresh old overviews that were listed.                         */
1216
    /* -------------------------------------------------------------------- */
1217
0
    GDALRasterBand **papoOverviewBands =
1218
0
        static_cast<GDALRasterBand **>(CPLCalloc(sizeof(void *), nOverviews));
1219
1220
0
    for (int iBand = 0; iBand < nBands && eErr == CE_None; iBand++)
1221
0
    {
1222
0
        poBand = poDS->GetRasterBand(panBandList[iBand]);
1223
0
        if (poBand == nullptr)
1224
0
        {
1225
0
            eErr = CE_Failure;
1226
0
            break;
1227
0
        }
1228
1229
0
        nNewOverviews = 0;
1230
0
        std::vector<bool> abAlreadyUsedOverviewBand(poBand->GetOverviewCount(),
1231
0
                                                    false);
1232
1233
0
        for (int i = 0; i < nOverviews; i++)
1234
0
        {
1235
0
            if (!abValidLevel[i] || !abRequireRefresh[i])
1236
0
                continue;
1237
1238
0
            for (int j = 0; j < poBand->GetOverviewCount(); j++)
1239
0
            {
1240
0
                if (abAlreadyUsedOverviewBand[j])
1241
0
                    continue;
1242
1243
0
                GDALRasterBand *poOverview = poBand->GetOverview(j);
1244
0
                if (poOverview == nullptr)
1245
0
                    continue;
1246
1247
0
                int bHasNoData = FALSE;
1248
0
                double noDataValue = poBand->GetNoDataValue(&bHasNoData);
1249
1250
0
                if (bHasNoData)
1251
0
                    poOverview->SetNoDataValue(noDataValue);
1252
1253
0
                const int nOvFactor = GDALComputeOvFactor(
1254
0
                    poOverview->GetXSize(), poBand->GetXSize(),
1255
0
                    poOverview->GetYSize(), poBand->GetYSize());
1256
1257
0
                if (nOvFactor == panOverviewList[i] ||
1258
0
                    nOvFactor == GDALOvLevelAdjust2(panOverviewList[i],
1259
0
                                                    poBand->GetXSize(),
1260
0
                                                    poBand->GetYSize()))
1261
0
                {
1262
0
                    abAlreadyUsedOverviewBand[j] = true;
1263
0
                    CPLAssert(nNewOverviews < poBand->GetOverviewCount());
1264
0
                    papoOverviewBands[nNewOverviews++] = poOverview;
1265
0
                    break;
1266
0
                }
1267
0
            }
1268
0
        }
1269
1270
0
        if (nNewOverviews > 0)
1271
0
        {
1272
0
            const double dfOffset =
1273
0
                dfAreaNewOverviews / AvoidZero(dfAreaRefreshedOverviews);
1274
0
            const double dfScale = 1.0 - dfOffset;
1275
0
            pScaledProgress = GDALCreateScaledProgress(
1276
0
                dfOffset + dfScale * iBand / nBands,
1277
0
                dfOffset + dfScale * (iBand + 1) / nBands, GDALScaledProgress,
1278
0
                pScaledOverviewWithoutMask);
1279
0
            eErr = GDALRegenerateOverviewsEx(
1280
0
                GDALRasterBand::ToHandle(poBand), nNewOverviews,
1281
0
                reinterpret_cast<GDALRasterBandH *>(papoOverviewBands),
1282
0
                pszResampling, GDALScaledProgress, pScaledProgress,
1283
0
                papszOptions);
1284
0
            GDALDestroyScaledProgress(pScaledProgress);
1285
0
        }
1286
0
    }
1287
1288
    /* -------------------------------------------------------------------- */
1289
    /*      Cleanup                                                         */
1290
    /* -------------------------------------------------------------------- */
1291
0
    CPLFree(papoOverviewBands);
1292
0
    CPLFree(panNewOverviewList);
1293
0
    CPLFree(pahBands);
1294
0
    GDALDestroyScaledProgress(pScaledOverviewWithoutMask);
1295
1296
    /* -------------------------------------------------------------------- */
1297
    /*      If we have a mask file, we need to build its overviews too.     */
1298
    /* -------------------------------------------------------------------- */
1299
0
    if (HaveMaskFile() && eErr == CE_None)
1300
0
    {
1301
0
        pScaledProgress = GDALCreateScaledProgress(
1302
0
            double(nBands) / (nBands + 1), 1.0, pfnProgress, pProgressData);
1303
0
        eErr = BuildOverviewsMask(pszResampling, nOverviews, panOverviewList,
1304
0
                                  GDALScaledProgress, pScaledProgress,
1305
0
                                  papszOptions);
1306
0
        GDALDestroyScaledProgress(pScaledProgress);
1307
0
    }
1308
1309
    /* -------------------------------------------------------------------- */
1310
    /*      If we have an overview dataset, then mark all the overviews     */
1311
    /*      with the base dataset  Used later for finding overviews         */
1312
    /*      masks.  Uggg.                                                   */
1313
    /* -------------------------------------------------------------------- */
1314
0
    if (poODS)
1315
0
    {
1316
0
        const int nOverviewCount = GetOverviewCount(1);
1317
1318
0
        for (int iOver = 0; iOver < nOverviewCount; iOver++)
1319
0
        {
1320
0
            GDALRasterBand *poOtherBand = GetOverview(1, iOver);
1321
0
            GDALDataset *poOverDS =
1322
0
                poOtherBand != nullptr ? poOtherBand->GetDataset() : nullptr;
1323
1324
0
            if (poOverDS != nullptr)
1325
0
            {
1326
0
                poOverDS->oOvManager.poBaseDS = poDS;
1327
0
                poOverDS->oOvManager.poDS = poOverDS;
1328
0
            }
1329
0
        }
1330
0
    }
1331
1332
0
    return eErr;
1333
0
}
1334
1335
/************************************************************************/
1336
/*                          BuildOverviewsMask()                        */
1337
/************************************************************************/
1338
1339
CPLErr GDALDefaultOverviews::BuildOverviewsMask(const char *pszResampling,
1340
                                                int nOverviews,
1341
                                                const int *panOverviewList,
1342
                                                GDALProgressFunc pfnProgress,
1343
                                                void *pProgressData,
1344
                                                CSLConstList papszOptions)
1345
0
{
1346
0
    CPLErr eErr = CE_None;
1347
0
    if (HaveMaskFile() && poMaskDS)
1348
0
    {
1349
        // Some options are not compatible with mask overviews
1350
        // so unset them, and define more sensible values.
1351
0
        CPLStringList aosMaskOptions(papszOptions);
1352
0
        const char *pszCompress =
1353
0
            GetOptionValue(papszOptions, "COMPRESS", "COMPRESS_OVERVIEW");
1354
0
        const bool bJPEG = pszCompress && EQUAL(pszCompress, "JPEG");
1355
0
        const char *pszPhotometric =
1356
0
            GetOptionValue(papszOptions, "PHOTOMETRIC", "PHOTOMETRIC_OVERVIEW");
1357
0
        const bool bPHOTOMETRIC_YCBCR =
1358
0
            pszPhotometric && EQUAL(pszPhotometric, "YCBCR");
1359
0
        if (bJPEG)
1360
0
            aosMaskOptions.SetNameValue("COMPRESS", "DEFLATE");
1361
0
        if (bPHOTOMETRIC_YCBCR)
1362
0
            aosMaskOptions.SetNameValue("PHOTOMETRIC", "MINISBLACK");
1363
1364
0
        eErr = poMaskDS->BuildOverviews(
1365
0
            pszResampling, nOverviews, panOverviewList, 0, nullptr, pfnProgress,
1366
0
            pProgressData, aosMaskOptions.List());
1367
1368
0
        if (bOwnMaskDS)
1369
0
        {
1370
            // Reset the poMask member of main dataset bands, since it
1371
            // will become invalid after poMaskDS closing.
1372
0
            for (int iBand = 1; iBand <= poDS->GetRasterCount(); iBand++)
1373
0
            {
1374
0
                GDALRasterBand *poOtherBand = poDS->GetRasterBand(iBand);
1375
0
                if (poOtherBand != nullptr)
1376
0
                    poOtherBand->InvalidateMaskBand();
1377
0
            }
1378
1379
0
            GDALClose(poMaskDS);
1380
0
        }
1381
1382
        // force next request to reread mask file.
1383
0
        poMaskDS = nullptr;
1384
0
        bOwnMaskDS = false;
1385
0
        bCheckedForMask = false;
1386
0
    }
1387
1388
0
    return eErr;
1389
0
}
1390
1391
/************************************************************************/
1392
/*                           CreateMaskBand()                           */
1393
/************************************************************************/
1394
1395
CPLErr GDALDefaultOverviews::CreateMaskBand(int nFlags, int nBand)
1396
1397
0
{
1398
0
    if (nBand < 1)
1399
0
        nFlags |= GMF_PER_DATASET;
1400
1401
    /* -------------------------------------------------------------------- */
1402
    /*      ensure existing file gets opened if there is one.               */
1403
    /* -------------------------------------------------------------------- */
1404
0
    CPL_IGNORE_RET_VAL(HaveMaskFile());
1405
1406
    /* -------------------------------------------------------------------- */
1407
    /*      Try creating the mask file.                                     */
1408
    /* -------------------------------------------------------------------- */
1409
0
    if (poMaskDS == nullptr)
1410
0
    {
1411
0
        GDALDriver *const poDr =
1412
0
            static_cast<GDALDriver *>(GDALGetDriverByName("GTiff"));
1413
1414
0
        if (poDr == nullptr)
1415
0
            return CE_Failure;
1416
1417
0
        GDALRasterBand *const poTBand = poDS->GetRasterBand(1);
1418
0
        if (poTBand == nullptr)
1419
0
            return CE_Failure;
1420
1421
0
        const int nBands =
1422
0
            (nFlags & GMF_PER_DATASET) ? 1 : poDS->GetRasterCount();
1423
1424
0
        char **papszOpt = CSLSetNameValue(nullptr, "COMPRESS", "DEFLATE");
1425
0
        papszOpt = CSLSetNameValue(papszOpt, "INTERLEAVE", "BAND");
1426
1427
0
        int nBX = 0;
1428
0
        int nBY = 0;
1429
0
        poTBand->GetBlockSize(&nBX, &nBY);
1430
1431
        // Try to create matching tile size if legal in TIFF.
1432
0
        if ((nBX % 16) == 0 && (nBY % 16) == 0)
1433
0
        {
1434
0
            papszOpt = CSLSetNameValue(papszOpt, "TILED", "YES");
1435
0
            papszOpt = CSLSetNameValue(papszOpt, "BLOCKXSIZE",
1436
0
                                       CPLString().Printf("%d", nBX));
1437
0
            papszOpt = CSLSetNameValue(papszOpt, "BLOCKYSIZE",
1438
0
                                       CPLString().Printf("%d", nBY));
1439
0
        }
1440
1441
0
        CPLString osMskFilename;
1442
0
        osMskFilename.Printf("%s.msk", poDS->GetDescription());
1443
0
        poMaskDS =
1444
0
            poDr->Create(osMskFilename, poDS->GetRasterXSize(),
1445
0
                         poDS->GetRasterYSize(), nBands, GDT_Byte, papszOpt);
1446
0
        CSLDestroy(papszOpt);
1447
1448
0
        if (poMaskDS == nullptr)  // Presumably error already issued.
1449
0
            return CE_Failure;
1450
1451
0
        bOwnMaskDS = true;
1452
0
    }
1453
1454
    /* -------------------------------------------------------------------- */
1455
    /*      Save the mask flags for this band.                              */
1456
    /* -------------------------------------------------------------------- */
1457
0
    if (nBand > poMaskDS->GetRasterCount())
1458
0
    {
1459
0
        CPLError(CE_Failure, CPLE_AppDefined,
1460
0
                 "Attempt to create a mask band for band %d of %s, "
1461
0
                 "but the .msk file has a PER_DATASET mask.",
1462
0
                 nBand, poDS->GetDescription());
1463
0
        return CE_Failure;
1464
0
    }
1465
1466
0
    for (int iBand = 0; iBand < poDS->GetRasterCount(); iBand++)
1467
0
    {
1468
        // we write only the info for this band, unless we are
1469
        // using PER_DATASET in which case we write for all.
1470
0
        if (nBand != iBand + 1 && !(nFlags & GMF_PER_DATASET))
1471
0
            continue;
1472
1473
0
        poMaskDS->SetMetadataItem(
1474
0
            CPLString().Printf("INTERNAL_MASK_FLAGS_%d", iBand + 1),
1475
0
            CPLString().Printf("%d", nFlags));
1476
0
    }
1477
1478
0
    return CE_None;
1479
0
}
1480
1481
/************************************************************************/
1482
/*                            GetMaskBand()                             */
1483
/************************************************************************/
1484
1485
// Secret code meaning we don't handle this band.
1486
constexpr int MISSING_FLAGS = 0x8000;
1487
1488
GDALRasterBand *GDALDefaultOverviews::GetMaskBand(int nBand)
1489
1490
0
{
1491
0
    const int nFlags = GetMaskFlags(nBand);
1492
1493
0
    if (poMaskDS == nullptr || nFlags == MISSING_FLAGS)
1494
0
        return nullptr;
1495
1496
0
    if (nFlags & GMF_PER_DATASET)
1497
0
        return poMaskDS->GetRasterBand(1);
1498
1499
0
    if (nBand > 0)
1500
0
        return poMaskDS->GetRasterBand(nBand);
1501
1502
0
    return nullptr;
1503
0
}
1504
1505
/************************************************************************/
1506
/*                            GetMaskFlags()                            */
1507
/************************************************************************/
1508
1509
int GDALDefaultOverviews::GetMaskFlags(int nBand)
1510
1511
0
{
1512
    /* -------------------------------------------------------------------- */
1513
    /*      Fetch this band's metadata entry.  They are of the form:        */
1514
    /*        INTERNAL_MASK_FLAGS_n: flags                                  */
1515
    /* -------------------------------------------------------------------- */
1516
0
    if (!HaveMaskFile())
1517
0
        return 0;
1518
1519
0
    const char *pszValue = poMaskDS->GetMetadataItem(
1520
0
        CPLString().Printf("INTERNAL_MASK_FLAGS_%d", std::max(nBand, 1)));
1521
1522
0
    if (pszValue == nullptr)
1523
0
        return MISSING_FLAGS;
1524
1525
0
    return atoi(pszValue);
1526
0
}
1527
1528
/************************************************************************/
1529
/*                            HaveMaskFile()                            */
1530
/*                                                                      */
1531
/*      Check for a mask file if we haven't already done so.            */
1532
/*      Returns TRUE if we have one, otherwise FALSE.                   */
1533
/************************************************************************/
1534
1535
int GDALDefaultOverviews::HaveMaskFile(char **papszSiblingFiles,
1536
                                       const char *pszBasename)
1537
1538
0
{
1539
    /* -------------------------------------------------------------------- */
1540
    /*      Have we already checked for masks?                              */
1541
    /* -------------------------------------------------------------------- */
1542
0
    if (bCheckedForMask)
1543
0
        return poMaskDS != nullptr;
1544
1545
0
    if (papszSiblingFiles == nullptr)
1546
0
        papszSiblingFiles = papszInitSiblingFiles;
1547
1548
    /* -------------------------------------------------------------------- */
1549
    /*      Are we an overview?  If so we need to find the corresponding    */
1550
    /*      overview in the base files mask file (if there is one).         */
1551
    /* -------------------------------------------------------------------- */
1552
0
    if (poBaseDS != nullptr && poBaseDS->oOvManager.HaveMaskFile())
1553
0
    {
1554
0
        GDALRasterBand *const poBaseBand = poBaseDS->GetRasterBand(1);
1555
0
        GDALDataset *poMaskDSTemp = nullptr;
1556
0
        if (poBaseBand != nullptr)
1557
0
        {
1558
0
            GDALRasterBand *poBaseMask = poBaseBand->GetMaskBand();
1559
0
            if (poBaseMask != nullptr)
1560
0
            {
1561
0
                const int nOverviewCount = poBaseMask->GetOverviewCount();
1562
0
                for (int iOver = 0; iOver < nOverviewCount; iOver++)
1563
0
                {
1564
0
                    GDALRasterBand *const poOverBand =
1565
0
                        poBaseMask->GetOverview(iOver);
1566
0
                    if (poOverBand == nullptr)
1567
0
                        continue;
1568
1569
0
                    if (poOverBand->GetXSize() == poDS->GetRasterXSize() &&
1570
0
                        poOverBand->GetYSize() == poDS->GetRasterYSize())
1571
0
                    {
1572
0
                        poMaskDSTemp = poOverBand->GetDataset();
1573
0
                        break;
1574
0
                    }
1575
0
                }
1576
0
            }
1577
0
        }
1578
1579
0
        if (poMaskDSTemp != poDS)
1580
0
        {
1581
0
            poMaskDS = poMaskDSTemp;
1582
0
            bCheckedForMask = true;
1583
0
            bOwnMaskDS = false;
1584
1585
0
            return poMaskDS != nullptr;
1586
0
        }
1587
0
    }
1588
1589
    /* -------------------------------------------------------------------- */
1590
    /*      Are we even initialized?  If not, we apparently don't want      */
1591
    /*      to support overviews and masks.                                 */
1592
    /* -------------------------------------------------------------------- */
1593
0
    if (poDS == nullptr)
1594
0
        return FALSE;
1595
1596
    /* -------------------------------------------------------------------- */
1597
    /*      Check for .msk file.                                            */
1598
    /* -------------------------------------------------------------------- */
1599
0
    bCheckedForMask = true;
1600
1601
0
    if (pszBasename == nullptr)
1602
0
        pszBasename = poDS->GetDescription();
1603
1604
    // Don't bother checking for masks of masks.
1605
0
    if (EQUAL(CPLGetExtensionSafe(pszBasename).c_str(), "msk"))
1606
0
        return FALSE;
1607
1608
0
    if (!GDALCanFileAcceptSidecarFile(pszBasename))
1609
0
        return FALSE;
1610
0
    CPLString osMskFilename;
1611
0
    osMskFilename.Printf("%s.msk", pszBasename);
1612
1613
0
    std::vector<char> achMskFilename;
1614
0
    achMskFilename.resize(osMskFilename.size() + 1);
1615
0
    memcpy(&(achMskFilename[0]), osMskFilename.c_str(),
1616
0
           osMskFilename.size() + 1);
1617
0
    bool bExists =
1618
0
        CPL_TO_BOOL(CPLCheckForFile(&achMskFilename[0], papszSiblingFiles));
1619
0
    osMskFilename = &achMskFilename[0];
1620
1621
0
#if !defined(_WIN32)
1622
0
    if (!bExists && !papszSiblingFiles)
1623
0
    {
1624
0
        osMskFilename.Printf("%s.MSK", pszBasename);
1625
0
        memcpy(&(achMskFilename[0]), osMskFilename.c_str(),
1626
0
               osMskFilename.size() + 1);
1627
0
        bExists =
1628
0
            CPL_TO_BOOL(CPLCheckForFile(&achMskFilename[0], papszSiblingFiles));
1629
0
        osMskFilename = &achMskFilename[0];
1630
0
    }
1631
0
#endif
1632
1633
0
    if (!bExists)
1634
0
        return FALSE;
1635
1636
    /* -------------------------------------------------------------------- */
1637
    /*      Open the file.                                                  */
1638
    /* -------------------------------------------------------------------- */
1639
0
    poMaskDS = GDALDataset::Open(
1640
0
        osMskFilename,
1641
0
        GDAL_OF_RASTER | (poDS->GetAccess() == GA_Update ? GDAL_OF_UPDATE : 0),
1642
0
        nullptr, nullptr, papszInitSiblingFiles);
1643
0
    CPLAssert(poMaskDS != poDS);
1644
1645
0
    if (poMaskDS == nullptr)
1646
0
        return FALSE;
1647
1648
0
    bOwnMaskDS = true;
1649
1650
0
    return TRUE;
1651
0
}
1652
1653
/************************************************************************/
1654
/*                    GDALGetNormalizedOvrResampling()                  */
1655
/************************************************************************/
1656
1657
std::string GDALGetNormalizedOvrResampling(const char *pszResampling)
1658
0
{
1659
0
    if (pszResampling &&
1660
0
        EQUAL(pszResampling, "AVERAGE_BIT2GRAYSCALE_MINISWHITE"))
1661
0
        return "AVERAGE_BIT2GRAYSCALE_MINISWHITE";
1662
0
    else if (pszResampling && STARTS_WITH_CI(pszResampling, "AVERAGE_BIT2"))
1663
0
        return "AVERAGE_BIT2GRAYSCALE";
1664
0
    else if (pszResampling && STARTS_WITH_CI(pszResampling, "NEAR"))
1665
0
        return "NEAREST";
1666
0
    else if (pszResampling && EQUAL(pszResampling, "AVERAGE_MAGPHASE"))
1667
0
        return "AVERAGE_MAGPHASE";
1668
0
    else if (pszResampling && STARTS_WITH_CI(pszResampling, "AVER"))
1669
0
        return "AVERAGE";
1670
0
    else if (pszResampling && !EQUAL(pszResampling, "NONE"))
1671
0
    {
1672
0
        return CPLString(pszResampling).toupper();
1673
0
    }
1674
0
    return std::string();
1675
0
}
1676
1677
//! @endcond