Coverage Report

Created: 2026-04-01 06:20

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/gdal/gcore/gdaloverviewdataset.cpp
Line
Count
Source
1
/******************************************************************************
2
 *
3
 * Project:  GDAL Core
4
 * Purpose:  Implementation of a dataset overview warping class
5
 * Author:   Even Rouault, <even dot rouault at spatialys dot com>
6
 *
7
 ******************************************************************************
8
 * Copyright (c) 2014, Even Rouault, <even dot rouault at spatialys dot com>
9
 *
10
 * SPDX-License-Identifier: MIT
11
 ****************************************************************************/
12
13
#include "cpl_port.h"
14
#include "gdal_priv.h"
15
16
#include <cassert>
17
#include <cstring>
18
19
#include "cpl_conv.h"
20
#include "cpl_error.h"
21
#include "cpl_progress.h"
22
#include "cpl_string.h"
23
#include "gdal.h"
24
#include "gdal_mdreader.h"
25
#include "gdal_proxy.h"
26
27
/** In GDAL, GDALRasterBand::GetOverview() returns a stand-alone band, that may
28
    have no parent dataset. This can be inconvenient in certain contexts, where
29
    cross-band processing must be done, or when API expect a fully fledged
30
    dataset.  Furthermore even if overview band has a container dataset, that
31
    one often fails to declare its projection, geotransform, etc... which make
32
    it somehow useless. GDALOverviewDataset remedies to those deficiencies.
33
*/
34
35
class GDALOverviewBand;
36
37
/* ******************************************************************** */
38
/*                          GDALOverviewDataset                         */
39
/* ******************************************************************** */
40
41
class GDALOverviewDataset final : public GDALDataset
42
{
43
  private:
44
    friend class GDALOverviewBand;
45
46
    GDALDataset *poMainDS = nullptr;
47
48
    GDALDataset *poOvrDS = nullptr;  // Will be often NULL.
49
    int nOvrLevel = 0;
50
    bool bThisLevelOnly = false;
51
52
    int nGCPCount = 0;
53
    GDAL_GCP *pasGCPList = nullptr;
54
    char **papszMD_RPC = nullptr;
55
    char **papszMD_GEOLOCATION = nullptr;
56
    GDALOverviewBand *m_poMaskBand = nullptr;
57
58
    static void Rescale(char **&papszMD, const char *pszItem, double dfRatio,
59
                        double dfDefaultVal, double dfPreShift = 0,
60
                        double dfPostShift = 0);
61
62
  protected:
63
    CPLErr IRasterIO(GDALRWFlag, int, int, int, int, void *, int, int,
64
                     GDALDataType, int, BANDMAP_TYPE, GSpacing, GSpacing,
65
                     GSpacing, GDALRasterIOExtraArg *psExtraArg) override;
66
67
  public:
68
    GDALOverviewDataset(GDALDataset *poMainDS, int nOvrLevel,
69
                        bool bThisLevelOnly);
70
    ~GDALOverviewDataset() override;
71
72
    const OGRSpatialReference *GetSpatialRef() const override;
73
    CPLErr GetGeoTransform(GDALGeoTransform &gt) const override;
74
75
    int GetGCPCount() override;
76
    const OGRSpatialReference *GetGCPSpatialRef() const override;
77
    const GDAL_GCP *GetGCPs() override;
78
79
    CSLConstList GetMetadata(const char *pszDomain = "") override;
80
    const char *GetMetadataItem(const char *pszName,
81
                                const char *pszDomain = "") override;
82
83
    int CloseDependentDatasets() override;
84
85
  private:
86
    CPL_DISALLOW_COPY_ASSIGN(GDALOverviewDataset)
87
};
88
89
/* ******************************************************************** */
90
/*                           GDALOverviewBand                           */
91
/* ******************************************************************** */
92
93
class GDALOverviewBand final : public GDALProxyRasterBand
94
{
95
  protected:
96
    friend class GDALOverviewDataset;
97
98
    GDALRasterBand *poUnderlyingBand = nullptr;
99
    GDALRasterBand *RefUnderlyingRasterBand(bool bForceOpen) const override;
100
101
    CPLErr IRasterIO(GDALRWFlag, int, int, int, int, void *, int, int,
102
                     GDALDataType, GSpacing, GSpacing,
103
                     GDALRasterIOExtraArg *psExtraArg) override;
104
105
  public:
106
    GDALOverviewBand(GDALOverviewDataset *poDS, int nBand);
107
    ~GDALOverviewBand() override;
108
109
    CPLErr FlushCache(bool bAtClosing) override;
110
111
    int GetOverviewCount() override;
112
    GDALRasterBand *GetOverview(int) override;
113
114
    int GetMaskFlags() override;
115
    GDALRasterBand *GetMaskBand() override;
116
117
  private:
118
    CPL_DISALLOW_COPY_ASSIGN(GDALOverviewBand)
119
};
120
121
/************************************************************************/
122
/*                           GetOverviewEx()                            */
123
/************************************************************************/
124
125
static GDALRasterBand *GetOverviewEx(GDALRasterBand *poBand, int nLevel)
126
0
{
127
0
    if (nLevel == -1)
128
0
        return poBand;
129
0
    return poBand->GetOverview(nLevel);
130
0
}
131
132
/************************************************************************/
133
/*                     GDALCreateOverviewDataset()                      */
134
/************************************************************************/
135
136
// Takes a reference on poMainDS in case of success.
137
// nOvrLevel=-1 means the full resolution dataset (only useful if
138
// bThisLevelOnly = false to expose a dataset without its overviews)
139
GDALDataset *GDALCreateOverviewDataset(GDALDataset *poMainDS, int nOvrLevel,
140
                                       bool bThisLevelOnly)
