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