Coverage Report

Created: 2025-12-31 08:30

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/gdal/frmts/vrt/vrtrasterband.cpp
Line
Count
Source
1
/******************************************************************************
2
 *
3
 * Project:  Virtual GDAL Datasets
4
 * Purpose:  Implementation of VRTRasterBand
5
 * Author:   Frank Warmerdam <warmerdam@pobox.com>
6
 *
7
 ******************************************************************************
8
 * Copyright (c) 2001, Frank Warmerdam <warmerdam@pobox.com>
9
 * Copyright (c) 2008-2013, Even Rouault <even dot rouault at spatialys.com>
10
 *
11
 * SPDX-License-Identifier: MIT
12
 ****************************************************************************/
13
14
#include "cpl_port.h"
15
#include "vrtdataset.h"
16
17
#include <cmath>
18
#include <cstdlib>
19
#include <cstring>
20
#include <algorithm>
21
#include <limits>
22
#include <memory>
23
#include <vector>
24
25
#include "gdal.h"
26
#include "gdalantirecursion.h"
27
#include "gdal_pam.h"
28
#include "gdal_priv.h"
29
#include "cpl_conv.h"
30
#include "cpl_error.h"
31
#include "cpl_hash_set.h"
32
#include "cpl_minixml.h"
33
#include "cpl_progress.h"
34
#include "cpl_string.h"
35
#include "cpl_vsi.h"
36
#include "vrt_priv.h"
37
38
/*! @cond Doxygen_Suppress */
39
40
/************************************************************************/
41
/* ==================================================================== */
42
/*                          VRTRasterBand                               */
43
/* ==================================================================== */
44
/************************************************************************/
45
46
/************************************************************************/
47
/*                           VRTRasterBand()                            */
48
/************************************************************************/
49
50
VRTRasterBand::VRTRasterBand()
51
202k
{
52
202k
    VRTRasterBand::Initialize(0, 0);
53
202k
}
54
55
/************************************************************************/
56
/*                             Initialize()                             */
57
/************************************************************************/
58
59
void VRTRasterBand::Initialize(int nXSize, int nYSize)
60
61
405k
{
62
405k
    poDS = nullptr;
63
405k
    nBand = 0;
64
405k
    eAccess = GA_ReadOnly;
65
405k
    eDataType = GDT_UInt8;
66
67
405k
    nRasterXSize = nXSize;
68
405k
    nRasterYSize = nYSize;
69
70
405k
    nBlockXSize = std::min(128, nXSize);
71
405k
    nBlockYSize = std::min(128, nYSize);
72
405k
}
73
74
/************************************************************************/
75
/*                           ~VRTRasterBand()                           */
76
/************************************************************************/
77
78
202k
VRTRasterBand::~VRTRasterBand() = default;
79
80
/************************************************************************/
81
/*                         CopyCommonInfoFrom()                         */
82
/*                                                                      */
83
/*      Copy common metadata, pixel descriptions, and color             */
84
/*      interpretation from the provided source band.                   */
85
/************************************************************************/
86
87
CPLErr VRTRasterBand::CopyCommonInfoFrom(GDALRasterBand *poSrcBand)
88
89
55.5k
{
90
55.5k
    SetMetadata(poSrcBand->GetMetadata());
91
55.5k
    const char *pszNBits =
92
55.5k
        poSrcBand->GetMetadataItem("NBITS", "IMAGE_STRUCTURE");
93
55.5k
    SetMetadataItem("NBITS", pszNBits, "IMAGE_STRUCTURE");
94
55.5k
    if (poSrcBand->GetRasterDataType() == GDT_UInt8)
95
52.9k
    {
96
52.9k
        poSrcBand->EnablePixelTypeSignedByteWarning(false);
97
52.9k
        const char *pszPixelType =
98
52.9k
            poSrcBand->GetMetadataItem("PIXELTYPE", "IMAGE_STRUCTURE");
99
52.9k
        poSrcBand->EnablePixelTypeSignedByteWarning(true);
100
52.9k
        SetMetadataItem("PIXELTYPE", pszPixelType, "IMAGE_STRUCTURE");
101
52.9k
    }
102
55.5k
    SetColorTable(poSrcBand->GetColorTable());
103
55.5k
    SetColorInterpretation(poSrcBand->GetColorInterpretation());
104
55.5k
    if (strlen(poSrcBand->GetDescription()) > 0)
105
0
        SetDescription(poSrcBand->GetDescription());
106
107
55.5k
    GDALCopyNoDataValue(this, poSrcBand);
108
55.5k
    SetOffset(poSrcBand->GetOffset());
109
55.5k
    SetScale(poSrcBand->GetScale());
110
55.5k
    SetCategoryNames(poSrcBand->GetCategoryNames());
111
55.5k
    if (!EQUAL(poSrcBand->GetUnitType(), ""))
112
14.1k
        SetUnitType(poSrcBand->GetUnitType());
113
114
55.5k
    GDALRasterAttributeTable *poRAT = poSrcBand->GetDefaultRAT();
115
55.5k
    if (poRAT != nullptr &&
116
0
        static_cast<GIntBig>(poRAT->GetColumnCount()) * poRAT->GetRowCount() <
117
0
            1024 * 1024)
118
0
    {
119
0
        SetDefaultRAT(poRAT);
120
0
    }
121
122
55.5k
    return CE_None;
123
55.5k
}
124
125
/************************************************************************/
126
/*                            SetMetadata()                             */
127
/************************************************************************/
128
129
CPLErr VRTRasterBand::SetMetadata(char **papszMetadata, const char *pszDomain)
130
131
167k
{
132
167k
    cpl::down_cast<VRTDataset *>(poDS)->SetNeedsFlush();
133
134
167k
    return GDALRasterBand::SetMetadata(papszMetadata, pszDomain);
135
167k
}
136
137
/************************************************************************/
138
/*                          SetMetadataItem()                           */
139
/************************************************************************/
140
141
CPLErr VRTRasterBand::SetMetadataItem(const char *pszName, const char *pszValue,
142
                                      const char *pszDomain)
