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