Coverage Report

Created: 2025-08-28 06:57

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