143
144
248k
{
145
248k
    cpl::down_cast<VRTDataset *>(poDS)->SetNeedsFlush();
146
147
248k
    if (EQUAL(pszName, "HideNoDataValue"))
148
0
    {
149
0
        m_bHideNoDataValue = CPLTestBool(pszValue);
150
0
        return CE_None;
151
0
    }
152
153
248k
    return GDALRasterBand::SetMetadataItem(pszName, pszValue, pszDomain);
154
248k
}
155
156
/************************************************************************/
157
/*                            GetUnitType()                             */
158
/************************************************************************/
159
160
const char *VRTRasterBand::GetUnitType()
161
162
141k
{
163
141k
    return m_osUnitType.c_str();
164
141k
}
165
166
/************************************************************************/
167
/*                            SetUnitType()                             */
168
/************************************************************************/
169
170
CPLErr VRTRasterBand::SetUnitType(const char *pszNewValue)
171
172
39.3k
{
173
39.3k
    cpl::down_cast<VRTDataset *>(poDS)->SetNeedsFlush();
174
175
39.3k
    m_osUnitType = pszNewValue ? pszNewValue : "";
176
177
39.3k
    return CE_None;
178
39.3k
}
179
180
/************************************************************************/
181
/*                             GetOffset()                              */
182
/************************************************************************/
183
184
double VRTRasterBand::GetOffset(int *pbSuccess)
185
186
164k
{
187
164k
    if (pbSuccess != nullptr)
188
109k
        *pbSuccess = TRUE;
189
190
164k
    return m_dfOffset;
191
164k
}
192
193
/************************************************************************/
194
/*                             SetOffset()                              */
195
/************************************************************************/
196
197
CPLErr VRTRasterBand::SetOffset(double dfNewOffset)
198
199
192k
{
200
192k
    cpl::down_cast<VRTDataset *>(poDS)->SetNeedsFlush();
201
202
192k
    m_dfOffset = dfNewOffset;
203
192k
    return CE_None;
204
192k
}
205
206
/************************************************************************/
207
/*                              GetScale()                              */
208
/************************************************************************/
209
210
double VRTRasterBand::GetScale(int *pbSuccess)
211
212
164k
{
213
164k
    if (pbSuccess != nullptr)
214
109k
        *pbSuccess = TRUE;
215
216
164k
    return m_dfScale;
217
164k
}
218
219
/************************************************************************/
220
/*                              SetScale()                              */
221
/************************************************************************/
222
223
CPLErr VRTRasterBand::SetScale(double dfNewScale)
224
225
192k
{
226
192k
    cpl::down_cast<VRTDataset *>(poDS)->SetNeedsFlush();
227
228
192k
    m_dfScale = dfNewScale;
229
192k
    return CE_None;
230
192k
}
231
232
/************************************************************************/
233
/*                          GetCategoryNames()                          */
234
/************************************************************************/
235
236
char **VRTRasterBand::GetCategoryNames()
237
238
162k
{
239
162k
    return m_aosCategoryNames.List();
240
162k
}
241
242
/************************************************************************/
243
/*                          SetCategoryNames()                          */
244
/************************************************************************/
245
246
CPLErr VRTRasterBand::SetCategoryNames(char **papszNewNames)
247
248
167k
{
249
167k
    cpl::down_cast<VRTDataset *>(poDS)->SetNeedsFlush();
250
251
167k
    m_aosCategoryNames = CSLDuplicate(papszNewNames);
252
253
167k
    return CE_None;
254
167k
}
255
256
/************************************************************************/
257
/*                        VRTParseCategoryNames()                       */
258
/************************************************************************/
259
260
CPLStringList VRTParseCategoryNames(const CPLXMLNode *psCategoryNames)
261
0
{
262
0
    CPLStringList oCategoryNames;
263
264
0
    for (const CPLXMLNode *psEntry = psCategoryNames->psChild;
265
0
         psEntry != nullptr; psEntry = psEntry->psNext)
266
0
    {
267
0
        if (psEntry->eType != CXT_Element ||
268
0
            !EQUAL(psEntry->pszValue, "Category") ||
269
0
            (psEntry->psChild != nullptr &&
270
0
             psEntry->psChild->eType != CXT_Text))
271
0
            continue;
272
273
0
        oCategoryNames.AddString((psEntry->psChild) ? psEntry->psChild->pszValue
274
0
                                                    : "");
275
0
    }
276
277
0
    return oCategoryNames;
278
0
}
279
280
/************************************************************************/
281
/*                          VRTParseColorTable()                        */
282
/************************************************************************/
283
284
std::unique_ptr<GDALColorTable>
285
VRTParseColorTable(const CPLXMLNode *psColorTable)
286
354
{
287
354
    auto poColorTable = std::make_unique<GDALColorTable>();
288
354
    int iEntry = 0;
289
290
1.15k
    for (const CPLXMLNode *psEntry = psColorTable->psChild; psEntry != nullptr;
291
802
         psEntry = psEntry->psNext)
292
802
    {
293
802
        if (psEntry->eType != CXT_Element || !EQUAL(psEntry->pszValue, "Entry"))
294
22
        {
295
22
            continue;
296
22
        }
297
298
780
        const GDALColorEntry sCEntry = {
299
780
            static_cast<short>(atoi(CPLGetXMLValue(psEntry, "c1", "0"))),
300
780
            static_cast<short>(atoi(CPLGetXMLValue(psEntry, "c2", "0"))),
301
780
            static_cast<short>(atoi(CPLGetXMLValue(psEntry, "c3", "0"))),
302
780
            static_cast<short>(atoi(CPLGetXMLValue(psEntry, "c4", "255")))};
303
304
780
        poColorTable->SetColorEntry(iEntry++, &sCEntry);
305
780
    }
306
307
354
    return poColorTable;
308
354
}
309
310
/************************************************************************/
311
/*                              XMLInit()                               */
312
/************************************************************************/
313
314
CPLErr VRTRasterBand::XMLInit(const CPLXMLNode *psTree, const char *pszVRTPath,
315
                              VRTMapSharedResources &oMapSharedSources)
