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