141
0
{
142
    // Sanity checks.
143
0
    const int nBands = poMainDS->GetRasterCount();
144
0
    if (nBands == 0)
145
0
        return nullptr;
146
147
0
    auto poFirstBand = GetOverviewEx(poMainDS->GetRasterBand(1), nOvrLevel);
148
0
    for (int i = 1; i <= nBands; ++i)
149
0
    {
150
0
        auto poBand = GetOverviewEx(poMainDS->GetRasterBand(i), nOvrLevel);
151
0
        if (poBand == nullptr)
152
0
        {
153
0
            return nullptr;
154
0
        }
155
0
        if (poBand->GetXSize() != poFirstBand->GetXSize() ||
156
0
            poBand->GetYSize() != poFirstBand->GetYSize())
157
0
        {
158
0
            return nullptr;
159
0
        }
160
0
    }
161
162
0
    return new GDALOverviewDataset(poMainDS, nOvrLevel, bThisLevelOnly);
163
0
}
164
165
/************************************************************************/
166
/*                        GDALOverviewDataset()                         */
167
/************************************************************************/
168
169
GDALOverviewDataset::GDALOverviewDataset(GDALDataset *poMainDSIn,
170
                                         int nOvrLevelIn, bool bThisLevelOnlyIn)
171
0
    : poMainDS(poMainDSIn), nOvrLevel(nOvrLevelIn),
172
0
      bThisLevelOnly(bThisLevelOnlyIn)