316
317
25.2k
{
318
    /* -------------------------------------------------------------------- */
319
    /*      Validate a bit.                                                 */
320
    /* -------------------------------------------------------------------- */
321
25.2k
    if (psTree == nullptr || psTree->eType != CXT_Element ||
322
25.2k
        !EQUAL(psTree->pszValue, "VRTRasterBand"))
323
0
    {
324
0
        CPLError(CE_Failure, CPLE_AppDefined,
325
0
                 "Invalid node passed to VRTRasterBand::XMLInit().");
326
0
        return CE_Failure;
327
0
    }
328
329
    /* -------------------------------------------------------------------- */
330
    /*      Set the band if provided as an attribute.                       */
331
    /* -------------------------------------------------------------------- */
332
25.2k
    const char *pszBand = CPLGetXMLValue(psTree, "band", nullptr);
333
25.2k
    if (pszBand != nullptr)
334
15.7k
    {
335
15.7k
        int nNewBand = atoi(pszBand);
336
15.7k
        if (nNewBand != nBand)
337
8.37k
        {
338
8.37k
            CPLError(CE_Warning, CPLE_AppDefined,
339
8.37k
                     "Invalid band number. Got %s, expected %d. Ignoring "
340
8.37k
                     "provided one, and using %d instead",
341
8.37k
                     pszBand, nBand, nBand);
342
8.37k
        }
343
15.7k
    }
344
345
    /* -------------------------------------------------------------------- */
346
    /*      Set the band if provided as an attribute.                       */
347
    /* -------------------------------------------------------------------- */
348
25.2k
    const char *pszDataType = CPLGetXMLValue(psTree, "dataType", nullptr);
349
25.2k
    if (pszDataType != nullptr)
350
16.1k
    {
351
16.1k
        eDataType = GDALGetDataTypeByName(pszDataType);
352
16.1k
        if (eDataType == GDT_Unknown)
353
40
        {
354
40
            CPLError(CE_Failure, CPLE_AppDefined, "Invalid dataType = %s",
355
40
                     pszDataType);
356
40
            return CE_Failure;
357
40
        }
358
16.1k
    }
359
360
25.1k
    const char *pszBlockXSize = CPLGetXMLValue(psTree, "blockXSize", nullptr);
361
25.1k
    if (pszBlockXSize)
362
32
    {
363
32
        int nBlockXSizeIn = atoi(pszBlockXSize);
364
32
        if (nBlockXSizeIn >= 32 && nBlockXSizeIn <= 16384)
365
32
            nBlockXSize = nBlockXSizeIn;
366
32
    }
367
368
25.1k
    const char *pszBlockYSize = CPLGetXMLValue(psTree, "blockYSize", nullptr);
369
25.1k
    if (pszBlockYSize)
370
28
    {
371
28
        int nBlockYSizeIn = atoi(pszBlockYSize);
372
28
        if (nBlockYSizeIn >= 32 && nBlockYSizeIn <= 16384)
373
20
            nBlockYSize = nBlockYSizeIn;
374
28
    }
375
376
    /* -------------------------------------------------------------------- */
377
    /*      Apply any band level metadata.                                  */
378
    /* -------------------------------------------------------------------- */
379
25.1k
    oMDMD.XMLInit(psTree, TRUE);
380
381
    /* -------------------------------------------------------------------- */
382
    /*      Collect various other items of metadata.                        */
383
    /* -------------------------------------------------------------------- */
384
25.1k
    SetDescription(CPLGetXMLValue(psTree, "Description", ""));
385
386
25.1k
    const char *pszNoDataValue = CPLGetXMLValue(psTree, "NoDataValue", nullptr);
387
25.1k
    if (pszNoDataValue != nullptr)
388
4.58k
    {
389
4.58k
        if (eDataType == GDT_Int64)
390
0
        {
391
0
            SetNoDataValueAsInt64(static_cast<int64_t>(
392
0
                std::strtoll(pszNoDataValue, nullptr, 10)));
393
0
        }
394
4.58k
        else if (eDataType == GDT_UInt64)
395
0
        {
396
0
            SetNoDataValueAsUInt64(static_cast<uint64_t>(
397
0
                std::strtoull(pszNoDataValue, nullptr, 10)));
398
0
        }
399
4.58k
        else
400
4.58k
        {
401
4.58k
            SetNoDataValue(CPLAtofM(pszNoDataValue));
402
4.58k
        }
403
4.58k
    }
404
405
25.1k
    if (CPLGetXMLValue(psTree, "HideNoDataValue", nullptr) != nullptr)
406
0
        m_bHideNoDataValue =
407
0
            CPLTestBool(CPLGetXMLValue(psTree, "HideNoDataValue", "0"));
408
409
25.1k
    SetUnitType(CPLGetXMLValue(psTree, "UnitType", nullptr));
410
411
25.1k
    SetOffset(CPLAtof(CPLGetXMLValue(psTree, "Offset", "0.0")));
412
25.1k
    SetScale(CPLAtof(CPLGetXMLValue(psTree, "Scale", "1.0")));
413
414
25.1k
    if (CPLGetXMLValue(psTree, "ColorInterp", nullptr) != nullptr)
415
9.52k
    {
416
9.52k
        const char *pszInterp = CPLGetXMLValue(psTree, "ColorInterp", nullptr);
417
9.52k
        SetColorInterpretation(GDALGetColorInterpretationByName(pszInterp));
418
9.52k
    }
419
420
    /* -------------------------------------------------------------------- */
421
    /*      Category names.                                                 */
422
    /* -------------------------------------------------------------------- */
423
25.1k
    if (const CPLXMLNode *psCategoryNames =
424
25.1k
            CPLGetXMLNode(psTree, "CategoryNames"))
425
0
    {
426
0
        m_aosCategoryNames = VRTParseCategoryNames(psCategoryNames);
427
0
    }
428
429
    /* -------------------------------------------------------------------- */
430
    /*      Collect a color table.                                          */
431
    /* -------------------------------------------------------------------- */
432
25.1k
    if (const CPLXMLNode *psColorTable = CPLGetXMLNode(psTree, "ColorTable"))
433
354
    {
434
354
        auto poColorTable = VRTParseColorTable(psColorTable);
435
354
        if (poColorTable)
436
354
            SetColorTable(poColorTable.get());
437
354
    }
438
439
    /* -------------------------------------------------------------------- */
440
    /*      Raster Attribute Table                                          */
441
    /* -------------------------------------------------------------------- */
442
25.1k
    if (const CPLXMLNode *psRAT =
443
25.1k
            CPLGetXMLNode(psTree, "GDALRasterAttributeTable"))
444
0
    {
445
0
        m_poRAT = std::make_unique<GDALDefaultRasterAttributeTable>();
446
0
        m_poRAT->XMLInit(psRAT, "");
447
0
    }
448
449
    /* -------------------------------------------------------------------- */
450
    /*      Histograms                                                      */
451
    /* -------------------------------------------------------------------- */
452
25.1k
    const CPLXMLNode *psHist = CPLGetXMLNode(psTree, "Histograms");
453
25.1k
    if (psHist != nullptr)
454
0
    {
455
0
        CPLXMLNode sHistTemp = *psHist;
456
0
        sHistTemp.psNext = nullptr;
457
0
        m_psSavedHistograms.reset(CPLCloneXMLTree(&sHistTemp));
458
0
    }
459
460
    /* ==================================================================== */
461
    /*      Overviews                                                       */
462
    /* ==================================================================== */
463
25.1k
    const CPLXMLNode *psNode = psTree->psChild;
464
465
151k
    for (; psNode != nullptr; psNode = psNode->psNext)
466
126k
    {
467
126k
        if (psNode->eType != CXT_Element ||
468
70.4k
            !EQUAL(psNode->pszValue, "Overview"))
469
126k
            continue;
470
471
        /* --------------------------------------------------------------------
472
         */
473
        /*      Prepare filename. */
474
        /* --------------------------------------------------------------------
475
         */
476
0
        const CPLXMLNode *psFileNameNode =
477
0
            CPLGetXMLNode(psNode, "SourceFilename");
478
0
        const char *pszFilename =
479
0
            psFileNameNode ? CPLGetXMLValue(psFileNameNode, nullptr, nullptr)
480
0
                           : nullptr;
481
482
0
        if (pszFilename == nullptr)
483
0
        {
484
0
            CPLError(CE_Warning, CPLE_AppDefined,
485
0
                     "Missing <SourceFilename> element in Overview.");
486
0
            return CE_Failure;
487
0
        }
488
489
0
        if (STARTS_WITH_CI(pszFilename, "MEM:::") && pszVRTPath != nullptr &&
490
0
            !CPLTestBool(CPLGetConfigOption("VRT_ALLOW_MEM_DRIVER", "NO")))
491
0
        {
492
0
            CPLError(CE_Failure, CPLE_AppDefined,
493
0
                     "<SourceFilename> points to a MEM dataset, which is "
494
0
                     "rather suspect! "
495
0
                     "If you know what you are doing, define the "
496
0
                     "VRT_ALLOW_MEM_DRIVER configuration option to YES");
497
0
            return CE_Failure;
498
0
        }
499
500
0
        char *pszSrcDSName = nullptr;
501
0
        if (pszVRTPath != nullptr &&
502
0
            atoi(CPLGetXMLValue(psFileNameNode, "relativetoVRT", "0")))
503
0
        {
504
0
            pszSrcDSName = CPLStrdup(
505
0
                CPLProjectRelativeFilenameSafe(pszVRTPath, pszFilename)
506
0
                    .c_str());
507
0
        }
508
0
        else
509
0
            pszSrcDSName = CPLStrdup(pszFilename);
510
511
        /* --------------------------------------------------------------------
512
         */
513
        /*      Get the raster band. */
514
        /* --------------------------------------------------------------------
515
         */
516
0
        const int nSrcBand = atoi(CPLGetXMLValue(psNode, "SourceBand", "1"));
517
518
0
        m_aoOverviewInfos.resize(m_aoOverviewInfos.size() + 1);
519
0
        m_aoOverviewInfos.back().osFilename = pszSrcDSName;
520
0
        m_aoOverviewInfos.back().nBand = nSrcBand;
521
522
0
        CPLFree(pszSrcDSName);
523
0
    }
524
525
    /* ==================================================================== */
526
    /*      Mask band (specific to that raster band)                        */
527
    /* ==================================================================== */
528
25.1k
    const CPLXMLNode *psMaskBandNode = CPLGetXMLNode(psTree, "MaskBand");
529
25.1k
    if (psMaskBandNode)
530
0
        psNode = psMaskBandNode->psChild;
531
25.1k
    else
532
25.1k
        psNode = nullptr;
533
25.1k
    for (; psNode != nullptr; psNode = psNode->psNext)
534
0
    {
535
0
        if (psNode->eType != CXT_Element ||
536
0
            !EQUAL(psNode->pszValue, "VRTRasterBand"))
537
0
            continue;
538
539
0
        if (cpl::down_cast<VRTDataset *>(poDS)->m_poMaskBand != nullptr)
540
0
        {
541
0
            CPLError(CE_Warning, CPLE_AppDefined,
542
0
                     "Illegal mask band at raster band level when a dataset "
543
0
                     "mask band already exists.");
544
0
            return CE_Failure;
545
0
        }
546
547
0
        const char *pszSubclass =
548
0
            CPLGetXMLValue(psNode, "subclass", "VRTSourcedRasterBand");
549
0
        std::unique_ptr<VRTRasterBand> poBand;
550
551
0
        if (EQUAL(pszSubclass, "VRTSourcedRasterBand"))
552
0
            poBand = std::make_unique<VRTSourcedRasterBand>(GetDataset(), 0);
553
0
        else if (EQUAL(pszSubclass, "VRTDerivedRasterBand"))
554
0
            poBand = std::make_unique<VRTDerivedRasterBand>(GetDataset(), 0);
555
0
        else if (EQUAL(pszSubclass, "VRTRawRasterBand"))
556
0
        {
557
0
#ifdef GDAL_VRT_ENABLE_RAWRASTERBAND
558
0
            if (!VRTDataset::IsRawRasterBandEnabled())
559
0
            {
560
0
                return CE_Failure;
561
0
            }
562
0
            poBand = std::make_unique<VRTRawRasterBand>(GetDataset(), 0);
563
#else
564
            CPLError(CE_Failure, CPLE_NotSupported,
565
                     "VRTRasterBand::XMLInit(): cannot instantiate "
566
                     "VRTRawRasterBand, because disabled in this GDAL build");
567
            return CE_Failure;
568
#endif
569
0
        }
570
0
        else if (EQUAL(pszSubclass, "VRTWarpedRasterBand"))
571
0
            poBand = std::make_unique<VRTWarpedRasterBand>(GetDataset(), 0);
572
0
        else
573
0
        {
574
0
            CPLError(CE_Failure, CPLE_AppDefined,
575
0
                     "VRTRasterBand of unrecognized subclass '%s'.",
576
0
                     pszSubclass);
577
0
            return CE_Failure;
578
0
        }
579
580
0
        if (poBand->XMLInit(psNode, pszVRTPath, oMapSharedSources) == CE_None)
581
0
        {
582
0
            SetMaskBand(std::move(poBand));
583
0
        }
584
0
        else
585
0
        {
586
0
            return CE_Failure;
587
0
        }
588
589
0
        break;
590
0
    }
591
592
25.1k
    return CE_None;
593
25.1k
}
594
595
/************************************************************************/
596
/*                        VRTSerializeNoData()                          */
597
/************************************************************************/
598
599
CPLString VRTSerializeNoData(double dfVal, GDALDataType eDataType,
600
                             int nPrecision)
