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 <array>
17 : #include <cassert>
18 : #include <climits>
19 : #include <cmath>
20 : #include <cstdarg>
21 : #include <cstdio>
22 : #include <cstdlib>
23 : #include <cstring>
24 : #include <algorithm>
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 :
44 : #include "gdal.h"
45 : #include "gdal_alg.h"
46 : #include "gdal_abstractbandblockcache.h"
47 : #include "gdalantirecursion.h"
48 : #include "gdal_dataset.h"
49 : #include "gdal_matrix.hpp"
50 :
51 : #ifdef CAN_DETECT_AVX2_FMA_AT_RUNTIME
52 : #include "gdal_matrix_avx2_fma.h"
53 : #endif
54 :
55 : #include "gdalsubdatasetinfo.h"
56 : #include "gdal_thread_pool.h"
57 : #include "gdal_typetraits.h"
58 :
59 : #include "ogr_api.h"
60 : #include "ogr_attrind.h"
61 : #include "ogr_core.h"
62 : #include "ogr_feature.h"
63 : #include "ogr_featurestyle.h"
64 : #include "ogr_gensql.h"
65 : #include "ogr_geometry.h"
66 : #include "ogr_p.h"
67 : #include "ogr_spatialref.h"
68 : #include "ogr_srs_api.h"
69 : #include "ograpispy.h"
70 : #include "ogrsf_frmts.h"
71 : #include "ogrunionlayer.h"
72 : #include "ogr_swq.h"
73 : #include "memmultidim.h"
74 : #include "gdalmultidim_priv.h"
75 :
76 : #include "../frmts/derived/derivedlist.h"
77 :
78 : #ifdef SQLITE_ENABLED
79 : #include "../sqlite/ogrsqliteexecutesql.h"
80 : #endif
81 :
82 : #ifdef HAVE_OPENMP
83 : #include <omp.h>
84 : #endif
85 :
86 : extern const swq_field_type SpecialFieldTypes[SPECIAL_FIELD_COUNT];
87 :
88 : enum class GDALAllowReadWriteMutexState
89 : {
90 : RW_MUTEX_STATE_UNKNOWN,
91 : RW_MUTEX_STATE_ALLOWED,
92 : RW_MUTEX_STATE_DISABLED
93 : };
94 :
95 : const GIntBig TOTAL_FEATURES_NOT_INIT = -2;
96 : const GIntBig TOTAL_FEATURES_UNKNOWN = -1;
97 :
98 : class GDALDataset::Private
99 : {
100 : CPL_DISALLOW_COPY_ASSIGN(Private)
101 :
102 : public:
103 : CPLMutex *hMutex = nullptr;
104 : std::map<GIntBig, int> oMapThreadToMutexTakenCount{};
105 : #ifdef DEBUG_EXTRA
106 : std::map<GIntBig, int> oMapThreadToMutexTakenCountSaved{};
107 : #endif
108 : GDALAllowReadWriteMutexState eStateReadWriteMutex =
109 : GDALAllowReadWriteMutexState::RW_MUTEX_STATE_UNKNOWN;
110 : int nCurrentLayerIdx = 0;
111 : int nLayerCount = -1;
112 : GIntBig nFeatureReadInLayer = 0;
113 : GIntBig nFeatureReadInDataset = 0;
114 : GIntBig nTotalFeaturesInLayer = TOTAL_FEATURES_NOT_INIT;
115 : GIntBig nTotalFeatures = TOTAL_FEATURES_NOT_INIT;
116 : OGRLayer *poCurrentLayer = nullptr;
117 :
118 : std::mutex m_oMutexWKT{};
119 :
120 : char *m_pszWKTCached = nullptr;
121 : OGRSpatialReference *m_poSRSCached = nullptr;
122 : char *m_pszWKTGCPCached = nullptr;
123 : OGRSpatialReference *m_poSRSGCPCached = nullptr;
124 :
125 : GDALDataset *poParentDataset = nullptr;
126 :
127 : bool m_bOverviewsEnabled = true;
128 :
129 : std::vector<int>
130 : m_anBandMap{}; // used by RasterIO(). Values are 1, 2, etc.
131 :
132 187946 : Private() = default;
133 : };
134 :
135 : struct SharedDatasetCtxt
136 : {
137 : // PID of the thread that mark the dataset as shared
138 : // This may not be the actual PID, but the responsiblePID.
139 : GIntBig nPID;
140 : char *pszDescription;
141 : char *pszConcatenatedOpenOptions;
142 : int nOpenFlags;
143 :
144 : GDALDataset *poDS;
145 : };
146 :
147 : // Set of datasets opened as shared datasets (with GDALOpenShared)
148 : // The values in the set are of type SharedDatasetCtxt.
149 : static CPLHashSet *phSharedDatasetSet = nullptr;
150 :
151 : // Set of all datasets created in the constructor of GDALDataset.
152 : // In the case of a shared dataset, memorize the PID of the thread
153 : // that marked the dataset as shared, so that we can remove it from
154 : // the phSharedDatasetSet in the destructor of the dataset, even
155 : // if GDALClose is called from a different thread.
156 : static std::map<GDALDataset *, GIntBig> *poAllDatasetMap = nullptr;
157 :
158 : static CPLMutex *hDLMutex = nullptr;
159 :
160 : // Static array of all datasets. Used by GDALGetOpenDatasets.
161 : // Not thread-safe. See GDALGetOpenDatasets.
162 : static GDALDataset **ppDatasets = nullptr;
163 :
164 8417 : static unsigned long GDALSharedDatasetHashFunc(const void *elt)
165 : {
166 8417 : const SharedDatasetCtxt *psStruct =
167 : static_cast<const SharedDatasetCtxt *>(elt);
168 : return static_cast<unsigned long>(
169 8417 : CPLHashSetHashStr(psStruct->pszDescription) ^
170 8417 : CPLHashSetHashStr(psStruct->pszConcatenatedOpenOptions) ^
171 8417 : psStruct->nOpenFlags ^ psStruct->nPID);
172 : }
173 :
174 6985 : static int GDALSharedDatasetEqualFunc(const void *elt1, const void *elt2)
175 : {
176 6985 : const SharedDatasetCtxt *psStruct1 =
177 : static_cast<const SharedDatasetCtxt *>(elt1);
178 6985 : const SharedDatasetCtxt *psStruct2 =
179 : static_cast<const SharedDatasetCtxt *>(elt2);
180 13926 : return strcmp(psStruct1->pszDescription, psStruct2->pszDescription) == 0 &&
181 6941 : strcmp(psStruct1->pszConcatenatedOpenOptions,
182 6941 : psStruct2->pszConcatenatedOpenOptions) == 0 &&
183 20858 : psStruct1->nPID == psStruct2->nPID &&
184 13917 : psStruct1->nOpenFlags == psStruct2->nOpenFlags;
185 : }
186 :
187 413 : static void GDALSharedDatasetFreeFunc(void *elt)
188 : {
189 413 : SharedDatasetCtxt *psStruct = static_cast<SharedDatasetCtxt *>(elt);
190 413 : CPLFree(psStruct->pszDescription);
191 413 : CPLFree(psStruct->pszConcatenatedOpenOptions);
192 413 : CPLFree(psStruct);
193 413 : }
194 :
195 : static std::string
196 7056 : GDALSharedDatasetConcatenateOpenOptions(CSLConstList papszOpenOptions)
197 : {
198 7056 : std::string osStr;
199 7069 : for (const char *pszOption : cpl::Iterate(papszOpenOptions))
200 13 : osStr += pszOption;
201 7056 : return osStr;
202 : }
203 :
204 : /************************************************************************/
205 : /* Functions shared between gdalproxypool.cpp and gdaldataset.cpp */
206 : /************************************************************************/
207 :
208 : // The open-shared mutex must be used by the ProxyPool too.
209 484199 : CPLMutex **GDALGetphDLMutex()
210 : {
211 484199 : return &hDLMutex;
212 : }
213 :
214 : // The current thread will act in the behalf of the thread of PID
215 : // responsiblePID.
216 473508 : void GDALSetResponsiblePIDForCurrentThread(GIntBig responsiblePID)
217 : {
218 : GIntBig *pResponsiblePID =
219 473508 : static_cast<GIntBig *>(CPLGetTLS(CTLS_RESPONSIBLEPID));
220 473508 : if (pResponsiblePID == nullptr)
221 : {
222 229 : pResponsiblePID = static_cast<GIntBig *>(CPLMalloc(sizeof(GIntBig)));
223 229 : CPLSetTLS(CTLS_RESPONSIBLEPID, pResponsiblePID, TRUE);
224 : }
225 473508 : *pResponsiblePID = responsiblePID;
226 473508 : }
227 :
228 : // Get the PID of the thread that the current thread will act in the behalf of
229 : // By default : the current thread acts in the behalf of itself.
230 608501 : GIntBig GDALGetResponsiblePIDForCurrentThread()
231 : {
232 : GIntBig *pResponsiblePID =
233 608501 : static_cast<GIntBig *>(CPLGetTLS(CTLS_RESPONSIBLEPID));
234 608501 : if (pResponsiblePID == nullptr)
235 44791 : return CPLGetPID();
236 563710 : return *pResponsiblePID;
237 : }
238 :
239 : /************************************************************************/
240 : /* ==================================================================== */
241 : /* GDALDataset */
242 : /* ==================================================================== */
243 : /************************************************************************/
244 :
245 : /**
246 : * \class GDALDataset "gdal_priv.h"
247 : *
248 : * A dataset encapsulating one or more raster bands. Details are further
249 : * discussed in the <a href="https://gdal.org/user/raster_data_model.html">GDAL
250 : * Raster Data Model</a>.
251 : *
252 : * Use GDALOpen() or GDALOpenShared() to create a GDALDataset for a named file,
253 : * or GDALDriver::Create() or GDALDriver::CreateCopy() to create a new
254 : * dataset.
255 : */
256 :
257 : /************************************************************************/
258 : /* GDALDataset() */
259 : /************************************************************************/
260 :
261 : //! @cond Doxygen_Suppress
262 166278 : GDALDataset::GDALDataset()
263 166278 : : GDALDataset(CPLTestBool(CPLGetConfigOption("GDAL_FORCE_CACHING", "NO")))
264 : {
265 166278 : }
266 :
267 187946 : GDALDataset::GDALDataset(int bForceCachedIOIn)
268 187946 : : bForceCachedIO(CPL_TO_BOOL(bForceCachedIOIn)),
269 187946 : m_poPrivate(new (std::nothrow) GDALDataset::Private)
270 : {
271 187946 : }
272 :
273 : //! @endcond
274 :
275 : /************************************************************************/
276 : /* ~GDALDataset() */
277 : /************************************************************************/
278 :
279 : /**
280 : * \brief Destroy an open GDALDataset.
281 : *
282 : * This is the accepted method of closing a GDAL dataset and deallocating
283 : * all resources associated with it.
284 : *
285 : * Equivalent of the C callable GDALClose(). Except that GDALClose() first
286 : * decrements the reference count, and then closes only if it has dropped to
287 : * zero.
288 : *
289 : * For Windows users, it is not recommended to use the delete operator on the
290 : * dataset object because of known issues when allocating and freeing memory
291 : * across module boundaries. Calling GDALClose() is then a better option.
292 : */
293 :
294 187926 : GDALDataset::~GDALDataset()
295 :
296 : {
297 : // we don't want to report destruction of datasets that
298 : // were never really open or meant as internal
299 187926 : if (!bIsInternal && (nBands != 0 || !EQUAL(GetDescription(), "")))
300 : {
301 75808 : if (CPLGetPID() != GDALGetResponsiblePIDForCurrentThread())
302 209 : CPLDebug("GDAL",
303 : "GDALClose(%s, this=%p) (pid=%d, responsiblePID=%d)",
304 209 : GetDescription(), this, static_cast<int>(CPLGetPID()),
305 209 : static_cast<int>(GDALGetResponsiblePIDForCurrentThread()));
306 : else
307 75599 : CPLDebug("GDAL", "GDALClose(%s, this=%p)", GetDescription(), this);
308 : }
309 :
310 187926 : GDALDataset::Close();
311 :
312 : /* -------------------------------------------------------------------- */
313 : /* Remove dataset from the "open" dataset list. */
314 : /* -------------------------------------------------------------------- */
315 187926 : if (!bIsInternal)
316 : {
317 154638 : CPLMutexHolderD(&hDLMutex);
318 77319 : if (poAllDatasetMap)
319 : {
320 : std::map<GDALDataset *, GIntBig>::iterator oIter =
321 77319 : poAllDatasetMap->find(this);
322 77319 : CPLAssert(oIter != poAllDatasetMap->end());
323 :
324 77319 : UnregisterFromSharedDataset();
325 :
326 77319 : poAllDatasetMap->erase(oIter);
327 :
328 77319 : if (poAllDatasetMap->empty())
329 : {
330 31780 : delete poAllDatasetMap;
331 31780 : poAllDatasetMap = nullptr;
332 31780 : if (phSharedDatasetSet)
333 : {
334 286 : CPLHashSetDestroy(phSharedDatasetSet);
335 : }
336 31780 : phSharedDatasetSet = nullptr;
337 31780 : CPLFree(ppDatasets);
338 31780 : ppDatasets = nullptr;
339 : }
340 : }
341 : }
342 :
343 : /* -------------------------------------------------------------------- */
344 : /* Destroy the raster bands if they exist. */
345 : /* -------------------------------------------------------------------- */
346 1728690 : for (int i = 0; i < nBands && papoBands != nullptr; ++i)
347 : {
348 1540760 : if (papoBands[i] != nullptr)
349 1540760 : delete papoBands[i];
350 1540760 : papoBands[i] = nullptr;
351 : }
352 :
353 187926 : CPLFree(papoBands);
354 :
355 187926 : if (m_poStyleTable)
356 : {
357 23 : delete m_poStyleTable;
358 23 : m_poStyleTable = nullptr;
359 : }
360 :
361 187926 : if (m_poPrivate != nullptr)
362 : {
363 187926 : if (m_poPrivate->hMutex != nullptr)
364 21593 : CPLDestroyMutex(m_poPrivate->hMutex);
365 :
366 : #if defined(__COVERITY__) || defined(DEBUG)
367 : // Not needed since at destruction there is no risk of concurrent use.
368 375852 : std::lock_guard oLock(m_poPrivate->m_oMutexWKT);
369 : #endif
370 187926 : CPLFree(m_poPrivate->m_pszWKTCached);
371 187926 : if (m_poPrivate->m_poSRSCached)
372 : {
373 0 : m_poPrivate->m_poSRSCached->Release();
374 : }
375 187926 : CPLFree(m_poPrivate->m_pszWKTGCPCached);
376 187926 : if (m_poPrivate->m_poSRSGCPCached)
377 : {
378 0 : m_poPrivate->m_poSRSGCPCached->Release();
379 : }
380 : }
381 :
382 187926 : delete m_poPrivate;
383 :
384 187926 : CSLDestroy(papszOpenOptions);
385 187926 : }
386 :
387 : /************************************************************************/
388 : /* Close() */
389 : /************************************************************************/
390 :
391 : /** Do final cleanup before a dataset is destroyed.
392 : *
393 : * This method is typically called by GDALClose() or the destructor of a
394 : * GDALDataset subclass. It might also be called by C++ users before
395 : * destroying a dataset. It should not be called on a shared dataset whose
396 : * reference count is greater than one.
397 : *
398 : * It gives a last chance to the closing process to return an error code if
399 : * something goes wrong, in particular in creation / update scenarios where
400 : * file write or network communication might occur when finalizing the dataset.
401 : *
402 : * Implementations should be robust to this method to be called several times
403 : * (on subsequent calls, it should do nothing and return CE_None).
404 : * Once it has been called, no other method than Close() or the dataset
405 : * destructor should be called. RasterBand or OGRLayer owned by the dataset
406 : * should be assumed as no longer being valid.
407 : *
408 : * If a driver implements this method, it must also call it from its
409 : * dataset destructor.
410 : *
411 : * Starting with GDAL 3.13, this function may report progress if a progress
412 : * callback if provided in the pfnProgress argument and if the dataset returns
413 : * true for GDALDataset::GetCloseReportsProgress()
414 : *
415 : * This is the equivalent of C function GDALDatasetRunCloseWithoutDestroying()
416 : * or GDALDatasetRunCloseWithoutDestroyingEx()
417 : *
418 : * A typical implementation might look as the following
419 : * \code{.cpp}
420 : *
421 : * MyDataset::~MyDataset()
422 : * {
423 : * try
424 : * {
425 : * MyDataset::Close();
426 : * }
427 : * catch (const std::exception &exc)
428 : * {
429 : * // If Close() can throw exception
430 : * CPLError(CE_Failure, CPLE_AppDefined,
431 : * "Exception thrown in MyDataset::Close(): %s",
432 : * exc.what());
433 : * }
434 : * catch (...)
435 : * {
436 : * // If Close() can throw exception
437 : * CPLError(CE_Failure, CPLE_AppDefined,
438 : * "Exception thrown in MyDataset::Close()");
439 : * }
440 : * }
441 : *
442 : * CPLErr MyDataset::Close(GDALProgressFunc pfnProgress, void* pProgressData)
443 : * {
444 : * CPLErr eErr = CE_None;
445 : * if( nOpenFlags != OPEN_FLAGS_CLOSED )
446 : * {
447 : * eErr = MyDataset::FlushCache(true);
448 : *
449 : * // Do something driver specific
450 : * if (m_fpImage)
451 : * {
452 : * if( VSIFCloseL(m_fpImage) != 0 )
453 : * {
454 : * CPLError(CE_Failure, CPLE_FileIO, "VSIFCloseL() failed");
455 : * eErr = CE_Failure;
456 : * }
457 : * }
458 : *
459 : * // Call parent Close() implementation.
460 : * eErr = GDAL::Combine(eErr, MyParentDatasetClass::Close());
461 : * }
462 : * return eErr;
463 : * }
464 : * \endcode
465 : *
466 : * @param pfnProgress (since GDAL 3.13) Progress callback, or nullptr
467 : * @param pProgressData (since GDAL 3.13) User data of progress callback, or nullptr
468 : * @return CE_None if no error
469 : *
470 : * @since GDAL 3.7
471 : */
472 307640 : CPLErr GDALDataset::Close(GDALProgressFunc pfnProgress, void *pProgressData)
473 : {
474 : (void)pfnProgress;
475 : (void)pProgressData;
476 :
477 307640 : if (nOpenFlags != OPEN_FLAGS_CLOSED)
478 : {
479 : // Call UnregisterFromSharedDataset() before altering nOpenFlags
480 187926 : UnregisterFromSharedDataset();
481 :
482 187926 : nOpenFlags = OPEN_FLAGS_CLOSED;
483 : }
484 :
485 307640 : if (IsMarkedSuppressOnClose())
486 : {
487 3534 : if (poDriver == nullptr ||
488 : // Someone issuing Create("foo.tif") on a
489 : // memory driver doesn't expect files with those names to be deleted
490 : // on a file system...
491 : // This is somewhat messy. Ideally there should be a way for the
492 : // driver to overload the default behavior
493 1723 : (!EQUAL(poDriver->GetDescription(), "MEM") &&
494 1645 : !EQUAL(poDriver->GetDescription(), "Memory")))
495 : {
496 1733 : if (VSIUnlink(GetDescription()) == 0)
497 683 : UnMarkSuppressOnClose();
498 : }
499 : }
500 :
501 307640 : return CE_None;
502 : }
503 :
504 : /************************************************************************/
505 : /* GDALDatasetRunCloseWithoutDestroying() */
506 : /************************************************************************/
507 :
508 : /** Run the Close() method, without running destruction of the object.
509 : *
510 : * This ensures that content that should be written to file is written and
511 : * that all file descriptors are closed.
512 : *
513 : * Note that this is different from GDALClose() which also destroys
514 : * the underlying C++ object. GDALClose() or GDALReleaseDataset() are actually
515 : * the only functions that can be safely called on the dataset handle after
516 : * this function has been called.
517 : *
518 : * Most users want to use GDALClose() or GDALReleaseDataset() rather than
519 : * this function.
520 : *
521 : * This function is equivalent to the C++ method GDALDataset:Close()
522 : *
523 : * @param hDS dataset handle.
524 : * @return CE_None if no error
525 : *
526 : * @since GDAL 3.12
527 : * @see GDALClose(), GDALDatasetRunCloseWithoutDestroyingEx()
528 : */
529 0 : CPLErr GDALDatasetRunCloseWithoutDestroying(GDALDatasetH hDS)
530 : {
531 0 : VALIDATE_POINTER1(hDS, __func__, CE_Failure);
532 0 : return GDALDataset::FromHandle(hDS)->Close();
533 : }
534 :
535 : /************************************************************************/
536 : /* GDALDatasetRunCloseWithoutDestroyingEx() */
537 : /************************************************************************/
538 :
539 : /** Run the Close() method, without running destruction of the object.
540 : *
541 : * This ensures that content that should be written to file is written and
542 : * that all file descriptors are closed.
543 : *
544 : * Note that this is different from GDALClose() which also destroys
545 : * the underlying C++ object. GDALClose() or GDALReleaseDataset() are actually
546 : * the only functions that can be safely called on the dataset handle after
547 : * this function has been called.
548 : *
549 : * Most users want to use GDALClose() or GDALReleaseDataset() rather than
550 : * this function.
551 : *
552 : * This function may report progress if a progress
553 : * callback if provided in the pfnProgress argument and if the dataset returns
554 : * true for GDALDataset::GetCloseReportsProgress()
555 : *
556 : * This function is equivalent to the C++ method GDALDataset:Close()
557 : *
558 : * @param hDS dataset handle.
559 : * @param pfnProgress Progress callback, or nullptr
560 : * @param pProgressData User data of progress callback, or nullptr
561 : *
562 : * @return CE_None if no error
563 : *
564 : * @since GDAL 3.13
565 : * @see GDALClose()
566 : */
567 12 : CPLErr GDALDatasetRunCloseWithoutDestroyingEx(GDALDatasetH hDS,
568 : GDALProgressFunc pfnProgress,
569 : void *pProgressData)
570 : {
571 12 : VALIDATE_POINTER1(hDS, __func__, CE_Failure);
572 12 : return GDALDataset::FromHandle(hDS)->Close(pfnProgress, pProgressData);
573 : }
574 :
575 : /************************************************************************/
576 : /* GetCloseReportsProgress() */
577 : /************************************************************************/
578 :
579 : /** Returns whether the Close() operation will report progress / is a potential
580 : * lengthy operation.
581 : *
582 : * At time of writing, only the COG driver will return true, if the dataset
583 : * has been created through the GDALDriver::Create() interface.
584 : *
585 : * This method is equivalent to the C function GDALDatasetGetCloseReportsProgress()
586 : *
587 : * @return true if the Close() operation will report progress
588 : * @since GDAL 3.13
589 : * @see Close()
590 : */
591 220 : bool GDALDataset::GetCloseReportsProgress() const
592 : {
593 220 : return false;
594 : }
595 :
596 : /************************************************************************/
597 : /* GDALDatasetGetCloseReportsProgress() */
598 : /************************************************************************/
599 :
600 : /** Returns whether the Close() operation will report progress / is a potential
601 : * lengthy operation.
602 : *
603 : * This function is equivalent to the C++ method GDALDataset::GetCloseReportsProgress()
604 : *
605 : * @param hDS dataset handle.
606 : * @return CE_None if no error
607 : *
608 : * @return true if the Close() operation will report progress
609 : * @since GDAL 3.13
610 : * @see GDALClose()
611 : */
612 2 : bool GDALDatasetGetCloseReportsProgress(GDALDatasetH hDS)
613 : {
614 2 : VALIDATE_POINTER1(hDS, __func__, false);
615 2 : return GDALDataset::FromHandle(hDS)->GetCloseReportsProgress();
616 : }
617 :
618 : /************************************************************************/
619 : /* CanReopenWithCurrentDescription() */
620 : /************************************************************************/
621 :
622 : /** Returns whether, once this dataset is closed, it can be re-opened with
623 : * Open() using the current value of GetDescription()
624 : *
625 : * The default implementation returns true. Some drivers, like MVT in Create()
626 : * mode, can return false. Some drivers return true, but the re-opened dataset
627 : * may be opened by another driver (e.g. the COG driver will return true, but
628 : * the driver used for re-opening is GTiff).
629 : *
630 : * @return true if the dataset can be re-opened using the value as
631 : * GetDescription() as connection string for Open()
632 : * @since GDAL 3.13
633 : */
634 2 : bool GDALDataset::CanReopenWithCurrentDescription() const
635 : {
636 2 : return true;
637 : }
638 :
639 : /************************************************************************/
640 : /* UnregisterFromSharedDataset() */
641 : /************************************************************************/
642 :
643 265245 : void GDALDataset::UnregisterFromSharedDataset()
644 : {
645 265245 : if (!(!bIsInternal && bShared && poAllDatasetMap && phSharedDatasetSet))
646 264832 : return;
647 :
648 826 : CPLMutexHolderD(&hDLMutex);
649 :
650 : std::map<GDALDataset *, GIntBig>::iterator oIter =
651 413 : poAllDatasetMap->find(this);
652 413 : CPLAssert(oIter != poAllDatasetMap->end());
653 413 : const GIntBig nPIDCreatorForShared = oIter->second;
654 413 : bShared = false;
655 : SharedDatasetCtxt sStruct;
656 413 : sStruct.nPID = nPIDCreatorForShared;
657 413 : sStruct.nOpenFlags = nOpenFlags & ~GDAL_OF_SHARED;
658 413 : sStruct.pszDescription = const_cast<char *>(GetDescription());
659 : std::string osConcatenatedOpenOptions =
660 826 : GDALSharedDatasetConcatenateOpenOptions(papszOpenOptions);
661 413 : sStruct.pszConcatenatedOpenOptions = &osConcatenatedOpenOptions[0];
662 413 : sStruct.poDS = nullptr;
663 : SharedDatasetCtxt *psStruct = static_cast<SharedDatasetCtxt *>(
664 413 : CPLHashSetLookup(phSharedDatasetSet, &sStruct));
665 413 : if (psStruct && psStruct->poDS == this)
666 : {
667 412 : CPLHashSetRemove(phSharedDatasetSet, psStruct);
668 : }
669 : else
670 : {
671 1 : CPLDebug("GDAL",
672 : "Should not happen. Cannot find %s, "
673 : "this=%p in phSharedDatasetSet",
674 1 : GetDescription(), this);
675 : }
676 : }
677 :
678 : /************************************************************************/
679 : /* AddToDatasetOpenList() */
680 : /************************************************************************/
681 :
682 78661 : void GDALDataset::AddToDatasetOpenList()
683 : {
684 : /* -------------------------------------------------------------------- */
685 : /* Add this dataset to the open dataset list. */
686 : /* -------------------------------------------------------------------- */
687 78661 : bIsInternal = false;
688 :
689 78661 : CPLMutexHolderD(&hDLMutex);
690 :
691 78661 : if (poAllDatasetMap == nullptr)
692 31790 : poAllDatasetMap = new std::map<GDALDataset *, GIntBig>;
693 78661 : (*poAllDatasetMap)[this] = -1;
694 78661 : }
695 :
696 : /************************************************************************/
697 : /* FlushCache() */
698 : /************************************************************************/
699 :
700 : /**
701 : * \brief Flush all write cached data to disk.
702 : *
703 : * Any raster (or other GDAL) data written via GDAL calls, but buffered
704 : * internally will be written to disk.
705 : *
706 : * The default implementation of this method just calls the FlushCache() method
707 : * on each of the raster bands and the SyncToDisk() method
708 : * on each of the layers. Conceptually, calling FlushCache() on a dataset
709 : * should include any work that might be accomplished by calling SyncToDisk()
710 : * on layers in that dataset.
711 : *
712 : * Using this method does not prevent use from calling GDALClose()
713 : * to properly close a dataset and ensure that important data not addressed
714 : * by FlushCache() is written in the file.
715 : *
716 : * This method is the same as the C function GDALFlushCache().
717 : *
718 : * @param bAtClosing Whether this is called from a GDALDataset destructor
719 : * @return CE_None in case of success (note: return value added in GDAL 3.7)
720 : */
721 :
722 125544 : CPLErr GDALDataset::FlushCache(bool bAtClosing)
723 :
724 : {
725 125544 : CPLErr eErr = CE_None;
726 : // This sometimes happens if a dataset is destroyed before completely
727 : // built.
728 :
729 125544 : if (papoBands)
730 : {
731 1945220 : for (int i = 0; i < nBands; ++i)
732 : {
733 1834600 : if (papoBands[i])
734 : {
735 1834600 : if (papoBands[i]->FlushCache(bAtClosing) != CE_None)
736 7 : eErr = CE_Failure;
737 : }
738 : }
739 : }
740 :
741 125544 : const int nLayers = GetLayerCount();
742 : // cppcheck-suppress knownConditionTrueFalse
743 125544 : if (nLayers > 0)
744 : {
745 17012 : CPLMutexHolderD(m_poPrivate ? &(m_poPrivate->hMutex) : nullptr);
746 26439 : for (int i = 0; i < nLayers; ++i)
747 : {
748 17933 : OGRLayer *poLayer = GetLayer(i);
749 :
750 17933 : if (poLayer)
751 : {
752 17933 : if (poLayer->SyncToDisk() != OGRERR_NONE)
753 1 : eErr = CE_Failure;
754 : }
755 : }
756 : }
757 :
758 125544 : return eErr;
759 : }
760 :
761 : /************************************************************************/
762 : /* GDALFlushCache() */
763 : /************************************************************************/
764 :
765 : /**
766 : * \brief Flush all write cached data to disk.
767 : *
768 : * @see GDALDataset::FlushCache().
769 : * @return CE_None in case of success (note: return value added in GDAL 3.7)
770 : */
771 :
772 5220 : CPLErr CPL_STDCALL GDALFlushCache(GDALDatasetH hDS)
773 :
774 : {
775 5220 : VALIDATE_POINTER1(hDS, "GDALFlushCache", CE_Failure);
776 :
777 5220 : return GDALDataset::FromHandle(hDS)->FlushCache(false);
778 : }
779 :
780 : /************************************************************************/
781 : /* DropCache() */
782 : /************************************************************************/
783 :
784 : /**
785 : * \brief Drop all write cached data
786 : *
787 : * This method is the same as the C function GDALDropCache().
788 : *
789 : * @return CE_None in case of success
790 : * @since 3.9
791 : */
792 :
793 1 : CPLErr GDALDataset::DropCache()
794 :
795 : {
796 1 : CPLErr eErr = CE_None;
797 :
798 1 : if (papoBands)
799 : {
800 2 : for (int i = 0; i < nBands; ++i)
801 : {
802 1 : if (papoBands[i])
803 : {
804 1 : if (papoBands[i]->DropCache() != CE_None)
805 0 : eErr = CE_Failure;
806 : }
807 : }
808 : }
809 :
810 1 : return eErr;
811 : }
812 :
813 : /************************************************************************/
814 : /* GDALDropCache() */
815 : /************************************************************************/
816 :
817 : /**
818 : * \brief Drop all write cached data
819 : *
820 : * @see GDALDataset::DropCache().
821 : * @return CE_None in case of success
822 : * @since 3.9
823 : */
824 :
825 0 : CPLErr CPL_STDCALL GDALDropCache(GDALDatasetH hDS)
826 :
827 : {
828 0 : VALIDATE_POINTER1(hDS, "GDALDropCache", CE_Failure);
829 :
830 0 : return GDALDataset::FromHandle(hDS)->DropCache();
831 : }
832 :
833 : /************************************************************************/
834 : /* GetEstimatedRAMUsage() */
835 : /************************************************************************/
836 :
837 : /**
838 : * \brief Return the intrinsic RAM usage of this dataset.
839 : *
840 : * The returned value should take into account caches in the underlying driver
841 : * and decoding library, but not the usage related to the GDAL block cache.
842 : *
843 : * At time of writing, this method is only implemented in the JP2OpenJPEG
844 : * driver. For single-tiled JPEG2000 images, the decoding of the image,
845 : * even partially, involves allocating at least
846 : * width * height * number_of_bands * sizeof(uint32_t) bytes inside the libopenjp2
847 : * library.
848 : *
849 : * This method is used by the GDALDatasetPool class, itself used by the GDAL VRT
850 : * driver, to determine how long a dataset in the pool must be kept open, given
851 : * the RAM usage of the dataset with respect to the usable total RAM.
852 : *
853 : * @since GDAL 3.7
854 : * @return RAM usage in bytes, or -1 if unknown (the default implementation
855 : * returns -1)
856 : */
857 :
858 3367 : GIntBig GDALDataset::GetEstimatedRAMUsage()
859 : {
860 3367 : return -1;
861 : }
862 :
863 : /************************************************************************/
864 : /* BlockBasedFlushCache() */
865 : /* */
866 : /* This helper method can be called by the */
867 : /* GDALDataset::FlushCache() for particular drivers to ensure */
868 : /* that buffers will be flushed in a manner suitable for pixel */
869 : /* interleaved (by block) IO. That is, if all the bands have */
870 : /* the same size blocks then a given block will be flushed for */
871 : /* all bands before proceeding to the next block. */
872 : /************************************************************************/
873 :
874 : //! @cond Doxygen_Suppress
875 350 : CPLErr GDALDataset::BlockBasedFlushCache(bool bAtClosing)
876 :
877 : {
878 350 : GDALRasterBand *poBand1 = GetRasterBand(1);
879 350 : if (poBand1 == nullptr || (IsMarkedSuppressOnClose() && bAtClosing))
880 : {
881 7 : return GDALDataset::FlushCache(bAtClosing);
882 : }
883 :
884 343 : int nBlockXSize = 0;
885 343 : int nBlockYSize = 0;
886 343 : poBand1->GetBlockSize(&nBlockXSize, &nBlockYSize);
887 :
888 : /* -------------------------------------------------------------------- */
889 : /* Verify that all bands match. */
890 : /* -------------------------------------------------------------------- */
891 1108 : for (int iBand = 1; iBand < nBands; ++iBand)
892 : {
893 765 : GDALRasterBand *poBand = GetRasterBand(iBand + 1);
894 :
895 : int nThisBlockXSize, nThisBlockYSize;
896 765 : poBand->GetBlockSize(&nThisBlockXSize, &nThisBlockYSize);
897 765 : if (nThisBlockXSize != nBlockXSize && nThisBlockYSize != nBlockYSize)
898 : {
899 0 : return GDALDataset::FlushCache(bAtClosing);
900 : }
901 : }
902 :
903 : /* -------------------------------------------------------------------- */
904 : /* Now flush writable data. */
905 : /* -------------------------------------------------------------------- */
906 794 : for (int iY = 0; iY < poBand1->nBlocksPerColumn; ++iY)
907 : {
908 991 : for (int iX = 0; iX < poBand1->nBlocksPerRow; ++iX)
909 : {
910 1690 : for (int iBand = 0; iBand < nBands; ++iBand)
911 : {
912 1150 : const CPLErr eErr = papoBands[iBand]->FlushBlock(iX, iY);
913 :
914 1150 : if (eErr != CE_None)
915 0 : return CE_Failure;
916 : }
917 : }
918 : }
919 343 : return CE_None;
920 : }
921 :
922 : /************************************************************************/
923 : /* RasterInitialize() */
924 : /* */
925 : /* Initialize raster size */
926 : /************************************************************************/
927 :
928 0 : void GDALDataset::RasterInitialize(int nXSize, int nYSize)
929 :
930 : {
931 0 : CPLAssert(nXSize > 0 && nYSize > 0);
932 :
933 0 : nRasterXSize = nXSize;
934 0 : nRasterYSize = nYSize;
935 0 : }
936 :
937 : //! @endcond
938 :
939 : /************************************************************************/
940 : /* AddBand() */
941 : /************************************************************************/
942 :
943 : /**
944 : * \fn GDALDataset::AddBand(GDALDataType, char**)
945 : * \brief Add a band to a dataset.
946 : *
947 : * This method will add a new band to the dataset if the underlying format
948 : * supports this action. Most formats do not.
949 : *
950 : * Note that the new GDALRasterBand is not returned. It may be fetched
951 : * after successful completion of the method by calling
952 : * GDALDataset::GetRasterBand(GDALDataset::GetRasterCount()) as the newest
953 : * band will always be the last band.
954 : *
955 : * @param eType the data type of the pixels in the new band.
956 : *
957 : * @param papszOptions a list of NAME=VALUE option strings. The supported
958 : * options are format specific. NULL may be passed by default.
959 : *
960 : * @return CE_None on success or CE_Failure on failure.
961 : */
962 :
963 0 : CPLErr GDALDataset::AddBand(CPL_UNUSED GDALDataType eType,
964 : CPL_UNUSED CSLConstList papszOptions)
965 :
966 : {
967 0 : ReportError(CE_Failure, CPLE_NotSupported,
968 : "Dataset does not support the AddBand() method.");
969 :
970 0 : return CE_Failure;
971 : }
972 :
973 : /************************************************************************/
974 : /* GDALAddBand() */
975 : /************************************************************************/
976 :
977 : /**
978 : * \brief Add a band to a dataset.
979 : *
980 : * @see GDALDataset::AddBand().
981 : */
982 :
983 32 : CPLErr CPL_STDCALL GDALAddBand(GDALDatasetH hDataset, GDALDataType eType,
984 : CSLConstList papszOptions)
985 :
986 : {
987 32 : VALIDATE_POINTER1(hDataset, "GDALAddBand", CE_Failure);
988 :
989 64 : return GDALDataset::FromHandle(hDataset)->AddBand(
990 32 : eType, const_cast<char **>(papszOptions));
991 : }
992 :
993 : /************************************************************************/
994 : /* SetBand() */
995 : /************************************************************************/
996 :
997 : //! @cond Doxygen_Suppress
998 : /** Set a band in the band array, updating the band count, and array size
999 : * appropriately.
1000 : *
1001 : * @param nNewBand new band number (indexing starts at 1)
1002 : * @param poBand band object.
1003 : */
1004 :
1005 1686350 : void GDALDataset::SetBand(int nNewBand, GDALRasterBand *poBand)
1006 :
1007 : {
1008 : /* -------------------------------------------------------------------- */
1009 : /* Do we need to grow the bands list? */
1010 : /* -------------------------------------------------------------------- */
1011 1686350 : if (nBands < nNewBand || papoBands == nullptr)
1012 : {
1013 951089 : GDALRasterBand **papoNewBands = nullptr;
1014 :
1015 951089 : if (papoBands == nullptr)
1016 102480 : papoNewBands = static_cast<GDALRasterBand **>(VSICalloc(
1017 102480 : sizeof(GDALRasterBand *), std::max(nNewBand, nBands)));
1018 : else
1019 : papoNewBands = static_cast<GDALRasterBand **>(
1020 848609 : VSIRealloc(papoBands, sizeof(GDALRasterBand *) *
1021 848609 : std::max(nNewBand, nBands)));
1022 951089 : if (papoNewBands == nullptr)
1023 : {
1024 0 : ReportError(CE_Failure, CPLE_OutOfMemory,
1025 : "Cannot allocate band array");
1026 0 : return;
1027 : }
1028 :
1029 951089 : papoBands = papoNewBands;
1030 :
1031 1848740 : for (int i = nBands; i < nNewBand; ++i)
1032 897649 : papoBands[i] = nullptr;
1033 :
1034 951089 : nBands = std::max(nBands, nNewBand);
1035 :
1036 951089 : if (m_poPrivate)
1037 : {
1038 951089 : for (int i = static_cast<int>(m_poPrivate->m_anBandMap.size());
1039 2637440 : i < nBands; ++i)
1040 : {
1041 1686350 : m_poPrivate->m_anBandMap.push_back(i + 1);
1042 : }
1043 : }
1044 : }
1045 :
1046 : /* -------------------------------------------------------------------- */
1047 : /* Set the band. Resetting the band is currently not permitted. */
1048 : /* -------------------------------------------------------------------- */
1049 1686350 : if (papoBands[nNewBand - 1] != nullptr)
1050 : {
1051 0 : ReportError(CE_Failure, CPLE_NotSupported,
1052 : "Cannot set band %d as it is already set", nNewBand);
1053 0 : return;
1054 : }
1055 :
1056 1686350 : papoBands[nNewBand - 1] = poBand;
1057 :
1058 : /* -------------------------------------------------------------------- */
1059 : /* Set back reference information on the raster band. Note */
1060 : /* that the GDALDataset is a friend of the GDALRasterBand */
1061 : /* specifically to allow this. */
1062 : /* -------------------------------------------------------------------- */
1063 1686350 : poBand->nBand = nNewBand;
1064 1686350 : poBand->poDS = this;
1065 1686350 : poBand->nRasterXSize = nRasterXSize;
1066 1686350 : poBand->nRasterYSize = nRasterYSize;
1067 1686350 : poBand->eAccess = eAccess; // Default access to be same as dataset.
1068 : }
1069 :
1070 : //! @endcond
1071 :
1072 : /************************************************************************/
1073 : /* SetBand() */
1074 : /************************************************************************/
1075 :
1076 : //! @cond Doxygen_Suppress
1077 : /** Set a band in the band array, updating the band count, and array size
1078 : * appropriately.
1079 : *
1080 : * @param nNewBand new band number (indexing starts at 1)
1081 : * @param poBand band object.
1082 : */
1083 :
1084 1112270 : void GDALDataset::SetBand(int nNewBand, std::unique_ptr<GDALRasterBand> poBand)
1085 : {
1086 1112270 : SetBand(nNewBand, poBand.release());
1087 1112270 : }
1088 :
1089 : //! @endcond
1090 :
1091 : /************************************************************************/
1092 : /* GetRasterXSize() */
1093 : /************************************************************************/
1094 :
1095 : /**
1096 :
1097 : \brief Fetch raster width in pixels.
1098 :
1099 : Equivalent of the C function GDALGetRasterXSize().
1100 :
1101 : @return the width in pixels of raster bands in this GDALDataset.
1102 :
1103 : */
1104 :
1105 723241 : int GDALDataset::GetRasterXSize() const
1106 : {
1107 723241 : return nRasterXSize;
1108 : }
1109 :
1110 : /************************************************************************/
1111 : /* GDALGetRasterXSize() */
1112 : /************************************************************************/
1113 :
1114 : /**
1115 : * \brief Fetch raster width in pixels.
1116 : *
1117 : * @see GDALDataset::GetRasterXSize().
1118 : */
1119 :
1120 40387 : int CPL_STDCALL GDALGetRasterXSize(GDALDatasetH hDataset)
1121 :
1122 : {
1123 40387 : VALIDATE_POINTER1(hDataset, "GDALGetRasterXSize", 0);
1124 :
1125 40387 : return GDALDataset::FromHandle(hDataset)->GetRasterXSize();
1126 : }
1127 :
1128 : /************************************************************************/
1129 : /* GetRasterYSize() */
1130 : /************************************************************************/
1131 :
1132 : /**
1133 :
1134 : \brief Fetch raster height in pixels.
1135 :
1136 : Equivalent of the C function GDALGetRasterYSize().
1137 :
1138 : @return the height in pixels of raster bands in this GDALDataset.
1139 :
1140 : */
1141 :
1142 613064 : int GDALDataset::GetRasterYSize() const
1143 : {
1144 613064 : return nRasterYSize;
1145 : }
1146 :
1147 : /************************************************************************/
1148 : /* GDALGetRasterYSize() */
1149 : /************************************************************************/
1150 :
1151 : /**
1152 : * \brief Fetch raster height in pixels.
1153 : *
1154 : * @see GDALDataset::GetRasterYSize().
1155 : */
1156 :
1157 39520 : int CPL_STDCALL GDALGetRasterYSize(GDALDatasetH hDataset)
1158 :
1159 : {
1160 39520 : VALIDATE_POINTER1(hDataset, "GDALGetRasterYSize", 0);
1161 :
1162 39520 : return GDALDataset::FromHandle(hDataset)->GetRasterYSize();
1163 : }
1164 :
1165 : /************************************************************************/
1166 : /* GetRasterBand() */
1167 : /************************************************************************/
1168 :
1169 : /**
1170 :
1171 : \brief Fetch a band object for a dataset.
1172 :
1173 : See GetBands() for a C++ iterator version of this method.
1174 :
1175 : Equivalent of the C function GDALGetRasterBand().
1176 :
1177 : @param nBandId the index number of the band to fetch, from 1 to
1178 : GetRasterCount().
1179 :
1180 : @return the nBandId th band object
1181 :
1182 : */
1183 :
1184 12686800 : GDALRasterBand *GDALDataset::GetRasterBand(int nBandId)
1185 :
1186 : {
1187 12686800 : if (papoBands)
1188 : {
1189 12686800 : if (nBandId < 1 || nBandId > nBands)
1190 : {
1191 12 : ReportError(CE_Failure, CPLE_IllegalArg,
1192 : "GDALDataset::GetRasterBand(%d) - Illegal band #\n",
1193 : nBandId);
1194 12 : return nullptr;
1195 : }
1196 :
1197 12686800 : return papoBands[nBandId - 1];
1198 : }
1199 13 : return nullptr;
1200 : }
1201 :
1202 : /************************************************************************/
1203 : /* GetRasterBand() */
1204 : /************************************************************************/
1205 :
1206 : /**
1207 :
1208 : \brief Fetch a band object for a dataset.
1209 :
1210 : See GetBands() for a C++ iterator version of this method.
1211 :
1212 : Equivalent of the C function GDALGetRasterBand().
1213 :
1214 : @param nBandId the index number of the band to fetch, from 1 to
1215 : GetRasterCount().
1216 :
1217 : @return the nBandId th band object
1218 :
1219 : */
1220 :
1221 594 : const GDALRasterBand *GDALDataset::GetRasterBand(int nBandId) const
1222 :
1223 : {
1224 594 : if (papoBands)
1225 : {
1226 594 : if (nBandId < 1 || nBandId > nBands)
1227 : {
1228 0 : ReportError(CE_Failure, CPLE_IllegalArg,
1229 : "GDALDataset::GetRasterBand(%d) - Illegal band #\n",
1230 : nBandId);
1231 0 : return nullptr;
1232 : }
1233 :
1234 594 : return papoBands[nBandId - 1];
1235 : }
1236 0 : return nullptr;
1237 : }
1238 :
1239 : /************************************************************************/
1240 : /* GDALGetRasterBand() */
1241 : /************************************************************************/
1242 :
1243 : /**
1244 : * \brief Fetch a band object for a dataset.
1245 : * @see GDALDataset::GetRasterBand().
1246 : */
1247 :
1248 414211 : GDALRasterBandH CPL_STDCALL GDALGetRasterBand(GDALDatasetH hDS, int nBandId)
1249 :
1250 : {
1251 414211 : VALIDATE_POINTER1(hDS, "GDALGetRasterBand", nullptr);
1252 :
1253 414211 : return GDALRasterBand::ToHandle(
1254 414211 : GDALDataset::FromHandle(hDS)->GetRasterBand(nBandId));
1255 : }
1256 :
1257 : /************************************************************************/
1258 : /* GetRasterCount() */
1259 : /************************************************************************/
1260 :
1261 : /**
1262 : * \brief Fetch the number of raster bands on this dataset.
1263 : *
1264 : * Same as the C function GDALGetRasterCount().
1265 : *
1266 : * @return the number of raster bands.
1267 : */
1268 :
1269 6466190 : int GDALDataset::GetRasterCount() const
1270 : {
1271 6466190 : return papoBands ? nBands : 0;
1272 : }
1273 :
1274 : /************************************************************************/
1275 : /* GDALGetRasterCount() */
1276 : /************************************************************************/
1277 :
1278 : /**
1279 : * \brief Fetch the number of raster bands on this dataset.
1280 : *
1281 : * @see GDALDataset::GetRasterCount().
1282 : */
1283 :
1284 387032 : int CPL_STDCALL GDALGetRasterCount(GDALDatasetH hDS)
1285 :
1286 : {
1287 387032 : VALIDATE_POINTER1(hDS, "GDALGetRasterCount", 0);
1288 :
1289 387032 : return GDALDataset::FromHandle(hDS)->GetRasterCount();
1290 : }
1291 :
1292 : /************************************************************************/
1293 : /* GetProjectionRef() */
1294 : /************************************************************************/
1295 :
1296 : /**
1297 : * \brief Fetch the projection definition string for this dataset.
1298 : *
1299 : * Same as the C function GDALGetProjectionRef().
1300 : *
1301 : * The returned string defines the projection coordinate system of the
1302 : * image in OpenGIS WKT format. It should be suitable for use with the
1303 : * OGRSpatialReference class.
1304 : *
1305 : * When a projection definition is not available an empty (but not NULL)
1306 : * string is returned.
1307 : *
1308 : * \note Starting with GDAL 3.0, this is a compatibility layer around
1309 : * GetSpatialRef()
1310 : *
1311 : * @return a pointer to an internal projection reference string. It should
1312 : * not be altered, freed or expected to last for long.
1313 : *
1314 : * @see https://gdal.org/tutorials/osr_api_tut.html
1315 : */
1316 :
1317 5297 : const char *GDALDataset::GetProjectionRef() const
1318 : {
1319 5297 : const auto poSRS = GetSpatialRef();
1320 5297 : if (!poSRS || !m_poPrivate)
1321 : {
1322 2384 : return "";
1323 : }
1324 2913 : char *pszWKT = nullptr;
1325 2913 : poSRS->exportToWkt(&pszWKT);
1326 2913 : if (!pszWKT)
1327 : {
1328 0 : return "";
1329 : }
1330 :
1331 : // If called on a thread-safe dataset, we might be called by several
1332 : // threads, so make sure our accesses to m_pszWKTCached are protected
1333 : // by a mutex.
1334 5826 : std::lock_guard oLock(m_poPrivate->m_oMutexWKT);
1335 2913 : if (m_poPrivate->m_pszWKTCached &&
1336 762 : strcmp(pszWKT, m_poPrivate->m_pszWKTCached) == 0)
1337 : {
1338 761 : CPLFree(pszWKT);
1339 761 : return m_poPrivate->m_pszWKTCached;
1340 : }
1341 2152 : CPLFree(m_poPrivate->m_pszWKTCached);
1342 2152 : m_poPrivate->m_pszWKTCached = pszWKT;
1343 2152 : return m_poPrivate->m_pszWKTCached;
1344 : }
1345 :
1346 : /************************************************************************/
1347 : /* GetSpatialRef() */
1348 : /************************************************************************/
1349 :
1350 : static thread_local int tlsEnableLayersInGetSpatialRefCounter = 0;
1351 :
1352 : /**
1353 : * \brief Fetch the spatial reference for this dataset.
1354 : *
1355 : * Same as the C function GDALGetSpatialRef().
1356 : *
1357 : * When a projection definition is not available, null is returned. If used on
1358 : * a dataset where there are GCPs and not a geotransform, this method returns
1359 : * null. Use GetGCPSpatialRef() instead.
1360 : *
1361 : * Since GDAL 3.12, the default implementation of this method will iterate over
1362 : * vector layers and return their SRS if all geometry columns of all layers use
1363 : * the same SRS, or nullptr otherwise.
1364 : *
1365 : * @since GDAL 3.0
1366 : *
1367 : * @return a pointer to an internal object. It should not be altered or freed.
1368 : * Its lifetime will be the one of the dataset object.
1369 : *
1370 : * @see https://gdal.org/tutorials/osr_api_tut.html
1371 : */
1372 :
1373 17714 : const OGRSpatialReference *GDALDataset::GetSpatialRef() const
1374 : {
1375 17714 : if (tlsEnableLayersInGetSpatialRefCounter == 0)
1376 17664 : return GetSpatialRefVectorOnly();
1377 50 : return nullptr;
1378 : }
1379 :
1380 : /************************************************************************/
1381 : /* GetSpatialRefVectorOnly() */
1382 : /************************************************************************/
1383 :
1384 : /**
1385 : * \brief Fetch the spatial reference for this dataset (only for vector layers)
1386 : *
1387 : * The default implementation of this method will iterate over
1388 : * vector layers and return their SRS if all geometry columns of all layers use
1389 : * the same SRS, or nullptr otherwise.
1390 : *
1391 : * @since GDAL 3.12
1392 : *
1393 : * @return a pointer to an internal object. It should not be altered or freed.
1394 : * Its lifetime will be the one of the dataset object.
1395 : */
1396 :
1397 17664 : const OGRSpatialReference *GDALDataset::GetSpatialRefVectorOnly() const
1398 : {
1399 17664 : bool bInit = false;
1400 17664 : const OGRSpatialReference *poGlobalSRS = nullptr;
1401 33827 : for (const OGRLayer *poLayer : GetLayers())
1402 : {
1403 16164 : for (const auto *poGeomFieldDefn :
1404 48494 : poLayer->GetLayerDefn()->GetGeomFields())
1405 : {
1406 16167 : const auto *poSRS = poGeomFieldDefn->GetSpatialRef();
1407 16167 : if (!bInit)
1408 : {
1409 207 : bInit = true;
1410 207 : poGlobalSRS = poSRS;
1411 : }
1412 31918 : else if ((poSRS && !poGlobalSRS) || (!poSRS && poGlobalSRS) ||
1413 15958 : (poSRS && poGlobalSRS && !poSRS->IsSame(poGlobalSRS)))
1414 : {
1415 3 : CPLDebug("GDAL",
1416 : "Not all geometry fields or layers have the same CRS");
1417 3 : return nullptr;
1418 : }
1419 : }
1420 : }
1421 17661 : return poGlobalSRS;
1422 : }
1423 :
1424 : /************************************************************************/
1425 : /* GetSpatialRefRasterOnly() */
1426 : /************************************************************************/
1427 :
1428 : /**
1429 : * \brief Fetch the spatial reference for this dataset (ignoring vector layers)
1430 : *
1431 : * @since GDAL 3.12
1432 : *
1433 : * @return a pointer to an internal object. It should not be altered or freed.
1434 : * Its lifetime will be the one of the dataset object.
1435 : */
1436 :
1437 1075 : const OGRSpatialReference *GDALDataset::GetSpatialRefRasterOnly() const
1438 : {
1439 1075 : ++tlsEnableLayersInGetSpatialRefCounter;
1440 1075 : const auto poRet = GetSpatialRef();
1441 1075 : --tlsEnableLayersInGetSpatialRefCounter;
1442 1075 : return poRet;
1443 : }
1444 :
1445 : /************************************************************************/
1446 : /* GDALGetSpatialRef() */
1447 : /************************************************************************/
1448 :
1449 : /**
1450 : * \brief Fetch the spatial reference for this dataset.
1451 : *
1452 : * Same as the C++ method GDALDataset::GetSpatialRef()
1453 : *
1454 : * @since GDAL 3.0
1455 : *
1456 : * @see GDALDataset::GetSpatialRef()
1457 : */
1458 :
1459 7885 : OGRSpatialReferenceH GDALGetSpatialRef(GDALDatasetH hDS)
1460 :
1461 : {
1462 7885 : VALIDATE_POINTER1(hDS, "GDALGetSpatialRef", nullptr);
1463 :
1464 7885 : return OGRSpatialReference::ToHandle(const_cast<OGRSpatialReference *>(
1465 7885 : GDALDataset::FromHandle(hDS)->GetSpatialRef()));
1466 : }
1467 :
1468 : /************************************************************************/
1469 : /* GDALGetProjectionRef() */
1470 : /************************************************************************/
1471 :
1472 : /**
1473 : * \brief Fetch the projection definition string for this dataset.
1474 : *
1475 : * @see GDALDataset::GetProjectionRef()
1476 : */
1477 :
1478 1485 : const char *CPL_STDCALL GDALGetProjectionRef(GDALDatasetH hDS)
1479 :
1480 : {
1481 1485 : VALIDATE_POINTER1(hDS, "GDALGetProjectionRef", nullptr);
1482 :
1483 1485 : return GDALDataset::FromHandle(hDS)->GetProjectionRef();
1484 : }
1485 :
1486 : /************************************************************************/
1487 : /* SetProjection() */
1488 : /************************************************************************/
1489 :
1490 : /**
1491 : * \brief Set the projection reference string for this dataset.
1492 : *
1493 : * The string should be in OGC WKT or PROJ.4 format. An error may occur
1494 : * because of incorrectly specified projection strings, because the dataset
1495 : * is not writable, or because the dataset does not support the indicated
1496 : * projection. Many formats do not support writing projections.
1497 : *
1498 : * This method is the same as the C GDALSetProjection() function.
1499 : *
1500 : * \note Startig with GDAL 3.0, this is a compatibility layer around
1501 : * SetSpatialRef()
1502 :
1503 : * @param pszProjection projection reference string.
1504 : *
1505 : * @return CE_Failure if an error occurs, otherwise CE_None.
1506 : */
1507 :
1508 2598 : CPLErr GDALDataset::SetProjection(const char *pszProjection)
1509 : {
1510 2598 : if (pszProjection && pszProjection[0] != '\0')
1511 : {
1512 4812 : OGRSpatialReference oSRS;
1513 2406 : oSRS.SetAxisMappingStrategy(OAMS_TRADITIONAL_GIS_ORDER);
1514 2406 : if (oSRS.SetFromUserInput(pszProjection) != OGRERR_NONE)
1515 : {
1516 2 : return CE_Failure;
1517 : }
1518 2404 : return SetSpatialRef(&oSRS);
1519 : }
1520 : else
1521 : {
1522 192 : return SetSpatialRef(nullptr);
1523 : }
1524 : }
1525 :
1526 : /************************************************************************/
1527 : /* SetSpatialRef() */
1528 : /************************************************************************/
1529 :
1530 : /**
1531 : * \brief Set the spatial reference system for this dataset.
1532 : *
1533 : * An error may occur because the dataset
1534 : * is not writable, or because the dataset does not support the indicated
1535 : * projection. Many formats do not support writing projections.
1536 : *
1537 : * This method is the same as the C GDALSetSpatialRef() function.
1538 : *
1539 : * @since GDAL 3.0
1540 :
1541 : * @param poSRS spatial reference system object. nullptr can potentially be
1542 : * passed for drivers that support unsetting the SRS.
1543 : *
1544 : * @return CE_Failure if an error occurs, otherwise CE_None.
1545 : */
1546 :
1547 0 : CPLErr GDALDataset::SetSpatialRef(CPL_UNUSED const OGRSpatialReference *poSRS)
1548 : {
1549 0 : if (!(GetMOFlags() & GMO_IGNORE_UNIMPLEMENTED))
1550 0 : ReportError(CE_Failure, CPLE_NotSupported,
1551 : "Dataset does not support the SetSpatialRef() method.");
1552 0 : return CE_Failure;
1553 : }
1554 :
1555 : /************************************************************************/
1556 : /* GDALSetSpatialRef() */
1557 : /************************************************************************/
1558 :
1559 : /**
1560 : * \brief Set the spatial reference system for this dataset.
1561 : *
1562 : * @since GDAL 3.0
1563 : *
1564 : * @see GDALDataset::SetSpatialRef()
1565 : */
1566 :
1567 1446 : CPLErr GDALSetSpatialRef(GDALDatasetH hDS, OGRSpatialReferenceH hSRS)
1568 :
1569 : {
1570 1446 : VALIDATE_POINTER1(hDS, "GDALSetSpatialRef", CE_Failure);
1571 :
1572 2892 : return GDALDataset::FromHandle(hDS)->SetSpatialRef(
1573 1446 : OGRSpatialReference::FromHandle(hSRS));
1574 : }
1575 :
1576 : /************************************************************************/
1577 : /* GDALSetProjection() */
1578 : /************************************************************************/
1579 :
1580 : /**
1581 : * \brief Set the projection reference string for this dataset.
1582 : *
1583 : * @see GDALDataset::SetProjection()
1584 : */
1585 :
1586 1947 : CPLErr CPL_STDCALL GDALSetProjection(GDALDatasetH hDS,
1587 : const char *pszProjection)
1588 :
1589 : {
1590 1947 : VALIDATE_POINTER1(hDS, "GDALSetProjection", CE_Failure);
1591 :
1592 1947 : return GDALDataset::FromHandle(hDS)->SetProjection(pszProjection);
1593 : }
1594 :
1595 : /************************************************************************/
1596 : /* GetGeoTransform() */
1597 : /************************************************************************/
1598 :
1599 : /**
1600 : * \brief Fetch the affine transformation coefficients.
1601 : *
1602 : * Fetches the coefficients for transforming between pixel/line (P,L) raster
1603 : * space, and projection coordinates (Xp,Yp) space.
1604 : *
1605 : * \code
1606 : * Xp = gt.xorig + P*gt.xscale + L*gt.xrot;
1607 : * Yp = gt.yorig + P*padfTransform[4] + L*gt.yscale;
1608 : * \endcode
1609 : *
1610 : * In a north up image, gt.xscale is the pixel width, and
1611 : * gt.yscale is the pixel height. The upper left corner of the
1612 : * upper left pixel is at position (gt.xorig,gt.yorig).
1613 : *
1614 : * The default transform is (0,1,0,0,0,1) and should be returned even when
1615 : * a CE_Failure error is returned, such as for formats that don't support
1616 : * transformation to projection coordinates.
1617 : *
1618 : * This method does the same thing as the C GDALGetGeoTransform() function.
1619 : *
1620 : * @param gt an existing six double buffer into which the
1621 : * transformation will be placed.
1622 : *
1623 : * @return CE_None on success, or CE_Failure if no transform can be fetched.
1624 : *
1625 : * @since 3.12
1626 : */
1627 :
1628 16099 : CPLErr GDALDataset::GetGeoTransform(GDALGeoTransform >) const
1629 :
1630 : {
1631 16099 : gt = GDALGeoTransform();
1632 :
1633 16099 : return CE_Failure;
1634 : }
1635 :
1636 : /************************************************************************/
1637 : /* GetGeoTransform() */
1638 : /************************************************************************/
1639 :
1640 : /**
1641 : * \brief Fetch the affine transformation coefficients.
1642 : *
1643 : * Fetches the coefficients for transforming between pixel/line (P,L) raster
1644 : * space, and projection coordinates (Xp,Yp) space.
1645 : *
1646 : * \code
1647 : * Xp = padfTransform[0] + P*padfTransform[1] + L*padfTransform[2];
1648 : * Yp = padfTransform[3] + P*padfTransform[4] + L*padfTransform[5];
1649 : * \endcode
1650 : *
1651 : * In a north up image, padfTransform[1] is the pixel width, and
1652 : * padfTransform[5] is the pixel height. The upper left corner of the
1653 : * upper left pixel is at position (padfTransform[0],padfTransform[3]).
1654 : *
1655 : * The default transform is (0,1,0,0,0,1) and should be returned even when
1656 : * a CE_Failure error is returned, such as for formats that don't support
1657 : * transformation to projection coordinates.
1658 : *
1659 : * This method does the same thing as the C GDALGetGeoTransform() function.
1660 : *
1661 : * @param padfTransform an existing six double buffer into which the
1662 : * transformation will be placed.
1663 : *
1664 : * @return CE_None on success, or CE_Failure if no transform can be fetched.
1665 : *
1666 : * @deprecated since 3.12. Use GetGeoTransform(GDALGeoTransform&) instead
1667 : */
1668 :
1669 2 : CPLErr GDALDataset::GetGeoTransform(double *padfTransform) const
1670 :
1671 : {
1672 2 : return GetGeoTransform(
1673 2 : *reinterpret_cast<GDALGeoTransform *>(padfTransform));
1674 : }
1675 :
1676 : /************************************************************************/
1677 : /* GDALGetGeoTransform() */
1678 : /************************************************************************/
1679 :
1680 : /**
1681 : * \brief Fetch the affine transformation coefficients.
1682 : *
1683 : * @see GDALDataset::GetGeoTransform()
1684 : */
1685 :
1686 9715 : CPLErr CPL_STDCALL GDALGetGeoTransform(GDALDatasetH hDS, double *padfTransform)
1687 :
1688 : {
1689 9715 : VALIDATE_POINTER1(hDS, "GDALGetGeoTransform", CE_Failure);
1690 :
1691 19430 : return GDALDataset::FromHandle(hDS)->GetGeoTransform(
1692 9715 : *reinterpret_cast<GDALGeoTransform *>(padfTransform));
1693 : }
1694 :
1695 : /************************************************************************/
1696 : /* SetGeoTransform() */
1697 : /************************************************************************/
1698 :
1699 : /**
1700 : * \fn GDALDataset::SetGeoTransform(const GDALGeoTransform&)
1701 : * \brief Set the affine transformation coefficients.
1702 : *
1703 : * See GetGeoTransform() for details on the meaning of the padfTransform
1704 : * coefficients.
1705 : *
1706 : * This method does the same thing as the C GDALSetGeoTransform() function.
1707 : *
1708 : * @param gt the transformation coefficients to be written with the dataset.
1709 : *
1710 : * @return CE_None on success, or CE_Failure if this transform cannot be
1711 : * written.
1712 : *
1713 : * @since 3.12
1714 : */
1715 :
1716 0 : CPLErr GDALDataset::SetGeoTransform(CPL_UNUSED const GDALGeoTransform >)
1717 :
1718 : {
1719 0 : if (!(GetMOFlags() & GMO_IGNORE_UNIMPLEMENTED))
1720 0 : ReportError(CE_Failure, CPLE_NotSupported,
1721 : "SetGeoTransform() not supported for this dataset.");
1722 :
1723 0 : return CE_Failure;
1724 : }
1725 :
1726 : /************************************************************************/
1727 : /* SetGeoTransform() */
1728 : /************************************************************************/
1729 :
1730 : /**
1731 : * \brief Set the affine transformation coefficients.
1732 : *
1733 : * See GetGeoTransform() for details on the meaning of the padfTransform
1734 : * coefficients.
1735 : *
1736 : * This method does the same thing as the C GDALSetGeoTransform() function.
1737 : *
1738 : * @param padfTransform a six double buffer containing the transformation
1739 : * coefficients to be written with the dataset.
1740 : *
1741 : * @return CE_None on success, or CE_Failure if this transform cannot be
1742 : * written.
1743 : *
1744 : * @deprecated since 3.12. Use SetGeoTransform(const GDALGeoTransform&) instead
1745 : */
1746 38 : CPLErr GDALDataset::SetGeoTransform(const double *padfTransform)
1747 :
1748 : {
1749 38 : return SetGeoTransform(
1750 38 : *reinterpret_cast<const GDALGeoTransform *>(padfTransform));
1751 : }
1752 :
1753 : /************************************************************************/
1754 : /* GDALSetGeoTransform() */
1755 : /************************************************************************/
1756 :
1757 : /**
1758 : * \brief Set the affine transformation coefficients.
1759 : *
1760 : * @see GDALDataset::SetGeoTransform()
1761 : */
1762 :
1763 4589 : CPLErr CPL_STDCALL GDALSetGeoTransform(GDALDatasetH hDS,
1764 : const double *padfTransform)
1765 :
1766 : {
1767 4589 : VALIDATE_POINTER1(hDS, "GDALSetGeoTransform", CE_Failure);
1768 4589 : VALIDATE_POINTER1(padfTransform, "GDALSetGeoTransform", CE_Failure);
1769 :
1770 9178 : return GDALDataset::FromHandle(hDS)->SetGeoTransform(
1771 4589 : *reinterpret_cast<const GDALGeoTransform *>(padfTransform));
1772 : }
1773 :
1774 : /************************************************************************/
1775 : /* GetInternalHandle() */
1776 : /************************************************************************/
1777 :
1778 : /**
1779 : * \fn GDALDataset::GetInternalHandle(const char*)
1780 : * \brief Fetch a format specific internally meaningful handle.
1781 : *
1782 : * This method is the same as the C GDALGetInternalHandle() method.
1783 : *
1784 : * @param pszHandleName the handle name desired. The meaningful names
1785 : * will be specific to the file format.
1786 : *
1787 : * @return the desired handle value, or NULL if not recognized/supported.
1788 : */
1789 :
1790 200 : void *GDALDataset::GetInternalHandle(CPL_UNUSED const char *pszHandleName)
1791 :
1792 : {
1793 200 : return nullptr;
1794 : }
1795 :
1796 : /************************************************************************/
1797 : /* GDALGetInternalHandle() */
1798 : /************************************************************************/
1799 :
1800 : /**
1801 : * \brief Fetch a format specific internally meaningful handle.
1802 : *
1803 : * @see GDALDataset::GetInternalHandle()
1804 : */
1805 :
1806 61 : void *CPL_STDCALL GDALGetInternalHandle(GDALDatasetH hDS,
1807 : const char *pszRequest)
1808 :
1809 : {
1810 61 : VALIDATE_POINTER1(hDS, "GDALGetInternalHandle", nullptr);
1811 :
1812 61 : return GDALDataset::FromHandle(hDS)->GetInternalHandle(pszRequest);
1813 : }
1814 :
1815 : /************************************************************************/
1816 : /* GetDriver() */
1817 : /************************************************************************/
1818 :
1819 : /**
1820 : * \brief Fetch the driver to which this dataset relates.
1821 : *
1822 : * This method is the same as the C GDALGetDatasetDriver() function.
1823 : *
1824 : * @return the driver on which the dataset was created with GDALOpen() or
1825 : * GDALCreate().
1826 : */
1827 :
1828 35785 : GDALDriver *GDALDataset::GetDriver()
1829 : {
1830 35785 : return poDriver;
1831 : }
1832 :
1833 : /************************************************************************/
1834 : /* GDALGetDatasetDriver() */
1835 : /************************************************************************/
1836 :
1837 : /**
1838 : * \brief Fetch the driver to which this dataset relates.
1839 : *
1840 : * @see GDALDataset::GetDriver()
1841 : */
1842 :
1843 2824 : GDALDriverH CPL_STDCALL GDALGetDatasetDriver(GDALDatasetH hDataset)
1844 :
1845 : {
1846 2824 : VALIDATE_POINTER1(hDataset, "GDALGetDatasetDriver", nullptr);
1847 :
1848 : return static_cast<GDALDriverH>(
1849 2824 : GDALDataset::FromHandle(hDataset)->GetDriver());
1850 : }
1851 :
1852 : /************************************************************************/
1853 : /* Reference() */
1854 : /************************************************************************/
1855 :
1856 : /**
1857 : * \brief Add one to dataset reference count.
1858 : *
1859 : * The reference is one after instantiation.
1860 : *
1861 : * This method is the same as the C GDALReferenceDataset() function.
1862 : *
1863 : * @return the post-increment reference count.
1864 : */
1865 :
1866 262706 : int GDALDataset::Reference()
1867 : {
1868 262706 : return ++nRefCount;
1869 : }
1870 :
1871 : /************************************************************************/
1872 : /* GDALReferenceDataset() */
1873 : /************************************************************************/
1874 :
1875 : /**
1876 : * \brief Add one to dataset reference count.
1877 : *
1878 : * @see GDALDataset::Reference()
1879 : */
1880 :
1881 1474 : int CPL_STDCALL GDALReferenceDataset(GDALDatasetH hDataset)
1882 :
1883 : {
1884 1474 : VALIDATE_POINTER1(hDataset, "GDALReferenceDataset", 0);
1885 :
1886 1474 : return GDALDataset::FromHandle(hDataset)->Reference();
1887 : }
1888 :
1889 : /************************************************************************/
1890 : /* Dereference() */
1891 : /************************************************************************/
1892 :
1893 : /**
1894 : * \brief Subtract one from dataset reference count.
1895 : *
1896 : * The reference is one after instantiation. Generally when the reference
1897 : * count has dropped to zero the dataset may be safely deleted (closed).
1898 : *
1899 : * This method is the same as the C GDALDereferenceDataset() function.
1900 : *
1901 : * @return the post-decrement reference count.
1902 : */
1903 :
1904 326531 : int GDALDataset::Dereference()
1905 : {
1906 326531 : return --nRefCount;
1907 : }
1908 :
1909 : /************************************************************************/
1910 : /* GDALDereferenceDataset() */
1911 : /************************************************************************/
1912 :
1913 : /**
1914 : * \brief Subtract one from dataset reference count.
1915 : *
1916 : * @see GDALDataset::Dereference()
1917 : */
1918 :
1919 61820 : int CPL_STDCALL GDALDereferenceDataset(GDALDatasetH hDataset)
1920 :
1921 : {
1922 61820 : VALIDATE_POINTER1(hDataset, "GDALDereferenceDataset", 0);
1923 :
1924 61820 : return GDALDataset::FromHandle(hDataset)->Dereference();
1925 : }
1926 :
1927 : /************************************************************************/
1928 : /* ReleaseRef() */
1929 : /************************************************************************/
1930 :
1931 : /**
1932 : * \brief Drop a reference to this object, and destroy if no longer referenced.
1933 : * @return TRUE if the object has been destroyed.
1934 : */
1935 :
1936 252677 : int GDALDataset::ReleaseRef()
1937 :
1938 : {
1939 252677 : if (Dereference() <= 0)
1940 : {
1941 7803 : nRefCount = 1;
1942 7803 : delete this;
1943 7803 : return TRUE;
1944 : }
1945 244874 : return FALSE;
1946 : }
1947 :
1948 : /************************************************************************/
1949 : /* GDALReleaseDataset() */
1950 : /************************************************************************/
1951 :
1952 : /**
1953 : * \brief Drop a reference to this object, and destroy if no longer referenced.
1954 : *
1955 : * @see GDALDataset::ReleaseRef()
1956 : */
1957 :
1958 1711 : int CPL_STDCALL GDALReleaseDataset(GDALDatasetH hDataset)
1959 :
1960 : {
1961 1711 : VALIDATE_POINTER1(hDataset, "GDALReleaseDataset", 0);
1962 :
1963 1711 : return GDALDataset::FromHandle(hDataset)->ReleaseRef();
1964 : }
1965 :
1966 : /************************************************************************/
1967 : /* GetShared() */
1968 : /************************************************************************/
1969 :
1970 : /**
1971 : * \brief Returns shared flag.
1972 : *
1973 : * @return TRUE if the GDALDataset is available for sharing, or FALSE if not.
1974 : */
1975 :
1976 313085 : int GDALDataset::GetShared() const
1977 : {
1978 313085 : return bShared;
1979 : }
1980 :
1981 : /************************************************************************/
1982 : /* MarkAsShared() */
1983 : /************************************************************************/
1984 :
1985 : /**
1986 : * \brief Mark this dataset as available for sharing.
1987 : */
1988 :
1989 438 : void GDALDataset::MarkAsShared()
1990 :
1991 : {
1992 438 : CPLAssert(!bShared);
1993 :
1994 438 : bShared = true;
1995 438 : if (bIsInternal)
1996 24 : return;
1997 :
1998 414 : GIntBig nPID = GDALGetResponsiblePIDForCurrentThread();
1999 :
2000 : // Insert the dataset in the set of shared opened datasets.
2001 828 : CPLMutexHolderD(&hDLMutex);
2002 414 : if (phSharedDatasetSet == nullptr)
2003 288 : phSharedDatasetSet =
2004 288 : CPLHashSetNew(GDALSharedDatasetHashFunc, GDALSharedDatasetEqualFunc,
2005 : GDALSharedDatasetFreeFunc);
2006 :
2007 : SharedDatasetCtxt *psStruct =
2008 414 : static_cast<SharedDatasetCtxt *>(CPLMalloc(sizeof(SharedDatasetCtxt)));
2009 414 : psStruct->poDS = this;
2010 414 : psStruct->nPID = nPID;
2011 414 : psStruct->nOpenFlags = nOpenFlags & ~GDAL_OF_SHARED;
2012 414 : psStruct->pszDescription = CPLStrdup(GetDescription());
2013 : std::string osConcatenatedOpenOptions =
2014 828 : GDALSharedDatasetConcatenateOpenOptions(papszOpenOptions);
2015 414 : psStruct->pszConcatenatedOpenOptions =
2016 414 : CPLStrdup(osConcatenatedOpenOptions.c_str());
2017 414 : if (CPLHashSetLookup(phSharedDatasetSet, psStruct) != nullptr)
2018 : {
2019 1 : GDALSharedDatasetFreeFunc(psStruct);
2020 1 : ReportError(CE_Failure, CPLE_AppDefined,
2021 : "An existing shared dataset already has this description. "
2022 : "This should not happen.");
2023 : }
2024 : else
2025 : {
2026 413 : CPLHashSetInsert(phSharedDatasetSet, psStruct);
2027 :
2028 413 : (*poAllDatasetMap)[this] = nPID;
2029 : }
2030 : }
2031 :
2032 : /************************************************************************/
2033 : /* MarkSuppressOnClose() */
2034 : /************************************************************************/
2035 :
2036 : /** Set that the dataset must be deleted on close.
2037 : *
2038 : * This is the same as C function GDALDatasetMarkSuppressOnClose()
2039 : */
2040 1251 : void GDALDataset::MarkSuppressOnClose()
2041 : {
2042 1251 : bSuppressOnClose = true;
2043 1251 : }
2044 :
2045 : /************************************************************************/
2046 : /* GDALDatasetMarkSuppressOnClose() */
2047 : /************************************************************************/
2048 :
2049 : /** Set that the dataset must be deleted on close.
2050 : *
2051 : * This is the same as C++ method GDALDataset::MarkSuppressOnClose()
2052 : *
2053 : * @since GDAL 3.12
2054 : */
2055 :
2056 4 : void GDALDatasetMarkSuppressOnClose(GDALDatasetH hDS)
2057 : {
2058 4 : VALIDATE_POINTER0(hDS, "GDALDatasetMarkSuppressOnClose");
2059 :
2060 4 : return GDALDataset::FromHandle(hDS)->MarkSuppressOnClose();
2061 : }
2062 :
2063 : /************************************************************************/
2064 : /* UnMarkSuppressOnClose() */
2065 : /************************************************************************/
2066 :
2067 : /** Remove the flag requesting the dataset to be deleted on close. */
2068 684 : void GDALDataset::UnMarkSuppressOnClose()
2069 : {
2070 684 : bSuppressOnClose = false;
2071 684 : }
2072 :
2073 : /************************************************************************/
2074 : /* CleanupPostFileClosing() */
2075 : /************************************************************************/
2076 :
2077 : /** This method should be called by driver implementations in their destructor,
2078 : * after having closed all files, but before having freed resources that
2079 : * are needed for their GetFileList() implementation.
2080 : * This is used to implement MarkSuppressOnClose behavior.
2081 : */
2082 259 : void GDALDataset::CleanupPostFileClosing()
2083 : {
2084 259 : if (IsMarkedSuppressOnClose())
2085 : {
2086 1 : char **papszFileList = GetFileList();
2087 3 : for (int i = 0; papszFileList && papszFileList[i]; ++i)
2088 2 : VSIUnlink(papszFileList[i]);
2089 1 : CSLDestroy(papszFileList);
2090 : }
2091 259 : }
2092 :
2093 : /************************************************************************/
2094 : /* GetGCPCount() */
2095 : /************************************************************************/
2096 :
2097 : /**
2098 : * \brief Get number of GCPs.
2099 : *
2100 : * This method is the same as the C function GDALGetGCPCount().
2101 : *
2102 : * @return number of GCPs for this dataset. Zero if there are none.
2103 : */
2104 :
2105 16644 : int GDALDataset::GetGCPCount()
2106 : {
2107 16644 : return 0;
2108 : }
2109 :
2110 : /************************************************************************/
2111 : /* GDALGetGCPCount() */
2112 : /************************************************************************/
2113 :
2114 : /**
2115 : * \brief Get number of GCPs.
2116 : *
2117 : * @see GDALDataset::GetGCPCount()
2118 : */
2119 :
2120 2305 : int CPL_STDCALL GDALGetGCPCount(GDALDatasetH hDS)
2121 :
2122 : {
2123 2305 : VALIDATE_POINTER1(hDS, "GDALGetGCPCount", 0);
2124 :
2125 2305 : return GDALDataset::FromHandle(hDS)->GetGCPCount();
2126 : }
2127 :
2128 : /************************************************************************/
2129 : /* GetGCPProjection() */
2130 : /************************************************************************/
2131 :
2132 : /**
2133 : * \brief Get output projection for GCPs.
2134 : *
2135 : * This method is the same as the C function GDALGetGCPProjection().
2136 : *
2137 : * The projection string follows the normal rules from GetProjectionRef().
2138 : *
2139 : * \note Starting with GDAL 3.0, this is a compatibility layer around
2140 : * GetGCPSpatialRef()
2141 : *
2142 : * @return internal projection string or "" if there are no GCPs.
2143 : * It should not be altered, freed or expected to last for long.
2144 : */
2145 :
2146 1054 : const char *GDALDataset::GetGCPProjection() const
2147 : {
2148 1054 : const auto poSRS = GetGCPSpatialRef();
2149 1054 : if (!poSRS || !m_poPrivate)
2150 : {
2151 716 : return "";
2152 : }
2153 338 : char *pszWKT = nullptr;
2154 338 : poSRS->exportToWkt(&pszWKT);
2155 338 : if (!pszWKT)
2156 : {
2157 0 : return "";
2158 : }
2159 :
2160 : // If called on a thread-safe dataset, we might be called by several
2161 : // threads, so make sure our accesses to m_pszWKTCached are protected
2162 : // by a mutex.
2163 676 : std::lock_guard oLock(m_poPrivate->m_oMutexWKT);
2164 338 : if (m_poPrivate->m_pszWKTGCPCached &&
2165 258 : strcmp(pszWKT, m_poPrivate->m_pszWKTGCPCached) == 0)
2166 : {
2167 258 : CPLFree(pszWKT);
2168 258 : return m_poPrivate->m_pszWKTGCPCached;
2169 : }
2170 80 : CPLFree(m_poPrivate->m_pszWKTGCPCached);
2171 80 : m_poPrivate->m_pszWKTGCPCached = pszWKT;
2172 80 : return m_poPrivate->m_pszWKTGCPCached;
2173 : }
2174 :
2175 : /************************************************************************/
2176 : /* GetGCPSpatialRef() */
2177 : /************************************************************************/
2178 :
2179 : /**
2180 : * \brief Get output spatial reference system for GCPs.
2181 : *
2182 : * Same as the C function GDALGetGCPSpatialRef().
2183 : *
2184 : * When a SRS is not available, null is returned. If used on
2185 : * a dataset where there is a geotransform, and not GCPs, this method returns
2186 : * null. Use GetSpatialRef() instead.
2187 : *
2188 : * @since GDAL 3.0
2189 : *
2190 : * @return a pointer to an internal object. It should not be altered or freed.
2191 : * Its lifetime will be the one of the dataset object, or until the next
2192 : * call to this method.
2193 : */
2194 :
2195 47 : const OGRSpatialReference *GDALDataset::GetGCPSpatialRef() const
2196 : {
2197 47 : return nullptr;
2198 : }
2199 :
2200 : /************************************************************************/
2201 : /* GDALGetGCPSpatialRef() */
2202 : /************************************************************************/
2203 :
2204 : /**
2205 : * \brief Get output spatial reference system for GCPs.
2206 : *
2207 : * @since GDAL 3.0
2208 : *
2209 : * @see GDALDataset::GetGCPSpatialRef()
2210 : */
2211 :
2212 470 : OGRSpatialReferenceH GDALGetGCPSpatialRef(GDALDatasetH hDS)
2213 :
2214 : {
2215 470 : VALIDATE_POINTER1(hDS, "GDALGetGCPSpatialRef", nullptr);
2216 :
2217 470 : return OGRSpatialReference::ToHandle(const_cast<OGRSpatialReference *>(
2218 470 : GDALDataset::FromHandle(hDS)->GetGCPSpatialRef()));
2219 : }
2220 :
2221 : /************************************************************************/
2222 : /* GDALGetGCPProjection() */
2223 : /************************************************************************/
2224 :
2225 : /**
2226 : * \brief Get output projection for GCPs.
2227 : *
2228 : * @see GDALDataset::GetGCPProjection()
2229 : */
2230 :
2231 1033 : const char *CPL_STDCALL GDALGetGCPProjection(GDALDatasetH hDS)
2232 :
2233 : {
2234 1033 : VALIDATE_POINTER1(hDS, "GDALGetGCPProjection", nullptr);
2235 :
2236 1033 : return GDALDataset::FromHandle(hDS)->GetGCPProjection();
2237 : }
2238 :
2239 : /************************************************************************/
2240 : /* GetGCPs() */
2241 : /************************************************************************/
2242 :
2243 : /**
2244 : * \brief Fetch GCPs.
2245 : *
2246 : * This method is the same as the C function GDALGetGCPs().
2247 : *
2248 : * @return pointer to internal GCP structure list. It should not be modified,
2249 : * and may change on the next GDAL call.
2250 : */
2251 :
2252 11 : const GDAL_GCP *GDALDataset::GetGCPs()
2253 : {
2254 11 : return nullptr;
2255 : }
2256 :
2257 : /************************************************************************/
2258 : /* GDALGetGCPs() */
2259 : /************************************************************************/
2260 :
2261 : /**
2262 : * \brief Fetch GCPs.
2263 : *
2264 : * @see GDALDataset::GetGCPs()
2265 : */
2266 :
2267 581 : const GDAL_GCP *CPL_STDCALL GDALGetGCPs(GDALDatasetH hDS)
2268 :
2269 : {
2270 581 : VALIDATE_POINTER1(hDS, "GDALGetGCPs", nullptr);
2271 :
2272 581 : return GDALDataset::FromHandle(hDS)->GetGCPs();
2273 : }
2274 :
2275 : /************************************************************************/
2276 : /* SetGCPs() */
2277 : /************************************************************************/
2278 :
2279 : /**
2280 : * \brief Assign GCPs.
2281 : *
2282 : * This method is the same as the C function GDALSetGCPs().
2283 : *
2284 : * This method assigns the passed set of GCPs to this dataset, as well as
2285 : * setting their coordinate system. Internally copies are made of the
2286 : * coordinate system and list of points, so the caller remains responsible for
2287 : * deallocating these arguments if appropriate.
2288 : *
2289 : * Most formats do not support setting of GCPs, even formats that can
2290 : * handle GCPs. These formats will return CE_Failure.
2291 : *
2292 : * \note Startig with GDAL 3.0, this is a compatibility layer around
2293 : * SetGCPs(int, const GDAL_GCP*, const char*)
2294 : *
2295 : * @param nGCPCount number of GCPs being assigned.
2296 : *
2297 : * @param pasGCPList array of GCP structures being assign (nGCPCount in array).
2298 : *
2299 : * @param pszGCPProjection the new OGC WKT coordinate system to assign for the
2300 : * GCP output coordinates. This parameter should be "" if no output coordinate
2301 : * system is known.
2302 : *
2303 : * @return CE_None on success, CE_Failure on failure (including if action is
2304 : * not supported for this format).
2305 : */
2306 :
2307 52 : CPLErr GDALDataset::SetGCPs(int nGCPCount, const GDAL_GCP *pasGCPList,
2308 : const char *pszGCPProjection)
2309 :
2310 : {
2311 52 : if (pszGCPProjection && pszGCPProjection[0] != '\0')
2312 : {
2313 66 : OGRSpatialReference oSRS;
2314 33 : oSRS.SetAxisMappingStrategy(OAMS_TRADITIONAL_GIS_ORDER);
2315 33 : if (oSRS.importFromWkt(pszGCPProjection) != OGRERR_NONE)
2316 : {
2317 0 : return CE_Failure;
2318 : }
2319 33 : return SetGCPs(nGCPCount, pasGCPList, &oSRS);
2320 : }
2321 : else
2322 : {
2323 19 : return SetGCPs(nGCPCount, pasGCPList,
2324 19 : static_cast<const OGRSpatialReference *>(nullptr));
2325 : }
2326 : }
2327 :
2328 : /************************************************************************/
2329 : /* SetGCPs() */
2330 : /************************************************************************/
2331 :
2332 : /**
2333 : * \brief Assign GCPs.
2334 : *
2335 : * This method is the same as the C function GDALSetGCPs().
2336 : *
2337 : * This method assigns the passed set of GCPs to this dataset, as well as
2338 : * setting their coordinate system. Internally copies are made of the
2339 : * coordinate system and list of points, so the caller remains responsible for
2340 : * deallocating these arguments if appropriate.
2341 : *
2342 : * Most formats do not support setting of GCPs, even formats that can
2343 : * handle GCPs. These formats will return CE_Failure.
2344 : *
2345 : * @since GDAL 3.0
2346 : *
2347 : * @param nGCPCount number of GCPs being assigned.
2348 : *
2349 : * @param pasGCPList array of GCP structures being assign (nGCPCount in array).
2350 : *
2351 : * @param poGCP_SRS the new coordinate reference system to assign for the
2352 : * GCP output coordinates. This parameter should be null if no output
2353 : * coordinate system is known.
2354 : *
2355 : * @return CE_None on success, CE_Failure on failure (including if action is
2356 : * not supported for this format).
2357 : */
2358 :
2359 1 : CPLErr GDALDataset::SetGCPs(CPL_UNUSED int nGCPCount,
2360 : CPL_UNUSED const GDAL_GCP *pasGCPList,
2361 : CPL_UNUSED const OGRSpatialReference *poGCP_SRS)
2362 :
2363 : {
2364 1 : if (!(GetMOFlags() & GMO_IGNORE_UNIMPLEMENTED))
2365 1 : ReportError(CE_Failure, CPLE_NotSupported,
2366 : "Dataset does not support the SetGCPs() method.");
2367 :
2368 1 : return CE_Failure;
2369 : }
2370 :
2371 : /************************************************************************/
2372 : /* GDALSetGCPs() */
2373 : /************************************************************************/
2374 :
2375 : /**
2376 : * \brief Assign GCPs.
2377 : *
2378 : * @see GDALDataset::SetGCPs(int, const GDAL_GCP*, const char*)
2379 : */
2380 :
2381 29 : CPLErr CPL_STDCALL GDALSetGCPs(GDALDatasetH hDS, int nGCPCount,
2382 : const GDAL_GCP *pasGCPList,
2383 : const char *pszGCPProjection)
2384 :
2385 : {
2386 29 : VALIDATE_POINTER1(hDS, "GDALSetGCPs", CE_Failure);
2387 :
2388 29 : return GDALDataset::FromHandle(hDS)->SetGCPs(nGCPCount, pasGCPList,
2389 29 : pszGCPProjection);
2390 : }
2391 :
2392 : /************************************************************************/
2393 : /* GDALSetGCPs2() */
2394 : /************************************************************************/
2395 :
2396 : /**
2397 : * \brief Assign GCPs.
2398 : *
2399 : * @since GDAL 3.0
2400 : * @see GDALDataset::SetGCPs(int, const GDAL_GCP*, const OGRSpatialReference*)
2401 : */
2402 :
2403 10 : CPLErr GDALSetGCPs2(GDALDatasetH hDS, int nGCPCount, const GDAL_GCP *pasGCPList,
2404 : OGRSpatialReferenceH hSRS)
2405 :
2406 : {
2407 10 : VALIDATE_POINTER1(hDS, "GDALSetGCPs2", CE_Failure);
2408 :
2409 20 : return GDALDataset::FromHandle(hDS)->SetGCPs(
2410 10 : nGCPCount, pasGCPList, OGRSpatialReference::FromHandle(hSRS));
2411 : }
2412 :
2413 : /************************************************************************/
2414 : /* BuildOverviews() */
2415 : /************************************************************************/
2416 :
2417 : /**
2418 : * \brief Build raster overview(s)
2419 : *
2420 : * If the operation is not supported for the indicated dataset, then
2421 : * CE_Failure is returned, and CPLGetLastErrorNo() will return
2422 : * CPLE_NotSupported.
2423 : *
2424 : * Depending on the actual file format, all overviews level can be also
2425 : * deleted by specifying nOverviews == 0. This works at least for external
2426 : * overviews (.ovr), TIFF internal overviews, etc.
2427 : *
2428 : * Starting with GDAL 3.2, the GDAL_NUM_THREADS configuration option can be set
2429 : * to "ALL_CPUS" or a integer value to specify the number of threads to use for
2430 : * overview computation.
2431 : *
2432 : * This method is the same as the C function GDALBuildOverviewsEx().
2433 : *
2434 : * @param pszResampling one of "AVERAGE", "AVERAGE_MAGPHASE", "RMS",
2435 : * "BILINEAR", "CUBIC", "CUBICSPLINE", "GAUSS", "LANCZOS", "MODE", "NEAREST",
2436 : * or "NONE" controlling the downsampling method applied.
2437 : * @param nOverviews number of overviews to build, or 0 to clean overviews.
2438 : * @param panOverviewList the list of overview decimation factors (positive
2439 : * integers, normally larger or equal to 2) to build, or
2440 : * NULL if nOverviews == 0.
2441 : * @param nListBands number of bands to build overviews for in panBandList.
2442 : * Build for all bands if this is 0.
2443 : * @param panBandList list of band numbers.
2444 : * @param pfnProgress a function to call to report progress, or NULL.
2445 : * @param pProgressData application data to pass to the progress function.
2446 : * @param papszOptions (GDAL >= 3.6) NULL terminated list of options as
2447 : * key=value pairs, or NULL.
2448 : * Possible keys are the ones returned by
2449 : * GetDriver()->GetMetadataItem(GDAL_DMD_OVERVIEW_CREATIONOPTIONLIST)
2450 : *
2451 : * @return CE_None on success or CE_Failure if the operation doesn't work.
2452 : *
2453 : * For example, to build overview level 2, 4 and 8 on all bands the following
2454 : * call could be made:
2455 : * \code{.cpp}
2456 : * int anOverviewList[3] = { 2, 4, 8 };
2457 : *
2458 : * poDataset->BuildOverviews( "NEAREST", 3, anOverviewList, 0, nullptr,
2459 : * GDALDummyProgress, nullptr );
2460 : * \endcode
2461 : *
2462 : * @see GDALRegenerateOverviewsEx()
2463 : */
2464 :
2465 752 : CPLErr GDALDataset::BuildOverviews(const char *pszResampling, int nOverviews,
2466 : const int *panOverviewList, int nListBands,
2467 : const int *panBandList,
2468 : GDALProgressFunc pfnProgress,
2469 : void *pProgressData,
2470 : CSLConstList papszOptions)
2471 : {
2472 752 : int *panAllBandList = nullptr;
2473 :
2474 1504 : CPLStringList aosOptions(papszOptions);
2475 752 : if (poDriver && !aosOptions.empty())
2476 : {
2477 : const char *pszOptionList =
2478 28 : poDriver->GetMetadataItem(GDAL_DMD_OVERVIEW_CREATIONOPTIONLIST);
2479 28 : if (pszOptionList)
2480 : {
2481 : // For backwards compatibility
2482 28 : if (const char *opt = aosOptions.FetchNameValue("USE_RRD"))
2483 : {
2484 4 : if (strstr(pszOptionList, "<Value>RRD</Value>") &&
2485 2 : aosOptions.FetchNameValue("LOCATION") == nullptr)
2486 : {
2487 2 : if (CPLTestBool(opt))
2488 2 : aosOptions.SetNameValue("LOCATION", "RRD");
2489 2 : aosOptions.SetNameValue("USE_RRD", nullptr);
2490 : }
2491 : }
2492 28 : if (const char *opt =
2493 28 : aosOptions.FetchNameValue("VRT_VIRTUAL_OVERVIEWS"))
2494 : {
2495 3 : if (strstr(pszOptionList, "VIRTUAL"))
2496 : {
2497 3 : aosOptions.SetNameValue("VIRTUAL", opt);
2498 3 : aosOptions.SetNameValue("VRT_VIRTUAL_OVERVIEWS", nullptr);
2499 : }
2500 : }
2501 :
2502 76 : for (const auto &[pszKey, pszValue] :
2503 104 : cpl::IterateNameValue(papszOptions))
2504 : {
2505 38 : if (cpl::ends_with(std::string_view(pszKey), "_OVERVIEW"))
2506 : {
2507 : aosOptions.SetNameValue(
2508 16 : std::string(pszKey)
2509 16 : .substr(0, strlen(pszKey) - strlen("_OVERVIEW"))
2510 : .c_str(),
2511 16 : pszValue);
2512 8 : aosOptions.SetNameValue(pszKey, nullptr);
2513 : }
2514 : }
2515 :
2516 56 : CPLString osDriver;
2517 28 : osDriver.Printf("driver %s", poDriver->GetDescription());
2518 28 : GDALValidateOptions(pszOptionList, aosOptions.List(),
2519 : "overview creation option", osDriver);
2520 : }
2521 : }
2522 :
2523 752 : if (nListBands == 0)
2524 : {
2525 740 : nListBands = GetRasterCount();
2526 : panAllBandList =
2527 740 : static_cast<int *>(CPLMalloc(sizeof(int) * nListBands));
2528 67477 : for (int i = 0; i < nListBands; ++i)
2529 66737 : panAllBandList[i] = i + 1;
2530 :
2531 740 : panBandList = panAllBandList;
2532 : }
2533 :
2534 752 : if (pfnProgress == nullptr)
2535 717 : pfnProgress = GDALDummyProgress;
2536 :
2537 1838 : for (int i = 0; i < nOverviews; ++i)
2538 : {
2539 1087 : if (panOverviewList[i] <= 0)
2540 : {
2541 1 : CPLError(CE_Failure, CPLE_IllegalArg,
2542 : "panOverviewList[%d] = %d is invalid. It must be a "
2543 : "positive value",
2544 1 : i, panOverviewList[i]);
2545 1 : CPLFree(panAllBandList);
2546 1 : return CE_Failure;
2547 : }
2548 : }
2549 :
2550 751 : const CPLErr eErr = IBuildOverviews(
2551 : pszResampling, nOverviews, panOverviewList, nListBands, panBandList,
2552 751 : pfnProgress, pProgressData, aosOptions.List());
2553 :
2554 751 : if (panAllBandList != nullptr)
2555 738 : CPLFree(panAllBandList);
2556 :
2557 751 : return eErr;
2558 : }
2559 :
2560 : /************************************************************************/
2561 : /* GDALBuildOverviews() */
2562 : /************************************************************************/
2563 :
2564 : /**
2565 : * \brief Build raster overview(s)
2566 : *
2567 : * @see GDALDataset::BuildOverviews() and GDALBuildOverviews()
2568 : */
2569 :
2570 27 : CPLErr CPL_STDCALL GDALBuildOverviews(GDALDatasetH hDataset,
2571 : const char *pszResampling, int nOverviews,
2572 : const int *panOverviewList,
2573 : int nListBands, const int *panBandList,
2574 : GDALProgressFunc pfnProgress,
2575 : void *pProgressData)
2576 :
2577 : {
2578 27 : VALIDATE_POINTER1(hDataset, "GDALBuildOverviews", CE_Failure);
2579 :
2580 27 : return GDALDataset::FromHandle(hDataset)->BuildOverviews(
2581 : pszResampling, nOverviews, panOverviewList, nListBands, panBandList,
2582 27 : pfnProgress, pProgressData, nullptr);
2583 : }
2584 :
2585 : /************************************************************************/
2586 : /* GDALBuildOverviews() */
2587 : /************************************************************************/
2588 :
2589 : /**
2590 : * \brief Build raster overview(s)
2591 : *
2592 : * @see GDALDataset::BuildOverviews()
2593 : * @since GDAL 3.6
2594 : */
2595 :
2596 : CPLErr CPL_STDCALL
2597 704 : GDALBuildOverviewsEx(GDALDatasetH hDataset, const char *pszResampling,
2598 : int nOverviews, const int *panOverviewList, int nListBands,
2599 : const int *panBandList, GDALProgressFunc pfnProgress,
2600 : void *pProgressData, CSLConstList papszOptions)
2601 :
2602 : {
2603 704 : VALIDATE_POINTER1(hDataset, "GDALBuildOverviews", CE_Failure);
2604 :
2605 704 : return GDALDataset::FromHandle(hDataset)->BuildOverviews(
2606 : pszResampling, nOverviews, panOverviewList, nListBands, panBandList,
2607 704 : pfnProgress, pProgressData, papszOptions);
2608 : }
2609 :
2610 : /************************************************************************/
2611 : /* IBuildOverviews() */
2612 : /* */
2613 : /* Default implementation. */
2614 : /************************************************************************/
2615 :
2616 : //! @cond Doxygen_Suppress
2617 196 : CPLErr GDALDataset::IBuildOverviews(const char *pszResampling, int nOverviews,
2618 : const int *panOverviewList, int nListBands,
2619 : const int *panBandList,
2620 : GDALProgressFunc pfnProgress,
2621 : void *pProgressData,
2622 : CSLConstList papszOptions)
2623 :
2624 : {
2625 196 : if (oOvManager.IsInitialized())
2626 195 : return oOvManager.BuildOverviews(
2627 : nullptr, pszResampling, nOverviews, panOverviewList, nListBands,
2628 195 : panBandList, pfnProgress, pProgressData, papszOptions);
2629 : else
2630 : {
2631 1 : ReportError(CE_Failure, CPLE_NotSupported,
2632 : "BuildOverviews() not supported for this dataset.");
2633 :
2634 1 : return CE_Failure;
2635 : }
2636 : }
2637 :
2638 : //! @endcond
2639 :
2640 : /************************************************************************/
2641 : /* AddOverviews() */
2642 : /* */
2643 : /* Default implementation. */
2644 : /************************************************************************/
2645 :
2646 : /**
2647 : * \brief Add overview from existing dataset(s)
2648 : *
2649 : * This function creates new overview levels or refresh existing one from
2650 : * the list of provided overview datasets.
2651 : * Source overviews may come from any GDAL supported format, provided they
2652 : * have the same number of bands and geospatial extent than the target
2653 : * dataset.
2654 : *
2655 : * If the operation is not supported for the indicated dataset, then
2656 : * CE_Failure is returned, and CPLGetLastErrorNo() will return
2657 : * CPLE_NotSupported.
2658 : *
2659 : * At time of writing, this method is only implemented for internal overviews
2660 : * of GeoTIFF datasets and external overviews in GeoTIFF format.
2661 : *
2662 : * @param apoSrcOvrDS Vector of source overviews.
2663 : * @param pfnProgress a function to call to report progress, or NULL.
2664 : * @param pProgressData application data to pass to the progress function.
2665 : * @param papszOptions NULL terminated list of options as
2666 : * key=value pairs, or NULL. Possible keys are the
2667 : * ones returned by
2668 : * GetDriver()->GetMetadataItem(GDAL_DMD_OVERVIEW_CREATIONOPTIONLIST)
2669 : *
2670 : * @return CE_None on success or CE_Failure if the operation doesn't work.
2671 : * @since 3.12
2672 : */
2673 5 : CPLErr GDALDataset::AddOverviews(const std::vector<GDALDataset *> &apoSrcOvrDS,
2674 : GDALProgressFunc pfnProgress,
2675 : void *pProgressData, CSLConstList papszOptions)
2676 : {
2677 5 : if (oOvManager.IsInitialized())
2678 : {
2679 4 : return oOvManager.AddOverviews(nullptr, apoSrcOvrDS, pfnProgress,
2680 4 : pProgressData, papszOptions);
2681 : }
2682 : else
2683 : {
2684 1 : ReportError(CE_Failure, CPLE_NotSupported,
2685 : "AddOverviews() not supported for this dataset.");
2686 1 : return CE_Failure;
2687 : }
2688 : }
2689 :
2690 : /************************************************************************/
2691 : /* IRasterIO() */
2692 : /* */
2693 : /* The default implementation of IRasterIO() is, in the general */
2694 : /* case to pass the request off to each band objects rasterio */
2695 : /* methods with appropriate arguments. In some cases, it might */
2696 : /* choose instead the BlockBasedRasterIO() implementation. */
2697 : /************************************************************************/
2698 :
2699 : //! @cond Doxygen_Suppress
2700 445161 : CPLErr GDALDataset::IRasterIO(GDALRWFlag eRWFlag, int nXOff, int nYOff,
2701 : int nXSize, int nYSize, void *pData,
2702 : int nBufXSize, int nBufYSize,
2703 : GDALDataType eBufType, int nBandCount,
2704 : BANDMAP_TYPE panBandMap, GSpacing nPixelSpace,
2705 : GSpacing nLineSpace, GSpacing nBandSpace,
2706 : GDALRasterIOExtraArg *psExtraArg)
2707 :
2708 : {
2709 445161 : const char *pszInterleave = nullptr;
2710 :
2711 445161 : CPLAssert(nullptr != pData);
2712 :
2713 445161 : const bool bHasSubpixelShift =
2714 447496 : psExtraArg->bFloatingPointWindowValidity &&
2715 445954 : psExtraArg->eResampleAlg != GRIORA_NearestNeighbour &&
2716 793 : (nXOff != psExtraArg->dfXOff || nYOff != psExtraArg->dfYOff);
2717 :
2718 445045 : if (!bHasSubpixelShift && nXSize == nBufXSize && nYSize == nBufYSize &&
2719 70748 : nBandCount > 1 &&
2720 70748 : (pszInterleave = GetMetadataItem("INTERLEAVE", "IMAGE_STRUCTURE")) !=
2721 890206 : nullptr &&
2722 67572 : EQUAL(pszInterleave, "PIXEL"))
2723 : {
2724 64158 : return BlockBasedRasterIO(eRWFlag, nXOff, nYOff, nXSize, nYSize, pData,
2725 : nBufXSize, nBufYSize, eBufType, nBandCount,
2726 : panBandMap, nPixelSpace, nLineSpace,
2727 64158 : nBandSpace, psExtraArg);
2728 : }
2729 :
2730 381003 : if (eRWFlag == GF_Read &&
2731 201414 : (psExtraArg->eResampleAlg == GRIORA_Cubic ||
2732 200626 : psExtraArg->eResampleAlg == GRIORA_CubicSpline ||
2733 200625 : psExtraArg->eResampleAlg == GRIORA_Bilinear ||
2734 201414 : psExtraArg->eResampleAlg == GRIORA_Lanczos) &&
2735 951 : !(nXSize == nBufXSize && nYSize == nBufYSize) && nBandCount > 1)
2736 : {
2737 930 : if (nBufXSize < nXSize && nBufYSize < nYSize && AreOverviewsEnabled())
2738 : {
2739 719 : int bTried = FALSE;
2740 719 : const CPLErr eErr = TryOverviewRasterIO(
2741 : eRWFlag, nXOff, nYOff, nXSize, nYSize, pData, nBufXSize,
2742 : nBufYSize, eBufType, nBandCount, panBandMap, nPixelSpace,
2743 : nLineSpace, nBandSpace, psExtraArg, &bTried);
2744 719 : if (bTried)
2745 1 : return eErr;
2746 : }
2747 :
2748 929 : GDALDataType eFirstBandDT = GDT_Unknown;
2749 929 : int nFirstMaskFlags = 0;
2750 929 : GDALRasterBand *poFirstMaskBand = nullptr;
2751 929 : int nOKBands = 0;
2752 :
2753 : // Check if bands share the same mask band
2754 2921 : for (int i = 0; i < nBandCount; ++i)
2755 : {
2756 2652 : GDALRasterBand *poBand = GetRasterBand(panBandMap[i]);
2757 4629 : if ((nBufXSize < nXSize || nBufYSize < nYSize) &&
2758 1977 : poBand->GetOverviewCount())
2759 : {
2760 : // Could be improved to select the appropriate overview.
2761 3 : break;
2762 : }
2763 2649 : if (poBand->GetColorTable() != nullptr)
2764 : {
2765 0 : break;
2766 : }
2767 2649 : const GDALDataType eDT = poBand->GetRasterDataType();
2768 2649 : if (GDALDataTypeIsComplex(eDT))
2769 : {
2770 30 : break;
2771 : }
2772 2619 : if (i == 0)
2773 : {
2774 896 : eFirstBandDT = eDT;
2775 896 : nFirstMaskFlags = poBand->GetMaskFlags();
2776 896 : if (nFirstMaskFlags == GMF_NODATA)
2777 : {
2778 : // The dataset-level resampling code is not ready for nodata
2779 : // Fallback to band-level resampling
2780 10 : break;
2781 : }
2782 886 : poFirstMaskBand = poBand->GetMaskBand();
2783 : }
2784 : else
2785 : {
2786 1723 : if (eDT != eFirstBandDT)
2787 : {
2788 0 : break;
2789 : }
2790 1723 : int nMaskFlags = poBand->GetMaskFlags();
2791 1723 : if (nMaskFlags == GMF_NODATA)
2792 : {
2793 : // The dataset-level resampling code is not ready for nodata
2794 : // Fallback to band-level resampling
2795 0 : break;
2796 : }
2797 1723 : GDALRasterBand *poMaskBand = poBand->GetMaskBand();
2798 1723 : if (nFirstMaskFlags == GMF_ALL_VALID &&
2799 : nMaskFlags == GMF_ALL_VALID)
2800 : {
2801 : // Ok.
2802 : }
2803 1077 : else if (poFirstMaskBand == poMaskBand)
2804 : {
2805 : // Ok.
2806 : }
2807 : else
2808 : {
2809 617 : break;
2810 : }
2811 : }
2812 :
2813 1992 : ++nOKBands;
2814 : }
2815 :
2816 929 : GDALProgressFunc pfnProgressGlobal = psExtraArg->pfnProgress;
2817 929 : void *pProgressDataGlobal = psExtraArg->pProgressData;
2818 :
2819 929 : CPLErr eErr = CE_None;
2820 929 : if (nOKBands > 0)
2821 : {
2822 886 : if (nOKBands < nBandCount)
2823 : {
2824 617 : psExtraArg->pfnProgress = GDALScaledProgress;
2825 1234 : psExtraArg->pProgressData = GDALCreateScaledProgress(
2826 617 : 0.0, static_cast<double>(nOKBands) / nBandCount,
2827 : pfnProgressGlobal, pProgressDataGlobal);
2828 617 : if (psExtraArg->pProgressData == nullptr)
2829 228 : psExtraArg->pfnProgress = nullptr;
2830 : }
2831 :
2832 886 : eErr = RasterIOResampled(eRWFlag, nXOff, nYOff, nXSize, nYSize,
2833 : pData, nBufXSize, nBufYSize, eBufType,
2834 : nOKBands, panBandMap, nPixelSpace,
2835 : nLineSpace, nBandSpace, psExtraArg);
2836 :
2837 886 : if (nOKBands < nBandCount)
2838 : {
2839 617 : GDALDestroyScaledProgress(psExtraArg->pProgressData);
2840 : }
2841 : }
2842 929 : if (eErr == CE_None && nOKBands < nBandCount)
2843 : {
2844 657 : if (nOKBands > 0)
2845 : {
2846 614 : psExtraArg->pfnProgress = GDALScaledProgress;
2847 1228 : psExtraArg->pProgressData = GDALCreateScaledProgress(
2848 614 : static_cast<double>(nOKBands) / nBandCount, 1.0,
2849 : pfnProgressGlobal, pProgressDataGlobal);
2850 614 : if (psExtraArg->pProgressData == nullptr)
2851 225 : psExtraArg->pfnProgress = nullptr;
2852 : }
2853 1314 : eErr = BandBasedRasterIO(
2854 : eRWFlag, nXOff, nYOff, nXSize, nYSize,
2855 657 : static_cast<GByte *>(pData) + nBandSpace * nOKBands, nBufXSize,
2856 : nBufYSize, eBufType, nBandCount - nOKBands,
2857 657 : panBandMap + nOKBands, nPixelSpace, nLineSpace, nBandSpace,
2858 : psExtraArg);
2859 657 : if (nOKBands > 0)
2860 : {
2861 614 : GDALDestroyScaledProgress(psExtraArg->pProgressData);
2862 : }
2863 : }
2864 :
2865 929 : psExtraArg->pfnProgress = pfnProgressGlobal;
2866 929 : psExtraArg->pProgressData = pProgressDataGlobal;
2867 :
2868 929 : return eErr;
2869 : }
2870 :
2871 380073 : return BandBasedRasterIO(eRWFlag, nXOff, nYOff, nXSize, nYSize, pData,
2872 : nBufXSize, nBufYSize, eBufType, nBandCount,
2873 : panBandMap, nPixelSpace, nLineSpace, nBandSpace,
2874 380073 : psExtraArg);
2875 : }
2876 :
2877 : //! @endcond
2878 :
2879 : /************************************************************************/
2880 : /* BandBasedRasterIO() */
2881 : /* */
2882 : /* Pass the request off to each band objects rasterio methods with */
2883 : /* appropriate arguments. */
2884 : /************************************************************************/
2885 :
2886 : //! @cond Doxygen_Suppress
2887 654668 : CPLErr GDALDataset::BandBasedRasterIO(
2888 : GDALRWFlag eRWFlag, int nXOff, int nYOff, int nXSize, int nYSize,
2889 : void *pData, int nBufXSize, int nBufYSize, GDALDataType eBufType,
2890 : int nBandCount, const int *panBandMap, GSpacing nPixelSpace,
2891 : GSpacing nLineSpace, GSpacing nBandSpace, GDALRasterIOExtraArg *psExtraArg)
2892 :
2893 : {
2894 : int iBandIndex;
2895 654668 : CPLErr eErr = CE_None;
2896 :
2897 654668 : GDALProgressFunc pfnProgressGlobal = psExtraArg->pfnProgress;
2898 654668 : void *pProgressDataGlobal = psExtraArg->pProgressData;
2899 :
2900 1699490 : for (iBandIndex = 0; iBandIndex < nBandCount && eErr == CE_None;
2901 : ++iBandIndex)
2902 : {
2903 1044820 : GDALRasterBand *poBand = GetRasterBand(panBandMap[iBandIndex]);
2904 :
2905 1044820 : if (poBand == nullptr)
2906 : {
2907 0 : eErr = CE_Failure;
2908 0 : break;
2909 : }
2910 :
2911 1044820 : GByte *pabyBandData =
2912 1044820 : static_cast<GByte *>(pData) + iBandIndex * nBandSpace;
2913 :
2914 1044820 : if (nBandCount > 1)
2915 : {
2916 575060 : psExtraArg->pfnProgress = GDALScaledProgress;
2917 1150120 : psExtraArg->pProgressData = GDALCreateScaledProgress(
2918 : 1.0 * iBandIndex / nBandCount,
2919 575060 : 1.0 * (iBandIndex + 1) / nBandCount, pfnProgressGlobal,
2920 : pProgressDataGlobal);
2921 575060 : if (psExtraArg->pProgressData == nullptr)
2922 571949 : psExtraArg->pfnProgress = nullptr;
2923 : }
2924 :
2925 2089640 : eErr = poBand->IRasterIO(eRWFlag, nXOff, nYOff, nXSize, nYSize,
2926 : pabyBandData, nBufXSize, nBufYSize, eBufType,
2927 1044820 : nPixelSpace, nLineSpace, psExtraArg);
2928 :
2929 1044820 : if (nBandCount > 1)
2930 575060 : GDALDestroyScaledProgress(psExtraArg->pProgressData);
2931 : }
2932 :
2933 654668 : psExtraArg->pfnProgress = pfnProgressGlobal;
2934 654668 : psExtraArg->pProgressData = pProgressDataGlobal;
2935 :
2936 654668 : return eErr;
2937 : }
2938 :
2939 : //! @endcond
2940 :
2941 : /************************************************************************/
2942 : /* ValidateRasterIOOrAdviseReadParameters() */
2943 : /************************************************************************/
2944 :
2945 : //! @cond Doxygen_Suppress
2946 753051 : CPLErr GDALDataset::ValidateRasterIOOrAdviseReadParameters(
2947 : const char *pszCallingFunc, int *pbStopProcessingOnCENone, int nXOff,
2948 : int nYOff, int nXSize, int nYSize, int nBufXSize, int nBufYSize,
2949 : int nBandCount, const int *panBandMap)
2950 : {
2951 :
2952 : /* -------------------------------------------------------------------- */
2953 : /* Some size values are "noop". Lets just return to avoid */
2954 : /* stressing lower level functions. */
2955 : /* -------------------------------------------------------------------- */
2956 753051 : if (nXSize < 1 || nYSize < 1 || nBufXSize < 1 || nBufYSize < 1)
2957 : {
2958 27 : CPLDebug("GDAL",
2959 : "%s skipped for odd window or buffer size.\n"
2960 : " Window = (%d,%d)x%dx%d\n"
2961 : " Buffer = %dx%d",
2962 : pszCallingFunc, nXOff, nYOff, nXSize, nYSize, nBufXSize,
2963 : nBufYSize);
2964 :
2965 27 : *pbStopProcessingOnCENone = TRUE;
2966 27 : return CE_None;
2967 : }
2968 :
2969 753024 : CPLErr eErr = CE_None;
2970 753024 : *pbStopProcessingOnCENone = FALSE;
2971 :
2972 753024 : if (nXOff < 0 || nXSize > nRasterXSize - nXOff || nYOff < 0 ||
2973 753022 : nYSize > nRasterYSize - nYOff)
2974 : {
2975 2 : ReportError(CE_Failure, CPLE_IllegalArg,
2976 : "Access window out of range in %s. Requested "
2977 : "(%d,%d) of size %dx%d on raster of %dx%d.",
2978 : pszCallingFunc, nXOff, nYOff, nXSize, nYSize, nRasterXSize,
2979 : nRasterYSize);
2980 2 : eErr = CE_Failure;
2981 : }
2982 :
2983 753024 : if (panBandMap == nullptr && nBandCount > GetRasterCount())
2984 : {
2985 0 : ReportError(CE_Failure, CPLE_IllegalArg,
2986 : "%s: nBandCount cannot be greater than %d", pszCallingFunc,
2987 : GetRasterCount());
2988 0 : eErr = CE_Failure;
2989 : }
2990 :
2991 2260600 : for (int i = 0; i < nBandCount && eErr == CE_None; ++i)
2992 : {
2993 1507580 : int iBand = (panBandMap != nullptr) ? panBandMap[i] : i + 1;
2994 1507580 : if (iBand < 1 || iBand > GetRasterCount())
2995 : {
2996 3 : ReportError(
2997 : CE_Failure, CPLE_IllegalArg,
2998 : "%s: panBandMap[%d] = %d, this band does not exist on dataset.",
2999 : pszCallingFunc, i, iBand);
3000 3 : eErr = CE_Failure;
3001 : }
3002 :
3003 1507580 : if (eErr == CE_None && GetRasterBand(iBand) == nullptr)
3004 : {
3005 0 : ReportError(
3006 : CE_Failure, CPLE_IllegalArg,
3007 : "%s: panBandMap[%d]=%d, this band should exist but is NULL!",
3008 : pszCallingFunc, i, iBand);
3009 0 : eErr = CE_Failure;
3010 : }
3011 : }
3012 :
3013 753024 : return eErr;
3014 : }
3015 :
3016 : //! @endcond
3017 :
3018 : /************************************************************************/
3019 : /* RasterIO() */
3020 : /************************************************************************/
3021 :
3022 : /**
3023 : * \brief Read/write a region of image data from multiple bands.
3024 : *
3025 : * This method allows reading a region of one or more GDALRasterBands from
3026 : * this dataset into a buffer, or writing data from a buffer into a region
3027 : * of the GDALRasterBands. It automatically takes care of data type
3028 : * translation if the data type (eBufType) of the buffer is different than
3029 : * that of the GDALRasterBand.
3030 : * The method also takes care of image decimation / replication if the
3031 : * buffer size (nBufXSize x nBufYSize) is different than the size of the
3032 : * region being accessed (nXSize x nYSize).
3033 : *
3034 : * The window of interest expressed by (nXOff, nYOff, nXSize, nYSize) should be
3035 : * fully within the raster space, that is nXOff >= 0, nYOff >= 0,
3036 : * nXOff + nXSize <= GetRasterXSize() and nYOff + nYSize <= GetRasterYSize().
3037 : * If reads larger than the raster space are wished, GDALTranslate() might be used.
3038 : * Or use nLineSpace and a possibly shifted pData value.
3039 : *
3040 : * The nPixelSpace, nLineSpace and nBandSpace parameters allow reading into or
3041 : * writing from various organization of buffers.
3042 : *
3043 : * Some formats may efficiently implement decimation into a buffer by
3044 : * reading from lower resolution overview images. The logic of the default
3045 : * implementation in the base class GDALRasterBand is the following one. It
3046 : * computes a target_downscaling_factor from the window of interest and buffer
3047 : * size which is min(nXSize/nBufXSize, nYSize/nBufYSize).
3048 : * It then walks through overviews and will select the first one whose
3049 : * downscaling factor is greater than target_downscaling_factor / 1.2.
3050 : *
3051 : * Let's assume we have overviews at downscaling factors 2, 4 and 8.
3052 : * The relationship between target_downscaling_factor and the select overview
3053 : * level is the following one:
3054 : *
3055 : * target_downscaling_factor | selected_overview
3056 : * ------------------------- | -----------------
3057 : * ]0, 2 / 1.2] | full resolution band
3058 : * ]2 / 1.2, 4 / 1.2] | 2x downsampled band
3059 : * ]4 / 1.2, 8 / 1.2] | 4x downsampled band
3060 : * ]8 / 1.2, infinity[ | 8x downsampled band
3061 : *
3062 : * Note that starting with GDAL 3.9, this 1.2 oversampling factor can be
3063 : * modified by setting the GDAL_OVERVIEW_OVERSAMPLING_THRESHOLD configuration
3064 : * option. Also note that starting with GDAL 3.9, when the resampling algorithm
3065 : * specified in psExtraArg->eResampleAlg is different from GRIORA_NearestNeighbour,
3066 : * this oversampling threshold defaults to 1. Consequently if there are overviews
3067 : * of downscaling factor 2, 4 and 8, and the desired downscaling factor is
3068 : * 7.99, the overview of factor 4 will be selected for a non nearest resampling.
3069 : *
3070 : * For highest performance full resolution data access, read and write
3071 : * on "block boundaries" as returned by GetBlockSize(), or use the
3072 : * ReadBlock() and WriteBlock() methods.
3073 : *
3074 : * This method is the same as the C GDALDatasetRasterIO() or
3075 : * GDALDatasetRasterIOEx() functions.
3076 : *
3077 : * @param eRWFlag Either GF_Read to read a region of data, or GF_Write to
3078 : * write a region of data.
3079 : *
3080 : * @param nXOff The pixel offset to the top left corner of the region
3081 : * of the band to be accessed. This would be zero to start from the left side.
3082 : *
3083 : * @param nYOff The line offset to the top left corner of the region
3084 : * of the band to be accessed. This would be zero to start from the top.
3085 : *
3086 : * @param nXSize The width of the region of the band to be accessed in pixels.
3087 : *
3088 : * @param nYSize The height of the region of the band to be accessed in lines.
3089 : *
3090 : * @param pData The buffer into which the data should be read, or from which
3091 : * it should be written. This buffer must contain at least
3092 : * nBufXSize * nBufYSize * nBandCount words of type eBufType. It is organized
3093 : * in left to right,top to bottom pixel order. Spacing is controlled by the
3094 : * nPixelSpace, and nLineSpace parameters.
3095 : * Note that even with eRWFlag==GF_Write, the content of the buffer might be
3096 : * temporarily modified during the execution of this method (and eventually
3097 : * restored back to its original content), so it is not safe to use a buffer
3098 : * stored in a read-only section of the calling program.
3099 : *
3100 : * @param nBufXSize the width of the buffer image into which the desired region
3101 : * is to be read, or from which it is to be written.
3102 : *
3103 : * @param nBufYSize the height of the buffer image into which the desired
3104 : * region is to be read, or from which it is to be written.
3105 : *
3106 : * @param eBufType the type of the pixel values in the pData data buffer. The
3107 : * pixel values will automatically be translated to/from the GDALRasterBand
3108 : * data type as needed. Most driver implementations will use GDALCopyWords64()
3109 : * to perform data type translation.
3110 : *
3111 : * @param nBandCount the number of bands being read or written.
3112 : *
3113 : * @param panBandMap the list of nBandCount band numbers being read/written.
3114 : * Note band numbers are 1 based. This may be NULL to select the first
3115 : * nBandCount bands. (Note: before GDAL 3.10, argument type was "int*", and
3116 : * not "const int*")
3117 : *
3118 : * @param nPixelSpace The byte offset from the start of one pixel value in
3119 : * pData to the start of the next pixel value within a scanline. If defaulted
3120 : * (0) the size of the datatype eBufType is used.
3121 : *
3122 : * @param nLineSpace The byte offset from the start of one scanline in
3123 : * pData to the start of the next. If defaulted (0) the size of the datatype
3124 : * eBufType * nBufXSize is used.
3125 : *
3126 : * @param nBandSpace the byte offset from the start of one bands data to the
3127 : * start of the next. If defaulted (0) the value will be
3128 : * nLineSpace * nBufYSize implying band sequential organization
3129 : * of the data buffer.
3130 : *
3131 : * @param psExtraArg pointer to a GDALRasterIOExtraArg
3132 : * structure with additional arguments to specify resampling and progress
3133 : * callback, or NULL for default behavior. The GDAL_RASTERIO_RESAMPLING
3134 : * configuration option can also be defined to override the default resampling
3135 : * to one of BILINEAR, CUBIC, CUBICSPLINE, LANCZOS, AVERAGE or MODE.
3136 : *
3137 : * @return CE_Failure if the access fails, otherwise CE_None.
3138 : */
3139 :
3140 737461 : CPLErr GDALDataset::RasterIO(GDALRWFlag eRWFlag, int nXOff, int nYOff,
3141 : int nXSize, int nYSize, void *pData, int nBufXSize,
3142 : int nBufYSize, GDALDataType eBufType,
3143 : int nBandCount, const int *panBandMap,
3144 : GSpacing nPixelSpace, GSpacing nLineSpace,
3145 : GSpacing nBandSpace,
3146 : GDALRasterIOExtraArg *psExtraArg)
3147 :
3148 : {
3149 : GDALRasterIOExtraArg sExtraArg;
3150 737461 : if (psExtraArg == nullptr)
3151 : {
3152 542659 : INIT_RASTERIO_EXTRA_ARG(sExtraArg);
3153 :
3154 : // 4 below inits are not strictly needed but make Coverity Scan
3155 : // happy
3156 542659 : sExtraArg.dfXOff = nXOff;
3157 542659 : sExtraArg.dfYOff = nYOff;
3158 542659 : sExtraArg.dfXSize = nXSize;
3159 542659 : sExtraArg.dfYSize = nYSize;
3160 :
3161 542659 : psExtraArg = &sExtraArg;
3162 : }
3163 194802 : else if (CPL_UNLIKELY(psExtraArg->nVersion >
3164 : RASTERIO_EXTRA_ARG_CURRENT_VERSION))
3165 : {
3166 0 : ReportError(CE_Failure, CPLE_AppDefined,
3167 : "Unhandled version of GDALRasterIOExtraArg");
3168 0 : return CE_Failure;
3169 : }
3170 :
3171 737461 : GDALRasterIOExtraArgSetResampleAlg(psExtraArg, nXSize, nYSize, nBufXSize,
3172 : nBufYSize);
3173 :
3174 737461 : if (CPL_UNLIKELY(nullptr == pData))
3175 : {
3176 0 : ReportError(CE_Failure, CPLE_AppDefined,
3177 : "The buffer into which the data should be read is null");
3178 0 : return CE_Failure;
3179 : }
3180 :
3181 : /* -------------------------------------------------------------------- */
3182 : /* Do some validation of parameters. */
3183 : /* -------------------------------------------------------------------- */
3184 :
3185 737461 : if (CPL_UNLIKELY(eRWFlag != GF_Read && eRWFlag != GF_Write))
3186 : {
3187 0 : ReportError(
3188 : CE_Failure, CPLE_IllegalArg,
3189 : "eRWFlag = %d, only GF_Read (0) and GF_Write (1) are legal.",
3190 : eRWFlag);
3191 0 : return CE_Failure;
3192 : }
3193 :
3194 737461 : if (eRWFlag == GF_Write)
3195 : {
3196 216749 : if (CPL_UNLIKELY(eAccess != GA_Update))
3197 : {
3198 2 : ReportError(CE_Failure, CPLE_AppDefined,
3199 : "Write operation not permitted on dataset opened "
3200 : "in read-only mode");
3201 2 : return CE_Failure;
3202 : }
3203 : }
3204 :
3205 737459 : int bStopProcessing = FALSE;
3206 737459 : CPLErr eErr = ValidateRasterIOOrAdviseReadParameters(
3207 : "RasterIO()", &bStopProcessing, nXOff, nYOff, nXSize, nYSize, nBufXSize,
3208 : nBufYSize, nBandCount, panBandMap);
3209 737459 : if (eErr != CE_None || bStopProcessing)
3210 9 : return eErr;
3211 737450 : if (CPL_UNLIKELY(eBufType == GDT_Unknown || eBufType == GDT_TypeCount))
3212 : {
3213 2 : ReportError(CE_Failure, CPLE_AppDefined,
3214 : "Illegal GDT_Unknown/GDT_TypeCount argument");
3215 2 : return CE_Failure;
3216 : }
3217 :
3218 : /* -------------------------------------------------------------------- */
3219 : /* If pixel and line spacing are defaulted assign reasonable */
3220 : /* value assuming a packed buffer. */
3221 : /* -------------------------------------------------------------------- */
3222 737448 : if (nPixelSpace == 0)
3223 425387 : nPixelSpace = GDALGetDataTypeSizeBytes(eBufType);
3224 :
3225 737448 : if (nLineSpace == 0)
3226 : {
3227 482702 : nLineSpace = nPixelSpace * nBufXSize;
3228 : }
3229 :
3230 737448 : if (nBandSpace == 0 && nBandCount > 1)
3231 : {
3232 67507 : nBandSpace = nLineSpace * nBufYSize;
3233 : }
3234 :
3235 737448 : if (panBandMap == nullptr)
3236 : {
3237 360384 : if (!m_poPrivate)
3238 0 : return CE_Failure;
3239 360384 : CPLAssert(static_cast<int>(m_poPrivate->m_anBandMap.size()) == nBands);
3240 360384 : panBandMap = m_poPrivate->m_anBandMap.data();
3241 : }
3242 :
3243 737448 : int bCallLeaveReadWrite = EnterReadWrite(eRWFlag);
3244 :
3245 : /* -------------------------------------------------------------------- */
3246 : /* We are being forced to use cached IO instead of a driver */
3247 : /* specific implementation. */
3248 : /* -------------------------------------------------------------------- */
3249 737448 : if (bForceCachedIO)
3250 : {
3251 21 : eErr = BlockBasedRasterIO(eRWFlag, nXOff, nYOff, nXSize, nYSize, pData,
3252 : nBufXSize, nBufYSize, eBufType, nBandCount,
3253 : panBandMap, nPixelSpace, nLineSpace,
3254 21 : nBandSpace, psExtraArg);
3255 : }
3256 :
3257 : /* -------------------------------------------------------------------- */
3258 : /* Call the format specific function. */
3259 : /* -------------------------------------------------------------------- */
3260 : else
3261 : {
3262 737427 : eErr = IRasterIO(eRWFlag, nXOff, nYOff, nXSize, nYSize, pData,
3263 : nBufXSize, nBufYSize, eBufType, nBandCount,
3264 : // TODO: remove this const_cast once IRasterIO()
3265 : // takes a const int*
3266 : const_cast<int *>(panBandMap), nPixelSpace, nLineSpace,
3267 737427 : nBandSpace, psExtraArg);
3268 : }
3269 :
3270 737448 : if (bCallLeaveReadWrite)
3271 407914 : LeaveReadWrite();
3272 :
3273 737448 : return eErr;
3274 : }
3275 :
3276 : /************************************************************************/
3277 : /* GDALDatasetRasterIO() */
3278 : /************************************************************************/
3279 :
3280 : /**
3281 : * \brief Read/write a region of image data from multiple bands.
3282 : *
3283 : * Use GDALDatasetRasterIOEx() if 64 bit spacings or extra arguments (resampling
3284 : * resolution, progress callback, etc. are needed)
3285 : *
3286 : * Note: before GDAL 3.10, panBandMap type was "int*", and not "const int*"
3287 : *
3288 : * @see GDALDataset::RasterIO()
3289 : */
3290 :
3291 4762 : CPLErr CPL_STDCALL GDALDatasetRasterIO(GDALDatasetH hDS, GDALRWFlag eRWFlag,
3292 : int nXOff, int nYOff, int nXSize,
3293 : int nYSize, void *pData, int nBufXSize,
3294 : int nBufYSize, GDALDataType eBufType,
3295 : int nBandCount, const int *panBandMap,
3296 : int nPixelSpace, int nLineSpace,
3297 : int nBandSpace)
3298 :
3299 : {
3300 4762 : VALIDATE_POINTER1(hDS, "GDALDatasetRasterIO", CE_Failure);
3301 :
3302 4762 : GDALDataset *poDS = GDALDataset::FromHandle(hDS);
3303 :
3304 4762 : return poDS->RasterIO(eRWFlag, nXOff, nYOff, nXSize, nYSize, pData,
3305 : nBufXSize, nBufYSize, eBufType, nBandCount,
3306 : panBandMap, nPixelSpace, nLineSpace, nBandSpace,
3307 4762 : nullptr);
3308 : }
3309 :
3310 : /************************************************************************/
3311 : /* GDALDatasetRasterIOEx() */
3312 : /************************************************************************/
3313 :
3314 : /**
3315 : * \brief Read/write a region of image data from multiple bands.
3316 : *
3317 : * Note: before GDAL 3.10, panBandMap type was "int*", and not "const int*"
3318 : *
3319 : * @see GDALDataset::RasterIO()
3320 : */
3321 :
3322 353801 : CPLErr CPL_STDCALL GDALDatasetRasterIOEx(
3323 : GDALDatasetH hDS, GDALRWFlag eRWFlag, int nXOff, int nYOff, int nXSize,
3324 : int nYSize, void *pData, int nBufXSize, int nBufYSize,
3325 : GDALDataType eBufType, int nBandCount, const int *panBandMap,
3326 : GSpacing nPixelSpace, GSpacing nLineSpace, GSpacing nBandSpace,
3327 : GDALRasterIOExtraArg *psExtraArg)
3328 :
3329 : {
3330 353801 : VALIDATE_POINTER1(hDS, "GDALDatasetRasterIOEx", CE_Failure);
3331 :
3332 353801 : GDALDataset *poDS = GDALDataset::FromHandle(hDS);
3333 :
3334 353801 : return poDS->RasterIO(eRWFlag, nXOff, nYOff, nXSize, nYSize, pData,
3335 : nBufXSize, nBufYSize, eBufType, nBandCount,
3336 : panBandMap, nPixelSpace, nLineSpace, nBandSpace,
3337 353801 : psExtraArg);
3338 : }
3339 :
3340 : /************************************************************************/
3341 : /* GetOpenDatasets() */
3342 : /************************************************************************/
3343 :
3344 : /**
3345 : * \brief Fetch all open GDAL dataset handles.
3346 : *
3347 : * This method is the same as the C function GDALGetOpenDatasets().
3348 : *
3349 : * NOTE: This method is not thread safe. The returned list may change
3350 : * at any time and it should not be freed.
3351 : *
3352 : * @param pnCount integer into which to place the count of dataset pointers
3353 : * being returned.
3354 : *
3355 : * @return a pointer to an array of dataset handles.
3356 : */
3357 :
3358 2273 : GDALDataset **GDALDataset::GetOpenDatasets(int *pnCount)
3359 :
3360 : {
3361 4546 : CPLMutexHolderD(&hDLMutex);
3362 :
3363 2273 : if (poAllDatasetMap == nullptr)
3364 : {
3365 2252 : *pnCount = 0;
3366 2252 : return nullptr;
3367 : }
3368 :
3369 21 : *pnCount = static_cast<int>(poAllDatasetMap->size());
3370 21 : ppDatasets = static_cast<GDALDataset **>(
3371 21 : CPLRealloc(ppDatasets, (*pnCount) * sizeof(GDALDataset *)));
3372 21 : std::map<GDALDataset *, GIntBig>::iterator oIter = poAllDatasetMap->begin();
3373 592 : for (int i = 0; oIter != poAllDatasetMap->end(); ++oIter, ++i)
3374 571 : ppDatasets[i] = oIter->first;
3375 21 : return ppDatasets;
3376 : }
3377 :
3378 : /************************************************************************/
3379 : /* GDALGetOpenDatasets() */
3380 : /************************************************************************/
3381 :
3382 : /**
3383 : * \brief Fetch all open GDAL dataset handles.
3384 : *
3385 : * @see GDALDataset::GetOpenDatasets()
3386 : */
3387 :
3388 0 : void CPL_STDCALL GDALGetOpenDatasets(GDALDatasetH **ppahDSList, int *pnCount)
3389 :
3390 : {
3391 0 : VALIDATE_POINTER0(ppahDSList, "GDALGetOpenDatasets");
3392 0 : VALIDATE_POINTER0(pnCount, "GDALGetOpenDatasets");
3393 :
3394 0 : *ppahDSList =
3395 0 : reinterpret_cast<GDALDatasetH *>(GDALDataset::GetOpenDatasets(pnCount));
3396 : }
3397 :
3398 : /************************************************************************/
3399 : /* GDALCleanOpenDatasetsList() */
3400 : /************************************************************************/
3401 :
3402 : // Useful when called from the child of a fork(), to avoid closing
3403 : // the datasets of the parent at the child termination.
3404 0 : void GDALNullifyOpenDatasetsList()
3405 : {
3406 0 : poAllDatasetMap = nullptr;
3407 0 : phSharedDatasetSet = nullptr;
3408 0 : ppDatasets = nullptr;
3409 0 : hDLMutex = nullptr;
3410 0 : }
3411 :
3412 : /************************************************************************/
3413 : /* GDALGetAccess() */
3414 : /************************************************************************/
3415 :
3416 : /**
3417 : * \brief Return access flag
3418 : *
3419 : * @see GDALDataset::GetAccess()
3420 : */
3421 :
3422 0 : int CPL_STDCALL GDALGetAccess(GDALDatasetH hDS)
3423 : {
3424 0 : VALIDATE_POINTER1(hDS, "GDALGetAccess", 0);
3425 :
3426 0 : return GDALDataset::FromHandle(hDS)->GetAccess();
3427 : }
3428 :
3429 : /************************************************************************/
3430 : /* AdviseRead() */
3431 : /************************************************************************/
3432 :
3433 : /**
3434 : * \brief Advise driver of upcoming read requests.
3435 : *
3436 : * Some GDAL drivers operate more efficiently if they know in advance what
3437 : * set of upcoming read requests will be made. The AdviseRead() method allows
3438 : * an application to notify the driver of the region and bands of interest,
3439 : * and at what resolution the region will be read.
3440 : *
3441 : * Many drivers just ignore the AdviseRead() call, but it can dramatically
3442 : * accelerate access via some drivers.
3443 : *
3444 : * Depending on call paths, drivers might receive several calls to
3445 : * AdviseRead() with the same parameters.
3446 : *
3447 : * @param nXOff The pixel offset to the top left corner of the region
3448 : * of the band to be accessed. This would be zero to start from the left side.
3449 : *
3450 : * @param nYOff The line offset to the top left corner of the region
3451 : * of the band to be accessed. This would be zero to start from the top.
3452 : *
3453 : * @param nXSize The width of the region of the band to be accessed in pixels.
3454 : *
3455 : * @param nYSize The height of the region of the band to be accessed in lines.
3456 : *
3457 : * @param nBufXSize the width of the buffer image into which the desired region
3458 : * is to be read, or from which it is to be written.
3459 : *
3460 : * @param nBufYSize the height of the buffer image into which the desired
3461 : * region is to be read, or from which it is to be written.
3462 : *
3463 : * @param eBufType the type of the pixel values in the pData data buffer. The
3464 : * pixel values will automatically be translated to/from the GDALRasterBand
3465 : * data type as needed.
3466 : *
3467 : * @param nBandCount the number of bands being read or written.
3468 : *
3469 : * @param panBandMap the list of nBandCount band numbers being read/written.
3470 : * Note band numbers are 1 based. This may be NULL to select the first
3471 : * nBandCount bands.
3472 : *
3473 : * @param papszOptions a list of name=value strings with special control
3474 : * options. Normally this is NULL.
3475 : *
3476 : * @return CE_Failure if the request is invalid and CE_None if it works or
3477 : * is ignored.
3478 : */
3479 :
3480 15304 : CPLErr GDALDataset::AdviseRead(int nXOff, int nYOff, int nXSize, int nYSize,
3481 : int nBufXSize, int nBufYSize,
3482 : GDALDataType eBufType, int nBandCount,
3483 : int *panBandMap, CSLConstList papszOptions)
3484 :
3485 : {
3486 : /* -------------------------------------------------------------------- */
3487 : /* Do some validation of parameters. */
3488 : /* -------------------------------------------------------------------- */
3489 15304 : int bStopProcessing = FALSE;
3490 15304 : CPLErr eErr = ValidateRasterIOOrAdviseReadParameters(
3491 : "AdviseRead()", &bStopProcessing, nXOff, nYOff, nXSize, nYSize,
3492 : nBufXSize, nBufYSize, nBandCount, panBandMap);
3493 15304 : if (eErr != CE_None || bStopProcessing)
3494 23 : return eErr;
3495 :
3496 130016 : for (int iBand = 0; iBand < nBandCount; ++iBand)
3497 : {
3498 114739 : GDALRasterBand *poBand = nullptr;
3499 :
3500 114739 : if (panBandMap == nullptr)
3501 113208 : poBand = GetRasterBand(iBand + 1);
3502 : else
3503 1531 : poBand = GetRasterBand(panBandMap[iBand]);
3504 :
3505 114739 : if (poBand == nullptr)
3506 0 : return CE_Failure;
3507 :
3508 229478 : eErr = poBand->AdviseRead(nXOff, nYOff, nXSize, nYSize, nBufXSize,
3509 114739 : nBufYSize, eBufType, papszOptions);
3510 :
3511 114739 : if (eErr != CE_None)
3512 4 : return eErr;
3513 : }
3514 :
3515 15277 : return CE_None;
3516 : }
3517 :
3518 : /************************************************************************/
3519 : /* GDALDatasetAdviseRead() */
3520 : /************************************************************************/
3521 :
3522 : /**
3523 : * \brief Advise driver of upcoming read requests.
3524 : *
3525 : * @see GDALDataset::AdviseRead()
3526 : */
3527 7 : CPLErr CPL_STDCALL GDALDatasetAdviseRead(GDALDatasetH hDS, int nXOff, int nYOff,
3528 : int nXSize, int nYSize, int nBufXSize,
3529 : int nBufYSize, GDALDataType eDT,
3530 : int nBandCount, int *panBandMap,
3531 : CSLConstList papszOptions)
3532 :
3533 : {
3534 7 : VALIDATE_POINTER1(hDS, "GDALDatasetAdviseRead", CE_Failure);
3535 :
3536 14 : return GDALDataset::FromHandle(hDS)->AdviseRead(
3537 : nXOff, nYOff, nXSize, nYSize, nBufXSize, nBufYSize, eDT, nBandCount,
3538 7 : panBandMap, const_cast<char **>(papszOptions));
3539 : }
3540 :
3541 : /************************************************************************/
3542 : /* GDALAntiRecursionStruct */
3543 : /************************************************************************/
3544 :
3545 : // Prevent infinite recursion.
3546 : struct GDALAntiRecursionStruct
3547 : {
3548 : struct DatasetContext
3549 : {
3550 : std::string osFilename;
3551 : int nOpenFlags;
3552 : std::string osAllowedDrivers;
3553 :
3554 87154 : DatasetContext(const std::string &osFilenameIn, int nOpenFlagsIn,
3555 : const std::string &osAllowedDriversIn)
3556 87154 : : osFilename(osFilenameIn), nOpenFlags(nOpenFlagsIn),
3557 87154 : osAllowedDrivers(osAllowedDriversIn)
3558 : {
3559 87154 : }
3560 : };
3561 :
3562 : struct DatasetContextCompare
3563 : {
3564 1049930 : bool operator()(const DatasetContext &lhs,
3565 : const DatasetContext &rhs) const
3566 : {
3567 3073420 : return lhs.osFilename < rhs.osFilename ||
3568 1018640 : (lhs.osFilename == rhs.osFilename &&
3569 1004840 : (lhs.nOpenFlags < rhs.nOpenFlags ||
3570 1993330 : (lhs.nOpenFlags == rhs.nOpenFlags &&
3571 2044550 : lhs.osAllowedDrivers < rhs.osAllowedDrivers)));
3572 : }
3573 : };
3574 :
3575 1378 : ~GDALAntiRecursionStruct()
3576 1378 : {
3577 1378 : CPLAssert(aosDatasetNamesWithFlags.empty());
3578 1378 : CPLAssert(nRecLevel == 0);
3579 1378 : CPLAssert(m_oMapDepth.empty());
3580 1378 : }
3581 :
3582 : std::set<DatasetContext, DatasetContextCompare> aosDatasetNamesWithFlags{};
3583 : int nRecLevel = 0;
3584 : std::map<std::string, int> m_oMapDepth{};
3585 : };
3586 :
3587 : #ifdef _WIN32
3588 : // Currently thread_local and C++ objects don't work well with DLL on Windows
3589 : static void FreeAntiRecursionOpen(void *pData)
3590 : {
3591 : delete static_cast<GDALAntiRecursionStruct *>(pData);
3592 : }
3593 :
3594 : static GDALAntiRecursionStruct &GetAntiRecursionOpen()
3595 : {
3596 : static GDALAntiRecursionStruct dummy;
3597 : int bMemoryErrorOccurred = false;
3598 : void *pData =
3599 : CPLGetTLSEx(CTLS_GDALOPEN_ANTIRECURSION, &bMemoryErrorOccurred);
3600 : if (bMemoryErrorOccurred)
3601 : {
3602 : return dummy;
3603 : }
3604 : if (pData == nullptr)
3605 : {
3606 : auto pAntiRecursion = new GDALAntiRecursionStruct();
3607 : CPLSetTLSWithFreeFuncEx(CTLS_GDALOPEN_ANTIRECURSION, pAntiRecursion,
3608 : FreeAntiRecursionOpen, &bMemoryErrorOccurred);
3609 : if (bMemoryErrorOccurred)
3610 : {
3611 : delete pAntiRecursion;
3612 : return dummy;
3613 : }
3614 : return *pAntiRecursion;
3615 : }
3616 : return *static_cast<GDALAntiRecursionStruct *>(pData);
3617 : }
3618 : #else
3619 : static thread_local GDALAntiRecursionStruct g_tls_antiRecursion;
3620 :
3621 359399 : static GDALAntiRecursionStruct &GetAntiRecursionOpen()
3622 : {
3623 359399 : return g_tls_antiRecursion;
3624 : }
3625 : #endif
3626 :
3627 : //! @cond Doxygen_Suppress
3628 272245 : GDALAntiRecursionGuard::GDALAntiRecursionGuard(const std::string &osIdentifier)
3629 272245 : : m_psAntiRecursionStruct(&GetAntiRecursionOpen()),
3630 : m_osIdentifier(osIdentifier),
3631 272245 : m_nDepth(++m_psAntiRecursionStruct->m_oMapDepth[m_osIdentifier])
3632 : {
3633 272245 : CPLAssert(!osIdentifier.empty());
3634 272245 : }
3635 :
3636 272245 : GDALAntiRecursionGuard::GDALAntiRecursionGuard(
3637 272245 : const GDALAntiRecursionGuard &other, const std::string &osIdentifier)
3638 272245 : : m_psAntiRecursionStruct(other.m_psAntiRecursionStruct),
3639 272245 : m_osIdentifier(osIdentifier.empty()
3640 : ? osIdentifier
3641 31178 : : other.m_osIdentifier + osIdentifier),
3642 272245 : m_nDepth(m_osIdentifier.empty()
3643 272245 : ? 0
3644 303423 : : ++m_psAntiRecursionStruct->m_oMapDepth[m_osIdentifier])
3645 : {
3646 272245 : }
3647 :
3648 544490 : GDALAntiRecursionGuard::~GDALAntiRecursionGuard()
3649 : {
3650 544490 : if (!m_osIdentifier.empty())
3651 : {
3652 303423 : auto oIter = m_psAntiRecursionStruct->m_oMapDepth.find(m_osIdentifier);
3653 303423 : CPLAssert(oIter != m_psAntiRecursionStruct->m_oMapDepth.end());
3654 303423 : if (--(oIter->second) == 0)
3655 298966 : m_psAntiRecursionStruct->m_oMapDepth.erase(oIter);
3656 : }
3657 544490 : }
3658 :
3659 : //! @endcond
3660 :
3661 : /************************************************************************/
3662 : /* GetFileList() */
3663 : /************************************************************************/
3664 :
3665 : /**
3666 : * \brief Fetch files forming dataset.
3667 : *
3668 : * Returns a list of files believed to be part of this dataset. If it returns
3669 : * an empty list of files it means there is believed to be no local file
3670 : * system files associated with the dataset (for instance a virtual dataset).
3671 : * The returned file list is owned by the caller and should be deallocated
3672 : * with CSLDestroy().
3673 : *
3674 : * The returned filenames will normally be relative or absolute paths
3675 : * depending on the path used to originally open the dataset. The strings
3676 : * will be UTF-8 encoded.
3677 : *
3678 : * This method is the same as the C GDALGetFileList() function.
3679 : *
3680 : * @return NULL or a NULL terminated array of file names.
3681 : */
3682 :
3683 4703 : char **GDALDataset::GetFileList()
3684 :
3685 : {
3686 9406 : CPLString osMainFilename = GetDescription();
3687 : VSIStatBufL sStat;
3688 :
3689 4703 : GDALAntiRecursionStruct &sAntiRecursion = GetAntiRecursionOpen();
3690 : GDALAntiRecursionStruct::DatasetContext datasetCtxt(osMainFilename, 0,
3691 9406 : std::string());
3692 4703 : auto &aosDatasetList = sAntiRecursion.aosDatasetNamesWithFlags;
3693 4703 : if (cpl::contains(aosDatasetList, datasetCtxt))
3694 0 : return nullptr;
3695 :
3696 : /* -------------------------------------------------------------------- */
3697 : /* Is the main filename even a real filesystem object? */
3698 : /* -------------------------------------------------------------------- */
3699 : int bMainFileReal =
3700 4703 : VSIStatExL(osMainFilename, &sStat, VSI_STAT_EXISTS_FLAG) == 0;
3701 :
3702 : /* -------------------------------------------------------------------- */
3703 : /* Form new list. */
3704 : /* -------------------------------------------------------------------- */
3705 4703 : char **papszList = nullptr;
3706 :
3707 4703 : if (bMainFileReal)
3708 4623 : papszList = CSLAddString(papszList, osMainFilename);
3709 :
3710 4703 : if (sAntiRecursion.nRecLevel == 100)
3711 : {
3712 0 : CPLError(CE_Failure, CPLE_AppDefined,
3713 : "GetFileList() called with too many recursion levels");
3714 0 : return papszList;
3715 : }
3716 4703 : ++sAntiRecursion.nRecLevel;
3717 :
3718 : /* -------------------------------------------------------------------- */
3719 : /* Do we have a known overview file? */
3720 : /* -------------------------------------------------------------------- */
3721 4703 : if (oOvManager.IsInitialized() && oOvManager.poODS != nullptr)
3722 : {
3723 60 : auto iter = aosDatasetList.insert(datasetCtxt).first;
3724 60 : char **papszOvrList = oOvManager.poODS->GetFileList();
3725 60 : papszList = CSLInsertStrings(papszList, -1, papszOvrList);
3726 60 : CSLDestroy(papszOvrList);
3727 60 : aosDatasetList.erase(iter);
3728 : }
3729 :
3730 : /* -------------------------------------------------------------------- */
3731 : /* Do we have a known mask file? */
3732 : /* -------------------------------------------------------------------- */
3733 4703 : if (oOvManager.HaveMaskFile())
3734 : {
3735 9 : auto iter = aosDatasetList.insert(std::move(datasetCtxt)).first;
3736 9 : for (const char *pszFile :
3737 18 : CPLStringList(oOvManager.poMaskDS->GetFileList()))
3738 : {
3739 9 : if (CSLFindString(papszList, pszFile) < 0)
3740 9 : papszList = CSLAddString(papszList, pszFile);
3741 : }
3742 9 : aosDatasetList.erase(iter);
3743 : }
3744 :
3745 4703 : --sAntiRecursion.nRecLevel;
3746 :
3747 4703 : return papszList;
3748 : }
3749 :
3750 : /************************************************************************/
3751 : /* GDALGetFileList() */
3752 : /************************************************************************/
3753 :
3754 : /**
3755 : * \brief Fetch files forming dataset.
3756 : *
3757 : * @see GDALDataset::GetFileList()
3758 : */
3759 :
3760 3880 : char **CPL_STDCALL GDALGetFileList(GDALDatasetH hDS)
3761 :
3762 : {
3763 3880 : VALIDATE_POINTER1(hDS, "GDALGetFileList", nullptr);
3764 :
3765 3880 : return GDALDataset::FromHandle(hDS)->GetFileList();
3766 : }
3767 :
3768 : /************************************************************************/
3769 : /* CreateMaskBand() */
3770 : /************************************************************************/
3771 :
3772 : /**
3773 : * \brief Adds a mask band to the dataset
3774 : *
3775 : * The default implementation of the CreateMaskBand() method is implemented
3776 : * based on similar rules to the .ovr handling implemented using the
3777 : * GDALDefaultOverviews object. A TIFF file with the extension .msk will
3778 : * be created with the same basename as the original file, and it will have
3779 : * one band.
3780 : * The mask images will be deflate compressed tiled images with the same
3781 : * block size as the original image if possible.
3782 : * It will have INTERNAL_MASK_FLAGS_xx metadata items set at the dataset
3783 : * level, where xx matches the band number of a band of the main dataset. The
3784 : * value of those items will be the one of the nFlagsIn parameter.
3785 : *
3786 : * Note that if you got a mask band with a previous call to GetMaskBand(), it
3787 : * might be invalidated by CreateMaskBand(). So you have to call GetMaskBand()
3788 : * again.
3789 : *
3790 : *
3791 : * @param nFlagsIn 0 or combination of GMF_PER_DATASET / GMF_ALPHA.
3792 : * GMF_PER_DATASET will be always set, even if not explicitly
3793 : * specified.
3794 : * @return CE_None on success or CE_Failure on an error.
3795 : *
3796 : * @see https://gdal.org/development/rfc/rfc15_nodatabitmask.html
3797 : * @see GDALRasterBand::CreateMaskBand()
3798 : *
3799 : */
3800 17 : CPLErr GDALDataset::CreateMaskBand(int nFlagsIn)
3801 :
3802 : {
3803 17 : if (oOvManager.IsInitialized())
3804 : {
3805 17 : CPLErr eErr = oOvManager.CreateMaskBand(nFlagsIn, -1);
3806 17 : if (eErr != CE_None)
3807 0 : return eErr;
3808 :
3809 : // Invalidate existing raster band masks.
3810 45 : for (int i = 0; i < nBands; ++i)
3811 : {
3812 28 : GDALRasterBand *poBand = papoBands[i];
3813 28 : poBand->poMask.reset();
3814 : }
3815 :
3816 17 : return CE_None;
3817 : }
3818 :
3819 0 : ReportError(CE_Failure, CPLE_NotSupported,
3820 : "CreateMaskBand() not supported for this dataset.");
3821 :
3822 0 : return CE_Failure;
3823 : }
3824 :
3825 : /************************************************************************/
3826 : /* GDALCreateDatasetMaskBand() */
3827 : /************************************************************************/
3828 :
3829 : /**
3830 : * \brief Adds a mask band to the dataset
3831 : * @see GDALDataset::CreateMaskBand()
3832 : */
3833 107 : CPLErr CPL_STDCALL GDALCreateDatasetMaskBand(GDALDatasetH hDS, int nFlags)
3834 :
3835 : {
3836 107 : VALIDATE_POINTER1(hDS, "GDALCreateDatasetMaskBand", CE_Failure);
3837 :
3838 107 : return GDALDataset::FromHandle(hDS)->CreateMaskBand(nFlags);
3839 : }
3840 :
3841 : /************************************************************************/
3842 : /* GDALOpen() */
3843 : /************************************************************************/
3844 :
3845 : /**
3846 : * \brief Open a raster file as a GDALDataset.
3847 : *
3848 : * This function will try to open the passed file, or virtual dataset
3849 : * name by invoking the Open method of each registered GDALDriver in turn.
3850 : * The first successful open will result in a returned dataset. If all
3851 : * drivers fail then NULL is returned and an error is issued.
3852 : *
3853 : * Several recommendations :
3854 : * <ul>
3855 : * <li>If you open a dataset object with GA_Update access, it is not recommended
3856 : * to open a new dataset on the same underlying file.</li>
3857 : * <li>The returned dataset should only be accessed by one thread at a time. If
3858 : * you want to use it from different threads, you must add all necessary code
3859 : * (mutexes, etc.) to avoid concurrent use of the object. (Some drivers, such
3860 : * as GeoTIFF, maintain internal state variables that are updated each time a
3861 : * new block is read, thus preventing concurrent use.) </li>
3862 : * </ul>
3863 : *
3864 : * For drivers supporting the VSI virtual file API, it is possible to open a
3865 : * file in a .zip archive (see VSIInstallZipFileHandler()), in a
3866 : * .tar/.tar.gz/.tgz archive (see VSIInstallTarFileHandler()) or on a HTTP / FTP
3867 : * server (see VSIInstallCurlFileHandler())
3868 : *
3869 : * \sa GDALOpenShared()
3870 : * \sa GDALOpenEx()
3871 : *
3872 : * @param pszFilename the name of the file to access. In the case of
3873 : * exotic drivers this may not refer to a physical file, but instead contain
3874 : * information for the driver on how to access a dataset. It should be in UTF-8
3875 : * encoding.
3876 : *
3877 : * @param eAccess the desired access, either GA_Update or GA_ReadOnly. Many
3878 : * drivers support only read only access.
3879 : *
3880 : * @return A GDALDatasetH handle or NULL on failure. For C++ applications
3881 : * this handle can be cast to a GDALDataset *.
3882 : */
3883 :
3884 26863 : GDALDatasetH CPL_STDCALL GDALOpen(const char *pszFilename, GDALAccess eAccess)
3885 :
3886 : {
3887 26863 : const int nUpdateFlag = eAccess == GA_Update ? GDAL_OF_UPDATE : 0;
3888 26863 : const int nOpenFlags = GDAL_OF_RASTER | nUpdateFlag | GDAL_OF_VERBOSE_ERROR;
3889 : GDALDatasetH hDataset =
3890 26863 : GDALOpenEx(pszFilename, nOpenFlags, nullptr, nullptr, nullptr);
3891 26863 : return hDataset;
3892 : }
3893 :
3894 : /************************************************************************/
3895 : /* GetSharedDS() */
3896 : /************************************************************************/
3897 :
3898 6488 : static GDALDataset *GetSharedDS(const char *pszFilename,
3899 : unsigned int nOpenFlags,
3900 : const char *const *papszOpenOptions)
3901 : {
3902 12976 : CPLMutexHolderD(&hDLMutex);
3903 :
3904 6488 : if (phSharedDatasetSet != nullptr)
3905 : {
3906 6229 : const GIntBig nThisPID = GDALGetResponsiblePIDForCurrentThread();
3907 : SharedDatasetCtxt sStruct;
3908 :
3909 6229 : sStruct.nPID = nThisPID;
3910 6229 : sStruct.pszDescription = const_cast<char *>(pszFilename);
3911 6229 : sStruct.nOpenFlags = nOpenFlags & ~GDAL_OF_SHARED;
3912 : std::string osConcatenatedOpenOptions =
3913 6229 : GDALSharedDatasetConcatenateOpenOptions(papszOpenOptions);
3914 6229 : sStruct.pszConcatenatedOpenOptions = &osConcatenatedOpenOptions[0];
3915 6229 : sStruct.poDS = nullptr;
3916 : SharedDatasetCtxt *psStruct = static_cast<SharedDatasetCtxt *>(
3917 6229 : CPLHashSetLookup(phSharedDatasetSet, &sStruct));
3918 6229 : if (psStruct == nullptr && (nOpenFlags & GDAL_OF_UPDATE) == 0)
3919 : {
3920 123 : sStruct.nOpenFlags |= GDAL_OF_UPDATE;
3921 : psStruct = static_cast<SharedDatasetCtxt *>(
3922 123 : CPLHashSetLookup(phSharedDatasetSet, &sStruct));
3923 : }
3924 6229 : if (psStruct)
3925 : {
3926 6107 : return psStruct->poDS;
3927 : }
3928 : }
3929 381 : return nullptr;
3930 : }
3931 :
3932 : /************************************************************************/
3933 : /* GDALOpenEx() */
3934 : /************************************************************************/
3935 :
3936 : /**
3937 : * \brief Open a raster or vector file as a GDALDataset.
3938 : *
3939 : * This function will try to open the passed file, or virtual dataset
3940 : * name by invoking the Open method of each registered GDALDriver in turn.
3941 : * The first successful open will result in a returned dataset. If all
3942 : * drivers fail then NULL is returned and an error is issued.
3943 : *
3944 : * Several recommendations :
3945 : * <ul>
3946 : * <li>If you open a dataset object with GDAL_OF_UPDATE access, it is not
3947 : * recommended to open a new dataset on the same underlying file.</li>
3948 : * <li>The returned dataset should only be accessed by one thread at a time. If
3949 : * you want to use it from different threads, you must add all necessary code
3950 : * (mutexes, etc.) to avoid concurrent use of the object. (Some drivers, such
3951 : * as GeoTIFF, maintain internal state variables that are updated each time a
3952 : * new block is read, thus preventing concurrent use.) </li>
3953 : * </ul>
3954 : *
3955 : * For drivers supporting the VSI virtual file API, it is possible to open a
3956 : * file in a .zip archive (see VSIInstallZipFileHandler()), in a
3957 : * .tar/.tar.gz/.tgz archive (see VSIInstallTarFileHandler()) or on a HTTP / FTP
3958 : * server (see VSIInstallCurlFileHandler())
3959 : *
3960 : * In order to reduce the need for searches through the operating system
3961 : * file system machinery, it is possible to give an optional list of files with
3962 : * the papszSiblingFiles parameter.
3963 : * This is the list of all files at the same level in the file system as the
3964 : * target file, including the target file. The filenames must not include any
3965 : * path components, are essentially just the output of VSIReadDir() on the
3966 : * parent directory. If the target object does not have filesystem semantics
3967 : * then the file list should be NULL.
3968 : *
3969 : * @param pszFilename the name of the file to access. In the case of
3970 : * exotic drivers this may not refer to a physical file, but instead contain
3971 : * information for the driver on how to access a dataset. It should be in UTF-8
3972 : * encoding.
3973 : *
3974 : * @param nOpenFlags a combination of GDAL_OF_ flags that may be combined
3975 : * through logical or operator.
3976 : * <ul>
3977 : * <li>Driver kind:
3978 : * <ul>
3979 : * <li>GDAL_OF_RASTER for raster drivers,</li>
3980 : * <li>GDAL_OF_MULTIDIM_RASTER for multidimensional raster drivers,</li>
3981 : * <li>GDAL_OF_VECTOR for vector drivers,</li>
3982 : * <li>GDAL_OF_GNM for Geographic Network Model drivers.</li>
3983 : * </ul>
3984 : * GDAL_OF_RASTER and GDAL_OF_MULTIDIM_RASTER are generally mutually
3985 : * exclusive. If none of the value is specified, GDAL_OF_RASTER | GDAL_OF_VECTOR
3986 : * | GDAL_OF_GNM is implied.
3987 : * </li>
3988 : * <li>Access mode: GDAL_OF_READONLY (exclusive)or GDAL_OF_UPDATE.
3989 : * </li>
3990 : * <li>Shared mode: GDAL_OF_SHARED. If set,
3991 : * it allows the sharing of GDALDataset handles for a dataset with other callers
3992 : * that have set GDAL_OF_SHARED. In particular, GDALOpenEx() will first consult
3993 : * its list of currently open and shared GDALDataset's, and if the
3994 : * GetDescription() name for one exactly matches the pszFilename passed to
3995 : * GDALOpenEx() it will be referenced and returned, if GDALOpenEx() is called
3996 : * from the same thread.
3997 : * </li>
3998 : * <li>Thread safe mode: GDAL_OF_THREAD_SAFE (added in 3.10).
3999 : * This must be use in combination with GDAL_OF_RASTER, and is mutually
4000 : * exclusive with GDAL_OF_UPDATE, GDAL_OF_VECTOR, GDAL_OF_MULTIDIM_RASTER or
4001 : * GDAL_OF_GNM.
4002 : * </li>
4003 : * <li>Verbose error: GDAL_OF_VERBOSE_ERROR. If set,
4004 : * a failed attempt to open the file will lead to an error message to be
4005 : * reported.
4006 : * </li>
4007 : * </ul>
4008 : *
4009 : * @param papszAllowedDrivers NULL to consider all candidate drivers, or a NULL
4010 : * terminated list of strings with the driver short names that must be
4011 : * considered.
4012 : * Starting with GDAL 3.13, a string starting with the dash (-) character
4013 : * followed by the driver short name can be used to exclude a driver.
4014 : *
4015 : * @param papszOpenOptions NULL, or a NULL terminated list of strings with open
4016 : * options passed to candidate drivers. An option exists for all drivers,
4017 : * OVERVIEW_LEVEL=level, to select a particular overview level of a dataset.
4018 : * The level index starts at 0. The level number can be suffixed by "only" to
4019 : * specify that only this overview level must be visible, and not sub-levels.
4020 : * Open options are validated by default, and a warning is emitted in case the
4021 : * option is not recognized. In some scenarios, it might be not desirable (e.g.
4022 : * when not knowing which driver will open the file), so the special open option
4023 : * VALIDATE_OPEN_OPTIONS can be set to NO to avoid such warnings. Alternatively,
4024 : * that it may not cause a warning if the driver doesn't declare this option.
4025 : * Starting with GDAL 3.3, OVERVIEW_LEVEL=NONE is supported to indicate that
4026 : * no overviews should be exposed.
4027 : *
4028 : * @param papszSiblingFiles NULL, or a NULL terminated list of strings that are
4029 : * filenames that are auxiliary to the main filename. If NULL is passed, a
4030 : * probing of the file system will be done.
4031 : *
4032 : * @return A GDALDatasetH handle or NULL on failure. For C++ applications
4033 : * this handle can be cast to a GDALDataset *.
4034 : *
4035 : */
4036 :
4037 86567 : GDALDatasetH CPL_STDCALL GDALOpenEx(const char *pszFilename,
4038 : unsigned int nOpenFlags,
4039 : const char *const *papszAllowedDrivers,
4040 : const char *const *papszOpenOptions,
4041 : const char *const *papszSiblingFiles)
4042 : {
4043 86567 : VALIDATE_POINTER1(pszFilename, "GDALOpen", nullptr);
4044 :
4045 : // Do some sanity checks on incompatible flags with thread-safe mode.
4046 86567 : if ((nOpenFlags & GDAL_OF_THREAD_SAFE) != 0)
4047 : {
4048 : const struct
4049 : {
4050 : int nFlag;
4051 : const char *pszFlagName;
4052 128 : } asFlags[] = {
4053 : {GDAL_OF_UPDATE, "GDAL_OF_UPDATE"},
4054 : {GDAL_OF_VECTOR, "GDAL_OF_VECTOR"},
4055 : {GDAL_OF_MULTIDIM_RASTER, "GDAL_OF_MULTIDIM_RASTER"},
4056 : {GDAL_OF_GNM, "GDAL_OF_GNM"},
4057 : };
4058 :
4059 630 : for (const auto &asFlag : asFlags)
4060 : {
4061 506 : if ((nOpenFlags & asFlag.nFlag) != 0)
4062 : {
4063 4 : CPLError(CE_Failure, CPLE_IllegalArg,
4064 : "GDAL_OF_THREAD_SAFE and %s are mutually "
4065 : "exclusive",
4066 4 : asFlag.pszFlagName);
4067 4 : return nullptr;
4068 : }
4069 : }
4070 : }
4071 :
4072 : // If no driver kind is specified, assume all are to be probed.
4073 86563 : if ((nOpenFlags & GDAL_OF_KIND_MASK) == 0)
4074 7654 : nOpenFlags |= GDAL_OF_KIND_MASK & ~GDAL_OF_MULTIDIM_RASTER;
4075 :
4076 : /* -------------------------------------------------------------------- */
4077 : /* In case of shared dataset, first scan the existing list to see */
4078 : /* if it could already contain the requested dataset. */
4079 : /* -------------------------------------------------------------------- */
4080 86563 : if (nOpenFlags & GDAL_OF_SHARED)
4081 : {
4082 6488 : if (nOpenFlags & GDAL_OF_INTERNAL)
4083 : {
4084 0 : CPLError(CE_Failure, CPLE_IllegalArg,
4085 : "GDAL_OF_SHARED and GDAL_OF_INTERNAL are exclusive");
4086 0 : return nullptr;
4087 : }
4088 :
4089 : auto poSharedDS =
4090 6488 : GetSharedDS(pszFilename, nOpenFlags, papszOpenOptions);
4091 6488 : if (poSharedDS)
4092 : {
4093 6107 : poSharedDS->Reference();
4094 6107 : return poSharedDS;
4095 : }
4096 : }
4097 :
4098 80456 : CPLErrorReset();
4099 80456 : VSIErrorReset();
4100 :
4101 : // Build GDALOpenInfo just now to avoid useless file stat'ing if a
4102 : // shared dataset was asked before.
4103 80456 : GDALOpenInfo oOpenInfo(pszFilename, nOpenFlags, papszSiblingFiles);
4104 :
4105 160912 : return GDALDataset::Open(&oOpenInfo, papszAllowedDrivers, papszOpenOptions)
4106 80456 : .release();
4107 : }
4108 :
4109 : /************************************************************************/
4110 : /* GDALDataset::Open() */
4111 : /************************************************************************/
4112 :
4113 : /**
4114 : * \brief Open a raster or vector file as a GDALDataset.
4115 : *
4116 : * This function will use the passed open info on each registered GDALDriver in
4117 : * turn.
4118 : * The first successful open will result in a returned dataset. If all
4119 : * drivers fail then NULL is returned and an error is issued.
4120 : *
4121 : * Several recommendations :
4122 : * <ul>
4123 : * <li>If you open a dataset object with GDAL_OF_UPDATE access, it is not
4124 : * recommended to open a new dataset on the same underlying file.</li>
4125 : * <li>The returned dataset should only be accessed by one thread at a time. If
4126 : * you want to use it from different threads, you must add all necessary code
4127 : * (mutexes, etc.) to avoid concurrent use of the object. (Some drivers, such
4128 : * as GeoTIFF, maintain internal state variables that are updated each time a
4129 : * new block is read, thus preventing concurrent use.) </li>
4130 : * </ul>
4131 : *
4132 : * For drivers supporting the VSI virtual file API, it is possible to open a
4133 : * file in a .zip archive (see VSIInstallZipFileHandler()), in a
4134 : * .tar/.tar.gz/.tgz archive (see VSIInstallTarFileHandler()) or on a HTTP / FTP
4135 : * server (see VSIInstallCurlFileHandler())
4136 : *
4137 : * @param poOpenInfo a pointer to an open info instance. Must NOT be NULL,
4138 : * and the GDAL_OF_SHARED flag must NOT be set in poOpenInfo->nOpenFlags.
4139 : * If shared dataset is needed, use GDALOpenEx() or the other variant of
4140 : * GDALDataset::Open()
4141 : *
4142 : * @param papszAllowedDrivers NULL to consider all candidate drivers, or a NULL
4143 : * terminated list of strings with the driver short names that must be
4144 : * considered.
4145 : * Starting with GDAL 3.13, a string starting with the dash (-) character
4146 : * followed by the driver short name can be used to exclude a driver.
4147 : *
4148 : * @param papszOpenOptions NULL, or a NULL terminated list of strings with open
4149 : * options passed to candidate drivers. An option exists for all drivers,
4150 : * OVERVIEW_LEVEL=level, to select a particular overview level of a dataset.
4151 : * The level index starts at 0. The level number can be suffixed by "only" to
4152 : * specify that only this overview level must be visible, and not sub-levels.
4153 : * Open options are validated by default, and a warning is emitted in case the
4154 : * option is not recognized. In some scenarios, it might be not desirable (e.g.
4155 : * when not knowing which driver will open the file), so the special open option
4156 : * VALIDATE_OPEN_OPTIONS can be set to NO to avoid such warnings. Alternatively,
4157 : * that it may not cause a warning if the driver doesn't declare this option.
4158 : * OVERVIEW_LEVEL=NONE is supported to indicate that
4159 : * no overviews should be exposed.
4160 : *
4161 : * @return A GDALDataset unique pointer or NULL on failure.
4162 : *
4163 : * @since 3.13
4164 : */
4165 :
4166 : std::unique_ptr<GDALDataset>
4167 82451 : GDALDataset::Open(GDALOpenInfo *poOpenInfo,
4168 : const char *const *papszAllowedDrivers,
4169 : const char *const *papszOpenOptions)
4170 : {
4171 : // Hack for the ZARR driver. We translate the CACHE_KERCHUNK_JSON
4172 : // into VSIKERCHUNK_USE_CACHE config option
4173 82451 : std::unique_ptr<CPLConfigOptionSetter> poVSIKERCHUNK_USE_CACHESetter;
4174 82451 : if (CPLFetchBool(papszOpenOptions, "CACHE_KERCHUNK_JSON", false))
4175 : {
4176 13 : poVSIKERCHUNK_USE_CACHESetter = std::make_unique<CPLConfigOptionSetter>(
4177 26 : "VSIKERCHUNK_USE_CACHE", "YES", false);
4178 : }
4179 :
4180 82451 : GDALDriverManager *poDM = GetGDALDriverManager();
4181 :
4182 82451 : CPLAssert(nullptr != poDM);
4183 :
4184 82451 : GDALOpenInfo &oOpenInfo = *poOpenInfo;
4185 82451 : const char *pszFilename = poOpenInfo->pszFilename;
4186 82451 : const int nOpenFlags = poOpenInfo->nOpenFlags;
4187 82451 : oOpenInfo.papszAllowedDrivers = papszAllowedDrivers;
4188 :
4189 82451 : GDALAntiRecursionStruct &sAntiRecursion = GetAntiRecursionOpen();
4190 82451 : if (sAntiRecursion.nRecLevel == 100)
4191 : {
4192 0 : CPLError(CE_Failure, CPLE_AppDefined,
4193 : "GDALOpen() called with too many recursion levels");
4194 0 : return nullptr;
4195 : }
4196 :
4197 164902 : std::string osAllowedDrivers;
4198 177032 : for (const char *pszDriverName : cpl::Iterate(papszAllowedDrivers))
4199 94581 : osAllowedDrivers += pszDriverName;
4200 : auto dsCtxt = GDALAntiRecursionStruct::DatasetContext(
4201 247353 : std::string(pszFilename), nOpenFlags, osAllowedDrivers);
4202 82451 : if (cpl::contains(sAntiRecursion.aosDatasetNamesWithFlags, dsCtxt))
4203 : {
4204 0 : CPLError(CE_Failure, CPLE_AppDefined,
4205 : "GDALOpen() called on %s recursively", pszFilename);
4206 0 : return nullptr;
4207 : }
4208 :
4209 : // Remove leading @ if present.
4210 : char **papszOpenOptionsCleaned =
4211 82451 : CSLDuplicate(const_cast<char **>(papszOpenOptions));
4212 88115 : for (char **papszIter = papszOpenOptionsCleaned; papszIter && *papszIter;
4213 : ++papszIter)
4214 : {
4215 5664 : char *pszOption = *papszIter;
4216 5664 : if (pszOption[0] == '@')
4217 228 : memmove(pszOption, pszOption + 1, strlen(pszOption + 1) + 1);
4218 : }
4219 :
4220 82451 : oOpenInfo.papszOpenOptions = papszOpenOptionsCleaned;
4221 82451 : oOpenInfo.nOpenFlags |= GDAL_OF_FROM_GDALOPEN;
4222 :
4223 : #ifdef OGRAPISPY_ENABLED
4224 82451 : const bool bUpdate = (nOpenFlags & GDAL_OF_UPDATE) != 0;
4225 : const int iSnapshot =
4226 19596 : (nOpenFlags & GDAL_OF_VECTOR) != 0 && (nOpenFlags & GDAL_OF_RASTER) == 0
4227 102047 : ? OGRAPISpyOpenTakeSnapshot(pszFilename, bUpdate)
4228 82451 : : INT_MIN;
4229 : #endif
4230 :
4231 82451 : const int nDriverCount = poDM->GetDriverCount(/*bIncludeHidden=*/true);
4232 82451 : GDALDriver *poMissingPluginDriver = nullptr;
4233 164902 : std::vector<GDALDriver *> apoSecondPassDrivers;
4234 :
4235 : // Lookup of matching driver for dataset can involve up to 2 passes:
4236 : // - in the first pass, all drivers that are compabile of the request mode
4237 : // (raster/vector/etc.) are probed using their Identify() method if it
4238 : // exists. If the Identify() method returns FALSE, the driver is skipped.
4239 : // If the Identify() methods returns GDAL_IDENTIFY_UNKNOWN and that the
4240 : // driver is a deferred-loading plugin, it is added to the
4241 : // apoSecondPassDrivers list for potential later probing, and execution
4242 : // continues to the next driver in the list.
4243 : // Otherwise if Identify() returns non-FALSE, the Open() method is used.
4244 : // If Open() returns a non-NULL dataset, the loop stops and it is
4245 : // returned. Otherwise looping over remaining drivers continues.
4246 : // - the second pass is optional, only if at least one driver was added
4247 : // into apoSecondPassDrivers during the first pass. It is similar
4248 : // to the first pass except it runs only on apoSecondPassDrivers drivers.
4249 : // And the Open() method of such drivers is used, causing them to be
4250 : // loaded for real.
4251 82451 : int iPass = 1;
4252 82465 : retry:
4253 8553590 : for (int iDriver = 0;
4254 8553630 : iDriver < (iPass == 1 ? nDriverCount
4255 34 : : static_cast<int>(apoSecondPassDrivers.size()));
4256 : ++iDriver)
4257 : {
4258 : GDALDriver *poDriver =
4259 8534160 : iPass == 1 ? poDM->GetDriver(iDriver, /*bIncludeHidden=*/true)
4260 25 : : apoSecondPassDrivers[iDriver];
4261 8534130 : const char *pszDriverName = GDALGetDriverShortName(poDriver);
4262 8534130 : if (pszDriverName && papszAllowedDrivers)
4263 : {
4264 3841380 : bool bDriverMatchedPositively = false;
4265 3841380 : bool bDriverMatchedNegatively = false;
4266 3841380 : bool bOnlyExcludedDrivers = true;
4267 17924200 : for (const char *pszAllowedDriver :
4268 39689700 : cpl::Iterate(papszAllowedDrivers))
4269 : {
4270 17924200 : if (pszAllowedDriver[0] != '-')
4271 17918700 : bOnlyExcludedDrivers = false;
4272 17924200 : if (EQUAL(pszAllowedDriver, pszDriverName))
4273 : {
4274 89457 : bDriverMatchedPositively = true;
4275 : }
4276 17834800 : else if (pszAllowedDriver[0] == '-' &&
4277 5496 : EQUAL(pszAllowedDriver + 1, pszDriverName))
4278 : {
4279 25 : bDriverMatchedNegatively = true;
4280 25 : break;
4281 : }
4282 : }
4283 3841380 : if ((!bDriverMatchedPositively && !bOnlyExcludedDrivers) ||
4284 : bDriverMatchedNegatively)
4285 : {
4286 8036920 : continue;
4287 : }
4288 : }
4289 :
4290 4787450 : if (poDriver->GetMetadataItem(GDAL_DCAP_OPEN) == nullptr)
4291 46277 : continue;
4292 :
4293 12542800 : if ((nOpenFlags & GDAL_OF_RASTER) != 0 &&
4294 6879410 : (nOpenFlags & GDAL_OF_VECTOR) == 0 &&
4295 2138240 : poDriver->GetMetadataItem(GDAL_DCAP_RASTER) == nullptr)
4296 475784 : continue;
4297 12224700 : if ((nOpenFlags & GDAL_OF_VECTOR) != 0 &&
4298 6118490 : (nOpenFlags & GDAL_OF_RASTER) == 0 &&
4299 1853100 : poDriver->GetMetadataItem(GDAL_DCAP_VECTOR) == nullptr)
4300 1394360 : continue;
4301 6339250 : if ((nOpenFlags & GDAL_OF_MULTIDIM_RASTER) != 0 &&
4302 3173390 : (nOpenFlags & GDAL_OF_RASTER) == 0 &&
4303 302367 : poDriver->GetMetadataItem(GDAL_DCAP_MULTIDIM_RASTER) == nullptr)
4304 284973 : continue;
4305 :
4306 : // Remove general OVERVIEW_LEVEL open options from list before passing
4307 : // it to the driver, if it isn't a driver specific option already.
4308 2586050 : char **papszTmpOpenOptions = nullptr;
4309 2586050 : char **papszTmpOpenOptionsToValidate = nullptr;
4310 2586050 : char **papszOptionsToValidate = const_cast<char **>(papszOpenOptions);
4311 2586050 : if (CSLFetchNameValue(papszOpenOptionsCleaned, "OVERVIEW_LEVEL") !=
4312 2586200 : nullptr &&
4313 152 : !poDriver->HasOpenOption("OVERVIEW_LEVEL"))
4314 : {
4315 152 : papszTmpOpenOptions = CSLDuplicate(papszOpenOptionsCleaned);
4316 : papszTmpOpenOptions =
4317 152 : CSLSetNameValue(papszTmpOpenOptions, "OVERVIEW_LEVEL", nullptr);
4318 152 : oOpenInfo.papszOpenOptions = papszTmpOpenOptions;
4319 :
4320 152 : papszOptionsToValidate = CSLDuplicate(papszOptionsToValidate);
4321 152 : papszOptionsToValidate = CSLSetNameValue(papszOptionsToValidate,
4322 : "OVERVIEW_LEVEL", nullptr);
4323 152 : papszTmpOpenOptionsToValidate = papszOptionsToValidate;
4324 : }
4325 :
4326 : const int nIdentifyRes =
4327 2586050 : poDriver->pfnIdentifyEx
4328 5172100 : ? poDriver->pfnIdentifyEx(poDriver, &oOpenInfo)
4329 2586040 : : poDriver->pfnIdentify ? poDriver->pfnIdentify(&oOpenInfo)
4330 2586050 : : GDAL_IDENTIFY_UNKNOWN;
4331 2586050 : if (nIdentifyRes == FALSE)
4332 : {
4333 2088750 : CSLDestroy(papszTmpOpenOptions);
4334 2088750 : CSLDestroy(papszTmpOpenOptionsToValidate);
4335 2088750 : oOpenInfo.papszOpenOptions = papszOpenOptionsCleaned;
4336 2088750 : continue;
4337 : }
4338 497282 : else if (iPass == 1 && nIdentifyRes < 0 &&
4339 994690 : poDriver->pfnOpen == nullptr &&
4340 101 : poDriver->GetMetadataItem("IS_NON_LOADED_PLUGIN"))
4341 : {
4342 : // Not loaded plugin
4343 98 : apoSecondPassDrivers.push_back(poDriver);
4344 98 : CSLDestroy(papszTmpOpenOptions);
4345 98 : CSLDestroy(papszTmpOpenOptionsToValidate);
4346 98 : oOpenInfo.papszOpenOptions = papszOpenOptionsCleaned;
4347 98 : continue;
4348 : }
4349 :
4350 497209 : const bool bIdentifyRes = nIdentifyRes == GDAL_IDENTIFY_TRUE;
4351 497209 : if (bIdentifyRes)
4352 : {
4353 62052 : GDALValidateOpenOptions(poDriver, papszOptionsToValidate);
4354 : }
4355 :
4356 : #ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION
4357 : const bool bFpAvailableBefore = oOpenInfo.fpL != nullptr;
4358 : CPLErrorReset();
4359 : #endif
4360 :
4361 497209 : sAntiRecursion.nRecLevel++;
4362 497209 : sAntiRecursion.aosDatasetNamesWithFlags.insert(dsCtxt);
4363 :
4364 497209 : GDALDataset *poDS = poDriver->Open(&oOpenInfo, false);
4365 :
4366 497209 : sAntiRecursion.nRecLevel--;
4367 497209 : sAntiRecursion.aosDatasetNamesWithFlags.erase(dsCtxt);
4368 :
4369 497209 : if (poDriver->pfnOpen != nullptr)
4370 : {
4371 : // If we couldn't determine for sure with Identify() (it returned
4372 : // -1), but Open() managed to open the file, post validate options.
4373 497206 : if (poDS != nullptr &&
4374 61894 : (poDriver->pfnIdentify || poDriver->pfnIdentifyEx) &&
4375 61328 : !bIdentifyRes)
4376 : {
4377 824 : GDALValidateOpenOptions(poDriver, papszOptionsToValidate);
4378 : }
4379 : }
4380 3 : else if (poDriver->pfnOpenWithDriverArg != nullptr)
4381 : {
4382 : // do nothing
4383 : }
4384 0 : else if (bIdentifyRes &&
4385 0 : poDriver->GetMetadataItem("MISSING_PLUGIN_FILENAME"))
4386 : {
4387 0 : if (!poMissingPluginDriver)
4388 : {
4389 0 : poMissingPluginDriver = poDriver;
4390 : }
4391 : }
4392 : else
4393 : {
4394 : // should not happen given the GDAL_DCAP_OPEN check
4395 0 : CSLDestroy(papszTmpOpenOptions);
4396 0 : CSLDestroy(papszTmpOpenOptionsToValidate);
4397 0 : oOpenInfo.papszOpenOptions = papszOpenOptionsCleaned;
4398 0 : continue;
4399 : }
4400 :
4401 497209 : CSLDestroy(papszTmpOpenOptions);
4402 497209 : CSLDestroy(papszTmpOpenOptionsToValidate);
4403 497209 : oOpenInfo.papszOpenOptions = papszOpenOptionsCleaned;
4404 :
4405 497209 : if (poDS != nullptr)
4406 : {
4407 61897 : if (poDS->papszOpenOptions == nullptr)
4408 : {
4409 61627 : poDS->papszOpenOptions = papszOpenOptionsCleaned;
4410 61627 : papszOpenOptionsCleaned = nullptr;
4411 : }
4412 :
4413 : // Deal with generic OVERVIEW_LEVEL open option, unless it is
4414 : // driver specific.
4415 61897 : if (CSLFetchNameValue(papszOpenOptions, "OVERVIEW_LEVEL") !=
4416 61936 : nullptr &&
4417 39 : !poDriver->HasOpenOption("OVERVIEW_LEVEL"))
4418 : {
4419 : CPLString osVal(
4420 78 : CSLFetchNameValue(papszOpenOptions, "OVERVIEW_LEVEL"));
4421 39 : const int nOvrLevel = EQUAL(osVal, "NONE") ? -1 : atoi(osVal);
4422 : const bool bThisLevelOnly =
4423 39 : nOvrLevel == -1 || osVal.ifind("only") != std::string::npos;
4424 : GDALDataset *poOvrDS =
4425 39 : GDALCreateOverviewDataset(poDS, nOvrLevel, bThisLevelOnly);
4426 39 : if (poOvrDS && (nOpenFlags & GDAL_OF_SHARED) != 0)
4427 : {
4428 4 : if (strcmp(pszFilename, poDS->GetDescription()) != 0)
4429 : {
4430 0 : CPLError(
4431 : CE_Warning, CPLE_NotSupported,
4432 : "A dataset opened by GDALOpenShared should have "
4433 : "the same filename (%s) "
4434 : "and description (%s)",
4435 0 : pszFilename, poDS->GetDescription());
4436 : }
4437 : else
4438 : {
4439 4 : CSLDestroy(poDS->papszOpenOptions);
4440 4 : poDS->papszOpenOptions = CSLDuplicate(papszOpenOptions);
4441 4 : poDS->papszOpenOptions = CSLSetNameValue(
4442 : poDS->papszOpenOptions, "OVERVIEW_LEVEL", nullptr);
4443 : }
4444 : }
4445 39 : poDS->ReleaseRef();
4446 39 : poDS = poOvrDS;
4447 39 : if (poDS == nullptr)
4448 : {
4449 1 : if (nOpenFlags & GDAL_OF_VERBOSE_ERROR)
4450 : {
4451 1 : CPLError(CE_Failure, CPLE_OpenFailed,
4452 : "Cannot open overview level %d of %s",
4453 : nOvrLevel, pszFilename);
4454 : }
4455 : }
4456 : else
4457 : {
4458 : // For thread-safe opening, currently poDS is what will be
4459 : // the "master" dataset owned by the thread-safe dataset
4460 : // returned to the user, hence we do not register it as a
4461 : // visible one in the open dataset list, or mark it as shared.
4462 38 : if (!(nOpenFlags & GDAL_OF_INTERNAL) &&
4463 36 : !(nOpenFlags & GDAL_OF_THREAD_SAFE))
4464 : {
4465 35 : poDS->AddToDatasetOpenList();
4466 : }
4467 38 : if (nOpenFlags & GDAL_OF_SHARED)
4468 : {
4469 4 : CSLDestroy(poDS->papszOpenOptions);
4470 4 : poDS->papszOpenOptions = CSLDuplicate(papszOpenOptions);
4471 4 : poDS->nOpenFlags = nOpenFlags;
4472 4 : if (!(nOpenFlags & GDAL_OF_THREAD_SAFE))
4473 4 : poDS->MarkAsShared();
4474 : }
4475 : }
4476 : }
4477 61858 : else if (nOpenFlags & GDAL_OF_SHARED)
4478 : {
4479 371 : if (strcmp(pszFilename, poDS->GetDescription()) != 0)
4480 : {
4481 2 : CPLError(CE_Warning, CPLE_NotSupported,
4482 : "A dataset opened by GDALOpenShared should have "
4483 : "the same filename (%s) "
4484 : "and description (%s)",
4485 2 : pszFilename, poDS->GetDescription());
4486 : }
4487 369 : else if (!(nOpenFlags & GDAL_OF_THREAD_SAFE))
4488 : {
4489 : // For thread-safe opening, currently poDS is what will be
4490 : // the "master" dataset owned by the thread-safe dataset
4491 : // returned to the user, hence we do not or mark it as shared.
4492 369 : poDS->MarkAsShared();
4493 : }
4494 : }
4495 :
4496 61897 : VSIErrorReset();
4497 :
4498 61897 : CSLDestroy(papszOpenOptionsCleaned);
4499 :
4500 : #ifdef OGRAPISPY_ENABLED
4501 61897 : if (iSnapshot != INT_MIN)
4502 : {
4503 11654 : GDALDatasetH hDS = GDALDataset::ToHandle(poDS);
4504 11654 : OGRAPISpyOpen(pszFilename, bUpdate, iSnapshot, &hDS);
4505 11654 : poDS = GDALDataset::FromHandle(hDS);
4506 : }
4507 : #endif
4508 :
4509 61897 : if (poDS)
4510 : {
4511 61896 : poDS->m_bCanBeReopened = true;
4512 :
4513 61896 : if ((nOpenFlags & GDAL_OF_THREAD_SAFE) != 0)
4514 : {
4515 : poDS =
4516 248 : GDALGetThreadSafeDataset(
4517 248 : std::unique_ptr<GDALDataset>(poDS), GDAL_OF_RASTER)
4518 124 : .release();
4519 124 : if (poDS)
4520 : {
4521 124 : poDS->m_bCanBeReopened = true;
4522 124 : poDS->poDriver = poDriver;
4523 124 : poDS->nOpenFlags = nOpenFlags;
4524 124 : if (!(nOpenFlags & GDAL_OF_INTERNAL))
4525 124 : poDS->AddToDatasetOpenList();
4526 124 : if (nOpenFlags & GDAL_OF_SHARED)
4527 0 : poDS->MarkAsShared();
4528 : }
4529 : }
4530 : }
4531 :
4532 63003 : return std::unique_ptr<GDALDataset>(poDS);
4533 : }
4534 :
4535 : #ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION
4536 : if (bFpAvailableBefore && oOpenInfo.fpL == nullptr)
4537 : {
4538 : // In case the file descriptor was "consumed" by a driver
4539 : // that ultimately failed, re-open it for next drivers.
4540 : oOpenInfo.fpL = VSIFOpenL(
4541 : pszFilename, (oOpenInfo.eAccess == GA_Update) ? "r+b" : "rb");
4542 : }
4543 : #else
4544 435312 : if (CPLGetLastErrorNo() != 0 && CPLGetLastErrorType() > CE_Warning)
4545 : {
4546 1106 : CSLDestroy(papszOpenOptionsCleaned);
4547 :
4548 : #ifdef OGRAPISPY_ENABLED
4549 1106 : if (iSnapshot != INT_MIN)
4550 : {
4551 193 : GDALDatasetH hDS = nullptr;
4552 193 : OGRAPISpyOpen(pszFilename, bUpdate, iSnapshot, &hDS);
4553 : }
4554 : #endif
4555 1106 : return nullptr;
4556 : }
4557 : #endif
4558 : }
4559 :
4560 : // cppcheck-suppress knownConditionTrueFalse
4561 19462 : if (iPass == 1 && !apoSecondPassDrivers.empty())
4562 : {
4563 14 : CPLDebugOnly("GDAL", "GDALOpen(): Second pass");
4564 14 : iPass = 2;
4565 14 : goto retry;
4566 : }
4567 :
4568 19448 : CSLDestroy(papszOpenOptionsCleaned);
4569 :
4570 : #ifdef OGRAPISPY_ENABLED
4571 19448 : if (iSnapshot != INT_MIN)
4572 : {
4573 655 : GDALDatasetH hDS = nullptr;
4574 655 : OGRAPISpyOpen(pszFilename, bUpdate, iSnapshot, &hDS);
4575 : }
4576 : #endif
4577 :
4578 19448 : if (nOpenFlags & GDAL_OF_VERBOSE_ERROR)
4579 : {
4580 5964 : if (nDriverCount == 0)
4581 : {
4582 0 : CPLError(CE_Failure, CPLE_OpenFailed, "No driver registered.");
4583 : }
4584 5964 : else if (poMissingPluginDriver)
4585 : {
4586 0 : std::string osMsg("`");
4587 0 : osMsg += pszFilename;
4588 : osMsg += "' not recognized as being in a supported file format. "
4589 0 : "It could have been recognized by driver ";
4590 0 : osMsg += poMissingPluginDriver->GetDescription();
4591 0 : osMsg += ", but plugin ";
4592 : osMsg +=
4593 0 : GDALGetMessageAboutMissingPluginDriver(poMissingPluginDriver);
4594 :
4595 0 : CPLError(CE_Failure, CPLE_OpenFailed, "%s", osMsg.c_str());
4596 : }
4597 : // Check to see if there was a filesystem error, and report it if so.
4598 : // If not, return a more generic error.
4599 5964 : else if (!VSIToCPLError(CE_Failure, CPLE_OpenFailed))
4600 : {
4601 512 : if (oOpenInfo.bStatOK)
4602 : {
4603 509 : CPLError(CE_Failure, CPLE_OpenFailed,
4604 : "`%s' not recognized as being in a supported file "
4605 : "format.",
4606 : pszFilename);
4607 : }
4608 : else
4609 : {
4610 : // If Stat failed and no VSI error was set, assume it is because
4611 : // the file did not exist on the filesystem.
4612 3 : CPLError(CE_Failure, CPLE_OpenFailed,
4613 : "`%s' does not exist in the file system, "
4614 : "and is not recognized as a supported dataset name.",
4615 : pszFilename);
4616 : }
4617 : }
4618 : }
4619 :
4620 19448 : return nullptr;
4621 : }
4622 :
4623 : /************************************************************************/
4624 : /* GDALOpenShared() */
4625 : /************************************************************************/
4626 :
4627 : /**
4628 : * \brief Open a raster file as a GDALDataset.
4629 : *
4630 : * This function works the same as GDALOpen(), but allows the sharing of
4631 : * GDALDataset handles for a dataset with other callers to GDALOpenShared().
4632 : *
4633 : * In particular, GDALOpenShared() will first consult its list of currently
4634 : * open and shared GDALDataset's, and if the GetDescription() name for one
4635 : * exactly matches the pszFilename passed to GDALOpenShared() it will be
4636 : * referenced and returned.
4637 : *
4638 : * If GDALOpenShared() is called on the same
4639 : * pszFilename from two different threads, a different GDALDataset object will
4640 : * be returned as it is not safe to use the same dataset from different threads,
4641 : * unless the user does explicitly use mutexes in its code.
4642 : *
4643 : * For drivers supporting the VSI virtual file API, it is possible to open a
4644 : * file in a .zip archive (see VSIInstallZipFileHandler()), in a
4645 : * .tar/.tar.gz/.tgz archive (see VSIInstallTarFileHandler()) or on a HTTP / FTP
4646 : * server (see VSIInstallCurlFileHandler())
4647 : *
4648 : * \sa GDALOpen()
4649 : * \sa GDALOpenEx()
4650 : *
4651 : * @param pszFilename the name of the file to access. In the case of
4652 : * exotic drivers this may not refer to a physical file, but instead contain
4653 : * information for the driver on how to access a dataset. It should be in
4654 : * UTF-8 encoding.
4655 : *
4656 : * @param eAccess the desired access, either GA_Update or GA_ReadOnly. Many
4657 : * drivers support only read only access.
4658 : *
4659 : * @return A GDALDatasetH handle or NULL on failure. For C++ applications
4660 : * this handle can be cast to a GDALDataset *.
4661 : */
4662 :
4663 5207 : GDALDatasetH CPL_STDCALL GDALOpenShared(const char *pszFilename,
4664 : GDALAccess eAccess)
4665 : {
4666 5207 : VALIDATE_POINTER1(pszFilename, "GDALOpenShared", nullptr);
4667 5207 : return GDALOpenEx(pszFilename,
4668 : GDAL_OF_RASTER |
4669 : (eAccess == GA_Update ? GDAL_OF_UPDATE : 0) |
4670 : GDAL_OF_SHARED | GDAL_OF_VERBOSE_ERROR,
4671 5207 : nullptr, nullptr, nullptr);
4672 : }
4673 :
4674 : /************************************************************************/
4675 : /* GDALClose() */
4676 : /************************************************************************/
4677 :
4678 : /**
4679 : * \brief Close GDAL dataset.
4680 : *
4681 : * For non-shared datasets (opened with GDALOpen()) the dataset is closed
4682 : * using the C++ "delete" operator, recovering all dataset related resources.
4683 : * For shared datasets (opened with GDALOpenShared()) the dataset is
4684 : * dereferenced, and closed only if the referenced count has dropped below 1.
4685 : *
4686 : * @param hDS The dataset to close, or nullptr.
4687 : * @return CE_None in case of success (return value since GDAL 3.7). On a
4688 : * shared dataset whose reference count is not dropped below 1, CE_None will
4689 : * be returned.
4690 : *
4691 : * @see GDALCloseEx()
4692 : */
4693 :
4694 76046 : CPLErr CPL_STDCALL GDALClose(GDALDatasetH hDS)
4695 :
4696 : {
4697 76046 : return GDALCloseEx(hDS, nullptr, nullptr);
4698 : }
4699 :
4700 : /************************************************************************/
4701 : /* GDALCloseEx() */
4702 : /************************************************************************/
4703 :
4704 : /**
4705 : * \brief Close GDAL dataset.
4706 : *
4707 : * For non-shared datasets (opened with GDALOpen()) the dataset is closed
4708 : * using the C++ "delete" operator, recovering all dataset related resources.
4709 : * For shared datasets (opened with GDALOpenShared()) the dataset is
4710 : * dereferenced, and closed only if the referenced count has dropped below 1.
4711 : *
4712 : * This function may report progress if a progress
4713 : * callback if provided in the pfnProgress argument and if the dataset returns
4714 : * true for GDALDataset::GetCloseReportsProgress()
4715 :
4716 : * @param hDS The dataset to close, or nullptr
4717 : * @param pfnProgress Progress callback, or nullptr
4718 : * @param pProgressData User data of progress callback, or nullptr
4719 : *
4720 : * @return CE_None in case of success. On a
4721 : * shared dataset whose reference count is not dropped below 1, CE_None will
4722 : * be returned.
4723 : *
4724 : * @since GDAL 3.13
4725 : * @see GDALClose()
4726 : */
4727 :
4728 80352 : CPLErr GDALCloseEx(GDALDatasetH hDS, GDALProgressFunc pfnProgress,
4729 : void *pProgressData)
4730 : {
4731 80352 : if (!hDS)
4732 404 : return CE_None;
4733 :
4734 : #ifdef OGRAPISPY_ENABLED
4735 79948 : if (bOGRAPISpyEnabled)
4736 11 : OGRAPISpyPreClose(hDS);
4737 : #endif
4738 :
4739 79948 : GDALDataset *poDS = GDALDataset::FromHandle(hDS);
4740 :
4741 79948 : if (poDS->GetShared())
4742 : {
4743 : /* --------------------------------------------------------------------
4744 : */
4745 : /* If this file is in the shared dataset list then dereference */
4746 : /* it, and only delete/remote it if the reference count has */
4747 : /* dropped to zero. */
4748 : /* --------------------------------------------------------------------
4749 : */
4750 238 : if (poDS->Dereference() > 0)
4751 15 : return CE_None;
4752 : }
4753 :
4754 79933 : CPLErr eErr = poDS->Close(pfnProgress, pProgressData);
4755 79933 : delete poDS;
4756 :
4757 : #ifdef OGRAPISPY_ENABLED
4758 79933 : if (bOGRAPISpyEnabled)
4759 11 : OGRAPISpyPostClose();
4760 : #endif
4761 79933 : return eErr;
4762 : }
4763 :
4764 : /************************************************************************/
4765 : /* GDALDumpOpenDataset() */
4766 : /************************************************************************/
4767 :
4768 0 : static int GDALDumpOpenSharedDatasetsForeach(void *elt, void *user_data)
4769 : {
4770 0 : SharedDatasetCtxt *psStruct = static_cast<SharedDatasetCtxt *>(elt);
4771 0 : FILE *fp = static_cast<FILE *>(user_data);
4772 0 : GDALDataset *poDS = psStruct->poDS;
4773 :
4774 0 : const char *pszDriverName = poDS->GetDriver() == nullptr
4775 0 : ? "DriverIsNULL"
4776 0 : : poDS->GetDriver()->GetDescription();
4777 :
4778 0 : poDS->Reference();
4779 0 : CPL_IGNORE_RET_VAL(
4780 0 : VSIFPrintf(fp, " %d %c %-6s %7d %dx%dx%d %s\n", poDS->Dereference(),
4781 0 : poDS->GetShared() ? 'S' : 'N', pszDriverName,
4782 0 : static_cast<int>(psStruct->nPID), poDS->GetRasterXSize(),
4783 : poDS->GetRasterYSize(), poDS->GetRasterCount(),
4784 0 : poDS->GetDescription()));
4785 :
4786 0 : return TRUE;
4787 : }
4788 :
4789 0 : static int GDALDumpOpenDatasetsForeach(GDALDataset *poDS, FILE *fp)
4790 : {
4791 :
4792 : // Don't list shared datasets. They have already been listed by
4793 : // GDALDumpOpenSharedDatasetsForeach.
4794 0 : if (poDS->GetShared())
4795 0 : return TRUE;
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, -1,
4805 : poDS->GetRasterXSize(), poDS->GetRasterYSize(),
4806 0 : poDS->GetRasterCount(), poDS->GetDescription()));
4807 :
4808 0 : return TRUE;
4809 : }
4810 :
4811 : /**
4812 : * \brief List open datasets.
4813 : *
4814 : * Dumps a list of all open datasets (shared or not) to the indicated
4815 : * text file (may be stdout or stderr). This function is primarily intended
4816 : * to assist in debugging "dataset leaks" and reference counting issues.
4817 : * The information reported includes the dataset name, referenced count,
4818 : * shared status, driver name, size, and band count.
4819 : */
4820 :
4821 272 : int CPL_STDCALL GDALDumpOpenDatasets(FILE *fp)
4822 :
4823 : {
4824 272 : VALIDATE_POINTER1(fp, "GDALDumpOpenDatasets", 0);
4825 :
4826 544 : CPLMutexHolderD(&hDLMutex);
4827 :
4828 272 : if (poAllDatasetMap == nullptr)
4829 272 : return 0;
4830 :
4831 0 : CPL_IGNORE_RET_VAL(VSIFPrintf(fp, "Open GDAL Datasets:\n"));
4832 :
4833 0 : for (const auto &oIter : *poAllDatasetMap)
4834 : {
4835 0 : GDALDumpOpenDatasetsForeach(oIter.first, fp);
4836 : }
4837 :
4838 0 : if (phSharedDatasetSet != nullptr)
4839 : {
4840 0 : CPLHashSetForeach(phSharedDatasetSet, GDALDumpOpenSharedDatasetsForeach,
4841 : fp);
4842 : }
4843 0 : return static_cast<int>(poAllDatasetMap->size());
4844 : }
4845 :
4846 : /************************************************************************/
4847 : /* BeginAsyncReader() */
4848 : /************************************************************************/
4849 :
4850 : /**
4851 : * \brief Sets up an asynchronous data request
4852 : *
4853 : * This method establish an asynchronous raster read request for the
4854 : * indicated window on the dataset into the indicated buffer. The parameters
4855 : * for windowing, buffer size, buffer type and buffer organization are similar
4856 : * to those for GDALDataset::RasterIO(); however, this call only launches
4857 : * the request and filling the buffer is accomplished via calls to
4858 : * GetNextUpdatedRegion() on the return GDALAsyncReader session object.
4859 : *
4860 : * Once all processing for the created session is complete, or if no further
4861 : * refinement of the request is required, the GDALAsyncReader object should
4862 : * be destroyed with the GDALDataset::EndAsyncReader() method.
4863 : *
4864 : * Note that the data buffer (pData) will potentially continue to be
4865 : * updated as long as the session lives, but it is not deallocated when
4866 : * the session (GDALAsyncReader) is destroyed with EndAsyncReader(). It
4867 : * should be deallocated by the application at that point.
4868 : *
4869 : * Additional information on asynchronous IO in GDAL may be found at:
4870 : * https://gdal.org/development/rfc/rfc24_progressive_data_support.html
4871 : *
4872 : * This method is the same as the C GDALBeginAsyncReader() function.
4873 : *
4874 : * @param nXOff The pixel offset to the top left corner of the region
4875 : * of the band to be accessed. This would be zero to start from the left side.
4876 : *
4877 : * @param nYOff The line offset to the top left corner of the region
4878 : * of the band to be accessed. This would be zero to start from the top.
4879 : *
4880 : * @param nXSize The width of the region of the band to be accessed in pixels.
4881 : *
4882 : * @param nYSize The height of the region of the band to be accessed in lines.
4883 : *
4884 : * @param pBuf The buffer into which the data should be read. This buffer must
4885 : * contain at least nBufXSize * nBufYSize * nBandCount words of type eBufType.
4886 : * It is organized in left to right,top to bottom pixel order. Spacing is
4887 : * controlled by the nPixelSpace, and nLineSpace parameters.
4888 : *
4889 : * @param nBufXSize the width of the buffer image into which the desired region
4890 : * is to be read, or from which it is to be written.
4891 : *
4892 : * @param nBufYSize the height of the buffer image into which the desired
4893 : * region is to be read, or from which it is to be written.
4894 : *
4895 : * @param eBufType the type of the pixel values in the pData data buffer. The
4896 : * pixel values will automatically be translated to/from the GDALRasterBand
4897 : * data type as needed.
4898 : *
4899 : * @param nBandCount the number of bands being read or written.
4900 : *
4901 : * @param panBandMap the list of nBandCount band numbers being read/written.
4902 : * Note band numbers are 1 based. This may be NULL to select the first
4903 : * nBandCount bands.
4904 : *
4905 : * @param nPixelSpace The byte offset from the start of one pixel value in
4906 : * pData to the start of the next pixel value within a scanline. If defaulted
4907 : * (0) the size of the datatype eBufType is used.
4908 : *
4909 : * @param nLineSpace The byte offset from the start of one scanline in
4910 : * pData to the start of the next. If defaulted the size of the datatype
4911 : * eBufType * nBufXSize is used.
4912 : *
4913 : * @param nBandSpace the byte offset from the start of one bands data to the
4914 : * start of the next. If defaulted (zero) the value will be
4915 : * nLineSpace * nBufYSize implying band sequential organization
4916 : * of the data buffer.
4917 : *
4918 : * @param papszOptions Driver specific control options in a string list or NULL.
4919 : * Consult driver documentation for options supported.
4920 : *
4921 : * @return The GDALAsyncReader object representing the request.
4922 : */
4923 :
4924 1 : GDALAsyncReader *GDALDataset::BeginAsyncReader(
4925 : int nXOff, int nYOff, int nXSize, int nYSize, void *pBuf, int nBufXSize,
4926 : int nBufYSize, GDALDataType eBufType, int nBandCount, int *panBandMap,
4927 : int nPixelSpace, int nLineSpace, int nBandSpace, CSLConstList papszOptions)
4928 : {
4929 : // See gdaldefaultasync.cpp
4930 :
4931 1 : return GDALGetDefaultAsyncReader(this, nXOff, nYOff, nXSize, nYSize, pBuf,
4932 : nBufXSize, nBufYSize, eBufType, nBandCount,
4933 : panBandMap, nPixelSpace, nLineSpace,
4934 1 : nBandSpace, papszOptions);
4935 : }
4936 :
4937 : /************************************************************************/
4938 : /* GDALBeginAsyncReader() */
4939 : /************************************************************************/
4940 :
4941 : /**
4942 : * \brief Sets up an asynchronous data request
4943 : *
4944 : * This method establish an asynchronous raster read request for the
4945 : * indicated window on the dataset into the indicated buffer. The parameters
4946 : * for windowing, buffer size, buffer type and buffer organization are similar
4947 : * to those for GDALDataset::RasterIO(); however, this call only launches
4948 : * the request and filling the buffer is accomplished via calls to
4949 : * GetNextUpdatedRegion() on the return GDALAsyncReader session object.
4950 : *
4951 : * Once all processing for the created session is complete, or if no further
4952 : * refinement of the request is required, the GDALAsyncReader object should
4953 : * be destroyed with the GDALDataset::EndAsyncReader() method.
4954 : *
4955 : * Note that the data buffer (pData) will potentially continue to be
4956 : * updated as long as the session lives, but it is not deallocated when
4957 : * the session (GDALAsyncReader) is destroyed with EndAsyncReader(). It
4958 : * should be deallocated by the application at that point.
4959 : *
4960 : * Additional information on asynchronous IO in GDAL may be found at:
4961 : * https://gdal.org/development/rfc/rfc24_progressive_data_support.html
4962 : *
4963 : * This method is the same as the C++ GDALDataset::BeginAsyncReader() method.
4964 : *
4965 : * @param hDS handle to the dataset object.
4966 : *
4967 : * @param nXOff The pixel offset to the top left corner of the region
4968 : * of the band to be accessed. This would be zero to start from the left side.
4969 : *
4970 : * @param nYOff The line offset to the top left corner of the region
4971 : * of the band to be accessed. This would be zero to start from the top.
4972 : *
4973 : * @param nXSize The width of the region of the band to be accessed in pixels.
4974 : *
4975 : * @param nYSize The height of the region of the band to be accessed in lines.
4976 : *
4977 : * @param pBuf The buffer into which the data should be read. This buffer must
4978 : * contain at least nBufXSize * nBufYSize * nBandCount words of type eBufType.
4979 : * It is organized in left to right,top to bottom pixel order. Spacing is
4980 : * controlled by the nPixelSpace, and nLineSpace parameters.
4981 : *
4982 : * @param nBufXSize the width of the buffer image into which the desired region
4983 : * is to be read, or from which it is to be written.
4984 : *
4985 : * @param nBufYSize the height of the buffer image into which the desired
4986 : * region is to be read, or from which it is to be written.
4987 : *
4988 : * @param eBufType the type of the pixel values in the pData data buffer. The
4989 : * pixel values will automatically be translated to/from the GDALRasterBand
4990 : * data type as needed.
4991 : *
4992 : * @param nBandCount the number of bands being read or written.
4993 : *
4994 : * @param panBandMap the list of nBandCount band numbers being read/written.
4995 : * Note band numbers are 1 based. This may be NULL to select the first
4996 : * nBandCount bands.
4997 : *
4998 : * @param nPixelSpace The byte offset from the start of one pixel value in
4999 : * pData to the start of the next pixel value within a scanline. If defaulted
5000 : * (0) the size of the datatype eBufType is used.
5001 : *
5002 : * @param nLineSpace The byte offset from the start of one scanline in
5003 : * pData to the start of the next. If defaulted the size of the datatype
5004 : * eBufType * nBufXSize is used.
5005 : *
5006 : * @param nBandSpace the byte offset from the start of one bands data to the
5007 : * start of the next. If defaulted (zero) the value will be
5008 : * nLineSpace * nBufYSize implying band sequential organization
5009 : * of the data buffer.
5010 : *
5011 : * @param papszOptions Driver specific control options in a string list or NULL.
5012 : * Consult driver documentation for options supported.
5013 : *
5014 : * @return handle representing the request.
5015 : */
5016 :
5017 2 : GDALAsyncReaderH CPL_STDCALL GDALBeginAsyncReader(
5018 : GDALDatasetH hDS, int nXOff, int nYOff, int nXSize, int nYSize, void *pBuf,
5019 : int nBufXSize, int nBufYSize, GDALDataType eBufType, int nBandCount,
5020 : int *panBandMap, int nPixelSpace, int nLineSpace, int nBandSpace,
5021 : CSLConstList papszOptions)
5022 :
5023 : {
5024 2 : VALIDATE_POINTER1(hDS, "GDALDataset", nullptr);
5025 : return static_cast<GDALAsyncReaderH>(
5026 2 : GDALDataset::FromHandle(hDS)->BeginAsyncReader(
5027 : nXOff, nYOff, nXSize, nYSize, pBuf, nBufXSize, nBufYSize, eBufType,
5028 : nBandCount, panBandMap, nPixelSpace, nLineSpace, nBandSpace,
5029 2 : const_cast<char **>(papszOptions)));
5030 : }
5031 :
5032 : /************************************************************************/
5033 : /* EndAsyncReader() */
5034 : /************************************************************************/
5035 :
5036 : /**
5037 : * End asynchronous request.
5038 : *
5039 : * This method destroys an asynchronous io request and recovers all
5040 : * resources associated with it.
5041 : *
5042 : * This method is the same as the C function GDALEndAsyncReader().
5043 : *
5044 : * @param poARIO pointer to a GDALAsyncReader
5045 : */
5046 :
5047 1 : void GDALDataset::EndAsyncReader(GDALAsyncReader *poARIO)
5048 : {
5049 1 : delete poARIO;
5050 1 : }
5051 :
5052 : /************************************************************************/
5053 : /* GDALEndAsyncReader() */
5054 : /************************************************************************/
5055 :
5056 : /**
5057 : * End asynchronous request.
5058 : *
5059 : * This method destroys an asynchronous io request and recovers all
5060 : * resources associated with it.
5061 : *
5062 : * This method is the same as the C++ method GDALDataset::EndAsyncReader().
5063 : *
5064 : * @param hDS handle to the dataset object.
5065 : * @param hAsyncReaderH handle returned by GDALBeginAsyncReader()
5066 : */
5067 :
5068 1 : void CPL_STDCALL GDALEndAsyncReader(GDALDatasetH hDS,
5069 : GDALAsyncReaderH hAsyncReaderH)
5070 : {
5071 1 : VALIDATE_POINTER0(hDS, "GDALDataset");
5072 1 : VALIDATE_POINTER0(hAsyncReaderH, "GDALAsyncReader");
5073 1 : GDALDataset::FromHandle(hDS)->EndAsyncReader(
5074 1 : static_cast<GDALAsyncReader *>(hAsyncReaderH));
5075 : }
5076 :
5077 : /************************************************************************/
5078 : /* CloseDependentDatasets() */
5079 : /************************************************************************/
5080 :
5081 : /**
5082 : * Drop references to any other datasets referenced by this dataset.
5083 : *
5084 : * This method should release any reference to other datasets (e.g. a VRT
5085 : * dataset to its sources), but not close the current dataset itself.
5086 : *
5087 : * If at least, one reference to a dependent dataset has been dropped,
5088 : * this method should return TRUE. Otherwise it *should* return FALSE.
5089 : * (Failure to return the proper value might result in infinite loop)
5090 : *
5091 : * This method can be called several times on a given dataset. After
5092 : * the first time, it should not do anything and return FALSE.
5093 : *
5094 : * The driver implementation may choose to destroy its raster bands,
5095 : * so be careful not to call any method on the raster bands afterwards.
5096 : *
5097 : * Basically the only safe action you can do after calling
5098 : * CloseDependentDatasets() is to call the destructor.
5099 : *
5100 : * Note: the only legitimate caller of CloseDependentDatasets() is
5101 : * GDALDriverManager::~GDALDriverManager()
5102 : *
5103 : * @return TRUE if at least one reference to another dataset has been dropped.
5104 : */
5105 19946 : int GDALDataset::CloseDependentDatasets()
5106 : {
5107 19946 : return oOvManager.CloseDependentDatasets();
5108 : }
5109 :
5110 : /************************************************************************/
5111 : /* ReportError() */
5112 : /************************************************************************/
5113 :
5114 : #ifndef DOXYGEN_XML
5115 : /**
5116 : * \brief Emits an error related to a dataset.
5117 : *
5118 : * This function is a wrapper for regular CPLError(). The only difference
5119 : * with CPLError() is that it prepends the error message with the dataset
5120 : * name.
5121 : *
5122 : * @param eErrClass one of CE_Warning, CE_Failure or CE_Fatal.
5123 : * @param err_no the error number (CPLE_*) from cpl_error.h.
5124 : * @param fmt a printf() style format string. Any additional arguments
5125 : * will be treated as arguments to fill in this format in a manner
5126 : * similar to printf().
5127 : *
5128 : */
5129 :
5130 104 : void GDALDataset::ReportError(CPLErr eErrClass, CPLErrorNum err_no,
5131 : const char *fmt, ...) const
5132 : {
5133 : va_list args;
5134 104 : va_start(args, fmt);
5135 104 : ReportErrorV(GetDescription(), eErrClass, err_no, fmt, args);
5136 104 : va_end(args);
5137 104 : }
5138 :
5139 : /**
5140 : * \brief Emits an error related to a dataset (static method)
5141 : *
5142 : * This function is a wrapper for regular CPLError(). The only difference
5143 : * with CPLError() is that it prepends the error message with the dataset
5144 : * name.
5145 : *
5146 : * @param pszDSName dataset name.
5147 : * @param eErrClass one of CE_Warning, CE_Failure or CE_Fatal.
5148 : * @param err_no the error number (CPLE_*) from cpl_error.h.
5149 : * @param fmt a printf() style format string. Any additional arguments
5150 : * will be treated as arguments to fill in this format in a manner
5151 : * similar to printf().
5152 : *
5153 : * @since GDAL 3.2.0
5154 : */
5155 :
5156 187 : void GDALDataset::ReportError(const char *pszDSName, CPLErr eErrClass,
5157 : CPLErrorNum err_no, const char *fmt, ...)
5158 : {
5159 : va_list args;
5160 187 : va_start(args, fmt);
5161 187 : ReportErrorV(pszDSName, eErrClass, err_no, fmt, args);
5162 187 : va_end(args);
5163 187 : }
5164 :
5165 291 : void GDALDataset::ReportErrorV(const char *pszDSName, CPLErr eErrClass,
5166 : CPLErrorNum err_no, const char *fmt,
5167 : va_list args)
5168 : {
5169 291 : pszDSName = CPLGetFilename(pszDSName);
5170 291 : if (pszDSName[0] != '\0')
5171 : {
5172 274 : CPLError(eErrClass, err_no, "%s",
5173 548 : std::string(pszDSName)
5174 274 : .append(": ")
5175 548 : .append(CPLString().vPrintf(fmt, args))
5176 : .c_str());
5177 : }
5178 : else
5179 : {
5180 17 : CPLErrorV(eErrClass, err_no, fmt, args);
5181 : }
5182 291 : }
5183 : #endif
5184 :
5185 : /************************************************************************/
5186 : /* GetMetadata() */
5187 : /************************************************************************/
5188 74031 : CSLConstList GDALDataset::GetMetadata(const char *pszDomain)
5189 : {
5190 : #ifndef WITHOUT_DERIVED
5191 74031 : if (pszDomain != nullptr && EQUAL(pszDomain, "DERIVED_SUBDATASETS"))
5192 : {
5193 10 : oDerivedMetadataList.Clear();
5194 :
5195 : // First condition: at least one raster band.
5196 10 : if (GetRasterCount() > 0)
5197 : {
5198 : // Check if there is at least one complex band.
5199 10 : bool hasAComplexBand = false;
5200 :
5201 19 : for (int rasterId = 1; rasterId <= GetRasterCount(); ++rasterId)
5202 : {
5203 11 : if (GDALDataTypeIsComplex(
5204 11 : GetRasterBand(rasterId)->GetRasterDataType()))
5205 : {
5206 2 : hasAComplexBand = true;
5207 2 : break;
5208 : }
5209 : }
5210 :
5211 10 : unsigned int nbSupportedDerivedDS = 0;
5212 : const DerivedDatasetDescription *poDDSDesc =
5213 10 : GDALGetDerivedDatasetDescriptions(&nbSupportedDerivedDS);
5214 :
5215 10 : int nNumDataset = 1;
5216 80 : for (unsigned int derivedId = 0; derivedId < nbSupportedDerivedDS;
5217 : ++derivedId)
5218 : {
5219 126 : if (hasAComplexBand ||
5220 126 : CPLString(poDDSDesc[derivedId].pszInputPixelType) !=
5221 : "complex")
5222 : {
5223 : oDerivedMetadataList.SetNameValue(
5224 : CPLSPrintf("DERIVED_SUBDATASET_%d_NAME", nNumDataset),
5225 : CPLSPrintf("DERIVED_SUBDATASET:%s:%s",
5226 22 : poDDSDesc[derivedId].pszDatasetName,
5227 22 : GetDescription()));
5228 :
5229 : CPLString osDesc(
5230 : CPLSPrintf("%s from %s",
5231 22 : poDDSDesc[derivedId].pszDatasetDescription,
5232 22 : GetDescription()));
5233 : oDerivedMetadataList.SetNameValue(
5234 : CPLSPrintf("DERIVED_SUBDATASET_%d_DESC", nNumDataset),
5235 22 : osDesc.c_str());
5236 :
5237 22 : nNumDataset++;
5238 : }
5239 : }
5240 : }
5241 10 : return oDerivedMetadataList.List();
5242 : }
5243 : #endif
5244 :
5245 74021 : return GDALMajorObject::GetMetadata(pszDomain);
5246 : }
5247 :
5248 : // clang-format off
5249 :
5250 : /**
5251 : * \fn GDALDataset::SetMetadata( char ** papszMetadata, const char * pszDomain)
5252 : * \brief Set metadata.
5253 : *
5254 : * CAUTION: depending on the format, older values of the updated information
5255 : * might still be found in the file in a "ghost" state, even if no longer
5256 : * accessible through the GDAL API. This is for example the case of the GTiff
5257 : * format (this is not a exhaustive list)
5258 : *
5259 : * The C function GDALSetMetadata() does the same thing as this method.
5260 : *
5261 : * @param papszMetadata the metadata in name=value string list format to
5262 : * apply.
5263 : * @param pszDomain the domain of interest. Use "" or NULL for the default
5264 : * domain.
5265 : * @return CE_None on success, CE_Failure on failure and CE_Warning if the
5266 : * metadata has been accepted, but is likely not maintained persistently
5267 : * by the underlying object between sessions.
5268 : */
5269 :
5270 : /**
5271 : * \fn GDALDataset::SetMetadataItem( const char * pszName, const char * pszValue, const char * pszDomain)
5272 : * \brief Set single metadata item.
5273 : *
5274 : * CAUTION: depending on the format, older values of the updated information
5275 : * might still be found in the file in a "ghost" state, even if no longer
5276 : * accessible through the GDAL API. This is for example the case of the GTiff
5277 : * format (this is not a exhaustive list)
5278 : *
5279 : * The C function GDALSetMetadataItem() does the same thing as this method.
5280 : *
5281 : * @param pszName the key for the metadata item to fetch.
5282 : * @param pszValue the value to assign to the key.
5283 : * @param pszDomain the domain to set within, use NULL for the default domain.
5284 : *
5285 : * @return CE_None on success, or an error code on failure.
5286 : */
5287 :
5288 : // clang-format on
5289 :
5290 : /************************************************************************/
5291 : /* GetMetadataDomainList() */
5292 : /************************************************************************/
5293 :
5294 1073 : char **GDALDataset::GetMetadataDomainList()
5295 : {
5296 1073 : char **currentDomainList = CSLDuplicate(oMDMD.GetDomainList());
5297 :
5298 : // Ensure that we do not duplicate DERIVED domain.
5299 1220 : if (GetRasterCount() > 0 &&
5300 147 : CSLFindString(currentDomainList, "DERIVED_SUBDATASETS") == -1)
5301 : {
5302 : currentDomainList =
5303 147 : CSLAddString(currentDomainList, "DERIVED_SUBDATASETS");
5304 : }
5305 1073 : return currentDomainList;
5306 : }
5307 :
5308 : /************************************************************************/
5309 : /* GetDriverName() */
5310 : /************************************************************************/
5311 :
5312 : /** Return driver name.
5313 : * @return driver name.
5314 : */
5315 2348 : const char *GDALDataset::GetDriverName() const
5316 : {
5317 2348 : if (poDriver)
5318 2334 : return poDriver->GetDescription();
5319 14 : return "";
5320 : }
5321 :
5322 : /************************************************************************/
5323 : /* GDALDatasetReleaseResultSet() */
5324 : /************************************************************************/
5325 :
5326 : /**
5327 : \brief Release results of ExecuteSQL().
5328 :
5329 : This function should only be used to deallocate OGRLayers resulting from
5330 : an ExecuteSQL() call on the same GDALDataset. Failure to deallocate a
5331 : results set before destroying the GDALDataset may cause errors.
5332 :
5333 : This function is the same as the C++ method GDALDataset::ReleaseResultSet()
5334 :
5335 :
5336 : @param hDS the dataset handle.
5337 : @param hLayer the result of a previous ExecuteSQL() call.
5338 :
5339 : */
5340 3519 : void GDALDatasetReleaseResultSet(GDALDatasetH hDS, OGRLayerH hLayer)
5341 :
5342 : {
5343 3519 : VALIDATE_POINTER0(hDS, "GDALDatasetReleaseResultSet");
5344 :
5345 : #ifdef OGRAPISPY_ENABLED
5346 3519 : if (bOGRAPISpyEnabled)
5347 6 : OGRAPISpy_DS_ReleaseResultSet(hDS, hLayer);
5348 : #endif
5349 :
5350 7038 : GDALDataset::FromHandle(hDS)->ReleaseResultSet(
5351 3519 : OGRLayer::FromHandle(hLayer));
5352 : }
5353 :
5354 : /************************************************************************/
5355 : /* GDALDatasetGetLayerCount() */
5356 : /************************************************************************/
5357 :
5358 : /**
5359 : \brief Get the number of layers in this dataset.
5360 :
5361 : This function is the same as the C++ method GDALDataset::GetLayerCount()
5362 :
5363 :
5364 : @param hDS the dataset handle.
5365 : @return layer count.
5366 : */
5367 :
5368 1506 : int GDALDatasetGetLayerCount(GDALDatasetH hDS)
5369 :
5370 : {
5371 1506 : VALIDATE_POINTER1(hDS, "GDALDatasetH", 0);
5372 :
5373 : #ifdef OGRAPISPY_ENABLED
5374 1506 : if (bOGRAPISpyEnabled)
5375 2 : OGRAPISpy_DS_GetLayerCount(reinterpret_cast<GDALDatasetH>(hDS));
5376 : #endif
5377 :
5378 1506 : return GDALDataset::FromHandle(hDS)->GetLayerCount();
5379 : }
5380 :
5381 : /************************************************************************/
5382 : /* GDALDatasetGetLayer() */
5383 : /************************************************************************/
5384 :
5385 : /**
5386 : \brief Fetch a layer by index.
5387 :
5388 : The returned layer remains owned by the
5389 : GDALDataset and should not be deleted by the application.
5390 :
5391 : This function is the same as the C++ method GDALDataset::GetLayer()
5392 :
5393 :
5394 : @param hDS the dataset handle.
5395 : @param iLayer a layer number between 0 and GetLayerCount()-1.
5396 :
5397 : @return the layer, or NULL if iLayer is out of range or an error occurs.
5398 : */
5399 :
5400 9995 : OGRLayerH GDALDatasetGetLayer(GDALDatasetH hDS, int iLayer)
5401 :
5402 : {
5403 9995 : VALIDATE_POINTER1(hDS, "GDALDatasetGetLayer", nullptr);
5404 :
5405 : OGRLayerH hLayer =
5406 9995 : OGRLayer::ToHandle(GDALDataset::FromHandle(hDS)->GetLayer(iLayer));
5407 :
5408 : #ifdef OGRAPISPY_ENABLED
5409 9995 : if (bOGRAPISpyEnabled)
5410 3 : OGRAPISpy_DS_GetLayer(hDS, iLayer, hLayer);
5411 : #endif
5412 :
5413 9995 : return hLayer;
5414 : }
5415 :
5416 : /************************************************************************/
5417 : /* GDALDatasetGetLayerByName() */
5418 : /************************************************************************/
5419 :
5420 : /**
5421 : \brief Fetch a layer by name.
5422 :
5423 : The returned layer remains owned by the
5424 : GDALDataset and should not be deleted by the application.
5425 :
5426 : This function is the same as the C++ method GDALDataset::GetLayerByName()
5427 :
5428 :
5429 : @param hDS the dataset handle.
5430 : @param pszName the layer name of the layer to fetch.
5431 :
5432 : @return the layer, or NULL if Layer is not found or an error occurs.
5433 : */
5434 :
5435 3416 : OGRLayerH GDALDatasetGetLayerByName(GDALDatasetH hDS, const char *pszName)
5436 :
5437 : {
5438 3416 : VALIDATE_POINTER1(hDS, "GDALDatasetGetLayerByName", nullptr);
5439 :
5440 3416 : OGRLayerH hLayer = OGRLayer::ToHandle(
5441 3416 : GDALDataset::FromHandle(hDS)->GetLayerByName(pszName));
5442 :
5443 : #ifdef OGRAPISPY_ENABLED
5444 3416 : if (bOGRAPISpyEnabled)
5445 4 : OGRAPISpy_DS_GetLayerByName(hDS, pszName, hLayer);
5446 : #endif
5447 :
5448 3416 : return hLayer;
5449 : }
5450 :
5451 : /************************************************************************/
5452 : /* GDALDatasetIsLayerPrivate() */
5453 : /************************************************************************/
5454 :
5455 : /**
5456 : \brief Returns true if the layer at the specified index is deemed a private or
5457 : system table, or an internal detail only.
5458 :
5459 : This function is the same as the C++ method GDALDataset::IsLayerPrivate()
5460 :
5461 : @since GDAL 3.4
5462 :
5463 : @param hDS the dataset handle.
5464 : @param iLayer a layer number between 0 and GetLayerCount()-1.
5465 :
5466 : @return true if the layer is a private or system table.
5467 : */
5468 :
5469 91 : int GDALDatasetIsLayerPrivate(GDALDatasetH hDS, int iLayer)
5470 :
5471 : {
5472 91 : VALIDATE_POINTER1(hDS, "GDALDatasetIsLayerPrivate", false);
5473 :
5474 91 : const bool res = GDALDataset::FromHandle(hDS)->IsLayerPrivate(iLayer);
5475 :
5476 91 : return res ? 1 : 0;
5477 : }
5478 :
5479 : /************************************************************************/
5480 : /* GetLayerIndex() */
5481 : /************************************************************************/
5482 :
5483 : /**
5484 : \brief Returns the index of the layer specified by name.
5485 :
5486 : @since GDAL 3.12
5487 :
5488 : @param pszName layer name (not NULL)
5489 :
5490 : @return an index >= 0, or -1 if not found.
5491 : */
5492 :
5493 3 : int GDALDataset::GetLayerIndex(const char *pszName) const
5494 : {
5495 3 : const int nLayerCount = GetLayerCount();
5496 3 : int iMatch = -1;
5497 6 : for (int i = 0; i < nLayerCount; ++i)
5498 : {
5499 5 : if (const auto poLayer = GetLayer(i))
5500 : {
5501 5 : const char *pszLayerName = poLayer->GetDescription();
5502 5 : if (strcmp(pszName, pszLayerName) == 0)
5503 : {
5504 2 : iMatch = i;
5505 2 : break;
5506 : }
5507 3 : else if (EQUAL(pszName, pszLayerName))
5508 : {
5509 0 : iMatch = i;
5510 : }
5511 : }
5512 : }
5513 3 : return iMatch;
5514 : }
5515 :
5516 : /************************************************************************/
5517 : /* GDALDatasetDeleteLayer() */
5518 : /************************************************************************/
5519 :
5520 : /**
5521 : \brief Delete the indicated layer from the datasource.
5522 :
5523 : If this function is supported
5524 : the ODsCDeleteLayer capability will test TRUE on the GDALDataset.
5525 :
5526 : This method is the same as the C++ method GDALDataset::DeleteLayer().
5527 :
5528 :
5529 : @param hDS the dataset handle.
5530 : @param iLayer the index of the layer to delete.
5531 :
5532 : @return OGRERR_NONE on success, or OGRERR_UNSUPPORTED_OPERATION if deleting
5533 : layers is not supported for this datasource.
5534 :
5535 : */
5536 41 : OGRErr GDALDatasetDeleteLayer(GDALDatasetH hDS, int iLayer)
5537 :
5538 : {
5539 41 : VALIDATE_POINTER1(hDS, "GDALDatasetH", OGRERR_INVALID_HANDLE);
5540 :
5541 : #ifdef OGRAPISPY_ENABLED
5542 41 : if (bOGRAPISpyEnabled)
5543 2 : OGRAPISpy_DS_DeleteLayer(hDS, iLayer);
5544 : #endif
5545 :
5546 41 : return GDALDataset::FromHandle(hDS)->DeleteLayer(iLayer);
5547 : }
5548 :
5549 : /************************************************************************/
5550 : /* CreateLayer() */
5551 : /************************************************************************/
5552 :
5553 : /**
5554 : \brief This method attempts to create a new layer on the dataset with the
5555 : indicated name, coordinate system, geometry type.
5556 :
5557 : The papszOptions argument
5558 : can be used to control driver specific creation options. These options are
5559 : normally documented in the format specific documentation.
5560 : That function will try to validate the creation option list passed to the
5561 : driver with the GDALValidateCreationOptions() method. This check can be
5562 : disabled by defining the configuration option GDAL_VALIDATE_CREATION_OPTIONS set
5563 : to NO.
5564 :
5565 : Drivers should extend the ICreateLayer() method and not
5566 : CreateLayer(). CreateLayer() adds validation of layer creation options, before
5567 : delegating the actual work to ICreateLayer().
5568 :
5569 : This method is the same as the C function GDALDatasetCreateLayer() and the
5570 : deprecated OGR_DS_CreateLayer().
5571 :
5572 : Example:
5573 :
5574 : \code{.cpp}
5575 : #include "gdal.h"
5576 : #include "cpl_string.h"
5577 :
5578 : ...
5579 :
5580 : OGRLayer *poLayer;
5581 : char **papszOptions;
5582 :
5583 : if( !poDS->TestCapability( ODsCCreateLayer ) )
5584 : {
5585 : ...
5586 : }
5587 :
5588 : papszOptions = CSLSetNameValue( papszOptions, "DIM", "2" );
5589 : poLayer = poDS->CreateLayer( "NewLayer", nullptr, wkbUnknown,
5590 : papszOptions );
5591 : CSLDestroy( papszOptions );
5592 :
5593 : if( poLayer == NULL )
5594 : {
5595 : ...
5596 : }
5597 : \endcode
5598 :
5599 : @param pszName the name for the new layer. This should ideally not
5600 : match any existing layer on the datasource.
5601 : @param poSpatialRef the coordinate system to use for the new layer, or NULL if
5602 : no coordinate system is available.
5603 : @param eGType the geometry type for the layer. Use wkbUnknown if there
5604 : are no constraints on the types geometry to be written.
5605 : @param papszOptions a StringList of name=value options. Options are driver
5606 : specific.
5607 :
5608 : @return NULL is returned on failure, or a new OGRLayer handle on success.
5609 :
5610 : */
5611 :
5612 8325 : OGRLayer *GDALDataset::CreateLayer(const char *pszName,
5613 : const OGRSpatialReference *poSpatialRef,
5614 : OGRwkbGeometryType eGType,
5615 : CSLConstList papszOptions)
5616 :
5617 : {
5618 8325 : if (eGType == wkbNone)
5619 : {
5620 525 : return CreateLayer(pszName, nullptr, papszOptions);
5621 : }
5622 : else
5623 : {
5624 15600 : OGRGeomFieldDefn oGeomFieldDefn("", eGType);
5625 7800 : oGeomFieldDefn.SetSpatialRef(poSpatialRef);
5626 7800 : return CreateLayer(pszName, &oGeomFieldDefn, papszOptions);
5627 : }
5628 : }
5629 :
5630 : /**
5631 : \brief This method attempts to create a new layer on the dataset with the
5632 : indicated name and geometry field definition.
5633 :
5634 : When poGeomFieldDefn is not null, most drivers should honor
5635 : poGeomFieldDefn->GetType() and poGeomFieldDefn->GetSpatialRef().
5636 : Drivers that honor poGeomFieldDefn->GetCoordinatePrecision() will declare the
5637 : GDAL_DCAP_HONOR_GEOM_COORDINATE_PRECISION capability. Drivers may honor
5638 : poGeomFieldDefn->GetNameRef() and poGeomFieldDefn->IsNullable(), but there are
5639 : very few currently.
5640 :
5641 : Note that even if a geometry coordinate precision is set and a driver honors the
5642 : GDAL_DCAP_HONOR_GEOM_COORDINATE_PRECISION capability, geometries passed to
5643 : OGRLayer::CreateFeature() and OGRLayer::SetFeature() are assumed to be compatible
5644 : with the coordinate precision. That is they are assumed to be valid once their
5645 : coordinates are rounded to it. If it might not be the case, the user may set
5646 : the OGR_APPLY_GEOM_SET_PRECISION configuration option before calling CreateFeature()
5647 : or SetFeature() to force the OGRGeometry::SetPrecision() method to be called on
5648 : the passed geometries.
5649 :
5650 : The papszOptions argument
5651 : can be used to control driver specific creation options. These options are
5652 : normally documented in the format specific documentation.
5653 : This function will try to validate the creation option list passed to the
5654 : driver with the GDALValidateCreationOptions() method. This check can be
5655 : disabled by defining the configuration option GDAL_VALIDATE_CREATION_OPTIONS set
5656 : to NO.
5657 :
5658 : Drivers should extend the ICreateLayer() method and not
5659 : CreateLayer(). CreateLayer() adds validation of layer creation options, before
5660 : delegating the actual work to ICreateLayer().
5661 :
5662 : This method is the same as the C function GDALDatasetCreateLayerFromGeomFieldDefn().
5663 :
5664 : @param pszName the name for the new layer. This should ideally not
5665 : match any existing layer on the datasource.
5666 : @param poGeomFieldDefn the geometry field definition to use for the new layer,
5667 : or NULL if there is no geometry field.
5668 : @param papszOptions a StringList of name=value options. Options are driver
5669 : specific.
5670 :
5671 : @return NULL is returned on failure, or a new OGRLayer handle on success.
5672 : @since 3.9
5673 :
5674 : */
5675 :
5676 9733 : OGRLayer *GDALDataset::CreateLayer(const char *pszName,
5677 : const OGRGeomFieldDefn *poGeomFieldDefn,
5678 : CSLConstList papszOptions)
5679 :
5680 : {
5681 9733 : if (CPLTestBool(
5682 : CPLGetConfigOption("GDAL_VALIDATE_CREATION_OPTIONS", "YES")))
5683 : {
5684 9733 : ValidateLayerCreationOptions(papszOptions);
5685 : }
5686 :
5687 : OGRLayer *poLayer;
5688 9733 : if (poGeomFieldDefn)
5689 : {
5690 8795 : OGRGeomFieldDefn oGeomFieldDefn(poGeomFieldDefn);
5691 8889 : if (OGR_GT_IsNonLinear(poGeomFieldDefn->GetType()) &&
5692 94 : !TestCapability(ODsCCurveGeometries))
5693 : {
5694 23 : oGeomFieldDefn.SetType(
5695 : OGR_GT_GetLinear(poGeomFieldDefn->GetType()));
5696 : }
5697 :
5698 8795 : poLayer = ICreateLayer(pszName, &oGeomFieldDefn, papszOptions);
5699 : }
5700 : else
5701 : {
5702 938 : poLayer = ICreateLayer(pszName, nullptr, papszOptions);
5703 : }
5704 : #ifdef DEBUG
5705 9804 : if (poLayer != nullptr && OGR_GT_IsNonLinear(poLayer->GetGeomType()) &&
5706 71 : !poLayer->TestCapability(OLCCurveGeometries))
5707 : {
5708 0 : CPLError(CE_Warning, CPLE_AppDefined,
5709 : "Inconsistent driver: Layer geometry type is non-linear, but "
5710 : "TestCapability(OLCCurveGeometries) returns FALSE.");
5711 : }
5712 : #endif
5713 :
5714 9733 : return poLayer;
5715 : }
5716 :
5717 : //! @cond Doxygen_Suppress
5718 :
5719 : // Technical override to avoid ambiguous choice between the old and new
5720 : // new CreateLayer() signatures.
5721 12 : OGRLayer *GDALDataset::CreateLayer(const char *pszName)
5722 : {
5723 24 : OGRGeomFieldDefn oGeomFieldDefn("", wkbUnknown);
5724 24 : return CreateLayer(pszName, &oGeomFieldDefn, nullptr);
5725 : }
5726 :
5727 : // Technical override to avoid ambiguous choice between the old and new
5728 : // new CreateLayer() signatures.
5729 1 : OGRLayer *GDALDataset::CreateLayer(const char *pszName, std::nullptr_t)
5730 : {
5731 2 : OGRGeomFieldDefn oGeomFieldDefn("", wkbUnknown);
5732 2 : return CreateLayer(pszName, &oGeomFieldDefn, nullptr);
5733 : }
5734 :
5735 : //!@endcond
5736 :
5737 : /************************************************************************/
5738 : /* GDALDatasetCreateLayer() */
5739 : /************************************************************************/
5740 :
5741 : /**
5742 : \brief This function attempts to create a new layer on the dataset with the
5743 : indicated name, coordinate system, geometry type.
5744 :
5745 : The papszOptions argument can be used to control driver specific creation
5746 : options. These options are normally documented in the format specific
5747 : documentation.
5748 :
5749 : This method is the same as the C++ method GDALDataset::CreateLayer().
5750 :
5751 : Example:
5752 :
5753 : \code{.c}
5754 : #include "gdal.h"
5755 : #include "cpl_string.h"
5756 :
5757 : ...
5758 :
5759 : OGRLayerH hLayer;
5760 : char **papszOptions;
5761 :
5762 : if( !GDALDatasetTestCapability( hDS, ODsCCreateLayer ) )
5763 : {
5764 : ...
5765 : }
5766 :
5767 : papszOptions = CSLSetNameValue( papszOptions, "DIM", "2" );
5768 : hLayer = GDALDatasetCreateLayer( hDS, "NewLayer", NULL, wkbUnknown,
5769 : papszOptions );
5770 : CSLDestroy( papszOptions );
5771 :
5772 : if( hLayer == NULL )
5773 : {
5774 : ...
5775 : }
5776 : \endcode
5777 :
5778 :
5779 : @param hDS the dataset handle
5780 : @param pszName the name for the new layer. This should ideally not
5781 : match any existing layer on the datasource.
5782 : @param hSpatialRef the coordinate system to use for the new layer, or NULL if
5783 : no coordinate system is available.
5784 : @param eGType the geometry type for the layer. Use wkbUnknown if there
5785 : are no constraints on the types geometry to be written.
5786 : @param papszOptions a StringList of name=value options. Options are driver
5787 : specific.
5788 :
5789 : @return NULL is returned on failure, or a new OGRLayer handle on success.
5790 :
5791 : */
5792 :
5793 6455 : OGRLayerH GDALDatasetCreateLayer(GDALDatasetH hDS, const char *pszName,
5794 : OGRSpatialReferenceH hSpatialRef,
5795 : OGRwkbGeometryType eGType,
5796 : CSLConstList papszOptions)
5797 :
5798 : {
5799 6455 : VALIDATE_POINTER1(hDS, "GDALDatasetCreateLayer", nullptr);
5800 :
5801 6455 : if (pszName == nullptr)
5802 : {
5803 0 : CPLError(CE_Failure, CPLE_ObjectNull,
5804 : "Name was NULL in GDALDatasetCreateLayer");
5805 0 : return nullptr;
5806 : }
5807 :
5808 : OGRLayerH hLayer =
5809 12910 : OGRLayer::ToHandle(GDALDataset::FromHandle(hDS)->CreateLayer(
5810 6455 : pszName, OGRSpatialReference::FromHandle(hSpatialRef), eGType,
5811 : const_cast<char **>(papszOptions)));
5812 :
5813 : #ifdef OGRAPISPY_ENABLED
5814 6455 : if (bOGRAPISpyEnabled)
5815 8 : OGRAPISpy_DS_CreateLayer(hDS, pszName, hSpatialRef, eGType,
5816 : const_cast<char **>(papszOptions), hLayer);
5817 : #endif
5818 :
5819 6455 : return hLayer;
5820 : }
5821 :
5822 : /************************************************************************/
5823 : /* GDALDatasetCreateLayerFromGeomFieldDefn() */
5824 : /************************************************************************/
5825 :
5826 : /**
5827 : \brief This function attempts to create a new layer on the dataset with the
5828 : indicated name and geometry field.
5829 :
5830 : When poGeomFieldDefn is not null, most drivers should honor
5831 : poGeomFieldDefn->GetType() and poGeomFieldDefn->GetSpatialRef().
5832 : Drivers that honor poGeomFieldDefn->GetCoordinatePrecision() will declare the
5833 : GDAL_DCAP_HONOR_GEOM_COORDINATE_PRECISION capability. Drivers may honor
5834 : poGeomFieldDefn->GetNameRef() and poGeomFieldDefn->IsNullable(), but there are
5835 : very few currently.
5836 :
5837 : Note that even if a geometry coordinate precision is set and a driver honors the
5838 : GDAL_DCAP_HONOR_GEOM_COORDINATE_PRECISION capability, geometries passed to
5839 : OGRLayer::CreateFeature() and OGRLayer::SetFeature() are assumed to be compatible
5840 : with the coordinate precision. That is they are assumed to be valid once their
5841 : coordinates are rounded to it. If it might not be the case, the user may set
5842 : the OGR_APPLY_GEOM_SET_PRECISION configuration option before calling CreateFeature()
5843 : or SetFeature() to force the OGRGeometry::SetPrecision() method to be called on
5844 : the passed geometries.
5845 :
5846 : The papszOptions argument can be used to control driver specific creation
5847 : options. These options are normally documented in the format specific
5848 : documentation.
5849 :
5850 : This method is the same as the C++ method GDALDataset::CreateLayer().
5851 :
5852 : @param hDS the dataset handle
5853 : @param pszName the name for the new layer. This should ideally not
5854 : match any existing layer on the datasource.
5855 : @param hGeomFieldDefn the geometry field definition. May be NULL to indicate
5856 : a non-spatial file (or if adding geometry fields later with OGR_L_CreateGeomField()
5857 : for drivers supporting that interface).
5858 : @param papszOptions a StringList of name=value options. Options are driver
5859 : specific.
5860 :
5861 : @return NULL is returned on failure, or a new OGRLayer handle on success.
5862 :
5863 : @since GDAL 3.9
5864 :
5865 : */
5866 :
5867 : OGRLayerH
5868 14 : GDALDatasetCreateLayerFromGeomFieldDefn(GDALDatasetH hDS, const char *pszName,
5869 : OGRGeomFieldDefnH hGeomFieldDefn,
5870 : CSLConstList papszOptions)
5871 :
5872 : {
5873 14 : VALIDATE_POINTER1(hDS, "GDALDatasetCreateLayerFromGeomFieldDefn", nullptr);
5874 :
5875 14 : if (!pszName)
5876 : {
5877 0 : CPLError(CE_Failure, CPLE_ObjectNull,
5878 : "Name was NULL in GDALDatasetCreateLayerFromGeomFieldDefn");
5879 0 : return nullptr;
5880 : }
5881 :
5882 : OGRLayerH hLayer =
5883 28 : OGRLayer::ToHandle(GDALDataset::FromHandle(hDS)->CreateLayer(
5884 14 : pszName, OGRGeomFieldDefn::FromHandle(hGeomFieldDefn),
5885 : papszOptions));
5886 14 : return hLayer;
5887 : }
5888 :
5889 : /************************************************************************/
5890 : /* GDALDatasetCopyLayer() */
5891 : /************************************************************************/
5892 :
5893 : /**
5894 : \brief Duplicate an existing layer.
5895 :
5896 : This function creates a new layer, duplicate the field definitions of the
5897 : source layer and then duplicate each features of the source layer.
5898 : The papszOptions argument
5899 : can be used to control driver specific creation options. These options are
5900 : normally documented in the format specific documentation.
5901 : The source layer may come from another dataset.
5902 :
5903 : This method is the same as the C++ method GDALDataset::CopyLayer()
5904 :
5905 :
5906 : @param hDS the dataset handle.
5907 : @param hSrcLayer source layer.
5908 : @param pszNewName the name of the layer to create.
5909 : @param papszOptions a StringList of name=value options. Options are driver
5910 : specific.
5911 :
5912 : @return a handle to the layer, or NULL if an error occurs.
5913 : */
5914 48 : OGRLayerH GDALDatasetCopyLayer(GDALDatasetH hDS, OGRLayerH hSrcLayer,
5915 : const char *pszNewName,
5916 : CSLConstList papszOptions)
5917 :
5918 : {
5919 48 : VALIDATE_POINTER1(hDS, "OGR_DS_CopyGDALDatasetCopyLayerLayer", nullptr);
5920 48 : VALIDATE_POINTER1(hSrcLayer, "GDALDatasetCopyLayer", nullptr);
5921 48 : VALIDATE_POINTER1(pszNewName, "GDALDatasetCopyLayer", nullptr);
5922 :
5923 96 : return OGRLayer::ToHandle(GDALDataset::FromHandle(hDS)->CopyLayer(
5924 96 : OGRLayer::FromHandle(hSrcLayer), pszNewName, papszOptions));
5925 : }
5926 :
5927 : /************************************************************************/
5928 : /* GDALDatasetExecuteSQL() */
5929 : /************************************************************************/
5930 :
5931 : /**
5932 : \brief Execute an SQL statement against the data store.
5933 :
5934 : The result of an SQL query is either NULL for statements that are in error,
5935 : or that have no results set, or an OGRLayer pointer representing a results
5936 : set from the query. Note that this OGRLayer is in addition to the layers
5937 : in the data store and must be destroyed with
5938 : ReleaseResultSet() before the dataset is closed
5939 : (destroyed).
5940 :
5941 : This method is the same as the C++ method GDALDataset::ExecuteSQL()
5942 :
5943 : For more information on the SQL dialect supported internally by OGR
5944 : review the <a href="https://gdal.org/user/ogr_sql_dialect.html">OGR SQL</a>
5945 : document. Some drivers (i.e. Oracle and PostGIS) pass the SQL directly through
5946 : to the underlying RDBMS.
5947 :
5948 : Starting with OGR 1.10, the <a
5949 : href="https://gdal.org/user/sql_sqlite_dialect.html">SQLITE dialect</a> can
5950 : also be used.
5951 :
5952 :
5953 : @param hDS the dataset handle.
5954 : @param pszStatement the SQL statement to execute.
5955 : @param hSpatialFilter geometry which represents a spatial filter. Can be NULL.
5956 :
5957 : @param pszDialect allows control of the statement dialect. If set to NULL, the
5958 : OGR SQL engine will be used, except for RDBMS drivers that will use their
5959 : dedicated SQL engine, unless OGRSQL is explicitly passed as the
5960 : dialect. Starting with OGR 1.10, the SQLITE dialect can also be used.
5961 :
5962 : @return an OGRLayer containing the results of the query. Deallocate with
5963 : GDALDatasetReleaseResultSet().
5964 :
5965 : */
5966 :
5967 10586 : OGRLayerH GDALDatasetExecuteSQL(GDALDatasetH hDS, const char *pszStatement,
5968 : OGRGeometryH hSpatialFilter,
5969 : const char *pszDialect)
5970 :
5971 : {
5972 10586 : VALIDATE_POINTER1(hDS, "GDALDatasetExecuteSQL", nullptr);
5973 :
5974 : OGRLayerH hLayer =
5975 21172 : OGRLayer::ToHandle(GDALDataset::FromHandle(hDS)->ExecuteSQL(
5976 10586 : pszStatement, OGRGeometry::FromHandle(hSpatialFilter), pszDialect));
5977 :
5978 : #ifdef OGRAPISPY_ENABLED
5979 10586 : if (bOGRAPISpyEnabled)
5980 4 : OGRAPISpy_DS_ExecuteSQL(hDS, pszStatement, hSpatialFilter, pszDialect,
5981 : hLayer);
5982 : #endif
5983 :
5984 10586 : return hLayer;
5985 : }
5986 :
5987 : /************************************************************************/
5988 : /* GDALDatasetAbortSQL() */
5989 : /************************************************************************/
5990 :
5991 : /**
5992 : \brief Abort any SQL statement running in the data store.
5993 :
5994 : This function can be safely called from any thread (pending that the dataset
5995 : object is still alive). Driver implementations will make sure that it can be
5996 : called in a thread-safe way.
5997 :
5998 : This might not be implemented by all drivers. At time of writing, only SQLite,
5999 : GPKG and PG drivers implement it
6000 :
6001 : This method is the same as the C++ method GDALDataset::AbortSQL()
6002 :
6003 : @since GDAL 3.2.0
6004 :
6005 : @param hDS the dataset handle.
6006 :
6007 : @return OGRERR_NONE on success, or OGRERR_UNSUPPORTED_OPERATION if AbortSQL
6008 : is not supported for this datasource. .
6009 :
6010 : */
6011 :
6012 6 : OGRErr GDALDatasetAbortSQL(GDALDatasetH hDS)
6013 :
6014 : {
6015 6 : VALIDATE_POINTER1(hDS, "GDALDatasetAbortSQL", OGRERR_FAILURE);
6016 6 : return GDALDataset::FromHandle(hDS)->AbortSQL();
6017 : }
6018 :
6019 : /************************************************************************/
6020 : /* GDALDatasetGetStyleTable() */
6021 : /************************************************************************/
6022 :
6023 : /**
6024 : \brief Returns dataset style table.
6025 :
6026 : This function is the same as the C++ method GDALDataset::GetStyleTable()
6027 :
6028 :
6029 : @param hDS the dataset handle
6030 : @return handle to a style table which should not be modified or freed by the
6031 : caller.
6032 : */
6033 :
6034 6 : OGRStyleTableH GDALDatasetGetStyleTable(GDALDatasetH hDS)
6035 :
6036 : {
6037 6 : VALIDATE_POINTER1(hDS, "OGR_DS_GetStyleTable", nullptr);
6038 :
6039 : return reinterpret_cast<OGRStyleTableH>(
6040 6 : GDALDataset::FromHandle(hDS)->GetStyleTable());
6041 : }
6042 :
6043 : /************************************************************************/
6044 : /* GDALDatasetSetStyleTableDirectly() */
6045 : /************************************************************************/
6046 :
6047 : /**
6048 : \brief Set dataset style table.
6049 :
6050 : This function operate exactly as GDALDatasetSetStyleTable() except that it
6051 : assumes ownership of the passed table.
6052 :
6053 : This function is the same as the C++ method
6054 : GDALDataset::SetStyleTableDirectly()
6055 :
6056 :
6057 : @param hDS the dataset handle
6058 : @param hStyleTable style table handle to set
6059 :
6060 : */
6061 :
6062 0 : void GDALDatasetSetStyleTableDirectly(GDALDatasetH hDS,
6063 : OGRStyleTableH hStyleTable)
6064 :
6065 : {
6066 0 : VALIDATE_POINTER0(hDS, "OGR_DS_SetStyleTableDirectly");
6067 :
6068 0 : GDALDataset::FromHandle(hDS)->SetStyleTableDirectly(
6069 0 : reinterpret_cast<OGRStyleTable *>(hStyleTable));
6070 : }
6071 :
6072 : /************************************************************************/
6073 : /* GDALDatasetSetStyleTable() */
6074 : /************************************************************************/
6075 :
6076 : /**
6077 : \brief Set dataset style table.
6078 :
6079 : This function operate exactly as GDALDatasetSetStyleTableDirectly() except that
6080 : it assumes ownership of the passed table.
6081 :
6082 : This function is the same as the C++ method GDALDataset::SetStyleTable()
6083 :
6084 :
6085 : @param hDS the dataset handle
6086 : @param hStyleTable style table handle to set
6087 :
6088 : */
6089 :
6090 5 : void GDALDatasetSetStyleTable(GDALDatasetH hDS, OGRStyleTableH hStyleTable)
6091 :
6092 : {
6093 5 : VALIDATE_POINTER0(hDS, "OGR_DS_SetStyleTable");
6094 5 : VALIDATE_POINTER0(hStyleTable, "OGR_DS_SetStyleTable");
6095 :
6096 5 : GDALDataset::FromHandle(hDS)->SetStyleTable(
6097 5 : reinterpret_cast<OGRStyleTable *>(hStyleTable));
6098 : }
6099 :
6100 : /************************************************************************/
6101 : /* ValidateLayerCreationOptions() */
6102 : /************************************************************************/
6103 :
6104 : //! @cond Doxygen_Suppress
6105 9733 : int GDALDataset::ValidateLayerCreationOptions(const char *const *papszLCO)
6106 : {
6107 : const char *pszOptionList =
6108 9733 : GetMetadataItem(GDAL_DS_LAYER_CREATIONOPTIONLIST);
6109 9733 : if (pszOptionList == nullptr && poDriver != nullptr)
6110 : {
6111 : pszOptionList =
6112 9692 : poDriver->GetMetadataItem(GDAL_DS_LAYER_CREATIONOPTIONLIST);
6113 : }
6114 19466 : CPLString osDataset;
6115 9733 : osDataset.Printf("dataset %s", GetDescription());
6116 9733 : return GDALValidateOptions(pszOptionList, papszLCO, "layer creation option",
6117 19466 : osDataset);
6118 : }
6119 :
6120 : //! @endcond
6121 :
6122 : /************************************************************************/
6123 : /* Release() */
6124 : /************************************************************************/
6125 :
6126 : /**
6127 : \brief Drop a reference to this dataset, and if the reference count drops to one
6128 : close (destroy) the dataset.
6129 :
6130 : This method is the same as the C function OGRReleaseDataSource().
6131 :
6132 : @deprecated. Use GDALClose() instead
6133 :
6134 : @return OGRERR_NONE on success or an error code.
6135 : */
6136 :
6137 4451 : OGRErr GDALDataset::Release()
6138 :
6139 : {
6140 4451 : ReleaseRef();
6141 4451 : return OGRERR_NONE;
6142 : }
6143 :
6144 : /************************************************************************/
6145 : /* GetRefCount() */
6146 : /************************************************************************/
6147 :
6148 : /**
6149 : \brief Fetch reference count.
6150 :
6151 : This method is the same as the C function OGR_DS_GetRefCount().
6152 :
6153 : @return the current reference count for the datasource object itself.
6154 : */
6155 :
6156 5353 : int GDALDataset::GetRefCount() const
6157 : {
6158 5353 : return nRefCount;
6159 : }
6160 :
6161 : /************************************************************************/
6162 : /* GetSummaryRefCount() */
6163 : /************************************************************************/
6164 :
6165 : /**
6166 : \brief Fetch reference count of datasource and all owned layers.
6167 :
6168 : This method is the same as the C function OGR_DS_GetSummaryRefCount().
6169 :
6170 : @deprecated
6171 :
6172 : @return the current summary reference count for the datasource and its layers.
6173 : */
6174 :
6175 0 : int GDALDataset::GetSummaryRefCount() const
6176 :
6177 : {
6178 0 : CPLMutexHolderD(m_poPrivate ? &(m_poPrivate->hMutex) : nullptr);
6179 0 : int nSummaryCount = nRefCount;
6180 0 : GDALDataset *poUseThis = const_cast<GDALDataset *>(this);
6181 :
6182 0 : for (int iLayer = 0; iLayer < poUseThis->GetLayerCount(); ++iLayer)
6183 0 : nSummaryCount += poUseThis->GetLayer(iLayer)->GetRefCount();
6184 :
6185 0 : return nSummaryCount;
6186 : }
6187 :
6188 : /************************************************************************/
6189 : /* ICreateLayer() */
6190 : /************************************************************************/
6191 :
6192 : /**
6193 : \brief This method attempts to create a new layer on the dataset with the
6194 : indicated name, coordinate system, geometry type.
6195 :
6196 : This method is reserved to implementation by drivers.
6197 :
6198 : The papszOptions argument can be used to control driver specific creation
6199 : options. These options are normally documented in the format specific
6200 : documentation.
6201 :
6202 : @param pszName the name for the new layer. This should ideally not
6203 : match any existing layer on the datasource.
6204 : @param poGeomFieldDefn the geometry field definition to use for the new layer,
6205 : or NULL if there is no geometry field.
6206 : @param papszOptions a StringList of name=value options. Options are driver
6207 : specific.
6208 :
6209 : @return NULL is returned on failure, or a new OGRLayer handle on success.
6210 :
6211 : */
6212 :
6213 : OGRLayer *
6214 16 : GDALDataset::ICreateLayer(CPL_UNUSED const char *pszName,
6215 : CPL_UNUSED const OGRGeomFieldDefn *poGeomFieldDefn,
6216 : CPL_UNUSED CSLConstList papszOptions)
6217 :
6218 : {
6219 16 : CPLError(CE_Failure, CPLE_NotSupported,
6220 : "CreateLayer() not supported by this dataset.");
6221 :
6222 16 : return nullptr;
6223 : }
6224 :
6225 : /************************************************************************/
6226 : /* CopyLayer() */
6227 : /************************************************************************/
6228 :
6229 : /**
6230 : \brief Duplicate an existing layer.
6231 :
6232 : This method creates a new layer, duplicate the field definitions of the
6233 : source layer and then duplicate each features of the source layer.
6234 : The papszOptions argument
6235 : can be used to control driver specific creation options. These options are
6236 : normally documented in the format specific documentation.
6237 : The source layer may come from another dataset.
6238 :
6239 : This method is the same as the C function GDALDatasetCopyLayer() and the
6240 : deprecated OGR_DS_CopyLayer().
6241 :
6242 : @param poSrcLayer source layer.
6243 : @param pszNewName the name of the layer to create.
6244 : @param papszOptions a StringList of name=value options. Options are driver
6245 : specific. There is a common option to set output layer
6246 : spatial reference: DST_SRSWKT. The option should be in
6247 : WKT format. Starting with GDAL 3.7, the common option
6248 : COPY_MD can be set to NO to prevent the default copying
6249 : of the metadata from the source layer to the target layer.
6250 :
6251 : @return a handle to the layer, or NULL if an error occurs.
6252 : */
6253 :
6254 164 : OGRLayer *GDALDataset::CopyLayer(OGRLayer *poSrcLayer, const char *pszNewName,
6255 : CSLConstList papszOptions)
6256 :
6257 : {
6258 : /* -------------------------------------------------------------------- */
6259 : /* Create the layer. */
6260 : /* -------------------------------------------------------------------- */
6261 164 : if (!TestCapability(ODsCCreateLayer))
6262 : {
6263 0 : CPLError(CE_Failure, CPLE_NotSupported,
6264 : "This datasource does not support creation of layers.");
6265 0 : return nullptr;
6266 : }
6267 :
6268 164 : const char *pszSRSWKT = CSLFetchNameValue(papszOptions, "DST_SRSWKT");
6269 328 : OGRSpatialReference oDstSpaRef(pszSRSWKT);
6270 164 : oDstSpaRef.SetAxisMappingStrategy(OAMS_TRADITIONAL_GIS_ORDER);
6271 164 : OGRFeatureDefn *poSrcDefn = poSrcLayer->GetLayerDefn();
6272 164 : OGRLayer *poDstLayer = nullptr;
6273 :
6274 328 : CPLStringList aosCleanedUpOptions(CSLDuplicate(papszOptions));
6275 164 : aosCleanedUpOptions.SetNameValue("DST_SRSWKT", nullptr);
6276 164 : aosCleanedUpOptions.SetNameValue("COPY_MD", nullptr);
6277 :
6278 164 : CPLErrorReset();
6279 164 : const int nSrcGeomFieldCount = poSrcDefn->GetGeomFieldCount();
6280 164 : if (nSrcGeomFieldCount == 1)
6281 : {
6282 112 : OGRGeomFieldDefn oGeomFieldDefn(poSrcDefn->GetGeomFieldDefn(0));
6283 112 : if (pszSRSWKT)
6284 5 : oGeomFieldDefn.SetSpatialRef(&oDstSpaRef);
6285 112 : poDstLayer = ICreateLayer(pszNewName, &oGeomFieldDefn,
6286 112 : aosCleanedUpOptions.List());
6287 : }
6288 : else
6289 : {
6290 : poDstLayer =
6291 52 : ICreateLayer(pszNewName, nullptr, aosCleanedUpOptions.List());
6292 : }
6293 :
6294 164 : if (poDstLayer == nullptr)
6295 0 : return nullptr;
6296 :
6297 164 : if (CPLTestBool(CSLFetchNameValueDef(papszOptions, "COPY_MD", "YES")))
6298 : {
6299 163 : CSLConstList papszMD = poSrcLayer->GetMetadata();
6300 163 : if (papszMD)
6301 31 : poDstLayer->SetMetadata(papszMD);
6302 : }
6303 :
6304 : /* -------------------------------------------------------------------- */
6305 : /* Add fields. Default to copy all fields, and make sure to */
6306 : /* establish a mapping between indices, rather than names, in */
6307 : /* case the target datasource has altered it (e.g. Shapefile */
6308 : /* limited to 10 char field names). */
6309 : /* -------------------------------------------------------------------- */
6310 164 : const int nSrcFieldCount = poSrcDefn->GetFieldCount();
6311 :
6312 : // Initialize the index-to-index map to -1's.
6313 328 : std::vector<int> anMap(nSrcFieldCount, -1);
6314 :
6315 : // Caution: At the time of writing, the MapInfo driver
6316 : // returns NULL until a field has been added.
6317 164 : OGRFeatureDefn *poDstFDefn = poDstLayer->GetLayerDefn();
6318 164 : int nDstFieldCount = poDstFDefn ? poDstFDefn->GetFieldCount() : 0;
6319 391 : for (int iField = 0; iField < nSrcFieldCount; ++iField)
6320 : {
6321 227 : OGRFieldDefn *poSrcFieldDefn = poSrcDefn->GetFieldDefn(iField);
6322 454 : OGRFieldDefn oFieldDefn(poSrcFieldDefn);
6323 :
6324 : // The field may have been already created at layer creation.
6325 227 : int iDstField = -1;
6326 227 : if (poDstFDefn)
6327 227 : iDstField = poDstFDefn->GetFieldIndex(oFieldDefn.GetNameRef());
6328 227 : if (iDstField >= 0)
6329 : {
6330 0 : anMap[iField] = iDstField;
6331 : }
6332 227 : else if (poDstLayer->CreateField(&oFieldDefn) == OGRERR_NONE)
6333 : {
6334 : // Now that we've created a field, GetLayerDefn() won't return NULL.
6335 227 : if (poDstFDefn == nullptr)
6336 0 : poDstFDefn = poDstLayer->GetLayerDefn();
6337 :
6338 : // Sanity check: if it fails, the driver is buggy.
6339 454 : if (poDstFDefn != nullptr &&
6340 227 : poDstFDefn->GetFieldCount() != nDstFieldCount + 1)
6341 : {
6342 0 : CPLError(CE_Warning, CPLE_AppDefined,
6343 : "The output driver has claimed to have added the %s "
6344 : "field, but it did not!",
6345 : oFieldDefn.GetNameRef());
6346 : }
6347 : else
6348 : {
6349 227 : anMap[iField] = nDstFieldCount;
6350 227 : ++nDstFieldCount;
6351 : }
6352 : }
6353 : }
6354 :
6355 : /* -------------------------------------------------------------------- */
6356 164 : std::unique_ptr<OGRCoordinateTransformation> poCT;
6357 164 : const OGRSpatialReference *sourceSRS = poSrcLayer->GetSpatialRef();
6358 164 : if (sourceSRS != nullptr && pszSRSWKT != nullptr && !oDstSpaRef.IsEmpty() &&
6359 0 : sourceSRS->IsSame(&oDstSpaRef) == FALSE)
6360 : {
6361 0 : poCT.reset(OGRCreateCoordinateTransformation(sourceSRS, &oDstSpaRef));
6362 0 : if (nullptr == poCT)
6363 : {
6364 0 : CPLError(CE_Failure, CPLE_NotSupported,
6365 : "This input/output spatial reference is not supported.");
6366 0 : return nullptr;
6367 : }
6368 : }
6369 : /* -------------------------------------------------------------------- */
6370 : /* Create geometry fields. */
6371 : /* -------------------------------------------------------------------- */
6372 165 : if (nSrcGeomFieldCount > 1 &&
6373 1 : TestCapability(ODsCCreateGeomFieldAfterCreateLayer))
6374 : {
6375 :
6376 3 : for (int iField = 0; iField < nSrcGeomFieldCount; ++iField)
6377 : {
6378 2 : if (nullptr == pszSRSWKT)
6379 : {
6380 2 : poDstLayer->CreateGeomField(
6381 2 : poSrcDefn->GetGeomFieldDefn(iField));
6382 : }
6383 : else
6384 : {
6385 : OGRGeomFieldDefn *pDstGeomFieldDefn =
6386 0 : poSrcDefn->GetGeomFieldDefn(iField);
6387 0 : pDstGeomFieldDefn->SetSpatialRef(&oDstSpaRef);
6388 0 : poDstLayer->CreateGeomField(pDstGeomFieldDefn);
6389 : }
6390 : }
6391 : }
6392 :
6393 : /* -------------------------------------------------------------------- */
6394 : /* Check if the destination layer supports transactions and set a */
6395 : /* default number of features in a single transaction. */
6396 : /* -------------------------------------------------------------------- */
6397 : const int nGroupTransactions =
6398 164 : poDstLayer->TestCapability(OLCTransactions) ? 128 : 0;
6399 :
6400 : /* -------------------------------------------------------------------- */
6401 : /* Transfer features. */
6402 : /* -------------------------------------------------------------------- */
6403 164 : poSrcLayer->ResetReading();
6404 :
6405 164 : if (nGroupTransactions <= 0)
6406 : {
6407 : while (true)
6408 : {
6409 : auto poFeature =
6410 682 : std::unique_ptr<OGRFeature>(poSrcLayer->GetNextFeature());
6411 :
6412 682 : if (poFeature == nullptr)
6413 155 : break;
6414 :
6415 527 : CPLErrorReset();
6416 : auto poDstFeature =
6417 527 : std::make_unique<OGRFeature>(poDstLayer->GetLayerDefn());
6418 :
6419 527 : if (poDstFeature->SetFrom(poFeature.get(), anMap.data(), TRUE) !=
6420 : OGRERR_NONE)
6421 : {
6422 0 : CPLError(CE_Failure, CPLE_AppDefined,
6423 : "Unable to translate feature " CPL_FRMT_GIB
6424 : " from layer %s.",
6425 0 : poFeature->GetFID(), poSrcDefn->GetName());
6426 0 : return poDstLayer;
6427 : }
6428 :
6429 527 : if (nullptr != poCT)
6430 : {
6431 0 : for (int iField = 0; iField < nSrcGeomFieldCount; ++iField)
6432 : {
6433 0 : OGRGeometry *pGeom = poDstFeature->GetGeomFieldRef(iField);
6434 0 : if (nullptr == pGeom)
6435 0 : continue;
6436 :
6437 0 : const OGRErr eErr = pGeom->transform(poCT.get());
6438 0 : if (eErr == OGRERR_NONE)
6439 0 : continue;
6440 :
6441 0 : CPLError(CE_Failure, CPLE_AppDefined,
6442 : "Unable to transform geometry " CPL_FRMT_GIB
6443 : " from layer %s.",
6444 0 : poFeature->GetFID(), poSrcDefn->GetName());
6445 0 : return poDstLayer;
6446 : }
6447 : }
6448 :
6449 527 : poDstFeature->SetFID(poFeature->GetFID());
6450 :
6451 527 : CPLErrorReset();
6452 527 : if (poDstLayer->CreateFeature(poDstFeature.get()) != OGRERR_NONE)
6453 : {
6454 0 : return poDstLayer;
6455 : }
6456 527 : }
6457 : }
6458 : else
6459 : {
6460 9 : std::vector<std::unique_ptr<OGRFeature>> apoDstFeatures;
6461 : try
6462 : {
6463 9 : apoDstFeatures.resize(nGroupTransactions);
6464 : }
6465 0 : catch (const std::exception &e)
6466 : {
6467 0 : CPLError(CE_Failure, CPLE_OutOfMemory, "%s", e.what());
6468 0 : return poDstLayer;
6469 : }
6470 9 : bool bStopTransfer = false;
6471 18 : while (!bStopTransfer)
6472 : {
6473 : /* --------------------------------------------------------------------
6474 : */
6475 : /* Fill the array with features. */
6476 : /* --------------------------------------------------------------------
6477 : */
6478 : // Number of features in the temporary array.
6479 9 : int nFeatCount = 0; // Used after for.
6480 85 : for (nFeatCount = 0; nFeatCount < nGroupTransactions; ++nFeatCount)
6481 : {
6482 : auto poFeature =
6483 85 : std::unique_ptr<OGRFeature>(poSrcLayer->GetNextFeature());
6484 :
6485 85 : if (poFeature == nullptr)
6486 : {
6487 9 : bStopTransfer = true;
6488 9 : break;
6489 : }
6490 :
6491 76 : CPLErrorReset();
6492 76 : apoDstFeatures[nFeatCount] =
6493 152 : std::make_unique<OGRFeature>(poDstLayer->GetLayerDefn());
6494 :
6495 152 : if (apoDstFeatures[nFeatCount]->SetFrom(
6496 152 : poFeature.get(), anMap.data(), TRUE) != OGRERR_NONE)
6497 : {
6498 0 : CPLError(CE_Failure, CPLE_AppDefined,
6499 : "Unable to translate feature " CPL_FRMT_GIB
6500 : " from layer %s.",
6501 0 : poFeature->GetFID(), poSrcDefn->GetName());
6502 0 : bStopTransfer = true;
6503 0 : poFeature.reset();
6504 0 : break;
6505 : }
6506 :
6507 76 : if (nullptr != poCT)
6508 : {
6509 0 : for (int iField = 0; iField < nSrcGeomFieldCount; ++iField)
6510 : {
6511 : OGRGeometry *pGeom =
6512 0 : apoDstFeatures[nFeatCount]->GetGeomFieldRef(iField);
6513 0 : if (nullptr == pGeom)
6514 0 : continue;
6515 :
6516 0 : const OGRErr eErr = pGeom->transform(poCT.get());
6517 0 : if (eErr == OGRERR_NONE)
6518 0 : continue;
6519 :
6520 0 : CPLError(CE_Failure, CPLE_AppDefined,
6521 : "Unable to transform geometry " CPL_FRMT_GIB
6522 : " from layer %s.",
6523 0 : poFeature->GetFID(), poSrcDefn->GetName());
6524 0 : bStopTransfer = true;
6525 0 : poFeature.reset();
6526 0 : break;
6527 : }
6528 : }
6529 :
6530 76 : if (poFeature)
6531 : {
6532 76 : apoDstFeatures[nFeatCount]->SetFID(poFeature->GetFID());
6533 : }
6534 : }
6535 :
6536 9 : CPLErrorReset();
6537 9 : bool bStopTransaction = false;
6538 18 : while (!bStopTransaction)
6539 : {
6540 9 : bStopTransaction = true;
6541 9 : if (poDstLayer->StartTransaction() != OGRERR_NONE)
6542 0 : break;
6543 85 : for (int i = 0; i < nFeatCount; ++i)
6544 : {
6545 76 : if (poDstLayer->CreateFeature(apoDstFeatures[i].get()) !=
6546 : OGRERR_NONE)
6547 : {
6548 0 : bStopTransfer = true;
6549 0 : bStopTransaction = false;
6550 0 : break;
6551 : }
6552 76 : apoDstFeatures[i].reset();
6553 : }
6554 9 : if (bStopTransaction)
6555 : {
6556 9 : if (poDstLayer->CommitTransaction() != OGRERR_NONE)
6557 0 : break;
6558 : }
6559 : else
6560 : {
6561 0 : poDstLayer->RollbackTransaction();
6562 : }
6563 : }
6564 : }
6565 : }
6566 :
6567 164 : return poDstLayer;
6568 : }
6569 :
6570 : /************************************************************************/
6571 : /* DeleteLayer() */
6572 : /************************************************************************/
6573 :
6574 : /**
6575 : \fn GDALDataset::DeleteLayer(int)
6576 : \brief Delete the indicated layer from the datasource.
6577 :
6578 : If this method is supported
6579 : the ODsCDeleteLayer capability will test TRUE on the GDALDataset.
6580 :
6581 : This method is the same as the C function GDALDatasetDeleteLayer() and the
6582 : deprecated OGR_DS_DeleteLayer().
6583 :
6584 : @param iLayer the index of the layer to delete.
6585 :
6586 : @return OGRERR_NONE on success, or OGRERR_UNSUPPORTED_OPERATION if deleting
6587 : layers is not supported for this datasource.
6588 :
6589 : */
6590 :
6591 389 : OGRErr GDALDataset::DeleteLayer(CPL_UNUSED int iLayer)
6592 :
6593 : {
6594 389 : CPLError(CE_Failure, CPLE_NotSupported,
6595 : "DeleteLayer() not supported by this dataset.");
6596 :
6597 389 : return OGRERR_UNSUPPORTED_OPERATION;
6598 : }
6599 :
6600 : /************************************************************************/
6601 : /* GetLayerByName() */
6602 : /************************************************************************/
6603 :
6604 : /**
6605 : \brief Fetch a layer by name.
6606 :
6607 : The returned layer remains owned by the
6608 : GDALDataset and should not be deleted by the application.
6609 :
6610 : This method is the same as the C function GDALDatasetGetLayerByName() and the
6611 : deprecated OGR_DS_GetLayerByName().
6612 :
6613 : @param pszName the layer name of the layer to fetch.
6614 :
6615 : @return the layer, or NULL if Layer is not found or an error occurs.
6616 : */
6617 :
6618 30112 : OGRLayer *GDALDataset::GetLayerByName(const char *pszName)
6619 :
6620 : {
6621 60224 : CPLMutexHolderD(m_poPrivate ? &(m_poPrivate->hMutex) : nullptr);
6622 :
6623 30112 : if (!pszName)
6624 0 : return nullptr;
6625 :
6626 : // First a case sensitive check.
6627 932680 : for (int i = 0; i < GetLayerCount(); ++i)
6628 : {
6629 914453 : OGRLayer *poLayer = GetLayer(i);
6630 :
6631 914453 : if (strcmp(pszName, poLayer->GetName()) == 0)
6632 11885 : return poLayer;
6633 : }
6634 :
6635 : // Then case insensitive.
6636 893842 : for (int i = 0; i < GetLayerCount(); ++i)
6637 : {
6638 875839 : OGRLayer *poLayer = GetLayer(i);
6639 :
6640 875839 : if (EQUAL(pszName, poLayer->GetName()))
6641 224 : return poLayer;
6642 : }
6643 :
6644 18003 : return nullptr;
6645 : }
6646 :
6647 : //! @cond Doxygen_Suppress
6648 : /************************************************************************/
6649 : /* ProcessSQLCreateIndex() */
6650 : /* */
6651 : /* The correct syntax for creating an index in our dialect of */
6652 : /* SQL is: */
6653 : /* */
6654 : /* CREATE INDEX ON <layername> USING <columnname> */
6655 : /************************************************************************/
6656 :
6657 28 : OGRErr GDALDataset::ProcessSQLCreateIndex(const char *pszSQLCommand)
6658 :
6659 : {
6660 28 : char **papszTokens = CSLTokenizeString(pszSQLCommand);
6661 :
6662 : /* -------------------------------------------------------------------- */
6663 : /* Do some general syntax checking. */
6664 : /* -------------------------------------------------------------------- */
6665 56 : if (CSLCount(papszTokens) != 6 || !EQUAL(papszTokens[0], "CREATE") ||
6666 84 : !EQUAL(papszTokens[1], "INDEX") || !EQUAL(papszTokens[2], "ON") ||
6667 28 : !EQUAL(papszTokens[4], "USING"))
6668 : {
6669 0 : CSLDestroy(papszTokens);
6670 0 : CPLError(CE_Failure, CPLE_AppDefined,
6671 : "Syntax error in CREATE INDEX command.\n"
6672 : "Was '%s'\n"
6673 : "Should be of form 'CREATE INDEX ON <table> USING <field>'",
6674 : pszSQLCommand);
6675 0 : return OGRERR_FAILURE;
6676 : }
6677 :
6678 : /* -------------------------------------------------------------------- */
6679 : /* Find the named layer. */
6680 : /* -------------------------------------------------------------------- */
6681 28 : OGRLayer *poLayer = GetLayerByName(papszTokens[3]);
6682 28 : if (poLayer == nullptr)
6683 : {
6684 0 : CPLError(CE_Failure, CPLE_AppDefined,
6685 : "CREATE INDEX ON failed, no such layer as `%s'.",
6686 0 : papszTokens[3]);
6687 0 : CSLDestroy(papszTokens);
6688 0 : return OGRERR_FAILURE;
6689 : }
6690 :
6691 : /* -------------------------------------------------------------------- */
6692 : /* Does this layer even support attribute indexes? */
6693 : /* -------------------------------------------------------------------- */
6694 28 : if (poLayer->GetIndex() == nullptr)
6695 : {
6696 0 : CPLError(CE_Failure, CPLE_AppDefined,
6697 : "CREATE INDEX ON not supported by this driver.");
6698 0 : CSLDestroy(papszTokens);
6699 0 : return OGRERR_FAILURE;
6700 : }
6701 :
6702 : /* -------------------------------------------------------------------- */
6703 : /* Find the named field. */
6704 : /* -------------------------------------------------------------------- */
6705 28 : int i = poLayer->GetLayerDefn()->GetFieldIndex(papszTokens[5]);
6706 :
6707 28 : CSLDestroy(papszTokens);
6708 :
6709 28 : if (i >= poLayer->GetLayerDefn()->GetFieldCount())
6710 : {
6711 0 : CPLError(CE_Failure, CPLE_AppDefined, "`%s' failed, field not found.",
6712 : pszSQLCommand);
6713 0 : return OGRERR_FAILURE;
6714 : }
6715 :
6716 : /* -------------------------------------------------------------------- */
6717 : /* Attempt to create the index. */
6718 : /* -------------------------------------------------------------------- */
6719 28 : OGRErr eErr = poLayer->GetIndex()->CreateIndex(i);
6720 28 : if (eErr == OGRERR_NONE)
6721 : {
6722 28 : eErr = poLayer->GetIndex()->IndexAllFeatures(i);
6723 : }
6724 : else
6725 : {
6726 0 : if (strlen(CPLGetLastErrorMsg()) == 0)
6727 0 : CPLError(CE_Failure, CPLE_AppDefined, "Cannot '%s'", pszSQLCommand);
6728 : }
6729 :
6730 28 : return eErr;
6731 : }
6732 :
6733 : /************************************************************************/
6734 : /* ProcessSQLDropIndex() */
6735 : /* */
6736 : /* The correct syntax for dropping one or more indexes in */
6737 : /* the OGR SQL dialect is: */
6738 : /* */
6739 : /* DROP INDEX ON <layername> [USING <columnname>] */
6740 : /************************************************************************/
6741 :
6742 10 : OGRErr GDALDataset::ProcessSQLDropIndex(const char *pszSQLCommand)
6743 :
6744 : {
6745 10 : char **papszTokens = CSLTokenizeString(pszSQLCommand);
6746 :
6747 : /* -------------------------------------------------------------------- */
6748 : /* Do some general syntax checking. */
6749 : /* -------------------------------------------------------------------- */
6750 20 : if ((CSLCount(papszTokens) != 4 && CSLCount(papszTokens) != 6) ||
6751 10 : !EQUAL(papszTokens[0], "DROP") || !EQUAL(papszTokens[1], "INDEX") ||
6752 30 : !EQUAL(papszTokens[2], "ON") ||
6753 10 : (CSLCount(papszTokens) == 6 && !EQUAL(papszTokens[4], "USING")))
6754 : {
6755 0 : CSLDestroy(papszTokens);
6756 0 : CPLError(CE_Failure, CPLE_AppDefined,
6757 : "Syntax error in DROP INDEX command.\n"
6758 : "Was '%s'\n"
6759 : "Should be of form 'DROP INDEX ON <table> [USING <field>]'",
6760 : pszSQLCommand);
6761 0 : return OGRERR_FAILURE;
6762 : }
6763 :
6764 : /* -------------------------------------------------------------------- */
6765 : /* Find the named layer. */
6766 : /* -------------------------------------------------------------------- */
6767 10 : OGRLayer *poLayer = GetLayerByName(papszTokens[3]);
6768 10 : if (poLayer == nullptr)
6769 : {
6770 0 : CPLError(CE_Failure, CPLE_AppDefined,
6771 : "DROP INDEX ON failed, no such layer as `%s'.",
6772 0 : papszTokens[3]);
6773 0 : CSLDestroy(papszTokens);
6774 0 : return OGRERR_FAILURE;
6775 : }
6776 :
6777 : /* -------------------------------------------------------------------- */
6778 : /* Does this layer even support attribute indexes? */
6779 : /* -------------------------------------------------------------------- */
6780 10 : if (poLayer->GetIndex() == nullptr)
6781 : {
6782 0 : CPLError(CE_Failure, CPLE_AppDefined,
6783 : "Indexes not supported by this driver.");
6784 0 : CSLDestroy(papszTokens);
6785 0 : return OGRERR_FAILURE;
6786 : }
6787 :
6788 : /* -------------------------------------------------------------------- */
6789 : /* If we were not given a field name, drop all indexes. */
6790 : /* -------------------------------------------------------------------- */
6791 10 : if (CSLCount(papszTokens) == 4)
6792 : {
6793 0 : for (int i = 0; i < poLayer->GetLayerDefn()->GetFieldCount(); ++i)
6794 : {
6795 : OGRAttrIndex *poAttrIndex;
6796 :
6797 0 : poAttrIndex = poLayer->GetIndex()->GetFieldIndex(i);
6798 0 : if (poAttrIndex != nullptr)
6799 : {
6800 0 : const OGRErr eErr = poLayer->GetIndex()->DropIndex(i);
6801 0 : if (eErr != OGRERR_NONE)
6802 : {
6803 0 : CSLDestroy(papszTokens);
6804 0 : return eErr;
6805 : }
6806 : }
6807 : }
6808 :
6809 0 : CSLDestroy(papszTokens);
6810 0 : return OGRERR_NONE;
6811 : }
6812 :
6813 : /* -------------------------------------------------------------------- */
6814 : /* Find the named field. */
6815 : /* -------------------------------------------------------------------- */
6816 10 : int i = poLayer->GetLayerDefn()->GetFieldIndex(papszTokens[5]);
6817 10 : CSLDestroy(papszTokens);
6818 :
6819 10 : if (i >= poLayer->GetLayerDefn()->GetFieldCount())
6820 : {
6821 0 : CPLError(CE_Failure, CPLE_AppDefined, "`%s' failed, field not found.",
6822 : pszSQLCommand);
6823 0 : return OGRERR_FAILURE;
6824 : }
6825 :
6826 : /* -------------------------------------------------------------------- */
6827 : /* Attempt to drop the index. */
6828 : /* -------------------------------------------------------------------- */
6829 10 : const OGRErr eErr = poLayer->GetIndex()->DropIndex(i);
6830 :
6831 10 : return eErr;
6832 : }
6833 :
6834 : /************************************************************************/
6835 : /* ProcessSQLDropTable() */
6836 : /* */
6837 : /* The correct syntax for dropping a table (layer) in the OGR SQL */
6838 : /* dialect is: */
6839 : /* */
6840 : /* DROP TABLE <layername> */
6841 : /************************************************************************/
6842 :
6843 500 : OGRErr GDALDataset::ProcessSQLDropTable(const char *pszSQLCommand)
6844 :
6845 : {
6846 500 : char **papszTokens = CSLTokenizeString(pszSQLCommand);
6847 :
6848 : /* -------------------------------------------------------------------- */
6849 : /* Do some general syntax checking. */
6850 : /* -------------------------------------------------------------------- */
6851 1000 : if (CSLCount(papszTokens) != 3 || !EQUAL(papszTokens[0], "DROP") ||
6852 500 : !EQUAL(papszTokens[1], "TABLE"))
6853 : {
6854 0 : CSLDestroy(papszTokens);
6855 0 : CPLError(CE_Failure, CPLE_AppDefined,
6856 : "Syntax error in DROP TABLE command.\n"
6857 : "Was '%s'\n"
6858 : "Should be of form 'DROP TABLE <table>'",
6859 : pszSQLCommand);
6860 0 : return OGRERR_FAILURE;
6861 : }
6862 :
6863 : /* -------------------------------------------------------------------- */
6864 : /* Find the named layer. */
6865 : /* -------------------------------------------------------------------- */
6866 500 : OGRLayer *poLayer = nullptr;
6867 :
6868 500 : int i = 0; // Used after for.
6869 40199 : for (; i < GetLayerCount(); ++i)
6870 : {
6871 40199 : poLayer = GetLayer(i);
6872 :
6873 40199 : if (poLayer != nullptr && EQUAL(poLayer->GetName(), papszTokens[2]))
6874 500 : break;
6875 39699 : poLayer = nullptr;
6876 : }
6877 :
6878 500 : if (poLayer == nullptr)
6879 : {
6880 0 : CPLError(CE_Failure, CPLE_AppDefined,
6881 0 : "DROP TABLE failed, no such layer as `%s'.", papszTokens[2]);
6882 0 : CSLDestroy(papszTokens);
6883 0 : return OGRERR_FAILURE;
6884 : }
6885 :
6886 500 : CSLDestroy(papszTokens);
6887 :
6888 : /* -------------------------------------------------------------------- */
6889 : /* Delete it. */
6890 : /* -------------------------------------------------------------------- */
6891 :
6892 500 : return DeleteLayer(i);
6893 : }
6894 :
6895 : //! @endcond
6896 :
6897 : /************************************************************************/
6898 : /* GDALDatasetParseSQLType() */
6899 : /************************************************************************/
6900 :
6901 : /* All arguments will be altered */
6902 6 : static OGRFieldType GDALDatasetParseSQLType(char *pszType, int &nWidth,
6903 : int &nPrecision)
6904 : {
6905 6 : char *pszParenthesis = strchr(pszType, '(');
6906 6 : if (pszParenthesis)
6907 : {
6908 4 : nWidth = atoi(pszParenthesis + 1);
6909 4 : *pszParenthesis = '\0';
6910 4 : char *pszComma = strchr(pszParenthesis + 1, ',');
6911 4 : if (pszComma)
6912 2 : nPrecision = atoi(pszComma + 1);
6913 : }
6914 :
6915 6 : OGRFieldType eType = OFTString;
6916 6 : if (EQUAL(pszType, "INTEGER"))
6917 0 : eType = OFTInteger;
6918 6 : else if (EQUAL(pszType, "INTEGER[]"))
6919 0 : eType = OFTIntegerList;
6920 6 : else if (EQUAL(pszType, "FLOAT") || EQUAL(pszType, "NUMERIC") ||
6921 4 : EQUAL(pszType, "DOUBLE") /* unofficial alias */ ||
6922 4 : EQUAL(pszType, "REAL") /* unofficial alias */)
6923 2 : eType = OFTReal;
6924 4 : else if (EQUAL(pszType, "FLOAT[]") || EQUAL(pszType, "NUMERIC[]") ||
6925 4 : EQUAL(pszType, "DOUBLE[]") /* unofficial alias */ ||
6926 4 : EQUAL(pszType, "REAL[]") /* unofficial alias */)
6927 0 : eType = OFTRealList;
6928 4 : else if (EQUAL(pszType, "CHARACTER") ||
6929 0 : EQUAL(pszType, "TEXT") /* unofficial alias */ ||
6930 0 : EQUAL(pszType, "STRING") /* unofficial alias */ ||
6931 0 : EQUAL(pszType, "VARCHAR") /* unofficial alias */)
6932 4 : eType = OFTString;
6933 0 : else if (EQUAL(pszType, "TEXT[]") ||
6934 0 : EQUAL(pszType, "STRING[]") /* unofficial alias */ ||
6935 0 : EQUAL(pszType, "VARCHAR[]") /* unofficial alias */)
6936 0 : eType = OFTStringList;
6937 0 : else if (EQUAL(pszType, "DATE"))
6938 0 : eType = OFTDate;
6939 0 : else if (EQUAL(pszType, "TIME"))
6940 0 : eType = OFTTime;
6941 0 : else if (EQUAL(pszType, "TIMESTAMP") ||
6942 0 : EQUAL(pszType, "DATETIME") /* unofficial alias */)
6943 0 : eType = OFTDateTime;
6944 : else
6945 0 : CPLError(CE_Warning, CPLE_NotSupported,
6946 : "Unsupported column type '%s'. Defaulting to VARCHAR",
6947 : pszType);
6948 :
6949 6 : return eType;
6950 : }
6951 :
6952 : /************************************************************************/
6953 : /* ProcessSQLAlterTableAddColumn() */
6954 : /* */
6955 : /* The correct syntax for adding a column in the OGR SQL */
6956 : /* dialect is: */
6957 : /* */
6958 : /* ALTER TABLE <layername> ADD [COLUMN] <columnname> <columntype> */
6959 : /************************************************************************/
6960 :
6961 : //! @cond Doxygen_Suppress
6962 2 : OGRErr GDALDataset::ProcessSQLAlterTableAddColumn(const char *pszSQLCommand)
6963 :
6964 : {
6965 2 : char **papszTokens = CSLTokenizeString(pszSQLCommand);
6966 :
6967 : /* -------------------------------------------------------------------- */
6968 : /* Do some general syntax checking. */
6969 : /* -------------------------------------------------------------------- */
6970 2 : const char *pszLayerName = nullptr;
6971 2 : const char *pszColumnName = nullptr;
6972 2 : int iTypeIndex = 0;
6973 2 : const int nTokens = CSLCount(papszTokens);
6974 :
6975 2 : if (nTokens >= 7 && EQUAL(papszTokens[0], "ALTER") &&
6976 2 : EQUAL(papszTokens[1], "TABLE") && EQUAL(papszTokens[3], "ADD") &&
6977 2 : EQUAL(papszTokens[4], "COLUMN"))
6978 : {
6979 1 : pszLayerName = papszTokens[2];
6980 1 : pszColumnName = papszTokens[5];
6981 1 : iTypeIndex = 6;
6982 : }
6983 1 : else if (nTokens >= 6 && EQUAL(papszTokens[0], "ALTER") &&
6984 1 : EQUAL(papszTokens[1], "TABLE") && EQUAL(papszTokens[3], "ADD"))
6985 : {
6986 1 : pszLayerName = papszTokens[2];
6987 1 : pszColumnName = papszTokens[4];
6988 1 : iTypeIndex = 5;
6989 : }
6990 : else
6991 : {
6992 0 : CSLDestroy(papszTokens);
6993 0 : CPLError(CE_Failure, CPLE_AppDefined,
6994 : "Syntax error in ALTER TABLE ADD COLUMN command.\n"
6995 : "Was '%s'\n"
6996 : "Should be of form 'ALTER TABLE <layername> ADD [COLUMN] "
6997 : "<columnname> <columntype>'",
6998 : pszSQLCommand);
6999 0 : return OGRERR_FAILURE;
7000 : }
7001 :
7002 : /* -------------------------------------------------------------------- */
7003 : /* Merge type components into a single string if there were split */
7004 : /* with spaces */
7005 : /* -------------------------------------------------------------------- */
7006 4 : CPLString osType;
7007 6 : for (int i = iTypeIndex; i < nTokens; ++i)
7008 : {
7009 4 : osType += papszTokens[i];
7010 4 : CPLFree(papszTokens[i]);
7011 : }
7012 2 : char *pszType = papszTokens[iTypeIndex] = CPLStrdup(osType);
7013 2 : papszTokens[iTypeIndex + 1] = nullptr;
7014 :
7015 : /* -------------------------------------------------------------------- */
7016 : /* Find the named layer. */
7017 : /* -------------------------------------------------------------------- */
7018 2 : OGRLayer *poLayer = GetLayerByName(pszLayerName);
7019 2 : if (poLayer == nullptr)
7020 : {
7021 0 : CPLError(CE_Failure, CPLE_AppDefined,
7022 : "%s failed, no such layer as `%s'.", pszSQLCommand,
7023 : pszLayerName);
7024 0 : CSLDestroy(papszTokens);
7025 0 : return OGRERR_FAILURE;
7026 : }
7027 :
7028 : /* -------------------------------------------------------------------- */
7029 : /* Add column. */
7030 : /* -------------------------------------------------------------------- */
7031 :
7032 2 : int nWidth = 0;
7033 2 : int nPrecision = 0;
7034 2 : OGRFieldType eType = GDALDatasetParseSQLType(pszType, nWidth, nPrecision);
7035 4 : OGRFieldDefn oFieldDefn(pszColumnName, eType);
7036 2 : oFieldDefn.SetWidth(nWidth);
7037 2 : oFieldDefn.SetPrecision(nPrecision);
7038 :
7039 2 : CSLDestroy(papszTokens);
7040 :
7041 2 : return poLayer->CreateField(&oFieldDefn);
7042 : }
7043 :
7044 : /************************************************************************/
7045 : /* ProcessSQLAlterTableDropColumn() */
7046 : /* */
7047 : /* The correct syntax for dropping a column in the OGR SQL */
7048 : /* dialect is: */
7049 : /* */
7050 : /* ALTER TABLE <layername> DROP [COLUMN] <columnname> */
7051 : /************************************************************************/
7052 :
7053 2 : OGRErr GDALDataset::ProcessSQLAlterTableDropColumn(const char *pszSQLCommand)
7054 :
7055 : {
7056 2 : char **papszTokens = CSLTokenizeString(pszSQLCommand);
7057 :
7058 : /* -------------------------------------------------------------------- */
7059 : /* Do some general syntax checking. */
7060 : /* -------------------------------------------------------------------- */
7061 2 : const char *pszLayerName = nullptr;
7062 2 : const char *pszColumnName = nullptr;
7063 3 : if (CSLCount(papszTokens) == 6 && EQUAL(papszTokens[0], "ALTER") &&
7064 4 : EQUAL(papszTokens[1], "TABLE") && EQUAL(papszTokens[3], "DROP") &&
7065 1 : EQUAL(papszTokens[4], "COLUMN"))
7066 : {
7067 1 : pszLayerName = papszTokens[2];
7068 1 : pszColumnName = papszTokens[5];
7069 : }
7070 2 : else if (CSLCount(papszTokens) == 5 && EQUAL(papszTokens[0], "ALTER") &&
7071 2 : EQUAL(papszTokens[1], "TABLE") && EQUAL(papszTokens[3], "DROP"))
7072 : {
7073 1 : pszLayerName = papszTokens[2];
7074 1 : pszColumnName = papszTokens[4];
7075 : }
7076 : else
7077 : {
7078 0 : CSLDestroy(papszTokens);
7079 0 : CPLError(CE_Failure, CPLE_AppDefined,
7080 : "Syntax error in ALTER TABLE DROP COLUMN command.\n"
7081 : "Was '%s'\n"
7082 : "Should be of form 'ALTER TABLE <layername> DROP [COLUMN] "
7083 : "<columnname>'",
7084 : pszSQLCommand);
7085 0 : return OGRERR_FAILURE;
7086 : }
7087 :
7088 : /* -------------------------------------------------------------------- */
7089 : /* Find the named layer. */
7090 : /* -------------------------------------------------------------------- */
7091 2 : OGRLayer *poLayer = GetLayerByName(pszLayerName);
7092 2 : if (poLayer == nullptr)
7093 : {
7094 0 : CPLError(CE_Failure, CPLE_AppDefined,
7095 : "%s failed, no such layer as `%s'.", pszSQLCommand,
7096 : pszLayerName);
7097 0 : CSLDestroy(papszTokens);
7098 0 : return OGRERR_FAILURE;
7099 : }
7100 :
7101 : /* -------------------------------------------------------------------- */
7102 : /* Find the field. */
7103 : /* -------------------------------------------------------------------- */
7104 :
7105 2 : int nFieldIndex = poLayer->GetLayerDefn()->GetFieldIndex(pszColumnName);
7106 2 : if (nFieldIndex < 0)
7107 : {
7108 0 : CPLError(CE_Failure, CPLE_AppDefined,
7109 : "%s failed, no such field as `%s'.", pszSQLCommand,
7110 : pszColumnName);
7111 0 : CSLDestroy(papszTokens);
7112 0 : return OGRERR_FAILURE;
7113 : }
7114 :
7115 : /* -------------------------------------------------------------------- */
7116 : /* Remove it. */
7117 : /* -------------------------------------------------------------------- */
7118 :
7119 2 : CSLDestroy(papszTokens);
7120 :
7121 2 : return poLayer->DeleteField(nFieldIndex);
7122 : }
7123 :
7124 : /************************************************************************/
7125 : /* ProcessSQLAlterTableRenameColumn() */
7126 : /* */
7127 : /* The correct syntax for renaming a column in the OGR SQL */
7128 : /* dialect is: */
7129 : /* */
7130 : /* ALTER TABLE <layername> RENAME [COLUMN] <oldname> TO <newname> */
7131 : /************************************************************************/
7132 :
7133 2 : OGRErr GDALDataset::ProcessSQLAlterTableRenameColumn(const char *pszSQLCommand)
7134 :
7135 : {
7136 2 : char **papszTokens = CSLTokenizeString(pszSQLCommand);
7137 :
7138 : /* -------------------------------------------------------------------- */
7139 : /* Do some general syntax checking. */
7140 : /* -------------------------------------------------------------------- */
7141 2 : const char *pszLayerName = nullptr;
7142 2 : const char *pszOldColName = nullptr;
7143 2 : const char *pszNewColName = nullptr;
7144 3 : if (CSLCount(papszTokens) == 8 && EQUAL(papszTokens[0], "ALTER") &&
7145 1 : EQUAL(papszTokens[1], "TABLE") && EQUAL(papszTokens[3], "RENAME") &&
7146 3 : EQUAL(papszTokens[4], "COLUMN") && EQUAL(papszTokens[6], "TO"))
7147 : {
7148 1 : pszLayerName = papszTokens[2];
7149 1 : pszOldColName = papszTokens[5];
7150 1 : pszNewColName = papszTokens[7];
7151 : }
7152 2 : else if (CSLCount(papszTokens) == 7 && EQUAL(papszTokens[0], "ALTER") &&
7153 1 : EQUAL(papszTokens[1], "TABLE") &&
7154 2 : EQUAL(papszTokens[3], "RENAME") && EQUAL(papszTokens[5], "TO"))
7155 : {
7156 1 : pszLayerName = papszTokens[2];
7157 1 : pszOldColName = papszTokens[4];
7158 1 : pszNewColName = papszTokens[6];
7159 : }
7160 : else
7161 : {
7162 0 : CSLDestroy(papszTokens);
7163 0 : CPLError(CE_Failure, CPLE_AppDefined,
7164 : "Syntax error in ALTER TABLE RENAME COLUMN command.\n"
7165 : "Was '%s'\n"
7166 : "Should be of form 'ALTER TABLE <layername> RENAME [COLUMN] "
7167 : "<columnname> TO <newname>'",
7168 : pszSQLCommand);
7169 0 : return OGRERR_FAILURE;
7170 : }
7171 :
7172 : /* -------------------------------------------------------------------- */
7173 : /* Find the named layer. */
7174 : /* -------------------------------------------------------------------- */
7175 2 : OGRLayer *poLayer = GetLayerByName(pszLayerName);
7176 2 : if (poLayer == nullptr)
7177 : {
7178 0 : CPLError(CE_Failure, CPLE_AppDefined,
7179 : "%s failed, no such layer as `%s'.", pszSQLCommand,
7180 : pszLayerName);
7181 0 : CSLDestroy(papszTokens);
7182 0 : return OGRERR_FAILURE;
7183 : }
7184 :
7185 : /* -------------------------------------------------------------------- */
7186 : /* Find the field. */
7187 : /* -------------------------------------------------------------------- */
7188 :
7189 : const int nFieldIndex =
7190 2 : poLayer->GetLayerDefn()->GetFieldIndex(pszOldColName);
7191 2 : if (nFieldIndex < 0)
7192 : {
7193 0 : CPLError(CE_Failure, CPLE_AppDefined,
7194 : "%s failed, no such field as `%s'.", pszSQLCommand,
7195 : pszOldColName);
7196 0 : CSLDestroy(papszTokens);
7197 0 : return OGRERR_FAILURE;
7198 : }
7199 :
7200 : /* -------------------------------------------------------------------- */
7201 : /* Rename column. */
7202 : /* -------------------------------------------------------------------- */
7203 : OGRFieldDefn *poOldFieldDefn =
7204 2 : poLayer->GetLayerDefn()->GetFieldDefn(nFieldIndex);
7205 4 : OGRFieldDefn oNewFieldDefn(poOldFieldDefn);
7206 2 : oNewFieldDefn.SetName(pszNewColName);
7207 :
7208 2 : CSLDestroy(papszTokens);
7209 :
7210 2 : return poLayer->AlterFieldDefn(nFieldIndex, &oNewFieldDefn,
7211 2 : ALTER_NAME_FLAG);
7212 : }
7213 :
7214 : /************************************************************************/
7215 : /* ProcessSQLAlterTableAlterColumn() */
7216 : /* */
7217 : /* The correct syntax for altering the type of a column in the */
7218 : /* OGR SQL dialect is: */
7219 : /* */
7220 : /* ALTER TABLE <layername> ALTER [COLUMN] <columnname> TYPE <newtype> */
7221 : /************************************************************************/
7222 :
7223 4 : OGRErr GDALDataset::ProcessSQLAlterTableAlterColumn(const char *pszSQLCommand)
7224 :
7225 : {
7226 4 : char **papszTokens = CSLTokenizeString(pszSQLCommand);
7227 :
7228 : /* -------------------------------------------------------------------- */
7229 : /* Do some general syntax checking. */
7230 : /* -------------------------------------------------------------------- */
7231 4 : const char *pszLayerName = nullptr;
7232 4 : const char *pszColumnName = nullptr;
7233 4 : int iTypeIndex = 0;
7234 4 : const int nTokens = CSLCount(papszTokens);
7235 :
7236 4 : if (nTokens >= 8 && EQUAL(papszTokens[0], "ALTER") &&
7237 2 : EQUAL(papszTokens[1], "TABLE") && EQUAL(papszTokens[3], "ALTER") &&
7238 2 : EQUAL(papszTokens[4], "COLUMN") && EQUAL(papszTokens[6], "TYPE"))
7239 : {
7240 2 : pszLayerName = papszTokens[2];
7241 2 : pszColumnName = papszTokens[5];
7242 2 : iTypeIndex = 7;
7243 : }
7244 2 : else if (nTokens >= 7 && EQUAL(papszTokens[0], "ALTER") &&
7245 2 : EQUAL(papszTokens[1], "TABLE") && EQUAL(papszTokens[3], "ALTER") &&
7246 2 : EQUAL(papszTokens[5], "TYPE"))
7247 : {
7248 2 : pszLayerName = papszTokens[2];
7249 2 : pszColumnName = papszTokens[4];
7250 2 : iTypeIndex = 6;
7251 : }
7252 : else
7253 : {
7254 0 : CSLDestroy(papszTokens);
7255 0 : CPLError(CE_Failure, CPLE_AppDefined,
7256 : "Syntax error in ALTER TABLE ALTER COLUMN command.\n"
7257 : "Was '%s'\n"
7258 : "Should be of form 'ALTER TABLE <layername> ALTER [COLUMN] "
7259 : "<columnname> TYPE <columntype>'",
7260 : pszSQLCommand);
7261 0 : return OGRERR_FAILURE;
7262 : }
7263 :
7264 : /* -------------------------------------------------------------------- */
7265 : /* Merge type components into a single string if there were split */
7266 : /* with spaces */
7267 : /* -------------------------------------------------------------------- */
7268 8 : CPLString osType;
7269 8 : for (int i = iTypeIndex; i < nTokens; ++i)
7270 : {
7271 4 : osType += papszTokens[i];
7272 4 : CPLFree(papszTokens[i]);
7273 : }
7274 4 : char *pszType = papszTokens[iTypeIndex] = CPLStrdup(osType);
7275 4 : papszTokens[iTypeIndex + 1] = nullptr;
7276 :
7277 : /* -------------------------------------------------------------------- */
7278 : /* Find the named layer. */
7279 : /* -------------------------------------------------------------------- */
7280 4 : OGRLayer *poLayer = GetLayerByName(pszLayerName);
7281 4 : if (poLayer == nullptr)
7282 : {
7283 0 : CPLError(CE_Failure, CPLE_AppDefined,
7284 : "%s failed, no such layer as `%s'.", pszSQLCommand,
7285 : pszLayerName);
7286 0 : CSLDestroy(papszTokens);
7287 0 : return OGRERR_FAILURE;
7288 : }
7289 :
7290 : /* -------------------------------------------------------------------- */
7291 : /* Find the field. */
7292 : /* -------------------------------------------------------------------- */
7293 :
7294 : const int nFieldIndex =
7295 4 : poLayer->GetLayerDefn()->GetFieldIndex(pszColumnName);
7296 4 : if (nFieldIndex < 0)
7297 : {
7298 0 : CPLError(CE_Failure, CPLE_AppDefined,
7299 : "%s failed, no such field as `%s'.", pszSQLCommand,
7300 : pszColumnName);
7301 0 : CSLDestroy(papszTokens);
7302 0 : return OGRERR_FAILURE;
7303 : }
7304 :
7305 : /* -------------------------------------------------------------------- */
7306 : /* Alter column. */
7307 : /* -------------------------------------------------------------------- */
7308 :
7309 : OGRFieldDefn *poOldFieldDefn =
7310 4 : poLayer->GetLayerDefn()->GetFieldDefn(nFieldIndex);
7311 8 : OGRFieldDefn oNewFieldDefn(poOldFieldDefn);
7312 :
7313 4 : int nWidth = 0;
7314 4 : int nPrecision = 0;
7315 4 : OGRFieldType eType = GDALDatasetParseSQLType(pszType, nWidth, nPrecision);
7316 4 : oNewFieldDefn.SetType(eType);
7317 4 : oNewFieldDefn.SetWidth(nWidth);
7318 4 : oNewFieldDefn.SetPrecision(nPrecision);
7319 :
7320 4 : int l_nFlags = 0;
7321 4 : if (poOldFieldDefn->GetType() != oNewFieldDefn.GetType())
7322 2 : l_nFlags |= ALTER_TYPE_FLAG;
7323 4 : if (poOldFieldDefn->GetWidth() != oNewFieldDefn.GetWidth() ||
7324 0 : poOldFieldDefn->GetPrecision() != oNewFieldDefn.GetPrecision())
7325 4 : l_nFlags |= ALTER_WIDTH_PRECISION_FLAG;
7326 :
7327 4 : CSLDestroy(papszTokens);
7328 :
7329 4 : if (l_nFlags == 0)
7330 0 : return OGRERR_NONE;
7331 :
7332 4 : return poLayer->AlterFieldDefn(nFieldIndex, &oNewFieldDefn, l_nFlags);
7333 : }
7334 :
7335 : //! @endcond
7336 :
7337 : /************************************************************************/
7338 : /* ExecuteSQL() */
7339 : /************************************************************************/
7340 :
7341 : /**
7342 : \brief Execute an SQL statement against the data store.
7343 :
7344 : The result of an SQL query is either NULL for statements that are in error,
7345 : or that have no results set, or an OGRLayer pointer representing a results
7346 : set from the query. Note that this OGRLayer is in addition to the layers
7347 : in the data store and must be destroyed with
7348 : ReleaseResultSet() before the dataset is closed
7349 : (destroyed).
7350 :
7351 : This method is the same as the C function GDALDatasetExecuteSQL() and the
7352 : deprecated OGR_DS_ExecuteSQL().
7353 :
7354 : For more information on the SQL dialect supported internally by OGR
7355 : review the <a href="https://gdal.org/user/ogr_sql_dialect.html">OGR SQL</a>
7356 : document. Some drivers (i.e. Oracle and PostGIS) pass the SQL directly through
7357 : to the underlying RDBMS.
7358 :
7359 : Starting with OGR 1.10, the <a
7360 : href="https://gdal.org/user/sql_sqlite_dialect.html">SQLITE dialect</a> can
7361 : also be used.
7362 :
7363 : @param pszStatement the SQL statement to execute.
7364 : @param poSpatialFilter geometry which represents a spatial filter. Can be NULL.
7365 : @param pszDialect allows control of the statement dialect. If set to NULL, the
7366 : OGR SQL engine will be used, except for RDBMS drivers that will use their
7367 : dedicated SQL engine, unless OGRSQL is explicitly passed as the
7368 : dialect. Starting with OGR 1.10, the SQLITE dialect can also be used.
7369 :
7370 : @return an OGRLayer containing the results of the query. Deallocate with
7371 : ReleaseResultSet().
7372 :
7373 : */
7374 :
7375 3589 : OGRLayer *GDALDataset::ExecuteSQL(const char *pszStatement,
7376 : OGRGeometry *poSpatialFilter,
7377 : const char *pszDialect)
7378 :
7379 : {
7380 3589 : return ExecuteSQL(pszStatement, poSpatialFilter, pszDialect, nullptr);
7381 : }
7382 :
7383 : //! @cond Doxygen_Suppress
7384 : OGRLayer *
7385 3597 : GDALDataset::ExecuteSQL(const char *pszStatement, OGRGeometry *poSpatialFilter,
7386 : const char *pszDialect,
7387 : swq_select_parse_options *poSelectParseOptions)
7388 :
7389 : {
7390 3597 : if (pszDialect != nullptr && EQUAL(pszDialect, "SQLite"))
7391 : {
7392 : #ifdef SQLITE_ENABLED
7393 650 : return OGRSQLiteExecuteSQL(this, pszStatement, poSpatialFilter,
7394 650 : pszDialect);
7395 : #else
7396 : CPLError(CE_Failure, CPLE_NotSupported,
7397 : "The SQLite driver needs to be compiled to support the "
7398 : "SQLite SQL dialect");
7399 : return nullptr;
7400 : #endif
7401 : }
7402 :
7403 2947 : if (pszDialect != nullptr && !EQUAL(pszDialect, "") &&
7404 14 : !EQUAL(pszDialect, "OGRSQL"))
7405 : {
7406 6 : std::string osDialectList = "'OGRSQL'";
7407 : #ifdef SQLITE_ENABLED
7408 3 : osDialectList += ", 'SQLITE'";
7409 : #endif
7410 : const char *pszDialects =
7411 3 : GetMetadataItem(GDAL_DMD_SUPPORTED_SQL_DIALECTS);
7412 3 : if (pszDialects)
7413 : {
7414 : const CPLStringList aosTokens(
7415 0 : CSLTokenizeString2(pszDialects, " ", 0));
7416 0 : for (int i = 0; i < aosTokens.size(); ++i)
7417 : {
7418 0 : if (!EQUAL(aosTokens[i], "OGRSQL") &&
7419 0 : !EQUAL(aosTokens[i], "SQLITE"))
7420 : {
7421 0 : osDialectList += ", '";
7422 0 : osDialectList += aosTokens[i];
7423 0 : osDialectList += "'";
7424 : }
7425 : }
7426 : }
7427 3 : CPLError(CE_Warning, CPLE_NotSupported,
7428 : "Dialect '%s' is unsupported. Only supported dialects are %s. "
7429 : "Defaulting to OGRSQL",
7430 : pszDialect, osDialectList.c_str());
7431 : }
7432 :
7433 : /* -------------------------------------------------------------------- */
7434 : /* Handle CREATE INDEX statements specially. */
7435 : /* -------------------------------------------------------------------- */
7436 2947 : if (STARTS_WITH_CI(pszStatement, "CREATE INDEX"))
7437 : {
7438 28 : ProcessSQLCreateIndex(pszStatement);
7439 28 : return nullptr;
7440 : }
7441 :
7442 : /* -------------------------------------------------------------------- */
7443 : /* Handle DROP INDEX statements specially. */
7444 : /* -------------------------------------------------------------------- */
7445 2919 : if (STARTS_WITH_CI(pszStatement, "DROP INDEX"))
7446 : {
7447 10 : ProcessSQLDropIndex(pszStatement);
7448 10 : return nullptr;
7449 : }
7450 :
7451 : /* -------------------------------------------------------------------- */
7452 : /* Handle DROP TABLE statements specially. */
7453 : /* -------------------------------------------------------------------- */
7454 2909 : if (STARTS_WITH_CI(pszStatement, "DROP TABLE"))
7455 : {
7456 500 : ProcessSQLDropTable(pszStatement);
7457 500 : return nullptr;
7458 : }
7459 :
7460 : /* -------------------------------------------------------------------- */
7461 : /* Handle ALTER TABLE statements specially. */
7462 : /* -------------------------------------------------------------------- */
7463 2409 : if (STARTS_WITH_CI(pszStatement, "ALTER TABLE"))
7464 : {
7465 11 : char **papszTokens = CSLTokenizeString(pszStatement);
7466 11 : const int nTokens = CSLCount(papszTokens);
7467 11 : if (nTokens >= 4 && EQUAL(papszTokens[3], "ADD"))
7468 : {
7469 2 : ProcessSQLAlterTableAddColumn(pszStatement);
7470 2 : CSLDestroy(papszTokens);
7471 2 : return nullptr;
7472 : }
7473 9 : else if (nTokens >= 4 && EQUAL(papszTokens[3], "DROP"))
7474 : {
7475 2 : ProcessSQLAlterTableDropColumn(pszStatement);
7476 2 : CSLDestroy(papszTokens);
7477 2 : return nullptr;
7478 : }
7479 7 : else if (nTokens == 6 && EQUAL(papszTokens[3], "RENAME") &&
7480 1 : EQUAL(papszTokens[4], "TO"))
7481 : {
7482 1 : const char *pszSrcTableName = papszTokens[2];
7483 1 : const char *pszDstTableName = papszTokens[5];
7484 1 : auto poSrcLayer = GetLayerByName(pszSrcTableName);
7485 1 : if (poSrcLayer)
7486 : {
7487 1 : CPL_IGNORE_RET_VAL(poSrcLayer->Rename(pszDstTableName));
7488 : }
7489 : else
7490 : {
7491 0 : CPLError(CE_Failure, CPLE_AppDefined, "Invalid layer name");
7492 : }
7493 1 : CSLDestroy(papszTokens);
7494 1 : return nullptr;
7495 : }
7496 6 : else if (nTokens >= 4 && EQUAL(papszTokens[3], "RENAME"))
7497 : {
7498 2 : ProcessSQLAlterTableRenameColumn(pszStatement);
7499 2 : CSLDestroy(papszTokens);
7500 2 : return nullptr;
7501 : }
7502 4 : else if (nTokens >= 4 && EQUAL(papszTokens[3], "ALTER"))
7503 : {
7504 4 : ProcessSQLAlterTableAlterColumn(pszStatement);
7505 4 : CSLDestroy(papszTokens);
7506 4 : return nullptr;
7507 : }
7508 : else
7509 : {
7510 0 : CPLError(CE_Failure, CPLE_AppDefined,
7511 : "Unsupported ALTER TABLE command : %s", pszStatement);
7512 0 : CSLDestroy(papszTokens);
7513 0 : return nullptr;
7514 : }
7515 : }
7516 :
7517 : /* -------------------------------------------------------------------- */
7518 : /* Preparse the SQL statement. */
7519 : /* -------------------------------------------------------------------- */
7520 2398 : swq_select *psSelectInfo = new swq_select();
7521 2398 : swq_custom_func_registrar *poCustomFuncRegistrar = nullptr;
7522 2398 : if (poSelectParseOptions != nullptr)
7523 8 : poCustomFuncRegistrar = poSelectParseOptions->poCustomFuncRegistrar;
7524 2398 : if (psSelectInfo->preparse(pszStatement,
7525 2398 : poCustomFuncRegistrar != nullptr) != CE_None)
7526 : {
7527 145 : delete psSelectInfo;
7528 145 : return nullptr;
7529 : }
7530 :
7531 : /* -------------------------------------------------------------------- */
7532 : /* If there is no UNION ALL, build result layer. */
7533 : /* -------------------------------------------------------------------- */
7534 2253 : if (psSelectInfo->poOtherSelect == nullptr)
7535 : {
7536 2247 : return BuildLayerFromSelectInfo(psSelectInfo, poSpatialFilter,
7537 2247 : pszDialect, poSelectParseOptions);
7538 : }
7539 :
7540 : /* -------------------------------------------------------------------- */
7541 : /* Build result union layer. */
7542 : /* -------------------------------------------------------------------- */
7543 6 : int nSrcLayers = 0;
7544 6 : OGRLayer **papoSrcLayers = nullptr;
7545 :
7546 6 : do
7547 : {
7548 12 : swq_select *psNextSelectInfo = psSelectInfo->poOtherSelect;
7549 12 : psSelectInfo->poOtherSelect = nullptr;
7550 :
7551 12 : OGRLayer *poLayer = BuildLayerFromSelectInfo(
7552 : psSelectInfo, poSpatialFilter, pszDialect, poSelectParseOptions);
7553 12 : if (poLayer == nullptr)
7554 : {
7555 : // Each source layer owns an independent select info.
7556 0 : for (int i = 0; i < nSrcLayers; ++i)
7557 0 : delete papoSrcLayers[i];
7558 0 : CPLFree(papoSrcLayers);
7559 :
7560 : // So we just have to destroy the remaining select info.
7561 0 : delete psNextSelectInfo;
7562 :
7563 0 : return nullptr;
7564 : }
7565 : else
7566 : {
7567 24 : papoSrcLayers = static_cast<OGRLayer **>(CPLRealloc(
7568 12 : papoSrcLayers, sizeof(OGRLayer *) * (nSrcLayers + 1)));
7569 12 : papoSrcLayers[nSrcLayers] = poLayer;
7570 12 : ++nSrcLayers;
7571 :
7572 12 : psSelectInfo = psNextSelectInfo;
7573 : }
7574 12 : } while (psSelectInfo != nullptr);
7575 :
7576 6 : return new OGRUnionLayer("SELECT", nSrcLayers, papoSrcLayers, TRUE);
7577 : }
7578 :
7579 : //! @endcond
7580 :
7581 : /************************************************************************/
7582 : /* AbortSQL() */
7583 : /************************************************************************/
7584 :
7585 : /**
7586 : \brief Abort any SQL statement running in the data store.
7587 :
7588 : This function can be safely called from any thread (pending that the dataset
7589 : object is still alive). Driver implementations will make sure that it can be
7590 : called in a thread-safe way.
7591 :
7592 : This might not be implemented by all drivers. At time of writing, only SQLite,
7593 : GPKG and PG drivers implement it
7594 :
7595 : This method is the same as the C method GDALDatasetAbortSQL()
7596 :
7597 : @since GDAL 3.2.0
7598 :
7599 :
7600 : */
7601 :
7602 0 : OGRErr GDALDataset::AbortSQL()
7603 : {
7604 0 : CPLError(CE_Failure, CPLE_NotSupported,
7605 : "AbortSQL is not supported for this driver.");
7606 0 : return OGRERR_UNSUPPORTED_OPERATION;
7607 : }
7608 :
7609 : /************************************************************************/
7610 : /* BuildLayerFromSelectInfo() */
7611 : /************************************************************************/
7612 :
7613 : struct GDALSQLParseInfo
7614 : {
7615 : swq_field_list sFieldList;
7616 : int nExtraDSCount;
7617 : GDALDataset **papoExtraDS;
7618 : char *pszWHERE;
7619 : };
7620 :
7621 2259 : OGRLayer *GDALDataset::BuildLayerFromSelectInfo(
7622 : swq_select *psSelectInfo, OGRGeometry *poSpatialFilter,
7623 : const char *pszDialect, swq_select_parse_options *poSelectParseOptions)
7624 : {
7625 4518 : std::unique_ptr<swq_select> psSelectInfoUnique(psSelectInfo);
7626 :
7627 2259 : std::unique_ptr<OGRGenSQLResultsLayer> poResults;
7628 : GDALSQLParseInfo *psParseInfo =
7629 2259 : BuildParseInfo(psSelectInfoUnique.get(), poSelectParseOptions);
7630 :
7631 2259 : if (psParseInfo)
7632 : {
7633 2224 : const auto nErrorCounter = CPLGetErrorCounter();
7634 4448 : poResults = std::make_unique<OGRGenSQLResultsLayer>(
7635 2224 : this, std::move(psSelectInfoUnique), poSpatialFilter,
7636 4448 : psParseInfo->pszWHERE, pszDialect);
7637 2301 : if (CPLGetErrorCounter() > nErrorCounter &&
7638 77 : CPLGetLastErrorType() != CE_None)
7639 77 : poResults.reset();
7640 : }
7641 :
7642 2259 : DestroyParseInfo(psParseInfo);
7643 :
7644 4518 : return poResults.release();
7645 : }
7646 :
7647 : /************************************************************************/
7648 : /* DestroyParseInfo() */
7649 : /************************************************************************/
7650 :
7651 : //! @cond Doxygen_Suppress
7652 2328 : void GDALDataset::DestroyParseInfo(GDALSQLParseInfo *psParseInfo)
7653 : {
7654 2328 : if (psParseInfo == nullptr)
7655 35 : return;
7656 :
7657 2293 : CPLFree(psParseInfo->sFieldList.names);
7658 2293 : CPLFree(psParseInfo->sFieldList.types);
7659 2293 : CPLFree(psParseInfo->sFieldList.table_ids);
7660 2293 : CPLFree(psParseInfo->sFieldList.ids);
7661 :
7662 : // Release the datasets we have opened with OGROpenShared()
7663 : // It is safe to do that as the 'new OGRGenSQLResultsLayer' itself
7664 : // has taken a reference on them, which it will release in its
7665 : // destructor.
7666 2300 : for (int iEDS = 0; iEDS < psParseInfo->nExtraDSCount; ++iEDS)
7667 7 : GDALClose(psParseInfo->papoExtraDS[iEDS]);
7668 :
7669 2293 : CPLFree(psParseInfo->papoExtraDS);
7670 2293 : CPLFree(psParseInfo->pszWHERE);
7671 2293 : CPLFree(psParseInfo);
7672 : }
7673 :
7674 : /************************************************************************/
7675 : /* BuildParseInfo() */
7676 : /************************************************************************/
7677 :
7678 : GDALSQLParseInfo *
7679 2293 : GDALDataset::BuildParseInfo(swq_select *psSelectInfo,
7680 : swq_select_parse_options *poSelectParseOptions)
7681 : {
7682 2293 : int nFirstLayerFirstSpecialFieldIndex = 0;
7683 :
7684 : GDALSQLParseInfo *psParseInfo =
7685 2293 : static_cast<GDALSQLParseInfo *>(CPLCalloc(1, sizeof(GDALSQLParseInfo)));
7686 :
7687 : /* -------------------------------------------------------------------- */
7688 : /* Validate that all the source tables are recognized, count */
7689 : /* fields. */
7690 : /* -------------------------------------------------------------------- */
7691 2293 : int nFieldCount = 0;
7692 :
7693 4654 : for (int iTable = 0; iTable < psSelectInfo->table_count; iTable++)
7694 : {
7695 2364 : swq_table_def *psTableDef = psSelectInfo->table_defs + iTable;
7696 2364 : GDALDataset *poTableDS = this;
7697 :
7698 2364 : if (psTableDef->data_source != nullptr)
7699 : {
7700 7 : poTableDS = GDALDataset::FromHandle(
7701 7 : OGROpenShared(psTableDef->data_source, FALSE, nullptr));
7702 7 : if (poTableDS == nullptr)
7703 : {
7704 0 : if (strlen(CPLGetLastErrorMsg()) == 0)
7705 0 : CPLError(CE_Failure, CPLE_AppDefined,
7706 : "Unable to open secondary datasource "
7707 : "`%s' required by JOIN.",
7708 : psTableDef->data_source);
7709 :
7710 0 : DestroyParseInfo(psParseInfo);
7711 0 : return nullptr;
7712 : }
7713 :
7714 : // Keep in an array to release at the end of this function.
7715 14 : psParseInfo->papoExtraDS = static_cast<GDALDataset **>(CPLRealloc(
7716 7 : psParseInfo->papoExtraDS,
7717 7 : sizeof(GDALDataset *) * (psParseInfo->nExtraDSCount + 1)));
7718 7 : psParseInfo->papoExtraDS[psParseInfo->nExtraDSCount++] = poTableDS;
7719 : }
7720 :
7721 : OGRLayer *poSrcLayer =
7722 2364 : poTableDS->GetLayerByName(psTableDef->table_name);
7723 :
7724 2364 : if (poSrcLayer == nullptr)
7725 : {
7726 3 : CPLError(CE_Failure, CPLE_AppDefined,
7727 : "SELECT from table %s failed, no such table/featureclass.",
7728 : psTableDef->table_name);
7729 :
7730 3 : DestroyParseInfo(psParseInfo);
7731 3 : return nullptr;
7732 : }
7733 :
7734 2361 : nFieldCount += poSrcLayer->GetLayerDefn()->GetFieldCount();
7735 2361 : if (iTable == 0 ||
7736 34 : (poSelectParseOptions &&
7737 34 : poSelectParseOptions->bAddSecondaryTablesGeometryFields))
7738 2324 : nFieldCount += poSrcLayer->GetLayerDefn()->GetGeomFieldCount();
7739 :
7740 2361 : const char *pszFID = poSrcLayer->GetFIDColumn();
7741 2972 : if (pszFID && !EQUAL(pszFID, "") && !EQUAL(pszFID, "FID") &&
7742 611 : poSrcLayer->GetLayerDefn()->GetFieldIndex(pszFID) < 0)
7743 561 : nFieldCount++;
7744 : }
7745 :
7746 : /* -------------------------------------------------------------------- */
7747 : /* Build the field list for all indicated tables. */
7748 : /* -------------------------------------------------------------------- */
7749 :
7750 2290 : psParseInfo->sFieldList.table_count = psSelectInfo->table_count;
7751 2290 : psParseInfo->sFieldList.table_defs = psSelectInfo->table_defs;
7752 :
7753 2290 : psParseInfo->sFieldList.count = 0;
7754 2290 : psParseInfo->sFieldList.names = static_cast<char **>(
7755 2290 : CPLMalloc(sizeof(char *) * (nFieldCount + SPECIAL_FIELD_COUNT)));
7756 4580 : psParseInfo->sFieldList.types = static_cast<swq_field_type *>(CPLMalloc(
7757 2290 : sizeof(swq_field_type) * (nFieldCount + SPECIAL_FIELD_COUNT)));
7758 2290 : psParseInfo->sFieldList.table_ids = static_cast<int *>(
7759 2290 : CPLMalloc(sizeof(int) * (nFieldCount + SPECIAL_FIELD_COUNT)));
7760 2290 : psParseInfo->sFieldList.ids = static_cast<int *>(
7761 2290 : CPLMalloc(sizeof(int) * (nFieldCount + SPECIAL_FIELD_COUNT)));
7762 :
7763 2290 : bool bIsFID64 = false;
7764 4651 : for (int iTable = 0; iTable < psSelectInfo->table_count; iTable++)
7765 : {
7766 2361 : swq_table_def *psTableDef = psSelectInfo->table_defs + iTable;
7767 2361 : GDALDataset *poTableDS = this;
7768 :
7769 2361 : if (psTableDef->data_source != nullptr)
7770 : {
7771 7 : poTableDS = GDALDataset::FromHandle(
7772 7 : OGROpenShared(psTableDef->data_source, FALSE, nullptr));
7773 7 : CPLAssert(poTableDS != nullptr);
7774 7 : poTableDS->Dereference();
7775 : }
7776 :
7777 : OGRLayer *poSrcLayer =
7778 2361 : poTableDS->GetLayerByName(psTableDef->table_name);
7779 :
7780 2361 : for (int iField = 0;
7781 18588 : iField < poSrcLayer->GetLayerDefn()->GetFieldCount(); iField++)
7782 : {
7783 : OGRFieldDefn *poFDefn =
7784 16227 : poSrcLayer->GetLayerDefn()->GetFieldDefn(iField);
7785 16227 : const int iOutField = psParseInfo->sFieldList.count++;
7786 32454 : psParseInfo->sFieldList.names[iOutField] =
7787 16227 : const_cast<char *>(poFDefn->GetNameRef());
7788 16227 : if (poFDefn->GetType() == OFTInteger)
7789 : {
7790 4089 : if (poFDefn->GetSubType() == OFSTBoolean)
7791 160 : psParseInfo->sFieldList.types[iOutField] = SWQ_BOOLEAN;
7792 : else
7793 3929 : psParseInfo->sFieldList.types[iOutField] = SWQ_INTEGER;
7794 : }
7795 12138 : else if (poFDefn->GetType() == OFTInteger64)
7796 : {
7797 760 : if (poFDefn->GetSubType() == OFSTBoolean)
7798 0 : psParseInfo->sFieldList.types[iOutField] = SWQ_BOOLEAN;
7799 : else
7800 760 : psParseInfo->sFieldList.types[iOutField] = SWQ_INTEGER64;
7801 : }
7802 11378 : else if (poFDefn->GetType() == OFTReal)
7803 2723 : psParseInfo->sFieldList.types[iOutField] = SWQ_FLOAT;
7804 8655 : else if (poFDefn->GetType() == OFTString)
7805 5601 : psParseInfo->sFieldList.types[iOutField] = SWQ_STRING;
7806 3054 : else if (poFDefn->GetType() == OFTTime)
7807 83 : psParseInfo->sFieldList.types[iOutField] = SWQ_TIME;
7808 2971 : else if (poFDefn->GetType() == OFTDate)
7809 143 : psParseInfo->sFieldList.types[iOutField] = SWQ_DATE;
7810 2828 : else if (poFDefn->GetType() == OFTDateTime)
7811 939 : psParseInfo->sFieldList.types[iOutField] = SWQ_TIMESTAMP;
7812 : else
7813 1889 : psParseInfo->sFieldList.types[iOutField] = SWQ_OTHER;
7814 :
7815 16227 : psParseInfo->sFieldList.table_ids[iOutField] = iTable;
7816 16227 : psParseInfo->sFieldList.ids[iOutField] = iField;
7817 : }
7818 :
7819 2361 : if (iTable == 0)
7820 : {
7821 2290 : nFirstLayerFirstSpecialFieldIndex = psParseInfo->sFieldList.count;
7822 : }
7823 :
7824 2361 : if (iTable == 0 ||
7825 34 : (poSelectParseOptions &&
7826 34 : poSelectParseOptions->bAddSecondaryTablesGeometryFields))
7827 : {
7828 :
7829 2324 : for (int iField = 0;
7830 4297 : iField < poSrcLayer->GetLayerDefn()->GetGeomFieldCount();
7831 : iField++)
7832 : {
7833 : OGRGeomFieldDefn *poFDefn =
7834 1973 : poSrcLayer->GetLayerDefn()->GetGeomFieldDefn(iField);
7835 1973 : const int iOutField = psParseInfo->sFieldList.count++;
7836 3946 : psParseInfo->sFieldList.names[iOutField] =
7837 1973 : const_cast<char *>(poFDefn->GetNameRef());
7838 1973 : if (*psParseInfo->sFieldList.names[iOutField] == '\0')
7839 1153 : psParseInfo->sFieldList.names[iOutField] =
7840 : const_cast<char *>(OGR_GEOMETRY_DEFAULT_NON_EMPTY_NAME);
7841 1973 : psParseInfo->sFieldList.types[iOutField] = SWQ_GEOMETRY;
7842 :
7843 1973 : psParseInfo->sFieldList.table_ids[iOutField] = iTable;
7844 1973 : psParseInfo->sFieldList.ids[iOutField] =
7845 1973 : GEOM_FIELD_INDEX_TO_ALL_FIELD_INDEX(
7846 : poSrcLayer->GetLayerDefn(), iField);
7847 : }
7848 : }
7849 :
7850 2362 : if (iTable == 0 && poSrcLayer->GetMetadataItem(OLMD_FID64) != nullptr &&
7851 1 : EQUAL(poSrcLayer->GetMetadataItem(OLMD_FID64), "YES"))
7852 : {
7853 1 : bIsFID64 = true;
7854 : }
7855 : }
7856 :
7857 : /* -------------------------------------------------------------------- */
7858 : /* Expand '*' in 'SELECT *' now before we add the pseudo fields */
7859 : /* -------------------------------------------------------------------- */
7860 2290 : const bool bAlwaysPrefixWithTableName =
7861 2332 : poSelectParseOptions &&
7862 42 : poSelectParseOptions->bAlwaysPrefixWithTableName;
7863 2290 : if (psSelectInfo->expand_wildcard(&psParseInfo->sFieldList,
7864 2290 : bAlwaysPrefixWithTableName) != CE_None)
7865 : {
7866 2 : DestroyParseInfo(psParseInfo);
7867 2 : return nullptr;
7868 : }
7869 :
7870 13728 : for (int iField = 0; iField < SPECIAL_FIELD_COUNT; iField++)
7871 : {
7872 11440 : psParseInfo->sFieldList.names[psParseInfo->sFieldList.count] =
7873 11440 : const_cast<char *>(SpecialFieldNames[iField]);
7874 11440 : psParseInfo->sFieldList.types[psParseInfo->sFieldList.count] =
7875 11440 : (iField == SPF_FID && bIsFID64) ? SWQ_INTEGER64
7876 : : SpecialFieldTypes[iField];
7877 11440 : psParseInfo->sFieldList.table_ids[psParseInfo->sFieldList.count] = 0;
7878 11440 : psParseInfo->sFieldList.ids[psParseInfo->sFieldList.count] =
7879 11440 : nFirstLayerFirstSpecialFieldIndex + iField;
7880 11440 : psParseInfo->sFieldList.count++;
7881 : }
7882 :
7883 : /* In the case a layer has an explicit FID column name, then add it */
7884 : /* so it can be selected */
7885 4647 : for (int iTable = 0; iTable < psSelectInfo->table_count; iTable++)
7886 : {
7887 2359 : swq_table_def *psTableDef = psSelectInfo->table_defs + iTable;
7888 2359 : GDALDataset *poTableDS = this;
7889 :
7890 2359 : if (psTableDef->data_source != nullptr)
7891 : {
7892 7 : poTableDS = GDALDataset::FromHandle(
7893 7 : OGROpenShared(psTableDef->data_source, FALSE, nullptr));
7894 7 : CPLAssert(poTableDS != nullptr);
7895 7 : poTableDS->Dereference();
7896 : }
7897 :
7898 : OGRLayer *poSrcLayer =
7899 2359 : poTableDS->GetLayerByName(psTableDef->table_name);
7900 :
7901 2359 : const char *pszFID = poSrcLayer->GetFIDColumn();
7902 2970 : if (pszFID && !EQUAL(pszFID, "") && !EQUAL(pszFID, "FID") &&
7903 611 : poSrcLayer->GetLayerDefn()->GetFieldIndex(pszFID) < 0)
7904 : {
7905 561 : const int iOutField = psParseInfo->sFieldList.count++;
7906 561 : psParseInfo->sFieldList.names[iOutField] =
7907 : const_cast<char *>(pszFID);
7908 561 : if (poSrcLayer->GetMetadataItem(OLMD_FID64) != nullptr &&
7909 0 : EQUAL(poSrcLayer->GetMetadataItem(OLMD_FID64), "YES"))
7910 : {
7911 0 : psParseInfo->sFieldList.types[iOutField] = SWQ_INTEGER64;
7912 : }
7913 : else
7914 : {
7915 561 : psParseInfo->sFieldList.types[iOutField] = SWQ_INTEGER;
7916 : }
7917 561 : psParseInfo->sFieldList.table_ids[iOutField] = iTable;
7918 1122 : psParseInfo->sFieldList.ids[iOutField] =
7919 561 : poSrcLayer->GetLayerDefn()->GetFieldCount() + SPF_FID;
7920 : }
7921 : }
7922 :
7923 : /* -------------------------------------------------------------------- */
7924 : /* Finish the parse operation. */
7925 : /* -------------------------------------------------------------------- */
7926 2288 : if (psSelectInfo->parse(&psParseInfo->sFieldList, poSelectParseOptions) !=
7927 : CE_None)
7928 : {
7929 30 : DestroyParseInfo(psParseInfo);
7930 30 : return nullptr;
7931 : }
7932 :
7933 : /* -------------------------------------------------------------------- */
7934 : /* Extract the WHERE expression to use separately. */
7935 : /* -------------------------------------------------------------------- */
7936 2258 : if (psSelectInfo->where_expr != nullptr)
7937 : {
7938 967 : psParseInfo->pszWHERE =
7939 967 : psSelectInfo->where_expr->Unparse(&psParseInfo->sFieldList, '"');
7940 : // CPLDebug( "OGR", "Unparse() -> %s", pszWHERE );
7941 : }
7942 :
7943 2258 : return psParseInfo;
7944 : }
7945 :
7946 : //! @endcond
7947 :
7948 : /************************************************************************/
7949 : /* ReleaseResultSet() */
7950 : /************************************************************************/
7951 :
7952 : /**
7953 : \brief Release results of ExecuteSQL().
7954 :
7955 : This method should only be used to deallocate OGRLayers resulting from
7956 : an ExecuteSQL() call on the same GDALDataset. Failure to deallocate a
7957 : results set before destroying the GDALDataset may cause errors.
7958 :
7959 : This method is the same as the C function GDALDatasetReleaseResultSet() and the
7960 : deprecated OGR_DS_ReleaseResultSet().
7961 :
7962 : @param poResultsSet the result of a previous ExecuteSQL() call.
7963 : */
7964 :
7965 2174 : void GDALDataset::ReleaseResultSet(OGRLayer *poResultsSet)
7966 :
7967 : {
7968 2174 : delete poResultsSet;
7969 2174 : }
7970 :
7971 : /************************************************************************/
7972 : /* GetStyleTable() */
7973 : /************************************************************************/
7974 :
7975 : /**
7976 : \brief Returns dataset style table.
7977 :
7978 : This method is the same as the C function GDALDatasetGetStyleTable() and the
7979 : deprecated OGR_DS_GetStyleTable().
7980 :
7981 : @return pointer to a style table which should not be modified or freed by the
7982 : caller.
7983 : */
7984 :
7985 955 : OGRStyleTable *GDALDataset::GetStyleTable()
7986 : {
7987 955 : return m_poStyleTable;
7988 : }
7989 :
7990 : /************************************************************************/
7991 : /* SetStyleTableDirectly() */
7992 : /************************************************************************/
7993 :
7994 : /**
7995 : \brief Set dataset style table.
7996 :
7997 : This method operate exactly as SetStyleTable() except that it
7998 : assumes ownership of the passed table.
7999 :
8000 : This method is the same as the C function GDALDatasetSetStyleTableDirectly()
8001 : and the deprecated OGR_DS_SetStyleTableDirectly().
8002 :
8003 : @param poStyleTable pointer to style table to set
8004 :
8005 : */
8006 0 : void GDALDataset::SetStyleTableDirectly(OGRStyleTable *poStyleTable)
8007 : {
8008 0 : if (m_poStyleTable)
8009 0 : delete m_poStyleTable;
8010 0 : m_poStyleTable = poStyleTable;
8011 0 : }
8012 :
8013 : /************************************************************************/
8014 : /* SetStyleTable() */
8015 : /************************************************************************/
8016 :
8017 : /**
8018 : \brief Set dataset style table.
8019 :
8020 : This method operate exactly as SetStyleTableDirectly() except
8021 : that it does not assume ownership of the passed table.
8022 :
8023 : This method is the same as the C function GDALDatasetSetStyleTable() and the
8024 : deprecated OGR_DS_SetStyleTable().
8025 :
8026 : @param poStyleTable pointer to style table to set
8027 :
8028 : */
8029 :
8030 951 : void GDALDataset::SetStyleTable(OGRStyleTable *poStyleTable)
8031 : {
8032 951 : if (m_poStyleTable)
8033 0 : delete m_poStyleTable;
8034 951 : if (poStyleTable)
8035 1 : m_poStyleTable = poStyleTable->Clone();
8036 951 : }
8037 :
8038 : /************************************************************************/
8039 : /* IsGenericSQLDialect() */
8040 : /************************************************************************/
8041 :
8042 : //! @cond Doxygen_Suppress
8043 1780 : int GDALDataset::IsGenericSQLDialect(const char *pszDialect)
8044 : {
8045 3252 : return pszDialect != nullptr &&
8046 3252 : (EQUAL(pszDialect, "OGRSQL") || EQUAL(pszDialect, "SQLITE"));
8047 : }
8048 :
8049 : //! @endcond
8050 :
8051 : /************************************************************************/
8052 : /* GetLayerCount() */
8053 : /************************************************************************/
8054 :
8055 : /**
8056 : \brief Get the number of layers in this dataset.
8057 :
8058 : This method is the same as the C function GDALDatasetGetLayerCount(),
8059 : and the deprecated OGR_DS_GetLayerCount().
8060 :
8061 : Note that even if this method is const, there is no guarantee it can be
8062 : safely called by concurrent threads on the same GDALDataset object.
8063 :
8064 : @return layer count.
8065 : */
8066 :
8067 121301 : int GDALDataset::GetLayerCount() const
8068 : {
8069 121301 : return 0;
8070 : }
8071 :
8072 : /************************************************************************/
8073 : /* GetLayer() */
8074 : /************************************************************************/
8075 :
8076 : /**
8077 : \fn const GDALDataset::GetLayer(int) const
8078 : \brief Fetch a layer by index.
8079 :
8080 : The returned layer remains owned by the
8081 : GDALDataset and should not be deleted by the application.
8082 :
8083 : Note that even if this method is const, there is no guarantee it can be
8084 : safely called by concurrent threads on the same GDALDataset object.
8085 :
8086 : See GetLayers() for a C++ iterator version of this method.
8087 :
8088 : This method is the same as the C function GDALDatasetGetLayer() and the
8089 : deprecated OGR_DS_GetLayer().
8090 :
8091 : @param iLayer a layer number between 0 and GetLayerCount()-1.
8092 :
8093 : @return the layer, or NULL if iLayer is out of range or an error occurs.
8094 :
8095 : @see GetLayers()
8096 :
8097 : @since GDAL 3.12
8098 : */
8099 :
8100 0 : const OGRLayer *GDALDataset::GetLayer(CPL_UNUSED int iLayer) const
8101 : {
8102 0 : return nullptr;
8103 : }
8104 :
8105 : /**
8106 : \fn GDALDataset::GetLayer(int)
8107 : \brief Fetch a layer by index.
8108 :
8109 : The returned layer remains owned by the
8110 : GDALDataset and should not be deleted by the application.
8111 :
8112 : See GetLayers() for a C++ iterator version of this method.
8113 :
8114 : This method is the same as the C function GDALDatasetGetLayer() and the
8115 : deprecated OGR_DS_GetLayer().
8116 :
8117 : @param iLayer a layer number between 0 and GetLayerCount()-1.
8118 :
8119 : @return the layer, or NULL if iLayer is out of range or an error occurs.
8120 :
8121 : @see GetLayers()
8122 : */
8123 :
8124 : /************************************************************************/
8125 : /* IsLayerPrivate() */
8126 : /************************************************************************/
8127 :
8128 : /**
8129 : \fn GDALDataset::IsLayerPrivate(int)
8130 : \brief Returns true if the layer at the specified index is deemed a private or
8131 : system table, or an internal detail only.
8132 :
8133 : This method is the same as the C function GDALDatasetIsLayerPrivate().
8134 :
8135 : @param iLayer a layer number between 0 and GetLayerCount()-1.
8136 :
8137 : @return true if the layer is a private or system table.
8138 :
8139 : @since GDAL 3.4
8140 : */
8141 :
8142 975 : bool GDALDataset::IsLayerPrivate(CPL_UNUSED int iLayer) const
8143 : {
8144 975 : return false;
8145 : }
8146 :
8147 : /************************************************************************/
8148 : /* ResetReading() */
8149 : /************************************************************************/
8150 :
8151 : /**
8152 : \brief Reset feature reading to start on the first feature.
8153 :
8154 : This affects GetNextFeature().
8155 :
8156 : Depending on drivers, this may also have the side effect of calling
8157 : OGRLayer::ResetReading() on the layers of this dataset.
8158 :
8159 : This method is the same as the C function GDALDatasetResetReading().
8160 :
8161 : */
8162 7 : void GDALDataset::ResetReading()
8163 : {
8164 7 : if (!m_poPrivate)
8165 0 : return;
8166 7 : m_poPrivate->nCurrentLayerIdx = 0;
8167 7 : m_poPrivate->nLayerCount = -1;
8168 7 : m_poPrivate->poCurrentLayer = nullptr;
8169 7 : m_poPrivate->nFeatureReadInLayer = 0;
8170 7 : m_poPrivate->nFeatureReadInDataset = 0;
8171 7 : m_poPrivate->nTotalFeaturesInLayer = TOTAL_FEATURES_NOT_INIT;
8172 7 : m_poPrivate->nTotalFeatures = TOTAL_FEATURES_NOT_INIT;
8173 : }
8174 :
8175 : /************************************************************************/
8176 : /* GDALDatasetResetReading() */
8177 : /************************************************************************/
8178 :
8179 : /**
8180 : \brief Reset feature reading to start on the first feature.
8181 :
8182 : This affects GDALDatasetGetNextFeature().
8183 :
8184 : Depending on drivers, this may also have the side effect of calling
8185 : OGR_L_ResetReading() on the layers of this dataset.
8186 :
8187 : This method is the same as the C++ method GDALDataset::ResetReading()
8188 :
8189 : @param hDS dataset handle
8190 : */
8191 14 : void CPL_DLL GDALDatasetResetReading(GDALDatasetH hDS)
8192 : {
8193 14 : VALIDATE_POINTER0(hDS, "GDALDatasetResetReading");
8194 :
8195 14 : return GDALDataset::FromHandle(hDS)->ResetReading();
8196 : }
8197 :
8198 : /************************************************************************/
8199 : /* GetNextFeature() */
8200 : /************************************************************************/
8201 :
8202 : /**
8203 : \brief Fetch the next available feature from this dataset.
8204 :
8205 : This method is intended for the few drivers where OGRLayer::GetNextFeature()
8206 : is not efficient, but in general OGRLayer::GetNextFeature() is a more
8207 : natural API.
8208 :
8209 : See GetFeatures() for a C++ iterator version of this method.
8210 :
8211 : The returned feature becomes the responsibility of the caller to
8212 : delete with OGRFeature::DestroyFeature().
8213 :
8214 : Depending on the driver, this method may return features from layers in a
8215 : non sequential way. This is what may happen when the
8216 : ODsCRandomLayerRead capability is declared (for example for the
8217 : OSM and GMLAS drivers). When datasets declare this capability, it is strongly
8218 : advised to use GDALDataset::GetNextFeature() instead of
8219 : OGRLayer::GetNextFeature(), as the later might have a slow, incomplete or stub
8220 : implementation.
8221 :
8222 : The default implementation, used by most drivers, will
8223 : however iterate over each layer, and then over each feature within this
8224 : layer.
8225 :
8226 : This method takes into account spatial and attribute filters set on layers that
8227 : will be iterated upon.
8228 :
8229 : The ResetReading() method can be used to start at the beginning again.
8230 :
8231 : Depending on drivers, this may also have the side effect of calling
8232 : OGRLayer::GetNextFeature() on the layers of this dataset.
8233 :
8234 : This method is the same as the C function GDALDatasetGetNextFeature().
8235 :
8236 : @param ppoBelongingLayer a pointer to a OGRLayer* variable to receive the
8237 : layer to which the object belongs to, or NULL.
8238 : It is possible that the output of *ppoBelongingLayer
8239 : to be NULL despite the feature not being NULL.
8240 : @param pdfProgressPct a pointer to a double variable to receive the
8241 : percentage progress (in [0,1] range), or NULL.
8242 : On return, the pointed value might be negative if
8243 : determining the progress is not possible.
8244 : @param pfnProgress a progress callback to report progress (for
8245 : GetNextFeature() calls that might have a long
8246 : duration) and offer cancellation possibility, or NULL.
8247 : @param pProgressData user data provided to pfnProgress, or NULL
8248 : @return a feature, or NULL if no more features are available.
8249 : @see GetFeatures()
8250 : */
8251 :
8252 68 : OGRFeature *GDALDataset::GetNextFeature(OGRLayer **ppoBelongingLayer,
8253 : double *pdfProgressPct,
8254 : GDALProgressFunc pfnProgress,
8255 : void *pProgressData)
8256 : {
8257 68 : if (!m_poPrivate || m_poPrivate->nCurrentLayerIdx < 0)
8258 : {
8259 2 : if (ppoBelongingLayer != nullptr)
8260 2 : *ppoBelongingLayer = nullptr;
8261 2 : if (pdfProgressPct != nullptr)
8262 1 : *pdfProgressPct = 1.0;
8263 2 : if (pfnProgress != nullptr)
8264 0 : pfnProgress(1.0, "", pProgressData);
8265 2 : return nullptr;
8266 : }
8267 :
8268 66 : if (m_poPrivate->poCurrentLayer == nullptr &&
8269 11 : (pdfProgressPct != nullptr || pfnProgress != nullptr))
8270 : {
8271 4 : if (m_poPrivate->nLayerCount < 0)
8272 : {
8273 4 : m_poPrivate->nLayerCount = GetLayerCount();
8274 : }
8275 :
8276 4 : if (m_poPrivate->nTotalFeatures == TOTAL_FEATURES_NOT_INIT)
8277 : {
8278 4 : m_poPrivate->nTotalFeatures = 0;
8279 8 : for (int i = 0; i < m_poPrivate->nLayerCount; i++)
8280 : {
8281 7 : OGRLayer *poLayer = GetLayer(i);
8282 14 : if (poLayer == nullptr ||
8283 7 : !poLayer->TestCapability(OLCFastFeatureCount))
8284 : {
8285 3 : m_poPrivate->nTotalFeatures = TOTAL_FEATURES_UNKNOWN;
8286 3 : break;
8287 : }
8288 4 : GIntBig nCount = poLayer->GetFeatureCount(FALSE);
8289 4 : if (nCount < 0)
8290 : {
8291 0 : m_poPrivate->nTotalFeatures = TOTAL_FEATURES_UNKNOWN;
8292 0 : break;
8293 : }
8294 4 : m_poPrivate->nTotalFeatures += nCount;
8295 : }
8296 : }
8297 : }
8298 :
8299 : while (true)
8300 : {
8301 82 : if (m_poPrivate->poCurrentLayer == nullptr)
8302 : {
8303 56 : m_poPrivate->poCurrentLayer =
8304 28 : GetLayer(m_poPrivate->nCurrentLayerIdx);
8305 28 : if (m_poPrivate->poCurrentLayer == nullptr)
8306 : {
8307 10 : m_poPrivate->nCurrentLayerIdx = -1;
8308 10 : if (ppoBelongingLayer != nullptr)
8309 7 : *ppoBelongingLayer = nullptr;
8310 10 : if (pdfProgressPct != nullptr)
8311 1 : *pdfProgressPct = 1.0;
8312 10 : return nullptr;
8313 : }
8314 18 : m_poPrivate->poCurrentLayer->ResetReading();
8315 18 : m_poPrivate->nFeatureReadInLayer = 0;
8316 18 : if (m_poPrivate->nTotalFeatures < 0 && pdfProgressPct != nullptr)
8317 : {
8318 0 : if (m_poPrivate->poCurrentLayer->TestCapability(
8319 0 : OLCFastFeatureCount))
8320 0 : m_poPrivate->nTotalFeaturesInLayer =
8321 0 : m_poPrivate->poCurrentLayer->GetFeatureCount(FALSE);
8322 : else
8323 0 : m_poPrivate->nTotalFeaturesInLayer = 0;
8324 : }
8325 : }
8326 72 : OGRFeature *poFeature = m_poPrivate->poCurrentLayer->GetNextFeature();
8327 72 : if (poFeature == nullptr)
8328 : {
8329 16 : m_poPrivate->nCurrentLayerIdx++;
8330 16 : m_poPrivate->poCurrentLayer = nullptr;
8331 16 : continue;
8332 : }
8333 :
8334 56 : m_poPrivate->nFeatureReadInLayer++;
8335 56 : m_poPrivate->nFeatureReadInDataset++;
8336 56 : if (pdfProgressPct != nullptr || pfnProgress != nullptr)
8337 : {
8338 9 : double dfPct = 0.0;
8339 9 : if (m_poPrivate->nTotalFeatures > 0)
8340 : {
8341 4 : dfPct = 1.0 * m_poPrivate->nFeatureReadInDataset /
8342 4 : m_poPrivate->nTotalFeatures;
8343 : }
8344 : else
8345 : {
8346 5 : dfPct = 1.0 * m_poPrivate->nCurrentLayerIdx /
8347 5 : m_poPrivate->nLayerCount;
8348 5 : if (m_poPrivate->nTotalFeaturesInLayer > 0)
8349 : {
8350 0 : dfPct += 1.0 * m_poPrivate->nFeatureReadInLayer /
8351 0 : m_poPrivate->nTotalFeaturesInLayer /
8352 0 : m_poPrivate->nLayerCount;
8353 : }
8354 : }
8355 9 : if (pdfProgressPct)
8356 4 : *pdfProgressPct = dfPct;
8357 9 : if (pfnProgress)
8358 5 : pfnProgress(dfPct, "", nullptr);
8359 : }
8360 :
8361 56 : if (ppoBelongingLayer != nullptr)
8362 51 : *ppoBelongingLayer = m_poPrivate->poCurrentLayer;
8363 56 : return poFeature;
8364 16 : }
8365 : }
8366 :
8367 : /************************************************************************/
8368 : /* GDALDatasetGetNextFeature() */
8369 : /************************************************************************/
8370 : /**
8371 : \brief Fetch the next available feature from this dataset.
8372 :
8373 : This method is intended for the few drivers where OGR_L_GetNextFeature()
8374 : is not efficient, but in general OGR_L_GetNextFeature() is a more
8375 : natural API.
8376 :
8377 : The returned feature becomes the responsibility of the caller to
8378 : delete with OGRFeature::DestroyFeature().
8379 :
8380 : Depending on the driver, this method may return features from layers in a
8381 : non sequential way. This is what may happen when the
8382 : ODsCRandomLayerRead capability is declared (for example for the
8383 : OSM and GMLAS drivers). When datasets declare this capability, it is strongly
8384 : advised to use GDALDataset::GetNextFeature() instead of
8385 : OGRLayer::GetNextFeature(), as the later might have a slow, incomplete or stub
8386 : implementation.
8387 :
8388 : The default implementation, used by most drivers, will
8389 : however iterate over each layer, and then over each feature within this
8390 : layer.
8391 :
8392 : This method takes into account spatial and attribute filters set on layers that
8393 : will be iterated upon.
8394 :
8395 : The ResetReading() method can be used to start at the beginning again.
8396 :
8397 : Depending on drivers, this may also have the side effect of calling
8398 : OGRLayer::GetNextFeature() on the layers of this dataset.
8399 :
8400 : This method is the same as the C++ method GDALDataset::GetNextFeature()
8401 :
8402 : @param hDS dataset handle.
8403 : @param phBelongingLayer a pointer to a OGRLayer* variable to receive the
8404 : layer to which the object belongs to, or NULL.
8405 : It is possible that the output of *ppoBelongingLayer
8406 : to be NULL despite the feature not being NULL.
8407 : @param pdfProgressPct a pointer to a double variable to receive the
8408 : percentage progress (in [0,1] range), or NULL.
8409 : On return, the pointed value might be negative if
8410 : determining the progress is not possible.
8411 : @param pfnProgress a progress callback to report progress (for
8412 : GetNextFeature() calls that might have a long
8413 : duration) and offer cancellation possibility, or NULL
8414 : @param pProgressData user data provided to pfnProgress, or NULL
8415 : @return a feature, or NULL if no more features are available.
8416 : */
8417 1917 : OGRFeatureH CPL_DLL GDALDatasetGetNextFeature(GDALDatasetH hDS,
8418 : OGRLayerH *phBelongingLayer,
8419 : double *pdfProgressPct,
8420 : GDALProgressFunc pfnProgress,
8421 : void *pProgressData)
8422 : {
8423 1917 : VALIDATE_POINTER1(hDS, "GDALDatasetGetNextFeature", nullptr);
8424 :
8425 3834 : return OGRFeature::ToHandle(GDALDataset::FromHandle(hDS)->GetNextFeature(
8426 : reinterpret_cast<OGRLayer **>(phBelongingLayer), pdfProgressPct,
8427 3834 : pfnProgress, pProgressData));
8428 : }
8429 :
8430 : /************************************************************************/
8431 : /* TestCapability() */
8432 : /************************************************************************/
8433 :
8434 : /**
8435 : \fn GDALDataset::TestCapability( const char * pszCap )
8436 : \brief Test if capability is available.
8437 :
8438 : One of the following dataset capability names can be passed into this
8439 : method, and a TRUE or FALSE value will be returned indicating whether or not
8440 : the capability is available for this object.
8441 :
8442 : <ul>
8443 : <li> <b>ODsCCreateLayer</b>: True if this datasource can create new layers.<p>
8444 : <li> <b>ODsCDeleteLayer</b>: True if this datasource can delete existing
8445 : layers.<p>
8446 : <li> <b>ODsCCreateGeomFieldAfterCreateLayer</b>: True if the layers of this
8447 : datasource support CreateGeomField() just after layer creation.<p>
8448 : <li> <b>ODsCCurveGeometries</b>: True if this datasource supports curve
8449 : geometries.<p>
8450 : <li> <b>ODsCTransactions</b>: True if this datasource supports (efficient)
8451 : transactions.<p>
8452 : <li> <b>ODsCEmulatedTransactions</b>: True if this datasource supports
8453 : transactions through emulation.<p>
8454 : <li> <b>ODsCRandomLayerRead</b>: True if this datasource has a dedicated
8455 : GetNextFeature() implementation, potentially returning features from
8456 : layers in a non sequential way.<p>
8457 : <li> <b>ODsCRandomLayerWrite</b>: True if this datasource supports calling
8458 : CreateFeature() on layers in a non sequential way.<p>
8459 : <li> <b>GDsCAddRelationship</b>: True if AddRelationship() is supported</li>
8460 : <li> <b>GDsCDeleteRelationship</b>: True if DeleteRelationship() is supported</li>
8461 : <li> <b>GDsCUpdateRelationship</b>: True if UpdateRelationship() is supported</li>
8462 : <li> <b>GDsCFastGetExtent</b>: True if GetExtent() is fast</li>
8463 : <li> <b>GDsCFastGetExtentWGS84LongLat</b>: True if GetExtentWGS84LongLat() is fast</li>
8464 : </ul>
8465 :
8466 : The \#define macro forms of the capability names should be used in preference
8467 : to the strings themselves to avoid misspelling.
8468 :
8469 : This method is the same as the C function GDALDatasetTestCapability() and the
8470 : deprecated OGR_DS_TestCapability().
8471 :
8472 : @param pszCap the capability to test.
8473 :
8474 : @return TRUE if capability available otherwise FALSE.
8475 : */
8476 :
8477 767 : int GDALDataset::TestCapability(const char *pszCap) const
8478 : {
8479 767 : if (EQUAL(pszCap, GDsCFastGetExtent) ||
8480 765 : EQUAL(pszCap, GDsCFastGetExtentWGS84LongLat))
8481 : {
8482 4 : for (auto &&poLayer : GetLayers())
8483 : {
8484 2 : if (!poLayer->TestCapability(OLCFastGetExtent))
8485 2 : return FALSE;
8486 : }
8487 2 : return TRUE;
8488 : }
8489 763 : return FALSE;
8490 : }
8491 :
8492 : /************************************************************************/
8493 : /* GDALDatasetTestCapability() */
8494 : /************************************************************************/
8495 :
8496 : /**
8497 : \brief Test if capability is available.
8498 :
8499 : One of the following dataset capability names can be passed into this
8500 : function, and a TRUE or FALSE value will be returned indicating whether or not
8501 : the capability is available for this object.
8502 :
8503 : <ul>
8504 : <li> <b>ODsCCreateLayer</b>: True if this datasource can create new layers.<p>
8505 : <li> <b>ODsCDeleteLayer</b>: True if this datasource can delete existing
8506 : layers.<p>
8507 : <li> <b>ODsCCreateGeomFieldAfterCreateLayer</b>: True if the layers of this
8508 : datasource support CreateGeomField() just after layer creation.<p>
8509 : <li> <b>ODsCCurveGeometries</b>: True if this datasource supports curve
8510 : geometries.<p>
8511 : <li> <b>ODsCTransactions</b>: True if this datasource supports (efficient)
8512 : transactions.<p>
8513 : <li> <b>ODsCEmulatedTransactions</b>: True if this datasource supports
8514 : transactions through emulation.<p>
8515 : <li> <b>ODsCRandomLayerRead</b>: True if this datasource has a dedicated
8516 : GetNextFeature() implementation, potentially returning features from
8517 : layers in a non sequential way.<p>
8518 : <li> <b>ODsCRandomLayerWrite</b>: True if this datasource supports calling
8519 : CreateFeature() on layers in a non sequential way.<p>
8520 : <li> <b>GDsCAddRelationship</b>: True if AddRelationship() is supported</li>
8521 : <li> <b>GDsCDeleteRelationship</b>: True if DeleteRelationship() is supported</li>
8522 : <li> <b>GDsCUpdateRelationship</b>: True if UpdateRelationship() is supported</li>
8523 : <li> <b>GDsCFastGetExtent</b>: True if GetExtent() is fast</li>
8524 : <li> <b>GDsCFastGetExtentWGS84LongLat</b>: True if GetExtentWGS84LongLat() is fast</li>
8525 : </ul>
8526 :
8527 : The \#define macro forms of the capability names should be used in preference
8528 : to the strings themselves to avoid misspelling.
8529 :
8530 : This function is the same as the C++ method GDALDataset::TestCapability()
8531 :
8532 :
8533 : @param hDS the dataset handle.
8534 : @param pszCap the capability to test.
8535 :
8536 : @return TRUE if capability available otherwise FALSE.
8537 : */
8538 127 : int GDALDatasetTestCapability(GDALDatasetH hDS, const char *pszCap)
8539 :
8540 : {
8541 127 : VALIDATE_POINTER1(hDS, "GDALDatasetTestCapability", 0);
8542 127 : VALIDATE_POINTER1(pszCap, "GDALDatasetTestCapability", 0);
8543 :
8544 127 : return GDALDataset::FromHandle(hDS)->TestCapability(pszCap);
8545 : }
8546 :
8547 : /************************************************************************/
8548 : /* StartTransaction() */
8549 : /************************************************************************/
8550 :
8551 : /**
8552 : \fn GDALDataset::StartTransaction(int)
8553 : \brief For datasources which support transactions, StartTransaction creates a
8554 : `transaction.
8555 :
8556 : If starting the transaction fails, will return
8557 : OGRERR_FAILURE. Datasources which do not support transactions will
8558 : always return OGRERR_UNSUPPORTED_OPERATION.
8559 :
8560 : Nested transactions are not supported.
8561 :
8562 : All changes done after the start of the transaction are definitely applied in
8563 : the datasource if CommitTransaction() is called. They may be canceled by
8564 : calling RollbackTransaction() instead.
8565 :
8566 : At the time of writing, transactions only apply on vector layers.
8567 :
8568 : Datasets that support transactions will advertise the ODsCTransactions
8569 : capability. Use of transactions at dataset level is generally preferred to
8570 : transactions at layer level, whose scope is rarely limited to the layer from
8571 : which it was started.
8572 :
8573 : In case StartTransaction() fails, neither CommitTransaction() or
8574 : RollbackTransaction() should be called.
8575 :
8576 : If an error occurs after a successful StartTransaction(), the whole transaction
8577 : may or may not be implicitly canceled, depending on drivers. (e.g. the PG
8578 : driver will cancel it, SQLite/GPKG not). In any case, in the event of an error,
8579 : an explicit call to RollbackTransaction() should be done to keep things
8580 : balanced.
8581 :
8582 : By default, when bForce is set to FALSE, only "efficient" transactions will be
8583 : attempted. Some drivers may offer an emulation of transactions, but sometimes
8584 : with significant overhead, in which case the user must explicitly allow for
8585 : such an emulation by setting bForce to TRUE. Drivers that offer emulated
8586 : transactions should advertise the ODsCEmulatedTransactions capability (and not
8587 : ODsCTransactions).
8588 :
8589 : This function is the same as the C function GDALDatasetStartTransaction().
8590 :
8591 : @param bForce can be set to TRUE if an emulation, possibly slow, of a
8592 : transaction
8593 : mechanism is acceptable.
8594 :
8595 : @return OGRERR_NONE on success.
8596 : */
8597 :
8598 37 : OGRErr GDALDataset::StartTransaction(CPL_UNUSED int bForce)
8599 : {
8600 37 : return OGRERR_UNSUPPORTED_OPERATION;
8601 : }
8602 :
8603 : /************************************************************************/
8604 : /* GDALDatasetStartTransaction() */
8605 : /************************************************************************/
8606 :
8607 : /**
8608 : \brief For datasources which support transactions, StartTransaction creates a
8609 : transaction.
8610 :
8611 : If starting the transaction fails, will return
8612 : OGRERR_FAILURE. Datasources which do not support transactions will
8613 : always return OGRERR_UNSUPPORTED_OPERATION.
8614 :
8615 : Nested transactions are not supported.
8616 :
8617 : All changes done after the start of the transaction are definitely applied in
8618 : the datasource if CommitTransaction() is called. They may be canceled by
8619 : calling RollbackTransaction() instead.
8620 :
8621 : At the time of writing, transactions only apply on vector layers.
8622 :
8623 : Datasets that support transactions will advertise the ODsCTransactions
8624 : capability.
8625 : Use of transactions at dataset level is generally preferred to transactions at
8626 : layer level, whose scope is rarely limited to the layer from which it was
8627 : started.
8628 :
8629 : In case StartTransaction() fails, neither CommitTransaction() or
8630 : RollbackTransaction() should be called.
8631 :
8632 : If an error occurs after a successful StartTransaction(), the whole
8633 : transaction may or may not be implicitly canceled, depending on drivers. (e.g.
8634 : the PG driver will cancel it, SQLite/GPKG not). In any case, in the event of an
8635 : error, an explicit call to RollbackTransaction() should be done to keep things
8636 : balanced.
8637 :
8638 : By default, when bForce is set to FALSE, only "efficient" transactions will be
8639 : attempted. Some drivers may offer an emulation of transactions, but sometimes
8640 : with significant overhead, in which case the user must explicitly allow for
8641 : such an emulation by setting bForce to TRUE. Drivers that offer emulated
8642 : transactions should advertise the ODsCEmulatedTransactions capability (and not
8643 : ODsCTransactions).
8644 :
8645 : This function is the same as the C++ method GDALDataset::StartTransaction()
8646 :
8647 : @param hDS the dataset handle.
8648 : @param bForce can be set to TRUE if an emulation, possibly slow, of a
8649 : transaction
8650 : mechanism is acceptable.
8651 :
8652 : @return OGRERR_NONE on success.
8653 : */
8654 106 : OGRErr GDALDatasetStartTransaction(GDALDatasetH hDS, int bForce)
8655 : {
8656 106 : VALIDATE_POINTER1(hDS, "GDALDatasetStartTransaction",
8657 : OGRERR_INVALID_HANDLE);
8658 :
8659 : #ifdef OGRAPISPY_ENABLED
8660 106 : if (bOGRAPISpyEnabled)
8661 2 : OGRAPISpy_Dataset_StartTransaction(hDS, bForce);
8662 : #endif
8663 :
8664 106 : return GDALDataset::FromHandle(hDS)->StartTransaction(bForce);
8665 : }
8666 :
8667 : /************************************************************************/
8668 : /* CommitTransaction() */
8669 : /************************************************************************/
8670 :
8671 : /**
8672 : \brief For datasources which support transactions, CommitTransaction commits a
8673 : transaction.
8674 :
8675 : If no transaction is active, or the commit fails, will return
8676 : OGRERR_FAILURE. Datasources which do not support transactions will
8677 : always return OGRERR_UNSUPPORTED_OPERATION.
8678 :
8679 : Depending on drivers, this may or may not abort layer sequential readings that
8680 : are active.
8681 :
8682 : This function is the same as the C function GDALDatasetCommitTransaction().
8683 :
8684 : @return OGRERR_NONE on success.
8685 : */
8686 52 : OGRErr GDALDataset::CommitTransaction()
8687 : {
8688 52 : return OGRERR_UNSUPPORTED_OPERATION;
8689 : }
8690 :
8691 : /************************************************************************/
8692 : /* GDALDatasetCommitTransaction() */
8693 : /************************************************************************/
8694 :
8695 : /**
8696 : \brief For datasources which support transactions, CommitTransaction commits a
8697 : transaction.
8698 :
8699 : If no transaction is active, or the commit fails, will return
8700 : OGRERR_FAILURE. Datasources which do not support transactions will
8701 : always return OGRERR_UNSUPPORTED_OPERATION.
8702 :
8703 : Depending on drivers, this may or may not abort layer sequential readings that
8704 : are active.
8705 :
8706 : This function is the same as the C++ method GDALDataset::CommitTransaction()
8707 :
8708 : @return OGRERR_NONE on success.
8709 : */
8710 77 : OGRErr GDALDatasetCommitTransaction(GDALDatasetH hDS)
8711 : {
8712 77 : VALIDATE_POINTER1(hDS, "GDALDatasetCommitTransaction",
8713 : OGRERR_INVALID_HANDLE);
8714 :
8715 : #ifdef OGRAPISPY_ENABLED
8716 77 : if (bOGRAPISpyEnabled)
8717 2 : OGRAPISpy_Dataset_CommitTransaction(hDS);
8718 : #endif
8719 :
8720 77 : return GDALDataset::FromHandle(hDS)->CommitTransaction();
8721 : }
8722 :
8723 : /************************************************************************/
8724 : /* RollbackTransaction() */
8725 : /************************************************************************/
8726 :
8727 : /**
8728 : \brief For datasources which support transactions, RollbackTransaction will
8729 : roll back a datasource to its state before the start of the current
8730 : transaction.
8731 : If no transaction is active, or the rollback fails, will return
8732 : OGRERR_FAILURE. Datasources which do not support transactions will
8733 : always return OGRERR_UNSUPPORTED_OPERATION.
8734 :
8735 : This function is the same as the C function GDALDatasetRollbackTransaction().
8736 :
8737 : @return OGRERR_NONE on success.
8738 : */
8739 2 : OGRErr GDALDataset::RollbackTransaction()
8740 : {
8741 2 : return OGRERR_UNSUPPORTED_OPERATION;
8742 : }
8743 :
8744 : /************************************************************************/
8745 : /* GDALDatasetRollbackTransaction() */
8746 : /************************************************************************/
8747 :
8748 : /**
8749 : \brief For datasources which support transactions, RollbackTransaction will
8750 : roll back a datasource to its state before the start of the current
8751 : transaction.
8752 : If no transaction is active, or the rollback fails, will return
8753 : OGRERR_FAILURE. Datasources which do not support transactions will
8754 : always return OGRERR_UNSUPPORTED_OPERATION.
8755 :
8756 : This function is the same as the C++ method GDALDataset::RollbackTransaction().
8757 :
8758 : @return OGRERR_NONE on success.
8759 : */
8760 44 : OGRErr GDALDatasetRollbackTransaction(GDALDatasetH hDS)
8761 : {
8762 44 : VALIDATE_POINTER1(hDS, "GDALDatasetRollbackTransaction",
8763 : OGRERR_INVALID_HANDLE);
8764 :
8765 : #ifdef OGRAPISPY_ENABLED
8766 44 : if (bOGRAPISpyEnabled)
8767 2 : OGRAPISpy_Dataset_RollbackTransaction(hDS);
8768 : #endif
8769 :
8770 44 : return GDALDataset::FromHandle(hDS)->RollbackTransaction();
8771 : }
8772 :
8773 : //! @cond Doxygen_Suppress
8774 :
8775 : /************************************************************************/
8776 : /* ShareLockWithParentDataset() */
8777 : /************************************************************************/
8778 :
8779 : /* To be used typically by the GTiff driver to link overview datasets */
8780 : /* with their main dataset, so that they share the same lock */
8781 : /* Cf https://github.com/OSGeo/gdal/issues/1488 */
8782 : /* The parent dataset should remain alive while the this dataset is alive */
8783 :
8784 2338 : void GDALDataset::ShareLockWithParentDataset(GDALDataset *poParentDataset)
8785 : {
8786 2338 : if (m_poPrivate != nullptr)
8787 : {
8788 2338 : m_poPrivate->poParentDataset = poParentDataset;
8789 : }
8790 2338 : }
8791 :
8792 : /************************************************************************/
8793 : /* SetQueryLoggerFunc() */
8794 : /************************************************************************/
8795 :
8796 0 : bool GDALDataset::SetQueryLoggerFunc(CPL_UNUSED GDALQueryLoggerFunc callback,
8797 : CPL_UNUSED void *context)
8798 : {
8799 0 : return false;
8800 : }
8801 :
8802 : /************************************************************************/
8803 : /* EnterReadWrite() */
8804 : /************************************************************************/
8805 :
8806 8286060 : int GDALDataset::EnterReadWrite(GDALRWFlag eRWFlag)
8807 : {
8808 16572100 : if (m_poPrivate == nullptr ||
8809 8286060 : IsThreadSafe(GDAL_OF_RASTER | (nOpenFlags & GDAL_OF_UPDATE)))
8810 11992 : return FALSE;
8811 :
8812 8274070 : if (m_poPrivate->poParentDataset)
8813 242623 : return m_poPrivate->poParentDataset->EnterReadWrite(eRWFlag);
8814 :
8815 8031450 : if (eAccess == GA_Update)
8816 : {
8817 2456300 : if (m_poPrivate->eStateReadWriteMutex ==
8818 : GDALAllowReadWriteMutexState::RW_MUTEX_STATE_UNKNOWN)
8819 : {
8820 : // In case dead-lock would occur, which is not impossible,
8821 : // this can be used to prevent it, but at the risk of other
8822 : // issues.
8823 10825 : if (CPLTestBool(
8824 : CPLGetConfigOption("GDAL_ENABLE_READ_WRITE_MUTEX", "YES")))
8825 : {
8826 10825 : m_poPrivate->eStateReadWriteMutex =
8827 : GDALAllowReadWriteMutexState::RW_MUTEX_STATE_ALLOWED;
8828 : }
8829 : else
8830 : {
8831 0 : m_poPrivate->eStateReadWriteMutex =
8832 : GDALAllowReadWriteMutexState::RW_MUTEX_STATE_DISABLED;
8833 : }
8834 : }
8835 2456300 : if (m_poPrivate->eStateReadWriteMutex ==
8836 : GDALAllowReadWriteMutexState::RW_MUTEX_STATE_ALLOWED)
8837 : {
8838 : // There should be no race related to creating this mutex since
8839 : // it should be first created through IWriteBlock() / IRasterIO()
8840 : // and then GDALRasterBlock might call it from another thread.
8841 : #ifdef DEBUG_VERBOSE
8842 : CPLDebug("GDAL",
8843 : "[Thread " CPL_FRMT_GIB "] Acquiring RW mutex for %s",
8844 : CPLGetPID(), GetDescription());
8845 : #endif
8846 1552620 : CPLCreateOrAcquireMutex(&(m_poPrivate->hMutex), 1000.0);
8847 :
8848 : const int nCountMutex =
8849 1552620 : m_poPrivate->oMapThreadToMutexTakenCount[CPLGetPID()]++;
8850 1552620 : if (nCountMutex == 0 && eRWFlag == GF_Read)
8851 : {
8852 530527 : CPLReleaseMutex(m_poPrivate->hMutex);
8853 1686960 : for (int i = 0; i < nBands; i++)
8854 : {
8855 1156430 : auto blockCache = papoBands[i]->poBandBlockCache;
8856 1156430 : if (blockCache)
8857 823538 : blockCache->WaitCompletionPendingTasks();
8858 : }
8859 530527 : CPLCreateOrAcquireMutex(&(m_poPrivate->hMutex), 1000.0);
8860 : }
8861 :
8862 1552620 : return TRUE;
8863 : }
8864 : }
8865 6478830 : return FALSE;
8866 : }
8867 :
8868 : /************************************************************************/
8869 : /* LeaveReadWrite() */
8870 : /************************************************************************/
8871 :
8872 1781580 : void GDALDataset::LeaveReadWrite()
8873 : {
8874 1781580 : if (m_poPrivate)
8875 : {
8876 1781580 : if (m_poPrivate->poParentDataset)
8877 : {
8878 228963 : m_poPrivate->poParentDataset->LeaveReadWrite();
8879 228963 : return;
8880 : }
8881 :
8882 1552620 : m_poPrivate->oMapThreadToMutexTakenCount[CPLGetPID()]--;
8883 1552620 : CPLReleaseMutex(m_poPrivate->hMutex);
8884 : #ifdef DEBUG_VERBOSE
8885 : CPLDebug("GDAL", "[Thread " CPL_FRMT_GIB "] Releasing RW mutex for %s",
8886 : CPLGetPID(), GetDescription());
8887 : #endif
8888 : }
8889 : }
8890 :
8891 : /************************************************************************/
8892 : /* InitRWLock() */
8893 : /************************************************************************/
8894 :
8895 3997250 : void GDALDataset::InitRWLock()
8896 : {
8897 3997250 : if (m_poPrivate)
8898 : {
8899 3997250 : if (m_poPrivate->poParentDataset)
8900 : {
8901 8584 : m_poPrivate->poParentDataset->InitRWLock();
8902 8584 : return;
8903 : }
8904 :
8905 3988660 : if (m_poPrivate->eStateReadWriteMutex ==
8906 : GDALAllowReadWriteMutexState::RW_MUTEX_STATE_UNKNOWN)
8907 : {
8908 1 : if (EnterReadWrite(GF_Write))
8909 1 : LeaveReadWrite();
8910 : }
8911 : }
8912 : }
8913 :
8914 : /************************************************************************/
8915 : /* DisableReadWriteMutex() */
8916 : /************************************************************************/
8917 :
8918 : // The mutex logic is broken in multi-threaded situations, for example
8919 : // with 2 WarpedVRT datasets being read at the same time. In that
8920 : // particular case, the mutex is not needed, so allow the VRTWarpedDataset code
8921 : // to disable it.
8922 22082 : void GDALDataset::DisableReadWriteMutex()
8923 : {
8924 22082 : if (m_poPrivate)
8925 : {
8926 22082 : if (m_poPrivate->poParentDataset)
8927 : {
8928 0 : m_poPrivate->poParentDataset->DisableReadWriteMutex();
8929 0 : return;
8930 : }
8931 :
8932 22082 : m_poPrivate->eStateReadWriteMutex =
8933 : GDALAllowReadWriteMutexState::RW_MUTEX_STATE_DISABLED;
8934 : }
8935 : }
8936 :
8937 : /************************************************************************/
8938 : /* TemporarilyDropReadWriteLock() */
8939 : /************************************************************************/
8940 :
8941 3416560 : void GDALDataset::TemporarilyDropReadWriteLock()
8942 : {
8943 3416560 : if (m_poPrivate == nullptr)
8944 0 : return;
8945 :
8946 3416560 : if (m_poPrivate->poParentDataset)
8947 : {
8948 26346 : m_poPrivate->poParentDataset->TemporarilyDropReadWriteLock();
8949 26346 : return;
8950 : }
8951 :
8952 : #ifndef __COVERITY__
8953 3390220 : if (m_poPrivate->hMutex)
8954 : {
8955 : #ifdef DEBUG_VERBOSE
8956 : CPLDebug("GDAL",
8957 : "[Thread " CPL_FRMT_GIB "] "
8958 : "Temporarily drop RW mutex for %s",
8959 : CPLGetPID(), GetDescription());
8960 : #endif
8961 422184 : CPLAcquireMutex(m_poPrivate->hMutex, 1000.0);
8962 : const int nCount =
8963 422184 : m_poPrivate->oMapThreadToMutexTakenCount[CPLGetPID()];
8964 : #ifdef DEBUG_EXTRA
8965 : m_poPrivate->oMapThreadToMutexTakenCountSaved[CPLGetPID()] = nCount;
8966 : #endif
8967 1273960 : for (int i = 0; i < nCount + 1; i++)
8968 : {
8969 : // The mutex is recursive
8970 851776 : CPLReleaseMutex(m_poPrivate->hMutex);
8971 : }
8972 : }
8973 : #endif
8974 : }
8975 :
8976 : /************************************************************************/
8977 : /* ReacquireReadWriteLock() */
8978 : /************************************************************************/
8979 :
8980 3416560 : void GDALDataset::ReacquireReadWriteLock()
8981 : {
8982 3416560 : if (m_poPrivate == nullptr)
8983 0 : return;
8984 :
8985 3416560 : if (m_poPrivate->poParentDataset)
8986 : {
8987 26346 : m_poPrivate->poParentDataset->ReacquireReadWriteLock();
8988 26346 : return;
8989 : }
8990 :
8991 : #ifndef __COVERITY__
8992 3390220 : if (m_poPrivate->hMutex)
8993 : {
8994 : #ifdef DEBUG_VERBOSE
8995 : CPLDebug("GDAL",
8996 : "[Thread " CPL_FRMT_GIB "] "
8997 : "Reacquire temporarily dropped RW mutex for %s",
8998 : CPLGetPID(), GetDescription());
8999 : #endif
9000 422185 : CPLAcquireMutex(m_poPrivate->hMutex, 1000.0);
9001 : const int nCount =
9002 422185 : m_poPrivate->oMapThreadToMutexTakenCount[CPLGetPID()];
9003 : #ifdef DEBUG_EXTRA
9004 : CPLAssert(nCount ==
9005 : m_poPrivate->oMapThreadToMutexTakenCountSaved[CPLGetPID()]);
9006 : #endif
9007 422185 : if (nCount == 0)
9008 18278 : CPLReleaseMutex(m_poPrivate->hMutex);
9009 447870 : for (int i = 0; i < nCount - 1; i++)
9010 : {
9011 : // The mutex is recursive
9012 25685 : CPLAcquireMutex(m_poPrivate->hMutex, 1000.0);
9013 : }
9014 : }
9015 : #endif
9016 : }
9017 :
9018 : /************************************************************************/
9019 : /* AcquireMutex() */
9020 : /************************************************************************/
9021 :
9022 196 : int GDALDataset::AcquireMutex()
9023 : {
9024 196 : if (m_poPrivate == nullptr)
9025 0 : return 0;
9026 196 : if (m_poPrivate->poParentDataset)
9027 : {
9028 0 : return m_poPrivate->poParentDataset->AcquireMutex();
9029 : }
9030 :
9031 196 : return CPLCreateOrAcquireMutex(&(m_poPrivate->hMutex), 1000.0);
9032 : }
9033 :
9034 : /************************************************************************/
9035 : /* ReleaseMutex() */
9036 : /************************************************************************/
9037 :
9038 196 : void GDALDataset::ReleaseMutex()
9039 : {
9040 196 : if (m_poPrivate)
9041 : {
9042 196 : if (m_poPrivate->poParentDataset)
9043 : {
9044 0 : m_poPrivate->poParentDataset->ReleaseMutex();
9045 0 : return;
9046 : }
9047 :
9048 196 : CPLReleaseMutex(m_poPrivate->hMutex);
9049 : }
9050 : }
9051 :
9052 : //! @endcond
9053 :
9054 : /************************************************************************/
9055 : /* GDALDataset::Features::Iterator::Private */
9056 : /************************************************************************/
9057 :
9058 : struct GDALDataset::Features::Iterator::Private
9059 : {
9060 : GDALDataset::FeatureLayerPair m_oPair{};
9061 : GDALDataset *m_poDS = nullptr;
9062 : bool m_bEOF = true;
9063 : };
9064 :
9065 4 : GDALDataset::Features::Iterator::Iterator(GDALDataset *poDS, bool bStart)
9066 4 : : m_poPrivate(new GDALDataset::Features::Iterator::Private())
9067 : {
9068 4 : m_poPrivate->m_poDS = poDS;
9069 4 : if (bStart)
9070 : {
9071 2 : poDS->ResetReading();
9072 4 : m_poPrivate->m_oPair.feature.reset(poDS->GetNextFeature(
9073 2 : &m_poPrivate->m_oPair.layer, nullptr, nullptr, nullptr));
9074 2 : m_poPrivate->m_bEOF = m_poPrivate->m_oPair.feature == nullptr;
9075 : }
9076 4 : }
9077 :
9078 : GDALDataset::Features::Iterator::~Iterator() = default;
9079 :
9080 : const GDALDataset::FeatureLayerPair &
9081 20 : GDALDataset::Features::Iterator::operator*() const
9082 : {
9083 20 : return m_poPrivate->m_oPair;
9084 : }
9085 :
9086 20 : GDALDataset::Features::Iterator &GDALDataset::Features::Iterator::operator++()
9087 : {
9088 40 : m_poPrivate->m_oPair.feature.reset(m_poPrivate->m_poDS->GetNextFeature(
9089 20 : &m_poPrivate->m_oPair.layer, nullptr, nullptr, nullptr));
9090 20 : m_poPrivate->m_bEOF = m_poPrivate->m_oPair.feature == nullptr;
9091 20 : return *this;
9092 : }
9093 :
9094 22 : bool GDALDataset::Features::Iterator::operator!=(const Iterator &it) const
9095 : {
9096 22 : return m_poPrivate->m_bEOF != it.m_poPrivate->m_bEOF;
9097 : }
9098 :
9099 : /************************************************************************/
9100 : /* GetFeatures() */
9101 : /************************************************************************/
9102 :
9103 : /** Function that return an iterable object over features in the dataset
9104 : * layer.
9105 : *
9106 : * This is a C++ iterator friendly version of GetNextFeature().
9107 : *
9108 : * Using this iterator for standard range-based loops is safe, but
9109 : * due to implementation limitations, you shouldn't try to access
9110 : * (dereference) more than one iterator step at a time, since the
9111 : * FeatureLayerPair reference which is returned is reused.
9112 : *
9113 : * Typical use is:
9114 : * \code{.cpp}
9115 : * for( auto&& oFeatureLayerPair: poDS->GetFeatures() )
9116 : * {
9117 : * std::cout << "Feature of layer " <<
9118 : * oFeatureLayerPair.layer->GetName() << std::endl;
9119 : * oFeatureLayerPair.feature->DumpReadable();
9120 : * }
9121 : * \endcode
9122 : *
9123 : * @see GetNextFeature()
9124 : *
9125 : */
9126 2 : GDALDataset::Features GDALDataset::GetFeatures()
9127 : {
9128 2 : return Features(this);
9129 : }
9130 :
9131 : /************************************************************************/
9132 : /* begin() */
9133 : /************************************************************************/
9134 :
9135 : /**
9136 : \brief Return beginning of feature iterator.
9137 :
9138 : */
9139 :
9140 2 : const GDALDataset::Features::Iterator GDALDataset::Features::begin() const
9141 : {
9142 2 : return {m_poSelf, true};
9143 : }
9144 :
9145 : /************************************************************************/
9146 : /* end() */
9147 : /************************************************************************/
9148 :
9149 : /**
9150 : \brief Return end of feature iterator.
9151 :
9152 : */
9153 :
9154 2 : const GDALDataset::Features::Iterator GDALDataset::Features::end() const
9155 : {
9156 2 : return {m_poSelf, false};
9157 : }
9158 :
9159 : /************************************************************************/
9160 : /* GDALDataset::Layers::Iterator::Private */
9161 : /************************************************************************/
9162 :
9163 : struct GDALDataset::Layers::Iterator::Private
9164 : {
9165 : OGRLayer *m_poLayer = nullptr;
9166 : int m_iCurLayer = 0;
9167 : int m_nLayerCount = 0;
9168 : GDALDataset *m_poDS = nullptr;
9169 : };
9170 :
9171 2 : GDALDataset::Layers::Iterator::Iterator() : m_poPrivate(new Private())
9172 : {
9173 2 : }
9174 :
9175 : // False positive of cppcheck 1.72
9176 : // cppcheck-suppress uninitMemberVar
9177 9 : GDALDataset::Layers::Iterator::Iterator(const Iterator &oOther)
9178 9 : : m_poPrivate(new Private(*(oOther.m_poPrivate)))
9179 : {
9180 9 : }
9181 :
9182 5 : GDALDataset::Layers::Iterator::Iterator(Iterator &&oOther) noexcept
9183 5 : : m_poPrivate(std::move(oOther.m_poPrivate))
9184 : {
9185 5 : }
9186 :
9187 814 : GDALDataset::Layers::Iterator::Iterator(GDALDataset *poDS, bool bStart)
9188 814 : : m_poPrivate(new Private())
9189 : {
9190 814 : m_poPrivate->m_poDS = poDS;
9191 814 : m_poPrivate->m_nLayerCount = poDS->GetLayerCount();
9192 814 : if (bStart)
9193 : {
9194 409 : if (m_poPrivate->m_nLayerCount)
9195 358 : m_poPrivate->m_poLayer = poDS->GetLayer(0);
9196 : }
9197 : else
9198 : {
9199 405 : m_poPrivate->m_iCurLayer = m_poPrivate->m_nLayerCount;
9200 : }
9201 814 : }
9202 :
9203 : GDALDataset::Layers::Iterator::~Iterator() = default;
9204 :
9205 : // False positive of cppcheck 1.72
9206 : // cppcheck-suppress operatorEqVarError
9207 : GDALDataset::Layers::Iterator &
9208 1 : GDALDataset::Layers::Iterator::operator=(const Iterator &oOther)
9209 : {
9210 1 : *m_poPrivate = *oOther.m_poPrivate;
9211 1 : return *this;
9212 : }
9213 :
9214 3 : GDALDataset::Layers::Iterator &GDALDataset::Layers::Iterator::operator=(
9215 : GDALDataset::Layers::Iterator &&oOther) noexcept
9216 : {
9217 3 : m_poPrivate = std::move(oOther.m_poPrivate);
9218 3 : return *this;
9219 : }
9220 :
9221 442 : OGRLayer *GDALDataset::Layers::Iterator::operator*() const
9222 : {
9223 442 : return m_poPrivate->m_poLayer;
9224 : }
9225 :
9226 419 : GDALDataset::Layers::Iterator &GDALDataset::Layers::Iterator::operator++()
9227 : {
9228 419 : m_poPrivate->m_iCurLayer++;
9229 419 : if (m_poPrivate->m_iCurLayer < m_poPrivate->m_nLayerCount)
9230 : {
9231 90 : m_poPrivate->m_poLayer =
9232 90 : m_poPrivate->m_poDS->GetLayer(m_poPrivate->m_iCurLayer);
9233 : }
9234 : else
9235 : {
9236 329 : m_poPrivate->m_poLayer = nullptr;
9237 : }
9238 419 : return *this;
9239 : }
9240 :
9241 2 : GDALDataset::Layers::Iterator GDALDataset::Layers::Iterator::operator++(int)
9242 : {
9243 2 : GDALDataset::Layers::Iterator temp = *this;
9244 2 : ++(*this);
9245 2 : return temp;
9246 : }
9247 :
9248 818 : bool GDALDataset::Layers::Iterator::operator!=(const Iterator &it) const
9249 : {
9250 818 : return m_poPrivate->m_iCurLayer != it.m_poPrivate->m_iCurLayer;
9251 : }
9252 :
9253 : /************************************************************************/
9254 : /* GetLayers() */
9255 : /************************************************************************/
9256 :
9257 : /** Function that returns an iterable object over layers in the dataset.
9258 : *
9259 : * This is a C++ iterator friendly version of GetLayer().
9260 : *
9261 : * Typical use is:
9262 : * \code{.cpp}
9263 : * for( auto&& poLayer: poDS->GetLayers() )
9264 : * {
9265 : * std::cout << "Layer << poLayer->GetName() << std::endl;
9266 : * }
9267 : * \endcode
9268 : *
9269 : * @see GetLayer()
9270 : *
9271 : */
9272 410 : GDALDataset::Layers GDALDataset::GetLayers()
9273 : {
9274 410 : return Layers(this);
9275 : }
9276 :
9277 : /************************************************************************/
9278 : /* begin() */
9279 : /************************************************************************/
9280 :
9281 : /**
9282 : \brief Return beginning of layer iterator.
9283 :
9284 : */
9285 :
9286 409 : GDALDataset::Layers::Iterator GDALDataset::Layers::begin() const
9287 : {
9288 409 : return {m_poSelf, true};
9289 : }
9290 :
9291 : /************************************************************************/
9292 : /* end() */
9293 : /************************************************************************/
9294 :
9295 : /**
9296 : \brief Return end of layer iterator.
9297 :
9298 : */
9299 :
9300 405 : GDALDataset::Layers::Iterator GDALDataset::Layers::end() const
9301 : {
9302 405 : return {m_poSelf, false};
9303 : }
9304 :
9305 : /************************************************************************/
9306 : /* size() */
9307 : /************************************************************************/
9308 :
9309 : /**
9310 : \brief Get the number of layers in this dataset.
9311 :
9312 : @return layer count.
9313 :
9314 : */
9315 :
9316 1 : size_t GDALDataset::Layers::size() const
9317 : {
9318 1 : return static_cast<size_t>(m_poSelf->GetLayerCount());
9319 : }
9320 :
9321 : /************************************************************************/
9322 : /* operator[]() */
9323 : /************************************************************************/
9324 : /**
9325 : \brief Fetch a layer by index.
9326 :
9327 : The returned layer remains owned by the
9328 : GDALDataset and should not be deleted by the application.
9329 :
9330 : @param iLayer a layer number between 0 and size()-1.
9331 :
9332 : @return the layer, or nullptr if iLayer is out of range or an error occurs.
9333 :
9334 : */
9335 :
9336 9 : OGRLayer *GDALDataset::Layers::operator[](int iLayer)
9337 : {
9338 9 : return m_poSelf->GetLayer(iLayer);
9339 : }
9340 :
9341 : /************************************************************************/
9342 : /* operator[]() */
9343 : /************************************************************************/
9344 : /**
9345 : \brief Fetch a layer by index.
9346 :
9347 : The returned layer remains owned by the
9348 : GDALDataset and should not be deleted by the application.
9349 :
9350 : @param iLayer a layer number between 0 and size()-1.
9351 :
9352 : @return the layer, or nullptr if iLayer is out of range or an error occurs.
9353 :
9354 : */
9355 :
9356 1 : OGRLayer *GDALDataset::Layers::operator[](size_t iLayer)
9357 : {
9358 1 : return m_poSelf->GetLayer(static_cast<int>(iLayer));
9359 : }
9360 :
9361 : /************************************************************************/
9362 : /* operator[]() */
9363 : /************************************************************************/
9364 : /**
9365 : \brief Fetch a layer by name.
9366 :
9367 : The returned layer remains owned by the
9368 : GDALDataset and should not be deleted by the application.
9369 :
9370 : @param pszLayerName layer name
9371 :
9372 : @return the layer, or nullptr if pszLayerName does not match with a layer
9373 :
9374 : */
9375 :
9376 1 : OGRLayer *GDALDataset::Layers::operator[](const char *pszLayerName)
9377 : {
9378 1 : return m_poSelf->GetLayerByName(pszLayerName);
9379 : }
9380 :
9381 : /************************************************************************/
9382 : /* GDALDataset::ConstLayers::Iterator::Private */
9383 : /************************************************************************/
9384 :
9385 : struct GDALDataset::ConstLayers::Iterator::Private
9386 : {
9387 : const OGRLayer *m_poLayer = nullptr;
9388 : int m_iCurLayer = 0;
9389 : int m_nLayerCount = 0;
9390 : const GDALDataset *m_poDS = nullptr;
9391 : };
9392 :
9393 2 : GDALDataset::ConstLayers::Iterator::Iterator() : m_poPrivate(new Private())
9394 : {
9395 2 : }
9396 :
9397 : // False positive of cppcheck 1.72
9398 : // cppcheck-suppress uninitMemberVar
9399 9 : GDALDataset::ConstLayers::Iterator::Iterator(const Iterator &oOther)
9400 9 : : m_poPrivate(new Private(*(oOther.m_poPrivate)))
9401 : {
9402 9 : }
9403 :
9404 5 : GDALDataset::ConstLayers::Iterator::Iterator(Iterator &&oOther) noexcept
9405 5 : : m_poPrivate(std::move(oOther.m_poPrivate))
9406 : {
9407 5 : }
9408 :
9409 35348 : GDALDataset::ConstLayers::Iterator::Iterator(const GDALDataset *poDS,
9410 35348 : bool bStart)
9411 35348 : : m_poPrivate(new Private())
9412 : {
9413 35348 : m_poPrivate->m_poDS = poDS;
9414 35348 : m_poPrivate->m_nLayerCount = poDS->GetLayerCount();
9415 35348 : if (bStart)
9416 : {
9417 17676 : if (m_poPrivate->m_nLayerCount)
9418 218 : m_poPrivate->m_poLayer = poDS->GetLayer(0);
9419 : }
9420 : else
9421 : {
9422 17672 : m_poPrivate->m_iCurLayer = m_poPrivate->m_nLayerCount;
9423 : }
9424 35348 : }
9425 :
9426 : GDALDataset::ConstLayers::Iterator::~Iterator() = default;
9427 :
9428 : // False positive of cppcheck 1.72
9429 : // cppcheck-suppress operatorEqVarError
9430 : GDALDataset::ConstLayers::Iterator &
9431 1 : GDALDataset::ConstLayers::Iterator::operator=(const Iterator &oOther)
9432 : {
9433 1 : *m_poPrivate = *oOther.m_poPrivate;
9434 1 : return *this;
9435 : }
9436 :
9437 : GDALDataset::ConstLayers::Iterator &
9438 3 : GDALDataset::ConstLayers::Iterator::operator=(
9439 : GDALDataset::ConstLayers::Iterator &&oOther) noexcept
9440 : {
9441 3 : m_poPrivate = std::move(oOther.m_poPrivate);
9442 3 : return *this;
9443 : }
9444 :
9445 16176 : const OGRLayer *GDALDataset::ConstLayers::Iterator::operator*() const
9446 : {
9447 16176 : return m_poPrivate->m_poLayer;
9448 : }
9449 :
9450 : GDALDataset::ConstLayers::Iterator &
9451 16171 : GDALDataset::ConstLayers::Iterator::operator++()
9452 : {
9453 16171 : m_poPrivate->m_iCurLayer++;
9454 16171 : if (m_poPrivate->m_iCurLayer < m_poPrivate->m_nLayerCount)
9455 : {
9456 15964 : m_poPrivate->m_poLayer =
9457 15964 : m_poPrivate->m_poDS->GetLayer(m_poPrivate->m_iCurLayer);
9458 : }
9459 : else
9460 : {
9461 207 : m_poPrivate->m_poLayer = nullptr;
9462 : }
9463 16171 : return *this;
9464 : }
9465 :
9466 : GDALDataset::ConstLayers::Iterator
9467 2 : GDALDataset::ConstLayers::Iterator::operator++(int)
9468 : {
9469 2 : GDALDataset::ConstLayers::Iterator temp = *this;
9470 2 : ++(*this);
9471 2 : return temp;
9472 : }
9473 :
9474 33837 : bool GDALDataset::ConstLayers::Iterator::operator!=(const Iterator &it) const
9475 : {
9476 33837 : return m_poPrivate->m_iCurLayer != it.m_poPrivate->m_iCurLayer;
9477 : }
9478 :
9479 : /************************************************************************/
9480 : /* GetLayers() */
9481 : /************************************************************************/
9482 :
9483 : /** Function that returns an iterable object over layers in the dataset.
9484 : *
9485 : * This is a C++ iterator friendly version of GetLayer().
9486 : *
9487 : * Typical use is:
9488 : * \code{.cpp}
9489 : * for( auto&& poLayer: poDS->GetLayers() )
9490 : * {
9491 : * std::cout << "Layer << poLayer->GetName() << std::endl;
9492 : * }
9493 : * \endcode
9494 : *
9495 : * @see GetLayer()
9496 : *
9497 : * @since GDAL 3.12
9498 : */
9499 17677 : GDALDataset::ConstLayers GDALDataset::GetLayers() const
9500 : {
9501 17677 : return ConstLayers(this);
9502 : }
9503 :
9504 : /************************************************************************/
9505 : /* begin() */
9506 : /************************************************************************/
9507 :
9508 : /**
9509 : \brief Return beginning of layer iterator.
9510 :
9511 : @since GDAL 3.12
9512 : */
9513 :
9514 17676 : GDALDataset::ConstLayers::Iterator GDALDataset::ConstLayers::begin() const
9515 : {
9516 17676 : return {m_poSelf, true};
9517 : }
9518 :
9519 : /************************************************************************/
9520 : /* end() */
9521 : /************************************************************************/
9522 :
9523 : /**
9524 : \brief Return end of layer iterator.
9525 :
9526 : @since GDAL 3.12
9527 : */
9528 :
9529 17672 : GDALDataset::ConstLayers::Iterator GDALDataset::ConstLayers::end() const
9530 : {
9531 17672 : return {m_poSelf, false};
9532 : }
9533 :
9534 : /************************************************************************/
9535 : /* size() */
9536 : /************************************************************************/
9537 :
9538 : /**
9539 : \brief Get the number of layers in this dataset.
9540 :
9541 : @return layer count.
9542 :
9543 : @since GDAL 3.12
9544 : */
9545 :
9546 1 : size_t GDALDataset::ConstLayers::size() const
9547 : {
9548 1 : return static_cast<size_t>(m_poSelf->GetLayerCount());
9549 : }
9550 :
9551 : /************************************************************************/
9552 : /* operator[]() */
9553 : /************************************************************************/
9554 : /**
9555 : \brief Fetch a layer by index.
9556 :
9557 : The returned layer remains owned by the
9558 : GDALDataset and should not be deleted by the application.
9559 :
9560 : @param iLayer a layer number between 0 and size()-1.
9561 :
9562 : @return the layer, or nullptr if iLayer is out of range or an error occurs.
9563 :
9564 : @since GDAL 3.12
9565 : */
9566 :
9567 9 : const OGRLayer *GDALDataset::ConstLayers::operator[](int iLayer)
9568 : {
9569 9 : return m_poSelf->GetLayer(iLayer);
9570 : }
9571 :
9572 : /************************************************************************/
9573 : /* operator[]() */
9574 : /************************************************************************/
9575 : /**
9576 : \brief Fetch a layer by index.
9577 :
9578 : The returned layer remains owned by the
9579 : GDALDataset and should not be deleted by the application.
9580 :
9581 : @param iLayer a layer number between 0 and size()-1.
9582 :
9583 : @return the layer, or nullptr if iLayer is out of range or an error occurs.
9584 :
9585 : @since GDAL 3.12
9586 : */
9587 :
9588 1 : const OGRLayer *GDALDataset::ConstLayers::operator[](size_t iLayer)
9589 : {
9590 1 : return m_poSelf->GetLayer(static_cast<int>(iLayer));
9591 : }
9592 :
9593 : /************************************************************************/
9594 : /* operator[]() */
9595 : /************************************************************************/
9596 : /**
9597 : \brief Fetch a layer by name.
9598 :
9599 : The returned layer remains owned by the
9600 : GDALDataset and should not be deleted by the application.
9601 :
9602 : @param pszLayerName layer name
9603 :
9604 : @return the layer, or nullptr if pszLayerName does not match with a layer
9605 :
9606 : @since GDAL 3.12
9607 : */
9608 :
9609 1 : const OGRLayer *GDALDataset::ConstLayers::operator[](const char *pszLayerName)
9610 : {
9611 1 : return const_cast<GDALDataset *>(m_poSelf)->GetLayerByName(pszLayerName);
9612 : }
9613 :
9614 : /************************************************************************/
9615 : /* GDALDataset::Bands::Iterator::Private */
9616 : /************************************************************************/
9617 :
9618 : struct GDALDataset::Bands::Iterator::Private
9619 : {
9620 : GDALRasterBand *m_poBand = nullptr;
9621 : int m_iCurBand = 0;
9622 : int m_nBandCount = 0;
9623 : GDALDataset *m_poDS = nullptr;
9624 : };
9625 :
9626 32 : GDALDataset::Bands::Iterator::Iterator(GDALDataset *poDS, bool bStart)
9627 32 : : m_poPrivate(new GDALDataset::Bands::Iterator::Private())
9628 : {
9629 32 : m_poPrivate->m_poDS = poDS;
9630 32 : m_poPrivate->m_nBandCount = poDS->GetRasterCount();
9631 32 : if (bStart)
9632 : {
9633 16 : if (m_poPrivate->m_nBandCount)
9634 16 : m_poPrivate->m_poBand = poDS->GetRasterBand(1);
9635 : }
9636 : else
9637 : {
9638 16 : m_poPrivate->m_iCurBand = m_poPrivate->m_nBandCount;
9639 : }
9640 32 : }
9641 :
9642 : GDALDataset::Bands::Iterator::~Iterator() = default;
9643 :
9644 18 : GDALRasterBand *GDALDataset::Bands::Iterator::operator*()
9645 : {
9646 18 : return m_poPrivate->m_poBand;
9647 : }
9648 :
9649 4 : GDALDataset::Bands::Iterator &GDALDataset::Bands::Iterator::operator++()
9650 : {
9651 4 : m_poPrivate->m_iCurBand++;
9652 4 : if (m_poPrivate->m_iCurBand < m_poPrivate->m_nBandCount)
9653 : {
9654 2 : m_poPrivate->m_poBand =
9655 2 : m_poPrivate->m_poDS->GetRasterBand(1 + m_poPrivate->m_iCurBand);
9656 : }
9657 : else
9658 : {
9659 2 : m_poPrivate->m_poBand = nullptr;
9660 : }
9661 4 : return *this;
9662 : }
9663 :
9664 20 : bool GDALDataset::Bands::Iterator::operator!=(const Iterator &it) const
9665 : {
9666 20 : return m_poPrivate->m_iCurBand != it.m_poPrivate->m_iCurBand;
9667 : }
9668 :
9669 : /************************************************************************/
9670 : /* GetBands() */
9671 : /************************************************************************/
9672 :
9673 : /** Function that returns an iterable object over GDALRasterBand in the dataset.
9674 : *
9675 : * This is a C++ iterator friendly version of GetRasterBand().
9676 : *
9677 : * Typical use is:
9678 : * \code{.cpp}
9679 : * for( auto&& poBand: poDS->GetBands() )
9680 : * {
9681 : * std::cout << "Band << poBand->GetDescription() << std::endl;
9682 : * }
9683 : * \endcode
9684 : *
9685 : * @see GetRasterBand()
9686 : *
9687 : */
9688 20 : GDALDataset::Bands GDALDataset::GetBands()
9689 : {
9690 20 : return Bands(this);
9691 : }
9692 :
9693 : /************************************************************************/
9694 : /* begin() */
9695 : /************************************************************************/
9696 :
9697 : /**
9698 : \brief Return beginning of band iterator.
9699 :
9700 : */
9701 :
9702 16 : const GDALDataset::Bands::Iterator GDALDataset::Bands::begin() const
9703 : {
9704 16 : return {m_poSelf, true};
9705 : }
9706 :
9707 : /************************************************************************/
9708 : /* end() */
9709 : /************************************************************************/
9710 :
9711 : /**
9712 : \brief Return end of band iterator.
9713 :
9714 : */
9715 :
9716 16 : const GDALDataset::Bands::Iterator GDALDataset::Bands::end() const
9717 : {
9718 16 : return {m_poSelf, false};
9719 : }
9720 :
9721 : /************************************************************************/
9722 : /* size() */
9723 : /************************************************************************/
9724 :
9725 : /**
9726 : \brief Get the number of raster bands in this dataset.
9727 :
9728 : @return raster band count.
9729 :
9730 : */
9731 :
9732 2 : size_t GDALDataset::Bands::size() const
9733 : {
9734 2 : return static_cast<size_t>(m_poSelf->GetRasterCount());
9735 : }
9736 :
9737 : /************************************************************************/
9738 : /* operator[]() */
9739 : /************************************************************************/
9740 : /**
9741 : \brief Fetch a raster band by index.
9742 :
9743 : The returned band remains owned by the
9744 : GDALDataset and should not be deleted by the application.
9745 :
9746 : @warning Contrary to GDALDataset::GetRasterBand(), the indexing here is
9747 : consistent with the conventions of C/C++, i.e. starting at 0.
9748 :
9749 : @param iBand a band index between 0 and size()-1.
9750 :
9751 : @return the band, or nullptr if iBand is out of range or an error occurs.
9752 :
9753 : */
9754 :
9755 1 : GDALRasterBand *GDALDataset::Bands::operator[](int iBand)
9756 : {
9757 1 : return m_poSelf->GetRasterBand(1 + iBand);
9758 : }
9759 :
9760 : /************************************************************************/
9761 : /* operator[]() */
9762 : /************************************************************************/
9763 :
9764 : /**
9765 : \brief Fetch a raster band by index.
9766 :
9767 : The returned band remains owned by the
9768 : GDALDataset and should not be deleted by the application.
9769 :
9770 : @warning Contrary to GDALDataset::GetRasterBand(), the indexing here is
9771 : consistent with the conventions of C/C++, i.e. starting at 0.
9772 :
9773 : @param iBand a band index between 0 and size()-1.
9774 :
9775 : @return the band, or nullptr if iBand is out of range or an error occurs.
9776 :
9777 : */
9778 :
9779 1 : GDALRasterBand *GDALDataset::Bands::operator[](size_t iBand)
9780 : {
9781 1 : return m_poSelf->GetRasterBand(1 + static_cast<int>(iBand));
9782 : }
9783 :
9784 : /************************************************************************/
9785 : /* GDALDataset::ConstBands::Iterator::Private */
9786 : /************************************************************************/
9787 :
9788 : struct GDALDataset::ConstBands::Iterator::Private
9789 : {
9790 : const GDALRasterBand *m_poBand = nullptr;
9791 : int m_iCurBand = 0;
9792 : int m_nBandCount = 0;
9793 : const GDALDataset *m_poDS = nullptr;
9794 : };
9795 :
9796 2 : GDALDataset::ConstBands::Iterator::Iterator(const GDALDataset *poDS,
9797 2 : bool bStart)
9798 2 : : m_poPrivate(new GDALDataset::ConstBands::Iterator::Private())
9799 : {
9800 2 : m_poPrivate->m_poDS = poDS;
9801 2 : m_poPrivate->m_nBandCount = poDS->GetRasterCount();
9802 2 : if (bStart)
9803 : {
9804 1 : if (m_poPrivate->m_nBandCount)
9805 1 : m_poPrivate->m_poBand = poDS->GetRasterBand(1);
9806 : }
9807 : else
9808 : {
9809 1 : m_poPrivate->m_iCurBand = m_poPrivate->m_nBandCount;
9810 : }
9811 2 : }
9812 :
9813 : GDALDataset::ConstBands::Iterator::~Iterator() = default;
9814 :
9815 3 : const GDALRasterBand *GDALDataset::ConstBands::Iterator::operator*() const
9816 : {
9817 3 : return m_poPrivate->m_poBand;
9818 : }
9819 :
9820 : GDALDataset::ConstBands::Iterator &
9821 3 : GDALDataset::ConstBands::Iterator::operator++()
9822 : {
9823 3 : m_poPrivate->m_iCurBand++;
9824 3 : if (m_poPrivate->m_iCurBand < m_poPrivate->m_nBandCount)
9825 : {
9826 2 : m_poPrivate->m_poBand =
9827 2 : m_poPrivate->m_poDS->GetRasterBand(1 + m_poPrivate->m_iCurBand);
9828 : }
9829 : else
9830 : {
9831 1 : m_poPrivate->m_poBand = nullptr;
9832 : }
9833 3 : return *this;
9834 : }
9835 :
9836 4 : bool GDALDataset::ConstBands::Iterator::operator!=(const Iterator &it) const
9837 : {
9838 4 : return m_poPrivate->m_iCurBand != it.m_poPrivate->m_iCurBand;
9839 : }
9840 :
9841 : /************************************************************************/
9842 : /* GetBands() */
9843 : /************************************************************************/
9844 :
9845 : /** Function that returns an iterable object over GDALRasterBand in the dataset.
9846 : *
9847 : * This is a C++ iterator friendly version of GetRasterBand().
9848 : *
9849 : * Typical use is:
9850 : * \code{.cpp}
9851 : * for( const auto* poBand: poDS->GetConstBands() )
9852 : * {
9853 : * std::cout << "Band << poBand->GetDescription() << std::endl;
9854 : * }
9855 : * \endcode
9856 : *
9857 : * @see GetRasterBand()
9858 : *
9859 : * @since GDAL 3.12
9860 : */
9861 4 : GDALDataset::ConstBands GDALDataset::GetBands() const
9862 : {
9863 4 : return ConstBands(this);
9864 : }
9865 :
9866 : /************************************************************************/
9867 : /* begin() */
9868 : /************************************************************************/
9869 :
9870 : /**
9871 : \brief Return beginning of band iterator.
9872 :
9873 : @since GDAL 3.12
9874 : */
9875 :
9876 1 : const GDALDataset::ConstBands::Iterator GDALDataset::ConstBands::begin() const
9877 : {
9878 1 : return {m_poSelf, true};
9879 : }
9880 :
9881 : /************************************************************************/
9882 : /* end() */
9883 : /************************************************************************/
9884 :
9885 : /**
9886 : \brief Return end of band iterator.
9887 :
9888 : @since GDAL 3.12
9889 : */
9890 :
9891 1 : const GDALDataset::ConstBands::Iterator GDALDataset::ConstBands::end() const
9892 : {
9893 1 : return {m_poSelf, false};
9894 : }
9895 :
9896 : /************************************************************************/
9897 : /* size() */
9898 : /************************************************************************/
9899 :
9900 : /**
9901 : \brief Get the number of raster bands in this dataset.
9902 :
9903 : @return raster band count.
9904 :
9905 : @since GDAL 3.12
9906 : */
9907 :
9908 1 : size_t GDALDataset::ConstBands::size() const
9909 : {
9910 1 : return static_cast<size_t>(m_poSelf->GetRasterCount());
9911 : }
9912 :
9913 : /************************************************************************/
9914 : /* operator[]() */
9915 : /************************************************************************/
9916 : /**
9917 : \brief Fetch a raster band by index.
9918 :
9919 : The returned band remains owned by the
9920 : GDALDataset and should not be deleted by the application.
9921 :
9922 : @warning Contrary to GDALDataset::GetRasterBand(), the indexing here is
9923 : consistent with the conventions of C/C++, i.e. starting at 0.
9924 :
9925 : @param iBand a band index between 0 and size()-1.
9926 :
9927 : @return the band, or nullptr if iBand is out of range or an error occurs.
9928 :
9929 : @since GDAL 3.12
9930 : */
9931 :
9932 1 : const GDALRasterBand *GDALDataset::ConstBands::operator[](int iBand) const
9933 : {
9934 1 : return m_poSelf->GetRasterBand(1 + iBand);
9935 : }
9936 :
9937 : /************************************************************************/
9938 : /* operator[]() */
9939 : /************************************************************************/
9940 :
9941 : /**
9942 : \brief Fetch a raster band by index.
9943 :
9944 : The returned band remains owned by the
9945 : GDALDataset and should not be deleted by the application.
9946 :
9947 : @warning Contrary to GDALDataset::GetRasterBand(), the indexing here is
9948 : consistent with the conventions of C/C++, i.e. starting at 0.
9949 :
9950 : @param iBand a band index between 0 and size()-1.
9951 :
9952 : @return the band, or nullptr if iBand is out of range or an error occurs.
9953 :
9954 : @since GDAL 3.12
9955 : */
9956 :
9957 1 : const GDALRasterBand *GDALDataset::ConstBands::operator[](size_t iBand) const
9958 : {
9959 1 : return m_poSelf->GetRasterBand(1 + static_cast<int>(iBand));
9960 : }
9961 :
9962 : /************************************************************************/
9963 : /* GetRootGroup() */
9964 : /************************************************************************/
9965 :
9966 : /**
9967 : \brief Return the root GDALGroup of this dataset.
9968 :
9969 : Only valid for multidimensional datasets.
9970 :
9971 : This is the same as the C function GDALDatasetGetRootGroup().
9972 :
9973 : @since GDAL 3.1
9974 : */
9975 :
9976 2930 : std::shared_ptr<GDALGroup> GDALDataset::GetRootGroup() const
9977 : {
9978 2930 : return nullptr;
9979 : }
9980 :
9981 : /************************************************************************/
9982 : /* GetRawBinaryLayout() */
9983 : /************************************************************************/
9984 :
9985 : //! @cond Doxygen_Suppress
9986 : /**
9987 : \brief Return the layout of a dataset that can be considered as a raw binary
9988 : format.
9989 :
9990 : @param sLayout Structure that will be set if the dataset is a raw binary one.
9991 : @return true if the dataset is a raw binary one.
9992 : @since GDAL 3.1
9993 : */
9994 :
9995 0 : bool GDALDataset::GetRawBinaryLayout(RawBinaryLayout &sLayout)
9996 : {
9997 0 : CPL_IGNORE_RET_VAL(sLayout);
9998 0 : return false;
9999 : }
10000 :
10001 : //! @endcond
10002 :
10003 : /************************************************************************/
10004 : /* ClearStatistics() */
10005 : /************************************************************************/
10006 :
10007 : /**
10008 : \brief Clear statistics
10009 :
10010 : Only implemented for now in PAM supported datasets
10011 :
10012 : This is the same as the C function GDALDatasetClearStatistics().
10013 :
10014 : @since GDAL 3.2
10015 : */
10016 :
10017 11 : void GDALDataset::ClearStatistics()
10018 : {
10019 22 : auto poRootGroup = GetRootGroup();
10020 11 : if (poRootGroup)
10021 1 : poRootGroup->ClearStatistics();
10022 11 : }
10023 :
10024 : /************************************************************************/
10025 : /* GDALDatasetClearStatistics() */
10026 : /************************************************************************/
10027 :
10028 : /**
10029 : \brief Clear statistics
10030 :
10031 : This is the same as the C++ method GDALDataset::ClearStatistics().
10032 :
10033 : @since GDAL 3.2
10034 : */
10035 :
10036 2 : void GDALDatasetClearStatistics(GDALDatasetH hDS)
10037 : {
10038 2 : VALIDATE_POINTER0(hDS, __func__);
10039 2 : GDALDataset::FromHandle(hDS)->ClearStatistics();
10040 : }
10041 :
10042 : /************************************************************************/
10043 : /* GetFieldDomainNames() */
10044 : /************************************************************************/
10045 :
10046 : /** Returns a list of the names of all field domains stored in the dataset.
10047 : *
10048 : * @note The default implementation assumes that drivers fully populate
10049 : * m_oMapFieldDomains when opening a dataset. If this assumption is incorrect
10050 : * then a specialized implementation of GetFieldDomainNames() must be
10051 : * implemented.
10052 : *
10053 : * @param papszOptions Driver specific options determining how attributes
10054 : * should be retrieved. Pass nullptr for default behavior.
10055 : *
10056 : * @return list of field domain names
10057 : * @since GDAL 3.5
10058 : */
10059 : std::vector<std::string>
10060 47 : GDALDataset::GetFieldDomainNames(CPL_UNUSED CSLConstList papszOptions) const
10061 : {
10062 :
10063 47 : std::vector<std::string> names;
10064 47 : names.reserve(m_oMapFieldDomains.size());
10065 59 : for (const auto &it : m_oMapFieldDomains)
10066 : {
10067 12 : names.emplace_back(it.first);
10068 : }
10069 47 : return names;
10070 : }
10071 :
10072 : /************************************************************************/
10073 : /* GDALDatasetGetFieldDomainNames() */
10074 : /************************************************************************/
10075 :
10076 : /** Returns a list of the names of all field domains stored in the dataset.
10077 : *
10078 : * This is the same as the C++ method GDALDataset::GetFieldDomainNames().
10079 : *
10080 : * @param hDS Dataset handle.
10081 : * @param papszOptions Driver specific options determining how attributes
10082 : * should be retrieved. Pass nullptr for default behavior.
10083 : *
10084 : * @return list of field domain names, to be freed with CSLDestroy()
10085 : * @since GDAL 3.5
10086 : */
10087 34 : char **GDALDatasetGetFieldDomainNames(GDALDatasetH hDS,
10088 : CSLConstList papszOptions)
10089 : {
10090 34 : VALIDATE_POINTER1(hDS, __func__, nullptr);
10091 : auto names =
10092 68 : GDALDataset::FromHandle(hDS)->GetFieldDomainNames(papszOptions);
10093 68 : CPLStringList res;
10094 154 : for (const auto &name : names)
10095 : {
10096 120 : res.AddString(name.c_str());
10097 : }
10098 34 : return res.StealList();
10099 : }
10100 :
10101 : /************************************************************************/
10102 : /* GetFieldDomain() */
10103 : /************************************************************************/
10104 :
10105 : /** Get a field domain from its name.
10106 : *
10107 : * @return the field domain, or nullptr if not found.
10108 : * @since GDAL 3.3
10109 : */
10110 323 : const OGRFieldDomain *GDALDataset::GetFieldDomain(const std::string &name) const
10111 : {
10112 323 : const auto iter = m_oMapFieldDomains.find(name);
10113 323 : if (iter == m_oMapFieldDomains.end())
10114 151 : return nullptr;
10115 172 : return iter->second.get();
10116 : }
10117 :
10118 : /************************************************************************/
10119 : /* GDALDatasetGetFieldDomain() */
10120 : /************************************************************************/
10121 :
10122 : /** Get a field domain from its name.
10123 : *
10124 : * This is the same as the C++ method GDALDataset::GetFieldDomain().
10125 : *
10126 : * @param hDS Dataset handle.
10127 : * @param pszName Name of field domain.
10128 : * @return the field domain (ownership remains to the dataset), or nullptr if
10129 : * not found.
10130 : * @since GDAL 3.3
10131 : */
10132 130 : OGRFieldDomainH GDALDatasetGetFieldDomain(GDALDatasetH hDS, const char *pszName)
10133 : {
10134 130 : VALIDATE_POINTER1(hDS, __func__, nullptr);
10135 130 : VALIDATE_POINTER1(pszName, __func__, nullptr);
10136 130 : return OGRFieldDomain::ToHandle(const_cast<OGRFieldDomain *>(
10137 130 : GDALDataset::FromHandle(hDS)->GetFieldDomain(pszName)));
10138 : }
10139 :
10140 : /************************************************************************/
10141 : /* AddFieldDomain() */
10142 : /************************************************************************/
10143 :
10144 : /** Add a field domain to the dataset.
10145 : *
10146 : * Only a few drivers will support this operation, and some of them might only
10147 : * support it only for some types of field domains.
10148 : * At the time of writing (GDAL 3.3), only the Memory and GeoPackage drivers
10149 : * support this operation. A dataset having at least some support for this
10150 : * operation should report the ODsCAddFieldDomain dataset capability.
10151 : *
10152 : * Anticipated failures will not be emitted through the CPLError()
10153 : * infrastructure, but will be reported in the failureReason output parameter.
10154 : *
10155 : * @note Drivers should make sure to update m_oMapFieldDomains in order for the
10156 : * default implementation of GetFieldDomainNames() to work correctly, or
10157 : * alternatively a specialized implementation of GetFieldDomainNames() should be
10158 : * implemented.
10159 : *
10160 : * @param domain The domain definition.
10161 : * @param failureReason Output parameter. Will contain an error message if
10162 : * an error occurs.
10163 : * @return true in case of success.
10164 : * @since GDAL 3.3
10165 : */
10166 0 : bool GDALDataset::AddFieldDomain(
10167 : CPL_UNUSED std::unique_ptr<OGRFieldDomain> &&domain,
10168 : std::string &failureReason)
10169 : {
10170 0 : failureReason = "AddFieldDomain not supported by this driver";
10171 0 : return false;
10172 : }
10173 :
10174 : /************************************************************************/
10175 : /* GDALDatasetAddFieldDomain() */
10176 : /************************************************************************/
10177 :
10178 : /** Add a field domain to the dataset.
10179 : *
10180 : * Only a few drivers will support this operation, and some of them might only
10181 : * support it only for some types of field domains.
10182 : * At the time of writing (GDAL 3.3), only the Memory and GeoPackage drivers
10183 : * support this operation. A dataset having at least some support for this
10184 : * operation should report the ODsCAddFieldDomain dataset capability.
10185 : *
10186 : * Anticipated failures will not be emitted through the CPLError()
10187 : * infrastructure, but will be reported in the ppszFailureReason output
10188 : * parameter.
10189 : *
10190 : * @param hDS Dataset handle.
10191 : * @param hFieldDomain The domain definition. Contrary to the C++ version,
10192 : * the passed object is copied.
10193 : * @param ppszFailureReason Output parameter. Will contain an error message if
10194 : * an error occurs (*ppszFailureReason to be freed
10195 : * with CPLFree). May be NULL.
10196 : * @return true in case of success.
10197 : * @since GDAL 3.3
10198 : */
10199 37 : bool GDALDatasetAddFieldDomain(GDALDatasetH hDS, OGRFieldDomainH hFieldDomain,
10200 : char **ppszFailureReason)
10201 : {
10202 37 : VALIDATE_POINTER1(hDS, __func__, false);
10203 37 : VALIDATE_POINTER1(hFieldDomain, __func__, false);
10204 : auto poDomain = std::unique_ptr<OGRFieldDomain>(
10205 74 : OGRFieldDomain::FromHandle(hFieldDomain)->Clone());
10206 37 : if (poDomain == nullptr)
10207 0 : return false;
10208 37 : std::string failureReason;
10209 74 : const bool bRet = GDALDataset::FromHandle(hDS)->AddFieldDomain(
10210 37 : std::move(poDomain), failureReason);
10211 37 : if (ppszFailureReason)
10212 : {
10213 37 : *ppszFailureReason =
10214 37 : failureReason.empty() ? nullptr : CPLStrdup(failureReason.c_str());
10215 : }
10216 37 : return bRet;
10217 : }
10218 :
10219 : /************************************************************************/
10220 : /* DeleteFieldDomain() */
10221 : /************************************************************************/
10222 :
10223 : /** Removes a field domain from the dataset.
10224 : *
10225 : * Only a few drivers will support this operation.
10226 : *
10227 : * At the time of writing (GDAL 3.5), only the Memory and GeoPackage drivers
10228 : * support this operation. A dataset having at least some support for this
10229 : * operation should report the ODsCDeleteFieldDomain dataset capability.
10230 : *
10231 : * Anticipated failures will not be emitted through the CPLError()
10232 : * infrastructure, but will be reported in the failureReason output parameter.
10233 : *
10234 : * @note Drivers should make sure to update m_oMapFieldDomains in order for the
10235 : * default implementation of GetFieldDomainNames() to work correctly, or
10236 : * alternatively a specialized implementation of GetFieldDomainNames() should be
10237 : * implemented.
10238 : *
10239 : * @param name The domain name.
10240 : * @param failureReason Output parameter. Will contain an error message if
10241 : * an error occurs.
10242 : * @return true in case of success.
10243 : * @since GDAL 3.5
10244 : */
10245 0 : bool GDALDataset::DeleteFieldDomain(CPL_UNUSED const std::string &name,
10246 : std::string &failureReason)
10247 : {
10248 0 : failureReason = "DeleteFieldDomain not supported by this driver";
10249 0 : return false;
10250 : }
10251 :
10252 : /************************************************************************/
10253 : /* GDALDatasetDeleteFieldDomain() */
10254 : /************************************************************************/
10255 :
10256 : /** Removes a field domain from the dataset.
10257 : *
10258 : * Only a few drivers will support this operation.
10259 : *
10260 : * At the time of writing (GDAL 3.5), only the Memory and GeoPackage drivers
10261 : * support this operation. A dataset having at least some support for this
10262 : * operation should report the ODsCDeleteFieldDomain dataset capability.
10263 : *
10264 : * Anticipated failures will not be emitted through the CPLError()
10265 : * infrastructure, but will be reported in the ppszFailureReason output
10266 : * parameter.
10267 : *
10268 : * @param hDS Dataset handle.
10269 : * @param pszName The domain name.
10270 : * @param ppszFailureReason Output parameter. Will contain an error message if
10271 : * an error occurs (*ppszFailureReason to be freed
10272 : * with CPLFree). May be NULL.
10273 : * @return true in case of success.
10274 : * @since GDAL 3.3
10275 : */
10276 25 : bool GDALDatasetDeleteFieldDomain(GDALDatasetH hDS, const char *pszName,
10277 : char **ppszFailureReason)
10278 : {
10279 25 : VALIDATE_POINTER1(hDS, __func__, false);
10280 25 : VALIDATE_POINTER1(pszName, __func__, false);
10281 25 : std::string failureReason;
10282 : const bool bRet =
10283 25 : GDALDataset::FromHandle(hDS)->DeleteFieldDomain(pszName, failureReason);
10284 25 : if (ppszFailureReason)
10285 : {
10286 0 : *ppszFailureReason =
10287 0 : failureReason.empty() ? nullptr : CPLStrdup(failureReason.c_str());
10288 : }
10289 25 : return bRet;
10290 : }
10291 :
10292 : /************************************************************************/
10293 : /* UpdateFieldDomain() */
10294 : /************************************************************************/
10295 :
10296 : /** Updates an existing field domain by replacing its definition.
10297 : *
10298 : * The existing field domain with matching name will be replaced.
10299 : *
10300 : * Only a few drivers will support this operation, and some of them might only
10301 : * support it only for some types of field domains.
10302 : * At the time of writing (GDAL 3.5), only the Memory driver
10303 : * supports this operation. A dataset having at least some support for this
10304 : * operation should report the ODsCUpdateFieldDomain dataset capability.
10305 : *
10306 : * Anticipated failures will not be emitted through the CPLError()
10307 : * infrastructure, but will be reported in the failureReason output parameter.
10308 : *
10309 : * @param domain The domain definition.
10310 : * @param failureReason Output parameter. Will contain an error message if
10311 : * an error occurs.
10312 : * @return true in case of success.
10313 : * @since GDAL 3.5
10314 : */
10315 0 : bool GDALDataset::UpdateFieldDomain(
10316 : CPL_UNUSED std::unique_ptr<OGRFieldDomain> &&domain,
10317 : std::string &failureReason)
10318 : {
10319 0 : failureReason = "UpdateFieldDomain not supported by this driver";
10320 0 : return false;
10321 : }
10322 :
10323 : /************************************************************************/
10324 : /* GDALDatasetUpdateFieldDomain() */
10325 : /************************************************************************/
10326 :
10327 : /** Updates an existing field domain by replacing its definition.
10328 : *
10329 : * The existing field domain with matching name will be replaced.
10330 : *
10331 : * Only a few drivers will support this operation, and some of them might only
10332 : * support it only for some types of field domains.
10333 : * At the time of writing (GDAL 3.5), only the Memory driver
10334 : * supports this operation. A dataset having at least some support for this
10335 : * operation should report the ODsCUpdateFieldDomain dataset capability.
10336 : *
10337 : * Anticipated failures will not be emitted through the CPLError()
10338 : * infrastructure, but will be reported in the failureReason output parameter.
10339 : *
10340 : * @param hDS Dataset handle.
10341 : * @param hFieldDomain The domain definition. Contrary to the C++ version,
10342 : * the passed object is copied.
10343 : * @param ppszFailureReason Output parameter. Will contain an error message if
10344 : * an error occurs (*ppszFailureReason to be freed
10345 : * with CPLFree). May be NULL.
10346 : * @return true in case of success.
10347 : * @since GDAL 3.5
10348 : */
10349 7 : bool GDALDatasetUpdateFieldDomain(GDALDatasetH hDS,
10350 : OGRFieldDomainH hFieldDomain,
10351 : char **ppszFailureReason)
10352 : {
10353 7 : VALIDATE_POINTER1(hDS, __func__, false);
10354 7 : VALIDATE_POINTER1(hFieldDomain, __func__, false);
10355 : auto poDomain = std::unique_ptr<OGRFieldDomain>(
10356 14 : OGRFieldDomain::FromHandle(hFieldDomain)->Clone());
10357 7 : if (poDomain == nullptr)
10358 0 : return false;
10359 7 : std::string failureReason;
10360 14 : const bool bRet = GDALDataset::FromHandle(hDS)->UpdateFieldDomain(
10361 7 : std::move(poDomain), failureReason);
10362 7 : if (ppszFailureReason)
10363 : {
10364 0 : *ppszFailureReason =
10365 0 : failureReason.empty() ? nullptr : CPLStrdup(failureReason.c_str());
10366 : }
10367 7 : return bRet;
10368 : }
10369 :
10370 : /************************************************************************/
10371 : /* GetRelationshipNames() */
10372 : /************************************************************************/
10373 :
10374 : /** Returns a list of the names of all relationships stored in the dataset.
10375 : *
10376 : * @param papszOptions Driver specific options determining how relationships
10377 : * should be retrieved. Pass nullptr for default behavior.
10378 : *
10379 : * @return list of relationship names
10380 : * @since GDAL 3.6
10381 : */
10382 : std::vector<std::string>
10383 187 : GDALDataset::GetRelationshipNames(CPL_UNUSED CSLConstList papszOptions) const
10384 : {
10385 187 : return {};
10386 : }
10387 :
10388 : /************************************************************************/
10389 : /* GDALDatasetGetRelationshipNames() */
10390 : /************************************************************************/
10391 :
10392 : /** Returns a list of the names of all relationships stored in the dataset.
10393 : *
10394 : * This is the same as the C++ method GDALDataset::GetRelationshipNames().
10395 : *
10396 : * @param hDS Dataset handle.
10397 : * @param papszOptions Driver specific options determining how relationships
10398 : * should be retrieved. Pass nullptr for default behavior.
10399 : *
10400 : * @return list of relationship names, to be freed with CSLDestroy()
10401 : * @since GDAL 3.6
10402 : */
10403 46 : char **GDALDatasetGetRelationshipNames(GDALDatasetH hDS,
10404 : CSLConstList papszOptions)
10405 : {
10406 46 : VALIDATE_POINTER1(hDS, __func__, nullptr);
10407 : auto names =
10408 92 : GDALDataset::FromHandle(hDS)->GetRelationshipNames(papszOptions);
10409 92 : CPLStringList res;
10410 146 : for (const auto &name : names)
10411 : {
10412 100 : res.AddString(name.c_str());
10413 : }
10414 46 : return res.StealList();
10415 : }
10416 :
10417 : /************************************************************************/
10418 : /* GetRelationship() */
10419 : /************************************************************************/
10420 :
10421 : /** Get a relationship from its name.
10422 : *
10423 : * @return the relationship, or nullptr if not found.
10424 : * @since GDAL 3.6
10425 : */
10426 : const GDALRelationship *
10427 0 : GDALDataset::GetRelationship(CPL_UNUSED const std::string &name) const
10428 : {
10429 0 : return nullptr;
10430 : }
10431 :
10432 : /************************************************************************/
10433 : /* GDALDatasetGetRelationship() */
10434 : /************************************************************************/
10435 :
10436 : /** Get a relationship from its name.
10437 : *
10438 : * This is the same as the C++ method GDALDataset::GetRelationship().
10439 : *
10440 : * @param hDS Dataset handle.
10441 : * @param pszName Name of relationship.
10442 : * @return the relationship (ownership remains to the dataset), or nullptr if
10443 : * not found.
10444 : * @since GDAL 3.6
10445 : */
10446 52 : GDALRelationshipH GDALDatasetGetRelationship(GDALDatasetH hDS,
10447 : const char *pszName)
10448 : {
10449 52 : VALIDATE_POINTER1(hDS, __func__, nullptr);
10450 52 : VALIDATE_POINTER1(pszName, __func__, nullptr);
10451 52 : return GDALRelationship::ToHandle(const_cast<GDALRelationship *>(
10452 52 : GDALDataset::FromHandle(hDS)->GetRelationship(pszName)));
10453 : }
10454 :
10455 : /************************************************************************/
10456 : /* AddRelationship() */
10457 : /************************************************************************/
10458 :
10459 : /** Add a relationship to the dataset.
10460 : *
10461 : * Only a few drivers will support this operation, and some of them might only
10462 : * support it only for some types of relationships.
10463 : *
10464 : * A dataset having at least some support for this
10465 : * operation should report the GDsCAddRelationship dataset capability.
10466 : *
10467 : * Anticipated failures will not be emitted through the CPLError()
10468 : * infrastructure, but will be reported in the failureReason output parameter.
10469 : *
10470 : * When adding a many-to-many relationship
10471 : * (GDALRelationshipCardinality::GRC_MANY_TO_MANY), it is possible to omit the
10472 : * mapping table name (see GDALRelationship::GetMappingTableName) to instruct
10473 : * the driver to create an appropriately named and structured mapping table.
10474 : * Some dataset formats require particular naming conventions and field
10475 : * structures for the mapping table, and delegating the construction of the
10476 : * mapping table to the driver will avoid these pitfalls.
10477 : *
10478 : * @param relationship The relationship definition.
10479 : * @param failureReason Output parameter. Will contain an error message if
10480 : * an error occurs.
10481 : * @return true in case of success.
10482 : * @since GDAL 3.6
10483 : */
10484 0 : bool GDALDataset::AddRelationship(
10485 : CPL_UNUSED std::unique_ptr<GDALRelationship> &&relationship,
10486 : std::string &failureReason)
10487 : {
10488 0 : failureReason = "AddRelationship not supported by this driver";
10489 0 : return false;
10490 : }
10491 :
10492 : /************************************************************************/
10493 : /* GDALDatasetAddRelationship() */
10494 : /************************************************************************/
10495 :
10496 : /** Add a relationship to the dataset.
10497 : *
10498 : * Only a few drivers will support this operation, and some of them might only
10499 : * support it only for some types of relationships.
10500 : *
10501 : * A dataset having at least some support for this
10502 : * operation should report the GDsCAddRelationship dataset capability.
10503 : *
10504 : * Anticipated failures will not be emitted through the CPLError()
10505 : * infrastructure, but will be reported in the failureReason output parameter.
10506 : *
10507 : * When adding a many-to-many relationship
10508 : * (GDALRelationshipCardinality::GRC_MANY_TO_MANY), it is possible to omit the
10509 : * mapping table name (see GDALRelationshipGetMappingTableName) to instruct the
10510 : * driver to create an appropriately named and structured mapping table. Some
10511 : * dataset formats require particular naming conventions and field structures
10512 : * for the mapping table, and delegating the construction of the mapping table
10513 : * to the driver will avoid these pitfalls.
10514 : *
10515 : * @param hDS Dataset handle.
10516 : * @param hRelationship The relationship definition. Contrary to the C++
10517 : * version, the passed object is copied.
10518 : * @param ppszFailureReason Output parameter. Will contain an error message if
10519 : * an error occurs (*ppszFailureReason to be freed
10520 : * with CPLFree). May be NULL.
10521 : * @return true in case of success.
10522 : * @since GDAL 3.6
10523 : */
10524 42 : bool GDALDatasetAddRelationship(GDALDatasetH hDS,
10525 : GDALRelationshipH hRelationship,
10526 : char **ppszFailureReason)
10527 : {
10528 42 : VALIDATE_POINTER1(hDS, __func__, false);
10529 42 : VALIDATE_POINTER1(hRelationship, __func__, false);
10530 : std::unique_ptr<GDALRelationship> poRelationship(
10531 84 : new GDALRelationship(*GDALRelationship::FromHandle(hRelationship)));
10532 42 : std::string failureReason;
10533 84 : const bool bRet = GDALDataset::FromHandle(hDS)->AddRelationship(
10534 42 : std::move(poRelationship), failureReason);
10535 42 : if (ppszFailureReason)
10536 : {
10537 0 : *ppszFailureReason =
10538 0 : failureReason.empty() ? nullptr : CPLStrdup(failureReason.c_str());
10539 : }
10540 42 : return bRet;
10541 : }
10542 :
10543 : /************************************************************************/
10544 : /* DeleteRelationship() */
10545 : /************************************************************************/
10546 :
10547 : /** Removes a relationship from the dataset.
10548 : *
10549 : * Only a few drivers will support this operation.
10550 : *
10551 : * A dataset having at least some support for this
10552 : * operation should report the GDsCDeleteRelationship dataset capability.
10553 : *
10554 : * Anticipated failures will not be emitted through the CPLError()
10555 : * infrastructure, but will be reported in the failureReason output parameter.
10556 : *
10557 : * @param name The relationship name.
10558 : * @param failureReason Output parameter. Will contain an error message if
10559 : * an error occurs.
10560 : * @return true in case of success.
10561 : * @since GDAL 3.6
10562 : */
10563 0 : bool GDALDataset::DeleteRelationship(CPL_UNUSED const std::string &name,
10564 : std::string &failureReason)
10565 : {
10566 0 : failureReason = "DeleteRelationship not supported by this driver";
10567 0 : return false;
10568 : }
10569 :
10570 : /************************************************************************/
10571 : /* GDALDatasetDeleteRelationship() */
10572 : /************************************************************************/
10573 :
10574 : /** Removes a relationship from the dataset.
10575 : *
10576 : * Only a few drivers will support this operation.
10577 : *
10578 : * A dataset having at least some support for this
10579 : * operation should report the GDsCDeleteRelationship dataset capability.
10580 : *
10581 : * Anticipated failures will not be emitted through the CPLError()
10582 : * infrastructure, but will be reported in the ppszFailureReason output
10583 : * parameter.
10584 : *
10585 : * @param hDS Dataset handle.
10586 : * @param pszName The relationship name.
10587 : * @param ppszFailureReason Output parameter. Will contain an error message if
10588 : * an error occurs (*ppszFailureReason to be freed
10589 : * with CPLFree). May be NULL.
10590 : * @return true in case of success.
10591 : * @since GDAL 3.6
10592 : */
10593 6 : bool GDALDatasetDeleteRelationship(GDALDatasetH hDS, const char *pszName,
10594 : char **ppszFailureReason)
10595 : {
10596 6 : VALIDATE_POINTER1(hDS, __func__, false);
10597 6 : VALIDATE_POINTER1(pszName, __func__, false);
10598 6 : std::string failureReason;
10599 12 : const bool bRet = GDALDataset::FromHandle(hDS)->DeleteRelationship(
10600 6 : pszName, failureReason);
10601 6 : if (ppszFailureReason)
10602 : {
10603 0 : *ppszFailureReason =
10604 0 : failureReason.empty() ? nullptr : CPLStrdup(failureReason.c_str());
10605 : }
10606 6 : return bRet;
10607 : }
10608 :
10609 : /************************************************************************/
10610 : /* UpdateRelationship() */
10611 : /************************************************************************/
10612 :
10613 : /** Updates an existing relationship by replacing its definition.
10614 : *
10615 : * The existing relationship with matching name will be replaced.
10616 : *
10617 : * Only a few drivers will support this operation, and some of them might only
10618 : * support it only for some types of relationships.
10619 : * A dataset having at least some support for this
10620 : * operation should report the GDsCUpdateRelationship dataset capability.
10621 : *
10622 : * Anticipated failures will not be emitted through the CPLError()
10623 : * infrastructure, but will be reported in the failureReason output parameter.
10624 : *
10625 : * @param relationship The relationship definition.
10626 : * @param failureReason Output parameter. Will contain an error message if
10627 : * an error occurs.
10628 : * @return true in case of success.
10629 : * @since GDAL 3.6
10630 : */
10631 0 : bool GDALDataset::UpdateRelationship(
10632 : CPL_UNUSED std::unique_ptr<GDALRelationship> &&relationship,
10633 : std::string &failureReason)
10634 : {
10635 0 : failureReason = "UpdateRelationship not supported by this driver";
10636 0 : return false;
10637 : }
10638 :
10639 : /************************************************************************/
10640 : /* GDALDatasetUpdateRelationship() */
10641 : /************************************************************************/
10642 :
10643 : /** Updates an existing relationship by replacing its definition.
10644 : *
10645 : * The existing relationship with matching name will be replaced.
10646 : *
10647 : * Only a few drivers will support this operation, and some of them might only
10648 : * support it only for some types of relationships.
10649 : * A dataset having at least some support for this
10650 : * operation should report the GDsCUpdateRelationship dataset capability.
10651 : *
10652 : * Anticipated failures will not be emitted through the CPLError()
10653 : * infrastructure, but will be reported in the failureReason output parameter.
10654 : *
10655 : * @param hDS Dataset handle.
10656 : * @param hRelationship The relationship definition. Contrary to the C++
10657 : * version, the passed object is copied.
10658 : * @param ppszFailureReason Output parameter. Will contain an error message if
10659 : * an error occurs (*ppszFailureReason to be freed
10660 : * with CPLFree). May be NULL.
10661 : * @return true in case of success.
10662 : * @since GDAL 3.5
10663 : */
10664 9 : bool GDALDatasetUpdateRelationship(GDALDatasetH hDS,
10665 : GDALRelationshipH hRelationship,
10666 : char **ppszFailureReason)
10667 : {
10668 9 : VALIDATE_POINTER1(hDS, __func__, false);
10669 9 : VALIDATE_POINTER1(hRelationship, __func__, false);
10670 : std::unique_ptr<GDALRelationship> poRelationship(
10671 18 : new GDALRelationship(*GDALRelationship::FromHandle(hRelationship)));
10672 9 : std::string failureReason;
10673 18 : const bool bRet = GDALDataset::FromHandle(hDS)->UpdateRelationship(
10674 9 : std::move(poRelationship), failureReason);
10675 9 : if (ppszFailureReason)
10676 : {
10677 0 : *ppszFailureReason =
10678 0 : failureReason.empty() ? nullptr : CPLStrdup(failureReason.c_str());
10679 : }
10680 9 : return bRet;
10681 : }
10682 :
10683 : /************************************************************************/
10684 : /* GDALDatasetSetQueryLoggerFunc() */
10685 : /************************************************************************/
10686 :
10687 : /**
10688 : * Sets the SQL query logger callback.
10689 : *
10690 : * When supported by the driver, the callback will be called with
10691 : * the executed SQL text, the error message, the execution time in milliseconds,
10692 : * the number of records fetched/affected and the client status data.
10693 : *
10694 : * A value of -1 in the execution time or in the number of records indicates
10695 : * that the values are unknown.
10696 : *
10697 : * @param hDS Dataset handle.
10698 : * @param pfnQueryLoggerFunc Callback function
10699 : * @param poQueryLoggerArg Opaque client status data
10700 : * @return true in case of success.
10701 : * @since GDAL 3.7
10702 : */
10703 1 : bool GDALDatasetSetQueryLoggerFunc(GDALDatasetH hDS,
10704 : GDALQueryLoggerFunc pfnQueryLoggerFunc,
10705 : void *poQueryLoggerArg)
10706 : {
10707 1 : VALIDATE_POINTER1(hDS, __func__, false);
10708 2 : return GDALDataset::FromHandle(hDS)->SetQueryLoggerFunc(pfnQueryLoggerFunc,
10709 1 : poQueryLoggerArg);
10710 : }
10711 :
10712 : //! @cond Doxygen_Suppress
10713 :
10714 : /************************************************************************/
10715 : /* SetEnableOverviews() */
10716 : /************************************************************************/
10717 :
10718 7531 : void GDALDataset::SetEnableOverviews(bool bEnable)
10719 : {
10720 7531 : if (m_poPrivate)
10721 : {
10722 7531 : m_poPrivate->m_bOverviewsEnabled = bEnable;
10723 : }
10724 7531 : }
10725 :
10726 : /************************************************************************/
10727 : /* AreOverviewsEnabled() */
10728 : /************************************************************************/
10729 :
10730 2007060 : bool GDALDataset::AreOverviewsEnabled() const
10731 : {
10732 2007060 : return m_poPrivate ? m_poPrivate->m_bOverviewsEnabled : true;
10733 : }
10734 :
10735 : /************************************************************************/
10736 : /* IsAllBands() */
10737 : /************************************************************************/
10738 :
10739 4200 : bool GDALDataset::IsAllBands(int nBandCount, const int *panBandList) const
10740 : {
10741 4200 : if (nBands != nBandCount)
10742 1 : return false;
10743 4199 : if (panBandList)
10744 : {
10745 15895 : for (int i = 0; i < nBandCount; ++i)
10746 : {
10747 11790 : if (panBandList[i] != i + 1)
10748 27 : return false;
10749 : }
10750 : }
10751 4172 : return true;
10752 : }
10753 :
10754 : //! @endcond
10755 :
10756 : /************************************************************************/
10757 : /* GetCompressionFormats() */
10758 : /************************************************************************/
10759 :
10760 : /** Return the compression formats that can be natively obtained for the
10761 : * window of interest and requested bands.
10762 : *
10763 : * For example, a tiled dataset may be able to return data in a compressed
10764 : * format if the window of interest matches exactly a tile. For some formats,
10765 : * drivers may also be able to merge several tiles together (not currently
10766 : * implemented though).
10767 : *
10768 : * Each format string is a pseudo MIME type, whose first part can be passed
10769 : * as the pszFormat argument of ReadCompressedData(), with additional
10770 : * parameters specified as key=value with a semi-colon separator.
10771 : *
10772 : * The amount and types of optional parameters passed after the MIME type is
10773 : * format dependent, and driver dependent (some drivers might not be able to
10774 : * return those extra information without doing a rather costly processing).
10775 : *
10776 : * For example, a driver might return "JPEG;frame_type=SOF0_baseline;"
10777 : * "bit_depth=8;num_components=3;subsampling=4:2:0;colorspace=YCbCr", and
10778 : * consequently "JPEG" can be passed as the pszFormat argument of
10779 : * ReadCompressedData(). For JPEG, implementations can use the
10780 : * GDALGetCompressionFormatForJPEG() helper method to generate a string like
10781 : * above from a JPEG codestream.
10782 : *
10783 : * Several values might be returned. For example,
10784 : * the JPEGXL driver will return "JXL", but also potentially "JPEG"
10785 : * if the JPEGXL codestream includes a JPEG reconstruction box.
10786 : *
10787 : * In the general case this method will return an empty list.
10788 : *
10789 : * This is the same as C function GDALDatasetGetCompressionFormats().
10790 : *
10791 : * @param nXOff The pixel offset to the top left corner of the region
10792 : * of the band to be accessed. This would be zero to start from the left side.
10793 : *
10794 : * @param nYOff The line offset to the top left corner of the region
10795 : * of the band to be accessed. This would be zero to start from the top.
10796 : *
10797 : * @param nXSize The width of the region of the band to be accessed in pixels.
10798 : *
10799 : * @param nYSize The height of the region of the band to be accessed in lines.
10800 : *
10801 : * @param nBandCount the number of bands being requested.
10802 : *
10803 : * @param panBandList the list of nBandCount band numbers.
10804 : * Note band numbers are 1 based. This may be NULL to select the first
10805 : * nBandCount bands.
10806 : *
10807 : * @return a list of compatible formats (which may be empty)
10808 : *
10809 : * For example, to check if native compression format(s) are available on the
10810 : * whole image:
10811 : * \code{.cpp}
10812 : * const CPLStringList aosFormats =
10813 : * poDataset->GetCompressionFormats(0, 0,
10814 : * poDataset->GetRasterXSize(),
10815 : * poDataset->GetRasterYSize(),
10816 : * poDataset->GetRasterCount(),
10817 : * nullptr);
10818 : * for( const char* pszFormat: aosFormats )
10819 : * {
10820 : * // Remove optional parameters and just print out the MIME type.
10821 : * const CPLStringList aosTokens(CSLTokenizeString2(pszFormat, ";", 0));
10822 : * printf("Found format %s\n, aosTokens[0]);
10823 : * }
10824 : * \endcode
10825 : *
10826 : * @since GDAL 3.7
10827 : */
10828 : CPLStringList
10829 0 : GDALDataset::GetCompressionFormats(CPL_UNUSED int nXOff, CPL_UNUSED int nYOff,
10830 : CPL_UNUSED int nXSize, CPL_UNUSED int nYSize,
10831 : CPL_UNUSED int nBandCount,
10832 : CPL_UNUSED const int *panBandList)
10833 : {
10834 0 : return CPLStringList();
10835 : }
10836 :
10837 : /************************************************************************/
10838 : /* GDALDatasetGetCompressionFormats() */
10839 : /************************************************************************/
10840 :
10841 : /** Return the compression formats that can be natively obtained for the
10842 : * window of interest and requested bands.
10843 : *
10844 : * For example, a tiled dataset may be able to return data in a compressed
10845 : * format if the window of interest matches exactly a tile. For some formats,
10846 : * drivers may also be able to merge several tiles together (not currently
10847 : * implemented though).
10848 : *
10849 : * Each format string is a pseudo MIME type, whose first part can be passed
10850 : * as the pszFormat argument of ReadCompressedData(), with additional
10851 : * parameters specified as key=value with a semi-colon separator.
10852 : *
10853 : * The amount and types of optional parameters passed after the MIME type is
10854 : * format dependent, and driver dependent (some drivers might not be able to
10855 : * return those extra information without doing a rather costly processing).
10856 : *
10857 : * For example, a driver might return "JPEG;frame_type=SOF0_baseline;"
10858 : * "bit_depth=8;num_components=3;subsampling=4:2:0;colorspace=YCbCr", and
10859 : * consequently "JPEG" can be passed as the pszFormat argument of
10860 : * ReadCompressedData(). For JPEG, implementations can use the
10861 : * GDALGetCompressionFormatForJPEG() helper method to generate a string like
10862 : * above from a JPEG codestream.
10863 : *
10864 : * Several values might be returned. For example,
10865 : * the JPEGXL driver will return "JXL", but also potentially "JPEG"
10866 : * if the JPEGXL codestream includes a JPEG reconstruction box.
10867 : *
10868 : * In the general case this method will return an empty list.
10869 : *
10870 : * This is the same as C++ method GDALDataset::GetCompressionFormats().
10871 : *
10872 : * @param hDS Dataset handle.
10873 : *
10874 : * @param nXOff The pixel offset to the top left corner of the region
10875 : * of the band to be accessed. This would be zero to start from the left side.
10876 : *
10877 : * @param nYOff The line offset to the top left corner of the region
10878 : * of the band to be accessed. This would be zero to start from the top.
10879 : *
10880 : * @param nXSize The width of the region of the band to be accessed in pixels.
10881 : *
10882 : * @param nYSize The height of the region of the band to be accessed in lines.
10883 : *
10884 : * @param nBandCount the number of bands being requested.
10885 : *
10886 : * @param panBandList the list of nBandCount band numbers.
10887 : * Note band numbers are 1 based. This may be NULL to select the first
10888 : * nBandCount bands.
10889 : *
10890 : * @return a list of compatible formats (which may be empty) that should be
10891 : * freed with CSLDestroy(), or nullptr.
10892 : *
10893 : * @since GDAL 3.7
10894 : */
10895 9 : char **GDALDatasetGetCompressionFormats(GDALDatasetH hDS, int nXOff, int nYOff,
10896 : int nXSize, int nYSize, int nBandCount,
10897 : const int *panBandList)
10898 : {
10899 9 : VALIDATE_POINTER1(hDS, __func__, nullptr);
10900 9 : return GDALDataset::FromHandle(hDS)
10901 9 : ->GetCompressionFormats(nXOff, nYOff, nXSize, nYSize, nBandCount,
10902 9 : panBandList)
10903 9 : .StealList();
10904 : }
10905 :
10906 : /************************************************************************/
10907 : /* ReadCompressedData() */
10908 : /************************************************************************/
10909 :
10910 : /** Return the compressed content that can be natively obtained for the
10911 : * window of interest and requested bands.
10912 : *
10913 : * For example, a tiled dataset may be able to return data in compressed format
10914 : * if the window of interest matches exactly a tile. For some formats, drivers
10915 : * may also be example to merge several tiles together (not currently
10916 : * implemented though).
10917 : *
10918 : * The implementation should make sure that the content returned forms a valid
10919 : * standalone file. For example, for the GeoTIFF implementation of this method,
10920 : * when extracting a JPEG tile, the method will automatically add the content
10921 : * of the JPEG Huffman and/or quantization tables that might be stored in the
10922 : * TIFF JpegTables tag, and not in tile data itself.
10923 : *
10924 : * In the general case this method will return CE_Failure.
10925 : *
10926 : * This is the same as C function GDALDatasetReadCompressedData().
10927 : *
10928 : * @param pszFormat Requested compression format (e.g. "JPEG",
10929 : * "WEBP", "JXL"). This is the MIME type of one of the values
10930 : * returned by GetCompressionFormats(). The format string is designed to
10931 : * potentially include at a later point key=value optional parameters separated
10932 : * by a semi-colon character. At time of writing, none are implemented.
10933 : * ReadCompressedData() implementations should verify optional parameters and
10934 : * return CE_Failure if they cannot support one of them.
10935 : *
10936 : * @param nXOff The pixel offset to the top left corner of the region
10937 : * of the band to be accessed. This would be zero to start from the left side.
10938 : *
10939 : * @param nYOff The line offset to the top left corner of the region
10940 : * of the band to be accessed. This would be zero to start from the top.
10941 : *
10942 : * @param nXSize The width of the region of the band to be accessed in pixels.
10943 : *
10944 : * @param nYSize The height of the region of the band to be accessed in lines.
10945 : *
10946 : * @param nBandCount the number of bands being requested.
10947 : *
10948 : * @param panBandList the list of nBandCount band numbers.
10949 : * Note band numbers are 1 based. This may be NULL to select the first
10950 : * nBandCount bands.
10951 : *
10952 : * @param ppBuffer Pointer to a buffer to store the compressed data or nullptr.
10953 : * If ppBuffer is not nullptr, then pnBufferSize should also not be nullptr.
10954 : * If ppBuffer is not nullptr, and *ppBuffer is not nullptr, then the provided
10955 : * buffer will be filled with the compressed data, provided that pnBufferSize
10956 : * and *pnBufferSize are not nullptr, and *pnBufferSize, indicating the size
10957 : * of *ppBuffer, is sufficiently large to hold the data.
10958 : * If ppBuffer is not nullptr, but *ppBuffer is nullptr, then the method will
10959 : * allocate *ppBuffer using VSIMalloc(), and thus the caller is responsible to
10960 : * free it with VSIFree().
10961 : * If ppBuffer is nullptr, then the compressed data itself will not be returned,
10962 : * but *pnBufferSize will be updated with an upper bound of the size that would
10963 : * be necessary to hold it (if pnBufferSize != nullptr).
10964 : *
10965 : * @param pnBufferSize Output buffer size, or nullptr.
10966 : * If ppBuffer != nullptr && *ppBuffer != nullptr, then pnBufferSize should
10967 : * be != nullptr and *pnBufferSize contain the size of *ppBuffer. If the
10968 : * method is successful, *pnBufferSize will be updated with the actual size
10969 : * used.
10970 : *
10971 : * @param ppszDetailedFormat Pointer to an output string, or nullptr.
10972 : * If ppszDetailedFormat is not nullptr, then, on success, the method will
10973 : * allocate a new string in *ppszDetailedFormat (to be freed with VSIFree())
10974 : * *ppszDetailedFormat might contain strings like
10975 : * "JPEG;frame_type=SOF0_baseline;bit_depth=8;num_components=3;"
10976 : * "subsampling=4:2:0;colorspace=YCbCr" or simply the MIME type.
10977 : * The string will contain at least as much information as what
10978 : * GetCompressionFormats() returns, and potentially more when
10979 : * ppBuffer != nullptr.
10980 : *
10981 : * @return CE_None in case of success, CE_Failure otherwise.
10982 : *
10983 : * For example, to request JPEG content on the whole image and let GDAL deal
10984 : * with the buffer allocation.
10985 : * \code{.cpp}
10986 : * void* pBuffer = nullptr;
10987 : * size_t nBufferSize = 0;
10988 : * CPLErr eErr =
10989 : * poDataset->ReadCompressedData("JPEG",
10990 : * 0, 0,
10991 : * poDataset->GetRasterXSize(),
10992 : * poDataset->GetRasterYSize(),
10993 : * poDataset->GetRasterCount(),
10994 : * nullptr, // panBandList
10995 : * &pBuffer,
10996 : * &nBufferSize,
10997 : * nullptr // ppszDetailedFormat
10998 : * );
10999 : * if (eErr == CE_None)
11000 : * {
11001 : * CPLAssert(pBuffer != nullptr);
11002 : * CPLAssert(nBufferSize > 0);
11003 : * VSILFILE* fp = VSIFOpenL("my.jpeg", "wb");
11004 : * if (fp)
11005 : * {
11006 : * VSIFWriteL(pBuffer, nBufferSize, 1, fp);
11007 : * VSIFCloseL(fp);
11008 : * }
11009 : * VSIFree(pBuffer);
11010 : * }
11011 : * \endcode
11012 : *
11013 : * Or to manage the buffer allocation on your side:
11014 : * \code{.cpp}
11015 : * size_t nUpperBoundBufferSize = 0;
11016 : * CPLErr eErr =
11017 : * poDataset->ReadCompressedData("JPEG",
11018 : * 0, 0,
11019 : * poDataset->GetRasterXSize(),
11020 : * poDataset->GetRasterYSize(),
11021 : * poDataset->GetRasterCount(),
11022 : * nullptr, // panBandList
11023 : * nullptr, // ppBuffer,
11024 : * &nUpperBoundBufferSize,
11025 : * nullptr // ppszDetailedFormat
11026 : * );
11027 : * if (eErr == CE_None)
11028 : * {
11029 : * std::vector<uint8_t> myBuffer;
11030 : * myBuffer.resize(nUpperBoundBufferSize);
11031 : * void* pBuffer = myBuffer.data();
11032 : * size_t nActualSize = nUpperBoundBufferSize;
11033 : * char* pszDetailedFormat = nullptr;
11034 : * // We also request detailed format, but we could have passed it to
11035 : * // nullptr as well.
11036 : * eErr =
11037 : * poDataset->ReadCompressedData("JPEG",
11038 : * 0, 0,
11039 : * poDataset->GetRasterXSize(),
11040 : * poDataset->GetRasterYSize(),
11041 : * poDataset->GetRasterCount(),
11042 : * nullptr, // panBandList
11043 : * &pBuffer,
11044 : * &nActualSize,
11045 : * &pszDetailedFormat);
11046 : * if (eErr == CE_None)
11047 : * {
11048 : * CPLAssert(pBuffer == myBuffer.data()); // pointed value not modified
11049 : * CPLAssert(nActualSize <= nUpperBoundBufferSize);
11050 : * myBuffer.resize(nActualSize);
11051 : * // do something useful
11052 : * VSIFree(pszDetailedFormat);
11053 : * }
11054 : * }
11055 : * \endcode
11056 : *
11057 : * @since GDAL 3.7
11058 : */
11059 441 : CPLErr GDALDataset::ReadCompressedData(
11060 : CPL_UNUSED const char *pszFormat, CPL_UNUSED int nXOff,
11061 : CPL_UNUSED int nYOff, CPL_UNUSED int nXSize, CPL_UNUSED int nYSize,
11062 : CPL_UNUSED int nBandCount, CPL_UNUSED const int *panBandList,
11063 : CPL_UNUSED void **ppBuffer, CPL_UNUSED size_t *pnBufferSize,
11064 : CPL_UNUSED char **ppszDetailedFormat)
11065 : {
11066 441 : return CE_Failure;
11067 : }
11068 :
11069 : /************************************************************************/
11070 : /* GDALDatasetReadCompressedData() */
11071 : /************************************************************************/
11072 :
11073 : /** Return the compressed content that can be natively obtained for the
11074 : * window of interest and requested bands.
11075 : *
11076 : * For example, a tiled dataset may be able to return data in compressed format
11077 : * if the window of interest matches exactly a tile. For some formats, drivers
11078 : * may also be example to merge several tiles together (not currently
11079 : * implemented though).
11080 : *
11081 : * The implementation should make sure that the content returned forms a valid
11082 : * standalone file. For example, for the GeoTIFF implementation of this method,
11083 : * when extracting a JPEG tile, the method will automatically adds the content
11084 : * of the JPEG Huffman and/or quantization tables that might be stored in the
11085 : * TIFF JpegTables tag, and not in tile data itself.
11086 : *
11087 : * In the general case this method will return CE_Failure.
11088 : *
11089 : * This is the same as C++ method GDALDataset:ReadCompressedData().
11090 : *
11091 : * @param hDS Dataset handle.
11092 : *
11093 : * @param pszFormat Requested compression format (e.g. "JPEG",
11094 : * "WEBP", "JXL"). This is the MIME type of one of the values
11095 : * returned by GetCompressionFormats(). The format string is designed to
11096 : * potentially include at a later point key=value optional parameters separated
11097 : * by a semi-colon character. At time of writing, none are implemented.
11098 : * ReadCompressedData() implementations should verify optional parameters and
11099 : * return CE_Failure if they cannot support one of them.
11100 : *
11101 : * @param nXOff The pixel offset to the top left corner of the region
11102 : * of the band to be accessed. This would be zero to start from the left side.
11103 : *
11104 : * @param nYOff The line offset to the top left corner of the region
11105 : * of the band to be accessed. This would be zero to start from the top.
11106 : *
11107 : * @param nXSize The width of the region of the band to be accessed in pixels.
11108 : *
11109 : * @param nYSize The height of the region of the band to be accessed in lines.
11110 : *
11111 : * @param nBandCount the number of bands being requested.
11112 : *
11113 : * @param panBandList the list of nBandCount band numbers.
11114 : * Note band numbers are 1 based. This may be NULL to select the first
11115 : * nBandCount bands.
11116 : *
11117 : * @param ppBuffer Pointer to a buffer to store the compressed data or nullptr.
11118 : * If ppBuffer is not nullptr, then pnBufferSize should also not be nullptr.
11119 : * If ppBuffer is not nullptr, and *ppBuffer is not nullptr, then the provided
11120 : * buffer will be filled with the compressed data, provided that pnBufferSize
11121 : * and *pnBufferSize are not nullptr, and *pnBufferSize, indicating the size
11122 : * of *ppBuffer, is sufficiently large to hold the data.
11123 : * If ppBuffer is not nullptr, but *ppBuffer is nullptr, then the method will
11124 : * allocate *ppBuffer using VSIMalloc(), and thus the caller is responsible to
11125 : * free it with VSIFree().
11126 : * If ppBuffer is nullptr, then the compressed data itself will not be returned,
11127 : * but *pnBufferSize will be updated with an upper bound of the size that would
11128 : * be necessary to hold it (if pnBufferSize != nullptr).
11129 : *
11130 : * @param pnBufferSize Output buffer size, or nullptr.
11131 : * If ppBuffer != nullptr && *ppBuffer != nullptr, then pnBufferSize should
11132 : * be != nullptr and *pnBufferSize contain the size of *ppBuffer. If the
11133 : * method is successful, *pnBufferSize will be updated with the actual size
11134 : * used.
11135 : *
11136 : * @param ppszDetailedFormat Pointer to an output string, or nullptr.
11137 : * If ppszDetailedFormat is not nullptr, then, on success, the method will
11138 : * allocate a new string in *ppszDetailedFormat (to be freed with VSIFree())
11139 : * *ppszDetailedFormat might contain strings like
11140 : * "JPEG;frame_type=SOF0_baseline;bit_depth=8;num_components=3;"
11141 : * "subsampling=4:2:0;colorspace=YCbCr" or simply the MIME type.
11142 : * The string will contain at least as much information as what
11143 : * GetCompressionFormats() returns, and potentially more when
11144 : * ppBuffer != nullptr.
11145 : *
11146 : * @return CE_None in case of success, CE_Failure otherwise.
11147 : *
11148 : * @since GDAL 3.7
11149 : */
11150 28 : CPLErr GDALDatasetReadCompressedData(GDALDatasetH hDS, const char *pszFormat,
11151 : int nXOff, int nYOff, int nXSize,
11152 : int nYSize, int nBandCount,
11153 : const int *panBandList, void **ppBuffer,
11154 : size_t *pnBufferSize,
11155 : char **ppszDetailedFormat)
11156 : {
11157 28 : VALIDATE_POINTER1(hDS, __func__, CE_Failure);
11158 56 : return GDALDataset::FromHandle(hDS)->ReadCompressedData(
11159 : pszFormat, nXOff, nYOff, nXSize, nYSize, nBandCount, panBandList,
11160 28 : ppBuffer, pnBufferSize, ppszDetailedFormat);
11161 : }
11162 :
11163 : /************************************************************************/
11164 : /* CanBeCloned() */
11165 : /************************************************************************/
11166 :
11167 : //! @cond Doxygen_Suppress
11168 :
11169 : /** This method is called by GDALThreadSafeDataset::Create() to determine if
11170 : * it is possible to create a thread-safe wrapper for a dataset, which involves
11171 : * the ability to Clone() it.
11172 : *
11173 : * Implementations of this method must be thread-safe.
11174 : *
11175 : * @param nScopeFlags Combination of GDAL_OF_RASTER, GDAL_OF_VECTOR, etc. flags,
11176 : * expressing the intended use for thread-safety.
11177 : * Currently, the only valid scope is in the base
11178 : * implementation is GDAL_OF_RASTER.
11179 : * @param bCanShareState Determines if cloned datasets are allowed to share
11180 : * state with the dataset they have been cloned from.
11181 : * If set to true, the dataset from which they have been
11182 : * cloned from must remain opened during the lifetime of
11183 : * its clones.
11184 : * @return true if the Clone() method is expected to succeed with the same values
11185 : * of nScopeFlags and bCanShareState.
11186 : */
11187 149 : bool GDALDataset::CanBeCloned(int nScopeFlags,
11188 : [[maybe_unused]] bool bCanShareState) const
11189 : {
11190 149 : return m_bCanBeReopened && nScopeFlags == GDAL_OF_RASTER;
11191 : }
11192 :
11193 : //! @endcond
11194 :
11195 : /************************************************************************/
11196 : /* Clone() */
11197 : /************************************************************************/
11198 :
11199 : //! @cond Doxygen_Suppress
11200 :
11201 : /** This method "clones" the current dataset, that is it returns a new instance
11202 : * that is opened on the same underlying "file".
11203 : *
11204 : * The base implementation uses GDALDataset::Open() to re-open the dataset.
11205 : * The MEM driver has a specialized implementation that returns a new instance,
11206 : * but which shares the same memory buffer as this.
11207 : *
11208 : * Implementations of this method must be thread-safe.
11209 : *
11210 : * @param nScopeFlags Combination of GDAL_OF_RASTER, GDAL_OF_VECTOR, etc. flags,
11211 : * expressing the intended use for thread-safety.
11212 : * Currently, the only valid scope is in the base
11213 : * implementation is GDAL_OF_RASTER.
11214 : * @param bCanShareState Determines if cloned datasets are allowed to share
11215 : * state with the dataset they have been cloned from.
11216 : * If set to true, the dataset from which they have been
11217 : * cloned from must remain opened during the lifetime of
11218 : * its clones.
11219 : * @return a new instance, or nullptr in case of error.
11220 : */
11221 : std::unique_ptr<GDALDataset>
11222 2051 : GDALDataset::Clone(int nScopeFlags, [[maybe_unused]] bool bCanShareState) const
11223 : {
11224 4102 : CPLStringList aosAllowedDrivers;
11225 2051 : if (poDriver)
11226 2051 : aosAllowedDrivers.AddString(poDriver->GetDescription());
11227 : return std::unique_ptr<GDALDataset>(GDALDataset::Open(
11228 2051 : GetDescription(),
11229 2051 : nScopeFlags | GDAL_OF_INTERNAL | GDAL_OF_VERBOSE_ERROR,
11230 4102 : aosAllowedDrivers.List(), papszOpenOptions));
11231 : }
11232 :
11233 : //! @endcond
11234 :
11235 : /************************************************************************/
11236 : /* GeolocationToPixelLine() */
11237 : /************************************************************************/
11238 :
11239 : /** Transform georeferenced coordinates to pixel/line coordinates.
11240 : *
11241 : * When poSRS is null, those georeferenced coordinates (dfGeolocX, dfGeolocY)
11242 : * must be in the "natural" SRS of the dataset, that is the one returned by
11243 : * GetSpatialRef() if there is a geotransform, GetGCPSpatialRef() if there are
11244 : * GCPs, WGS 84 if there are RPC coefficients, or the SRS of the geolocation
11245 : * array (generally WGS 84) if there is a geolocation array.
11246 : * If that natural SRS is a geographic one, dfGeolocX must be a longitude, and
11247 : * dfGeolocY a latitude. If that natural SRS is a projected one, dfGeolocX must
11248 : * be a easting, and dfGeolocY a northing.
11249 : *
11250 : * When poSRS is set to a non-null value, (dfGeolocX, dfGeolocY) must be
11251 : * expressed in that CRS, and that tuple must be conformant with the
11252 : * data-axis-to-crs-axis setting of poSRS, that is the one returned by
11253 : * the OGRSpatialReference::GetDataAxisToSRSAxisMapping(). If you want to be sure
11254 : * of the axis order, then make sure to call poSRS->SetAxisMappingStrategy(OAMS_TRADITIONAL_GIS_ORDER)
11255 : * before calling this method, and in that case, dfGeolocX must be a longitude
11256 : * or an easting value, and dfGeolocX a latitude or a northing value.
11257 : *
11258 : * This method uses GDALCreateGenImgProjTransformer2() underneath.
11259 : *
11260 : * @param dfGeolocX X coordinate of the position (longitude or easting if poSRS
11261 : * is null, otherwise consistent with poSRS data-axis-to-crs-axis mapping),
11262 : * where interpolation should be done.
11263 : * @param dfGeolocY Y coordinate of the position (latitude or northing if poSRS
11264 : * is null, otherwise consistent with poSRS data-axis-to-crs-axis mapping),
11265 : * where interpolation should be done.
11266 : * @param poSRS If set, override the natural CRS in which dfGeolocX, dfGeolocY are expressed
11267 : * @param[out] pdfPixel Pointer to the variable where to the store the pixel/column coordinate.
11268 : * @param[out] pdfLine Pointer to the variable where to the store the line coordinate.
11269 : * @param papszTransformerOptions Options accepted by GDALCreateGenImgProjTransformer2(), or nullptr.
11270 : *
11271 : * @return CE_None on success, or an error code on failure.
11272 : * @since GDAL 3.11
11273 : */
11274 :
11275 : CPLErr
11276 15 : GDALDataset::GeolocationToPixelLine(double dfGeolocX, double dfGeolocY,
11277 : const OGRSpatialReference *poSRS,
11278 : double *pdfPixel, double *pdfLine,
11279 : CSLConstList papszTransformerOptions) const
11280 : {
11281 30 : CPLStringList aosTO(papszTransformerOptions);
11282 :
11283 15 : if (poSRS)
11284 : {
11285 4 : const char *const apszOptions[] = {"FORMAT=WKT2", nullptr};
11286 8 : const std::string osWKT = poSRS->exportToWkt(apszOptions);
11287 4 : aosTO.SetNameValue("DST_SRS", osWKT.c_str());
11288 4 : const auto eAxisMappingStrategy = poSRS->GetAxisMappingStrategy();
11289 4 : if (eAxisMappingStrategy == OAMS_TRADITIONAL_GIS_ORDER)
11290 : aosTO.SetNameValue("DST_SRS_AXIS_MAPPING_STRATEGY",
11291 1 : "TRADITIONAL_GIS_ORDER");
11292 3 : else if (eAxisMappingStrategy == OAMS_AUTHORITY_COMPLIANT)
11293 : aosTO.SetNameValue("DST_SRS_AXIS_MAPPING_STRATEGY",
11294 1 : "AUTHORITY_COMPLIANT");
11295 : else
11296 : {
11297 2 : const auto &anValues = poSRS->GetDataAxisToSRSAxisMapping();
11298 4 : std::string osVal;
11299 6 : for (int v : anValues)
11300 : {
11301 4 : if (!osVal.empty())
11302 2 : osVal += ',';
11303 4 : osVal += std::to_string(v);
11304 : }
11305 : aosTO.SetNameValue("DST_SRS_DATA_AXIS_TO_SRS_AXIS_MAPPING",
11306 2 : osVal.c_str());
11307 : }
11308 : }
11309 :
11310 15 : auto hTransformer = GDALCreateGenImgProjTransformer2(
11311 : GDALDataset::ToHandle(const_cast<GDALDataset *>(this)), nullptr,
11312 15 : aosTO.List());
11313 15 : if (hTransformer == nullptr)
11314 : {
11315 1 : return CE_Failure;
11316 : }
11317 :
11318 14 : double z = 0;
11319 14 : int bSuccess = 0;
11320 14 : GDALGenImgProjTransform(hTransformer, TRUE, 1, &dfGeolocX, &dfGeolocY, &z,
11321 : &bSuccess);
11322 14 : GDALDestroyTransformer(hTransformer);
11323 14 : if (bSuccess)
11324 : {
11325 14 : if (pdfPixel)
11326 14 : *pdfPixel = dfGeolocX;
11327 14 : if (pdfLine)
11328 14 : *pdfLine = dfGeolocY;
11329 14 : return CE_None;
11330 : }
11331 : else
11332 : {
11333 0 : return CE_Failure;
11334 : }
11335 : }
11336 :
11337 : /************************************************************************/
11338 : /* GDALDatasetGeolocationToPixelLine() */
11339 : /************************************************************************/
11340 :
11341 : /** Transform georeferenced coordinates to pixel/line coordinates.
11342 : *
11343 : * @see GDALDataset::GeolocationToPixelLine()
11344 : * @since GDAL 3.11
11345 : */
11346 :
11347 0 : CPLErr GDALDatasetGeolocationToPixelLine(GDALDatasetH hDS, double dfGeolocX,
11348 : double dfGeolocY,
11349 : OGRSpatialReferenceH hSRS,
11350 : double *pdfPixel, double *pdfLine,
11351 : CSLConstList papszTransformerOptions)
11352 : {
11353 0 : VALIDATE_POINTER1(hDS, "GDALDatasetGeolocationToPixelLine", CE_Failure);
11354 :
11355 0 : GDALDataset *poDS = GDALDataset::FromHandle(hDS);
11356 0 : return poDS->GeolocationToPixelLine(
11357 0 : dfGeolocX, dfGeolocY, OGRSpatialReference::FromHandle(hSRS), pdfPixel,
11358 0 : pdfLine, papszTransformerOptions);
11359 : }
11360 :
11361 : /************************************************************************/
11362 : /* GetExtent() */
11363 : /************************************************************************/
11364 :
11365 : /** Return extent of dataset in specified CRS.
11366 : *
11367 : * OGREnvelope.MinX/MaxX represents longitudes, and MinY/MaxY latitudes.
11368 : *
11369 : * For rasters, the base implementation of this method only succeeds if
11370 : * GetGeoTransform() and GetSpatialRef() succeed.
11371 : * For vectors, the base implementation of this method iterates over layers
11372 : * and call their OGRLayer::GetExtent() method.
11373 : *
11374 : * TestCapability(GDsCFastGetExtent) can be used to test if the execution
11375 : * time of this method is fast.
11376 : *
11377 : * This is the same as C function GDALGetExtent()
11378 : *
11379 : * @param[out] psExtent Pointer to output extent. Must NOT be null.
11380 : * @param poCRS CRS in which to express the extent. If not specified, this will
11381 : * be the raster CRS or the CRS of the first layer for a vector dataset.
11382 : * @return CE_None in case of success, CE_Failure otherwise
11383 : * @since GDAL 3.12
11384 : */
11385 :
11386 456 : CPLErr GDALDataset::GetExtent(OGREnvelope *psExtent,
11387 : const OGRSpatialReference *poCRS) const
11388 : {
11389 456 : const OGRSpatialReference *poThisCRS = GetSpatialRefRasterOnly();
11390 456 : int nLayerCount = 0;
11391 456 : if (!poThisCRS)
11392 : {
11393 93 : nLayerCount = GetLayerCount();
11394 93 : if (nLayerCount >= 1)
11395 : {
11396 3 : if (auto poLayer = GetLayer(0))
11397 3 : poThisCRS = poLayer->GetSpatialRef();
11398 : }
11399 : }
11400 456 : if (!poCRS)
11401 246 : poCRS = poThisCRS;
11402 210 : else if (!poThisCRS)
11403 3 : return CE_Failure;
11404 :
11405 453 : *psExtent = OGREnvelope();
11406 :
11407 453 : GDALGeoTransform gt;
11408 453 : auto poThisDS = const_cast<GDALDataset *>(this);
11409 453 : const bool bHasGT = poThisDS->GetGeoTransform(gt) == CE_None;
11410 453 : if (bHasGT)
11411 : {
11412 0 : std::unique_ptr<OGRCoordinateTransformation> poCT;
11413 448 : if (poCRS)
11414 : {
11415 363 : poCT.reset(OGRCreateCoordinateTransformation(poThisCRS, poCRS));
11416 : }
11417 :
11418 448 : constexpr int DENSIFY_POINT_COUNT = 21;
11419 448 : double dfULX = gt.xorig;
11420 448 : double dfULY = gt.yorig;
11421 448 : double dfURX = 0, dfURY = 0;
11422 448 : gt.Apply(nRasterXSize, 0, &dfURX, &dfURY);
11423 448 : double dfLLX = 0, dfLLY = 0;
11424 448 : gt.Apply(0, nRasterYSize, &dfLLX, &dfLLY);
11425 448 : double dfLRX = 0, dfLRY = 0;
11426 448 : gt.Apply(nRasterXSize, nRasterYSize, &dfLRX, &dfLRY);
11427 448 : const double xmin = std::min({dfULX, dfURX, dfLLX, dfLRX});
11428 448 : const double ymin = std::min({dfULY, dfURY, dfLLY, dfLRY});
11429 448 : const double xmax = std::max({dfULX, dfURX, dfLLX, dfLRX});
11430 448 : const double ymax = std::max({dfULY, dfURY, dfLLY, dfLRY});
11431 448 : if (poCT)
11432 : {
11433 361 : OGREnvelope sEnvTmp;
11434 722 : if (!poCT->TransformBounds(xmin, ymin, xmax, ymax, &(sEnvTmp.MinX),
11435 : &(sEnvTmp.MinY), &(sEnvTmp.MaxX),
11436 361 : &(sEnvTmp.MaxY), DENSIFY_POINT_COUNT))
11437 : {
11438 0 : return CE_Failure;
11439 : }
11440 361 : *psExtent = sEnvTmp;
11441 : }
11442 : else
11443 : {
11444 87 : psExtent->MinX = xmin;
11445 87 : psExtent->MinY = ymin;
11446 87 : psExtent->MaxX = xmax;
11447 87 : psExtent->MaxY = ymax;
11448 : }
11449 : }
11450 :
11451 453 : if (nLayerCount > 0)
11452 : {
11453 6 : for (auto &&poLayer : poThisDS->GetLayers())
11454 : {
11455 3 : auto poLayerCRS = poLayer->GetSpatialRef();
11456 3 : if (poLayerCRS)
11457 : {
11458 3 : OGREnvelope sLayerExtent;
11459 3 : if (poLayer->GetExtent(&sLayerExtent) == OGRERR_NONE)
11460 : {
11461 : auto poCT = std::unique_ptr<OGRCoordinateTransformation>(
11462 6 : OGRCreateCoordinateTransformation(poLayerCRS, poCRS));
11463 3 : if (poCT)
11464 : {
11465 3 : constexpr int DENSIFY_POINT_COUNT = 21;
11466 3 : OGREnvelope sEnvTmp;
11467 3 : if (poCT->TransformBounds(
11468 : sLayerExtent.MinX, sLayerExtent.MinY,
11469 : sLayerExtent.MaxX, sLayerExtent.MaxY,
11470 : &(sEnvTmp.MinX), &(sEnvTmp.MinY),
11471 : &(sEnvTmp.MaxX), &(sEnvTmp.MaxY),
11472 3 : DENSIFY_POINT_COUNT))
11473 : {
11474 3 : psExtent->Merge(sEnvTmp);
11475 : }
11476 : }
11477 : }
11478 : }
11479 : }
11480 : }
11481 :
11482 453 : return psExtent->IsInit() ? CE_None : CE_Failure;
11483 : }
11484 :
11485 : /************************************************************************/
11486 : /* GDALGetExtent() */
11487 : /************************************************************************/
11488 :
11489 : /** Return extent of dataset in specified CRS.
11490 : *
11491 : * OGREnvelope.MinX/MaxX represents longitudes, and MinY/MaxY latitudes.
11492 : *
11493 : * For rasters, the base implementation of this method only succeeds if
11494 : * GetGeoTransform() and GetSpatialRef() succeed.
11495 : * For vectors, the base implementation of this method iterates over layers
11496 : * and call their OGRLayer::GetExtent() method.
11497 : *
11498 : * TestCapability(GDsCFastGetExtent) can be used to test if the execution
11499 : * time of this method is fast.
11500 : *
11501 : * This is the same as C++ method GDALDataset::GetExtent()
11502 : *
11503 : * @param hDS Dataset handle. Must NOT be null.
11504 : * @param[out] psExtent Pointer to output extent. Must NOT be null.
11505 : * @param hCRS CRS in which to express the extent. If not specified, this will
11506 : * be the raster CRS or the CRS of the first layer for a vector dataset.
11507 : * @return extent in poCRS (valid only if IsInit() method returns true)
11508 : * @since GDAL 3.12
11509 : */
11510 :
11511 28 : CPLErr GDALGetExtent(GDALDatasetH hDS, OGREnvelope *psExtent,
11512 : OGRSpatialReferenceH hCRS)
11513 : {
11514 28 : VALIDATE_POINTER1(hDS, __func__, CE_Failure);
11515 28 : VALIDATE_POINTER1(psExtent, __func__, CE_Failure);
11516 56 : return GDALDataset::FromHandle(hDS)->GetExtent(
11517 28 : psExtent, OGRSpatialReference::FromHandle(hCRS));
11518 : }
11519 :
11520 : /************************************************************************/
11521 : /* GetExtentWGS84LongLat() */
11522 : /************************************************************************/
11523 :
11524 : /** Return extent of dataset in WGS84 longitude/latitude
11525 : *
11526 : * OGREnvelope.MinX/MaxX represents longitudes, and MinY/MaxY latitudes.
11527 : *
11528 : * TestCapability(GDsCFastGetExtentWGS84LongLat) can be used to test if the execution
11529 : * time of this method is fast.
11530 : *
11531 : * This is the same as C function GDALGetExtentWGS84LongLat()
11532 : *
11533 : * @return extent (valid only if IsInit() method returns true)
11534 : * @since GDAL 3.12
11535 : */
11536 :
11537 208 : CPLErr GDALDataset::GetExtentWGS84LongLat(OGREnvelope *psExtent) const
11538 : {
11539 416 : OGRSpatialReference oSRS_WGS84;
11540 208 : oSRS_WGS84.SetFromUserInput("WGS84");
11541 208 : oSRS_WGS84.SetAxisMappingStrategy(OAMS_TRADITIONAL_GIS_ORDER);
11542 416 : return GetExtent(psExtent, &oSRS_WGS84);
11543 : }
11544 :
11545 : /************************************************************************/
11546 : /* GDALGetExtentWGS84LongLat() */
11547 : /************************************************************************/
11548 :
11549 : /** Return extent of dataset in WGS84 longitude/latitude
11550 : *
11551 : * OGREnvelope.MinX/MaxX represents longitudes, and MinY/MaxY latitudes.
11552 : *
11553 : * TestCapability(GDsCFastGetExtentWGS84LongLat) can be used to test if the execution
11554 : * time of this method is fast.
11555 : *
11556 : * This is the same as C++ method GDALDataset::GetExtentWGS84LongLat()
11557 : *
11558 : * @param hDS Dataset handle. Must NOT be null.
11559 : * @param[out] psExtent Pointer to output extent. Must NOT be null.
11560 : * @return extent (valid only if IsInit() method returns true)
11561 : * @since GDAL 3.12
11562 : */
11563 :
11564 5 : CPLErr GDALGetExtentWGS84LongLat(GDALDatasetH hDS, OGREnvelope *psExtent)
11565 : {
11566 5 : VALIDATE_POINTER1(hDS, __func__, CE_Failure);
11567 5 : VALIDATE_POINTER1(psExtent, __func__, CE_Failure);
11568 5 : return GDALDataset::FromHandle(hDS)->GetExtentWGS84LongLat(psExtent);
11569 : }
11570 :
11571 : /************************************************************************/
11572 : /* ReportUpdateNotSupportedByDriver() */
11573 : /************************************************************************/
11574 :
11575 : //! @cond Doxygen_Suppress
11576 :
11577 : /* static */
11578 1 : void GDALDataset::ReportUpdateNotSupportedByDriver(const char *pszDriverName)
11579 : {
11580 1 : CPLError(CE_Failure, CPLE_NotSupported,
11581 : "The %s driver does not support update access to existing "
11582 : "datasets.",
11583 : pszDriverName);
11584 1 : }
11585 :
11586 : //! @endcond
11587 :
11588 : /************************************************************************/
11589 : /* BuildFilename() */
11590 : /************************************************************************/
11591 :
11592 : /** Generates a filename, potentially relative to another one.
11593 : *
11594 : * Given the path to a reference directory, and a path to a file
11595 : * referenced from it, build a path to the file that the current application
11596 : * can use. If the file path is already absolute, rather than relative, or if
11597 : * bRelativeToReferencePath is false, then the filename of interest will be
11598 : * returned unaltered.
11599 : *
11600 : * This is enhanced version of CPLProjectRelativeFilenameSafe() that takes
11601 : * into account the subdataset syntax.
11602 : *
11603 : * Examples:
11604 : * \code{.cpp}
11605 : * BuildFilename("tmp/abc.gif", "abc/def", true) == "abc/def/tmp/abc.gif"
11606 : * BuildFilename("../abc.gif", "/abc/def") == "/abc/abc.gif"
11607 : * BuildFilename("abc.gif", "C:\WIN", true) == "C:\WIN\abc.gif"
11608 : * BuildFilename("abc.gif", "C:\WIN", false) == "abc.gif"
11609 : * BuildFilename("/home/even/foo.tif", "/home/even/workdir", true) == "/home/even/foo.tif"
11610 : * \endcode
11611 : *
11612 : * @param pszFilename Filename of interest.
11613 : * @param pszReferencePath Path to a reference directory.
11614 : * @param bRelativeToReferencePath Whether pszFilename, if a relative path, is
11615 : * relative to pszReferencePath
11616 : * @since 3.11
11617 : */
11618 :
11619 : /* static */
11620 104296 : std::string GDALDataset::BuildFilename(const char *pszFilename,
11621 : const char *pszReferencePath,
11622 : bool bRelativeToReferencePath)
11623 : {
11624 104296 : std::string osSrcDSName;
11625 104296 : if (pszReferencePath != nullptr && bRelativeToReferencePath)
11626 : {
11627 : // Try subdatasetinfo API first
11628 : // Note: this will become the only branch when subdatasetinfo will become
11629 : // available for NITF_IM, RASTERLITE and TILEDB
11630 2594 : const auto oSubDSInfo{GDALGetSubdatasetInfo(pszFilename)};
11631 2594 : if (oSubDSInfo && !oSubDSInfo->GetPathComponent().empty())
11632 : {
11633 8 : auto path{oSubDSInfo->GetPathComponent()};
11634 12 : osSrcDSName = oSubDSInfo->ModifyPathComponent(
11635 8 : CPLProjectRelativeFilenameSafe(pszReferencePath, path.c_str())
11636 4 : .c_str());
11637 4 : GDALDestroySubdatasetInfo(oSubDSInfo);
11638 : }
11639 : else
11640 : {
11641 2590 : bool bDone = false;
11642 15525 : for (const char *pszSyntax : apszSpecialSubDatasetSyntax)
11643 : {
11644 12938 : CPLString osPrefix(pszSyntax);
11645 12938 : osPrefix.resize(strchr(pszSyntax, ':') - pszSyntax + 1);
11646 12938 : if (pszSyntax[osPrefix.size()] == '"')
11647 2587 : osPrefix += '"';
11648 12938 : if (EQUALN(pszFilename, osPrefix, osPrefix.size()))
11649 : {
11650 3 : if (STARTS_WITH_CI(pszSyntax + osPrefix.size(), "{ANY}"))
11651 : {
11652 3 : const char *pszLastPart = strrchr(pszFilename, ':') + 1;
11653 : // CSV:z:/foo.xyz
11654 3 : if ((pszLastPart[0] == '/' || pszLastPart[0] == '\\') &&
11655 0 : pszLastPart - pszFilename >= 3 &&
11656 0 : pszLastPart[-3] == ':')
11657 : {
11658 0 : pszLastPart -= 2;
11659 : }
11660 3 : CPLString osPrefixFilename = pszFilename;
11661 3 : osPrefixFilename.resize(pszLastPart - pszFilename);
11662 6 : osSrcDSName = osPrefixFilename +
11663 6 : CPLProjectRelativeFilenameSafe(
11664 3 : pszReferencePath, pszLastPart);
11665 3 : bDone = true;
11666 : }
11667 0 : else if (STARTS_WITH_CI(pszSyntax + osPrefix.size(),
11668 : "{FILENAME}"))
11669 : {
11670 0 : CPLString osFilename(pszFilename + osPrefix.size());
11671 0 : size_t nPos = 0;
11672 0 : if (osFilename.size() >= 3 && osFilename[1] == ':' &&
11673 0 : (osFilename[2] == '\\' || osFilename[2] == '/'))
11674 0 : nPos = 2;
11675 0 : nPos = osFilename.find(
11676 0 : pszSyntax[osPrefix.size() + strlen("{FILENAME}")],
11677 : nPos);
11678 0 : if (nPos != std::string::npos)
11679 : {
11680 0 : const CPLString osSuffix = osFilename.substr(nPos);
11681 0 : osFilename.resize(nPos);
11682 0 : osSrcDSName = osPrefix +
11683 0 : CPLProjectRelativeFilenameSafe(
11684 0 : pszReferencePath, osFilename) +
11685 0 : osSuffix;
11686 0 : bDone = true;
11687 : }
11688 : }
11689 3 : break;
11690 : }
11691 : }
11692 2590 : if (!bDone)
11693 : {
11694 2587 : std::string osReferencePath = pszReferencePath;
11695 2587 : if (!CPLIsFilenameRelative(pszReferencePath))
11696 : {
11697 : // Simplify path by replacing "foo/a/../b" with "foo/b"
11698 2294 : while (STARTS_WITH(pszFilename, "../"))
11699 : {
11700 : osReferencePath =
11701 5 : CPLGetPathSafe(osReferencePath.c_str());
11702 5 : pszFilename += strlen("../");
11703 : }
11704 : }
11705 :
11706 5174 : osSrcDSName = CPLProjectRelativeFilenameSafe(
11707 2587 : osReferencePath.c_str(), pszFilename);
11708 : }
11709 2594 : }
11710 : }
11711 : else
11712 : {
11713 101702 : osSrcDSName = pszFilename;
11714 : }
11715 104296 : return osSrcDSName;
11716 : }
11717 :
11718 : /************************************************************************/
11719 : /* GDALMDArrayFromDataset */
11720 : /************************************************************************/
11721 :
11722 : class GDALMDArrayFromDataset final : public GDALMDArray
11723 : {
11724 : CPL_DISALLOW_COPY_ASSIGN(GDALMDArrayFromDataset)
11725 :
11726 : GDALDataset *const m_poDS;
11727 : const GDALExtendedDataType m_dt;
11728 : std::vector<std::shared_ptr<GDALDimension>> m_dims{};
11729 : std::string m_osUnit{};
11730 : std::vector<GByte> m_abyNoData{};
11731 : std::shared_ptr<GDALMDArray> m_varX{};
11732 : std::shared_ptr<GDALMDArray> m_varY{};
11733 : std::shared_ptr<GDALMDArray> m_varBand{};
11734 : const std::string m_osFilename;
11735 : const CPLStringList m_aosOptions;
11736 : int m_iBandDim = 0;
11737 : int m_iYDim = 1;
11738 : int m_iXDim = 2;
11739 : mutable std::vector<std::shared_ptr<GDALMDArray>> m_apoOverviews{};
11740 :
11741 : bool ReadWrite(GDALRWFlag eRWFlag, const GUInt64 *arrayStartIdx,
11742 : const size_t *count, const GInt64 *arrayStep,
11743 : const GPtrDiff_t *bufferStride,
11744 : const GDALExtendedDataType &bufferDataType,
11745 : void *pBuffer) const;
11746 :
11747 : protected:
11748 17 : GDALMDArrayFromDataset(GDALDataset *poDS, CSLConstList papszOptions)
11749 34 : : GDALAbstractMDArray(std::string(),
11750 34 : std::string(poDS->GetDescription())),
11751 34 : GDALMDArray(std::string(), std::string(poDS->GetDescription())),
11752 : m_poDS(poDS), m_dt(GDALExtendedDataType::Create(
11753 : poDS->GetRasterBand(1)->GetRasterDataType())),
11754 85 : m_osFilename(poDS->GetDescription()), m_aosOptions(papszOptions)
11755 : {
11756 17 : m_poDS->Reference();
11757 :
11758 17 : const int nBandCount = poDS->GetRasterCount();
11759 47 : for (int i = 1; i <= nBandCount; ++i)
11760 : {
11761 30 : const auto poBand = poDS->GetRasterBand(i);
11762 30 : if (i == 1)
11763 17 : m_osUnit = poBand->GetUnitType();
11764 13 : else if (m_osUnit != poBand->GetUnitType())
11765 7 : m_osUnit.clear();
11766 :
11767 60 : std::vector<GByte> abyNoData;
11768 30 : int bHasNoData = false;
11769 30 : switch (poBand->GetRasterDataType())
11770 : {
11771 0 : case GDT_Int64:
11772 : {
11773 : const auto nNoData =
11774 0 : poBand->GetNoDataValueAsInt64(&bHasNoData);
11775 0 : if (bHasNoData)
11776 : {
11777 0 : abyNoData.resize(m_dt.GetSize());
11778 0 : GDALCopyWords64(&nNoData, GDT_Int64, 0, &abyNoData[0],
11779 : m_dt.GetNumericDataType(), 0, 1);
11780 : }
11781 0 : break;
11782 : }
11783 :
11784 0 : case GDT_UInt64:
11785 : {
11786 : const auto nNoData =
11787 0 : poBand->GetNoDataValueAsUInt64(&bHasNoData);
11788 0 : if (bHasNoData)
11789 : {
11790 0 : abyNoData.resize(m_dt.GetSize());
11791 0 : GDALCopyWords64(&nNoData, GDT_UInt64, 0, &abyNoData[0],
11792 : m_dt.GetNumericDataType(), 0, 1);
11793 : }
11794 0 : break;
11795 : }
11796 :
11797 30 : default:
11798 : {
11799 30 : const auto dfNoData = poBand->GetNoDataValue(&bHasNoData);
11800 30 : if (bHasNoData)
11801 : {
11802 11 : abyNoData.resize(m_dt.GetSize());
11803 22 : GDALCopyWords64(&dfNoData, GDT_Float64, 0,
11804 11 : &abyNoData[0],
11805 : m_dt.GetNumericDataType(), 0, 1);
11806 : }
11807 30 : break;
11808 : }
11809 : }
11810 :
11811 30 : if (i == 1)
11812 17 : m_abyNoData = std::move(abyNoData);
11813 13 : else if (m_abyNoData != abyNoData)
11814 7 : m_abyNoData.clear();
11815 : }
11816 :
11817 17 : const int nXSize = poDS->GetRasterXSize();
11818 17 : const int nYSize = poDS->GetRasterYSize();
11819 :
11820 17 : auto poSRS = poDS->GetSpatialRef();
11821 34 : std::string osTypeY;
11822 34 : std::string osTypeX;
11823 34 : std::string osDirectionY;
11824 34 : std::string osDirectionX;
11825 17 : if (poSRS && poSRS->GetAxesCount() == 2)
11826 : {
11827 8 : const auto &mapping = poSRS->GetDataAxisToSRSAxisMapping();
11828 8 : OGRAxisOrientation eOrientation1 = OAO_Other;
11829 8 : poSRS->GetAxis(nullptr, 0, &eOrientation1);
11830 8 : OGRAxisOrientation eOrientation2 = OAO_Other;
11831 8 : poSRS->GetAxis(nullptr, 1, &eOrientation2);
11832 8 : if (eOrientation1 == OAO_East && eOrientation2 == OAO_North)
11833 : {
11834 6 : if (mapping == std::vector<int>{1, 2})
11835 : {
11836 6 : osTypeY = GDAL_DIM_TYPE_HORIZONTAL_Y;
11837 6 : osDirectionY = "NORTH";
11838 6 : osTypeX = GDAL_DIM_TYPE_HORIZONTAL_X;
11839 6 : osDirectionX = "EAST";
11840 : }
11841 : }
11842 2 : else if (eOrientation1 == OAO_North && eOrientation2 == OAO_East)
11843 : {
11844 2 : if (mapping == std::vector<int>{2, 1})
11845 : {
11846 2 : osTypeY = GDAL_DIM_TYPE_HORIZONTAL_Y;
11847 2 : osDirectionY = "NORTH";
11848 2 : osTypeX = GDAL_DIM_TYPE_HORIZONTAL_X;
11849 2 : osDirectionX = "EAST";
11850 : }
11851 : }
11852 : }
11853 :
11854 47 : const bool bBandYX = [papszOptions, poDS, nBandCount]()
11855 : {
11856 : const char *pszDimOrder =
11857 17 : CSLFetchNameValueDef(papszOptions, "DIM_ORDER", "AUTO");
11858 17 : if (EQUAL(pszDimOrder, "AUTO"))
11859 : {
11860 : const char *pszInterleave =
11861 15 : poDS->GetMetadataItem("INTERLEAVE", "IMAGE_STRUCTURE");
11862 24 : return nBandCount == 1 || !pszInterleave ||
11863 24 : !EQUAL(pszInterleave, "PIXEL");
11864 : }
11865 : else
11866 : {
11867 2 : return EQUAL(pszDimOrder, "BAND,Y,X");
11868 : }
11869 17 : }();
11870 : const char *const pszBandDimName =
11871 17 : CSLFetchNameValueDef(papszOptions, "BAND_DIM_NAME", "Band");
11872 : auto poBandDim = std::make_shared<GDALDimensionWeakIndexingVar>(
11873 51 : "/", pszBandDimName, std::string(), std::string(), nBandCount);
11874 : const char *const pszYDimName =
11875 17 : CSLFetchNameValueDef(papszOptions, "Y_DIM_NAME", "Y");
11876 : auto poYDim = std::make_shared<GDALDimensionWeakIndexingVar>(
11877 34 : "/", pszYDimName, osTypeY, osDirectionY, nYSize);
11878 : const char *const pszXDimName =
11879 17 : CSLFetchNameValueDef(papszOptions, "X_DIM_NAME", "X");
11880 : auto poXDim = std::make_shared<GDALDimensionWeakIndexingVar>(
11881 34 : "/", pszXDimName, osTypeX, osDirectionX, nXSize);
11882 :
11883 17 : const char *const pszBandIndexingVarItem = CSLFetchNameValueDef(
11884 : papszOptions, "BAND_INDEXING_VAR_ITEM", "{Description}");
11885 17 : if (EQUAL(pszBandIndexingVarItem, "{Description}"))
11886 : {
11887 : const auto oIndexingVarType =
11888 22 : GDALExtendedDataType::CreateString(strlen("Band 65535"));
11889 11 : auto poBandVar = MEMMDArray::Create("/", poBandDim->GetName(),
11890 44 : {poBandDim}, oIndexingVarType);
11891 11 : CPL_IGNORE_RET_VAL(poBandVar->Init());
11892 29 : for (int i = 0; i < nBandCount; ++i)
11893 : {
11894 : const char *pszDesc =
11895 18 : poDS->GetRasterBand(i + 1)->GetDescription();
11896 : const std::string osBandName =
11897 36 : pszDesc[0] ? pszDesc : CPLSPrintf("Band %d", i + 1);
11898 18 : const char *pszBandName = osBandName.c_str();
11899 18 : const char *const apszBandVal[] = {pszBandName};
11900 18 : const GUInt64 anStartIdx[] = {static_cast<GUInt64>(i)};
11901 18 : const size_t anCount[] = {1};
11902 18 : const GInt64 arrayStep[] = {1};
11903 18 : const GPtrDiff_t anBufferStride[] = {1};
11904 18 : poBandVar->Write(anStartIdx, anCount, arrayStep, anBufferStride,
11905 : oIndexingVarType, apszBandVal);
11906 : }
11907 11 : m_varBand = std::move(poBandVar);
11908 11 : poBandDim->SetIndexingVariable(m_varBand);
11909 : }
11910 6 : else if (EQUAL(pszBandIndexingVarItem, "{Index}"))
11911 : {
11912 : const auto oIndexingVarType =
11913 2 : GDALExtendedDataType::Create(GDT_Int32);
11914 1 : auto poBandVar = MEMMDArray::Create("/", poBandDim->GetName(),
11915 4 : {poBandDim}, oIndexingVarType);
11916 1 : CPL_IGNORE_RET_VAL(poBandVar->Init());
11917 3 : for (int i = 0; i < nBandCount; ++i)
11918 : {
11919 2 : const int anBandIdx[] = {i + 1};
11920 2 : const GUInt64 anStartIdx[] = {static_cast<GUInt64>(i)};
11921 2 : const size_t anCount[] = {1};
11922 2 : const GInt64 arrayStep[] = {1};
11923 2 : const GPtrDiff_t anBufferStride[] = {1};
11924 2 : poBandVar->Write(anStartIdx, anCount, arrayStep, anBufferStride,
11925 : oIndexingVarType, anBandIdx);
11926 : }
11927 1 : m_varBand = std::move(poBandVar);
11928 1 : poBandDim->SetIndexingVariable(m_varBand);
11929 : }
11930 5 : else if (EQUAL(pszBandIndexingVarItem, "{ColorInterpretation}"))
11931 : {
11932 1 : size_t nMaxLen = 0;
11933 3 : for (int i = 0; i < nBandCount; ++i)
11934 : {
11935 2 : const char *pszDesc = GDALGetColorInterpretationName(
11936 2 : poDS->GetRasterBand(i + 1)->GetColorInterpretation());
11937 2 : nMaxLen = std::max(nMaxLen, strlen(pszDesc));
11938 : }
11939 : const auto oIndexingVarType =
11940 2 : GDALExtendedDataType::CreateString(nMaxLen);
11941 1 : auto poBandVar = MEMMDArray::Create("/", poBandDim->GetName(),
11942 4 : {poBandDim}, oIndexingVarType);
11943 1 : CPL_IGNORE_RET_VAL(poBandVar->Init());
11944 3 : for (int i = 0; i < nBandCount; ++i)
11945 : {
11946 2 : const char *pszDesc = GDALGetColorInterpretationName(
11947 2 : poDS->GetRasterBand(i + 1)->GetColorInterpretation());
11948 2 : const char *const apszBandVal[] = {pszDesc};
11949 2 : const GUInt64 anStartIdx[] = {static_cast<GUInt64>(i)};
11950 2 : const size_t anCount[] = {1};
11951 2 : const GInt64 arrayStep[] = {1};
11952 2 : const GPtrDiff_t anBufferStride[] = {1};
11953 2 : poBandVar->Write(anStartIdx, anCount, arrayStep, anBufferStride,
11954 : oIndexingVarType, apszBandVal);
11955 : }
11956 1 : m_varBand = std::move(poBandVar);
11957 1 : poBandDim->SetIndexingVariable(m_varBand);
11958 : }
11959 4 : else if (!EQUAL(pszBandIndexingVarItem, "{None}"))
11960 : {
11961 3 : const char *const pszBandIndexingVarType = CSLFetchNameValueDef(
11962 : papszOptions, "BAND_INDEXING_VAR_TYPE", "String");
11963 3 : size_t nMaxLen = 0;
11964 3 : if (EQUAL(pszBandIndexingVarType, "String"))
11965 : {
11966 3 : for (int i = 0; i < nBandCount; ++i)
11967 : {
11968 : const char *pszVal =
11969 2 : poDS->GetRasterBand(i + 1)->GetMetadataItem(
11970 2 : pszBandIndexingVarItem);
11971 2 : if (pszVal)
11972 1 : nMaxLen = std::max(nMaxLen, strlen(pszVal));
11973 : }
11974 : }
11975 : const auto oIndexingVarType =
11976 3 : EQUAL(pszBandIndexingVarType, "String")
11977 : ? GDALExtendedDataType::CreateString(nMaxLen)
11978 2 : : EQUAL(pszBandIndexingVarType, "Integer")
11979 : ? GDALExtendedDataType::Create(GDT_Int32)
11980 6 : : GDALExtendedDataType::Create(GDT_Float64);
11981 3 : auto poBandVar = MEMMDArray::Create("/", poBandDim->GetName(),
11982 12 : {poBandDim}, oIndexingVarType);
11983 3 : CPL_IGNORE_RET_VAL(poBandVar->Init());
11984 9 : for (int i = 0; i < nBandCount; ++i)
11985 : {
11986 6 : const GUInt64 anStartIdx[] = {static_cast<GUInt64>(i)};
11987 6 : const size_t anCount[] = {1};
11988 6 : const GInt64 arrayStep[] = {1};
11989 6 : const GPtrDiff_t anBufferStride[] = {1};
11990 : const char *pszVal =
11991 6 : poDS->GetRasterBand(i + 1)->GetMetadataItem(
11992 6 : pszBandIndexingVarItem);
11993 6 : if (oIndexingVarType.GetClass() == GEDTC_STRING)
11994 : {
11995 2 : const char *const apszBandVal[] = {pszVal ? pszVal : ""};
11996 2 : poBandVar->Write(anStartIdx, anCount, arrayStep,
11997 : anBufferStride, oIndexingVarType,
11998 : apszBandVal);
11999 : }
12000 4 : else if (oIndexingVarType.GetNumericDataType() == GDT_Int32)
12001 : {
12002 2 : const int anVal[] = {pszVal ? atoi(pszVal) : 0};
12003 2 : poBandVar->Write(anStartIdx, anCount, arrayStep,
12004 : anBufferStride, oIndexingVarType, anVal);
12005 : }
12006 : else
12007 : {
12008 2 : const double adfVal[] = {pszVal ? CPLAtof(pszVal) : 0.0};
12009 2 : poBandVar->Write(anStartIdx, anCount, arrayStep,
12010 : anBufferStride, oIndexingVarType, adfVal);
12011 : }
12012 : }
12013 3 : m_varBand = std::move(poBandVar);
12014 3 : poBandDim->SetIndexingVariable(m_varBand);
12015 : }
12016 :
12017 17 : GDALGeoTransform gt;
12018 17 : if (m_poDS->GetGeoTransform(gt) == CE_None && gt.IsAxisAligned())
12019 : {
12020 24 : m_varX = GDALMDArrayRegularlySpaced::Create(
12021 16 : "/", poBandDim->GetName(), poXDim, gt.xorig, gt.xscale, 0.5);
12022 8 : poXDim->SetIndexingVariable(m_varX);
12023 :
12024 24 : m_varY = GDALMDArrayRegularlySpaced::Create(
12025 16 : "/", poYDim->GetName(), poYDim, gt.yorig, gt.yscale, 0.5);
12026 8 : poYDim->SetIndexingVariable(m_varY);
12027 : }
12028 17 : if (bBandYX)
12029 : {
12030 96 : m_dims = {std::move(poBandDim), std::move(poYDim),
12031 80 : std::move(poXDim)};
12032 : }
12033 : else
12034 : {
12035 1 : m_iYDim = 0;
12036 1 : m_iXDim = 1;
12037 1 : m_iBandDim = 2;
12038 6 : m_dims = {std::move(poYDim), std::move(poXDim),
12039 5 : std::move(poBandDim)};
12040 : }
12041 17 : }
12042 :
12043 : bool IRead(const GUInt64 *arrayStartIdx, const size_t *count,
12044 : const GInt64 *arrayStep, const GPtrDiff_t *bufferStride,
12045 : const GDALExtendedDataType &bufferDataType,
12046 : void *pDstBuffer) const override;
12047 :
12048 1 : bool IWrite(const GUInt64 *arrayStartIdx, const size_t *count,
12049 : const GInt64 *arrayStep, const GPtrDiff_t *bufferStride,
12050 : const GDALExtendedDataType &bufferDataType,
12051 : const void *pSrcBuffer) override
12052 : {
12053 1 : return ReadWrite(GF_Write, arrayStartIdx, count, arrayStep,
12054 : bufferStride, bufferDataType,
12055 1 : const_cast<void *>(pSrcBuffer));
12056 : }
12057 :
12058 : public:
12059 34 : ~GDALMDArrayFromDataset() override
12060 17 : {
12061 17 : m_poDS->ReleaseRef();
12062 34 : }
12063 :
12064 17 : static std::shared_ptr<GDALMDArray> Create(GDALDataset *poDS,
12065 : CSLConstList papszOptions)
12066 : {
12067 : auto array(std::shared_ptr<GDALMDArrayFromDataset>(
12068 34 : new GDALMDArrayFromDataset(poDS, papszOptions)));
12069 17 : array->SetSelf(array);
12070 34 : return array;
12071 : }
12072 :
12073 2 : bool IsWritable() const override
12074 : {
12075 2 : return m_poDS->GetAccess() == GA_Update;
12076 : }
12077 :
12078 16 : const std::string &GetFilename() const override
12079 : {
12080 16 : return m_osFilename;
12081 : }
12082 :
12083 : const std::vector<std::shared_ptr<GDALDimension>> &
12084 102 : GetDimensions() const override
12085 : {
12086 102 : return m_dims;
12087 : }
12088 :
12089 38 : const GDALExtendedDataType &GetDataType() const override
12090 : {
12091 38 : return m_dt;
12092 : }
12093 :
12094 5 : const std::string &GetUnit() const override
12095 : {
12096 5 : return m_osUnit;
12097 : }
12098 :
12099 5 : const void *GetRawNoDataValue() const override
12100 : {
12101 5 : return m_abyNoData.empty() ? nullptr : m_abyNoData.data();
12102 : }
12103 :
12104 5 : double GetOffset(bool *pbHasOffset,
12105 : GDALDataType *peStorageType) const override
12106 : {
12107 5 : double dfRes = 0;
12108 5 : int bHasOffset = false;
12109 5 : auto poFirstBand = m_poDS->GetRasterBand(1);
12110 5 : if (poFirstBand) // to avoid -Wnull-dereference
12111 : {
12112 5 : dfRes = poFirstBand->GetOffset(&bHasOffset);
12113 7 : for (int i = 2; bHasOffset && i <= m_poDS->GetRasterCount(); ++i)
12114 : {
12115 : const double dfOtherRes =
12116 2 : m_poDS->GetRasterBand(i)->GetOffset(&bHasOffset);
12117 2 : bHasOffset = bHasOffset && (dfOtherRes == dfRes);
12118 : }
12119 : }
12120 5 : if (pbHasOffset)
12121 5 : *pbHasOffset = CPL_TO_BOOL(bHasOffset);
12122 5 : if (peStorageType)
12123 3 : *peStorageType = GDT_Unknown;
12124 5 : return dfRes;
12125 : }
12126 :
12127 5 : double GetScale(bool *pbHasScale,
12128 : GDALDataType *peStorageType) const override
12129 : {
12130 5 : double dfRes = 0;
12131 5 : int bHasScale = false;
12132 5 : auto poFirstBand = m_poDS->GetRasterBand(1);
12133 5 : if (poFirstBand) // to avoid -Wnull-dereference
12134 : {
12135 5 : dfRes = poFirstBand->GetScale(&bHasScale);
12136 7 : for (int i = 2; bHasScale && i <= m_poDS->GetRasterCount(); ++i)
12137 : {
12138 : const double dfOtherRes =
12139 2 : m_poDS->GetRasterBand(i)->GetScale(&bHasScale);
12140 2 : bHasScale = bHasScale && (dfOtherRes == dfRes);
12141 : }
12142 : }
12143 5 : if (pbHasScale)
12144 5 : *pbHasScale = CPL_TO_BOOL(bHasScale);
12145 5 : if (peStorageType)
12146 3 : *peStorageType = GDT_Unknown;
12147 5 : return dfRes;
12148 : }
12149 :
12150 9 : std::shared_ptr<OGRSpatialReference> GetSpatialRef() const override
12151 : {
12152 9 : auto poSrcSRS = m_poDS->GetSpatialRef();
12153 9 : if (!poSrcSRS)
12154 1 : return nullptr;
12155 16 : auto poSRS = std::shared_ptr<OGRSpatialReference>(poSrcSRS->Clone());
12156 :
12157 16 : auto axisMapping = poSRS->GetDataAxisToSRSAxisMapping();
12158 24 : for (auto &m : axisMapping)
12159 : {
12160 16 : if (m == 1)
12161 8 : m = m_iXDim + 1;
12162 8 : else if (m == 2)
12163 8 : m = m_iYDim + 1;
12164 : else
12165 0 : m = 0;
12166 : }
12167 8 : poSRS->SetDataAxisToSRSAxisMapping(axisMapping);
12168 8 : return poSRS;
12169 : }
12170 :
12171 7 : std::vector<GUInt64> GetBlockSize() const override
12172 : {
12173 7 : int nBlockXSize = 0;
12174 7 : int nBlockYSize = 0;
12175 7 : m_poDS->GetRasterBand(1)->GetBlockSize(&nBlockXSize, &nBlockYSize);
12176 7 : if (m_iBandDim == 0)
12177 : {
12178 6 : return std::vector<GUInt64>{1, static_cast<GUInt64>(nBlockYSize),
12179 6 : static_cast<GUInt64>(nBlockXSize)};
12180 : }
12181 : else
12182 : {
12183 1 : return std::vector<GUInt64>{static_cast<GUInt64>(nBlockYSize),
12184 1 : static_cast<GUInt64>(nBlockXSize), 1};
12185 : }
12186 : }
12187 :
12188 : std::vector<std::shared_ptr<GDALAttribute>>
12189 7 : GetAttributes(CSLConstList) const override
12190 : {
12191 7 : std::vector<std::shared_ptr<GDALAttribute>> res;
12192 7 : auto papszMD = m_poDS->GetMetadata();
12193 14 : for (auto iter = papszMD; iter && iter[0]; ++iter)
12194 : {
12195 7 : char *pszKey = nullptr;
12196 7 : const char *pszValue = CPLParseNameValue(*iter, &pszKey);
12197 7 : if (pszKey && pszValue)
12198 : {
12199 : res.emplace_back(
12200 7 : std::make_shared<GDALMDIAsAttribute>(pszKey, pszValue));
12201 : }
12202 7 : CPLFree(pszKey);
12203 : }
12204 7 : return res;
12205 : }
12206 :
12207 6 : int GetOverviewCount() const override
12208 : {
12209 6 : int nOvrCount = 0;
12210 6 : GDALDataset *poOvrDS = nullptr;
12211 6 : bool bOK = true;
12212 12 : for (int i = 1; bOK && i <= m_poDS->GetRasterCount(); ++i)
12213 : {
12214 6 : auto poBand = m_poDS->GetRasterBand(i);
12215 6 : const int nThisOvrCount = poBand->GetOverviewCount();
12216 6 : bOK = (nThisOvrCount > 0 && (i == 1 || nThisOvrCount == nOvrCount));
12217 6 : if (bOK)
12218 : {
12219 6 : nOvrCount = nThisOvrCount;
12220 6 : auto poFirstOvrBand = poBand->GetOverview(0);
12221 6 : bOK = poFirstOvrBand != nullptr;
12222 6 : if (bOK)
12223 : {
12224 6 : auto poThisOvrDS = poFirstOvrBand->GetDataset();
12225 12 : bOK = poThisOvrDS != nullptr &&
12226 6 : poThisOvrDS->GetRasterBand(i) == poFirstOvrBand &&
12227 0 : (i == 1 || poThisOvrDS == poOvrDS);
12228 6 : if (bOK)
12229 6 : poOvrDS = poThisOvrDS;
12230 : }
12231 : }
12232 : }
12233 6 : return bOK ? nOvrCount : 0;
12234 : }
12235 :
12236 5 : std::shared_ptr<GDALMDArray> GetOverview(int idx) const override
12237 : {
12238 5 : const int nOverviews = GetOverviewCount();
12239 5 : if (idx < 0 || idx >= nOverviews)
12240 2 : return nullptr;
12241 3 : m_apoOverviews.resize(nOverviews);
12242 3 : if (!m_apoOverviews[idx])
12243 : {
12244 1 : if (auto poBand = m_poDS->GetRasterBand(1))
12245 : {
12246 1 : if (auto poOvrBand = poBand->GetOverview(idx))
12247 : {
12248 1 : if (auto poOvrDS = poOvrBand->GetDataset())
12249 : {
12250 1 : m_apoOverviews[idx] =
12251 2 : Create(poOvrDS, m_aosOptions.List());
12252 : }
12253 : }
12254 : }
12255 : }
12256 3 : return m_apoOverviews[idx];
12257 : }
12258 : };
12259 :
12260 10 : bool GDALMDArrayFromDataset::IRead(const GUInt64 *arrayStartIdx,
12261 : const size_t *count, const GInt64 *arrayStep,
12262 : const GPtrDiff_t *bufferStride,
12263 : const GDALExtendedDataType &bufferDataType,
12264 : void *pDstBuffer) const
12265 : {
12266 10 : return ReadWrite(GF_Read, arrayStartIdx, count, arrayStep, bufferStride,
12267 10 : bufferDataType, pDstBuffer);
12268 : }
12269 :
12270 : /************************************************************************/
12271 : /* ReadWrite() */
12272 : /************************************************************************/
12273 :
12274 11 : bool GDALMDArrayFromDataset::ReadWrite(
12275 : GDALRWFlag eRWFlag, const GUInt64 *arrayStartIdx, const size_t *count,
12276 : const GInt64 *arrayStep, const GPtrDiff_t *bufferStride,
12277 : const GDALExtendedDataType &bufferDataType, void *pBuffer) const
12278 : {
12279 11 : const auto eDT(bufferDataType.GetNumericDataType());
12280 11 : const auto nDTSize(GDALGetDataTypeSizeBytes(eDT));
12281 11 : const int nX =
12282 11 : arrayStep[m_iXDim] > 0
12283 11 : ? static_cast<int>(arrayStartIdx[m_iXDim])
12284 0 : : static_cast<int>(arrayStartIdx[m_iXDim] -
12285 0 : (count[m_iXDim] - 1) * -arrayStep[m_iXDim]);
12286 11 : const int nY =
12287 11 : arrayStep[m_iYDim] > 0
12288 11 : ? static_cast<int>(arrayStartIdx[m_iYDim])
12289 1 : : static_cast<int>(arrayStartIdx[m_iYDim] -
12290 1 : (count[m_iYDim] - 1) * -arrayStep[m_iYDim]);
12291 11 : const int nSizeX =
12292 11 : static_cast<int>(count[m_iXDim] * ABS(arrayStep[m_iXDim]));
12293 11 : const int nSizeY =
12294 11 : static_cast<int>(count[m_iYDim] * ABS(arrayStep[m_iYDim]));
12295 11 : GByte *pabyBuffer = static_cast<GByte *>(pBuffer);
12296 11 : int nStrideXSign = 1;
12297 11 : if (arrayStep[m_iXDim] < 0)
12298 : {
12299 0 : pabyBuffer += (count[m_iXDim] - 1) * bufferStride[m_iXDim] * nDTSize;
12300 0 : nStrideXSign = -1;
12301 : }
12302 11 : int nStrideYSign = 1;
12303 11 : if (arrayStep[m_iYDim] < 0)
12304 : {
12305 1 : pabyBuffer += (count[m_iYDim] - 1) * bufferStride[m_iYDim] * nDTSize;
12306 1 : nStrideYSign = -1;
12307 : }
12308 11 : const GSpacing nPixelSpace =
12309 11 : static_cast<GSpacing>(nStrideXSign * bufferStride[m_iXDim] * nDTSize);
12310 11 : const GSpacing nLineSpace =
12311 11 : static_cast<GSpacing>(nStrideYSign * bufferStride[m_iYDim] * nDTSize);
12312 11 : const GSpacing nBandSpace =
12313 11 : static_cast<GSpacing>(bufferStride[m_iBandDim] * nDTSize);
12314 11 : std::vector<int> anBandList;
12315 28 : for (int i = 0; i < static_cast<int>(count[m_iBandDim]); ++i)
12316 17 : anBandList.push_back(1 + static_cast<int>(arrayStartIdx[m_iBandDim]) +
12317 17 : i * static_cast<int>(arrayStep[m_iBandDim]));
12318 :
12319 33 : return m_poDS->RasterIO(eRWFlag, nX, nY, nSizeX, nSizeY, pabyBuffer,
12320 11 : static_cast<int>(count[m_iXDim]),
12321 11 : static_cast<int>(count[m_iYDim]), eDT,
12322 11 : static_cast<int>(count[m_iBandDim]),
12323 11 : anBandList.data(), nPixelSpace, nLineSpace,
12324 22 : nBandSpace, nullptr) == CE_None;
12325 : }
12326 :
12327 : /************************************************************************/
12328 : /* AsMDArray() */
12329 : /************************************************************************/
12330 :
12331 : /** Return a view of this dataset as a 3D multidimensional GDALMDArray.
12332 : *
12333 : * If this dataset is not already marked as shared, it will be, so that the
12334 : * returned array holds a reference to it.
12335 : *
12336 : * If the dataset has a geotransform attached, the X and Y dimensions of the
12337 : * returned array will have an associated indexing variable.
12338 : *
12339 : * The currently supported list of options is:
12340 : * <ul>
12341 : * <li>DIM_ORDER=<order> where order can be "AUTO", "Band,Y,X" or "Y,X,Band".
12342 : * "Band,Y,X" means that the first (slowest changing) dimension is Band
12343 : * and the last (fastest changing direction) is X
12344 : * "Y,X,Band" means that the first (slowest changing) dimension is Y
12345 : * and the last (fastest changing direction) is Band.
12346 : * "AUTO" (the default) selects "Band,Y,X" for single band datasets, or takes
12347 : * into account the INTERLEAVE metadata item in the IMAGE_STRUCTURE domain.
12348 : * If it equals BAND, then "Band,Y,X" is used. Otherwise (if it equals PIXEL),
12349 : * "Y,X,Band" is use.
12350 : * </li>
12351 : * <li>BAND_INDEXING_VAR_ITEM={Description}|{None}|{Index}|{ColorInterpretation}|<BandMetadataItem>:
12352 : * item from which to build the band indexing variable.
12353 : * <ul>
12354 : * <li>"{Description}", the default, means to use the band description (or "Band index" if empty).</li>
12355 : * <li>"{None}" means that no band indexing variable must be created.</li>
12356 : * <li>"{Index}" means that the band index (starting at one) is used.</li>
12357 : * <li>"{ColorInterpretation}" means that the band color interpretation is used (i.e. "Red", "Green", "Blue").</li>
12358 : * <li><BandMetadataItem> is the name of a band metadata item to use.</li>
12359 : * </ul>
12360 : * </li>
12361 : * <li>BAND_INDEXING_VAR_TYPE=String|Real|Integer: the data type of the band
12362 : * indexing variable, when BAND_INDEXING_VAR_ITEM corresponds to a band metadata item.
12363 : * Defaults to String.
12364 : * </li>
12365 : * <li>BAND_DIM_NAME=<string>: Name of the band dimension.
12366 : * Defaults to "Band".
12367 : * </li>
12368 : * <li>X_DIM_NAME=<string>: Name of the X dimension. Defaults to "X".
12369 : * </li>
12370 : * <li>Y_DIM_NAME=<string>: Name of the Y dimension. Defaults to "Y".
12371 : * </li>
12372 : * </ul>
12373 : *
12374 : * This is the same as the C function GDALDatasetAsMDArray().
12375 : *
12376 : * The "reverse" method is GDALMDArray::AsClassicDataset().
12377 : *
12378 : * @param papszOptions Null-terminated list of strings, or nullptr.
12379 : * @return a new array, or nullptr.
12380 : *
12381 : * @since GDAL 3.12
12382 : */
12383 19 : std::shared_ptr<GDALMDArray> GDALDataset::AsMDArray(CSLConstList papszOptions)
12384 : {
12385 19 : if (!GetShared())
12386 : {
12387 18 : MarkAsShared();
12388 : }
12389 19 : if (nBands == 0 || nRasterXSize == 0 || nRasterYSize == 0)
12390 : {
12391 1 : ReportError(
12392 : CE_Failure, CPLE_AppDefined,
12393 : "Degenerated array (band, Y and/or X dimension of size zero)");
12394 1 : return nullptr;
12395 : }
12396 18 : const GDALDataType eDT = papoBands[0]->GetRasterDataType();
12397 31 : for (int i = 1; i < nBands; ++i)
12398 : {
12399 14 : if (eDT != papoBands[i]->GetRasterDataType())
12400 : {
12401 1 : ReportError(CE_Failure, CPLE_AppDefined,
12402 : "Non-uniform data type amongst bands");
12403 1 : return nullptr;
12404 : }
12405 : }
12406 : const char *pszDimOrder =
12407 17 : CSLFetchNameValueDef(papszOptions, "DIM_ORDER", "AUTO");
12408 17 : if (!EQUAL(pszDimOrder, "AUTO") && !EQUAL(pszDimOrder, "Band,Y,X") &&
12409 2 : !EQUAL(pszDimOrder, "Y,X,Band"))
12410 : {
12411 1 : ReportError(CE_Failure, CPLE_IllegalArg,
12412 : "Illegal value for DIM_ORDER option");
12413 1 : return nullptr;
12414 : }
12415 16 : return GDALMDArrayFromDataset::Create(this, papszOptions);
12416 : }
12417 :
12418 : /************************************************************************/
12419 : /* GDALDataset::GetInterBandCovarianceMatrix() */
12420 : /************************************************************************/
12421 :
12422 : /**
12423 : \brief Fetch or compute the covariance matrix between bands of this dataset.
12424 :
12425 : The covariance indicates the level to which two bands vary together.
12426 :
12427 : If we call \f$ v_i[y,x] \f$ the value of pixel at row=y and column=x for band i,
12428 : and \f$ mean_i \f$ the mean value of all pixels of band i, then
12429 :
12430 : \f[
12431 : \mathrm{cov}[i,j] =
12432 : \frac{
12433 : \sum_{y,x} \left( v_i[y,x] - \mathrm{mean}_i \right)
12434 : \left( v_j[y,x] - \mathrm{mean}_j \right)
12435 : }{
12436 : \mathrm{pixel\_count} - \mathrm{nDeltaDegreeOfFreedom}
12437 : }
12438 : \f]
12439 :
12440 : When there are no nodata values, \f$ pixel\_count = GetRasterXSize() * GetRasterYSize() \f$.
12441 : We can see that \f$ cov[i,j] = cov[j,i] \f$, and consequently the returned matrix
12442 : is symmetric.
12443 :
12444 : A value of nDeltaDegreeOfFreedom=1 (the default) will return a unbiased estimate
12445 : if the pixels in bands are considered to be a sample of the whole population.
12446 : This is consistent with the default of
12447 : https://numpy.org/doc/stable/reference/generated/numpy.cov.html and the returned
12448 : matrix is consistent with what can be obtained with
12449 :
12450 : \verbatim embed:rst
12451 : .. code-block:: python
12452 :
12453 : numpy.cov(
12454 : [ds.GetRasterBand(n + 1).ReadAsArray().ravel() for n in range(ds.RasterCount)]
12455 : )
12456 : \endverbatim
12457 :
12458 : Otherwise a value of nDeltaDegreeOfFreedom=0 can be used if they are considered
12459 : to be the whole population.
12460 :
12461 : If STATISTICS_COVARIANCES metadata items are available in band metadata,
12462 : this method uses them.
12463 : Otherwise, if bForce is true, ComputeInterBandCovarianceMatrix() is called.
12464 : Otherwise, if bForce is false, an empty vector is returned
12465 :
12466 : @param nBandCount Zero for all bands, or number of values in panBandList.
12467 : Defaults to 0.
12468 : @param panBandList nullptr for all bands if nBandCount == 0, or array of
12469 : nBandCount values such as panBandList[i] is the index
12470 : between 1 and GetRasterCount() of a band that must be used
12471 : in the covariance computation. Defaults to nullptr.
12472 : @param bApproxOK Whether it is acceptable to use a subsample of values in
12473 : ComputeInterBandCovarianceMatrix().
12474 : Defaults to false.
12475 : @param bForce Whether ComputeInterBandCovarianceMatrix() should be called
12476 : when the STATISTICS_COVARIANCES metadata items are missing.
12477 : Defaults to false.
12478 : @param bWriteIntoMetadata Whether ComputeInterBandCovarianceMatrix() must
12479 : write STATISTICS_COVARIANCES band metadata items.
12480 : Defaults to true.
12481 : @param nDeltaDegreeOfFreedom Correction term to subtract in the final
12482 : averaging phase of the covariance computation.
12483 : Defaults to 1.
12484 : @param pfnProgress a function to call to report progress, or NULL.
12485 : @param pProgressData application data to pass to the progress function.
12486 :
12487 : @return a vector of nBandCount * nBandCount values if successful,
12488 : in row-major order, or an empty vector in case of failure
12489 :
12490 : @since 3.13
12491 :
12492 : @see ComputeInterBandCovarianceMatrix()
12493 : */
12494 :
12495 0 : std::vector<double> GDALDataset::GetInterBandCovarianceMatrix(
12496 : int nBandCount, const int *panBandList, bool bApproxOK, bool bForce,
12497 : bool bWriteIntoMetadata, int nDeltaDegreeOfFreedom,
12498 : GDALProgressFunc pfnProgress, void *pProgressData)
12499 : {
12500 0 : std::vector<double> res;
12501 0 : const int nBandCountToUse = nBandCount == 0 ? nBands : nBandCount;
12502 0 : if (nBandCountToUse == 0)
12503 0 : return res;
12504 : if constexpr (sizeof(size_t) < sizeof(uint64_t))
12505 : {
12506 : // Check that nBandCountToUse * nBandCountToUse will not overflow size_t
12507 : if (static_cast<uint32_t>(nBandCountToUse) >
12508 : std::numeric_limits<uint16_t>::max())
12509 : {
12510 : CPLError(CE_Failure, CPLE_OutOfMemory,
12511 : "Not enough memory to store result");
12512 : return res;
12513 : }
12514 : }
12515 : try
12516 : {
12517 0 : res.resize(static_cast<size_t>(nBandCountToUse) * nBandCountToUse);
12518 : }
12519 0 : catch (const std::exception &)
12520 : {
12521 0 : CPLError(CE_Failure, CPLE_OutOfMemory,
12522 : "Not enough memory to store result");
12523 0 : return res;
12524 : }
12525 :
12526 0 : if (GetInterBandCovarianceMatrix(res.data(), res.size(), nBandCount,
12527 : panBandList, bApproxOK, bForce,
12528 : bWriteIntoMetadata, nDeltaDegreeOfFreedom,
12529 0 : pfnProgress, pProgressData) != CE_None)
12530 : {
12531 0 : res.clear();
12532 : }
12533 0 : return res;
12534 : }
12535 :
12536 : /************************************************************************/
12537 : /* GDALDataset::GetInterBandCovarianceMatrix() */
12538 : /************************************************************************/
12539 :
12540 : /**
12541 : \brief Fetch or compute the covariance matrix between bands of this dataset.
12542 :
12543 : The covariance indicates the level to which two bands vary together.
12544 :
12545 : If we call \f$ v_i[y,x] \f$ the value of pixel at row=y and column=x for band i,
12546 : and \f$ mean_i \f$ the mean value of all pixels of band i, then
12547 :
12548 : \f[
12549 : \mathrm{cov}[i,j] =
12550 : \frac{
12551 : \sum_{y,x} \left( v_i[y,x] - \mathrm{mean}_i \right)
12552 : \left( v_j[y,x] - \mathrm{mean}_j \right)
12553 : }{
12554 : \mathrm{pixel\_count} - \mathrm{nDeltaDegreeOfFreedom}
12555 : }
12556 : \f]
12557 :
12558 : When there are no nodata values, \f$ pixel\_count = GetRasterXSize() * GetRasterYSize() \f$.
12559 : We can see that \f$ cov[i,j] = cov[j,i] \f$, and consequently the returned matrix
12560 : is symmetric.
12561 :
12562 : A value of nDeltaDegreeOfFreedom=1 (the default) will return a unbiased estimate
12563 : if the pixels in bands are considered to be a sample of the whole population.
12564 : This is consistent with the default of
12565 : https://numpy.org/doc/stable/reference/generated/numpy.cov.html and the returned
12566 : matrix is consistent with what can be obtained with
12567 :
12568 : \verbatim embed:rst
12569 : .. code-block:: python
12570 :
12571 : numpy.cov(
12572 : [ds.GetRasterBand(n + 1).ReadAsArray().ravel() for n in range(ds.RasterCount)]
12573 : )
12574 : \endverbatim
12575 :
12576 : Otherwise a value of nDeltaDegreeOfFreedom=0 can be used if they are considered
12577 : to be the whole population.
12578 :
12579 : The caller must provide an already allocated array in padfCovMatrix of size
12580 : at least nBandCount * nBandCount.
12581 :
12582 : If STATISTICS_COVARIANCES metadata items are available in band metadata,
12583 : this method uses them.
12584 : Otherwise, if bForce is true, ComputeInterBandCovarianceMatrix() is called.
12585 : Otherwise, if bForce is false, an empty vector is returned
12586 :
12587 : This is the same as the C function GDALDatasetGetInterBandCovarianceMatrix()
12588 :
12589 : @param[out] padfCovMatrix Pointer to an already allocated output array, of size at least
12590 : nBandCount * nBandCount.
12591 : @param nSize Number of elements in output array.
12592 : @param nBandCount Zero for all bands, or number of values in panBandList.
12593 : Defaults to 0.
12594 : @param panBandList nullptr for all bands if nBandCount == 0, or array of
12595 : nBandCount values such as panBandList[i] is the index
12596 : between 1 and GetRasterCount() of a band that must be used
12597 : in the covariance computation. Defaults to nullptr.
12598 : @param bApproxOK Whether it is acceptable to use a subsample of values in
12599 : ComputeInterBandCovarianceMatrix().
12600 : Defaults to false.
12601 : @param bForce Whether ComputeInterBandCovarianceMatrix() should be called
12602 : when the STATISTICS_COVARIANCES metadata items are missing.
12603 : Defaults to false.
12604 : @param bWriteIntoMetadata Whether ComputeInterBandCovarianceMatrix() must
12605 : write STATISTICS_COVARIANCES band metadata items.
12606 : Defaults to true.
12607 : @param nDeltaDegreeOfFreedom Correction term to subtract in the final
12608 : averaging phase of the covariance computation.
12609 : Defaults to 1.
12610 : @param pfnProgress a function to call to report progress, or NULL.
12611 : @param pProgressData application data to pass to the progress function.
12612 :
12613 : @return CE_None if successful, CE_Warning if values are not available in
12614 : metadata and bForce is false, or CE_Failure in case of failure
12615 :
12616 : @since 3.13
12617 :
12618 : @see ComputeInterBandCovarianceMatrix()
12619 : */
12620 :
12621 11 : CPLErr GDALDataset::GetInterBandCovarianceMatrix(
12622 : double *padfCovMatrix, size_t nSize, int nBandCount, const int *panBandList,
12623 : bool bApproxOK, bool bForce, bool bWriteIntoMetadata,
12624 : int nDeltaDegreeOfFreedom, GDALProgressFunc pfnProgress,
12625 : void *pProgressData)
12626 : {
12627 22 : std::vector<int> anBandListTmp; // keep in this scope
12628 11 : if (nBandCount == 0)
12629 : {
12630 0 : if (nBands == 0)
12631 0 : return CE_None;
12632 0 : for (int i = 0; i < nBands; ++i)
12633 0 : anBandListTmp.push_back(i + 1);
12634 0 : nBandCount = nBands;
12635 0 : panBandList = anBandListTmp.data();
12636 : }
12637 : else
12638 : {
12639 11 : if (nBandCount > nBands)
12640 : {
12641 1 : CPLError(CE_Failure, CPLE_AppDefined,
12642 : "GetInterBandCovarianceMatrix(): nBandCount > nBands");
12643 1 : return CE_Failure;
12644 : }
12645 29 : for (int i = 0; i < nBandCount; ++i)
12646 : {
12647 21 : if (panBandList[i] <= 0 || panBandList[i] > nBands)
12648 : {
12649 2 : CPLError(CE_Failure, CPLE_AppDefined,
12650 : "GetInterBandCovarianceMatrix(): invalid value "
12651 : "panBandList[%d] = %d",
12652 2 : i, panBandList[i]);
12653 2 : return CE_Failure;
12654 : }
12655 : }
12656 : }
12657 :
12658 8 : if (nSize < static_cast<uint64_t>(nBandCount) * nBandCount)
12659 : {
12660 0 : CPLError(
12661 : CE_Failure, CPLE_AppDefined,
12662 : "GetInterBandCovarianceMatrix(): too small result matrix provided");
12663 0 : return CE_Failure;
12664 : }
12665 8 : bool bGotFromMD = true;
12666 8 : size_t resIdx = 0;
12667 20 : for (int i = 0; bGotFromMD && i < nBandCount; ++i)
12668 : {
12669 24 : const char *pszCov = papoBands[panBandList[i] - 1]->GetMetadataItem(
12670 12 : "STATISTICS_COVARIANCES");
12671 12 : bGotFromMD = pszCov != nullptr;
12672 12 : if (bGotFromMD)
12673 : {
12674 12 : const CPLStringList aosTokens(CSLTokenizeString2(pszCov, ",", 0));
12675 6 : bGotFromMD = aosTokens.size() == nBands;
12676 6 : if (bGotFromMD)
12677 : {
12678 24 : for (int j = 0; j < nBandCount; ++j)
12679 18 : padfCovMatrix[resIdx++] =
12680 18 : CPLAtof(aosTokens[panBandList[j] - 1]);
12681 : }
12682 : }
12683 : }
12684 8 : if (bGotFromMD)
12685 2 : return CE_None;
12686 :
12687 6 : if (!bForce)
12688 1 : return CE_Warning;
12689 5 : return ComputeInterBandCovarianceMatrix(
12690 : padfCovMatrix, nSize, nBandCount, panBandList, bApproxOK,
12691 5 : bWriteIntoMetadata, nDeltaDegreeOfFreedom, pfnProgress, pProgressData);
12692 : }
12693 :
12694 : /************************************************************************/
12695 : /* GDALDatasetGetInterBandCovarianceMatrix() */
12696 : /************************************************************************/
12697 :
12698 : /**
12699 : \brief Fetch or compute the covariance matrix between bands of this dataset.
12700 :
12701 : The covariance indicates the level to which two bands vary together.
12702 :
12703 : If we call \f$ v_i[y,x] \f$ the value of pixel at row=y and column=x for band i,
12704 : and \f$ mean_i \f$ the mean value of all pixels of band i, then
12705 :
12706 : \f[
12707 : \mathrm{cov}[i,j] =
12708 : \frac{
12709 : \sum_{y,x} \left( v_i[y,x] - \mathrm{mean}_i \right)
12710 : \left( v_j[y,x] - \mathrm{mean}_j \right)
12711 : }{
12712 : \mathrm{pixel\_count} - \mathrm{nDeltaDegreeOfFreedom}
12713 : }
12714 : \f]
12715 :
12716 : When there are no nodata values, \f$ pixel\_count = GetRasterXSize() * GetRasterYSize() \f$.
12717 : We can see that \f$ cov[i,j] = cov[j,i] \f$, and consequently the returned matrix
12718 : is symmetric.
12719 :
12720 : A value of nDeltaDegreeOfFreedom=1 (the default) will return a unbiased estimate
12721 : if the pixels in bands are considered to be a sample of the whole population.
12722 : This is consistent with the default of
12723 : https://numpy.org/doc/stable/reference/generated/numpy.cov.html and the returned
12724 : matrix is consistent with what can be obtained with
12725 :
12726 : \verbatim embed:rst
12727 : .. code-block:: python
12728 :
12729 : numpy.cov(
12730 : [ds.GetRasterBand(n + 1).ReadAsArray().ravel() for n in range(ds.RasterCount)]
12731 : )
12732 : \endverbatim
12733 :
12734 : Otherwise a value of nDeltaDegreeOfFreedom=0 can be used if they are considered
12735 : to be the whole population.
12736 :
12737 : The caller must provide an already allocated array in padfCovMatrix of size
12738 : at least nBandCount * nBandCount.
12739 :
12740 : If STATISTICS_COVARIANCES metadata items are available in band metadata,
12741 : this method uses them.
12742 : Otherwise, if bForce is true, GDALDatasetComputeInterBandCovarianceMatrix() is called.
12743 : Otherwise, if bForce is false, an empty vector is returned
12744 :
12745 : This is the same as the C++ method GDALDataset::GetInterBandCovarianceMatrix()
12746 :
12747 : @param hDS Dataset handle.
12748 : @param[out] padfCovMatrix Pointer to an already allocated output array, of size at least
12749 : nBandCount * nBandCount.
12750 : @param nSize Number of elements in output array.
12751 : @param nBandCount Zero for all bands, or number of values in panBandList.
12752 : Defaults to 0.
12753 : @param panBandList nullptr for all bands if nBandCount == 0, or array of
12754 : nBandCount values such as panBandList[i] is the index
12755 : between 1 and GetRasterCount() of a band that must be used
12756 : in the covariance computation. Defaults to nullptr.
12757 : @param bApproxOK Whether it is acceptable to use a subsample of values in
12758 : GDALDatasetComputeInterBandCovarianceMatrix().
12759 : Defaults to false.
12760 : @param bForce Whether GDALDatasetComputeInterBandCovarianceMatrix() should be called
12761 : when the STATISTICS_COVARIANCES metadata items are missing.
12762 : Defaults to false.
12763 : @param bWriteIntoMetadata Whether GDALDatasetComputeInterBandCovarianceMatrix() must
12764 : write STATISTICS_COVARIANCES band metadata items.
12765 : Defaults to true.
12766 : @param nDeltaDegreeOfFreedom Correction term to subtract in the final
12767 : averaging phase of the covariance computation.
12768 : Defaults to 1.
12769 : @param pfnProgress a function to call to report progress, or NULL.
12770 : @param pProgressData application data to pass to the progress function.
12771 :
12772 : @return CE_None if successful, CE_Warning if values are not available in
12773 : metadata and bForce is false, or CE_Failure in case of failure
12774 :
12775 : @since 3.13
12776 :
12777 : @see GDALDatasetComputeInterBandCovarianceMatrix()
12778 : */
12779 11 : CPLErr GDALDatasetGetInterBandCovarianceMatrix(
12780 : GDALDatasetH hDS, double *padfCovMatrix, size_t nSize, int nBandCount,
12781 : const int *panBandList, bool bApproxOK, bool bForce,
12782 : bool bWriteIntoMetadata, int nDeltaDegreeOfFreedom,
12783 : GDALProgressFunc pfnProgress, void *pProgressData)
12784 : {
12785 11 : VALIDATE_POINTER1(hDS, __func__, CE_Failure);
12786 11 : VALIDATE_POINTER1(padfCovMatrix, __func__, CE_Failure);
12787 11 : return GDALDataset::FromHandle(hDS)->GetInterBandCovarianceMatrix(
12788 : padfCovMatrix, nSize, nBandCount, panBandList, bApproxOK, bForce,
12789 11 : bWriteIntoMetadata, nDeltaDegreeOfFreedom, pfnProgress, pProgressData);
12790 : }
12791 :
12792 : /************************************************************************/
12793 : /* GDALDataset::ComputeInterBandCovarianceMatrix() */
12794 : /************************************************************************/
12795 :
12796 : /**
12797 : \brief Compute the covariance matrix between bands of this dataset.
12798 :
12799 : The covariance indicates the level to which two bands vary together.
12800 :
12801 : If we call \f$ v_i[y,x] \f$ the value of pixel at row=y and column=x for band i,
12802 : and \f$ mean_i \f$ the mean value of all pixels of band i, then
12803 :
12804 : \f[
12805 : \mathrm{cov}[i,j] =
12806 : \frac{
12807 : \sum_{y,x} \left( v_i[y,x] - \mathrm{mean}_i \right)
12808 : \left( v_j[y,x] - \mathrm{mean}_j \right)
12809 : }{
12810 : \mathrm{pixel\_count} - \mathrm{nDeltaDegreeOfFreedom}
12811 : }
12812 : \f]
12813 :
12814 : When there are no nodata values, \f$ pixel\_count = GetRasterXSize() * GetRasterYSize() \f$.
12815 : We can see that \f$ cov[i,j] = cov[j,i] \f$, and consequently the returned matrix
12816 : is symmetric.
12817 :
12818 : A value of nDeltaDegreeOfFreedom=1 (the default) will return a unbiased estimate
12819 : if the pixels in bands are considered to be a sample of the whole population.
12820 : This is consistent with the default of
12821 : https://numpy.org/doc/stable/reference/generated/numpy.cov.html and the returned
12822 : matrix is consistent with what can be obtained with
12823 :
12824 : \verbatim embed:rst
12825 : .. code-block:: python
12826 :
12827 : numpy.cov(
12828 : [ds.GetRasterBand(n + 1).ReadAsArray().ravel() for n in range(ds.RasterCount)]
12829 : )
12830 : \endverbatim
12831 :
12832 : Otherwise a value of nDeltaDegreeOfFreedom=0 can be used if they are considered
12833 : to be the whole population.
12834 :
12835 : This method recomputes the covariance matrix, even if STATISTICS_COVARIANCES
12836 : metadata items are available in bands. See GetInterBandCovarianceMatrix()
12837 : to use them.
12838 :
12839 : @param nBandCount Zero for all bands, or number of values in panBandList.
12840 : Defaults to 0.
12841 : @param panBandList nullptr for all bands if nBandCount == 0, or array of
12842 : nBandCount values such as panBandList[i] is the index
12843 : between 1 and GetRasterCount() of a band that must be used
12844 : in the covariance computation. Defaults to nullptr.
12845 : @param bApproxOK Whether it is acceptable to use a subsample of values.
12846 : Defaults to false.
12847 : @param bWriteIntoMetadata Whether this method must write
12848 : STATISTICS_COVARIANCES band metadata items.
12849 : Defaults to true.
12850 : @param nDeltaDegreeOfFreedom Correction term to subtract in the final
12851 : averaging phase of the covariance computation.
12852 : Defaults to 1.
12853 : @param pfnProgress a function to call to report progress, or NULL.
12854 : @param pProgressData application data to pass to the progress function.
12855 :
12856 : @return a vector of nBandCount * nBandCount values if successful,
12857 : in row-major order, or an empty vector in case of failure
12858 :
12859 : @since 3.13
12860 :
12861 : @see GetInterBandCovarianceMatrix()
12862 : */
12863 0 : std::vector<double> GDALDataset::ComputeInterBandCovarianceMatrix(
12864 : int nBandCount, const int *panBandList, bool bApproxOK,
12865 : bool bWriteIntoMetadata, int nDeltaDegreeOfFreedom,
12866 : GDALProgressFunc pfnProgress, void *pProgressData)
12867 : {
12868 0 : std::vector<double> res;
12869 0 : const int nBandCountToUse = nBandCount == 0 ? nBands : nBandCount;
12870 0 : if (nBandCountToUse == 0)
12871 0 : return res;
12872 : if constexpr (sizeof(size_t) < sizeof(uint64_t))
12873 : {
12874 : // Check that nBandCountToUse * nBandCountToUse will not overflow size_t
12875 : if (static_cast<uint32_t>(nBandCountToUse) >
12876 : std::numeric_limits<uint16_t>::max())
12877 : {
12878 : CPLError(CE_Failure, CPLE_OutOfMemory,
12879 : "Not enough memory to store result");
12880 : return res;
12881 : }
12882 : }
12883 : try
12884 : {
12885 0 : res.resize(static_cast<size_t>(nBandCountToUse) * nBandCountToUse);
12886 : }
12887 0 : catch (const std::exception &)
12888 : {
12889 0 : CPLError(CE_Failure, CPLE_OutOfMemory,
12890 : "Not enough memory to store result");
12891 0 : return res;
12892 : }
12893 :
12894 0 : if (ComputeInterBandCovarianceMatrix(
12895 : res.data(), res.size(), nBandCount, panBandList, bApproxOK,
12896 : bWriteIntoMetadata, nDeltaDegreeOfFreedom, pfnProgress,
12897 0 : pProgressData) != CE_None)
12898 0 : res.clear();
12899 0 : return res;
12900 : }
12901 :
12902 : /************************************************************************/
12903 : /* ComputeInterBandCovarianceMatrixInternal() */
12904 : /************************************************************************/
12905 :
12906 : template <class T>
12907 : // CPL_NOSANITIZE_UNSIGNED_INT_OVERFLOW because it seems the uses of openmp-simd
12908 : // causes that to happen
12909 : CPL_NOSANITIZE_UNSIGNED_INT_OVERFLOW static CPLErr
12910 15 : ComputeInterBandCovarianceMatrixInternal(GDALDataset *poDS,
12911 : double *padfCovMatrix, int nBandCount,
12912 : const int *panBandList,
12913 : GDALRasterBand *const *papoBands,
12914 : int nDeltaDegreeOfFreedom,
12915 : GDALProgressFunc pfnProgress,
12916 : void *pProgressData)
12917 : {
12918 : // We use the padfCovMatrix to accumulate co-moments
12919 : // Dimension = nBandCount * nBandCount
12920 15 : double *const padfComomentMatrix = padfCovMatrix;
12921 :
12922 : // Matrix of nBandCount * nBandCount storing co-moments, in optimized
12923 : // case when the block has no nodata value
12924 : // Only used if T != double
12925 30 : [[maybe_unused]] std::vector<T> aCurBlockComomentMatrix;
12926 :
12927 : // Count number of valid values in padfComomentMatrix for each (i,j) tuple
12928 : // Updated while iterating over blocks
12929 : // Dimension = nBandCount * nBandCount
12930 30 : std::vector<uint64_t> anCount;
12931 :
12932 : // Mean of bands, for each (i,j) tuple.
12933 : // Updated while iterating over blocks.
12934 : // This is a matrix rather than a vector due to the fact when need to update
12935 : // it in sync with padfComomentMatrix
12936 : // Dimension = nBandCount * nBandCount
12937 30 : std::vector<T> adfMean;
12938 :
12939 : // Number of valid values when computing adfMean, for each (i,j) tuple.
12940 : // Updated while iterating over blocks.
12941 : // This is a matrix rather than a vector due to the fact when need to update
12942 : // it in sync with padfComomentMatrix
12943 : // Dimension = nBandCount * nBandCount
12944 30 : std::vector<uint64_t> anCountMean;
12945 :
12946 : // Mean of values for each band i. Refreshed for each block.
12947 : // Dimension = nBandCount
12948 30 : std::vector<T> adfCurBlockMean;
12949 :
12950 : // Number of values participating to the mean for each band i.
12951 : // Refreshed for each block. Dimension = nBandCount
12952 30 : std::vector<size_t> anCurBlockCount;
12953 :
12954 : // Pixel values for all selected values for the current block
12955 : // Dimension = nBlockXSize * nBlockYSize * nBandCount
12956 30 : std::vector<T> adfCurBlockPixelsAllBands;
12957 :
12958 : // Vector of nodata values for all bands. Dimension = nBandCount
12959 30 : std::vector<T> adfNoData;
12960 :
12961 : // Vector of mask bands for all bands. Dimension = nBandCount
12962 30 : std::vector<GDALRasterBand *> apoMaskBands;
12963 :
12964 : // Vector of vector of mask values. Dimension = nBandCount
12965 30 : std::vector<std::vector<GByte>> aabyCurBlockMask;
12966 :
12967 : // Vector of pointer to vector of mask values. Dimension = nBandCount
12968 30 : std::vector<std::vector<GByte> *> pabyCurBlockMask;
12969 :
12970 15 : int nBlockXSize = 0;
12971 15 : int nBlockYSize = 0;
12972 15 : papoBands[panBandList[0] - 1]->GetBlockSize(&nBlockXSize, &nBlockYSize);
12973 :
12974 30 : if (static_cast<uint64_t>(nBlockXSize) * nBlockYSize >
12975 15 : std::numeric_limits<size_t>::max() / nBandCount)
12976 : {
12977 0 : poDS->ReportError(CE_Failure, CPLE_OutOfMemory,
12978 : "Not enough memory for intermediate computations");
12979 0 : return CE_Failure;
12980 : }
12981 15 : const size_t nPixelsInBlock =
12982 15 : static_cast<size_t>(nBlockXSize) * nBlockYSize;
12983 :
12984 : // Allocate temporary matrices and vectors
12985 15 : const auto nMatrixSize = static_cast<size_t>(nBandCount) * nBandCount;
12986 :
12987 : using MySignedSize_t = std::make_signed_t<size_t>;
12988 15 : const auto kMax =
12989 15 : static_cast<MySignedSize_t>(nBandCount) * (nBandCount + 1) / 2;
12990 30 : std::vector<std::pair<int, int>> anMapLinearIdxToIJ;
12991 : try
12992 : {
12993 15 : anCount.resize(nMatrixSize);
12994 15 : adfMean.resize(nMatrixSize);
12995 15 : anCountMean.resize(nMatrixSize);
12996 :
12997 : if constexpr (!std::is_same_v<T, double>)
12998 : {
12999 : aCurBlockComomentMatrix.resize(nMatrixSize);
13000 : }
13001 :
13002 15 : anMapLinearIdxToIJ.resize(kMax);
13003 :
13004 15 : adfCurBlockPixelsAllBands.resize(nPixelsInBlock * nBandCount);
13005 :
13006 15 : adfCurBlockMean.resize(nBandCount);
13007 15 : anCurBlockCount.resize(nBandCount);
13008 15 : adfNoData.resize(nBandCount);
13009 15 : apoMaskBands.resize(nBandCount);
13010 15 : aabyCurBlockMask.resize(nBandCount);
13011 15 : pabyCurBlockMask.resize(nBandCount);
13012 : }
13013 0 : catch (const std::exception &)
13014 : {
13015 0 : poDS->ReportError(CE_Failure, CPLE_OutOfMemory,
13016 : "Not enough memory for intermediate computations");
13017 0 : return CE_Failure;
13018 : }
13019 :
13020 15 : constexpr T ZERO{0};
13021 15 : std::fill(padfComomentMatrix,
13022 15 : padfComomentMatrix + static_cast<size_t>(nBandCount) * nBandCount,
13023 15 : 0);
13024 :
13025 : {
13026 15 : MySignedSize_t nLinearIdx = 0;
13027 1045 : for (int i = 0; i < nBandCount; ++i)
13028 : {
13029 501581 : for (int j = i; j < nBandCount; ++j)
13030 : {
13031 500551 : anMapLinearIdxToIJ[nLinearIdx] = {i, j};
13032 500551 : ++nLinearIdx;
13033 : }
13034 : }
13035 : }
13036 :
13037 : // Fetch nodata values and mask bands
13038 15 : bool bAllBandsSameMask = false;
13039 15 : bool bIsAllInteger = false;
13040 15 : bool bNoneHasMaskOrNodata = false;
13041 1045 : for (int i = 0; i < nBandCount; ++i)
13042 : {
13043 1030 : const auto poBand = papoBands[panBandList[i] - 1];
13044 2057 : bIsAllInteger = (i == 0 || bIsAllInteger) &&
13045 1027 : GDALDataTypeIsInteger(poBand->GetRasterDataType());
13046 1030 : int bHasNoData = FALSE;
13047 1030 : double dfNoData = poBand->GetNoDataValue(&bHasNoData);
13048 1030 : if (!bHasNoData)
13049 : {
13050 1028 : dfNoData = std::numeric_limits<double>::quiet_NaN();
13051 :
13052 1032 : if (poBand->GetMaskFlags() != GMF_ALL_VALID &&
13053 4 : poBand->GetColorInterpretation() != GCI_AlphaBand)
13054 : {
13055 4 : apoMaskBands[i] = poBand->GetMaskBand();
13056 : try
13057 : {
13058 4 : aabyCurBlockMask[i].resize(nPixelsInBlock);
13059 : }
13060 0 : catch (const std::exception &)
13061 : {
13062 0 : poDS->ReportError(
13063 : CE_Failure, CPLE_OutOfMemory,
13064 : "Not enough memory for intermediate computations");
13065 0 : return CE_Failure;
13066 : }
13067 : #ifndef __COVERITY__
13068 : // coverity[escape]
13069 4 : pabyCurBlockMask[i] = &aabyCurBlockMask[i];
13070 : #endif
13071 : }
13072 : }
13073 1030 : adfNoData[i] = static_cast<T>(dfNoData);
13074 1030 : if (i == 0)
13075 15 : bAllBandsSameMask = (apoMaskBands[0] != nullptr);
13076 1015 : else if (bAllBandsSameMask)
13077 2 : bAllBandsSameMask = (apoMaskBands[i] == apoMaskBands[0]);
13078 :
13079 3072 : bNoneHasMaskOrNodata = (i == 0 || bNoneHasMaskOrNodata) &&
13080 3072 : std::isnan(dfNoData) &&
13081 1026 : apoMaskBands[i] == nullptr;
13082 : }
13083 15 : if (bAllBandsSameMask)
13084 : {
13085 2 : for (int i = 1; i < nBandCount; ++i)
13086 : {
13087 1 : apoMaskBands[i] = nullptr;
13088 1 : aabyCurBlockMask[i].clear();
13089 1 : pabyCurBlockMask[i] = pabyCurBlockMask[0];
13090 : }
13091 : }
13092 :
13093 15 : const auto nIterCount =
13094 : static_cast<uint64_t>(
13095 15 : cpl::div_round_up(poDS->GetRasterXSize(), nBlockXSize)) *
13096 15 : cpl::div_round_up(poDS->GetRasterYSize(), nBlockYSize);
13097 15 : uint64_t nCurIter = 0;
13098 :
13099 15 : int nNumThreads = 1;
13100 : #ifdef HAVE_OPENMP
13101 15 : if (nBandCount >= 100)
13102 : {
13103 1 : const int nMaxNumThreads = std::max(1, CPLGetNumCPUs() / 2);
13104 : nNumThreads =
13105 1 : GDALGetNumThreads(nMaxNumThreads, /* bDefaultToAllCPUs= */ false);
13106 : }
13107 : #endif
13108 :
13109 : #ifdef CAN_DETECT_AVX2_FMA_AT_RUNTIME
13110 30 : const bool bHasAVX2_FMA = CPLHaveRuntimeAVX() &&
13111 30 : __builtin_cpu_supports("avx2") &&
13112 : __builtin_cpu_supports("fma");
13113 : #endif
13114 :
13115 : // Iterate over all blocks
13116 77 : for (const auto &window : papoBands[panBandList[0] - 1]->IterateWindows())
13117 : {
13118 32 : const auto nThisBlockPixelCount =
13119 32 : static_cast<size_t>(window.nXSize) * window.nYSize;
13120 :
13121 : // Extract pixel values and masks
13122 96 : CPLErr eErr = poDS->RasterIO(
13123 32 : GF_Read, window.nXOff, window.nYOff, window.nXSize, window.nYSize,
13124 32 : adfCurBlockPixelsAllBands.data(), window.nXSize, window.nYSize,
13125 : gdal::CXXTypeTraits<T>::gdal_type, nBandCount, panBandList, 0, 0, 0,
13126 : nullptr);
13127 32 : if (eErr == CE_None && bAllBandsSameMask)
13128 : {
13129 2 : eErr = apoMaskBands[0]->RasterIO(
13130 1 : GF_Read, window.nXOff, window.nYOff, window.nXSize,
13131 1 : window.nYSize, aabyCurBlockMask[0].data(), window.nXSize,
13132 1 : window.nYSize, GDT_Byte, 0, 0, nullptr);
13133 : }
13134 : else
13135 : {
13136 1108 : for (int i = 0; eErr == CE_None && i < nBandCount; ++i)
13137 : {
13138 1077 : if (apoMaskBands[i])
13139 : {
13140 4 : eErr = apoMaskBands[i]->RasterIO(
13141 2 : GF_Read, window.nXOff, window.nYOff, window.nXSize,
13142 2 : window.nYSize, aabyCurBlockMask[i].data(),
13143 2 : window.nXSize, window.nYSize, GDT_Byte, 0, 0, nullptr);
13144 : }
13145 : }
13146 : }
13147 32 : if (eErr != CE_None)
13148 1 : return eErr;
13149 :
13150 : // Compute the mean of all bands for this block
13151 32 : bool bAllBandsAreAllNodata = false;
13152 32 : bool bNoBandHasNodata = false;
13153 1111 : for (int i = 0; i < nBandCount; ++i)
13154 : {
13155 1079 : T dfSum = 0;
13156 1079 : size_t nCount = 0;
13157 1079 : const T dfNoDataI = adfNoData[i];
13158 1079 : const T *padfI =
13159 1079 : adfCurBlockPixelsAllBands.data() + i * nThisBlockPixelCount;
13160 : #ifdef HAVE_OPENMP_SIMD
13161 1079 : #pragma omp simd reduction(+ : dfSum)
13162 : #endif
13163 : for (size_t iPixel = 0; iPixel < nThisBlockPixelCount; ++iPixel)
13164 : {
13165 822482 : const T dfI = padfI[iPixel];
13166 822482 : const bool bIsValid =
13167 1644950 : !std::isnan(dfI) && dfI != dfNoDataI &&
13168 822466 : (!pabyCurBlockMask[i] || (*pabyCurBlockMask[i])[iPixel]);
13169 822482 : nCount += bIsValid;
13170 822482 : dfSum += bIsValid ? dfI : ZERO;
13171 : }
13172 1079 : adfCurBlockMean[i] = nCount > 0 ? dfSum / nCount : ZERO;
13173 1079 : anCurBlockCount[i] = nCount;
13174 1079 : bAllBandsAreAllNodata =
13175 1079 : (i == 0 || bAllBandsAreAllNodata) && (nCount == 0);
13176 1079 : bNoBandHasNodata = (i == 0 || bNoBandHasNodata) &&
13177 : (nCount == nThisBlockPixelCount);
13178 : }
13179 :
13180 : // Modify the pixel values to shift them by minus the mean
13181 32 : if (!bAllBandsAreAllNodata)
13182 : {
13183 1103 : for (int i = 0; i < nBandCount; ++i)
13184 : {
13185 1074 : T *padfI =
13186 1074 : adfCurBlockPixelsAllBands.data() + i * nThisBlockPixelCount;
13187 1074 : const T dfMeanI = adfCurBlockMean[i];
13188 823546 : for (size_t iPixel = 0; iPixel < nThisBlockPixelCount; ++iPixel)
13189 : {
13190 822472 : padfI[iPixel] -= dfMeanI;
13191 : }
13192 : }
13193 : }
13194 :
13195 : // Update padfComomentMatrix, anCount, adfMean, anCountMean
13196 : // from dfComoment, nCount, adfCurBlockMean, anCurBlockCount
13197 32 : const auto UpdateGlobalValues =
13198 13507600 : [&anCount, &adfMean, &anCountMean, &adfCurBlockMean,
13199 : &anCurBlockCount, padfComomentMatrix,
13200 : nBandCount](int i, int j, size_t nCount, T dfComoment)
13201 : {
13202 500647 : const auto idxInMatrixI = static_cast<size_t>(i) * nBandCount + j;
13203 500647 : const auto idxInMatrixJ = static_cast<size_t>(j) * nBandCount + i;
13204 :
13205 : // Update the total comoment using last formula of paragraph
13206 : // https://en.wikipedia.org/wiki/Algorithms_for_calculating_variance#Online :
13207 : // CoMoment(A+B) = CoMoment(A) + CoMoment(B) +
13208 : // (mean_I(A) - mean_I(B)) *
13209 : // (mean_J(A) - mean_J(B)) *
13210 : // (count(A) * count(B)) / (count(A) + count(B))
13211 : //
13212 : // There might be a small gotcha in the fact that the set of
13213 : // pixels on which the means are computed is not always the
13214 : // same as the the one on which the comoment is computed, if
13215 : // pixels are not valid/invalid at the same indices among bands
13216 : // It is not obvious (to me) what should be the correct behavior.
13217 : // The current approach has the benefit to avoid recomputing
13218 : // the mean for each (i,j) tuple, but only for all i.
13219 500647 : if (nCount > 0)
13220 : {
13221 500639 : padfComomentMatrix[idxInMatrixI] +=
13222 : static_cast<double>(dfComoment);
13223 500639 : padfComomentMatrix[idxInMatrixI] +=
13224 500639 : static_cast<double>(adfMean[idxInMatrixI] -
13225 500639 : adfCurBlockMean[i]) *
13226 500639 : static_cast<double>(adfMean[idxInMatrixJ] -
13227 500639 : adfCurBlockMean[j]) *
13228 500639 : (static_cast<double>(anCount[idxInMatrixI]) *
13229 500639 : static_cast<double>(nCount) /
13230 500639 : static_cast<double>(anCount[idxInMatrixI] + nCount));
13231 :
13232 500639 : anCount[idxInMatrixI] += nCount;
13233 : }
13234 :
13235 : // Update means
13236 500647 : if (anCurBlockCount[i] > 0)
13237 : {
13238 1001280 : adfMean[idxInMatrixI] +=
13239 500640 : (adfCurBlockMean[i] - adfMean[idxInMatrixI]) *
13240 : static_cast<T>(
13241 500640 : static_cast<double>(anCurBlockCount[i]) /
13242 500640 : static_cast<double>(anCountMean[idxInMatrixI] +
13243 : anCurBlockCount[i]));
13244 :
13245 500640 : anCountMean[idxInMatrixI] += anCurBlockCount[i];
13246 : }
13247 :
13248 500647 : if (idxInMatrixI != idxInMatrixJ && anCurBlockCount[j] > 0)
13249 : {
13250 999132 : adfMean[idxInMatrixJ] +=
13251 499566 : (adfCurBlockMean[j] - adfMean[idxInMatrixJ]) *
13252 : static_cast<T>(
13253 499566 : static_cast<double>(anCurBlockCount[j]) /
13254 499566 : static_cast<double>(anCountMean[idxInMatrixJ] +
13255 : anCurBlockCount[j]));
13256 :
13257 499566 : anCountMean[idxInMatrixJ] += anCurBlockCount[j];
13258 : }
13259 : };
13260 :
13261 32 : if (bAllBandsAreAllNodata)
13262 : {
13263 : // Optimized code path where all values in the current block
13264 : // are invalid
13265 :
13266 8 : for (int i = 0; i < nBandCount; ++i)
13267 : {
13268 12 : for (int j = i; j < nBandCount; ++j)
13269 : {
13270 7 : UpdateGlobalValues(i, j, 0, ZERO);
13271 : }
13272 : }
13273 : }
13274 29 : else if (bNoBandHasNodata)
13275 : {
13276 : // Optimized code path where there are no invalid value in the
13277 : // current block
13278 :
13279 : if constexpr (!std::is_same_v<T, double>)
13280 : {
13281 : std::fill(aCurBlockComomentMatrix.begin(),
13282 : aCurBlockComomentMatrix.end(), ZERO);
13283 :
13284 : GDALMatrixMultiplyAByTransposeAUpperTriangle(
13285 : nNumThreads, adfCurBlockPixelsAllBands.data(),
13286 : aCurBlockComomentMatrix.data(), nBandCount,
13287 : nThisBlockPixelCount);
13288 : }
13289 : #ifdef CAN_DETECT_AVX2_FMA_AT_RUNTIME
13290 24 : else if (bHasAVX2_FMA)
13291 : {
13292 24 : GDALMatrixMultiplyAByTransposeAUpperTriangle_AVX2_FMA(
13293 : nNumThreads, adfCurBlockPixelsAllBands.data(),
13294 : padfComomentMatrix, nBandCount, nThisBlockPixelCount);
13295 : }
13296 : #endif
13297 : else
13298 : {
13299 0 : GDALMatrixMultiplyAByTransposeAUpperTriangle(
13300 : nNumThreads, adfCurBlockPixelsAllBands.data(),
13301 : padfComomentMatrix, nBandCount, nThisBlockPixelCount);
13302 : }
13303 :
13304 1088 : for (int i = 0; i < nBandCount; ++i)
13305 : {
13306 501689 : for (int j = i; j < nBandCount; ++j)
13307 : {
13308 : if constexpr (!std::is_same_v<T, double>)
13309 : {
13310 : const auto idxInMatrixI =
13311 : static_cast<size_t>(i) * nBandCount + j;
13312 : UpdateGlobalValues(
13313 : i, j, nThisBlockPixelCount,
13314 : aCurBlockComomentMatrix[idxInMatrixI]);
13315 : }
13316 : else
13317 : {
13318 500625 : UpdateGlobalValues(i, j, nThisBlockPixelCount, ZERO);
13319 : }
13320 : }
13321 : }
13322 : }
13323 : else
13324 : {
13325 : #ifdef HAVE_OPENMP
13326 5 : #pragma omp parallel for schedule(static) num_threads(nNumThreads)
13327 : #endif
13328 : for (MySignedSize_t k = 0; k < kMax; ++k)
13329 : {
13330 : int i, j;
13331 : std::tie(i, j) = anMapLinearIdxToIJ[k];
13332 :
13333 : // Now compute the moment of (i, j), but just for this block
13334 : size_t nCount = 0;
13335 : T dfComoment = 0;
13336 : const T *padfI =
13337 : adfCurBlockPixelsAllBands.data() + i * nThisBlockPixelCount;
13338 : const T *padfJ =
13339 : adfCurBlockPixelsAllBands.data() + j * nThisBlockPixelCount;
13340 :
13341 : // Use https://en.wikipedia.org/wiki/Algorithms_for_calculating_variance#Two-pass
13342 : // for the current block
13343 : if ((anCurBlockCount[i] == nThisBlockPixelCount &&
13344 : anCurBlockCount[j] == nThisBlockPixelCount) ||
13345 : (bNoneHasMaskOrNodata && bIsAllInteger))
13346 : {
13347 : // Most optimized code path: integer, no nodata, no mask
13348 : #ifdef HAVE_OPENMP_SIMD
13349 : #pragma omp simd reduction(+ : dfComoment)
13350 : #endif
13351 : for (size_t iPixel = 0; iPixel < nThisBlockPixelCount;
13352 : ++iPixel)
13353 : {
13354 : dfComoment += padfI[iPixel] * padfJ[iPixel];
13355 : }
13356 : nCount = nThisBlockPixelCount;
13357 : }
13358 : else if (bNoneHasMaskOrNodata)
13359 : {
13360 : // Floating-point code path with no nodata and no mask
13361 : #ifdef HAVE_OPENMP_SIMD
13362 : #pragma omp simd reduction(+ : dfComoment)
13363 : #endif
13364 : for (size_t iPixel = 0; iPixel < nThisBlockPixelCount;
13365 : ++iPixel)
13366 : {
13367 : const T dfAcc = padfI[iPixel] * padfJ[iPixel];
13368 : const bool bIsValid = !std::isnan(dfAcc);
13369 : nCount += bIsValid;
13370 : dfComoment += bIsValid ? dfAcc : ZERO;
13371 : }
13372 : }
13373 : else if (!std::isnan(adfNoData[i]) && !std::isnan(adfNoData[j]))
13374 : {
13375 : // Code path when there are both nodata values
13376 : const T shiftedNoDataI = adfNoData[i] - adfCurBlockMean[i];
13377 : const T shiftedNoDataJ = adfNoData[j] - adfCurBlockMean[j];
13378 :
13379 : #ifdef HAVE_OPENMP_SIMD
13380 : #pragma omp simd reduction(+ : dfComoment)
13381 : #endif
13382 : for (size_t iPixel = 0; iPixel < nThisBlockPixelCount;
13383 : ++iPixel)
13384 : {
13385 : const T dfI = padfI[iPixel];
13386 : const T dfJ = padfJ[iPixel];
13387 : const T dfAcc = dfI * dfJ;
13388 : const bool bIsValid = !std::isnan(dfAcc) &&
13389 : dfI != shiftedNoDataI &&
13390 : dfJ != shiftedNoDataJ;
13391 : nCount += bIsValid;
13392 : dfComoment += bIsValid ? dfAcc : ZERO;
13393 : }
13394 : }
13395 : else
13396 : {
13397 : // Generic code path
13398 : const T shiftedNoDataI = adfNoData[i] - adfCurBlockMean[i];
13399 : const T shiftedNoDataJ = adfNoData[j] - adfCurBlockMean[j];
13400 :
13401 : #ifdef HAVE_OPENMP_SIMD
13402 : #pragma omp simd reduction(+ : dfComoment)
13403 : #endif
13404 : for (size_t iPixel = 0; iPixel < nThisBlockPixelCount;
13405 : ++iPixel)
13406 : {
13407 : const T dfI = padfI[iPixel];
13408 : const T dfJ = padfJ[iPixel];
13409 : const T dfAcc = dfI * dfJ;
13410 : const bool bIsValid =
13411 : !std::isnan(dfAcc) && dfI != shiftedNoDataI &&
13412 : dfJ != shiftedNoDataJ &&
13413 : (!pabyCurBlockMask[i] ||
13414 : (*pabyCurBlockMask[i])[iPixel]) &&
13415 : (!pabyCurBlockMask[j] ||
13416 : (*pabyCurBlockMask[j])[iPixel]);
13417 : nCount += bIsValid;
13418 : dfComoment += bIsValid ? dfAcc : ZERO;
13419 : }
13420 : }
13421 :
13422 : UpdateGlobalValues(i, j, nCount, dfComoment);
13423 : }
13424 : }
13425 :
13426 32 : ++nCurIter;
13427 35 : if (pfnProgress &&
13428 3 : !pfnProgress(static_cast<double>(nCurIter) / nIterCount, "",
13429 : pProgressData))
13430 : {
13431 1 : poDS->ReportError(CE_Failure, CPLE_UserInterrupt,
13432 : "User terminated");
13433 1 : return CE_Failure;
13434 : }
13435 : }
13436 :
13437 : // Finalize by dividing co-moments by the number of contributing values
13438 : // (minus nDeltaDegreeOfFreedom) to compute final covariances.
13439 44 : for (int i = 0; i < nBandCount; ++i)
13440 : {
13441 : // The covariance matrix is symmetric. So start at i
13442 81 : for (int j = i; j < nBandCount; ++j)
13443 : {
13444 51 : const auto idxInMatrixI = static_cast<size_t>(i) * nBandCount + j;
13445 51 : const double dfCovariance =
13446 51 : (nDeltaDegreeOfFreedom < 0 ||
13447 51 : anCount[idxInMatrixI] <=
13448 51 : static_cast<uint64_t>(nDeltaDegreeOfFreedom))
13449 4 : ? std::numeric_limits<double>::quiet_NaN()
13450 94 : : padfComomentMatrix[idxInMatrixI] /
13451 47 : static_cast<double>(anCount[idxInMatrixI] -
13452 47 : nDeltaDegreeOfFreedom);
13453 :
13454 51 : padfCovMatrix[idxInMatrixI] = dfCovariance;
13455 : // Fill lower triangle
13456 51 : padfCovMatrix[static_cast<size_t>(j) * nBandCount + i] =
13457 : dfCovariance;
13458 : }
13459 : }
13460 :
13461 14 : return CE_None;
13462 : }
13463 :
13464 : /************************************************************************/
13465 : /* GDALDataset::ComputeInterBandCovarianceMatrix() */
13466 : /************************************************************************/
13467 :
13468 : /**
13469 : \brief Compute the covariance matrix between bands of this dataset.
13470 :
13471 : The covariance indicates the level to which two bands vary together.
13472 :
13473 : If we call \f$ v_i[y,x] \f$ the value of pixel at row=y and column=x for band i,
13474 : and \f$ mean_i \f$ the mean value of all pixels of band i, then
13475 :
13476 : \f[
13477 : \mathrm{cov}[i,j] =
13478 : \frac{
13479 : \sum_{y,x} \left( v_i[y,x] - \mathrm{mean}_i \right)
13480 : \left( v_j[y,x] - \mathrm{mean}_j \right)
13481 : }{
13482 : \mathrm{pixel\_count} - \mathrm{nDeltaDegreeOfFreedom}
13483 : }
13484 : \f]
13485 :
13486 : When there are no nodata values, \f$ pixel\_count = GetRasterXSize() * GetRasterYSize() \f$.
13487 : We can see that \f$ cov[i,j] = cov[j,i] \f$, and consequently the returned matrix
13488 : is symmetric.
13489 :
13490 : A value of nDeltaDegreeOfFreedom=1 (the default) will return a unbiased estimate
13491 : if the pixels in bands are considered to be a sample of the whole population.
13492 : This is consistent with the default of
13493 : https://numpy.org/doc/stable/reference/generated/numpy.cov.html and the returned
13494 : matrix is consistent with what can be obtained with
13495 :
13496 : \verbatim embed:rst
13497 : .. code-block:: python
13498 :
13499 : numpy.cov(
13500 : [ds.GetRasterBand(n + 1).ReadAsArray().ravel() for n in range(ds.RasterCount)]
13501 : )
13502 : \endverbatim
13503 :
13504 : Otherwise a value of nDeltaDegreeOfFreedom=0 can be used if they are considered
13505 : to be the whole population.
13506 :
13507 : The caller must provide an already allocated array in padfCovMatrix of size
13508 : at least nBandCount * nBandCount.
13509 :
13510 : This method recomputes the covariance matrix, even if STATISTICS_COVARIANCES
13511 : metadata items are available in bands. See GetInterBandCovarianceMatrix()
13512 : to use them.
13513 :
13514 : The implementation is optimized to minimize the amount of pixel reading.
13515 :
13516 : This method is the same as the C function GDALDatasetComputeInterBandCovarianceMatrix()
13517 :
13518 : @param[out] padfCovMatrix Pointer to an already allocated output array, of size at least
13519 : nBandCount * nBandCount.
13520 : @param nSize Number of elements in output array.
13521 : @param nBandCount Zero for all bands, or number of values in panBandList.
13522 : Defaults to 0.
13523 : @param panBandList nullptr for all bands if nBandCount == 0, or array of
13524 : nBandCount values such as panBandList[i] is the index
13525 : between 1 and GetRasterCount() of a band that must be used
13526 : in the covariance computation. Defaults to nullptr.
13527 : @param bApproxOK Whether it is acceptable to use a subsample of values.
13528 : Defaults to false.
13529 : @param bWriteIntoMetadata Whether this method must write
13530 : STATISTICS_COVARIANCES band metadata items.
13531 : Defaults to true.
13532 : @param nDeltaDegreeOfFreedom Correction term to subtract in the final
13533 : averaging phase of the covariance computation.
13534 : Defaults to 1.
13535 : @param pfnProgress a function to call to report progress, or NULL.
13536 : @param pProgressData application data to pass to the progress function.
13537 :
13538 : @return CE_None if successful, or CE_Failure in case of failure
13539 :
13540 : @since 3.13
13541 :
13542 : @see GetInterBandCovarianceMatrix()
13543 : */
13544 22 : CPLErr GDALDataset::ComputeInterBandCovarianceMatrix(
13545 : double *padfCovMatrix, size_t nSize, int nBandCount, const int *panBandList,
13546 : bool bApproxOK, bool bWriteIntoMetadata, int nDeltaDegreeOfFreedom,
13547 : GDALProgressFunc pfnProgress, void *pProgressData)
13548 : {
13549 44 : std::vector<int> anBandListTmp; // keep in this scope
13550 22 : if (nBandCount == 0)
13551 : {
13552 0 : if (nBands == 0)
13553 0 : return CE_None;
13554 0 : for (int i = 0; i < nBands; ++i)
13555 0 : anBandListTmp.push_back(i + 1);
13556 0 : nBandCount = nBands;
13557 0 : panBandList = anBandListTmp.data();
13558 : }
13559 : else
13560 : {
13561 22 : if (nBandCount > nBands)
13562 : {
13563 1 : CPLError(CE_Failure, CPLE_AppDefined,
13564 : "ComputeInterBandCovarianceMatrix(): nBandCount > nBands");
13565 1 : return CE_Failure;
13566 : }
13567 1057 : for (int i = 0; i < nBandCount; ++i)
13568 : {
13569 1038 : if (panBandList[i] <= 0 || panBandList[i] > nBands)
13570 : {
13571 2 : CPLError(CE_Failure, CPLE_AppDefined,
13572 : "ComputeInterBandCovarianceMatrix(): invalid value "
13573 : "panBandList[%d] = %d",
13574 2 : i, panBandList[i]);
13575 2 : return CE_Failure;
13576 : }
13577 : }
13578 :
13579 19 : if (bWriteIntoMetadata)
13580 : {
13581 14 : bool bOK = nBandCount == nBands;
13582 38 : for (int i = 0; bOK && i < nBandCount; ++i)
13583 : {
13584 24 : bOK = (panBandList[i] == i + 1);
13585 : }
13586 14 : if (!bOK)
13587 : {
13588 4 : CPLError(CE_Failure, CPLE_AppDefined,
13589 : "ComputeInterBandCovarianceMatrix(): cannot write "
13590 : "STATISTICS_COVARIANCES metadata since the input band "
13591 : "list is not [1, 2, ... GetRasterCount()]");
13592 4 : return CE_Failure;
13593 : }
13594 : }
13595 : }
13596 :
13597 15 : const auto nMatrixSize = static_cast<size_t>(nBandCount) * nBandCount;
13598 15 : if (nSize < nMatrixSize)
13599 : {
13600 0 : CPLError(CE_Failure, CPLE_AppDefined,
13601 : "ComputeInterBandCovarianceMatrix(): too small result matrix "
13602 : "provided");
13603 0 : return CE_Failure;
13604 : }
13605 :
13606 : // Find appropriate overview dataset
13607 15 : GDALDataset *poActiveDS = this;
13608 15 : if (bApproxOK && papoBands[panBandList[0] - 1]->GetOverviewCount() > 0)
13609 : {
13610 1 : GDALDataset *poOvrDS = nullptr;
13611 4 : for (int i = 0; i < nBandCount; ++i)
13612 : {
13613 3 : const int nIdxBand = panBandList[i] - 1;
13614 6 : auto poOvrBand = papoBands[nIdxBand]->GetRasterSampleOverview(
13615 3 : GDALSTAT_APPROX_NUMSAMPLES);
13616 :
13617 6 : if (poOvrBand == papoBands[i] ||
13618 3 : poOvrBand->GetBand() != panBandList[i])
13619 : {
13620 0 : poOvrDS = nullptr;
13621 0 : break;
13622 : }
13623 3 : else if (i == 0)
13624 : {
13625 1 : if (poOvrBand->GetDataset() == this)
13626 : {
13627 0 : break;
13628 : }
13629 1 : poOvrDS = poOvrBand->GetDataset();
13630 : }
13631 2 : else if (poOvrBand->GetDataset() != poOvrDS)
13632 : {
13633 0 : poOvrDS = nullptr;
13634 0 : break;
13635 : }
13636 : }
13637 1 : if (poOvrDS)
13638 : {
13639 1 : poActiveDS = poOvrDS;
13640 : }
13641 : }
13642 :
13643 : #ifdef GDAL_COVARIANCE_CAN_USE_FLOAT32
13644 : const auto UseFloat32 = [](GDALDataType eDT)
13645 : {
13646 : return eDT == GDT_UInt8 || eDT == GDT_Int8 || eDT == GDT_UInt16 ||
13647 : eDT == GDT_Int16 || eDT == GDT_Float32;
13648 : };
13649 :
13650 : bool bUseFloat32 = UseFloat32(
13651 : poActiveDS->GetRasterBand(panBandList[0])->GetRasterDataType());
13652 : for (int i = 1; bUseFloat32 && i < nBandCount; ++i)
13653 : {
13654 : bUseFloat32 = UseFloat32(
13655 : poActiveDS->GetRasterBand(panBandList[i])->GetRasterDataType());
13656 : }
13657 : #endif
13658 :
13659 : CPLErr eErr =
13660 : #ifdef GDAL_COVARIANCE_CAN_USE_FLOAT32
13661 : bUseFloat32 ? ComputeInterBandCovarianceMatrixInternal<float>(
13662 : poActiveDS, padfCovMatrix, nBandCount, panBandList,
13663 : poActiveDS->papoBands, nDeltaDegreeOfFreedom,
13664 : pfnProgress, pProgressData)
13665 : :
13666 : #endif
13667 30 : ComputeInterBandCovarianceMatrixInternal<double>(
13668 : poActiveDS, padfCovMatrix, nBandCount, panBandList,
13669 15 : poActiveDS->papoBands, nDeltaDegreeOfFreedom,
13670 : pfnProgress, pProgressData);
13671 :
13672 15 : if (bWriteIntoMetadata && eErr == CE_None)
13673 : {
13674 10 : CPLAssert(nBands == nBandCount);
13675 20 : std::string osStr;
13676 10 : size_t idx = 0;
13677 32 : for (int i = 0; i < nBands; ++i)
13678 : {
13679 22 : osStr.clear();
13680 74 : for (int j = 0; j < nBands; ++j, ++idx)
13681 : {
13682 52 : if (j > 0)
13683 30 : osStr += ',';
13684 52 : osStr += CPLSPrintf("%.17g", padfCovMatrix[idx]);
13685 : }
13686 22 : papoBands[i]->SetMetadataItem("STATISTICS_COVARIANCES",
13687 22 : osStr.c_str());
13688 : }
13689 : }
13690 :
13691 15 : return eErr;
13692 : }
13693 :
13694 : /************************************************************************/
13695 : /* GDALDatasetComputeInterBandCovarianceMatrix() */
13696 : /************************************************************************/
13697 :
13698 : /**
13699 : \brief Compute the covariance matrix between bands of this dataset.
13700 :
13701 : The covariance indicates the level to which two bands vary together.
13702 :
13703 : If we call \f$ v_i[y,x] \f$ the value of pixel at row=y and column=x for band i,
13704 : and \f$ mean_i \f$ the mean value of all pixels of band i, then
13705 :
13706 : \f[
13707 : \mathrm{cov}[i,j] =
13708 : \frac{
13709 : \sum_{y,x} \left( v_i[y,x] - \mathrm{mean}_i \right)
13710 : \left( v_j[y,x] - \mathrm{mean}_j \right)
13711 : }{
13712 : \mathrm{pixel\_count} - \mathrm{nDeltaDegreeOfFreedom}
13713 : }
13714 : \f]
13715 :
13716 : When there are no nodata values, \f$ pixel\_count = GetRasterXSize() * GetRasterYSize() \f$.
13717 : We can see that \f$ cov[i,j] = cov[j,i] \f$, and consequently the returned matrix
13718 : is symmetric.
13719 :
13720 : A value of nDeltaDegreeOfFreedom=1 (the default) will return a unbiased estimate
13721 : if the pixels in bands are considered to be a sample of the whole population.
13722 : This is consistent with the default of
13723 : https://numpy.org/doc/stable/reference/generated/numpy.cov.html and the returned
13724 : matrix is consistent with what can be obtained with
13725 :
13726 : \verbatim embed:rst
13727 : .. code-block:: python
13728 :
13729 : numpy.cov(
13730 : [ds.GetRasterBand(n + 1).ReadAsArray().ravel() for n in range(ds.RasterCount)]
13731 : )
13732 : \endverbatim
13733 :
13734 : Otherwise a value of nDeltaDegreeOfFreedom=0 can be used if they are considered
13735 : to be the whole population.
13736 :
13737 : The caller must provide an already allocated array in padfCovMatrix of size
13738 : at least GDALGetRasterCount() * GDALGetRasterCount().
13739 :
13740 : This method recomputes the covariance matrix, even if STATISTICS_COVARIANCES
13741 : metadata items are available in bands. See GDALDatasetGetInterBandCovarianceMatrix()
13742 : to use them.
13743 :
13744 : This function is the same as the C++ method GDALDataset::ComputeInterBandCovarianceMatrix()
13745 :
13746 : @param hDS Dataset handle.
13747 : @param[out] padfCovMatrix Pointer to an already allocated output array, of size at least
13748 : nBandCount * nBandCount.
13749 : @param nSize Number of elements in output array.
13750 : @param nBandCount Zero for all bands, or number of values in panBandList.
13751 : Defaults to 0.
13752 : @param panBandList nullptr for all bands if nBandCount == 0, or array of
13753 : nBandCount values such as panBandList[i] is the index
13754 : between 1 and GetRasterCount() of a band that must be used
13755 : in the covariance computation. Defaults to nullptr.
13756 : @param bApproxOK Whether it is acceptable to use a subsample of values.
13757 : Defaults to false.
13758 : @param bWriteIntoMetadata Whether this method must write
13759 : STATISTICS_COVARIANCES band metadata items.
13760 : Defaults to true.
13761 : @param nDeltaDegreeOfFreedom Correction term to subtract in the final
13762 : averaging phase of the covariance computation.
13763 : Defaults to 1.
13764 : @param pfnProgress a function to call to report progress, or NULL.
13765 : @param pProgressData application data to pass to the progress function.
13766 :
13767 : @return CE_None if successful, or CE_Failure in case of failure
13768 :
13769 : @since 3.13
13770 :
13771 : @see GDALDatasetGetInterBandCovarianceMatrix()
13772 : */
13773 17 : CPLErr GDALDatasetComputeInterBandCovarianceMatrix(
13774 : GDALDatasetH hDS, double *padfCovMatrix, size_t nSize, int nBandCount,
13775 : const int *panBandList, bool bApproxOK, bool bWriteIntoMetadata,
13776 : int nDeltaDegreeOfFreedom, GDALProgressFunc pfnProgress,
13777 : void *pProgressData)
13778 : {
13779 17 : VALIDATE_POINTER1(hDS, __func__, CE_Failure);
13780 17 : VALIDATE_POINTER1(padfCovMatrix, __func__, CE_Failure);
13781 17 : return GDALDataset::FromHandle(hDS)->ComputeInterBandCovarianceMatrix(
13782 : padfCovMatrix, nSize, nBandCount, panBandList, bApproxOK,
13783 17 : bWriteIntoMetadata, nDeltaDegreeOfFreedom, pfnProgress, pProgressData);
13784 : }
|