Coverage Report

Created: 2026-04-01 06:20

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