Line data Source code
1 : /******************************************************************************
2 : *
3 : * Project: Virtual GDAL Datasets
4 : * Purpose: Implementation of VRTSimpleSource, VRTFuncSource and
5 : * VRTAveragedSource.
6 : * Author: Frank Warmerdam <warmerdam@pobox.com>
7 : *
8 : ******************************************************************************
9 : * Copyright (c) 2001, Frank Warmerdam <warmerdam@pobox.com>
10 : * Copyright (c) 2008-2013, Even Rouault <even dot rouault at spatialys.com>
11 : *
12 : * SPDX-License-Identifier: MIT
13 : ****************************************************************************/
14 :
15 : #include "gdal_vrt.h"
16 : #include "vrtdataset.h"
17 :
18 : #include <cassert>
19 : #include <climits>
20 : #include <cmath>
21 : #include <cstddef>
22 : #include <cstdio>
23 : #include <cstdlib>
24 : #include <cstring>
25 : #include <algorithm>
26 : #include <limits>
27 : #include <string>
28 :
29 : #include "cpl_conv.h"
30 : #include "cpl_error.h"
31 : #include "cpl_hash_set.h"
32 : #include "cpl_minixml.h"
33 : #include "cpl_progress.h"
34 : #include "cpl_string.h"
35 : #include "cpl_vsi.h"
36 : #include "gdal.h"
37 : #include "gdal_priv.h"
38 : #include "gdal_proxy.h"
39 : #include "gdal_priv_templates.hpp"
40 :
41 : /*! @cond Doxygen_Suppress */
42 :
43 : // #define DEBUG_VERBOSE 1
44 :
45 : // See #5459
46 : #ifdef isnan
47 : #define HAS_ISNAN_MACRO
48 : #endif
49 : #include <algorithm>
50 : #if defined(HAS_ISNAN_MACRO) && !defined(isnan)
51 : #define isnan std::isnan
52 : #endif
53 :
54 : /************************************************************************/
55 : /* ==================================================================== */
56 : /* VRTSource */
57 : /* ==================================================================== */
58 : /************************************************************************/
59 :
60 13194 : VRTSource::~VRTSource()
61 : {
62 13194 : }
63 :
64 : /************************************************************************/
65 : /* GetFileList() */
66 : /************************************************************************/
67 :
68 0 : void VRTSource::GetFileList(char *** /* ppapszFileList */, int * /* pnSize */,
69 : int * /* pnMaxSize */, CPLHashSet * /* hSetFiles */)
70 : {
71 0 : }
72 :
73 : /************************************************************************/
74 : /* ==================================================================== */
75 : /* VRTSimpleSource */
76 : /* ==================================================================== */
77 : /************************************************************************/
78 :
79 : /************************************************************************/
80 : /* VRTSimpleSource() */
81 : /************************************************************************/
82 :
83 : VRTSimpleSource::VRTSimpleSource() = default;
84 :
85 : /************************************************************************/
86 : /* VRTSimpleSource() */
87 : /************************************************************************/
88 :
89 76 : VRTSimpleSource::VRTSimpleSource(const VRTSimpleSource *poSrcSource,
90 76 : double dfXDstRatio, double dfYDstRatio)
91 76 : : m_poMapSharedSources(poSrcSource->m_poMapSharedSources),
92 76 : m_poRasterBand(poSrcSource->m_poRasterBand),
93 76 : m_poMaskBandMainBand(poSrcSource->m_poMaskBandMainBand),
94 76 : m_aosOpenOptionsOri(poSrcSource->m_aosOpenOptionsOri),
95 76 : m_aosOpenOptions(poSrcSource->m_aosOpenOptions),
96 76 : m_bSrcDSNameFromVRT(poSrcSource->m_bSrcDSNameFromVRT),
97 76 : m_nBand(poSrcSource->m_nBand),
98 76 : m_bGetMaskBand(poSrcSource->m_bGetMaskBand),
99 76 : m_dfSrcXOff(poSrcSource->m_dfSrcXOff),
100 76 : m_dfSrcYOff(poSrcSource->m_dfSrcYOff),
101 76 : m_dfSrcXSize(poSrcSource->m_dfSrcXSize),
102 76 : m_dfSrcYSize(poSrcSource->m_dfSrcYSize),
103 76 : m_nMaxValue(poSrcSource->m_nMaxValue), m_bRelativeToVRTOri(-1),
104 76 : m_nExplicitSharedStatus(poSrcSource->m_nExplicitSharedStatus),
105 76 : m_osSrcDSName(poSrcSource->m_osSrcDSName),
106 76 : m_bDropRefOnSrcBand(poSrcSource->m_bDropRefOnSrcBand)
107 : {
108 76 : if (!poSrcSource->IsSrcWinSet() && !poSrcSource->IsDstWinSet() &&
109 0 : (dfXDstRatio != 1.0 || dfYDstRatio != 1.0))
110 : {
111 1 : auto l_band = GetRasterBand();
112 1 : if (l_band)
113 : {
114 1 : m_dfSrcXOff = 0;
115 1 : m_dfSrcYOff = 0;
116 1 : m_dfSrcXSize = l_band->GetXSize();
117 1 : m_dfSrcYSize = l_band->GetYSize();
118 1 : m_dfDstXOff = 0;
119 1 : m_dfDstYOff = 0;
120 1 : m_dfDstXSize = l_band->GetXSize() * dfXDstRatio;
121 1 : m_dfDstYSize = l_band->GetYSize() * dfYDstRatio;
122 : }
123 : }
124 75 : else if (poSrcSource->IsDstWinSet())
125 : {
126 75 : m_dfDstXOff = poSrcSource->m_dfDstXOff * dfXDstRatio;
127 75 : m_dfDstYOff = poSrcSource->m_dfDstYOff * dfYDstRatio;
128 75 : m_dfDstXSize = poSrcSource->m_dfDstXSize * dfXDstRatio;
129 75 : m_dfDstYSize = poSrcSource->m_dfDstYSize * dfYDstRatio;
130 : }
131 76 : }
132 :
133 : /************************************************************************/
134 : /* ~VRTSimpleSource() */
135 : /************************************************************************/
136 :
137 27716 : VRTSimpleSource::~VRTSimpleSource()
138 :
139 : {
140 13151 : if (!m_bDropRefOnSrcBand)
141 396 : return;
142 :
143 12755 : if (m_poMaskBandMainBand != nullptr)
144 : {
145 43 : if (m_poMaskBandMainBand->GetDataset() != nullptr)
146 : {
147 43 : m_poMaskBandMainBand->GetDataset()->ReleaseRef();
148 : }
149 : }
150 22882 : else if (m_poRasterBand != nullptr &&
151 10170 : m_poRasterBand->GetDataset() != nullptr)
152 : {
153 10170 : m_poRasterBand->GetDataset()->ReleaseRef();
154 : }
155 25736 : }
156 :
157 : /************************************************************************/
158 : /* GetTypeStatic() */
159 : /************************************************************************/
160 :
161 29214 : const char *VRTSimpleSource::GetTypeStatic()
162 : {
163 : static const char *TYPE = "SimpleSource";
164 29214 : return TYPE;
165 : }
166 :
167 : /************************************************************************/
168 : /* GetType() */
169 : /************************************************************************/
170 :
171 10128 : const char *VRTSimpleSource::GetType() const
172 : {
173 10128 : return GetTypeStatic();
174 : }
175 :
176 : /************************************************************************/
177 : /* FlushCache() */
178 : /************************************************************************/
179 :
180 13218 : CPLErr VRTSimpleSource::FlushCache(bool bAtClosing)
181 :
182 : {
183 13218 : if (m_poMaskBandMainBand != nullptr)
184 : {
185 5 : return m_poMaskBandMainBand->FlushCache(bAtClosing);
186 : }
187 13213 : else if (m_poRasterBand != nullptr)
188 : {
189 10660 : return m_poRasterBand->FlushCache(bAtClosing);
190 : }
191 2553 : return CE_None;
192 : }
193 :
194 : /************************************************************************/
195 : /* UnsetPreservedRelativeFilenames() */
196 : /************************************************************************/
197 :
198 5 : void VRTSimpleSource::UnsetPreservedRelativeFilenames()
199 : {
200 9 : if (!STARTS_WITH(m_osSourceFileNameOri.c_str(), "http://") &&
201 4 : !STARTS_WITH(m_osSourceFileNameOri.c_str(), "https://"))
202 : {
203 4 : m_bRelativeToVRTOri = -1;
204 4 : m_osSourceFileNameOri = "";
205 : }
206 5 : }
207 :
208 : /************************************************************************/
209 : /* SetSrcBand() */
210 : /************************************************************************/
211 :
212 446 : void VRTSimpleSource::SetSrcBand(const char *pszFilename, int nBand)
213 :
214 : {
215 446 : m_nBand = nBand;
216 446 : m_osSrcDSName = pszFilename;
217 446 : }
218 :
219 : /************************************************************************/
220 : /* SetSrcBand() */
221 : /************************************************************************/
222 :
223 9198 : void VRTSimpleSource::SetSrcBand(GDALRasterBand *poNewSrcBand)
224 :
225 : {
226 9198 : m_poRasterBand = poNewSrcBand;
227 9198 : m_nBand = m_poRasterBand->GetBand();
228 9198 : auto poDS = poNewSrcBand->GetDataset();
229 9198 : if (poDS != nullptr)
230 : {
231 9198 : m_osSrcDSName = poDS->GetDescription();
232 9198 : m_aosOpenOptions = CSLDuplicate(poDS->GetOpenOptions());
233 9198 : m_aosOpenOptionsOri = m_aosOpenOptions;
234 : }
235 9198 : }
236 :
237 : /************************************************************************/
238 : /* SetSrcMaskBand() */
239 : /************************************************************************/
240 :
241 : // poSrcBand is not the mask band, but the band from which the mask band is
242 : // taken.
243 28 : void VRTSimpleSource::SetSrcMaskBand(GDALRasterBand *poNewSrcBand)
244 :
245 : {
246 28 : m_poRasterBand = poNewSrcBand->GetMaskBand();
247 28 : m_poMaskBandMainBand = poNewSrcBand;
248 28 : m_nBand = poNewSrcBand->GetBand();
249 28 : auto poDS = poNewSrcBand->GetDataset();
250 28 : if (poDS != nullptr)
251 : {
252 28 : m_osSrcDSName = poDS->GetDescription();
253 28 : m_aosOpenOptions = CSLDuplicate(poDS->GetOpenOptions());
254 28 : m_aosOpenOptionsOri = m_aosOpenOptions;
255 : }
256 28 : m_bGetMaskBand = true;
257 28 : }
258 :
259 : /************************************************************************/
260 : /* RoundIfCloseToInt() */
261 : /************************************************************************/
262 :
263 297273 : static double RoundIfCloseToInt(double dfValue)
264 : {
265 297273 : double dfClosestInt = floor(dfValue + 0.5);
266 297273 : return (fabs(dfValue - dfClosestInt) < 1e-3) ? dfClosestInt : dfValue;
267 : }
268 :
269 : /************************************************************************/
270 : /* SetSrcWindow() */
271 : /************************************************************************/
272 :
273 12553 : void VRTSimpleSource::SetSrcWindow(double dfNewXOff, double dfNewYOff,
274 : double dfNewXSize, double dfNewYSize)
275 :
276 : {
277 12553 : m_dfSrcXOff = RoundIfCloseToInt(dfNewXOff);
278 12553 : m_dfSrcYOff = RoundIfCloseToInt(dfNewYOff);
279 12553 : m_dfSrcXSize = RoundIfCloseToInt(dfNewXSize);
280 12553 : m_dfSrcYSize = RoundIfCloseToInt(dfNewYSize);
281 12553 : }
282 :
283 : /************************************************************************/
284 : /* SetDstWindow() */
285 : /************************************************************************/
286 :
287 12552 : void VRTSimpleSource::SetDstWindow(double dfNewXOff, double dfNewYOff,
288 : double dfNewXSize, double dfNewYSize)
289 :
290 : {
291 12552 : m_dfDstXOff = RoundIfCloseToInt(dfNewXOff);
292 12552 : m_dfDstYOff = RoundIfCloseToInt(dfNewYOff);
293 12552 : m_dfDstXSize = RoundIfCloseToInt(dfNewXSize);
294 12552 : m_dfDstYSize = RoundIfCloseToInt(dfNewYSize);
295 12552 : }
296 :
297 : /************************************************************************/
298 : /* GetDstWindow() */
299 : /************************************************************************/
300 :
301 517 : void VRTSimpleSource::GetDstWindow(double &dfDstXOff, double &dfDstYOff,
302 : double &dfDstXSize, double &dfDstYSize) const
303 : {
304 517 : dfDstXOff = m_dfDstXOff;
305 517 : dfDstYOff = m_dfDstYOff;
306 517 : dfDstXSize = m_dfDstXSize;
307 517 : dfDstYSize = m_dfDstYSize;
308 517 : }
309 :
310 : /************************************************************************/
311 : /* DstWindowIntersects() */
312 : /************************************************************************/
313 :
314 1073 : bool VRTSimpleSource::DstWindowIntersects(double dfXOff, double dfYOff,
315 : double dfXSize, double dfYSize) const
316 : {
317 2137 : return IsDstWinSet() && m_dfDstXOff + m_dfDstXSize > dfXOff &&
318 1064 : m_dfDstYOff + m_dfDstYSize > dfYOff &&
319 2137 : m_dfDstXOff < dfXOff + dfXSize && m_dfDstYOff < dfYOff + dfYSize;
320 : }
321 :
322 : /************************************************************************/
323 : /* IsSlowSource() */
324 : /************************************************************************/
325 :
326 2480 : static bool IsSlowSource(const char *pszSrcName)
327 : {
328 4960 : return strstr(pszSrcName, "/vsicurl/http") != nullptr ||
329 4960 : strstr(pszSrcName, "/vsicurl/ftp") != nullptr ||
330 2480 : (strstr(pszSrcName, "/vsicurl?") != nullptr &&
331 2480 : strstr(pszSrcName, "&url=http") != nullptr);
332 : }
333 :
334 : /************************************************************************/
335 : /* AddSourceFilenameNode() */
336 : /************************************************************************/
337 :
338 2512 : void VRTSimpleSource::AddSourceFilenameNode(const char *pszVRTPath,
339 : CPLXMLNode *psSrc)
340 : {
341 :
342 : VSIStatBufL sStat;
343 2512 : int bRelativeToVRT = FALSE; // TODO(schwehr): Make this a bool?
344 5024 : std::string osSourceFilename;
345 :
346 2512 : if (m_bRelativeToVRTOri >= 0)
347 : {
348 32 : osSourceFilename = m_osSourceFileNameOri;
349 32 : bRelativeToVRT = m_bRelativeToVRTOri;
350 : }
351 2480 : else if (IsSlowSource(m_osSrcDSName))
352 : {
353 : // Testing the existence of remote resources can be excruciating
354 : // slow, so let's just suppose they exist.
355 0 : osSourceFilename = m_osSrcDSName;
356 0 : bRelativeToVRT = FALSE;
357 : }
358 : // If this isn't actually a file, don't even try to know if it is a
359 : // relative path. It can't be !, and unfortunately CPLIsFilenameRelative()
360 : // can only work with strings that are filenames To be clear
361 : // NITF_TOC_ENTRY:CADRG_JOG-A_250K_1_0:some_path isn't a relative file
362 : // path.
363 2480 : else if (VSIStatExL(m_osSrcDSName, &sStat, VSI_STAT_EXISTS_FLAG) != 0)
364 : {
365 58 : osSourceFilename = m_osSrcDSName;
366 58 : bRelativeToVRT = FALSE;
367 :
368 : // Try subdatasetinfo API first
369 : // Note: this will become the only branch when subdatasetinfo will become
370 : // available for NITF_IM, RASTERLITE and TILEDB
371 58 : const auto oSubDSInfo{GDALGetSubdatasetInfo(osSourceFilename.c_str())};
372 58 : if (oSubDSInfo && !oSubDSInfo->GetPathComponent().empty())
373 : {
374 10 : auto path{oSubDSInfo->GetPathComponent()};
375 : std::string relPath{CPLExtractRelativePath(pszVRTPath, path.c_str(),
376 10 : &bRelativeToVRT)};
377 5 : osSourceFilename = oSubDSInfo->ModifyPathComponent(relPath);
378 5 : GDALDestroySubdatasetInfo(oSubDSInfo);
379 : }
380 : else
381 : {
382 303 : for (const char *pszSyntax : VRTDataset::apszSpecialSyntax)
383 : {
384 253 : CPLString osPrefix(pszSyntax);
385 253 : osPrefix.resize(strchr(pszSyntax, ':') - pszSyntax + 1);
386 253 : if (pszSyntax[osPrefix.size()] == '"')
387 50 : osPrefix += '"';
388 253 : if (EQUALN(osSourceFilename.c_str(), osPrefix, osPrefix.size()))
389 : {
390 3 : if (STARTS_WITH_CI(pszSyntax + osPrefix.size(), "{ANY}"))
391 : {
392 : const char *pszLastPart =
393 3 : strrchr(osSourceFilename.c_str(), ':') + 1;
394 : // CSV:z:/foo.xyz
395 1 : if ((pszLastPart[0] == '/' || pszLastPart[0] == '\\') &&
396 6 : pszLastPart - osSourceFilename.c_str() >= 3 &&
397 2 : pszLastPart[-3] == ':')
398 0 : pszLastPart -= 2;
399 3 : CPLString osPrefixFilename(osSourceFilename);
400 3 : osPrefixFilename.resize(pszLastPart -
401 3 : osSourceFilename.c_str());
402 : osSourceFilename = CPLExtractRelativePath(
403 3 : pszVRTPath, pszLastPart, &bRelativeToVRT);
404 3 : osSourceFilename = osPrefixFilename + osSourceFilename;
405 : }
406 0 : else if (STARTS_WITH_CI(pszSyntax + osPrefix.size(),
407 : "{FILENAME}"))
408 : {
409 0 : CPLString osFilename(osSourceFilename.c_str() +
410 0 : osPrefix.size());
411 0 : size_t nPos = 0;
412 0 : if (osFilename.size() >= 3 && osFilename[1] == ':' &&
413 0 : (osFilename[2] == '\\' || osFilename[2] == '/'))
414 0 : nPos = 2;
415 0 : nPos = osFilename.find(
416 0 : pszSyntax[osPrefix.size() + strlen("{FILENAME}")],
417 : nPos);
418 0 : if (nPos != std::string::npos)
419 : {
420 0 : const CPLString osSuffix = osFilename.substr(nPos);
421 0 : osFilename.resize(nPos);
422 : osSourceFilename = CPLExtractRelativePath(
423 0 : pszVRTPath, osFilename, &bRelativeToVRT);
424 : osSourceFilename =
425 0 : osPrefix + osSourceFilename + osSuffix;
426 : }
427 : }
428 3 : break;
429 : }
430 : }
431 : }
432 : }
433 : else
434 : {
435 4844 : std::string osVRTFilename = pszVRTPath;
436 4844 : std::string osSourceDataset = m_osSrcDSName;
437 2422 : char *pszCurDir = CPLGetCurrentDir();
438 2422 : if (CPLIsFilenameRelative(osSourceDataset.c_str()) &&
439 2422 : !CPLIsFilenameRelative(osVRTFilename.c_str()) &&
440 : pszCurDir != nullptr)
441 : {
442 : osSourceDataset =
443 62 : CPLFormFilename(pszCurDir, osSourceDataset.c_str(), nullptr);
444 : }
445 2360 : else if (!CPLIsFilenameRelative(osSourceDataset.c_str()) &&
446 2360 : CPLIsFilenameRelative(osVRTFilename.c_str()) &&
447 : pszCurDir != nullptr)
448 : {
449 : osVRTFilename =
450 94 : CPLFormFilename(pszCurDir, osVRTFilename.c_str(), nullptr);
451 : }
452 2422 : CPLFree(pszCurDir);
453 : osSourceFilename = CPLExtractRelativePath(
454 2422 : osVRTFilename.c_str(), osSourceDataset.c_str(), &bRelativeToVRT);
455 : }
456 :
457 2512 : CPLSetXMLValue(psSrc, "SourceFilename", osSourceFilename.c_str());
458 :
459 2512 : CPLCreateXMLNode(CPLCreateXMLNode(CPLGetXMLNode(psSrc, "SourceFilename"),
460 : CXT_Attribute, "relativeToVRT"),
461 2512 : CXT_Text, bRelativeToVRT ? "1" : "0");
462 :
463 : // Determine if we must write the shared attribute. The config option
464 : // will override the m_nExplicitSharedStatus value
465 2512 : const char *pszShared = CPLGetConfigOption("VRT_SHARED_SOURCE", nullptr);
466 2512 : if ((pszShared == nullptr && m_nExplicitSharedStatus == 0) ||
467 0 : (pszShared != nullptr && !CPLTestBool(pszShared)))
468 : {
469 0 : CPLCreateXMLNode(
470 : CPLCreateXMLNode(CPLGetXMLNode(psSrc, "SourceFilename"),
471 : CXT_Attribute, "shared"),
472 : CXT_Text, "0");
473 : }
474 2512 : }
475 :
476 : /************************************************************************/
477 : /* SerializeToXML() */
478 : /************************************************************************/
479 :
480 2513 : CPLXMLNode *VRTSimpleSource::SerializeToXML(const char *pszVRTPath)
481 :
482 : {
483 : CPLXMLNode *const psSrc =
484 2513 : CPLCreateXMLNode(nullptr, CXT_Element, GetTypeStatic());
485 :
486 2513 : if (!m_osResampling.empty())
487 : {
488 8 : CPLCreateXMLNode(CPLCreateXMLNode(psSrc, CXT_Attribute, "resampling"),
489 : CXT_Text, m_osResampling.c_str());
490 : }
491 :
492 2513 : if (m_bSrcDSNameFromVRT)
493 : {
494 1 : CPLAddXMLChild(psSrc, CPLParseXMLString(m_osSrcDSName.c_str()));
495 : }
496 : else
497 : {
498 2512 : AddSourceFilenameNode(pszVRTPath, psSrc);
499 : }
500 :
501 2513 : GDALSerializeOpenOptionsToXML(psSrc, m_aosOpenOptionsOri.List());
502 :
503 2513 : if (m_bGetMaskBand)
504 14 : CPLSetXMLValue(psSrc, "SourceBand", CPLSPrintf("mask,%d", m_nBand));
505 : else
506 2499 : CPLSetXMLValue(psSrc, "SourceBand", CPLSPrintf("%d", m_nBand));
507 :
508 : // TODO: in a later version, no longer emit SourceProperties, which
509 : // is no longer used by GDAL 3.4
510 2513 : if (m_poRasterBand)
511 : {
512 : /* Write a few additional useful properties of the dataset */
513 : /* so that we can use a proxy dataset when re-opening. See XMLInit() */
514 : /* below */
515 2405 : CPLSetXMLValue(psSrc, "SourceProperties.#RasterXSize",
516 2405 : CPLSPrintf("%d", m_poRasterBand->GetXSize()));
517 2405 : CPLSetXMLValue(psSrc, "SourceProperties.#RasterYSize",
518 2405 : CPLSPrintf("%d", m_poRasterBand->GetYSize()));
519 2405 : CPLSetXMLValue(
520 : psSrc, "SourceProperties.#DataType",
521 2405 : GDALGetDataTypeName(m_poRasterBand->GetRasterDataType()));
522 :
523 2405 : int nBlockXSize = 0;
524 2405 : int nBlockYSize = 0;
525 2405 : m_poRasterBand->GetBlockSize(&nBlockXSize, &nBlockYSize);
526 :
527 2405 : CPLSetXMLValue(psSrc, "SourceProperties.#BlockXSize",
528 : CPLSPrintf("%d", nBlockXSize));
529 2405 : CPLSetXMLValue(psSrc, "SourceProperties.#BlockYSize",
530 : CPLSPrintf("%d", nBlockYSize));
531 : }
532 :
533 2513 : if (IsSrcWinSet())
534 : {
535 2500 : CPLSetXMLValue(psSrc, "SrcRect.#xOff",
536 : CPLSPrintf("%.15g", m_dfSrcXOff));
537 2500 : CPLSetXMLValue(psSrc, "SrcRect.#yOff",
538 : CPLSPrintf("%.15g", m_dfSrcYOff));
539 2500 : CPLSetXMLValue(psSrc, "SrcRect.#xSize",
540 : CPLSPrintf("%.15g", m_dfSrcXSize));
541 2500 : CPLSetXMLValue(psSrc, "SrcRect.#ySize",
542 : CPLSPrintf("%.15g", m_dfSrcYSize));
543 : }
544 :
545 2513 : if (IsDstWinSet())
546 : {
547 2500 : CPLSetXMLValue(psSrc, "DstRect.#xOff",
548 : CPLSPrintf("%.15g", m_dfDstXOff));
549 2500 : CPLSetXMLValue(psSrc, "DstRect.#yOff",
550 : CPLSPrintf("%.15g", m_dfDstYOff));
551 2500 : CPLSetXMLValue(psSrc, "DstRect.#xSize",
552 : CPLSPrintf("%.15g", m_dfDstXSize));
553 2500 : CPLSetXMLValue(psSrc, "DstRect.#ySize",
554 : CPLSPrintf("%.15g", m_dfDstYSize));
555 : }
556 :
557 2513 : return psSrc;
558 : }
559 :
560 : /************************************************************************/
561 : /* XMLInit() */
562 : /************************************************************************/
563 :
564 3057 : CPLErr VRTSimpleSource::XMLInit(const CPLXMLNode *psSrc, const char *pszVRTPath,
565 : VRTMapSharedResources &oMapSharedSources)
566 :
567 : {
568 3057 : m_poMapSharedSources = &oMapSharedSources;
569 :
570 3057 : m_osResampling = CPLGetXMLValue(psSrc, "resampling", "");
571 :
572 : /* -------------------------------------------------------------------- */
573 : /* Prepare filename. */
574 : /* -------------------------------------------------------------------- */
575 : const CPLXMLNode *psSourceFileNameNode =
576 3057 : CPLGetXMLNode(psSrc, "SourceFilename");
577 3057 : const CPLXMLNode *psSourceVRTDataset = CPLGetXMLNode(psSrc, "VRTDataset");
578 : const char *pszFilename =
579 3057 : psSourceFileNameNode ? CPLGetXMLValue(psSourceFileNameNode, nullptr, "")
580 3057 : : "";
581 :
582 3057 : if (pszFilename[0] == '\0' && !psSourceVRTDataset)
583 : {
584 1 : CPLError(CE_Warning, CPLE_AppDefined,
585 : "Missing <SourceFilename> or <VRTDataset> element in <%s>.",
586 1 : psSrc->pszValue);
587 1 : return CE_Failure;
588 : }
589 :
590 : // Backup original filename and relativeToVRT so as to be able to
591 : // serialize them identically again (#5985)
592 3056 : m_osSourceFileNameOri = pszFilename;
593 3056 : if (pszFilename[0])
594 : {
595 3053 : m_bRelativeToVRTOri =
596 3053 : atoi(CPLGetXMLValue(psSourceFileNameNode, "relativetoVRT", "0"));
597 : const char *pszShared =
598 3053 : CPLGetXMLValue(psSourceFileNameNode, "shared", nullptr);
599 3053 : if (pszShared == nullptr)
600 : {
601 3051 : pszShared = CPLGetConfigOption("VRT_SHARED_SOURCE", nullptr);
602 : }
603 3053 : if (pszShared != nullptr)
604 : {
605 8 : m_nExplicitSharedStatus = CPLTestBool(pszShared);
606 : }
607 :
608 6106 : m_osSrcDSName = VRTDataset::BuildSourceFilename(
609 6106 : pszFilename, pszVRTPath, CPL_TO_BOOL(m_bRelativeToVRTOri));
610 : }
611 3 : else if (psSourceVRTDataset)
612 : {
613 : CPLXMLNode sNode;
614 3 : sNode.eType = psSourceVRTDataset->eType;
615 3 : sNode.pszValue = psSourceVRTDataset->pszValue;
616 3 : sNode.psNext = nullptr;
617 3 : sNode.psChild = psSourceVRTDataset->psChild;
618 3 : char *pszXML = CPLSerializeXMLTree(&sNode);
619 3 : if (pszXML)
620 : {
621 3 : m_bSrcDSNameFromVRT = true;
622 3 : m_osSrcDSName = pszXML;
623 3 : CPLFree(pszXML);
624 : }
625 : }
626 :
627 3056 : const char *pszSourceBand = CPLGetXMLValue(psSrc, "SourceBand", "1");
628 3056 : m_bGetMaskBand = false;
629 3056 : if (STARTS_WITH_CI(pszSourceBand, "mask"))
630 : {
631 18 : m_bGetMaskBand = true;
632 18 : if (pszSourceBand[4] == ',')
633 18 : m_nBand = atoi(pszSourceBand + 5);
634 : else
635 0 : m_nBand = 1;
636 : }
637 : else
638 : {
639 3038 : m_nBand = atoi(pszSourceBand);
640 : }
641 3056 : if (!GDALCheckBandCount(m_nBand, 0))
642 : {
643 0 : CPLError(CE_Warning, CPLE_AppDefined,
644 : "Invalid <SourceBand> element in VRTRasterBand.");
645 0 : return CE_Failure;
646 : }
647 :
648 3056 : m_aosOpenOptions = GDALDeserializeOpenOptionsFromXML(psSrc);
649 3056 : m_aosOpenOptionsOri = m_aosOpenOptions;
650 3056 : if (strstr(m_osSrcDSName.c_str(), "<VRTDataset") != nullptr)
651 5 : m_aosOpenOptions.SetNameValue("ROOT_PATH", pszVRTPath);
652 :
653 3056 : return ParseSrcRectAndDstRect(psSrc);
654 : }
655 :
656 : /************************************************************************/
657 : /* ParseSrcRectAndDstRect() */
658 : /************************************************************************/
659 :
660 3069 : CPLErr VRTSimpleSource::ParseSrcRectAndDstRect(const CPLXMLNode *psSrc)
661 : {
662 23060 : const auto GetAttrValue = [](const CPLXMLNode *psNode,
663 : const char *pszAttrName, double dfDefaultVal)
664 : {
665 23060 : if (const char *pszVal = CPLGetXMLValue(psNode, pszAttrName, nullptr))
666 23060 : return CPLAtof(pszVal);
667 : else
668 0 : return dfDefaultVal;
669 : };
670 :
671 : /* -------------------------------------------------------------------- */
672 : /* Set characteristics. */
673 : /* -------------------------------------------------------------------- */
674 3069 : const CPLXMLNode *const psSrcRect = CPLGetXMLNode(psSrc, "SrcRect");
675 3069 : if (psSrcRect)
676 : {
677 2883 : double xOff = GetAttrValue(psSrcRect, "xOff", UNINIT_WINDOW);
678 2883 : double yOff = GetAttrValue(psSrcRect, "yOff", UNINIT_WINDOW);
679 2883 : double xSize = GetAttrValue(psSrcRect, "xSize", UNINIT_WINDOW);
680 2883 : double ySize = GetAttrValue(psSrcRect, "ySize", UNINIT_WINDOW);
681 : // Test written that way to catch NaN values
682 2883 : if (!(xOff >= INT_MIN && xOff <= INT_MAX) ||
683 2883 : !(yOff >= INT_MIN && yOff <= INT_MAX) ||
684 2883 : !(xSize > 0 || xSize == UNINIT_WINDOW) || xSize > INT_MAX ||
685 2882 : !(ySize > 0 || ySize == UNINIT_WINDOW) || ySize > INT_MAX)
686 : {
687 1 : CPLError(CE_Failure, CPLE_AppDefined, "Wrong values in SrcRect");
688 1 : return CE_Failure;
689 : }
690 2882 : SetSrcWindow(xOff, yOff, xSize, ySize);
691 : }
692 : else
693 : {
694 186 : m_dfSrcXOff = UNINIT_WINDOW;
695 186 : m_dfSrcYOff = UNINIT_WINDOW;
696 186 : m_dfSrcXSize = UNINIT_WINDOW;
697 186 : m_dfSrcYSize = UNINIT_WINDOW;
698 : }
699 :
700 3068 : const CPLXMLNode *const psDstRect = CPLGetXMLNode(psSrc, "DstRect");
701 3068 : if (psDstRect)
702 : {
703 2882 : double xOff = GetAttrValue(psDstRect, "xOff", UNINIT_WINDOW);
704 : ;
705 2882 : double yOff = GetAttrValue(psDstRect, "yOff", UNINIT_WINDOW);
706 2882 : double xSize = GetAttrValue(psDstRect, "xSize", UNINIT_WINDOW);
707 : ;
708 2882 : double ySize = GetAttrValue(psDstRect, "ySize", UNINIT_WINDOW);
709 : // Test written that way to catch NaN values
710 2882 : if (!(xOff >= INT_MIN && xOff <= INT_MAX) ||
711 2882 : !(yOff >= INT_MIN && yOff <= INT_MAX) ||
712 2882 : !(xSize > 0 || xSize == UNINIT_WINDOW) || xSize > INT_MAX ||
713 2882 : !(ySize > 0 || ySize == UNINIT_WINDOW) || ySize > INT_MAX)
714 : {
715 1 : CPLError(CE_Failure, CPLE_AppDefined, "Wrong values in DstRect");
716 1 : return CE_Failure;
717 : }
718 2881 : SetDstWindow(xOff, yOff, xSize, ySize);
719 : }
720 : else
721 : {
722 186 : m_dfDstXOff = UNINIT_WINDOW;
723 186 : m_dfDstYOff = UNINIT_WINDOW;
724 186 : m_dfDstXSize = UNINIT_WINDOW;
725 186 : m_dfDstYSize = UNINIT_WINDOW;
726 : }
727 :
728 3067 : return CE_None;
729 : }
730 :
731 : /************************************************************************/
732 : /* GetFileList() */
733 : /************************************************************************/
734 :
735 112 : void VRTSimpleSource::GetFileList(char ***ppapszFileList, int *pnSize,
736 : int *pnMaxSize, CPLHashSet *hSetFiles)
737 : {
738 112 : if (!m_osSrcDSName.empty() && !m_bSrcDSNameFromVRT)
739 : {
740 112 : const char *pszFilename = m_osSrcDSName.c_str();
741 :
742 : /* --------------------------------------------------------------------
743 : */
744 : /* Is it already in the list ? */
745 : /* --------------------------------------------------------------------
746 : */
747 112 : if (CPLHashSetLookup(hSetFiles, pszFilename) != nullptr)
748 15 : return;
749 :
750 : /* --------------------------------------------------------------------
751 : */
752 : /* Grow array if necessary */
753 : /* --------------------------------------------------------------------
754 : */
755 97 : if (*pnSize + 1 >= *pnMaxSize)
756 : {
757 66 : *pnMaxSize = std::max(*pnSize + 2, 2 + 2 * (*pnMaxSize));
758 66 : *ppapszFileList = static_cast<char **>(
759 66 : CPLRealloc(*ppapszFileList, sizeof(char *) * (*pnMaxSize)));
760 : }
761 :
762 : /* --------------------------------------------------------------------
763 : */
764 : /* Add the string to the list */
765 : /* --------------------------------------------------------------------
766 : */
767 97 : (*ppapszFileList)[*pnSize] = CPLStrdup(pszFilename);
768 97 : (*ppapszFileList)[(*pnSize + 1)] = nullptr;
769 97 : CPLHashSetInsert(hSetFiles, (*ppapszFileList)[*pnSize]);
770 :
771 97 : (*pnSize)++;
772 : }
773 : }
774 :
775 : /************************************************************************/
776 : /* OpenSource() */
777 : /************************************************************************/
778 :
779 1187 : void VRTSimpleSource::OpenSource() const
780 : {
781 1187 : CPLAssert(m_poRasterBand == nullptr);
782 :
783 : /* ----------------------------------------------------------------- */
784 : /* Create a proxy dataset */
785 : /* ----------------------------------------------------------------- */
786 1187 : GDALProxyPoolDataset *proxyDS = nullptr;
787 1187 : std::string osKeyMapSharedSources;
788 1186 : if (m_poMapSharedSources)
789 : {
790 1139 : osKeyMapSharedSources = m_osSrcDSName;
791 1149 : for (int i = 0; i < m_aosOpenOptions.size(); ++i)
792 : {
793 9 : osKeyMapSharedSources += "||";
794 9 : osKeyMapSharedSources += m_aosOpenOptions[i];
795 : }
796 :
797 1140 : proxyDS = cpl::down_cast<GDALProxyPoolDataset *>(
798 1139 : m_poMapSharedSources->Get(osKeyMapSharedSources));
799 : }
800 :
801 1187 : if (proxyDS == nullptr)
802 : {
803 1024 : int bShared = true;
804 1024 : if (m_nExplicitSharedStatus != -1)
805 8 : bShared = m_nExplicitSharedStatus;
806 :
807 1024 : const CPLString osUniqueHandle(CPLSPrintf("%p", m_poMapSharedSources));
808 1024 : proxyDS = GDALProxyPoolDataset::Create(
809 : m_osSrcDSName, m_aosOpenOptions.List(), GA_ReadOnly, bShared,
810 : osUniqueHandle.c_str());
811 1024 : if (proxyDS == nullptr)
812 213 : return;
813 : }
814 : else
815 : {
816 163 : proxyDS->Reference();
817 : }
818 :
819 974 : if (m_bGetMaskBand)
820 : {
821 : GDALProxyPoolRasterBand *poMaskBand =
822 11 : cpl::down_cast<GDALProxyPoolRasterBand *>(
823 11 : proxyDS->GetRasterBand(m_nBand));
824 11 : poMaskBand->AddSrcMaskBandDescriptionFromUnderlying();
825 : }
826 :
827 : /* -------------------------------------------------------------------- */
828 : /* Get the raster band. */
829 : /* -------------------------------------------------------------------- */
830 :
831 974 : m_poRasterBand = proxyDS->GetRasterBand(m_nBand);
832 974 : if (m_poRasterBand == nullptr || !ValidateOpenedBand(m_poRasterBand))
833 : {
834 2 : proxyDS->ReleaseRef();
835 2 : return;
836 : }
837 :
838 971 : if (m_bGetMaskBand)
839 : {
840 11 : m_poRasterBand = m_poRasterBand->GetMaskBand();
841 11 : if (m_poRasterBand == nullptr)
842 : {
843 0 : proxyDS->ReleaseRef();
844 0 : return;
845 : }
846 11 : m_poMaskBandMainBand = m_poRasterBand;
847 : }
848 :
849 971 : if (m_poMapSharedSources)
850 : {
851 925 : m_poMapSharedSources->Insert(osKeyMapSharedSources, proxyDS);
852 : }
853 : }
854 :
855 : /************************************************************************/
856 : /* GetRasterBand() */
857 : /************************************************************************/
858 :
859 104590 : GDALRasterBand *VRTSimpleSource::GetRasterBand() const
860 : {
861 104590 : if (m_poRasterBand == nullptr)
862 1185 : OpenSource();
863 104591 : return m_poRasterBand;
864 : }
865 :
866 : /************************************************************************/
867 : /* GetMaskBandMainBand() */
868 : /************************************************************************/
869 :
870 1187 : GDALRasterBand *VRTSimpleSource::GetMaskBandMainBand()
871 : {
872 1187 : if (m_poRasterBand == nullptr)
873 2 : OpenSource();
874 1187 : return m_poMaskBandMainBand;
875 : }
876 :
877 : /************************************************************************/
878 : /* IsSameExceptBandNumber() */
879 : /************************************************************************/
880 :
881 971 : bool VRTSimpleSource::IsSameExceptBandNumber(
882 : const VRTSimpleSource *poOtherSource) const
883 : {
884 1942 : return m_dfSrcXOff == poOtherSource->m_dfSrcXOff &&
885 971 : m_dfSrcYOff == poOtherSource->m_dfSrcYOff &&
886 971 : m_dfSrcXSize == poOtherSource->m_dfSrcXSize &&
887 971 : m_dfSrcYSize == poOtherSource->m_dfSrcYSize &&
888 971 : m_dfDstXOff == poOtherSource->m_dfDstXOff &&
889 971 : m_dfDstYOff == poOtherSource->m_dfDstYOff &&
890 971 : m_dfDstXSize == poOtherSource->m_dfDstXSize &&
891 971 : m_dfDstYSize == poOtherSource->m_dfDstYSize &&
892 2913 : !m_osSrcDSName.empty() &&
893 1942 : m_osSrcDSName == poOtherSource->m_osSrcDSName;
894 : }
895 :
896 : /************************************************************************/
897 : /* SrcToDst() */
898 : /* */
899 : /* Note: this is a no-op if the both src and dst windows are unset */
900 : /************************************************************************/
901 :
902 6482 : void VRTSimpleSource::SrcToDst(double dfX, double dfY, double &dfXOut,
903 : double &dfYOut) const
904 :
905 : {
906 6482 : dfXOut = ((dfX - m_dfSrcXOff) / m_dfSrcXSize) * m_dfDstXSize + m_dfDstXOff;
907 6482 : dfYOut = ((dfY - m_dfSrcYOff) / m_dfSrcYSize) * m_dfDstYSize + m_dfDstYOff;
908 6482 : }
909 :
910 : /************************************************************************/
911 : /* DstToSrc() */
912 : /* */
913 : /* Note: this is a no-op if the both src and dst windows are unset */
914 : /************************************************************************/
915 :
916 4022310 : void VRTSimpleSource::DstToSrc(double dfX, double dfY, double &dfXOut,
917 : double &dfYOut) const
918 :
919 : {
920 4022310 : dfXOut = ((dfX - m_dfDstXOff) / m_dfDstXSize) * m_dfSrcXSize + m_dfSrcXOff;
921 4022310 : dfYOut = ((dfY - m_dfDstYOff) / m_dfDstYSize) * m_dfSrcYSize + m_dfSrcYOff;
922 4022310 : }
923 :
924 : /************************************************************************/
925 : /* GetSrcDstWindow() */
926 : /************************************************************************/
927 :
928 69640 : int VRTSimpleSource::GetSrcDstWindow(
929 : double dfXOff, double dfYOff, double dfXSize, double dfYSize, int nBufXSize,
930 : int nBufYSize, double *pdfReqXOff, double *pdfReqYOff, double *pdfReqXSize,
931 : double *pdfReqYSize, int *pnReqXOff, int *pnReqYOff, int *pnReqXSize,
932 : int *pnReqYSize, int *pnOutXOff, int *pnOutYOff, int *pnOutXSize,
933 : int *pnOutYSize, bool &bErrorOut)
934 :
935 : {
936 69640 : bErrorOut = false;
937 :
938 69640 : if (m_dfSrcXSize == 0.0 || m_dfSrcYSize == 0.0 || m_dfDstXSize == 0.0 ||
939 69640 : m_dfDstYSize == 0.0)
940 : {
941 0 : return FALSE;
942 : }
943 :
944 69641 : const bool bDstWinSet = IsDstWinSet();
945 :
946 : #ifdef DEBUG
947 69641 : const bool bSrcWinSet = IsSrcWinSet();
948 :
949 69641 : if (bSrcWinSet != bDstWinSet)
950 : {
951 0 : return FALSE;
952 : }
953 : #endif
954 :
955 : /* -------------------------------------------------------------------- */
956 : /* If the input window completely misses the portion of the */
957 : /* virtual dataset provided by this source we have nothing to do. */
958 : /* -------------------------------------------------------------------- */
959 69641 : if (bDstWinSet)
960 : {
961 69354 : if (dfXOff >= m_dfDstXOff + m_dfDstXSize ||
962 58926 : dfYOff >= m_dfDstYOff + m_dfDstYSize ||
963 58390 : dfXOff + dfXSize <= m_dfDstXOff || dfYOff + dfYSize <= m_dfDstYOff)
964 20311 : return FALSE;
965 : }
966 :
967 : /* -------------------------------------------------------------------- */
968 : /* This request window corresponds to the whole output buffer. */
969 : /* -------------------------------------------------------------------- */
970 49330 : *pnOutXOff = 0;
971 49330 : *pnOutYOff = 0;
972 49330 : *pnOutXSize = nBufXSize;
973 49330 : *pnOutYSize = nBufYSize;
974 :
975 : /* -------------------------------------------------------------------- */
976 : /* If the input window extents outside the portion of the on */
977 : /* the virtual file that this source can set, then clip down */
978 : /* the requested window. */
979 : /* -------------------------------------------------------------------- */
980 49330 : bool bModifiedX = false;
981 49330 : bool bModifiedY = false;
982 49330 : double dfRXOff = dfXOff;
983 49330 : double dfRYOff = dfYOff;
984 49330 : double dfRXSize = dfXSize;
985 49330 : double dfRYSize = dfYSize;
986 :
987 49330 : if (bDstWinSet)
988 : {
989 49041 : if (dfRXOff < m_dfDstXOff)
990 : {
991 1857 : dfRXSize = dfRXSize + dfRXOff - m_dfDstXOff;
992 1857 : dfRXOff = m_dfDstXOff;
993 1857 : bModifiedX = true;
994 : }
995 :
996 49041 : if (dfRYOff < m_dfDstYOff)
997 : {
998 164 : dfRYSize = dfRYSize + dfRYOff - m_dfDstYOff;
999 164 : dfRYOff = m_dfDstYOff;
1000 164 : bModifiedY = true;
1001 : }
1002 :
1003 49041 : if (dfRXOff + dfRXSize > m_dfDstXOff + m_dfDstXSize)
1004 : {
1005 1929 : dfRXSize = m_dfDstXOff + m_dfDstXSize - dfRXOff;
1006 1929 : bModifiedX = true;
1007 : }
1008 :
1009 49041 : if (dfRYOff + dfRYSize > m_dfDstYOff + m_dfDstYSize)
1010 : {
1011 256 : dfRYSize = m_dfDstYOff + m_dfDstYSize - dfRYOff;
1012 256 : bModifiedY = true;
1013 : }
1014 : }
1015 :
1016 : /* -------------------------------------------------------------------- */
1017 : /* Translate requested region in virtual file into the source */
1018 : /* band coordinates. */
1019 : /* -------------------------------------------------------------------- */
1020 49330 : const double dfScaleX = m_dfSrcXSize / m_dfDstXSize;
1021 49330 : const double dfScaleY = m_dfSrcYSize / m_dfDstYSize;
1022 :
1023 49330 : *pdfReqXOff = (dfRXOff - m_dfDstXOff) * dfScaleX + m_dfSrcXOff;
1024 49330 : *pdfReqYOff = (dfRYOff - m_dfDstYOff) * dfScaleY + m_dfSrcYOff;
1025 49330 : *pdfReqXSize = dfRXSize * dfScaleX;
1026 49330 : *pdfReqYSize = dfRYSize * dfScaleY;
1027 :
1028 98658 : if (!std::isfinite(*pdfReqXOff) || !std::isfinite(*pdfReqYOff) ||
1029 49328 : !std::isfinite(*pdfReqXSize) || !std::isfinite(*pdfReqYSize) ||
1030 147986 : *pdfReqXOff > INT_MAX || *pdfReqYOff > INT_MAX || *pdfReqXSize < 0 ||
1031 49329 : *pdfReqYSize < 0)
1032 : {
1033 0 : return FALSE;
1034 : }
1035 :
1036 : /* -------------------------------------------------------------------- */
1037 : /* Clamp within the bounds of the available source data. */
1038 : /* -------------------------------------------------------------------- */
1039 49329 : if (*pdfReqXOff < 0)
1040 : {
1041 6 : *pdfReqXSize += *pdfReqXOff;
1042 6 : *pdfReqXOff = 0;
1043 6 : bModifiedX = true;
1044 : }
1045 49329 : if (*pdfReqYOff < 0)
1046 : {
1047 6 : *pdfReqYSize += *pdfReqYOff;
1048 6 : *pdfReqYOff = 0;
1049 6 : bModifiedY = true;
1050 : }
1051 :
1052 49329 : *pnReqXOff = static_cast<int>(floor(*pdfReqXOff));
1053 49329 : *pnReqYOff = static_cast<int>(floor(*pdfReqYOff));
1054 :
1055 49329 : constexpr double EPS = 1e-3;
1056 49329 : constexpr double ONE_MINUS_EPS = 1.0 - EPS;
1057 49329 : if (*pdfReqXOff - *pnReqXOff > ONE_MINUS_EPS)
1058 : {
1059 2 : (*pnReqXOff)++;
1060 2 : *pdfReqXOff = *pnReqXOff;
1061 : }
1062 49329 : if (*pdfReqYOff - *pnReqYOff > ONE_MINUS_EPS)
1063 : {
1064 18 : (*pnReqYOff)++;
1065 18 : *pdfReqYOff = *pnReqYOff;
1066 : }
1067 :
1068 49329 : if (*pdfReqXSize > INT_MAX)
1069 0 : *pnReqXSize = INT_MAX;
1070 : else
1071 49329 : *pnReqXSize = static_cast<int>(floor(*pdfReqXSize + 0.5));
1072 :
1073 49329 : if (*pdfReqYSize > INT_MAX)
1074 0 : *pnReqYSize = INT_MAX;
1075 : else
1076 49329 : *pnReqYSize = static_cast<int>(floor(*pdfReqYSize + 0.5));
1077 :
1078 : /* -------------------------------------------------------------------- */
1079 : /* Clamp within the bounds of the available source data. */
1080 : /* -------------------------------------------------------------------- */
1081 :
1082 49329 : if (*pnReqXSize == 0)
1083 675 : *pnReqXSize = 1;
1084 49329 : if (*pnReqYSize == 0)
1085 22678 : *pnReqYSize = 1;
1086 :
1087 49329 : auto l_band = GetRasterBand();
1088 49329 : if (!l_band)
1089 : {
1090 106 : bErrorOut = true;
1091 106 : return FALSE;
1092 : }
1093 98447 : if (*pnReqXSize > INT_MAX - *pnReqXOff ||
1094 49223 : *pnReqXOff + *pnReqXSize > l_band->GetXSize())
1095 : {
1096 44 : *pnReqXSize = l_band->GetXSize() - *pnReqXOff;
1097 44 : bModifiedX = true;
1098 : }
1099 49224 : if (*pdfReqXOff + *pdfReqXSize > l_band->GetXSize())
1100 : {
1101 44 : *pdfReqXSize = l_band->GetXSize() - *pdfReqXOff;
1102 44 : bModifiedX = true;
1103 : }
1104 :
1105 98445 : if (*pnReqYSize > INT_MAX - *pnReqYOff ||
1106 49223 : *pnReqYOff + *pnReqYSize > l_band->GetYSize())
1107 : {
1108 44 : *pnReqYSize = l_band->GetYSize() - *pnReqYOff;
1109 44 : bModifiedY = true;
1110 : }
1111 49222 : if (*pdfReqYOff + *pdfReqYSize > l_band->GetYSize())
1112 : {
1113 56 : *pdfReqYSize = l_band->GetYSize() - *pdfReqYOff;
1114 56 : bModifiedY = true;
1115 : }
1116 :
1117 : /* -------------------------------------------------------------------- */
1118 : /* Don't do anything if the requesting region is completely off */
1119 : /* the source image. */
1120 : /* -------------------------------------------------------------------- */
1121 98442 : if (*pnReqXOff >= l_band->GetXSize() || *pnReqYOff >= l_band->GetYSize() ||
1122 98442 : *pnReqXSize <= 0 || *pnReqYSize <= 0)
1123 : {
1124 9 : return FALSE;
1125 : }
1126 :
1127 : /* -------------------------------------------------------------------- */
1128 : /* If we haven't had to modify the source rectangle, then the */
1129 : /* destination rectangle must be the whole region. */
1130 : /* -------------------------------------------------------------------- */
1131 49214 : if (bModifiedX || bModifiedY)
1132 : {
1133 : /* --------------------------------------------------------------------
1134 : */
1135 : /* Now transform this possibly reduced request back into the */
1136 : /* destination buffer coordinates in case the output region is */
1137 : /* less than the whole buffer. */
1138 : /* --------------------------------------------------------------------
1139 : */
1140 3242 : double dfDstULX = 0.0;
1141 3242 : double dfDstULY = 0.0;
1142 3242 : double dfDstLRX = 0.0;
1143 3242 : double dfDstLRY = 0.0;
1144 :
1145 3242 : SrcToDst(*pdfReqXOff, *pdfReqYOff, dfDstULX, dfDstULY);
1146 3241 : SrcToDst(*pdfReqXOff + *pdfReqXSize, *pdfReqYOff + *pdfReqYSize,
1147 : dfDstLRX, dfDstLRY);
1148 : #if DEBUG_VERBOSE
1149 : CPLDebug("VRT", "dfDstULX=%g dfDstULY=%g dfDstLRX=%g dfDstLRY=%g",
1150 : dfDstULX, dfDstULY, dfDstLRX, dfDstLRY);
1151 : #endif
1152 :
1153 3243 : if (bModifiedX)
1154 : {
1155 3203 : const double dfScaleWinToBufX = nBufXSize / dfXSize;
1156 :
1157 3203 : const double dfOutXOff = (dfDstULX - dfXOff) * dfScaleWinToBufX;
1158 3203 : if (dfOutXOff <= 0)
1159 1346 : *pnOutXOff = 0;
1160 1857 : else if (dfOutXOff > INT_MAX)
1161 0 : *pnOutXOff = INT_MAX;
1162 : else
1163 1857 : *pnOutXOff = static_cast<int>(dfOutXOff + EPS);
1164 :
1165 : // Apply correction on floating-point source window
1166 : {
1167 3203 : double dfDstDeltaX =
1168 3203 : (dfOutXOff - *pnOutXOff) / dfScaleWinToBufX;
1169 3203 : double dfSrcDeltaX = dfDstDeltaX / m_dfDstXSize * m_dfSrcXSize;
1170 3203 : *pdfReqXOff -= dfSrcDeltaX;
1171 6406 : *pdfReqXSize = std::min(*pdfReqXSize + dfSrcDeltaX,
1172 3203 : static_cast<double>(INT_MAX));
1173 : }
1174 :
1175 3203 : double dfOutRightXOff = (dfDstLRX - dfXOff) * dfScaleWinToBufX;
1176 3203 : if (dfOutRightXOff < dfOutXOff)
1177 0 : return FALSE;
1178 3203 : if (dfOutRightXOff > INT_MAX)
1179 0 : dfOutRightXOff = INT_MAX;
1180 3203 : const int nOutRightXOff =
1181 3203 : static_cast<int>(ceil(dfOutRightXOff - EPS));
1182 3203 : *pnOutXSize = nOutRightXOff - *pnOutXOff;
1183 :
1184 3203 : if (*pnOutXSize > INT_MAX - *pnOutXOff ||
1185 3203 : *pnOutXOff + *pnOutXSize > nBufXSize)
1186 0 : *pnOutXSize = nBufXSize - *pnOutXOff;
1187 :
1188 : // Apply correction on floating-point source window
1189 : {
1190 3203 : double dfDstDeltaX =
1191 3203 : (nOutRightXOff - dfOutRightXOff) / dfScaleWinToBufX;
1192 3203 : double dfSrcDeltaX = dfDstDeltaX / m_dfDstXSize * m_dfSrcXSize;
1193 6405 : *pdfReqXSize = std::min(*pdfReqXSize + dfSrcDeltaX,
1194 3203 : static_cast<double>(INT_MAX));
1195 : }
1196 : }
1197 :
1198 3242 : if (bModifiedY)
1199 : {
1200 358 : const double dfScaleWinToBufY = nBufYSize / dfYSize;
1201 :
1202 358 : const double dfOutYOff = (dfDstULY - dfYOff) * dfScaleWinToBufY;
1203 358 : if (dfOutYOff <= 0)
1204 183 : *pnOutYOff = 0;
1205 175 : else if (dfOutYOff > INT_MAX)
1206 0 : *pnOutYOff = INT_MAX;
1207 : else
1208 175 : *pnOutYOff = static_cast<int>(dfOutYOff + EPS);
1209 :
1210 : // Apply correction on floating-point source window
1211 : {
1212 358 : double dfDstDeltaY =
1213 358 : (dfOutYOff - *pnOutYOff) / dfScaleWinToBufY;
1214 358 : double dfSrcDeltaY = dfDstDeltaY / m_dfDstYSize * m_dfSrcYSize;
1215 358 : *pdfReqYOff -= dfSrcDeltaY;
1216 716 : *pdfReqYSize = std::min(*pdfReqYSize + dfSrcDeltaY,
1217 358 : static_cast<double>(INT_MAX));
1218 : }
1219 :
1220 358 : double dfOutTopYOff = (dfDstLRY - dfYOff) * dfScaleWinToBufY;
1221 358 : if (dfOutTopYOff < dfOutYOff)
1222 0 : return FALSE;
1223 358 : if (dfOutTopYOff > INT_MAX)
1224 0 : dfOutTopYOff = INT_MAX;
1225 358 : const int nOutTopYOff = static_cast<int>(ceil(dfOutTopYOff - EPS));
1226 358 : *pnOutYSize = nOutTopYOff - *pnOutYOff;
1227 :
1228 358 : if (*pnOutYSize > INT_MAX - *pnOutYOff ||
1229 358 : *pnOutYOff + *pnOutYSize > nBufYSize)
1230 0 : *pnOutYSize = nBufYSize - *pnOutYOff;
1231 :
1232 : // Apply correction on floating-point source window
1233 : {
1234 358 : double dfDstDeltaY =
1235 358 : (nOutTopYOff - dfOutTopYOff) / dfScaleWinToBufY;
1236 358 : double dfSrcDeltaY = dfDstDeltaY / m_dfDstYSize * m_dfSrcYSize;
1237 716 : *pdfReqYSize = std::min(*pdfReqYSize + dfSrcDeltaY,
1238 358 : static_cast<double>(INT_MAX));
1239 : }
1240 : }
1241 :
1242 3242 : if (*pnOutXSize < 1 || *pnOutYSize < 1)
1243 0 : return FALSE;
1244 : }
1245 :
1246 49215 : *pdfReqXOff = RoundIfCloseToInt(*pdfReqXOff);
1247 49214 : *pdfReqYOff = RoundIfCloseToInt(*pdfReqYOff);
1248 49214 : *pdfReqXSize = RoundIfCloseToInt(*pdfReqXSize);
1249 49215 : *pdfReqYSize = RoundIfCloseToInt(*pdfReqYSize);
1250 :
1251 49215 : return TRUE;
1252 : }
1253 :
1254 : /************************************************************************/
1255 : /* NeedMaxValAdjustment() */
1256 : /************************************************************************/
1257 :
1258 41972 : int VRTSimpleSource::NeedMaxValAdjustment() const
1259 : {
1260 41972 : if (!m_nMaxValue)
1261 41950 : return FALSE;
1262 :
1263 22 : auto l_band = GetRasterBand();
1264 22 : if (!l_band)
1265 0 : return FALSE;
1266 22 : const char *pszNBITS = l_band->GetMetadataItem("NBITS", "IMAGE_STRUCTURE");
1267 22 : const int nBits = (pszNBITS) ? atoi(pszNBITS) : 0;
1268 22 : if (nBits >= 1 && nBits <= 31)
1269 : {
1270 0 : const int nBandMaxValue = static_cast<int>((1U << nBits) - 1);
1271 0 : return nBandMaxValue > m_nMaxValue;
1272 : }
1273 22 : return TRUE;
1274 : }
1275 :
1276 : /************************************************************************/
1277 : /* RasterIO() */
1278 : /************************************************************************/
1279 :
1280 50199 : CPLErr VRTSimpleSource::RasterIO(GDALDataType eVRTBandDataType, int nXOff,
1281 : int nYOff, int nXSize, int nYSize, void *pData,
1282 : int nBufXSize, int nBufYSize,
1283 : GDALDataType eBufType, GSpacing nPixelSpace,
1284 : GSpacing nLineSpace,
1285 : GDALRasterIOExtraArg *psExtraArgIn,
1286 : WorkingState & /*oWorkingState*/)
1287 :
1288 : {
1289 : GDALRasterIOExtraArg sExtraArg;
1290 50199 : INIT_RASTERIO_EXTRA_ARG(sExtraArg);
1291 50199 : GDALRasterIOExtraArg *psExtraArg = &sExtraArg;
1292 :
1293 50199 : double dfXOff = nXOff;
1294 50199 : double dfYOff = nYOff;
1295 50199 : double dfXSize = nXSize;
1296 50199 : double dfYSize = nYSize;
1297 50199 : if (psExtraArgIn != nullptr && psExtraArgIn->bFloatingPointWindowValidity)
1298 : {
1299 61 : dfXOff = psExtraArgIn->dfXOff;
1300 61 : dfYOff = psExtraArgIn->dfYOff;
1301 61 : dfXSize = psExtraArgIn->dfXSize;
1302 61 : dfYSize = psExtraArgIn->dfYSize;
1303 : }
1304 :
1305 : // The window we will actually request from the source raster band.
1306 50199 : double dfReqXOff = 0.0;
1307 50199 : double dfReqYOff = 0.0;
1308 50199 : double dfReqXSize = 0.0;
1309 50199 : double dfReqYSize = 0.0;
1310 50199 : int nReqXOff = 0;
1311 50199 : int nReqYOff = 0;
1312 50199 : int nReqXSize = 0;
1313 50199 : int nReqYSize = 0;
1314 :
1315 : // The window we will actual set _within_ the pData buffer.
1316 50199 : int nOutXOff = 0;
1317 50199 : int nOutYOff = 0;
1318 50199 : int nOutXSize = 0;
1319 50199 : int nOutYSize = 0;
1320 :
1321 50199 : bool bError = false;
1322 50199 : if (!GetSrcDstWindow(dfXOff, dfYOff, dfXSize, dfYSize, nBufXSize, nBufYSize,
1323 : &dfReqXOff, &dfReqYOff, &dfReqXSize, &dfReqYSize,
1324 : &nReqXOff, &nReqYOff, &nReqXSize, &nReqYSize,
1325 : &nOutXOff, &nOutYOff, &nOutXSize, &nOutYSize, bError))
1326 : {
1327 9313 : return bError ? CE_Failure : CE_None;
1328 : }
1329 : #if DEBUG_VERBOSE
1330 : CPLDebug("VRT",
1331 : "nXOff=%d, nYOff=%d, nXSize=%d, nYSize=%d, nBufXSize=%d, "
1332 : "nBufYSize=%d,\n"
1333 : "dfReqXOff=%g, dfReqYOff=%g, dfReqXSize=%g, dfReqYSize=%g,\n"
1334 : "nReqXOff=%d, nReqYOff=%d, nReqXSize=%d, nReqYSize=%d,\n"
1335 : "nOutXOff=%d, nOutYOff=%d, nOutXSize=%d, nOutYSize=%d",
1336 : nXOff, nYOff, nXSize, nYSize, nBufXSize, nBufYSize, dfReqXOff,
1337 : dfReqYOff, dfReqXSize, dfReqYSize, nReqXOff, nReqYOff, nReqXSize,
1338 : nReqYSize, nOutXOff, nOutYOff, nOutXSize, nOutYSize);
1339 : #endif
1340 :
1341 : /* -------------------------------------------------------------------- */
1342 : /* Actually perform the IO request. */
1343 : /* -------------------------------------------------------------------- */
1344 40886 : if (!m_osResampling.empty())
1345 : {
1346 2050 : psExtraArg->eResampleAlg = GDALRasterIOGetResampleAlg(m_osResampling);
1347 : }
1348 38836 : else if (psExtraArgIn != nullptr)
1349 : {
1350 38835 : psExtraArg->eResampleAlg = psExtraArgIn->eResampleAlg;
1351 : }
1352 40886 : psExtraArg->bFloatingPointWindowValidity = TRUE;
1353 40886 : psExtraArg->dfXOff = dfReqXOff;
1354 40886 : psExtraArg->dfYOff = dfReqYOff;
1355 40886 : psExtraArg->dfXSize = dfReqXSize;
1356 40886 : psExtraArg->dfYSize = dfReqYSize;
1357 40886 : if (psExtraArgIn)
1358 : {
1359 40885 : psExtraArg->pfnProgress = psExtraArgIn->pfnProgress;
1360 40885 : psExtraArg->pProgressData = psExtraArgIn->pProgressData;
1361 : }
1362 :
1363 40886 : GByte *pabyOut = static_cast<unsigned char *>(pData) +
1364 40886 : nOutXOff * nPixelSpace +
1365 40886 : static_cast<GPtrDiff_t>(nOutYOff) * nLineSpace;
1366 :
1367 40886 : auto l_band = GetRasterBand();
1368 40885 : if (!l_band)
1369 0 : return CE_Failure;
1370 :
1371 40885 : CPLErr eErr = CE_Failure;
1372 40885 : if (GDALDataTypeIsConversionLossy(l_band->GetRasterDataType(),
1373 40886 : eVRTBandDataType))
1374 : {
1375 49 : const int nBandDTSize = GDALGetDataTypeSizeBytes(eVRTBandDataType);
1376 49 : void *pTemp = VSI_MALLOC3_VERBOSE(nOutXSize, nOutYSize, nBandDTSize);
1377 49 : if (pTemp)
1378 : {
1379 49 : eErr = l_band->RasterIO(GF_Read, nReqXOff, nReqYOff, nReqXSize,
1380 : nReqYSize, pTemp, nOutXSize, nOutYSize,
1381 : eVRTBandDataType, 0, 0, psExtraArg);
1382 49 : if (eErr == CE_None)
1383 : {
1384 49 : GByte *pabyTemp = static_cast<GByte *>(pTemp);
1385 779 : for (int iY = 0; iY < nOutYSize; iY++)
1386 : {
1387 730 : GDALCopyWords(
1388 730 : pabyTemp +
1389 730 : static_cast<size_t>(iY) * nBandDTSize * nOutXSize,
1390 : eVRTBandDataType, nBandDTSize,
1391 730 : pabyOut + static_cast<GPtrDiff_t>(iY * nLineSpace),
1392 : eBufType, static_cast<int>(nPixelSpace), nOutXSize);
1393 : }
1394 : }
1395 49 : VSIFree(pTemp);
1396 : }
1397 : }
1398 : else
1399 : {
1400 40837 : eErr = l_band->RasterIO(GF_Read, nReqXOff, nReqYOff, nReqXSize,
1401 : nReqYSize, pabyOut, nOutXSize, nOutYSize,
1402 : eBufType, nPixelSpace, nLineSpace, psExtraArg);
1403 : }
1404 :
1405 40886 : if (NeedMaxValAdjustment())
1406 : {
1407 234 : for (int j = 0; j < nOutYSize; j++)
1408 : {
1409 4620 : for (int i = 0; i < nOutXSize; i++)
1410 : {
1411 4400 : int nVal = 0;
1412 4400 : GDALCopyWords(pabyOut + j * nLineSpace + i * nPixelSpace,
1413 : eBufType, 0, &nVal, GDT_Int32, 0, 1);
1414 4400 : if (nVal > m_nMaxValue)
1415 800 : nVal = m_nMaxValue;
1416 4400 : GDALCopyWords(&nVal, GDT_Int32, 0,
1417 4400 : pabyOut + j * nLineSpace + i * nPixelSpace,
1418 : eBufType, 0, 1);
1419 : }
1420 : }
1421 : }
1422 :
1423 40886 : if (psExtraArg->pfnProgress)
1424 2920 : psExtraArg->pfnProgress(1.0, "", psExtraArg->pProgressData);
1425 :
1426 40886 : return eErr;
1427 : }
1428 :
1429 : /************************************************************************/
1430 : /* GetMinimum() */
1431 : /************************************************************************/
1432 :
1433 52 : double VRTSimpleSource::GetMinimum(int nXSize, int nYSize, int *pbSuccess)
1434 : {
1435 : // The window we will actually request from the source raster band.
1436 52 : double dfReqXOff = 0.0;
1437 52 : double dfReqYOff = 0.0;
1438 52 : double dfReqXSize = 0.0;
1439 52 : double dfReqYSize = 0.0;
1440 52 : int nReqXOff = 0;
1441 52 : int nReqYOff = 0;
1442 52 : int nReqXSize = 0;
1443 52 : int nReqYSize = 0;
1444 :
1445 : // The window we will actual set _within_ the pData buffer.
1446 52 : int nOutXOff = 0;
1447 52 : int nOutYOff = 0;
1448 52 : int nOutXSize = 0;
1449 52 : int nOutYSize = 0;
1450 :
1451 52 : bool bError = false;
1452 52 : auto l_band = GetRasterBand();
1453 104 : if (!l_band ||
1454 52 : !GetSrcDstWindow(0, 0, nXSize, nYSize, nXSize, nYSize, &dfReqXOff,
1455 : &dfReqYOff, &dfReqXSize, &dfReqYSize, &nReqXOff,
1456 : &nReqYOff, &nReqXSize, &nReqYSize, &nOutXOff,
1457 52 : &nOutYOff, &nOutXSize, &nOutYSize, bError) ||
1458 156 : nReqXOff != 0 || nReqYOff != 0 || nReqXSize != l_band->GetXSize() ||
1459 52 : nReqYSize != l_band->GetYSize())
1460 : {
1461 0 : *pbSuccess = FALSE;
1462 0 : return 0;
1463 : }
1464 :
1465 52 : const double dfVal = l_band->GetMinimum(pbSuccess);
1466 52 : if (NeedMaxValAdjustment() && dfVal > m_nMaxValue)
1467 2 : return m_nMaxValue;
1468 50 : return dfVal;
1469 : }
1470 :
1471 : /************************************************************************/
1472 : /* GetMaximum() */
1473 : /************************************************************************/
1474 :
1475 51 : double VRTSimpleSource::GetMaximum(int nXSize, int nYSize, int *pbSuccess)
1476 : {
1477 : // The window we will actually request from the source raster band.
1478 51 : double dfReqXOff = 0.0;
1479 51 : double dfReqYOff = 0.0;
1480 51 : double dfReqXSize = 0.0;
1481 51 : double dfReqYSize = 0.0;
1482 51 : int nReqXOff = 0;
1483 51 : int nReqYOff = 0;
1484 51 : int nReqXSize = 0;
1485 51 : int nReqYSize = 0;
1486 :
1487 : // The window we will actual set _within_ the pData buffer.
1488 51 : int nOutXOff = 0;
1489 51 : int nOutYOff = 0;
1490 51 : int nOutXSize = 0;
1491 51 : int nOutYSize = 0;
1492 :
1493 51 : bool bError = false;
1494 51 : auto l_band = GetRasterBand();
1495 102 : if (!l_band ||
1496 51 : !GetSrcDstWindow(0, 0, nXSize, nYSize, nXSize, nYSize, &dfReqXOff,
1497 : &dfReqYOff, &dfReqXSize, &dfReqYSize, &nReqXOff,
1498 : &nReqYOff, &nReqXSize, &nReqYSize, &nOutXOff,
1499 51 : &nOutYOff, &nOutXSize, &nOutYSize, bError) ||
1500 153 : nReqXOff != 0 || nReqYOff != 0 || nReqXSize != l_band->GetXSize() ||
1501 51 : nReqYSize != l_band->GetYSize())
1502 : {
1503 0 : *pbSuccess = FALSE;
1504 0 : return 0;
1505 : }
1506 :
1507 51 : const double dfVal = l_band->GetMaximum(pbSuccess);
1508 51 : if (NeedMaxValAdjustment() && dfVal > m_nMaxValue)
1509 2 : return m_nMaxValue;
1510 49 : return dfVal;
1511 : }
1512 :
1513 : /************************************************************************/
1514 : /* GetHistogram() */
1515 : /************************************************************************/
1516 :
1517 4 : CPLErr VRTSimpleSource::GetHistogram(int nXSize, int nYSize, double dfMin,
1518 : double dfMax, int nBuckets,
1519 : GUIntBig *panHistogram,
1520 : int bIncludeOutOfRange, int bApproxOK,
1521 : GDALProgressFunc pfnProgress,
1522 : void *pProgressData)
1523 : {
1524 : // The window we will actually request from the source raster band.
1525 4 : double dfReqXOff = 0.0;
1526 4 : double dfReqYOff = 0.0;
1527 4 : double dfReqXSize = 0.0;
1528 4 : double dfReqYSize = 0.0;
1529 4 : int nReqXOff = 0;
1530 4 : int nReqYOff = 0;
1531 4 : int nReqXSize = 0;
1532 4 : int nReqYSize = 0;
1533 :
1534 : // The window we will actual set _within_ the pData buffer.
1535 4 : int nOutXOff = 0;
1536 4 : int nOutYOff = 0;
1537 4 : int nOutXSize = 0;
1538 4 : int nOutYSize = 0;
1539 :
1540 4 : bool bError = false;
1541 4 : auto l_band = GetRasterBand();
1542 4 : if (!l_band || NeedMaxValAdjustment() ||
1543 4 : !GetSrcDstWindow(0, 0, nXSize, nYSize, nXSize, nYSize, &dfReqXOff,
1544 : &dfReqYOff, &dfReqXSize, &dfReqYSize, &nReqXOff,
1545 : &nReqYOff, &nReqXSize, &nReqYSize, &nOutXOff,
1546 4 : &nOutYOff, &nOutXSize, &nOutYSize, bError) ||
1547 12 : nReqXOff != 0 || nReqYOff != 0 || nReqXSize != l_band->GetXSize() ||
1548 4 : nReqYSize != l_band->GetYSize())
1549 : {
1550 0 : return CE_Failure;
1551 : }
1552 :
1553 4 : return l_band->GetHistogram(dfMin, dfMax, nBuckets, panHistogram,
1554 : bIncludeOutOfRange, bApproxOK, pfnProgress,
1555 4 : pProgressData);
1556 : }
1557 :
1558 : /************************************************************************/
1559 : /* DatasetRasterIO() */
1560 : /************************************************************************/
1561 :
1562 992 : CPLErr VRTSimpleSource::DatasetRasterIO(
1563 : GDALDataType eVRTBandDataType, int nXOff, int nYOff, int nXSize, int nYSize,
1564 : void *pData, int nBufXSize, int nBufYSize, GDALDataType eBufType,
1565 : int nBandCount, const int *panBandMap, GSpacing nPixelSpace,
1566 : GSpacing nLineSpace, GSpacing nBandSpace,
1567 : GDALRasterIOExtraArg *psExtraArgIn)
1568 : {
1569 992 : if (GetType() != VRTSimpleSource::GetTypeStatic())
1570 : {
1571 0 : CPLError(CE_Failure, CPLE_NotSupported,
1572 0 : "DatasetRasterIO() not implemented for %s", GetType());
1573 0 : return CE_Failure;
1574 : }
1575 :
1576 : GDALRasterIOExtraArg sExtraArg;
1577 991 : INIT_RASTERIO_EXTRA_ARG(sExtraArg);
1578 991 : GDALRasterIOExtraArg *psExtraArg = &sExtraArg;
1579 :
1580 991 : double dfXOff = nXOff;
1581 991 : double dfYOff = nYOff;
1582 991 : double dfXSize = nXSize;
1583 991 : double dfYSize = nYSize;
1584 991 : if (psExtraArgIn != nullptr && psExtraArgIn->bFloatingPointWindowValidity)
1585 : {
1586 11 : dfXOff = psExtraArgIn->dfXOff;
1587 11 : dfYOff = psExtraArgIn->dfYOff;
1588 11 : dfXSize = psExtraArgIn->dfXSize;
1589 11 : dfYSize = psExtraArgIn->dfYSize;
1590 : }
1591 :
1592 : // The window we will actually request from the source raster band.
1593 991 : double dfReqXOff = 0.0;
1594 991 : double dfReqYOff = 0.0;
1595 991 : double dfReqXSize = 0.0;
1596 991 : double dfReqYSize = 0.0;
1597 991 : int nReqXOff = 0;
1598 991 : int nReqYOff = 0;
1599 991 : int nReqXSize = 0;
1600 991 : int nReqYSize = 0;
1601 :
1602 : // The window we will actual set _within_ the pData buffer.
1603 991 : int nOutXOff = 0;
1604 991 : int nOutYOff = 0;
1605 991 : int nOutXSize = 0;
1606 991 : int nOutYSize = 0;
1607 :
1608 991 : bool bError = false;
1609 991 : if (!GetSrcDstWindow(dfXOff, dfYOff, dfXSize, dfYSize, nBufXSize, nBufYSize,
1610 : &dfReqXOff, &dfReqYOff, &dfReqXSize, &dfReqYSize,
1611 : &nReqXOff, &nReqYOff, &nReqXSize, &nReqYSize,
1612 : &nOutXOff, &nOutYOff, &nOutXSize, &nOutYSize, bError))
1613 : {
1614 71 : return bError ? CE_Failure : CE_None;
1615 : }
1616 :
1617 921 : auto l_band = GetRasterBand();
1618 920 : if (!l_band)
1619 0 : return CE_Failure;
1620 :
1621 920 : GDALDataset *poDS = l_band->GetDataset();
1622 920 : if (poDS == nullptr)
1623 0 : return CE_Failure;
1624 :
1625 920 : if (!m_osResampling.empty())
1626 : {
1627 6 : psExtraArg->eResampleAlg = GDALRasterIOGetResampleAlg(m_osResampling);
1628 : }
1629 915 : else if (psExtraArgIn != nullptr)
1630 : {
1631 914 : psExtraArg->eResampleAlg = psExtraArgIn->eResampleAlg;
1632 : }
1633 921 : psExtraArg->bFloatingPointWindowValidity = TRUE;
1634 921 : psExtraArg->dfXOff = dfReqXOff;
1635 921 : psExtraArg->dfYOff = dfReqYOff;
1636 921 : psExtraArg->dfXSize = dfReqXSize;
1637 921 : psExtraArg->dfYSize = dfReqYSize;
1638 921 : if (psExtraArgIn)
1639 : {
1640 921 : psExtraArg->pfnProgress = psExtraArgIn->pfnProgress;
1641 921 : psExtraArg->pProgressData = psExtraArgIn->pProgressData;
1642 : }
1643 :
1644 921 : GByte *pabyOut = static_cast<unsigned char *>(pData) +
1645 921 : nOutXOff * nPixelSpace +
1646 921 : static_cast<GPtrDiff_t>(nOutYOff) * nLineSpace;
1647 :
1648 921 : CPLErr eErr = CE_Failure;
1649 :
1650 921 : if (GDALDataTypeIsConversionLossy(l_band->GetRasterDataType(),
1651 921 : eVRTBandDataType))
1652 : {
1653 1 : const int nBandDTSize = GDALGetDataTypeSizeBytes(eVRTBandDataType);
1654 1 : void *pTemp = VSI_MALLOC3_VERBOSE(
1655 : nOutXSize, nOutYSize, cpl::fits_on<int>(nBandDTSize * nBandCount));
1656 1 : if (pTemp)
1657 : {
1658 1 : eErr = poDS->RasterIO(GF_Read, nReqXOff, nReqYOff, nReqXSize,
1659 : nReqYSize, pTemp, nOutXSize, nOutYSize,
1660 : eVRTBandDataType, nBandCount, panBandMap, 0,
1661 : 0, 0, psExtraArg);
1662 1 : if (eErr == CE_None)
1663 : {
1664 1 : GByte *pabyTemp = static_cast<GByte *>(pTemp);
1665 1 : const size_t nSrcBandSpace =
1666 1 : static_cast<size_t>(nOutYSize) * nOutXSize * nBandDTSize;
1667 2 : for (int iBand = 0; iBand < nBandCount; iBand++)
1668 : {
1669 21 : for (int iY = 0; iY < nOutYSize; iY++)
1670 : {
1671 20 : GDALCopyWords(
1672 20 : pabyTemp + iBand * nSrcBandSpace +
1673 20 : static_cast<size_t>(iY) * nBandDTSize *
1674 20 : nOutXSize,
1675 : eVRTBandDataType, nBandDTSize,
1676 20 : pabyOut + static_cast<GPtrDiff_t>(
1677 20 : iY * nLineSpace + iBand * nBandSpace),
1678 : eBufType, static_cast<int>(nPixelSpace), nOutXSize);
1679 : }
1680 : }
1681 : }
1682 1 : VSIFree(pTemp);
1683 : }
1684 : }
1685 : else
1686 : {
1687 920 : eErr = poDS->RasterIO(GF_Read, nReqXOff, nReqYOff, nReqXSize, nReqYSize,
1688 : pabyOut, nOutXSize, nOutYSize, eBufType,
1689 : nBandCount, panBandMap, nPixelSpace, nLineSpace,
1690 : nBandSpace, psExtraArg);
1691 : }
1692 :
1693 921 : if (NeedMaxValAdjustment())
1694 : {
1695 0 : for (int k = 0; k < nBandCount; k++)
1696 : {
1697 0 : for (int j = 0; j < nOutYSize; j++)
1698 : {
1699 0 : for (int i = 0; i < nOutXSize; i++)
1700 : {
1701 0 : int nVal = 0;
1702 0 : GDALCopyWords(pabyOut + k * nBandSpace + j * nLineSpace +
1703 0 : i * nPixelSpace,
1704 : eBufType, 0, &nVal, GDT_Int32, 0, 1);
1705 :
1706 0 : if (nVal > m_nMaxValue)
1707 0 : nVal = m_nMaxValue;
1708 :
1709 0 : GDALCopyWords(&nVal, GDT_Int32, 0,
1710 0 : pabyOut + k * nBandSpace + j * nLineSpace +
1711 0 : i * nPixelSpace,
1712 : eBufType, 0, 1);
1713 : }
1714 : }
1715 : }
1716 : }
1717 :
1718 921 : if (psExtraArg->pfnProgress)
1719 460 : psExtraArg->pfnProgress(1.0, "", psExtraArg->pProgressData);
1720 :
1721 921 : return eErr;
1722 : }
1723 :
1724 : /************************************************************************/
1725 : /* SetResampling() */
1726 : /************************************************************************/
1727 :
1728 4010 : void VRTSimpleSource::SetResampling(const char *pszResampling)
1729 : {
1730 4010 : m_osResampling = (pszResampling) ? pszResampling : "";
1731 4010 : }
1732 :
1733 : /************************************************************************/
1734 : /* ==================================================================== */
1735 : /* VRTAveragedSource */
1736 : /* ==================================================================== */
1737 : /************************************************************************/
1738 :
1739 : /************************************************************************/
1740 : /* VRTAveragedSource() */
1741 : /************************************************************************/
1742 :
1743 16 : VRTAveragedSource::VRTAveragedSource()
1744 : {
1745 16 : }
1746 :
1747 : /************************************************************************/
1748 : /* GetTypeStatic() */
1749 : /************************************************************************/
1750 :
1751 3054 : const char *VRTAveragedSource::GetTypeStatic()
1752 : {
1753 : static const char *TYPE = "AveragedSource";
1754 3054 : return TYPE;
1755 : }
1756 :
1757 : /************************************************************************/
1758 : /* GetType() */
1759 : /************************************************************************/
1760 :
1761 11 : const char *VRTAveragedSource::GetType() const
1762 : {
1763 11 : return GetTypeStatic();
1764 : }
1765 :
1766 : /************************************************************************/
1767 : /* SerializeToXML() */
1768 : /************************************************************************/
1769 :
1770 0 : CPLXMLNode *VRTAveragedSource::SerializeToXML(const char *pszVRTPath)
1771 :
1772 : {
1773 0 : CPLXMLNode *const psSrc = VRTSimpleSource::SerializeToXML(pszVRTPath);
1774 :
1775 0 : if (psSrc == nullptr)
1776 0 : return nullptr;
1777 :
1778 0 : CPLFree(psSrc->pszValue);
1779 0 : psSrc->pszValue = CPLStrdup(GetTypeStatic());
1780 :
1781 0 : return psSrc;
1782 : }
1783 :
1784 : /************************************************************************/
1785 : /* SetNoDataValue() */
1786 : /************************************************************************/
1787 :
1788 0 : void VRTAveragedSource::SetNoDataValue(double dfNewNoDataValue)
1789 :
1790 : {
1791 0 : if (dfNewNoDataValue == VRT_NODATA_UNSET)
1792 : {
1793 0 : m_bNoDataSet = FALSE;
1794 0 : m_dfNoDataValue = VRT_NODATA_UNSET;
1795 0 : return;
1796 : }
1797 :
1798 0 : m_bNoDataSet = TRUE;
1799 0 : m_dfNoDataValue = dfNewNoDataValue;
1800 : }
1801 :
1802 : /************************************************************************/
1803 : /* RasterIO() */
1804 : /************************************************************************/
1805 :
1806 33 : CPLErr VRTAveragedSource::RasterIO(GDALDataType /*eVRTBandDataType*/, int nXOff,
1807 : int nYOff, int nXSize, int nYSize,
1808 : void *pData, int nBufXSize, int nBufYSize,
1809 : GDALDataType eBufType, GSpacing nPixelSpace,
1810 : GSpacing nLineSpace,
1811 : GDALRasterIOExtraArg *psExtraArgIn,
1812 : WorkingState & /*oWorkingState*/)
1813 :
1814 : {
1815 : GDALRasterIOExtraArg sExtraArg;
1816 33 : INIT_RASTERIO_EXTRA_ARG(sExtraArg);
1817 33 : GDALRasterIOExtraArg *psExtraArg = &sExtraArg;
1818 :
1819 33 : double dfXOff = nXOff;
1820 33 : double dfYOff = nYOff;
1821 33 : double dfXSize = nXSize;
1822 33 : double dfYSize = nYSize;
1823 33 : if (psExtraArgIn != nullptr && psExtraArgIn->bFloatingPointWindowValidity)
1824 : {
1825 0 : dfXOff = psExtraArgIn->dfXOff;
1826 0 : dfYOff = psExtraArgIn->dfYOff;
1827 0 : dfXSize = psExtraArgIn->dfXSize;
1828 0 : dfYSize = psExtraArgIn->dfYSize;
1829 : }
1830 :
1831 : // The window we will actually request from the source raster band.
1832 33 : double dfReqXOff = 0.0;
1833 33 : double dfReqYOff = 0.0;
1834 33 : double dfReqXSize = 0.0;
1835 33 : double dfReqYSize = 0.0;
1836 33 : int nReqXOff = 0;
1837 33 : int nReqYOff = 0;
1838 33 : int nReqXSize = 0;
1839 33 : int nReqYSize = 0;
1840 :
1841 : // The window we will actual set _within_ the pData buffer.
1842 33 : int nOutXOff = 0;
1843 33 : int nOutYOff = 0;
1844 33 : int nOutXSize = 0;
1845 33 : int nOutYSize = 0;
1846 :
1847 33 : bool bError = false;
1848 33 : if (!GetSrcDstWindow(dfXOff, dfYOff, dfXSize, dfYSize, nBufXSize, nBufYSize,
1849 : &dfReqXOff, &dfReqYOff, &dfReqXSize, &dfReqYSize,
1850 : &nReqXOff, &nReqYOff, &nReqXSize, &nReqYSize,
1851 : &nOutXOff, &nOutYOff, &nOutXSize, &nOutYSize, bError))
1852 : {
1853 0 : return bError ? CE_Failure : CE_None;
1854 : }
1855 :
1856 33 : auto l_band = GetRasterBand();
1857 33 : if (!l_band)
1858 0 : return CE_Failure;
1859 :
1860 : /* -------------------------------------------------------------------- */
1861 : /* Allocate a temporary buffer to whole the full resolution */
1862 : /* data from the area of interest. */
1863 : /* -------------------------------------------------------------------- */
1864 : float *const pafSrc = static_cast<float *>(
1865 33 : VSI_MALLOC3_VERBOSE(sizeof(float), nReqXSize, nReqYSize));
1866 33 : if (pafSrc == nullptr)
1867 : {
1868 0 : return CE_Failure;
1869 : }
1870 :
1871 : /* -------------------------------------------------------------------- */
1872 : /* Load it. */
1873 : /* -------------------------------------------------------------------- */
1874 33 : if (!m_osResampling.empty())
1875 : {
1876 28 : psExtraArg->eResampleAlg = GDALRasterIOGetResampleAlg(m_osResampling);
1877 : }
1878 5 : else if (psExtraArgIn != nullptr)
1879 : {
1880 5 : psExtraArg->eResampleAlg = psExtraArgIn->eResampleAlg;
1881 : }
1882 :
1883 33 : psExtraArg->bFloatingPointWindowValidity = TRUE;
1884 33 : psExtraArg->dfXOff = dfReqXOff;
1885 33 : psExtraArg->dfYOff = dfReqYOff;
1886 33 : psExtraArg->dfXSize = dfReqXSize;
1887 33 : psExtraArg->dfYSize = dfReqYSize;
1888 33 : if (psExtraArgIn)
1889 : {
1890 33 : psExtraArg->pfnProgress = psExtraArgIn->pfnProgress;
1891 33 : psExtraArg->pProgressData = psExtraArgIn->pProgressData;
1892 : }
1893 :
1894 33 : const CPLErr eErr = l_band->RasterIO(
1895 : GF_Read, nReqXOff, nReqYOff, nReqXSize, nReqYSize, pafSrc, nReqXSize,
1896 : nReqYSize, GDT_Float32, 0, 0, psExtraArg);
1897 :
1898 33 : if (eErr != CE_None)
1899 : {
1900 0 : VSIFree(pafSrc);
1901 0 : return eErr;
1902 : }
1903 :
1904 : /* -------------------------------------------------------------------- */
1905 : /* Do the averaging. */
1906 : /* -------------------------------------------------------------------- */
1907 5956 : for (int iBufLine = nOutYOff; iBufLine < nOutYOff + nOutYSize; iBufLine++)
1908 : {
1909 5923 : const double dfYDst =
1910 5923 : (iBufLine / static_cast<double>(nBufYSize)) * nYSize + nYOff;
1911 :
1912 2017080 : for (int iBufPixel = nOutXOff; iBufPixel < nOutXOff + nOutXSize;
1913 : iBufPixel++)
1914 : {
1915 : double dfXSrcStart, dfXSrcEnd, dfYSrcStart, dfYSrcEnd;
1916 : int iXSrcStart, iYSrcStart, iXSrcEnd, iYSrcEnd;
1917 :
1918 2011160 : const double dfXDst =
1919 2011160 : (iBufPixel / static_cast<double>(nBufXSize)) * nXSize + nXOff;
1920 :
1921 : // Compute the source image rectangle needed for this pixel.
1922 2011160 : DstToSrc(dfXDst, dfYDst, dfXSrcStart, dfYSrcStart);
1923 2011160 : DstToSrc(dfXDst + 1.0, dfYDst + 1.0, dfXSrcEnd, dfYSrcEnd);
1924 :
1925 : // Convert to integers, assuming that the center of the source
1926 : // pixel must be in our rect to get included.
1927 2011160 : if (dfXSrcEnd >= dfXSrcStart + 1)
1928 : {
1929 1049560 : iXSrcStart = static_cast<int>(floor(dfXSrcStart + 0.5));
1930 1049560 : iXSrcEnd = static_cast<int>(floor(dfXSrcEnd + 0.5));
1931 : }
1932 : else
1933 : {
1934 : /* If the resampling factor is less than 100%, the distance */
1935 : /* between the source pixel is < 1, so we stick to nearest */
1936 : /* neighbour */
1937 961600 : iXSrcStart = static_cast<int>(floor(dfXSrcStart));
1938 961600 : iXSrcEnd = iXSrcStart + 1;
1939 : }
1940 2011160 : if (dfYSrcEnd >= dfYSrcStart + 1)
1941 : {
1942 1049560 : iYSrcStart = static_cast<int>(floor(dfYSrcStart + 0.5));
1943 1049560 : iYSrcEnd = static_cast<int>(floor(dfYSrcEnd + 0.5));
1944 : }
1945 : else
1946 : {
1947 961600 : iYSrcStart = static_cast<int>(floor(dfYSrcStart));
1948 961600 : iYSrcEnd = iYSrcStart + 1;
1949 : }
1950 :
1951 : // Transform into the coordinate system of the source *buffer*
1952 2011160 : iXSrcStart -= nReqXOff;
1953 2011160 : iYSrcStart -= nReqYOff;
1954 2011160 : iXSrcEnd -= nReqXOff;
1955 2011160 : iYSrcEnd -= nReqYOff;
1956 :
1957 2011160 : double dfSum = 0.0;
1958 2011160 : int nPixelCount = 0;
1959 :
1960 4022510 : for (int iY = iYSrcStart; iY < iYSrcEnd; iY++)
1961 : {
1962 2011360 : if (iY < 0 || iY >= nReqYSize)
1963 0 : continue;
1964 :
1965 4023130 : for (int iX = iXSrcStart; iX < iXSrcEnd; iX++)
1966 : {
1967 2011780 : if (iX < 0 || iX >= nReqXSize)
1968 0 : continue;
1969 :
1970 2011780 : const float fSampledValue =
1971 2011780 : pafSrc[iX + static_cast<size_t>(iY) * nReqXSize];
1972 2011780 : if (std::isnan(fSampledValue))
1973 0 : continue;
1974 :
1975 0 : if (m_bNoDataSet &&
1976 2011780 : GDALIsValueInRange<float>(m_dfNoDataValue) &&
1977 0 : ARE_REAL_EQUAL(fSampledValue,
1978 0 : static_cast<float>(m_dfNoDataValue)))
1979 0 : continue;
1980 :
1981 2011780 : nPixelCount++;
1982 2011780 : dfSum += pafSrc[iX + static_cast<size_t>(iY) * nReqXSize];
1983 : }
1984 : }
1985 :
1986 2011160 : if (nPixelCount == 0)
1987 0 : continue;
1988 :
1989 : // Compute output value.
1990 2011160 : const float dfOutputValue = static_cast<float>(dfSum / nPixelCount);
1991 :
1992 : // Put it in the output buffer.
1993 2011160 : GByte *pDstLocation =
1994 2011160 : static_cast<GByte *>(pData) + nPixelSpace * iBufPixel +
1995 2011160 : static_cast<GPtrDiff_t>(nLineSpace) * iBufLine;
1996 :
1997 2011160 : if (eBufType == GDT_Byte)
1998 2008660 : *pDstLocation = static_cast<GByte>(
1999 2008660 : std::min(255.0, std::max(0.0, dfOutputValue + 0.5)));
2000 : else
2001 2500 : GDALCopyWords(&dfOutputValue, GDT_Float32, 4, pDstLocation,
2002 : eBufType, 8, 1);
2003 : }
2004 : }
2005 :
2006 33 : VSIFree(pafSrc);
2007 :
2008 33 : if (psExtraArg->pfnProgress)
2009 0 : psExtraArg->pfnProgress(1.0, "", psExtraArg->pProgressData);
2010 :
2011 33 : return CE_None;
2012 : }
2013 :
2014 : /************************************************************************/
2015 : /* GetMinimum() */
2016 : /************************************************************************/
2017 :
2018 0 : double VRTAveragedSource::GetMinimum(int /* nXSize */, int /* nYSize */,
2019 : int *pbSuccess)
2020 : {
2021 0 : *pbSuccess = FALSE;
2022 0 : return 0.0;
2023 : }
2024 :
2025 : /************************************************************************/
2026 : /* GetMaximum() */
2027 : /************************************************************************/
2028 :
2029 0 : double VRTAveragedSource::GetMaximum(int /* nXSize */, int /* nYSize */,
2030 : int *pbSuccess)
2031 : {
2032 0 : *pbSuccess = FALSE;
2033 0 : return 0.0;
2034 : }
2035 :
2036 : /************************************************************************/
2037 : /* GetHistogram() */
2038 : /************************************************************************/
2039 :
2040 0 : CPLErr VRTAveragedSource::GetHistogram(
2041 : int /* nXSize */, int /* nYSize */, double /* dfMin */, double /* dfMax */,
2042 : int /* nBuckets */, GUIntBig * /* panHistogram */,
2043 : int /* bIncludeOutOfRange */, int /* bApproxOK */,
2044 : GDALProgressFunc /* pfnProgress */, void * /* pProgressData */)
2045 : {
2046 0 : return CE_Failure;
2047 : }
2048 :
2049 : /************************************************************************/
2050 : /* ==================================================================== */
2051 : /* VRTNoDataFromMaskSource */
2052 : /* ==================================================================== */
2053 : /************************************************************************/
2054 :
2055 : /************************************************************************/
2056 : /* VRTNoDataFromMaskSource() */
2057 : /************************************************************************/
2058 :
2059 23 : VRTNoDataFromMaskSource::VRTNoDataFromMaskSource()
2060 : {
2061 23 : }
2062 :
2063 : /************************************************************************/
2064 : /* XMLInit() */
2065 : /************************************************************************/
2066 :
2067 : CPLErr
2068 8 : VRTNoDataFromMaskSource::XMLInit(const CPLXMLNode *psSrc,
2069 : const char *pszVRTPath,
2070 : VRTMapSharedResources &oMapSharedSources)
2071 :
2072 : {
2073 : /* -------------------------------------------------------------------- */
2074 : /* Do base initialization. */
2075 : /* -------------------------------------------------------------------- */
2076 : {
2077 : const CPLErr eErr =
2078 8 : VRTSimpleSource::XMLInit(psSrc, pszVRTPath, oMapSharedSources);
2079 8 : if (eErr != CE_None)
2080 0 : return eErr;
2081 : }
2082 :
2083 8 : if (const char *pszNODATA = CPLGetXMLValue(psSrc, "NODATA", nullptr))
2084 : {
2085 8 : m_bNoDataSet = true;
2086 8 : m_dfNoDataValue = CPLAtofM(pszNODATA);
2087 : }
2088 :
2089 8 : m_dfMaskValueThreshold =
2090 8 : CPLAtofM(CPLGetXMLValue(psSrc, "MaskValueThreshold", "0"));
2091 :
2092 8 : if (const char *pszRemappedValue =
2093 8 : CPLGetXMLValue(psSrc, "RemappedValue", nullptr))
2094 : {
2095 0 : m_bHasRemappedValue = true;
2096 0 : m_dfRemappedValue = CPLAtofM(pszRemappedValue);
2097 : }
2098 :
2099 8 : return CE_None;
2100 : }
2101 :
2102 : /************************************************************************/
2103 : /* GetTypeStatic() */
2104 : /************************************************************************/
2105 :
2106 27 : const char *VRTNoDataFromMaskSource::GetTypeStatic()
2107 : {
2108 : static const char *TYPE = "NoDataFromMaskSource";
2109 27 : return TYPE;
2110 : }
2111 :
2112 : /************************************************************************/
2113 : /* GetType() */
2114 : /************************************************************************/
2115 :
2116 11 : const char *VRTNoDataFromMaskSource::GetType() const
2117 : {
2118 11 : return GetTypeStatic();
2119 : }
2120 :
2121 : /************************************************************************/
2122 : /* SerializeToXML() */
2123 : /************************************************************************/
2124 :
2125 8 : CPLXMLNode *VRTNoDataFromMaskSource::SerializeToXML(const char *pszVRTPath)
2126 :
2127 : {
2128 8 : CPLXMLNode *const psSrc = VRTSimpleSource::SerializeToXML(pszVRTPath);
2129 :
2130 8 : if (psSrc == nullptr)
2131 0 : return nullptr;
2132 :
2133 8 : CPLFree(psSrc->pszValue);
2134 8 : psSrc->pszValue = CPLStrdup(GetTypeStatic());
2135 :
2136 8 : if (m_bNoDataSet)
2137 : {
2138 8 : CPLSetXMLValue(psSrc, "MaskValueThreshold",
2139 : CPLSPrintf("%.17g", m_dfMaskValueThreshold));
2140 :
2141 8 : GDALDataType eBandDT = GDT_Unknown;
2142 8 : double dfNoDataValue = m_dfNoDataValue;
2143 8 : const auto kMaxFloat = std::numeric_limits<float>::max();
2144 8 : if (std::fabs(std::fabs(m_dfNoDataValue) - kMaxFloat) <
2145 : 1e-10 * kMaxFloat)
2146 : {
2147 0 : auto l_band = GetRasterBand();
2148 0 : if (l_band)
2149 : {
2150 0 : eBandDT = l_band->GetRasterDataType();
2151 0 : if (eBandDT == GDT_Float32)
2152 : {
2153 : dfNoDataValue =
2154 0 : GDALAdjustNoDataCloseToFloatMax(m_dfNoDataValue);
2155 : }
2156 : }
2157 : }
2158 8 : CPLSetXMLValue(psSrc, "NODATA",
2159 16 : VRTSerializeNoData(dfNoDataValue, eBandDT, 18).c_str());
2160 : }
2161 :
2162 8 : if (m_bHasRemappedValue)
2163 : {
2164 0 : CPLSetXMLValue(psSrc, "RemappedValue",
2165 : CPLSPrintf("%.17g", m_dfRemappedValue));
2166 : }
2167 :
2168 8 : return psSrc;
2169 : }
2170 :
2171 : /************************************************************************/
2172 : /* SetParameters() */
2173 : /************************************************************************/
2174 :
2175 15 : void VRTNoDataFromMaskSource::SetParameters(double dfNoDataValue,
2176 : double dfMaskValueThreshold)
2177 : {
2178 15 : m_bNoDataSet = true;
2179 15 : m_dfNoDataValue = dfNoDataValue;
2180 15 : m_dfMaskValueThreshold = dfMaskValueThreshold;
2181 15 : if (!m_bHasRemappedValue)
2182 15 : m_dfRemappedValue = m_dfNoDataValue;
2183 15 : }
2184 :
2185 : /************************************************************************/
2186 : /* SetParameters() */
2187 : /************************************************************************/
2188 :
2189 0 : void VRTNoDataFromMaskSource::SetParameters(double dfNoDataValue,
2190 : double dfMaskValueThreshold,
2191 : double dfRemappedValue)
2192 : {
2193 0 : SetParameters(dfNoDataValue, dfMaskValueThreshold);
2194 0 : m_bHasRemappedValue = true;
2195 0 : m_dfRemappedValue = dfRemappedValue;
2196 0 : }
2197 :
2198 : /************************************************************************/
2199 : /* RasterIO() */
2200 : /************************************************************************/
2201 :
2202 13 : CPLErr VRTNoDataFromMaskSource::RasterIO(
2203 : GDALDataType eVRTBandDataType, int nXOff, int nYOff, int nXSize, int nYSize,
2204 : void *pData, int nBufXSize, int nBufYSize, GDALDataType eBufType,
2205 : GSpacing nPixelSpace, GSpacing nLineSpace,
2206 : GDALRasterIOExtraArg *psExtraArgIn, WorkingState &oWorkingState)
2207 :
2208 : {
2209 13 : if (!m_bNoDataSet)
2210 : {
2211 0 : return VRTSimpleSource::RasterIO(eVRTBandDataType, nXOff, nYOff, nXSize,
2212 : nYSize, pData, nBufXSize, nBufYSize,
2213 : eBufType, nPixelSpace, nLineSpace,
2214 0 : psExtraArgIn, oWorkingState);
2215 : }
2216 :
2217 : GDALRasterIOExtraArg sExtraArg;
2218 13 : INIT_RASTERIO_EXTRA_ARG(sExtraArg);
2219 13 : GDALRasterIOExtraArg *psExtraArg = &sExtraArg;
2220 :
2221 13 : double dfXOff = nXOff;
2222 13 : double dfYOff = nYOff;
2223 13 : double dfXSize = nXSize;
2224 13 : double dfYSize = nYSize;
2225 13 : if (psExtraArgIn != nullptr && psExtraArgIn->bFloatingPointWindowValidity)
2226 : {
2227 0 : dfXOff = psExtraArgIn->dfXOff;
2228 0 : dfYOff = psExtraArgIn->dfYOff;
2229 0 : dfXSize = psExtraArgIn->dfXSize;
2230 0 : dfYSize = psExtraArgIn->dfYSize;
2231 : }
2232 :
2233 : // The window we will actually request from the source raster band.
2234 13 : double dfReqXOff = 0.0;
2235 13 : double dfReqYOff = 0.0;
2236 13 : double dfReqXSize = 0.0;
2237 13 : double dfReqYSize = 0.0;
2238 13 : int nReqXOff = 0;
2239 13 : int nReqYOff = 0;
2240 13 : int nReqXSize = 0;
2241 13 : int nReqYSize = 0;
2242 :
2243 : // The window we will actual set _within_ the pData buffer.
2244 13 : int nOutXOff = 0;
2245 13 : int nOutYOff = 0;
2246 13 : int nOutXSize = 0;
2247 13 : int nOutYSize = 0;
2248 :
2249 13 : bool bError = false;
2250 13 : if (!GetSrcDstWindow(dfXOff, dfYOff, dfXSize, dfYSize, nBufXSize, nBufYSize,
2251 : &dfReqXOff, &dfReqYOff, &dfReqXSize, &dfReqYSize,
2252 : &nReqXOff, &nReqYOff, &nReqXSize, &nReqYSize,
2253 : &nOutXOff, &nOutYOff, &nOutXSize, &nOutYSize, bError))
2254 : {
2255 0 : return bError ? CE_Failure : CE_None;
2256 : }
2257 :
2258 13 : auto l_band = GetRasterBand();
2259 13 : if (!l_band)
2260 0 : return CE_Failure;
2261 :
2262 : /* -------------------------------------------------------------------- */
2263 : /* Allocate temporary buffer(s). */
2264 : /* -------------------------------------------------------------------- */
2265 13 : const auto eSrcBandDT = l_band->GetRasterDataType();
2266 13 : const int nSrcBandDTSize = GDALGetDataTypeSizeBytes(eSrcBandDT);
2267 13 : const auto eSrcMaskBandDT = l_band->GetMaskBand()->GetRasterDataType();
2268 13 : const int nSrcMaskBandDTSize = GDALGetDataTypeSizeBytes(eSrcMaskBandDT);
2269 13 : double dfRemappedValue = m_dfRemappedValue;
2270 13 : if (!m_bHasRemappedValue)
2271 : {
2272 19 : if (eSrcBandDT == GDT_Byte &&
2273 6 : m_dfNoDataValue >= std::numeric_limits<GByte>::min() &&
2274 25 : m_dfNoDataValue <= std::numeric_limits<GByte>::max() &&
2275 6 : static_cast<int>(m_dfNoDataValue) == m_dfNoDataValue)
2276 : {
2277 6 : if (m_dfNoDataValue == std::numeric_limits<GByte>::max())
2278 1 : dfRemappedValue = m_dfNoDataValue - 1;
2279 : else
2280 5 : dfRemappedValue = m_dfNoDataValue + 1;
2281 : }
2282 10 : else if (eSrcBandDT == GDT_UInt16 &&
2283 3 : m_dfNoDataValue >= std::numeric_limits<uint16_t>::min() &&
2284 13 : m_dfNoDataValue <= std::numeric_limits<uint16_t>::max() &&
2285 3 : static_cast<int>(m_dfNoDataValue) == m_dfNoDataValue)
2286 : {
2287 3 : if (m_dfNoDataValue == std::numeric_limits<uint16_t>::max())
2288 1 : dfRemappedValue = m_dfNoDataValue - 1;
2289 : else
2290 2 : dfRemappedValue = m_dfNoDataValue + 1;
2291 : }
2292 6 : else if (eSrcBandDT == GDT_Int16 &&
2293 2 : m_dfNoDataValue >= std::numeric_limits<int16_t>::min() &&
2294 8 : m_dfNoDataValue <= std::numeric_limits<int16_t>::max() &&
2295 2 : static_cast<int>(m_dfNoDataValue) == m_dfNoDataValue)
2296 : {
2297 2 : if (m_dfNoDataValue == std::numeric_limits<int16_t>::max())
2298 1 : dfRemappedValue = m_dfNoDataValue - 1;
2299 : else
2300 1 : dfRemappedValue = m_dfNoDataValue + 1;
2301 : }
2302 : else
2303 : {
2304 2 : constexpr double EPS = 1e-3;
2305 2 : if (m_dfNoDataValue == 0)
2306 1 : dfRemappedValue = EPS;
2307 : else
2308 1 : dfRemappedValue = m_dfNoDataValue * (1 + EPS);
2309 : }
2310 : }
2311 13 : const bool bByteOptim =
2312 6 : (eSrcBandDT == GDT_Byte && eBufType == GDT_Byte &&
2313 5 : eSrcMaskBandDT == GDT_Byte && m_dfMaskValueThreshold >= 0 &&
2314 5 : m_dfMaskValueThreshold <= 255 &&
2315 5 : static_cast<int>(m_dfMaskValueThreshold) == m_dfMaskValueThreshold &&
2316 4 : m_dfNoDataValue >= 0 && m_dfNoDataValue <= 255 &&
2317 4 : static_cast<int>(m_dfNoDataValue) == m_dfNoDataValue &&
2318 23 : dfRemappedValue >= 0 && dfRemappedValue <= 255 &&
2319 4 : static_cast<int>(dfRemappedValue) == dfRemappedValue);
2320 : GByte *pabyWrkBuffer;
2321 : try
2322 : {
2323 13 : if (bByteOptim && nOutXOff == 0 && nOutYOff == 0 &&
2324 4 : nOutXSize == nBufXSize && nOutYSize == nBufYSize &&
2325 4 : eSrcBandDT == eBufType && nPixelSpace == nSrcBandDTSize &&
2326 4 : nLineSpace == nPixelSpace * nBufXSize)
2327 : {
2328 4 : pabyWrkBuffer = static_cast<GByte *>(pData);
2329 : }
2330 : else
2331 : {
2332 9 : oWorkingState.m_abyWrkBuffer.resize(static_cast<size_t>(nOutXSize) *
2333 9 : nOutYSize * nSrcBandDTSize);
2334 : pabyWrkBuffer =
2335 9 : reinterpret_cast<GByte *>(oWorkingState.m_abyWrkBuffer.data());
2336 : }
2337 13 : oWorkingState.m_abyWrkBufferMask.resize(static_cast<size_t>(nOutXSize) *
2338 13 : nOutYSize * nSrcMaskBandDTSize);
2339 : }
2340 0 : catch (const std::exception &)
2341 : {
2342 0 : CPLError(CE_Failure, CPLE_OutOfMemory,
2343 : "Out of memory when allocating buffers");
2344 0 : return CE_Failure;
2345 : }
2346 :
2347 : /* -------------------------------------------------------------------- */
2348 : /* Load data. */
2349 : /* -------------------------------------------------------------------- */
2350 13 : if (!m_osResampling.empty())
2351 : {
2352 0 : psExtraArg->eResampleAlg = GDALRasterIOGetResampleAlg(m_osResampling);
2353 : }
2354 13 : else if (psExtraArgIn != nullptr)
2355 : {
2356 13 : psExtraArg->eResampleAlg = psExtraArgIn->eResampleAlg;
2357 : }
2358 :
2359 13 : psExtraArg->bFloatingPointWindowValidity = TRUE;
2360 13 : psExtraArg->dfXOff = dfReqXOff;
2361 13 : psExtraArg->dfYOff = dfReqYOff;
2362 13 : psExtraArg->dfXSize = dfReqXSize;
2363 13 : psExtraArg->dfYSize = dfReqYSize;
2364 13 : if (psExtraArgIn)
2365 : {
2366 13 : psExtraArg->pfnProgress = psExtraArgIn->pfnProgress;
2367 13 : psExtraArg->pProgressData = psExtraArgIn->pProgressData;
2368 : }
2369 :
2370 13 : if (l_band->RasterIO(GF_Read, nReqXOff, nReqYOff, nReqXSize, nReqYSize,
2371 : pabyWrkBuffer, nOutXSize, nOutYSize, eSrcBandDT, 0, 0,
2372 13 : psExtraArg) != CE_None)
2373 : {
2374 0 : return CE_Failure;
2375 : }
2376 :
2377 26 : if (l_band->GetMaskBand()->RasterIO(
2378 : GF_Read, nReqXOff, nReqYOff, nReqXSize, nReqYSize,
2379 13 : oWorkingState.m_abyWrkBufferMask.data(), nOutXSize, nOutYSize,
2380 13 : eSrcMaskBandDT, 0, 0, psExtraArg) != CE_None)
2381 : {
2382 0 : return CE_Failure;
2383 : }
2384 :
2385 : /* -------------------------------------------------------------------- */
2386 : /* Do the processing. */
2387 : /* -------------------------------------------------------------------- */
2388 :
2389 13 : GByte *const pabyOut = static_cast<GByte *>(pData) +
2390 13 : nPixelSpace * nOutXOff +
2391 13 : static_cast<GPtrDiff_t>(nLineSpace) * nOutYOff;
2392 13 : if (bByteOptim)
2393 : {
2394 : // Special case when everything fits on Byte
2395 4 : const GByte nMaskValueThreshold =
2396 4 : static_cast<GByte>(m_dfMaskValueThreshold);
2397 4 : const GByte nNoDataValue = static_cast<GByte>(m_dfNoDataValue);
2398 4 : const GByte nRemappedValue = static_cast<GByte>(dfRemappedValue);
2399 4 : size_t nSrcIdx = 0;
2400 8 : for (int iY = 0; iY < nOutYSize; iY++)
2401 : {
2402 4 : GSpacing nDstOffset = iY * nLineSpace;
2403 12 : for (int iX = 0; iX < nOutXSize; iX++)
2404 : {
2405 : const GByte nMaskVal =
2406 8 : oWorkingState.m_abyWrkBufferMask[nSrcIdx];
2407 8 : if (nMaskVal <= nMaskValueThreshold)
2408 : {
2409 4 : pabyOut[static_cast<GPtrDiff_t>(nDstOffset)] = nNoDataValue;
2410 : }
2411 : else
2412 : {
2413 4 : if (pabyWrkBuffer[nSrcIdx] == nNoDataValue)
2414 : {
2415 2 : pabyOut[static_cast<GPtrDiff_t>(nDstOffset)] =
2416 : nRemappedValue;
2417 : }
2418 : else
2419 : {
2420 2 : pabyOut[static_cast<GPtrDiff_t>(nDstOffset)] =
2421 2 : pabyWrkBuffer[nSrcIdx];
2422 : }
2423 : }
2424 8 : nDstOffset += nPixelSpace;
2425 8 : nSrcIdx++;
2426 : }
2427 : }
2428 : }
2429 : else
2430 : {
2431 9 : size_t nSrcIdx = 0;
2432 9 : double dfMaskVal = 0;
2433 9 : const int nBufDTSize = GDALGetDataTypeSizeBytes(eBufType);
2434 18 : std::vector<GByte> abyDstNoData(nBufDTSize);
2435 9 : GDALCopyWords(&m_dfNoDataValue, GDT_Float64, 0, abyDstNoData.data(),
2436 : eBufType, 0, 1);
2437 18 : std::vector<GByte> abyRemappedValue(nBufDTSize);
2438 9 : GDALCopyWords(&dfRemappedValue, GDT_Float64, 0, abyRemappedValue.data(),
2439 : eBufType, 0, 1);
2440 18 : for (int iY = 0; iY < nOutYSize; iY++)
2441 : {
2442 9 : GSpacing nDstOffset = iY * nLineSpace;
2443 28 : for (int iX = 0; iX < nOutXSize; iX++)
2444 : {
2445 19 : if (eSrcMaskBandDT == GDT_Byte)
2446 : {
2447 19 : dfMaskVal = oWorkingState.m_abyWrkBufferMask[nSrcIdx];
2448 : }
2449 : else
2450 : {
2451 0 : GDALCopyWords(oWorkingState.m_abyWrkBufferMask.data() +
2452 0 : nSrcIdx * nSrcMaskBandDTSize,
2453 : eSrcMaskBandDT, 0, &dfMaskVal, GDT_Float64, 0,
2454 : 1);
2455 : }
2456 19 : void *const pDst =
2457 19 : pabyOut + static_cast<GPtrDiff_t>(nDstOffset);
2458 19 : if (!(dfMaskVal > m_dfMaskValueThreshold))
2459 : {
2460 9 : memcpy(pDst, abyDstNoData.data(), nBufDTSize);
2461 : }
2462 : else
2463 : {
2464 10 : const void *const pSrc =
2465 10 : pabyWrkBuffer + nSrcIdx * nSrcBandDTSize;
2466 10 : if (eSrcBandDT == eBufType)
2467 : {
2468 : // coverity[overrun-buffer-arg]
2469 8 : memcpy(pDst, pSrc, nBufDTSize);
2470 : }
2471 : else
2472 : {
2473 2 : GDALCopyWords(pSrc, eSrcBandDT, 0, pDst, eBufType, 0,
2474 : 1);
2475 : }
2476 10 : if (memcmp(pDst, abyDstNoData.data(), nBufDTSize) == 0)
2477 9 : memcpy(pDst, abyRemappedValue.data(), nBufDTSize);
2478 : }
2479 19 : nDstOffset += nPixelSpace;
2480 19 : nSrcIdx++;
2481 : }
2482 : }
2483 : }
2484 :
2485 13 : if (psExtraArg->pfnProgress)
2486 0 : psExtraArg->pfnProgress(1.0, "", psExtraArg->pProgressData);
2487 :
2488 13 : return CE_None;
2489 : }
2490 :
2491 : /************************************************************************/
2492 : /* GetMinimum() */
2493 : /************************************************************************/
2494 :
2495 0 : double VRTNoDataFromMaskSource::GetMinimum(int /* nXSize */, int /* nYSize */,
2496 : int *pbSuccess)
2497 : {
2498 0 : *pbSuccess = FALSE;
2499 0 : return 0.0;
2500 : }
2501 :
2502 : /************************************************************************/
2503 : /* GetMaximum() */
2504 : /************************************************************************/
2505 :
2506 0 : double VRTNoDataFromMaskSource::GetMaximum(int /* nXSize */, int /* nYSize */,
2507 : int *pbSuccess)
2508 : {
2509 0 : *pbSuccess = FALSE;
2510 0 : return 0.0;
2511 : }
2512 :
2513 : /************************************************************************/
2514 : /* GetHistogram() */
2515 : /************************************************************************/
2516 :
2517 0 : CPLErr VRTNoDataFromMaskSource::GetHistogram(
2518 : int /* nXSize */, int /* nYSize */, double /* dfMin */, double /* dfMax */,
2519 : int /* nBuckets */, GUIntBig * /* panHistogram */,
2520 : int /* bIncludeOutOfRange */, int /* bApproxOK */,
2521 : GDALProgressFunc /* pfnProgress */, void * /* pProgressData */)
2522 : {
2523 0 : return CE_Failure;
2524 : }
2525 :
2526 : /************************************************************************/
2527 : /* ==================================================================== */
2528 : /* VRTComplexSource */
2529 : /* ==================================================================== */
2530 : /************************************************************************/
2531 :
2532 : /************************************************************************/
2533 : /* VRTComplexSource() */
2534 : /************************************************************************/
2535 :
2536 5 : VRTComplexSource::VRTComplexSource(const VRTComplexSource *poSrcSource,
2537 5 : double dfXDstRatio, double dfYDstRatio)
2538 : : VRTSimpleSource(poSrcSource, dfXDstRatio, dfYDstRatio),
2539 5 : m_nProcessingFlags(poSrcSource->m_nProcessingFlags),
2540 5 : m_dfNoDataValue(poSrcSource->m_dfNoDataValue),
2541 5 : m_osNoDataValueOri(poSrcSource->m_osNoDataValueOri),
2542 5 : m_dfScaleOff(poSrcSource->m_dfScaleOff),
2543 5 : m_dfScaleRatio(poSrcSource->m_dfScaleRatio),
2544 5 : m_bSrcMinMaxDefined(poSrcSource->m_bSrcMinMaxDefined),
2545 5 : m_dfSrcMin(poSrcSource->m_dfSrcMin), m_dfSrcMax(poSrcSource->m_dfSrcMax),
2546 5 : m_dfDstMin(poSrcSource->m_dfDstMin), m_dfDstMax(poSrcSource->m_dfDstMax),
2547 5 : m_dfExponent(poSrcSource->m_dfExponent),
2548 5 : m_nColorTableComponent(poSrcSource->m_nColorTableComponent),
2549 5 : m_adfLUTInputs(poSrcSource->m_adfLUTInputs),
2550 5 : m_adfLUTOutputs(poSrcSource->m_adfLUTOutputs)
2551 : {
2552 5 : }
2553 :
2554 : /************************************************************************/
2555 : /* GetTypeStatic() */
2556 : /************************************************************************/
2557 :
2558 623 : const char *VRTComplexSource::GetTypeStatic()
2559 : {
2560 : static const char *TYPE = "ComplexSource";
2561 623 : return TYPE;
2562 : }
2563 :
2564 : /************************************************************************/
2565 : /* GetType() */
2566 : /************************************************************************/
2567 :
2568 351 : const char *VRTComplexSource::GetType() const
2569 : {
2570 351 : return GetTypeStatic();
2571 : }
2572 :
2573 : /************************************************************************/
2574 : /* SetNoDataValue() */
2575 : /************************************************************************/
2576 :
2577 51 : void VRTComplexSource::SetNoDataValue(double dfNewNoDataValue)
2578 :
2579 : {
2580 51 : if (dfNewNoDataValue == VRT_NODATA_UNSET)
2581 : {
2582 0 : m_nProcessingFlags &= ~PROCESSING_FLAG_NODATA;
2583 0 : m_dfNoDataValue = VRT_NODATA_UNSET;
2584 0 : return;
2585 : }
2586 :
2587 51 : m_nProcessingFlags |= PROCESSING_FLAG_NODATA;
2588 51 : m_dfNoDataValue = dfNewNoDataValue;
2589 : }
2590 :
2591 : /************************************************************************/
2592 : /* GetAdjustedNoDataValue() */
2593 : /************************************************************************/
2594 :
2595 4684 : double VRTComplexSource::GetAdjustedNoDataValue() const
2596 : {
2597 4684 : if ((m_nProcessingFlags & PROCESSING_FLAG_NODATA) != 0)
2598 : {
2599 24 : auto l_band = GetRasterBand();
2600 24 : if (l_band && l_band->GetRasterDataType() == GDT_Float32)
2601 : {
2602 9 : return GDALAdjustNoDataCloseToFloatMax(m_dfNoDataValue);
2603 : }
2604 : }
2605 4675 : return m_dfNoDataValue;
2606 : }
2607 :
2608 : /************************************************************************/
2609 : /* SerializeToXML() */
2610 : /************************************************************************/
2611 :
2612 49 : CPLXMLNode *VRTComplexSource::SerializeToXML(const char *pszVRTPath)
2613 :
2614 : {
2615 49 : CPLXMLNode *psSrc = VRTSimpleSource::SerializeToXML(pszVRTPath);
2616 :
2617 49 : if (psSrc == nullptr)
2618 0 : return nullptr;
2619 :
2620 49 : CPLFree(psSrc->pszValue);
2621 49 : psSrc->pszValue = CPLStrdup(GetTypeStatic());
2622 :
2623 49 : if ((m_nProcessingFlags & PROCESSING_FLAG_USE_MASK_BAND) != 0)
2624 : {
2625 14 : CPLSetXMLValue(psSrc, "UseMaskBand", "true");
2626 : }
2627 :
2628 49 : if ((m_nProcessingFlags & PROCESSING_FLAG_NODATA) != 0)
2629 : {
2630 25 : if (!m_osNoDataValueOri.empty() && GetRasterBandNoOpen() == nullptr)
2631 : {
2632 2 : CPLSetXMLValue(psSrc, "NODATA", m_osNoDataValueOri.c_str());
2633 : }
2634 : else
2635 : {
2636 23 : GDALDataType eBandDT = GDT_Unknown;
2637 23 : double dfNoDataValue = m_dfNoDataValue;
2638 23 : const auto kMaxFloat = std::numeric_limits<float>::max();
2639 23 : if (std::fabs(std::fabs(m_dfNoDataValue) - kMaxFloat) <
2640 : 1e-10 * kMaxFloat)
2641 : {
2642 1 : auto l_band = GetRasterBand();
2643 1 : if (l_band)
2644 : {
2645 1 : dfNoDataValue = GetAdjustedNoDataValue();
2646 1 : eBandDT = l_band->GetRasterDataType();
2647 : }
2648 : }
2649 23 : CPLSetXMLValue(
2650 : psSrc, "NODATA",
2651 46 : VRTSerializeNoData(dfNoDataValue, eBandDT, 18).c_str());
2652 : }
2653 : }
2654 :
2655 49 : if ((m_nProcessingFlags & PROCESSING_FLAG_SCALING_LINEAR) != 0)
2656 : {
2657 1 : CPLSetXMLValue(psSrc, "ScaleOffset", CPLSPrintf("%g", m_dfScaleOff));
2658 1 : CPLSetXMLValue(psSrc, "ScaleRatio", CPLSPrintf("%g", m_dfScaleRatio));
2659 : }
2660 48 : else if ((m_nProcessingFlags & PROCESSING_FLAG_SCALING_EXPONENTIAL) != 0)
2661 : {
2662 0 : CPLSetXMLValue(psSrc, "Exponent", CPLSPrintf("%g", m_dfExponent));
2663 0 : if (m_bSrcMinMaxDefined)
2664 : {
2665 0 : CPLSetXMLValue(psSrc, "SrcMin", CPLSPrintf("%g", m_dfSrcMin));
2666 0 : CPLSetXMLValue(psSrc, "SrcMax", CPLSPrintf("%g", m_dfSrcMax));
2667 : }
2668 0 : CPLSetXMLValue(psSrc, "DstMin", CPLSPrintf("%g", m_dfDstMin));
2669 0 : CPLSetXMLValue(psSrc, "DstMax", CPLSPrintf("%g", m_dfDstMax));
2670 : }
2671 :
2672 49 : if (!m_adfLUTInputs.empty())
2673 : {
2674 : // Make sure we print with sufficient precision to address really close
2675 : // entries (#6422).
2676 0 : CPLString osLUT;
2677 0 : if (m_adfLUTInputs.size() >= 2 &&
2678 0 : CPLString().Printf("%g", m_adfLUTInputs[0]) ==
2679 0 : CPLString().Printf("%g", m_adfLUTInputs[1]))
2680 : {
2681 0 : osLUT = CPLString().Printf("%.17g:%g", m_adfLUTInputs[0],
2682 0 : m_adfLUTOutputs[0]);
2683 : }
2684 : else
2685 : {
2686 0 : osLUT = CPLString().Printf("%g:%g", m_adfLUTInputs[0],
2687 0 : m_adfLUTOutputs[0]);
2688 : }
2689 0 : for (size_t i = 1; i < m_adfLUTInputs.size(); i++)
2690 : {
2691 0 : if (CPLString().Printf("%g", m_adfLUTInputs[i]) ==
2692 0 : CPLString().Printf("%g", m_adfLUTInputs[i - 1]) ||
2693 0 : (i + 1 < m_adfLUTInputs.size() &&
2694 0 : CPLString().Printf("%g", m_adfLUTInputs[i]) ==
2695 0 : CPLString().Printf("%g", m_adfLUTInputs[i + 1])))
2696 : {
2697 : // TODO(schwehr): An explanation of the 18 would be helpful.
2698 : // Can someone distill the issue down to a quick comment?
2699 : // https://trac.osgeo.org/gdal/ticket/6422
2700 0 : osLUT += CPLString().Printf(",%.17g:%g", m_adfLUTInputs[i],
2701 0 : m_adfLUTOutputs[i]);
2702 : }
2703 : else
2704 : {
2705 0 : osLUT += CPLString().Printf(",%g:%g", m_adfLUTInputs[i],
2706 0 : m_adfLUTOutputs[i]);
2707 : }
2708 : }
2709 0 : CPLSetXMLValue(psSrc, "LUT", osLUT);
2710 : }
2711 :
2712 49 : if (m_nColorTableComponent)
2713 : {
2714 7 : CPLSetXMLValue(psSrc, "ColorTableComponent",
2715 : CPLSPrintf("%d", m_nColorTableComponent));
2716 : }
2717 :
2718 49 : return psSrc;
2719 : }
2720 :
2721 : /************************************************************************/
2722 : /* XMLInit() */
2723 : /************************************************************************/
2724 :
2725 201 : CPLErr VRTComplexSource::XMLInit(const CPLXMLNode *psSrc,
2726 : const char *pszVRTPath,
2727 : VRTMapSharedResources &oMapSharedSources)
2728 :
2729 : {
2730 : /* -------------------------------------------------------------------- */
2731 : /* Do base initialization. */
2732 : /* -------------------------------------------------------------------- */
2733 : {
2734 : const CPLErr eErr =
2735 201 : VRTSimpleSource::XMLInit(psSrc, pszVRTPath, oMapSharedSources);
2736 201 : if (eErr != CE_None)
2737 0 : return eErr;
2738 : }
2739 :
2740 : /* -------------------------------------------------------------------- */
2741 : /* Complex parameters. */
2742 : /* -------------------------------------------------------------------- */
2743 201 : const char *pszScaleOffset = CPLGetXMLValue(psSrc, "ScaleOffset", nullptr);
2744 201 : const char *pszScaleRatio = CPLGetXMLValue(psSrc, "ScaleRatio", nullptr);
2745 201 : if (pszScaleOffset || pszScaleRatio)
2746 : {
2747 18 : m_nProcessingFlags |= PROCESSING_FLAG_SCALING_LINEAR;
2748 18 : if (pszScaleOffset)
2749 18 : m_dfScaleOff = CPLAtof(pszScaleOffset);
2750 18 : if (pszScaleRatio)
2751 15 : m_dfScaleRatio = CPLAtof(pszScaleRatio);
2752 : }
2753 183 : else if (CPLGetXMLValue(psSrc, "Exponent", nullptr) != nullptr &&
2754 184 : CPLGetXMLValue(psSrc, "DstMin", nullptr) != nullptr &&
2755 1 : CPLGetXMLValue(psSrc, "DstMax", nullptr) != nullptr)
2756 : {
2757 1 : m_nProcessingFlags |= PROCESSING_FLAG_SCALING_EXPONENTIAL;
2758 1 : m_dfExponent = CPLAtof(CPLGetXMLValue(psSrc, "Exponent", "1.0"));
2759 :
2760 1 : const char *pszSrcMin = CPLGetXMLValue(psSrc, "SrcMin", nullptr);
2761 1 : const char *pszSrcMax = CPLGetXMLValue(psSrc, "SrcMax", nullptr);
2762 1 : if (pszSrcMin && pszSrcMax)
2763 : {
2764 0 : m_dfSrcMin = CPLAtof(pszSrcMin);
2765 0 : m_dfSrcMax = CPLAtof(pszSrcMax);
2766 0 : m_bSrcMinMaxDefined = true;
2767 : }
2768 :
2769 1 : m_dfDstMin = CPLAtof(CPLGetXMLValue(psSrc, "DstMin", "0.0"));
2770 1 : m_dfDstMax = CPLAtof(CPLGetXMLValue(psSrc, "DstMax", "0.0"));
2771 : }
2772 :
2773 201 : if (const char *pszNODATA = CPLGetXMLValue(psSrc, "NODATA", nullptr))
2774 : {
2775 50 : m_nProcessingFlags |= PROCESSING_FLAG_NODATA;
2776 50 : m_osNoDataValueOri = pszNODATA;
2777 50 : m_dfNoDataValue = CPLAtofM(m_osNoDataValueOri.c_str());
2778 : }
2779 :
2780 201 : const char *pszUseMaskBand = CPLGetXMLValue(psSrc, "UseMaskBand", nullptr);
2781 201 : if (pszUseMaskBand && CPLTestBool(pszUseMaskBand))
2782 : {
2783 22 : m_nProcessingFlags |= PROCESSING_FLAG_USE_MASK_BAND;
2784 : }
2785 :
2786 201 : const char *pszLUT = CPLGetXMLValue(psSrc, "LUT", nullptr);
2787 201 : if (pszLUT)
2788 : {
2789 : const CPLStringList aosValues(
2790 59 : CSLTokenizeString2(pszLUT, ",:", CSLT_ALLOWEMPTYTOKENS));
2791 :
2792 59 : const int nLUTItemCount = aosValues.size() / 2;
2793 : try
2794 : {
2795 59 : m_adfLUTInputs.resize(nLUTItemCount);
2796 59 : m_adfLUTOutputs.resize(nLUTItemCount);
2797 : }
2798 0 : catch (const std::bad_alloc &e)
2799 : {
2800 0 : CPLError(CE_Failure, CPLE_OutOfMemory, "%s", e.what());
2801 0 : m_adfLUTInputs.clear();
2802 0 : m_adfLUTOutputs.clear();
2803 0 : return CE_Failure;
2804 : }
2805 :
2806 544 : for (int nIndex = 0; nIndex < nLUTItemCount; nIndex++)
2807 : {
2808 485 : m_adfLUTInputs[nIndex] = CPLAtof(aosValues[nIndex * 2]);
2809 485 : m_adfLUTOutputs[nIndex] = CPLAtof(aosValues[nIndex * 2 + 1]);
2810 :
2811 : // Enforce the requirement that the LUT input array is
2812 : // monotonically non-decreasing.
2813 485 : if (std::isnan(m_adfLUTInputs[nIndex]) && nIndex != 0)
2814 : {
2815 0 : CPLError(CE_Failure, CPLE_AppDefined,
2816 : "A Not-A-Number (NaN) source value should be the "
2817 : "first one of the LUT.");
2818 0 : m_adfLUTInputs.clear();
2819 0 : m_adfLUTOutputs.clear();
2820 0 : return CE_Failure;
2821 : }
2822 911 : else if (nIndex > 0 &&
2823 426 : m_adfLUTInputs[nIndex] < m_adfLUTInputs[nIndex - 1])
2824 : {
2825 0 : CPLError(CE_Failure, CPLE_AppDefined,
2826 : "Source values of the LUT are not listed in a "
2827 : "monotonically non-decreasing order");
2828 0 : m_adfLUTInputs.clear();
2829 0 : m_adfLUTOutputs.clear();
2830 0 : return CE_Failure;
2831 : }
2832 : }
2833 :
2834 59 : m_nProcessingFlags |= PROCESSING_FLAG_LUT;
2835 : }
2836 :
2837 : const char *pszColorTableComponent =
2838 201 : CPLGetXMLValue(psSrc, "ColorTableComponent", nullptr);
2839 201 : if (pszColorTableComponent)
2840 : {
2841 15 : m_nColorTableComponent = atoi(pszColorTableComponent);
2842 15 : m_nProcessingFlags |= PROCESSING_FLAG_COLOR_TABLE_EXPANSION;
2843 : }
2844 :
2845 201 : return CE_None;
2846 : }
2847 :
2848 : /************************************************************************/
2849 : /* LookupValue() */
2850 : /************************************************************************/
2851 :
2852 583336 : double VRTComplexSource::LookupValue(double dfInput)
2853 : {
2854 583336 : auto beginIter = m_adfLUTInputs.begin();
2855 583336 : auto endIter = m_adfLUTInputs.end();
2856 583336 : size_t offset = 0;
2857 583336 : if (std::isnan(m_adfLUTInputs[0]))
2858 : {
2859 6 : if (std::isnan(dfInput) || m_adfLUTInputs.size() == 1)
2860 1 : return m_adfLUTOutputs[0];
2861 5 : ++beginIter;
2862 5 : offset = 1;
2863 : }
2864 :
2865 : // Find the index of the first element in the LUT input array that
2866 : // is not smaller than the input value.
2867 : const size_t i =
2868 : offset +
2869 583335 : std::distance(beginIter, std::lower_bound(beginIter, endIter, dfInput));
2870 :
2871 583335 : if (i == offset)
2872 129039 : return m_adfLUTOutputs[offset];
2873 :
2874 : // If the index is beyond the end of the LUT input array, the input
2875 : // value is larger than all the values in the array.
2876 454296 : if (i == m_adfLUTInputs.size())
2877 8 : return m_adfLUTOutputs.back();
2878 :
2879 454288 : if (m_adfLUTInputs[i] == dfInput)
2880 179297 : return m_adfLUTOutputs[i];
2881 :
2882 : // Otherwise, interpolate.
2883 274991 : return m_adfLUTOutputs[i - 1] +
2884 274991 : (dfInput - m_adfLUTInputs[i - 1]) *
2885 274991 : ((m_adfLUTOutputs[i] - m_adfLUTOutputs[i - 1]) /
2886 274991 : (m_adfLUTInputs[i] - m_adfLUTInputs[i - 1]));
2887 : }
2888 :
2889 : /************************************************************************/
2890 : /* SetLinearScaling() */
2891 : /************************************************************************/
2892 :
2893 86 : void VRTComplexSource::SetLinearScaling(double dfOffset, double dfScale)
2894 : {
2895 86 : m_nProcessingFlags &= ~PROCESSING_FLAG_SCALING_EXPONENTIAL;
2896 86 : m_nProcessingFlags |= PROCESSING_FLAG_SCALING_LINEAR;
2897 86 : m_dfScaleOff = dfOffset;
2898 86 : m_dfScaleRatio = dfScale;
2899 86 : }
2900 :
2901 : /************************************************************************/
2902 : /* SetPowerScaling() */
2903 : /************************************************************************/
2904 :
2905 8 : void VRTComplexSource::SetPowerScaling(double dfExponentIn, double dfSrcMinIn,
2906 : double dfSrcMaxIn, double dfDstMinIn,
2907 : double dfDstMaxIn)
2908 : {
2909 8 : m_nProcessingFlags &= ~PROCESSING_FLAG_SCALING_LINEAR;
2910 8 : m_nProcessingFlags |= PROCESSING_FLAG_SCALING_EXPONENTIAL;
2911 8 : m_dfExponent = dfExponentIn;
2912 8 : m_dfSrcMin = dfSrcMinIn;
2913 8 : m_dfSrcMax = dfSrcMaxIn;
2914 8 : m_dfDstMin = dfDstMinIn;
2915 8 : m_dfDstMax = dfDstMaxIn;
2916 8 : m_bSrcMinMaxDefined = true;
2917 8 : }
2918 :
2919 : /************************************************************************/
2920 : /* SetColorTableComponent() */
2921 : /************************************************************************/
2922 :
2923 172 : void VRTComplexSource::SetColorTableComponent(int nComponent)
2924 : {
2925 172 : m_nProcessingFlags |= PROCESSING_FLAG_COLOR_TABLE_EXPANSION;
2926 172 : m_nColorTableComponent = nComponent;
2927 172 : }
2928 :
2929 : /************************************************************************/
2930 : /* RasterIO() */
2931 : /************************************************************************/
2932 :
2933 15659 : CPLErr VRTComplexSource::RasterIO(GDALDataType eVRTBandDataType, int nXOff,
2934 : int nYOff, int nXSize, int nYSize,
2935 : void *pData, int nBufXSize, int nBufYSize,
2936 : GDALDataType eBufType, GSpacing nPixelSpace,
2937 : GSpacing nLineSpace,
2938 : GDALRasterIOExtraArg *psExtraArgIn,
2939 : WorkingState &oWorkingState)
2940 :
2941 : {
2942 : GDALRasterIOExtraArg sExtraArg;
2943 15659 : INIT_RASTERIO_EXTRA_ARG(sExtraArg);
2944 15659 : GDALRasterIOExtraArg *psExtraArg = &sExtraArg;
2945 :
2946 15659 : double dfXOff = nXOff;
2947 15659 : double dfYOff = nYOff;
2948 15659 : double dfXSize = nXSize;
2949 15659 : double dfYSize = nYSize;
2950 15659 : if (psExtraArgIn != nullptr && psExtraArgIn->bFloatingPointWindowValidity)
2951 : {
2952 87 : dfXOff = psExtraArgIn->dfXOff;
2953 87 : dfYOff = psExtraArgIn->dfYOff;
2954 87 : dfXSize = psExtraArgIn->dfXSize;
2955 87 : dfYSize = psExtraArgIn->dfYSize;
2956 : }
2957 :
2958 : // The window we will actually request from the source raster band.
2959 15659 : double dfReqXOff = 0.0;
2960 15659 : double dfReqYOff = 0.0;
2961 15659 : double dfReqXSize = 0.0;
2962 15659 : double dfReqYSize = 0.0;
2963 15659 : int nReqXOff = 0;
2964 15659 : int nReqYOff = 0;
2965 15659 : int nReqXSize = 0;
2966 15659 : int nReqYSize = 0;
2967 :
2968 : // The window we will actual set _within_ the pData buffer.
2969 15659 : int nOutXOff = 0;
2970 15659 : int nOutYOff = 0;
2971 15659 : int nOutXSize = 0;
2972 15659 : int nOutYSize = 0;
2973 :
2974 15659 : bool bError = false;
2975 15659 : if (!GetSrcDstWindow(dfXOff, dfYOff, dfXSize, dfYSize, nBufXSize, nBufYSize,
2976 : &dfReqXOff, &dfReqYOff, &dfReqXSize, &dfReqYSize,
2977 : &nReqXOff, &nReqYOff, &nReqXSize, &nReqYSize,
2978 : &nOutXOff, &nOutYOff, &nOutXSize, &nOutYSize, bError))
2979 : {
2980 10946 : return bError ? CE_Failure : CE_None;
2981 : }
2982 : #if DEBUG_VERBOSE
2983 : CPLDebug("VRT",
2984 : "nXOff=%d, nYOff=%d, nXSize=%d, nYSize=%d, nBufXSize=%d, "
2985 : "nBufYSize=%d,\n"
2986 : "dfReqXOff=%g, dfReqYOff=%g, dfReqXSize=%g, dfReqYSize=%g,\n"
2987 : "nReqXOff=%d, nReqYOff=%d, nReqXSize=%d, nReqYSize=%d,\n"
2988 : "nOutXOff=%d, nOutYOff=%d, nOutXSize=%d, nOutYSize=%d",
2989 : nXOff, nYOff, nXSize, nYSize, nBufXSize, nBufYSize, dfReqXOff,
2990 : dfReqYOff, dfReqXSize, dfReqYSize, nReqXOff, nReqYOff, nReqXSize,
2991 : nReqYSize, nOutXOff, nOutYOff, nOutXSize, nOutYSize);
2992 : #endif
2993 :
2994 4713 : auto poSourceBand = GetRasterBand();
2995 4713 : if (!poSourceBand)
2996 0 : return CE_Failure;
2997 :
2998 4713 : if (!m_osResampling.empty())
2999 : {
3000 0 : psExtraArg->eResampleAlg = GDALRasterIOGetResampleAlg(m_osResampling);
3001 : }
3002 4713 : else if (psExtraArgIn != nullptr)
3003 : {
3004 4713 : psExtraArg->eResampleAlg = psExtraArgIn->eResampleAlg;
3005 : }
3006 4713 : psExtraArg->bFloatingPointWindowValidity = TRUE;
3007 4713 : psExtraArg->dfXOff = dfReqXOff;
3008 4713 : psExtraArg->dfYOff = dfReqYOff;
3009 4713 : psExtraArg->dfXSize = dfReqXSize;
3010 4713 : psExtraArg->dfYSize = dfReqYSize;
3011 4713 : if (psExtraArgIn)
3012 : {
3013 4713 : psExtraArg->pfnProgress = psExtraArgIn->pfnProgress;
3014 4713 : psExtraArg->pProgressData = psExtraArgIn->pProgressData;
3015 : }
3016 :
3017 4713 : GByte *const pabyOut = static_cast<GByte *>(pData) +
3018 4713 : nPixelSpace * nOutXOff +
3019 4713 : static_cast<GPtrDiff_t>(nLineSpace) * nOutYOff;
3020 4713 : const auto eSourceType = poSourceBand->GetRasterDataType();
3021 4713 : if (m_nProcessingFlags == PROCESSING_FLAG_NODATA)
3022 : {
3023 : // Optimization if doing only nodata processing
3024 63 : if (eSourceType == GDT_Byte)
3025 : {
3026 33 : if (!GDALIsValueInRange<GByte>(m_dfNoDataValue))
3027 : {
3028 1 : return VRTSimpleSource::RasterIO(
3029 : eVRTBandDataType, nXOff, nYOff, nXSize, nYSize, pData,
3030 : nBufXSize, nBufYSize, eBufType, nPixelSpace, nLineSpace,
3031 1 : psExtraArgIn, oWorkingState);
3032 : }
3033 :
3034 33 : return RasterIOProcessNoData<GByte, GDT_Byte>(
3035 : poSourceBand, eVRTBandDataType, nReqXOff, nReqYOff, nReqXSize,
3036 : nReqYSize, pabyOut, nOutXSize, nOutYSize, eBufType, nPixelSpace,
3037 33 : nLineSpace, psExtraArg, oWorkingState);
3038 : }
3039 30 : else if (eSourceType == GDT_Int16)
3040 : {
3041 2 : if (!GDALIsValueInRange<int16_t>(m_dfNoDataValue))
3042 : {
3043 1 : return VRTSimpleSource::RasterIO(
3044 : eVRTBandDataType, nXOff, nYOff, nXSize, nYSize, pData,
3045 : nBufXSize, nBufYSize, eBufType, nPixelSpace, nLineSpace,
3046 1 : psExtraArgIn, oWorkingState);
3047 : }
3048 :
3049 1 : return RasterIOProcessNoData<int16_t, GDT_Int16>(
3050 : poSourceBand, eVRTBandDataType, nReqXOff, nReqYOff, nReqXSize,
3051 : nReqYSize, pabyOut, nOutXSize, nOutYSize, eBufType, nPixelSpace,
3052 1 : nLineSpace, psExtraArg, oWorkingState);
3053 : }
3054 28 : else if (eSourceType == GDT_UInt16)
3055 : {
3056 8 : if (!GDALIsValueInRange<uint16_t>(m_dfNoDataValue))
3057 : {
3058 1 : return VRTSimpleSource::RasterIO(
3059 : eVRTBandDataType, nXOff, nYOff, nXSize, nYSize, pData,
3060 : nBufXSize, nBufYSize, eBufType, nPixelSpace, nLineSpace,
3061 1 : psExtraArgIn, oWorkingState);
3062 : }
3063 :
3064 7 : return RasterIOProcessNoData<uint16_t, GDT_UInt16>(
3065 : poSourceBand, eVRTBandDataType, nReqXOff, nReqYOff, nReqXSize,
3066 : nReqYSize, pabyOut, nOutXSize, nOutYSize, eBufType, nPixelSpace,
3067 7 : nLineSpace, psExtraArg, oWorkingState);
3068 : }
3069 : }
3070 :
3071 4670 : const bool bIsComplex = CPL_TO_BOOL(GDALDataTypeIsComplex(eBufType));
3072 : CPLErr eErr;
3073 : // For Int32, float32 isn't sufficiently precise as working data type
3074 4669 : if (eVRTBandDataType == GDT_CInt32 || eVRTBandDataType == GDT_CFloat64 ||
3075 4667 : eVRTBandDataType == GDT_Int32 || eVRTBandDataType == GDT_UInt32 ||
3076 4665 : eVRTBandDataType == GDT_Int64 || eVRTBandDataType == GDT_UInt64 ||
3077 4660 : eVRTBandDataType == GDT_Float64 || eSourceType == GDT_Int32 ||
3078 4659 : eSourceType == GDT_UInt32 || eSourceType == GDT_Int64 ||
3079 : eSourceType == GDT_UInt64)
3080 : {
3081 11 : eErr = RasterIOInternal<double>(
3082 : poSourceBand, eVRTBandDataType, nReqXOff, nReqYOff, nReqXSize,
3083 : nReqYSize, pabyOut, nOutXSize, nOutYSize, eBufType, nPixelSpace,
3084 : nLineSpace, psExtraArg, bIsComplex ? GDT_CFloat64 : GDT_Float64,
3085 : oWorkingState);
3086 : }
3087 : else
3088 : {
3089 4658 : eErr = RasterIOInternal<float>(
3090 : poSourceBand, eVRTBandDataType, nReqXOff, nReqYOff, nReqXSize,
3091 : nReqYSize, pabyOut, nOutXSize, nOutYSize, eBufType, nPixelSpace,
3092 : nLineSpace, psExtraArg, bIsComplex ? GDT_CFloat32 : GDT_Float32,
3093 : oWorkingState);
3094 : }
3095 :
3096 4669 : if (psExtraArg->pfnProgress)
3097 43 : psExtraArg->pfnProgress(1.0, "", psExtraArg->pProgressData);
3098 :
3099 4669 : return eErr;
3100 : }
3101 :
3102 : /************************************************************************/
3103 : /* hasZeroByte() */
3104 : /************************************************************************/
3105 :
3106 : CPL_NOSANITIZE_UNSIGNED_INT_OVERFLOW
3107 3698500 : static inline bool hasZeroByte(uint32_t v)
3108 : {
3109 : // Cf https://graphics.stanford.edu/~seander/bithacks.html#ZeroInWord
3110 3698500 : return (((v)-0x01010101U) & ~(v)&0x80808080U) != 0;
3111 : }
3112 :
3113 : /************************************************************************/
3114 : /* CopyWord() */
3115 : /************************************************************************/
3116 :
3117 : template <class SrcType>
3118 6418480 : static void CopyWord(const SrcType *pSrcVal, GDALDataType eSrcType,
3119 : void *pDstVal, GDALDataType eDstType)
3120 : {
3121 6418480 : switch (eDstType)
3122 : {
3123 2144660 : case GDT_Byte:
3124 2144660 : GDALCopyWord(*pSrcVal, *static_cast<uint8_t *>(pDstVal));
3125 2144660 : break;
3126 80 : case GDT_Int8:
3127 80 : GDALCopyWord(*pSrcVal, *static_cast<int8_t *>(pDstVal));
3128 80 : break;
3129 1348720 : case GDT_UInt16:
3130 1348720 : GDALCopyWord(*pSrcVal, *static_cast<uint16_t *>(pDstVal));
3131 1348720 : break;
3132 2920180 : case GDT_Int16:
3133 2920180 : GDALCopyWord(*pSrcVal, *static_cast<int16_t *>(pDstVal));
3134 2920180 : break;
3135 20 : case GDT_UInt32:
3136 20 : GDALCopyWord(*pSrcVal, *static_cast<uint32_t *>(pDstVal));
3137 20 : break;
3138 638 : case GDT_Int32:
3139 638 : GDALCopyWord(*pSrcVal, *static_cast<int32_t *>(pDstVal));
3140 638 : break;
3141 20 : case GDT_UInt64:
3142 20 : GDALCopyWord(*pSrcVal, *static_cast<uint64_t *>(pDstVal));
3143 20 : break;
3144 40 : case GDT_Int64:
3145 40 : GDALCopyWord(*pSrcVal, *static_cast<int64_t *>(pDstVal));
3146 40 : break;
3147 1650 : case GDT_Float32:
3148 1650 : GDALCopyWord(*pSrcVal, *static_cast<float *>(pDstVal));
3149 1650 : break;
3150 1461 : case GDT_Float64:
3151 1461 : GDALCopyWord(*pSrcVal, *static_cast<double *>(pDstVal));
3152 1461 : break;
3153 1016 : default:
3154 1016 : GDALCopyWords(pSrcVal, eSrcType, 0, pDstVal, eDstType, 0, 1);
3155 1016 : break;
3156 : }
3157 6418480 : }
3158 :
3159 : /************************************************************************/
3160 : /* RasterIOProcessNoData() */
3161 : /************************************************************************/
3162 :
3163 : // This method is an optimization of the generic RasterIOInternal()
3164 : // that deals with a VRTComplexSource with only a NODATA value in it, and
3165 : // no other processing flags.
3166 :
3167 : // nReqXOff, nReqYOff, nReqXSize, nReqYSize are expressed in source band
3168 : // referential.
3169 : template <class SourceDT, GDALDataType eSourceType>
3170 40 : CPLErr VRTComplexSource::RasterIOProcessNoData(
3171 : GDALRasterBand *poSourceBand, GDALDataType eVRTBandDataType, int nReqXOff,
3172 : int nReqYOff, int nReqXSize, int nReqYSize, void *pData, int nOutXSize,
3173 : int nOutYSize, GDALDataType eBufType, GSpacing nPixelSpace,
3174 : GSpacing nLineSpace, GDALRasterIOExtraArg *psExtraArg,
3175 : WorkingState &oWorkingState)
3176 : {
3177 40 : CPLAssert(m_nProcessingFlags == PROCESSING_FLAG_NODATA);
3178 40 : CPLAssert(GDALIsValueInRange<SourceDT>(m_dfNoDataValue));
3179 :
3180 : /* -------------------------------------------------------------------- */
3181 : /* Read into a temporary buffer. */
3182 : /* -------------------------------------------------------------------- */
3183 : try
3184 : {
3185 : // Cannot overflow since pData should at least have that number of
3186 : // elements
3187 41 : const size_t nPixelCount = static_cast<size_t>(nOutXSize) * nOutYSize;
3188 39 : if (nPixelCount >
3189 41 : static_cast<size_t>(std::numeric_limits<ptrdiff_t>::max()) /
3190 : sizeof(SourceDT))
3191 : {
3192 0 : CPLError(CE_Failure, CPLE_OutOfMemory,
3193 : "Too large temporary buffer");
3194 0 : return CE_Failure;
3195 : }
3196 39 : oWorkingState.m_abyWrkBuffer.resize(sizeof(SourceDT) * nPixelCount);
3197 : }
3198 0 : catch (const std::bad_alloc &e)
3199 : {
3200 0 : CPLError(CE_Failure, CPLE_OutOfMemory, "%s", e.what());
3201 0 : return CE_Failure;
3202 : }
3203 : const auto paSrcData =
3204 40 : reinterpret_cast<const SourceDT *>(oWorkingState.m_abyWrkBuffer.data());
3205 :
3206 39 : const GDALRIOResampleAlg eResampleAlgBack = psExtraArg->eResampleAlg;
3207 39 : if (!m_osResampling.empty())
3208 : {
3209 0 : psExtraArg->eResampleAlg = GDALRasterIOGetResampleAlg(m_osResampling);
3210 : }
3211 :
3212 39 : const CPLErr eErr = poSourceBand->RasterIO(
3213 : GF_Read, nReqXOff, nReqYOff, nReqXSize, nReqYSize,
3214 39 : oWorkingState.m_abyWrkBuffer.data(), nOutXSize, nOutYSize, eSourceType,
3215 8 : sizeof(SourceDT), sizeof(SourceDT) * static_cast<GSpacing>(nOutXSize),
3216 : psExtraArg);
3217 41 : if (!m_osResampling.empty())
3218 0 : psExtraArg->eResampleAlg = eResampleAlgBack;
3219 :
3220 41 : if (eErr != CE_None)
3221 : {
3222 0 : return eErr;
3223 : }
3224 :
3225 41 : const auto nNoDataValue = static_cast<SourceDT>(m_dfNoDataValue);
3226 41 : size_t idxBuffer = 0;
3227 72 : if (eSourceType == eBufType &&
3228 31 : !GDALDataTypeIsConversionLossy(eSourceType, eVRTBandDataType))
3229 : {
3230 : // Most optimized case: the output type is the same as the source type,
3231 : // and conversion from the source type to the VRT band data type is
3232 : // not lossy
3233 14 : for (int iY = 0; iY < nOutYSize; iY++)
3234 : {
3235 19605 : GByte *pDstLocation = static_cast<GByte *>(pData) +
3236 19605 : static_cast<GPtrDiff_t>(nLineSpace) * iY;
3237 :
3238 19605 : int iX = 0;
3239 19593 : if (sizeof(SourceDT) == 1 && nPixelSpace == 1)
3240 : {
3241 : // Optimization to detect more quickly if source pixels are
3242 : // at nodata.
3243 19591 : const GByte byNoDataValue = static_cast<GByte>(nNoDataValue);
3244 19591 : const uint32_t wordNoData =
3245 19591 : (static_cast<uint32_t>(byNoDataValue) << 24) |
3246 19591 : (byNoDataValue << 16) | (byNoDataValue << 8) |
3247 19591 : byNoDataValue;
3248 :
3249 : // Warning: hasZeroByte() assumes WORD_SIZE = 4
3250 19591 : constexpr int WORD_SIZE = 4;
3251 3670180 : for (; iX < nOutXSize - (WORD_SIZE - 1); iX += WORD_SIZE)
3252 : {
3253 : uint32_t v;
3254 : static_assert(sizeof(v) == WORD_SIZE,
3255 : "sizeof(v) == WORD_SIZE");
3256 3741500 : memcpy(&v, paSrcData + idxBuffer, sizeof(v));
3257 : // Cf https://graphics.stanford.edu/~seander/bithacks.html#ValueInWord
3258 3741500 : if (!hasZeroByte(v ^ wordNoData))
3259 : {
3260 : // No bytes are at nodata
3261 3598450 : memcpy(pDstLocation, &v, WORD_SIZE);
3262 3598450 : idxBuffer += WORD_SIZE;
3263 3598450 : pDstLocation += WORD_SIZE;
3264 : }
3265 52141 : else if (v == wordNoData)
3266 : {
3267 : // All bytes are at nodata
3268 131075 : idxBuffer += WORD_SIZE;
3269 131075 : pDstLocation += WORD_SIZE;
3270 : }
3271 : else
3272 : {
3273 : // There are both bytes at nodata and valid bytes
3274 0 : for (int k = 0; k < WORD_SIZE; ++k)
3275 : {
3276 48 : if (paSrcData[idxBuffer] != nNoDataValue)
3277 : {
3278 36 : memcpy(pDstLocation, &paSrcData[idxBuffer],
3279 : sizeof(SourceDT));
3280 : }
3281 48 : idxBuffer++;
3282 48 : pDstLocation += nPixelSpace;
3283 : }
3284 : }
3285 : }
3286 : }
3287 :
3288 72 : for (; iX < nOutXSize;
3289 3709 : iX++, pDstLocation += nPixelSpace, idxBuffer++)
3290 : {
3291 3709 : if (paSrcData[idxBuffer] != nNoDataValue)
3292 : {
3293 3679 : memcpy(pDstLocation, &paSrcData[idxBuffer],
3294 : sizeof(SourceDT));
3295 : }
3296 : }
3297 : }
3298 : }
3299 11 : else if (!GDALDataTypeIsConversionLossy(eSourceType, eVRTBandDataType))
3300 : {
3301 : // Conversion from the source type to the VRT band data type is
3302 : // not lossy, so we can directly convert from the source type to
3303 : // the the output type
3304 102 : for (int iY = 0; iY < nOutYSize; iY++)
3305 : {
3306 92 : GByte *pDstLocation = static_cast<GByte *>(pData) +
3307 92 : static_cast<GPtrDiff_t>(nLineSpace) * iY;
3308 :
3309 1552 : for (int iX = 0; iX < nOutXSize;
3310 1460 : iX++, pDstLocation += nPixelSpace, idxBuffer++)
3311 : {
3312 1460 : if (paSrcData[idxBuffer] != nNoDataValue)
3313 : {
3314 658 : CopyWord(&paSrcData[idxBuffer], eSourceType, pDstLocation,
3315 : eBufType);
3316 : }
3317 : }
3318 : }
3319 : }
3320 : else
3321 : {
3322 : GByte abyTemp[2 * sizeof(double)];
3323 7 : for (int iY = 0; iY < nOutYSize; iY++)
3324 : {
3325 6 : GByte *pDstLocation = static_cast<GByte *>(pData) +
3326 6 : static_cast<GPtrDiff_t>(nLineSpace) * iY;
3327 :
3328 36 : for (int iX = 0; iX < nOutXSize;
3329 30 : iX++, pDstLocation += nPixelSpace, idxBuffer++)
3330 : {
3331 30 : if (paSrcData[idxBuffer] != nNoDataValue)
3332 : {
3333 : // Convert first to the VRTRasterBand data type
3334 : // to get its clamping, before outputting to buffer data type
3335 20 : CopyWord(&paSrcData[idxBuffer], eSourceType, abyTemp,
3336 : eVRTBandDataType);
3337 20 : GDALCopyWords(abyTemp, eVRTBandDataType, 0, pDstLocation,
3338 : eBufType, 0, 1);
3339 : }
3340 : }
3341 : }
3342 : }
3343 :
3344 8 : return CE_None;
3345 : }
3346 :
3347 : /************************************************************************/
3348 : /* RasterIOInternal() */
3349 : /************************************************************************/
3350 :
3351 : // nReqXOff, nReqYOff, nReqXSize, nReqYSize are expressed in source band
3352 : // referential.
3353 : template <class WorkingDT>
3354 4683 : CPLErr VRTComplexSource::RasterIOInternal(
3355 : GDALRasterBand *poSourceBand, GDALDataType eVRTBandDataType, int nReqXOff,
3356 : int nReqYOff, int nReqXSize, int nReqYSize, void *pData, int nOutXSize,
3357 : int nOutYSize, GDALDataType eBufType, GSpacing nPixelSpace,
3358 : GSpacing nLineSpace, GDALRasterIOExtraArg *psExtraArg,
3359 : GDALDataType eWrkDataType, WorkingState &oWorkingState)
3360 : {
3361 4683 : const GDALColorTable *poColorTable = nullptr;
3362 4683 : const bool bIsComplex = CPL_TO_BOOL(GDALDataTypeIsComplex(eBufType));
3363 4683 : const int nWordSize = GDALGetDataTypeSizeBytes(eWrkDataType);
3364 4683 : assert(nWordSize != 0);
3365 :
3366 : // If no explicit <NODATA> is set, but UseMaskBand is set, and the band
3367 : // has a nodata value, then use it as if it was set as <NODATA>
3368 4683 : int bNoDataSet = (m_nProcessingFlags & PROCESSING_FLAG_NODATA) != 0;
3369 4683 : double dfNoDataValue = GetAdjustedNoDataValue();
3370 :
3371 4758 : if ((m_nProcessingFlags & PROCESSING_FLAG_USE_MASK_BAND) != 0 &&
3372 75 : poSourceBand->GetMaskFlags() == GMF_NODATA)
3373 : {
3374 0 : dfNoDataValue = poSourceBand->GetNoDataValue(&bNoDataSet);
3375 : }
3376 :
3377 4683 : const bool bNoDataSetIsNan = bNoDataSet && std::isnan(dfNoDataValue);
3378 4683 : const bool bNoDataSetAndNotNan =
3379 4704 : bNoDataSet && !std::isnan(dfNoDataValue) &&
3380 21 : GDALIsValueInRange<WorkingDT>(dfNoDataValue);
3381 4683 : const auto fWorkingDataTypeNoData = static_cast<WorkingDT>(dfNoDataValue);
3382 :
3383 4683 : const GByte *pabyMask = nullptr;
3384 4683 : const WorkingDT *pafData = nullptr;
3385 4683 : if ((m_nProcessingFlags & PROCESSING_FLAG_SCALING_LINEAR) != 0 &&
3386 4421 : m_dfScaleRatio == 0 && bNoDataSet == FALSE &&
3387 4040 : (m_nProcessingFlags & PROCESSING_FLAG_USE_MASK_BAND) == 0)
3388 : {
3389 : /* ------------------------------------------------------------------ */
3390 : /* Optimization when writing a constant value */
3391 : /* (used by the -addalpha option of gdalbuildvrt) */
3392 : /* ------------------------------------------------------------------ */
3393 : // Already set to NULL when defined.
3394 : // pafData = NULL;
3395 : }
3396 : else
3397 : {
3398 : /* ---------------------------------------------------------------- */
3399 : /* Read into a temporary buffer. */
3400 : /* ---------------------------------------------------------------- */
3401 643 : const size_t nPixelCount = static_cast<size_t>(nOutXSize) * nOutYSize;
3402 : try
3403 : {
3404 : // Cannot overflow since pData should at least have that number of
3405 : // elements
3406 643 : if (nPixelCount >
3407 643 : static_cast<size_t>(std::numeric_limits<ptrdiff_t>::max()) /
3408 643 : static_cast<size_t>(nWordSize))
3409 : {
3410 0 : CPLError(CE_Failure, CPLE_OutOfMemory,
3411 : "Too large temporary buffer");
3412 0 : return CE_Failure;
3413 : }
3414 643 : oWorkingState.m_abyWrkBuffer.resize(nWordSize * nPixelCount);
3415 : }
3416 0 : catch (const std::bad_alloc &e)
3417 : {
3418 0 : CPLError(CE_Failure, CPLE_OutOfMemory, "%s", e.what());
3419 0 : return CE_Failure;
3420 : }
3421 : pafData = reinterpret_cast<const WorkingDT *>(
3422 643 : oWorkingState.m_abyWrkBuffer.data());
3423 :
3424 643 : const GDALRIOResampleAlg eResampleAlgBack = psExtraArg->eResampleAlg;
3425 643 : if (!m_osResampling.empty())
3426 : {
3427 0 : psExtraArg->eResampleAlg =
3428 0 : GDALRasterIOGetResampleAlg(m_osResampling);
3429 : }
3430 :
3431 643 : const CPLErr eErr = poSourceBand->RasterIO(
3432 : GF_Read, nReqXOff, nReqYOff, nReqXSize, nReqYSize,
3433 643 : oWorkingState.m_abyWrkBuffer.data(), nOutXSize, nOutYSize,
3434 : eWrkDataType, nWordSize,
3435 643 : nWordSize * static_cast<GSpacing>(nOutXSize), psExtraArg);
3436 643 : if (!m_osResampling.empty())
3437 0 : psExtraArg->eResampleAlg = eResampleAlgBack;
3438 :
3439 643 : if (eErr != CE_None)
3440 : {
3441 0 : return eErr;
3442 : }
3443 :
3444 : // Allocate and read mask band if needed
3445 1906 : if (!bNoDataSet &&
3446 718 : (m_nProcessingFlags & PROCESSING_FLAG_USE_MASK_BAND) != 0 &&
3447 75 : (poSourceBand->GetMaskFlags() != GMF_ALL_VALID ||
3448 31 : poSourceBand->GetColorInterpretation() == GCI_AlphaBand ||
3449 19 : GetMaskBandMainBand() != nullptr))
3450 : {
3451 : try
3452 : {
3453 75 : oWorkingState.m_abyWrkBufferMask.resize(nPixelCount);
3454 : }
3455 0 : catch (const std::exception &)
3456 : {
3457 0 : CPLError(CE_Failure, CPLE_OutOfMemory,
3458 : "Out of memory when allocating mask buffer");
3459 0 : return CE_Failure;
3460 : }
3461 : pabyMask = reinterpret_cast<const GByte *>(
3462 75 : oWorkingState.m_abyWrkBufferMask.data());
3463 31 : auto poMaskBand =
3464 75 : (poSourceBand->GetColorInterpretation() == GCI_AlphaBand ||
3465 63 : GetMaskBandMainBand() != nullptr)
3466 : ? poSourceBand
3467 44 : : poSourceBand->GetMaskBand();
3468 75 : if (poMaskBand->RasterIO(
3469 : GF_Read, nReqXOff, nReqYOff, nReqXSize, nReqYSize,
3470 75 : oWorkingState.m_abyWrkBufferMask.data(), nOutXSize,
3471 : nOutYSize, GDT_Byte, 1, static_cast<GSpacing>(nOutXSize),
3472 75 : psExtraArg) != CE_None)
3473 : {
3474 0 : return CE_Failure;
3475 : }
3476 : }
3477 :
3478 643 : if (m_nColorTableComponent != 0)
3479 : {
3480 64 : poColorTable = poSourceBand->GetColorTable();
3481 64 : if (poColorTable == nullptr)
3482 : {
3483 0 : CPLError(CE_Failure, CPLE_AppDefined,
3484 : "Source band has no color table.");
3485 0 : return CE_Failure;
3486 : }
3487 : }
3488 : }
3489 :
3490 : /* -------------------------------------------------------------------- */
3491 : /* Selectively copy into output buffer with nodata masking, */
3492 : /* and/or scaling. */
3493 : /* -------------------------------------------------------------------- */
3494 :
3495 4683 : const bool bTwoStepDataTypeConversion =
3496 4683 : CPL_TO_BOOL(
3497 9323 : GDALDataTypeIsConversionLossy(eWrkDataType, eVRTBandDataType)) &&
3498 4640 : !CPL_TO_BOOL(GDALDataTypeIsConversionLossy(eVRTBandDataType, eBufType));
3499 :
3500 4683 : size_t idxBuffer = 0;
3501 74782 : for (int iY = 0; iY < nOutYSize; iY++)
3502 : {
3503 70099 : GByte *pDstLocation = static_cast<GByte *>(pData) +
3504 70099 : static_cast<GPtrDiff_t>(nLineSpace) * iY;
3505 :
3506 11948028 : for (int iX = 0; iX < nOutXSize;
3507 11877972 : iX++, pDstLocation += nPixelSpace, idxBuffer++)
3508 : {
3509 : WorkingDT afResult[2];
3510 11877972 : if (pafData && !bIsComplex)
3511 : {
3512 6268670 : WorkingDT fResult = pafData[idxBuffer];
3513 6268670 : if (bNoDataSetIsNan && std::isnan(fResult))
3514 1175180 : continue;
3515 6269880 : if (bNoDataSetAndNotNan &&
3516 1230 : ARE_REAL_EQUAL(fResult, fWorkingDataTypeNoData))
3517 254 : continue;
3518 6268390 : if (pabyMask && pabyMask[idxBuffer] == 0)
3519 1174910 : continue;
3520 :
3521 5093490 : if (poColorTable)
3522 : {
3523 : const GDALColorEntry *poEntry =
3524 1925900 : poColorTable->GetColorEntry(static_cast<int>(fResult));
3525 1925900 : if (poEntry)
3526 : {
3527 1925900 : if (m_nColorTableComponent == 1)
3528 683585 : fResult = poEntry->c1;
3529 1242320 : else if (m_nColorTableComponent == 2)
3530 529008 : fResult = poEntry->c2;
3531 713309 : else if (m_nColorTableComponent == 3)
3532 529008 : fResult = poEntry->c3;
3533 184301 : else if (m_nColorTableComponent == 4)
3534 184301 : fResult = poEntry->c4;
3535 : }
3536 : else
3537 : {
3538 : static bool bHasWarned = false;
3539 0 : if (!bHasWarned)
3540 : {
3541 0 : bHasWarned = true;
3542 0 : CPLError(CE_Failure, CPLE_AppDefined,
3543 : "No entry %d.", static_cast<int>(fResult));
3544 : }
3545 0 : continue;
3546 : }
3547 : }
3548 :
3549 5093490 : if ((m_nProcessingFlags & PROCESSING_FLAG_SCALING_LINEAR) != 0)
3550 : {
3551 1649570 : fResult = static_cast<WorkingDT>(fResult * m_dfScaleRatio +
3552 1649570 : m_dfScaleOff);
3553 : }
3554 3443920 : else if ((m_nProcessingFlags &
3555 : PROCESSING_FLAG_SCALING_EXPONENTIAL) != 0)
3556 : {
3557 3543 : if (!m_bSrcMinMaxDefined)
3558 : {
3559 1 : int bSuccessMin = FALSE;
3560 1 : int bSuccessMax = FALSE;
3561 2 : double adfMinMax[2] = {
3562 1 : poSourceBand->GetMinimum(&bSuccessMin),
3563 1 : poSourceBand->GetMaximum(&bSuccessMax)};
3564 2 : if ((bSuccessMin && bSuccessMax) ||
3565 1 : poSourceBand->ComputeRasterMinMax(
3566 : TRUE, adfMinMax) == CE_None)
3567 : {
3568 1 : m_dfSrcMin = adfMinMax[0];
3569 1 : m_dfSrcMax = adfMinMax[1];
3570 1 : m_bSrcMinMaxDefined = true;
3571 : }
3572 : else
3573 : {
3574 0 : CPLError(CE_Failure, CPLE_AppDefined,
3575 : "Cannot determine source min/max value");
3576 0 : return CE_Failure;
3577 : }
3578 : }
3579 :
3580 3543 : double dfPowVal =
3581 3543 : (fResult - m_dfSrcMin) / (m_dfSrcMax - m_dfSrcMin);
3582 3543 : if (dfPowVal < 0.0)
3583 0 : dfPowVal = 0.0;
3584 3543 : else if (dfPowVal > 1.0)
3585 699 : dfPowVal = 1.0;
3586 3543 : fResult =
3587 3543 : static_cast<WorkingDT>((m_dfDstMax - m_dfDstMin) *
3588 3543 : pow(dfPowVal, m_dfExponent) +
3589 3543 : m_dfDstMin);
3590 : }
3591 :
3592 5093490 : if (!m_adfLUTInputs.empty())
3593 583336 : fResult = static_cast<WorkingDT>(LookupValue(fResult));
3594 :
3595 5093490 : if (m_nMaxValue != 0 && fResult > m_nMaxValue)
3596 800 : fResult = static_cast<WorkingDT>(m_nMaxValue);
3597 :
3598 5093490 : afResult[0] = fResult;
3599 5093490 : afResult[1] = 0;
3600 : }
3601 5609252 : else if (pafData && bIsComplex)
3602 : {
3603 1015 : afResult[0] = pafData[2 * idxBuffer];
3604 1015 : afResult[1] = pafData[2 * idxBuffer + 1];
3605 :
3606 : // Do not use color table.
3607 1015 : if ((m_nProcessingFlags & PROCESSING_FLAG_SCALING_LINEAR) != 0)
3608 : {
3609 1 : afResult[0] = static_cast<WorkingDT>(
3610 1 : afResult[0] * m_dfScaleRatio + m_dfScaleOff);
3611 1 : afResult[1] = static_cast<WorkingDT>(
3612 1 : afResult[1] * m_dfScaleRatio + m_dfScaleOff);
3613 : }
3614 :
3615 : /* Do not use LUT */
3616 : }
3617 : else
3618 : {
3619 5608242 : afResult[0] = static_cast<WorkingDT>(m_dfScaleOff);
3620 5608242 : afResult[1] = 0;
3621 :
3622 5608242 : if (!m_adfLUTInputs.empty())
3623 0 : afResult[0] =
3624 0 : static_cast<WorkingDT>(LookupValue(afResult[0]));
3625 :
3626 5608242 : if (m_nMaxValue != 0 && afResult[0] > m_nMaxValue)
3627 0 : afResult[0] = static_cast<WorkingDT>(m_nMaxValue);
3628 : }
3629 :
3630 10702782 : if (eBufType == GDT_Byte && eVRTBandDataType == GDT_Byte)
3631 : {
3632 4284920 : *pDstLocation = static_cast<GByte>(std::min(
3633 8569840 : 255.0f,
3634 4284920 : std::max(0.0f, static_cast<float>(afResult[0]) + 0.5f)));
3635 : }
3636 6417822 : else if (!bTwoStepDataTypeConversion)
3637 : {
3638 3957 : CopyWord<WorkingDT>(afResult, eWrkDataType, pDstLocation,
3639 : eBufType);
3640 : }
3641 6413870 : else if (eVRTBandDataType == GDT_Float32 && eBufType == GDT_Float64)
3642 : {
3643 : // Particular case of the below 2-step conversion.
3644 : // Helps a bit for some geolocation based warping with Sentinel3
3645 : // data where the longitude/latitude arrays are Int32 bands,
3646 : // rescaled in VRT as Float32 and requested as Float64
3647 : float fVal;
3648 20 : GDALCopyWord(afResult[0], fVal);
3649 20 : *reinterpret_cast<double *>(pDstLocation) = fVal;
3650 : }
3651 : else
3652 : {
3653 : GByte abyTemp[2 * sizeof(double)];
3654 : // Convert first to the VRTRasterBand data type
3655 : // to get its clamping, before outputting to buffer data type
3656 6413850 : CopyWord<WorkingDT>(afResult, eWrkDataType, abyTemp,
3657 : eVRTBandDataType);
3658 6413850 : GDALCopyWords(abyTemp, eVRTBandDataType, 0, pDstLocation,
3659 : eBufType, 0, 1);
3660 : }
3661 : }
3662 : }
3663 :
3664 4683 : return CE_None;
3665 : }
3666 :
3667 : // Explicitly instantiate template method, as it is used in another file.
3668 : template CPLErr VRTComplexSource::RasterIOInternal<float>(
3669 : GDALRasterBand *poSourceBand, GDALDataType eVRTBandDataType, int nReqXOff,
3670 : int nReqYOff, int nReqXSize, int nReqYSize, void *pData, int nOutXSize,
3671 : int nOutYSize, GDALDataType eBufType, GSpacing nPixelSpace,
3672 : GSpacing nLineSpace, GDALRasterIOExtraArg *psExtraArg,
3673 : GDALDataType eWrkDataType, WorkingState &oWorkingState);
3674 :
3675 : /************************************************************************/
3676 : /* AreValuesUnchanged() */
3677 : /************************************************************************/
3678 :
3679 9 : bool VRTComplexSource::AreValuesUnchanged() const
3680 : {
3681 10 : return m_dfScaleOff == 0.0 && m_dfScaleRatio == 1.0 &&
3682 24 : m_adfLUTInputs.empty() && m_nColorTableComponent == 0 &&
3683 14 : (m_nProcessingFlags & PROCESSING_FLAG_SCALING_EXPONENTIAL) == 0;
3684 : }
3685 :
3686 : /************************************************************************/
3687 : /* GetMinimum() */
3688 : /************************************************************************/
3689 :
3690 2 : double VRTComplexSource::GetMinimum(int nXSize, int nYSize, int *pbSuccess)
3691 : {
3692 2 : if (AreValuesUnchanged())
3693 : {
3694 1 : return VRTSimpleSource::GetMinimum(nXSize, nYSize, pbSuccess);
3695 : }
3696 :
3697 1 : *pbSuccess = FALSE;
3698 1 : return 0;
3699 : }
3700 :
3701 : /************************************************************************/
3702 : /* GetMaximum() */
3703 : /************************************************************************/
3704 :
3705 2 : double VRTComplexSource::GetMaximum(int nXSize, int nYSize, int *pbSuccess)
3706 : {
3707 2 : if (AreValuesUnchanged())
3708 : {
3709 1 : return VRTSimpleSource::GetMaximum(nXSize, nYSize, pbSuccess);
3710 : }
3711 :
3712 1 : *pbSuccess = FALSE;
3713 1 : return 0;
3714 : }
3715 :
3716 : /************************************************************************/
3717 : /* GetHistogram() */
3718 : /************************************************************************/
3719 :
3720 0 : CPLErr VRTComplexSource::GetHistogram(int nXSize, int nYSize, double dfMin,
3721 : double dfMax, int nBuckets,
3722 : GUIntBig *panHistogram,
3723 : int bIncludeOutOfRange, int bApproxOK,
3724 : GDALProgressFunc pfnProgress,
3725 : void *pProgressData)
3726 : {
3727 0 : if (AreValuesUnchanged())
3728 : {
3729 0 : return VRTSimpleSource::GetHistogram(
3730 : nXSize, nYSize, dfMin, dfMax, nBuckets, panHistogram,
3731 0 : bIncludeOutOfRange, bApproxOK, pfnProgress, pProgressData);
3732 : }
3733 :
3734 0 : return CE_Failure;
3735 : }
3736 :
3737 : /************************************************************************/
3738 : /* ==================================================================== */
3739 : /* VRTFuncSource */
3740 : /* ==================================================================== */
3741 : /************************************************************************/
3742 :
3743 : /************************************************************************/
3744 : /* VRTFuncSource() */
3745 : /************************************************************************/
3746 :
3747 12 : VRTFuncSource::VRTFuncSource()
3748 : : pfnReadFunc(nullptr), pCBData(nullptr), eType(GDT_Byte),
3749 12 : fNoDataValue(static_cast<float>(VRT_NODATA_UNSET))
3750 : {
3751 12 : }
3752 :
3753 : /************************************************************************/
3754 : /* ~VRTFuncSource() */
3755 : /************************************************************************/
3756 :
3757 24 : VRTFuncSource::~VRTFuncSource()
3758 : {
3759 24 : }
3760 :
3761 : /************************************************************************/
3762 : /* GetType() */
3763 : /************************************************************************/
3764 :
3765 0 : const char *VRTFuncSource::GetType() const
3766 : {
3767 : static const char *TYPE = "FuncSource";
3768 0 : return TYPE;
3769 : }
3770 :
3771 : /************************************************************************/
3772 : /* SerializeToXML() */
3773 : /************************************************************************/
3774 :
3775 0 : CPLXMLNode *VRTFuncSource::SerializeToXML(CPL_UNUSED const char *pszVRTPath)
3776 : {
3777 0 : return nullptr;
3778 : }
3779 :
3780 : /************************************************************************/
3781 : /* RasterIO() */
3782 : /************************************************************************/
3783 :
3784 10 : CPLErr VRTFuncSource::RasterIO(GDALDataType /*eVRTBandDataType*/, int nXOff,
3785 : int nYOff, int nXSize, int nYSize, void *pData,
3786 : int nBufXSize, int nBufYSize,
3787 : GDALDataType eBufType, GSpacing nPixelSpace,
3788 : GSpacing nLineSpace,
3789 : GDALRasterIOExtraArg * /* psExtraArg */,
3790 : WorkingState & /* oWorkingState */)
3791 : {
3792 10 : if (nPixelSpace * 8 == GDALGetDataTypeSize(eBufType) &&
3793 10 : nLineSpace == nPixelSpace * nXSize && nBufXSize == nXSize &&
3794 20 : nBufYSize == nYSize && eBufType == eType)
3795 : {
3796 10 : return pfnReadFunc(pCBData, nXOff, nYOff, nXSize, nYSize, pData);
3797 : }
3798 : else
3799 : {
3800 0 : CPLError(CE_Failure, CPLE_AppDefined,
3801 : "VRTFuncSource::RasterIO() - Irregular request.");
3802 0 : CPLDebug("VRT", "Irregular request: %d,%d %d,%d, %d,%d %d,%d %d,%d",
3803 : static_cast<int>(nPixelSpace) * 8,
3804 : GDALGetDataTypeSize(eBufType), static_cast<int>(nLineSpace),
3805 : static_cast<int>(nPixelSpace) * nXSize, nBufXSize, nXSize,
3806 : nBufYSize, nYSize, static_cast<int>(eBufType),
3807 0 : static_cast<int>(eType));
3808 :
3809 0 : return CE_Failure;
3810 : }
3811 : }
3812 :
3813 : /************************************************************************/
3814 : /* GetMinimum() */
3815 : /************************************************************************/
3816 :
3817 0 : double VRTFuncSource::GetMinimum(int /* nXSize */, int /* nYSize */,
3818 : int *pbSuccess)
3819 : {
3820 0 : *pbSuccess = FALSE;
3821 0 : return 0;
3822 : }
3823 :
3824 : /************************************************************************/
3825 : /* GetMaximum() */
3826 : /************************************************************************/
3827 :
3828 0 : double VRTFuncSource::GetMaximum(int /* nXSize */, int /* nYSize */,
3829 : int *pbSuccess)
3830 : {
3831 0 : *pbSuccess = FALSE;
3832 0 : return 0;
3833 : }
3834 :
3835 : /************************************************************************/
3836 : /* GetHistogram() */
3837 : /************************************************************************/
3838 :
3839 0 : CPLErr VRTFuncSource::GetHistogram(
3840 : int /* nXSize */, int /* nYSize */, double /* dfMin */, double /* dfMax */,
3841 : int /* nBuckets */, GUIntBig * /* panHistogram */,
3842 : int /* bIncludeOutOfRange */, int /* bApproxOK */,
3843 : GDALProgressFunc /* pfnProgress */, void * /* pProgressData */)
3844 : {
3845 0 : return CE_Failure;
3846 : }
3847 :
3848 : /************************************************************************/
3849 : /* VRTParseCoreSources() */
3850 : /************************************************************************/
3851 :
3852 3043 : VRTSource *VRTParseCoreSources(const CPLXMLNode *psChild,
3853 : const char *pszVRTPath,
3854 : VRTMapSharedResources &oMapSharedSources)
3855 :
3856 : {
3857 3043 : VRTSource *poSource = nullptr;
3858 :
3859 6079 : if (EQUAL(psChild->pszValue, VRTAveragedSource::GetTypeStatic()) ||
3860 3036 : (EQUAL(psChild->pszValue, VRTSimpleSource::GetTypeStatic()) &&
3861 2841 : STARTS_WITH_CI(CPLGetXMLValue(psChild, "Resampling", "Nearest"),
3862 : "Aver")))
3863 : {
3864 16 : poSource = new VRTAveragedSource();
3865 : }
3866 3027 : else if (EQUAL(psChild->pszValue, VRTSimpleSource::GetTypeStatic()))
3867 : {
3868 2832 : poSource = new VRTSimpleSource();
3869 : }
3870 195 : else if (EQUAL(psChild->pszValue, VRTComplexSource::GetTypeStatic()))
3871 : {
3872 187 : poSource = new VRTComplexSource();
3873 : }
3874 8 : else if (EQUAL(psChild->pszValue, VRTNoDataFromMaskSource::GetTypeStatic()))
3875 : {
3876 8 : poSource = new VRTNoDataFromMaskSource();
3877 : }
3878 : else
3879 : {
3880 0 : CPLError(CE_Failure, CPLE_AppDefined,
3881 : "VRTParseCoreSources() - Unknown source : %s",
3882 0 : psChild->pszValue);
3883 0 : return nullptr;
3884 : }
3885 :
3886 3043 : if (poSource->XMLInit(psChild, pszVRTPath, oMapSharedSources) == CE_None)
3887 3040 : return poSource;
3888 :
3889 3 : delete poSource;
3890 3 : return nullptr;
3891 : }
3892 :
3893 : /*! @endcond */
|