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