601
684
{
602
684
    if (std::isnan(dfVal))
603
5
    {
604
5
        return "nan";
605
5
    }
606
679
    else if (eDataType == GDT_Float16 && dfVal == -6.55e4)
607
0
    {
608
        // To avoid rounding out of the range of GFloat16
609
0
        return "-6.55e4";
610
0
    }
611
679
    else if (eDataType == GDT_Float16 && dfVal == 6.55e4)
612
0
    {
613
        // To avoid rounding out of the range of GFloat16
614
0
        return "6.55e4";
615
0
    }
616
679
    else if (eDataType == GDT_Float32 &&
617
0
             dfVal == -static_cast<double>(std::numeric_limits<float>::max()))
618
0
    {
619
        // To avoid rounding out of the range of float
620
0
        return "-3.4028234663852886e+38";
621
0
    }
622
679
    else if (eDataType == GDT_Float32 &&
623
0
             dfVal == static_cast<double>(std::numeric_limits<float>::max()))
624
0
    {
625
        // To avoid rounding out of the range of float
626
0
        return "3.4028234663852886e+38";
627
0
    }
628
679
    else
629
679
    {
630
679
        char szFormat[16];
631
679
        snprintf(szFormat, sizeof(szFormat), "%%.%dg", nPrecision);
632
679
        return CPLSPrintf(szFormat, dfVal);
633
679
    }
634
684
}
635
636
/************************************************************************/
637
/*                           SerializeToXML()                           */
638
/************************************************************************/
639
640
CPLXMLNode *VRTRasterBand::SerializeToXML(const char *pszVRTPath,
641
                                          bool &bHasWarnedAboutRAMUsage,
642
                                          size_t &nAccRAMUsage)
