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