Coverage Report

Created: 2026-02-14 06:52

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