643
644
61.0k
{
645
61.0k
    CPLXMLNode *psTree =
646
61.0k
        CPLCreateXMLNode(nullptr, CXT_Element, "VRTRasterBand");
647
648
    /* -------------------------------------------------------------------- */
649
    /*      Various kinds of metadata.                                      */
650
    /* -------------------------------------------------------------------- */
651
61.0k
    CPLSetXMLValue(psTree, "#dataType",
652
61.0k
                   GDALGetDataTypeName(GetRasterDataType()));
653
654
61.0k
    if (nBand > 0)
655
60.7k
        CPLSetXMLValue(psTree, "#band", CPLSPrintf("%d", GetBand()));
656
657
    // Do not serialize block size of VRTWarpedRasterBand since it is already
658
    // serialized at the dataset level.
659
61.0k
    if (dynamic_cast<VRTWarpedRasterBand *>(this) == nullptr)
660
61.0k
    {
661
61.0k
        if (!VRTDataset::IsDefaultBlockSize(nBlockXSize, nRasterXSize))
662
23.1k
        {
663
23.1k
            CPLSetXMLValue(psTree, "#blockXSize",
664
23.1k
                           CPLSPrintf("%d", nBlockXSize));
665
23.1k
        }
666
667
61.0k
        if (!VRTDataset::IsDefaultBlockSize(nBlockYSize, nRasterYSize))
668
19.5k
        {
669
19.5k
            CPLSetXMLValue(psTree, "#blockYSize",
670
19.5k
                           CPLSPrintf("%d", nBlockYSize));
671
19.5k
        }
672
61.0k
    }
673
674
61.0k
    CPLXMLNode *psMD = oMDMD.Serialize();
675
61.0k
    if (psMD != nullptr)
676
35.2k
    {
677
35.2k
        CPLAddXMLChild(psTree, psMD);
678
35.2k
    }
679
680
61.0k
    if (strlen(GetDescription()) > 0)
681
0
        CPLSetXMLValue(psTree, "Description", GetDescription());
682
683
61.0k
    if (m_bNoDataValueSet)
684
637
    {
685
637
        CPLSetXMLValue(
686
637
            psTree, "NoDataValue",
687
637
            VRTSerializeNoData(m_dfNoDataValue, eDataType, 18).c_str());
688
637
    }
689
60.4k
    else if (m_bNoDataSetAsInt64)
690
0
    {
691
0
        CPLSetXMLValue(psTree, "NoDataValue",
692
0
                       CPLSPrintf(CPL_FRMT_GIB,
693
0
                                  static_cast<GIntBig>(m_nNoDataValueInt64)));
694
0
    }
695
60.4k
    else if (m_bNoDataSetAsUInt64)
696
2
    {
697
2
        CPLSetXMLValue(psTree, "NoDataValue",
698
2
                       CPLSPrintf(CPL_FRMT_GUIB,
699
2
                                  static_cast<GUIntBig>(m_nNoDataValueUInt64)));
700
2
    }
701
702
61.0k
    if (m_bHideNoDataValue)
703
0
        CPLSetXMLValue(psTree, "HideNoDataValue",
704
0
                       CPLSPrintf("%d", static_cast<int>(m_bHideNoDataValue)));
705
706
61.0k
    if (!m_osUnitType.empty())
707
14.1k
        CPLSetXMLValue(psTree, "UnitType", m_osUnitType.c_str());
708
709
61.0k
    if (m_dfOffset != 0.0)
710
25
        CPLSetXMLValue(psTree, "Offset", CPLSPrintf("%.16g", m_dfOffset));
711
712
61.0k
    if (m_dfScale != 1.0)
713
26
        CPLSetXMLValue(psTree, "Scale", CPLSPrintf("%.16g", m_dfScale));
714
715
61.0k
    if (m_eColorInterp != GCI_Undefined)
716
60.6k
        CPLSetXMLValue(psTree, "ColorInterp",
717
60.6k
                       GDALGetColorInterpretationName(m_eColorInterp));
718
719
    /* -------------------------------------------------------------------- */
720
    /*      Category names.                                                 */
721
    /* -------------------------------------------------------------------- */
722
61.0k
    if (!m_aosCategoryNames.empty())
723
0
    {
724
0
        CPLXMLNode *psCT_XML =
725
0
            CPLCreateXMLNode(psTree, CXT_Element, "CategoryNames");
726
0
        CPLXMLNode *psLastChild = nullptr;
727
728
0
        for (const char *pszName : m_aosCategoryNames)
729
0
        {
730
0
            CPLXMLNode *psNode =
731
0
                CPLCreateXMLElementAndValue(nullptr, "Category", pszName);
732
0
            if (psLastChild == nullptr)
733
0
                psCT_XML->psChild = psNode;
734
0
            else
735
0
                psLastChild->psNext = psNode;
736
0
            psLastChild = psNode;
737
0
        }
738
0
    }
739
740
    /* -------------------------------------------------------------------- */
741
    /*      Histograms.                                                     */
742
    /* -------------------------------------------------------------------- */
743
61.0k
    if (m_psSavedHistograms != nullptr)
744
0
        CPLAddXMLChild(psTree, CPLCloneXMLTree(m_psSavedHistograms.get()));
745
746
    /* -------------------------------------------------------------------- */
747
    /*      Color Table.                                                    */
748
    /* -------------------------------------------------------------------- */
749
61.0k
    if (m_poColorTable != nullptr)
750
33.7k
    {
751
33.7k
        CPLXMLNode *psCT_XML =
752
33.7k
            CPLCreateXMLNode(psTree, CXT_Element, "ColorTable");
753
33.7k
        CPLXMLNode *psLastChild = nullptr;
754
755
381k
        for (int iEntry = 0; iEntry < m_poColorTable->GetColorEntryCount();
756
347k
             iEntry++)
757
347k
        {
758
347k
            CPLXMLNode *psEntry_XML =
759
347k
                CPLCreateXMLNode(nullptr, CXT_Element, "Entry");
760
347k
            if (psLastChild == nullptr)
761
33.7k
                psCT_XML->psChild = psEntry_XML;
762
314k
            else
763
314k
                psLastChild->psNext = psEntry_XML;
764
347k
            psLastChild = psEntry_XML;
765
766
347k
            GDALColorEntry sEntry;
767
347k
            m_poColorTable->GetColorEntryAsRGB(iEntry, &sEntry);
768
769
347k
            CPLSetXMLValue(psEntry_XML, "#c1", CPLSPrintf("%d", sEntry.c1));
770
347k
            CPLSetXMLValue(psEntry_XML, "#c2", CPLSPrintf("%d", sEntry.c2));
771
347k
            CPLSetXMLValue(psEntry_XML, "#c3", CPLSPrintf("%d", sEntry.c3));
772
347k
            CPLSetXMLValue(psEntry_XML, "#c4", CPLSPrintf("%d", sEntry.c4));
773
347k
        }
774
33.7k
    }
775
776
    /* -------------------------------------------------------------------- */
777
    /*      Raster Attribute Table                                          */
778
    /* -------------------------------------------------------------------- */
779
61.0k
    if (m_poRAT != nullptr)
780
0
    {
781
0
        CPLXMLNode *psSerializedRAT = m_poRAT->Serialize();
782
0
        if (psSerializedRAT != nullptr)
783
0
            CPLAddXMLChild(psTree, psSerializedRAT);
784
0
    }
785
786
    /* ==================================================================== */
787
    /*      Overviews                                                       */
788
    /* ==================================================================== */
789
790
61.0k
    for (const auto &ovrInfo : m_aoOverviewInfos)
791
0
    {
792
0
        CPLXMLNode *psOVR_XML =
793
0
            CPLCreateXMLNode(psTree, CXT_Element, "Overview");
794
795
0
        int bRelativeToVRT = FALSE;
796
0
        const char *pszRelativePath = nullptr;
797
0
        VSIStatBufL sStat;
798
799
0
        if (VSIStatExL(ovrInfo.osFilename, &sStat, VSI_STAT_EXISTS_FLAG) != 0)
800
0
        {
801
0
            pszRelativePath = ovrInfo.osFilename;
802
0
            bRelativeToVRT = FALSE;
803
0
        }
804
0
        else
805
0
        {
806
0
            pszRelativePath = CPLExtractRelativePath(
807
0
                pszVRTPath, ovrInfo.osFilename, &bRelativeToVRT);
808
0
        }
809
810
0
        CPLSetXMLValue(psOVR_XML, "SourceFilename", pszRelativePath);
811
812
0
        CPLCreateXMLNode(
813
0
            CPLCreateXMLNode(CPLGetXMLNode(psOVR_XML, "SourceFilename"),
814
0
                             CXT_Attribute, "relativeToVRT"),
815
0
            CXT_Text, bRelativeToVRT ? "1" : "0");
816
817
0
        CPLSetXMLValue(psOVR_XML, "SourceBand",
818
0
                       CPLSPrintf("%d", ovrInfo.nBand));
819
0
    }
820
821
    /* ==================================================================== */
822
    /*      Mask band (specific to that raster band)                        */
823
    /* ==================================================================== */
824
825
61.0k
    nAccRAMUsage += CPLXMLNodeGetRAMUsageEstimate(psTree);
826
827
61.0k
    if (m_poMaskBand != nullptr)
828
0
    {
829
0
        CPLXMLNode *psBandTree = m_poMaskBand->SerializeToXML(
830
0
            pszVRTPath, bHasWarnedAboutRAMUsage, nAccRAMUsage);
831
832
0
        if (psBandTree != nullptr)
833
0
        {
834
0
            CPLXMLNode *psMaskBandElement =
835
0
                CPLCreateXMLNode(psTree, CXT_Element, "MaskBand");
836
0
            CPLAddXMLChild(psMaskBandElement, psBandTree);
837
0
        }
838
0
    }
839
840
61.0k
    return psTree;
841
61.0k
}
842
843
/************************************************************************/
844
/*                         ResetNoDataValues()                          */
845
/************************************************************************/
846
847
void VRTRasterBand::ResetNoDataValues()
848
46.4k
{
849
46.4k
    m_bNoDataValueSet = false;
850
46.4k
    m_dfNoDataValue = VRT_DEFAULT_NODATA_VALUE;
851
852
46.4k
    m_bNoDataSetAsInt64 = false;
853
46.4k
    m_nNoDataValueInt64 = GDAL_PAM_DEFAULT_NODATA_VALUE_INT64;
854
855
46.4k
    m_bNoDataSetAsUInt64 = false;
856
46.4k
    m_nNoDataValueUInt64 = GDAL_PAM_DEFAULT_NODATA_VALUE_UINT64;
857
46.4k
}
858
859
/************************************************************************/
860
/*                           SetNoDataValue()                           */
861
/************************************************************************/
862
863
CPLErr VRTRasterBand::SetNoDataValue(double dfNewValue)
864
865
46.3k
{
866
46.3k
    if (eDataType == GDT_Float32)
867
3.30k
    {
868
3.30k
        dfNewValue = GDALAdjustNoDataCloseToFloatMax(dfNewValue);
869
3.30k
    }
870
871
46.3k
    ResetNoDataValues();
872
873
46.3k
    m_bNoDataValueSet = true;
874
46.3k
    m_dfNoDataValue = dfNewValue;
875
876
46.3k
    cpl::down_cast<VRTDataset *>(poDS)->SetNeedsFlush();
877
878
46.3k
    return CE_None;
879
46.3k
}
880
881
/************************************************************************/
882
/*                     IsNoDataValueInDataTypeRange()                   */
883
/************************************************************************/
884
885
bool VRTRasterBand::IsNoDataValueInDataTypeRange() const
886
0
{
887
0
    if (m_bNoDataSetAsInt64)
888
0
        return eDataType == GDT_Int64;
889
0
    if (m_bNoDataSetAsUInt64)
890
0
        return eDataType == GDT_UInt64;
891
0
    if (!m_bNoDataValueSet)
892
0
        return true;
893
0
    if (!std::isfinite(m_dfNoDataValue))
894
0
        return eDataType == GDT_Float16 || eDataType == GDT_Float32 ||
895
0
               eDataType == GDT_Float64;
896
0
    GByte abyTempBuffer[2 * sizeof(double)];
897
0
    CPLAssert(GDALGetDataTypeSizeBytes(eDataType) <=
898
0
              static_cast<int>(sizeof(abyTempBuffer)));
899
0
    GDALCopyWords(&m_dfNoDataValue, GDT_Float64, 0, &abyTempBuffer[0],
900
0
                  eDataType, 0, 1);
901
0
    double dfNoDataValueAfter = 0;
902
0
    GDALCopyWords(&abyTempBuffer[0], eDataType, 0, &dfNoDataValueAfter,
903
0
                  GDT_Float64, 0, 1);
904
0
    return std::fabs(dfNoDataValueAfter - m_dfNoDataValue) < 1.0;
905
0
}
906
907
/************************************************************************/
908
/*                       SetNoDataValueAsInt64()                        */
909
/************************************************************************/
910
911
CPLErr VRTRasterBand::SetNoDataValueAsInt64(int64_t nNewValue)
912
913
0
{
914
0
    ResetNoDataValues();
915
916
0
    m_bNoDataSetAsInt64 = true;
917
0
    m_nNoDataValueInt64 = nNewValue;
918
919
0
    cpl::down_cast<VRTDataset *>(poDS)->SetNeedsFlush();
920
921
0
    return CE_None;
922
0
}
923
924
/************************************************************************/
925
/*                      SetNoDataValueAsUInt64()                        */
926
/************************************************************************/
927
928
CPLErr VRTRasterBand::SetNoDataValueAsUInt64(uint64_t nNewValue)
929
930
128
{
931
128
    ResetNoDataValues();
932
933
128
    m_bNoDataSetAsUInt64 = true;
934
128
    m_nNoDataValueUInt64 = nNewValue;
935
936
128
    cpl::down_cast<VRTDataset *>(poDS)->SetNeedsFlush();
937
938
128
    return CE_None;
939
128
}
940
941
/************************************************************************/
942
/*                         DeleteNoDataValue()                          */
943
/************************************************************************/
944
945
CPLErr VRTRasterBand::DeleteNoDataValue()
946
0
{
947
0
    ResetNoDataValues();
948
949
0
    cpl::down_cast<VRTDataset *>(poDS)->SetNeedsFlush();
950
951
0
    return CE_None;
952
0
}
953
954
/************************************************************************/
955
/*                         UnsetNoDataValue()                           */
956
/************************************************************************/
957
958
CPLErr VRTRasterBand::UnsetNoDataValue()
959
0
{
960
0
    return DeleteNoDataValue();
961
0
}
962
963
/************************************************************************/
964
/*                           GetNoDataValue()                           */
965
/************************************************************************/
966
967
double VRTRasterBand::GetNoDataValue(int *pbSuccess)
968
969
291k
{
970
291k
    if (m_bNoDataSetAsInt64)
971
0
    {
972
0
        if (pbSuccess)
973
0
            *pbSuccess = !m_bHideNoDataValue;
974
0
        return GDALGetNoDataValueCastToDouble(m_nNoDataValueInt64);
975
0
    }
976
977
291k
    if (m_bNoDataSetAsUInt64)
978
0
    {
979
0
        if (pbSuccess)
980
0
            *pbSuccess = !m_bHideNoDataValue;
981
0
        return GDALGetNoDataValueCastToDouble(m_nNoDataValueUInt64);
982
0
    }
983
984
291k
    if (pbSuccess)
985
267k
        *pbSuccess = m_bNoDataValueSet && !m_bHideNoDataValue;
986
987
291k
    return m_dfNoDataValue;
988
291k
}
989
990
/************************************************************************/
991
/*                        GetNoDataValueAsInt64()                       */
992
/************************************************************************/
993
994
int64_t VRTRasterBand::GetNoDataValueAsInt64(int *pbSuccess)
995
996
877
{
997
877
    if (eDataType == GDT_UInt64)
998
0
    {
999
0
        CPLError(CE_Failure, CPLE_AppDefined,
1000
0
                 "GetNoDataValueAsUInt64() should be called instead");
1001
0
        if (pbSuccess)
1002
0
            *pbSuccess = FALSE;
1003
0
        return GDAL_PAM_DEFAULT_NODATA_VALUE_INT64;
1004
0
    }
1005
877
    if (eDataType != GDT_Int64)
1006
0
    {
1007
0
        CPLError(CE_Failure, CPLE_AppDefined,
1008
0
                 "GetNoDataValue() should be called instead");
1009
0
        if (pbSuccess)
1010
0
            *pbSuccess = FALSE;
1011
0
        return GDAL_PAM_DEFAULT_NODATA_VALUE_INT64;
1012
0
    }
1013
1014
877
    if (pbSuccess)
1015
877
        *pbSuccess = m_bNoDataSetAsInt64 && !m_bHideNoDataValue;
1016
1017
877
    return m_nNoDataValueInt64;
1018
877
}
1019
1020
/************************************************************************/
1021
/*                       GetNoDataValueAsUInt64()                       */
1022
/************************************************************************/
1023
1024
uint64_t VRTRasterBand::GetNoDataValueAsUInt64(int *pbSuccess)
1025
1026
640
{
1027
640
    if (eDataType == GDT_Int64)
1028
0
    {
1029
0
        CPLError(CE_Failure, CPLE_AppDefined,
1030
0
                 "GetNoDataValueAsInt64() should be called instead");
1031
0
        if (pbSuccess)
1032
0
            *pbSuccess = FALSE;
1033
0
        return GDAL_PAM_DEFAULT_NODATA_VALUE_UINT64;
1034
0
    }
1035
640
    if (eDataType != GDT_UInt64)
1036
0
    {
1037
0
        CPLError(CE_Failure, CPLE_AppDefined,
1038
0
                 "GetNoDataValue() should be called instead");
1039
0
        if (pbSuccess)
1040
0
            *pbSuccess = FALSE;
1041
0
        return GDAL_PAM_DEFAULT_NODATA_VALUE_UINT64;
1042
0
    }
1043
1044
640
    if (pbSuccess)
1045
640
        *pbSuccess = m_bNoDataSetAsUInt64 && !m_bHideNoDataValue;
1046
1047
640
    return m_nNoDataValueUInt64;
1048
640
}
1049
1050
/************************************************************************/
1051
/*                           SetColorTable()                            */
1052
/************************************************************************/
1053
1054
CPLErr VRTRasterBand::SetColorTable(GDALColorTable *poTableIn)
1055
1056
167k
{
1057
167k
    if (poTableIn == nullptr)
1058
122k
        m_poColorTable.reset();
1059
45.4k
    else
1060
45.4k
    {
1061
45.4k
        m_poColorTable.reset(poTableIn->Clone());
1062
45.4k
        m_eColorInterp = GCI_PaletteIndex;
1063
45.4k
    }
1064
1065
167k
    cpl::down_cast<VRTDataset *>(poDS)->SetNeedsFlush();
1066
1067
167k
    return CE_None;
1068
167k
}
1069
1070
/************************************************************************/
1071
/*                           GetColorTable()                            */
1072
/************************************************************************/
1073
1074
GDALColorTable *VRTRasterBand::GetColorTable()
1075
1076
133k
{
1077
133k
    return m_poColorTable.get();
1078
133k
}
1079
1080
/************************************************************************/
1081
/*                       SetColorInterpretation()                       */
1082
/************************************************************************/
1083
1084
CPLErr VRTRasterBand::SetColorInterpretation(GDALColorInterp eInterpIn)
1085
1086
185k
{
1087
185k
    cpl::down_cast<VRTDataset *>(poDS)->SetNeedsFlush();
1088
1089
185k
    m_eColorInterp = eInterpIn;
1090
1091
185k
    return CE_None;
1092
185k
}
1093
1094
/************************************************************************/
1095
/*                           GetDefaultRAT()                            */
1096
/************************************************************************/
1097
1098
GDALRasterAttributeTable *VRTRasterBand::GetDefaultRAT()
1099
181k
{
1100
181k
    return m_poRAT.get();
1101
181k
}
1102
1103
/************************************************************************/
1104
/*                            SetDefaultRAT()                           */
1105
/************************************************************************/
1106
1107
CPLErr VRTRasterBand::SetDefaultRAT(const GDALRasterAttributeTable *poRAT)
1108
1.54k
{
1109
1.54k
    if (poRAT == nullptr)
1110
959
        m_poRAT.reset();
1111
582
    else
1112
582
        m_poRAT.reset(poRAT->Clone());
1113
1114
1.54k
    cpl::down_cast<VRTDataset *>(poDS)->SetNeedsFlush();
1115
1116
1.54k
    return CE_None;
1117
1.54k
}
1118
1119
/************************************************************************/
1120
/*                       GetColorInterpretation()                       */
1121
/************************************************************************/
1122
1123
GDALColorInterp VRTRasterBand::GetColorInterpretation()
1124
1125
362k
{
1126
362k
    return m_eColorInterp;
1127
362k
}
1128
1129
/************************************************************************/
1130
/*                            GetHistogram()                            */
1131
/************************************************************************/
1132
1133
CPLErr VRTRasterBand::GetHistogram(double dfMin, double dfMax, int nBuckets,
1134
                                   GUIntBig *panHistogram,
1135
                                   int bIncludeOutOfRange, int bApproxOK,
1136
                                   GDALProgressFunc pfnProgress,
1137
                                   void *pProgressData)
