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