Coverage Report

Created: 2025-06-13 06:29

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