1138
1139
0
{
1140
    /* -------------------------------------------------------------------- */
1141
    /*      Check if we have a matching histogram.                          */
1142
    /* -------------------------------------------------------------------- */
1143
0
    CPLXMLNode *psHistItem =
1144
0
        PamFindMatchingHistogram(m_psSavedHistograms.get(), dfMin, dfMax,
1145
0
                                 nBuckets, bIncludeOutOfRange, bApproxOK);
1146
0
    if (psHistItem != nullptr)
1147
0
    {
1148
0
        GUIntBig *panTempHist = nullptr;
1149
1150
0
        if (PamParseHistogram(psHistItem, &dfMin, &dfMax, &nBuckets,
1151
0
                              &panTempHist, &bIncludeOutOfRange, &bApproxOK))
1152
0
        {
1153
0
            memcpy(panHistogram, panTempHist, sizeof(GUIntBig) * nBuckets);
1154
0
            CPLFree(panTempHist);
1155
0
            return CE_None;
1156
0
        }
1157
0
    }
1158
1159
    /* -------------------------------------------------------------------- */
1160
    /*      We don't have an existing histogram matching the request, so    */
1161
    /*      generate one manually.                                          */
1162
    /* -------------------------------------------------------------------- */
1163
0
    CPLErr eErr = GDALRasterBand::GetHistogram(
1164
0
        dfMin, dfMax, nBuckets, panHistogram, bIncludeOutOfRange, bApproxOK,
1165
0
        pfnProgress, pProgressData);
1166
1167
    /* -------------------------------------------------------------------- */
1168
    /*      Save an XML description of this histogram.                      */
1169
    /* -------------------------------------------------------------------- */
1170
0
    if (eErr == CE_None)
1171
0
    {
1172
0
        CPLXMLNode *psXMLHist =
1173
0
            PamHistogramToXMLTree(dfMin, dfMax, nBuckets, panHistogram,
1174
0
                                  bIncludeOutOfRange, bApproxOK);
1175
0
        if (psXMLHist != nullptr)
1176
0
        {
1177
0
            cpl::down_cast<VRTDataset *>(poDS)->SetNeedsFlush();
1178
1179
0
            if (m_psSavedHistograms == nullptr)
1180
0
                m_psSavedHistograms.reset(
1181
0
                    CPLCreateXMLNode(nullptr, CXT_Element, "Histograms"));
1182
1183
0
            CPLAddXMLChild(m_psSavedHistograms.get(), psXMLHist);
1184
0
        }
1185
0
    }
1186
1187
0
    return eErr;
1188
0
}
1189
1190
/************************************************************************/
1191
/*                        SetDefaultHistogram()                         */
1192
/************************************************************************/
1193
1194
CPLErr VRTRasterBand::SetDefaultHistogram(double dfMin, double dfMax,
1195
                                          int nBuckets, GUIntBig *panHistogram)
