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_typetraits.h"
57 :
58 : #include "ogr_api.h"
59 : #include "ogr_attrind.h"
60 : #include "ogr_core.h"
61 : #include "ogr_feature.h"
62 : #include "ogr_featurestyle.h"
63 : #include "ogr_gensql.h"
64 : #include "ogr_geometry.h"
65 : #include "ogr_p.h"
66 : #include "ogr_spatialref.h"
67 : #include "ogr_srs_api.h"
68 : #include "ograpispy.h"
69 : #include "ogrsf_frmts.h"
70 : #include "ogrunionlayer.h"
71 : #include "ogr_swq.h"
72 : #include "memmultidim.h"
73 : #include "gdalmultidim_priv.h"
74 :
75 : #include "../frmts/derived/derivedlist.h"
76 :
77 : #ifdef SQLITE_ENABLED
78 : #include "../sqlite/ogrsqliteexecutesql.h"
79 : #endif
80 :
81 : #ifdef HAVE_OPENMP
82 : #include <omp.h>
83 : #endif
84 :
85 : extern const swq_field_type SpecialFieldTypes[SPECIAL_FIELD_COUNT];
86 :
87 : enum class GDALAllowReadWriteMutexState
88 : {
89 : RW_MUTEX_STATE_UNKNOWN,
90 : RW_MUTEX_STATE_ALLOWED,
91 : RW_MUTEX_STATE_DISABLED
92 : };
93 :
94 : const GIntBig TOTAL_FEATURES_NOT_INIT = -2;
95 : const GIntBig TOTAL_FEATURES_UNKNOWN = -1;
96 :
97 : class GDALDataset::Private
98 : {
99 : CPL_DISALLOW_COPY_ASSIGN(Private)
100 :
101 : public:
102 : CPLMutex *hMutex = nullptr;
103 : std::map<GIntBig, int> oMapThreadToMutexTakenCount{};
104 : #ifdef DEBUG_EXTRA
105 : std::map<GIntBig, int> oMapThreadToMutexTakenCountSaved{};
106 : #endif
107 : GDALAllowReadWriteMutexState eStateReadWriteMutex =
108 : GDALAllowReadWriteMutexState::RW_MUTEX_STATE_UNKNOWN;
109 : int nCurrentLayerIdx = 0;
110 : int nLayerCount = -1;
111 : GIntBig nFeatureReadInLayer = 0;
112 : GIntBig nFeatureReadInDataset = 0;
113 : GIntBig nTotalFeaturesInLayer = TOTAL_FEATURES_NOT_INIT;
114 : GIntBig nTotalFeatures = TOTAL_FEATURES_NOT_INIT;
115 : OGRLayer *poCurrentLayer = nullptr;
116 :
117 : std::mutex m_oMutexWKT{};
118 :
119 : char *m_pszWKTCached = nullptr;
120 : OGRSpatialReference *m_poSRSCached = nullptr;
121 : char *m_pszWKTGCPCached = nullptr;
122 : OGRSpatialReference *m_poSRSGCPCached = nullptr;
123 :
124 : GDALDataset *poParentDataset = nullptr;
125 :
126 : bool m_bOverviewsEnabled = true;
127 :
128 : std::vector<int>
129 : m_anBandMap{}; // used by RasterIO(). Values are 1, 2, etc.
130 :
131 186271 : Private() = default;
132 : };
133 :
134 : struct SharedDatasetCtxt
135 : {
136 : // PID of the thread that mark the dataset as shared
137 : // This may not be the actual PID, but the responsiblePID.
138 : GIntBig nPID;
139 : char *pszDescription;
140 : char *pszConcatenatedOpenOptions;
141 : int nOpenFlags;
142 :
143 : GDALDataset *poDS;
144 : };
145 :
146 : // Set of datasets opened as shared datasets (with GDALOpenShared)
147 : // The values in the set are of type SharedDatasetCtxt.
148 : static CPLHashSet *phSharedDatasetSet = nullptr;
149 :
150 : // Set of all datasets created in the constructor of GDALDataset.
151 : // In the case of a shared dataset, memorize the PID of the thread
152 : // that marked the dataset as shared, so that we can remove it from
153 : // the phSharedDatasetSet in the destructor of the dataset, even
154 : // if GDALClose is called from a different thread.
155 : static std::map<GDALDataset *, GIntBig> *poAllDatasetMap = nullptr;
156 :
157 : static CPLMutex *hDLMutex = nullptr;
158 :
159 : // Static array of all datasets. Used by GDALGetOpenDatasets.
160 : // Not thread-safe. See GDALGetOpenDatasets.
161 : static GDALDataset **ppDatasets = nullptr;
162 :
163 8408 : static unsigned long GDALSharedDatasetHashFunc(const void *elt)
164 : {
165 8408 : const SharedDatasetCtxt *psStruct =
166 : static_cast<const SharedDatasetCtxt *>(elt);
167 : return static_cast<unsigned long>(
168 8408 : CPLHashSetHashStr(psStruct->pszDescription) ^
169 8408 : CPLHashSetHashStr(psStruct->pszConcatenatedOpenOptions) ^
170 8408 : psStruct->nOpenFlags ^ psStruct->nPID);
171 : }
172 :
173 7000 : static int GDALSharedDatasetEqualFunc(const void *elt1, const void *elt2)
174 : {
175 7000 : const SharedDatasetCtxt *psStruct1 =
176 : static_cast<const SharedDatasetCtxt *>(elt1);
177 7000 : const SharedDatasetCtxt *psStruct2 =
178 : static_cast<const SharedDatasetCtxt *>(elt2);
179 13927 : return strcmp(psStruct1->pszDescription, psStruct2->pszDescription) == 0 &&
180 6927 : strcmp(psStruct1->pszConcatenatedOpenOptions,
181 6927 : psStruct2->pszConcatenatedOpenOptions) == 0 &&
182 20854 : psStruct1->nPID == psStruct2->nPID &&
183 13927 : psStruct1->nOpenFlags == psStruct2->nOpenFlags;
184 : }
185 :
186 411 : static void GDALSharedDatasetFreeFunc(void *elt)
187 : {
188 411 : SharedDatasetCtxt *psStruct = static_cast<SharedDatasetCtxt *>(elt);
189 411 : CPLFree(psStruct->pszDescription);
190 411 : CPLFree(psStruct->pszConcatenatedOpenOptions);
191 411 : CPLFree(psStruct);
192 411 : }
193 :
194 : static std::string
195 7052 : GDALSharedDatasetConcatenateOpenOptions(CSLConstList papszOpenOptions)
196 : {
197 7052 : std::string osStr;
198 7065 : for (const char *pszOption : cpl::Iterate(papszOpenOptions))
199 13 : osStr += pszOption;
200 7052 : return osStr;
201 : }
202 :
203 : /************************************************************************/
204 : /* Functions shared between gdalproxypool.cpp and gdaldataset.cpp */
205 : /************************************************************************/
206 :
207 : // The open-shared mutex must be used by the ProxyPool too.
208 483667 : CPLMutex **GDALGetphDLMutex()
209 : {
210 483667 : return &hDLMutex;
211 : }
212 :
213 : // The current thread will act in the behalf of the thread of PID
214 : // responsiblePID.
215 473009 : void GDALSetResponsiblePIDForCurrentThread(GIntBig responsiblePID)
216 : {
217 : GIntBig *pResponsiblePID =
218 473009 : static_cast<GIntBig *>(CPLGetTLS(CTLS_RESPONSIBLEPID));
219 473009 : if (pResponsiblePID == nullptr)
220 : {
221 228 : pResponsiblePID = static_cast<GIntBig *>(CPLMalloc(sizeof(GIntBig)));
222 228 : CPLSetTLS(CTLS_RESPONSIBLEPID, pResponsiblePID, TRUE);
223 : }
224 473009 : *pResponsiblePID = responsiblePID;
225 473009 : }
226 :
227 : // Get the PID of the thread that the current thread will act in the behalf of
228 : // By default : the current thread acts in the behalf of itself.
229 606792 : GIntBig GDALGetResponsiblePIDForCurrentThread()
230 : {
231 : GIntBig *pResponsiblePID =
232 606792 : static_cast<GIntBig *>(CPLGetTLS(CTLS_RESPONSIBLEPID));
233 606792 : if (pResponsiblePID == nullptr)
234 44733 : return CPLGetPID();
235 562059 : return *pResponsiblePID;
236 : }
237 :
238 : /************************************************************************/
239 : /* ==================================================================== */
240 : /* GDALDataset */
241 : /* ==================================================================== */
242 : /************************************************************************/
243 :
244 : /**
245 : * \class GDALDataset "gdal_priv.h"
246 : *
247 : * A dataset encapsulating one or more raster bands. Details are further
248 : * discussed in the <a href="https://gdal.org/user/raster_data_model.html">GDAL
249 : * Raster Data Model</a>.
250 : *
251 : * Use GDALOpen() or GDALOpenShared() to create a GDALDataset for a named file,
252 : * or GDALDriver::Create() or GDALDriver::CreateCopy() to create a new
253 : * dataset.
254 : */
255 :
256 : /************************************************************************/
257 : /* GDALDataset() */
258 : /************************************************************************/
259 :
260 : //! @cond Doxygen_Suppress
261 164857 : GDALDataset::GDALDataset()
262 164857 : : GDALDataset(CPLTestBool(CPLGetConfigOption("GDAL_FORCE_CACHING", "NO")))
263 : {
264 164857 : }
265 :
266 186271 : GDALDataset::GDALDataset(int bForceCachedIOIn)
267 186271 : : bForceCachedIO(CPL_TO_BOOL(bForceCachedIOIn)),
268 186271 : m_poPrivate(new(std::nothrow) GDALDataset::Private)
269 : {
270 186271 : }
271 :
272 : //! @endcond
273 :
274 : /************************************************************************/
275 : /* ~GDALDataset() */
276 : /************************************************************************/
277 :
278 : /**
279 : * \brief Destroy an open GDALDataset.
280 : *
281 : * This is the accepted method of closing a GDAL dataset and deallocating
282 : * all resources associated with it.
283 : *
284 : * Equivalent of the C callable GDALClose(). Except that GDALClose() first
285 : * decrements the reference count, and then closes only if it has dropped to
286 : * zero.
287 : *
288 : * For Windows users, it is not recommended to use the delete operator on the
289 : * dataset object because of known issues when allocating and freeing memory
290 : * across module boundaries. Calling GDALClose() is then a better option.
291 : */
292 :
293 186251 : GDALDataset::~GDALDataset()
294 :
295 : {
296 : // we don't want to report destruction of datasets that
297 : // were never really open or meant as internal
298 186251 : if (!bIsInternal && (nBands != 0 || !EQUAL(GetDescription(), "")))
299 : {
300 75001 : if (CPLGetPID() != GDALGetResponsiblePIDForCurrentThread())
301 207 : CPLDebug("GDAL",
302 : "GDALClose(%s, this=%p) (pid=%d, responsiblePID=%d)",
303 207 : GetDescription(), this, static_cast<int>(CPLGetPID()),
304 207 : static_cast<int>(GDALGetResponsiblePIDForCurrentThread()));
305 : else
306 74794 : CPLDebug("GDAL", "GDALClose(%s, this=%p)", GetDescription(), this);
307 : }
308 :
309 186251 : GDALDataset::Close();
310 :
311 : /* -------------------------------------------------------------------- */
312 : /* Remove dataset from the "open" dataset list. */
313 : /* -------------------------------------------------------------------- */
314 186251 : if (!bIsInternal)
315 : {
316 152886 : CPLMutexHolderD(&hDLMutex);
317 76443 : if (poAllDatasetMap)
318 : {
319 : std::map<GDALDataset *, GIntBig>::iterator oIter =
320 76443 : poAllDatasetMap->find(this);
321 76443 : CPLAssert(oIter != poAllDatasetMap->end());
322 :
323 76443 : UnregisterFromSharedDataset();
324 :
325 76443 : poAllDatasetMap->erase(oIter);
326 :
327 76443 : if (poAllDatasetMap->empty())
328 : {
329 32182 : delete poAllDatasetMap;
330 32182 : poAllDatasetMap = nullptr;
331 32182 : if (phSharedDatasetSet)
332 : {
333 283 : CPLHashSetDestroy(phSharedDatasetSet);
334 : }
335 32182 : phSharedDatasetSet = nullptr;
336 32182 : CPLFree(ppDatasets);
337 32182 : ppDatasets = nullptr;
338 : }
339 : }
340 : }
341 :
342 : /* -------------------------------------------------------------------- */
343 : /* Destroy the raster bands if they exist. */
344 : /* -------------------------------------------------------------------- */
345 1726220 : for (int i = 0; i < nBands && papoBands != nullptr; ++i)
346 : {
347 1539970 : if (papoBands[i] != nullptr)
348 1539970 : delete papoBands[i];
349 1539970 : papoBands[i] = nullptr;
350 : }
351 :
352 186251 : CPLFree(papoBands);
353 :
354 186251 : if (m_poStyleTable)
355 : {
356 23 : delete m_poStyleTable;
357 23 : m_poStyleTable = nullptr;
358 : }
359 :
360 186251 : if (m_poPrivate != nullptr)
361 : {
362 186251 : if (m_poPrivate->hMutex != nullptr)
363 21428 : CPLDestroyMutex(m_poPrivate->hMutex);
364 :
365 : #if defined(__COVERITY__) || defined(DEBUG)
366 : // Not needed since at destruction there is no risk of concurrent use.
367 372502 : std::lock_guard oLock(m_poPrivate->m_oMutexWKT);
368 : #endif
369 186251 : CPLFree(m_poPrivate->m_pszWKTCached);
370 186251 : if (m_poPrivate->m_poSRSCached)
371 : {
372 0 : m_poPrivate->m_poSRSCached->Release();
373 : }
374 186251 : CPLFree(m_poPrivate->m_pszWKTGCPCached);
375 186251 : if (m_poPrivate->m_poSRSGCPCached)
376 : {
377 0 : m_poPrivate->m_poSRSGCPCached->Release();
378 : }
379 : }
380 :
381 186251 : delete m_poPrivate;
382 :
383 186251 : CSLDestroy(papszOpenOptions);
384 186251 : }
385 :
386 : /************************************************************************/
387 : /* Close() */
388 : /************************************************************************/
389 :
390 : /** Do final cleanup before a dataset is destroyed.
391 : *
392 : * This method is typically called by GDALClose() or the destructor of a
393 : * GDALDataset subclass. It might also be called by C++ users before
394 : * destroying a dataset. It should not be called on a shared dataset whose
395 : * reference count is greater than one.
396 : *
397 : * It gives a last chance to the closing process to return an error code if
398 : * something goes wrong, in particular in creation / update scenarios where
399 : * file write or network communication might occur when finalizing the dataset.
400 : *
401 : * Implementations should be robust to this method to be called several times
402 : * (on subsequent calls, it should do nothing and return CE_None).
403 : * Once it has been called, no other method than Close() or the dataset
404 : * destructor should be called. RasterBand or OGRLayer owned by the dataset
405 : * should be assumed as no longer being valid.
406 : *
407 : * If a driver implements this method, it must also call it from its
408 : * dataset destructor.
409 : *
410 : * Starting with GDAL 3.13, this function may report progress if a progress
411 : * callback if provided in the pfnProgress argument and if the dataset returns
412 : * true for GDALDataset::GetCloseReportsProgress()
413 : *
414 : * This is the equivalent of C function GDALDatasetRunCloseWithoutDestroying()
415 : * or GDALDatasetRunCloseWithoutDestroyingEx()
416 : *
417 : * A typical implementation might look as the following
418 : * \code{.cpp}
419 : *
420 : * MyDataset::~MyDataset()
421 : * {
422 : * try
423 : * {
424 : * MyDataset::Close();
425 : * }
426 : * catch (const std::exception &exc)
427 : * {
428 : * // If Close() can throw exception
429 : * CPLError(CE_Failure, CPLE_AppDefined,
430 : * "Exception thrown in MyDataset::Close(): %s",
431 : * exc.what());
432 : * }
433 : * catch (...)
434 : * {
435 : * // If Close() can throw exception
436 : * CPLError(CE_Failure, CPLE_AppDefined,
437 : * "Exception thrown in MyDataset::Close()");
438 : * }
439 : * }
440 : *
441 : * CPLErr MyDataset::Close(GDALProgressFunc pfnProgress, void* pProgressData)
442 : * {
443 : * CPLErr eErr = CE_None;
444 : * if( nOpenFlags != OPEN_FLAGS_CLOSED )
445 : * {
446 : * eErr = MyDataset::FlushCache(true);
447 : *
448 : * // Do something driver specific
449 : * if (m_fpImage)
450 : * {
451 : * if( VSIFCloseL(m_fpImage) != 0 )
452 : * {
453 : * CPLError(CE_Failure, CPLE_FileIO, "VSIFCloseL() failed");
454 : * eErr = CE_Failure;
455 : * }
456 : * }
457 : *
458 : * // Call parent Close() implementation.
459 : * eErr = GDAL::Combine(eErr, MyParentDatasetClass::Close());
460 : * }
461 : * return eErr;
462 : * }
463 : * \endcode
464 : *
465 : * @param pfnProgress (since GDAL 3.13) Progress callback, or nullptr
466 : * @param pProgressData (since GDAL 3.13) User data of progress callback, or nullptr
467 : * @return CE_None if no error
468 : *
469 : * @since GDAL 3.7
470 : */
471 304891 : CPLErr GDALDataset::Close(GDALProgressFunc pfnProgress, void *pProgressData)
472 : {
473 : (void)pfnProgress;
474 : (void)pProgressData;
475 :
476 304891 : if (nOpenFlags != OPEN_FLAGS_CLOSED)
477 : {
478 : // Call UnregisterFromSharedDataset() before altering nOpenFlags
479 186251 : UnregisterFromSharedDataset();
480 :
481 186251 : nOpenFlags = OPEN_FLAGS_CLOSED;
482 : }
483 :
484 304891 : if (IsMarkedSuppressOnClose())
485 : {
486 3454 : if (poDriver == nullptr ||
487 : // Someone issuing Create("foo.tif") on a
488 : // memory driver doesn't expect files with those names to be deleted
489 : // on a file system...
490 : // This is somewhat messy. Ideally there should be a way for the
491 : // driver to overload the default behavior
492 1683 : (!EQUAL(poDriver->GetDescription(), "MEM") &&
493 1605 : !EQUAL(poDriver->GetDescription(), "Memory")))
494 : {
495 1693 : if (VSIUnlink(GetDescription()) == 0)
496 683 : UnMarkSuppressOnClose();
497 : }
498 : }
499 :
500 304891 : return CE_None;
501 : }
502 :
503 : /************************************************************************/
504 : /* GDALDatasetRunCloseWithoutDestroying() */
505 : /************************************************************************/
506 :
507 : /** Run the Close() method, without running destruction of the object.
508 : *
509 : * This ensures that content that should be written to file is written and
510 : * that all file descriptors are closed.
511 : *
512 : * Note that this is different from GDALClose() which also destroys
513 : * the underlying C++ object. GDALClose() or GDALReleaseDataset() are actually
514 : * the only functions that can be safely called on the dataset handle after
515 : * this function has been called.
516 : *
517 : * Most users want to use GDALClose() or GDALReleaseDataset() rather than
518 : * this function.
519 : *
520 : * This function is equivalent to the C++ method GDALDataset:Close()
521 : *
522 : * @param hDS dataset handle.
523 : * @return CE_None if no error
524 : *
525 : * @since GDAL 3.12
526 : * @see GDALClose(), GDALDatasetRunCloseWithoutDestroyingEx()
527 : */
528 0 : CPLErr GDALDatasetRunCloseWithoutDestroying(GDALDatasetH hDS)
529 : {
530 0 : VALIDATE_POINTER1(hDS, __func__, CE_Failure);
531 0 : return GDALDataset::FromHandle(hDS)->Close();
532 : }
533 :
534 : /************************************************************************/
535 : /* GDALDatasetRunCloseWithoutDestroyingEx() */
536 : /************************************************************************/
537 :
538 : /** Run the Close() method, without running destruction of the object.
539 : *
540 : * This ensures that content that should be written to file is written and
541 : * that all file descriptors are closed.
542 : *
543 : * Note that this is different from GDALClose() which also destroys
544 : * the underlying C++ object. GDALClose() or GDALReleaseDataset() are actually
545 : * the only functions that can be safely called on the dataset handle after
546 : * this function has been called.
547 : *
548 : * Most users want to use GDALClose() or GDALReleaseDataset() rather than
549 : * this function.
550 : *
551 : * This function may report progress if a progress
552 : * callback if provided in the pfnProgress argument and if the dataset returns
553 : * true for GDALDataset::GetCloseReportsProgress()
554 : *
555 : * This function is equivalent to the C++ method GDALDataset:Close()
556 : *
557 : * @param hDS dataset handle.
558 : * @param pfnProgress Progress callback, or nullptr
559 : * @param pProgressData User data of progress callback, or nullptr
560 : *
561 : * @return CE_None if no error
562 : *
563 : * @since GDAL 3.13
564 : * @see GDALClose()
565 : */
566 12 : CPLErr GDALDatasetRunCloseWithoutDestroyingEx(GDALDatasetH hDS,
567 : GDALProgressFunc pfnProgress,
568 : void *pProgressData)
569 : {
570 12 : VALIDATE_POINTER1(hDS, __func__, CE_Failure);
571 12 : return GDALDataset::FromHandle(hDS)->Close(pfnProgress, pProgressData);
572 : }
573 :
574 : /************************************************************************/
575 : /* GetCloseReportsProgress() */
576 : /************************************************************************/
577 :
578 : /** Returns whether the Close() operation will report progress / is a potential
579 : * lengthy operation.
580 : *
581 : * At time of writing, only the COG driver will return true, if the dataset
582 : * has been created through the GDALDriver::Create() interface.
583 : *
584 : * This method is equivalent to the C function GDALDatasetGetCloseReportsProgress()
585 : *
586 : * @return true if the Close() operation will report progress
587 : * @since GDAL 3.13
588 : * @see Close()
589 : */
590 220 : bool GDALDataset::GetCloseReportsProgress() const
591 : {
592 220 : return false;
593 : }
594 :
595 : /************************************************************************/
596 : /* GDALDatasetGetCloseReportsProgress() */
597 : /************************************************************************/
598 :
599 : /** Returns whether the Close() operation will report progress / is a potential
600 : * lengthy operation.
601 : *
602 : * This function is equivalent to the C++ method GDALDataset::GetCloseReportsProgress()
603 : *
604 : * @param hDS dataset handle.
605 : * @return CE_None if no error
606 : *
607 : * @return true if the Close() operation will report progress
608 : * @since GDAL 3.13
609 : * @see GDALClose()
610 : */
611 2 : bool GDALDatasetGetCloseReportsProgress(GDALDatasetH hDS)
612 : {
613 2 : VALIDATE_POINTER1(hDS, __func__, false);
614 2 : return GDALDataset::FromHandle(hDS)->GetCloseReportsProgress();
615 : }
616 :
617 : /************************************************************************/
618 : /* CanReopenWithCurrentDescription() */
619 : /************************************************************************/
620 :
621 : /** Returns whether, once this dataset is closed, it can be re-opened with
622 : * Open() using the current value of GetDescription()
623 : *
624 : * The default implementation returns true. Some drivers, like MVT in Create()
625 : * mode, can return false. Some drivers return true, but the re-opened dataset
626 : * may be opened by another driver (e.g. the COG driver will return true, but
627 : * the driver used for re-opening is GTiff).
628 : *
629 : * @return true if the dataset can be re-opened using the value as
630 : * GetDescription() as connection string for Open()
631 : * @since GDAL 3.13
632 : */
633 2 : bool GDALDataset::CanReopenWithCurrentDescription() const
634 : {
635 2 : return true;
636 : }
637 :
638 : /************************************************************************/
639 : /* UnregisterFromSharedDataset() */
640 : /************************************************************************/
641 :
642 262694 : void GDALDataset::UnregisterFromSharedDataset()
643 : {
644 262694 : if (!(!bIsInternal && bShared && poAllDatasetMap && phSharedDatasetSet))
645 262283 : return;
646 :
647 822 : CPLMutexHolderD(&hDLMutex);
648 :
649 : std::map<GDALDataset *, GIntBig>::iterator oIter =
650 411 : poAllDatasetMap->find(this);
651 411 : CPLAssert(oIter != poAllDatasetMap->end());
652 411 : const GIntBig nPIDCreatorForShared = oIter->second;
653 411 : bShared = false;
654 : SharedDatasetCtxt sStruct;
655 411 : sStruct.nPID = nPIDCreatorForShared;
656 411 : sStruct.nOpenFlags = nOpenFlags & ~GDAL_OF_SHARED;
657 411 : sStruct.pszDescription = const_cast<char *>(GetDescription());
658 : std::string osConcatenatedOpenOptions =
659 822 : GDALSharedDatasetConcatenateOpenOptions(papszOpenOptions);
660 411 : sStruct.pszConcatenatedOpenOptions = &osConcatenatedOpenOptions[0];
661 411 : sStruct.poDS = nullptr;
662 : SharedDatasetCtxt *psStruct = static_cast<SharedDatasetCtxt *>(
663 411 : CPLHashSetLookup(phSharedDatasetSet, &sStruct));
664 411 : if (psStruct && psStruct->poDS == this)
665 : {
666 410 : CPLHashSetRemove(phSharedDatasetSet, psStruct);
667 : }
668 : else
669 : {
670 1 : CPLDebug("GDAL",
671 : "Should not happen. Cannot find %s, "
672 : "this=%p in phSharedDatasetSet",
673 1 : GetDescription(), this);
674 : }
675 : }
676 :
677 : /************************************************************************/
678 : /* AddToDatasetOpenList() */
679 : /************************************************************************/
680 :
681 77781 : void GDALDataset::AddToDatasetOpenList()
682 : {
683 : /* -------------------------------------------------------------------- */
684 : /* Add this dataset to the open dataset list. */
685 : /* -------------------------------------------------------------------- */
686 77781 : bIsInternal = false;
687 :
688 77781 : CPLMutexHolderD(&hDLMutex);
689 :
690 77781 : if (poAllDatasetMap == nullptr)
691 32192 : poAllDatasetMap = new std::map<GDALDataset *, GIntBig>;
692 77781 : (*poAllDatasetMap)[this] = -1;
693 77781 : }
694 :
695 : /************************************************************************/
696 : /* FlushCache() */
697 : /************************************************************************/
698 :
699 : /**
700 : * \brief Flush all write cached data to disk.
701 : *
702 : * Any raster (or other GDAL) data written via GDAL calls, but buffered
703 : * internally will be written to disk.
704 : *
705 : * The default implementation of this method just calls the FlushCache() method
706 : * on each of the raster bands and the SyncToDisk() method
707 : * on each of the layers. Conceptually, calling FlushCache() on a dataset
708 : * should include any work that might be accomplished by calling SyncToDisk()
709 : * on layers in that dataset.
710 : *
711 : * Using this method does not prevent use from calling GDALClose()
712 : * to properly close a dataset and ensure that important data not addressed
713 : * by FlushCache() is written in the file.
714 : *
715 : * This method is the same as the C function GDALFlushCache().
716 : *
717 : * @param bAtClosing Whether this is called from a GDALDataset destructor
718 : * @return CE_None in case of success (note: return value added in GDAL 3.7)
719 : */
720 :
721 124488 : CPLErr GDALDataset::FlushCache(bool bAtClosing)
722 :
723 : {
724 124488 : CPLErr eErr = CE_None;
725 : // This sometimes happens if a dataset is destroyed before completely
726 : // built.
727 :
728 124488 : if (papoBands)
729 : {
730 1943110 : for (int i = 0; i < nBands; ++i)
731 : {
732 1833320 : if (papoBands[i])
733 : {
734 1833320 : if (papoBands[i]->FlushCache(bAtClosing) != CE_None)
735 7 : eErr = CE_Failure;
736 : }
737 : }
738 : }
739 :
740 124488 : const int nLayers = GetLayerCount();
741 : // cppcheck-suppress knownConditionTrueFalse
742 124488 : if (nLayers > 0)
743 : {
744 16848 : CPLMutexHolderD(m_poPrivate ? &(m_poPrivate->hMutex) : nullptr);
745 26262 : for (int i = 0; i < nLayers; ++i)
746 : {
747 17838 : OGRLayer *poLayer = GetLayer(i);
748 :
749 17838 : if (poLayer)
750 : {
751 17838 : if (poLayer->SyncToDisk() != OGRERR_NONE)
752 1 : eErr = CE_Failure;
753 : }
754 : }
755 : }
756 :
757 124488 : return eErr;
758 : }
759 :
760 : /************************************************************************/
761 : /* GDALFlushCache() */
762 : /************************************************************************/
763 :
764 : /**
765 : * \brief Flush all write cached data to disk.
766 : *
767 : * @see GDALDataset::FlushCache().
768 : * @return CE_None in case of success (note: return value added in GDAL 3.7)
769 : */
770 :
771 5150 : CPLErr CPL_STDCALL GDALFlushCache(GDALDatasetH hDS)
772 :
773 : {
774 5150 : VALIDATE_POINTER1(hDS, "GDALFlushCache", CE_Failure);
775 :
776 5150 : return GDALDataset::FromHandle(hDS)->FlushCache(false);
777 : }
778 :
779 : /************************************************************************/
780 : /* DropCache() */
781 : /************************************************************************/
782 :
783 : /**
784 : * \brief Drop all write cached data
785 : *
786 : * This method is the same as the C function GDALDropCache().
787 : *
788 : * @return CE_None in case of success
789 : * @since 3.9
790 : */
791 :
792 1 : CPLErr GDALDataset::DropCache()
793 :
794 : {
795 1 : CPLErr eErr = CE_None;
796 :
797 1 : if (papoBands)
798 : {
799 2 : for (int i = 0; i < nBands; ++i)
800 : {
801 1 : if (papoBands[i])
802 : {
803 1 : if (papoBands[i]->DropCache() != CE_None)
804 0 : eErr = CE_Failure;
805 : }
806 : }
807 : }
808 :
809 1 : return eErr;
810 : }
811 :
812 : /************************************************************************/
813 : /* GDALDropCache() */
814 : /************************************************************************/
815 :
816 : /**
817 : * \brief Drop all write cached data
818 : *
819 : * @see GDALDataset::DropCache().
820 : * @return CE_None in case of success
821 : * @since 3.9
822 : */
823 :
824 0 : CPLErr CPL_STDCALL GDALDropCache(GDALDatasetH hDS)
825 :
826 : {
827 0 : VALIDATE_POINTER1(hDS, "GDALDropCache", CE_Failure);
828 :
829 0 : return GDALDataset::FromHandle(hDS)->DropCache();
830 : }
831 :
832 : /************************************************************************/
833 : /* GetEstimatedRAMUsage() */
834 : /************************************************************************/
835 :
836 : /**
837 : * \brief Return the intrinsic RAM usage of this dataset.
838 : *
839 : * The returned value should take into account caches in the underlying driver
840 : * and decoding library, but not the usage related to the GDAL block cache.
841 : *
842 : * At time of writing, this method is only implemented in the JP2OpenJPEG
843 : * driver. For single-tiled JPEG2000 images, the decoding of the image,
844 : * even partially, involves allocating at least
845 : * width * height * number_of_bands * sizeof(uint32_t) bytes inside the libopenjp2
846 : * library.
847 : *
848 : * This method is used by the GDALDatasetPool class, itself used by the GDAL VRT
849 : * driver, to determine how long a dataset in the pool must be kept open, given
850 : * the RAM usage of the dataset with respect to the usable total RAM.
851 : *
852 : * @since GDAL 3.7
853 : * @return RAM usage in bytes, or -1 if unknown (the default implementation
854 : * returns -1)
855 : */
856 :
857 3356 : GIntBig GDALDataset::GetEstimatedRAMUsage()
858 : {
859 3356 : return -1;
860 : }
861 :
862 : /************************************************************************/
863 : /* BlockBasedFlushCache() */
864 : /* */
865 : /* This helper method can be called by the */
866 : /* GDALDataset::FlushCache() for particular drivers to ensure */
867 : /* that buffers will be flushed in a manner suitable for pixel */
868 : /* interleaved (by block) IO. That is, if all the bands have */
869 : /* the same size blocks then a given block will be flushed for */
870 : /* all bands before proceeding to the next block. */
871 : /************************************************************************/
872 :
873 : //! @cond Doxygen_Suppress
874 350 : CPLErr GDALDataset::BlockBasedFlushCache(bool bAtClosing)
875 :
876 : {
877 350 : GDALRasterBand *poBand1 = GetRasterBand(1);
878 350 : if (poBand1 == nullptr || (IsMarkedSuppressOnClose() && bAtClosing))
879 : {
880 7 : return GDALDataset::FlushCache(bAtClosing);
881 : }
882 :
883 343 : int nBlockXSize = 0;
884 343 : int nBlockYSize = 0;
885 343 : poBand1->GetBlockSize(&nBlockXSize, &nBlockYSize);
886 :
887 : /* -------------------------------------------------------------------- */
888 : /* Verify that all bands match. */
889 : /* -------------------------------------------------------------------- */
890 1108 : for (int iBand = 1; iBand < nBands; ++iBand)
891 : {
892 765 : GDALRasterBand *poBand = GetRasterBand(iBand + 1);
893 :
894 : int nThisBlockXSize, nThisBlockYSize;
895 765 : poBand->GetBlockSize(&nThisBlockXSize, &nThisBlockYSize);
896 765 : if (nThisBlockXSize != nBlockXSize && nThisBlockYSize != nBlockYSize)
897 : {
898 0 : return GDALDataset::FlushCache(bAtClosing);
899 : }
900 : }
901 :
902 : /* -------------------------------------------------------------------- */
903 : /* Now flush writable data. */
904 : /* -------------------------------------------------------------------- */
905 794 : for (int iY = 0; iY < poBand1->nBlocksPerColumn; ++iY)
906 : {
907 991 : for (int iX = 0; iX < poBand1->nBlocksPerRow; ++iX)
908 : {
909 1690 : for (int iBand = 0; iBand < nBands; ++iBand)
910 : {
911 1150 : const CPLErr eErr = papoBands[iBand]->FlushBlock(iX, iY);
912 :
913 1150 : if (eErr != CE_None)
914 0 : return CE_Failure;
915 : }
916 : }
917 : }
918 343 : return CE_None;
919 : }
920 :
921 : /************************************************************************/
922 : /* RasterInitialize() */
923 : /* */
924 : /* Initialize raster size */
925 : /************************************************************************/
926 :
927 0 : void GDALDataset::RasterInitialize(int nXSize, int nYSize)
928 :
929 : {
930 0 : CPLAssert(nXSize > 0 && nYSize > 0);
931 :
932 0 : nRasterXSize = nXSize;
933 0 : nRasterYSize = nYSize;
934 0 : }
935 :
936 : //! @endcond
937 :
938 : /************************************************************************/
939 : /* AddBand() */
940 : /************************************************************************/
941 :
942 : /**
943 : * \fn GDALDataset::AddBand(GDALDataType, char**)
944 : * \brief Add a band to a dataset.
945 : *
946 : * This method will add a new band to the dataset if the underlying format
947 : * supports this action. Most formats do not.
948 : *
949 : * Note that the new GDALRasterBand is not returned. It may be fetched
950 : * after successful completion of the method by calling
951 : * GDALDataset::GetRasterBand(GDALDataset::GetRasterCount()) as the newest
952 : * band will always be the last band.
953 : *
954 : * @param eType the data type of the pixels in the new band.
955 : *
956 : * @param papszOptions a list of NAME=VALUE option strings. The supported
957 : * options are format specific. NULL may be passed by default.
958 : *
959 : * @return CE_None on success or CE_Failure on failure.
960 : */
961 :
962 0 : CPLErr GDALDataset::AddBand(CPL_UNUSED GDALDataType eType,
963 : CPL_UNUSED CSLConstList papszOptions)
964 :
965 : {
966 0 : ReportError(CE_Failure, CPLE_NotSupported,
967 : "Dataset does not support the AddBand() method.");
968 :
969 0 : return CE_Failure;
970 : }
971 :
972 : /************************************************************************/
973 : /* GDALAddBand() */
974 : /************************************************************************/
975 :
976 : /**
977 : * \brief Add a band to a dataset.
978 : *
979 : * @see GDALDataset::AddBand().
980 : */
981 :
982 32 : CPLErr CPL_STDCALL GDALAddBand(GDALDatasetH hDataset, GDALDataType eType,
983 : CSLConstList papszOptions)
984 :
985 : {
986 32 : VALIDATE_POINTER1(hDataset, "GDALAddBand", CE_Failure);
987 :
988 64 : return GDALDataset::FromHandle(hDataset)->AddBand(
989 32 : eType, const_cast<char **>(papszOptions));
990 : }
991 :
992 : /************************************************************************/
993 : /* SetBand() */
994 : /************************************************************************/
995 :
996 : //! @cond Doxygen_Suppress
997 : /** Set a band in the band array, updating the band count, and array size
998 : * appropriately.
999 : *
1000 : * @param nNewBand new band number (indexing starts at 1)
1001 : * @param poBand band object.
1002 : */
1003 :
1004 1685320 : void GDALDataset::SetBand(int nNewBand, GDALRasterBand *poBand)
1005 :
1006 : {
1007 : /* -------------------------------------------------------------------- */
1008 : /* Do we need to grow the bands list? */
1009 : /* -------------------------------------------------------------------- */
1010 1685320 : if (nBands < nNewBand || papoBands == nullptr)
1011 : {
1012 950087 : GDALRasterBand **papoNewBands = nullptr;
1013 :
1014 950087 : if (papoBands == nullptr)
1015 101741 : papoNewBands = static_cast<GDALRasterBand **>(VSICalloc(
1016 101741 : sizeof(GDALRasterBand *), std::max(nNewBand, nBands)));
1017 : else
1018 : papoNewBands = static_cast<GDALRasterBand **>(
1019 848346 : VSIRealloc(papoBands, sizeof(GDALRasterBand *) *
1020 848346 : std::max(nNewBand, nBands)));
1021 950087 : if (papoNewBands == nullptr)
1022 : {
1023 0 : ReportError(CE_Failure, CPLE_OutOfMemory,
1024 : "Cannot allocate band array");
1025 0 : return;
1026 : }
1027 :
1028 950087 : papoBands = papoNewBands;
1029 :
1030 1846840 : for (int i = nBands; i < nNewBand; ++i)
1031 896757 : papoBands[i] = nullptr;
1032 :
1033 950087 : nBands = std::max(nBands, nNewBand);
1034 :
1035 950087 : if (m_poPrivate)
1036 : {
1037 950087 : for (int i = static_cast<int>(m_poPrivate->m_anBandMap.size());
1038 2635410 : i < nBands; ++i)
1039 : {
1040 1685320 : m_poPrivate->m_anBandMap.push_back(i + 1);
1041 : }
1042 : }
1043 : }
1044 :
1045 : /* -------------------------------------------------------------------- */
1046 : /* Set the band. Resetting the band is currently not permitted. */
1047 : /* -------------------------------------------------------------------- */
1048 1685320 : if (papoBands[nNewBand - 1] != nullptr)
1049 : {
1050 0 : ReportError(CE_Failure, CPLE_NotSupported,
1051 : "Cannot set band %d as it is already set", nNewBand);
1052 0 : return;
1053 : }
1054 :
1055 1685320 : papoBands[nNewBand - 1] = poBand;
1056 :
1057 : /* -------------------------------------------------------------------- */
1058 : /* Set back reference information on the raster band. Note */
1059 : /* that the GDALDataset is a friend of the GDALRasterBand */
1060 : /* specifically to allow this. */
1061 : /* -------------------------------------------------------------------- */
1062 1685320 : poBand->nBand = nNewBand;
1063 1685320 : poBand->poDS = this;
1064 1685320 : poBand->nRasterXSize = nRasterXSize;
1065 1685320 : poBand->nRasterYSize = nRasterYSize;
1066 1685320 : poBand->eAccess = eAccess; // Default access to be same as dataset.
1067 : }
1068 :
1069 : //! @endcond
1070 :
1071 : /************************************************************************/
1072 : /* SetBand() */
1073 : /************************************************************************/
1074 :
1075 : //! @cond Doxygen_Suppress
1076 : /** Set a band in the band array, updating the band count, and array size
1077 : * appropriately.
1078 : *
1079 : * @param nNewBand new band number (indexing starts at 1)
1080 : * @param poBand band object.
1081 : */
1082 :
1083 1111320 : void GDALDataset::SetBand(int nNewBand, std::unique_ptr<GDALRasterBand> poBand)
1084 : {
1085 1111320 : SetBand(nNewBand, poBand.release());
1086 1111320 : }
1087 :
1088 : //! @endcond
1089 :
1090 : /************************************************************************/
1091 : /* GetRasterXSize() */
1092 : /************************************************************************/
1093 :
1094 : /**
1095 :
1096 : \brief Fetch raster width in pixels.
1097 :
1098 : Equivalent of the C function GDALGetRasterXSize().
1099 :
1100 : @return the width in pixels of raster bands in this GDALDataset.
1101 :
1102 : */
1103 :
1104 718897 : int GDALDataset::GetRasterXSize() const
1105 : {
1106 718897 : return nRasterXSize;
1107 : }
1108 :
1109 : /************************************************************************/
1110 : /* GDALGetRasterXSize() */
1111 : /************************************************************************/
1112 :
1113 : /**
1114 : * \brief Fetch raster width in pixels.
1115 : *
1116 : * @see GDALDataset::GetRasterXSize().
1117 : */
1118 :
1119 38200 : int CPL_STDCALL GDALGetRasterXSize(GDALDatasetH hDataset)
1120 :
1121 : {
1122 38200 : VALIDATE_POINTER1(hDataset, "GDALGetRasterXSize", 0);
1123 :
1124 38200 : return GDALDataset::FromHandle(hDataset)->GetRasterXSize();
1125 : }
1126 :
1127 : /************************************************************************/
1128 : /* GetRasterYSize() */
1129 : /************************************************************************/
1130 :
1131 : /**
1132 :
1133 : \brief Fetch raster height in pixels.
1134 :
1135 : Equivalent of the C function GDALGetRasterYSize().
1136 :
1137 : @return the height in pixels of raster bands in this GDALDataset.
1138 :
1139 : */
1140 :
1141 609283 : int GDALDataset::GetRasterYSize() const
1142 : {
1143 609283 : return nRasterYSize;
1144 : }
1145 :
1146 : /************************************************************************/
1147 : /* GDALGetRasterYSize() */
1148 : /************************************************************************/
1149 :
1150 : /**
1151 : * \brief Fetch raster height in pixels.
1152 : *
1153 : * @see GDALDataset::GetRasterYSize().
1154 : */
1155 :
1156 37811 : int CPL_STDCALL GDALGetRasterYSize(GDALDatasetH hDataset)
1157 :
1158 : {
1159 37811 : VALIDATE_POINTER1(hDataset, "GDALGetRasterYSize", 0);
1160 :
1161 37811 : return GDALDataset::FromHandle(hDataset)->GetRasterYSize();
1162 : }
1163 :
1164 : /************************************************************************/
1165 : /* GetRasterBand() */
1166 : /************************************************************************/
1167 :
1168 : /**
1169 :
1170 : \brief Fetch a band object for a dataset.
1171 :
1172 : See GetBands() for a C++ iterator version of this method.
1173 :
1174 : Equivalent of the C function GDALGetRasterBand().
1175 :
1176 : @param nBandId the index number of the band to fetch, from 1 to
1177 : GetRasterCount().
1178 :
1179 : @return the nBandId th band object
1180 :
1181 : */
1182 :
1183 12603500 : GDALRasterBand *GDALDataset::GetRasterBand(int nBandId)
1184 :
1185 : {
1186 12603500 : if (papoBands)
1187 : {
1188 12603500 : if (nBandId < 1 || nBandId > nBands)
1189 : {
1190 12 : ReportError(CE_Failure, CPLE_IllegalArg,
1191 : "GDALDataset::GetRasterBand(%d) - Illegal band #\n",
1192 : nBandId);
1193 12 : return nullptr;
1194 : }
1195 :
1196 12603500 : return papoBands[nBandId - 1];
1197 : }
1198 13 : return nullptr;
1199 : }
1200 :
1201 : /************************************************************************/
1202 : /* GetRasterBand() */
1203 : /************************************************************************/
1204 :
1205 : /**
1206 :
1207 : \brief Fetch a band object for a dataset.
1208 :
1209 : See GetBands() for a C++ iterator version of this method.
1210 :
1211 : Equivalent of the C function GDALGetRasterBand().
1212 :
1213 : @param nBandId the index number of the band to fetch, from 1 to
1214 : GetRasterCount().
1215 :
1216 : @return the nBandId th band object
1217 :
1218 : */
1219 :
1220 594 : const GDALRasterBand *GDALDataset::GetRasterBand(int nBandId) const
1221 :
1222 : {
1223 594 : if (papoBands)
1224 : {
1225 594 : if (nBandId < 1 || nBandId > nBands)
1226 : {
1227 0 : ReportError(CE_Failure, CPLE_IllegalArg,
1228 : "GDALDataset::GetRasterBand(%d) - Illegal band #\n",
1229 : nBandId);
1230 0 : return nullptr;
1231 : }
1232 :
1233 594 : return papoBands[nBandId - 1];
1234 : }
1235 0 : return nullptr;
1236 : }
1237 :
1238 : /************************************************************************/
1239 : /* GDALGetRasterBand() */
1240 : /************************************************************************/
1241 :
1242 : /**
1243 : * \brief Fetch a band object for a dataset.
1244 : * @see GDALDataset::GetRasterBand().
1245 : */
1246 :
1247 410109 : GDALRasterBandH CPL_STDCALL GDALGetRasterBand(GDALDatasetH hDS, int nBandId)
1248 :
1249 : {
1250 410109 : VALIDATE_POINTER1(hDS, "GDALGetRasterBand", nullptr);
1251 :
1252 410109 : return GDALRasterBand::ToHandle(
1253 410109 : GDALDataset::FromHandle(hDS)->GetRasterBand(nBandId));
1254 : }
1255 :
1256 : /************************************************************************/
1257 : /* GetRasterCount() */
1258 : /************************************************************************/
1259 :
1260 : /**
1261 : * \brief Fetch the number of raster bands on this dataset.
1262 : *
1263 : * Same as the C function GDALGetRasterCount().
1264 : *
1265 : * @return the number of raster bands.
1266 : */
1267 :
1268 6452180 : int GDALDataset::GetRasterCount() const
1269 : {
1270 6452180 : return papoBands ? nBands : 0;
1271 : }
1272 :
1273 : /************************************************************************/
1274 : /* GDALGetRasterCount() */
1275 : /************************************************************************/
1276 :
1277 : /**
1278 : * \brief Fetch the number of raster bands on this dataset.
1279 : *
1280 : * @see GDALDataset::GetRasterCount().
1281 : */
1282 :
1283 385847 : int CPL_STDCALL GDALGetRasterCount(GDALDatasetH hDS)
1284 :
1285 : {
1286 385847 : VALIDATE_POINTER1(hDS, "GDALGetRasterCount", 0);
1287 :
1288 385847 : return GDALDataset::FromHandle(hDS)->GetRasterCount();
1289 : }
1290 :
1291 : /************************************************************************/
1292 : /* GetProjectionRef() */
1293 : /************************************************************************/
1294 :
1295 : /**
1296 : * \brief Fetch the projection definition string for this dataset.
1297 : *
1298 : * Same as the C function GDALGetProjectionRef().
1299 : *
1300 : * The returned string defines the projection coordinate system of the
1301 : * image in OpenGIS WKT format. It should be suitable for use with the
1302 : * OGRSpatialReference class.
1303 : *
1304 : * When a projection definition is not available an empty (but not NULL)
1305 : * string is returned.
1306 : *
1307 : * \note Starting with GDAL 3.0, this is a compatibility layer around
1308 : * GetSpatialRef()
1309 : *
1310 : * @return a pointer to an internal projection reference string. It should
1311 : * not be altered, freed or expected to last for long.
1312 : *
1313 : * @see https://gdal.org/tutorials/osr_api_tut.html
1314 : */
1315 :
1316 5399 : const char *GDALDataset::GetProjectionRef() const
1317 : {
1318 5399 : const auto poSRS = GetSpatialRef();
1319 5399 : if (!poSRS || !m_poPrivate)
1320 : {
1321 2428 : return "";
1322 : }
1323 2971 : char *pszWKT = nullptr;
1324 2971 : poSRS->exportToWkt(&pszWKT);
1325 2971 : if (!pszWKT)
1326 : {
1327 0 : return "";
1328 : }
1329 :
1330 : // If called on a thread-safe dataset, we might be called by several
1331 : // threads, so make sure our accesses to m_pszWKTCached are protected
1332 : // by a mutex.
1333 5942 : std::lock_guard oLock(m_poPrivate->m_oMutexWKT);
1334 2971 : if (m_poPrivate->m_pszWKTCached &&
1335 793 : strcmp(pszWKT, m_poPrivate->m_pszWKTCached) == 0)
1336 : {
1337 792 : CPLFree(pszWKT);
1338 792 : return m_poPrivate->m_pszWKTCached;
1339 : }
1340 2179 : CPLFree(m_poPrivate->m_pszWKTCached);
1341 2179 : m_poPrivate->m_pszWKTCached = pszWKT;
1342 2179 : return m_poPrivate->m_pszWKTCached;
1343 : }
1344 :
1345 : /************************************************************************/
1346 : /* GetSpatialRef() */
1347 : /************************************************************************/
1348 :
1349 : static thread_local int tlsEnableLayersInGetSpatialRefCounter = 0;
1350 :
1351 : /**
1352 : * \brief Fetch the spatial reference for this dataset.
1353 : *
1354 : * Same as the C function GDALGetSpatialRef().
1355 : *
1356 : * When a projection definition is not available, null is returned. If used on
1357 : * a dataset where there are GCPs and not a geotransform, this method returns
1358 : * null. Use GetGCPSpatialRef() instead.
1359 : *
1360 : * Since GDAL 3.12, the default implementation of this method will iterate over
1361 : * vector layers and return their SRS if all geometry columns of all layers use
1362 : * the same SRS, or nullptr otherwise.
1363 : *
1364 : * @since GDAL 3.0
1365 : *
1366 : * @return a pointer to an internal object. It should not be altered or freed.
1367 : * Its lifetime will be the one of the dataset object.
1368 : *
1369 : * @see https://gdal.org/tutorials/osr_api_tut.html
1370 : */
1371 :
1372 17691 : const OGRSpatialReference *GDALDataset::GetSpatialRef() const
1373 : {
1374 17691 : if (tlsEnableLayersInGetSpatialRefCounter == 0)
1375 17641 : return GetSpatialRefVectorOnly();
1376 50 : return nullptr;
1377 : }
1378 :
1379 : /************************************************************************/
1380 : /* GetSpatialRefVectorOnly() */
1381 : /************************************************************************/
1382 :
1383 : /**
1384 : * \brief Fetch the spatial reference for this dataset (only for vector layers)
1385 : *
1386 : * The default implementation of this method will iterate over
1387 : * vector layers and return their SRS if all geometry columns of all layers use
1388 : * the same SRS, or nullptr otherwise.
1389 : *
1390 : * @since GDAL 3.12
1391 : *
1392 : * @return a pointer to an internal object. It should not be altered or freed.
1393 : * Its lifetime will be the one of the dataset object.
1394 : */
1395 :
1396 17641 : const OGRSpatialReference *GDALDataset::GetSpatialRefVectorOnly() const
1397 : {
1398 17641 : bool bInit = false;
1399 17641 : const OGRSpatialReference *poGlobalSRS = nullptr;
1400 33804 : for (const OGRLayer *poLayer : GetLayers())
1401 : {
1402 16164 : for (const auto *poGeomFieldDefn :
1403 48494 : poLayer->GetLayerDefn()->GetGeomFields())
1404 : {
1405 16167 : const auto *poSRS = poGeomFieldDefn->GetSpatialRef();
1406 16167 : if (!bInit)
1407 : {
1408 207 : bInit = true;
1409 207 : poGlobalSRS = poSRS;
1410 : }
1411 31918 : else if ((poSRS && !poGlobalSRS) || (!poSRS && poGlobalSRS) ||
1412 15958 : (poSRS && poGlobalSRS && !poSRS->IsSame(poGlobalSRS)))
1413 : {
1414 3 : CPLDebug("GDAL",
1415 : "Not all geometry fields or layers have the same CRS");
1416 3 : return nullptr;
1417 : }
1418 : }
1419 : }
1420 17638 : return poGlobalSRS;
1421 : }
1422 :
1423 : /************************************************************************/
1424 : /* GetSpatialRefRasterOnly() */
1425 : /************************************************************************/
1426 :
1427 : /**
1428 : * \brief Fetch the spatial reference for this dataset (ignoring vector layers)
1429 : *
1430 : * @since GDAL 3.12
1431 : *
1432 : * @return a pointer to an internal object. It should not be altered or freed.
1433 : * Its lifetime will be the one of the dataset object.
1434 : */
1435 :
1436 909 : const OGRSpatialReference *GDALDataset::GetSpatialRefRasterOnly() const
1437 : {
1438 909 : ++tlsEnableLayersInGetSpatialRefCounter;
1439 909 : const auto poRet = GetSpatialRef();
1440 909 : --tlsEnableLayersInGetSpatialRefCounter;
1441 909 : return poRet;
1442 : }
1443 :
1444 : /************************************************************************/
1445 : /* GDALGetSpatialRef() */
1446 : /************************************************************************/
1447 :
1448 : /**
1449 : * \brief Fetch the spatial reference for this dataset.
1450 : *
1451 : * Same as the C++ method GDALDataset::GetSpatialRef()
1452 : *
1453 : * @since GDAL 3.0
1454 : *
1455 : * @see GDALDataset::GetSpatialRef()
1456 : */
1457 :
1458 7516 : OGRSpatialReferenceH GDALGetSpatialRef(GDALDatasetH hDS)
1459 :
1460 : {
1461 7516 : VALIDATE_POINTER1(hDS, "GDALGetSpatialRef", nullptr);
1462 :
1463 7516 : return OGRSpatialReference::ToHandle(const_cast<OGRSpatialReference *>(
1464 7516 : GDALDataset::FromHandle(hDS)->GetSpatialRef()));
1465 : }
1466 :
1467 : /************************************************************************/
1468 : /* GDALGetProjectionRef() */
1469 : /************************************************************************/
1470 :
1471 : /**
1472 : * \brief Fetch the projection definition string for this dataset.
1473 : *
1474 : * @see GDALDataset::GetProjectionRef()
1475 : */
1476 :
1477 1485 : const char *CPL_STDCALL GDALGetProjectionRef(GDALDatasetH hDS)
1478 :
1479 : {
1480 1485 : VALIDATE_POINTER1(hDS, "GDALGetProjectionRef", nullptr);
1481 :
1482 1485 : return GDALDataset::FromHandle(hDS)->GetProjectionRef();
1483 : }
1484 :
1485 : /************************************************************************/
1486 : /* SetProjection() */
1487 : /************************************************************************/
1488 :
1489 : /**
1490 : * \brief Set the projection reference string for this dataset.
1491 : *
1492 : * The string should be in OGC WKT or PROJ.4 format. An error may occur
1493 : * because of incorrectly specified projection strings, because the dataset
1494 : * is not writable, or because the dataset does not support the indicated
1495 : * projection. Many formats do not support writing projections.
1496 : *
1497 : * This method is the same as the C GDALSetProjection() function.
1498 : *
1499 : * \note Startig with GDAL 3.0, this is a compatibility layer around
1500 : * SetSpatialRef()
1501 :
1502 : * @param pszProjection projection reference string.
1503 : *
1504 : * @return CE_Failure if an error occurs, otherwise CE_None.
1505 : */
1506 :
1507 2488 : CPLErr GDALDataset::SetProjection(const char *pszProjection)
1508 : {
1509 2488 : if (pszProjection && pszProjection[0] != '\0')
1510 : {
1511 4598 : OGRSpatialReference oSRS;
1512 2299 : oSRS.SetAxisMappingStrategy(OAMS_TRADITIONAL_GIS_ORDER);
1513 2299 : if (oSRS.SetFromUserInput(pszProjection) != OGRERR_NONE)
1514 : {
1515 2 : return CE_Failure;
1516 : }
1517 2297 : return SetSpatialRef(&oSRS);
1518 : }
1519 : else
1520 : {
1521 189 : return SetSpatialRef(nullptr);
1522 : }
1523 : }
1524 :
1525 : /************************************************************************/
1526 : /* SetSpatialRef() */
1527 : /************************************************************************/
1528 :
1529 : /**
1530 : * \brief Set the spatial reference system for this dataset.
1531 : *
1532 : * An error may occur because the dataset
1533 : * is not writable, or because the dataset does not support the indicated
1534 : * projection. Many formats do not support writing projections.
1535 : *
1536 : * This method is the same as the C GDALSetSpatialRef() function.
1537 : *
1538 : * @since GDAL 3.0
1539 :
1540 : * @param poSRS spatial reference system object. nullptr can potentially be
1541 : * passed for drivers that support unsetting the SRS.
1542 : *
1543 : * @return CE_Failure if an error occurs, otherwise CE_None.
1544 : */
1545 :
1546 0 : CPLErr GDALDataset::SetSpatialRef(CPL_UNUSED const OGRSpatialReference *poSRS)
1547 : {
1548 0 : if (!(GetMOFlags() & GMO_IGNORE_UNIMPLEMENTED))
1549 0 : ReportError(CE_Failure, CPLE_NotSupported,
1550 : "Dataset does not support the SetSpatialRef() method.");
1551 0 : return CE_Failure;
1552 : }
1553 :
1554 : /************************************************************************/
1555 : /* GDALSetSpatialRef() */
1556 : /************************************************************************/
1557 :
1558 : /**
1559 : * \brief Set the spatial reference system for this dataset.
1560 : *
1561 : * @since GDAL 3.0
1562 : *
1563 : * @see GDALDataset::SetSpatialRef()
1564 : */
1565 :
1566 1386 : CPLErr GDALSetSpatialRef(GDALDatasetH hDS, OGRSpatialReferenceH hSRS)
1567 :
1568 : {
1569 1386 : VALIDATE_POINTER1(hDS, "GDALSetSpatialRef", CE_Failure);
1570 :
1571 2772 : return GDALDataset::FromHandle(hDS)->SetSpatialRef(
1572 1386 : OGRSpatialReference::FromHandle(hSRS));
1573 : }
1574 :
1575 : /************************************************************************/
1576 : /* GDALSetProjection() */
1577 : /************************************************************************/
1578 :
1579 : /**
1580 : * \brief Set the projection reference string for this dataset.
1581 : *
1582 : * @see GDALDataset::SetProjection()
1583 : */
1584 :
1585 1849 : CPLErr CPL_STDCALL GDALSetProjection(GDALDatasetH hDS,
1586 : const char *pszProjection)
1587 :
1588 : {
1589 1849 : VALIDATE_POINTER1(hDS, "GDALSetProjection", CE_Failure);
1590 :
1591 1849 : return GDALDataset::FromHandle(hDS)->SetProjection(pszProjection);
1592 : }
1593 :
1594 : /************************************************************************/
1595 : /* GetGeoTransform() */
1596 : /************************************************************************/
1597 :
1598 : /**
1599 : * \brief Fetch the affine transformation coefficients.
1600 : *
1601 : * Fetches the coefficients for transforming between pixel/line (P,L) raster
1602 : * space, and projection coordinates (Xp,Yp) space.
1603 : *
1604 : * \code
1605 : * Xp = gt[0] + P*gt[1] + L*gt[2];
1606 : * Yp = gt[3] + P*padfTransform[4] + L*gt[5];
1607 : * \endcode
1608 : *
1609 : * In a north up image, gt[1] is the pixel width, and
1610 : * gt[5] is the pixel height. The upper left corner of the
1611 : * upper left pixel is at position (gt[0],gt[3]).
1612 : *
1613 : * The default transform is (0,1,0,0,0,1) and should be returned even when
1614 : * a CE_Failure error is returned, such as for formats that don't support
1615 : * transformation to projection coordinates.
1616 : *
1617 : * This method does the same thing as the C GDALGetGeoTransform() function.
1618 : *
1619 : * @param gt an existing six double buffer into which the
1620 : * transformation will be placed.
1621 : *
1622 : * @return CE_None on success, or CE_Failure if no transform can be fetched.
1623 : *
1624 : * @since 3.12
1625 : */
1626 :
1627 16084 : CPLErr GDALDataset::GetGeoTransform(GDALGeoTransform >) const
1628 :
1629 : {
1630 16084 : gt = GDALGeoTransform();
1631 :
1632 16084 : return CE_Failure;
1633 : }
1634 :
1635 : /************************************************************************/
1636 : /* GetGeoTransform() */
1637 : /************************************************************************/
1638 :
1639 : /**
1640 : * \brief Fetch the affine transformation coefficients.
1641 : *
1642 : * Fetches the coefficients for transforming between pixel/line (P,L) raster
1643 : * space, and projection coordinates (Xp,Yp) space.
1644 : *
1645 : * \code
1646 : * Xp = padfTransform[0] + P*padfTransform[1] + L*padfTransform[2];
1647 : * Yp = padfTransform[3] + P*padfTransform[4] + L*padfTransform[5];
1648 : * \endcode
1649 : *
1650 : * In a north up image, padfTransform[1] is the pixel width, and
1651 : * padfTransform[5] is the pixel height. The upper left corner of the
1652 : * upper left pixel is at position (padfTransform[0],padfTransform[3]).
1653 : *
1654 : * The default transform is (0,1,0,0,0,1) and should be returned even when
1655 : * a CE_Failure error is returned, such as for formats that don't support
1656 : * transformation to projection coordinates.
1657 : *
1658 : * This method does the same thing as the C GDALGetGeoTransform() function.
1659 : *
1660 : * @param padfTransform an existing six double buffer into which the
1661 : * transformation will be placed.
1662 : *
1663 : * @return CE_None on success, or CE_Failure if no transform can be fetched.
1664 : *
1665 : * @deprecated since 3.12. Use GetGeoTransform(GDALGeoTransform&) instead
1666 : */
1667 :
1668 2 : CPLErr GDALDataset::GetGeoTransform(double *padfTransform) const
1669 :
1670 : {
1671 2 : return GetGeoTransform(
1672 2 : *reinterpret_cast<GDALGeoTransform *>(padfTransform));
1673 : }
1674 :
1675 : /************************************************************************/
1676 : /* GDALGetGeoTransform() */
1677 : /************************************************************************/
1678 :
1679 : /**
1680 : * \brief Fetch the affine transformation coefficients.
1681 : *
1682 : * @see GDALDataset::GetGeoTransform()
1683 : */
1684 :
1685 9477 : CPLErr CPL_STDCALL GDALGetGeoTransform(GDALDatasetH hDS, double *padfTransform)
1686 :
1687 : {
1688 9477 : VALIDATE_POINTER1(hDS, "GDALGetGeoTransform", CE_Failure);
1689 :
1690 18954 : return GDALDataset::FromHandle(hDS)->GetGeoTransform(
1691 9477 : *reinterpret_cast<GDALGeoTransform *>(padfTransform));
1692 : }
1693 :
1694 : /************************************************************************/
1695 : /* SetGeoTransform() */
1696 : /************************************************************************/
1697 :
1698 : /**
1699 : * \fn GDALDataset::SetGeoTransform(const GDALGeoTransform&)
1700 : * \brief Set the affine transformation coefficients.
1701 : *
1702 : * See GetGeoTransform() for details on the meaning of the padfTransform
1703 : * coefficients.
1704 : *
1705 : * This method does the same thing as the C GDALSetGeoTransform() function.
1706 : *
1707 : * @param gt the transformation coefficients to be written with the dataset.
1708 : *
1709 : * @return CE_None on success, or CE_Failure if this transform cannot be
1710 : * written.
1711 : *
1712 : * @since 3.12
1713 : */
1714 :
1715 0 : CPLErr GDALDataset::SetGeoTransform(CPL_UNUSED const GDALGeoTransform >)
1716 :
1717 : {
1718 0 : if (!(GetMOFlags() & GMO_IGNORE_UNIMPLEMENTED))
1719 0 : ReportError(CE_Failure, CPLE_NotSupported,
1720 : "SetGeoTransform() not supported for this dataset.");
1721 :
1722 0 : return CE_Failure;
1723 : }
1724 :
1725 : /************************************************************************/
1726 : /* SetGeoTransform() */
1727 : /************************************************************************/
1728 :
1729 : /**
1730 : * \brief Set the affine transformation coefficients.
1731 : *
1732 : * See GetGeoTransform() for details on the meaning of the padfTransform
1733 : * coefficients.
1734 : *
1735 : * This method does the same thing as the C GDALSetGeoTransform() function.
1736 : *
1737 : * @param padfTransform a six double buffer containing the transformation
1738 : * coefficients to be written with the dataset.
1739 : *
1740 : * @return CE_None on success, or CE_Failure if this transform cannot be
1741 : * written.
1742 : *
1743 : * @deprecated since 3.12. Use SetGeoTransform(const GDALGeoTransform&) instead
1744 : */
1745 38 : CPLErr GDALDataset::SetGeoTransform(const double *padfTransform)
1746 :
1747 : {
1748 38 : return SetGeoTransform(
1749 38 : *reinterpret_cast<const GDALGeoTransform *>(padfTransform));
1750 : }
1751 :
1752 : /************************************************************************/
1753 : /* GDALSetGeoTransform() */
1754 : /************************************************************************/
1755 :
1756 : /**
1757 : * \brief Set the affine transformation coefficients.
1758 : *
1759 : * @see GDALDataset::SetGeoTransform()
1760 : */
1761 :
1762 4427 : CPLErr CPL_STDCALL GDALSetGeoTransform(GDALDatasetH hDS,
1763 : const double *padfTransform)
1764 :
1765 : {
1766 4427 : VALIDATE_POINTER1(hDS, "GDALSetGeoTransform", CE_Failure);
1767 4427 : VALIDATE_POINTER1(padfTransform, "GDALSetGeoTransform", CE_Failure);
1768 :
1769 8854 : return GDALDataset::FromHandle(hDS)->SetGeoTransform(
1770 4427 : *reinterpret_cast<const GDALGeoTransform *>(padfTransform));
1771 : }
1772 :
1773 : /************************************************************************/
1774 : /* GetInternalHandle() */
1775 : /************************************************************************/
1776 :
1777 : /**
1778 : * \fn GDALDataset::GetInternalHandle(const char*)
1779 : * \brief Fetch a format specific internally meaningful handle.
1780 : *
1781 : * This method is the same as the C GDALGetInternalHandle() method.
1782 : *
1783 : * @param pszHandleName the handle name desired. The meaningful names
1784 : * will be specific to the file format.
1785 : *
1786 : * @return the desired handle value, or NULL if not recognized/supported.
1787 : */
1788 :
1789 199 : void *GDALDataset::GetInternalHandle(CPL_UNUSED const char *pszHandleName)
1790 :
1791 : {
1792 199 : return nullptr;
1793 : }
1794 :
1795 : /************************************************************************/
1796 : /* GDALGetInternalHandle() */
1797 : /************************************************************************/
1798 :
1799 : /**
1800 : * \brief Fetch a format specific internally meaningful handle.
1801 : *
1802 : * @see GDALDataset::GetInternalHandle()
1803 : */
1804 :
1805 61 : void *CPL_STDCALL GDALGetInternalHandle(GDALDatasetH hDS,
1806 : const char *pszRequest)
1807 :
1808 : {
1809 61 : VALIDATE_POINTER1(hDS, "GDALGetInternalHandle", nullptr);
1810 :
1811 61 : return GDALDataset::FromHandle(hDS)->GetInternalHandle(pszRequest);
1812 : }
1813 :
1814 : /************************************************************************/
1815 : /* GetDriver() */
1816 : /************************************************************************/
1817 :
1818 : /**
1819 : * \brief Fetch the driver to which this dataset relates.
1820 : *
1821 : * This method is the same as the C GDALGetDatasetDriver() function.
1822 : *
1823 : * @return the driver on which the dataset was created with GDALOpen() or
1824 : * GDALCreate().
1825 : */
1826 :
1827 35406 : GDALDriver *GDALDataset::GetDriver()
1828 : {
1829 35406 : return poDriver;
1830 : }
1831 :
1832 : /************************************************************************/
1833 : /* GDALGetDatasetDriver() */
1834 : /************************************************************************/
1835 :
1836 : /**
1837 : * \brief Fetch the driver to which this dataset relates.
1838 : *
1839 : * @see GDALDataset::GetDriver()
1840 : */
1841 :
1842 2708 : GDALDriverH CPL_STDCALL GDALGetDatasetDriver(GDALDatasetH hDataset)
1843 :
1844 : {
1845 2708 : VALIDATE_POINTER1(hDataset, "GDALGetDatasetDriver", nullptr);
1846 :
1847 : return static_cast<GDALDriverH>(
1848 2708 : GDALDataset::FromHandle(hDataset)->GetDriver());
1849 : }
1850 :
1851 : /************************************************************************/
1852 : /* Reference() */
1853 : /************************************************************************/
1854 :
1855 : /**
1856 : * \brief Add one to dataset reference count.
1857 : *
1858 : * The reference is one after instantiation.
1859 : *
1860 : * This method is the same as the C GDALReferenceDataset() function.
1861 : *
1862 : * @return the post-increment reference count.
1863 : */
1864 :
1865 261013 : int GDALDataset::Reference()
1866 : {
1867 261013 : return ++nRefCount;
1868 : }
1869 :
1870 : /************************************************************************/
1871 : /* GDALReferenceDataset() */
1872 : /************************************************************************/
1873 :
1874 : /**
1875 : * \brief Add one to dataset reference count.
1876 : *
1877 : * @see GDALDataset::Reference()
1878 : */
1879 :
1880 1384 : int CPL_STDCALL GDALReferenceDataset(GDALDatasetH hDataset)
1881 :
1882 : {
1883 1384 : VALIDATE_POINTER1(hDataset, "GDALReferenceDataset", 0);
1884 :
1885 1384 : return GDALDataset::FromHandle(hDataset)->Reference();
1886 : }
1887 :
1888 : /************************************************************************/
1889 : /* Dereference() */
1890 : /************************************************************************/
1891 :
1892 : /**
1893 : * \brief Subtract one from dataset reference count.
1894 : *
1895 : * The reference is one after instantiation. Generally when the reference
1896 : * count has dropped to zero the dataset may be safely deleted (closed).
1897 : *
1898 : * This method is the same as the C GDALDereferenceDataset() function.
1899 : *
1900 : * @return the post-decrement reference count.
1901 : */
1902 :
1903 324145 : int GDALDataset::Dereference()
1904 : {
1905 324145 : return --nRefCount;
1906 : }
1907 :
1908 : /************************************************************************/
1909 : /* GDALDereferenceDataset() */
1910 : /************************************************************************/
1911 :
1912 : /**
1913 : * \brief Subtract one from dataset reference count.
1914 : *
1915 : * @see GDALDataset::Dereference()
1916 : */
1917 :
1918 61229 : int CPL_STDCALL GDALDereferenceDataset(GDALDatasetH hDataset)
1919 :
1920 : {
1921 61229 : VALIDATE_POINTER1(hDataset, "GDALDereferenceDataset", 0);
1922 :
1923 61229 : return GDALDataset::FromHandle(hDataset)->Dereference();
1924 : }
1925 :
1926 : /************************************************************************/
1927 : /* ReleaseRef() */
1928 : /************************************************************************/
1929 :
1930 : /**
1931 : * \brief Drop a reference to this object, and destroy if no longer referenced.
1932 : * @return TRUE if the object has been destroyed.
1933 : */
1934 :
1935 252374 : int GDALDataset::ReleaseRef()
1936 :
1937 : {
1938 252374 : if (Dereference() <= 0)
1939 : {
1940 7768 : nRefCount = 1;
1941 7768 : delete this;
1942 7768 : return TRUE;
1943 : }
1944 244606 : return FALSE;
1945 : }
1946 :
1947 : /************************************************************************/
1948 : /* GDALReleaseDataset() */
1949 : /************************************************************************/
1950 :
1951 : /**
1952 : * \brief Drop a reference to this object, and destroy if no longer referenced.
1953 : *
1954 : * @see GDALDataset::ReleaseRef()
1955 : */
1956 :
1957 1621 : int CPL_STDCALL GDALReleaseDataset(GDALDatasetH hDataset)
1958 :
1959 : {
1960 1621 : VALIDATE_POINTER1(hDataset, "GDALReleaseDataset", 0);
1961 :
1962 1621 : return GDALDataset::FromHandle(hDataset)->ReleaseRef();
1963 : }
1964 :
1965 : /************************************************************************/
1966 : /* GetShared() */
1967 : /************************************************************************/
1968 :
1969 : /**
1970 : * \brief Returns shared flag.
1971 : *
1972 : * @return TRUE if the GDALDataset is available for sharing, or FALSE if not.
1973 : */
1974 :
1975 312178 : int GDALDataset::GetShared() const
1976 : {
1977 312178 : return bShared;
1978 : }
1979 :
1980 : /************************************************************************/
1981 : /* MarkAsShared() */
1982 : /************************************************************************/
1983 :
1984 : /**
1985 : * \brief Mark this dataset as available for sharing.
1986 : */
1987 :
1988 436 : void GDALDataset::MarkAsShared()
1989 :
1990 : {
1991 436 : CPLAssert(!bShared);
1992 :
1993 436 : bShared = true;
1994 436 : if (bIsInternal)
1995 24 : return;
1996 :
1997 412 : GIntBig nPID = GDALGetResponsiblePIDForCurrentThread();
1998 :
1999 : // Insert the dataset in the set of shared opened datasets.
2000 824 : CPLMutexHolderD(&hDLMutex);
2001 412 : if (phSharedDatasetSet == nullptr)
2002 285 : phSharedDatasetSet =
2003 285 : CPLHashSetNew(GDALSharedDatasetHashFunc, GDALSharedDatasetEqualFunc,
2004 : GDALSharedDatasetFreeFunc);
2005 :
2006 : SharedDatasetCtxt *psStruct =
2007 412 : static_cast<SharedDatasetCtxt *>(CPLMalloc(sizeof(SharedDatasetCtxt)));
2008 412 : psStruct->poDS = this;
2009 412 : psStruct->nPID = nPID;
2010 412 : psStruct->nOpenFlags = nOpenFlags & ~GDAL_OF_SHARED;
2011 412 : psStruct->pszDescription = CPLStrdup(GetDescription());
2012 : std::string osConcatenatedOpenOptions =
2013 824 : GDALSharedDatasetConcatenateOpenOptions(papszOpenOptions);
2014 412 : psStruct->pszConcatenatedOpenOptions =
2015 412 : CPLStrdup(osConcatenatedOpenOptions.c_str());
2016 412 : if (CPLHashSetLookup(phSharedDatasetSet, psStruct) != nullptr)
2017 : {
2018 1 : GDALSharedDatasetFreeFunc(psStruct);
2019 1 : ReportError(CE_Failure, CPLE_AppDefined,
2020 : "An existing shared dataset already has this description. "
2021 : "This should not happen.");
2022 : }
2023 : else
2024 : {
2025 411 : CPLHashSetInsert(phSharedDatasetSet, psStruct);
2026 :
2027 411 : (*poAllDatasetMap)[this] = nPID;
2028 : }
2029 : }
2030 :
2031 : /************************************************************************/
2032 : /* MarkSuppressOnClose() */
2033 : /************************************************************************/
2034 :
2035 : /** Set that the dataset must be deleted on close.
2036 : *
2037 : * This is the same as C function GDALDatasetMarkSuppressOnClose()
2038 : */
2039 1231 : void GDALDataset::MarkSuppressOnClose()
2040 : {
2041 1231 : bSuppressOnClose = true;
2042 1231 : }
2043 :
2044 : /************************************************************************/
2045 : /* GDALDatasetMarkSuppressOnClose() */
2046 : /************************************************************************/
2047 :
2048 : /** Set that the dataset must be deleted on close.
2049 : *
2050 : * This is the same as C++ method GDALDataset::MarkSuppressOnClose()
2051 : *
2052 : * @since GDAL 3.12
2053 : */
2054 :
2055 4 : void GDALDatasetMarkSuppressOnClose(GDALDatasetH hDS)
2056 : {
2057 4 : VALIDATE_POINTER0(hDS, "GDALDatasetMarkSuppressOnClose");
2058 :
2059 4 : return GDALDataset::FromHandle(hDS)->MarkSuppressOnClose();
2060 : }
2061 :
2062 : /************************************************************************/
2063 : /* UnMarkSuppressOnClose() */
2064 : /************************************************************************/
2065 :
2066 : /** Remove the flag requesting the dataset to be deleted on close. */
2067 684 : void GDALDataset::UnMarkSuppressOnClose()
2068 : {
2069 684 : bSuppressOnClose = false;
2070 684 : }
2071 :
2072 : /************************************************************************/
2073 : /* CleanupPostFileClosing() */
2074 : /************************************************************************/
2075 :
2076 : /** This method should be called by driver implementations in their destructor,
2077 : * after having closed all files, but before having freed resources that
2078 : * are needed for their GetFileList() implementation.
2079 : * This is used to implement MarkSuppressOnClose behavior.
2080 : */
2081 259 : void GDALDataset::CleanupPostFileClosing()
2082 : {
2083 259 : if (IsMarkedSuppressOnClose())
2084 : {
2085 1 : char **papszFileList = GetFileList();
2086 3 : for (int i = 0; papszFileList && papszFileList[i]; ++i)
2087 2 : VSIUnlink(papszFileList[i]);
2088 1 : CSLDestroy(papszFileList);
2089 : }
2090 259 : }
2091 :
2092 : /************************************************************************/
2093 : /* GetGCPCount() */
2094 : /************************************************************************/
2095 :
2096 : /**
2097 : * \brief Get number of GCPs.
2098 : *
2099 : * This method is the same as the C function GDALGetGCPCount().
2100 : *
2101 : * @return number of GCPs for this dataset. Zero if there are none.
2102 : */
2103 :
2104 16623 : int GDALDataset::GetGCPCount()
2105 : {
2106 16623 : return 0;
2107 : }
2108 :
2109 : /************************************************************************/
2110 : /* GDALGetGCPCount() */
2111 : /************************************************************************/
2112 :
2113 : /**
2114 : * \brief Get number of GCPs.
2115 : *
2116 : * @see GDALDataset::GetGCPCount()
2117 : */
2118 :
2119 2247 : int CPL_STDCALL GDALGetGCPCount(GDALDatasetH hDS)
2120 :
2121 : {
2122 2247 : VALIDATE_POINTER1(hDS, "GDALGetGCPCount", 0);
2123 :
2124 2247 : return GDALDataset::FromHandle(hDS)->GetGCPCount();
2125 : }
2126 :
2127 : /************************************************************************/
2128 : /* GetGCPProjection() */
2129 : /************************************************************************/
2130 :
2131 : /**
2132 : * \brief Get output projection for GCPs.
2133 : *
2134 : * This method is the same as the C function GDALGetGCPProjection().
2135 : *
2136 : * The projection string follows the normal rules from GetProjectionRef().
2137 : *
2138 : * \note Starting with GDAL 3.0, this is a compatibility layer around
2139 : * GetGCPSpatialRef()
2140 : *
2141 : * @return internal projection string or "" if there are no GCPs.
2142 : * It should not be altered, freed or expected to last for long.
2143 : */
2144 :
2145 1093 : const char *GDALDataset::GetGCPProjection() const
2146 : {
2147 1093 : const auto poSRS = GetGCPSpatialRef();
2148 1093 : if (!poSRS || !m_poPrivate)
2149 : {
2150 754 : return "";
2151 : }
2152 339 : char *pszWKT = nullptr;
2153 339 : poSRS->exportToWkt(&pszWKT);
2154 339 : if (!pszWKT)
2155 : {
2156 0 : return "";
2157 : }
2158 :
2159 : // If called on a thread-safe dataset, we might be called by several
2160 : // threads, so make sure our accesses to m_pszWKTCached are protected
2161 : // by a mutex.
2162 678 : std::lock_guard oLock(m_poPrivate->m_oMutexWKT);
2163 339 : if (m_poPrivate->m_pszWKTGCPCached &&
2164 258 : strcmp(pszWKT, m_poPrivate->m_pszWKTGCPCached) == 0)
2165 : {
2166 258 : CPLFree(pszWKT);
2167 258 : return m_poPrivate->m_pszWKTGCPCached;
2168 : }
2169 81 : CPLFree(m_poPrivate->m_pszWKTGCPCached);
2170 81 : m_poPrivate->m_pszWKTGCPCached = pszWKT;
2171 81 : return m_poPrivate->m_pszWKTGCPCached;
2172 : }
2173 :
2174 : /************************************************************************/
2175 : /* GetGCPSpatialRef() */
2176 : /************************************************************************/
2177 :
2178 : /**
2179 : * \brief Get output spatial reference system for GCPs.
2180 : *
2181 : * Same as the C function GDALGetGCPSpatialRef().
2182 : *
2183 : * When a SRS is not available, null is returned. If used on
2184 : * a dataset where there is a geotransform, and not GCPs, this method returns
2185 : * null. Use GetSpatialRef() instead.
2186 : *
2187 : * @since GDAL 3.0
2188 : *
2189 : * @return a pointer to an internal object. It should not be altered or freed.
2190 : * Its lifetime will be the one of the dataset object, or until the next
2191 : * call to this method.
2192 : */
2193 :
2194 39 : const OGRSpatialReference *GDALDataset::GetGCPSpatialRef() const
2195 : {
2196 39 : return nullptr;
2197 : }
2198 :
2199 : /************************************************************************/
2200 : /* GDALGetGCPSpatialRef() */
2201 : /************************************************************************/
2202 :
2203 : /**
2204 : * \brief Get output spatial reference system for GCPs.
2205 : *
2206 : * @since GDAL 3.0
2207 : *
2208 : * @see GDALDataset::GetGCPSpatialRef()
2209 : */
2210 :
2211 469 : OGRSpatialReferenceH GDALGetGCPSpatialRef(GDALDatasetH hDS)
2212 :
2213 : {
2214 469 : VALIDATE_POINTER1(hDS, "GDALGetGCPSpatialRef", nullptr);
2215 :
2216 469 : return OGRSpatialReference::ToHandle(const_cast<OGRSpatialReference *>(
2217 469 : GDALDataset::FromHandle(hDS)->GetGCPSpatialRef()));
2218 : }
2219 :
2220 : /************************************************************************/
2221 : /* GDALGetGCPProjection() */
2222 : /************************************************************************/
2223 :
2224 : /**
2225 : * \brief Get output projection for GCPs.
2226 : *
2227 : * @see GDALDataset::GetGCPProjection()
2228 : */
2229 :
2230 1023 : const char *CPL_STDCALL GDALGetGCPProjection(GDALDatasetH hDS)
2231 :
2232 : {
2233 1023 : VALIDATE_POINTER1(hDS, "GDALGetGCPProjection", nullptr);
2234 :
2235 1023 : return GDALDataset::FromHandle(hDS)->GetGCPProjection();
2236 : }
2237 :
2238 : /************************************************************************/
2239 : /* GetGCPs() */
2240 : /************************************************************************/
2241 :
2242 : /**
2243 : * \brief Fetch GCPs.
2244 : *
2245 : * This method is the same as the C function GDALGetGCPs().
2246 : *
2247 : * @return pointer to internal GCP structure list. It should not be modified,
2248 : * and may change on the next GDAL call.
2249 : */
2250 :
2251 11 : const GDAL_GCP *GDALDataset::GetGCPs()
2252 : {
2253 11 : return nullptr;
2254 : }
2255 :
2256 : /************************************************************************/
2257 : /* GDALGetGCPs() */
2258 : /************************************************************************/
2259 :
2260 : /**
2261 : * \brief Fetch GCPs.
2262 : *
2263 : * @see GDALDataset::GetGCPs()
2264 : */
2265 :
2266 580 : const GDAL_GCP *CPL_STDCALL GDALGetGCPs(GDALDatasetH hDS)
2267 :
2268 : {
2269 580 : VALIDATE_POINTER1(hDS, "GDALGetGCPs", nullptr);
2270 :
2271 580 : return GDALDataset::FromHandle(hDS)->GetGCPs();
2272 : }
2273 :
2274 : /************************************************************************/
2275 : /* SetGCPs() */
2276 : /************************************************************************/
2277 :
2278 : /**
2279 : * \brief Assign GCPs.
2280 : *
2281 : * This method is the same as the C function GDALSetGCPs().
2282 : *
2283 : * This method assigns the passed set of GCPs to this dataset, as well as
2284 : * setting their coordinate system. Internally copies are made of the
2285 : * coordinate system and list of points, so the caller remains responsible for
2286 : * deallocating these arguments if appropriate.
2287 : *
2288 : * Most formats do not support setting of GCPs, even formats that can
2289 : * handle GCPs. These formats will return CE_Failure.
2290 : *
2291 : * \note Startig with GDAL 3.0, this is a compatibility layer around
2292 : * SetGCPs(int, const GDAL_GCP*, const char*)
2293 : *
2294 : * @param nGCPCount number of GCPs being assigned.
2295 : *
2296 : * @param pasGCPList array of GCP structures being assign (nGCPCount in array).
2297 : *
2298 : * @param pszGCPProjection the new OGC WKT coordinate system to assign for the
2299 : * GCP output coordinates. This parameter should be "" if no output coordinate
2300 : * system is known.
2301 : *
2302 : * @return CE_None on success, CE_Failure on failure (including if action is
2303 : * not supported for this format).
2304 : */
2305 :
2306 52 : CPLErr GDALDataset::SetGCPs(int nGCPCount, const GDAL_GCP *pasGCPList,
2307 : const char *pszGCPProjection)
2308 :
2309 : {
2310 52 : if (pszGCPProjection && pszGCPProjection[0] != '\0')
2311 : {
2312 66 : OGRSpatialReference oSRS;
2313 33 : oSRS.SetAxisMappingStrategy(OAMS_TRADITIONAL_GIS_ORDER);
2314 33 : if (oSRS.importFromWkt(pszGCPProjection) != OGRERR_NONE)
2315 : {
2316 0 : return CE_Failure;
2317 : }
2318 33 : return SetGCPs(nGCPCount, pasGCPList, &oSRS);
2319 : }
2320 : else
2321 : {
2322 19 : return SetGCPs(nGCPCount, pasGCPList,
2323 19 : static_cast<const OGRSpatialReference *>(nullptr));
2324 : }
2325 : }
2326 :
2327 : /************************************************************************/
2328 : /* SetGCPs() */
2329 : /************************************************************************/
2330 :
2331 : /**
2332 : * \brief Assign GCPs.
2333 : *
2334 : * This method is the same as the C function GDALSetGCPs().
2335 : *
2336 : * This method assigns the passed set of GCPs to this dataset, as well as
2337 : * setting their coordinate system. Internally copies are made of the
2338 : * coordinate system and list of points, so the caller remains responsible for
2339 : * deallocating these arguments if appropriate.
2340 : *
2341 : * Most formats do not support setting of GCPs, even formats that can
2342 : * handle GCPs. These formats will return CE_Failure.
2343 : *
2344 : * @since GDAL 3.0
2345 : *
2346 : * @param nGCPCount number of GCPs being assigned.
2347 : *
2348 : * @param pasGCPList array of GCP structures being assign (nGCPCount in array).
2349 : *
2350 : * @param poGCP_SRS the new coordinate reference system to assign for the
2351 : * GCP output coordinates. This parameter should be null if no output
2352 : * coordinate system is known.
2353 : *
2354 : * @return CE_None on success, CE_Failure on failure (including if action is
2355 : * not supported for this format).
2356 : */
2357 :
2358 1 : CPLErr GDALDataset::SetGCPs(CPL_UNUSED int nGCPCount,
2359 : CPL_UNUSED const GDAL_GCP *pasGCPList,
2360 : CPL_UNUSED const OGRSpatialReference *poGCP_SRS)
2361 :
2362 : {
2363 1 : if (!(GetMOFlags() & GMO_IGNORE_UNIMPLEMENTED))
2364 1 : ReportError(CE_Failure, CPLE_NotSupported,
2365 : "Dataset does not support the SetGCPs() method.");
2366 :
2367 1 : return CE_Failure;
2368 : }
2369 :
2370 : /************************************************************************/
2371 : /* GDALSetGCPs() */
2372 : /************************************************************************/
2373 :
2374 : /**
2375 : * \brief Assign GCPs.
2376 : *
2377 : * @see GDALDataset::SetGCPs(int, const GDAL_GCP*, const char*)
2378 : */
2379 :
2380 29 : CPLErr CPL_STDCALL GDALSetGCPs(GDALDatasetH hDS, int nGCPCount,
2381 : const GDAL_GCP *pasGCPList,
2382 : const char *pszGCPProjection)
2383 :
2384 : {
2385 29 : VALIDATE_POINTER1(hDS, "GDALSetGCPs", CE_Failure);
2386 :
2387 29 : return GDALDataset::FromHandle(hDS)->SetGCPs(nGCPCount, pasGCPList,
2388 29 : pszGCPProjection);
2389 : }
2390 :
2391 : /************************************************************************/
2392 : /* GDALSetGCPs2() */
2393 : /************************************************************************/
2394 :
2395 : /**
2396 : * \brief Assign GCPs.
2397 : *
2398 : * @since GDAL 3.0
2399 : * @see GDALDataset::SetGCPs(int, const GDAL_GCP*, const OGRSpatialReference*)
2400 : */
2401 :
2402 9 : CPLErr GDALSetGCPs2(GDALDatasetH hDS, int nGCPCount, const GDAL_GCP *pasGCPList,
2403 : OGRSpatialReferenceH hSRS)
2404 :
2405 : {
2406 9 : VALIDATE_POINTER1(hDS, "GDALSetGCPs2", CE_Failure);
2407 :
2408 18 : return GDALDataset::FromHandle(hDS)->SetGCPs(
2409 9 : nGCPCount, pasGCPList, OGRSpatialReference::FromHandle(hSRS));
2410 : }
2411 :
2412 : /************************************************************************/
2413 : /* BuildOverviews() */
2414 : /************************************************************************/
2415 :
2416 : /**
2417 : * \brief Build raster overview(s)
2418 : *
2419 : * If the operation is not supported for the indicated dataset, then
2420 : * CE_Failure is returned, and CPLGetLastErrorNo() will return
2421 : * CPLE_NotSupported.
2422 : *
2423 : * Depending on the actual file format, all overviews level can be also
2424 : * deleted by specifying nOverviews == 0. This works at least for external
2425 : * overviews (.ovr), TIFF internal overviews, etc.
2426 : *
2427 : * Starting with GDAL 3.2, the GDAL_NUM_THREADS configuration option can be set
2428 : * to "ALL_CPUS" or a integer value to specify the number of threads to use for
2429 : * overview computation.
2430 : *
2431 : * This method is the same as the C function GDALBuildOverviewsEx().
2432 : *
2433 : * @param pszResampling one of "AVERAGE", "AVERAGE_MAGPHASE", "RMS",
2434 : * "BILINEAR", "CUBIC", "CUBICSPLINE", "GAUSS", "LANCZOS", "MODE", "NEAREST",
2435 : * or "NONE" controlling the downsampling method applied.
2436 : * @param nOverviews number of overviews to build, or 0 to clean overviews.
2437 : * @param panOverviewList the list of overview decimation factors (positive
2438 : * integers, normally larger or equal to 2) to build, or
2439 : * NULL if nOverviews == 0.
2440 : * @param nListBands number of bands to build overviews for in panBandList.
2441 : * Build for all bands if this is 0.
2442 : * @param panBandList list of band numbers.
2443 : * @param pfnProgress a function to call to report progress, or NULL.
2444 : * @param pProgressData application data to pass to the progress function.
2445 : * @param papszOptions (GDAL >= 3.6) NULL terminated list of options as
2446 : * key=value pairs, or NULL.
2447 : * Possible keys are the ones returned by
2448 : * GetDriver()->GetMetadataItem(GDAL_DMD_OVERVIEW_CREATIONOPTIONLIST)
2449 : *
2450 : * @return CE_None on success or CE_Failure if the operation doesn't work.
2451 : *
2452 : * For example, to build overview level 2, 4 and 8 on all bands the following
2453 : * call could be made:
2454 : * \code{.cpp}
2455 : * int anOverviewList[3] = { 2, 4, 8 };
2456 : *
2457 : * poDataset->BuildOverviews( "NEAREST", 3, anOverviewList, 0, nullptr,
2458 : * GDALDummyProgress, nullptr );
2459 : * \endcode
2460 : *
2461 : * @see GDALRegenerateOverviewsEx()
2462 : */
2463 :
2464 751 : CPLErr GDALDataset::BuildOverviews(const char *pszResampling, int nOverviews,
2465 : const int *panOverviewList, int nListBands,
2466 : const int *panBandList,
2467 : GDALProgressFunc pfnProgress,
2468 : void *pProgressData,
2469 : CSLConstList papszOptions)
2470 : {
2471 751 : int *panAllBandList = nullptr;
2472 :
2473 1502 : CPLStringList aosOptions(papszOptions);
2474 751 : if (poDriver && !aosOptions.empty())
2475 : {
2476 : const char *pszOptionList =
2477 28 : poDriver->GetMetadataItem(GDAL_DMD_OVERVIEW_CREATIONOPTIONLIST);
2478 28 : if (pszOptionList)
2479 : {
2480 : // For backwards compatibility
2481 28 : if (const char *opt = aosOptions.FetchNameValue("USE_RRD"))
2482 : {
2483 4 : if (strstr(pszOptionList, "<Value>RRD</Value>") &&
2484 2 : aosOptions.FetchNameValue("LOCATION") == nullptr)
2485 : {
2486 2 : if (CPLTestBool(opt))
2487 2 : aosOptions.SetNameValue("LOCATION", "RRD");
2488 2 : aosOptions.SetNameValue("USE_RRD", nullptr);
2489 : }
2490 : }
2491 28 : if (const char *opt =
2492 28 : aosOptions.FetchNameValue("VRT_VIRTUAL_OVERVIEWS"))
2493 : {
2494 3 : if (strstr(pszOptionList, "VIRTUAL"))
2495 : {
2496 3 : aosOptions.SetNameValue("VIRTUAL", opt);
2497 3 : aosOptions.SetNameValue("VRT_VIRTUAL_OVERVIEWS", nullptr);
2498 : }
2499 : }
2500 :
2501 76 : for (const auto &[pszKey, pszValue] :
2502 104 : cpl::IterateNameValue(papszOptions))
2503 : {
2504 38 : if (cpl::ends_with(std::string_view(pszKey), "_OVERVIEW"))
2505 : {
2506 : aosOptions.SetNameValue(
2507 16 : std::string(pszKey)
2508 16 : .substr(0, strlen(pszKey) - strlen("_OVERVIEW"))
2509 : .c_str(),
2510 16 : pszValue);
2511 8 : aosOptions.SetNameValue(pszKey, nullptr);
2512 : }
2513 : }
2514 :
2515 56 : CPLString osDriver;
2516 28 : osDriver.Printf("driver %s", poDriver->GetDescription());
2517 28 : GDALValidateOptions(pszOptionList, aosOptions.List(),
2518 : "overview creation option", osDriver);
2519 : }
2520 : }
2521 :
2522 751 : if (nListBands == 0)
2523 : {
2524 739 : nListBands = GetRasterCount();
2525 : panAllBandList =
2526 739 : static_cast<int *>(CPLMalloc(sizeof(int) * nListBands));
2527 67475 : for (int i = 0; i < nListBands; ++i)
2528 66736 : panAllBandList[i] = i + 1;
2529 :
2530 739 : panBandList = panAllBandList;
2531 : }
2532 :
2533 751 : if (pfnProgress == nullptr)
2534 716 : pfnProgress = GDALDummyProgress;
2535 :
2536 1836 : for (int i = 0; i < nOverviews; ++i)
2537 : {
2538 1086 : if (panOverviewList[i] <= 0)
2539 : {
2540 1 : CPLError(CE_Failure, CPLE_IllegalArg,
2541 : "panOverviewList[%d] = %d is invalid. It must be a "
2542 : "positive value",
2543 1 : i, panOverviewList[i]);
2544 1 : CPLFree(panAllBandList);
2545 1 : return CE_Failure;
2546 : }
2547 : }
2548 :
2549 750 : const CPLErr eErr = IBuildOverviews(
2550 : pszResampling, nOverviews, panOverviewList, nListBands, panBandList,
2551 750 : pfnProgress, pProgressData, aosOptions.List());
2552 :
2553 750 : if (panAllBandList != nullptr)
2554 737 : CPLFree(panAllBandList);
2555 :
2556 750 : return eErr;
2557 : }
2558 :
2559 : /************************************************************************/
2560 : /* GDALBuildOverviews() */
2561 : /************************************************************************/
2562 :
2563 : /**
2564 : * \brief Build raster overview(s)
2565 : *
2566 : * @see GDALDataset::BuildOverviews() and GDALBuildOverviews()
2567 : */
2568 :
2569 27 : CPLErr CPL_STDCALL GDALBuildOverviews(GDALDatasetH hDataset,
2570 : const char *pszResampling, int nOverviews,
2571 : const int *panOverviewList,
2572 : int nListBands, const int *panBandList,
2573 : GDALProgressFunc pfnProgress,
2574 : void *pProgressData)
2575 :
2576 : {
2577 27 : VALIDATE_POINTER1(hDataset, "GDALBuildOverviews", CE_Failure);
2578 :
2579 27 : return GDALDataset::FromHandle(hDataset)->BuildOverviews(
2580 : pszResampling, nOverviews, panOverviewList, nListBands, panBandList,
2581 27 : pfnProgress, pProgressData, nullptr);
2582 : }
2583 :
2584 : /************************************************************************/
2585 : /* GDALBuildOverviews() */
2586 : /************************************************************************/
2587 :
2588 : /**
2589 : * \brief Build raster overview(s)
2590 : *
2591 : * @see GDALDataset::BuildOverviews()
2592 : * @since GDAL 3.6
2593 : */
2594 :
2595 : CPLErr CPL_STDCALL
2596 703 : GDALBuildOverviewsEx(GDALDatasetH hDataset, const char *pszResampling,
2597 : int nOverviews, const int *panOverviewList, int nListBands,
2598 : const int *panBandList, GDALProgressFunc pfnProgress,
2599 : void *pProgressData, CSLConstList papszOptions)
2600 :
2601 : {
2602 703 : VALIDATE_POINTER1(hDataset, "GDALBuildOverviews", CE_Failure);
2603 :
2604 703 : return GDALDataset::FromHandle(hDataset)->BuildOverviews(
2605 : pszResampling, nOverviews, panOverviewList, nListBands, panBandList,
2606 703 : pfnProgress, pProgressData, papszOptions);
2607 : }
2608 :
2609 : /************************************************************************/
2610 : /* IBuildOverviews() */
2611 : /* */
2612 : /* Default implementation. */
2613 : /************************************************************************/
2614 :
2615 : //! @cond Doxygen_Suppress
2616 196 : CPLErr GDALDataset::IBuildOverviews(const char *pszResampling, int nOverviews,
2617 : const int *panOverviewList, int nListBands,
2618 : const int *panBandList,
2619 : GDALProgressFunc pfnProgress,
2620 : void *pProgressData,
2621 : CSLConstList papszOptions)
2622 :
2623 : {
2624 196 : if (oOvManager.IsInitialized())
2625 195 : return oOvManager.BuildOverviews(
2626 : nullptr, pszResampling, nOverviews, panOverviewList, nListBands,
2627 195 : panBandList, pfnProgress, pProgressData, papszOptions);
2628 : else
2629 : {
2630 1 : ReportError(CE_Failure, CPLE_NotSupported,
2631 : "BuildOverviews() not supported for this dataset.");
2632 :
2633 1 : return CE_Failure;
2634 : }
2635 : }
2636 :
2637 : //! @endcond
2638 :
2639 : /************************************************************************/
2640 : /* AddOverviews() */
2641 : /* */
2642 : /* Default implementation. */
2643 : /************************************************************************/
2644 :
2645 : /**
2646 : * \brief Add overview from existing dataset(s)
2647 : *
2648 : * This function creates new overview levels or refresh existing one from
2649 : * the list of provided overview datasets.
2650 : * Source overviews may come from any GDAL supported format, provided they
2651 : * have the same number of bands and geospatial extent than the target
2652 : * dataset.
2653 : *
2654 : * If the operation is not supported for the indicated dataset, then
2655 : * CE_Failure is returned, and CPLGetLastErrorNo() will return
2656 : * CPLE_NotSupported.
2657 : *
2658 : * At time of writing, this method is only implemented for internal overviews
2659 : * of GeoTIFF datasets and external overviews in GeoTIFF format.
2660 : *
2661 : * @param apoSrcOvrDS Vector of source overviews.
2662 : * @param pfnProgress a function to call to report progress, or NULL.
2663 : * @param pProgressData application data to pass to the progress function.
2664 : * @param papszOptions NULL terminated list of options as
2665 : * key=value pairs, or NULL. Possible keys are the
2666 : * ones returned by
2667 : * GetDriver()->GetMetadataItem(GDAL_DMD_OVERVIEW_CREATIONOPTIONLIST)
2668 : *
2669 : * @return CE_None on success or CE_Failure if the operation doesn't work.
2670 : * @since 3.12
2671 : */
2672 5 : CPLErr GDALDataset::AddOverviews(const std::vector<GDALDataset *> &apoSrcOvrDS,
2673 : GDALProgressFunc pfnProgress,
2674 : void *pProgressData, CSLConstList papszOptions)
2675 : {
2676 5 : if (oOvManager.IsInitialized())
2677 : {
2678 4 : return oOvManager.AddOverviews(nullptr, apoSrcOvrDS, pfnProgress,
2679 4 : pProgressData, papszOptions);
2680 : }
2681 : else
2682 : {
2683 1 : ReportError(CE_Failure, CPLE_NotSupported,
2684 : "AddOverviews() not supported for this dataset.");
2685 1 : return CE_Failure;
2686 : }
2687 : }
2688 :
2689 : /************************************************************************/
2690 : /* IRasterIO() */
2691 : /* */
2692 : /* The default implementation of IRasterIO() is, in the general */
2693 : /* case to pass the request off to each band objects rasterio */
2694 : /* methods with appropriate arguments. In some cases, it might */
2695 : /* choose instead the BlockBasedRasterIO() implementation. */
2696 : /************************************************************************/
2697 :
2698 : //! @cond Doxygen_Suppress
2699 444919 : CPLErr GDALDataset::IRasterIO(GDALRWFlag eRWFlag, int nXOff, int nYOff,
2700 : int nXSize, int nYSize, void *pData,
2701 : int nBufXSize, int nBufYSize,
2702 : GDALDataType eBufType, int nBandCount,
2703 : BANDMAP_TYPE panBandMap, GSpacing nPixelSpace,
2704 : GSpacing nLineSpace, GSpacing nBandSpace,
2705 : GDALRasterIOExtraArg *psExtraArg)
2706 :
2707 : {
2708 444919 : const char *pszInterleave = nullptr;
2709 :
2710 444919 : CPLAssert(nullptr != pData);
2711 :
2712 444919 : const bool bHasSubpixelShift =
2713 447203 : psExtraArg->bFloatingPointWindowValidity &&
2714 445712 : psExtraArg->eResampleAlg != GRIORA_NearestNeighbour &&
2715 793 : (nXOff != psExtraArg->dfXOff || nYOff != psExtraArg->dfYOff);
2716 :
2717 444803 : if (!bHasSubpixelShift && nXSize == nBufXSize && nYSize == nBufYSize &&
2718 70575 : nBandCount > 1 &&
2719 70575 : (pszInterleave = GetMetadataItem("INTERLEAVE", "IMAGE_STRUCTURE")) !=
2720 889722 : nullptr &&
2721 67483 : EQUAL(pszInterleave, "PIXEL"))
2722 : {
2723 64137 : return BlockBasedRasterIO(eRWFlag, nXOff, nYOff, nXSize, nYSize, pData,
2724 : nBufXSize, nBufYSize, eBufType, nBandCount,
2725 : panBandMap, nPixelSpace, nLineSpace,
2726 64137 : nBandSpace, psExtraArg);
2727 : }
2728 :
2729 380782 : if (eRWFlag == GF_Read &&
2730 201208 : (psExtraArg->eResampleAlg == GRIORA_Cubic ||
2731 200420 : psExtraArg->eResampleAlg == GRIORA_CubicSpline ||
2732 200419 : psExtraArg->eResampleAlg == GRIORA_Bilinear ||
2733 201208 : psExtraArg->eResampleAlg == GRIORA_Lanczos) &&
2734 951 : !(nXSize == nBufXSize && nYSize == nBufYSize) && nBandCount > 1)
2735 : {
2736 930 : if (nBufXSize < nXSize && nBufYSize < nYSize && AreOverviewsEnabled())
2737 : {
2738 719 : int bTried = FALSE;
2739 719 : const CPLErr eErr = TryOverviewRasterIO(
2740 : eRWFlag, nXOff, nYOff, nXSize, nYSize, pData, nBufXSize,
2741 : nBufYSize, eBufType, nBandCount, panBandMap, nPixelSpace,
2742 : nLineSpace, nBandSpace, psExtraArg, &bTried);
2743 719 : if (bTried)
2744 1 : return eErr;
2745 : }
2746 :
2747 929 : GDALDataType eFirstBandDT = GDT_Unknown;
2748 929 : int nFirstMaskFlags = 0;
2749 929 : GDALRasterBand *poFirstMaskBand = nullptr;
2750 929 : int nOKBands = 0;
2751 :
2752 : // Check if bands share the same mask band
2753 2921 : for (int i = 0; i < nBandCount; ++i)
2754 : {
2755 2652 : GDALRasterBand *poBand = GetRasterBand(panBandMap[i]);
2756 4629 : if ((nBufXSize < nXSize || nBufYSize < nYSize) &&
2757 1977 : poBand->GetOverviewCount())
2758 : {
2759 : // Could be improved to select the appropriate overview.
2760 3 : break;
2761 : }
2762 2649 : if (poBand->GetColorTable() != nullptr)
2763 : {
2764 0 : break;
2765 : }
2766 2649 : const GDALDataType eDT = poBand->GetRasterDataType();
2767 2649 : if (GDALDataTypeIsComplex(eDT))
2768 : {
2769 30 : break;
2770 : }
2771 2619 : if (i == 0)
2772 : {
2773 896 : eFirstBandDT = eDT;
2774 896 : nFirstMaskFlags = poBand->GetMaskFlags();
2775 896 : if (nFirstMaskFlags == GMF_NODATA)
2776 : {
2777 : // The dataset-level resampling code is not ready for nodata
2778 : // Fallback to band-level resampling
2779 10 : break;
2780 : }
2781 886 : poFirstMaskBand = poBand->GetMaskBand();
2782 : }
2783 : else
2784 : {
2785 1723 : if (eDT != eFirstBandDT)
2786 : {
2787 0 : break;
2788 : }
2789 1723 : int nMaskFlags = poBand->GetMaskFlags();
2790 1723 : if (nMaskFlags == GMF_NODATA)
2791 : {
2792 : // The dataset-level resampling code is not ready for nodata
2793 : // Fallback to band-level resampling
2794 0 : break;
2795 : }
2796 1723 : GDALRasterBand *poMaskBand = poBand->GetMaskBand();
2797 1723 : if (nFirstMaskFlags == GMF_ALL_VALID &&
2798 : nMaskFlags == GMF_ALL_VALID)
2799 : {
2800 : // Ok.
2801 : }
2802 1077 : else if (poFirstMaskBand == poMaskBand)
2803 : {
2804 : // Ok.
2805 : }
2806 : else
2807 : {
2808 617 : break;
2809 : }
2810 : }
2811 :
2812 1992 : ++nOKBands;
2813 : }
2814 :
2815 929 : GDALProgressFunc pfnProgressGlobal = psExtraArg->pfnProgress;
2816 929 : void *pProgressDataGlobal = psExtraArg->pProgressData;
2817 :
2818 929 : CPLErr eErr = CE_None;
2819 929 : if (nOKBands > 0)
2820 : {
2821 886 : if (nOKBands < nBandCount)
2822 : {
2823 617 : psExtraArg->pfnProgress = GDALScaledProgress;
2824 1234 : psExtraArg->pProgressData = GDALCreateScaledProgress(
2825 617 : 0.0, static_cast<double>(nOKBands) / nBandCount,
2826 : pfnProgressGlobal, pProgressDataGlobal);
2827 617 : if (psExtraArg->pProgressData == nullptr)
2828 228 : psExtraArg->pfnProgress = nullptr;
2829 : }
2830 :
2831 886 : eErr = RasterIOResampled(eRWFlag, nXOff, nYOff, nXSize, nYSize,
2832 : pData, nBufXSize, nBufYSize, eBufType,
2833 : nOKBands, panBandMap, nPixelSpace,
2834 : nLineSpace, nBandSpace, psExtraArg);
2835 :
2836 886 : if (nOKBands < nBandCount)
2837 : {
2838 617 : GDALDestroyScaledProgress(psExtraArg->pProgressData);
2839 : }
2840 : }
2841 929 : if (eErr == CE_None && nOKBands < nBandCount)
2842 : {
2843 657 : if (nOKBands > 0)
2844 : {
2845 614 : psExtraArg->pfnProgress = GDALScaledProgress;
2846 1228 : psExtraArg->pProgressData = GDALCreateScaledProgress(
2847 614 : static_cast<double>(nOKBands) / nBandCount, 1.0,
2848 : pfnProgressGlobal, pProgressDataGlobal);
2849 614 : if (psExtraArg->pProgressData == nullptr)
2850 225 : psExtraArg->pfnProgress = nullptr;
2851 : }
2852 1314 : eErr = BandBasedRasterIO(
2853 : eRWFlag, nXOff, nYOff, nXSize, nYSize,
2854 657 : static_cast<GByte *>(pData) + nBandSpace * nOKBands, nBufXSize,
2855 : nBufYSize, eBufType, nBandCount - nOKBands,
2856 657 : panBandMap + nOKBands, nPixelSpace, nLineSpace, nBandSpace,
2857 : psExtraArg);
2858 657 : if (nOKBands > 0)
2859 : {
2860 614 : GDALDestroyScaledProgress(psExtraArg->pProgressData);
2861 : }
2862 : }
2863 :
2864 929 : psExtraArg->pfnProgress = pfnProgressGlobal;
2865 929 : psExtraArg->pProgressData = pProgressDataGlobal;
2866 :
2867 929 : return eErr;
2868 : }
2869 :
2870 379852 : return BandBasedRasterIO(eRWFlag, nXOff, nYOff, nXSize, nYSize, pData,
2871 : nBufXSize, nBufYSize, eBufType, nBandCount,
2872 : panBandMap, nPixelSpace, nLineSpace, nBandSpace,
2873 379852 : psExtraArg);
2874 : }
2875 :
2876 : //! @endcond
2877 :
2878 : /************************************************************************/
2879 : /* BandBasedRasterIO() */
2880 : /* */
2881 : /* Pass the request off to each band objects rasterio methods with */
2882 : /* appropriate arguments. */
2883 : /************************************************************************/
2884 :
2885 : //! @cond Doxygen_Suppress
2886 654353 : CPLErr GDALDataset::BandBasedRasterIO(
2887 : GDALRWFlag eRWFlag, int nXOff, int nYOff, int nXSize, int nYSize,
2888 : void *pData, int nBufXSize, int nBufYSize, GDALDataType eBufType,
2889 : int nBandCount, const int *panBandMap, GSpacing nPixelSpace,
2890 : GSpacing nLineSpace, GSpacing nBandSpace, GDALRasterIOExtraArg *psExtraArg)
2891 :
2892 : {
2893 : int iBandIndex;
2894 654353 : CPLErr eErr = CE_None;
2895 :
2896 654353 : GDALProgressFunc pfnProgressGlobal = psExtraArg->pfnProgress;
2897 654353 : void *pProgressDataGlobal = psExtraArg->pProgressData;
2898 :
2899 1698490 : for (iBandIndex = 0; iBandIndex < nBandCount && eErr == CE_None;
2900 : ++iBandIndex)
2901 : {
2902 1044140 : GDALRasterBand *poBand = GetRasterBand(panBandMap[iBandIndex]);
2903 :
2904 1044140 : if (poBand == nullptr)
2905 : {
2906 0 : eErr = CE_Failure;
2907 0 : break;
2908 : }
2909 :
2910 1044140 : GByte *pabyBandData =
2911 1044140 : static_cast<GByte *>(pData) + iBandIndex * nBandSpace;
2912 :
2913 1044140 : if (nBandCount > 1)
2914 : {
2915 574511 : psExtraArg->pfnProgress = GDALScaledProgress;
2916 1149020 : psExtraArg->pProgressData = GDALCreateScaledProgress(
2917 : 1.0 * iBandIndex / nBandCount,
2918 574511 : 1.0 * (iBandIndex + 1) / nBandCount, pfnProgressGlobal,
2919 : pProgressDataGlobal);
2920 574511 : if (psExtraArg->pProgressData == nullptr)
2921 571496 : psExtraArg->pfnProgress = nullptr;
2922 : }
2923 :
2924 2088270 : eErr = poBand->IRasterIO(eRWFlag, nXOff, nYOff, nXSize, nYSize,
2925 : pabyBandData, nBufXSize, nBufYSize, eBufType,
2926 1044140 : nPixelSpace, nLineSpace, psExtraArg);
2927 :
2928 1044140 : if (nBandCount > 1)
2929 574511 : GDALDestroyScaledProgress(psExtraArg->pProgressData);
2930 : }
2931 :
2932 654353 : psExtraArg->pfnProgress = pfnProgressGlobal;
2933 654353 : psExtraArg->pProgressData = pProgressDataGlobal;
2934 :
2935 654353 : return eErr;
2936 : }
2937 :
2938 : //! @endcond
2939 :
2940 : /************************************************************************/
2941 : /* ValidateRasterIOOrAdviseReadParameters() */
2942 : /************************************************************************/
2943 :
2944 : //! @cond Doxygen_Suppress
2945 752364 : CPLErr GDALDataset::ValidateRasterIOOrAdviseReadParameters(
2946 : const char *pszCallingFunc, int *pbStopProcessingOnCENone, int nXOff,
2947 : int nYOff, int nXSize, int nYSize, int nBufXSize, int nBufYSize,
2948 : int nBandCount, const int *panBandMap)
2949 : {
2950 :
2951 : /* -------------------------------------------------------------------- */
2952 : /* Some size values are "noop". Lets just return to avoid */
2953 : /* stressing lower level functions. */
2954 : /* -------------------------------------------------------------------- */
2955 752364 : if (nXSize < 1 || nYSize < 1 || nBufXSize < 1 || nBufYSize < 1)
2956 : {
2957 27 : CPLDebug("GDAL",
2958 : "%s skipped for odd window or buffer size.\n"
2959 : " Window = (%d,%d)x%dx%d\n"
2960 : " Buffer = %dx%d",
2961 : pszCallingFunc, nXOff, nYOff, nXSize, nYSize, nBufXSize,
2962 : nBufYSize);
2963 :
2964 27 : *pbStopProcessingOnCENone = TRUE;
2965 27 : return CE_None;
2966 : }
2967 :
2968 752337 : CPLErr eErr = CE_None;
2969 752337 : *pbStopProcessingOnCENone = FALSE;
2970 :
2971 752337 : if (nXOff < 0 || nXSize > nRasterXSize - nXOff || nYOff < 0 ||
2972 752335 : nYSize > nRasterYSize - nYOff)
2973 : {
2974 2 : ReportError(CE_Failure, CPLE_IllegalArg,
2975 : "Access window out of range in %s. Requested "
2976 : "(%d,%d) of size %dx%d on raster of %dx%d.",
2977 : pszCallingFunc, nXOff, nYOff, nXSize, nYSize, nRasterXSize,
2978 : nRasterYSize);
2979 2 : eErr = CE_Failure;
2980 : }
2981 :
2982 752337 : if (panBandMap == nullptr && nBandCount > GetRasterCount())
2983 : {
2984 0 : ReportError(CE_Failure, CPLE_IllegalArg,
2985 : "%s: nBandCount cannot be greater than %d", pszCallingFunc,
2986 : GetRasterCount());
2987 0 : eErr = CE_Failure;
2988 : }
2989 :
2990 2258540 : for (int i = 0; i < nBandCount && eErr == CE_None; ++i)
2991 : {
2992 1506210 : int iBand = (panBandMap != nullptr) ? panBandMap[i] : i + 1;
2993 1506210 : if (iBand < 1 || iBand > GetRasterCount())
2994 : {
2995 3 : ReportError(
2996 : CE_Failure, CPLE_IllegalArg,
2997 : "%s: panBandMap[%d] = %d, this band does not exist on dataset.",
2998 : pszCallingFunc, i, iBand);
2999 3 : eErr = CE_Failure;
3000 : }
3001 :
3002 1506210 : if (eErr == CE_None && GetRasterBand(iBand) == nullptr)
3003 : {
3004 0 : ReportError(
3005 : CE_Failure, CPLE_IllegalArg,
3006 : "%s: panBandMap[%d]=%d, this band should exist but is NULL!",
3007 : pszCallingFunc, i, iBand);
3008 0 : eErr = CE_Failure;
3009 : }
3010 : }
3011 :
3012 752337 : return eErr;
3013 : }
3014 :
3015 : //! @endcond
3016 :
3017 : /************************************************************************/
3018 : /* RasterIO() */
3019 : /************************************************************************/
3020 :
3021 : /**
3022 : * \brief Read/write a region of image data from multiple bands.
3023 : *
3024 : * This method allows reading a region of one or more GDALRasterBands from
3025 : * this dataset into a buffer, or writing data from a buffer into a region
3026 : * of the GDALRasterBands. It automatically takes care of data type
3027 : * translation if the data type (eBufType) of the buffer is different than
3028 : * that of the GDALRasterBand.
3029 : * The method also takes care of image decimation / replication if the
3030 : * buffer size (nBufXSize x nBufYSize) is different than the size of the
3031 : * region being accessed (nXSize x nYSize).
3032 : *
3033 : * The window of interest expressed by (nXOff, nYOff, nXSize, nYSize) should be
3034 : * fully within the raster space, that is nXOff >= 0, nYOff >= 0,
3035 : * nXOff + nXSize <= GetRasterXSize() and nYOff + nYSize <= GetRasterYSize().
3036 : * If reads larger than the raster space are wished, GDALTranslate() might be used.
3037 : * Or use nLineSpace and a possibly shifted pData value.
3038 : *
3039 : * The nPixelSpace, nLineSpace and nBandSpace parameters allow reading into or
3040 : * writing from various organization of buffers.
3041 : *
3042 : * Some formats may efficiently implement decimation into a buffer by
3043 : * reading from lower resolution overview images. The logic of the default
3044 : * implementation in the base class GDALRasterBand is the following one. It
3045 : * computes a target_downscaling_factor from the window of interest and buffer
3046 : * size which is min(nXSize/nBufXSize, nYSize/nBufYSize).
3047 : * It then walks through overviews and will select the first one whose
3048 : * downscaling factor is greater than target_downscaling_factor / 1.2.
3049 : *
3050 : * Let's assume we have overviews at downscaling factors 2, 4 and 8.
3051 : * The relationship between target_downscaling_factor and the select overview
3052 : * level is the following one:
3053 : *
3054 : * target_downscaling_factor | selected_overview
3055 : * ------------------------- | -----------------
3056 : * ]0, 2 / 1.2] | full resolution band
3057 : * ]2 / 1.2, 4 / 1.2] | 2x downsampled band
3058 : * ]4 / 1.2, 8 / 1.2] | 4x downsampled band
3059 : * ]8 / 1.2, infinity[ | 8x downsampled band
3060 : *
3061 : * Note that starting with GDAL 3.9, this 1.2 oversampling factor can be
3062 : * modified by setting the GDAL_OVERVIEW_OVERSAMPLING_THRESHOLD configuration
3063 : * option. Also note that starting with GDAL 3.9, when the resampling algorithm
3064 : * specified in psExtraArg->eResampleAlg is different from GRIORA_NearestNeighbour,
3065 : * this oversampling threshold defaults to 1. Consequently if there are overviews
3066 : * of downscaling factor 2, 4 and 8, and the desired downscaling factor is
3067 : * 7.99, the overview of factor 4 will be selected for a non nearest resampling.
3068 : *
3069 : * For highest performance full resolution data access, read and write
3070 : * on "block boundaries" as returned by GetBlockSize(), or use the
3071 : * ReadBlock() and WriteBlock() methods.
3072 : *
3073 : * This method is the same as the C GDALDatasetRasterIO() or
3074 : * GDALDatasetRasterIOEx() functions.
3075 : *
3076 : * @param eRWFlag Either GF_Read to read a region of data, or GF_Write to
3077 : * write a region of data.
3078 : *
3079 : * @param nXOff The pixel offset to the top left corner of the region
3080 : * of the band to be accessed. This would be zero to start from the left side.
3081 : *
3082 : * @param nYOff The line offset to the top left corner of the region
3083 : * of the band to be accessed. This would be zero to start from the top.
3084 : *
3085 : * @param nXSize The width of the region of the band to be accessed in pixels.
3086 : *
3087 : * @param nYSize The height of the region of the band to be accessed in lines.
3088 : *
3089 : * @param pData The buffer into which the data should be read, or from which
3090 : * it should be written. This buffer must contain at least
3091 : * nBufXSize * nBufYSize * nBandCount words of type eBufType. It is organized
3092 : * in left to right,top to bottom pixel order. Spacing is controlled by the
3093 : * nPixelSpace, and nLineSpace parameters.
3094 : * Note that even with eRWFlag==GF_Write, the content of the buffer might be
3095 : * temporarily modified during the execution of this method (and eventually
3096 : * restored back to its original content), so it is not safe to use a buffer
3097 : * stored in a read-only section of the calling program.
3098 : *
3099 : * @param nBufXSize the width of the buffer image into which the desired region
3100 : * is to be read, or from which it is to be written.
3101 : *
3102 : * @param nBufYSize the height of the buffer image into which the desired
3103 : * region is to be read, or from which it is to be written.
3104 : *
3105 : * @param eBufType the type of the pixel values in the pData data buffer. The
3106 : * pixel values will automatically be translated to/from the GDALRasterBand
3107 : * data type as needed. Most driver implementations will use GDALCopyWords64()
3108 : * to perform data type translation.
3109 : *
3110 : * @param nBandCount the number of bands being read or written.
3111 : *
3112 : * @param panBandMap the list of nBandCount band numbers being read/written.
3113 : * Note band numbers are 1 based. This may be NULL to select the first
3114 : * nBandCount bands. (Note: before GDAL 3.10, argument type was "int*", and
3115 : * not "const int*")
3116 : *
3117 : * @param nPixelSpace The byte offset from the start of one pixel value in
3118 : * pData to the start of the next pixel value within a scanline. If defaulted
3119 : * (0) the size of the datatype eBufType is used.
3120 : *
3121 : * @param nLineSpace The byte offset from the start of one scanline in
3122 : * pData to the start of the next. If defaulted (0) the size of the datatype
3123 : * eBufType * nBufXSize is used.
3124 : *
3125 : * @param nBandSpace the byte offset from the start of one bands data to the
3126 : * start of the next. If defaulted (0) the value will be
3127 : * nLineSpace * nBufYSize implying band sequential organization
3128 : * of the data buffer.
3129 : *
3130 : * @param psExtraArg pointer to a GDALRasterIOExtraArg
3131 : * structure with additional arguments to specify resampling and progress
3132 : * callback, or NULL for default behavior. The GDAL_RASTERIO_RESAMPLING
3133 : * configuration option can also be defined to override the default resampling
3134 : * to one of BILINEAR, CUBIC, CUBICSPLINE, LANCZOS, AVERAGE or MODE.
3135 : *
3136 : * @return CE_Failure if the access fails, otherwise CE_None.
3137 : */
3138 :
3139 737024 : CPLErr GDALDataset::RasterIO(GDALRWFlag eRWFlag, int nXOff, int nYOff,
3140 : int nXSize, int nYSize, void *pData, int nBufXSize,
3141 : int nBufYSize, GDALDataType eBufType,
3142 : int nBandCount, const int *panBandMap,
3143 : GSpacing nPixelSpace, GSpacing nLineSpace,
3144 : GSpacing nBandSpace,
3145 : GDALRasterIOExtraArg *psExtraArg)
3146 :
3147 : {
3148 : GDALRasterIOExtraArg sExtraArg;
3149 737024 : if (psExtraArg == nullptr)
3150 : {
3151 542380 : INIT_RASTERIO_EXTRA_ARG(sExtraArg);
3152 :
3153 : // 4 below inits are not strictly needed but make Coverity Scan
3154 : // happy
3155 542380 : sExtraArg.dfXOff = nXOff;
3156 542380 : sExtraArg.dfYOff = nYOff;
3157 542380 : sExtraArg.dfXSize = nXSize;
3158 542380 : sExtraArg.dfYSize = nYSize;
3159 :
3160 542380 : psExtraArg = &sExtraArg;
3161 : }
3162 194644 : else if (CPL_UNLIKELY(psExtraArg->nVersion >
3163 : RASTERIO_EXTRA_ARG_CURRENT_VERSION))
3164 : {
3165 0 : ReportError(CE_Failure, CPLE_AppDefined,
3166 : "Unhandled version of GDALRasterIOExtraArg");
3167 0 : return CE_Failure;
3168 : }
3169 :
3170 737024 : GDALRasterIOExtraArgSetResampleAlg(psExtraArg, nXSize, nYSize, nBufXSize,
3171 : nBufYSize);
3172 :
3173 737024 : if (CPL_UNLIKELY(nullptr == pData))
3174 : {
3175 0 : ReportError(CE_Failure, CPLE_AppDefined,
3176 : "The buffer into which the data should be read is null");
3177 0 : return CE_Failure;
3178 : }
3179 :
3180 : /* -------------------------------------------------------------------- */
3181 : /* Do some validation of parameters. */
3182 : /* -------------------------------------------------------------------- */
3183 :
3184 737024 : if (CPL_UNLIKELY(eRWFlag != GF_Read && eRWFlag != GF_Write))
3185 : {
3186 0 : ReportError(
3187 : CE_Failure, CPLE_IllegalArg,
3188 : "eRWFlag = %d, only GF_Read (0) and GF_Write (1) are legal.",
3189 : eRWFlag);
3190 0 : return CE_Failure;
3191 : }
3192 :
3193 737024 : if (eRWFlag == GF_Write)
3194 : {
3195 216662 : if (CPL_UNLIKELY(eAccess != GA_Update))
3196 : {
3197 2 : ReportError(CE_Failure, CPLE_AppDefined,
3198 : "Write operation not permitted on dataset opened "
3199 : "in read-only mode");
3200 2 : return CE_Failure;
3201 : }
3202 : }
3203 :
3204 737022 : int bStopProcessing = FALSE;
3205 737022 : CPLErr eErr = ValidateRasterIOOrAdviseReadParameters(
3206 : "RasterIO()", &bStopProcessing, nXOff, nYOff, nXSize, nYSize, nBufXSize,
3207 : nBufYSize, nBandCount, panBandMap);
3208 737022 : if (eErr != CE_None || bStopProcessing)
3209 9 : return eErr;
3210 737013 : if (CPL_UNLIKELY(eBufType == GDT_Unknown || eBufType == GDT_TypeCount))
3211 : {
3212 2 : ReportError(CE_Failure, CPLE_AppDefined,
3213 : "Illegal GDT_Unknown/GDT_TypeCount argument");
3214 2 : return CE_Failure;
3215 : }
3216 :
3217 : /* -------------------------------------------------------------------- */
3218 : /* If pixel and line spacing are defaulted assign reasonable */
3219 : /* value assuming a packed buffer. */
3220 : /* -------------------------------------------------------------------- */
3221 737011 : if (nPixelSpace == 0)
3222 425024 : nPixelSpace = GDALGetDataTypeSizeBytes(eBufType);
3223 :
3224 737011 : if (nLineSpace == 0)
3225 : {
3226 482340 : nLineSpace = nPixelSpace * nBufXSize;
3227 : }
3228 :
3229 737011 : if (nBandSpace == 0 && nBandCount > 1)
3230 : {
3231 67465 : nBandSpace = nLineSpace * nBufYSize;
3232 : }
3233 :
3234 737011 : if (panBandMap == nullptr)
3235 : {
3236 360317 : if (!m_poPrivate)
3237 0 : return CE_Failure;
3238 360317 : CPLAssert(static_cast<int>(m_poPrivate->m_anBandMap.size()) == nBands);
3239 360317 : panBandMap = m_poPrivate->m_anBandMap.data();
3240 : }
3241 :
3242 737011 : int bCallLeaveReadWrite = EnterReadWrite(eRWFlag);
3243 :
3244 : /* -------------------------------------------------------------------- */
3245 : /* We are being forced to use cached IO instead of a driver */
3246 : /* specific implementation. */
3247 : /* -------------------------------------------------------------------- */
3248 737011 : if (bForceCachedIO)
3249 : {
3250 21 : eErr = BlockBasedRasterIO(eRWFlag, nXOff, nYOff, nXSize, nYSize, pData,
3251 : nBufXSize, nBufYSize, eBufType, nBandCount,
3252 : panBandMap, nPixelSpace, nLineSpace,
3253 21 : nBandSpace, psExtraArg);
3254 : }
3255 :
3256 : /* -------------------------------------------------------------------- */
3257 : /* Call the format specific function. */
3258 : /* -------------------------------------------------------------------- */
3259 : else
3260 : {
3261 736990 : eErr = IRasterIO(eRWFlag, nXOff, nYOff, nXSize, nYSize, pData,
3262 : nBufXSize, nBufYSize, eBufType, nBandCount,
3263 : // TODO: remove this const_cast once IRasterIO()
3264 : // takes a const int*
3265 : const_cast<int *>(panBandMap), nPixelSpace, nLineSpace,
3266 736990 : nBandSpace, psExtraArg);
3267 : }
3268 :
3269 737011 : if (bCallLeaveReadWrite)
3270 407729 : LeaveReadWrite();
3271 :
3272 737011 : return eErr;
3273 : }
3274 :
3275 : /************************************************************************/
3276 : /* GDALDatasetRasterIO() */
3277 : /************************************************************************/
3278 :
3279 : /**
3280 : * \brief Read/write a region of image data from multiple bands.
3281 : *
3282 : * Use GDALDatasetRasterIOEx() if 64 bit spacings or extra arguments (resampling
3283 : * resolution, progress callback, etc. are needed)
3284 : *
3285 : * Note: before GDAL 3.10, panBandMap type was "int*", and not "const int*"
3286 : *
3287 : * @see GDALDataset::RasterIO()
3288 : */
3289 :
3290 4762 : CPLErr CPL_STDCALL GDALDatasetRasterIO(GDALDatasetH hDS, GDALRWFlag eRWFlag,
3291 : int nXOff, int nYOff, int nXSize,
3292 : int nYSize, void *pData, int nBufXSize,
3293 : int nBufYSize, GDALDataType eBufType,
3294 : int nBandCount, const int *panBandMap,
3295 : int nPixelSpace, int nLineSpace,
3296 : int nBandSpace)
3297 :
3298 : {
3299 4762 : VALIDATE_POINTER1(hDS, "GDALDatasetRasterIO", CE_Failure);
3300 :
3301 4762 : GDALDataset *poDS = GDALDataset::FromHandle(hDS);
3302 :
3303 4762 : return poDS->RasterIO(eRWFlag, nXOff, nYOff, nXSize, nYSize, pData,
3304 : nBufXSize, nBufYSize, eBufType, nBandCount,
3305 : panBandMap, nPixelSpace, nLineSpace, nBandSpace,
3306 4762 : nullptr);
3307 : }
3308 :
3309 : /************************************************************************/
3310 : /* GDALDatasetRasterIOEx() */
3311 : /************************************************************************/
3312 :
3313 : /**
3314 : * \brief Read/write a region of image data from multiple bands.
3315 : *
3316 : * Note: before GDAL 3.10, panBandMap type was "int*", and not "const int*"
3317 : *
3318 : * @see GDALDataset::RasterIO()
3319 : */
3320 :
3321 353788 : CPLErr CPL_STDCALL GDALDatasetRasterIOEx(
3322 : GDALDatasetH hDS, GDALRWFlag eRWFlag, int nXOff, int nYOff, int nXSize,
3323 : int nYSize, void *pData, int nBufXSize, int nBufYSize,
3324 : GDALDataType eBufType, int nBandCount, const int *panBandMap,
3325 : GSpacing nPixelSpace, GSpacing nLineSpace, GSpacing nBandSpace,
3326 : GDALRasterIOExtraArg *psExtraArg)
3327 :
3328 : {
3329 353788 : VALIDATE_POINTER1(hDS, "GDALDatasetRasterIOEx", CE_Failure);
3330 :
3331 353788 : GDALDataset *poDS = GDALDataset::FromHandle(hDS);
3332 :
3333 353788 : return poDS->RasterIO(eRWFlag, nXOff, nYOff, nXSize, nYSize, pData,
3334 : nBufXSize, nBufYSize, eBufType, nBandCount,
3335 : panBandMap, nPixelSpace, nLineSpace, nBandSpace,
3336 353788 : psExtraArg);
3337 : }
3338 :
3339 : /************************************************************************/
3340 : /* GetOpenDatasets() */
3341 : /************************************************************************/
3342 :
3343 : /**
3344 : * \brief Fetch all open GDAL dataset handles.
3345 : *
3346 : * This method is the same as the C function GDALGetOpenDatasets().
3347 : *
3348 : * NOTE: This method is not thread safe. The returned list may change
3349 : * at any time and it should not be freed.
3350 : *
3351 : * @param pnCount integer into which to place the count of dataset pointers
3352 : * being returned.
3353 : *
3354 : * @return a pointer to an array of dataset handles.
3355 : */
3356 :
3357 2267 : GDALDataset **GDALDataset::GetOpenDatasets(int *pnCount)
3358 :
3359 : {
3360 4534 : CPLMutexHolderD(&hDLMutex);
3361 :
3362 2267 : if (poAllDatasetMap == nullptr)
3363 : {
3364 2246 : *pnCount = 0;
3365 2246 : return nullptr;
3366 : }
3367 :
3368 21 : *pnCount = static_cast<int>(poAllDatasetMap->size());
3369 21 : ppDatasets = static_cast<GDALDataset **>(
3370 21 : CPLRealloc(ppDatasets, (*pnCount) * sizeof(GDALDataset *)));
3371 21 : std::map<GDALDataset *, GIntBig>::iterator oIter = poAllDatasetMap->begin();
3372 595 : for (int i = 0; oIter != poAllDatasetMap->end(); ++oIter, ++i)
3373 574 : ppDatasets[i] = oIter->first;
3374 21 : return ppDatasets;
3375 : }
3376 :
3377 : /************************************************************************/
3378 : /* GDALGetOpenDatasets() */
3379 : /************************************************************************/
3380 :
3381 : /**
3382 : * \brief Fetch all open GDAL dataset handles.
3383 : *
3384 : * @see GDALDataset::GetOpenDatasets()
3385 : */
3386 :
3387 0 : void CPL_STDCALL GDALGetOpenDatasets(GDALDatasetH **ppahDSList, int *pnCount)
3388 :
3389 : {
3390 0 : VALIDATE_POINTER0(ppahDSList, "GDALGetOpenDatasets");
3391 0 : VALIDATE_POINTER0(pnCount, "GDALGetOpenDatasets");
3392 :
3393 0 : *ppahDSList =
3394 0 : reinterpret_cast<GDALDatasetH *>(GDALDataset::GetOpenDatasets(pnCount));
3395 : }
3396 :
3397 : /************************************************************************/
3398 : /* GDALCleanOpenDatasetsList() */
3399 : /************************************************************************/
3400 :
3401 : // Useful when called from the child of a fork(), to avoid closing
3402 : // the datasets of the parent at the child termination.
3403 0 : void GDALNullifyOpenDatasetsList()
3404 : {
3405 0 : poAllDatasetMap = nullptr;
3406 0 : phSharedDatasetSet = nullptr;
3407 0 : ppDatasets = nullptr;
3408 0 : hDLMutex = nullptr;
3409 0 : }
3410 :
3411 : /************************************************************************/
3412 : /* GDALGetAccess() */
3413 : /************************************************************************/
3414 :
3415 : /**
3416 : * \brief Return access flag
3417 : *
3418 : * @see GDALDataset::GetAccess()
3419 : */
3420 :
3421 0 : int CPL_STDCALL GDALGetAccess(GDALDatasetH hDS)
3422 : {
3423 0 : VALIDATE_POINTER1(hDS, "GDALGetAccess", 0);
3424 :
3425 0 : return GDALDataset::FromHandle(hDS)->GetAccess();
3426 : }
3427 :
3428 : /************************************************************************/
3429 : /* AdviseRead() */
3430 : /************************************************************************/
3431 :
3432 : /**
3433 : * \brief Advise driver of upcoming read requests.
3434 : *
3435 : * Some GDAL drivers operate more efficiently if they know in advance what
3436 : * set of upcoming read requests will be made. The AdviseRead() method allows
3437 : * an application to notify the driver of the region and bands of interest,
3438 : * and at what resolution the region will be read.
3439 : *
3440 : * Many drivers just ignore the AdviseRead() call, but it can dramatically
3441 : * accelerate access via some drivers.
3442 : *
3443 : * Depending on call paths, drivers might receive several calls to
3444 : * AdviseRead() with the same parameters.
3445 : *
3446 : * @param nXOff The pixel offset to the top left corner of the region
3447 : * of the band to be accessed. This would be zero to start from the left side.
3448 : *
3449 : * @param nYOff The line offset to the top left corner of the region
3450 : * of the band to be accessed. This would be zero to start from the top.
3451 : *
3452 : * @param nXSize The width of the region of the band to be accessed in pixels.
3453 : *
3454 : * @param nYSize The height of the region of the band to be accessed in lines.
3455 : *
3456 : * @param nBufXSize the width of the buffer image into which the desired region
3457 : * is to be read, or from which it is to be written.
3458 : *
3459 : * @param nBufYSize the height of the buffer image into which the desired
3460 : * region is to be read, or from which it is to be written.
3461 : *
3462 : * @param eBufType the type of the pixel values in the pData data buffer. The
3463 : * pixel values will automatically be translated to/from the GDALRasterBand
3464 : * data type as needed.
3465 : *
3466 : * @param nBandCount the number of bands being read or written.
3467 : *
3468 : * @param panBandMap the list of nBandCount band numbers being read/written.
3469 : * Note band numbers are 1 based. This may be NULL to select the first
3470 : * nBandCount bands.
3471 : *
3472 : * @param papszOptions a list of name=value strings with special control
3473 : * options. Normally this is NULL.
3474 : *
3475 : * @return CE_Failure if the request is invalid and CE_None if it works or
3476 : * is ignored.
3477 : */
3478 :
3479 15093 : CPLErr GDALDataset::AdviseRead(int nXOff, int nYOff, int nXSize, int nYSize,
3480 : int nBufXSize, int nBufYSize,
3481 : GDALDataType eBufType, int nBandCount,
3482 : int *panBandMap, CSLConstList papszOptions)
3483 :
3484 : {
3485 : /* -------------------------------------------------------------------- */
3486 : /* Do some validation of parameters. */
3487 : /* -------------------------------------------------------------------- */
3488 15093 : int bStopProcessing = FALSE;
3489 15093 : CPLErr eErr = ValidateRasterIOOrAdviseReadParameters(
3490 : "AdviseRead()", &bStopProcessing, nXOff, nYOff, nXSize, nYSize,
3491 : nBufXSize, nBufYSize, nBandCount, panBandMap);
3492 15093 : if (eErr != CE_None || bStopProcessing)
3493 23 : return eErr;
3494 :
3495 129489 : for (int iBand = 0; iBand < nBandCount; ++iBand)
3496 : {
3497 114419 : GDALRasterBand *poBand = nullptr;
3498 :
3499 114419 : if (panBandMap == nullptr)
3500 112895 : poBand = GetRasterBand(iBand + 1);
3501 : else
3502 1524 : poBand = GetRasterBand(panBandMap[iBand]);
3503 :
3504 114419 : if (poBand == nullptr)
3505 0 : return CE_Failure;
3506 :
3507 228838 : eErr = poBand->AdviseRead(nXOff, nYOff, nXSize, nYSize, nBufXSize,
3508 114419 : nBufYSize, eBufType, papszOptions);
3509 :
3510 114419 : if (eErr != CE_None)
3511 0 : return eErr;
3512 : }
3513 :
3514 15070 : return CE_None;
3515 : }
3516 :
3517 : /************************************************************************/
3518 : /* GDALDatasetAdviseRead() */
3519 : /************************************************************************/
3520 :
3521 : /**
3522 : * \brief Advise driver of upcoming read requests.
3523 : *
3524 : * @see GDALDataset::AdviseRead()
3525 : */
3526 1 : CPLErr CPL_STDCALL GDALDatasetAdviseRead(GDALDatasetH hDS, int nXOff, int nYOff,
3527 : int nXSize, int nYSize, int nBufXSize,
3528 : int nBufYSize, GDALDataType eDT,
3529 : int nBandCount, int *panBandMap,
3530 : CSLConstList papszOptions)
3531 :
3532 : {
3533 1 : VALIDATE_POINTER1(hDS, "GDALDatasetAdviseRead", CE_Failure);
3534 :
3535 2 : return GDALDataset::FromHandle(hDS)->AdviseRead(
3536 : nXOff, nYOff, nXSize, nYSize, nBufXSize, nBufYSize, eDT, nBandCount,
3537 1 : panBandMap, const_cast<char **>(papszOptions));
3538 : }
3539 :
3540 : /************************************************************************/
3541 : /* GDALAntiRecursionStruct */
3542 : /************************************************************************/
3543 :
3544 : // Prevent infinite recursion.
3545 : struct GDALAntiRecursionStruct
3546 : {
3547 : struct DatasetContext
3548 : {
3549 : std::string osFilename;
3550 : int nOpenFlags;
3551 : std::string osAllowedDrivers;
3552 :
3553 86499 : DatasetContext(const std::string &osFilenameIn, int nOpenFlagsIn,
3554 : const std::string &osAllowedDriversIn)
3555 86499 : : osFilename(osFilenameIn), nOpenFlags(nOpenFlagsIn),
3556 86499 : osAllowedDrivers(osAllowedDriversIn)
3557 : {
3558 86499 : }
3559 : };
3560 :
3561 : struct DatasetContextCompare
3562 : {
3563 1040560 : bool operator()(const DatasetContext &lhs,
3564 : const DatasetContext &rhs) const
3565 : {
3566 3046310 : return lhs.osFilename < rhs.osFilename ||
3567 1009700 : (lhs.osFilename == rhs.osFilename &&
3568 996055 : (lhs.nOpenFlags < rhs.nOpenFlags ||
3569 1975760 : (lhs.nOpenFlags == rhs.nOpenFlags &&
3570 2026390 : lhs.osAllowedDrivers < rhs.osAllowedDrivers)));
3571 : }
3572 : };
3573 :
3574 1359 : ~GDALAntiRecursionStruct()
3575 1359 : {
3576 1359 : CPLAssert(aosDatasetNamesWithFlags.empty());
3577 1359 : CPLAssert(nRecLevel == 0);
3578 1359 : CPLAssert(m_oMapDepth.empty());
3579 1359 : }
3580 :
3581 : std::set<DatasetContext, DatasetContextCompare> aosDatasetNamesWithFlags{};
3582 : int nRecLevel = 0;
3583 : std::map<std::string, int> m_oMapDepth{};
3584 : };
3585 :
3586 : #ifdef _WIN32
3587 : // Currently thread_local and C++ objects don't work well with DLL on Windows
3588 : static void FreeAntiRecursionOpen(void *pData)
3589 : {
3590 : delete static_cast<GDALAntiRecursionStruct *>(pData);
3591 : }
3592 :
3593 : static GDALAntiRecursionStruct &GetAntiRecursionOpen()
3594 : {
3595 : static GDALAntiRecursionStruct dummy;
3596 : int bMemoryErrorOccurred = false;
3597 : void *pData =
3598 : CPLGetTLSEx(CTLS_GDALOPEN_ANTIRECURSION, &bMemoryErrorOccurred);
3599 : if (bMemoryErrorOccurred)
3600 : {
3601 : return dummy;
3602 : }
3603 : if (pData == nullptr)
3604 : {
3605 : auto pAntiRecursion = new GDALAntiRecursionStruct();
3606 : CPLSetTLSWithFreeFuncEx(CTLS_GDALOPEN_ANTIRECURSION, pAntiRecursion,
3607 : FreeAntiRecursionOpen, &bMemoryErrorOccurred);
3608 : if (bMemoryErrorOccurred)
3609 : {
3610 : delete pAntiRecursion;
3611 : return dummy;
3612 : }
3613 : return *pAntiRecursion;
3614 : }
3615 : return *static_cast<GDALAntiRecursionStruct *>(pData);
3616 : }
3617 : #else
3618 : static thread_local GDALAntiRecursionStruct g_tls_antiRecursion;
3619 :
3620 351391 : static GDALAntiRecursionStruct &GetAntiRecursionOpen()
3621 : {
3622 351391 : return g_tls_antiRecursion;
3623 : }
3624 : #endif
3625 :
3626 : //! @cond Doxygen_Suppress
3627 264892 : GDALAntiRecursionGuard::GDALAntiRecursionGuard(const std::string &osIdentifier)
3628 264892 : : m_psAntiRecursionStruct(&GetAntiRecursionOpen()),
3629 : m_osIdentifier(osIdentifier),
3630 264892 : m_nDepth(++m_psAntiRecursionStruct->m_oMapDepth[m_osIdentifier])
3631 : {
3632 264892 : CPLAssert(!osIdentifier.empty());
3633 264892 : }
3634 :
3635 264892 : GDALAntiRecursionGuard::GDALAntiRecursionGuard(
3636 264892 : const GDALAntiRecursionGuard &other, const std::string &osIdentifier)
3637 264892 : : m_psAntiRecursionStruct(other.m_psAntiRecursionStruct),
3638 264892 : m_osIdentifier(osIdentifier.empty()
3639 : ? osIdentifier
3640 30560 : : other.m_osIdentifier + osIdentifier),
3641 264892 : m_nDepth(m_osIdentifier.empty()
3642 264892 : ? 0
3643 295452 : : ++m_psAntiRecursionStruct->m_oMapDepth[m_osIdentifier])
3644 : {
3645 264892 : }
3646 :
3647 529784 : GDALAntiRecursionGuard::~GDALAntiRecursionGuard()
3648 : {
3649 529784 : if (!m_osIdentifier.empty())
3650 : {
3651 295452 : auto oIter = m_psAntiRecursionStruct->m_oMapDepth.find(m_osIdentifier);
3652 295452 : CPLAssert(oIter != m_psAntiRecursionStruct->m_oMapDepth.end());
3653 295452 : if (--(oIter->second) == 0)
3654 290995 : m_psAntiRecursionStruct->m_oMapDepth.erase(oIter);
3655 : }
3656 529784 : }
3657 :
3658 : //! @endcond
3659 :
3660 : /************************************************************************/
3661 : /* GetFileList() */
3662 : /************************************************************************/
3663 :
3664 : /**
3665 : * \brief Fetch files forming dataset.
3666 : *
3667 : * Returns a list of files believed to be part of this dataset. If it returns
3668 : * an empty list of files it means there is believed to be no local file
3669 : * system files associated with the dataset (for instance a virtual dataset).
3670 : * The returned file list is owned by the caller and should be deallocated
3671 : * with CSLDestroy().
3672 : *
3673 : * The returned filenames will normally be relative or absolute paths
3674 : * depending on the path used to originally open the dataset. The strings
3675 : * will be UTF-8 encoded.
3676 : *
3677 : * This method is the same as the C GDALGetFileList() function.
3678 : *
3679 : * @return NULL or a NULL terminated array of file names.
3680 : */
3681 :
3682 4693 : char **GDALDataset::GetFileList()
3683 :
3684 : {
3685 9386 : CPLString osMainFilename = GetDescription();
3686 : VSIStatBufL sStat;
3687 :
3688 4693 : GDALAntiRecursionStruct &sAntiRecursion = GetAntiRecursionOpen();
3689 : GDALAntiRecursionStruct::DatasetContext datasetCtxt(osMainFilename, 0,
3690 9386 : std::string());
3691 4693 : auto &aosDatasetList = sAntiRecursion.aosDatasetNamesWithFlags;
3692 4693 : if (cpl::contains(aosDatasetList, datasetCtxt))
3693 0 : return nullptr;
3694 :
3695 : /* -------------------------------------------------------------------- */
3696 : /* Is the main filename even a real filesystem object? */
3697 : /* -------------------------------------------------------------------- */
3698 : int bMainFileReal =
3699 4693 : VSIStatExL(osMainFilename, &sStat, VSI_STAT_EXISTS_FLAG) == 0;
3700 :
3701 : /* -------------------------------------------------------------------- */
3702 : /* Form new list. */
3703 : /* -------------------------------------------------------------------- */
3704 4693 : char **papszList = nullptr;
3705 :
3706 4693 : if (bMainFileReal)
3707 4613 : papszList = CSLAddString(papszList, osMainFilename);
3708 :
3709 4693 : if (sAntiRecursion.nRecLevel == 100)
3710 : {
3711 0 : CPLError(CE_Failure, CPLE_AppDefined,
3712 : "GetFileList() called with too many recursion levels");
3713 0 : return papszList;
3714 : }
3715 4693 : ++sAntiRecursion.nRecLevel;
3716 :
3717 : /* -------------------------------------------------------------------- */
3718 : /* Do we have a known overview file? */
3719 : /* -------------------------------------------------------------------- */
3720 4693 : if (oOvManager.IsInitialized() && oOvManager.poODS != nullptr)
3721 : {
3722 60 : auto iter = aosDatasetList.insert(datasetCtxt).first;
3723 60 : char **papszOvrList = oOvManager.poODS->GetFileList();
3724 60 : papszList = CSLInsertStrings(papszList, -1, papszOvrList);
3725 60 : CSLDestroy(papszOvrList);
3726 60 : aosDatasetList.erase(iter);
3727 : }
3728 :
3729 : /* -------------------------------------------------------------------- */
3730 : /* Do we have a known mask file? */
3731 : /* -------------------------------------------------------------------- */
3732 4693 : if (oOvManager.HaveMaskFile())
3733 : {
3734 9 : auto iter = aosDatasetList.insert(std::move(datasetCtxt)).first;
3735 9 : for (const char *pszFile :
3736 18 : CPLStringList(oOvManager.poMaskDS->GetFileList()))
3737 : {
3738 9 : if (CSLFindString(papszList, pszFile) < 0)
3739 9 : papszList = CSLAddString(papszList, pszFile);
3740 : }
3741 9 : aosDatasetList.erase(iter);
3742 : }
3743 :
3744 4693 : --sAntiRecursion.nRecLevel;
3745 :
3746 4693 : return papszList;
3747 : }
3748 :
3749 : /************************************************************************/
3750 : /* GDALGetFileList() */
3751 : /************************************************************************/
3752 :
3753 : /**
3754 : * \brief Fetch files forming dataset.
3755 : *
3756 : * @see GDALDataset::GetFileList()
3757 : */
3758 :
3759 3877 : char **CPL_STDCALL GDALGetFileList(GDALDatasetH hDS)
3760 :
3761 : {
3762 3877 : VALIDATE_POINTER1(hDS, "GDALGetFileList", nullptr);
3763 :
3764 3877 : return GDALDataset::FromHandle(hDS)->GetFileList();
3765 : }
3766 :
3767 : /************************************************************************/
3768 : /* CreateMaskBand() */
3769 : /************************************************************************/
3770 :
3771 : /**
3772 : * \brief Adds a mask band to the dataset
3773 : *
3774 : * The default implementation of the CreateMaskBand() method is implemented
3775 : * based on similar rules to the .ovr handling implemented using the
3776 : * GDALDefaultOverviews object. A TIFF file with the extension .msk will
3777 : * be created with the same basename as the original file, and it will have
3778 : * one band.
3779 : * The mask images will be deflate compressed tiled images with the same
3780 : * block size as the original image if possible.
3781 : * It will have INTERNAL_MASK_FLAGS_xx metadata items set at the dataset
3782 : * level, where xx matches the band number of a band of the main dataset. The
3783 : * value of those items will be the one of the nFlagsIn parameter.
3784 : *
3785 : * Note that if you got a mask band with a previous call to GetMaskBand(), it
3786 : * might be invalidated by CreateMaskBand(). So you have to call GetMaskBand()
3787 : * again.
3788 : *
3789 : *
3790 : * @param nFlagsIn 0 or combination of GMF_PER_DATASET / GMF_ALPHA.
3791 : * GMF_PER_DATASET will be always set, even if not explicitly
3792 : * specified.
3793 : * @return CE_None on success or CE_Failure on an error.
3794 : *
3795 : * @see https://gdal.org/development/rfc/rfc15_nodatabitmask.html
3796 : * @see GDALRasterBand::CreateMaskBand()
3797 : *
3798 : */
3799 17 : CPLErr GDALDataset::CreateMaskBand(int nFlagsIn)
3800 :
3801 : {
3802 17 : if (oOvManager.IsInitialized())
3803 : {
3804 17 : CPLErr eErr = oOvManager.CreateMaskBand(nFlagsIn, -1);
3805 17 : if (eErr != CE_None)
3806 0 : return eErr;
3807 :
3808 : // Invalidate existing raster band masks.
3809 45 : for (int i = 0; i < nBands; ++i)
3810 : {
3811 28 : GDALRasterBand *poBand = papoBands[i];
3812 28 : poBand->poMask.reset();
3813 : }
3814 :
3815 17 : return CE_None;
3816 : }
3817 :
3818 0 : ReportError(CE_Failure, CPLE_NotSupported,
3819 : "CreateMaskBand() not supported for this dataset.");
3820 :
3821 0 : return CE_Failure;
3822 : }
3823 :
3824 : /************************************************************************/
3825 : /* GDALCreateDatasetMaskBand() */
3826 : /************************************************************************/
3827 :
3828 : /**
3829 : * \brief Adds a mask band to the dataset
3830 : * @see GDALDataset::CreateMaskBand()
3831 : */
3832 107 : CPLErr CPL_STDCALL GDALCreateDatasetMaskBand(GDALDatasetH hDS, int nFlags)
3833 :
3834 : {
3835 107 : VALIDATE_POINTER1(hDS, "GDALCreateDatasetMaskBand", CE_Failure);
3836 :
3837 107 : return GDALDataset::FromHandle(hDS)->CreateMaskBand(nFlags);
3838 : }
3839 :
3840 : /************************************************************************/
3841 : /* GDALOpen() */
3842 : /************************************************************************/
3843 :
3844 : /**
3845 : * \brief Open a raster file as a GDALDataset.
3846 : *
3847 : * This function will try to open the passed file, or virtual dataset
3848 : * name by invoking the Open method of each registered GDALDriver in turn.
3849 : * The first successful open will result in a returned dataset. If all
3850 : * drivers fail then NULL is returned and an error is issued.
3851 : *
3852 : * Several recommendations :
3853 : * <ul>
3854 : * <li>If you open a dataset object with GA_Update access, it is not recommended
3855 : * to open a new dataset on the same underlying file.</li>
3856 : * <li>The returned dataset should only be accessed by one thread at a time. If
3857 : * you want to use it from different threads, you must add all necessary code
3858 : * (mutexes, etc.) to avoid concurrent use of the object. (Some drivers, such
3859 : * as GeoTIFF, maintain internal state variables that are updated each time a
3860 : * new block is read, thus preventing concurrent use.) </li>
3861 : * </ul>
3862 : *
3863 : * For drivers supporting the VSI virtual file API, it is possible to open a
3864 : * file in a .zip archive (see VSIInstallZipFileHandler()), in a
3865 : * .tar/.tar.gz/.tgz archive (see VSIInstallTarFileHandler()) or on a HTTP / FTP
3866 : * server (see VSIInstallCurlFileHandler())
3867 : *
3868 : * \sa GDALOpenShared()
3869 : * \sa GDALOpenEx()
3870 : *
3871 : * @param pszFilename the name of the file to access. In the case of
3872 : * exotic drivers this may not refer to a physical file, but instead contain
3873 : * information for the driver on how to access a dataset. It should be in UTF-8
3874 : * encoding.
3875 : *
3876 : * @param eAccess the desired access, either GA_Update or GA_ReadOnly. Many
3877 : * drivers support only read only access.
3878 : *
3879 : * @return A GDALDatasetH handle or NULL on failure. For C++ applications
3880 : * this handle can be cast to a GDALDataset *.
3881 : */
3882 :
3883 26664 : GDALDatasetH CPL_STDCALL GDALOpen(const char *pszFilename, GDALAccess eAccess)
3884 :
3885 : {
3886 26664 : const int nUpdateFlag = eAccess == GA_Update ? GDAL_OF_UPDATE : 0;
3887 26664 : const int nOpenFlags = GDAL_OF_RASTER | nUpdateFlag | GDAL_OF_VERBOSE_ERROR;
3888 : GDALDatasetH hDataset =
3889 26664 : GDALOpenEx(pszFilename, nOpenFlags, nullptr, nullptr, nullptr);
3890 26664 : return hDataset;
3891 : }
3892 :
3893 : /************************************************************************/
3894 : /* GetSharedDS() */
3895 : /************************************************************************/
3896 :
3897 6485 : static GDALDataset *GetSharedDS(const char *pszFilename,
3898 : unsigned int nOpenFlags,
3899 : const char *const *papszOpenOptions)
3900 : {
3901 12970 : CPLMutexHolderD(&hDLMutex);
3902 :
3903 6485 : if (phSharedDatasetSet != nullptr)
3904 : {
3905 6229 : const GIntBig nThisPID = GDALGetResponsiblePIDForCurrentThread();
3906 : SharedDatasetCtxt sStruct;
3907 :
3908 6229 : sStruct.nPID = nThisPID;
3909 6229 : sStruct.pszDescription = const_cast<char *>(pszFilename);
3910 6229 : sStruct.nOpenFlags = nOpenFlags & ~GDAL_OF_SHARED;
3911 : std::string osConcatenatedOpenOptions =
3912 6229 : GDALSharedDatasetConcatenateOpenOptions(papszOpenOptions);
3913 6229 : sStruct.pszConcatenatedOpenOptions = &osConcatenatedOpenOptions[0];
3914 6229 : sStruct.poDS = nullptr;
3915 : SharedDatasetCtxt *psStruct = static_cast<SharedDatasetCtxt *>(
3916 6229 : CPLHashSetLookup(phSharedDatasetSet, &sStruct));
3917 6229 : if (psStruct == nullptr && (nOpenFlags & GDAL_OF_UPDATE) == 0)
3918 : {
3919 124 : sStruct.nOpenFlags |= GDAL_OF_UPDATE;
3920 : psStruct = static_cast<SharedDatasetCtxt *>(
3921 124 : CPLHashSetLookup(phSharedDatasetSet, &sStruct));
3922 : }
3923 6229 : if (psStruct)
3924 : {
3925 6106 : return psStruct->poDS;
3926 : }
3927 : }
3928 379 : return nullptr;
3929 : }
3930 :
3931 : /************************************************************************/
3932 : /* GDALOpenEx() */
3933 : /************************************************************************/
3934 :
3935 : /**
3936 : * \brief Open a raster or vector file as a GDALDataset.
3937 : *
3938 : * This function will try to open the passed file, or virtual dataset
3939 : * name by invoking the Open method of each registered GDALDriver in turn.
3940 : * The first successful open will result in a returned dataset. If all
3941 : * drivers fail then NULL is returned and an error is issued.
3942 : *
3943 : * Several recommendations :
3944 : * <ul>
3945 : * <li>If you open a dataset object with GDAL_OF_UPDATE access, it is not
3946 : * recommended to open a new dataset on the same underlying file.</li>
3947 : * <li>The returned dataset should only be accessed by one thread at a time. If
3948 : * you want to use it from different threads, you must add all necessary code
3949 : * (mutexes, etc.) to avoid concurrent use of the object. (Some drivers, such
3950 : * as GeoTIFF, maintain internal state variables that are updated each time a
3951 : * new block is read, thus preventing concurrent use.) </li>
3952 : * </ul>
3953 : *
3954 : * For drivers supporting the VSI virtual file API, it is possible to open a
3955 : * file in a .zip archive (see VSIInstallZipFileHandler()), in a
3956 : * .tar/.tar.gz/.tgz archive (see VSIInstallTarFileHandler()) or on a HTTP / FTP
3957 : * server (see VSIInstallCurlFileHandler())
3958 : *
3959 : * In order to reduce the need for searches through the operating system
3960 : * file system machinery, it is possible to give an optional list of files with
3961 : * the papszSiblingFiles parameter.
3962 : * This is the list of all files at the same level in the file system as the
3963 : * target file, including the target file. The filenames must not include any
3964 : * path components, are essentially just the output of VSIReadDir() on the
3965 : * parent directory. If the target object does not have filesystem semantics
3966 : * then the file list should be NULL.
3967 : *
3968 : * @param pszFilename the name of the file to access. In the case of
3969 : * exotic drivers this may not refer to a physical file, but instead contain
3970 : * information for the driver on how to access a dataset. It should be in UTF-8
3971 : * encoding.
3972 : *
3973 : * @param nOpenFlags a combination of GDAL_OF_ flags that may be combined
3974 : * through logical or operator.
3975 : * <ul>
3976 : * <li>Driver kind:
3977 : * <ul>
3978 : * <li>GDAL_OF_RASTER for raster drivers,</li>
3979 : * <li>GDAL_OF_MULTIDIM_RASTER for multidimensional raster drivers,</li>
3980 : * <li>GDAL_OF_VECTOR for vector drivers,</li>
3981 : * <li>GDAL_OF_GNM for Geographic Network Model drivers.</li>
3982 : * </ul>
3983 : * GDAL_OF_RASTER and GDAL_OF_MULTIDIM_RASTER are generally mutually
3984 : * exclusive. If none of the value is specified, GDAL_OF_RASTER | GDAL_OF_VECTOR
3985 : * | GDAL_OF_GNM is implied.
3986 : * </li>
3987 : * <li>Access mode: GDAL_OF_READONLY (exclusive)or GDAL_OF_UPDATE.
3988 : * </li>
3989 : * <li>Shared mode: GDAL_OF_SHARED. If set,
3990 : * it allows the sharing of GDALDataset handles for a dataset with other callers
3991 : * that have set GDAL_OF_SHARED. In particular, GDALOpenEx() will first consult
3992 : * its list of currently open and shared GDALDataset's, and if the
3993 : * GetDescription() name for one exactly matches the pszFilename passed to
3994 : * GDALOpenEx() it will be referenced and returned, if GDALOpenEx() is called
3995 : * from the same thread.
3996 : * </li>
3997 : * <li>Thread safe mode: GDAL_OF_THREAD_SAFE (added in 3.10).
3998 : * This must be use in combination with GDAL_OF_RASTER, and is mutually
3999 : * exclusive with GDAL_OF_UPDATE, GDAL_OF_VECTOR, GDAL_OF_MULTIDIM_RASTER or
4000 : * GDAL_OF_GNM.
4001 : * </li>
4002 : * <li>Verbose error: GDAL_OF_VERBOSE_ERROR. If set,
4003 : * a failed attempt to open the file will lead to an error message to be
4004 : * reported.
4005 : * </li>
4006 : * </ul>
4007 : *
4008 : * @param papszAllowedDrivers NULL to consider all candidate drivers, or a NULL
4009 : * terminated list of strings with the driver short names that must be
4010 : * considered.
4011 : * Starting with GDAL 3.13, a string starting with the dash (-) character
4012 : * followed by the driver short name can be used to exclude a driver.
4013 : *
4014 : * @param papszOpenOptions NULL, or a NULL terminated list of strings with open
4015 : * options passed to candidate drivers. An option exists for all drivers,
4016 : * OVERVIEW_LEVEL=level, to select a particular overview level of a dataset.
4017 : * The level index starts at 0. The level number can be suffixed by "only" to
4018 : * specify that only this overview level must be visible, and not sub-levels.
4019 : * Open options are validated by default, and a warning is emitted in case the
4020 : * option is not recognized. In some scenarios, it might be not desirable (e.g.
4021 : * when not knowing which driver will open the file), so the special open option
4022 : * VALIDATE_OPEN_OPTIONS can be set to NO to avoid such warnings. Alternatively,
4023 : * that it may not cause a warning if the driver doesn't declare this option.
4024 : * Starting with GDAL 3.3, OVERVIEW_LEVEL=NONE is supported to indicate that
4025 : * no overviews should be exposed.
4026 : *
4027 : * @param papszSiblingFiles NULL, or a NULL terminated list of strings that are
4028 : * filenames that are auxiliary to the main filename. If NULL is passed, a
4029 : * probing of the file system will be done.
4030 : *
4031 : * @return A GDALDatasetH handle or NULL on failure. For C++ applications
4032 : * this handle can be cast to a GDALDataset *.
4033 : *
4034 : */
4035 :
4036 85921 : GDALDatasetH CPL_STDCALL GDALOpenEx(const char *pszFilename,
4037 : unsigned int nOpenFlags,
4038 : const char *const *papszAllowedDrivers,
4039 : const char *const *papszOpenOptions,
4040 : const char *const *papszSiblingFiles)
4041 : {
4042 85921 : VALIDATE_POINTER1(pszFilename, "GDALOpen", nullptr);
4043 :
4044 : // Do some sanity checks on incompatible flags with thread-safe mode.
4045 85921 : if ((nOpenFlags & GDAL_OF_THREAD_SAFE) != 0)
4046 : {
4047 : const struct
4048 : {
4049 : int nFlag;
4050 : const char *pszFlagName;
4051 128 : } asFlags[] = {
4052 : {GDAL_OF_UPDATE, "GDAL_OF_UPDATE"},
4053 : {GDAL_OF_VECTOR, "GDAL_OF_VECTOR"},
4054 : {GDAL_OF_MULTIDIM_RASTER, "GDAL_OF_MULTIDIM_RASTER"},
4055 : {GDAL_OF_GNM, "GDAL_OF_GNM"},
4056 : };
4057 :
4058 630 : for (const auto &asFlag : asFlags)
4059 : {
4060 506 : if ((nOpenFlags & asFlag.nFlag) != 0)
4061 : {
4062 4 : CPLError(CE_Failure, CPLE_IllegalArg,
4063 : "GDAL_OF_THREAD_SAFE and %s are mutually "
4064 : "exclusive",
4065 4 : asFlag.pszFlagName);
4066 4 : return nullptr;
4067 : }
4068 : }
4069 : }
4070 :
4071 : // If no driver kind is specified, assume all are to be probed.
4072 85917 : if ((nOpenFlags & GDAL_OF_KIND_MASK) == 0)
4073 7631 : nOpenFlags |= GDAL_OF_KIND_MASK & ~GDAL_OF_MULTIDIM_RASTER;
4074 :
4075 : /* -------------------------------------------------------------------- */
4076 : /* In case of shared dataset, first scan the existing list to see */
4077 : /* if it could already contain the requested dataset. */
4078 : /* -------------------------------------------------------------------- */
4079 85917 : if (nOpenFlags & GDAL_OF_SHARED)
4080 : {
4081 6485 : if (nOpenFlags & GDAL_OF_INTERNAL)
4082 : {
4083 0 : CPLError(CE_Failure, CPLE_IllegalArg,
4084 : "GDAL_OF_SHARED and GDAL_OF_INTERNAL are exclusive");
4085 0 : return nullptr;
4086 : }
4087 :
4088 : auto poSharedDS =
4089 6485 : GetSharedDS(pszFilename, nOpenFlags, papszOpenOptions);
4090 6485 : if (poSharedDS)
4091 : {
4092 6106 : poSharedDS->Reference();
4093 6106 : return poSharedDS;
4094 : }
4095 : }
4096 :
4097 79811 : CPLErrorReset();
4098 79811 : VSIErrorReset();
4099 :
4100 : // Build GDALOpenInfo just now to avoid useless file stat'ing if a
4101 : // shared dataset was asked before.
4102 79811 : GDALOpenInfo oOpenInfo(pszFilename, nOpenFlags, papszSiblingFiles);
4103 :
4104 159622 : return GDALDataset::Open(&oOpenInfo, papszAllowedDrivers, papszOpenOptions)
4105 79811 : .release();
4106 : }
4107 :
4108 : /************************************************************************/
4109 : /* GDALDataset::Open() */
4110 : /************************************************************************/
4111 :
4112 : /**
4113 : * \brief Open a raster or vector file as a GDALDataset.
4114 : *
4115 : * This function will use the passed open info on each registered GDALDriver in
4116 : * turn.
4117 : * The first successful open will result in a returned dataset. If all
4118 : * drivers fail then NULL is returned and an error is issued.
4119 : *
4120 : * Several recommendations :
4121 : * <ul>
4122 : * <li>If you open a dataset object with GDAL_OF_UPDATE access, it is not
4123 : * recommended to open a new dataset on the same underlying file.</li>
4124 : * <li>The returned dataset should only be accessed by one thread at a time. If
4125 : * you want to use it from different threads, you must add all necessary code
4126 : * (mutexes, etc.) to avoid concurrent use of the object. (Some drivers, such
4127 : * as GeoTIFF, maintain internal state variables that are updated each time a
4128 : * new block is read, thus preventing concurrent use.) </li>
4129 : * </ul>
4130 : *
4131 : * For drivers supporting the VSI virtual file API, it is possible to open a
4132 : * file in a .zip archive (see VSIInstallZipFileHandler()), in a
4133 : * .tar/.tar.gz/.tgz archive (see VSIInstallTarFileHandler()) or on a HTTP / FTP
4134 : * server (see VSIInstallCurlFileHandler())
4135 : *
4136 : * @param poOpenInfo a pointer to an open info instance. Must NOT be NULL,
4137 : * and the GDAL_OF_SHARED flag must NOT be set in poOpenInfo->nOpenFlags.
4138 : * If shared dataset is needed, use GDALOpenEx() or the other variant of
4139 : * GDALDataset::Open()
4140 : *
4141 : * @param papszAllowedDrivers NULL to consider all candidate drivers, or a NULL
4142 : * terminated list of strings with the driver short names that must be
4143 : * considered.
4144 : * Starting with GDAL 3.13, a string starting with the dash (-) character
4145 : * followed by the driver short name can be used to exclude a driver.
4146 : *
4147 : * @param papszOpenOptions NULL, or a NULL terminated list of strings with open
4148 : * options passed to candidate drivers. An option exists for all drivers,
4149 : * OVERVIEW_LEVEL=level, to select a particular overview level of a dataset.
4150 : * The level index starts at 0. The level number can be suffixed by "only" to
4151 : * specify that only this overview level must be visible, and not sub-levels.
4152 : * Open options are validated by default, and a warning is emitted in case the
4153 : * option is not recognized. In some scenarios, it might be not desirable (e.g.
4154 : * when not knowing which driver will open the file), so the special open option
4155 : * VALIDATE_OPEN_OPTIONS can be set to NO to avoid such warnings. Alternatively,
4156 : * that it may not cause a warning if the driver doesn't declare this option.
4157 : * OVERVIEW_LEVEL=NONE is supported to indicate that
4158 : * no overviews should be exposed.
4159 : *
4160 : * @return A GDALDataset unique pointer or NULL on failure.
4161 : *
4162 : * @since 3.13
4163 : */
4164 :
4165 : std::unique_ptr<GDALDataset>
4166 81806 : GDALDataset::Open(GDALOpenInfo *poOpenInfo,
4167 : const char *const *papszAllowedDrivers,
4168 : const char *const *papszOpenOptions)
4169 : {
4170 : // Hack for the ZARR driver. We translate the CACHE_KERCHUNK_JSON
4171 : // into VSIKERCHUNK_USE_CACHE config option
4172 81806 : std::unique_ptr<CPLConfigOptionSetter> poVSIKERCHUNK_USE_CACHESetter;
4173 81806 : if (CPLFetchBool(papszOpenOptions, "CACHE_KERCHUNK_JSON", false))
4174 : {
4175 13 : poVSIKERCHUNK_USE_CACHESetter = std::make_unique<CPLConfigOptionSetter>(
4176 26 : "VSIKERCHUNK_USE_CACHE", "YES", false);
4177 : }
4178 :
4179 81806 : GDALDriverManager *poDM = GetGDALDriverManager();
4180 :
4181 81806 : CPLAssert(nullptr != poDM);
4182 :
4183 81806 : GDALOpenInfo &oOpenInfo = *poOpenInfo;
4184 81806 : const char *pszFilename = poOpenInfo->pszFilename;
4185 81806 : const int nOpenFlags = poOpenInfo->nOpenFlags;
4186 81806 : oOpenInfo.papszAllowedDrivers = papszAllowedDrivers;
4187 :
4188 81806 : GDALAntiRecursionStruct &sAntiRecursion = GetAntiRecursionOpen();
4189 81806 : if (sAntiRecursion.nRecLevel == 100)
4190 : {
4191 0 : CPLError(CE_Failure, CPLE_AppDefined,
4192 : "GDALOpen() called with too many recursion levels");
4193 0 : return nullptr;
4194 : }
4195 :
4196 163612 : std::string osAllowedDrivers;
4197 176099 : for (const char *pszDriverName : cpl::Iterate(papszAllowedDrivers))
4198 94293 : osAllowedDrivers += pszDriverName;
4199 : auto dsCtxt = GDALAntiRecursionStruct::DatasetContext(
4200 245418 : std::string(pszFilename), nOpenFlags, osAllowedDrivers);
4201 81806 : if (cpl::contains(sAntiRecursion.aosDatasetNamesWithFlags, dsCtxt))
4202 : {
4203 0 : CPLError(CE_Failure, CPLE_AppDefined,
4204 : "GDALOpen() called on %s recursively", pszFilename);
4205 0 : return nullptr;
4206 : }
4207 :
4208 : // Remove leading @ if present.
4209 : char **papszOpenOptionsCleaned =
4210 81806 : CSLDuplicate(const_cast<char **>(papszOpenOptions));
4211 87466 : for (char **papszIter = papszOpenOptionsCleaned; papszIter && *papszIter;
4212 : ++papszIter)
4213 : {
4214 5660 : char *pszOption = *papszIter;
4215 5660 : if (pszOption[0] == '@')
4216 228 : memmove(pszOption, pszOption + 1, strlen(pszOption + 1) + 1);
4217 : }
4218 :
4219 81806 : oOpenInfo.papszOpenOptions = papszOpenOptionsCleaned;
4220 81806 : oOpenInfo.nOpenFlags |= GDAL_OF_FROM_GDALOPEN;
4221 :
4222 : #ifdef OGRAPISPY_ENABLED
4223 81806 : const bool bUpdate = (nOpenFlags & GDAL_OF_UPDATE) != 0;
4224 : const int iSnapshot =
4225 19518 : (nOpenFlags & GDAL_OF_VECTOR) != 0 && (nOpenFlags & GDAL_OF_RASTER) == 0
4226 101324 : ? OGRAPISpyOpenTakeSnapshot(pszFilename, bUpdate)
4227 81806 : : INT_MIN;
4228 : #endif
4229 :
4230 81806 : const int nDriverCount = poDM->GetDriverCount(/*bIncludeHidden=*/true);
4231 81806 : GDALDriver *poMissingPluginDriver = nullptr;
4232 163612 : std::vector<GDALDriver *> apoSecondPassDrivers;
4233 :
4234 : // Lookup of matching driver for dataset can involve up to 2 passes:
4235 : // - in the first pass, all drivers that are compabile of the request mode
4236 : // (raster/vector/etc.) are probed using their Identify() method if it
4237 : // exists. If the Identify() method returns FALSE, the driver is skipped.
4238 : // If the Identify() methods returns GDAL_IDENTIFY_UNKNOWN and that the
4239 : // driver is a deferred-loading plugin, it is added to the
4240 : // apoSecondPassDrivers list for potential later probing, and execution
4241 : // continues to the next driver in the list.
4242 : // Otherwise if Identify() returns non-FALSE, the Open() method is used.
4243 : // If Open() returns a non-NULL dataset, the loop stops and it is
4244 : // returned. Otherwise looping over remaining drivers continues.
4245 : // - the second pass is optional, only if at least one driver was added
4246 : // into apoSecondPassDrivers during the first pass. It is similar
4247 : // to the first pass except it runs only on apoSecondPassDrivers drivers.
4248 : // And the Open() method of such drivers is used, causing them to be
4249 : // loaded for real.
4250 81806 : int iPass = 1;
4251 81820 : retry:
4252 8454140 : for (int iDriver = 0;
4253 8454180 : iDriver < (iPass == 1 ? nDriverCount
4254 34 : : static_cast<int>(apoSecondPassDrivers.size()));
4255 : ++iDriver)
4256 : {
4257 : GDALDriver *poDriver =
4258 8434960 : iPass == 1 ? poDM->GetDriver(iDriver, /*bIncludeHidden=*/true)
4259 25 : : apoSecondPassDrivers[iDriver];
4260 8434940 : const char *pszDriverName = GDALGetDriverShortName(poDriver);
4261 8434940 : if (pszDriverName && papszAllowedDrivers)
4262 : {
4263 3783460 : bool bDriverMatchedPositively = false;
4264 3783460 : bool bDriverMatchedNegatively = false;
4265 3783460 : bool bOnlyExcludedDrivers = true;
4266 17866300 : for (const char *pszAllowedDriver :
4267 39516000 : cpl::Iterate(papszAllowedDrivers))
4268 : {
4269 17866300 : if (pszAllowedDriver[0] != '-')
4270 17861000 : bOnlyExcludedDrivers = false;
4271 17866300 : if (EQUAL(pszAllowedDriver, pszDriverName))
4272 : {
4273 89170 : bDriverMatchedPositively = true;
4274 : }
4275 17777100 : else if (pszAllowedDriver[0] == '-' &&
4276 5271 : EQUAL(pszAllowedDriver + 1, pszDriverName))
4277 : {
4278 24 : bDriverMatchedNegatively = true;
4279 24 : break;
4280 : }
4281 : }
4282 3783460 : if ((!bDriverMatchedPositively && !bOnlyExcludedDrivers) ||
4283 : bDriverMatchedNegatively)
4284 : {
4285 7942120 : continue;
4286 : }
4287 : }
4288 :
4289 4745660 : if (poDriver->GetMetadataItem(GDAL_DCAP_OPEN) == nullptr)
4290 45858 : continue;
4291 :
4292 12422000 : if ((nOpenFlags & GDAL_OF_RASTER) != 0 &&
4293 6810100 : (nOpenFlags & GDAL_OF_VECTOR) == 0 &&
4294 2110300 : poDriver->GetMetadataItem(GDAL_DCAP_RASTER) == nullptr)
4295 467484 : continue;
4296 12145500 : if ((nOpenFlags & GDAL_OF_VECTOR) != 0 &&
4297 6079280 : (nOpenFlags & GDAL_OF_RASTER) == 0 &&
4298 1846960 : poDriver->GetMetadataItem(GDAL_DCAP_VECTOR) == nullptr)
4299 1389310 : continue;
4300 6272730 : if ((nOpenFlags & GDAL_OF_MULTIDIM_RASTER) != 0 &&
4301 3139980 : (nOpenFlags & GDAL_OF_RASTER) == 0 &&
4302 296976 : poDriver->GetMetadataItem(GDAL_DCAP_MULTIDIM_RASTER) == nullptr)
4303 279885 : continue;
4304 :
4305 : // Remove general OVERVIEW_LEVEL open options from list before passing
4306 : // it to the driver, if it isn't a driver specific option already.
4307 2563120 : char **papszTmpOpenOptions = nullptr;
4308 2563120 : char **papszTmpOpenOptionsToValidate = nullptr;
4309 2563120 : char **papszOptionsToValidate = const_cast<char **>(papszOpenOptions);
4310 2563120 : if (CSLFetchNameValue(papszOpenOptionsCleaned, "OVERVIEW_LEVEL") !=
4311 2563270 : nullptr &&
4312 152 : !poDriver->HasOpenOption("OVERVIEW_LEVEL"))
4313 : {
4314 152 : papszTmpOpenOptions = CSLDuplicate(papszOpenOptionsCleaned);
4315 : papszTmpOpenOptions =
4316 152 : CSLSetNameValue(papszTmpOpenOptions, "OVERVIEW_LEVEL", nullptr);
4317 152 : oOpenInfo.papszOpenOptions = papszTmpOpenOptions;
4318 :
4319 152 : papszOptionsToValidate = CSLDuplicate(papszOptionsToValidate);
4320 152 : papszOptionsToValidate = CSLSetNameValue(papszOptionsToValidate,
4321 : "OVERVIEW_LEVEL", nullptr);
4322 152 : papszTmpOpenOptionsToValidate = papszOptionsToValidate;
4323 : }
4324 :
4325 : const int nIdentifyRes =
4326 2563120 : poDriver->pfnIdentifyEx
4327 5126230 : ? poDriver->pfnIdentifyEx(poDriver, &oOpenInfo)
4328 2563110 : : poDriver->pfnIdentify ? poDriver->pfnIdentify(&oOpenInfo)
4329 2563120 : : GDAL_IDENTIFY_UNKNOWN;
4330 2563120 : if (nIdentifyRes == FALSE)
4331 : {
4332 2070200 : CSLDestroy(papszTmpOpenOptions);
4333 2070200 : CSLDestroy(papszTmpOpenOptionsToValidate);
4334 2070200 : oOpenInfo.papszOpenOptions = papszOpenOptionsCleaned;
4335 2070200 : continue;
4336 : }
4337 492894 : else if (iPass == 1 && nIdentifyRes < 0 &&
4338 985920 : poDriver->pfnOpen == nullptr &&
4339 107 : poDriver->GetMetadataItem("IS_NON_LOADED_PLUGIN"))
4340 : {
4341 : // Not loaded plugin
4342 104 : apoSecondPassDrivers.push_back(poDriver);
4343 104 : CSLDestroy(papszTmpOpenOptions);
4344 104 : CSLDestroy(papszTmpOpenOptionsToValidate);
4345 104 : oOpenInfo.papszOpenOptions = papszOpenOptionsCleaned;
4346 104 : continue;
4347 : }
4348 :
4349 492815 : const bool bIdentifyRes = nIdentifyRes == GDAL_IDENTIFY_TRUE;
4350 492815 : if (bIdentifyRes)
4351 : {
4352 61656 : GDALValidateOpenOptions(poDriver, papszOptionsToValidate);
4353 : }
4354 :
4355 : #ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION
4356 : const bool bFpAvailableBefore = oOpenInfo.fpL != nullptr;
4357 : CPLErrorReset();
4358 : #endif
4359 :
4360 492815 : sAntiRecursion.nRecLevel++;
4361 492815 : sAntiRecursion.aosDatasetNamesWithFlags.insert(dsCtxt);
4362 :
4363 492815 : GDALDataset *poDS = poDriver->Open(&oOpenInfo, false);
4364 :
4365 492815 : sAntiRecursion.nRecLevel--;
4366 492815 : sAntiRecursion.aosDatasetNamesWithFlags.erase(dsCtxt);
4367 :
4368 492815 : if (poDriver->pfnOpen != nullptr)
4369 : {
4370 : // If we couldn't determine for sure with Identify() (it returned
4371 : // -1), but Open() managed to open the file, post validate options.
4372 492812 : if (poDS != nullptr &&
4373 61504 : (poDriver->pfnIdentify || poDriver->pfnIdentifyEx) &&
4374 60938 : !bIdentifyRes)
4375 : {
4376 820 : GDALValidateOpenOptions(poDriver, papszOptionsToValidate);
4377 : }
4378 : }
4379 3 : else if (poDriver->pfnOpenWithDriverArg != nullptr)
4380 : {
4381 : // do nothing
4382 : }
4383 0 : else if (bIdentifyRes &&
4384 0 : poDriver->GetMetadataItem("MISSING_PLUGIN_FILENAME"))
4385 : {
4386 0 : if (!poMissingPluginDriver)
4387 : {
4388 0 : poMissingPluginDriver = poDriver;
4389 : }
4390 : }
4391 : else
4392 : {
4393 : // should not happen given the GDAL_DCAP_OPEN check
4394 0 : CSLDestroy(papszTmpOpenOptions);
4395 0 : CSLDestroy(papszTmpOpenOptionsToValidate);
4396 0 : oOpenInfo.papszOpenOptions = papszOpenOptionsCleaned;
4397 0 : continue;
4398 : }
4399 :
4400 492815 : CSLDestroy(papszTmpOpenOptions);
4401 492815 : CSLDestroy(papszTmpOpenOptionsToValidate);
4402 492815 : oOpenInfo.papszOpenOptions = papszOpenOptionsCleaned;
4403 :
4404 492815 : if (poDS != nullptr)
4405 : {
4406 61507 : if (poDS->papszOpenOptions == nullptr)
4407 : {
4408 61237 : poDS->papszOpenOptions = papszOpenOptionsCleaned;
4409 61237 : papszOpenOptionsCleaned = nullptr;
4410 : }
4411 :
4412 : // Deal with generic OVERVIEW_LEVEL open option, unless it is
4413 : // driver specific.
4414 61507 : if (CSLFetchNameValue(papszOpenOptions, "OVERVIEW_LEVEL") !=
4415 61546 : nullptr &&
4416 39 : !poDriver->HasOpenOption("OVERVIEW_LEVEL"))
4417 : {
4418 : CPLString osVal(
4419 78 : CSLFetchNameValue(papszOpenOptions, "OVERVIEW_LEVEL"));
4420 39 : const int nOvrLevel = EQUAL(osVal, "NONE") ? -1 : atoi(osVal);
4421 : const bool bThisLevelOnly =
4422 39 : nOvrLevel == -1 || osVal.ifind("only") != std::string::npos;
4423 : GDALDataset *poOvrDS =
4424 39 : GDALCreateOverviewDataset(poDS, nOvrLevel, bThisLevelOnly);
4425 39 : if (poOvrDS && (nOpenFlags & GDAL_OF_SHARED) != 0)
4426 : {
4427 4 : if (strcmp(pszFilename, poDS->GetDescription()) != 0)
4428 : {
4429 0 : CPLError(
4430 : CE_Warning, CPLE_NotSupported,
4431 : "A dataset opened by GDALOpenShared should have "
4432 : "the same filename (%s) "
4433 : "and description (%s)",
4434 0 : pszFilename, poDS->GetDescription());
4435 : }
4436 : else
4437 : {
4438 4 : CSLDestroy(poDS->papszOpenOptions);
4439 4 : poDS->papszOpenOptions = CSLDuplicate(papszOpenOptions);
4440 4 : poDS->papszOpenOptions = CSLSetNameValue(
4441 : poDS->papszOpenOptions, "OVERVIEW_LEVEL", nullptr);
4442 : }
4443 : }
4444 39 : poDS->ReleaseRef();
4445 39 : poDS = poOvrDS;
4446 39 : if (poDS == nullptr)
4447 : {
4448 1 : if (nOpenFlags & GDAL_OF_VERBOSE_ERROR)
4449 : {
4450 1 : CPLError(CE_Failure, CPLE_OpenFailed,
4451 : "Cannot open overview level %d of %s",
4452 : nOvrLevel, pszFilename);
4453 : }
4454 : }
4455 : else
4456 : {
4457 : // For thread-safe opening, currently poDS is what will be
4458 : // the "master" dataset owned by the thread-safe dataset
4459 : // returned to the user, hence we do not register it as a
4460 : // visible one in the open dataset list, or mark it as shared.
4461 38 : if (!(nOpenFlags & GDAL_OF_INTERNAL) &&
4462 36 : !(nOpenFlags & GDAL_OF_THREAD_SAFE))
4463 : {
4464 35 : poDS->AddToDatasetOpenList();
4465 : }
4466 38 : if (nOpenFlags & GDAL_OF_SHARED)
4467 : {
4468 4 : CSLDestroy(poDS->papszOpenOptions);
4469 4 : poDS->papszOpenOptions = CSLDuplicate(papszOpenOptions);
4470 4 : poDS->nOpenFlags = nOpenFlags;
4471 4 : if (!(nOpenFlags & GDAL_OF_THREAD_SAFE))
4472 4 : poDS->MarkAsShared();
4473 : }
4474 : }
4475 : }
4476 61468 : else if (nOpenFlags & GDAL_OF_SHARED)
4477 : {
4478 369 : if (strcmp(pszFilename, poDS->GetDescription()) != 0)
4479 : {
4480 2 : CPLError(CE_Warning, CPLE_NotSupported,
4481 : "A dataset opened by GDALOpenShared should have "
4482 : "the same filename (%s) "
4483 : "and description (%s)",
4484 2 : pszFilename, poDS->GetDescription());
4485 : }
4486 367 : else if (!(nOpenFlags & GDAL_OF_THREAD_SAFE))
4487 : {
4488 : // For thread-safe opening, currently poDS is what will be
4489 : // the "master" dataset owned by the thread-safe dataset
4490 : // returned to the user, hence we do not or mark it as shared.
4491 367 : poDS->MarkAsShared();
4492 : }
4493 : }
4494 :
4495 61507 : VSIErrorReset();
4496 :
4497 61507 : CSLDestroy(papszOpenOptionsCleaned);
4498 :
4499 : #ifdef OGRAPISPY_ENABLED
4500 61507 : if (iSnapshot != INT_MIN)
4501 : {
4502 11615 : GDALDatasetH hDS = GDALDataset::ToHandle(poDS);
4503 11615 : OGRAPISpyOpen(pszFilename, bUpdate, iSnapshot, &hDS);
4504 11615 : poDS = GDALDataset::FromHandle(hDS);
4505 : }
4506 : #endif
4507 :
4508 61507 : if (poDS)
4509 : {
4510 61506 : poDS->m_bCanBeReopened = true;
4511 :
4512 61506 : if ((nOpenFlags & GDAL_OF_THREAD_SAFE) != 0)
4513 : {
4514 : poDS =
4515 248 : GDALGetThreadSafeDataset(
4516 248 : std::unique_ptr<GDALDataset>(poDS), GDAL_OF_RASTER)
4517 124 : .release();
4518 124 : if (poDS)
4519 : {
4520 124 : poDS->m_bCanBeReopened = true;
4521 124 : poDS->poDriver = poDriver;
4522 124 : poDS->nOpenFlags = nOpenFlags;
4523 124 : if (!(nOpenFlags & GDAL_OF_INTERNAL))
4524 124 : poDS->AddToDatasetOpenList();
4525 124 : if (nOpenFlags & GDAL_OF_SHARED)
4526 0 : poDS->MarkAsShared();
4527 : }
4528 : }
4529 : }
4530 :
4531 62611 : return std::unique_ptr<GDALDataset>(poDS);
4532 : }
4533 :
4534 : #ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION
4535 : if (bFpAvailableBefore && oOpenInfo.fpL == nullptr)
4536 : {
4537 : // In case the file descriptor was "consumed" by a driver
4538 : // that ultimately failed, re-open it for next drivers.
4539 : oOpenInfo.fpL = VSIFOpenL(
4540 : pszFilename, (oOpenInfo.eAccess == GA_Update) ? "r+b" : "rb");
4541 : }
4542 : #else
4543 431308 : if (CPLGetLastErrorNo() != 0 && CPLGetLastErrorType() > CE_Warning)
4544 : {
4545 1104 : CSLDestroy(papszOpenOptionsCleaned);
4546 :
4547 : #ifdef OGRAPISPY_ENABLED
4548 1104 : if (iSnapshot != INT_MIN)
4549 : {
4550 193 : GDALDatasetH hDS = nullptr;
4551 193 : OGRAPISpyOpen(pszFilename, bUpdate, iSnapshot, &hDS);
4552 : }
4553 : #endif
4554 1104 : return nullptr;
4555 : }
4556 : #endif
4557 : }
4558 :
4559 : // cppcheck-suppress knownConditionTrueFalse
4560 19209 : if (iPass == 1 && !apoSecondPassDrivers.empty())
4561 : {
4562 14 : CPLDebugOnly("GDAL", "GDALOpen(): Second pass");
4563 14 : iPass = 2;
4564 14 : goto retry;
4565 : }
4566 :
4567 19195 : CSLDestroy(papszOpenOptionsCleaned);
4568 :
4569 : #ifdef OGRAPISPY_ENABLED
4570 19195 : if (iSnapshot != INT_MIN)
4571 : {
4572 654 : GDALDatasetH hDS = nullptr;
4573 654 : OGRAPISpyOpen(pszFilename, bUpdate, iSnapshot, &hDS);
4574 : }
4575 : #endif
4576 :
4577 19195 : if (nOpenFlags & GDAL_OF_VERBOSE_ERROR)
4578 : {
4579 5952 : if (nDriverCount == 0)
4580 : {
4581 0 : CPLError(CE_Failure, CPLE_OpenFailed, "No driver registered.");
4582 : }
4583 5952 : else if (poMissingPluginDriver)
4584 : {
4585 0 : std::string osMsg("`");
4586 0 : osMsg += pszFilename;
4587 : osMsg += "' not recognized as being in a supported file format. "
4588 0 : "It could have been recognized by driver ";
4589 0 : osMsg += poMissingPluginDriver->GetDescription();
4590 0 : osMsg += ", but plugin ";
4591 : osMsg +=
4592 0 : GDALGetMessageAboutMissingPluginDriver(poMissingPluginDriver);
4593 :
4594 0 : CPLError(CE_Failure, CPLE_OpenFailed, "%s", osMsg.c_str());
4595 : }
4596 : // Check to see if there was a filesystem error, and report it if so.
4597 : // If not, return a more generic error.
4598 5952 : else if (!VSIToCPLError(CE_Failure, CPLE_OpenFailed))
4599 : {
4600 504 : if (oOpenInfo.bStatOK)
4601 : {
4602 501 : CPLError(CE_Failure, CPLE_OpenFailed,
4603 : "`%s' not recognized as being in a supported file "
4604 : "format.",
4605 : pszFilename);
4606 : }
4607 : else
4608 : {
4609 : // If Stat failed and no VSI error was set, assume it is because
4610 : // the file did not exist on the filesystem.
4611 3 : CPLError(CE_Failure, CPLE_OpenFailed,
4612 : "`%s' does not exist in the file system, "
4613 : "and is not recognized as a supported dataset name.",
4614 : pszFilename);
4615 : }
4616 : }
4617 : }
4618 :
4619 19195 : return nullptr;
4620 : }
4621 :
4622 : /************************************************************************/
4623 : /* GDALOpenShared() */
4624 : /************************************************************************/
4625 :
4626 : /**
4627 : * \brief Open a raster file as a GDALDataset.
4628 : *
4629 : * This function works the same as GDALOpen(), but allows the sharing of
4630 : * GDALDataset handles for a dataset with other callers to GDALOpenShared().
4631 : *
4632 : * In particular, GDALOpenShared() will first consult its list of currently
4633 : * open and shared GDALDataset's, and if the GetDescription() name for one
4634 : * exactly matches the pszFilename passed to GDALOpenShared() it will be
4635 : * referenced and returned.
4636 : *
4637 : * If GDALOpenShared() is called on the same
4638 : * pszFilename from two different threads, a different GDALDataset object will
4639 : * be returned as it is not safe to use the same dataset from different threads,
4640 : * unless the user does explicitly use mutexes in its code.
4641 : *
4642 : * For drivers supporting the VSI virtual file API, it is possible to open a
4643 : * file in a .zip archive (see VSIInstallZipFileHandler()), in a
4644 : * .tar/.tar.gz/.tgz archive (see VSIInstallTarFileHandler()) or on a HTTP / FTP
4645 : * server (see VSIInstallCurlFileHandler())
4646 : *
4647 : * \sa GDALOpen()
4648 : * \sa GDALOpenEx()
4649 : *
4650 : * @param pszFilename the name of the file to access. In the case of
4651 : * exotic drivers this may not refer to a physical file, but instead contain
4652 : * information for the driver on how to access a dataset. It should be in
4653 : * UTF-8 encoding.
4654 : *
4655 : * @param eAccess the desired access, either GA_Update or GA_ReadOnly. Many
4656 : * drivers support only read only access.
4657 : *
4658 : * @return A GDALDatasetH handle or NULL on failure. For C++ applications
4659 : * this handle can be cast to a GDALDataset *.
4660 : */
4661 :
4662 5204 : GDALDatasetH CPL_STDCALL GDALOpenShared(const char *pszFilename,
4663 : GDALAccess eAccess)
4664 : {
4665 5204 : VALIDATE_POINTER1(pszFilename, "GDALOpenShared", nullptr);
4666 5204 : return GDALOpenEx(pszFilename,
4667 : GDAL_OF_RASTER |
4668 : (eAccess == GA_Update ? GDAL_OF_UPDATE : 0) |
4669 : GDAL_OF_SHARED | GDAL_OF_VERBOSE_ERROR,
4670 5204 : nullptr, nullptr, nullptr);
4671 : }
4672 :
4673 : /************************************************************************/
4674 : /* GDALClose() */
4675 : /************************************************************************/
4676 :
4677 : /**
4678 : * \brief Close GDAL dataset.
4679 : *
4680 : * For non-shared datasets (opened with GDALOpen()) the dataset is closed
4681 : * using the C++ "delete" operator, recovering all dataset related resources.
4682 : * For shared datasets (opened with GDALOpenShared()) the dataset is
4683 : * dereferenced, and closed only if the referenced count has dropped below 1.
4684 : *
4685 : * @param hDS The dataset to close, or nullptr.
4686 : * @return CE_None in case of success (return value since GDAL 3.7). On a
4687 : * shared dataset whose reference count is not dropped below 1, CE_None will
4688 : * be returned.
4689 : *
4690 : * @see GDALCloseEx()
4691 : */
4692 :
4693 75433 : CPLErr CPL_STDCALL GDALClose(GDALDatasetH hDS)
4694 :
4695 : {
4696 75433 : return GDALCloseEx(hDS, nullptr, nullptr);
4697 : }
4698 :
4699 : /************************************************************************/
4700 : /* GDALCloseEx() */
4701 : /************************************************************************/
4702 :
4703 : /**
4704 : * \brief Close GDAL dataset.
4705 : *
4706 : * For non-shared datasets (opened with GDALOpen()) the dataset is closed
4707 : * using the C++ "delete" operator, recovering all dataset related resources.
4708 : * For shared datasets (opened with GDALOpenShared()) the dataset is
4709 : * dereferenced, and closed only if the referenced count has dropped below 1.
4710 : *
4711 : * This function may report progress if a progress
4712 : * callback if provided in the pfnProgress argument and if the dataset returns
4713 : * true for GDALDataset::GetCloseReportsProgress()
4714 :
4715 : * @param hDS The dataset to close, or nullptr
4716 : * @param pfnProgress Progress callback, or nullptr
4717 : * @param pProgressData User data of progress callback, or nullptr
4718 : *
4719 : * @return CE_None in case of success. On a
4720 : * shared dataset whose reference count is not dropped below 1, CE_None will
4721 : * be returned.
4722 : *
4723 : * @since GDAL 3.13
4724 : * @see GDALClose()
4725 : */
4726 :
4727 79680 : CPLErr GDALCloseEx(GDALDatasetH hDS, GDALProgressFunc pfnProgress,
4728 : void *pProgressData)
4729 : {
4730 79680 : if (!hDS)
4731 403 : return CE_None;
4732 :
4733 : #ifdef OGRAPISPY_ENABLED
4734 79277 : if (bOGRAPISpyEnabled)
4735 11 : OGRAPISpyPreClose(hDS);
4736 : #endif
4737 :
4738 79277 : GDALDataset *poDS = GDALDataset::FromHandle(hDS);
4739 :
4740 79277 : if (poDS->GetShared())
4741 : {
4742 : /* --------------------------------------------------------------------
4743 : */
4744 : /* If this file is in the shared dataset list then dereference */
4745 : /* it, and only delete/remote it if the reference count has */
4746 : /* dropped to zero. */
4747 : /* --------------------------------------------------------------------
4748 : */
4749 236 : if (poDS->Dereference() > 0)
4750 15 : return CE_None;
4751 : }
4752 :
4753 79262 : CPLErr eErr = poDS->Close(pfnProgress, pProgressData);
4754 79262 : delete poDS;
4755 :
4756 : #ifdef OGRAPISPY_ENABLED
4757 79262 : if (bOGRAPISpyEnabled)
4758 11 : OGRAPISpyPostClose();
4759 : #endif
4760 79262 : return eErr;
4761 : }
4762 :
4763 : /************************************************************************/
4764 : /* GDALDumpOpenDataset() */
4765 : /************************************************************************/
4766 :
4767 0 : static int GDALDumpOpenSharedDatasetsForeach(void *elt, void *user_data)
4768 : {
4769 0 : SharedDatasetCtxt *psStruct = static_cast<SharedDatasetCtxt *>(elt);
4770 0 : FILE *fp = static_cast<FILE *>(user_data);
4771 0 : GDALDataset *poDS = psStruct->poDS;
4772 :
4773 0 : const char *pszDriverName = poDS->GetDriver() == nullptr
4774 0 : ? "DriverIsNULL"
4775 0 : : poDS->GetDriver()->GetDescription();
4776 :
4777 0 : poDS->Reference();
4778 0 : CPL_IGNORE_RET_VAL(
4779 0 : VSIFPrintf(fp, " %d %c %-6s %7d %dx%dx%d %s\n", poDS->Dereference(),
4780 0 : poDS->GetShared() ? 'S' : 'N', pszDriverName,
4781 0 : static_cast<int>(psStruct->nPID), poDS->GetRasterXSize(),
4782 : poDS->GetRasterYSize(), poDS->GetRasterCount(),
4783 0 : poDS->GetDescription()));
4784 :
4785 0 : return TRUE;
4786 : }
4787 :
4788 0 : static int GDALDumpOpenDatasetsForeach(GDALDataset *poDS, FILE *fp)
4789 : {
4790 :
4791 : // Don't list shared datasets. They have already been listed by
4792 : // GDALDumpOpenSharedDatasetsForeach.
4793 0 : if (poDS->GetShared())
4794 0 : return TRUE;
4795 :
4796 0 : const char *pszDriverName = poDS->GetDriver() == nullptr
4797 0 : ? "DriverIsNULL"
4798 0 : : poDS->GetDriver()->GetDescription();
4799 :
4800 0 : poDS->Reference();
4801 0 : CPL_IGNORE_RET_VAL(
4802 0 : VSIFPrintf(fp, " %d %c %-6s %7d %dx%dx%d %s\n", poDS->Dereference(),
4803 0 : poDS->GetShared() ? 'S' : 'N', pszDriverName, -1,
4804 : poDS->GetRasterXSize(), poDS->GetRasterYSize(),
4805 0 : poDS->GetRasterCount(), poDS->GetDescription()));
4806 :
4807 0 : return TRUE;
4808 : }
4809 :
4810 : /**
4811 : * \brief List open datasets.
4812 : *
4813 : * Dumps a list of all open datasets (shared or not) to the indicated
4814 : * text file (may be stdout or stderr). This function is primarily intended
4815 : * to assist in debugging "dataset leaks" and reference counting issues.
4816 : * The information reported includes the dataset name, referenced count,
4817 : * shared status, driver name, size, and band count.
4818 : */
4819 :
4820 272 : int CPL_STDCALL GDALDumpOpenDatasets(FILE *fp)
4821 :
4822 : {
4823 272 : VALIDATE_POINTER1(fp, "GDALDumpOpenDatasets", 0);
4824 :
4825 544 : CPLMutexHolderD(&hDLMutex);
4826 :
4827 272 : if (poAllDatasetMap == nullptr)
4828 272 : return 0;
4829 :
4830 0 : CPL_IGNORE_RET_VAL(VSIFPrintf(fp, "Open GDAL Datasets:\n"));
4831 :
4832 0 : for (const auto &oIter : *poAllDatasetMap)
4833 : {
4834 0 : GDALDumpOpenDatasetsForeach(oIter.first, fp);
4835 : }
4836 :
4837 0 : if (phSharedDatasetSet != nullptr)
4838 : {
4839 0 : CPLHashSetForeach(phSharedDatasetSet, GDALDumpOpenSharedDatasetsForeach,
4840 : fp);
4841 : }
4842 0 : return static_cast<int>(poAllDatasetMap->size());
4843 : }
4844 :
4845 : /************************************************************************/
4846 : /* BeginAsyncReader() */
4847 : /************************************************************************/
4848 :
4849 : /**
4850 : * \brief Sets up an asynchronous data request
4851 : *
4852 : * This method establish an asynchronous raster read request for the
4853 : * indicated window on the dataset into the indicated buffer. The parameters
4854 : * for windowing, buffer size, buffer type and buffer organization are similar
4855 : * to those for GDALDataset::RasterIO(); however, this call only launches
4856 : * the request and filling the buffer is accomplished via calls to
4857 : * GetNextUpdatedRegion() on the return GDALAsyncReader session object.
4858 : *
4859 : * Once all processing for the created session is complete, or if no further
4860 : * refinement of the request is required, the GDALAsyncReader object should
4861 : * be destroyed with the GDALDataset::EndAsyncReader() method.
4862 : *
4863 : * Note that the data buffer (pData) will potentially continue to be
4864 : * updated as long as the session lives, but it is not deallocated when
4865 : * the session (GDALAsyncReader) is destroyed with EndAsyncReader(). It
4866 : * should be deallocated by the application at that point.
4867 : *
4868 : * Additional information on asynchronous IO in GDAL may be found at:
4869 : * https://gdal.org/development/rfc/rfc24_progressive_data_support.html
4870 : *
4871 : * This method is the same as the C GDALBeginAsyncReader() function.
4872 : *
4873 : * @param nXOff The pixel offset to the top left corner of the region
4874 : * of the band to be accessed. This would be zero to start from the left side.
4875 : *
4876 : * @param nYOff The line offset to the top left corner of the region
4877 : * of the band to be accessed. This would be zero to start from the top.
4878 : *
4879 : * @param nXSize The width of the region of the band to be accessed in pixels.
4880 : *
4881 : * @param nYSize The height of the region of the band to be accessed in lines.
4882 : *
4883 : * @param pBuf The buffer into which the data should be read. This buffer must
4884 : * contain at least nBufXSize * nBufYSize * nBandCount words of type eBufType.
4885 : * It is organized in left to right,top to bottom pixel order. Spacing is
4886 : * controlled by the nPixelSpace, and nLineSpace parameters.
4887 : *
4888 : * @param nBufXSize the width of the buffer image into which the desired region
4889 : * is to be read, or from which it is to be written.
4890 : *
4891 : * @param nBufYSize the height of the buffer image into which the desired
4892 : * region is to be read, or from which it is to be written.
4893 : *
4894 : * @param eBufType the type of the pixel values in the pData data buffer. The
4895 : * pixel values will automatically be translated to/from the GDALRasterBand
4896 : * data type as needed.
4897 : *
4898 : * @param nBandCount the number of bands being read or written.
4899 : *
4900 : * @param panBandMap the list of nBandCount band numbers being read/written.
4901 : * Note band numbers are 1 based. This may be NULL to select the first
4902 : * nBandCount bands.
4903 : *
4904 : * @param nPixelSpace The byte offset from the start of one pixel value in
4905 : * pData to the start of the next pixel value within a scanline. If defaulted
4906 : * (0) the size of the datatype eBufType is used.
4907 : *
4908 : * @param nLineSpace The byte offset from the start of one scanline in
4909 : * pData to the start of the next. If defaulted the size of the datatype
4910 : * eBufType * nBufXSize is used.
4911 : *
4912 : * @param nBandSpace the byte offset from the start of one bands data to the
4913 : * start of the next. If defaulted (zero) the value will be
4914 : * nLineSpace * nBufYSize implying band sequential organization
4915 : * of the data buffer.
4916 : *
4917 : * @param papszOptions Driver specific control options in a string list or NULL.
4918 : * Consult driver documentation for options supported.
4919 : *
4920 : * @return The GDALAsyncReader object representing the request.
4921 : */
4922 :
4923 1 : GDALAsyncReader *GDALDataset::BeginAsyncReader(
4924 : int nXOff, int nYOff, int nXSize, int nYSize, void *pBuf, int nBufXSize,
4925 : int nBufYSize, GDALDataType eBufType, int nBandCount, int *panBandMap,
4926 : int nPixelSpace, int nLineSpace, int nBandSpace, CSLConstList papszOptions)
4927 : {
4928 : // See gdaldefaultasync.cpp
4929 :
4930 1 : return GDALGetDefaultAsyncReader(this, nXOff, nYOff, nXSize, nYSize, pBuf,
4931 : nBufXSize, nBufYSize, eBufType, nBandCount,
4932 : panBandMap, nPixelSpace, nLineSpace,
4933 1 : nBandSpace, papszOptions);
4934 : }
4935 :
4936 : /************************************************************************/
4937 : /* GDALBeginAsyncReader() */
4938 : /************************************************************************/
4939 :
4940 : /**
4941 : * \brief Sets up an asynchronous data request
4942 : *
4943 : * This method establish an asynchronous raster read request for the
4944 : * indicated window on the dataset into the indicated buffer. The parameters
4945 : * for windowing, buffer size, buffer type and buffer organization are similar
4946 : * to those for GDALDataset::RasterIO(); however, this call only launches
4947 : * the request and filling the buffer is accomplished via calls to
4948 : * GetNextUpdatedRegion() on the return GDALAsyncReader session object.
4949 : *
4950 : * Once all processing for the created session is complete, or if no further
4951 : * refinement of the request is required, the GDALAsyncReader object should
4952 : * be destroyed with the GDALDataset::EndAsyncReader() method.
4953 : *
4954 : * Note that the data buffer (pData) will potentially continue to be
4955 : * updated as long as the session lives, but it is not deallocated when
4956 : * the session (GDALAsyncReader) is destroyed with EndAsyncReader(). It
4957 : * should be deallocated by the application at that point.
4958 : *
4959 : * Additional information on asynchronous IO in GDAL may be found at:
4960 : * https://gdal.org/development/rfc/rfc24_progressive_data_support.html
4961 : *
4962 : * This method is the same as the C++ GDALDataset::BeginAsyncReader() method.
4963 : *
4964 : * @param hDS handle to the dataset object.
4965 : *
4966 : * @param nXOff The pixel offset to the top left corner of the region
4967 : * of the band to be accessed. This would be zero to start from the left side.
4968 : *
4969 : * @param nYOff The line offset to the top left corner of the region
4970 : * of the band to be accessed. This would be zero to start from the top.
4971 : *
4972 : * @param nXSize The width of the region of the band to be accessed in pixels.
4973 : *
4974 : * @param nYSize The height of the region of the band to be accessed in lines.
4975 : *
4976 : * @param pBuf The buffer into which the data should be read. This buffer must
4977 : * contain at least nBufXSize * nBufYSize * nBandCount words of type eBufType.
4978 : * It is organized in left to right,top to bottom pixel order. Spacing is
4979 : * controlled by the nPixelSpace, and nLineSpace parameters.
4980 : *
4981 : * @param nBufXSize the width of the buffer image into which the desired region
4982 : * is to be read, or from which it is to be written.
4983 : *
4984 : * @param nBufYSize the height of the buffer image into which the desired
4985 : * region is to be read, or from which it is to be written.
4986 : *
4987 : * @param eBufType the type of the pixel values in the pData data buffer. The
4988 : * pixel values will automatically be translated to/from the GDALRasterBand
4989 : * data type as needed.
4990 : *
4991 : * @param nBandCount the number of bands being read or written.
4992 : *
4993 : * @param panBandMap the list of nBandCount band numbers being read/written.
4994 : * Note band numbers are 1 based. This may be NULL to select the first
4995 : * nBandCount bands.
4996 : *
4997 : * @param nPixelSpace The byte offset from the start of one pixel value in
4998 : * pData to the start of the next pixel value within a scanline. If defaulted
4999 : * (0) the size of the datatype eBufType is used.
5000 : *
5001 : * @param nLineSpace The byte offset from the start of one scanline in
5002 : * pData to the start of the next. If defaulted the size of the datatype
5003 : * eBufType * nBufXSize is used.
5004 : *
5005 : * @param nBandSpace the byte offset from the start of one bands data to the
5006 : * start of the next. If defaulted (zero) the value will be
5007 : * nLineSpace * nBufYSize implying band sequential organization
5008 : * of the data buffer.
5009 : *
5010 : * @param papszOptions Driver specific control options in a string list or NULL.
5011 : * Consult driver documentation for options supported.
5012 : *
5013 : * @return handle representing the request.
5014 : */
5015 :
5016 2 : GDALAsyncReaderH CPL_STDCALL GDALBeginAsyncReader(
5017 : GDALDatasetH hDS, int nXOff, int nYOff, int nXSize, int nYSize, void *pBuf,
5018 : int nBufXSize, int nBufYSize, GDALDataType eBufType, int nBandCount,
5019 : int *panBandMap, int nPixelSpace, int nLineSpace, int nBandSpace,
5020 : CSLConstList papszOptions)
5021 :
5022 : {
5023 2 : VALIDATE_POINTER1(hDS, "GDALDataset", nullptr);
5024 : return static_cast<GDALAsyncReaderH>(
5025 2 : GDALDataset::FromHandle(hDS)->BeginAsyncReader(
5026 : nXOff, nYOff, nXSize, nYSize, pBuf, nBufXSize, nBufYSize, eBufType,
5027 : nBandCount, panBandMap, nPixelSpace, nLineSpace, nBandSpace,
5028 2 : const_cast<char **>(papszOptions)));
5029 : }
5030 :
5031 : /************************************************************************/
5032 : /* EndAsyncReader() */
5033 : /************************************************************************/
5034 :
5035 : /**
5036 : * End asynchronous request.
5037 : *
5038 : * This method destroys an asynchronous io request and recovers all
5039 : * resources associated with it.
5040 : *
5041 : * This method is the same as the C function GDALEndAsyncReader().
5042 : *
5043 : * @param poARIO pointer to a GDALAsyncReader
5044 : */
5045 :
5046 1 : void GDALDataset::EndAsyncReader(GDALAsyncReader *poARIO)
5047 : {
5048 1 : delete poARIO;
5049 1 : }
5050 :
5051 : /************************************************************************/
5052 : /* GDALEndAsyncReader() */
5053 : /************************************************************************/
5054 :
5055 : /**
5056 : * End asynchronous request.
5057 : *
5058 : * This method destroys an asynchronous io request and recovers all
5059 : * resources associated with it.
5060 : *
5061 : * This method is the same as the C++ method GDALDataset::EndAsyncReader().
5062 : *
5063 : * @param hDS handle to the dataset object.
5064 : * @param hAsyncReaderH handle returned by GDALBeginAsyncReader()
5065 : */
5066 :
5067 1 : void CPL_STDCALL GDALEndAsyncReader(GDALDatasetH hDS,
5068 : GDALAsyncReaderH hAsyncReaderH)
5069 : {
5070 1 : VALIDATE_POINTER0(hDS, "GDALDataset");
5071 1 : VALIDATE_POINTER0(hAsyncReaderH, "GDALAsyncReader");
5072 1 : GDALDataset::FromHandle(hDS)->EndAsyncReader(
5073 1 : static_cast<GDALAsyncReader *>(hAsyncReaderH));
5074 : }
5075 :
5076 : /************************************************************************/
5077 : /* CloseDependentDatasets() */
5078 : /************************************************************************/
5079 :
5080 : /**
5081 : * Drop references to any other datasets referenced by this dataset.
5082 : *
5083 : * This method should release any reference to other datasets (e.g. a VRT
5084 : * dataset to its sources), but not close the current dataset itself.
5085 : *
5086 : * If at least, one reference to a dependent dataset has been dropped,
5087 : * this method should return TRUE. Otherwise it *should* return FALSE.
5088 : * (Failure to return the proper value might result in infinite loop)
5089 : *
5090 : * This method can be called several times on a given dataset. After
5091 : * the first time, it should not do anything and return FALSE.
5092 : *
5093 : * The driver implementation may choose to destroy its raster bands,
5094 : * so be careful not to call any method on the raster bands afterwards.
5095 : *
5096 : * Basically the only safe action you can do after calling
5097 : * CloseDependentDatasets() is to call the destructor.
5098 : *
5099 : * Note: the only legitimate caller of CloseDependentDatasets() is
5100 : * GDALDriverManager::~GDALDriverManager()
5101 : *
5102 : * @return TRUE if at least one reference to another dataset has been dropped.
5103 : */
5104 19784 : int GDALDataset::CloseDependentDatasets()
5105 : {
5106 19784 : return oOvManager.CloseDependentDatasets();
5107 : }
5108 :
5109 : /************************************************************************/
5110 : /* ReportError() */
5111 : /************************************************************************/
5112 :
5113 : #ifndef DOXYGEN_XML
5114 : /**
5115 : * \brief Emits an error related to a dataset.
5116 : *
5117 : * This function is a wrapper for regular CPLError(). The only difference
5118 : * with CPLError() is that it prepends the error message with the dataset
5119 : * name.
5120 : *
5121 : * @param eErrClass one of CE_Warning, CE_Failure or CE_Fatal.
5122 : * @param err_no the error number (CPLE_*) from cpl_error.h.
5123 : * @param fmt a printf() style format string. Any additional arguments
5124 : * will be treated as arguments to fill in this format in a manner
5125 : * similar to printf().
5126 : *
5127 : */
5128 :
5129 104 : void GDALDataset::ReportError(CPLErr eErrClass, CPLErrorNum err_no,
5130 : const char *fmt, ...) const
5131 : {
5132 : va_list args;
5133 104 : va_start(args, fmt);
5134 104 : ReportErrorV(GetDescription(), eErrClass, err_no, fmt, args);
5135 104 : va_end(args);
5136 104 : }
5137 :
5138 : /**
5139 : * \brief Emits an error related to a dataset (static method)
5140 : *
5141 : * This function is a wrapper for regular CPLError(). The only difference
5142 : * with CPLError() is that it prepends the error message with the dataset
5143 : * name.
5144 : *
5145 : * @param pszDSName dataset name.
5146 : * @param eErrClass one of CE_Warning, CE_Failure or CE_Fatal.
5147 : * @param err_no the error number (CPLE_*) from cpl_error.h.
5148 : * @param fmt a printf() style format string. Any additional arguments
5149 : * will be treated as arguments to fill in this format in a manner
5150 : * similar to printf().
5151 : *
5152 : * @since GDAL 3.2.0
5153 : */
5154 :
5155 183 : void GDALDataset::ReportError(const char *pszDSName, CPLErr eErrClass,
5156 : CPLErrorNum err_no, const char *fmt, ...)
5157 : {
5158 : va_list args;
5159 183 : va_start(args, fmt);
5160 183 : ReportErrorV(pszDSName, eErrClass, err_no, fmt, args);
5161 183 : va_end(args);
5162 183 : }
5163 :
5164 287 : void GDALDataset::ReportErrorV(const char *pszDSName, CPLErr eErrClass,
5165 : CPLErrorNum err_no, const char *fmt,
5166 : va_list args)
5167 : {
5168 287 : pszDSName = CPLGetFilename(pszDSName);
5169 287 : if (pszDSName[0] != '\0')
5170 : {
5171 270 : CPLError(eErrClass, err_no, "%s",
5172 540 : std::string(pszDSName)
5173 270 : .append(": ")
5174 540 : .append(CPLString().vPrintf(fmt, args))
5175 : .c_str());
5176 : }
5177 : else
5178 : {
5179 17 : CPLErrorV(eErrClass, err_no, fmt, args);
5180 : }
5181 287 : }
5182 : #endif
5183 :
5184 : /************************************************************************/
5185 : /* GetMetadata() */
5186 : /************************************************************************/
5187 72633 : CSLConstList GDALDataset::GetMetadata(const char *pszDomain)
5188 : {
5189 : #ifndef WITHOUT_DERIVED
5190 72633 : if (pszDomain != nullptr && EQUAL(pszDomain, "DERIVED_SUBDATASETS"))
5191 : {
5192 10 : oDerivedMetadataList.Clear();
5193 :
5194 : // First condition: at least one raster band.
5195 10 : if (GetRasterCount() > 0)
5196 : {
5197 : // Check if there is at least one complex band.
5198 10 : bool hasAComplexBand = false;
5199 :
5200 19 : for (int rasterId = 1; rasterId <= GetRasterCount(); ++rasterId)
5201 : {
5202 11 : if (GDALDataTypeIsComplex(
5203 11 : GetRasterBand(rasterId)->GetRasterDataType()))
5204 : {
5205 2 : hasAComplexBand = true;
5206 2 : break;
5207 : }
5208 : }
5209 :
5210 10 : unsigned int nbSupportedDerivedDS = 0;
5211 : const DerivedDatasetDescription *poDDSDesc =
5212 10 : GDALGetDerivedDatasetDescriptions(&nbSupportedDerivedDS);
5213 :
5214 10 : int nNumDataset = 1;
5215 80 : for (unsigned int derivedId = 0; derivedId < nbSupportedDerivedDS;
5216 : ++derivedId)
5217 : {
5218 126 : if (hasAComplexBand ||
5219 126 : CPLString(poDDSDesc[derivedId].pszInputPixelType) !=
5220 : "complex")
5221 : {
5222 : oDerivedMetadataList.SetNameValue(
5223 : CPLSPrintf("DERIVED_SUBDATASET_%d_NAME", nNumDataset),
5224 : CPLSPrintf("DERIVED_SUBDATASET:%s:%s",
5225 22 : poDDSDesc[derivedId].pszDatasetName,
5226 22 : GetDescription()));
5227 :
5228 : CPLString osDesc(
5229 : CPLSPrintf("%s from %s",
5230 22 : poDDSDesc[derivedId].pszDatasetDescription,
5231 22 : GetDescription()));
5232 : oDerivedMetadataList.SetNameValue(
5233 : CPLSPrintf("DERIVED_SUBDATASET_%d_DESC", nNumDataset),
5234 22 : osDesc.c_str());
5235 :
5236 22 : nNumDataset++;
5237 : }
5238 : }
5239 : }
5240 10 : return oDerivedMetadataList.List();
5241 : }
5242 : #endif
5243 :
5244 72623 : return GDALMajorObject::GetMetadata(pszDomain);
5245 : }
5246 :
5247 : // clang-format off
5248 :
5249 : /**
5250 : * \fn GDALDataset::SetMetadata( char ** papszMetadata, const char * pszDomain)
5251 : * \brief Set metadata.
5252 : *
5253 : * CAUTION: depending on the format, older values of the updated information
5254 : * might still be found in the file in a "ghost" state, even if no longer
5255 : * accessible through the GDAL API. This is for example the case of the GTiff
5256 : * format (this is not a exhaustive list)
5257 : *
5258 : * The C function GDALSetMetadata() does the same thing as this method.
5259 : *
5260 : * @param papszMetadata the metadata in name=value string list format to
5261 : * apply.
5262 : * @param pszDomain the domain of interest. Use "" or NULL for the default
5263 : * domain.
5264 : * @return CE_None on success, CE_Failure on failure and CE_Warning if the
5265 : * metadata has been accepted, but is likely not maintained persistently
5266 : * by the underlying object between sessions.
5267 : */
5268 :
5269 : /**
5270 : * \fn GDALDataset::SetMetadataItem( const char * pszName, const char * pszValue, const char * pszDomain)
5271 : * \brief Set single metadata item.
5272 : *
5273 : * CAUTION: depending on the format, older values of the updated information
5274 : * might still be found in the file in a "ghost" state, even if no longer
5275 : * accessible through the GDAL API. This is for example the case of the GTiff
5276 : * format (this is not a exhaustive list)
5277 : *
5278 : * The C function GDALSetMetadataItem() does the same thing as this method.
5279 : *
5280 : * @param pszName the key for the metadata item to fetch.
5281 : * @param pszValue the value to assign to the key.
5282 : * @param pszDomain the domain to set within, use NULL for the default domain.
5283 : *
5284 : * @return CE_None on success, or an error code on failure.
5285 : */
5286 :
5287 : // clang-format on
5288 :
5289 : /************************************************************************/
5290 : /* GetMetadataDomainList() */
5291 : /************************************************************************/
5292 :
5293 1067 : char **GDALDataset::GetMetadataDomainList()
5294 : {
5295 1067 : char **currentDomainList = CSLDuplicate(oMDMD.GetDomainList());
5296 :
5297 : // Ensure that we do not duplicate DERIVED domain.
5298 1212 : if (GetRasterCount() > 0 &&
5299 145 : CSLFindString(currentDomainList, "DERIVED_SUBDATASETS") == -1)
5300 : {
5301 : currentDomainList =
5302 145 : CSLAddString(currentDomainList, "DERIVED_SUBDATASETS");
5303 : }
5304 1067 : return currentDomainList;
5305 : }
5306 :
5307 : /************************************************************************/
5308 : /* GetDriverName() */
5309 : /************************************************************************/
5310 :
5311 : /** Return driver name.
5312 : * @return driver name.
5313 : */
5314 2314 : const char *GDALDataset::GetDriverName() const
5315 : {
5316 2314 : if (poDriver)
5317 2302 : return poDriver->GetDescription();
5318 12 : return "";
5319 : }
5320 :
5321 : /************************************************************************/
5322 : /* GDALDatasetReleaseResultSet() */
5323 : /************************************************************************/
5324 :
5325 : /**
5326 : \brief Release results of ExecuteSQL().
5327 :
5328 : This function should only be used to deallocate OGRLayers resulting from
5329 : an ExecuteSQL() call on the same GDALDataset. Failure to deallocate a
5330 : results set before destroying the GDALDataset may cause errors.
5331 :
5332 : This function is the same as the C++ method GDALDataset::ReleaseResultSet()
5333 :
5334 :
5335 : @param hDS the dataset handle.
5336 : @param hLayer the result of a previous ExecuteSQL() call.
5337 :
5338 : */
5339 3518 : void GDALDatasetReleaseResultSet(GDALDatasetH hDS, OGRLayerH hLayer)
5340 :
5341 : {
5342 3518 : VALIDATE_POINTER0(hDS, "GDALDatasetReleaseResultSet");
5343 :
5344 : #ifdef OGRAPISPY_ENABLED
5345 3518 : if (bOGRAPISpyEnabled)
5346 6 : OGRAPISpy_DS_ReleaseResultSet(hDS, hLayer);
5347 : #endif
5348 :
5349 7036 : GDALDataset::FromHandle(hDS)->ReleaseResultSet(
5350 3518 : OGRLayer::FromHandle(hLayer));
5351 : }
5352 :
5353 : /************************************************************************/
5354 : /* GDALDatasetGetLayerCount() */
5355 : /************************************************************************/
5356 :
5357 : /**
5358 : \brief Get the number of layers in this dataset.
5359 :
5360 : This function is the same as the C++ method GDALDataset::GetLayerCount()
5361 :
5362 :
5363 : @param hDS the dataset handle.
5364 : @return layer count.
5365 : */
5366 :
5367 1498 : int GDALDatasetGetLayerCount(GDALDatasetH hDS)
5368 :
5369 : {
5370 1498 : VALIDATE_POINTER1(hDS, "GDALDatasetH", 0);
5371 :
5372 : #ifdef OGRAPISPY_ENABLED
5373 1498 : if (bOGRAPISpyEnabled)
5374 2 : OGRAPISpy_DS_GetLayerCount(reinterpret_cast<GDALDatasetH>(hDS));
5375 : #endif
5376 :
5377 1498 : return GDALDataset::FromHandle(hDS)->GetLayerCount();
5378 : }
5379 :
5380 : /************************************************************************/
5381 : /* GDALDatasetGetLayer() */
5382 : /************************************************************************/
5383 :
5384 : /**
5385 : \brief Fetch a layer by index.
5386 :
5387 : The returned layer remains owned by the
5388 : GDALDataset and should not be deleted by the application.
5389 :
5390 : This function is the same as the C++ method GDALDataset::GetLayer()
5391 :
5392 :
5393 : @param hDS the dataset handle.
5394 : @param iLayer a layer number between 0 and GetLayerCount()-1.
5395 :
5396 : @return the layer, or NULL if iLayer is out of range or an error occurs.
5397 : */
5398 :
5399 9948 : OGRLayerH GDALDatasetGetLayer(GDALDatasetH hDS, int iLayer)
5400 :
5401 : {
5402 9948 : VALIDATE_POINTER1(hDS, "GDALDatasetGetLayer", nullptr);
5403 :
5404 : OGRLayerH hLayer =
5405 9948 : OGRLayer::ToHandle(GDALDataset::FromHandle(hDS)->GetLayer(iLayer));
5406 :
5407 : #ifdef OGRAPISPY_ENABLED
5408 9948 : if (bOGRAPISpyEnabled)
5409 3 : OGRAPISpy_DS_GetLayer(hDS, iLayer, hLayer);
5410 : #endif
5411 :
5412 9948 : return hLayer;
5413 : }
5414 :
5415 : /************************************************************************/
5416 : /* GDALDatasetGetLayerByName() */
5417 : /************************************************************************/
5418 :
5419 : /**
5420 : \brief Fetch a layer by name.
5421 :
5422 : The returned layer remains owned by the
5423 : GDALDataset and should not be deleted by the application.
5424 :
5425 : This function is the same as the C++ method GDALDataset::GetLayerByName()
5426 :
5427 :
5428 : @param hDS the dataset handle.
5429 : @param pszName the layer name of the layer to fetch.
5430 :
5431 : @return the layer, or NULL if Layer is not found or an error occurs.
5432 : */
5433 :
5434 3414 : OGRLayerH GDALDatasetGetLayerByName(GDALDatasetH hDS, const char *pszName)
5435 :
5436 : {
5437 3414 : VALIDATE_POINTER1(hDS, "GDALDatasetGetLayerByName", nullptr);
5438 :
5439 3414 : OGRLayerH hLayer = OGRLayer::ToHandle(
5440 3414 : GDALDataset::FromHandle(hDS)->GetLayerByName(pszName));
5441 :
5442 : #ifdef OGRAPISPY_ENABLED
5443 3414 : if (bOGRAPISpyEnabled)
5444 4 : OGRAPISpy_DS_GetLayerByName(hDS, pszName, hLayer);
5445 : #endif
5446 :
5447 3414 : return hLayer;
5448 : }
5449 :
5450 : /************************************************************************/
5451 : /* GDALDatasetIsLayerPrivate() */
5452 : /************************************************************************/
5453 :
5454 : /**
5455 : \brief Returns true if the layer at the specified index is deemed a private or
5456 : system table, or an internal detail only.
5457 :
5458 : This function is the same as the C++ method GDALDataset::IsLayerPrivate()
5459 :
5460 : @since GDAL 3.4
5461 :
5462 : @param hDS the dataset handle.
5463 : @param iLayer a layer number between 0 and GetLayerCount()-1.
5464 :
5465 : @return true if the layer is a private or system table.
5466 : */
5467 :
5468 91 : int GDALDatasetIsLayerPrivate(GDALDatasetH hDS, int iLayer)
5469 :
5470 : {
5471 91 : VALIDATE_POINTER1(hDS, "GDALDatasetIsLayerPrivate", false);
5472 :
5473 91 : const bool res = GDALDataset::FromHandle(hDS)->IsLayerPrivate(iLayer);
5474 :
5475 91 : return res ? 1 : 0;
5476 : }
5477 :
5478 : /************************************************************************/
5479 : /* GetLayerIndex() */
5480 : /************************************************************************/
5481 :
5482 : /**
5483 : \brief Returns the index of the layer specified by name.
5484 :
5485 : @since GDAL 3.12
5486 :
5487 : @param pszName layer name (not NULL)
5488 :
5489 : @return an index >= 0, or -1 if not found.
5490 : */
5491 :
5492 3 : int GDALDataset::GetLayerIndex(const char *pszName) const
5493 : {
5494 3 : const int nLayerCount = GetLayerCount();
5495 3 : int iMatch = -1;
5496 6 : for (int i = 0; i < nLayerCount; ++i)
5497 : {
5498 5 : if (const auto poLayer = GetLayer(i))
5499 : {
5500 5 : const char *pszLayerName = poLayer->GetDescription();
5501 5 : if (strcmp(pszName, pszLayerName) == 0)
5502 : {
5503 2 : iMatch = i;
5504 2 : break;
5505 : }
5506 3 : else if (EQUAL(pszName, pszLayerName))
5507 : {
5508 0 : iMatch = i;
5509 : }
5510 : }
5511 : }
5512 3 : return iMatch;
5513 : }
5514 :
5515 : /************************************************************************/
5516 : /* GDALDatasetDeleteLayer() */
5517 : /************************************************************************/
5518 :
5519 : /**
5520 : \brief Delete the indicated layer from the datasource.
5521 :
5522 : If this function is supported
5523 : the ODsCDeleteLayer capability will test TRUE on the GDALDataset.
5524 :
5525 : This method is the same as the C++ method GDALDataset::DeleteLayer().
5526 :
5527 :
5528 : @param hDS the dataset handle.
5529 : @param iLayer the index of the layer to delete.
5530 :
5531 : @return OGRERR_NONE on success, or OGRERR_UNSUPPORTED_OPERATION if deleting
5532 : layers is not supported for this datasource.
5533 :
5534 : */
5535 41 : OGRErr GDALDatasetDeleteLayer(GDALDatasetH hDS, int iLayer)
5536 :
5537 : {
5538 41 : VALIDATE_POINTER1(hDS, "GDALDatasetH", OGRERR_INVALID_HANDLE);
5539 :
5540 : #ifdef OGRAPISPY_ENABLED
5541 41 : if (bOGRAPISpyEnabled)
5542 2 : OGRAPISpy_DS_DeleteLayer(hDS, iLayer);
5543 : #endif
5544 :
5545 41 : return GDALDataset::FromHandle(hDS)->DeleteLayer(iLayer);
5546 : }
5547 :
5548 : /************************************************************************/
5549 : /* CreateLayer() */
5550 : /************************************************************************/
5551 :
5552 : /**
5553 : \brief This method attempts to create a new layer on the dataset with the
5554 : indicated name, coordinate system, geometry type.
5555 :
5556 : The papszOptions argument
5557 : can be used to control driver specific creation options. These options are
5558 : normally documented in the format specific documentation.
5559 : That function will try to validate the creation option list passed to the
5560 : driver with the GDALValidateCreationOptions() method. This check can be
5561 : disabled by defining the configuration option GDAL_VALIDATE_CREATION_OPTIONS set
5562 : to NO.
5563 :
5564 : Drivers should extend the ICreateLayer() method and not
5565 : CreateLayer(). CreateLayer() adds validation of layer creation options, before
5566 : delegating the actual work to ICreateLayer().
5567 :
5568 : This method is the same as the C function GDALDatasetCreateLayer() and the
5569 : deprecated OGR_DS_CreateLayer().
5570 :
5571 : Example:
5572 :
5573 : \code{.cpp}
5574 : #include "gdal.h"
5575 : #include "cpl_string.h"
5576 :
5577 : ...
5578 :
5579 : OGRLayer *poLayer;
5580 : char **papszOptions;
5581 :
5582 : if( !poDS->TestCapability( ODsCCreateLayer ) )
5583 : {
5584 : ...
5585 : }
5586 :
5587 : papszOptions = CSLSetNameValue( papszOptions, "DIM", "2" );
5588 : poLayer = poDS->CreateLayer( "NewLayer", nullptr, wkbUnknown,
5589 : papszOptions );
5590 : CSLDestroy( papszOptions );
5591 :
5592 : if( poLayer == NULL )
5593 : {
5594 : ...
5595 : }
5596 : \endcode
5597 :
5598 : @param pszName the name for the new layer. This should ideally not
5599 : match any existing layer on the datasource.
5600 : @param poSpatialRef the coordinate system to use for the new layer, or NULL if
5601 : no coordinate system is available.
5602 : @param eGType the geometry type for the layer. Use wkbUnknown if there
5603 : are no constraints on the types geometry to be written.
5604 : @param papszOptions a StringList of name=value options. Options are driver
5605 : specific.
5606 :
5607 : @return NULL is returned on failure, or a new OGRLayer handle on success.
5608 :
5609 : */
5610 :
5611 8284 : OGRLayer *GDALDataset::CreateLayer(const char *pszName,
5612 : const OGRSpatialReference *poSpatialRef,
5613 : OGRwkbGeometryType eGType,
5614 : CSLConstList papszOptions)
5615 :
5616 : {
5617 8284 : if (eGType == wkbNone)
5618 : {
5619 524 : return CreateLayer(pszName, nullptr, papszOptions);
5620 : }
5621 : else
5622 : {
5623 15520 : OGRGeomFieldDefn oGeomFieldDefn("", eGType);
5624 7760 : oGeomFieldDefn.SetSpatialRef(poSpatialRef);
5625 7760 : return CreateLayer(pszName, &oGeomFieldDefn, papszOptions);
5626 : }
5627 : }
5628 :
5629 : /**
5630 : \brief This method attempts to create a new layer on the dataset with the
5631 : indicated name and geometry field definition.
5632 :
5633 : When poGeomFieldDefn is not null, most drivers should honor
5634 : poGeomFieldDefn->GetType() and poGeomFieldDefn->GetSpatialRef().
5635 : Drivers that honor poGeomFieldDefn->GetCoordinatePrecision() will declare the
5636 : GDAL_DCAP_HONOR_GEOM_COORDINATE_PRECISION capability. Drivers may honor
5637 : poGeomFieldDefn->GetNameRef() and poGeomFieldDefn->IsNullable(), but there are
5638 : very few currently.
5639 :
5640 : Note that even if a geometry coordinate precision is set and a driver honors the
5641 : GDAL_DCAP_HONOR_GEOM_COORDINATE_PRECISION capability, geometries passed to
5642 : OGRLayer::CreateFeature() and OGRLayer::SetFeature() are assumed to be compatible
5643 : with the coordinate precision. That is they are assumed to be valid once their
5644 : coordinates are rounded to it. If it might not be the case, the user may set
5645 : the OGR_APPLY_GEOM_SET_PRECISION configuration option before calling CreateFeature()
5646 : or SetFeature() to force the OGRGeometry::SetPrecision() method to be called on
5647 : the passed geometries.
5648 :
5649 : The papszOptions argument
5650 : can be used to control driver specific creation options. These options are
5651 : normally documented in the format specific documentation.
5652 : This function will try to validate the creation option list passed to the
5653 : driver with the GDALValidateCreationOptions() method. This check can be
5654 : disabled by defining the configuration option GDAL_VALIDATE_CREATION_OPTIONS set
5655 : to NO.
5656 :
5657 : Drivers should extend the ICreateLayer() method and not
5658 : CreateLayer(). CreateLayer() adds validation of layer creation options, before
5659 : delegating the actual work to ICreateLayer().
5660 :
5661 : This method is the same as the C function GDALDatasetCreateLayerFromGeomFieldDefn().
5662 :
5663 : @param pszName the name for the new layer. This should ideally not
5664 : match any existing layer on the datasource.
5665 : @param poGeomFieldDefn the geometry field definition to use for the new layer,
5666 : or NULL if there is no geometry field.
5667 : @param papszOptions a StringList of name=value options. Options are driver
5668 : specific.
5669 :
5670 : @return NULL is returned on failure, or a new OGRLayer handle on success.
5671 : @since 3.9
5672 :
5673 : */
5674 :
5675 9688 : OGRLayer *GDALDataset::CreateLayer(const char *pszName,
5676 : const OGRGeomFieldDefn *poGeomFieldDefn,
5677 : CSLConstList papszOptions)
5678 :
5679 : {
5680 9688 : if (CPLTestBool(
5681 : CPLGetConfigOption("GDAL_VALIDATE_CREATION_OPTIONS", "YES")))
5682 : {
5683 9688 : ValidateLayerCreationOptions(papszOptions);
5684 : }
5685 :
5686 : OGRLayer *poLayer;
5687 9688 : if (poGeomFieldDefn)
5688 : {
5689 8752 : OGRGeomFieldDefn oGeomFieldDefn(poGeomFieldDefn);
5690 8846 : if (OGR_GT_IsNonLinear(poGeomFieldDefn->GetType()) &&
5691 94 : !TestCapability(ODsCCurveGeometries))
5692 : {
5693 23 : oGeomFieldDefn.SetType(
5694 : OGR_GT_GetLinear(poGeomFieldDefn->GetType()));
5695 : }
5696 :
5697 8752 : poLayer = ICreateLayer(pszName, &oGeomFieldDefn, papszOptions);
5698 : }
5699 : else
5700 : {
5701 936 : poLayer = ICreateLayer(pszName, nullptr, papszOptions);
5702 : }
5703 : #ifdef DEBUG
5704 9759 : if (poLayer != nullptr && OGR_GT_IsNonLinear(poLayer->GetGeomType()) &&
5705 71 : !poLayer->TestCapability(OLCCurveGeometries))
5706 : {
5707 0 : CPLError(CE_Warning, CPLE_AppDefined,
5708 : "Inconsistent driver: Layer geometry type is non-linear, but "
5709 : "TestCapability(OLCCurveGeometries) returns FALSE.");
5710 : }
5711 : #endif
5712 :
5713 9688 : return poLayer;
5714 : }
5715 :
5716 : //! @cond Doxygen_Suppress
5717 :
5718 : // Technical override to avoid ambiguous choice between the old and new
5719 : // new CreateLayer() signatures.
5720 12 : OGRLayer *GDALDataset::CreateLayer(const char *pszName)
5721 : {
5722 24 : OGRGeomFieldDefn oGeomFieldDefn("", wkbUnknown);
5723 24 : return CreateLayer(pszName, &oGeomFieldDefn, nullptr);
5724 : }
5725 :
5726 : // Technical override to avoid ambiguous choice between the old and new
5727 : // new CreateLayer() signatures.
5728 1 : OGRLayer *GDALDataset::CreateLayer(const char *pszName, std::nullptr_t)
5729 : {
5730 2 : OGRGeomFieldDefn oGeomFieldDefn("", wkbUnknown);
5731 2 : return CreateLayer(pszName, &oGeomFieldDefn, nullptr);
5732 : }
5733 :
5734 : //!@endcond
5735 :
5736 : /************************************************************************/
5737 : /* GDALDatasetCreateLayer() */
5738 : /************************************************************************/
5739 :
5740 : /**
5741 : \brief This function attempts to create a new layer on the dataset with the
5742 : indicated name, coordinate system, geometry type.
5743 :
5744 : The papszOptions argument can be used to control driver specific creation
5745 : options. These options are normally documented in the format specific
5746 : documentation.
5747 :
5748 : This method is the same as the C++ method GDALDataset::CreateLayer().
5749 :
5750 : Example:
5751 :
5752 : \code{.c}
5753 : #include "gdal.h"
5754 : #include "cpl_string.h"
5755 :
5756 : ...
5757 :
5758 : OGRLayerH hLayer;
5759 : char **papszOptions;
5760 :
5761 : if( !GDALDatasetTestCapability( hDS, ODsCCreateLayer ) )
5762 : {
5763 : ...
5764 : }
5765 :
5766 : papszOptions = CSLSetNameValue( papszOptions, "DIM", "2" );
5767 : hLayer = GDALDatasetCreateLayer( hDS, "NewLayer", NULL, wkbUnknown,
5768 : papszOptions );
5769 : CSLDestroy( papszOptions );
5770 :
5771 : if( hLayer == NULL )
5772 : {
5773 : ...
5774 : }
5775 : \endcode
5776 :
5777 :
5778 : @param hDS the dataset handle
5779 : @param pszName the name for the new layer. This should ideally not
5780 : match any existing layer on the datasource.
5781 : @param hSpatialRef the coordinate system to use for the new layer, or NULL if
5782 : no coordinate system is available.
5783 : @param eGType the geometry type for the layer. Use wkbUnknown if there
5784 : are no constraints on the types geometry to be written.
5785 : @param papszOptions a StringList of name=value options. Options are driver
5786 : specific.
5787 :
5788 : @return NULL is returned on failure, or a new OGRLayer handle on success.
5789 :
5790 : */
5791 :
5792 6435 : OGRLayerH GDALDatasetCreateLayer(GDALDatasetH hDS, const char *pszName,
5793 : OGRSpatialReferenceH hSpatialRef,
5794 : OGRwkbGeometryType eGType,
5795 : CSLConstList papszOptions)
5796 :
5797 : {
5798 6435 : VALIDATE_POINTER1(hDS, "GDALDatasetCreateLayer", nullptr);
5799 :
5800 6435 : if (pszName == nullptr)
5801 : {
5802 0 : CPLError(CE_Failure, CPLE_ObjectNull,
5803 : "Name was NULL in GDALDatasetCreateLayer");
5804 0 : return nullptr;
5805 : }
5806 :
5807 : OGRLayerH hLayer =
5808 12870 : OGRLayer::ToHandle(GDALDataset::FromHandle(hDS)->CreateLayer(
5809 6435 : pszName, OGRSpatialReference::FromHandle(hSpatialRef), eGType,
5810 : const_cast<char **>(papszOptions)));
5811 :
5812 : #ifdef OGRAPISPY_ENABLED
5813 6435 : if (bOGRAPISpyEnabled)
5814 8 : OGRAPISpy_DS_CreateLayer(hDS, pszName, hSpatialRef, eGType,
5815 : const_cast<char **>(papszOptions), hLayer);
5816 : #endif
5817 :
5818 6435 : return hLayer;
5819 : }
5820 :
5821 : /************************************************************************/
5822 : /* GDALDatasetCreateLayerFromGeomFieldDefn() */
5823 : /************************************************************************/
5824 :
5825 : /**
5826 : \brief This function attempts to create a new layer on the dataset with the
5827 : indicated name and geometry field.
5828 :
5829 : When poGeomFieldDefn is not null, most drivers should honor
5830 : poGeomFieldDefn->GetType() and poGeomFieldDefn->GetSpatialRef().
5831 : Drivers that honor poGeomFieldDefn->GetCoordinatePrecision() will declare the
5832 : GDAL_DCAP_HONOR_GEOM_COORDINATE_PRECISION capability. Drivers may honor
5833 : poGeomFieldDefn->GetNameRef() and poGeomFieldDefn->IsNullable(), but there are
5834 : very few currently.
5835 :
5836 : Note that even if a geometry coordinate precision is set and a driver honors the
5837 : GDAL_DCAP_HONOR_GEOM_COORDINATE_PRECISION capability, geometries passed to
5838 : OGRLayer::CreateFeature() and OGRLayer::SetFeature() are assumed to be compatible
5839 : with the coordinate precision. That is they are assumed to be valid once their
5840 : coordinates are rounded to it. If it might not be the case, the user may set
5841 : the OGR_APPLY_GEOM_SET_PRECISION configuration option before calling CreateFeature()
5842 : or SetFeature() to force the OGRGeometry::SetPrecision() method to be called on
5843 : the passed geometries.
5844 :
5845 : The papszOptions argument can be used to control driver specific creation
5846 : options. These options are normally documented in the format specific
5847 : documentation.
5848 :
5849 : This method is the same as the C++ method GDALDataset::CreateLayer().
5850 :
5851 : @param hDS the dataset handle
5852 : @param pszName the name for the new layer. This should ideally not
5853 : match any existing layer on the datasource.
5854 : @param hGeomFieldDefn the geometry field definition. May be NULL to indicate
5855 : a non-spatial file (or if adding geometry fields later with OGR_L_CreateGeomField()
5856 : for drivers supporting that interface).
5857 : @param papszOptions a StringList of name=value options. Options are driver
5858 : specific.
5859 :
5860 : @return NULL is returned on failure, or a new OGRLayer handle on success.
5861 :
5862 : @since GDAL 3.9
5863 :
5864 : */
5865 :
5866 : OGRLayerH
5867 14 : GDALDatasetCreateLayerFromGeomFieldDefn(GDALDatasetH hDS, const char *pszName,
5868 : OGRGeomFieldDefnH hGeomFieldDefn,
5869 : CSLConstList papszOptions)
5870 :
5871 : {
5872 14 : VALIDATE_POINTER1(hDS, "GDALDatasetCreateLayerFromGeomFieldDefn", nullptr);
5873 :
5874 14 : if (!pszName)
5875 : {
5876 0 : CPLError(CE_Failure, CPLE_ObjectNull,
5877 : "Name was NULL in GDALDatasetCreateLayerFromGeomFieldDefn");
5878 0 : return nullptr;
5879 : }
5880 :
5881 : OGRLayerH hLayer =
5882 28 : OGRLayer::ToHandle(GDALDataset::FromHandle(hDS)->CreateLayer(
5883 14 : pszName, OGRGeomFieldDefn::FromHandle(hGeomFieldDefn),
5884 : papszOptions));
5885 14 : return hLayer;
5886 : }
5887 :
5888 : /************************************************************************/
5889 : /* GDALDatasetCopyLayer() */
5890 : /************************************************************************/
5891 :
5892 : /**
5893 : \brief Duplicate an existing layer.
5894 :
5895 : This function creates a new layer, duplicate the field definitions of the
5896 : source layer and then duplicate each features of the source layer.
5897 : The papszOptions argument
5898 : can be used to control driver specific creation options. These options are
5899 : normally documented in the format specific documentation.
5900 : The source layer may come from another dataset.
5901 :
5902 : This method is the same as the C++ method GDALDataset::CopyLayer()
5903 :
5904 :
5905 : @param hDS the dataset handle.
5906 : @param hSrcLayer source layer.
5907 : @param pszNewName the name of the layer to create.
5908 : @param papszOptions a StringList of name=value options. Options are driver
5909 : specific.
5910 :
5911 : @return a handle to the layer, or NULL if an error occurs.
5912 : */
5913 30 : OGRLayerH GDALDatasetCopyLayer(GDALDatasetH hDS, OGRLayerH hSrcLayer,
5914 : const char *pszNewName,
5915 : CSLConstList papszOptions)
5916 :
5917 : {
5918 30 : VALIDATE_POINTER1(hDS, "OGR_DS_CopyGDALDatasetCopyLayerLayer", nullptr);
5919 30 : VALIDATE_POINTER1(hSrcLayer, "GDALDatasetCopyLayer", nullptr);
5920 30 : VALIDATE_POINTER1(pszNewName, "GDALDatasetCopyLayer", nullptr);
5921 :
5922 60 : return OGRLayer::ToHandle(GDALDataset::FromHandle(hDS)->CopyLayer(
5923 60 : OGRLayer::FromHandle(hSrcLayer), pszNewName, papszOptions));
5924 : }
5925 :
5926 : /************************************************************************/
5927 : /* GDALDatasetExecuteSQL() */
5928 : /************************************************************************/
5929 :
5930 : /**
5931 : \brief Execute an SQL statement against the data store.
5932 :
5933 : The result of an SQL query is either NULL for statements that are in error,
5934 : or that have no results set, or an OGRLayer pointer representing a results
5935 : set from the query. Note that this OGRLayer is in addition to the layers
5936 : in the data store and must be destroyed with
5937 : ReleaseResultSet() before the dataset is closed
5938 : (destroyed).
5939 :
5940 : This method is the same as the C++ method GDALDataset::ExecuteSQL()
5941 :
5942 : For more information on the SQL dialect supported internally by OGR
5943 : review the <a href="https://gdal.org/user/ogr_sql_dialect.html">OGR SQL</a>
5944 : document. Some drivers (i.e. Oracle and PostGIS) pass the SQL directly through
5945 : to the underlying RDBMS.
5946 :
5947 : Starting with OGR 1.10, the <a
5948 : href="https://gdal.org/user/sql_sqlite_dialect.html">SQLITE dialect</a> can
5949 : also be used.
5950 :
5951 :
5952 : @param hDS the dataset handle.
5953 : @param pszStatement the SQL statement to execute.
5954 : @param hSpatialFilter geometry which represents a spatial filter. Can be NULL.
5955 :
5956 : @param pszDialect allows control of the statement dialect. If set to NULL, the
5957 : OGR SQL engine will be used, except for RDBMS drivers that will use their
5958 : dedicated SQL engine, unless OGRSQL is explicitly passed as the
5959 : dialect. Starting with OGR 1.10, the SQLITE dialect can also be used.
5960 :
5961 : @return an OGRLayer containing the results of the query. Deallocate with
5962 : GDALDatasetReleaseResultSet().
5963 :
5964 : */
5965 :
5966 10585 : OGRLayerH GDALDatasetExecuteSQL(GDALDatasetH hDS, const char *pszStatement,
5967 : OGRGeometryH hSpatialFilter,
5968 : const char *pszDialect)
5969 :
5970 : {
5971 10585 : VALIDATE_POINTER1(hDS, "GDALDatasetExecuteSQL", nullptr);
5972 :
5973 : OGRLayerH hLayer =
5974 21170 : OGRLayer::ToHandle(GDALDataset::FromHandle(hDS)->ExecuteSQL(
5975 10585 : pszStatement, OGRGeometry::FromHandle(hSpatialFilter), pszDialect));
5976 :
5977 : #ifdef OGRAPISPY_ENABLED
5978 10585 : if (bOGRAPISpyEnabled)
5979 4 : OGRAPISpy_DS_ExecuteSQL(hDS, pszStatement, hSpatialFilter, pszDialect,
5980 : hLayer);
5981 : #endif
5982 :
5983 10585 : return hLayer;
5984 : }
5985 :
5986 : /************************************************************************/
5987 : /* GDALDatasetAbortSQL() */
5988 : /************************************************************************/
5989 :
5990 : /**
5991 : \brief Abort any SQL statement running in the data store.
5992 :
5993 : This function can be safely called from any thread (pending that the dataset
5994 : object is still alive). Driver implementations will make sure that it can be
5995 : called in a thread-safe way.
5996 :
5997 : This might not be implemented by all drivers. At time of writing, only SQLite,
5998 : GPKG and PG drivers implement it
5999 :
6000 : This method is the same as the C++ method GDALDataset::AbortSQL()
6001 :
6002 : @since GDAL 3.2.0
6003 :
6004 : @param hDS the dataset handle.
6005 :
6006 : @return OGRERR_NONE on success, or OGRERR_UNSUPPORTED_OPERATION if AbortSQL
6007 : is not supported for this datasource. .
6008 :
6009 : */
6010 :
6011 6 : OGRErr GDALDatasetAbortSQL(GDALDatasetH hDS)
6012 :
6013 : {
6014 6 : VALIDATE_POINTER1(hDS, "GDALDatasetAbortSQL", OGRERR_FAILURE);
6015 6 : return GDALDataset::FromHandle(hDS)->AbortSQL();
6016 : }
6017 :
6018 : /************************************************************************/
6019 : /* GDALDatasetGetStyleTable() */
6020 : /************************************************************************/
6021 :
6022 : /**
6023 : \brief Returns dataset style table.
6024 :
6025 : This function is the same as the C++ method GDALDataset::GetStyleTable()
6026 :
6027 :
6028 : @param hDS the dataset handle
6029 : @return handle to a style table which should not be modified or freed by the
6030 : caller.
6031 : */
6032 :
6033 6 : OGRStyleTableH GDALDatasetGetStyleTable(GDALDatasetH hDS)
6034 :
6035 : {
6036 6 : VALIDATE_POINTER1(hDS, "OGR_DS_GetStyleTable", nullptr);
6037 :
6038 : return reinterpret_cast<OGRStyleTableH>(
6039 6 : GDALDataset::FromHandle(hDS)->GetStyleTable());
6040 : }
6041 :
6042 : /************************************************************************/
6043 : /* GDALDatasetSetStyleTableDirectly() */
6044 : /************************************************************************/
6045 :
6046 : /**
6047 : \brief Set dataset style table.
6048 :
6049 : This function operate exactly as GDALDatasetSetStyleTable() except that it
6050 : assumes ownership of the passed table.
6051 :
6052 : This function is the same as the C++ method
6053 : GDALDataset::SetStyleTableDirectly()
6054 :
6055 :
6056 : @param hDS the dataset handle
6057 : @param hStyleTable style table handle to set
6058 :
6059 : */
6060 :
6061 0 : void GDALDatasetSetStyleTableDirectly(GDALDatasetH hDS,
6062 : OGRStyleTableH hStyleTable)
6063 :
6064 : {
6065 0 : VALIDATE_POINTER0(hDS, "OGR_DS_SetStyleTableDirectly");
6066 :
6067 0 : GDALDataset::FromHandle(hDS)->SetStyleTableDirectly(
6068 0 : reinterpret_cast<OGRStyleTable *>(hStyleTable));
6069 : }
6070 :
6071 : /************************************************************************/
6072 : /* GDALDatasetSetStyleTable() */
6073 : /************************************************************************/
6074 :
6075 : /**
6076 : \brief Set dataset style table.
6077 :
6078 : This function operate exactly as GDALDatasetSetStyleTableDirectly() except that
6079 : it assumes ownership of the passed table.
6080 :
6081 : This function is the same as the C++ method GDALDataset::SetStyleTable()
6082 :
6083 :
6084 : @param hDS the dataset handle
6085 : @param hStyleTable style table handle to set
6086 :
6087 : */
6088 :
6089 5 : void GDALDatasetSetStyleTable(GDALDatasetH hDS, OGRStyleTableH hStyleTable)
6090 :
6091 : {
6092 5 : VALIDATE_POINTER0(hDS, "OGR_DS_SetStyleTable");
6093 5 : VALIDATE_POINTER0(hStyleTable, "OGR_DS_SetStyleTable");
6094 :
6095 5 : GDALDataset::FromHandle(hDS)->SetStyleTable(
6096 5 : reinterpret_cast<OGRStyleTable *>(hStyleTable));
6097 : }
6098 :
6099 : /************************************************************************/
6100 : /* ValidateLayerCreationOptions() */
6101 : /************************************************************************/
6102 :
6103 : //! @cond Doxygen_Suppress
6104 9688 : int GDALDataset::ValidateLayerCreationOptions(const char *const *papszLCO)
6105 : {
6106 : const char *pszOptionList =
6107 9688 : GetMetadataItem(GDAL_DS_LAYER_CREATIONOPTIONLIST);
6108 9688 : if (pszOptionList == nullptr && poDriver != nullptr)
6109 : {
6110 : pszOptionList =
6111 9647 : poDriver->GetMetadataItem(GDAL_DS_LAYER_CREATIONOPTIONLIST);
6112 : }
6113 19376 : CPLString osDataset;
6114 9688 : osDataset.Printf("dataset %s", GetDescription());
6115 9688 : return GDALValidateOptions(pszOptionList, papszLCO, "layer creation option",
6116 19376 : osDataset);
6117 : }
6118 :
6119 : //! @endcond
6120 :
6121 : /************************************************************************/
6122 : /* Release() */
6123 : /************************************************************************/
6124 :
6125 : /**
6126 : \brief Drop a reference to this dataset, and if the reference count drops to one
6127 : close (destroy) the dataset.
6128 :
6129 : This method is the same as the C function OGRReleaseDataSource().
6130 :
6131 : @deprecated. Use GDALClose() instead
6132 :
6133 : @return OGRERR_NONE on success or an error code.
6134 : */
6135 :
6136 4401 : OGRErr GDALDataset::Release()
6137 :
6138 : {
6139 4401 : ReleaseRef();
6140 4401 : return OGRERR_NONE;
6141 : }
6142 :
6143 : /************************************************************************/
6144 : /* GetRefCount() */
6145 : /************************************************************************/
6146 :
6147 : /**
6148 : \brief Fetch reference count.
6149 :
6150 : This method is the same as the C function OGR_DS_GetRefCount().
6151 :
6152 : @return the current reference count for the datasource object itself.
6153 : */
6154 :
6155 5287 : int GDALDataset::GetRefCount() const
6156 : {
6157 5287 : return nRefCount;
6158 : }
6159 :
6160 : /************************************************************************/
6161 : /* GetSummaryRefCount() */
6162 : /************************************************************************/
6163 :
6164 : /**
6165 : \brief Fetch reference count of datasource and all owned layers.
6166 :
6167 : This method is the same as the C function OGR_DS_GetSummaryRefCount().
6168 :
6169 : @deprecated
6170 :
6171 : @return the current summary reference count for the datasource and its layers.
6172 : */
6173 :
6174 0 : int GDALDataset::GetSummaryRefCount() const
6175 :
6176 : {
6177 0 : CPLMutexHolderD(m_poPrivate ? &(m_poPrivate->hMutex) : nullptr);
6178 0 : int nSummaryCount = nRefCount;
6179 0 : GDALDataset *poUseThis = const_cast<GDALDataset *>(this);
6180 :
6181 0 : for (int iLayer = 0; iLayer < poUseThis->GetLayerCount(); ++iLayer)
6182 0 : nSummaryCount += poUseThis->GetLayer(iLayer)->GetRefCount();
6183 :
6184 0 : return nSummaryCount;
6185 : }
6186 :
6187 : /************************************************************************/
6188 : /* ICreateLayer() */
6189 : /************************************************************************/
6190 :
6191 : /**
6192 : \brief This method attempts to create a new layer on the dataset with the
6193 : indicated name, coordinate system, geometry type.
6194 :
6195 : This method is reserved to implementation by drivers.
6196 :
6197 : The papszOptions argument can be used to control driver specific creation
6198 : options. These options are normally documented in the format specific
6199 : documentation.
6200 :
6201 : @param pszName the name for the new layer. This should ideally not
6202 : match any existing layer on the datasource.
6203 : @param poGeomFieldDefn the geometry field definition to use for the new layer,
6204 : or NULL if there is no geometry field.
6205 : @param papszOptions a StringList of name=value options. Options are driver
6206 : specific.
6207 :
6208 : @return NULL is returned on failure, or a new OGRLayer handle on success.
6209 :
6210 : */
6211 :
6212 : OGRLayer *
6213 16 : GDALDataset::ICreateLayer(CPL_UNUSED const char *pszName,
6214 : CPL_UNUSED const OGRGeomFieldDefn *poGeomFieldDefn,
6215 : CPL_UNUSED CSLConstList papszOptions)
6216 :
6217 : {
6218 16 : CPLError(CE_Failure, CPLE_NotSupported,
6219 : "CreateLayer() not supported by this dataset.");
6220 :
6221 16 : return nullptr;
6222 : }
6223 :
6224 : /************************************************************************/
6225 : /* CopyLayer() */
6226 : /************************************************************************/
6227 :
6228 : /**
6229 : \brief Duplicate an existing layer.
6230 :
6231 : This method creates a new layer, duplicate the field definitions of the
6232 : source layer and then duplicate each features of the source layer.
6233 : The papszOptions argument
6234 : can be used to control driver specific creation options. These options are
6235 : normally documented in the format specific documentation.
6236 : The source layer may come from another dataset.
6237 :
6238 : This method is the same as the C function GDALDatasetCopyLayer() and the
6239 : deprecated OGR_DS_CopyLayer().
6240 :
6241 : @param poSrcLayer source layer.
6242 : @param pszNewName the name of the layer to create.
6243 : @param papszOptions a StringList of name=value options. Options are driver
6244 : specific. There is a common option to set output layer
6245 : spatial reference: DST_SRSWKT. The option should be in
6246 : WKT format. Starting with GDAL 3.7, the common option
6247 : COPY_MD can be set to NO to prevent the default copying
6248 : of the metadata from the source layer to the target layer.
6249 :
6250 : @return a handle to the layer, or NULL if an error occurs.
6251 : */
6252 :
6253 146 : OGRLayer *GDALDataset::CopyLayer(OGRLayer *poSrcLayer, const char *pszNewName,
6254 : CSLConstList papszOptions)
6255 :
6256 : {
6257 : /* -------------------------------------------------------------------- */
6258 : /* Create the layer. */
6259 : /* -------------------------------------------------------------------- */
6260 146 : if (!TestCapability(ODsCCreateLayer))
6261 : {
6262 0 : CPLError(CE_Failure, CPLE_NotSupported,
6263 : "This datasource does not support creation of layers.");
6264 0 : return nullptr;
6265 : }
6266 :
6267 146 : const char *pszSRSWKT = CSLFetchNameValue(papszOptions, "DST_SRSWKT");
6268 292 : OGRSpatialReference oDstSpaRef(pszSRSWKT);
6269 146 : oDstSpaRef.SetAxisMappingStrategy(OAMS_TRADITIONAL_GIS_ORDER);
6270 146 : OGRFeatureDefn *poSrcDefn = poSrcLayer->GetLayerDefn();
6271 146 : OGRLayer *poDstLayer = nullptr;
6272 :
6273 292 : CPLStringList aosCleanedUpOptions(CSLDuplicate(papszOptions));
6274 146 : aosCleanedUpOptions.SetNameValue("DST_SRSWKT", nullptr);
6275 146 : aosCleanedUpOptions.SetNameValue("COPY_MD", nullptr);
6276 :
6277 146 : CPLErrorReset();
6278 146 : const int nSrcGeomFieldCount = poSrcDefn->GetGeomFieldCount();
6279 146 : if (nSrcGeomFieldCount == 1)
6280 : {
6281 94 : OGRGeomFieldDefn oGeomFieldDefn(poSrcDefn->GetGeomFieldDefn(0));
6282 94 : if (pszSRSWKT)
6283 5 : oGeomFieldDefn.SetSpatialRef(&oDstSpaRef);
6284 94 : poDstLayer = ICreateLayer(pszNewName, &oGeomFieldDefn,
6285 94 : aosCleanedUpOptions.List());
6286 : }
6287 : else
6288 : {
6289 : poDstLayer =
6290 52 : ICreateLayer(pszNewName, nullptr, aosCleanedUpOptions.List());
6291 : }
6292 :
6293 146 : if (poDstLayer == nullptr)
6294 0 : return nullptr;
6295 :
6296 146 : if (CPLTestBool(CSLFetchNameValueDef(papszOptions, "COPY_MD", "YES")))
6297 : {
6298 145 : CSLConstList papszMD = poSrcLayer->GetMetadata();
6299 145 : if (papszMD)
6300 19 : poDstLayer->SetMetadata(papszMD);
6301 : }
6302 :
6303 : /* -------------------------------------------------------------------- */
6304 : /* Add fields. Default to copy all fields, and make sure to */
6305 : /* establish a mapping between indices, rather than names, in */
6306 : /* case the target datasource has altered it (e.g. Shapefile */
6307 : /* limited to 10 char field names). */
6308 : /* -------------------------------------------------------------------- */
6309 146 : const int nSrcFieldCount = poSrcDefn->GetFieldCount();
6310 :
6311 : // Initialize the index-to-index map to -1's.
6312 292 : std::vector<int> anMap(nSrcFieldCount, -1);
6313 :
6314 : // Caution: At the time of writing, the MapInfo driver
6315 : // returns NULL until a field has been added.
6316 146 : OGRFeatureDefn *poDstFDefn = poDstLayer->GetLayerDefn();
6317 146 : int nDstFieldCount = poDstFDefn ? poDstFDefn->GetFieldCount() : 0;
6318 337 : for (int iField = 0; iField < nSrcFieldCount; ++iField)
6319 : {
6320 191 : OGRFieldDefn *poSrcFieldDefn = poSrcDefn->GetFieldDefn(iField);
6321 382 : OGRFieldDefn oFieldDefn(poSrcFieldDefn);
6322 :
6323 : // The field may have been already created at layer creation.
6324 191 : int iDstField = -1;
6325 191 : if (poDstFDefn)
6326 191 : iDstField = poDstFDefn->GetFieldIndex(oFieldDefn.GetNameRef());
6327 191 : if (iDstField >= 0)
6328 : {
6329 0 : anMap[iField] = iDstField;
6330 : }
6331 191 : else if (poDstLayer->CreateField(&oFieldDefn) == OGRERR_NONE)
6332 : {
6333 : // Now that we've created a field, GetLayerDefn() won't return NULL.
6334 191 : if (poDstFDefn == nullptr)
6335 0 : poDstFDefn = poDstLayer->GetLayerDefn();
6336 :
6337 : // Sanity check: if it fails, the driver is buggy.
6338 382 : if (poDstFDefn != nullptr &&
6339 191 : poDstFDefn->GetFieldCount() != nDstFieldCount + 1)
6340 : {
6341 0 : CPLError(CE_Warning, CPLE_AppDefined,
6342 : "The output driver has claimed to have added the %s "
6343 : "field, but it did not!",
6344 : oFieldDefn.GetNameRef());
6345 : }
6346 : else
6347 : {
6348 191 : anMap[iField] = nDstFieldCount;
6349 191 : ++nDstFieldCount;
6350 : }
6351 : }
6352 : }
6353 :
6354 : /* -------------------------------------------------------------------- */
6355 146 : std::unique_ptr<OGRCoordinateTransformation> poCT;
6356 146 : const OGRSpatialReference *sourceSRS = poSrcLayer->GetSpatialRef();
6357 146 : if (sourceSRS != nullptr && pszSRSWKT != nullptr && !oDstSpaRef.IsEmpty() &&
6358 0 : sourceSRS->IsSame(&oDstSpaRef) == FALSE)
6359 : {
6360 0 : poCT.reset(OGRCreateCoordinateTransformation(sourceSRS, &oDstSpaRef));
6361 0 : if (nullptr == poCT)
6362 : {
6363 0 : CPLError(CE_Failure, CPLE_NotSupported,
6364 : "This input/output spatial reference is not supported.");
6365 0 : return nullptr;
6366 : }
6367 : }
6368 : /* -------------------------------------------------------------------- */
6369 : /* Create geometry fields. */
6370 : /* -------------------------------------------------------------------- */
6371 147 : if (nSrcGeomFieldCount > 1 &&
6372 1 : TestCapability(ODsCCreateGeomFieldAfterCreateLayer))
6373 : {
6374 :
6375 3 : for (int iField = 0; iField < nSrcGeomFieldCount; ++iField)
6376 : {
6377 2 : if (nullptr == pszSRSWKT)
6378 : {
6379 2 : poDstLayer->CreateGeomField(
6380 2 : poSrcDefn->GetGeomFieldDefn(iField));
6381 : }
6382 : else
6383 : {
6384 : OGRGeomFieldDefn *pDstGeomFieldDefn =
6385 0 : poSrcDefn->GetGeomFieldDefn(iField);
6386 0 : pDstGeomFieldDefn->SetSpatialRef(&oDstSpaRef);
6387 0 : poDstLayer->CreateGeomField(pDstGeomFieldDefn);
6388 : }
6389 : }
6390 : }
6391 :
6392 : /* -------------------------------------------------------------------- */
6393 : /* Check if the destination layer supports transactions and set a */
6394 : /* default number of features in a single transaction. */
6395 : /* -------------------------------------------------------------------- */
6396 : const int nGroupTransactions =
6397 146 : poDstLayer->TestCapability(OLCTransactions) ? 128 : 0;
6398 :
6399 : /* -------------------------------------------------------------------- */
6400 : /* Transfer features. */
6401 : /* -------------------------------------------------------------------- */
6402 146 : poSrcLayer->ResetReading();
6403 :
6404 146 : if (nGroupTransactions <= 0)
6405 : {
6406 : while (true)
6407 : {
6408 : auto poFeature =
6409 578 : std::unique_ptr<OGRFeature>(poSrcLayer->GetNextFeature());
6410 :
6411 578 : if (poFeature == nullptr)
6412 143 : break;
6413 :
6414 435 : CPLErrorReset();
6415 : auto poDstFeature =
6416 435 : std::make_unique<OGRFeature>(poDstLayer->GetLayerDefn());
6417 :
6418 435 : if (poDstFeature->SetFrom(poFeature.get(), anMap.data(), TRUE) !=
6419 : OGRERR_NONE)
6420 : {
6421 0 : CPLError(CE_Failure, CPLE_AppDefined,
6422 : "Unable to translate feature " CPL_FRMT_GIB
6423 : " from layer %s.",
6424 0 : poFeature->GetFID(), poSrcDefn->GetName());
6425 0 : return poDstLayer;
6426 : }
6427 :
6428 435 : if (nullptr != poCT)
6429 : {
6430 0 : for (int iField = 0; iField < nSrcGeomFieldCount; ++iField)
6431 : {
6432 0 : OGRGeometry *pGeom = poDstFeature->GetGeomFieldRef(iField);
6433 0 : if (nullptr == pGeom)
6434 0 : continue;
6435 :
6436 0 : const OGRErr eErr = pGeom->transform(poCT.get());
6437 0 : if (eErr == OGRERR_NONE)
6438 0 : continue;
6439 :
6440 0 : CPLError(CE_Failure, CPLE_AppDefined,
6441 : "Unable to transform geometry " CPL_FRMT_GIB
6442 : " from layer %s.",
6443 0 : poFeature->GetFID(), poSrcDefn->GetName());
6444 0 : return poDstLayer;
6445 : }
6446 : }
6447 :
6448 435 : poDstFeature->SetFID(poFeature->GetFID());
6449 :
6450 435 : CPLErrorReset();
6451 435 : if (poDstLayer->CreateFeature(poDstFeature.get()) != OGRERR_NONE)
6452 : {
6453 0 : return poDstLayer;
6454 : }
6455 435 : }
6456 : }
6457 : else
6458 : {
6459 3 : std::vector<std::unique_ptr<OGRFeature>> apoDstFeatures;
6460 : try
6461 : {
6462 3 : apoDstFeatures.resize(nGroupTransactions);
6463 : }
6464 0 : catch (const std::exception &e)
6465 : {
6466 0 : CPLError(CE_Failure, CPLE_OutOfMemory, "%s", e.what());
6467 0 : return poDstLayer;
6468 : }
6469 3 : bool bStopTransfer = false;
6470 6 : while (!bStopTransfer)
6471 : {
6472 : /* --------------------------------------------------------------------
6473 : */
6474 : /* Fill the array with features. */
6475 : /* --------------------------------------------------------------------
6476 : */
6477 : // Number of features in the temporary array.
6478 3 : int nFeatCount = 0; // Used after for.
6479 33 : for (nFeatCount = 0; nFeatCount < nGroupTransactions; ++nFeatCount)
6480 : {
6481 : auto poFeature =
6482 33 : std::unique_ptr<OGRFeature>(poSrcLayer->GetNextFeature());
6483 :
6484 33 : if (poFeature == nullptr)
6485 : {
6486 3 : bStopTransfer = true;
6487 3 : break;
6488 : }
6489 :
6490 30 : CPLErrorReset();
6491 30 : apoDstFeatures[nFeatCount] =
6492 60 : std::make_unique<OGRFeature>(poDstLayer->GetLayerDefn());
6493 :
6494 60 : if (apoDstFeatures[nFeatCount]->SetFrom(
6495 60 : poFeature.get(), anMap.data(), TRUE) != OGRERR_NONE)
6496 : {
6497 0 : CPLError(CE_Failure, CPLE_AppDefined,
6498 : "Unable to translate feature " CPL_FRMT_GIB
6499 : " from layer %s.",
6500 0 : poFeature->GetFID(), poSrcDefn->GetName());
6501 0 : bStopTransfer = true;
6502 0 : poFeature.reset();
6503 0 : break;
6504 : }
6505 :
6506 30 : if (nullptr != poCT)
6507 : {
6508 0 : for (int iField = 0; iField < nSrcGeomFieldCount; ++iField)
6509 : {
6510 : OGRGeometry *pGeom =
6511 0 : apoDstFeatures[nFeatCount]->GetGeomFieldRef(iField);
6512 0 : if (nullptr == pGeom)
6513 0 : continue;
6514 :
6515 0 : const OGRErr eErr = pGeom->transform(poCT.get());
6516 0 : if (eErr == OGRERR_NONE)
6517 0 : continue;
6518 :
6519 0 : CPLError(CE_Failure, CPLE_AppDefined,
6520 : "Unable to transform geometry " CPL_FRMT_GIB
6521 : " from layer %s.",
6522 0 : poFeature->GetFID(), poSrcDefn->GetName());
6523 0 : bStopTransfer = true;
6524 0 : poFeature.reset();
6525 0 : break;
6526 : }
6527 : }
6528 :
6529 30 : if (poFeature)
6530 : {
6531 30 : apoDstFeatures[nFeatCount]->SetFID(poFeature->GetFID());
6532 : }
6533 : }
6534 :
6535 3 : CPLErrorReset();
6536 3 : bool bStopTransaction = false;
6537 6 : while (!bStopTransaction)
6538 : {
6539 3 : bStopTransaction = true;
6540 3 : if (poDstLayer->StartTransaction() != OGRERR_NONE)
6541 0 : break;
6542 33 : for (int i = 0; i < nFeatCount; ++i)
6543 : {
6544 30 : if (poDstLayer->CreateFeature(apoDstFeatures[i].get()) !=
6545 : OGRERR_NONE)
6546 : {
6547 0 : bStopTransfer = true;
6548 0 : bStopTransaction = false;
6549 0 : break;
6550 : }
6551 30 : apoDstFeatures[i].reset();
6552 : }
6553 3 : if (bStopTransaction)
6554 : {
6555 3 : if (poDstLayer->CommitTransaction() != OGRERR_NONE)
6556 0 : break;
6557 : }
6558 : else
6559 : {
6560 0 : poDstLayer->RollbackTransaction();
6561 : }
6562 : }
6563 : }
6564 : }
6565 :
6566 146 : return poDstLayer;
6567 : }
6568 :
6569 : /************************************************************************/
6570 : /* DeleteLayer() */
6571 : /************************************************************************/
6572 :
6573 : /**
6574 : \fn GDALDataset::DeleteLayer(int)
6575 : \brief Delete the indicated layer from the datasource.
6576 :
6577 : If this method is supported
6578 : the ODsCDeleteLayer capability will test TRUE on the GDALDataset.
6579 :
6580 : This method is the same as the C function GDALDatasetDeleteLayer() and the
6581 : deprecated OGR_DS_DeleteLayer().
6582 :
6583 : @param iLayer the index of the layer to delete.
6584 :
6585 : @return OGRERR_NONE on success, or OGRERR_UNSUPPORTED_OPERATION if deleting
6586 : layers is not supported for this datasource.
6587 :
6588 : */
6589 :
6590 389 : OGRErr GDALDataset::DeleteLayer(CPL_UNUSED int iLayer)
6591 :
6592 : {
6593 389 : CPLError(CE_Failure, CPLE_NotSupported,
6594 : "DeleteLayer() not supported by this dataset.");
6595 :
6596 389 : return OGRERR_UNSUPPORTED_OPERATION;
6597 : }
6598 :
6599 : /************************************************************************/
6600 : /* GetLayerByName() */
6601 : /************************************************************************/
6602 :
6603 : /**
6604 : \brief Fetch a layer by name.
6605 :
6606 : The returned layer remains owned by the
6607 : GDALDataset and should not be deleted by the application.
6608 :
6609 : This method is the same as the C function GDALDatasetGetLayerByName() and the
6610 : deprecated OGR_DS_GetLayerByName().
6611 :
6612 : @param pszName the layer name of the layer to fetch.
6613 :
6614 : @return the layer, or NULL if Layer is not found or an error occurs.
6615 : */
6616 :
6617 30054 : OGRLayer *GDALDataset::GetLayerByName(const char *pszName)
6618 :
6619 : {
6620 60108 : CPLMutexHolderD(m_poPrivate ? &(m_poPrivate->hMutex) : nullptr);
6621 :
6622 30054 : if (!pszName)
6623 0 : return nullptr;
6624 :
6625 : // First a case sensitive check.
6626 932613 : for (int i = 0; i < GetLayerCount(); ++i)
6627 : {
6628 914396 : OGRLayer *poLayer = GetLayer(i);
6629 :
6630 914396 : if (strcmp(pszName, poLayer->GetName()) == 0)
6631 11837 : return poLayer;
6632 : }
6633 :
6634 : // Then case insensitive.
6635 893828 : for (int i = 0; i < GetLayerCount(); ++i)
6636 : {
6637 875835 : OGRLayer *poLayer = GetLayer(i);
6638 :
6639 875835 : if (EQUAL(pszName, poLayer->GetName()))
6640 224 : return poLayer;
6641 : }
6642 :
6643 17993 : return nullptr;
6644 : }
6645 :
6646 : //! @cond Doxygen_Suppress
6647 : /************************************************************************/
6648 : /* ProcessSQLCreateIndex() */
6649 : /* */
6650 : /* The correct syntax for creating an index in our dialect of */
6651 : /* SQL is: */
6652 : /* */
6653 : /* CREATE INDEX ON <layername> USING <columnname> */
6654 : /************************************************************************/
6655 :
6656 28 : OGRErr GDALDataset::ProcessSQLCreateIndex(const char *pszSQLCommand)
6657 :
6658 : {
6659 28 : char **papszTokens = CSLTokenizeString(pszSQLCommand);
6660 :
6661 : /* -------------------------------------------------------------------- */
6662 : /* Do some general syntax checking. */
6663 : /* -------------------------------------------------------------------- */
6664 56 : if (CSLCount(papszTokens) != 6 || !EQUAL(papszTokens[0], "CREATE") ||
6665 84 : !EQUAL(papszTokens[1], "INDEX") || !EQUAL(papszTokens[2], "ON") ||
6666 28 : !EQUAL(papszTokens[4], "USING"))
6667 : {
6668 0 : CSLDestroy(papszTokens);
6669 0 : CPLError(CE_Failure, CPLE_AppDefined,
6670 : "Syntax error in CREATE INDEX command.\n"
6671 : "Was '%s'\n"
6672 : "Should be of form 'CREATE INDEX ON <table> USING <field>'",
6673 : pszSQLCommand);
6674 0 : return OGRERR_FAILURE;
6675 : }
6676 :
6677 : /* -------------------------------------------------------------------- */
6678 : /* Find the named layer. */
6679 : /* -------------------------------------------------------------------- */
6680 28 : OGRLayer *poLayer = GetLayerByName(papszTokens[3]);
6681 28 : if (poLayer == nullptr)
6682 : {
6683 0 : CPLError(CE_Failure, CPLE_AppDefined,
6684 : "CREATE INDEX ON failed, no such layer as `%s'.",
6685 0 : papszTokens[3]);
6686 0 : CSLDestroy(papszTokens);
6687 0 : return OGRERR_FAILURE;
6688 : }
6689 :
6690 : /* -------------------------------------------------------------------- */
6691 : /* Does this layer even support attribute indexes? */
6692 : /* -------------------------------------------------------------------- */
6693 28 : if (poLayer->GetIndex() == nullptr)
6694 : {
6695 0 : CPLError(CE_Failure, CPLE_AppDefined,
6696 : "CREATE INDEX ON not supported by this driver.");
6697 0 : CSLDestroy(papszTokens);
6698 0 : return OGRERR_FAILURE;
6699 : }
6700 :
6701 : /* -------------------------------------------------------------------- */
6702 : /* Find the named field. */
6703 : /* -------------------------------------------------------------------- */
6704 28 : int i = poLayer->GetLayerDefn()->GetFieldIndex(papszTokens[5]);
6705 :
6706 28 : CSLDestroy(papszTokens);
6707 :
6708 28 : if (i >= poLayer->GetLayerDefn()->GetFieldCount())
6709 : {
6710 0 : CPLError(CE_Failure, CPLE_AppDefined, "`%s' failed, field not found.",
6711 : pszSQLCommand);
6712 0 : return OGRERR_FAILURE;
6713 : }
6714 :
6715 : /* -------------------------------------------------------------------- */
6716 : /* Attempt to create the index. */
6717 : /* -------------------------------------------------------------------- */
6718 28 : OGRErr eErr = poLayer->GetIndex()->CreateIndex(i);
6719 28 : if (eErr == OGRERR_NONE)
6720 : {
6721 28 : eErr = poLayer->GetIndex()->IndexAllFeatures(i);
6722 : }
6723 : else
6724 : {
6725 0 : if (strlen(CPLGetLastErrorMsg()) == 0)
6726 0 : CPLError(CE_Failure, CPLE_AppDefined, "Cannot '%s'", pszSQLCommand);
6727 : }
6728 :
6729 28 : return eErr;
6730 : }
6731 :
6732 : /************************************************************************/
6733 : /* ProcessSQLDropIndex() */
6734 : /* */
6735 : /* The correct syntax for dropping one or more indexes in */
6736 : /* the OGR SQL dialect is: */
6737 : /* */
6738 : /* DROP INDEX ON <layername> [USING <columnname>] */
6739 : /************************************************************************/
6740 :
6741 10 : OGRErr GDALDataset::ProcessSQLDropIndex(const char *pszSQLCommand)
6742 :
6743 : {
6744 10 : char **papszTokens = CSLTokenizeString(pszSQLCommand);
6745 :
6746 : /* -------------------------------------------------------------------- */
6747 : /* Do some general syntax checking. */
6748 : /* -------------------------------------------------------------------- */
6749 20 : if ((CSLCount(papszTokens) != 4 && CSLCount(papszTokens) != 6) ||
6750 10 : !EQUAL(papszTokens[0], "DROP") || !EQUAL(papszTokens[1], "INDEX") ||
6751 30 : !EQUAL(papszTokens[2], "ON") ||
6752 10 : (CSLCount(papszTokens) == 6 && !EQUAL(papszTokens[4], "USING")))
6753 : {
6754 0 : CSLDestroy(papszTokens);
6755 0 : CPLError(CE_Failure, CPLE_AppDefined,
6756 : "Syntax error in DROP INDEX command.\n"
6757 : "Was '%s'\n"
6758 : "Should be of form 'DROP INDEX ON <table> [USING <field>]'",
6759 : pszSQLCommand);
6760 0 : return OGRERR_FAILURE;
6761 : }
6762 :
6763 : /* -------------------------------------------------------------------- */
6764 : /* Find the named layer. */
6765 : /* -------------------------------------------------------------------- */
6766 10 : OGRLayer *poLayer = GetLayerByName(papszTokens[3]);
6767 10 : if (poLayer == nullptr)
6768 : {
6769 0 : CPLError(CE_Failure, CPLE_AppDefined,
6770 : "DROP INDEX ON failed, no such layer as `%s'.",
6771 0 : papszTokens[3]);
6772 0 : CSLDestroy(papszTokens);
6773 0 : return OGRERR_FAILURE;
6774 : }
6775 :
6776 : /* -------------------------------------------------------------------- */
6777 : /* Does this layer even support attribute indexes? */
6778 : /* -------------------------------------------------------------------- */
6779 10 : if (poLayer->GetIndex() == nullptr)
6780 : {
6781 0 : CPLError(CE_Failure, CPLE_AppDefined,
6782 : "Indexes not supported by this driver.");
6783 0 : CSLDestroy(papszTokens);
6784 0 : return OGRERR_FAILURE;
6785 : }
6786 :
6787 : /* -------------------------------------------------------------------- */
6788 : /* If we were not given a field name, drop all indexes. */
6789 : /* -------------------------------------------------------------------- */
6790 10 : if (CSLCount(papszTokens) == 4)
6791 : {
6792 0 : for (int i = 0; i < poLayer->GetLayerDefn()->GetFieldCount(); ++i)
6793 : {
6794 : OGRAttrIndex *poAttrIndex;
6795 :
6796 0 : poAttrIndex = poLayer->GetIndex()->GetFieldIndex(i);
6797 0 : if (poAttrIndex != nullptr)
6798 : {
6799 0 : const OGRErr eErr = poLayer->GetIndex()->DropIndex(i);
6800 0 : if (eErr != OGRERR_NONE)
6801 : {
6802 0 : CSLDestroy(papszTokens);
6803 0 : return eErr;
6804 : }
6805 : }
6806 : }
6807 :
6808 0 : CSLDestroy(papszTokens);
6809 0 : return OGRERR_NONE;
6810 : }
6811 :
6812 : /* -------------------------------------------------------------------- */
6813 : /* Find the named field. */
6814 : /* -------------------------------------------------------------------- */
6815 10 : int i = poLayer->GetLayerDefn()->GetFieldIndex(papszTokens[5]);
6816 10 : CSLDestroy(papszTokens);
6817 :
6818 10 : if (i >= poLayer->GetLayerDefn()->GetFieldCount())
6819 : {
6820 0 : CPLError(CE_Failure, CPLE_AppDefined, "`%s' failed, field not found.",
6821 : pszSQLCommand);
6822 0 : return OGRERR_FAILURE;
6823 : }
6824 :
6825 : /* -------------------------------------------------------------------- */
6826 : /* Attempt to drop the index. */
6827 : /* -------------------------------------------------------------------- */
6828 10 : const OGRErr eErr = poLayer->GetIndex()->DropIndex(i);
6829 :
6830 10 : return eErr;
6831 : }
6832 :
6833 : /************************************************************************/
6834 : /* ProcessSQLDropTable() */
6835 : /* */
6836 : /* The correct syntax for dropping a table (layer) in the OGR SQL */
6837 : /* dialect is: */
6838 : /* */
6839 : /* DROP TABLE <layername> */
6840 : /************************************************************************/
6841 :
6842 500 : OGRErr GDALDataset::ProcessSQLDropTable(const char *pszSQLCommand)
6843 :
6844 : {
6845 500 : char **papszTokens = CSLTokenizeString(pszSQLCommand);
6846 :
6847 : /* -------------------------------------------------------------------- */
6848 : /* Do some general syntax checking. */
6849 : /* -------------------------------------------------------------------- */
6850 1000 : if (CSLCount(papszTokens) != 3 || !EQUAL(papszTokens[0], "DROP") ||
6851 500 : !EQUAL(papszTokens[1], "TABLE"))
6852 : {
6853 0 : CSLDestroy(papszTokens);
6854 0 : CPLError(CE_Failure, CPLE_AppDefined,
6855 : "Syntax error in DROP TABLE command.\n"
6856 : "Was '%s'\n"
6857 : "Should be of form 'DROP TABLE <table>'",
6858 : pszSQLCommand);
6859 0 : return OGRERR_FAILURE;
6860 : }
6861 :
6862 : /* -------------------------------------------------------------------- */
6863 : /* Find the named layer. */
6864 : /* -------------------------------------------------------------------- */
6865 500 : OGRLayer *poLayer = nullptr;
6866 :
6867 500 : int i = 0; // Used after for.
6868 40199 : for (; i < GetLayerCount(); ++i)
6869 : {
6870 40199 : poLayer = GetLayer(i);
6871 :
6872 40199 : if (poLayer != nullptr && EQUAL(poLayer->GetName(), papszTokens[2]))
6873 500 : break;
6874 39699 : poLayer = nullptr;
6875 : }
6876 :
6877 500 : if (poLayer == nullptr)
6878 : {
6879 0 : CPLError(CE_Failure, CPLE_AppDefined,
6880 0 : "DROP TABLE failed, no such layer as `%s'.", papszTokens[2]);
6881 0 : CSLDestroy(papszTokens);
6882 0 : return OGRERR_FAILURE;
6883 : }
6884 :
6885 500 : CSLDestroy(papszTokens);
6886 :
6887 : /* -------------------------------------------------------------------- */
6888 : /* Delete it. */
6889 : /* -------------------------------------------------------------------- */
6890 :
6891 500 : return DeleteLayer(i);
6892 : }
6893 :
6894 : //! @endcond
6895 :
6896 : /************************************************************************/
6897 : /* GDALDatasetParseSQLType() */
6898 : /************************************************************************/
6899 :
6900 : /* All arguments will be altered */
6901 6 : static OGRFieldType GDALDatasetParseSQLType(char *pszType, int &nWidth,
6902 : int &nPrecision)
6903 : {
6904 6 : char *pszParenthesis = strchr(pszType, '(');
6905 6 : if (pszParenthesis)
6906 : {
6907 4 : nWidth = atoi(pszParenthesis + 1);
6908 4 : *pszParenthesis = '\0';
6909 4 : char *pszComma = strchr(pszParenthesis + 1, ',');
6910 4 : if (pszComma)
6911 2 : nPrecision = atoi(pszComma + 1);
6912 : }
6913 :
6914 6 : OGRFieldType eType = OFTString;
6915 6 : if (EQUAL(pszType, "INTEGER"))
6916 0 : eType = OFTInteger;
6917 6 : else if (EQUAL(pszType, "INTEGER[]"))
6918 0 : eType = OFTIntegerList;
6919 6 : else if (EQUAL(pszType, "FLOAT") || EQUAL(pszType, "NUMERIC") ||
6920 4 : EQUAL(pszType, "DOUBLE") /* unofficial alias */ ||
6921 4 : EQUAL(pszType, "REAL") /* unofficial alias */)
6922 2 : eType = OFTReal;
6923 4 : else if (EQUAL(pszType, "FLOAT[]") || EQUAL(pszType, "NUMERIC[]") ||
6924 4 : EQUAL(pszType, "DOUBLE[]") /* unofficial alias */ ||
6925 4 : EQUAL(pszType, "REAL[]") /* unofficial alias */)
6926 0 : eType = OFTRealList;
6927 4 : else if (EQUAL(pszType, "CHARACTER") ||
6928 0 : EQUAL(pszType, "TEXT") /* unofficial alias */ ||
6929 0 : EQUAL(pszType, "STRING") /* unofficial alias */ ||
6930 0 : EQUAL(pszType, "VARCHAR") /* unofficial alias */)
6931 4 : eType = OFTString;
6932 0 : else if (EQUAL(pszType, "TEXT[]") ||
6933 0 : EQUAL(pszType, "STRING[]") /* unofficial alias */ ||
6934 0 : EQUAL(pszType, "VARCHAR[]") /* unofficial alias */)
6935 0 : eType = OFTStringList;
6936 0 : else if (EQUAL(pszType, "DATE"))
6937 0 : eType = OFTDate;
6938 0 : else if (EQUAL(pszType, "TIME"))
6939 0 : eType = OFTTime;
6940 0 : else if (EQUAL(pszType, "TIMESTAMP") ||
6941 0 : EQUAL(pszType, "DATETIME") /* unofficial alias */)
6942 0 : eType = OFTDateTime;
6943 : else
6944 0 : CPLError(CE_Warning, CPLE_NotSupported,
6945 : "Unsupported column type '%s'. Defaulting to VARCHAR",
6946 : pszType);
6947 :
6948 6 : return eType;
6949 : }
6950 :
6951 : /************************************************************************/
6952 : /* ProcessSQLAlterTableAddColumn() */
6953 : /* */
6954 : /* The correct syntax for adding a column in the OGR SQL */
6955 : /* dialect is: */
6956 : /* */
6957 : /* ALTER TABLE <layername> ADD [COLUMN] <columnname> <columntype> */
6958 : /************************************************************************/
6959 :
6960 : //! @cond Doxygen_Suppress
6961 2 : OGRErr GDALDataset::ProcessSQLAlterTableAddColumn(const char *pszSQLCommand)
6962 :
6963 : {
6964 2 : char **papszTokens = CSLTokenizeString(pszSQLCommand);
6965 :
6966 : /* -------------------------------------------------------------------- */
6967 : /* Do some general syntax checking. */
6968 : /* -------------------------------------------------------------------- */
6969 2 : const char *pszLayerName = nullptr;
6970 2 : const char *pszColumnName = nullptr;
6971 2 : int iTypeIndex = 0;
6972 2 : const int nTokens = CSLCount(papszTokens);
6973 :
6974 2 : if (nTokens >= 7 && EQUAL(papszTokens[0], "ALTER") &&
6975 2 : EQUAL(papszTokens[1], "TABLE") && EQUAL(papszTokens[3], "ADD") &&
6976 2 : EQUAL(papszTokens[4], "COLUMN"))
6977 : {
6978 1 : pszLayerName = papszTokens[2];
6979 1 : pszColumnName = papszTokens[5];
6980 1 : iTypeIndex = 6;
6981 : }
6982 1 : else if (nTokens >= 6 && EQUAL(papszTokens[0], "ALTER") &&
6983 1 : EQUAL(papszTokens[1], "TABLE") && EQUAL(papszTokens[3], "ADD"))
6984 : {
6985 1 : pszLayerName = papszTokens[2];
6986 1 : pszColumnName = papszTokens[4];
6987 1 : iTypeIndex = 5;
6988 : }
6989 : else
6990 : {
6991 0 : CSLDestroy(papszTokens);
6992 0 : CPLError(CE_Failure, CPLE_AppDefined,
6993 : "Syntax error in ALTER TABLE ADD COLUMN command.\n"
6994 : "Was '%s'\n"
6995 : "Should be of form 'ALTER TABLE <layername> ADD [COLUMN] "
6996 : "<columnname> <columntype>'",
6997 : pszSQLCommand);
6998 0 : return OGRERR_FAILURE;
6999 : }
7000 :
7001 : /* -------------------------------------------------------------------- */
7002 : /* Merge type components into a single string if there were split */
7003 : /* with spaces */
7004 : /* -------------------------------------------------------------------- */
7005 4 : CPLString osType;
7006 6 : for (int i = iTypeIndex; i < nTokens; ++i)
7007 : {
7008 4 : osType += papszTokens[i];
7009 4 : CPLFree(papszTokens[i]);
7010 : }
7011 2 : char *pszType = papszTokens[iTypeIndex] = CPLStrdup(osType);
7012 2 : papszTokens[iTypeIndex + 1] = nullptr;
7013 :
7014 : /* -------------------------------------------------------------------- */
7015 : /* Find the named layer. */
7016 : /* -------------------------------------------------------------------- */
7017 2 : OGRLayer *poLayer = GetLayerByName(pszLayerName);
7018 2 : if (poLayer == nullptr)
7019 : {
7020 0 : CPLError(CE_Failure, CPLE_AppDefined,
7021 : "%s failed, no such layer as `%s'.", pszSQLCommand,
7022 : pszLayerName);
7023 0 : CSLDestroy(papszTokens);
7024 0 : return OGRERR_FAILURE;
7025 : }
7026 :
7027 : /* -------------------------------------------------------------------- */
7028 : /* Add column. */
7029 : /* -------------------------------------------------------------------- */
7030 :
7031 2 : int nWidth = 0;
7032 2 : int nPrecision = 0;
7033 2 : OGRFieldType eType = GDALDatasetParseSQLType(pszType, nWidth, nPrecision);
7034 4 : OGRFieldDefn oFieldDefn(pszColumnName, eType);
7035 2 : oFieldDefn.SetWidth(nWidth);
7036 2 : oFieldDefn.SetPrecision(nPrecision);
7037 :
7038 2 : CSLDestroy(papszTokens);
7039 :
7040 2 : return poLayer->CreateField(&oFieldDefn);
7041 : }
7042 :
7043 : /************************************************************************/
7044 : /* ProcessSQLAlterTableDropColumn() */
7045 : /* */
7046 : /* The correct syntax for dropping a column in the OGR SQL */
7047 : /* dialect is: */
7048 : /* */
7049 : /* ALTER TABLE <layername> DROP [COLUMN] <columnname> */
7050 : /************************************************************************/
7051 :
7052 2 : OGRErr GDALDataset::ProcessSQLAlterTableDropColumn(const char *pszSQLCommand)
7053 :
7054 : {
7055 2 : char **papszTokens = CSLTokenizeString(pszSQLCommand);
7056 :
7057 : /* -------------------------------------------------------------------- */
7058 : /* Do some general syntax checking. */
7059 : /* -------------------------------------------------------------------- */
7060 2 : const char *pszLayerName = nullptr;
7061 2 : const char *pszColumnName = nullptr;
7062 3 : if (CSLCount(papszTokens) == 6 && EQUAL(papszTokens[0], "ALTER") &&
7063 4 : EQUAL(papszTokens[1], "TABLE") && EQUAL(papszTokens[3], "DROP") &&
7064 1 : EQUAL(papszTokens[4], "COLUMN"))
7065 : {
7066 1 : pszLayerName = papszTokens[2];
7067 1 : pszColumnName = papszTokens[5];
7068 : }
7069 2 : else if (CSLCount(papszTokens) == 5 && EQUAL(papszTokens[0], "ALTER") &&
7070 2 : EQUAL(papszTokens[1], "TABLE") && EQUAL(papszTokens[3], "DROP"))
7071 : {
7072 1 : pszLayerName = papszTokens[2];
7073 1 : pszColumnName = papszTokens[4];
7074 : }
7075 : else
7076 : {
7077 0 : CSLDestroy(papszTokens);
7078 0 : CPLError(CE_Failure, CPLE_AppDefined,
7079 : "Syntax error in ALTER TABLE DROP COLUMN command.\n"
7080 : "Was '%s'\n"
7081 : "Should be of form 'ALTER TABLE <layername> DROP [COLUMN] "
7082 : "<columnname>'",
7083 : pszSQLCommand);
7084 0 : return OGRERR_FAILURE;
7085 : }
7086 :
7087 : /* -------------------------------------------------------------------- */
7088 : /* Find the named layer. */
7089 : /* -------------------------------------------------------------------- */
7090 2 : OGRLayer *poLayer = GetLayerByName(pszLayerName);
7091 2 : if (poLayer == nullptr)
7092 : {
7093 0 : CPLError(CE_Failure, CPLE_AppDefined,
7094 : "%s failed, no such layer as `%s'.", pszSQLCommand,
7095 : pszLayerName);
7096 0 : CSLDestroy(papszTokens);
7097 0 : return OGRERR_FAILURE;
7098 : }
7099 :
7100 : /* -------------------------------------------------------------------- */
7101 : /* Find the field. */
7102 : /* -------------------------------------------------------------------- */
7103 :
7104 2 : int nFieldIndex = poLayer->GetLayerDefn()->GetFieldIndex(pszColumnName);
7105 2 : if (nFieldIndex < 0)
7106 : {
7107 0 : CPLError(CE_Failure, CPLE_AppDefined,
7108 : "%s failed, no such field as `%s'.", pszSQLCommand,
7109 : pszColumnName);
7110 0 : CSLDestroy(papszTokens);
7111 0 : return OGRERR_FAILURE;
7112 : }
7113 :
7114 : /* -------------------------------------------------------------------- */
7115 : /* Remove it. */
7116 : /* -------------------------------------------------------------------- */
7117 :
7118 2 : CSLDestroy(papszTokens);
7119 :
7120 2 : return poLayer->DeleteField(nFieldIndex);
7121 : }
7122 :
7123 : /************************************************************************/
7124 : /* ProcessSQLAlterTableRenameColumn() */
7125 : /* */
7126 : /* The correct syntax for renaming a column in the OGR SQL */
7127 : /* dialect is: */
7128 : /* */
7129 : /* ALTER TABLE <layername> RENAME [COLUMN] <oldname> TO <newname> */
7130 : /************************************************************************/
7131 :
7132 2 : OGRErr GDALDataset::ProcessSQLAlterTableRenameColumn(const char *pszSQLCommand)
7133 :
7134 : {
7135 2 : char **papszTokens = CSLTokenizeString(pszSQLCommand);
7136 :
7137 : /* -------------------------------------------------------------------- */
7138 : /* Do some general syntax checking. */
7139 : /* -------------------------------------------------------------------- */
7140 2 : const char *pszLayerName = nullptr;
7141 2 : const char *pszOldColName = nullptr;
7142 2 : const char *pszNewColName = nullptr;
7143 3 : if (CSLCount(papszTokens) == 8 && EQUAL(papszTokens[0], "ALTER") &&
7144 1 : EQUAL(papszTokens[1], "TABLE") && EQUAL(papszTokens[3], "RENAME") &&
7145 3 : EQUAL(papszTokens[4], "COLUMN") && EQUAL(papszTokens[6], "TO"))
7146 : {
7147 1 : pszLayerName = papszTokens[2];
7148 1 : pszOldColName = papszTokens[5];
7149 1 : pszNewColName = papszTokens[7];
7150 : }
7151 2 : else if (CSLCount(papszTokens) == 7 && EQUAL(papszTokens[0], "ALTER") &&
7152 1 : EQUAL(papszTokens[1], "TABLE") &&
7153 2 : EQUAL(papszTokens[3], "RENAME") && EQUAL(papszTokens[5], "TO"))
7154 : {
7155 1 : pszLayerName = papszTokens[2];
7156 1 : pszOldColName = papszTokens[4];
7157 1 : pszNewColName = papszTokens[6];
7158 : }
7159 : else
7160 : {
7161 0 : CSLDestroy(papszTokens);
7162 0 : CPLError(CE_Failure, CPLE_AppDefined,
7163 : "Syntax error in ALTER TABLE RENAME COLUMN command.\n"
7164 : "Was '%s'\n"
7165 : "Should be of form 'ALTER TABLE <layername> RENAME [COLUMN] "
7166 : "<columnname> TO <newname>'",
7167 : pszSQLCommand);
7168 0 : return OGRERR_FAILURE;
7169 : }
7170 :
7171 : /* -------------------------------------------------------------------- */
7172 : /* Find the named layer. */
7173 : /* -------------------------------------------------------------------- */
7174 2 : OGRLayer *poLayer = GetLayerByName(pszLayerName);
7175 2 : if (poLayer == nullptr)
7176 : {
7177 0 : CPLError(CE_Failure, CPLE_AppDefined,
7178 : "%s failed, no such layer as `%s'.", pszSQLCommand,
7179 : pszLayerName);
7180 0 : CSLDestroy(papszTokens);
7181 0 : return OGRERR_FAILURE;
7182 : }
7183 :
7184 : /* -------------------------------------------------------------------- */
7185 : /* Find the field. */
7186 : /* -------------------------------------------------------------------- */
7187 :
7188 : const int nFieldIndex =
7189 2 : poLayer->GetLayerDefn()->GetFieldIndex(pszOldColName);
7190 2 : if (nFieldIndex < 0)
7191 : {
7192 0 : CPLError(CE_Failure, CPLE_AppDefined,
7193 : "%s failed, no such field as `%s'.", pszSQLCommand,
7194 : pszOldColName);
7195 0 : CSLDestroy(papszTokens);
7196 0 : return OGRERR_FAILURE;
7197 : }
7198 :
7199 : /* -------------------------------------------------------------------- */
7200 : /* Rename column. */
7201 : /* -------------------------------------------------------------------- */
7202 : OGRFieldDefn *poOldFieldDefn =
7203 2 : poLayer->GetLayerDefn()->GetFieldDefn(nFieldIndex);
7204 4 : OGRFieldDefn oNewFieldDefn(poOldFieldDefn);
7205 2 : oNewFieldDefn.SetName(pszNewColName);
7206 :
7207 2 : CSLDestroy(papszTokens);
7208 :
7209 2 : return poLayer->AlterFieldDefn(nFieldIndex, &oNewFieldDefn,
7210 2 : ALTER_NAME_FLAG);
7211 : }
7212 :
7213 : /************************************************************************/
7214 : /* ProcessSQLAlterTableAlterColumn() */
7215 : /* */
7216 : /* The correct syntax for altering the type of a column in the */
7217 : /* OGR SQL dialect is: */
7218 : /* */
7219 : /* ALTER TABLE <layername> ALTER [COLUMN] <columnname> TYPE <newtype> */
7220 : /************************************************************************/
7221 :
7222 4 : OGRErr GDALDataset::ProcessSQLAlterTableAlterColumn(const char *pszSQLCommand)
7223 :
7224 : {
7225 4 : char **papszTokens = CSLTokenizeString(pszSQLCommand);
7226 :
7227 : /* -------------------------------------------------------------------- */
7228 : /* Do some general syntax checking. */
7229 : /* -------------------------------------------------------------------- */
7230 4 : const char *pszLayerName = nullptr;
7231 4 : const char *pszColumnName = nullptr;
7232 4 : int iTypeIndex = 0;
7233 4 : const int nTokens = CSLCount(papszTokens);
7234 :
7235 4 : if (nTokens >= 8 && EQUAL(papszTokens[0], "ALTER") &&
7236 2 : EQUAL(papszTokens[1], "TABLE") && EQUAL(papszTokens[3], "ALTER") &&
7237 2 : EQUAL(papszTokens[4], "COLUMN") && EQUAL(papszTokens[6], "TYPE"))
7238 : {
7239 2 : pszLayerName = papszTokens[2];
7240 2 : pszColumnName = papszTokens[5];
7241 2 : iTypeIndex = 7;
7242 : }
7243 2 : else if (nTokens >= 7 && EQUAL(papszTokens[0], "ALTER") &&
7244 2 : EQUAL(papszTokens[1], "TABLE") && EQUAL(papszTokens[3], "ALTER") &&
7245 2 : EQUAL(papszTokens[5], "TYPE"))
7246 : {
7247 2 : pszLayerName = papszTokens[2];
7248 2 : pszColumnName = papszTokens[4];
7249 2 : iTypeIndex = 6;
7250 : }
7251 : else
7252 : {
7253 0 : CSLDestroy(papszTokens);
7254 0 : CPLError(CE_Failure, CPLE_AppDefined,
7255 : "Syntax error in ALTER TABLE ALTER COLUMN command.\n"
7256 : "Was '%s'\n"
7257 : "Should be of form 'ALTER TABLE <layername> ALTER [COLUMN] "
7258 : "<columnname> TYPE <columntype>'",
7259 : pszSQLCommand);
7260 0 : return OGRERR_FAILURE;
7261 : }
7262 :
7263 : /* -------------------------------------------------------------------- */
7264 : /* Merge type components into a single string if there were split */
7265 : /* with spaces */
7266 : /* -------------------------------------------------------------------- */
7267 8 : CPLString osType;
7268 8 : for (int i = iTypeIndex; i < nTokens; ++i)
7269 : {
7270 4 : osType += papszTokens[i];
7271 4 : CPLFree(papszTokens[i]);
7272 : }
7273 4 : char *pszType = papszTokens[iTypeIndex] = CPLStrdup(osType);
7274 4 : papszTokens[iTypeIndex + 1] = nullptr;
7275 :
7276 : /* -------------------------------------------------------------------- */
7277 : /* Find the named layer. */
7278 : /* -------------------------------------------------------------------- */
7279 4 : OGRLayer *poLayer = GetLayerByName(pszLayerName);
7280 4 : if (poLayer == nullptr)
7281 : {
7282 0 : CPLError(CE_Failure, CPLE_AppDefined,
7283 : "%s failed, no such layer as `%s'.", pszSQLCommand,
7284 : pszLayerName);
7285 0 : CSLDestroy(papszTokens);
7286 0 : return OGRERR_FAILURE;
7287 : }
7288 :
7289 : /* -------------------------------------------------------------------- */
7290 : /* Find the field. */
7291 : /* -------------------------------------------------------------------- */
7292 :
7293 : const int nFieldIndex =
7294 4 : poLayer->GetLayerDefn()->GetFieldIndex(pszColumnName);
7295 4 : if (nFieldIndex < 0)
7296 : {
7297 0 : CPLError(CE_Failure, CPLE_AppDefined,
7298 : "%s failed, no such field as `%s'.", pszSQLCommand,
7299 : pszColumnName);
7300 0 : CSLDestroy(papszTokens);
7301 0 : return OGRERR_FAILURE;
7302 : }
7303 :
7304 : /* -------------------------------------------------------------------- */
7305 : /* Alter column. */
7306 : /* -------------------------------------------------------------------- */
7307 :
7308 : OGRFieldDefn *poOldFieldDefn =
7309 4 : poLayer->GetLayerDefn()->GetFieldDefn(nFieldIndex);
7310 8 : OGRFieldDefn oNewFieldDefn(poOldFieldDefn);
7311 :
7312 4 : int nWidth = 0;
7313 4 : int nPrecision = 0;
7314 4 : OGRFieldType eType = GDALDatasetParseSQLType(pszType, nWidth, nPrecision);
7315 4 : oNewFieldDefn.SetType(eType);
7316 4 : oNewFieldDefn.SetWidth(nWidth);
7317 4 : oNewFieldDefn.SetPrecision(nPrecision);
7318 :
7319 4 : int l_nFlags = 0;
7320 4 : if (poOldFieldDefn->GetType() != oNewFieldDefn.GetType())
7321 2 : l_nFlags |= ALTER_TYPE_FLAG;
7322 4 : if (poOldFieldDefn->GetWidth() != oNewFieldDefn.GetWidth() ||
7323 0 : poOldFieldDefn->GetPrecision() != oNewFieldDefn.GetPrecision())
7324 4 : l_nFlags |= ALTER_WIDTH_PRECISION_FLAG;
7325 :
7326 4 : CSLDestroy(papszTokens);
7327 :
7328 4 : if (l_nFlags == 0)
7329 0 : return OGRERR_NONE;
7330 :
7331 4 : return poLayer->AlterFieldDefn(nFieldIndex, &oNewFieldDefn, l_nFlags);
7332 : }
7333 :
7334 : //! @endcond
7335 :
7336 : /************************************************************************/
7337 : /* ExecuteSQL() */
7338 : /************************************************************************/
7339 :
7340 : /**
7341 : \brief Execute an SQL statement against the data store.
7342 :
7343 : The result of an SQL query is either NULL for statements that are in error,
7344 : or that have no results set, or an OGRLayer pointer representing a results
7345 : set from the query. Note that this OGRLayer is in addition to the layers
7346 : in the data store and must be destroyed with
7347 : ReleaseResultSet() before the dataset is closed
7348 : (destroyed).
7349 :
7350 : This method is the same as the C function GDALDatasetExecuteSQL() and the
7351 : deprecated OGR_DS_ExecuteSQL().
7352 :
7353 : For more information on the SQL dialect supported internally by OGR
7354 : review the <a href="https://gdal.org/user/ogr_sql_dialect.html">OGR SQL</a>
7355 : document. Some drivers (i.e. Oracle and PostGIS) pass the SQL directly through
7356 : to the underlying RDBMS.
7357 :
7358 : Starting with OGR 1.10, the <a
7359 : href="https://gdal.org/user/sql_sqlite_dialect.html">SQLITE dialect</a> can
7360 : also be used.
7361 :
7362 : @param pszStatement the SQL statement to execute.
7363 : @param poSpatialFilter geometry which represents a spatial filter. Can be NULL.
7364 : @param pszDialect allows control of the statement dialect. If set to NULL, the
7365 : OGR SQL engine will be used, except for RDBMS drivers that will use their
7366 : dedicated SQL engine, unless OGRSQL is explicitly passed as the
7367 : dialect. Starting with OGR 1.10, the SQLITE dialect can also be used.
7368 :
7369 : @return an OGRLayer containing the results of the query. Deallocate with
7370 : ReleaseResultSet().
7371 :
7372 : */
7373 :
7374 3576 : OGRLayer *GDALDataset::ExecuteSQL(const char *pszStatement,
7375 : OGRGeometry *poSpatialFilter,
7376 : const char *pszDialect)
7377 :
7378 : {
7379 3576 : return ExecuteSQL(pszStatement, poSpatialFilter, pszDialect, nullptr);
7380 : }
7381 :
7382 : //! @cond Doxygen_Suppress
7383 : OGRLayer *
7384 3584 : GDALDataset::ExecuteSQL(const char *pszStatement, OGRGeometry *poSpatialFilter,
7385 : const char *pszDialect,
7386 : swq_select_parse_options *poSelectParseOptions)
7387 :
7388 : {
7389 3584 : if (pszDialect != nullptr && EQUAL(pszDialect, "SQLite"))
7390 : {
7391 : #ifdef SQLITE_ENABLED
7392 650 : return OGRSQLiteExecuteSQL(this, pszStatement, poSpatialFilter,
7393 650 : pszDialect);
7394 : #else
7395 : CPLError(CE_Failure, CPLE_NotSupported,
7396 : "The SQLite driver needs to be compiled to support the "
7397 : "SQLite SQL dialect");
7398 : return nullptr;
7399 : #endif
7400 : }
7401 :
7402 2934 : if (pszDialect != nullptr && !EQUAL(pszDialect, "") &&
7403 14 : !EQUAL(pszDialect, "OGRSQL"))
7404 : {
7405 6 : std::string osDialectList = "'OGRSQL'";
7406 : #ifdef SQLITE_ENABLED
7407 3 : osDialectList += ", 'SQLITE'";
7408 : #endif
7409 : const char *pszDialects =
7410 3 : GetMetadataItem(GDAL_DMD_SUPPORTED_SQL_DIALECTS);
7411 3 : if (pszDialects)
7412 : {
7413 : const CPLStringList aosTokens(
7414 0 : CSLTokenizeString2(pszDialects, " ", 0));
7415 0 : for (int i = 0; i < aosTokens.size(); ++i)
7416 : {
7417 0 : if (!EQUAL(aosTokens[i], "OGRSQL") &&
7418 0 : !EQUAL(aosTokens[i], "SQLITE"))
7419 : {
7420 0 : osDialectList += ", '";
7421 0 : osDialectList += aosTokens[i];
7422 0 : osDialectList += "'";
7423 : }
7424 : }
7425 : }
7426 3 : CPLError(CE_Warning, CPLE_NotSupported,
7427 : "Dialect '%s' is unsupported. Only supported dialects are %s. "
7428 : "Defaulting to OGRSQL",
7429 : pszDialect, osDialectList.c_str());
7430 : }
7431 :
7432 : /* -------------------------------------------------------------------- */
7433 : /* Handle CREATE INDEX statements specially. */
7434 : /* -------------------------------------------------------------------- */
7435 2934 : if (STARTS_WITH_CI(pszStatement, "CREATE INDEX"))
7436 : {
7437 28 : ProcessSQLCreateIndex(pszStatement);
7438 28 : return nullptr;
7439 : }
7440 :
7441 : /* -------------------------------------------------------------------- */
7442 : /* Handle DROP INDEX statements specially. */
7443 : /* -------------------------------------------------------------------- */
7444 2906 : if (STARTS_WITH_CI(pszStatement, "DROP INDEX"))
7445 : {
7446 10 : ProcessSQLDropIndex(pszStatement);
7447 10 : return nullptr;
7448 : }
7449 :
7450 : /* -------------------------------------------------------------------- */
7451 : /* Handle DROP TABLE statements specially. */
7452 : /* -------------------------------------------------------------------- */
7453 2896 : if (STARTS_WITH_CI(pszStatement, "DROP TABLE"))
7454 : {
7455 500 : ProcessSQLDropTable(pszStatement);
7456 500 : return nullptr;
7457 : }
7458 :
7459 : /* -------------------------------------------------------------------- */
7460 : /* Handle ALTER TABLE statements specially. */
7461 : /* -------------------------------------------------------------------- */
7462 2396 : if (STARTS_WITH_CI(pszStatement, "ALTER TABLE"))
7463 : {
7464 11 : char **papszTokens = CSLTokenizeString(pszStatement);
7465 11 : const int nTokens = CSLCount(papszTokens);
7466 11 : if (nTokens >= 4 && EQUAL(papszTokens[3], "ADD"))
7467 : {
7468 2 : ProcessSQLAlterTableAddColumn(pszStatement);
7469 2 : CSLDestroy(papszTokens);
7470 2 : return nullptr;
7471 : }
7472 9 : else if (nTokens >= 4 && EQUAL(papszTokens[3], "DROP"))
7473 : {
7474 2 : ProcessSQLAlterTableDropColumn(pszStatement);
7475 2 : CSLDestroy(papszTokens);
7476 2 : return nullptr;
7477 : }
7478 7 : else if (nTokens == 6 && EQUAL(papszTokens[3], "RENAME") &&
7479 1 : EQUAL(papszTokens[4], "TO"))
7480 : {
7481 1 : const char *pszSrcTableName = papszTokens[2];
7482 1 : const char *pszDstTableName = papszTokens[5];
7483 1 : auto poSrcLayer = GetLayerByName(pszSrcTableName);
7484 1 : if (poSrcLayer)
7485 : {
7486 1 : CPL_IGNORE_RET_VAL(poSrcLayer->Rename(pszDstTableName));
7487 : }
7488 : else
7489 : {
7490 0 : CPLError(CE_Failure, CPLE_AppDefined, "Invalid layer name");
7491 : }
7492 1 : CSLDestroy(papszTokens);
7493 1 : return nullptr;
7494 : }
7495 6 : else if (nTokens >= 4 && EQUAL(papszTokens[3], "RENAME"))
7496 : {
7497 2 : ProcessSQLAlterTableRenameColumn(pszStatement);
7498 2 : CSLDestroy(papszTokens);
7499 2 : return nullptr;
7500 : }
7501 4 : else if (nTokens >= 4 && EQUAL(papszTokens[3], "ALTER"))
7502 : {
7503 4 : ProcessSQLAlterTableAlterColumn(pszStatement);
7504 4 : CSLDestroy(papszTokens);
7505 4 : return nullptr;
7506 : }
7507 : else
7508 : {
7509 0 : CPLError(CE_Failure, CPLE_AppDefined,
7510 : "Unsupported ALTER TABLE command : %s", pszStatement);
7511 0 : CSLDestroy(papszTokens);
7512 0 : return nullptr;
7513 : }
7514 : }
7515 :
7516 : /* -------------------------------------------------------------------- */
7517 : /* Preparse the SQL statement. */
7518 : /* -------------------------------------------------------------------- */
7519 2385 : swq_select *psSelectInfo = new swq_select();
7520 2385 : swq_custom_func_registrar *poCustomFuncRegistrar = nullptr;
7521 2385 : if (poSelectParseOptions != nullptr)
7522 8 : poCustomFuncRegistrar = poSelectParseOptions->poCustomFuncRegistrar;
7523 2385 : if (psSelectInfo->preparse(pszStatement,
7524 2385 : poCustomFuncRegistrar != nullptr) != CE_None)
7525 : {
7526 143 : delete psSelectInfo;
7527 143 : return nullptr;
7528 : }
7529 :
7530 : /* -------------------------------------------------------------------- */
7531 : /* If there is no UNION ALL, build result layer. */
7532 : /* -------------------------------------------------------------------- */
7533 2242 : if (psSelectInfo->poOtherSelect == nullptr)
7534 : {
7535 2236 : return BuildLayerFromSelectInfo(psSelectInfo, poSpatialFilter,
7536 2236 : pszDialect, poSelectParseOptions);
7537 : }
7538 :
7539 : /* -------------------------------------------------------------------- */
7540 : /* Build result union layer. */
7541 : /* -------------------------------------------------------------------- */
7542 6 : int nSrcLayers = 0;
7543 6 : OGRLayer **papoSrcLayers = nullptr;
7544 :
7545 6 : do
7546 : {
7547 12 : swq_select *psNextSelectInfo = psSelectInfo->poOtherSelect;
7548 12 : psSelectInfo->poOtherSelect = nullptr;
7549 :
7550 12 : OGRLayer *poLayer = BuildLayerFromSelectInfo(
7551 : psSelectInfo, poSpatialFilter, pszDialect, poSelectParseOptions);
7552 12 : if (poLayer == nullptr)
7553 : {
7554 : // Each source layer owns an independent select info.
7555 0 : for (int i = 0; i < nSrcLayers; ++i)
7556 0 : delete papoSrcLayers[i];
7557 0 : CPLFree(papoSrcLayers);
7558 :
7559 : // So we just have to destroy the remaining select info.
7560 0 : delete psNextSelectInfo;
7561 :
7562 0 : return nullptr;
7563 : }
7564 : else
7565 : {
7566 24 : papoSrcLayers = static_cast<OGRLayer **>(CPLRealloc(
7567 12 : papoSrcLayers, sizeof(OGRLayer *) * (nSrcLayers + 1)));
7568 12 : papoSrcLayers[nSrcLayers] = poLayer;
7569 12 : ++nSrcLayers;
7570 :
7571 12 : psSelectInfo = psNextSelectInfo;
7572 : }
7573 12 : } while (psSelectInfo != nullptr);
7574 :
7575 6 : return new OGRUnionLayer("SELECT", nSrcLayers, papoSrcLayers, TRUE);
7576 : }
7577 :
7578 : //! @endcond
7579 :
7580 : /************************************************************************/
7581 : /* AbortSQL() */
7582 : /************************************************************************/
7583 :
7584 : /**
7585 : \brief Abort any SQL statement running in the data store.
7586 :
7587 : This function can be safely called from any thread (pending that the dataset
7588 : object is still alive). Driver implementations will make sure that it can be
7589 : called in a thread-safe way.
7590 :
7591 : This might not be implemented by all drivers. At time of writing, only SQLite,
7592 : GPKG and PG drivers implement it
7593 :
7594 : This method is the same as the C method GDALDatasetAbortSQL()
7595 :
7596 : @since GDAL 3.2.0
7597 :
7598 :
7599 : */
7600 :
7601 0 : OGRErr GDALDataset::AbortSQL()
7602 : {
7603 0 : CPLError(CE_Failure, CPLE_NotSupported,
7604 : "AbortSQL is not supported for this driver.");
7605 0 : return OGRERR_UNSUPPORTED_OPERATION;
7606 : }
7607 :
7608 : /************************************************************************/
7609 : /* BuildLayerFromSelectInfo() */
7610 : /************************************************************************/
7611 :
7612 : struct GDALSQLParseInfo
7613 : {
7614 : swq_field_list sFieldList;
7615 : int nExtraDSCount;
7616 : GDALDataset **papoExtraDS;
7617 : char *pszWHERE;
7618 : };
7619 :
7620 2248 : OGRLayer *GDALDataset::BuildLayerFromSelectInfo(
7621 : swq_select *psSelectInfo, OGRGeometry *poSpatialFilter,
7622 : const char *pszDialect, swq_select_parse_options *poSelectParseOptions)
7623 : {
7624 4496 : std::unique_ptr<swq_select> psSelectInfoUnique(psSelectInfo);
7625 :
7626 2248 : std::unique_ptr<OGRGenSQLResultsLayer> poResults;
7627 : GDALSQLParseInfo *psParseInfo =
7628 2248 : BuildParseInfo(psSelectInfoUnique.get(), poSelectParseOptions);
7629 :
7630 2248 : if (psParseInfo)
7631 : {
7632 2213 : const auto nErrorCounter = CPLGetErrorCounter();
7633 4426 : poResults = std::make_unique<OGRGenSQLResultsLayer>(
7634 2213 : this, std::move(psSelectInfoUnique), poSpatialFilter,
7635 4426 : psParseInfo->pszWHERE, pszDialect);
7636 2290 : if (CPLGetErrorCounter() > nErrorCounter &&
7637 77 : CPLGetLastErrorType() != CE_None)
7638 77 : poResults.reset();
7639 : }
7640 :
7641 2248 : DestroyParseInfo(psParseInfo);
7642 :
7643 4496 : return poResults.release();
7644 : }
7645 :
7646 : /************************************************************************/
7647 : /* DestroyParseInfo() */
7648 : /************************************************************************/
7649 :
7650 : //! @cond Doxygen_Suppress
7651 2317 : void GDALDataset::DestroyParseInfo(GDALSQLParseInfo *psParseInfo)
7652 : {
7653 2317 : if (psParseInfo == nullptr)
7654 35 : return;
7655 :
7656 2282 : CPLFree(psParseInfo->sFieldList.names);
7657 2282 : CPLFree(psParseInfo->sFieldList.types);
7658 2282 : CPLFree(psParseInfo->sFieldList.table_ids);
7659 2282 : CPLFree(psParseInfo->sFieldList.ids);
7660 :
7661 : // Release the datasets we have opened with OGROpenShared()
7662 : // It is safe to do that as the 'new OGRGenSQLResultsLayer' itself
7663 : // has taken a reference on them, which it will release in its
7664 : // destructor.
7665 2289 : for (int iEDS = 0; iEDS < psParseInfo->nExtraDSCount; ++iEDS)
7666 7 : GDALClose(psParseInfo->papoExtraDS[iEDS]);
7667 :
7668 2282 : CPLFree(psParseInfo->papoExtraDS);
7669 2282 : CPLFree(psParseInfo->pszWHERE);
7670 2282 : CPLFree(psParseInfo);
7671 : }
7672 :
7673 : /************************************************************************/
7674 : /* BuildParseInfo() */
7675 : /************************************************************************/
7676 :
7677 : GDALSQLParseInfo *
7678 2282 : GDALDataset::BuildParseInfo(swq_select *psSelectInfo,
7679 : swq_select_parse_options *poSelectParseOptions)
7680 : {
7681 2282 : int nFirstLayerFirstSpecialFieldIndex = 0;
7682 :
7683 : GDALSQLParseInfo *psParseInfo =
7684 2282 : static_cast<GDALSQLParseInfo *>(CPLCalloc(1, sizeof(GDALSQLParseInfo)));
7685 :
7686 : /* -------------------------------------------------------------------- */
7687 : /* Validate that all the source tables are recognized, count */
7688 : /* fields. */
7689 : /* -------------------------------------------------------------------- */
7690 2282 : int nFieldCount = 0;
7691 :
7692 4632 : for (int iTable = 0; iTable < psSelectInfo->table_count; iTable++)
7693 : {
7694 2353 : swq_table_def *psTableDef = psSelectInfo->table_defs + iTable;
7695 2353 : GDALDataset *poTableDS = this;
7696 :
7697 2353 : if (psTableDef->data_source != nullptr)
7698 : {
7699 7 : poTableDS = GDALDataset::FromHandle(
7700 7 : OGROpenShared(psTableDef->data_source, FALSE, nullptr));
7701 7 : if (poTableDS == nullptr)
7702 : {
7703 0 : if (strlen(CPLGetLastErrorMsg()) == 0)
7704 0 : CPLError(CE_Failure, CPLE_AppDefined,
7705 : "Unable to open secondary datasource "
7706 : "`%s' required by JOIN.",
7707 : psTableDef->data_source);
7708 :
7709 0 : DestroyParseInfo(psParseInfo);
7710 0 : return nullptr;
7711 : }
7712 :
7713 : // Keep in an array to release at the end of this function.
7714 14 : psParseInfo->papoExtraDS = static_cast<GDALDataset **>(CPLRealloc(
7715 7 : psParseInfo->papoExtraDS,
7716 7 : sizeof(GDALDataset *) * (psParseInfo->nExtraDSCount + 1)));
7717 7 : psParseInfo->papoExtraDS[psParseInfo->nExtraDSCount++] = poTableDS;
7718 : }
7719 :
7720 : OGRLayer *poSrcLayer =
7721 2353 : poTableDS->GetLayerByName(psTableDef->table_name);
7722 :
7723 2353 : if (poSrcLayer == nullptr)
7724 : {
7725 3 : CPLError(CE_Failure, CPLE_AppDefined,
7726 : "SELECT from table %s failed, no such table/featureclass.",
7727 : psTableDef->table_name);
7728 :
7729 3 : DestroyParseInfo(psParseInfo);
7730 3 : return nullptr;
7731 : }
7732 :
7733 2350 : nFieldCount += poSrcLayer->GetLayerDefn()->GetFieldCount();
7734 2350 : if (iTable == 0 ||
7735 34 : (poSelectParseOptions &&
7736 34 : poSelectParseOptions->bAddSecondaryTablesGeometryFields))
7737 2313 : nFieldCount += poSrcLayer->GetLayerDefn()->GetGeomFieldCount();
7738 :
7739 2350 : const char *pszFID = poSrcLayer->GetFIDColumn();
7740 2961 : if (pszFID && !EQUAL(pszFID, "") && !EQUAL(pszFID, "FID") &&
7741 611 : poSrcLayer->GetLayerDefn()->GetFieldIndex(pszFID) < 0)
7742 561 : nFieldCount++;
7743 : }
7744 :
7745 : /* -------------------------------------------------------------------- */
7746 : /* Build the field list for all indicated tables. */
7747 : /* -------------------------------------------------------------------- */
7748 :
7749 2279 : psParseInfo->sFieldList.table_count = psSelectInfo->table_count;
7750 2279 : psParseInfo->sFieldList.table_defs = psSelectInfo->table_defs;
7751 :
7752 2279 : psParseInfo->sFieldList.count = 0;
7753 2279 : psParseInfo->sFieldList.names = static_cast<char **>(
7754 2279 : CPLMalloc(sizeof(char *) * (nFieldCount + SPECIAL_FIELD_COUNT)));
7755 4558 : psParseInfo->sFieldList.types = static_cast<swq_field_type *>(CPLMalloc(
7756 2279 : sizeof(swq_field_type) * (nFieldCount + SPECIAL_FIELD_COUNT)));
7757 2279 : psParseInfo->sFieldList.table_ids = static_cast<int *>(
7758 2279 : CPLMalloc(sizeof(int) * (nFieldCount + SPECIAL_FIELD_COUNT)));
7759 2279 : psParseInfo->sFieldList.ids = static_cast<int *>(
7760 2279 : CPLMalloc(sizeof(int) * (nFieldCount + SPECIAL_FIELD_COUNT)));
7761 :
7762 2279 : bool bIsFID64 = false;
7763 4629 : for (int iTable = 0; iTable < psSelectInfo->table_count; iTable++)
7764 : {
7765 2350 : swq_table_def *psTableDef = psSelectInfo->table_defs + iTable;
7766 2350 : GDALDataset *poTableDS = this;
7767 :
7768 2350 : if (psTableDef->data_source != nullptr)
7769 : {
7770 7 : poTableDS = GDALDataset::FromHandle(
7771 7 : OGROpenShared(psTableDef->data_source, FALSE, nullptr));
7772 7 : CPLAssert(poTableDS != nullptr);
7773 7 : poTableDS->Dereference();
7774 : }
7775 :
7776 : OGRLayer *poSrcLayer =
7777 2350 : poTableDS->GetLayerByName(psTableDef->table_name);
7778 :
7779 2350 : for (int iField = 0;
7780 18571 : iField < poSrcLayer->GetLayerDefn()->GetFieldCount(); iField++)
7781 : {
7782 : OGRFieldDefn *poFDefn =
7783 16221 : poSrcLayer->GetLayerDefn()->GetFieldDefn(iField);
7784 16221 : const int iOutField = psParseInfo->sFieldList.count++;
7785 32442 : psParseInfo->sFieldList.names[iOutField] =
7786 16221 : const_cast<char *>(poFDefn->GetNameRef());
7787 16221 : if (poFDefn->GetType() == OFTInteger)
7788 : {
7789 4089 : if (poFDefn->GetSubType() == OFSTBoolean)
7790 160 : psParseInfo->sFieldList.types[iOutField] = SWQ_BOOLEAN;
7791 : else
7792 3929 : psParseInfo->sFieldList.types[iOutField] = SWQ_INTEGER;
7793 : }
7794 12132 : else if (poFDefn->GetType() == OFTInteger64)
7795 : {
7796 760 : if (poFDefn->GetSubType() == OFSTBoolean)
7797 0 : psParseInfo->sFieldList.types[iOutField] = SWQ_BOOLEAN;
7798 : else
7799 760 : psParseInfo->sFieldList.types[iOutField] = SWQ_INTEGER64;
7800 : }
7801 11372 : else if (poFDefn->GetType() == OFTReal)
7802 2722 : psParseInfo->sFieldList.types[iOutField] = SWQ_FLOAT;
7803 8650 : else if (poFDefn->GetType() == OFTString)
7804 5596 : psParseInfo->sFieldList.types[iOutField] = SWQ_STRING;
7805 3054 : else if (poFDefn->GetType() == OFTTime)
7806 83 : psParseInfo->sFieldList.types[iOutField] = SWQ_TIME;
7807 2971 : else if (poFDefn->GetType() == OFTDate)
7808 143 : psParseInfo->sFieldList.types[iOutField] = SWQ_DATE;
7809 2828 : else if (poFDefn->GetType() == OFTDateTime)
7810 939 : psParseInfo->sFieldList.types[iOutField] = SWQ_TIMESTAMP;
7811 : else
7812 1889 : psParseInfo->sFieldList.types[iOutField] = SWQ_OTHER;
7813 :
7814 16221 : psParseInfo->sFieldList.table_ids[iOutField] = iTable;
7815 16221 : psParseInfo->sFieldList.ids[iOutField] = iField;
7816 : }
7817 :
7818 2350 : if (iTable == 0)
7819 : {
7820 2279 : nFirstLayerFirstSpecialFieldIndex = psParseInfo->sFieldList.count;
7821 : }
7822 :
7823 2350 : if (iTable == 0 ||
7824 34 : (poSelectParseOptions &&
7825 34 : poSelectParseOptions->bAddSecondaryTablesGeometryFields))
7826 : {
7827 :
7828 2313 : for (int iField = 0;
7829 4275 : iField < poSrcLayer->GetLayerDefn()->GetGeomFieldCount();
7830 : iField++)
7831 : {
7832 : OGRGeomFieldDefn *poFDefn =
7833 1962 : poSrcLayer->GetLayerDefn()->GetGeomFieldDefn(iField);
7834 1962 : const int iOutField = psParseInfo->sFieldList.count++;
7835 3924 : psParseInfo->sFieldList.names[iOutField] =
7836 1962 : const_cast<char *>(poFDefn->GetNameRef());
7837 1962 : if (*psParseInfo->sFieldList.names[iOutField] == '\0')
7838 1142 : psParseInfo->sFieldList.names[iOutField] =
7839 : const_cast<char *>(OGR_GEOMETRY_DEFAULT_NON_EMPTY_NAME);
7840 1962 : psParseInfo->sFieldList.types[iOutField] = SWQ_GEOMETRY;
7841 :
7842 1962 : psParseInfo->sFieldList.table_ids[iOutField] = iTable;
7843 1962 : psParseInfo->sFieldList.ids[iOutField] =
7844 1962 : GEOM_FIELD_INDEX_TO_ALL_FIELD_INDEX(
7845 : poSrcLayer->GetLayerDefn(), iField);
7846 : }
7847 : }
7848 :
7849 2351 : if (iTable == 0 && poSrcLayer->GetMetadataItem(OLMD_FID64) != nullptr &&
7850 1 : EQUAL(poSrcLayer->GetMetadataItem(OLMD_FID64), "YES"))
7851 : {
7852 1 : bIsFID64 = true;
7853 : }
7854 : }
7855 :
7856 : /* -------------------------------------------------------------------- */
7857 : /* Expand '*' in 'SELECT *' now before we add the pseudo fields */
7858 : /* -------------------------------------------------------------------- */
7859 2279 : const bool bAlwaysPrefixWithTableName =
7860 2321 : poSelectParseOptions &&
7861 42 : poSelectParseOptions->bAlwaysPrefixWithTableName;
7862 2279 : if (psSelectInfo->expand_wildcard(&psParseInfo->sFieldList,
7863 2279 : bAlwaysPrefixWithTableName) != CE_None)
7864 : {
7865 2 : DestroyParseInfo(psParseInfo);
7866 2 : return nullptr;
7867 : }
7868 :
7869 13662 : for (int iField = 0; iField < SPECIAL_FIELD_COUNT; iField++)
7870 : {
7871 11385 : psParseInfo->sFieldList.names[psParseInfo->sFieldList.count] =
7872 11385 : const_cast<char *>(SpecialFieldNames[iField]);
7873 11385 : psParseInfo->sFieldList.types[psParseInfo->sFieldList.count] =
7874 11385 : (iField == SPF_FID && bIsFID64) ? SWQ_INTEGER64
7875 : : SpecialFieldTypes[iField];
7876 11385 : psParseInfo->sFieldList.table_ids[psParseInfo->sFieldList.count] = 0;
7877 11385 : psParseInfo->sFieldList.ids[psParseInfo->sFieldList.count] =
7878 11385 : nFirstLayerFirstSpecialFieldIndex + iField;
7879 11385 : psParseInfo->sFieldList.count++;
7880 : }
7881 :
7882 : /* In the case a layer has an explicit FID column name, then add it */
7883 : /* so it can be selected */
7884 4625 : for (int iTable = 0; iTable < psSelectInfo->table_count; iTable++)
7885 : {
7886 2348 : swq_table_def *psTableDef = psSelectInfo->table_defs + iTable;
7887 2348 : GDALDataset *poTableDS = this;
7888 :
7889 2348 : if (psTableDef->data_source != nullptr)
7890 : {
7891 7 : poTableDS = GDALDataset::FromHandle(
7892 7 : OGROpenShared(psTableDef->data_source, FALSE, nullptr));
7893 7 : CPLAssert(poTableDS != nullptr);
7894 7 : poTableDS->Dereference();
7895 : }
7896 :
7897 : OGRLayer *poSrcLayer =
7898 2348 : poTableDS->GetLayerByName(psTableDef->table_name);
7899 :
7900 2348 : const char *pszFID = poSrcLayer->GetFIDColumn();
7901 2959 : if (pszFID && !EQUAL(pszFID, "") && !EQUAL(pszFID, "FID") &&
7902 611 : poSrcLayer->GetLayerDefn()->GetFieldIndex(pszFID) < 0)
7903 : {
7904 561 : const int iOutField = psParseInfo->sFieldList.count++;
7905 561 : psParseInfo->sFieldList.names[iOutField] =
7906 : const_cast<char *>(pszFID);
7907 561 : if (poSrcLayer->GetMetadataItem(OLMD_FID64) != nullptr &&
7908 0 : EQUAL(poSrcLayer->GetMetadataItem(OLMD_FID64), "YES"))
7909 : {
7910 0 : psParseInfo->sFieldList.types[iOutField] = SWQ_INTEGER64;
7911 : }
7912 : else
7913 : {
7914 561 : psParseInfo->sFieldList.types[iOutField] = SWQ_INTEGER;
7915 : }
7916 561 : psParseInfo->sFieldList.table_ids[iOutField] = iTable;
7917 1122 : psParseInfo->sFieldList.ids[iOutField] =
7918 561 : poSrcLayer->GetLayerDefn()->GetFieldCount() + SPF_FID;
7919 : }
7920 : }
7921 :
7922 : /* -------------------------------------------------------------------- */
7923 : /* Finish the parse operation. */
7924 : /* -------------------------------------------------------------------- */
7925 2277 : if (psSelectInfo->parse(&psParseInfo->sFieldList, poSelectParseOptions) !=
7926 : CE_None)
7927 : {
7928 30 : DestroyParseInfo(psParseInfo);
7929 30 : return nullptr;
7930 : }
7931 :
7932 : /* -------------------------------------------------------------------- */
7933 : /* Extract the WHERE expression to use separately. */
7934 : /* -------------------------------------------------------------------- */
7935 2247 : if (psSelectInfo->where_expr != nullptr)
7936 : {
7937 963 : psParseInfo->pszWHERE =
7938 963 : psSelectInfo->where_expr->Unparse(&psParseInfo->sFieldList, '"');
7939 : // CPLDebug( "OGR", "Unparse() -> %s", pszWHERE );
7940 : }
7941 :
7942 2247 : return psParseInfo;
7943 : }
7944 :
7945 : //! @endcond
7946 :
7947 : /************************************************************************/
7948 : /* ReleaseResultSet() */
7949 : /************************************************************************/
7950 :
7951 : /**
7952 : \brief Release results of ExecuteSQL().
7953 :
7954 : This method should only be used to deallocate OGRLayers resulting from
7955 : an ExecuteSQL() call on the same GDALDataset. Failure to deallocate a
7956 : results set before destroying the GDALDataset may cause errors.
7957 :
7958 : This method is the same as the C function GDALDatasetReleaseResultSet() and the
7959 : deprecated OGR_DS_ReleaseResultSet().
7960 :
7961 : @param poResultsSet the result of a previous ExecuteSQL() call.
7962 : */
7963 :
7964 2163 : void GDALDataset::ReleaseResultSet(OGRLayer *poResultsSet)
7965 :
7966 : {
7967 2163 : delete poResultsSet;
7968 2163 : }
7969 :
7970 : /************************************************************************/
7971 : /* GetStyleTable() */
7972 : /************************************************************************/
7973 :
7974 : /**
7975 : \brief Returns dataset style table.
7976 :
7977 : This method is the same as the C function GDALDatasetGetStyleTable() and the
7978 : deprecated OGR_DS_GetStyleTable().
7979 :
7980 : @return pointer to a style table which should not be modified or freed by the
7981 : caller.
7982 : */
7983 :
7984 952 : OGRStyleTable *GDALDataset::GetStyleTable()
7985 : {
7986 952 : return m_poStyleTable;
7987 : }
7988 :
7989 : /************************************************************************/
7990 : /* SetStyleTableDirectly() */
7991 : /************************************************************************/
7992 :
7993 : /**
7994 : \brief Set dataset style table.
7995 :
7996 : This method operate exactly as SetStyleTable() except that it
7997 : assumes ownership of the passed table.
7998 :
7999 : This method is the same as the C function GDALDatasetSetStyleTableDirectly()
8000 : and the deprecated OGR_DS_SetStyleTableDirectly().
8001 :
8002 : @param poStyleTable pointer to style table to set
8003 :
8004 : */
8005 0 : void GDALDataset::SetStyleTableDirectly(OGRStyleTable *poStyleTable)
8006 : {
8007 0 : if (m_poStyleTable)
8008 0 : delete m_poStyleTable;
8009 0 : m_poStyleTable = poStyleTable;
8010 0 : }
8011 :
8012 : /************************************************************************/
8013 : /* SetStyleTable() */
8014 : /************************************************************************/
8015 :
8016 : /**
8017 : \brief Set dataset style table.
8018 :
8019 : This method operate exactly as SetStyleTableDirectly() except
8020 : that it does not assume ownership of the passed table.
8021 :
8022 : This method is the same as the C function GDALDatasetSetStyleTable() and the
8023 : deprecated OGR_DS_SetStyleTable().
8024 :
8025 : @param poStyleTable pointer to style table to set
8026 :
8027 : */
8028 :
8029 948 : void GDALDataset::SetStyleTable(OGRStyleTable *poStyleTable)
8030 : {
8031 948 : if (m_poStyleTable)
8032 0 : delete m_poStyleTable;
8033 948 : if (poStyleTable)
8034 1 : m_poStyleTable = poStyleTable->Clone();
8035 948 : }
8036 :
8037 : /************************************************************************/
8038 : /* IsGenericSQLDialect() */
8039 : /************************************************************************/
8040 :
8041 : //! @cond Doxygen_Suppress
8042 1780 : int GDALDataset::IsGenericSQLDialect(const char *pszDialect)
8043 : {
8044 3252 : return pszDialect != nullptr &&
8045 3252 : (EQUAL(pszDialect, "OGRSQL") || EQUAL(pszDialect, "SQLITE"));
8046 : }
8047 :
8048 : //! @endcond
8049 :
8050 : /************************************************************************/
8051 : /* GetLayerCount() */
8052 : /************************************************************************/
8053 :
8054 : /**
8055 : \brief Get the number of layers in this dataset.
8056 :
8057 : This method is the same as the C function GDALDatasetGetLayerCount(),
8058 : and the deprecated OGR_DS_GetLayerCount().
8059 :
8060 : Note that even if this method is const, there is no guarantee it can be
8061 : safely called by concurrent threads on the same GDALDataset object.
8062 :
8063 : @return layer count.
8064 : */
8065 :
8066 120604 : int GDALDataset::GetLayerCount() const
8067 : {
8068 120604 : return 0;
8069 : }
8070 :
8071 : /************************************************************************/
8072 : /* GetLayer() */
8073 : /************************************************************************/
8074 :
8075 : /**
8076 : \fn const GDALDataset::GetLayer(int) const
8077 : \brief Fetch a layer by index.
8078 :
8079 : The returned layer remains owned by the
8080 : GDALDataset and should not be deleted by the application.
8081 :
8082 : Note that even if this method is const, there is no guarantee it can be
8083 : safely called by concurrent threads on the same GDALDataset object.
8084 :
8085 : See GetLayers() for a C++ iterator version of this method.
8086 :
8087 : This method is the same as the C function GDALDatasetGetLayer() and the
8088 : deprecated OGR_DS_GetLayer().
8089 :
8090 : @param iLayer a layer number between 0 and GetLayerCount()-1.
8091 :
8092 : @return the layer, or NULL if iLayer is out of range or an error occurs.
8093 :
8094 : @see GetLayers()
8095 :
8096 : @since GDAL 3.12
8097 : */
8098 :
8099 0 : const OGRLayer *GDALDataset::GetLayer(CPL_UNUSED int iLayer) const
8100 : {
8101 0 : return nullptr;
8102 : }
8103 :
8104 : /**
8105 : \fn GDALDataset::GetLayer(int)
8106 : \brief Fetch a layer by index.
8107 :
8108 : The returned layer remains owned by the
8109 : GDALDataset and should not be deleted by the application.
8110 :
8111 : See GetLayers() for a C++ iterator version of this method.
8112 :
8113 : This method is the same as the C function GDALDatasetGetLayer() and the
8114 : deprecated OGR_DS_GetLayer().
8115 :
8116 : @param iLayer a layer number between 0 and GetLayerCount()-1.
8117 :
8118 : @return the layer, or NULL if iLayer is out of range or an error occurs.
8119 :
8120 : @see GetLayers()
8121 : */
8122 :
8123 : /************************************************************************/
8124 : /* IsLayerPrivate() */
8125 : /************************************************************************/
8126 :
8127 : /**
8128 : \fn GDALDataset::IsLayerPrivate(int)
8129 : \brief Returns true if the layer at the specified index is deemed a private or
8130 : system table, or an internal detail only.
8131 :
8132 : This method is the same as the C function GDALDatasetIsLayerPrivate().
8133 :
8134 : @param iLayer a layer number between 0 and GetLayerCount()-1.
8135 :
8136 : @return true if the layer is a private or system table.
8137 :
8138 : @since GDAL 3.4
8139 : */
8140 :
8141 972 : bool GDALDataset::IsLayerPrivate(CPL_UNUSED int iLayer) const
8142 : {
8143 972 : return false;
8144 : }
8145 :
8146 : /************************************************************************/
8147 : /* ResetReading() */
8148 : /************************************************************************/
8149 :
8150 : /**
8151 : \brief Reset feature reading to start on the first feature.
8152 :
8153 : This affects GetNextFeature().
8154 :
8155 : Depending on drivers, this may also have the side effect of calling
8156 : OGRLayer::ResetReading() on the layers of this dataset.
8157 :
8158 : This method is the same as the C function GDALDatasetResetReading().
8159 :
8160 : */
8161 7 : void GDALDataset::ResetReading()
8162 : {
8163 7 : if (!m_poPrivate)
8164 0 : return;
8165 7 : m_poPrivate->nCurrentLayerIdx = 0;
8166 7 : m_poPrivate->nLayerCount = -1;
8167 7 : m_poPrivate->poCurrentLayer = nullptr;
8168 7 : m_poPrivate->nFeatureReadInLayer = 0;
8169 7 : m_poPrivate->nFeatureReadInDataset = 0;
8170 7 : m_poPrivate->nTotalFeaturesInLayer = TOTAL_FEATURES_NOT_INIT;
8171 7 : m_poPrivate->nTotalFeatures = TOTAL_FEATURES_NOT_INIT;
8172 : }
8173 :
8174 : /************************************************************************/
8175 : /* GDALDatasetResetReading() */
8176 : /************************************************************************/
8177 :
8178 : /**
8179 : \brief Reset feature reading to start on the first feature.
8180 :
8181 : This affects GDALDatasetGetNextFeature().
8182 :
8183 : Depending on drivers, this may also have the side effect of calling
8184 : OGR_L_ResetReading() on the layers of this dataset.
8185 :
8186 : This method is the same as the C++ method GDALDataset::ResetReading()
8187 :
8188 : @param hDS dataset handle
8189 : */
8190 14 : void CPL_DLL GDALDatasetResetReading(GDALDatasetH hDS)
8191 : {
8192 14 : VALIDATE_POINTER0(hDS, "GDALDatasetResetReading");
8193 :
8194 14 : return GDALDataset::FromHandle(hDS)->ResetReading();
8195 : }
8196 :
8197 : /************************************************************************/
8198 : /* GetNextFeature() */
8199 : /************************************************************************/
8200 :
8201 : /**
8202 : \brief Fetch the next available feature from this dataset.
8203 :
8204 : This method is intended for the few drivers where OGRLayer::GetNextFeature()
8205 : is not efficient, but in general OGRLayer::GetNextFeature() is a more
8206 : natural API.
8207 :
8208 : See GetFeatures() for a C++ iterator version of this method.
8209 :
8210 : The returned feature becomes the responsibility of the caller to
8211 : delete with OGRFeature::DestroyFeature().
8212 :
8213 : Depending on the driver, this method may return features from layers in a
8214 : non sequential way. This is what may happen when the
8215 : ODsCRandomLayerRead capability is declared (for example for the
8216 : OSM and GMLAS drivers). When datasets declare this capability, it is strongly
8217 : advised to use GDALDataset::GetNextFeature() instead of
8218 : OGRLayer::GetNextFeature(), as the later might have a slow, incomplete or stub
8219 : implementation.
8220 :
8221 : The default implementation, used by most drivers, will
8222 : however iterate over each layer, and then over each feature within this
8223 : layer.
8224 :
8225 : This method takes into account spatial and attribute filters set on layers that
8226 : will be iterated upon.
8227 :
8228 : The ResetReading() method can be used to start at the beginning again.
8229 :
8230 : Depending on drivers, this may also have the side effect of calling
8231 : OGRLayer::GetNextFeature() on the layers of this dataset.
8232 :
8233 : This method is the same as the C function GDALDatasetGetNextFeature().
8234 :
8235 : @param ppoBelongingLayer a pointer to a OGRLayer* variable to receive the
8236 : layer to which the object belongs to, or NULL.
8237 : It is possible that the output of *ppoBelongingLayer
8238 : to be NULL despite the feature not being NULL.
8239 : @param pdfProgressPct a pointer to a double variable to receive the
8240 : percentage progress (in [0,1] range), or NULL.
8241 : On return, the pointed value might be negative if
8242 : determining the progress is not possible.
8243 : @param pfnProgress a progress callback to report progress (for
8244 : GetNextFeature() calls that might have a long
8245 : duration) and offer cancellation possibility, or NULL.
8246 : @param pProgressData user data provided to pfnProgress, or NULL
8247 : @return a feature, or NULL if no more features are available.
8248 : @see GetFeatures()
8249 : */
8250 :
8251 68 : OGRFeature *GDALDataset::GetNextFeature(OGRLayer **ppoBelongingLayer,
8252 : double *pdfProgressPct,
8253 : GDALProgressFunc pfnProgress,
8254 : void *pProgressData)
8255 : {
8256 68 : if (!m_poPrivate || m_poPrivate->nCurrentLayerIdx < 0)
8257 : {
8258 2 : if (ppoBelongingLayer != nullptr)
8259 2 : *ppoBelongingLayer = nullptr;
8260 2 : if (pdfProgressPct != nullptr)
8261 1 : *pdfProgressPct = 1.0;
8262 2 : if (pfnProgress != nullptr)
8263 0 : pfnProgress(1.0, "", pProgressData);
8264 2 : return nullptr;
8265 : }
8266 :
8267 66 : if (m_poPrivate->poCurrentLayer == nullptr &&
8268 11 : (pdfProgressPct != nullptr || pfnProgress != nullptr))
8269 : {
8270 4 : if (m_poPrivate->nLayerCount < 0)
8271 : {
8272 4 : m_poPrivate->nLayerCount = GetLayerCount();
8273 : }
8274 :
8275 4 : if (m_poPrivate->nTotalFeatures == TOTAL_FEATURES_NOT_INIT)
8276 : {
8277 4 : m_poPrivate->nTotalFeatures = 0;
8278 8 : for (int i = 0; i < m_poPrivate->nLayerCount; i++)
8279 : {
8280 7 : OGRLayer *poLayer = GetLayer(i);
8281 14 : if (poLayer == nullptr ||
8282 7 : !poLayer->TestCapability(OLCFastFeatureCount))
8283 : {
8284 3 : m_poPrivate->nTotalFeatures = TOTAL_FEATURES_UNKNOWN;
8285 3 : break;
8286 : }
8287 4 : GIntBig nCount = poLayer->GetFeatureCount(FALSE);
8288 4 : if (nCount < 0)
8289 : {
8290 0 : m_poPrivate->nTotalFeatures = TOTAL_FEATURES_UNKNOWN;
8291 0 : break;
8292 : }
8293 4 : m_poPrivate->nTotalFeatures += nCount;
8294 : }
8295 : }
8296 : }
8297 :
8298 : while (true)
8299 : {
8300 82 : if (m_poPrivate->poCurrentLayer == nullptr)
8301 : {
8302 56 : m_poPrivate->poCurrentLayer =
8303 28 : GetLayer(m_poPrivate->nCurrentLayerIdx);
8304 28 : if (m_poPrivate->poCurrentLayer == nullptr)
8305 : {
8306 10 : m_poPrivate->nCurrentLayerIdx = -1;
8307 10 : if (ppoBelongingLayer != nullptr)
8308 7 : *ppoBelongingLayer = nullptr;
8309 10 : if (pdfProgressPct != nullptr)
8310 1 : *pdfProgressPct = 1.0;
8311 10 : return nullptr;
8312 : }
8313 18 : m_poPrivate->poCurrentLayer->ResetReading();
8314 18 : m_poPrivate->nFeatureReadInLayer = 0;
8315 18 : if (m_poPrivate->nTotalFeatures < 0 && pdfProgressPct != nullptr)
8316 : {
8317 0 : if (m_poPrivate->poCurrentLayer->TestCapability(
8318 0 : OLCFastFeatureCount))
8319 0 : m_poPrivate->nTotalFeaturesInLayer =
8320 0 : m_poPrivate->poCurrentLayer->GetFeatureCount(FALSE);
8321 : else
8322 0 : m_poPrivate->nTotalFeaturesInLayer = 0;
8323 : }
8324 : }
8325 72 : OGRFeature *poFeature = m_poPrivate->poCurrentLayer->GetNextFeature();
8326 72 : if (poFeature == nullptr)
8327 : {
8328 16 : m_poPrivate->nCurrentLayerIdx++;
8329 16 : m_poPrivate->poCurrentLayer = nullptr;
8330 16 : continue;
8331 : }
8332 :
8333 56 : m_poPrivate->nFeatureReadInLayer++;
8334 56 : m_poPrivate->nFeatureReadInDataset++;
8335 56 : if (pdfProgressPct != nullptr || pfnProgress != nullptr)
8336 : {
8337 9 : double dfPct = 0.0;
8338 9 : if (m_poPrivate->nTotalFeatures > 0)
8339 : {
8340 4 : dfPct = 1.0 * m_poPrivate->nFeatureReadInDataset /
8341 4 : m_poPrivate->nTotalFeatures;
8342 : }
8343 : else
8344 : {
8345 5 : dfPct = 1.0 * m_poPrivate->nCurrentLayerIdx /
8346 5 : m_poPrivate->nLayerCount;
8347 5 : if (m_poPrivate->nTotalFeaturesInLayer > 0)
8348 : {
8349 0 : dfPct += 1.0 * m_poPrivate->nFeatureReadInLayer /
8350 0 : m_poPrivate->nTotalFeaturesInLayer /
8351 0 : m_poPrivate->nLayerCount;
8352 : }
8353 : }
8354 9 : if (pdfProgressPct)
8355 4 : *pdfProgressPct = dfPct;
8356 9 : if (pfnProgress)
8357 5 : pfnProgress(dfPct, "", nullptr);
8358 : }
8359 :
8360 56 : if (ppoBelongingLayer != nullptr)
8361 51 : *ppoBelongingLayer = m_poPrivate->poCurrentLayer;
8362 56 : return poFeature;
8363 16 : }
8364 : }
8365 :
8366 : /************************************************************************/
8367 : /* GDALDatasetGetNextFeature() */
8368 : /************************************************************************/
8369 : /**
8370 : \brief Fetch the next available feature from this dataset.
8371 :
8372 : This method is intended for the few drivers where OGR_L_GetNextFeature()
8373 : is not efficient, but in general OGR_L_GetNextFeature() is a more
8374 : natural API.
8375 :
8376 : The returned feature becomes the responsibility of the caller to
8377 : delete with OGRFeature::DestroyFeature().
8378 :
8379 : Depending on the driver, this method may return features from layers in a
8380 : non sequential way. This is what may happen when the
8381 : ODsCRandomLayerRead capability is declared (for example for the
8382 : OSM and GMLAS drivers). When datasets declare this capability, it is strongly
8383 : advised to use GDALDataset::GetNextFeature() instead of
8384 : OGRLayer::GetNextFeature(), as the later might have a slow, incomplete or stub
8385 : implementation.
8386 :
8387 : The default implementation, used by most drivers, will
8388 : however iterate over each layer, and then over each feature within this
8389 : layer.
8390 :
8391 : This method takes into account spatial and attribute filters set on layers that
8392 : will be iterated upon.
8393 :
8394 : The ResetReading() method can be used to start at the beginning again.
8395 :
8396 : Depending on drivers, this may also have the side effect of calling
8397 : OGRLayer::GetNextFeature() on the layers of this dataset.
8398 :
8399 : This method is the same as the C++ method GDALDataset::GetNextFeature()
8400 :
8401 : @param hDS dataset handle.
8402 : @param phBelongingLayer a pointer to a OGRLayer* variable to receive the
8403 : layer to which the object belongs to, or NULL.
8404 : It is possible that the output of *ppoBelongingLayer
8405 : to be NULL despite the feature not being NULL.
8406 : @param pdfProgressPct a pointer to a double variable to receive the
8407 : percentage progress (in [0,1] range), or NULL.
8408 : On return, the pointed value might be negative if
8409 : determining the progress is not possible.
8410 : @param pfnProgress a progress callback to report progress (for
8411 : GetNextFeature() calls that might have a long
8412 : duration) and offer cancellation possibility, or NULL
8413 : @param pProgressData user data provided to pfnProgress, or NULL
8414 : @return a feature, or NULL if no more features are available.
8415 : */
8416 1917 : OGRFeatureH CPL_DLL GDALDatasetGetNextFeature(GDALDatasetH hDS,
8417 : OGRLayerH *phBelongingLayer,
8418 : double *pdfProgressPct,
8419 : GDALProgressFunc pfnProgress,
8420 : void *pProgressData)
8421 : {
8422 1917 : VALIDATE_POINTER1(hDS, "GDALDatasetGetNextFeature", nullptr);
8423 :
8424 3834 : return OGRFeature::ToHandle(GDALDataset::FromHandle(hDS)->GetNextFeature(
8425 : reinterpret_cast<OGRLayer **>(phBelongingLayer), pdfProgressPct,
8426 3834 : pfnProgress, pProgressData));
8427 : }
8428 :
8429 : /************************************************************************/
8430 : /* TestCapability() */
8431 : /************************************************************************/
8432 :
8433 : /**
8434 : \fn GDALDataset::TestCapability( const char * pszCap )
8435 : \brief Test if capability is available.
8436 :
8437 : One of the following dataset capability names can be passed into this
8438 : method, and a TRUE or FALSE value will be returned indicating whether or not
8439 : the capability is available for this object.
8440 :
8441 : <ul>
8442 : <li> <b>ODsCCreateLayer</b>: True if this datasource can create new layers.<p>
8443 : <li> <b>ODsCDeleteLayer</b>: True if this datasource can delete existing
8444 : layers.<p>
8445 : <li> <b>ODsCCreateGeomFieldAfterCreateLayer</b>: True if the layers of this
8446 : datasource support CreateGeomField() just after layer creation.<p>
8447 : <li> <b>ODsCCurveGeometries</b>: True if this datasource supports curve
8448 : geometries.<p>
8449 : <li> <b>ODsCTransactions</b>: True if this datasource supports (efficient)
8450 : transactions.<p>
8451 : <li> <b>ODsCEmulatedTransactions</b>: True if this datasource supports
8452 : transactions through emulation.<p>
8453 : <li> <b>ODsCRandomLayerRead</b>: True if this datasource has a dedicated
8454 : GetNextFeature() implementation, potentially returning features from
8455 : layers in a non sequential way.<p>
8456 : <li> <b>ODsCRandomLayerWrite</b>: True if this datasource supports calling
8457 : CreateFeature() on layers in a non sequential way.<p>
8458 : <li> <b>GDsCAddRelationship</b>: True if AddRelationship() is supported</li>
8459 : <li> <b>GDsCDeleteRelationship</b>: True if DeleteRelationship() is supported</li>
8460 : <li> <b>GDsCUpdateRelationship</b>: True if UpdateRelationship() is supported</li>
8461 : <li> <b>GDsCFastGetExtent</b>: True if GetExtent() is fast</li>
8462 : <li> <b>GDsCFastGetExtentWGS84LongLat</b>: True if GetExtentWGS84LongLat() is fast</li>
8463 : </ul>
8464 :
8465 : The \#define macro forms of the capability names should be used in preference
8466 : to the strings themselves to avoid misspelling.
8467 :
8468 : This method is the same as the C function GDALDatasetTestCapability() and the
8469 : deprecated OGR_DS_TestCapability().
8470 :
8471 : @param pszCap the capability to test.
8472 :
8473 : @return TRUE if capability available otherwise FALSE.
8474 : */
8475 :
8476 745 : int GDALDataset::TestCapability(const char *pszCap) const
8477 : {
8478 745 : if (EQUAL(pszCap, GDsCFastGetExtent) ||
8479 743 : EQUAL(pszCap, GDsCFastGetExtentWGS84LongLat))
8480 : {
8481 4 : for (auto &&poLayer : GetLayers())
8482 : {
8483 2 : if (!poLayer->TestCapability(OLCFastGetExtent))
8484 2 : return FALSE;
8485 : }
8486 2 : return TRUE;
8487 : }
8488 741 : return FALSE;
8489 : }
8490 :
8491 : /************************************************************************/
8492 : /* GDALDatasetTestCapability() */
8493 : /************************************************************************/
8494 :
8495 : /**
8496 : \brief Test if capability is available.
8497 :
8498 : One of the following dataset capability names can be passed into this
8499 : function, and a TRUE or FALSE value will be returned indicating whether or not
8500 : the capability is available for this object.
8501 :
8502 : <ul>
8503 : <li> <b>ODsCCreateLayer</b>: True if this datasource can create new layers.<p>
8504 : <li> <b>ODsCDeleteLayer</b>: True if this datasource can delete existing
8505 : layers.<p>
8506 : <li> <b>ODsCCreateGeomFieldAfterCreateLayer</b>: True if the layers of this
8507 : datasource support CreateGeomField() just after layer creation.<p>
8508 : <li> <b>ODsCCurveGeometries</b>: True if this datasource supports curve
8509 : geometries.<p>
8510 : <li> <b>ODsCTransactions</b>: True if this datasource supports (efficient)
8511 : transactions.<p>
8512 : <li> <b>ODsCEmulatedTransactions</b>: True if this datasource supports
8513 : transactions through emulation.<p>
8514 : <li> <b>ODsCRandomLayerRead</b>: True if this datasource has a dedicated
8515 : GetNextFeature() implementation, potentially returning features from
8516 : layers in a non sequential way.<p>
8517 : <li> <b>ODsCRandomLayerWrite</b>: True if this datasource supports calling
8518 : CreateFeature() on layers in a non sequential way.<p>
8519 : <li> <b>GDsCAddRelationship</b>: True if AddRelationship() is supported</li>
8520 : <li> <b>GDsCDeleteRelationship</b>: True if DeleteRelationship() is supported</li>
8521 : <li> <b>GDsCUpdateRelationship</b>: True if UpdateRelationship() is supported</li>
8522 : <li> <b>GDsCFastGetExtent</b>: True if GetExtent() is fast</li>
8523 : <li> <b>GDsCFastGetExtentWGS84LongLat</b>: True if GetExtentWGS84LongLat() is fast</li>
8524 : </ul>
8525 :
8526 : The \#define macro forms of the capability names should be used in preference
8527 : to the strings themselves to avoid misspelling.
8528 :
8529 : This function is the same as the C++ method GDALDataset::TestCapability()
8530 :
8531 :
8532 : @param hDS the dataset handle.
8533 : @param pszCap the capability to test.
8534 :
8535 : @return TRUE if capability available otherwise FALSE.
8536 : */
8537 127 : int GDALDatasetTestCapability(GDALDatasetH hDS, const char *pszCap)
8538 :
8539 : {
8540 127 : VALIDATE_POINTER1(hDS, "GDALDatasetTestCapability", 0);
8541 127 : VALIDATE_POINTER1(pszCap, "GDALDatasetTestCapability", 0);
8542 :
8543 127 : return GDALDataset::FromHandle(hDS)->TestCapability(pszCap);
8544 : }
8545 :
8546 : /************************************************************************/
8547 : /* StartTransaction() */
8548 : /************************************************************************/
8549 :
8550 : /**
8551 : \fn GDALDataset::StartTransaction(int)
8552 : \brief For datasources which support transactions, StartTransaction creates a
8553 : `transaction.
8554 :
8555 : If starting the transaction fails, will return
8556 : OGRERR_FAILURE. Datasources which do not support transactions will
8557 : always return OGRERR_UNSUPPORTED_OPERATION.
8558 :
8559 : Nested transactions are not supported.
8560 :
8561 : All changes done after the start of the transaction are definitely applied in
8562 : the datasource if CommitTransaction() is called. They may be canceled by
8563 : calling RollbackTransaction() instead.
8564 :
8565 : At the time of writing, transactions only apply on vector layers.
8566 :
8567 : Datasets that support transactions will advertise the ODsCTransactions
8568 : capability. Use of transactions at dataset level is generally preferred to
8569 : transactions at layer level, whose scope is rarely limited to the layer from
8570 : which it was started.
8571 :
8572 : In case StartTransaction() fails, neither CommitTransaction() or
8573 : RollbackTransaction() should be called.
8574 :
8575 : If an error occurs after a successful StartTransaction(), the whole transaction
8576 : may or may not be implicitly canceled, depending on drivers. (e.g. the PG
8577 : driver will cancel it, SQLite/GPKG not). In any case, in the event of an error,
8578 : an explicit call to RollbackTransaction() should be done to keep things
8579 : balanced.
8580 :
8581 : By default, when bForce is set to FALSE, only "efficient" transactions will be
8582 : attempted. Some drivers may offer an emulation of transactions, but sometimes
8583 : with significant overhead, in which case the user must explicitly allow for
8584 : such an emulation by setting bForce to TRUE. Drivers that offer emulated
8585 : transactions should advertise the ODsCEmulatedTransactions capability (and not
8586 : ODsCTransactions).
8587 :
8588 : This function is the same as the C function GDALDatasetStartTransaction().
8589 :
8590 : @param bForce can be set to TRUE if an emulation, possibly slow, of a
8591 : transaction
8592 : mechanism is acceptable.
8593 :
8594 : @return OGRERR_NONE on success.
8595 : */
8596 :
8597 37 : OGRErr GDALDataset::StartTransaction(CPL_UNUSED int bForce)
8598 : {
8599 37 : return OGRERR_UNSUPPORTED_OPERATION;
8600 : }
8601 :
8602 : /************************************************************************/
8603 : /* GDALDatasetStartTransaction() */
8604 : /************************************************************************/
8605 :
8606 : /**
8607 : \brief For datasources which support transactions, StartTransaction creates a
8608 : transaction.
8609 :
8610 : If starting the transaction fails, will return
8611 : OGRERR_FAILURE. Datasources which do not support transactions will
8612 : always return OGRERR_UNSUPPORTED_OPERATION.
8613 :
8614 : Nested transactions are not supported.
8615 :
8616 : All changes done after the start of the transaction are definitely applied in
8617 : the datasource if CommitTransaction() is called. They may be canceled by
8618 : calling RollbackTransaction() instead.
8619 :
8620 : At the time of writing, transactions only apply on vector layers.
8621 :
8622 : Datasets that support transactions will advertise the ODsCTransactions
8623 : capability.
8624 : Use of transactions at dataset level is generally preferred to transactions at
8625 : layer level, whose scope is rarely limited to the layer from which it was
8626 : started.
8627 :
8628 : In case StartTransaction() fails, neither CommitTransaction() or
8629 : RollbackTransaction() should be called.
8630 :
8631 : If an error occurs after a successful StartTransaction(), the whole
8632 : transaction may or may not be implicitly canceled, depending on drivers. (e.g.
8633 : the PG driver will cancel it, SQLite/GPKG not). In any case, in the event of an
8634 : error, an explicit call to RollbackTransaction() should be done to keep things
8635 : balanced.
8636 :
8637 : By default, when bForce is set to FALSE, only "efficient" transactions will be
8638 : attempted. Some drivers may offer an emulation of transactions, but sometimes
8639 : with significant overhead, in which case the user must explicitly allow for
8640 : such an emulation by setting bForce to TRUE. Drivers that offer emulated
8641 : transactions should advertise the ODsCEmulatedTransactions capability (and not
8642 : ODsCTransactions).
8643 :
8644 : This function is the same as the C++ method GDALDataset::StartTransaction()
8645 :
8646 : @param hDS the dataset handle.
8647 : @param bForce can be set to TRUE if an emulation, possibly slow, of a
8648 : transaction
8649 : mechanism is acceptable.
8650 :
8651 : @return OGRERR_NONE on success.
8652 : */
8653 105 : OGRErr GDALDatasetStartTransaction(GDALDatasetH hDS, int bForce)
8654 : {
8655 105 : VALIDATE_POINTER1(hDS, "GDALDatasetStartTransaction",
8656 : OGRERR_INVALID_HANDLE);
8657 :
8658 : #ifdef OGRAPISPY_ENABLED
8659 105 : if (bOGRAPISpyEnabled)
8660 2 : OGRAPISpy_Dataset_StartTransaction(hDS, bForce);
8661 : #endif
8662 :
8663 105 : return GDALDataset::FromHandle(hDS)->StartTransaction(bForce);
8664 : }
8665 :
8666 : /************************************************************************/
8667 : /* CommitTransaction() */
8668 : /************************************************************************/
8669 :
8670 : /**
8671 : \brief For datasources which support transactions, CommitTransaction commits a
8672 : transaction.
8673 :
8674 : If no transaction is active, or the commit fails, will return
8675 : OGRERR_FAILURE. Datasources which do not support transactions will
8676 : always return OGRERR_UNSUPPORTED_OPERATION.
8677 :
8678 : Depending on drivers, this may or may not abort layer sequential readings that
8679 : are active.
8680 :
8681 : This function is the same as the C function GDALDatasetCommitTransaction().
8682 :
8683 : @return OGRERR_NONE on success.
8684 : */
8685 52 : OGRErr GDALDataset::CommitTransaction()
8686 : {
8687 52 : return OGRERR_UNSUPPORTED_OPERATION;
8688 : }
8689 :
8690 : /************************************************************************/
8691 : /* GDALDatasetCommitTransaction() */
8692 : /************************************************************************/
8693 :
8694 : /**
8695 : \brief For datasources which support transactions, CommitTransaction commits a
8696 : transaction.
8697 :
8698 : If no transaction is active, or the commit fails, will return
8699 : OGRERR_FAILURE. Datasources which do not support transactions will
8700 : always return OGRERR_UNSUPPORTED_OPERATION.
8701 :
8702 : Depending on drivers, this may or may not abort layer sequential readings that
8703 : are active.
8704 :
8705 : This function is the same as the C++ method GDALDataset::CommitTransaction()
8706 :
8707 : @return OGRERR_NONE on success.
8708 : */
8709 76 : OGRErr GDALDatasetCommitTransaction(GDALDatasetH hDS)
8710 : {
8711 76 : VALIDATE_POINTER1(hDS, "GDALDatasetCommitTransaction",
8712 : OGRERR_INVALID_HANDLE);
8713 :
8714 : #ifdef OGRAPISPY_ENABLED
8715 76 : if (bOGRAPISpyEnabled)
8716 2 : OGRAPISpy_Dataset_CommitTransaction(hDS);
8717 : #endif
8718 :
8719 76 : return GDALDataset::FromHandle(hDS)->CommitTransaction();
8720 : }
8721 :
8722 : /************************************************************************/
8723 : /* RollbackTransaction() */
8724 : /************************************************************************/
8725 :
8726 : /**
8727 : \brief For datasources which support transactions, RollbackTransaction will
8728 : roll back a datasource to its state before the start of the current
8729 : transaction.
8730 : If no transaction is active, or the rollback fails, will return
8731 : OGRERR_FAILURE. Datasources which do not support transactions will
8732 : always return OGRERR_UNSUPPORTED_OPERATION.
8733 :
8734 : This function is the same as the C function GDALDatasetRollbackTransaction().
8735 :
8736 : @return OGRERR_NONE on success.
8737 : */
8738 2 : OGRErr GDALDataset::RollbackTransaction()
8739 : {
8740 2 : return OGRERR_UNSUPPORTED_OPERATION;
8741 : }
8742 :
8743 : /************************************************************************/
8744 : /* GDALDatasetRollbackTransaction() */
8745 : /************************************************************************/
8746 :
8747 : /**
8748 : \brief For datasources which support transactions, RollbackTransaction will
8749 : roll back a datasource to its state before the start of the current
8750 : transaction.
8751 : If no transaction is active, or the rollback fails, will return
8752 : OGRERR_FAILURE. Datasources which do not support transactions will
8753 : always return OGRERR_UNSUPPORTED_OPERATION.
8754 :
8755 : This function is the same as the C++ method GDALDataset::RollbackTransaction().
8756 :
8757 : @return OGRERR_NONE on success.
8758 : */
8759 44 : OGRErr GDALDatasetRollbackTransaction(GDALDatasetH hDS)
8760 : {
8761 44 : VALIDATE_POINTER1(hDS, "GDALDatasetRollbackTransaction",
8762 : OGRERR_INVALID_HANDLE);
8763 :
8764 : #ifdef OGRAPISPY_ENABLED
8765 44 : if (bOGRAPISpyEnabled)
8766 2 : OGRAPISpy_Dataset_RollbackTransaction(hDS);
8767 : #endif
8768 :
8769 44 : return GDALDataset::FromHandle(hDS)->RollbackTransaction();
8770 : }
8771 :
8772 : //! @cond Doxygen_Suppress
8773 :
8774 : /************************************************************************/
8775 : /* ShareLockWithParentDataset() */
8776 : /************************************************************************/
8777 :
8778 : /* To be used typically by the GTiff driver to link overview datasets */
8779 : /* with their main dataset, so that they share the same lock */
8780 : /* Cf https://github.com/OSGeo/gdal/issues/1488 */
8781 : /* The parent dataset should remain alive while the this dataset is alive */
8782 :
8783 2338 : void GDALDataset::ShareLockWithParentDataset(GDALDataset *poParentDataset)
8784 : {
8785 2338 : if (m_poPrivate != nullptr)
8786 : {
8787 2338 : m_poPrivate->poParentDataset = poParentDataset;
8788 : }
8789 2338 : }
8790 :
8791 : /************************************************************************/
8792 : /* SetQueryLoggerFunc() */
8793 : /************************************************************************/
8794 :
8795 0 : bool GDALDataset::SetQueryLoggerFunc(CPL_UNUSED GDALQueryLoggerFunc callback,
8796 : CPL_UNUSED void *context)
8797 : {
8798 0 : return false;
8799 : }
8800 :
8801 : /************************************************************************/
8802 : /* EnterReadWrite() */
8803 : /************************************************************************/
8804 :
8805 8030260 : int GDALDataset::EnterReadWrite(GDALRWFlag eRWFlag)
8806 : {
8807 16060500 : if (m_poPrivate == nullptr ||
8808 8030260 : IsThreadSafe(GDAL_OF_RASTER | (nOpenFlags & GDAL_OF_UPDATE)))
8809 11998 : return FALSE;
8810 :
8811 8018260 : if (m_poPrivate->poParentDataset)
8812 242623 : return m_poPrivate->poParentDataset->EnterReadWrite(eRWFlag);
8813 :
8814 7775640 : if (eAccess == GA_Update)
8815 : {
8816 2219860 : if (m_poPrivate->eStateReadWriteMutex ==
8817 : GDALAllowReadWriteMutexState::RW_MUTEX_STATE_UNKNOWN)
8818 : {
8819 : // In case dead-lock would occur, which is not impossible,
8820 : // this can be used to prevent it, but at the risk of other
8821 : // issues.
8822 10745 : if (CPLTestBool(
8823 : CPLGetConfigOption("GDAL_ENABLE_READ_WRITE_MUTEX", "YES")))
8824 : {
8825 10745 : m_poPrivate->eStateReadWriteMutex =
8826 : GDALAllowReadWriteMutexState::RW_MUTEX_STATE_ALLOWED;
8827 : }
8828 : else
8829 : {
8830 0 : m_poPrivate->eStateReadWriteMutex =
8831 : GDALAllowReadWriteMutexState::RW_MUTEX_STATE_DISABLED;
8832 : }
8833 : }
8834 2219860 : if (m_poPrivate->eStateReadWriteMutex ==
8835 : GDALAllowReadWriteMutexState::RW_MUTEX_STATE_ALLOWED)
8836 : {
8837 : // There should be no race related to creating this mutex since
8838 : // it should be first created through IWriteBlock() / IRasterIO()
8839 : // and then GDALRasterBlock might call it from another thread.
8840 : #ifdef DEBUG_VERBOSE
8841 : CPLDebug("GDAL",
8842 : "[Thread " CPL_FRMT_GIB "] Acquiring RW mutex for %s",
8843 : CPLGetPID(), GetDescription());
8844 : #endif
8845 1542800 : CPLCreateOrAcquireMutex(&(m_poPrivate->hMutex), 1000.0);
8846 :
8847 : const int nCountMutex =
8848 1542800 : m_poPrivate->oMapThreadToMutexTakenCount[CPLGetPID()]++;
8849 1542800 : if (nCountMutex == 0 && eRWFlag == GF_Read)
8850 : {
8851 523096 : CPLReleaseMutex(m_poPrivate->hMutex);
8852 1662280 : for (int i = 0; i < nBands; i++)
8853 : {
8854 1139180 : auto blockCache = papoBands[i]->poBandBlockCache;
8855 1139180 : if (blockCache)
8856 822571 : blockCache->WaitCompletionPendingTasks();
8857 : }
8858 523096 : CPLCreateOrAcquireMutex(&(m_poPrivate->hMutex), 1000.0);
8859 : }
8860 :
8861 1542800 : return TRUE;
8862 : }
8863 : }
8864 6232840 : return FALSE;
8865 : }
8866 :
8867 : /************************************************************************/
8868 : /* LeaveReadWrite() */
8869 : /************************************************************************/
8870 :
8871 1771760 : void GDALDataset::LeaveReadWrite()
8872 : {
8873 1771760 : if (m_poPrivate)
8874 : {
8875 1771760 : if (m_poPrivate->poParentDataset)
8876 : {
8877 228963 : m_poPrivate->poParentDataset->LeaveReadWrite();
8878 228963 : return;
8879 : }
8880 :
8881 1542800 : m_poPrivate->oMapThreadToMutexTakenCount[CPLGetPID()]--;
8882 1542800 : CPLReleaseMutex(m_poPrivate->hMutex);
8883 : #ifdef DEBUG_VERBOSE
8884 : CPLDebug("GDAL", "[Thread " CPL_FRMT_GIB "] Releasing RW mutex for %s",
8885 : CPLGetPID(), GetDescription());
8886 : #endif
8887 : }
8888 : }
8889 :
8890 : /************************************************************************/
8891 : /* InitRWLock() */
8892 : /************************************************************************/
8893 :
8894 3988630 : void GDALDataset::InitRWLock()
8895 : {
8896 3988630 : if (m_poPrivate)
8897 : {
8898 3988630 : if (m_poPrivate->poParentDataset)
8899 : {
8900 8584 : m_poPrivate->poParentDataset->InitRWLock();
8901 8584 : return;
8902 : }
8903 :
8904 3980050 : if (m_poPrivate->eStateReadWriteMutex ==
8905 : GDALAllowReadWriteMutexState::RW_MUTEX_STATE_UNKNOWN)
8906 : {
8907 1 : if (EnterReadWrite(GF_Write))
8908 1 : LeaveReadWrite();
8909 : }
8910 : }
8911 : }
8912 :
8913 : /************************************************************************/
8914 : /* DisableReadWriteMutex() */
8915 : /************************************************************************/
8916 :
8917 : // The mutex logic is broken in multi-threaded situations, for example
8918 : // with 2 WarpedVRT datasets being read at the same time. In that
8919 : // particular case, the mutex is not needed, so allow the VRTWarpedDataset code
8920 : // to disable it.
8921 21786 : void GDALDataset::DisableReadWriteMutex()
8922 : {
8923 21786 : if (m_poPrivate)
8924 : {
8925 21786 : if (m_poPrivate->poParentDataset)
8926 : {
8927 0 : m_poPrivate->poParentDataset->DisableReadWriteMutex();
8928 0 : return;
8929 : }
8930 :
8931 21786 : m_poPrivate->eStateReadWriteMutex =
8932 : GDALAllowReadWriteMutexState::RW_MUTEX_STATE_DISABLED;
8933 : }
8934 : }
8935 :
8936 : /************************************************************************/
8937 : /* TemporarilyDropReadWriteLock() */
8938 : /************************************************************************/
8939 :
8940 3403920 : void GDALDataset::TemporarilyDropReadWriteLock()
8941 : {
8942 3403920 : if (m_poPrivate == nullptr)
8943 0 : return;
8944 :
8945 3403920 : if (m_poPrivate->poParentDataset)
8946 : {
8947 26346 : m_poPrivate->poParentDataset->TemporarilyDropReadWriteLock();
8948 26346 : return;
8949 : }
8950 :
8951 : #ifndef __COVERITY__
8952 3377570 : if (m_poPrivate->hMutex)
8953 : {
8954 : #ifdef DEBUG_VERBOSE
8955 : CPLDebug("GDAL",
8956 : "[Thread " CPL_FRMT_GIB "] "
8957 : "Temporarily drop RW mutex for %s",
8958 : CPLGetPID(), GetDescription());
8959 : #endif
8960 421473 : CPLAcquireMutex(m_poPrivate->hMutex, 1000.0);
8961 : const int nCount =
8962 421473 : m_poPrivate->oMapThreadToMutexTakenCount[CPLGetPID()];
8963 : #ifdef DEBUG_EXTRA
8964 : m_poPrivate->oMapThreadToMutexTakenCountSaved[CPLGetPID()] = nCount;
8965 : #endif
8966 1271830 : for (int i = 0; i < nCount + 1; i++)
8967 : {
8968 : // The mutex is recursive
8969 850355 : CPLReleaseMutex(m_poPrivate->hMutex);
8970 : }
8971 : }
8972 : #endif
8973 : }
8974 :
8975 : /************************************************************************/
8976 : /* ReacquireReadWriteLock() */
8977 : /************************************************************************/
8978 :
8979 3403920 : void GDALDataset::ReacquireReadWriteLock()
8980 : {
8981 3403920 : if (m_poPrivate == nullptr)
8982 0 : return;
8983 :
8984 3403920 : if (m_poPrivate->poParentDataset)
8985 : {
8986 26346 : m_poPrivate->poParentDataset->ReacquireReadWriteLock();
8987 26346 : return;
8988 : }
8989 :
8990 : #ifndef __COVERITY__
8991 3377570 : if (m_poPrivate->hMutex)
8992 : {
8993 : #ifdef DEBUG_VERBOSE
8994 : CPLDebug("GDAL",
8995 : "[Thread " CPL_FRMT_GIB "] "
8996 : "Reacquire temporarily dropped RW mutex for %s",
8997 : CPLGetPID(), GetDescription());
8998 : #endif
8999 421475 : CPLAcquireMutex(m_poPrivate->hMutex, 1000.0);
9000 : const int nCount =
9001 421475 : m_poPrivate->oMapThreadToMutexTakenCount[CPLGetPID()];
9002 : #ifdef DEBUG_EXTRA
9003 : CPLAssert(nCount ==
9004 : m_poPrivate->oMapThreadToMutexTakenCountSaved[CPLGetPID()]);
9005 : #endif
9006 421475 : if (nCount == 0)
9007 18278 : CPLReleaseMutex(m_poPrivate->hMutex);
9008 447160 : for (int i = 0; i < nCount - 1; i++)
9009 : {
9010 : // The mutex is recursive
9011 25685 : CPLAcquireMutex(m_poPrivate->hMutex, 1000.0);
9012 : }
9013 : }
9014 : #endif
9015 : }
9016 :
9017 : /************************************************************************/
9018 : /* AcquireMutex() */
9019 : /************************************************************************/
9020 :
9021 196 : int GDALDataset::AcquireMutex()
9022 : {
9023 196 : if (m_poPrivate == nullptr)
9024 0 : return 0;
9025 196 : if (m_poPrivate->poParentDataset)
9026 : {
9027 0 : return m_poPrivate->poParentDataset->AcquireMutex();
9028 : }
9029 :
9030 196 : return CPLCreateOrAcquireMutex(&(m_poPrivate->hMutex), 1000.0);
9031 : }
9032 :
9033 : /************************************************************************/
9034 : /* ReleaseMutex() */
9035 : /************************************************************************/
9036 :
9037 196 : void GDALDataset::ReleaseMutex()
9038 : {
9039 196 : if (m_poPrivate)
9040 : {
9041 196 : if (m_poPrivate->poParentDataset)
9042 : {
9043 0 : m_poPrivate->poParentDataset->ReleaseMutex();
9044 0 : return;
9045 : }
9046 :
9047 196 : CPLReleaseMutex(m_poPrivate->hMutex);
9048 : }
9049 : }
9050 :
9051 : //! @endcond
9052 :
9053 : /************************************************************************/
9054 : /* GDALDataset::Features::Iterator::Private */
9055 : /************************************************************************/
9056 :
9057 : struct GDALDataset::Features::Iterator::Private
9058 : {
9059 : GDALDataset::FeatureLayerPair m_oPair{};
9060 : GDALDataset *m_poDS = nullptr;
9061 : bool m_bEOF = true;
9062 : };
9063 :
9064 4 : GDALDataset::Features::Iterator::Iterator(GDALDataset *poDS, bool bStart)
9065 4 : : m_poPrivate(new GDALDataset::Features::Iterator::Private())
9066 : {
9067 4 : m_poPrivate->m_poDS = poDS;
9068 4 : if (bStart)
9069 : {
9070 2 : poDS->ResetReading();
9071 4 : m_poPrivate->m_oPair.feature.reset(poDS->GetNextFeature(
9072 2 : &m_poPrivate->m_oPair.layer, nullptr, nullptr, nullptr));
9073 2 : m_poPrivate->m_bEOF = m_poPrivate->m_oPair.feature == nullptr;
9074 : }
9075 4 : }
9076 :
9077 : GDALDataset::Features::Iterator::~Iterator() = default;
9078 :
9079 : const GDALDataset::FeatureLayerPair &
9080 20 : GDALDataset::Features::Iterator::operator*() const
9081 : {
9082 20 : return m_poPrivate->m_oPair;
9083 : }
9084 :
9085 20 : GDALDataset::Features::Iterator &GDALDataset::Features::Iterator::operator++()
9086 : {
9087 40 : m_poPrivate->m_oPair.feature.reset(m_poPrivate->m_poDS->GetNextFeature(
9088 20 : &m_poPrivate->m_oPair.layer, nullptr, nullptr, nullptr));
9089 20 : m_poPrivate->m_bEOF = m_poPrivate->m_oPair.feature == nullptr;
9090 20 : return *this;
9091 : }
9092 :
9093 22 : bool GDALDataset::Features::Iterator::operator!=(const Iterator &it) const
9094 : {
9095 22 : return m_poPrivate->m_bEOF != it.m_poPrivate->m_bEOF;
9096 : }
9097 :
9098 : /************************************************************************/
9099 : /* GetFeatures() */
9100 : /************************************************************************/
9101 :
9102 : /** Function that return an iterable object over features in the dataset
9103 : * layer.
9104 : *
9105 : * This is a C++ iterator friendly version of GetNextFeature().
9106 : *
9107 : * Using this iterator for standard range-based loops is safe, but
9108 : * due to implementation limitations, you shouldn't try to access
9109 : * (dereference) more than one iterator step at a time, since the
9110 : * FeatureLayerPair reference which is returned is reused.
9111 : *
9112 : * Typical use is:
9113 : * \code{.cpp}
9114 : * for( auto&& oFeatureLayerPair: poDS->GetFeatures() )
9115 : * {
9116 : * std::cout << "Feature of layer " <<
9117 : * oFeatureLayerPair.layer->GetName() << std::endl;
9118 : * oFeatureLayerPair.feature->DumpReadable();
9119 : * }
9120 : * \endcode
9121 : *
9122 : * @see GetNextFeature()
9123 : *
9124 : */
9125 2 : GDALDataset::Features GDALDataset::GetFeatures()
9126 : {
9127 2 : return Features(this);
9128 : }
9129 :
9130 : /************************************************************************/
9131 : /* begin() */
9132 : /************************************************************************/
9133 :
9134 : /**
9135 : \brief Return beginning of feature iterator.
9136 :
9137 : */
9138 :
9139 2 : const GDALDataset::Features::Iterator GDALDataset::Features::begin() const
9140 : {
9141 2 : return {m_poSelf, true};
9142 : }
9143 :
9144 : /************************************************************************/
9145 : /* end() */
9146 : /************************************************************************/
9147 :
9148 : /**
9149 : \brief Return end of feature iterator.
9150 :
9151 : */
9152 :
9153 2 : const GDALDataset::Features::Iterator GDALDataset::Features::end() const
9154 : {
9155 2 : return {m_poSelf, false};
9156 : }
9157 :
9158 : /************************************************************************/
9159 : /* GDALDataset::Layers::Iterator::Private */
9160 : /************************************************************************/
9161 :
9162 : struct GDALDataset::Layers::Iterator::Private
9163 : {
9164 : OGRLayer *m_poLayer = nullptr;
9165 : int m_iCurLayer = 0;
9166 : int m_nLayerCount = 0;
9167 : GDALDataset *m_poDS = nullptr;
9168 : };
9169 :
9170 2 : GDALDataset::Layers::Iterator::Iterator() : m_poPrivate(new Private())
9171 : {
9172 2 : }
9173 :
9174 : // False positive of cppcheck 1.72
9175 : // cppcheck-suppress uninitMemberVar
9176 9 : GDALDataset::Layers::Iterator::Iterator(const Iterator &oOther)
9177 9 : : m_poPrivate(new Private(*(oOther.m_poPrivate)))
9178 : {
9179 9 : }
9180 :
9181 5 : GDALDataset::Layers::Iterator::Iterator(Iterator &&oOther) noexcept
9182 5 : : m_poPrivate(std::move(oOther.m_poPrivate))
9183 : {
9184 5 : }
9185 :
9186 790 : GDALDataset::Layers::Iterator::Iterator(GDALDataset *poDS, bool bStart)
9187 790 : : m_poPrivate(new Private())
9188 : {
9189 790 : m_poPrivate->m_poDS = poDS;
9190 790 : m_poPrivate->m_nLayerCount = poDS->GetLayerCount();
9191 790 : if (bStart)
9192 : {
9193 397 : if (m_poPrivate->m_nLayerCount)
9194 346 : m_poPrivate->m_poLayer = poDS->GetLayer(0);
9195 : }
9196 : else
9197 : {
9198 393 : m_poPrivate->m_iCurLayer = m_poPrivate->m_nLayerCount;
9199 : }
9200 790 : }
9201 :
9202 : GDALDataset::Layers::Iterator::~Iterator() = default;
9203 :
9204 : // False positive of cppcheck 1.72
9205 : // cppcheck-suppress operatorEqVarError
9206 : GDALDataset::Layers::Iterator &
9207 1 : GDALDataset::Layers::Iterator::operator=(const Iterator &oOther)
9208 : {
9209 1 : *m_poPrivate = *oOther.m_poPrivate;
9210 1 : return *this;
9211 : }
9212 :
9213 3 : GDALDataset::Layers::Iterator &GDALDataset::Layers::Iterator::operator=(
9214 : GDALDataset::Layers::Iterator &&oOther) noexcept
9215 : {
9216 3 : m_poPrivate = std::move(oOther.m_poPrivate);
9217 3 : return *this;
9218 : }
9219 :
9220 424 : OGRLayer *GDALDataset::Layers::Iterator::operator*() const
9221 : {
9222 424 : return m_poPrivate->m_poLayer;
9223 : }
9224 :
9225 401 : GDALDataset::Layers::Iterator &GDALDataset::Layers::Iterator::operator++()
9226 : {
9227 401 : m_poPrivate->m_iCurLayer++;
9228 401 : if (m_poPrivate->m_iCurLayer < m_poPrivate->m_nLayerCount)
9229 : {
9230 84 : m_poPrivate->m_poLayer =
9231 84 : m_poPrivate->m_poDS->GetLayer(m_poPrivate->m_iCurLayer);
9232 : }
9233 : else
9234 : {
9235 317 : m_poPrivate->m_poLayer = nullptr;
9236 : }
9237 401 : return *this;
9238 : }
9239 :
9240 2 : GDALDataset::Layers::Iterator GDALDataset::Layers::Iterator::operator++(int)
9241 : {
9242 2 : GDALDataset::Layers::Iterator temp = *this;
9243 2 : ++(*this);
9244 2 : return temp;
9245 : }
9246 :
9247 788 : bool GDALDataset::Layers::Iterator::operator!=(const Iterator &it) const
9248 : {
9249 788 : return m_poPrivate->m_iCurLayer != it.m_poPrivate->m_iCurLayer;
9250 : }
9251 :
9252 : /************************************************************************/
9253 : /* GetLayers() */
9254 : /************************************************************************/
9255 :
9256 : /** Function that returns an iterable object over layers in the dataset.
9257 : *
9258 : * This is a C++ iterator friendly version of GetLayer().
9259 : *
9260 : * Typical use is:
9261 : * \code{.cpp}
9262 : * for( auto&& poLayer: poDS->GetLayers() )
9263 : * {
9264 : * std::cout << "Layer << poLayer->GetName() << std::endl;
9265 : * }
9266 : * \endcode
9267 : *
9268 : * @see GetLayer()
9269 : *
9270 : */
9271 398 : GDALDataset::Layers GDALDataset::GetLayers()
9272 : {
9273 398 : return Layers(this);
9274 : }
9275 :
9276 : /************************************************************************/
9277 : /* begin() */
9278 : /************************************************************************/
9279 :
9280 : /**
9281 : \brief Return beginning of layer iterator.
9282 :
9283 : */
9284 :
9285 397 : GDALDataset::Layers::Iterator GDALDataset::Layers::begin() const
9286 : {
9287 397 : return {m_poSelf, true};
9288 : }
9289 :
9290 : /************************************************************************/
9291 : /* end() */
9292 : /************************************************************************/
9293 :
9294 : /**
9295 : \brief Return end of layer iterator.
9296 :
9297 : */
9298 :
9299 393 : GDALDataset::Layers::Iterator GDALDataset::Layers::end() const
9300 : {
9301 393 : return {m_poSelf, false};
9302 : }
9303 :
9304 : /************************************************************************/
9305 : /* size() */
9306 : /************************************************************************/
9307 :
9308 : /**
9309 : \brief Get the number of layers in this dataset.
9310 :
9311 : @return layer count.
9312 :
9313 : */
9314 :
9315 1 : size_t GDALDataset::Layers::size() const
9316 : {
9317 1 : return static_cast<size_t>(m_poSelf->GetLayerCount());
9318 : }
9319 :
9320 : /************************************************************************/
9321 : /* operator[]() */
9322 : /************************************************************************/
9323 : /**
9324 : \brief Fetch a layer by index.
9325 :
9326 : The returned layer remains owned by the
9327 : GDALDataset and should not be deleted by the application.
9328 :
9329 : @param iLayer a layer number between 0 and size()-1.
9330 :
9331 : @return the layer, or nullptr if iLayer is out of range or an error occurs.
9332 :
9333 : */
9334 :
9335 9 : OGRLayer *GDALDataset::Layers::operator[](int iLayer)
9336 : {
9337 9 : return m_poSelf->GetLayer(iLayer);
9338 : }
9339 :
9340 : /************************************************************************/
9341 : /* operator[]() */
9342 : /************************************************************************/
9343 : /**
9344 : \brief Fetch a layer by index.
9345 :
9346 : The returned layer remains owned by the
9347 : GDALDataset and should not be deleted by the application.
9348 :
9349 : @param iLayer a layer number between 0 and size()-1.
9350 :
9351 : @return the layer, or nullptr if iLayer is out of range or an error occurs.
9352 :
9353 : */
9354 :
9355 1 : OGRLayer *GDALDataset::Layers::operator[](size_t iLayer)
9356 : {
9357 1 : return m_poSelf->GetLayer(static_cast<int>(iLayer));
9358 : }
9359 :
9360 : /************************************************************************/
9361 : /* operator[]() */
9362 : /************************************************************************/
9363 : /**
9364 : \brief Fetch a layer by name.
9365 :
9366 : The returned layer remains owned by the
9367 : GDALDataset and should not be deleted by the application.
9368 :
9369 : @param pszLayerName layer name
9370 :
9371 : @return the layer, or nullptr if pszLayerName does not match with a layer
9372 :
9373 : */
9374 :
9375 1 : OGRLayer *GDALDataset::Layers::operator[](const char *pszLayerName)
9376 : {
9377 1 : return m_poSelf->GetLayerByName(pszLayerName);
9378 : }
9379 :
9380 : /************************************************************************/
9381 : /* GDALDataset::ConstLayers::Iterator::Private */
9382 : /************************************************************************/
9383 :
9384 : struct GDALDataset::ConstLayers::Iterator::Private
9385 : {
9386 : const OGRLayer *m_poLayer = nullptr;
9387 : int m_iCurLayer = 0;
9388 : int m_nLayerCount = 0;
9389 : const GDALDataset *m_poDS = nullptr;
9390 : };
9391 :
9392 2 : GDALDataset::ConstLayers::Iterator::Iterator() : m_poPrivate(new Private())
9393 : {
9394 2 : }
9395 :
9396 : // False positive of cppcheck 1.72
9397 : // cppcheck-suppress uninitMemberVar
9398 9 : GDALDataset::ConstLayers::Iterator::Iterator(const Iterator &oOther)
9399 9 : : m_poPrivate(new Private(*(oOther.m_poPrivate)))
9400 : {
9401 9 : }
9402 :
9403 5 : GDALDataset::ConstLayers::Iterator::Iterator(Iterator &&oOther) noexcept
9404 5 : : m_poPrivate(std::move(oOther.m_poPrivate))
9405 : {
9406 5 : }
9407 :
9408 35302 : GDALDataset::ConstLayers::Iterator::Iterator(const GDALDataset *poDS,
9409 35302 : bool bStart)
9410 35302 : : m_poPrivate(new Private())
9411 : {
9412 35302 : m_poPrivate->m_poDS = poDS;
9413 35302 : m_poPrivate->m_nLayerCount = poDS->GetLayerCount();
9414 35302 : if (bStart)
9415 : {
9416 17653 : if (m_poPrivate->m_nLayerCount)
9417 218 : m_poPrivate->m_poLayer = poDS->GetLayer(0);
9418 : }
9419 : else
9420 : {
9421 17649 : m_poPrivate->m_iCurLayer = m_poPrivate->m_nLayerCount;
9422 : }
9423 35302 : }
9424 :
9425 : GDALDataset::ConstLayers::Iterator::~Iterator() = default;
9426 :
9427 : // False positive of cppcheck 1.72
9428 : // cppcheck-suppress operatorEqVarError
9429 : GDALDataset::ConstLayers::Iterator &
9430 1 : GDALDataset::ConstLayers::Iterator::operator=(const Iterator &oOther)
9431 : {
9432 1 : *m_poPrivate = *oOther.m_poPrivate;
9433 1 : return *this;
9434 : }
9435 :
9436 : GDALDataset::ConstLayers::Iterator &
9437 3 : GDALDataset::ConstLayers::Iterator::operator=(
9438 : GDALDataset::ConstLayers::Iterator &&oOther) noexcept
9439 : {
9440 3 : m_poPrivate = std::move(oOther.m_poPrivate);
9441 3 : return *this;
9442 : }
9443 :
9444 16176 : const OGRLayer *GDALDataset::ConstLayers::Iterator::operator*() const
9445 : {
9446 16176 : return m_poPrivate->m_poLayer;
9447 : }
9448 :
9449 : GDALDataset::ConstLayers::Iterator &
9450 16171 : GDALDataset::ConstLayers::Iterator::operator++()
9451 : {
9452 16171 : m_poPrivate->m_iCurLayer++;
9453 16171 : if (m_poPrivate->m_iCurLayer < m_poPrivate->m_nLayerCount)
9454 : {
9455 15964 : m_poPrivate->m_poLayer =
9456 15964 : m_poPrivate->m_poDS->GetLayer(m_poPrivate->m_iCurLayer);
9457 : }
9458 : else
9459 : {
9460 207 : m_poPrivate->m_poLayer = nullptr;
9461 : }
9462 16171 : return *this;
9463 : }
9464 :
9465 : GDALDataset::ConstLayers::Iterator
9466 2 : GDALDataset::ConstLayers::Iterator::operator++(int)
9467 : {
9468 2 : GDALDataset::ConstLayers::Iterator temp = *this;
9469 2 : ++(*this);
9470 2 : return temp;
9471 : }
9472 :
9473 33814 : bool GDALDataset::ConstLayers::Iterator::operator!=(const Iterator &it) const
9474 : {
9475 33814 : return m_poPrivate->m_iCurLayer != it.m_poPrivate->m_iCurLayer;
9476 : }
9477 :
9478 : /************************************************************************/
9479 : /* GetLayers() */
9480 : /************************************************************************/
9481 :
9482 : /** Function that returns an iterable object over layers in the dataset.
9483 : *
9484 : * This is a C++ iterator friendly version of GetLayer().
9485 : *
9486 : * Typical use is:
9487 : * \code{.cpp}
9488 : * for( auto&& poLayer: poDS->GetLayers() )
9489 : * {
9490 : * std::cout << "Layer << poLayer->GetName() << std::endl;
9491 : * }
9492 : * \endcode
9493 : *
9494 : * @see GetLayer()
9495 : *
9496 : * @since GDAL 3.12
9497 : */
9498 17654 : GDALDataset::ConstLayers GDALDataset::GetLayers() const
9499 : {
9500 17654 : return ConstLayers(this);
9501 : }
9502 :
9503 : /************************************************************************/
9504 : /* begin() */
9505 : /************************************************************************/
9506 :
9507 : /**
9508 : \brief Return beginning of layer iterator.
9509 :
9510 : @since GDAL 3.12
9511 : */
9512 :
9513 17653 : GDALDataset::ConstLayers::Iterator GDALDataset::ConstLayers::begin() const
9514 : {
9515 17653 : return {m_poSelf, true};
9516 : }
9517 :
9518 : /************************************************************************/
9519 : /* end() */
9520 : /************************************************************************/
9521 :
9522 : /**
9523 : \brief Return end of layer iterator.
9524 :
9525 : @since GDAL 3.12
9526 : */
9527 :
9528 17649 : GDALDataset::ConstLayers::Iterator GDALDataset::ConstLayers::end() const
9529 : {
9530 17649 : return {m_poSelf, false};
9531 : }
9532 :
9533 : /************************************************************************/
9534 : /* size() */
9535 : /************************************************************************/
9536 :
9537 : /**
9538 : \brief Get the number of layers in this dataset.
9539 :
9540 : @return layer count.
9541 :
9542 : @since GDAL 3.12
9543 : */
9544 :
9545 1 : size_t GDALDataset::ConstLayers::size() const
9546 : {
9547 1 : return static_cast<size_t>(m_poSelf->GetLayerCount());
9548 : }
9549 :
9550 : /************************************************************************/
9551 : /* operator[]() */
9552 : /************************************************************************/
9553 : /**
9554 : \brief Fetch a layer by index.
9555 :
9556 : The returned layer remains owned by the
9557 : GDALDataset and should not be deleted by the application.
9558 :
9559 : @param iLayer a layer number between 0 and size()-1.
9560 :
9561 : @return the layer, or nullptr if iLayer is out of range or an error occurs.
9562 :
9563 : @since GDAL 3.12
9564 : */
9565 :
9566 9 : const OGRLayer *GDALDataset::ConstLayers::operator[](int iLayer)
9567 : {
9568 9 : return m_poSelf->GetLayer(iLayer);
9569 : }
9570 :
9571 : /************************************************************************/
9572 : /* operator[]() */
9573 : /************************************************************************/
9574 : /**
9575 : \brief Fetch a layer by index.
9576 :
9577 : The returned layer remains owned by the
9578 : GDALDataset and should not be deleted by the application.
9579 :
9580 : @param iLayer a layer number between 0 and size()-1.
9581 :
9582 : @return the layer, or nullptr if iLayer is out of range or an error occurs.
9583 :
9584 : @since GDAL 3.12
9585 : */
9586 :
9587 1 : const OGRLayer *GDALDataset::ConstLayers::operator[](size_t iLayer)
9588 : {
9589 1 : return m_poSelf->GetLayer(static_cast<int>(iLayer));
9590 : }
9591 :
9592 : /************************************************************************/
9593 : /* operator[]() */
9594 : /************************************************************************/
9595 : /**
9596 : \brief Fetch a layer by name.
9597 :
9598 : The returned layer remains owned by the
9599 : GDALDataset and should not be deleted by the application.
9600 :
9601 : @param pszLayerName layer name
9602 :
9603 : @return the layer, or nullptr if pszLayerName does not match with a layer
9604 :
9605 : @since GDAL 3.12
9606 : */
9607 :
9608 1 : const OGRLayer *GDALDataset::ConstLayers::operator[](const char *pszLayerName)
9609 : {
9610 1 : return const_cast<GDALDataset *>(m_poSelf)->GetLayerByName(pszLayerName);
9611 : }
9612 :
9613 : /************************************************************************/
9614 : /* GDALDataset::Bands::Iterator::Private */
9615 : /************************************************************************/
9616 :
9617 : struct GDALDataset::Bands::Iterator::Private
9618 : {
9619 : GDALRasterBand *m_poBand = nullptr;
9620 : int m_iCurBand = 0;
9621 : int m_nBandCount = 0;
9622 : GDALDataset *m_poDS = nullptr;
9623 : };
9624 :
9625 32 : GDALDataset::Bands::Iterator::Iterator(GDALDataset *poDS, bool bStart)
9626 32 : : m_poPrivate(new GDALDataset::Bands::Iterator::Private())
9627 : {
9628 32 : m_poPrivate->m_poDS = poDS;
9629 32 : m_poPrivate->m_nBandCount = poDS->GetRasterCount();
9630 32 : if (bStart)
9631 : {
9632 16 : if (m_poPrivate->m_nBandCount)
9633 16 : m_poPrivate->m_poBand = poDS->GetRasterBand(1);
9634 : }
9635 : else
9636 : {
9637 16 : m_poPrivate->m_iCurBand = m_poPrivate->m_nBandCount;
9638 : }
9639 32 : }
9640 :
9641 : GDALDataset::Bands::Iterator::~Iterator() = default;
9642 :
9643 18 : GDALRasterBand *GDALDataset::Bands::Iterator::operator*()
9644 : {
9645 18 : return m_poPrivate->m_poBand;
9646 : }
9647 :
9648 4 : GDALDataset::Bands::Iterator &GDALDataset::Bands::Iterator::operator++()
9649 : {
9650 4 : m_poPrivate->m_iCurBand++;
9651 4 : if (m_poPrivate->m_iCurBand < m_poPrivate->m_nBandCount)
9652 : {
9653 2 : m_poPrivate->m_poBand =
9654 2 : m_poPrivate->m_poDS->GetRasterBand(1 + m_poPrivate->m_iCurBand);
9655 : }
9656 : else
9657 : {
9658 2 : m_poPrivate->m_poBand = nullptr;
9659 : }
9660 4 : return *this;
9661 : }
9662 :
9663 20 : bool GDALDataset::Bands::Iterator::operator!=(const Iterator &it) const
9664 : {
9665 20 : return m_poPrivate->m_iCurBand != it.m_poPrivate->m_iCurBand;
9666 : }
9667 :
9668 : /************************************************************************/
9669 : /* GetBands() */
9670 : /************************************************************************/
9671 :
9672 : /** Function that returns an iterable object over GDALRasterBand in the dataset.
9673 : *
9674 : * This is a C++ iterator friendly version of GetRasterBand().
9675 : *
9676 : * Typical use is:
9677 : * \code{.cpp}
9678 : * for( auto&& poBand: poDS->GetBands() )
9679 : * {
9680 : * std::cout << "Band << poBand->GetDescription() << std::endl;
9681 : * }
9682 : * \endcode
9683 : *
9684 : * @see GetRasterBand()
9685 : *
9686 : */
9687 20 : GDALDataset::Bands GDALDataset::GetBands()
9688 : {
9689 20 : return Bands(this);
9690 : }
9691 :
9692 : /************************************************************************/
9693 : /* begin() */
9694 : /************************************************************************/
9695 :
9696 : /**
9697 : \brief Return beginning of band iterator.
9698 :
9699 : */
9700 :
9701 16 : const GDALDataset::Bands::Iterator GDALDataset::Bands::begin() const
9702 : {
9703 16 : return {m_poSelf, true};
9704 : }
9705 :
9706 : /************************************************************************/
9707 : /* end() */
9708 : /************************************************************************/
9709 :
9710 : /**
9711 : \brief Return end of band iterator.
9712 :
9713 : */
9714 :
9715 16 : const GDALDataset::Bands::Iterator GDALDataset::Bands::end() const
9716 : {
9717 16 : return {m_poSelf, false};
9718 : }
9719 :
9720 : /************************************************************************/
9721 : /* size() */
9722 : /************************************************************************/
9723 :
9724 : /**
9725 : \brief Get the number of raster bands in this dataset.
9726 :
9727 : @return raster band count.
9728 :
9729 : */
9730 :
9731 2 : size_t GDALDataset::Bands::size() const
9732 : {
9733 2 : return static_cast<size_t>(m_poSelf->GetRasterCount());
9734 : }
9735 :
9736 : /************************************************************************/
9737 : /* operator[]() */
9738 : /************************************************************************/
9739 : /**
9740 : \brief Fetch a raster band by index.
9741 :
9742 : The returned band remains owned by the
9743 : GDALDataset and should not be deleted by the application.
9744 :
9745 : @warning Contrary to GDALDataset::GetRasterBand(), the indexing here is
9746 : consistent with the conventions of C/C++, i.e. starting at 0.
9747 :
9748 : @param iBand a band index between 0 and size()-1.
9749 :
9750 : @return the band, or nullptr if iBand is out of range or an error occurs.
9751 :
9752 : */
9753 :
9754 1 : GDALRasterBand *GDALDataset::Bands::operator[](int iBand)
9755 : {
9756 1 : return m_poSelf->GetRasterBand(1 + iBand);
9757 : }
9758 :
9759 : /************************************************************************/
9760 : /* operator[]() */
9761 : /************************************************************************/
9762 :
9763 : /**
9764 : \brief Fetch a raster band by index.
9765 :
9766 : The returned band remains owned by the
9767 : GDALDataset and should not be deleted by the application.
9768 :
9769 : @warning Contrary to GDALDataset::GetRasterBand(), the indexing here is
9770 : consistent with the conventions of C/C++, i.e. starting at 0.
9771 :
9772 : @param iBand a band index between 0 and size()-1.
9773 :
9774 : @return the band, or nullptr if iBand is out of range or an error occurs.
9775 :
9776 : */
9777 :
9778 1 : GDALRasterBand *GDALDataset::Bands::operator[](size_t iBand)
9779 : {
9780 1 : return m_poSelf->GetRasterBand(1 + static_cast<int>(iBand));
9781 : }
9782 :
9783 : /************************************************************************/
9784 : /* GDALDataset::ConstBands::Iterator::Private */
9785 : /************************************************************************/
9786 :
9787 : struct GDALDataset::ConstBands::Iterator::Private
9788 : {
9789 : const GDALRasterBand *m_poBand = nullptr;
9790 : int m_iCurBand = 0;
9791 : int m_nBandCount = 0;
9792 : const GDALDataset *m_poDS = nullptr;
9793 : };
9794 :
9795 2 : GDALDataset::ConstBands::Iterator::Iterator(const GDALDataset *poDS,
9796 2 : bool bStart)
9797 2 : : m_poPrivate(new GDALDataset::ConstBands::Iterator::Private())
9798 : {
9799 2 : m_poPrivate->m_poDS = poDS;
9800 2 : m_poPrivate->m_nBandCount = poDS->GetRasterCount();
9801 2 : if (bStart)
9802 : {
9803 1 : if (m_poPrivate->m_nBandCount)
9804 1 : m_poPrivate->m_poBand = poDS->GetRasterBand(1);
9805 : }
9806 : else
9807 : {
9808 1 : m_poPrivate->m_iCurBand = m_poPrivate->m_nBandCount;
9809 : }
9810 2 : }
9811 :
9812 : GDALDataset::ConstBands::Iterator::~Iterator() = default;
9813 :
9814 3 : const GDALRasterBand *GDALDataset::ConstBands::Iterator::operator*() const
9815 : {
9816 3 : return m_poPrivate->m_poBand;
9817 : }
9818 :
9819 : GDALDataset::ConstBands::Iterator &
9820 3 : GDALDataset::ConstBands::Iterator::operator++()
9821 : {
9822 3 : m_poPrivate->m_iCurBand++;
9823 3 : if (m_poPrivate->m_iCurBand < m_poPrivate->m_nBandCount)
9824 : {
9825 2 : m_poPrivate->m_poBand =
9826 2 : m_poPrivate->m_poDS->GetRasterBand(1 + m_poPrivate->m_iCurBand);
9827 : }
9828 : else
9829 : {
9830 1 : m_poPrivate->m_poBand = nullptr;
9831 : }
9832 3 : return *this;
9833 : }
9834 :
9835 4 : bool GDALDataset::ConstBands::Iterator::operator!=(const Iterator &it) const
9836 : {
9837 4 : return m_poPrivate->m_iCurBand != it.m_poPrivate->m_iCurBand;
9838 : }
9839 :
9840 : /************************************************************************/
9841 : /* GetBands() */
9842 : /************************************************************************/
9843 :
9844 : /** Function that returns an iterable object over GDALRasterBand in the dataset.
9845 : *
9846 : * This is a C++ iterator friendly version of GetRasterBand().
9847 : *
9848 : * Typical use is:
9849 : * \code{.cpp}
9850 : * for( const auto* poBand: poDS->GetConstBands() )
9851 : * {
9852 : * std::cout << "Band << poBand->GetDescription() << std::endl;
9853 : * }
9854 : * \endcode
9855 : *
9856 : * @see GetRasterBand()
9857 : *
9858 : * @since GDAL 3.12
9859 : */
9860 4 : GDALDataset::ConstBands GDALDataset::GetBands() const
9861 : {
9862 4 : return ConstBands(this);
9863 : }
9864 :
9865 : /************************************************************************/
9866 : /* begin() */
9867 : /************************************************************************/
9868 :
9869 : /**
9870 : \brief Return beginning of band iterator.
9871 :
9872 : @since GDAL 3.12
9873 : */
9874 :
9875 1 : const GDALDataset::ConstBands::Iterator GDALDataset::ConstBands::begin() const
9876 : {
9877 1 : return {m_poSelf, true};
9878 : }
9879 :
9880 : /************************************************************************/
9881 : /* end() */
9882 : /************************************************************************/
9883 :
9884 : /**
9885 : \brief Return end of band iterator.
9886 :
9887 : @since GDAL 3.12
9888 : */
9889 :
9890 1 : const GDALDataset::ConstBands::Iterator GDALDataset::ConstBands::end() const
9891 : {
9892 1 : return {m_poSelf, false};
9893 : }
9894 :
9895 : /************************************************************************/
9896 : /* size() */
9897 : /************************************************************************/
9898 :
9899 : /**
9900 : \brief Get the number of raster bands in this dataset.
9901 :
9902 : @return raster band count.
9903 :
9904 : @since GDAL 3.12
9905 : */
9906 :
9907 1 : size_t GDALDataset::ConstBands::size() const
9908 : {
9909 1 : return static_cast<size_t>(m_poSelf->GetRasterCount());
9910 : }
9911 :
9912 : /************************************************************************/
9913 : /* operator[]() */
9914 : /************************************************************************/
9915 : /**
9916 : \brief Fetch a raster band by index.
9917 :
9918 : The returned band remains owned by the
9919 : GDALDataset and should not be deleted by the application.
9920 :
9921 : @warning Contrary to GDALDataset::GetRasterBand(), the indexing here is
9922 : consistent with the conventions of C/C++, i.e. starting at 0.
9923 :
9924 : @param iBand a band index between 0 and size()-1.
9925 :
9926 : @return the band, or nullptr if iBand is out of range or an error occurs.
9927 :
9928 : @since GDAL 3.12
9929 : */
9930 :
9931 1 : const GDALRasterBand *GDALDataset::ConstBands::operator[](int iBand) const
9932 : {
9933 1 : return m_poSelf->GetRasterBand(1 + iBand);
9934 : }
9935 :
9936 : /************************************************************************/
9937 : /* operator[]() */
9938 : /************************************************************************/
9939 :
9940 : /**
9941 : \brief Fetch a raster band by index.
9942 :
9943 : The returned band remains owned by the
9944 : GDALDataset and should not be deleted by the application.
9945 :
9946 : @warning Contrary to GDALDataset::GetRasterBand(), the indexing here is
9947 : consistent with the conventions of C/C++, i.e. starting at 0.
9948 :
9949 : @param iBand a band index between 0 and size()-1.
9950 :
9951 : @return the band, or nullptr if iBand is out of range or an error occurs.
9952 :
9953 : @since GDAL 3.12
9954 : */
9955 :
9956 1 : const GDALRasterBand *GDALDataset::ConstBands::operator[](size_t iBand) const
9957 : {
9958 1 : return m_poSelf->GetRasterBand(1 + static_cast<int>(iBand));
9959 : }
9960 :
9961 : /************************************************************************/
9962 : /* GetRootGroup() */
9963 : /************************************************************************/
9964 :
9965 : /**
9966 : \brief Return the root GDALGroup of this dataset.
9967 :
9968 : Only valid for multidimensional datasets.
9969 :
9970 : This is the same as the C function GDALDatasetGetRootGroup().
9971 :
9972 : @since GDAL 3.1
9973 : */
9974 :
9975 2911 : std::shared_ptr<GDALGroup> GDALDataset::GetRootGroup() const
9976 : {
9977 2911 : return nullptr;
9978 : }
9979 :
9980 : /************************************************************************/
9981 : /* GetRawBinaryLayout() */
9982 : /************************************************************************/
9983 :
9984 : //! @cond Doxygen_Suppress
9985 : /**
9986 : \brief Return the layout of a dataset that can be considered as a raw binary
9987 : format.
9988 :
9989 : @param sLayout Structure that will be set if the dataset is a raw binary one.
9990 : @return true if the dataset is a raw binary one.
9991 : @since GDAL 3.1
9992 : */
9993 :
9994 0 : bool GDALDataset::GetRawBinaryLayout(RawBinaryLayout &sLayout)
9995 : {
9996 0 : CPL_IGNORE_RET_VAL(sLayout);
9997 0 : return false;
9998 : }
9999 :
10000 : //! @endcond
10001 :
10002 : /************************************************************************/
10003 : /* ClearStatistics() */
10004 : /************************************************************************/
10005 :
10006 : /**
10007 : \brief Clear statistics
10008 :
10009 : Only implemented for now in PAM supported datasets
10010 :
10011 : This is the same as the C function GDALDatasetClearStatistics().
10012 :
10013 : @since GDAL 3.2
10014 : */
10015 :
10016 11 : void GDALDataset::ClearStatistics()
10017 : {
10018 22 : auto poRootGroup = GetRootGroup();
10019 11 : if (poRootGroup)
10020 1 : poRootGroup->ClearStatistics();
10021 11 : }
10022 :
10023 : /************************************************************************/
10024 : /* GDALDatasetClearStatistics() */
10025 : /************************************************************************/
10026 :
10027 : /**
10028 : \brief Clear statistics
10029 :
10030 : This is the same as the C++ method GDALDataset::ClearStatistics().
10031 :
10032 : @since GDAL 3.2
10033 : */
10034 :
10035 2 : void GDALDatasetClearStatistics(GDALDatasetH hDS)
10036 : {
10037 2 : VALIDATE_POINTER0(hDS, __func__);
10038 2 : GDALDataset::FromHandle(hDS)->ClearStatistics();
10039 : }
10040 :
10041 : /************************************************************************/
10042 : /* GetFieldDomainNames() */
10043 : /************************************************************************/
10044 :
10045 : /** Returns a list of the names of all field domains stored in the dataset.
10046 : *
10047 : * @note The default implementation assumes that drivers fully populate
10048 : * m_oMapFieldDomains when opening a dataset. If this assumption is incorrect
10049 : * then a specialized implementation of GetFieldDomainNames() must be
10050 : * implemented.
10051 : *
10052 : * @param papszOptions Driver specific options determining how attributes
10053 : * should be retrieved. Pass nullptr for default behavior.
10054 : *
10055 : * @return list of field domain names
10056 : * @since GDAL 3.5
10057 : */
10058 : std::vector<std::string>
10059 46 : GDALDataset::GetFieldDomainNames(CPL_UNUSED CSLConstList papszOptions) const
10060 : {
10061 :
10062 46 : std::vector<std::string> names;
10063 46 : names.reserve(m_oMapFieldDomains.size());
10064 58 : for (const auto &it : m_oMapFieldDomains)
10065 : {
10066 12 : names.emplace_back(it.first);
10067 : }
10068 46 : return names;
10069 : }
10070 :
10071 : /************************************************************************/
10072 : /* GDALDatasetGetFieldDomainNames() */
10073 : /************************************************************************/
10074 :
10075 : /** Returns a list of the names of all field domains stored in the dataset.
10076 : *
10077 : * This is the same as the C++ method GDALDataset::GetFieldDomainNames().
10078 : *
10079 : * @param hDS Dataset handle.
10080 : * @param papszOptions Driver specific options determining how attributes
10081 : * should be retrieved. Pass nullptr for default behavior.
10082 : *
10083 : * @return list of field domain names, to be freed with CSLDestroy()
10084 : * @since GDAL 3.5
10085 : */
10086 34 : char **GDALDatasetGetFieldDomainNames(GDALDatasetH hDS,
10087 : CSLConstList papszOptions)
10088 : {
10089 34 : VALIDATE_POINTER1(hDS, __func__, nullptr);
10090 : auto names =
10091 68 : GDALDataset::FromHandle(hDS)->GetFieldDomainNames(papszOptions);
10092 68 : CPLStringList res;
10093 154 : for (const auto &name : names)
10094 : {
10095 120 : res.AddString(name.c_str());
10096 : }
10097 34 : return res.StealList();
10098 : }
10099 :
10100 : /************************************************************************/
10101 : /* GetFieldDomain() */
10102 : /************************************************************************/
10103 :
10104 : /** Get a field domain from its name.
10105 : *
10106 : * @return the field domain, or nullptr if not found.
10107 : * @since GDAL 3.3
10108 : */
10109 323 : const OGRFieldDomain *GDALDataset::GetFieldDomain(const std::string &name) const
10110 : {
10111 323 : const auto iter = m_oMapFieldDomains.find(name);
10112 323 : if (iter == m_oMapFieldDomains.end())
10113 151 : return nullptr;
10114 172 : return iter->second.get();
10115 : }
10116 :
10117 : /************************************************************************/
10118 : /* GDALDatasetGetFieldDomain() */
10119 : /************************************************************************/
10120 :
10121 : /** Get a field domain from its name.
10122 : *
10123 : * This is the same as the C++ method GDALDataset::GetFieldDomain().
10124 : *
10125 : * @param hDS Dataset handle.
10126 : * @param pszName Name of field domain.
10127 : * @return the field domain (ownership remains to the dataset), or nullptr if
10128 : * not found.
10129 : * @since GDAL 3.3
10130 : */
10131 130 : OGRFieldDomainH GDALDatasetGetFieldDomain(GDALDatasetH hDS, const char *pszName)
10132 : {
10133 130 : VALIDATE_POINTER1(hDS, __func__, nullptr);
10134 130 : VALIDATE_POINTER1(pszName, __func__, nullptr);
10135 130 : return OGRFieldDomain::ToHandle(const_cast<OGRFieldDomain *>(
10136 130 : GDALDataset::FromHandle(hDS)->GetFieldDomain(pszName)));
10137 : }
10138 :
10139 : /************************************************************************/
10140 : /* AddFieldDomain() */
10141 : /************************************************************************/
10142 :
10143 : /** Add a field domain to the dataset.
10144 : *
10145 : * Only a few drivers will support this operation, and some of them might only
10146 : * support it only for some types of field domains.
10147 : * At the time of writing (GDAL 3.3), only the Memory and GeoPackage drivers
10148 : * support this operation. A dataset having at least some support for this
10149 : * operation should report the ODsCAddFieldDomain dataset capability.
10150 : *
10151 : * Anticipated failures will not be emitted through the CPLError()
10152 : * infrastructure, but will be reported in the failureReason output parameter.
10153 : *
10154 : * @note Drivers should make sure to update m_oMapFieldDomains in order for the
10155 : * default implementation of GetFieldDomainNames() to work correctly, or
10156 : * alternatively a specialized implementation of GetFieldDomainNames() should be
10157 : * implemented.
10158 : *
10159 : * @param domain The domain definition.
10160 : * @param failureReason Output parameter. Will contain an error message if
10161 : * an error occurs.
10162 : * @return true in case of success.
10163 : * @since GDAL 3.3
10164 : */
10165 0 : bool GDALDataset::AddFieldDomain(
10166 : CPL_UNUSED std::unique_ptr<OGRFieldDomain> &&domain,
10167 : std::string &failureReason)
10168 : {
10169 0 : failureReason = "AddFieldDomain not supported by this driver";
10170 0 : return false;
10171 : }
10172 :
10173 : /************************************************************************/
10174 : /* GDALDatasetAddFieldDomain() */
10175 : /************************************************************************/
10176 :
10177 : /** Add a field domain to the dataset.
10178 : *
10179 : * Only a few drivers will support this operation, and some of them might only
10180 : * support it only for some types of field domains.
10181 : * At the time of writing (GDAL 3.3), only the Memory and GeoPackage drivers
10182 : * support this operation. A dataset having at least some support for this
10183 : * operation should report the ODsCAddFieldDomain dataset capability.
10184 : *
10185 : * Anticipated failures will not be emitted through the CPLError()
10186 : * infrastructure, but will be reported in the ppszFailureReason output
10187 : * parameter.
10188 : *
10189 : * @param hDS Dataset handle.
10190 : * @param hFieldDomain The domain definition. Contrary to the C++ version,
10191 : * the passed object is copied.
10192 : * @param ppszFailureReason Output parameter. Will contain an error message if
10193 : * an error occurs (*ppszFailureReason to be freed
10194 : * with CPLFree). May be NULL.
10195 : * @return true in case of success.
10196 : * @since GDAL 3.3
10197 : */
10198 37 : bool GDALDatasetAddFieldDomain(GDALDatasetH hDS, OGRFieldDomainH hFieldDomain,
10199 : char **ppszFailureReason)
10200 : {
10201 37 : VALIDATE_POINTER1(hDS, __func__, false);
10202 37 : VALIDATE_POINTER1(hFieldDomain, __func__, false);
10203 : auto poDomain = std::unique_ptr<OGRFieldDomain>(
10204 74 : OGRFieldDomain::FromHandle(hFieldDomain)->Clone());
10205 37 : if (poDomain == nullptr)
10206 0 : return false;
10207 37 : std::string failureReason;
10208 74 : const bool bRet = GDALDataset::FromHandle(hDS)->AddFieldDomain(
10209 37 : std::move(poDomain), failureReason);
10210 37 : if (ppszFailureReason)
10211 : {
10212 37 : *ppszFailureReason =
10213 37 : failureReason.empty() ? nullptr : CPLStrdup(failureReason.c_str());
10214 : }
10215 37 : return bRet;
10216 : }
10217 :
10218 : /************************************************************************/
10219 : /* DeleteFieldDomain() */
10220 : /************************************************************************/
10221 :
10222 : /** Removes a field domain from the dataset.
10223 : *
10224 : * Only a few drivers will support this operation.
10225 : *
10226 : * At the time of writing (GDAL 3.5), only the Memory and GeoPackage drivers
10227 : * support this operation. A dataset having at least some support for this
10228 : * operation should report the ODsCDeleteFieldDomain dataset capability.
10229 : *
10230 : * Anticipated failures will not be emitted through the CPLError()
10231 : * infrastructure, but will be reported in the failureReason output parameter.
10232 : *
10233 : * @note Drivers should make sure to update m_oMapFieldDomains in order for the
10234 : * default implementation of GetFieldDomainNames() to work correctly, or
10235 : * alternatively a specialized implementation of GetFieldDomainNames() should be
10236 : * implemented.
10237 : *
10238 : * @param name The domain name.
10239 : * @param failureReason Output parameter. Will contain an error message if
10240 : * an error occurs.
10241 : * @return true in case of success.
10242 : * @since GDAL 3.5
10243 : */
10244 0 : bool GDALDataset::DeleteFieldDomain(CPL_UNUSED const std::string &name,
10245 : std::string &failureReason)
10246 : {
10247 0 : failureReason = "DeleteFieldDomain not supported by this driver";
10248 0 : return false;
10249 : }
10250 :
10251 : /************************************************************************/
10252 : /* GDALDatasetDeleteFieldDomain() */
10253 : /************************************************************************/
10254 :
10255 : /** Removes a field domain from the dataset.
10256 : *
10257 : * Only a few drivers will support this operation.
10258 : *
10259 : * At the time of writing (GDAL 3.5), only the Memory and GeoPackage drivers
10260 : * support this operation. A dataset having at least some support for this
10261 : * operation should report the ODsCDeleteFieldDomain dataset capability.
10262 : *
10263 : * Anticipated failures will not be emitted through the CPLError()
10264 : * infrastructure, but will be reported in the ppszFailureReason output
10265 : * parameter.
10266 : *
10267 : * @param hDS Dataset handle.
10268 : * @param pszName The domain name.
10269 : * @param ppszFailureReason Output parameter. Will contain an error message if
10270 : * an error occurs (*ppszFailureReason to be freed
10271 : * with CPLFree). May be NULL.
10272 : * @return true in case of success.
10273 : * @since GDAL 3.3
10274 : */
10275 25 : bool GDALDatasetDeleteFieldDomain(GDALDatasetH hDS, const char *pszName,
10276 : char **ppszFailureReason)
10277 : {
10278 25 : VALIDATE_POINTER1(hDS, __func__, false);
10279 25 : VALIDATE_POINTER1(pszName, __func__, false);
10280 25 : std::string failureReason;
10281 : const bool bRet =
10282 25 : GDALDataset::FromHandle(hDS)->DeleteFieldDomain(pszName, failureReason);
10283 25 : if (ppszFailureReason)
10284 : {
10285 0 : *ppszFailureReason =
10286 0 : failureReason.empty() ? nullptr : CPLStrdup(failureReason.c_str());
10287 : }
10288 25 : return bRet;
10289 : }
10290 :
10291 : /************************************************************************/
10292 : /* UpdateFieldDomain() */
10293 : /************************************************************************/
10294 :
10295 : /** Updates an existing field domain by replacing its definition.
10296 : *
10297 : * The existing field domain with matching name will be replaced.
10298 : *
10299 : * Only a few drivers will support this operation, and some of them might only
10300 : * support it only for some types of field domains.
10301 : * At the time of writing (GDAL 3.5), only the Memory driver
10302 : * supports this operation. A dataset having at least some support for this
10303 : * operation should report the ODsCUpdateFieldDomain dataset capability.
10304 : *
10305 : * Anticipated failures will not be emitted through the CPLError()
10306 : * infrastructure, but will be reported in the failureReason output parameter.
10307 : *
10308 : * @param domain The domain definition.
10309 : * @param failureReason Output parameter. Will contain an error message if
10310 : * an error occurs.
10311 : * @return true in case of success.
10312 : * @since GDAL 3.5
10313 : */
10314 0 : bool GDALDataset::UpdateFieldDomain(
10315 : CPL_UNUSED std::unique_ptr<OGRFieldDomain> &&domain,
10316 : std::string &failureReason)
10317 : {
10318 0 : failureReason = "UpdateFieldDomain not supported by this driver";
10319 0 : return false;
10320 : }
10321 :
10322 : /************************************************************************/
10323 : /* GDALDatasetUpdateFieldDomain() */
10324 : /************************************************************************/
10325 :
10326 : /** Updates an existing field domain by replacing its definition.
10327 : *
10328 : * The existing field domain with matching name will be replaced.
10329 : *
10330 : * Only a few drivers will support this operation, and some of them might only
10331 : * support it only for some types of field domains.
10332 : * At the time of writing (GDAL 3.5), only the Memory driver
10333 : * supports this operation. A dataset having at least some support for this
10334 : * operation should report the ODsCUpdateFieldDomain dataset capability.
10335 : *
10336 : * Anticipated failures will not be emitted through the CPLError()
10337 : * infrastructure, but will be reported in the failureReason output parameter.
10338 : *
10339 : * @param hDS Dataset handle.
10340 : * @param hFieldDomain The domain definition. Contrary to the C++ version,
10341 : * the passed object is copied.
10342 : * @param ppszFailureReason Output parameter. Will contain an error message if
10343 : * an error occurs (*ppszFailureReason to be freed
10344 : * with CPLFree). May be NULL.
10345 : * @return true in case of success.
10346 : * @since GDAL 3.5
10347 : */
10348 7 : bool GDALDatasetUpdateFieldDomain(GDALDatasetH hDS,
10349 : OGRFieldDomainH hFieldDomain,
10350 : char **ppszFailureReason)
10351 : {
10352 7 : VALIDATE_POINTER1(hDS, __func__, false);
10353 7 : VALIDATE_POINTER1(hFieldDomain, __func__, false);
10354 : auto poDomain = std::unique_ptr<OGRFieldDomain>(
10355 14 : OGRFieldDomain::FromHandle(hFieldDomain)->Clone());
10356 7 : if (poDomain == nullptr)
10357 0 : return false;
10358 7 : std::string failureReason;
10359 14 : const bool bRet = GDALDataset::FromHandle(hDS)->UpdateFieldDomain(
10360 7 : std::move(poDomain), failureReason);
10361 7 : if (ppszFailureReason)
10362 : {
10363 0 : *ppszFailureReason =
10364 0 : failureReason.empty() ? nullptr : CPLStrdup(failureReason.c_str());
10365 : }
10366 7 : return bRet;
10367 : }
10368 :
10369 : /************************************************************************/
10370 : /* GetRelationshipNames() */
10371 : /************************************************************************/
10372 :
10373 : /** Returns a list of the names of all relationships stored in the dataset.
10374 : *
10375 : * @param papszOptions Driver specific options determining how relationships
10376 : * should be retrieved. Pass nullptr for default behavior.
10377 : *
10378 : * @return list of relationship names
10379 : * @since GDAL 3.6
10380 : */
10381 : std::vector<std::string>
10382 186 : GDALDataset::GetRelationshipNames(CPL_UNUSED CSLConstList papszOptions) const
10383 : {
10384 186 : return {};
10385 : }
10386 :
10387 : /************************************************************************/
10388 : /* GDALDatasetGetRelationshipNames() */
10389 : /************************************************************************/
10390 :
10391 : /** Returns a list of the names of all relationships stored in the dataset.
10392 : *
10393 : * This is the same as the C++ method GDALDataset::GetRelationshipNames().
10394 : *
10395 : * @param hDS Dataset handle.
10396 : * @param papszOptions Driver specific options determining how relationships
10397 : * should be retrieved. Pass nullptr for default behavior.
10398 : *
10399 : * @return list of relationship names, to be freed with CSLDestroy()
10400 : * @since GDAL 3.6
10401 : */
10402 46 : char **GDALDatasetGetRelationshipNames(GDALDatasetH hDS,
10403 : CSLConstList papszOptions)
10404 : {
10405 46 : VALIDATE_POINTER1(hDS, __func__, nullptr);
10406 : auto names =
10407 92 : GDALDataset::FromHandle(hDS)->GetRelationshipNames(papszOptions);
10408 92 : CPLStringList res;
10409 146 : for (const auto &name : names)
10410 : {
10411 100 : res.AddString(name.c_str());
10412 : }
10413 46 : return res.StealList();
10414 : }
10415 :
10416 : /************************************************************************/
10417 : /* GetRelationship() */
10418 : /************************************************************************/
10419 :
10420 : /** Get a relationship from its name.
10421 : *
10422 : * @return the relationship, or nullptr if not found.
10423 : * @since GDAL 3.6
10424 : */
10425 : const GDALRelationship *
10426 0 : GDALDataset::GetRelationship(CPL_UNUSED const std::string &name) const
10427 : {
10428 0 : return nullptr;
10429 : }
10430 :
10431 : /************************************************************************/
10432 : /* GDALDatasetGetRelationship() */
10433 : /************************************************************************/
10434 :
10435 : /** Get a relationship from its name.
10436 : *
10437 : * This is the same as the C++ method GDALDataset::GetRelationship().
10438 : *
10439 : * @param hDS Dataset handle.
10440 : * @param pszName Name of relationship.
10441 : * @return the relationship (ownership remains to the dataset), or nullptr if
10442 : * not found.
10443 : * @since GDAL 3.6
10444 : */
10445 52 : GDALRelationshipH GDALDatasetGetRelationship(GDALDatasetH hDS,
10446 : const char *pszName)
10447 : {
10448 52 : VALIDATE_POINTER1(hDS, __func__, nullptr);
10449 52 : VALIDATE_POINTER1(pszName, __func__, nullptr);
10450 52 : return GDALRelationship::ToHandle(const_cast<GDALRelationship *>(
10451 52 : GDALDataset::FromHandle(hDS)->GetRelationship(pszName)));
10452 : }
10453 :
10454 : /************************************************************************/
10455 : /* AddRelationship() */
10456 : /************************************************************************/
10457 :
10458 : /** Add a relationship to the dataset.
10459 : *
10460 : * Only a few drivers will support this operation, and some of them might only
10461 : * support it only for some types of relationships.
10462 : *
10463 : * A dataset having at least some support for this
10464 : * operation should report the GDsCAddRelationship dataset capability.
10465 : *
10466 : * Anticipated failures will not be emitted through the CPLError()
10467 : * infrastructure, but will be reported in the failureReason output parameter.
10468 : *
10469 : * When adding a many-to-many relationship
10470 : * (GDALRelationshipCardinality::GRC_MANY_TO_MANY), it is possible to omit the
10471 : * mapping table name (see GDALRelationship::GetMappingTableName) to instruct
10472 : * the driver to create an appropriately named and structured mapping table.
10473 : * Some dataset formats require particular naming conventions and field
10474 : * structures for the mapping table, and delegating the construction of the
10475 : * mapping table to the driver will avoid these pitfalls.
10476 : *
10477 : * @param relationship The relationship definition.
10478 : * @param failureReason Output parameter. Will contain an error message if
10479 : * an error occurs.
10480 : * @return true in case of success.
10481 : * @since GDAL 3.6
10482 : */
10483 0 : bool GDALDataset::AddRelationship(
10484 : CPL_UNUSED std::unique_ptr<GDALRelationship> &&relationship,
10485 : std::string &failureReason)
10486 : {
10487 0 : failureReason = "AddRelationship not supported by this driver";
10488 0 : return false;
10489 : }
10490 :
10491 : /************************************************************************/
10492 : /* GDALDatasetAddRelationship() */
10493 : /************************************************************************/
10494 :
10495 : /** Add a relationship to the dataset.
10496 : *
10497 : * Only a few drivers will support this operation, and some of them might only
10498 : * support it only for some types of relationships.
10499 : *
10500 : * A dataset having at least some support for this
10501 : * operation should report the GDsCAddRelationship dataset capability.
10502 : *
10503 : * Anticipated failures will not be emitted through the CPLError()
10504 : * infrastructure, but will be reported in the failureReason output parameter.
10505 : *
10506 : * When adding a many-to-many relationship
10507 : * (GDALRelationshipCardinality::GRC_MANY_TO_MANY), it is possible to omit the
10508 : * mapping table name (see GDALRelationshipGetMappingTableName) to instruct the
10509 : * driver to create an appropriately named and structured mapping table. Some
10510 : * dataset formats require particular naming conventions and field structures
10511 : * for the mapping table, and delegating the construction of the mapping table
10512 : * to the driver will avoid these pitfalls.
10513 : *
10514 : * @param hDS Dataset handle.
10515 : * @param hRelationship The relationship definition. Contrary to the C++
10516 : * version, the passed object is copied.
10517 : * @param ppszFailureReason Output parameter. Will contain an error message if
10518 : * an error occurs (*ppszFailureReason to be freed
10519 : * with CPLFree). May be NULL.
10520 : * @return true in case of success.
10521 : * @since GDAL 3.6
10522 : */
10523 42 : bool GDALDatasetAddRelationship(GDALDatasetH hDS,
10524 : GDALRelationshipH hRelationship,
10525 : char **ppszFailureReason)
10526 : {
10527 42 : VALIDATE_POINTER1(hDS, __func__, false);
10528 42 : VALIDATE_POINTER1(hRelationship, __func__, false);
10529 : std::unique_ptr<GDALRelationship> poRelationship(
10530 84 : new GDALRelationship(*GDALRelationship::FromHandle(hRelationship)));
10531 42 : std::string failureReason;
10532 84 : const bool bRet = GDALDataset::FromHandle(hDS)->AddRelationship(
10533 42 : std::move(poRelationship), failureReason);
10534 42 : if (ppszFailureReason)
10535 : {
10536 0 : *ppszFailureReason =
10537 0 : failureReason.empty() ? nullptr : CPLStrdup(failureReason.c_str());
10538 : }
10539 42 : return bRet;
10540 : }
10541 :
10542 : /************************************************************************/
10543 : /* DeleteRelationship() */
10544 : /************************************************************************/
10545 :
10546 : /** Removes a relationship from the dataset.
10547 : *
10548 : * Only a few drivers will support this operation.
10549 : *
10550 : * A dataset having at least some support for this
10551 : * operation should report the GDsCDeleteRelationship dataset capability.
10552 : *
10553 : * Anticipated failures will not be emitted through the CPLError()
10554 : * infrastructure, but will be reported in the failureReason output parameter.
10555 : *
10556 : * @param name The relationship name.
10557 : * @param failureReason Output parameter. Will contain an error message if
10558 : * an error occurs.
10559 : * @return true in case of success.
10560 : * @since GDAL 3.6
10561 : */
10562 0 : bool GDALDataset::DeleteRelationship(CPL_UNUSED const std::string &name,
10563 : std::string &failureReason)
10564 : {
10565 0 : failureReason = "DeleteRelationship not supported by this driver";
10566 0 : return false;
10567 : }
10568 :
10569 : /************************************************************************/
10570 : /* GDALDatasetDeleteRelationship() */
10571 : /************************************************************************/
10572 :
10573 : /** Removes a relationship from the dataset.
10574 : *
10575 : * Only a few drivers will support this operation.
10576 : *
10577 : * A dataset having at least some support for this
10578 : * operation should report the GDsCDeleteRelationship dataset capability.
10579 : *
10580 : * Anticipated failures will not be emitted through the CPLError()
10581 : * infrastructure, but will be reported in the ppszFailureReason output
10582 : * parameter.
10583 : *
10584 : * @param hDS Dataset handle.
10585 : * @param pszName The relationship name.
10586 : * @param ppszFailureReason Output parameter. Will contain an error message if
10587 : * an error occurs (*ppszFailureReason to be freed
10588 : * with CPLFree). May be NULL.
10589 : * @return true in case of success.
10590 : * @since GDAL 3.6
10591 : */
10592 6 : bool GDALDatasetDeleteRelationship(GDALDatasetH hDS, const char *pszName,
10593 : char **ppszFailureReason)
10594 : {
10595 6 : VALIDATE_POINTER1(hDS, __func__, false);
10596 6 : VALIDATE_POINTER1(pszName, __func__, false);
10597 6 : std::string failureReason;
10598 12 : const bool bRet = GDALDataset::FromHandle(hDS)->DeleteRelationship(
10599 6 : pszName, failureReason);
10600 6 : if (ppszFailureReason)
10601 : {
10602 0 : *ppszFailureReason =
10603 0 : failureReason.empty() ? nullptr : CPLStrdup(failureReason.c_str());
10604 : }
10605 6 : return bRet;
10606 : }
10607 :
10608 : /************************************************************************/
10609 : /* UpdateRelationship() */
10610 : /************************************************************************/
10611 :
10612 : /** Updates an existing relationship by replacing its definition.
10613 : *
10614 : * The existing relationship with matching name will be replaced.
10615 : *
10616 : * Only a few drivers will support this operation, and some of them might only
10617 : * support it only for some types of relationships.
10618 : * A dataset having at least some support for this
10619 : * operation should report the GDsCUpdateRelationship dataset capability.
10620 : *
10621 : * Anticipated failures will not be emitted through the CPLError()
10622 : * infrastructure, but will be reported in the failureReason output parameter.
10623 : *
10624 : * @param relationship The relationship definition.
10625 : * @param failureReason Output parameter. Will contain an error message if
10626 : * an error occurs.
10627 : * @return true in case of success.
10628 : * @since GDAL 3.6
10629 : */
10630 0 : bool GDALDataset::UpdateRelationship(
10631 : CPL_UNUSED std::unique_ptr<GDALRelationship> &&relationship,
10632 : std::string &failureReason)
10633 : {
10634 0 : failureReason = "UpdateRelationship not supported by this driver";
10635 0 : return false;
10636 : }
10637 :
10638 : /************************************************************************/
10639 : /* GDALDatasetUpdateRelationship() */
10640 : /************************************************************************/
10641 :
10642 : /** Updates an existing relationship by replacing its definition.
10643 : *
10644 : * The existing relationship with matching name will be replaced.
10645 : *
10646 : * Only a few drivers will support this operation, and some of them might only
10647 : * support it only for some types of relationships.
10648 : * A dataset having at least some support for this
10649 : * operation should report the GDsCUpdateRelationship dataset capability.
10650 : *
10651 : * Anticipated failures will not be emitted through the CPLError()
10652 : * infrastructure, but will be reported in the failureReason output parameter.
10653 : *
10654 : * @param hDS Dataset handle.
10655 : * @param hRelationship The relationship definition. Contrary to the C++
10656 : * version, the passed object is copied.
10657 : * @param ppszFailureReason Output parameter. Will contain an error message if
10658 : * an error occurs (*ppszFailureReason to be freed
10659 : * with CPLFree). May be NULL.
10660 : * @return true in case of success.
10661 : * @since GDAL 3.5
10662 : */
10663 9 : bool GDALDatasetUpdateRelationship(GDALDatasetH hDS,
10664 : GDALRelationshipH hRelationship,
10665 : char **ppszFailureReason)
10666 : {
10667 9 : VALIDATE_POINTER1(hDS, __func__, false);
10668 9 : VALIDATE_POINTER1(hRelationship, __func__, false);
10669 : std::unique_ptr<GDALRelationship> poRelationship(
10670 18 : new GDALRelationship(*GDALRelationship::FromHandle(hRelationship)));
10671 9 : std::string failureReason;
10672 18 : const bool bRet = GDALDataset::FromHandle(hDS)->UpdateRelationship(
10673 9 : std::move(poRelationship), failureReason);
10674 9 : if (ppszFailureReason)
10675 : {
10676 0 : *ppszFailureReason =
10677 0 : failureReason.empty() ? nullptr : CPLStrdup(failureReason.c_str());
10678 : }
10679 9 : return bRet;
10680 : }
10681 :
10682 : /************************************************************************/
10683 : /* GDALDatasetSetQueryLoggerFunc() */
10684 : /************************************************************************/
10685 :
10686 : /**
10687 : * Sets the SQL query logger callback.
10688 : *
10689 : * When supported by the driver, the callback will be called with
10690 : * the executed SQL text, the error message, the execution time in milliseconds,
10691 : * the number of records fetched/affected and the client status data.
10692 : *
10693 : * A value of -1 in the execution time or in the number of records indicates
10694 : * that the values are unknown.
10695 : *
10696 : * @param hDS Dataset handle.
10697 : * @param pfnQueryLoggerFunc Callback function
10698 : * @param poQueryLoggerArg Opaque client status data
10699 : * @return true in case of success.
10700 : * @since GDAL 3.7
10701 : */
10702 1 : bool GDALDatasetSetQueryLoggerFunc(GDALDatasetH hDS,
10703 : GDALQueryLoggerFunc pfnQueryLoggerFunc,
10704 : void *poQueryLoggerArg)
10705 : {
10706 1 : VALIDATE_POINTER1(hDS, __func__, false);
10707 2 : return GDALDataset::FromHandle(hDS)->SetQueryLoggerFunc(pfnQueryLoggerFunc,
10708 1 : poQueryLoggerArg);
10709 : }
10710 :
10711 : //! @cond Doxygen_Suppress
10712 :
10713 : /************************************************************************/
10714 : /* SetEnableOverviews() */
10715 : /************************************************************************/
10716 :
10717 7531 : void GDALDataset::SetEnableOverviews(bool bEnable)
10718 : {
10719 7531 : if (m_poPrivate)
10720 : {
10721 7531 : m_poPrivate->m_bOverviewsEnabled = bEnable;
10722 : }
10723 7531 : }
10724 :
10725 : /************************************************************************/
10726 : /* AreOverviewsEnabled() */
10727 : /************************************************************************/
10728 :
10729 2006660 : bool GDALDataset::AreOverviewsEnabled() const
10730 : {
10731 2006660 : return m_poPrivate ? m_poPrivate->m_bOverviewsEnabled : true;
10732 : }
10733 :
10734 : /************************************************************************/
10735 : /* IsAllBands() */
10736 : /************************************************************************/
10737 :
10738 4188 : bool GDALDataset::IsAllBands(int nBandCount, const int *panBandList) const
10739 : {
10740 4188 : if (nBands != nBandCount)
10741 1 : return false;
10742 4187 : if (panBandList)
10743 : {
10744 15871 : for (int i = 0; i < nBandCount; ++i)
10745 : {
10746 11778 : if (panBandList[i] != i + 1)
10747 27 : return false;
10748 : }
10749 : }
10750 4160 : return true;
10751 : }
10752 :
10753 : //! @endcond
10754 :
10755 : /************************************************************************/
10756 : /* GetCompressionFormats() */
10757 : /************************************************************************/
10758 :
10759 : /** Return the compression formats that can be natively obtained for the
10760 : * window of interest and requested bands.
10761 : *
10762 : * For example, a tiled dataset may be able to return data in a compressed
10763 : * format if the window of interest matches exactly a tile. For some formats,
10764 : * drivers may also be able to merge several tiles together (not currently
10765 : * implemented though).
10766 : *
10767 : * Each format string is a pseudo MIME type, whose first part can be passed
10768 : * as the pszFormat argument of ReadCompressedData(), with additional
10769 : * parameters specified as key=value with a semi-colon separator.
10770 : *
10771 : * The amount and types of optional parameters passed after the MIME type is
10772 : * format dependent, and driver dependent (some drivers might not be able to
10773 : * return those extra information without doing a rather costly processing).
10774 : *
10775 : * For example, a driver might return "JPEG;frame_type=SOF0_baseline;"
10776 : * "bit_depth=8;num_components=3;subsampling=4:2:0;colorspace=YCbCr", and
10777 : * consequently "JPEG" can be passed as the pszFormat argument of
10778 : * ReadCompressedData(). For JPEG, implementations can use the
10779 : * GDALGetCompressionFormatForJPEG() helper method to generate a string like
10780 : * above from a JPEG codestream.
10781 : *
10782 : * Several values might be returned. For example,
10783 : * the JPEGXL driver will return "JXL", but also potentially "JPEG"
10784 : * if the JPEGXL codestream includes a JPEG reconstruction box.
10785 : *
10786 : * In the general case this method will return an empty list.
10787 : *
10788 : * This is the same as C function GDALDatasetGetCompressionFormats().
10789 : *
10790 : * @param nXOff The pixel offset to the top left corner of the region
10791 : * of the band to be accessed. This would be zero to start from the left side.
10792 : *
10793 : * @param nYOff The line offset to the top left corner of the region
10794 : * of the band to be accessed. This would be zero to start from the top.
10795 : *
10796 : * @param nXSize The width of the region of the band to be accessed in pixels.
10797 : *
10798 : * @param nYSize The height of the region of the band to be accessed in lines.
10799 : *
10800 : * @param nBandCount the number of bands being requested.
10801 : *
10802 : * @param panBandList the list of nBandCount band numbers.
10803 : * Note band numbers are 1 based. This may be NULL to select the first
10804 : * nBandCount bands.
10805 : *
10806 : * @return a list of compatible formats (which may be empty)
10807 : *
10808 : * For example, to check if native compression format(s) are available on the
10809 : * whole image:
10810 : * \code{.cpp}
10811 : * const CPLStringList aosFormats =
10812 : * poDataset->GetCompressionFormats(0, 0,
10813 : * poDataset->GetRasterXSize(),
10814 : * poDataset->GetRasterYSize(),
10815 : * poDataset->GetRasterCount(),
10816 : * nullptr);
10817 : * for( const char* pszFormat: aosFormats )
10818 : * {
10819 : * // Remove optional parameters and just print out the MIME type.
10820 : * const CPLStringList aosTokens(CSLTokenizeString2(pszFormat, ";", 0));
10821 : * printf("Found format %s\n, aosTokens[0]);
10822 : * }
10823 : * \endcode
10824 : *
10825 : * @since GDAL 3.7
10826 : */
10827 : CPLStringList
10828 0 : GDALDataset::GetCompressionFormats(CPL_UNUSED int nXOff, CPL_UNUSED int nYOff,
10829 : CPL_UNUSED int nXSize, CPL_UNUSED int nYSize,
10830 : CPL_UNUSED int nBandCount,
10831 : CPL_UNUSED const int *panBandList)
10832 : {
10833 0 : return CPLStringList();
10834 : }
10835 :
10836 : /************************************************************************/
10837 : /* GDALDatasetGetCompressionFormats() */
10838 : /************************************************************************/
10839 :
10840 : /** Return the compression formats that can be natively obtained for the
10841 : * window of interest and requested bands.
10842 : *
10843 : * For example, a tiled dataset may be able to return data in a compressed
10844 : * format if the window of interest matches exactly a tile. For some formats,
10845 : * drivers may also be able to merge several tiles together (not currently
10846 : * implemented though).
10847 : *
10848 : * Each format string is a pseudo MIME type, whose first part can be passed
10849 : * as the pszFormat argument of ReadCompressedData(), with additional
10850 : * parameters specified as key=value with a semi-colon separator.
10851 : *
10852 : * The amount and types of optional parameters passed after the MIME type is
10853 : * format dependent, and driver dependent (some drivers might not be able to
10854 : * return those extra information without doing a rather costly processing).
10855 : *
10856 : * For example, a driver might return "JPEG;frame_type=SOF0_baseline;"
10857 : * "bit_depth=8;num_components=3;subsampling=4:2:0;colorspace=YCbCr", and
10858 : * consequently "JPEG" can be passed as the pszFormat argument of
10859 : * ReadCompressedData(). For JPEG, implementations can use the
10860 : * GDALGetCompressionFormatForJPEG() helper method to generate a string like
10861 : * above from a JPEG codestream.
10862 : *
10863 : * Several values might be returned. For example,
10864 : * the JPEGXL driver will return "JXL", but also potentially "JPEG"
10865 : * if the JPEGXL codestream includes a JPEG reconstruction box.
10866 : *
10867 : * In the general case this method will return an empty list.
10868 : *
10869 : * This is the same as C++ method GDALDataset::GetCompressionFormats().
10870 : *
10871 : * @param hDS Dataset handle.
10872 : *
10873 : * @param nXOff The pixel offset to the top left corner of the region
10874 : * of the band to be accessed. This would be zero to start from the left side.
10875 : *
10876 : * @param nYOff The line offset to the top left corner of the region
10877 : * of the band to be accessed. This would be zero to start from the top.
10878 : *
10879 : * @param nXSize The width of the region of the band to be accessed in pixels.
10880 : *
10881 : * @param nYSize The height of the region of the band to be accessed in lines.
10882 : *
10883 : * @param nBandCount the number of bands being requested.
10884 : *
10885 : * @param panBandList the list of nBandCount band numbers.
10886 : * Note band numbers are 1 based. This may be NULL to select the first
10887 : * nBandCount bands.
10888 : *
10889 : * @return a list of compatible formats (which may be empty) that should be
10890 : * freed with CSLDestroy(), or nullptr.
10891 : *
10892 : * @since GDAL 3.7
10893 : */
10894 9 : char **GDALDatasetGetCompressionFormats(GDALDatasetH hDS, int nXOff, int nYOff,
10895 : int nXSize, int nYSize, int nBandCount,
10896 : const int *panBandList)
10897 : {
10898 9 : VALIDATE_POINTER1(hDS, __func__, nullptr);
10899 9 : return GDALDataset::FromHandle(hDS)
10900 9 : ->GetCompressionFormats(nXOff, nYOff, nXSize, nYSize, nBandCount,
10901 9 : panBandList)
10902 9 : .StealList();
10903 : }
10904 :
10905 : /************************************************************************/
10906 : /* ReadCompressedData() */
10907 : /************************************************************************/
10908 :
10909 : /** Return the compressed content that can be natively obtained for the
10910 : * window of interest and requested bands.
10911 : *
10912 : * For example, a tiled dataset may be able to return data in compressed format
10913 : * if the window of interest matches exactly a tile. For some formats, drivers
10914 : * may also be example to merge several tiles together (not currently
10915 : * implemented though).
10916 : *
10917 : * The implementation should make sure that the content returned forms a valid
10918 : * standalone file. For example, for the GeoTIFF implementation of this method,
10919 : * when extracting a JPEG tile, the method will automatically add the content
10920 : * of the JPEG Huffman and/or quantization tables that might be stored in the
10921 : * TIFF JpegTables tag, and not in tile data itself.
10922 : *
10923 : * In the general case this method will return CE_Failure.
10924 : *
10925 : * This is the same as C function GDALDatasetReadCompressedData().
10926 : *
10927 : * @param pszFormat Requested compression format (e.g. "JPEG",
10928 : * "WEBP", "JXL"). This is the MIME type of one of the values
10929 : * returned by GetCompressionFormats(). The format string is designed to
10930 : * potentially include at a later point key=value optional parameters separated
10931 : * by a semi-colon character. At time of writing, none are implemented.
10932 : * ReadCompressedData() implementations should verify optional parameters and
10933 : * return CE_Failure if they cannot support one of them.
10934 : *
10935 : * @param nXOff The pixel offset to the top left corner of the region
10936 : * of the band to be accessed. This would be zero to start from the left side.
10937 : *
10938 : * @param nYOff The line offset to the top left corner of the region
10939 : * of the band to be accessed. This would be zero to start from the top.
10940 : *
10941 : * @param nXSize The width of the region of the band to be accessed in pixels.
10942 : *
10943 : * @param nYSize The height of the region of the band to be accessed in lines.
10944 : *
10945 : * @param nBandCount the number of bands being requested.
10946 : *
10947 : * @param panBandList the list of nBandCount band numbers.
10948 : * Note band numbers are 1 based. This may be NULL to select the first
10949 : * nBandCount bands.
10950 : *
10951 : * @param ppBuffer Pointer to a buffer to store the compressed data or nullptr.
10952 : * If ppBuffer is not nullptr, then pnBufferSize should also not be nullptr.
10953 : * If ppBuffer is not nullptr, and *ppBuffer is not nullptr, then the provided
10954 : * buffer will be filled with the compressed data, provided that pnBufferSize
10955 : * and *pnBufferSize are not nullptr, and *pnBufferSize, indicating the size
10956 : * of *ppBuffer, is sufficiently large to hold the data.
10957 : * If ppBuffer is not nullptr, but *ppBuffer is nullptr, then the method will
10958 : * allocate *ppBuffer using VSIMalloc(), and thus the caller is responsible to
10959 : * free it with VSIFree().
10960 : * If ppBuffer is nullptr, then the compressed data itself will not be returned,
10961 : * but *pnBufferSize will be updated with an upper bound of the size that would
10962 : * be necessary to hold it (if pnBufferSize != nullptr).
10963 : *
10964 : * @param pnBufferSize Output buffer size, or nullptr.
10965 : * If ppBuffer != nullptr && *ppBuffer != nullptr, then pnBufferSize should
10966 : * be != nullptr and *pnBufferSize contain the size of *ppBuffer. If the
10967 : * method is successful, *pnBufferSize will be updated with the actual size
10968 : * used.
10969 : *
10970 : * @param ppszDetailedFormat Pointer to an output string, or nullptr.
10971 : * If ppszDetailedFormat is not nullptr, then, on success, the method will
10972 : * allocate a new string in *ppszDetailedFormat (to be freed with VSIFree())
10973 : * *ppszDetailedFormat might contain strings like
10974 : * "JPEG;frame_type=SOF0_baseline;bit_depth=8;num_components=3;"
10975 : * "subsampling=4:2:0;colorspace=YCbCr" or simply the MIME type.
10976 : * The string will contain at least as much information as what
10977 : * GetCompressionFormats() returns, and potentially more when
10978 : * ppBuffer != nullptr.
10979 : *
10980 : * @return CE_None in case of success, CE_Failure otherwise.
10981 : *
10982 : * For example, to request JPEG content on the whole image and let GDAL deal
10983 : * with the buffer allocation.
10984 : * \code{.cpp}
10985 : * void* pBuffer = nullptr;
10986 : * size_t nBufferSize = 0;
10987 : * CPLErr eErr =
10988 : * poDataset->ReadCompressedData("JPEG",
10989 : * 0, 0,
10990 : * poDataset->GetRasterXSize(),
10991 : * poDataset->GetRasterYSize(),
10992 : * poDataset->GetRasterCount(),
10993 : * nullptr, // panBandList
10994 : * &pBuffer,
10995 : * &nBufferSize,
10996 : * nullptr // ppszDetailedFormat
10997 : * );
10998 : * if (eErr == CE_None)
10999 : * {
11000 : * CPLAssert(pBuffer != nullptr);
11001 : * CPLAssert(nBufferSize > 0);
11002 : * VSILFILE* fp = VSIFOpenL("my.jpeg", "wb");
11003 : * if (fp)
11004 : * {
11005 : * VSIFWriteL(pBuffer, nBufferSize, 1, fp);
11006 : * VSIFCloseL(fp);
11007 : * }
11008 : * VSIFree(pBuffer);
11009 : * }
11010 : * \endcode
11011 : *
11012 : * Or to manage the buffer allocation on your side:
11013 : * \code{.cpp}
11014 : * size_t nUpperBoundBufferSize = 0;
11015 : * CPLErr eErr =
11016 : * poDataset->ReadCompressedData("JPEG",
11017 : * 0, 0,
11018 : * poDataset->GetRasterXSize(),
11019 : * poDataset->GetRasterYSize(),
11020 : * poDataset->GetRasterCount(),
11021 : * nullptr, // panBandList
11022 : * nullptr, // ppBuffer,
11023 : * &nUpperBoundBufferSize,
11024 : * nullptr // ppszDetailedFormat
11025 : * );
11026 : * if (eErr == CE_None)
11027 : * {
11028 : * std::vector<uint8_t> myBuffer;
11029 : * myBuffer.resize(nUpperBoundBufferSize);
11030 : * void* pBuffer = myBuffer.data();
11031 : * size_t nActualSize = nUpperBoundBufferSize;
11032 : * char* pszDetailedFormat = nullptr;
11033 : * // We also request detailed format, but we could have passed it to
11034 : * // nullptr as well.
11035 : * eErr =
11036 : * poDataset->ReadCompressedData("JPEG",
11037 : * 0, 0,
11038 : * poDataset->GetRasterXSize(),
11039 : * poDataset->GetRasterYSize(),
11040 : * poDataset->GetRasterCount(),
11041 : * nullptr, // panBandList
11042 : * &pBuffer,
11043 : * &nActualSize,
11044 : * &pszDetailedFormat);
11045 : * if (eErr == CE_None)
11046 : * {
11047 : * CPLAssert(pBuffer == myBuffer.data()); // pointed value not modified
11048 : * CPLAssert(nActualSize <= nUpperBoundBufferSize);
11049 : * myBuffer.resize(nActualSize);
11050 : * // do something useful
11051 : * VSIFree(pszDetailedFormat);
11052 : * }
11053 : * }
11054 : * \endcode
11055 : *
11056 : * @since GDAL 3.7
11057 : */
11058 441 : CPLErr GDALDataset::ReadCompressedData(
11059 : CPL_UNUSED const char *pszFormat, CPL_UNUSED int nXOff,
11060 : CPL_UNUSED int nYOff, CPL_UNUSED int nXSize, CPL_UNUSED int nYSize,
11061 : CPL_UNUSED int nBandCount, CPL_UNUSED const int *panBandList,
11062 : CPL_UNUSED void **ppBuffer, CPL_UNUSED size_t *pnBufferSize,
11063 : CPL_UNUSED char **ppszDetailedFormat)
11064 : {
11065 441 : return CE_Failure;
11066 : }
11067 :
11068 : /************************************************************************/
11069 : /* GDALDatasetReadCompressedData() */
11070 : /************************************************************************/
11071 :
11072 : /** Return the compressed content that can be natively obtained for the
11073 : * window of interest and requested bands.
11074 : *
11075 : * For example, a tiled dataset may be able to return data in compressed format
11076 : * if the window of interest matches exactly a tile. For some formats, drivers
11077 : * may also be example to merge several tiles together (not currently
11078 : * implemented though).
11079 : *
11080 : * The implementation should make sure that the content returned forms a valid
11081 : * standalone file. For example, for the GeoTIFF implementation of this method,
11082 : * when extracting a JPEG tile, the method will automatically adds the content
11083 : * of the JPEG Huffman and/or quantization tables that might be stored in the
11084 : * TIFF JpegTables tag, and not in tile data itself.
11085 : *
11086 : * In the general case this method will return CE_Failure.
11087 : *
11088 : * This is the same as C++ method GDALDataset:ReadCompressedData().
11089 : *
11090 : * @param hDS Dataset handle.
11091 : *
11092 : * @param pszFormat Requested compression format (e.g. "JPEG",
11093 : * "WEBP", "JXL"). This is the MIME type of one of the values
11094 : * returned by GetCompressionFormats(). The format string is designed to
11095 : * potentially include at a later point key=value optional parameters separated
11096 : * by a semi-colon character. At time of writing, none are implemented.
11097 : * ReadCompressedData() implementations should verify optional parameters and
11098 : * return CE_Failure if they cannot support one of them.
11099 : *
11100 : * @param nXOff The pixel offset to the top left corner of the region
11101 : * of the band to be accessed. This would be zero to start from the left side.
11102 : *
11103 : * @param nYOff The line offset to the top left corner of the region
11104 : * of the band to be accessed. This would be zero to start from the top.
11105 : *
11106 : * @param nXSize The width of the region of the band to be accessed in pixels.
11107 : *
11108 : * @param nYSize The height of the region of the band to be accessed in lines.
11109 : *
11110 : * @param nBandCount the number of bands being requested.
11111 : *
11112 : * @param panBandList the list of nBandCount band numbers.
11113 : * Note band numbers are 1 based. This may be NULL to select the first
11114 : * nBandCount bands.
11115 : *
11116 : * @param ppBuffer Pointer to a buffer to store the compressed data or nullptr.
11117 : * If ppBuffer is not nullptr, then pnBufferSize should also not be nullptr.
11118 : * If ppBuffer is not nullptr, and *ppBuffer is not nullptr, then the provided
11119 : * buffer will be filled with the compressed data, provided that pnBufferSize
11120 : * and *pnBufferSize are not nullptr, and *pnBufferSize, indicating the size
11121 : * of *ppBuffer, is sufficiently large to hold the data.
11122 : * If ppBuffer is not nullptr, but *ppBuffer is nullptr, then the method will
11123 : * allocate *ppBuffer using VSIMalloc(), and thus the caller is responsible to
11124 : * free it with VSIFree().
11125 : * If ppBuffer is nullptr, then the compressed data itself will not be returned,
11126 : * but *pnBufferSize will be updated with an upper bound of the size that would
11127 : * be necessary to hold it (if pnBufferSize != nullptr).
11128 : *
11129 : * @param pnBufferSize Output buffer size, or nullptr.
11130 : * If ppBuffer != nullptr && *ppBuffer != nullptr, then pnBufferSize should
11131 : * be != nullptr and *pnBufferSize contain the size of *ppBuffer. If the
11132 : * method is successful, *pnBufferSize will be updated with the actual size
11133 : * used.
11134 : *
11135 : * @param ppszDetailedFormat Pointer to an output string, or nullptr.
11136 : * If ppszDetailedFormat is not nullptr, then, on success, the method will
11137 : * allocate a new string in *ppszDetailedFormat (to be freed with VSIFree())
11138 : * *ppszDetailedFormat might contain strings like
11139 : * "JPEG;frame_type=SOF0_baseline;bit_depth=8;num_components=3;"
11140 : * "subsampling=4:2:0;colorspace=YCbCr" or simply the MIME type.
11141 : * The string will contain at least as much information as what
11142 : * GetCompressionFormats() returns, and potentially more when
11143 : * ppBuffer != nullptr.
11144 : *
11145 : * @return CE_None in case of success, CE_Failure otherwise.
11146 : *
11147 : * @since GDAL 3.7
11148 : */
11149 28 : CPLErr GDALDatasetReadCompressedData(GDALDatasetH hDS, const char *pszFormat,
11150 : int nXOff, int nYOff, int nXSize,
11151 : int nYSize, int nBandCount,
11152 : const int *panBandList, void **ppBuffer,
11153 : size_t *pnBufferSize,
11154 : char **ppszDetailedFormat)
11155 : {
11156 28 : VALIDATE_POINTER1(hDS, __func__, CE_Failure);
11157 56 : return GDALDataset::FromHandle(hDS)->ReadCompressedData(
11158 : pszFormat, nXOff, nYOff, nXSize, nYSize, nBandCount, panBandList,
11159 28 : ppBuffer, pnBufferSize, ppszDetailedFormat);
11160 : }
11161 :
11162 : /************************************************************************/
11163 : /* CanBeCloned() */
11164 : /************************************************************************/
11165 :
11166 : //! @cond Doxygen_Suppress
11167 :
11168 : /** This method is called by GDALThreadSafeDataset::Create() to determine if
11169 : * it is possible to create a thread-safe wrapper for a dataset, which involves
11170 : * the ability to Clone() it.
11171 : *
11172 : * Implementations of this method must be thread-safe.
11173 : *
11174 : * @param nScopeFlags Combination of GDAL_OF_RASTER, GDAL_OF_VECTOR, etc. flags,
11175 : * expressing the intended use for thread-safety.
11176 : * Currently, the only valid scope is in the base
11177 : * implementation is GDAL_OF_RASTER.
11178 : * @param bCanShareState Determines if cloned datasets are allowed to share
11179 : * state with the dataset they have been cloned from.
11180 : * If set to true, the dataset from which they have been
11181 : * cloned from must remain opened during the lifetime of
11182 : * its clones.
11183 : * @return true if the Clone() method is expected to succeed with the same values
11184 : * of nScopeFlags and bCanShareState.
11185 : */
11186 149 : bool GDALDataset::CanBeCloned(int nScopeFlags,
11187 : [[maybe_unused]] bool bCanShareState) const
11188 : {
11189 149 : return m_bCanBeReopened && nScopeFlags == GDAL_OF_RASTER;
11190 : }
11191 :
11192 : //! @endcond
11193 :
11194 : /************************************************************************/
11195 : /* Clone() */
11196 : /************************************************************************/
11197 :
11198 : //! @cond Doxygen_Suppress
11199 :
11200 : /** This method "clones" the current dataset, that is it returns a new instance
11201 : * that is opened on the same underlying "file".
11202 : *
11203 : * The base implementation uses GDALDataset::Open() to re-open the dataset.
11204 : * The MEM driver has a specialized implementation that returns a new instance,
11205 : * but which shares the same memory buffer as this.
11206 : *
11207 : * Implementations of this method must be thread-safe.
11208 : *
11209 : * @param nScopeFlags Combination of GDAL_OF_RASTER, GDAL_OF_VECTOR, etc. flags,
11210 : * expressing the intended use for thread-safety.
11211 : * Currently, the only valid scope is in the base
11212 : * implementation is GDAL_OF_RASTER.
11213 : * @param bCanShareState Determines if cloned datasets are allowed to share
11214 : * state with the dataset they have been cloned from.
11215 : * If set to true, the dataset from which they have been
11216 : * cloned from must remain opened during the lifetime of
11217 : * its clones.
11218 : * @return a new instance, or nullptr in case of error.
11219 : */
11220 : std::unique_ptr<GDALDataset>
11221 2051 : GDALDataset::Clone(int nScopeFlags, [[maybe_unused]] bool bCanShareState) const
11222 : {
11223 4102 : CPLStringList aosAllowedDrivers;
11224 2051 : if (poDriver)
11225 2051 : aosAllowedDrivers.AddString(poDriver->GetDescription());
11226 : return std::unique_ptr<GDALDataset>(GDALDataset::Open(
11227 2051 : GetDescription(),
11228 2051 : nScopeFlags | GDAL_OF_INTERNAL | GDAL_OF_VERBOSE_ERROR,
11229 4102 : aosAllowedDrivers.List(), papszOpenOptions));
11230 : }
11231 :
11232 : //! @endcond
11233 :
11234 : /************************************************************************/
11235 : /* GeolocationToPixelLine() */
11236 : /************************************************************************/
11237 :
11238 : /** Transform georeferenced coordinates to pixel/line coordinates.
11239 : *
11240 : * When poSRS is null, those georeferenced coordinates (dfGeolocX, dfGeolocY)
11241 : * must be in the "natural" SRS of the dataset, that is the one returned by
11242 : * GetSpatialRef() if there is a geotransform, GetGCPSpatialRef() if there are
11243 : * GCPs, WGS 84 if there are RPC coefficients, or the SRS of the geolocation
11244 : * array (generally WGS 84) if there is a geolocation array.
11245 : * If that natural SRS is a geographic one, dfGeolocX must be a longitude, and
11246 : * dfGeolocY a latitude. If that natural SRS is a projected one, dfGeolocX must
11247 : * be a easting, and dfGeolocY a northing.
11248 : *
11249 : * When poSRS is set to a non-null value, (dfGeolocX, dfGeolocY) must be
11250 : * expressed in that CRS, and that tuple must be conformant with the
11251 : * data-axis-to-crs-axis setting of poSRS, that is the one returned by
11252 : * the OGRSpatialReference::GetDataAxisToSRSAxisMapping(). If you want to be sure
11253 : * of the axis order, then make sure to call poSRS->SetAxisMappingStrategy(OAMS_TRADITIONAL_GIS_ORDER)
11254 : * before calling this method, and in that case, dfGeolocX must be a longitude
11255 : * or an easting value, and dfGeolocX a latitude or a northing value.
11256 : *
11257 : * This method uses GDALCreateGenImgProjTransformer2() underneath.
11258 : *
11259 : * @param dfGeolocX X coordinate of the position (longitude or easting if poSRS
11260 : * is null, otherwise consistent with poSRS data-axis-to-crs-axis mapping),
11261 : * where interpolation should be done.
11262 : * @param dfGeolocY Y coordinate of the position (latitude or northing if poSRS
11263 : * is null, otherwise consistent with poSRS data-axis-to-crs-axis mapping),
11264 : * where interpolation should be done.
11265 : * @param poSRS If set, override the natural CRS in which dfGeolocX, dfGeolocY are expressed
11266 : * @param[out] pdfPixel Pointer to the variable where to the store the pixel/column coordinate.
11267 : * @param[out] pdfLine Pointer to the variable where to the store the line coordinate.
11268 : * @param papszTransformerOptions Options accepted by GDALCreateGenImgProjTransformer2(), or nullptr.
11269 : *
11270 : * @return CE_None on success, or an error code on failure.
11271 : * @since GDAL 3.11
11272 : */
11273 :
11274 : CPLErr
11275 15 : GDALDataset::GeolocationToPixelLine(double dfGeolocX, double dfGeolocY,
11276 : const OGRSpatialReference *poSRS,
11277 : double *pdfPixel, double *pdfLine,
11278 : CSLConstList papszTransformerOptions) const
11279 : {
11280 30 : CPLStringList aosTO(papszTransformerOptions);
11281 :
11282 15 : if (poSRS)
11283 : {
11284 4 : const char *const apszOptions[] = {"FORMAT=WKT2", nullptr};
11285 8 : const std::string osWKT = poSRS->exportToWkt(apszOptions);
11286 4 : aosTO.SetNameValue("DST_SRS", osWKT.c_str());
11287 4 : const auto eAxisMappingStrategy = poSRS->GetAxisMappingStrategy();
11288 4 : if (eAxisMappingStrategy == OAMS_TRADITIONAL_GIS_ORDER)
11289 : aosTO.SetNameValue("DST_SRS_AXIS_MAPPING_STRATEGY",
11290 1 : "TRADITIONAL_GIS_ORDER");
11291 3 : else if (eAxisMappingStrategy == OAMS_AUTHORITY_COMPLIANT)
11292 : aosTO.SetNameValue("DST_SRS_AXIS_MAPPING_STRATEGY",
11293 1 : "AUTHORITY_COMPLIANT");
11294 : else
11295 : {
11296 2 : const auto &anValues = poSRS->GetDataAxisToSRSAxisMapping();
11297 4 : std::string osVal;
11298 6 : for (int v : anValues)
11299 : {
11300 4 : if (!osVal.empty())
11301 2 : osVal += ',';
11302 4 : osVal += std::to_string(v);
11303 : }
11304 : aosTO.SetNameValue("DST_SRS_DATA_AXIS_TO_SRS_AXIS_MAPPING",
11305 2 : osVal.c_str());
11306 : }
11307 : }
11308 :
11309 15 : auto hTransformer = GDALCreateGenImgProjTransformer2(
11310 : GDALDataset::ToHandle(const_cast<GDALDataset *>(this)), nullptr,
11311 15 : aosTO.List());
11312 15 : if (hTransformer == nullptr)
11313 : {
11314 1 : return CE_Failure;
11315 : }
11316 :
11317 14 : double z = 0;
11318 14 : int bSuccess = 0;
11319 14 : GDALGenImgProjTransform(hTransformer, TRUE, 1, &dfGeolocX, &dfGeolocY, &z,
11320 : &bSuccess);
11321 14 : GDALDestroyTransformer(hTransformer);
11322 14 : if (bSuccess)
11323 : {
11324 14 : if (pdfPixel)
11325 14 : *pdfPixel = dfGeolocX;
11326 14 : if (pdfLine)
11327 14 : *pdfLine = dfGeolocY;
11328 14 : return CE_None;
11329 : }
11330 : else
11331 : {
11332 0 : return CE_Failure;
11333 : }
11334 : }
11335 :
11336 : /************************************************************************/
11337 : /* GDALDatasetGeolocationToPixelLine() */
11338 : /************************************************************************/
11339 :
11340 : /** Transform georeferenced coordinates to pixel/line coordinates.
11341 : *
11342 : * @see GDALDataset::GeolocationToPixelLine()
11343 : * @since GDAL 3.11
11344 : */
11345 :
11346 0 : CPLErr GDALDatasetGeolocationToPixelLine(GDALDatasetH hDS, double dfGeolocX,
11347 : double dfGeolocY,
11348 : OGRSpatialReferenceH hSRS,
11349 : double *pdfPixel, double *pdfLine,
11350 : CSLConstList papszTransformerOptions)
11351 : {
11352 0 : VALIDATE_POINTER1(hDS, "GDALDatasetGeolocationToPixelLine", CE_Failure);
11353 :
11354 0 : GDALDataset *poDS = GDALDataset::FromHandle(hDS);
11355 0 : return poDS->GeolocationToPixelLine(
11356 0 : dfGeolocX, dfGeolocY, OGRSpatialReference::FromHandle(hSRS), pdfPixel,
11357 0 : pdfLine, papszTransformerOptions);
11358 : }
11359 :
11360 : /************************************************************************/
11361 : /* GetExtent() */
11362 : /************************************************************************/
11363 :
11364 : /** Return extent of dataset in specified CRS.
11365 : *
11366 : * OGREnvelope.MinX/MaxX represents longitudes, and MinY/MaxY latitudes.
11367 : *
11368 : * For rasters, the base implementation of this method only succeeds if
11369 : * GetGeoTransform() and GetSpatialRef() succeed.
11370 : * For vectors, the base implementation of this method iterates over layers
11371 : * and call their OGRLayer::GetExtent() method.
11372 : *
11373 : * TestCapability(GDsCFastGetExtent) can be used to test if the execution
11374 : * time of this method is fast.
11375 : *
11376 : * This is the same as C function GDALGetExtent()
11377 : *
11378 : * @param[out] psExtent Pointer to output extent. Must NOT be null.
11379 : * @param poCRS CRS in which to express the extent. If not specified, this will
11380 : * be the raster CRS or the CRS of the first layer for a vector dataset.
11381 : * @return CE_None in case of success, CE_Failure otherwise
11382 : * @since GDAL 3.12
11383 : */
11384 :
11385 229 : CPLErr GDALDataset::GetExtent(OGREnvelope *psExtent,
11386 : const OGRSpatialReference *poCRS) const
11387 : {
11388 229 : const OGRSpatialReference *poThisCRS = GetSpatialRefRasterOnly();
11389 229 : int nLayerCount = 0;
11390 229 : if (!poThisCRS)
11391 : {
11392 93 : nLayerCount = GetLayerCount();
11393 93 : if (nLayerCount >= 1)
11394 : {
11395 3 : if (auto poLayer = GetLayer(0))
11396 3 : poThisCRS = poLayer->GetSpatialRef();
11397 : }
11398 : }
11399 229 : if (!poCRS)
11400 131 : poCRS = poThisCRS;
11401 98 : else if (!poThisCRS)
11402 3 : return CE_Failure;
11403 :
11404 226 : *psExtent = OGREnvelope();
11405 :
11406 226 : GDALGeoTransform gt;
11407 226 : auto poThisDS = const_cast<GDALDataset *>(this);
11408 226 : const bool bHasGT = poThisDS->GetGeoTransform(gt) == CE_None;
11409 226 : if (bHasGT)
11410 : {
11411 0 : std::unique_ptr<OGRCoordinateTransformation> poCT;
11412 221 : if (poCRS)
11413 : {
11414 136 : poCT.reset(OGRCreateCoordinateTransformation(poThisCRS, poCRS));
11415 : }
11416 :
11417 221 : constexpr int DENSIFY_POINT_COUNT = 21;
11418 221 : double dfULX = gt[0];
11419 221 : double dfULY = gt[3];
11420 221 : double dfURX = 0, dfURY = 0;
11421 221 : gt.Apply(nRasterXSize, 0, &dfURX, &dfURY);
11422 221 : double dfLLX = 0, dfLLY = 0;
11423 221 : gt.Apply(0, nRasterYSize, &dfLLX, &dfLLY);
11424 221 : double dfLRX = 0, dfLRY = 0;
11425 221 : gt.Apply(nRasterXSize, nRasterYSize, &dfLRX, &dfLRY);
11426 221 : const double xmin = std::min({dfULX, dfURX, dfLLX, dfLRX});
11427 221 : const double ymin = std::min({dfULY, dfURY, dfLLY, dfLRY});
11428 221 : const double xmax = std::max({dfULX, dfURX, dfLLX, dfLRX});
11429 221 : const double ymax = std::max({dfULY, dfURY, dfLLY, dfLRY});
11430 221 : if (poCT)
11431 : {
11432 136 : OGREnvelope sEnvTmp;
11433 272 : if (!poCT->TransformBounds(xmin, ymin, xmax, ymax, &(sEnvTmp.MinX),
11434 : &(sEnvTmp.MinY), &(sEnvTmp.MaxX),
11435 136 : &(sEnvTmp.MaxY), DENSIFY_POINT_COUNT))
11436 : {
11437 0 : return CE_Failure;
11438 : }
11439 136 : *psExtent = sEnvTmp;
11440 : }
11441 : else
11442 : {
11443 85 : psExtent->MinX = xmin;
11444 85 : psExtent->MinY = ymin;
11445 85 : psExtent->MaxX = xmax;
11446 85 : psExtent->MaxY = ymax;
11447 : }
11448 : }
11449 :
11450 226 : if (nLayerCount > 0)
11451 : {
11452 6 : for (auto &&poLayer : poThisDS->GetLayers())
11453 : {
11454 3 : auto poLayerCRS = poLayer->GetSpatialRef();
11455 3 : if (poLayerCRS)
11456 : {
11457 3 : OGREnvelope sLayerExtent;
11458 3 : if (poLayer->GetExtent(&sLayerExtent) == OGRERR_NONE)
11459 : {
11460 : auto poCT = std::unique_ptr<OGRCoordinateTransformation>(
11461 6 : OGRCreateCoordinateTransformation(poLayerCRS, poCRS));
11462 3 : if (poCT)
11463 : {
11464 3 : constexpr int DENSIFY_POINT_COUNT = 21;
11465 3 : OGREnvelope sEnvTmp;
11466 3 : if (poCT->TransformBounds(
11467 : sLayerExtent.MinX, sLayerExtent.MinY,
11468 : sLayerExtent.MaxX, sLayerExtent.MaxY,
11469 : &(sEnvTmp.MinX), &(sEnvTmp.MinY),
11470 : &(sEnvTmp.MaxX), &(sEnvTmp.MaxY),
11471 3 : DENSIFY_POINT_COUNT))
11472 : {
11473 3 : psExtent->Merge(sEnvTmp);
11474 : }
11475 : }
11476 : }
11477 : }
11478 : }
11479 : }
11480 :
11481 226 : return psExtent->IsInit() ? CE_None : CE_Failure;
11482 : }
11483 :
11484 : /************************************************************************/
11485 : /* GDALGetExtent() */
11486 : /************************************************************************/
11487 :
11488 : /** Return extent of dataset in specified CRS.
11489 : *
11490 : * OGREnvelope.MinX/MaxX represents longitudes, and MinY/MaxY latitudes.
11491 : *
11492 : * For rasters, the base implementation of this method only succeeds if
11493 : * GetGeoTransform() and GetSpatialRef() succeed.
11494 : * For vectors, the base implementation of this method iterates over layers
11495 : * and call their OGRLayer::GetExtent() method.
11496 : *
11497 : * TestCapability(GDsCFastGetExtent) can be used to test if the execution
11498 : * time of this method is fast.
11499 : *
11500 : * This is the same as C++ method GDALDataset::GetExtent()
11501 : *
11502 : * @param hDS Dataset handle. Must NOT be null.
11503 : * @param[out] psExtent Pointer to output extent. Must NOT be null.
11504 : * @param hCRS CRS in which to express the extent. If not specified, this will
11505 : * be the raster CRS or the CRS of the first layer for a vector dataset.
11506 : * @return extent in poCRS (valid only if IsInit() method returns true)
11507 : * @since GDAL 3.12
11508 : */
11509 :
11510 28 : CPLErr GDALGetExtent(GDALDatasetH hDS, OGREnvelope *psExtent,
11511 : OGRSpatialReferenceH hCRS)
11512 : {
11513 28 : VALIDATE_POINTER1(hDS, __func__, CE_Failure);
11514 28 : VALIDATE_POINTER1(psExtent, __func__, CE_Failure);
11515 56 : return GDALDataset::FromHandle(hDS)->GetExtent(
11516 28 : psExtent, OGRSpatialReference::FromHandle(hCRS));
11517 : }
11518 :
11519 : /************************************************************************/
11520 : /* GetExtentWGS84LongLat() */
11521 : /************************************************************************/
11522 :
11523 : /** Return extent of dataset in WGS84 longitude/latitude
11524 : *
11525 : * OGREnvelope.MinX/MaxX represents longitudes, and MinY/MaxY latitudes.
11526 : *
11527 : * TestCapability(GDsCFastGetExtentWGS84LongLat) can be used to test if the execution
11528 : * time of this method is fast.
11529 : *
11530 : * This is the same as C function GDALGetExtentWGS84LongLat()
11531 : *
11532 : * @return extent (valid only if IsInit() method returns true)
11533 : * @since GDAL 3.12
11534 : */
11535 :
11536 96 : CPLErr GDALDataset::GetExtentWGS84LongLat(OGREnvelope *psExtent) const
11537 : {
11538 192 : OGRSpatialReference oSRS_WGS84;
11539 96 : oSRS_WGS84.SetFromUserInput("WGS84");
11540 96 : oSRS_WGS84.SetAxisMappingStrategy(OAMS_TRADITIONAL_GIS_ORDER);
11541 192 : return GetExtent(psExtent, &oSRS_WGS84);
11542 : }
11543 :
11544 : /************************************************************************/
11545 : /* GDALGetExtentWGS84LongLat() */
11546 : /************************************************************************/
11547 :
11548 : /** Return extent of dataset in WGS84 longitude/latitude
11549 : *
11550 : * OGREnvelope.MinX/MaxX represents longitudes, and MinY/MaxY latitudes.
11551 : *
11552 : * TestCapability(GDsCFastGetExtentWGS84LongLat) can be used to test if the execution
11553 : * time of this method is fast.
11554 : *
11555 : * This is the same as C++ method GDALDataset::GetExtentWGS84LongLat()
11556 : *
11557 : * @param hDS Dataset handle. Must NOT be null.
11558 : * @param[out] psExtent Pointer to output extent. Must NOT be null.
11559 : * @return extent (valid only if IsInit() method returns true)
11560 : * @since GDAL 3.12
11561 : */
11562 :
11563 4 : CPLErr GDALGetExtentWGS84LongLat(GDALDatasetH hDS, OGREnvelope *psExtent)
11564 : {
11565 4 : VALIDATE_POINTER1(hDS, __func__, CE_Failure);
11566 4 : VALIDATE_POINTER1(psExtent, __func__, CE_Failure);
11567 4 : return GDALDataset::FromHandle(hDS)->GetExtentWGS84LongLat(psExtent);
11568 : }
11569 :
11570 : /************************************************************************/
11571 : /* ReportUpdateNotSupportedByDriver() */
11572 : /************************************************************************/
11573 :
11574 : //! @cond Doxygen_Suppress
11575 :
11576 : /* static */
11577 1 : void GDALDataset::ReportUpdateNotSupportedByDriver(const char *pszDriverName)
11578 : {
11579 1 : CPLError(CE_Failure, CPLE_NotSupported,
11580 : "The %s driver does not support update access to existing "
11581 : "datasets.",
11582 : pszDriverName);
11583 1 : }
11584 :
11585 : //! @endcond
11586 :
11587 : /************************************************************************/
11588 : /* BuildFilename() */
11589 : /************************************************************************/
11590 :
11591 : /** Generates a filename, potentially relative to another one.
11592 : *
11593 : * Given the path to a reference directory, and a path to a file
11594 : * referenced from it, build a path to the file that the current application
11595 : * can use. If the file path is already absolute, rather than relative, or if
11596 : * bRelativeToReferencePath is false, then the filename of interest will be
11597 : * returned unaltered.
11598 : *
11599 : * This is enhanced version of CPLProjectRelativeFilenameSafe() that takes
11600 : * into account the subdataset syntax.
11601 : *
11602 : * Examples:
11603 : * \code{.cpp}
11604 : * BuildFilename("tmp/abc.gif", "abc/def", true) == "abc/def/tmp/abc.gif"
11605 : * BuildFilename("../abc.gif", "/abc/def") == "/abc/abc.gif"
11606 : * BuildFilename("abc.gif", "C:\WIN", true) == "C:\WIN\abc.gif"
11607 : * BuildFilename("abc.gif", "C:\WIN", false) == "abc.gif"
11608 : * BuildFilename("/home/even/foo.tif", "/home/even/workdir", true) == "/home/even/foo.tif"
11609 : * \endcode
11610 : *
11611 : * @param pszFilename Filename of interest.
11612 : * @param pszReferencePath Path to a reference directory.
11613 : * @param bRelativeToReferencePath Whether pszFilename, if a relative path, is
11614 : * relative to pszReferencePath
11615 : * @since 3.11
11616 : */
11617 :
11618 : /* static */
11619 104289 : std::string GDALDataset::BuildFilename(const char *pszFilename,
11620 : const char *pszReferencePath,
11621 : bool bRelativeToReferencePath)
11622 : {
11623 104289 : std::string osSrcDSName;
11624 104289 : if (pszReferencePath != nullptr && bRelativeToReferencePath)
11625 : {
11626 : // Try subdatasetinfo API first
11627 : // Note: this will become the only branch when subdatasetinfo will become
11628 : // available for NITF_IM, RASTERLITE and TILEDB
11629 2594 : const auto oSubDSInfo{GDALGetSubdatasetInfo(pszFilename)};
11630 2594 : if (oSubDSInfo && !oSubDSInfo->GetPathComponent().empty())
11631 : {
11632 8 : auto path{oSubDSInfo->GetPathComponent()};
11633 12 : osSrcDSName = oSubDSInfo->ModifyPathComponent(
11634 8 : CPLProjectRelativeFilenameSafe(pszReferencePath, path.c_str())
11635 4 : .c_str());
11636 4 : GDALDestroySubdatasetInfo(oSubDSInfo);
11637 : }
11638 : else
11639 : {
11640 2590 : bool bDone = false;
11641 15525 : for (const char *pszSyntax : apszSpecialSubDatasetSyntax)
11642 : {
11643 12938 : CPLString osPrefix(pszSyntax);
11644 12938 : osPrefix.resize(strchr(pszSyntax, ':') - pszSyntax + 1);
11645 12938 : if (pszSyntax[osPrefix.size()] == '"')
11646 2587 : osPrefix += '"';
11647 12938 : if (EQUALN(pszFilename, osPrefix, osPrefix.size()))
11648 : {
11649 3 : if (STARTS_WITH_CI(pszSyntax + osPrefix.size(), "{ANY}"))
11650 : {
11651 3 : const char *pszLastPart = strrchr(pszFilename, ':') + 1;
11652 : // CSV:z:/foo.xyz
11653 3 : if ((pszLastPart[0] == '/' || pszLastPart[0] == '\\') &&
11654 0 : pszLastPart - pszFilename >= 3 &&
11655 0 : pszLastPart[-3] == ':')
11656 : {
11657 0 : pszLastPart -= 2;
11658 : }
11659 3 : CPLString osPrefixFilename = pszFilename;
11660 3 : osPrefixFilename.resize(pszLastPart - pszFilename);
11661 6 : osSrcDSName = osPrefixFilename +
11662 6 : CPLProjectRelativeFilenameSafe(
11663 3 : pszReferencePath, pszLastPart);
11664 3 : bDone = true;
11665 : }
11666 0 : else if (STARTS_WITH_CI(pszSyntax + osPrefix.size(),
11667 : "{FILENAME}"))
11668 : {
11669 0 : CPLString osFilename(pszFilename + osPrefix.size());
11670 0 : size_t nPos = 0;
11671 0 : if (osFilename.size() >= 3 && osFilename[1] == ':' &&
11672 0 : (osFilename[2] == '\\' || osFilename[2] == '/'))
11673 0 : nPos = 2;
11674 0 : nPos = osFilename.find(
11675 0 : pszSyntax[osPrefix.size() + strlen("{FILENAME}")],
11676 : nPos);
11677 0 : if (nPos != std::string::npos)
11678 : {
11679 0 : const CPLString osSuffix = osFilename.substr(nPos);
11680 0 : osFilename.resize(nPos);
11681 0 : osSrcDSName = osPrefix +
11682 0 : CPLProjectRelativeFilenameSafe(
11683 0 : pszReferencePath, osFilename) +
11684 0 : osSuffix;
11685 0 : bDone = true;
11686 : }
11687 : }
11688 3 : break;
11689 : }
11690 : }
11691 2590 : if (!bDone)
11692 : {
11693 2587 : std::string osReferencePath = pszReferencePath;
11694 2587 : if (!CPLIsFilenameRelative(pszReferencePath))
11695 : {
11696 : // Simplify path by replacing "foo/a/../b" with "foo/b"
11697 2294 : while (STARTS_WITH(pszFilename, "../"))
11698 : {
11699 : osReferencePath =
11700 5 : CPLGetPathSafe(osReferencePath.c_str());
11701 5 : pszFilename += strlen("../");
11702 : }
11703 : }
11704 :
11705 5174 : osSrcDSName = CPLProjectRelativeFilenameSafe(
11706 2587 : osReferencePath.c_str(), pszFilename);
11707 : }
11708 2594 : }
11709 : }
11710 : else
11711 : {
11712 101695 : osSrcDSName = pszFilename;
11713 : }
11714 104289 : return osSrcDSName;
11715 : }
11716 :
11717 : /************************************************************************/
11718 : /* GDALMDArrayFromDataset */
11719 : /************************************************************************/
11720 :
11721 : class GDALMDArrayFromDataset final : public GDALMDArray
11722 : {
11723 : CPL_DISALLOW_COPY_ASSIGN(GDALMDArrayFromDataset)
11724 :
11725 : GDALDataset *const m_poDS;
11726 : const GDALExtendedDataType m_dt;
11727 : std::vector<std::shared_ptr<GDALDimension>> m_dims{};
11728 : std::string m_osUnit{};
11729 : std::vector<GByte> m_abyNoData{};
11730 : std::shared_ptr<GDALMDArray> m_varX{};
11731 : std::shared_ptr<GDALMDArray> m_varY{};
11732 : std::shared_ptr<GDALMDArray> m_varBand{};
11733 : const std::string m_osFilename;
11734 : const CPLStringList m_aosOptions;
11735 : int m_iBandDim = 0;
11736 : int m_iYDim = 1;
11737 : int m_iXDim = 2;
11738 : mutable std::vector<std::shared_ptr<GDALMDArray>> m_apoOverviews{};
11739 :
11740 : bool ReadWrite(GDALRWFlag eRWFlag, const GUInt64 *arrayStartIdx,
11741 : const size_t *count, const GInt64 *arrayStep,
11742 : const GPtrDiff_t *bufferStride,
11743 : const GDALExtendedDataType &bufferDataType,
11744 : void *pBuffer) const;
11745 :
11746 : protected:
11747 17 : GDALMDArrayFromDataset(GDALDataset *poDS, CSLConstList papszOptions)
11748 34 : : GDALAbstractMDArray(std::string(),
11749 34 : std::string(poDS->GetDescription())),
11750 34 : GDALMDArray(std::string(), std::string(poDS->GetDescription())),
11751 : m_poDS(poDS), m_dt(GDALExtendedDataType::Create(
11752 : poDS->GetRasterBand(1)->GetRasterDataType())),
11753 85 : m_osFilename(poDS->GetDescription()), m_aosOptions(papszOptions)
11754 : {
11755 17 : m_poDS->Reference();
11756 :
11757 17 : const int nBandCount = poDS->GetRasterCount();
11758 47 : for (int i = 1; i <= nBandCount; ++i)
11759 : {
11760 30 : const auto poBand = poDS->GetRasterBand(i);
11761 30 : if (i == 1)
11762 17 : m_osUnit = poBand->GetUnitType();
11763 13 : else if (m_osUnit != poBand->GetUnitType())
11764 7 : m_osUnit.clear();
11765 :
11766 60 : std::vector<GByte> abyNoData;
11767 30 : int bHasNoData = false;
11768 30 : switch (poBand->GetRasterDataType())
11769 : {
11770 0 : case GDT_Int64:
11771 : {
11772 : const auto nNoData =
11773 0 : poBand->GetNoDataValueAsInt64(&bHasNoData);
11774 0 : if (bHasNoData)
11775 : {
11776 0 : abyNoData.resize(m_dt.GetSize());
11777 0 : GDALCopyWords64(&nNoData, GDT_Int64, 0, &abyNoData[0],
11778 : m_dt.GetNumericDataType(), 0, 1);
11779 : }
11780 0 : break;
11781 : }
11782 :
11783 0 : case GDT_UInt64:
11784 : {
11785 : const auto nNoData =
11786 0 : poBand->GetNoDataValueAsUInt64(&bHasNoData);
11787 0 : if (bHasNoData)
11788 : {
11789 0 : abyNoData.resize(m_dt.GetSize());
11790 0 : GDALCopyWords64(&nNoData, GDT_UInt64, 0, &abyNoData[0],
11791 : m_dt.GetNumericDataType(), 0, 1);
11792 : }
11793 0 : break;
11794 : }
11795 :
11796 30 : default:
11797 : {
11798 30 : const auto dfNoData = poBand->GetNoDataValue(&bHasNoData);
11799 30 : if (bHasNoData)
11800 : {
11801 11 : abyNoData.resize(m_dt.GetSize());
11802 22 : GDALCopyWords64(&dfNoData, GDT_Float64, 0,
11803 11 : &abyNoData[0],
11804 : m_dt.GetNumericDataType(), 0, 1);
11805 : }
11806 30 : break;
11807 : }
11808 : }
11809 :
11810 30 : if (i == 1)
11811 17 : m_abyNoData = std::move(abyNoData);
11812 13 : else if (m_abyNoData != abyNoData)
11813 7 : m_abyNoData.clear();
11814 : }
11815 :
11816 17 : const int nXSize = poDS->GetRasterXSize();
11817 17 : const int nYSize = poDS->GetRasterYSize();
11818 :
11819 17 : auto poSRS = poDS->GetSpatialRef();
11820 34 : std::string osTypeY;
11821 34 : std::string osTypeX;
11822 34 : std::string osDirectionY;
11823 34 : std::string osDirectionX;
11824 17 : if (poSRS && poSRS->GetAxesCount() == 2)
11825 : {
11826 8 : const auto &mapping = poSRS->GetDataAxisToSRSAxisMapping();
11827 8 : OGRAxisOrientation eOrientation1 = OAO_Other;
11828 8 : poSRS->GetAxis(nullptr, 0, &eOrientation1);
11829 8 : OGRAxisOrientation eOrientation2 = OAO_Other;
11830 8 : poSRS->GetAxis(nullptr, 1, &eOrientation2);
11831 8 : if (eOrientation1 == OAO_East && eOrientation2 == OAO_North)
11832 : {
11833 6 : if (mapping == std::vector<int>{1, 2})
11834 : {
11835 6 : osTypeY = GDAL_DIM_TYPE_HORIZONTAL_Y;
11836 6 : osDirectionY = "NORTH";
11837 6 : osTypeX = GDAL_DIM_TYPE_HORIZONTAL_X;
11838 6 : osDirectionX = "EAST";
11839 : }
11840 : }
11841 2 : else if (eOrientation1 == OAO_North && eOrientation2 == OAO_East)
11842 : {
11843 2 : if (mapping == std::vector<int>{2, 1})
11844 : {
11845 2 : osTypeY = GDAL_DIM_TYPE_HORIZONTAL_Y;
11846 2 : osDirectionY = "NORTH";
11847 2 : osTypeX = GDAL_DIM_TYPE_HORIZONTAL_X;
11848 2 : osDirectionX = "EAST";
11849 : }
11850 : }
11851 : }
11852 :
11853 47 : const bool bBandYX = [papszOptions, poDS, nBandCount]()
11854 : {
11855 : const char *pszDimOrder =
11856 17 : CSLFetchNameValueDef(papszOptions, "DIM_ORDER", "AUTO");
11857 17 : if (EQUAL(pszDimOrder, "AUTO"))
11858 : {
11859 : const char *pszInterleave =
11860 15 : poDS->GetMetadataItem("INTERLEAVE", "IMAGE_STRUCTURE");
11861 24 : return nBandCount == 1 || !pszInterleave ||
11862 24 : !EQUAL(pszInterleave, "PIXEL");
11863 : }
11864 : else
11865 : {
11866 2 : return EQUAL(pszDimOrder, "BAND,Y,X");
11867 : }
11868 17 : }();
11869 : const char *const pszBandDimName =
11870 17 : CSLFetchNameValueDef(papszOptions, "BAND_DIM_NAME", "Band");
11871 : auto poBandDim = std::make_shared<GDALDimensionWeakIndexingVar>(
11872 51 : "/", pszBandDimName, std::string(), std::string(), nBandCount);
11873 : const char *const pszYDimName =
11874 17 : CSLFetchNameValueDef(papszOptions, "Y_DIM_NAME", "Y");
11875 : auto poYDim = std::make_shared<GDALDimensionWeakIndexingVar>(
11876 34 : "/", pszYDimName, osTypeY, osDirectionY, nYSize);
11877 : const char *const pszXDimName =
11878 17 : CSLFetchNameValueDef(papszOptions, "X_DIM_NAME", "X");
11879 : auto poXDim = std::make_shared<GDALDimensionWeakIndexingVar>(
11880 34 : "/", pszXDimName, osTypeX, osDirectionX, nXSize);
11881 :
11882 17 : const char *const pszBandIndexingVarItem = CSLFetchNameValueDef(
11883 : papszOptions, "BAND_INDEXING_VAR_ITEM", "{Description}");
11884 17 : if (EQUAL(pszBandIndexingVarItem, "{Description}"))
11885 : {
11886 : const auto oIndexingVarType =
11887 22 : GDALExtendedDataType::CreateString(strlen("Band 65535"));
11888 11 : auto poBandVar = MEMMDArray::Create("/", poBandDim->GetName(),
11889 44 : {poBandDim}, oIndexingVarType);
11890 11 : CPL_IGNORE_RET_VAL(poBandVar->Init());
11891 29 : for (int i = 0; i < nBandCount; ++i)
11892 : {
11893 : const char *pszDesc =
11894 18 : poDS->GetRasterBand(i + 1)->GetDescription();
11895 : const std::string osBandName =
11896 36 : pszDesc[0] ? pszDesc : CPLSPrintf("Band %d", i + 1);
11897 18 : const char *pszBandName = osBandName.c_str();
11898 18 : const char *const apszBandVal[] = {pszBandName};
11899 18 : const GUInt64 anStartIdx[] = {static_cast<GUInt64>(i)};
11900 18 : const size_t anCount[] = {1};
11901 18 : const GInt64 arrayStep[] = {1};
11902 18 : const GPtrDiff_t anBufferStride[] = {1};
11903 18 : poBandVar->Write(anStartIdx, anCount, arrayStep, anBufferStride,
11904 : oIndexingVarType, apszBandVal);
11905 : }
11906 11 : m_varBand = std::move(poBandVar);
11907 11 : poBandDim->SetIndexingVariable(m_varBand);
11908 : }
11909 6 : else if (EQUAL(pszBandIndexingVarItem, "{Index}"))
11910 : {
11911 : const auto oIndexingVarType =
11912 2 : GDALExtendedDataType::Create(GDT_Int32);
11913 1 : auto poBandVar = MEMMDArray::Create("/", poBandDim->GetName(),
11914 4 : {poBandDim}, oIndexingVarType);
11915 1 : CPL_IGNORE_RET_VAL(poBandVar->Init());
11916 3 : for (int i = 0; i < nBandCount; ++i)
11917 : {
11918 2 : const int anBandIdx[] = {i + 1};
11919 2 : const GUInt64 anStartIdx[] = {static_cast<GUInt64>(i)};
11920 2 : const size_t anCount[] = {1};
11921 2 : const GInt64 arrayStep[] = {1};
11922 2 : const GPtrDiff_t anBufferStride[] = {1};
11923 2 : poBandVar->Write(anStartIdx, anCount, arrayStep, anBufferStride,
11924 : oIndexingVarType, anBandIdx);
11925 : }
11926 1 : m_varBand = std::move(poBandVar);
11927 1 : poBandDim->SetIndexingVariable(m_varBand);
11928 : }
11929 5 : else if (EQUAL(pszBandIndexingVarItem, "{ColorInterpretation}"))
11930 : {
11931 1 : size_t nMaxLen = 0;
11932 3 : for (int i = 0; i < nBandCount; ++i)
11933 : {
11934 2 : const char *pszDesc = GDALGetColorInterpretationName(
11935 2 : poDS->GetRasterBand(i + 1)->GetColorInterpretation());
11936 2 : nMaxLen = std::max(nMaxLen, strlen(pszDesc));
11937 : }
11938 : const auto oIndexingVarType =
11939 2 : GDALExtendedDataType::CreateString(nMaxLen);
11940 1 : auto poBandVar = MEMMDArray::Create("/", poBandDim->GetName(),
11941 4 : {poBandDim}, oIndexingVarType);
11942 1 : CPL_IGNORE_RET_VAL(poBandVar->Init());
11943 3 : for (int i = 0; i < nBandCount; ++i)
11944 : {
11945 2 : const char *pszDesc = GDALGetColorInterpretationName(
11946 2 : poDS->GetRasterBand(i + 1)->GetColorInterpretation());
11947 2 : const char *const apszBandVal[] = {pszDesc};
11948 2 : const GUInt64 anStartIdx[] = {static_cast<GUInt64>(i)};
11949 2 : const size_t anCount[] = {1};
11950 2 : const GInt64 arrayStep[] = {1};
11951 2 : const GPtrDiff_t anBufferStride[] = {1};
11952 2 : poBandVar->Write(anStartIdx, anCount, arrayStep, anBufferStride,
11953 : oIndexingVarType, apszBandVal);
11954 : }
11955 1 : m_varBand = std::move(poBandVar);
11956 1 : poBandDim->SetIndexingVariable(m_varBand);
11957 : }
11958 4 : else if (!EQUAL(pszBandIndexingVarItem, "{None}"))
11959 : {
11960 3 : const char *const pszBandIndexingVarType = CSLFetchNameValueDef(
11961 : papszOptions, "BAND_INDEXING_VAR_TYPE", "String");
11962 3 : size_t nMaxLen = 0;
11963 3 : if (EQUAL(pszBandIndexingVarType, "String"))
11964 : {
11965 3 : for (int i = 0; i < nBandCount; ++i)
11966 : {
11967 : const char *pszVal =
11968 2 : poDS->GetRasterBand(i + 1)->GetMetadataItem(
11969 2 : pszBandIndexingVarItem);
11970 2 : if (pszVal)
11971 1 : nMaxLen = std::max(nMaxLen, strlen(pszVal));
11972 : }
11973 : }
11974 : const auto oIndexingVarType =
11975 3 : EQUAL(pszBandIndexingVarType, "String")
11976 : ? GDALExtendedDataType::CreateString(nMaxLen)
11977 2 : : EQUAL(pszBandIndexingVarType, "Integer")
11978 : ? GDALExtendedDataType::Create(GDT_Int32)
11979 6 : : GDALExtendedDataType::Create(GDT_Float64);
11980 3 : auto poBandVar = MEMMDArray::Create("/", poBandDim->GetName(),
11981 12 : {poBandDim}, oIndexingVarType);
11982 3 : CPL_IGNORE_RET_VAL(poBandVar->Init());
11983 9 : for (int i = 0; i < nBandCount; ++i)
11984 : {
11985 6 : const GUInt64 anStartIdx[] = {static_cast<GUInt64>(i)};
11986 6 : const size_t anCount[] = {1};
11987 6 : const GInt64 arrayStep[] = {1};
11988 6 : const GPtrDiff_t anBufferStride[] = {1};
11989 : const char *pszVal =
11990 6 : poDS->GetRasterBand(i + 1)->GetMetadataItem(
11991 6 : pszBandIndexingVarItem);
11992 6 : if (oIndexingVarType.GetClass() == GEDTC_STRING)
11993 : {
11994 2 : const char *const apszBandVal[] = {pszVal ? pszVal : ""};
11995 2 : poBandVar->Write(anStartIdx, anCount, arrayStep,
11996 : anBufferStride, oIndexingVarType,
11997 : apszBandVal);
11998 : }
11999 4 : else if (oIndexingVarType.GetNumericDataType() == GDT_Int32)
12000 : {
12001 2 : const int anVal[] = {pszVal ? atoi(pszVal) : 0};
12002 2 : poBandVar->Write(anStartIdx, anCount, arrayStep,
12003 : anBufferStride, oIndexingVarType, anVal);
12004 : }
12005 : else
12006 : {
12007 2 : const double adfVal[] = {pszVal ? CPLAtof(pszVal) : 0.0};
12008 2 : poBandVar->Write(anStartIdx, anCount, arrayStep,
12009 : anBufferStride, oIndexingVarType, adfVal);
12010 : }
12011 : }
12012 3 : m_varBand = std::move(poBandVar);
12013 3 : poBandDim->SetIndexingVariable(m_varBand);
12014 : }
12015 :
12016 17 : GDALGeoTransform gt;
12017 17 : if (m_poDS->GetGeoTransform(gt) == CE_None && gt[2] == 0 && gt[4] == 0)
12018 : {
12019 24 : m_varX = GDALMDArrayRegularlySpaced::Create(
12020 24 : "/", poBandDim->GetName(), poXDim, gt[0], gt[1], 0.5);
12021 8 : poXDim->SetIndexingVariable(m_varX);
12022 :
12023 24 : m_varY = GDALMDArrayRegularlySpaced::Create(
12024 24 : "/", poYDim->GetName(), poYDim, gt[3], gt[5], 0.5);
12025 8 : poYDim->SetIndexingVariable(m_varY);
12026 : }
12027 17 : if (bBandYX)
12028 : {
12029 96 : m_dims = {std::move(poBandDim), std::move(poYDim),
12030 80 : std::move(poXDim)};
12031 : }
12032 : else
12033 : {
12034 1 : m_iYDim = 0;
12035 1 : m_iXDim = 1;
12036 1 : m_iBandDim = 2;
12037 6 : m_dims = {std::move(poYDim), std::move(poXDim),
12038 5 : std::move(poBandDim)};
12039 : }
12040 17 : }
12041 :
12042 : bool IRead(const GUInt64 *arrayStartIdx, const size_t *count,
12043 : const GInt64 *arrayStep, const GPtrDiff_t *bufferStride,
12044 : const GDALExtendedDataType &bufferDataType,
12045 : void *pDstBuffer) const override;
12046 :
12047 1 : bool IWrite(const GUInt64 *arrayStartIdx, const size_t *count,
12048 : const GInt64 *arrayStep, const GPtrDiff_t *bufferStride,
12049 : const GDALExtendedDataType &bufferDataType,
12050 : const void *pSrcBuffer) override
12051 : {
12052 1 : return ReadWrite(GF_Write, arrayStartIdx, count, arrayStep,
12053 : bufferStride, bufferDataType,
12054 1 : const_cast<void *>(pSrcBuffer));
12055 : }
12056 :
12057 : public:
12058 34 : ~GDALMDArrayFromDataset() override
12059 17 : {
12060 17 : m_poDS->ReleaseRef();
12061 34 : }
12062 :
12063 17 : static std::shared_ptr<GDALMDArray> Create(GDALDataset *poDS,
12064 : CSLConstList papszOptions)
12065 : {
12066 : auto array(std::shared_ptr<GDALMDArrayFromDataset>(
12067 34 : new GDALMDArrayFromDataset(poDS, papszOptions)));
12068 17 : array->SetSelf(array);
12069 34 : return array;
12070 : }
12071 :
12072 2 : bool IsWritable() const override
12073 : {
12074 2 : return m_poDS->GetAccess() == GA_Update;
12075 : }
12076 :
12077 16 : const std::string &GetFilename() const override
12078 : {
12079 16 : return m_osFilename;
12080 : }
12081 :
12082 : const std::vector<std::shared_ptr<GDALDimension>> &
12083 102 : GetDimensions() const override
12084 : {
12085 102 : return m_dims;
12086 : }
12087 :
12088 38 : const GDALExtendedDataType &GetDataType() const override
12089 : {
12090 38 : return m_dt;
12091 : }
12092 :
12093 5 : const std::string &GetUnit() const override
12094 : {
12095 5 : return m_osUnit;
12096 : }
12097 :
12098 5 : const void *GetRawNoDataValue() const override
12099 : {
12100 5 : return m_abyNoData.empty() ? nullptr : m_abyNoData.data();
12101 : }
12102 :
12103 5 : double GetOffset(bool *pbHasOffset,
12104 : GDALDataType *peStorageType) const override
12105 : {
12106 5 : double dfRes = 0;
12107 5 : int bHasOffset = false;
12108 5 : auto poFirstBand = m_poDS->GetRasterBand(1);
12109 5 : if (poFirstBand) // to avoid -Wnull-dereference
12110 : {
12111 5 : dfRes = poFirstBand->GetOffset(&bHasOffset);
12112 7 : for (int i = 2; bHasOffset && i <= m_poDS->GetRasterCount(); ++i)
12113 : {
12114 : const double dfOtherRes =
12115 2 : m_poDS->GetRasterBand(i)->GetOffset(&bHasOffset);
12116 2 : bHasOffset = bHasOffset && (dfOtherRes == dfRes);
12117 : }
12118 : }
12119 5 : if (pbHasOffset)
12120 5 : *pbHasOffset = CPL_TO_BOOL(bHasOffset);
12121 5 : if (peStorageType)
12122 3 : *peStorageType = GDT_Unknown;
12123 5 : return dfRes;
12124 : }
12125 :
12126 5 : double GetScale(bool *pbHasScale,
12127 : GDALDataType *peStorageType) const override
12128 : {
12129 5 : double dfRes = 0;
12130 5 : int bHasScale = false;
12131 5 : auto poFirstBand = m_poDS->GetRasterBand(1);
12132 5 : if (poFirstBand) // to avoid -Wnull-dereference
12133 : {
12134 5 : dfRes = poFirstBand->GetScale(&bHasScale);
12135 7 : for (int i = 2; bHasScale && i <= m_poDS->GetRasterCount(); ++i)
12136 : {
12137 : const double dfOtherRes =
12138 2 : m_poDS->GetRasterBand(i)->GetScale(&bHasScale);
12139 2 : bHasScale = bHasScale && (dfOtherRes == dfRes);
12140 : }
12141 : }
12142 5 : if (pbHasScale)
12143 5 : *pbHasScale = CPL_TO_BOOL(bHasScale);
12144 5 : if (peStorageType)
12145 3 : *peStorageType = GDT_Unknown;
12146 5 : return dfRes;
12147 : }
12148 :
12149 9 : std::shared_ptr<OGRSpatialReference> GetSpatialRef() const override
12150 : {
12151 9 : auto poSrcSRS = m_poDS->GetSpatialRef();
12152 9 : if (!poSrcSRS)
12153 1 : return nullptr;
12154 16 : auto poSRS = std::shared_ptr<OGRSpatialReference>(poSrcSRS->Clone());
12155 :
12156 16 : auto axisMapping = poSRS->GetDataAxisToSRSAxisMapping();
12157 24 : for (auto &m : axisMapping)
12158 : {
12159 16 : if (m == 1)
12160 8 : m = m_iXDim + 1;
12161 8 : else if (m == 2)
12162 8 : m = m_iYDim + 1;
12163 : else
12164 0 : m = 0;
12165 : }
12166 8 : poSRS->SetDataAxisToSRSAxisMapping(axisMapping);
12167 8 : return poSRS;
12168 : }
12169 :
12170 7 : std::vector<GUInt64> GetBlockSize() const override
12171 : {
12172 7 : int nBlockXSize = 0;
12173 7 : int nBlockYSize = 0;
12174 7 : m_poDS->GetRasterBand(1)->GetBlockSize(&nBlockXSize, &nBlockYSize);
12175 7 : if (m_iBandDim == 0)
12176 : {
12177 6 : return std::vector<GUInt64>{1, static_cast<GUInt64>(nBlockYSize),
12178 6 : static_cast<GUInt64>(nBlockXSize)};
12179 : }
12180 : else
12181 : {
12182 1 : return std::vector<GUInt64>{static_cast<GUInt64>(nBlockYSize),
12183 1 : static_cast<GUInt64>(nBlockXSize), 1};
12184 : }
12185 : }
12186 :
12187 : std::vector<std::shared_ptr<GDALAttribute>>
12188 7 : GetAttributes(CSLConstList) const override
12189 : {
12190 7 : std::vector<std::shared_ptr<GDALAttribute>> res;
12191 7 : auto papszMD = m_poDS->GetMetadata();
12192 14 : for (auto iter = papszMD; iter && iter[0]; ++iter)
12193 : {
12194 7 : char *pszKey = nullptr;
12195 7 : const char *pszValue = CPLParseNameValue(*iter, &pszKey);
12196 7 : if (pszKey && pszValue)
12197 : {
12198 : res.emplace_back(
12199 7 : std::make_shared<GDALMDIAsAttribute>(pszKey, pszValue));
12200 : }
12201 7 : CPLFree(pszKey);
12202 : }
12203 7 : return res;
12204 : }
12205 :
12206 6 : int GetOverviewCount() const override
12207 : {
12208 6 : int nOvrCount = 0;
12209 6 : GDALDataset *poOvrDS = nullptr;
12210 6 : bool bOK = true;
12211 12 : for (int i = 1; bOK && i <= m_poDS->GetRasterCount(); ++i)
12212 : {
12213 6 : auto poBand = m_poDS->GetRasterBand(i);
12214 6 : const int nThisOvrCount = poBand->GetOverviewCount();
12215 6 : bOK = (nThisOvrCount > 0 && (i == 1 || nThisOvrCount == nOvrCount));
12216 6 : if (bOK)
12217 : {
12218 6 : nOvrCount = nThisOvrCount;
12219 6 : auto poFirstOvrBand = poBand->GetOverview(0);
12220 6 : bOK = poFirstOvrBand != nullptr;
12221 6 : if (bOK)
12222 : {
12223 6 : auto poThisOvrDS = poFirstOvrBand->GetDataset();
12224 12 : bOK = poThisOvrDS != nullptr &&
12225 6 : poThisOvrDS->GetRasterBand(i) == poFirstOvrBand &&
12226 0 : (i == 1 || poThisOvrDS == poOvrDS);
12227 6 : if (bOK)
12228 6 : poOvrDS = poThisOvrDS;
12229 : }
12230 : }
12231 : }
12232 6 : return bOK ? nOvrCount : 0;
12233 : }
12234 :
12235 5 : std::shared_ptr<GDALMDArray> GetOverview(int idx) const override
12236 : {
12237 5 : const int nOverviews = GetOverviewCount();
12238 5 : if (idx < 0 || idx >= nOverviews)
12239 2 : return nullptr;
12240 3 : m_apoOverviews.resize(nOverviews);
12241 3 : if (!m_apoOverviews[idx])
12242 : {
12243 1 : if (auto poBand = m_poDS->GetRasterBand(1))
12244 : {
12245 1 : if (auto poOvrBand = poBand->GetOverview(idx))
12246 : {
12247 1 : if (auto poOvrDS = poOvrBand->GetDataset())
12248 : {
12249 1 : m_apoOverviews[idx] =
12250 2 : Create(poOvrDS, m_aosOptions.List());
12251 : }
12252 : }
12253 : }
12254 : }
12255 3 : return m_apoOverviews[idx];
12256 : }
12257 : };
12258 :
12259 10 : bool GDALMDArrayFromDataset::IRead(const GUInt64 *arrayStartIdx,
12260 : const size_t *count, const GInt64 *arrayStep,
12261 : const GPtrDiff_t *bufferStride,
12262 : const GDALExtendedDataType &bufferDataType,
12263 : void *pDstBuffer) const
12264 : {
12265 10 : return ReadWrite(GF_Read, arrayStartIdx, count, arrayStep, bufferStride,
12266 10 : bufferDataType, pDstBuffer);
12267 : }
12268 :
12269 : /************************************************************************/
12270 : /* ReadWrite() */
12271 : /************************************************************************/
12272 :
12273 11 : bool GDALMDArrayFromDataset::ReadWrite(
12274 : GDALRWFlag eRWFlag, const GUInt64 *arrayStartIdx, const size_t *count,
12275 : const GInt64 *arrayStep, const GPtrDiff_t *bufferStride,
12276 : const GDALExtendedDataType &bufferDataType, void *pBuffer) const
12277 : {
12278 11 : const auto eDT(bufferDataType.GetNumericDataType());
12279 11 : const auto nDTSize(GDALGetDataTypeSizeBytes(eDT));
12280 11 : const int nX =
12281 11 : arrayStep[m_iXDim] > 0
12282 11 : ? static_cast<int>(arrayStartIdx[m_iXDim])
12283 0 : : static_cast<int>(arrayStartIdx[m_iXDim] -
12284 0 : (count[m_iXDim] - 1) * -arrayStep[m_iXDim]);
12285 11 : const int nY =
12286 11 : arrayStep[m_iYDim] > 0
12287 11 : ? static_cast<int>(arrayStartIdx[m_iYDim])
12288 1 : : static_cast<int>(arrayStartIdx[m_iYDim] -
12289 1 : (count[m_iYDim] - 1) * -arrayStep[m_iYDim]);
12290 11 : const int nSizeX =
12291 11 : static_cast<int>(count[m_iXDim] * ABS(arrayStep[m_iXDim]));
12292 11 : const int nSizeY =
12293 11 : static_cast<int>(count[m_iYDim] * ABS(arrayStep[m_iYDim]));
12294 11 : GByte *pabyBuffer = static_cast<GByte *>(pBuffer);
12295 11 : int nStrideXSign = 1;
12296 11 : if (arrayStep[m_iXDim] < 0)
12297 : {
12298 0 : pabyBuffer += (count[m_iXDim] - 1) * bufferStride[m_iXDim] * nDTSize;
12299 0 : nStrideXSign = -1;
12300 : }
12301 11 : int nStrideYSign = 1;
12302 11 : if (arrayStep[m_iYDim] < 0)
12303 : {
12304 1 : pabyBuffer += (count[m_iYDim] - 1) * bufferStride[m_iYDim] * nDTSize;
12305 1 : nStrideYSign = -1;
12306 : }
12307 11 : const GSpacing nPixelSpace =
12308 11 : static_cast<GSpacing>(nStrideXSign * bufferStride[m_iXDim] * nDTSize);
12309 11 : const GSpacing nLineSpace =
12310 11 : static_cast<GSpacing>(nStrideYSign * bufferStride[m_iYDim] * nDTSize);
12311 11 : const GSpacing nBandSpace =
12312 11 : static_cast<GSpacing>(bufferStride[m_iBandDim] * nDTSize);
12313 11 : std::vector<int> anBandList;
12314 28 : for (int i = 0; i < static_cast<int>(count[m_iBandDim]); ++i)
12315 17 : anBandList.push_back(1 + static_cast<int>(arrayStartIdx[m_iBandDim]) +
12316 17 : i * static_cast<int>(arrayStep[m_iBandDim]));
12317 :
12318 33 : return m_poDS->RasterIO(eRWFlag, nX, nY, nSizeX, nSizeY, pabyBuffer,
12319 11 : static_cast<int>(count[m_iXDim]),
12320 11 : static_cast<int>(count[m_iYDim]), eDT,
12321 11 : static_cast<int>(count[m_iBandDim]),
12322 11 : anBandList.data(), nPixelSpace, nLineSpace,
12323 22 : nBandSpace, nullptr) == CE_None;
12324 : }
12325 :
12326 : /************************************************************************/
12327 : /* AsMDArray() */
12328 : /************************************************************************/
12329 :
12330 : /** Return a view of this dataset as a 3D multidimensional GDALMDArray.
12331 : *
12332 : * If this dataset is not already marked as shared, it will be, so that the
12333 : * returned array holds a reference to it.
12334 : *
12335 : * If the dataset has a geotransform attached, the X and Y dimensions of the
12336 : * returned array will have an associated indexing variable.
12337 : *
12338 : * The currently supported list of options is:
12339 : * <ul>
12340 : * <li>DIM_ORDER=<order> where order can be "AUTO", "Band,Y,X" or "Y,X,Band".
12341 : * "Band,Y,X" means that the first (slowest changing) dimension is Band
12342 : * and the last (fastest changing direction) is X
12343 : * "Y,X,Band" means that the first (slowest changing) dimension is Y
12344 : * and the last (fastest changing direction) is Band.
12345 : * "AUTO" (the default) selects "Band,Y,X" for single band datasets, or takes
12346 : * into account the INTERLEAVE metadata item in the IMAGE_STRUCTURE domain.
12347 : * If it equals BAND, then "Band,Y,X" is used. Otherwise (if it equals PIXEL),
12348 : * "Y,X,Band" is use.
12349 : * </li>
12350 : * <li>BAND_INDEXING_VAR_ITEM={Description}|{None}|{Index}|{ColorInterpretation}|<BandMetadataItem>:
12351 : * item from which to build the band indexing variable.
12352 : * <ul>
12353 : * <li>"{Description}", the default, means to use the band description (or "Band index" if empty).</li>
12354 : * <li>"{None}" means that no band indexing variable must be created.</li>
12355 : * <li>"{Index}" means that the band index (starting at one) is used.</li>
12356 : * <li>"{ColorInterpretation}" means that the band color interpretation is used (i.e. "Red", "Green", "Blue").</li>
12357 : * <li><BandMetadataItem> is the name of a band metadata item to use.</li>
12358 : * </ul>
12359 : * </li>
12360 : * <li>BAND_INDEXING_VAR_TYPE=String|Real|Integer: the data type of the band
12361 : * indexing variable, when BAND_INDEXING_VAR_ITEM corresponds to a band metadata item.
12362 : * Defaults to String.
12363 : * </li>
12364 : * <li>BAND_DIM_NAME=<string>: Name of the band dimension.
12365 : * Defaults to "Band".
12366 : * </li>
12367 : * <li>X_DIM_NAME=<string>: Name of the X dimension. Defaults to "X".
12368 : * </li>
12369 : * <li>Y_DIM_NAME=<string>: Name of the Y dimension. Defaults to "Y".
12370 : * </li>
12371 : * </ul>
12372 : *
12373 : * This is the same as the C function GDALDatasetAsMDArray().
12374 : *
12375 : * The "reverse" method is GDALMDArray::AsClassicDataset().
12376 : *
12377 : * @param papszOptions Null-terminated list of strings, or nullptr.
12378 : * @return a new array, or nullptr.
12379 : *
12380 : * @since GDAL 3.12
12381 : */
12382 19 : std::shared_ptr<GDALMDArray> GDALDataset::AsMDArray(CSLConstList papszOptions)
12383 : {
12384 19 : if (!GetShared())
12385 : {
12386 18 : MarkAsShared();
12387 : }
12388 19 : if (nBands == 0 || nRasterXSize == 0 || nRasterYSize == 0)
12389 : {
12390 1 : ReportError(
12391 : CE_Failure, CPLE_AppDefined,
12392 : "Degenerated array (band, Y and/or X dimension of size zero)");
12393 1 : return nullptr;
12394 : }
12395 18 : const GDALDataType eDT = papoBands[0]->GetRasterDataType();
12396 31 : for (int i = 1; i < nBands; ++i)
12397 : {
12398 14 : if (eDT != papoBands[i]->GetRasterDataType())
12399 : {
12400 1 : ReportError(CE_Failure, CPLE_AppDefined,
12401 : "Non-uniform data type amongst bands");
12402 1 : return nullptr;
12403 : }
12404 : }
12405 : const char *pszDimOrder =
12406 17 : CSLFetchNameValueDef(papszOptions, "DIM_ORDER", "AUTO");
12407 17 : if (!EQUAL(pszDimOrder, "AUTO") && !EQUAL(pszDimOrder, "Band,Y,X") &&
12408 2 : !EQUAL(pszDimOrder, "Y,X,Band"))
12409 : {
12410 1 : ReportError(CE_Failure, CPLE_IllegalArg,
12411 : "Illegal value for DIM_ORDER option");
12412 1 : return nullptr;
12413 : }
12414 16 : return GDALMDArrayFromDataset::Create(this, papszOptions);
12415 : }
12416 :
12417 : /************************************************************************/
12418 : /* GDALDataset::GetInterBandCovarianceMatrix() */
12419 : /************************************************************************/
12420 :
12421 : /**
12422 : \brief Fetch or compute the covariance matrix between bands of this dataset.
12423 :
12424 : The covariance indicates the level to which two bands vary together.
12425 :
12426 : If we call \f$ v_i[y,x] \f$ the value of pixel at row=y and column=x for band i,
12427 : and \f$ mean_i \f$ the mean value of all pixels of band i, then
12428 :
12429 : \f[
12430 : \mathrm{cov}[i,j] =
12431 : \frac{
12432 : \sum_{y,x} \left( v_i[y,x] - \mathrm{mean}_i \right)
12433 : \left( v_j[y,x] - \mathrm{mean}_j \right)
12434 : }{
12435 : \mathrm{pixel\_count} - \mathrm{nDeltaDegreeOfFreedom}
12436 : }
12437 : \f]
12438 :
12439 : When there are no nodata values, \f$ pixel\_count = GetRasterXSize() * GetRasterYSize() \f$.
12440 : We can see that \f$ cov[i,j] = cov[j,i] \f$, and consequently the returned matrix
12441 : is symmetric.
12442 :
12443 : A value of nDeltaDegreeOfFreedom=1 (the default) will return a unbiased estimate
12444 : if the pixels in bands are considered to be a sample of the whole population.
12445 : This is consistent with the default of
12446 : https://numpy.org/doc/stable/reference/generated/numpy.cov.html and the returned
12447 : matrix is consistent with what can be obtained with
12448 :
12449 : \verbatim embed:rst
12450 : .. code-block:: python
12451 :
12452 : numpy.cov(
12453 : [ds.GetRasterBand(n + 1).ReadAsArray().ravel() for n in range(ds.RasterCount)]
12454 : )
12455 : \endverbatim
12456 :
12457 : Otherwise a value of nDeltaDegreeOfFreedom=0 can be used if they are considered
12458 : to be the whole population.
12459 :
12460 : If STATISTICS_COVARIANCES metadata items are available in band metadata,
12461 : this method uses them.
12462 : Otherwise, if bForce is true, ComputeInterBandCovarianceMatrix() is called.
12463 : Otherwise, if bForce is false, an empty vector is returned
12464 :
12465 : @param nBandCount Zero for all bands, or number of values in panBandList.
12466 : Defaults to 0.
12467 : @param panBandList nullptr for all bands if nBandCount == 0, or array of
12468 : nBandCount values such as panBandList[i] is the index
12469 : between 1 and GetRasterCount() of a band that must be used
12470 : in the covariance computation. Defaults to nullptr.
12471 : @param bApproxOK Whether it is acceptable to use a subsample of values in
12472 : ComputeInterBandCovarianceMatrix().
12473 : Defaults to false.
12474 : @param bForce Whether ComputeInterBandCovarianceMatrix() should be called
12475 : when the STATISTICS_COVARIANCES metadata items are missing.
12476 : Defaults to false.
12477 : @param bWriteIntoMetadata Whether ComputeInterBandCovarianceMatrix() must
12478 : write STATISTICS_COVARIANCES band metadata items.
12479 : Defaults to true.
12480 : @param nDeltaDegreeOfFreedom Correction term to subtract in the final
12481 : averaging phase of the covariance computation.
12482 : Defaults to 1.
12483 : @param pfnProgress a function to call to report progress, or NULL.
12484 : @param pProgressData application data to pass to the progress function.
12485 :
12486 : @return a vector of nBandCount * nBandCount values if successful,
12487 : in row-major order, or an empty vector in case of failure
12488 :
12489 : @since 3.13
12490 :
12491 : @see ComputeInterBandCovarianceMatrix()
12492 : */
12493 :
12494 0 : std::vector<double> GDALDataset::GetInterBandCovarianceMatrix(
12495 : int nBandCount, const int *panBandList, bool bApproxOK, bool bForce,
12496 : bool bWriteIntoMetadata, int nDeltaDegreeOfFreedom,
12497 : GDALProgressFunc pfnProgress, void *pProgressData)
12498 : {
12499 0 : std::vector<double> res;
12500 0 : const int nBandCountToUse = nBandCount == 0 ? nBands : nBandCount;
12501 0 : if (nBandCountToUse == 0)
12502 0 : return res;
12503 : if constexpr (sizeof(size_t) < sizeof(uint64_t))
12504 : {
12505 : // Check that nBandCountToUse * nBandCountToUse will not overflow size_t
12506 : if (static_cast<uint32_t>(nBandCountToUse) >
12507 : std::numeric_limits<uint16_t>::max())
12508 : {
12509 : CPLError(CE_Failure, CPLE_OutOfMemory,
12510 : "Not enough memory to store result");
12511 : return res;
12512 : }
12513 : }
12514 : try
12515 : {
12516 0 : res.resize(static_cast<size_t>(nBandCountToUse) * nBandCountToUse);
12517 : }
12518 0 : catch (const std::exception &)
12519 : {
12520 0 : CPLError(CE_Failure, CPLE_OutOfMemory,
12521 : "Not enough memory to store result");
12522 0 : return res;
12523 : }
12524 :
12525 0 : if (GetInterBandCovarianceMatrix(res.data(), res.size(), nBandCount,
12526 : panBandList, bApproxOK, bForce,
12527 : bWriteIntoMetadata, nDeltaDegreeOfFreedom,
12528 0 : pfnProgress, pProgressData) != CE_None)
12529 : {
12530 0 : res.clear();
12531 : }
12532 0 : return res;
12533 : }
12534 :
12535 : /************************************************************************/
12536 : /* GDALDataset::GetInterBandCovarianceMatrix() */
12537 : /************************************************************************/
12538 :
12539 : /**
12540 : \brief Fetch or compute the covariance matrix between bands of this dataset.
12541 :
12542 : The covariance indicates the level to which two bands vary together.
12543 :
12544 : If we call \f$ v_i[y,x] \f$ the value of pixel at row=y and column=x for band i,
12545 : and \f$ mean_i \f$ the mean value of all pixels of band i, then
12546 :
12547 : \f[
12548 : \mathrm{cov}[i,j] =
12549 : \frac{
12550 : \sum_{y,x} \left( v_i[y,x] - \mathrm{mean}_i \right)
12551 : \left( v_j[y,x] - \mathrm{mean}_j \right)
12552 : }{
12553 : \mathrm{pixel\_count} - \mathrm{nDeltaDegreeOfFreedom}
12554 : }
12555 : \f]
12556 :
12557 : When there are no nodata values, \f$ pixel\_count = GetRasterXSize() * GetRasterYSize() \f$.
12558 : We can see that \f$ cov[i,j] = cov[j,i] \f$, and consequently the returned matrix
12559 : is symmetric.
12560 :
12561 : A value of nDeltaDegreeOfFreedom=1 (the default) will return a unbiased estimate
12562 : if the pixels in bands are considered to be a sample of the whole population.
12563 : This is consistent with the default of
12564 : https://numpy.org/doc/stable/reference/generated/numpy.cov.html and the returned
12565 : matrix is consistent with what can be obtained with
12566 :
12567 : \verbatim embed:rst
12568 : .. code-block:: python
12569 :
12570 : numpy.cov(
12571 : [ds.GetRasterBand(n + 1).ReadAsArray().ravel() for n in range(ds.RasterCount)]
12572 : )
12573 : \endverbatim
12574 :
12575 : Otherwise a value of nDeltaDegreeOfFreedom=0 can be used if they are considered
12576 : to be the whole population.
12577 :
12578 : The caller must provide an already allocated array in padfCovMatrix of size
12579 : at least nBandCount * nBandCount.
12580 :
12581 : If STATISTICS_COVARIANCES metadata items are available in band metadata,
12582 : this method uses them.
12583 : Otherwise, if bForce is true, ComputeInterBandCovarianceMatrix() is called.
12584 : Otherwise, if bForce is false, an empty vector is returned
12585 :
12586 : This is the same as the C function GDALDatasetGetInterBandCovarianceMatrix()
12587 :
12588 : @param[out] padfCovMatrix Pointer to an already allocated output array, of size at least
12589 : nBandCount * nBandCount.
12590 : @param nSize Number of elements in output array.
12591 : @param nBandCount Zero for all bands, or number of values in panBandList.
12592 : Defaults to 0.
12593 : @param panBandList nullptr for all bands if nBandCount == 0, or array of
12594 : nBandCount values such as panBandList[i] is the index
12595 : between 1 and GetRasterCount() of a band that must be used
12596 : in the covariance computation. Defaults to nullptr.
12597 : @param bApproxOK Whether it is acceptable to use a subsample of values in
12598 : ComputeInterBandCovarianceMatrix().
12599 : Defaults to false.
12600 : @param bForce Whether ComputeInterBandCovarianceMatrix() should be called
12601 : when the STATISTICS_COVARIANCES metadata items are missing.
12602 : Defaults to false.
12603 : @param bWriteIntoMetadata Whether ComputeInterBandCovarianceMatrix() must
12604 : write STATISTICS_COVARIANCES band metadata items.
12605 : Defaults to true.
12606 : @param nDeltaDegreeOfFreedom Correction term to subtract in the final
12607 : averaging phase of the covariance computation.
12608 : Defaults to 1.
12609 : @param pfnProgress a function to call to report progress, or NULL.
12610 : @param pProgressData application data to pass to the progress function.
12611 :
12612 : @return CE_None if successful, CE_Warning if values are not available in
12613 : metadata and bForce is false, or CE_Failure in case of failure
12614 :
12615 : @since 3.13
12616 :
12617 : @see ComputeInterBandCovarianceMatrix()
12618 : */
12619 :
12620 11 : CPLErr GDALDataset::GetInterBandCovarianceMatrix(
12621 : double *padfCovMatrix, size_t nSize, int nBandCount, const int *panBandList,
12622 : bool bApproxOK, bool bForce, bool bWriteIntoMetadata,
12623 : int nDeltaDegreeOfFreedom, GDALProgressFunc pfnProgress,
12624 : void *pProgressData)
12625 : {
12626 22 : std::vector<int> anBandListTmp; // keep in this scope
12627 11 : if (nBandCount == 0)
12628 : {
12629 0 : if (nBands == 0)
12630 0 : return CE_None;
12631 0 : for (int i = 0; i < nBands; ++i)
12632 0 : anBandListTmp.push_back(i + 1);
12633 0 : nBandCount = nBands;
12634 0 : panBandList = anBandListTmp.data();
12635 : }
12636 : else
12637 : {
12638 11 : if (nBandCount > nBands)
12639 : {
12640 1 : CPLError(CE_Failure, CPLE_AppDefined,
12641 : "GetInterBandCovarianceMatrix(): nBandCount > nBands");
12642 1 : return CE_Failure;
12643 : }
12644 29 : for (int i = 0; i < nBandCount; ++i)
12645 : {
12646 21 : if (panBandList[i] <= 0 || panBandList[i] > nBands)
12647 : {
12648 2 : CPLError(CE_Failure, CPLE_AppDefined,
12649 : "GetInterBandCovarianceMatrix(): invalid value "
12650 : "panBandList[%d] = %d",
12651 2 : i, panBandList[i]);
12652 2 : return CE_Failure;
12653 : }
12654 : }
12655 : }
12656 :
12657 8 : if (nSize < static_cast<uint64_t>(nBandCount) * nBandCount)
12658 : {
12659 0 : CPLError(
12660 : CE_Failure, CPLE_AppDefined,
12661 : "GetInterBandCovarianceMatrix(): too small result matrix provided");
12662 0 : return CE_Failure;
12663 : }
12664 8 : bool bGotFromMD = true;
12665 8 : size_t resIdx = 0;
12666 20 : for (int i = 0; bGotFromMD && i < nBandCount; ++i)
12667 : {
12668 24 : const char *pszCov = papoBands[panBandList[i] - 1]->GetMetadataItem(
12669 12 : "STATISTICS_COVARIANCES");
12670 12 : bGotFromMD = pszCov != nullptr;
12671 12 : if (bGotFromMD)
12672 : {
12673 12 : const CPLStringList aosTokens(CSLTokenizeString2(pszCov, ",", 0));
12674 6 : bGotFromMD = aosTokens.size() == nBands;
12675 6 : if (bGotFromMD)
12676 : {
12677 24 : for (int j = 0; j < nBandCount; ++j)
12678 18 : padfCovMatrix[resIdx++] =
12679 18 : CPLAtof(aosTokens[panBandList[j] - 1]);
12680 : }
12681 : }
12682 : }
12683 8 : if (bGotFromMD)
12684 2 : return CE_None;
12685 :
12686 6 : if (!bForce)
12687 1 : return CE_Warning;
12688 5 : return ComputeInterBandCovarianceMatrix(
12689 : padfCovMatrix, nSize, nBandCount, panBandList, bApproxOK,
12690 5 : bWriteIntoMetadata, nDeltaDegreeOfFreedom, pfnProgress, pProgressData);
12691 : }
12692 :
12693 : /************************************************************************/
12694 : /* GDALDatasetGetInterBandCovarianceMatrix() */
12695 : /************************************************************************/
12696 :
12697 : /**
12698 : \brief Fetch or compute the covariance matrix between bands of this dataset.
12699 :
12700 : The covariance indicates the level to which two bands vary together.
12701 :
12702 : If we call \f$ v_i[y,x] \f$ the value of pixel at row=y and column=x for band i,
12703 : and \f$ mean_i \f$ the mean value of all pixels of band i, then
12704 :
12705 : \f[
12706 : \mathrm{cov}[i,j] =
12707 : \frac{
12708 : \sum_{y,x} \left( v_i[y,x] - \mathrm{mean}_i \right)
12709 : \left( v_j[y,x] - \mathrm{mean}_j \right)
12710 : }{
12711 : \mathrm{pixel\_count} - \mathrm{nDeltaDegreeOfFreedom}
12712 : }
12713 : \f]
12714 :
12715 : When there are no nodata values, \f$ pixel\_count = GetRasterXSize() * GetRasterYSize() \f$.
12716 : We can see that \f$ cov[i,j] = cov[j,i] \f$, and consequently the returned matrix
12717 : is symmetric.
12718 :
12719 : A value of nDeltaDegreeOfFreedom=1 (the default) will return a unbiased estimate
12720 : if the pixels in bands are considered to be a sample of the whole population.
12721 : This is consistent with the default of
12722 : https://numpy.org/doc/stable/reference/generated/numpy.cov.html and the returned
12723 : matrix is consistent with what can be obtained with
12724 :
12725 : \verbatim embed:rst
12726 : .. code-block:: python
12727 :
12728 : numpy.cov(
12729 : [ds.GetRasterBand(n + 1).ReadAsArray().ravel() for n in range(ds.RasterCount)]
12730 : )
12731 : \endverbatim
12732 :
12733 : Otherwise a value of nDeltaDegreeOfFreedom=0 can be used if they are considered
12734 : to be the whole population.
12735 :
12736 : The caller must provide an already allocated array in padfCovMatrix of size
12737 : at least nBandCount * nBandCount.
12738 :
12739 : If STATISTICS_COVARIANCES metadata items are available in band metadata,
12740 : this method uses them.
12741 : Otherwise, if bForce is true, GDALDatasetComputeInterBandCovarianceMatrix() is called.
12742 : Otherwise, if bForce is false, an empty vector is returned
12743 :
12744 : This is the same as the C++ method GDALDataset::GetInterBandCovarianceMatrix()
12745 :
12746 : @param hDS Dataset handle.
12747 : @param[out] padfCovMatrix Pointer to an already allocated output array, of size at least
12748 : nBandCount * nBandCount.
12749 : @param nSize Number of elements in output array.
12750 : @param nBandCount Zero for all bands, or number of values in panBandList.
12751 : Defaults to 0.
12752 : @param panBandList nullptr for all bands if nBandCount == 0, or array of
12753 : nBandCount values such as panBandList[i] is the index
12754 : between 1 and GetRasterCount() of a band that must be used
12755 : in the covariance computation. Defaults to nullptr.
12756 : @param bApproxOK Whether it is acceptable to use a subsample of values in
12757 : GDALDatasetComputeInterBandCovarianceMatrix().
12758 : Defaults to false.
12759 : @param bForce Whether GDALDatasetComputeInterBandCovarianceMatrix() should be called
12760 : when the STATISTICS_COVARIANCES metadata items are missing.
12761 : Defaults to false.
12762 : @param bWriteIntoMetadata Whether GDALDatasetComputeInterBandCovarianceMatrix() must
12763 : write STATISTICS_COVARIANCES band metadata items.
12764 : Defaults to true.
12765 : @param nDeltaDegreeOfFreedom Correction term to subtract in the final
12766 : averaging phase of the covariance computation.
12767 : Defaults to 1.
12768 : @param pfnProgress a function to call to report progress, or NULL.
12769 : @param pProgressData application data to pass to the progress function.
12770 :
12771 : @return CE_None if successful, CE_Warning if values are not available in
12772 : metadata and bForce is false, or CE_Failure in case of failure
12773 :
12774 : @since 3.13
12775 :
12776 : @see GDALDatasetComputeInterBandCovarianceMatrix()
12777 : */
12778 11 : CPLErr GDALDatasetGetInterBandCovarianceMatrix(
12779 : GDALDatasetH hDS, double *padfCovMatrix, size_t nSize, int nBandCount,
12780 : const int *panBandList, bool bApproxOK, bool bForce,
12781 : bool bWriteIntoMetadata, int nDeltaDegreeOfFreedom,
12782 : GDALProgressFunc pfnProgress, void *pProgressData)
12783 : {
12784 11 : VALIDATE_POINTER1(hDS, __func__, CE_Failure);
12785 11 : VALIDATE_POINTER1(padfCovMatrix, __func__, CE_Failure);
12786 11 : return GDALDataset::FromHandle(hDS)->GetInterBandCovarianceMatrix(
12787 : padfCovMatrix, nSize, nBandCount, panBandList, bApproxOK, bForce,
12788 11 : bWriteIntoMetadata, nDeltaDegreeOfFreedom, pfnProgress, pProgressData);
12789 : }
12790 :
12791 : /************************************************************************/
12792 : /* GDALDataset::ComputeInterBandCovarianceMatrix() */
12793 : /************************************************************************/
12794 :
12795 : /**
12796 : \brief Compute the covariance matrix between bands of this dataset.
12797 :
12798 : The covariance indicates the level to which two bands vary together.
12799 :
12800 : If we call \f$ v_i[y,x] \f$ the value of pixel at row=y and column=x for band i,
12801 : and \f$ mean_i \f$ the mean value of all pixels of band i, then
12802 :
12803 : \f[
12804 : \mathrm{cov}[i,j] =
12805 : \frac{
12806 : \sum_{y,x} \left( v_i[y,x] - \mathrm{mean}_i \right)
12807 : \left( v_j[y,x] - \mathrm{mean}_j \right)
12808 : }{
12809 : \mathrm{pixel\_count} - \mathrm{nDeltaDegreeOfFreedom}
12810 : }
12811 : \f]
12812 :
12813 : When there are no nodata values, \f$ pixel\_count = GetRasterXSize() * GetRasterYSize() \f$.
12814 : We can see that \f$ cov[i,j] = cov[j,i] \f$, and consequently the returned matrix
12815 : is symmetric.
12816 :
12817 : A value of nDeltaDegreeOfFreedom=1 (the default) will return a unbiased estimate
12818 : if the pixels in bands are considered to be a sample of the whole population.
12819 : This is consistent with the default of
12820 : https://numpy.org/doc/stable/reference/generated/numpy.cov.html and the returned
12821 : matrix is consistent with what can be obtained with
12822 :
12823 : \verbatim embed:rst
12824 : .. code-block:: python
12825 :
12826 : numpy.cov(
12827 : [ds.GetRasterBand(n + 1).ReadAsArray().ravel() for n in range(ds.RasterCount)]
12828 : )
12829 : \endverbatim
12830 :
12831 : Otherwise a value of nDeltaDegreeOfFreedom=0 can be used if they are considered
12832 : to be the whole population.
12833 :
12834 : This method recomputes the covariance matrix, even if STATISTICS_COVARIANCES
12835 : metadata items are available in bands. See GetInterBandCovarianceMatrix()
12836 : to use them.
12837 :
12838 : @param nBandCount Zero for all bands, or number of values in panBandList.
12839 : Defaults to 0.
12840 : @param panBandList nullptr for all bands if nBandCount == 0, or array of
12841 : nBandCount values such as panBandList[i] is the index
12842 : between 1 and GetRasterCount() of a band that must be used
12843 : in the covariance computation. Defaults to nullptr.
12844 : @param bApproxOK Whether it is acceptable to use a subsample of values.
12845 : Defaults to false.
12846 : @param bWriteIntoMetadata Whether this method must write
12847 : STATISTICS_COVARIANCES band metadata items.
12848 : Defaults to true.
12849 : @param nDeltaDegreeOfFreedom Correction term to subtract in the final
12850 : averaging phase of the covariance computation.
12851 : Defaults to 1.
12852 : @param pfnProgress a function to call to report progress, or NULL.
12853 : @param pProgressData application data to pass to the progress function.
12854 :
12855 : @return a vector of nBandCount * nBandCount values if successful,
12856 : in row-major order, or an empty vector in case of failure
12857 :
12858 : @since 3.13
12859 :
12860 : @see GetInterBandCovarianceMatrix()
12861 : */
12862 0 : std::vector<double> GDALDataset::ComputeInterBandCovarianceMatrix(
12863 : int nBandCount, const int *panBandList, bool bApproxOK,
12864 : bool bWriteIntoMetadata, int nDeltaDegreeOfFreedom,
12865 : GDALProgressFunc pfnProgress, void *pProgressData)
12866 : {
12867 0 : std::vector<double> res;
12868 0 : const int nBandCountToUse = nBandCount == 0 ? nBands : nBandCount;
12869 0 : if (nBandCountToUse == 0)
12870 0 : return res;
12871 : if constexpr (sizeof(size_t) < sizeof(uint64_t))
12872 : {
12873 : // Check that nBandCountToUse * nBandCountToUse will not overflow size_t
12874 : if (static_cast<uint32_t>(nBandCountToUse) >
12875 : std::numeric_limits<uint16_t>::max())
12876 : {
12877 : CPLError(CE_Failure, CPLE_OutOfMemory,
12878 : "Not enough memory to store result");
12879 : return res;
12880 : }
12881 : }
12882 : try
12883 : {
12884 0 : res.resize(static_cast<size_t>(nBandCountToUse) * nBandCountToUse);
12885 : }
12886 0 : catch (const std::exception &)
12887 : {
12888 0 : CPLError(CE_Failure, CPLE_OutOfMemory,
12889 : "Not enough memory to store result");
12890 0 : return res;
12891 : }
12892 :
12893 0 : if (ComputeInterBandCovarianceMatrix(
12894 : res.data(), res.size(), nBandCount, panBandList, bApproxOK,
12895 : bWriteIntoMetadata, nDeltaDegreeOfFreedom, pfnProgress,
12896 0 : pProgressData) != CE_None)
12897 0 : res.clear();
12898 0 : return res;
12899 : }
12900 :
12901 : /************************************************************************/
12902 : /* ComputeInterBandCovarianceMatrixInternal() */
12903 : /************************************************************************/
12904 :
12905 : template <class T>
12906 : // CPL_NOSANITIZE_UNSIGNED_INT_OVERFLOW because it seems the uses of openmp-simd
12907 : // causes that to happen
12908 : CPL_NOSANITIZE_UNSIGNED_INT_OVERFLOW static CPLErr
12909 15 : ComputeInterBandCovarianceMatrixInternal(GDALDataset *poDS,
12910 : double *padfCovMatrix, int nBandCount,
12911 : const int *panBandList,
12912 : GDALRasterBand *const *papoBands,
12913 : int nDeltaDegreeOfFreedom,
12914 : GDALProgressFunc pfnProgress,
12915 : void *pProgressData)
12916 : {
12917 : // We use the padfCovMatrix to accumulate co-moments
12918 : // Dimension = nBandCount * nBandCount
12919 15 : double *const padfComomentMatrix = padfCovMatrix;
12920 :
12921 : // Matrix of nBandCount * nBandCount storing co-moments, in optimized
12922 : // case when the block has no nodata value
12923 : // Only used if T != double
12924 30 : [[maybe_unused]] std::vector<T> aCurBlockComomentMatrix;
12925 :
12926 : // Count number of valid values in padfComomentMatrix for each (i,j) tuple
12927 : // Updated while iterating over blocks
12928 : // Dimension = nBandCount * nBandCount
12929 30 : std::vector<uint64_t> anCount;
12930 :
12931 : // Mean of bands, for each (i,j) tuple.
12932 : // Updated while iterating over blocks.
12933 : // This is a matrix rather than a vector due to the fact when need to update
12934 : // it in sync with padfComomentMatrix
12935 : // Dimension = nBandCount * nBandCount
12936 30 : std::vector<T> adfMean;
12937 :
12938 : // Number of valid values when computing adfMean, for each (i,j) tuple.
12939 : // Updated while iterating over blocks.
12940 : // This is a matrix rather than a vector due to the fact when need to update
12941 : // it in sync with padfComomentMatrix
12942 : // Dimension = nBandCount * nBandCount
12943 30 : std::vector<uint64_t> anCountMean;
12944 :
12945 : // Mean of values for each band i. Refreshed for each block.
12946 : // Dimension = nBandCount
12947 30 : std::vector<T> adfCurBlockMean;
12948 :
12949 : // Number of values participating to the mean for each band i.
12950 : // Refreshed for each block. Dimension = nBandCount
12951 30 : std::vector<size_t> anCurBlockCount;
12952 :
12953 : // Pixel values for all selected values for the current block
12954 : // Dimension = nBlockXSize * nBlockYSize * nBandCount
12955 30 : std::vector<T> adfCurBlockPixelsAllBands;
12956 :
12957 : // Vector of nodata values for all bands. Dimension = nBandCount
12958 30 : std::vector<T> adfNoData;
12959 :
12960 : // Vector of mask bands for all bands. Dimension = nBandCount
12961 30 : std::vector<GDALRasterBand *> apoMaskBands;
12962 :
12963 : // Vector of vector of mask values. Dimension = nBandCount
12964 30 : std::vector<std::vector<GByte>> aabyCurBlockMask;
12965 :
12966 : // Vector of pointer to vector of mask values. Dimension = nBandCount
12967 30 : std::vector<std::vector<GByte> *> pabyCurBlockMask;
12968 :
12969 15 : int nBlockXSize = 0;
12970 15 : int nBlockYSize = 0;
12971 15 : papoBands[panBandList[0] - 1]->GetBlockSize(&nBlockXSize, &nBlockYSize);
12972 :
12973 30 : if (static_cast<uint64_t>(nBlockXSize) * nBlockYSize >
12974 15 : std::numeric_limits<size_t>::max() / nBandCount)
12975 : {
12976 0 : poDS->ReportError(CE_Failure, CPLE_OutOfMemory,
12977 : "Not enough memory for intermediate computations");
12978 0 : return CE_Failure;
12979 : }
12980 15 : const size_t nPixelsInBlock =
12981 15 : static_cast<size_t>(nBlockXSize) * nBlockYSize;
12982 :
12983 : // Allocate temporary matrices and vectors
12984 15 : const auto nMatrixSize = static_cast<size_t>(nBandCount) * nBandCount;
12985 :
12986 : using MySignedSize_t = std::make_signed_t<size_t>;
12987 15 : const auto kMax =
12988 15 : static_cast<MySignedSize_t>(nBandCount) * (nBandCount + 1) / 2;
12989 30 : std::vector<std::pair<int, int>> anMapLinearIdxToIJ;
12990 : try
12991 : {
12992 15 : anCount.resize(nMatrixSize);
12993 15 : adfMean.resize(nMatrixSize);
12994 15 : anCountMean.resize(nMatrixSize);
12995 :
12996 : if constexpr (!std::is_same_v<T, double>)
12997 : {
12998 : aCurBlockComomentMatrix.resize(nMatrixSize);
12999 : }
13000 :
13001 15 : anMapLinearIdxToIJ.resize(kMax);
13002 :
13003 15 : adfCurBlockPixelsAllBands.resize(nPixelsInBlock * nBandCount);
13004 :
13005 15 : adfCurBlockMean.resize(nBandCount);
13006 15 : anCurBlockCount.resize(nBandCount);
13007 15 : adfNoData.resize(nBandCount);
13008 15 : apoMaskBands.resize(nBandCount);
13009 15 : aabyCurBlockMask.resize(nBandCount);
13010 15 : pabyCurBlockMask.resize(nBandCount);
13011 : }
13012 0 : catch (const std::exception &)
13013 : {
13014 0 : poDS->ReportError(CE_Failure, CPLE_OutOfMemory,
13015 : "Not enough memory for intermediate computations");
13016 0 : return CE_Failure;
13017 : }
13018 :
13019 15 : constexpr T ZERO{0};
13020 15 : std::fill(padfComomentMatrix,
13021 15 : padfComomentMatrix + static_cast<size_t>(nBandCount) * nBandCount,
13022 15 : 0);
13023 :
13024 : {
13025 15 : MySignedSize_t nLinearIdx = 0;
13026 1045 : for (int i = 0; i < nBandCount; ++i)
13027 : {
13028 501581 : for (int j = i; j < nBandCount; ++j)
13029 : {
13030 500551 : anMapLinearIdxToIJ[nLinearIdx] = {i, j};
13031 500551 : ++nLinearIdx;
13032 : }
13033 : }
13034 : }
13035 :
13036 : // Fetch nodata values and mask bands
13037 15 : bool bAllBandsSameMask = false;
13038 15 : bool bIsAllInteger = false;
13039 15 : bool bNoneHasMaskOrNodata = false;
13040 1045 : for (int i = 0; i < nBandCount; ++i)
13041 : {
13042 1030 : const auto poBand = papoBands[panBandList[i] - 1];
13043 2057 : bIsAllInteger = (i == 0 || bIsAllInteger) &&
13044 1027 : GDALDataTypeIsInteger(poBand->GetRasterDataType());
13045 1030 : int bHasNoData = FALSE;
13046 1030 : double dfNoData = poBand->GetNoDataValue(&bHasNoData);
13047 1030 : if (!bHasNoData)
13048 : {
13049 1028 : dfNoData = std::numeric_limits<double>::quiet_NaN();
13050 :
13051 1032 : if (poBand->GetMaskFlags() != GMF_ALL_VALID &&
13052 4 : poBand->GetColorInterpretation() != GCI_AlphaBand)
13053 : {
13054 4 : apoMaskBands[i] = poBand->GetMaskBand();
13055 : try
13056 : {
13057 4 : aabyCurBlockMask[i].resize(nPixelsInBlock);
13058 : }
13059 0 : catch (const std::exception &)
13060 : {
13061 0 : poDS->ReportError(
13062 : CE_Failure, CPLE_OutOfMemory,
13063 : "Not enough memory for intermediate computations");
13064 0 : return CE_Failure;
13065 : }
13066 : // coverity[escape]
13067 4 : pabyCurBlockMask[i] = &aabyCurBlockMask[i];
13068 : }
13069 : }
13070 1030 : adfNoData[i] = static_cast<T>(dfNoData);
13071 1030 : if (i == 0)
13072 15 : bAllBandsSameMask = (apoMaskBands[0] != nullptr);
13073 1015 : else if (bAllBandsSameMask)
13074 2 : bAllBandsSameMask = (apoMaskBands[i] == apoMaskBands[0]);
13075 :
13076 3072 : bNoneHasMaskOrNodata = (i == 0 || bNoneHasMaskOrNodata) &&
13077 3072 : std::isnan(dfNoData) &&
13078 1026 : apoMaskBands[i] == nullptr;
13079 : }
13080 15 : if (bAllBandsSameMask)
13081 : {
13082 2 : for (int i = 1; i < nBandCount; ++i)
13083 : {
13084 1 : apoMaskBands[i] = nullptr;
13085 1 : aabyCurBlockMask[i].clear();
13086 1 : pabyCurBlockMask[i] = pabyCurBlockMask[0];
13087 : }
13088 : }
13089 :
13090 15 : const auto nIterCount =
13091 : static_cast<uint64_t>(
13092 15 : cpl::div_round_up(poDS->GetRasterXSize(), nBlockXSize)) *
13093 15 : cpl::div_round_up(poDS->GetRasterYSize(), nBlockYSize);
13094 15 : uint64_t nCurIter = 0;
13095 :
13096 15 : int nNumThreads = 1;
13097 : #ifdef HAVE_OPENMP
13098 15 : if (nBandCount >= 100)
13099 : {
13100 1 : const int nNumCPUs = CPLGetNumCPUs();
13101 1 : nNumThreads = std::max(1, nNumCPUs / 2);
13102 : const char *pszThreads =
13103 1 : CPLGetConfigOption("GDAL_NUM_THREADS", nullptr);
13104 1 : if (pszThreads && !EQUAL(pszThreads, "ALL_CPUS"))
13105 : {
13106 0 : nNumThreads = std::clamp(atoi(pszThreads), 1, nNumCPUs);
13107 : }
13108 : }
13109 : #endif
13110 :
13111 : #ifdef CAN_DETECT_AVX2_FMA_AT_RUNTIME
13112 30 : const bool bHasAVX2_FMA = CPLHaveRuntimeAVX() &&
13113 30 : __builtin_cpu_supports("avx2") &&
13114 : __builtin_cpu_supports("fma");
13115 : #endif
13116 :
13117 : // Iterate over all blocks
13118 77 : for (const auto &window : papoBands[panBandList[0] - 1]->IterateWindows())
13119 : {
13120 32 : const auto nThisBlockPixelCount =
13121 32 : static_cast<size_t>(window.nXSize) * window.nYSize;
13122 :
13123 : // Extract pixel values and masks
13124 96 : CPLErr eErr = poDS->RasterIO(
13125 32 : GF_Read, window.nXOff, window.nYOff, window.nXSize, window.nYSize,
13126 32 : adfCurBlockPixelsAllBands.data(), window.nXSize, window.nYSize,
13127 : gdal::CXXTypeTraits<T>::gdal_type, nBandCount, panBandList, 0, 0, 0,
13128 : nullptr);
13129 32 : if (eErr == CE_None && bAllBandsSameMask)
13130 : {
13131 2 : eErr = apoMaskBands[0]->RasterIO(
13132 1 : GF_Read, window.nXOff, window.nYOff, window.nXSize,
13133 1 : window.nYSize, aabyCurBlockMask[0].data(), window.nXSize,
13134 1 : window.nYSize, GDT_Byte, 0, 0, nullptr);
13135 : }
13136 : else
13137 : {
13138 1108 : for (int i = 0; eErr == CE_None && i < nBandCount; ++i)
13139 : {
13140 1077 : if (apoMaskBands[i])
13141 : {
13142 4 : eErr = apoMaskBands[i]->RasterIO(
13143 2 : GF_Read, window.nXOff, window.nYOff, window.nXSize,
13144 2 : window.nYSize, aabyCurBlockMask[i].data(),
13145 2 : window.nXSize, window.nYSize, GDT_Byte, 0, 0, nullptr);
13146 : }
13147 : }
13148 : }
13149 32 : if (eErr != CE_None)
13150 1 : return eErr;
13151 :
13152 : // Compute the mean of all bands for this block
13153 32 : bool bAllBandsAreAllNodata = false;
13154 32 : bool bNoBandHasNodata = false;
13155 1111 : for (int i = 0; i < nBandCount; ++i)
13156 : {
13157 1079 : T dfSum = 0;
13158 1079 : size_t nCount = 0;
13159 1079 : const T dfNoDataI = adfNoData[i];
13160 1079 : const T *padfI =
13161 1079 : adfCurBlockPixelsAllBands.data() + i * nThisBlockPixelCount;
13162 : #ifdef HAVE_OPENMP_SIMD
13163 1079 : #pragma omp simd reduction(+ : dfSum)
13164 : #endif
13165 : for (size_t iPixel = 0; iPixel < nThisBlockPixelCount; ++iPixel)
13166 : {
13167 822482 : const T dfI = padfI[iPixel];
13168 822482 : const bool bIsValid =
13169 1644950 : !std::isnan(dfI) && dfI != dfNoDataI &&
13170 822466 : (!pabyCurBlockMask[i] || (*pabyCurBlockMask[i])[iPixel]);
13171 822482 : nCount += bIsValid;
13172 822482 : dfSum += bIsValid ? dfI : ZERO;
13173 : }
13174 1079 : adfCurBlockMean[i] = nCount > 0 ? dfSum / nCount : ZERO;
13175 1079 : anCurBlockCount[i] = nCount;
13176 1079 : bAllBandsAreAllNodata =
13177 1079 : (i == 0 || bAllBandsAreAllNodata) && (nCount == 0);
13178 1079 : bNoBandHasNodata = (i == 0 || bNoBandHasNodata) &&
13179 : (nCount == nThisBlockPixelCount);
13180 : }
13181 :
13182 : // Modify the pixel values to shift them by minus the mean
13183 32 : if (!bAllBandsAreAllNodata)
13184 : {
13185 1103 : for (int i = 0; i < nBandCount; ++i)
13186 : {
13187 1074 : T *padfI =
13188 1074 : adfCurBlockPixelsAllBands.data() + i * nThisBlockPixelCount;
13189 1074 : const T dfMeanI = adfCurBlockMean[i];
13190 823546 : for (size_t iPixel = 0; iPixel < nThisBlockPixelCount; ++iPixel)
13191 : {
13192 822472 : padfI[iPixel] -= dfMeanI;
13193 : }
13194 : }
13195 : }
13196 :
13197 : // Update padfComomentMatrix, anCount, adfMean, anCountMean
13198 : // from dfComoment, nCount, adfCurBlockMean, anCurBlockCount
13199 32 : const auto UpdateGlobalValues =
13200 13507600 : [&anCount, &adfMean, &anCountMean, &adfCurBlockMean,
13201 : &anCurBlockCount, padfComomentMatrix,
13202 : nBandCount](int i, int j, size_t nCount, T dfComoment)
13203 : {
13204 500647 : const auto idxInMatrixI = static_cast<size_t>(i) * nBandCount + j;
13205 500647 : const auto idxInMatrixJ = static_cast<size_t>(j) * nBandCount + i;
13206 :
13207 : // Update the total comoment using last formula of paragraph
13208 : // https://en.wikipedia.org/wiki/Algorithms_for_calculating_variance#Online :
13209 : // CoMoment(A+B) = CoMoment(A) + CoMoment(B) +
13210 : // (mean_I(A) - mean_I(B)) *
13211 : // (mean_J(A) - mean_J(B)) *
13212 : // (count(A) * count(B)) / (count(A) + count(B))
13213 : //
13214 : // There might be a small gotcha in the fact that the set of
13215 : // pixels on which the means are computed is not always the
13216 : // same as the the one on which the comoment is computed, if
13217 : // pixels are not valid/invalid at the same indices among bands
13218 : // It is not obvious (to me) what should be the correct behavior.
13219 : // The current approach has the benefit to avoid recomputing
13220 : // the mean for each (i,j) tuple, but only for all i.
13221 500647 : if (nCount > 0)
13222 : {
13223 500639 : padfComomentMatrix[idxInMatrixI] +=
13224 : static_cast<double>(dfComoment);
13225 500639 : padfComomentMatrix[idxInMatrixI] +=
13226 500639 : static_cast<double>(adfMean[idxInMatrixI] -
13227 500639 : adfCurBlockMean[i]) *
13228 500639 : static_cast<double>(adfMean[idxInMatrixJ] -
13229 500639 : adfCurBlockMean[j]) *
13230 500639 : (static_cast<double>(anCount[idxInMatrixI]) *
13231 500639 : static_cast<double>(nCount) /
13232 500639 : static_cast<double>(anCount[idxInMatrixI] + nCount));
13233 :
13234 500639 : anCount[idxInMatrixI] += nCount;
13235 : }
13236 :
13237 : // Update means
13238 500647 : if (anCurBlockCount[i] > 0)
13239 : {
13240 1001280 : adfMean[idxInMatrixI] +=
13241 500640 : (adfCurBlockMean[i] - adfMean[idxInMatrixI]) *
13242 : static_cast<T>(
13243 500640 : static_cast<double>(anCurBlockCount[i]) /
13244 500640 : static_cast<double>(anCountMean[idxInMatrixI] +
13245 : anCurBlockCount[i]));
13246 :
13247 500640 : anCountMean[idxInMatrixI] += anCurBlockCount[i];
13248 : }
13249 :
13250 500647 : if (idxInMatrixI != idxInMatrixJ && anCurBlockCount[j] > 0)
13251 : {
13252 999132 : adfMean[idxInMatrixJ] +=
13253 499566 : (adfCurBlockMean[j] - adfMean[idxInMatrixJ]) *
13254 : static_cast<T>(
13255 499566 : static_cast<double>(anCurBlockCount[j]) /
13256 499566 : static_cast<double>(anCountMean[idxInMatrixJ] +
13257 : anCurBlockCount[j]));
13258 :
13259 499566 : anCountMean[idxInMatrixJ] += anCurBlockCount[j];
13260 : }
13261 : };
13262 :
13263 32 : if (bAllBandsAreAllNodata)
13264 : {
13265 : // Optimized code path where all values in the current block
13266 : // are invalid
13267 :
13268 8 : for (int i = 0; i < nBandCount; ++i)
13269 : {
13270 12 : for (int j = i; j < nBandCount; ++j)
13271 : {
13272 7 : UpdateGlobalValues(i, j, 0, ZERO);
13273 : }
13274 : }
13275 : }
13276 29 : else if (bNoBandHasNodata)
13277 : {
13278 : // Optimized code path where there are no invalid value in the
13279 : // current block
13280 :
13281 : if constexpr (!std::is_same_v<T, double>)
13282 : {
13283 : std::fill(aCurBlockComomentMatrix.begin(),
13284 : aCurBlockComomentMatrix.end(), ZERO);
13285 :
13286 : GDALMatrixMultiplyAByTransposeAUpperTriangle(
13287 : nNumThreads, adfCurBlockPixelsAllBands.data(),
13288 : aCurBlockComomentMatrix.data(), nBandCount,
13289 : nThisBlockPixelCount);
13290 : }
13291 : #ifdef CAN_DETECT_AVX2_FMA_AT_RUNTIME
13292 24 : else if (bHasAVX2_FMA)
13293 : {
13294 24 : GDALMatrixMultiplyAByTransposeAUpperTriangle_AVX2_FMA(
13295 : nNumThreads, adfCurBlockPixelsAllBands.data(),
13296 : padfComomentMatrix, nBandCount, nThisBlockPixelCount);
13297 : }
13298 : #endif
13299 : else
13300 : {
13301 0 : GDALMatrixMultiplyAByTransposeAUpperTriangle(
13302 : nNumThreads, adfCurBlockPixelsAllBands.data(),
13303 : padfComomentMatrix, nBandCount, nThisBlockPixelCount);
13304 : }
13305 :
13306 1088 : for (int i = 0; i < nBandCount; ++i)
13307 : {
13308 501689 : for (int j = i; j < nBandCount; ++j)
13309 : {
13310 : if constexpr (!std::is_same_v<T, double>)
13311 : {
13312 : const auto idxInMatrixI =
13313 : static_cast<size_t>(i) * nBandCount + j;
13314 : UpdateGlobalValues(
13315 : i, j, nThisBlockPixelCount,
13316 : aCurBlockComomentMatrix[idxInMatrixI]);
13317 : }
13318 : else
13319 : {
13320 500625 : UpdateGlobalValues(i, j, nThisBlockPixelCount, ZERO);
13321 : }
13322 : }
13323 : }
13324 : }
13325 : else
13326 : {
13327 : #ifdef HAVE_OPENMP
13328 5 : #pragma omp parallel for schedule(static) num_threads(nNumThreads)
13329 : #endif
13330 : for (MySignedSize_t k = 0; k < kMax; ++k)
13331 : {
13332 : int i, j;
13333 : std::tie(i, j) = anMapLinearIdxToIJ[k];
13334 :
13335 : // Now compute the moment of (i, j), but just for this block
13336 : size_t nCount = 0;
13337 : T dfComoment = 0;
13338 : const T *padfI =
13339 : adfCurBlockPixelsAllBands.data() + i * nThisBlockPixelCount;
13340 : const T *padfJ =
13341 : adfCurBlockPixelsAllBands.data() + j * nThisBlockPixelCount;
13342 :
13343 : // Use https://en.wikipedia.org/wiki/Algorithms_for_calculating_variance#Two-pass
13344 : // for the current block
13345 : if ((anCurBlockCount[i] == nThisBlockPixelCount &&
13346 : anCurBlockCount[j] == nThisBlockPixelCount) ||
13347 : (bNoneHasMaskOrNodata && bIsAllInteger))
13348 : {
13349 : // Most optimized code path: integer, no nodata, no mask
13350 : #ifdef HAVE_OPENMP_SIMD
13351 : #pragma omp simd reduction(+ : dfComoment)
13352 : #endif
13353 : for (size_t iPixel = 0; iPixel < nThisBlockPixelCount;
13354 : ++iPixel)
13355 : {
13356 : dfComoment += padfI[iPixel] * padfJ[iPixel];
13357 : }
13358 : nCount = nThisBlockPixelCount;
13359 : }
13360 : else if (bNoneHasMaskOrNodata)
13361 : {
13362 : // Floating-point code path with no nodata and no mask
13363 : #ifdef HAVE_OPENMP_SIMD
13364 : #pragma omp simd reduction(+ : dfComoment)
13365 : #endif
13366 : for (size_t iPixel = 0; iPixel < nThisBlockPixelCount;
13367 : ++iPixel)
13368 : {
13369 : const T dfAcc = padfI[iPixel] * padfJ[iPixel];
13370 : const bool bIsValid = !std::isnan(dfAcc);
13371 : nCount += bIsValid;
13372 : dfComoment += bIsValid ? dfAcc : ZERO;
13373 : }
13374 : }
13375 : else if (!std::isnan(adfNoData[i]) && !std::isnan(adfNoData[j]))
13376 : {
13377 : // Code path when there are both nodata values
13378 : const T shiftedNoDataI = adfNoData[i] - adfCurBlockMean[i];
13379 : const T shiftedNoDataJ = adfNoData[j] - adfCurBlockMean[j];
13380 :
13381 : #ifdef HAVE_OPENMP_SIMD
13382 : #pragma omp simd reduction(+ : dfComoment)
13383 : #endif
13384 : for (size_t iPixel = 0; iPixel < nThisBlockPixelCount;
13385 : ++iPixel)
13386 : {
13387 : const T dfI = padfI[iPixel];
13388 : const T dfJ = padfJ[iPixel];
13389 : const T dfAcc = dfI * dfJ;
13390 : const bool bIsValid = !std::isnan(dfAcc) &&
13391 : dfI != shiftedNoDataI &&
13392 : dfJ != shiftedNoDataJ;
13393 : nCount += bIsValid;
13394 : dfComoment += bIsValid ? dfAcc : ZERO;
13395 : }
13396 : }
13397 : else
13398 : {
13399 : // Generic code path
13400 : const T shiftedNoDataI = adfNoData[i] - adfCurBlockMean[i];
13401 : const T shiftedNoDataJ = adfNoData[j] - adfCurBlockMean[j];
13402 :
13403 : #ifdef HAVE_OPENMP_SIMD
13404 : #pragma omp simd reduction(+ : dfComoment)
13405 : #endif
13406 : for (size_t iPixel = 0; iPixel < nThisBlockPixelCount;
13407 : ++iPixel)
13408 : {
13409 : const T dfI = padfI[iPixel];
13410 : const T dfJ = padfJ[iPixel];
13411 : const T dfAcc = dfI * dfJ;
13412 : const bool bIsValid =
13413 : !std::isnan(dfAcc) && dfI != shiftedNoDataI &&
13414 : dfJ != shiftedNoDataJ &&
13415 : (!pabyCurBlockMask[i] ||
13416 : (*pabyCurBlockMask[i])[iPixel]) &&
13417 : (!pabyCurBlockMask[j] ||
13418 : (*pabyCurBlockMask[j])[iPixel]);
13419 : nCount += bIsValid;
13420 : dfComoment += bIsValid ? dfAcc : ZERO;
13421 : }
13422 : }
13423 :
13424 : UpdateGlobalValues(i, j, nCount, dfComoment);
13425 : }
13426 : }
13427 :
13428 32 : ++nCurIter;
13429 35 : if (pfnProgress &&
13430 3 : !pfnProgress(static_cast<double>(nCurIter) / nIterCount, "",
13431 : pProgressData))
13432 : {
13433 1 : poDS->ReportError(CE_Failure, CPLE_UserInterrupt,
13434 : "User terminated");
13435 1 : return CE_Failure;
13436 : }
13437 : }
13438 :
13439 : // Finalize by dividing co-moments by the number of contributing values
13440 : // (minus nDeltaDegreeOfFreedom) to compute final covariances.
13441 44 : for (int i = 0; i < nBandCount; ++i)
13442 : {
13443 : // The covariance matrix is symmetric. So start at i
13444 81 : for (int j = i; j < nBandCount; ++j)
13445 : {
13446 51 : const auto idxInMatrixI = static_cast<size_t>(i) * nBandCount + j;
13447 51 : const double dfCovariance =
13448 51 : (nDeltaDegreeOfFreedom < 0 ||
13449 51 : anCount[idxInMatrixI] <=
13450 51 : static_cast<uint64_t>(nDeltaDegreeOfFreedom))
13451 4 : ? std::numeric_limits<double>::quiet_NaN()
13452 94 : : padfComomentMatrix[idxInMatrixI] /
13453 47 : static_cast<double>(anCount[idxInMatrixI] -
13454 47 : nDeltaDegreeOfFreedom);
13455 :
13456 51 : padfCovMatrix[idxInMatrixI] = dfCovariance;
13457 : // Fill lower triangle
13458 51 : padfCovMatrix[static_cast<size_t>(j) * nBandCount + i] =
13459 : dfCovariance;
13460 : }
13461 : }
13462 :
13463 14 : return CE_None;
13464 : }
13465 :
13466 : /************************************************************************/
13467 : /* GDALDataset::ComputeInterBandCovarianceMatrix() */
13468 : /************************************************************************/
13469 :
13470 : /**
13471 : \brief Compute the covariance matrix between bands of this dataset.
13472 :
13473 : The covariance indicates the level to which two bands vary together.
13474 :
13475 : If we call \f$ v_i[y,x] \f$ the value of pixel at row=y and column=x for band i,
13476 : and \f$ mean_i \f$ the mean value of all pixels of band i, then
13477 :
13478 : \f[
13479 : \mathrm{cov}[i,j] =
13480 : \frac{
13481 : \sum_{y,x} \left( v_i[y,x] - \mathrm{mean}_i \right)
13482 : \left( v_j[y,x] - \mathrm{mean}_j \right)
13483 : }{
13484 : \mathrm{pixel\_count} - \mathrm{nDeltaDegreeOfFreedom}
13485 : }
13486 : \f]
13487 :
13488 : When there are no nodata values, \f$ pixel\_count = GetRasterXSize() * GetRasterYSize() \f$.
13489 : We can see that \f$ cov[i,j] = cov[j,i] \f$, and consequently the returned matrix
13490 : is symmetric.
13491 :
13492 : A value of nDeltaDegreeOfFreedom=1 (the default) will return a unbiased estimate
13493 : if the pixels in bands are considered to be a sample of the whole population.
13494 : This is consistent with the default of
13495 : https://numpy.org/doc/stable/reference/generated/numpy.cov.html and the returned
13496 : matrix is consistent with what can be obtained with
13497 :
13498 : \verbatim embed:rst
13499 : .. code-block:: python
13500 :
13501 : numpy.cov(
13502 : [ds.GetRasterBand(n + 1).ReadAsArray().ravel() for n in range(ds.RasterCount)]
13503 : )
13504 : \endverbatim
13505 :
13506 : Otherwise a value of nDeltaDegreeOfFreedom=0 can be used if they are considered
13507 : to be the whole population.
13508 :
13509 : The caller must provide an already allocated array in padfCovMatrix of size
13510 : at least nBandCount * nBandCount.
13511 :
13512 : This method recomputes the covariance matrix, even if STATISTICS_COVARIANCES
13513 : metadata items are available in bands. See GetInterBandCovarianceMatrix()
13514 : to use them.
13515 :
13516 : The implementation is optimized to minimize the amount of pixel reading.
13517 :
13518 : This method is the same as the C function GDALDatasetComputeInterBandCovarianceMatrix()
13519 :
13520 : @param[out] padfCovMatrix Pointer to an already allocated output array, of size at least
13521 : nBandCount * nBandCount.
13522 : @param nSize Number of elements in output array.
13523 : @param nBandCount Zero for all bands, or number of values in panBandList.
13524 : Defaults to 0.
13525 : @param panBandList nullptr for all bands if nBandCount == 0, or array of
13526 : nBandCount values such as panBandList[i] is the index
13527 : between 1 and GetRasterCount() of a band that must be used
13528 : in the covariance computation. Defaults to nullptr.
13529 : @param bApproxOK Whether it is acceptable to use a subsample of values.
13530 : Defaults to false.
13531 : @param bWriteIntoMetadata Whether this method must write
13532 : STATISTICS_COVARIANCES band metadata items.
13533 : Defaults to true.
13534 : @param nDeltaDegreeOfFreedom Correction term to subtract in the final
13535 : averaging phase of the covariance computation.
13536 : Defaults to 1.
13537 : @param pfnProgress a function to call to report progress, or NULL.
13538 : @param pProgressData application data to pass to the progress function.
13539 :
13540 : @return CE_None if successful, or CE_Failure in case of failure
13541 :
13542 : @since 3.13
13543 :
13544 : @see GetInterBandCovarianceMatrix()
13545 : */
13546 22 : CPLErr GDALDataset::ComputeInterBandCovarianceMatrix(
13547 : double *padfCovMatrix, size_t nSize, int nBandCount, const int *panBandList,
13548 : bool bApproxOK, bool bWriteIntoMetadata, int nDeltaDegreeOfFreedom,
13549 : GDALProgressFunc pfnProgress, void *pProgressData)
13550 : {
13551 44 : std::vector<int> anBandListTmp; // keep in this scope
13552 22 : if (nBandCount == 0)
13553 : {
13554 0 : if (nBands == 0)
13555 0 : return CE_None;
13556 0 : for (int i = 0; i < nBands; ++i)
13557 0 : anBandListTmp.push_back(i + 1);
13558 0 : nBandCount = nBands;
13559 0 : panBandList = anBandListTmp.data();
13560 : }
13561 : else
13562 : {
13563 22 : if (nBandCount > nBands)
13564 : {
13565 1 : CPLError(CE_Failure, CPLE_AppDefined,
13566 : "ComputeInterBandCovarianceMatrix(): nBandCount > nBands");
13567 1 : return CE_Failure;
13568 : }
13569 1057 : for (int i = 0; i < nBandCount; ++i)
13570 : {
13571 1038 : if (panBandList[i] <= 0 || panBandList[i] > nBands)
13572 : {
13573 2 : CPLError(CE_Failure, CPLE_AppDefined,
13574 : "ComputeInterBandCovarianceMatrix(): invalid value "
13575 : "panBandList[%d] = %d",
13576 2 : i, panBandList[i]);
13577 2 : return CE_Failure;
13578 : }
13579 : }
13580 :
13581 19 : if (bWriteIntoMetadata)
13582 : {
13583 14 : bool bOK = nBandCount == nBands;
13584 38 : for (int i = 0; bOK && i < nBandCount; ++i)
13585 : {
13586 24 : bOK = (panBandList[i] == i + 1);
13587 : }
13588 14 : if (!bOK)
13589 : {
13590 4 : CPLError(CE_Failure, CPLE_AppDefined,
13591 : "ComputeInterBandCovarianceMatrix(): cannot write "
13592 : "STATISTICS_COVARIANCES metadata since the input band "
13593 : "list is not [1, 2, ... GetRasterCount()]");
13594 4 : return CE_Failure;
13595 : }
13596 : }
13597 : }
13598 :
13599 15 : const auto nMatrixSize = static_cast<size_t>(nBandCount) * nBandCount;
13600 15 : if (nSize < nMatrixSize)
13601 : {
13602 0 : CPLError(CE_Failure, CPLE_AppDefined,
13603 : "ComputeInterBandCovarianceMatrix(): too small result matrix "
13604 : "provided");
13605 0 : return CE_Failure;
13606 : }
13607 :
13608 : // Find appropriate overview dataset
13609 15 : GDALDataset *poActiveDS = this;
13610 15 : if (bApproxOK && papoBands[panBandList[0] - 1]->GetOverviewCount() > 0)
13611 : {
13612 1 : GDALDataset *poOvrDS = nullptr;
13613 4 : for (int i = 0; i < nBandCount; ++i)
13614 : {
13615 3 : const int nIdxBand = panBandList[i] - 1;
13616 6 : auto poOvrBand = papoBands[nIdxBand]->GetRasterSampleOverview(
13617 3 : GDALSTAT_APPROX_NUMSAMPLES);
13618 :
13619 6 : if (poOvrBand == papoBands[i] ||
13620 3 : poOvrBand->GetBand() != panBandList[i])
13621 : {
13622 0 : poOvrDS = nullptr;
13623 0 : break;
13624 : }
13625 3 : else if (i == 0)
13626 : {
13627 1 : if (poOvrBand->GetDataset() == this)
13628 : {
13629 0 : break;
13630 : }
13631 1 : poOvrDS = poOvrBand->GetDataset();
13632 : }
13633 2 : else if (poOvrBand->GetDataset() != poOvrDS)
13634 : {
13635 0 : poOvrDS = nullptr;
13636 0 : break;
13637 : }
13638 : }
13639 1 : if (poOvrDS)
13640 : {
13641 1 : poActiveDS = poOvrDS;
13642 : }
13643 : }
13644 :
13645 : #ifdef GDAL_COVARIANCE_CAN_USE_FLOAT32
13646 : const auto UseFloat32 = [](GDALDataType eDT)
13647 : {
13648 : return eDT == GDT_UInt8 || eDT == GDT_Int8 || eDT == GDT_UInt16 ||
13649 : eDT == GDT_Int16 || eDT == GDT_Float32;
13650 : };
13651 :
13652 : bool bUseFloat32 = UseFloat32(
13653 : poActiveDS->GetRasterBand(panBandList[0])->GetRasterDataType());
13654 : for (int i = 1; bUseFloat32 && i < nBandCount; ++i)
13655 : {
13656 : bUseFloat32 = UseFloat32(
13657 : poActiveDS->GetRasterBand(panBandList[i])->GetRasterDataType());
13658 : }
13659 : #endif
13660 :
13661 : CPLErr eErr =
13662 : #ifdef GDAL_COVARIANCE_CAN_USE_FLOAT32
13663 : bUseFloat32 ? ComputeInterBandCovarianceMatrixInternal<float>(
13664 : poActiveDS, padfCovMatrix, nBandCount, panBandList,
13665 : poActiveDS->papoBands, nDeltaDegreeOfFreedom,
13666 : pfnProgress, pProgressData)
13667 : :
13668 : #endif
13669 30 : ComputeInterBandCovarianceMatrixInternal<double>(
13670 : poActiveDS, padfCovMatrix, nBandCount, panBandList,
13671 15 : poActiveDS->papoBands, nDeltaDegreeOfFreedom,
13672 : pfnProgress, pProgressData);
13673 :
13674 15 : if (bWriteIntoMetadata && eErr == CE_None)
13675 : {
13676 10 : CPLAssert(nBands == nBandCount);
13677 20 : std::string osStr;
13678 10 : size_t idx = 0;
13679 32 : for (int i = 0; i < nBands; ++i)
13680 : {
13681 22 : osStr.clear();
13682 74 : for (int j = 0; j < nBands; ++j, ++idx)
13683 : {
13684 52 : if (j > 0)
13685 30 : osStr += ',';
13686 52 : osStr += CPLSPrintf("%.17g", padfCovMatrix[idx]);
13687 : }
13688 22 : papoBands[i]->SetMetadataItem("STATISTICS_COVARIANCES",
13689 22 : osStr.c_str());
13690 : }
13691 : }
13692 :
13693 15 : return eErr;
13694 : }
13695 :
13696 : /************************************************************************/
13697 : /* GDALDatasetComputeInterBandCovarianceMatrix() */
13698 : /************************************************************************/
13699 :
13700 : /**
13701 : \brief Compute the covariance matrix between bands of this dataset.
13702 :
13703 : The covariance indicates the level to which two bands vary together.
13704 :
13705 : If we call \f$ v_i[y,x] \f$ the value of pixel at row=y and column=x for band i,
13706 : and \f$ mean_i \f$ the mean value of all pixels of band i, then
13707 :
13708 : \f[
13709 : \mathrm{cov}[i,j] =
13710 : \frac{
13711 : \sum_{y,x} \left( v_i[y,x] - \mathrm{mean}_i \right)
13712 : \left( v_j[y,x] - \mathrm{mean}_j \right)
13713 : }{
13714 : \mathrm{pixel\_count} - \mathrm{nDeltaDegreeOfFreedom}
13715 : }
13716 : \f]
13717 :
13718 : When there are no nodata values, \f$ pixel\_count = GetRasterXSize() * GetRasterYSize() \f$.
13719 : We can see that \f$ cov[i,j] = cov[j,i] \f$, and consequently the returned matrix
13720 : is symmetric.
13721 :
13722 : A value of nDeltaDegreeOfFreedom=1 (the default) will return a unbiased estimate
13723 : if the pixels in bands are considered to be a sample of the whole population.
13724 : This is consistent with the default of
13725 : https://numpy.org/doc/stable/reference/generated/numpy.cov.html and the returned
13726 : matrix is consistent with what can be obtained with
13727 :
13728 : \verbatim embed:rst
13729 : .. code-block:: python
13730 :
13731 : numpy.cov(
13732 : [ds.GetRasterBand(n + 1).ReadAsArray().ravel() for n in range(ds.RasterCount)]
13733 : )
13734 : \endverbatim
13735 :
13736 : Otherwise a value of nDeltaDegreeOfFreedom=0 can be used if they are considered
13737 : to be the whole population.
13738 :
13739 : The caller must provide an already allocated array in padfCovMatrix of size
13740 : at least GDALGetRasterCount() * GDALGetRasterCount().
13741 :
13742 : This method recomputes the covariance matrix, even if STATISTICS_COVARIANCES
13743 : metadata items are available in bands. See GDALDatasetGetInterBandCovarianceMatrix()
13744 : to use them.
13745 :
13746 : This function is the same as the C++ method GDALDataset::ComputeInterBandCovarianceMatrix()
13747 :
13748 : @param hDS Dataset handle.
13749 : @param[out] padfCovMatrix Pointer to an already allocated output array, of size at least
13750 : nBandCount * nBandCount.
13751 : @param nSize Number of elements in output array.
13752 : @param nBandCount Zero for all bands, or number of values in panBandList.
13753 : Defaults to 0.
13754 : @param panBandList nullptr for all bands if nBandCount == 0, or array of
13755 : nBandCount values such as panBandList[i] is the index
13756 : between 1 and GetRasterCount() of a band that must be used
13757 : in the covariance computation. Defaults to nullptr.
13758 : @param bApproxOK Whether it is acceptable to use a subsample of values.
13759 : Defaults to false.
13760 : @param bWriteIntoMetadata Whether this method must write
13761 : STATISTICS_COVARIANCES band metadata items.
13762 : Defaults to true.
13763 : @param nDeltaDegreeOfFreedom Correction term to subtract in the final
13764 : averaging phase of the covariance computation.
13765 : Defaults to 1.
13766 : @param pfnProgress a function to call to report progress, or NULL.
13767 : @param pProgressData application data to pass to the progress function.
13768 :
13769 : @return CE_None if successful, or CE_Failure in case of failure
13770 :
13771 : @since 3.13
13772 :
13773 : @see GDALDatasetGetInterBandCovarianceMatrix()
13774 : */
13775 17 : CPLErr GDALDatasetComputeInterBandCovarianceMatrix(
13776 : GDALDatasetH hDS, double *padfCovMatrix, size_t nSize, int nBandCount,
13777 : const int *panBandList, bool bApproxOK, bool bWriteIntoMetadata,
13778 : int nDeltaDegreeOfFreedom, GDALProgressFunc pfnProgress,
13779 : void *pProgressData)
13780 : {
13781 17 : VALIDATE_POINTER1(hDS, __func__, CE_Failure);
13782 17 : VALIDATE_POINTER1(padfCovMatrix, __func__, CE_Failure);
13783 17 : return GDALDataset::FromHandle(hDS)->ComputeInterBandCovarianceMatrix(
13784 : padfCovMatrix, nSize, nBandCount, panBandList, bApproxOK,
13785 17 : bWriteIntoMetadata, nDeltaDegreeOfFreedom, pfnProgress, pProgressData);
13786 : }
|