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