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