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