Coverage Report

Created: 2025-08-28 06:57

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