1196
1197
8.73k
{
1198
    /* -------------------------------------------------------------------- */
1199
    /*      Do we have a matching histogram we should replace?              */
1200
    /* -------------------------------------------------------------------- */
1201
8.73k
    CPLXMLNode *psNode = PamFindMatchingHistogram(
1202
8.73k
        m_psSavedHistograms.get(), dfMin, dfMax, nBuckets, TRUE, TRUE);
1203
8.73k
    if (psNode != nullptr)
1204
0
    {
1205
        /* blow this one away */
1206
0
        CPLRemoveXMLChild(m_psSavedHistograms.get(), psNode);
1207
0
        CPLDestroyXMLNode(psNode);
1208
0
    }
1209
1210
    /* -------------------------------------------------------------------- */
1211
    /*      Translate into a histogram XML tree.                            */
1212
    /* -------------------------------------------------------------------- */
1213
8.73k
    CPLXMLNode *psHistItem = PamHistogramToXMLTree(dfMin, dfMax, nBuckets,
1214
8.73k
                                                   panHistogram, TRUE, FALSE);
1215
8.73k
    if (psHistItem == nullptr)
1216
0
        return CE_Failure;
1217
1218
    /* -------------------------------------------------------------------- */
1219
    /*      Insert our new default histogram at the front of the            */
1220
    /*      histogram list so that it will be the default histogram.        */
1221
    /* -------------------------------------------------------------------- */
1222
8.73k
    cpl::down_cast<VRTDataset *>(poDS)->SetNeedsFlush();
1223
1224
8.73k
    if (m_psSavedHistograms == nullptr)
1225
8.73k
        m_psSavedHistograms.reset(
1226
8.73k
            CPLCreateXMLNode(nullptr, CXT_Element, "Histograms"));
1227
1228
8.73k
    psHistItem->psNext = m_psSavedHistograms->psChild;
1229
8.73k
    m_psSavedHistograms->psChild = psHistItem;
1230
1231
8.73k
    return CE_None;
1232
8.73k
}
1233
1234
/************************************************************************/
1235
/*                        GetDefaultHistogram()                         */
1236
/************************************************************************/
1237
1238
CPLErr VRTRasterBand::GetDefaultHistogram(double *pdfMin, double *pdfMax,
1239
                                          int *pnBuckets,
1240
                                          GUIntBig **ppanHistogram, int bForce,
1241
                                          GDALProgressFunc pfnProgress,
1242
                                          void *pProgressData)
1243
1244
15.0k
{
1245
15.0k
    if (m_psSavedHistograms != nullptr)
1246
0
    {
1247
0
        for (CPLXMLNode *psXMLHist = m_psSavedHistograms->psChild;
1248
0
             psXMLHist != nullptr; psXMLHist = psXMLHist->psNext)
1249
0
        {
1250
0
            if (psXMLHist->eType != CXT_Element ||
1251
0
                !EQUAL(psXMLHist->pszValue, "HistItem"))
1252
0
                continue;
1253
1254
0
            int bIncludeOutOfRange;
1255
0
            int bApprox;
1256
0
            if (PamParseHistogram(psXMLHist, pdfMin, pdfMax, pnBuckets,
1257
0
                                  ppanHistogram, &bIncludeOutOfRange, &bApprox))
1258
0
                return CE_None;
1259
1260
0
            return CE_Failure;
1261
0
        }
1262
0
    }
1263
1264
15.0k
    return GDALRasterBand::GetDefaultHistogram(pdfMin, pdfMax, pnBuckets,
1265
15.0k
                                               ppanHistogram, bForce,
1266
15.0k
                                               pfnProgress, pProgressData);
1267
15.0k
}
1268
1269
/************************************************************************/
1270
/*                             GetFileList()                            */
1271
/************************************************************************/
1272
1273
void VRTRasterBand::GetFileList(char ***ppapszFileList, int *pnSize,
1274
                                int *pnMaxSize, CPLHashSet *hSetFiles)