173
0
{
174
0
    poMainDSIn->Reference();
175
0
    eAccess = poMainDS->GetAccess();
176
0
    auto poFirstBand = GetOverviewEx(poMainDS->GetRasterBand(1), nOvrLevel);
177
0
    nRasterXSize = poFirstBand->GetXSize();
178
0
    nRasterYSize = poFirstBand->GetYSize();
179
0
    poOvrDS = poFirstBand->GetDataset();
180
0
    if (nOvrLevel != -1 && poOvrDS != nullptr && poOvrDS == poMainDS)
181
0
    {
182
0
        CPLDebug("GDAL", "Dataset of overview is the same as the main band. "
183
0
                         "This is not expected");
184
0
        poOvrDS = nullptr;
185
0
    }
186
0
    nBands = poMainDS->GetRasterCount();
187
0
    for (int i = 0; i < nBands; ++i)
188
0
    {
189
0
        if (poOvrDS)
190
0
        {
191
            // Check that all overview bands belong to the same dataset
192
0
            auto poOvrBand =
193
0
                GetOverviewEx(poMainDS->GetRasterBand(i + 1), nOvrLevel);
194
0
            if (poOvrBand->GetDataset() != poOvrDS)
195
0
                poOvrDS = nullptr;
196
0
        }
197
0
        SetBand(i + 1, new GDALOverviewBand(this, i + 1));
198
0
    }
199
200
0
    if (poFirstBand->GetMaskFlags() == GMF_PER_DATASET)
201
0
    {
202
0
        auto poOvrMaskBand = poFirstBand->GetMaskBand();
203
0
        if (poOvrMaskBand && poOvrMaskBand->GetXSize() == nRasterXSize &&
204
0
            poOvrMaskBand->GetYSize() == nRasterYSize)
205
0
        {
206
0
            m_poMaskBand = new GDALOverviewBand(this, 0);
207
0
        }
208
0
    }
209
210
    // We create a fake driver that has the same name as the original
211
    // one, but we cannot use the real driver object, so that code
212
    // doesn't try to cast the GDALOverviewDataset* as a native dataset
213
    // object.
214
0
    if (poMainDS->GetDriver() != nullptr)
215
0
    {
216
0
        poDriver = new GDALDriver();
217
0
        poDriver->SetDescription(poMainDS->GetDriver()->GetDescription());
218
0
        poDriver->SetMetadata(poMainDS->GetDriver()->GetMetadata());
219
0
    }
220
221
0
    SetDescription(poMainDS->GetDescription());
222
223
0
    CPLDebug("GDAL", "GDALOverviewDataset(%s, this=%p) creation.",
224
0
             poMainDS->GetDescription(), this);
225
226
0
    papszOpenOptions = CSLDuplicate(poMainDS->GetOpenOptions());
227
    // Add OVERVIEW_LEVEL if not called from GDALOpenEx(), but directly.
228
0
    papszOpenOptions = CSLSetNameValue(
229
0
        papszOpenOptions, "OVERVIEW_LEVEL",
230
0
        nOvrLevel == -1
231
0
            ? "NONE"
232
0
            : CPLSPrintf("%d%s", nOvrLevel, bThisLevelOnly ? " only" : ""));
233
0
}
234
235
/************************************************************************/
236
/*                        ~GDALOverviewDataset()                        */
237
/************************************************************************/
238
239
GDALOverviewDataset::~GDALOverviewDataset()
240
0
{
241
0
    GDALOverviewDataset::FlushCache(true);
242
243
0
    GDALOverviewDataset::CloseDependentDatasets();
244
245
0
    if (nGCPCount > 0)
246
0
    {
247
0
        GDALDeinitGCPs(nGCPCount, pasGCPList);
248
0
        CPLFree(pasGCPList);
249
0
    }
250
0
    CSLDestroy(papszMD_RPC);
251
252
0
    CSLDestroy(papszMD_GEOLOCATION);
253
254
0
    delete poDriver;
255
0
}
256
257
/************************************************************************/
258
/*                       CloseDependentDatasets()                       */
259
/************************************************************************/
260
261
int GDALOverviewDataset::CloseDependentDatasets()
262
0
{
263
0
    bool bRet = false;
264
265
0
    if (poMainDS)
266
0
    {
267
0
        for (int i = 0; i < nBands; ++i)
268
0
        {
269
0
            GDALOverviewBand *const band =
270
0
                cpl::down_cast<GDALOverviewBand *>(papoBands[i]);
271
0
            band->poUnderlyingBand = nullptr;
272
0
        }
273
0
        if (poMainDS->ReleaseRef())
274
0
            bRet = true;
275
0
        poMainDS = nullptr;
276
0
    }
277
278
0
    if (m_poMaskBand)
279
0
    {
280
0
        m_poMaskBand->poUnderlyingBand = nullptr;
281
0
        delete m_poMaskBand;
282
0
        m_poMaskBand = nullptr;
283
0
    }
284
285
0
    return bRet;
286
0
}
287
288
/************************************************************************/
289
/*                             IRasterIO()                              */
290
/*                                                                      */
291
/*      The default implementation of IRasterIO() is to pass the        */
292
/*      request off to each band objects rasterio methods with          */
293
/*      appropriate arguments.                                          */
294
/************************************************************************/
295
296
CPLErr GDALOverviewDataset::IRasterIO(
297
    GDALRWFlag eRWFlag, int nXOff, int nYOff, int nXSize, int nYSize,
298
    void *pData, int nBufXSize, int nBufYSize, GDALDataType eBufType,
299
    int nBandCount, BANDMAP_TYPE panBandMap, GSpacing nPixelSpace,
300
    GSpacing nLineSpace, GSpacing nBandSpace, GDALRasterIOExtraArg *psExtraArg)
