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