1275
20.0k
{
1276
20.0k
    for (unsigned int iOver = 0; iOver < m_aoOverviewInfos.size(); iOver++)
1277
0
    {
1278
0
        const CPLString &osFilename = m_aoOverviewInfos[iOver].osFilename;
1279
1280
        /* --------------------------------------------------------------------
1281
         */
1282
        /*      Is the filename even a real filesystem object? */
1283
        /* --------------------------------------------------------------------
1284
         */
1285
0
        VSIStatBufL sStat;
1286
0
        if (VSIStatL(osFilename, &sStat) != 0)
1287
0
            return;
1288
1289
        /* --------------------------------------------------------------------
1290
         */
1291
        /*      Is it already in the list ? */
1292
        /* --------------------------------------------------------------------
1293
         */
1294
0
        if (CPLHashSetLookup(hSetFiles, osFilename) != nullptr)
1295
0
            return;
1296
1297
        /* --------------------------------------------------------------------
1298
         */
1299
        /*      Grow array if necessary */
1300
        /* --------------------------------------------------------------------
1301
         */
1302
0
        if (*pnSize + 1 >= *pnMaxSize)
1303
0
        {
1304
0
            *pnMaxSize = 2 + 2 * (*pnMaxSize);
1305
0
            *ppapszFileList = static_cast<char **>(
1306
0
                CPLRealloc(*ppapszFileList, sizeof(char *) * (*pnMaxSize)));
1307
0
        }
1308
1309
        /* --------------------------------------------------------------------
1310
         */
1311
        /*      Add the string to the list */
1312
        /* --------------------------------------------------------------------
1313
         */
1314
0
        (*ppapszFileList)[*pnSize] = CPLStrdup(osFilename);
1315
0
        (*ppapszFileList)[(*pnSize + 1)] = nullptr;
1316
0
        CPLHashSetInsert(hSetFiles, (*ppapszFileList)[*pnSize]);
1317
1318
0
        (*pnSize)++;
1319
0
    }
1320
20.0k
}
1321
1322
/************************************************************************/
1323
/*                          GetOverviewCount()                          */
1324
/************************************************************************/
1325
1326
int VRTRasterBand::GetOverviewCount()
1327
1328
59.6k
{
1329
59.6k
    VRTDataset *poVRTDS = cpl::down_cast<VRTDataset *>(poDS);
1330
59.6k
    if (!poVRTDS->AreOverviewsEnabled())
1331
0
        return 0;
1332
1333
    // First: overviews declared in <Overview> element
1334
59.6k
    if (!m_aoOverviewInfos.empty())
1335
0
        return static_cast<int>(m_aoOverviewInfos.size());
1336
1337
    // If not found, external .ovr overviews
1338
59.6k
    const int nOverviewCount = GDALRasterBand::GetOverviewCount();
1339
59.6k
    if (nOverviewCount)
1340
698
        return nOverviewCount;
1341
1342
58.9k
    if (poVRTDS->m_apoOverviews.empty())
1343
58.8k
    {
1344
        // If not found, implicit virtual overviews
1345
1346
58.8k
        const std::string osFctId("VRTRasterBand::GetOverviewCount");
1347
58.8k
        GDALAntiRecursionGuard oGuard(osFctId);
1348
58.8k
        if (oGuard.GetCallDepth() >= 32)
1349
0
        {
1350
0
            CPLError(CE_Failure, CPLE_AppDefined, "Recursion detected");
1351
0
            return 0;
1352
0
        }
1353
1354
58.8k
        GDALAntiRecursionGuard oGuard2(oGuard, poVRTDS->GetDescription());
1355
58.8k
        if (oGuard2.GetCallDepth() >= 2)
1356
485
        {
1357
485
            CPLError(CE_Failure, CPLE_AppDefined, "Recursion detected");
1358
485
            return 0;
1359
485
        }
1360
1361
58.3k
        poVRTDS->BuildVirtualOverviews();
1362
58.3k
    }
1363
58.4k
    if (!poVRTDS->m_apoOverviews.empty() && poVRTDS->m_apoOverviews[0])
1364
60
        return static_cast<int>(poVRTDS->m_apoOverviews.size());
1365
1366
58.3k
    return 0;
1367
58.4k
}
1368
1369
/************************************************************************/
1370
/*                            GetOverview()                             */
1371
/************************************************************************/
1372
1373
GDALRasterBand *VRTRasterBand::GetOverview(int iOverview)
1374
1375
410
{
1376
    // First: overviews declared in <Overview> element
1377
410
    if (!m_aoOverviewInfos.empty())
1378
0
    {
1379
0
        if (iOverview < 0 ||
1380
0
            iOverview >= static_cast<int>(m_aoOverviewInfos.size()))
1381
0
            return nullptr;
1382
1383
0
        if (m_aoOverviewInfos[iOverview].poBand == nullptr &&
1384
0
            !m_aoOverviewInfos[iOverview].bTriedToOpen)
1385
0
        {
1386
0
            m_aoOverviewInfos[iOverview].bTriedToOpen = TRUE;
1387
0
            CPLConfigOptionSetter oSetter("CPL_ALLOW_VSISTDIN", "NO", true);
1388
0
            GDALDataset *poSrcDS = GDALDataset::FromHandle(GDALOpenShared(
1389
0
                m_aoOverviewInfos[iOverview].osFilename, GA_ReadOnly));
1390
1391
0
            if (poSrcDS == nullptr)
1392
0
                return nullptr;
1393
0
            if (poSrcDS == poDS)
1394
0
            {
1395
0
                CPLError(CE_Failure, CPLE_AppDefined,
1396
0
                         "Recursive opening attempt");
1397
0
                GDALClose(GDALDataset::ToHandle(poSrcDS));
1398
0
                return nullptr;
1399
0
            }
1400
1401
0
            m_aoOverviewInfos[iOverview].poBand =
1402
0
                poSrcDS->GetRasterBand(m_aoOverviewInfos[iOverview].nBand);
1403
1404
0
            if (m_aoOverviewInfos[iOverview].poBand == nullptr)
1405
0
            {
1406
0
                GDALClose(GDALDataset::ToHandle(poSrcDS));
1407
0
            }
1408
0
        }
1409
1410
0
        return m_aoOverviewInfos[iOverview].poBand;
1411
0
    }
1412
1413
    // If not found, external .ovr overviews
1414
410
    GDALRasterBand *poRet = GDALRasterBand::GetOverview(iOverview);
1415
410
    if (poRet)
1416
390
        return poRet;
1417
1418
    // If not found, implicit virtual overviews
1419
20
    VRTDataset *poVRTDS = cpl::down_cast<VRTDataset *>(poDS);
1420
20
    poVRTDS->BuildVirtualOverviews();
1421
20
    if (!poVRTDS->m_apoOverviews.empty() && poVRTDS->m_apoOverviews[0])
1422
20
    {
1423
20
        if (iOverview < 0 ||
1424
20
            iOverview >= static_cast<int>(poVRTDS->m_apoOverviews.size()))
1425
0
            return nullptr;
1426
1427
20
        auto poOvrBand = poVRTDS->m_apoOverviews[iOverview]->GetRasterBand(
1428
20
            nBand ? nBand : 1);
1429
20
        if (m_bIsMaskBand)
1430
0
            return poOvrBand->GetMaskBand();
1431
20
        return poOvrBand;
1432
20
    }
1433
1434
0
    return nullptr;
1435
20
}
1436
1437
/************************************************************************/
1438
/*                          SetDescription()                            */
1439
/************************************************************************/
1440
1441
void VRTRasterBand::SetDescription(const char *pszDescription)
1442
1443
32.2k
{
1444
32.2k
    cpl::down_cast<VRTDataset *>(poDS)->SetNeedsFlush();
1445
1446
32.2k
    GDALRasterBand::SetDescription(pszDescription);
1447
32.2k
}
1448
1449
/************************************************************************/
1450
/*                          CreateMaskBand()                            */
1451
/************************************************************************/
1452
1453
CPLErr VRTRasterBand::CreateMaskBand(int nFlagsIn)
1454
0
{
1455
0
    VRTDataset *poGDS = cpl::down_cast<VRTDataset *>(poDS);
1456
1457
0
    if (poGDS->m_poMaskBand)
1458
0
    {
1459
0
        CPLError(CE_Failure, CPLE_AppDefined,
1460
0
                 "Cannot create mask band at raster band level when a dataset "
1461
0
                 "mask band already exists.");
1462
0
        return CE_Failure;
1463
0
    }
1464
1465
0
    if (m_poMaskBand != nullptr)
1466
0
    {
1467
0
        CPLError(CE_Failure, CPLE_AppDefined,
1468
0
                 "This VRT band has already a mask band");
1469
0
        return CE_Failure;
1470
0
    }
1471
1472
0
    if ((nFlagsIn & GMF_PER_DATASET) != 0)
1473
0
        return poGDS->CreateMaskBand(nFlagsIn);
1474
1475
0
    SetMaskBand(std::make_unique<VRTSourcedRasterBand>(poGDS, 0));
1476
1477
0
    return CE_None;
1478
0
}
1479
1480
/************************************************************************/
1481
/*                           GetMaskBand()                              */
1482
/************************************************************************/
1483
1484
GDALRasterBand *VRTRasterBand::GetMaskBand()
1485
84.0k
{
1486
84.0k
    VRTDataset *poGDS = cpl::down_cast<VRTDataset *>(poDS);
1487
1488
84.0k
    if (poGDS->m_poMaskBand)
1489
469
        return poGDS->m_poMaskBand.get();
1490
83.5k
    else if (m_poMaskBand)
1491
0
        return m_poMaskBand.get();
1492
83.5k
    else
1493
83.5k
        return GDALRasterBand::GetMaskBand();
1494
84.0k
}
1495
1496
/************************************************************************/
1497
/*                            GetMaskFlags()                            */
1498
/************************************************************************/
1499
1500
int VRTRasterBand::GetMaskFlags()
1501
178k
{
1502
178k
    VRTDataset *poGDS = cpl::down_cast<VRTDataset *>(poDS);
1503
1504
178k
    if (poGDS->m_poMaskBand)
1505
1.14k
        return GMF_PER_DATASET;
1506
177k
    else if (m_poMaskBand)
1507
0
        return 0;
1508
177k
    else
1509
177k
        return GDALRasterBand::GetMaskFlags();
1510
178k
}
1511
1512
/************************************************************************/
1513
/*                           SetMaskBand()                              */
1514
/************************************************************************/
1515
1516
void VRTRasterBand::SetMaskBand(std::unique_ptr<VRTRasterBand> poMaskBand)
1517
0
{
1518
0
    m_poMaskBand = std::move(poMaskBand);
1519
0
    m_poMaskBand->SetIsMaskBand();
1520
0
}
1521
1522
/************************************************************************/
1523
/*                          SetIsMaskBand()                             */
1524
/************************************************************************/
1525
1526
void VRTRasterBand::SetIsMaskBand()
1527
358
{
1528
358
    nBand = 0;
1529
358
    m_bIsMaskBand = true;
1530
358
}
1531
1532
/************************************************************************/
1533
/*                            IsMaskBand()                              */
1534
/************************************************************************/
1535
1536
bool VRTRasterBand::IsMaskBand() const
1537
0
{
1538
0
    return m_bIsMaskBand || m_eColorInterp == GCI_AlphaBand;
1539
0
}
1540
1541
/************************************************************************/
1542
/*                        CloseDependentDatasets()                      */
1543
/************************************************************************/
1544
1545
int VRTRasterBand::CloseDependentDatasets()
1546
202k
{
1547
202k
    int ret = FALSE;
1548
202k
    for (auto &oOverviewInfo : m_aoOverviewInfos)
1549
0
    {
1550
0
        if (oOverviewInfo.CloseDataset())
1551
0
        {
1552
0
            ret = TRUE;
1553
0
        }
1554
0
    }
1555
202k
    return ret;
1556
202k
}
1557
1558
/*! @endcond */