301
302
0
{
303
    // Try to pass the request to the most appropriate overview dataset.
304
0
    if (nBufXSize < nXSize && nBufYSize < nYSize)
305
0
    {
306
0
        int bTried = FALSE;
307
0
        const CPLErr eErr = TryOverviewRasterIO(
308
0
            eRWFlag, nXOff, nYOff, nXSize, nYSize, pData, nBufXSize, nBufYSize,
309
0
            eBufType, nBandCount, panBandMap, nPixelSpace, nLineSpace,
310
0
            nBandSpace, psExtraArg, &bTried);
311
0
        if (bTried)
312
0
            return eErr;
313
0
    }
314
315
    // In case the overview bands are really linked to a dataset, then issue
316
    // the request to that dataset.
317
0
    if (poOvrDS != nullptr)
318
0
    {
319
0
        const bool bEnabledOverviews = poOvrDS->AreOverviewsEnabled();
320
0
        poOvrDS->SetEnableOverviews(false);
321
0
        CPLErr eErr = poOvrDS->RasterIO(eRWFlag, nXOff, nYOff, nXSize, nYSize,
322
0
                                        pData, nBufXSize, nBufYSize, eBufType,
323
0
                                        nBandCount, panBandMap, nPixelSpace,
324
0
                                        nLineSpace, nBandSpace, psExtraArg);
325
0
        poOvrDS->SetEnableOverviews(bEnabledOverviews);
326
0
        return eErr;
327
0
    }
328
329
0
    GDALProgressFunc pfnProgressGlobal = psExtraArg->pfnProgress;
330
0
    void *pProgressDataGlobal = psExtraArg->pProgressData;
331
0
    CPLErr eErr = CE_None;
332
333
0
    for (int iBandIndex = 0; iBandIndex < nBandCount && eErr == CE_None;
334
0
         ++iBandIndex)
335
0
    {
336
0
        GDALOverviewBand *poBand = cpl::down_cast<GDALOverviewBand *>(
337
0
            GetRasterBand(panBandMap[iBandIndex]));
338
0
        GByte *pabyBandData =
339
0
            static_cast<GByte *>(pData) + iBandIndex * nBandSpace;
340
341
0
        psExtraArg->pfnProgress = GDALScaledProgress;
342
0
        psExtraArg->pProgressData = GDALCreateScaledProgress(
343
0
            1.0 * iBandIndex / nBandCount, 1.0 * (iBandIndex + 1) / nBandCount,
344
0
            pfnProgressGlobal, pProgressDataGlobal);
345
346
0
        eErr = poBand->IRasterIO(eRWFlag, nXOff, nYOff, nXSize, nYSize,
347
0
                                 pabyBandData, nBufXSize, nBufYSize, eBufType,
348
0
                                 nPixelSpace, nLineSpace, psExtraArg);
349
350
0
        GDALDestroyScaledProgress(psExtraArg->pProgressData);
351
0
    }
352
353
0
    psExtraArg->pfnProgress = pfnProgressGlobal;
354
0
    psExtraArg->pProgressData = pProgressDataGlobal;
355
356
0
    return eErr;
357
0
}
358
359
/************************************************************************/
360
/*                           GetSpatialRef()                            */
361
/************************************************************************/
362
363
const OGRSpatialReference *GDALOverviewDataset::GetSpatialRef() const
364
365
0
{
366
0
    return poMainDS->GetSpatialRef();
367
0
}
368
369
/************************************************************************/
370
/*                          GetGeoTransform()                           */
371
/************************************************************************/
372
373
CPLErr GDALOverviewDataset::GetGeoTransform(GDALGeoTransform &gt) const
374
375
0
{
376
0
    if (poMainDS->GetGeoTransform(gt) != CE_None)
377
0
        return CE_Failure;
378
379
0
    const double dfOvrXRatio =
380
0
        static_cast<double>(poMainDS->GetRasterXSize()) / nRasterXSize;
381
0
    const double dfOvrYRatio =
382
0
        static_cast<double>(poMainDS->GetRasterYSize()) / nRasterYSize;
383
0
    gt.Rescale(dfOvrXRatio, dfOvrYRatio);
384
385
0
    return CE_None;
386
0
}
387
388
/************************************************************************/
389
/*                            GetGCPCount()                             */
390
/************************************************************************/
391
392
int GDALOverviewDataset::GetGCPCount()
393
394
0
{
395
0
    return poMainDS->GetGCPCount();
396
0
}
397
398
/************************************************************************/
399
/*                          GetGCPSpatialRef()                          */
400
/************************************************************************/
401
402
const OGRSpatialReference *GDALOverviewDataset::GetGCPSpatialRef() const
403
404
0
{
405
0
    return poMainDS->GetGCPSpatialRef();
406
0
}
407
408
/************************************************************************/
409
/*                              GetGCPs()                               */
410
/************************************************************************/
411
412
const GDAL_GCP *GDALOverviewDataset::GetGCPs()
413
414
0
{
415
0
    if (pasGCPList != nullptr)
416
0
        return pasGCPList;
417
418
0
    const GDAL_GCP *pasGCPsMain = poMainDS->GetGCPs();
419
0
    if (pasGCPsMain == nullptr)
420
0
        return nullptr;
421
0
    nGCPCount = poMainDS->GetGCPCount();
422
423
0
    pasGCPList = GDALDuplicateGCPs(nGCPCount, pasGCPsMain);
424
0
    for (int i = 0; i < nGCPCount; ++i)
425
0
    {
426
0
        pasGCPList[i].dfGCPPixel *=
427
0
            static_cast<double>(nRasterXSize) / poMainDS->GetRasterXSize();
428
0
        pasGCPList[i].dfGCPLine *=
429
0
            static_cast<double>(nRasterYSize) / poMainDS->GetRasterYSize();
430
0
    }
431
0
    return pasGCPList;
432
0
}
433
434
/************************************************************************/
435
/*                              Rescale()                               */
436
/************************************************************************/
437
438
/* static */
439
void GDALOverviewDataset::Rescale(char **&papszMD, const char *pszItem,
440
                                  double dfRatio, double dfDefaultVal,
441
                                  double dfPreShift /*= 0*/,
442
                                  double dfPostShift /*= 0*/)
