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