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 141318 : VRTRasterBand::VRTRasterBand()
50 : {
51 141318 : VRTRasterBand::Initialize(0, 0);
52 141318 : }
53 :
54 : /************************************************************************/
55 : /* Initialize() */
56 : /************************************************************************/
57 :
58 282636 : void VRTRasterBand::Initialize(int nXSize, int nYSize)
59 :
60 : {
61 282636 : poDS = nullptr;
62 282636 : nBand = 0;
63 282636 : eAccess = GA_ReadOnly;
64 282636 : eDataType = GDT_Byte;
65 :
66 282636 : nRasterXSize = nXSize;
67 282636 : nRasterYSize = nYSize;
68 :
69 282636 : nBlockXSize = std::min(128, nXSize);
70 282636 : nBlockYSize = std::min(128, nYSize);
71 282636 : }
72 :
73 : /************************************************************************/
74 : /* ~VRTRasterBand() */
75 : /************************************************************************/
76 :
77 141316 : VRTRasterBand::~VRTRasterBand()
78 :
79 : {
80 141316 : CPLFree(m_pszUnitType);
81 :
82 141316 : if (m_psSavedHistograms != nullptr)
83 10 : CPLDestroyXMLNode(m_psSavedHistograms);
84 :
85 141316 : delete m_poMaskBand;
86 141316 : }
87 :
88 : /************************************************************************/
89 : /* CopyCommonInfoFrom() */
90 : /* */
91 : /* Copy common metadata, pixel descriptions, and color */
92 : /* interpretation from the provided source band. */
93 : /************************************************************************/
94 :
95 66092 : CPLErr VRTRasterBand::CopyCommonInfoFrom(GDALRasterBand *poSrcBand)
96 :
97 : {
98 66092 : SetMetadata(poSrcBand->GetMetadata());
99 : const char *pszNBits =
100 66092 : poSrcBand->GetMetadataItem("NBITS", "IMAGE_STRUCTURE");
101 66092 : SetMetadataItem("NBITS", pszNBits, "IMAGE_STRUCTURE");
102 66092 : if (poSrcBand->GetRasterDataType() == GDT_Byte)
103 : {
104 66044 : poSrcBand->EnablePixelTypeSignedByteWarning(false);
105 : const char *pszPixelType =
106 66044 : poSrcBand->GetMetadataItem("PIXELTYPE", "IMAGE_STRUCTURE");
107 66044 : poSrcBand->EnablePixelTypeSignedByteWarning(true);
108 66044 : SetMetadataItem("PIXELTYPE", pszPixelType, "IMAGE_STRUCTURE");
109 : }
110 66092 : SetColorTable(poSrcBand->GetColorTable());
111 66092 : SetColorInterpretation(poSrcBand->GetColorInterpretation());
112 66092 : if (strlen(poSrcBand->GetDescription()) > 0)
113 1 : SetDescription(poSrcBand->GetDescription());
114 :
115 66092 : GDALCopyNoDataValue(this, poSrcBand);
116 66092 : SetOffset(poSrcBand->GetOffset());
117 66092 : SetScale(poSrcBand->GetScale());
118 66092 : SetCategoryNames(poSrcBand->GetCategoryNames());
119 66092 : if (!EQUAL(poSrcBand->GetUnitType(), ""))
120 1 : SetUnitType(poSrcBand->GetUnitType());
121 :
122 66092 : GDALRasterAttributeTable *poRAT = poSrcBand->GetDefaultRAT();
123 66093 : if (poRAT != nullptr &&
124 1 : static_cast<GIntBig>(poRAT->GetColumnCount()) * poRAT->GetRowCount() <
125 : 1024 * 1024)
126 : {
127 1 : SetDefaultRAT(poRAT);
128 : }
129 :
130 66092 : return CE_None;
131 : }
132 :
133 : /************************************************************************/
134 : /* SetMetadata() */
135 : /************************************************************************/
136 :
137 70316 : CPLErr VRTRasterBand::SetMetadata(char **papszMetadata, const char *pszDomain)
138 :
139 : {
140 70316 : static_cast<VRTDataset *>(poDS)->SetNeedsFlush();
141 :
142 70316 : return GDALRasterBand::SetMetadata(papszMetadata, pszDomain);
143 : }
144 :
145 : /************************************************************************/
146 : /* SetMetadataItem() */
147 : /************************************************************************/
148 :
149 133814 : CPLErr VRTRasterBand::SetMetadataItem(const char *pszName, const char *pszValue,
150 : const char *pszDomain)
151 :
152 : {
153 133814 : static_cast<VRTDataset *>(poDS)->SetNeedsFlush();
154 :
155 133814 : if (EQUAL(pszName, "HideNoDataValue"))
156 : {
157 2 : m_bHideNoDataValue = CPLTestBool(pszValue);
158 2 : return CE_None;
159 : }
160 :
161 133812 : return GDALRasterBand::SetMetadataItem(pszName, pszValue, pszDomain);
162 : }
163 :
164 : /************************************************************************/
165 : /* GetUnitType() */
166 : /************************************************************************/
167 :
168 6773 : const char *VRTRasterBand::GetUnitType()
169 :
170 : {
171 6773 : if (m_pszUnitType == nullptr)
172 6756 : return "";
173 :
174 17 : return m_pszUnitType;
175 : }
176 :
177 : /************************************************************************/
178 : /* SetUnitType() */
179 : /************************************************************************/
180 :
181 2987 : CPLErr VRTRasterBand::SetUnitType(const char *pszNewValue)
182 :
183 : {
184 2987 : static_cast<VRTDataset *>(poDS)->SetNeedsFlush();
185 :
186 2987 : CPLFree(m_pszUnitType);
187 :
188 2987 : if (pszNewValue == nullptr)
189 2958 : m_pszUnitType = nullptr;
190 : else
191 29 : m_pszUnitType = CPLStrdup(pszNewValue);
192 :
193 2987 : return CE_None;
194 : }
195 :
196 : /************************************************************************/
197 : /* GetOffset() */
198 : /************************************************************************/
199 :
200 8584 : double VRTRasterBand::GetOffset(int *pbSuccess)
201 :
202 : {
203 8584 : if (pbSuccess != nullptr)
204 5191 : *pbSuccess = TRUE;
205 :
206 8584 : return m_dfOffset;
207 : }
208 :
209 : /************************************************************************/
210 : /* SetOffset() */
211 : /************************************************************************/
212 :
213 73249 : CPLErr VRTRasterBand::SetOffset(double dfNewOffset)
214 :
215 : {
216 73249 : static_cast<VRTDataset *>(poDS)->SetNeedsFlush();
217 :
218 73249 : m_dfOffset = dfNewOffset;
219 73249 : return CE_None;
220 : }
221 :
222 : /************************************************************************/
223 : /* GetScale() */
224 : /************************************************************************/
225 :
226 8585 : double VRTRasterBand::GetScale(int *pbSuccess)
227 :
228 : {
229 8585 : if (pbSuccess != nullptr)
230 5192 : *pbSuccess = TRUE;
231 :
232 8585 : return m_dfScale;
233 : }
234 :
235 : /************************************************************************/
236 : /* SetScale() */
237 : /************************************************************************/
238 :
239 73245 : CPLErr VRTRasterBand::SetScale(double dfNewScale)
240 :
241 : {
242 73245 : static_cast<VRTDataset *>(poDS)->SetNeedsFlush();
243 :
244 73245 : m_dfScale = dfNewScale;
245 73245 : return CE_None;
246 : }
247 :
248 : /************************************************************************/
249 : /* GetCategoryNames() */
250 : /************************************************************************/
251 :
252 7389 : char **VRTRasterBand::GetCategoryNames()
253 :
254 : {
255 7389 : return m_aosCategoryNames.List();
256 : }
257 :
258 : /************************************************************************/
259 : /* SetCategoryNames() */
260 : /************************************************************************/
261 :
262 70310 : CPLErr VRTRasterBand::SetCategoryNames(char **papszNewNames)
263 :
264 : {
265 70310 : static_cast<VRTDataset *>(poDS)->SetNeedsFlush();
266 :
267 70310 : m_aosCategoryNames = CSLDuplicate(papszNewNames);
268 :
269 70310 : 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 2959 : CPLErr VRTRasterBand::XMLInit(const CPLXMLNode *psTree, const char *pszVRTPath,
331 : VRTMapSharedResources &oMapSharedSources)
332 :
333 : {
334 : /* -------------------------------------------------------------------- */
335 : /* Validate a bit. */
336 : /* -------------------------------------------------------------------- */
337 2959 : if (psTree == nullptr || psTree->eType != CXT_Element ||
338 2959 : !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 2959 : const char *pszBand = CPLGetXMLValue(psTree, "band", nullptr);
349 2959 : if (pszBand != nullptr)
350 : {
351 2837 : int nNewBand = atoi(pszBand);
352 2837 : 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 2959 : const char *pszDataType = CPLGetXMLValue(psTree, "dataType", nullptr);
365 2959 : if (pszDataType != nullptr)
366 : {
367 2937 : eDataType = GDALGetDataTypeByName(pszDataType);
368 2937 : 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 2959 : const char *pszBlockXSize = CPLGetXMLValue(psTree, "blockXSize", nullptr);
377 2959 : if (pszBlockXSize)
378 : {
379 191 : int nBlockXSizeIn = atoi(pszBlockXSize);
380 191 : if (nBlockXSizeIn >= 32 && nBlockXSizeIn <= 16384)
381 188 : nBlockXSize = nBlockXSizeIn;
382 : }
383 :
384 2959 : const char *pszBlockYSize = CPLGetXMLValue(psTree, "blockYSize", nullptr);
385 2959 : if (pszBlockYSize)
386 : {
387 192 : int nBlockYSizeIn = atoi(pszBlockYSize);
388 192 : if (nBlockYSizeIn >= 32 && nBlockYSizeIn <= 16384)
389 50 : nBlockYSize = nBlockYSizeIn;
390 : }
391 :
392 : /* -------------------------------------------------------------------- */
393 : /* Apply any band level metadata. */
394 : /* -------------------------------------------------------------------- */
395 2959 : oMDMD.XMLInit(psTree, TRUE);
396 :
397 : /* -------------------------------------------------------------------- */
398 : /* Collect various other items of metadata. */
399 : /* -------------------------------------------------------------------- */
400 2959 : SetDescription(CPLGetXMLValue(psTree, "Description", ""));
401 :
402 2959 : const char *pszNoDataValue = CPLGetXMLValue(psTree, "NoDataValue", nullptr);
403 2959 : if (pszNoDataValue != nullptr)
404 : {
405 330 : if (eDataType == GDT_Int64)
406 : {
407 2 : SetNoDataValueAsInt64(static_cast<int64_t>(
408 2 : std::strtoll(pszNoDataValue, nullptr, 10)));
409 : }
410 328 : 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 326 : SetNoDataValue(CPLAtofM(pszNoDataValue));
418 : }
419 : }
420 :
421 2959 : if (CPLGetXMLValue(psTree, "HideNoDataValue", nullptr) != nullptr)
422 3 : m_bHideNoDataValue =
423 3 : CPLTestBool(CPLGetXMLValue(psTree, "HideNoDataValue", "0"));
424 :
425 2959 : SetUnitType(CPLGetXMLValue(psTree, "UnitType", nullptr));
426 :
427 2959 : SetOffset(CPLAtof(CPLGetXMLValue(psTree, "Offset", "0.0")));
428 2959 : SetScale(CPLAtof(CPLGetXMLValue(psTree, "Scale", "1.0")));
429 :
430 2959 : if (CPLGetXMLValue(psTree, "ColorInterp", nullptr) != nullptr)
431 : {
432 1251 : const char *pszInterp = CPLGetXMLValue(psTree, "ColorInterp", nullptr);
433 1251 : SetColorInterpretation(GDALGetColorInterpretationByName(pszInterp));
434 : }
435 :
436 : /* -------------------------------------------------------------------- */
437 : /* Category names. */
438 : /* -------------------------------------------------------------------- */
439 2959 : if (const CPLXMLNode *psCategoryNames =
440 2959 : CPLGetXMLNode(psTree, "CategoryNames"))
441 : {
442 1 : m_aosCategoryNames = VRTParseCategoryNames(psCategoryNames);
443 : }
444 :
445 : /* -------------------------------------------------------------------- */
446 : /* Collect a color table. */
447 : /* -------------------------------------------------------------------- */
448 2959 : 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 2959 : if (const CPLXMLNode *psRAT =
459 2959 : 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 2959 : const CPLXMLNode *psHist = CPLGetXMLNode(psTree, "Histograms");
469 2959 : 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 2959 : const CPLXMLNode *psNode = psTree->psChild;
480 :
481 21605 : for (; psNode != nullptr; psNode = psNode->psNext)
482 : {
483 18646 : if (psNode->eType != CXT_Element ||
484 10628 : !EQUAL(psNode->pszValue, "Overview"))
485 18630 : 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 2959 : const CPLXMLNode *psMaskBandNode = CPLGetXMLNode(psTree, "MaskBand");
545 2959 : if (psMaskBandNode)
546 1 : psNode = psMaskBandNode->psChild;
547 : else
548 2958 : psNode = nullptr;
549 2959 : 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 2959 : return CE_None;
596 : }
597 :
598 : /************************************************************************/
599 : /* VRTSerializeNoData() */
600 : /************************************************************************/
601 :
602 154 : CPLString VRTSerializeNoData(double dfVal, GDALDataType eDataType,
603 : int nPrecision)
604 : {
605 154 : if (std::isnan(dfVal))
606 : {
607 0 : return "nan";
608 : }
609 154 : 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 154 : 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 175 : 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 159 : 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 140 : snprintf(szFormat, sizeof(szFormat), "%%.%dg", nPrecision);
635 140 : return CPLSPrintf(szFormat, dfVal);
636 : }
637 : }
638 :
639 : /************************************************************************/
640 : /* SerializeToXML() */
641 : /************************************************************************/
642 :
643 855 : CPLXMLNode *VRTRasterBand::SerializeToXML(const char *pszVRTPath,
644 : bool &bHasWarnedAboutRAMUsage,
645 : size_t &nAccRAMUsage)
646 :
647 : {
648 : CPLXMLNode *psTree =
649 855 : CPLCreateXMLNode(nullptr, CXT_Element, "VRTRasterBand");
650 :
651 : /* -------------------------------------------------------------------- */
652 : /* Various kinds of metadata. */
653 : /* -------------------------------------------------------------------- */
654 855 : CPLSetXMLValue(psTree, "#dataType",
655 : GDALGetDataTypeName(GetRasterDataType()));
656 :
657 855 : if (nBand > 0)
658 836 : 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 855 : if (dynamic_cast<VRTWarpedRasterBand *>(this) == nullptr)
663 : {
664 668 : if (!VRTDataset::IsDefaultBlockSize(nBlockXSize, nRasterXSize))
665 : {
666 170 : CPLSetXMLValue(psTree, "#blockXSize",
667 : CPLSPrintf("%d", nBlockXSize));
668 : }
669 :
670 668 : if (!VRTDataset::IsDefaultBlockSize(nBlockYSize, nRasterYSize))
671 : {
672 215 : CPLSetXMLValue(psTree, "#blockYSize",
673 : CPLSPrintf("%d", nBlockYSize));
674 : }
675 : }
676 :
677 855 : CPLXMLNode *psMD = oMDMD.Serialize();
678 855 : if (psMD != nullptr)
679 : {
680 97 : CPLAddXMLChild(psTree, psMD);
681 : }
682 :
683 855 : if (strlen(GetDescription()) > 0)
684 66 : CPLSetXMLValue(psTree, "Description", GetDescription());
685 :
686 855 : if (m_bNoDataValueSet)
687 : {
688 96 : CPLSetXMLValue(
689 : psTree, "NoDataValue",
690 192 : VRTSerializeNoData(m_dfNoDataValue, eDataType, 18).c_str());
691 : }
692 759 : else if (m_bNoDataSetAsInt64)
693 : {
694 1 : CPLSetXMLValue(psTree, "NoDataValue",
695 : CPLSPrintf(CPL_FRMT_GIB,
696 1 : static_cast<GIntBig>(m_nNoDataValueInt64)));
697 : }
698 758 : else if (m_bNoDataSetAsUInt64)
699 : {
700 1 : CPLSetXMLValue(psTree, "NoDataValue",
701 : CPLSPrintf(CPL_FRMT_GUIB,
702 1 : static_cast<GUIntBig>(m_nNoDataValueUInt64)));
703 : }
704 :
705 855 : if (m_bHideNoDataValue)
706 0 : CPLSetXMLValue(psTree, "HideNoDataValue",
707 : CPLSPrintf("%d", m_bHideNoDataValue));
708 :
709 855 : if (m_pszUnitType != nullptr)
710 2 : CPLSetXMLValue(psTree, "UnitType", m_pszUnitType);
711 :
712 855 : if (m_dfOffset != 0.0)
713 6 : CPLSetXMLValue(psTree, "Offset", CPLSPrintf("%.16g", m_dfOffset));
714 :
715 855 : if (m_dfScale != 1.0)
716 6 : CPLSetXMLValue(psTree, "Scale", CPLSPrintf("%.16g", m_dfScale));
717 :
718 855 : if (m_eColorInterp != GCI_Undefined)
719 621 : CPLSetXMLValue(psTree, "ColorInterp",
720 : GDALGetColorInterpretationName(m_eColorInterp));
721 :
722 : /* -------------------------------------------------------------------- */
723 : /* Category names. */
724 : /* -------------------------------------------------------------------- */
725 855 : if (!m_aosCategoryNames.empty())
726 : {
727 : CPLXMLNode *psCT_XML =
728 5 : CPLCreateXMLNode(psTree, CXT_Element, "CategoryNames");
729 5 : CPLXMLNode *psLastChild = nullptr;
730 :
731 45 : for (const char *pszName : m_aosCategoryNames)
732 : {
733 : CPLXMLNode *psNode =
734 40 : CPLCreateXMLElementAndValue(nullptr, "Category", pszName);
735 40 : if (psLastChild == nullptr)
736 5 : psCT_XML->psChild = psNode;
737 : else
738 35 : psLastChild->psNext = psNode;
739 40 : psLastChild = psNode;
740 : }
741 : }
742 :
743 : /* -------------------------------------------------------------------- */
744 : /* Histograms. */
745 : /* -------------------------------------------------------------------- */
746 855 : if (m_psSavedHistograms != nullptr)
747 8 : CPLAddXMLChild(psTree, CPLCloneXMLTree(m_psSavedHistograms));
748 :
749 : /* -------------------------------------------------------------------- */
750 : /* Color Table. */
751 : /* -------------------------------------------------------------------- */
752 855 : if (m_poColorTable != nullptr)
753 : {
754 : CPLXMLNode *psCT_XML =
755 7 : CPLCreateXMLNode(psTree, CXT_Element, "ColorTable");
756 7 : CPLXMLNode *psLastChild = nullptr;
757 :
758 783 : for (int iEntry = 0; iEntry < m_poColorTable->GetColorEntryCount();
759 : iEntry++)
760 : {
761 : CPLXMLNode *psEntry_XML =
762 776 : CPLCreateXMLNode(nullptr, CXT_Element, "Entry");
763 776 : if (psLastChild == nullptr)
764 7 : psCT_XML->psChild = psEntry_XML;
765 : else
766 769 : psLastChild->psNext = psEntry_XML;
767 776 : psLastChild = psEntry_XML;
768 :
769 : GDALColorEntry sEntry;
770 776 : m_poColorTable->GetColorEntryAsRGB(iEntry, &sEntry);
771 :
772 776 : CPLSetXMLValue(psEntry_XML, "#c1", CPLSPrintf("%d", sEntry.c1));
773 776 : CPLSetXMLValue(psEntry_XML, "#c2", CPLSPrintf("%d", sEntry.c2));
774 776 : CPLSetXMLValue(psEntry_XML, "#c3", CPLSPrintf("%d", sEntry.c3));
775 776 : CPLSetXMLValue(psEntry_XML, "#c4", CPLSPrintf("%d", sEntry.c4));
776 : }
777 : }
778 :
779 : /* -------------------------------------------------------------------- */
780 : /* Raster Attribute Table */
781 : /* -------------------------------------------------------------------- */
782 855 : if (m_poRAT != nullptr)
783 : {
784 4 : CPLXMLNode *psSerializedRAT = m_poRAT->Serialize();
785 4 : if (psSerializedRAT != nullptr)
786 4 : CPLAddXMLChild(psTree, psSerializedRAT);
787 : }
788 :
789 : /* ==================================================================== */
790 : /* Overviews */
791 : /* ==================================================================== */
792 :
793 856 : for (int iOvr = 0; iOvr < static_cast<int>(m_aoOverviewInfos.size());
794 : iOvr++)
795 : {
796 : CPLXMLNode *psOVR_XML =
797 1 : CPLCreateXMLNode(psTree, CXT_Element, "Overview");
798 :
799 1 : int bRelativeToVRT = FALSE;
800 1 : const char *pszRelativePath = nullptr;
801 : VSIStatBufL sStat;
802 :
803 1 : if (VSIStatExL(m_aoOverviewInfos[iOvr].osFilename, &sStat,
804 1 : VSI_STAT_EXISTS_FLAG) != 0)
805 : {
806 0 : pszRelativePath = m_aoOverviewInfos[iOvr].osFilename;
807 0 : bRelativeToVRT = FALSE;
808 : }
809 : else
810 : {
811 1 : pszRelativePath = CPLExtractRelativePath(
812 1 : pszVRTPath, m_aoOverviewInfos[iOvr].osFilename,
813 : &bRelativeToVRT);
814 : }
815 :
816 1 : CPLSetXMLValue(psOVR_XML, "SourceFilename", pszRelativePath);
817 :
818 1 : CPLCreateXMLNode(
819 : CPLCreateXMLNode(CPLGetXMLNode(psOVR_XML, "SourceFilename"),
820 : CXT_Attribute, "relativeToVRT"),
821 1 : CXT_Text, bRelativeToVRT ? "1" : "0");
822 :
823 1 : CPLSetXMLValue(psOVR_XML, "SourceBand",
824 1 : CPLSPrintf("%d", m_aoOverviewInfos[iOvr].nBand));
825 : }
826 :
827 : /* ==================================================================== */
828 : /* Mask band (specific to that raster band) */
829 : /* ==================================================================== */
830 :
831 855 : nAccRAMUsage += CPLXMLNodeGetRAMUsageEstimate(psTree);
832 :
833 855 : if (m_poMaskBand != nullptr)
834 : {
835 0 : CPLXMLNode *psBandTree = m_poMaskBand->SerializeToXML(
836 0 : pszVRTPath, bHasWarnedAboutRAMUsage, nAccRAMUsage);
837 :
838 0 : if (psBandTree != nullptr)
839 : {
840 : CPLXMLNode *psMaskBandElement =
841 0 : CPLCreateXMLNode(psTree, CXT_Element, "MaskBand");
842 0 : CPLAddXMLChild(psMaskBandElement, psBandTree);
843 : }
844 : }
845 :
846 855 : return psTree;
847 : }
848 :
849 : /************************************************************************/
850 : /* ResetNoDataValues() */
851 : /************************************************************************/
852 :
853 681 : void VRTRasterBand::ResetNoDataValues()
854 : {
855 681 : m_bNoDataValueSet = FALSE;
856 681 : m_dfNoDataValue = VRT_DEFAULT_NODATA_VALUE;
857 :
858 681 : m_bNoDataSetAsInt64 = false;
859 681 : m_nNoDataValueInt64 = GDAL_PAM_DEFAULT_NODATA_VALUE_INT64;
860 :
861 681 : m_bNoDataSetAsUInt64 = false;
862 681 : m_nNoDataValueUInt64 = GDAL_PAM_DEFAULT_NODATA_VALUE_UINT64;
863 681 : }
864 :
865 : /************************************************************************/
866 : /* SetNoDataValue() */
867 : /************************************************************************/
868 :
869 671 : CPLErr VRTRasterBand::SetNoDataValue(double dfNewValue)
870 :
871 : {
872 671 : if (eDataType == GDT_Float32)
873 : {
874 132 : dfNewValue = GDALAdjustNoDataCloseToFloatMax(dfNewValue);
875 : }
876 :
877 671 : ResetNoDataValues();
878 :
879 671 : m_bNoDataValueSet = TRUE;
880 671 : m_dfNoDataValue = dfNewValue;
881 :
882 671 : static_cast<VRTDataset *>(poDS)->SetNeedsFlush();
883 :
884 671 : return CE_None;
885 : }
886 :
887 : /************************************************************************/
888 : /* IsNoDataValueInDataTypeRange() */
889 : /************************************************************************/
890 :
891 2 : bool VRTRasterBand::IsNoDataValueInDataTypeRange() const
892 : {
893 2 : if (m_bNoDataSetAsInt64)
894 0 : return eDataType == GDT_Int64;
895 2 : if (m_bNoDataSetAsUInt64)
896 0 : return eDataType == GDT_UInt64;
897 2 : if (!m_bNoDataValueSet)
898 0 : return true;
899 2 : if (!std::isfinite(m_dfNoDataValue))
900 0 : return eDataType == GDT_Float16 || eDataType == GDT_Float32 ||
901 0 : eDataType == GDT_Float64;
902 : GByte abyTempBuffer[2 * sizeof(double)];
903 2 : CPLAssert(GDALGetDataTypeSizeBytes(eDataType) <=
904 : static_cast<int>(sizeof(abyTempBuffer)));
905 2 : GDALCopyWords(&m_dfNoDataValue, GDT_Float64, 0, &abyTempBuffer[0],
906 2 : eDataType, 0, 1);
907 2 : double dfNoDataValueAfter = 0;
908 2 : GDALCopyWords(&abyTempBuffer[0], eDataType, 0, &dfNoDataValueAfter,
909 : GDT_Float64, 0, 1);
910 2 : return std::fabs(dfNoDataValueAfter - m_dfNoDataValue) < 1.0;
911 : }
912 :
913 : /************************************************************************/
914 : /* SetNoDataValueAsInt64() */
915 : /************************************************************************/
916 :
917 4 : CPLErr VRTRasterBand::SetNoDataValueAsInt64(int64_t nNewValue)
918 :
919 : {
920 4 : ResetNoDataValues();
921 :
922 4 : m_bNoDataSetAsInt64 = true;
923 4 : m_nNoDataValueInt64 = nNewValue;
924 :
925 4 : static_cast<VRTDataset *>(poDS)->SetNeedsFlush();
926 :
927 4 : return CE_None;
928 : }
929 :
930 : /************************************************************************/
931 : /* SetNoDataValueAsUInt64() */
932 : /************************************************************************/
933 :
934 4 : CPLErr VRTRasterBand::SetNoDataValueAsUInt64(uint64_t nNewValue)
935 :
936 : {
937 4 : ResetNoDataValues();
938 :
939 4 : m_bNoDataSetAsUInt64 = true;
940 4 : m_nNoDataValueUInt64 = nNewValue;
941 :
942 4 : static_cast<VRTDataset *>(poDS)->SetNeedsFlush();
943 :
944 4 : return CE_None;
945 : }
946 :
947 : /************************************************************************/
948 : /* DeleteNoDataValue() */
949 : /************************************************************************/
950 :
951 2 : CPLErr VRTRasterBand::DeleteNoDataValue()
952 : {
953 2 : ResetNoDataValues();
954 :
955 2 : static_cast<VRTDataset *>(poDS)->SetNeedsFlush();
956 :
957 2 : return CE_None;
958 : }
959 :
960 : /************************************************************************/
961 : /* UnsetNoDataValue() */
962 : /************************************************************************/
963 :
964 0 : CPLErr VRTRasterBand::UnsetNoDataValue()
965 : {
966 0 : return DeleteNoDataValue();
967 : }
968 :
969 : /************************************************************************/
970 : /* GetNoDataValue() */
971 : /************************************************************************/
972 :
973 37081 : double VRTRasterBand::GetNoDataValue(int *pbSuccess)
974 :
975 : {
976 37081 : if (m_bNoDataSetAsInt64)
977 : {
978 0 : if (pbSuccess)
979 0 : *pbSuccess = !m_bHideNoDataValue;
980 0 : return GDALGetNoDataValueCastToDouble(m_nNoDataValueInt64);
981 : }
982 :
983 37081 : if (m_bNoDataSetAsUInt64)
984 : {
985 0 : if (pbSuccess)
986 0 : *pbSuccess = !m_bHideNoDataValue;
987 0 : return GDALGetNoDataValueCastToDouble(m_nNoDataValueUInt64);
988 : }
989 :
990 37081 : if (pbSuccess)
991 36874 : *pbSuccess = m_bNoDataValueSet && !m_bHideNoDataValue;
992 :
993 37081 : return m_dfNoDataValue;
994 : }
995 :
996 : /************************************************************************/
997 : /* GetNoDataValueAsInt64() */
998 : /************************************************************************/
999 :
1000 16 : int64_t VRTRasterBand::GetNoDataValueAsInt64(int *pbSuccess)
1001 :
1002 : {
1003 16 : if (eDataType == GDT_UInt64)
1004 : {
1005 0 : CPLError(CE_Failure, CPLE_AppDefined,
1006 : "GetNoDataValueAsUInt64() should be called instead");
1007 0 : if (pbSuccess)
1008 0 : *pbSuccess = FALSE;
1009 0 : return GDAL_PAM_DEFAULT_NODATA_VALUE_INT64;
1010 : }
1011 16 : if (eDataType != GDT_Int64)
1012 : {
1013 0 : CPLError(CE_Failure, CPLE_AppDefined,
1014 : "GetNoDataValue() should be called instead");
1015 0 : if (pbSuccess)
1016 0 : *pbSuccess = FALSE;
1017 0 : return GDAL_PAM_DEFAULT_NODATA_VALUE_INT64;
1018 : }
1019 :
1020 16 : if (pbSuccess)
1021 15 : *pbSuccess = m_bNoDataSetAsInt64 && !m_bHideNoDataValue;
1022 :
1023 16 : return m_nNoDataValueInt64;
1024 : }
1025 :
1026 : /************************************************************************/
1027 : /* GetNoDataValueAsUInt64() */
1028 : /************************************************************************/
1029 :
1030 8 : uint64_t VRTRasterBand::GetNoDataValueAsUInt64(int *pbSuccess)
1031 :
1032 : {
1033 8 : if (eDataType == GDT_Int64)
1034 : {
1035 0 : CPLError(CE_Failure, CPLE_AppDefined,
1036 : "GetNoDataValueAsInt64() should be called instead");
1037 0 : if (pbSuccess)
1038 0 : *pbSuccess = FALSE;
1039 0 : return GDAL_PAM_DEFAULT_NODATA_VALUE_UINT64;
1040 : }
1041 8 : if (eDataType != GDT_UInt64)
1042 : {
1043 0 : CPLError(CE_Failure, CPLE_AppDefined,
1044 : "GetNoDataValue() should be called instead");
1045 0 : if (pbSuccess)
1046 0 : *pbSuccess = FALSE;
1047 0 : return GDAL_PAM_DEFAULT_NODATA_VALUE_UINT64;
1048 : }
1049 :
1050 8 : if (pbSuccess)
1051 7 : *pbSuccess = m_bNoDataSetAsUInt64 && !m_bHideNoDataValue;
1052 :
1053 8 : return m_nNoDataValueUInt64;
1054 : }
1055 :
1056 : /************************************************************************/
1057 : /* SetColorTable() */
1058 : /************************************************************************/
1059 :
1060 70325 : CPLErr VRTRasterBand::SetColorTable(GDALColorTable *poTableIn)
1061 :
1062 : {
1063 70325 : if (poTableIn == nullptr)
1064 70296 : m_poColorTable.reset();
1065 : else
1066 : {
1067 29 : m_poColorTable.reset(poTableIn->Clone());
1068 29 : m_eColorInterp = GCI_PaletteIndex;
1069 : }
1070 :
1071 70325 : static_cast<VRTDataset *>(poDS)->SetNeedsFlush();
1072 :
1073 70325 : return CE_None;
1074 : }
1075 :
1076 : /************************************************************************/
1077 : /* GetColorTable() */
1078 : /************************************************************************/
1079 :
1080 6203 : GDALColorTable *VRTRasterBand::GetColorTable()
1081 :
1082 : {
1083 6203 : return m_poColorTable.get();
1084 : }
1085 :
1086 : /************************************************************************/
1087 : /* SetColorInterpretation() */
1088 : /************************************************************************/
1089 :
1090 72937 : CPLErr VRTRasterBand::SetColorInterpretation(GDALColorInterp eInterpIn)
1091 :
1092 : {
1093 72937 : static_cast<VRTDataset *>(poDS)->SetNeedsFlush();
1094 :
1095 72937 : m_eColorInterp = eInterpIn;
1096 :
1097 72937 : return CE_None;
1098 : }
1099 :
1100 : /************************************************************************/
1101 : /* GetDefaultRAT() */
1102 : /************************************************************************/
1103 :
1104 4207 : GDALRasterAttributeTable *VRTRasterBand::GetDefaultRAT()
1105 : {
1106 4207 : return m_poRAT.get();
1107 : }
1108 :
1109 : /************************************************************************/
1110 : /* SetDefaultRAT() */
1111 : /************************************************************************/
1112 :
1113 779 : CPLErr VRTRasterBand::SetDefaultRAT(const GDALRasterAttributeTable *poRAT)
1114 : {
1115 779 : if (poRAT == nullptr)
1116 777 : m_poRAT.reset();
1117 : else
1118 2 : m_poRAT.reset(poRAT->Clone());
1119 :
1120 779 : static_cast<VRTDataset *>(poDS)->SetNeedsFlush();
1121 :
1122 779 : return CE_None;
1123 : }
1124 :
1125 : /************************************************************************/
1126 : /* GetColorInterpretation() */
1127 : /************************************************************************/
1128 :
1129 16875 : GDALColorInterp VRTRasterBand::GetColorInterpretation()
1130 :
1131 : {
1132 16875 : return m_eColorInterp;
1133 : }
1134 :
1135 : /************************************************************************/
1136 : /* GetHistogram() */
1137 : /************************************************************************/
1138 :
1139 3 : CPLErr VRTRasterBand::GetHistogram(double dfMin, double dfMax, int nBuckets,
1140 : GUIntBig *panHistogram,
1141 : int bIncludeOutOfRange, int bApproxOK,
1142 : GDALProgressFunc pfnProgress,
1143 : void *pProgressData)
1144 :
1145 : {
1146 : /* -------------------------------------------------------------------- */
1147 : /* Check if we have a matching histogram. */
1148 : /* -------------------------------------------------------------------- */
1149 : CPLXMLNode *psHistItem =
1150 3 : PamFindMatchingHistogram(m_psSavedHistograms, dfMin, dfMax, nBuckets,
1151 : bIncludeOutOfRange, bApproxOK);
1152 3 : if (psHistItem != nullptr)
1153 : {
1154 0 : GUIntBig *panTempHist = nullptr;
1155 :
1156 0 : if (PamParseHistogram(psHistItem, &dfMin, &dfMax, &nBuckets,
1157 0 : &panTempHist, &bIncludeOutOfRange, &bApproxOK))
1158 : {
1159 0 : memcpy(panHistogram, panTempHist, sizeof(GUIntBig) * nBuckets);
1160 0 : CPLFree(panTempHist);
1161 0 : return CE_None;
1162 : }
1163 : }
1164 :
1165 : /* -------------------------------------------------------------------- */
1166 : /* We don't have an existing histogram matching the request, so */
1167 : /* generate one manually. */
1168 : /* -------------------------------------------------------------------- */
1169 3 : CPLErr eErr = GDALRasterBand::GetHistogram(
1170 : dfMin, dfMax, nBuckets, panHistogram, bIncludeOutOfRange, bApproxOK,
1171 : pfnProgress, pProgressData);
1172 :
1173 : /* -------------------------------------------------------------------- */
1174 : /* Save an XML description of this histogram. */
1175 : /* -------------------------------------------------------------------- */
1176 3 : if (eErr == CE_None)
1177 : {
1178 : CPLXMLNode *psXMLHist =
1179 3 : PamHistogramToXMLTree(dfMin, dfMax, nBuckets, panHistogram,
1180 : bIncludeOutOfRange, bApproxOK);
1181 3 : if (psXMLHist != nullptr)
1182 : {
1183 3 : static_cast<VRTDataset *>(poDS)->SetNeedsFlush();
1184 :
1185 3 : if (m_psSavedHistograms == nullptr)
1186 3 : m_psSavedHistograms =
1187 3 : CPLCreateXMLNode(nullptr, CXT_Element, "Histograms");
1188 :
1189 3 : CPLAddXMLChild(m_psSavedHistograms, psXMLHist);
1190 : }
1191 : }
1192 :
1193 3 : return eErr;
1194 : }
1195 :
1196 : /************************************************************************/
1197 : /* SetDefaultHistogram() */
1198 : /************************************************************************/
1199 :
1200 5 : CPLErr VRTRasterBand::SetDefaultHistogram(double dfMin, double dfMax,
1201 : int nBuckets, GUIntBig *panHistogram)
1202 :
1203 : {
1204 : /* -------------------------------------------------------------------- */
1205 : /* Do we have a matching histogram we should replace? */
1206 : /* -------------------------------------------------------------------- */
1207 5 : CPLXMLNode *psNode = PamFindMatchingHistogram(m_psSavedHistograms, dfMin,
1208 : dfMax, nBuckets, TRUE, TRUE);
1209 5 : if (psNode != nullptr)
1210 : {
1211 : /* blow this one away */
1212 0 : CPLRemoveXMLChild(m_psSavedHistograms, psNode);
1213 0 : CPLDestroyXMLNode(psNode);
1214 : }
1215 :
1216 : /* -------------------------------------------------------------------- */
1217 : /* Translate into a histogram XML tree. */
1218 : /* -------------------------------------------------------------------- */
1219 5 : CPLXMLNode *psHistItem = PamHistogramToXMLTree(dfMin, dfMax, nBuckets,
1220 : panHistogram, TRUE, FALSE);
1221 5 : if (psHistItem == nullptr)
1222 0 : return CE_Failure;
1223 :
1224 : /* -------------------------------------------------------------------- */
1225 : /* Insert our new default histogram at the front of the */
1226 : /* histogram list so that it will be the default histogram. */
1227 : /* -------------------------------------------------------------------- */
1228 5 : static_cast<VRTDataset *>(poDS)->SetNeedsFlush();
1229 :
1230 5 : if (m_psSavedHistograms == nullptr)
1231 5 : m_psSavedHistograms =
1232 5 : CPLCreateXMLNode(nullptr, CXT_Element, "Histograms");
1233 :
1234 5 : psHistItem->psNext = m_psSavedHistograms->psChild;
1235 5 : m_psSavedHistograms->psChild = psHistItem;
1236 :
1237 5 : return CE_None;
1238 : }
1239 :
1240 : /************************************************************************/
1241 : /* GetDefaultHistogram() */
1242 : /************************************************************************/
1243 :
1244 4 : CPLErr VRTRasterBand::GetDefaultHistogram(double *pdfMin, double *pdfMax,
1245 : int *pnBuckets,
1246 : GUIntBig **ppanHistogram, int bForce,
1247 : GDALProgressFunc pfnProgress,
1248 : void *pProgressData)
1249 :
1250 : {
1251 4 : if (m_psSavedHistograms != nullptr)
1252 : {
1253 1 : for (CPLXMLNode *psXMLHist = m_psSavedHistograms->psChild;
1254 1 : psXMLHist != nullptr; psXMLHist = psXMLHist->psNext)
1255 : {
1256 1 : if (psXMLHist->eType != CXT_Element ||
1257 1 : !EQUAL(psXMLHist->pszValue, "HistItem"))
1258 0 : continue;
1259 :
1260 : int bIncludeOutOfRange;
1261 : int bApprox;
1262 1 : if (PamParseHistogram(psXMLHist, pdfMin, pdfMax, pnBuckets,
1263 1 : ppanHistogram, &bIncludeOutOfRange, &bApprox))
1264 1 : return CE_None;
1265 :
1266 0 : return CE_Failure;
1267 : }
1268 : }
1269 :
1270 3 : return GDALRasterBand::GetDefaultHistogram(pdfMin, pdfMax, pnBuckets,
1271 : ppanHistogram, bForce,
1272 3 : pfnProgress, pProgressData);
1273 : }
1274 :
1275 : /************************************************************************/
1276 : /* GetFileList() */
1277 : /************************************************************************/
1278 :
1279 69 : void VRTRasterBand::GetFileList(char ***ppapszFileList, int *pnSize,
1280 : int *pnMaxSize, CPLHashSet *hSetFiles)
1281 : {
1282 70 : for (unsigned int iOver = 0; iOver < m_aoOverviewInfos.size(); iOver++)
1283 : {
1284 1 : const CPLString &osFilename = m_aoOverviewInfos[iOver].osFilename;
1285 :
1286 : /* --------------------------------------------------------------------
1287 : */
1288 : /* Is the filename even a real filesystem object? */
1289 : /* --------------------------------------------------------------------
1290 : */
1291 : VSIStatBufL sStat;
1292 1 : if (VSIStatL(osFilename, &sStat) != 0)
1293 0 : return;
1294 :
1295 : /* --------------------------------------------------------------------
1296 : */
1297 : /* Is it already in the list ? */
1298 : /* --------------------------------------------------------------------
1299 : */
1300 1 : if (CPLHashSetLookup(hSetFiles, osFilename) != nullptr)
1301 0 : return;
1302 :
1303 : /* --------------------------------------------------------------------
1304 : */
1305 : /* Grow array if necessary */
1306 : /* --------------------------------------------------------------------
1307 : */
1308 1 : if (*pnSize + 1 >= *pnMaxSize)
1309 : {
1310 1 : *pnMaxSize = 2 + 2 * (*pnMaxSize);
1311 1 : *ppapszFileList = static_cast<char **>(
1312 1 : CPLRealloc(*ppapszFileList, sizeof(char *) * (*pnMaxSize)));
1313 : }
1314 :
1315 : /* --------------------------------------------------------------------
1316 : */
1317 : /* Add the string to the list */
1318 : /* --------------------------------------------------------------------
1319 : */
1320 1 : (*ppapszFileList)[*pnSize] = CPLStrdup(osFilename);
1321 1 : (*ppapszFileList)[(*pnSize + 1)] = nullptr;
1322 1 : CPLHashSetInsert(hSetFiles, (*ppapszFileList)[*pnSize]);
1323 :
1324 1 : (*pnSize)++;
1325 : }
1326 : }
1327 :
1328 : /************************************************************************/
1329 : /* GetOverviewCount() */
1330 : /************************************************************************/
1331 :
1332 5702 : int VRTRasterBand::GetOverviewCount()
1333 :
1334 : {
1335 5702 : VRTDataset *poVRTDS = cpl::down_cast<VRTDataset *>(poDS);
1336 5702 : if (!poVRTDS->AreOverviewsEnabled())
1337 1 : return 0;
1338 :
1339 : // First: overviews declared in <Overview> element
1340 5701 : if (!m_aoOverviewInfos.empty())
1341 22 : return static_cast<int>(m_aoOverviewInfos.size());
1342 :
1343 : // If not found, external .ovr overviews
1344 5679 : const int nOverviewCount = GDALRasterBand::GetOverviewCount();
1345 5679 : if (nOverviewCount)
1346 52 : return nOverviewCount;
1347 :
1348 5627 : if (poVRTDS->m_apoOverviews.empty())
1349 : {
1350 : // If not found, implicit virtual overviews
1351 :
1352 5515 : const std::string osFctId("VRTRasterBand::GetOverviewCount");
1353 5515 : GDALAntiRecursionGuard oGuard(osFctId);
1354 5515 : if (oGuard.GetCallDepth() >= 32)
1355 : {
1356 0 : CPLError(CE_Failure, CPLE_AppDefined, "Recursion detected");
1357 0 : return 0;
1358 : }
1359 :
1360 11030 : GDALAntiRecursionGuard oGuard2(oGuard, poVRTDS->GetDescription());
1361 5515 : if (oGuard2.GetCallDepth() >= 2)
1362 : {
1363 0 : CPLError(CE_Failure, CPLE_AppDefined, "Recursion detected");
1364 0 : return 0;
1365 : }
1366 :
1367 5515 : poVRTDS->BuildVirtualOverviews();
1368 : }
1369 5627 : if (!poVRTDS->m_apoOverviews.empty() && poVRTDS->m_apoOverviews[0])
1370 67 : return static_cast<int>(poVRTDS->m_apoOverviews.size());
1371 :
1372 5560 : return 0;
1373 : }
1374 :
1375 : /************************************************************************/
1376 : /* GetOverview() */
1377 : /************************************************************************/
1378 :
1379 113 : GDALRasterBand *VRTRasterBand::GetOverview(int iOverview)
1380 :
1381 : {
1382 : // First: overviews declared in <Overview> element
1383 113 : if (!m_aoOverviewInfos.empty())
1384 : {
1385 35 : if (iOverview < 0 ||
1386 17 : iOverview >= static_cast<int>(m_aoOverviewInfos.size()))
1387 2 : return nullptr;
1388 :
1389 28 : if (m_aoOverviewInfos[iOverview].poBand == nullptr &&
1390 12 : !m_aoOverviewInfos[iOverview].bTriedToOpen)
1391 : {
1392 12 : m_aoOverviewInfos[iOverview].bTriedToOpen = TRUE;
1393 12 : CPLConfigOptionSetter oSetter("CPL_ALLOW_VSISTDIN", "NO", true);
1394 12 : GDALDataset *poSrcDS = GDALDataset::FromHandle(GDALOpenShared(
1395 12 : m_aoOverviewInfos[iOverview].osFilename, GA_ReadOnly));
1396 :
1397 12 : if (poSrcDS == nullptr)
1398 1 : return nullptr;
1399 11 : if (poSrcDS == poDS)
1400 : {
1401 1 : CPLError(CE_Failure, CPLE_AppDefined,
1402 : "Recursive opening attempt");
1403 1 : GDALClose(GDALDataset::ToHandle(poSrcDS));
1404 1 : return nullptr;
1405 : }
1406 :
1407 20 : m_aoOverviewInfos[iOverview].poBand =
1408 10 : poSrcDS->GetRasterBand(m_aoOverviewInfos[iOverview].nBand);
1409 :
1410 10 : if (m_aoOverviewInfos[iOverview].poBand == nullptr)
1411 : {
1412 1 : GDALClose(GDALDataset::ToHandle(poSrcDS));
1413 : }
1414 : }
1415 :
1416 14 : return m_aoOverviewInfos[iOverview].poBand;
1417 : }
1418 :
1419 : // If not found, external .ovr overviews
1420 95 : GDALRasterBand *poRet = GDALRasterBand::GetOverview(iOverview);
1421 95 : if (poRet)
1422 56 : return poRet;
1423 :
1424 : // If not found, implicit virtual overviews
1425 39 : VRTDataset *poVRTDS = static_cast<VRTDataset *>(poDS);
1426 39 : poVRTDS->BuildVirtualOverviews();
1427 39 : if (!poVRTDS->m_apoOverviews.empty() && poVRTDS->m_apoOverviews[0])
1428 : {
1429 69 : if (iOverview < 0 ||
1430 34 : iOverview >= static_cast<int>(poVRTDS->m_apoOverviews.size()))
1431 2 : return nullptr;
1432 :
1433 66 : auto poOvrBand = poVRTDS->m_apoOverviews[iOverview]->GetRasterBand(
1434 33 : nBand ? nBand : 1);
1435 33 : if (m_bIsMaskBand)
1436 0 : return poOvrBand->GetMaskBand();
1437 33 : return poOvrBand;
1438 : }
1439 :
1440 4 : return nullptr;
1441 : }
1442 :
1443 : /************************************************************************/
1444 : /* SetDescription() */
1445 : /************************************************************************/
1446 :
1447 3198 : void VRTRasterBand::SetDescription(const char *pszDescription)
1448 :
1449 : {
1450 3198 : static_cast<VRTDataset *>(poDS)->SetNeedsFlush();
1451 :
1452 3198 : GDALRasterBand::SetDescription(pszDescription);
1453 3198 : }
1454 :
1455 : /************************************************************************/
1456 : /* CreateMaskBand() */
1457 : /************************************************************************/
1458 :
1459 10 : CPLErr VRTRasterBand::CreateMaskBand(int nFlagsIn)
1460 : {
1461 10 : VRTDataset *poGDS = static_cast<VRTDataset *>(poDS);
1462 :
1463 10 : if (poGDS->m_poMaskBand)
1464 : {
1465 1 : CPLError(CE_Failure, CPLE_AppDefined,
1466 : "Cannot create mask band at raster band level when a dataset "
1467 : "mask band already exists.");
1468 1 : return CE_Failure;
1469 : }
1470 :
1471 9 : if (m_poMaskBand != nullptr)
1472 : {
1473 1 : CPLError(CE_Failure, CPLE_AppDefined,
1474 : "This VRT band has already a mask band");
1475 1 : return CE_Failure;
1476 : }
1477 :
1478 8 : if ((nFlagsIn & GMF_PER_DATASET) != 0)
1479 1 : return poGDS->CreateMaskBand(nFlagsIn);
1480 :
1481 7 : SetMaskBand(new VRTSourcedRasterBand(poGDS, 0));
1482 :
1483 7 : return CE_None;
1484 : }
1485 :
1486 : /************************************************************************/
1487 : /* GetMaskBand() */
1488 : /************************************************************************/
1489 :
1490 4465 : GDALRasterBand *VRTRasterBand::GetMaskBand()
1491 : {
1492 4465 : VRTDataset *poGDS = static_cast<VRTDataset *>(poDS);
1493 :
1494 4465 : if (poGDS->m_poMaskBand)
1495 139 : return poGDS->m_poMaskBand;
1496 4326 : else if (m_poMaskBand)
1497 10 : return m_poMaskBand;
1498 : else
1499 4316 : return GDALRasterBand::GetMaskBand();
1500 : }
1501 :
1502 : /************************************************************************/
1503 : /* GetMaskFlags() */
1504 : /************************************************************************/
1505 :
1506 11293 : int VRTRasterBand::GetMaskFlags()
1507 : {
1508 11293 : VRTDataset *poGDS = static_cast<VRTDataset *>(poDS);
1509 :
1510 11293 : if (poGDS->m_poMaskBand)
1511 80 : return GMF_PER_DATASET;
1512 11213 : else if (m_poMaskBand)
1513 11 : return 0;
1514 : else
1515 11202 : return GDALRasterBand::GetMaskFlags();
1516 : }
1517 :
1518 : /************************************************************************/
1519 : /* SetMaskBand() */
1520 : /************************************************************************/
1521 :
1522 8 : void VRTRasterBand::SetMaskBand(VRTRasterBand *poMaskBandIn)
1523 : {
1524 8 : delete m_poMaskBand;
1525 8 : m_poMaskBand = poMaskBandIn;
1526 8 : m_poMaskBand->SetIsMaskBand();
1527 8 : }
1528 :
1529 : /************************************************************************/
1530 : /* SetIsMaskBand() */
1531 : /************************************************************************/
1532 :
1533 81 : void VRTRasterBand::SetIsMaskBand()
1534 : {
1535 81 : nBand = 0;
1536 81 : m_bIsMaskBand = TRUE;
1537 81 : }
1538 :
1539 : /************************************************************************/
1540 : /* IsMaskBand() */
1541 : /************************************************************************/
1542 :
1543 112 : bool VRTRasterBand::IsMaskBand() const
1544 : {
1545 112 : return m_bIsMaskBand || m_eColorInterp == GCI_AlphaBand;
1546 : }
1547 :
1548 : /************************************************************************/
1549 : /* CloseDependentDatasets() */
1550 : /************************************************************************/
1551 :
1552 141350 : int VRTRasterBand::CloseDependentDatasets()
1553 : {
1554 141350 : int ret = FALSE;
1555 141366 : for (auto &oOverviewInfo : m_aoOverviewInfos)
1556 : {
1557 16 : if (oOverviewInfo.CloseDataset())
1558 : {
1559 9 : ret = TRUE;
1560 : }
1561 : }
1562 141350 : return ret;
1563 : }
1564 :
1565 : /*! @endcond */
|