Coverage Report

Created: 2025-06-13 06:18

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