Coverage Report

Created: 2026-07-25 06:50

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