443
0
{
444
0
    double dfVal = CPLAtofM(CSLFetchNameValueDef(
445
0
        papszMD, pszItem, CPLSPrintf("%.17g", dfDefaultVal)));
446
0
    dfVal += dfPreShift;
447
0
    dfVal *= dfRatio;
448
0
    dfVal += dfPostShift;
449
0
    papszMD = CSLSetNameValue(papszMD, pszItem, CPLSPrintf("%.17g", dfVal));
450
0
}
451
452
/************************************************************************/
453
/*                            GetMetadata()                             */
454
/************************************************************************/
455
456
CSLConstList GDALOverviewDataset::GetMetadata(const char *pszDomain)
457
0
{
458
0
    if (poOvrDS != nullptr)
459
0
    {
460
0
        CSLConstList papszMD = poOvrDS->GetMetadata(pszDomain);
461
0
        if (papszMD != nullptr)
462
0
            return papszMD;
463
0
    }
464
465
0
    CSLConstList papszMD = poMainDS->GetMetadata(pszDomain);
466
467
    // We may need to rescale some values from the RPC metadata domain.
468
0
    if (pszDomain != nullptr && EQUAL(pszDomain, MD_DOMAIN_RPC) &&
469
0
        papszMD != nullptr)
470
0
    {
471
0
        if (papszMD_RPC)
472
0
            return papszMD_RPC;
473
0
        papszMD_RPC = CSLDuplicate(papszMD);
474
475
0
        const double dfXRatio =
476
0
            static_cast<double>(nRasterXSize) / poMainDS->GetRasterXSize();
477
0
        const double dfYRatio =
478
0
            static_cast<double>(nRasterYSize) / poMainDS->GetRasterYSize();
479
480
        // For line offset and pixel offset, we need to convert from RPC
481
        // pixel center registration convention to GDAL pixel top-left corner
482
        // registration convention by adding an initial 0.5 shift, and un-apply
483
        // it after scaling.
484
485
0
        Rescale(papszMD_RPC, RPC_LINE_OFF, dfYRatio, 0.0, 0.5, -0.5);
486
0
        Rescale(papszMD_RPC, RPC_LINE_SCALE, dfYRatio, 1.0);
487
0
        Rescale(papszMD_RPC, RPC_SAMP_OFF, dfXRatio, 0.0, 0.5, -0.5);
488
0
        Rescale(papszMD_RPC, RPC_SAMP_SCALE, dfXRatio, 1.0);
489
490
0
        papszMD = papszMD_RPC;
491
0
    }
492
493
    // We may need to rescale some values from the GEOLOCATION metadata domain.
494
0
    if (pszDomain != nullptr && EQUAL(pszDomain, "GEOLOCATION") &&
495
0
        papszMD != nullptr)
496
0
    {
497
0
        if (papszMD_GEOLOCATION)
498
0
            return papszMD_GEOLOCATION;
499
0
        papszMD_GEOLOCATION = CSLDuplicate(papszMD);
500
501
0
        Rescale(papszMD_GEOLOCATION, "PIXEL_OFFSET",
502
0
                static_cast<double>(poMainDS->GetRasterXSize()) / nRasterXSize,
503
0
                0.0);
504
0
        Rescale(papszMD_GEOLOCATION, "LINE_OFFSET",
505
0
                static_cast<double>(poMainDS->GetRasterYSize()) / nRasterYSize,
506
0
                0.0);
507
508
0
        Rescale(papszMD_GEOLOCATION, "PIXEL_STEP",
509
0
                static_cast<double>(nRasterXSize) / poMainDS->GetRasterXSize(),
510
0
                1.0);
511
0
        Rescale(papszMD_GEOLOCATION, "LINE_STEP",
512
0
                static_cast<double>(nRasterYSize) / poMainDS->GetRasterYSize(),
513
0
                1.0);
514
515
0
        papszMD = papszMD_GEOLOCATION;
516
0
    }
517
518
0
    return papszMD;
519
0
}
520
521
/************************************************************************/
522
/*                          GetMetadataItem()                           */
523
/************************************************************************/
524
525
const char *GDALOverviewDataset::GetMetadataItem(const char *pszName,
526
                                                 const char *pszDomain)
