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