Coverage Report

Created: 2025-11-16 06:25

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