527
0
{
528
0
    if (poOvrDS != nullptr)
529
0
    {
530
0
        const char *pszValue = poOvrDS->GetMetadataItem(pszName, pszDomain);
531
0
        if (pszValue != nullptr)
532
0
            return pszValue;
533
0
    }
534
535
0
    if (pszDomain != nullptr &&
536
0
        (EQUAL(pszDomain, "RPC") || EQUAL(pszDomain, "GEOLOCATION")))
537
0
    {
538
0
        CSLConstList papszMD = GetMetadata(pszDomain);
539
0
        return CSLFetchNameValue(papszMD, pszName);
540
0
    }
541
542
0
    return poMainDS->GetMetadataItem(pszName, pszDomain);
543
0
}
544
545
/************************************************************************/
546
/*                          GDALOverviewBand()                          */
547
/************************************************************************/
548
549
GDALOverviewBand::GDALOverviewBand(GDALOverviewDataset *poDSIn, int nBandIn)
550
0
{
551
0
    poDS = poDSIn;
552
0
    nBand = nBandIn;
553
0
    nRasterXSize = poDSIn->nRasterXSize;
554
0
    nRasterYSize = poDSIn->nRasterYSize;
555
0
#if defined(__GNUC__)
556
0
#pragma GCC diagnostic push
557
0
#pragma GCC diagnostic ignored "-Wnull-dereference"
558
0
#endif
559
0
    if (nBandIn == 0)
560
0
    {
561
0
        poUnderlyingBand = GetOverviewEx(poDSIn->poMainDS->GetRasterBand(1),
562
0
                                         poDSIn->nOvrLevel);
563
0
        assert(poUnderlyingBand);
564
0
        poUnderlyingBand = poUnderlyingBand->GetMaskBand();
565
0
    }
566
0
    else
567
0
    {
568
0
        poUnderlyingBand = GetOverviewEx(
569
0
            poDSIn->poMainDS->GetRasterBand(nBandIn), poDSIn->nOvrLevel);
570
0
    }
571
0
    assert(poUnderlyingBand);
572
0
    eDataType = poUnderlyingBand->GetRasterDataType();
573
0
    poUnderlyingBand->GetBlockSize(&nBlockXSize, &nBlockYSize);
574
0
#if defined(__GNUC__)
575
0
#pragma GCC diagnostic pop
576
0
#endif
577
0
}
578
579
/************************************************************************/
580
/*                         ~GDALOverviewBand()                          */
581
/************************************************************************/
582
583
GDALOverviewBand::~GDALOverviewBand()
584
0
{
585
0
    GDALOverviewBand::FlushCache(true);
586
0
}
587
588
/************************************************************************/
589
/*                             FlushCache()                             */
590
/************************************************************************/
591
592
CPLErr GDALOverviewBand::FlushCache(bool bAtClosing)
593
0
{
594
0
    if (poUnderlyingBand)
595
0
        return poUnderlyingBand->FlushCache(bAtClosing);
596
0
    return CE_None;
597
0
}
598
599
/************************************************************************/
600
/*                      RefUnderlyingRasterBand()                       */
601
/************************************************************************/
602
603
GDALRasterBand *
604
GDALOverviewBand::RefUnderlyingRasterBand(bool /*bForceOpen */) const
605
0
{
606
0
    return poUnderlyingBand;
607
0
}
608
609
/************************************************************************/
610
/*                          GetOverviewCount()                          */
611
/************************************************************************/
612
613
int GDALOverviewBand::GetOverviewCount()
614
0
{
615
0
    GDALOverviewDataset *const poOvrDS =
616
0
        cpl::down_cast<GDALOverviewDataset *>(poDS);
617
0
    if (poOvrDS->bThisLevelOnly)
618
0
        return 0;
619
0
    GDALDataset *const poMainDS = poOvrDS->poMainDS;
620
0
    GDALRasterBand *poMainBand = (nBand == 0)
621
0
                                     ? poMainDS->GetRasterBand(1)->GetMaskBand()
622
0
                                     : poMainDS->GetRasterBand(nBand);
623
0
    return poMainBand->GetOverviewCount() - poOvrDS->nOvrLevel - 1;
624
0
    ;
625
0
}
626
627
/************************************************************************/
628
/*                            GetOverview()                             */
629
/************************************************************************/
630
631
GDALRasterBand *GDALOverviewBand::GetOverview(int iOvr)
632
0
{
633
0
    if (iOvr < 0 || iOvr >= GetOverviewCount())
634
0
        return nullptr;
635
0
    GDALOverviewDataset *const poOvrDS =
636
0
        cpl::down_cast<GDALOverviewDataset *>(poDS);
637
0
    GDALDataset *const poMainDS = poOvrDS->poMainDS;
638
0
    GDALRasterBand *poMainBand = (nBand == 0)
639
0
                                     ? poMainDS->GetRasterBand(1)->GetMaskBand()
640
0
                                     : poMainDS->GetRasterBand(nBand);
641
0
    return poMainBand->GetOverview(iOvr + poOvrDS->nOvrLevel + 1);
642
0
}
643
644
/************************************************************************/
645
/*                            GetMaskFlags()                            */
646
/************************************************************************/
647
648
int GDALOverviewBand::GetMaskFlags()
649
0
{
650
0
    GDALOverviewDataset *const poOvrDS =
651
0
        cpl::down_cast<GDALOverviewDataset *>(poDS);
652
0
    if (nBand != 0 && poOvrDS->m_poMaskBand)
653
0
        return GMF_PER_DATASET;
654
0
    return GDALProxyRasterBand::GetMaskFlags();
655
0
}
656
657
/************************************************************************/
658
/*                            GetMaskBand()                             */
659
/************************************************************************/
660
661
GDALRasterBand *GDALOverviewBand::GetMaskBand()
662
0
{
663
0
    GDALOverviewDataset *const poOvrDS =
664
0
        cpl::down_cast<GDALOverviewDataset *>(poDS);
665
0
    if (nBand != 0 && poOvrDS->m_poMaskBand)
666
0
        return poOvrDS->m_poMaskBand;
667
0
    return GDALProxyRasterBand::GetMaskBand();
668
0
}
669
670
/************************************************************************/
671
/*                             IRasterIO()                              */
672
/************************************************************************/
673
674
CPLErr GDALOverviewBand::IRasterIO(GDALRWFlag eRWFlag, int nXOff, int nYOff,
675
                                   int nXSize, int nYSize, void *pData,
676
                                   int nBufXSize, int nBufYSize,
677
                                   GDALDataType eBufType, GSpacing nPixelSpace,
678
                                   GSpacing nLineSpace,
679
                                   GDALRasterIOExtraArg *psExtraArg)
