Line data Source code
1 : /******************************************************************************
2 : *
3 : * Project: GDAL Core
4 : * Purpose: Base class for raster file formats.
5 : * Author: Frank Warmerdam, warmerdam@pobox.com
6 : *
7 : ******************************************************************************
8 : * Copyright (c) 1998, 2003, Frank Warmerdam
9 : * Copyright (c) 2008-2013, Even Rouault <even dot rouault at spatialys.com>
10 : *
11 : * SPDX-License-Identifier: MIT
12 : ****************************************************************************/
13 :
14 : #include "cpl_port.h"
15 :
16 : #include <algorithm>
17 : #include <array>
18 : #include <cassert>
19 : #include <climits>
20 : #include <cmath>
21 : #include <cstdarg>
22 : #include <cstdio>
23 : #include <cstdlib>
24 : #include <cstring>
25 : #include <limits>
26 : #include <map>
27 : #include <mutex>
28 : #include <new>
29 : #include <set>
30 : #include <string>
31 : #include <type_traits>
32 : #include <utility>
33 :
34 : #include "cpl_conv.h"
35 : #include "cpl_cpu_features.h"
36 : #include "cpl_error.h"
37 : #include "cpl_hash_set.h"
38 : #include "cpl_multiproc.h"
39 : #include "cpl_progress.h"
40 : #include "cpl_string.h"
41 : #include "cpl_vsi.h"
42 : #include "cpl_vsi_error.h"
43 : #include "cpl_vsi_virtual.h"
44 :
45 : #include "gdal.h"
46 : #include "gdal_alg.h"
47 : #include "gdal_abstractbandblockcache.h"
48 : #include "gdalantirecursion.h"
49 : #include "gdal_dataset.h"
50 : #include "gdal_matrix.hpp"
51 :
52 : #ifdef CAN_DETECT_AVX2_FMA_AT_RUNTIME
53 : #include "gdal_matrix_avx2_fma.h"
54 : #endif
55 :
56 : #include "gdalsubdatasetinfo.h"
57 : #include "gdal_thread_pool.h"
58 : #include "gdal_typetraits.h"
59 :
60 : #include "ogr_api.h"
61 : #include "ogr_attrind.h"
62 : #include "ogr_core.h"
63 : #include "ogr_feature.h"
64 : #include "ogr_featurestyle.h"
65 : #include "ogr_gensql.h"
66 : #include "ogr_geometry.h"
67 : #include "ogr_p.h"
68 : #include "ogr_spatialref.h"
69 : #include "ogr_srs_api.h"
70 : #include "ograpispy.h"
71 : #include "ogrsf_frmts.h"
72 : #include "ogrunionlayer.h"
73 : #include "ogr_swq.h"
74 : #include "memmultidim.h"
75 : #include "gdalmultidim_priv.h"
76 :
77 : #include "../frmts/derived/derivedlist.h"
78 :
79 : #ifdef SQLITE_ENABLED
80 : #include "../sqlite/ogrsqliteexecutesql.h"
81 : #endif
82 :
83 : #ifdef HAVE_OPENMP
84 : #include <omp.h>
85 : #endif
86 :
87 : extern const swq_field_type SpecialFieldTypes[SPECIAL_FIELD_COUNT];
88 :
89 : enum class GDALAllowReadWriteMutexState
90 : {
91 : RW_MUTEX_STATE_UNKNOWN,
92 : RW_MUTEX_STATE_ALLOWED,
93 : RW_MUTEX_STATE_DISABLED
94 : };
95 :
96 : const GIntBig TOTAL_FEATURES_NOT_INIT = -2;
97 : const GIntBig TOTAL_FEATURES_UNKNOWN = -1;
98 :
99 : class GDALDataset::Private
100 : {
101 : CPL_DISALLOW_COPY_ASSIGN(Private)
102 :
103 : public:
104 : CPLMutex *hMutex = nullptr;
105 : std::map<GIntBig, int> oMapThreadToMutexTakenCount{};
106 : #ifdef DEBUG_EXTRA
107 : std::map<GIntBig, int> oMapThreadToMutexTakenCountSaved{};
108 : #endif
109 : GDALAllowReadWriteMutexState eStateReadWriteMutex =
110 : GDALAllowReadWriteMutexState::RW_MUTEX_STATE_UNKNOWN;
111 : int nCurrentLayerIdx = 0;
112 : int nLayerCount = -1;
113 : GIntBig nFeatureReadInLayer = 0;
114 : GIntBig nFeatureReadInDataset = 0;
115 : GIntBig nTotalFeaturesInLayer = TOTAL_FEATURES_NOT_INIT;
116 : GIntBig nTotalFeatures = TOTAL_FEATURES_NOT_INIT;
117 : OGRLayer *poCurrentLayer = nullptr;
118 :
119 : std::mutex m_oMutexWKT{};
120 :
121 : char *m_pszWKTCached = nullptr;
122 : OGRSpatialReference *m_poSRSCached = nullptr;
123 : char *m_pszWKTGCPCached = nullptr;
124 : OGRSpatialReference *m_poSRSGCPCached = nullptr;
125 :
126 : GDALDataset *poParentDataset = nullptr;
127 :
128 : bool m_bOverviewsEnabled = true;
129 :
130 : std::vector<int>
131 : m_anBandMap{}; // used by RasterIO(). Values are 1, 2, etc.
132 :
133 199568 : Private() = default;
134 : };
135 :
136 : struct SharedDatasetCtxt
137 : {
138 : // PID of the thread that mark the dataset as shared
139 : // This may not be the actual PID, but the responsiblePID.
140 : GIntBig nPID;
141 : char *pszDescription;
142 : char *pszConcatenatedOpenOptions;
143 : int nOpenFlags;
144 :
145 : GDALDataset *poDS;
146 : };
147 :
148 : // Set of datasets opened as shared datasets (with GDALOpenShared)
149 : // The values in the set are of type SharedDatasetCtxt.
150 : static CPLHashSet *phSharedDatasetSet = nullptr;
151 :
152 : // Set of all datasets created in the constructor of GDALDataset.
153 : // In the case of a shared dataset, memorize the PID of the thread
154 : // that marked the dataset as shared, so that we can remove it from
155 : // the phSharedDatasetSet in the destructor of the dataset, even
156 : // if GDALClose is called from a different thread.
157 : static std::map<GDALDataset *, GIntBig> *poAllDatasetMap = nullptr;
158 :
159 : static CPLMutex *hDLMutex = nullptr;
160 :
161 : // Static array of all datasets. Used by GDALGetOpenDatasets.
162 : // Not thread-safe. See GDALGetOpenDatasets.
163 : static GDALDataset **ppDatasets = nullptr;
164 :
165 8429 : static unsigned long GDALSharedDatasetHashFunc(const void *elt)
166 : {
167 8429 : const SharedDatasetCtxt *psStruct =
168 : static_cast<const SharedDatasetCtxt *>(elt);
169 : return static_cast<unsigned long>(
170 8429 : CPLHashSetHashStr(psStruct->pszDescription) ^
171 8429 : CPLHashSetHashStr(psStruct->pszConcatenatedOpenOptions) ^
172 8429 : psStruct->nOpenFlags ^ psStruct->nPID);
173 : }
174 :
175 7031 : static int GDALSharedDatasetEqualFunc(const void *elt1, const void *elt2)
176 : {
177 7031 : const SharedDatasetCtxt *psStruct1 =
178 : static_cast<const SharedDatasetCtxt *>(elt1);
179 7031 : const SharedDatasetCtxt *psStruct2 =
180 : static_cast<const SharedDatasetCtxt *>(elt2);
181 13967 : return strcmp(psStruct1->pszDescription, psStruct2->pszDescription) == 0 &&
182 6936 : strcmp(psStruct1->pszConcatenatedOpenOptions,
183 6936 : psStruct2->pszConcatenatedOpenOptions) == 0 &&
184 20903 : psStruct1->nPID == psStruct2->nPID &&
185 13967 : psStruct1->nOpenFlags == psStruct2->nOpenFlags;
186 : }
187 :
188 415 : static void GDALSharedDatasetFreeFunc(void *elt)
189 : {
190 415 : SharedDatasetCtxt *psStruct = static_cast<SharedDatasetCtxt *>(elt);
191 415 : CPLFree(psStruct->pszDescription);
192 415 : CPLFree(psStruct->pszConcatenatedOpenOptions);
193 415 : CPLFree(psStruct);
194 415 : }
195 :
196 : static std::string
197 7061 : GDALSharedDatasetConcatenateOpenOptions(CSLConstList papszOpenOptions)
198 : {
199 7061 : std::string osStr;
200 7074 : for (const char *pszOption : cpl::Iterate(papszOpenOptions))
201 13 : osStr += pszOption;
202 7061 : return osStr;
203 : }
204 :
205 : /************************************************************************/
206 : /* Functions shared between gdalproxypool.cpp and gdaldataset.cpp */
207 : /************************************************************************/
208 :
209 : // The open-shared mutex must be used by the ProxyPool too.
210 485213 : CPLMutex **GDALGetphDLMutex()
211 : {
212 485213 : return &hDLMutex;
213 : }
214 :
215 : // The current thread will act in the behalf of the thread of PID
216 : // responsiblePID.
217 474491 : void GDALSetResponsiblePIDForCurrentThread(GIntBig responsiblePID)
218 : {
219 : GIntBig *pResponsiblePID =
220 474491 : static_cast<GIntBig *>(CPLGetTLS(CTLS_RESPONSIBLEPID));
221 474491 : if (pResponsiblePID == nullptr)
222 : {
223 223 : pResponsiblePID = static_cast<GIntBig *>(CPLMalloc(sizeof(GIntBig)));
224 223 : CPLSetTLS(CTLS_RESPONSIBLEPID, pResponsiblePID, TRUE);
225 : }
226 474491 : *pResponsiblePID = responsiblePID;
227 474491 : }
228 :
229 : // Get the PID of the thread that the current thread will act in the behalf of
230 : // By default : the current thread acts in the behalf of itself.
231 609839 : GIntBig GDALGetResponsiblePIDForCurrentThread()
232 : {
233 : GIntBig *pResponsiblePID =
234 609839 : static_cast<GIntBig *>(CPLGetTLS(CTLS_RESPONSIBLEPID));
235 609839 : if (pResponsiblePID == nullptr)
236 44790 : return CPLGetPID();
237 565049 : return *pResponsiblePID;
238 : }
239 :
240 : /************************************************************************/
241 : /* ==================================================================== */
242 : /* GDALDataset */
243 : /* ==================================================================== */
244 : /************************************************************************/
245 :
246 : /**
247 : * \class GDALDataset "gdal_priv.h"
248 : *
249 : * A dataset encapsulating one or more raster bands. Details are further
250 : * discussed in the <a href="https://gdal.org/user/raster_data_model.html">GDAL
251 : * Raster Data Model</a>.
252 : *
253 : * Use GDALOpen() or GDALOpenShared() to create a GDALDataset for a named file,
254 : * or GDALDriver::Create() or GDALDriver::CreateCopy() to create a new
255 : * dataset.
256 : */
257 :
258 : /************************************************************************/
259 : /* GDALDataset() */
260 : /************************************************************************/
261 :
262 : //! @cond Doxygen_Suppress
263 167143 : GDALDataset::GDALDataset()
264 167143 : : GDALDataset(CPLTestBool(CPLGetConfigOption("GDAL_FORCE_CACHING", "NO")))
265 : {
266 167143 : }
267 :
268 199568 : GDALDataset::GDALDataset(int bForceCachedIOIn)
269 199568 : : bForceCachedIO(CPL_TO_BOOL(bForceCachedIOIn)),
270 199568 : m_poPrivate(new (std::nothrow) GDALDataset::Private)
271 : {
272 199568 : }
273 :
274 : //! @endcond
275 :
276 : /************************************************************************/
277 : /* ~GDALDataset() */
278 : /************************************************************************/
279 :
280 : /**
281 : * \brief Destroy an open GDALDataset.
282 : *
283 : * This is the accepted method of closing a GDAL dataset and deallocating
284 : * all resources associated with it.
285 : *
286 : * Equivalent of the C callable GDALClose(). Except that GDALClose() first
287 : * decrements the reference count, and then closes only if it has dropped to
288 : * zero.
289 : *
290 : * For Windows users, it is not recommended to use the delete operator on the
291 : * dataset object because of known issues when allocating and freeing memory
292 : * across module boundaries. Calling GDALClose() is then a better option.
293 : */
294 :
295 199549 : GDALDataset::~GDALDataset()
296 :
297 : {
298 : // we don't want to report destruction of datasets that
299 : // were never really open or meant as internal
300 199549 : if (!bIsInternal && (nBands != 0 || !EQUAL(GetDescription(), "")))
301 : {
302 75930 : if (CPLGetPID() != GDALGetResponsiblePIDForCurrentThread())
303 209 : CPLDebug("GDAL",
304 : "GDALClose(%s, this=%p) (pid=%d, responsiblePID=%d)",
305 209 : GetDescription(), this, static_cast<int>(CPLGetPID()),
306 209 : static_cast<int>(GDALGetResponsiblePIDForCurrentThread()));
307 : else
308 75721 : CPLDebug("GDAL", "GDALClose(%s, this=%p)", GetDescription(), this);
309 : }
310 :
311 199549 : GDALDataset::Close();
312 :
313 : /* -------------------------------------------------------------------- */
314 : /* Remove dataset from the "open" dataset list. */
315 : /* -------------------------------------------------------------------- */
316 199549 : if (!bIsInternal)
317 : {
318 155036 : CPLMutexHolderD(&hDLMutex);
319 77518 : if (poAllDatasetMap)
320 : {
321 : std::map<GDALDataset *, GIntBig>::iterator oIter =
322 77518 : poAllDatasetMap->find(this);
323 77518 : CPLAssert(oIter != poAllDatasetMap->end());
324 :
325 77518 : UnregisterFromSharedDataset();
326 :
327 77518 : poAllDatasetMap->erase(oIter);
328 :
329 77518 : if (poAllDatasetMap->empty())
330 : {
331 33060 : delete poAllDatasetMap;
332 33060 : poAllDatasetMap = nullptr;
333 33060 : if (phSharedDatasetSet)
334 : {
335 289 : CPLHashSetDestroy(phSharedDatasetSet);
336 : }
337 33060 : phSharedDatasetSet = nullptr;
338 33060 : CPLFree(ppDatasets);
339 33060 : ppDatasets = nullptr;
340 : }
341 : }
342 : }
343 :
344 : /* -------------------------------------------------------------------- */
345 : /* Destroy the raster bands if they exist. */
346 : /* -------------------------------------------------------------------- */
347 1751150 : for (int i = 0; i < nBands && papoBands != nullptr; ++i)
348 : {
349 1551600 : if (papoBands[i] != nullptr)
350 1551600 : delete papoBands[i];
351 1551600 : papoBands[i] = nullptr;
352 : }
353 :
354 199549 : CPLFree(papoBands);
355 :
356 199549 : if (m_poStyleTable)
357 : {
358 23 : delete m_poStyleTable;
359 23 : m_poStyleTable = nullptr;
360 : }
361 :
362 199549 : if (m_poPrivate != nullptr)
363 : {
364 199549 : if (m_poPrivate->hMutex != nullptr)
365 21853 : CPLDestroyMutex(m_poPrivate->hMutex);
366 :
367 : #if defined(__COVERITY__) || defined(DEBUG)
368 : // Not needed since at destruction there is no risk of concurrent use.
369 399098 : std::lock_guard oLock(m_poPrivate->m_oMutexWKT);
370 : #endif
371 199549 : CPLFree(m_poPrivate->m_pszWKTCached);
372 199549 : if (m_poPrivate->m_poSRSCached)
373 : {
374 0 : m_poPrivate->m_poSRSCached->Release();
375 : }
376 199549 : CPLFree(m_poPrivate->m_pszWKTGCPCached);
377 199549 : if (m_poPrivate->m_poSRSGCPCached)
378 : {
379 0 : m_poPrivate->m_poSRSGCPCached->Release();
380 : }
381 : }
382 :
383 199549 : delete m_poPrivate;
384 :
385 199549 : CSLDestroy(papszOpenOptions);
386 199549 : }
387 :
388 : /************************************************************************/
389 : /* Close() */
390 : /************************************************************************/
391 :
392 : /** Do final cleanup before a dataset is destroyed.
393 : *
394 : * This method is typically called by GDALClose() or the destructor of a
395 : * GDALDataset subclass. It might also be called by C++ users before
396 : * destroying a dataset. It should not be called on a shared dataset whose
397 : * reference count is greater than one.
398 : *
399 : * It gives a last chance to the closing process to return an error code if
400 : * something goes wrong, in particular in creation / update scenarios where
401 : * file write or network communication might occur when finalizing the dataset.
402 : *
403 : * Implementations should be robust to this method to be called several times
404 : * (on subsequent calls, it should do nothing and return CE_None).
405 : * Once it has been called, no other method than Close() or the dataset
406 : * destructor should be called. RasterBand or OGRLayer owned by the dataset
407 : * should be assumed as no longer being valid.
408 : *
409 : * If a driver implements this method, it must also call it from its
410 : * dataset destructor.
411 : *
412 : * Starting with GDAL 3.13, this function may report progress if a progress
413 : * callback if provided in the pfnProgress argument and if the dataset returns
414 : * true for GDALDataset::GetCloseReportsProgress()
415 : *
416 : * This is the equivalent of C function GDALDatasetRunCloseWithoutDestroying()
417 : * or GDALDatasetRunCloseWithoutDestroyingEx()
418 : *
419 : * A typical implementation might look as the following
420 : * \code{.cpp}
421 : *
422 : * MyDataset::~MyDataset()
423 : * {
424 : * try
425 : * {
426 : * MyDataset::Close();
427 : * }
428 : * catch (const std::exception &exc)
429 : * {
430 : * // If Close() can throw exception
431 : * CPLError(CE_Failure, CPLE_AppDefined,
432 : * "Exception thrown in MyDataset::Close(): %s",
433 : * exc.what());
434 : * }
435 : * catch (...)
436 : * {
437 : * // If Close() can throw exception
438 : * CPLError(CE_Failure, CPLE_AppDefined,
439 : * "Exception thrown in MyDataset::Close()");
440 : * }
441 : * }
442 : *
443 : * CPLErr MyDataset::Close(GDALProgressFunc pfnProgress, void* pProgressData)
444 : * {
445 : * CPLErr eErr = CE_None;
446 : * if( nOpenFlags != OPEN_FLAGS_CLOSED )
447 : * {
448 : * eErr = MyDataset::FlushCache(true);
449 : *
450 : * // Do something driver specific
451 : * if (m_fpImage)
452 : * {
453 : * if( VSIFCloseL(m_fpImage) != 0 )
454 : * {
455 : * CPLError(CE_Failure, CPLE_FileIO, "VSIFCloseL() failed");
456 : * eErr = CE_Failure;
457 : * }
458 : * }
459 : *
460 : * // Call parent Close() implementation.
461 : * eErr = GDAL::Combine(eErr, MyParentDatasetClass::Close());
462 : * }
463 : * return eErr;
464 : * }
465 : * \endcode
466 : *
467 : * @param pfnProgress (since GDAL 3.13) Progress callback, or nullptr
468 : * @param pProgressData (since GDAL 3.13) User data of progress callback, or nullptr
469 : * @return CE_None if no error
470 : *
471 : * @since GDAL 3.7
472 : */
473 330482 : CPLErr GDALDataset::Close(GDALProgressFunc pfnProgress, void *pProgressData)
474 : {
475 : (void)pfnProgress;
476 : (void)pProgressData;
477 :
478 330482 : if (nOpenFlags != OPEN_FLAGS_CLOSED)
479 : {
480 : // Call UnregisterFromSharedDataset() before altering nOpenFlags
481 199549 : UnregisterFromSharedDataset();
482 :
483 199549 : nOpenFlags = OPEN_FLAGS_CLOSED;
484 : }
485 :
486 330482 : if (IsMarkedSuppressOnClose())
487 : {
488 3538 : if (poDriver == nullptr ||
489 : // Someone issuing Create("foo.tif") on a
490 : // memory driver doesn't expect files with those names to be deleted
491 : // on a file system...
492 : // This is somewhat messy. Ideally there should be a way for the
493 : // driver to overload the default behavior
494 1725 : (!EQUAL(poDriver->GetDescription(), "MEM") &&
495 1647 : !EQUAL(poDriver->GetDescription(), "Memory")))
496 : {
497 1735 : if (VSIUnlink(GetDescription()) == 0)
498 683 : UnMarkSuppressOnClose();
499 : }
500 : }
501 :
502 330482 : return CE_None;
503 : }
504 :
505 : /************************************************************************/
506 : /* GDALDatasetRunCloseWithoutDestroying() */
507 : /************************************************************************/
508 :
509 : /** Run the Close() method, without running destruction of the object.
510 : *
511 : * This ensures that content that should be written to file is written and
512 : * that all file descriptors are closed.
513 : *
514 : * Note that this is different from GDALClose() which also destroys
515 : * the underlying C++ object. GDALClose() or GDALReleaseDataset() are actually
516 : * the only functions that can be safely called on the dataset handle after
517 : * this function has been called.
518 : *
519 : * Most users want to use GDALClose() or GDALReleaseDataset() rather than
520 : * this function.
521 : *
522 : * This function is equivalent to the C++ method GDALDataset:Close()
523 : *
524 : * @param hDS dataset handle.
525 : * @return CE_None if no error
526 : *
527 : * @since GDAL 3.12
528 : * @see GDALClose(), GDALDatasetRunCloseWithoutDestroyingEx()
529 : */
530 0 : CPLErr GDALDatasetRunCloseWithoutDestroying(GDALDatasetH hDS)
531 : {
532 0 : VALIDATE_POINTER1(hDS, __func__, CE_Failure);
533 0 : return GDALDataset::FromHandle(hDS)->Close();
534 : }
535 :
536 : /************************************************************************/
537 : /* GDALDatasetRunCloseWithoutDestroyingEx() */
538 : /************************************************************************/
539 :
540 : /** Run the Close() method, without running destruction of the object.
541 : *
542 : * This ensures that content that should be written to file is written and
543 : * that all file descriptors are closed.
544 : *
545 : * Note that this is different from GDALClose() which also destroys
546 : * the underlying C++ object. GDALClose() or GDALReleaseDataset() are actually
547 : * the only functions that can be safely called on the dataset handle after
548 : * this function has been called.
549 : *
550 : * Most users want to use GDALClose() or GDALReleaseDataset() rather than
551 : * this function.
552 : *
553 : * This function may report progress if a progress
554 : * callback if provided in the pfnProgress argument and if the dataset returns
555 : * true for GDALDataset::GetCloseReportsProgress()
556 : *
557 : * This function is equivalent to the C++ method GDALDataset:Close()
558 : *
559 : * @param hDS dataset handle.
560 : * @param pfnProgress Progress callback, or nullptr
561 : * @param pProgressData User data of progress callback, or nullptr
562 : *
563 : * @return CE_None if no error
564 : *
565 : * @since GDAL 3.13
566 : * @see GDALClose()
567 : */
568 12 : CPLErr GDALDatasetRunCloseWithoutDestroyingEx(GDALDatasetH hDS,
569 : GDALProgressFunc pfnProgress,
570 : void *pProgressData)
571 : {
572 12 : VALIDATE_POINTER1(hDS, __func__, CE_Failure);
573 12 : return GDALDataset::FromHandle(hDS)->Close(pfnProgress, pProgressData);
574 : }
575 :
576 : /************************************************************************/
577 : /* GetCloseReportsProgress() */
578 : /************************************************************************/
579 :
580 : /** Returns whether the Close() operation will report progress / is a potential
581 : * lengthy operation.
582 : *
583 : * At time of writing, only the COG driver will return true, if the dataset
584 : * has been created through the GDALDriver::Create() interface.
585 : *
586 : * This method is equivalent to the C function GDALDatasetGetCloseReportsProgress()
587 : *
588 : * @return true if the Close() operation will report progress
589 : * @since GDAL 3.13
590 : * @see Close()
591 : */
592 243 : bool GDALDataset::GetCloseReportsProgress() const
593 : {
594 243 : return false;
595 : }
596 :
597 : /************************************************************************/
598 : /* GDALDatasetGetCloseReportsProgress() */
599 : /************************************************************************/
600 :
601 : /** Returns whether the Close() operation will report progress / is a potential
602 : * lengthy operation.
603 : *
604 : * This function is equivalent to the C++ method GDALDataset::GetCloseReportsProgress()
605 : *
606 : * @param hDS dataset handle.
607 : * @return CE_None if no error
608 : *
609 : * @return true if the Close() operation will report progress
610 : * @since GDAL 3.13
611 : * @see GDALClose()
612 : */
613 2 : bool GDALDatasetGetCloseReportsProgress(GDALDatasetH hDS)
614 : {
615 2 : VALIDATE_POINTER1(hDS, __func__, false);
616 2 : return GDALDataset::FromHandle(hDS)->GetCloseReportsProgress();
617 : }
618 :
619 : /************************************************************************/
620 : /* CanReopenWithCurrentDescription() */
621 : /************************************************************************/
622 :
623 : /** Returns whether, once this dataset is closed, it can be re-opened with
624 : * Open() using the current value of GetDescription()
625 : *
626 : * The default implementation returns true. Some drivers, like MVT in Create()
627 : * mode, can return false. Some drivers return true, but the re-opened dataset
628 : * may be opened by another driver (e.g. the COG driver will return true, but
629 : * the driver used for re-opening is GTiff).
630 : *
631 : * @return true if the dataset can be re-opened using the value as
632 : * GetDescription() as connection string for Open()
633 : * @since GDAL 3.13
634 : */
635 2 : bool GDALDataset::CanReopenWithCurrentDescription() const
636 : {
637 2 : return true;
638 : }
639 :
640 : /************************************************************************/
641 : /* UnregisterFromSharedDataset() */
642 : /************************************************************************/
643 :
644 277067 : void GDALDataset::UnregisterFromSharedDataset()
645 : {
646 277067 : if (!(!bIsInternal && bShared && poAllDatasetMap && phSharedDatasetSet))
647 276652 : return;
648 :
649 830 : CPLMutexHolderD(&hDLMutex);
650 :
651 : std::map<GDALDataset *, GIntBig>::iterator oIter =
652 415 : poAllDatasetMap->find(this);
653 415 : CPLAssert(oIter != poAllDatasetMap->end());
654 415 : const GIntBig nPIDCreatorForShared = oIter->second;
655 415 : bShared = false;
656 : SharedDatasetCtxt sStruct;
657 415 : sStruct.nPID = nPIDCreatorForShared;
658 415 : sStruct.nOpenFlags = nOpenFlags & ~GDAL_OF_SHARED;
659 415 : sStruct.pszDescription = const_cast<char *>(GetDescription());
660 : std::string osConcatenatedOpenOptions =
661 830 : GDALSharedDatasetConcatenateOpenOptions(papszOpenOptions);
662 415 : sStruct.pszConcatenatedOpenOptions = &osConcatenatedOpenOptions[0];
663 415 : sStruct.poDS = nullptr;
664 : SharedDatasetCtxt *psStruct = static_cast<SharedDatasetCtxt *>(
665 415 : CPLHashSetLookup(phSharedDatasetSet, &sStruct));
666 415 : if (psStruct && psStruct->poDS == this)
667 : {
668 414 : CPLHashSetRemove(phSharedDatasetSet, psStruct);
669 : }
670 : else
671 : {
672 1 : CPLDebug("GDAL",
673 : "Should not happen. Cannot find %s, "
674 : "this=%p in phSharedDatasetSet",
675 1 : GetDescription(), this);
676 : }
677 : }
678 :
679 : /************************************************************************/
680 : /* AddToDatasetOpenList() */
681 : /************************************************************************/
682 :
683 78836 : void GDALDataset::AddToDatasetOpenList()
684 : {
685 : /* -------------------------------------------------------------------- */
686 : /* Add this dataset to the open dataset list. */
687 : /* -------------------------------------------------------------------- */
688 78836 : bIsInternal = false;
689 :
690 78836 : CPLMutexHolderD(&hDLMutex);
691 :
692 78836 : if (poAllDatasetMap == nullptr)
693 33070 : poAllDatasetMap = new std::map<GDALDataset *, GIntBig>;
694 78836 : (*poAllDatasetMap)[this] = -1;
695 78836 : }
696 :
697 : /************************************************************************/
698 : /* FlushCache() */
699 : /************************************************************************/
700 :
701 : /**
702 : * \brief Flush all write cached data to disk.
703 : *
704 : * Any raster (or other GDAL) data written via GDAL calls, but buffered
705 : * internally will be written to disk.
706 : *
707 : * The default implementation of this method just calls the FlushCache() method
708 : * on each of the raster bands and the SyncToDisk() method
709 : * on each of the layers. Conceptually, calling FlushCache() on a dataset
710 : * should include any work that might be accomplished by calling SyncToDisk()
711 : * on layers in that dataset.
712 : *
713 : * Using this method does not prevent use from calling GDALClose()
714 : * to properly close a dataset and ensure that important data not addressed
715 : * by FlushCache() is written in the file.
716 : *
717 : * This method is the same as the C function GDALFlushCache().
718 : *
719 : * @param bAtClosing Whether this is called from a GDALDataset destructor
720 : * @return CE_None in case of success (note: return value added in GDAL 3.7)
721 : */
722 :
723 136738 : CPLErr GDALDataset::FlushCache(bool bAtClosing)
724 :
725 : {
726 136738 : CPLErr eErr = CE_None;
727 : // This sometimes happens if a dataset is destroyed before completely
728 : // built.
729 :
730 136738 : if (papoBands)
731 : {
732 1966460 : for (int i = 0; i < nBands; ++i)
733 : {
734 1845020 : if (papoBands[i])
735 : {
736 1845020 : if (papoBands[i]->FlushCache(bAtClosing) != CE_None)
737 7 : eErr = CE_Failure;
738 : }
739 : }
740 : }
741 :
742 136738 : const int nLayers = GetLayerCount();
743 : // cppcheck-suppress knownConditionTrueFalse
744 136738 : if (nLayers > 0)
745 : {
746 17362 : CPLMutexHolderD(m_poPrivate ? &(m_poPrivate->hMutex) : nullptr);
747 26810 : for (int i = 0; i < nLayers; ++i)
748 : {
749 18129 : OGRLayer *poLayer = GetLayer(i);
750 :
751 18129 : if (poLayer)
752 : {
753 18129 : if (poLayer->SyncToDisk() != OGRERR_NONE)
754 1 : eErr = CE_Failure;
755 : }
756 : }
757 : }
758 :
759 136738 : return eErr;
760 : }
761 :
762 : /************************************************************************/
763 : /* GDALFlushCache() */
764 : /************************************************************************/
765 :
766 : /**
767 : * \brief Flush all write cached data to disk.
768 : *
769 : * @see GDALDataset::FlushCache().
770 : * @return CE_None in case of success (note: return value added in GDAL 3.7)
771 : */
772 :
773 5251 : CPLErr CPL_STDCALL GDALFlushCache(GDALDatasetH hDS)
774 :
775 : {
776 5251 : VALIDATE_POINTER1(hDS, "GDALFlushCache", CE_Failure);
777 :
778 5251 : return GDALDataset::FromHandle(hDS)->FlushCache(false);
779 : }
780 :
781 : /************************************************************************/
782 : /* DropCache() */
783 : /************************************************************************/
784 :
785 : /**
786 : * \brief Drop all write cached data
787 : *
788 : * This method is the same as the C function GDALDropCache().
789 : *
790 : * @return CE_None in case of success
791 : * @since 3.9
792 : */
793 :
794 1 : CPLErr GDALDataset::DropCache()
795 :
796 : {
797 1 : CPLErr eErr = CE_None;
798 :
799 1 : if (papoBands)
800 : {
801 2 : for (int i = 0; i < nBands; ++i)
802 : {
803 1 : if (papoBands[i])
804 : {
805 1 : if (papoBands[i]->DropCache() != CE_None)
806 0 : eErr = CE_Failure;
807 : }
808 : }
809 : }
810 :
811 1 : return eErr;
812 : }
813 :
814 : /************************************************************************/
815 : /* GDALDropCache() */
816 : /************************************************************************/
817 :
818 : /**
819 : * \brief Drop all write cached data
820 : *
821 : * @see GDALDataset::DropCache().
822 : * @return CE_None in case of success
823 : * @since 3.9
824 : */
825 :
826 0 : CPLErr CPL_STDCALL GDALDropCache(GDALDatasetH hDS)
827 :
828 : {
829 0 : VALIDATE_POINTER1(hDS, "GDALDropCache", CE_Failure);
830 :
831 0 : return GDALDataset::FromHandle(hDS)->DropCache();
832 : }
833 :
834 : /************************************************************************/
835 : /* GetEstimatedRAMUsage() */
836 : /************************************************************************/
837 :
838 : /**
839 : * \brief Return the intrinsic RAM usage of this dataset.
840 : *
841 : * The returned value should take into account caches in the underlying driver
842 : * and decoding library, but not the usage related to the GDAL block cache.
843 : *
844 : * At time of writing, this method is only implemented in the JP2OpenJPEG
845 : * driver. For single-tiled JPEG2000 images, the decoding of the image,
846 : * even partially, involves allocating at least
847 : * width * height * number_of_bands * sizeof(uint32_t) bytes inside the libopenjp2
848 : * library.
849 : *
850 : * This method is used by the GDALDatasetPool class, itself used by the GDAL VRT
851 : * driver, to determine how long a dataset in the pool must be kept open, given
852 : * the RAM usage of the dataset with respect to the usable total RAM.
853 : *
854 : * @since GDAL 3.7
855 : * @return RAM usage in bytes, or -1 if unknown (the default implementation
856 : * returns -1)
857 : */
858 :
859 3366 : GIntBig GDALDataset::GetEstimatedRAMUsage()
860 : {
861 3366 : return -1;
862 : }
863 :
864 : /************************************************************************/
865 : /* BlockBasedFlushCache() */
866 : /* */
867 : /* This helper method can be called by the */
868 : /* GDALDataset::FlushCache() for particular drivers to ensure */
869 : /* that buffers will be flushed in a manner suitable for pixel */
870 : /* interleaved (by block) IO. That is, if all the bands have */
871 : /* the same size blocks then a given block will be flushed for */
872 : /* all bands before proceeding to the next block. */
873 : /************************************************************************/
874 :
875 : //! @cond Doxygen_Suppress
876 350 : CPLErr GDALDataset::BlockBasedFlushCache(bool bAtClosing)
877 :
878 : {
879 350 : GDALRasterBand *poBand1 = GetRasterBand(1);
880 350 : if (poBand1 == nullptr || (IsMarkedSuppressOnClose() && bAtClosing))
881 : {
882 7 : return GDALDataset::FlushCache(bAtClosing);
883 : }
884 :
885 343 : int nBlockXSize = 0;
886 343 : int nBlockYSize = 0;
887 343 : poBand1->GetBlockSize(&nBlockXSize, &nBlockYSize);
888 :
889 : /* -------------------------------------------------------------------- */
890 : /* Verify that all bands match. */
891 : /* -------------------------------------------------------------------- */
892 1108 : for (int iBand = 1; iBand < nBands; ++iBand)
893 : {
894 765 : GDALRasterBand *poBand = GetRasterBand(iBand + 1);
895 :
896 : int nThisBlockXSize, nThisBlockYSize;
897 765 : poBand->GetBlockSize(&nThisBlockXSize, &nThisBlockYSize);
898 765 : if (nThisBlockXSize != nBlockXSize && nThisBlockYSize != nBlockYSize)
899 : {
900 0 : return GDALDataset::FlushCache(bAtClosing);
901 : }
902 : }
903 :
904 : /* -------------------------------------------------------------------- */
905 : /* Now flush writable data. */
906 : /* -------------------------------------------------------------------- */
907 794 : for (int iY = 0; iY < poBand1->nBlocksPerColumn; ++iY)
908 : {
909 991 : for (int iX = 0; iX < poBand1->nBlocksPerRow; ++iX)
910 : {
911 1690 : for (int iBand = 0; iBand < nBands; ++iBand)
912 : {
913 1150 : const CPLErr eErr = papoBands[iBand]->FlushBlock(iX, iY);
914 :
915 1150 : if (eErr != CE_None)
916 0 : return CE_Failure;
917 : }
918 : }
919 : }
920 343 : return CE_None;
921 : }
922 :
923 : /************************************************************************/
924 : /* RasterInitialize() */
925 : /* */
926 : /* Initialize raster size */
927 : /************************************************************************/
928 :
929 0 : void GDALDataset::RasterInitialize(int nXSize, int nYSize)
930 :
931 : {
932 0 : CPLAssert(nXSize > 0 && nYSize > 0);
933 :
934 0 : nRasterXSize = nXSize;
935 0 : nRasterYSize = nYSize;
936 0 : }
937 :
938 : //! @endcond
939 :
940 : /************************************************************************/
941 : /* AddBand() */
942 : /************************************************************************/
943 :
944 : /**
945 : * \fn GDALDataset::AddBand(GDALDataType, char**)
946 : * \brief Add a band to a dataset.
947 : *
948 : * This method will add a new band to the dataset if the underlying format
949 : * supports this action. Most formats do not.
950 : *
951 : * Note that the new GDALRasterBand is not returned. It may be fetched
952 : * after successful completion of the method by calling
953 : * GDALDataset::GetRasterBand(GDALDataset::GetRasterCount()) as the newest
954 : * band will always be the last band.
955 : *
956 : * @param eType the data type of the pixels in the new band.
957 : *
958 : * @param papszOptions a list of NAME=VALUE option strings. The supported
959 : * options are format specific. NULL may be passed by default.
960 : *
961 : * @return CE_None on success or CE_Failure on failure.
962 : */
963 :
964 0 : CPLErr GDALDataset::AddBand(CPL_UNUSED GDALDataType eType,
965 : CPL_UNUSED CSLConstList papszOptions)
966 :
967 : {
968 0 : ReportError(CE_Failure, CPLE_NotSupported,
969 : "Dataset does not support the AddBand() method.");
970 :
971 0 : return CE_Failure;
972 : }
973 :
974 : /************************************************************************/
975 : /* GDALAddBand() */
976 : /************************************************************************/
977 :
978 : /**
979 : * \brief Add a band to a dataset.
980 : *
981 : * @see GDALDataset::AddBand().
982 : */
983 :
984 26 : CPLErr CPL_STDCALL GDALAddBand(GDALDatasetH hDataset, GDALDataType eType,
985 : CSLConstList papszOptions)
986 :
987 : {
988 26 : VALIDATE_POINTER1(hDataset, "GDALAddBand", CE_Failure);
989 :
990 52 : return GDALDataset::FromHandle(hDataset)->AddBand(
991 26 : eType, const_cast<char **>(papszOptions));
992 : }
993 :
994 : /************************************************************************/
995 : /* SetBand() */
996 : /************************************************************************/
997 :
998 : //! @cond Doxygen_Suppress
999 : /** Set a band in the band array, updating the band count, and array size
1000 : * appropriately.
1001 : *
1002 : * @param nNewBand new band number (indexing starts at 1)
1003 : * @param poBand band object.
1004 : */
1005 :
1006 1697040 : void GDALDataset::SetBand(int nNewBand, GDALRasterBand *poBand)
1007 :
1008 : {
1009 : /* -------------------------------------------------------------------- */
1010 : /* Do we need to grow the bands list? */
1011 : /* -------------------------------------------------------------------- */
1012 1697040 : if (nBands < nNewBand || papoBands == nullptr)
1013 : {
1014 961785 : GDALRasterBand **papoNewBands = nullptr;
1015 :
1016 961785 : if (papoBands == nullptr)
1017 113358 : papoNewBands = static_cast<GDALRasterBand **>(VSICalloc(
1018 113358 : sizeof(GDALRasterBand *), std::max(nNewBand, nBands)));
1019 : else
1020 : papoNewBands = static_cast<GDALRasterBand **>(
1021 848427 : VSIRealloc(papoBands, sizeof(GDALRasterBand *) *
1022 848427 : std::max(nNewBand, nBands)));
1023 961785 : if (papoNewBands == nullptr)
1024 : {
1025 0 : ReportError(CE_Failure, CPLE_OutOfMemory,
1026 : "Cannot allocate band array");
1027 0 : return;
1028 : }
1029 :
1030 961785 : papoBands = papoNewBands;
1031 :
1032 1870090 : for (int i = nBands; i < nNewBand; ++i)
1033 908306 : papoBands[i] = nullptr;
1034 :
1035 961785 : nBands = std::max(nBands, nNewBand);
1036 :
1037 961785 : if (m_poPrivate)
1038 : {
1039 961785 : for (int i = static_cast<int>(m_poPrivate->m_anBandMap.size());
1040 2658820 : i < nBands; ++i)
1041 : {
1042 1697040 : m_poPrivate->m_anBandMap.push_back(i + 1);
1043 : }
1044 : }
1045 : }
1046 :
1047 : /* -------------------------------------------------------------------- */
1048 : /* Set the band. Resetting the band is currently not permitted. */
1049 : /* -------------------------------------------------------------------- */
1050 1697040 : if (papoBands[nNewBand - 1] != nullptr)
1051 : {
1052 0 : ReportError(CE_Failure, CPLE_NotSupported,
1053 : "Cannot set band %d as it is already set", nNewBand);
1054 0 : return;
1055 : }
1056 :
1057 1697040 : papoBands[nNewBand - 1] = poBand;
1058 :
1059 : /* -------------------------------------------------------------------- */
1060 : /* Set back reference information on the raster band. Note */
1061 : /* that the GDALDataset is a friend of the GDALRasterBand */
1062 : /* specifically to allow this. */
1063 : /* -------------------------------------------------------------------- */
1064 1697040 : poBand->nBand = nNewBand;
1065 1697040 : poBand->poDS = this;
1066 1697040 : poBand->nRasterXSize = nRasterXSize;
1067 1697040 : poBand->nRasterYSize = nRasterYSize;
1068 1697040 : poBand->eAccess = eAccess; // Default access to be same as dataset.
1069 : }
1070 :
1071 : //! @endcond
1072 :
1073 : /************************************************************************/
1074 : /* SetBand() */
1075 : /************************************************************************/
1076 :
1077 : //! @cond Doxygen_Suppress
1078 : /** Set a band in the band array, updating the band count, and array size
1079 : * appropriately.
1080 : *
1081 : * @param nNewBand new band number (indexing starts at 1)
1082 : * @param poBand band object.
1083 : */
1084 :
1085 1112130 : void GDALDataset::SetBand(int nNewBand, std::unique_ptr<GDALRasterBand> poBand)
1086 : {
1087 1112130 : SetBand(nNewBand, poBand.release());
1088 1112130 : }
1089 :
1090 : //! @endcond
1091 :
1092 : /************************************************************************/
1093 : /* GetRasterXSize() */
1094 : /************************************************************************/
1095 :
1096 : /**
1097 :
1098 : \brief Fetch raster width in pixels.
1099 :
1100 : Equivalent of the C function GDALGetRasterXSize().
1101 :
1102 : @return the width in pixels of raster bands in this GDALDataset.
1103 :
1104 : */
1105 :
1106 734241 : int GDALDataset::GetRasterXSize() const
1107 : {
1108 734241 : return nRasterXSize;
1109 : }
1110 :
1111 : /************************************************************************/
1112 : /* GDALGetRasterXSize() */
1113 : /************************************************************************/
1114 :
1115 : /**
1116 : * \brief Fetch raster width in pixels.
1117 : *
1118 : * @see GDALDataset::GetRasterXSize().
1119 : */
1120 :
1121 40301 : int CPL_STDCALL GDALGetRasterXSize(GDALDatasetH hDataset)
1122 :
1123 : {
1124 40301 : VALIDATE_POINTER1(hDataset, "GDALGetRasterXSize", 0);
1125 :
1126 40301 : return GDALDataset::FromHandle(hDataset)->GetRasterXSize();
1127 : }
1128 :
1129 : /************************************************************************/
1130 : /* GetRasterYSize() */
1131 : /************************************************************************/
1132 :
1133 : /**
1134 :
1135 : \brief Fetch raster height in pixels.
1136 :
1137 : Equivalent of the C function GDALGetRasterYSize().
1138 :
1139 : @return the height in pixels of raster bands in this GDALDataset.
1140 :
1141 : */
1142 :
1143 613977 : int GDALDataset::GetRasterYSize() const
1144 : {
1145 613977 : return nRasterYSize;
1146 : }
1147 :
1148 : /************************************************************************/
1149 : /* GDALGetRasterYSize() */
1150 : /************************************************************************/
1151 :
1152 : /**
1153 : * \brief Fetch raster height in pixels.
1154 : *
1155 : * @see GDALDataset::GetRasterYSize().
1156 : */
1157 :
1158 39518 : int CPL_STDCALL GDALGetRasterYSize(GDALDatasetH hDataset)
1159 :
1160 : {
1161 39518 : VALIDATE_POINTER1(hDataset, "GDALGetRasterYSize", 0);
1162 :
1163 39518 : return GDALDataset::FromHandle(hDataset)->GetRasterYSize();
1164 : }
1165 :
1166 : /************************************************************************/
1167 : /* GetRasterBand() */
1168 : /************************************************************************/
1169 :
1170 : /**
1171 :
1172 : \brief Fetch a band object for a dataset.
1173 :
1174 : See GetBands() for a C++ iterator version of this method.
1175 :
1176 : Equivalent of the C function GDALGetRasterBand().
1177 :
1178 : @param nBandId the index number of the band to fetch, from 1 to
1179 : GetRasterCount().
1180 :
1181 : @return the nBandId th band object
1182 :
1183 : */
1184 :
1185 12318000 : GDALRasterBand *GDALDataset::GetRasterBand(int nBandId)
1186 :
1187 : {
1188 12318000 : if (papoBands)
1189 : {
1190 12318000 : if (nBandId < 1 || nBandId > nBands)
1191 : {
1192 12 : ReportError(CE_Failure, CPLE_IllegalArg,
1193 : "GDALDataset::GetRasterBand(%d) - Illegal band #\n",
1194 : nBandId);
1195 12 : return nullptr;
1196 : }
1197 :
1198 12317900 : return papoBands[nBandId - 1];
1199 : }
1200 13 : return nullptr;
1201 : }
1202 :
1203 : /************************************************************************/
1204 : /* GetRasterBand() */
1205 : /************************************************************************/
1206 :
1207 : /**
1208 :
1209 : \brief Fetch a band object for a dataset.
1210 :
1211 : See GetBands() for a C++ iterator version of this method.
1212 :
1213 : Equivalent of the C function GDALGetRasterBand().
1214 :
1215 : @param nBandId the index number of the band to fetch, from 1 to
1216 : GetRasterCount().
1217 :
1218 : @return the nBandId th band object
1219 :
1220 : */
1221 :
1222 594 : const GDALRasterBand *GDALDataset::GetRasterBand(int nBandId) const
1223 :
1224 : {
1225 594 : if (papoBands)
1226 : {
1227 594 : if (nBandId < 1 || nBandId > nBands)
1228 : {
1229 0 : ReportError(CE_Failure, CPLE_IllegalArg,
1230 : "GDALDataset::GetRasterBand(%d) - Illegal band #\n",
1231 : nBandId);
1232 0 : return nullptr;
1233 : }
1234 :
1235 594 : return papoBands[nBandId - 1];
1236 : }
1237 0 : return nullptr;
1238 : }
1239 :
1240 : /************************************************************************/
1241 : /* GDALGetRasterBand() */
1242 : /************************************************************************/
1243 :
1244 : /**
1245 : * \brief Fetch a band object for a dataset.
1246 : * @see GDALDataset::GetRasterBand().
1247 : */
1248 :
1249 413532 : GDALRasterBandH CPL_STDCALL GDALGetRasterBand(GDALDatasetH hDS, int nBandId)
1250 :
1251 : {
1252 413532 : VALIDATE_POINTER1(hDS, "GDALGetRasterBand", nullptr);
1253 :
1254 413532 : return GDALRasterBand::ToHandle(
1255 413532 : GDALDataset::FromHandle(hDS)->GetRasterBand(nBandId));
1256 : }
1257 :
1258 : /************************************************************************/
1259 : /* GetRasterCount() */
1260 : /************************************************************************/
1261 :
1262 : /**
1263 : * \brief Fetch the number of raster bands on this dataset.
1264 : *
1265 : * Same as the C function GDALGetRasterCount().
1266 : *
1267 : * @return the number of raster bands.
1268 : */
1269 :
1270 6161500 : int GDALDataset::GetRasterCount() const
1271 : {
1272 6161500 : return papoBands ? nBands : 0;
1273 : }
1274 :
1275 : /************************************************************************/
1276 : /* GDALGetRasterCount() */
1277 : /************************************************************************/
1278 :
1279 : /**
1280 : * \brief Fetch the number of raster bands on this dataset.
1281 : *
1282 : * @see GDALDataset::GetRasterCount().
1283 : */
1284 :
1285 386817 : int CPL_STDCALL GDALGetRasterCount(GDALDatasetH hDS)
1286 :
1287 : {
1288 386817 : VALIDATE_POINTER1(hDS, "GDALGetRasterCount", 0);
1289 :
1290 386817 : return GDALDataset::FromHandle(hDS)->GetRasterCount();
1291 : }
1292 :
1293 : /************************************************************************/
1294 : /* GetProjectionRef() */
1295 : /************************************************************************/
1296 :
1297 : /**
1298 : * \brief Fetch the projection definition string for this dataset.
1299 : *
1300 : * Same as the C function GDALGetProjectionRef().
1301 : *
1302 : * The returned string defines the projection coordinate system of the
1303 : * image in OpenGIS WKT format. It should be suitable for use with the
1304 : * OGRSpatialReference class.
1305 : *
1306 : * When a projection definition is not available an empty (but not NULL)
1307 : * string is returned.
1308 : *
1309 : * \note Starting with GDAL 3.0, this is a compatibility layer around
1310 : * GetSpatialRef()
1311 : *
1312 : * @return a pointer to an internal projection reference string. It should
1313 : * not be altered, freed or expected to last for long.
1314 : *
1315 : * @see https://gdal.org/tutorials/osr_api_tut.html
1316 : */
1317 :
1318 5259 : const char *GDALDataset::GetProjectionRef() const
1319 : {
1320 5259 : const auto poSRS = GetSpatialRef();
1321 5259 : if (!poSRS || !m_poPrivate)
1322 : {
1323 2383 : return "";
1324 : }
1325 2876 : char *pszWKT = nullptr;
1326 2876 : poSRS->exportToWkt(&pszWKT);
1327 2876 : if (!pszWKT)
1328 : {
1329 0 : return "";
1330 : }
1331 :
1332 : // If called on a thread-safe dataset, we might be called by several
1333 : // threads, so make sure our accesses to m_pszWKTCached are protected
1334 : // by a mutex.
1335 5752 : std::lock_guard oLock(m_poPrivate->m_oMutexWKT);
1336 2876 : if (m_poPrivate->m_pszWKTCached &&
1337 762 : strcmp(pszWKT, m_poPrivate->m_pszWKTCached) == 0)
1338 : {
1339 761 : CPLFree(pszWKT);
1340 761 : return m_poPrivate->m_pszWKTCached;
1341 : }
1342 2115 : CPLFree(m_poPrivate->m_pszWKTCached);
1343 2115 : m_poPrivate->m_pszWKTCached = pszWKT;
1344 2115 : return m_poPrivate->m_pszWKTCached;
1345 : }
1346 :
1347 : /************************************************************************/
1348 : /* GetSpatialRef() */
1349 : /************************************************************************/
1350 :
1351 : static thread_local int tlsEnableLayersInGetSpatialRefCounter = 0;
1352 :
1353 : /**
1354 : * \brief Fetch the spatial reference for this dataset.
1355 : *
1356 : * Same as the C function GDALGetSpatialRef().
1357 : *
1358 : * When a projection definition is not available, null is returned. If used on
1359 : * a dataset where there are GCPs and not a geotransform, this method returns
1360 : * null. Use GetGCPSpatialRef() instead.
1361 : *
1362 : * Since GDAL 3.12, the default implementation of this method will iterate over
1363 : * vector layers and return their SRS if all geometry columns of all layers use
1364 : * the same SRS, or nullptr otherwise.
1365 : *
1366 : * @since GDAL 3.0
1367 : *
1368 : * @return a pointer to an internal object. It should not be altered or freed.
1369 : * Its lifetime will be the one of the dataset object.
1370 : *
1371 : * @see https://gdal.org/tutorials/osr_api_tut.html
1372 : */
1373 :
1374 17736 : const OGRSpatialReference *GDALDataset::GetSpatialRef() const
1375 : {
1376 17736 : if (tlsEnableLayersInGetSpatialRefCounter == 0)
1377 17692 : return GetSpatialRefVectorOnly();
1378 44 : return nullptr;
1379 : }
1380 :
1381 : /************************************************************************/
1382 : /* GetSpatialRefVectorOnly() */
1383 : /************************************************************************/
1384 :
1385 : /**
1386 : * \brief Fetch the spatial reference for this dataset (only for vector layers)
1387 : *
1388 : * The default implementation of this method will iterate over
1389 : * vector layers and return their SRS if all geometry columns of all layers use
1390 : * the same SRS, or nullptr otherwise.
1391 : *
1392 : * @since GDAL 3.12
1393 : *
1394 : * @return a pointer to an internal object. It should not be altered or freed.
1395 : * Its lifetime will be the one of the dataset object.
1396 : */
1397 :
1398 17692 : const OGRSpatialReference *GDALDataset::GetSpatialRefVectorOnly() const
1399 : {
1400 17692 : bool bInit = false;
1401 17692 : const OGRSpatialReference *poGlobalSRS = nullptr;
1402 33857 : for (const OGRLayer *poLayer : GetLayers())
1403 : {
1404 16166 : for (const auto *poGeomFieldDefn :
1405 48500 : poLayer->GetLayerDefn()->GetGeomFields())
1406 : {
1407 16169 : const auto *poSRS = poGeomFieldDefn->GetSpatialRef();
1408 16169 : if (!bInit)
1409 : {
1410 209 : bInit = true;
1411 209 : poGlobalSRS = poSRS;
1412 : }
1413 31918 : else if ((poSRS && !poGlobalSRS) || (!poSRS && poGlobalSRS) ||
1414 15958 : (poSRS && poGlobalSRS && !poSRS->IsSame(poGlobalSRS)))
1415 : {
1416 3 : CPLDebug("GDAL",
1417 : "Not all geometry fields or layers have the same CRS");
1418 3 : return nullptr;
1419 : }
1420 : }
1421 : }
1422 17689 : return poGlobalSRS;
1423 : }
1424 :
1425 : /************************************************************************/
1426 : /* GetSpatialRefRasterOnly() */
1427 : /************************************************************************/
1428 :
1429 : /**
1430 : * \brief Fetch the spatial reference for this dataset (ignoring vector layers)
1431 : *
1432 : * @since GDAL 3.12
1433 : *
1434 : * @return a pointer to an internal object. It should not be altered or freed.
1435 : * Its lifetime will be the one of the dataset object.
1436 : */
1437 :
1438 1076 : const OGRSpatialReference *GDALDataset::GetSpatialRefRasterOnly() const
1439 : {
1440 1076 : ++tlsEnableLayersInGetSpatialRefCounter;
1441 1076 : const auto poRet = GetSpatialRef();
1442 1076 : --tlsEnableLayersInGetSpatialRefCounter;
1443 1076 : return poRet;
1444 : }
1445 :
1446 : /************************************************************************/
1447 : /* GDALGetSpatialRef() */
1448 : /************************************************************************/
1449 :
1450 : /**
1451 : * \brief Fetch the spatial reference for this dataset.
1452 : *
1453 : * Same as the C++ method GDALDataset::GetSpatialRef()
1454 : *
1455 : * @since GDAL 3.0
1456 : *
1457 : * @see GDALDataset::GetSpatialRef()
1458 : */
1459 :
1460 8024 : OGRSpatialReferenceH GDALGetSpatialRef(GDALDatasetH hDS)
1461 :
1462 : {
1463 8024 : VALIDATE_POINTER1(hDS, "GDALGetSpatialRef", nullptr);
1464 :
1465 8024 : return OGRSpatialReference::ToHandle(const_cast<OGRSpatialReference *>(
1466 8024 : GDALDataset::FromHandle(hDS)->GetSpatialRef()));
1467 : }
1468 :
1469 : /************************************************************************/
1470 : /* GDALGetProjectionRef() */
1471 : /************************************************************************/
1472 :
1473 : /**
1474 : * \brief Fetch the projection definition string for this dataset.
1475 : *
1476 : * @see GDALDataset::GetProjectionRef()
1477 : */
1478 :
1479 1458 : const char *CPL_STDCALL GDALGetProjectionRef(GDALDatasetH hDS)
1480 :
1481 : {
1482 1458 : VALIDATE_POINTER1(hDS, "GDALGetProjectionRef", nullptr);
1483 :
1484 1458 : return GDALDataset::FromHandle(hDS)->GetProjectionRef();
1485 : }
1486 :
1487 : /************************************************************************/
1488 : /* SetProjection() */
1489 : /************************************************************************/
1490 :
1491 : /**
1492 : * \brief Set the projection reference string for this dataset.
1493 : *
1494 : * The string should be in OGC WKT or PROJ.4 format. An error may occur
1495 : * because of incorrectly specified projection strings, because the dataset
1496 : * is not writable, or because the dataset does not support the indicated
1497 : * projection. Many formats do not support writing projections.
1498 : *
1499 : * This method is the same as the C GDALSetProjection() function.
1500 : *
1501 : * \note Startig with GDAL 3.0, this is a compatibility layer around
1502 : * SetSpatialRef()
1503 :
1504 : * @param pszProjection projection reference string.
1505 : *
1506 : * @return CE_Failure if an error occurs, otherwise CE_None.
1507 : */
1508 :
1509 2605 : CPLErr GDALDataset::SetProjection(const char *pszProjection)
1510 : {
1511 2605 : if (pszProjection && pszProjection[0] != '\0')
1512 : {
1513 4826 : OGRSpatialReference oSRS;
1514 2413 : oSRS.SetAxisMappingStrategy(OAMS_TRADITIONAL_GIS_ORDER);
1515 2413 : if (oSRS.SetFromUserInput(pszProjection) != OGRERR_NONE)
1516 : {
1517 2 : return CE_Failure;
1518 : }
1519 2411 : return SetSpatialRef(&oSRS);
1520 : }
1521 : else
1522 : {
1523 192 : return SetSpatialRef(nullptr);
1524 : }
1525 : }
1526 :
1527 : /************************************************************************/
1528 : /* SetSpatialRef() */
1529 : /************************************************************************/
1530 :
1531 : /**
1532 : * \brief Set the spatial reference system for this dataset.
1533 : *
1534 : * An error may occur because the dataset
1535 : * is not writable, or because the dataset does not support the indicated
1536 : * projection. Many formats do not support writing projections.
1537 : *
1538 : * This method is the same as the C GDALSetSpatialRef() function.
1539 : *
1540 : * @since GDAL 3.0
1541 :
1542 : * @param poSRS spatial reference system object. nullptr can potentially be
1543 : * passed for drivers that support unsetting the SRS.
1544 : *
1545 : * @return CE_Failure if an error occurs, otherwise CE_None.
1546 : */
1547 :
1548 0 : CPLErr GDALDataset::SetSpatialRef(CPL_UNUSED const OGRSpatialReference *poSRS)
1549 : {
1550 0 : if (!(GetMOFlags() & GMO_IGNORE_UNIMPLEMENTED))
1551 0 : ReportError(CE_Failure, CPLE_NotSupported,
1552 : "Dataset does not support the SetSpatialRef() method.");
1553 0 : return CE_Failure;
1554 : }
1555 :
1556 : /************************************************************************/
1557 : /* GDALSetSpatialRef() */
1558 : /************************************************************************/
1559 :
1560 : /**
1561 : * \brief Set the spatial reference system for this dataset.
1562 : *
1563 : * @since GDAL 3.0
1564 : *
1565 : * @see GDALDataset::SetSpatialRef()
1566 : */
1567 :
1568 1461 : CPLErr GDALSetSpatialRef(GDALDatasetH hDS, OGRSpatialReferenceH hSRS)
1569 :
1570 : {
1571 1461 : VALIDATE_POINTER1(hDS, "GDALSetSpatialRef", CE_Failure);
1572 :
1573 2922 : return GDALDataset::FromHandle(hDS)->SetSpatialRef(
1574 1461 : OGRSpatialReference::FromHandle(hSRS));
1575 : }
1576 :
1577 : /************************************************************************/
1578 : /* GDALSetProjection() */
1579 : /************************************************************************/
1580 :
1581 : /**
1582 : * \brief Set the projection reference string for this dataset.
1583 : *
1584 : * @see GDALDataset::SetProjection()
1585 : */
1586 :
1587 1944 : CPLErr CPL_STDCALL GDALSetProjection(GDALDatasetH hDS,
1588 : const char *pszProjection)
1589 :
1590 : {
1591 1944 : VALIDATE_POINTER1(hDS, "GDALSetProjection", CE_Failure);
1592 :
1593 1944 : return GDALDataset::FromHandle(hDS)->SetProjection(pszProjection);
1594 : }
1595 :
1596 : /************************************************************************/
1597 : /* GetGeoTransform() */
1598 : /************************************************************************/
1599 :
1600 : /**
1601 : * \brief Fetch the affine transformation coefficients.
1602 : *
1603 : * Fetches the coefficients for transforming between pixel/line (P,L) raster
1604 : * space, and projection coordinates (Xp,Yp) space.
1605 : *
1606 : * \code
1607 : * Xp = gt.xorig + P*gt.xscale + L*gt.xrot;
1608 : * Yp = gt.yorig + P*padfTransform[4] + L*gt.yscale;
1609 : * \endcode
1610 : *
1611 : * In a north up image, gt.xscale is the pixel width, and
1612 : * gt.yscale is the pixel height. The upper left corner of the
1613 : * upper left pixel is at position (gt.xorig,gt.yorig).
1614 : *
1615 : * The default transform is (0,1,0,0,0,1) and should be returned even when
1616 : * a CE_Failure error is returned, such as for formats that don't support
1617 : * transformation to projection coordinates.
1618 : *
1619 : * This method does the same thing as the C GDALGetGeoTransform() function.
1620 : *
1621 : * @param gt an existing six double buffer into which the
1622 : * transformation will be placed.
1623 : *
1624 : * @return CE_None on success, or CE_Failure if no transform can be fetched.
1625 : *
1626 : * @since 3.12
1627 : */
1628 :
1629 16057 : CPLErr GDALDataset::GetGeoTransform(GDALGeoTransform >) const
1630 :
1631 : {
1632 16057 : gt = GDALGeoTransform();
1633 :
1634 16057 : return CE_Failure;
1635 : }
1636 :
1637 : /************************************************************************/
1638 : /* GetGeoTransform() */
1639 : /************************************************************************/
1640 :
1641 : /**
1642 : * \brief Fetch the affine transformation coefficients.
1643 : *
1644 : * Fetches the coefficients for transforming between pixel/line (P,L) raster
1645 : * space, and projection coordinates (Xp,Yp) space.
1646 : *
1647 : * \code
1648 : * Xp = padfTransform[0] + P*padfTransform[1] + L*padfTransform[2];
1649 : * Yp = padfTransform[3] + P*padfTransform[4] + L*padfTransform[5];
1650 : * \endcode
1651 : *
1652 : * In a north up image, padfTransform[1] is the pixel width, and
1653 : * padfTransform[5] is the pixel height. The upper left corner of the
1654 : * upper left pixel is at position (padfTransform[0],padfTransform[3]).
1655 : *
1656 : * The default transform is (0,1,0,0,0,1) and should be returned even when
1657 : * a CE_Failure error is returned, such as for formats that don't support
1658 : * transformation to projection coordinates.
1659 : *
1660 : * This method does the same thing as the C GDALGetGeoTransform() function.
1661 : *
1662 : * @param padfTransform an existing six double buffer into which the
1663 : * transformation will be placed.
1664 : *
1665 : * @return CE_None on success, or CE_Failure if no transform can be fetched.
1666 : *
1667 : * @deprecated since 3.12. Use GetGeoTransform(GDALGeoTransform&) instead
1668 : */
1669 :
1670 2 : CPLErr GDALDataset::GetGeoTransform(double *padfTransform) const
1671 :
1672 : {
1673 2 : return GetGeoTransform(
1674 2 : *reinterpret_cast<GDALGeoTransform *>(padfTransform));
1675 : }
1676 :
1677 : /************************************************************************/
1678 : /* GDALGetGeoTransform() */
1679 : /************************************************************************/
1680 :
1681 : /**
1682 : * \brief Fetch the affine transformation coefficients.
1683 : *
1684 : * @see GDALDataset::GetGeoTransform()
1685 : */
1686 :
1687 9604 : CPLErr CPL_STDCALL GDALGetGeoTransform(GDALDatasetH hDS, double *padfTransform)
1688 :
1689 : {
1690 9604 : VALIDATE_POINTER1(hDS, "GDALGetGeoTransform", CE_Failure);
1691 :
1692 19208 : return GDALDataset::FromHandle(hDS)->GetGeoTransform(
1693 9604 : *reinterpret_cast<GDALGeoTransform *>(padfTransform));
1694 : }
1695 :
1696 : /************************************************************************/
1697 : /* SetGeoTransform() */
1698 : /************************************************************************/
1699 :
1700 : /**
1701 : * \fn GDALDataset::SetGeoTransform(const GDALGeoTransform&)
1702 : * \brief Set the affine transformation coefficients.
1703 : *
1704 : * See GetGeoTransform() for details on the meaning of the padfTransform
1705 : * coefficients.
1706 : *
1707 : * This method does the same thing as the C GDALSetGeoTransform() function.
1708 : *
1709 : * @param gt the transformation coefficients to be written with the dataset.
1710 : *
1711 : * @return CE_None on success, or CE_Failure if this transform cannot be
1712 : * written.
1713 : *
1714 : * @since 3.12
1715 : */
1716 :
1717 0 : CPLErr GDALDataset::SetGeoTransform(CPL_UNUSED const GDALGeoTransform >)
1718 :
1719 : {
1720 0 : if (!(GetMOFlags() & GMO_IGNORE_UNIMPLEMENTED))
1721 0 : ReportError(CE_Failure, CPLE_NotSupported,
1722 : "SetGeoTransform() not supported for this dataset.");
1723 :
1724 0 : return CE_Failure;
1725 : }
1726 :
1727 : /************************************************************************/
1728 : /* SetGeoTransform() */
1729 : /************************************************************************/
1730 :
1731 : /**
1732 : * \brief Set the affine transformation coefficients.
1733 : *
1734 : * See GetGeoTransform() for details on the meaning of the padfTransform
1735 : * coefficients.
1736 : *
1737 : * This method does the same thing as the C GDALSetGeoTransform() function.
1738 : *
1739 : * @param padfTransform a six double buffer containing the transformation
1740 : * coefficients to be written with the dataset.
1741 : *
1742 : * @return CE_None on success, or CE_Failure if this transform cannot be
1743 : * written.
1744 : *
1745 : * @deprecated since 3.12. Use SetGeoTransform(const GDALGeoTransform&) instead
1746 : */
1747 38 : CPLErr GDALDataset::SetGeoTransform(const double *padfTransform)
1748 :
1749 : {
1750 38 : return SetGeoTransform(
1751 38 : *reinterpret_cast<const GDALGeoTransform *>(padfTransform));
1752 : }
1753 :
1754 : /************************************************************************/
1755 : /* GDALSetGeoTransform() */
1756 : /************************************************************************/
1757 :
1758 : /**
1759 : * \brief Set the affine transformation coefficients.
1760 : *
1761 : * @see GDALDataset::SetGeoTransform()
1762 : */
1763 :
1764 4479 : CPLErr CPL_STDCALL GDALSetGeoTransform(GDALDatasetH hDS,
1765 : const double *padfTransform)
1766 :
1767 : {
1768 4479 : VALIDATE_POINTER1(hDS, "GDALSetGeoTransform", CE_Failure);
1769 4479 : VALIDATE_POINTER1(padfTransform, "GDALSetGeoTransform", CE_Failure);
1770 :
1771 8958 : return GDALDataset::FromHandle(hDS)->SetGeoTransform(
1772 4479 : *reinterpret_cast<const GDALGeoTransform *>(padfTransform));
1773 : }
1774 :
1775 : /************************************************************************/
1776 : /* GetInternalHandle() */
1777 : /************************************************************************/
1778 :
1779 : /**
1780 : * \fn GDALDataset::GetInternalHandle(const char*)
1781 : * \brief Fetch a format specific internally meaningful handle.
1782 : *
1783 : * This method is the same as the C GDALGetInternalHandle() method.
1784 : *
1785 : * @param pszHandleName the handle name desired. The meaningful names
1786 : * will be specific to the file format.
1787 : *
1788 : * @return the desired handle value, or NULL if not recognized/supported.
1789 : */
1790 :
1791 172 : void *GDALDataset::GetInternalHandle(CPL_UNUSED const char *pszHandleName)
1792 :
1793 : {
1794 172 : return nullptr;
1795 : }
1796 :
1797 : /************************************************************************/
1798 : /* GDALGetInternalHandle() */
1799 : /************************************************************************/
1800 :
1801 : /**
1802 : * \brief Fetch a format specific internally meaningful handle.
1803 : *
1804 : * @see GDALDataset::GetInternalHandle()
1805 : */
1806 :
1807 61 : void *CPL_STDCALL GDALGetInternalHandle(GDALDatasetH hDS,
1808 : const char *pszRequest)
1809 :
1810 : {
1811 61 : VALIDATE_POINTER1(hDS, "GDALGetInternalHandle", nullptr);
1812 :
1813 61 : return GDALDataset::FromHandle(hDS)->GetInternalHandle(pszRequest);
1814 : }
1815 :
1816 : /************************************************************************/
1817 : /* GetDriver() */
1818 : /************************************************************************/
1819 :
1820 : /**
1821 : * \brief Fetch the driver to which this dataset relates.
1822 : *
1823 : * This method is the same as the C GDALGetDatasetDriver() function.
1824 : *
1825 : * @return the driver on which the dataset was created with GDALOpen() or
1826 : * GDALCreate().
1827 : */
1828 :
1829 36272 : GDALDriver *GDALDataset::GetDriver()
1830 : {
1831 36272 : return poDriver;
1832 : }
1833 :
1834 : /************************************************************************/
1835 : /* GDALGetDatasetDriver() */
1836 : /************************************************************************/
1837 :
1838 : /**
1839 : * \brief Fetch the driver to which this dataset relates.
1840 : *
1841 : * @see GDALDataset::GetDriver()
1842 : */
1843 :
1844 2824 : GDALDriverH CPL_STDCALL GDALGetDatasetDriver(GDALDatasetH hDataset)
1845 :
1846 : {
1847 2824 : VALIDATE_POINTER1(hDataset, "GDALGetDatasetDriver", nullptr);
1848 :
1849 : return static_cast<GDALDriverH>(
1850 2824 : GDALDataset::FromHandle(hDataset)->GetDriver());
1851 : }
1852 :
1853 : /************************************************************************/
1854 : /* Reference() */
1855 : /************************************************************************/
1856 :
1857 : /**
1858 : * \brief Add one to dataset reference count.
1859 : *
1860 : * The reference is one after instantiation.
1861 : *
1862 : * This method is the same as the C GDALReferenceDataset() function.
1863 : *
1864 : * @return the post-increment reference count.
1865 : */
1866 :
1867 263528 : int GDALDataset::Reference()
1868 : {
1869 263528 : return ++nRefCount;
1870 : }
1871 :
1872 : /************************************************************************/
1873 : /* GDALReferenceDataset() */
1874 : /************************************************************************/
1875 :
1876 : /**
1877 : * \brief Add one to dataset reference count.
1878 : *
1879 : * @see GDALDataset::Reference()
1880 : */
1881 :
1882 1485 : int CPL_STDCALL GDALReferenceDataset(GDALDatasetH hDataset)
1883 :
1884 : {
1885 1485 : VALIDATE_POINTER1(hDataset, "GDALReferenceDataset", 0);
1886 :
1887 1485 : return GDALDataset::FromHandle(hDataset)->Reference();
1888 : }
1889 :
1890 : /************************************************************************/
1891 : /* Dereference() */
1892 : /************************************************************************/
1893 :
1894 : /**
1895 : * \brief Subtract one from dataset reference count.
1896 : *
1897 : * The reference is one after instantiation. Generally when the reference
1898 : * count has dropped to zero the dataset may be safely deleted (closed).
1899 : *
1900 : * This method is the same as the C GDALDereferenceDataset() function.
1901 : *
1902 : * @return the post-decrement reference count.
1903 : */
1904 :
1905 327444 : int GDALDataset::Dereference()
1906 : {
1907 327444 : return --nRefCount;
1908 : }
1909 :
1910 : /************************************************************************/
1911 : /* GDALDereferenceDataset() */
1912 : /************************************************************************/
1913 :
1914 : /**
1915 : * \brief Subtract one from dataset reference count.
1916 : *
1917 : * @see GDALDataset::Dereference()
1918 : */
1919 :
1920 61866 : int CPL_STDCALL GDALDereferenceDataset(GDALDatasetH hDataset)
1921 :
1922 : {
1923 61866 : VALIDATE_POINTER1(hDataset, "GDALDereferenceDataset", 0);
1924 :
1925 61866 : return GDALDataset::FromHandle(hDataset)->Dereference();
1926 : }
1927 :
1928 : /************************************************************************/
1929 : /* ReleaseRef() */
1930 : /************************************************************************/
1931 :
1932 : /**
1933 : * \brief Drop a reference to this object, and destroy if no longer referenced.
1934 : * @return TRUE if the object has been destroyed.
1935 : */
1936 :
1937 253067 : int GDALDataset::ReleaseRef()
1938 :
1939 : {
1940 253067 : if (Dereference() <= 0)
1941 : {
1942 7763 : nRefCount = 1;
1943 7763 : delete this;
1944 7763 : return TRUE;
1945 : }
1946 245304 : return FALSE;
1947 : }
1948 :
1949 : /************************************************************************/
1950 : /* GDALReleaseDataset() */
1951 : /************************************************************************/
1952 :
1953 : /**
1954 : * \brief Drop a reference to this object, and destroy if no longer referenced.
1955 : *
1956 : * @see GDALDataset::ReleaseRef()
1957 : */
1958 :
1959 1671 : int CPL_STDCALL GDALReleaseDataset(GDALDatasetH hDataset)
1960 :
1961 : {
1962 1671 : VALIDATE_POINTER1(hDataset, "GDALReleaseDataset", 0);
1963 :
1964 1671 : return GDALDataset::FromHandle(hDataset)->ReleaseRef();
1965 : }
1966 :
1967 : /************************************************************************/
1968 : /* GetShared() */
1969 : /************************************************************************/
1970 :
1971 : /**
1972 : * \brief Returns shared flag.
1973 : *
1974 : * @return TRUE if the GDALDataset is available for sharing, or FALSE if not.
1975 : */
1976 :
1977 324265 : int GDALDataset::GetShared() const
1978 : {
1979 324265 : return bShared;
1980 : }
1981 :
1982 : /************************************************************************/
1983 : /* MarkAsShared() */
1984 : /************************************************************************/
1985 :
1986 : /**
1987 : * \brief Mark this dataset as available for sharing.
1988 : */
1989 :
1990 448 : void GDALDataset::MarkAsShared()
1991 :
1992 : {
1993 448 : CPLAssert(!bShared);
1994 :
1995 448 : bShared = true;
1996 448 : if (bIsInternal)
1997 32 : return;
1998 :
1999 416 : GIntBig nPID = GDALGetResponsiblePIDForCurrentThread();
2000 :
2001 : // Insert the dataset in the set of shared opened datasets.
2002 832 : CPLMutexHolderD(&hDLMutex);
2003 416 : if (phSharedDatasetSet == nullptr)
2004 290 : phSharedDatasetSet =
2005 290 : CPLHashSetNew(GDALSharedDatasetHashFunc, GDALSharedDatasetEqualFunc,
2006 : GDALSharedDatasetFreeFunc);
2007 :
2008 : SharedDatasetCtxt *psStruct =
2009 416 : static_cast<SharedDatasetCtxt *>(CPLMalloc(sizeof(SharedDatasetCtxt)));
2010 416 : psStruct->poDS = this;
2011 416 : psStruct->nPID = nPID;
2012 416 : psStruct->nOpenFlags = nOpenFlags & ~GDAL_OF_SHARED;
2013 416 : psStruct->pszDescription = CPLStrdup(GetDescription());
2014 : std::string osConcatenatedOpenOptions =
2015 832 : GDALSharedDatasetConcatenateOpenOptions(papszOpenOptions);
2016 416 : psStruct->pszConcatenatedOpenOptions =
2017 416 : CPLStrdup(osConcatenatedOpenOptions.c_str());
2018 416 : if (CPLHashSetLookup(phSharedDatasetSet, psStruct) != nullptr)
2019 : {
2020 1 : GDALSharedDatasetFreeFunc(psStruct);
2021 1 : ReportError(CE_Failure, CPLE_AppDefined,
2022 : "An existing shared dataset already has this description. "
2023 : "This should not happen.");
2024 : }
2025 : else
2026 : {
2027 415 : CPLHashSetInsert(phSharedDatasetSet, psStruct);
2028 :
2029 415 : (*poAllDatasetMap)[this] = nPID;
2030 : }
2031 : }
2032 :
2033 : /************************************************************************/
2034 : /* MarkSuppressOnClose() */
2035 : /************************************************************************/
2036 :
2037 : /** Set that the dataset must be deleted on close.
2038 : *
2039 : * This is the same as C function GDALDatasetMarkSuppressOnClose()
2040 : */
2041 1252 : void GDALDataset::MarkSuppressOnClose()
2042 : {
2043 1252 : bSuppressOnClose = true;
2044 1252 : }
2045 :
2046 : /************************************************************************/
2047 : /* GDALDatasetMarkSuppressOnClose() */
2048 : /************************************************************************/
2049 :
2050 : /** Set that the dataset must be deleted on close.
2051 : *
2052 : * This is the same as C++ method GDALDataset::MarkSuppressOnClose()
2053 : *
2054 : * @since GDAL 3.12
2055 : */
2056 :
2057 4 : void GDALDatasetMarkSuppressOnClose(GDALDatasetH hDS)
2058 : {
2059 4 : VALIDATE_POINTER0(hDS, "GDALDatasetMarkSuppressOnClose");
2060 :
2061 4 : return GDALDataset::FromHandle(hDS)->MarkSuppressOnClose();
2062 : }
2063 :
2064 : /************************************************************************/
2065 : /* UnMarkSuppressOnClose() */
2066 : /************************************************************************/
2067 :
2068 : /** Remove the flag requesting the dataset to be deleted on close. */
2069 684 : void GDALDataset::UnMarkSuppressOnClose()
2070 : {
2071 684 : bSuppressOnClose = false;
2072 684 : }
2073 :
2074 : /************************************************************************/
2075 : /* CleanupPostFileClosing() */
2076 : /************************************************************************/
2077 :
2078 : /** This method should be called by driver implementations in their destructor,
2079 : * after having closed all files, but before having freed resources that
2080 : * are needed for their GetFileList() implementation.
2081 : * This is used to implement MarkSuppressOnClose behavior.
2082 : */
2083 259 : void GDALDataset::CleanupPostFileClosing()
2084 : {
2085 259 : if (IsMarkedSuppressOnClose())
2086 : {
2087 1 : char **papszFileList = GetFileList();
2088 3 : for (int i = 0; papszFileList && papszFileList[i]; ++i)
2089 2 : VSIUnlink(papszFileList[i]);
2090 1 : CSLDestroy(papszFileList);
2091 : }
2092 259 : }
2093 :
2094 : /************************************************************************/
2095 : /* GetGCPCount() */
2096 : /************************************************************************/
2097 :
2098 : /**
2099 : * \brief Get number of GCPs.
2100 : *
2101 : * This method is the same as the C function GDALGetGCPCount().
2102 : *
2103 : * @return number of GCPs for this dataset. Zero if there are none.
2104 : */
2105 :
2106 16651 : int GDALDataset::GetGCPCount()
2107 : {
2108 16651 : return 0;
2109 : }
2110 :
2111 : /************************************************************************/
2112 : /* GDALGetGCPCount() */
2113 : /************************************************************************/
2114 :
2115 : /**
2116 : * \brief Get number of GCPs.
2117 : *
2118 : * @see GDALDataset::GetGCPCount()
2119 : */
2120 :
2121 2309 : int CPL_STDCALL GDALGetGCPCount(GDALDatasetH hDS)
2122 :
2123 : {
2124 2309 : VALIDATE_POINTER1(hDS, "GDALGetGCPCount", 0);
2125 :
2126 2309 : return GDALDataset::FromHandle(hDS)->GetGCPCount();
2127 : }
2128 :
2129 : /************************************************************************/
2130 : /* GetGCPProjection() */
2131 : /************************************************************************/
2132 :
2133 : /**
2134 : * \brief Get output projection for GCPs.
2135 : *
2136 : * This method is the same as the C function GDALGetGCPProjection().
2137 : *
2138 : * The projection string follows the normal rules from GetProjectionRef().
2139 : *
2140 : * \note Starting with GDAL 3.0, this is a compatibility layer around
2141 : * GetGCPSpatialRef()
2142 : *
2143 : * @return internal projection string or "" if there are no GCPs.
2144 : * It should not be altered, freed or expected to last for long.
2145 : */
2146 :
2147 1053 : const char *GDALDataset::GetGCPProjection() const
2148 : {
2149 1053 : const auto poSRS = GetGCPSpatialRef();
2150 1053 : if (!poSRS || !m_poPrivate)
2151 : {
2152 715 : return "";
2153 : }
2154 338 : char *pszWKT = nullptr;
2155 338 : poSRS->exportToWkt(&pszWKT);
2156 338 : if (!pszWKT)
2157 : {
2158 0 : return "";
2159 : }
2160 :
2161 : // If called on a thread-safe dataset, we might be called by several
2162 : // threads, so make sure our accesses to m_pszWKTCached are protected
2163 : // by a mutex.
2164 676 : std::lock_guard oLock(m_poPrivate->m_oMutexWKT);
2165 338 : if (m_poPrivate->m_pszWKTGCPCached &&
2166 258 : strcmp(pszWKT, m_poPrivate->m_pszWKTGCPCached) == 0)
2167 : {
2168 258 : CPLFree(pszWKT);
2169 258 : return m_poPrivate->m_pszWKTGCPCached;
2170 : }
2171 80 : CPLFree(m_poPrivate->m_pszWKTGCPCached);
2172 80 : m_poPrivate->m_pszWKTGCPCached = pszWKT;
2173 80 : return m_poPrivate->m_pszWKTGCPCached;
2174 : }
2175 :
2176 : /************************************************************************/
2177 : /* GetGCPSpatialRef() */
2178 : /************************************************************************/
2179 :
2180 : /**
2181 : * \brief Get output spatial reference system for GCPs.
2182 : *
2183 : * Same as the C function GDALGetGCPSpatialRef().
2184 : *
2185 : * When a SRS is not available, null is returned. If used on
2186 : * a dataset where there is a geotransform, and not GCPs, this method returns
2187 : * null. Use GetSpatialRef() instead.
2188 : *
2189 : * @since GDAL 3.0
2190 : *
2191 : * @return a pointer to an internal object. It should not be altered or freed.
2192 : * Its lifetime will be the one of the dataset object, or until the next
2193 : * call to this method.
2194 : */
2195 :
2196 47 : const OGRSpatialReference *GDALDataset::GetGCPSpatialRef() const
2197 : {
2198 47 : return nullptr;
2199 : }
2200 :
2201 : /************************************************************************/
2202 : /* GDALGetGCPSpatialRef() */
2203 : /************************************************************************/
2204 :
2205 : /**
2206 : * \brief Get output spatial reference system for GCPs.
2207 : *
2208 : * @since GDAL 3.0
2209 : *
2210 : * @see GDALDataset::GetGCPSpatialRef()
2211 : */
2212 :
2213 472 : OGRSpatialReferenceH GDALGetGCPSpatialRef(GDALDatasetH hDS)
2214 :
2215 : {
2216 472 : VALIDATE_POINTER1(hDS, "GDALGetGCPSpatialRef", nullptr);
2217 :
2218 472 : return OGRSpatialReference::ToHandle(const_cast<OGRSpatialReference *>(
2219 472 : GDALDataset::FromHandle(hDS)->GetGCPSpatialRef()));
2220 : }
2221 :
2222 : /************************************************************************/
2223 : /* GDALGetGCPProjection() */
2224 : /************************************************************************/
2225 :
2226 : /**
2227 : * \brief Get output projection for GCPs.
2228 : *
2229 : * @see GDALDataset::GetGCPProjection()
2230 : */
2231 :
2232 1032 : const char *CPL_STDCALL GDALGetGCPProjection(GDALDatasetH hDS)
2233 :
2234 : {
2235 1032 : VALIDATE_POINTER1(hDS, "GDALGetGCPProjection", nullptr);
2236 :
2237 1032 : return GDALDataset::FromHandle(hDS)->GetGCPProjection();
2238 : }
2239 :
2240 : /************************************************************************/
2241 : /* GetGCPs() */
2242 : /************************************************************************/
2243 :
2244 : /**
2245 : * \brief Fetch GCPs.
2246 : *
2247 : * This method is the same as the C function GDALGetGCPs().
2248 : *
2249 : * @return pointer to internal GCP structure list. It should not be modified,
2250 : * and may change on the next GDAL call.
2251 : */
2252 :
2253 11 : const GDAL_GCP *GDALDataset::GetGCPs()
2254 : {
2255 11 : return nullptr;
2256 : }
2257 :
2258 : /************************************************************************/
2259 : /* GDALGetGCPs() */
2260 : /************************************************************************/
2261 :
2262 : /**
2263 : * \brief Fetch GCPs.
2264 : *
2265 : * @see GDALDataset::GetGCPs()
2266 : */
2267 :
2268 582 : const GDAL_GCP *CPL_STDCALL GDALGetGCPs(GDALDatasetH hDS)
2269 :
2270 : {
2271 582 : VALIDATE_POINTER1(hDS, "GDALGetGCPs", nullptr);
2272 :
2273 582 : return GDALDataset::FromHandle(hDS)->GetGCPs();
2274 : }
2275 :
2276 : /************************************************************************/
2277 : /* SetGCPs() */
2278 : /************************************************************************/
2279 :
2280 : /**
2281 : * \brief Assign GCPs.
2282 : *
2283 : * This method is the same as the C function GDALSetGCPs().
2284 : *
2285 : * This method assigns the passed set of GCPs to this dataset, as well as
2286 : * setting their coordinate system. Internally copies are made of the
2287 : * coordinate system and list of points, so the caller remains responsible for
2288 : * deallocating these arguments if appropriate.
2289 : *
2290 : * Most formats do not support setting of GCPs, even formats that can
2291 : * handle GCPs. These formats will return CE_Failure.
2292 : *
2293 : * \note Startig with GDAL 3.0, this is a compatibility layer around
2294 : * SetGCPs(int, const GDAL_GCP*, const char*)
2295 : *
2296 : * @param nGCPCount number of GCPs being assigned.
2297 : *
2298 : * @param pasGCPList array of GCP structures being assign (nGCPCount in array).
2299 : *
2300 : * @param pszGCPProjection the new OGC WKT coordinate system to assign for the
2301 : * GCP output coordinates. This parameter should be "" if no output coordinate
2302 : * system is known.
2303 : *
2304 : * @return CE_None on success, CE_Failure on failure (including if action is
2305 : * not supported for this format).
2306 : */
2307 :
2308 52 : CPLErr GDALDataset::SetGCPs(int nGCPCount, const GDAL_GCP *pasGCPList,
2309 : const char *pszGCPProjection)
2310 :
2311 : {
2312 52 : if (pszGCPProjection && pszGCPProjection[0] != '\0')
2313 : {
2314 66 : OGRSpatialReference oSRS;
2315 33 : oSRS.SetAxisMappingStrategy(OAMS_TRADITIONAL_GIS_ORDER);
2316 33 : if (oSRS.importFromWkt(pszGCPProjection) != OGRERR_NONE)
2317 : {
2318 0 : return CE_Failure;
2319 : }
2320 33 : return SetGCPs(nGCPCount, pasGCPList, &oSRS);
2321 : }
2322 : else
2323 : {
2324 19 : return SetGCPs(nGCPCount, pasGCPList,
2325 19 : static_cast<const OGRSpatialReference *>(nullptr));
2326 : }
2327 : }
2328 :
2329 : /************************************************************************/
2330 : /* SetGCPs() */
2331 : /************************************************************************/
2332 :
2333 : /**
2334 : * \brief Assign GCPs.
2335 : *
2336 : * This method is the same as the C function GDALSetGCPs().
2337 : *
2338 : * This method assigns the passed set of GCPs to this dataset, as well as
2339 : * setting their coordinate system. Internally copies are made of the
2340 : * coordinate system and list of points, so the caller remains responsible for
2341 : * deallocating these arguments if appropriate.
2342 : *
2343 : * Most formats do not support setting of GCPs, even formats that can
2344 : * handle GCPs. These formats will return CE_Failure.
2345 : *
2346 : * @since GDAL 3.0
2347 : *
2348 : * @param nGCPCount number of GCPs being assigned.
2349 : *
2350 : * @param pasGCPList array of GCP structures being assign (nGCPCount in array).
2351 : *
2352 : * @param poGCP_SRS the new coordinate reference system to assign for the
2353 : * GCP output coordinates. This parameter should be null if no output
2354 : * coordinate system is known.
2355 : *
2356 : * @return CE_None on success, CE_Failure on failure (including if action is
2357 : * not supported for this format).
2358 : */
2359 :
2360 1 : CPLErr GDALDataset::SetGCPs(CPL_UNUSED int nGCPCount,
2361 : CPL_UNUSED const GDAL_GCP *pasGCPList,
2362 : CPL_UNUSED const OGRSpatialReference *poGCP_SRS)
2363 :
2364 : {
2365 1 : if (!(GetMOFlags() & GMO_IGNORE_UNIMPLEMENTED))
2366 1 : ReportError(CE_Failure, CPLE_NotSupported,
2367 : "Dataset does not support the SetGCPs() method.");
2368 :
2369 1 : return CE_Failure;
2370 : }
2371 :
2372 : /************************************************************************/
2373 : /* GDALSetGCPs() */
2374 : /************************************************************************/
2375 :
2376 : /**
2377 : * \brief Assign GCPs.
2378 : *
2379 : * @see GDALDataset::SetGCPs(int, const GDAL_GCP*, const char*)
2380 : */
2381 :
2382 29 : CPLErr CPL_STDCALL GDALSetGCPs(GDALDatasetH hDS, int nGCPCount,
2383 : const GDAL_GCP *pasGCPList,
2384 : const char *pszGCPProjection)
2385 :
2386 : {
2387 29 : VALIDATE_POINTER1(hDS, "GDALSetGCPs", CE_Failure);
2388 :
2389 29 : return GDALDataset::FromHandle(hDS)->SetGCPs(nGCPCount, pasGCPList,
2390 29 : pszGCPProjection);
2391 : }
2392 :
2393 : /************************************************************************/
2394 : /* GDALSetGCPs2() */
2395 : /************************************************************************/
2396 :
2397 : /**
2398 : * \brief Assign GCPs.
2399 : *
2400 : * @since GDAL 3.0
2401 : * @see GDALDataset::SetGCPs(int, const GDAL_GCP*, const OGRSpatialReference*)
2402 : */
2403 :
2404 10 : CPLErr GDALSetGCPs2(GDALDatasetH hDS, int nGCPCount, const GDAL_GCP *pasGCPList,
2405 : OGRSpatialReferenceH hSRS)
2406 :
2407 : {
2408 10 : VALIDATE_POINTER1(hDS, "GDALSetGCPs2", CE_Failure);
2409 :
2410 20 : return GDALDataset::FromHandle(hDS)->SetGCPs(
2411 10 : nGCPCount, pasGCPList, OGRSpatialReference::FromHandle(hSRS));
2412 : }
2413 :
2414 : /************************************************************************/
2415 : /* BuildOverviews() */
2416 : /************************************************************************/
2417 :
2418 : /**
2419 : * \brief Build raster overview(s)
2420 : *
2421 : * If the operation is not supported for the indicated dataset, then
2422 : * CE_Failure is returned, and CPLGetLastErrorNo() will return
2423 : * CPLE_NotSupported.
2424 : *
2425 : * Depending on the actual file format, all overviews level can be also
2426 : * deleted by specifying nOverviews == 0. This works at least for external
2427 : * overviews (.ovr), TIFF internal overviews, etc.
2428 : *
2429 : * Starting with GDAL 3.2, the GDAL_NUM_THREADS configuration option can be set
2430 : * to "ALL_CPUS" or a integer value to specify the number of threads to use for
2431 : * overview computation.
2432 : *
2433 : * This method is the same as the C function GDALBuildOverviewsEx().
2434 : *
2435 : * @param pszResampling one of "AVERAGE", "AVERAGE_MAGPHASE", "RMS",
2436 : * "BILINEAR", "CUBIC", "CUBICSPLINE", "GAUSS", "LANCZOS", "MODE", "NEAREST",
2437 : * or "NONE" controlling the downsampling method applied.
2438 : * @param nOverviews number of overviews to build, or 0 to clean overviews.
2439 : * @param panOverviewList the list of overview decimation factors (positive
2440 : * integers, normally larger or equal to 2) to build, or
2441 : * NULL if nOverviews == 0.
2442 : * @param nListBands number of bands to build overviews for in panBandList.
2443 : * Build for all bands if this is 0.
2444 : * @param panBandList list of band numbers.
2445 : * @param pfnProgress a function to call to report progress, or NULL.
2446 : * @param pProgressData application data to pass to the progress function.
2447 : * @param papszOptions (GDAL >= 3.6) NULL terminated list of options as
2448 : * key=value pairs, or NULL.
2449 : * Possible keys are the ones returned by
2450 : * GetDriver()->GetMetadataItem(GDAL_DMD_OVERVIEW_CREATIONOPTIONLIST)
2451 : *
2452 : * @return CE_None on success or CE_Failure if the operation doesn't work.
2453 : *
2454 : * For example, to build overview level 2, 4 and 8 on all bands the following
2455 : * call could be made:
2456 : * \code{.cpp}
2457 : * int anOverviewList[3] = { 2, 4, 8 };
2458 : *
2459 : * poDataset->BuildOverviews( "NEAREST", 3, anOverviewList, 0, nullptr,
2460 : * GDALDummyProgress, nullptr );
2461 : * \endcode
2462 : *
2463 : * @see GDALRegenerateOverviewsEx()
2464 : */
2465 :
2466 755 : CPLErr GDALDataset::BuildOverviews(const char *pszResampling, int nOverviews,
2467 : const int *panOverviewList, int nListBands,
2468 : const int *panBandList,
2469 : GDALProgressFunc pfnProgress,
2470 : void *pProgressData,
2471 : CSLConstList papszOptions)
2472 : {
2473 755 : int *panAllBandList = nullptr;
2474 :
2475 1510 : CPLStringList aosOptions(papszOptions);
2476 755 : if (poDriver && !aosOptions.empty())
2477 : {
2478 : const char *pszOptionList =
2479 28 : poDriver->GetMetadataItem(GDAL_DMD_OVERVIEW_CREATIONOPTIONLIST);
2480 28 : if (pszOptionList)
2481 : {
2482 : // For backwards compatibility
2483 28 : if (const char *opt = aosOptions.FetchNameValue("USE_RRD"))
2484 : {
2485 4 : if (strstr(pszOptionList, "<Value>RRD</Value>") &&
2486 2 : aosOptions.FetchNameValue("LOCATION") == nullptr)
2487 : {
2488 2 : if (CPLTestBool(opt))
2489 2 : aosOptions.SetNameValue("LOCATION", "RRD");
2490 2 : aosOptions.SetNameValue("USE_RRD", nullptr);
2491 : }
2492 : }
2493 28 : if (const char *opt =
2494 28 : aosOptions.FetchNameValue("VRT_VIRTUAL_OVERVIEWS"))
2495 : {
2496 3 : if (strstr(pszOptionList, "VIRTUAL"))
2497 : {
2498 3 : aosOptions.SetNameValue("VIRTUAL", opt);
2499 3 : aosOptions.SetNameValue("VRT_VIRTUAL_OVERVIEWS", nullptr);
2500 : }
2501 : }
2502 :
2503 76 : for (const auto &[pszKey, pszValue] :
2504 104 : cpl::IterateNameValue(papszOptions))
2505 : {
2506 38 : if (cpl::ends_with(std::string_view(pszKey), "_OVERVIEW"))
2507 : {
2508 : aosOptions.SetNameValue(
2509 16 : std::string(pszKey)
2510 16 : .substr(0, strlen(pszKey) - strlen("_OVERVIEW"))
2511 : .c_str(),
2512 16 : pszValue);
2513 8 : aosOptions.SetNameValue(pszKey, nullptr);
2514 : }
2515 : }
2516 :
2517 56 : CPLString osDriver;
2518 28 : osDriver.Printf("driver %s", poDriver->GetDescription());
2519 28 : GDALValidateOptions(pszOptionList, aosOptions.List(),
2520 : "overview creation option", osDriver);
2521 : }
2522 : }
2523 :
2524 755 : if (nListBands == 0)
2525 : {
2526 743 : nListBands = GetRasterCount();
2527 : panAllBandList =
2528 743 : static_cast<int *>(CPLMalloc(sizeof(int) * nListBands));
2529 67483 : for (int i = 0; i < nListBands; ++i)
2530 66740 : panAllBandList[i] = i + 1;
2531 :
2532 743 : panBandList = panAllBandList;
2533 : }
2534 :
2535 755 : if (pfnProgress == nullptr)
2536 720 : pfnProgress = GDALDummyProgress;
2537 :
2538 1844 : for (int i = 0; i < nOverviews; ++i)
2539 : {
2540 1090 : if (panOverviewList[i] <= 0)
2541 : {
2542 1 : CPLError(CE_Failure, CPLE_IllegalArg,
2543 : "panOverviewList[%d] = %d is invalid. It must be a "
2544 : "positive value",
2545 1 : i, panOverviewList[i]);
2546 1 : CPLFree(panAllBandList);
2547 1 : return CE_Failure;
2548 : }
2549 : }
2550 :
2551 754 : const CPLErr eErr = IBuildOverviews(
2552 : pszResampling, nOverviews, panOverviewList, nListBands, panBandList,
2553 754 : pfnProgress, pProgressData, aosOptions.List());
2554 :
2555 754 : if (panAllBandList != nullptr)
2556 741 : CPLFree(panAllBandList);
2557 :
2558 754 : return eErr;
2559 : }
2560 :
2561 : /************************************************************************/
2562 : /* GDALBuildOverviews() */
2563 : /************************************************************************/
2564 :
2565 : /**
2566 : * \brief Build raster overview(s)
2567 : *
2568 : * @see GDALDataset::BuildOverviews() and GDALBuildOverviews()
2569 : */
2570 :
2571 27 : CPLErr CPL_STDCALL GDALBuildOverviews(GDALDatasetH hDataset,
2572 : const char *pszResampling, int nOverviews,
2573 : const int *panOverviewList,
2574 : int nListBands, const int *panBandList,
2575 : GDALProgressFunc pfnProgress,
2576 : void *pProgressData)
2577 :
2578 : {
2579 27 : VALIDATE_POINTER1(hDataset, "GDALBuildOverviews", CE_Failure);
2580 :
2581 27 : return GDALDataset::FromHandle(hDataset)->BuildOverviews(
2582 : pszResampling, nOverviews, panOverviewList, nListBands, panBandList,
2583 27 : pfnProgress, pProgressData, nullptr);
2584 : }
2585 :
2586 : /************************************************************************/
2587 : /* GDALBuildOverviews() */
2588 : /************************************************************************/
2589 :
2590 : /**
2591 : * \brief Build raster overview(s)
2592 : *
2593 : * @see GDALDataset::BuildOverviews()
2594 : * @since GDAL 3.6
2595 : */
2596 :
2597 : CPLErr CPL_STDCALL
2598 707 : GDALBuildOverviewsEx(GDALDatasetH hDataset, const char *pszResampling,
2599 : int nOverviews, const int *panOverviewList, int nListBands,
2600 : const int *panBandList, GDALProgressFunc pfnProgress,
2601 : void *pProgressData, CSLConstList papszOptions)
2602 :
2603 : {
2604 707 : VALIDATE_POINTER1(hDataset, "GDALBuildOverviews", CE_Failure);
2605 :
2606 707 : return GDALDataset::FromHandle(hDataset)->BuildOverviews(
2607 : pszResampling, nOverviews, panOverviewList, nListBands, panBandList,
2608 707 : pfnProgress, pProgressData, papszOptions);
2609 : }
2610 :
2611 : /************************************************************************/
2612 : /* IBuildOverviews() */
2613 : /* */
2614 : /* Default implementation. */
2615 : /************************************************************************/
2616 :
2617 : //! @cond Doxygen_Suppress
2618 198 : CPLErr GDALDataset::IBuildOverviews(const char *pszResampling, int nOverviews,
2619 : const int *panOverviewList, int nListBands,
2620 : const int *panBandList,
2621 : GDALProgressFunc pfnProgress,
2622 : void *pProgressData,
2623 : CSLConstList papszOptions)
2624 :
2625 : {
2626 198 : if (oOvManager.IsInitialized())
2627 197 : return oOvManager.BuildOverviews(
2628 : nullptr, pszResampling, nOverviews, panOverviewList, nListBands,
2629 197 : panBandList, pfnProgress, pProgressData, papszOptions);
2630 : else
2631 : {
2632 1 : ReportError(CE_Failure, CPLE_NotSupported,
2633 : "BuildOverviews() not supported for this dataset.");
2634 :
2635 1 : return CE_Failure;
2636 : }
2637 : }
2638 :
2639 : //! @endcond
2640 :
2641 : /************************************************************************/
2642 : /* AddOverviews() */
2643 : /* */
2644 : /* Default implementation. */
2645 : /************************************************************************/
2646 :
2647 : /**
2648 : * \brief Add overview from existing dataset(s)
2649 : *
2650 : * This function creates new overview levels or refresh existing one from
2651 : * the list of provided overview datasets.
2652 : * Source overviews may come from any GDAL supported format, provided they
2653 : * have the same number of bands and geospatial extent than the target
2654 : * dataset.
2655 : *
2656 : * If the operation is not supported for the indicated dataset, then
2657 : * CE_Failure is returned, and CPLGetLastErrorNo() will return
2658 : * CPLE_NotSupported.
2659 : *
2660 : * At time of writing, this method is only implemented for internal overviews
2661 : * of GeoTIFF datasets and external overviews in GeoTIFF format.
2662 : *
2663 : * @param apoSrcOvrDS Vector of source overviews.
2664 : * @param pfnProgress a function to call to report progress, or NULL.
2665 : * @param pProgressData application data to pass to the progress function.
2666 : * @param papszOptions NULL terminated list of options as
2667 : * key=value pairs, or NULL. Possible keys are the
2668 : * ones returned by
2669 : * GetDriver()->GetMetadataItem(GDAL_DMD_OVERVIEW_CREATIONOPTIONLIST)
2670 : *
2671 : * @return CE_None on success or CE_Failure if the operation doesn't work.
2672 : * @since 3.12
2673 : */
2674 5 : CPLErr GDALDataset::AddOverviews(const std::vector<GDALDataset *> &apoSrcOvrDS,
2675 : GDALProgressFunc pfnProgress,
2676 : void *pProgressData, CSLConstList papszOptions)
2677 : {
2678 5 : if (oOvManager.IsInitialized())
2679 : {
2680 4 : return oOvManager.AddOverviews(nullptr, apoSrcOvrDS, pfnProgress,
2681 4 : pProgressData, papszOptions);
2682 : }
2683 : else
2684 : {
2685 1 : ReportError(CE_Failure, CPLE_NotSupported,
2686 : "AddOverviews() not supported for this dataset.");
2687 1 : return CE_Failure;
2688 : }
2689 : }
2690 :
2691 : /************************************************************************/
2692 : /* IRasterIO() */
2693 : /* */
2694 : /* The default implementation of IRasterIO() is, in the general */
2695 : /* case to pass the request off to each band objects rasterio */
2696 : /* methods with appropriate arguments. In some cases, it might */
2697 : /* choose instead the BlockBasedRasterIO() implementation. */
2698 : /************************************************************************/
2699 :
2700 : //! @cond Doxygen_Suppress
2701 449181 : CPLErr GDALDataset::IRasterIO(GDALRWFlag eRWFlag, int nXOff, int nYOff,
2702 : int nXSize, int nYSize, void *pData,
2703 : int nBufXSize, int nBufYSize,
2704 : GDALDataType eBufType, int nBandCount,
2705 : BANDMAP_TYPE panBandMap, GSpacing nPixelSpace,
2706 : GSpacing nLineSpace, GSpacing nBandSpace,
2707 : GDALRasterIOExtraArg *psExtraArg)
2708 :
2709 : {
2710 449181 : const char *pszInterleave = nullptr;
2711 :
2712 449181 : CPLAssert(nullptr != pData);
2713 :
2714 449181 : const bool bHasSubpixelShift =
2715 454744 : psExtraArg->bFloatingPointWindowValidity &&
2716 453187 : psExtraArg->eResampleAlg != GRIORA_NearestNeighbour &&
2717 4006 : (nXOff != psExtraArg->dfXOff || nYOff != psExtraArg->dfYOff);
2718 :
2719 449062 : if (!bHasSubpixelShift && nXSize == nBufXSize && nYSize == nBufYSize &&
2720 71565 : nBandCount > 1 &&
2721 71565 : (pszInterleave = GetMetadataItem("INTERLEAVE", "IMAGE_STRUCTURE")) !=
2722 898243 : nullptr &&
2723 68378 : EQUAL(pszInterleave, "PIXEL"))
2724 : {
2725 64956 : return BlockBasedRasterIO(eRWFlag, nXOff, nYOff, nXSize, nYSize, pData,
2726 : nBufXSize, nBufYSize, eBufType, nBandCount,
2727 : panBandMap, nPixelSpace, nLineSpace,
2728 64956 : nBandSpace, psExtraArg);
2729 : }
2730 :
2731 384225 : if (eRWFlag == GF_Read &&
2732 204631 : (psExtraArg->eResampleAlg == GRIORA_Cubic ||
2733 203842 : psExtraArg->eResampleAlg == GRIORA_CubicSpline ||
2734 203841 : psExtraArg->eResampleAlg == GRIORA_Bilinear ||
2735 204631 : psExtraArg->eResampleAlg == GRIORA_Lanczos) &&
2736 952 : !(nXSize == nBufXSize && nYSize == nBufYSize) && nBandCount > 1)
2737 : {
2738 930 : if (nBufXSize < nXSize && nBufYSize < nYSize && AreOverviewsEnabled())
2739 : {
2740 719 : int bTried = FALSE;
2741 719 : const CPLErr eErr = TryOverviewRasterIO(
2742 : eRWFlag, nXOff, nYOff, nXSize, nYSize, pData, nBufXSize,
2743 : nBufYSize, eBufType, nBandCount, panBandMap, nPixelSpace,
2744 : nLineSpace, nBandSpace, psExtraArg, &bTried);
2745 719 : if (bTried)
2746 1 : return eErr;
2747 : }
2748 :
2749 929 : GDALDataType eFirstBandDT = GDT_Unknown;
2750 929 : int nFirstMaskFlags = 0;
2751 929 : GDALRasterBand *poFirstMaskBand = nullptr;
2752 929 : int nOKBands = 0;
2753 :
2754 : // Check if bands share the same mask band
2755 2921 : for (int i = 0; i < nBandCount; ++i)
2756 : {
2757 2652 : GDALRasterBand *poBand = GetRasterBand(panBandMap[i]);
2758 4629 : if ((nBufXSize < nXSize || nBufYSize < nYSize) &&
2759 1977 : poBand->GetOverviewCount())
2760 : {
2761 : // Could be improved to select the appropriate overview.
2762 3 : break;
2763 : }
2764 2649 : if (poBand->GetColorTable() != nullptr)
2765 : {
2766 0 : break;
2767 : }
2768 2649 : const GDALDataType eDT = poBand->GetRasterDataType();
2769 2649 : if (GDALDataTypeIsComplex(eDT))
2770 : {
2771 30 : break;
2772 : }
2773 2619 : if (i == 0)
2774 : {
2775 896 : eFirstBandDT = eDT;
2776 896 : nFirstMaskFlags = poBand->GetMaskFlags();
2777 896 : if (nFirstMaskFlags == GMF_NODATA)
2778 : {
2779 : // The dataset-level resampling code is not ready for nodata
2780 : // Fallback to band-level resampling
2781 10 : break;
2782 : }
2783 886 : poFirstMaskBand = poBand->GetMaskBand();
2784 : }
2785 : else
2786 : {
2787 1723 : if (eDT != eFirstBandDT)
2788 : {
2789 0 : break;
2790 : }
2791 1723 : int nMaskFlags = poBand->GetMaskFlags();
2792 1723 : if (nMaskFlags == GMF_NODATA)
2793 : {
2794 : // The dataset-level resampling code is not ready for nodata
2795 : // Fallback to band-level resampling
2796 0 : break;
2797 : }
2798 1723 : GDALRasterBand *poMaskBand = poBand->GetMaskBand();
2799 1723 : if (nFirstMaskFlags == GMF_ALL_VALID &&
2800 : nMaskFlags == GMF_ALL_VALID)
2801 : {
2802 : // Ok.
2803 : }
2804 1077 : else if (poFirstMaskBand == poMaskBand)
2805 : {
2806 : // Ok.
2807 : }
2808 : else
2809 : {
2810 617 : break;
2811 : }
2812 : }
2813 :
2814 1992 : ++nOKBands;
2815 : }
2816 :
2817 929 : GDALProgressFunc pfnProgressGlobal = psExtraArg->pfnProgress;
2818 929 : void *pProgressDataGlobal = psExtraArg->pProgressData;
2819 :
2820 929 : CPLErr eErr = CE_None;
2821 929 : if (nOKBands > 0)
2822 : {
2823 886 : if (nOKBands < nBandCount)
2824 : {
2825 617 : psExtraArg->pfnProgress = GDALScaledProgress;
2826 1234 : psExtraArg->pProgressData = GDALCreateScaledProgress(
2827 617 : 0.0, static_cast<double>(nOKBands) / nBandCount,
2828 : pfnProgressGlobal, pProgressDataGlobal);
2829 617 : if (psExtraArg->pProgressData == nullptr)
2830 228 : psExtraArg->pfnProgress = nullptr;
2831 : }
2832 :
2833 886 : eErr = RasterIOResampled(eRWFlag, nXOff, nYOff, nXSize, nYSize,
2834 : pData, nBufXSize, nBufYSize, eBufType,
2835 : nOKBands, panBandMap, nPixelSpace,
2836 : nLineSpace, nBandSpace, psExtraArg);
2837 :
2838 886 : if (nOKBands < nBandCount)
2839 : {
2840 617 : GDALDestroyScaledProgress(psExtraArg->pProgressData);
2841 : }
2842 : }
2843 929 : if (eErr == CE_None && nOKBands < nBandCount)
2844 : {
2845 657 : if (nOKBands > 0)
2846 : {
2847 614 : psExtraArg->pfnProgress = GDALScaledProgress;
2848 1228 : psExtraArg->pProgressData = GDALCreateScaledProgress(
2849 614 : static_cast<double>(nOKBands) / nBandCount, 1.0,
2850 : pfnProgressGlobal, pProgressDataGlobal);
2851 614 : if (psExtraArg->pProgressData == nullptr)
2852 225 : psExtraArg->pfnProgress = nullptr;
2853 : }
2854 1314 : eErr = BandBasedRasterIO(
2855 : eRWFlag, nXOff, nYOff, nXSize, nYSize,
2856 657 : static_cast<GByte *>(pData) + nBandSpace * nOKBands, nBufXSize,
2857 : nBufYSize, eBufType, nBandCount - nOKBands,
2858 657 : panBandMap + nOKBands, nPixelSpace, nLineSpace, nBandSpace,
2859 : psExtraArg);
2860 657 : if (nOKBands > 0)
2861 : {
2862 614 : GDALDestroyScaledProgress(psExtraArg->pProgressData);
2863 : }
2864 : }
2865 :
2866 929 : psExtraArg->pfnProgress = pfnProgressGlobal;
2867 929 : psExtraArg->pProgressData = pProgressDataGlobal;
2868 :
2869 929 : return eErr;
2870 : }
2871 :
2872 383295 : return BandBasedRasterIO(eRWFlag, nXOff, nYOff, nXSize, nYSize, pData,
2873 : nBufXSize, nBufYSize, eBufType, nBandCount,
2874 : panBandMap, nPixelSpace, nLineSpace, nBandSpace,
2875 383295 : psExtraArg);
2876 : }
2877 :
2878 : //! @endcond
2879 :
2880 : /************************************************************************/
2881 : /* BandBasedRasterIO() */
2882 : /* */
2883 : /* Pass the request off to each band objects rasterio methods with */
2884 : /* appropriate arguments. */
2885 : /************************************************************************/
2886 :
2887 : //! @cond Doxygen_Suppress
2888 647254 : CPLErr GDALDataset::BandBasedRasterIO(
2889 : GDALRWFlag eRWFlag, int nXOff, int nYOff, int nXSize, int nYSize,
2890 : void *pData, int nBufXSize, int nBufYSize, GDALDataType eBufType,
2891 : int nBandCount, const int *panBandMap, GSpacing nPixelSpace,
2892 : GSpacing nLineSpace, GSpacing nBandSpace, GDALRasterIOExtraArg *psExtraArg)
2893 :
2894 : {
2895 : int iBandIndex;
2896 647254 : CPLErr eErr = CE_None;
2897 :
2898 647254 : GDALProgressFunc pfnProgressGlobal = psExtraArg->pfnProgress;
2899 647254 : void *pProgressDataGlobal = psExtraArg->pProgressData;
2900 :
2901 1661500 : for (iBandIndex = 0; iBandIndex < nBandCount && eErr == CE_None;
2902 : ++iBandIndex)
2903 : {
2904 1014240 : GDALRasterBand *poBand = GetRasterBand(panBandMap[iBandIndex]);
2905 :
2906 1014240 : if (poBand == nullptr)
2907 : {
2908 0 : eErr = CE_Failure;
2909 0 : break;
2910 : }
2911 :
2912 1014240 : GByte *pabyBandData =
2913 1014240 : static_cast<GByte *>(pData) + iBandIndex * nBandSpace;
2914 :
2915 1014240 : if (nBandCount > 1)
2916 : {
2917 544996 : psExtraArg->pfnProgress = GDALScaledProgress;
2918 1089990 : psExtraArg->pProgressData = GDALCreateScaledProgress(
2919 : 1.0 * iBandIndex / nBandCount,
2920 544996 : 1.0 * (iBandIndex + 1) / nBandCount, pfnProgressGlobal,
2921 : pProgressDataGlobal);
2922 544996 : if (psExtraArg->pProgressData == nullptr)
2923 531401 : psExtraArg->pfnProgress = nullptr;
2924 : }
2925 :
2926 2028490 : eErr = poBand->IRasterIO(eRWFlag, nXOff, nYOff, nXSize, nYSize,
2927 : pabyBandData, nBufXSize, nBufYSize, eBufType,
2928 1014240 : nPixelSpace, nLineSpace, psExtraArg);
2929 :
2930 1014240 : if (nBandCount > 1)
2931 544996 : GDALDestroyScaledProgress(psExtraArg->pProgressData);
2932 : }
2933 :
2934 647254 : psExtraArg->pfnProgress = pfnProgressGlobal;
2935 647254 : psExtraArg->pProgressData = pProgressDataGlobal;
2936 :
2937 647254 : return eErr;
2938 : }
2939 :
2940 : //! @endcond
2941 :
2942 : /************************************************************************/
2943 : /* ValidateRasterIOOrAdviseReadParameters() */
2944 : /************************************************************************/
2945 :
2946 : //! @cond Doxygen_Suppress
2947 752054 : CPLErr GDALDataset::ValidateRasterIOOrAdviseReadParameters(
2948 : const char *pszCallingFunc, int *pbStopProcessingOnCENone, int nXOff,
2949 : int nYOff, int nXSize, int nYSize, int nBufXSize, int nBufYSize,
2950 : int nBandCount, const int *panBandMap)
2951 : {
2952 :
2953 : /* -------------------------------------------------------------------- */
2954 : /* Some size values are "noop". Lets just return to avoid */
2955 : /* stressing lower level functions. */
2956 : /* -------------------------------------------------------------------- */
2957 752054 : if (nXSize < 1 || nYSize < 1 || nBufXSize < 1 || nBufYSize < 1)
2958 : {
2959 27 : CPLDebug("GDAL",
2960 : "%s skipped for odd window or buffer size.\n"
2961 : " Window = (%d,%d)x%dx%d\n"
2962 : " Buffer = %dx%d",
2963 : pszCallingFunc, nXOff, nYOff, nXSize, nYSize, nBufXSize,
2964 : nBufYSize);
2965 :
2966 27 : *pbStopProcessingOnCENone = TRUE;
2967 27 : return CE_None;
2968 : }
2969 :
2970 752027 : CPLErr eErr = CE_None;
2971 752027 : *pbStopProcessingOnCENone = FALSE;
2972 :
2973 752027 : if (nXOff < 0 || nXSize > nRasterXSize - nXOff || nYOff < 0 ||
2974 752025 : nYSize > nRasterYSize - nYOff)
2975 : {
2976 2 : ReportError(CE_Failure, CPLE_IllegalArg,
2977 : "Access window out of range in %s. Requested "
2978 : "(%d,%d) of size %dx%d on raster of %dx%d.",
2979 : pszCallingFunc, nXOff, nYOff, nXSize, nYSize, nRasterXSize,
2980 : nRasterYSize);
2981 2 : eErr = CE_Failure;
2982 : }
2983 :
2984 752027 : if (panBandMap == nullptr && nBandCount > GetRasterCount())
2985 : {
2986 0 : ReportError(CE_Failure, CPLE_IllegalArg,
2987 : "%s: nBandCount cannot be greater than %d", pszCallingFunc,
2988 : GetRasterCount());
2989 0 : eErr = CE_Failure;
2990 : }
2991 :
2992 2249450 : for (int i = 0; i < nBandCount && eErr == CE_None; ++i)
2993 : {
2994 1497420 : int iBand = (panBandMap != nullptr) ? panBandMap[i] : i + 1;
2995 1497420 : if (iBand < 1 || iBand > GetRasterCount())
2996 : {
2997 3 : ReportError(
2998 : CE_Failure, CPLE_IllegalArg,
2999 : "%s: panBandMap[%d] = %d, this band does not exist on dataset.",
3000 : pszCallingFunc, i, iBand);
3001 3 : eErr = CE_Failure;
3002 : }
3003 :
3004 1497420 : if (eErr == CE_None && GetRasterBand(iBand) == nullptr)
3005 : {
3006 0 : ReportError(
3007 : CE_Failure, CPLE_IllegalArg,
3008 : "%s: panBandMap[%d]=%d, this band should exist but is NULL!",
3009 : pszCallingFunc, i, iBand);
3010 0 : eErr = CE_Failure;
3011 : }
3012 : }
3013 :
3014 752027 : return eErr;
3015 : }
3016 :
3017 : //! @endcond
3018 :
3019 : /************************************************************************/
3020 : /* RasterIO() */
3021 : /************************************************************************/
3022 :
3023 : /**
3024 : * \brief Read/write a region of image data from multiple bands.
3025 : *
3026 : * This method allows reading a region of one or more GDALRasterBands from
3027 : * this dataset into a buffer, or writing data from a buffer into a region
3028 : * of the GDALRasterBands. It automatically takes care of data type
3029 : * translation if the data type (eBufType) of the buffer is different than
3030 : * that of the GDALRasterBand.
3031 : * The method also takes care of image decimation / replication if the
3032 : * buffer size (nBufXSize x nBufYSize) is different than the size of the
3033 : * region being accessed (nXSize x nYSize).
3034 : *
3035 : * The window of interest expressed by (nXOff, nYOff, nXSize, nYSize) should be
3036 : * fully within the raster space, that is nXOff >= 0, nYOff >= 0,
3037 : * nXOff + nXSize <= GetRasterXSize() and nYOff + nYSize <= GetRasterYSize().
3038 : * If reads larger than the raster space are wished, GDALTranslate() might be used.
3039 : * Or use nLineSpace and a possibly shifted pData value.
3040 : *
3041 : * The nPixelSpace, nLineSpace and nBandSpace parameters allow reading into or
3042 : * writing from various organization of buffers.
3043 : *
3044 : * Some formats may efficiently implement decimation into a buffer by
3045 : * reading from lower resolution overview images. The logic of the default
3046 : * implementation in the base class GDALRasterBand is the following one. It
3047 : * computes a target_downscaling_factor from the window of interest and buffer
3048 : * size which is min(nXSize/nBufXSize, nYSize/nBufYSize).
3049 : * It then walks through overviews and will select the first one whose
3050 : * downscaling factor is greater than target_downscaling_factor / 1.2.
3051 : *
3052 : * Let's assume we have overviews at downscaling factors 2, 4 and 8.
3053 : * The relationship between target_downscaling_factor and the select overview
3054 : * level is the following one:
3055 : *
3056 : * target_downscaling_factor | selected_overview
3057 : * ------------------------- | -----------------
3058 : * ]0, 2 / 1.2] | full resolution band
3059 : * ]2 / 1.2, 4 / 1.2] | 2x downsampled band
3060 : * ]4 / 1.2, 8 / 1.2] | 4x downsampled band
3061 : * ]8 / 1.2, infinity[ | 8x downsampled band
3062 : *
3063 : * Note that starting with GDAL 3.9, this 1.2 oversampling factor can be
3064 : * modified by setting the GDAL_OVERVIEW_OVERSAMPLING_THRESHOLD configuration
3065 : * option. Also note that starting with GDAL 3.9, when the resampling algorithm
3066 : * specified in psExtraArg->eResampleAlg is different from GRIORA_NearestNeighbour,
3067 : * this oversampling threshold defaults to 1. Consequently if there are overviews
3068 : * of downscaling factor 2, 4 and 8, and the desired downscaling factor is
3069 : * 7.99, the overview of factor 4 will be selected for a non nearest resampling.
3070 : *
3071 : * For highest performance full resolution data access, read and write
3072 : * on "block boundaries" as returned by GetBlockSize(), or use the
3073 : * ReadBlock() and WriteBlock() methods.
3074 : *
3075 : * This method is the same as the C GDALDatasetRasterIO() or
3076 : * GDALDatasetRasterIOEx() functions.
3077 : *
3078 : * @param eRWFlag Either GF_Read to read a region of data, or GF_Write to
3079 : * write a region of data.
3080 : *
3081 : * @param nXOff The pixel offset to the top left corner of the region
3082 : * of the band to be accessed. This would be zero to start from the left side.
3083 : *
3084 : * @param nYOff The line offset to the top left corner of the region
3085 : * of the band to be accessed. This would be zero to start from the top.
3086 : *
3087 : * @param nXSize The width of the region of the band to be accessed in pixels.
3088 : *
3089 : * @param nYSize The height of the region of the band to be accessed in lines.
3090 : *
3091 : * @param pData The buffer into which the data should be read, or from which
3092 : * it should be written. This buffer must contain at least
3093 : * nBufXSize * nBufYSize * nBandCount words of type eBufType. It is organized
3094 : * in left to right,top to bottom pixel order. Spacing is controlled by the
3095 : * nPixelSpace, and nLineSpace parameters.
3096 : * Note that even with eRWFlag==GF_Write, the content of the buffer might be
3097 : * temporarily modified during the execution of this method (and eventually
3098 : * restored back to its original content), so it is not safe to use a buffer
3099 : * stored in a read-only section of the calling program.
3100 : *
3101 : * @param nBufXSize the width of the buffer image into which the desired region
3102 : * is to be read, or from which it is to be written.
3103 : *
3104 : * @param nBufYSize the height of the buffer image into which the desired
3105 : * region is to be read, or from which it is to be written.
3106 : *
3107 : * @param eBufType the type of the pixel values in the pData data buffer. The
3108 : * pixel values will automatically be translated to/from the GDALRasterBand
3109 : * data type as needed. Most driver implementations will use GDALCopyWords64()
3110 : * to perform data type translation.
3111 : *
3112 : * @param nBandCount the number of bands being read or written.
3113 : *
3114 : * @param panBandMap the list of nBandCount band numbers being read/written.
3115 : * Note band numbers are 1 based. This may be NULL to select the first
3116 : * nBandCount bands. (Note: before GDAL 3.10, argument type was "int*", and
3117 : * not "const int*")
3118 : *
3119 : * @param nPixelSpace The byte offset from the start of one pixel value in
3120 : * pData to the start of the next pixel value within a scanline. If defaulted
3121 : * (0) the size of the datatype eBufType is used.
3122 : *
3123 : * @param nLineSpace The byte offset from the start of one scanline in
3124 : * pData to the start of the next. If defaulted (0) the size of the datatype
3125 : * eBufType * nBufXSize is used.
3126 : *
3127 : * @param nBandSpace the byte offset from the start of one bands data to the
3128 : * start of the next. If defaulted (0) the value will be
3129 : * nLineSpace * nBufYSize implying band sequential organization
3130 : * of the data buffer.
3131 : *
3132 : * @param psExtraArg pointer to a GDALRasterIOExtraArg
3133 : * structure with additional arguments to specify resampling and progress
3134 : * callback, or NULL for default behavior. The GDAL_RASTERIO_RESAMPLING
3135 : * configuration option can also be defined to override the default resampling
3136 : * to one of BILINEAR, CUBIC, CUBICSPLINE, LANCZOS, AVERAGE or MODE.
3137 : *
3138 : * @return CE_Failure if the access fails, otherwise CE_None.
3139 : */
3140 :
3141 736500 : CPLErr GDALDataset::RasterIO(GDALRWFlag eRWFlag, int nXOff, int nYOff,
3142 : int nXSize, int nYSize, void *pData, int nBufXSize,
3143 : int nBufYSize, GDALDataType eBufType,
3144 : int nBandCount, const int *panBandMap,
3145 : GSpacing nPixelSpace, GSpacing nLineSpace,
3146 : GSpacing nBandSpace,
3147 : GDALRasterIOExtraArg *psExtraArg)
3148 :
3149 : {
3150 : GDALRasterIOExtraArg sExtraArg;
3151 736500 : if (psExtraArg == nullptr)
3152 : {
3153 538447 : INIT_RASTERIO_EXTRA_ARG(sExtraArg);
3154 :
3155 : // 4 below inits are not strictly needed but make Coverity Scan
3156 : // happy
3157 538447 : sExtraArg.dfXOff = nXOff;
3158 538447 : sExtraArg.dfYOff = nYOff;
3159 538447 : sExtraArg.dfXSize = nXSize;
3160 538447 : sExtraArg.dfYSize = nYSize;
3161 :
3162 538447 : psExtraArg = &sExtraArg;
3163 : }
3164 198053 : else if (CPL_UNLIKELY(psExtraArg->nVersion >
3165 : RASTERIO_EXTRA_ARG_CURRENT_VERSION))
3166 : {
3167 0 : ReportError(CE_Failure, CPLE_AppDefined,
3168 : "Unhandled version of GDALRasterIOExtraArg");
3169 0 : return CE_Failure;
3170 : }
3171 :
3172 736500 : GDALRasterIOExtraArgSetResampleAlg(psExtraArg, nXSize, nYSize, nBufXSize,
3173 : nBufYSize);
3174 :
3175 736500 : if (CPL_UNLIKELY(nullptr == pData))
3176 : {
3177 0 : ReportError(CE_Failure, CPLE_AppDefined,
3178 : "The buffer into which the data should be read is null");
3179 0 : return CE_Failure;
3180 : }
3181 :
3182 : /* -------------------------------------------------------------------- */
3183 : /* Do some validation of parameters. */
3184 : /* -------------------------------------------------------------------- */
3185 :
3186 736500 : if (CPL_UNLIKELY(eRWFlag != GF_Read && eRWFlag != GF_Write))
3187 : {
3188 0 : ReportError(
3189 : CE_Failure, CPLE_IllegalArg,
3190 : "eRWFlag = %d, only GF_Read (0) and GF_Write (1) are legal.",
3191 : eRWFlag);
3192 0 : return CE_Failure;
3193 : }
3194 :
3195 736500 : if (eRWFlag == GF_Write)
3196 : {
3197 216627 : if (CPL_UNLIKELY(eAccess != GA_Update))
3198 : {
3199 2 : ReportError(CE_Failure, CPLE_AppDefined,
3200 : "Write operation not permitted on dataset opened "
3201 : "in read-only mode");
3202 2 : return CE_Failure;
3203 : }
3204 : }
3205 :
3206 736498 : int bStopProcessing = FALSE;
3207 736498 : CPLErr eErr = ValidateRasterIOOrAdviseReadParameters(
3208 : "RasterIO()", &bStopProcessing, nXOff, nYOff, nXSize, nYSize, nBufXSize,
3209 : nBufYSize, nBandCount, panBandMap);
3210 736498 : if (eErr != CE_None || bStopProcessing)
3211 9 : return eErr;
3212 736489 : if (CPL_UNLIKELY(eBufType == GDT_Unknown || eBufType == GDT_TypeCount))
3213 : {
3214 2 : ReportError(CE_Failure, CPLE_AppDefined,
3215 : "Illegal GDT_Unknown/GDT_TypeCount argument");
3216 2 : return CE_Failure;
3217 : }
3218 :
3219 : /* -------------------------------------------------------------------- */
3220 : /* If pixel and line spacing are defaulted assign reasonable */
3221 : /* value assuming a packed buffer. */
3222 : /* -------------------------------------------------------------------- */
3223 736487 : if (nPixelSpace == 0)
3224 425262 : nPixelSpace = GDALGetDataTypeSizeBytes(eBufType);
3225 :
3226 736487 : if (nLineSpace == 0)
3227 : {
3228 482577 : nLineSpace = nPixelSpace * nBufXSize;
3229 : }
3230 :
3231 736487 : if (nBandSpace == 0 && nBandCount > 1)
3232 : {
3233 67390 : nBandSpace = nLineSpace * nBufYSize;
3234 : }
3235 :
3236 736487 : if (panBandMap == nullptr)
3237 : {
3238 356324 : if (!m_poPrivate)
3239 0 : return CE_Failure;
3240 356324 : CPLAssert(static_cast<int>(m_poPrivate->m_anBandMap.size()) == nBands);
3241 356324 : panBandMap = m_poPrivate->m_anBandMap.data();
3242 : }
3243 :
3244 736487 : int bCallLeaveReadWrite = EnterReadWrite(eRWFlag);
3245 :
3246 : /* -------------------------------------------------------------------- */
3247 : /* We are being forced to use cached IO instead of a driver */
3248 : /* specific implementation. */
3249 : /* -------------------------------------------------------------------- */
3250 736487 : if (bForceCachedIO)
3251 : {
3252 21 : eErr = BlockBasedRasterIO(eRWFlag, nXOff, nYOff, nXSize, nYSize, pData,
3253 : nBufXSize, nBufYSize, eBufType, nBandCount,
3254 : panBandMap, nPixelSpace, nLineSpace,
3255 21 : nBandSpace, psExtraArg);
3256 : }
3257 :
3258 : /* -------------------------------------------------------------------- */
3259 : /* Call the format specific function. */
3260 : /* -------------------------------------------------------------------- */
3261 : else
3262 : {
3263 736466 : eErr = IRasterIO(eRWFlag, nXOff, nYOff, nXSize, nYSize, pData,
3264 : nBufXSize, nBufYSize, eBufType, nBandCount,
3265 : // TODO: remove this const_cast once IRasterIO()
3266 : // takes a const int*
3267 : const_cast<int *>(panBandMap), nPixelSpace, nLineSpace,
3268 736466 : nBandSpace, psExtraArg);
3269 : }
3270 :
3271 736487 : if (bCallLeaveReadWrite)
3272 413590 : LeaveReadWrite();
3273 :
3274 736487 : return eErr;
3275 : }
3276 :
3277 : /************************************************************************/
3278 : /* GDALDatasetRasterIO() */
3279 : /************************************************************************/
3280 :
3281 : /**
3282 : * \brief Read/write a region of image data from multiple bands.
3283 : *
3284 : * Use GDALDatasetRasterIOEx() if 64 bit spacings or extra arguments (resampling
3285 : * resolution, progress callback, etc. are needed)
3286 : *
3287 : * Note: before GDAL 3.10, panBandMap type was "int*", and not "const int*"
3288 : *
3289 : * @see GDALDataset::RasterIO()
3290 : */
3291 :
3292 4762 : CPLErr CPL_STDCALL GDALDatasetRasterIO(GDALDatasetH hDS, GDALRWFlag eRWFlag,
3293 : int nXOff, int nYOff, int nXSize,
3294 : int nYSize, void *pData, int nBufXSize,
3295 : int nBufYSize, GDALDataType eBufType,
3296 : int nBandCount, const int *panBandMap,
3297 : int nPixelSpace, int nLineSpace,
3298 : int nBandSpace)
3299 :
3300 : {
3301 4762 : VALIDATE_POINTER1(hDS, "GDALDatasetRasterIO", CE_Failure);
3302 :
3303 4762 : GDALDataset *poDS = GDALDataset::FromHandle(hDS);
3304 :
3305 4762 : return poDS->RasterIO(eRWFlag, nXOff, nYOff, nXSize, nYSize, pData,
3306 : nBufXSize, nBufYSize, eBufType, nBandCount,
3307 : panBandMap, nPixelSpace, nLineSpace, nBandSpace,
3308 4762 : nullptr);
3309 : }
3310 :
3311 : /************************************************************************/
3312 : /* GDALDatasetRasterIOEx() */
3313 : /************************************************************************/
3314 :
3315 : /**
3316 : * \brief Read/write a region of image data from multiple bands.
3317 : *
3318 : * Note: before GDAL 3.10, panBandMap type was "int*", and not "const int*"
3319 : *
3320 : * @see GDALDataset::RasterIO()
3321 : */
3322 :
3323 353662 : CPLErr CPL_STDCALL GDALDatasetRasterIOEx(
3324 : GDALDatasetH hDS, GDALRWFlag eRWFlag, int nXOff, int nYOff, int nXSize,
3325 : int nYSize, void *pData, int nBufXSize, int nBufYSize,
3326 : GDALDataType eBufType, int nBandCount, const int *panBandMap,
3327 : GSpacing nPixelSpace, GSpacing nLineSpace, GSpacing nBandSpace,
3328 : GDALRasterIOExtraArg *psExtraArg)
3329 :
3330 : {
3331 353662 : VALIDATE_POINTER1(hDS, "GDALDatasetRasterIOEx", CE_Failure);
3332 :
3333 353662 : GDALDataset *poDS = GDALDataset::FromHandle(hDS);
3334 :
3335 353662 : return poDS->RasterIO(eRWFlag, nXOff, nYOff, nXSize, nYSize, pData,
3336 : nBufXSize, nBufYSize, eBufType, nBandCount,
3337 : panBandMap, nPixelSpace, nLineSpace, nBandSpace,
3338 353662 : psExtraArg);
3339 : }
3340 :
3341 : /************************************************************************/
3342 : /* GetOpenDatasets() */
3343 : /************************************************************************/
3344 :
3345 : /**
3346 : * \brief Fetch all open GDAL dataset handles.
3347 : *
3348 : * This method is the same as the C function GDALGetOpenDatasets().
3349 : *
3350 : * NOTE: This method is not thread safe. The returned list may change
3351 : * at any time and it should not be freed.
3352 : *
3353 : * @param pnCount integer into which to place the count of dataset pointers
3354 : * being returned.
3355 : *
3356 : * @return a pointer to an array of dataset handles.
3357 : */
3358 :
3359 2277 : GDALDataset **GDALDataset::GetOpenDatasets(int *pnCount)
3360 :
3361 : {
3362 4554 : CPLMutexHolderD(&hDLMutex);
3363 :
3364 2277 : if (poAllDatasetMap == nullptr)
3365 : {
3366 2256 : *pnCount = 0;
3367 2256 : return nullptr;
3368 : }
3369 :
3370 21 : *pnCount = static_cast<int>(poAllDatasetMap->size());
3371 21 : ppDatasets = static_cast<GDALDataset **>(
3372 21 : CPLRealloc(ppDatasets, (*pnCount) * sizeof(GDALDataset *)));
3373 21 : std::map<GDALDataset *, GIntBig>::iterator oIter = poAllDatasetMap->begin();
3374 591 : for (int i = 0; oIter != poAllDatasetMap->end(); ++oIter, ++i)
3375 570 : ppDatasets[i] = oIter->first;
3376 21 : return ppDatasets;
3377 : }
3378 :
3379 : /************************************************************************/
3380 : /* GDALGetOpenDatasets() */
3381 : /************************************************************************/
3382 :
3383 : /**
3384 : * \brief Fetch all open GDAL dataset handles.
3385 : *
3386 : * @see GDALDataset::GetOpenDatasets()
3387 : */
3388 :
3389 0 : void CPL_STDCALL GDALGetOpenDatasets(GDALDatasetH **ppahDSList, int *pnCount)
3390 :
3391 : {
3392 0 : VALIDATE_POINTER0(ppahDSList, "GDALGetOpenDatasets");
3393 0 : VALIDATE_POINTER0(pnCount, "GDALGetOpenDatasets");
3394 :
3395 0 : *ppahDSList =
3396 0 : reinterpret_cast<GDALDatasetH *>(GDALDataset::GetOpenDatasets(pnCount));
3397 : }
3398 :
3399 : /************************************************************************/
3400 : /* GDALCleanOpenDatasetsList() */
3401 : /************************************************************************/
3402 :
3403 : // Useful when called from the child of a fork(), to avoid closing
3404 : // the datasets of the parent at the child termination.
3405 0 : void GDALNullifyOpenDatasetsList()
3406 : {
3407 0 : poAllDatasetMap = nullptr;
3408 0 : phSharedDatasetSet = nullptr;
3409 0 : ppDatasets = nullptr;
3410 0 : hDLMutex = nullptr;
3411 0 : }
3412 :
3413 : /************************************************************************/
3414 : /* GDALGetAccess() */
3415 : /************************************************************************/
3416 :
3417 : /**
3418 : * \brief Return access flag
3419 : *
3420 : * @see GDALDataset::GetAccess()
3421 : */
3422 :
3423 1 : int CPL_STDCALL GDALGetAccess(GDALDatasetH hDS)
3424 : {
3425 1 : VALIDATE_POINTER1(hDS, "GDALGetAccess", 0);
3426 :
3427 1 : return GDALDataset::FromHandle(hDS)->GetAccess();
3428 : }
3429 :
3430 : /************************************************************************/
3431 : /* AdviseRead() */
3432 : /************************************************************************/
3433 :
3434 : /**
3435 : * \brief Advise driver of upcoming read requests.
3436 : *
3437 : * Some GDAL drivers operate more efficiently if they know in advance what
3438 : * set of upcoming read requests will be made. The AdviseRead() method allows
3439 : * an application to notify the driver of the region and bands of interest,
3440 : * and at what resolution the region will be read.
3441 : *
3442 : * Many drivers just ignore the AdviseRead() call, but it can dramatically
3443 : * accelerate access via some drivers.
3444 : *
3445 : * Depending on call paths, drivers might receive several calls to
3446 : * AdviseRead() with the same parameters.
3447 : *
3448 : * @param nXOff The pixel offset to the top left corner of the region
3449 : * of the band to be accessed. This would be zero to start from the left side.
3450 : *
3451 : * @param nYOff The line offset to the top left corner of the region
3452 : * of the band to be accessed. This would be zero to start from the top.
3453 : *
3454 : * @param nXSize The width of the region of the band to be accessed in pixels.
3455 : *
3456 : * @param nYSize The height of the region of the band to be accessed in lines.
3457 : *
3458 : * @param nBufXSize the width of the buffer image into which the desired region
3459 : * is to be read, or from which it is to be written.
3460 : *
3461 : * @param nBufYSize the height of the buffer image into which the desired
3462 : * region is to be read, or from which it is to be written.
3463 : *
3464 : * @param eBufType the type of the pixel values in the pData data buffer. The
3465 : * pixel values will automatically be translated to/from the GDALRasterBand
3466 : * data type as needed.
3467 : *
3468 : * @param nBandCount the number of bands being read or written.
3469 : *
3470 : * @param panBandMap the list of nBandCount band numbers being read/written.
3471 : * Note band numbers are 1 based. This may be NULL to select the first
3472 : * nBandCount bands.
3473 : *
3474 : * @param papszOptions a list of name=value strings with special control
3475 : * options. Normally this is NULL.
3476 : *
3477 : * @return CE_Failure if the request is invalid and CE_None if it works or
3478 : * is ignored.
3479 : */
3480 :
3481 15262 : CPLErr GDALDataset::AdviseRead(int nXOff, int nYOff, int nXSize, int nYSize,
3482 : int nBufXSize, int nBufYSize,
3483 : GDALDataType eBufType, int nBandCount,
3484 : int *panBandMap, CSLConstList papszOptions)
3485 :
3486 : {
3487 : /* -------------------------------------------------------------------- */
3488 : /* Do some validation of parameters. */
3489 : /* -------------------------------------------------------------------- */
3490 15262 : int bStopProcessing = FALSE;
3491 15262 : CPLErr eErr = ValidateRasterIOOrAdviseReadParameters(
3492 : "AdviseRead()", &bStopProcessing, nXOff, nYOff, nXSize, nYSize,
3493 : nBufXSize, nBufYSize, nBandCount, panBandMap);
3494 15262 : if (eErr != CE_None || bStopProcessing)
3495 23 : return eErr;
3496 :
3497 129828 : for (int iBand = 0; iBand < nBandCount; ++iBand)
3498 : {
3499 114593 : GDALRasterBand *poBand = nullptr;
3500 :
3501 114593 : if (panBandMap == nullptr)
3502 113106 : poBand = GetRasterBand(iBand + 1);
3503 : else
3504 1487 : poBand = GetRasterBand(panBandMap[iBand]);
3505 :
3506 114593 : if (poBand == nullptr)
3507 0 : return CE_Failure;
3508 :
3509 229186 : eErr = poBand->AdviseRead(nXOff, nYOff, nXSize, nYSize, nBufXSize,
3510 114593 : nBufYSize, eBufType, papszOptions);
3511 :
3512 114593 : if (eErr != CE_None)
3513 4 : return eErr;
3514 : }
3515 :
3516 15235 : return CE_None;
3517 : }
3518 :
3519 : /************************************************************************/
3520 : /* GDALDatasetAdviseRead() */
3521 : /************************************************************************/
3522 :
3523 : /**
3524 : * \brief Advise driver of upcoming read requests.
3525 : *
3526 : * @see GDALDataset::AdviseRead()
3527 : */
3528 7 : CPLErr CPL_STDCALL GDALDatasetAdviseRead(GDALDatasetH hDS, int nXOff, int nYOff,
3529 : int nXSize, int nYSize, int nBufXSize,
3530 : int nBufYSize, GDALDataType eDT,
3531 : int nBandCount, int *panBandMap,
3532 : CSLConstList papszOptions)
3533 :
3534 : {
3535 7 : VALIDATE_POINTER1(hDS, "GDALDatasetAdviseRead", CE_Failure);
3536 :
3537 14 : return GDALDataset::FromHandle(hDS)->AdviseRead(
3538 : nXOff, nYOff, nXSize, nYSize, nBufXSize, nBufYSize, eDT, nBandCount,
3539 7 : panBandMap, const_cast<char **>(papszOptions));
3540 : }
3541 :
3542 : /************************************************************************/
3543 : /* GDALAntiRecursionStruct */
3544 : /************************************************************************/
3545 :
3546 : // Prevent infinite recursion.
3547 : struct GDALAntiRecursionStruct
3548 : {
3549 : struct DatasetContext
3550 : {
3551 : std::string osFilename;
3552 : int nOpenFlags;
3553 : std::string osAllowedDrivers;
3554 :
3555 86813 : DatasetContext(const std::string &osFilenameIn, int nOpenFlagsIn,
3556 : const std::string &osAllowedDriversIn)
3557 86813 : : osFilename(osFilenameIn), nOpenFlags(nOpenFlagsIn),
3558 86813 : osAllowedDrivers(osAllowedDriversIn)
3559 : {
3560 86813 : }
3561 : };
3562 :
3563 : struct DatasetContextCompare
3564 : {
3565 1076350 : bool operator()(const DatasetContext &lhs,
3566 : const DatasetContext &rhs) const
3567 : {
3568 3152950 : return lhs.osFilename < rhs.osFilename ||
3569 1045130 : (lhs.osFilename == rhs.osFilename &&
3570 1031470 : (lhs.nOpenFlags < rhs.nOpenFlags ||
3571 2046580 : (lhs.nOpenFlags == rhs.nOpenFlags &&
3572 2097590 : lhs.osAllowedDrivers < rhs.osAllowedDrivers)));
3573 : }
3574 : };
3575 :
3576 1389 : ~GDALAntiRecursionStruct()
3577 1389 : {
3578 1389 : CPLAssert(aosDatasetNamesWithFlags.empty());
3579 1389 : CPLAssert(nRecLevel == 0);
3580 1389 : CPLAssert(m_oMapDepth.empty());
3581 1389 : }
3582 :
3583 : std::set<DatasetContext, DatasetContextCompare> aosDatasetNamesWithFlags{};
3584 : int nRecLevel = 0;
3585 : std::map<std::string, int> m_oMapDepth{};
3586 : };
3587 :
3588 : #ifdef _WIN32
3589 : // Currently thread_local and C++ objects don't work well with DLL on Windows
3590 : static void FreeAntiRecursionOpen(void *pData)
3591 : {
3592 : delete static_cast<GDALAntiRecursionStruct *>(pData);
3593 : }
3594 :
3595 : static GDALAntiRecursionStruct &GetAntiRecursionOpen()
3596 : {
3597 : static GDALAntiRecursionStruct dummy;
3598 : int bMemoryErrorOccurred = false;
3599 : void *pData =
3600 : CPLGetTLSEx(CTLS_GDALOPEN_ANTIRECURSION, &bMemoryErrorOccurred);
3601 : if (bMemoryErrorOccurred)
3602 : {
3603 : return dummy;
3604 : }
3605 : if (pData == nullptr)
3606 : {
3607 : auto pAntiRecursion = new GDALAntiRecursionStruct();
3608 : CPLSetTLSWithFreeFuncEx(CTLS_GDALOPEN_ANTIRECURSION, pAntiRecursion,
3609 : FreeAntiRecursionOpen, &bMemoryErrorOccurred);
3610 : if (bMemoryErrorOccurred)
3611 : {
3612 : delete pAntiRecursion;
3613 : return dummy;
3614 : }
3615 : return *pAntiRecursion;
3616 : }
3617 : return *static_cast<GDALAntiRecursionStruct *>(pData);
3618 : }
3619 : #else
3620 : static thread_local GDALAntiRecursionStruct g_tls_antiRecursion;
3621 :
3622 376458 : static GDALAntiRecursionStruct &GetAntiRecursionOpen()
3623 : {
3624 376458 : return g_tls_antiRecursion;
3625 : }
3626 : #endif
3627 :
3628 : //! @cond Doxygen_Suppress
3629 289645 : GDALAntiRecursionGuard::GDALAntiRecursionGuard(const std::string &osIdentifier)
3630 289645 : : m_psAntiRecursionStruct(&GetAntiRecursionOpen()),
3631 : m_osIdentifier(osIdentifier),
3632 289645 : m_nDepth(++m_psAntiRecursionStruct->m_oMapDepth[m_osIdentifier])
3633 : {
3634 289645 : CPLAssert(!osIdentifier.empty());
3635 289645 : }
3636 :
3637 289645 : GDALAntiRecursionGuard::GDALAntiRecursionGuard(
3638 289645 : const GDALAntiRecursionGuard &other, const std::string &osIdentifier)
3639 289645 : : m_psAntiRecursionStruct(other.m_psAntiRecursionStruct),
3640 289645 : m_osIdentifier(osIdentifier.empty()
3641 : ? osIdentifier
3642 31138 : : other.m_osIdentifier + osIdentifier),
3643 289645 : m_nDepth(m_osIdentifier.empty()
3644 289645 : ? 0
3645 320783 : : ++m_psAntiRecursionStruct->m_oMapDepth[m_osIdentifier])
3646 : {
3647 289645 : }
3648 :
3649 579290 : GDALAntiRecursionGuard::~GDALAntiRecursionGuard()
3650 : {
3651 579290 : if (!m_osIdentifier.empty())
3652 : {
3653 320783 : auto oIter = m_psAntiRecursionStruct->m_oMapDepth.find(m_osIdentifier);
3654 320783 : CPLAssert(oIter != m_psAntiRecursionStruct->m_oMapDepth.end());
3655 320783 : if (--(oIter->second) == 0)
3656 316326 : m_psAntiRecursionStruct->m_oMapDepth.erase(oIter);
3657 : }
3658 579290 : }
3659 :
3660 : //! @endcond
3661 :
3662 : /************************************************************************/
3663 : /* GetFileList() */
3664 : /************************************************************************/
3665 :
3666 : /**
3667 : * \brief Fetch files forming dataset.
3668 : *
3669 : * Returns a list of files believed to be part of this dataset. If it returns
3670 : * an empty list of files it means there is believed to be no local file
3671 : * system files associated with the dataset (for instance a virtual dataset).
3672 : * The returned file list is owned by the caller and should be deallocated
3673 : * with CSLDestroy().
3674 : *
3675 : * The returned filenames will normally be relative or absolute paths
3676 : * depending on the path used to originally open the dataset. The strings
3677 : * will be UTF-8 encoded.
3678 : *
3679 : * This method is the same as the C GDALGetFileList() function.
3680 : *
3681 : * @return NULL or a NULL terminated array of file names.
3682 : */
3683 :
3684 4730 : char **GDALDataset::GetFileList()
3685 :
3686 : {
3687 9460 : CPLString osMainFilename = GetDescription();
3688 : VSIStatBufL sStat;
3689 :
3690 4730 : GDALAntiRecursionStruct &sAntiRecursion = GetAntiRecursionOpen();
3691 : GDALAntiRecursionStruct::DatasetContext datasetCtxt(osMainFilename, 0,
3692 9460 : std::string());
3693 4730 : auto &aosDatasetList = sAntiRecursion.aosDatasetNamesWithFlags;
3694 4730 : if (cpl::contains(aosDatasetList, datasetCtxt))
3695 0 : return nullptr;
3696 :
3697 : /* -------------------------------------------------------------------- */
3698 : /* Is the main filename even a real filesystem object? */
3699 : /* -------------------------------------------------------------------- */
3700 : int bMainFileReal =
3701 4730 : VSIStatExL(osMainFilename, &sStat, VSI_STAT_EXISTS_FLAG) == 0;
3702 :
3703 : /* -------------------------------------------------------------------- */
3704 : /* Form new list. */
3705 : /* -------------------------------------------------------------------- */
3706 4730 : char **papszList = nullptr;
3707 :
3708 4730 : if (bMainFileReal)
3709 4650 : papszList = CSLAddString(papszList, osMainFilename);
3710 :
3711 4730 : if (sAntiRecursion.nRecLevel == 100)
3712 : {
3713 0 : CPLError(CE_Failure, CPLE_AppDefined,
3714 : "GetFileList() called with too many recursion levels");
3715 0 : return papszList;
3716 : }
3717 4730 : ++sAntiRecursion.nRecLevel;
3718 :
3719 : /* -------------------------------------------------------------------- */
3720 : /* Do we have a known overview file? */
3721 : /* -------------------------------------------------------------------- */
3722 4730 : if (oOvManager.IsInitialized() && oOvManager.poODS != nullptr)
3723 : {
3724 60 : auto iter = aosDatasetList.insert(datasetCtxt).first;
3725 60 : char **papszOvrList = oOvManager.poODS->GetFileList();
3726 60 : papszList = CSLInsertStrings(papszList, -1, papszOvrList);
3727 60 : CSLDestroy(papszOvrList);
3728 60 : aosDatasetList.erase(iter);
3729 : }
3730 :
3731 : /* -------------------------------------------------------------------- */
3732 : /* Do we have a known mask file? */
3733 : /* -------------------------------------------------------------------- */
3734 4730 : if (oOvManager.HaveMaskFile())
3735 : {
3736 9 : auto iter = aosDatasetList.insert(std::move(datasetCtxt)).first;
3737 9 : for (const char *pszFile :
3738 18 : CPLStringList(oOvManager.poMaskDS->GetFileList()))
3739 : {
3740 9 : if (CSLFindString(papszList, pszFile) < 0)
3741 9 : papszList = CSLAddString(papszList, pszFile);
3742 : }
3743 9 : aosDatasetList.erase(iter);
3744 : }
3745 :
3746 4730 : --sAntiRecursion.nRecLevel;
3747 :
3748 4730 : return papszList;
3749 : }
3750 :
3751 : /************************************************************************/
3752 : /* GDALGetFileList() */
3753 : /************************************************************************/
3754 :
3755 : /**
3756 : * \brief Fetch files forming dataset.
3757 : *
3758 : * @see GDALDataset::GetFileList()
3759 : */
3760 :
3761 3729 : char **CPL_STDCALL GDALGetFileList(GDALDatasetH hDS)
3762 :
3763 : {
3764 3729 : VALIDATE_POINTER1(hDS, "GDALGetFileList", nullptr);
3765 :
3766 3729 : return GDALDataset::FromHandle(hDS)->GetFileList();
3767 : }
3768 :
3769 : /************************************************************************/
3770 : /* CreateMaskBand() */
3771 : /************************************************************************/
3772 :
3773 : /**
3774 : * \brief Adds a mask band to the dataset
3775 : *
3776 : * The default implementation of the CreateMaskBand() method is implemented
3777 : * based on similar rules to the .ovr handling implemented using the
3778 : * GDALDefaultOverviews object. A TIFF file with the extension .msk will
3779 : * be created with the same basename as the original file, and it will have
3780 : * one band.
3781 : * The mask images will be deflate compressed tiled images with the same
3782 : * block size as the original image if possible.
3783 : * It will have INTERNAL_MASK_FLAGS_xx metadata items set at the dataset
3784 : * level, where xx matches the band number of a band of the main dataset. The
3785 : * value of those items will be the one of the nFlagsIn parameter.
3786 : *
3787 : * Note that if you got a mask band with a previous call to GetMaskBand(), it
3788 : * might be invalidated by CreateMaskBand(). So you have to call GetMaskBand()
3789 : * again.
3790 : *
3791 : *
3792 : * @param nFlagsIn 0 or combination of GMF_PER_DATASET / GMF_ALPHA.
3793 : * GMF_PER_DATASET will be always set, even if not explicitly
3794 : * specified.
3795 : * @return CE_None on success or CE_Failure on an error.
3796 : *
3797 : * @see https://gdal.org/development/rfc/rfc15_nodatabitmask.html
3798 : * @see GDALRasterBand::CreateMaskBand()
3799 : *
3800 : */
3801 17 : CPLErr GDALDataset::CreateMaskBand(int nFlagsIn)
3802 :
3803 : {
3804 17 : if (oOvManager.IsInitialized())
3805 : {
3806 17 : CPLErr eErr = oOvManager.CreateMaskBand(nFlagsIn, -1);
3807 17 : if (eErr != CE_None)
3808 0 : return eErr;
3809 :
3810 : // Invalidate existing raster band masks.
3811 45 : for (int i = 0; i < nBands; ++i)
3812 : {
3813 28 : GDALRasterBand *poBand = papoBands[i];
3814 28 : poBand->poMask.reset();
3815 : }
3816 :
3817 17 : return CE_None;
3818 : }
3819 :
3820 0 : ReportError(CE_Failure, CPLE_NotSupported,
3821 : "CreateMaskBand() not supported for this dataset.");
3822 :
3823 0 : return CE_Failure;
3824 : }
3825 :
3826 : /************************************************************************/
3827 : /* GDALCreateDatasetMaskBand() */
3828 : /************************************************************************/
3829 :
3830 : /**
3831 : * \brief Adds a mask band to the dataset
3832 : * @see GDALDataset::CreateMaskBand()
3833 : */
3834 107 : CPLErr CPL_STDCALL GDALCreateDatasetMaskBand(GDALDatasetH hDS, int nFlags)
3835 :
3836 : {
3837 107 : VALIDATE_POINTER1(hDS, "GDALCreateDatasetMaskBand", CE_Failure);
3838 :
3839 107 : return GDALDataset::FromHandle(hDS)->CreateMaskBand(nFlags);
3840 : }
3841 :
3842 : /************************************************************************/
3843 : /* GDALOpen() */
3844 : /************************************************************************/
3845 :
3846 : /**
3847 : * \brief Open a raster file as a GDALDataset.
3848 : *
3849 : * This function will try to open the passed file, or virtual dataset
3850 : * name by invoking the Open method of each registered GDALDriver in turn.
3851 : * The first successful open will result in a returned dataset. If all
3852 : * drivers fail then NULL is returned and an error is issued.
3853 : *
3854 : * Several recommendations :
3855 : * <ul>
3856 : * <li>If you open a dataset object with GA_Update access, it is not recommended
3857 : * to open a new dataset on the same underlying file.</li>
3858 : * <li>The returned dataset should only be accessed by one thread at a time. If
3859 : * you want to use it from different threads, you must add all necessary code
3860 : * (mutexes, etc.) to avoid concurrent use of the object. (Some drivers, such
3861 : * as GeoTIFF, maintain internal state variables that are updated each time a
3862 : * new block is read, thus preventing concurrent use.) </li>
3863 : * </ul>
3864 : *
3865 : * For drivers supporting the VSI virtual file API, it is possible to open a
3866 : * file in a .zip archive (see VSIInstallZipFileHandler()), in a
3867 : * .tar/.tar.gz/.tgz archive (see VSIInstallTarFileHandler()) or on a HTTP / FTP
3868 : * server (see VSIInstallCurlFileHandler())
3869 : *
3870 : * \sa GDALOpenShared()
3871 : * \sa GDALOpenEx()
3872 : *
3873 : * @param pszFilename the name of the file to access. In the case of
3874 : * exotic drivers this may not refer to a physical file, but instead contain
3875 : * information for the driver on how to access a dataset. It should be in UTF-8
3876 : * encoding.
3877 : *
3878 : * @param eAccess the desired access, either GA_Update or GA_ReadOnly. Many
3879 : * drivers support only read only access.
3880 : *
3881 : * @return A GDALDatasetH handle or NULL on failure. For C++ applications
3882 : * this handle can be cast to a GDALDataset *.
3883 : */
3884 :
3885 26662 : GDALDatasetH CPL_STDCALL GDALOpen(const char *pszFilename, GDALAccess eAccess)
3886 :
3887 : {
3888 26662 : const int nUpdateFlag = eAccess == GA_Update ? GDAL_OF_UPDATE : 0;
3889 26662 : const int nOpenFlags = GDAL_OF_RASTER | nUpdateFlag | GDAL_OF_VERBOSE_ERROR;
3890 : GDALDatasetH hDataset =
3891 26662 : GDALOpenEx(pszFilename, nOpenFlags, nullptr, nullptr, nullptr);
3892 26662 : return hDataset;
3893 : }
3894 :
3895 : /************************************************************************/
3896 : /* GetSharedDS() */
3897 : /************************************************************************/
3898 :
3899 6490 : static GDALDataset *GetSharedDS(const char *pszFilename,
3900 : unsigned int nOpenFlags,
3901 : const char *const *papszOpenOptions)
3902 : {
3903 12980 : CPLMutexHolderD(&hDLMutex);
3904 :
3905 6490 : if (phSharedDatasetSet != nullptr)
3906 : {
3907 6230 : const GIntBig nThisPID = GDALGetResponsiblePIDForCurrentThread();
3908 : SharedDatasetCtxt sStruct;
3909 :
3910 6230 : sStruct.nPID = nThisPID;
3911 6230 : sStruct.pszDescription = const_cast<char *>(pszFilename);
3912 6230 : sStruct.nOpenFlags = nOpenFlags & ~GDAL_OF_SHARED;
3913 : std::string osConcatenatedOpenOptions =
3914 6230 : GDALSharedDatasetConcatenateOpenOptions(papszOpenOptions);
3915 6230 : sStruct.pszConcatenatedOpenOptions = &osConcatenatedOpenOptions[0];
3916 6230 : sStruct.poDS = nullptr;
3917 : SharedDatasetCtxt *psStruct = static_cast<SharedDatasetCtxt *>(
3918 6230 : CPLHashSetLookup(phSharedDatasetSet, &sStruct));
3919 6230 : if (psStruct == nullptr && (nOpenFlags & GDAL_OF_UPDATE) == 0)
3920 : {
3921 124 : sStruct.nOpenFlags |= GDAL_OF_UPDATE;
3922 : psStruct = static_cast<SharedDatasetCtxt *>(
3923 124 : CPLHashSetLookup(phSharedDatasetSet, &sStruct));
3924 : }
3925 6230 : if (psStruct)
3926 : {
3927 6107 : return psStruct->poDS;
3928 : }
3929 : }
3930 383 : return nullptr;
3931 : }
3932 :
3933 : /************************************************************************/
3934 : /* GDALOpenEx() */
3935 : /************************************************************************/
3936 :
3937 : /**
3938 : * \brief Open a raster or vector file as a GDALDataset.
3939 : *
3940 : * This function will try to open the passed file, or virtual dataset
3941 : * name by invoking the Open method of each registered GDALDriver in turn.
3942 : * The first successful open will result in a returned dataset. If all
3943 : * drivers fail then NULL is returned and an error is issued.
3944 : *
3945 : * Several recommendations :
3946 : * <ul>
3947 : * <li>If you open a dataset object with GDAL_OF_UPDATE access, it is not
3948 : * recommended to open a new dataset on the same underlying file.</li>
3949 : * <li>The returned dataset should only be accessed by one thread at a time. If
3950 : * you want to use it from different threads, you must add all necessary code
3951 : * (mutexes, etc.) to avoid concurrent use of the object. (Some drivers, such
3952 : * as GeoTIFF, maintain internal state variables that are updated each time a
3953 : * new block is read, thus preventing concurrent use.) </li>
3954 : * </ul>
3955 : *
3956 : * For drivers supporting the VSI virtual file API, it is possible to open a
3957 : * file in a .zip archive (see VSIInstallZipFileHandler()), in a
3958 : * .tar/.tar.gz/.tgz archive (see VSIInstallTarFileHandler()) or on a HTTP / FTP
3959 : * server (see VSIInstallCurlFileHandler())
3960 : *
3961 : * In order to reduce the need for searches through the operating system
3962 : * file system machinery, it is possible to give an optional list of files with
3963 : * the papszSiblingFiles parameter.
3964 : * This is the list of all files at the same level in the file system as the
3965 : * target file, including the target file. The filenames must not include any
3966 : * path components, are essentially just the output of VSIReadDir() on the
3967 : * parent directory. If the target object does not have filesystem semantics
3968 : * then the file list should be NULL.
3969 : *
3970 : * @param pszFilename the name of the file to access. In the case of
3971 : * exotic drivers this may not refer to a physical file, but instead contain
3972 : * information for the driver on how to access a dataset. It should be in UTF-8
3973 : * encoding.
3974 : *
3975 : * @param nOpenFlags a combination of GDAL_OF_ flags that may be combined
3976 : * through logical or operator.
3977 : * <ul>
3978 : * <li>Driver kind:
3979 : * <ul>
3980 : * <li>GDAL_OF_RASTER for raster drivers,</li>
3981 : * <li>GDAL_OF_MULTIDIM_RASTER for multidimensional raster drivers,</li>
3982 : * <li>GDAL_OF_VECTOR for vector drivers,</li>
3983 : * <li>GDAL_OF_GNM for Geographic Network Model drivers.</li>
3984 : * </ul>
3985 : * GDAL_OF_RASTER and GDAL_OF_MULTIDIM_RASTER are generally mutually
3986 : * exclusive. If none of the value is specified, GDAL_OF_RASTER | GDAL_OF_VECTOR
3987 : * | GDAL_OF_GNM is implied.
3988 : * </li>
3989 : * <li>Access mode: GDAL_OF_READONLY (exclusive)or GDAL_OF_UPDATE.
3990 : * </li>
3991 : * <li>Shared mode: GDAL_OF_SHARED. If set,
3992 : * it allows the sharing of GDALDataset handles for a dataset with other callers
3993 : * that have set GDAL_OF_SHARED. In particular, GDALOpenEx() will first consult
3994 : * its list of currently open and shared GDALDataset's, and if the
3995 : * GetDescription() name for one exactly matches the pszFilename passed to
3996 : * GDALOpenEx() it will be referenced and returned, if GDALOpenEx() is called
3997 : * from the same thread.
3998 : * </li>
3999 : * <li>Thread safe mode: GDAL_OF_THREAD_SAFE (added in 3.10).
4000 : * This must be use in combination with GDAL_OF_RASTER, and is mutually
4001 : * exclusive with GDAL_OF_UPDATE, GDAL_OF_VECTOR, GDAL_OF_MULTIDIM_RASTER or
4002 : * GDAL_OF_GNM.
4003 : * </li>
4004 : * <li>Verbose error: GDAL_OF_VERBOSE_ERROR. If set,
4005 : * a failed attempt to open the file will lead to an error message to be
4006 : * reported.
4007 : * </li>
4008 : * </ul>
4009 : *
4010 : * @param papszAllowedDrivers NULL to consider all candidate drivers, or a NULL
4011 : * terminated list of strings with the driver short names that must be
4012 : * considered.
4013 : * Starting with GDAL 3.13, a string starting with the dash (-) character
4014 : * followed by the driver short name can be used to exclude a driver.
4015 : *
4016 : * @param papszOpenOptions NULL, or a NULL terminated list of strings with open
4017 : * options passed to candidate drivers. An option exists for all drivers,
4018 : * OVERVIEW_LEVEL=level, to select a particular overview level of a dataset.
4019 : * The level index starts at 0. The level number can be suffixed by "only" to
4020 : * specify that only this overview level must be visible, and not sub-levels.
4021 : * Open options are validated by default, and a warning is emitted in case the
4022 : * option is not recognized. In some scenarios, it might be not desirable (e.g.
4023 : * when not knowing which driver will open the file), so the special open option
4024 : * VALIDATE_OPEN_OPTIONS can be set to NO to avoid such warnings. Alternatively,
4025 : * that it may not cause a warning if the driver doesn't declare this option.
4026 : * Starting with GDAL 3.3, OVERVIEW_LEVEL=NONE is supported to indicate that
4027 : * no overviews should be exposed.
4028 : *
4029 : * @param papszSiblingFiles NULL, or a NULL terminated list of strings that are
4030 : * filenames that are auxiliary to the main filename. If NULL is passed, a
4031 : * probing of the file system will be done.
4032 : *
4033 : * @return A GDALDatasetH handle or NULL on failure. For C++ applications
4034 : * this handle can be cast to a GDALDataset *.
4035 : *
4036 : */
4037 :
4038 86199 : GDALDatasetH CPL_STDCALL GDALOpenEx(const char *pszFilename,
4039 : unsigned int nOpenFlags,
4040 : const char *const *papszAllowedDrivers,
4041 : const char *const *papszOpenOptions,
4042 : const char *const *papszSiblingFiles)
4043 : {
4044 86199 : VALIDATE_POINTER1(pszFilename, "GDALOpen", nullptr);
4045 :
4046 : // Do some sanity checks on incompatible flags with thread-safe mode.
4047 86199 : if ((nOpenFlags & GDAL_OF_THREAD_SAFE) != 0)
4048 : {
4049 : const struct
4050 : {
4051 : int nFlag;
4052 : const char *pszFlagName;
4053 128 : } asFlags[] = {
4054 : {GDAL_OF_UPDATE, "GDAL_OF_UPDATE"},
4055 : {GDAL_OF_VECTOR, "GDAL_OF_VECTOR"},
4056 : {GDAL_OF_MULTIDIM_RASTER, "GDAL_OF_MULTIDIM_RASTER"},
4057 : {GDAL_OF_GNM, "GDAL_OF_GNM"},
4058 : };
4059 :
4060 630 : for (const auto &asFlag : asFlags)
4061 : {
4062 506 : if ((nOpenFlags & asFlag.nFlag) != 0)
4063 : {
4064 4 : CPLError(CE_Failure, CPLE_IllegalArg,
4065 : "GDAL_OF_THREAD_SAFE and %s are mutually "
4066 : "exclusive",
4067 4 : asFlag.pszFlagName);
4068 4 : return nullptr;
4069 : }
4070 : }
4071 : }
4072 :
4073 : // If no driver kind is specified, assume all are to be probed.
4074 86195 : if ((nOpenFlags & GDAL_OF_KIND_MASK) == 0)
4075 7880 : nOpenFlags |= GDAL_OF_KIND_MASK & ~GDAL_OF_MULTIDIM_RASTER;
4076 :
4077 : /* -------------------------------------------------------------------- */
4078 : /* In case of shared dataset, first scan the existing list to see */
4079 : /* if it could already contain the requested dataset. */
4080 : /* -------------------------------------------------------------------- */
4081 86195 : if (nOpenFlags & GDAL_OF_SHARED)
4082 : {
4083 6490 : if (nOpenFlags & GDAL_OF_INTERNAL)
4084 : {
4085 0 : CPLError(CE_Failure, CPLE_IllegalArg,
4086 : "GDAL_OF_SHARED and GDAL_OF_INTERNAL are exclusive");
4087 0 : return nullptr;
4088 : }
4089 :
4090 : auto poSharedDS =
4091 6490 : GetSharedDS(pszFilename, nOpenFlags, papszOpenOptions);
4092 6490 : if (poSharedDS)
4093 : {
4094 6107 : poSharedDS->Reference();
4095 6107 : return poSharedDS;
4096 : }
4097 : }
4098 :
4099 80088 : CPLErrorReset();
4100 80088 : VSIErrorReset();
4101 :
4102 : // Build GDALOpenInfo just now to avoid useless file stat'ing if a
4103 : // shared dataset was asked before.
4104 80088 : GDALOpenInfo oOpenInfo(pszFilename, nOpenFlags, papszSiblingFiles);
4105 :
4106 160176 : return GDALDataset::Open(&oOpenInfo, papszAllowedDrivers, papszOpenOptions)
4107 80088 : .release();
4108 : }
4109 :
4110 : /************************************************************************/
4111 : /* GDALDataset::Open() */
4112 : /************************************************************************/
4113 :
4114 : /**
4115 : * \brief Open a raster or vector file as a GDALDataset.
4116 : *
4117 : * This function will use the passed open info on each registered GDALDriver in
4118 : * turn.
4119 : * The first successful open will result in a returned dataset. If all
4120 : * drivers fail then NULL is returned and an error is issued.
4121 : *
4122 : * Several recommendations :
4123 : * <ul>
4124 : * <li>If you open a dataset object with GDAL_OF_UPDATE access, it is not
4125 : * recommended to open a new dataset on the same underlying file.</li>
4126 : * <li>The returned dataset should only be accessed by one thread at a time. If
4127 : * you want to use it from different threads, you must add all necessary code
4128 : * (mutexes, etc.) to avoid concurrent use of the object. (Some drivers, such
4129 : * as GeoTIFF, maintain internal state variables that are updated each time a
4130 : * new block is read, thus preventing concurrent use.) </li>
4131 : * </ul>
4132 : *
4133 : * For drivers supporting the VSI virtual file API, it is possible to open a
4134 : * file in a .zip archive (see VSIInstallZipFileHandler()), in a
4135 : * .tar/.tar.gz/.tgz archive (see VSIInstallTarFileHandler()) or on a HTTP / FTP
4136 : * server (see VSIInstallCurlFileHandler())
4137 : *
4138 : * @param poOpenInfo a pointer to an open info instance. Must NOT be NULL,
4139 : * and the GDAL_OF_SHARED flag must NOT be set in poOpenInfo->nOpenFlags.
4140 : * If shared dataset is needed, use GDALOpenEx() or the other variant of
4141 : * GDALDataset::Open()
4142 : *
4143 : * @param papszAllowedDrivers NULL to consider all candidate drivers, or a NULL
4144 : * terminated list of strings with the driver short names that must be
4145 : * considered.
4146 : * Starting with GDAL 3.13, a string starting with the dash (-) character
4147 : * followed by the driver short name can be used to exclude a driver.
4148 : *
4149 : * @param papszOpenOptions NULL, or a NULL terminated list of strings with open
4150 : * options passed to candidate drivers. An option exists for all drivers,
4151 : * OVERVIEW_LEVEL=level, to select a particular overview level of a dataset.
4152 : * The level index starts at 0. The level number can be suffixed by "only" to
4153 : * specify that only this overview level must be visible, and not sub-levels.
4154 : * Open options are validated by default, and a warning is emitted in case the
4155 : * option is not recognized. In some scenarios, it might be not desirable (e.g.
4156 : * when not knowing which driver will open the file), so the special open option
4157 : * VALIDATE_OPEN_OPTIONS can be set to NO to avoid such warnings. Alternatively,
4158 : * that it may not cause a warning if the driver doesn't declare this option.
4159 : * OVERVIEW_LEVEL=NONE is supported to indicate that
4160 : * no overviews should be exposed.
4161 : *
4162 : * @return A GDALDataset unique pointer or NULL on failure.
4163 : *
4164 : * @since 3.13
4165 : */
4166 :
4167 : std::unique_ptr<GDALDataset>
4168 82083 : GDALDataset::Open(GDALOpenInfo *poOpenInfo,
4169 : const char *const *papszAllowedDrivers,
4170 : const char *const *papszOpenOptions)
4171 : {
4172 : // Hack for the ZARR driver. We translate the CACHE_KERCHUNK_JSON
4173 : // into VSIKERCHUNK_USE_CACHE config option
4174 82083 : std::unique_ptr<CPLConfigOptionSetter> poVSIKERCHUNK_USE_CACHESetter;
4175 82083 : if (CPLFetchBool(papszOpenOptions, "CACHE_KERCHUNK_JSON", false))
4176 : {
4177 13 : poVSIKERCHUNK_USE_CACHESetter = std::make_unique<CPLConfigOptionSetter>(
4178 26 : "VSIKERCHUNK_USE_CACHE", "YES", false);
4179 : }
4180 :
4181 82083 : GDALDriverManager *poDM = GetGDALDriverManager();
4182 :
4183 82083 : CPLAssert(nullptr != poDM);
4184 :
4185 82083 : GDALOpenInfo &oOpenInfo = *poOpenInfo;
4186 82083 : const char *pszFilename = poOpenInfo->pszFilename;
4187 82083 : const int nOpenFlags = poOpenInfo->nOpenFlags;
4188 82083 : oOpenInfo.papszAllowedDrivers = papszAllowedDrivers;
4189 :
4190 82083 : GDALAntiRecursionStruct &sAntiRecursion = GetAntiRecursionOpen();
4191 82083 : if (sAntiRecursion.nRecLevel == 100)
4192 : {
4193 0 : CPLError(CE_Failure, CPLE_AppDefined,
4194 : "GDALOpen() called with too many recursion levels");
4195 0 : return nullptr;
4196 : }
4197 :
4198 164166 : std::string osAllowedDrivers;
4199 176596 : for (const char *pszDriverName : cpl::Iterate(papszAllowedDrivers))
4200 94513 : osAllowedDrivers += pszDriverName;
4201 : auto dsCtxt = GDALAntiRecursionStruct::DatasetContext(
4202 246249 : std::string(pszFilename), nOpenFlags, osAllowedDrivers);
4203 82083 : if (cpl::contains(sAntiRecursion.aosDatasetNamesWithFlags, dsCtxt))
4204 : {
4205 0 : CPLError(CE_Failure, CPLE_AppDefined,
4206 : "GDALOpen() called on %s recursively", pszFilename);
4207 0 : return nullptr;
4208 : }
4209 :
4210 : // Remove leading @ if present.
4211 : char **papszOpenOptionsCleaned =
4212 82083 : CSLDuplicate(const_cast<char **>(papszOpenOptions));
4213 87754 : for (char **papszIter = papszOpenOptionsCleaned; papszIter && *papszIter;
4214 : ++papszIter)
4215 : {
4216 5671 : char *pszOption = *papszIter;
4217 5671 : if (pszOption[0] == '@')
4218 228 : memmove(pszOption, pszOption + 1, strlen(pszOption + 1) + 1);
4219 : }
4220 :
4221 82083 : oOpenInfo.papszOpenOptions = papszOpenOptionsCleaned;
4222 82083 : oOpenInfo.nOpenFlags |= GDAL_OF_FROM_GDALOPEN;
4223 :
4224 : #ifdef OGRAPISPY_ENABLED
4225 82083 : const bool bUpdate = (nOpenFlags & GDAL_OF_UPDATE) != 0;
4226 : const int iSnapshot =
4227 19932 : (nOpenFlags & GDAL_OF_VECTOR) != 0 && (nOpenFlags & GDAL_OF_RASTER) == 0
4228 102015 : ? OGRAPISpyOpenTakeSnapshot(pszFilename, bUpdate)
4229 82083 : : INT_MIN;
4230 : #endif
4231 :
4232 82083 : const int nDriverCount = poDM->GetDriverCount(/*bIncludeHidden=*/true);
4233 82083 : GDALDriver *poMissingPluginDriver = nullptr;
4234 164166 : std::vector<GDALDriver *> apoSecondPassDrivers;
4235 :
4236 : // Lookup of matching driver for dataset can involve up to 2 passes:
4237 : // - in the first pass, all drivers that are compabile of the request mode
4238 : // (raster/vector/etc.) are probed using their Identify() method if it
4239 : // exists. If the Identify() method returns FALSE, the driver is skipped.
4240 : // If the Identify() methods returns GDAL_IDENTIFY_UNKNOWN and that the
4241 : // driver is a deferred-loading plugin, it is added to the
4242 : // apoSecondPassDrivers list for potential later probing, and execution
4243 : // continues to the next driver in the list.
4244 : // Otherwise if Identify() returns non-FALSE, the Open() method is used.
4245 : // If Open() returns a non-NULL dataset, the loop stops and it is
4246 : // returned. Otherwise looping over remaining drivers continues.
4247 : // - the second pass is optional, only if at least one driver was added
4248 : // into apoSecondPassDrivers during the first pass. It is similar
4249 : // to the first pass except it runs only on apoSecondPassDrivers drivers.
4250 : // And the Open() method of such drivers is used, causing them to be
4251 : // loaded for real.
4252 82083 : int iPass = 1;
4253 82097 : retry:
4254 8513860 : for (int iDriver = 0;
4255 8513900 : iDriver < (iPass == 1 ? nDriverCount
4256 34 : : static_cast<int>(apoSecondPassDrivers.size()));
4257 : ++iDriver)
4258 : {
4259 : GDALDriver *poDriver =
4260 8495080 : iPass == 1 ? poDM->GetDriver(iDriver, /*bIncludeHidden=*/true)
4261 25 : : apoSecondPassDrivers[iDriver];
4262 8495060 : const char *pszDriverName = GDALGetDriverShortName(poDriver);
4263 8495060 : if (pszDriverName && papszAllowedDrivers)
4264 : {
4265 3720510 : bool bDriverMatchedPositively = false;
4266 3720510 : bool bDriverMatchedNegatively = false;
4267 3720510 : bool bOnlyExcludedDrivers = true;
4268 18051800 : for (const char *pszAllowedDriver :
4269 39824100 : cpl::Iterate(papszAllowedDrivers))
4270 : {
4271 18051800 : if (pszAllowedDriver[0] != '-')
4272 18050400 : bOnlyExcludedDrivers = false;
4273 18051800 : if (EQUAL(pszAllowedDriver, pszDriverName))
4274 : {
4275 89405 : bDriverMatchedPositively = true;
4276 : }
4277 17962400 : else if (pszAllowedDriver[0] == '-' &&
4278 1462 : EQUAL(pszAllowedDriver + 1, pszDriverName))
4279 : {
4280 7 : bDriverMatchedNegatively = true;
4281 7 : break;
4282 : }
4283 : }
4284 3720510 : if ((!bDriverMatchedPositively && !bOnlyExcludedDrivers) ||
4285 : bDriverMatchedNegatively)
4286 : {
4287 7984540 : continue;
4288 : }
4289 : }
4290 :
4291 4865180 : if (poDriver->GetMetadataItem(GDAL_DCAP_OPEN) == nullptr)
4292 46630 : continue;
4293 :
4294 12738500 : if ((nOpenFlags & GDAL_OF_RASTER) != 0 &&
4295 6972210 : (nOpenFlags & GDAL_OF_VECTOR) == 0 &&
4296 2153660 : poDriver->GetMetadataItem(GDAL_DCAP_RASTER) == nullptr)
4297 490568 : continue;
4298 12398700 : if ((nOpenFlags & GDAL_OF_VECTOR) != 0 &&
4299 6206030 : (nOpenFlags & GDAL_OF_RASTER) == 0 &&
4300 1878050 : poDriver->GetMetadataItem(GDAL_DCAP_VECTOR) == nullptr)
4301 1407490 : continue;
4302 6489250 : if ((nOpenFlags & GDAL_OF_MULTIDIM_RASTER) != 0 &&
4303 3249120 : (nOpenFlags & GDAL_OF_RASTER) == 0 &&
4304 328635 : poDriver->GetMetadataItem(GDAL_DCAP_MULTIDIM_RASTER) == nullptr)
4305 309918 : continue;
4306 :
4307 : // Remove general OVERVIEW_LEVEL open options from list before passing
4308 : // it to the driver, if it isn't a driver specific option already.
4309 2610570 : char **papszTmpOpenOptions = nullptr;
4310 2610570 : char **papszTmpOpenOptionsToValidate = nullptr;
4311 2610570 : char **papszOptionsToValidate = const_cast<char **>(papszOpenOptions);
4312 2610570 : if (CSLFetchNameValue(papszOpenOptionsCleaned, "OVERVIEW_LEVEL") !=
4313 2610720 : nullptr &&
4314 152 : !poDriver->HasOpenOption("OVERVIEW_LEVEL"))
4315 : {
4316 152 : papszTmpOpenOptions = CSLDuplicate(papszOpenOptionsCleaned);
4317 : papszTmpOpenOptions =
4318 152 : CSLSetNameValue(papszTmpOpenOptions, "OVERVIEW_LEVEL", nullptr);
4319 152 : oOpenInfo.papszOpenOptions = papszTmpOpenOptions;
4320 :
4321 152 : papszOptionsToValidate = CSLDuplicate(papszOptionsToValidate);
4322 152 : papszOptionsToValidate = CSLSetNameValue(papszOptionsToValidate,
4323 : "OVERVIEW_LEVEL", nullptr);
4324 152 : papszTmpOpenOptionsToValidate = papszOptionsToValidate;
4325 : }
4326 :
4327 : const int nIdentifyRes =
4328 2610570 : poDriver->pfnIdentifyEx
4329 5221130 : ? poDriver->pfnIdentifyEx(poDriver, &oOpenInfo)
4330 2610560 : : poDriver->pfnIdentify ? poDriver->pfnIdentify(&oOpenInfo)
4331 2610570 : : GDAL_IDENTIFY_UNKNOWN;
4332 2610570 : if (nIdentifyRes == FALSE)
4333 : {
4334 2099950 : CSLDestroy(papszTmpOpenOptions);
4335 2099950 : CSLDestroy(papszTmpOpenOptionsToValidate);
4336 2099950 : oOpenInfo.papszOpenOptions = papszOpenOptionsCleaned;
4337 2099950 : continue;
4338 : }
4339 510592 : else if (iPass == 1 && nIdentifyRes < 0 &&
4340 1021310 : poDriver->pfnOpen == nullptr &&
4341 101 : poDriver->GetMetadataItem("IS_NON_LOADED_PLUGIN"))
4342 : {
4343 : // Not loaded plugin
4344 98 : apoSecondPassDrivers.push_back(poDriver);
4345 98 : CSLDestroy(papszTmpOpenOptions);
4346 98 : CSLDestroy(papszTmpOpenOptionsToValidate);
4347 98 : oOpenInfo.papszOpenOptions = papszOpenOptionsCleaned;
4348 98 : continue;
4349 : }
4350 :
4351 510519 : const bool bIdentifyRes = nIdentifyRes == GDAL_IDENTIFY_TRUE;
4352 510519 : if (bIdentifyRes)
4353 : {
4354 62328 : GDALValidateOpenOptions(poDriver, papszOptionsToValidate);
4355 : }
4356 :
4357 : #ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION
4358 : const bool bFpAvailableBefore = oOpenInfo.fpL != nullptr;
4359 : CPLErrorReset();
4360 : #endif
4361 :
4362 510519 : sAntiRecursion.nRecLevel++;
4363 510519 : sAntiRecursion.aosDatasetNamesWithFlags.insert(dsCtxt);
4364 :
4365 510519 : GDALDataset *poDS = poDriver->Open(&oOpenInfo, false);
4366 :
4367 510519 : sAntiRecursion.nRecLevel--;
4368 510519 : sAntiRecursion.aosDatasetNamesWithFlags.erase(dsCtxt);
4369 :
4370 510519 : if (poDriver->pfnOpen != nullptr)
4371 : {
4372 : // If we couldn't determine for sure with Identify() (it returned
4373 : // -1), but Open() managed to open the file, post validate options.
4374 510516 : if (poDS != nullptr &&
4375 62180 : (poDriver->pfnIdentify || poDriver->pfnIdentifyEx) &&
4376 61611 : !bIdentifyRes)
4377 : {
4378 832 : GDALValidateOpenOptions(poDriver, papszOptionsToValidate);
4379 : }
4380 : }
4381 3 : else if (poDriver->pfnOpenWithDriverArg != nullptr)
4382 : {
4383 : // do nothing
4384 : }
4385 0 : else if (bIdentifyRes &&
4386 0 : poDriver->GetMetadataItem("MISSING_PLUGIN_FILENAME"))
4387 : {
4388 0 : if (!poMissingPluginDriver)
4389 : {
4390 0 : poMissingPluginDriver = poDriver;
4391 : }
4392 : }
4393 : else
4394 : {
4395 : // should not happen given the GDAL_DCAP_OPEN check
4396 0 : CSLDestroy(papszTmpOpenOptions);
4397 0 : CSLDestroy(papszTmpOpenOptionsToValidate);
4398 0 : oOpenInfo.papszOpenOptions = papszOpenOptionsCleaned;
4399 0 : continue;
4400 : }
4401 :
4402 510519 : CSLDestroy(papszTmpOpenOptions);
4403 510519 : CSLDestroy(papszTmpOpenOptionsToValidate);
4404 510519 : oOpenInfo.papszOpenOptions = papszOpenOptionsCleaned;
4405 :
4406 510519 : if (poDS != nullptr)
4407 : {
4408 62183 : if (poDS->papszOpenOptions == nullptr)
4409 : {
4410 61913 : poDS->papszOpenOptions = papszOpenOptionsCleaned;
4411 61913 : papszOpenOptionsCleaned = nullptr;
4412 : }
4413 :
4414 : // Deal with generic OVERVIEW_LEVEL open option, unless it is
4415 : // driver specific.
4416 62183 : if (CSLFetchNameValue(papszOpenOptions, "OVERVIEW_LEVEL") !=
4417 62222 : nullptr &&
4418 39 : !poDriver->HasOpenOption("OVERVIEW_LEVEL"))
4419 : {
4420 : CPLString osVal(
4421 78 : CSLFetchNameValue(papszOpenOptions, "OVERVIEW_LEVEL"));
4422 39 : const int nOvrLevel = EQUAL(osVal, "NONE") ? -1 : atoi(osVal);
4423 : const bool bThisLevelOnly =
4424 39 : nOvrLevel == -1 || osVal.ifind("only") != std::string::npos;
4425 : GDALDataset *poOvrDS =
4426 39 : GDALCreateOverviewDataset(poDS, nOvrLevel, bThisLevelOnly);
4427 39 : if (poOvrDS && (nOpenFlags & GDAL_OF_SHARED) != 0)
4428 : {
4429 4 : if (strcmp(pszFilename, poDS->GetDescription()) != 0)
4430 : {
4431 0 : CPLError(
4432 : CE_Warning, CPLE_NotSupported,
4433 : "A dataset opened by GDALOpenShared should have "
4434 : "the same filename (%s) "
4435 : "and description (%s)",
4436 0 : pszFilename, poDS->GetDescription());
4437 : }
4438 : else
4439 : {
4440 4 : CSLDestroy(poDS->papszOpenOptions);
4441 4 : poDS->papszOpenOptions = CSLDuplicate(papszOpenOptions);
4442 4 : poDS->papszOpenOptions = CSLSetNameValue(
4443 : poDS->papszOpenOptions, "OVERVIEW_LEVEL", nullptr);
4444 : }
4445 : }
4446 39 : poDS->ReleaseRef();
4447 39 : poDS = poOvrDS;
4448 39 : if (poDS == nullptr)
4449 : {
4450 1 : if (nOpenFlags & GDAL_OF_VERBOSE_ERROR)
4451 : {
4452 1 : CPLError(CE_Failure, CPLE_OpenFailed,
4453 : "Cannot open overview level %d of %s",
4454 : nOvrLevel, pszFilename);
4455 : }
4456 : }
4457 : else
4458 : {
4459 : // For thread-safe opening, currently poDS is what will be
4460 : // the "master" dataset owned by the thread-safe dataset
4461 : // returned to the user, hence we do not register it as a
4462 : // visible one in the open dataset list, or mark it as shared.
4463 38 : if (!(nOpenFlags & GDAL_OF_INTERNAL) &&
4464 36 : !(nOpenFlags & GDAL_OF_THREAD_SAFE))
4465 : {
4466 35 : poDS->AddToDatasetOpenList();
4467 : }
4468 38 : if (nOpenFlags & GDAL_OF_SHARED)
4469 : {
4470 4 : CSLDestroy(poDS->papszOpenOptions);
4471 4 : poDS->papszOpenOptions = CSLDuplicate(papszOpenOptions);
4472 4 : poDS->nOpenFlags = nOpenFlags;
4473 4 : if (!(nOpenFlags & GDAL_OF_THREAD_SAFE))
4474 4 : poDS->MarkAsShared();
4475 : }
4476 : }
4477 : }
4478 62144 : else if (nOpenFlags & GDAL_OF_SHARED)
4479 : {
4480 373 : if (strcmp(pszFilename, poDS->GetDescription()) != 0)
4481 : {
4482 2 : CPLError(CE_Warning, CPLE_NotSupported,
4483 : "A dataset opened by GDALOpenShared should have "
4484 : "the same filename (%s) "
4485 : "and description (%s)",
4486 2 : pszFilename, poDS->GetDescription());
4487 : }
4488 371 : else if (!(nOpenFlags & GDAL_OF_THREAD_SAFE))
4489 : {
4490 : // For thread-safe opening, currently poDS is what will be
4491 : // the "master" dataset owned by the thread-safe dataset
4492 : // returned to the user, hence we do not or mark it as shared.
4493 371 : poDS->MarkAsShared();
4494 : }
4495 : }
4496 :
4497 62183 : VSIErrorReset();
4498 :
4499 62183 : CSLDestroy(papszOpenOptionsCleaned);
4500 :
4501 : #ifdef OGRAPISPY_ENABLED
4502 62183 : if (iSnapshot != INT_MIN)
4503 : {
4504 11753 : GDALDatasetH hDS = GDALDataset::ToHandle(poDS);
4505 11753 : OGRAPISpyOpen(pszFilename, bUpdate, iSnapshot, &hDS);
4506 11753 : poDS = GDALDataset::FromHandle(hDS);
4507 : }
4508 : #endif
4509 :
4510 62183 : if (poDS)
4511 : {
4512 62182 : poDS->m_bCanBeReopened = true;
4513 :
4514 62182 : if ((nOpenFlags & GDAL_OF_THREAD_SAFE) != 0)
4515 : {
4516 : poDS =
4517 248 : GDALGetThreadSafeDataset(
4518 248 : std::unique_ptr<GDALDataset>(poDS), GDAL_OF_RASTER)
4519 124 : .release();
4520 124 : if (poDS)
4521 : {
4522 124 : poDS->m_bCanBeReopened = true;
4523 124 : poDS->poDriver = poDriver;
4524 124 : poDS->nOpenFlags = nOpenFlags;
4525 124 : if (!(nOpenFlags & GDAL_OF_INTERNAL))
4526 124 : poDS->AddToDatasetOpenList();
4527 124 : if (nOpenFlags & GDAL_OF_SHARED)
4528 0 : poDS->MarkAsShared();
4529 : }
4530 : }
4531 : }
4532 :
4533 63290 : return std::unique_ptr<GDALDataset>(poDS);
4534 : }
4535 :
4536 : #ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION
4537 : if (bFpAvailableBefore && oOpenInfo.fpL == nullptr)
4538 : {
4539 : // In case the file descriptor was "consumed" by a driver
4540 : // that ultimately failed, re-open it for next drivers.
4541 : oOpenInfo.fpL = VSIFOpenL(
4542 : pszFilename, (oOpenInfo.eAccess == GA_Update) ? "r+b" : "rb");
4543 : }
4544 : #else
4545 448336 : if (CPLGetLastErrorNo() != 0 && CPLGetLastErrorType() > CE_Warning)
4546 : {
4547 1107 : CSLDestroy(papszOpenOptionsCleaned);
4548 :
4549 : #ifdef OGRAPISPY_ENABLED
4550 1107 : if (iSnapshot != INT_MIN)
4551 : {
4552 193 : GDALDatasetH hDS = nullptr;
4553 193 : OGRAPISpyOpen(pszFilename, bUpdate, iSnapshot, &hDS);
4554 : }
4555 : #endif
4556 1107 : return nullptr;
4557 : }
4558 : #endif
4559 : }
4560 :
4561 : // cppcheck-suppress knownConditionTrueFalse
4562 18807 : if (iPass == 1 && !apoSecondPassDrivers.empty())
4563 : {
4564 14 : CPLDebugOnly("GDAL", "GDALOpen(): Second pass");
4565 14 : iPass = 2;
4566 14 : goto retry;
4567 : }
4568 :
4569 18793 : CSLDestroy(papszOpenOptionsCleaned);
4570 :
4571 : #ifdef OGRAPISPY_ENABLED
4572 18793 : if (iSnapshot != INT_MIN)
4573 : {
4574 660 : GDALDatasetH hDS = nullptr;
4575 660 : OGRAPISpyOpen(pszFilename, bUpdate, iSnapshot, &hDS);
4576 : }
4577 : #endif
4578 :
4579 18793 : if (nOpenFlags & GDAL_OF_VERBOSE_ERROR)
4580 : {
4581 11960 : std::string osHint;
4582 11960 : const CPLStringList aosVSIFSPrefixes(VSIFileManager::GetPrefixes());
4583 185295 : for (const char *pszFSPrefix : aosVSIFSPrefixes)
4584 : {
4585 179322 : auto poFS = VSIFileManager::GetHandler(pszFSPrefix);
4586 179322 : if (poFS)
4587 : {
4588 179322 : osHint = poFS->GetHintForPotentiallyRecognizedPath(pszFilename);
4589 179322 : if (!osHint.empty())
4590 : {
4591 14 : osHint = " Changing the filename to " + osHint +
4592 7 : " may help it to be recognized.";
4593 7 : break;
4594 : }
4595 : }
4596 : }
4597 :
4598 5980 : if (nDriverCount == 0)
4599 : {
4600 0 : CPLError(CE_Failure, CPLE_OpenFailed, "No driver registered.");
4601 : }
4602 5980 : else if (poMissingPluginDriver)
4603 : {
4604 0 : std::string osMsg("`");
4605 0 : osMsg += pszFilename;
4606 : osMsg += "' not recognized as being in a supported file format. "
4607 0 : "It could have been recognized by driver ";
4608 0 : osMsg += poMissingPluginDriver->GetDescription();
4609 0 : osMsg += ", but plugin ";
4610 : osMsg +=
4611 0 : GDALGetMessageAboutMissingPluginDriver(poMissingPluginDriver);
4612 :
4613 0 : CPLError(CE_Failure, CPLE_OpenFailed, "%s", osMsg.c_str());
4614 : }
4615 : // Check to see if there was a filesystem error, and report it if so.
4616 : // If not, return a more generic error.
4617 5980 : else if (!osHint.empty() && VSIGetLastErrorNo() == VSIE_FileError)
4618 : {
4619 3 : CPLError(CE_Failure, CPLE_FileIO, "%s.%s", VSIGetLastErrorMsg(),
4620 : osHint.c_str());
4621 : }
4622 5977 : else if (!VSIToCPLError(CE_Failure, CPLE_OpenFailed))
4623 : {
4624 518 : if (oOpenInfo.bStatOK)
4625 : {
4626 513 : CPLError(CE_Failure, CPLE_OpenFailed,
4627 : "`%s' not recognized as being in a supported file "
4628 : "format.%s",
4629 : pszFilename, osHint.c_str());
4630 : }
4631 : else
4632 : {
4633 : // If Stat failed and no VSI error was set, assume it is because
4634 : // the file did not exist on the filesystem.
4635 5 : CPLError(CE_Failure, CPLE_OpenFailed,
4636 : "`%s' does not exist in the file system, "
4637 : "and is not recognized as a supported dataset name.%s",
4638 : pszFilename, osHint.c_str());
4639 : }
4640 : }
4641 : }
4642 :
4643 18793 : return nullptr;
4644 : }
4645 :
4646 : /************************************************************************/
4647 : /* GDALOpenShared() */
4648 : /************************************************************************/
4649 :
4650 : /**
4651 : * \brief Open a raster file as a GDALDataset.
4652 : *
4653 : * This function works the same as GDALOpen(), but allows the sharing of
4654 : * GDALDataset handles for a dataset with other callers to GDALOpenShared().
4655 : *
4656 : * In particular, GDALOpenShared() will first consult its list of currently
4657 : * open and shared GDALDataset's, and if the GetDescription() name for one
4658 : * exactly matches the pszFilename passed to GDALOpenShared() it will be
4659 : * referenced and returned.
4660 : *
4661 : * If GDALOpenShared() is called on the same
4662 : * pszFilename from two different threads, a different GDALDataset object will
4663 : * be returned as it is not safe to use the same dataset from different threads,
4664 : * unless the user does explicitly use mutexes in its code.
4665 : *
4666 : * For drivers supporting the VSI virtual file API, it is possible to open a
4667 : * file in a .zip archive (see VSIInstallZipFileHandler()), in a
4668 : * .tar/.tar.gz/.tgz archive (see VSIInstallTarFileHandler()) or on a HTTP / FTP
4669 : * server (see VSIInstallCurlFileHandler())
4670 : *
4671 : * \sa GDALOpen()
4672 : * \sa GDALOpenEx()
4673 : *
4674 : * @param pszFilename the name of the file to access. In the case of
4675 : * exotic drivers this may not refer to a physical file, but instead contain
4676 : * information for the driver on how to access a dataset. It should be in
4677 : * UTF-8 encoding.
4678 : *
4679 : * @param eAccess the desired access, either GA_Update or GA_ReadOnly. Many
4680 : * drivers support only read only access.
4681 : *
4682 : * @return A GDALDatasetH handle or NULL on failure. For C++ applications
4683 : * this handle can be cast to a GDALDataset *.
4684 : */
4685 :
4686 5208 : GDALDatasetH CPL_STDCALL GDALOpenShared(const char *pszFilename,
4687 : GDALAccess eAccess)
4688 : {
4689 5208 : VALIDATE_POINTER1(pszFilename, "GDALOpenShared", nullptr);
4690 5208 : return GDALOpenEx(pszFilename,
4691 : GDAL_OF_RASTER |
4692 : (eAccess == GA_Update ? GDAL_OF_UPDATE : 0) |
4693 : GDAL_OF_SHARED | GDAL_OF_VERBOSE_ERROR,
4694 5208 : nullptr, nullptr, nullptr);
4695 : }
4696 :
4697 : /************************************************************************/
4698 : /* GDALClose() */
4699 : /************************************************************************/
4700 :
4701 : /**
4702 : * \brief Close GDAL dataset.
4703 : *
4704 : * For non-shared datasets (opened with GDALOpen()) the dataset is closed
4705 : * using the C++ "delete" operator, recovering all dataset related resources.
4706 : * For shared datasets (opened with GDALOpenShared()) the dataset is
4707 : * dereferenced, and closed only if the referenced count has dropped below 1.
4708 : *
4709 : * @param hDS The dataset to close, or nullptr.
4710 : * @return CE_None in case of success (return value since GDAL 3.7). On a
4711 : * shared dataset whose reference count is not dropped below 1, CE_None will
4712 : * be returned.
4713 : *
4714 : * @see GDALCloseEx()
4715 : */
4716 :
4717 86709 : CPLErr CPL_STDCALL GDALClose(GDALDatasetH hDS)
4718 :
4719 : {
4720 86709 : return GDALCloseEx(hDS, nullptr, nullptr);
4721 : }
4722 :
4723 : /************************************************************************/
4724 : /* GDALCloseEx() */
4725 : /************************************************************************/
4726 :
4727 : /**
4728 : * \brief Close GDAL dataset.
4729 : *
4730 : * For non-shared datasets (opened with GDALOpen()) the dataset is closed
4731 : * using the C++ "delete" operator, recovering all dataset related resources.
4732 : * For shared datasets (opened with GDALOpenShared()) the dataset is
4733 : * dereferenced, and closed only if the referenced count has dropped below 1.
4734 : *
4735 : * This function may report progress if a progress
4736 : * callback if provided in the pfnProgress argument and if the dataset returns
4737 : * true for GDALDataset::GetCloseReportsProgress()
4738 :
4739 : * @param hDS The dataset to close, or nullptr
4740 : * @param pfnProgress Progress callback, or nullptr
4741 : * @param pProgressData User data of progress callback, or nullptr
4742 : *
4743 : * @return CE_None in case of success. On a
4744 : * shared dataset whose reference count is not dropped below 1, CE_None will
4745 : * be returned.
4746 : *
4747 : * @since GDAL 3.13
4748 : * @see GDALClose()
4749 : */
4750 :
4751 91036 : CPLErr GDALCloseEx(GDALDatasetH hDS, GDALProgressFunc pfnProgress,
4752 : void *pProgressData)
4753 : {
4754 91036 : if (!hDS)
4755 404 : return CE_None;
4756 :
4757 : #ifdef OGRAPISPY_ENABLED
4758 90632 : if (bOGRAPISpyEnabled)
4759 11 : OGRAPISpyPreClose(hDS);
4760 : #endif
4761 :
4762 90632 : GDALDataset *poDS = GDALDataset::FromHandle(hDS);
4763 :
4764 90632 : if (poDS->GetShared())
4765 : {
4766 : /* --------------------------------------------------------------------
4767 : */
4768 : /* If this file is in the shared dataset list then dereference */
4769 : /* it, and only delete/remote it if the reference count has */
4770 : /* dropped to zero. */
4771 : /* --------------------------------------------------------------------
4772 : */
4773 232 : if (poDS->Dereference() > 0)
4774 15 : return CE_None;
4775 : }
4776 :
4777 90617 : CPLErr eErr = poDS->Close(pfnProgress, pProgressData);
4778 90617 : delete poDS;
4779 :
4780 : #ifdef OGRAPISPY_ENABLED
4781 90617 : if (bOGRAPISpyEnabled)
4782 11 : OGRAPISpyPostClose();
4783 : #endif
4784 90617 : return eErr;
4785 : }
4786 :
4787 : /************************************************************************/
4788 : /* GDALDumpOpenDataset() */
4789 : /************************************************************************/
4790 :
4791 0 : static int GDALDumpOpenSharedDatasetsForeach(void *elt, void *user_data)
4792 : {
4793 0 : SharedDatasetCtxt *psStruct = static_cast<SharedDatasetCtxt *>(elt);
4794 0 : FILE *fp = static_cast<FILE *>(user_data);
4795 0 : GDALDataset *poDS = psStruct->poDS;
4796 :
4797 0 : const char *pszDriverName = poDS->GetDriver() == nullptr
4798 0 : ? "DriverIsNULL"
4799 0 : : poDS->GetDriver()->GetDescription();
4800 :
4801 0 : poDS->Reference();
4802 0 : CPL_IGNORE_RET_VAL(
4803 0 : VSIFPrintf(fp, " %d %c %-6s %7d %dx%dx%d %s\n", poDS->Dereference(),
4804 0 : poDS->GetShared() ? 'S' : 'N', pszDriverName,
4805 0 : static_cast<int>(psStruct->nPID), poDS->GetRasterXSize(),
4806 : poDS->GetRasterYSize(), poDS->GetRasterCount(),
4807 0 : poDS->GetDescription()));
4808 :
4809 0 : return TRUE;
4810 : }
4811 :
4812 0 : static int GDALDumpOpenDatasetsForeach(GDALDataset *poDS, FILE *fp)
4813 : {
4814 :
4815 : // Don't list shared datasets. They have already been listed by
4816 : // GDALDumpOpenSharedDatasetsForeach.
4817 0 : if (poDS->GetShared())
4818 0 : return TRUE;
4819 :
4820 0 : const char *pszDriverName = poDS->GetDriver() == nullptr
4821 0 : ? "DriverIsNULL"
4822 0 : : poDS->GetDriver()->GetDescription();
4823 :
4824 0 : poDS->Reference();
4825 0 : CPL_IGNORE_RET_VAL(
4826 0 : VSIFPrintf(fp, " %d %c %-6s %7d %dx%dx%d %s\n", poDS->Dereference(),
4827 0 : poDS->GetShared() ? 'S' : 'N', pszDriverName, -1,
4828 : poDS->GetRasterXSize(), poDS->GetRasterYSize(),
4829 0 : poDS->GetRasterCount(), poDS->GetDescription()));
4830 :
4831 0 : return TRUE;
4832 : }
4833 :
4834 : /**
4835 : * \brief List open datasets.
4836 : *
4837 : * Dumps a list of all open datasets (shared or not) to the indicated
4838 : * text file (may be stdout or stderr). This function is primarily intended
4839 : * to assist in debugging "dataset leaks" and reference counting issues.
4840 : * The information reported includes the dataset name, referenced count,
4841 : * shared status, driver name, size, and band count.
4842 : */
4843 :
4844 272 : int CPL_STDCALL GDALDumpOpenDatasets(FILE *fp)
4845 :
4846 : {
4847 272 : VALIDATE_POINTER1(fp, "GDALDumpOpenDatasets", 0);
4848 :
4849 544 : CPLMutexHolderD(&hDLMutex);
4850 :
4851 272 : if (poAllDatasetMap == nullptr)
4852 272 : return 0;
4853 :
4854 0 : CPL_IGNORE_RET_VAL(VSIFPrintf(fp, "Open GDAL Datasets:\n"));
4855 :
4856 0 : for (const auto &oIter : *poAllDatasetMap)
4857 : {
4858 0 : GDALDumpOpenDatasetsForeach(oIter.first, fp);
4859 : }
4860 :
4861 0 : if (phSharedDatasetSet != nullptr)
4862 : {
4863 0 : CPLHashSetForeach(phSharedDatasetSet, GDALDumpOpenSharedDatasetsForeach,
4864 : fp);
4865 : }
4866 0 : return static_cast<int>(poAllDatasetMap->size());
4867 : }
4868 :
4869 : /************************************************************************/
4870 : /* BeginAsyncReader() */
4871 : /************************************************************************/
4872 :
4873 : /**
4874 : * \brief Sets up an asynchronous data request
4875 : *
4876 : * This method establish an asynchronous raster read request for the
4877 : * indicated window on the dataset into the indicated buffer. The parameters
4878 : * for windowing, buffer size, buffer type and buffer organization are similar
4879 : * to those for GDALDataset::RasterIO(); however, this call only launches
4880 : * the request and filling the buffer is accomplished via calls to
4881 : * GetNextUpdatedRegion() on the return GDALAsyncReader session object.
4882 : *
4883 : * Once all processing for the created session is complete, or if no further
4884 : * refinement of the request is required, the GDALAsyncReader object should
4885 : * be destroyed with the GDALDataset::EndAsyncReader() method.
4886 : *
4887 : * Note that the data buffer (pData) will potentially continue to be
4888 : * updated as long as the session lives, but it is not deallocated when
4889 : * the session (GDALAsyncReader) is destroyed with EndAsyncReader(). It
4890 : * should be deallocated by the application at that point.
4891 : *
4892 : * Additional information on asynchronous IO in GDAL may be found at:
4893 : * https://gdal.org/development/rfc/rfc24_progressive_data_support.html
4894 : *
4895 : * This method is the same as the C GDALBeginAsyncReader() function.
4896 : *
4897 : * @param nXOff The pixel offset to the top left corner of the region
4898 : * of the band to be accessed. This would be zero to start from the left side.
4899 : *
4900 : * @param nYOff The line offset to the top left corner of the region
4901 : * of the band to be accessed. This would be zero to start from the top.
4902 : *
4903 : * @param nXSize The width of the region of the band to be accessed in pixels.
4904 : *
4905 : * @param nYSize The height of the region of the band to be accessed in lines.
4906 : *
4907 : * @param pBuf The buffer into which the data should be read. This buffer must
4908 : * contain at least nBufXSize * nBufYSize * nBandCount words of type eBufType.
4909 : * It is organized in left to right,top to bottom pixel order. Spacing is
4910 : * controlled by the nPixelSpace, and nLineSpace parameters.
4911 : *
4912 : * @param nBufXSize the width of the buffer image into which the desired region
4913 : * is to be read, or from which it is to be written.
4914 : *
4915 : * @param nBufYSize the height of the buffer image into which the desired
4916 : * region is to be read, or from which it is to be written.
4917 : *
4918 : * @param eBufType the type of the pixel values in the pData data buffer. The
4919 : * pixel values will automatically be translated to/from the GDALRasterBand
4920 : * data type as needed.
4921 : *
4922 : * @param nBandCount the number of bands being read or written.
4923 : *
4924 : * @param panBandMap the list of nBandCount band numbers being read/written.
4925 : * Note band numbers are 1 based. This may be NULL to select the first
4926 : * nBandCount bands.
4927 : *
4928 : * @param nPixelSpace The byte offset from the start of one pixel value in
4929 : * pData to the start of the next pixel value within a scanline. If defaulted
4930 : * (0) the size of the datatype eBufType is used.
4931 : *
4932 : * @param nLineSpace The byte offset from the start of one scanline in
4933 : * pData to the start of the next. If defaulted the size of the datatype
4934 : * eBufType * nBufXSize is used.
4935 : *
4936 : * @param nBandSpace the byte offset from the start of one bands data to the
4937 : * start of the next. If defaulted (zero) the value will be
4938 : * nLineSpace * nBufYSize implying band sequential organization
4939 : * of the data buffer.
4940 : *
4941 : * @param papszOptions Driver specific control options in a string list or NULL.
4942 : * Consult driver documentation for options supported.
4943 : *
4944 : * @return The GDALAsyncReader object representing the request.
4945 : */
4946 :
4947 1 : GDALAsyncReader *GDALDataset::BeginAsyncReader(
4948 : int nXOff, int nYOff, int nXSize, int nYSize, void *pBuf, int nBufXSize,
4949 : int nBufYSize, GDALDataType eBufType, int nBandCount, int *panBandMap,
4950 : int nPixelSpace, int nLineSpace, int nBandSpace, CSLConstList papszOptions)
4951 : {
4952 : // See gdaldefaultasync.cpp
4953 :
4954 1 : return GDALGetDefaultAsyncReader(this, nXOff, nYOff, nXSize, nYSize, pBuf,
4955 : nBufXSize, nBufYSize, eBufType, nBandCount,
4956 : panBandMap, nPixelSpace, nLineSpace,
4957 1 : nBandSpace, papszOptions);
4958 : }
4959 :
4960 : /************************************************************************/
4961 : /* GDALBeginAsyncReader() */
4962 : /************************************************************************/
4963 :
4964 : /**
4965 : * \brief Sets up an asynchronous data request
4966 : *
4967 : * This method establish an asynchronous raster read request for the
4968 : * indicated window on the dataset into the indicated buffer. The parameters
4969 : * for windowing, buffer size, buffer type and buffer organization are similar
4970 : * to those for GDALDataset::RasterIO(); however, this call only launches
4971 : * the request and filling the buffer is accomplished via calls to
4972 : * GetNextUpdatedRegion() on the return GDALAsyncReader session object.
4973 : *
4974 : * Once all processing for the created session is complete, or if no further
4975 : * refinement of the request is required, the GDALAsyncReader object should
4976 : * be destroyed with the GDALDataset::EndAsyncReader() method.
4977 : *
4978 : * Note that the data buffer (pData) will potentially continue to be
4979 : * updated as long as the session lives, but it is not deallocated when
4980 : * the session (GDALAsyncReader) is destroyed with EndAsyncReader(). It
4981 : * should be deallocated by the application at that point.
4982 : *
4983 : * Additional information on asynchronous IO in GDAL may be found at:
4984 : * https://gdal.org/development/rfc/rfc24_progressive_data_support.html
4985 : *
4986 : * This method is the same as the C++ GDALDataset::BeginAsyncReader() method.
4987 : *
4988 : * @param hDS handle to the dataset object.
4989 : *
4990 : * @param nXOff The pixel offset to the top left corner of the region
4991 : * of the band to be accessed. This would be zero to start from the left side.
4992 : *
4993 : * @param nYOff The line offset to the top left corner of the region
4994 : * of the band to be accessed. This would be zero to start from the top.
4995 : *
4996 : * @param nXSize The width of the region of the band to be accessed in pixels.
4997 : *
4998 : * @param nYSize The height of the region of the band to be accessed in lines.
4999 : *
5000 : * @param pBuf The buffer into which the data should be read. This buffer must
5001 : * contain at least nBufXSize * nBufYSize * nBandCount words of type eBufType.
5002 : * It is organized in left to right,top to bottom pixel order. Spacing is
5003 : * controlled by the nPixelSpace, and nLineSpace parameters.
5004 : *
5005 : * @param nBufXSize the width of the buffer image into which the desired region
5006 : * is to be read, or from which it is to be written.
5007 : *
5008 : * @param nBufYSize the height of the buffer image into which the desired
5009 : * region is to be read, or from which it is to be written.
5010 : *
5011 : * @param eBufType the type of the pixel values in the pData data buffer. The
5012 : * pixel values will automatically be translated to/from the GDALRasterBand
5013 : * data type as needed.
5014 : *
5015 : * @param nBandCount the number of bands being read or written.
5016 : *
5017 : * @param panBandMap the list of nBandCount band numbers being read/written.
5018 : * Note band numbers are 1 based. This may be NULL to select the first
5019 : * nBandCount bands.
5020 : *
5021 : * @param nPixelSpace The byte offset from the start of one pixel value in
5022 : * pData to the start of the next pixel value within a scanline. If defaulted
5023 : * (0) the size of the datatype eBufType is used.
5024 : *
5025 : * @param nLineSpace The byte offset from the start of one scanline in
5026 : * pData to the start of the next. If defaulted the size of the datatype
5027 : * eBufType * nBufXSize is used.
5028 : *
5029 : * @param nBandSpace the byte offset from the start of one bands data to the
5030 : * start of the next. If defaulted (zero) the value will be
5031 : * nLineSpace * nBufYSize implying band sequential organization
5032 : * of the data buffer.
5033 : *
5034 : * @param papszOptions Driver specific control options in a string list or NULL.
5035 : * Consult driver documentation for options supported.
5036 : *
5037 : * @return handle representing the request.
5038 : */
5039 :
5040 2 : GDALAsyncReaderH CPL_STDCALL GDALBeginAsyncReader(
5041 : GDALDatasetH hDS, int nXOff, int nYOff, int nXSize, int nYSize, void *pBuf,
5042 : int nBufXSize, int nBufYSize, GDALDataType eBufType, int nBandCount,
5043 : int *panBandMap, int nPixelSpace, int nLineSpace, int nBandSpace,
5044 : CSLConstList papszOptions)
5045 :
5046 : {
5047 2 : VALIDATE_POINTER1(hDS, "GDALDataset", nullptr);
5048 : return static_cast<GDALAsyncReaderH>(
5049 2 : GDALDataset::FromHandle(hDS)->BeginAsyncReader(
5050 : nXOff, nYOff, nXSize, nYSize, pBuf, nBufXSize, nBufYSize, eBufType,
5051 : nBandCount, panBandMap, nPixelSpace, nLineSpace, nBandSpace,
5052 2 : const_cast<char **>(papszOptions)));
5053 : }
5054 :
5055 : /************************************************************************/
5056 : /* EndAsyncReader() */
5057 : /************************************************************************/
5058 :
5059 : /**
5060 : * End asynchronous request.
5061 : *
5062 : * This method destroys an asynchronous io request and recovers all
5063 : * resources associated with it.
5064 : *
5065 : * This method is the same as the C function GDALEndAsyncReader().
5066 : *
5067 : * @param poARIO pointer to a GDALAsyncReader
5068 : */
5069 :
5070 1 : void GDALDataset::EndAsyncReader(GDALAsyncReader *poARIO)
5071 : {
5072 1 : delete poARIO;
5073 1 : }
5074 :
5075 : /************************************************************************/
5076 : /* GDALEndAsyncReader() */
5077 : /************************************************************************/
5078 :
5079 : /**
5080 : * End asynchronous request.
5081 : *
5082 : * This method destroys an asynchronous io request and recovers all
5083 : * resources associated with it.
5084 : *
5085 : * This method is the same as the C++ method GDALDataset::EndAsyncReader().
5086 : *
5087 : * @param hDS handle to the dataset object.
5088 : * @param hAsyncReaderH handle returned by GDALBeginAsyncReader()
5089 : */
5090 :
5091 1 : void CPL_STDCALL GDALEndAsyncReader(GDALDatasetH hDS,
5092 : GDALAsyncReaderH hAsyncReaderH)
5093 : {
5094 1 : VALIDATE_POINTER0(hDS, "GDALDataset");
5095 1 : VALIDATE_POINTER0(hAsyncReaderH, "GDALAsyncReader");
5096 1 : GDALDataset::FromHandle(hDS)->EndAsyncReader(
5097 1 : static_cast<GDALAsyncReader *>(hAsyncReaderH));
5098 : }
5099 :
5100 : /************************************************************************/
5101 : /* CloseDependentDatasets() */
5102 : /************************************************************************/
5103 :
5104 : /**
5105 : * Drop references to any other datasets referenced by this dataset.
5106 : *
5107 : * This method should release any reference to other datasets (e.g. a VRT
5108 : * dataset to its sources), but not close the current dataset itself.
5109 : *
5110 : * If at least, one reference to a dependent dataset has been dropped,
5111 : * this method should return TRUE. Otherwise it *should* return FALSE.
5112 : * (Failure to return the proper value might result in infinite loop)
5113 : *
5114 : * This method can be called several times on a given dataset. After
5115 : * the first time, it should not do anything and return FALSE.
5116 : *
5117 : * The driver implementation may choose to destroy its raster bands,
5118 : * so be careful not to call any method on the raster bands afterwards.
5119 : *
5120 : * Basically the only safe action you can do after calling
5121 : * CloseDependentDatasets() is to call the destructor.
5122 : *
5123 : * Note: the only legitimate caller of CloseDependentDatasets() is
5124 : * GDALDriverManager::~GDALDriverManager()
5125 : *
5126 : * @return TRUE if at least one reference to another dataset has been dropped.
5127 : */
5128 19916 : int GDALDataset::CloseDependentDatasets()
5129 : {
5130 19916 : return oOvManager.CloseDependentDatasets();
5131 : }
5132 :
5133 : /************************************************************************/
5134 : /* ReportError() */
5135 : /************************************************************************/
5136 :
5137 : #ifndef DOXYGEN_XML
5138 : /**
5139 : * \brief Emits an error related to a dataset.
5140 : *
5141 : * This function is a wrapper for regular CPLError(). The only difference
5142 : * with CPLError() is that it prepends the error message with the dataset
5143 : * name.
5144 : *
5145 : * @param eErrClass one of CE_Warning, CE_Failure or CE_Fatal.
5146 : * @param err_no the error number (CPLE_*) from cpl_error.h.
5147 : * @param fmt a printf() style format string. Any additional arguments
5148 : * will be treated as arguments to fill in this format in a manner
5149 : * similar to printf().
5150 : *
5151 : */
5152 :
5153 105 : void GDALDataset::ReportError(CPLErr eErrClass, CPLErrorNum err_no,
5154 : const char *fmt, ...) const
5155 : {
5156 : va_list args;
5157 105 : va_start(args, fmt);
5158 105 : ReportErrorV(GetDescription(), eErrClass, err_no, fmt, args);
5159 105 : va_end(args);
5160 105 : }
5161 :
5162 : /**
5163 : * \brief Emits an error related to a dataset (static method)
5164 : *
5165 : * This function is a wrapper for regular CPLError(). The only difference
5166 : * with CPLError() is that it prepends the error message with the dataset
5167 : * name.
5168 : *
5169 : * @param pszDSName dataset name.
5170 : * @param eErrClass one of CE_Warning, CE_Failure or CE_Fatal.
5171 : * @param err_no the error number (CPLE_*) from cpl_error.h.
5172 : * @param fmt a printf() style format string. Any additional arguments
5173 : * will be treated as arguments to fill in this format in a manner
5174 : * similar to printf().
5175 : *
5176 : * @since GDAL 3.2.0
5177 : */
5178 :
5179 187 : void GDALDataset::ReportError(const char *pszDSName, CPLErr eErrClass,
5180 : CPLErrorNum err_no, const char *fmt, ...)
5181 : {
5182 : va_list args;
5183 187 : va_start(args, fmt);
5184 187 : ReportErrorV(pszDSName, eErrClass, err_no, fmt, args);
5185 187 : va_end(args);
5186 187 : }
5187 :
5188 292 : void GDALDataset::ReportErrorV(const char *pszDSName, CPLErr eErrClass,
5189 : CPLErrorNum err_no, const char *fmt,
5190 : va_list args)
5191 : {
5192 292 : pszDSName = CPLGetFilename(pszDSName);
5193 292 : if (pszDSName[0] != '\0')
5194 : {
5195 275 : CPLError(eErrClass, err_no, "%s",
5196 550 : std::string(pszDSName)
5197 275 : .append(": ")
5198 550 : .append(CPLString().vPrintf(fmt, args))
5199 : .c_str());
5200 : }
5201 : else
5202 : {
5203 17 : CPLErrorV(eErrClass, err_no, fmt, args);
5204 : }
5205 292 : }
5206 : #endif
5207 :
5208 : /************************************************************************/
5209 : /* GetMetadata() */
5210 : /************************************************************************/
5211 73867 : CSLConstList GDALDataset::GetMetadata(const char *pszDomain)
5212 : {
5213 : #ifndef WITHOUT_DERIVED
5214 73867 : if (pszDomain != nullptr && EQUAL(pszDomain, "DERIVED_SUBDATASETS"))
5215 : {
5216 10 : oDerivedMetadataList.Clear();
5217 :
5218 : // First condition: at least one raster band.
5219 10 : if (GetRasterCount() > 0)
5220 : {
5221 : // Check if there is at least one complex band.
5222 10 : bool hasAComplexBand = false;
5223 :
5224 19 : for (int rasterId = 1; rasterId <= GetRasterCount(); ++rasterId)
5225 : {
5226 11 : if (GDALDataTypeIsComplex(
5227 11 : GetRasterBand(rasterId)->GetRasterDataType()))
5228 : {
5229 2 : hasAComplexBand = true;
5230 2 : break;
5231 : }
5232 : }
5233 :
5234 10 : unsigned int nbSupportedDerivedDS = 0;
5235 : const DerivedDatasetDescription *poDDSDesc =
5236 10 : GDALGetDerivedDatasetDescriptions(&nbSupportedDerivedDS);
5237 :
5238 10 : int nNumDataset = 1;
5239 80 : for (unsigned int derivedId = 0; derivedId < nbSupportedDerivedDS;
5240 : ++derivedId)
5241 : {
5242 126 : if (hasAComplexBand ||
5243 126 : CPLString(poDDSDesc[derivedId].pszInputPixelType) !=
5244 : "complex")
5245 : {
5246 : oDerivedMetadataList.SetNameValue(
5247 : CPLSPrintf("DERIVED_SUBDATASET_%d_NAME", nNumDataset),
5248 : CPLSPrintf("DERIVED_SUBDATASET:%s:%s",
5249 22 : poDDSDesc[derivedId].pszDatasetName,
5250 22 : GetDescription()));
5251 :
5252 : CPLString osDesc(
5253 : CPLSPrintf("%s from %s",
5254 22 : poDDSDesc[derivedId].pszDatasetDescription,
5255 22 : GetDescription()));
5256 : oDerivedMetadataList.SetNameValue(
5257 : CPLSPrintf("DERIVED_SUBDATASET_%d_DESC", nNumDataset),
5258 22 : osDesc.c_str());
5259 :
5260 22 : nNumDataset++;
5261 : }
5262 : }
5263 : }
5264 10 : return oDerivedMetadataList.List();
5265 : }
5266 : #endif
5267 :
5268 73857 : return GDALMajorObject::GetMetadata(pszDomain);
5269 : }
5270 :
5271 : // clang-format off
5272 :
5273 : /**
5274 : * \fn GDALDataset::SetMetadata( char ** papszMetadata, const char * pszDomain)
5275 : * \brief Set metadata.
5276 : *
5277 : * CAUTION: depending on the format, older values of the updated information
5278 : * might still be found in the file in a "ghost" state, even if no longer
5279 : * accessible through the GDAL API. This is for example the case of the GTiff
5280 : * format (this is not a exhaustive list)
5281 : *
5282 : * The C function GDALSetMetadata() does the same thing as this method.
5283 : *
5284 : * @param papszMetadata the metadata in name=value string list format to
5285 : * apply.
5286 : * @param pszDomain the domain of interest. Use "" or NULL for the default
5287 : * domain.
5288 : * @return CE_None on success, CE_Failure on failure and CE_Warning if the
5289 : * metadata has been accepted, but is likely not maintained persistently
5290 : * by the underlying object between sessions.
5291 : */
5292 :
5293 : /**
5294 : * \fn GDALDataset::SetMetadataItem( const char * pszName, const char * pszValue, const char * pszDomain)
5295 : * \brief Set single metadata item.
5296 : *
5297 : * CAUTION: depending on the format, older values of the updated information
5298 : * might still be found in the file in a "ghost" state, even if no longer
5299 : * accessible through the GDAL API. This is for example the case of the GTiff
5300 : * format (this is not a exhaustive list)
5301 : *
5302 : * The C function GDALSetMetadataItem() does the same thing as this method.
5303 : *
5304 : * @param pszName the key for the metadata item to fetch.
5305 : * @param pszValue the value to assign to the key.
5306 : * @param pszDomain the domain to set within, use NULL for the default domain.
5307 : *
5308 : * @return CE_None on success, or an error code on failure.
5309 : */
5310 :
5311 : // clang-format on
5312 :
5313 : /************************************************************************/
5314 : /* GetMetadataDomainList() */
5315 : /************************************************************************/
5316 :
5317 1101 : char **GDALDataset::GetMetadataDomainList()
5318 : {
5319 1101 : char **currentDomainList = CSLDuplicate(oMDMD.GetDomainList());
5320 :
5321 : // Ensure that we do not duplicate DERIVED domain.
5322 1248 : if (GetRasterCount() > 0 &&
5323 147 : CSLFindString(currentDomainList, "DERIVED_SUBDATASETS") == -1)
5324 : {
5325 : currentDomainList =
5326 147 : CSLAddString(currentDomainList, "DERIVED_SUBDATASETS");
5327 : }
5328 1101 : return currentDomainList;
5329 : }
5330 :
5331 : /************************************************************************/
5332 : /* GetDriverName() */
5333 : /************************************************************************/
5334 :
5335 : /** Return driver name.
5336 : * @return driver name.
5337 : */
5338 2356 : const char *GDALDataset::GetDriverName() const
5339 : {
5340 2356 : if (poDriver)
5341 2342 : return poDriver->GetDescription();
5342 14 : return "";
5343 : }
5344 :
5345 : /************************************************************************/
5346 : /* GDALDatasetReleaseResultSet() */
5347 : /************************************************************************/
5348 :
5349 : /**
5350 : \brief Release results of ExecuteSQL().
5351 :
5352 : This function should only be used to deallocate OGRLayers resulting from
5353 : an ExecuteSQL() call on the same GDALDataset. Failure to deallocate a
5354 : results set before destroying the GDALDataset may cause errors.
5355 :
5356 : This function is the same as the C++ method GDALDataset::ReleaseResultSet()
5357 :
5358 :
5359 : @param hDS the dataset handle.
5360 : @param hLayer the result of a previous ExecuteSQL() call.
5361 :
5362 : */
5363 3546 : void GDALDatasetReleaseResultSet(GDALDatasetH hDS, OGRLayerH hLayer)
5364 :
5365 : {
5366 3546 : VALIDATE_POINTER0(hDS, "GDALDatasetReleaseResultSet");
5367 :
5368 : #ifdef OGRAPISPY_ENABLED
5369 3546 : if (bOGRAPISpyEnabled)
5370 6 : OGRAPISpy_DS_ReleaseResultSet(hDS, hLayer);
5371 : #endif
5372 :
5373 7092 : GDALDataset::FromHandle(hDS)->ReleaseResultSet(
5374 3546 : OGRLayer::FromHandle(hLayer));
5375 : }
5376 :
5377 : /************************************************************************/
5378 : /* GDALDatasetGetLayerCount() */
5379 : /************************************************************************/
5380 :
5381 : /**
5382 : \brief Get the number of layers in this dataset.
5383 :
5384 : This function is the same as the C++ method GDALDataset::GetLayerCount()
5385 :
5386 :
5387 : @param hDS the dataset handle.
5388 : @return layer count.
5389 : */
5390 :
5391 1605 : int GDALDatasetGetLayerCount(GDALDatasetH hDS)
5392 :
5393 : {
5394 1605 : VALIDATE_POINTER1(hDS, "GDALDatasetH", 0);
5395 :
5396 : #ifdef OGRAPISPY_ENABLED
5397 1605 : if (bOGRAPISpyEnabled)
5398 2 : OGRAPISpy_DS_GetLayerCount(reinterpret_cast<GDALDatasetH>(hDS));
5399 : #endif
5400 :
5401 1605 : return GDALDataset::FromHandle(hDS)->GetLayerCount();
5402 : }
5403 :
5404 : /************************************************************************/
5405 : /* GDALDatasetGetLayer() */
5406 : /************************************************************************/
5407 :
5408 : /**
5409 : \brief Fetch a layer by index.
5410 :
5411 : The returned layer remains owned by the
5412 : GDALDataset and should not be deleted by the application.
5413 :
5414 : This function is the same as the C++ method GDALDataset::GetLayer()
5415 :
5416 :
5417 : @param hDS the dataset handle.
5418 : @param iLayer a layer number between 0 and GetLayerCount()-1.
5419 :
5420 : @return the layer, or NULL if iLayer is out of range or an error occurs.
5421 : */
5422 :
5423 10091 : OGRLayerH GDALDatasetGetLayer(GDALDatasetH hDS, int iLayer)
5424 :
5425 : {
5426 10091 : VALIDATE_POINTER1(hDS, "GDALDatasetGetLayer", nullptr);
5427 :
5428 : OGRLayerH hLayer =
5429 10091 : OGRLayer::ToHandle(GDALDataset::FromHandle(hDS)->GetLayer(iLayer));
5430 :
5431 : #ifdef OGRAPISPY_ENABLED
5432 10091 : if (bOGRAPISpyEnabled)
5433 3 : OGRAPISpy_DS_GetLayer(hDS, iLayer, hLayer);
5434 : #endif
5435 :
5436 10091 : return hLayer;
5437 : }
5438 :
5439 : /************************************************************************/
5440 : /* GDALDatasetGetLayerByName() */
5441 : /************************************************************************/
5442 :
5443 : /**
5444 : \brief Fetch a layer by name.
5445 :
5446 : The returned layer remains owned by the
5447 : GDALDataset and should not be deleted by the application.
5448 :
5449 : This function is the same as the C++ method GDALDataset::GetLayerByName()
5450 :
5451 :
5452 : @param hDS the dataset handle.
5453 : @param pszName the layer name of the layer to fetch.
5454 :
5455 : @return the layer, or NULL if Layer is not found or an error occurs.
5456 : */
5457 :
5458 3420 : OGRLayerH GDALDatasetGetLayerByName(GDALDatasetH hDS, const char *pszName)
5459 :
5460 : {
5461 3420 : VALIDATE_POINTER1(hDS, "GDALDatasetGetLayerByName", nullptr);
5462 :
5463 3420 : OGRLayerH hLayer = OGRLayer::ToHandle(
5464 3420 : GDALDataset::FromHandle(hDS)->GetLayerByName(pszName));
5465 :
5466 : #ifdef OGRAPISPY_ENABLED
5467 3420 : if (bOGRAPISpyEnabled)
5468 4 : OGRAPISpy_DS_GetLayerByName(hDS, pszName, hLayer);
5469 : #endif
5470 :
5471 3420 : return hLayer;
5472 : }
5473 :
5474 : /************************************************************************/
5475 : /* GDALDatasetIsLayerPrivate() */
5476 : /************************************************************************/
5477 :
5478 : /**
5479 : \brief Returns true if the layer at the specified index is deemed a private or
5480 : system table, or an internal detail only.
5481 :
5482 : This function is the same as the C++ method GDALDataset::IsLayerPrivate()
5483 :
5484 : @since GDAL 3.4
5485 :
5486 : @param hDS the dataset handle.
5487 : @param iLayer a layer number between 0 and GetLayerCount()-1.
5488 :
5489 : @return true if the layer is a private or system table.
5490 : */
5491 :
5492 91 : int GDALDatasetIsLayerPrivate(GDALDatasetH hDS, int iLayer)
5493 :
5494 : {
5495 91 : VALIDATE_POINTER1(hDS, "GDALDatasetIsLayerPrivate", false);
5496 :
5497 91 : const bool res = GDALDataset::FromHandle(hDS)->IsLayerPrivate(iLayer);
5498 :
5499 91 : return res ? 1 : 0;
5500 : }
5501 :
5502 : /************************************************************************/
5503 : /* GetLayerIndex() */
5504 : /************************************************************************/
5505 :
5506 : /**
5507 : \brief Returns the index of the layer specified by name.
5508 :
5509 : @since GDAL 3.12
5510 :
5511 : @param pszName layer name (not NULL)
5512 :
5513 : @return an index >= 0, or -1 if not found.
5514 : */
5515 :
5516 3 : int GDALDataset::GetLayerIndex(const char *pszName) const
5517 : {
5518 3 : const int nLayerCount = GetLayerCount();
5519 3 : int iMatch = -1;
5520 6 : for (int i = 0; i < nLayerCount; ++i)
5521 : {
5522 5 : if (const auto poLayer = GetLayer(i))
5523 : {
5524 5 : const char *pszLayerName = poLayer->GetDescription();
5525 5 : if (strcmp(pszName, pszLayerName) == 0)
5526 : {
5527 2 : iMatch = i;
5528 2 : break;
5529 : }
5530 3 : else if (EQUAL(pszName, pszLayerName))
5531 : {
5532 0 : iMatch = i;
5533 : }
5534 : }
5535 : }
5536 3 : return iMatch;
5537 : }
5538 :
5539 : /************************************************************************/
5540 : /* GDALDatasetDeleteLayer() */
5541 : /************************************************************************/
5542 :
5543 : /**
5544 : \brief Delete the indicated layer from the datasource.
5545 :
5546 : If this function is supported
5547 : the ODsCDeleteLayer capability will test TRUE on the GDALDataset.
5548 :
5549 : This method is the same as the C++ method GDALDataset::DeleteLayer().
5550 :
5551 :
5552 : @param hDS the dataset handle.
5553 : @param iLayer the index of the layer to delete.
5554 :
5555 : @return OGRERR_NONE on success, or OGRERR_UNSUPPORTED_OPERATION if deleting
5556 : layers is not supported for this datasource.
5557 :
5558 : */
5559 41 : OGRErr GDALDatasetDeleteLayer(GDALDatasetH hDS, int iLayer)
5560 :
5561 : {
5562 41 : VALIDATE_POINTER1(hDS, "GDALDatasetH", OGRERR_INVALID_HANDLE);
5563 :
5564 : #ifdef OGRAPISPY_ENABLED
5565 41 : if (bOGRAPISpyEnabled)
5566 2 : OGRAPISpy_DS_DeleteLayer(hDS, iLayer);
5567 : #endif
5568 :
5569 41 : return GDALDataset::FromHandle(hDS)->DeleteLayer(iLayer);
5570 : }
5571 :
5572 : /************************************************************************/
5573 : /* CreateLayer() */
5574 : /************************************************************************/
5575 :
5576 : /**
5577 : \brief This method attempts to create a new layer on the dataset with the
5578 : indicated name, coordinate system, geometry type.
5579 :
5580 : The papszOptions argument
5581 : can be used to control driver specific creation options. These options are
5582 : normally documented in the format specific documentation.
5583 : That function will try to validate the creation option list passed to the
5584 : driver with the GDALValidateCreationOptions() method. This check can be
5585 : disabled by defining the configuration option GDAL_VALIDATE_CREATION_OPTIONS set
5586 : to NO.
5587 :
5588 : Drivers should extend the ICreateLayer() method and not
5589 : CreateLayer(). CreateLayer() adds validation of layer creation options, before
5590 : delegating the actual work to ICreateLayer().
5591 :
5592 : This method is the same as the C function GDALDatasetCreateLayer() and the
5593 : deprecated OGR_DS_CreateLayer().
5594 :
5595 : Example:
5596 :
5597 : \code{.cpp}
5598 : #include "gdal.h"
5599 : #include "cpl_string.h"
5600 :
5601 : ...
5602 :
5603 : OGRLayer *poLayer;
5604 : char **papszOptions;
5605 :
5606 : if( !poDS->TestCapability( ODsCCreateLayer ) )
5607 : {
5608 : ...
5609 : }
5610 :
5611 : papszOptions = CSLSetNameValue( papszOptions, "DIM", "2" );
5612 : poLayer = poDS->CreateLayer( "NewLayer", nullptr, wkbUnknown,
5613 : papszOptions );
5614 : CSLDestroy( papszOptions );
5615 :
5616 : if( poLayer == NULL )
5617 : {
5618 : ...
5619 : }
5620 : \endcode
5621 :
5622 : @param pszName the name for the new layer. This should ideally not
5623 : match any existing layer on the datasource.
5624 : @param poSpatialRef the coordinate system to use for the new layer, or NULL if
5625 : no coordinate system is available.
5626 : @param eGType the geometry type for the layer. Use wkbUnknown if there
5627 : are no constraints on the types geometry to be written.
5628 : @param papszOptions a StringList of name=value options. Options are driver
5629 : specific.
5630 :
5631 : @return NULL is returned on failure, or a new OGRLayer handle on success.
5632 :
5633 : */
5634 :
5635 8395 : OGRLayer *GDALDataset::CreateLayer(const char *pszName,
5636 : const OGRSpatialReference *poSpatialRef,
5637 : OGRwkbGeometryType eGType,
5638 : CSLConstList papszOptions)
5639 :
5640 : {
5641 8395 : if (eGType == wkbNone)
5642 : {
5643 525 : return CreateLayer(pszName, nullptr, papszOptions);
5644 : }
5645 : else
5646 : {
5647 15740 : OGRGeomFieldDefn oGeomFieldDefn("", eGType);
5648 7870 : oGeomFieldDefn.SetSpatialRef(poSpatialRef);
5649 7870 : return CreateLayer(pszName, &oGeomFieldDefn, papszOptions);
5650 : }
5651 : }
5652 :
5653 : /**
5654 : \brief This method attempts to create a new layer on the dataset with the
5655 : indicated name and geometry field definition.
5656 :
5657 : When poGeomFieldDefn is not null, most drivers should honor
5658 : poGeomFieldDefn->GetType() and poGeomFieldDefn->GetSpatialRef().
5659 : Drivers that honor poGeomFieldDefn->GetCoordinatePrecision() will declare the
5660 : GDAL_DCAP_HONOR_GEOM_COORDINATE_PRECISION capability. Drivers may honor
5661 : poGeomFieldDefn->GetNameRef() and poGeomFieldDefn->IsNullable(), but there are
5662 : very few currently.
5663 :
5664 : Note that even if a geometry coordinate precision is set and a driver honors the
5665 : GDAL_DCAP_HONOR_GEOM_COORDINATE_PRECISION capability, geometries passed to
5666 : OGRLayer::CreateFeature() and OGRLayer::SetFeature() are assumed to be compatible
5667 : with the coordinate precision. That is they are assumed to be valid once their
5668 : coordinates are rounded to it. If it might not be the case, the user may set
5669 : the OGR_APPLY_GEOM_SET_PRECISION configuration option before calling CreateFeature()
5670 : or SetFeature() to force the OGRGeometry::SetPrecision() method to be called on
5671 : the passed geometries.
5672 :
5673 : The papszOptions argument
5674 : can be used to control driver specific creation options. These options are
5675 : normally documented in the format specific documentation.
5676 : This function will try to validate the creation option list passed to the
5677 : driver with the GDALValidateCreationOptions() method. This check can be
5678 : disabled by defining the configuration option GDAL_VALIDATE_CREATION_OPTIONS set
5679 : to NO.
5680 :
5681 : Drivers should extend the ICreateLayer() method and not
5682 : CreateLayer(). CreateLayer() adds validation of layer creation options, before
5683 : delegating the actual work to ICreateLayer().
5684 :
5685 : This method is the same as the C function GDALDatasetCreateLayerFromGeomFieldDefn().
5686 :
5687 : @param pszName the name for the new layer. This should ideally not
5688 : match any existing layer on the datasource.
5689 : @param poGeomFieldDefn the geometry field definition to use for the new layer,
5690 : or NULL if there is no geometry field.
5691 : @param papszOptions a StringList of name=value options. Options are driver
5692 : specific.
5693 :
5694 : @return NULL is returned on failure, or a new OGRLayer handle on success.
5695 : @since 3.9
5696 :
5697 : */
5698 :
5699 9834 : OGRLayer *GDALDataset::CreateLayer(const char *pszName,
5700 : const OGRGeomFieldDefn *poGeomFieldDefn,
5701 : CSLConstList papszOptions)
5702 :
5703 : {
5704 9834 : if (CPLTestBool(
5705 : CPLGetConfigOption("GDAL_VALIDATE_CREATION_OPTIONS", "YES")))
5706 : {
5707 9834 : ValidateLayerCreationOptions(papszOptions);
5708 : }
5709 :
5710 : OGRLayer *poLayer;
5711 9834 : if (poGeomFieldDefn)
5712 : {
5713 8896 : OGRGeomFieldDefn oGeomFieldDefn(poGeomFieldDefn);
5714 8990 : if (OGR_GT_IsNonLinear(poGeomFieldDefn->GetType()) &&
5715 94 : !TestCapability(ODsCCurveGeometries))
5716 : {
5717 23 : oGeomFieldDefn.SetType(
5718 : OGR_GT_GetLinear(poGeomFieldDefn->GetType()));
5719 : }
5720 :
5721 8896 : poLayer = ICreateLayer(pszName, &oGeomFieldDefn, papszOptions);
5722 : }
5723 : else
5724 : {
5725 938 : poLayer = ICreateLayer(pszName, nullptr, papszOptions);
5726 : }
5727 : #ifdef DEBUG
5728 9905 : if (poLayer != nullptr && OGR_GT_IsNonLinear(poLayer->GetGeomType()) &&
5729 71 : !poLayer->TestCapability(OLCCurveGeometries))
5730 : {
5731 0 : CPLError(CE_Warning, CPLE_AppDefined,
5732 : "Inconsistent driver: Layer geometry type is non-linear, but "
5733 : "TestCapability(OLCCurveGeometries) returns FALSE.");
5734 : }
5735 : #endif
5736 :
5737 9834 : return poLayer;
5738 : }
5739 :
5740 : //! @cond Doxygen_Suppress
5741 :
5742 : // Technical override to avoid ambiguous choice between the old and new
5743 : // new CreateLayer() signatures.
5744 12 : OGRLayer *GDALDataset::CreateLayer(const char *pszName)
5745 : {
5746 24 : OGRGeomFieldDefn oGeomFieldDefn("", wkbUnknown);
5747 24 : return CreateLayer(pszName, &oGeomFieldDefn, nullptr);
5748 : }
5749 :
5750 : // Technical override to avoid ambiguous choice between the old and new
5751 : // new CreateLayer() signatures.
5752 1 : OGRLayer *GDALDataset::CreateLayer(const char *pszName, std::nullptr_t)
5753 : {
5754 2 : OGRGeomFieldDefn oGeomFieldDefn("", wkbUnknown);
5755 2 : return CreateLayer(pszName, &oGeomFieldDefn, nullptr);
5756 : }
5757 :
5758 : //!@endcond
5759 :
5760 : /************************************************************************/
5761 : /* GDALDatasetCreateLayer() */
5762 : /************************************************************************/
5763 :
5764 : /**
5765 : \brief This function attempts to create a new layer on the dataset with the
5766 : indicated name, coordinate system, geometry type.
5767 :
5768 : The papszOptions argument can be used to control driver specific creation
5769 : options. These options are normally documented in the format specific
5770 : documentation.
5771 :
5772 : This method is the same as the C++ method GDALDataset::CreateLayer().
5773 :
5774 : Example:
5775 :
5776 : \code{.c}
5777 : #include "gdal.h"
5778 : #include "cpl_string.h"
5779 :
5780 : ...
5781 :
5782 : OGRLayerH hLayer;
5783 : char **papszOptions;
5784 :
5785 : if( !GDALDatasetTestCapability( hDS, ODsCCreateLayer ) )
5786 : {
5787 : ...
5788 : }
5789 :
5790 : papszOptions = CSLSetNameValue( papszOptions, "DIM", "2" );
5791 : hLayer = GDALDatasetCreateLayer( hDS, "NewLayer", NULL, wkbUnknown,
5792 : papszOptions );
5793 : CSLDestroy( papszOptions );
5794 :
5795 : if( hLayer == NULL )
5796 : {
5797 : ...
5798 : }
5799 : \endcode
5800 :
5801 :
5802 : @param hDS the dataset handle
5803 : @param pszName the name for the new layer. This should ideally not
5804 : match any existing layer on the datasource.
5805 : @param hSpatialRef the coordinate system to use for the new layer, or NULL if
5806 : no coordinate system is available.
5807 : @param eGType the geometry type for the layer. Use wkbUnknown if there
5808 : are no constraints on the types geometry to be written.
5809 : @param papszOptions a StringList of name=value options. Options are driver
5810 : specific.
5811 :
5812 : @return NULL is returned on failure, or a new OGRLayer handle on success.
5813 :
5814 : */
5815 :
5816 6522 : OGRLayerH GDALDatasetCreateLayer(GDALDatasetH hDS, const char *pszName,
5817 : OGRSpatialReferenceH hSpatialRef,
5818 : OGRwkbGeometryType eGType,
5819 : CSLConstList papszOptions)
5820 :
5821 : {
5822 6522 : VALIDATE_POINTER1(hDS, "GDALDatasetCreateLayer", nullptr);
5823 :
5824 6522 : if (pszName == nullptr)
5825 : {
5826 0 : CPLError(CE_Failure, CPLE_ObjectNull,
5827 : "Name was NULL in GDALDatasetCreateLayer");
5828 0 : return nullptr;
5829 : }
5830 :
5831 : OGRLayerH hLayer =
5832 13044 : OGRLayer::ToHandle(GDALDataset::FromHandle(hDS)->CreateLayer(
5833 6522 : pszName, OGRSpatialReference::FromHandle(hSpatialRef), eGType,
5834 : const_cast<char **>(papszOptions)));
5835 :
5836 : #ifdef OGRAPISPY_ENABLED
5837 6522 : if (bOGRAPISpyEnabled)
5838 8 : OGRAPISpy_DS_CreateLayer(hDS, pszName, hSpatialRef, eGType,
5839 : const_cast<char **>(papszOptions), hLayer);
5840 : #endif
5841 :
5842 6522 : return hLayer;
5843 : }
5844 :
5845 : /************************************************************************/
5846 : /* GDALDatasetCreateLayerFromGeomFieldDefn() */
5847 : /************************************************************************/
5848 :
5849 : /**
5850 : \brief This function attempts to create a new layer on the dataset with the
5851 : indicated name and geometry field.
5852 :
5853 : When poGeomFieldDefn is not null, most drivers should honor
5854 : poGeomFieldDefn->GetType() and poGeomFieldDefn->GetSpatialRef().
5855 : Drivers that honor poGeomFieldDefn->GetCoordinatePrecision() will declare the
5856 : GDAL_DCAP_HONOR_GEOM_COORDINATE_PRECISION capability. Drivers may honor
5857 : poGeomFieldDefn->GetNameRef() and poGeomFieldDefn->IsNullable(), but there are
5858 : very few currently.
5859 :
5860 : Note that even if a geometry coordinate precision is set and a driver honors the
5861 : GDAL_DCAP_HONOR_GEOM_COORDINATE_PRECISION capability, geometries passed to
5862 : OGRLayer::CreateFeature() and OGRLayer::SetFeature() are assumed to be compatible
5863 : with the coordinate precision. That is they are assumed to be valid once their
5864 : coordinates are rounded to it. If it might not be the case, the user may set
5865 : the OGR_APPLY_GEOM_SET_PRECISION configuration option before calling CreateFeature()
5866 : or SetFeature() to force the OGRGeometry::SetPrecision() method to be called on
5867 : the passed geometries.
5868 :
5869 : The papszOptions argument can be used to control driver specific creation
5870 : options. These options are normally documented in the format specific
5871 : documentation.
5872 :
5873 : This method is the same as the C++ method GDALDataset::CreateLayer().
5874 :
5875 : @param hDS the dataset handle
5876 : @param pszName the name for the new layer. This should ideally not
5877 : match any existing layer on the datasource.
5878 : @param hGeomFieldDefn the geometry field definition. May be NULL to indicate
5879 : a non-spatial file (or if adding geometry fields later with OGR_L_CreateGeomField()
5880 : for drivers supporting that interface).
5881 : @param papszOptions a StringList of name=value options. Options are driver
5882 : specific.
5883 :
5884 : @return NULL is returned on failure, or a new OGRLayer handle on success.
5885 :
5886 : @since GDAL 3.9
5887 :
5888 : */
5889 :
5890 : OGRLayerH
5891 14 : GDALDatasetCreateLayerFromGeomFieldDefn(GDALDatasetH hDS, const char *pszName,
5892 : OGRGeomFieldDefnH hGeomFieldDefn,
5893 : CSLConstList papszOptions)
5894 :
5895 : {
5896 14 : VALIDATE_POINTER1(hDS, "GDALDatasetCreateLayerFromGeomFieldDefn", nullptr);
5897 :
5898 14 : if (!pszName)
5899 : {
5900 0 : CPLError(CE_Failure, CPLE_ObjectNull,
5901 : "Name was NULL in GDALDatasetCreateLayerFromGeomFieldDefn");
5902 0 : return nullptr;
5903 : }
5904 :
5905 : OGRLayerH hLayer =
5906 28 : OGRLayer::ToHandle(GDALDataset::FromHandle(hDS)->CreateLayer(
5907 14 : pszName, OGRGeomFieldDefn::FromHandle(hGeomFieldDefn),
5908 : papszOptions));
5909 14 : return hLayer;
5910 : }
5911 :
5912 : /************************************************************************/
5913 : /* GDALDatasetCopyLayer() */
5914 : /************************************************************************/
5915 :
5916 : /**
5917 : \brief Duplicate an existing layer.
5918 :
5919 : This function creates a new layer, duplicate the field definitions of the
5920 : source layer and then duplicate each features of the source layer.
5921 : The papszOptions argument
5922 : can be used to control driver specific creation options. These options are
5923 : normally documented in the format specific documentation.
5924 : The source layer may come from another dataset.
5925 :
5926 : This method is the same as the C++ method GDALDataset::CopyLayer()
5927 :
5928 :
5929 : @param hDS the dataset handle.
5930 : @param hSrcLayer source layer.
5931 : @param pszNewName the name of the layer to create.
5932 : @param papszOptions a StringList of name=value options. Options are driver
5933 : specific.
5934 :
5935 : @return a handle to the layer, or NULL if an error occurs.
5936 : */
5937 48 : OGRLayerH GDALDatasetCopyLayer(GDALDatasetH hDS, OGRLayerH hSrcLayer,
5938 : const char *pszNewName,
5939 : CSLConstList papszOptions)
5940 :
5941 : {
5942 48 : VALIDATE_POINTER1(hDS, "OGR_DS_CopyGDALDatasetCopyLayerLayer", nullptr);
5943 48 : VALIDATE_POINTER1(hSrcLayer, "GDALDatasetCopyLayer", nullptr);
5944 48 : VALIDATE_POINTER1(pszNewName, "GDALDatasetCopyLayer", nullptr);
5945 :
5946 96 : return OGRLayer::ToHandle(GDALDataset::FromHandle(hDS)->CopyLayer(
5947 96 : OGRLayer::FromHandle(hSrcLayer), pszNewName, papszOptions));
5948 : }
5949 :
5950 : /************************************************************************/
5951 : /* GDALDatasetExecuteSQL() */
5952 : /************************************************************************/
5953 :
5954 : /**
5955 : \brief Execute an SQL statement against the data store.
5956 :
5957 : The result of an SQL query is either NULL for statements that are in error,
5958 : or that have no results set, or an OGRLayer pointer representing a results
5959 : set from the query. Note that this OGRLayer is in addition to the layers
5960 : in the data store and must be destroyed with
5961 : ReleaseResultSet() before the dataset is closed
5962 : (destroyed).
5963 :
5964 : This method is the same as the C++ method GDALDataset::ExecuteSQL()
5965 :
5966 : For more information on the SQL dialect supported internally by OGR
5967 : review the <a href="https://gdal.org/user/ogr_sql_dialect.html">OGR SQL</a>
5968 : document. Some drivers (i.e. Oracle and PostGIS) pass the SQL directly through
5969 : to the underlying RDBMS.
5970 :
5971 : Starting with OGR 1.10, the <a
5972 : href="https://gdal.org/user/sql_sqlite_dialect.html">SQLITE dialect</a> can
5973 : also be used.
5974 :
5975 :
5976 : @param hDS the dataset handle.
5977 : @param pszStatement the SQL statement to execute.
5978 : @param hSpatialFilter geometry which represents a spatial filter. Can be NULL.
5979 :
5980 : @param pszDialect allows control of the statement dialect. If set to NULL, the
5981 : OGR SQL engine will be used, except for RDBMS drivers that will use their
5982 : dedicated SQL engine, unless OGRSQL is explicitly passed as the
5983 : dialect. Starting with OGR 1.10, the SQLITE dialect can also be used.
5984 :
5985 : @return an OGRLayer containing the results of the query. Deallocate with
5986 : GDALDatasetReleaseResultSet().
5987 :
5988 : */
5989 :
5990 10623 : OGRLayerH GDALDatasetExecuteSQL(GDALDatasetH hDS, const char *pszStatement,
5991 : OGRGeometryH hSpatialFilter,
5992 : const char *pszDialect)
5993 :
5994 : {
5995 10623 : VALIDATE_POINTER1(hDS, "GDALDatasetExecuteSQL", nullptr);
5996 :
5997 : OGRLayerH hLayer =
5998 21246 : OGRLayer::ToHandle(GDALDataset::FromHandle(hDS)->ExecuteSQL(
5999 10623 : pszStatement, OGRGeometry::FromHandle(hSpatialFilter), pszDialect));
6000 :
6001 : #ifdef OGRAPISPY_ENABLED
6002 10623 : if (bOGRAPISpyEnabled)
6003 4 : OGRAPISpy_DS_ExecuteSQL(hDS, pszStatement, hSpatialFilter, pszDialect,
6004 : hLayer);
6005 : #endif
6006 :
6007 10623 : return hLayer;
6008 : }
6009 :
6010 : /************************************************************************/
6011 : /* GDALDatasetAbortSQL() */
6012 : /************************************************************************/
6013 :
6014 : /**
6015 : \brief Abort any SQL statement running in the data store.
6016 :
6017 : This function can be safely called from any thread (pending that the dataset
6018 : object is still alive). Driver implementations will make sure that it can be
6019 : called in a thread-safe way.
6020 :
6021 : This might not be implemented by all drivers. At time of writing, only SQLite,
6022 : GPKG and PG drivers implement it
6023 :
6024 : This method is the same as the C++ method GDALDataset::AbortSQL()
6025 :
6026 : @since GDAL 3.2.0
6027 :
6028 : @param hDS the dataset handle.
6029 :
6030 : @return OGRERR_NONE on success, or OGRERR_UNSUPPORTED_OPERATION if AbortSQL
6031 : is not supported for this datasource. .
6032 :
6033 : */
6034 :
6035 6 : OGRErr GDALDatasetAbortSQL(GDALDatasetH hDS)
6036 :
6037 : {
6038 6 : VALIDATE_POINTER1(hDS, "GDALDatasetAbortSQL", OGRERR_FAILURE);
6039 6 : return GDALDataset::FromHandle(hDS)->AbortSQL();
6040 : }
6041 :
6042 : /************************************************************************/
6043 : /* GDALDatasetGetStyleTable() */
6044 : /************************************************************************/
6045 :
6046 : /**
6047 : \brief Returns dataset style table.
6048 :
6049 : This function is the same as the C++ method GDALDataset::GetStyleTable()
6050 :
6051 :
6052 : @param hDS the dataset handle
6053 : @return handle to a style table which should not be modified or freed by the
6054 : caller.
6055 : */
6056 :
6057 6 : OGRStyleTableH GDALDatasetGetStyleTable(GDALDatasetH hDS)
6058 :
6059 : {
6060 6 : VALIDATE_POINTER1(hDS, "OGR_DS_GetStyleTable", nullptr);
6061 :
6062 : return reinterpret_cast<OGRStyleTableH>(
6063 6 : GDALDataset::FromHandle(hDS)->GetStyleTable());
6064 : }
6065 :
6066 : /************************************************************************/
6067 : /* GDALDatasetSetStyleTableDirectly() */
6068 : /************************************************************************/
6069 :
6070 : /**
6071 : \brief Set dataset style table.
6072 :
6073 : This function operate exactly as GDALDatasetSetStyleTable() except that it
6074 : assumes ownership of the passed table.
6075 :
6076 : This function is the same as the C++ method
6077 : GDALDataset::SetStyleTableDirectly()
6078 :
6079 :
6080 : @param hDS the dataset handle
6081 : @param hStyleTable style table handle to set
6082 :
6083 : */
6084 :
6085 0 : void GDALDatasetSetStyleTableDirectly(GDALDatasetH hDS,
6086 : OGRStyleTableH hStyleTable)
6087 :
6088 : {
6089 0 : VALIDATE_POINTER0(hDS, "OGR_DS_SetStyleTableDirectly");
6090 :
6091 0 : GDALDataset::FromHandle(hDS)->SetStyleTableDirectly(
6092 0 : reinterpret_cast<OGRStyleTable *>(hStyleTable));
6093 : }
6094 :
6095 : /************************************************************************/
6096 : /* GDALDatasetSetStyleTable() */
6097 : /************************************************************************/
6098 :
6099 : /**
6100 : \brief Set dataset style table.
6101 :
6102 : This function operate exactly as GDALDatasetSetStyleTableDirectly() except that
6103 : it assumes ownership of the passed table.
6104 :
6105 : This function is the same as the C++ method GDALDataset::SetStyleTable()
6106 :
6107 :
6108 : @param hDS the dataset handle
6109 : @param hStyleTable style table handle to set
6110 :
6111 : */
6112 :
6113 5 : void GDALDatasetSetStyleTable(GDALDatasetH hDS, OGRStyleTableH hStyleTable)
6114 :
6115 : {
6116 5 : VALIDATE_POINTER0(hDS, "OGR_DS_SetStyleTable");
6117 5 : VALIDATE_POINTER0(hStyleTable, "OGR_DS_SetStyleTable");
6118 :
6119 5 : GDALDataset::FromHandle(hDS)->SetStyleTable(
6120 5 : reinterpret_cast<OGRStyleTable *>(hStyleTable));
6121 : }
6122 :
6123 : /************************************************************************/
6124 : /* ValidateLayerCreationOptions() */
6125 : /************************************************************************/
6126 :
6127 : //! @cond Doxygen_Suppress
6128 9834 : int GDALDataset::ValidateLayerCreationOptions(const char *const *papszLCO)
6129 : {
6130 : const char *pszOptionList =
6131 9834 : GetMetadataItem(GDAL_DS_LAYER_CREATIONOPTIONLIST);
6132 9834 : if (pszOptionList == nullptr && poDriver != nullptr)
6133 : {
6134 : pszOptionList =
6135 9793 : poDriver->GetMetadataItem(GDAL_DS_LAYER_CREATIONOPTIONLIST);
6136 : }
6137 19668 : CPLString osDataset;
6138 9834 : osDataset.Printf("dataset %s", GetDescription());
6139 9834 : return GDALValidateOptions(pszOptionList, papszLCO, "layer creation option",
6140 19668 : osDataset);
6141 : }
6142 :
6143 : //! @endcond
6144 :
6145 : /************************************************************************/
6146 : /* Release() */
6147 : /************************************************************************/
6148 :
6149 : /**
6150 : \brief Drop a reference to this dataset, and if the reference count drops to one
6151 : close (destroy) the dataset.
6152 :
6153 : This method is the same as the C function OGRReleaseDataSource().
6154 :
6155 : @deprecated. Use GDALClose() instead
6156 :
6157 : @return OGRERR_NONE on success or an error code.
6158 : */
6159 :
6160 4514 : OGRErr GDALDataset::Release()
6161 :
6162 : {
6163 4514 : ReleaseRef();
6164 4514 : return OGRERR_NONE;
6165 : }
6166 :
6167 : /************************************************************************/
6168 : /* GetRefCount() */
6169 : /************************************************************************/
6170 :
6171 : /**
6172 : \brief Fetch reference count.
6173 :
6174 : This method is the same as the C function OGR_DS_GetRefCount().
6175 :
6176 : @return the current reference count for the datasource object itself.
6177 : */
6178 :
6179 5364 : int GDALDataset::GetRefCount() const
6180 : {
6181 5364 : return nRefCount;
6182 : }
6183 :
6184 : /************************************************************************/
6185 : /* GetSummaryRefCount() */
6186 : /************************************************************************/
6187 :
6188 : /**
6189 : \brief Fetch reference count of datasource and all owned layers.
6190 :
6191 : This method is the same as the C function OGR_DS_GetSummaryRefCount().
6192 :
6193 : @deprecated
6194 :
6195 : @return the current summary reference count for the datasource and its layers.
6196 : */
6197 :
6198 0 : int GDALDataset::GetSummaryRefCount() const
6199 :
6200 : {
6201 0 : CPLMutexHolderD(m_poPrivate ? &(m_poPrivate->hMutex) : nullptr);
6202 0 : int nSummaryCount = nRefCount;
6203 0 : GDALDataset *poUseThis = const_cast<GDALDataset *>(this);
6204 :
6205 0 : for (int iLayer = 0; iLayer < poUseThis->GetLayerCount(); ++iLayer)
6206 0 : nSummaryCount += poUseThis->GetLayer(iLayer)->GetRefCount();
6207 :
6208 0 : return nSummaryCount;
6209 : }
6210 :
6211 : /************************************************************************/
6212 : /* ICreateLayer() */
6213 : /************************************************************************/
6214 :
6215 : /**
6216 : \brief This method attempts to create a new layer on the dataset with the
6217 : indicated name, coordinate system, geometry type.
6218 :
6219 : This method is reserved to implementation by drivers.
6220 :
6221 : The papszOptions argument can be used to control driver specific creation
6222 : options. These options are normally documented in the format specific
6223 : documentation.
6224 :
6225 : @param pszName the name for the new layer. This should ideally not
6226 : match any existing layer on the datasource.
6227 : @param poGeomFieldDefn the geometry field definition to use for the new layer,
6228 : or NULL if there is no geometry field.
6229 : @param papszOptions a StringList of name=value options. Options are driver
6230 : specific.
6231 :
6232 : @return NULL is returned on failure, or a new OGRLayer handle on success.
6233 :
6234 : */
6235 :
6236 : OGRLayer *
6237 16 : GDALDataset::ICreateLayer(CPL_UNUSED const char *pszName,
6238 : CPL_UNUSED const OGRGeomFieldDefn *poGeomFieldDefn,
6239 : CPL_UNUSED CSLConstList papszOptions)
6240 :
6241 : {
6242 16 : CPLError(CE_Failure, CPLE_NotSupported,
6243 : "CreateLayer() not supported by this dataset.");
6244 :
6245 16 : return nullptr;
6246 : }
6247 :
6248 : /************************************************************************/
6249 : /* CopyLayer() */
6250 : /************************************************************************/
6251 :
6252 : /**
6253 : \brief Duplicate an existing layer.
6254 :
6255 : This method creates a new layer, duplicate the field definitions of the
6256 : source layer and then duplicate each features of the source layer.
6257 : The papszOptions argument
6258 : can be used to control driver specific creation options. These options are
6259 : normally documented in the format specific documentation.
6260 : The source layer may come from another dataset.
6261 :
6262 : This method is the same as the C function GDALDatasetCopyLayer() and the
6263 : deprecated OGR_DS_CopyLayer().
6264 :
6265 : @param poSrcLayer source layer.
6266 : @param pszNewName the name of the layer to create.
6267 : @param papszOptions a StringList of name=value options. Options are driver
6268 : specific. There is a common option to set output layer
6269 : spatial reference: DST_SRSWKT. The option should be in
6270 : WKT format. Starting with GDAL 3.7, the common option
6271 : COPY_MD can be set to NO to prevent the default copying
6272 : of the metadata from the source layer to the target layer.
6273 :
6274 : @return a handle to the layer, or NULL if an error occurs.
6275 : */
6276 :
6277 164 : OGRLayer *GDALDataset::CopyLayer(OGRLayer *poSrcLayer, const char *pszNewName,
6278 : CSLConstList papszOptions)
6279 :
6280 : {
6281 : /* -------------------------------------------------------------------- */
6282 : /* Create the layer. */
6283 : /* -------------------------------------------------------------------- */
6284 164 : if (!TestCapability(ODsCCreateLayer))
6285 : {
6286 0 : CPLError(CE_Failure, CPLE_NotSupported,
6287 : "This datasource does not support creation of layers.");
6288 0 : return nullptr;
6289 : }
6290 :
6291 164 : const char *pszSRSWKT = CSLFetchNameValue(papszOptions, "DST_SRSWKT");
6292 328 : OGRSpatialReference oDstSpaRef(pszSRSWKT);
6293 164 : oDstSpaRef.SetAxisMappingStrategy(OAMS_TRADITIONAL_GIS_ORDER);
6294 164 : OGRFeatureDefn *poSrcDefn = poSrcLayer->GetLayerDefn();
6295 164 : OGRLayer *poDstLayer = nullptr;
6296 :
6297 328 : CPLStringList aosCleanedUpOptions(CSLDuplicate(papszOptions));
6298 164 : aosCleanedUpOptions.SetNameValue("DST_SRSWKT", nullptr);
6299 164 : aosCleanedUpOptions.SetNameValue("COPY_MD", nullptr);
6300 :
6301 164 : CPLErrorReset();
6302 164 : const int nSrcGeomFieldCount = poSrcDefn->GetGeomFieldCount();
6303 164 : if (nSrcGeomFieldCount == 1)
6304 : {
6305 112 : OGRGeomFieldDefn oGeomFieldDefn(poSrcDefn->GetGeomFieldDefn(0));
6306 112 : if (pszSRSWKT)
6307 5 : oGeomFieldDefn.SetSpatialRef(&oDstSpaRef);
6308 112 : poDstLayer = ICreateLayer(pszNewName, &oGeomFieldDefn,
6309 112 : aosCleanedUpOptions.List());
6310 : }
6311 : else
6312 : {
6313 : poDstLayer =
6314 52 : ICreateLayer(pszNewName, nullptr, aosCleanedUpOptions.List());
6315 : }
6316 :
6317 164 : if (poDstLayer == nullptr)
6318 0 : return nullptr;
6319 :
6320 164 : if (CPLTestBool(CSLFetchNameValueDef(papszOptions, "COPY_MD", "YES")))
6321 : {
6322 163 : CSLConstList papszMD = poSrcLayer->GetMetadata();
6323 163 : if (papszMD)
6324 31 : poDstLayer->SetMetadata(papszMD);
6325 : }
6326 :
6327 : /* -------------------------------------------------------------------- */
6328 : /* Add fields. Default to copy all fields, and make sure to */
6329 : /* establish a mapping between indices, rather than names, in */
6330 : /* case the target datasource has altered it (e.g. Shapefile */
6331 : /* limited to 10 char field names). */
6332 : /* -------------------------------------------------------------------- */
6333 164 : const int nSrcFieldCount = poSrcDefn->GetFieldCount();
6334 :
6335 : // Initialize the index-to-index map to -1's.
6336 328 : std::vector<int> anMap(nSrcFieldCount, -1);
6337 :
6338 : // Caution: At the time of writing, the MapInfo driver
6339 : // returns NULL until a field has been added.
6340 164 : OGRFeatureDefn *poDstFDefn = poDstLayer->GetLayerDefn();
6341 164 : int nDstFieldCount = poDstFDefn ? poDstFDefn->GetFieldCount() : 0;
6342 391 : for (int iField = 0; iField < nSrcFieldCount; ++iField)
6343 : {
6344 227 : OGRFieldDefn *poSrcFieldDefn = poSrcDefn->GetFieldDefn(iField);
6345 454 : OGRFieldDefn oFieldDefn(poSrcFieldDefn);
6346 :
6347 : // The field may have been already created at layer creation.
6348 227 : int iDstField = -1;
6349 227 : if (poDstFDefn)
6350 227 : iDstField = poDstFDefn->GetFieldIndex(oFieldDefn.GetNameRef());
6351 227 : if (iDstField >= 0)
6352 : {
6353 0 : anMap[iField] = iDstField;
6354 : }
6355 227 : else if (poDstLayer->CreateField(&oFieldDefn) == OGRERR_NONE)
6356 : {
6357 : // Now that we've created a field, GetLayerDefn() won't return NULL.
6358 227 : if (poDstFDefn == nullptr)
6359 0 : poDstFDefn = poDstLayer->GetLayerDefn();
6360 :
6361 : // Sanity check: if it fails, the driver is buggy.
6362 454 : if (poDstFDefn != nullptr &&
6363 227 : poDstFDefn->GetFieldCount() != nDstFieldCount + 1)
6364 : {
6365 0 : CPLError(CE_Warning, CPLE_AppDefined,
6366 : "The output driver has claimed to have added the %s "
6367 : "field, but it did not!",
6368 : oFieldDefn.GetNameRef());
6369 : }
6370 : else
6371 : {
6372 227 : anMap[iField] = nDstFieldCount;
6373 227 : ++nDstFieldCount;
6374 : }
6375 : }
6376 : }
6377 :
6378 : /* -------------------------------------------------------------------- */
6379 164 : std::unique_ptr<OGRCoordinateTransformation> poCT;
6380 164 : const OGRSpatialReference *sourceSRS = poSrcLayer->GetSpatialRef();
6381 164 : if (sourceSRS != nullptr && pszSRSWKT != nullptr && !oDstSpaRef.IsEmpty() &&
6382 0 : sourceSRS->IsSame(&oDstSpaRef) == FALSE)
6383 : {
6384 0 : poCT.reset(OGRCreateCoordinateTransformation(sourceSRS, &oDstSpaRef));
6385 0 : if (nullptr == poCT)
6386 : {
6387 0 : CPLError(CE_Failure, CPLE_NotSupported,
6388 : "This input/output spatial reference is not supported.");
6389 0 : return nullptr;
6390 : }
6391 : }
6392 : /* -------------------------------------------------------------------- */
6393 : /* Create geometry fields. */
6394 : /* -------------------------------------------------------------------- */
6395 165 : if (nSrcGeomFieldCount > 1 &&
6396 1 : TestCapability(ODsCCreateGeomFieldAfterCreateLayer))
6397 : {
6398 :
6399 3 : for (int iField = 0; iField < nSrcGeomFieldCount; ++iField)
6400 : {
6401 2 : if (nullptr == pszSRSWKT)
6402 : {
6403 2 : poDstLayer->CreateGeomField(
6404 2 : poSrcDefn->GetGeomFieldDefn(iField));
6405 : }
6406 : else
6407 : {
6408 : OGRGeomFieldDefn *pDstGeomFieldDefn =
6409 0 : poSrcDefn->GetGeomFieldDefn(iField);
6410 0 : pDstGeomFieldDefn->SetSpatialRef(&oDstSpaRef);
6411 0 : poDstLayer->CreateGeomField(pDstGeomFieldDefn);
6412 : }
6413 : }
6414 : }
6415 :
6416 : /* -------------------------------------------------------------------- */
6417 : /* Check if the destination layer supports transactions and set a */
6418 : /* default number of features in a single transaction. */
6419 : /* -------------------------------------------------------------------- */
6420 : const int nGroupTransactions =
6421 164 : poDstLayer->TestCapability(OLCTransactions) ? 128 : 0;
6422 :
6423 : /* -------------------------------------------------------------------- */
6424 : /* Transfer features. */
6425 : /* -------------------------------------------------------------------- */
6426 164 : poSrcLayer->ResetReading();
6427 :
6428 164 : if (nGroupTransactions <= 0)
6429 : {
6430 : while (true)
6431 : {
6432 : auto poFeature =
6433 682 : std::unique_ptr<OGRFeature>(poSrcLayer->GetNextFeature());
6434 :
6435 682 : if (poFeature == nullptr)
6436 155 : break;
6437 :
6438 527 : CPLErrorReset();
6439 : auto poDstFeature =
6440 527 : std::make_unique<OGRFeature>(poDstLayer->GetLayerDefn());
6441 :
6442 527 : if (poDstFeature->SetFrom(poFeature.get(), anMap.data(), TRUE) !=
6443 : OGRERR_NONE)
6444 : {
6445 0 : CPLError(CE_Failure, CPLE_AppDefined,
6446 : "Unable to translate feature " CPL_FRMT_GIB
6447 : " from layer %s.",
6448 0 : poFeature->GetFID(), poSrcDefn->GetName());
6449 0 : return poDstLayer;
6450 : }
6451 :
6452 527 : if (nullptr != poCT)
6453 : {
6454 0 : for (int iField = 0; iField < nSrcGeomFieldCount; ++iField)
6455 : {
6456 0 : OGRGeometry *pGeom = poDstFeature->GetGeomFieldRef(iField);
6457 0 : if (nullptr == pGeom)
6458 0 : continue;
6459 :
6460 0 : const OGRErr eErr = pGeom->transform(poCT.get());
6461 0 : if (eErr == OGRERR_NONE)
6462 0 : continue;
6463 :
6464 0 : CPLError(CE_Failure, CPLE_AppDefined,
6465 : "Unable to transform geometry " CPL_FRMT_GIB
6466 : " from layer %s.",
6467 0 : poFeature->GetFID(), poSrcDefn->GetName());
6468 0 : return poDstLayer;
6469 : }
6470 : }
6471 :
6472 527 : poDstFeature->SetFID(poFeature->GetFID());
6473 :
6474 527 : CPLErrorReset();
6475 527 : if (poDstLayer->CreateFeature(poDstFeature.get()) != OGRERR_NONE)
6476 : {
6477 0 : return poDstLayer;
6478 : }
6479 527 : }
6480 : }
6481 : else
6482 : {
6483 9 : std::vector<std::unique_ptr<OGRFeature>> apoDstFeatures;
6484 : try
6485 : {
6486 9 : apoDstFeatures.resize(nGroupTransactions);
6487 : }
6488 0 : catch (const std::exception &e)
6489 : {
6490 0 : CPLError(CE_Failure, CPLE_OutOfMemory, "%s", e.what());
6491 0 : return poDstLayer;
6492 : }
6493 9 : bool bStopTransfer = false;
6494 18 : while (!bStopTransfer)
6495 : {
6496 : /* --------------------------------------------------------------------
6497 : */
6498 : /* Fill the array with features. */
6499 : /* --------------------------------------------------------------------
6500 : */
6501 : // Number of features in the temporary array.
6502 9 : int nFeatCount = 0; // Used after for.
6503 85 : for (nFeatCount = 0; nFeatCount < nGroupTransactions; ++nFeatCount)
6504 : {
6505 : auto poFeature =
6506 85 : std::unique_ptr<OGRFeature>(poSrcLayer->GetNextFeature());
6507 :
6508 85 : if (poFeature == nullptr)
6509 : {
6510 9 : bStopTransfer = true;
6511 9 : break;
6512 : }
6513 :
6514 76 : CPLErrorReset();
6515 76 : apoDstFeatures[nFeatCount] =
6516 152 : std::make_unique<OGRFeature>(poDstLayer->GetLayerDefn());
6517 :
6518 152 : if (apoDstFeatures[nFeatCount]->SetFrom(
6519 152 : poFeature.get(), anMap.data(), TRUE) != OGRERR_NONE)
6520 : {
6521 0 : CPLError(CE_Failure, CPLE_AppDefined,
6522 : "Unable to translate feature " CPL_FRMT_GIB
6523 : " from layer %s.",
6524 0 : poFeature->GetFID(), poSrcDefn->GetName());
6525 0 : bStopTransfer = true;
6526 0 : poFeature.reset();
6527 0 : break;
6528 : }
6529 :
6530 76 : if (nullptr != poCT)
6531 : {
6532 0 : for (int iField = 0; iField < nSrcGeomFieldCount; ++iField)
6533 : {
6534 : OGRGeometry *pGeom =
6535 0 : apoDstFeatures[nFeatCount]->GetGeomFieldRef(iField);
6536 0 : if (nullptr == pGeom)
6537 0 : continue;
6538 :
6539 0 : const OGRErr eErr = pGeom->transform(poCT.get());
6540 0 : if (eErr == OGRERR_NONE)
6541 0 : continue;
6542 :
6543 0 : CPLError(CE_Failure, CPLE_AppDefined,
6544 : "Unable to transform geometry " CPL_FRMT_GIB
6545 : " from layer %s.",
6546 0 : poFeature->GetFID(), poSrcDefn->GetName());
6547 0 : bStopTransfer = true;
6548 0 : poFeature.reset();
6549 0 : break;
6550 : }
6551 : }
6552 :
6553 76 : if (poFeature)
6554 : {
6555 76 : apoDstFeatures[nFeatCount]->SetFID(poFeature->GetFID());
6556 : }
6557 : }
6558 :
6559 9 : CPLErrorReset();
6560 9 : bool bStopTransaction = false;
6561 18 : while (!bStopTransaction)
6562 : {
6563 9 : bStopTransaction = true;
6564 9 : if (poDstLayer->StartTransaction() != OGRERR_NONE)
6565 0 : break;
6566 85 : for (int i = 0; i < nFeatCount; ++i)
6567 : {
6568 76 : if (poDstLayer->CreateFeature(apoDstFeatures[i].get()) !=
6569 : OGRERR_NONE)
6570 : {
6571 0 : bStopTransfer = true;
6572 0 : bStopTransaction = false;
6573 0 : break;
6574 : }
6575 76 : apoDstFeatures[i].reset();
6576 : }
6577 9 : if (bStopTransaction)
6578 : {
6579 9 : if (poDstLayer->CommitTransaction() != OGRERR_NONE)
6580 0 : break;
6581 : }
6582 : else
6583 : {
6584 0 : poDstLayer->RollbackTransaction();
6585 : }
6586 : }
6587 : }
6588 : }
6589 :
6590 164 : return poDstLayer;
6591 : }
6592 :
6593 : /************************************************************************/
6594 : /* DeleteLayer() */
6595 : /************************************************************************/
6596 :
6597 : /**
6598 : \fn GDALDataset::DeleteLayer(int)
6599 : \brief Delete the indicated layer from the datasource.
6600 :
6601 : If this method is supported
6602 : the ODsCDeleteLayer capability will test TRUE on the GDALDataset.
6603 :
6604 : This method is the same as the C function GDALDatasetDeleteLayer() and the
6605 : deprecated OGR_DS_DeleteLayer().
6606 :
6607 : @param iLayer the index of the layer to delete.
6608 :
6609 : @return OGRERR_NONE on success, or OGRERR_UNSUPPORTED_OPERATION if deleting
6610 : layers is not supported for this datasource.
6611 :
6612 : */
6613 :
6614 389 : OGRErr GDALDataset::DeleteLayer(CPL_UNUSED int iLayer)
6615 :
6616 : {
6617 389 : CPLError(CE_Failure, CPLE_NotSupported,
6618 : "DeleteLayer() not supported by this dataset.");
6619 :
6620 389 : return OGRERR_UNSUPPORTED_OPERATION;
6621 : }
6622 :
6623 : /************************************************************************/
6624 : /* GetLayerByName() */
6625 : /************************************************************************/
6626 :
6627 : /**
6628 : \brief Fetch a layer by name.
6629 :
6630 : The returned layer remains owned by the
6631 : GDALDataset and should not be deleted by the application.
6632 :
6633 : This method is the same as the C function GDALDatasetGetLayerByName() and the
6634 : deprecated OGR_DS_GetLayerByName().
6635 :
6636 : @param pszName the layer name of the layer to fetch.
6637 :
6638 : @return the layer, or NULL if Layer is not found or an error occurs.
6639 : */
6640 :
6641 30241 : OGRLayer *GDALDataset::GetLayerByName(const char *pszName)
6642 :
6643 : {
6644 60482 : CPLMutexHolderD(m_poPrivate ? &(m_poPrivate->hMutex) : nullptr);
6645 :
6646 30241 : if (!pszName)
6647 0 : return nullptr;
6648 :
6649 : // First a case sensitive check.
6650 932961 : for (auto *poLayer : GetLayers())
6651 : {
6652 914682 : if (strcmp(pszName, poLayer->GetName()) == 0)
6653 11962 : return poLayer;
6654 : }
6655 :
6656 : // Then case insensitive.
6657 894003 : for (auto *poLayer : GetLayers())
6658 : {
6659 875948 : if (EQUAL(pszName, poLayer->GetName()))
6660 224 : return poLayer;
6661 : }
6662 :
6663 18055 : return nullptr;
6664 : }
6665 :
6666 : //! @cond Doxygen_Suppress
6667 : /************************************************************************/
6668 : /* ProcessSQLCreateIndex() */
6669 : /* */
6670 : /* The correct syntax for creating an index in our dialect of */
6671 : /* SQL is: */
6672 : /* */
6673 : /* CREATE INDEX ON <layername> USING <columnname> */
6674 : /************************************************************************/
6675 :
6676 28 : OGRErr GDALDataset::ProcessSQLCreateIndex(const char *pszSQLCommand)
6677 :
6678 : {
6679 28 : char **papszTokens = CSLTokenizeString(pszSQLCommand);
6680 :
6681 : /* -------------------------------------------------------------------- */
6682 : /* Do some general syntax checking. */
6683 : /* -------------------------------------------------------------------- */
6684 56 : if (CSLCount(papszTokens) != 6 || !EQUAL(papszTokens[0], "CREATE") ||
6685 84 : !EQUAL(papszTokens[1], "INDEX") || !EQUAL(papszTokens[2], "ON") ||
6686 28 : !EQUAL(papszTokens[4], "USING"))
6687 : {
6688 0 : CSLDestroy(papszTokens);
6689 0 : CPLError(CE_Failure, CPLE_AppDefined,
6690 : "Syntax error in CREATE INDEX command.\n"
6691 : "Was '%s'\n"
6692 : "Should be of form 'CREATE INDEX ON <table> USING <field>'",
6693 : pszSQLCommand);
6694 0 : return OGRERR_FAILURE;
6695 : }
6696 :
6697 : /* -------------------------------------------------------------------- */
6698 : /* Find the named layer. */
6699 : /* -------------------------------------------------------------------- */
6700 28 : OGRLayer *poLayer = GetLayerByName(papszTokens[3]);
6701 28 : if (poLayer == nullptr)
6702 : {
6703 0 : CPLError(CE_Failure, CPLE_AppDefined,
6704 : "CREATE INDEX ON failed, no such layer as `%s'.",
6705 0 : papszTokens[3]);
6706 0 : CSLDestroy(papszTokens);
6707 0 : return OGRERR_FAILURE;
6708 : }
6709 :
6710 : /* -------------------------------------------------------------------- */
6711 : /* Does this layer even support attribute indexes? */
6712 : /* -------------------------------------------------------------------- */
6713 28 : if (poLayer->GetIndex() == nullptr)
6714 : {
6715 0 : CPLError(CE_Failure, CPLE_AppDefined,
6716 : "CREATE INDEX ON not supported by this driver.");
6717 0 : CSLDestroy(papszTokens);
6718 0 : return OGRERR_FAILURE;
6719 : }
6720 :
6721 : /* -------------------------------------------------------------------- */
6722 : /* Find the named field. */
6723 : /* -------------------------------------------------------------------- */
6724 28 : int i = poLayer->GetLayerDefn()->GetFieldIndex(papszTokens[5]);
6725 :
6726 28 : CSLDestroy(papszTokens);
6727 :
6728 28 : if (i >= poLayer->GetLayerDefn()->GetFieldCount())
6729 : {
6730 0 : CPLError(CE_Failure, CPLE_AppDefined, "`%s' failed, field not found.",
6731 : pszSQLCommand);
6732 0 : return OGRERR_FAILURE;
6733 : }
6734 :
6735 : /* -------------------------------------------------------------------- */
6736 : /* Attempt to create the index. */
6737 : /* -------------------------------------------------------------------- */
6738 28 : OGRErr eErr = poLayer->GetIndex()->CreateIndex(i);
6739 28 : if (eErr == OGRERR_NONE)
6740 : {
6741 28 : eErr = poLayer->GetIndex()->IndexAllFeatures(i);
6742 : }
6743 : else
6744 : {
6745 0 : if (strlen(CPLGetLastErrorMsg()) == 0)
6746 0 : CPLError(CE_Failure, CPLE_AppDefined, "Cannot '%s'", pszSQLCommand);
6747 : }
6748 :
6749 28 : return eErr;
6750 : }
6751 :
6752 : /************************************************************************/
6753 : /* ProcessSQLDropIndex() */
6754 : /* */
6755 : /* The correct syntax for dropping one or more indexes in */
6756 : /* the OGR SQL dialect is: */
6757 : /* */
6758 : /* DROP INDEX ON <layername> [USING <columnname>] */
6759 : /************************************************************************/
6760 :
6761 10 : OGRErr GDALDataset::ProcessSQLDropIndex(const char *pszSQLCommand)
6762 :
6763 : {
6764 10 : char **papszTokens = CSLTokenizeString(pszSQLCommand);
6765 :
6766 : /* -------------------------------------------------------------------- */
6767 : /* Do some general syntax checking. */
6768 : /* -------------------------------------------------------------------- */
6769 20 : if ((CSLCount(papszTokens) != 4 && CSLCount(papszTokens) != 6) ||
6770 10 : !EQUAL(papszTokens[0], "DROP") || !EQUAL(papszTokens[1], "INDEX") ||
6771 30 : !EQUAL(papszTokens[2], "ON") ||
6772 10 : (CSLCount(papszTokens) == 6 && !EQUAL(papszTokens[4], "USING")))
6773 : {
6774 0 : CSLDestroy(papszTokens);
6775 0 : CPLError(CE_Failure, CPLE_AppDefined,
6776 : "Syntax error in DROP INDEX command.\n"
6777 : "Was '%s'\n"
6778 : "Should be of form 'DROP INDEX ON <table> [USING <field>]'",
6779 : pszSQLCommand);
6780 0 : return OGRERR_FAILURE;
6781 : }
6782 :
6783 : /* -------------------------------------------------------------------- */
6784 : /* Find the named layer. */
6785 : /* -------------------------------------------------------------------- */
6786 10 : OGRLayer *poLayer = GetLayerByName(papszTokens[3]);
6787 10 : if (poLayer == nullptr)
6788 : {
6789 0 : CPLError(CE_Failure, CPLE_AppDefined,
6790 : "DROP INDEX ON failed, no such layer as `%s'.",
6791 0 : papszTokens[3]);
6792 0 : CSLDestroy(papszTokens);
6793 0 : return OGRERR_FAILURE;
6794 : }
6795 :
6796 : /* -------------------------------------------------------------------- */
6797 : /* Does this layer even support attribute indexes? */
6798 : /* -------------------------------------------------------------------- */
6799 10 : if (poLayer->GetIndex() == nullptr)
6800 : {
6801 0 : CPLError(CE_Failure, CPLE_AppDefined,
6802 : "Indexes not supported by this driver.");
6803 0 : CSLDestroy(papszTokens);
6804 0 : return OGRERR_FAILURE;
6805 : }
6806 :
6807 : /* -------------------------------------------------------------------- */
6808 : /* If we were not given a field name, drop all indexes. */
6809 : /* -------------------------------------------------------------------- */
6810 10 : if (CSLCount(papszTokens) == 4)
6811 : {
6812 0 : for (int i = 0; i < poLayer->GetLayerDefn()->GetFieldCount(); ++i)
6813 : {
6814 : OGRAttrIndex *poAttrIndex;
6815 :
6816 0 : poAttrIndex = poLayer->GetIndex()->GetFieldIndex(i);
6817 0 : if (poAttrIndex != nullptr)
6818 : {
6819 0 : const OGRErr eErr = poLayer->GetIndex()->DropIndex(i);
6820 0 : if (eErr != OGRERR_NONE)
6821 : {
6822 0 : CSLDestroy(papszTokens);
6823 0 : return eErr;
6824 : }
6825 : }
6826 : }
6827 :
6828 0 : CSLDestroy(papszTokens);
6829 0 : return OGRERR_NONE;
6830 : }
6831 :
6832 : /* -------------------------------------------------------------------- */
6833 : /* Find the named field. */
6834 : /* -------------------------------------------------------------------- */
6835 10 : int i = poLayer->GetLayerDefn()->GetFieldIndex(papszTokens[5]);
6836 10 : CSLDestroy(papszTokens);
6837 :
6838 10 : if (i >= poLayer->GetLayerDefn()->GetFieldCount())
6839 : {
6840 0 : CPLError(CE_Failure, CPLE_AppDefined, "`%s' failed, field not found.",
6841 : pszSQLCommand);
6842 0 : return OGRERR_FAILURE;
6843 : }
6844 :
6845 : /* -------------------------------------------------------------------- */
6846 : /* Attempt to drop the index. */
6847 : /* -------------------------------------------------------------------- */
6848 10 : const OGRErr eErr = poLayer->GetIndex()->DropIndex(i);
6849 :
6850 10 : return eErr;
6851 : }
6852 :
6853 : /************************************************************************/
6854 : /* ProcessSQLDropTable() */
6855 : /* */
6856 : /* The correct syntax for dropping a table (layer) in the OGR SQL */
6857 : /* dialect is: */
6858 : /* */
6859 : /* DROP TABLE <layername> */
6860 : /************************************************************************/
6861 :
6862 500 : OGRErr GDALDataset::ProcessSQLDropTable(const char *pszSQLCommand)
6863 :
6864 : {
6865 500 : char **papszTokens = CSLTokenizeString(pszSQLCommand);
6866 :
6867 : /* -------------------------------------------------------------------- */
6868 : /* Do some general syntax checking. */
6869 : /* -------------------------------------------------------------------- */
6870 1000 : if (CSLCount(papszTokens) != 3 || !EQUAL(papszTokens[0], "DROP") ||
6871 500 : !EQUAL(papszTokens[1], "TABLE"))
6872 : {
6873 0 : CSLDestroy(papszTokens);
6874 0 : CPLError(CE_Failure, CPLE_AppDefined,
6875 : "Syntax error in DROP TABLE command.\n"
6876 : "Was '%s'\n"
6877 : "Should be of form 'DROP TABLE <table>'",
6878 : pszSQLCommand);
6879 0 : return OGRERR_FAILURE;
6880 : }
6881 :
6882 : /* -------------------------------------------------------------------- */
6883 : /* Find the named layer. */
6884 : /* -------------------------------------------------------------------- */
6885 500 : OGRLayer *poLayer = nullptr;
6886 :
6887 500 : int i = 0; // Used after for.
6888 40199 : for (; i < GetLayerCount(); ++i)
6889 : {
6890 40199 : poLayer = GetLayer(i);
6891 :
6892 40199 : if (poLayer != nullptr && EQUAL(poLayer->GetName(), papszTokens[2]))
6893 500 : break;
6894 39699 : poLayer = nullptr;
6895 : }
6896 :
6897 500 : if (poLayer == nullptr)
6898 : {
6899 0 : CPLError(CE_Failure, CPLE_AppDefined,
6900 0 : "DROP TABLE failed, no such layer as `%s'.", papszTokens[2]);
6901 0 : CSLDestroy(papszTokens);
6902 0 : return OGRERR_FAILURE;
6903 : }
6904 :
6905 500 : CSLDestroy(papszTokens);
6906 :
6907 : /* -------------------------------------------------------------------- */
6908 : /* Delete it. */
6909 : /* -------------------------------------------------------------------- */
6910 :
6911 500 : return DeleteLayer(i);
6912 : }
6913 :
6914 : //! @endcond
6915 :
6916 : /************************************************************************/
6917 : /* GDALDatasetParseSQLType() */
6918 : /************************************************************************/
6919 :
6920 : /* All arguments will be altered */
6921 6 : static OGRFieldType GDALDatasetParseSQLType(char *pszType, int &nWidth,
6922 : int &nPrecision)
6923 : {
6924 6 : char *pszParenthesis = strchr(pszType, '(');
6925 6 : if (pszParenthesis)
6926 : {
6927 4 : nWidth = atoi(pszParenthesis + 1);
6928 4 : *pszParenthesis = '\0';
6929 4 : char *pszComma = strchr(pszParenthesis + 1, ',');
6930 4 : if (pszComma)
6931 2 : nPrecision = atoi(pszComma + 1);
6932 : }
6933 :
6934 6 : OGRFieldType eType = OFTString;
6935 6 : if (EQUAL(pszType, "INTEGER"))
6936 0 : eType = OFTInteger;
6937 6 : else if (EQUAL(pszType, "INTEGER[]"))
6938 0 : eType = OFTIntegerList;
6939 6 : else if (EQUAL(pszType, "FLOAT") || EQUAL(pszType, "NUMERIC") ||
6940 4 : EQUAL(pszType, "DOUBLE") /* unofficial alias */ ||
6941 4 : EQUAL(pszType, "REAL") /* unofficial alias */)
6942 2 : eType = OFTReal;
6943 4 : else if (EQUAL(pszType, "FLOAT[]") || EQUAL(pszType, "NUMERIC[]") ||
6944 4 : EQUAL(pszType, "DOUBLE[]") /* unofficial alias */ ||
6945 4 : EQUAL(pszType, "REAL[]") /* unofficial alias */)
6946 0 : eType = OFTRealList;
6947 4 : else if (EQUAL(pszType, "CHARACTER") ||
6948 0 : EQUAL(pszType, "TEXT") /* unofficial alias */ ||
6949 0 : EQUAL(pszType, "STRING") /* unofficial alias */ ||
6950 0 : EQUAL(pszType, "VARCHAR") /* unofficial alias */)
6951 4 : eType = OFTString;
6952 0 : else if (EQUAL(pszType, "TEXT[]") ||
6953 0 : EQUAL(pszType, "STRING[]") /* unofficial alias */ ||
6954 0 : EQUAL(pszType, "VARCHAR[]") /* unofficial alias */)
6955 0 : eType = OFTStringList;
6956 0 : else if (EQUAL(pszType, "DATE"))
6957 0 : eType = OFTDate;
6958 0 : else if (EQUAL(pszType, "TIME"))
6959 0 : eType = OFTTime;
6960 0 : else if (EQUAL(pszType, "TIMESTAMP") ||
6961 0 : EQUAL(pszType, "DATETIME") /* unofficial alias */)
6962 0 : eType = OFTDateTime;
6963 : else
6964 0 : CPLError(CE_Warning, CPLE_NotSupported,
6965 : "Unsupported column type '%s'. Defaulting to VARCHAR",
6966 : pszType);
6967 :
6968 6 : return eType;
6969 : }
6970 :
6971 : /************************************************************************/
6972 : /* ProcessSQLAlterTableAddColumn() */
6973 : /* */
6974 : /* The correct syntax for adding a column in the OGR SQL */
6975 : /* dialect is: */
6976 : /* */
6977 : /* ALTER TABLE <layername> ADD [COLUMN] <columnname> <columntype> */
6978 : /************************************************************************/
6979 :
6980 : //! @cond Doxygen_Suppress
6981 2 : OGRErr GDALDataset::ProcessSQLAlterTableAddColumn(const char *pszSQLCommand)
6982 :
6983 : {
6984 2 : char **papszTokens = CSLTokenizeString(pszSQLCommand);
6985 :
6986 : /* -------------------------------------------------------------------- */
6987 : /* Do some general syntax checking. */
6988 : /* -------------------------------------------------------------------- */
6989 2 : const char *pszLayerName = nullptr;
6990 2 : const char *pszColumnName = nullptr;
6991 2 : int iTypeIndex = 0;
6992 2 : const int nTokens = CSLCount(papszTokens);
6993 :
6994 2 : if (nTokens >= 7 && EQUAL(papszTokens[0], "ALTER") &&
6995 2 : EQUAL(papszTokens[1], "TABLE") && EQUAL(papszTokens[3], "ADD") &&
6996 2 : EQUAL(papszTokens[4], "COLUMN"))
6997 : {
6998 1 : pszLayerName = papszTokens[2];
6999 1 : pszColumnName = papszTokens[5];
7000 1 : iTypeIndex = 6;
7001 : }
7002 1 : else if (nTokens >= 6 && EQUAL(papszTokens[0], "ALTER") &&
7003 1 : EQUAL(papszTokens[1], "TABLE") && EQUAL(papszTokens[3], "ADD"))
7004 : {
7005 1 : pszLayerName = papszTokens[2];
7006 1 : pszColumnName = papszTokens[4];
7007 1 : iTypeIndex = 5;
7008 : }
7009 : else
7010 : {
7011 0 : CSLDestroy(papszTokens);
7012 0 : CPLError(CE_Failure, CPLE_AppDefined,
7013 : "Syntax error in ALTER TABLE ADD COLUMN command.\n"
7014 : "Was '%s'\n"
7015 : "Should be of form 'ALTER TABLE <layername> ADD [COLUMN] "
7016 : "<columnname> <columntype>'",
7017 : pszSQLCommand);
7018 0 : return OGRERR_FAILURE;
7019 : }
7020 :
7021 : /* -------------------------------------------------------------------- */
7022 : /* Merge type components into a single string if there were split */
7023 : /* with spaces */
7024 : /* -------------------------------------------------------------------- */
7025 4 : CPLString osType;
7026 6 : for (int i = iTypeIndex; i < nTokens; ++i)
7027 : {
7028 4 : osType += papszTokens[i];
7029 4 : CPLFree(papszTokens[i]);
7030 : }
7031 2 : char *pszType = papszTokens[iTypeIndex] = CPLStrdup(osType);
7032 2 : papszTokens[iTypeIndex + 1] = nullptr;
7033 :
7034 : /* -------------------------------------------------------------------- */
7035 : /* Find the named layer. */
7036 : /* -------------------------------------------------------------------- */
7037 2 : OGRLayer *poLayer = GetLayerByName(pszLayerName);
7038 2 : if (poLayer == nullptr)
7039 : {
7040 0 : CPLError(CE_Failure, CPLE_AppDefined,
7041 : "%s failed, no such layer as `%s'.", pszSQLCommand,
7042 : pszLayerName);
7043 0 : CSLDestroy(papszTokens);
7044 0 : return OGRERR_FAILURE;
7045 : }
7046 :
7047 : /* -------------------------------------------------------------------- */
7048 : /* Add column. */
7049 : /* -------------------------------------------------------------------- */
7050 :
7051 2 : int nWidth = 0;
7052 2 : int nPrecision = 0;
7053 2 : OGRFieldType eType = GDALDatasetParseSQLType(pszType, nWidth, nPrecision);
7054 4 : OGRFieldDefn oFieldDefn(pszColumnName, eType);
7055 2 : oFieldDefn.SetWidth(nWidth);
7056 2 : oFieldDefn.SetPrecision(nPrecision);
7057 :
7058 2 : CSLDestroy(papszTokens);
7059 :
7060 2 : return poLayer->CreateField(&oFieldDefn);
7061 : }
7062 :
7063 : /************************************************************************/
7064 : /* ProcessSQLAlterTableDropColumn() */
7065 : /* */
7066 : /* The correct syntax for dropping a column in the OGR SQL */
7067 : /* dialect is: */
7068 : /* */
7069 : /* ALTER TABLE <layername> DROP [COLUMN] <columnname> */
7070 : /************************************************************************/
7071 :
7072 2 : OGRErr GDALDataset::ProcessSQLAlterTableDropColumn(const char *pszSQLCommand)
7073 :
7074 : {
7075 2 : char **papszTokens = CSLTokenizeString(pszSQLCommand);
7076 :
7077 : /* -------------------------------------------------------------------- */
7078 : /* Do some general syntax checking. */
7079 : /* -------------------------------------------------------------------- */
7080 2 : const char *pszLayerName = nullptr;
7081 2 : const char *pszColumnName = nullptr;
7082 3 : if (CSLCount(papszTokens) == 6 && EQUAL(papszTokens[0], "ALTER") &&
7083 4 : EQUAL(papszTokens[1], "TABLE") && EQUAL(papszTokens[3], "DROP") &&
7084 1 : EQUAL(papszTokens[4], "COLUMN"))
7085 : {
7086 1 : pszLayerName = papszTokens[2];
7087 1 : pszColumnName = papszTokens[5];
7088 : }
7089 2 : else if (CSLCount(papszTokens) == 5 && EQUAL(papszTokens[0], "ALTER") &&
7090 2 : EQUAL(papszTokens[1], "TABLE") && EQUAL(papszTokens[3], "DROP"))
7091 : {
7092 1 : pszLayerName = papszTokens[2];
7093 1 : pszColumnName = papszTokens[4];
7094 : }
7095 : else
7096 : {
7097 0 : CSLDestroy(papszTokens);
7098 0 : CPLError(CE_Failure, CPLE_AppDefined,
7099 : "Syntax error in ALTER TABLE DROP COLUMN command.\n"
7100 : "Was '%s'\n"
7101 : "Should be of form 'ALTER TABLE <layername> DROP [COLUMN] "
7102 : "<columnname>'",
7103 : pszSQLCommand);
7104 0 : return OGRERR_FAILURE;
7105 : }
7106 :
7107 : /* -------------------------------------------------------------------- */
7108 : /* Find the named layer. */
7109 : /* -------------------------------------------------------------------- */
7110 2 : OGRLayer *poLayer = GetLayerByName(pszLayerName);
7111 2 : if (poLayer == nullptr)
7112 : {
7113 0 : CPLError(CE_Failure, CPLE_AppDefined,
7114 : "%s failed, no such layer as `%s'.", pszSQLCommand,
7115 : pszLayerName);
7116 0 : CSLDestroy(papszTokens);
7117 0 : return OGRERR_FAILURE;
7118 : }
7119 :
7120 : /* -------------------------------------------------------------------- */
7121 : /* Find the field. */
7122 : /* -------------------------------------------------------------------- */
7123 :
7124 2 : int nFieldIndex = poLayer->GetLayerDefn()->GetFieldIndex(pszColumnName);
7125 2 : if (nFieldIndex < 0)
7126 : {
7127 0 : CPLError(CE_Failure, CPLE_AppDefined,
7128 : "%s failed, no such field as `%s'.", pszSQLCommand,
7129 : pszColumnName);
7130 0 : CSLDestroy(papszTokens);
7131 0 : return OGRERR_FAILURE;
7132 : }
7133 :
7134 : /* -------------------------------------------------------------------- */
7135 : /* Remove it. */
7136 : /* -------------------------------------------------------------------- */
7137 :
7138 2 : CSLDestroy(papszTokens);
7139 :
7140 2 : return poLayer->DeleteField(nFieldIndex);
7141 : }
7142 :
7143 : /************************************************************************/
7144 : /* ProcessSQLAlterTableRenameColumn() */
7145 : /* */
7146 : /* The correct syntax for renaming a column in the OGR SQL */
7147 : /* dialect is: */
7148 : /* */
7149 : /* ALTER TABLE <layername> RENAME [COLUMN] <oldname> TO <newname> */
7150 : /************************************************************************/
7151 :
7152 2 : OGRErr GDALDataset::ProcessSQLAlterTableRenameColumn(const char *pszSQLCommand)
7153 :
7154 : {
7155 2 : char **papszTokens = CSLTokenizeString(pszSQLCommand);
7156 :
7157 : /* -------------------------------------------------------------------- */
7158 : /* Do some general syntax checking. */
7159 : /* -------------------------------------------------------------------- */
7160 2 : const char *pszLayerName = nullptr;
7161 2 : const char *pszOldColName = nullptr;
7162 2 : const char *pszNewColName = nullptr;
7163 3 : if (CSLCount(papszTokens) == 8 && EQUAL(papszTokens[0], "ALTER") &&
7164 1 : EQUAL(papszTokens[1], "TABLE") && EQUAL(papszTokens[3], "RENAME") &&
7165 3 : EQUAL(papszTokens[4], "COLUMN") && EQUAL(papszTokens[6], "TO"))
7166 : {
7167 1 : pszLayerName = papszTokens[2];
7168 1 : pszOldColName = papszTokens[5];
7169 1 : pszNewColName = papszTokens[7];
7170 : }
7171 2 : else if (CSLCount(papszTokens) == 7 && EQUAL(papszTokens[0], "ALTER") &&
7172 1 : EQUAL(papszTokens[1], "TABLE") &&
7173 2 : EQUAL(papszTokens[3], "RENAME") && EQUAL(papszTokens[5], "TO"))
7174 : {
7175 1 : pszLayerName = papszTokens[2];
7176 1 : pszOldColName = papszTokens[4];
7177 1 : pszNewColName = papszTokens[6];
7178 : }
7179 : else
7180 : {
7181 0 : CSLDestroy(papszTokens);
7182 0 : CPLError(CE_Failure, CPLE_AppDefined,
7183 : "Syntax error in ALTER TABLE RENAME COLUMN command.\n"
7184 : "Was '%s'\n"
7185 : "Should be of form 'ALTER TABLE <layername> RENAME [COLUMN] "
7186 : "<columnname> TO <newname>'",
7187 : pszSQLCommand);
7188 0 : return OGRERR_FAILURE;
7189 : }
7190 :
7191 : /* -------------------------------------------------------------------- */
7192 : /* Find the named layer. */
7193 : /* -------------------------------------------------------------------- */
7194 2 : OGRLayer *poLayer = GetLayerByName(pszLayerName);
7195 2 : if (poLayer == nullptr)
7196 : {
7197 0 : CPLError(CE_Failure, CPLE_AppDefined,
7198 : "%s failed, no such layer as `%s'.", pszSQLCommand,
7199 : pszLayerName);
7200 0 : CSLDestroy(papszTokens);
7201 0 : return OGRERR_FAILURE;
7202 : }
7203 :
7204 : /* -------------------------------------------------------------------- */
7205 : /* Find the field. */
7206 : /* -------------------------------------------------------------------- */
7207 :
7208 : const int nFieldIndex =
7209 2 : poLayer->GetLayerDefn()->GetFieldIndex(pszOldColName);
7210 2 : if (nFieldIndex < 0)
7211 : {
7212 0 : CPLError(CE_Failure, CPLE_AppDefined,
7213 : "%s failed, no such field as `%s'.", pszSQLCommand,
7214 : pszOldColName);
7215 0 : CSLDestroy(papszTokens);
7216 0 : return OGRERR_FAILURE;
7217 : }
7218 :
7219 : /* -------------------------------------------------------------------- */
7220 : /* Rename column. */
7221 : /* -------------------------------------------------------------------- */
7222 : OGRFieldDefn *poOldFieldDefn =
7223 2 : poLayer->GetLayerDefn()->GetFieldDefn(nFieldIndex);
7224 4 : OGRFieldDefn oNewFieldDefn(poOldFieldDefn);
7225 2 : oNewFieldDefn.SetName(pszNewColName);
7226 :
7227 2 : CSLDestroy(papszTokens);
7228 :
7229 2 : return poLayer->AlterFieldDefn(nFieldIndex, &oNewFieldDefn,
7230 2 : ALTER_NAME_FLAG);
7231 : }
7232 :
7233 : /************************************************************************/
7234 : /* ProcessSQLAlterTableAlterColumn() */
7235 : /* */
7236 : /* The correct syntax for altering the type of a column in the */
7237 : /* OGR SQL dialect is: */
7238 : /* */
7239 : /* ALTER TABLE <layername> ALTER [COLUMN] <columnname> TYPE <newtype> */
7240 : /************************************************************************/
7241 :
7242 4 : OGRErr GDALDataset::ProcessSQLAlterTableAlterColumn(const char *pszSQLCommand)
7243 :
7244 : {
7245 4 : char **papszTokens = CSLTokenizeString(pszSQLCommand);
7246 :
7247 : /* -------------------------------------------------------------------- */
7248 : /* Do some general syntax checking. */
7249 : /* -------------------------------------------------------------------- */
7250 4 : const char *pszLayerName = nullptr;
7251 4 : const char *pszColumnName = nullptr;
7252 4 : int iTypeIndex = 0;
7253 4 : const int nTokens = CSLCount(papszTokens);
7254 :
7255 4 : if (nTokens >= 8 && EQUAL(papszTokens[0], "ALTER") &&
7256 2 : EQUAL(papszTokens[1], "TABLE") && EQUAL(papszTokens[3], "ALTER") &&
7257 2 : EQUAL(papszTokens[4], "COLUMN") && EQUAL(papszTokens[6], "TYPE"))
7258 : {
7259 2 : pszLayerName = papszTokens[2];
7260 2 : pszColumnName = papszTokens[5];
7261 2 : iTypeIndex = 7;
7262 : }
7263 2 : else if (nTokens >= 7 && EQUAL(papszTokens[0], "ALTER") &&
7264 2 : EQUAL(papszTokens[1], "TABLE") && EQUAL(papszTokens[3], "ALTER") &&
7265 2 : EQUAL(papszTokens[5], "TYPE"))
7266 : {
7267 2 : pszLayerName = papszTokens[2];
7268 2 : pszColumnName = papszTokens[4];
7269 2 : iTypeIndex = 6;
7270 : }
7271 : else
7272 : {
7273 0 : CSLDestroy(papszTokens);
7274 0 : CPLError(CE_Failure, CPLE_AppDefined,
7275 : "Syntax error in ALTER TABLE ALTER COLUMN command.\n"
7276 : "Was '%s'\n"
7277 : "Should be of form 'ALTER TABLE <layername> ALTER [COLUMN] "
7278 : "<columnname> TYPE <columntype>'",
7279 : pszSQLCommand);
7280 0 : return OGRERR_FAILURE;
7281 : }
7282 :
7283 : /* -------------------------------------------------------------------- */
7284 : /* Merge type components into a single string if there were split */
7285 : /* with spaces */
7286 : /* -------------------------------------------------------------------- */
7287 8 : CPLString osType;
7288 8 : for (int i = iTypeIndex; i < nTokens; ++i)
7289 : {
7290 4 : osType += papszTokens[i];
7291 4 : CPLFree(papszTokens[i]);
7292 : }
7293 4 : char *pszType = papszTokens[iTypeIndex] = CPLStrdup(osType);
7294 4 : papszTokens[iTypeIndex + 1] = nullptr;
7295 :
7296 : /* -------------------------------------------------------------------- */
7297 : /* Find the named layer. */
7298 : /* -------------------------------------------------------------------- */
7299 4 : OGRLayer *poLayer = GetLayerByName(pszLayerName);
7300 4 : if (poLayer == nullptr)
7301 : {
7302 0 : CPLError(CE_Failure, CPLE_AppDefined,
7303 : "%s failed, no such layer as `%s'.", pszSQLCommand,
7304 : pszLayerName);
7305 0 : CSLDestroy(papszTokens);
7306 0 : return OGRERR_FAILURE;
7307 : }
7308 :
7309 : /* -------------------------------------------------------------------- */
7310 : /* Find the field. */
7311 : /* -------------------------------------------------------------------- */
7312 :
7313 : const int nFieldIndex =
7314 4 : poLayer->GetLayerDefn()->GetFieldIndex(pszColumnName);
7315 4 : if (nFieldIndex < 0)
7316 : {
7317 0 : CPLError(CE_Failure, CPLE_AppDefined,
7318 : "%s failed, no such field as `%s'.", pszSQLCommand,
7319 : pszColumnName);
7320 0 : CSLDestroy(papszTokens);
7321 0 : return OGRERR_FAILURE;
7322 : }
7323 :
7324 : /* -------------------------------------------------------------------- */
7325 : /* Alter column. */
7326 : /* -------------------------------------------------------------------- */
7327 :
7328 : OGRFieldDefn *poOldFieldDefn =
7329 4 : poLayer->GetLayerDefn()->GetFieldDefn(nFieldIndex);
7330 8 : OGRFieldDefn oNewFieldDefn(poOldFieldDefn);
7331 :
7332 4 : int nWidth = 0;
7333 4 : int nPrecision = 0;
7334 4 : OGRFieldType eType = GDALDatasetParseSQLType(pszType, nWidth, nPrecision);
7335 4 : oNewFieldDefn.SetType(eType);
7336 4 : oNewFieldDefn.SetWidth(nWidth);
7337 4 : oNewFieldDefn.SetPrecision(nPrecision);
7338 :
7339 4 : int l_nFlags = 0;
7340 4 : if (poOldFieldDefn->GetType() != oNewFieldDefn.GetType())
7341 2 : l_nFlags |= ALTER_TYPE_FLAG;
7342 4 : if (poOldFieldDefn->GetWidth() != oNewFieldDefn.GetWidth() ||
7343 0 : poOldFieldDefn->GetPrecision() != oNewFieldDefn.GetPrecision())
7344 4 : l_nFlags |= ALTER_WIDTH_PRECISION_FLAG;
7345 :
7346 4 : CSLDestroy(papszTokens);
7347 :
7348 4 : if (l_nFlags == 0)
7349 0 : return OGRERR_NONE;
7350 :
7351 4 : return poLayer->AlterFieldDefn(nFieldIndex, &oNewFieldDefn, l_nFlags);
7352 : }
7353 :
7354 : //! @endcond
7355 :
7356 : /************************************************************************/
7357 : /* ExecuteSQL() */
7358 : /************************************************************************/
7359 :
7360 : /**
7361 : \brief Execute an SQL statement against the data store.
7362 :
7363 : The result of an SQL query is either NULL for statements that are in error,
7364 : or that have no results set, or an OGRLayer pointer representing a results
7365 : set from the query. Note that this OGRLayer is in addition to the layers
7366 : in the data store and must be destroyed with
7367 : ReleaseResultSet() before the dataset is closed
7368 : (destroyed).
7369 :
7370 : This method is the same as the C function GDALDatasetExecuteSQL() and the
7371 : deprecated OGR_DS_ExecuteSQL().
7372 :
7373 : For more information on the SQL dialect supported internally by OGR
7374 : review the <a href="https://gdal.org/user/ogr_sql_dialect.html">OGR SQL</a>
7375 : document. Some drivers (i.e. Oracle and PostGIS) pass the SQL directly through
7376 : to the underlying RDBMS.
7377 :
7378 : Starting with OGR 1.10, the <a
7379 : href="https://gdal.org/user/sql_sqlite_dialect.html">SQLITE dialect</a> can
7380 : also be used.
7381 :
7382 : @param pszStatement the SQL statement to execute.
7383 : @param poSpatialFilter geometry which represents a spatial filter. Can be NULL.
7384 : @param pszDialect allows control of the statement dialect. If set to NULL, the
7385 : OGR SQL engine will be used, except for RDBMS drivers that will use their
7386 : dedicated SQL engine, unless OGRSQL is explicitly passed as the
7387 : dialect. Starting with OGR 1.10, the SQLITE dialect can also be used.
7388 :
7389 : @return an OGRLayer containing the results of the query. Deallocate with
7390 : ReleaseResultSet().
7391 :
7392 : */
7393 :
7394 3617 : OGRLayer *GDALDataset::ExecuteSQL(const char *pszStatement,
7395 : OGRGeometry *poSpatialFilter,
7396 : const char *pszDialect)
7397 :
7398 : {
7399 3617 : return ExecuteSQL(pszStatement, poSpatialFilter, pszDialect, nullptr);
7400 : }
7401 :
7402 : //! @cond Doxygen_Suppress
7403 : OGRLayer *
7404 3625 : GDALDataset::ExecuteSQL(const char *pszStatement, OGRGeometry *poSpatialFilter,
7405 : const char *pszDialect,
7406 : swq_select_parse_options *poSelectParseOptions)
7407 :
7408 : {
7409 3625 : if (pszDialect != nullptr && EQUAL(pszDialect, "SQLite"))
7410 : {
7411 : #ifdef SQLITE_ENABLED
7412 666 : return OGRSQLiteExecuteSQL(this, pszStatement, poSpatialFilter,
7413 666 : pszDialect);
7414 : #else
7415 : CPLError(CE_Failure, CPLE_NotSupported,
7416 : "The SQLite driver needs to be compiled to support the "
7417 : "SQLite SQL dialect");
7418 : return nullptr;
7419 : #endif
7420 : }
7421 :
7422 2959 : if (pszDialect != nullptr && !EQUAL(pszDialect, "") &&
7423 14 : !EQUAL(pszDialect, "OGRSQL"))
7424 : {
7425 6 : std::string osDialectList = "'OGRSQL'";
7426 : #ifdef SQLITE_ENABLED
7427 3 : osDialectList += ", 'SQLITE'";
7428 : #endif
7429 : const char *pszDialects =
7430 3 : GetMetadataItem(GDAL_DMD_SUPPORTED_SQL_DIALECTS);
7431 3 : if (pszDialects)
7432 : {
7433 : const CPLStringList aosTokens(
7434 0 : CSLTokenizeString2(pszDialects, " ", 0));
7435 0 : for (int i = 0; i < aosTokens.size(); ++i)
7436 : {
7437 0 : if (!EQUAL(aosTokens[i], "OGRSQL") &&
7438 0 : !EQUAL(aosTokens[i], "SQLITE"))
7439 : {
7440 0 : osDialectList += ", '";
7441 0 : osDialectList += aosTokens[i];
7442 0 : osDialectList += "'";
7443 : }
7444 : }
7445 : }
7446 3 : CPLError(CE_Warning, CPLE_NotSupported,
7447 : "Dialect '%s' is unsupported. Only supported dialects are %s. "
7448 : "Defaulting to OGRSQL",
7449 : pszDialect, osDialectList.c_str());
7450 : }
7451 :
7452 : /* -------------------------------------------------------------------- */
7453 : /* Handle CREATE INDEX statements specially. */
7454 : /* -------------------------------------------------------------------- */
7455 2959 : if (STARTS_WITH_CI(pszStatement, "CREATE INDEX"))
7456 : {
7457 28 : ProcessSQLCreateIndex(pszStatement);
7458 28 : return nullptr;
7459 : }
7460 :
7461 : /* -------------------------------------------------------------------- */
7462 : /* Handle DROP INDEX statements specially. */
7463 : /* -------------------------------------------------------------------- */
7464 2931 : if (STARTS_WITH_CI(pszStatement, "DROP INDEX"))
7465 : {
7466 10 : ProcessSQLDropIndex(pszStatement);
7467 10 : return nullptr;
7468 : }
7469 :
7470 : /* -------------------------------------------------------------------- */
7471 : /* Handle DROP TABLE statements specially. */
7472 : /* -------------------------------------------------------------------- */
7473 2921 : if (STARTS_WITH_CI(pszStatement, "DROP TABLE"))
7474 : {
7475 500 : ProcessSQLDropTable(pszStatement);
7476 500 : return nullptr;
7477 : }
7478 :
7479 : /* -------------------------------------------------------------------- */
7480 : /* Handle ALTER TABLE statements specially. */
7481 : /* -------------------------------------------------------------------- */
7482 2421 : if (STARTS_WITH_CI(pszStatement, "ALTER TABLE"))
7483 : {
7484 11 : char **papszTokens = CSLTokenizeString(pszStatement);
7485 11 : const int nTokens = CSLCount(papszTokens);
7486 11 : if (nTokens >= 4 && EQUAL(papszTokens[3], "ADD"))
7487 : {
7488 2 : ProcessSQLAlterTableAddColumn(pszStatement);
7489 2 : CSLDestroy(papszTokens);
7490 2 : return nullptr;
7491 : }
7492 9 : else if (nTokens >= 4 && EQUAL(papszTokens[3], "DROP"))
7493 : {
7494 2 : ProcessSQLAlterTableDropColumn(pszStatement);
7495 2 : CSLDestroy(papszTokens);
7496 2 : return nullptr;
7497 : }
7498 7 : else if (nTokens == 6 && EQUAL(papszTokens[3], "RENAME") &&
7499 1 : EQUAL(papszTokens[4], "TO"))
7500 : {
7501 1 : const char *pszSrcTableName = papszTokens[2];
7502 1 : const char *pszDstTableName = papszTokens[5];
7503 1 : auto poSrcLayer = GetLayerByName(pszSrcTableName);
7504 1 : if (poSrcLayer)
7505 : {
7506 1 : CPL_IGNORE_RET_VAL(poSrcLayer->Rename(pszDstTableName));
7507 : }
7508 : else
7509 : {
7510 0 : CPLError(CE_Failure, CPLE_AppDefined, "Invalid layer name");
7511 : }
7512 1 : CSLDestroy(papszTokens);
7513 1 : return nullptr;
7514 : }
7515 6 : else if (nTokens >= 4 && EQUAL(papszTokens[3], "RENAME"))
7516 : {
7517 2 : ProcessSQLAlterTableRenameColumn(pszStatement);
7518 2 : CSLDestroy(papszTokens);
7519 2 : return nullptr;
7520 : }
7521 4 : else if (nTokens >= 4 && EQUAL(papszTokens[3], "ALTER"))
7522 : {
7523 4 : ProcessSQLAlterTableAlterColumn(pszStatement);
7524 4 : CSLDestroy(papszTokens);
7525 4 : return nullptr;
7526 : }
7527 : else
7528 : {
7529 0 : CPLError(CE_Failure, CPLE_AppDefined,
7530 : "Unsupported ALTER TABLE command : %s", pszStatement);
7531 0 : CSLDestroy(papszTokens);
7532 0 : return nullptr;
7533 : }
7534 : }
7535 :
7536 : /* -------------------------------------------------------------------- */
7537 : /* Preparse the SQL statement. */
7538 : /* -------------------------------------------------------------------- */
7539 2410 : swq_select *psSelectInfo = new swq_select();
7540 2410 : swq_custom_func_registrar *poCustomFuncRegistrar = nullptr;
7541 2410 : if (poSelectParseOptions != nullptr)
7542 8 : poCustomFuncRegistrar = poSelectParseOptions->poCustomFuncRegistrar;
7543 2410 : if (psSelectInfo->preparse(pszStatement,
7544 2410 : poCustomFuncRegistrar != nullptr) != CE_None)
7545 : {
7546 147 : delete psSelectInfo;
7547 147 : return nullptr;
7548 : }
7549 :
7550 : /* -------------------------------------------------------------------- */
7551 : /* If there is no UNION ALL, build result layer. */
7552 : /* -------------------------------------------------------------------- */
7553 2263 : if (psSelectInfo->poOtherSelect == nullptr)
7554 : {
7555 2257 : return BuildLayerFromSelectInfo(psSelectInfo, poSpatialFilter,
7556 2257 : pszDialect, poSelectParseOptions);
7557 : }
7558 :
7559 : /* -------------------------------------------------------------------- */
7560 : /* Build result union layer. */
7561 : /* -------------------------------------------------------------------- */
7562 6 : int nSrcLayers = 0;
7563 6 : OGRLayer **papoSrcLayers = nullptr;
7564 :
7565 6 : do
7566 : {
7567 12 : swq_select *psNextSelectInfo = psSelectInfo->poOtherSelect;
7568 12 : psSelectInfo->poOtherSelect = nullptr;
7569 :
7570 12 : OGRLayer *poLayer = BuildLayerFromSelectInfo(
7571 : psSelectInfo, poSpatialFilter, pszDialect, poSelectParseOptions);
7572 12 : if (poLayer == nullptr)
7573 : {
7574 : // Each source layer owns an independent select info.
7575 0 : for (int i = 0; i < nSrcLayers; ++i)
7576 0 : delete papoSrcLayers[i];
7577 0 : CPLFree(papoSrcLayers);
7578 :
7579 : // So we just have to destroy the remaining select info.
7580 0 : delete psNextSelectInfo;
7581 :
7582 0 : return nullptr;
7583 : }
7584 : else
7585 : {
7586 24 : papoSrcLayers = static_cast<OGRLayer **>(CPLRealloc(
7587 12 : papoSrcLayers, sizeof(OGRLayer *) * (nSrcLayers + 1)));
7588 12 : papoSrcLayers[nSrcLayers] = poLayer;
7589 12 : ++nSrcLayers;
7590 :
7591 12 : psSelectInfo = psNextSelectInfo;
7592 : }
7593 12 : } while (psSelectInfo != nullptr);
7594 :
7595 6 : return new OGRUnionLayer("SELECT", nSrcLayers, papoSrcLayers, TRUE);
7596 : }
7597 :
7598 : //! @endcond
7599 :
7600 : /************************************************************************/
7601 : /* AbortSQL() */
7602 : /************************************************************************/
7603 :
7604 : /**
7605 : \brief Abort any SQL statement running in the data store.
7606 :
7607 : This function can be safely called from any thread (pending that the dataset
7608 : object is still alive). Driver implementations will make sure that it can be
7609 : called in a thread-safe way.
7610 :
7611 : This might not be implemented by all drivers. At time of writing, only SQLite,
7612 : GPKG and PG drivers implement it
7613 :
7614 : This method is the same as the C method GDALDatasetAbortSQL()
7615 :
7616 : @since GDAL 3.2.0
7617 :
7618 :
7619 : */
7620 :
7621 0 : OGRErr GDALDataset::AbortSQL()
7622 : {
7623 0 : CPLError(CE_Failure, CPLE_NotSupported,
7624 : "AbortSQL is not supported for this driver.");
7625 0 : return OGRERR_UNSUPPORTED_OPERATION;
7626 : }
7627 :
7628 : /************************************************************************/
7629 : /* BuildLayerFromSelectInfo() */
7630 : /************************************************************************/
7631 :
7632 : struct GDALSQLParseInfo
7633 : {
7634 : swq_field_list sFieldList;
7635 : int nExtraDSCount;
7636 : GDALDataset **papoExtraDS;
7637 : char *pszWHERE;
7638 : };
7639 :
7640 2269 : OGRLayer *GDALDataset::BuildLayerFromSelectInfo(
7641 : swq_select *psSelectInfo, OGRGeometry *poSpatialFilter,
7642 : const char *pszDialect, swq_select_parse_options *poSelectParseOptions)
7643 : {
7644 4538 : std::unique_ptr<swq_select> psSelectInfoUnique(psSelectInfo);
7645 :
7646 2269 : std::unique_ptr<OGRGenSQLResultsLayer> poResults;
7647 : GDALSQLParseInfo *psParseInfo =
7648 2269 : BuildParseInfo(psSelectInfoUnique.get(), poSelectParseOptions);
7649 :
7650 2269 : if (psParseInfo)
7651 : {
7652 2234 : const auto nErrorCounter = CPLGetErrorCounter();
7653 4468 : poResults = std::make_unique<OGRGenSQLResultsLayer>(
7654 2234 : this, std::move(psSelectInfoUnique), poSpatialFilter,
7655 4468 : psParseInfo->pszWHERE, pszDialect);
7656 2311 : if (CPLGetErrorCounter() > nErrorCounter &&
7657 77 : CPLGetLastErrorType() != CE_None)
7658 77 : poResults.reset();
7659 : }
7660 :
7661 2269 : DestroyParseInfo(psParseInfo);
7662 :
7663 4538 : return poResults.release();
7664 : }
7665 :
7666 : /************************************************************************/
7667 : /* DestroyParseInfo() */
7668 : /************************************************************************/
7669 :
7670 : //! @cond Doxygen_Suppress
7671 2338 : void GDALDataset::DestroyParseInfo(GDALSQLParseInfo *psParseInfo)
7672 : {
7673 2338 : if (psParseInfo == nullptr)
7674 35 : return;
7675 :
7676 2303 : CPLFree(psParseInfo->sFieldList.names);
7677 2303 : CPLFree(psParseInfo->sFieldList.types);
7678 2303 : CPLFree(psParseInfo->sFieldList.table_ids);
7679 2303 : CPLFree(psParseInfo->sFieldList.ids);
7680 :
7681 : // Release the datasets we have opened with OGROpenShared()
7682 : // It is safe to do that as the 'new OGRGenSQLResultsLayer' itself
7683 : // has taken a reference on them, which it will release in its
7684 : // destructor.
7685 2310 : for (int iEDS = 0; iEDS < psParseInfo->nExtraDSCount; ++iEDS)
7686 7 : GDALClose(psParseInfo->papoExtraDS[iEDS]);
7687 :
7688 2303 : CPLFree(psParseInfo->papoExtraDS);
7689 2303 : CPLFree(psParseInfo->pszWHERE);
7690 2303 : CPLFree(psParseInfo);
7691 : }
7692 :
7693 : /************************************************************************/
7694 : /* BuildParseInfo() */
7695 : /************************************************************************/
7696 :
7697 : GDALSQLParseInfo *
7698 2303 : GDALDataset::BuildParseInfo(swq_select *psSelectInfo,
7699 : swq_select_parse_options *poSelectParseOptions)
7700 : {
7701 2303 : int nFirstLayerFirstSpecialFieldIndex = 0;
7702 :
7703 : GDALSQLParseInfo *psParseInfo =
7704 2303 : static_cast<GDALSQLParseInfo *>(CPLCalloc(1, sizeof(GDALSQLParseInfo)));
7705 :
7706 : /* -------------------------------------------------------------------- */
7707 : /* Validate that all the source tables are recognized, count */
7708 : /* fields. */
7709 : /* -------------------------------------------------------------------- */
7710 2303 : int nFieldCount = 0;
7711 :
7712 4674 : for (int iTable = 0; iTable < psSelectInfo->table_count; iTable++)
7713 : {
7714 2374 : swq_table_def *psTableDef = psSelectInfo->table_defs + iTable;
7715 2374 : GDALDataset *poTableDS = this;
7716 :
7717 2374 : if (psTableDef->data_source != nullptr)
7718 : {
7719 7 : poTableDS = GDALDataset::FromHandle(
7720 7 : OGROpenShared(psTableDef->data_source, FALSE, nullptr));
7721 7 : if (poTableDS == nullptr)
7722 : {
7723 0 : if (strlen(CPLGetLastErrorMsg()) == 0)
7724 0 : CPLError(CE_Failure, CPLE_AppDefined,
7725 : "Unable to open secondary datasource "
7726 : "`%s' required by JOIN.",
7727 : psTableDef->data_source);
7728 :
7729 0 : DestroyParseInfo(psParseInfo);
7730 0 : return nullptr;
7731 : }
7732 :
7733 : // Keep in an array to release at the end of this function.
7734 14 : psParseInfo->papoExtraDS = static_cast<GDALDataset **>(CPLRealloc(
7735 7 : psParseInfo->papoExtraDS,
7736 7 : sizeof(GDALDataset *) * (psParseInfo->nExtraDSCount + 1)));
7737 7 : psParseInfo->papoExtraDS[psParseInfo->nExtraDSCount++] = poTableDS;
7738 : }
7739 :
7740 : OGRLayer *poSrcLayer =
7741 2374 : poTableDS->GetLayerByName(psTableDef->table_name);
7742 :
7743 2374 : if (poSrcLayer == nullptr)
7744 : {
7745 3 : CPLError(CE_Failure, CPLE_AppDefined,
7746 : "SELECT from table %s failed, no such table/featureclass.",
7747 : psTableDef->table_name);
7748 :
7749 3 : DestroyParseInfo(psParseInfo);
7750 3 : return nullptr;
7751 : }
7752 :
7753 2371 : nFieldCount += poSrcLayer->GetLayerDefn()->GetFieldCount();
7754 2371 : if (iTable == 0 ||
7755 34 : (poSelectParseOptions &&
7756 34 : poSelectParseOptions->bAddSecondaryTablesGeometryFields))
7757 2334 : nFieldCount += poSrcLayer->GetLayerDefn()->GetGeomFieldCount();
7758 :
7759 2371 : const char *pszFID = poSrcLayer->GetFIDColumn();
7760 2982 : if (pszFID && !EQUAL(pszFID, "") && !EQUAL(pszFID, "FID") &&
7761 611 : poSrcLayer->GetLayerDefn()->GetFieldIndex(pszFID) < 0)
7762 561 : nFieldCount++;
7763 : }
7764 :
7765 : /* -------------------------------------------------------------------- */
7766 : /* Build the field list for all indicated tables. */
7767 : /* -------------------------------------------------------------------- */
7768 :
7769 2300 : psParseInfo->sFieldList.table_count = psSelectInfo->table_count;
7770 2300 : psParseInfo->sFieldList.table_defs = psSelectInfo->table_defs;
7771 :
7772 2300 : psParseInfo->sFieldList.count = 0;
7773 2300 : psParseInfo->sFieldList.names = static_cast<char **>(
7774 2300 : CPLMalloc(sizeof(char *) * (nFieldCount + SPECIAL_FIELD_COUNT)));
7775 4600 : psParseInfo->sFieldList.types = static_cast<swq_field_type *>(CPLMalloc(
7776 2300 : sizeof(swq_field_type) * (nFieldCount + SPECIAL_FIELD_COUNT)));
7777 2300 : psParseInfo->sFieldList.table_ids = static_cast<int *>(
7778 2300 : CPLMalloc(sizeof(int) * (nFieldCount + SPECIAL_FIELD_COUNT)));
7779 2300 : psParseInfo->sFieldList.ids = static_cast<int *>(
7780 2300 : CPLMalloc(sizeof(int) * (nFieldCount + SPECIAL_FIELD_COUNT)));
7781 :
7782 2300 : bool bIsFID64 = false;
7783 4671 : for (int iTable = 0; iTable < psSelectInfo->table_count; iTable++)
7784 : {
7785 2371 : swq_table_def *psTableDef = psSelectInfo->table_defs + iTable;
7786 2371 : GDALDataset *poTableDS = this;
7787 :
7788 2371 : if (psTableDef->data_source != nullptr)
7789 : {
7790 7 : poTableDS = GDALDataset::FromHandle(
7791 7 : OGROpenShared(psTableDef->data_source, FALSE, nullptr));
7792 7 : CPLAssert(poTableDS != nullptr);
7793 7 : poTableDS->Dereference();
7794 : }
7795 :
7796 : OGRLayer *poSrcLayer =
7797 2371 : poTableDS->GetLayerByName(psTableDef->table_name);
7798 :
7799 2371 : for (int iField = 0;
7800 18634 : iField < poSrcLayer->GetLayerDefn()->GetFieldCount(); iField++)
7801 : {
7802 : OGRFieldDefn *poFDefn =
7803 16263 : poSrcLayer->GetLayerDefn()->GetFieldDefn(iField);
7804 16263 : const int iOutField = psParseInfo->sFieldList.count++;
7805 32526 : psParseInfo->sFieldList.names[iOutField] =
7806 16263 : const_cast<char *>(poFDefn->GetNameRef());
7807 16263 : if (poFDefn->GetType() == OFTInteger)
7808 : {
7809 4094 : if (poFDefn->GetSubType() == OFSTBoolean)
7810 160 : psParseInfo->sFieldList.types[iOutField] = SWQ_BOOLEAN;
7811 : else
7812 3934 : psParseInfo->sFieldList.types[iOutField] = SWQ_INTEGER;
7813 : }
7814 12169 : else if (poFDefn->GetType() == OFTInteger64)
7815 : {
7816 773 : if (poFDefn->GetSubType() == OFSTBoolean)
7817 0 : psParseInfo->sFieldList.types[iOutField] = SWQ_BOOLEAN;
7818 : else
7819 773 : psParseInfo->sFieldList.types[iOutField] = SWQ_INTEGER64;
7820 : }
7821 11396 : else if (poFDefn->GetType() == OFTReal)
7822 2728 : psParseInfo->sFieldList.types[iOutField] = SWQ_FLOAT;
7823 8668 : else if (poFDefn->GetType() == OFTString)
7824 5606 : psParseInfo->sFieldList.types[iOutField] = SWQ_STRING;
7825 3062 : else if (poFDefn->GetType() == OFTTime)
7826 83 : psParseInfo->sFieldList.types[iOutField] = SWQ_TIME;
7827 2979 : else if (poFDefn->GetType() == OFTDate)
7828 151 : psParseInfo->sFieldList.types[iOutField] = SWQ_DATE;
7829 2828 : else if (poFDefn->GetType() == OFTDateTime)
7830 939 : psParseInfo->sFieldList.types[iOutField] = SWQ_TIMESTAMP;
7831 : else
7832 1889 : psParseInfo->sFieldList.types[iOutField] = SWQ_OTHER;
7833 :
7834 16263 : psParseInfo->sFieldList.table_ids[iOutField] = iTable;
7835 16263 : psParseInfo->sFieldList.ids[iOutField] = iField;
7836 : }
7837 :
7838 2371 : if (iTable == 0)
7839 : {
7840 2300 : nFirstLayerFirstSpecialFieldIndex = psParseInfo->sFieldList.count;
7841 : }
7842 :
7843 2371 : if (iTable == 0 ||
7844 34 : (poSelectParseOptions &&
7845 34 : poSelectParseOptions->bAddSecondaryTablesGeometryFields))
7846 : {
7847 :
7848 2334 : for (int iField = 0;
7849 4317 : iField < poSrcLayer->GetLayerDefn()->GetGeomFieldCount();
7850 : iField++)
7851 : {
7852 : OGRGeomFieldDefn *poFDefn =
7853 1983 : poSrcLayer->GetLayerDefn()->GetGeomFieldDefn(iField);
7854 1983 : const int iOutField = psParseInfo->sFieldList.count++;
7855 3966 : psParseInfo->sFieldList.names[iOutField] =
7856 1983 : const_cast<char *>(poFDefn->GetNameRef());
7857 1983 : if (*psParseInfo->sFieldList.names[iOutField] == '\0')
7858 1163 : psParseInfo->sFieldList.names[iOutField] =
7859 : const_cast<char *>(OGR_GEOMETRY_DEFAULT_NON_EMPTY_NAME);
7860 1983 : psParseInfo->sFieldList.types[iOutField] = SWQ_GEOMETRY;
7861 :
7862 1983 : psParseInfo->sFieldList.table_ids[iOutField] = iTable;
7863 1983 : psParseInfo->sFieldList.ids[iOutField] =
7864 1983 : GEOM_FIELD_INDEX_TO_ALL_FIELD_INDEX(
7865 : poSrcLayer->GetLayerDefn(), iField);
7866 : }
7867 : }
7868 :
7869 2372 : if (iTable == 0 && poSrcLayer->GetMetadataItem(OLMD_FID64) != nullptr &&
7870 1 : EQUAL(poSrcLayer->GetMetadataItem(OLMD_FID64), "YES"))
7871 : {
7872 1 : bIsFID64 = true;
7873 : }
7874 : }
7875 :
7876 : /* -------------------------------------------------------------------- */
7877 : /* Expand '*' in 'SELECT *' now before we add the pseudo fields */
7878 : /* -------------------------------------------------------------------- */
7879 2300 : const bool bAlwaysPrefixWithTableName =
7880 2342 : poSelectParseOptions &&
7881 42 : poSelectParseOptions->bAlwaysPrefixWithTableName;
7882 2300 : if (psSelectInfo->expand_wildcard(&psParseInfo->sFieldList,
7883 2300 : bAlwaysPrefixWithTableName) != CE_None)
7884 : {
7885 2 : DestroyParseInfo(psParseInfo);
7886 2 : return nullptr;
7887 : }
7888 :
7889 13788 : for (int iField = 0; iField < SPECIAL_FIELD_COUNT; iField++)
7890 : {
7891 11490 : psParseInfo->sFieldList.names[psParseInfo->sFieldList.count] =
7892 11490 : const_cast<char *>(SpecialFieldNames[iField]);
7893 11490 : psParseInfo->sFieldList.types[psParseInfo->sFieldList.count] =
7894 11490 : (iField == SPF_FID && bIsFID64) ? SWQ_INTEGER64
7895 : : SpecialFieldTypes[iField];
7896 11490 : psParseInfo->sFieldList.table_ids[psParseInfo->sFieldList.count] = 0;
7897 11490 : psParseInfo->sFieldList.ids[psParseInfo->sFieldList.count] =
7898 11490 : nFirstLayerFirstSpecialFieldIndex + iField;
7899 11490 : psParseInfo->sFieldList.count++;
7900 : }
7901 :
7902 : /* In the case a layer has an explicit FID column name, then add it */
7903 : /* so it can be selected */
7904 4667 : for (int iTable = 0; iTable < psSelectInfo->table_count; iTable++)
7905 : {
7906 2369 : swq_table_def *psTableDef = psSelectInfo->table_defs + iTable;
7907 2369 : GDALDataset *poTableDS = this;
7908 :
7909 2369 : if (psTableDef->data_source != nullptr)
7910 : {
7911 7 : poTableDS = GDALDataset::FromHandle(
7912 7 : OGROpenShared(psTableDef->data_source, FALSE, nullptr));
7913 7 : CPLAssert(poTableDS != nullptr);
7914 7 : poTableDS->Dereference();
7915 : }
7916 :
7917 : OGRLayer *poSrcLayer =
7918 2369 : poTableDS->GetLayerByName(psTableDef->table_name);
7919 :
7920 2369 : const char *pszFID = poSrcLayer->GetFIDColumn();
7921 2980 : if (pszFID && !EQUAL(pszFID, "") && !EQUAL(pszFID, "FID") &&
7922 611 : poSrcLayer->GetLayerDefn()->GetFieldIndex(pszFID) < 0)
7923 : {
7924 561 : const int iOutField = psParseInfo->sFieldList.count++;
7925 561 : psParseInfo->sFieldList.names[iOutField] =
7926 : const_cast<char *>(pszFID);
7927 561 : if (poSrcLayer->GetMetadataItem(OLMD_FID64) != nullptr &&
7928 0 : EQUAL(poSrcLayer->GetMetadataItem(OLMD_FID64), "YES"))
7929 : {
7930 0 : psParseInfo->sFieldList.types[iOutField] = SWQ_INTEGER64;
7931 : }
7932 : else
7933 : {
7934 561 : psParseInfo->sFieldList.types[iOutField] = SWQ_INTEGER;
7935 : }
7936 561 : psParseInfo->sFieldList.table_ids[iOutField] = iTable;
7937 1122 : psParseInfo->sFieldList.ids[iOutField] =
7938 561 : poSrcLayer->GetLayerDefn()->GetFieldCount() + SPF_FID;
7939 : }
7940 : }
7941 :
7942 : /* -------------------------------------------------------------------- */
7943 : /* Finish the parse operation. */
7944 : /* -------------------------------------------------------------------- */
7945 2298 : if (psSelectInfo->parse(&psParseInfo->sFieldList, poSelectParseOptions) !=
7946 : CE_None)
7947 : {
7948 30 : DestroyParseInfo(psParseInfo);
7949 30 : return nullptr;
7950 : }
7951 :
7952 : /* -------------------------------------------------------------------- */
7953 : /* Extract the WHERE expression to use separately. */
7954 : /* -------------------------------------------------------------------- */
7955 2268 : if (psSelectInfo->where_expr != nullptr)
7956 : {
7957 971 : psParseInfo->pszWHERE =
7958 971 : psSelectInfo->where_expr->Unparse(&psParseInfo->sFieldList, '"');
7959 : // CPLDebug( "OGR", "Unparse() -> %s", pszWHERE );
7960 : }
7961 :
7962 2268 : return psParseInfo;
7963 : }
7964 :
7965 : //! @endcond
7966 :
7967 : /************************************************************************/
7968 : /* ReleaseResultSet() */
7969 : /************************************************************************/
7970 :
7971 : /**
7972 : \brief Release results of ExecuteSQL().
7973 :
7974 : This method should only be used to deallocate OGRLayers resulting from
7975 : an ExecuteSQL() call on the same GDALDataset. Failure to deallocate a
7976 : results set before destroying the GDALDataset may cause errors.
7977 :
7978 : This method is the same as the C function GDALDatasetReleaseResultSet() and the
7979 : deprecated OGR_DS_ReleaseResultSet().
7980 :
7981 : @param poResultsSet the result of a previous ExecuteSQL() call.
7982 : */
7983 :
7984 2197 : void GDALDataset::ReleaseResultSet(OGRLayer *poResultsSet)
7985 :
7986 : {
7987 2197 : delete poResultsSet;
7988 2197 : }
7989 :
7990 : /************************************************************************/
7991 : /* GetStyleTable() */
7992 : /************************************************************************/
7993 :
7994 : /**
7995 : \brief Returns dataset style table.
7996 :
7997 : This method is the same as the C function GDALDatasetGetStyleTable() and the
7998 : deprecated OGR_DS_GetStyleTable().
7999 :
8000 : @return pointer to a style table which should not be modified or freed by the
8001 : caller.
8002 : */
8003 :
8004 987 : OGRStyleTable *GDALDataset::GetStyleTable()
8005 : {
8006 987 : return m_poStyleTable;
8007 : }
8008 :
8009 : /************************************************************************/
8010 : /* SetStyleTableDirectly() */
8011 : /************************************************************************/
8012 :
8013 : /**
8014 : \brief Set dataset style table.
8015 :
8016 : This method operate exactly as SetStyleTable() except that it
8017 : assumes ownership of the passed table.
8018 :
8019 : This method is the same as the C function GDALDatasetSetStyleTableDirectly()
8020 : and the deprecated OGR_DS_SetStyleTableDirectly().
8021 :
8022 : @param poStyleTable pointer to style table to set
8023 :
8024 : */
8025 0 : void GDALDataset::SetStyleTableDirectly(OGRStyleTable *poStyleTable)
8026 : {
8027 0 : if (m_poStyleTable)
8028 0 : delete m_poStyleTable;
8029 0 : m_poStyleTable = poStyleTable;
8030 0 : }
8031 :
8032 : /************************************************************************/
8033 : /* SetStyleTable() */
8034 : /************************************************************************/
8035 :
8036 : /**
8037 : \brief Set dataset style table.
8038 :
8039 : This method operate exactly as SetStyleTableDirectly() except
8040 : that it does not assume ownership of the passed table.
8041 :
8042 : This method is the same as the C function GDALDatasetSetStyleTable() and the
8043 : deprecated OGR_DS_SetStyleTable().
8044 :
8045 : @param poStyleTable pointer to style table to set
8046 :
8047 : */
8048 :
8049 983 : void GDALDataset::SetStyleTable(OGRStyleTable *poStyleTable)
8050 : {
8051 983 : if (m_poStyleTable)
8052 0 : delete m_poStyleTable;
8053 983 : if (poStyleTable)
8054 1 : m_poStyleTable = poStyleTable->Clone();
8055 983 : }
8056 :
8057 : /************************************************************************/
8058 : /* IsGenericSQLDialect() */
8059 : /************************************************************************/
8060 :
8061 : //! @cond Doxygen_Suppress
8062 1780 : int GDALDataset::IsGenericSQLDialect(const char *pszDialect)
8063 : {
8064 3252 : return pszDialect != nullptr &&
8065 3252 : (EQUAL(pszDialect, "OGRSQL") || EQUAL(pszDialect, "SQLITE"));
8066 : }
8067 :
8068 : //! @endcond
8069 :
8070 : /************************************************************************/
8071 : /* GetLayerCount() */
8072 : /************************************************************************/
8073 :
8074 : /**
8075 : \brief Get the number of layers in this dataset.
8076 :
8077 : This method is the same as the C function GDALDatasetGetLayerCount(),
8078 : and the deprecated OGR_DS_GetLayerCount().
8079 :
8080 : Note that even if this method is const, there is no guarantee it can be
8081 : safely called by concurrent threads on the same GDALDataset object.
8082 :
8083 : @return layer count.
8084 : */
8085 :
8086 121672 : int GDALDataset::GetLayerCount() const
8087 : {
8088 121672 : return 0;
8089 : }
8090 :
8091 : /************************************************************************/
8092 : /* GetLayer() */
8093 : /************************************************************************/
8094 :
8095 : /**
8096 : \fn const GDALDataset::GetLayer(int) const
8097 : \brief Fetch a layer by index.
8098 :
8099 : The returned layer remains owned by the
8100 : GDALDataset and should not be deleted by the application.
8101 :
8102 : Note that even if this method is const, there is no guarantee it can be
8103 : safely called by concurrent threads on the same GDALDataset object.
8104 :
8105 : See GetLayers() for a C++ iterator version of this method.
8106 :
8107 : This method is the same as the C function GDALDatasetGetLayer() and the
8108 : deprecated OGR_DS_GetLayer().
8109 :
8110 : @param iLayer a layer number between 0 and GetLayerCount()-1.
8111 :
8112 : @return the layer, or NULL if iLayer is out of range or an error occurs.
8113 :
8114 : @see GetLayers()
8115 :
8116 : @since GDAL 3.12
8117 : */
8118 :
8119 0 : const OGRLayer *GDALDataset::GetLayer(CPL_UNUSED int iLayer) const
8120 : {
8121 0 : return nullptr;
8122 : }
8123 :
8124 : /**
8125 : \fn GDALDataset::GetLayer(int)
8126 : \brief Fetch a layer by index.
8127 :
8128 : The returned layer remains owned by the
8129 : GDALDataset and should not be deleted by the application.
8130 :
8131 : See GetLayers() for a C++ iterator version of this method.
8132 :
8133 : This method is the same as the C function GDALDatasetGetLayer() and the
8134 : deprecated OGR_DS_GetLayer().
8135 :
8136 : @param iLayer a layer number between 0 and GetLayerCount()-1.
8137 :
8138 : @return the layer, or NULL if iLayer is out of range or an error occurs.
8139 :
8140 : @see GetLayers()
8141 : */
8142 :
8143 : /************************************************************************/
8144 : /* IsLayerPrivate() */
8145 : /************************************************************************/
8146 :
8147 : /**
8148 : \fn GDALDataset::IsLayerPrivate(int)
8149 : \brief Returns true if the layer at the specified index is deemed a private or
8150 : system table, or an internal detail only.
8151 :
8152 : This method is the same as the C function GDALDatasetIsLayerPrivate().
8153 :
8154 : @param iLayer a layer number between 0 and GetLayerCount()-1.
8155 :
8156 : @return true if the layer is a private or system table.
8157 :
8158 : @since GDAL 3.4
8159 : */
8160 :
8161 1005 : bool GDALDataset::IsLayerPrivate(CPL_UNUSED int iLayer) const
8162 : {
8163 1005 : return false;
8164 : }
8165 :
8166 : /************************************************************************/
8167 : /* ResetReading() */
8168 : /************************************************************************/
8169 :
8170 : /**
8171 : \brief Reset feature reading to start on the first feature.
8172 :
8173 : This affects GetNextFeature().
8174 :
8175 : Depending on drivers, this may also have the side effect of calling
8176 : OGRLayer::ResetReading() on the layers of this dataset.
8177 :
8178 : This method is the same as the C function GDALDatasetResetReading().
8179 :
8180 : */
8181 7 : void GDALDataset::ResetReading()
8182 : {
8183 7 : if (!m_poPrivate)
8184 0 : return;
8185 7 : m_poPrivate->nCurrentLayerIdx = 0;
8186 7 : m_poPrivate->nLayerCount = -1;
8187 7 : m_poPrivate->poCurrentLayer = nullptr;
8188 7 : m_poPrivate->nFeatureReadInLayer = 0;
8189 7 : m_poPrivate->nFeatureReadInDataset = 0;
8190 7 : m_poPrivate->nTotalFeaturesInLayer = TOTAL_FEATURES_NOT_INIT;
8191 7 : m_poPrivate->nTotalFeatures = TOTAL_FEATURES_NOT_INIT;
8192 : }
8193 :
8194 : /************************************************************************/
8195 : /* GDALDatasetResetReading() */
8196 : /************************************************************************/
8197 :
8198 : /**
8199 : \brief Reset feature reading to start on the first feature.
8200 :
8201 : This affects GDALDatasetGetNextFeature().
8202 :
8203 : Depending on drivers, this may also have the side effect of calling
8204 : OGR_L_ResetReading() on the layers of this dataset.
8205 :
8206 : This method is the same as the C++ method GDALDataset::ResetReading()
8207 :
8208 : @param hDS dataset handle
8209 : */
8210 14 : void CPL_DLL GDALDatasetResetReading(GDALDatasetH hDS)
8211 : {
8212 14 : VALIDATE_POINTER0(hDS, "GDALDatasetResetReading");
8213 :
8214 14 : return GDALDataset::FromHandle(hDS)->ResetReading();
8215 : }
8216 :
8217 : /************************************************************************/
8218 : /* GetNextFeature() */
8219 : /************************************************************************/
8220 :
8221 : /**
8222 : \brief Fetch the next available feature from this dataset.
8223 :
8224 : This method is intended for the few drivers where OGRLayer::GetNextFeature()
8225 : is not efficient, but in general OGRLayer::GetNextFeature() is a more
8226 : natural API.
8227 :
8228 : See GetFeatures() for a C++ iterator version of this method.
8229 :
8230 : The returned feature becomes the responsibility of the caller to
8231 : delete with OGRFeature::DestroyFeature().
8232 :
8233 : Depending on the driver, this method may return features from layers in a
8234 : non sequential way. This is what may happen when the
8235 : ODsCRandomLayerRead capability is declared (for example for the
8236 : OSM and GMLAS drivers). When datasets declare this capability, it is strongly
8237 : advised to use GDALDataset::GetNextFeature() instead of
8238 : OGRLayer::GetNextFeature(), as the later might have a slow, incomplete or stub
8239 : implementation.
8240 :
8241 : The default implementation, used by most drivers, will
8242 : however iterate over each layer, and then over each feature within this
8243 : layer.
8244 :
8245 : This method takes into account spatial and attribute filters set on layers that
8246 : will be iterated upon.
8247 :
8248 : The ResetReading() method can be used to start at the beginning again.
8249 :
8250 : Depending on drivers, this may also have the side effect of calling
8251 : OGRLayer::GetNextFeature() on the layers of this dataset.
8252 :
8253 : This method is the same as the C function GDALDatasetGetNextFeature().
8254 :
8255 : @param ppoBelongingLayer a pointer to a OGRLayer* variable to receive the
8256 : layer to which the object belongs to, or NULL.
8257 : It is possible that the output of *ppoBelongingLayer
8258 : to be NULL despite the feature not being NULL.
8259 : @param pdfProgressPct a pointer to a double variable to receive the
8260 : percentage progress (in [0,1] range), or NULL.
8261 : On return, the pointed value might be negative if
8262 : determining the progress is not possible.
8263 : @param pfnProgress a progress callback to report progress (for
8264 : GetNextFeature() calls that might have a long
8265 : duration) and offer cancellation possibility, or NULL.
8266 : @param pProgressData user data provided to pfnProgress, or NULL
8267 : @return a feature, or NULL if no more features are available.
8268 : @see GetFeatures()
8269 : */
8270 :
8271 68 : OGRFeature *GDALDataset::GetNextFeature(OGRLayer **ppoBelongingLayer,
8272 : double *pdfProgressPct,
8273 : GDALProgressFunc pfnProgress,
8274 : void *pProgressData)
8275 : {
8276 68 : if (!m_poPrivate || m_poPrivate->nCurrentLayerIdx < 0)
8277 : {
8278 2 : if (ppoBelongingLayer != nullptr)
8279 2 : *ppoBelongingLayer = nullptr;
8280 2 : if (pdfProgressPct != nullptr)
8281 1 : *pdfProgressPct = 1.0;
8282 2 : if (pfnProgress != nullptr)
8283 0 : pfnProgress(1.0, "", pProgressData);
8284 2 : return nullptr;
8285 : }
8286 :
8287 66 : if (m_poPrivate->poCurrentLayer == nullptr &&
8288 11 : (pdfProgressPct != nullptr || pfnProgress != nullptr))
8289 : {
8290 4 : if (m_poPrivate->nLayerCount < 0)
8291 : {
8292 4 : m_poPrivate->nLayerCount = GetLayerCount();
8293 : }
8294 :
8295 4 : if (m_poPrivate->nTotalFeatures == TOTAL_FEATURES_NOT_INIT)
8296 : {
8297 4 : m_poPrivate->nTotalFeatures = 0;
8298 8 : for (int i = 0; i < m_poPrivate->nLayerCount; i++)
8299 : {
8300 7 : OGRLayer *poLayer = GetLayer(i);
8301 14 : if (poLayer == nullptr ||
8302 7 : !poLayer->TestCapability(OLCFastFeatureCount))
8303 : {
8304 3 : m_poPrivate->nTotalFeatures = TOTAL_FEATURES_UNKNOWN;
8305 3 : break;
8306 : }
8307 4 : GIntBig nCount = poLayer->GetFeatureCount(FALSE);
8308 4 : if (nCount < 0)
8309 : {
8310 0 : m_poPrivate->nTotalFeatures = TOTAL_FEATURES_UNKNOWN;
8311 0 : break;
8312 : }
8313 4 : m_poPrivate->nTotalFeatures += nCount;
8314 : }
8315 : }
8316 : }
8317 :
8318 : while (true)
8319 : {
8320 82 : if (m_poPrivate->poCurrentLayer == nullptr)
8321 : {
8322 56 : m_poPrivate->poCurrentLayer =
8323 28 : GetLayer(m_poPrivate->nCurrentLayerIdx);
8324 28 : if (m_poPrivate->poCurrentLayer == nullptr)
8325 : {
8326 10 : m_poPrivate->nCurrentLayerIdx = -1;
8327 10 : if (ppoBelongingLayer != nullptr)
8328 7 : *ppoBelongingLayer = nullptr;
8329 10 : if (pdfProgressPct != nullptr)
8330 1 : *pdfProgressPct = 1.0;
8331 10 : return nullptr;
8332 : }
8333 18 : m_poPrivate->poCurrentLayer->ResetReading();
8334 18 : m_poPrivate->nFeatureReadInLayer = 0;
8335 18 : if (m_poPrivate->nTotalFeatures < 0 && pdfProgressPct != nullptr)
8336 : {
8337 0 : if (m_poPrivate->poCurrentLayer->TestCapability(
8338 0 : OLCFastFeatureCount))
8339 0 : m_poPrivate->nTotalFeaturesInLayer =
8340 0 : m_poPrivate->poCurrentLayer->GetFeatureCount(FALSE);
8341 : else
8342 0 : m_poPrivate->nTotalFeaturesInLayer = 0;
8343 : }
8344 : }
8345 72 : OGRFeature *poFeature = m_poPrivate->poCurrentLayer->GetNextFeature();
8346 72 : if (poFeature == nullptr)
8347 : {
8348 16 : m_poPrivate->nCurrentLayerIdx++;
8349 16 : m_poPrivate->poCurrentLayer = nullptr;
8350 16 : continue;
8351 : }
8352 :
8353 56 : m_poPrivate->nFeatureReadInLayer++;
8354 56 : m_poPrivate->nFeatureReadInDataset++;
8355 56 : if (pdfProgressPct != nullptr || pfnProgress != nullptr)
8356 : {
8357 9 : double dfPct = 0.0;
8358 9 : if (m_poPrivate->nTotalFeatures > 0)
8359 : {
8360 4 : dfPct = 1.0 * m_poPrivate->nFeatureReadInDataset /
8361 4 : m_poPrivate->nTotalFeatures;
8362 : }
8363 : else
8364 : {
8365 5 : dfPct = 1.0 * m_poPrivate->nCurrentLayerIdx /
8366 5 : m_poPrivate->nLayerCount;
8367 5 : if (m_poPrivate->nTotalFeaturesInLayer > 0)
8368 : {
8369 0 : dfPct += 1.0 * m_poPrivate->nFeatureReadInLayer /
8370 0 : m_poPrivate->nTotalFeaturesInLayer /
8371 0 : m_poPrivate->nLayerCount;
8372 : }
8373 : }
8374 9 : if (pdfProgressPct)
8375 4 : *pdfProgressPct = dfPct;
8376 9 : if (pfnProgress)
8377 5 : pfnProgress(dfPct, "", nullptr);
8378 : }
8379 :
8380 56 : if (ppoBelongingLayer != nullptr)
8381 51 : *ppoBelongingLayer = m_poPrivate->poCurrentLayer;
8382 56 : return poFeature;
8383 16 : }
8384 : }
8385 :
8386 : /************************************************************************/
8387 : /* GDALDatasetGetNextFeature() */
8388 : /************************************************************************/
8389 : /**
8390 : \brief Fetch the next available feature from this dataset.
8391 :
8392 : This method is intended for the few drivers where OGR_L_GetNextFeature()
8393 : is not efficient, but in general OGR_L_GetNextFeature() is a more
8394 : natural API.
8395 :
8396 : The returned feature becomes the responsibility of the caller to
8397 : delete with OGRFeature::DestroyFeature().
8398 :
8399 : Depending on the driver, this method may return features from layers in a
8400 : non sequential way. This is what may happen when the
8401 : ODsCRandomLayerRead capability is declared (for example for the
8402 : OSM and GMLAS drivers). When datasets declare this capability, it is strongly
8403 : advised to use GDALDataset::GetNextFeature() instead of
8404 : OGRLayer::GetNextFeature(), as the later might have a slow, incomplete or stub
8405 : implementation.
8406 :
8407 : The default implementation, used by most drivers, will
8408 : however iterate over each layer, and then over each feature within this
8409 : layer.
8410 :
8411 : This method takes into account spatial and attribute filters set on layers that
8412 : will be iterated upon.
8413 :
8414 : The ResetReading() method can be used to start at the beginning again.
8415 :
8416 : Depending on drivers, this may also have the side effect of calling
8417 : OGRLayer::GetNextFeature() on the layers of this dataset.
8418 :
8419 : This method is the same as the C++ method GDALDataset::GetNextFeature()
8420 :
8421 : @param hDS dataset handle.
8422 : @param phBelongingLayer a pointer to a OGRLayer* variable to receive the
8423 : layer to which the object belongs to, or NULL.
8424 : It is possible that the output of *ppoBelongingLayer
8425 : to be NULL despite the feature not being NULL.
8426 : @param pdfProgressPct a pointer to a double variable to receive the
8427 : percentage progress (in [0,1] range), or NULL.
8428 : On return, the pointed value might be negative if
8429 : determining the progress is not possible.
8430 : @param pfnProgress a progress callback to report progress (for
8431 : GetNextFeature() calls that might have a long
8432 : duration) and offer cancellation possibility, or NULL
8433 : @param pProgressData user data provided to pfnProgress, or NULL
8434 : @return a feature, or NULL if no more features are available.
8435 : */
8436 1917 : OGRFeatureH CPL_DLL GDALDatasetGetNextFeature(GDALDatasetH hDS,
8437 : OGRLayerH *phBelongingLayer,
8438 : double *pdfProgressPct,
8439 : GDALProgressFunc pfnProgress,
8440 : void *pProgressData)
8441 : {
8442 1917 : VALIDATE_POINTER1(hDS, "GDALDatasetGetNextFeature", nullptr);
8443 :
8444 3834 : return OGRFeature::ToHandle(GDALDataset::FromHandle(hDS)->GetNextFeature(
8445 : reinterpret_cast<OGRLayer **>(phBelongingLayer), pdfProgressPct,
8446 3834 : pfnProgress, pProgressData));
8447 : }
8448 :
8449 : /************************************************************************/
8450 : /* TestCapability() */
8451 : /************************************************************************/
8452 :
8453 : /**
8454 : \fn GDALDataset::TestCapability( const char * pszCap )
8455 : \brief Test if capability is available.
8456 :
8457 : One of the following dataset capability names can be passed into this
8458 : method, and a TRUE or FALSE value will be returned indicating whether or not
8459 : the capability is available for this object.
8460 :
8461 : <ul>
8462 : <li> <b>ODsCCreateLayer</b>: True if this datasource can create new layers.<p>
8463 : <li> <b>ODsCDeleteLayer</b>: True if this datasource can delete existing
8464 : layers.<p>
8465 : <li> <b>ODsCCreateGeomFieldAfterCreateLayer</b>: True if the layers of this
8466 : datasource support CreateGeomField() just after layer creation.<p>
8467 : <li> <b>ODsCCurveGeometries</b>: True if this datasource supports curve
8468 : geometries.<p>
8469 : <li> <b>ODsCTransactions</b>: True if this datasource supports (efficient)
8470 : transactions.<p>
8471 : <li> <b>ODsCEmulatedTransactions</b>: True if this datasource supports
8472 : transactions through emulation.<p>
8473 : <li> <b>ODsCRandomLayerRead</b>: True if this datasource has a dedicated
8474 : GetNextFeature() implementation, potentially returning features from
8475 : layers in a non sequential way.<p>
8476 : <li> <b>ODsCRandomLayerWrite</b>: True if this datasource supports calling
8477 : CreateFeature() on layers in a non sequential way.<p>
8478 : <li> <b>GDsCAddRelationship</b>: True if AddRelationship() is supported</li>
8479 : <li> <b>GDsCDeleteRelationship</b>: True if DeleteRelationship() is supported</li>
8480 : <li> <b>GDsCUpdateRelationship</b>: True if UpdateRelationship() is supported</li>
8481 : <li> <b>GDsCFastGetExtent</b>: True if GetExtent() is fast</li>
8482 : <li> <b>GDsCFastGetExtentWGS84LongLat</b>: True if GetExtentWGS84LongLat() is fast</li>
8483 : </ul>
8484 :
8485 : The \#define macro forms of the capability names should be used in preference
8486 : to the strings themselves to avoid misspelling.
8487 :
8488 : This method is the same as the C function GDALDatasetTestCapability() and the
8489 : deprecated OGR_DS_TestCapability().
8490 :
8491 : @param pszCap the capability to test.
8492 :
8493 : @return TRUE if capability available otherwise FALSE.
8494 : */
8495 :
8496 798 : int GDALDataset::TestCapability(const char *pszCap) const
8497 : {
8498 798 : if (EQUAL(pszCap, GDsCFastGetExtent) ||
8499 796 : EQUAL(pszCap, GDsCFastGetExtentWGS84LongLat))
8500 : {
8501 4 : for (auto &&poLayer : GetLayers())
8502 : {
8503 2 : if (!poLayer->TestCapability(OLCFastGetExtent))
8504 2 : return FALSE;
8505 : }
8506 2 : return TRUE;
8507 : }
8508 794 : return FALSE;
8509 : }
8510 :
8511 : /************************************************************************/
8512 : /* GDALDatasetTestCapability() */
8513 : /************************************************************************/
8514 :
8515 : /**
8516 : \brief Test if capability is available.
8517 :
8518 : One of the following dataset capability names can be passed into this
8519 : function, and a TRUE or FALSE value will be returned indicating whether or not
8520 : the capability is available for this object.
8521 :
8522 : <ul>
8523 : <li> <b>ODsCCreateLayer</b>: True if this datasource can create new layers.<p>
8524 : <li> <b>ODsCDeleteLayer</b>: True if this datasource can delete existing
8525 : layers.<p>
8526 : <li> <b>ODsCCreateGeomFieldAfterCreateLayer</b>: True if the layers of this
8527 : datasource support CreateGeomField() just after layer creation.<p>
8528 : <li> <b>ODsCCurveGeometries</b>: True if this datasource supports curve
8529 : geometries.<p>
8530 : <li> <b>ODsCTransactions</b>: True if this datasource supports (efficient)
8531 : transactions.<p>
8532 : <li> <b>ODsCEmulatedTransactions</b>: True if this datasource supports
8533 : transactions through emulation.<p>
8534 : <li> <b>ODsCRandomLayerRead</b>: True if this datasource has a dedicated
8535 : GetNextFeature() implementation, potentially returning features from
8536 : layers in a non sequential way.<p>
8537 : <li> <b>ODsCRandomLayerWrite</b>: True if this datasource supports calling
8538 : CreateFeature() on layers in a non sequential way.<p>
8539 : <li> <b>GDsCAddRelationship</b>: True if AddRelationship() is supported</li>
8540 : <li> <b>GDsCDeleteRelationship</b>: True if DeleteRelationship() is supported</li>
8541 : <li> <b>GDsCUpdateRelationship</b>: True if UpdateRelationship() is supported</li>
8542 : <li> <b>GDsCFastGetExtent</b>: True if GetExtent() is fast</li>
8543 : <li> <b>GDsCFastGetExtentWGS84LongLat</b>: True if GetExtentWGS84LongLat() is fast</li>
8544 : </ul>
8545 :
8546 : The \#define macro forms of the capability names should be used in preference
8547 : to the strings themselves to avoid misspelling.
8548 :
8549 : This function is the same as the C++ method GDALDataset::TestCapability()
8550 :
8551 :
8552 : @param hDS the dataset handle.
8553 : @param pszCap the capability to test.
8554 :
8555 : @return TRUE if capability available otherwise FALSE.
8556 : */
8557 130 : int GDALDatasetTestCapability(GDALDatasetH hDS, const char *pszCap)
8558 :
8559 : {
8560 130 : VALIDATE_POINTER1(hDS, "GDALDatasetTestCapability", 0);
8561 130 : VALIDATE_POINTER1(pszCap, "GDALDatasetTestCapability", 0);
8562 :
8563 130 : return GDALDataset::FromHandle(hDS)->TestCapability(pszCap);
8564 : }
8565 :
8566 : /************************************************************************/
8567 : /* StartTransaction() */
8568 : /************************************************************************/
8569 :
8570 : /**
8571 : \fn GDALDataset::StartTransaction(int)
8572 : \brief For datasources which support transactions, StartTransaction creates a
8573 : `transaction.
8574 :
8575 : If starting the transaction fails, will return
8576 : OGRERR_FAILURE. Datasources which do not support transactions will
8577 : always return OGRERR_UNSUPPORTED_OPERATION.
8578 :
8579 : Nested transactions are not supported.
8580 :
8581 : All changes done after the start of the transaction are definitely applied in
8582 : the datasource if CommitTransaction() is called. They may be canceled by
8583 : calling RollbackTransaction() instead.
8584 :
8585 : At the time of writing, transactions only apply on vector layers.
8586 :
8587 : Datasets that support transactions will advertise the ODsCTransactions
8588 : capability. Use of transactions at dataset level is generally preferred to
8589 : transactions at layer level, whose scope is rarely limited to the layer from
8590 : which it was started.
8591 :
8592 : In case StartTransaction() fails, neither CommitTransaction() or
8593 : RollbackTransaction() should be called.
8594 :
8595 : If an error occurs after a successful StartTransaction(), the whole transaction
8596 : may or may not be implicitly canceled, depending on drivers. (e.g. the PG
8597 : driver will cancel it, SQLite/GPKG not). In any case, in the event of an error,
8598 : an explicit call to RollbackTransaction() should be done to keep things
8599 : balanced.
8600 :
8601 : By default, when bForce is set to FALSE, only "efficient" transactions will be
8602 : attempted. Some drivers may offer an emulation of transactions, but sometimes
8603 : with significant overhead, in which case the user must explicitly allow for
8604 : such an emulation by setting bForce to TRUE. Drivers that offer emulated
8605 : transactions should advertise the ODsCEmulatedTransactions capability (and not
8606 : ODsCTransactions).
8607 :
8608 : This function is the same as the C function GDALDatasetStartTransaction().
8609 :
8610 : @param bForce can be set to TRUE if an emulation, possibly slow, of a
8611 : transaction
8612 : mechanism is acceptable.
8613 :
8614 : @return OGRERR_NONE on success.
8615 : */
8616 :
8617 37 : OGRErr GDALDataset::StartTransaction(CPL_UNUSED int bForce)
8618 : {
8619 37 : return OGRERR_UNSUPPORTED_OPERATION;
8620 : }
8621 :
8622 : /************************************************************************/
8623 : /* GDALDatasetStartTransaction() */
8624 : /************************************************************************/
8625 :
8626 : /**
8627 : \brief For datasources which support transactions, StartTransaction creates a
8628 : transaction.
8629 :
8630 : If starting the transaction fails, will return
8631 : OGRERR_FAILURE. Datasources which do not support transactions will
8632 : always return OGRERR_UNSUPPORTED_OPERATION.
8633 :
8634 : Nested transactions are not supported.
8635 :
8636 : All changes done after the start of the transaction are definitely applied in
8637 : the datasource if CommitTransaction() is called. They may be canceled by
8638 : calling RollbackTransaction() instead.
8639 :
8640 : At the time of writing, transactions only apply on vector layers.
8641 :
8642 : Datasets that support transactions will advertise the ODsCTransactions
8643 : capability.
8644 : Use of transactions at dataset level is generally preferred to transactions at
8645 : layer level, whose scope is rarely limited to the layer from which it was
8646 : started.
8647 :
8648 : In case StartTransaction() fails, neither CommitTransaction() or
8649 : RollbackTransaction() should be called.
8650 :
8651 : If an error occurs after a successful StartTransaction(), the whole
8652 : transaction may or may not be implicitly canceled, depending on drivers. (e.g.
8653 : the PG driver will cancel it, SQLite/GPKG not). In any case, in the event of an
8654 : error, an explicit call to RollbackTransaction() should be done to keep things
8655 : balanced.
8656 :
8657 : By default, when bForce is set to FALSE, only "efficient" transactions will be
8658 : attempted. Some drivers may offer an emulation of transactions, but sometimes
8659 : with significant overhead, in which case the user must explicitly allow for
8660 : such an emulation by setting bForce to TRUE. Drivers that offer emulated
8661 : transactions should advertise the ODsCEmulatedTransactions capability (and not
8662 : ODsCTransactions).
8663 :
8664 : This function is the same as the C++ method GDALDataset::StartTransaction()
8665 :
8666 : @param hDS the dataset handle.
8667 : @param bForce can be set to TRUE if an emulation, possibly slow, of a
8668 : transaction
8669 : mechanism is acceptable.
8670 :
8671 : @return OGRERR_NONE on success.
8672 : */
8673 106 : OGRErr GDALDatasetStartTransaction(GDALDatasetH hDS, int bForce)
8674 : {
8675 106 : VALIDATE_POINTER1(hDS, "GDALDatasetStartTransaction",
8676 : OGRERR_INVALID_HANDLE);
8677 :
8678 : #ifdef OGRAPISPY_ENABLED
8679 106 : if (bOGRAPISpyEnabled)
8680 2 : OGRAPISpy_Dataset_StartTransaction(hDS, bForce);
8681 : #endif
8682 :
8683 106 : return GDALDataset::FromHandle(hDS)->StartTransaction(bForce);
8684 : }
8685 :
8686 : /************************************************************************/
8687 : /* CommitTransaction() */
8688 : /************************************************************************/
8689 :
8690 : /**
8691 : \brief For datasources which support transactions, CommitTransaction commits a
8692 : transaction.
8693 :
8694 : If no transaction is active, or the commit fails, will return
8695 : OGRERR_FAILURE. Datasources which do not support transactions will
8696 : always return OGRERR_UNSUPPORTED_OPERATION.
8697 :
8698 : Depending on drivers, this may or may not abort layer sequential readings that
8699 : are active.
8700 :
8701 : This function is the same as the C function GDALDatasetCommitTransaction().
8702 :
8703 : @return OGRERR_NONE on success.
8704 : */
8705 52 : OGRErr GDALDataset::CommitTransaction()
8706 : {
8707 52 : return OGRERR_UNSUPPORTED_OPERATION;
8708 : }
8709 :
8710 : /************************************************************************/
8711 : /* GDALDatasetCommitTransaction() */
8712 : /************************************************************************/
8713 :
8714 : /**
8715 : \brief For datasources which support transactions, CommitTransaction commits a
8716 : transaction.
8717 :
8718 : If no transaction is active, or the commit fails, will return
8719 : OGRERR_FAILURE. Datasources which do not support transactions will
8720 : always return OGRERR_UNSUPPORTED_OPERATION.
8721 :
8722 : Depending on drivers, this may or may not abort layer sequential readings that
8723 : are active.
8724 :
8725 : This function is the same as the C++ method GDALDataset::CommitTransaction()
8726 :
8727 : @return OGRERR_NONE on success.
8728 : */
8729 77 : OGRErr GDALDatasetCommitTransaction(GDALDatasetH hDS)
8730 : {
8731 77 : VALIDATE_POINTER1(hDS, "GDALDatasetCommitTransaction",
8732 : OGRERR_INVALID_HANDLE);
8733 :
8734 : #ifdef OGRAPISPY_ENABLED
8735 77 : if (bOGRAPISpyEnabled)
8736 2 : OGRAPISpy_Dataset_CommitTransaction(hDS);
8737 : #endif
8738 :
8739 77 : return GDALDataset::FromHandle(hDS)->CommitTransaction();
8740 : }
8741 :
8742 : /************************************************************************/
8743 : /* RollbackTransaction() */
8744 : /************************************************************************/
8745 :
8746 : /**
8747 : \brief For datasources which support transactions, RollbackTransaction will
8748 : roll back a datasource to its state before the start of the current
8749 : transaction.
8750 : If no transaction is active, or the rollback fails, will return
8751 : OGRERR_FAILURE. Datasources which do not support transactions will
8752 : always return OGRERR_UNSUPPORTED_OPERATION.
8753 :
8754 : This function is the same as the C function GDALDatasetRollbackTransaction().
8755 :
8756 : @return OGRERR_NONE on success.
8757 : */
8758 2 : OGRErr GDALDataset::RollbackTransaction()
8759 : {
8760 2 : return OGRERR_UNSUPPORTED_OPERATION;
8761 : }
8762 :
8763 : /************************************************************************/
8764 : /* GDALDatasetRollbackTransaction() */
8765 : /************************************************************************/
8766 :
8767 : /**
8768 : \brief For datasources which support transactions, RollbackTransaction will
8769 : roll back a datasource to its state before the start of the current
8770 : transaction.
8771 : If no transaction is active, or the rollback fails, will return
8772 : OGRERR_FAILURE. Datasources which do not support transactions will
8773 : always return OGRERR_UNSUPPORTED_OPERATION.
8774 :
8775 : This function is the same as the C++ method GDALDataset::RollbackTransaction().
8776 :
8777 : @return OGRERR_NONE on success.
8778 : */
8779 44 : OGRErr GDALDatasetRollbackTransaction(GDALDatasetH hDS)
8780 : {
8781 44 : VALIDATE_POINTER1(hDS, "GDALDatasetRollbackTransaction",
8782 : OGRERR_INVALID_HANDLE);
8783 :
8784 : #ifdef OGRAPISPY_ENABLED
8785 44 : if (bOGRAPISpyEnabled)
8786 2 : OGRAPISpy_Dataset_RollbackTransaction(hDS);
8787 : #endif
8788 :
8789 44 : return GDALDataset::FromHandle(hDS)->RollbackTransaction();
8790 : }
8791 :
8792 : //! @cond Doxygen_Suppress
8793 :
8794 : /************************************************************************/
8795 : /* ShareLockWithParentDataset() */
8796 : /************************************************************************/
8797 :
8798 : /* To be used typically by the GTiff driver to link overview datasets */
8799 : /* with their main dataset, so that they share the same lock */
8800 : /* Cf https://github.com/OSGeo/gdal/issues/1488 */
8801 : /* The parent dataset should remain alive while the this dataset is alive */
8802 :
8803 2340 : void GDALDataset::ShareLockWithParentDataset(GDALDataset *poParentDataset)
8804 : {
8805 2340 : if (m_poPrivate != nullptr)
8806 : {
8807 2340 : m_poPrivate->poParentDataset = poParentDataset;
8808 : }
8809 2340 : }
8810 :
8811 : /************************************************************************/
8812 : /* SetQueryLoggerFunc() */
8813 : /************************************************************************/
8814 :
8815 0 : bool GDALDataset::SetQueryLoggerFunc(CPL_UNUSED GDALQueryLoggerFunc callback,
8816 : CPL_UNUSED void *context)
8817 : {
8818 0 : return false;
8819 : }
8820 :
8821 : /************************************************************************/
8822 : /* EnterReadWrite() */
8823 : /************************************************************************/
8824 :
8825 8270070 : int GDALDataset::EnterReadWrite(GDALRWFlag eRWFlag)
8826 : {
8827 16540100 : if (m_poPrivate == nullptr ||
8828 8270070 : IsThreadSafe(GDAL_OF_RASTER | (nOpenFlags & GDAL_OF_UPDATE)))
8829 11992 : return FALSE;
8830 :
8831 8258080 : if (m_poPrivate->poParentDataset)
8832 242627 : return m_poPrivate->poParentDataset->EnterReadWrite(eRWFlag);
8833 :
8834 8015450 : if (eAccess == GA_Update)
8835 : {
8836 2411220 : if (m_poPrivate->eStateReadWriteMutex ==
8837 : GDALAllowReadWriteMutexState::RW_MUTEX_STATE_UNKNOWN)
8838 : {
8839 : // In case dead-lock would occur, which is not impossible,
8840 : // this can be used to prevent it, but at the risk of other
8841 : // issues.
8842 10920 : if (CPLTestBool(
8843 : CPLGetConfigOption("GDAL_ENABLE_READ_WRITE_MUTEX", "YES")))
8844 : {
8845 10920 : m_poPrivate->eStateReadWriteMutex =
8846 : GDALAllowReadWriteMutexState::RW_MUTEX_STATE_ALLOWED;
8847 : }
8848 : else
8849 : {
8850 0 : m_poPrivate->eStateReadWriteMutex =
8851 : GDALAllowReadWriteMutexState::RW_MUTEX_STATE_DISABLED;
8852 : }
8853 : }
8854 2411220 : if (m_poPrivate->eStateReadWriteMutex ==
8855 : GDALAllowReadWriteMutexState::RW_MUTEX_STATE_ALLOWED)
8856 : {
8857 : // There should be no race related to creating this mutex since
8858 : // it should be first created through IWriteBlock() / IRasterIO()
8859 : // and then GDALRasterBlock might call it from another thread.
8860 : #ifdef DEBUG_VERBOSE
8861 : CPLDebug("GDAL",
8862 : "[Thread " CPL_FRMT_GIB "] Acquiring RW mutex for %s",
8863 : CPLGetPID(), GetDescription());
8864 : #endif
8865 1559060 : CPLCreateOrAcquireMutex(&(m_poPrivate->hMutex), 1000.0);
8866 :
8867 : const int nCountMutex =
8868 1559060 : m_poPrivate->oMapThreadToMutexTakenCount[CPLGetPID()]++;
8869 1559060 : if (nCountMutex == 0 && eRWFlag == GF_Read)
8870 : {
8871 536309 : CPLReleaseMutex(m_poPrivate->hMutex);
8872 1710640 : for (int i = 0; i < nBands; i++)
8873 : {
8874 1174330 : auto blockCache = papoBands[i]->poBandBlockCache;
8875 1174330 : if (blockCache)
8876 823560 : blockCache->WaitCompletionPendingTasks();
8877 : }
8878 536309 : CPLCreateOrAcquireMutex(&(m_poPrivate->hMutex), 1000.0);
8879 : }
8880 :
8881 1559060 : return TRUE;
8882 : }
8883 : }
8884 6456390 : return FALSE;
8885 : }
8886 :
8887 : /************************************************************************/
8888 : /* LeaveReadWrite() */
8889 : /************************************************************************/
8890 :
8891 1788030 : void GDALDataset::LeaveReadWrite()
8892 : {
8893 1788030 : if (m_poPrivate)
8894 : {
8895 1788030 : if (m_poPrivate->poParentDataset)
8896 : {
8897 228964 : m_poPrivate->poParentDataset->LeaveReadWrite();
8898 228964 : return;
8899 : }
8900 :
8901 1559060 : m_poPrivate->oMapThreadToMutexTakenCount[CPLGetPID()]--;
8902 1559060 : CPLReleaseMutex(m_poPrivate->hMutex);
8903 : #ifdef DEBUG_VERBOSE
8904 : CPLDebug("GDAL", "[Thread " CPL_FRMT_GIB "] Releasing RW mutex for %s",
8905 : CPLGetPID(), GetDescription());
8906 : #endif
8907 : }
8908 : }
8909 :
8910 : /************************************************************************/
8911 : /* InitRWLock() */
8912 : /************************************************************************/
8913 :
8914 3997210 : void GDALDataset::InitRWLock()
8915 : {
8916 3997210 : if (m_poPrivate)
8917 : {
8918 3997210 : if (m_poPrivate->poParentDataset)
8919 : {
8920 8584 : m_poPrivate->poParentDataset->InitRWLock();
8921 8584 : return;
8922 : }
8923 :
8924 3988630 : if (m_poPrivate->eStateReadWriteMutex ==
8925 : GDALAllowReadWriteMutexState::RW_MUTEX_STATE_UNKNOWN)
8926 : {
8927 1 : if (EnterReadWrite(GF_Write))
8928 1 : LeaveReadWrite();
8929 : }
8930 : }
8931 : }
8932 :
8933 : /************************************************************************/
8934 : /* DisableReadWriteMutex() */
8935 : /************************************************************************/
8936 :
8937 : // The mutex logic is broken in multi-threaded situations, for example
8938 : // with 2 WarpedVRT datasets being read at the same time. In that
8939 : // particular case, the mutex is not needed, so allow the VRTWarpedDataset code
8940 : // to disable it.
8941 32797 : void GDALDataset::DisableReadWriteMutex()
8942 : {
8943 32797 : if (m_poPrivate)
8944 : {
8945 32797 : if (m_poPrivate->poParentDataset)
8946 : {
8947 0 : m_poPrivate->poParentDataset->DisableReadWriteMutex();
8948 0 : return;
8949 : }
8950 :
8951 32797 : m_poPrivate->eStateReadWriteMutex =
8952 : GDALAllowReadWriteMutexState::RW_MUTEX_STATE_DISABLED;
8953 : }
8954 : }
8955 :
8956 : /************************************************************************/
8957 : /* TemporarilyDropReadWriteLock() */
8958 : /************************************************************************/
8959 :
8960 3424650 : void GDALDataset::TemporarilyDropReadWriteLock()
8961 : {
8962 3424650 : if (m_poPrivate == nullptr)
8963 0 : return;
8964 :
8965 3424650 : if (m_poPrivate->poParentDataset)
8966 : {
8967 26347 : m_poPrivate->poParentDataset->TemporarilyDropReadWriteLock();
8968 26347 : return;
8969 : }
8970 :
8971 : #ifndef __COVERITY__
8972 3398300 : if (m_poPrivate->hMutex)
8973 : {
8974 : #ifdef DEBUG_VERBOSE
8975 : CPLDebug("GDAL",
8976 : "[Thread " CPL_FRMT_GIB "] "
8977 : "Temporarily drop RW mutex for %s",
8978 : CPLGetPID(), GetDescription());
8979 : #endif
8980 422708 : CPLAcquireMutex(m_poPrivate->hMutex, 1000.0);
8981 : const int nCount =
8982 422708 : m_poPrivate->oMapThreadToMutexTakenCount[CPLGetPID()];
8983 : #ifdef DEBUG_EXTRA
8984 : m_poPrivate->oMapThreadToMutexTakenCountSaved[CPLGetPID()] = nCount;
8985 : #endif
8986 1275800 : for (int i = 0; i < nCount + 1; i++)
8987 : {
8988 : // The mutex is recursive
8989 853092 : CPLReleaseMutex(m_poPrivate->hMutex);
8990 : }
8991 : }
8992 : #endif
8993 : }
8994 :
8995 : /************************************************************************/
8996 : /* ReacquireReadWriteLock() */
8997 : /************************************************************************/
8998 :
8999 3424650 : void GDALDataset::ReacquireReadWriteLock()
9000 : {
9001 3424650 : if (m_poPrivate == nullptr)
9002 0 : return;
9003 :
9004 3424650 : if (m_poPrivate->poParentDataset)
9005 : {
9006 26347 : m_poPrivate->poParentDataset->ReacquireReadWriteLock();
9007 26347 : return;
9008 : }
9009 :
9010 : #ifndef __COVERITY__
9011 3398300 : if (m_poPrivate->hMutex)
9012 : {
9013 : #ifdef DEBUG_VERBOSE
9014 : CPLDebug("GDAL",
9015 : "[Thread " CPL_FRMT_GIB "] "
9016 : "Reacquire temporarily dropped RW mutex for %s",
9017 : CPLGetPID(), GetDescription());
9018 : #endif
9019 422709 : CPLAcquireMutex(m_poPrivate->hMutex, 1000.0);
9020 : const int nCount =
9021 422709 : m_poPrivate->oMapThreadToMutexTakenCount[CPLGetPID()];
9022 : #ifdef DEBUG_EXTRA
9023 : CPLAssert(nCount ==
9024 : m_poPrivate->oMapThreadToMutexTakenCountSaved[CPLGetPID()]);
9025 : #endif
9026 422709 : if (nCount == 0)
9027 18278 : CPLReleaseMutex(m_poPrivate->hMutex);
9028 448662 : for (int i = 0; i < nCount - 1; i++)
9029 : {
9030 : // The mutex is recursive
9031 25953 : CPLAcquireMutex(m_poPrivate->hMutex, 1000.0);
9032 : }
9033 : }
9034 : #endif
9035 : }
9036 :
9037 : /************************************************************************/
9038 : /* AcquireMutex() */
9039 : /************************************************************************/
9040 :
9041 196 : int GDALDataset::AcquireMutex()
9042 : {
9043 196 : if (m_poPrivate == nullptr)
9044 0 : return 0;
9045 196 : if (m_poPrivate->poParentDataset)
9046 : {
9047 0 : return m_poPrivate->poParentDataset->AcquireMutex();
9048 : }
9049 :
9050 196 : return CPLCreateOrAcquireMutex(&(m_poPrivate->hMutex), 1000.0);
9051 : }
9052 :
9053 : /************************************************************************/
9054 : /* ReleaseMutex() */
9055 : /************************************************************************/
9056 :
9057 196 : void GDALDataset::ReleaseMutex()
9058 : {
9059 196 : if (m_poPrivate)
9060 : {
9061 196 : if (m_poPrivate->poParentDataset)
9062 : {
9063 0 : m_poPrivate->poParentDataset->ReleaseMutex();
9064 0 : return;
9065 : }
9066 :
9067 196 : CPLReleaseMutex(m_poPrivate->hMutex);
9068 : }
9069 : }
9070 :
9071 : //! @endcond
9072 :
9073 : /************************************************************************/
9074 : /* GDALDataset::Features::Iterator::Private */
9075 : /************************************************************************/
9076 :
9077 : struct GDALDataset::Features::Iterator::Private
9078 : {
9079 : GDALDataset::FeatureLayerPair m_oPair{};
9080 : GDALDataset *m_poDS = nullptr;
9081 : bool m_bEOF = true;
9082 : };
9083 :
9084 4 : GDALDataset::Features::Iterator::Iterator(GDALDataset *poDS, bool bStart)
9085 4 : : m_poPrivate(new GDALDataset::Features::Iterator::Private())
9086 : {
9087 4 : m_poPrivate->m_poDS = poDS;
9088 4 : if (bStart)
9089 : {
9090 2 : poDS->ResetReading();
9091 4 : m_poPrivate->m_oPair.feature.reset(poDS->GetNextFeature(
9092 2 : &m_poPrivate->m_oPair.layer, nullptr, nullptr, nullptr));
9093 2 : m_poPrivate->m_bEOF = m_poPrivate->m_oPair.feature == nullptr;
9094 : }
9095 4 : }
9096 :
9097 : GDALDataset::Features::Iterator::~Iterator() = default;
9098 :
9099 : const GDALDataset::FeatureLayerPair &
9100 20 : GDALDataset::Features::Iterator::operator*() const
9101 : {
9102 20 : return m_poPrivate->m_oPair;
9103 : }
9104 :
9105 20 : GDALDataset::Features::Iterator &GDALDataset::Features::Iterator::operator++()
9106 : {
9107 40 : m_poPrivate->m_oPair.feature.reset(m_poPrivate->m_poDS->GetNextFeature(
9108 20 : &m_poPrivate->m_oPair.layer, nullptr, nullptr, nullptr));
9109 20 : m_poPrivate->m_bEOF = m_poPrivate->m_oPair.feature == nullptr;
9110 20 : return *this;
9111 : }
9112 :
9113 22 : bool GDALDataset::Features::Iterator::operator!=(const Iterator &it) const
9114 : {
9115 22 : return m_poPrivate->m_bEOF != it.m_poPrivate->m_bEOF;
9116 : }
9117 :
9118 : /************************************************************************/
9119 : /* GetFeatures() */
9120 : /************************************************************************/
9121 :
9122 : /** Function that return an iterable object over features in the dataset
9123 : * layer.
9124 : *
9125 : * This is a C++ iterator friendly version of GetNextFeature().
9126 : *
9127 : * Using this iterator for standard range-based loops is safe, but
9128 : * due to implementation limitations, you shouldn't try to access
9129 : * (dereference) more than one iterator step at a time, since the
9130 : * FeatureLayerPair reference which is returned is reused.
9131 : *
9132 : * Typical use is:
9133 : * \code{.cpp}
9134 : * for( auto&& oFeatureLayerPair: poDS->GetFeatures() )
9135 : * {
9136 : * std::cout << "Feature of layer " <<
9137 : * oFeatureLayerPair.layer->GetName() << std::endl;
9138 : * oFeatureLayerPair.feature->DumpReadable();
9139 : * }
9140 : * \endcode
9141 : *
9142 : * @see GetNextFeature()
9143 : *
9144 : */
9145 2 : GDALDataset::Features GDALDataset::GetFeatures()
9146 : {
9147 2 : return Features(this);
9148 : }
9149 :
9150 : /************************************************************************/
9151 : /* begin() */
9152 : /************************************************************************/
9153 :
9154 : /**
9155 : \brief Return beginning of feature iterator.
9156 :
9157 : */
9158 :
9159 2 : const GDALDataset::Features::Iterator GDALDataset::Features::begin() const
9160 : {
9161 2 : return {m_poSelf, true};
9162 : }
9163 :
9164 : /************************************************************************/
9165 : /* end() */
9166 : /************************************************************************/
9167 :
9168 : /**
9169 : \brief Return end of feature iterator.
9170 :
9171 : */
9172 :
9173 2 : const GDALDataset::Features::Iterator GDALDataset::Features::end() const
9174 : {
9175 2 : return {m_poSelf, false};
9176 : }
9177 :
9178 : /************************************************************************/
9179 : /* GDALDataset::Layers::Iterator::Private */
9180 : /************************************************************************/
9181 :
9182 : struct GDALDataset::Layers::Iterator::Private
9183 : {
9184 : OGRLayer *m_poLayer = nullptr;
9185 : int m_iCurLayer = 0;
9186 : int m_nLayerCount = 0;
9187 : GDALDataset *m_poDS = nullptr;
9188 : };
9189 :
9190 2 : GDALDataset::Layers::Iterator::Iterator() : m_poPrivate(new Private())
9191 : {
9192 2 : }
9193 :
9194 : // False positive of cppcheck 1.72
9195 : // cppcheck-suppress uninitMemberVar
9196 9 : GDALDataset::Layers::Iterator::Iterator(const Iterator &oOther)
9197 9 : : m_poPrivate(new Private(*(oOther.m_poPrivate)))
9198 : {
9199 9 : }
9200 :
9201 5 : GDALDataset::Layers::Iterator::Iterator(Iterator &&oOther) noexcept
9202 5 : : m_poPrivate(std::move(oOther.m_poPrivate))
9203 : {
9204 5 : }
9205 :
9206 105424 : GDALDataset::Layers::Iterator::Iterator(GDALDataset *poDS, bool bStart)
9207 105424 : : m_poPrivate(new Private())
9208 : {
9209 105424 : m_poPrivate->m_poDS = poDS;
9210 105424 : m_poPrivate->m_nLayerCount = poDS->GetLayerCount();
9211 105424 : if (bStart)
9212 : {
9213 52714 : if (m_poPrivate->m_nLayerCount)
9214 44459 : m_poPrivate->m_poLayer = poDS->GetLayer(0);
9215 : }
9216 : else
9217 : {
9218 52710 : m_poPrivate->m_iCurLayer = m_poPrivate->m_nLayerCount;
9219 : }
9220 105424 : }
9221 :
9222 : GDALDataset::Layers::Iterator::~Iterator() = default;
9223 :
9224 : // False positive of cppcheck 1.72
9225 : // cppcheck-suppress operatorEqVarError
9226 : GDALDataset::Layers::Iterator &
9227 1 : GDALDataset::Layers::Iterator::operator=(const Iterator &oOther)
9228 : {
9229 1 : *m_poPrivate = *oOther.m_poPrivate;
9230 1 : return *this;
9231 : }
9232 :
9233 3 : GDALDataset::Layers::Iterator &GDALDataset::Layers::Iterator::operator=(
9234 : GDALDataset::Layers::Iterator &&oOther) noexcept
9235 : {
9236 3 : m_poPrivate = std::move(oOther.m_poPrivate);
9237 3 : return *this;
9238 : }
9239 :
9240 1794200 : OGRLayer *GDALDataset::Layers::Iterator::operator*() const
9241 : {
9242 1794200 : return m_poPrivate->m_poLayer;
9243 : }
9244 :
9245 1781990 : GDALDataset::Layers::Iterator &GDALDataset::Layers::Iterator::operator++()
9246 : {
9247 1781990 : m_poPrivate->m_iCurLayer++;
9248 1781990 : if (m_poPrivate->m_iCurLayer < m_poPrivate->m_nLayerCount)
9249 : {
9250 1749740 : m_poPrivate->m_poLayer =
9251 1749740 : m_poPrivate->m_poDS->GetLayer(m_poPrivate->m_iCurLayer);
9252 : }
9253 : else
9254 : {
9255 32243 : m_poPrivate->m_poLayer = nullptr;
9256 : }
9257 1781990 : return *this;
9258 : }
9259 :
9260 2 : GDALDataset::Layers::Iterator GDALDataset::Layers::Iterator::operator++(int)
9261 : {
9262 2 : GDALDataset::Layers::Iterator temp = *this;
9263 2 : ++(*this);
9264 2 : return temp;
9265 : }
9266 :
9267 1834690 : bool GDALDataset::Layers::Iterator::operator!=(const Iterator &it) const
9268 : {
9269 1834690 : return m_poPrivate->m_iCurLayer != it.m_poPrivate->m_iCurLayer;
9270 : }
9271 :
9272 : /************************************************************************/
9273 : /* GetLayers() */
9274 : /************************************************************************/
9275 :
9276 : /** Function that returns an iterable object over layers in the dataset.
9277 : *
9278 : * This is a C++ iterator friendly version of GetLayer().
9279 : *
9280 : * Typical use is:
9281 : * \code{.cpp}
9282 : * for( auto&& poLayer: poDS->GetLayers() )
9283 : * {
9284 : * std::cout << "Layer << poLayer->GetName() << std::endl;
9285 : * }
9286 : * \endcode
9287 : *
9288 : * @see GetLayer()
9289 : *
9290 : */
9291 52715 : GDALDataset::Layers GDALDataset::GetLayers()
9292 : {
9293 52715 : return Layers(this);
9294 : }
9295 :
9296 : /************************************************************************/
9297 : /* begin() */
9298 : /************************************************************************/
9299 :
9300 : /**
9301 : \brief Return beginning of layer iterator.
9302 :
9303 : */
9304 :
9305 52714 : GDALDataset::Layers::Iterator GDALDataset::Layers::begin() const
9306 : {
9307 52714 : return {m_poSelf, true};
9308 : }
9309 :
9310 : /************************************************************************/
9311 : /* end() */
9312 : /************************************************************************/
9313 :
9314 : /**
9315 : \brief Return end of layer iterator.
9316 :
9317 : */
9318 :
9319 52710 : GDALDataset::Layers::Iterator GDALDataset::Layers::end() const
9320 : {
9321 52710 : return {m_poSelf, false};
9322 : }
9323 :
9324 : /************************************************************************/
9325 : /* size() */
9326 : /************************************************************************/
9327 :
9328 : /**
9329 : \brief Get the number of layers in this dataset.
9330 :
9331 : @return layer count.
9332 :
9333 : */
9334 :
9335 1 : size_t GDALDataset::Layers::size() const
9336 : {
9337 1 : return static_cast<size_t>(m_poSelf->GetLayerCount());
9338 : }
9339 :
9340 : /************************************************************************/
9341 : /* operator[]() */
9342 : /************************************************************************/
9343 : /**
9344 : \brief Fetch a layer by index.
9345 :
9346 : The returned layer remains owned by the
9347 : GDALDataset and should not be deleted by the application.
9348 :
9349 : @param iLayer a layer number between 0 and size()-1.
9350 :
9351 : @return the layer, or nullptr if iLayer is out of range or an error occurs.
9352 :
9353 : */
9354 :
9355 9 : OGRLayer *GDALDataset::Layers::operator[](int iLayer)
9356 : {
9357 9 : return m_poSelf->GetLayer(iLayer);
9358 : }
9359 :
9360 : /************************************************************************/
9361 : /* operator[]() */
9362 : /************************************************************************/
9363 : /**
9364 : \brief Fetch a layer by index.
9365 :
9366 : The returned layer remains owned by the
9367 : GDALDataset and should not be deleted by the application.
9368 :
9369 : @param iLayer a layer number between 0 and size()-1.
9370 :
9371 : @return the layer, or nullptr if iLayer is out of range or an error occurs.
9372 :
9373 : */
9374 :
9375 1 : OGRLayer *GDALDataset::Layers::operator[](size_t iLayer)
9376 : {
9377 1 : return m_poSelf->GetLayer(static_cast<int>(iLayer));
9378 : }
9379 :
9380 : /************************************************************************/
9381 : /* operator[]() */
9382 : /************************************************************************/
9383 : /**
9384 : \brief Fetch a layer by name.
9385 :
9386 : The returned layer remains owned by the
9387 : GDALDataset and should not be deleted by the application.
9388 :
9389 : @param pszLayerName layer name
9390 :
9391 : @return the layer, or nullptr if pszLayerName does not match with a layer
9392 :
9393 : */
9394 :
9395 1 : OGRLayer *GDALDataset::Layers::operator[](const char *pszLayerName)
9396 : {
9397 1 : return m_poSelf->GetLayerByName(pszLayerName);
9398 : }
9399 :
9400 : /************************************************************************/
9401 : /* GDALDataset::ConstLayers::Iterator::Private */
9402 : /************************************************************************/
9403 :
9404 : struct GDALDataset::ConstLayers::Iterator::Private
9405 : {
9406 : const OGRLayer *m_poLayer = nullptr;
9407 : int m_iCurLayer = 0;
9408 : int m_nLayerCount = 0;
9409 : const GDALDataset *m_poDS = nullptr;
9410 : };
9411 :
9412 2 : GDALDataset::ConstLayers::Iterator::Iterator() : m_poPrivate(new Private())
9413 : {
9414 2 : }
9415 :
9416 : // False positive of cppcheck 1.72
9417 : // cppcheck-suppress uninitMemberVar
9418 9 : GDALDataset::ConstLayers::Iterator::Iterator(const Iterator &oOther)
9419 9 : : m_poPrivate(new Private(*(oOther.m_poPrivate)))
9420 : {
9421 9 : }
9422 :
9423 5 : GDALDataset::ConstLayers::Iterator::Iterator(Iterator &&oOther) noexcept
9424 5 : : m_poPrivate(std::move(oOther.m_poPrivate))
9425 : {
9426 5 : }
9427 :
9428 35404 : GDALDataset::ConstLayers::Iterator::Iterator(const GDALDataset *poDS,
9429 35404 : bool bStart)
9430 35404 : : m_poPrivate(new Private())
9431 : {
9432 35404 : m_poPrivate->m_poDS = poDS;
9433 35404 : m_poPrivate->m_nLayerCount = poDS->GetLayerCount();
9434 35404 : if (bStart)
9435 : {
9436 17704 : if (m_poPrivate->m_nLayerCount)
9437 220 : m_poPrivate->m_poLayer = poDS->GetLayer(0);
9438 : }
9439 : else
9440 : {
9441 17700 : m_poPrivate->m_iCurLayer = m_poPrivate->m_nLayerCount;
9442 : }
9443 35404 : }
9444 :
9445 : GDALDataset::ConstLayers::Iterator::~Iterator() = default;
9446 :
9447 : // False positive of cppcheck 1.72
9448 : // cppcheck-suppress operatorEqVarError
9449 : GDALDataset::ConstLayers::Iterator &
9450 1 : GDALDataset::ConstLayers::Iterator::operator=(const Iterator &oOther)
9451 : {
9452 1 : *m_poPrivate = *oOther.m_poPrivate;
9453 1 : return *this;
9454 : }
9455 :
9456 : GDALDataset::ConstLayers::Iterator &
9457 3 : GDALDataset::ConstLayers::Iterator::operator=(
9458 : GDALDataset::ConstLayers::Iterator &&oOther) noexcept
9459 : {
9460 3 : m_poPrivate = std::move(oOther.m_poPrivate);
9461 3 : return *this;
9462 : }
9463 :
9464 16178 : const OGRLayer *GDALDataset::ConstLayers::Iterator::operator*() const
9465 : {
9466 16178 : return m_poPrivate->m_poLayer;
9467 : }
9468 :
9469 : GDALDataset::ConstLayers::Iterator &
9470 16173 : GDALDataset::ConstLayers::Iterator::operator++()
9471 : {
9472 16173 : m_poPrivate->m_iCurLayer++;
9473 16173 : if (m_poPrivate->m_iCurLayer < m_poPrivate->m_nLayerCount)
9474 : {
9475 15964 : m_poPrivate->m_poLayer =
9476 15964 : m_poPrivate->m_poDS->GetLayer(m_poPrivate->m_iCurLayer);
9477 : }
9478 : else
9479 : {
9480 209 : m_poPrivate->m_poLayer = nullptr;
9481 : }
9482 16173 : return *this;
9483 : }
9484 :
9485 : GDALDataset::ConstLayers::Iterator
9486 2 : GDALDataset::ConstLayers::Iterator::operator++(int)
9487 : {
9488 2 : GDALDataset::ConstLayers::Iterator temp = *this;
9489 2 : ++(*this);
9490 2 : return temp;
9491 : }
9492 :
9493 33867 : bool GDALDataset::ConstLayers::Iterator::operator!=(const Iterator &it) const
9494 : {
9495 33867 : return m_poPrivate->m_iCurLayer != it.m_poPrivate->m_iCurLayer;
9496 : }
9497 :
9498 : /************************************************************************/
9499 : /* GetLayers() */
9500 : /************************************************************************/
9501 :
9502 : /** Function that returns an iterable object over layers in the dataset.
9503 : *
9504 : * This is a C++ iterator friendly version of GetLayer().
9505 : *
9506 : * Typical use is:
9507 : * \code{.cpp}
9508 : * for( auto&& poLayer: poDS->GetLayers() )
9509 : * {
9510 : * std::cout << "Layer << poLayer->GetName() << std::endl;
9511 : * }
9512 : * \endcode
9513 : *
9514 : * @see GetLayer()
9515 : *
9516 : * @since GDAL 3.12
9517 : */
9518 17705 : GDALDataset::ConstLayers GDALDataset::GetLayers() const
9519 : {
9520 17705 : return ConstLayers(this);
9521 : }
9522 :
9523 : /************************************************************************/
9524 : /* begin() */
9525 : /************************************************************************/
9526 :
9527 : /**
9528 : \brief Return beginning of layer iterator.
9529 :
9530 : @since GDAL 3.12
9531 : */
9532 :
9533 17704 : GDALDataset::ConstLayers::Iterator GDALDataset::ConstLayers::begin() const
9534 : {
9535 17704 : return {m_poSelf, true};
9536 : }
9537 :
9538 : /************************************************************************/
9539 : /* end() */
9540 : /************************************************************************/
9541 :
9542 : /**
9543 : \brief Return end of layer iterator.
9544 :
9545 : @since GDAL 3.12
9546 : */
9547 :
9548 17700 : GDALDataset::ConstLayers::Iterator GDALDataset::ConstLayers::end() const
9549 : {
9550 17700 : return {m_poSelf, false};
9551 : }
9552 :
9553 : /************************************************************************/
9554 : /* size() */
9555 : /************************************************************************/
9556 :
9557 : /**
9558 : \brief Get the number of layers in this dataset.
9559 :
9560 : @return layer count.
9561 :
9562 : @since GDAL 3.12
9563 : */
9564 :
9565 1 : size_t GDALDataset::ConstLayers::size() const
9566 : {
9567 1 : return static_cast<size_t>(m_poSelf->GetLayerCount());
9568 : }
9569 :
9570 : /************************************************************************/
9571 : /* operator[]() */
9572 : /************************************************************************/
9573 : /**
9574 : \brief Fetch a layer by index.
9575 :
9576 : The returned layer remains owned by the
9577 : GDALDataset and should not be deleted by the application.
9578 :
9579 : @param iLayer a layer number between 0 and size()-1.
9580 :
9581 : @return the layer, or nullptr if iLayer is out of range or an error occurs.
9582 :
9583 : @since GDAL 3.12
9584 : */
9585 :
9586 9 : const OGRLayer *GDALDataset::ConstLayers::operator[](int iLayer)
9587 : {
9588 9 : return m_poSelf->GetLayer(iLayer);
9589 : }
9590 :
9591 : /************************************************************************/
9592 : /* operator[]() */
9593 : /************************************************************************/
9594 : /**
9595 : \brief Fetch a layer by index.
9596 :
9597 : The returned layer remains owned by the
9598 : GDALDataset and should not be deleted by the application.
9599 :
9600 : @param iLayer a layer number between 0 and size()-1.
9601 :
9602 : @return the layer, or nullptr if iLayer is out of range or an error occurs.
9603 :
9604 : @since GDAL 3.12
9605 : */
9606 :
9607 1 : const OGRLayer *GDALDataset::ConstLayers::operator[](size_t iLayer)
9608 : {
9609 1 : return m_poSelf->GetLayer(static_cast<int>(iLayer));
9610 : }
9611 :
9612 : /************************************************************************/
9613 : /* operator[]() */
9614 : /************************************************************************/
9615 : /**
9616 : \brief Fetch a layer by name.
9617 :
9618 : The returned layer remains owned by the
9619 : GDALDataset and should not be deleted by the application.
9620 :
9621 : @param pszLayerName layer name
9622 :
9623 : @return the layer, or nullptr if pszLayerName does not match with a layer
9624 :
9625 : @since GDAL 3.12
9626 : */
9627 :
9628 1 : const OGRLayer *GDALDataset::ConstLayers::operator[](const char *pszLayerName)
9629 : {
9630 1 : return const_cast<GDALDataset *>(m_poSelf)->GetLayerByName(pszLayerName);
9631 : }
9632 :
9633 : /************************************************************************/
9634 : /* GDALDataset::Bands::Iterator::Private */
9635 : /************************************************************************/
9636 :
9637 : struct GDALDataset::Bands::Iterator::Private
9638 : {
9639 : GDALRasterBand *m_poBand = nullptr;
9640 : int m_iCurBand = 0;
9641 : int m_nBandCount = 0;
9642 : GDALDataset *m_poDS = nullptr;
9643 : };
9644 :
9645 32 : GDALDataset::Bands::Iterator::Iterator(GDALDataset *poDS, bool bStart)
9646 32 : : m_poPrivate(new GDALDataset::Bands::Iterator::Private())
9647 : {
9648 32 : m_poPrivate->m_poDS = poDS;
9649 32 : m_poPrivate->m_nBandCount = poDS->GetRasterCount();
9650 32 : if (bStart)
9651 : {
9652 16 : if (m_poPrivate->m_nBandCount)
9653 16 : m_poPrivate->m_poBand = poDS->GetRasterBand(1);
9654 : }
9655 : else
9656 : {
9657 16 : m_poPrivate->m_iCurBand = m_poPrivate->m_nBandCount;
9658 : }
9659 32 : }
9660 :
9661 : GDALDataset::Bands::Iterator::~Iterator() = default;
9662 :
9663 18 : GDALRasterBand *GDALDataset::Bands::Iterator::operator*()
9664 : {
9665 18 : return m_poPrivate->m_poBand;
9666 : }
9667 :
9668 4 : GDALDataset::Bands::Iterator &GDALDataset::Bands::Iterator::operator++()
9669 : {
9670 4 : m_poPrivate->m_iCurBand++;
9671 4 : if (m_poPrivate->m_iCurBand < m_poPrivate->m_nBandCount)
9672 : {
9673 2 : m_poPrivate->m_poBand =
9674 2 : m_poPrivate->m_poDS->GetRasterBand(1 + m_poPrivate->m_iCurBand);
9675 : }
9676 : else
9677 : {
9678 2 : m_poPrivate->m_poBand = nullptr;
9679 : }
9680 4 : return *this;
9681 : }
9682 :
9683 20 : bool GDALDataset::Bands::Iterator::operator!=(const Iterator &it) const
9684 : {
9685 20 : return m_poPrivate->m_iCurBand != it.m_poPrivate->m_iCurBand;
9686 : }
9687 :
9688 : /************************************************************************/
9689 : /* GetBands() */
9690 : /************************************************************************/
9691 :
9692 : /** Function that returns an iterable object over GDALRasterBand in the dataset.
9693 : *
9694 : * This is a C++ iterator friendly version of GetRasterBand().
9695 : *
9696 : * Typical use is:
9697 : * \code{.cpp}
9698 : * for( auto&& poBand: poDS->GetBands() )
9699 : * {
9700 : * std::cout << "Band << poBand->GetDescription() << std::endl;
9701 : * }
9702 : * \endcode
9703 : *
9704 : * @see GetRasterBand()
9705 : *
9706 : */
9707 20 : GDALDataset::Bands GDALDataset::GetBands()
9708 : {
9709 20 : return Bands(this);
9710 : }
9711 :
9712 : /************************************************************************/
9713 : /* begin() */
9714 : /************************************************************************/
9715 :
9716 : /**
9717 : \brief Return beginning of band iterator.
9718 :
9719 : */
9720 :
9721 16 : const GDALDataset::Bands::Iterator GDALDataset::Bands::begin() const
9722 : {
9723 16 : return {m_poSelf, true};
9724 : }
9725 :
9726 : /************************************************************************/
9727 : /* end() */
9728 : /************************************************************************/
9729 :
9730 : /**
9731 : \brief Return end of band iterator.
9732 :
9733 : */
9734 :
9735 16 : const GDALDataset::Bands::Iterator GDALDataset::Bands::end() const
9736 : {
9737 16 : return {m_poSelf, false};
9738 : }
9739 :
9740 : /************************************************************************/
9741 : /* size() */
9742 : /************************************************************************/
9743 :
9744 : /**
9745 : \brief Get the number of raster bands in this dataset.
9746 :
9747 : @return raster band count.
9748 :
9749 : */
9750 :
9751 2 : size_t GDALDataset::Bands::size() const
9752 : {
9753 2 : return static_cast<size_t>(m_poSelf->GetRasterCount());
9754 : }
9755 :
9756 : /************************************************************************/
9757 : /* operator[]() */
9758 : /************************************************************************/
9759 : /**
9760 : \brief Fetch a raster band by index.
9761 :
9762 : The returned band remains owned by the
9763 : GDALDataset and should not be deleted by the application.
9764 :
9765 : @warning Contrary to GDALDataset::GetRasterBand(), the indexing here is
9766 : consistent with the conventions of C/C++, i.e. starting at 0.
9767 :
9768 : @param iBand a band index between 0 and size()-1.
9769 :
9770 : @return the band, or nullptr if iBand is out of range or an error occurs.
9771 :
9772 : */
9773 :
9774 1 : GDALRasterBand *GDALDataset::Bands::operator[](int iBand)
9775 : {
9776 1 : return m_poSelf->GetRasterBand(1 + iBand);
9777 : }
9778 :
9779 : /************************************************************************/
9780 : /* operator[]() */
9781 : /************************************************************************/
9782 :
9783 : /**
9784 : \brief Fetch a raster band by index.
9785 :
9786 : The returned band remains owned by the
9787 : GDALDataset and should not be deleted by the application.
9788 :
9789 : @warning Contrary to GDALDataset::GetRasterBand(), the indexing here is
9790 : consistent with the conventions of C/C++, i.e. starting at 0.
9791 :
9792 : @param iBand a band index between 0 and size()-1.
9793 :
9794 : @return the band, or nullptr if iBand is out of range or an error occurs.
9795 :
9796 : */
9797 :
9798 1 : GDALRasterBand *GDALDataset::Bands::operator[](size_t iBand)
9799 : {
9800 1 : return m_poSelf->GetRasterBand(1 + static_cast<int>(iBand));
9801 : }
9802 :
9803 : /************************************************************************/
9804 : /* GDALDataset::ConstBands::Iterator::Private */
9805 : /************************************************************************/
9806 :
9807 : struct GDALDataset::ConstBands::Iterator::Private
9808 : {
9809 : const GDALRasterBand *m_poBand = nullptr;
9810 : int m_iCurBand = 0;
9811 : int m_nBandCount = 0;
9812 : const GDALDataset *m_poDS = nullptr;
9813 : };
9814 :
9815 2 : GDALDataset::ConstBands::Iterator::Iterator(const GDALDataset *poDS,
9816 2 : bool bStart)
9817 2 : : m_poPrivate(new GDALDataset::ConstBands::Iterator::Private())
9818 : {
9819 2 : m_poPrivate->m_poDS = poDS;
9820 2 : m_poPrivate->m_nBandCount = poDS->GetRasterCount();
9821 2 : if (bStart)
9822 : {
9823 1 : if (m_poPrivate->m_nBandCount)
9824 1 : m_poPrivate->m_poBand = poDS->GetRasterBand(1);
9825 : }
9826 : else
9827 : {
9828 1 : m_poPrivate->m_iCurBand = m_poPrivate->m_nBandCount;
9829 : }
9830 2 : }
9831 :
9832 : GDALDataset::ConstBands::Iterator::~Iterator() = default;
9833 :
9834 3 : const GDALRasterBand *GDALDataset::ConstBands::Iterator::operator*() const
9835 : {
9836 3 : return m_poPrivate->m_poBand;
9837 : }
9838 :
9839 : GDALDataset::ConstBands::Iterator &
9840 3 : GDALDataset::ConstBands::Iterator::operator++()
9841 : {
9842 3 : m_poPrivate->m_iCurBand++;
9843 3 : if (m_poPrivate->m_iCurBand < m_poPrivate->m_nBandCount)
9844 : {
9845 2 : m_poPrivate->m_poBand =
9846 2 : m_poPrivate->m_poDS->GetRasterBand(1 + m_poPrivate->m_iCurBand);
9847 : }
9848 : else
9849 : {
9850 1 : m_poPrivate->m_poBand = nullptr;
9851 : }
9852 3 : return *this;
9853 : }
9854 :
9855 4 : bool GDALDataset::ConstBands::Iterator::operator!=(const Iterator &it) const
9856 : {
9857 4 : return m_poPrivate->m_iCurBand != it.m_poPrivate->m_iCurBand;
9858 : }
9859 :
9860 : /************************************************************************/
9861 : /* GetBands() */
9862 : /************************************************************************/
9863 :
9864 : /** Function that returns an iterable object over GDALRasterBand in the dataset.
9865 : *
9866 : * This is a C++ iterator friendly version of GetRasterBand().
9867 : *
9868 : * Typical use is:
9869 : * \code{.cpp}
9870 : * for( const auto* poBand: poDS->GetConstBands() )
9871 : * {
9872 : * std::cout << "Band << poBand->GetDescription() << std::endl;
9873 : * }
9874 : * \endcode
9875 : *
9876 : * @see GetRasterBand()
9877 : *
9878 : * @since GDAL 3.12
9879 : */
9880 4 : GDALDataset::ConstBands GDALDataset::GetBands() const
9881 : {
9882 4 : return ConstBands(this);
9883 : }
9884 :
9885 : /************************************************************************/
9886 : /* begin() */
9887 : /************************************************************************/
9888 :
9889 : /**
9890 : \brief Return beginning of band iterator.
9891 :
9892 : @since GDAL 3.12
9893 : */
9894 :
9895 1 : const GDALDataset::ConstBands::Iterator GDALDataset::ConstBands::begin() const
9896 : {
9897 1 : return {m_poSelf, true};
9898 : }
9899 :
9900 : /************************************************************************/
9901 : /* end() */
9902 : /************************************************************************/
9903 :
9904 : /**
9905 : \brief Return end of band iterator.
9906 :
9907 : @since GDAL 3.12
9908 : */
9909 :
9910 1 : const GDALDataset::ConstBands::Iterator GDALDataset::ConstBands::end() const
9911 : {
9912 1 : return {m_poSelf, false};
9913 : }
9914 :
9915 : /************************************************************************/
9916 : /* size() */
9917 : /************************************************************************/
9918 :
9919 : /**
9920 : \brief Get the number of raster bands in this dataset.
9921 :
9922 : @return raster band count.
9923 :
9924 : @since GDAL 3.12
9925 : */
9926 :
9927 1 : size_t GDALDataset::ConstBands::size() const
9928 : {
9929 1 : return static_cast<size_t>(m_poSelf->GetRasterCount());
9930 : }
9931 :
9932 : /************************************************************************/
9933 : /* operator[]() */
9934 : /************************************************************************/
9935 : /**
9936 : \brief Fetch a raster band by index.
9937 :
9938 : The returned band remains owned by the
9939 : GDALDataset and should not be deleted by the application.
9940 :
9941 : @warning Contrary to GDALDataset::GetRasterBand(), the indexing here is
9942 : consistent with the conventions of C/C++, i.e. starting at 0.
9943 :
9944 : @param iBand a band index between 0 and size()-1.
9945 :
9946 : @return the band, or nullptr if iBand is out of range or an error occurs.
9947 :
9948 : @since GDAL 3.12
9949 : */
9950 :
9951 1 : const GDALRasterBand *GDALDataset::ConstBands::operator[](int iBand) const
9952 : {
9953 1 : return m_poSelf->GetRasterBand(1 + iBand);
9954 : }
9955 :
9956 : /************************************************************************/
9957 : /* operator[]() */
9958 : /************************************************************************/
9959 :
9960 : /**
9961 : \brief Fetch a raster band by index.
9962 :
9963 : The returned band remains owned by the
9964 : GDALDataset and should not be deleted by the application.
9965 :
9966 : @warning Contrary to GDALDataset::GetRasterBand(), the indexing here is
9967 : consistent with the conventions of C/C++, i.e. starting at 0.
9968 :
9969 : @param iBand a band index between 0 and size()-1.
9970 :
9971 : @return the band, or nullptr if iBand is out of range or an error occurs.
9972 :
9973 : @since GDAL 3.12
9974 : */
9975 :
9976 1 : const GDALRasterBand *GDALDataset::ConstBands::operator[](size_t iBand) const
9977 : {
9978 1 : return m_poSelf->GetRasterBand(1 + static_cast<int>(iBand));
9979 : }
9980 :
9981 : /************************************************************************/
9982 : /* GetRootGroup() */
9983 : /************************************************************************/
9984 :
9985 : /**
9986 : \brief Return the root GDALGroup of this dataset.
9987 :
9988 : Only valid for multidimensional datasets.
9989 :
9990 : This is the same as the C function GDALDatasetGetRootGroup().
9991 :
9992 : @since GDAL 3.1
9993 : */
9994 :
9995 2928 : std::shared_ptr<GDALGroup> GDALDataset::GetRootGroup() const
9996 : {
9997 2928 : return nullptr;
9998 : }
9999 :
10000 : /************************************************************************/
10001 : /* GetRawBinaryLayout() */
10002 : /************************************************************************/
10003 :
10004 : //! @cond Doxygen_Suppress
10005 : /**
10006 : \brief Return the layout of a dataset that can be considered as a raw binary
10007 : format.
10008 :
10009 : @param sLayout Structure that will be set if the dataset is a raw binary one.
10010 : @return true if the dataset is a raw binary one.
10011 : @since GDAL 3.1
10012 : */
10013 :
10014 0 : bool GDALDataset::GetRawBinaryLayout(RawBinaryLayout &sLayout)
10015 : {
10016 0 : CPL_IGNORE_RET_VAL(sLayout);
10017 0 : return false;
10018 : }
10019 :
10020 : //! @endcond
10021 :
10022 : /************************************************************************/
10023 : /* ClearStatistics() */
10024 : /************************************************************************/
10025 :
10026 : /**
10027 : \brief Clear statistics
10028 :
10029 : Only implemented for now in PAM supported datasets
10030 :
10031 : This is the same as the C function GDALDatasetClearStatistics().
10032 :
10033 : @since GDAL 3.2
10034 : */
10035 :
10036 11 : void GDALDataset::ClearStatistics()
10037 : {
10038 22 : auto poRootGroup = GetRootGroup();
10039 11 : if (poRootGroup)
10040 1 : poRootGroup->ClearStatistics();
10041 11 : }
10042 :
10043 : /************************************************************************/
10044 : /* GDALDatasetClearStatistics() */
10045 : /************************************************************************/
10046 :
10047 : /**
10048 : \brief Clear statistics
10049 :
10050 : This is the same as the C++ method GDALDataset::ClearStatistics().
10051 :
10052 : @since GDAL 3.2
10053 : */
10054 :
10055 2 : void GDALDatasetClearStatistics(GDALDatasetH hDS)
10056 : {
10057 2 : VALIDATE_POINTER0(hDS, __func__);
10058 2 : GDALDataset::FromHandle(hDS)->ClearStatistics();
10059 : }
10060 :
10061 : /************************************************************************/
10062 : /* GetFieldDomainNames() */
10063 : /************************************************************************/
10064 :
10065 : /** Returns a list of the names of all field domains stored in the dataset.
10066 : *
10067 : * @note The default implementation assumes that drivers fully populate
10068 : * m_oMapFieldDomains when opening a dataset. If this assumption is incorrect
10069 : * then a specialized implementation of GetFieldDomainNames() must be
10070 : * implemented.
10071 : *
10072 : * @param papszOptions Driver specific options determining how attributes
10073 : * should be retrieved. Pass nullptr for default behavior.
10074 : *
10075 : * @return list of field domain names
10076 : * @since GDAL 3.5
10077 : */
10078 : std::vector<std::string>
10079 47 : GDALDataset::GetFieldDomainNames(CPL_UNUSED CSLConstList papszOptions) const
10080 : {
10081 :
10082 47 : std::vector<std::string> names;
10083 47 : names.reserve(m_oMapFieldDomains.size());
10084 59 : for (const auto &it : m_oMapFieldDomains)
10085 : {
10086 12 : names.emplace_back(it.first);
10087 : }
10088 47 : return names;
10089 : }
10090 :
10091 : /************************************************************************/
10092 : /* GDALDatasetGetFieldDomainNames() */
10093 : /************************************************************************/
10094 :
10095 : /** Returns a list of the names of all field domains stored in the dataset.
10096 : *
10097 : * This is the same as the C++ method GDALDataset::GetFieldDomainNames().
10098 : *
10099 : * @param hDS Dataset handle.
10100 : * @param papszOptions Driver specific options determining how attributes
10101 : * should be retrieved. Pass nullptr for default behavior.
10102 : *
10103 : * @return list of field domain names, to be freed with CSLDestroy()
10104 : * @since GDAL 3.5
10105 : */
10106 37 : char **GDALDatasetGetFieldDomainNames(GDALDatasetH hDS,
10107 : CSLConstList papszOptions)
10108 : {
10109 37 : VALIDATE_POINTER1(hDS, __func__, nullptr);
10110 : auto names =
10111 74 : GDALDataset::FromHandle(hDS)->GetFieldDomainNames(papszOptions);
10112 74 : CPLStringList res;
10113 175 : for (const auto &name : names)
10114 : {
10115 138 : res.AddString(name.c_str());
10116 : }
10117 37 : return res.StealList();
10118 : }
10119 :
10120 : /************************************************************************/
10121 : /* GetFieldDomain() */
10122 : /************************************************************************/
10123 :
10124 : /** Get a field domain from its name.
10125 : *
10126 : * @return the field domain, or nullptr if not found.
10127 : * @since GDAL 3.3
10128 : */
10129 325 : const OGRFieldDomain *GDALDataset::GetFieldDomain(const std::string &name) const
10130 : {
10131 325 : const auto iter = m_oMapFieldDomains.find(name);
10132 325 : if (iter == m_oMapFieldDomains.end())
10133 152 : return nullptr;
10134 173 : return iter->second.get();
10135 : }
10136 :
10137 : /************************************************************************/
10138 : /* GDALDatasetGetFieldDomain() */
10139 : /************************************************************************/
10140 :
10141 : /** Get a field domain from its name.
10142 : *
10143 : * This is the same as the C++ method GDALDataset::GetFieldDomain().
10144 : *
10145 : * @param hDS Dataset handle.
10146 : * @param pszName Name of field domain.
10147 : * @return the field domain (ownership remains to the dataset), or nullptr if
10148 : * not found.
10149 : * @since GDAL 3.3
10150 : */
10151 131 : OGRFieldDomainH GDALDatasetGetFieldDomain(GDALDatasetH hDS, const char *pszName)
10152 : {
10153 131 : VALIDATE_POINTER1(hDS, __func__, nullptr);
10154 131 : VALIDATE_POINTER1(pszName, __func__, nullptr);
10155 131 : return OGRFieldDomain::ToHandle(const_cast<OGRFieldDomain *>(
10156 131 : GDALDataset::FromHandle(hDS)->GetFieldDomain(pszName)));
10157 : }
10158 :
10159 : /************************************************************************/
10160 : /* AddFieldDomain() */
10161 : /************************************************************************/
10162 :
10163 : /** Add a field domain to the dataset.
10164 : *
10165 : * Only a few drivers will support this operation, and some of them might only
10166 : * support it only for some types of field domains.
10167 : * At the time of writing (GDAL 3.3), only the Memory and GeoPackage drivers
10168 : * support this operation. A dataset having at least some support for this
10169 : * operation should report the ODsCAddFieldDomain dataset capability.
10170 : *
10171 : * Anticipated failures will not be emitted through the CPLError()
10172 : * infrastructure, but will be reported in the failureReason output parameter.
10173 : *
10174 : * @note Drivers should make sure to update m_oMapFieldDomains in order for the
10175 : * default implementation of GetFieldDomainNames() to work correctly, or
10176 : * alternatively a specialized implementation of GetFieldDomainNames() should be
10177 : * implemented.
10178 : *
10179 : * @param domain The domain definition.
10180 : * @param failureReason Output parameter. Will contain an error message if
10181 : * an error occurs.
10182 : * @return true in case of success.
10183 : * @since GDAL 3.3
10184 : */
10185 0 : bool GDALDataset::AddFieldDomain(
10186 : CPL_UNUSED std::unique_ptr<OGRFieldDomain> &&domain,
10187 : std::string &failureReason)
10188 : {
10189 0 : failureReason = "AddFieldDomain not supported by this driver";
10190 0 : return false;
10191 : }
10192 :
10193 : /************************************************************************/
10194 : /* GDALDatasetAddFieldDomain() */
10195 : /************************************************************************/
10196 :
10197 : /** Add a field domain to the dataset.
10198 : *
10199 : * Only a few drivers will support this operation, and some of them might only
10200 : * support it only for some types of field domains.
10201 : * At the time of writing (GDAL 3.3), only the Memory and GeoPackage drivers
10202 : * support this operation. A dataset having at least some support for this
10203 : * operation should report the ODsCAddFieldDomain dataset capability.
10204 : *
10205 : * Anticipated failures will not be emitted through the CPLError()
10206 : * infrastructure, but will be reported in the ppszFailureReason output
10207 : * parameter.
10208 : *
10209 : * @param hDS Dataset handle.
10210 : * @param hFieldDomain The domain definition. Contrary to the C++ version,
10211 : * the passed object is copied.
10212 : * @param ppszFailureReason Output parameter. Will contain an error message if
10213 : * an error occurs (*ppszFailureReason to be freed
10214 : * with CPLFree). May be NULL.
10215 : * @return true in case of success.
10216 : * @since GDAL 3.3
10217 : */
10218 37 : bool GDALDatasetAddFieldDomain(GDALDatasetH hDS, OGRFieldDomainH hFieldDomain,
10219 : char **ppszFailureReason)
10220 : {
10221 37 : VALIDATE_POINTER1(hDS, __func__, false);
10222 37 : VALIDATE_POINTER1(hFieldDomain, __func__, false);
10223 : auto poDomain = std::unique_ptr<OGRFieldDomain>(
10224 74 : OGRFieldDomain::FromHandle(hFieldDomain)->Clone());
10225 37 : if (poDomain == nullptr)
10226 0 : return false;
10227 37 : std::string failureReason;
10228 74 : const bool bRet = GDALDataset::FromHandle(hDS)->AddFieldDomain(
10229 37 : std::move(poDomain), failureReason);
10230 37 : if (ppszFailureReason)
10231 : {
10232 37 : *ppszFailureReason =
10233 37 : failureReason.empty() ? nullptr : CPLStrdup(failureReason.c_str());
10234 : }
10235 37 : return bRet;
10236 : }
10237 :
10238 : /************************************************************************/
10239 : /* DeleteFieldDomain() */
10240 : /************************************************************************/
10241 :
10242 : /** Removes a field domain from the dataset.
10243 : *
10244 : * Only a few drivers will support this operation.
10245 : *
10246 : * At the time of writing (GDAL 3.5), only the Memory and GeoPackage drivers
10247 : * support this operation. A dataset having at least some support for this
10248 : * operation should report the ODsCDeleteFieldDomain dataset capability.
10249 : *
10250 : * Anticipated failures will not be emitted through the CPLError()
10251 : * infrastructure, but will be reported in the failureReason output parameter.
10252 : *
10253 : * @note Drivers should make sure to update m_oMapFieldDomains in order for the
10254 : * default implementation of GetFieldDomainNames() to work correctly, or
10255 : * alternatively a specialized implementation of GetFieldDomainNames() should be
10256 : * implemented.
10257 : *
10258 : * @param name The domain name.
10259 : * @param failureReason Output parameter. Will contain an error message if
10260 : * an error occurs.
10261 : * @return true in case of success.
10262 : * @since GDAL 3.5
10263 : */
10264 0 : bool GDALDataset::DeleteFieldDomain(CPL_UNUSED const std::string &name,
10265 : std::string &failureReason)
10266 : {
10267 0 : failureReason = "DeleteFieldDomain not supported by this driver";
10268 0 : return false;
10269 : }
10270 :
10271 : /************************************************************************/
10272 : /* GDALDatasetDeleteFieldDomain() */
10273 : /************************************************************************/
10274 :
10275 : /** Removes a field domain from the dataset.
10276 : *
10277 : * Only a few drivers will support this operation.
10278 : *
10279 : * At the time of writing (GDAL 3.5), only the Memory and GeoPackage drivers
10280 : * support this operation. A dataset having at least some support for this
10281 : * operation should report the ODsCDeleteFieldDomain dataset capability.
10282 : *
10283 : * Anticipated failures will not be emitted through the CPLError()
10284 : * infrastructure, but will be reported in the ppszFailureReason output
10285 : * parameter.
10286 : *
10287 : * @param hDS Dataset handle.
10288 : * @param pszName The domain name.
10289 : * @param ppszFailureReason Output parameter. Will contain an error message if
10290 : * an error occurs (*ppszFailureReason to be freed
10291 : * with CPLFree). May be NULL.
10292 : * @return true in case of success.
10293 : * @since GDAL 3.3
10294 : */
10295 25 : bool GDALDatasetDeleteFieldDomain(GDALDatasetH hDS, const char *pszName,
10296 : char **ppszFailureReason)
10297 : {
10298 25 : VALIDATE_POINTER1(hDS, __func__, false);
10299 25 : VALIDATE_POINTER1(pszName, __func__, false);
10300 25 : std::string failureReason;
10301 : const bool bRet =
10302 25 : GDALDataset::FromHandle(hDS)->DeleteFieldDomain(pszName, failureReason);
10303 25 : if (ppszFailureReason)
10304 : {
10305 0 : *ppszFailureReason =
10306 0 : failureReason.empty() ? nullptr : CPLStrdup(failureReason.c_str());
10307 : }
10308 25 : return bRet;
10309 : }
10310 :
10311 : /************************************************************************/
10312 : /* UpdateFieldDomain() */
10313 : /************************************************************************/
10314 :
10315 : /** Updates an existing field domain by replacing its definition.
10316 : *
10317 : * The existing field domain with matching name will be replaced.
10318 : *
10319 : * Only a few drivers will support this operation, and some of them might only
10320 : * support it only for some types of field domains.
10321 : * At the time of writing (GDAL 3.5), only the Memory driver
10322 : * supports this operation. A dataset having at least some support for this
10323 : * operation should report the ODsCUpdateFieldDomain dataset capability.
10324 : *
10325 : * Anticipated failures will not be emitted through the CPLError()
10326 : * infrastructure, but will be reported in the failureReason output parameter.
10327 : *
10328 : * @param domain The domain definition.
10329 : * @param failureReason Output parameter. Will contain an error message if
10330 : * an error occurs.
10331 : * @return true in case of success.
10332 : * @since GDAL 3.5
10333 : */
10334 0 : bool GDALDataset::UpdateFieldDomain(
10335 : CPL_UNUSED std::unique_ptr<OGRFieldDomain> &&domain,
10336 : std::string &failureReason)
10337 : {
10338 0 : failureReason = "UpdateFieldDomain not supported by this driver";
10339 0 : return false;
10340 : }
10341 :
10342 : /************************************************************************/
10343 : /* GDALDatasetUpdateFieldDomain() */
10344 : /************************************************************************/
10345 :
10346 : /** Updates an existing field domain by replacing its definition.
10347 : *
10348 : * The existing field domain with matching name will be replaced.
10349 : *
10350 : * Only a few drivers will support this operation, and some of them might only
10351 : * support it only for some types of field domains.
10352 : * At the time of writing (GDAL 3.5), only the Memory driver
10353 : * supports this operation. A dataset having at least some support for this
10354 : * operation should report the ODsCUpdateFieldDomain dataset capability.
10355 : *
10356 : * Anticipated failures will not be emitted through the CPLError()
10357 : * infrastructure, but will be reported in the failureReason output parameter.
10358 : *
10359 : * @param hDS Dataset handle.
10360 : * @param hFieldDomain The domain definition. Contrary to the C++ version,
10361 : * the passed object is copied.
10362 : * @param ppszFailureReason Output parameter. Will contain an error message if
10363 : * an error occurs (*ppszFailureReason to be freed
10364 : * with CPLFree). May be NULL.
10365 : * @return true in case of success.
10366 : * @since GDAL 3.5
10367 : */
10368 7 : bool GDALDatasetUpdateFieldDomain(GDALDatasetH hDS,
10369 : OGRFieldDomainH hFieldDomain,
10370 : char **ppszFailureReason)
10371 : {
10372 7 : VALIDATE_POINTER1(hDS, __func__, false);
10373 7 : VALIDATE_POINTER1(hFieldDomain, __func__, false);
10374 : auto poDomain = std::unique_ptr<OGRFieldDomain>(
10375 14 : OGRFieldDomain::FromHandle(hFieldDomain)->Clone());
10376 7 : if (poDomain == nullptr)
10377 0 : return false;
10378 7 : std::string failureReason;
10379 14 : const bool bRet = GDALDataset::FromHandle(hDS)->UpdateFieldDomain(
10380 7 : std::move(poDomain), failureReason);
10381 7 : if (ppszFailureReason)
10382 : {
10383 0 : *ppszFailureReason =
10384 0 : failureReason.empty() ? nullptr : CPLStrdup(failureReason.c_str());
10385 : }
10386 7 : return bRet;
10387 : }
10388 :
10389 : /************************************************************************/
10390 : /* GetRelationshipNames() */
10391 : /************************************************************************/
10392 :
10393 : /** Returns a list of the names of all relationships stored in the dataset.
10394 : *
10395 : * @param papszOptions Driver specific options determining how relationships
10396 : * should be retrieved. Pass nullptr for default behavior.
10397 : *
10398 : * @return list of relationship names
10399 : * @since GDAL 3.6
10400 : */
10401 : std::vector<std::string>
10402 236 : GDALDataset::GetRelationshipNames(CPL_UNUSED CSLConstList papszOptions) const
10403 : {
10404 236 : return {};
10405 : }
10406 :
10407 : /************************************************************************/
10408 : /* GDALDatasetGetRelationshipNames() */
10409 : /************************************************************************/
10410 :
10411 : /** Returns a list of the names of all relationships stored in the dataset.
10412 : *
10413 : * This is the same as the C++ method GDALDataset::GetRelationshipNames().
10414 : *
10415 : * @param hDS Dataset handle.
10416 : * @param papszOptions Driver specific options determining how relationships
10417 : * should be retrieved. Pass nullptr for default behavior.
10418 : *
10419 : * @return list of relationship names, to be freed with CSLDestroy()
10420 : * @since GDAL 3.6
10421 : */
10422 53 : char **GDALDatasetGetRelationshipNames(GDALDatasetH hDS,
10423 : CSLConstList papszOptions)
10424 : {
10425 53 : VALIDATE_POINTER1(hDS, __func__, nullptr);
10426 : auto names =
10427 106 : GDALDataset::FromHandle(hDS)->GetRelationshipNames(papszOptions);
10428 106 : CPLStringList res;
10429 161 : for (const auto &name : names)
10430 : {
10431 108 : res.AddString(name.c_str());
10432 : }
10433 53 : return res.StealList();
10434 : }
10435 :
10436 : /************************************************************************/
10437 : /* GetRelationship() */
10438 : /************************************************************************/
10439 :
10440 : /** Get a relationship from its name.
10441 : *
10442 : * @return the relationship, or nullptr if not found.
10443 : * @since GDAL 3.6
10444 : */
10445 : const GDALRelationship *
10446 0 : GDALDataset::GetRelationship(CPL_UNUSED const std::string &name) const
10447 : {
10448 0 : return nullptr;
10449 : }
10450 :
10451 : /************************************************************************/
10452 : /* GDALDatasetGetRelationship() */
10453 : /************************************************************************/
10454 :
10455 : /** Get a relationship from its name.
10456 : *
10457 : * This is the same as the C++ method GDALDataset::GetRelationship().
10458 : *
10459 : * @param hDS Dataset handle.
10460 : * @param pszName Name of relationship.
10461 : * @return the relationship (ownership remains to the dataset), or nullptr if
10462 : * not found.
10463 : * @since GDAL 3.6
10464 : */
10465 63 : GDALRelationshipH GDALDatasetGetRelationship(GDALDatasetH hDS,
10466 : const char *pszName)
10467 : {
10468 63 : VALIDATE_POINTER1(hDS, __func__, nullptr);
10469 63 : VALIDATE_POINTER1(pszName, __func__, nullptr);
10470 63 : return GDALRelationship::ToHandle(const_cast<GDALRelationship *>(
10471 63 : GDALDataset::FromHandle(hDS)->GetRelationship(pszName)));
10472 : }
10473 :
10474 : /************************************************************************/
10475 : /* AddRelationship() */
10476 : /************************************************************************/
10477 :
10478 : /** Add a relationship to the dataset.
10479 : *
10480 : * Only a few drivers will support this operation, and some of them might only
10481 : * support it only for some types of relationships.
10482 : *
10483 : * A dataset having at least some support for this
10484 : * operation should report the GDsCAddRelationship dataset capability.
10485 : *
10486 : * Anticipated failures will not be emitted through the CPLError()
10487 : * infrastructure, but will be reported in the failureReason output parameter.
10488 : *
10489 : * When adding a many-to-many relationship
10490 : * (GDALRelationshipCardinality::GRC_MANY_TO_MANY), it is possible to omit the
10491 : * mapping table name (see GDALRelationship::GetMappingTableName) to instruct
10492 : * the driver to create an appropriately named and structured mapping table.
10493 : * Some dataset formats require particular naming conventions and field
10494 : * structures for the mapping table, and delegating the construction of the
10495 : * mapping table to the driver will avoid these pitfalls.
10496 : *
10497 : * @param relationship The relationship definition.
10498 : * @param failureReason Output parameter. Will contain an error message if
10499 : * an error occurs.
10500 : * @return true in case of success.
10501 : * @since GDAL 3.6
10502 : */
10503 0 : bool GDALDataset::AddRelationship(
10504 : CPL_UNUSED std::unique_ptr<GDALRelationship> &&relationship,
10505 : std::string &failureReason)
10506 : {
10507 0 : failureReason = "AddRelationship not supported by this driver";
10508 0 : return false;
10509 : }
10510 :
10511 : /************************************************************************/
10512 : /* GDALDatasetAddRelationship() */
10513 : /************************************************************************/
10514 :
10515 : /** Add a relationship to the dataset.
10516 : *
10517 : * Only a few drivers will support this operation, and some of them might only
10518 : * support it only for some types of relationships.
10519 : *
10520 : * A dataset having at least some support for this
10521 : * operation should report the GDsCAddRelationship dataset capability.
10522 : *
10523 : * Anticipated failures will not be emitted through the CPLError()
10524 : * infrastructure, but will be reported in the failureReason output parameter.
10525 : *
10526 : * When adding a many-to-many relationship
10527 : * (GDALRelationshipCardinality::GRC_MANY_TO_MANY), it is possible to omit the
10528 : * mapping table name (see GDALRelationshipGetMappingTableName) to instruct the
10529 : * driver to create an appropriately named and structured mapping table. Some
10530 : * dataset formats require particular naming conventions and field structures
10531 : * for the mapping table, and delegating the construction of the mapping table
10532 : * to the driver will avoid these pitfalls.
10533 : *
10534 : * @param hDS Dataset handle.
10535 : * @param hRelationship The relationship definition. Contrary to the C++
10536 : * version, the passed object is copied.
10537 : * @param ppszFailureReason Output parameter. Will contain an error message if
10538 : * an error occurs (*ppszFailureReason to be freed
10539 : * with CPLFree). May be NULL.
10540 : * @return true in case of success.
10541 : * @since GDAL 3.6
10542 : */
10543 45 : bool GDALDatasetAddRelationship(GDALDatasetH hDS,
10544 : GDALRelationshipH hRelationship,
10545 : char **ppszFailureReason)
10546 : {
10547 45 : VALIDATE_POINTER1(hDS, __func__, false);
10548 45 : VALIDATE_POINTER1(hRelationship, __func__, false);
10549 : std::unique_ptr<GDALRelationship> poRelationship(
10550 90 : new GDALRelationship(*GDALRelationship::FromHandle(hRelationship)));
10551 45 : std::string failureReason;
10552 90 : const bool bRet = GDALDataset::FromHandle(hDS)->AddRelationship(
10553 45 : std::move(poRelationship), failureReason);
10554 45 : if (ppszFailureReason)
10555 : {
10556 0 : *ppszFailureReason =
10557 0 : failureReason.empty() ? nullptr : CPLStrdup(failureReason.c_str());
10558 : }
10559 45 : return bRet;
10560 : }
10561 :
10562 : /************************************************************************/
10563 : /* DeleteRelationship() */
10564 : /************************************************************************/
10565 :
10566 : /** Removes a relationship from the dataset.
10567 : *
10568 : * Only a few drivers will support this operation.
10569 : *
10570 : * A dataset having at least some support for this
10571 : * operation should report the GDsCDeleteRelationship dataset capability.
10572 : *
10573 : * Anticipated failures will not be emitted through the CPLError()
10574 : * infrastructure, but will be reported in the failureReason output parameter.
10575 : *
10576 : * @param name The relationship name.
10577 : * @param failureReason Output parameter. Will contain an error message if
10578 : * an error occurs.
10579 : * @return true in case of success.
10580 : * @since GDAL 3.6
10581 : */
10582 0 : bool GDALDataset::DeleteRelationship(CPL_UNUSED const std::string &name,
10583 : std::string &failureReason)
10584 : {
10585 0 : failureReason = "DeleteRelationship not supported by this driver";
10586 0 : return false;
10587 : }
10588 :
10589 : /************************************************************************/
10590 : /* GDALDatasetDeleteRelationship() */
10591 : /************************************************************************/
10592 :
10593 : /** Removes a relationship from the dataset.
10594 : *
10595 : * Only a few drivers will support this operation.
10596 : *
10597 : * A dataset having at least some support for this
10598 : * operation should report the GDsCDeleteRelationship dataset capability.
10599 : *
10600 : * Anticipated failures will not be emitted through the CPLError()
10601 : * infrastructure, but will be reported in the ppszFailureReason output
10602 : * parameter.
10603 : *
10604 : * @param hDS Dataset handle.
10605 : * @param pszName The relationship name.
10606 : * @param ppszFailureReason Output parameter. Will contain an error message if
10607 : * an error occurs (*ppszFailureReason to be freed
10608 : * with CPLFree). May be NULL.
10609 : * @return true in case of success.
10610 : * @since GDAL 3.6
10611 : */
10612 8 : bool GDALDatasetDeleteRelationship(GDALDatasetH hDS, const char *pszName,
10613 : char **ppszFailureReason)
10614 : {
10615 8 : VALIDATE_POINTER1(hDS, __func__, false);
10616 8 : VALIDATE_POINTER1(pszName, __func__, false);
10617 8 : std::string failureReason;
10618 16 : const bool bRet = GDALDataset::FromHandle(hDS)->DeleteRelationship(
10619 8 : pszName, failureReason);
10620 8 : if (ppszFailureReason)
10621 : {
10622 0 : *ppszFailureReason =
10623 0 : failureReason.empty() ? nullptr : CPLStrdup(failureReason.c_str());
10624 : }
10625 8 : return bRet;
10626 : }
10627 :
10628 : /************************************************************************/
10629 : /* UpdateRelationship() */
10630 : /************************************************************************/
10631 :
10632 : /** Updates an existing relationship by replacing its definition.
10633 : *
10634 : * The existing relationship with matching name will be replaced.
10635 : *
10636 : * Only a few drivers will support this operation, and some of them might only
10637 : * support it only for some types of relationships.
10638 : * A dataset having at least some support for this
10639 : * operation should report the GDsCUpdateRelationship dataset capability.
10640 : *
10641 : * Anticipated failures will not be emitted through the CPLError()
10642 : * infrastructure, but will be reported in the failureReason output parameter.
10643 : *
10644 : * @param relationship The relationship definition.
10645 : * @param failureReason Output parameter. Will contain an error message if
10646 : * an error occurs.
10647 : * @return true in case of success.
10648 : * @since GDAL 3.6
10649 : */
10650 0 : bool GDALDataset::UpdateRelationship(
10651 : CPL_UNUSED std::unique_ptr<GDALRelationship> &&relationship,
10652 : std::string &failureReason)
10653 : {
10654 0 : failureReason = "UpdateRelationship not supported by this driver";
10655 0 : return false;
10656 : }
10657 :
10658 : /************************************************************************/
10659 : /* GDALDatasetUpdateRelationship() */
10660 : /************************************************************************/
10661 :
10662 : /** Updates an existing relationship by replacing its definition.
10663 : *
10664 : * The existing relationship with matching name will be replaced.
10665 : *
10666 : * Only a few drivers will support this operation, and some of them might only
10667 : * support it only for some types of relationships.
10668 : * A dataset having at least some support for this
10669 : * operation should report the GDsCUpdateRelationship dataset capability.
10670 : *
10671 : * Anticipated failures will not be emitted through the CPLError()
10672 : * infrastructure, but will be reported in the failureReason output parameter.
10673 : *
10674 : * @param hDS Dataset handle.
10675 : * @param hRelationship The relationship definition. Contrary to the C++
10676 : * version, the passed object is copied.
10677 : * @param ppszFailureReason Output parameter. Will contain an error message if
10678 : * an error occurs (*ppszFailureReason to be freed
10679 : * with CPLFree). May be NULL.
10680 : * @return true in case of success.
10681 : * @since GDAL 3.5
10682 : */
10683 11 : bool GDALDatasetUpdateRelationship(GDALDatasetH hDS,
10684 : GDALRelationshipH hRelationship,
10685 : char **ppszFailureReason)
10686 : {
10687 11 : VALIDATE_POINTER1(hDS, __func__, false);
10688 11 : VALIDATE_POINTER1(hRelationship, __func__, false);
10689 : std::unique_ptr<GDALRelationship> poRelationship(
10690 22 : new GDALRelationship(*GDALRelationship::FromHandle(hRelationship)));
10691 11 : std::string failureReason;
10692 22 : const bool bRet = GDALDataset::FromHandle(hDS)->UpdateRelationship(
10693 11 : std::move(poRelationship), failureReason);
10694 11 : if (ppszFailureReason)
10695 : {
10696 0 : *ppszFailureReason =
10697 0 : failureReason.empty() ? nullptr : CPLStrdup(failureReason.c_str());
10698 : }
10699 11 : return bRet;
10700 : }
10701 :
10702 : /************************************************************************/
10703 : /* GDALDatasetSetQueryLoggerFunc() */
10704 : /************************************************************************/
10705 :
10706 : /**
10707 : * Sets the SQL query logger callback.
10708 : *
10709 : * When supported by the driver, the callback will be called with
10710 : * the executed SQL text, the error message, the execution time in milliseconds,
10711 : * the number of records fetched/affected and the client status data.
10712 : *
10713 : * A value of -1 in the execution time or in the number of records indicates
10714 : * that the values are unknown.
10715 : *
10716 : * @param hDS Dataset handle.
10717 : * @param pfnQueryLoggerFunc Callback function
10718 : * @param poQueryLoggerArg Opaque client status data
10719 : * @return true in case of success.
10720 : * @since GDAL 3.7
10721 : */
10722 1 : bool GDALDatasetSetQueryLoggerFunc(GDALDatasetH hDS,
10723 : GDALQueryLoggerFunc pfnQueryLoggerFunc,
10724 : void *poQueryLoggerArg)
10725 : {
10726 1 : VALIDATE_POINTER1(hDS, __func__, false);
10727 2 : return GDALDataset::FromHandle(hDS)->SetQueryLoggerFunc(pfnQueryLoggerFunc,
10728 1 : poQueryLoggerArg);
10729 : }
10730 :
10731 : //! @cond Doxygen_Suppress
10732 :
10733 : /************************************************************************/
10734 : /* SetEnableOverviews() */
10735 : /************************************************************************/
10736 :
10737 7531 : void GDALDataset::SetEnableOverviews(bool bEnable)
10738 : {
10739 7531 : if (m_poPrivate)
10740 : {
10741 7531 : m_poPrivate->m_bOverviewsEnabled = bEnable;
10742 : }
10743 7531 : }
10744 :
10745 : /************************************************************************/
10746 : /* AreOverviewsEnabled() */
10747 : /************************************************************************/
10748 :
10749 2007030 : bool GDALDataset::AreOverviewsEnabled() const
10750 : {
10751 2007030 : return m_poPrivate ? m_poPrivate->m_bOverviewsEnabled : true;
10752 : }
10753 :
10754 : /************************************************************************/
10755 : /* IsAllBands() */
10756 : /************************************************************************/
10757 :
10758 4210 : bool GDALDataset::IsAllBands(int nBandCount, const int *panBandList) const
10759 : {
10760 4210 : if (nBands != nBandCount)
10761 21 : return false;
10762 4189 : if (panBandList)
10763 : {
10764 15840 : for (int i = 0; i < nBandCount; ++i)
10765 : {
10766 11745 : if (panBandList[i] != i + 1)
10767 27 : return false;
10768 : }
10769 : }
10770 4162 : return true;
10771 : }
10772 :
10773 : //! @endcond
10774 :
10775 : /************************************************************************/
10776 : /* GetCompressionFormats() */
10777 : /************************************************************************/
10778 :
10779 : /** Return the compression formats that can be natively obtained for the
10780 : * window of interest and requested bands.
10781 : *
10782 : * For example, a tiled dataset may be able to return data in a compressed
10783 : * format if the window of interest matches exactly a tile. For some formats,
10784 : * drivers may also be able to merge several tiles together (not currently
10785 : * implemented though).
10786 : *
10787 : * Each format string is a pseudo MIME type, whose first part can be passed
10788 : * as the pszFormat argument of ReadCompressedData(), with additional
10789 : * parameters specified as key=value with a semi-colon separator.
10790 : *
10791 : * The amount and types of optional parameters passed after the MIME type is
10792 : * format dependent, and driver dependent (some drivers might not be able to
10793 : * return those extra information without doing a rather costly processing).
10794 : *
10795 : * For example, a driver might return "JPEG;frame_type=SOF0_baseline;"
10796 : * "bit_depth=8;num_components=3;subsampling=4:2:0;colorspace=YCbCr", and
10797 : * consequently "JPEG" can be passed as the pszFormat argument of
10798 : * ReadCompressedData(). For JPEG, implementations can use the
10799 : * GDALGetCompressionFormatForJPEG() helper method to generate a string like
10800 : * above from a JPEG codestream.
10801 : *
10802 : * Several values might be returned. For example,
10803 : * the JPEGXL driver will return "JXL", but also potentially "JPEG"
10804 : * if the JPEGXL codestream includes a JPEG reconstruction box.
10805 : *
10806 : * In the general case this method will return an empty list.
10807 : *
10808 : * This is the same as C function GDALDatasetGetCompressionFormats().
10809 : *
10810 : * @param nXOff The pixel offset to the top left corner of the region
10811 : * of the band to be accessed. This would be zero to start from the left side.
10812 : *
10813 : * @param nYOff The line offset to the top left corner of the region
10814 : * of the band to be accessed. This would be zero to start from the top.
10815 : *
10816 : * @param nXSize The width of the region of the band to be accessed in pixels.
10817 : *
10818 : * @param nYSize The height of the region of the band to be accessed in lines.
10819 : *
10820 : * @param nBandCount the number of bands being requested.
10821 : *
10822 : * @param panBandList the list of nBandCount band numbers.
10823 : * Note band numbers are 1 based. This may be NULL to select the first
10824 : * nBandCount bands.
10825 : *
10826 : * @return a list of compatible formats (which may be empty)
10827 : *
10828 : * For example, to check if native compression format(s) are available on the
10829 : * whole image:
10830 : * \code{.cpp}
10831 : * const CPLStringList aosFormats =
10832 : * poDataset->GetCompressionFormats(0, 0,
10833 : * poDataset->GetRasterXSize(),
10834 : * poDataset->GetRasterYSize(),
10835 : * poDataset->GetRasterCount(),
10836 : * nullptr);
10837 : * for( const char* pszFormat: aosFormats )
10838 : * {
10839 : * // Remove optional parameters and just print out the MIME type.
10840 : * const CPLStringList aosTokens(CSLTokenizeString2(pszFormat, ";", 0));
10841 : * printf("Found format %s\n, aosTokens[0]);
10842 : * }
10843 : * \endcode
10844 : *
10845 : * @since GDAL 3.7
10846 : */
10847 : CPLStringList
10848 0 : GDALDataset::GetCompressionFormats(CPL_UNUSED int nXOff, CPL_UNUSED int nYOff,
10849 : CPL_UNUSED int nXSize, CPL_UNUSED int nYSize,
10850 : CPL_UNUSED int nBandCount,
10851 : CPL_UNUSED const int *panBandList)
10852 : {
10853 0 : return CPLStringList();
10854 : }
10855 :
10856 : /************************************************************************/
10857 : /* GDALDatasetGetCompressionFormats() */
10858 : /************************************************************************/
10859 :
10860 : /** Return the compression formats that can be natively obtained for the
10861 : * window of interest and requested bands.
10862 : *
10863 : * For example, a tiled dataset may be able to return data in a compressed
10864 : * format if the window of interest matches exactly a tile. For some formats,
10865 : * drivers may also be able to merge several tiles together (not currently
10866 : * implemented though).
10867 : *
10868 : * Each format string is a pseudo MIME type, whose first part can be passed
10869 : * as the pszFormat argument of ReadCompressedData(), with additional
10870 : * parameters specified as key=value with a semi-colon separator.
10871 : *
10872 : * The amount and types of optional parameters passed after the MIME type is
10873 : * format dependent, and driver dependent (some drivers might not be able to
10874 : * return those extra information without doing a rather costly processing).
10875 : *
10876 : * For example, a driver might return "JPEG;frame_type=SOF0_baseline;"
10877 : * "bit_depth=8;num_components=3;subsampling=4:2:0;colorspace=YCbCr", and
10878 : * consequently "JPEG" can be passed as the pszFormat argument of
10879 : * ReadCompressedData(). For JPEG, implementations can use the
10880 : * GDALGetCompressionFormatForJPEG() helper method to generate a string like
10881 : * above from a JPEG codestream.
10882 : *
10883 : * Several values might be returned. For example,
10884 : * the JPEGXL driver will return "JXL", but also potentially "JPEG"
10885 : * if the JPEGXL codestream includes a JPEG reconstruction box.
10886 : *
10887 : * In the general case this method will return an empty list.
10888 : *
10889 : * This is the same as C++ method GDALDataset::GetCompressionFormats().
10890 : *
10891 : * @param hDS Dataset handle.
10892 : *
10893 : * @param nXOff The pixel offset to the top left corner of the region
10894 : * of the band to be accessed. This would be zero to start from the left side.
10895 : *
10896 : * @param nYOff The line offset to the top left corner of the region
10897 : * of the band to be accessed. This would be zero to start from the top.
10898 : *
10899 : * @param nXSize The width of the region of the band to be accessed in pixels.
10900 : *
10901 : * @param nYSize The height of the region of the band to be accessed in lines.
10902 : *
10903 : * @param nBandCount the number of bands being requested.
10904 : *
10905 : * @param panBandList the list of nBandCount band numbers.
10906 : * Note band numbers are 1 based. This may be NULL to select the first
10907 : * nBandCount bands.
10908 : *
10909 : * @return a list of compatible formats (which may be empty) that should be
10910 : * freed with CSLDestroy(), or nullptr.
10911 : *
10912 : * @since GDAL 3.7
10913 : */
10914 9 : char **GDALDatasetGetCompressionFormats(GDALDatasetH hDS, int nXOff, int nYOff,
10915 : int nXSize, int nYSize, int nBandCount,
10916 : const int *panBandList)
10917 : {
10918 9 : VALIDATE_POINTER1(hDS, __func__, nullptr);
10919 9 : return GDALDataset::FromHandle(hDS)
10920 9 : ->GetCompressionFormats(nXOff, nYOff, nXSize, nYSize, nBandCount,
10921 9 : panBandList)
10922 9 : .StealList();
10923 : }
10924 :
10925 : /************************************************************************/
10926 : /* ReadCompressedData() */
10927 : /************************************************************************/
10928 :
10929 : /** Return the compressed content that can be natively obtained for the
10930 : * window of interest and requested bands.
10931 : *
10932 : * For example, a tiled dataset may be able to return data in compressed format
10933 : * if the window of interest matches exactly a tile. For some formats, drivers
10934 : * may also be example to merge several tiles together (not currently
10935 : * implemented though).
10936 : *
10937 : * The implementation should make sure that the content returned forms a valid
10938 : * standalone file. For example, for the GeoTIFF implementation of this method,
10939 : * when extracting a JPEG tile, the method will automatically add the content
10940 : * of the JPEG Huffman and/or quantization tables that might be stored in the
10941 : * TIFF JpegTables tag, and not in tile data itself.
10942 : *
10943 : * In the general case this method will return CE_Failure.
10944 : *
10945 : * This is the same as C function GDALDatasetReadCompressedData().
10946 : *
10947 : * @param pszFormat Requested compression format (e.g. "JPEG",
10948 : * "WEBP", "JXL"). This is the MIME type of one of the values
10949 : * returned by GetCompressionFormats(). The format string is designed to
10950 : * potentially include at a later point key=value optional parameters separated
10951 : * by a semi-colon character. At time of writing, none are implemented.
10952 : * ReadCompressedData() implementations should verify optional parameters and
10953 : * return CE_Failure if they cannot support one of them.
10954 : *
10955 : * @param nXOff The pixel offset to the top left corner of the region
10956 : * of the band to be accessed. This would be zero to start from the left side.
10957 : *
10958 : * @param nYOff The line offset to the top left corner of the region
10959 : * of the band to be accessed. This would be zero to start from the top.
10960 : *
10961 : * @param nXSize The width of the region of the band to be accessed in pixels.
10962 : *
10963 : * @param nYSize The height of the region of the band to be accessed in lines.
10964 : *
10965 : * @param nBandCount the number of bands being requested.
10966 : *
10967 : * @param panBandList the list of nBandCount band numbers.
10968 : * Note band numbers are 1 based. This may be NULL to select the first
10969 : * nBandCount bands.
10970 : *
10971 : * @param ppBuffer Pointer to a buffer to store the compressed data or nullptr.
10972 : * If ppBuffer is not nullptr, then pnBufferSize should also not be nullptr.
10973 : * If ppBuffer is not nullptr, and *ppBuffer is not nullptr, then the provided
10974 : * buffer will be filled with the compressed data, provided that pnBufferSize
10975 : * and *pnBufferSize are not nullptr, and *pnBufferSize, indicating the size
10976 : * of *ppBuffer, is sufficiently large to hold the data.
10977 : * If ppBuffer is not nullptr, but *ppBuffer is nullptr, then the method will
10978 : * allocate *ppBuffer using VSIMalloc(), and thus the caller is responsible to
10979 : * free it with VSIFree().
10980 : * If ppBuffer is nullptr, then the compressed data itself will not be returned,
10981 : * but *pnBufferSize will be updated with an upper bound of the size that would
10982 : * be necessary to hold it (if pnBufferSize != nullptr).
10983 : *
10984 : * @param pnBufferSize Output buffer size, or nullptr.
10985 : * If ppBuffer != nullptr && *ppBuffer != nullptr, then pnBufferSize should
10986 : * be != nullptr and *pnBufferSize contain the size of *ppBuffer. If the
10987 : * method is successful, *pnBufferSize will be updated with the actual size
10988 : * used.
10989 : *
10990 : * @param ppszDetailedFormat Pointer to an output string, or nullptr.
10991 : * If ppszDetailedFormat is not nullptr, then, on success, the method will
10992 : * allocate a new string in *ppszDetailedFormat (to be freed with VSIFree())
10993 : * *ppszDetailedFormat might contain strings like
10994 : * "JPEG;frame_type=SOF0_baseline;bit_depth=8;num_components=3;"
10995 : * "subsampling=4:2:0;colorspace=YCbCr" or simply the MIME type.
10996 : * The string will contain at least as much information as what
10997 : * GetCompressionFormats() returns, and potentially more when
10998 : * ppBuffer != nullptr.
10999 : *
11000 : * @return CE_None in case of success, CE_Failure otherwise.
11001 : *
11002 : * For example, to request JPEG content on the whole image and let GDAL deal
11003 : * with the buffer allocation.
11004 : * \code{.cpp}
11005 : * void* pBuffer = nullptr;
11006 : * size_t nBufferSize = 0;
11007 : * CPLErr eErr =
11008 : * poDataset->ReadCompressedData("JPEG",
11009 : * 0, 0,
11010 : * poDataset->GetRasterXSize(),
11011 : * poDataset->GetRasterYSize(),
11012 : * poDataset->GetRasterCount(),
11013 : * nullptr, // panBandList
11014 : * &pBuffer,
11015 : * &nBufferSize,
11016 : * nullptr // ppszDetailedFormat
11017 : * );
11018 : * if (eErr == CE_None)
11019 : * {
11020 : * CPLAssert(pBuffer != nullptr);
11021 : * CPLAssert(nBufferSize > 0);
11022 : * VSILFILE* fp = VSIFOpenL("my.jpeg", "wb");
11023 : * if (fp)
11024 : * {
11025 : * VSIFWriteL(pBuffer, nBufferSize, 1, fp);
11026 : * VSIFCloseL(fp);
11027 : * }
11028 : * VSIFree(pBuffer);
11029 : * }
11030 : * \endcode
11031 : *
11032 : * Or to manage the buffer allocation on your side:
11033 : * \code{.cpp}
11034 : * size_t nUpperBoundBufferSize = 0;
11035 : * CPLErr eErr =
11036 : * poDataset->ReadCompressedData("JPEG",
11037 : * 0, 0,
11038 : * poDataset->GetRasterXSize(),
11039 : * poDataset->GetRasterYSize(),
11040 : * poDataset->GetRasterCount(),
11041 : * nullptr, // panBandList
11042 : * nullptr, // ppBuffer,
11043 : * &nUpperBoundBufferSize,
11044 : * nullptr // ppszDetailedFormat
11045 : * );
11046 : * if (eErr == CE_None)
11047 : * {
11048 : * std::vector<uint8_t> myBuffer;
11049 : * myBuffer.resize(nUpperBoundBufferSize);
11050 : * void* pBuffer = myBuffer.data();
11051 : * size_t nActualSize = nUpperBoundBufferSize;
11052 : * char* pszDetailedFormat = nullptr;
11053 : * // We also request detailed format, but we could have passed it to
11054 : * // nullptr as well.
11055 : * eErr =
11056 : * poDataset->ReadCompressedData("JPEG",
11057 : * 0, 0,
11058 : * poDataset->GetRasterXSize(),
11059 : * poDataset->GetRasterYSize(),
11060 : * poDataset->GetRasterCount(),
11061 : * nullptr, // panBandList
11062 : * &pBuffer,
11063 : * &nActualSize,
11064 : * &pszDetailedFormat);
11065 : * if (eErr == CE_None)
11066 : * {
11067 : * CPLAssert(pBuffer == myBuffer.data()); // pointed value not modified
11068 : * CPLAssert(nActualSize <= nUpperBoundBufferSize);
11069 : * myBuffer.resize(nActualSize);
11070 : * // do something useful
11071 : * VSIFree(pszDetailedFormat);
11072 : * }
11073 : * }
11074 : * \endcode
11075 : *
11076 : * @since GDAL 3.7
11077 : */
11078 444 : CPLErr GDALDataset::ReadCompressedData(
11079 : CPL_UNUSED const char *pszFormat, CPL_UNUSED int nXOff,
11080 : CPL_UNUSED int nYOff, CPL_UNUSED int nXSize, CPL_UNUSED int nYSize,
11081 : CPL_UNUSED int nBandCount, CPL_UNUSED const int *panBandList,
11082 : CPL_UNUSED void **ppBuffer, CPL_UNUSED size_t *pnBufferSize,
11083 : CPL_UNUSED char **ppszDetailedFormat)
11084 : {
11085 444 : return CE_Failure;
11086 : }
11087 :
11088 : /************************************************************************/
11089 : /* GDALDatasetReadCompressedData() */
11090 : /************************************************************************/
11091 :
11092 : /** Return the compressed content that can be natively obtained for the
11093 : * window of interest and requested bands.
11094 : *
11095 : * For example, a tiled dataset may be able to return data in compressed format
11096 : * if the window of interest matches exactly a tile. For some formats, drivers
11097 : * may also be example to merge several tiles together (not currently
11098 : * implemented though).
11099 : *
11100 : * The implementation should make sure that the content returned forms a valid
11101 : * standalone file. For example, for the GeoTIFF implementation of this method,
11102 : * when extracting a JPEG tile, the method will automatically adds the content
11103 : * of the JPEG Huffman and/or quantization tables that might be stored in the
11104 : * TIFF JpegTables tag, and not in tile data itself.
11105 : *
11106 : * In the general case this method will return CE_Failure.
11107 : *
11108 : * This is the same as C++ method GDALDataset:ReadCompressedData().
11109 : *
11110 : * @param hDS Dataset handle.
11111 : *
11112 : * @param pszFormat Requested compression format (e.g. "JPEG",
11113 : * "WEBP", "JXL"). This is the MIME type of one of the values
11114 : * returned by GetCompressionFormats(). The format string is designed to
11115 : * potentially include at a later point key=value optional parameters separated
11116 : * by a semi-colon character. At time of writing, none are implemented.
11117 : * ReadCompressedData() implementations should verify optional parameters and
11118 : * return CE_Failure if they cannot support one of them.
11119 : *
11120 : * @param nXOff The pixel offset to the top left corner of the region
11121 : * of the band to be accessed. This would be zero to start from the left side.
11122 : *
11123 : * @param nYOff The line offset to the top left corner of the region
11124 : * of the band to be accessed. This would be zero to start from the top.
11125 : *
11126 : * @param nXSize The width of the region of the band to be accessed in pixels.
11127 : *
11128 : * @param nYSize The height of the region of the band to be accessed in lines.
11129 : *
11130 : * @param nBandCount the number of bands being requested.
11131 : *
11132 : * @param panBandList the list of nBandCount band numbers.
11133 : * Note band numbers are 1 based. This may be NULL to select the first
11134 : * nBandCount bands.
11135 : *
11136 : * @param ppBuffer Pointer to a buffer to store the compressed data or nullptr.
11137 : * If ppBuffer is not nullptr, then pnBufferSize should also not be nullptr.
11138 : * If ppBuffer is not nullptr, and *ppBuffer is not nullptr, then the provided
11139 : * buffer will be filled with the compressed data, provided that pnBufferSize
11140 : * and *pnBufferSize are not nullptr, and *pnBufferSize, indicating the size
11141 : * of *ppBuffer, is sufficiently large to hold the data.
11142 : * If ppBuffer is not nullptr, but *ppBuffer is nullptr, then the method will
11143 : * allocate *ppBuffer using VSIMalloc(), and thus the caller is responsible to
11144 : * free it with VSIFree().
11145 : * If ppBuffer is nullptr, then the compressed data itself will not be returned,
11146 : * but *pnBufferSize will be updated with an upper bound of the size that would
11147 : * be necessary to hold it (if pnBufferSize != nullptr).
11148 : *
11149 : * @param pnBufferSize Output buffer size, or nullptr.
11150 : * If ppBuffer != nullptr && *ppBuffer != nullptr, then pnBufferSize should
11151 : * be != nullptr and *pnBufferSize contain the size of *ppBuffer. If the
11152 : * method is successful, *pnBufferSize will be updated with the actual size
11153 : * used.
11154 : *
11155 : * @param ppszDetailedFormat Pointer to an output string, or nullptr.
11156 : * If ppszDetailedFormat is not nullptr, then, on success, the method will
11157 : * allocate a new string in *ppszDetailedFormat (to be freed with VSIFree())
11158 : * *ppszDetailedFormat might contain strings like
11159 : * "JPEG;frame_type=SOF0_baseline;bit_depth=8;num_components=3;"
11160 : * "subsampling=4:2:0;colorspace=YCbCr" or simply the MIME type.
11161 : * The string will contain at least as much information as what
11162 : * GetCompressionFormats() returns, and potentially more when
11163 : * ppBuffer != nullptr.
11164 : *
11165 : * @return CE_None in case of success, CE_Failure otherwise.
11166 : *
11167 : * @since GDAL 3.7
11168 : */
11169 28 : CPLErr GDALDatasetReadCompressedData(GDALDatasetH hDS, const char *pszFormat,
11170 : int nXOff, int nYOff, int nXSize,
11171 : int nYSize, int nBandCount,
11172 : const int *panBandList, void **ppBuffer,
11173 : size_t *pnBufferSize,
11174 : char **ppszDetailedFormat)
11175 : {
11176 28 : VALIDATE_POINTER1(hDS, __func__, CE_Failure);
11177 56 : return GDALDataset::FromHandle(hDS)->ReadCompressedData(
11178 : pszFormat, nXOff, nYOff, nXSize, nYSize, nBandCount, panBandList,
11179 28 : ppBuffer, pnBufferSize, ppszDetailedFormat);
11180 : }
11181 :
11182 : /************************************************************************/
11183 : /* CanBeCloned() */
11184 : /************************************************************************/
11185 :
11186 : //! @cond Doxygen_Suppress
11187 :
11188 : /** This method is called by GDALThreadSafeDataset::Create() to determine if
11189 : * it is possible to create a thread-safe wrapper for a dataset, which involves
11190 : * the ability to Clone() it.
11191 : *
11192 : * Implementations of this method must be thread-safe.
11193 : *
11194 : * @param nScopeFlags Combination of GDAL_OF_RASTER, GDAL_OF_VECTOR, etc. flags,
11195 : * expressing the intended use for thread-safety.
11196 : * Currently, the only valid scope is in the base
11197 : * implementation is GDAL_OF_RASTER.
11198 : * @param bCanShareState Determines if cloned datasets are allowed to share
11199 : * state with the dataset they have been cloned from.
11200 : * If set to true, the dataset from which they have been
11201 : * cloned from must remain opened during the lifetime of
11202 : * its clones.
11203 : * @return true if the Clone() method is expected to succeed with the same values
11204 : * of nScopeFlags and bCanShareState.
11205 : */
11206 149 : bool GDALDataset::CanBeCloned(int nScopeFlags,
11207 : [[maybe_unused]] bool bCanShareState) const
11208 : {
11209 149 : return m_bCanBeReopened && nScopeFlags == GDAL_OF_RASTER;
11210 : }
11211 :
11212 : //! @endcond
11213 :
11214 : /************************************************************************/
11215 : /* Clone() */
11216 : /************************************************************************/
11217 :
11218 : //! @cond Doxygen_Suppress
11219 :
11220 : /** This method "clones" the current dataset, that is it returns a new instance
11221 : * that is opened on the same underlying "file".
11222 : *
11223 : * The base implementation uses GDALDataset::Open() to re-open the dataset.
11224 : * The MEM driver has a specialized implementation that returns a new instance,
11225 : * but which shares the same memory buffer as this.
11226 : *
11227 : * Implementations of this method must be thread-safe.
11228 : *
11229 : * @param nScopeFlags Combination of GDAL_OF_RASTER, GDAL_OF_VECTOR, etc. flags,
11230 : * expressing the intended use for thread-safety.
11231 : * Currently, the only valid scope is in the base
11232 : * implementation is GDAL_OF_RASTER.
11233 : * @param bCanShareState Determines if cloned datasets are allowed to share
11234 : * state with the dataset they have been cloned from.
11235 : * If set to true, the dataset from which they have been
11236 : * cloned from must remain opened during the lifetime of
11237 : * its clones.
11238 : * @return a new instance, or nullptr in case of error.
11239 : */
11240 : std::unique_ptr<GDALDataset>
11241 2051 : GDALDataset::Clone(int nScopeFlags, [[maybe_unused]] bool bCanShareState) const
11242 : {
11243 4102 : CPLStringList aosAllowedDrivers;
11244 2051 : if (poDriver)
11245 2051 : aosAllowedDrivers.AddString(poDriver->GetDescription());
11246 : return std::unique_ptr<GDALDataset>(GDALDataset::Open(
11247 2051 : GetDescription(),
11248 2051 : nScopeFlags | GDAL_OF_INTERNAL | GDAL_OF_VERBOSE_ERROR,
11249 4102 : aosAllowedDrivers.List(), papszOpenOptions));
11250 : }
11251 :
11252 : //! @endcond
11253 :
11254 : /************************************************************************/
11255 : /* GeolocationToPixelLine() */
11256 : /************************************************************************/
11257 :
11258 : /** Transform georeferenced coordinates to pixel/line coordinates.
11259 : *
11260 : * When poSRS is null, those georeferenced coordinates (dfGeolocX, dfGeolocY)
11261 : * must be in the "natural" SRS of the dataset, that is the one returned by
11262 : * GetSpatialRef() if there is a geotransform, GetGCPSpatialRef() if there are
11263 : * GCPs, WGS 84 if there are RPC coefficients, or the SRS of the geolocation
11264 : * array (generally WGS 84) if there is a geolocation array.
11265 : * If that natural SRS is a geographic one, dfGeolocX must be a longitude, and
11266 : * dfGeolocY a latitude. If that natural SRS is a projected one, dfGeolocX must
11267 : * be a easting, and dfGeolocY a northing.
11268 : *
11269 : * When poSRS is set to a non-null value, (dfGeolocX, dfGeolocY) must be
11270 : * expressed in that CRS, and that tuple must be conformant with the
11271 : * data-axis-to-crs-axis setting of poSRS, that is the one returned by
11272 : * the OGRSpatialReference::GetDataAxisToSRSAxisMapping(). If you want to be sure
11273 : * of the axis order, then make sure to call poSRS->SetAxisMappingStrategy(OAMS_TRADITIONAL_GIS_ORDER)
11274 : * before calling this method, and in that case, dfGeolocX must be a longitude
11275 : * or an easting value, and dfGeolocX a latitude or a northing value.
11276 : *
11277 : * This method uses GDALCreateGenImgProjTransformer2() underneath.
11278 : *
11279 : * @param dfGeolocX X coordinate of the position (longitude or easting if poSRS
11280 : * is null, otherwise consistent with poSRS data-axis-to-crs-axis mapping),
11281 : * where interpolation should be done.
11282 : * @param dfGeolocY Y coordinate of the position (latitude or northing if poSRS
11283 : * is null, otherwise consistent with poSRS data-axis-to-crs-axis mapping),
11284 : * where interpolation should be done.
11285 : * @param poSRS If set, override the natural CRS in which dfGeolocX, dfGeolocY are expressed
11286 : * @param[out] pdfPixel Pointer to the variable where to the store the pixel/column coordinate.
11287 : * @param[out] pdfLine Pointer to the variable where to the store the line coordinate.
11288 : * @param papszTransformerOptions Options accepted by GDALCreateGenImgProjTransformer2(), or nullptr.
11289 : *
11290 : * @return CE_None on success, or an error code on failure.
11291 : * @since GDAL 3.11
11292 : */
11293 :
11294 : CPLErr
11295 15 : GDALDataset::GeolocationToPixelLine(double dfGeolocX, double dfGeolocY,
11296 : const OGRSpatialReference *poSRS,
11297 : double *pdfPixel, double *pdfLine,
11298 : CSLConstList papszTransformerOptions) const
11299 : {
11300 30 : CPLStringList aosTO(papszTransformerOptions);
11301 :
11302 15 : if (poSRS)
11303 : {
11304 4 : const char *const apszOptions[] = {"FORMAT=WKT2", nullptr};
11305 8 : const std::string osWKT = poSRS->exportToWkt(apszOptions);
11306 4 : aosTO.SetNameValue("DST_SRS", osWKT.c_str());
11307 4 : const auto eAxisMappingStrategy = poSRS->GetAxisMappingStrategy();
11308 4 : if (eAxisMappingStrategy == OAMS_TRADITIONAL_GIS_ORDER)
11309 : aosTO.SetNameValue("DST_SRS_AXIS_MAPPING_STRATEGY",
11310 1 : "TRADITIONAL_GIS_ORDER");
11311 3 : else if (eAxisMappingStrategy == OAMS_AUTHORITY_COMPLIANT)
11312 : aosTO.SetNameValue("DST_SRS_AXIS_MAPPING_STRATEGY",
11313 1 : "AUTHORITY_COMPLIANT");
11314 : else
11315 : {
11316 2 : const auto &anValues = poSRS->GetDataAxisToSRSAxisMapping();
11317 4 : std::string osVal;
11318 6 : for (int v : anValues)
11319 : {
11320 4 : if (!osVal.empty())
11321 2 : osVal += ',';
11322 4 : osVal += std::to_string(v);
11323 : }
11324 : aosTO.SetNameValue("DST_SRS_DATA_AXIS_TO_SRS_AXIS_MAPPING",
11325 2 : osVal.c_str());
11326 : }
11327 : }
11328 :
11329 15 : auto hTransformer = GDALCreateGenImgProjTransformer2(
11330 : GDALDataset::ToHandle(const_cast<GDALDataset *>(this)), nullptr,
11331 15 : aosTO.List());
11332 15 : if (hTransformer == nullptr)
11333 : {
11334 1 : return CE_Failure;
11335 : }
11336 :
11337 14 : double z = 0;
11338 14 : int bSuccess = 0;
11339 14 : GDALGenImgProjTransform(hTransformer, TRUE, 1, &dfGeolocX, &dfGeolocY, &z,
11340 : &bSuccess);
11341 14 : GDALDestroyTransformer(hTransformer);
11342 14 : if (bSuccess)
11343 : {
11344 14 : if (pdfPixel)
11345 14 : *pdfPixel = dfGeolocX;
11346 14 : if (pdfLine)
11347 14 : *pdfLine = dfGeolocY;
11348 14 : return CE_None;
11349 : }
11350 : else
11351 : {
11352 0 : return CE_Failure;
11353 : }
11354 : }
11355 :
11356 : /************************************************************************/
11357 : /* GDALDatasetGeolocationToPixelLine() */
11358 : /************************************************************************/
11359 :
11360 : /** Transform georeferenced coordinates to pixel/line coordinates.
11361 : *
11362 : * @see GDALDataset::GeolocationToPixelLine()
11363 : * @since GDAL 3.11
11364 : */
11365 :
11366 0 : CPLErr GDALDatasetGeolocationToPixelLine(GDALDatasetH hDS, double dfGeolocX,
11367 : double dfGeolocY,
11368 : OGRSpatialReferenceH hSRS,
11369 : double *pdfPixel, double *pdfLine,
11370 : CSLConstList papszTransformerOptions)
11371 : {
11372 0 : VALIDATE_POINTER1(hDS, "GDALDatasetGeolocationToPixelLine", CE_Failure);
11373 :
11374 0 : GDALDataset *poDS = GDALDataset::FromHandle(hDS);
11375 0 : return poDS->GeolocationToPixelLine(
11376 0 : dfGeolocX, dfGeolocY, OGRSpatialReference::FromHandle(hSRS), pdfPixel,
11377 0 : pdfLine, papszTransformerOptions);
11378 : }
11379 :
11380 : /************************************************************************/
11381 : /* GetExtent() */
11382 : /************************************************************************/
11383 :
11384 : /** Return extent of dataset in specified CRS.
11385 : *
11386 : * OGREnvelope.MinX/MaxX represents longitudes, and MinY/MaxY latitudes.
11387 : *
11388 : * For rasters, the base implementation of this method only succeeds if
11389 : * GetGeoTransform() and GetSpatialRef() succeed.
11390 : * For vectors, the base implementation of this method iterates over layers
11391 : * and call their OGRLayer::GetExtent() method.
11392 : *
11393 : * TestCapability(GDsCFastGetExtent) can be used to test if the execution
11394 : * time of this method is fast.
11395 : *
11396 : * This is the same as C function GDALGetExtent()
11397 : *
11398 : * @param[out] psExtent Pointer to output extent. Must NOT be null.
11399 : * @param poCRS CRS in which to express the extent. If not specified, this will
11400 : * be the raster CRS or the CRS of the first layer for a vector dataset.
11401 : * @return CE_None in case of success, CE_Failure otherwise
11402 : * @since GDAL 3.12
11403 : */
11404 :
11405 456 : CPLErr GDALDataset::GetExtent(OGREnvelope *psExtent,
11406 : const OGRSpatialReference *poCRS) const
11407 : {
11408 456 : const OGRSpatialReference *poThisCRS = GetSpatialRefRasterOnly();
11409 456 : int nLayerCount = 0;
11410 456 : if (!poThisCRS)
11411 : {
11412 93 : nLayerCount = GetLayerCount();
11413 93 : if (nLayerCount >= 1)
11414 : {
11415 3 : if (auto poLayer = GetLayer(0))
11416 3 : poThisCRS = poLayer->GetSpatialRef();
11417 : }
11418 : }
11419 456 : if (!poCRS)
11420 246 : poCRS = poThisCRS;
11421 210 : else if (!poThisCRS)
11422 3 : return CE_Failure;
11423 :
11424 453 : *psExtent = OGREnvelope();
11425 :
11426 453 : GDALGeoTransform gt;
11427 453 : auto poThisDS = const_cast<GDALDataset *>(this);
11428 453 : const bool bHasGT = poThisDS->GetGeoTransform(gt) == CE_None;
11429 453 : if (bHasGT)
11430 : {
11431 0 : std::unique_ptr<OGRCoordinateTransformation> poCT;
11432 448 : if (poCRS)
11433 : {
11434 363 : poCT.reset(OGRCreateCoordinateTransformation(poThisCRS, poCRS));
11435 : }
11436 :
11437 448 : constexpr int DENSIFY_POINT_COUNT = 21;
11438 448 : double dfULX = gt.xorig;
11439 448 : double dfULY = gt.yorig;
11440 448 : double dfURX = 0, dfURY = 0;
11441 448 : gt.Apply(nRasterXSize, 0, &dfURX, &dfURY);
11442 448 : double dfLLX = 0, dfLLY = 0;
11443 448 : gt.Apply(0, nRasterYSize, &dfLLX, &dfLLY);
11444 448 : double dfLRX = 0, dfLRY = 0;
11445 448 : gt.Apply(nRasterXSize, nRasterYSize, &dfLRX, &dfLRY);
11446 448 : const double xmin = std::min({dfULX, dfURX, dfLLX, dfLRX});
11447 448 : const double ymin = std::min({dfULY, dfURY, dfLLY, dfLRY});
11448 448 : const double xmax = std::max({dfULX, dfURX, dfLLX, dfLRX});
11449 448 : const double ymax = std::max({dfULY, dfURY, dfLLY, dfLRY});
11450 448 : if (poCT)
11451 : {
11452 361 : OGREnvelope sEnvTmp;
11453 722 : if (!poCT->TransformBounds(xmin, ymin, xmax, ymax, &(sEnvTmp.MinX),
11454 : &(sEnvTmp.MinY), &(sEnvTmp.MaxX),
11455 361 : &(sEnvTmp.MaxY), DENSIFY_POINT_COUNT))
11456 : {
11457 0 : return CE_Failure;
11458 : }
11459 361 : *psExtent = sEnvTmp;
11460 : }
11461 : else
11462 : {
11463 87 : psExtent->MinX = xmin;
11464 87 : psExtent->MinY = ymin;
11465 87 : psExtent->MaxX = xmax;
11466 87 : psExtent->MaxY = ymax;
11467 : }
11468 : }
11469 :
11470 453 : if (nLayerCount > 0)
11471 : {
11472 6 : for (auto &&poLayer : poThisDS->GetLayers())
11473 : {
11474 3 : auto poLayerCRS = poLayer->GetSpatialRef();
11475 3 : if (poLayerCRS)
11476 : {
11477 3 : OGREnvelope sLayerExtent;
11478 3 : if (poLayer->GetExtent(&sLayerExtent) == OGRERR_NONE)
11479 : {
11480 : auto poCT = std::unique_ptr<OGRCoordinateTransformation>(
11481 6 : OGRCreateCoordinateTransformation(poLayerCRS, poCRS));
11482 3 : if (poCT)
11483 : {
11484 3 : constexpr int DENSIFY_POINT_COUNT = 21;
11485 3 : OGREnvelope sEnvTmp;
11486 3 : if (poCT->TransformBounds(
11487 : sLayerExtent.MinX, sLayerExtent.MinY,
11488 : sLayerExtent.MaxX, sLayerExtent.MaxY,
11489 : &(sEnvTmp.MinX), &(sEnvTmp.MinY),
11490 : &(sEnvTmp.MaxX), &(sEnvTmp.MaxY),
11491 3 : DENSIFY_POINT_COUNT))
11492 : {
11493 3 : psExtent->Merge(sEnvTmp);
11494 : }
11495 : }
11496 : }
11497 : }
11498 : }
11499 : }
11500 :
11501 453 : return psExtent->IsInit() ? CE_None : CE_Failure;
11502 : }
11503 :
11504 : /************************************************************************/
11505 : /* GDALGetExtent() */
11506 : /************************************************************************/
11507 :
11508 : /** Return extent of dataset in specified CRS.
11509 : *
11510 : * OGREnvelope.MinX/MaxX represents longitudes, and MinY/MaxY latitudes.
11511 : *
11512 : * For rasters, the base implementation of this method only succeeds if
11513 : * GetGeoTransform() and GetSpatialRef() succeed.
11514 : * For vectors, the base implementation of this method iterates over layers
11515 : * and call their OGRLayer::GetExtent() method.
11516 : *
11517 : * TestCapability(GDsCFastGetExtent) can be used to test if the execution
11518 : * time of this method is fast.
11519 : *
11520 : * This is the same as C++ method GDALDataset::GetExtent()
11521 : *
11522 : * @param hDS Dataset handle. Must NOT be null.
11523 : * @param[out] psExtent Pointer to output extent. Must NOT be null.
11524 : * @param hCRS CRS in which to express the extent. If not specified, this will
11525 : * be the raster CRS or the CRS of the first layer for a vector dataset.
11526 : * @return extent in poCRS (valid only if IsInit() method returns true)
11527 : * @since GDAL 3.12
11528 : */
11529 :
11530 28 : CPLErr GDALGetExtent(GDALDatasetH hDS, OGREnvelope *psExtent,
11531 : OGRSpatialReferenceH hCRS)
11532 : {
11533 28 : VALIDATE_POINTER1(hDS, __func__, CE_Failure);
11534 28 : VALIDATE_POINTER1(psExtent, __func__, CE_Failure);
11535 56 : return GDALDataset::FromHandle(hDS)->GetExtent(
11536 28 : psExtent, OGRSpatialReference::FromHandle(hCRS));
11537 : }
11538 :
11539 : /************************************************************************/
11540 : /* GetExtentWGS84LongLat() */
11541 : /************************************************************************/
11542 :
11543 : /** Return extent of dataset in WGS84 longitude/latitude
11544 : *
11545 : * OGREnvelope.MinX/MaxX represents longitudes, and MinY/MaxY latitudes.
11546 : *
11547 : * TestCapability(GDsCFastGetExtentWGS84LongLat) can be used to test if the execution
11548 : * time of this method is fast.
11549 : *
11550 : * This is the same as C function GDALGetExtentWGS84LongLat()
11551 : *
11552 : * @return extent (valid only if IsInit() method returns true)
11553 : * @since GDAL 3.12
11554 : */
11555 :
11556 208 : CPLErr GDALDataset::GetExtentWGS84LongLat(OGREnvelope *psExtent) const
11557 : {
11558 416 : OGRSpatialReference oSRS_WGS84;
11559 208 : oSRS_WGS84.SetFromUserInput("WGS84");
11560 208 : oSRS_WGS84.SetAxisMappingStrategy(OAMS_TRADITIONAL_GIS_ORDER);
11561 416 : return GetExtent(psExtent, &oSRS_WGS84);
11562 : }
11563 :
11564 : /************************************************************************/
11565 : /* GDALGetExtentWGS84LongLat() */
11566 : /************************************************************************/
11567 :
11568 : /** Return extent of dataset in WGS84 longitude/latitude
11569 : *
11570 : * OGREnvelope.MinX/MaxX represents longitudes, and MinY/MaxY latitudes.
11571 : *
11572 : * TestCapability(GDsCFastGetExtentWGS84LongLat) can be used to test if the execution
11573 : * time of this method is fast.
11574 : *
11575 : * This is the same as C++ method GDALDataset::GetExtentWGS84LongLat()
11576 : *
11577 : * @param hDS Dataset handle. Must NOT be null.
11578 : * @param[out] psExtent Pointer to output extent. Must NOT be null.
11579 : * @return extent (valid only if IsInit() method returns true)
11580 : * @since GDAL 3.12
11581 : */
11582 :
11583 5 : CPLErr GDALGetExtentWGS84LongLat(GDALDatasetH hDS, OGREnvelope *psExtent)
11584 : {
11585 5 : VALIDATE_POINTER1(hDS, __func__, CE_Failure);
11586 5 : VALIDATE_POINTER1(psExtent, __func__, CE_Failure);
11587 5 : return GDALDataset::FromHandle(hDS)->GetExtentWGS84LongLat(psExtent);
11588 : }
11589 :
11590 : /************************************************************************/
11591 : /* ReportUpdateNotSupportedByDriver() */
11592 : /************************************************************************/
11593 :
11594 : //! @cond Doxygen_Suppress
11595 :
11596 : /* static */
11597 1 : void GDALDataset::ReportUpdateNotSupportedByDriver(const char *pszDriverName)
11598 : {
11599 1 : CPLError(CE_Failure, CPLE_NotSupported,
11600 : "The %s driver does not support update access to existing "
11601 : "datasets.",
11602 : pszDriverName);
11603 1 : }
11604 :
11605 : //! @endcond
11606 :
11607 : /************************************************************************/
11608 : /* BuildFilename() */
11609 : /************************************************************************/
11610 :
11611 : /** Generates a filename, potentially relative to another one.
11612 : *
11613 : * Given the path to a reference directory, and a path to a file
11614 : * referenced from it, build a path to the file that the current application
11615 : * can use. If the file path is already absolute, rather than relative, or if
11616 : * bRelativeToReferencePath is false, then the filename of interest will be
11617 : * returned unaltered.
11618 : *
11619 : * This is enhanced version of CPLProjectRelativeFilenameSafe() that takes
11620 : * into account the subdataset syntax.
11621 : *
11622 : * Examples:
11623 : * \code{.cpp}
11624 : * BuildFilename("tmp/abc.gif", "abc/def", true) == "abc/def/tmp/abc.gif"
11625 : * BuildFilename("../abc.gif", "/abc/def") == "/abc/abc.gif"
11626 : * BuildFilename("abc.gif", "C:\WIN", true) == "C:\WIN\abc.gif"
11627 : * BuildFilename("abc.gif", "C:\WIN", false) == "abc.gif"
11628 : * BuildFilename("/home/even/foo.tif", "/home/even/workdir", true) == "/home/even/foo.tif"
11629 : * \endcode
11630 : *
11631 : * @param pszFilename Filename of interest.
11632 : * @param pszReferencePath Path to a reference directory.
11633 : * @param bRelativeToReferencePath Whether pszFilename, if a relative path, is
11634 : * relative to pszReferencePath
11635 : * @since 3.11
11636 : */
11637 :
11638 : /* static */
11639 104255 : std::string GDALDataset::BuildFilename(const char *pszFilename,
11640 : const char *pszReferencePath,
11641 : bool bRelativeToReferencePath)
11642 : {
11643 104255 : std::string osSrcDSName;
11644 104255 : if (pszReferencePath != nullptr && bRelativeToReferencePath)
11645 : {
11646 : // Try subdatasetinfo API first
11647 : // Note: this will become the only branch when subdatasetinfo will become
11648 : // available for NITF_IM, RASTERLITE and TILEDB
11649 2619 : const auto oSubDSInfo{GDALGetSubdatasetInfo(pszFilename)};
11650 2619 : if (oSubDSInfo && !oSubDSInfo->GetPathComponent().empty())
11651 : {
11652 8 : auto path{oSubDSInfo->GetPathComponent()};
11653 12 : osSrcDSName = oSubDSInfo->ModifyPathComponent(
11654 8 : CPLProjectRelativeFilenameSafe(pszReferencePath, path.c_str())
11655 4 : .c_str());
11656 4 : GDALDestroySubdatasetInfo(oSubDSInfo);
11657 : }
11658 : else
11659 : {
11660 2615 : bool bDone = false;
11661 15675 : for (const char *pszSyntax : apszSpecialSubDatasetSyntax)
11662 : {
11663 13063 : CPLString osPrefix(pszSyntax);
11664 13063 : osPrefix.resize(strchr(pszSyntax, ':') - pszSyntax + 1);
11665 13063 : if (pszSyntax[osPrefix.size()] == '"')
11666 2612 : osPrefix += '"';
11667 13063 : if (EQUALN(pszFilename, osPrefix, osPrefix.size()))
11668 : {
11669 3 : if (STARTS_WITH_CI(pszSyntax + osPrefix.size(), "{ANY}"))
11670 : {
11671 3 : const char *pszLastPart = strrchr(pszFilename, ':') + 1;
11672 : // CSV:z:/foo.xyz
11673 3 : if ((pszLastPart[0] == '/' || pszLastPart[0] == '\\') &&
11674 0 : pszLastPart - pszFilename >= 3 &&
11675 0 : pszLastPart[-3] == ':')
11676 : {
11677 0 : pszLastPart -= 2;
11678 : }
11679 3 : CPLString osPrefixFilename = pszFilename;
11680 3 : osPrefixFilename.resize(pszLastPart - pszFilename);
11681 6 : osSrcDSName = osPrefixFilename +
11682 6 : CPLProjectRelativeFilenameSafe(
11683 3 : pszReferencePath, pszLastPart);
11684 3 : bDone = true;
11685 : }
11686 0 : else if (STARTS_WITH_CI(pszSyntax + osPrefix.size(),
11687 : "{FILENAME}"))
11688 : {
11689 0 : CPLString osFilename(pszFilename + osPrefix.size());
11690 0 : size_t nPos = 0;
11691 0 : if (osFilename.size() >= 3 && osFilename[1] == ':' &&
11692 0 : (osFilename[2] == '\\' || osFilename[2] == '/'))
11693 0 : nPos = 2;
11694 0 : nPos = osFilename.find(
11695 0 : pszSyntax[osPrefix.size() + strlen("{FILENAME}")],
11696 : nPos);
11697 0 : if (nPos != std::string::npos)
11698 : {
11699 0 : const CPLString osSuffix = osFilename.substr(nPos);
11700 0 : osFilename.resize(nPos);
11701 0 : osSrcDSName = osPrefix +
11702 0 : CPLProjectRelativeFilenameSafe(
11703 0 : pszReferencePath, osFilename) +
11704 0 : osSuffix;
11705 0 : bDone = true;
11706 : }
11707 : }
11708 3 : break;
11709 : }
11710 : }
11711 2615 : if (!bDone)
11712 : {
11713 2612 : std::string osReferencePath = pszReferencePath;
11714 2612 : if (!CPLIsFilenameRelative(pszReferencePath))
11715 : {
11716 : // Simplify path by replacing "foo/a/../b" with "foo/b"
11717 2319 : while (STARTS_WITH(pszFilename, "../"))
11718 : {
11719 : osReferencePath =
11720 5 : CPLGetPathSafe(osReferencePath.c_str());
11721 5 : pszFilename += strlen("../");
11722 : }
11723 : }
11724 :
11725 5224 : osSrcDSName = CPLProjectRelativeFilenameSafe(
11726 2612 : osReferencePath.c_str(), pszFilename);
11727 : }
11728 2619 : }
11729 : }
11730 : else
11731 : {
11732 101636 : osSrcDSName = pszFilename;
11733 : }
11734 104255 : return osSrcDSName;
11735 : }
11736 :
11737 : /************************************************************************/
11738 : /* GDALMDArrayFromDataset */
11739 : /************************************************************************/
11740 :
11741 : class GDALMDArrayFromDataset final : public GDALMDArray
11742 : {
11743 : CPL_DISALLOW_COPY_ASSIGN(GDALMDArrayFromDataset)
11744 :
11745 : GDALDataset *const m_poDS;
11746 : const GDALExtendedDataType m_dt;
11747 : std::vector<std::shared_ptr<GDALDimension>> m_dims{};
11748 : std::string m_osUnit{};
11749 : std::vector<GByte> m_abyNoData{};
11750 : std::shared_ptr<GDALMDArray> m_varX{};
11751 : std::shared_ptr<GDALMDArray> m_varY{};
11752 : std::shared_ptr<GDALMDArray> m_varBand{};
11753 : const std::string m_osFilename;
11754 : const CPLStringList m_aosOptions;
11755 : int m_iBandDim = 0;
11756 : int m_iYDim = 1;
11757 : int m_iXDim = 2;
11758 : mutable std::vector<std::shared_ptr<GDALMDArray>> m_apoOverviews{};
11759 :
11760 : bool ReadWrite(GDALRWFlag eRWFlag, const GUInt64 *arrayStartIdx,
11761 : const size_t *count, const GInt64 *arrayStep,
11762 : const GPtrDiff_t *bufferStride,
11763 : const GDALExtendedDataType &bufferDataType,
11764 : void *pBuffer) const;
11765 :
11766 : protected:
11767 17 : GDALMDArrayFromDataset(GDALDataset *poDS, CSLConstList papszOptions)
11768 34 : : GDALAbstractMDArray(std::string(),
11769 34 : std::string(poDS->GetDescription())),
11770 34 : GDALMDArray(std::string(), std::string(poDS->GetDescription())),
11771 : m_poDS(poDS), m_dt(GDALExtendedDataType::Create(
11772 : poDS->GetRasterBand(1)->GetRasterDataType())),
11773 85 : m_osFilename(poDS->GetDescription()), m_aosOptions(papszOptions)
11774 : {
11775 17 : m_poDS->Reference();
11776 :
11777 17 : const int nBandCount = poDS->GetRasterCount();
11778 47 : for (int i = 1; i <= nBandCount; ++i)
11779 : {
11780 30 : const auto poBand = poDS->GetRasterBand(i);
11781 30 : if (i == 1)
11782 17 : m_osUnit = poBand->GetUnitType();
11783 13 : else if (m_osUnit != poBand->GetUnitType())
11784 7 : m_osUnit.clear();
11785 :
11786 60 : std::vector<GByte> abyNoData;
11787 30 : int bHasNoData = false;
11788 30 : switch (poBand->GetRasterDataType())
11789 : {
11790 0 : case GDT_Int64:
11791 : {
11792 : const auto nNoData =
11793 0 : poBand->GetNoDataValueAsInt64(&bHasNoData);
11794 0 : if (bHasNoData)
11795 : {
11796 0 : abyNoData.resize(m_dt.GetSize());
11797 0 : GDALCopyWords64(&nNoData, GDT_Int64, 0, &abyNoData[0],
11798 : m_dt.GetNumericDataType(), 0, 1);
11799 : }
11800 0 : break;
11801 : }
11802 :
11803 0 : case GDT_UInt64:
11804 : {
11805 : const auto nNoData =
11806 0 : poBand->GetNoDataValueAsUInt64(&bHasNoData);
11807 0 : if (bHasNoData)
11808 : {
11809 0 : abyNoData.resize(m_dt.GetSize());
11810 0 : GDALCopyWords64(&nNoData, GDT_UInt64, 0, &abyNoData[0],
11811 : m_dt.GetNumericDataType(), 0, 1);
11812 : }
11813 0 : break;
11814 : }
11815 :
11816 30 : default:
11817 : {
11818 30 : const auto dfNoData = poBand->GetNoDataValue(&bHasNoData);
11819 30 : if (bHasNoData)
11820 : {
11821 11 : abyNoData.resize(m_dt.GetSize());
11822 22 : GDALCopyWords64(&dfNoData, GDT_Float64, 0,
11823 11 : &abyNoData[0],
11824 : m_dt.GetNumericDataType(), 0, 1);
11825 : }
11826 30 : break;
11827 : }
11828 : }
11829 :
11830 30 : if (i == 1)
11831 17 : m_abyNoData = std::move(abyNoData);
11832 13 : else if (m_abyNoData != abyNoData)
11833 7 : m_abyNoData.clear();
11834 : }
11835 :
11836 17 : const int nXSize = poDS->GetRasterXSize();
11837 17 : const int nYSize = poDS->GetRasterYSize();
11838 :
11839 17 : auto poSRS = poDS->GetSpatialRef();
11840 34 : std::string osTypeY;
11841 34 : std::string osTypeX;
11842 34 : std::string osDirectionY;
11843 34 : std::string osDirectionX;
11844 17 : if (poSRS && poSRS->GetAxesCount() == 2)
11845 : {
11846 8 : const auto &mapping = poSRS->GetDataAxisToSRSAxisMapping();
11847 8 : OGRAxisOrientation eOrientation1 = OAO_Other;
11848 8 : poSRS->GetAxis(nullptr, 0, &eOrientation1);
11849 8 : OGRAxisOrientation eOrientation2 = OAO_Other;
11850 8 : poSRS->GetAxis(nullptr, 1, &eOrientation2);
11851 8 : if (eOrientation1 == OAO_East && eOrientation2 == OAO_North)
11852 : {
11853 6 : if (mapping == std::vector<int>{1, 2})
11854 : {
11855 6 : osTypeY = GDAL_DIM_TYPE_HORIZONTAL_Y;
11856 6 : osDirectionY = "NORTH";
11857 6 : osTypeX = GDAL_DIM_TYPE_HORIZONTAL_X;
11858 6 : osDirectionX = "EAST";
11859 : }
11860 : }
11861 2 : else if (eOrientation1 == OAO_North && eOrientation2 == OAO_East)
11862 : {
11863 2 : if (mapping == std::vector<int>{2, 1})
11864 : {
11865 2 : osTypeY = GDAL_DIM_TYPE_HORIZONTAL_Y;
11866 2 : osDirectionY = "NORTH";
11867 2 : osTypeX = GDAL_DIM_TYPE_HORIZONTAL_X;
11868 2 : osDirectionX = "EAST";
11869 : }
11870 : }
11871 : }
11872 :
11873 47 : const bool bBandYX = [papszOptions, poDS, nBandCount]()
11874 : {
11875 : const char *pszDimOrder =
11876 17 : CSLFetchNameValueDef(papszOptions, "DIM_ORDER", "AUTO");
11877 17 : if (EQUAL(pszDimOrder, "AUTO"))
11878 : {
11879 : const char *pszInterleave =
11880 15 : poDS->GetMetadataItem("INTERLEAVE", "IMAGE_STRUCTURE");
11881 24 : return nBandCount == 1 || !pszInterleave ||
11882 24 : !EQUAL(pszInterleave, "PIXEL");
11883 : }
11884 : else
11885 : {
11886 2 : return EQUAL(pszDimOrder, "BAND,Y,X");
11887 : }
11888 17 : }();
11889 : const char *const pszBandDimName =
11890 17 : CSLFetchNameValueDef(papszOptions, "BAND_DIM_NAME", "Band");
11891 : auto poBandDim = std::make_shared<GDALDimensionWeakIndexingVar>(
11892 51 : "/", pszBandDimName, std::string(), std::string(), nBandCount);
11893 : const char *const pszYDimName =
11894 17 : CSLFetchNameValueDef(papszOptions, "Y_DIM_NAME", "Y");
11895 : auto poYDim = std::make_shared<GDALDimensionWeakIndexingVar>(
11896 34 : "/", pszYDimName, osTypeY, osDirectionY, nYSize);
11897 : const char *const pszXDimName =
11898 17 : CSLFetchNameValueDef(papszOptions, "X_DIM_NAME", "X");
11899 : auto poXDim = std::make_shared<GDALDimensionWeakIndexingVar>(
11900 34 : "/", pszXDimName, osTypeX, osDirectionX, nXSize);
11901 :
11902 17 : const char *const pszBandIndexingVarItem = CSLFetchNameValueDef(
11903 : papszOptions, "BAND_INDEXING_VAR_ITEM", "{Description}");
11904 17 : if (EQUAL(pszBandIndexingVarItem, "{Description}"))
11905 : {
11906 : const auto oIndexingVarType =
11907 22 : GDALExtendedDataType::CreateString(strlen("Band 65535"));
11908 11 : auto poBandVar = MEMMDArray::Create("/", poBandDim->GetName(),
11909 44 : {poBandDim}, oIndexingVarType);
11910 11 : CPL_IGNORE_RET_VAL(poBandVar->Init());
11911 29 : for (int i = 0; i < nBandCount; ++i)
11912 : {
11913 : const char *pszDesc =
11914 18 : poDS->GetRasterBand(i + 1)->GetDescription();
11915 : const std::string osBandName =
11916 36 : pszDesc[0] ? pszDesc : CPLSPrintf("Band %d", i + 1);
11917 18 : const char *pszBandName = osBandName.c_str();
11918 18 : const char *const apszBandVal[] = {pszBandName};
11919 18 : const GUInt64 anStartIdx[] = {static_cast<GUInt64>(i)};
11920 18 : const size_t anCount[] = {1};
11921 18 : const GInt64 arrayStep[] = {1};
11922 18 : const GPtrDiff_t anBufferStride[] = {1};
11923 18 : poBandVar->Write(anStartIdx, anCount, arrayStep, anBufferStride,
11924 : oIndexingVarType, apszBandVal);
11925 : }
11926 11 : m_varBand = std::move(poBandVar);
11927 11 : poBandDim->SetIndexingVariable(m_varBand);
11928 : }
11929 6 : else if (EQUAL(pszBandIndexingVarItem, "{Index}"))
11930 : {
11931 : const auto oIndexingVarType =
11932 2 : GDALExtendedDataType::Create(GDT_Int32);
11933 1 : auto poBandVar = MEMMDArray::Create("/", poBandDim->GetName(),
11934 4 : {poBandDim}, oIndexingVarType);
11935 1 : CPL_IGNORE_RET_VAL(poBandVar->Init());
11936 3 : for (int i = 0; i < nBandCount; ++i)
11937 : {
11938 2 : const int anBandIdx[] = {i + 1};
11939 2 : const GUInt64 anStartIdx[] = {static_cast<GUInt64>(i)};
11940 2 : const size_t anCount[] = {1};
11941 2 : const GInt64 arrayStep[] = {1};
11942 2 : const GPtrDiff_t anBufferStride[] = {1};
11943 2 : poBandVar->Write(anStartIdx, anCount, arrayStep, anBufferStride,
11944 : oIndexingVarType, anBandIdx);
11945 : }
11946 1 : m_varBand = std::move(poBandVar);
11947 1 : poBandDim->SetIndexingVariable(m_varBand);
11948 : }
11949 5 : else if (EQUAL(pszBandIndexingVarItem, "{ColorInterpretation}"))
11950 : {
11951 1 : size_t nMaxLen = 0;
11952 3 : for (int i = 0; i < nBandCount; ++i)
11953 : {
11954 2 : const char *pszDesc = GDALGetColorInterpretationName(
11955 2 : poDS->GetRasterBand(i + 1)->GetColorInterpretation());
11956 2 : nMaxLen = std::max(nMaxLen, strlen(pszDesc));
11957 : }
11958 : const auto oIndexingVarType =
11959 2 : GDALExtendedDataType::CreateString(nMaxLen);
11960 1 : auto poBandVar = MEMMDArray::Create("/", poBandDim->GetName(),
11961 4 : {poBandDim}, oIndexingVarType);
11962 1 : CPL_IGNORE_RET_VAL(poBandVar->Init());
11963 3 : for (int i = 0; i < nBandCount; ++i)
11964 : {
11965 2 : const char *pszDesc = GDALGetColorInterpretationName(
11966 2 : poDS->GetRasterBand(i + 1)->GetColorInterpretation());
11967 2 : const char *const apszBandVal[] = {pszDesc};
11968 2 : const GUInt64 anStartIdx[] = {static_cast<GUInt64>(i)};
11969 2 : const size_t anCount[] = {1};
11970 2 : const GInt64 arrayStep[] = {1};
11971 2 : const GPtrDiff_t anBufferStride[] = {1};
11972 2 : poBandVar->Write(anStartIdx, anCount, arrayStep, anBufferStride,
11973 : oIndexingVarType, apszBandVal);
11974 : }
11975 1 : m_varBand = std::move(poBandVar);
11976 1 : poBandDim->SetIndexingVariable(m_varBand);
11977 : }
11978 4 : else if (!EQUAL(pszBandIndexingVarItem, "{None}"))
11979 : {
11980 3 : const char *const pszBandIndexingVarType = CSLFetchNameValueDef(
11981 : papszOptions, "BAND_INDEXING_VAR_TYPE", "String");
11982 3 : size_t nMaxLen = 0;
11983 3 : if (EQUAL(pszBandIndexingVarType, "String"))
11984 : {
11985 3 : for (int i = 0; i < nBandCount; ++i)
11986 : {
11987 : const char *pszVal =
11988 2 : poDS->GetRasterBand(i + 1)->GetMetadataItem(
11989 2 : pszBandIndexingVarItem);
11990 2 : if (pszVal)
11991 1 : nMaxLen = std::max(nMaxLen, strlen(pszVal));
11992 : }
11993 : }
11994 : const auto oIndexingVarType =
11995 3 : EQUAL(pszBandIndexingVarType, "String")
11996 : ? GDALExtendedDataType::CreateString(nMaxLen)
11997 2 : : EQUAL(pszBandIndexingVarType, "Integer")
11998 : ? GDALExtendedDataType::Create(GDT_Int32)
11999 6 : : GDALExtendedDataType::Create(GDT_Float64);
12000 3 : auto poBandVar = MEMMDArray::Create("/", poBandDim->GetName(),
12001 12 : {poBandDim}, oIndexingVarType);
12002 3 : CPL_IGNORE_RET_VAL(poBandVar->Init());
12003 9 : for (int i = 0; i < nBandCount; ++i)
12004 : {
12005 6 : const GUInt64 anStartIdx[] = {static_cast<GUInt64>(i)};
12006 6 : const size_t anCount[] = {1};
12007 6 : const GInt64 arrayStep[] = {1};
12008 6 : const GPtrDiff_t anBufferStride[] = {1};
12009 : const char *pszVal =
12010 6 : poDS->GetRasterBand(i + 1)->GetMetadataItem(
12011 6 : pszBandIndexingVarItem);
12012 6 : if (oIndexingVarType.GetClass() == GEDTC_STRING)
12013 : {
12014 2 : const char *const apszBandVal[] = {pszVal ? pszVal : ""};
12015 2 : poBandVar->Write(anStartIdx, anCount, arrayStep,
12016 : anBufferStride, oIndexingVarType,
12017 : apszBandVal);
12018 : }
12019 4 : else if (oIndexingVarType.GetNumericDataType() == GDT_Int32)
12020 : {
12021 2 : const int anVal[] = {pszVal ? atoi(pszVal) : 0};
12022 2 : poBandVar->Write(anStartIdx, anCount, arrayStep,
12023 : anBufferStride, oIndexingVarType, anVal);
12024 : }
12025 : else
12026 : {
12027 2 : const double adfVal[] = {pszVal ? CPLAtof(pszVal) : 0.0};
12028 2 : poBandVar->Write(anStartIdx, anCount, arrayStep,
12029 : anBufferStride, oIndexingVarType, adfVal);
12030 : }
12031 : }
12032 3 : m_varBand = std::move(poBandVar);
12033 3 : poBandDim->SetIndexingVariable(m_varBand);
12034 : }
12035 :
12036 17 : GDALGeoTransform gt;
12037 17 : if (m_poDS->GetGeoTransform(gt) == CE_None && gt.IsAxisAligned())
12038 : {
12039 24 : m_varX = GDALMDArrayRegularlySpaced::Create(
12040 16 : "/", poBandDim->GetName(), poXDim, gt.xorig, gt.xscale, 0.5);
12041 8 : poXDim->SetIndexingVariable(m_varX);
12042 :
12043 24 : m_varY = GDALMDArrayRegularlySpaced::Create(
12044 16 : "/", poYDim->GetName(), poYDim, gt.yorig, gt.yscale, 0.5);
12045 8 : poYDim->SetIndexingVariable(m_varY);
12046 : }
12047 17 : if (bBandYX)
12048 : {
12049 96 : m_dims = {std::move(poBandDim), std::move(poYDim),
12050 80 : std::move(poXDim)};
12051 : }
12052 : else
12053 : {
12054 1 : m_iYDim = 0;
12055 1 : m_iXDim = 1;
12056 1 : m_iBandDim = 2;
12057 6 : m_dims = {std::move(poYDim), std::move(poXDim),
12058 5 : std::move(poBandDim)};
12059 : }
12060 17 : }
12061 :
12062 : bool IRead(const GUInt64 *arrayStartIdx, const size_t *count,
12063 : const GInt64 *arrayStep, const GPtrDiff_t *bufferStride,
12064 : const GDALExtendedDataType &bufferDataType,
12065 : void *pDstBuffer) const override;
12066 :
12067 1 : bool IWrite(const GUInt64 *arrayStartIdx, const size_t *count,
12068 : const GInt64 *arrayStep, const GPtrDiff_t *bufferStride,
12069 : const GDALExtendedDataType &bufferDataType,
12070 : const void *pSrcBuffer) override
12071 : {
12072 1 : return ReadWrite(GF_Write, arrayStartIdx, count, arrayStep,
12073 : bufferStride, bufferDataType,
12074 1 : const_cast<void *>(pSrcBuffer));
12075 : }
12076 :
12077 : public:
12078 34 : ~GDALMDArrayFromDataset() override
12079 17 : {
12080 17 : m_poDS->ReleaseRef();
12081 34 : }
12082 :
12083 17 : static std::shared_ptr<GDALMDArray> Create(GDALDataset *poDS,
12084 : CSLConstList papszOptions)
12085 : {
12086 : auto array(std::shared_ptr<GDALMDArrayFromDataset>(
12087 34 : new GDALMDArrayFromDataset(poDS, papszOptions)));
12088 17 : array->SetSelf(array);
12089 34 : return array;
12090 : }
12091 :
12092 2 : bool IsWritable() const override
12093 : {
12094 2 : return m_poDS->GetAccess() == GA_Update;
12095 : }
12096 :
12097 15 : const std::string &GetFilename() const override
12098 : {
12099 15 : return m_osFilename;
12100 : }
12101 :
12102 : const std::vector<std::shared_ptr<GDALDimension>> &
12103 102 : GetDimensions() const override
12104 : {
12105 102 : return m_dims;
12106 : }
12107 :
12108 38 : const GDALExtendedDataType &GetDataType() const override
12109 : {
12110 38 : return m_dt;
12111 : }
12112 :
12113 5 : const std::string &GetUnit() const override
12114 : {
12115 5 : return m_osUnit;
12116 : }
12117 :
12118 5 : const void *GetRawNoDataValue() const override
12119 : {
12120 5 : return m_abyNoData.empty() ? nullptr : m_abyNoData.data();
12121 : }
12122 :
12123 5 : double GetOffset(bool *pbHasOffset,
12124 : GDALDataType *peStorageType) const override
12125 : {
12126 5 : double dfRes = 0;
12127 5 : int bHasOffset = false;
12128 5 : auto poFirstBand = m_poDS->GetRasterBand(1);
12129 5 : if (poFirstBand) // to avoid -Wnull-dereference
12130 : {
12131 5 : dfRes = poFirstBand->GetOffset(&bHasOffset);
12132 7 : for (int i = 2; bHasOffset && i <= m_poDS->GetRasterCount(); ++i)
12133 : {
12134 : const double dfOtherRes =
12135 2 : m_poDS->GetRasterBand(i)->GetOffset(&bHasOffset);
12136 2 : bHasOffset = bHasOffset && (dfOtherRes == dfRes);
12137 : }
12138 : }
12139 5 : if (pbHasOffset)
12140 5 : *pbHasOffset = CPL_TO_BOOL(bHasOffset);
12141 5 : if (peStorageType)
12142 3 : *peStorageType = GDT_Unknown;
12143 5 : return dfRes;
12144 : }
12145 :
12146 5 : double GetScale(bool *pbHasScale,
12147 : GDALDataType *peStorageType) const override
12148 : {
12149 5 : double dfRes = 0;
12150 5 : int bHasScale = false;
12151 5 : auto poFirstBand = m_poDS->GetRasterBand(1);
12152 5 : if (poFirstBand) // to avoid -Wnull-dereference
12153 : {
12154 5 : dfRes = poFirstBand->GetScale(&bHasScale);
12155 7 : for (int i = 2; bHasScale && i <= m_poDS->GetRasterCount(); ++i)
12156 : {
12157 : const double dfOtherRes =
12158 2 : m_poDS->GetRasterBand(i)->GetScale(&bHasScale);
12159 2 : bHasScale = bHasScale && (dfOtherRes == dfRes);
12160 : }
12161 : }
12162 5 : if (pbHasScale)
12163 5 : *pbHasScale = CPL_TO_BOOL(bHasScale);
12164 5 : if (peStorageType)
12165 3 : *peStorageType = GDT_Unknown;
12166 5 : return dfRes;
12167 : }
12168 :
12169 9 : std::shared_ptr<OGRSpatialReference> GetSpatialRef() const override
12170 : {
12171 9 : auto poSrcSRS = m_poDS->GetSpatialRef();
12172 9 : if (!poSrcSRS)
12173 1 : return nullptr;
12174 16 : auto poSRS = std::shared_ptr<OGRSpatialReference>(poSrcSRS->Clone());
12175 :
12176 16 : auto axisMapping = poSRS->GetDataAxisToSRSAxisMapping();
12177 24 : for (auto &m : axisMapping)
12178 : {
12179 16 : if (m == 1)
12180 8 : m = m_iXDim + 1;
12181 8 : else if (m == 2)
12182 8 : m = m_iYDim + 1;
12183 : else
12184 0 : m = 0;
12185 : }
12186 8 : poSRS->SetDataAxisToSRSAxisMapping(axisMapping);
12187 8 : return poSRS;
12188 : }
12189 :
12190 7 : std::vector<GUInt64> GetBlockSize() const override
12191 : {
12192 7 : int nBlockXSize = 0;
12193 7 : int nBlockYSize = 0;
12194 7 : m_poDS->GetRasterBand(1)->GetBlockSize(&nBlockXSize, &nBlockYSize);
12195 7 : if (m_iBandDim == 0)
12196 : {
12197 6 : return std::vector<GUInt64>{1, static_cast<GUInt64>(nBlockYSize),
12198 6 : static_cast<GUInt64>(nBlockXSize)};
12199 : }
12200 : else
12201 : {
12202 1 : return std::vector<GUInt64>{static_cast<GUInt64>(nBlockYSize),
12203 1 : static_cast<GUInt64>(nBlockXSize), 1};
12204 : }
12205 : }
12206 :
12207 : std::vector<std::shared_ptr<GDALAttribute>>
12208 7 : GetAttributes(CSLConstList) const override
12209 : {
12210 7 : std::vector<std::shared_ptr<GDALAttribute>> res;
12211 7 : auto papszMD = m_poDS->GetMetadata();
12212 14 : for (auto iter = papszMD; iter && iter[0]; ++iter)
12213 : {
12214 7 : char *pszKey = nullptr;
12215 7 : const char *pszValue = CPLParseNameValue(*iter, &pszKey);
12216 7 : if (pszKey && pszValue)
12217 : {
12218 : res.emplace_back(
12219 7 : std::make_shared<GDALMDIAsAttribute>(pszKey, pszValue));
12220 : }
12221 7 : CPLFree(pszKey);
12222 : }
12223 7 : return res;
12224 : }
12225 :
12226 6 : int GetOverviewCount() const override
12227 : {
12228 6 : int nOvrCount = 0;
12229 6 : GDALDataset *poOvrDS = nullptr;
12230 6 : bool bOK = true;
12231 12 : for (int i = 1; bOK && i <= m_poDS->GetRasterCount(); ++i)
12232 : {
12233 6 : auto poBand = m_poDS->GetRasterBand(i);
12234 6 : const int nThisOvrCount = poBand->GetOverviewCount();
12235 6 : bOK = (nThisOvrCount > 0 && (i == 1 || nThisOvrCount == nOvrCount));
12236 6 : if (bOK)
12237 : {
12238 6 : nOvrCount = nThisOvrCount;
12239 6 : auto poFirstOvrBand = poBand->GetOverview(0);
12240 6 : bOK = poFirstOvrBand != nullptr;
12241 6 : if (bOK)
12242 : {
12243 6 : auto poThisOvrDS = poFirstOvrBand->GetDataset();
12244 12 : bOK = poThisOvrDS != nullptr &&
12245 6 : poThisOvrDS->GetRasterBand(i) == poFirstOvrBand &&
12246 0 : (i == 1 || poThisOvrDS == poOvrDS);
12247 6 : if (bOK)
12248 6 : poOvrDS = poThisOvrDS;
12249 : }
12250 : }
12251 : }
12252 6 : return bOK ? nOvrCount : 0;
12253 : }
12254 :
12255 5 : std::shared_ptr<GDALMDArray> GetOverview(int idx) const override
12256 : {
12257 5 : const int nOverviews = GetOverviewCount();
12258 5 : if (idx < 0 || idx >= nOverviews)
12259 2 : return nullptr;
12260 3 : m_apoOverviews.resize(nOverviews);
12261 3 : if (!m_apoOverviews[idx])
12262 : {
12263 1 : if (auto poBand = m_poDS->GetRasterBand(1))
12264 : {
12265 1 : if (auto poOvrBand = poBand->GetOverview(idx))
12266 : {
12267 1 : if (auto poOvrDS = poOvrBand->GetDataset())
12268 : {
12269 1 : m_apoOverviews[idx] =
12270 2 : Create(poOvrDS, m_aosOptions.List());
12271 : }
12272 : }
12273 : }
12274 : }
12275 3 : return m_apoOverviews[idx];
12276 : }
12277 : };
12278 :
12279 10 : bool GDALMDArrayFromDataset::IRead(const GUInt64 *arrayStartIdx,
12280 : const size_t *count, const GInt64 *arrayStep,
12281 : const GPtrDiff_t *bufferStride,
12282 : const GDALExtendedDataType &bufferDataType,
12283 : void *pDstBuffer) const
12284 : {
12285 10 : return ReadWrite(GF_Read, arrayStartIdx, count, arrayStep, bufferStride,
12286 10 : bufferDataType, pDstBuffer);
12287 : }
12288 :
12289 : /************************************************************************/
12290 : /* ReadWrite() */
12291 : /************************************************************************/
12292 :
12293 11 : bool GDALMDArrayFromDataset::ReadWrite(
12294 : GDALRWFlag eRWFlag, const GUInt64 *arrayStartIdx, const size_t *count,
12295 : const GInt64 *arrayStep, const GPtrDiff_t *bufferStride,
12296 : const GDALExtendedDataType &bufferDataType, void *pBuffer) const
12297 : {
12298 11 : const auto eDT(bufferDataType.GetNumericDataType());
12299 11 : const auto nDTSize(GDALGetDataTypeSizeBytes(eDT));
12300 11 : const int nX =
12301 11 : arrayStep[m_iXDim] > 0
12302 11 : ? static_cast<int>(arrayStartIdx[m_iXDim])
12303 0 : : static_cast<int>(arrayStartIdx[m_iXDim] -
12304 0 : (count[m_iXDim] - 1) * -arrayStep[m_iXDim]);
12305 11 : const int nY =
12306 11 : arrayStep[m_iYDim] > 0
12307 11 : ? static_cast<int>(arrayStartIdx[m_iYDim])
12308 1 : : static_cast<int>(arrayStartIdx[m_iYDim] -
12309 1 : (count[m_iYDim] - 1) * -arrayStep[m_iYDim]);
12310 : const int nSizeX =
12311 11 : static_cast<int>(count[m_iXDim] * std::abs(arrayStep[m_iXDim]));
12312 : const int nSizeY =
12313 11 : static_cast<int>(count[m_iYDim] * std::abs(arrayStep[m_iYDim]));
12314 11 : GByte *pabyBuffer = static_cast<GByte *>(pBuffer);
12315 11 : int nStrideXSign = 1;
12316 11 : if (arrayStep[m_iXDim] < 0)
12317 : {
12318 0 : pabyBuffer += (count[m_iXDim] - 1) * bufferStride[m_iXDim] * nDTSize;
12319 0 : nStrideXSign = -1;
12320 : }
12321 11 : int nStrideYSign = 1;
12322 11 : if (arrayStep[m_iYDim] < 0)
12323 : {
12324 1 : pabyBuffer += (count[m_iYDim] - 1) * bufferStride[m_iYDim] * nDTSize;
12325 1 : nStrideYSign = -1;
12326 : }
12327 11 : const GSpacing nPixelSpace =
12328 11 : static_cast<GSpacing>(nStrideXSign * bufferStride[m_iXDim] * nDTSize);
12329 11 : const GSpacing nLineSpace =
12330 11 : static_cast<GSpacing>(nStrideYSign * bufferStride[m_iYDim] * nDTSize);
12331 11 : const GSpacing nBandSpace =
12332 11 : static_cast<GSpacing>(bufferStride[m_iBandDim] * nDTSize);
12333 11 : std::vector<int> anBandList;
12334 28 : for (int i = 0; i < static_cast<int>(count[m_iBandDim]); ++i)
12335 17 : anBandList.push_back(1 + static_cast<int>(arrayStartIdx[m_iBandDim]) +
12336 17 : i * static_cast<int>(arrayStep[m_iBandDim]));
12337 :
12338 33 : return m_poDS->RasterIO(eRWFlag, nX, nY, nSizeX, nSizeY, pabyBuffer,
12339 11 : static_cast<int>(count[m_iXDim]),
12340 11 : static_cast<int>(count[m_iYDim]), eDT,
12341 11 : static_cast<int>(count[m_iBandDim]),
12342 11 : anBandList.data(), nPixelSpace, nLineSpace,
12343 22 : nBandSpace, nullptr) == CE_None;
12344 : }
12345 :
12346 : /************************************************************************/
12347 : /* AsMDArray() */
12348 : /************************************************************************/
12349 :
12350 : /** Return a view of this dataset as a 3D multidimensional GDALMDArray.
12351 : *
12352 : * If this dataset is not already marked as shared, it will be, so that the
12353 : * returned array holds a reference to it.
12354 : *
12355 : * If the dataset has a geotransform attached, the X and Y dimensions of the
12356 : * returned array will have an associated indexing variable.
12357 : *
12358 : * The currently supported list of options is:
12359 : * <ul>
12360 : * <li>DIM_ORDER=<order> where order can be "AUTO", "Band,Y,X" or "Y,X,Band".
12361 : * "Band,Y,X" means that the first (slowest changing) dimension is Band
12362 : * and the last (fastest changing direction) is X
12363 : * "Y,X,Band" means that the first (slowest changing) dimension is Y
12364 : * and the last (fastest changing direction) is Band.
12365 : * "AUTO" (the default) selects "Band,Y,X" for single band datasets, or takes
12366 : * into account the INTERLEAVE metadata item in the IMAGE_STRUCTURE domain.
12367 : * If it equals BAND, then "Band,Y,X" is used. Otherwise (if it equals PIXEL),
12368 : * "Y,X,Band" is use.
12369 : * </li>
12370 : * <li>BAND_INDEXING_VAR_ITEM={Description}|{None}|{Index}|{ColorInterpretation}|<BandMetadataItem>:
12371 : * item from which to build the band indexing variable.
12372 : * <ul>
12373 : * <li>"{Description}", the default, means to use the band description (or "Band index" if empty).</li>
12374 : * <li>"{None}" means that no band indexing variable must be created.</li>
12375 : * <li>"{Index}" means that the band index (starting at one) is used.</li>
12376 : * <li>"{ColorInterpretation}" means that the band color interpretation is used (i.e. "Red", "Green", "Blue").</li>
12377 : * <li><BandMetadataItem> is the name of a band metadata item to use.</li>
12378 : * </ul>
12379 : * </li>
12380 : * <li>BAND_INDEXING_VAR_TYPE=String|Real|Integer: the data type of the band
12381 : * indexing variable, when BAND_INDEXING_VAR_ITEM corresponds to a band metadata item.
12382 : * Defaults to String.
12383 : * </li>
12384 : * <li>BAND_DIM_NAME=<string>: Name of the band dimension.
12385 : * Defaults to "Band".
12386 : * </li>
12387 : * <li>X_DIM_NAME=<string>: Name of the X dimension. Defaults to "X".
12388 : * </li>
12389 : * <li>Y_DIM_NAME=<string>: Name of the Y dimension. Defaults to "Y".
12390 : * </li>
12391 : * </ul>
12392 : *
12393 : * This is the same as the C function GDALDatasetAsMDArray().
12394 : *
12395 : * The "reverse" method is GDALMDArray::AsClassicDataset().
12396 : *
12397 : * @param papszOptions Null-terminated list of strings, or nullptr.
12398 : * @return a new array, or nullptr.
12399 : *
12400 : * @since GDAL 3.12
12401 : */
12402 19 : std::shared_ptr<GDALMDArray> GDALDataset::AsMDArray(CSLConstList papszOptions)
12403 : {
12404 19 : if (!GetShared())
12405 : {
12406 18 : MarkAsShared();
12407 : }
12408 19 : if (nBands == 0 || nRasterXSize == 0 || nRasterYSize == 0)
12409 : {
12410 1 : ReportError(
12411 : CE_Failure, CPLE_AppDefined,
12412 : "Degenerated array (band, Y and/or X dimension of size zero)");
12413 1 : return nullptr;
12414 : }
12415 18 : const GDALDataType eDT = papoBands[0]->GetRasterDataType();
12416 31 : for (int i = 1; i < nBands; ++i)
12417 : {
12418 14 : if (eDT != papoBands[i]->GetRasterDataType())
12419 : {
12420 1 : ReportError(CE_Failure, CPLE_AppDefined,
12421 : "Non-uniform data type amongst bands");
12422 1 : return nullptr;
12423 : }
12424 : }
12425 : const char *pszDimOrder =
12426 17 : CSLFetchNameValueDef(papszOptions, "DIM_ORDER", "AUTO");
12427 17 : if (!EQUAL(pszDimOrder, "AUTO") && !EQUAL(pszDimOrder, "Band,Y,X") &&
12428 2 : !EQUAL(pszDimOrder, "Y,X,Band"))
12429 : {
12430 1 : ReportError(CE_Failure, CPLE_IllegalArg,
12431 : "Illegal value for DIM_ORDER option");
12432 1 : return nullptr;
12433 : }
12434 16 : return GDALMDArrayFromDataset::Create(this, papszOptions);
12435 : }
12436 :
12437 : /************************************************************************/
12438 : /* GDALDataset::GetInterBandCovarianceMatrix() */
12439 : /************************************************************************/
12440 :
12441 : /**
12442 : \brief Fetch or compute the covariance matrix between bands of this dataset.
12443 :
12444 : The covariance indicates the level to which two bands vary together.
12445 :
12446 : If we call \f$ v_i[y,x] \f$ the value of pixel at row=y and column=x for band i,
12447 : and \f$ mean_i \f$ the mean value of all pixels of band i, then
12448 :
12449 : \f[
12450 : \mathrm{cov}[i,j] =
12451 : \frac{
12452 : \sum_{y,x} \left( v_i[y,x] - \mathrm{mean}_i \right)
12453 : \left( v_j[y,x] - \mathrm{mean}_j \right)
12454 : }{
12455 : \mathrm{pixel\_count} - \mathrm{nDeltaDegreeOfFreedom}
12456 : }
12457 : \f]
12458 :
12459 : When there are no nodata values, \f$ pixel\_count = GetRasterXSize() * GetRasterYSize() \f$.
12460 : We can see that \f$ cov[i,j] = cov[j,i] \f$, and consequently the returned matrix
12461 : is symmetric.
12462 :
12463 : A value of nDeltaDegreeOfFreedom=1 (the default) will return a unbiased estimate
12464 : if the pixels in bands are considered to be a sample of the whole population.
12465 : This is consistent with the default of
12466 : https://numpy.org/doc/stable/reference/generated/numpy.cov.html and the returned
12467 : matrix is consistent with what can be obtained with
12468 :
12469 : \verbatim embed:rst
12470 : .. code-block:: python
12471 :
12472 : numpy.cov(
12473 : [ds.GetRasterBand(n + 1).ReadAsArray().ravel() for n in range(ds.RasterCount)]
12474 : )
12475 : \endverbatim
12476 :
12477 : Otherwise a value of nDeltaDegreeOfFreedom=0 can be used if they are considered
12478 : to be the whole population.
12479 :
12480 : If STATISTICS_COVARIANCES metadata items are available in band metadata,
12481 : this method uses them.
12482 : Otherwise, if bForce is true, ComputeInterBandCovarianceMatrix() is called.
12483 : Otherwise, if bForce is false, an empty vector is returned
12484 :
12485 : @param nBandCount Zero for all bands, or number of values in panBandList.
12486 : Defaults to 0.
12487 : @param panBandList nullptr for all bands if nBandCount == 0, or array of
12488 : nBandCount values such as panBandList[i] is the index
12489 : between 1 and GetRasterCount() of a band that must be used
12490 : in the covariance computation. Defaults to nullptr.
12491 : @param bApproxOK Whether it is acceptable to use a subsample of values in
12492 : ComputeInterBandCovarianceMatrix().
12493 : Defaults to false.
12494 : @param bForce Whether ComputeInterBandCovarianceMatrix() should be called
12495 : when the STATISTICS_COVARIANCES metadata items are missing.
12496 : Defaults to false.
12497 : @param bWriteIntoMetadata Whether ComputeInterBandCovarianceMatrix() must
12498 : write STATISTICS_COVARIANCES band metadata items.
12499 : Defaults to true.
12500 : @param nDeltaDegreeOfFreedom Correction term to subtract in the final
12501 : averaging phase of the covariance computation.
12502 : Defaults to 1.
12503 : @param pfnProgress a function to call to report progress, or NULL.
12504 : @param pProgressData application data to pass to the progress function.
12505 :
12506 : @return a vector of nBandCount * nBandCount values if successful,
12507 : in row-major order, or an empty vector in case of failure
12508 :
12509 : @since 3.13
12510 :
12511 : @see ComputeInterBandCovarianceMatrix()
12512 : */
12513 :
12514 0 : std::vector<double> GDALDataset::GetInterBandCovarianceMatrix(
12515 : int nBandCount, const int *panBandList, bool bApproxOK, bool bForce,
12516 : bool bWriteIntoMetadata, int nDeltaDegreeOfFreedom,
12517 : GDALProgressFunc pfnProgress, void *pProgressData)
12518 : {
12519 0 : std::vector<double> res;
12520 0 : const int nBandCountToUse = nBandCount == 0 ? nBands : nBandCount;
12521 0 : if (nBandCountToUse == 0)
12522 0 : return res;
12523 : if constexpr (sizeof(size_t) < sizeof(uint64_t))
12524 : {
12525 : // Check that nBandCountToUse * nBandCountToUse will not overflow size_t
12526 : if (static_cast<uint32_t>(nBandCountToUse) >
12527 : std::numeric_limits<uint16_t>::max())
12528 : {
12529 : CPLError(CE_Failure, CPLE_OutOfMemory,
12530 : "Not enough memory to store result");
12531 : return res;
12532 : }
12533 : }
12534 : try
12535 : {
12536 0 : res.resize(static_cast<size_t>(nBandCountToUse) * nBandCountToUse);
12537 : }
12538 0 : catch (const std::exception &)
12539 : {
12540 0 : CPLError(CE_Failure, CPLE_OutOfMemory,
12541 : "Not enough memory to store result");
12542 0 : return res;
12543 : }
12544 :
12545 0 : if (GetInterBandCovarianceMatrix(res.data(), res.size(), nBandCount,
12546 : panBandList, bApproxOK, bForce,
12547 : bWriteIntoMetadata, nDeltaDegreeOfFreedom,
12548 0 : pfnProgress, pProgressData) != CE_None)
12549 : {
12550 0 : res.clear();
12551 : }
12552 0 : return res;
12553 : }
12554 :
12555 : /************************************************************************/
12556 : /* GDALDataset::GetInterBandCovarianceMatrix() */
12557 : /************************************************************************/
12558 :
12559 : /**
12560 : \brief Fetch or compute the covariance matrix between bands of this dataset.
12561 :
12562 : The covariance indicates the level to which two bands vary together.
12563 :
12564 : If we call \f$ v_i[y,x] \f$ the value of pixel at row=y and column=x for band i,
12565 : and \f$ mean_i \f$ the mean value of all pixels of band i, then
12566 :
12567 : \f[
12568 : \mathrm{cov}[i,j] =
12569 : \frac{
12570 : \sum_{y,x} \left( v_i[y,x] - \mathrm{mean}_i \right)
12571 : \left( v_j[y,x] - \mathrm{mean}_j \right)
12572 : }{
12573 : \mathrm{pixel\_count} - \mathrm{nDeltaDegreeOfFreedom}
12574 : }
12575 : \f]
12576 :
12577 : When there are no nodata values, \f$ pixel\_count = GetRasterXSize() * GetRasterYSize() \f$.
12578 : We can see that \f$ cov[i,j] = cov[j,i] \f$, and consequently the returned matrix
12579 : is symmetric.
12580 :
12581 : A value of nDeltaDegreeOfFreedom=1 (the default) will return a unbiased estimate
12582 : if the pixels in bands are considered to be a sample of the whole population.
12583 : This is consistent with the default of
12584 : https://numpy.org/doc/stable/reference/generated/numpy.cov.html and the returned
12585 : matrix is consistent with what can be obtained with
12586 :
12587 : \verbatim embed:rst
12588 : .. code-block:: python
12589 :
12590 : numpy.cov(
12591 : [ds.GetRasterBand(n + 1).ReadAsArray().ravel() for n in range(ds.RasterCount)]
12592 : )
12593 : \endverbatim
12594 :
12595 : Otherwise a value of nDeltaDegreeOfFreedom=0 can be used if they are considered
12596 : to be the whole population.
12597 :
12598 : The caller must provide an already allocated array in padfCovMatrix of size
12599 : at least nBandCount * nBandCount.
12600 :
12601 : If STATISTICS_COVARIANCES metadata items are available in band metadata,
12602 : this method uses them.
12603 : Otherwise, if bForce is true, ComputeInterBandCovarianceMatrix() is called.
12604 : Otherwise, if bForce is false, an empty vector is returned
12605 :
12606 : This is the same as the C function GDALDatasetGetInterBandCovarianceMatrix()
12607 :
12608 : @param[out] padfCovMatrix Pointer to an already allocated output array, of size at least
12609 : nBandCount * nBandCount.
12610 : @param nSize Number of elements in output array.
12611 : @param nBandCount Zero for all bands, or number of values in panBandList.
12612 : Defaults to 0.
12613 : @param panBandList nullptr for all bands if nBandCount == 0, or array of
12614 : nBandCount values such as panBandList[i] is the index
12615 : between 1 and GetRasterCount() of a band that must be used
12616 : in the covariance computation. Defaults to nullptr.
12617 : @param bApproxOK Whether it is acceptable to use a subsample of values in
12618 : ComputeInterBandCovarianceMatrix().
12619 : Defaults to false.
12620 : @param bForce Whether ComputeInterBandCovarianceMatrix() should be called
12621 : when the STATISTICS_COVARIANCES metadata items are missing.
12622 : Defaults to false.
12623 : @param bWriteIntoMetadata Whether ComputeInterBandCovarianceMatrix() must
12624 : write STATISTICS_COVARIANCES band metadata items.
12625 : Defaults to true.
12626 : @param nDeltaDegreeOfFreedom Correction term to subtract in the final
12627 : averaging phase of the covariance computation.
12628 : Defaults to 1.
12629 : @param pfnProgress a function to call to report progress, or NULL.
12630 : @param pProgressData application data to pass to the progress function.
12631 :
12632 : @return CE_None if successful, CE_Warning if values are not available in
12633 : metadata and bForce is false, or CE_Failure in case of failure
12634 :
12635 : @since 3.13
12636 :
12637 : @see ComputeInterBandCovarianceMatrix()
12638 : */
12639 :
12640 11 : CPLErr GDALDataset::GetInterBandCovarianceMatrix(
12641 : double *padfCovMatrix, size_t nSize, int nBandCount, const int *panBandList,
12642 : bool bApproxOK, bool bForce, bool bWriteIntoMetadata,
12643 : int nDeltaDegreeOfFreedom, GDALProgressFunc pfnProgress,
12644 : void *pProgressData)
12645 : {
12646 22 : std::vector<int> anBandListTmp; // keep in this scope
12647 11 : if (nBandCount == 0)
12648 : {
12649 0 : if (nBands == 0)
12650 0 : return CE_None;
12651 0 : for (int i = 0; i < nBands; ++i)
12652 0 : anBandListTmp.push_back(i + 1);
12653 0 : nBandCount = nBands;
12654 0 : panBandList = anBandListTmp.data();
12655 : }
12656 : else
12657 : {
12658 11 : if (nBandCount > nBands)
12659 : {
12660 1 : CPLError(CE_Failure, CPLE_AppDefined,
12661 : "GetInterBandCovarianceMatrix(): nBandCount > nBands");
12662 1 : return CE_Failure;
12663 : }
12664 29 : for (int i = 0; i < nBandCount; ++i)
12665 : {
12666 21 : if (panBandList[i] <= 0 || panBandList[i] > nBands)
12667 : {
12668 2 : CPLError(CE_Failure, CPLE_AppDefined,
12669 : "GetInterBandCovarianceMatrix(): invalid value "
12670 : "panBandList[%d] = %d",
12671 2 : i, panBandList[i]);
12672 2 : return CE_Failure;
12673 : }
12674 : }
12675 : }
12676 :
12677 8 : if (nSize < static_cast<uint64_t>(nBandCount) * nBandCount)
12678 : {
12679 0 : CPLError(
12680 : CE_Failure, CPLE_AppDefined,
12681 : "GetInterBandCovarianceMatrix(): too small result matrix provided");
12682 0 : return CE_Failure;
12683 : }
12684 8 : bool bGotFromMD = true;
12685 8 : size_t resIdx = 0;
12686 20 : for (int i = 0; bGotFromMD && i < nBandCount; ++i)
12687 : {
12688 24 : const char *pszCov = papoBands[panBandList[i] - 1]->GetMetadataItem(
12689 12 : "STATISTICS_COVARIANCES");
12690 12 : bGotFromMD = pszCov != nullptr;
12691 12 : if (bGotFromMD)
12692 : {
12693 12 : const CPLStringList aosTokens(CSLTokenizeString2(pszCov, ",", 0));
12694 6 : bGotFromMD = aosTokens.size() == nBands;
12695 6 : if (bGotFromMD)
12696 : {
12697 24 : for (int j = 0; j < nBandCount; ++j)
12698 18 : padfCovMatrix[resIdx++] =
12699 18 : CPLAtof(aosTokens[panBandList[j] - 1]);
12700 : }
12701 : }
12702 : }
12703 8 : if (bGotFromMD)
12704 2 : return CE_None;
12705 :
12706 6 : if (!bForce)
12707 1 : return CE_Warning;
12708 5 : return ComputeInterBandCovarianceMatrix(
12709 : padfCovMatrix, nSize, nBandCount, panBandList, bApproxOK,
12710 5 : bWriteIntoMetadata, nDeltaDegreeOfFreedom, pfnProgress, pProgressData);
12711 : }
12712 :
12713 : /************************************************************************/
12714 : /* GDALDatasetGetInterBandCovarianceMatrix() */
12715 : /************************************************************************/
12716 :
12717 : /**
12718 : \brief Fetch or compute the covariance matrix between bands of this dataset.
12719 :
12720 : The covariance indicates the level to which two bands vary together.
12721 :
12722 : If we call \f$ v_i[y,x] \f$ the value of pixel at row=y and column=x for band i,
12723 : and \f$ mean_i \f$ the mean value of all pixels of band i, then
12724 :
12725 : \f[
12726 : \mathrm{cov}[i,j] =
12727 : \frac{
12728 : \sum_{y,x} \left( v_i[y,x] - \mathrm{mean}_i \right)
12729 : \left( v_j[y,x] - \mathrm{mean}_j \right)
12730 : }{
12731 : \mathrm{pixel\_count} - \mathrm{nDeltaDegreeOfFreedom}
12732 : }
12733 : \f]
12734 :
12735 : When there are no nodata values, \f$ pixel\_count = GetRasterXSize() * GetRasterYSize() \f$.
12736 : We can see that \f$ cov[i,j] = cov[j,i] \f$, and consequently the returned matrix
12737 : is symmetric.
12738 :
12739 : A value of nDeltaDegreeOfFreedom=1 (the default) will return a unbiased estimate
12740 : if the pixels in bands are considered to be a sample of the whole population.
12741 : This is consistent with the default of
12742 : https://numpy.org/doc/stable/reference/generated/numpy.cov.html and the returned
12743 : matrix is consistent with what can be obtained with
12744 :
12745 : \verbatim embed:rst
12746 : .. code-block:: python
12747 :
12748 : numpy.cov(
12749 : [ds.GetRasterBand(n + 1).ReadAsArray().ravel() for n in range(ds.RasterCount)]
12750 : )
12751 : \endverbatim
12752 :
12753 : Otherwise a value of nDeltaDegreeOfFreedom=0 can be used if they are considered
12754 : to be the whole population.
12755 :
12756 : The caller must provide an already allocated array in padfCovMatrix of size
12757 : at least nBandCount * nBandCount.
12758 :
12759 : If STATISTICS_COVARIANCES metadata items are available in band metadata,
12760 : this method uses them.
12761 : Otherwise, if bForce is true, GDALDatasetComputeInterBandCovarianceMatrix() is called.
12762 : Otherwise, if bForce is false, an empty vector is returned
12763 :
12764 : This is the same as the C++ method GDALDataset::GetInterBandCovarianceMatrix()
12765 :
12766 : @param hDS Dataset handle.
12767 : @param[out] padfCovMatrix Pointer to an already allocated output array, of size at least
12768 : nBandCount * nBandCount.
12769 : @param nSize Number of elements in output array.
12770 : @param nBandCount Zero for all bands, or number of values in panBandList.
12771 : Defaults to 0.
12772 : @param panBandList nullptr for all bands if nBandCount == 0, or array of
12773 : nBandCount values such as panBandList[i] is the index
12774 : between 1 and GetRasterCount() of a band that must be used
12775 : in the covariance computation. Defaults to nullptr.
12776 : @param bApproxOK Whether it is acceptable to use a subsample of values in
12777 : GDALDatasetComputeInterBandCovarianceMatrix().
12778 : Defaults to false.
12779 : @param bForce Whether GDALDatasetComputeInterBandCovarianceMatrix() should be called
12780 : when the STATISTICS_COVARIANCES metadata items are missing.
12781 : Defaults to false.
12782 : @param bWriteIntoMetadata Whether GDALDatasetComputeInterBandCovarianceMatrix() must
12783 : write STATISTICS_COVARIANCES band metadata items.
12784 : Defaults to true.
12785 : @param nDeltaDegreeOfFreedom Correction term to subtract in the final
12786 : averaging phase of the covariance computation.
12787 : Defaults to 1.
12788 : @param pfnProgress a function to call to report progress, or NULL.
12789 : @param pProgressData application data to pass to the progress function.
12790 :
12791 : @return CE_None if successful, CE_Warning if values are not available in
12792 : metadata and bForce is false, or CE_Failure in case of failure
12793 :
12794 : @since 3.13
12795 :
12796 : @see GDALDatasetComputeInterBandCovarianceMatrix()
12797 : */
12798 11 : CPLErr GDALDatasetGetInterBandCovarianceMatrix(
12799 : GDALDatasetH hDS, double *padfCovMatrix, size_t nSize, int nBandCount,
12800 : const int *panBandList, bool bApproxOK, bool bForce,
12801 : bool bWriteIntoMetadata, int nDeltaDegreeOfFreedom,
12802 : GDALProgressFunc pfnProgress, void *pProgressData)
12803 : {
12804 11 : VALIDATE_POINTER1(hDS, __func__, CE_Failure);
12805 11 : VALIDATE_POINTER1(padfCovMatrix, __func__, CE_Failure);
12806 11 : return GDALDataset::FromHandle(hDS)->GetInterBandCovarianceMatrix(
12807 : padfCovMatrix, nSize, nBandCount, panBandList, bApproxOK, bForce,
12808 11 : bWriteIntoMetadata, nDeltaDegreeOfFreedom, pfnProgress, pProgressData);
12809 : }
12810 :
12811 : /************************************************************************/
12812 : /* GDALDataset::ComputeInterBandCovarianceMatrix() */
12813 : /************************************************************************/
12814 :
12815 : /**
12816 : \brief Compute the covariance matrix between bands of this dataset.
12817 :
12818 : The covariance indicates the level to which two bands vary together.
12819 :
12820 : If we call \f$ v_i[y,x] \f$ the value of pixel at row=y and column=x for band i,
12821 : and \f$ mean_i \f$ the mean value of all pixels of band i, then
12822 :
12823 : \f[
12824 : \mathrm{cov}[i,j] =
12825 : \frac{
12826 : \sum_{y,x} \left( v_i[y,x] - \mathrm{mean}_i \right)
12827 : \left( v_j[y,x] - \mathrm{mean}_j \right)
12828 : }{
12829 : \mathrm{pixel\_count} - \mathrm{nDeltaDegreeOfFreedom}
12830 : }
12831 : \f]
12832 :
12833 : When there are no nodata values, \f$ pixel\_count = GetRasterXSize() * GetRasterYSize() \f$.
12834 : We can see that \f$ cov[i,j] = cov[j,i] \f$, and consequently the returned matrix
12835 : is symmetric.
12836 :
12837 : A value of nDeltaDegreeOfFreedom=1 (the default) will return a unbiased estimate
12838 : if the pixels in bands are considered to be a sample of the whole population.
12839 : This is consistent with the default of
12840 : https://numpy.org/doc/stable/reference/generated/numpy.cov.html and the returned
12841 : matrix is consistent with what can be obtained with
12842 :
12843 : \verbatim embed:rst
12844 : .. code-block:: python
12845 :
12846 : numpy.cov(
12847 : [ds.GetRasterBand(n + 1).ReadAsArray().ravel() for n in range(ds.RasterCount)]
12848 : )
12849 : \endverbatim
12850 :
12851 : Otherwise a value of nDeltaDegreeOfFreedom=0 can be used if they are considered
12852 : to be the whole population.
12853 :
12854 : This method recomputes the covariance matrix, even if STATISTICS_COVARIANCES
12855 : metadata items are available in bands. See GetInterBandCovarianceMatrix()
12856 : to use them.
12857 :
12858 : @param nBandCount Zero for all bands, or number of values in panBandList.
12859 : Defaults to 0.
12860 : @param panBandList nullptr for all bands if nBandCount == 0, or array of
12861 : nBandCount values such as panBandList[i] is the index
12862 : between 1 and GetRasterCount() of a band that must be used
12863 : in the covariance computation. Defaults to nullptr.
12864 : @param bApproxOK Whether it is acceptable to use a subsample of values.
12865 : Defaults to false.
12866 : @param bWriteIntoMetadata Whether this method must write
12867 : STATISTICS_COVARIANCES band metadata items.
12868 : Defaults to true.
12869 : @param nDeltaDegreeOfFreedom Correction term to subtract in the final
12870 : averaging phase of the covariance computation.
12871 : Defaults to 1.
12872 : @param pfnProgress a function to call to report progress, or NULL.
12873 : @param pProgressData application data to pass to the progress function.
12874 :
12875 : @return a vector of nBandCount * nBandCount values if successful,
12876 : in row-major order, or an empty vector in case of failure
12877 :
12878 : @since 3.13
12879 :
12880 : @see GetInterBandCovarianceMatrix()
12881 : */
12882 0 : std::vector<double> GDALDataset::ComputeInterBandCovarianceMatrix(
12883 : int nBandCount, const int *panBandList, bool bApproxOK,
12884 : bool bWriteIntoMetadata, int nDeltaDegreeOfFreedom,
12885 : GDALProgressFunc pfnProgress, void *pProgressData)
12886 : {
12887 0 : std::vector<double> res;
12888 0 : const int nBandCountToUse = nBandCount == 0 ? nBands : nBandCount;
12889 0 : if (nBandCountToUse == 0)
12890 0 : return res;
12891 : if constexpr (sizeof(size_t) < sizeof(uint64_t))
12892 : {
12893 : // Check that nBandCountToUse * nBandCountToUse will not overflow size_t
12894 : if (static_cast<uint32_t>(nBandCountToUse) >
12895 : std::numeric_limits<uint16_t>::max())
12896 : {
12897 : CPLError(CE_Failure, CPLE_OutOfMemory,
12898 : "Not enough memory to store result");
12899 : return res;
12900 : }
12901 : }
12902 : try
12903 : {
12904 0 : res.resize(static_cast<size_t>(nBandCountToUse) * nBandCountToUse);
12905 : }
12906 0 : catch (const std::exception &)
12907 : {
12908 0 : CPLError(CE_Failure, CPLE_OutOfMemory,
12909 : "Not enough memory to store result");
12910 0 : return res;
12911 : }
12912 :
12913 0 : if (ComputeInterBandCovarianceMatrix(
12914 : res.data(), res.size(), nBandCount, panBandList, bApproxOK,
12915 : bWriteIntoMetadata, nDeltaDegreeOfFreedom, pfnProgress,
12916 0 : pProgressData) != CE_None)
12917 0 : res.clear();
12918 0 : return res;
12919 : }
12920 :
12921 : /************************************************************************/
12922 : /* ComputeInterBandCovarianceMatrixInternal() */
12923 : /************************************************************************/
12924 :
12925 : template <class T>
12926 : // CPL_NOSANITIZE_UNSIGNED_INT_OVERFLOW because it seems the uses of openmp-simd
12927 : // causes that to happen
12928 : CPL_NOSANITIZE_UNSIGNED_INT_OVERFLOW static CPLErr
12929 15 : ComputeInterBandCovarianceMatrixInternal(GDALDataset *poDS,
12930 : double *padfCovMatrix, int nBandCount,
12931 : const int *panBandList,
12932 : GDALRasterBand *const *papoBands,
12933 : int nDeltaDegreeOfFreedom,
12934 : GDALProgressFunc pfnProgress,
12935 : void *pProgressData)
12936 : {
12937 : // We use the padfCovMatrix to accumulate co-moments
12938 : // Dimension = nBandCount * nBandCount
12939 15 : double *const padfComomentMatrix = padfCovMatrix;
12940 :
12941 : // Matrix of nBandCount * nBandCount storing co-moments, in optimized
12942 : // case when the block has no nodata value
12943 : // Only used if T != double
12944 30 : [[maybe_unused]] std::vector<T> aCurBlockComomentMatrix;
12945 :
12946 : // Count number of valid values in padfComomentMatrix for each (i,j) tuple
12947 : // Updated while iterating over blocks
12948 : // Dimension = nBandCount * nBandCount
12949 30 : std::vector<uint64_t> anCount;
12950 :
12951 : // Mean of bands, for each (i,j) tuple.
12952 : // Updated while iterating over blocks.
12953 : // This is a matrix rather than a vector due to the fact when need to update
12954 : // it in sync with padfComomentMatrix
12955 : // Dimension = nBandCount * nBandCount
12956 30 : std::vector<T> adfMean;
12957 :
12958 : // Number of valid values when computing adfMean, for each (i,j) tuple.
12959 : // Updated while iterating over blocks.
12960 : // This is a matrix rather than a vector due to the fact when need to update
12961 : // it in sync with padfComomentMatrix
12962 : // Dimension = nBandCount * nBandCount
12963 30 : std::vector<uint64_t> anCountMean;
12964 :
12965 : // Mean of values for each band i. Refreshed for each block.
12966 : // Dimension = nBandCount
12967 30 : std::vector<T> adfCurBlockMean;
12968 :
12969 : // Number of values participating to the mean for each band i.
12970 : // Refreshed for each block. Dimension = nBandCount
12971 30 : std::vector<size_t> anCurBlockCount;
12972 :
12973 : // Pixel values for all selected values for the current block
12974 : // Dimension = nBlockXSize * nBlockYSize * nBandCount
12975 30 : std::vector<T> adfCurBlockPixelsAllBands;
12976 :
12977 : // Vector of nodata values for all bands. Dimension = nBandCount
12978 30 : std::vector<T> adfNoData;
12979 :
12980 : // Vector of mask bands for all bands. Dimension = nBandCount
12981 30 : std::vector<GDALRasterBand *> apoMaskBands;
12982 :
12983 : // Vector of vector of mask values. Dimension = nBandCount
12984 30 : std::vector<std::vector<GByte>> aabyCurBlockMask;
12985 :
12986 : // Vector of pointer to vector of mask values. Dimension = nBandCount
12987 30 : std::vector<std::vector<GByte> *> pabyCurBlockMask;
12988 :
12989 15 : int nBlockXSize = 0;
12990 15 : int nBlockYSize = 0;
12991 15 : papoBands[panBandList[0] - 1]->GetBlockSize(&nBlockXSize, &nBlockYSize);
12992 :
12993 30 : if (static_cast<uint64_t>(nBlockXSize) * nBlockYSize >
12994 15 : std::numeric_limits<size_t>::max() / nBandCount)
12995 : {
12996 0 : poDS->ReportError(CE_Failure, CPLE_OutOfMemory,
12997 : "Not enough memory for intermediate computations");
12998 0 : return CE_Failure;
12999 : }
13000 15 : const size_t nPixelsInBlock =
13001 15 : static_cast<size_t>(nBlockXSize) * nBlockYSize;
13002 :
13003 : // Allocate temporary matrices and vectors
13004 15 : const auto nMatrixSize = static_cast<size_t>(nBandCount) * nBandCount;
13005 :
13006 : using MySignedSize_t = std::make_signed_t<size_t>;
13007 15 : const auto kMax =
13008 15 : static_cast<MySignedSize_t>(nBandCount) * (nBandCount + 1) / 2;
13009 30 : std::vector<std::pair<int, int>> anMapLinearIdxToIJ;
13010 : try
13011 : {
13012 15 : anCount.resize(nMatrixSize);
13013 15 : adfMean.resize(nMatrixSize);
13014 15 : anCountMean.resize(nMatrixSize);
13015 :
13016 : if constexpr (!std::is_same_v<T, double>)
13017 : {
13018 : aCurBlockComomentMatrix.resize(nMatrixSize);
13019 : }
13020 :
13021 15 : anMapLinearIdxToIJ.resize(kMax);
13022 :
13023 15 : adfCurBlockPixelsAllBands.resize(nPixelsInBlock * nBandCount);
13024 :
13025 15 : adfCurBlockMean.resize(nBandCount);
13026 15 : anCurBlockCount.resize(nBandCount);
13027 15 : adfNoData.resize(nBandCount);
13028 15 : apoMaskBands.resize(nBandCount);
13029 15 : aabyCurBlockMask.resize(nBandCount);
13030 15 : pabyCurBlockMask.resize(nBandCount);
13031 : }
13032 0 : catch (const std::exception &)
13033 : {
13034 0 : poDS->ReportError(CE_Failure, CPLE_OutOfMemory,
13035 : "Not enough memory for intermediate computations");
13036 0 : return CE_Failure;
13037 : }
13038 :
13039 15 : constexpr T ZERO{0};
13040 15 : std::fill(padfComomentMatrix,
13041 15 : padfComomentMatrix + static_cast<size_t>(nBandCount) * nBandCount,
13042 15 : 0);
13043 :
13044 : {
13045 15 : MySignedSize_t nLinearIdx = 0;
13046 1045 : for (int i = 0; i < nBandCount; ++i)
13047 : {
13048 501581 : for (int j = i; j < nBandCount; ++j)
13049 : {
13050 500551 : anMapLinearIdxToIJ[nLinearIdx] = {i, j};
13051 500551 : ++nLinearIdx;
13052 : }
13053 : }
13054 : }
13055 :
13056 : // Fetch nodata values and mask bands
13057 15 : bool bAllBandsSameMask = false;
13058 15 : bool bIsAllInteger = false;
13059 15 : bool bNoneHasMaskOrNodata = false;
13060 1045 : for (int i = 0; i < nBandCount; ++i)
13061 : {
13062 1030 : const auto poBand = papoBands[panBandList[i] - 1];
13063 2057 : bIsAllInteger = (i == 0 || bIsAllInteger) &&
13064 1027 : GDALDataTypeIsInteger(poBand->GetRasterDataType());
13065 1030 : int bHasNoData = FALSE;
13066 1030 : double dfNoData = poBand->GetNoDataValue(&bHasNoData);
13067 1030 : if (!bHasNoData)
13068 : {
13069 1028 : dfNoData = std::numeric_limits<double>::quiet_NaN();
13070 :
13071 1032 : if (poBand->GetMaskFlags() != GMF_ALL_VALID &&
13072 4 : poBand->GetColorInterpretation() != GCI_AlphaBand)
13073 : {
13074 4 : apoMaskBands[i] = poBand->GetMaskBand();
13075 : try
13076 : {
13077 4 : aabyCurBlockMask[i].resize(nPixelsInBlock);
13078 : }
13079 0 : catch (const std::exception &)
13080 : {
13081 0 : poDS->ReportError(
13082 : CE_Failure, CPLE_OutOfMemory,
13083 : "Not enough memory for intermediate computations");
13084 0 : return CE_Failure;
13085 : }
13086 : #ifndef __COVERITY__
13087 : // coverity[escape]
13088 4 : pabyCurBlockMask[i] = &aabyCurBlockMask[i];
13089 : #endif
13090 : }
13091 : }
13092 1030 : adfNoData[i] = static_cast<T>(dfNoData);
13093 1030 : if (i == 0)
13094 15 : bAllBandsSameMask = (apoMaskBands[0] != nullptr);
13095 1015 : else if (bAllBandsSameMask)
13096 2 : bAllBandsSameMask = (apoMaskBands[i] == apoMaskBands[0]);
13097 :
13098 3072 : bNoneHasMaskOrNodata = (i == 0 || bNoneHasMaskOrNodata) &&
13099 3072 : std::isnan(dfNoData) &&
13100 1026 : apoMaskBands[i] == nullptr;
13101 : }
13102 15 : if (bAllBandsSameMask)
13103 : {
13104 2 : for (int i = 1; i < nBandCount; ++i)
13105 : {
13106 1 : apoMaskBands[i] = nullptr;
13107 1 : aabyCurBlockMask[i].clear();
13108 1 : pabyCurBlockMask[i] = pabyCurBlockMask[0];
13109 : }
13110 : }
13111 :
13112 15 : const auto nIterCount =
13113 : static_cast<uint64_t>(
13114 15 : cpl::div_round_up(poDS->GetRasterXSize(), nBlockXSize)) *
13115 15 : cpl::div_round_up(poDS->GetRasterYSize(), nBlockYSize);
13116 15 : uint64_t nCurIter = 0;
13117 :
13118 15 : int nNumThreads = 1;
13119 : #ifdef HAVE_OPENMP
13120 15 : if (nBandCount >= 100)
13121 : {
13122 1 : const int nMaxNumThreads = std::max(1, CPLGetNumCPUs() / 2);
13123 : nNumThreads =
13124 1 : GDALGetNumThreads(nMaxNumThreads, /* bDefaultToAllCPUs= */ false);
13125 : }
13126 : #endif
13127 :
13128 : #ifdef CAN_DETECT_AVX2_FMA_AT_RUNTIME
13129 30 : const bool bHasAVX2_FMA = CPLHaveRuntimeAVX() &&
13130 30 : __builtin_cpu_supports("avx2") &&
13131 : __builtin_cpu_supports("fma");
13132 : #endif
13133 :
13134 : // Iterate over all blocks
13135 77 : for (const auto &window : papoBands[panBandList[0] - 1]->IterateWindows())
13136 : {
13137 32 : const auto nThisBlockPixelCount =
13138 32 : static_cast<size_t>(window.nXSize) * window.nYSize;
13139 :
13140 : // Extract pixel values and masks
13141 96 : CPLErr eErr = poDS->RasterIO(
13142 32 : GF_Read, window.nXOff, window.nYOff, window.nXSize, window.nYSize,
13143 32 : adfCurBlockPixelsAllBands.data(), window.nXSize, window.nYSize,
13144 : gdal::CXXTypeTraits<T>::gdal_type, nBandCount, panBandList, 0, 0, 0,
13145 : nullptr);
13146 32 : if (eErr == CE_None && bAllBandsSameMask)
13147 : {
13148 2 : eErr = apoMaskBands[0]->RasterIO(
13149 1 : GF_Read, window.nXOff, window.nYOff, window.nXSize,
13150 1 : window.nYSize, aabyCurBlockMask[0].data(), window.nXSize,
13151 1 : window.nYSize, GDT_Byte, 0, 0, nullptr);
13152 : }
13153 : else
13154 : {
13155 1108 : for (int i = 0; eErr == CE_None && i < nBandCount; ++i)
13156 : {
13157 1077 : if (apoMaskBands[i])
13158 : {
13159 4 : eErr = apoMaskBands[i]->RasterIO(
13160 2 : GF_Read, window.nXOff, window.nYOff, window.nXSize,
13161 2 : window.nYSize, aabyCurBlockMask[i].data(),
13162 2 : window.nXSize, window.nYSize, GDT_Byte, 0, 0, nullptr);
13163 : }
13164 : }
13165 : }
13166 32 : if (eErr != CE_None)
13167 1 : return eErr;
13168 :
13169 : // Compute the mean of all bands for this block
13170 32 : bool bAllBandsAreAllNodata = false;
13171 32 : bool bNoBandHasNodata = false;
13172 1111 : for (int i = 0; i < nBandCount; ++i)
13173 : {
13174 1079 : T dfSum = 0;
13175 1079 : size_t nCount = 0;
13176 1079 : const T dfNoDataI = adfNoData[i];
13177 1079 : const T *padfI =
13178 1079 : adfCurBlockPixelsAllBands.data() + i * nThisBlockPixelCount;
13179 : #ifdef HAVE_OPENMP_SIMD
13180 1079 : #pragma omp simd reduction(+ : dfSum)
13181 : #endif
13182 : for (size_t iPixel = 0; iPixel < nThisBlockPixelCount; ++iPixel)
13183 : {
13184 822482 : const T dfI = padfI[iPixel];
13185 822482 : const bool bIsValid =
13186 1644950 : !std::isnan(dfI) && dfI != dfNoDataI &&
13187 822466 : (!pabyCurBlockMask[i] || (*pabyCurBlockMask[i])[iPixel]);
13188 822482 : nCount += bIsValid;
13189 822482 : dfSum += bIsValid ? dfI : ZERO;
13190 : }
13191 1079 : adfCurBlockMean[i] = nCount > 0 ? dfSum / nCount : ZERO;
13192 1079 : anCurBlockCount[i] = nCount;
13193 1079 : bAllBandsAreAllNodata =
13194 1079 : (i == 0 || bAllBandsAreAllNodata) && (nCount == 0);
13195 1079 : bNoBandHasNodata = (i == 0 || bNoBandHasNodata) &&
13196 : (nCount == nThisBlockPixelCount);
13197 : }
13198 :
13199 : // Modify the pixel values to shift them by minus the mean
13200 32 : if (!bAllBandsAreAllNodata)
13201 : {
13202 1103 : for (int i = 0; i < nBandCount; ++i)
13203 : {
13204 1074 : T *padfI =
13205 1074 : adfCurBlockPixelsAllBands.data() + i * nThisBlockPixelCount;
13206 1074 : const T dfMeanI = adfCurBlockMean[i];
13207 823546 : for (size_t iPixel = 0; iPixel < nThisBlockPixelCount; ++iPixel)
13208 : {
13209 822472 : padfI[iPixel] -= dfMeanI;
13210 : }
13211 : }
13212 : }
13213 :
13214 : // Update padfComomentMatrix, anCount, adfMean, anCountMean
13215 : // from dfComoment, nCount, adfCurBlockMean, anCurBlockCount
13216 32 : const auto UpdateGlobalValues =
13217 13507600 : [&anCount, &adfMean, &anCountMean, &adfCurBlockMean,
13218 : &anCurBlockCount, padfComomentMatrix,
13219 : nBandCount](int i, int j, size_t nCount, T dfComoment)
13220 : {
13221 500647 : const auto idxInMatrixI = static_cast<size_t>(i) * nBandCount + j;
13222 500647 : const auto idxInMatrixJ = static_cast<size_t>(j) * nBandCount + i;
13223 :
13224 : // Update the total comoment using last formula of paragraph
13225 : // https://en.wikipedia.org/wiki/Algorithms_for_calculating_variance#Online :
13226 : // CoMoment(A+B) = CoMoment(A) + CoMoment(B) +
13227 : // (mean_I(A) - mean_I(B)) *
13228 : // (mean_J(A) - mean_J(B)) *
13229 : // (count(A) * count(B)) / (count(A) + count(B))
13230 : //
13231 : // There might be a small gotcha in the fact that the set of
13232 : // pixels on which the means are computed is not always the
13233 : // same as the the one on which the comoment is computed, if
13234 : // pixels are not valid/invalid at the same indices among bands
13235 : // It is not obvious (to me) what should be the correct behavior.
13236 : // The current approach has the benefit to avoid recomputing
13237 : // the mean for each (i,j) tuple, but only for all i.
13238 500647 : if (nCount > 0)
13239 : {
13240 500639 : padfComomentMatrix[idxInMatrixI] +=
13241 : static_cast<double>(dfComoment);
13242 500639 : padfComomentMatrix[idxInMatrixI] +=
13243 500639 : static_cast<double>(adfMean[idxInMatrixI] -
13244 500639 : adfCurBlockMean[i]) *
13245 500639 : static_cast<double>(adfMean[idxInMatrixJ] -
13246 500639 : adfCurBlockMean[j]) *
13247 500639 : (static_cast<double>(anCount[idxInMatrixI]) *
13248 500639 : static_cast<double>(nCount) /
13249 500639 : static_cast<double>(anCount[idxInMatrixI] + nCount));
13250 :
13251 500639 : anCount[idxInMatrixI] += nCount;
13252 : }
13253 :
13254 : // Update means
13255 500647 : if (anCurBlockCount[i] > 0)
13256 : {
13257 1001280 : adfMean[idxInMatrixI] +=
13258 500640 : (adfCurBlockMean[i] - adfMean[idxInMatrixI]) *
13259 : static_cast<T>(
13260 500640 : static_cast<double>(anCurBlockCount[i]) /
13261 500640 : static_cast<double>(anCountMean[idxInMatrixI] +
13262 : anCurBlockCount[i]));
13263 :
13264 500640 : anCountMean[idxInMatrixI] += anCurBlockCount[i];
13265 : }
13266 :
13267 500647 : if (idxInMatrixI != idxInMatrixJ && anCurBlockCount[j] > 0)
13268 : {
13269 999132 : adfMean[idxInMatrixJ] +=
13270 499566 : (adfCurBlockMean[j] - adfMean[idxInMatrixJ]) *
13271 : static_cast<T>(
13272 499566 : static_cast<double>(anCurBlockCount[j]) /
13273 499566 : static_cast<double>(anCountMean[idxInMatrixJ] +
13274 : anCurBlockCount[j]));
13275 :
13276 499566 : anCountMean[idxInMatrixJ] += anCurBlockCount[j];
13277 : }
13278 : };
13279 :
13280 32 : if (bAllBandsAreAllNodata)
13281 : {
13282 : // Optimized code path where all values in the current block
13283 : // are invalid
13284 :
13285 8 : for (int i = 0; i < nBandCount; ++i)
13286 : {
13287 12 : for (int j = i; j < nBandCount; ++j)
13288 : {
13289 7 : UpdateGlobalValues(i, j, 0, ZERO);
13290 : }
13291 : }
13292 : }
13293 29 : else if (bNoBandHasNodata)
13294 : {
13295 : // Optimized code path where there are no invalid value in the
13296 : // current block
13297 :
13298 : if constexpr (!std::is_same_v<T, double>)
13299 : {
13300 : std::fill(aCurBlockComomentMatrix.begin(),
13301 : aCurBlockComomentMatrix.end(), ZERO);
13302 :
13303 : GDALMatrixMultiplyAByTransposeAUpperTriangle(
13304 : nNumThreads, adfCurBlockPixelsAllBands.data(),
13305 : aCurBlockComomentMatrix.data(), nBandCount,
13306 : nThisBlockPixelCount);
13307 : }
13308 : #ifdef CAN_DETECT_AVX2_FMA_AT_RUNTIME
13309 24 : else if (bHasAVX2_FMA)
13310 : {
13311 24 : GDALMatrixMultiplyAByTransposeAUpperTriangle_AVX2_FMA(
13312 : nNumThreads, adfCurBlockPixelsAllBands.data(),
13313 : padfComomentMatrix, nBandCount, nThisBlockPixelCount);
13314 : }
13315 : #endif
13316 : else
13317 : {
13318 0 : GDALMatrixMultiplyAByTransposeAUpperTriangle(
13319 : nNumThreads, adfCurBlockPixelsAllBands.data(),
13320 : padfComomentMatrix, nBandCount, nThisBlockPixelCount);
13321 : }
13322 :
13323 1088 : for (int i = 0; i < nBandCount; ++i)
13324 : {
13325 501689 : for (int j = i; j < nBandCount; ++j)
13326 : {
13327 : if constexpr (!std::is_same_v<T, double>)
13328 : {
13329 : const auto idxInMatrixI =
13330 : static_cast<size_t>(i) * nBandCount + j;
13331 : UpdateGlobalValues(
13332 : i, j, nThisBlockPixelCount,
13333 : aCurBlockComomentMatrix[idxInMatrixI]);
13334 : }
13335 : else
13336 : {
13337 500625 : UpdateGlobalValues(i, j, nThisBlockPixelCount, ZERO);
13338 : }
13339 : }
13340 : }
13341 : }
13342 : else
13343 : {
13344 : #ifdef HAVE_OPENMP
13345 5 : #pragma omp parallel for schedule(static) num_threads(nNumThreads)
13346 : #endif
13347 : for (MySignedSize_t k = 0; k < kMax; ++k)
13348 : {
13349 : int i, j;
13350 : std::tie(i, j) = anMapLinearIdxToIJ[k];
13351 :
13352 : // Now compute the moment of (i, j), but just for this block
13353 : size_t nCount = 0;
13354 : T dfComoment = 0;
13355 : const T *padfI =
13356 : adfCurBlockPixelsAllBands.data() + i * nThisBlockPixelCount;
13357 : const T *padfJ =
13358 : adfCurBlockPixelsAllBands.data() + j * nThisBlockPixelCount;
13359 :
13360 : // Use https://en.wikipedia.org/wiki/Algorithms_for_calculating_variance#Two-pass
13361 : // for the current block
13362 : if ((anCurBlockCount[i] == nThisBlockPixelCount &&
13363 : anCurBlockCount[j] == nThisBlockPixelCount) ||
13364 : (bNoneHasMaskOrNodata && bIsAllInteger))
13365 : {
13366 : // Most optimized code path: integer, no nodata, no mask
13367 : #ifdef HAVE_OPENMP_SIMD
13368 : #pragma omp simd reduction(+ : dfComoment)
13369 : #endif
13370 : for (size_t iPixel = 0; iPixel < nThisBlockPixelCount;
13371 : ++iPixel)
13372 : {
13373 : dfComoment += padfI[iPixel] * padfJ[iPixel];
13374 : }
13375 : nCount = nThisBlockPixelCount;
13376 : }
13377 : else if (bNoneHasMaskOrNodata)
13378 : {
13379 : // Floating-point code path with no nodata and no mask
13380 : #ifdef HAVE_OPENMP_SIMD
13381 : #pragma omp simd reduction(+ : dfComoment)
13382 : #endif
13383 : for (size_t iPixel = 0; iPixel < nThisBlockPixelCount;
13384 : ++iPixel)
13385 : {
13386 : const T dfAcc = padfI[iPixel] * padfJ[iPixel];
13387 : const bool bIsValid = !std::isnan(dfAcc);
13388 : nCount += bIsValid;
13389 : dfComoment += bIsValid ? dfAcc : ZERO;
13390 : }
13391 : }
13392 : else if (!std::isnan(adfNoData[i]) && !std::isnan(adfNoData[j]))
13393 : {
13394 : // Code path when there are both nodata values
13395 : const T shiftedNoDataI = adfNoData[i] - adfCurBlockMean[i];
13396 : const T shiftedNoDataJ = adfNoData[j] - adfCurBlockMean[j];
13397 :
13398 : #ifdef HAVE_OPENMP_SIMD
13399 : #pragma omp simd reduction(+ : dfComoment)
13400 : #endif
13401 : for (size_t iPixel = 0; iPixel < nThisBlockPixelCount;
13402 : ++iPixel)
13403 : {
13404 : const T dfI = padfI[iPixel];
13405 : const T dfJ = padfJ[iPixel];
13406 : const T dfAcc = dfI * dfJ;
13407 : const bool bIsValid = !std::isnan(dfAcc) &&
13408 : dfI != shiftedNoDataI &&
13409 : dfJ != shiftedNoDataJ;
13410 : nCount += bIsValid;
13411 : dfComoment += bIsValid ? dfAcc : ZERO;
13412 : }
13413 : }
13414 : else
13415 : {
13416 : // Generic code path
13417 : const T shiftedNoDataI = adfNoData[i] - adfCurBlockMean[i];
13418 : const T shiftedNoDataJ = adfNoData[j] - adfCurBlockMean[j];
13419 :
13420 : #ifdef HAVE_OPENMP_SIMD
13421 : #pragma omp simd reduction(+ : dfComoment)
13422 : #endif
13423 : for (size_t iPixel = 0; iPixel < nThisBlockPixelCount;
13424 : ++iPixel)
13425 : {
13426 : const T dfI = padfI[iPixel];
13427 : const T dfJ = padfJ[iPixel];
13428 : const T dfAcc = dfI * dfJ;
13429 : const bool bIsValid =
13430 : !std::isnan(dfAcc) && dfI != shiftedNoDataI &&
13431 : dfJ != shiftedNoDataJ &&
13432 : (!pabyCurBlockMask[i] ||
13433 : (*pabyCurBlockMask[i])[iPixel]) &&
13434 : (!pabyCurBlockMask[j] ||
13435 : (*pabyCurBlockMask[j])[iPixel]);
13436 : nCount += bIsValid;
13437 : dfComoment += bIsValid ? dfAcc : ZERO;
13438 : }
13439 : }
13440 :
13441 : UpdateGlobalValues(i, j, nCount, dfComoment);
13442 : }
13443 : }
13444 :
13445 32 : ++nCurIter;
13446 35 : if (pfnProgress &&
13447 3 : !pfnProgress(static_cast<double>(nCurIter) / nIterCount, "",
13448 : pProgressData))
13449 : {
13450 1 : poDS->ReportError(CE_Failure, CPLE_UserInterrupt,
13451 : "User terminated");
13452 1 : return CE_Failure;
13453 : }
13454 : }
13455 :
13456 : // Finalize by dividing co-moments by the number of contributing values
13457 : // (minus nDeltaDegreeOfFreedom) to compute final covariances.
13458 44 : for (int i = 0; i < nBandCount; ++i)
13459 : {
13460 : // The covariance matrix is symmetric. So start at i
13461 81 : for (int j = i; j < nBandCount; ++j)
13462 : {
13463 51 : const auto idxInMatrixI = static_cast<size_t>(i) * nBandCount + j;
13464 51 : const double dfCovariance =
13465 51 : (nDeltaDegreeOfFreedom < 0 ||
13466 51 : anCount[idxInMatrixI] <=
13467 51 : static_cast<uint64_t>(nDeltaDegreeOfFreedom))
13468 4 : ? std::numeric_limits<double>::quiet_NaN()
13469 94 : : padfComomentMatrix[idxInMatrixI] /
13470 47 : static_cast<double>(anCount[idxInMatrixI] -
13471 47 : nDeltaDegreeOfFreedom);
13472 :
13473 51 : padfCovMatrix[idxInMatrixI] = dfCovariance;
13474 : // Fill lower triangle
13475 51 : padfCovMatrix[static_cast<size_t>(j) * nBandCount + i] =
13476 : dfCovariance;
13477 : }
13478 : }
13479 :
13480 14 : return CE_None;
13481 : }
13482 :
13483 : /************************************************************************/
13484 : /* GDALDataset::ComputeInterBandCovarianceMatrix() */
13485 : /************************************************************************/
13486 :
13487 : /**
13488 : \brief Compute the covariance matrix between bands of this dataset.
13489 :
13490 : The covariance indicates the level to which two bands vary together.
13491 :
13492 : If we call \f$ v_i[y,x] \f$ the value of pixel at row=y and column=x for band i,
13493 : and \f$ mean_i \f$ the mean value of all pixels of band i, then
13494 :
13495 : \f[
13496 : \mathrm{cov}[i,j] =
13497 : \frac{
13498 : \sum_{y,x} \left( v_i[y,x] - \mathrm{mean}_i \right)
13499 : \left( v_j[y,x] - \mathrm{mean}_j \right)
13500 : }{
13501 : \mathrm{pixel\_count} - \mathrm{nDeltaDegreeOfFreedom}
13502 : }
13503 : \f]
13504 :
13505 : When there are no nodata values, \f$ pixel\_count = GetRasterXSize() * GetRasterYSize() \f$.
13506 : We can see that \f$ cov[i,j] = cov[j,i] \f$, and consequently the returned matrix
13507 : is symmetric.
13508 :
13509 : A value of nDeltaDegreeOfFreedom=1 (the default) will return a unbiased estimate
13510 : if the pixels in bands are considered to be a sample of the whole population.
13511 : This is consistent with the default of
13512 : https://numpy.org/doc/stable/reference/generated/numpy.cov.html and the returned
13513 : matrix is consistent with what can be obtained with
13514 :
13515 : \verbatim embed:rst
13516 : .. code-block:: python
13517 :
13518 : numpy.cov(
13519 : [ds.GetRasterBand(n + 1).ReadAsArray().ravel() for n in range(ds.RasterCount)]
13520 : )
13521 : \endverbatim
13522 :
13523 : Otherwise a value of nDeltaDegreeOfFreedom=0 can be used if they are considered
13524 : to be the whole population.
13525 :
13526 : The caller must provide an already allocated array in padfCovMatrix of size
13527 : at least nBandCount * nBandCount.
13528 :
13529 : This method recomputes the covariance matrix, even if STATISTICS_COVARIANCES
13530 : metadata items are available in bands. See GetInterBandCovarianceMatrix()
13531 : to use them.
13532 :
13533 : The implementation is optimized to minimize the amount of pixel reading.
13534 :
13535 : This method is the same as the C function GDALDatasetComputeInterBandCovarianceMatrix()
13536 :
13537 : @param[out] padfCovMatrix Pointer to an already allocated output array, of size at least
13538 : nBandCount * nBandCount.
13539 : @param nSize Number of elements in output array.
13540 : @param nBandCount Zero for all bands, or number of values in panBandList.
13541 : Defaults to 0.
13542 : @param panBandList nullptr for all bands if nBandCount == 0, or array of
13543 : nBandCount values such as panBandList[i] is the index
13544 : between 1 and GetRasterCount() of a band that must be used
13545 : in the covariance computation. Defaults to nullptr.
13546 : @param bApproxOK Whether it is acceptable to use a subsample of values.
13547 : Defaults to false.
13548 : @param bWriteIntoMetadata Whether this method must write
13549 : STATISTICS_COVARIANCES band metadata items.
13550 : Defaults to true.
13551 : @param nDeltaDegreeOfFreedom Correction term to subtract in the final
13552 : averaging phase of the covariance computation.
13553 : Defaults to 1.
13554 : @param pfnProgress a function to call to report progress, or NULL.
13555 : @param pProgressData application data to pass to the progress function.
13556 :
13557 : @return CE_None if successful, or CE_Failure in case of failure
13558 :
13559 : @since 3.13
13560 :
13561 : @see GetInterBandCovarianceMatrix()
13562 : */
13563 22 : CPLErr GDALDataset::ComputeInterBandCovarianceMatrix(
13564 : double *padfCovMatrix, size_t nSize, int nBandCount, const int *panBandList,
13565 : bool bApproxOK, bool bWriteIntoMetadata, int nDeltaDegreeOfFreedom,
13566 : GDALProgressFunc pfnProgress, void *pProgressData)
13567 : {
13568 44 : std::vector<int> anBandListTmp; // keep in this scope
13569 22 : if (nBandCount == 0)
13570 : {
13571 0 : if (nBands == 0)
13572 0 : return CE_None;
13573 0 : for (int i = 0; i < nBands; ++i)
13574 0 : anBandListTmp.push_back(i + 1);
13575 0 : nBandCount = nBands;
13576 0 : panBandList = anBandListTmp.data();
13577 : }
13578 : else
13579 : {
13580 22 : if (nBandCount > nBands)
13581 : {
13582 1 : CPLError(CE_Failure, CPLE_AppDefined,
13583 : "ComputeInterBandCovarianceMatrix(): nBandCount > nBands");
13584 1 : return CE_Failure;
13585 : }
13586 1057 : for (int i = 0; i < nBandCount; ++i)
13587 : {
13588 1038 : if (panBandList[i] <= 0 || panBandList[i] > nBands)
13589 : {
13590 2 : CPLError(CE_Failure, CPLE_AppDefined,
13591 : "ComputeInterBandCovarianceMatrix(): invalid value "
13592 : "panBandList[%d] = %d",
13593 2 : i, panBandList[i]);
13594 2 : return CE_Failure;
13595 : }
13596 : }
13597 :
13598 19 : if (bWriteIntoMetadata)
13599 : {
13600 14 : bool bOK = nBandCount == nBands;
13601 38 : for (int i = 0; bOK && i < nBandCount; ++i)
13602 : {
13603 24 : bOK = (panBandList[i] == i + 1);
13604 : }
13605 14 : if (!bOK)
13606 : {
13607 4 : CPLError(CE_Failure, CPLE_AppDefined,
13608 : "ComputeInterBandCovarianceMatrix(): cannot write "
13609 : "STATISTICS_COVARIANCES metadata since the input band "
13610 : "list is not [1, 2, ... GetRasterCount()]");
13611 4 : return CE_Failure;
13612 : }
13613 : }
13614 : }
13615 :
13616 15 : const auto nMatrixSize = static_cast<size_t>(nBandCount) * nBandCount;
13617 15 : if (nSize < nMatrixSize)
13618 : {
13619 0 : CPLError(CE_Failure, CPLE_AppDefined,
13620 : "ComputeInterBandCovarianceMatrix(): too small result matrix "
13621 : "provided");
13622 0 : return CE_Failure;
13623 : }
13624 :
13625 : // Find appropriate overview dataset
13626 15 : GDALDataset *poActiveDS = this;
13627 15 : if (bApproxOK && papoBands[panBandList[0] - 1]->GetOverviewCount() > 0)
13628 : {
13629 1 : GDALDataset *poOvrDS = nullptr;
13630 4 : for (int i = 0; i < nBandCount; ++i)
13631 : {
13632 3 : const int nIdxBand = panBandList[i] - 1;
13633 6 : auto poOvrBand = papoBands[nIdxBand]->GetRasterSampleOverview(
13634 3 : GDALSTAT_APPROX_NUMSAMPLES);
13635 :
13636 6 : if (poOvrBand == papoBands[i] ||
13637 3 : poOvrBand->GetBand() != panBandList[i])
13638 : {
13639 0 : poOvrDS = nullptr;
13640 0 : break;
13641 : }
13642 3 : else if (i == 0)
13643 : {
13644 1 : if (poOvrBand->GetDataset() == this)
13645 : {
13646 0 : break;
13647 : }
13648 1 : poOvrDS = poOvrBand->GetDataset();
13649 : }
13650 2 : else if (poOvrBand->GetDataset() != poOvrDS)
13651 : {
13652 0 : poOvrDS = nullptr;
13653 0 : break;
13654 : }
13655 : }
13656 1 : if (poOvrDS)
13657 : {
13658 1 : poActiveDS = poOvrDS;
13659 : }
13660 : }
13661 :
13662 : #ifdef GDAL_COVARIANCE_CAN_USE_FLOAT32
13663 : const auto UseFloat32 = [](GDALDataType eDT)
13664 : {
13665 : return eDT == GDT_UInt8 || eDT == GDT_Int8 || eDT == GDT_UInt16 ||
13666 : eDT == GDT_Int16 || eDT == GDT_Float32;
13667 : };
13668 :
13669 : bool bUseFloat32 = UseFloat32(
13670 : poActiveDS->GetRasterBand(panBandList[0])->GetRasterDataType());
13671 : for (int i = 1; bUseFloat32 && i < nBandCount; ++i)
13672 : {
13673 : bUseFloat32 = UseFloat32(
13674 : poActiveDS->GetRasterBand(panBandList[i])->GetRasterDataType());
13675 : }
13676 : #endif
13677 :
13678 : CPLErr eErr =
13679 : #ifdef GDAL_COVARIANCE_CAN_USE_FLOAT32
13680 : bUseFloat32 ? ComputeInterBandCovarianceMatrixInternal<float>(
13681 : poActiveDS, padfCovMatrix, nBandCount, panBandList,
13682 : poActiveDS->papoBands, nDeltaDegreeOfFreedom,
13683 : pfnProgress, pProgressData)
13684 : :
13685 : #endif
13686 30 : ComputeInterBandCovarianceMatrixInternal<double>(
13687 : poActiveDS, padfCovMatrix, nBandCount, panBandList,
13688 15 : poActiveDS->papoBands, nDeltaDegreeOfFreedom,
13689 : pfnProgress, pProgressData);
13690 :
13691 15 : if (bWriteIntoMetadata && eErr == CE_None)
13692 : {
13693 10 : CPLAssert(nBands == nBandCount);
13694 20 : std::string osStr;
13695 10 : size_t idx = 0;
13696 32 : for (int i = 0; i < nBands; ++i)
13697 : {
13698 22 : osStr.clear();
13699 74 : for (int j = 0; j < nBands; ++j, ++idx)
13700 : {
13701 52 : if (j > 0)
13702 30 : osStr += ',';
13703 52 : osStr += CPLSPrintf("%.17g", padfCovMatrix[idx]);
13704 : }
13705 22 : papoBands[i]->SetMetadataItem("STATISTICS_COVARIANCES",
13706 22 : osStr.c_str());
13707 : }
13708 : }
13709 :
13710 15 : return eErr;
13711 : }
13712 :
13713 : /************************************************************************/
13714 : /* GDALDatasetComputeInterBandCovarianceMatrix() */
13715 : /************************************************************************/
13716 :
13717 : /**
13718 : \brief Compute the covariance matrix between bands of this dataset.
13719 :
13720 : The covariance indicates the level to which two bands vary together.
13721 :
13722 : If we call \f$ v_i[y,x] \f$ the value of pixel at row=y and column=x for band i,
13723 : and \f$ mean_i \f$ the mean value of all pixels of band i, then
13724 :
13725 : \f[
13726 : \mathrm{cov}[i,j] =
13727 : \frac{
13728 : \sum_{y,x} \left( v_i[y,x] - \mathrm{mean}_i \right)
13729 : \left( v_j[y,x] - \mathrm{mean}_j \right)
13730 : }{
13731 : \mathrm{pixel\_count} - \mathrm{nDeltaDegreeOfFreedom}
13732 : }
13733 : \f]
13734 :
13735 : When there are no nodata values, \f$ pixel\_count = GetRasterXSize() * GetRasterYSize() \f$.
13736 : We can see that \f$ cov[i,j] = cov[j,i] \f$, and consequently the returned matrix
13737 : is symmetric.
13738 :
13739 : A value of nDeltaDegreeOfFreedom=1 (the default) will return a unbiased estimate
13740 : if the pixels in bands are considered to be a sample of the whole population.
13741 : This is consistent with the default of
13742 : https://numpy.org/doc/stable/reference/generated/numpy.cov.html and the returned
13743 : matrix is consistent with what can be obtained with
13744 :
13745 : \verbatim embed:rst
13746 : .. code-block:: python
13747 :
13748 : numpy.cov(
13749 : [ds.GetRasterBand(n + 1).ReadAsArray().ravel() for n in range(ds.RasterCount)]
13750 : )
13751 : \endverbatim
13752 :
13753 : Otherwise a value of nDeltaDegreeOfFreedom=0 can be used if they are considered
13754 : to be the whole population.
13755 :
13756 : The caller must provide an already allocated array in padfCovMatrix of size
13757 : at least GDALGetRasterCount() * GDALGetRasterCount().
13758 :
13759 : This method recomputes the covariance matrix, even if STATISTICS_COVARIANCES
13760 : metadata items are available in bands. See GDALDatasetGetInterBandCovarianceMatrix()
13761 : to use them.
13762 :
13763 : This function is the same as the C++ method GDALDataset::ComputeInterBandCovarianceMatrix()
13764 :
13765 : @param hDS Dataset handle.
13766 : @param[out] padfCovMatrix Pointer to an already allocated output array, of size at least
13767 : nBandCount * nBandCount.
13768 : @param nSize Number of elements in output array.
13769 : @param nBandCount Zero for all bands, or number of values in panBandList.
13770 : Defaults to 0.
13771 : @param panBandList nullptr for all bands if nBandCount == 0, or array of
13772 : nBandCount values such as panBandList[i] is the index
13773 : between 1 and GetRasterCount() of a band that must be used
13774 : in the covariance computation. Defaults to nullptr.
13775 : @param bApproxOK Whether it is acceptable to use a subsample of values.
13776 : Defaults to false.
13777 : @param bWriteIntoMetadata Whether this method must write
13778 : STATISTICS_COVARIANCES band metadata items.
13779 : Defaults to true.
13780 : @param nDeltaDegreeOfFreedom Correction term to subtract in the final
13781 : averaging phase of the covariance computation.
13782 : Defaults to 1.
13783 : @param pfnProgress a function to call to report progress, or NULL.
13784 : @param pProgressData application data to pass to the progress function.
13785 :
13786 : @return CE_None if successful, or CE_Failure in case of failure
13787 :
13788 : @since 3.13
13789 :
13790 : @see GDALDatasetGetInterBandCovarianceMatrix()
13791 : */
13792 17 : CPLErr GDALDatasetComputeInterBandCovarianceMatrix(
13793 : GDALDatasetH hDS, double *padfCovMatrix, size_t nSize, int nBandCount,
13794 : const int *panBandList, bool bApproxOK, bool bWriteIntoMetadata,
13795 : int nDeltaDegreeOfFreedom, GDALProgressFunc pfnProgress,
13796 : void *pProgressData)
13797 : {
13798 17 : VALIDATE_POINTER1(hDS, __func__, CE_Failure);
13799 17 : VALIDATE_POINTER1(padfCovMatrix, __func__, CE_Failure);
13800 17 : return GDALDataset::FromHandle(hDS)->ComputeInterBandCovarianceMatrix(
13801 : padfCovMatrix, nSize, nBandCount, panBandList, bApproxOK,
13802 17 : bWriteIntoMetadata, nDeltaDegreeOfFreedom, pfnProgress, pProgressData);
13803 : }
|