Line data Source code
1 : /******************************************************************************
2 : *
3 : * Project: Virtual GDAL Datasets
4 : * Purpose: Implementation of a sourced raster band that derives its raster
5 : * by applying an algorithm (GDALDerivedPixelFunc) to the sources.
6 : * Author: Pete Nagy
7 : *
8 : ******************************************************************************
9 : * Copyright (c) 2005 Vexcel Corp.
10 : * Copyright (c) 2008-2011, Even Rouault <even dot rouault at spatialys.com>
11 : *
12 : * SPDX-License-Identifier: MIT
13 : *****************************************************************************/
14 :
15 : #include "cpl_minixml.h"
16 : #include "cpl_string.h"
17 : #include "vrtdataset.h"
18 : #include "cpl_multiproc.h"
19 : #include "gdalpython.h"
20 :
21 : #include <algorithm>
22 : #include <map>
23 : #include <vector>
24 : #include <utility>
25 :
26 : /*! @cond Doxygen_Suppress */
27 :
28 : using namespace GDALPy;
29 :
30 : // #define GDAL_VRT_DISABLE_PYTHON
31 :
32 : #ifndef GDAL_VRT_ENABLE_PYTHON_DEFAULT
33 : // Can be YES, NO or TRUSTED_MODULES
34 : #define GDAL_VRT_ENABLE_PYTHON_DEFAULT "TRUSTED_MODULES"
35 : #endif
36 :
37 : /* Flags for getting buffers */
38 : #define PyBUF_WRITABLE 0x0001
39 : #define PyBUF_FORMAT 0x0004
40 : #define PyBUF_ND 0x0008
41 : #define PyBUF_STRIDES (0x0010 | PyBUF_ND)
42 : #define PyBUF_INDIRECT (0x0100 | PyBUF_STRIDES)
43 : #define PyBUF_FULL (PyBUF_INDIRECT | PyBUF_WRITABLE | PyBUF_FORMAT)
44 :
45 : /************************************************************************/
46 : /* GDALCreateNumpyArray() */
47 : /************************************************************************/
48 :
49 399 : static PyObject *GDALCreateNumpyArray(PyObject *pCreateArray, void *pBuffer,
50 : GDALDataType eType, int nHeight,
51 : int nWidth)
52 : {
53 : PyObject *poPyBuffer;
54 : const size_t nSize =
55 399 : static_cast<size_t>(nHeight) * nWidth * GDALGetDataTypeSizeBytes(eType);
56 : Py_buffer pybuffer;
57 399 : if (PyBuffer_FillInfo(&pybuffer, nullptr, static_cast<char *>(pBuffer),
58 399 : nSize, 0, PyBUF_FULL) != 0)
59 : {
60 0 : return nullptr;
61 : }
62 399 : poPyBuffer = PyMemoryView_FromBuffer(&pybuffer);
63 399 : PyObject *pArgsCreateArray = PyTuple_New(4);
64 399 : PyTuple_SetItem(pArgsCreateArray, 0, poPyBuffer);
65 399 : const char *pszDataType = nullptr;
66 399 : switch (eType)
67 : {
68 357 : case GDT_Byte:
69 357 : pszDataType = "uint8";
70 357 : break;
71 15 : case GDT_Int8:
72 15 : pszDataType = "int8";
73 15 : break;
74 2 : case GDT_UInt16:
75 2 : pszDataType = "uint16";
76 2 : break;
77 7 : case GDT_Int16:
78 7 : pszDataType = "int16";
79 7 : break;
80 2 : case GDT_UInt32:
81 2 : pszDataType = "uint32";
82 2 : break;
83 2 : case GDT_Int32:
84 2 : pszDataType = "int32";
85 2 : break;
86 2 : case GDT_Int64:
87 2 : pszDataType = "int64";
88 2 : break;
89 2 : case GDT_UInt64:
90 2 : pszDataType = "uint64";
91 2 : break;
92 2 : case GDT_Float16:
93 2 : pszDataType = "float16";
94 2 : break;
95 2 : case GDT_Float32:
96 2 : pszDataType = "float32";
97 2 : break;
98 2 : case GDT_Float64:
99 2 : pszDataType = "float64";
100 2 : break;
101 0 : case GDT_CInt16:
102 : case GDT_CInt32:
103 0 : CPLAssert(FALSE);
104 : break;
105 0 : case GDT_CFloat16:
106 0 : CPLAssert(FALSE);
107 : break;
108 2 : case GDT_CFloat32:
109 2 : pszDataType = "complex64";
110 2 : break;
111 2 : case GDT_CFloat64:
112 2 : pszDataType = "complex128";
113 2 : break;
114 0 : case GDT_Unknown:
115 : case GDT_TypeCount:
116 0 : CPLAssert(FALSE);
117 : break;
118 : }
119 399 : PyTuple_SetItem(
120 : pArgsCreateArray, 1,
121 : PyBytes_FromStringAndSize(pszDataType, strlen(pszDataType)));
122 399 : PyTuple_SetItem(pArgsCreateArray, 2, PyLong_FromLong(nHeight));
123 399 : PyTuple_SetItem(pArgsCreateArray, 3, PyLong_FromLong(nWidth));
124 : PyObject *poNumpyArray =
125 399 : PyObject_Call(pCreateArray, pArgsCreateArray, nullptr);
126 399 : Py_DecRef(pArgsCreateArray);
127 399 : if (PyErr_Occurred())
128 0 : PyErr_Print();
129 399 : return poNumpyArray;
130 : }
131 :
132 : /************************************************************************/
133 : /* ==================================================================== */
134 : /* VRTDerivedRasterBandPrivateData */
135 : /* ==================================================================== */
136 : /************************************************************************/
137 :
138 : class VRTDerivedRasterBandPrivateData
139 : {
140 : VRTDerivedRasterBandPrivateData(const VRTDerivedRasterBandPrivateData &) =
141 : delete;
142 : VRTDerivedRasterBandPrivateData &
143 : operator=(const VRTDerivedRasterBandPrivateData &) = delete;
144 :
145 : public:
146 : CPLString m_osCode{};
147 : CPLString m_osLanguage = "C";
148 : int m_nBufferRadius = 0;
149 : PyObject *m_poGDALCreateNumpyArray = nullptr;
150 : PyObject *m_poUserFunction = nullptr;
151 : bool m_bPythonInitializationDone = false;
152 : bool m_bPythonInitializationSuccess = false;
153 : bool m_bExclusiveLock = false;
154 : bool m_bFirstTime = true;
155 : std::vector<std::pair<CPLString, CPLString>> m_oFunctionArgs{};
156 : bool m_bSkipNonContributingSourcesSpecified = false;
157 : bool m_bSkipNonContributingSources = false;
158 :
159 1297 : VRTDerivedRasterBandPrivateData() = default;
160 :
161 2594 : virtual ~VRTDerivedRasterBandPrivateData()
162 1297 : {
163 1297 : if (m_poGDALCreateNumpyArray)
164 48 : Py_DecRef(m_poGDALCreateNumpyArray);
165 1297 : if (m_poUserFunction)
166 49 : Py_DecRef(m_poUserFunction);
167 2594 : }
168 : };
169 :
170 : /************************************************************************/
171 : /* ==================================================================== */
172 : /* VRTDerivedRasterBand */
173 : /* ==================================================================== */
174 : /************************************************************************/
175 :
176 : /************************************************************************/
177 : /* VRTDerivedRasterBand() */
178 : /************************************************************************/
179 :
180 1273 : VRTDerivedRasterBand::VRTDerivedRasterBand(GDALDataset *poDSIn, int nBandIn)
181 : : VRTSourcedRasterBand(poDSIn, nBandIn), m_poPrivate(nullptr),
182 1273 : eSourceTransferType(GDT_Unknown)
183 : {
184 1273 : m_poPrivate = new VRTDerivedRasterBandPrivateData;
185 1273 : }
186 :
187 : /************************************************************************/
188 : /* VRTDerivedRasterBand() */
189 : /************************************************************************/
190 :
191 24 : VRTDerivedRasterBand::VRTDerivedRasterBand(GDALDataset *poDSIn, int nBandIn,
192 : GDALDataType eType, int nXSize,
193 24 : int nYSize)
194 : : VRTSourcedRasterBand(poDSIn, nBandIn, eType, nXSize, nYSize),
195 24 : m_poPrivate(nullptr), eSourceTransferType(GDT_Unknown)
196 : {
197 24 : m_poPrivate = new VRTDerivedRasterBandPrivateData;
198 24 : }
199 :
200 : /************************************************************************/
201 : /* ~VRTDerivedRasterBand() */
202 : /************************************************************************/
203 :
204 2594 : VRTDerivedRasterBand::~VRTDerivedRasterBand()
205 :
206 : {
207 1297 : delete m_poPrivate;
208 2594 : }
209 :
210 : /************************************************************************/
211 : /* Cleanup() */
212 : /************************************************************************/
213 :
214 1113 : void VRTDerivedRasterBand::Cleanup()
215 : {
216 1113 : }
217 :
218 : /************************************************************************/
219 : /* GetGlobalMapPixelFunction() */
220 : /************************************************************************/
221 :
222 : static std::map<std::string,
223 : std::pair<VRTDerivedRasterBand::PixelFunc, std::string>> &
224 50456 : GetGlobalMapPixelFunction()
225 : {
226 : static std::map<std::string,
227 : std::pair<VRTDerivedRasterBand::PixelFunc, std::string>>
228 50456 : gosMapPixelFunction;
229 50456 : return gosMapPixelFunction;
230 : }
231 :
232 : /************************************************************************/
233 : /* AddPixelFunction() */
234 : /************************************************************************/
235 :
236 : /*! @endcond */
237 :
238 : /**
239 : * This adds a pixel function to the global list of available pixel
240 : * functions for derived bands. Pixel functions must be registered
241 : * in this way before a derived band tries to access data.
242 : *
243 : * Derived bands are stored with only the name of the pixel function
244 : * that it will apply, and if a pixel function matching the name is not
245 : * found the IRasterIO() call will do nothing.
246 : *
247 : * @param pszName Name used to access pixel function
248 : * @param pfnNewFunction Pixel function associated with name. An
249 : * existing pixel function registered with the same name will be
250 : * replaced with the new one.
251 : *
252 : * @return CE_None, invalid (NULL) parameters are currently ignored.
253 : */
254 14072 : CPLErr CPL_STDCALL GDALAddDerivedBandPixelFunc(
255 : const char *pszName, GDALDerivedPixelFunc pfnNewFunction)
256 : {
257 14072 : if (pszName == nullptr || pszName[0] == '\0' || pfnNewFunction == nullptr)
258 : {
259 0 : return CE_None;
260 : }
261 :
262 28144 : GetGlobalMapPixelFunction()[pszName] = {
263 47 : [pfnNewFunction](void **papoSources, int nSources, void *pData,
264 : int nBufXSize, int nBufYSize, GDALDataType eSrcType,
265 : GDALDataType eBufType, int nPixelSpace, int nLineSpace,
266 47 : CSLConstList papszFunctionArgs)
267 : {
268 : (void)papszFunctionArgs;
269 47 : return pfnNewFunction(papoSources, nSources, pData, nBufXSize,
270 : nBufYSize, eSrcType, eBufType, nPixelSpace,
271 47 : nLineSpace);
272 : },
273 42216 : ""};
274 :
275 14072 : return CE_None;
276 : }
277 :
278 : /**
279 : * This adds a pixel function to the global list of available pixel
280 : * functions for derived bands. Pixel functions must be registered
281 : * in this way before a derived band tries to access data.
282 : *
283 : * Derived bands are stored with only the name of the pixel function
284 : * that it will apply, and if a pixel function matching the name is not
285 : * found the IRasterIO() call will do nothing.
286 : *
287 : * @param pszName Name used to access pixel function
288 : * @param pfnNewFunction Pixel function associated with name. An
289 : * existing pixel function registered with the same name will be
290 : * replaced with the new one.
291 : * @param pszMetadata Pixel function metadata (not currently implemented)
292 : *
293 : * @return CE_None, invalid (NULL) parameters are currently ignored.
294 : * @since GDAL 3.4
295 : */
296 35177 : CPLErr CPL_STDCALL GDALAddDerivedBandPixelFuncWithArgs(
297 : const char *pszName, GDALDerivedPixelFuncWithArgs pfnNewFunction,
298 : const char *pszMetadata)
299 : {
300 35177 : if (!pszName || pszName[0] == '\0' || !pfnNewFunction)
301 : {
302 0 : return CE_None;
303 : }
304 :
305 70354 : GetGlobalMapPixelFunction()[pszName] = {pfnNewFunction,
306 105531 : pszMetadata ? pszMetadata : ""};
307 :
308 35177 : return CE_None;
309 : }
310 :
311 : /*! @cond Doxygen_Suppress */
312 :
313 : /**
314 : * This adds a pixel function to the global list of available pixel
315 : * functions for derived bands.
316 : *
317 : * This is the same as the C function GDALAddDerivedBandPixelFunc()
318 : *
319 : * @param pszFuncNameIn Name used to access pixel function
320 : * @param pfnNewFunction Pixel function associated with name. An
321 : * existing pixel function registered with the same name will be
322 : * replaced with the new one.
323 : *
324 : * @return CE_None, invalid (NULL) parameters are currently ignored.
325 : */
326 : CPLErr
327 0 : VRTDerivedRasterBand::AddPixelFunction(const char *pszFuncNameIn,
328 : GDALDerivedPixelFunc pfnNewFunction)
329 : {
330 0 : return GDALAddDerivedBandPixelFunc(pszFuncNameIn, pfnNewFunction);
331 : }
332 :
333 0 : CPLErr VRTDerivedRasterBand::AddPixelFunction(
334 : const char *pszFuncNameIn, GDALDerivedPixelFuncWithArgs pfnNewFunction,
335 : const char *pszMetadata)
336 : {
337 0 : return GDALAddDerivedBandPixelFuncWithArgs(pszFuncNameIn, pfnNewFunction,
338 0 : pszMetadata);
339 : }
340 :
341 : /************************************************************************/
342 : /* GetPixelFunction() */
343 : /************************************************************************/
344 :
345 : /**
346 : * Get a pixel function previously registered using the global
347 : * AddPixelFunction.
348 : *
349 : * @param pszFuncNameIn The name associated with the pixel function.
350 : *
351 : * @return A pointer to a std::pair whose first element is the pixel
352 : * function pointer and second element is the pixel function
353 : * metadata string. If no pixel function has been registered
354 : * for pszFuncNameIn, nullptr will be returned.
355 : */
356 : const std::pair<VRTDerivedRasterBand::PixelFunc, std::string> *
357 1207 : VRTDerivedRasterBand::GetPixelFunction(const char *pszFuncNameIn)
358 : {
359 1207 : if (pszFuncNameIn == nullptr || pszFuncNameIn[0] == '\0')
360 : {
361 0 : return nullptr;
362 : }
363 :
364 1207 : const auto &oMapPixelFunction = GetGlobalMapPixelFunction();
365 1207 : const auto oIter = oMapPixelFunction.find(pszFuncNameIn);
366 :
367 1207 : if (oIter == oMapPixelFunction.end())
368 3 : return nullptr;
369 :
370 1204 : return &(oIter->second);
371 : }
372 :
373 : /************************************************************************/
374 : /* SetPixelFunctionName() */
375 : /************************************************************************/
376 :
377 : /**
378 : * Set the pixel function name to be applied to this derived band. The
379 : * name should match a pixel function registered using AddPixelFunction.
380 : *
381 : * @param pszFuncNameIn Name of pixel function to be applied to this derived
382 : * band.
383 : */
384 1298 : void VRTDerivedRasterBand::SetPixelFunctionName(const char *pszFuncNameIn)
385 : {
386 1298 : osFuncName = (pszFuncNameIn == nullptr) ? "" : pszFuncNameIn;
387 1298 : }
388 :
389 : /************************************************************************/
390 : /* AddPixelFunctionArgument() */
391 : /************************************************************************/
392 :
393 : /**
394 : * Set a pixel function argument to a specified value.
395 : * @param pszArg the argument name
396 : * @param pszValue the argument value
397 : *
398 : * @since 3.12
399 : */
400 1242 : void VRTDerivedRasterBand::AddPixelFunctionArgument(const char *pszArg,
401 : const char *pszValue)
402 : {
403 1242 : m_poPrivate->m_oFunctionArgs.emplace_back(pszArg, pszValue);
404 1242 : }
405 :
406 : /************************************************************************/
407 : /* SetPixelFunctionLanguage() */
408 : /************************************************************************/
409 :
410 : /**
411 : * Set the language of the pixel function.
412 : *
413 : * @param pszLanguage Language of the pixel function (only "C" and "Python"
414 : * are supported currently)
415 : * @since GDAL 2.3
416 : */
417 1 : void VRTDerivedRasterBand::SetPixelFunctionLanguage(const char *pszLanguage)
418 : {
419 1 : m_poPrivate->m_osLanguage = pszLanguage;
420 1 : }
421 :
422 : /************************************************************************/
423 : /* SetSkipNonContributingSources() */
424 : /************************************************************************/
425 :
426 : /** Whether sources that do not intersect the VRTRasterBand RasterIO() requested
427 : * region should be omitted. By default, data for all sources, including ones
428 : * that do not intersect it, are passed to the pixel function. By setting this
429 : * parameter to true, only sources that intersect the requested region will be
430 : * passed.
431 : *
432 : * @param bSkip whether to skip non-contributing sources
433 : *
434 : * @since 3.12
435 : */
436 5 : void VRTDerivedRasterBand::SetSkipNonContributingSources(bool bSkip)
437 : {
438 5 : m_poPrivate->m_bSkipNonContributingSources = bSkip;
439 5 : m_poPrivate->m_bSkipNonContributingSourcesSpecified = true;
440 5 : }
441 :
442 : /************************************************************************/
443 : /* SetSourceTransferType() */
444 : /************************************************************************/
445 :
446 : /**
447 : * Set the transfer type to be used to obtain pixel information from
448 : * all of the sources. If unset, the transfer type used will be the
449 : * same as the derived band data type. This makes it possible, for
450 : * example, to pass CFloat32 source pixels to the pixel function, even
451 : * if the pixel function generates a raster for a derived band that
452 : * is of type Byte.
453 : *
454 : * @param eDataTypeIn Data type to use to obtain pixel information from
455 : * the sources to be passed to the derived band pixel function.
456 : */
457 21 : void VRTDerivedRasterBand::SetSourceTransferType(GDALDataType eDataTypeIn)
458 : {
459 21 : eSourceTransferType = eDataTypeIn;
460 21 : }
461 :
462 : /************************************************************************/
463 : /* InitializePython() */
464 : /************************************************************************/
465 :
466 384 : bool VRTDerivedRasterBand::InitializePython()
467 : {
468 384 : if (m_poPrivate->m_bPythonInitializationDone)
469 321 : return m_poPrivate->m_bPythonInitializationSuccess;
470 :
471 63 : m_poPrivate->m_bPythonInitializationDone = true;
472 63 : m_poPrivate->m_bPythonInitializationSuccess = false;
473 :
474 63 : const size_t nIdxDot = osFuncName.rfind(".");
475 126 : CPLString osPythonModule;
476 126 : CPLString osPythonFunction;
477 63 : if (nIdxDot != std::string::npos)
478 : {
479 29 : osPythonModule = osFuncName.substr(0, nIdxDot);
480 29 : osPythonFunction = osFuncName.substr(nIdxDot + 1);
481 : }
482 : else
483 : {
484 34 : osPythonFunction = osFuncName;
485 : }
486 :
487 : #ifndef GDAL_VRT_DISABLE_PYTHON
488 : const char *pszPythonEnabled =
489 63 : CPLGetConfigOption("GDAL_VRT_ENABLE_PYTHON", nullptr);
490 : #else
491 : const char *pszPythonEnabled = "NO";
492 : #endif
493 : const CPLString osPythonEnabled(
494 126 : pszPythonEnabled ? pszPythonEnabled : GDAL_VRT_ENABLE_PYTHON_DEFAULT);
495 :
496 63 : if (EQUAL(osPythonEnabled, "TRUSTED_MODULES"))
497 : {
498 12 : bool bIsTrustedModule = false;
499 : const CPLString osVRTTrustedModules(
500 12 : CPLGetConfigOption("GDAL_VRT_PYTHON_TRUSTED_MODULES", ""));
501 12 : if (!osPythonModule.empty())
502 : {
503 : char **papszTrustedModules =
504 10 : CSLTokenizeString2(osVRTTrustedModules, ",", 0);
505 23 : for (char **papszIter = papszTrustedModules;
506 23 : !bIsTrustedModule && papszIter && *papszIter; ++papszIter)
507 : {
508 13 : const char *pszIterModule = *papszIter;
509 13 : size_t nIterModuleLen = strlen(pszIterModule);
510 13 : if (nIterModuleLen > 2 &&
511 12 : strncmp(pszIterModule + nIterModuleLen - 2, ".*", 2) == 0)
512 : {
513 2 : bIsTrustedModule =
514 2 : (strncmp(osPythonModule, pszIterModule,
515 3 : nIterModuleLen - 2) == 0) &&
516 1 : (osPythonModule.size() == nIterModuleLen - 2 ||
517 0 : (osPythonModule.size() >= nIterModuleLen &&
518 0 : osPythonModule[nIterModuleLen - 1] == '.'));
519 : }
520 11 : else if (nIterModuleLen >= 1 &&
521 11 : pszIterModule[nIterModuleLen - 1] == '*')
522 : {
523 4 : bIsTrustedModule = (strncmp(osPythonModule, pszIterModule,
524 : nIterModuleLen - 1) == 0);
525 : }
526 : else
527 : {
528 7 : bIsTrustedModule =
529 7 : (strcmp(osPythonModule, pszIterModule) == 0);
530 : }
531 : }
532 10 : CSLDestroy(papszTrustedModules);
533 : }
534 :
535 12 : if (!bIsTrustedModule)
536 : {
537 7 : if (osPythonModule.empty())
538 : {
539 2 : CPLError(
540 : CE_Failure, CPLE_AppDefined,
541 : "Python code needs to be executed, but it uses inline code "
542 : "in the VRT whereas the current policy is to trust only "
543 : "code from external trusted modules (defined in the "
544 : "GDAL_VRT_PYTHON_TRUSTED_MODULES configuration option). "
545 : "If you trust the code in %s, you can set the "
546 : "GDAL_VRT_ENABLE_PYTHON configuration option to YES.",
547 2 : GetDataset() ? GetDataset()->GetDescription()
548 : : "(unknown VRT)");
549 : }
550 5 : else if (osVRTTrustedModules.empty())
551 : {
552 2 : CPLError(
553 : CE_Failure, CPLE_AppDefined,
554 : "Python code needs to be executed, but it uses code "
555 : "from module '%s', whereas the current policy is to "
556 : "trust only code from modules defined in the "
557 : "GDAL_VRT_PYTHON_TRUSTED_MODULES configuration option, "
558 : "which is currently unset. "
559 : "If you trust the code in '%s', you can add module '%s' "
560 : "to GDAL_VRT_PYTHON_TRUSTED_MODULES (or set the "
561 : "GDAL_VRT_ENABLE_PYTHON configuration option to YES).",
562 : osPythonModule.c_str(),
563 1 : GetDataset() ? GetDataset()->GetDescription()
564 : : "(unknown VRT)",
565 : osPythonModule.c_str());
566 : }
567 : else
568 : {
569 8 : CPLError(
570 : CE_Failure, CPLE_AppDefined,
571 : "Python code needs to be executed, but it uses code "
572 : "from module '%s', whereas the current policy is to "
573 : "trust only code from modules '%s' (defined in the "
574 : "GDAL_VRT_PYTHON_TRUSTED_MODULES configuration option). "
575 : "If you trust the code in '%s', you can add module '%s' "
576 : "to GDAL_VRT_PYTHON_TRUSTED_MODULES (or set the "
577 : "GDAL_VRT_ENABLE_PYTHON configuration option to YES).",
578 : osPythonModule.c_str(), osVRTTrustedModules.c_str(),
579 4 : GetDataset() ? GetDataset()->GetDescription()
580 : : "(unknown VRT)",
581 : osPythonModule.c_str());
582 : }
583 7 : return false;
584 : }
585 : }
586 :
587 : #ifdef disabled_because_this_is_probably_broken_by_design
588 : // See https://lwn.net/Articles/574215/
589 : // and http://nedbatchelder.com/blog/201206/eval_really_is_dangerous.html
590 : else if (EQUAL(osPythonEnabled, "IF_SAFE"))
591 : {
592 : bool bSafe = true;
593 : // If the function comes from another module, then we don't know
594 : if (!osPythonModule.empty())
595 : {
596 : CPLDebug("VRT", "Python function is from another module");
597 : bSafe = false;
598 : }
599 :
600 : CPLString osCode(m_poPrivate->m_osCode);
601 :
602 : // Reject all imports except a few trusted modules
603 : const char *const apszTrustedImports[] = {
604 : "import math",
605 : "from math import",
606 : "import numpy", // caution: numpy has lots of I/O functions !
607 : "from numpy import",
608 : // TODO: not sure if importing arbitrary stuff from numba is OK
609 : // so let's just restrict to jit.
610 : "from numba import jit",
611 :
612 : // Not imports but still whitelisted, whereas other __ is banned
613 : "__init__",
614 : "__call__",
615 : };
616 : for (size_t i = 0; i < CPL_ARRAYSIZE(apszTrustedImports); ++i)
617 : {
618 : osCode.replaceAll(CPLString(apszTrustedImports[i]), "");
619 : }
620 :
621 : // Some dangerous built-in functions or numpy functions
622 : const char *const apszUntrusted[] = {
623 : "import", // and __import__
624 : "eval", "compile", "open",
625 : "load", // reload, numpy.load
626 : "file", // and exec_file, numpy.fromfile, numpy.tofile
627 : "input", // and raw_input
628 : "save", // numpy.save
629 : "memmap", // numpy.memmap
630 : "DataSource", // numpy.DataSource
631 : "genfromtxt", // numpy.genfromtxt
632 : "getattr",
633 : "ctypeslib", // numpy.ctypeslib
634 : "testing", // numpy.testing
635 : "dump", // numpy.ndarray.dump
636 : "fromregex", // numpy.fromregex
637 : "__"};
638 : for (size_t i = 0; i < CPL_ARRAYSIZE(apszUntrusted); ++i)
639 : {
640 : if (osCode.find(apszUntrusted[i]) != std::string::npos)
641 : {
642 : CPLDebug("VRT", "Found '%s' word in Python code",
643 : apszUntrusted[i]);
644 : bSafe = false;
645 : }
646 : }
647 :
648 : if (!bSafe)
649 : {
650 : CPLError(CE_Failure, CPLE_AppDefined,
651 : "Python code needs to be executed, but we cannot verify "
652 : "if it is safe, so this is disabled by default. "
653 : "If you trust the code in %s, you can set the "
654 : "GDAL_VRT_ENABLE_PYTHON configuration option to YES.",
655 : GetDataset() ? GetDataset()->GetDescription()
656 : : "(unknown VRT)");
657 : return false;
658 : }
659 : }
660 : #endif // disabled_because_this_is_probably_broken_by_design
661 :
662 52 : else if (!EQUAL(osPythonEnabled, "YES") && !EQUAL(osPythonEnabled, "ON") &&
663 1 : !EQUAL(osPythonEnabled, "TRUE"))
664 : {
665 1 : if (pszPythonEnabled == nullptr)
666 : {
667 : // Note: this is dead code with our current default policy
668 : // GDAL_VRT_ENABLE_PYTHON == "TRUSTED_MODULES"
669 0 : CPLError(CE_Failure, CPLE_AppDefined,
670 : "Python code needs to be executed, but this is "
671 : "disabled by default. If you trust the code in %s, "
672 : "you can set the GDAL_VRT_ENABLE_PYTHON configuration "
673 : "option to YES.",
674 0 : GetDataset() ? GetDataset()->GetDescription()
675 : : "(unknown VRT)");
676 : }
677 : else
678 : {
679 1 : CPLError(
680 : CE_Failure, CPLE_AppDefined,
681 : "Python code in %s needs to be executed, but this has been "
682 : "explicitly disabled.",
683 1 : GetDataset() ? GetDataset()->GetDescription()
684 : : "(unknown VRT)");
685 : }
686 1 : return false;
687 : }
688 :
689 55 : if (!GDALPythonInitialize())
690 2 : return false;
691 :
692 : // Whether we should just use our own global mutex, in addition to Python
693 : // GIL locking.
694 106 : m_poPrivate->m_bExclusiveLock =
695 53 : CPLTestBool(CPLGetConfigOption("GDAL_VRT_PYTHON_EXCLUSIVE_LOCK", "NO"));
696 :
697 : // numba jit'ification doesn't seem to be thread-safe, so force use of
698 : // lock now and at first execution of function. Later executions seem to
699 : // be thread-safe. This problem doesn't seem to appear for code in
700 : // regular files
701 : const bool bUseExclusiveLock =
702 106 : m_poPrivate->m_bExclusiveLock ||
703 53 : m_poPrivate->m_osCode.find("@jit") != std::string::npos;
704 106 : GIL_Holder oHolder(bUseExclusiveLock);
705 :
706 : // As we don't want to depend on numpy C API/ABI, we use a trick to build
707 : // a numpy array object. We define a Python function to which we pass a
708 : // Python buffer object.
709 :
710 : // We need to build a unique module name, otherwise this will crash in
711 : // multithreaded use cases.
712 106 : CPLString osModuleName(CPLSPrintf("gdal_vrt_module_%p", this));
713 106 : PyObject *poCompiledString = Py_CompileString(
714 : ("import numpy\n"
715 : "def GDALCreateNumpyArray(buffer, dtype, height, width):\n"
716 : " return numpy.frombuffer(buffer, str(dtype.decode('ascii')))."
717 : "reshape([height, width])\n"
718 53 : "\n" +
719 53 : m_poPrivate->m_osCode)
720 : .c_str(),
721 : osModuleName, Py_file_input);
722 53 : if (poCompiledString == nullptr || PyErr_Occurred())
723 : {
724 1 : CPLError(CE_Failure, CPLE_AppDefined, "Couldn't compile code:\n%s",
725 2 : GetPyExceptionString().c_str());
726 1 : return false;
727 : }
728 : PyObject *poModule =
729 52 : PyImport_ExecCodeModule(osModuleName, poCompiledString);
730 52 : Py_DecRef(poCompiledString);
731 :
732 52 : if (poModule == nullptr || PyErr_Occurred())
733 : {
734 1 : CPLError(CE_Failure, CPLE_AppDefined, "%s",
735 2 : GetPyExceptionString().c_str());
736 1 : return false;
737 : }
738 :
739 : // Fetch user computation function
740 51 : if (!osPythonModule.empty())
741 : {
742 24 : PyObject *poUserModule = PyImport_ImportModule(osPythonModule);
743 24 : if (poUserModule == nullptr || PyErr_Occurred())
744 : {
745 1 : CPLString osException = GetPyExceptionString();
746 1 : if (!osException.empty() && osException.back() == '\n')
747 : {
748 1 : osException.pop_back();
749 : }
750 1 : if (osException.find("ModuleNotFoundError") == 0)
751 : {
752 1 : osException += ". You may need to define PYTHONPATH";
753 : }
754 1 : CPLError(CE_Failure, CPLE_AppDefined, "%s", osException.c_str());
755 1 : Py_DecRef(poModule);
756 1 : return false;
757 : }
758 46 : m_poPrivate->m_poUserFunction =
759 23 : PyObject_GetAttrString(poUserModule, osPythonFunction);
760 23 : Py_DecRef(poUserModule);
761 : }
762 : else
763 : {
764 54 : m_poPrivate->m_poUserFunction =
765 27 : PyObject_GetAttrString(poModule, osPythonFunction);
766 : }
767 50 : if (m_poPrivate->m_poUserFunction == nullptr || PyErr_Occurred())
768 : {
769 1 : CPLError(CE_Failure, CPLE_AppDefined, "%s",
770 2 : GetPyExceptionString().c_str());
771 1 : Py_DecRef(poModule);
772 1 : return false;
773 : }
774 49 : if (!PyCallable_Check(m_poPrivate->m_poUserFunction))
775 : {
776 1 : CPLError(CE_Failure, CPLE_AppDefined, "Object '%s' is not callable",
777 : osPythonFunction.c_str());
778 1 : Py_DecRef(poModule);
779 1 : return false;
780 : }
781 :
782 : // Fetch our GDALCreateNumpyArray python function
783 96 : m_poPrivate->m_poGDALCreateNumpyArray =
784 48 : PyObject_GetAttrString(poModule, "GDALCreateNumpyArray");
785 48 : if (m_poPrivate->m_poGDALCreateNumpyArray == nullptr || PyErr_Occurred())
786 : {
787 : // Shouldn't happen normally...
788 0 : CPLError(CE_Failure, CPLE_AppDefined, "%s",
789 0 : GetPyExceptionString().c_str());
790 0 : Py_DecRef(poModule);
791 0 : return false;
792 : }
793 48 : Py_DecRef(poModule);
794 :
795 48 : m_poPrivate->m_bPythonInitializationSuccess = true;
796 48 : return true;
797 : }
798 :
799 1152 : CPLErr VRTDerivedRasterBand::GetPixelFunctionArguments(
800 : const CPLString &osMetadata,
801 : const std::vector<int> &anMapBufferIdxToSourceIdx,
802 : std::vector<std::pair<CPLString, CPLString>> &oAdditionalArgs)
803 : {
804 :
805 2304 : auto poArgs = CPLXMLTreeCloser(CPLParseXMLString(osMetadata));
806 2304 : if (poArgs != nullptr && poArgs->eType == CXT_Element &&
807 1152 : !strcmp(poArgs->pszValue, "PixelFunctionArgumentsList"))
808 : {
809 4483 : for (CPLXMLNode *psIter = poArgs->psChild; psIter != nullptr;
810 3331 : psIter = psIter->psNext)
811 : {
812 3332 : if (psIter->eType == CXT_Element &&
813 3332 : !strcmp(psIter->pszValue, "Argument"))
814 : {
815 3332 : CPLString osName, osType, osValue;
816 3332 : auto pszName = CPLGetXMLValue(psIter, "name", nullptr);
817 3332 : if (pszName != nullptr)
818 2180 : osName = pszName;
819 3332 : auto pszType = CPLGetXMLValue(psIter, "type", nullptr);
820 3332 : if (pszType != nullptr)
821 3332 : osType = pszType;
822 3332 : auto pszValue = CPLGetXMLValue(psIter, "value", nullptr);
823 3332 : if (pszValue != nullptr)
824 1217 : osValue = pszValue;
825 3332 : if (osType == "constant" && osValue != "" && osName != "")
826 1 : oAdditionalArgs.push_back(
827 2 : std::pair<CPLString, CPLString>(osName, osValue));
828 3332 : if (osType == "builtin")
829 : {
830 1152 : const CPLString &osArgName = osValue;
831 1152 : CPLString osVal;
832 1152 : double dfVal = 0;
833 :
834 : int success;
835 1152 : if (osArgName == "NoData")
836 1087 : dfVal = this->GetNoDataValue(&success);
837 65 : else if (osArgName == "scale")
838 3 : dfVal = this->GetScale(&success);
839 62 : else if (osArgName == "offset")
840 2 : dfVal = this->GetOffset(&success);
841 60 : else if (osArgName == "source_names")
842 : {
843 174 : for (size_t iBuffer = 0;
844 174 : iBuffer < anMapBufferIdxToSourceIdx.size();
845 : iBuffer++)
846 : {
847 114 : int iSource = anMapBufferIdxToSourceIdx[iBuffer];
848 114 : const VRTSource *poSource = papoSources[iSource];
849 :
850 114 : if (iBuffer > 0)
851 : {
852 61 : osVal += "|";
853 : }
854 :
855 114 : const auto &osSourceName = poSource->GetName();
856 114 : if (osSourceName.empty())
857 : {
858 36 : osVal += "B" + std::to_string(iBuffer + 1);
859 : }
860 : else
861 : {
862 78 : osVal += osSourceName;
863 : }
864 : }
865 :
866 60 : success = true;
867 : }
868 : else
869 : {
870 0 : CPLError(
871 : CE_Failure, CPLE_NotSupported,
872 : "PixelFunction builtin argument %s not supported",
873 : osArgName.c_str());
874 0 : return CE_Failure;
875 : }
876 1152 : if (!success)
877 : {
878 1008 : if (CPLTestBool(
879 : CPLGetXMLValue(psIter, "optional", "false")))
880 1007 : continue;
881 :
882 1 : CPLError(CE_Failure, CPLE_AppDefined,
883 : "Raster has no %s", osValue.c_str());
884 1 : return CE_Failure;
885 : }
886 :
887 144 : if (osVal.empty())
888 : {
889 91 : osVal = CPLSPrintf("%.17g", dfVal);
890 : }
891 :
892 144 : oAdditionalArgs.push_back(
893 288 : std::pair<CPLString, CPLString>(osArgName, osVal));
894 144 : CPLDebug("VRT",
895 : "Added builtin pixel function argument %s = %s",
896 : osArgName.c_str(), osVal.c_str());
897 : }
898 : }
899 : }
900 : }
901 :
902 1151 : return CE_None;
903 : }
904 :
905 : /************************************************************************/
906 : /* IRasterIO() */
907 : /************************************************************************/
908 :
909 : /**
910 : * Read/write a region of image data for this band.
911 : *
912 : * Each of the sources for this derived band will be read and passed to
913 : * the derived band pixel function. The pixel function is responsible
914 : * for applying whatever algorithm is necessary to generate this band's
915 : * pixels from the sources.
916 : *
917 : * The sources will be read using the transfer type specified for sources
918 : * using SetSourceTransferType(). If no transfer type has been set for
919 : * this derived band, the band's data type will be used as the transfer type.
920 : *
921 : * @see gdalrasterband
922 : *
923 : * @param eRWFlag Either GF_Read to read a region of data, or GT_Write to
924 : * write a region of data.
925 : *
926 : * @param nXOff The pixel offset to the top left corner of the region
927 : * of the band to be accessed. This would be zero to start from the left side.
928 : *
929 : * @param nYOff The line offset to the top left corner of the region
930 : * of the band to be accessed. This would be zero to start from the top.
931 : *
932 : * @param nXSize The width of the region of the band to be accessed in pixels.
933 : *
934 : * @param nYSize The height of the region of the band to be accessed in lines.
935 : *
936 : * @param pData The buffer into which the data should be read, or from which
937 : * it should be written. This buffer must contain at least nBufXSize *
938 : * nBufYSize words of type eBufType. It is organized in left to right,
939 : * top to bottom pixel order. Spacing is controlled by the nPixelSpace,
940 : * and nLineSpace parameters.
941 : *
942 : * @param nBufXSize The width of the buffer image into which the desired
943 : * region is to be read, or from which it is to be written.
944 : *
945 : * @param nBufYSize The height of the buffer image into which the desired
946 : * region is to be read, or from which it is to be written.
947 : *
948 : * @param eBufType The type of the pixel values in the pData data buffer. The
949 : * pixel values will automatically be translated to/from the GDALRasterBand
950 : * data type as needed.
951 : *
952 : * @param nPixelSpace The byte offset from the start of one pixel value in
953 : * pData to the start of the next pixel value within a scanline. If defaulted
954 : * (0) the size of the datatype eBufType is used.
955 : *
956 : * @param nLineSpace The byte offset from the start of one scanline in
957 : * pData to the start of the next. If defaulted the size of the datatype
958 : * eBufType * nBufXSize is used.
959 : *
960 : * @return CE_Failure if the access fails, otherwise CE_None.
961 : */
962 1596 : CPLErr VRTDerivedRasterBand::IRasterIO(
963 : GDALRWFlag eRWFlag, int nXOff, int nYOff, int nXSize, int nYSize,
964 : void *pData, int nBufXSize, int nBufYSize, GDALDataType eBufType,
965 : GSpacing nPixelSpace, GSpacing nLineSpace, GDALRasterIOExtraArg *psExtraArg)
966 : {
967 1596 : if (eRWFlag == GF_Write)
968 : {
969 1 : CPLError(CE_Failure, CPLE_AppDefined,
970 : "Writing through VRTSourcedRasterBand is not supported.");
971 1 : return CE_Failure;
972 : }
973 :
974 1595 : const int nBufTypeSize = GDALGetDataTypeSizeBytes(eBufType);
975 1595 : GDALDataType eSrcType = eSourceTransferType;
976 1595 : if (eSrcType == GDT_Unknown || eSrcType >= GDT_TypeCount)
977 : {
978 : // Check the largest data type for all sources
979 711 : GDALDataType eAllSrcType = GDT_Unknown;
980 1387 : for (int iSource = 0; iSource < nSources; iSource++)
981 : {
982 677 : if (papoSources[iSource]->GetType() ==
983 677 : VRTSimpleSource::GetTypeStatic())
984 : {
985 676 : const auto poSS =
986 676 : static_cast<VRTSimpleSource *>(papoSources[iSource]);
987 676 : auto l_poBand = poSS->GetRasterBand();
988 676 : if (l_poBand)
989 : {
990 676 : eAllSrcType = GDALDataTypeUnion(
991 : eAllSrcType, l_poBand->GetRasterDataType());
992 : }
993 : else
994 : {
995 0 : eAllSrcType = GDT_Unknown;
996 0 : break;
997 : }
998 : }
999 : else
1000 : {
1001 1 : eAllSrcType = GDT_Unknown;
1002 1 : break;
1003 : }
1004 : }
1005 :
1006 711 : if (eAllSrcType != GDT_Unknown)
1007 329 : eSrcType = eAllSrcType;
1008 : else
1009 382 : eSrcType = eBufType;
1010 : }
1011 1595 : const int nSrcTypeSize = GDALGetDataTypeSizeBytes(eSrcType);
1012 :
1013 : /* -------------------------------------------------------------------- */
1014 : /* Initialize the buffer to some background value. Use the */
1015 : /* nodata value if available. */
1016 : /* -------------------------------------------------------------------- */
1017 1595 : if (SkipBufferInitialization())
1018 : {
1019 : // Do nothing
1020 : }
1021 1509 : else if (nPixelSpace == nBufTypeSize &&
1022 1509 : (!m_bNoDataValueSet || m_dfNoDataValue == 0))
1023 : {
1024 1441 : memset(pData, 0,
1025 1441 : static_cast<size_t>(nBufXSize) * nBufYSize * nBufTypeSize);
1026 : }
1027 68 : else if (m_bNoDataValueSet)
1028 : {
1029 68 : double dfWriteValue = m_dfNoDataValue;
1030 :
1031 201 : for (int iLine = 0; iLine < nBufYSize; iLine++)
1032 : {
1033 133 : GDALCopyWords64(&dfWriteValue, GDT_Float64, 0,
1034 133 : static_cast<GByte *>(pData) + nLineSpace * iLine,
1035 : eBufType, static_cast<int>(nPixelSpace), nBufXSize);
1036 : }
1037 : }
1038 :
1039 : /* -------------------------------------------------------------------- */
1040 : /* Do we have overviews that would be appropriate to satisfy */
1041 : /* this request? */
1042 : /* -------------------------------------------------------------------- */
1043 1595 : if ((nBufXSize < nXSize || nBufYSize < nYSize) && GetOverviewCount() > 0)
1044 : {
1045 0 : if (OverviewRasterIO(eRWFlag, nXOff, nYOff, nXSize, nYSize, pData,
1046 : nBufXSize, nBufYSize, eBufType, nPixelSpace,
1047 0 : nLineSpace, psExtraArg) == CE_None)
1048 0 : return CE_None;
1049 : }
1050 :
1051 : /* ---- Get pixel function for band ---- */
1052 1595 : const std::pair<PixelFunc, std::string> *poPixelFunc = nullptr;
1053 3190 : std::vector<std::pair<CPLString, CPLString>> oAdditionalArgs;
1054 :
1055 1595 : if (EQUAL(m_poPrivate->m_osLanguage, "C"))
1056 : {
1057 : poPixelFunc =
1058 1201 : VRTDerivedRasterBand::GetPixelFunction(osFuncName.c_str());
1059 1201 : if (poPixelFunc == nullptr)
1060 : {
1061 1 : CPLError(CE_Failure, CPLE_IllegalArg,
1062 : "VRTDerivedRasterBand::IRasterIO:"
1063 : "Derived band pixel function '%s' not registered.",
1064 : osFuncName.c_str());
1065 1 : return CE_Failure;
1066 : }
1067 : }
1068 :
1069 : /* TODO: It would be nice to use a MallocBlock function for each
1070 : individual buffer that would recycle blocks of memory from a
1071 : cache by reassigning blocks that are nearly the same size.
1072 : A corresponding FreeBlock might only truly free if the total size
1073 : of freed blocks gets to be too great of a percentage of the size
1074 : of the allocated blocks. */
1075 :
1076 : // Get buffers for each source.
1077 1594 : const int nBufferRadius = m_poPrivate->m_nBufferRadius;
1078 1594 : if (nBufferRadius > (INT_MAX - nBufXSize) / 2 ||
1079 1594 : nBufferRadius > (INT_MAX - nBufYSize) / 2)
1080 : {
1081 0 : CPLError(CE_Failure, CPLE_AppDefined,
1082 : "Integer overflow: "
1083 : "nBufferRadius > (INT_MAX - nBufXSize) / 2 || "
1084 : "nBufferRadius > (INT_MAX - nBufYSize) / 2)");
1085 0 : return CE_Failure;
1086 : }
1087 1594 : const int nExtBufXSize = nBufXSize + 2 * nBufferRadius;
1088 1594 : const int nExtBufYSize = nBufYSize + 2 * nBufferRadius;
1089 1594 : int nBufferCount = 0;
1090 :
1091 3188 : std::vector<void *> apBuffers(nSources);
1092 3188 : std::vector<int> anMapBufferIdxToSourceIdx(nSources);
1093 3966 : for (int iSource = 0; iSource < nSources; iSource++)
1094 : {
1095 2386 : if (m_poPrivate->m_bSkipNonContributingSources &&
1096 14 : papoSources[iSource]->IsSimpleSource())
1097 : {
1098 14 : bool bError = false;
1099 : double dfReqXOff, dfReqYOff, dfReqXSize, dfReqYSize;
1100 : int nReqXOff, nReqYOff, nReqXSize, nReqYSize;
1101 : int nOutXOff, nOutYOff, nOutXSize, nOutYSize;
1102 14 : auto poSource =
1103 14 : static_cast<VRTSimpleSource *>(papoSources[iSource]);
1104 14 : if (!poSource->GetSrcDstWindow(
1105 : nXOff, nYOff, nXSize, nYSize, nBufXSize, nBufYSize,
1106 : &dfReqXOff, &dfReqYOff, &dfReqXSize, &dfReqYSize, &nReqXOff,
1107 : &nReqYOff, &nReqXSize, &nReqYSize, &nOutXOff, &nOutYOff,
1108 : &nOutXSize, &nOutYSize, bError))
1109 : {
1110 4 : if (bError)
1111 : {
1112 0 : for (int i = 0; i < nBufferCount; i++)
1113 : {
1114 0 : VSIFree(apBuffers[i]);
1115 : }
1116 0 : return CE_Failure;
1117 : }
1118 :
1119 : // Skip non contributing source
1120 4 : continue;
1121 : }
1122 : }
1123 :
1124 2368 : anMapBufferIdxToSourceIdx[nBufferCount] = iSource;
1125 4736 : apBuffers[nBufferCount] =
1126 2368 : VSI_MALLOC3_VERBOSE(nSrcTypeSize, nExtBufXSize, nExtBufYSize);
1127 2368 : if (apBuffers[nBufferCount] == nullptr)
1128 : {
1129 0 : for (int i = 0; i < nBufferCount; i++)
1130 : {
1131 0 : VSIFree(apBuffers[i]);
1132 : }
1133 0 : return CE_Failure;
1134 : }
1135 :
1136 2368 : bool bBufferInit = true;
1137 2368 : if (papoSources[iSource]->GetType() == VRTSimpleSource::GetTypeStatic())
1138 : {
1139 2356 : const auto poSS =
1140 2356 : static_cast<VRTSimpleSource *>(papoSources[iSource]);
1141 2356 : auto l_poBand = poSS->GetRasterBand();
1142 2356 : if (l_poBand != nullptr && poSS->m_dfSrcXOff == 0.0 &&
1143 269 : poSS->m_dfSrcYOff == 0.0 &&
1144 538 : poSS->m_dfSrcXOff + poSS->m_dfSrcXSize ==
1145 269 : l_poBand->GetXSize() &&
1146 502 : poSS->m_dfSrcYOff + poSS->m_dfSrcYSize ==
1147 251 : l_poBand->GetYSize() &&
1148 251 : poSS->m_dfDstXOff == 0.0 && poSS->m_dfDstYOff == 0.0 &&
1149 4957 : poSS->m_dfDstXOff + poSS->m_dfDstXSize == nRasterXSize &&
1150 245 : poSS->m_dfDstYOff + poSS->m_dfDstYSize == nRasterYSize)
1151 : {
1152 245 : bBufferInit = false;
1153 : }
1154 : }
1155 2368 : if (bBufferInit)
1156 : {
1157 : /* ------------------------------------------------------------ */
1158 : /* #4045: Initialize the newly allocated buffers before handing */
1159 : /* them off to the sources. These buffers are packed, so we */
1160 : /* don't need any special line-by-line handling when a nonzero */
1161 : /* nodata value is set. */
1162 : /* ------------------------------------------------------------ */
1163 2123 : if (!m_bNoDataValueSet || m_dfNoDataValue == 0)
1164 : {
1165 1941 : memset(apBuffers[nBufferCount], 0,
1166 1941 : static_cast<size_t>(nSrcTypeSize) * nExtBufXSize *
1167 1941 : nExtBufYSize);
1168 : }
1169 : else
1170 : {
1171 182 : GDALCopyWords64(&m_dfNoDataValue, GDT_Float64, 0,
1172 182 : static_cast<GByte *>(apBuffers[nBufferCount]),
1173 : eSrcType, nSrcTypeSize,
1174 182 : static_cast<GPtrDiff_t>(nExtBufXSize) *
1175 182 : nExtBufYSize);
1176 : }
1177 : }
1178 :
1179 2368 : ++nBufferCount;
1180 : }
1181 :
1182 : // No contributing sources and SkipNonContributingSources mode ?
1183 : // Do not call the pixel function and just return the 0/nodata initialized
1184 : // output buffer.
1185 1594 : if (nBufferCount == 0 && m_poPrivate->m_bSkipNonContributingSources)
1186 : {
1187 1 : return CE_None;
1188 : }
1189 :
1190 : GDALRasterIOExtraArg sExtraArg;
1191 1593 : GDALCopyRasterIOExtraArg(&sExtraArg, psExtraArg);
1192 :
1193 1593 : int nXShiftInBuffer = 0;
1194 1593 : int nYShiftInBuffer = 0;
1195 1593 : int nExtBufXSizeReq = nExtBufXSize;
1196 1593 : int nExtBufYSizeReq = nExtBufYSize;
1197 :
1198 1593 : int nXOffExt = nXOff;
1199 1593 : int nYOffExt = nYOff;
1200 1593 : int nXSizeExt = nXSize;
1201 1593 : int nYSizeExt = nYSize;
1202 :
1203 1593 : if (nBufferRadius)
1204 : {
1205 9 : double dfXRatio = static_cast<double>(nXSize) / nBufXSize;
1206 9 : double dfYRatio = static_cast<double>(nYSize) / nBufYSize;
1207 :
1208 9 : if (!sExtraArg.bFloatingPointWindowValidity)
1209 : {
1210 9 : sExtraArg.dfXOff = nXOff;
1211 9 : sExtraArg.dfYOff = nYOff;
1212 9 : sExtraArg.dfXSize = nXSize;
1213 9 : sExtraArg.dfYSize = nYSize;
1214 : }
1215 :
1216 9 : sExtraArg.dfXOff -= dfXRatio * nBufferRadius;
1217 9 : sExtraArg.dfYOff -= dfYRatio * nBufferRadius;
1218 9 : sExtraArg.dfXSize += 2 * dfXRatio * nBufferRadius;
1219 9 : sExtraArg.dfYSize += 2 * dfYRatio * nBufferRadius;
1220 9 : if (sExtraArg.dfXOff < 0)
1221 : {
1222 9 : nXShiftInBuffer = -static_cast<int>(sExtraArg.dfXOff / dfXRatio);
1223 9 : nExtBufXSizeReq -= nXShiftInBuffer;
1224 9 : sExtraArg.dfXSize += sExtraArg.dfXOff;
1225 9 : sExtraArg.dfXOff = 0;
1226 : }
1227 9 : if (sExtraArg.dfYOff < 0)
1228 : {
1229 9 : nYShiftInBuffer = -static_cast<int>(sExtraArg.dfYOff / dfYRatio);
1230 9 : nExtBufYSizeReq -= nYShiftInBuffer;
1231 9 : sExtraArg.dfYSize += sExtraArg.dfYOff;
1232 9 : sExtraArg.dfYOff = 0;
1233 : }
1234 9 : if (sExtraArg.dfXOff + sExtraArg.dfXSize > nRasterXSize)
1235 : {
1236 9 : nExtBufXSizeReq -= static_cast<int>(
1237 9 : (sExtraArg.dfXOff + sExtraArg.dfXSize - nRasterXSize) /
1238 : dfXRatio);
1239 9 : sExtraArg.dfXSize = nRasterXSize - sExtraArg.dfXOff;
1240 : }
1241 9 : if (sExtraArg.dfYOff + sExtraArg.dfYSize > nRasterYSize)
1242 : {
1243 9 : nExtBufYSizeReq -= static_cast<int>(
1244 9 : (sExtraArg.dfYOff + sExtraArg.dfYSize - nRasterYSize) /
1245 : dfYRatio);
1246 9 : sExtraArg.dfYSize = nRasterYSize - sExtraArg.dfYOff;
1247 : }
1248 :
1249 9 : nXOffExt = static_cast<int>(sExtraArg.dfXOff);
1250 9 : nYOffExt = static_cast<int>(sExtraArg.dfYOff);
1251 18 : nXSizeExt = std::min(static_cast<int>(sExtraArg.dfXSize + 0.5),
1252 9 : nRasterXSize - nXOffExt);
1253 18 : nYSizeExt = std::min(static_cast<int>(sExtraArg.dfYSize + 0.5),
1254 9 : nRasterYSize - nYOffExt);
1255 : }
1256 :
1257 : // Load values for sources into packed buffers.
1258 1593 : CPLErr eErr = CE_None;
1259 1593 : VRTSource::WorkingState oWorkingState;
1260 3961 : for (int iBuffer = 0; iBuffer < nBufferCount && eErr == CE_None; iBuffer++)
1261 : {
1262 2368 : const int iSource = anMapBufferIdxToSourceIdx[iBuffer];
1263 2368 : GByte *pabyBuffer = static_cast<GByte *>(apBuffers[iBuffer]);
1264 2368 : eErr = static_cast<VRTSource *>(papoSources[iSource])
1265 4736 : ->RasterIO(
1266 : eSrcType, nXOffExt, nYOffExt, nXSizeExt, nYSizeExt,
1267 2368 : pabyBuffer + (static_cast<size_t>(nYShiftInBuffer) *
1268 2368 : nExtBufXSize +
1269 2368 : nXShiftInBuffer) *
1270 2368 : nSrcTypeSize,
1271 : nExtBufXSizeReq, nExtBufYSizeReq, eSrcType, nSrcTypeSize,
1272 2368 : static_cast<GSpacing>(nSrcTypeSize) * nExtBufXSize,
1273 2368 : &sExtraArg, oWorkingState);
1274 :
1275 : // Extend first lines
1276 2377 : for (int iY = 0; iY < nYShiftInBuffer; iY++)
1277 : {
1278 9 : memcpy(pabyBuffer +
1279 9 : static_cast<size_t>(iY) * nExtBufXSize * nSrcTypeSize,
1280 9 : pabyBuffer + static_cast<size_t>(nYShiftInBuffer) *
1281 9 : nExtBufXSize * nSrcTypeSize,
1282 9 : static_cast<size_t>(nExtBufXSize) * nSrcTypeSize);
1283 : }
1284 : // Extend last lines
1285 2377 : for (int iY = nYShiftInBuffer + nExtBufYSizeReq; iY < nExtBufYSize;
1286 : iY++)
1287 : {
1288 9 : memcpy(pabyBuffer +
1289 9 : static_cast<size_t>(iY) * nExtBufXSize * nSrcTypeSize,
1290 9 : pabyBuffer + static_cast<size_t>(nYShiftInBuffer +
1291 9 : nExtBufYSizeReq - 1) *
1292 9 : nExtBufXSize * nSrcTypeSize,
1293 9 : static_cast<size_t>(nExtBufXSize) * nSrcTypeSize);
1294 : }
1295 : // Extend first cols
1296 2368 : if (nXShiftInBuffer)
1297 : {
1298 1116 : for (int iY = 0; iY < nExtBufYSize; iY++)
1299 : {
1300 2214 : for (int iX = 0; iX < nXShiftInBuffer; iX++)
1301 : {
1302 1107 : memcpy(pabyBuffer +
1303 1107 : static_cast<size_t>(iY * nExtBufXSize + iX) *
1304 1107 : nSrcTypeSize,
1305 1107 : pabyBuffer +
1306 1107 : (static_cast<size_t>(iY) * nExtBufXSize +
1307 1107 : nXShiftInBuffer) *
1308 1107 : nSrcTypeSize,
1309 : nSrcTypeSize);
1310 : }
1311 : }
1312 : }
1313 : // Extent last cols
1314 2368 : if (nXShiftInBuffer + nExtBufXSizeReq < nExtBufXSize)
1315 : {
1316 1116 : for (int iY = 0; iY < nExtBufYSize; iY++)
1317 : {
1318 1107 : for (int iX = nXShiftInBuffer + nExtBufXSizeReq;
1319 2214 : iX < nExtBufXSize; iX++)
1320 : {
1321 1107 : memcpy(pabyBuffer +
1322 1107 : (static_cast<size_t>(iY) * nExtBufXSize + iX) *
1323 1107 : nSrcTypeSize,
1324 1107 : pabyBuffer +
1325 1107 : (static_cast<size_t>(iY) * nExtBufXSize +
1326 1107 : nXShiftInBuffer + nExtBufXSizeReq - 1) *
1327 1107 : nSrcTypeSize,
1328 : nSrcTypeSize);
1329 : }
1330 : }
1331 : }
1332 : }
1333 :
1334 : // Collect any pixel function arguments
1335 1593 : if (poPixelFunc != nullptr && !poPixelFunc->second.empty())
1336 : {
1337 2304 : if (GetPixelFunctionArguments(poPixelFunc->second,
1338 : anMapBufferIdxToSourceIdx,
1339 1152 : oAdditionalArgs) != CE_None)
1340 : {
1341 1 : eErr = CE_Failure;
1342 : }
1343 : }
1344 :
1345 : // Apply pixel function.
1346 1593 : if (eErr == CE_None && EQUAL(m_poPrivate->m_osLanguage, "Python"))
1347 : {
1348 393 : eErr = CE_Failure;
1349 :
1350 : // numpy doesn't have native cint16/cint32/cfloat16
1351 393 : if (eSrcType == GDT_CInt16 || eSrcType == GDT_CInt32 ||
1352 : eSrcType == GDT_CFloat16)
1353 : {
1354 2 : CPLError(CE_Failure, CPLE_AppDefined,
1355 : "CInt16/CInt32/CFloat16 data type not supported for "
1356 : "SourceTransferType");
1357 2 : goto end;
1358 : }
1359 391 : if (eDataType == GDT_CInt16 || eDataType == GDT_CInt32 ||
1360 387 : eDataType == GDT_CFloat16)
1361 : {
1362 7 : CPLError(
1363 : CE_Failure, CPLE_AppDefined,
1364 : "CInt16/CInt32/CFloat16 data type not supported for data type");
1365 7 : goto end;
1366 : }
1367 :
1368 384 : if (!InitializePython())
1369 15 : goto end;
1370 :
1371 369 : GByte *pabyTmpBuffer = nullptr;
1372 : // Do we need a temporary buffer or can we use directly the output
1373 : // buffer ?
1374 369 : if (nBufferRadius != 0 || eDataType != eBufType ||
1375 25 : nPixelSpace != nBufTypeSize ||
1376 25 : nLineSpace != static_cast<GSpacing>(nBufTypeSize) * nBufXSize)
1377 : {
1378 344 : pabyTmpBuffer = static_cast<GByte *>(VSI_CALLOC_VERBOSE(
1379 : static_cast<size_t>(nExtBufXSize) * nExtBufYSize,
1380 : GDALGetDataTypeSizeBytes(eDataType)));
1381 344 : if (!pabyTmpBuffer)
1382 0 : goto end;
1383 : }
1384 :
1385 : {
1386 : const bool bUseExclusiveLock =
1387 738 : m_poPrivate->m_bExclusiveLock ||
1388 417 : (m_poPrivate->m_bFirstTime &&
1389 48 : m_poPrivate->m_osCode.find("@jit") != std::string::npos);
1390 369 : m_poPrivate->m_bFirstTime = false;
1391 369 : GIL_Holder oHolder(bUseExclusiveLock);
1392 :
1393 : // Prepare target numpy array
1394 : PyObject *poPyDstArray =
1395 369 : GDALCreateNumpyArray(m_poPrivate->m_poGDALCreateNumpyArray,
1396 : pabyTmpBuffer ? pabyTmpBuffer : pData,
1397 : eDataType, nExtBufYSize, nExtBufXSize);
1398 369 : if (!poPyDstArray)
1399 : {
1400 0 : VSIFree(pabyTmpBuffer);
1401 0 : goto end;
1402 : }
1403 :
1404 : // Wrap source buffers as input numpy arrays
1405 369 : PyObject *pyArgInputArray = PyTuple_New(nBufferCount);
1406 399 : for (int i = 0; i < nBufferCount; i++)
1407 : {
1408 30 : GByte *pabyBuffer = static_cast<GByte *>(apBuffers[i]);
1409 60 : PyObject *poPySrcArray = GDALCreateNumpyArray(
1410 30 : m_poPrivate->m_poGDALCreateNumpyArray, pabyBuffer, eSrcType,
1411 : nExtBufYSize, nExtBufXSize);
1412 30 : CPLAssert(poPySrcArray);
1413 30 : PyTuple_SetItem(pyArgInputArray, i, poPySrcArray);
1414 : }
1415 :
1416 : // Create arguments
1417 369 : PyObject *pyArgs = PyTuple_New(10);
1418 369 : PyTuple_SetItem(pyArgs, 0, pyArgInputArray);
1419 369 : PyTuple_SetItem(pyArgs, 1, poPyDstArray);
1420 369 : PyTuple_SetItem(pyArgs, 2, PyLong_FromLong(nXOff));
1421 369 : PyTuple_SetItem(pyArgs, 3, PyLong_FromLong(nYOff));
1422 369 : PyTuple_SetItem(pyArgs, 4, PyLong_FromLong(nXSize));
1423 369 : PyTuple_SetItem(pyArgs, 5, PyLong_FromLong(nYSize));
1424 369 : PyTuple_SetItem(pyArgs, 6, PyLong_FromLong(nRasterXSize));
1425 369 : PyTuple_SetItem(pyArgs, 7, PyLong_FromLong(nRasterYSize));
1426 369 : PyTuple_SetItem(pyArgs, 8, PyLong_FromLong(nBufferRadius));
1427 :
1428 : double adfGeoTransform[6];
1429 369 : adfGeoTransform[0] = 0;
1430 369 : adfGeoTransform[1] = 1;
1431 369 : adfGeoTransform[2] = 0;
1432 369 : adfGeoTransform[3] = 0;
1433 369 : adfGeoTransform[4] = 0;
1434 369 : adfGeoTransform[5] = 1;
1435 369 : if (GetDataset())
1436 369 : GetDataset()->GetGeoTransform(adfGeoTransform);
1437 369 : PyObject *pyGT = PyTuple_New(6);
1438 2583 : for (int i = 0; i < 6; i++)
1439 2214 : PyTuple_SetItem(pyGT, i,
1440 : PyFloat_FromDouble(adfGeoTransform[i]));
1441 369 : PyTuple_SetItem(pyArgs, 9, pyGT);
1442 :
1443 : // Prepare kwargs
1444 369 : PyObject *pyKwargs = PyDict_New();
1445 379 : for (size_t i = 0; i < m_poPrivate->m_oFunctionArgs.size(); ++i)
1446 : {
1447 : const char *pszKey =
1448 10 : m_poPrivate->m_oFunctionArgs[i].first.c_str();
1449 : const char *pszValue =
1450 10 : m_poPrivate->m_oFunctionArgs[i].second.c_str();
1451 10 : PyDict_SetItemString(
1452 : pyKwargs, pszKey,
1453 : PyBytes_FromStringAndSize(pszValue, strlen(pszValue)));
1454 : }
1455 :
1456 : // Call user function
1457 : PyObject *pRetValue =
1458 369 : PyObject_Call(m_poPrivate->m_poUserFunction, pyArgs, pyKwargs);
1459 :
1460 369 : Py_DecRef(pyArgs);
1461 369 : Py_DecRef(pyKwargs);
1462 :
1463 369 : if (ErrOccurredEmitCPLError())
1464 : {
1465 : // do nothing
1466 : }
1467 : else
1468 : {
1469 367 : eErr = CE_None;
1470 : }
1471 369 : if (pRetValue)
1472 367 : Py_DecRef(pRetValue);
1473 : } // End of GIL section
1474 :
1475 369 : if (pabyTmpBuffer)
1476 : {
1477 : // Copy numpy destination array to user buffer
1478 41224 : for (int iY = 0; iY < nBufYSize; iY++)
1479 : {
1480 : size_t nSrcOffset =
1481 40880 : (static_cast<size_t>(iY + nBufferRadius) * nExtBufXSize +
1482 40880 : nBufferRadius) *
1483 40880 : GDALGetDataTypeSizeBytes(eDataType);
1484 40878 : GDALCopyWords64(pabyTmpBuffer + nSrcOffset, eDataType,
1485 : GDALGetDataTypeSizeBytes(eDataType),
1486 40877 : static_cast<GByte *>(pData) + iY * nLineSpace,
1487 : eBufType, static_cast<int>(nPixelSpace),
1488 : nBufXSize);
1489 : }
1490 :
1491 344 : VSIFree(pabyTmpBuffer);
1492 : }
1493 : }
1494 1200 : else if (eErr == CE_None && poPixelFunc != nullptr)
1495 : {
1496 1199 : CPLStringList aosArgs;
1497 :
1498 1199 : oAdditionalArgs.insert(oAdditionalArgs.end(),
1499 1199 : m_poPrivate->m_oFunctionArgs.begin(),
1500 2398 : m_poPrivate->m_oFunctionArgs.end());
1501 2494 : for (const auto &oArg : oAdditionalArgs)
1502 : {
1503 1295 : const char *pszKey = oArg.first.c_str();
1504 1295 : const char *pszValue = oArg.second.c_str();
1505 1295 : aosArgs.SetNameValue(pszKey, pszValue);
1506 : }
1507 :
1508 1199 : eErr = (poPixelFunc->first)(
1509 : apBuffers.data(), nBufferCount, pData, nBufXSize, nBufYSize,
1510 : eSrcType, eBufType, static_cast<int>(nPixelSpace),
1511 1199 : static_cast<int>(nLineSpace), aosArgs.List());
1512 : }
1513 1 : end:
1514 : // Release buffers.
1515 3961 : for (int iBuffer = 0; iBuffer < nBufferCount; iBuffer++)
1516 : {
1517 2368 : VSIFree(apBuffers[iBuffer]);
1518 : }
1519 :
1520 1593 : return eErr;
1521 : }
1522 :
1523 : /************************************************************************/
1524 : /* IGetDataCoverageStatus() */
1525 : /************************************************************************/
1526 :
1527 57 : int VRTDerivedRasterBand::IGetDataCoverageStatus(
1528 : int /* nXOff */, int /* nYOff */, int /* nXSize */, int /* nYSize */,
1529 : int /* nMaskFlagStop */, double *pdfDataPct)
1530 : {
1531 57 : if (pdfDataPct != nullptr)
1532 0 : *pdfDataPct = -1.0;
1533 : return GDAL_DATA_COVERAGE_STATUS_UNIMPLEMENTED |
1534 57 : GDAL_DATA_COVERAGE_STATUS_DATA;
1535 : }
1536 :
1537 : /************************************************************************/
1538 : /* XMLInit() */
1539 : /************************************************************************/
1540 :
1541 1273 : CPLErr VRTDerivedRasterBand::XMLInit(const CPLXMLNode *psTree,
1542 : const char *pszVRTPath,
1543 : VRTMapSharedResources &oMapSharedSources)
1544 :
1545 : {
1546 : const CPLErr eErr =
1547 1273 : VRTSourcedRasterBand::XMLInit(psTree, pszVRTPath, oMapSharedSources);
1548 1273 : if (eErr != CE_None)
1549 0 : return eErr;
1550 :
1551 : // Read derived pixel function type.
1552 1273 : SetPixelFunctionName(CPLGetXMLValue(psTree, "PixelFunctionType", nullptr));
1553 1273 : if (osFuncName.empty())
1554 : {
1555 1 : CPLError(CE_Failure, CPLE_AppDefined, "PixelFunctionType missing");
1556 1 : return CE_Failure;
1557 : }
1558 :
1559 1272 : m_poPrivate->m_osLanguage =
1560 1272 : CPLGetXMLValue(psTree, "PixelFunctionLanguage", "C");
1561 1347 : if (!EQUAL(m_poPrivate->m_osLanguage, "C") &&
1562 75 : !EQUAL(m_poPrivate->m_osLanguage, "Python"))
1563 : {
1564 1 : CPLError(CE_Failure, CPLE_NotSupported,
1565 : "Unsupported PixelFunctionLanguage");
1566 1 : return CE_Failure;
1567 : }
1568 :
1569 1271 : m_poPrivate->m_osCode = CPLGetXMLValue(psTree, "PixelFunctionCode", "");
1570 1310 : if (!m_poPrivate->m_osCode.empty() &&
1571 39 : !EQUAL(m_poPrivate->m_osLanguage, "Python"))
1572 : {
1573 1 : CPLError(CE_Failure, CPLE_NotSupported,
1574 : "PixelFunctionCode can only be used with Python");
1575 1 : return CE_Failure;
1576 : }
1577 :
1578 1270 : m_poPrivate->m_nBufferRadius =
1579 1270 : atoi(CPLGetXMLValue(psTree, "BufferRadius", "0"));
1580 1270 : if (m_poPrivate->m_nBufferRadius < 0 || m_poPrivate->m_nBufferRadius > 1024)
1581 : {
1582 1 : CPLError(CE_Failure, CPLE_AppDefined, "Invalid value for BufferRadius");
1583 1 : return CE_Failure;
1584 : }
1585 1280 : if (m_poPrivate->m_nBufferRadius != 0 &&
1586 11 : !EQUAL(m_poPrivate->m_osLanguage, "Python"))
1587 : {
1588 1 : CPLError(CE_Failure, CPLE_NotSupported,
1589 : "BufferRadius can only be used with Python");
1590 1 : return CE_Failure;
1591 : }
1592 :
1593 : const CPLXMLNode *const psArgs =
1594 1268 : CPLGetXMLNode(psTree, "PixelFunctionArguments");
1595 1268 : if (psArgs != nullptr)
1596 : {
1597 2358 : for (const CPLXMLNode *psIter = psArgs->psChild; psIter;
1598 1241 : psIter = psIter->psNext)
1599 : {
1600 1241 : if (psIter->eType == CXT_Attribute)
1601 : {
1602 1241 : AddPixelFunctionArgument(psIter->pszValue,
1603 1241 : psIter->psChild->pszValue);
1604 : }
1605 : }
1606 : }
1607 :
1608 : // Read optional source transfer data type.
1609 : const char *pszTypeName =
1610 1268 : CPLGetXMLValue(psTree, "SourceTransferType", nullptr);
1611 1268 : if (pszTypeName != nullptr)
1612 : {
1613 874 : eSourceTransferType = GDALGetDataTypeByName(pszTypeName);
1614 : }
1615 :
1616 : // Whether to skip non contributing sources
1617 : const char *pszSkipNonContributingSources =
1618 1268 : CPLGetXMLValue(psTree, "SkipNonContributingSources", nullptr);
1619 1268 : if (pszSkipNonContributingSources)
1620 : {
1621 2 : SetSkipNonContributingSources(
1622 2 : CPLTestBool(pszSkipNonContributingSources));
1623 : }
1624 :
1625 1268 : return CE_None;
1626 : }
1627 :
1628 : /************************************************************************/
1629 : /* SerializeToXML() */
1630 : /************************************************************************/
1631 :
1632 24 : CPLXMLNode *VRTDerivedRasterBand::SerializeToXML(const char *pszVRTPath,
1633 : bool &bHasWarnedAboutRAMUsage,
1634 : size_t &nAccRAMUsage)
1635 : {
1636 24 : CPLXMLNode *psTree = VRTSourcedRasterBand::SerializeToXML(
1637 : pszVRTPath, bHasWarnedAboutRAMUsage, nAccRAMUsage);
1638 :
1639 : /* -------------------------------------------------------------------- */
1640 : /* Set subclass. */
1641 : /* -------------------------------------------------------------------- */
1642 24 : CPLCreateXMLNode(CPLCreateXMLNode(psTree, CXT_Attribute, "subClass"),
1643 : CXT_Text, "VRTDerivedRasterBand");
1644 :
1645 : /* ---- Encode DerivedBand-specific fields ---- */
1646 24 : if (!EQUAL(m_poPrivate->m_osLanguage, "C"))
1647 : {
1648 5 : CPLSetXMLValue(psTree, "PixelFunctionLanguage",
1649 5 : m_poPrivate->m_osLanguage);
1650 : }
1651 24 : if (!osFuncName.empty())
1652 23 : CPLSetXMLValue(psTree, "PixelFunctionType", osFuncName.c_str());
1653 24 : if (!m_poPrivate->m_oFunctionArgs.empty())
1654 : {
1655 : CPLXMLNode *psArgs =
1656 18 : CPLCreateXMLNode(psTree, CXT_Element, "PixelFunctionArguments");
1657 52 : for (size_t i = 0; i < m_poPrivate->m_oFunctionArgs.size(); ++i)
1658 : {
1659 34 : const char *pszKey = m_poPrivate->m_oFunctionArgs[i].first.c_str();
1660 : const char *pszValue =
1661 34 : m_poPrivate->m_oFunctionArgs[i].second.c_str();
1662 34 : CPLCreateXMLNode(CPLCreateXMLNode(psArgs, CXT_Attribute, pszKey),
1663 : CXT_Text, pszValue);
1664 : }
1665 : }
1666 24 : if (!m_poPrivate->m_osCode.empty())
1667 : {
1668 4 : if (m_poPrivate->m_osCode.find("<![CDATA[") == std::string::npos)
1669 : {
1670 4 : CPLCreateXMLNode(
1671 : CPLCreateXMLNode(psTree, CXT_Element, "PixelFunctionCode"),
1672 : CXT_Literal,
1673 8 : ("<![CDATA[" + m_poPrivate->m_osCode + "]]>").c_str());
1674 : }
1675 : else
1676 : {
1677 0 : CPLSetXMLValue(psTree, "PixelFunctionCode", m_poPrivate->m_osCode);
1678 : }
1679 : }
1680 24 : if (m_poPrivate->m_nBufferRadius != 0)
1681 1 : CPLSetXMLValue(psTree, "BufferRadius",
1682 1 : CPLSPrintf("%d", m_poPrivate->m_nBufferRadius));
1683 24 : if (this->eSourceTransferType != GDT_Unknown)
1684 4 : CPLSetXMLValue(psTree, "SourceTransferType",
1685 : GDALGetDataTypeName(eSourceTransferType));
1686 :
1687 24 : if (m_poPrivate->m_bSkipNonContributingSourcesSpecified)
1688 : {
1689 1 : CPLSetXMLValue(psTree, "SkipNonContributingSources",
1690 1 : m_poPrivate->m_bSkipNonContributingSources ? "true"
1691 : : "false");
1692 : }
1693 :
1694 24 : return psTree;
1695 : }
1696 :
1697 : /************************************************************************/
1698 : /* GetMinimum() */
1699 : /************************************************************************/
1700 :
1701 5 : double VRTDerivedRasterBand::GetMinimum(int *pbSuccess)
1702 : {
1703 5 : return GDALRasterBand::GetMinimum(pbSuccess);
1704 : }
1705 :
1706 : /************************************************************************/
1707 : /* GetMaximum() */
1708 : /************************************************************************/
1709 :
1710 5 : double VRTDerivedRasterBand::GetMaximum(int *pbSuccess)
1711 : {
1712 5 : return GDALRasterBand::GetMaximum(pbSuccess);
1713 : }
1714 :
1715 : /************************************************************************/
1716 : /* ComputeRasterMinMax() */
1717 : /************************************************************************/
1718 :
1719 2 : CPLErr VRTDerivedRasterBand::ComputeRasterMinMax(int bApproxOK,
1720 : double *adfMinMax)
1721 : {
1722 2 : return GDALRasterBand::ComputeRasterMinMax(bApproxOK, adfMinMax);
1723 : }
1724 :
1725 : /************************************************************************/
1726 : /* ComputeStatistics() */
1727 : /************************************************************************/
1728 :
1729 1 : CPLErr VRTDerivedRasterBand::ComputeStatistics(int bApproxOK, double *pdfMin,
1730 : double *pdfMax, double *pdfMean,
1731 : double *pdfStdDev,
1732 : GDALProgressFunc pfnProgress,
1733 : void *pProgressData)
1734 :
1735 : {
1736 1 : return GDALRasterBand::ComputeStatistics(bApproxOK, pdfMin, pdfMax, pdfMean,
1737 : pdfStdDev, pfnProgress,
1738 1 : pProgressData);
1739 : }
1740 :
1741 : /************************************************************************/
1742 : /* GetHistogram() */
1743 : /************************************************************************/
1744 :
1745 1 : CPLErr VRTDerivedRasterBand::GetHistogram(double dfMin, double dfMax,
1746 : int nBuckets, GUIntBig *panHistogram,
1747 : int bIncludeOutOfRange, int bApproxOK,
1748 : GDALProgressFunc pfnProgress,
1749 : void *pProgressData)
1750 :
1751 : {
1752 1 : return VRTRasterBand::GetHistogram(dfMin, dfMax, nBuckets, panHistogram,
1753 : bIncludeOutOfRange, bApproxOK,
1754 1 : pfnProgress, pProgressData);
1755 : }
1756 :
1757 : /*! @endcond */
|