680
0
{
681
0
    GDALOverviewDataset *const poOvrDS =
682
0
        cpl::down_cast<GDALOverviewDataset *>(poDS);
683
0
    if (poOvrDS->bThisLevelOnly && poOvrDS->poOvrDS)
684
0
    {
685
0
        const bool bEnabledOverviews = poOvrDS->poOvrDS->AreOverviewsEnabled();
686
0
        poOvrDS->poOvrDS->SetEnableOverviews(false);
687
0
        CPLErr eErr = GDALProxyRasterBand::IRasterIO(
688
0
            eRWFlag, nXOff, nYOff, nXSize, nYSize, pData, nBufXSize, nBufYSize,
689
0
            eBufType, nPixelSpace, nLineSpace, psExtraArg);
690
0
        poOvrDS->poOvrDS->SetEnableOverviews(bEnabledOverviews);
691
0
        return eErr;
692
0
    }
693
694
    // Try to pass the request to the most appropriate overview.
695
0
    if (nBufXSize < nXSize && nBufYSize < nYSize)
696
0
    {
697
0
        int bTried = FALSE;
698
0
        const CPLErr eErr = TryOverviewRasterIO(
699
0
            eRWFlag, nXOff, nYOff, nXSize, nYSize, pData, nBufXSize, nBufYSize,
700
0
            eBufType, nPixelSpace, nLineSpace, psExtraArg, &bTried);
701
0
        if (bTried)
702
0
            return eErr;
703
0
    }
704
705
0
    return GDALProxyRasterBand::IRasterIO(eRWFlag, nXOff, nYOff, nXSize, nYSize,
706
0
                                          pData, nBufXSize, nBufYSize, eBufType,
707
0
                                          nPixelSpace, nLineSpace, psExtraArg);
708
0
}