Line data Source code
1 : /******************************************************************************
2 : *
3 : * Project: GDAL Core
4 : * Purpose: Base class for raster file formats.
5 : * Author: Frank Warmerdam, warmerdam@pobox.com
6 : *
7 : ******************************************************************************
8 : * Copyright (c) 1998, 2003, Frank Warmerdam
9 : * Copyright (c) 2008-2013, Even Rouault <even dot rouault at spatialys.com>
10 : *
11 : * SPDX-License-Identifier: MIT
12 : ****************************************************************************/
13 :
14 : #include "cpl_port.h"
15 :
16 : #include <algorithm>
17 : #include <array>
18 : #include <cassert>
19 : #include <climits>
20 : #include <cmath>
21 : #include <cstdarg>
22 : #include <cstdio>
23 : #include <cstdlib>
24 : #include <cstring>
25 : #include <limits>
26 : #include <map>
27 : #include <mutex>
28 : #include <new>
29 : #include <set>
30 : #include <string>
31 : #include <type_traits>
32 : #include <utility>
33 :
34 : #include "cpl_conv.h"
35 : #include "cpl_cpu_features.h"
36 : #include "cpl_error.h"
37 : #include "cpl_hash_set.h"
38 : #include "cpl_multiproc.h"
39 : #include "cpl_progress.h"
40 : #include "cpl_string.h"
41 : #include "cpl_vsi.h"
42 : #include "cpl_vsi_error.h"
43 : #include "cpl_vsi_virtual.h"
44 :
45 : #include "gdal.h"
46 : #include "gdal_alg.h"
47 : #include "gdal_abstractbandblockcache.h"
48 : #include "gdalantirecursion.h"
49 : #include "gdal_dataset.h"
50 : #include "gdal_matrix.hpp"
51 :
52 : #ifdef CAN_DETECT_AVX2_FMA_AT_RUNTIME
53 : #include "gdal_matrix_avx2_fma.h"
54 : #endif
55 :
56 : #include "gdalsubdatasetinfo.h"
57 : #include "gdal_thread_pool.h"
58 : #include "gdal_typetraits.h"
59 :
60 : #include "ogr_api.h"
61 : #include "ogr_attrind.h"
62 : #include "ogr_core.h"
63 : #include "ogr_feature.h"
64 : #include "ogr_featurestyle.h"
65 : #include "ogr_gensql.h"
66 : #include "ogr_geometry.h"
67 : #include "ogr_p.h"
68 : #include "ogr_spatialref.h"
69 : #include "ogr_srs_api.h"
70 : #include "ograpispy.h"
71 : #include "ogrsf_frmts.h"
72 : #include "ogrunionlayer.h"
73 : #include "ogr_swq.h"
74 : #include "memmultidim.h"
75 : #include "gdalmultidim_priv.h"
76 :
77 : #include "../frmts/derived/derivedlist.h"
78 :
79 : #ifdef SQLITE_ENABLED
80 : #include "../sqlite/ogrsqliteexecutesql.h"
81 : #endif
82 :
83 : #ifdef HAVE_OPENMP
84 : #include <omp.h>
85 : #endif
86 :
87 : extern const swq_field_type SpecialFieldTypes[SPECIAL_FIELD_COUNT];
88 :
89 : enum class GDALAllowReadWriteMutexState
90 : {
91 : RW_MUTEX_STATE_UNKNOWN,
92 : RW_MUTEX_STATE_ALLOWED,
93 : RW_MUTEX_STATE_DISABLED
94 : };
95 :
96 : const GIntBig TOTAL_FEATURES_NOT_INIT = -2;
97 : const GIntBig TOTAL_FEATURES_UNKNOWN = -1;
98 :
99 : class GDALDataset::Private
100 : {
101 : CPL_DISALLOW_COPY_ASSIGN(Private)
102 :
103 : public:
104 : CPLMutex *hMutex = nullptr;
105 : std::map<GIntBig, int> oMapThreadToMutexTakenCount{};
106 : #ifdef DEBUG_EXTRA
107 : std::map<GIntBig, int> oMapThreadToMutexTakenCountSaved{};
108 : #endif
109 : GDALAllowReadWriteMutexState eStateReadWriteMutex =
110 : GDALAllowReadWriteMutexState::RW_MUTEX_STATE_UNKNOWN;
111 : int nCurrentLayerIdx = 0;
112 : int nLayerCount = -1;
113 : GIntBig nFeatureReadInLayer = 0;
114 : GIntBig nFeatureReadInDataset = 0;
115 : GIntBig nTotalFeaturesInLayer = TOTAL_FEATURES_NOT_INIT;
116 : GIntBig nTotalFeatures = TOTAL_FEATURES_NOT_INIT;
117 : OGRLayer *poCurrentLayer = nullptr;
118 :
119 : std::mutex m_oMutexWKT{};
120 :
121 : char *m_pszWKTCached = nullptr;
122 : OGRSpatialReference *m_poSRSCached = nullptr;
123 : char *m_pszWKTGCPCached = nullptr;
124 : OGRSpatialReference *m_poSRSGCPCached = nullptr;
125 :
126 : GDALDataset *poParentDataset = nullptr;
127 :
128 : bool m_bOverviewsEnabled = true;
129 :
130 : std::vector<int>
131 : m_anBandMap{}; // used by RasterIO(). Values are 1, 2, etc.
132 :
133 199999 : Private() = default;
134 : };
135 :
136 : struct SharedDatasetCtxt
137 : {
138 : // PID of the thread that mark the dataset as shared
139 : // This may not be the actual PID, but the responsiblePID.
140 : GIntBig nPID;
141 : char *pszDescription;
142 : char *pszConcatenatedOpenOptions;
143 : int nOpenFlags;
144 :
145 : GDALDataset *poDS;
146 : };
147 :
148 : // Set of datasets opened as shared datasets (with GDALOpenShared)
149 : // The values in the set are of type SharedDatasetCtxt.
150 : static CPLHashSet *phSharedDatasetSet = nullptr;
151 :
152 : // Set of all datasets created in the constructor of GDALDataset.
153 : // In the case of a shared dataset, memorize the PID of the thread
154 : // that marked the dataset as shared, so that we can remove it from
155 : // the phSharedDatasetSet in the destructor of the dataset, even
156 : // if GDALClose is called from a different thread.
157 : static std::map<GDALDataset *, GIntBig> *poAllDatasetMap = nullptr;
158 :
159 : static CPLMutex *hDLMutex = nullptr;
160 :
161 : // Static array of all datasets. Used by GDALGetOpenDatasets.
162 : // Not thread-safe. See GDALGetOpenDatasets.
163 : static GDALDataset **ppDatasets = nullptr;
164 :
165 8471 : static unsigned long GDALSharedDatasetHashFunc(const void *elt)
166 : {
167 8471 : const SharedDatasetCtxt *psStruct =
168 : static_cast<const SharedDatasetCtxt *>(elt);
169 : return static_cast<unsigned long>(
170 8471 : CPLHashSetHashStr(psStruct->pszDescription) ^
171 8471 : CPLHashSetHashStr(psStruct->pszConcatenatedOpenOptions) ^
172 8471 : psStruct->nOpenFlags ^ psStruct->nPID);
173 : }
174 :
175 6982 : static int GDALSharedDatasetEqualFunc(const void *elt1, const void *elt2)
176 : {
177 6982 : const SharedDatasetCtxt *psStruct1 =
178 : static_cast<const SharedDatasetCtxt *>(elt1);
179 6982 : const SharedDatasetCtxt *psStruct2 =
180 : static_cast<const SharedDatasetCtxt *>(elt2);
181 13918 : return strcmp(psStruct1->pszDescription, psStruct2->pszDescription) == 0 &&
182 6936 : strcmp(psStruct1->pszConcatenatedOpenOptions,
183 6936 : psStruct2->pszConcatenatedOpenOptions) == 0 &&
184 20854 : psStruct1->nPID == psStruct2->nPID &&
185 13918 : psStruct1->nOpenFlags == psStruct2->nOpenFlags;
186 : }
187 :
188 415 : static void GDALSharedDatasetFreeFunc(void *elt)
189 : {
190 415 : SharedDatasetCtxt *psStruct = static_cast<SharedDatasetCtxt *>(elt);
191 415 : CPLFree(psStruct->pszDescription);
192 415 : CPLFree(psStruct->pszConcatenatedOpenOptions);
193 415 : CPLFree(psStruct);
194 415 : }
195 :
196 : static std::string
197 7082 : GDALSharedDatasetConcatenateOpenOptions(CSLConstList papszOpenOptions)
198 : {
199 7082 : std::string osStr;
200 7095 : for (const char *pszOption : cpl::Iterate(papszOpenOptions))
201 13 : osStr += pszOption;
202 7082 : return osStr;
203 : }
204 :
205 : /************************************************************************/
206 : /* Functions shared between gdalproxypool.cpp and gdaldataset.cpp */
207 : /************************************************************************/
208 :
209 : // The open-shared mutex must be used by the ProxyPool too.
210 485436 : CPLMutex **GDALGetphDLMutex()
211 : {
212 485436 : return &hDLMutex;
213 : }
214 :
215 : // The current thread will act in the behalf of the thread of PID
216 : // responsiblePID.
217 474683 : void GDALSetResponsiblePIDForCurrentThread(GIntBig responsiblePID)
218 : {
219 : GIntBig *pResponsiblePID =
220 474683 : static_cast<GIntBig *>(CPLGetTLS(CTLS_RESPONSIBLEPID));
221 474683 : if (pResponsiblePID == nullptr)
222 : {
223 223 : pResponsiblePID = static_cast<GIntBig *>(CPLMalloc(sizeof(GIntBig)));
224 223 : CPLSetTLS(CTLS_RESPONSIBLEPID, pResponsiblePID, TRUE);
225 : }
226 474683 : *pResponsiblePID = responsiblePID;
227 474683 : }
228 :
229 : // Get the PID of the thread that the current thread will act in the behalf of
230 : // By default : the current thread acts in the behalf of itself.
231 610305 : GIntBig GDALGetResponsiblePIDForCurrentThread()
232 : {
233 : GIntBig *pResponsiblePID =
234 610305 : static_cast<GIntBig *>(CPLGetTLS(CTLS_RESPONSIBLEPID));
235 610305 : if (pResponsiblePID == nullptr)
236 44845 : return CPLGetPID();
237 565460 : return *pResponsiblePID;
238 : }
239 :
240 : /************************************************************************/
241 : /* ==================================================================== */
242 : /* GDALDataset */
243 : /* ==================================================================== */
244 : /************************************************************************/
245 :
246 : /**
247 : * \class GDALDataset "gdal_priv.h"
248 : *
249 : * A dataset encapsulating one or more raster bands. Details are further
250 : * discussed in the <a href="https://gdal.org/user/raster_data_model.html">GDAL
251 : * Raster Data Model</a>.
252 : *
253 : * Use GDALOpen() or GDALOpenShared() to create a GDALDataset for a named file,
254 : * or GDALDriver::Create() or GDALDriver::CreateCopy() to create a new
255 : * dataset.
256 : */
257 :
258 : /************************************************************************/
259 : /* GDALDataset() */
260 : /************************************************************************/
261 :
262 : //! @cond Doxygen_Suppress
263 167533 : GDALDataset::GDALDataset()
264 167533 : : GDALDataset(CPLTestBool(CPLGetConfigOption("GDAL_FORCE_CACHING", "NO")))
265 : {
266 167533 : }
267 :
268 199999 : GDALDataset::GDALDataset(int bForceCachedIOIn)
269 199999 : : bForceCachedIO(CPL_TO_BOOL(bForceCachedIOIn)),
270 199999 : m_poPrivate(new (std::nothrow) GDALDataset::Private)
271 : {
272 199999 : }
273 :
274 : //! @endcond
275 :
276 : /************************************************************************/
277 : /* ~GDALDataset() */
278 : /************************************************************************/
279 :
280 : /**
281 : * \brief Destroy an open GDALDataset.
282 : *
283 : * This is the accepted method of closing a GDAL dataset and deallocating
284 : * all resources associated with it.
285 : *
286 : * Equivalent of the C callable GDALClose(). Except that GDALClose() first
287 : * decrements the reference count, and then closes only if it has dropped to
288 : * zero.
289 : *
290 : * For Windows users, it is not recommended to use the delete operator on the
291 : * dataset object because of known issues when allocating and freeing memory
292 : * across module boundaries. Calling GDALClose() is then a better option.
293 : */
294 :
295 199980 : GDALDataset::~GDALDataset()
296 :
297 : {
298 : // we don't want to report destruction of datasets that
299 : // were never really open or meant as internal
300 199980 : if (!bIsInternal && (nBands != 0 || !EQUAL(GetDescription(), "")))
301 : {
302 76080 : if (CPLGetPID() != GDALGetResponsiblePIDForCurrentThread())
303 209 : CPLDebug("GDAL",
304 : "GDALClose(%s, this=%p) (pid=%d, responsiblePID=%d)",
305 209 : GetDescription(), this, static_cast<int>(CPLGetPID()),
306 209 : static_cast<int>(GDALGetResponsiblePIDForCurrentThread()));
307 : else
308 75871 : CPLDebug("GDAL", "GDALClose(%s, this=%p)", GetDescription(), this);
309 : }
310 :
311 199980 : GDALDataset::Close();
312 :
313 : /* -------------------------------------------------------------------- */
314 : /* Remove dataset from the "open" dataset list. */
315 : /* -------------------------------------------------------------------- */
316 199980 : if (!bIsInternal)
317 : {
318 155382 : CPLMutexHolderD(&hDLMutex);
319 77691 : if (poAllDatasetMap)
320 : {
321 : std::map<GDALDataset *, GIntBig>::iterator oIter =
322 77691 : poAllDatasetMap->find(this);
323 77691 : CPLAssert(oIter != poAllDatasetMap->end());
324 :
325 77691 : UnregisterFromSharedDataset();
326 :
327 77691 : poAllDatasetMap->erase(oIter);
328 :
329 77691 : if (poAllDatasetMap->empty())
330 : {
331 32561 : delete poAllDatasetMap;
332 32561 : poAllDatasetMap = nullptr;
333 32561 : if (phSharedDatasetSet)
334 : {
335 273 : CPLHashSetDestroy(phSharedDatasetSet);
336 : }
337 32561 : phSharedDatasetSet = nullptr;
338 32561 : CPLFree(ppDatasets);
339 32561 : ppDatasets = nullptr;
340 : }
341 : }
342 : }
343 :
344 : /* -------------------------------------------------------------------- */
345 : /* Destroy the raster bands if they exist. */
346 : /* -------------------------------------------------------------------- */
347 1751660 : for (int i = 0; i < nBands && papoBands != nullptr; ++i)
348 : {
349 1551680 : if (papoBands[i] != nullptr)
350 1551680 : delete papoBands[i];
351 1551680 : papoBands[i] = nullptr;
352 : }
353 :
354 199980 : CPLFree(papoBands);
355 :
356 199980 : if (m_poStyleTable)
357 : {
358 23 : delete m_poStyleTable;
359 23 : m_poStyleTable = nullptr;
360 : }
361 :
362 199980 : if (m_poPrivate != nullptr)
363 : {
364 199980 : if (m_poPrivate->hMutex != nullptr)
365 21956 : CPLDestroyMutex(m_poPrivate->hMutex);
366 :
367 : #if defined(__COVERITY__) || defined(DEBUG)
368 : // Not needed since at destruction there is no risk of concurrent use.
369 399960 : std::lock_guard oLock(m_poPrivate->m_oMutexWKT);
370 : #endif
371 199980 : CPLFree(m_poPrivate->m_pszWKTCached);
372 199980 : if (m_poPrivate->m_poSRSCached)
373 : {
374 0 : m_poPrivate->m_poSRSCached->Release();
375 : }
376 199980 : CPLFree(m_poPrivate->m_pszWKTGCPCached);
377 199980 : if (m_poPrivate->m_poSRSGCPCached)
378 : {
379 0 : m_poPrivate->m_poSRSGCPCached->Release();
380 : }
381 : }
382 :
383 199980 : delete m_poPrivate;
384 :
385 199980 : CSLDestroy(papszOpenOptions);
386 199980 : }
387 :
388 : /************************************************************************/
389 : /* Close() */
390 : /************************************************************************/
391 :
392 : /** Do final cleanup before a dataset is destroyed.
393 : *
394 : * This method is typically called by GDALClose() or the destructor of a
395 : * GDALDataset subclass. It might also be called by C++ users before
396 : * destroying a dataset. It should not be called on a shared dataset whose
397 : * reference count is greater than one.
398 : *
399 : * It gives a last chance to the closing process to return an error code if
400 : * something goes wrong, in particular in creation / update scenarios where
401 : * file write or network communication might occur when finalizing the dataset.
402 : *
403 : * Implementations should be robust to this method to be called several times
404 : * (on subsequent calls, it should do nothing and return CE_None).
405 : * Once it has been called, no other method than Close() or the dataset
406 : * destructor should be called. RasterBand or OGRLayer owned by the dataset
407 : * should be assumed as no longer being valid.
408 : *
409 : * If a driver implements this method, it must also call it from its
410 : * dataset destructor.
411 : *
412 : * Starting with GDAL 3.13, this function may report progress if a progress
413 : * callback if provided in the pfnProgress argument and if the dataset returns
414 : * true for GDALDataset::GetCloseReportsProgress()
415 : *
416 : * This is the equivalent of C function GDALDatasetRunCloseWithoutDestroying()
417 : * or GDALDatasetRunCloseWithoutDestroyingEx()
418 : *
419 : * A typical implementation might look as the following
420 : * \code{.cpp}
421 : *
422 : * MyDataset::~MyDataset()
423 : * {
424 : * try
425 : * {
426 : * MyDataset::Close();
427 : * }
428 : * catch (const std::exception &exc)
429 : * {
430 : * // If Close() can throw exception
431 : * CPLError(CE_Failure, CPLE_AppDefined,
432 : * "Exception thrown in MyDataset::Close(): %s",
433 : * exc.what());
434 : * }
435 : * catch (...)
436 : * {
437 : * // If Close() can throw exception
438 : * CPLError(CE_Failure, CPLE_AppDefined,
439 : * "Exception thrown in MyDataset::Close()");
440 : * }
441 : * }
442 : *
443 : * CPLErr MyDataset::Close(GDALProgressFunc pfnProgress, void* pProgressData)
444 : * {
445 : * CPLErr eErr = CE_None;
446 : * if( nOpenFlags != OPEN_FLAGS_CLOSED )
447 : * {
448 : * eErr = MyDataset::FlushCache(true);
449 : *
450 : * // Do something driver specific
451 : * if (m_fpImage)
452 : * {
453 : * if( VSIFCloseL(m_fpImage) != 0 )
454 : * {
455 : * CPLError(CE_Failure, CPLE_FileIO, "VSIFCloseL() failed");
456 : * eErr = CE_Failure;
457 : * }
458 : * }
459 : *
460 : * // Call parent Close() implementation.
461 : * eErr = GDAL::Combine(eErr, MyParentDatasetClass::Close());
462 : * }
463 : * return eErr;
464 : * }
465 : * \endcode
466 : *
467 : * @param pfnProgress (since GDAL 3.13) Progress callback, or nullptr
468 : * @param pProgressData (since GDAL 3.13) User data of progress callback, or nullptr
469 : * @return CE_None if no error
470 : *
471 : * @since GDAL 3.7
472 : */
473 331123 : CPLErr GDALDataset::Close(GDALProgressFunc pfnProgress, void *pProgressData)
474 : {
475 : (void)pfnProgress;
476 : (void)pProgressData;
477 :
478 331123 : if (nOpenFlags != OPEN_FLAGS_CLOSED)
479 : {
480 : // Call UnregisterFromSharedDataset() before altering nOpenFlags
481 199980 : UnregisterFromSharedDataset();
482 :
483 199980 : nOpenFlags = OPEN_FLAGS_CLOSED;
484 : }
485 :
486 331123 : if (IsMarkedSuppressOnClose())
487 : {
488 3538 : if (poDriver == nullptr ||
489 : // Someone issuing Create("foo.tif") on a
490 : // memory driver doesn't expect files with those names to be deleted
491 : // on a file system...
492 : // This is somewhat messy. Ideally there should be a way for the
493 : // driver to overload the default behavior
494 1725 : (!EQUAL(poDriver->GetDescription(), "MEM") &&
495 1647 : !EQUAL(poDriver->GetDescription(), "Memory")))
496 : {
497 1735 : if (VSIUnlink(GetDescription()) == 0)
498 683 : UnMarkSuppressOnClose();
499 : }
500 : }
501 :
502 331123 : return CE_None;
503 : }
504 :
505 : /************************************************************************/
506 : /* GDALDatasetRunCloseWithoutDestroying() */
507 : /************************************************************************/
508 :
509 : /** Run the Close() method, without running destruction of the object.
510 : *
511 : * This ensures that content that should be written to file is written and
512 : * that all file descriptors are closed.
513 : *
514 : * Note that this is different from GDALClose() which also destroys
515 : * the underlying C++ object. GDALClose() or GDALReleaseDataset() are actually
516 : * the only functions that can be safely called on the dataset handle after
517 : * this function has been called.
518 : *
519 : * Most users want to use GDALClose() or GDALReleaseDataset() rather than
520 : * this function.
521 : *
522 : * This function is equivalent to the C++ method GDALDataset:Close()
523 : *
524 : * @param hDS dataset handle.
525 : * @return CE_None if no error
526 : *
527 : * @since GDAL 3.12
528 : * @see GDALClose(), GDALDatasetRunCloseWithoutDestroyingEx()
529 : */
530 0 : CPLErr GDALDatasetRunCloseWithoutDestroying(GDALDatasetH hDS)
531 : {
532 0 : VALIDATE_POINTER1(hDS, __func__, CE_Failure);
533 0 : return GDALDataset::FromHandle(hDS)->Close();
534 : }
535 :
536 : /************************************************************************/
537 : /* GDALDatasetRunCloseWithoutDestroyingEx() */
538 : /************************************************************************/
539 :
540 : /** Run the Close() method, without running destruction of the object.
541 : *
542 : * This ensures that content that should be written to file is written and
543 : * that all file descriptors are closed.
544 : *
545 : * Note that this is different from GDALClose() which also destroys
546 : * the underlying C++ object. GDALClose() or GDALReleaseDataset() are actually
547 : * the only functions that can be safely called on the dataset handle after
548 : * this function has been called.
549 : *
550 : * Most users want to use GDALClose() or GDALReleaseDataset() rather than
551 : * this function.
552 : *
553 : * This function may report progress if a progress
554 : * callback if provided in the pfnProgress argument and if the dataset returns
555 : * true for GDALDataset::GetCloseReportsProgress()
556 : *
557 : * This function is equivalent to the C++ method GDALDataset:Close()
558 : *
559 : * @param hDS dataset handle.
560 : * @param pfnProgress Progress callback, or nullptr
561 : * @param pProgressData User data of progress callback, or nullptr
562 : *
563 : * @return CE_None if no error
564 : *
565 : * @since GDAL 3.13
566 : * @see GDALClose()
567 : */
568 12 : CPLErr GDALDatasetRunCloseWithoutDestroyingEx(GDALDatasetH hDS,
569 : GDALProgressFunc pfnProgress,
570 : void *pProgressData)
571 : {
572 12 : VALIDATE_POINTER1(hDS, __func__, CE_Failure);
573 12 : return GDALDataset::FromHandle(hDS)->Close(pfnProgress, pProgressData);
574 : }
575 :
576 : /************************************************************************/
577 : /* GetCloseReportsProgress() */
578 : /************************************************************************/
579 :
580 : /** Returns whether the Close() operation will report progress / is a potential
581 : * lengthy operation.
582 : *
583 : * At time of writing, only the COG driver will return true, if the dataset
584 : * has been created through the GDALDriver::Create() interface.
585 : *
586 : * This method is equivalent to the C function GDALDatasetGetCloseReportsProgress()
587 : *
588 : * @return true if the Close() operation will report progress
589 : * @since GDAL 3.13
590 : * @see Close()
591 : */
592 243 : bool GDALDataset::GetCloseReportsProgress() const
593 : {
594 243 : return false;
595 : }
596 :
597 : /************************************************************************/
598 : /* GDALDatasetGetCloseReportsProgress() */
599 : /************************************************************************/
600 :
601 : /** Returns whether the Close() operation will report progress / is a potential
602 : * lengthy operation.
603 : *
604 : * This function is equivalent to the C++ method GDALDataset::GetCloseReportsProgress()
605 : *
606 : * @param hDS dataset handle.
607 : * @return CE_None if no error
608 : *
609 : * @return true if the Close() operation will report progress
610 : * @since GDAL 3.13
611 : * @see GDALClose()
612 : */
613 2 : bool GDALDatasetGetCloseReportsProgress(GDALDatasetH hDS)
614 : {
615 2 : VALIDATE_POINTER1(hDS, __func__, false);
616 2 : return GDALDataset::FromHandle(hDS)->GetCloseReportsProgress();
617 : }
618 :
619 : /************************************************************************/
620 : /* CanReopenWithCurrentDescription() */
621 : /************************************************************************/
622 :
623 : /** Returns whether, once this dataset is closed, it can be re-opened with
624 : * Open() using the current value of GetDescription()
625 : *
626 : * The default implementation returns true. Some drivers, like MVT in Create()
627 : * mode, can return false. Some drivers return true, but the re-opened dataset
628 : * may be opened by another driver (e.g. the COG driver will return true, but
629 : * the driver used for re-opening is GTiff).
630 : *
631 : * @return true if the dataset can be re-opened using the value as
632 : * GetDescription() as connection string for Open()
633 : * @since GDAL 3.13
634 : */
635 2 : bool GDALDataset::CanReopenWithCurrentDescription() const
636 : {
637 2 : return true;
638 : }
639 :
640 : /************************************************************************/
641 : /* UnregisterFromSharedDataset() */
642 : /************************************************************************/
643 :
644 277671 : void GDALDataset::UnregisterFromSharedDataset()
645 : {
646 277671 : if (!(!bIsInternal && bShared && poAllDatasetMap && phSharedDatasetSet))
647 277256 : return;
648 :
649 830 : CPLMutexHolderD(&hDLMutex);
650 :
651 : std::map<GDALDataset *, GIntBig>::iterator oIter =
652 415 : poAllDatasetMap->find(this);
653 415 : CPLAssert(oIter != poAllDatasetMap->end());
654 415 : const GIntBig nPIDCreatorForShared = oIter->second;
655 415 : bShared = false;
656 : SharedDatasetCtxt sStruct;
657 415 : sStruct.nPID = nPIDCreatorForShared;
658 415 : sStruct.nOpenFlags = nOpenFlags & ~GDAL_OF_SHARED;
659 415 : sStruct.pszDescription = const_cast<char *>(GetDescription());
660 : std::string osConcatenatedOpenOptions =
661 830 : GDALSharedDatasetConcatenateOpenOptions(papszOpenOptions);
662 415 : sStruct.pszConcatenatedOpenOptions = &osConcatenatedOpenOptions[0];
663 415 : sStruct.poDS = nullptr;
664 : SharedDatasetCtxt *psStruct = static_cast<SharedDatasetCtxt *>(
665 415 : CPLHashSetLookup(phSharedDatasetSet, &sStruct));
666 415 : if (psStruct && psStruct->poDS == this)
667 : {
668 414 : CPLHashSetRemove(phSharedDatasetSet, psStruct);
669 : }
670 : else
671 : {
672 1 : CPLDebug("GDAL",
673 : "Should not happen. Cannot find %s, "
674 : "this=%p in phSharedDatasetSet",
675 1 : GetDescription(), this);
676 : }
677 : }
678 :
679 : /************************************************************************/
680 : /* AddToDatasetOpenList() */
681 : /************************************************************************/
682 :
683 79009 : void GDALDataset::AddToDatasetOpenList()
684 : {
685 : /* -------------------------------------------------------------------- */
686 : /* Add this dataset to the open dataset list. */
687 : /* -------------------------------------------------------------------- */
688 79009 : bIsInternal = false;
689 :
690 79009 : CPLMutexHolderD(&hDLMutex);
691 :
692 79009 : if (poAllDatasetMap == nullptr)
693 32571 : poAllDatasetMap = new std::map<GDALDataset *, GIntBig>;
694 79009 : (*poAllDatasetMap)[this] = -1;
695 79009 : }
696 :
697 : /************************************************************************/
698 : /* FlushCache() */
699 : /************************************************************************/
700 :
701 : /**
702 : * \brief Flush all write cached data to disk.
703 : *
704 : * Any raster (or other GDAL) data written via GDAL calls, but buffered
705 : * internally will be written to disk.
706 : *
707 : * The default implementation of this method just calls the FlushCache() method
708 : * on each of the raster bands and the SyncToDisk() method
709 : * on each of the layers. Conceptually, calling FlushCache() on a dataset
710 : * should include any work that might be accomplished by calling SyncToDisk()
711 : * on layers in that dataset.
712 : *
713 : * Using this method does not prevent use from calling GDALClose()
714 : * to properly close a dataset and ensure that important data not addressed
715 : * by FlushCache() is written in the file.
716 : *
717 : * This method is the same as the C function GDALFlushCache().
718 : *
719 : * @param bAtClosing Whether this is called from a GDALDataset destructor
720 : * @return CE_None in case of success (note: return value added in GDAL 3.7)
721 : */
722 :
723 136921 : CPLErr GDALDataset::FlushCache(bool bAtClosing)
724 :
725 : {
726 136921 : CPLErr eErr = CE_None;
727 : // This sometimes happens if a dataset is destroyed before completely
728 : // built.
729 :
730 136921 : if (papoBands)
731 : {
732 1966620 : for (int i = 0; i < nBands; ++i)
733 : {
734 1845100 : if (papoBands[i])
735 : {
736 1845100 : if (papoBands[i]->FlushCache(bAtClosing) != CE_None)
737 7 : eErr = CE_Failure;
738 : }
739 : }
740 : }
741 :
742 136921 : const int nLayers = GetLayerCount();
743 : // cppcheck-suppress knownConditionTrueFalse
744 136921 : if (nLayers > 0)
745 : {
746 17562 : CPLMutexHolderD(m_poPrivate ? &(m_poPrivate->hMutex) : nullptr);
747 27041 : for (int i = 0; i < nLayers; ++i)
748 : {
749 18260 : OGRLayer *poLayer = GetLayer(i);
750 :
751 18260 : if (poLayer)
752 : {
753 18260 : if (poLayer->SyncToDisk() != OGRERR_NONE)
754 1 : eErr = CE_Failure;
755 : }
756 : }
757 : }
758 :
759 136921 : return eErr;
760 : }
761 :
762 : /************************************************************************/
763 : /* GDALFlushCache() */
764 : /************************************************************************/
765 :
766 : /**
767 : * \brief Flush all write cached data to disk.
768 : *
769 : * @see GDALDataset::FlushCache().
770 : * @return CE_None in case of success (note: return value added in GDAL 3.7)
771 : */
772 :
773 5251 : CPLErr CPL_STDCALL GDALFlushCache(GDALDatasetH hDS)
774 :
775 : {
776 5251 : VALIDATE_POINTER1(hDS, "GDALFlushCache", CE_Failure);
777 :
778 5251 : return GDALDataset::FromHandle(hDS)->FlushCache(false);
779 : }
780 :
781 : /************************************************************************/
782 : /* DropCache() */
783 : /************************************************************************/
784 :
785 : /**
786 : * \brief Drop all write cached data
787 : *
788 : * This method is the same as the C function GDALDropCache().
789 : *
790 : * @return CE_None in case of success
791 : * @since 3.9
792 : */
793 :
794 1 : CPLErr GDALDataset::DropCache()
795 :
796 : {
797 1 : CPLErr eErr = CE_None;
798 :
799 1 : if (papoBands)
800 : {
801 2 : for (int i = 0; i < nBands; ++i)
802 : {
803 1 : if (papoBands[i])
804 : {
805 1 : if (papoBands[i]->DropCache() != CE_None)
806 0 : eErr = CE_Failure;
807 : }
808 : }
809 : }
810 :
811 1 : return eErr;
812 : }
813 :
814 : /************************************************************************/
815 : /* GDALDropCache() */
816 : /************************************************************************/
817 :
818 : /**
819 : * \brief Drop all write cached data
820 : *
821 : * @see GDALDataset::DropCache().
822 : * @return CE_None in case of success
823 : * @since 3.9
824 : */
825 :
826 0 : CPLErr CPL_STDCALL GDALDropCache(GDALDatasetH hDS)
827 :
828 : {
829 0 : VALIDATE_POINTER1(hDS, "GDALDropCache", CE_Failure);
830 :
831 0 : return GDALDataset::FromHandle(hDS)->DropCache();
832 : }
833 :
834 : /************************************************************************/
835 : /* GetEstimatedRAMUsage() */
836 : /************************************************************************/
837 :
838 : /**
839 : * \brief Return the intrinsic RAM usage of this dataset.
840 : *
841 : * The returned value should take into account caches in the underlying driver
842 : * and decoding library, but not the usage related to the GDAL block cache.
843 : *
844 : * At time of writing, this method is only implemented in the JP2OpenJPEG
845 : * driver. For single-tiled JPEG2000 images, the decoding of the image,
846 : * even partially, involves allocating at least
847 : * width * height * number_of_bands * sizeof(uint32_t) bytes inside the libopenjp2
848 : * library.
849 : *
850 : * This method is used by the GDALDatasetPool class, itself used by the GDAL VRT
851 : * driver, to determine how long a dataset in the pool must be kept open, given
852 : * the RAM usage of the dataset with respect to the usable total RAM.
853 : *
854 : * @since GDAL 3.7
855 : * @return RAM usage in bytes, or -1 if unknown (the default implementation
856 : * returns -1)
857 : */
858 :
859 3372 : GIntBig GDALDataset::GetEstimatedRAMUsage()
860 : {
861 3372 : return -1;
862 : }
863 :
864 : /************************************************************************/
865 : /* BlockBasedFlushCache() */
866 : /* */
867 : /* This helper method can be called by the */
868 : /* GDALDataset::FlushCache() for particular drivers to ensure */
869 : /* that buffers will be flushed in a manner suitable for pixel */
870 : /* interleaved (by block) IO. That is, if all the bands have */
871 : /* the same size blocks then a given block will be flushed for */
872 : /* all bands before proceeding to the next block. */
873 : /************************************************************************/
874 :
875 : //! @cond Doxygen_Suppress
876 350 : CPLErr GDALDataset::BlockBasedFlushCache(bool bAtClosing)
877 :
878 : {
879 350 : GDALRasterBand *poBand1 = GetRasterBand(1);
880 350 : if (poBand1 == nullptr || (IsMarkedSuppressOnClose() && bAtClosing))
881 : {
882 7 : return GDALDataset::FlushCache(bAtClosing);
883 : }
884 :
885 343 : int nBlockXSize = 0;
886 343 : int nBlockYSize = 0;
887 343 : poBand1->GetBlockSize(&nBlockXSize, &nBlockYSize);
888 :
889 : /* -------------------------------------------------------------------- */
890 : /* Verify that all bands match. */
891 : /* -------------------------------------------------------------------- */
892 1108 : for (int iBand = 1; iBand < nBands; ++iBand)
893 : {
894 765 : GDALRasterBand *poBand = GetRasterBand(iBand + 1);
895 :
896 : int nThisBlockXSize, nThisBlockYSize;
897 765 : poBand->GetBlockSize(&nThisBlockXSize, &nThisBlockYSize);
898 765 : if (nThisBlockXSize != nBlockXSize && nThisBlockYSize != nBlockYSize)
899 : {
900 0 : return GDALDataset::FlushCache(bAtClosing);
901 : }
902 : }
903 :
904 : /* -------------------------------------------------------------------- */
905 : /* Now flush writable data. */
906 : /* -------------------------------------------------------------------- */
907 794 : for (int iY = 0; iY < poBand1->nBlocksPerColumn; ++iY)
908 : {
909 991 : for (int iX = 0; iX < poBand1->nBlocksPerRow; ++iX)
910 : {
911 1690 : for (int iBand = 0; iBand < nBands; ++iBand)
912 : {
913 1150 : const CPLErr eErr = papoBands[iBand]->FlushBlock(iX, iY);
914 :
915 1150 : if (eErr != CE_None)
916 0 : return CE_Failure;
917 : }
918 : }
919 : }
920 343 : return CE_None;
921 : }
922 :
923 : /************************************************************************/
924 : /* RasterInitialize() */
925 : /* */
926 : /* Initialize raster size */
927 : /************************************************************************/
928 :
929 0 : void GDALDataset::RasterInitialize(int nXSize, int nYSize)
930 :
931 : {
932 0 : CPLAssert(nXSize > 0 && nYSize > 0);
933 :
934 0 : nRasterXSize = nXSize;
935 0 : nRasterYSize = nYSize;
936 0 : }
937 :
938 : //! @endcond
939 :
940 : /************************************************************************/
941 : /* AddBand() */
942 : /************************************************************************/
943 :
944 : /**
945 : * \fn GDALDataset::AddBand(GDALDataType, char**)
946 : * \brief Add a band to a dataset.
947 : *
948 : * This method will add a new band to the dataset if the underlying format
949 : * supports this action. Most formats do not.
950 : *
951 : * Note that the new GDALRasterBand is not returned. It may be fetched
952 : * after successful completion of the method by calling
953 : * GDALDataset::GetRasterBand(GDALDataset::GetRasterCount()) as the newest
954 : * band will always be the last band.
955 : *
956 : * @param eType the data type of the pixels in the new band.
957 : *
958 : * @param papszOptions a list of NAME=VALUE option strings. The supported
959 : * options are format specific. NULL may be passed by default.
960 : *
961 : * @return CE_None on success or CE_Failure on failure.
962 : */
963 :
964 0 : CPLErr GDALDataset::AddBand(CPL_UNUSED GDALDataType eType,
965 : CPL_UNUSED CSLConstList papszOptions)
966 :
967 : {
968 0 : ReportError(CE_Failure, CPLE_NotSupported,
969 : "Dataset does not support the AddBand() method.");
970 :
971 0 : return CE_Failure;
972 : }
973 :
974 : /************************************************************************/
975 : /* GDALAddBand() */
976 : /************************************************************************/
977 :
978 : /**
979 : * \brief Add a band to a dataset.
980 : *
981 : * @see GDALDataset::AddBand().
982 : */
983 :
984 26 : CPLErr CPL_STDCALL GDALAddBand(GDALDatasetH hDataset, GDALDataType eType,
985 : CSLConstList papszOptions)
986 :
987 : {
988 26 : VALIDATE_POINTER1(hDataset, "GDALAddBand", CE_Failure);
989 :
990 52 : return GDALDataset::FromHandle(hDataset)->AddBand(
991 26 : eType, const_cast<char **>(papszOptions));
992 : }
993 :
994 : /************************************************************************/
995 : /* SetBand() */
996 : /************************************************************************/
997 :
998 : //! @cond Doxygen_Suppress
999 : /** Set a band in the band array, updating the band count, and array size
1000 : * appropriately.
1001 : *
1002 : * @param nNewBand new band number (indexing starts at 1)
1003 : * @param poBand band object.
1004 : */
1005 :
1006 1697120 : void GDALDataset::SetBand(int nNewBand, GDALRasterBand *poBand)
1007 :
1008 : {
1009 : /* -------------------------------------------------------------------- */
1010 : /* Do we need to grow the bands list? */
1011 : /* -------------------------------------------------------------------- */
1012 1697120 : if (nBands < nNewBand || papoBands == nullptr)
1013 : {
1014 961869 : GDALRasterBand **papoNewBands = nullptr;
1015 :
1016 961869 : if (papoBands == nullptr)
1017 113434 : papoNewBands = static_cast<GDALRasterBand **>(VSICalloc(
1018 113434 : sizeof(GDALRasterBand *), std::max(nNewBand, nBands)));
1019 : else
1020 : papoNewBands = static_cast<GDALRasterBand **>(
1021 848435 : VSIRealloc(papoBands, sizeof(GDALRasterBand *) *
1022 848435 : std::max(nNewBand, nBands)));
1023 961869 : if (papoNewBands == nullptr)
1024 : {
1025 0 : ReportError(CE_Failure, CPLE_OutOfMemory,
1026 : "Cannot allocate band array");
1027 0 : return;
1028 : }
1029 :
1030 961869 : papoBands = papoNewBands;
1031 :
1032 1870230 : for (int i = nBands; i < nNewBand; ++i)
1033 908359 : papoBands[i] = nullptr;
1034 :
1035 961869 : nBands = std::max(nBands, nNewBand);
1036 :
1037 961869 : if (m_poPrivate)
1038 : {
1039 961869 : for (int i = static_cast<int>(m_poPrivate->m_anBandMap.size());
1040 2658990 : i < nBands; ++i)
1041 : {
1042 1697120 : m_poPrivate->m_anBandMap.push_back(i + 1);
1043 : }
1044 : }
1045 : }
1046 :
1047 : /* -------------------------------------------------------------------- */
1048 : /* Set the band. Resetting the band is currently not permitted. */
1049 : /* -------------------------------------------------------------------- */
1050 1697120 : if (papoBands[nNewBand - 1] != nullptr)
1051 : {
1052 0 : ReportError(CE_Failure, CPLE_NotSupported,
1053 : "Cannot set band %d as it is already set", nNewBand);
1054 0 : return;
1055 : }
1056 :
1057 1697120 : papoBands[nNewBand - 1] = poBand;
1058 :
1059 : /* -------------------------------------------------------------------- */
1060 : /* Set back reference information on the raster band. Note */
1061 : /* that the GDALDataset is a friend of the GDALRasterBand */
1062 : /* specifically to allow this. */
1063 : /* -------------------------------------------------------------------- */
1064 1697120 : poBand->nBand = nNewBand;
1065 1697120 : poBand->poDS = this;
1066 1697120 : poBand->nRasterXSize = nRasterXSize;
1067 1697120 : poBand->nRasterYSize = nRasterYSize;
1068 1697120 : poBand->eAccess = eAccess; // Default access to be same as dataset.
1069 : }
1070 :
1071 : //! @endcond
1072 :
1073 : /************************************************************************/
1074 : /* SetBand() */
1075 : /************************************************************************/
1076 :
1077 : //! @cond Doxygen_Suppress
1078 : /** Set a band in the band array, updating the band count, and array size
1079 : * appropriately.
1080 : *
1081 : * @param nNewBand new band number (indexing starts at 1)
1082 : * @param poBand band object.
1083 : */
1084 :
1085 1112160 : void GDALDataset::SetBand(int nNewBand, std::unique_ptr<GDALRasterBand> poBand)
1086 : {
1087 1112160 : SetBand(nNewBand, poBand.release());
1088 1112160 : }
1089 :
1090 : //! @endcond
1091 :
1092 : /************************************************************************/
1093 : /* GetRasterXSize() */
1094 : /************************************************************************/
1095 :
1096 : /**
1097 :
1098 : \brief Fetch raster width in pixels.
1099 :
1100 : Equivalent of the C function GDALGetRasterXSize().
1101 :
1102 : @return the width in pixels of raster bands in this GDALDataset.
1103 :
1104 : */
1105 :
1106 734390 : int GDALDataset::GetRasterXSize() const
1107 : {
1108 734390 : return nRasterXSize;
1109 : }
1110 :
1111 : /************************************************************************/
1112 : /* GDALGetRasterXSize() */
1113 : /************************************************************************/
1114 :
1115 : /**
1116 : * \brief Fetch raster width in pixels.
1117 : *
1118 : * @see GDALDataset::GetRasterXSize().
1119 : */
1120 :
1121 40360 : int CPL_STDCALL GDALGetRasterXSize(GDALDatasetH hDataset)
1122 :
1123 : {
1124 40360 : VALIDATE_POINTER1(hDataset, "GDALGetRasterXSize", 0);
1125 :
1126 40360 : return GDALDataset::FromHandle(hDataset)->GetRasterXSize();
1127 : }
1128 :
1129 : /************************************************************************/
1130 : /* GetRasterYSize() */
1131 : /************************************************************************/
1132 :
1133 : /**
1134 :
1135 : \brief Fetch raster height in pixels.
1136 :
1137 : Equivalent of the C function GDALGetRasterYSize().
1138 :
1139 : @return the height in pixels of raster bands in this GDALDataset.
1140 :
1141 : */
1142 :
1143 620218 : int GDALDataset::GetRasterYSize() const
1144 : {
1145 620218 : return nRasterYSize;
1146 : }
1147 :
1148 : /************************************************************************/
1149 : /* GDALGetRasterYSize() */
1150 : /************************************************************************/
1151 :
1152 : /**
1153 : * \brief Fetch raster height in pixels.
1154 : *
1155 : * @see GDALDataset::GetRasterYSize().
1156 : */
1157 :
1158 39577 : int CPL_STDCALL GDALGetRasterYSize(GDALDatasetH hDataset)
1159 :
1160 : {
1161 39577 : VALIDATE_POINTER1(hDataset, "GDALGetRasterYSize", 0);
1162 :
1163 39577 : return GDALDataset::FromHandle(hDataset)->GetRasterYSize();
1164 : }
1165 :
1166 : /************************************************************************/
1167 : /* GetRasterBand() */
1168 : /************************************************************************/
1169 :
1170 : /**
1171 :
1172 : \brief Fetch a band object for a dataset.
1173 :
1174 : See GetBands() for a C++ iterator version of this method.
1175 :
1176 : Equivalent of the C function GDALGetRasterBand().
1177 :
1178 : @param nBandId the index number of the band to fetch, from 1 to
1179 : GetRasterCount().
1180 :
1181 : @return the nBandId th band object
1182 :
1183 : */
1184 :
1185 12316500 : GDALRasterBand *GDALDataset::GetRasterBand(int nBandId)
1186 :
1187 : {
1188 12316500 : if (papoBands)
1189 : {
1190 12316500 : if (nBandId < 1 || nBandId > nBands)
1191 : {
1192 12 : ReportError(CE_Failure, CPLE_IllegalArg,
1193 : "GDALDataset::GetRasterBand(%d) - Illegal band #\n",
1194 : nBandId);
1195 12 : return nullptr;
1196 : }
1197 :
1198 12316500 : return papoBands[nBandId - 1];
1199 : }
1200 13 : return nullptr;
1201 : }
1202 :
1203 : /************************************************************************/
1204 : /* GetRasterBand() */
1205 : /************************************************************************/
1206 :
1207 : /**
1208 :
1209 : \brief Fetch a band object for a dataset.
1210 :
1211 : See GetBands() for a C++ iterator version of this method.
1212 :
1213 : Equivalent of the C function GDALGetRasterBand().
1214 :
1215 : @param nBandId the index number of the band to fetch, from 1 to
1216 : GetRasterCount().
1217 :
1218 : @return the nBandId th band object
1219 :
1220 : */
1221 :
1222 594 : const GDALRasterBand *GDALDataset::GetRasterBand(int nBandId) const
1223 :
1224 : {
1225 594 : if (papoBands)
1226 : {
1227 594 : if (nBandId < 1 || nBandId > nBands)
1228 : {
1229 0 : ReportError(CE_Failure, CPLE_IllegalArg,
1230 : "GDALDataset::GetRasterBand(%d) - Illegal band #\n",
1231 : nBandId);
1232 0 : return nullptr;
1233 : }
1234 :
1235 594 : return papoBands[nBandId - 1];
1236 : }
1237 0 : return nullptr;
1238 : }
1239 :
1240 : /************************************************************************/
1241 : /* GDALGetRasterBand() */
1242 : /************************************************************************/
1243 :
1244 : /**
1245 : * \brief Fetch a band object for a dataset.
1246 : * @see GDALDataset::GetRasterBand().
1247 : */
1248 :
1249 413731 : GDALRasterBandH CPL_STDCALL GDALGetRasterBand(GDALDatasetH hDS, int nBandId)
1250 :
1251 : {
1252 413731 : VALIDATE_POINTER1(hDS, "GDALGetRasterBand", nullptr);
1253 :
1254 413731 : return GDALRasterBand::ToHandle(
1255 413731 : GDALDataset::FromHandle(hDS)->GetRasterBand(nBandId));
1256 : }
1257 :
1258 : /************************************************************************/
1259 : /* GetRasterCount() */
1260 : /************************************************************************/
1261 :
1262 : /**
1263 : * \brief Fetch the number of raster bands on this dataset.
1264 : *
1265 : * Same as the C function GDALGetRasterCount().
1266 : *
1267 : * @return the number of raster bands.
1268 : */
1269 :
1270 6166130 : int GDALDataset::GetRasterCount() const
1271 : {
1272 6166130 : return papoBands ? nBands : 0;
1273 : }
1274 :
1275 : /************************************************************************/
1276 : /* GDALGetRasterCount() */
1277 : /************************************************************************/
1278 :
1279 : /**
1280 : * \brief Fetch the number of raster bands on this dataset.
1281 : *
1282 : * @see GDALDataset::GetRasterCount().
1283 : */
1284 :
1285 386999 : int CPL_STDCALL GDALGetRasterCount(GDALDatasetH hDS)
1286 :
1287 : {
1288 386999 : VALIDATE_POINTER1(hDS, "GDALGetRasterCount", 0);
1289 :
1290 386999 : return GDALDataset::FromHandle(hDS)->GetRasterCount();
1291 : }
1292 :
1293 : /************************************************************************/
1294 : /* GetProjectionRef() */
1295 : /************************************************************************/
1296 :
1297 : /**
1298 : * \brief Fetch the projection definition string for this dataset.
1299 : *
1300 : * Same as the C function GDALGetProjectionRef().
1301 : *
1302 : * The returned string defines the projection coordinate system of the
1303 : * image in OpenGIS WKT format. It should be suitable for use with the
1304 : * OGRSpatialReference class.
1305 : *
1306 : * When a projection definition is not available an empty (but not NULL)
1307 : * string is returned.
1308 : *
1309 : * \note Starting with GDAL 3.0, this is a compatibility layer around
1310 : * GetSpatialRef()
1311 : *
1312 : * @return a pointer to an internal projection reference string. It should
1313 : * not be altered, freed or expected to last for long.
1314 : *
1315 : * @see https://gdal.org/tutorials/osr_api_tut.html
1316 : */
1317 :
1318 5259 : const char *GDALDataset::GetProjectionRef() const
1319 : {
1320 5259 : const auto poSRS = GetSpatialRef();
1321 5259 : if (!poSRS || !m_poPrivate)
1322 : {
1323 2383 : return "";
1324 : }
1325 2876 : char *pszWKT = nullptr;
1326 2876 : poSRS->exportToWkt(&pszWKT);
1327 2876 : if (!pszWKT)
1328 : {
1329 0 : return "";
1330 : }
1331 :
1332 : // If called on a thread-safe dataset, we might be called by several
1333 : // threads, so make sure our accesses to m_pszWKTCached are protected
1334 : // by a mutex.
1335 5752 : std::lock_guard oLock(m_poPrivate->m_oMutexWKT);
1336 2876 : if (m_poPrivate->m_pszWKTCached &&
1337 762 : strcmp(pszWKT, m_poPrivate->m_pszWKTCached) == 0)
1338 : {
1339 761 : CPLFree(pszWKT);
1340 761 : return m_poPrivate->m_pszWKTCached;
1341 : }
1342 2115 : CPLFree(m_poPrivate->m_pszWKTCached);
1343 2115 : m_poPrivate->m_pszWKTCached = pszWKT;
1344 2115 : return m_poPrivate->m_pszWKTCached;
1345 : }
1346 :
1347 : /************************************************************************/
1348 : /* GetSpatialRef() */
1349 : /************************************************************************/
1350 :
1351 : static thread_local int tlsEnableLayersInGetSpatialRefCounter = 0;
1352 :
1353 : /**
1354 : * \brief Fetch the spatial reference for this dataset.
1355 : *
1356 : * Same as the C function GDALGetSpatialRef().
1357 : *
1358 : * When a projection definition is not available, null is returned. If used on
1359 : * a dataset where there are GCPs and not a geotransform, this method returns
1360 : * null. Use GetGCPSpatialRef() instead.
1361 : *
1362 : * Since GDAL 3.12, the default implementation of this method will iterate over
1363 : * vector layers and return their SRS if all geometry columns of all layers use
1364 : * the same SRS, or nullptr otherwise.
1365 : *
1366 : * @since GDAL 3.0
1367 : *
1368 : * @return a pointer to an internal object. It should not be altered or freed.
1369 : * Its lifetime will be the one of the dataset object.
1370 : *
1371 : * @see https://gdal.org/tutorials/osr_api_tut.html
1372 : */
1373 :
1374 17759 : const OGRSpatialReference *GDALDataset::GetSpatialRef() const
1375 : {
1376 17759 : if (tlsEnableLayersInGetSpatialRefCounter == 0)
1377 17715 : return GetSpatialRefVectorOnly();
1378 44 : return nullptr;
1379 : }
1380 :
1381 : /************************************************************************/
1382 : /* GetSpatialRefVectorOnly() */
1383 : /************************************************************************/
1384 :
1385 : /**
1386 : * \brief Fetch the spatial reference for this dataset (only for vector layers)
1387 : *
1388 : * The default implementation of this method will iterate over
1389 : * vector layers and return their SRS if all geometry columns of all layers use
1390 : * the same SRS, or nullptr otherwise.
1391 : *
1392 : * @since GDAL 3.12
1393 : *
1394 : * @return a pointer to an internal object. It should not be altered or freed.
1395 : * Its lifetime will be the one of the dataset object.
1396 : */
1397 :
1398 17715 : const OGRSpatialReference *GDALDataset::GetSpatialRefVectorOnly() const
1399 : {
1400 17715 : bool bInit = false;
1401 17715 : const OGRSpatialReference *poGlobalSRS = nullptr;
1402 33880 : for (const OGRLayer *poLayer : GetLayers())
1403 : {
1404 16166 : for (const auto *poGeomFieldDefn :
1405 48500 : poLayer->GetLayerDefn()->GetGeomFields())
1406 : {
1407 16169 : const auto *poSRS = poGeomFieldDefn->GetSpatialRef();
1408 16169 : if (!bInit)
1409 : {
1410 209 : bInit = true;
1411 209 : poGlobalSRS = poSRS;
1412 : }
1413 31918 : else if ((poSRS && !poGlobalSRS) || (!poSRS && poGlobalSRS) ||
1414 15958 : (poSRS && poGlobalSRS && !poSRS->IsSame(poGlobalSRS)))
1415 : {
1416 3 : CPLDebug("GDAL",
1417 : "Not all geometry fields or layers have the same CRS");
1418 3 : return nullptr;
1419 : }
1420 : }
1421 : }
1422 17712 : return poGlobalSRS;
1423 : }
1424 :
1425 : /************************************************************************/
1426 : /* GetSpatialRefRasterOnly() */
1427 : /************************************************************************/
1428 :
1429 : /**
1430 : * \brief Fetch the spatial reference for this dataset (ignoring vector layers)
1431 : *
1432 : * @since GDAL 3.12
1433 : *
1434 : * @return a pointer to an internal object. It should not be altered or freed.
1435 : * Its lifetime will be the one of the dataset object.
1436 : */
1437 :
1438 1076 : const OGRSpatialReference *GDALDataset::GetSpatialRefRasterOnly() const
1439 : {
1440 1076 : ++tlsEnableLayersInGetSpatialRefCounter;
1441 1076 : const auto poRet = GetSpatialRef();
1442 1076 : --tlsEnableLayersInGetSpatialRefCounter;
1443 1076 : return poRet;
1444 : }
1445 :
1446 : /************************************************************************/
1447 : /* GDALGetSpatialRef() */
1448 : /************************************************************************/
1449 :
1450 : /**
1451 : * \brief Fetch the spatial reference for this dataset.
1452 : *
1453 : * Same as the C++ method GDALDataset::GetSpatialRef()
1454 : *
1455 : * @since GDAL 3.0
1456 : *
1457 : * @see GDALDataset::GetSpatialRef()
1458 : */
1459 :
1460 8086 : OGRSpatialReferenceH GDALGetSpatialRef(GDALDatasetH hDS)
1461 :
1462 : {
1463 8086 : VALIDATE_POINTER1(hDS, "GDALGetSpatialRef", nullptr);
1464 :
1465 8086 : return OGRSpatialReference::ToHandle(const_cast<OGRSpatialReference *>(
1466 8086 : GDALDataset::FromHandle(hDS)->GetSpatialRef()));
1467 : }
1468 :
1469 : /************************************************************************/
1470 : /* GDALGetProjectionRef() */
1471 : /************************************************************************/
1472 :
1473 : /**
1474 : * \brief Fetch the projection definition string for this dataset.
1475 : *
1476 : * @see GDALDataset::GetProjectionRef()
1477 : */
1478 :
1479 1458 : const char *CPL_STDCALL GDALGetProjectionRef(GDALDatasetH hDS)
1480 :
1481 : {
1482 1458 : VALIDATE_POINTER1(hDS, "GDALGetProjectionRef", nullptr);
1483 :
1484 1458 : return GDALDataset::FromHandle(hDS)->GetProjectionRef();
1485 : }
1486 :
1487 : /************************************************************************/
1488 : /* SetProjection() */
1489 : /************************************************************************/
1490 :
1491 : /**
1492 : * \brief Set the projection reference string for this dataset.
1493 : *
1494 : * The string should be in OGC WKT or PROJ.4 format. An error may occur
1495 : * because of incorrectly specified projection strings, because the dataset
1496 : * is not writable, or because the dataset does not support the indicated
1497 : * projection. Many formats do not support writing projections.
1498 : *
1499 : * This method is the same as the C GDALSetProjection() function.
1500 : *
1501 : * \note Startig with GDAL 3.0, this is a compatibility layer around
1502 : * SetSpatialRef()
1503 :
1504 : * @param pszProjection projection reference string.
1505 : *
1506 : * @return CE_Failure if an error occurs, otherwise CE_None.
1507 : */
1508 :
1509 2605 : CPLErr GDALDataset::SetProjection(const char *pszProjection)
1510 : {
1511 2605 : if (pszProjection && pszProjection[0] != '\0')
1512 : {
1513 4826 : OGRSpatialReference oSRS;
1514 2413 : oSRS.SetAxisMappingStrategy(OAMS_TRADITIONAL_GIS_ORDER);
1515 2413 : if (oSRS.SetFromUserInput(pszProjection) != OGRERR_NONE)
1516 : {
1517 2 : return CE_Failure;
1518 : }
1519 2411 : return SetSpatialRef(&oSRS);
1520 : }
1521 : else
1522 : {
1523 192 : return SetSpatialRef(nullptr);
1524 : }
1525 : }
1526 :
1527 : /************************************************************************/
1528 : /* SetSpatialRef() */
1529 : /************************************************************************/
1530 :
1531 : /**
1532 : * \brief Set the spatial reference system for this dataset.
1533 : *
1534 : * An error may occur because the dataset
1535 : * is not writable, or because the dataset does not support the indicated
1536 : * projection. Many formats do not support writing projections.
1537 : *
1538 : * This method is the same as the C GDALSetSpatialRef() function.
1539 : *
1540 : * @since GDAL 3.0
1541 :
1542 : * @param poSRS spatial reference system object. nullptr can potentially be
1543 : * passed for drivers that support unsetting the SRS.
1544 : *
1545 : * @return CE_Failure if an error occurs, otherwise CE_None.
1546 : */
1547 :
1548 0 : CPLErr GDALDataset::SetSpatialRef(CPL_UNUSED const OGRSpatialReference *poSRS)
1549 : {
1550 0 : if (!(GetMOFlags() & GMO_IGNORE_UNIMPLEMENTED))
1551 0 : ReportError(CE_Failure, CPLE_NotSupported,
1552 : "Dataset does not support the SetSpatialRef() method.");
1553 0 : return CE_Failure;
1554 : }
1555 :
1556 : /************************************************************************/
1557 : /* GDALSetSpatialRef() */
1558 : /************************************************************************/
1559 :
1560 : /**
1561 : * \brief Set the spatial reference system for this dataset.
1562 : *
1563 : * @since GDAL 3.0
1564 : *
1565 : * @see GDALDataset::SetSpatialRef()
1566 : */
1567 :
1568 1470 : CPLErr GDALSetSpatialRef(GDALDatasetH hDS, OGRSpatialReferenceH hSRS)
1569 :
1570 : {
1571 1470 : VALIDATE_POINTER1(hDS, "GDALSetSpatialRef", CE_Failure);
1572 :
1573 2940 : return GDALDataset::FromHandle(hDS)->SetSpatialRef(
1574 1470 : OGRSpatialReference::FromHandle(hSRS));
1575 : }
1576 :
1577 : /************************************************************************/
1578 : /* GDALSetProjection() */
1579 : /************************************************************************/
1580 :
1581 : /**
1582 : * \brief Set the projection reference string for this dataset.
1583 : *
1584 : * @see GDALDataset::SetProjection()
1585 : */
1586 :
1587 1944 : CPLErr CPL_STDCALL GDALSetProjection(GDALDatasetH hDS,
1588 : const char *pszProjection)
1589 :
1590 : {
1591 1944 : VALIDATE_POINTER1(hDS, "GDALSetProjection", CE_Failure);
1592 :
1593 1944 : return GDALDataset::FromHandle(hDS)->SetProjection(pszProjection);
1594 : }
1595 :
1596 : /************************************************************************/
1597 : /* GetGeoTransform() */
1598 : /************************************************************************/
1599 :
1600 : /**
1601 : * \brief Fetch the affine transformation coefficients.
1602 : *
1603 : * Fetches the coefficients for transforming between pixel/line (P,L) raster
1604 : * space, and projection coordinates (Xp,Yp) space.
1605 : *
1606 : * \code
1607 : * Xp = gt.xorig + P*gt.xscale + L*gt.xrot;
1608 : * Yp = gt.yorig + P*padfTransform[4] + L*gt.yscale;
1609 : * \endcode
1610 : *
1611 : * In a north up image, gt.xscale is the pixel width, and
1612 : * gt.yscale is the pixel height. The upper left corner of the
1613 : * upper left pixel is at position (gt.xorig,gt.yorig).
1614 : *
1615 : * The default transform is (0,1,0,0,0,1) and should be returned even when
1616 : * a CE_Failure error is returned, such as for formats that don't support
1617 : * transformation to projection coordinates.
1618 : *
1619 : * This method does the same thing as the C GDALGetGeoTransform() function.
1620 : *
1621 : * @param gt an existing six double buffer into which the
1622 : * transformation will be placed.
1623 : *
1624 : * @return CE_None on success, or CE_Failure if no transform can be fetched.
1625 : *
1626 : * @since 3.12
1627 : */
1628 :
1629 16080 : CPLErr GDALDataset::GetGeoTransform(GDALGeoTransform >) const
1630 :
1631 : {
1632 16080 : gt = GDALGeoTransform();
1633 :
1634 16080 : return CE_Failure;
1635 : }
1636 :
1637 : /************************************************************************/
1638 : /* GetGeoTransform() */
1639 : /************************************************************************/
1640 :
1641 : /**
1642 : * \brief Fetch the affine transformation coefficients.
1643 : *
1644 : * Fetches the coefficients for transforming between pixel/line (P,L) raster
1645 : * space, and projection coordinates (Xp,Yp) space.
1646 : *
1647 : * \code
1648 : * Xp = padfTransform[0] + P*padfTransform[1] + L*padfTransform[2];
1649 : * Yp = padfTransform[3] + P*padfTransform[4] + L*padfTransform[5];
1650 : * \endcode
1651 : *
1652 : * In a north up image, padfTransform[1] is the pixel width, and
1653 : * padfTransform[5] is the pixel height. The upper left corner of the
1654 : * upper left pixel is at position (padfTransform[0],padfTransform[3]).
1655 : *
1656 : * The default transform is (0,1,0,0,0,1) and should be returned even when
1657 : * a CE_Failure error is returned, such as for formats that don't support
1658 : * transformation to projection coordinates.
1659 : *
1660 : * This method does the same thing as the C GDALGetGeoTransform() function.
1661 : *
1662 : * @param padfTransform an existing six double buffer into which the
1663 : * transformation will be placed.
1664 : *
1665 : * @return CE_None on success, or CE_Failure if no transform can be fetched.
1666 : *
1667 : * @deprecated since 3.12. Use GetGeoTransform(GDALGeoTransform&) instead
1668 : */
1669 :
1670 2 : CPLErr GDALDataset::GetGeoTransform(double *padfTransform) const
1671 :
1672 : {
1673 2 : return GetGeoTransform(
1674 2 : *reinterpret_cast<GDALGeoTransform *>(padfTransform));
1675 : }
1676 :
1677 : /************************************************************************/
1678 : /* GDALGetGeoTransform() */
1679 : /************************************************************************/
1680 :
1681 : /**
1682 : * \brief Fetch the affine transformation coefficients.
1683 : *
1684 : * @see GDALDataset::GetGeoTransform()
1685 : */
1686 :
1687 9626 : CPLErr CPL_STDCALL GDALGetGeoTransform(GDALDatasetH hDS, double *padfTransform)
1688 :
1689 : {
1690 9626 : VALIDATE_POINTER1(hDS, "GDALGetGeoTransform", CE_Failure);
1691 :
1692 19252 : return GDALDataset::FromHandle(hDS)->GetGeoTransform(
1693 9626 : *reinterpret_cast<GDALGeoTransform *>(padfTransform));
1694 : }
1695 :
1696 : /************************************************************************/
1697 : /* SetGeoTransform() */
1698 : /************************************************************************/
1699 :
1700 : /**
1701 : * \fn GDALDataset::SetGeoTransform(const GDALGeoTransform&)
1702 : * \brief Set the affine transformation coefficients.
1703 : *
1704 : * See GetGeoTransform() for details on the meaning of the padfTransform
1705 : * coefficients.
1706 : *
1707 : * This method does the same thing as the C GDALSetGeoTransform() function.
1708 : *
1709 : * @param gt the transformation coefficients to be written with the dataset.
1710 : *
1711 : * @return CE_None on success, or CE_Failure if this transform cannot be
1712 : * written.
1713 : *
1714 : * @since 3.12
1715 : */
1716 :
1717 0 : CPLErr GDALDataset::SetGeoTransform(CPL_UNUSED const GDALGeoTransform >)
1718 :
1719 : {
1720 0 : if (!(GetMOFlags() & GMO_IGNORE_UNIMPLEMENTED))
1721 0 : ReportError(CE_Failure, CPLE_NotSupported,
1722 : "SetGeoTransform() not supported for this dataset.");
1723 :
1724 0 : return CE_Failure;
1725 : }
1726 :
1727 : /************************************************************************/
1728 : /* SetGeoTransform() */
1729 : /************************************************************************/
1730 :
1731 : /**
1732 : * \brief Set the affine transformation coefficients.
1733 : *
1734 : * See GetGeoTransform() for details on the meaning of the padfTransform
1735 : * coefficients.
1736 : *
1737 : * This method does the same thing as the C GDALSetGeoTransform() function.
1738 : *
1739 : * @param padfTransform a six double buffer containing the transformation
1740 : * coefficients to be written with the dataset.
1741 : *
1742 : * @return CE_None on success, or CE_Failure if this transform cannot be
1743 : * written.
1744 : *
1745 : * @deprecated since 3.12. Use SetGeoTransform(const GDALGeoTransform&) instead
1746 : */
1747 38 : CPLErr GDALDataset::SetGeoTransform(const double *padfTransform)
1748 :
1749 : {
1750 38 : return SetGeoTransform(
1751 38 : *reinterpret_cast<const GDALGeoTransform *>(padfTransform));
1752 : }
1753 :
1754 : /************************************************************************/
1755 : /* GDALSetGeoTransform() */
1756 : /************************************************************************/
1757 :
1758 : /**
1759 : * \brief Set the affine transformation coefficients.
1760 : *
1761 : * @see GDALDataset::SetGeoTransform()
1762 : */
1763 :
1764 4488 : CPLErr CPL_STDCALL GDALSetGeoTransform(GDALDatasetH hDS,
1765 : const double *padfTransform)
1766 :
1767 : {
1768 4488 : VALIDATE_POINTER1(hDS, "GDALSetGeoTransform", CE_Failure);
1769 4488 : VALIDATE_POINTER1(padfTransform, "GDALSetGeoTransform", CE_Failure);
1770 :
1771 8976 : return GDALDataset::FromHandle(hDS)->SetGeoTransform(
1772 4488 : *reinterpret_cast<const GDALGeoTransform *>(padfTransform));
1773 : }
1774 :
1775 : /************************************************************************/
1776 : /* GetInternalHandle() */
1777 : /************************************************************************/
1778 :
1779 : /**
1780 : * \fn GDALDataset::GetInternalHandle(const char*)
1781 : * \brief Fetch a format specific internally meaningful handle.
1782 : *
1783 : * This method is the same as the C GDALGetInternalHandle() method.
1784 : *
1785 : * @param pszHandleName the handle name desired. The meaningful names
1786 : * will be specific to the file format.
1787 : *
1788 : * @return the desired handle value, or NULL if not recognized/supported.
1789 : */
1790 :
1791 172 : void *GDALDataset::GetInternalHandle(CPL_UNUSED const char *pszHandleName)
1792 :
1793 : {
1794 172 : return nullptr;
1795 : }
1796 :
1797 : /************************************************************************/
1798 : /* GDALGetInternalHandle() */
1799 : /************************************************************************/
1800 :
1801 : /**
1802 : * \brief Fetch a format specific internally meaningful handle.
1803 : *
1804 : * @see GDALDataset::GetInternalHandle()
1805 : */
1806 :
1807 61 : void *CPL_STDCALL GDALGetInternalHandle(GDALDatasetH hDS,
1808 : const char *pszRequest)
1809 :
1810 : {
1811 61 : VALIDATE_POINTER1(hDS, "GDALGetInternalHandle", nullptr);
1812 :
1813 61 : return GDALDataset::FromHandle(hDS)->GetInternalHandle(pszRequest);
1814 : }
1815 :
1816 : /************************************************************************/
1817 : /* GetDriver() */
1818 : /************************************************************************/
1819 :
1820 : /**
1821 : * \brief Fetch the driver to which this dataset relates.
1822 : *
1823 : * This method is the same as the C GDALGetDatasetDriver() function.
1824 : *
1825 : * @return the driver on which the dataset was created with GDALOpen() or
1826 : * GDALCreate().
1827 : */
1828 :
1829 36342 : GDALDriver *GDALDataset::GetDriver() const
1830 : {
1831 36342 : return poDriver;
1832 : }
1833 :
1834 : /************************************************************************/
1835 : /* GDALGetDatasetDriver() */
1836 : /************************************************************************/
1837 :
1838 : /**
1839 : * \brief Fetch the driver to which this dataset relates.
1840 : *
1841 : * @see GDALDataset::GetDriver()
1842 : */
1843 :
1844 2827 : GDALDriverH CPL_STDCALL GDALGetDatasetDriver(GDALDatasetH hDataset)
1845 :
1846 : {
1847 2827 : VALIDATE_POINTER1(hDataset, "GDALGetDatasetDriver", nullptr);
1848 :
1849 : return static_cast<GDALDriverH>(
1850 2827 : GDALDataset::FromHandle(hDataset)->GetDriver());
1851 : }
1852 :
1853 : /************************************************************************/
1854 : /* Reference() */
1855 : /************************************************************************/
1856 :
1857 : /**
1858 : * \brief Add one to dataset reference count.
1859 : *
1860 : * The reference is one after instantiation.
1861 : *
1862 : * This method is the same as the C GDALReferenceDataset() function.
1863 : *
1864 : * @return the post-increment reference count.
1865 : */
1866 :
1867 263792 : int GDALDataset::Reference()
1868 : {
1869 263792 : return ++nRefCount;
1870 : }
1871 :
1872 : /************************************************************************/
1873 : /* GDALReferenceDataset() */
1874 : /************************************************************************/
1875 :
1876 : /**
1877 : * \brief Add one to dataset reference count.
1878 : *
1879 : * @see GDALDataset::Reference()
1880 : */
1881 :
1882 1503 : int CPL_STDCALL GDALReferenceDataset(GDALDatasetH hDataset)
1883 :
1884 : {
1885 1503 : VALIDATE_POINTER1(hDataset, "GDALReferenceDataset", 0);
1886 :
1887 1503 : return GDALDataset::FromHandle(hDataset)->Reference();
1888 : }
1889 :
1890 : /************************************************************************/
1891 : /* Dereference() */
1892 : /************************************************************************/
1893 :
1894 : /**
1895 : * \brief Subtract one from dataset reference count.
1896 : *
1897 : * The reference is one after instantiation. Generally when the reference
1898 : * count has dropped to zero the dataset may be safely deleted (closed).
1899 : *
1900 : * This method is the same as the C GDALDereferenceDataset() function.
1901 : *
1902 : * @return the post-decrement reference count.
1903 : */
1904 :
1905 327876 : int GDALDataset::Dereference()
1906 : {
1907 327876 : return --nRefCount;
1908 : }
1909 :
1910 : /************************************************************************/
1911 : /* GDALDereferenceDataset() */
1912 : /************************************************************************/
1913 :
1914 : /**
1915 : * \brief Subtract one from dataset reference count.
1916 : *
1917 : * @see GDALDataset::Dereference()
1918 : */
1919 :
1920 61944 : int CPL_STDCALL GDALDereferenceDataset(GDALDatasetH hDataset)
1921 :
1922 : {
1923 61944 : VALIDATE_POINTER1(hDataset, "GDALDereferenceDataset", 0);
1924 :
1925 61944 : return GDALDataset::FromHandle(hDataset)->Dereference();
1926 : }
1927 :
1928 : /************************************************************************/
1929 : /* ReleaseRef() */
1930 : /************************************************************************/
1931 :
1932 : /**
1933 : * \brief Drop a reference to this object, and destroy if no longer referenced.
1934 : * @return TRUE if the object has been destroyed.
1935 : */
1936 :
1937 253138 : int GDALDataset::ReleaseRef()
1938 :
1939 : {
1940 253138 : if (Dereference() <= 0)
1941 : {
1942 7773 : nRefCount = 1;
1943 7773 : delete this;
1944 7773 : return TRUE;
1945 : }
1946 245365 : return FALSE;
1947 : }
1948 :
1949 : /************************************************************************/
1950 : /* GDALReleaseDataset() */
1951 : /************************************************************************/
1952 :
1953 : /**
1954 : * \brief Drop a reference to this object, and destroy if no longer referenced.
1955 : *
1956 : * @see GDALDataset::ReleaseRef()
1957 : */
1958 :
1959 1689 : int CPL_STDCALL GDALReleaseDataset(GDALDatasetH hDataset)
1960 :
1961 : {
1962 1689 : VALIDATE_POINTER1(hDataset, "GDALReleaseDataset", 0);
1963 :
1964 1689 : return GDALDataset::FromHandle(hDataset)->ReleaseRef();
1965 : }
1966 :
1967 : /************************************************************************/
1968 : /* GetShared() */
1969 : /************************************************************************/
1970 :
1971 : /**
1972 : * \brief Returns shared flag.
1973 : *
1974 : * @return TRUE if the GDALDataset is available for sharing, or FALSE if not.
1975 : */
1976 :
1977 323551 : int GDALDataset::GetShared() const
1978 : {
1979 323551 : return bShared;
1980 : }
1981 :
1982 : /************************************************************************/
1983 : /* MarkAsShared() */
1984 : /************************************************************************/
1985 :
1986 : /**
1987 : * \brief Mark this dataset as available for sharing.
1988 : */
1989 :
1990 448 : void GDALDataset::MarkAsShared()
1991 :
1992 : {
1993 448 : CPLAssert(!bShared);
1994 :
1995 448 : bShared = true;
1996 448 : if (bIsInternal)
1997 32 : return;
1998 :
1999 416 : GIntBig nPID = GDALGetResponsiblePIDForCurrentThread();
2000 :
2001 : // Insert the dataset in the set of shared opened datasets.
2002 832 : CPLMutexHolderD(&hDLMutex);
2003 416 : if (phSharedDatasetSet == nullptr)
2004 274 : phSharedDatasetSet =
2005 274 : CPLHashSetNew(GDALSharedDatasetHashFunc, GDALSharedDatasetEqualFunc,
2006 : GDALSharedDatasetFreeFunc);
2007 :
2008 : SharedDatasetCtxt *psStruct =
2009 416 : static_cast<SharedDatasetCtxt *>(CPLMalloc(sizeof(SharedDatasetCtxt)));
2010 416 : psStruct->poDS = this;
2011 416 : psStruct->nPID = nPID;
2012 416 : psStruct->nOpenFlags = nOpenFlags & ~GDAL_OF_SHARED;
2013 416 : psStruct->pszDescription = CPLStrdup(GetDescription());
2014 : std::string osConcatenatedOpenOptions =
2015 832 : GDALSharedDatasetConcatenateOpenOptions(papszOpenOptions);
2016 416 : psStruct->pszConcatenatedOpenOptions =
2017 416 : CPLStrdup(osConcatenatedOpenOptions.c_str());
2018 416 : if (CPLHashSetLookup(phSharedDatasetSet, psStruct) != nullptr)
2019 : {
2020 1 : GDALSharedDatasetFreeFunc(psStruct);
2021 1 : ReportError(CE_Failure, CPLE_AppDefined,
2022 : "An existing shared dataset already has this description. "
2023 : "This should not happen.");
2024 : }
2025 : else
2026 : {
2027 415 : CPLHashSetInsert(phSharedDatasetSet, psStruct);
2028 :
2029 415 : (*poAllDatasetMap)[this] = nPID;
2030 : }
2031 : }
2032 :
2033 : /************************************************************************/
2034 : /* MarkSuppressOnClose() */
2035 : /************************************************************************/
2036 :
2037 : /** Set that the dataset must be deleted on close.
2038 : *
2039 : * This is the same as C function GDALDatasetMarkSuppressOnClose()
2040 : */
2041 1252 : void GDALDataset::MarkSuppressOnClose()
2042 : {
2043 1252 : bSuppressOnClose = true;
2044 1252 : }
2045 :
2046 : /************************************************************************/
2047 : /* GDALDatasetMarkSuppressOnClose() */
2048 : /************************************************************************/
2049 :
2050 : /** Set that the dataset must be deleted on close.
2051 : *
2052 : * This is the same as C++ method GDALDataset::MarkSuppressOnClose()
2053 : *
2054 : * @since GDAL 3.12
2055 : */
2056 :
2057 4 : void GDALDatasetMarkSuppressOnClose(GDALDatasetH hDS)
2058 : {
2059 4 : VALIDATE_POINTER0(hDS, "GDALDatasetMarkSuppressOnClose");
2060 :
2061 4 : return GDALDataset::FromHandle(hDS)->MarkSuppressOnClose();
2062 : }
2063 :
2064 : /************************************************************************/
2065 : /* UnMarkSuppressOnClose() */
2066 : /************************************************************************/
2067 :
2068 : /** Remove the flag requesting the dataset to be deleted on close. */
2069 684 : void GDALDataset::UnMarkSuppressOnClose()
2070 : {
2071 684 : bSuppressOnClose = false;
2072 684 : }
2073 :
2074 : /************************************************************************/
2075 : /* CleanupPostFileClosing() */
2076 : /************************************************************************/
2077 :
2078 : /** This method should be called by driver implementations in their destructor,
2079 : * after having closed all files, but before having freed resources that
2080 : * are needed for their GetFileList() implementation.
2081 : * This is used to implement MarkSuppressOnClose behavior.
2082 : */
2083 259 : void GDALDataset::CleanupPostFileClosing()
2084 : {
2085 259 : if (IsMarkedSuppressOnClose())
2086 : {
2087 1 : char **papszFileList = GetFileList();
2088 3 : for (int i = 0; papszFileList && papszFileList[i]; ++i)
2089 2 : VSIUnlink(papszFileList[i]);
2090 1 : CSLDestroy(papszFileList);
2091 : }
2092 259 : }
2093 :
2094 : /************************************************************************/
2095 : /* GetGCPCount() */
2096 : /************************************************************************/
2097 :
2098 : /**
2099 : * \brief Get number of GCPs.
2100 : *
2101 : * This method is the same as the C function GDALGetGCPCount().
2102 : *
2103 : * @return number of GCPs for this dataset. Zero if there are none.
2104 : */
2105 :
2106 16673 : int GDALDataset::GetGCPCount()
2107 : {
2108 16673 : return 0;
2109 : }
2110 :
2111 : /************************************************************************/
2112 : /* GDALGetGCPCount() */
2113 : /************************************************************************/
2114 :
2115 : /**
2116 : * \brief Get number of GCPs.
2117 : *
2118 : * @see GDALDataset::GetGCPCount()
2119 : */
2120 :
2121 2318 : int CPL_STDCALL GDALGetGCPCount(GDALDatasetH hDS)
2122 :
2123 : {
2124 2318 : VALIDATE_POINTER1(hDS, "GDALGetGCPCount", 0);
2125 :
2126 2318 : return GDALDataset::FromHandle(hDS)->GetGCPCount();
2127 : }
2128 :
2129 : /************************************************************************/
2130 : /* GetGCPProjection() */
2131 : /************************************************************************/
2132 :
2133 : /**
2134 : * \brief Get output projection for GCPs.
2135 : *
2136 : * This method is the same as the C function GDALGetGCPProjection().
2137 : *
2138 : * The projection string follows the normal rules from GetProjectionRef().
2139 : *
2140 : * \note Starting with GDAL 3.0, this is a compatibility layer around
2141 : * GetGCPSpatialRef()
2142 : *
2143 : * @return internal projection string or "" if there are no GCPs.
2144 : * It should not be altered, freed or expected to last for long.
2145 : */
2146 :
2147 1053 : const char *GDALDataset::GetGCPProjection() const
2148 : {
2149 1053 : const auto poSRS = GetGCPSpatialRef();
2150 1053 : if (!poSRS || !m_poPrivate)
2151 : {
2152 715 : return "";
2153 : }
2154 338 : char *pszWKT = nullptr;
2155 338 : poSRS->exportToWkt(&pszWKT);
2156 338 : if (!pszWKT)
2157 : {
2158 0 : return "";
2159 : }
2160 :
2161 : // If called on a thread-safe dataset, we might be called by several
2162 : // threads, so make sure our accesses to m_pszWKTCached are protected
2163 : // by a mutex.
2164 676 : std::lock_guard oLock(m_poPrivate->m_oMutexWKT);
2165 338 : if (m_poPrivate->m_pszWKTGCPCached &&
2166 258 : strcmp(pszWKT, m_poPrivate->m_pszWKTGCPCached) == 0)
2167 : {
2168 258 : CPLFree(pszWKT);
2169 258 : return m_poPrivate->m_pszWKTGCPCached;
2170 : }
2171 80 : CPLFree(m_poPrivate->m_pszWKTGCPCached);
2172 80 : m_poPrivate->m_pszWKTGCPCached = pszWKT;
2173 80 : return m_poPrivate->m_pszWKTGCPCached;
2174 : }
2175 :
2176 : /************************************************************************/
2177 : /* GetGCPSpatialRef() */
2178 : /************************************************************************/
2179 :
2180 : /**
2181 : * \brief Get output spatial reference system for GCPs.
2182 : *
2183 : * Same as the C function GDALGetGCPSpatialRef().
2184 : *
2185 : * When a SRS is not available, null is returned. If used on
2186 : * a dataset where there is a geotransform, and not GCPs, this method returns
2187 : * null. Use GetSpatialRef() instead.
2188 : *
2189 : * @since GDAL 3.0
2190 : *
2191 : * @return a pointer to an internal object. It should not be altered or freed.
2192 : * Its lifetime will be the one of the dataset object, or until the next
2193 : * call to this method.
2194 : */
2195 :
2196 47 : const OGRSpatialReference *GDALDataset::GetGCPSpatialRef() const
2197 : {
2198 47 : return nullptr;
2199 : }
2200 :
2201 : /************************************************************************/
2202 : /* GDALGetGCPSpatialRef() */
2203 : /************************************************************************/
2204 :
2205 : /**
2206 : * \brief Get output spatial reference system for GCPs.
2207 : *
2208 : * @since GDAL 3.0
2209 : *
2210 : * @see GDALDataset::GetGCPSpatialRef()
2211 : */
2212 :
2213 472 : OGRSpatialReferenceH GDALGetGCPSpatialRef(GDALDatasetH hDS)
2214 :
2215 : {
2216 472 : VALIDATE_POINTER1(hDS, "GDALGetGCPSpatialRef", nullptr);
2217 :
2218 472 : return OGRSpatialReference::ToHandle(const_cast<OGRSpatialReference *>(
2219 472 : GDALDataset::FromHandle(hDS)->GetGCPSpatialRef()));
2220 : }
2221 :
2222 : /************************************************************************/
2223 : /* GDALGetGCPProjection() */
2224 : /************************************************************************/
2225 :
2226 : /**
2227 : * \brief Get output projection for GCPs.
2228 : *
2229 : * @see GDALDataset::GetGCPProjection()
2230 : */
2231 :
2232 1032 : const char *CPL_STDCALL GDALGetGCPProjection(GDALDatasetH hDS)
2233 :
2234 : {
2235 1032 : VALIDATE_POINTER1(hDS, "GDALGetGCPProjection", nullptr);
2236 :
2237 1032 : return GDALDataset::FromHandle(hDS)->GetGCPProjection();
2238 : }
2239 :
2240 : /************************************************************************/
2241 : /* GetGCPs() */
2242 : /************************************************************************/
2243 :
2244 : /**
2245 : * \brief Fetch GCPs.
2246 : *
2247 : * This method is the same as the C function GDALGetGCPs().
2248 : *
2249 : * @return pointer to internal GCP structure list. It should not be modified,
2250 : * and may change on the next GDAL call.
2251 : */
2252 :
2253 11 : const GDAL_GCP *GDALDataset::GetGCPs()
2254 : {
2255 11 : return nullptr;
2256 : }
2257 :
2258 : /************************************************************************/
2259 : /* GDALGetGCPs() */
2260 : /************************************************************************/
2261 :
2262 : /**
2263 : * \brief Fetch GCPs.
2264 : *
2265 : * @see GDALDataset::GetGCPs()
2266 : */
2267 :
2268 582 : const GDAL_GCP *CPL_STDCALL GDALGetGCPs(GDALDatasetH hDS)
2269 :
2270 : {
2271 582 : VALIDATE_POINTER1(hDS, "GDALGetGCPs", nullptr);
2272 :
2273 582 : return GDALDataset::FromHandle(hDS)->GetGCPs();
2274 : }
2275 :
2276 : /************************************************************************/
2277 : /* SetGCPs() */
2278 : /************************************************************************/
2279 :
2280 : /**
2281 : * \brief Assign GCPs.
2282 : *
2283 : * This method is the same as the C function GDALSetGCPs().
2284 : *
2285 : * This method assigns the passed set of GCPs to this dataset, as well as
2286 : * setting their coordinate system. Internally copies are made of the
2287 : * coordinate system and list of points, so the caller remains responsible for
2288 : * deallocating these arguments if appropriate.
2289 : *
2290 : * Most formats do not support setting of GCPs, even formats that can
2291 : * handle GCPs. These formats will return CE_Failure.
2292 : *
2293 : * \note Startig with GDAL 3.0, this is a compatibility layer around
2294 : * SetGCPs(int, const GDAL_GCP*, const char*)
2295 : *
2296 : * @param nGCPCount number of GCPs being assigned.
2297 : *
2298 : * @param pasGCPList array of GCP structures being assign (nGCPCount in array).
2299 : *
2300 : * @param pszGCPProjection the new OGC WKT coordinate system to assign for the
2301 : * GCP output coordinates. This parameter should be "" if no output coordinate
2302 : * system is known.
2303 : *
2304 : * @return CE_None on success, CE_Failure on failure (including if action is
2305 : * not supported for this format).
2306 : */
2307 :
2308 52 : CPLErr GDALDataset::SetGCPs(int nGCPCount, const GDAL_GCP *pasGCPList,
2309 : const char *pszGCPProjection)
2310 :
2311 : {
2312 52 : if (pszGCPProjection && pszGCPProjection[0] != '\0')
2313 : {
2314 66 : OGRSpatialReference oSRS;
2315 33 : oSRS.SetAxisMappingStrategy(OAMS_TRADITIONAL_GIS_ORDER);
2316 33 : if (oSRS.importFromWkt(pszGCPProjection) != OGRERR_NONE)
2317 : {
2318 0 : return CE_Failure;
2319 : }
2320 33 : return SetGCPs(nGCPCount, pasGCPList, &oSRS);
2321 : }
2322 : else
2323 : {
2324 19 : return SetGCPs(nGCPCount, pasGCPList,
2325 19 : static_cast<const OGRSpatialReference *>(nullptr));
2326 : }
2327 : }
2328 :
2329 : /************************************************************************/
2330 : /* SetGCPs() */
2331 : /************************************************************************/
2332 :
2333 : /**
2334 : * \brief Assign GCPs.
2335 : *
2336 : * This method is the same as the C function GDALSetGCPs().
2337 : *
2338 : * This method assigns the passed set of GCPs to this dataset, as well as
2339 : * setting their coordinate system. Internally copies are made of the
2340 : * coordinate system and list of points, so the caller remains responsible for
2341 : * deallocating these arguments if appropriate.
2342 : *
2343 : * Most formats do not support setting of GCPs, even formats that can
2344 : * handle GCPs. These formats will return CE_Failure.
2345 : *
2346 : * @since GDAL 3.0
2347 : *
2348 : * @param nGCPCount number of GCPs being assigned.
2349 : *
2350 : * @param pasGCPList array of GCP structures being assign (nGCPCount in array).
2351 : *
2352 : * @param poGCP_SRS the new coordinate reference system to assign for the
2353 : * GCP output coordinates. This parameter should be null if no output
2354 : * coordinate system is known.
2355 : *
2356 : * @return CE_None on success, CE_Failure on failure (including if action is
2357 : * not supported for this format).
2358 : */
2359 :
2360 1 : CPLErr GDALDataset::SetGCPs(CPL_UNUSED int nGCPCount,
2361 : CPL_UNUSED const GDAL_GCP *pasGCPList,
2362 : CPL_UNUSED const OGRSpatialReference *poGCP_SRS)
2363 :
2364 : {
2365 1 : if (!(GetMOFlags() & GMO_IGNORE_UNIMPLEMENTED))
2366 1 : ReportError(CE_Failure, CPLE_NotSupported,
2367 : "Dataset does not support the SetGCPs() method.");
2368 :
2369 1 : return CE_Failure;
2370 : }
2371 :
2372 : /************************************************************************/
2373 : /* GDALSetGCPs() */
2374 : /************************************************************************/
2375 :
2376 : /**
2377 : * \brief Assign GCPs.
2378 : *
2379 : * @see GDALDataset::SetGCPs(int, const GDAL_GCP*, const char*)
2380 : */
2381 :
2382 29 : CPLErr CPL_STDCALL GDALSetGCPs(GDALDatasetH hDS, int nGCPCount,
2383 : const GDAL_GCP *pasGCPList,
2384 : const char *pszGCPProjection)
2385 :
2386 : {
2387 29 : VALIDATE_POINTER1(hDS, "GDALSetGCPs", CE_Failure);
2388 :
2389 29 : return GDALDataset::FromHandle(hDS)->SetGCPs(nGCPCount, pasGCPList,
2390 29 : pszGCPProjection);
2391 : }
2392 :
2393 : /************************************************************************/
2394 : /* GDALSetGCPs2() */
2395 : /************************************************************************/
2396 :
2397 : /**
2398 : * \brief Assign GCPs.
2399 : *
2400 : * @since GDAL 3.0
2401 : * @see GDALDataset::SetGCPs(int, const GDAL_GCP*, const OGRSpatialReference*)
2402 : */
2403 :
2404 10 : CPLErr GDALSetGCPs2(GDALDatasetH hDS, int nGCPCount, const GDAL_GCP *pasGCPList,
2405 : OGRSpatialReferenceH hSRS)
2406 :
2407 : {
2408 10 : VALIDATE_POINTER1(hDS, "GDALSetGCPs2", CE_Failure);
2409 :
2410 20 : return GDALDataset::FromHandle(hDS)->SetGCPs(
2411 10 : nGCPCount, pasGCPList, OGRSpatialReference::FromHandle(hSRS));
2412 : }
2413 :
2414 : /************************************************************************/
2415 : /* BuildOverviews() */
2416 : /************************************************************************/
2417 :
2418 : /**
2419 : * \brief Build raster overview(s)
2420 : *
2421 : * If the operation is not supported for the indicated dataset, then
2422 : * CE_Failure is returned, and CPLGetLastErrorNo() will return
2423 : * CPLE_NotSupported.
2424 : *
2425 : * Depending on the actual file format, all overviews level can be also
2426 : * deleted by specifying nOverviews == 0. This works at least for external
2427 : * overviews (.ovr), TIFF internal overviews, etc.
2428 : *
2429 : * Starting with GDAL 3.2, the GDAL_NUM_THREADS configuration option can be set
2430 : * to "ALL_CPUS" or a integer value to specify the number of threads to use for
2431 : * overview computation.
2432 : *
2433 : * This method is the same as the C function GDALBuildOverviewsEx().
2434 : *
2435 : * @param pszResampling one of "AVERAGE", "AVERAGE_MAGPHASE", "RMS",
2436 : * "BILINEAR", "CUBIC", "CUBICSPLINE", "GAUSS", "LANCZOS", "MODE", "NEAREST",
2437 : * or "NONE" controlling the downsampling method applied.
2438 : * @param nOverviews number of overviews to build, or 0 to clean overviews.
2439 : * @param panOverviewList the list of overview decimation factors (positive
2440 : * integers, normally larger or equal to 2) to build, or
2441 : * NULL if nOverviews == 0.
2442 : * @param nListBands number of bands to build overviews for in panBandList.
2443 : * Build for all bands if this is 0.
2444 : * @param panBandList list of band numbers.
2445 : * @param pfnProgress a function to call to report progress, or NULL.
2446 : * @param pProgressData application data to pass to the progress function.
2447 : * @param papszOptions (GDAL >= 3.6) NULL terminated list of options as
2448 : * key=value pairs, or NULL.
2449 : * Possible keys are the ones returned by
2450 : * GetDriver()->GetMetadataItem(GDAL_DMD_OVERVIEW_CREATIONOPTIONLIST)
2451 : *
2452 : * @return CE_None on success or CE_Failure if the operation doesn't work.
2453 : *
2454 : * For example, to build overview level 2, 4 and 8 on all bands the following
2455 : * call could be made:
2456 : * \code{.cpp}
2457 : * int anOverviewList[3] = { 2, 4, 8 };
2458 : *
2459 : * poDataset->BuildOverviews( "NEAREST", 3, anOverviewList, 0, nullptr,
2460 : * GDALDummyProgress, nullptr );
2461 : * \endcode
2462 : *
2463 : * @see GDALRegenerateOverviewsEx()
2464 : */
2465 :
2466 755 : CPLErr GDALDataset::BuildOverviews(const char *pszResampling, int nOverviews,
2467 : const int *panOverviewList, int nListBands,
2468 : const int *panBandList,
2469 : GDALProgressFunc pfnProgress,
2470 : void *pProgressData,
2471 : CSLConstList papszOptions)
2472 : {
2473 755 : int *panAllBandList = nullptr;
2474 :
2475 1510 : CPLStringList aosOptions(papszOptions);
2476 755 : if (poDriver && !aosOptions.empty())
2477 : {
2478 : const char *pszOptionList =
2479 28 : poDriver->GetMetadataItem(GDAL_DMD_OVERVIEW_CREATIONOPTIONLIST);
2480 28 : if (pszOptionList)
2481 : {
2482 : // For backwards compatibility
2483 28 : if (const char *opt = aosOptions.FetchNameValue("USE_RRD"))
2484 : {
2485 4 : if (strstr(pszOptionList, "<Value>RRD</Value>") &&
2486 2 : aosOptions.FetchNameValue("LOCATION") == nullptr)
2487 : {
2488 2 : if (CPLTestBool(opt))
2489 2 : aosOptions.SetNameValue("LOCATION", "RRD");
2490 2 : aosOptions.SetNameValue("USE_RRD", nullptr);
2491 : }
2492 : }
2493 28 : if (const char *opt =
2494 28 : aosOptions.FetchNameValue("VRT_VIRTUAL_OVERVIEWS"))
2495 : {
2496 3 : if (strstr(pszOptionList, "VIRTUAL"))
2497 : {
2498 3 : aosOptions.SetNameValue("VIRTUAL", opt);
2499 3 : aosOptions.SetNameValue("VRT_VIRTUAL_OVERVIEWS", nullptr);
2500 : }
2501 : }
2502 :
2503 76 : for (const auto &[pszKey, pszValue] :
2504 104 : cpl::IterateNameValue(papszOptions))
2505 : {
2506 38 : if (cpl::ends_with(std::string_view(pszKey), "_OVERVIEW"))
2507 : {
2508 : aosOptions.SetNameValue(
2509 16 : std::string(pszKey)
2510 16 : .substr(0, strlen(pszKey) - strlen("_OVERVIEW"))
2511 : .c_str(),
2512 16 : pszValue);
2513 8 : aosOptions.SetNameValue(pszKey, nullptr);
2514 : }
2515 : }
2516 :
2517 56 : CPLString osDriver;
2518 28 : osDriver.Printf("driver %s", poDriver->GetDescription());
2519 28 : GDALValidateOptions(pszOptionList, aosOptions.List(),
2520 : "overview creation option", osDriver);
2521 : }
2522 : }
2523 :
2524 755 : if (nListBands == 0)
2525 : {
2526 743 : nListBands = GetRasterCount();
2527 : panAllBandList =
2528 743 : static_cast<int *>(CPLMalloc(sizeof(int) * nListBands));
2529 67483 : for (int i = 0; i < nListBands; ++i)
2530 66740 : panAllBandList[i] = i + 1;
2531 :
2532 743 : panBandList = panAllBandList;
2533 : }
2534 :
2535 755 : if (pfnProgress == nullptr)
2536 720 : pfnProgress = GDALDummyProgress;
2537 :
2538 1844 : for (int i = 0; i < nOverviews; ++i)
2539 : {
2540 1090 : if (panOverviewList[i] <= 0)
2541 : {
2542 1 : CPLError(CE_Failure, CPLE_IllegalArg,
2543 : "panOverviewList[%d] = %d is invalid. It must be a "
2544 : "positive value",
2545 1 : i, panOverviewList[i]);
2546 1 : CPLFree(panAllBandList);
2547 1 : return CE_Failure;
2548 : }
2549 : }
2550 :
2551 754 : const CPLErr eErr = IBuildOverviews(
2552 : pszResampling, nOverviews, panOverviewList, nListBands, panBandList,
2553 754 : pfnProgress, pProgressData, aosOptions.List());
2554 :
2555 754 : if (panAllBandList != nullptr)
2556 741 : CPLFree(panAllBandList);
2557 :
2558 754 : return eErr;
2559 : }
2560 :
2561 : /************************************************************************/
2562 : /* GDALBuildOverviews() */
2563 : /************************************************************************/
2564 :
2565 : /**
2566 : * \brief Build raster overview(s)
2567 : *
2568 : * @see GDALDataset::BuildOverviews() and GDALBuildOverviews()
2569 : */
2570 :
2571 27 : CPLErr CPL_STDCALL GDALBuildOverviews(GDALDatasetH hDataset,
2572 : const char *pszResampling, int nOverviews,
2573 : const int *panOverviewList,
2574 : int nListBands, const int *panBandList,
2575 : GDALProgressFunc pfnProgress,
2576 : void *pProgressData)
2577 :
2578 : {
2579 27 : VALIDATE_POINTER1(hDataset, "GDALBuildOverviews", CE_Failure);
2580 :
2581 27 : return GDALDataset::FromHandle(hDataset)->BuildOverviews(
2582 : pszResampling, nOverviews, panOverviewList, nListBands, panBandList,
2583 27 : pfnProgress, pProgressData, nullptr);
2584 : }
2585 :
2586 : /************************************************************************/
2587 : /* GDALBuildOverviews() */
2588 : /************************************************************************/
2589 :
2590 : /**
2591 : * \brief Build raster overview(s)
2592 : *
2593 : * @see GDALDataset::BuildOverviews()
2594 : * @since GDAL 3.6
2595 : */
2596 :
2597 : CPLErr CPL_STDCALL
2598 707 : GDALBuildOverviewsEx(GDALDatasetH hDataset, const char *pszResampling,
2599 : int nOverviews, const int *panOverviewList, int nListBands,
2600 : const int *panBandList, GDALProgressFunc pfnProgress,
2601 : void *pProgressData, CSLConstList papszOptions)
2602 :
2603 : {
2604 707 : VALIDATE_POINTER1(hDataset, "GDALBuildOverviews", CE_Failure);
2605 :
2606 707 : return GDALDataset::FromHandle(hDataset)->BuildOverviews(
2607 : pszResampling, nOverviews, panOverviewList, nListBands, panBandList,
2608 707 : pfnProgress, pProgressData, papszOptions);
2609 : }
2610 :
2611 : /************************************************************************/
2612 : /* IBuildOverviews() */
2613 : /* */
2614 : /* Default implementation. */
2615 : /************************************************************************/
2616 :
2617 : //! @cond Doxygen_Suppress
2618 198 : CPLErr GDALDataset::IBuildOverviews(const char *pszResampling, int nOverviews,
2619 : const int *panOverviewList, int nListBands,
2620 : const int *panBandList,
2621 : GDALProgressFunc pfnProgress,
2622 : void *pProgressData,
2623 : CSLConstList papszOptions)
2624 :
2625 : {
2626 198 : if (oOvManager.IsInitialized())
2627 197 : return oOvManager.BuildOverviews(
2628 : nullptr, pszResampling, nOverviews, panOverviewList, nListBands,
2629 197 : panBandList, pfnProgress, pProgressData, papszOptions);
2630 : else
2631 : {
2632 1 : ReportError(CE_Failure, CPLE_NotSupported,
2633 : "BuildOverviews() not supported for this dataset.");
2634 :
2635 1 : return CE_Failure;
2636 : }
2637 : }
2638 :
2639 : //! @endcond
2640 :
2641 : /************************************************************************/
2642 : /* AddOverviews() */
2643 : /* */
2644 : /* Default implementation. */
2645 : /************************************************************************/
2646 :
2647 : /**
2648 : * \brief Add overview from existing dataset(s)
2649 : *
2650 : * This function creates new overview levels or refresh existing one from
2651 : * the list of provided overview datasets.
2652 : * Source overviews may come from any GDAL supported format, provided they
2653 : * have the same number of bands and geospatial extent than the target
2654 : * dataset.
2655 : *
2656 : * If the operation is not supported for the indicated dataset, then
2657 : * CE_Failure is returned, and CPLGetLastErrorNo() will return
2658 : * CPLE_NotSupported.
2659 : *
2660 : * At time of writing, this method is only implemented for internal overviews
2661 : * of GeoTIFF datasets and external overviews in GeoTIFF format.
2662 : *
2663 : * @param apoSrcOvrDS Vector of source overviews.
2664 : * @param pfnProgress a function to call to report progress, or NULL.
2665 : * @param pProgressData application data to pass to the progress function.
2666 : * @param papszOptions NULL terminated list of options as
2667 : * key=value pairs, or NULL. Possible keys are the
2668 : * ones returned by
2669 : * GetDriver()->GetMetadataItem(GDAL_DMD_OVERVIEW_CREATIONOPTIONLIST)
2670 : *
2671 : * @return CE_None on success or CE_Failure if the operation doesn't work.
2672 : * @since 3.12
2673 : */
2674 5 : CPLErr GDALDataset::AddOverviews(const std::vector<GDALDataset *> &apoSrcOvrDS,
2675 : GDALProgressFunc pfnProgress,
2676 : void *pProgressData, CSLConstList papszOptions)
2677 : {
2678 5 : if (oOvManager.IsInitialized())
2679 : {
2680 4 : return oOvManager.AddOverviews(nullptr, apoSrcOvrDS, pfnProgress,
2681 4 : pProgressData, papszOptions);
2682 : }
2683 : else
2684 : {
2685 1 : ReportError(CE_Failure, CPLE_NotSupported,
2686 : "AddOverviews() not supported for this dataset.");
2687 1 : return CE_Failure;
2688 : }
2689 : }
2690 :
2691 : /************************************************************************/
2692 : /* IRasterIO() */
2693 : /* */
2694 : /* The default implementation of IRasterIO() is, in the general */
2695 : /* case to pass the request off to each band objects rasterio */
2696 : /* methods with appropriate arguments. In some cases, it might */
2697 : /* choose instead the BlockBasedRasterIO() implementation. */
2698 : /************************************************************************/
2699 :
2700 : //! @cond Doxygen_Suppress
2701 449174 : CPLErr GDALDataset::IRasterIO(GDALRWFlag eRWFlag, int nXOff, int nYOff,
2702 : int nXSize, int nYSize, void *pData,
2703 : int nBufXSize, int nBufYSize,
2704 : GDALDataType eBufType, int nBandCount,
2705 : BANDMAP_TYPE panBandMap, GSpacing nPixelSpace,
2706 : GSpacing nLineSpace, GSpacing nBandSpace,
2707 : GDALRasterIOExtraArg *psExtraArg)
2708 :
2709 : {
2710 449174 : const char *pszInterleave = nullptr;
2711 :
2712 449174 : CPLAssert(nullptr != pData);
2713 :
2714 449174 : const bool bHasSubpixelShift =
2715 454737 : psExtraArg->bFloatingPointWindowValidity &&
2716 453180 : psExtraArg->eResampleAlg != GRIORA_NearestNeighbour &&
2717 4006 : (nXOff != psExtraArg->dfXOff || nYOff != psExtraArg->dfYOff);
2718 :
2719 449055 : if (!bHasSubpixelShift && nXSize == nBufXSize && nYSize == nBufYSize &&
2720 71560 : nBandCount > 1 &&
2721 71560 : (pszInterleave = GetMetadataItem("INTERLEAVE", "IMAGE_STRUCTURE")) !=
2722 898229 : nullptr &&
2723 68379 : EQUAL(pszInterleave, "PIXEL"))
2724 : {
2725 64956 : return BlockBasedRasterIO(eRWFlag, nXOff, nYOff, nXSize, nYSize, pData,
2726 : nBufXSize, nBufYSize, eBufType, nBandCount,
2727 : panBandMap, nPixelSpace, nLineSpace,
2728 64956 : nBandSpace, psExtraArg);
2729 : }
2730 :
2731 384218 : if (eRWFlag == GF_Read &&
2732 204624 : (psExtraArg->eResampleAlg == GRIORA_Cubic ||
2733 203835 : psExtraArg->eResampleAlg == GRIORA_CubicSpline ||
2734 203828 : psExtraArg->eResampleAlg == GRIORA_Bilinear ||
2735 204624 : psExtraArg->eResampleAlg == GRIORA_Lanczos) &&
2736 958 : !(nXSize == nBufXSize && nYSize == nBufYSize) && nBandCount > 1)
2737 : {
2738 936 : if (nBufXSize < nXSize && nBufYSize < nYSize && AreOverviewsEnabled())
2739 : {
2740 725 : int bTried = FALSE;
2741 725 : const CPLErr eErr = TryOverviewRasterIO(
2742 : eRWFlag, nXOff, nYOff, nXSize, nYSize, pData, nBufXSize,
2743 : nBufYSize, eBufType, nBandCount, panBandMap, nPixelSpace,
2744 : nLineSpace, nBandSpace, psExtraArg, &bTried);
2745 725 : if (bTried)
2746 1 : return eErr;
2747 : }
2748 :
2749 935 : GDALDataType eFirstBandDT = GDT_Unknown;
2750 935 : int nFirstMaskFlags = 0;
2751 935 : GDALRasterBand *poFirstMaskBand = nullptr;
2752 935 : int nOKBands = 0;
2753 :
2754 : // Check if bands share the same mask band
2755 2939 : for (int i = 0; i < nBandCount; ++i)
2756 : {
2757 2664 : GDALRasterBand *poBand = GetRasterBand(panBandMap[i]);
2758 4653 : if ((nBufXSize < nXSize || nBufYSize < nYSize) &&
2759 1989 : poBand->GetOverviewCount())
2760 : {
2761 : // Could be improved to select the appropriate overview.
2762 3 : break;
2763 : }
2764 2661 : if (poBand->GetColorTable() != nullptr)
2765 : {
2766 0 : break;
2767 : }
2768 2661 : const GDALDataType eDT = poBand->GetRasterDataType();
2769 2661 : if (GDALDataTypeIsComplex(eDT))
2770 : {
2771 30 : break;
2772 : }
2773 2631 : if (i == 0)
2774 : {
2775 902 : eFirstBandDT = eDT;
2776 902 : nFirstMaskFlags = poBand->GetMaskFlags();
2777 902 : if (nFirstMaskFlags == GMF_NODATA)
2778 : {
2779 : // The dataset-level resampling code is not ready for nodata
2780 : // Fallback to band-level resampling
2781 10 : break;
2782 : }
2783 892 : poFirstMaskBand = poBand->GetMaskBand();
2784 : }
2785 : else
2786 : {
2787 1729 : if (eDT != eFirstBandDT)
2788 : {
2789 0 : break;
2790 : }
2791 1729 : int nMaskFlags = poBand->GetMaskFlags();
2792 1729 : if (nMaskFlags == GMF_NODATA)
2793 : {
2794 : // The dataset-level resampling code is not ready for nodata
2795 : // Fallback to band-level resampling
2796 0 : break;
2797 : }
2798 1729 : GDALRasterBand *poMaskBand = poBand->GetMaskBand();
2799 1729 : if (nFirstMaskFlags == GMF_ALL_VALID &&
2800 : nMaskFlags == GMF_ALL_VALID)
2801 : {
2802 : // Ok.
2803 : }
2804 1077 : else if (poFirstMaskBand == poMaskBand)
2805 : {
2806 : // Ok.
2807 : }
2808 : else
2809 : {
2810 617 : break;
2811 : }
2812 : }
2813 :
2814 2004 : ++nOKBands;
2815 : }
2816 :
2817 935 : GDALProgressFunc pfnProgressGlobal = psExtraArg->pfnProgress;
2818 935 : void *pProgressDataGlobal = psExtraArg->pProgressData;
2819 :
2820 935 : CPLErr eErr = CE_None;
2821 935 : if (nOKBands > 0)
2822 : {
2823 892 : if (nOKBands < nBandCount)
2824 : {
2825 617 : psExtraArg->pfnProgress = GDALScaledProgress;
2826 1234 : psExtraArg->pProgressData = GDALCreateScaledProgress(
2827 617 : 0.0, static_cast<double>(nOKBands) / nBandCount,
2828 : pfnProgressGlobal, pProgressDataGlobal);
2829 617 : if (psExtraArg->pProgressData == nullptr)
2830 228 : psExtraArg->pfnProgress = nullptr;
2831 : }
2832 :
2833 892 : eErr = RasterIOResampled(eRWFlag, nXOff, nYOff, nXSize, nYSize,
2834 : pData, nBufXSize, nBufYSize, eBufType,
2835 : nOKBands, panBandMap, nPixelSpace,
2836 : nLineSpace, nBandSpace, psExtraArg);
2837 :
2838 892 : if (nOKBands < nBandCount)
2839 : {
2840 617 : GDALDestroyScaledProgress(psExtraArg->pProgressData);
2841 : }
2842 : }
2843 935 : if (eErr == CE_None && nOKBands < nBandCount)
2844 : {
2845 657 : if (nOKBands > 0)
2846 : {
2847 614 : psExtraArg->pfnProgress = GDALScaledProgress;
2848 1228 : psExtraArg->pProgressData = GDALCreateScaledProgress(
2849 614 : static_cast<double>(nOKBands) / nBandCount, 1.0,
2850 : pfnProgressGlobal, pProgressDataGlobal);
2851 614 : if (psExtraArg->pProgressData == nullptr)
2852 225 : psExtraArg->pfnProgress = nullptr;
2853 : }
2854 1314 : eErr = BandBasedRasterIO(
2855 : eRWFlag, nXOff, nYOff, nXSize, nYSize,
2856 657 : static_cast<GByte *>(pData) + nBandSpace * nOKBands, nBufXSize,
2857 : nBufYSize, eBufType, nBandCount - nOKBands,
2858 657 : panBandMap + nOKBands, nPixelSpace, nLineSpace, nBandSpace,
2859 : psExtraArg);
2860 657 : if (nOKBands > 0)
2861 : {
2862 614 : GDALDestroyScaledProgress(psExtraArg->pProgressData);
2863 : }
2864 : }
2865 :
2866 935 : psExtraArg->pfnProgress = pfnProgressGlobal;
2867 935 : psExtraArg->pProgressData = pProgressDataGlobal;
2868 :
2869 935 : return eErr;
2870 : }
2871 :
2872 383282 : return BandBasedRasterIO(eRWFlag, nXOff, nYOff, nXSize, nYSize, pData,
2873 : nBufXSize, nBufYSize, eBufType, nBandCount,
2874 : panBandMap, nPixelSpace, nLineSpace, nBandSpace,
2875 383282 : psExtraArg);
2876 : }
2877 :
2878 : //! @endcond
2879 :
2880 : /************************************************************************/
2881 : /* BandBasedRasterIO() */
2882 : /* */
2883 : /* Pass the request off to each band objects rasterio methods with */
2884 : /* appropriate arguments. */
2885 : /************************************************************************/
2886 :
2887 : //! @cond Doxygen_Suppress
2888 647251 : CPLErr GDALDataset::BandBasedRasterIO(
2889 : GDALRWFlag eRWFlag, int nXOff, int nYOff, int nXSize, int nYSize,
2890 : void *pData, int nBufXSize, int nBufYSize, GDALDataType eBufType,
2891 : int nBandCount, const int *panBandMap, GSpacing nPixelSpace,
2892 : GSpacing nLineSpace, GSpacing nBandSpace, GDALRasterIOExtraArg *psExtraArg)
2893 :
2894 : {
2895 : int iBandIndex;
2896 647251 : CPLErr eErr = CE_None;
2897 :
2898 647251 : GDALProgressFunc pfnProgressGlobal = psExtraArg->pfnProgress;
2899 647251 : void *pProgressDataGlobal = psExtraArg->pProgressData;
2900 :
2901 1661490 : for (iBandIndex = 0; iBandIndex < nBandCount && eErr == CE_None;
2902 : ++iBandIndex)
2903 : {
2904 1014240 : GDALRasterBand *poBand = GetRasterBand(panBandMap[iBandIndex]);
2905 :
2906 1014240 : if (poBand == nullptr)
2907 : {
2908 0 : eErr = CE_Failure;
2909 0 : break;
2910 : }
2911 :
2912 1014240 : GByte *pabyBandData =
2913 1014240 : static_cast<GByte *>(pData) + iBandIndex * nBandSpace;
2914 :
2915 1014240 : if (nBandCount > 1)
2916 : {
2917 545001 : psExtraArg->pfnProgress = GDALScaledProgress;
2918 1090000 : psExtraArg->pProgressData = GDALCreateScaledProgress(
2919 : 1.0 * iBandIndex / nBandCount,
2920 545001 : 1.0 * (iBandIndex + 1) / nBandCount, pfnProgressGlobal,
2921 : pProgressDataGlobal);
2922 545001 : if (psExtraArg->pProgressData == nullptr)
2923 531402 : psExtraArg->pfnProgress = nullptr;
2924 : }
2925 :
2926 2028480 : eErr = poBand->IRasterIO(eRWFlag, nXOff, nYOff, nXSize, nYSize,
2927 : pabyBandData, nBufXSize, nBufYSize, eBufType,
2928 1014240 : nPixelSpace, nLineSpace, psExtraArg);
2929 :
2930 1014240 : if (nBandCount > 1)
2931 545001 : GDALDestroyScaledProgress(psExtraArg->pProgressData);
2932 : }
2933 :
2934 647251 : psExtraArg->pfnProgress = pfnProgressGlobal;
2935 647251 : psExtraArg->pProgressData = pProgressDataGlobal;
2936 :
2937 647251 : return eErr;
2938 : }
2939 :
2940 : //! @endcond
2941 :
2942 : /************************************************************************/
2943 : /* ValidateRasterIOOrAdviseReadParameters() */
2944 : /************************************************************************/
2945 :
2946 : //! @cond Doxygen_Suppress
2947 752069 : CPLErr GDALDataset::ValidateRasterIOOrAdviseReadParameters(
2948 : const char *pszCallingFunc, int *pbStopProcessingOnCENone, int nXOff,
2949 : int nYOff, int nXSize, int nYSize, int nBufXSize, int nBufYSize,
2950 : int nBandCount, const int *panBandMap)
2951 : {
2952 752069 : if (nBands == 0)
2953 : {
2954 137 : *pbStopProcessingOnCENone = TRUE;
2955 137 : return CE_None;
2956 : }
2957 :
2958 : /* -------------------------------------------------------------------- */
2959 : /* Some size values are "noop". Lets just return to avoid */
2960 : /* stressing lower level functions. */
2961 : /* -------------------------------------------------------------------- */
2962 751932 : if (nXSize < 1 || nYSize < 1 || nBufXSize < 1 || nBufYSize < 1)
2963 : {
2964 9 : CPLDebug("GDAL",
2965 : "%s skipped for odd window or buffer size.\n"
2966 : " Window = (%d,%d)x%dx%d\n"
2967 : " Buffer = %dx%d",
2968 : pszCallingFunc, nXOff, nYOff, nXSize, nYSize, nBufXSize,
2969 : nBufYSize);
2970 :
2971 9 : *pbStopProcessingOnCENone = TRUE;
2972 9 : return CE_None;
2973 : }
2974 :
2975 751923 : CPLErr eErr = CE_None;
2976 751923 : *pbStopProcessingOnCENone = FALSE;
2977 :
2978 751923 : if (nXOff < 0 || nXSize > nRasterXSize - nXOff || nYOff < 0 ||
2979 751921 : nYSize > nRasterYSize - nYOff)
2980 : {
2981 2 : ReportError(CE_Failure, CPLE_IllegalArg,
2982 : "Access window out of range in %s. Requested "
2983 : "(%d,%d) of size %dx%d on raster of %dx%d.",
2984 : pszCallingFunc, nXOff, nYOff, nXSize, nYSize, nRasterXSize,
2985 : nRasterYSize);
2986 2 : eErr = CE_Failure;
2987 : }
2988 :
2989 751923 : if (panBandMap == nullptr && nBandCount > GetRasterCount())
2990 : {
2991 0 : ReportError(CE_Failure, CPLE_IllegalArg,
2992 : "%s: nBandCount cannot be greater than %d", pszCallingFunc,
2993 : GetRasterCount());
2994 0 : eErr = CE_Failure;
2995 : }
2996 :
2997 2249380 : for (int i = 0; i < nBandCount && eErr == CE_None; ++i)
2998 : {
2999 1497450 : int iBand = (panBandMap != nullptr) ? panBandMap[i] : i + 1;
3000 1497450 : if (iBand < 1 || iBand > GetRasterCount())
3001 : {
3002 3 : ReportError(
3003 : CE_Failure, CPLE_IllegalArg,
3004 : "%s: panBandMap[%d] = %d, this band does not exist on dataset.",
3005 : pszCallingFunc, i, iBand);
3006 3 : eErr = CE_Failure;
3007 : }
3008 :
3009 1497450 : if (eErr == CE_None && GetRasterBand(iBand) == nullptr)
3010 : {
3011 0 : ReportError(
3012 : CE_Failure, CPLE_IllegalArg,
3013 : "%s: panBandMap[%d]=%d, this band should exist but is NULL!",
3014 : pszCallingFunc, i, iBand);
3015 0 : eErr = CE_Failure;
3016 : }
3017 : }
3018 :
3019 751923 : return eErr;
3020 : }
3021 :
3022 : //! @endcond
3023 :
3024 : /************************************************************************/
3025 : /* RasterIO() */
3026 : /************************************************************************/
3027 :
3028 : /**
3029 : * \brief Read/write a region of image data from multiple bands.
3030 : *
3031 : * This method allows reading a region of one or more GDALRasterBands from
3032 : * this dataset into a buffer, or writing data from a buffer into a region
3033 : * of the GDALRasterBands. It automatically takes care of data type
3034 : * translation if the data type (eBufType) of the buffer is different than
3035 : * that of the GDALRasterBand.
3036 : * The method also takes care of image decimation / replication if the
3037 : * buffer size (nBufXSize x nBufYSize) is different than the size of the
3038 : * region being accessed (nXSize x nYSize).
3039 : *
3040 : * The window of interest expressed by (nXOff, nYOff, nXSize, nYSize) should be
3041 : * fully within the raster space, that is nXOff >= 0, nYOff >= 0,
3042 : * nXOff + nXSize <= GetRasterXSize() and nYOff + nYSize <= GetRasterYSize().
3043 : * If reads larger than the raster space are wished, GDALTranslate() might be used.
3044 : * Or use nLineSpace and a possibly shifted pData value.
3045 : *
3046 : * The nPixelSpace, nLineSpace and nBandSpace parameters allow reading into or
3047 : * writing from various organization of buffers.
3048 : *
3049 : * Some formats may efficiently implement decimation into a buffer by
3050 : * reading from lower resolution overview images. The logic of the default
3051 : * implementation in the base class GDALRasterBand is the following one. It
3052 : * computes a target_downscaling_factor from the window of interest and buffer
3053 : * size which is min(nXSize/nBufXSize, nYSize/nBufYSize).
3054 : * It then walks through overviews and will select the first one whose
3055 : * downscaling factor is greater than target_downscaling_factor / 1.2.
3056 : *
3057 : * Let's assume we have overviews at downscaling factors 2, 4 and 8.
3058 : * The relationship between target_downscaling_factor and the select overview
3059 : * level is the following one:
3060 : *
3061 : * target_downscaling_factor | selected_overview
3062 : * ------------------------- | -----------------
3063 : * ]0, 2 / 1.2] | full resolution band
3064 : * ]2 / 1.2, 4 / 1.2] | 2x downsampled band
3065 : * ]4 / 1.2, 8 / 1.2] | 4x downsampled band
3066 : * ]8 / 1.2, infinity[ | 8x downsampled band
3067 : *
3068 : * Note that starting with GDAL 3.9, this 1.2 oversampling factor can be
3069 : * modified by setting the GDAL_OVERVIEW_OVERSAMPLING_THRESHOLD configuration
3070 : * option. Also note that starting with GDAL 3.9, when the resampling algorithm
3071 : * specified in psExtraArg->eResampleAlg is different from GRIORA_NearestNeighbour,
3072 : * this oversampling threshold defaults to 1. Consequently if there are overviews
3073 : * of downscaling factor 2, 4 and 8, and the desired downscaling factor is
3074 : * 7.99, the overview of factor 4 will be selected for a non nearest resampling.
3075 : *
3076 : * For highest performance full resolution data access, read and write
3077 : * on "block boundaries" as returned by GetBlockSize(), or use the
3078 : * ReadBlock() and WriteBlock() methods.
3079 : *
3080 : * This method is the same as the C GDALDatasetRasterIO() or
3081 : * GDALDatasetRasterIOEx() functions.
3082 : *
3083 : * @param eRWFlag Either GF_Read to read a region of data, or GF_Write to
3084 : * write a region of data.
3085 : *
3086 : * @param nXOff The pixel offset to the top left corner of the region
3087 : * of the band to be accessed. This would be zero to start from the left side.
3088 : *
3089 : * @param nYOff The line offset to the top left corner of the region
3090 : * of the band to be accessed. This would be zero to start from the top.
3091 : *
3092 : * @param nXSize The width of the region of the band to be accessed in pixels.
3093 : *
3094 : * @param nYSize The height of the region of the band to be accessed in lines.
3095 : *
3096 : * @param pData The buffer into which the data should be read, or from which
3097 : * it should be written. This buffer must contain at least
3098 : * nBufXSize * nBufYSize * nBandCount words of type eBufType. It is organized
3099 : * in left to right,top to bottom pixel order. Spacing is controlled by the
3100 : * nPixelSpace, and nLineSpace parameters.
3101 : * Note that even with eRWFlag==GF_Write, the content of the buffer might be
3102 : * temporarily modified during the execution of this method (and eventually
3103 : * restored back to its original content), so it is not safe to use a buffer
3104 : * stored in a read-only section of the calling program.
3105 : *
3106 : * @param nBufXSize the width of the buffer image into which the desired region
3107 : * is to be read, or from which it is to be written.
3108 : *
3109 : * @param nBufYSize the height of the buffer image into which the desired
3110 : * region is to be read, or from which it is to be written.
3111 : *
3112 : * @param eBufType the type of the pixel values in the pData data buffer. The
3113 : * pixel values will automatically be translated to/from the GDALRasterBand
3114 : * data type as needed. Most driver implementations will use GDALCopyWords64()
3115 : * to perform data type translation.
3116 : *
3117 : * @param nBandCount the number of bands being read or written.
3118 : *
3119 : * @param panBandMap the list of nBandCount band numbers being read/written.
3120 : * Note band numbers are 1 based. This may be NULL to select the first
3121 : * nBandCount bands. (Note: before GDAL 3.10, argument type was "int*", and
3122 : * not "const int*")
3123 : *
3124 : * @param nPixelSpace The byte offset from the start of one pixel value in
3125 : * pData to the start of the next pixel value within a scanline. If defaulted
3126 : * (0) the size of the datatype eBufType is used.
3127 : *
3128 : * @param nLineSpace The byte offset from the start of one scanline in
3129 : * pData to the start of the next. If defaulted (0) the size of the datatype
3130 : * eBufType * nBufXSize is used.
3131 : *
3132 : * @param nBandSpace the byte offset from the start of one bands data to the
3133 : * start of the next. If defaulted (0) the value will be
3134 : * nLineSpace * nBufYSize implying band sequential organization
3135 : * of the data buffer.
3136 : *
3137 : * @param psExtraArg pointer to a GDALRasterIOExtraArg
3138 : * structure with additional arguments to specify resampling and progress
3139 : * callback, or NULL for default behavior. The GDAL_RASTERIO_RESAMPLING
3140 : * configuration option can also be defined to override the default resampling
3141 : * to one of BILINEAR, CUBIC, CUBICSPLINE, LANCZOS, AVERAGE or MODE.
3142 : *
3143 : * @return CE_Failure if the access fails, otherwise CE_None.
3144 : */
3145 :
3146 736515 : CPLErr GDALDataset::RasterIO(GDALRWFlag eRWFlag, int nXOff, int nYOff,
3147 : int nXSize, int nYSize, void *pData, int nBufXSize,
3148 : int nBufYSize, GDALDataType eBufType,
3149 : int nBandCount, const int *panBandMap,
3150 : GSpacing nPixelSpace, GSpacing nLineSpace,
3151 : GSpacing nBandSpace,
3152 : GDALRasterIOExtraArg *psExtraArg)
3153 :
3154 : {
3155 : GDALRasterIOExtraArg sExtraArg;
3156 736515 : if (psExtraArg == nullptr)
3157 : {
3158 538453 : INIT_RASTERIO_EXTRA_ARG(sExtraArg);
3159 :
3160 : // 4 below inits are not strictly needed but make Coverity Scan
3161 : // happy
3162 538453 : sExtraArg.dfXOff = nXOff;
3163 538453 : sExtraArg.dfYOff = nYOff;
3164 538453 : sExtraArg.dfXSize = nXSize;
3165 538453 : sExtraArg.dfYSize = nYSize;
3166 :
3167 538453 : psExtraArg = &sExtraArg;
3168 : }
3169 198062 : else if (CPL_UNLIKELY(psExtraArg->nVersion >
3170 : RASTERIO_EXTRA_ARG_CURRENT_VERSION))
3171 : {
3172 0 : ReportError(CE_Failure, CPLE_AppDefined,
3173 : "Unhandled version of GDALRasterIOExtraArg");
3174 0 : return CE_Failure;
3175 : }
3176 :
3177 736515 : GDALRasterIOExtraArgSetResampleAlg(psExtraArg, nXSize, nYSize, nBufXSize,
3178 : nBufYSize);
3179 :
3180 736515 : if (CPL_UNLIKELY(nullptr == pData))
3181 : {
3182 0 : ReportError(CE_Failure, CPLE_AppDefined,
3183 : "The buffer into which the data should be read is null");
3184 0 : return CE_Failure;
3185 : }
3186 :
3187 : /* -------------------------------------------------------------------- */
3188 : /* Do some validation of parameters. */
3189 : /* -------------------------------------------------------------------- */
3190 :
3191 736515 : if (CPL_UNLIKELY(eRWFlag != GF_Read && eRWFlag != GF_Write))
3192 : {
3193 0 : ReportError(
3194 : CE_Failure, CPLE_IllegalArg,
3195 : "eRWFlag = %d, only GF_Read (0) and GF_Write (1) are legal.",
3196 : eRWFlag);
3197 0 : return CE_Failure;
3198 : }
3199 :
3200 736515 : if (eRWFlag == GF_Write)
3201 : {
3202 216627 : if (CPL_UNLIKELY(eAccess != GA_Update))
3203 : {
3204 2 : ReportError(CE_Failure, CPLE_AppDefined,
3205 : "Write operation not permitted on dataset opened "
3206 : "in read-only mode");
3207 2 : return CE_Failure;
3208 : }
3209 : }
3210 :
3211 736513 : int bStopProcessing = FALSE;
3212 736513 : CPLErr eErr = ValidateRasterIOOrAdviseReadParameters(
3213 : "RasterIO()", &bStopProcessing, nXOff, nYOff, nXSize, nYSize, nBufXSize,
3214 : nBufYSize, nBandCount, panBandMap);
3215 736513 : if (eErr != CE_None || bStopProcessing)
3216 9 : return eErr;
3217 736504 : if (CPL_UNLIKELY(eBufType == GDT_Unknown || eBufType == GDT_TypeCount))
3218 : {
3219 2 : ReportError(CE_Failure, CPLE_AppDefined,
3220 : "Illegal GDT_Unknown/GDT_TypeCount argument");
3221 2 : return CE_Failure;
3222 : }
3223 :
3224 : /* -------------------------------------------------------------------- */
3225 : /* If pixel and line spacing are defaulted assign reasonable */
3226 : /* value assuming a packed buffer. */
3227 : /* -------------------------------------------------------------------- */
3228 736502 : if (nPixelSpace == 0)
3229 425273 : nPixelSpace = GDALGetDataTypeSizeBytes(eBufType);
3230 :
3231 736502 : if (nLineSpace == 0)
3232 : {
3233 482588 : nLineSpace = nPixelSpace * nBufXSize;
3234 : }
3235 :
3236 736502 : if (nBandSpace == 0 && nBandCount > 1)
3237 : {
3238 67401 : nBandSpace = nLineSpace * nBufYSize;
3239 : }
3240 :
3241 736502 : if (panBandMap == nullptr)
3242 : {
3243 356322 : if (!m_poPrivate)
3244 0 : return CE_Failure;
3245 356322 : CPLAssert(static_cast<int>(m_poPrivate->m_anBandMap.size()) == nBands);
3246 356322 : panBandMap = m_poPrivate->m_anBandMap.data();
3247 : }
3248 :
3249 736502 : int bCallLeaveReadWrite = EnterReadWrite(eRWFlag);
3250 :
3251 : /* -------------------------------------------------------------------- */
3252 : /* We are being forced to use cached IO instead of a driver */
3253 : /* specific implementation. */
3254 : /* -------------------------------------------------------------------- */
3255 736502 : if (bForceCachedIO)
3256 : {
3257 21 : eErr = BlockBasedRasterIO(eRWFlag, nXOff, nYOff, nXSize, nYSize, pData,
3258 : nBufXSize, nBufYSize, eBufType, nBandCount,
3259 : panBandMap, nPixelSpace, nLineSpace,
3260 21 : nBandSpace, psExtraArg);
3261 : }
3262 :
3263 : /* -------------------------------------------------------------------- */
3264 : /* Call the format specific function. */
3265 : /* -------------------------------------------------------------------- */
3266 : else
3267 : {
3268 736481 : eErr = IRasterIO(eRWFlag, nXOff, nYOff, nXSize, nYSize, pData,
3269 : nBufXSize, nBufYSize, eBufType, nBandCount,
3270 : // TODO: remove this const_cast once IRasterIO()
3271 : // takes a const int*
3272 : const_cast<int *>(panBandMap), nPixelSpace, nLineSpace,
3273 736481 : nBandSpace, psExtraArg);
3274 : }
3275 :
3276 736502 : if (bCallLeaveReadWrite)
3277 413591 : LeaveReadWrite();
3278 :
3279 736502 : return eErr;
3280 : }
3281 :
3282 : /************************************************************************/
3283 : /* GDALDatasetRasterIO() */
3284 : /************************************************************************/
3285 :
3286 : /**
3287 : * \brief Read/write a region of image data from multiple bands.
3288 : *
3289 : * Use GDALDatasetRasterIOEx() if 64 bit spacings or extra arguments (resampling
3290 : * resolution, progress callback, etc. are needed)
3291 : *
3292 : * Note: before GDAL 3.10, panBandMap type was "int*", and not "const int*"
3293 : *
3294 : * @see GDALDataset::RasterIO()
3295 : */
3296 :
3297 4762 : CPLErr CPL_STDCALL GDALDatasetRasterIO(GDALDatasetH hDS, GDALRWFlag eRWFlag,
3298 : int nXOff, int nYOff, int nXSize,
3299 : int nYSize, void *pData, int nBufXSize,
3300 : int nBufYSize, GDALDataType eBufType,
3301 : int nBandCount, const int *panBandMap,
3302 : int nPixelSpace, int nLineSpace,
3303 : int nBandSpace)
3304 :
3305 : {
3306 4762 : VALIDATE_POINTER1(hDS, "GDALDatasetRasterIO", CE_Failure);
3307 :
3308 4762 : GDALDataset *poDS = GDALDataset::FromHandle(hDS);
3309 :
3310 4762 : return poDS->RasterIO(eRWFlag, nXOff, nYOff, nXSize, nYSize, pData,
3311 : nBufXSize, nBufYSize, eBufType, nBandCount,
3312 : panBandMap, nPixelSpace, nLineSpace, nBandSpace,
3313 4762 : nullptr);
3314 : }
3315 :
3316 : /************************************************************************/
3317 : /* GDALDatasetRasterIOEx() */
3318 : /************************************************************************/
3319 :
3320 : /**
3321 : * \brief Read/write a region of image data from multiple bands.
3322 : *
3323 : * Note: before GDAL 3.10, panBandMap type was "int*", and not "const int*"
3324 : *
3325 : * @see GDALDataset::RasterIO()
3326 : */
3327 :
3328 353671 : CPLErr CPL_STDCALL GDALDatasetRasterIOEx(
3329 : GDALDatasetH hDS, GDALRWFlag eRWFlag, int nXOff, int nYOff, int nXSize,
3330 : int nYSize, void *pData, int nBufXSize, int nBufYSize,
3331 : GDALDataType eBufType, int nBandCount, const int *panBandMap,
3332 : GSpacing nPixelSpace, GSpacing nLineSpace, GSpacing nBandSpace,
3333 : GDALRasterIOExtraArg *psExtraArg)
3334 :
3335 : {
3336 353671 : VALIDATE_POINTER1(hDS, "GDALDatasetRasterIOEx", CE_Failure);
3337 :
3338 353671 : GDALDataset *poDS = GDALDataset::FromHandle(hDS);
3339 :
3340 353671 : return poDS->RasterIO(eRWFlag, nXOff, nYOff, nXSize, nYSize, pData,
3341 : nBufXSize, nBufYSize, eBufType, nBandCount,
3342 : panBandMap, nPixelSpace, nLineSpace, nBandSpace,
3343 353671 : psExtraArg);
3344 : }
3345 :
3346 : /************************************************************************/
3347 : /* GetOpenDatasets() */
3348 : /************************************************************************/
3349 :
3350 : /**
3351 : * \brief Fetch all open GDAL dataset handles.
3352 : *
3353 : * This method is the same as the C function GDALGetOpenDatasets().
3354 : *
3355 : * NOTE: This method is not thread safe. The returned list may change
3356 : * at any time and it should not be freed.
3357 : *
3358 : * @param pnCount integer into which to place the count of dataset pointers
3359 : * being returned.
3360 : *
3361 : * @return a pointer to an array of dataset handles.
3362 : */
3363 :
3364 2287 : GDALDataset **GDALDataset::GetOpenDatasets(int *pnCount)
3365 :
3366 : {
3367 4574 : CPLMutexHolderD(&hDLMutex);
3368 :
3369 2287 : if (poAllDatasetMap == nullptr)
3370 : {
3371 2266 : *pnCount = 0;
3372 2266 : return nullptr;
3373 : }
3374 :
3375 21 : *pnCount = static_cast<int>(poAllDatasetMap->size());
3376 21 : ppDatasets = static_cast<GDALDataset **>(
3377 21 : CPLRealloc(ppDatasets, (*pnCount) * sizeof(GDALDataset *)));
3378 21 : std::map<GDALDataset *, GIntBig>::iterator oIter = poAllDatasetMap->begin();
3379 599 : for (int i = 0; oIter != poAllDatasetMap->end(); ++oIter, ++i)
3380 578 : ppDatasets[i] = oIter->first;
3381 21 : return ppDatasets;
3382 : }
3383 :
3384 : /************************************************************************/
3385 : /* GDALGetOpenDatasets() */
3386 : /************************************************************************/
3387 :
3388 : /**
3389 : * \brief Fetch all open GDAL dataset handles.
3390 : *
3391 : * @see GDALDataset::GetOpenDatasets()
3392 : */
3393 :
3394 0 : void CPL_STDCALL GDALGetOpenDatasets(GDALDatasetH **ppahDSList, int *pnCount)
3395 :
3396 : {
3397 0 : VALIDATE_POINTER0(ppahDSList, "GDALGetOpenDatasets");
3398 0 : VALIDATE_POINTER0(pnCount, "GDALGetOpenDatasets");
3399 :
3400 0 : *ppahDSList =
3401 0 : reinterpret_cast<GDALDatasetH *>(GDALDataset::GetOpenDatasets(pnCount));
3402 : }
3403 :
3404 : /************************************************************************/
3405 : /* GDALCleanOpenDatasetsList() */
3406 : /************************************************************************/
3407 :
3408 : // Useful when called from the child of a fork(), to avoid closing
3409 : // the datasets of the parent at the child termination.
3410 0 : void GDALNullifyOpenDatasetsList()
3411 : {
3412 0 : poAllDatasetMap = nullptr;
3413 0 : phSharedDatasetSet = nullptr;
3414 0 : ppDatasets = nullptr;
3415 0 : hDLMutex = nullptr;
3416 0 : }
3417 :
3418 : /************************************************************************/
3419 : /* GDALGetAccess() */
3420 : /************************************************************************/
3421 :
3422 : /**
3423 : * \brief Return access flag
3424 : *
3425 : * @see GDALDataset::GetAccess()
3426 : */
3427 :
3428 1 : int CPL_STDCALL GDALGetAccess(GDALDatasetH hDS)
3429 : {
3430 1 : VALIDATE_POINTER1(hDS, "GDALGetAccess", 0);
3431 :
3432 1 : return GDALDataset::FromHandle(hDS)->GetAccess();
3433 : }
3434 :
3435 : /************************************************************************/
3436 : /* AdviseRead() */
3437 : /************************************************************************/
3438 :
3439 : /**
3440 : * \brief Advise driver of upcoming read requests.
3441 : *
3442 : * Some GDAL drivers operate more efficiently if they know in advance what
3443 : * set of upcoming read requests will be made. The AdviseRead() method allows
3444 : * an application to notify the driver of the region and bands of interest,
3445 : * and at what resolution the region will be read.
3446 : *
3447 : * Many drivers just ignore the AdviseRead() call, but it can dramatically
3448 : * accelerate access via some drivers.
3449 : *
3450 : * Depending on call paths, drivers might receive several calls to
3451 : * AdviseRead() with the same parameters.
3452 : *
3453 : * @param nXOff The pixel offset to the top left corner of the region
3454 : * of the band to be accessed. This would be zero to start from the left side.
3455 : *
3456 : * @param nYOff The line offset to the top left corner of the region
3457 : * of the band to be accessed. This would be zero to start from the top.
3458 : *
3459 : * @param nXSize The width of the region of the band to be accessed in pixels.
3460 : *
3461 : * @param nYSize The height of the region of the band to be accessed in lines.
3462 : *
3463 : * @param nBufXSize the width of the buffer image into which the desired region
3464 : * is to be read, or from which it is to be written.
3465 : *
3466 : * @param nBufYSize the height of the buffer image into which the desired
3467 : * region is to be read, or from which it is to be written.
3468 : *
3469 : * @param eBufType the type of the pixel values in the pData data buffer. The
3470 : * pixel values will automatically be translated to/from the GDALRasterBand
3471 : * data type as needed.
3472 : *
3473 : * @param nBandCount the number of bands being read or written.
3474 : *
3475 : * @param panBandMap the list of nBandCount band numbers being read/written.
3476 : * Note band numbers are 1 based. This may be NULL to select the first
3477 : * nBandCount bands.
3478 : *
3479 : * @param papszOptions a list of name=value strings with special control
3480 : * options. Normally this is NULL.
3481 : *
3482 : * @return CE_Failure if the request is invalid and CE_None if it works or
3483 : * is ignored.
3484 : */
3485 :
3486 15262 : CPLErr GDALDataset::AdviseRead(int nXOff, int nYOff, int nXSize, int nYSize,
3487 : int nBufXSize, int nBufYSize,
3488 : GDALDataType eBufType, int nBandCount,
3489 : int *panBandMap, CSLConstList papszOptions)
3490 :
3491 : {
3492 : /* -------------------------------------------------------------------- */
3493 : /* Do some validation of parameters. */
3494 : /* -------------------------------------------------------------------- */
3495 15262 : int bStopProcessing = FALSE;
3496 15262 : CPLErr eErr = ValidateRasterIOOrAdviseReadParameters(
3497 : "AdviseRead()", &bStopProcessing, nXOff, nYOff, nXSize, nYSize,
3498 : nBufXSize, nBufYSize, nBandCount, panBandMap);
3499 15262 : if (eErr != CE_None || bStopProcessing)
3500 142 : return eErr;
3501 :
3502 129709 : for (int iBand = 0; iBand < nBandCount; ++iBand)
3503 : {
3504 114593 : GDALRasterBand *poBand = nullptr;
3505 :
3506 114593 : if (panBandMap == nullptr)
3507 113106 : poBand = GetRasterBand(iBand + 1);
3508 : else
3509 1487 : poBand = GetRasterBand(panBandMap[iBand]);
3510 :
3511 114593 : if (poBand == nullptr)
3512 0 : return CE_Failure;
3513 :
3514 229186 : eErr = poBand->AdviseRead(nXOff, nYOff, nXSize, nYSize, nBufXSize,
3515 114593 : nBufYSize, eBufType, papszOptions);
3516 :
3517 114593 : if (eErr != CE_None)
3518 4 : return eErr;
3519 : }
3520 :
3521 15116 : return CE_None;
3522 : }
3523 :
3524 : /************************************************************************/
3525 : /* GDALDatasetAdviseRead() */
3526 : /************************************************************************/
3527 :
3528 : /**
3529 : * \brief Advise driver of upcoming read requests.
3530 : *
3531 : * @see GDALDataset::AdviseRead()
3532 : */
3533 7 : CPLErr CPL_STDCALL GDALDatasetAdviseRead(GDALDatasetH hDS, int nXOff, int nYOff,
3534 : int nXSize, int nYSize, int nBufXSize,
3535 : int nBufYSize, GDALDataType eDT,
3536 : int nBandCount, int *panBandMap,
3537 : CSLConstList papszOptions)
3538 :
3539 : {
3540 7 : VALIDATE_POINTER1(hDS, "GDALDatasetAdviseRead", CE_Failure);
3541 :
3542 14 : return GDALDataset::FromHandle(hDS)->AdviseRead(
3543 : nXOff, nYOff, nXSize, nYSize, nBufXSize, nBufYSize, eDT, nBandCount,
3544 7 : panBandMap, const_cast<char **>(papszOptions));
3545 : }
3546 :
3547 : /************************************************************************/
3548 : /* GDALAntiRecursionStruct */
3549 : /************************************************************************/
3550 :
3551 : // Prevent infinite recursion.
3552 : struct GDALAntiRecursionStruct
3553 : {
3554 : struct DatasetContext
3555 : {
3556 : std::string osFilename;
3557 : int nOpenFlags;
3558 : std::string osAllowedDrivers;
3559 :
3560 86953 : DatasetContext(const std::string &osFilenameIn, int nOpenFlagsIn,
3561 : const std::string &osAllowedDriversIn)
3562 86953 : : osFilename(osFilenameIn), nOpenFlags(nOpenFlagsIn),
3563 86953 : osAllowedDrivers(osAllowedDriversIn)
3564 : {
3565 86953 : }
3566 : };
3567 :
3568 : struct DatasetContextCompare
3569 : {
3570 1078010 : bool operator()(const DatasetContext &lhs,
3571 : const DatasetContext &rhs) const
3572 : {
3573 3157520 : return lhs.osFilename < rhs.osFilename ||
3574 1046620 : (lhs.osFilename == rhs.osFilename &&
3575 1032890 : (lhs.nOpenFlags < rhs.nOpenFlags ||
3576 2049420 : (lhs.nOpenFlags == rhs.nOpenFlags &&
3577 2100670 : lhs.osAllowedDrivers < rhs.osAllowedDrivers)));
3578 : }
3579 : };
3580 :
3581 1393 : ~GDALAntiRecursionStruct()
3582 1393 : {
3583 1393 : CPLAssert(aosDatasetNamesWithFlags.empty());
3584 1393 : CPLAssert(nRecLevel == 0);
3585 1393 : CPLAssert(m_oMapDepth.empty());
3586 1393 : }
3587 :
3588 : std::set<DatasetContext, DatasetContextCompare> aosDatasetNamesWithFlags{};
3589 : int nRecLevel = 0;
3590 : std::map<std::string, int> m_oMapDepth{};
3591 : };
3592 :
3593 : #ifdef _WIN32
3594 : // Currently thread_local and C++ objects don't work well with DLL on Windows
3595 : static void FreeAntiRecursionOpen(void *pData)
3596 : {
3597 : delete static_cast<GDALAntiRecursionStruct *>(pData);
3598 : }
3599 :
3600 : static GDALAntiRecursionStruct &GetAntiRecursionOpen()
3601 : {
3602 : static GDALAntiRecursionStruct dummy;
3603 : int bMemoryErrorOccurred = false;
3604 : void *pData =
3605 : CPLGetTLSEx(CTLS_GDALOPEN_ANTIRECURSION, &bMemoryErrorOccurred);
3606 : if (bMemoryErrorOccurred)
3607 : {
3608 : return dummy;
3609 : }
3610 : if (pData == nullptr)
3611 : {
3612 : auto pAntiRecursion = new GDALAntiRecursionStruct();
3613 : CPLSetTLSWithFreeFuncEx(CTLS_GDALOPEN_ANTIRECURSION, pAntiRecursion,
3614 : FreeAntiRecursionOpen, &bMemoryErrorOccurred);
3615 : if (bMemoryErrorOccurred)
3616 : {
3617 : delete pAntiRecursion;
3618 : return dummy;
3619 : }
3620 : return *pAntiRecursion;
3621 : }
3622 : return *static_cast<GDALAntiRecursionStruct *>(pData);
3623 : }
3624 : #else
3625 : static thread_local GDALAntiRecursionStruct g_tls_antiRecursion;
3626 :
3627 376606 : static GDALAntiRecursionStruct &GetAntiRecursionOpen()
3628 : {
3629 376606 : return g_tls_antiRecursion;
3630 : }
3631 : #endif
3632 :
3633 : //! @cond Doxygen_Suppress
3634 289653 : GDALAntiRecursionGuard::GDALAntiRecursionGuard(const std::string &osIdentifier)
3635 289653 : : m_psAntiRecursionStruct(&GetAntiRecursionOpen()),
3636 : m_osIdentifier(osIdentifier),
3637 289653 : m_nDepth(++m_psAntiRecursionStruct->m_oMapDepth[m_osIdentifier])
3638 : {
3639 289653 : CPLAssert(!osIdentifier.empty());
3640 289653 : }
3641 :
3642 289653 : GDALAntiRecursionGuard::GDALAntiRecursionGuard(
3643 289653 : const GDALAntiRecursionGuard &other, const std::string &osIdentifier)
3644 289653 : : m_psAntiRecursionStruct(other.m_psAntiRecursionStruct),
3645 289653 : m_osIdentifier(osIdentifier.empty()
3646 : ? osIdentifier
3647 31142 : : other.m_osIdentifier + osIdentifier),
3648 289653 : m_nDepth(m_osIdentifier.empty()
3649 289653 : ? 0
3650 320795 : : ++m_psAntiRecursionStruct->m_oMapDepth[m_osIdentifier])
3651 : {
3652 289653 : }
3653 :
3654 579306 : GDALAntiRecursionGuard::~GDALAntiRecursionGuard()
3655 : {
3656 579306 : if (!m_osIdentifier.empty())
3657 : {
3658 320795 : auto oIter = m_psAntiRecursionStruct->m_oMapDepth.find(m_osIdentifier);
3659 320795 : CPLAssert(oIter != m_psAntiRecursionStruct->m_oMapDepth.end());
3660 320795 : if (--(oIter->second) == 0)
3661 316338 : m_psAntiRecursionStruct->m_oMapDepth.erase(oIter);
3662 : }
3663 579306 : }
3664 :
3665 : //! @endcond
3666 :
3667 : /************************************************************************/
3668 : /* GetFileList() */
3669 : /************************************************************************/
3670 :
3671 : /**
3672 : * \brief Fetch files forming dataset.
3673 : *
3674 : * Returns a list of files believed to be part of this dataset. If it returns
3675 : * an empty list of files it means there is believed to be no local file
3676 : * system files associated with the dataset (for instance a virtual dataset).
3677 : * The returned file list is owned by the caller and should be deallocated
3678 : * with CSLDestroy().
3679 : *
3680 : * The returned filenames will normally be relative or absolute paths
3681 : * depending on the path used to originally open the dataset. The strings
3682 : * will be UTF-8 encoded.
3683 : *
3684 : * This method is the same as the C GDALGetFileList() function.
3685 : *
3686 : * @return NULL or a NULL terminated array of file names.
3687 : */
3688 :
3689 4733 : char **GDALDataset::GetFileList()
3690 :
3691 : {
3692 9466 : CPLString osMainFilename = GetDescription();
3693 : VSIStatBufL sStat;
3694 :
3695 4733 : GDALAntiRecursionStruct &sAntiRecursion = GetAntiRecursionOpen();
3696 : GDALAntiRecursionStruct::DatasetContext datasetCtxt(osMainFilename, 0,
3697 9466 : std::string());
3698 4733 : auto &aosDatasetList = sAntiRecursion.aosDatasetNamesWithFlags;
3699 4733 : if (cpl::contains(aosDatasetList, datasetCtxt))
3700 0 : return nullptr;
3701 :
3702 : /* -------------------------------------------------------------------- */
3703 : /* Is the main filename even a real filesystem object? */
3704 : /* -------------------------------------------------------------------- */
3705 : int bMainFileReal =
3706 4733 : VSIStatExL(osMainFilename, &sStat, VSI_STAT_EXISTS_FLAG) == 0;
3707 :
3708 : /* -------------------------------------------------------------------- */
3709 : /* Form new list. */
3710 : /* -------------------------------------------------------------------- */
3711 4733 : char **papszList = nullptr;
3712 :
3713 4733 : if (bMainFileReal)
3714 4653 : papszList = CSLAddString(papszList, osMainFilename);
3715 :
3716 4733 : if (sAntiRecursion.nRecLevel == 100)
3717 : {
3718 0 : CPLError(CE_Failure, CPLE_AppDefined,
3719 : "GetFileList() called with too many recursion levels");
3720 0 : return papszList;
3721 : }
3722 4733 : ++sAntiRecursion.nRecLevel;
3723 :
3724 : /* -------------------------------------------------------------------- */
3725 : /* Do we have a known overview file? */
3726 : /* -------------------------------------------------------------------- */
3727 4733 : if (oOvManager.IsInitialized() && oOvManager.poODS != nullptr)
3728 : {
3729 60 : auto iter = aosDatasetList.insert(datasetCtxt).first;
3730 60 : char **papszOvrList = oOvManager.poODS->GetFileList();
3731 60 : papszList = CSLInsertStrings(papszList, -1, papszOvrList);
3732 60 : CSLDestroy(papszOvrList);
3733 60 : aosDatasetList.erase(iter);
3734 : }
3735 :
3736 : /* -------------------------------------------------------------------- */
3737 : /* Do we have a known mask file? */
3738 : /* -------------------------------------------------------------------- */
3739 4733 : if (oOvManager.HaveMaskFile())
3740 : {
3741 9 : auto iter = aosDatasetList.insert(std::move(datasetCtxt)).first;
3742 9 : for (const char *pszFile :
3743 18 : CPLStringList(oOvManager.poMaskDS->GetFileList()))
3744 : {
3745 9 : if (CSLFindString(papszList, pszFile) < 0)
3746 9 : papszList = CSLAddString(papszList, pszFile);
3747 : }
3748 9 : aosDatasetList.erase(iter);
3749 : }
3750 :
3751 4733 : --sAntiRecursion.nRecLevel;
3752 :
3753 4733 : return papszList;
3754 : }
3755 :
3756 : /************************************************************************/
3757 : /* GDALGetFileList() */
3758 : /************************************************************************/
3759 :
3760 : /**
3761 : * \brief Fetch files forming dataset.
3762 : *
3763 : * @see GDALDataset::GetFileList()
3764 : */
3765 :
3766 3732 : char **CPL_STDCALL GDALGetFileList(GDALDatasetH hDS)
3767 :
3768 : {
3769 3732 : VALIDATE_POINTER1(hDS, "GDALGetFileList", nullptr);
3770 :
3771 3732 : return GDALDataset::FromHandle(hDS)->GetFileList();
3772 : }
3773 :
3774 : /************************************************************************/
3775 : /* CreateMaskBand() */
3776 : /************************************************************************/
3777 :
3778 : /**
3779 : * \brief Adds a mask band to the dataset
3780 : *
3781 : * The default implementation of the CreateMaskBand() method is implemented
3782 : * based on similar rules to the .ovr handling implemented using the
3783 : * GDALDefaultOverviews object. A TIFF file with the extension .msk will
3784 : * be created with the same basename as the original file, and it will have
3785 : * one band.
3786 : * The mask images will be deflate compressed tiled images with the same
3787 : * block size as the original image if possible.
3788 : * It will have INTERNAL_MASK_FLAGS_xx metadata items set at the dataset
3789 : * level, where xx matches the band number of a band of the main dataset. The
3790 : * value of those items will be the one of the nFlagsIn parameter.
3791 : *
3792 : * Note that if you got a mask band with a previous call to GetMaskBand(), it
3793 : * might be invalidated by CreateMaskBand(). So you have to call GetMaskBand()
3794 : * again.
3795 : *
3796 : *
3797 : * @param nFlagsIn 0 or combination of GMF_PER_DATASET / GMF_ALPHA.
3798 : * GMF_PER_DATASET will be always set, even if not explicitly
3799 : * specified.
3800 : * @return CE_None on success or CE_Failure on an error.
3801 : *
3802 : * @see https://gdal.org/development/rfc/rfc15_nodatabitmask.html
3803 : * @see GDALRasterBand::CreateMaskBand()
3804 : *
3805 : */
3806 17 : CPLErr GDALDataset::CreateMaskBand(int nFlagsIn)
3807 :
3808 : {
3809 17 : if (oOvManager.IsInitialized())
3810 : {
3811 17 : CPLErr eErr = oOvManager.CreateMaskBand(nFlagsIn, -1);
3812 17 : if (eErr != CE_None)
3813 0 : return eErr;
3814 :
3815 : // Invalidate existing raster band masks.
3816 45 : for (int i = 0; i < nBands; ++i)
3817 : {
3818 28 : GDALRasterBand *poBand = papoBands[i];
3819 28 : poBand->poMask.reset();
3820 : }
3821 :
3822 17 : return CE_None;
3823 : }
3824 :
3825 0 : ReportError(CE_Failure, CPLE_NotSupported,
3826 : "CreateMaskBand() not supported for this dataset.");
3827 :
3828 0 : return CE_Failure;
3829 : }
3830 :
3831 : /************************************************************************/
3832 : /* GDALCreateDatasetMaskBand() */
3833 : /************************************************************************/
3834 :
3835 : /**
3836 : * \brief Adds a mask band to the dataset
3837 : * @see GDALDataset::CreateMaskBand()
3838 : */
3839 107 : CPLErr CPL_STDCALL GDALCreateDatasetMaskBand(GDALDatasetH hDS, int nFlags)
3840 :
3841 : {
3842 107 : VALIDATE_POINTER1(hDS, "GDALCreateDatasetMaskBand", CE_Failure);
3843 :
3844 107 : return GDALDataset::FromHandle(hDS)->CreateMaskBand(nFlags);
3845 : }
3846 :
3847 : /************************************************************************/
3848 : /* GDALOpen() */
3849 : /************************************************************************/
3850 :
3851 : /**
3852 : * \brief Open a raster file as a GDALDataset.
3853 : *
3854 : * This function will try to open the passed file, or virtual dataset
3855 : * name by invoking the Open method of each registered GDALDriver in turn.
3856 : * The first successful open will result in a returned dataset. If all
3857 : * drivers fail then NULL is returned and an error is issued.
3858 : *
3859 : * Several recommendations :
3860 : * <ul>
3861 : * <li>If you open a dataset object with GA_Update access, it is not recommended
3862 : * to open a new dataset on the same underlying file.</li>
3863 : * <li>The returned dataset should only be accessed by one thread at a time. If
3864 : * you want to use it from different threads, you must add all necessary code
3865 : * (mutexes, etc.) to avoid concurrent use of the object. (Some drivers, such
3866 : * as GeoTIFF, maintain internal state variables that are updated each time a
3867 : * new block is read, thus preventing concurrent use.) </li>
3868 : * </ul>
3869 : *
3870 : * For drivers supporting the VSI virtual file API, it is possible to open a
3871 : * file in a .zip archive (see VSIInstallZipFileHandler()), in a
3872 : * .tar/.tar.gz/.tgz archive (see VSIInstallTarFileHandler()) or on a HTTP / FTP
3873 : * server (see VSIInstallCurlFileHandler())
3874 : *
3875 : * \sa GDALOpenShared()
3876 : * \sa GDALOpenEx()
3877 : *
3878 : * @param pszFilename the name of the file to access. In the case of
3879 : * exotic drivers this may not refer to a physical file, but instead contain
3880 : * information for the driver on how to access a dataset. It should be in UTF-8
3881 : * encoding.
3882 : *
3883 : * @param eAccess the desired access, either GA_Update or GA_ReadOnly. Many
3884 : * drivers support only read only access.
3885 : *
3886 : * @return A GDALDatasetH handle or NULL on failure. For C++ applications
3887 : * this handle can be cast to a GDALDataset *.
3888 : */
3889 :
3890 26675 : GDALDatasetH CPL_STDCALL GDALOpen(const char *pszFilename, GDALAccess eAccess)
3891 :
3892 : {
3893 26675 : const int nUpdateFlag = eAccess == GA_Update ? GDAL_OF_UPDATE : 0;
3894 26675 : const int nOpenFlags = GDAL_OF_RASTER | nUpdateFlag | GDAL_OF_VERBOSE_ERROR;
3895 : GDALDatasetH hDataset =
3896 26675 : GDALOpenEx(pszFilename, nOpenFlags, nullptr, nullptr, nullptr);
3897 26675 : return hDataset;
3898 : }
3899 :
3900 : /************************************************************************/
3901 : /* GetSharedDS() */
3902 : /************************************************************************/
3903 :
3904 6490 : static GDALDataset *GetSharedDS(const char *pszFilename,
3905 : unsigned int nOpenFlags,
3906 : const char *const *papszOpenOptions)
3907 : {
3908 12980 : CPLMutexHolderD(&hDLMutex);
3909 :
3910 6490 : if (phSharedDatasetSet != nullptr)
3911 : {
3912 6251 : const GIntBig nThisPID = GDALGetResponsiblePIDForCurrentThread();
3913 : SharedDatasetCtxt sStruct;
3914 :
3915 6251 : sStruct.nPID = nThisPID;
3916 6251 : sStruct.pszDescription = const_cast<char *>(pszFilename);
3917 6251 : sStruct.nOpenFlags = nOpenFlags & ~GDAL_OF_SHARED;
3918 : std::string osConcatenatedOpenOptions =
3919 6251 : GDALSharedDatasetConcatenateOpenOptions(papszOpenOptions);
3920 6251 : sStruct.pszConcatenatedOpenOptions = &osConcatenatedOpenOptions[0];
3921 6251 : sStruct.poDS = nullptr;
3922 : SharedDatasetCtxt *psStruct = static_cast<SharedDatasetCtxt *>(
3923 6251 : CPLHashSetLookup(phSharedDatasetSet, &sStruct));
3924 6251 : if (psStruct == nullptr && (nOpenFlags & GDAL_OF_UPDATE) == 0)
3925 : {
3926 145 : sStruct.nOpenFlags |= GDAL_OF_UPDATE;
3927 : psStruct = static_cast<SharedDatasetCtxt *>(
3928 145 : CPLHashSetLookup(phSharedDatasetSet, &sStruct));
3929 : }
3930 6251 : if (psStruct)
3931 : {
3932 6107 : return psStruct->poDS;
3933 : }
3934 : }
3935 383 : return nullptr;
3936 : }
3937 :
3938 : /************************************************************************/
3939 : /* GDALOpenEx() */
3940 : /************************************************************************/
3941 :
3942 : /**
3943 : * \brief Open a raster or vector file as a GDALDataset.
3944 : *
3945 : * This function will try to open the passed file, or virtual dataset
3946 : * name by invoking the Open method of each registered GDALDriver in turn.
3947 : * The first successful open will result in a returned dataset. If all
3948 : * drivers fail then NULL is returned and an error is issued.
3949 : *
3950 : * Several recommendations :
3951 : * <ul>
3952 : * <li>If you open a dataset object with GDAL_OF_UPDATE access, it is not
3953 : * recommended to open a new dataset on the same underlying file.</li>
3954 : * <li>The returned dataset should only be accessed by one thread at a time. If
3955 : * you want to use it from different threads, you must add all necessary code
3956 : * (mutexes, etc.) to avoid concurrent use of the object. (Some drivers, such
3957 : * as GeoTIFF, maintain internal state variables that are updated each time a
3958 : * new block is read, thus preventing concurrent use.) </li>
3959 : * </ul>
3960 : *
3961 : * For drivers supporting the VSI virtual file API, it is possible to open a
3962 : * file in a .zip archive (see VSIInstallZipFileHandler()), in a
3963 : * .tar/.tar.gz/.tgz archive (see VSIInstallTarFileHandler()) or on a HTTP / FTP
3964 : * server (see VSIInstallCurlFileHandler())
3965 : *
3966 : * In order to reduce the need for searches through the operating system
3967 : * file system machinery, it is possible to give an optional list of files with
3968 : * the papszSiblingFiles parameter.
3969 : * This is the list of all files at the same level in the file system as the
3970 : * target file, including the target file. The filenames must not include any
3971 : * path components, are essentially just the output of VSIReadDir() on the
3972 : * parent directory. If the target object does not have filesystem semantics
3973 : * then the file list should be NULL.
3974 : *
3975 : * @param pszFilename the name of the file to access. In the case of
3976 : * exotic drivers this may not refer to a physical file, but instead contain
3977 : * information for the driver on how to access a dataset. It should be in UTF-8
3978 : * encoding.
3979 : *
3980 : * @param nOpenFlags a combination of GDAL_OF_ flags that may be combined
3981 : * through logical or operator.
3982 : * <ul>
3983 : * <li>Driver kind:
3984 : * <ul>
3985 : * <li>GDAL_OF_RASTER for raster drivers,</li>
3986 : * <li>GDAL_OF_MULTIDIM_RASTER for multidimensional raster drivers,</li>
3987 : * <li>GDAL_OF_VECTOR for vector drivers,</li>
3988 : * <li>GDAL_OF_GNM for Geographic Network Model drivers.</li>
3989 : * </ul>
3990 : * GDAL_OF_RASTER and GDAL_OF_MULTIDIM_RASTER are generally mutually
3991 : * exclusive. If none of the value is specified, GDAL_OF_RASTER | GDAL_OF_VECTOR
3992 : * | GDAL_OF_GNM is implied.
3993 : * </li>
3994 : * <li>Access mode: GDAL_OF_READONLY (exclusive)or GDAL_OF_UPDATE.
3995 : * </li>
3996 : * <li>Shared mode: GDAL_OF_SHARED. If set,
3997 : * it allows the sharing of GDALDataset handles for a dataset with other callers
3998 : * that have set GDAL_OF_SHARED. In particular, GDALOpenEx() will first consult
3999 : * its list of currently open and shared GDALDataset's, and if the
4000 : * GetDescription() name for one exactly matches the pszFilename passed to
4001 : * GDALOpenEx() it will be referenced and returned, if GDALOpenEx() is called
4002 : * from the same thread.
4003 : * </li>
4004 : * <li>Thread safe mode: GDAL_OF_THREAD_SAFE (added in 3.10).
4005 : * This must be use in combination with GDAL_OF_RASTER, and is mutually
4006 : * exclusive with GDAL_OF_UPDATE, GDAL_OF_VECTOR, GDAL_OF_MULTIDIM_RASTER or
4007 : * GDAL_OF_GNM.
4008 : * </li>
4009 : * <li>Verbose error: GDAL_OF_VERBOSE_ERROR. If set,
4010 : * a failed attempt to open the file will lead to an error message to be
4011 : * reported.
4012 : * </li>
4013 : * </ul>
4014 : *
4015 : * @param papszAllowedDrivers NULL to consider all candidate drivers, or a NULL
4016 : * terminated list of strings with the driver short names that must be
4017 : * considered.
4018 : * Starting with GDAL 3.13, a string starting with the dash (-) character
4019 : * followed by the driver short name can be used to exclude a driver.
4020 : *
4021 : * @param papszOpenOptions NULL, or a NULL terminated list of strings with open
4022 : * options passed to candidate drivers. An option exists for all drivers,
4023 : * OVERVIEW_LEVEL=level, to select a particular overview level of a dataset.
4024 : * The level index starts at 0. The level number can be suffixed by "only" to
4025 : * specify that only this overview level must be visible, and not sub-levels.
4026 : * Open options are validated by default, and a warning is emitted in case the
4027 : * option is not recognized. In some scenarios, it might be not desirable (e.g.
4028 : * when not knowing which driver will open the file), so the special open option
4029 : * VALIDATE_OPEN_OPTIONS can be set to NO to avoid such warnings. Alternatively,
4030 : * that it may not cause a warning if the driver doesn't declare this option.
4031 : * Starting with GDAL 3.3, OVERVIEW_LEVEL=NONE is supported to indicate that
4032 : * no overviews should be exposed.
4033 : *
4034 : * @param papszSiblingFiles NULL, or a NULL terminated list of strings that are
4035 : * filenames that are auxiliary to the main filename. If NULL is passed, a
4036 : * probing of the file system will be done.
4037 : *
4038 : * @return A GDALDatasetH handle or NULL on failure. For C++ applications
4039 : * this handle can be cast to a GDALDataset *.
4040 : *
4041 : */
4042 :
4043 86336 : GDALDatasetH CPL_STDCALL GDALOpenEx(const char *pszFilename,
4044 : unsigned int nOpenFlags,
4045 : const char *const *papszAllowedDrivers,
4046 : const char *const *papszOpenOptions,
4047 : const char *const *papszSiblingFiles)
4048 : {
4049 86336 : VALIDATE_POINTER1(pszFilename, "GDALOpen", nullptr);
4050 :
4051 : // Do some sanity checks on incompatible flags with thread-safe mode.
4052 86336 : if ((nOpenFlags & GDAL_OF_THREAD_SAFE) != 0)
4053 : {
4054 : const struct
4055 : {
4056 : int nFlag;
4057 : const char *pszFlagName;
4058 128 : } asFlags[] = {
4059 : {GDAL_OF_UPDATE, "GDAL_OF_UPDATE"},
4060 : {GDAL_OF_VECTOR, "GDAL_OF_VECTOR"},
4061 : {GDAL_OF_MULTIDIM_RASTER, "GDAL_OF_MULTIDIM_RASTER"},
4062 : {GDAL_OF_GNM, "GDAL_OF_GNM"},
4063 : };
4064 :
4065 630 : for (const auto &asFlag : asFlags)
4066 : {
4067 506 : if ((nOpenFlags & asFlag.nFlag) != 0)
4068 : {
4069 4 : CPLError(CE_Failure, CPLE_IllegalArg,
4070 : "GDAL_OF_THREAD_SAFE and %s are mutually "
4071 : "exclusive",
4072 4 : asFlag.pszFlagName);
4073 4 : return nullptr;
4074 : }
4075 : }
4076 : }
4077 :
4078 : // If no driver kind is specified, assume all are to be probed.
4079 86332 : if ((nOpenFlags & GDAL_OF_KIND_MASK) == 0)
4080 7889 : nOpenFlags |= GDAL_OF_KIND_MASK & ~GDAL_OF_MULTIDIM_RASTER;
4081 :
4082 : /* -------------------------------------------------------------------- */
4083 : /* In case of shared dataset, first scan the existing list to see */
4084 : /* if it could already contain the requested dataset. */
4085 : /* -------------------------------------------------------------------- */
4086 86332 : if (nOpenFlags & GDAL_OF_SHARED)
4087 : {
4088 6490 : if (nOpenFlags & GDAL_OF_INTERNAL)
4089 : {
4090 0 : CPLError(CE_Failure, CPLE_IllegalArg,
4091 : "GDAL_OF_SHARED and GDAL_OF_INTERNAL are exclusive");
4092 0 : return nullptr;
4093 : }
4094 :
4095 : auto poSharedDS =
4096 6490 : GetSharedDS(pszFilename, nOpenFlags, papszOpenOptions);
4097 6490 : if (poSharedDS)
4098 : {
4099 6107 : poSharedDS->Reference();
4100 6107 : return poSharedDS;
4101 : }
4102 : }
4103 :
4104 80225 : CPLErrorReset();
4105 80225 : VSIErrorReset();
4106 :
4107 : // Build GDALOpenInfo just now to avoid useless file stat'ing if a
4108 : // shared dataset was asked before.
4109 80225 : GDALOpenInfo oOpenInfo(pszFilename, nOpenFlags, papszSiblingFiles);
4110 :
4111 160450 : return GDALDataset::Open(&oOpenInfo, papszAllowedDrivers, papszOpenOptions)
4112 80225 : .release();
4113 : }
4114 :
4115 : /************************************************************************/
4116 : /* GDALDataset::Open() */
4117 : /************************************************************************/
4118 :
4119 : /**
4120 : * \brief Open a raster or vector file as a GDALDataset.
4121 : *
4122 : * This function will use the passed open info on each registered GDALDriver in
4123 : * turn.
4124 : * The first successful open will result in a returned dataset. If all
4125 : * drivers fail then NULL is returned and an error is issued.
4126 : *
4127 : * Several recommendations :
4128 : * <ul>
4129 : * <li>If you open a dataset object with GDAL_OF_UPDATE access, it is not
4130 : * recommended to open a new dataset on the same underlying file.</li>
4131 : * <li>The returned dataset should only be accessed by one thread at a time. If
4132 : * you want to use it from different threads, you must add all necessary code
4133 : * (mutexes, etc.) to avoid concurrent use of the object. (Some drivers, such
4134 : * as GeoTIFF, maintain internal state variables that are updated each time a
4135 : * new block is read, thus preventing concurrent use.) </li>
4136 : * </ul>
4137 : *
4138 : * For drivers supporting the VSI virtual file API, it is possible to open a
4139 : * file in a .zip archive (see VSIInstallZipFileHandler()), in a
4140 : * .tar/.tar.gz/.tgz archive (see VSIInstallTarFileHandler()) or on a HTTP / FTP
4141 : * server (see VSIInstallCurlFileHandler())
4142 : *
4143 : * @param poOpenInfo a pointer to an open info instance. Must NOT be NULL,
4144 : * and the GDAL_OF_SHARED flag must NOT be set in poOpenInfo->nOpenFlags.
4145 : * If shared dataset is needed, use GDALOpenEx() or the other variant of
4146 : * GDALDataset::Open()
4147 : *
4148 : * @param papszAllowedDrivers NULL to consider all candidate drivers, or a NULL
4149 : * terminated list of strings with the driver short names that must be
4150 : * considered.
4151 : * Starting with GDAL 3.13, a string starting with the dash (-) character
4152 : * followed by the driver short name can be used to exclude a driver.
4153 : *
4154 : * @param papszOpenOptions NULL, or a NULL terminated list of strings with open
4155 : * options passed to candidate drivers. An option exists for all drivers,
4156 : * OVERVIEW_LEVEL=level, to select a particular overview level of a dataset.
4157 : * The level index starts at 0. The level number can be suffixed by "only" to
4158 : * specify that only this overview level must be visible, and not sub-levels.
4159 : * Open options are validated by default, and a warning is emitted in case the
4160 : * option is not recognized. In some scenarios, it might be not desirable (e.g.
4161 : * when not knowing which driver will open the file), so the special open option
4162 : * VALIDATE_OPEN_OPTIONS can be set to NO to avoid such warnings. Alternatively,
4163 : * that it may not cause a warning if the driver doesn't declare this option.
4164 : * OVERVIEW_LEVEL=NONE is supported to indicate that
4165 : * no overviews should be exposed.
4166 : *
4167 : * @return A GDALDataset unique pointer or NULL on failure.
4168 : *
4169 : * @since 3.13
4170 : */
4171 :
4172 : std::unique_ptr<GDALDataset>
4173 82220 : GDALDataset::Open(GDALOpenInfo *poOpenInfo,
4174 : const char *const *papszAllowedDrivers,
4175 : const char *const *papszOpenOptions)
4176 : {
4177 : // Hack for the ZARR driver. We translate the CACHE_KERCHUNK_JSON
4178 : // into VSIKERCHUNK_USE_CACHE config option
4179 82220 : std::unique_ptr<CPLConfigOptionSetter> poVSIKERCHUNK_USE_CACHESetter;
4180 82220 : if (CPLFetchBool(papszOpenOptions, "CACHE_KERCHUNK_JSON", false))
4181 : {
4182 13 : poVSIKERCHUNK_USE_CACHESetter = std::make_unique<CPLConfigOptionSetter>(
4183 26 : "VSIKERCHUNK_USE_CACHE", "YES", false);
4184 : }
4185 :
4186 82220 : GDALDriverManager *poDM = GetGDALDriverManager();
4187 :
4188 82220 : CPLAssert(nullptr != poDM);
4189 :
4190 82220 : GDALOpenInfo &oOpenInfo = *poOpenInfo;
4191 82220 : const char *pszFilename = poOpenInfo->pszFilename;
4192 82220 : const int nOpenFlags = poOpenInfo->nOpenFlags;
4193 82220 : oOpenInfo.papszAllowedDrivers = papszAllowedDrivers;
4194 :
4195 82220 : GDALAntiRecursionStruct &sAntiRecursion = GetAntiRecursionOpen();
4196 82220 : if (sAntiRecursion.nRecLevel == 100)
4197 : {
4198 0 : CPLError(CE_Failure, CPLE_AppDefined,
4199 : "GDALOpen() called with too many recursion levels");
4200 0 : return nullptr;
4201 : }
4202 :
4203 164440 : std::string osAllowedDrivers;
4204 176744 : for (const char *pszDriverName : cpl::Iterate(papszAllowedDrivers))
4205 94524 : osAllowedDrivers += pszDriverName;
4206 : auto dsCtxt = GDALAntiRecursionStruct::DatasetContext(
4207 246660 : std::string(pszFilename), nOpenFlags, osAllowedDrivers);
4208 82220 : if (cpl::contains(sAntiRecursion.aosDatasetNamesWithFlags, dsCtxt))
4209 : {
4210 0 : CPLError(CE_Failure, CPLE_AppDefined,
4211 : "GDALOpen() called on %s recursively", pszFilename);
4212 0 : return nullptr;
4213 : }
4214 :
4215 : // Remove leading @ if present.
4216 : char **papszOpenOptionsCleaned =
4217 82220 : CSLDuplicate(const_cast<char **>(papszOpenOptions));
4218 87899 : for (char **papszIter = papszOpenOptionsCleaned; papszIter && *papszIter;
4219 : ++papszIter)
4220 : {
4221 5679 : char *pszOption = *papszIter;
4222 5679 : if (pszOption[0] == '@')
4223 228 : memmove(pszOption, pszOption + 1, strlen(pszOption + 1) + 1);
4224 : }
4225 :
4226 82220 : oOpenInfo.papszOpenOptions = papszOpenOptionsCleaned;
4227 82220 : oOpenInfo.nOpenFlags |= GDAL_OF_FROM_GDALOPEN;
4228 :
4229 : #ifdef OGRAPISPY_ENABLED
4230 82220 : const bool bUpdate = (nOpenFlags & GDAL_OF_UPDATE) != 0;
4231 : const int iSnapshot =
4232 20033 : (nOpenFlags & GDAL_OF_VECTOR) != 0 && (nOpenFlags & GDAL_OF_RASTER) == 0
4233 102253 : ? OGRAPISpyOpenTakeSnapshot(pszFilename, bUpdate)
4234 82220 : : INT_MIN;
4235 : #endif
4236 :
4237 82220 : const int nDriverCount = poDM->GetDriverCount(/*bIncludeHidden=*/true);
4238 82220 : GDALDriver *poMissingPluginDriver = nullptr;
4239 164440 : std::vector<GDALDriver *> apoSecondPassDrivers;
4240 :
4241 : // Lookup of matching driver for dataset can involve up to 2 passes:
4242 : // - in the first pass, all drivers that are compabile of the request mode
4243 : // (raster/vector/etc.) are probed using their Identify() method if it
4244 : // exists. If the Identify() method returns FALSE, the driver is skipped.
4245 : // If the Identify() methods returns GDAL_IDENTIFY_UNKNOWN and that the
4246 : // driver is a deferred-loading plugin, it is added to the
4247 : // apoSecondPassDrivers list for potential later probing, and execution
4248 : // continues to the next driver in the list.
4249 : // Otherwise if Identify() returns non-FALSE, the Open() method is used.
4250 : // If Open() returns a non-NULL dataset, the loop stops and it is
4251 : // returned. Otherwise looping over remaining drivers continues.
4252 : // - the second pass is optional, only if at least one driver was added
4253 : // into apoSecondPassDrivers during the first pass. It is similar
4254 : // to the first pass except it runs only on apoSecondPassDrivers drivers.
4255 : // And the Open() method of such drivers is used, causing them to be
4256 : // loaded for real.
4257 82220 : int iPass = 1;
4258 82234 : retry:
4259 8532270 : for (int iDriver = 0;
4260 8532310 : iDriver < (iPass == 1 ? nDriverCount
4261 34 : : static_cast<int>(apoSecondPassDrivers.size()));
4262 : ++iDriver)
4263 : {
4264 : GDALDriver *poDriver =
4265 8513460 : iPass == 1 ? poDM->GetDriver(iDriver, /*bIncludeHidden=*/true)
4266 25 : : apoSecondPassDrivers[iDriver];
4267 8513430 : const char *pszDriverName = GDALGetDriverShortName(poDriver);
4268 8513430 : if (pszDriverName && papszAllowedDrivers)
4269 : {
4270 3723180 : bool bDriverMatchedPositively = false;
4271 3723180 : bool bDriverMatchedNegatively = false;
4272 3723180 : bool bOnlyExcludedDrivers = true;
4273 18054500 : for (const char *pszAllowedDriver :
4274 39832100 : cpl::Iterate(papszAllowedDrivers))
4275 : {
4276 18054500 : if (pszAllowedDriver[0] != '-')
4277 18053000 : bOnlyExcludedDrivers = false;
4278 18054500 : if (EQUAL(pszAllowedDriver, pszDriverName))
4279 : {
4280 89416 : bDriverMatchedPositively = true;
4281 : }
4282 17965100 : else if (pszAllowedDriver[0] == '-' &&
4283 1462 : EQUAL(pszAllowedDriver + 1, pszDriverName))
4284 : {
4285 7 : bDriverMatchedNegatively = true;
4286 7 : break;
4287 : }
4288 : }
4289 3723180 : if ((!bDriverMatchedPositively && !bOnlyExcludedDrivers) ||
4290 : bDriverMatchedNegatively)
4291 : {
4292 8002200 : continue;
4293 : }
4294 : }
4295 :
4296 4880890 : if (poDriver->GetMetadataItem(GDAL_DCAP_OPEN) == nullptr)
4297 46751 : continue;
4298 :
4299 12770500 : if ((nOpenFlags & GDAL_OF_RASTER) != 0 &&
4300 6987920 : (nOpenFlags & GDAL_OF_VECTOR) == 0 &&
4301 2153780 : poDriver->GetMetadataItem(GDAL_DCAP_RASTER) == nullptr)
4302 490568 : continue;
4303 12455900 : if ((nOpenFlags & GDAL_OF_VECTOR) != 0 &&
4304 6236300 : (nOpenFlags & GDAL_OF_RASTER) == 0 &&
4305 1892730 : poDriver->GetMetadataItem(GDAL_DCAP_VECTOR) == nullptr)
4306 1418080 : continue;
4307 6499450 : if ((nOpenFlags & GDAL_OF_MULTIDIM_RASTER) != 0 &&
4308 3254230 : (nOpenFlags & GDAL_OF_RASTER) == 0 &&
4309 328740 : poDriver->GetMetadataItem(GDAL_DCAP_MULTIDIM_RASTER) == nullptr)
4310 310012 : continue;
4311 :
4312 : // Remove general OVERVIEW_LEVEL open options from list before passing
4313 : // it to the driver, if it isn't a driver specific option already.
4314 2615480 : char **papszTmpOpenOptions = nullptr;
4315 2615480 : char **papszTmpOpenOptionsToValidate = nullptr;
4316 2615480 : char **papszOptionsToValidate = const_cast<char **>(papszOpenOptions);
4317 2615480 : if (CSLFetchNameValue(papszOpenOptionsCleaned, "OVERVIEW_LEVEL") !=
4318 2615630 : nullptr &&
4319 152 : !poDriver->HasOpenOption("OVERVIEW_LEVEL"))
4320 : {
4321 152 : papszTmpOpenOptions = CSLDuplicate(papszOpenOptionsCleaned);
4322 : papszTmpOpenOptions =
4323 152 : CSLSetNameValue(papszTmpOpenOptions, "OVERVIEW_LEVEL", nullptr);
4324 152 : oOpenInfo.papszOpenOptions = papszTmpOpenOptions;
4325 :
4326 152 : papszOptionsToValidate = CSLDuplicate(papszOptionsToValidate);
4327 152 : papszOptionsToValidate = CSLSetNameValue(papszOptionsToValidate,
4328 : "OVERVIEW_LEVEL", nullptr);
4329 152 : papszTmpOpenOptionsToValidate = papszOptionsToValidate;
4330 : }
4331 :
4332 : const int nIdentifyRes =
4333 2615480 : poDriver->pfnIdentifyEx
4334 5230940 : ? poDriver->pfnIdentifyEx(poDriver, &oOpenInfo)
4335 2615470 : : poDriver->pfnIdentify ? poDriver->pfnIdentify(&oOpenInfo)
4336 2615480 : : GDAL_IDENTIFY_UNKNOWN;
4337 2615480 : if (nIdentifyRes == FALSE)
4338 : {
4339 2104150 : CSLDestroy(papszTmpOpenOptions);
4340 2104150 : CSLDestroy(papszTmpOpenOptionsToValidate);
4341 2104150 : oOpenInfo.papszOpenOptions = papszOpenOptionsCleaned;
4342 2104150 : continue;
4343 : }
4344 511302 : else if (iPass == 1 && nIdentifyRes < 0 &&
4345 1022730 : poDriver->pfnOpen == nullptr &&
4346 101 : poDriver->GetMetadataItem("IS_NON_LOADED_PLUGIN"))
4347 : {
4348 : // Not loaded plugin
4349 98 : apoSecondPassDrivers.push_back(poDriver);
4350 98 : CSLDestroy(papszTmpOpenOptions);
4351 98 : CSLDestroy(papszTmpOpenOptionsToValidate);
4352 98 : oOpenInfo.papszOpenOptions = papszOpenOptionsCleaned;
4353 98 : continue;
4354 : }
4355 :
4356 511229 : const bool bIdentifyRes = nIdentifyRes == GDAL_IDENTIFY_TRUE;
4357 511229 : if (bIdentifyRes)
4358 : {
4359 62423 : GDALValidateOpenOptions(poDriver, papszOptionsToValidate);
4360 : }
4361 :
4362 : #ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION
4363 : const bool bFpAvailableBefore = oOpenInfo.fpL != nullptr;
4364 : CPLErrorReset();
4365 : #endif
4366 :
4367 511229 : sAntiRecursion.nRecLevel++;
4368 511229 : sAntiRecursion.aosDatasetNamesWithFlags.insert(dsCtxt);
4369 :
4370 511229 : GDALDataset *poDS = poDriver->Open(&oOpenInfo, false);
4371 :
4372 511229 : sAntiRecursion.nRecLevel--;
4373 511229 : sAntiRecursion.aosDatasetNamesWithFlags.erase(dsCtxt);
4374 :
4375 511229 : if (poDriver->pfnOpen != nullptr)
4376 : {
4377 : // If we couldn't determine for sure with Identify() (it returned
4378 : // -1), but Open() managed to open the file, post validate options.
4379 511226 : if (poDS != nullptr &&
4380 62279 : (poDriver->pfnIdentify || poDriver->pfnIdentifyEx) &&
4381 61710 : !bIdentifyRes)
4382 : {
4383 837 : GDALValidateOpenOptions(poDriver, papszOptionsToValidate);
4384 : }
4385 : }
4386 3 : else if (poDriver->pfnOpenWithDriverArg != nullptr)
4387 : {
4388 : // do nothing
4389 : }
4390 0 : else if (bIdentifyRes &&
4391 0 : poDriver->GetMetadataItem("MISSING_PLUGIN_FILENAME"))
4392 : {
4393 0 : if (!poMissingPluginDriver)
4394 : {
4395 0 : poMissingPluginDriver = poDriver;
4396 : }
4397 : }
4398 : else
4399 : {
4400 : // should not happen given the GDAL_DCAP_OPEN check
4401 0 : CSLDestroy(papszTmpOpenOptions);
4402 0 : CSLDestroy(papszTmpOpenOptionsToValidate);
4403 0 : oOpenInfo.papszOpenOptions = papszOpenOptionsCleaned;
4404 0 : continue;
4405 : }
4406 :
4407 511229 : CSLDestroy(papszTmpOpenOptions);
4408 511229 : CSLDestroy(papszTmpOpenOptionsToValidate);
4409 511229 : oOpenInfo.papszOpenOptions = papszOpenOptionsCleaned;
4410 :
4411 511229 : if (poDS != nullptr)
4412 : {
4413 62282 : if (poDS->papszOpenOptions == nullptr)
4414 : {
4415 62012 : poDS->papszOpenOptions = papszOpenOptionsCleaned;
4416 62012 : papszOpenOptionsCleaned = nullptr;
4417 : }
4418 :
4419 : // Deal with generic OVERVIEW_LEVEL open option, unless it is
4420 : // driver specific.
4421 62282 : if (CSLFetchNameValue(papszOpenOptions, "OVERVIEW_LEVEL") !=
4422 62321 : nullptr &&
4423 39 : !poDriver->HasOpenOption("OVERVIEW_LEVEL"))
4424 : {
4425 : CPLString osVal(
4426 78 : CSLFetchNameValue(papszOpenOptions, "OVERVIEW_LEVEL"));
4427 39 : const int nOvrLevel = EQUAL(osVal, "NONE") ? -1 : atoi(osVal);
4428 : const bool bThisLevelOnly =
4429 39 : nOvrLevel == -1 || osVal.ifind("only") != std::string::npos;
4430 : GDALDataset *poOvrDS =
4431 39 : GDALCreateOverviewDataset(poDS, nOvrLevel, bThisLevelOnly);
4432 39 : if (poOvrDS && (nOpenFlags & GDAL_OF_SHARED) != 0)
4433 : {
4434 4 : if (strcmp(pszFilename, poDS->GetDescription()) != 0)
4435 : {
4436 0 : CPLError(
4437 : CE_Warning, CPLE_NotSupported,
4438 : "A dataset opened by GDALOpenShared should have "
4439 : "the same filename (%s) "
4440 : "and description (%s)",
4441 0 : pszFilename, poDS->GetDescription());
4442 : }
4443 : else
4444 : {
4445 4 : CSLDestroy(poDS->papszOpenOptions);
4446 4 : poDS->papszOpenOptions = CSLDuplicate(papszOpenOptions);
4447 4 : poDS->papszOpenOptions = CSLSetNameValue(
4448 : poDS->papszOpenOptions, "OVERVIEW_LEVEL", nullptr);
4449 : }
4450 : }
4451 39 : poDS->ReleaseRef();
4452 39 : poDS = poOvrDS;
4453 39 : if (poDS == nullptr)
4454 : {
4455 1 : if (nOpenFlags & GDAL_OF_VERBOSE_ERROR)
4456 : {
4457 1 : CPLError(CE_Failure, CPLE_OpenFailed,
4458 : "Cannot open overview level %d of %s",
4459 : nOvrLevel, pszFilename);
4460 : }
4461 : }
4462 : else
4463 : {
4464 : // For thread-safe opening, currently poDS is what will be
4465 : // the "master" dataset owned by the thread-safe dataset
4466 : // returned to the user, hence we do not register it as a
4467 : // visible one in the open dataset list, or mark it as shared.
4468 38 : if (!(nOpenFlags & GDAL_OF_INTERNAL) &&
4469 36 : !(nOpenFlags & GDAL_OF_THREAD_SAFE))
4470 : {
4471 35 : poDS->AddToDatasetOpenList();
4472 : }
4473 38 : if (nOpenFlags & GDAL_OF_SHARED)
4474 : {
4475 4 : CSLDestroy(poDS->papszOpenOptions);
4476 4 : poDS->papszOpenOptions = CSLDuplicate(papszOpenOptions);
4477 4 : poDS->nOpenFlags = nOpenFlags;
4478 4 : if (!(nOpenFlags & GDAL_OF_THREAD_SAFE))
4479 4 : poDS->MarkAsShared();
4480 : }
4481 : }
4482 : }
4483 62243 : else if (nOpenFlags & GDAL_OF_SHARED)
4484 : {
4485 373 : if (strcmp(pszFilename, poDS->GetDescription()) != 0)
4486 : {
4487 2 : CPLError(CE_Warning, CPLE_NotSupported,
4488 : "A dataset opened by GDALOpenShared should have "
4489 : "the same filename (%s) "
4490 : "and description (%s)",
4491 2 : pszFilename, poDS->GetDescription());
4492 : }
4493 371 : else if (!(nOpenFlags & GDAL_OF_THREAD_SAFE))
4494 : {
4495 : // For thread-safe opening, currently poDS is what will be
4496 : // the "master" dataset owned by the thread-safe dataset
4497 : // returned to the user, hence we do not or mark it as shared.
4498 371 : poDS->MarkAsShared();
4499 : }
4500 : }
4501 :
4502 62282 : VSIErrorReset();
4503 :
4504 62282 : CSLDestroy(papszOpenOptionsCleaned);
4505 :
4506 : #ifdef OGRAPISPY_ENABLED
4507 62282 : if (iSnapshot != INT_MIN)
4508 : {
4509 11807 : GDALDatasetH hDS = GDALDataset::ToHandle(poDS);
4510 11807 : OGRAPISpyOpen(pszFilename, bUpdate, iSnapshot, &hDS);
4511 11807 : poDS = GDALDataset::FromHandle(hDS);
4512 : }
4513 : #endif
4514 :
4515 62282 : if (poDS)
4516 : {
4517 62281 : poDS->m_bCanBeReopened = true;
4518 :
4519 62281 : if ((nOpenFlags & GDAL_OF_THREAD_SAFE) != 0)
4520 : {
4521 : poDS =
4522 248 : GDALGetThreadSafeDataset(
4523 248 : std::unique_ptr<GDALDataset>(poDS), GDAL_OF_RASTER)
4524 124 : .release();
4525 124 : if (poDS)
4526 : {
4527 124 : poDS->m_bCanBeReopened = true;
4528 124 : poDS->poDriver = poDriver;
4529 124 : poDS->nOpenFlags = nOpenFlags;
4530 124 : if (!(nOpenFlags & GDAL_OF_INTERNAL))
4531 124 : poDS->AddToDatasetOpenList();
4532 124 : if (nOpenFlags & GDAL_OF_SHARED)
4533 0 : poDS->MarkAsShared();
4534 : }
4535 : }
4536 : }
4537 :
4538 63391 : return std::unique_ptr<GDALDataset>(poDS);
4539 : }
4540 :
4541 : #ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION
4542 : if (bFpAvailableBefore && oOpenInfo.fpL == nullptr)
4543 : {
4544 : // In case the file descriptor was "consumed" by a driver
4545 : // that ultimately failed, re-open it for next drivers.
4546 : oOpenInfo.fpL = VSIFOpenL(
4547 : pszFilename, (oOpenInfo.eAccess == GA_Update) ? "r+b" : "rb");
4548 : }
4549 : #else
4550 448947 : if (CPLGetLastErrorNo() != 0 && CPLGetLastErrorType() > CE_Warning)
4551 : {
4552 1109 : CSLDestroy(papszOpenOptionsCleaned);
4553 :
4554 : #ifdef OGRAPISPY_ENABLED
4555 1109 : if (iSnapshot != INT_MIN)
4556 : {
4557 194 : GDALDatasetH hDS = nullptr;
4558 194 : OGRAPISpyOpen(pszFilename, bUpdate, iSnapshot, &hDS);
4559 : }
4560 : #endif
4561 1109 : return nullptr;
4562 : }
4563 : #endif
4564 : }
4565 :
4566 : // cppcheck-suppress knownConditionTrueFalse
4567 18843 : if (iPass == 1 && !apoSecondPassDrivers.empty())
4568 : {
4569 14 : CPLDebugOnly("GDAL", "GDALOpen(): Second pass");
4570 14 : iPass = 2;
4571 14 : goto retry;
4572 : }
4573 :
4574 18829 : CSLDestroy(papszOpenOptionsCleaned);
4575 :
4576 : #ifdef OGRAPISPY_ENABLED
4577 18829 : if (iSnapshot != INT_MIN)
4578 : {
4579 687 : GDALDatasetH hDS = nullptr;
4580 687 : OGRAPISpyOpen(pszFilename, bUpdate, iSnapshot, &hDS);
4581 : }
4582 : #endif
4583 :
4584 18829 : if (nOpenFlags & GDAL_OF_VERBOSE_ERROR)
4585 : {
4586 11962 : std::string osHint;
4587 11962 : const CPLStringList aosVSIFSPrefixes(VSIFileManager::GetPrefixes());
4588 185326 : for (const char *pszFSPrefix : aosVSIFSPrefixes)
4589 : {
4590 179352 : auto poFS = VSIFileManager::GetHandler(pszFSPrefix);
4591 179352 : if (poFS)
4592 : {
4593 179352 : osHint = poFS->GetHintForPotentiallyRecognizedPath(pszFilename);
4594 179352 : if (!osHint.empty())
4595 : {
4596 14 : osHint = " Changing the filename to " + osHint +
4597 7 : " may help it to be recognized.";
4598 7 : break;
4599 : }
4600 : }
4601 : }
4602 :
4603 5981 : if (nDriverCount == 0)
4604 : {
4605 0 : CPLError(CE_Failure, CPLE_OpenFailed, "No driver registered.");
4606 : }
4607 5981 : else if (poMissingPluginDriver)
4608 : {
4609 0 : std::string osMsg("`");
4610 0 : osMsg += pszFilename;
4611 : osMsg += "' not recognized as being in a supported file format. "
4612 0 : "It could have been recognized by driver ";
4613 0 : osMsg += poMissingPluginDriver->GetDescription();
4614 0 : osMsg += ", but plugin ";
4615 : osMsg +=
4616 0 : GDALGetMessageAboutMissingPluginDriver(poMissingPluginDriver);
4617 :
4618 0 : CPLError(CE_Failure, CPLE_OpenFailed, "%s", osMsg.c_str());
4619 : }
4620 : // Check to see if there was a filesystem error, and report it if so.
4621 : // If not, return a more generic error.
4622 5981 : else if (!osHint.empty() && VSIGetLastErrorNo() == VSIE_FileError)
4623 : {
4624 3 : CPLError(CE_Failure, CPLE_FileIO, "%s.%s", VSIGetLastErrorMsg(),
4625 : osHint.c_str());
4626 : }
4627 5978 : else if (!VSIToCPLError(CE_Failure, CPLE_OpenFailed))
4628 : {
4629 518 : if (oOpenInfo.bStatOK)
4630 : {
4631 513 : CPLError(CE_Failure, CPLE_OpenFailed,
4632 : "`%s' not recognized as being in a supported file "
4633 : "format.%s",
4634 : pszFilename, osHint.c_str());
4635 : }
4636 : else
4637 : {
4638 : // If Stat failed and no VSI error was set, assume it is because
4639 : // the file did not exist on the filesystem.
4640 5 : CPLError(CE_Failure, CPLE_OpenFailed,
4641 : "`%s' does not exist in the file system, "
4642 : "and is not recognized as a supported dataset name.%s",
4643 : pszFilename, osHint.c_str());
4644 : }
4645 : }
4646 : }
4647 :
4648 18829 : return nullptr;
4649 : }
4650 :
4651 : /************************************************************************/
4652 : /* GDALOpenShared() */
4653 : /************************************************************************/
4654 :
4655 : /**
4656 : * \brief Open a raster file as a GDALDataset.
4657 : *
4658 : * This function works the same as GDALOpen(), but allows the sharing of
4659 : * GDALDataset handles for a dataset with other callers to GDALOpenShared().
4660 : *
4661 : * In particular, GDALOpenShared() will first consult its list of currently
4662 : * open and shared GDALDataset's, and if the GetDescription() name for one
4663 : * exactly matches the pszFilename passed to GDALOpenShared() it will be
4664 : * referenced and returned.
4665 : *
4666 : * If GDALOpenShared() is called on the same
4667 : * pszFilename from two different threads, a different GDALDataset object will
4668 : * be returned as it is not safe to use the same dataset from different threads,
4669 : * unless the user does explicitly use mutexes in its code.
4670 : *
4671 : * For drivers supporting the VSI virtual file API, it is possible to open a
4672 : * file in a .zip archive (see VSIInstallZipFileHandler()), in a
4673 : * .tar/.tar.gz/.tgz archive (see VSIInstallTarFileHandler()) or on a HTTP / FTP
4674 : * server (see VSIInstallCurlFileHandler())
4675 : *
4676 : * \sa GDALOpen()
4677 : * \sa GDALOpenEx()
4678 : *
4679 : * @param pszFilename the name of the file to access. In the case of
4680 : * exotic drivers this may not refer to a physical file, but instead contain
4681 : * information for the driver on how to access a dataset. It should be in
4682 : * UTF-8 encoding.
4683 : *
4684 : * @param eAccess the desired access, either GA_Update or GA_ReadOnly. Many
4685 : * drivers support only read only access.
4686 : *
4687 : * @return A GDALDatasetH handle or NULL on failure. For C++ applications
4688 : * this handle can be cast to a GDALDataset *.
4689 : */
4690 :
4691 5208 : GDALDatasetH CPL_STDCALL GDALOpenShared(const char *pszFilename,
4692 : GDALAccess eAccess)
4693 : {
4694 5208 : VALIDATE_POINTER1(pszFilename, "GDALOpenShared", nullptr);
4695 5208 : return GDALOpenEx(pszFilename,
4696 : GDAL_OF_RASTER |
4697 : (eAccess == GA_Update ? GDAL_OF_UPDATE : 0) |
4698 : GDAL_OF_SHARED | GDAL_OF_VERBOSE_ERROR,
4699 5208 : nullptr, nullptr, nullptr);
4700 : }
4701 :
4702 : /************************************************************************/
4703 : /* GDALClose() */
4704 : /************************************************************************/
4705 :
4706 : /**
4707 : * \brief Close GDAL dataset.
4708 : *
4709 : * For non-shared datasets (opened with GDALOpen()) the dataset is closed
4710 : * using the C++ "delete" operator, recovering all dataset related resources.
4711 : * For shared datasets (opened with GDALOpenShared()) the dataset is
4712 : * dereferenced, and closed only if the referenced count has dropped below 1.
4713 : *
4714 : * @param hDS The dataset to close, or nullptr.
4715 : * @return CE_None in case of success (return value since GDAL 3.7). On a
4716 : * shared dataset whose reference count is not dropped below 1, CE_None will
4717 : * be returned.
4718 : *
4719 : * @see GDALCloseEx()
4720 : */
4721 :
4722 85905 : CPLErr CPL_STDCALL GDALClose(GDALDatasetH hDS)
4723 :
4724 : {
4725 85905 : return GDALCloseEx(hDS, nullptr, nullptr);
4726 : }
4727 :
4728 : /************************************************************************/
4729 : /* GDALCloseEx() */
4730 : /************************************************************************/
4731 :
4732 : /**
4733 : * \brief Close GDAL dataset.
4734 : *
4735 : * For non-shared datasets (opened with GDALOpen()) the dataset is closed
4736 : * using the C++ "delete" operator, recovering all dataset related resources.
4737 : * For shared datasets (opened with GDALOpenShared()) the dataset is
4738 : * dereferenced, and closed only if the referenced count has dropped below 1.
4739 : *
4740 : * This function may report progress if a progress
4741 : * callback if provided in the pfnProgress argument and if the dataset returns
4742 : * true for GDALDataset::GetCloseReportsProgress()
4743 :
4744 : * @param hDS The dataset to close, or nullptr
4745 : * @param pfnProgress Progress callback, or nullptr
4746 : * @param pProgressData User data of progress callback, or nullptr
4747 : *
4748 : * @return CE_None in case of success. On a
4749 : * shared dataset whose reference count is not dropped below 1, CE_None will
4750 : * be returned.
4751 : *
4752 : * @since GDAL 3.13
4753 : * @see GDALClose()
4754 : */
4755 :
4756 90232 : CPLErr GDALCloseEx(GDALDatasetH hDS, GDALProgressFunc pfnProgress,
4757 : void *pProgressData)
4758 : {
4759 90232 : if (!hDS)
4760 404 : return CE_None;
4761 :
4762 : #ifdef OGRAPISPY_ENABLED
4763 89828 : if (bOGRAPISpyEnabled)
4764 11 : OGRAPISpyPreClose(hDS);
4765 : #endif
4766 :
4767 89828 : GDALDataset *poDS = GDALDataset::FromHandle(hDS);
4768 :
4769 89828 : if (poDS->GetShared())
4770 : {
4771 : /* --------------------------------------------------------------------
4772 : */
4773 : /* If this file is in the shared dataset list then dereference */
4774 : /* it, and only delete/remote it if the reference count has */
4775 : /* dropped to zero. */
4776 : /* --------------------------------------------------------------------
4777 : */
4778 232 : if (poDS->Dereference() > 0)
4779 15 : return CE_None;
4780 : }
4781 :
4782 89813 : CPLErr eErr = poDS->Close(pfnProgress, pProgressData);
4783 89813 : delete poDS;
4784 :
4785 : #ifdef OGRAPISPY_ENABLED
4786 89813 : if (bOGRAPISpyEnabled)
4787 11 : OGRAPISpyPostClose();
4788 : #endif
4789 89813 : return eErr;
4790 : }
4791 :
4792 : /************************************************************************/
4793 : /* GDALDumpOpenDataset() */
4794 : /************************************************************************/
4795 :
4796 0 : static int GDALDumpOpenSharedDatasetsForeach(void *elt, void *user_data)
4797 : {
4798 0 : SharedDatasetCtxt *psStruct = static_cast<SharedDatasetCtxt *>(elt);
4799 0 : FILE *fp = static_cast<FILE *>(user_data);
4800 0 : GDALDataset *poDS = psStruct->poDS;
4801 :
4802 0 : const char *pszDriverName = poDS->GetDriver() == nullptr
4803 0 : ? "DriverIsNULL"
4804 0 : : poDS->GetDriver()->GetDescription();
4805 :
4806 0 : poDS->Reference();
4807 0 : CPL_IGNORE_RET_VAL(
4808 0 : VSIFPrintf(fp, " %d %c %-6s %7d %dx%dx%d %s\n", poDS->Dereference(),
4809 0 : poDS->GetShared() ? 'S' : 'N', pszDriverName,
4810 0 : static_cast<int>(psStruct->nPID), poDS->GetRasterXSize(),
4811 : poDS->GetRasterYSize(), poDS->GetRasterCount(),
4812 0 : poDS->GetDescription()));
4813 :
4814 0 : return TRUE;
4815 : }
4816 :
4817 0 : static int GDALDumpOpenDatasetsForeach(GDALDataset *poDS, FILE *fp)
4818 : {
4819 :
4820 : // Don't list shared datasets. They have already been listed by
4821 : // GDALDumpOpenSharedDatasetsForeach.
4822 0 : if (poDS->GetShared())
4823 0 : return TRUE;
4824 :
4825 0 : const char *pszDriverName = poDS->GetDriver() == nullptr
4826 0 : ? "DriverIsNULL"
4827 0 : : poDS->GetDriver()->GetDescription();
4828 :
4829 0 : poDS->Reference();
4830 0 : CPL_IGNORE_RET_VAL(
4831 0 : VSIFPrintf(fp, " %d %c %-6s %7d %dx%dx%d %s\n", poDS->Dereference(),
4832 0 : poDS->GetShared() ? 'S' : 'N', pszDriverName, -1,
4833 : poDS->GetRasterXSize(), poDS->GetRasterYSize(),
4834 0 : poDS->GetRasterCount(), poDS->GetDescription()));
4835 :
4836 0 : return TRUE;
4837 : }
4838 :
4839 : /**
4840 : * \brief List open datasets.
4841 : *
4842 : * Dumps a list of all open datasets (shared or not) to the indicated
4843 : * text file (may be stdout or stderr). This function is primarily intended
4844 : * to assist in debugging "dataset leaks" and reference counting issues.
4845 : * The information reported includes the dataset name, referenced count,
4846 : * shared status, driver name, size, and band count.
4847 : */
4848 :
4849 272 : int CPL_STDCALL GDALDumpOpenDatasets(FILE *fp)
4850 :
4851 : {
4852 272 : VALIDATE_POINTER1(fp, "GDALDumpOpenDatasets", 0);
4853 :
4854 544 : CPLMutexHolderD(&hDLMutex);
4855 :
4856 272 : if (poAllDatasetMap == nullptr)
4857 272 : return 0;
4858 :
4859 0 : CPL_IGNORE_RET_VAL(VSIFPrintf(fp, "Open GDAL Datasets:\n"));
4860 :
4861 0 : for (const auto &oIter : *poAllDatasetMap)
4862 : {
4863 0 : GDALDumpOpenDatasetsForeach(oIter.first, fp);
4864 : }
4865 :
4866 0 : if (phSharedDatasetSet != nullptr)
4867 : {
4868 0 : CPLHashSetForeach(phSharedDatasetSet, GDALDumpOpenSharedDatasetsForeach,
4869 : fp);
4870 : }
4871 0 : return static_cast<int>(poAllDatasetMap->size());
4872 : }
4873 :
4874 : /************************************************************************/
4875 : /* BeginAsyncReader() */
4876 : /************************************************************************/
4877 :
4878 : /**
4879 : * \brief Sets up an asynchronous data request
4880 : *
4881 : * This method establish an asynchronous raster read request for the
4882 : * indicated window on the dataset into the indicated buffer. The parameters
4883 : * for windowing, buffer size, buffer type and buffer organization are similar
4884 : * to those for GDALDataset::RasterIO(); however, this call only launches
4885 : * the request and filling the buffer is accomplished via calls to
4886 : * GetNextUpdatedRegion() on the return GDALAsyncReader session object.
4887 : *
4888 : * Once all processing for the created session is complete, or if no further
4889 : * refinement of the request is required, the GDALAsyncReader object should
4890 : * be destroyed with the GDALDataset::EndAsyncReader() method.
4891 : *
4892 : * Note that the data buffer (pData) will potentially continue to be
4893 : * updated as long as the session lives, but it is not deallocated when
4894 : * the session (GDALAsyncReader) is destroyed with EndAsyncReader(). It
4895 : * should be deallocated by the application at that point.
4896 : *
4897 : * Additional information on asynchronous IO in GDAL may be found at:
4898 : * https://gdal.org/development/rfc/rfc24_progressive_data_support.html
4899 : *
4900 : * This method is the same as the C GDALBeginAsyncReader() function.
4901 : *
4902 : * @param nXOff The pixel offset to the top left corner of the region
4903 : * of the band to be accessed. This would be zero to start from the left side.
4904 : *
4905 : * @param nYOff The line offset to the top left corner of the region
4906 : * of the band to be accessed. This would be zero to start from the top.
4907 : *
4908 : * @param nXSize The width of the region of the band to be accessed in pixels.
4909 : *
4910 : * @param nYSize The height of the region of the band to be accessed in lines.
4911 : *
4912 : * @param pBuf The buffer into which the data should be read. This buffer must
4913 : * contain at least nBufXSize * nBufYSize * nBandCount words of type eBufType.
4914 : * It is organized in left to right,top to bottom pixel order. Spacing is
4915 : * controlled by the nPixelSpace, and nLineSpace parameters.
4916 : *
4917 : * @param nBufXSize the width of the buffer image into which the desired region
4918 : * is to be read, or from which it is to be written.
4919 : *
4920 : * @param nBufYSize the height of the buffer image into which the desired
4921 : * region is to be read, or from which it is to be written.
4922 : *
4923 : * @param eBufType the type of the pixel values in the pData data buffer. The
4924 : * pixel values will automatically be translated to/from the GDALRasterBand
4925 : * data type as needed.
4926 : *
4927 : * @param nBandCount the number of bands being read or written.
4928 : *
4929 : * @param panBandMap the list of nBandCount band numbers being read/written.
4930 : * Note band numbers are 1 based. This may be NULL to select the first
4931 : * nBandCount bands.
4932 : *
4933 : * @param nPixelSpace The byte offset from the start of one pixel value in
4934 : * pData to the start of the next pixel value within a scanline. If defaulted
4935 : * (0) the size of the datatype eBufType is used.
4936 : *
4937 : * @param nLineSpace The byte offset from the start of one scanline in
4938 : * pData to the start of the next. If defaulted the size of the datatype
4939 : * eBufType * nBufXSize is used.
4940 : *
4941 : * @param nBandSpace the byte offset from the start of one bands data to the
4942 : * start of the next. If defaulted (zero) the value will be
4943 : * nLineSpace * nBufYSize implying band sequential organization
4944 : * of the data buffer.
4945 : *
4946 : * @param papszOptions Driver specific control options in a string list or NULL.
4947 : * Consult driver documentation for options supported.
4948 : *
4949 : * @return The GDALAsyncReader object representing the request.
4950 : */
4951 :
4952 1 : GDALAsyncReader *GDALDataset::BeginAsyncReader(
4953 : int nXOff, int nYOff, int nXSize, int nYSize, void *pBuf, int nBufXSize,
4954 : int nBufYSize, GDALDataType eBufType, int nBandCount, int *panBandMap,
4955 : int nPixelSpace, int nLineSpace, int nBandSpace, CSLConstList papszOptions)
4956 : {
4957 : // See gdaldefaultasync.cpp
4958 :
4959 1 : return GDALGetDefaultAsyncReader(this, nXOff, nYOff, nXSize, nYSize, pBuf,
4960 : nBufXSize, nBufYSize, eBufType, nBandCount,
4961 : panBandMap, nPixelSpace, nLineSpace,
4962 1 : nBandSpace, papszOptions);
4963 : }
4964 :
4965 : /************************************************************************/
4966 : /* GDALBeginAsyncReader() */
4967 : /************************************************************************/
4968 :
4969 : /**
4970 : * \brief Sets up an asynchronous data request
4971 : *
4972 : * This method establish an asynchronous raster read request for the
4973 : * indicated window on the dataset into the indicated buffer. The parameters
4974 : * for windowing, buffer size, buffer type and buffer organization are similar
4975 : * to those for GDALDataset::RasterIO(); however, this call only launches
4976 : * the request and filling the buffer is accomplished via calls to
4977 : * GetNextUpdatedRegion() on the return GDALAsyncReader session object.
4978 : *
4979 : * Once all processing for the created session is complete, or if no further
4980 : * refinement of the request is required, the GDALAsyncReader object should
4981 : * be destroyed with the GDALDataset::EndAsyncReader() method.
4982 : *
4983 : * Note that the data buffer (pData) will potentially continue to be
4984 : * updated as long as the session lives, but it is not deallocated when
4985 : * the session (GDALAsyncReader) is destroyed with EndAsyncReader(). It
4986 : * should be deallocated by the application at that point.
4987 : *
4988 : * Additional information on asynchronous IO in GDAL may be found at:
4989 : * https://gdal.org/development/rfc/rfc24_progressive_data_support.html
4990 : *
4991 : * This method is the same as the C++ GDALDataset::BeginAsyncReader() method.
4992 : *
4993 : * @param hDS handle to the dataset object.
4994 : *
4995 : * @param nXOff The pixel offset to the top left corner of the region
4996 : * of the band to be accessed. This would be zero to start from the left side.
4997 : *
4998 : * @param nYOff The line offset to the top left corner of the region
4999 : * of the band to be accessed. This would be zero to start from the top.
5000 : *
5001 : * @param nXSize The width of the region of the band to be accessed in pixels.
5002 : *
5003 : * @param nYSize The height of the region of the band to be accessed in lines.
5004 : *
5005 : * @param pBuf The buffer into which the data should be read. This buffer must
5006 : * contain at least nBufXSize * nBufYSize * nBandCount words of type eBufType.
5007 : * It is organized in left to right,top to bottom pixel order. Spacing is
5008 : * controlled by the nPixelSpace, and nLineSpace parameters.
5009 : *
5010 : * @param nBufXSize the width of the buffer image into which the desired region
5011 : * is to be read, or from which it is to be written.
5012 : *
5013 : * @param nBufYSize the height of the buffer image into which the desired
5014 : * region is to be read, or from which it is to be written.
5015 : *
5016 : * @param eBufType the type of the pixel values in the pData data buffer. The
5017 : * pixel values will automatically be translated to/from the GDALRasterBand
5018 : * data type as needed.
5019 : *
5020 : * @param nBandCount the number of bands being read or written.
5021 : *
5022 : * @param panBandMap the list of nBandCount band numbers being read/written.
5023 : * Note band numbers are 1 based. This may be NULL to select the first
5024 : * nBandCount bands.
5025 : *
5026 : * @param nPixelSpace The byte offset from the start of one pixel value in
5027 : * pData to the start of the next pixel value within a scanline. If defaulted
5028 : * (0) the size of the datatype eBufType is used.
5029 : *
5030 : * @param nLineSpace The byte offset from the start of one scanline in
5031 : * pData to the start of the next. If defaulted the size of the datatype
5032 : * eBufType * nBufXSize is used.
5033 : *
5034 : * @param nBandSpace the byte offset from the start of one bands data to the
5035 : * start of the next. If defaulted (zero) the value will be
5036 : * nLineSpace * nBufYSize implying band sequential organization
5037 : * of the data buffer.
5038 : *
5039 : * @param papszOptions Driver specific control options in a string list or NULL.
5040 : * Consult driver documentation for options supported.
5041 : *
5042 : * @return handle representing the request.
5043 : */
5044 :
5045 2 : GDALAsyncReaderH CPL_STDCALL GDALBeginAsyncReader(
5046 : GDALDatasetH hDS, int nXOff, int nYOff, int nXSize, int nYSize, void *pBuf,
5047 : int nBufXSize, int nBufYSize, GDALDataType eBufType, int nBandCount,
5048 : int *panBandMap, int nPixelSpace, int nLineSpace, int nBandSpace,
5049 : CSLConstList papszOptions)
5050 :
5051 : {
5052 2 : VALIDATE_POINTER1(hDS, "GDALDataset", nullptr);
5053 : return static_cast<GDALAsyncReaderH>(
5054 2 : GDALDataset::FromHandle(hDS)->BeginAsyncReader(
5055 : nXOff, nYOff, nXSize, nYSize, pBuf, nBufXSize, nBufYSize, eBufType,
5056 : nBandCount, panBandMap, nPixelSpace, nLineSpace, nBandSpace,
5057 2 : const_cast<char **>(papszOptions)));
5058 : }
5059 :
5060 : /************************************************************************/
5061 : /* EndAsyncReader() */
5062 : /************************************************************************/
5063 :
5064 : /**
5065 : * End asynchronous request.
5066 : *
5067 : * This method destroys an asynchronous io request and recovers all
5068 : * resources associated with it.
5069 : *
5070 : * This method is the same as the C function GDALEndAsyncReader().
5071 : *
5072 : * @param poARIO pointer to a GDALAsyncReader
5073 : */
5074 :
5075 1 : void GDALDataset::EndAsyncReader(GDALAsyncReader *poARIO)
5076 : {
5077 1 : delete poARIO;
5078 1 : }
5079 :
5080 : /************************************************************************/
5081 : /* GDALEndAsyncReader() */
5082 : /************************************************************************/
5083 :
5084 : /**
5085 : * End asynchronous request.
5086 : *
5087 : * This method destroys an asynchronous io request and recovers all
5088 : * resources associated with it.
5089 : *
5090 : * This method is the same as the C++ method GDALDataset::EndAsyncReader().
5091 : *
5092 : * @param hDS handle to the dataset object.
5093 : * @param hAsyncReaderH handle returned by GDALBeginAsyncReader()
5094 : */
5095 :
5096 1 : void CPL_STDCALL GDALEndAsyncReader(GDALDatasetH hDS,
5097 : GDALAsyncReaderH hAsyncReaderH)
5098 : {
5099 1 : VALIDATE_POINTER0(hDS, "GDALDataset");
5100 1 : VALIDATE_POINTER0(hAsyncReaderH, "GDALAsyncReader");
5101 1 : GDALDataset::FromHandle(hDS)->EndAsyncReader(
5102 1 : static_cast<GDALAsyncReader *>(hAsyncReaderH));
5103 : }
5104 :
5105 : /************************************************************************/
5106 : /* CloseDependentDatasets() */
5107 : /************************************************************************/
5108 :
5109 : /**
5110 : * Drop references to any other datasets referenced by this dataset.
5111 : *
5112 : * This method should release any reference to other datasets (e.g. a VRT
5113 : * dataset to its sources), but not close the current dataset itself.
5114 : *
5115 : * If at least, one reference to a dependent dataset has been dropped,
5116 : * this method should return TRUE. Otherwise it *should* return FALSE.
5117 : * (Failure to return the proper value might result in infinite loop)
5118 : *
5119 : * This method can be called several times on a given dataset. After
5120 : * the first time, it should not do anything and return FALSE.
5121 : *
5122 : * The driver implementation may choose to destroy its raster bands,
5123 : * so be careful not to call any method on the raster bands afterwards.
5124 : *
5125 : * Basically the only safe action you can do after calling
5126 : * CloseDependentDatasets() is to call the destructor.
5127 : *
5128 : * Note: the only legitimate caller of CloseDependentDatasets() is
5129 : * GDALDriverManager::~GDALDriverManager()
5130 : *
5131 : * @return TRUE if at least one reference to another dataset has been dropped.
5132 : */
5133 19954 : int GDALDataset::CloseDependentDatasets()
5134 : {
5135 19954 : return oOvManager.CloseDependentDatasets();
5136 : }
5137 :
5138 : /************************************************************************/
5139 : /* ReportError() */
5140 : /************************************************************************/
5141 :
5142 : #ifndef DOXYGEN_XML
5143 : /**
5144 : * \brief Emits an error related to a dataset.
5145 : *
5146 : * This function is a wrapper for regular CPLError(). The only difference
5147 : * with CPLError() is that it prepends the error message with the dataset
5148 : * name.
5149 : *
5150 : * @param eErrClass one of CE_Warning, CE_Failure or CE_Fatal.
5151 : * @param err_no the error number (CPLE_*) from cpl_error.h.
5152 : * @param fmt a printf() style format string. Any additional arguments
5153 : * will be treated as arguments to fill in this format in a manner
5154 : * similar to printf().
5155 : *
5156 : */
5157 :
5158 105 : void GDALDataset::ReportError(CPLErr eErrClass, CPLErrorNum err_no,
5159 : const char *fmt, ...) const
5160 : {
5161 : va_list args;
5162 105 : va_start(args, fmt);
5163 105 : ReportErrorV(GetDescription(), eErrClass, err_no, fmt, args);
5164 105 : va_end(args);
5165 105 : }
5166 :
5167 : /**
5168 : * \brief Emits an error related to a dataset (static method)
5169 : *
5170 : * This function is a wrapper for regular CPLError(). The only difference
5171 : * with CPLError() is that it prepends the error message with the dataset
5172 : * name.
5173 : *
5174 : * @param pszDSName dataset name.
5175 : * @param eErrClass one of CE_Warning, CE_Failure or CE_Fatal.
5176 : * @param err_no the error number (CPLE_*) from cpl_error.h.
5177 : * @param fmt a printf() style format string. Any additional arguments
5178 : * will be treated as arguments to fill in this format in a manner
5179 : * similar to printf().
5180 : *
5181 : * @since GDAL 3.2.0
5182 : */
5183 :
5184 187 : void GDALDataset::ReportError(const char *pszDSName, CPLErr eErrClass,
5185 : CPLErrorNum err_no, const char *fmt, ...)
5186 : {
5187 : va_list args;
5188 187 : va_start(args, fmt);
5189 187 : ReportErrorV(pszDSName, eErrClass, err_no, fmt, args);
5190 187 : va_end(args);
5191 187 : }
5192 :
5193 292 : void GDALDataset::ReportErrorV(const char *pszDSName, CPLErr eErrClass,
5194 : CPLErrorNum err_no, const char *fmt,
5195 : va_list args)
5196 : {
5197 292 : pszDSName = CPLGetFilename(pszDSName);
5198 292 : if (pszDSName[0] != '\0')
5199 : {
5200 275 : CPLError(eErrClass, err_no, "%s",
5201 550 : std::string(pszDSName)
5202 275 : .append(": ")
5203 550 : .append(CPLString().vPrintf(fmt, args))
5204 : .c_str());
5205 : }
5206 : else
5207 : {
5208 17 : CPLErrorV(eErrClass, err_no, fmt, args);
5209 : }
5210 292 : }
5211 : #endif
5212 :
5213 : /************************************************************************/
5214 : /* GetMetadata() */
5215 : /************************************************************************/
5216 73945 : CSLConstList GDALDataset::GetMetadata(const char *pszDomain)
5217 : {
5218 : #ifndef WITHOUT_DERIVED
5219 73945 : if (pszDomain != nullptr && EQUAL(pszDomain, "DERIVED_SUBDATASETS"))
5220 : {
5221 10 : oDerivedMetadataList.Clear();
5222 :
5223 : // First condition: at least one raster band.
5224 10 : if (GetRasterCount() > 0)
5225 : {
5226 : // Check if there is at least one complex band.
5227 10 : bool hasAComplexBand = false;
5228 :
5229 19 : for (int rasterId = 1; rasterId <= GetRasterCount(); ++rasterId)
5230 : {
5231 11 : if (GDALDataTypeIsComplex(
5232 11 : GetRasterBand(rasterId)->GetRasterDataType()))
5233 : {
5234 2 : hasAComplexBand = true;
5235 2 : break;
5236 : }
5237 : }
5238 :
5239 10 : unsigned int nbSupportedDerivedDS = 0;
5240 : const DerivedDatasetDescription *poDDSDesc =
5241 10 : GDALGetDerivedDatasetDescriptions(&nbSupportedDerivedDS);
5242 :
5243 10 : int nNumDataset = 1;
5244 80 : for (unsigned int derivedId = 0; derivedId < nbSupportedDerivedDS;
5245 : ++derivedId)
5246 : {
5247 126 : if (hasAComplexBand ||
5248 126 : CPLString(poDDSDesc[derivedId].pszInputPixelType) !=
5249 : "complex")
5250 : {
5251 : oDerivedMetadataList.SetNameValue(
5252 : CPLSPrintf("DERIVED_SUBDATASET_%d_NAME", nNumDataset),
5253 : CPLSPrintf("DERIVED_SUBDATASET:%s:%s",
5254 22 : poDDSDesc[derivedId].pszDatasetName,
5255 22 : GetDescription()));
5256 :
5257 : CPLString osDesc(
5258 : CPLSPrintf("%s from %s",
5259 22 : poDDSDesc[derivedId].pszDatasetDescription,
5260 22 : GetDescription()));
5261 : oDerivedMetadataList.SetNameValue(
5262 : CPLSPrintf("DERIVED_SUBDATASET_%d_DESC", nNumDataset),
5263 22 : osDesc.c_str());
5264 :
5265 22 : nNumDataset++;
5266 : }
5267 : }
5268 : }
5269 10 : return oDerivedMetadataList.List();
5270 : }
5271 : #endif
5272 :
5273 73935 : return GDALMajorObject::GetMetadata(pszDomain);
5274 : }
5275 :
5276 : // clang-format off
5277 :
5278 : /**
5279 : * \fn GDALDataset::SetMetadata( char ** papszMetadata, const char * pszDomain)
5280 : * \brief Set metadata.
5281 : *
5282 : * CAUTION: depending on the format, older values of the updated information
5283 : * might still be found in the file in a "ghost" state, even if no longer
5284 : * accessible through the GDAL API. This is for example the case of the GTiff
5285 : * format (this is not a exhaustive list)
5286 : *
5287 : * The C function GDALSetMetadata() does the same thing as this method.
5288 : *
5289 : * @param papszMetadata the metadata in name=value string list format to
5290 : * apply.
5291 : * @param pszDomain the domain of interest. Use "" or NULL for the default
5292 : * domain.
5293 : * @return CE_None on success, CE_Failure on failure and CE_Warning if the
5294 : * metadata has been accepted, but is likely not maintained persistently
5295 : * by the underlying object between sessions.
5296 : */
5297 :
5298 : /**
5299 : * \fn GDALDataset::SetMetadataItem( const char * pszName, const char * pszValue, const char * pszDomain)
5300 : * \brief Set single metadata item.
5301 : *
5302 : * CAUTION: depending on the format, older values of the updated information
5303 : * might still be found in the file in a "ghost" state, even if no longer
5304 : * accessible through the GDAL API. This is for example the case of the GTiff
5305 : * format (this is not a exhaustive list)
5306 : *
5307 : * The C function GDALSetMetadataItem() does the same thing as this method.
5308 : *
5309 : * @param pszName the key for the metadata item to fetch.
5310 : * @param pszValue the value to assign to the key.
5311 : * @param pszDomain the domain to set within, use NULL for the default domain.
5312 : *
5313 : * @return CE_None on success, or an error code on failure.
5314 : */
5315 :
5316 : // clang-format on
5317 :
5318 : /************************************************************************/
5319 : /* GetMetadataDomainList() */
5320 : /************************************************************************/
5321 :
5322 1104 : char **GDALDataset::GetMetadataDomainList()
5323 : {
5324 1104 : char **currentDomainList = CSLDuplicate(oMDMD.GetDomainList());
5325 :
5326 : // Ensure that we do not duplicate DERIVED domain.
5327 1251 : if (GetRasterCount() > 0 &&
5328 147 : CSLFindString(currentDomainList, "DERIVED_SUBDATASETS") == -1)
5329 : {
5330 : currentDomainList =
5331 147 : CSLAddString(currentDomainList, "DERIVED_SUBDATASETS");
5332 : }
5333 1104 : return currentDomainList;
5334 : }
5335 :
5336 : /************************************************************************/
5337 : /* GetDriverName() */
5338 : /************************************************************************/
5339 :
5340 : /** Return driver name.
5341 : * @return driver name.
5342 : */
5343 2364 : const char *GDALDataset::GetDriverName() const
5344 : {
5345 2364 : if (poDriver)
5346 2350 : return poDriver->GetDescription();
5347 14 : return "";
5348 : }
5349 :
5350 : /************************************************************************/
5351 : /* GDALDatasetReleaseResultSet() */
5352 : /************************************************************************/
5353 :
5354 : /**
5355 : \brief Release results of ExecuteSQL().
5356 :
5357 : This function should only be used to deallocate OGRLayers resulting from
5358 : an ExecuteSQL() call on the same GDALDataset. Failure to deallocate a
5359 : results set before destroying the GDALDataset may cause errors.
5360 :
5361 : This function is the same as the C++ method GDALDataset::ReleaseResultSet()
5362 :
5363 :
5364 : @param hDS the dataset handle.
5365 : @param hLayer the result of a previous ExecuteSQL() call.
5366 :
5367 : */
5368 3546 : void GDALDatasetReleaseResultSet(GDALDatasetH hDS, OGRLayerH hLayer)
5369 :
5370 : {
5371 3546 : VALIDATE_POINTER0(hDS, "GDALDatasetReleaseResultSet");
5372 :
5373 : #ifdef OGRAPISPY_ENABLED
5374 3546 : if (bOGRAPISpyEnabled)
5375 6 : OGRAPISpy_DS_ReleaseResultSet(hDS, hLayer);
5376 : #endif
5377 :
5378 7092 : GDALDataset::FromHandle(hDS)->ReleaseResultSet(
5379 3546 : OGRLayer::FromHandle(hLayer));
5380 : }
5381 :
5382 : /************************************************************************/
5383 : /* GDALDatasetGetLayerCount() */
5384 : /************************************************************************/
5385 :
5386 : /**
5387 : \brief Get the number of layers in this dataset.
5388 :
5389 : This function is the same as the C++ method GDALDataset::GetLayerCount()
5390 :
5391 :
5392 : @param hDS the dataset handle.
5393 : @return layer count.
5394 : */
5395 :
5396 1614 : int GDALDatasetGetLayerCount(GDALDatasetH hDS)
5397 :
5398 : {
5399 1614 : VALIDATE_POINTER1(hDS, "GDALDatasetH", 0);
5400 :
5401 : #ifdef OGRAPISPY_ENABLED
5402 1614 : if (bOGRAPISpyEnabled)
5403 2 : OGRAPISpy_DS_GetLayerCount(reinterpret_cast<GDALDatasetH>(hDS));
5404 : #endif
5405 :
5406 1614 : return GDALDataset::FromHandle(hDS)->GetLayerCount();
5407 : }
5408 :
5409 : /************************************************************************/
5410 : /* GDALDatasetGetLayer() */
5411 : /************************************************************************/
5412 :
5413 : /**
5414 : \brief Fetch a layer by index.
5415 :
5416 : The returned layer remains owned by the
5417 : GDALDataset and should not be deleted by the application.
5418 :
5419 : This function is the same as the C++ method GDALDataset::GetLayer()
5420 :
5421 :
5422 : @param hDS the dataset handle.
5423 : @param iLayer a layer number between 0 and GetLayerCount()-1.
5424 :
5425 : @return the layer, or NULL if iLayer is out of range or an error occurs.
5426 : */
5427 :
5428 10127 : OGRLayerH GDALDatasetGetLayer(GDALDatasetH hDS, int iLayer)
5429 :
5430 : {
5431 10127 : VALIDATE_POINTER1(hDS, "GDALDatasetGetLayer", nullptr);
5432 :
5433 : OGRLayerH hLayer =
5434 10127 : OGRLayer::ToHandle(GDALDataset::FromHandle(hDS)->GetLayer(iLayer));
5435 :
5436 : #ifdef OGRAPISPY_ENABLED
5437 10127 : if (bOGRAPISpyEnabled)
5438 3 : OGRAPISpy_DS_GetLayer(hDS, iLayer, hLayer);
5439 : #endif
5440 :
5441 10127 : return hLayer;
5442 : }
5443 :
5444 : /************************************************************************/
5445 : /* GDALDatasetGetLayerByName() */
5446 : /************************************************************************/
5447 :
5448 : /**
5449 : \brief Fetch a layer by name.
5450 :
5451 : The returned layer remains owned by the
5452 : GDALDataset and should not be deleted by the application.
5453 :
5454 : This function is the same as the C++ method GDALDataset::GetLayerByName()
5455 :
5456 :
5457 : @param hDS the dataset handle.
5458 : @param pszName the layer name of the layer to fetch.
5459 :
5460 : @return the layer, or NULL if Layer is not found or an error occurs.
5461 : */
5462 :
5463 3423 : OGRLayerH GDALDatasetGetLayerByName(GDALDatasetH hDS, const char *pszName)
5464 :
5465 : {
5466 3423 : VALIDATE_POINTER1(hDS, "GDALDatasetGetLayerByName", nullptr);
5467 :
5468 3423 : OGRLayerH hLayer = OGRLayer::ToHandle(
5469 3423 : GDALDataset::FromHandle(hDS)->GetLayerByName(pszName));
5470 :
5471 : #ifdef OGRAPISPY_ENABLED
5472 3423 : if (bOGRAPISpyEnabled)
5473 4 : OGRAPISpy_DS_GetLayerByName(hDS, pszName, hLayer);
5474 : #endif
5475 :
5476 3423 : return hLayer;
5477 : }
5478 :
5479 : /************************************************************************/
5480 : /* GDALDatasetIsLayerPrivate() */
5481 : /************************************************************************/
5482 :
5483 : /**
5484 : \brief Returns true if the layer at the specified index is deemed a private or
5485 : system table, or an internal detail only.
5486 :
5487 : This function is the same as the C++ method GDALDataset::IsLayerPrivate()
5488 :
5489 : @since GDAL 3.4
5490 :
5491 : @param hDS the dataset handle.
5492 : @param iLayer a layer number between 0 and GetLayerCount()-1.
5493 :
5494 : @return true if the layer is a private or system table.
5495 : */
5496 :
5497 91 : int GDALDatasetIsLayerPrivate(GDALDatasetH hDS, int iLayer)
5498 :
5499 : {
5500 91 : VALIDATE_POINTER1(hDS, "GDALDatasetIsLayerPrivate", false);
5501 :
5502 91 : const bool res = GDALDataset::FromHandle(hDS)->IsLayerPrivate(iLayer);
5503 :
5504 91 : return res ? 1 : 0;
5505 : }
5506 :
5507 : /************************************************************************/
5508 : /* GetLayerIndex() */
5509 : /************************************************************************/
5510 :
5511 : /**
5512 : \brief Returns the index of the layer specified by name.
5513 :
5514 : @since GDAL 3.12
5515 :
5516 : @param pszName layer name (not NULL)
5517 :
5518 : @return an index >= 0, or -1 if not found.
5519 : */
5520 :
5521 3 : int GDALDataset::GetLayerIndex(const char *pszName) const
5522 : {
5523 3 : const int nLayerCount = GetLayerCount();
5524 3 : int iMatch = -1;
5525 6 : for (int i = 0; i < nLayerCount; ++i)
5526 : {
5527 5 : if (const auto poLayer = GetLayer(i))
5528 : {
5529 5 : const char *pszLayerName = poLayer->GetDescription();
5530 5 : if (strcmp(pszName, pszLayerName) == 0)
5531 : {
5532 2 : iMatch = i;
5533 2 : break;
5534 : }
5535 3 : else if (EQUAL(pszName, pszLayerName))
5536 : {
5537 0 : iMatch = i;
5538 : }
5539 : }
5540 : }
5541 3 : return iMatch;
5542 : }
5543 :
5544 : /************************************************************************/
5545 : /* GDALDatasetDeleteLayer() */
5546 : /************************************************************************/
5547 :
5548 : /**
5549 : \brief Delete the indicated layer from the datasource.
5550 :
5551 : If this function is supported
5552 : the ODsCDeleteLayer capability will test TRUE on the GDALDataset.
5553 :
5554 : This method is the same as the C++ method GDALDataset::DeleteLayer().
5555 :
5556 :
5557 : @param hDS the dataset handle.
5558 : @param iLayer the index of the layer to delete.
5559 :
5560 : @return OGRERR_NONE on success, or OGRERR_UNSUPPORTED_OPERATION if deleting
5561 : layers is not supported for this datasource.
5562 :
5563 : */
5564 41 : OGRErr GDALDatasetDeleteLayer(GDALDatasetH hDS, int iLayer)
5565 :
5566 : {
5567 41 : VALIDATE_POINTER1(hDS, "GDALDatasetH", OGRERR_INVALID_HANDLE);
5568 :
5569 : #ifdef OGRAPISPY_ENABLED
5570 41 : if (bOGRAPISpyEnabled)
5571 2 : OGRAPISpy_DS_DeleteLayer(hDS, iLayer);
5572 : #endif
5573 :
5574 41 : return GDALDataset::FromHandle(hDS)->DeleteLayer(iLayer);
5575 : }
5576 :
5577 : /************************************************************************/
5578 : /* CreateLayer() */
5579 : /************************************************************************/
5580 :
5581 : /**
5582 : \brief This method attempts to create a new layer on the dataset with the
5583 : indicated name, coordinate system, geometry type.
5584 :
5585 : The papszOptions argument
5586 : can be used to control driver specific creation options. These options are
5587 : normally documented in the format specific documentation.
5588 : That function will try to validate the creation option list passed to the
5589 : driver with the GDALValidateCreationOptions() method. This check can be
5590 : disabled by defining the configuration option GDAL_VALIDATE_CREATION_OPTIONS set
5591 : to NO.
5592 :
5593 : Drivers should extend the ICreateLayer() method and not
5594 : CreateLayer(). CreateLayer() adds validation of layer creation options, before
5595 : delegating the actual work to ICreateLayer().
5596 :
5597 : This method is the same as the C function GDALDatasetCreateLayer() and the
5598 : deprecated OGR_DS_CreateLayer().
5599 :
5600 : Example:
5601 :
5602 : \code{.cpp}
5603 : #include "gdal.h"
5604 : #include "cpl_string.h"
5605 :
5606 : ...
5607 :
5608 : OGRLayer *poLayer;
5609 : char **papszOptions;
5610 :
5611 : if( !poDS->TestCapability( ODsCCreateLayer ) )
5612 : {
5613 : ...
5614 : }
5615 :
5616 : papszOptions = CSLSetNameValue( papszOptions, "DIM", "2" );
5617 : poLayer = poDS->CreateLayer( "NewLayer", nullptr, wkbUnknown,
5618 : papszOptions );
5619 : CSLDestroy( papszOptions );
5620 :
5621 : if( poLayer == NULL )
5622 : {
5623 : ...
5624 : }
5625 : \endcode
5626 :
5627 : @param pszName the name for the new layer. This should ideally not
5628 : match any existing layer on the datasource.
5629 : @param poSpatialRef the coordinate system to use for the new layer, or NULL if
5630 : no coordinate system is available.
5631 : @param eGType the geometry type for the layer. Use wkbUnknown if there
5632 : are no constraints on the types geometry to be written.
5633 : @param papszOptions a StringList of name=value options. Options are driver
5634 : specific.
5635 :
5636 : @return NULL is returned on failure, or a new OGRLayer handle on success.
5637 :
5638 : */
5639 :
5640 8413 : OGRLayer *GDALDataset::CreateLayer(const char *pszName,
5641 : const OGRSpatialReference *poSpatialRef,
5642 : OGRwkbGeometryType eGType,
5643 : CSLConstList papszOptions)
5644 :
5645 : {
5646 8413 : if (eGType == wkbNone)
5647 : {
5648 526 : return CreateLayer(pszName, nullptr, papszOptions);
5649 : }
5650 : else
5651 : {
5652 15774 : OGRGeomFieldDefn oGeomFieldDefn("", eGType);
5653 7887 : oGeomFieldDefn.SetSpatialRef(poSpatialRef);
5654 7887 : return CreateLayer(pszName, &oGeomFieldDefn, papszOptions);
5655 : }
5656 : }
5657 :
5658 : /**
5659 : \brief This method attempts to create a new layer on the dataset with the
5660 : indicated name and geometry field definition.
5661 :
5662 : When poGeomFieldDefn is not null, most drivers should honor
5663 : poGeomFieldDefn->GetType() and poGeomFieldDefn->GetSpatialRef().
5664 : Drivers that honor poGeomFieldDefn->GetCoordinatePrecision() will declare the
5665 : GDAL_DCAP_HONOR_GEOM_COORDINATE_PRECISION capability. Drivers may honor
5666 : poGeomFieldDefn->GetNameRef() and poGeomFieldDefn->IsNullable(), but there are
5667 : very few currently.
5668 :
5669 : Note that even if a geometry coordinate precision is set and a driver honors the
5670 : GDAL_DCAP_HONOR_GEOM_COORDINATE_PRECISION capability, geometries passed to
5671 : OGRLayer::CreateFeature() and OGRLayer::SetFeature() are assumed to be compatible
5672 : with the coordinate precision. That is they are assumed to be valid once their
5673 : coordinates are rounded to it. If it might not be the case, the user may set
5674 : the OGR_APPLY_GEOM_SET_PRECISION configuration option before calling CreateFeature()
5675 : or SetFeature() to force the OGRGeometry::SetPrecision() method to be called on
5676 : the passed geometries.
5677 :
5678 : The papszOptions argument
5679 : can be used to control driver specific creation options. These options are
5680 : normally documented in the format specific documentation.
5681 : This function will try to validate the creation option list passed to the
5682 : driver with the GDALValidateCreationOptions() method. This check can be
5683 : disabled by defining the configuration option GDAL_VALIDATE_CREATION_OPTIONS set
5684 : to NO.
5685 :
5686 : Drivers should extend the ICreateLayer() method and not
5687 : CreateLayer(). CreateLayer() adds validation of layer creation options, before
5688 : delegating the actual work to ICreateLayer().
5689 :
5690 : This method is the same as the C function GDALDatasetCreateLayerFromGeomFieldDefn().
5691 :
5692 : @param pszName the name for the new layer. This should ideally not
5693 : match any existing layer on the datasource.
5694 : @param poGeomFieldDefn the geometry field definition to use for the new layer,
5695 : or NULL if there is no geometry field.
5696 : @param papszOptions a StringList of name=value options. Options are driver
5697 : specific.
5698 :
5699 : @return NULL is returned on failure, or a new OGRLayer handle on success.
5700 : @since 3.9
5701 :
5702 : */
5703 :
5704 9892 : OGRLayer *GDALDataset::CreateLayer(const char *pszName,
5705 : const OGRGeomFieldDefn *poGeomFieldDefn,
5706 : CSLConstList papszOptions)
5707 :
5708 : {
5709 9892 : if (CPLTestBool(
5710 : CPLGetConfigOption("GDAL_VALIDATE_CREATION_OPTIONS", "YES")))
5711 : {
5712 9892 : ValidateLayerCreationOptions(papszOptions);
5713 : }
5714 :
5715 : OGRLayer *poLayer;
5716 9892 : if (poGeomFieldDefn)
5717 : {
5718 8949 : OGRGeomFieldDefn oGeomFieldDefn(poGeomFieldDefn);
5719 9043 : if (OGR_GT_IsNonLinear(poGeomFieldDefn->GetType()) &&
5720 94 : !TestCapability(ODsCCurveGeometries))
5721 : {
5722 23 : oGeomFieldDefn.SetType(
5723 : OGR_GT_GetLinear(poGeomFieldDefn->GetType()));
5724 : }
5725 :
5726 8949 : poLayer = ICreateLayer(pszName, &oGeomFieldDefn, papszOptions);
5727 : }
5728 : else
5729 : {
5730 943 : poLayer = ICreateLayer(pszName, nullptr, papszOptions);
5731 : }
5732 : #ifdef DEBUG
5733 9963 : if (poLayer != nullptr && OGR_GT_IsNonLinear(poLayer->GetGeomType()) &&
5734 71 : !poLayer->TestCapability(OLCCurveGeometries))
5735 : {
5736 0 : CPLError(CE_Warning, CPLE_AppDefined,
5737 : "Inconsistent driver: Layer geometry type is non-linear, but "
5738 : "TestCapability(OLCCurveGeometries) returns FALSE.");
5739 : }
5740 : #endif
5741 :
5742 9892 : return poLayer;
5743 : }
5744 :
5745 : //! @cond Doxygen_Suppress
5746 :
5747 : // Technical override to avoid ambiguous choice between the old and new
5748 : // new CreateLayer() signatures.
5749 12 : OGRLayer *GDALDataset::CreateLayer(const char *pszName)
5750 : {
5751 24 : OGRGeomFieldDefn oGeomFieldDefn("", wkbUnknown);
5752 24 : return CreateLayer(pszName, &oGeomFieldDefn, nullptr);
5753 : }
5754 :
5755 : // Technical override to avoid ambiguous choice between the old and new
5756 : // new CreateLayer() signatures.
5757 1 : OGRLayer *GDALDataset::CreateLayer(const char *pszName, std::nullptr_t)
5758 : {
5759 2 : OGRGeomFieldDefn oGeomFieldDefn("", wkbUnknown);
5760 2 : return CreateLayer(pszName, &oGeomFieldDefn, nullptr);
5761 : }
5762 :
5763 : //!@endcond
5764 :
5765 : /************************************************************************/
5766 : /* GDALDatasetCreateLayer() */
5767 : /************************************************************************/
5768 :
5769 : /**
5770 : \brief This function attempts to create a new layer on the dataset with the
5771 : indicated name, coordinate system, geometry type.
5772 :
5773 : The papszOptions argument can be used to control driver specific creation
5774 : options. These options are normally documented in the format specific
5775 : documentation.
5776 :
5777 : This method is the same as the C++ method GDALDataset::CreateLayer().
5778 :
5779 : Example:
5780 :
5781 : \code{.c}
5782 : #include "gdal.h"
5783 : #include "cpl_string.h"
5784 :
5785 : ...
5786 :
5787 : OGRLayerH hLayer;
5788 : char **papszOptions;
5789 :
5790 : if( !GDALDatasetTestCapability( hDS, ODsCCreateLayer ) )
5791 : {
5792 : ...
5793 : }
5794 :
5795 : papszOptions = CSLSetNameValue( papszOptions, "DIM", "2" );
5796 : hLayer = GDALDatasetCreateLayer( hDS, "NewLayer", NULL, wkbUnknown,
5797 : papszOptions );
5798 : CSLDestroy( papszOptions );
5799 :
5800 : if( hLayer == NULL )
5801 : {
5802 : ...
5803 : }
5804 : \endcode
5805 :
5806 :
5807 : @param hDS the dataset handle
5808 : @param pszName the name for the new layer. This should ideally not
5809 : match any existing layer on the datasource.
5810 : @param hSpatialRef the coordinate system to use for the new layer, or NULL if
5811 : no coordinate system is available.
5812 : @param eGType the geometry type for the layer. Use wkbUnknown if there
5813 : are no constraints on the types geometry to be written.
5814 : @param papszOptions a StringList of name=value options. Options are driver
5815 : specific.
5816 :
5817 : @return NULL is returned on failure, or a new OGRLayer handle on success.
5818 :
5819 : */
5820 :
5821 6539 : OGRLayerH GDALDatasetCreateLayer(GDALDatasetH hDS, const char *pszName,
5822 : OGRSpatialReferenceH hSpatialRef,
5823 : OGRwkbGeometryType eGType,
5824 : CSLConstList papszOptions)
5825 :
5826 : {
5827 6539 : VALIDATE_POINTER1(hDS, "GDALDatasetCreateLayer", nullptr);
5828 :
5829 6539 : if (pszName == nullptr)
5830 : {
5831 0 : CPLError(CE_Failure, CPLE_ObjectNull,
5832 : "Name was NULL in GDALDatasetCreateLayer");
5833 0 : return nullptr;
5834 : }
5835 :
5836 : OGRLayerH hLayer =
5837 13078 : OGRLayer::ToHandle(GDALDataset::FromHandle(hDS)->CreateLayer(
5838 6539 : pszName, OGRSpatialReference::FromHandle(hSpatialRef), eGType,
5839 : const_cast<char **>(papszOptions)));
5840 :
5841 : #ifdef OGRAPISPY_ENABLED
5842 6539 : if (bOGRAPISpyEnabled)
5843 8 : OGRAPISpy_DS_CreateLayer(hDS, pszName, hSpatialRef, eGType,
5844 : const_cast<char **>(papszOptions), hLayer);
5845 : #endif
5846 :
5847 6539 : return hLayer;
5848 : }
5849 :
5850 : /************************************************************************/
5851 : /* GDALDatasetCreateLayerFromGeomFieldDefn() */
5852 : /************************************************************************/
5853 :
5854 : /**
5855 : \brief This function attempts to create a new layer on the dataset with the
5856 : indicated name and geometry field.
5857 :
5858 : When poGeomFieldDefn is not null, most drivers should honor
5859 : poGeomFieldDefn->GetType() and poGeomFieldDefn->GetSpatialRef().
5860 : Drivers that honor poGeomFieldDefn->GetCoordinatePrecision() will declare the
5861 : GDAL_DCAP_HONOR_GEOM_COORDINATE_PRECISION capability. Drivers may honor
5862 : poGeomFieldDefn->GetNameRef() and poGeomFieldDefn->IsNullable(), but there are
5863 : very few currently.
5864 :
5865 : Note that even if a geometry coordinate precision is set and a driver honors the
5866 : GDAL_DCAP_HONOR_GEOM_COORDINATE_PRECISION capability, geometries passed to
5867 : OGRLayer::CreateFeature() and OGRLayer::SetFeature() are assumed to be compatible
5868 : with the coordinate precision. That is they are assumed to be valid once their
5869 : coordinates are rounded to it. If it might not be the case, the user may set
5870 : the OGR_APPLY_GEOM_SET_PRECISION configuration option before calling CreateFeature()
5871 : or SetFeature() to force the OGRGeometry::SetPrecision() method to be called on
5872 : the passed geometries.
5873 :
5874 : The papszOptions argument can be used to control driver specific creation
5875 : options. These options are normally documented in the format specific
5876 : documentation.
5877 :
5878 : This method is the same as the C++ method GDALDataset::CreateLayer().
5879 :
5880 : @param hDS the dataset handle
5881 : @param pszName the name for the new layer. This should ideally not
5882 : match any existing layer on the datasource.
5883 : @param hGeomFieldDefn the geometry field definition. May be NULL to indicate
5884 : a non-spatial file (or if adding geometry fields later with OGR_L_CreateGeomField()
5885 : for drivers supporting that interface).
5886 : @param papszOptions a StringList of name=value options. Options are driver
5887 : specific.
5888 :
5889 : @return NULL is returned on failure, or a new OGRLayer handle on success.
5890 :
5891 : @since GDAL 3.9
5892 :
5893 : */
5894 :
5895 : OGRLayerH
5896 14 : GDALDatasetCreateLayerFromGeomFieldDefn(GDALDatasetH hDS, const char *pszName,
5897 : OGRGeomFieldDefnH hGeomFieldDefn,
5898 : CSLConstList papszOptions)
5899 :
5900 : {
5901 14 : VALIDATE_POINTER1(hDS, "GDALDatasetCreateLayerFromGeomFieldDefn", nullptr);
5902 :
5903 14 : if (!pszName)
5904 : {
5905 0 : CPLError(CE_Failure, CPLE_ObjectNull,
5906 : "Name was NULL in GDALDatasetCreateLayerFromGeomFieldDefn");
5907 0 : return nullptr;
5908 : }
5909 :
5910 : OGRLayerH hLayer =
5911 28 : OGRLayer::ToHandle(GDALDataset::FromHandle(hDS)->CreateLayer(
5912 14 : pszName, OGRGeomFieldDefn::FromHandle(hGeomFieldDefn),
5913 : papszOptions));
5914 14 : return hLayer;
5915 : }
5916 :
5917 : /************************************************************************/
5918 : /* GDALDatasetCopyLayer() */
5919 : /************************************************************************/
5920 :
5921 : /**
5922 : \brief Duplicate an existing layer.
5923 :
5924 : This function creates a new layer, duplicate the field definitions of the
5925 : source layer and then duplicate each features of the source layer.
5926 : The papszOptions argument
5927 : can be used to control driver specific creation options. These options are
5928 : normally documented in the format specific documentation.
5929 : The source layer may come from another dataset.
5930 :
5931 : This method is the same as the C++ method GDALDataset::CopyLayer()
5932 :
5933 :
5934 : @param hDS the dataset handle.
5935 : @param hSrcLayer source layer.
5936 : @param pszNewName the name of the layer to create.
5937 : @param papszOptions a StringList of name=value options. Options are driver
5938 : specific.
5939 :
5940 : @return a handle to the layer, or NULL if an error occurs.
5941 : */
5942 48 : OGRLayerH GDALDatasetCopyLayer(GDALDatasetH hDS, OGRLayerH hSrcLayer,
5943 : const char *pszNewName,
5944 : CSLConstList papszOptions)
5945 :
5946 : {
5947 48 : VALIDATE_POINTER1(hDS, "OGR_DS_CopyGDALDatasetCopyLayerLayer", nullptr);
5948 48 : VALIDATE_POINTER1(hSrcLayer, "GDALDatasetCopyLayer", nullptr);
5949 48 : VALIDATE_POINTER1(pszNewName, "GDALDatasetCopyLayer", nullptr);
5950 :
5951 96 : return OGRLayer::ToHandle(GDALDataset::FromHandle(hDS)->CopyLayer(
5952 96 : OGRLayer::FromHandle(hSrcLayer), pszNewName, papszOptions));
5953 : }
5954 :
5955 : /************************************************************************/
5956 : /* GDALDatasetExecuteSQL() */
5957 : /************************************************************************/
5958 :
5959 : /**
5960 : \brief Execute an SQL statement against the data store.
5961 :
5962 : The result of an SQL query is either NULL for statements that are in error,
5963 : or that have no results set, or an OGRLayer pointer representing a results
5964 : set from the query. Note that this OGRLayer is in addition to the layers
5965 : in the data store and must be destroyed with
5966 : ReleaseResultSet() before the dataset is closed
5967 : (destroyed).
5968 :
5969 : This method is the same as the C++ method GDALDataset::ExecuteSQL()
5970 :
5971 : For more information on the SQL dialect supported internally by OGR
5972 : review the <a href="https://gdal.org/user/ogr_sql_dialect.html">OGR SQL</a>
5973 : document. Some drivers (i.e. Oracle and PostGIS) pass the SQL directly through
5974 : to the underlying RDBMS.
5975 :
5976 : Starting with OGR 1.10, the <a
5977 : href="https://gdal.org/user/sql_sqlite_dialect.html">SQLITE dialect</a> can
5978 : also be used.
5979 :
5980 :
5981 : @param hDS the dataset handle.
5982 : @param pszStatement the SQL statement to execute.
5983 : @param hSpatialFilter geometry which represents a spatial filter. Can be NULL.
5984 :
5985 : @param pszDialect allows control of the statement dialect. If set to NULL, the
5986 : OGR SQL engine will be used, except for RDBMS drivers that will use their
5987 : dedicated SQL engine, unless OGRSQL is explicitly passed as the
5988 : dialect. Starting with OGR 1.10, the SQLITE dialect can also be used.
5989 :
5990 : @return an OGRLayer containing the results of the query. Deallocate with
5991 : GDALDatasetReleaseResultSet().
5992 :
5993 : */
5994 :
5995 10623 : OGRLayerH GDALDatasetExecuteSQL(GDALDatasetH hDS, const char *pszStatement,
5996 : OGRGeometryH hSpatialFilter,
5997 : const char *pszDialect)
5998 :
5999 : {
6000 10623 : VALIDATE_POINTER1(hDS, "GDALDatasetExecuteSQL", nullptr);
6001 :
6002 : OGRLayerH hLayer =
6003 21246 : OGRLayer::ToHandle(GDALDataset::FromHandle(hDS)->ExecuteSQL(
6004 10623 : pszStatement, OGRGeometry::FromHandle(hSpatialFilter), pszDialect));
6005 :
6006 : #ifdef OGRAPISPY_ENABLED
6007 10623 : if (bOGRAPISpyEnabled)
6008 4 : OGRAPISpy_DS_ExecuteSQL(hDS, pszStatement, hSpatialFilter, pszDialect,
6009 : hLayer);
6010 : #endif
6011 :
6012 10623 : return hLayer;
6013 : }
6014 :
6015 : /************************************************************************/
6016 : /* GDALDatasetAbortSQL() */
6017 : /************************************************************************/
6018 :
6019 : /**
6020 : \brief Abort any SQL statement running in the data store.
6021 :
6022 : This function can be safely called from any thread (pending that the dataset
6023 : object is still alive). Driver implementations will make sure that it can be
6024 : called in a thread-safe way.
6025 :
6026 : This might not be implemented by all drivers. At time of writing, only SQLite,
6027 : GPKG and PG drivers implement it
6028 :
6029 : This method is the same as the C++ method GDALDataset::AbortSQL()
6030 :
6031 : @since GDAL 3.2.0
6032 :
6033 : @param hDS the dataset handle.
6034 :
6035 : @return OGRERR_NONE on success, or OGRERR_UNSUPPORTED_OPERATION if AbortSQL
6036 : is not supported for this datasource. .
6037 :
6038 : */
6039 :
6040 6 : OGRErr GDALDatasetAbortSQL(GDALDatasetH hDS)
6041 :
6042 : {
6043 6 : VALIDATE_POINTER1(hDS, "GDALDatasetAbortSQL", OGRERR_FAILURE);
6044 6 : return GDALDataset::FromHandle(hDS)->AbortSQL();
6045 : }
6046 :
6047 : /************************************************************************/
6048 : /* GDALDatasetGetStyleTable() */
6049 : /************************************************************************/
6050 :
6051 : /**
6052 : \brief Returns dataset style table.
6053 :
6054 : This function is the same as the C++ method GDALDataset::GetStyleTable()
6055 :
6056 :
6057 : @param hDS the dataset handle
6058 : @return handle to a style table which should not be modified or freed by the
6059 : caller.
6060 : */
6061 :
6062 6 : OGRStyleTableH GDALDatasetGetStyleTable(GDALDatasetH hDS)
6063 :
6064 : {
6065 6 : VALIDATE_POINTER1(hDS, "OGR_DS_GetStyleTable", nullptr);
6066 :
6067 : return reinterpret_cast<OGRStyleTableH>(
6068 6 : GDALDataset::FromHandle(hDS)->GetStyleTable());
6069 : }
6070 :
6071 : /************************************************************************/
6072 : /* GDALDatasetSetStyleTableDirectly() */
6073 : /************************************************************************/
6074 :
6075 : /**
6076 : \brief Set dataset style table.
6077 :
6078 : This function operate exactly as GDALDatasetSetStyleTable() except that it
6079 : assumes ownership of the passed table.
6080 :
6081 : This function is the same as the C++ method
6082 : GDALDataset::SetStyleTableDirectly()
6083 :
6084 :
6085 : @param hDS the dataset handle
6086 : @param hStyleTable style table handle to set
6087 :
6088 : */
6089 :
6090 0 : void GDALDatasetSetStyleTableDirectly(GDALDatasetH hDS,
6091 : OGRStyleTableH hStyleTable)
6092 :
6093 : {
6094 0 : VALIDATE_POINTER0(hDS, "OGR_DS_SetStyleTableDirectly");
6095 :
6096 0 : GDALDataset::FromHandle(hDS)->SetStyleTableDirectly(
6097 0 : reinterpret_cast<OGRStyleTable *>(hStyleTable));
6098 : }
6099 :
6100 : /************************************************************************/
6101 : /* GDALDatasetSetStyleTable() */
6102 : /************************************************************************/
6103 :
6104 : /**
6105 : \brief Set dataset style table.
6106 :
6107 : This function operate exactly as GDALDatasetSetStyleTableDirectly() except that
6108 : it assumes ownership of the passed table.
6109 :
6110 : This function is the same as the C++ method GDALDataset::SetStyleTable()
6111 :
6112 :
6113 : @param hDS the dataset handle
6114 : @param hStyleTable style table handle to set
6115 :
6116 : */
6117 :
6118 5 : void GDALDatasetSetStyleTable(GDALDatasetH hDS, OGRStyleTableH hStyleTable)
6119 :
6120 : {
6121 5 : VALIDATE_POINTER0(hDS, "OGR_DS_SetStyleTable");
6122 5 : VALIDATE_POINTER0(hStyleTable, "OGR_DS_SetStyleTable");
6123 :
6124 5 : GDALDataset::FromHandle(hDS)->SetStyleTable(
6125 5 : reinterpret_cast<OGRStyleTable *>(hStyleTable));
6126 : }
6127 :
6128 : /************************************************************************/
6129 : /* ValidateLayerCreationOptions() */
6130 : /************************************************************************/
6131 :
6132 : //! @cond Doxygen_Suppress
6133 9892 : int GDALDataset::ValidateLayerCreationOptions(const char *const *papszLCO)
6134 : {
6135 : const char *pszOptionList =
6136 9892 : GetMetadataItem(GDAL_DS_LAYER_CREATIONOPTIONLIST);
6137 9892 : if (pszOptionList == nullptr && poDriver != nullptr)
6138 : {
6139 : pszOptionList =
6140 9851 : poDriver->GetMetadataItem(GDAL_DS_LAYER_CREATIONOPTIONLIST);
6141 : }
6142 19784 : CPLString osDataset;
6143 9892 : osDataset.Printf("dataset %s", GetDescription());
6144 9892 : return GDALValidateOptions(pszOptionList, papszLCO, "layer creation option",
6145 19784 : osDataset);
6146 : }
6147 :
6148 : //! @endcond
6149 :
6150 : /************************************************************************/
6151 : /* Release() */
6152 : /************************************************************************/
6153 :
6154 : /**
6155 : \brief Drop a reference to this dataset, and if the reference count drops to one
6156 : close (destroy) the dataset.
6157 :
6158 : This method is the same as the C function OGRReleaseDataSource().
6159 :
6160 : @deprecated. Use GDALClose() instead
6161 :
6162 : @return OGRERR_NONE on success or an error code.
6163 : */
6164 :
6165 4521 : OGRErr GDALDataset::Release()
6166 :
6167 : {
6168 4521 : ReleaseRef();
6169 4521 : return OGRERR_NONE;
6170 : }
6171 :
6172 : /************************************************************************/
6173 : /* GetRefCount() */
6174 : /************************************************************************/
6175 :
6176 : /**
6177 : \brief Fetch reference count.
6178 :
6179 : This method is the same as the C function OGR_DS_GetRefCount().
6180 :
6181 : @return the current reference count for the datasource object itself.
6182 : */
6183 :
6184 5364 : int GDALDataset::GetRefCount() const
6185 : {
6186 5364 : return nRefCount;
6187 : }
6188 :
6189 : /************************************************************************/
6190 : /* GetSummaryRefCount() */
6191 : /************************************************************************/
6192 :
6193 : /**
6194 : \brief Fetch reference count of datasource and all owned layers.
6195 :
6196 : This method is the same as the C function OGR_DS_GetSummaryRefCount().
6197 :
6198 : @deprecated
6199 :
6200 : @return the current summary reference count for the datasource and its layers.
6201 : */
6202 :
6203 0 : int GDALDataset::GetSummaryRefCount() const
6204 :
6205 : {
6206 0 : CPLMutexHolderD(m_poPrivate ? &(m_poPrivate->hMutex) : nullptr);
6207 0 : int nSummaryCount = nRefCount;
6208 0 : GDALDataset *poUseThis = const_cast<GDALDataset *>(this);
6209 :
6210 0 : for (int iLayer = 0; iLayer < poUseThis->GetLayerCount(); ++iLayer)
6211 0 : nSummaryCount += poUseThis->GetLayer(iLayer)->GetRefCount();
6212 :
6213 0 : return nSummaryCount;
6214 : }
6215 :
6216 : /************************************************************************/
6217 : /* ICreateLayer() */
6218 : /************************************************************************/
6219 :
6220 : /**
6221 : \brief This method attempts to create a new layer on the dataset with the
6222 : indicated name, coordinate system, geometry type.
6223 :
6224 : This method is reserved to implementation by drivers.
6225 :
6226 : The papszOptions argument can be used to control driver specific creation
6227 : options. These options are normally documented in the format specific
6228 : documentation.
6229 :
6230 : @param pszName the name for the new layer. This should ideally not
6231 : match any existing layer on the datasource.
6232 : @param poGeomFieldDefn the geometry field definition to use for the new layer,
6233 : or NULL if there is no geometry field.
6234 : @param papszOptions a StringList of name=value options. Options are driver
6235 : specific.
6236 :
6237 : @return NULL is returned on failure, or a new OGRLayer handle on success.
6238 :
6239 : */
6240 :
6241 : OGRLayer *
6242 16 : GDALDataset::ICreateLayer(CPL_UNUSED const char *pszName,
6243 : CPL_UNUSED const OGRGeomFieldDefn *poGeomFieldDefn,
6244 : CPL_UNUSED CSLConstList papszOptions)
6245 :
6246 : {
6247 16 : CPLError(CE_Failure, CPLE_NotSupported,
6248 : "CreateLayer() not supported by this dataset.");
6249 :
6250 16 : return nullptr;
6251 : }
6252 :
6253 : /************************************************************************/
6254 : /* CopyLayer() */
6255 : /************************************************************************/
6256 :
6257 : /**
6258 : \brief Duplicate an existing layer.
6259 :
6260 : This method creates a new layer, duplicate the field definitions of the
6261 : source layer and then duplicate each features of the source layer.
6262 : The papszOptions argument
6263 : can be used to control driver specific creation options. These options are
6264 : normally documented in the format specific documentation.
6265 : The source layer may come from another dataset.
6266 :
6267 : This method is the same as the C function GDALDatasetCopyLayer() and the
6268 : deprecated OGR_DS_CopyLayer().
6269 :
6270 : @param poSrcLayer source layer.
6271 : @param pszNewName the name of the layer to create.
6272 : @param papszOptions a StringList of name=value options. Options are driver
6273 : specific. There is a common option to set output layer
6274 : spatial reference: DST_SRSWKT. The option should be in
6275 : WKT format. Starting with GDAL 3.7, the common option
6276 : COPY_MD can be set to NO to prevent the default copying
6277 : of the metadata from the source layer to the target layer.
6278 :
6279 : @return a handle to the layer, or NULL if an error occurs.
6280 : */
6281 :
6282 164 : OGRLayer *GDALDataset::CopyLayer(OGRLayer *poSrcLayer, const char *pszNewName,
6283 : CSLConstList papszOptions)
6284 :
6285 : {
6286 : /* -------------------------------------------------------------------- */
6287 : /* Create the layer. */
6288 : /* -------------------------------------------------------------------- */
6289 164 : if (!TestCapability(ODsCCreateLayer))
6290 : {
6291 0 : CPLError(CE_Failure, CPLE_NotSupported,
6292 : "This datasource does not support creation of layers.");
6293 0 : return nullptr;
6294 : }
6295 :
6296 164 : const char *pszSRSWKT = CSLFetchNameValue(papszOptions, "DST_SRSWKT");
6297 328 : OGRSpatialReference oDstSpaRef(pszSRSWKT);
6298 164 : oDstSpaRef.SetAxisMappingStrategy(OAMS_TRADITIONAL_GIS_ORDER);
6299 164 : OGRFeatureDefn *poSrcDefn = poSrcLayer->GetLayerDefn();
6300 164 : OGRLayer *poDstLayer = nullptr;
6301 :
6302 328 : CPLStringList aosCleanedUpOptions(CSLDuplicate(papszOptions));
6303 164 : aosCleanedUpOptions.SetNameValue("DST_SRSWKT", nullptr);
6304 164 : aosCleanedUpOptions.SetNameValue("COPY_MD", nullptr);
6305 :
6306 164 : CPLErrorReset();
6307 164 : const int nSrcGeomFieldCount = poSrcDefn->GetGeomFieldCount();
6308 164 : if (nSrcGeomFieldCount == 1)
6309 : {
6310 112 : OGRGeomFieldDefn oGeomFieldDefn(poSrcDefn->GetGeomFieldDefn(0));
6311 112 : if (pszSRSWKT)
6312 5 : oGeomFieldDefn.SetSpatialRef(&oDstSpaRef);
6313 112 : poDstLayer = ICreateLayer(pszNewName, &oGeomFieldDefn,
6314 112 : aosCleanedUpOptions.List());
6315 : }
6316 : else
6317 : {
6318 : poDstLayer =
6319 52 : ICreateLayer(pszNewName, nullptr, aosCleanedUpOptions.List());
6320 : }
6321 :
6322 164 : if (poDstLayer == nullptr)
6323 0 : return nullptr;
6324 :
6325 164 : if (CPLTestBool(CSLFetchNameValueDef(papszOptions, "COPY_MD", "YES")))
6326 : {
6327 163 : CSLConstList papszMD = poSrcLayer->GetMetadata();
6328 163 : if (papszMD)
6329 31 : poDstLayer->SetMetadata(papszMD);
6330 : }
6331 :
6332 : /* -------------------------------------------------------------------- */
6333 : /* Add fields. Default to copy all fields, and make sure to */
6334 : /* establish a mapping between indices, rather than names, in */
6335 : /* case the target datasource has altered it (e.g. Shapefile */
6336 : /* limited to 10 char field names). */
6337 : /* -------------------------------------------------------------------- */
6338 164 : const int nSrcFieldCount = poSrcDefn->GetFieldCount();
6339 :
6340 : // Initialize the index-to-index map to -1's.
6341 328 : std::vector<int> anMap(nSrcFieldCount, -1);
6342 :
6343 : // Caution: At the time of writing, the MapInfo driver
6344 : // returns NULL until a field has been added.
6345 164 : OGRFeatureDefn *poDstFDefn = poDstLayer->GetLayerDefn();
6346 164 : int nDstFieldCount = poDstFDefn ? poDstFDefn->GetFieldCount() : 0;
6347 391 : for (int iField = 0; iField < nSrcFieldCount; ++iField)
6348 : {
6349 227 : OGRFieldDefn *poSrcFieldDefn = poSrcDefn->GetFieldDefn(iField);
6350 454 : OGRFieldDefn oFieldDefn(poSrcFieldDefn);
6351 :
6352 : // The field may have been already created at layer creation.
6353 227 : int iDstField = -1;
6354 227 : if (poDstFDefn)
6355 227 : iDstField = poDstFDefn->GetFieldIndex(oFieldDefn.GetNameRef());
6356 227 : if (iDstField >= 0)
6357 : {
6358 0 : anMap[iField] = iDstField;
6359 : }
6360 227 : else if (poDstLayer->CreateField(&oFieldDefn) == OGRERR_NONE)
6361 : {
6362 : // Now that we've created a field, GetLayerDefn() won't return NULL.
6363 227 : if (poDstFDefn == nullptr)
6364 0 : poDstFDefn = poDstLayer->GetLayerDefn();
6365 :
6366 : // Sanity check: if it fails, the driver is buggy.
6367 454 : if (poDstFDefn != nullptr &&
6368 227 : poDstFDefn->GetFieldCount() != nDstFieldCount + 1)
6369 : {
6370 0 : CPLError(CE_Warning, CPLE_AppDefined,
6371 : "The output driver has claimed to have added the %s "
6372 : "field, but it did not!",
6373 : oFieldDefn.GetNameRef());
6374 : }
6375 : else
6376 : {
6377 227 : anMap[iField] = nDstFieldCount;
6378 227 : ++nDstFieldCount;
6379 : }
6380 : }
6381 : }
6382 :
6383 : /* -------------------------------------------------------------------- */
6384 164 : std::unique_ptr<OGRCoordinateTransformation> poCT;
6385 164 : const OGRSpatialReference *sourceSRS = poSrcLayer->GetSpatialRef();
6386 164 : if (sourceSRS != nullptr && pszSRSWKT != nullptr && !oDstSpaRef.IsEmpty() &&
6387 0 : sourceSRS->IsSame(&oDstSpaRef) == FALSE)
6388 : {
6389 0 : poCT.reset(OGRCreateCoordinateTransformation(sourceSRS, &oDstSpaRef));
6390 0 : if (nullptr == poCT)
6391 : {
6392 0 : CPLError(CE_Failure, CPLE_NotSupported,
6393 : "This input/output spatial reference is not supported.");
6394 0 : return nullptr;
6395 : }
6396 : }
6397 : /* -------------------------------------------------------------------- */
6398 : /* Create geometry fields. */
6399 : /* -------------------------------------------------------------------- */
6400 165 : if (nSrcGeomFieldCount > 1 &&
6401 1 : TestCapability(ODsCCreateGeomFieldAfterCreateLayer))
6402 : {
6403 :
6404 3 : for (int iField = 0; iField < nSrcGeomFieldCount; ++iField)
6405 : {
6406 2 : if (nullptr == pszSRSWKT)
6407 : {
6408 2 : poDstLayer->CreateGeomField(
6409 2 : poSrcDefn->GetGeomFieldDefn(iField));
6410 : }
6411 : else
6412 : {
6413 : OGRGeomFieldDefn *pDstGeomFieldDefn =
6414 0 : poSrcDefn->GetGeomFieldDefn(iField);
6415 0 : pDstGeomFieldDefn->SetSpatialRef(&oDstSpaRef);
6416 0 : poDstLayer->CreateGeomField(pDstGeomFieldDefn);
6417 : }
6418 : }
6419 : }
6420 :
6421 : /* -------------------------------------------------------------------- */
6422 : /* Check if the destination layer supports transactions and set a */
6423 : /* default number of features in a single transaction. */
6424 : /* -------------------------------------------------------------------- */
6425 : const int nGroupTransactions =
6426 164 : poDstLayer->TestCapability(OLCTransactions) ? 128 : 0;
6427 :
6428 : /* -------------------------------------------------------------------- */
6429 : /* Transfer features. */
6430 : /* -------------------------------------------------------------------- */
6431 164 : poSrcLayer->ResetReading();
6432 :
6433 164 : if (nGroupTransactions <= 0)
6434 : {
6435 : while (true)
6436 : {
6437 : auto poFeature =
6438 682 : std::unique_ptr<OGRFeature>(poSrcLayer->GetNextFeature());
6439 :
6440 682 : if (poFeature == nullptr)
6441 155 : break;
6442 :
6443 527 : CPLErrorReset();
6444 : auto poDstFeature =
6445 527 : std::make_unique<OGRFeature>(poDstLayer->GetLayerDefn());
6446 :
6447 527 : if (poDstFeature->SetFrom(poFeature.get(), anMap.data(), TRUE) !=
6448 : OGRERR_NONE)
6449 : {
6450 0 : CPLError(CE_Failure, CPLE_AppDefined,
6451 : "Unable to translate feature " CPL_FRMT_GIB
6452 : " from layer %s.",
6453 0 : poFeature->GetFID(), poSrcDefn->GetName());
6454 0 : return poDstLayer;
6455 : }
6456 :
6457 527 : if (nullptr != poCT)
6458 : {
6459 0 : for (int iField = 0; iField < nSrcGeomFieldCount; ++iField)
6460 : {
6461 0 : OGRGeometry *pGeom = poDstFeature->GetGeomFieldRef(iField);
6462 0 : if (nullptr == pGeom)
6463 0 : continue;
6464 :
6465 0 : const OGRErr eErr = pGeom->transform(poCT.get());
6466 0 : if (eErr == OGRERR_NONE)
6467 0 : continue;
6468 :
6469 0 : CPLError(CE_Failure, CPLE_AppDefined,
6470 : "Unable to transform geometry " CPL_FRMT_GIB
6471 : " from layer %s.",
6472 0 : poFeature->GetFID(), poSrcDefn->GetName());
6473 0 : return poDstLayer;
6474 : }
6475 : }
6476 :
6477 527 : poDstFeature->SetFID(poFeature->GetFID());
6478 :
6479 527 : CPLErrorReset();
6480 527 : if (poDstLayer->CreateFeature(poDstFeature.get()) != OGRERR_NONE)
6481 : {
6482 0 : return poDstLayer;
6483 : }
6484 527 : }
6485 : }
6486 : else
6487 : {
6488 9 : std::vector<std::unique_ptr<OGRFeature>> apoDstFeatures;
6489 : try
6490 : {
6491 9 : apoDstFeatures.resize(nGroupTransactions);
6492 : }
6493 0 : catch (const std::exception &e)
6494 : {
6495 0 : CPLError(CE_Failure, CPLE_OutOfMemory, "%s", e.what());
6496 0 : return poDstLayer;
6497 : }
6498 9 : bool bStopTransfer = false;
6499 18 : while (!bStopTransfer)
6500 : {
6501 : /* --------------------------------------------------------------------
6502 : */
6503 : /* Fill the array with features. */
6504 : /* --------------------------------------------------------------------
6505 : */
6506 : // Number of features in the temporary array.
6507 9 : int nFeatCount = 0; // Used after for.
6508 85 : for (nFeatCount = 0; nFeatCount < nGroupTransactions; ++nFeatCount)
6509 : {
6510 : auto poFeature =
6511 85 : std::unique_ptr<OGRFeature>(poSrcLayer->GetNextFeature());
6512 :
6513 85 : if (poFeature == nullptr)
6514 : {
6515 9 : bStopTransfer = true;
6516 9 : break;
6517 : }
6518 :
6519 76 : CPLErrorReset();
6520 76 : apoDstFeatures[nFeatCount] =
6521 152 : std::make_unique<OGRFeature>(poDstLayer->GetLayerDefn());
6522 :
6523 152 : if (apoDstFeatures[nFeatCount]->SetFrom(
6524 152 : poFeature.get(), anMap.data(), TRUE) != OGRERR_NONE)
6525 : {
6526 0 : CPLError(CE_Failure, CPLE_AppDefined,
6527 : "Unable to translate feature " CPL_FRMT_GIB
6528 : " from layer %s.",
6529 0 : poFeature->GetFID(), poSrcDefn->GetName());
6530 0 : bStopTransfer = true;
6531 0 : poFeature.reset();
6532 0 : break;
6533 : }
6534 :
6535 76 : if (nullptr != poCT)
6536 : {
6537 0 : for (int iField = 0; iField < nSrcGeomFieldCount; ++iField)
6538 : {
6539 : OGRGeometry *pGeom =
6540 0 : apoDstFeatures[nFeatCount]->GetGeomFieldRef(iField);
6541 0 : if (nullptr == pGeom)
6542 0 : continue;
6543 :
6544 0 : const OGRErr eErr = pGeom->transform(poCT.get());
6545 0 : if (eErr == OGRERR_NONE)
6546 0 : continue;
6547 :
6548 0 : CPLError(CE_Failure, CPLE_AppDefined,
6549 : "Unable to transform geometry " CPL_FRMT_GIB
6550 : " from layer %s.",
6551 0 : poFeature->GetFID(), poSrcDefn->GetName());
6552 0 : bStopTransfer = true;
6553 0 : poFeature.reset();
6554 0 : break;
6555 : }
6556 : }
6557 :
6558 76 : if (poFeature)
6559 : {
6560 76 : apoDstFeatures[nFeatCount]->SetFID(poFeature->GetFID());
6561 : }
6562 : }
6563 :
6564 9 : CPLErrorReset();
6565 9 : bool bStopTransaction = false;
6566 18 : while (!bStopTransaction)
6567 : {
6568 9 : bStopTransaction = true;
6569 9 : if (poDstLayer->StartTransaction() != OGRERR_NONE)
6570 0 : break;
6571 85 : for (int i = 0; i < nFeatCount; ++i)
6572 : {
6573 76 : if (poDstLayer->CreateFeature(apoDstFeatures[i].get()) !=
6574 : OGRERR_NONE)
6575 : {
6576 0 : bStopTransfer = true;
6577 0 : bStopTransaction = false;
6578 0 : break;
6579 : }
6580 76 : apoDstFeatures[i].reset();
6581 : }
6582 9 : if (bStopTransaction)
6583 : {
6584 9 : if (poDstLayer->CommitTransaction() != OGRERR_NONE)
6585 0 : break;
6586 : }
6587 : else
6588 : {
6589 0 : poDstLayer->RollbackTransaction();
6590 : }
6591 : }
6592 : }
6593 : }
6594 :
6595 164 : return poDstLayer;
6596 : }
6597 :
6598 : /************************************************************************/
6599 : /* DeleteLayer() */
6600 : /************************************************************************/
6601 :
6602 : /**
6603 : \fn GDALDataset::DeleteLayer(int)
6604 : \brief Delete the indicated layer from the datasource.
6605 :
6606 : If this method is supported
6607 : the ODsCDeleteLayer capability will test TRUE on the GDALDataset.
6608 :
6609 : This method is the same as the C function GDALDatasetDeleteLayer() and the
6610 : deprecated OGR_DS_DeleteLayer().
6611 :
6612 : @param iLayer the index of the layer to delete.
6613 :
6614 : @return OGRERR_NONE on success, or OGRERR_UNSUPPORTED_OPERATION if deleting
6615 : layers is not supported for this datasource.
6616 :
6617 : */
6618 :
6619 389 : OGRErr GDALDataset::DeleteLayer(CPL_UNUSED int iLayer)
6620 :
6621 : {
6622 389 : CPLError(CE_Failure, CPLE_NotSupported,
6623 : "DeleteLayer() not supported by this dataset.");
6624 :
6625 389 : return OGRERR_UNSUPPORTED_OPERATION;
6626 : }
6627 :
6628 : /************************************************************************/
6629 : /* GetLayerByName() */
6630 : /************************************************************************/
6631 :
6632 : /**
6633 : \brief Fetch a layer by name.
6634 :
6635 : The returned layer remains owned by the
6636 : GDALDataset and should not be deleted by the application.
6637 :
6638 : This method is the same as the C function GDALDatasetGetLayerByName() and the
6639 : deprecated OGR_DS_GetLayerByName().
6640 :
6641 : @param pszName the layer name of the layer to fetch.
6642 :
6643 : @return the layer, or NULL if Layer is not found or an error occurs.
6644 : */
6645 :
6646 30496 : OGRLayer *GDALDataset::GetLayerByName(const char *pszName)
6647 :
6648 : {
6649 60992 : CPLMutexHolderD(m_poPrivate ? &(m_poPrivate->hMutex) : nullptr);
6650 :
6651 30496 : if (!pszName)
6652 0 : return nullptr;
6653 :
6654 : // First a case sensitive check.
6655 933508 : for (auto *poLayer : GetLayers())
6656 : {
6657 915169 : if (strcmp(pszName, poLayer->GetName()) == 0)
6658 12157 : return poLayer;
6659 : }
6660 :
6661 : // Then case insensitive.
6662 894139 : for (auto *poLayer : GetLayers())
6663 : {
6664 876024 : if (EQUAL(pszName, poLayer->GetName()))
6665 224 : return poLayer;
6666 : }
6667 :
6668 18115 : return nullptr;
6669 : }
6670 :
6671 : //! @cond Doxygen_Suppress
6672 : /************************************************************************/
6673 : /* ProcessSQLCreateIndex() */
6674 : /* */
6675 : /* The correct syntax for creating an index in our dialect of */
6676 : /* SQL is: */
6677 : /* */
6678 : /* CREATE INDEX ON <layername> USING <columnname> */
6679 : /************************************************************************/
6680 :
6681 28 : OGRErr GDALDataset::ProcessSQLCreateIndex(const char *pszSQLCommand)
6682 :
6683 : {
6684 28 : char **papszTokens = CSLTokenizeString(pszSQLCommand);
6685 :
6686 : /* -------------------------------------------------------------------- */
6687 : /* Do some general syntax checking. */
6688 : /* -------------------------------------------------------------------- */
6689 56 : if (CSLCount(papszTokens) != 6 || !EQUAL(papszTokens[0], "CREATE") ||
6690 84 : !EQUAL(papszTokens[1], "INDEX") || !EQUAL(papszTokens[2], "ON") ||
6691 28 : !EQUAL(papszTokens[4], "USING"))
6692 : {
6693 0 : CSLDestroy(papszTokens);
6694 0 : CPLError(CE_Failure, CPLE_AppDefined,
6695 : "Syntax error in CREATE INDEX command.\n"
6696 : "Was '%s'\n"
6697 : "Should be of form 'CREATE INDEX ON <table> USING <field>'",
6698 : pszSQLCommand);
6699 0 : return OGRERR_FAILURE;
6700 : }
6701 :
6702 : /* -------------------------------------------------------------------- */
6703 : /* Find the named layer. */
6704 : /* -------------------------------------------------------------------- */
6705 28 : OGRLayer *poLayer = GetLayerByName(papszTokens[3]);
6706 28 : if (poLayer == nullptr)
6707 : {
6708 0 : CPLError(CE_Failure, CPLE_AppDefined,
6709 : "CREATE INDEX ON failed, no such layer as `%s'.",
6710 0 : papszTokens[3]);
6711 0 : CSLDestroy(papszTokens);
6712 0 : return OGRERR_FAILURE;
6713 : }
6714 :
6715 : /* -------------------------------------------------------------------- */
6716 : /* Does this layer even support attribute indexes? */
6717 : /* -------------------------------------------------------------------- */
6718 28 : if (poLayer->GetIndex() == nullptr)
6719 : {
6720 0 : CPLError(CE_Failure, CPLE_AppDefined,
6721 : "CREATE INDEX ON not supported by this driver.");
6722 0 : CSLDestroy(papszTokens);
6723 0 : return OGRERR_FAILURE;
6724 : }
6725 :
6726 : /* -------------------------------------------------------------------- */
6727 : /* Find the named field. */
6728 : /* -------------------------------------------------------------------- */
6729 28 : int i = poLayer->GetLayerDefn()->GetFieldIndex(papszTokens[5]);
6730 :
6731 28 : CSLDestroy(papszTokens);
6732 :
6733 28 : if (i >= poLayer->GetLayerDefn()->GetFieldCount())
6734 : {
6735 0 : CPLError(CE_Failure, CPLE_AppDefined, "`%s' failed, field not found.",
6736 : pszSQLCommand);
6737 0 : return OGRERR_FAILURE;
6738 : }
6739 :
6740 : /* -------------------------------------------------------------------- */
6741 : /* Attempt to create the index. */
6742 : /* -------------------------------------------------------------------- */
6743 28 : OGRErr eErr = poLayer->GetIndex()->CreateIndex(i);
6744 28 : if (eErr == OGRERR_NONE)
6745 : {
6746 28 : eErr = poLayer->GetIndex()->IndexAllFeatures(i);
6747 : }
6748 : else
6749 : {
6750 0 : if (strlen(CPLGetLastErrorMsg()) == 0)
6751 0 : CPLError(CE_Failure, CPLE_AppDefined, "Cannot '%s'", pszSQLCommand);
6752 : }
6753 :
6754 28 : return eErr;
6755 : }
6756 :
6757 : /************************************************************************/
6758 : /* ProcessSQLDropIndex() */
6759 : /* */
6760 : /* The correct syntax for dropping one or more indexes in */
6761 : /* the OGR SQL dialect is: */
6762 : /* */
6763 : /* DROP INDEX ON <layername> [USING <columnname>] */
6764 : /************************************************************************/
6765 :
6766 10 : OGRErr GDALDataset::ProcessSQLDropIndex(const char *pszSQLCommand)
6767 :
6768 : {
6769 10 : char **papszTokens = CSLTokenizeString(pszSQLCommand);
6770 :
6771 : /* -------------------------------------------------------------------- */
6772 : /* Do some general syntax checking. */
6773 : /* -------------------------------------------------------------------- */
6774 20 : if ((CSLCount(papszTokens) != 4 && CSLCount(papszTokens) != 6) ||
6775 10 : !EQUAL(papszTokens[0], "DROP") || !EQUAL(papszTokens[1], "INDEX") ||
6776 30 : !EQUAL(papszTokens[2], "ON") ||
6777 10 : (CSLCount(papszTokens) == 6 && !EQUAL(papszTokens[4], "USING")))
6778 : {
6779 0 : CSLDestroy(papszTokens);
6780 0 : CPLError(CE_Failure, CPLE_AppDefined,
6781 : "Syntax error in DROP INDEX command.\n"
6782 : "Was '%s'\n"
6783 : "Should be of form 'DROP INDEX ON <table> [USING <field>]'",
6784 : pszSQLCommand);
6785 0 : return OGRERR_FAILURE;
6786 : }
6787 :
6788 : /* -------------------------------------------------------------------- */
6789 : /* Find the named layer. */
6790 : /* -------------------------------------------------------------------- */
6791 10 : OGRLayer *poLayer = GetLayerByName(papszTokens[3]);
6792 10 : if (poLayer == nullptr)
6793 : {
6794 0 : CPLError(CE_Failure, CPLE_AppDefined,
6795 : "DROP INDEX ON failed, no such layer as `%s'.",
6796 0 : papszTokens[3]);
6797 0 : CSLDestroy(papszTokens);
6798 0 : return OGRERR_FAILURE;
6799 : }
6800 :
6801 : /* -------------------------------------------------------------------- */
6802 : /* Does this layer even support attribute indexes? */
6803 : /* -------------------------------------------------------------------- */
6804 10 : if (poLayer->GetIndex() == nullptr)
6805 : {
6806 0 : CPLError(CE_Failure, CPLE_AppDefined,
6807 : "Indexes not supported by this driver.");
6808 0 : CSLDestroy(papszTokens);
6809 0 : return OGRERR_FAILURE;
6810 : }
6811 :
6812 : /* -------------------------------------------------------------------- */
6813 : /* If we were not given a field name, drop all indexes. */
6814 : /* -------------------------------------------------------------------- */
6815 10 : if (CSLCount(papszTokens) == 4)
6816 : {
6817 0 : for (int i = 0; i < poLayer->GetLayerDefn()->GetFieldCount(); ++i)
6818 : {
6819 : OGRAttrIndex *poAttrIndex;
6820 :
6821 0 : poAttrIndex = poLayer->GetIndex()->GetFieldIndex(i);
6822 0 : if (poAttrIndex != nullptr)
6823 : {
6824 0 : const OGRErr eErr = poLayer->GetIndex()->DropIndex(i);
6825 0 : if (eErr != OGRERR_NONE)
6826 : {
6827 0 : CSLDestroy(papszTokens);
6828 0 : return eErr;
6829 : }
6830 : }
6831 : }
6832 :
6833 0 : CSLDestroy(papszTokens);
6834 0 : return OGRERR_NONE;
6835 : }
6836 :
6837 : /* -------------------------------------------------------------------- */
6838 : /* Find the named field. */
6839 : /* -------------------------------------------------------------------- */
6840 10 : int i = poLayer->GetLayerDefn()->GetFieldIndex(papszTokens[5]);
6841 10 : CSLDestroy(papszTokens);
6842 :
6843 10 : if (i >= poLayer->GetLayerDefn()->GetFieldCount())
6844 : {
6845 0 : CPLError(CE_Failure, CPLE_AppDefined, "`%s' failed, field not found.",
6846 : pszSQLCommand);
6847 0 : return OGRERR_FAILURE;
6848 : }
6849 :
6850 : /* -------------------------------------------------------------------- */
6851 : /* Attempt to drop the index. */
6852 : /* -------------------------------------------------------------------- */
6853 10 : const OGRErr eErr = poLayer->GetIndex()->DropIndex(i);
6854 :
6855 10 : return eErr;
6856 : }
6857 :
6858 : /************************************************************************/
6859 : /* ProcessSQLDropTable() */
6860 : /* */
6861 : /* The correct syntax for dropping a table (layer) in the OGR SQL */
6862 : /* dialect is: */
6863 : /* */
6864 : /* DROP TABLE <layername> */
6865 : /************************************************************************/
6866 :
6867 500 : OGRErr GDALDataset::ProcessSQLDropTable(const char *pszSQLCommand)
6868 :
6869 : {
6870 500 : char **papszTokens = CSLTokenizeString(pszSQLCommand);
6871 :
6872 : /* -------------------------------------------------------------------- */
6873 : /* Do some general syntax checking. */
6874 : /* -------------------------------------------------------------------- */
6875 1000 : if (CSLCount(papszTokens) != 3 || !EQUAL(papszTokens[0], "DROP") ||
6876 500 : !EQUAL(papszTokens[1], "TABLE"))
6877 : {
6878 0 : CSLDestroy(papszTokens);
6879 0 : CPLError(CE_Failure, CPLE_AppDefined,
6880 : "Syntax error in DROP TABLE command.\n"
6881 : "Was '%s'\n"
6882 : "Should be of form 'DROP TABLE <table>'",
6883 : pszSQLCommand);
6884 0 : return OGRERR_FAILURE;
6885 : }
6886 :
6887 : /* -------------------------------------------------------------------- */
6888 : /* Find the named layer. */
6889 : /* -------------------------------------------------------------------- */
6890 500 : OGRLayer *poLayer = nullptr;
6891 :
6892 500 : int i = 0; // Used after for.
6893 40199 : for (; i < GetLayerCount(); ++i)
6894 : {
6895 40199 : poLayer = GetLayer(i);
6896 :
6897 40199 : if (poLayer != nullptr && EQUAL(poLayer->GetName(), papszTokens[2]))
6898 500 : break;
6899 39699 : poLayer = nullptr;
6900 : }
6901 :
6902 500 : if (poLayer == nullptr)
6903 : {
6904 0 : CPLError(CE_Failure, CPLE_AppDefined,
6905 0 : "DROP TABLE failed, no such layer as `%s'.", papszTokens[2]);
6906 0 : CSLDestroy(papszTokens);
6907 0 : return OGRERR_FAILURE;
6908 : }
6909 :
6910 500 : CSLDestroy(papszTokens);
6911 :
6912 : /* -------------------------------------------------------------------- */
6913 : /* Delete it. */
6914 : /* -------------------------------------------------------------------- */
6915 :
6916 500 : return DeleteLayer(i);
6917 : }
6918 :
6919 : //! @endcond
6920 :
6921 : /************************************************************************/
6922 : /* GDALDatasetParseSQLType() */
6923 : /************************************************************************/
6924 :
6925 : /* All arguments will be altered */
6926 6 : static OGRFieldType GDALDatasetParseSQLType(char *pszType, int &nWidth,
6927 : int &nPrecision)
6928 : {
6929 6 : char *pszParenthesis = strchr(pszType, '(');
6930 6 : if (pszParenthesis)
6931 : {
6932 4 : nWidth = atoi(pszParenthesis + 1);
6933 4 : *pszParenthesis = '\0';
6934 4 : char *pszComma = strchr(pszParenthesis + 1, ',');
6935 4 : if (pszComma)
6936 2 : nPrecision = atoi(pszComma + 1);
6937 : }
6938 :
6939 6 : OGRFieldType eType = OFTString;
6940 6 : if (EQUAL(pszType, "INTEGER"))
6941 0 : eType = OFTInteger;
6942 6 : else if (EQUAL(pszType, "INTEGER[]"))
6943 0 : eType = OFTIntegerList;
6944 6 : else if (EQUAL(pszType, "FLOAT") || EQUAL(pszType, "NUMERIC") ||
6945 4 : EQUAL(pszType, "DOUBLE") /* unofficial alias */ ||
6946 4 : EQUAL(pszType, "REAL") /* unofficial alias */)
6947 2 : eType = OFTReal;
6948 4 : else if (EQUAL(pszType, "FLOAT[]") || EQUAL(pszType, "NUMERIC[]") ||
6949 4 : EQUAL(pszType, "DOUBLE[]") /* unofficial alias */ ||
6950 4 : EQUAL(pszType, "REAL[]") /* unofficial alias */)
6951 0 : eType = OFTRealList;
6952 4 : else if (EQUAL(pszType, "CHARACTER") ||
6953 0 : EQUAL(pszType, "TEXT") /* unofficial alias */ ||
6954 0 : EQUAL(pszType, "STRING") /* unofficial alias */ ||
6955 0 : EQUAL(pszType, "VARCHAR") /* unofficial alias */)
6956 4 : eType = OFTString;
6957 0 : else if (EQUAL(pszType, "TEXT[]") ||
6958 0 : EQUAL(pszType, "STRING[]") /* unofficial alias */ ||
6959 0 : EQUAL(pszType, "VARCHAR[]") /* unofficial alias */)
6960 0 : eType = OFTStringList;
6961 0 : else if (EQUAL(pszType, "DATE"))
6962 0 : eType = OFTDate;
6963 0 : else if (EQUAL(pszType, "TIME"))
6964 0 : eType = OFTTime;
6965 0 : else if (EQUAL(pszType, "TIMESTAMP") ||
6966 0 : EQUAL(pszType, "DATETIME") /* unofficial alias */)
6967 0 : eType = OFTDateTime;
6968 : else
6969 0 : CPLError(CE_Warning, CPLE_NotSupported,
6970 : "Unsupported column type '%s'. Defaulting to VARCHAR",
6971 : pszType);
6972 :
6973 6 : return eType;
6974 : }
6975 :
6976 : /************************************************************************/
6977 : /* ProcessSQLAlterTableAddColumn() */
6978 : /* */
6979 : /* The correct syntax for adding a column in the OGR SQL */
6980 : /* dialect is: */
6981 : /* */
6982 : /* ALTER TABLE <layername> ADD [COLUMN] <columnname> <columntype> */
6983 : /************************************************************************/
6984 :
6985 : //! @cond Doxygen_Suppress
6986 2 : OGRErr GDALDataset::ProcessSQLAlterTableAddColumn(const char *pszSQLCommand)
6987 :
6988 : {
6989 2 : char **papszTokens = CSLTokenizeString(pszSQLCommand);
6990 :
6991 : /* -------------------------------------------------------------------- */
6992 : /* Do some general syntax checking. */
6993 : /* -------------------------------------------------------------------- */
6994 2 : const char *pszLayerName = nullptr;
6995 2 : const char *pszColumnName = nullptr;
6996 2 : int iTypeIndex = 0;
6997 2 : const int nTokens = CSLCount(papszTokens);
6998 :
6999 2 : if (nTokens >= 7 && EQUAL(papszTokens[0], "ALTER") &&
7000 2 : EQUAL(papszTokens[1], "TABLE") && EQUAL(papszTokens[3], "ADD") &&
7001 2 : EQUAL(papszTokens[4], "COLUMN"))
7002 : {
7003 1 : pszLayerName = papszTokens[2];
7004 1 : pszColumnName = papszTokens[5];
7005 1 : iTypeIndex = 6;
7006 : }
7007 1 : else if (nTokens >= 6 && EQUAL(papszTokens[0], "ALTER") &&
7008 1 : EQUAL(papszTokens[1], "TABLE") && EQUAL(papszTokens[3], "ADD"))
7009 : {
7010 1 : pszLayerName = papszTokens[2];
7011 1 : pszColumnName = papszTokens[4];
7012 1 : iTypeIndex = 5;
7013 : }
7014 : else
7015 : {
7016 0 : CSLDestroy(papszTokens);
7017 0 : CPLError(CE_Failure, CPLE_AppDefined,
7018 : "Syntax error in ALTER TABLE ADD COLUMN command.\n"
7019 : "Was '%s'\n"
7020 : "Should be of form 'ALTER TABLE <layername> ADD [COLUMN] "
7021 : "<columnname> <columntype>'",
7022 : pszSQLCommand);
7023 0 : return OGRERR_FAILURE;
7024 : }
7025 :
7026 : /* -------------------------------------------------------------------- */
7027 : /* Merge type components into a single string if there were split */
7028 : /* with spaces */
7029 : /* -------------------------------------------------------------------- */
7030 4 : CPLString osType;
7031 6 : for (int i = iTypeIndex; i < nTokens; ++i)
7032 : {
7033 4 : osType += papszTokens[i];
7034 4 : CPLFree(papszTokens[i]);
7035 : }
7036 2 : char *pszType = papszTokens[iTypeIndex] = CPLStrdup(osType);
7037 2 : papszTokens[iTypeIndex + 1] = nullptr;
7038 :
7039 : /* -------------------------------------------------------------------- */
7040 : /* Find the named layer. */
7041 : /* -------------------------------------------------------------------- */
7042 2 : OGRLayer *poLayer = GetLayerByName(pszLayerName);
7043 2 : if (poLayer == nullptr)
7044 : {
7045 0 : CPLError(CE_Failure, CPLE_AppDefined,
7046 : "%s failed, no such layer as `%s'.", pszSQLCommand,
7047 : pszLayerName);
7048 0 : CSLDestroy(papszTokens);
7049 0 : return OGRERR_FAILURE;
7050 : }
7051 :
7052 : /* -------------------------------------------------------------------- */
7053 : /* Add column. */
7054 : /* -------------------------------------------------------------------- */
7055 :
7056 2 : int nWidth = 0;
7057 2 : int nPrecision = 0;
7058 2 : OGRFieldType eType = GDALDatasetParseSQLType(pszType, nWidth, nPrecision);
7059 4 : OGRFieldDefn oFieldDefn(pszColumnName, eType);
7060 2 : oFieldDefn.SetWidth(nWidth);
7061 2 : oFieldDefn.SetPrecision(nPrecision);
7062 :
7063 2 : CSLDestroy(papszTokens);
7064 :
7065 2 : return poLayer->CreateField(&oFieldDefn);
7066 : }
7067 :
7068 : /************************************************************************/
7069 : /* ProcessSQLAlterTableDropColumn() */
7070 : /* */
7071 : /* The correct syntax for dropping a column in the OGR SQL */
7072 : /* dialect is: */
7073 : /* */
7074 : /* ALTER TABLE <layername> DROP [COLUMN] <columnname> */
7075 : /************************************************************************/
7076 :
7077 2 : OGRErr GDALDataset::ProcessSQLAlterTableDropColumn(const char *pszSQLCommand)
7078 :
7079 : {
7080 2 : char **papszTokens = CSLTokenizeString(pszSQLCommand);
7081 :
7082 : /* -------------------------------------------------------------------- */
7083 : /* Do some general syntax checking. */
7084 : /* -------------------------------------------------------------------- */
7085 2 : const char *pszLayerName = nullptr;
7086 2 : const char *pszColumnName = nullptr;
7087 3 : if (CSLCount(papszTokens) == 6 && EQUAL(papszTokens[0], "ALTER") &&
7088 4 : EQUAL(papszTokens[1], "TABLE") && EQUAL(papszTokens[3], "DROP") &&
7089 1 : EQUAL(papszTokens[4], "COLUMN"))
7090 : {
7091 1 : pszLayerName = papszTokens[2];
7092 1 : pszColumnName = papszTokens[5];
7093 : }
7094 2 : else if (CSLCount(papszTokens) == 5 && EQUAL(papszTokens[0], "ALTER") &&
7095 2 : EQUAL(papszTokens[1], "TABLE") && EQUAL(papszTokens[3], "DROP"))
7096 : {
7097 1 : pszLayerName = papszTokens[2];
7098 1 : pszColumnName = papszTokens[4];
7099 : }
7100 : else
7101 : {
7102 0 : CSLDestroy(papszTokens);
7103 0 : CPLError(CE_Failure, CPLE_AppDefined,
7104 : "Syntax error in ALTER TABLE DROP COLUMN command.\n"
7105 : "Was '%s'\n"
7106 : "Should be of form 'ALTER TABLE <layername> DROP [COLUMN] "
7107 : "<columnname>'",
7108 : pszSQLCommand);
7109 0 : return OGRERR_FAILURE;
7110 : }
7111 :
7112 : /* -------------------------------------------------------------------- */
7113 : /* Find the named layer. */
7114 : /* -------------------------------------------------------------------- */
7115 2 : OGRLayer *poLayer = GetLayerByName(pszLayerName);
7116 2 : if (poLayer == nullptr)
7117 : {
7118 0 : CPLError(CE_Failure, CPLE_AppDefined,
7119 : "%s failed, no such layer as `%s'.", pszSQLCommand,
7120 : pszLayerName);
7121 0 : CSLDestroy(papszTokens);
7122 0 : return OGRERR_FAILURE;
7123 : }
7124 :
7125 : /* -------------------------------------------------------------------- */
7126 : /* Find the field. */
7127 : /* -------------------------------------------------------------------- */
7128 :
7129 2 : int nFieldIndex = poLayer->GetLayerDefn()->GetFieldIndex(pszColumnName);
7130 2 : if (nFieldIndex < 0)
7131 : {
7132 0 : CPLError(CE_Failure, CPLE_AppDefined,
7133 : "%s failed, no such field as `%s'.", pszSQLCommand,
7134 : pszColumnName);
7135 0 : CSLDestroy(papszTokens);
7136 0 : return OGRERR_FAILURE;
7137 : }
7138 :
7139 : /* -------------------------------------------------------------------- */
7140 : /* Remove it. */
7141 : /* -------------------------------------------------------------------- */
7142 :
7143 2 : CSLDestroy(papszTokens);
7144 :
7145 2 : return poLayer->DeleteField(nFieldIndex);
7146 : }
7147 :
7148 : /************************************************************************/
7149 : /* ProcessSQLAlterTableRenameColumn() */
7150 : /* */
7151 : /* The correct syntax for renaming a column in the OGR SQL */
7152 : /* dialect is: */
7153 : /* */
7154 : /* ALTER TABLE <layername> RENAME [COLUMN] <oldname> TO <newname> */
7155 : /************************************************************************/
7156 :
7157 2 : OGRErr GDALDataset::ProcessSQLAlterTableRenameColumn(const char *pszSQLCommand)
7158 :
7159 : {
7160 2 : char **papszTokens = CSLTokenizeString(pszSQLCommand);
7161 :
7162 : /* -------------------------------------------------------------------- */
7163 : /* Do some general syntax checking. */
7164 : /* -------------------------------------------------------------------- */
7165 2 : const char *pszLayerName = nullptr;
7166 2 : const char *pszOldColName = nullptr;
7167 2 : const char *pszNewColName = nullptr;
7168 3 : if (CSLCount(papszTokens) == 8 && EQUAL(papszTokens[0], "ALTER") &&
7169 1 : EQUAL(papszTokens[1], "TABLE") && EQUAL(papszTokens[3], "RENAME") &&
7170 3 : EQUAL(papszTokens[4], "COLUMN") && EQUAL(papszTokens[6], "TO"))
7171 : {
7172 1 : pszLayerName = papszTokens[2];
7173 1 : pszOldColName = papszTokens[5];
7174 1 : pszNewColName = papszTokens[7];
7175 : }
7176 2 : else if (CSLCount(papszTokens) == 7 && EQUAL(papszTokens[0], "ALTER") &&
7177 1 : EQUAL(papszTokens[1], "TABLE") &&
7178 2 : EQUAL(papszTokens[3], "RENAME") && EQUAL(papszTokens[5], "TO"))
7179 : {
7180 1 : pszLayerName = papszTokens[2];
7181 1 : pszOldColName = papszTokens[4];
7182 1 : pszNewColName = papszTokens[6];
7183 : }
7184 : else
7185 : {
7186 0 : CSLDestroy(papszTokens);
7187 0 : CPLError(CE_Failure, CPLE_AppDefined,
7188 : "Syntax error in ALTER TABLE RENAME COLUMN command.\n"
7189 : "Was '%s'\n"
7190 : "Should be of form 'ALTER TABLE <layername> RENAME [COLUMN] "
7191 : "<columnname> TO <newname>'",
7192 : pszSQLCommand);
7193 0 : return OGRERR_FAILURE;
7194 : }
7195 :
7196 : /* -------------------------------------------------------------------- */
7197 : /* Find the named layer. */
7198 : /* -------------------------------------------------------------------- */
7199 2 : OGRLayer *poLayer = GetLayerByName(pszLayerName);
7200 2 : if (poLayer == nullptr)
7201 : {
7202 0 : CPLError(CE_Failure, CPLE_AppDefined,
7203 : "%s failed, no such layer as `%s'.", pszSQLCommand,
7204 : pszLayerName);
7205 0 : CSLDestroy(papszTokens);
7206 0 : return OGRERR_FAILURE;
7207 : }
7208 :
7209 : /* -------------------------------------------------------------------- */
7210 : /* Find the field. */
7211 : /* -------------------------------------------------------------------- */
7212 :
7213 : const int nFieldIndex =
7214 2 : poLayer->GetLayerDefn()->GetFieldIndex(pszOldColName);
7215 2 : if (nFieldIndex < 0)
7216 : {
7217 0 : CPLError(CE_Failure, CPLE_AppDefined,
7218 : "%s failed, no such field as `%s'.", pszSQLCommand,
7219 : pszOldColName);
7220 0 : CSLDestroy(papszTokens);
7221 0 : return OGRERR_FAILURE;
7222 : }
7223 :
7224 : /* -------------------------------------------------------------------- */
7225 : /* Rename column. */
7226 : /* -------------------------------------------------------------------- */
7227 : OGRFieldDefn *poOldFieldDefn =
7228 2 : poLayer->GetLayerDefn()->GetFieldDefn(nFieldIndex);
7229 4 : OGRFieldDefn oNewFieldDefn(poOldFieldDefn);
7230 2 : oNewFieldDefn.SetName(pszNewColName);
7231 :
7232 2 : CSLDestroy(papszTokens);
7233 :
7234 2 : return poLayer->AlterFieldDefn(nFieldIndex, &oNewFieldDefn,
7235 2 : ALTER_NAME_FLAG);
7236 : }
7237 :
7238 : /************************************************************************/
7239 : /* ProcessSQLAlterTableAlterColumn() */
7240 : /* */
7241 : /* The correct syntax for altering the type of a column in the */
7242 : /* OGR SQL dialect is: */
7243 : /* */
7244 : /* ALTER TABLE <layername> ALTER [COLUMN] <columnname> TYPE <newtype> */
7245 : /************************************************************************/
7246 :
7247 4 : OGRErr GDALDataset::ProcessSQLAlterTableAlterColumn(const char *pszSQLCommand)
7248 :
7249 : {
7250 4 : char **papszTokens = CSLTokenizeString(pszSQLCommand);
7251 :
7252 : /* -------------------------------------------------------------------- */
7253 : /* Do some general syntax checking. */
7254 : /* -------------------------------------------------------------------- */
7255 4 : const char *pszLayerName = nullptr;
7256 4 : const char *pszColumnName = nullptr;
7257 4 : int iTypeIndex = 0;
7258 4 : const int nTokens = CSLCount(papszTokens);
7259 :
7260 4 : if (nTokens >= 8 && EQUAL(papszTokens[0], "ALTER") &&
7261 2 : EQUAL(papszTokens[1], "TABLE") && EQUAL(papszTokens[3], "ALTER") &&
7262 2 : EQUAL(papszTokens[4], "COLUMN") && EQUAL(papszTokens[6], "TYPE"))
7263 : {
7264 2 : pszLayerName = papszTokens[2];
7265 2 : pszColumnName = papszTokens[5];
7266 2 : iTypeIndex = 7;
7267 : }
7268 2 : else if (nTokens >= 7 && EQUAL(papszTokens[0], "ALTER") &&
7269 2 : EQUAL(papszTokens[1], "TABLE") && EQUAL(papszTokens[3], "ALTER") &&
7270 2 : EQUAL(papszTokens[5], "TYPE"))
7271 : {
7272 2 : pszLayerName = papszTokens[2];
7273 2 : pszColumnName = papszTokens[4];
7274 2 : iTypeIndex = 6;
7275 : }
7276 : else
7277 : {
7278 0 : CSLDestroy(papszTokens);
7279 0 : CPLError(CE_Failure, CPLE_AppDefined,
7280 : "Syntax error in ALTER TABLE ALTER COLUMN command.\n"
7281 : "Was '%s'\n"
7282 : "Should be of form 'ALTER TABLE <layername> ALTER [COLUMN] "
7283 : "<columnname> TYPE <columntype>'",
7284 : pszSQLCommand);
7285 0 : return OGRERR_FAILURE;
7286 : }
7287 :
7288 : /* -------------------------------------------------------------------- */
7289 : /* Merge type components into a single string if there were split */
7290 : /* with spaces */
7291 : /* -------------------------------------------------------------------- */
7292 8 : CPLString osType;
7293 8 : for (int i = iTypeIndex; i < nTokens; ++i)
7294 : {
7295 4 : osType += papszTokens[i];
7296 4 : CPLFree(papszTokens[i]);
7297 : }
7298 4 : char *pszType = papszTokens[iTypeIndex] = CPLStrdup(osType);
7299 4 : papszTokens[iTypeIndex + 1] = nullptr;
7300 :
7301 : /* -------------------------------------------------------------------- */
7302 : /* Find the named layer. */
7303 : /* -------------------------------------------------------------------- */
7304 4 : OGRLayer *poLayer = GetLayerByName(pszLayerName);
7305 4 : if (poLayer == nullptr)
7306 : {
7307 0 : CPLError(CE_Failure, CPLE_AppDefined,
7308 : "%s failed, no such layer as `%s'.", pszSQLCommand,
7309 : pszLayerName);
7310 0 : CSLDestroy(papszTokens);
7311 0 : return OGRERR_FAILURE;
7312 : }
7313 :
7314 : /* -------------------------------------------------------------------- */
7315 : /* Find the field. */
7316 : /* -------------------------------------------------------------------- */
7317 :
7318 : const int nFieldIndex =
7319 4 : poLayer->GetLayerDefn()->GetFieldIndex(pszColumnName);
7320 4 : if (nFieldIndex < 0)
7321 : {
7322 0 : CPLError(CE_Failure, CPLE_AppDefined,
7323 : "%s failed, no such field as `%s'.", pszSQLCommand,
7324 : pszColumnName);
7325 0 : CSLDestroy(papszTokens);
7326 0 : return OGRERR_FAILURE;
7327 : }
7328 :
7329 : /* -------------------------------------------------------------------- */
7330 : /* Alter column. */
7331 : /* -------------------------------------------------------------------- */
7332 :
7333 : OGRFieldDefn *poOldFieldDefn =
7334 4 : poLayer->GetLayerDefn()->GetFieldDefn(nFieldIndex);
7335 8 : OGRFieldDefn oNewFieldDefn(poOldFieldDefn);
7336 :
7337 4 : int nWidth = 0;
7338 4 : int nPrecision = 0;
7339 4 : OGRFieldType eType = GDALDatasetParseSQLType(pszType, nWidth, nPrecision);
7340 4 : oNewFieldDefn.SetType(eType);
7341 4 : oNewFieldDefn.SetWidth(nWidth);
7342 4 : oNewFieldDefn.SetPrecision(nPrecision);
7343 :
7344 4 : int l_nFlags = 0;
7345 4 : if (poOldFieldDefn->GetType() != oNewFieldDefn.GetType())
7346 2 : l_nFlags |= ALTER_TYPE_FLAG;
7347 4 : if (poOldFieldDefn->GetWidth() != oNewFieldDefn.GetWidth() ||
7348 0 : poOldFieldDefn->GetPrecision() != oNewFieldDefn.GetPrecision())
7349 4 : l_nFlags |= ALTER_WIDTH_PRECISION_FLAG;
7350 :
7351 4 : CSLDestroy(papszTokens);
7352 :
7353 4 : if (l_nFlags == 0)
7354 0 : return OGRERR_NONE;
7355 :
7356 4 : return poLayer->AlterFieldDefn(nFieldIndex, &oNewFieldDefn, l_nFlags);
7357 : }
7358 :
7359 : //! @endcond
7360 :
7361 : /************************************************************************/
7362 : /* ExecuteSQL() */
7363 : /************************************************************************/
7364 :
7365 : /**
7366 : \brief Execute an SQL statement against the data store.
7367 :
7368 : The result of an SQL query is either NULL for statements that are in error,
7369 : or that have no results set, or an OGRLayer pointer representing a results
7370 : set from the query. Note that this OGRLayer is in addition to the layers
7371 : in the data store and must be destroyed with
7372 : ReleaseResultSet() before the dataset is closed
7373 : (destroyed).
7374 :
7375 : This method is the same as the C function GDALDatasetExecuteSQL() and the
7376 : deprecated OGR_DS_ExecuteSQL().
7377 :
7378 : For more information on the SQL dialect supported internally by OGR
7379 : review the <a href="https://gdal.org/user/ogr_sql_dialect.html">OGR SQL</a>
7380 : document. Some drivers (i.e. Oracle and PostGIS) pass the SQL directly through
7381 : to the underlying RDBMS.
7382 :
7383 : Starting with OGR 1.10, the <a
7384 : href="https://gdal.org/user/sql_sqlite_dialect.html">SQLITE dialect</a> can
7385 : also be used.
7386 :
7387 : @param pszStatement the SQL statement to execute.
7388 : @param poSpatialFilter geometry which represents a spatial filter. Can be NULL.
7389 : @param pszDialect allows control of the statement dialect. If set to NULL, the
7390 : OGR SQL engine will be used, except for RDBMS drivers that will use their
7391 : dedicated SQL engine, unless OGRSQL is explicitly passed as the
7392 : dialect. Starting with OGR 1.10, the SQLITE dialect can also be used.
7393 :
7394 : @return an OGRLayer containing the results of the query. Deallocate with
7395 : ReleaseResultSet().
7396 :
7397 : */
7398 :
7399 3671 : OGRLayer *GDALDataset::ExecuteSQL(const char *pszStatement,
7400 : OGRGeometry *poSpatialFilter,
7401 : const char *pszDialect)
7402 :
7403 : {
7404 3671 : return ExecuteSQL(pszStatement, poSpatialFilter, pszDialect, nullptr);
7405 : }
7406 :
7407 : //! @cond Doxygen_Suppress
7408 : OGRLayer *
7409 3679 : GDALDataset::ExecuteSQL(const char *pszStatement, OGRGeometry *poSpatialFilter,
7410 : const char *pszDialect,
7411 : swq_select_parse_options *poSelectParseOptions)
7412 :
7413 : {
7414 3679 : if (pszDialect != nullptr && EQUAL(pszDialect, "SQLite"))
7415 : {
7416 : #ifdef SQLITE_ENABLED
7417 668 : return OGRSQLiteExecuteSQL(this, pszStatement, poSpatialFilter,
7418 668 : pszDialect);
7419 : #else
7420 : CPLError(CE_Failure, CPLE_NotSupported,
7421 : "The SQLite driver needs to be compiled to support the "
7422 : "SQLite SQL dialect");
7423 : return nullptr;
7424 : #endif
7425 : }
7426 :
7427 3011 : if (pszDialect != nullptr && !EQUAL(pszDialect, "") &&
7428 14 : !EQUAL(pszDialect, "OGRSQL"))
7429 : {
7430 6 : std::string osDialectList = "'OGRSQL'";
7431 : #ifdef SQLITE_ENABLED
7432 3 : osDialectList += ", 'SQLITE'";
7433 : #endif
7434 : const char *pszDialects =
7435 3 : GetMetadataItem(GDAL_DMD_SUPPORTED_SQL_DIALECTS);
7436 3 : if (pszDialects)
7437 : {
7438 : const CPLStringList aosTokens(
7439 0 : CSLTokenizeString2(pszDialects, " ", 0));
7440 0 : for (int i = 0; i < aosTokens.size(); ++i)
7441 : {
7442 0 : if (!EQUAL(aosTokens[i], "OGRSQL") &&
7443 0 : !EQUAL(aosTokens[i], "SQLITE"))
7444 : {
7445 0 : osDialectList += ", '";
7446 0 : osDialectList += aosTokens[i];
7447 0 : osDialectList += "'";
7448 : }
7449 : }
7450 : }
7451 3 : CPLError(CE_Warning, CPLE_NotSupported,
7452 : "Dialect '%s' is unsupported. Only supported dialects are %s. "
7453 : "Defaulting to OGRSQL",
7454 : pszDialect, osDialectList.c_str());
7455 : }
7456 :
7457 : /* -------------------------------------------------------------------- */
7458 : /* Handle CREATE INDEX statements specially. */
7459 : /* -------------------------------------------------------------------- */
7460 3011 : if (STARTS_WITH_CI(pszStatement, "CREATE INDEX"))
7461 : {
7462 28 : ProcessSQLCreateIndex(pszStatement);
7463 28 : return nullptr;
7464 : }
7465 :
7466 : /* -------------------------------------------------------------------- */
7467 : /* Handle DROP INDEX statements specially. */
7468 : /* -------------------------------------------------------------------- */
7469 2983 : if (STARTS_WITH_CI(pszStatement, "DROP INDEX"))
7470 : {
7471 10 : ProcessSQLDropIndex(pszStatement);
7472 10 : return nullptr;
7473 : }
7474 :
7475 : /* -------------------------------------------------------------------- */
7476 : /* Handle DROP TABLE statements specially. */
7477 : /* -------------------------------------------------------------------- */
7478 2973 : if (STARTS_WITH_CI(pszStatement, "DROP TABLE"))
7479 : {
7480 500 : ProcessSQLDropTable(pszStatement);
7481 500 : return nullptr;
7482 : }
7483 :
7484 : /* -------------------------------------------------------------------- */
7485 : /* Handle ALTER TABLE statements specially. */
7486 : /* -------------------------------------------------------------------- */
7487 2473 : if (STARTS_WITH_CI(pszStatement, "ALTER TABLE"))
7488 : {
7489 11 : char **papszTokens = CSLTokenizeString(pszStatement);
7490 11 : const int nTokens = CSLCount(papszTokens);
7491 11 : if (nTokens >= 4 && EQUAL(papszTokens[3], "ADD"))
7492 : {
7493 2 : ProcessSQLAlterTableAddColumn(pszStatement);
7494 2 : CSLDestroy(papszTokens);
7495 2 : return nullptr;
7496 : }
7497 9 : else if (nTokens >= 4 && EQUAL(papszTokens[3], "DROP"))
7498 : {
7499 2 : ProcessSQLAlterTableDropColumn(pszStatement);
7500 2 : CSLDestroy(papszTokens);
7501 2 : return nullptr;
7502 : }
7503 7 : else if (nTokens == 6 && EQUAL(papszTokens[3], "RENAME") &&
7504 1 : EQUAL(papszTokens[4], "TO"))
7505 : {
7506 1 : const char *pszSrcTableName = papszTokens[2];
7507 1 : const char *pszDstTableName = papszTokens[5];
7508 1 : auto poSrcLayer = GetLayerByName(pszSrcTableName);
7509 1 : if (poSrcLayer)
7510 : {
7511 1 : CPL_IGNORE_RET_VAL(poSrcLayer->Rename(pszDstTableName));
7512 : }
7513 : else
7514 : {
7515 0 : CPLError(CE_Failure, CPLE_AppDefined, "Invalid layer name");
7516 : }
7517 1 : CSLDestroy(papszTokens);
7518 1 : return nullptr;
7519 : }
7520 6 : else if (nTokens >= 4 && EQUAL(papszTokens[3], "RENAME"))
7521 : {
7522 2 : ProcessSQLAlterTableRenameColumn(pszStatement);
7523 2 : CSLDestroy(papszTokens);
7524 2 : return nullptr;
7525 : }
7526 4 : else if (nTokens >= 4 && EQUAL(papszTokens[3], "ALTER"))
7527 : {
7528 4 : ProcessSQLAlterTableAlterColumn(pszStatement);
7529 4 : CSLDestroy(papszTokens);
7530 4 : return nullptr;
7531 : }
7532 : else
7533 : {
7534 0 : CPLError(CE_Failure, CPLE_AppDefined,
7535 : "Unsupported ALTER TABLE command : %s", pszStatement);
7536 0 : CSLDestroy(papszTokens);
7537 0 : return nullptr;
7538 : }
7539 : }
7540 :
7541 : /* -------------------------------------------------------------------- */
7542 : /* Preparse the SQL statement. */
7543 : /* -------------------------------------------------------------------- */
7544 2462 : swq_select *psSelectInfo = new swq_select();
7545 2462 : swq_custom_func_registrar *poCustomFuncRegistrar = nullptr;
7546 2462 : if (poSelectParseOptions != nullptr)
7547 8 : poCustomFuncRegistrar = poSelectParseOptions->poCustomFuncRegistrar;
7548 2462 : if (psSelectInfo->preparse(pszStatement,
7549 2462 : poCustomFuncRegistrar != nullptr) != CE_None)
7550 : {
7551 152 : delete psSelectInfo;
7552 152 : return nullptr;
7553 : }
7554 :
7555 : /* -------------------------------------------------------------------- */
7556 : /* If there is no UNION ALL, build result layer. */
7557 : /* -------------------------------------------------------------------- */
7558 2310 : if (psSelectInfo->poOtherSelect == nullptr)
7559 : {
7560 2304 : return BuildLayerFromSelectInfo(psSelectInfo, poSpatialFilter,
7561 2304 : pszDialect, poSelectParseOptions);
7562 : }
7563 :
7564 : /* -------------------------------------------------------------------- */
7565 : /* Build result union layer. */
7566 : /* -------------------------------------------------------------------- */
7567 6 : int nSrcLayers = 0;
7568 6 : OGRLayer **papoSrcLayers = nullptr;
7569 :
7570 6 : do
7571 : {
7572 12 : swq_select *psNextSelectInfo = psSelectInfo->poOtherSelect;
7573 12 : psSelectInfo->poOtherSelect = nullptr;
7574 :
7575 12 : OGRLayer *poLayer = BuildLayerFromSelectInfo(
7576 : psSelectInfo, poSpatialFilter, pszDialect, poSelectParseOptions);
7577 12 : if (poLayer == nullptr)
7578 : {
7579 : // Each source layer owns an independent select info.
7580 0 : for (int i = 0; i < nSrcLayers; ++i)
7581 0 : delete papoSrcLayers[i];
7582 0 : CPLFree(papoSrcLayers);
7583 :
7584 : // So we just have to destroy the remaining select info.
7585 0 : delete psNextSelectInfo;
7586 :
7587 0 : return nullptr;
7588 : }
7589 : else
7590 : {
7591 24 : papoSrcLayers = static_cast<OGRLayer **>(CPLRealloc(
7592 12 : papoSrcLayers, sizeof(OGRLayer *) * (nSrcLayers + 1)));
7593 12 : papoSrcLayers[nSrcLayers] = poLayer;
7594 12 : ++nSrcLayers;
7595 :
7596 12 : psSelectInfo = psNextSelectInfo;
7597 : }
7598 12 : } while (psSelectInfo != nullptr);
7599 :
7600 6 : return new OGRUnionLayer("SELECT", nSrcLayers, papoSrcLayers, TRUE);
7601 : }
7602 :
7603 : //! @endcond
7604 :
7605 : /************************************************************************/
7606 : /* AbortSQL() */
7607 : /************************************************************************/
7608 :
7609 : /**
7610 : \brief Abort any SQL statement running in the data store.
7611 :
7612 : This function can be safely called from any thread (pending that the dataset
7613 : object is still alive). Driver implementations will make sure that it can be
7614 : called in a thread-safe way.
7615 :
7616 : This might not be implemented by all drivers. At time of writing, only SQLite,
7617 : GPKG and PG drivers implement it
7618 :
7619 : This method is the same as the C method GDALDatasetAbortSQL()
7620 :
7621 : @since GDAL 3.2.0
7622 :
7623 :
7624 : */
7625 :
7626 0 : OGRErr GDALDataset::AbortSQL()
7627 : {
7628 0 : CPLError(CE_Failure, CPLE_NotSupported,
7629 : "AbortSQL is not supported for this driver.");
7630 0 : return OGRERR_UNSUPPORTED_OPERATION;
7631 : }
7632 :
7633 : /************************************************************************/
7634 : /* BuildLayerFromSelectInfo() */
7635 : /************************************************************************/
7636 :
7637 : struct GDALSQLParseInfo
7638 : {
7639 : swq_field_list sFieldList;
7640 : int nExtraDSCount;
7641 : GDALDataset **papoExtraDS;
7642 : char *pszWHERE;
7643 : };
7644 :
7645 2316 : OGRLayer *GDALDataset::BuildLayerFromSelectInfo(
7646 : swq_select *psSelectInfo, OGRGeometry *poSpatialFilter,
7647 : const char *pszDialect, swq_select_parse_options *poSelectParseOptions)
7648 : {
7649 4632 : std::unique_ptr<swq_select> psSelectInfoUnique(psSelectInfo);
7650 :
7651 2316 : std::unique_ptr<OGRGenSQLResultsLayer> poResults;
7652 : GDALSQLParseInfo *psParseInfo =
7653 2316 : BuildParseInfo(psSelectInfoUnique.get(), poSelectParseOptions);
7654 :
7655 2316 : if (psParseInfo)
7656 : {
7657 2281 : const auto nErrorCounter = CPLGetErrorCounter();
7658 4562 : poResults = std::make_unique<OGRGenSQLResultsLayer>(
7659 2281 : this, std::move(psSelectInfoUnique), poSpatialFilter,
7660 4562 : psParseInfo->pszWHERE, pszDialect);
7661 2358 : if (CPLGetErrorCounter() > nErrorCounter &&
7662 77 : CPLGetLastErrorType() != CE_None)
7663 77 : poResults.reset();
7664 : }
7665 :
7666 2316 : DestroyParseInfo(psParseInfo);
7667 :
7668 4632 : return poResults.release();
7669 : }
7670 :
7671 : /************************************************************************/
7672 : /* DestroyParseInfo() */
7673 : /************************************************************************/
7674 :
7675 : //! @cond Doxygen_Suppress
7676 2385 : void GDALDataset::DestroyParseInfo(GDALSQLParseInfo *psParseInfo)
7677 : {
7678 2385 : if (psParseInfo == nullptr)
7679 35 : return;
7680 :
7681 2350 : CPLFree(psParseInfo->sFieldList.names);
7682 2350 : CPLFree(psParseInfo->sFieldList.types);
7683 2350 : CPLFree(psParseInfo->sFieldList.table_ids);
7684 2350 : CPLFree(psParseInfo->sFieldList.ids);
7685 :
7686 : // Release the datasets we have opened with OGROpenShared()
7687 : // It is safe to do that as the 'new OGRGenSQLResultsLayer' itself
7688 : // has taken a reference on them, which it will release in its
7689 : // destructor.
7690 2357 : for (int iEDS = 0; iEDS < psParseInfo->nExtraDSCount; ++iEDS)
7691 7 : GDALClose(psParseInfo->papoExtraDS[iEDS]);
7692 :
7693 2350 : CPLFree(psParseInfo->papoExtraDS);
7694 2350 : CPLFree(psParseInfo->pszWHERE);
7695 2350 : CPLFree(psParseInfo);
7696 : }
7697 :
7698 : /************************************************************************/
7699 : /* BuildParseInfo() */
7700 : /************************************************************************/
7701 :
7702 : GDALSQLParseInfo *
7703 2350 : GDALDataset::BuildParseInfo(swq_select *psSelectInfo,
7704 : swq_select_parse_options *poSelectParseOptions)
7705 : {
7706 2350 : int nFirstLayerFirstSpecialFieldIndex = 0;
7707 :
7708 : GDALSQLParseInfo *psParseInfo =
7709 2350 : static_cast<GDALSQLParseInfo *>(CPLCalloc(1, sizeof(GDALSQLParseInfo)));
7710 :
7711 : /* -------------------------------------------------------------------- */
7712 : /* Validate that all the source tables are recognized, count */
7713 : /* fields. */
7714 : /* -------------------------------------------------------------------- */
7715 2350 : int nFieldCount = 0;
7716 :
7717 4768 : for (int iTable = 0; iTable < psSelectInfo->table_count; iTable++)
7718 : {
7719 2421 : swq_table_def *psTableDef = psSelectInfo->table_defs + iTable;
7720 2421 : GDALDataset *poTableDS = this;
7721 :
7722 2421 : if (psTableDef->data_source != nullptr)
7723 : {
7724 7 : poTableDS = GDALDataset::FromHandle(
7725 7 : OGROpenShared(psTableDef->data_source, FALSE, nullptr));
7726 7 : if (poTableDS == nullptr)
7727 : {
7728 0 : if (strlen(CPLGetLastErrorMsg()) == 0)
7729 0 : CPLError(CE_Failure, CPLE_AppDefined,
7730 : "Unable to open secondary datasource "
7731 : "`%s' required by JOIN.",
7732 : psTableDef->data_source);
7733 :
7734 0 : DestroyParseInfo(psParseInfo);
7735 0 : return nullptr;
7736 : }
7737 :
7738 : // Keep in an array to release at the end of this function.
7739 14 : psParseInfo->papoExtraDS = static_cast<GDALDataset **>(CPLRealloc(
7740 7 : psParseInfo->papoExtraDS,
7741 7 : sizeof(GDALDataset *) * (psParseInfo->nExtraDSCount + 1)));
7742 7 : psParseInfo->papoExtraDS[psParseInfo->nExtraDSCount++] = poTableDS;
7743 : }
7744 :
7745 : OGRLayer *poSrcLayer =
7746 2421 : poTableDS->GetLayerByName(psTableDef->table_name);
7747 :
7748 2421 : if (poSrcLayer == nullptr)
7749 : {
7750 3 : CPLError(CE_Failure, CPLE_AppDefined,
7751 : "SELECT from table %s failed, no such table/featureclass.",
7752 : psTableDef->table_name);
7753 :
7754 3 : DestroyParseInfo(psParseInfo);
7755 3 : return nullptr;
7756 : }
7757 :
7758 2418 : nFieldCount += poSrcLayer->GetLayerDefn()->GetFieldCount();
7759 2418 : if (iTable == 0 ||
7760 34 : (poSelectParseOptions &&
7761 34 : poSelectParseOptions->bAddSecondaryTablesGeometryFields))
7762 2381 : nFieldCount += poSrcLayer->GetLayerDefn()->GetGeomFieldCount();
7763 :
7764 2418 : const char *pszFID = poSrcLayer->GetFIDColumn();
7765 3029 : if (pszFID && !EQUAL(pszFID, "") && !EQUAL(pszFID, "FID") &&
7766 611 : poSrcLayer->GetLayerDefn()->GetFieldIndex(pszFID) < 0)
7767 561 : nFieldCount++;
7768 : }
7769 :
7770 : /* -------------------------------------------------------------------- */
7771 : /* Build the field list for all indicated tables. */
7772 : /* -------------------------------------------------------------------- */
7773 :
7774 2347 : psParseInfo->sFieldList.table_count = psSelectInfo->table_count;
7775 2347 : psParseInfo->sFieldList.table_defs = psSelectInfo->table_defs;
7776 :
7777 2347 : psParseInfo->sFieldList.count = 0;
7778 2347 : psParseInfo->sFieldList.names = static_cast<char **>(
7779 2347 : CPLMalloc(sizeof(char *) * (nFieldCount + SPECIAL_FIELD_COUNT)));
7780 4694 : psParseInfo->sFieldList.types = static_cast<swq_field_type *>(CPLMalloc(
7781 2347 : sizeof(swq_field_type) * (nFieldCount + SPECIAL_FIELD_COUNT)));
7782 2347 : psParseInfo->sFieldList.table_ids = static_cast<int *>(
7783 2347 : CPLMalloc(sizeof(int) * (nFieldCount + SPECIAL_FIELD_COUNT)));
7784 2347 : psParseInfo->sFieldList.ids = static_cast<int *>(
7785 2347 : CPLMalloc(sizeof(int) * (nFieldCount + SPECIAL_FIELD_COUNT)));
7786 :
7787 2347 : bool bIsFID64 = false;
7788 4765 : for (int iTable = 0; iTable < psSelectInfo->table_count; iTable++)
7789 : {
7790 2418 : swq_table_def *psTableDef = psSelectInfo->table_defs + iTable;
7791 2418 : GDALDataset *poTableDS = this;
7792 :
7793 2418 : if (psTableDef->data_source != nullptr)
7794 : {
7795 7 : poTableDS = GDALDataset::FromHandle(
7796 7 : OGROpenShared(psTableDef->data_source, FALSE, nullptr));
7797 7 : CPLAssert(poTableDS != nullptr);
7798 7 : poTableDS->Dereference();
7799 : }
7800 :
7801 : OGRLayer *poSrcLayer =
7802 2418 : poTableDS->GetLayerByName(psTableDef->table_name);
7803 :
7804 2418 : for (int iField = 0;
7805 19012 : iField < poSrcLayer->GetLayerDefn()->GetFieldCount(); iField++)
7806 : {
7807 : OGRFieldDefn *poFDefn =
7808 16594 : poSrcLayer->GetLayerDefn()->GetFieldDefn(iField);
7809 16594 : const int iOutField = psParseInfo->sFieldList.count++;
7810 33188 : psParseInfo->sFieldList.names[iOutField] =
7811 16594 : const_cast<char *>(poFDefn->GetNameRef());
7812 16594 : if (poFDefn->GetType() == OFTInteger)
7813 : {
7814 4099 : if (poFDefn->GetSubType() == OFSTBoolean)
7815 160 : psParseInfo->sFieldList.types[iOutField] = SWQ_BOOLEAN;
7816 : else
7817 3939 : psParseInfo->sFieldList.types[iOutField] = SWQ_INTEGER;
7818 : }
7819 12495 : else if (poFDefn->GetType() == OFTInteger64)
7820 : {
7821 795 : if (poFDefn->GetSubType() == OFSTBoolean)
7822 0 : psParseInfo->sFieldList.types[iOutField] = SWQ_BOOLEAN;
7823 : else
7824 795 : psParseInfo->sFieldList.types[iOutField] = SWQ_INTEGER64;
7825 : }
7826 11700 : else if (poFDefn->GetType() == OFTReal)
7827 2750 : psParseInfo->sFieldList.types[iOutField] = SWQ_FLOAT;
7828 8950 : else if (poFDefn->GetType() == OFTString)
7829 5888 : psParseInfo->sFieldList.types[iOutField] = SWQ_STRING;
7830 3062 : else if (poFDefn->GetType() == OFTTime)
7831 83 : psParseInfo->sFieldList.types[iOutField] = SWQ_TIME;
7832 2979 : else if (poFDefn->GetType() == OFTDate)
7833 151 : psParseInfo->sFieldList.types[iOutField] = SWQ_DATE;
7834 2828 : else if (poFDefn->GetType() == OFTDateTime)
7835 939 : psParseInfo->sFieldList.types[iOutField] = SWQ_TIMESTAMP;
7836 : else
7837 1889 : psParseInfo->sFieldList.types[iOutField] = SWQ_OTHER;
7838 :
7839 16594 : psParseInfo->sFieldList.table_ids[iOutField] = iTable;
7840 16594 : psParseInfo->sFieldList.ids[iOutField] = iField;
7841 : }
7842 :
7843 2418 : if (iTable == 0)
7844 : {
7845 2347 : nFirstLayerFirstSpecialFieldIndex = psParseInfo->sFieldList.count;
7846 : }
7847 :
7848 2418 : if (iTable == 0 ||
7849 34 : (poSelectParseOptions &&
7850 34 : poSelectParseOptions->bAddSecondaryTablesGeometryFields))
7851 : {
7852 :
7853 2381 : for (int iField = 0;
7854 4411 : iField < poSrcLayer->GetLayerDefn()->GetGeomFieldCount();
7855 : iField++)
7856 : {
7857 : OGRGeomFieldDefn *poFDefn =
7858 2030 : poSrcLayer->GetLayerDefn()->GetGeomFieldDefn(iField);
7859 2030 : const int iOutField = psParseInfo->sFieldList.count++;
7860 4060 : psParseInfo->sFieldList.names[iOutField] =
7861 2030 : const_cast<char *>(poFDefn->GetNameRef());
7862 2030 : if (*psParseInfo->sFieldList.names[iOutField] == '\0')
7863 1205 : psParseInfo->sFieldList.names[iOutField] =
7864 : const_cast<char *>(OGR_GEOMETRY_DEFAULT_NON_EMPTY_NAME);
7865 2030 : psParseInfo->sFieldList.types[iOutField] = SWQ_GEOMETRY;
7866 :
7867 2030 : psParseInfo->sFieldList.table_ids[iOutField] = iTable;
7868 2030 : psParseInfo->sFieldList.ids[iOutField] =
7869 2030 : GEOM_FIELD_INDEX_TO_ALL_FIELD_INDEX(
7870 : poSrcLayer->GetLayerDefn(), iField);
7871 : }
7872 : }
7873 :
7874 2419 : if (iTable == 0 && poSrcLayer->GetMetadataItem(OLMD_FID64) != nullptr &&
7875 1 : EQUAL(poSrcLayer->GetMetadataItem(OLMD_FID64), "YES"))
7876 : {
7877 1 : bIsFID64 = true;
7878 : }
7879 : }
7880 :
7881 : /* -------------------------------------------------------------------- */
7882 : /* Expand '*' in 'SELECT *' now before we add the pseudo fields */
7883 : /* -------------------------------------------------------------------- */
7884 2347 : const bool bAlwaysPrefixWithTableName =
7885 2389 : poSelectParseOptions &&
7886 42 : poSelectParseOptions->bAlwaysPrefixWithTableName;
7887 2347 : if (psSelectInfo->expand_wildcard(&psParseInfo->sFieldList,
7888 2347 : bAlwaysPrefixWithTableName) != CE_None)
7889 : {
7890 2 : DestroyParseInfo(psParseInfo);
7891 2 : return nullptr;
7892 : }
7893 :
7894 14070 : for (int iField = 0; iField < SPECIAL_FIELD_COUNT; iField++)
7895 : {
7896 11725 : psParseInfo->sFieldList.names[psParseInfo->sFieldList.count] =
7897 11725 : const_cast<char *>(SpecialFieldNames[iField]);
7898 11725 : psParseInfo->sFieldList.types[psParseInfo->sFieldList.count] =
7899 11725 : (iField == SPF_FID && bIsFID64) ? SWQ_INTEGER64
7900 : : SpecialFieldTypes[iField];
7901 11725 : psParseInfo->sFieldList.table_ids[psParseInfo->sFieldList.count] = 0;
7902 11725 : psParseInfo->sFieldList.ids[psParseInfo->sFieldList.count] =
7903 11725 : nFirstLayerFirstSpecialFieldIndex + iField;
7904 11725 : psParseInfo->sFieldList.count++;
7905 : }
7906 :
7907 : /* In the case a layer has an explicit FID column name, then add it */
7908 : /* so it can be selected */
7909 4761 : for (int iTable = 0; iTable < psSelectInfo->table_count; iTable++)
7910 : {
7911 2416 : swq_table_def *psTableDef = psSelectInfo->table_defs + iTable;
7912 2416 : GDALDataset *poTableDS = this;
7913 :
7914 2416 : if (psTableDef->data_source != nullptr)
7915 : {
7916 7 : poTableDS = GDALDataset::FromHandle(
7917 7 : OGROpenShared(psTableDef->data_source, FALSE, nullptr));
7918 7 : CPLAssert(poTableDS != nullptr);
7919 7 : poTableDS->Dereference();
7920 : }
7921 :
7922 : OGRLayer *poSrcLayer =
7923 2416 : poTableDS->GetLayerByName(psTableDef->table_name);
7924 :
7925 2416 : const char *pszFID = poSrcLayer->GetFIDColumn();
7926 3027 : if (pszFID && !EQUAL(pszFID, "") && !EQUAL(pszFID, "FID") &&
7927 611 : poSrcLayer->GetLayerDefn()->GetFieldIndex(pszFID) < 0)
7928 : {
7929 561 : const int iOutField = psParseInfo->sFieldList.count++;
7930 561 : psParseInfo->sFieldList.names[iOutField] =
7931 : const_cast<char *>(pszFID);
7932 561 : if (poSrcLayer->GetMetadataItem(OLMD_FID64) != nullptr &&
7933 0 : EQUAL(poSrcLayer->GetMetadataItem(OLMD_FID64), "YES"))
7934 : {
7935 0 : psParseInfo->sFieldList.types[iOutField] = SWQ_INTEGER64;
7936 : }
7937 : else
7938 : {
7939 561 : psParseInfo->sFieldList.types[iOutField] = SWQ_INTEGER;
7940 : }
7941 561 : psParseInfo->sFieldList.table_ids[iOutField] = iTable;
7942 1122 : psParseInfo->sFieldList.ids[iOutField] =
7943 561 : poSrcLayer->GetLayerDefn()->GetFieldCount() + SPF_FID;
7944 : }
7945 : }
7946 :
7947 : /* -------------------------------------------------------------------- */
7948 : /* Finish the parse operation. */
7949 : /* -------------------------------------------------------------------- */
7950 2345 : if (psSelectInfo->parse(&psParseInfo->sFieldList, poSelectParseOptions) !=
7951 : CE_None)
7952 : {
7953 30 : DestroyParseInfo(psParseInfo);
7954 30 : return nullptr;
7955 : }
7956 :
7957 : /* -------------------------------------------------------------------- */
7958 : /* Extract the WHERE expression to use separately. */
7959 : /* -------------------------------------------------------------------- */
7960 2315 : if (psSelectInfo->where_expr != nullptr)
7961 : {
7962 991 : psParseInfo->pszWHERE =
7963 991 : psSelectInfo->where_expr->Unparse(&psParseInfo->sFieldList, '"');
7964 : // CPLDebug( "OGR", "Unparse() -> %s", pszWHERE );
7965 : }
7966 :
7967 2315 : return psParseInfo;
7968 : }
7969 :
7970 : //! @endcond
7971 :
7972 : /************************************************************************/
7973 : /* ReleaseResultSet() */
7974 : /************************************************************************/
7975 :
7976 : /**
7977 : \brief Release results of ExecuteSQL().
7978 :
7979 : This method should only be used to deallocate OGRLayers resulting from
7980 : an ExecuteSQL() call on the same GDALDataset. Failure to deallocate a
7981 : results set before destroying the GDALDataset may cause errors.
7982 :
7983 : This method is the same as the C function GDALDatasetReleaseResultSet() and the
7984 : deprecated OGR_DS_ReleaseResultSet().
7985 :
7986 : @param poResultsSet the result of a previous ExecuteSQL() call.
7987 : */
7988 :
7989 2246 : void GDALDataset::ReleaseResultSet(OGRLayer *poResultsSet)
7990 :
7991 : {
7992 2246 : delete poResultsSet;
7993 2246 : }
7994 :
7995 : /************************************************************************/
7996 : /* GetStyleTable() */
7997 : /************************************************************************/
7998 :
7999 : /**
8000 : \brief Returns dataset style table.
8001 :
8002 : This method is the same as the C function GDALDatasetGetStyleTable() and the
8003 : deprecated OGR_DS_GetStyleTable().
8004 :
8005 : @return pointer to a style table which should not be modified or freed by the
8006 : caller.
8007 : */
8008 :
8009 990 : OGRStyleTable *GDALDataset::GetStyleTable()
8010 : {
8011 990 : return m_poStyleTable;
8012 : }
8013 :
8014 : /************************************************************************/
8015 : /* SetStyleTableDirectly() */
8016 : /************************************************************************/
8017 :
8018 : /**
8019 : \brief Set dataset style table.
8020 :
8021 : This method operate exactly as SetStyleTable() except that it
8022 : assumes ownership of the passed table.
8023 :
8024 : This method is the same as the C function GDALDatasetSetStyleTableDirectly()
8025 : and the deprecated OGR_DS_SetStyleTableDirectly().
8026 :
8027 : @param poStyleTable pointer to style table to set
8028 :
8029 : */
8030 0 : void GDALDataset::SetStyleTableDirectly(OGRStyleTable *poStyleTable)
8031 : {
8032 0 : if (m_poStyleTable)
8033 0 : delete m_poStyleTable;
8034 0 : m_poStyleTable = poStyleTable;
8035 0 : }
8036 :
8037 : /************************************************************************/
8038 : /* SetStyleTable() */
8039 : /************************************************************************/
8040 :
8041 : /**
8042 : \brief Set dataset style table.
8043 :
8044 : This method operate exactly as SetStyleTableDirectly() except
8045 : that it does not assume ownership of the passed table.
8046 :
8047 : This method is the same as the C function GDALDatasetSetStyleTable() and the
8048 : deprecated OGR_DS_SetStyleTable().
8049 :
8050 : @param poStyleTable pointer to style table to set
8051 :
8052 : */
8053 :
8054 986 : void GDALDataset::SetStyleTable(OGRStyleTable *poStyleTable)
8055 : {
8056 986 : if (m_poStyleTable)
8057 0 : delete m_poStyleTable;
8058 986 : if (poStyleTable)
8059 1 : m_poStyleTable = poStyleTable->Clone();
8060 986 : }
8061 :
8062 : /************************************************************************/
8063 : /* IsGenericSQLDialect() */
8064 : /************************************************************************/
8065 :
8066 : //! @cond Doxygen_Suppress
8067 1780 : int GDALDataset::IsGenericSQLDialect(const char *pszDialect)
8068 : {
8069 3252 : return pszDialect != nullptr &&
8070 3252 : (EQUAL(pszDialect, "OGRSQL") || EQUAL(pszDialect, "SQLITE"));
8071 : }
8072 :
8073 : //! @endcond
8074 :
8075 : /************************************************************************/
8076 : /* GetLayerCount() */
8077 : /************************************************************************/
8078 :
8079 : /**
8080 : \brief Get the number of layers in this dataset.
8081 :
8082 : This method is the same as the C function GDALDatasetGetLayerCount(),
8083 : and the deprecated OGR_DS_GetLayerCount().
8084 :
8085 : Note that even if this method is const, there is no guarantee it can be
8086 : safely called by concurrent threads on the same GDALDataset object.
8087 :
8088 : @return layer count.
8089 : */
8090 :
8091 121770 : int GDALDataset::GetLayerCount() const
8092 : {
8093 121770 : return 0;
8094 : }
8095 :
8096 : /************************************************************************/
8097 : /* GetLayer() */
8098 : /************************************************************************/
8099 :
8100 : /**
8101 : \fn const GDALDataset::GetLayer(int) const
8102 : \brief Fetch a layer by index.
8103 :
8104 : The returned layer remains owned by the
8105 : GDALDataset and should not be deleted by the application.
8106 :
8107 : Note that even if this method is const, there is no guarantee it can be
8108 : safely called by concurrent threads on the same GDALDataset object.
8109 :
8110 : See GetLayers() for a C++ iterator version of this method.
8111 :
8112 : This method is the same as the C function GDALDatasetGetLayer() and the
8113 : deprecated OGR_DS_GetLayer().
8114 :
8115 : @param iLayer a layer number between 0 and GetLayerCount()-1.
8116 :
8117 : @return the layer, or NULL if iLayer is out of range or an error occurs.
8118 :
8119 : @see GetLayers()
8120 :
8121 : @since GDAL 3.12
8122 : */
8123 :
8124 0 : const OGRLayer *GDALDataset::GetLayer(CPL_UNUSED int iLayer) const
8125 : {
8126 0 : return nullptr;
8127 : }
8128 :
8129 : /**
8130 : \fn GDALDataset::GetLayer(int)
8131 : \brief Fetch a layer by index.
8132 :
8133 : The returned layer remains owned by the
8134 : GDALDataset and should not be deleted by the application.
8135 :
8136 : See GetLayers() for a C++ iterator version of this method.
8137 :
8138 : This method is the same as the C function GDALDatasetGetLayer() and the
8139 : deprecated OGR_DS_GetLayer().
8140 :
8141 : @param iLayer a layer number between 0 and GetLayerCount()-1.
8142 :
8143 : @return the layer, or NULL if iLayer is out of range or an error occurs.
8144 :
8145 : @see GetLayers()
8146 : */
8147 :
8148 : /************************************************************************/
8149 : /* IsLayerPrivate() */
8150 : /************************************************************************/
8151 :
8152 : /**
8153 : \fn GDALDataset::IsLayerPrivate(int)
8154 : \brief Returns true if the layer at the specified index is deemed a private or
8155 : system table, or an internal detail only.
8156 :
8157 : This method is the same as the C function GDALDatasetIsLayerPrivate().
8158 :
8159 : @param iLayer a layer number between 0 and GetLayerCount()-1.
8160 :
8161 : @return true if the layer is a private or system table.
8162 :
8163 : @since GDAL 3.4
8164 : */
8165 :
8166 1008 : bool GDALDataset::IsLayerPrivate(CPL_UNUSED int iLayer) const
8167 : {
8168 1008 : return false;
8169 : }
8170 :
8171 : /************************************************************************/
8172 : /* ResetReading() */
8173 : /************************************************************************/
8174 :
8175 : /**
8176 : \brief Reset feature reading to start on the first feature.
8177 :
8178 : This affects GetNextFeature().
8179 :
8180 : Depending on drivers, this may also have the side effect of calling
8181 : OGRLayer::ResetReading() on the layers of this dataset.
8182 :
8183 : This method is the same as the C function GDALDatasetResetReading().
8184 :
8185 : */
8186 7 : void GDALDataset::ResetReading()
8187 : {
8188 7 : if (!m_poPrivate)
8189 0 : return;
8190 7 : m_poPrivate->nCurrentLayerIdx = 0;
8191 7 : m_poPrivate->nLayerCount = -1;
8192 7 : m_poPrivate->poCurrentLayer = nullptr;
8193 7 : m_poPrivate->nFeatureReadInLayer = 0;
8194 7 : m_poPrivate->nFeatureReadInDataset = 0;
8195 7 : m_poPrivate->nTotalFeaturesInLayer = TOTAL_FEATURES_NOT_INIT;
8196 7 : m_poPrivate->nTotalFeatures = TOTAL_FEATURES_NOT_INIT;
8197 : }
8198 :
8199 : /************************************************************************/
8200 : /* GDALDatasetResetReading() */
8201 : /************************************************************************/
8202 :
8203 : /**
8204 : \brief Reset feature reading to start on the first feature.
8205 :
8206 : This affects GDALDatasetGetNextFeature().
8207 :
8208 : Depending on drivers, this may also have the side effect of calling
8209 : OGR_L_ResetReading() on the layers of this dataset.
8210 :
8211 : This method is the same as the C++ method GDALDataset::ResetReading()
8212 :
8213 : @param hDS dataset handle
8214 : */
8215 14 : void CPL_DLL GDALDatasetResetReading(GDALDatasetH hDS)
8216 : {
8217 14 : VALIDATE_POINTER0(hDS, "GDALDatasetResetReading");
8218 :
8219 14 : return GDALDataset::FromHandle(hDS)->ResetReading();
8220 : }
8221 :
8222 : /************************************************************************/
8223 : /* GetNextFeature() */
8224 : /************************************************************************/
8225 :
8226 : /**
8227 : \brief Fetch the next available feature from this dataset.
8228 :
8229 : This method is intended for the few drivers where OGRLayer::GetNextFeature()
8230 : is not efficient, but in general OGRLayer::GetNextFeature() is a more
8231 : natural API.
8232 :
8233 : See GetFeatures() for a C++ iterator version of this method.
8234 :
8235 : The returned feature becomes the responsibility of the caller to
8236 : delete with OGRFeature::DestroyFeature().
8237 :
8238 : Depending on the driver, this method may return features from layers in a
8239 : non sequential way. This is what may happen when the
8240 : ODsCRandomLayerRead capability is declared (for example for the
8241 : OSM and GMLAS drivers). When datasets declare this capability, it is strongly
8242 : advised to use GDALDataset::GetNextFeature() instead of
8243 : OGRLayer::GetNextFeature(), as the later might have a slow, incomplete or stub
8244 : implementation.
8245 :
8246 : The default implementation, used by most drivers, will
8247 : however iterate over each layer, and then over each feature within this
8248 : layer.
8249 :
8250 : This method takes into account spatial and attribute filters set on layers that
8251 : will be iterated upon.
8252 :
8253 : The ResetReading() method can be used to start at the beginning again.
8254 :
8255 : Depending on drivers, this may also have the side effect of calling
8256 : OGRLayer::GetNextFeature() on the layers of this dataset.
8257 :
8258 : This method is the same as the C function GDALDatasetGetNextFeature().
8259 :
8260 : @param ppoBelongingLayer a pointer to a OGRLayer* variable to receive the
8261 : layer to which the object belongs to, or NULL.
8262 : It is possible that the output of *ppoBelongingLayer
8263 : to be NULL despite the feature not being NULL.
8264 : @param pdfProgressPct a pointer to a double variable to receive the
8265 : percentage progress (in [0,1] range), or NULL.
8266 : On return, the pointed value might be negative if
8267 : determining the progress is not possible.
8268 : @param pfnProgress a progress callback to report progress (for
8269 : GetNextFeature() calls that might have a long
8270 : duration) and offer cancellation possibility, or NULL.
8271 : @param pProgressData user data provided to pfnProgress, or NULL
8272 : @return a feature, or NULL if no more features are available.
8273 : @see GetFeatures()
8274 : */
8275 :
8276 68 : OGRFeature *GDALDataset::GetNextFeature(OGRLayer **ppoBelongingLayer,
8277 : double *pdfProgressPct,
8278 : GDALProgressFunc pfnProgress,
8279 : void *pProgressData)
8280 : {
8281 68 : if (!m_poPrivate || m_poPrivate->nCurrentLayerIdx < 0)
8282 : {
8283 2 : if (ppoBelongingLayer != nullptr)
8284 2 : *ppoBelongingLayer = nullptr;
8285 2 : if (pdfProgressPct != nullptr)
8286 1 : *pdfProgressPct = 1.0;
8287 2 : if (pfnProgress != nullptr)
8288 0 : pfnProgress(1.0, "", pProgressData);
8289 2 : return nullptr;
8290 : }
8291 :
8292 66 : if (m_poPrivate->poCurrentLayer == nullptr &&
8293 11 : (pdfProgressPct != nullptr || pfnProgress != nullptr))
8294 : {
8295 4 : if (m_poPrivate->nLayerCount < 0)
8296 : {
8297 4 : m_poPrivate->nLayerCount = GetLayerCount();
8298 : }
8299 :
8300 4 : if (m_poPrivate->nTotalFeatures == TOTAL_FEATURES_NOT_INIT)
8301 : {
8302 4 : m_poPrivate->nTotalFeatures = 0;
8303 8 : for (int i = 0; i < m_poPrivate->nLayerCount; i++)
8304 : {
8305 7 : OGRLayer *poLayer = GetLayer(i);
8306 14 : if (poLayer == nullptr ||
8307 7 : !poLayer->TestCapability(OLCFastFeatureCount))
8308 : {
8309 3 : m_poPrivate->nTotalFeatures = TOTAL_FEATURES_UNKNOWN;
8310 3 : break;
8311 : }
8312 4 : GIntBig nCount = poLayer->GetFeatureCount(FALSE);
8313 4 : if (nCount < 0)
8314 : {
8315 0 : m_poPrivate->nTotalFeatures = TOTAL_FEATURES_UNKNOWN;
8316 0 : break;
8317 : }
8318 4 : m_poPrivate->nTotalFeatures += nCount;
8319 : }
8320 : }
8321 : }
8322 :
8323 : while (true)
8324 : {
8325 82 : if (m_poPrivate->poCurrentLayer == nullptr)
8326 : {
8327 56 : m_poPrivate->poCurrentLayer =
8328 28 : GetLayer(m_poPrivate->nCurrentLayerIdx);
8329 28 : if (m_poPrivate->poCurrentLayer == nullptr)
8330 : {
8331 10 : m_poPrivate->nCurrentLayerIdx = -1;
8332 10 : if (ppoBelongingLayer != nullptr)
8333 7 : *ppoBelongingLayer = nullptr;
8334 10 : if (pdfProgressPct != nullptr)
8335 1 : *pdfProgressPct = 1.0;
8336 10 : return nullptr;
8337 : }
8338 18 : m_poPrivate->poCurrentLayer->ResetReading();
8339 18 : m_poPrivate->nFeatureReadInLayer = 0;
8340 18 : if (m_poPrivate->nTotalFeatures < 0 && pdfProgressPct != nullptr)
8341 : {
8342 0 : if (m_poPrivate->poCurrentLayer->TestCapability(
8343 0 : OLCFastFeatureCount))
8344 0 : m_poPrivate->nTotalFeaturesInLayer =
8345 0 : m_poPrivate->poCurrentLayer->GetFeatureCount(FALSE);
8346 : else
8347 0 : m_poPrivate->nTotalFeaturesInLayer = 0;
8348 : }
8349 : }
8350 72 : OGRFeature *poFeature = m_poPrivate->poCurrentLayer->GetNextFeature();
8351 72 : if (poFeature == nullptr)
8352 : {
8353 16 : m_poPrivate->nCurrentLayerIdx++;
8354 16 : m_poPrivate->poCurrentLayer = nullptr;
8355 16 : continue;
8356 : }
8357 :
8358 56 : m_poPrivate->nFeatureReadInLayer++;
8359 56 : m_poPrivate->nFeatureReadInDataset++;
8360 56 : if (pdfProgressPct != nullptr || pfnProgress != nullptr)
8361 : {
8362 9 : double dfPct = 0.0;
8363 9 : if (m_poPrivate->nTotalFeatures > 0)
8364 : {
8365 4 : dfPct = 1.0 * m_poPrivate->nFeatureReadInDataset /
8366 4 : m_poPrivate->nTotalFeatures;
8367 : }
8368 : else
8369 : {
8370 5 : dfPct = 1.0 * m_poPrivate->nCurrentLayerIdx /
8371 5 : m_poPrivate->nLayerCount;
8372 5 : if (m_poPrivate->nTotalFeaturesInLayer > 0)
8373 : {
8374 0 : dfPct += 1.0 * m_poPrivate->nFeatureReadInLayer /
8375 0 : m_poPrivate->nTotalFeaturesInLayer /
8376 0 : m_poPrivate->nLayerCount;
8377 : }
8378 : }
8379 9 : if (pdfProgressPct)
8380 4 : *pdfProgressPct = dfPct;
8381 9 : if (pfnProgress)
8382 5 : pfnProgress(dfPct, "", nullptr);
8383 : }
8384 :
8385 56 : if (ppoBelongingLayer != nullptr)
8386 51 : *ppoBelongingLayer = m_poPrivate->poCurrentLayer;
8387 56 : return poFeature;
8388 16 : }
8389 : }
8390 :
8391 : /************************************************************************/
8392 : /* GDALDatasetGetNextFeature() */
8393 : /************************************************************************/
8394 : /**
8395 : \brief Fetch the next available feature from this dataset.
8396 :
8397 : This method is intended for the few drivers where OGR_L_GetNextFeature()
8398 : is not efficient, but in general OGR_L_GetNextFeature() is a more
8399 : natural API.
8400 :
8401 : The returned feature becomes the responsibility of the caller to
8402 : delete with OGRFeature::DestroyFeature().
8403 :
8404 : Depending on the driver, this method may return features from layers in a
8405 : non sequential way. This is what may happen when the
8406 : ODsCRandomLayerRead capability is declared (for example for the
8407 : OSM and GMLAS drivers). When datasets declare this capability, it is strongly
8408 : advised to use GDALDataset::GetNextFeature() instead of
8409 : OGRLayer::GetNextFeature(), as the later might have a slow, incomplete or stub
8410 : implementation.
8411 :
8412 : The default implementation, used by most drivers, will
8413 : however iterate over each layer, and then over each feature within this
8414 : layer.
8415 :
8416 : This method takes into account spatial and attribute filters set on layers that
8417 : will be iterated upon.
8418 :
8419 : The ResetReading() method can be used to start at the beginning again.
8420 :
8421 : Depending on drivers, this may also have the side effect of calling
8422 : OGRLayer::GetNextFeature() on the layers of this dataset.
8423 :
8424 : This method is the same as the C++ method GDALDataset::GetNextFeature()
8425 :
8426 : @param hDS dataset handle.
8427 : @param phBelongingLayer a pointer to a OGRLayer* variable to receive the
8428 : layer to which the object belongs to, or NULL.
8429 : It is possible that the output of *ppoBelongingLayer
8430 : to be NULL despite the feature not being NULL.
8431 : @param pdfProgressPct a pointer to a double variable to receive the
8432 : percentage progress (in [0,1] range), or NULL.
8433 : On return, the pointed value might be negative if
8434 : determining the progress is not possible.
8435 : @param pfnProgress a progress callback to report progress (for
8436 : GetNextFeature() calls that might have a long
8437 : duration) and offer cancellation possibility, or NULL
8438 : @param pProgressData user data provided to pfnProgress, or NULL
8439 : @return a feature, or NULL if no more features are available.
8440 : */
8441 1917 : OGRFeatureH CPL_DLL GDALDatasetGetNextFeature(GDALDatasetH hDS,
8442 : OGRLayerH *phBelongingLayer,
8443 : double *pdfProgressPct,
8444 : GDALProgressFunc pfnProgress,
8445 : void *pProgressData)
8446 : {
8447 1917 : VALIDATE_POINTER1(hDS, "GDALDatasetGetNextFeature", nullptr);
8448 :
8449 3834 : return OGRFeature::ToHandle(GDALDataset::FromHandle(hDS)->GetNextFeature(
8450 : reinterpret_cast<OGRLayer **>(phBelongingLayer), pdfProgressPct,
8451 3834 : pfnProgress, pProgressData));
8452 : }
8453 :
8454 : /************************************************************************/
8455 : /* TestCapability() */
8456 : /************************************************************************/
8457 :
8458 : /**
8459 : \fn GDALDataset::TestCapability( const char * pszCap )
8460 : \brief Test if capability is available.
8461 :
8462 : One of the following dataset capability names can be passed into this
8463 : method, and a TRUE or FALSE value will be returned indicating whether or not
8464 : the capability is available for this object.
8465 :
8466 : <ul>
8467 : <li> <b>ODsCCreateLayer</b>: True if this datasource can create new layers.<p>
8468 : <li> <b>ODsCDeleteLayer</b>: True if this datasource can delete existing
8469 : layers.<p>
8470 : <li> <b>ODsCCreateGeomFieldAfterCreateLayer</b>: True if the layers of this
8471 : datasource support CreateGeomField() just after layer creation.<p>
8472 : <li> <b>ODsCCurveGeometries</b>: True if this datasource supports curve
8473 : geometries.<p>
8474 : <li> <b>ODsCTransactions</b>: True if this datasource supports (efficient)
8475 : transactions.<p>
8476 : <li> <b>ODsCEmulatedTransactions</b>: True if this datasource supports
8477 : transactions through emulation.<p>
8478 : <li> <b>ODsCRandomLayerRead</b>: True if this datasource has a dedicated
8479 : GetNextFeature() implementation, potentially returning features from
8480 : layers in a non sequential way.<p>
8481 : <li> <b>ODsCRandomLayerWrite</b>: True if this datasource supports calling
8482 : CreateFeature() on layers in a non sequential way.<p>
8483 : <li> <b>GDsCAddRelationship</b>: True if AddRelationship() is supported</li>
8484 : <li> <b>GDsCDeleteRelationship</b>: True if DeleteRelationship() is supported</li>
8485 : <li> <b>GDsCUpdateRelationship</b>: True if UpdateRelationship() is supported</li>
8486 : <li> <b>GDsCFastGetExtent</b>: True if GetExtent() is fast</li>
8487 : <li> <b>GDsCFastGetExtentWGS84LongLat</b>: True if GetExtentWGS84LongLat() is fast</li>
8488 : </ul>
8489 :
8490 : The \#define macro forms of the capability names should be used in preference
8491 : to the strings themselves to avoid misspelling.
8492 :
8493 : This method is the same as the C function GDALDatasetTestCapability() and the
8494 : deprecated OGR_DS_TestCapability().
8495 :
8496 : @param pszCap the capability to test.
8497 :
8498 : @return TRUE if capability available otherwise FALSE.
8499 : */
8500 :
8501 796 : int GDALDataset::TestCapability(const char *pszCap) const
8502 : {
8503 796 : if (EQUAL(pszCap, GDsCFastGetExtent) ||
8504 794 : EQUAL(pszCap, GDsCFastGetExtentWGS84LongLat))
8505 : {
8506 4 : for (auto &&poLayer : GetLayers())
8507 : {
8508 2 : if (!poLayer->TestCapability(OLCFastGetExtent))
8509 2 : return FALSE;
8510 : }
8511 2 : return TRUE;
8512 : }
8513 792 : return FALSE;
8514 : }
8515 :
8516 : /************************************************************************/
8517 : /* GDALDatasetTestCapability() */
8518 : /************************************************************************/
8519 :
8520 : /**
8521 : \brief Test if capability is available.
8522 :
8523 : One of the following dataset capability names can be passed into this
8524 : function, and a TRUE or FALSE value will be returned indicating whether or not
8525 : the capability is available for this object.
8526 :
8527 : <ul>
8528 : <li> <b>ODsCCreateLayer</b>: True if this datasource can create new layers.<p>
8529 : <li> <b>ODsCDeleteLayer</b>: True if this datasource can delete existing
8530 : layers.<p>
8531 : <li> <b>ODsCCreateGeomFieldAfterCreateLayer</b>: True if the layers of this
8532 : datasource support CreateGeomField() just after layer creation.<p>
8533 : <li> <b>ODsCCurveGeometries</b>: True if this datasource supports curve
8534 : geometries.<p>
8535 : <li> <b>ODsCTransactions</b>: True if this datasource supports (efficient)
8536 : transactions.<p>
8537 : <li> <b>ODsCEmulatedTransactions</b>: True if this datasource supports
8538 : transactions through emulation.<p>
8539 : <li> <b>ODsCRandomLayerRead</b>: True if this datasource has a dedicated
8540 : GetNextFeature() implementation, potentially returning features from
8541 : layers in a non sequential way.<p>
8542 : <li> <b>ODsCRandomLayerWrite</b>: True if this datasource supports calling
8543 : CreateFeature() on layers in a non sequential way.<p>
8544 : <li> <b>GDsCAddRelationship</b>: True if AddRelationship() is supported</li>
8545 : <li> <b>GDsCDeleteRelationship</b>: True if DeleteRelationship() is supported</li>
8546 : <li> <b>GDsCUpdateRelationship</b>: True if UpdateRelationship() is supported</li>
8547 : <li> <b>GDsCFastGetExtent</b>: True if GetExtent() is fast</li>
8548 : <li> <b>GDsCFastGetExtentWGS84LongLat</b>: True if GetExtentWGS84LongLat() is fast</li>
8549 : </ul>
8550 :
8551 : The \#define macro forms of the capability names should be used in preference
8552 : to the strings themselves to avoid misspelling.
8553 :
8554 : This function is the same as the C++ method GDALDataset::TestCapability()
8555 :
8556 :
8557 : @param hDS the dataset handle.
8558 : @param pszCap the capability to test.
8559 :
8560 : @return TRUE if capability available otherwise FALSE.
8561 : */
8562 130 : int GDALDatasetTestCapability(GDALDatasetH hDS, const char *pszCap)
8563 :
8564 : {
8565 130 : VALIDATE_POINTER1(hDS, "GDALDatasetTestCapability", 0);
8566 130 : VALIDATE_POINTER1(pszCap, "GDALDatasetTestCapability", 0);
8567 :
8568 130 : return GDALDataset::FromHandle(hDS)->TestCapability(pszCap);
8569 : }
8570 :
8571 : /************************************************************************/
8572 : /* StartTransaction() */
8573 : /************************************************************************/
8574 :
8575 : /**
8576 : \fn GDALDataset::StartTransaction(int)
8577 : \brief For datasources which support transactions, StartTransaction creates a
8578 : `transaction.
8579 :
8580 : If starting the transaction fails, will return
8581 : OGRERR_FAILURE. Datasources which do not support transactions will
8582 : always return OGRERR_UNSUPPORTED_OPERATION.
8583 :
8584 : Nested transactions are not supported.
8585 :
8586 : All changes done after the start of the transaction are definitely applied in
8587 : the datasource if CommitTransaction() is called. They may be canceled by
8588 : calling RollbackTransaction() instead.
8589 :
8590 : At the time of writing, transactions only apply on vector layers.
8591 :
8592 : Datasets that support transactions will advertise the ODsCTransactions
8593 : capability. Use of transactions at dataset level is generally preferred to
8594 : transactions at layer level, whose scope is rarely limited to the layer from
8595 : which it was started.
8596 :
8597 : In case StartTransaction() fails, neither CommitTransaction() or
8598 : RollbackTransaction() should be called.
8599 :
8600 : If an error occurs after a successful StartTransaction(), the whole transaction
8601 : may or may not be implicitly canceled, depending on drivers. (e.g. the PG
8602 : driver will cancel it, SQLite/GPKG not). In any case, in the event of an error,
8603 : an explicit call to RollbackTransaction() should be done to keep things
8604 : balanced.
8605 :
8606 : By default, when bForce is set to FALSE, only "efficient" transactions will be
8607 : attempted. Some drivers may offer an emulation of transactions, but sometimes
8608 : with significant overhead, in which case the user must explicitly allow for
8609 : such an emulation by setting bForce to TRUE. Drivers that offer emulated
8610 : transactions should advertise the ODsCEmulatedTransactions capability (and not
8611 : ODsCTransactions).
8612 :
8613 : This function is the same as the C function GDALDatasetStartTransaction().
8614 :
8615 : @param bForce can be set to TRUE if an emulation, possibly slow, of a
8616 : transaction
8617 : mechanism is acceptable.
8618 :
8619 : @return OGRERR_NONE on success.
8620 : */
8621 :
8622 37 : OGRErr GDALDataset::StartTransaction(CPL_UNUSED int bForce)
8623 : {
8624 37 : return OGRERR_UNSUPPORTED_OPERATION;
8625 : }
8626 :
8627 : /************************************************************************/
8628 : /* GDALDatasetStartTransaction() */
8629 : /************************************************************************/
8630 :
8631 : /**
8632 : \brief For datasources which support transactions, StartTransaction creates a
8633 : transaction.
8634 :
8635 : If starting the transaction fails, will return
8636 : OGRERR_FAILURE. Datasources which do not support transactions will
8637 : always return OGRERR_UNSUPPORTED_OPERATION.
8638 :
8639 : Nested transactions are not supported.
8640 :
8641 : All changes done after the start of the transaction are definitely applied in
8642 : the datasource if CommitTransaction() is called. They may be canceled by
8643 : calling RollbackTransaction() instead.
8644 :
8645 : At the time of writing, transactions only apply on vector layers.
8646 :
8647 : Datasets that support transactions will advertise the ODsCTransactions
8648 : capability.
8649 : Use of transactions at dataset level is generally preferred to transactions at
8650 : layer level, whose scope is rarely limited to the layer from which it was
8651 : started.
8652 :
8653 : In case StartTransaction() fails, neither CommitTransaction() or
8654 : RollbackTransaction() should be called.
8655 :
8656 : If an error occurs after a successful StartTransaction(), the whole
8657 : transaction may or may not be implicitly canceled, depending on drivers. (e.g.
8658 : the PG driver will cancel it, SQLite/GPKG not). In any case, in the event of an
8659 : error, an explicit call to RollbackTransaction() should be done to keep things
8660 : balanced.
8661 :
8662 : By default, when bForce is set to FALSE, only "efficient" transactions will be
8663 : attempted. Some drivers may offer an emulation of transactions, but sometimes
8664 : with significant overhead, in which case the user must explicitly allow for
8665 : such an emulation by setting bForce to TRUE. Drivers that offer emulated
8666 : transactions should advertise the ODsCEmulatedTransactions capability (and not
8667 : ODsCTransactions).
8668 :
8669 : This function is the same as the C++ method GDALDataset::StartTransaction()
8670 :
8671 : @param hDS the dataset handle.
8672 : @param bForce can be set to TRUE if an emulation, possibly slow, of a
8673 : transaction
8674 : mechanism is acceptable.
8675 :
8676 : @return OGRERR_NONE on success.
8677 : */
8678 106 : OGRErr GDALDatasetStartTransaction(GDALDatasetH hDS, int bForce)
8679 : {
8680 106 : VALIDATE_POINTER1(hDS, "GDALDatasetStartTransaction",
8681 : OGRERR_INVALID_HANDLE);
8682 :
8683 : #ifdef OGRAPISPY_ENABLED
8684 106 : if (bOGRAPISpyEnabled)
8685 2 : OGRAPISpy_Dataset_StartTransaction(hDS, bForce);
8686 : #endif
8687 :
8688 106 : return GDALDataset::FromHandle(hDS)->StartTransaction(bForce);
8689 : }
8690 :
8691 : /************************************************************************/
8692 : /* CommitTransaction() */
8693 : /************************************************************************/
8694 :
8695 : /**
8696 : \brief For datasources which support transactions, CommitTransaction commits a
8697 : transaction.
8698 :
8699 : If no transaction is active, or the commit fails, will return
8700 : OGRERR_FAILURE. Datasources which do not support transactions will
8701 : always return OGRERR_UNSUPPORTED_OPERATION.
8702 :
8703 : Depending on drivers, this may or may not abort layer sequential readings that
8704 : are active.
8705 :
8706 : This function is the same as the C function GDALDatasetCommitTransaction().
8707 :
8708 : @return OGRERR_NONE on success.
8709 : */
8710 52 : OGRErr GDALDataset::CommitTransaction()
8711 : {
8712 52 : return OGRERR_UNSUPPORTED_OPERATION;
8713 : }
8714 :
8715 : /************************************************************************/
8716 : /* GDALDatasetCommitTransaction() */
8717 : /************************************************************************/
8718 :
8719 : /**
8720 : \brief For datasources which support transactions, CommitTransaction commits a
8721 : transaction.
8722 :
8723 : If no transaction is active, or the commit fails, will return
8724 : OGRERR_FAILURE. Datasources which do not support transactions will
8725 : always return OGRERR_UNSUPPORTED_OPERATION.
8726 :
8727 : Depending on drivers, this may or may not abort layer sequential readings that
8728 : are active.
8729 :
8730 : This function is the same as the C++ method GDALDataset::CommitTransaction()
8731 :
8732 : @return OGRERR_NONE on success.
8733 : */
8734 77 : OGRErr GDALDatasetCommitTransaction(GDALDatasetH hDS)
8735 : {
8736 77 : VALIDATE_POINTER1(hDS, "GDALDatasetCommitTransaction",
8737 : OGRERR_INVALID_HANDLE);
8738 :
8739 : #ifdef OGRAPISPY_ENABLED
8740 77 : if (bOGRAPISpyEnabled)
8741 2 : OGRAPISpy_Dataset_CommitTransaction(hDS);
8742 : #endif
8743 :
8744 77 : return GDALDataset::FromHandle(hDS)->CommitTransaction();
8745 : }
8746 :
8747 : /************************************************************************/
8748 : /* RollbackTransaction() */
8749 : /************************************************************************/
8750 :
8751 : /**
8752 : \brief For datasources which support transactions, RollbackTransaction will
8753 : roll back a datasource to its state before the start of the current
8754 : transaction.
8755 : If no transaction is active, or the rollback fails, will return
8756 : OGRERR_FAILURE. Datasources which do not support transactions will
8757 : always return OGRERR_UNSUPPORTED_OPERATION.
8758 :
8759 : This function is the same as the C function GDALDatasetRollbackTransaction().
8760 :
8761 : @return OGRERR_NONE on success.
8762 : */
8763 2 : OGRErr GDALDataset::RollbackTransaction()
8764 : {
8765 2 : return OGRERR_UNSUPPORTED_OPERATION;
8766 : }
8767 :
8768 : /************************************************************************/
8769 : /* GDALDatasetRollbackTransaction() */
8770 : /************************************************************************/
8771 :
8772 : /**
8773 : \brief For datasources which support transactions, RollbackTransaction will
8774 : roll back a datasource to its state before the start of the current
8775 : transaction.
8776 : If no transaction is active, or the rollback fails, will return
8777 : OGRERR_FAILURE. Datasources which do not support transactions will
8778 : always return OGRERR_UNSUPPORTED_OPERATION.
8779 :
8780 : This function is the same as the C++ method GDALDataset::RollbackTransaction().
8781 :
8782 : @return OGRERR_NONE on success.
8783 : */
8784 44 : OGRErr GDALDatasetRollbackTransaction(GDALDatasetH hDS)
8785 : {
8786 44 : VALIDATE_POINTER1(hDS, "GDALDatasetRollbackTransaction",
8787 : OGRERR_INVALID_HANDLE);
8788 :
8789 : #ifdef OGRAPISPY_ENABLED
8790 44 : if (bOGRAPISpyEnabled)
8791 2 : OGRAPISpy_Dataset_RollbackTransaction(hDS);
8792 : #endif
8793 :
8794 44 : return GDALDataset::FromHandle(hDS)->RollbackTransaction();
8795 : }
8796 :
8797 : //! @cond Doxygen_Suppress
8798 :
8799 : /************************************************************************/
8800 : /* ShareLockWithParentDataset() */
8801 : /************************************************************************/
8802 :
8803 : /* To be used typically by the GTiff driver to link overview datasets */
8804 : /* with their main dataset, so that they share the same lock */
8805 : /* Cf https://github.com/OSGeo/gdal/issues/1488 */
8806 : /* The parent dataset should remain alive while the this dataset is alive */
8807 :
8808 2340 : void GDALDataset::ShareLockWithParentDataset(GDALDataset *poParentDataset)
8809 : {
8810 2340 : if (m_poPrivate != nullptr)
8811 : {
8812 2340 : m_poPrivate->poParentDataset = poParentDataset;
8813 : }
8814 2340 : }
8815 :
8816 : /************************************************************************/
8817 : /* SetQueryLoggerFunc() */
8818 : /************************************************************************/
8819 :
8820 0 : bool GDALDataset::SetQueryLoggerFunc(CPL_UNUSED GDALQueryLoggerFunc callback,
8821 : CPL_UNUSED void *context)
8822 : {
8823 0 : return false;
8824 : }
8825 :
8826 : /************************************************************************/
8827 : /* EnterReadWrite() */
8828 : /************************************************************************/
8829 :
8830 8270090 : int GDALDataset::EnterReadWrite(GDALRWFlag eRWFlag)
8831 : {
8832 16540200 : if (m_poPrivate == nullptr ||
8833 8270090 : IsThreadSafe(GDAL_OF_RASTER | (nOpenFlags & GDAL_OF_UPDATE)))
8834 11992 : return FALSE;
8835 :
8836 8258100 : if (m_poPrivate->poParentDataset)
8837 242627 : return m_poPrivate->poParentDataset->EnterReadWrite(eRWFlag);
8838 :
8839 8015470 : if (eAccess == GA_Update)
8840 : {
8841 2411260 : if (m_poPrivate->eStateReadWriteMutex ==
8842 : GDALAllowReadWriteMutexState::RW_MUTEX_STATE_UNKNOWN)
8843 : {
8844 : // In case dead-lock would occur, which is not impossible,
8845 : // this can be used to prevent it, but at the risk of other
8846 : // issues.
8847 10920 : if (CPLTestBool(
8848 : CPLGetConfigOption("GDAL_ENABLE_READ_WRITE_MUTEX", "YES")))
8849 : {
8850 10920 : m_poPrivate->eStateReadWriteMutex =
8851 : GDALAllowReadWriteMutexState::RW_MUTEX_STATE_ALLOWED;
8852 : }
8853 : else
8854 : {
8855 0 : m_poPrivate->eStateReadWriteMutex =
8856 : GDALAllowReadWriteMutexState::RW_MUTEX_STATE_DISABLED;
8857 : }
8858 : }
8859 2411260 : if (m_poPrivate->eStateReadWriteMutex ==
8860 : GDALAllowReadWriteMutexState::RW_MUTEX_STATE_ALLOWED)
8861 : {
8862 : // There should be no race related to creating this mutex since
8863 : // it should be first created through IWriteBlock() / IRasterIO()
8864 : // and then GDALRasterBlock might call it from another thread.
8865 : #ifdef DEBUG_VERBOSE
8866 : CPLDebug("GDAL",
8867 : "[Thread " CPL_FRMT_GIB "] Acquiring RW mutex for %s",
8868 : CPLGetPID(), GetDescription());
8869 : #endif
8870 1559060 : CPLCreateOrAcquireMutex(&(m_poPrivate->hMutex), 1000.0);
8871 :
8872 : const int nCountMutex =
8873 1559060 : m_poPrivate->oMapThreadToMutexTakenCount[CPLGetPID()]++;
8874 1559060 : if (nCountMutex == 0 && eRWFlag == GF_Read)
8875 : {
8876 536311 : CPLReleaseMutex(m_poPrivate->hMutex);
8877 1710650 : for (int i = 0; i < nBands; i++)
8878 : {
8879 1174340 : auto blockCache = papoBands[i]->poBandBlockCache;
8880 1174340 : if (blockCache)
8881 823560 : blockCache->WaitCompletionPendingTasks();
8882 : }
8883 536311 : CPLCreateOrAcquireMutex(&(m_poPrivate->hMutex), 1000.0);
8884 : }
8885 :
8886 1559060 : return TRUE;
8887 : }
8888 : }
8889 6456410 : return FALSE;
8890 : }
8891 :
8892 : /************************************************************************/
8893 : /* LeaveReadWrite() */
8894 : /************************************************************************/
8895 :
8896 1788030 : void GDALDataset::LeaveReadWrite()
8897 : {
8898 1788030 : if (m_poPrivate)
8899 : {
8900 1788030 : if (m_poPrivate->poParentDataset)
8901 : {
8902 228964 : m_poPrivate->poParentDataset->LeaveReadWrite();
8903 228964 : return;
8904 : }
8905 :
8906 1559060 : m_poPrivate->oMapThreadToMutexTakenCount[CPLGetPID()]--;
8907 1559060 : CPLReleaseMutex(m_poPrivate->hMutex);
8908 : #ifdef DEBUG_VERBOSE
8909 : CPLDebug("GDAL", "[Thread " CPL_FRMT_GIB "] Releasing RW mutex for %s",
8910 : CPLGetPID(), GetDescription());
8911 : #endif
8912 : }
8913 : }
8914 :
8915 : /************************************************************************/
8916 : /* InitRWLock() */
8917 : /************************************************************************/
8918 :
8919 3997210 : void GDALDataset::InitRWLock()
8920 : {
8921 3997210 : if (m_poPrivate)
8922 : {
8923 3997210 : if (m_poPrivate->poParentDataset)
8924 : {
8925 8584 : m_poPrivate->poParentDataset->InitRWLock();
8926 8584 : return;
8927 : }
8928 :
8929 3988630 : if (m_poPrivate->eStateReadWriteMutex ==
8930 : GDALAllowReadWriteMutexState::RW_MUTEX_STATE_UNKNOWN)
8931 : {
8932 1 : if (EnterReadWrite(GF_Write))
8933 1 : LeaveReadWrite();
8934 : }
8935 : }
8936 : }
8937 :
8938 : /************************************************************************/
8939 : /* DisableReadWriteMutex() */
8940 : /************************************************************************/
8941 :
8942 : // The mutex logic is broken in multi-threaded situations, for example
8943 : // with 2 WarpedVRT datasets being read at the same time. In that
8944 : // particular case, the mutex is not needed, so allow the VRTWarpedDataset code
8945 : // to disable it.
8946 32847 : void GDALDataset::DisableReadWriteMutex()
8947 : {
8948 32847 : if (m_poPrivate)
8949 : {
8950 32847 : if (m_poPrivate->poParentDataset)
8951 : {
8952 0 : m_poPrivate->poParentDataset->DisableReadWriteMutex();
8953 0 : return;
8954 : }
8955 :
8956 32847 : m_poPrivate->eStateReadWriteMutex =
8957 : GDALAllowReadWriteMutexState::RW_MUTEX_STATE_DISABLED;
8958 : }
8959 : }
8960 :
8961 : /************************************************************************/
8962 : /* TemporarilyDropReadWriteLock() */
8963 : /************************************************************************/
8964 :
8965 3424570 : void GDALDataset::TemporarilyDropReadWriteLock()
8966 : {
8967 3424570 : if (m_poPrivate == nullptr)
8968 0 : return;
8969 :
8970 3424570 : if (m_poPrivate->poParentDataset)
8971 : {
8972 26347 : m_poPrivate->poParentDataset->TemporarilyDropReadWriteLock();
8973 26347 : return;
8974 : }
8975 :
8976 : #ifndef __COVERITY__
8977 3398220 : if (m_poPrivate->hMutex)
8978 : {
8979 : #ifdef DEBUG_VERBOSE
8980 : CPLDebug("GDAL",
8981 : "[Thread " CPL_FRMT_GIB "] "
8982 : "Temporarily drop RW mutex for %s",
8983 : CPLGetPID(), GetDescription());
8984 : #endif
8985 422708 : CPLAcquireMutex(m_poPrivate->hMutex, 1000.0);
8986 : const int nCount =
8987 422708 : m_poPrivate->oMapThreadToMutexTakenCount[CPLGetPID()];
8988 : #ifdef DEBUG_EXTRA
8989 : m_poPrivate->oMapThreadToMutexTakenCountSaved[CPLGetPID()] = nCount;
8990 : #endif
8991 1275800 : for (int i = 0; i < nCount + 1; i++)
8992 : {
8993 : // The mutex is recursive
8994 853092 : CPLReleaseMutex(m_poPrivate->hMutex);
8995 : }
8996 : }
8997 : #endif
8998 : }
8999 :
9000 : /************************************************************************/
9001 : /* ReacquireReadWriteLock() */
9002 : /************************************************************************/
9003 :
9004 3424570 : void GDALDataset::ReacquireReadWriteLock()
9005 : {
9006 3424570 : if (m_poPrivate == nullptr)
9007 0 : return;
9008 :
9009 3424570 : if (m_poPrivate->poParentDataset)
9010 : {
9011 26347 : m_poPrivate->poParentDataset->ReacquireReadWriteLock();
9012 26347 : return;
9013 : }
9014 :
9015 : #ifndef __COVERITY__
9016 3398220 : if (m_poPrivate->hMutex)
9017 : {
9018 : #ifdef DEBUG_VERBOSE
9019 : CPLDebug("GDAL",
9020 : "[Thread " CPL_FRMT_GIB "] "
9021 : "Reacquire temporarily dropped RW mutex for %s",
9022 : CPLGetPID(), GetDescription());
9023 : #endif
9024 422709 : CPLAcquireMutex(m_poPrivate->hMutex, 1000.0);
9025 : const int nCount =
9026 422709 : m_poPrivate->oMapThreadToMutexTakenCount[CPLGetPID()];
9027 : #ifdef DEBUG_EXTRA
9028 : CPLAssert(nCount ==
9029 : m_poPrivate->oMapThreadToMutexTakenCountSaved[CPLGetPID()]);
9030 : #endif
9031 422709 : if (nCount == 0)
9032 18278 : CPLReleaseMutex(m_poPrivate->hMutex);
9033 448662 : for (int i = 0; i < nCount - 1; i++)
9034 : {
9035 : // The mutex is recursive
9036 25953 : CPLAcquireMutex(m_poPrivate->hMutex, 1000.0);
9037 : }
9038 : }
9039 : #endif
9040 : }
9041 :
9042 : /************************************************************************/
9043 : /* AcquireMutex() */
9044 : /************************************************************************/
9045 :
9046 196 : int GDALDataset::AcquireMutex()
9047 : {
9048 196 : if (m_poPrivate == nullptr)
9049 0 : return 0;
9050 196 : if (m_poPrivate->poParentDataset)
9051 : {
9052 0 : return m_poPrivate->poParentDataset->AcquireMutex();
9053 : }
9054 :
9055 196 : return CPLCreateOrAcquireMutex(&(m_poPrivate->hMutex), 1000.0);
9056 : }
9057 :
9058 : /************************************************************************/
9059 : /* ReleaseMutex() */
9060 : /************************************************************************/
9061 :
9062 196 : void GDALDataset::ReleaseMutex()
9063 : {
9064 196 : if (m_poPrivate)
9065 : {
9066 196 : if (m_poPrivate->poParentDataset)
9067 : {
9068 0 : m_poPrivate->poParentDataset->ReleaseMutex();
9069 0 : return;
9070 : }
9071 :
9072 196 : CPLReleaseMutex(m_poPrivate->hMutex);
9073 : }
9074 : }
9075 :
9076 : //! @endcond
9077 :
9078 : /************************************************************************/
9079 : /* GDALDataset::Features::Iterator::Private */
9080 : /************************************************************************/
9081 :
9082 : struct GDALDataset::Features::Iterator::Private
9083 : {
9084 : GDALDataset::FeatureLayerPair m_oPair{};
9085 : GDALDataset *m_poDS = nullptr;
9086 : bool m_bEOF = true;
9087 : };
9088 :
9089 4 : GDALDataset::Features::Iterator::Iterator(GDALDataset *poDS, bool bStart)
9090 4 : : m_poPrivate(new GDALDataset::Features::Iterator::Private())
9091 : {
9092 4 : m_poPrivate->m_poDS = poDS;
9093 4 : if (bStart)
9094 : {
9095 2 : poDS->ResetReading();
9096 4 : m_poPrivate->m_oPair.feature.reset(poDS->GetNextFeature(
9097 2 : &m_poPrivate->m_oPair.layer, nullptr, nullptr, nullptr));
9098 2 : m_poPrivate->m_bEOF = m_poPrivate->m_oPair.feature == nullptr;
9099 : }
9100 4 : }
9101 :
9102 : GDALDataset::Features::Iterator::~Iterator() = default;
9103 :
9104 : const GDALDataset::FeatureLayerPair &
9105 20 : GDALDataset::Features::Iterator::operator*() const
9106 : {
9107 20 : return m_poPrivate->m_oPair;
9108 : }
9109 :
9110 20 : GDALDataset::Features::Iterator &GDALDataset::Features::Iterator::operator++()
9111 : {
9112 40 : m_poPrivate->m_oPair.feature.reset(m_poPrivate->m_poDS->GetNextFeature(
9113 20 : &m_poPrivate->m_oPair.layer, nullptr, nullptr, nullptr));
9114 20 : m_poPrivate->m_bEOF = m_poPrivate->m_oPair.feature == nullptr;
9115 20 : return *this;
9116 : }
9117 :
9118 22 : bool GDALDataset::Features::Iterator::operator!=(const Iterator &it) const
9119 : {
9120 22 : return m_poPrivate->m_bEOF != it.m_poPrivate->m_bEOF;
9121 : }
9122 :
9123 : /************************************************************************/
9124 : /* GetFeatures() */
9125 : /************************************************************************/
9126 :
9127 : /** Function that return an iterable object over features in the dataset
9128 : * layer.
9129 : *
9130 : * This is a C++ iterator friendly version of GetNextFeature().
9131 : *
9132 : * Using this iterator for standard range-based loops is safe, but
9133 : * due to implementation limitations, you shouldn't try to access
9134 : * (dereference) more than one iterator step at a time, since the
9135 : * FeatureLayerPair reference which is returned is reused.
9136 : *
9137 : * Typical use is:
9138 : * \code{.cpp}
9139 : * for( auto&& oFeatureLayerPair: poDS->GetFeatures() )
9140 : * {
9141 : * std::cout << "Feature of layer " <<
9142 : * oFeatureLayerPair.layer->GetName() << std::endl;
9143 : * oFeatureLayerPair.feature->DumpReadable();
9144 : * }
9145 : * \endcode
9146 : *
9147 : * @see GetNextFeature()
9148 : *
9149 : */
9150 2 : GDALDataset::Features GDALDataset::GetFeatures()
9151 : {
9152 2 : return Features(this);
9153 : }
9154 :
9155 : /************************************************************************/
9156 : /* begin() */
9157 : /************************************************************************/
9158 :
9159 : /**
9160 : \brief Return beginning of feature iterator.
9161 :
9162 : */
9163 :
9164 2 : const GDALDataset::Features::Iterator GDALDataset::Features::begin() const
9165 : {
9166 2 : return {m_poSelf, true};
9167 : }
9168 :
9169 : /************************************************************************/
9170 : /* end() */
9171 : /************************************************************************/
9172 :
9173 : /**
9174 : \brief Return end of feature iterator.
9175 :
9176 : */
9177 :
9178 2 : const GDALDataset::Features::Iterator GDALDataset::Features::end() const
9179 : {
9180 2 : return {m_poSelf, false};
9181 : }
9182 :
9183 : /************************************************************************/
9184 : /* GDALDataset::Layers::Iterator::Private */
9185 : /************************************************************************/
9186 :
9187 : struct GDALDataset::Layers::Iterator::Private
9188 : {
9189 : OGRLayer *m_poLayer = nullptr;
9190 : int m_iCurLayer = 0;
9191 : int m_nLayerCount = 0;
9192 : GDALDataset *m_poDS = nullptr;
9193 : };
9194 :
9195 2 : GDALDataset::Layers::Iterator::Iterator() : m_poPrivate(new Private())
9196 : {
9197 2 : }
9198 :
9199 : // False positive of cppcheck 1.72
9200 : // cppcheck-suppress uninitMemberVar
9201 9 : GDALDataset::Layers::Iterator::Iterator(const Iterator &oOther)
9202 9 : : m_poPrivate(new Private(*(oOther.m_poPrivate)))
9203 : {
9204 9 : }
9205 :
9206 5 : GDALDataset::Layers::Iterator::Iterator(Iterator &&oOther) noexcept
9207 5 : : m_poPrivate(std::move(oOther.m_poPrivate))
9208 : {
9209 5 : }
9210 :
9211 106222 : GDALDataset::Layers::Iterator::Iterator(GDALDataset *poDS, bool bStart)
9212 106222 : : m_poPrivate(new Private())
9213 : {
9214 106222 : m_poPrivate->m_poDS = poDS;
9215 106222 : m_poPrivate->m_nLayerCount = poDS->GetLayerCount();
9216 106222 : if (bStart)
9217 : {
9218 53113 : if (m_poPrivate->m_nLayerCount)
9219 44760 : m_poPrivate->m_poLayer = poDS->GetLayer(0);
9220 : }
9221 : else
9222 : {
9223 53109 : m_poPrivate->m_iCurLayer = m_poPrivate->m_nLayerCount;
9224 : }
9225 106222 : }
9226 :
9227 : GDALDataset::Layers::Iterator::~Iterator() = default;
9228 :
9229 : // False positive of cppcheck 1.72
9230 : // cppcheck-suppress operatorEqVarError
9231 : GDALDataset::Layers::Iterator &
9232 1 : GDALDataset::Layers::Iterator::operator=(const Iterator &oOther)
9233 : {
9234 1 : *m_poPrivate = *oOther.m_poPrivate;
9235 1 : return *this;
9236 : }
9237 :
9238 3 : GDALDataset::Layers::Iterator &GDALDataset::Layers::Iterator::operator=(
9239 : GDALDataset::Layers::Iterator &&oOther) noexcept
9240 : {
9241 3 : m_poPrivate = std::move(oOther.m_poPrivate);
9242 3 : return *this;
9243 : }
9244 :
9245 1794830 : OGRLayer *GDALDataset::Layers::Iterator::operator*() const
9246 : {
9247 1794830 : return m_poPrivate->m_poLayer;
9248 : }
9249 :
9250 1782420 : GDALDataset::Layers::Iterator &GDALDataset::Layers::Iterator::operator++()
9251 : {
9252 1782420 : m_poPrivate->m_iCurLayer++;
9253 1782420 : if (m_poPrivate->m_iCurLayer < m_poPrivate->m_nLayerCount)
9254 : {
9255 1750080 : m_poPrivate->m_poLayer =
9256 1750080 : m_poPrivate->m_poDS->GetLayer(m_poPrivate->m_iCurLayer);
9257 : }
9258 : else
9259 : {
9260 32349 : m_poPrivate->m_poLayer = nullptr;
9261 : }
9262 1782420 : return *this;
9263 : }
9264 :
9265 2 : GDALDataset::Layers::Iterator GDALDataset::Layers::Iterator::operator++(int)
9266 : {
9267 2 : GDALDataset::Layers::Iterator temp = *this;
9268 2 : ++(*this);
9269 2 : return temp;
9270 : }
9271 :
9272 1835530 : bool GDALDataset::Layers::Iterator::operator!=(const Iterator &it) const
9273 : {
9274 1835530 : return m_poPrivate->m_iCurLayer != it.m_poPrivate->m_iCurLayer;
9275 : }
9276 :
9277 : /************************************************************************/
9278 : /* GetLayers() */
9279 : /************************************************************************/
9280 :
9281 : /** Function that returns an iterable object over layers in the dataset.
9282 : *
9283 : * This is a C++ iterator friendly version of GetLayer().
9284 : *
9285 : * Typical use is:
9286 : * \code{.cpp}
9287 : * for( auto&& poLayer: poDS->GetLayers() )
9288 : * {
9289 : * std::cout << "Layer << poLayer->GetName() << std::endl;
9290 : * }
9291 : * \endcode
9292 : *
9293 : * @see GetLayer()
9294 : *
9295 : */
9296 53114 : GDALDataset::Layers GDALDataset::GetLayers()
9297 : {
9298 53114 : return Layers(this);
9299 : }
9300 :
9301 : /************************************************************************/
9302 : /* begin() */
9303 : /************************************************************************/
9304 :
9305 : /**
9306 : \brief Return beginning of layer iterator.
9307 :
9308 : */
9309 :
9310 53113 : GDALDataset::Layers::Iterator GDALDataset::Layers::begin() const
9311 : {
9312 53113 : return {m_poSelf, true};
9313 : }
9314 :
9315 : /************************************************************************/
9316 : /* end() */
9317 : /************************************************************************/
9318 :
9319 : /**
9320 : \brief Return end of layer iterator.
9321 :
9322 : */
9323 :
9324 53109 : GDALDataset::Layers::Iterator GDALDataset::Layers::end() const
9325 : {
9326 53109 : return {m_poSelf, false};
9327 : }
9328 :
9329 : /************************************************************************/
9330 : /* size() */
9331 : /************************************************************************/
9332 :
9333 : /**
9334 : \brief Get the number of layers in this dataset.
9335 :
9336 : @return layer count.
9337 :
9338 : */
9339 :
9340 1 : size_t GDALDataset::Layers::size() const
9341 : {
9342 1 : return static_cast<size_t>(m_poSelf->GetLayerCount());
9343 : }
9344 :
9345 : /************************************************************************/
9346 : /* operator[]() */
9347 : /************************************************************************/
9348 : /**
9349 : \brief Fetch a layer by index.
9350 :
9351 : The returned layer remains owned by the
9352 : GDALDataset and should not be deleted by the application.
9353 :
9354 : @param iLayer a layer number between 0 and size()-1.
9355 :
9356 : @return the layer, or nullptr if iLayer is out of range or an error occurs.
9357 :
9358 : */
9359 :
9360 9 : OGRLayer *GDALDataset::Layers::operator[](int iLayer)
9361 : {
9362 9 : return m_poSelf->GetLayer(iLayer);
9363 : }
9364 :
9365 : /************************************************************************/
9366 : /* operator[]() */
9367 : /************************************************************************/
9368 : /**
9369 : \brief Fetch a layer by index.
9370 :
9371 : The returned layer remains owned by the
9372 : GDALDataset and should not be deleted by the application.
9373 :
9374 : @param iLayer a layer number between 0 and size()-1.
9375 :
9376 : @return the layer, or nullptr if iLayer is out of range or an error occurs.
9377 :
9378 : */
9379 :
9380 1 : OGRLayer *GDALDataset::Layers::operator[](size_t iLayer)
9381 : {
9382 1 : return m_poSelf->GetLayer(static_cast<int>(iLayer));
9383 : }
9384 :
9385 : /************************************************************************/
9386 : /* operator[]() */
9387 : /************************************************************************/
9388 : /**
9389 : \brief Fetch a layer by name.
9390 :
9391 : The returned layer remains owned by the
9392 : GDALDataset and should not be deleted by the application.
9393 :
9394 : @param pszLayerName layer name
9395 :
9396 : @return the layer, or nullptr if pszLayerName does not match with a layer
9397 :
9398 : */
9399 :
9400 1 : OGRLayer *GDALDataset::Layers::operator[](const char *pszLayerName)
9401 : {
9402 1 : return m_poSelf->GetLayerByName(pszLayerName);
9403 : }
9404 :
9405 : /************************************************************************/
9406 : /* GDALDataset::ConstLayers::Iterator::Private */
9407 : /************************************************************************/
9408 :
9409 : struct GDALDataset::ConstLayers::Iterator::Private
9410 : {
9411 : const OGRLayer *m_poLayer = nullptr;
9412 : int m_iCurLayer = 0;
9413 : int m_nLayerCount = 0;
9414 : const GDALDataset *m_poDS = nullptr;
9415 : };
9416 :
9417 2 : GDALDataset::ConstLayers::Iterator::Iterator() : m_poPrivate(new Private())
9418 : {
9419 2 : }
9420 :
9421 : // False positive of cppcheck 1.72
9422 : // cppcheck-suppress uninitMemberVar
9423 9 : GDALDataset::ConstLayers::Iterator::Iterator(const Iterator &oOther)
9424 9 : : m_poPrivate(new Private(*(oOther.m_poPrivate)))
9425 : {
9426 9 : }
9427 :
9428 5 : GDALDataset::ConstLayers::Iterator::Iterator(Iterator &&oOther) noexcept
9429 5 : : m_poPrivate(std::move(oOther.m_poPrivate))
9430 : {
9431 5 : }
9432 :
9433 35450 : GDALDataset::ConstLayers::Iterator::Iterator(const GDALDataset *poDS,
9434 35450 : bool bStart)
9435 35450 : : m_poPrivate(new Private())
9436 : {
9437 35450 : m_poPrivate->m_poDS = poDS;
9438 35450 : m_poPrivate->m_nLayerCount = poDS->GetLayerCount();
9439 35450 : if (bStart)
9440 : {
9441 17727 : if (m_poPrivate->m_nLayerCount)
9442 220 : m_poPrivate->m_poLayer = poDS->GetLayer(0);
9443 : }
9444 : else
9445 : {
9446 17723 : m_poPrivate->m_iCurLayer = m_poPrivate->m_nLayerCount;
9447 : }
9448 35450 : }
9449 :
9450 : GDALDataset::ConstLayers::Iterator::~Iterator() = default;
9451 :
9452 : // False positive of cppcheck 1.72
9453 : // cppcheck-suppress operatorEqVarError
9454 : GDALDataset::ConstLayers::Iterator &
9455 1 : GDALDataset::ConstLayers::Iterator::operator=(const Iterator &oOther)
9456 : {
9457 1 : *m_poPrivate = *oOther.m_poPrivate;
9458 1 : return *this;
9459 : }
9460 :
9461 : GDALDataset::ConstLayers::Iterator &
9462 3 : GDALDataset::ConstLayers::Iterator::operator=(
9463 : GDALDataset::ConstLayers::Iterator &&oOther) noexcept
9464 : {
9465 3 : m_poPrivate = std::move(oOther.m_poPrivate);
9466 3 : return *this;
9467 : }
9468 :
9469 16178 : const OGRLayer *GDALDataset::ConstLayers::Iterator::operator*() const
9470 : {
9471 16178 : return m_poPrivate->m_poLayer;
9472 : }
9473 :
9474 : GDALDataset::ConstLayers::Iterator &
9475 16173 : GDALDataset::ConstLayers::Iterator::operator++()
9476 : {
9477 16173 : m_poPrivate->m_iCurLayer++;
9478 16173 : if (m_poPrivate->m_iCurLayer < m_poPrivate->m_nLayerCount)
9479 : {
9480 15964 : m_poPrivate->m_poLayer =
9481 15964 : m_poPrivate->m_poDS->GetLayer(m_poPrivate->m_iCurLayer);
9482 : }
9483 : else
9484 : {
9485 209 : m_poPrivate->m_poLayer = nullptr;
9486 : }
9487 16173 : return *this;
9488 : }
9489 :
9490 : GDALDataset::ConstLayers::Iterator
9491 2 : GDALDataset::ConstLayers::Iterator::operator++(int)
9492 : {
9493 2 : GDALDataset::ConstLayers::Iterator temp = *this;
9494 2 : ++(*this);
9495 2 : return temp;
9496 : }
9497 :
9498 33890 : bool GDALDataset::ConstLayers::Iterator::operator!=(const Iterator &it) const
9499 : {
9500 33890 : return m_poPrivate->m_iCurLayer != it.m_poPrivate->m_iCurLayer;
9501 : }
9502 :
9503 : /************************************************************************/
9504 : /* GetLayers() */
9505 : /************************************************************************/
9506 :
9507 : /** Function that returns an iterable object over layers in the dataset.
9508 : *
9509 : * This is a C++ iterator friendly version of GetLayer().
9510 : *
9511 : * Typical use is:
9512 : * \code{.cpp}
9513 : * for( auto&& poLayer: poDS->GetLayers() )
9514 : * {
9515 : * std::cout << "Layer << poLayer->GetName() << std::endl;
9516 : * }
9517 : * \endcode
9518 : *
9519 : * @see GetLayer()
9520 : *
9521 : * @since GDAL 3.12
9522 : */
9523 17728 : GDALDataset::ConstLayers GDALDataset::GetLayers() const
9524 : {
9525 17728 : return ConstLayers(this);
9526 : }
9527 :
9528 : /************************************************************************/
9529 : /* begin() */
9530 : /************************************************************************/
9531 :
9532 : /**
9533 : \brief Return beginning of layer iterator.
9534 :
9535 : @since GDAL 3.12
9536 : */
9537 :
9538 17727 : GDALDataset::ConstLayers::Iterator GDALDataset::ConstLayers::begin() const
9539 : {
9540 17727 : return {m_poSelf, true};
9541 : }
9542 :
9543 : /************************************************************************/
9544 : /* end() */
9545 : /************************************************************************/
9546 :
9547 : /**
9548 : \brief Return end of layer iterator.
9549 :
9550 : @since GDAL 3.12
9551 : */
9552 :
9553 17723 : GDALDataset::ConstLayers::Iterator GDALDataset::ConstLayers::end() const
9554 : {
9555 17723 : return {m_poSelf, false};
9556 : }
9557 :
9558 : /************************************************************************/
9559 : /* size() */
9560 : /************************************************************************/
9561 :
9562 : /**
9563 : \brief Get the number of layers in this dataset.
9564 :
9565 : @return layer count.
9566 :
9567 : @since GDAL 3.12
9568 : */
9569 :
9570 1 : size_t GDALDataset::ConstLayers::size() const
9571 : {
9572 1 : return static_cast<size_t>(m_poSelf->GetLayerCount());
9573 : }
9574 :
9575 : /************************************************************************/
9576 : /* operator[]() */
9577 : /************************************************************************/
9578 : /**
9579 : \brief Fetch a layer by index.
9580 :
9581 : The returned layer remains owned by the
9582 : GDALDataset and should not be deleted by the application.
9583 :
9584 : @param iLayer a layer number between 0 and size()-1.
9585 :
9586 : @return the layer, or nullptr if iLayer is out of range or an error occurs.
9587 :
9588 : @since GDAL 3.12
9589 : */
9590 :
9591 9 : const OGRLayer *GDALDataset::ConstLayers::operator[](int iLayer)
9592 : {
9593 9 : return m_poSelf->GetLayer(iLayer);
9594 : }
9595 :
9596 : /************************************************************************/
9597 : /* operator[]() */
9598 : /************************************************************************/
9599 : /**
9600 : \brief Fetch a layer by index.
9601 :
9602 : The returned layer remains owned by the
9603 : GDALDataset and should not be deleted by the application.
9604 :
9605 : @param iLayer a layer number between 0 and size()-1.
9606 :
9607 : @return the layer, or nullptr if iLayer is out of range or an error occurs.
9608 :
9609 : @since GDAL 3.12
9610 : */
9611 :
9612 1 : const OGRLayer *GDALDataset::ConstLayers::operator[](size_t iLayer)
9613 : {
9614 1 : return m_poSelf->GetLayer(static_cast<int>(iLayer));
9615 : }
9616 :
9617 : /************************************************************************/
9618 : /* operator[]() */
9619 : /************************************************************************/
9620 : /**
9621 : \brief Fetch a layer by name.
9622 :
9623 : The returned layer remains owned by the
9624 : GDALDataset and should not be deleted by the application.
9625 :
9626 : @param pszLayerName layer name
9627 :
9628 : @return the layer, or nullptr if pszLayerName does not match with a layer
9629 :
9630 : @since GDAL 3.12
9631 : */
9632 :
9633 1 : const OGRLayer *GDALDataset::ConstLayers::operator[](const char *pszLayerName)
9634 : {
9635 1 : return const_cast<GDALDataset *>(m_poSelf)->GetLayerByName(pszLayerName);
9636 : }
9637 :
9638 : /************************************************************************/
9639 : /* GDALDataset::Bands::Iterator::Private */
9640 : /************************************************************************/
9641 :
9642 : struct GDALDataset::Bands::Iterator::Private
9643 : {
9644 : GDALRasterBand *m_poBand = nullptr;
9645 : int m_iCurBand = 0;
9646 : int m_nBandCount = 0;
9647 : GDALDataset *m_poDS = nullptr;
9648 : };
9649 :
9650 32 : GDALDataset::Bands::Iterator::Iterator(GDALDataset *poDS, bool bStart)
9651 32 : : m_poPrivate(new GDALDataset::Bands::Iterator::Private())
9652 : {
9653 32 : m_poPrivate->m_poDS = poDS;
9654 32 : m_poPrivate->m_nBandCount = poDS->GetRasterCount();
9655 32 : if (bStart)
9656 : {
9657 16 : if (m_poPrivate->m_nBandCount)
9658 16 : m_poPrivate->m_poBand = poDS->GetRasterBand(1);
9659 : }
9660 : else
9661 : {
9662 16 : m_poPrivate->m_iCurBand = m_poPrivate->m_nBandCount;
9663 : }
9664 32 : }
9665 :
9666 : GDALDataset::Bands::Iterator::~Iterator() = default;
9667 :
9668 18 : GDALRasterBand *GDALDataset::Bands::Iterator::operator*()
9669 : {
9670 18 : return m_poPrivate->m_poBand;
9671 : }
9672 :
9673 4 : GDALDataset::Bands::Iterator &GDALDataset::Bands::Iterator::operator++()
9674 : {
9675 4 : m_poPrivate->m_iCurBand++;
9676 4 : if (m_poPrivate->m_iCurBand < m_poPrivate->m_nBandCount)
9677 : {
9678 2 : m_poPrivate->m_poBand =
9679 2 : m_poPrivate->m_poDS->GetRasterBand(1 + m_poPrivate->m_iCurBand);
9680 : }
9681 : else
9682 : {
9683 2 : m_poPrivate->m_poBand = nullptr;
9684 : }
9685 4 : return *this;
9686 : }
9687 :
9688 20 : bool GDALDataset::Bands::Iterator::operator!=(const Iterator &it) const
9689 : {
9690 20 : return m_poPrivate->m_iCurBand != it.m_poPrivate->m_iCurBand;
9691 : }
9692 :
9693 : /************************************************************************/
9694 : /* GetBands() */
9695 : /************************************************************************/
9696 :
9697 : /** Function that returns an iterable object over GDALRasterBand in the dataset.
9698 : *
9699 : * This is a C++ iterator friendly version of GetRasterBand().
9700 : *
9701 : * Typical use is:
9702 : * \code{.cpp}
9703 : * for( auto&& poBand: poDS->GetBands() )
9704 : * {
9705 : * std::cout << "Band << poBand->GetDescription() << std::endl;
9706 : * }
9707 : * \endcode
9708 : *
9709 : * @see GetRasterBand()
9710 : *
9711 : */
9712 20 : GDALDataset::Bands GDALDataset::GetBands()
9713 : {
9714 20 : return Bands(this);
9715 : }
9716 :
9717 : /************************************************************************/
9718 : /* begin() */
9719 : /************************************************************************/
9720 :
9721 : /**
9722 : \brief Return beginning of band iterator.
9723 :
9724 : */
9725 :
9726 16 : const GDALDataset::Bands::Iterator GDALDataset::Bands::begin() const
9727 : {
9728 16 : return {m_poSelf, true};
9729 : }
9730 :
9731 : /************************************************************************/
9732 : /* end() */
9733 : /************************************************************************/
9734 :
9735 : /**
9736 : \brief Return end of band iterator.
9737 :
9738 : */
9739 :
9740 16 : const GDALDataset::Bands::Iterator GDALDataset::Bands::end() const
9741 : {
9742 16 : return {m_poSelf, false};
9743 : }
9744 :
9745 : /************************************************************************/
9746 : /* size() */
9747 : /************************************************************************/
9748 :
9749 : /**
9750 : \brief Get the number of raster bands in this dataset.
9751 :
9752 : @return raster band count.
9753 :
9754 : */
9755 :
9756 2 : size_t GDALDataset::Bands::size() const
9757 : {
9758 2 : return static_cast<size_t>(m_poSelf->GetRasterCount());
9759 : }
9760 :
9761 : /************************************************************************/
9762 : /* operator[]() */
9763 : /************************************************************************/
9764 : /**
9765 : \brief Fetch a raster band by index.
9766 :
9767 : The returned band remains owned by the
9768 : GDALDataset and should not be deleted by the application.
9769 :
9770 : @warning Contrary to GDALDataset::GetRasterBand(), the indexing here is
9771 : consistent with the conventions of C/C++, i.e. starting at 0.
9772 :
9773 : @param iBand a band index between 0 and size()-1.
9774 :
9775 : @return the band, or nullptr if iBand is out of range or an error occurs.
9776 :
9777 : */
9778 :
9779 1 : GDALRasterBand *GDALDataset::Bands::operator[](int iBand)
9780 : {
9781 1 : return m_poSelf->GetRasterBand(1 + iBand);
9782 : }
9783 :
9784 : /************************************************************************/
9785 : /* operator[]() */
9786 : /************************************************************************/
9787 :
9788 : /**
9789 : \brief Fetch a raster band by index.
9790 :
9791 : The returned band remains owned by the
9792 : GDALDataset and should not be deleted by the application.
9793 :
9794 : @warning Contrary to GDALDataset::GetRasterBand(), the indexing here is
9795 : consistent with the conventions of C/C++, i.e. starting at 0.
9796 :
9797 : @param iBand a band index between 0 and size()-1.
9798 :
9799 : @return the band, or nullptr if iBand is out of range or an error occurs.
9800 :
9801 : */
9802 :
9803 1 : GDALRasterBand *GDALDataset::Bands::operator[](size_t iBand)
9804 : {
9805 1 : return m_poSelf->GetRasterBand(1 + static_cast<int>(iBand));
9806 : }
9807 :
9808 : /************************************************************************/
9809 : /* GDALDataset::ConstBands::Iterator::Private */
9810 : /************************************************************************/
9811 :
9812 : struct GDALDataset::ConstBands::Iterator::Private
9813 : {
9814 : const GDALRasterBand *m_poBand = nullptr;
9815 : int m_iCurBand = 0;
9816 : int m_nBandCount = 0;
9817 : const GDALDataset *m_poDS = nullptr;
9818 : };
9819 :
9820 2 : GDALDataset::ConstBands::Iterator::Iterator(const GDALDataset *poDS,
9821 2 : bool bStart)
9822 2 : : m_poPrivate(new GDALDataset::ConstBands::Iterator::Private())
9823 : {
9824 2 : m_poPrivate->m_poDS = poDS;
9825 2 : m_poPrivate->m_nBandCount = poDS->GetRasterCount();
9826 2 : if (bStart)
9827 : {
9828 1 : if (m_poPrivate->m_nBandCount)
9829 1 : m_poPrivate->m_poBand = poDS->GetRasterBand(1);
9830 : }
9831 : else
9832 : {
9833 1 : m_poPrivate->m_iCurBand = m_poPrivate->m_nBandCount;
9834 : }
9835 2 : }
9836 :
9837 : GDALDataset::ConstBands::Iterator::~Iterator() = default;
9838 :
9839 3 : const GDALRasterBand *GDALDataset::ConstBands::Iterator::operator*() const
9840 : {
9841 3 : return m_poPrivate->m_poBand;
9842 : }
9843 :
9844 : GDALDataset::ConstBands::Iterator &
9845 3 : GDALDataset::ConstBands::Iterator::operator++()
9846 : {
9847 3 : m_poPrivate->m_iCurBand++;
9848 3 : if (m_poPrivate->m_iCurBand < m_poPrivate->m_nBandCount)
9849 : {
9850 2 : m_poPrivate->m_poBand =
9851 2 : m_poPrivate->m_poDS->GetRasterBand(1 + m_poPrivate->m_iCurBand);
9852 : }
9853 : else
9854 : {
9855 1 : m_poPrivate->m_poBand = nullptr;
9856 : }
9857 3 : return *this;
9858 : }
9859 :
9860 4 : bool GDALDataset::ConstBands::Iterator::operator!=(const Iterator &it) const
9861 : {
9862 4 : return m_poPrivate->m_iCurBand != it.m_poPrivate->m_iCurBand;
9863 : }
9864 :
9865 : /************************************************************************/
9866 : /* GetBands() */
9867 : /************************************************************************/
9868 :
9869 : /** Function that returns an iterable object over GDALRasterBand in the dataset.
9870 : *
9871 : * This is a C++ iterator friendly version of GetRasterBand().
9872 : *
9873 : * Typical use is:
9874 : * \code{.cpp}
9875 : * for( const auto* poBand: poDS->GetConstBands() )
9876 : * {
9877 : * std::cout << "Band << poBand->GetDescription() << std::endl;
9878 : * }
9879 : * \endcode
9880 : *
9881 : * @see GetRasterBand()
9882 : *
9883 : * @since GDAL 3.12
9884 : */
9885 4 : GDALDataset::ConstBands GDALDataset::GetBands() const
9886 : {
9887 4 : return ConstBands(this);
9888 : }
9889 :
9890 : /************************************************************************/
9891 : /* begin() */
9892 : /************************************************************************/
9893 :
9894 : /**
9895 : \brief Return beginning of band iterator.
9896 :
9897 : @since GDAL 3.12
9898 : */
9899 :
9900 1 : const GDALDataset::ConstBands::Iterator GDALDataset::ConstBands::begin() const
9901 : {
9902 1 : return {m_poSelf, true};
9903 : }
9904 :
9905 : /************************************************************************/
9906 : /* end() */
9907 : /************************************************************************/
9908 :
9909 : /**
9910 : \brief Return end of band iterator.
9911 :
9912 : @since GDAL 3.12
9913 : */
9914 :
9915 1 : const GDALDataset::ConstBands::Iterator GDALDataset::ConstBands::end() const
9916 : {
9917 1 : return {m_poSelf, false};
9918 : }
9919 :
9920 : /************************************************************************/
9921 : /* size() */
9922 : /************************************************************************/
9923 :
9924 : /**
9925 : \brief Get the number of raster bands in this dataset.
9926 :
9927 : @return raster band count.
9928 :
9929 : @since GDAL 3.12
9930 : */
9931 :
9932 1 : size_t GDALDataset::ConstBands::size() const
9933 : {
9934 1 : return static_cast<size_t>(m_poSelf->GetRasterCount());
9935 : }
9936 :
9937 : /************************************************************************/
9938 : /* operator[]() */
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[](int iBand) const
9957 : {
9958 1 : return m_poSelf->GetRasterBand(1 + iBand);
9959 : }
9960 :
9961 : /************************************************************************/
9962 : /* operator[]() */
9963 : /************************************************************************/
9964 :
9965 : /**
9966 : \brief Fetch a raster band by index.
9967 :
9968 : The returned band remains owned by the
9969 : GDALDataset and should not be deleted by the application.
9970 :
9971 : @warning Contrary to GDALDataset::GetRasterBand(), the indexing here is
9972 : consistent with the conventions of C/C++, i.e. starting at 0.
9973 :
9974 : @param iBand a band index between 0 and size()-1.
9975 :
9976 : @return the band, or nullptr if iBand is out of range or an error occurs.
9977 :
9978 : @since GDAL 3.12
9979 : */
9980 :
9981 1 : const GDALRasterBand *GDALDataset::ConstBands::operator[](size_t iBand) const
9982 : {
9983 1 : return m_poSelf->GetRasterBand(1 + static_cast<int>(iBand));
9984 : }
9985 :
9986 : /************************************************************************/
9987 : /* GetRootGroup() */
9988 : /************************************************************************/
9989 :
9990 : /**
9991 : \brief Return the root GDALGroup of this dataset.
9992 :
9993 : Only valid for multidimensional datasets.
9994 :
9995 : This is the same as the C function GDALDatasetGetRootGroup().
9996 :
9997 : @since GDAL 3.1
9998 : */
9999 :
10000 2935 : std::shared_ptr<GDALGroup> GDALDataset::GetRootGroup() const
10001 : {
10002 2935 : return nullptr;
10003 : }
10004 :
10005 : /************************************************************************/
10006 : /* GDALDatasetGetRootGroup() */
10007 : /************************************************************************/
10008 :
10009 : /** Return the root GDALGroup of this dataset.
10010 : *
10011 : * Only valid for multidimensional datasets.
10012 : *
10013 : * The returned value must be freed with GDALGroupRelease().
10014 : *
10015 : * This is the same as the C++ method GDALDataset::GetRootGroup().
10016 : *
10017 : * @since GDAL 3.1
10018 : */
10019 2100 : GDALGroupH GDALDatasetGetRootGroup(GDALDatasetH hDS)
10020 : {
10021 2100 : VALIDATE_POINTER1(hDS, __func__, nullptr);
10022 2100 : auto poGroup(GDALDataset::FromHandle(hDS)->GetRootGroup());
10023 2100 : return poGroup ? new GDALGroupHS(poGroup) : nullptr;
10024 : }
10025 :
10026 : /************************************************************************/
10027 : /* GDALDatasetAsMDArray() */
10028 : /************************************************************************/
10029 :
10030 : /** Return a view of this dataset as a 3D multidimensional GDALMDArray.
10031 : *
10032 : * If this dataset is not already marked as shared, it will be, so that the
10033 : * returned array holds a reference to it.
10034 : *
10035 : * If the dataset has a geotransform attached, the X and Y dimensions of the
10036 : * returned array will have an associated indexing variable.
10037 : *
10038 : * The currently supported list of options is:
10039 : * <ul>
10040 : * <li>DIM_ORDER=<order> where order can be "AUTO", "Band,Y,X" or "Y,X,Band".
10041 : * "Band,Y,X" means that the first (slowest changing) dimension is Band
10042 : * and the last (fastest changing direction) is X
10043 : * "Y,X,Band" means that the first (slowest changing) dimension is Y
10044 : * and the last (fastest changing direction) is Band.
10045 : * "AUTO" (the default) selects "Band,Y,X" for single band datasets, or takes
10046 : * into account the INTERLEAVE metadata item in the IMAGE_STRUCTURE domain.
10047 : * If it equals BAND, then "Band,Y,X" is used. Otherwise (if it equals PIXEL),
10048 : * "Y,X,Band" is use.
10049 : * </li>
10050 : * <li>BAND_INDEXING_VAR_ITEM={Description}|{None}|{Index}|{ColorInterpretation}|<BandMetadataItem>:
10051 : * item from which to build the band indexing variable.
10052 : * <ul>
10053 : * <li>"{Description}", the default, means to use the band description (or "Band index" if empty).</li>
10054 : * <li>"{None}" means that no band indexing variable must be created.</li>
10055 : * <li>"{Index}" means that the band index (starting at one) is used.</li>
10056 : * <li>"{ColorInterpretation}" means that the band color interpretation is used (i.e. "Red", "Green", "Blue").</li>
10057 : * <li><BandMetadataItem> is the name of a band metadata item to use.</li>
10058 : * </ul>
10059 : * </li>
10060 : * <li>BAND_INDEXING_VAR_TYPE=String|Real|Integer: the data type of the band
10061 : * indexing variable, when BAND_INDEXING_VAR_ITEM corresponds to a band metadata item.
10062 : * Defaults to String.
10063 : * </li>
10064 : * <li>BAND_DIM_NAME=<string>: Name of the band dimension.
10065 : * Defaults to "Band".
10066 : * </li>
10067 : * <li>X_DIM_NAME=<string>: Name of the X dimension. Defaults to "X".
10068 : * </li>
10069 : * <li>Y_DIM_NAME=<string>: Name of the Y dimension. Defaults to "Y".
10070 : * </li>
10071 : * </ul>
10072 : *
10073 : * The returned pointer must be released with GDALMDArrayRelease().
10074 : *
10075 : * The "reverse" methods are GDALRasterBand::AsMDArray() and
10076 : * GDALDataset::AsMDArray()
10077 : *
10078 : * This is the same as the C++ method GDALDataset::AsMDArray().
10079 : *
10080 : * @param hDS Dataset handle.
10081 : * @param papszOptions Null-terminated list of strings, or nullptr.
10082 : * @return a new array, or NULL.
10083 : *
10084 : * @since GDAL 3.12
10085 : */
10086 15 : GDALMDArrayH GDALDatasetAsMDArray(GDALDatasetH hDS, CSLConstList papszOptions)
10087 : {
10088 15 : VALIDATE_POINTER1(hDS, __func__, nullptr);
10089 30 : auto poArray(GDALDataset::FromHandle(hDS)->AsMDArray(papszOptions));
10090 15 : if (!poArray)
10091 3 : return nullptr;
10092 12 : return new GDALMDArrayHS(poArray);
10093 : }
10094 :
10095 : /************************************************************************/
10096 : /* GetRawBinaryLayout() */
10097 : /************************************************************************/
10098 :
10099 : //! @cond Doxygen_Suppress
10100 : /**
10101 : \brief Return the layout of a dataset that can be considered as a raw binary
10102 : format.
10103 :
10104 : @param sLayout Structure that will be set if the dataset is a raw binary one.
10105 : @return true if the dataset is a raw binary one.
10106 : @since GDAL 3.1
10107 : */
10108 :
10109 0 : bool GDALDataset::GetRawBinaryLayout(RawBinaryLayout &sLayout)
10110 : {
10111 0 : CPL_IGNORE_RET_VAL(sLayout);
10112 0 : return false;
10113 : }
10114 :
10115 : //! @endcond
10116 :
10117 : /************************************************************************/
10118 : /* ClearStatistics() */
10119 : /************************************************************************/
10120 :
10121 : /**
10122 : \brief Clear statistics
10123 :
10124 : Only implemented for now in PAM supported datasets
10125 :
10126 : This is the same as the C function GDALDatasetClearStatistics().
10127 :
10128 : @since GDAL 3.2
10129 : */
10130 :
10131 11 : void GDALDataset::ClearStatistics()
10132 : {
10133 22 : auto poRootGroup = GetRootGroup();
10134 11 : if (poRootGroup)
10135 1 : poRootGroup->ClearStatistics();
10136 11 : }
10137 :
10138 : /************************************************************************/
10139 : /* GDALDatasetClearStatistics() */
10140 : /************************************************************************/
10141 :
10142 : /**
10143 : \brief Clear statistics
10144 :
10145 : This is the same as the C++ method GDALDataset::ClearStatistics().
10146 :
10147 : @since GDAL 3.2
10148 : */
10149 :
10150 2 : void GDALDatasetClearStatistics(GDALDatasetH hDS)
10151 : {
10152 2 : VALIDATE_POINTER0(hDS, __func__);
10153 2 : GDALDataset::FromHandle(hDS)->ClearStatistics();
10154 : }
10155 :
10156 : /************************************************************************/
10157 : /* GetFieldDomainNames() */
10158 : /************************************************************************/
10159 :
10160 : /** Returns a list of the names of all field domains stored in the dataset.
10161 : *
10162 : * @note The default implementation assumes that drivers fully populate
10163 : * m_oMapFieldDomains when opening a dataset. If this assumption is incorrect
10164 : * then a specialized implementation of GetFieldDomainNames() must be
10165 : * implemented.
10166 : *
10167 : * @param papszOptions Driver specific options determining how attributes
10168 : * should be retrieved. Pass nullptr for default behavior.
10169 : *
10170 : * @return list of field domain names
10171 : * @since GDAL 3.5
10172 : */
10173 : std::vector<std::string>
10174 47 : GDALDataset::GetFieldDomainNames(CPL_UNUSED CSLConstList papszOptions) const
10175 : {
10176 :
10177 47 : std::vector<std::string> names;
10178 47 : names.reserve(m_oMapFieldDomains.size());
10179 59 : for (const auto &it : m_oMapFieldDomains)
10180 : {
10181 12 : names.emplace_back(it.first);
10182 : }
10183 47 : return names;
10184 : }
10185 :
10186 : /************************************************************************/
10187 : /* GDALDatasetGetFieldDomainNames() */
10188 : /************************************************************************/
10189 :
10190 : /** Returns a list of the names of all field domains stored in the dataset.
10191 : *
10192 : * This is the same as the C++ method GDALDataset::GetFieldDomainNames().
10193 : *
10194 : * @param hDS Dataset handle.
10195 : * @param papszOptions Driver specific options determining how attributes
10196 : * should be retrieved. Pass nullptr for default behavior.
10197 : *
10198 : * @return list of field domain names, to be freed with CSLDestroy()
10199 : * @since GDAL 3.5
10200 : */
10201 37 : char **GDALDatasetGetFieldDomainNames(GDALDatasetH hDS,
10202 : CSLConstList papszOptions)
10203 : {
10204 37 : VALIDATE_POINTER1(hDS, __func__, nullptr);
10205 : auto names =
10206 74 : GDALDataset::FromHandle(hDS)->GetFieldDomainNames(papszOptions);
10207 74 : CPLStringList res;
10208 175 : for (const auto &name : names)
10209 : {
10210 138 : res.AddString(name.c_str());
10211 : }
10212 37 : return res.StealList();
10213 : }
10214 :
10215 : /************************************************************************/
10216 : /* GetFieldDomain() */
10217 : /************************************************************************/
10218 :
10219 : /** Get a field domain from its name.
10220 : *
10221 : * @return the field domain, or nullptr if not found.
10222 : * @since GDAL 3.3
10223 : */
10224 325 : const OGRFieldDomain *GDALDataset::GetFieldDomain(const std::string &name) const
10225 : {
10226 325 : const auto iter = m_oMapFieldDomains.find(name);
10227 325 : if (iter == m_oMapFieldDomains.end())
10228 152 : return nullptr;
10229 173 : return iter->second.get();
10230 : }
10231 :
10232 : /************************************************************************/
10233 : /* GDALDatasetGetFieldDomain() */
10234 : /************************************************************************/
10235 :
10236 : /** Get a field domain from its name.
10237 : *
10238 : * This is the same as the C++ method GDALDataset::GetFieldDomain().
10239 : *
10240 : * @param hDS Dataset handle.
10241 : * @param pszName Name of field domain.
10242 : * @return the field domain (ownership remains to the dataset), or nullptr if
10243 : * not found.
10244 : * @since GDAL 3.3
10245 : */
10246 131 : OGRFieldDomainH GDALDatasetGetFieldDomain(GDALDatasetH hDS, const char *pszName)
10247 : {
10248 131 : VALIDATE_POINTER1(hDS, __func__, nullptr);
10249 131 : VALIDATE_POINTER1(pszName, __func__, nullptr);
10250 131 : return OGRFieldDomain::ToHandle(const_cast<OGRFieldDomain *>(
10251 131 : GDALDataset::FromHandle(hDS)->GetFieldDomain(pszName)));
10252 : }
10253 :
10254 : /************************************************************************/
10255 : /* AddFieldDomain() */
10256 : /************************************************************************/
10257 :
10258 : /** Add a field domain to the dataset.
10259 : *
10260 : * Only a few drivers will support this operation, and some of them might only
10261 : * support it only for some types of field domains.
10262 : * At the time of writing (GDAL 3.3), only the Memory and GeoPackage drivers
10263 : * support this operation. A dataset having at least some support for this
10264 : * operation should report the ODsCAddFieldDomain dataset capability.
10265 : *
10266 : * Anticipated failures will not be emitted through the CPLError()
10267 : * infrastructure, but will be reported in the failureReason output parameter.
10268 : *
10269 : * @note Drivers should make sure to update m_oMapFieldDomains in order for the
10270 : * default implementation of GetFieldDomainNames() to work correctly, or
10271 : * alternatively a specialized implementation of GetFieldDomainNames() should be
10272 : * implemented.
10273 : *
10274 : * @param domain The domain definition.
10275 : * @param failureReason Output parameter. Will contain an error message if
10276 : * an error occurs.
10277 : * @return true in case of success.
10278 : * @since GDAL 3.3
10279 : */
10280 0 : bool GDALDataset::AddFieldDomain(
10281 : CPL_UNUSED std::unique_ptr<OGRFieldDomain> &&domain,
10282 : std::string &failureReason)
10283 : {
10284 0 : failureReason = "AddFieldDomain not supported by this driver";
10285 0 : return false;
10286 : }
10287 :
10288 : /************************************************************************/
10289 : /* GDALDatasetAddFieldDomain() */
10290 : /************************************************************************/
10291 :
10292 : /** Add a field domain to the dataset.
10293 : *
10294 : * Only a few drivers will support this operation, and some of them might only
10295 : * support it only for some types of field domains.
10296 : * At the time of writing (GDAL 3.3), only the Memory and GeoPackage drivers
10297 : * support this operation. A dataset having at least some support for this
10298 : * operation should report the ODsCAddFieldDomain dataset capability.
10299 : *
10300 : * Anticipated failures will not be emitted through the CPLError()
10301 : * infrastructure, but will be reported in the ppszFailureReason output
10302 : * parameter.
10303 : *
10304 : * @param hDS Dataset handle.
10305 : * @param hFieldDomain The domain definition. Contrary to the C++ version,
10306 : * the passed object is copied.
10307 : * @param ppszFailureReason Output parameter. Will contain an error message if
10308 : * an error occurs (*ppszFailureReason to be freed
10309 : * with CPLFree). May be NULL.
10310 : * @return true in case of success.
10311 : * @since GDAL 3.3
10312 : */
10313 37 : bool GDALDatasetAddFieldDomain(GDALDatasetH hDS, OGRFieldDomainH hFieldDomain,
10314 : char **ppszFailureReason)
10315 : {
10316 37 : VALIDATE_POINTER1(hDS, __func__, false);
10317 37 : VALIDATE_POINTER1(hFieldDomain, __func__, false);
10318 : auto poDomain = std::unique_ptr<OGRFieldDomain>(
10319 74 : OGRFieldDomain::FromHandle(hFieldDomain)->Clone());
10320 37 : if (poDomain == nullptr)
10321 0 : return false;
10322 37 : std::string failureReason;
10323 74 : const bool bRet = GDALDataset::FromHandle(hDS)->AddFieldDomain(
10324 37 : std::move(poDomain), failureReason);
10325 37 : if (ppszFailureReason)
10326 : {
10327 37 : *ppszFailureReason =
10328 37 : failureReason.empty() ? nullptr : CPLStrdup(failureReason.c_str());
10329 : }
10330 37 : return bRet;
10331 : }
10332 :
10333 : /************************************************************************/
10334 : /* DeleteFieldDomain() */
10335 : /************************************************************************/
10336 :
10337 : /** Removes a field domain from the dataset.
10338 : *
10339 : * Only a few drivers will support this operation.
10340 : *
10341 : * At the time of writing (GDAL 3.5), only the Memory and GeoPackage drivers
10342 : * support this operation. A dataset having at least some support for this
10343 : * operation should report the ODsCDeleteFieldDomain dataset capability.
10344 : *
10345 : * Anticipated failures will not be emitted through the CPLError()
10346 : * infrastructure, but will be reported in the failureReason output parameter.
10347 : *
10348 : * @note Drivers should make sure to update m_oMapFieldDomains in order for the
10349 : * default implementation of GetFieldDomainNames() to work correctly, or
10350 : * alternatively a specialized implementation of GetFieldDomainNames() should be
10351 : * implemented.
10352 : *
10353 : * @param name The domain name.
10354 : * @param failureReason Output parameter. Will contain an error message if
10355 : * an error occurs.
10356 : * @return true in case of success.
10357 : * @since GDAL 3.5
10358 : */
10359 0 : bool GDALDataset::DeleteFieldDomain(CPL_UNUSED const std::string &name,
10360 : std::string &failureReason)
10361 : {
10362 0 : failureReason = "DeleteFieldDomain not supported by this driver";
10363 0 : return false;
10364 : }
10365 :
10366 : /************************************************************************/
10367 : /* GDALDatasetDeleteFieldDomain() */
10368 : /************************************************************************/
10369 :
10370 : /** Removes a field domain from the dataset.
10371 : *
10372 : * Only a few drivers will support this operation.
10373 : *
10374 : * At the time of writing (GDAL 3.5), only the Memory and GeoPackage drivers
10375 : * support this operation. A dataset having at least some support for this
10376 : * operation should report the ODsCDeleteFieldDomain dataset capability.
10377 : *
10378 : * Anticipated failures will not be emitted through the CPLError()
10379 : * infrastructure, but will be reported in the ppszFailureReason output
10380 : * parameter.
10381 : *
10382 : * @param hDS Dataset handle.
10383 : * @param pszName The domain name.
10384 : * @param ppszFailureReason Output parameter. Will contain an error message if
10385 : * an error occurs (*ppszFailureReason to be freed
10386 : * with CPLFree). May be NULL.
10387 : * @return true in case of success.
10388 : * @since GDAL 3.3
10389 : */
10390 25 : bool GDALDatasetDeleteFieldDomain(GDALDatasetH hDS, const char *pszName,
10391 : char **ppszFailureReason)
10392 : {
10393 25 : VALIDATE_POINTER1(hDS, __func__, false);
10394 25 : VALIDATE_POINTER1(pszName, __func__, false);
10395 25 : std::string failureReason;
10396 : const bool bRet =
10397 25 : GDALDataset::FromHandle(hDS)->DeleteFieldDomain(pszName, failureReason);
10398 25 : if (ppszFailureReason)
10399 : {
10400 0 : *ppszFailureReason =
10401 0 : failureReason.empty() ? nullptr : CPLStrdup(failureReason.c_str());
10402 : }
10403 25 : return bRet;
10404 : }
10405 :
10406 : /************************************************************************/
10407 : /* UpdateFieldDomain() */
10408 : /************************************************************************/
10409 :
10410 : /** Updates an existing field domain by replacing its definition.
10411 : *
10412 : * The existing field domain with matching name will be replaced.
10413 : *
10414 : * Only a few drivers will support this operation, and some of them might only
10415 : * support it only for some types of field domains.
10416 : * At the time of writing (GDAL 3.5), only the Memory driver
10417 : * supports this operation. A dataset having at least some support for this
10418 : * operation should report the ODsCUpdateFieldDomain dataset capability.
10419 : *
10420 : * Anticipated failures will not be emitted through the CPLError()
10421 : * infrastructure, but will be reported in the failureReason output parameter.
10422 : *
10423 : * @param domain The domain definition.
10424 : * @param failureReason Output parameter. Will contain an error message if
10425 : * an error occurs.
10426 : * @return true in case of success.
10427 : * @since GDAL 3.5
10428 : */
10429 0 : bool GDALDataset::UpdateFieldDomain(
10430 : CPL_UNUSED std::unique_ptr<OGRFieldDomain> &&domain,
10431 : std::string &failureReason)
10432 : {
10433 0 : failureReason = "UpdateFieldDomain not supported by this driver";
10434 0 : return false;
10435 : }
10436 :
10437 : /************************************************************************/
10438 : /* GDALDatasetUpdateFieldDomain() */
10439 : /************************************************************************/
10440 :
10441 : /** Updates an existing field domain by replacing its definition.
10442 : *
10443 : * The existing field domain with matching name will be replaced.
10444 : *
10445 : * Only a few drivers will support this operation, and some of them might only
10446 : * support it only for some types of field domains.
10447 : * At the time of writing (GDAL 3.5), only the Memory driver
10448 : * supports this operation. A dataset having at least some support for this
10449 : * operation should report the ODsCUpdateFieldDomain dataset capability.
10450 : *
10451 : * Anticipated failures will not be emitted through the CPLError()
10452 : * infrastructure, but will be reported in the failureReason output parameter.
10453 : *
10454 : * @param hDS Dataset handle.
10455 : * @param hFieldDomain The domain definition. Contrary to the C++ version,
10456 : * the passed object is copied.
10457 : * @param ppszFailureReason Output parameter. Will contain an error message if
10458 : * an error occurs (*ppszFailureReason to be freed
10459 : * with CPLFree). May be NULL.
10460 : * @return true in case of success.
10461 : * @since GDAL 3.5
10462 : */
10463 7 : bool GDALDatasetUpdateFieldDomain(GDALDatasetH hDS,
10464 : OGRFieldDomainH hFieldDomain,
10465 : char **ppszFailureReason)
10466 : {
10467 7 : VALIDATE_POINTER1(hDS, __func__, false);
10468 7 : VALIDATE_POINTER1(hFieldDomain, __func__, false);
10469 : auto poDomain = std::unique_ptr<OGRFieldDomain>(
10470 14 : OGRFieldDomain::FromHandle(hFieldDomain)->Clone());
10471 7 : if (poDomain == nullptr)
10472 0 : return false;
10473 7 : std::string failureReason;
10474 14 : const bool bRet = GDALDataset::FromHandle(hDS)->UpdateFieldDomain(
10475 7 : std::move(poDomain), failureReason);
10476 7 : if (ppszFailureReason)
10477 : {
10478 0 : *ppszFailureReason =
10479 0 : failureReason.empty() ? nullptr : CPLStrdup(failureReason.c_str());
10480 : }
10481 7 : return bRet;
10482 : }
10483 :
10484 : /************************************************************************/
10485 : /* GetRelationshipNames() */
10486 : /************************************************************************/
10487 :
10488 : /** Returns a list of the names of all relationships stored in the dataset.
10489 : *
10490 : * @param papszOptions Driver specific options determining how relationships
10491 : * should be retrieved. Pass nullptr for default behavior.
10492 : *
10493 : * @return list of relationship names
10494 : * @since GDAL 3.6
10495 : */
10496 : std::vector<std::string>
10497 237 : GDALDataset::GetRelationshipNames(CPL_UNUSED CSLConstList papszOptions) const
10498 : {
10499 237 : return {};
10500 : }
10501 :
10502 : /************************************************************************/
10503 : /* GDALDatasetGetRelationshipNames() */
10504 : /************************************************************************/
10505 :
10506 : /** Returns a list of the names of all relationships stored in the dataset.
10507 : *
10508 : * This is the same as the C++ method GDALDataset::GetRelationshipNames().
10509 : *
10510 : * @param hDS Dataset handle.
10511 : * @param papszOptions Driver specific options determining how relationships
10512 : * should be retrieved. Pass nullptr for default behavior.
10513 : *
10514 : * @return list of relationship names, to be freed with CSLDestroy()
10515 : * @since GDAL 3.6
10516 : */
10517 53 : char **GDALDatasetGetRelationshipNames(GDALDatasetH hDS,
10518 : CSLConstList papszOptions)
10519 : {
10520 53 : VALIDATE_POINTER1(hDS, __func__, nullptr);
10521 : auto names =
10522 106 : GDALDataset::FromHandle(hDS)->GetRelationshipNames(papszOptions);
10523 106 : CPLStringList res;
10524 161 : for (const auto &name : names)
10525 : {
10526 108 : res.AddString(name.c_str());
10527 : }
10528 53 : return res.StealList();
10529 : }
10530 :
10531 : /************************************************************************/
10532 : /* GetRelationship() */
10533 : /************************************************************************/
10534 :
10535 : /** Get a relationship from its name.
10536 : *
10537 : * @return the relationship, or nullptr if not found.
10538 : * @since GDAL 3.6
10539 : */
10540 : const GDALRelationship *
10541 0 : GDALDataset::GetRelationship(CPL_UNUSED const std::string &name) const
10542 : {
10543 0 : return nullptr;
10544 : }
10545 :
10546 : /************************************************************************/
10547 : /* GDALDatasetGetRelationship() */
10548 : /************************************************************************/
10549 :
10550 : /** Get a relationship from its name.
10551 : *
10552 : * This is the same as the C++ method GDALDataset::GetRelationship().
10553 : *
10554 : * @param hDS Dataset handle.
10555 : * @param pszName Name of relationship.
10556 : * @return the relationship (ownership remains to the dataset), or nullptr if
10557 : * not found.
10558 : * @since GDAL 3.6
10559 : */
10560 63 : GDALRelationshipH GDALDatasetGetRelationship(GDALDatasetH hDS,
10561 : const char *pszName)
10562 : {
10563 63 : VALIDATE_POINTER1(hDS, __func__, nullptr);
10564 63 : VALIDATE_POINTER1(pszName, __func__, nullptr);
10565 63 : return GDALRelationship::ToHandle(const_cast<GDALRelationship *>(
10566 63 : GDALDataset::FromHandle(hDS)->GetRelationship(pszName)));
10567 : }
10568 :
10569 : /************************************************************************/
10570 : /* AddRelationship() */
10571 : /************************************************************************/
10572 :
10573 : /** Add a relationship to the dataset.
10574 : *
10575 : * Only a few drivers will support this operation, and some of them might only
10576 : * support it only for some types of relationships.
10577 : *
10578 : * A dataset having at least some support for this
10579 : * operation should report the GDsCAddRelationship dataset capability.
10580 : *
10581 : * Anticipated failures will not be emitted through the CPLError()
10582 : * infrastructure, but will be reported in the failureReason output parameter.
10583 : *
10584 : * When adding a many-to-many relationship
10585 : * (GDALRelationshipCardinality::GRC_MANY_TO_MANY), it is possible to omit the
10586 : * mapping table name (see GDALRelationship::GetMappingTableName) to instruct
10587 : * the driver to create an appropriately named and structured mapping table.
10588 : * Some dataset formats require particular naming conventions and field
10589 : * structures for the mapping table, and delegating the construction of the
10590 : * mapping table to the driver will avoid these pitfalls.
10591 : *
10592 : * @param relationship The relationship definition.
10593 : * @param failureReason Output parameter. Will contain an error message if
10594 : * an error occurs.
10595 : * @return true in case of success.
10596 : * @since GDAL 3.6
10597 : */
10598 0 : bool GDALDataset::AddRelationship(
10599 : CPL_UNUSED std::unique_ptr<GDALRelationship> &&relationship,
10600 : std::string &failureReason)
10601 : {
10602 0 : failureReason = "AddRelationship not supported by this driver";
10603 0 : return false;
10604 : }
10605 :
10606 : /************************************************************************/
10607 : /* GDALDatasetAddRelationship() */
10608 : /************************************************************************/
10609 :
10610 : /** Add a relationship to the dataset.
10611 : *
10612 : * Only a few drivers will support this operation, and some of them might only
10613 : * support it only for some types of relationships.
10614 : *
10615 : * A dataset having at least some support for this
10616 : * operation should report the GDsCAddRelationship dataset capability.
10617 : *
10618 : * Anticipated failures will not be emitted through the CPLError()
10619 : * infrastructure, but will be reported in the failureReason output parameter.
10620 : *
10621 : * When adding a many-to-many relationship
10622 : * (GDALRelationshipCardinality::GRC_MANY_TO_MANY), it is possible to omit the
10623 : * mapping table name (see GDALRelationshipGetMappingTableName) to instruct the
10624 : * driver to create an appropriately named and structured mapping table. Some
10625 : * dataset formats require particular naming conventions and field structures
10626 : * for the mapping table, and delegating the construction of the mapping table
10627 : * to the driver will avoid these pitfalls.
10628 : *
10629 : * @param hDS Dataset handle.
10630 : * @param hRelationship The relationship definition. Contrary to the C++
10631 : * version, the passed object is copied.
10632 : * @param ppszFailureReason Output parameter. Will contain an error message if
10633 : * an error occurs (*ppszFailureReason to be freed
10634 : * with CPLFree). May be NULL.
10635 : * @return true in case of success.
10636 : * @since GDAL 3.6
10637 : */
10638 45 : bool GDALDatasetAddRelationship(GDALDatasetH hDS,
10639 : GDALRelationshipH hRelationship,
10640 : char **ppszFailureReason)
10641 : {
10642 45 : VALIDATE_POINTER1(hDS, __func__, false);
10643 45 : VALIDATE_POINTER1(hRelationship, __func__, false);
10644 : std::unique_ptr<GDALRelationship> poRelationship(
10645 90 : new GDALRelationship(*GDALRelationship::FromHandle(hRelationship)));
10646 45 : std::string failureReason;
10647 90 : const bool bRet = GDALDataset::FromHandle(hDS)->AddRelationship(
10648 45 : std::move(poRelationship), failureReason);
10649 45 : if (ppszFailureReason)
10650 : {
10651 0 : *ppszFailureReason =
10652 0 : failureReason.empty() ? nullptr : CPLStrdup(failureReason.c_str());
10653 : }
10654 45 : return bRet;
10655 : }
10656 :
10657 : /************************************************************************/
10658 : /* DeleteRelationship() */
10659 : /************************************************************************/
10660 :
10661 : /** Removes a relationship from the dataset.
10662 : *
10663 : * Only a few drivers will support this operation.
10664 : *
10665 : * A dataset having at least some support for this
10666 : * operation should report the GDsCDeleteRelationship dataset capability.
10667 : *
10668 : * Anticipated failures will not be emitted through the CPLError()
10669 : * infrastructure, but will be reported in the failureReason output parameter.
10670 : *
10671 : * @param name The relationship name.
10672 : * @param failureReason Output parameter. Will contain an error message if
10673 : * an error occurs.
10674 : * @return true in case of success.
10675 : * @since GDAL 3.6
10676 : */
10677 0 : bool GDALDataset::DeleteRelationship(CPL_UNUSED const std::string &name,
10678 : std::string &failureReason)
10679 : {
10680 0 : failureReason = "DeleteRelationship not supported by this driver";
10681 0 : return false;
10682 : }
10683 :
10684 : /************************************************************************/
10685 : /* GDALDatasetDeleteRelationship() */
10686 : /************************************************************************/
10687 :
10688 : /** Removes a relationship from the dataset.
10689 : *
10690 : * Only a few drivers will support this operation.
10691 : *
10692 : * A dataset having at least some support for this
10693 : * operation should report the GDsCDeleteRelationship dataset capability.
10694 : *
10695 : * Anticipated failures will not be emitted through the CPLError()
10696 : * infrastructure, but will be reported in the ppszFailureReason output
10697 : * parameter.
10698 : *
10699 : * @param hDS Dataset handle.
10700 : * @param pszName The relationship name.
10701 : * @param ppszFailureReason Output parameter. Will contain an error message if
10702 : * an error occurs (*ppszFailureReason to be freed
10703 : * with CPLFree). May be NULL.
10704 : * @return true in case of success.
10705 : * @since GDAL 3.6
10706 : */
10707 8 : bool GDALDatasetDeleteRelationship(GDALDatasetH hDS, const char *pszName,
10708 : char **ppszFailureReason)
10709 : {
10710 8 : VALIDATE_POINTER1(hDS, __func__, false);
10711 8 : VALIDATE_POINTER1(pszName, __func__, false);
10712 8 : std::string failureReason;
10713 16 : const bool bRet = GDALDataset::FromHandle(hDS)->DeleteRelationship(
10714 8 : pszName, failureReason);
10715 8 : if (ppszFailureReason)
10716 : {
10717 0 : *ppszFailureReason =
10718 0 : failureReason.empty() ? nullptr : CPLStrdup(failureReason.c_str());
10719 : }
10720 8 : return bRet;
10721 : }
10722 :
10723 : /************************************************************************/
10724 : /* UpdateRelationship() */
10725 : /************************************************************************/
10726 :
10727 : /** Updates an existing relationship by replacing its definition.
10728 : *
10729 : * The existing relationship with matching name will be replaced.
10730 : *
10731 : * Only a few drivers will support this operation, and some of them might only
10732 : * support it only for some types of relationships.
10733 : * A dataset having at least some support for this
10734 : * operation should report the GDsCUpdateRelationship dataset capability.
10735 : *
10736 : * Anticipated failures will not be emitted through the CPLError()
10737 : * infrastructure, but will be reported in the failureReason output parameter.
10738 : *
10739 : * @param relationship The relationship definition.
10740 : * @param failureReason Output parameter. Will contain an error message if
10741 : * an error occurs.
10742 : * @return true in case of success.
10743 : * @since GDAL 3.6
10744 : */
10745 0 : bool GDALDataset::UpdateRelationship(
10746 : CPL_UNUSED std::unique_ptr<GDALRelationship> &&relationship,
10747 : std::string &failureReason)
10748 : {
10749 0 : failureReason = "UpdateRelationship not supported by this driver";
10750 0 : return false;
10751 : }
10752 :
10753 : /************************************************************************/
10754 : /* GDALDatasetUpdateRelationship() */
10755 : /************************************************************************/
10756 :
10757 : /** Updates an existing relationship by replacing its definition.
10758 : *
10759 : * The existing relationship with matching name will be replaced.
10760 : *
10761 : * Only a few drivers will support this operation, and some of them might only
10762 : * support it only for some types of relationships.
10763 : * A dataset having at least some support for this
10764 : * operation should report the GDsCUpdateRelationship dataset capability.
10765 : *
10766 : * Anticipated failures will not be emitted through the CPLError()
10767 : * infrastructure, but will be reported in the failureReason output parameter.
10768 : *
10769 : * @param hDS Dataset handle.
10770 : * @param hRelationship The relationship definition. Contrary to the C++
10771 : * version, the passed object is copied.
10772 : * @param ppszFailureReason Output parameter. Will contain an error message if
10773 : * an error occurs (*ppszFailureReason to be freed
10774 : * with CPLFree). May be NULL.
10775 : * @return true in case of success.
10776 : * @since GDAL 3.5
10777 : */
10778 11 : bool GDALDatasetUpdateRelationship(GDALDatasetH hDS,
10779 : GDALRelationshipH hRelationship,
10780 : char **ppszFailureReason)
10781 : {
10782 11 : VALIDATE_POINTER1(hDS, __func__, false);
10783 11 : VALIDATE_POINTER1(hRelationship, __func__, false);
10784 : std::unique_ptr<GDALRelationship> poRelationship(
10785 22 : new GDALRelationship(*GDALRelationship::FromHandle(hRelationship)));
10786 11 : std::string failureReason;
10787 22 : const bool bRet = GDALDataset::FromHandle(hDS)->UpdateRelationship(
10788 11 : std::move(poRelationship), failureReason);
10789 11 : if (ppszFailureReason)
10790 : {
10791 0 : *ppszFailureReason =
10792 0 : failureReason.empty() ? nullptr : CPLStrdup(failureReason.c_str());
10793 : }
10794 11 : return bRet;
10795 : }
10796 :
10797 : /************************************************************************/
10798 : /* GDALDatasetSetQueryLoggerFunc() */
10799 : /************************************************************************/
10800 :
10801 : /**
10802 : * Sets the SQL query logger callback.
10803 : *
10804 : * When supported by the driver, the callback will be called with
10805 : * the executed SQL text, the error message, the execution time in milliseconds,
10806 : * the number of records fetched/affected and the client status data.
10807 : *
10808 : * A value of -1 in the execution time or in the number of records indicates
10809 : * that the values are unknown.
10810 : *
10811 : * @param hDS Dataset handle.
10812 : * @param pfnQueryLoggerFunc Callback function
10813 : * @param poQueryLoggerArg Opaque client status data
10814 : * @return true in case of success.
10815 : * @since GDAL 3.7
10816 : */
10817 1 : bool GDALDatasetSetQueryLoggerFunc(GDALDatasetH hDS,
10818 : GDALQueryLoggerFunc pfnQueryLoggerFunc,
10819 : void *poQueryLoggerArg)
10820 : {
10821 1 : VALIDATE_POINTER1(hDS, __func__, false);
10822 2 : return GDALDataset::FromHandle(hDS)->SetQueryLoggerFunc(pfnQueryLoggerFunc,
10823 1 : poQueryLoggerArg);
10824 : }
10825 :
10826 : //! @cond Doxygen_Suppress
10827 :
10828 : /************************************************************************/
10829 : /* SetEnableOverviews() */
10830 : /************************************************************************/
10831 :
10832 7531 : void GDALDataset::SetEnableOverviews(bool bEnable)
10833 : {
10834 7531 : if (m_poPrivate)
10835 : {
10836 7531 : m_poPrivate->m_bOverviewsEnabled = bEnable;
10837 : }
10838 7531 : }
10839 :
10840 : /************************************************************************/
10841 : /* AreOverviewsEnabled() */
10842 : /************************************************************************/
10843 :
10844 2007060 : bool GDALDataset::AreOverviewsEnabled() const
10845 : {
10846 2007060 : return m_poPrivate ? m_poPrivate->m_bOverviewsEnabled : true;
10847 : }
10848 :
10849 : /************************************************************************/
10850 : /* IsAllBands() */
10851 : /************************************************************************/
10852 :
10853 4206 : bool GDALDataset::IsAllBands(int nBandCount, const int *panBandList) const
10854 : {
10855 4206 : if (nBands != nBandCount)
10856 21 : return false;
10857 4185 : if (panBandList)
10858 : {
10859 15824 : for (int i = 0; i < nBandCount; ++i)
10860 : {
10861 11733 : if (panBandList[i] != i + 1)
10862 27 : return false;
10863 : }
10864 : }
10865 4158 : return true;
10866 : }
10867 :
10868 : //! @endcond
10869 :
10870 : /************************************************************************/
10871 : /* GetCompressionFormats() */
10872 : /************************************************************************/
10873 :
10874 : /** Return the compression formats that can be natively obtained for the
10875 : * window of interest and requested bands.
10876 : *
10877 : * For example, a tiled dataset may be able to return data in a compressed
10878 : * format if the window of interest matches exactly a tile. For some formats,
10879 : * drivers may also be able to merge several tiles together (not currently
10880 : * implemented though).
10881 : *
10882 : * Each format string is a pseudo MIME type, whose first part can be passed
10883 : * as the pszFormat argument of ReadCompressedData(), with additional
10884 : * parameters specified as key=value with a semi-colon separator.
10885 : *
10886 : * The amount and types of optional parameters passed after the MIME type is
10887 : * format dependent, and driver dependent (some drivers might not be able to
10888 : * return those extra information without doing a rather costly processing).
10889 : *
10890 : * For example, a driver might return "JPEG;frame_type=SOF0_baseline;"
10891 : * "bit_depth=8;num_components=3;subsampling=4:2:0;colorspace=YCbCr", and
10892 : * consequently "JPEG" can be passed as the pszFormat argument of
10893 : * ReadCompressedData(). For JPEG, implementations can use the
10894 : * GDALGetCompressionFormatForJPEG() helper method to generate a string like
10895 : * above from a JPEG codestream.
10896 : *
10897 : * Several values might be returned. For example,
10898 : * the JPEGXL driver will return "JXL", but also potentially "JPEG"
10899 : * if the JPEGXL codestream includes a JPEG reconstruction box.
10900 : *
10901 : * In the general case this method will return an empty list.
10902 : *
10903 : * This is the same as C function GDALDatasetGetCompressionFormats().
10904 : *
10905 : * @param nXOff The pixel offset to the top left corner of the region
10906 : * of the band to be accessed. This would be zero to start from the left side.
10907 : *
10908 : * @param nYOff The line offset to the top left corner of the region
10909 : * of the band to be accessed. This would be zero to start from the top.
10910 : *
10911 : * @param nXSize The width of the region of the band to be accessed in pixels.
10912 : *
10913 : * @param nYSize The height of the region of the band to be accessed in lines.
10914 : *
10915 : * @param nBandCount the number of bands being requested.
10916 : *
10917 : * @param panBandList the list of nBandCount band numbers.
10918 : * Note band numbers are 1 based. This may be NULL to select the first
10919 : * nBandCount bands.
10920 : *
10921 : * @return a list of compatible formats (which may be empty)
10922 : *
10923 : * For example, to check if native compression format(s) are available on the
10924 : * whole image:
10925 : * \code{.cpp}
10926 : * const CPLStringList aosFormats =
10927 : * poDataset->GetCompressionFormats(0, 0,
10928 : * poDataset->GetRasterXSize(),
10929 : * poDataset->GetRasterYSize(),
10930 : * poDataset->GetRasterCount(),
10931 : * nullptr);
10932 : * for( const char* pszFormat: aosFormats )
10933 : * {
10934 : * // Remove optional parameters and just print out the MIME type.
10935 : * const CPLStringList aosTokens(CSLTokenizeString2(pszFormat, ";", 0));
10936 : * printf("Found format %s\n, aosTokens[0]);
10937 : * }
10938 : * \endcode
10939 : *
10940 : * @since GDAL 3.7
10941 : */
10942 : CPLStringList
10943 0 : GDALDataset::GetCompressionFormats(CPL_UNUSED int nXOff, CPL_UNUSED int nYOff,
10944 : CPL_UNUSED int nXSize, CPL_UNUSED int nYSize,
10945 : CPL_UNUSED int nBandCount,
10946 : CPL_UNUSED const int *panBandList)
10947 : {
10948 0 : return CPLStringList();
10949 : }
10950 :
10951 : /************************************************************************/
10952 : /* GDALDatasetGetCompressionFormats() */
10953 : /************************************************************************/
10954 :
10955 : /** Return the compression formats that can be natively obtained for the
10956 : * window of interest and requested bands.
10957 : *
10958 : * For example, a tiled dataset may be able to return data in a compressed
10959 : * format if the window of interest matches exactly a tile. For some formats,
10960 : * drivers may also be able to merge several tiles together (not currently
10961 : * implemented though).
10962 : *
10963 : * Each format string is a pseudo MIME type, whose first part can be passed
10964 : * as the pszFormat argument of ReadCompressedData(), with additional
10965 : * parameters specified as key=value with a semi-colon separator.
10966 : *
10967 : * The amount and types of optional parameters passed after the MIME type is
10968 : * format dependent, and driver dependent (some drivers might not be able to
10969 : * return those extra information without doing a rather costly processing).
10970 : *
10971 : * For example, a driver might return "JPEG;frame_type=SOF0_baseline;"
10972 : * "bit_depth=8;num_components=3;subsampling=4:2:0;colorspace=YCbCr", and
10973 : * consequently "JPEG" can be passed as the pszFormat argument of
10974 : * ReadCompressedData(). For JPEG, implementations can use the
10975 : * GDALGetCompressionFormatForJPEG() helper method to generate a string like
10976 : * above from a JPEG codestream.
10977 : *
10978 : * Several values might be returned. For example,
10979 : * the JPEGXL driver will return "JXL", but also potentially "JPEG"
10980 : * if the JPEGXL codestream includes a JPEG reconstruction box.
10981 : *
10982 : * In the general case this method will return an empty list.
10983 : *
10984 : * This is the same as C++ method GDALDataset::GetCompressionFormats().
10985 : *
10986 : * @param hDS Dataset handle.
10987 : *
10988 : * @param nXOff The pixel offset to the top left corner of the region
10989 : * of the band to be accessed. This would be zero to start from the left side.
10990 : *
10991 : * @param nYOff The line offset to the top left corner of the region
10992 : * of the band to be accessed. This would be zero to start from the top.
10993 : *
10994 : * @param nXSize The width of the region of the band to be accessed in pixels.
10995 : *
10996 : * @param nYSize The height of the region of the band to be accessed in lines.
10997 : *
10998 : * @param nBandCount the number of bands being requested.
10999 : *
11000 : * @param panBandList the list of nBandCount band numbers.
11001 : * Note band numbers are 1 based. This may be NULL to select the first
11002 : * nBandCount bands.
11003 : *
11004 : * @return a list of compatible formats (which may be empty) that should be
11005 : * freed with CSLDestroy(), or nullptr.
11006 : *
11007 : * @since GDAL 3.7
11008 : */
11009 9 : char **GDALDatasetGetCompressionFormats(GDALDatasetH hDS, int nXOff, int nYOff,
11010 : int nXSize, int nYSize, int nBandCount,
11011 : const int *panBandList)
11012 : {
11013 9 : VALIDATE_POINTER1(hDS, __func__, nullptr);
11014 9 : return GDALDataset::FromHandle(hDS)
11015 9 : ->GetCompressionFormats(nXOff, nYOff, nXSize, nYSize, nBandCount,
11016 9 : panBandList)
11017 9 : .StealList();
11018 : }
11019 :
11020 : /************************************************************************/
11021 : /* ReadCompressedData() */
11022 : /************************************************************************/
11023 :
11024 : /** Return the compressed content that can be natively obtained for the
11025 : * window of interest and requested bands.
11026 : *
11027 : * For example, a tiled dataset may be able to return data in compressed format
11028 : * if the window of interest matches exactly a tile. For some formats, drivers
11029 : * may also be example to merge several tiles together (not currently
11030 : * implemented though).
11031 : *
11032 : * The implementation should make sure that the content returned forms a valid
11033 : * standalone file. For example, for the GeoTIFF implementation of this method,
11034 : * when extracting a JPEG tile, the method will automatically add the content
11035 : * of the JPEG Huffman and/or quantization tables that might be stored in the
11036 : * TIFF JpegTables tag, and not in tile data itself.
11037 : *
11038 : * In the general case this method will return CE_Failure.
11039 : *
11040 : * This is the same as C function GDALDatasetReadCompressedData().
11041 : *
11042 : * @param pszFormat Requested compression format (e.g. "JPEG",
11043 : * "WEBP", "JXL"). This is the MIME type of one of the values
11044 : * returned by GetCompressionFormats(). The format string is designed to
11045 : * potentially include at a later point key=value optional parameters separated
11046 : * by a semi-colon character. At time of writing, none are implemented.
11047 : * ReadCompressedData() implementations should verify optional parameters and
11048 : * return CE_Failure if they cannot support one of them.
11049 : *
11050 : * @param nXOff The pixel offset to the top left corner of the region
11051 : * of the band to be accessed. This would be zero to start from the left side.
11052 : *
11053 : * @param nYOff The line offset to the top left corner of the region
11054 : * of the band to be accessed. This would be zero to start from the top.
11055 : *
11056 : * @param nXSize The width of the region of the band to be accessed in pixels.
11057 : *
11058 : * @param nYSize The height of the region of the band to be accessed in lines.
11059 : *
11060 : * @param nBandCount the number of bands being requested.
11061 : *
11062 : * @param panBandList the list of nBandCount band numbers.
11063 : * Note band numbers are 1 based. This may be NULL to select the first
11064 : * nBandCount bands.
11065 : *
11066 : * @param ppBuffer Pointer to a buffer to store the compressed data or nullptr.
11067 : * If ppBuffer is not nullptr, then pnBufferSize should also not be nullptr.
11068 : * If ppBuffer is not nullptr, and *ppBuffer is not nullptr, then the provided
11069 : * buffer will be filled with the compressed data, provided that pnBufferSize
11070 : * and *pnBufferSize are not nullptr, and *pnBufferSize, indicating the size
11071 : * of *ppBuffer, is sufficiently large to hold the data.
11072 : * If ppBuffer is not nullptr, but *ppBuffer is nullptr, then the method will
11073 : * allocate *ppBuffer using VSIMalloc(), and thus the caller is responsible to
11074 : * free it with VSIFree().
11075 : * If ppBuffer is nullptr, then the compressed data itself will not be returned,
11076 : * but *pnBufferSize will be updated with an upper bound of the size that would
11077 : * be necessary to hold it (if pnBufferSize != nullptr).
11078 : *
11079 : * @param pnBufferSize Output buffer size, or nullptr.
11080 : * If ppBuffer != nullptr && *ppBuffer != nullptr, then pnBufferSize should
11081 : * be != nullptr and *pnBufferSize contain the size of *ppBuffer. If the
11082 : * method is successful, *pnBufferSize will be updated with the actual size
11083 : * used.
11084 : *
11085 : * @param ppszDetailedFormat Pointer to an output string, or nullptr.
11086 : * If ppszDetailedFormat is not nullptr, then, on success, the method will
11087 : * allocate a new string in *ppszDetailedFormat (to be freed with VSIFree())
11088 : * *ppszDetailedFormat might contain strings like
11089 : * "JPEG;frame_type=SOF0_baseline;bit_depth=8;num_components=3;"
11090 : * "subsampling=4:2:0;colorspace=YCbCr" or simply the MIME type.
11091 : * The string will contain at least as much information as what
11092 : * GetCompressionFormats() returns, and potentially more when
11093 : * ppBuffer != nullptr.
11094 : *
11095 : * @return CE_None in case of success, CE_Failure otherwise.
11096 : *
11097 : * For example, to request JPEG content on the whole image and let GDAL deal
11098 : * with the buffer allocation.
11099 : * \code{.cpp}
11100 : * void* pBuffer = nullptr;
11101 : * size_t nBufferSize = 0;
11102 : * CPLErr eErr =
11103 : * poDataset->ReadCompressedData("JPEG",
11104 : * 0, 0,
11105 : * poDataset->GetRasterXSize(),
11106 : * poDataset->GetRasterYSize(),
11107 : * poDataset->GetRasterCount(),
11108 : * nullptr, // panBandList
11109 : * &pBuffer,
11110 : * &nBufferSize,
11111 : * nullptr // ppszDetailedFormat
11112 : * );
11113 : * if (eErr == CE_None)
11114 : * {
11115 : * CPLAssert(pBuffer != nullptr);
11116 : * CPLAssert(nBufferSize > 0);
11117 : * VSILFILE* fp = VSIFOpenL("my.jpeg", "wb");
11118 : * if (fp)
11119 : * {
11120 : * VSIFWriteL(pBuffer, nBufferSize, 1, fp);
11121 : * VSIFCloseL(fp);
11122 : * }
11123 : * VSIFree(pBuffer);
11124 : * }
11125 : * \endcode
11126 : *
11127 : * Or to manage the buffer allocation on your side:
11128 : * \code{.cpp}
11129 : * size_t nUpperBoundBufferSize = 0;
11130 : * CPLErr eErr =
11131 : * poDataset->ReadCompressedData("JPEG",
11132 : * 0, 0,
11133 : * poDataset->GetRasterXSize(),
11134 : * poDataset->GetRasterYSize(),
11135 : * poDataset->GetRasterCount(),
11136 : * nullptr, // panBandList
11137 : * nullptr, // ppBuffer,
11138 : * &nUpperBoundBufferSize,
11139 : * nullptr // ppszDetailedFormat
11140 : * );
11141 : * if (eErr == CE_None)
11142 : * {
11143 : * std::vector<uint8_t> myBuffer;
11144 : * myBuffer.resize(nUpperBoundBufferSize);
11145 : * void* pBuffer = myBuffer.data();
11146 : * size_t nActualSize = nUpperBoundBufferSize;
11147 : * char* pszDetailedFormat = nullptr;
11148 : * // We also request detailed format, but we could have passed it to
11149 : * // nullptr as well.
11150 : * eErr =
11151 : * poDataset->ReadCompressedData("JPEG",
11152 : * 0, 0,
11153 : * poDataset->GetRasterXSize(),
11154 : * poDataset->GetRasterYSize(),
11155 : * poDataset->GetRasterCount(),
11156 : * nullptr, // panBandList
11157 : * &pBuffer,
11158 : * &nActualSize,
11159 : * &pszDetailedFormat);
11160 : * if (eErr == CE_None)
11161 : * {
11162 : * CPLAssert(pBuffer == myBuffer.data()); // pointed value not modified
11163 : * CPLAssert(nActualSize <= nUpperBoundBufferSize);
11164 : * myBuffer.resize(nActualSize);
11165 : * // do something useful
11166 : * VSIFree(pszDetailedFormat);
11167 : * }
11168 : * }
11169 : * \endcode
11170 : *
11171 : * @since GDAL 3.7
11172 : */
11173 444 : CPLErr GDALDataset::ReadCompressedData(
11174 : CPL_UNUSED const char *pszFormat, CPL_UNUSED int nXOff,
11175 : CPL_UNUSED int nYOff, CPL_UNUSED int nXSize, CPL_UNUSED int nYSize,
11176 : CPL_UNUSED int nBandCount, CPL_UNUSED const int *panBandList,
11177 : CPL_UNUSED void **ppBuffer, CPL_UNUSED size_t *pnBufferSize,
11178 : CPL_UNUSED char **ppszDetailedFormat)
11179 : {
11180 444 : return CE_Failure;
11181 : }
11182 :
11183 : /************************************************************************/
11184 : /* GDALDatasetReadCompressedData() */
11185 : /************************************************************************/
11186 :
11187 : /** Return the compressed content that can be natively obtained for the
11188 : * window of interest and requested bands.
11189 : *
11190 : * For example, a tiled dataset may be able to return data in compressed format
11191 : * if the window of interest matches exactly a tile. For some formats, drivers
11192 : * may also be example to merge several tiles together (not currently
11193 : * implemented though).
11194 : *
11195 : * The implementation should make sure that the content returned forms a valid
11196 : * standalone file. For example, for the GeoTIFF implementation of this method,
11197 : * when extracting a JPEG tile, the method will automatically adds the content
11198 : * of the JPEG Huffman and/or quantization tables that might be stored in the
11199 : * TIFF JpegTables tag, and not in tile data itself.
11200 : *
11201 : * In the general case this method will return CE_Failure.
11202 : *
11203 : * This is the same as C++ method GDALDataset:ReadCompressedData().
11204 : *
11205 : * @param hDS Dataset handle.
11206 : *
11207 : * @param pszFormat Requested compression format (e.g. "JPEG",
11208 : * "WEBP", "JXL"). This is the MIME type of one of the values
11209 : * returned by GetCompressionFormats(). The format string is designed to
11210 : * potentially include at a later point key=value optional parameters separated
11211 : * by a semi-colon character. At time of writing, none are implemented.
11212 : * ReadCompressedData() implementations should verify optional parameters and
11213 : * return CE_Failure if they cannot support one of them.
11214 : *
11215 : * @param nXOff The pixel offset to the top left corner of the region
11216 : * of the band to be accessed. This would be zero to start from the left side.
11217 : *
11218 : * @param nYOff The line offset to the top left corner of the region
11219 : * of the band to be accessed. This would be zero to start from the top.
11220 : *
11221 : * @param nXSize The width of the region of the band to be accessed in pixels.
11222 : *
11223 : * @param nYSize The height of the region of the band to be accessed in lines.
11224 : *
11225 : * @param nBandCount the number of bands being requested.
11226 : *
11227 : * @param panBandList the list of nBandCount band numbers.
11228 : * Note band numbers are 1 based. This may be NULL to select the first
11229 : * nBandCount bands.
11230 : *
11231 : * @param ppBuffer Pointer to a buffer to store the compressed data or nullptr.
11232 : * If ppBuffer is not nullptr, then pnBufferSize should also not be nullptr.
11233 : * If ppBuffer is not nullptr, and *ppBuffer is not nullptr, then the provided
11234 : * buffer will be filled with the compressed data, provided that pnBufferSize
11235 : * and *pnBufferSize are not nullptr, and *pnBufferSize, indicating the size
11236 : * of *ppBuffer, is sufficiently large to hold the data.
11237 : * If ppBuffer is not nullptr, but *ppBuffer is nullptr, then the method will
11238 : * allocate *ppBuffer using VSIMalloc(), and thus the caller is responsible to
11239 : * free it with VSIFree().
11240 : * If ppBuffer is nullptr, then the compressed data itself will not be returned,
11241 : * but *pnBufferSize will be updated with an upper bound of the size that would
11242 : * be necessary to hold it (if pnBufferSize != nullptr).
11243 : *
11244 : * @param pnBufferSize Output buffer size, or nullptr.
11245 : * If ppBuffer != nullptr && *ppBuffer != nullptr, then pnBufferSize should
11246 : * be != nullptr and *pnBufferSize contain the size of *ppBuffer. If the
11247 : * method is successful, *pnBufferSize will be updated with the actual size
11248 : * used.
11249 : *
11250 : * @param ppszDetailedFormat Pointer to an output string, or nullptr.
11251 : * If ppszDetailedFormat is not nullptr, then, on success, the method will
11252 : * allocate a new string in *ppszDetailedFormat (to be freed with VSIFree())
11253 : * *ppszDetailedFormat might contain strings like
11254 : * "JPEG;frame_type=SOF0_baseline;bit_depth=8;num_components=3;"
11255 : * "subsampling=4:2:0;colorspace=YCbCr" or simply the MIME type.
11256 : * The string will contain at least as much information as what
11257 : * GetCompressionFormats() returns, and potentially more when
11258 : * ppBuffer != nullptr.
11259 : *
11260 : * @return CE_None in case of success, CE_Failure otherwise.
11261 : *
11262 : * @since GDAL 3.7
11263 : */
11264 28 : CPLErr GDALDatasetReadCompressedData(GDALDatasetH hDS, const char *pszFormat,
11265 : int nXOff, int nYOff, int nXSize,
11266 : int nYSize, int nBandCount,
11267 : const int *panBandList, void **ppBuffer,
11268 : size_t *pnBufferSize,
11269 : char **ppszDetailedFormat)
11270 : {
11271 28 : VALIDATE_POINTER1(hDS, __func__, CE_Failure);
11272 56 : return GDALDataset::FromHandle(hDS)->ReadCompressedData(
11273 : pszFormat, nXOff, nYOff, nXSize, nYSize, nBandCount, panBandList,
11274 28 : ppBuffer, pnBufferSize, ppszDetailedFormat);
11275 : }
11276 :
11277 : /************************************************************************/
11278 : /* CanBeCloned() */
11279 : /************************************************************************/
11280 :
11281 : //! @cond Doxygen_Suppress
11282 :
11283 : /** This method is called by GDALThreadSafeDataset::Create() to determine if
11284 : * it is possible to create a thread-safe wrapper for a dataset, which involves
11285 : * the ability to Clone() it.
11286 : *
11287 : * Implementations of this method must be thread-safe.
11288 : *
11289 : * @param nScopeFlags Combination of GDAL_OF_RASTER, GDAL_OF_VECTOR, etc. flags,
11290 : * expressing the intended use for thread-safety.
11291 : * Currently, the only valid scope is in the base
11292 : * implementation is GDAL_OF_RASTER.
11293 : * @param bCanShareState Determines if cloned datasets are allowed to share
11294 : * state with the dataset they have been cloned from.
11295 : * If set to true, the dataset from which they have been
11296 : * cloned from must remain opened during the lifetime of
11297 : * its clones.
11298 : * @return true if the Clone() method is expected to succeed with the same values
11299 : * of nScopeFlags and bCanShareState.
11300 : */
11301 149 : bool GDALDataset::CanBeCloned(int nScopeFlags,
11302 : [[maybe_unused]] bool bCanShareState) const
11303 : {
11304 149 : return m_bCanBeReopened && nScopeFlags == GDAL_OF_RASTER;
11305 : }
11306 :
11307 : //! @endcond
11308 :
11309 : /************************************************************************/
11310 : /* Clone() */
11311 : /************************************************************************/
11312 :
11313 : //! @cond Doxygen_Suppress
11314 :
11315 : /** This method "clones" the current dataset, that is it returns a new instance
11316 : * that is opened on the same underlying "file".
11317 : *
11318 : * The base implementation uses GDALDataset::Open() to re-open the dataset.
11319 : * The MEM driver has a specialized implementation that returns a new instance,
11320 : * but which shares the same memory buffer as this.
11321 : *
11322 : * Implementations of this method must be thread-safe.
11323 : *
11324 : * @param nScopeFlags Combination of GDAL_OF_RASTER, GDAL_OF_VECTOR, etc. flags,
11325 : * expressing the intended use for thread-safety.
11326 : * Currently, the only valid scope is in the base
11327 : * implementation is GDAL_OF_RASTER.
11328 : * @param bCanShareState Determines if cloned datasets are allowed to share
11329 : * state with the dataset they have been cloned from.
11330 : * If set to true, the dataset from which they have been
11331 : * cloned from must remain opened during the lifetime of
11332 : * its clones.
11333 : * @return a new instance, or nullptr in case of error.
11334 : */
11335 : std::unique_ptr<GDALDataset>
11336 2051 : GDALDataset::Clone(int nScopeFlags, [[maybe_unused]] bool bCanShareState) const
11337 : {
11338 4102 : CPLStringList aosAllowedDrivers;
11339 2051 : if (poDriver)
11340 2051 : aosAllowedDrivers.AddString(poDriver->GetDescription());
11341 : return std::unique_ptr<GDALDataset>(GDALDataset::Open(
11342 2051 : GetDescription(),
11343 2051 : nScopeFlags | GDAL_OF_INTERNAL | GDAL_OF_VERBOSE_ERROR,
11344 4102 : aosAllowedDrivers.List(), papszOpenOptions));
11345 : }
11346 :
11347 : //! @endcond
11348 :
11349 : /************************************************************************/
11350 : /* GeolocationToPixelLine() */
11351 : /************************************************************************/
11352 :
11353 : /** Transform georeferenced coordinates to pixel/line coordinates.
11354 : *
11355 : * When poSRS is null, those georeferenced coordinates (dfGeolocX, dfGeolocY)
11356 : * must be in the "natural" SRS of the dataset, that is the one returned by
11357 : * GetSpatialRef() if there is a geotransform, GetGCPSpatialRef() if there are
11358 : * GCPs, WGS 84 if there are RPC coefficients, or the SRS of the geolocation
11359 : * array (generally WGS 84) if there is a geolocation array.
11360 : * If that natural SRS is a geographic one, dfGeolocX must be a longitude, and
11361 : * dfGeolocY a latitude. If that natural SRS is a projected one, dfGeolocX must
11362 : * be a easting, and dfGeolocY a northing.
11363 : *
11364 : * When poSRS is set to a non-null value, (dfGeolocX, dfGeolocY) must be
11365 : * expressed in that CRS, and that tuple must be conformant with the
11366 : * data-axis-to-crs-axis setting of poSRS, that is the one returned by
11367 : * the OGRSpatialReference::GetDataAxisToSRSAxisMapping(). If you want to be sure
11368 : * of the axis order, then make sure to call poSRS->SetAxisMappingStrategy(OAMS_TRADITIONAL_GIS_ORDER)
11369 : * before calling this method, and in that case, dfGeolocX must be a longitude
11370 : * or an easting value, and dfGeolocX a latitude or a northing value.
11371 : *
11372 : * This method uses GDALCreateGenImgProjTransformer2() underneath.
11373 : *
11374 : * @param dfGeolocX X coordinate of the position (longitude or easting if poSRS
11375 : * is null, otherwise consistent with poSRS data-axis-to-crs-axis mapping),
11376 : * where interpolation should be done.
11377 : * @param dfGeolocY Y coordinate of the position (latitude or northing if poSRS
11378 : * is null, otherwise consistent with poSRS data-axis-to-crs-axis mapping),
11379 : * where interpolation should be done.
11380 : * @param poSRS If set, override the natural CRS in which dfGeolocX, dfGeolocY are expressed
11381 : * @param[out] pdfPixel Pointer to the variable where to the store the pixel/column coordinate.
11382 : * @param[out] pdfLine Pointer to the variable where to the store the line coordinate.
11383 : * @param papszTransformerOptions Options accepted by GDALCreateGenImgProjTransformer2(), or nullptr.
11384 : *
11385 : * @return CE_None on success, or an error code on failure.
11386 : * @since GDAL 3.11
11387 : */
11388 :
11389 : CPLErr
11390 15 : GDALDataset::GeolocationToPixelLine(double dfGeolocX, double dfGeolocY,
11391 : const OGRSpatialReference *poSRS,
11392 : double *pdfPixel, double *pdfLine,
11393 : CSLConstList papszTransformerOptions) const
11394 : {
11395 30 : CPLStringList aosTO(papszTransformerOptions);
11396 :
11397 15 : if (poSRS)
11398 : {
11399 4 : const char *const apszOptions[] = {"FORMAT=WKT2", nullptr};
11400 8 : const std::string osWKT = poSRS->exportToWkt(apszOptions);
11401 4 : aosTO.SetNameValue("DST_SRS", osWKT.c_str());
11402 4 : const auto eAxisMappingStrategy = poSRS->GetAxisMappingStrategy();
11403 4 : if (eAxisMappingStrategy == OAMS_TRADITIONAL_GIS_ORDER)
11404 : aosTO.SetNameValue("DST_SRS_AXIS_MAPPING_STRATEGY",
11405 1 : "TRADITIONAL_GIS_ORDER");
11406 3 : else if (eAxisMappingStrategy == OAMS_AUTHORITY_COMPLIANT)
11407 : aosTO.SetNameValue("DST_SRS_AXIS_MAPPING_STRATEGY",
11408 1 : "AUTHORITY_COMPLIANT");
11409 : else
11410 : {
11411 2 : const auto &anValues = poSRS->GetDataAxisToSRSAxisMapping();
11412 4 : std::string osVal;
11413 6 : for (int v : anValues)
11414 : {
11415 4 : if (!osVal.empty())
11416 2 : osVal += ',';
11417 4 : osVal += std::to_string(v);
11418 : }
11419 : aosTO.SetNameValue("DST_SRS_DATA_AXIS_TO_SRS_AXIS_MAPPING",
11420 2 : osVal.c_str());
11421 : }
11422 : }
11423 :
11424 15 : auto hTransformer = GDALCreateGenImgProjTransformer2(
11425 : GDALDataset::ToHandle(const_cast<GDALDataset *>(this)), nullptr,
11426 15 : aosTO.List());
11427 15 : if (hTransformer == nullptr)
11428 : {
11429 1 : return CE_Failure;
11430 : }
11431 :
11432 14 : double z = 0;
11433 14 : int bSuccess = 0;
11434 14 : GDALGenImgProjTransform(hTransformer, TRUE, 1, &dfGeolocX, &dfGeolocY, &z,
11435 : &bSuccess);
11436 14 : GDALDestroyTransformer(hTransformer);
11437 14 : if (bSuccess)
11438 : {
11439 14 : if (pdfPixel)
11440 14 : *pdfPixel = dfGeolocX;
11441 14 : if (pdfLine)
11442 14 : *pdfLine = dfGeolocY;
11443 14 : return CE_None;
11444 : }
11445 : else
11446 : {
11447 0 : return CE_Failure;
11448 : }
11449 : }
11450 :
11451 : /************************************************************************/
11452 : /* GDALDatasetGeolocationToPixelLine() */
11453 : /************************************************************************/
11454 :
11455 : /** Transform georeferenced coordinates to pixel/line coordinates.
11456 : *
11457 : * @see GDALDataset::GeolocationToPixelLine()
11458 : * @since GDAL 3.11
11459 : */
11460 :
11461 0 : CPLErr GDALDatasetGeolocationToPixelLine(GDALDatasetH hDS, double dfGeolocX,
11462 : double dfGeolocY,
11463 : OGRSpatialReferenceH hSRS,
11464 : double *pdfPixel, double *pdfLine,
11465 : CSLConstList papszTransformerOptions)
11466 : {
11467 0 : VALIDATE_POINTER1(hDS, "GDALDatasetGeolocationToPixelLine", CE_Failure);
11468 :
11469 0 : GDALDataset *poDS = GDALDataset::FromHandle(hDS);
11470 0 : return poDS->GeolocationToPixelLine(
11471 0 : dfGeolocX, dfGeolocY, OGRSpatialReference::FromHandle(hSRS), pdfPixel,
11472 0 : pdfLine, papszTransformerOptions);
11473 : }
11474 :
11475 : /************************************************************************/
11476 : /* GetExtent() */
11477 : /************************************************************************/
11478 :
11479 : /** Return extent of dataset in specified CRS.
11480 : *
11481 : * OGREnvelope.MinX/MaxX represents longitudes, and MinY/MaxY latitudes.
11482 : *
11483 : * For rasters, the base implementation of this method only succeeds if
11484 : * GetGeoTransform() and GetSpatialRef() succeed.
11485 : * For vectors, the base implementation of this method iterates over layers
11486 : * and call their OGRLayer::GetExtent() method.
11487 : *
11488 : * TestCapability(GDsCFastGetExtent) can be used to test if the execution
11489 : * time of this method is fast.
11490 : *
11491 : * This is the same as C function GDALGetExtent()
11492 : *
11493 : * @param[out] psExtent Pointer to output extent. Must NOT be null.
11494 : * @param poCRS CRS in which to express the extent. If not specified, this will
11495 : * be the raster CRS or the CRS of the first layer for a vector dataset.
11496 : * @return CE_None in case of success, CE_Failure otherwise
11497 : * @since GDAL 3.12
11498 : */
11499 :
11500 456 : CPLErr GDALDataset::GetExtent(OGREnvelope *psExtent,
11501 : const OGRSpatialReference *poCRS) const
11502 : {
11503 456 : const OGRSpatialReference *poThisCRS = GetSpatialRefRasterOnly();
11504 456 : int nLayerCount = 0;
11505 456 : if (!poThisCRS)
11506 : {
11507 93 : nLayerCount = GetLayerCount();
11508 93 : if (nLayerCount >= 1)
11509 : {
11510 3 : if (auto poLayer = GetLayer(0))
11511 3 : poThisCRS = poLayer->GetSpatialRef();
11512 : }
11513 : }
11514 456 : if (!poCRS)
11515 246 : poCRS = poThisCRS;
11516 210 : else if (!poThisCRS)
11517 3 : return CE_Failure;
11518 :
11519 453 : *psExtent = OGREnvelope();
11520 :
11521 453 : GDALGeoTransform gt;
11522 453 : auto poThisDS = const_cast<GDALDataset *>(this);
11523 453 : const bool bHasGT = poThisDS->GetGeoTransform(gt) == CE_None;
11524 453 : if (bHasGT)
11525 : {
11526 0 : std::unique_ptr<OGRCoordinateTransformation> poCT;
11527 448 : if (poCRS)
11528 : {
11529 363 : poCT.reset(OGRCreateCoordinateTransformation(poThisCRS, poCRS));
11530 : }
11531 :
11532 448 : constexpr int DENSIFY_POINT_COUNT = 21;
11533 448 : double dfULX = gt.xorig;
11534 448 : double dfULY = gt.yorig;
11535 448 : double dfURX = 0, dfURY = 0;
11536 448 : gt.Apply(nRasterXSize, 0, &dfURX, &dfURY);
11537 448 : double dfLLX = 0, dfLLY = 0;
11538 448 : gt.Apply(0, nRasterYSize, &dfLLX, &dfLLY);
11539 448 : double dfLRX = 0, dfLRY = 0;
11540 448 : gt.Apply(nRasterXSize, nRasterYSize, &dfLRX, &dfLRY);
11541 448 : const double xmin = std::min({dfULX, dfURX, dfLLX, dfLRX});
11542 448 : const double ymin = std::min({dfULY, dfURY, dfLLY, dfLRY});
11543 448 : const double xmax = std::max({dfULX, dfURX, dfLLX, dfLRX});
11544 448 : const double ymax = std::max({dfULY, dfURY, dfLLY, dfLRY});
11545 448 : if (poCT)
11546 : {
11547 361 : OGREnvelope sEnvTmp;
11548 722 : if (!poCT->TransformBounds(xmin, ymin, xmax, ymax, &(sEnvTmp.MinX),
11549 : &(sEnvTmp.MinY), &(sEnvTmp.MaxX),
11550 361 : &(sEnvTmp.MaxY), DENSIFY_POINT_COUNT))
11551 : {
11552 0 : return CE_Failure;
11553 : }
11554 361 : *psExtent = sEnvTmp;
11555 : }
11556 : else
11557 : {
11558 87 : psExtent->MinX = xmin;
11559 87 : psExtent->MinY = ymin;
11560 87 : psExtent->MaxX = xmax;
11561 87 : psExtent->MaxY = ymax;
11562 : }
11563 : }
11564 :
11565 453 : if (nLayerCount > 0)
11566 : {
11567 6 : for (auto &&poLayer : poThisDS->GetLayers())
11568 : {
11569 3 : auto poLayerCRS = poLayer->GetSpatialRef();
11570 3 : if (poLayerCRS)
11571 : {
11572 3 : OGREnvelope sLayerExtent;
11573 3 : if (poLayer->GetExtent(&sLayerExtent) == OGRERR_NONE)
11574 : {
11575 : auto poCT = std::unique_ptr<OGRCoordinateTransformation>(
11576 6 : OGRCreateCoordinateTransformation(poLayerCRS, poCRS));
11577 3 : if (poCT)
11578 : {
11579 3 : constexpr int DENSIFY_POINT_COUNT = 21;
11580 3 : OGREnvelope sEnvTmp;
11581 3 : if (poCT->TransformBounds(
11582 : sLayerExtent.MinX, sLayerExtent.MinY,
11583 : sLayerExtent.MaxX, sLayerExtent.MaxY,
11584 : &(sEnvTmp.MinX), &(sEnvTmp.MinY),
11585 : &(sEnvTmp.MaxX), &(sEnvTmp.MaxY),
11586 3 : DENSIFY_POINT_COUNT))
11587 : {
11588 3 : psExtent->Merge(sEnvTmp);
11589 : }
11590 : }
11591 : }
11592 : }
11593 : }
11594 : }
11595 :
11596 453 : return psExtent->IsInit() ? CE_None : CE_Failure;
11597 : }
11598 :
11599 : /************************************************************************/
11600 : /* GDALGetExtent() */
11601 : /************************************************************************/
11602 :
11603 : /** Return extent of dataset in specified CRS.
11604 : *
11605 : * OGREnvelope.MinX/MaxX represents longitudes, and MinY/MaxY latitudes.
11606 : *
11607 : * For rasters, the base implementation of this method only succeeds if
11608 : * GetGeoTransform() and GetSpatialRef() succeed.
11609 : * For vectors, the base implementation of this method iterates over layers
11610 : * and call their OGRLayer::GetExtent() method.
11611 : *
11612 : * TestCapability(GDsCFastGetExtent) can be used to test if the execution
11613 : * time of this method is fast.
11614 : *
11615 : * This is the same as C++ method GDALDataset::GetExtent()
11616 : *
11617 : * @param hDS Dataset handle. Must NOT be null.
11618 : * @param[out] psExtent Pointer to output extent. Must NOT be null.
11619 : * @param hCRS CRS in which to express the extent. If not specified, this will
11620 : * be the raster CRS or the CRS of the first layer for a vector dataset.
11621 : * @return extent in poCRS (valid only if IsInit() method returns true)
11622 : * @since GDAL 3.12
11623 : */
11624 :
11625 28 : CPLErr GDALGetExtent(GDALDatasetH hDS, OGREnvelope *psExtent,
11626 : OGRSpatialReferenceH hCRS)
11627 : {
11628 28 : VALIDATE_POINTER1(hDS, __func__, CE_Failure);
11629 28 : VALIDATE_POINTER1(psExtent, __func__, CE_Failure);
11630 56 : return GDALDataset::FromHandle(hDS)->GetExtent(
11631 28 : psExtent, OGRSpatialReference::FromHandle(hCRS));
11632 : }
11633 :
11634 : /************************************************************************/
11635 : /* GetExtentWGS84LongLat() */
11636 : /************************************************************************/
11637 :
11638 : /** Return extent of dataset in WGS84 longitude/latitude
11639 : *
11640 : * OGREnvelope.MinX/MaxX represents longitudes, and MinY/MaxY latitudes.
11641 : *
11642 : * TestCapability(GDsCFastGetExtentWGS84LongLat) can be used to test if the execution
11643 : * time of this method is fast.
11644 : *
11645 : * This is the same as C function GDALGetExtentWGS84LongLat()
11646 : *
11647 : * @return extent (valid only if IsInit() method returns true)
11648 : * @since GDAL 3.12
11649 : */
11650 :
11651 208 : CPLErr GDALDataset::GetExtentWGS84LongLat(OGREnvelope *psExtent) const
11652 : {
11653 416 : OGRSpatialReference oSRS_WGS84;
11654 208 : oSRS_WGS84.SetFromUserInput("WGS84");
11655 208 : oSRS_WGS84.SetAxisMappingStrategy(OAMS_TRADITIONAL_GIS_ORDER);
11656 416 : return GetExtent(psExtent, &oSRS_WGS84);
11657 : }
11658 :
11659 : /************************************************************************/
11660 : /* GDALGetExtentWGS84LongLat() */
11661 : /************************************************************************/
11662 :
11663 : /** Return extent of dataset in WGS84 longitude/latitude
11664 : *
11665 : * OGREnvelope.MinX/MaxX represents longitudes, and MinY/MaxY latitudes.
11666 : *
11667 : * TestCapability(GDsCFastGetExtentWGS84LongLat) can be used to test if the execution
11668 : * time of this method is fast.
11669 : *
11670 : * This is the same as C++ method GDALDataset::GetExtentWGS84LongLat()
11671 : *
11672 : * @param hDS Dataset handle. Must NOT be null.
11673 : * @param[out] psExtent Pointer to output extent. Must NOT be null.
11674 : * @return extent (valid only if IsInit() method returns true)
11675 : * @since GDAL 3.12
11676 : */
11677 :
11678 5 : CPLErr GDALGetExtentWGS84LongLat(GDALDatasetH hDS, OGREnvelope *psExtent)
11679 : {
11680 5 : VALIDATE_POINTER1(hDS, __func__, CE_Failure);
11681 5 : VALIDATE_POINTER1(psExtent, __func__, CE_Failure);
11682 5 : return GDALDataset::FromHandle(hDS)->GetExtentWGS84LongLat(psExtent);
11683 : }
11684 :
11685 : /************************************************************************/
11686 : /* ReportUpdateNotSupportedByDriver() */
11687 : /************************************************************************/
11688 :
11689 : //! @cond Doxygen_Suppress
11690 :
11691 : /* static */
11692 1 : void GDALDataset::ReportUpdateNotSupportedByDriver(const char *pszDriverName)
11693 : {
11694 1 : CPLError(CE_Failure, CPLE_NotSupported,
11695 : "The %s driver does not support update access to existing "
11696 : "datasets.",
11697 : pszDriverName);
11698 1 : }
11699 :
11700 : //! @endcond
11701 :
11702 : /************************************************************************/
11703 : /* BuildFilename() */
11704 : /************************************************************************/
11705 :
11706 : /** Generates a filename, potentially relative to another one.
11707 : *
11708 : * Given the path to a reference directory, and a path to a file
11709 : * referenced from it, build a path to the file that the current application
11710 : * can use. If the file path is already absolute, rather than relative, or if
11711 : * bRelativeToReferencePath is false, then the filename of interest will be
11712 : * returned unaltered.
11713 : *
11714 : * This is enhanced version of CPLProjectRelativeFilenameSafe() that takes
11715 : * into account the subdataset syntax.
11716 : *
11717 : * Examples:
11718 : * \code{.cpp}
11719 : * BuildFilename("tmp/abc.gif", "abc/def", true) == "abc/def/tmp/abc.gif"
11720 : * BuildFilename("../abc.gif", "/abc/def") == "/abc/abc.gif"
11721 : * BuildFilename("abc.gif", "C:\WIN", true) == "C:\WIN\abc.gif"
11722 : * BuildFilename("abc.gif", "C:\WIN", false) == "abc.gif"
11723 : * BuildFilename("/home/even/foo.tif", "/home/even/workdir", true) == "/home/even/foo.tif"
11724 : * \endcode
11725 : *
11726 : * @param pszFilename Filename of interest.
11727 : * @param pszReferencePath Path to a reference directory.
11728 : * @param bRelativeToReferencePath Whether pszFilename, if a relative path, is
11729 : * relative to pszReferencePath
11730 : * @since 3.11
11731 : */
11732 :
11733 : /* static */
11734 104259 : std::string GDALDataset::BuildFilename(const char *pszFilename,
11735 : const char *pszReferencePath,
11736 : bool bRelativeToReferencePath)
11737 : {
11738 104259 : std::string osSrcDSName;
11739 104259 : if (pszReferencePath != nullptr && bRelativeToReferencePath)
11740 : {
11741 : // Try subdatasetinfo API first
11742 : // Note: this will become the only branch when subdatasetinfo will become
11743 : // available for NITF_IM, RASTERLITE and TILEDB
11744 2619 : const auto oSubDSInfo{GDALGetSubdatasetInfo(pszFilename)};
11745 2619 : if (oSubDSInfo && !oSubDSInfo->GetPathComponent().empty())
11746 : {
11747 8 : auto path{oSubDSInfo->GetPathComponent()};
11748 12 : osSrcDSName = oSubDSInfo->ModifyPathComponent(
11749 8 : CPLProjectRelativeFilenameSafe(pszReferencePath, path.c_str())
11750 4 : .c_str());
11751 4 : GDALDestroySubdatasetInfo(oSubDSInfo);
11752 : }
11753 : else
11754 : {
11755 2615 : bool bDone = false;
11756 15675 : for (const char *pszSyntax : apszSpecialSubDatasetSyntax)
11757 : {
11758 13063 : CPLString osPrefix(pszSyntax);
11759 13063 : osPrefix.resize(strchr(pszSyntax, ':') - pszSyntax + 1);
11760 13063 : if (pszSyntax[osPrefix.size()] == '"')
11761 2612 : osPrefix += '"';
11762 13063 : if (EQUALN(pszFilename, osPrefix, osPrefix.size()))
11763 : {
11764 3 : if (STARTS_WITH_CI(pszSyntax + osPrefix.size(), "{ANY}"))
11765 : {
11766 3 : const char *pszLastPart = strrchr(pszFilename, ':') + 1;
11767 : // CSV:z:/foo.xyz
11768 3 : if ((pszLastPart[0] == '/' || pszLastPart[0] == '\\') &&
11769 0 : pszLastPart - pszFilename >= 3 &&
11770 0 : pszLastPart[-3] == ':')
11771 : {
11772 0 : pszLastPart -= 2;
11773 : }
11774 3 : CPLString osPrefixFilename = pszFilename;
11775 3 : osPrefixFilename.resize(pszLastPart - pszFilename);
11776 6 : osSrcDSName = osPrefixFilename +
11777 6 : CPLProjectRelativeFilenameSafe(
11778 3 : pszReferencePath, pszLastPart);
11779 3 : bDone = true;
11780 : }
11781 0 : else if (STARTS_WITH_CI(pszSyntax + osPrefix.size(),
11782 : "{FILENAME}"))
11783 : {
11784 0 : CPLString osFilename(pszFilename + osPrefix.size());
11785 0 : size_t nPos = 0;
11786 0 : if (osFilename.size() >= 3 && osFilename[1] == ':' &&
11787 0 : (osFilename[2] == '\\' || osFilename[2] == '/'))
11788 0 : nPos = 2;
11789 0 : nPos = osFilename.find(
11790 0 : pszSyntax[osPrefix.size() + strlen("{FILENAME}")],
11791 : nPos);
11792 0 : if (nPos != std::string::npos)
11793 : {
11794 0 : const CPLString osSuffix = osFilename.substr(nPos);
11795 0 : osFilename.resize(nPos);
11796 0 : osSrcDSName = osPrefix +
11797 0 : CPLProjectRelativeFilenameSafe(
11798 0 : pszReferencePath, osFilename) +
11799 0 : osSuffix;
11800 0 : bDone = true;
11801 : }
11802 : }
11803 3 : break;
11804 : }
11805 : }
11806 2615 : if (!bDone)
11807 : {
11808 2612 : std::string osReferencePath = pszReferencePath;
11809 2612 : if (!CPLIsFilenameRelative(pszReferencePath))
11810 : {
11811 : // Simplify path by replacing "foo/a/../b" with "foo/b"
11812 2319 : while (STARTS_WITH(pszFilename, "../"))
11813 : {
11814 : osReferencePath =
11815 5 : CPLGetPathSafe(osReferencePath.c_str());
11816 5 : pszFilename += strlen("../");
11817 : }
11818 : }
11819 :
11820 5224 : osSrcDSName = CPLProjectRelativeFilenameSafe(
11821 2612 : osReferencePath.c_str(), pszFilename);
11822 : }
11823 2619 : }
11824 : }
11825 : else
11826 : {
11827 101640 : osSrcDSName = pszFilename;
11828 : }
11829 104259 : return osSrcDSName;
11830 : }
11831 :
11832 : /************************************************************************/
11833 : /* GDALMDArrayFromDataset */
11834 : /************************************************************************/
11835 :
11836 : class GDALMDArrayFromDataset final : public GDALMDArray
11837 : {
11838 : CPL_DISALLOW_COPY_ASSIGN(GDALMDArrayFromDataset)
11839 :
11840 : GDALDataset *const m_poDS;
11841 : const GDALExtendedDataType m_dt;
11842 : std::vector<std::shared_ptr<GDALDimension>> m_dims{};
11843 : std::string m_osUnit{};
11844 : std::vector<GByte> m_abyNoData{};
11845 : std::shared_ptr<GDALMDArray> m_varX{};
11846 : std::shared_ptr<GDALMDArray> m_varY{};
11847 : std::shared_ptr<GDALMDArray> m_varBand{};
11848 : const std::string m_osFilename;
11849 : const CPLStringList m_aosOptions;
11850 : int m_iBandDim = 0;
11851 : int m_iYDim = 1;
11852 : int m_iXDim = 2;
11853 : mutable std::vector<std::shared_ptr<GDALMDArray>> m_apoOverviews{};
11854 :
11855 : bool ReadWrite(GDALRWFlag eRWFlag, const GUInt64 *arrayStartIdx,
11856 : const size_t *count, const GInt64 *arrayStep,
11857 : const GPtrDiff_t *bufferStride,
11858 : const GDALExtendedDataType &bufferDataType,
11859 : void *pBuffer) const;
11860 :
11861 : protected:
11862 17 : GDALMDArrayFromDataset(GDALDataset *poDS, CSLConstList papszOptions)
11863 34 : : GDALAbstractMDArray(std::string(),
11864 34 : std::string(poDS->GetDescription())),
11865 34 : GDALMDArray(std::string(), std::string(poDS->GetDescription())),
11866 : m_poDS(poDS), m_dt(GDALExtendedDataType::Create(
11867 : poDS->GetRasterBand(1)->GetRasterDataType())),
11868 85 : m_osFilename(poDS->GetDescription()), m_aosOptions(papszOptions)
11869 : {
11870 17 : m_poDS->Reference();
11871 :
11872 17 : const int nBandCount = poDS->GetRasterCount();
11873 47 : for (int i = 1; i <= nBandCount; ++i)
11874 : {
11875 30 : const auto poBand = poDS->GetRasterBand(i);
11876 30 : if (i == 1)
11877 17 : m_osUnit = poBand->GetUnitType();
11878 13 : else if (m_osUnit != poBand->GetUnitType())
11879 7 : m_osUnit.clear();
11880 :
11881 60 : std::vector<GByte> abyNoData;
11882 30 : int bHasNoData = false;
11883 30 : switch (poBand->GetRasterDataType())
11884 : {
11885 0 : case GDT_Int64:
11886 : {
11887 : const auto nNoData =
11888 0 : poBand->GetNoDataValueAsInt64(&bHasNoData);
11889 0 : if (bHasNoData)
11890 : {
11891 0 : abyNoData.resize(m_dt.GetSize());
11892 0 : GDALCopyWords64(&nNoData, GDT_Int64, 0, &abyNoData[0],
11893 : m_dt.GetNumericDataType(), 0, 1);
11894 : }
11895 0 : break;
11896 : }
11897 :
11898 0 : case GDT_UInt64:
11899 : {
11900 : const auto nNoData =
11901 0 : poBand->GetNoDataValueAsUInt64(&bHasNoData);
11902 0 : if (bHasNoData)
11903 : {
11904 0 : abyNoData.resize(m_dt.GetSize());
11905 0 : GDALCopyWords64(&nNoData, GDT_UInt64, 0, &abyNoData[0],
11906 : m_dt.GetNumericDataType(), 0, 1);
11907 : }
11908 0 : break;
11909 : }
11910 :
11911 30 : default:
11912 : {
11913 30 : const auto dfNoData = poBand->GetNoDataValue(&bHasNoData);
11914 30 : if (bHasNoData)
11915 : {
11916 11 : abyNoData.resize(m_dt.GetSize());
11917 22 : GDALCopyWords64(&dfNoData, GDT_Float64, 0,
11918 11 : &abyNoData[0],
11919 : m_dt.GetNumericDataType(), 0, 1);
11920 : }
11921 30 : break;
11922 : }
11923 : }
11924 :
11925 30 : if (i == 1)
11926 17 : m_abyNoData = std::move(abyNoData);
11927 13 : else if (m_abyNoData != abyNoData)
11928 7 : m_abyNoData.clear();
11929 : }
11930 :
11931 17 : const int nXSize = poDS->GetRasterXSize();
11932 17 : const int nYSize = poDS->GetRasterYSize();
11933 :
11934 17 : auto poSRS = poDS->GetSpatialRef();
11935 34 : std::string osTypeY;
11936 34 : std::string osTypeX;
11937 34 : std::string osDirectionY;
11938 34 : std::string osDirectionX;
11939 17 : if (poSRS && poSRS->GetAxesCount() == 2)
11940 : {
11941 8 : const auto &mapping = poSRS->GetDataAxisToSRSAxisMapping();
11942 8 : OGRAxisOrientation eOrientation1 = OAO_Other;
11943 8 : poSRS->GetAxis(nullptr, 0, &eOrientation1);
11944 8 : OGRAxisOrientation eOrientation2 = OAO_Other;
11945 8 : poSRS->GetAxis(nullptr, 1, &eOrientation2);
11946 8 : if (eOrientation1 == OAO_East && eOrientation2 == OAO_North)
11947 : {
11948 6 : if (mapping == std::vector<int>{1, 2})
11949 : {
11950 6 : osTypeY = GDAL_DIM_TYPE_HORIZONTAL_Y;
11951 6 : osDirectionY = "NORTH";
11952 6 : osTypeX = GDAL_DIM_TYPE_HORIZONTAL_X;
11953 6 : osDirectionX = "EAST";
11954 : }
11955 : }
11956 2 : else if (eOrientation1 == OAO_North && eOrientation2 == OAO_East)
11957 : {
11958 2 : if (mapping == std::vector<int>{2, 1})
11959 : {
11960 2 : osTypeY = GDAL_DIM_TYPE_HORIZONTAL_Y;
11961 2 : osDirectionY = "NORTH";
11962 2 : osTypeX = GDAL_DIM_TYPE_HORIZONTAL_X;
11963 2 : osDirectionX = "EAST";
11964 : }
11965 : }
11966 : }
11967 :
11968 47 : const bool bBandYX = [papszOptions, poDS, nBandCount]()
11969 : {
11970 : const char *pszDimOrder =
11971 17 : CSLFetchNameValueDef(papszOptions, "DIM_ORDER", "AUTO");
11972 17 : if (EQUAL(pszDimOrder, "AUTO"))
11973 : {
11974 : const char *pszInterleave =
11975 15 : poDS->GetMetadataItem("INTERLEAVE", "IMAGE_STRUCTURE");
11976 24 : return nBandCount == 1 || !pszInterleave ||
11977 24 : !EQUAL(pszInterleave, "PIXEL");
11978 : }
11979 : else
11980 : {
11981 2 : return EQUAL(pszDimOrder, "BAND,Y,X");
11982 : }
11983 17 : }();
11984 : const char *const pszBandDimName =
11985 17 : CSLFetchNameValueDef(papszOptions, "BAND_DIM_NAME", "Band");
11986 : auto poBandDim = std::make_shared<GDALDimensionWeakIndexingVar>(
11987 51 : "/", pszBandDimName, std::string(), std::string(), nBandCount);
11988 : const char *const pszYDimName =
11989 17 : CSLFetchNameValueDef(papszOptions, "Y_DIM_NAME", "Y");
11990 : auto poYDim = std::make_shared<GDALDimensionWeakIndexingVar>(
11991 34 : "/", pszYDimName, osTypeY, osDirectionY, nYSize);
11992 : const char *const pszXDimName =
11993 17 : CSLFetchNameValueDef(papszOptions, "X_DIM_NAME", "X");
11994 : auto poXDim = std::make_shared<GDALDimensionWeakIndexingVar>(
11995 34 : "/", pszXDimName, osTypeX, osDirectionX, nXSize);
11996 :
11997 17 : const char *const pszBandIndexingVarItem = CSLFetchNameValueDef(
11998 : papszOptions, "BAND_INDEXING_VAR_ITEM", "{Description}");
11999 17 : if (EQUAL(pszBandIndexingVarItem, "{Description}"))
12000 : {
12001 : const auto oIndexingVarType =
12002 22 : GDALExtendedDataType::CreateString(strlen("Band 65535"));
12003 11 : auto poBandVar = MEMMDArray::Create("/", poBandDim->GetName(),
12004 44 : {poBandDim}, oIndexingVarType);
12005 11 : CPL_IGNORE_RET_VAL(poBandVar->Init());
12006 29 : for (int i = 0; i < nBandCount; ++i)
12007 : {
12008 : const char *pszDesc =
12009 18 : poDS->GetRasterBand(i + 1)->GetDescription();
12010 : const std::string osBandName =
12011 36 : pszDesc[0] ? pszDesc : CPLSPrintf("Band %d", i + 1);
12012 18 : const char *pszBandName = osBandName.c_str();
12013 18 : const char *const apszBandVal[] = {pszBandName};
12014 18 : const GUInt64 anStartIdx[] = {static_cast<GUInt64>(i)};
12015 18 : const size_t anCount[] = {1};
12016 18 : const GInt64 arrayStep[] = {1};
12017 18 : const GPtrDiff_t anBufferStride[] = {1};
12018 18 : poBandVar->Write(anStartIdx, anCount, arrayStep, anBufferStride,
12019 : oIndexingVarType, apszBandVal);
12020 : }
12021 11 : m_varBand = std::move(poBandVar);
12022 11 : poBandDim->SetIndexingVariable(m_varBand);
12023 : }
12024 6 : else if (EQUAL(pszBandIndexingVarItem, "{Index}"))
12025 : {
12026 : const auto oIndexingVarType =
12027 2 : GDALExtendedDataType::Create(GDT_Int32);
12028 1 : auto poBandVar = MEMMDArray::Create("/", poBandDim->GetName(),
12029 4 : {poBandDim}, oIndexingVarType);
12030 1 : CPL_IGNORE_RET_VAL(poBandVar->Init());
12031 3 : for (int i = 0; i < nBandCount; ++i)
12032 : {
12033 2 : const int anBandIdx[] = {i + 1};
12034 2 : const GUInt64 anStartIdx[] = {static_cast<GUInt64>(i)};
12035 2 : const size_t anCount[] = {1};
12036 2 : const GInt64 arrayStep[] = {1};
12037 2 : const GPtrDiff_t anBufferStride[] = {1};
12038 2 : poBandVar->Write(anStartIdx, anCount, arrayStep, anBufferStride,
12039 : oIndexingVarType, anBandIdx);
12040 : }
12041 1 : m_varBand = std::move(poBandVar);
12042 1 : poBandDim->SetIndexingVariable(m_varBand);
12043 : }
12044 5 : else if (EQUAL(pszBandIndexingVarItem, "{ColorInterpretation}"))
12045 : {
12046 1 : size_t nMaxLen = 0;
12047 3 : for (int i = 0; i < nBandCount; ++i)
12048 : {
12049 2 : const char *pszDesc = GDALGetColorInterpretationName(
12050 2 : poDS->GetRasterBand(i + 1)->GetColorInterpretation());
12051 2 : nMaxLen = std::max(nMaxLen, strlen(pszDesc));
12052 : }
12053 : const auto oIndexingVarType =
12054 2 : GDALExtendedDataType::CreateString(nMaxLen);
12055 1 : auto poBandVar = MEMMDArray::Create("/", poBandDim->GetName(),
12056 4 : {poBandDim}, oIndexingVarType);
12057 1 : CPL_IGNORE_RET_VAL(poBandVar->Init());
12058 3 : for (int i = 0; i < nBandCount; ++i)
12059 : {
12060 2 : const char *pszDesc = GDALGetColorInterpretationName(
12061 2 : poDS->GetRasterBand(i + 1)->GetColorInterpretation());
12062 2 : const char *const apszBandVal[] = {pszDesc};
12063 2 : const GUInt64 anStartIdx[] = {static_cast<GUInt64>(i)};
12064 2 : const size_t anCount[] = {1};
12065 2 : const GInt64 arrayStep[] = {1};
12066 2 : const GPtrDiff_t anBufferStride[] = {1};
12067 2 : poBandVar->Write(anStartIdx, anCount, arrayStep, anBufferStride,
12068 : oIndexingVarType, apszBandVal);
12069 : }
12070 1 : m_varBand = std::move(poBandVar);
12071 1 : poBandDim->SetIndexingVariable(m_varBand);
12072 : }
12073 4 : else if (!EQUAL(pszBandIndexingVarItem, "{None}"))
12074 : {
12075 3 : const char *const pszBandIndexingVarType = CSLFetchNameValueDef(
12076 : papszOptions, "BAND_INDEXING_VAR_TYPE", "String");
12077 3 : size_t nMaxLen = 0;
12078 3 : if (EQUAL(pszBandIndexingVarType, "String"))
12079 : {
12080 3 : for (int i = 0; i < nBandCount; ++i)
12081 : {
12082 : const char *pszVal =
12083 2 : poDS->GetRasterBand(i + 1)->GetMetadataItem(
12084 2 : pszBandIndexingVarItem);
12085 2 : if (pszVal)
12086 1 : nMaxLen = std::max(nMaxLen, strlen(pszVal));
12087 : }
12088 : }
12089 : const auto oIndexingVarType =
12090 3 : EQUAL(pszBandIndexingVarType, "String")
12091 : ? GDALExtendedDataType::CreateString(nMaxLen)
12092 2 : : EQUAL(pszBandIndexingVarType, "Integer")
12093 : ? GDALExtendedDataType::Create(GDT_Int32)
12094 6 : : GDALExtendedDataType::Create(GDT_Float64);
12095 3 : auto poBandVar = MEMMDArray::Create("/", poBandDim->GetName(),
12096 12 : {poBandDim}, oIndexingVarType);
12097 3 : CPL_IGNORE_RET_VAL(poBandVar->Init());
12098 9 : for (int i = 0; i < nBandCount; ++i)
12099 : {
12100 6 : const GUInt64 anStartIdx[] = {static_cast<GUInt64>(i)};
12101 6 : const size_t anCount[] = {1};
12102 6 : const GInt64 arrayStep[] = {1};
12103 6 : const GPtrDiff_t anBufferStride[] = {1};
12104 : const char *pszVal =
12105 6 : poDS->GetRasterBand(i + 1)->GetMetadataItem(
12106 6 : pszBandIndexingVarItem);
12107 6 : if (oIndexingVarType.GetClass() == GEDTC_STRING)
12108 : {
12109 2 : const char *const apszBandVal[] = {pszVal ? pszVal : ""};
12110 2 : poBandVar->Write(anStartIdx, anCount, arrayStep,
12111 : anBufferStride, oIndexingVarType,
12112 : apszBandVal);
12113 : }
12114 4 : else if (oIndexingVarType.GetNumericDataType() == GDT_Int32)
12115 : {
12116 2 : const int anVal[] = {pszVal ? atoi(pszVal) : 0};
12117 2 : poBandVar->Write(anStartIdx, anCount, arrayStep,
12118 : anBufferStride, oIndexingVarType, anVal);
12119 : }
12120 : else
12121 : {
12122 2 : const double adfVal[] = {pszVal ? CPLAtof(pszVal) : 0.0};
12123 2 : poBandVar->Write(anStartIdx, anCount, arrayStep,
12124 : anBufferStride, oIndexingVarType, adfVal);
12125 : }
12126 : }
12127 3 : m_varBand = std::move(poBandVar);
12128 3 : poBandDim->SetIndexingVariable(m_varBand);
12129 : }
12130 :
12131 17 : GDALGeoTransform gt;
12132 17 : if (m_poDS->GetGeoTransform(gt) == CE_None && gt.IsAxisAligned())
12133 : {
12134 24 : m_varX = GDALMDArrayRegularlySpaced::Create(
12135 16 : "/", poBandDim->GetName(), poXDim, gt.xorig, gt.xscale, 0.5);
12136 8 : poXDim->SetIndexingVariable(m_varX);
12137 :
12138 24 : m_varY = GDALMDArrayRegularlySpaced::Create(
12139 16 : "/", poYDim->GetName(), poYDim, gt.yorig, gt.yscale, 0.5);
12140 8 : poYDim->SetIndexingVariable(m_varY);
12141 : }
12142 17 : if (bBandYX)
12143 : {
12144 96 : m_dims = {std::move(poBandDim), std::move(poYDim),
12145 80 : std::move(poXDim)};
12146 : }
12147 : else
12148 : {
12149 1 : m_iYDim = 0;
12150 1 : m_iXDim = 1;
12151 1 : m_iBandDim = 2;
12152 6 : m_dims = {std::move(poYDim), std::move(poXDim),
12153 5 : std::move(poBandDim)};
12154 : }
12155 17 : }
12156 :
12157 : bool IRead(const GUInt64 *arrayStartIdx, const size_t *count,
12158 : const GInt64 *arrayStep, const GPtrDiff_t *bufferStride,
12159 : const GDALExtendedDataType &bufferDataType,
12160 : void *pDstBuffer) const override;
12161 :
12162 1 : bool IWrite(const GUInt64 *arrayStartIdx, const size_t *count,
12163 : const GInt64 *arrayStep, const GPtrDiff_t *bufferStride,
12164 : const GDALExtendedDataType &bufferDataType,
12165 : const void *pSrcBuffer) override
12166 : {
12167 1 : return ReadWrite(GF_Write, arrayStartIdx, count, arrayStep,
12168 : bufferStride, bufferDataType,
12169 1 : const_cast<void *>(pSrcBuffer));
12170 : }
12171 :
12172 : public:
12173 34 : ~GDALMDArrayFromDataset() override
12174 17 : {
12175 17 : m_poDS->ReleaseRef();
12176 34 : }
12177 :
12178 17 : static std::shared_ptr<GDALMDArray> Create(GDALDataset *poDS,
12179 : CSLConstList papszOptions)
12180 : {
12181 : auto array(std::shared_ptr<GDALMDArrayFromDataset>(
12182 34 : new GDALMDArrayFromDataset(poDS, papszOptions)));
12183 17 : array->SetSelf(array);
12184 34 : return array;
12185 : }
12186 :
12187 2 : bool IsWritable() const override
12188 : {
12189 2 : return m_poDS->GetAccess() == GA_Update;
12190 : }
12191 :
12192 14 : const std::string &GetFilename() const override
12193 : {
12194 14 : return m_osFilename;
12195 : }
12196 :
12197 : const std::vector<std::shared_ptr<GDALDimension>> &
12198 100 : GetDimensions() const override
12199 : {
12200 100 : return m_dims;
12201 : }
12202 :
12203 36 : const GDALExtendedDataType &GetDataType() const override
12204 : {
12205 36 : return m_dt;
12206 : }
12207 :
12208 5 : const std::string &GetUnit() const override
12209 : {
12210 5 : return m_osUnit;
12211 : }
12212 :
12213 5 : const void *GetRawNoDataValue() const override
12214 : {
12215 5 : return m_abyNoData.empty() ? nullptr : m_abyNoData.data();
12216 : }
12217 :
12218 5 : double GetOffset(bool *pbHasOffset,
12219 : GDALDataType *peStorageType) const override
12220 : {
12221 5 : double dfRes = 0;
12222 5 : int bHasOffset = false;
12223 5 : auto poFirstBand = m_poDS->GetRasterBand(1);
12224 5 : if (poFirstBand) // to avoid -Wnull-dereference
12225 : {
12226 5 : dfRes = poFirstBand->GetOffset(&bHasOffset);
12227 7 : for (int i = 2; bHasOffset && i <= m_poDS->GetRasterCount(); ++i)
12228 : {
12229 : const double dfOtherRes =
12230 2 : m_poDS->GetRasterBand(i)->GetOffset(&bHasOffset);
12231 2 : bHasOffset = bHasOffset && (dfOtherRes == dfRes);
12232 : }
12233 : }
12234 5 : if (pbHasOffset)
12235 5 : *pbHasOffset = CPL_TO_BOOL(bHasOffset);
12236 5 : if (peStorageType)
12237 3 : *peStorageType = GDT_Unknown;
12238 5 : return dfRes;
12239 : }
12240 :
12241 5 : double GetScale(bool *pbHasScale,
12242 : GDALDataType *peStorageType) const override
12243 : {
12244 5 : double dfRes = 0;
12245 5 : int bHasScale = false;
12246 5 : auto poFirstBand = m_poDS->GetRasterBand(1);
12247 5 : if (poFirstBand) // to avoid -Wnull-dereference
12248 : {
12249 5 : dfRes = poFirstBand->GetScale(&bHasScale);
12250 7 : for (int i = 2; bHasScale && i <= m_poDS->GetRasterCount(); ++i)
12251 : {
12252 : const double dfOtherRes =
12253 2 : m_poDS->GetRasterBand(i)->GetScale(&bHasScale);
12254 2 : bHasScale = bHasScale && (dfOtherRes == dfRes);
12255 : }
12256 : }
12257 5 : if (pbHasScale)
12258 5 : *pbHasScale = CPL_TO_BOOL(bHasScale);
12259 5 : if (peStorageType)
12260 3 : *peStorageType = GDT_Unknown;
12261 5 : return dfRes;
12262 : }
12263 :
12264 9 : std::shared_ptr<OGRSpatialReference> GetSpatialRef() const override
12265 : {
12266 9 : auto poSrcSRS = m_poDS->GetSpatialRef();
12267 9 : if (!poSrcSRS)
12268 1 : return nullptr;
12269 16 : auto poSRS = std::shared_ptr<OGRSpatialReference>(poSrcSRS->Clone());
12270 :
12271 16 : auto axisMapping = poSRS->GetDataAxisToSRSAxisMapping();
12272 24 : for (auto &m : axisMapping)
12273 : {
12274 16 : if (m == 1)
12275 8 : m = m_iXDim + 1;
12276 8 : else if (m == 2)
12277 8 : m = m_iYDim + 1;
12278 : else
12279 0 : m = 0;
12280 : }
12281 8 : poSRS->SetDataAxisToSRSAxisMapping(axisMapping);
12282 8 : return poSRS;
12283 : }
12284 :
12285 7 : std::vector<GUInt64> GetBlockSize() const override
12286 : {
12287 7 : int nBlockXSize = 0;
12288 7 : int nBlockYSize = 0;
12289 7 : m_poDS->GetRasterBand(1)->GetBlockSize(&nBlockXSize, &nBlockYSize);
12290 7 : if (m_iBandDim == 0)
12291 : {
12292 6 : return std::vector<GUInt64>{1, static_cast<GUInt64>(nBlockYSize),
12293 6 : static_cast<GUInt64>(nBlockXSize)};
12294 : }
12295 : else
12296 : {
12297 1 : return std::vector<GUInt64>{static_cast<GUInt64>(nBlockYSize),
12298 1 : static_cast<GUInt64>(nBlockXSize), 1};
12299 : }
12300 : }
12301 :
12302 : std::vector<std::shared_ptr<GDALAttribute>>
12303 7 : GetAttributes(CSLConstList) const override
12304 : {
12305 7 : std::vector<std::shared_ptr<GDALAttribute>> res;
12306 7 : auto papszMD = m_poDS->GetMetadata();
12307 14 : for (auto iter = papszMD; iter && iter[0]; ++iter)
12308 : {
12309 7 : char *pszKey = nullptr;
12310 7 : const char *pszValue = CPLParseNameValue(*iter, &pszKey);
12311 7 : if (pszKey && pszValue)
12312 : {
12313 : res.emplace_back(
12314 7 : std::make_shared<GDALMDIAsAttribute>(pszKey, pszValue));
12315 : }
12316 7 : CPLFree(pszKey);
12317 : }
12318 7 : return res;
12319 : }
12320 :
12321 6 : int GetOverviewCount() const override
12322 : {
12323 6 : int nOvrCount = 0;
12324 6 : GDALDataset *poOvrDS = nullptr;
12325 6 : bool bOK = true;
12326 12 : for (int i = 1; bOK && i <= m_poDS->GetRasterCount(); ++i)
12327 : {
12328 6 : auto poBand = m_poDS->GetRasterBand(i);
12329 6 : const int nThisOvrCount = poBand->GetOverviewCount();
12330 6 : bOK = (nThisOvrCount > 0 && (i == 1 || nThisOvrCount == nOvrCount));
12331 6 : if (bOK)
12332 : {
12333 6 : nOvrCount = nThisOvrCount;
12334 6 : auto poFirstOvrBand = poBand->GetOverview(0);
12335 6 : bOK = poFirstOvrBand != nullptr;
12336 6 : if (bOK)
12337 : {
12338 6 : auto poThisOvrDS = poFirstOvrBand->GetDataset();
12339 12 : bOK = poThisOvrDS != nullptr &&
12340 6 : poThisOvrDS->GetRasterBand(i) == poFirstOvrBand &&
12341 0 : (i == 1 || poThisOvrDS == poOvrDS);
12342 6 : if (bOK)
12343 6 : poOvrDS = poThisOvrDS;
12344 : }
12345 : }
12346 : }
12347 6 : return bOK ? nOvrCount : 0;
12348 : }
12349 :
12350 5 : std::shared_ptr<GDALMDArray> GetOverview(int idx) const override
12351 : {
12352 5 : const int nOverviews = GetOverviewCount();
12353 5 : if (idx < 0 || idx >= nOverviews)
12354 2 : return nullptr;
12355 3 : m_apoOverviews.resize(nOverviews);
12356 3 : if (!m_apoOverviews[idx])
12357 : {
12358 1 : if (auto poBand = m_poDS->GetRasterBand(1))
12359 : {
12360 1 : if (auto poOvrBand = poBand->GetOverview(idx))
12361 : {
12362 1 : if (auto poOvrDS = poOvrBand->GetDataset())
12363 : {
12364 1 : m_apoOverviews[idx] =
12365 2 : Create(poOvrDS, m_aosOptions.List());
12366 : }
12367 : }
12368 : }
12369 : }
12370 3 : return m_apoOverviews[idx];
12371 : }
12372 : };
12373 :
12374 8 : bool GDALMDArrayFromDataset::IRead(const GUInt64 *arrayStartIdx,
12375 : const size_t *count, const GInt64 *arrayStep,
12376 : const GPtrDiff_t *bufferStride,
12377 : const GDALExtendedDataType &bufferDataType,
12378 : void *pDstBuffer) const
12379 : {
12380 8 : return ReadWrite(GF_Read, arrayStartIdx, count, arrayStep, bufferStride,
12381 8 : bufferDataType, pDstBuffer);
12382 : }
12383 :
12384 : /************************************************************************/
12385 : /* ReadWrite() */
12386 : /************************************************************************/
12387 :
12388 9 : bool GDALMDArrayFromDataset::ReadWrite(
12389 : GDALRWFlag eRWFlag, const GUInt64 *arrayStartIdx, const size_t *count,
12390 : const GInt64 *arrayStep, const GPtrDiff_t *bufferStride,
12391 : const GDALExtendedDataType &bufferDataType, void *pBuffer) const
12392 : {
12393 9 : const auto eDT(bufferDataType.GetNumericDataType());
12394 9 : const auto nDTSize(GDALGetDataTypeSizeBytes(eDT));
12395 9 : const int nX =
12396 9 : arrayStep[m_iXDim] > 0
12397 9 : ? static_cast<int>(arrayStartIdx[m_iXDim])
12398 0 : : static_cast<int>(arrayStartIdx[m_iXDim] -
12399 0 : (count[m_iXDim] - 1) * -arrayStep[m_iXDim]);
12400 9 : const int nY =
12401 9 : arrayStep[m_iYDim] > 0
12402 9 : ? static_cast<int>(arrayStartIdx[m_iYDim])
12403 1 : : static_cast<int>(arrayStartIdx[m_iYDim] -
12404 1 : (count[m_iYDim] - 1) * -arrayStep[m_iYDim]);
12405 : const int nSizeX =
12406 9 : static_cast<int>(count[m_iXDim] * std::abs(arrayStep[m_iXDim]));
12407 : const int nSizeY =
12408 9 : static_cast<int>(count[m_iYDim] * std::abs(arrayStep[m_iYDim]));
12409 9 : GByte *pabyBuffer = static_cast<GByte *>(pBuffer);
12410 9 : int nStrideXSign = 1;
12411 9 : if (arrayStep[m_iXDim] < 0)
12412 : {
12413 0 : pabyBuffer += (count[m_iXDim] - 1) * bufferStride[m_iXDim] * nDTSize;
12414 0 : nStrideXSign = -1;
12415 : }
12416 9 : int nStrideYSign = 1;
12417 9 : if (arrayStep[m_iYDim] < 0)
12418 : {
12419 1 : pabyBuffer += (count[m_iYDim] - 1) * bufferStride[m_iYDim] * nDTSize;
12420 1 : nStrideYSign = -1;
12421 : }
12422 9 : const GSpacing nPixelSpace =
12423 9 : static_cast<GSpacing>(nStrideXSign * bufferStride[m_iXDim] * nDTSize);
12424 9 : const GSpacing nLineSpace =
12425 9 : static_cast<GSpacing>(nStrideYSign * bufferStride[m_iYDim] * nDTSize);
12426 9 : const GSpacing nBandSpace =
12427 9 : static_cast<GSpacing>(bufferStride[m_iBandDim] * nDTSize);
12428 9 : std::vector<int> anBandList;
12429 26 : for (int i = 0; i < static_cast<int>(count[m_iBandDim]); ++i)
12430 17 : anBandList.push_back(1 + static_cast<int>(arrayStartIdx[m_iBandDim]) +
12431 17 : i * static_cast<int>(arrayStep[m_iBandDim]));
12432 :
12433 27 : return m_poDS->RasterIO(eRWFlag, nX, nY, nSizeX, nSizeY, pabyBuffer,
12434 9 : static_cast<int>(count[m_iXDim]),
12435 9 : static_cast<int>(count[m_iYDim]), eDT,
12436 9 : static_cast<int>(count[m_iBandDim]),
12437 9 : anBandList.data(), nPixelSpace, nLineSpace,
12438 18 : nBandSpace, nullptr) == CE_None;
12439 : }
12440 :
12441 : /************************************************************************/
12442 : /* AsMDArray() */
12443 : /************************************************************************/
12444 :
12445 : /** Return a view of this dataset as a 3D multidimensional GDALMDArray.
12446 : *
12447 : * If this dataset is not already marked as shared, it will be, so that the
12448 : * returned array holds a reference to it.
12449 : *
12450 : * If the dataset has a geotransform attached, the X and Y dimensions of the
12451 : * returned array will have an associated indexing variable.
12452 : *
12453 : * The currently supported list of options is:
12454 : * <ul>
12455 : * <li>DIM_ORDER=<order> where order can be "AUTO", "Band,Y,X" or "Y,X,Band".
12456 : * "Band,Y,X" means that the first (slowest changing) dimension is Band
12457 : * and the last (fastest changing direction) is X
12458 : * "Y,X,Band" means that the first (slowest changing) dimension is Y
12459 : * and the last (fastest changing direction) is Band.
12460 : * "AUTO" (the default) selects "Band,Y,X" for single band datasets, or takes
12461 : * into account the INTERLEAVE metadata item in the IMAGE_STRUCTURE domain.
12462 : * If it equals BAND, then "Band,Y,X" is used. Otherwise (if it equals PIXEL),
12463 : * "Y,X,Band" is use.
12464 : * </li>
12465 : * <li>BAND_INDEXING_VAR_ITEM={Description}|{None}|{Index}|{ColorInterpretation}|<BandMetadataItem>:
12466 : * item from which to build the band indexing variable.
12467 : * <ul>
12468 : * <li>"{Description}", the default, means to use the band description (or "Band index" if empty).</li>
12469 : * <li>"{None}" means that no band indexing variable must be created.</li>
12470 : * <li>"{Index}" means that the band index (starting at one) is used.</li>
12471 : * <li>"{ColorInterpretation}" means that the band color interpretation is used (i.e. "Red", "Green", "Blue").</li>
12472 : * <li><BandMetadataItem> is the name of a band metadata item to use.</li>
12473 : * </ul>
12474 : * </li>
12475 : * <li>BAND_INDEXING_VAR_TYPE=String|Real|Integer: the data type of the band
12476 : * indexing variable, when BAND_INDEXING_VAR_ITEM corresponds to a band metadata item.
12477 : * Defaults to String.
12478 : * </li>
12479 : * <li>BAND_DIM_NAME=<string>: Name of the band dimension.
12480 : * Defaults to "Band".
12481 : * </li>
12482 : * <li>X_DIM_NAME=<string>: Name of the X dimension. Defaults to "X".
12483 : * </li>
12484 : * <li>Y_DIM_NAME=<string>: Name of the Y dimension. Defaults to "Y".
12485 : * </li>
12486 : * </ul>
12487 : *
12488 : * This is the same as the C function GDALDatasetAsMDArray().
12489 : *
12490 : * The "reverse" method is GDALMDArray::AsClassicDataset().
12491 : *
12492 : * @param papszOptions Null-terminated list of strings, or nullptr.
12493 : * @return a new array, or nullptr.
12494 : *
12495 : * @since GDAL 3.12
12496 : */
12497 19 : std::shared_ptr<GDALMDArray> GDALDataset::AsMDArray(CSLConstList papszOptions)
12498 : {
12499 19 : if (!GetShared())
12500 : {
12501 18 : MarkAsShared();
12502 : }
12503 19 : if (nBands == 0 || nRasterXSize == 0 || nRasterYSize == 0)
12504 : {
12505 1 : ReportError(
12506 : CE_Failure, CPLE_AppDefined,
12507 : "Degenerated array (band, Y and/or X dimension of size zero)");
12508 1 : return nullptr;
12509 : }
12510 18 : const GDALDataType eDT = papoBands[0]->GetRasterDataType();
12511 31 : for (int i = 1; i < nBands; ++i)
12512 : {
12513 14 : if (eDT != papoBands[i]->GetRasterDataType())
12514 : {
12515 1 : ReportError(CE_Failure, CPLE_AppDefined,
12516 : "Non-uniform data type amongst bands");
12517 1 : return nullptr;
12518 : }
12519 : }
12520 : const char *pszDimOrder =
12521 17 : CSLFetchNameValueDef(papszOptions, "DIM_ORDER", "AUTO");
12522 17 : if (!EQUAL(pszDimOrder, "AUTO") && !EQUAL(pszDimOrder, "Band,Y,X") &&
12523 2 : !EQUAL(pszDimOrder, "Y,X,Band"))
12524 : {
12525 1 : ReportError(CE_Failure, CPLE_IllegalArg,
12526 : "Illegal value for DIM_ORDER option");
12527 1 : return nullptr;
12528 : }
12529 16 : return GDALMDArrayFromDataset::Create(this, papszOptions);
12530 : }
12531 :
12532 : /************************************************************************/
12533 : /* GDALDataset::GetInterBandCovarianceMatrix() */
12534 : /************************************************************************/
12535 :
12536 : /**
12537 : \brief Fetch or compute the covariance matrix between bands of this dataset.
12538 :
12539 : The covariance indicates the level to which two bands vary together.
12540 :
12541 : If we call \f$ v_i[y,x] \f$ the value of pixel at row=y and column=x for band i,
12542 : and \f$ mean_i \f$ the mean value of all pixels of band i, then
12543 :
12544 : \f[
12545 : \mathrm{cov}[i,j] =
12546 : \frac{
12547 : \sum_{y,x} \left( v_i[y,x] - \mathrm{mean}_i \right)
12548 : \left( v_j[y,x] - \mathrm{mean}_j \right)
12549 : }{
12550 : \mathrm{pixel\_count} - \mathrm{nDeltaDegreeOfFreedom}
12551 : }
12552 : \f]
12553 :
12554 : When there are no nodata values, \f$ pixel\_count = GetRasterXSize() * GetRasterYSize() \f$.
12555 : We can see that \f$ cov[i,j] = cov[j,i] \f$, and consequently the returned matrix
12556 : is symmetric.
12557 :
12558 : A value of nDeltaDegreeOfFreedom=1 (the default) will return a unbiased estimate
12559 : if the pixels in bands are considered to be a sample of the whole population.
12560 : This is consistent with the default of
12561 : https://numpy.org/doc/stable/reference/generated/numpy.cov.html and the returned
12562 : matrix is consistent with what can be obtained with
12563 :
12564 : \verbatim embed:rst
12565 : .. code-block:: python
12566 :
12567 : numpy.cov(
12568 : [ds.GetRasterBand(n + 1).ReadAsArray().ravel() for n in range(ds.RasterCount)]
12569 : )
12570 : \endverbatim
12571 :
12572 : Otherwise a value of nDeltaDegreeOfFreedom=0 can be used if they are considered
12573 : to be the whole population.
12574 :
12575 : If STATISTICS_COVARIANCES metadata items are available in band metadata,
12576 : this method uses them.
12577 : Otherwise, if bForce is true, ComputeInterBandCovarianceMatrix() is called.
12578 : Otherwise, if bForce is false, an empty vector is returned
12579 :
12580 : @param nBandCount Zero for all bands, or number of values in panBandList.
12581 : Defaults to 0.
12582 : @param panBandList nullptr for all bands if nBandCount == 0, or array of
12583 : nBandCount values such as panBandList[i] is the index
12584 : between 1 and GetRasterCount() of a band that must be used
12585 : in the covariance computation. Defaults to nullptr.
12586 : @param bApproxOK Whether it is acceptable to use a subsample of values in
12587 : ComputeInterBandCovarianceMatrix().
12588 : Defaults to false.
12589 : @param bForce Whether ComputeInterBandCovarianceMatrix() should be called
12590 : when the STATISTICS_COVARIANCES metadata items are missing.
12591 : Defaults to false.
12592 : @param bWriteIntoMetadata Whether ComputeInterBandCovarianceMatrix() must
12593 : write STATISTICS_COVARIANCES band metadata items.
12594 : Defaults to true.
12595 : @param nDeltaDegreeOfFreedom Correction term to subtract in the final
12596 : averaging phase of the covariance computation.
12597 : Defaults to 1.
12598 : @param pfnProgress a function to call to report progress, or NULL.
12599 : @param pProgressData application data to pass to the progress function.
12600 :
12601 : @return a vector of nBandCount * nBandCount values if successful,
12602 : in row-major order, or an empty vector in case of failure
12603 :
12604 : @since 3.13
12605 :
12606 : @see ComputeInterBandCovarianceMatrix()
12607 : */
12608 :
12609 0 : std::vector<double> GDALDataset::GetInterBandCovarianceMatrix(
12610 : int nBandCount, const int *panBandList, bool bApproxOK, bool bForce,
12611 : bool bWriteIntoMetadata, int nDeltaDegreeOfFreedom,
12612 : GDALProgressFunc pfnProgress, void *pProgressData)
12613 : {
12614 0 : std::vector<double> res;
12615 0 : const int nBandCountToUse = nBandCount == 0 ? nBands : nBandCount;
12616 0 : if (nBandCountToUse == 0)
12617 0 : return res;
12618 : if constexpr (sizeof(size_t) < sizeof(uint64_t))
12619 : {
12620 : // Check that nBandCountToUse * nBandCountToUse will not overflow size_t
12621 : if (static_cast<uint32_t>(nBandCountToUse) >
12622 : std::numeric_limits<uint16_t>::max())
12623 : {
12624 : CPLError(CE_Failure, CPLE_OutOfMemory,
12625 : "Not enough memory to store result");
12626 : return res;
12627 : }
12628 : }
12629 : try
12630 : {
12631 0 : res.resize(static_cast<size_t>(nBandCountToUse) * nBandCountToUse);
12632 : }
12633 0 : catch (const std::exception &)
12634 : {
12635 0 : CPLError(CE_Failure, CPLE_OutOfMemory,
12636 : "Not enough memory to store result");
12637 0 : return res;
12638 : }
12639 :
12640 0 : if (GetInterBandCovarianceMatrix(res.data(), res.size(), nBandCount,
12641 : panBandList, bApproxOK, bForce,
12642 : bWriteIntoMetadata, nDeltaDegreeOfFreedom,
12643 0 : pfnProgress, pProgressData) != CE_None)
12644 : {
12645 0 : res.clear();
12646 : }
12647 0 : return res;
12648 : }
12649 :
12650 : /************************************************************************/
12651 : /* GDALDataset::GetInterBandCovarianceMatrix() */
12652 : /************************************************************************/
12653 :
12654 : /**
12655 : \brief Fetch or compute the covariance matrix between bands of this dataset.
12656 :
12657 : The covariance indicates the level to which two bands vary together.
12658 :
12659 : If we call \f$ v_i[y,x] \f$ the value of pixel at row=y and column=x for band i,
12660 : and \f$ mean_i \f$ the mean value of all pixels of band i, then
12661 :
12662 : \f[
12663 : \mathrm{cov}[i,j] =
12664 : \frac{
12665 : \sum_{y,x} \left( v_i[y,x] - \mathrm{mean}_i \right)
12666 : \left( v_j[y,x] - \mathrm{mean}_j \right)
12667 : }{
12668 : \mathrm{pixel\_count} - \mathrm{nDeltaDegreeOfFreedom}
12669 : }
12670 : \f]
12671 :
12672 : When there are no nodata values, \f$ pixel\_count = GetRasterXSize() * GetRasterYSize() \f$.
12673 : We can see that \f$ cov[i,j] = cov[j,i] \f$, and consequently the returned matrix
12674 : is symmetric.
12675 :
12676 : A value of nDeltaDegreeOfFreedom=1 (the default) will return a unbiased estimate
12677 : if the pixels in bands are considered to be a sample of the whole population.
12678 : This is consistent with the default of
12679 : https://numpy.org/doc/stable/reference/generated/numpy.cov.html and the returned
12680 : matrix is consistent with what can be obtained with
12681 :
12682 : \verbatim embed:rst
12683 : .. code-block:: python
12684 :
12685 : numpy.cov(
12686 : [ds.GetRasterBand(n + 1).ReadAsArray().ravel() for n in range(ds.RasterCount)]
12687 : )
12688 : \endverbatim
12689 :
12690 : Otherwise a value of nDeltaDegreeOfFreedom=0 can be used if they are considered
12691 : to be the whole population.
12692 :
12693 : The caller must provide an already allocated array in padfCovMatrix of size
12694 : at least nBandCount * nBandCount.
12695 :
12696 : If STATISTICS_COVARIANCES metadata items are available in band metadata,
12697 : this method uses them.
12698 : Otherwise, if bForce is true, ComputeInterBandCovarianceMatrix() is called.
12699 : Otherwise, if bForce is false, an empty vector is returned
12700 :
12701 : This is the same as the C function GDALDatasetGetInterBandCovarianceMatrix()
12702 :
12703 : @param[out] padfCovMatrix Pointer to an already allocated output array, of size at least
12704 : nBandCount * nBandCount.
12705 : @param nSize Number of elements in output array.
12706 : @param nBandCount Zero for all bands, or number of values in panBandList.
12707 : Defaults to 0.
12708 : @param panBandList nullptr for all bands if nBandCount == 0, or array of
12709 : nBandCount values such as panBandList[i] is the index
12710 : between 1 and GetRasterCount() of a band that must be used
12711 : in the covariance computation. Defaults to nullptr.
12712 : @param bApproxOK Whether it is acceptable to use a subsample of values in
12713 : ComputeInterBandCovarianceMatrix().
12714 : Defaults to false.
12715 : @param bForce Whether ComputeInterBandCovarianceMatrix() should be called
12716 : when the STATISTICS_COVARIANCES metadata items are missing.
12717 : Defaults to false.
12718 : @param bWriteIntoMetadata Whether ComputeInterBandCovarianceMatrix() must
12719 : write STATISTICS_COVARIANCES band metadata items.
12720 : Defaults to true.
12721 : @param nDeltaDegreeOfFreedom Correction term to subtract in the final
12722 : averaging phase of the covariance computation.
12723 : Defaults to 1.
12724 : @param pfnProgress a function to call to report progress, or NULL.
12725 : @param pProgressData application data to pass to the progress function.
12726 :
12727 : @return CE_None if successful, CE_Warning if values are not available in
12728 : metadata and bForce is false, or CE_Failure in case of failure
12729 :
12730 : @since 3.13
12731 :
12732 : @see ComputeInterBandCovarianceMatrix()
12733 : */
12734 :
12735 11 : CPLErr GDALDataset::GetInterBandCovarianceMatrix(
12736 : double *padfCovMatrix, size_t nSize, int nBandCount, const int *panBandList,
12737 : bool bApproxOK, bool bForce, bool bWriteIntoMetadata,
12738 : int nDeltaDegreeOfFreedom, GDALProgressFunc pfnProgress,
12739 : void *pProgressData)
12740 : {
12741 22 : std::vector<int> anBandListTmp; // keep in this scope
12742 11 : if (nBandCount == 0)
12743 : {
12744 0 : if (nBands == 0)
12745 0 : return CE_None;
12746 0 : for (int i = 0; i < nBands; ++i)
12747 0 : anBandListTmp.push_back(i + 1);
12748 0 : nBandCount = nBands;
12749 0 : panBandList = anBandListTmp.data();
12750 : }
12751 : else
12752 : {
12753 11 : if (nBandCount > nBands)
12754 : {
12755 1 : CPLError(CE_Failure, CPLE_AppDefined,
12756 : "GetInterBandCovarianceMatrix(): nBandCount > nBands");
12757 1 : return CE_Failure;
12758 : }
12759 29 : for (int i = 0; i < nBandCount; ++i)
12760 : {
12761 21 : if (panBandList[i] <= 0 || panBandList[i] > nBands)
12762 : {
12763 2 : CPLError(CE_Failure, CPLE_AppDefined,
12764 : "GetInterBandCovarianceMatrix(): invalid value "
12765 : "panBandList[%d] = %d",
12766 2 : i, panBandList[i]);
12767 2 : return CE_Failure;
12768 : }
12769 : }
12770 : }
12771 :
12772 8 : if (nSize < static_cast<uint64_t>(nBandCount) * nBandCount)
12773 : {
12774 0 : CPLError(
12775 : CE_Failure, CPLE_AppDefined,
12776 : "GetInterBandCovarianceMatrix(): too small result matrix provided");
12777 0 : return CE_Failure;
12778 : }
12779 8 : bool bGotFromMD = true;
12780 8 : size_t resIdx = 0;
12781 20 : for (int i = 0; bGotFromMD && i < nBandCount; ++i)
12782 : {
12783 24 : const char *pszCov = papoBands[panBandList[i] - 1]->GetMetadataItem(
12784 12 : "STATISTICS_COVARIANCES");
12785 12 : bGotFromMD = pszCov != nullptr;
12786 12 : if (bGotFromMD)
12787 : {
12788 12 : const CPLStringList aosTokens(CSLTokenizeString2(pszCov, ",", 0));
12789 6 : bGotFromMD = aosTokens.size() == nBands;
12790 6 : if (bGotFromMD)
12791 : {
12792 24 : for (int j = 0; j < nBandCount; ++j)
12793 18 : padfCovMatrix[resIdx++] =
12794 18 : CPLAtof(aosTokens[panBandList[j] - 1]);
12795 : }
12796 : }
12797 : }
12798 8 : if (bGotFromMD)
12799 2 : return CE_None;
12800 :
12801 6 : if (!bForce)
12802 1 : return CE_Warning;
12803 5 : return ComputeInterBandCovarianceMatrix(
12804 : padfCovMatrix, nSize, nBandCount, panBandList, bApproxOK,
12805 5 : bWriteIntoMetadata, nDeltaDegreeOfFreedom, pfnProgress, pProgressData);
12806 : }
12807 :
12808 : /************************************************************************/
12809 : /* GDALDatasetGetInterBandCovarianceMatrix() */
12810 : /************************************************************************/
12811 :
12812 : /**
12813 : \brief Fetch or compute the covariance matrix between bands of this dataset.
12814 :
12815 : The covariance indicates the level to which two bands vary together.
12816 :
12817 : If we call \f$ v_i[y,x] \f$ the value of pixel at row=y and column=x for band i,
12818 : and \f$ mean_i \f$ the mean value of all pixels of band i, then
12819 :
12820 : \f[
12821 : \mathrm{cov}[i,j] =
12822 : \frac{
12823 : \sum_{y,x} \left( v_i[y,x] - \mathrm{mean}_i \right)
12824 : \left( v_j[y,x] - \mathrm{mean}_j \right)
12825 : }{
12826 : \mathrm{pixel\_count} - \mathrm{nDeltaDegreeOfFreedom}
12827 : }
12828 : \f]
12829 :
12830 : When there are no nodata values, \f$ pixel\_count = GetRasterXSize() * GetRasterYSize() \f$.
12831 : We can see that \f$ cov[i,j] = cov[j,i] \f$, and consequently the returned matrix
12832 : is symmetric.
12833 :
12834 : A value of nDeltaDegreeOfFreedom=1 (the default) will return a unbiased estimate
12835 : if the pixels in bands are considered to be a sample of the whole population.
12836 : This is consistent with the default of
12837 : https://numpy.org/doc/stable/reference/generated/numpy.cov.html and the returned
12838 : matrix is consistent with what can be obtained with
12839 :
12840 : \verbatim embed:rst
12841 : .. code-block:: python
12842 :
12843 : numpy.cov(
12844 : [ds.GetRasterBand(n + 1).ReadAsArray().ravel() for n in range(ds.RasterCount)]
12845 : )
12846 : \endverbatim
12847 :
12848 : Otherwise a value of nDeltaDegreeOfFreedom=0 can be used if they are considered
12849 : to be the whole population.
12850 :
12851 : The caller must provide an already allocated array in padfCovMatrix of size
12852 : at least nBandCount * nBandCount.
12853 :
12854 : If STATISTICS_COVARIANCES metadata items are available in band metadata,
12855 : this method uses them.
12856 : Otherwise, if bForce is true, GDALDatasetComputeInterBandCovarianceMatrix() is called.
12857 : Otherwise, if bForce is false, an empty vector is returned
12858 :
12859 : This is the same as the C++ method GDALDataset::GetInterBandCovarianceMatrix()
12860 :
12861 : @param hDS Dataset handle.
12862 : @param[out] padfCovMatrix Pointer to an already allocated output array, of size at least
12863 : nBandCount * nBandCount.
12864 : @param nSize Number of elements in output array.
12865 : @param nBandCount Zero for all bands, or number of values in panBandList.
12866 : Defaults to 0.
12867 : @param panBandList nullptr for all bands if nBandCount == 0, or array of
12868 : nBandCount values such as panBandList[i] is the index
12869 : between 1 and GetRasterCount() of a band that must be used
12870 : in the covariance computation. Defaults to nullptr.
12871 : @param bApproxOK Whether it is acceptable to use a subsample of values in
12872 : GDALDatasetComputeInterBandCovarianceMatrix().
12873 : Defaults to false.
12874 : @param bForce Whether GDALDatasetComputeInterBandCovarianceMatrix() should be called
12875 : when the STATISTICS_COVARIANCES metadata items are missing.
12876 : Defaults to false.
12877 : @param bWriteIntoMetadata Whether GDALDatasetComputeInterBandCovarianceMatrix() must
12878 : write STATISTICS_COVARIANCES band metadata items.
12879 : Defaults to true.
12880 : @param nDeltaDegreeOfFreedom Correction term to subtract in the final
12881 : averaging phase of the covariance computation.
12882 : Defaults to 1.
12883 : @param pfnProgress a function to call to report progress, or NULL.
12884 : @param pProgressData application data to pass to the progress function.
12885 :
12886 : @return CE_None if successful, CE_Warning if values are not available in
12887 : metadata and bForce is false, or CE_Failure in case of failure
12888 :
12889 : @since 3.13
12890 :
12891 : @see GDALDatasetComputeInterBandCovarianceMatrix()
12892 : */
12893 11 : CPLErr GDALDatasetGetInterBandCovarianceMatrix(
12894 : GDALDatasetH hDS, double *padfCovMatrix, size_t nSize, int nBandCount,
12895 : const int *panBandList, bool bApproxOK, bool bForce,
12896 : bool bWriteIntoMetadata, int nDeltaDegreeOfFreedom,
12897 : GDALProgressFunc pfnProgress, void *pProgressData)
12898 : {
12899 11 : VALIDATE_POINTER1(hDS, __func__, CE_Failure);
12900 11 : VALIDATE_POINTER1(padfCovMatrix, __func__, CE_Failure);
12901 11 : return GDALDataset::FromHandle(hDS)->GetInterBandCovarianceMatrix(
12902 : padfCovMatrix, nSize, nBandCount, panBandList, bApproxOK, bForce,
12903 11 : bWriteIntoMetadata, nDeltaDegreeOfFreedom, pfnProgress, pProgressData);
12904 : }
12905 :
12906 : /************************************************************************/
12907 : /* GDALDataset::ComputeInterBandCovarianceMatrix() */
12908 : /************************************************************************/
12909 :
12910 : /**
12911 : \brief Compute the covariance matrix between bands of this dataset.
12912 :
12913 : The covariance indicates the level to which two bands vary together.
12914 :
12915 : If we call \f$ v_i[y,x] \f$ the value of pixel at row=y and column=x for band i,
12916 : and \f$ mean_i \f$ the mean value of all pixels of band i, then
12917 :
12918 : \f[
12919 : \mathrm{cov}[i,j] =
12920 : \frac{
12921 : \sum_{y,x} \left( v_i[y,x] - \mathrm{mean}_i \right)
12922 : \left( v_j[y,x] - \mathrm{mean}_j \right)
12923 : }{
12924 : \mathrm{pixel\_count} - \mathrm{nDeltaDegreeOfFreedom}
12925 : }
12926 : \f]
12927 :
12928 : When there are no nodata values, \f$ pixel\_count = GetRasterXSize() * GetRasterYSize() \f$.
12929 : We can see that \f$ cov[i,j] = cov[j,i] \f$, and consequently the returned matrix
12930 : is symmetric.
12931 :
12932 : A value of nDeltaDegreeOfFreedom=1 (the default) will return a unbiased estimate
12933 : if the pixels in bands are considered to be a sample of the whole population.
12934 : This is consistent with the default of
12935 : https://numpy.org/doc/stable/reference/generated/numpy.cov.html and the returned
12936 : matrix is consistent with what can be obtained with
12937 :
12938 : \verbatim embed:rst
12939 : .. code-block:: python
12940 :
12941 : numpy.cov(
12942 : [ds.GetRasterBand(n + 1).ReadAsArray().ravel() for n in range(ds.RasterCount)]
12943 : )
12944 : \endverbatim
12945 :
12946 : Otherwise a value of nDeltaDegreeOfFreedom=0 can be used if they are considered
12947 : to be the whole population.
12948 :
12949 : This method recomputes the covariance matrix, even if STATISTICS_COVARIANCES
12950 : metadata items are available in bands. See GetInterBandCovarianceMatrix()
12951 : to use them.
12952 :
12953 : @param nBandCount Zero for all bands, or number of values in panBandList.
12954 : Defaults to 0.
12955 : @param panBandList nullptr for all bands if nBandCount == 0, or array of
12956 : nBandCount values such as panBandList[i] is the index
12957 : between 1 and GetRasterCount() of a band that must be used
12958 : in the covariance computation. Defaults to nullptr.
12959 : @param bApproxOK Whether it is acceptable to use a subsample of values.
12960 : Defaults to false.
12961 : @param bWriteIntoMetadata Whether this method must write
12962 : STATISTICS_COVARIANCES band metadata items.
12963 : Defaults to true.
12964 : @param nDeltaDegreeOfFreedom Correction term to subtract in the final
12965 : averaging phase of the covariance computation.
12966 : Defaults to 1.
12967 : @param pfnProgress a function to call to report progress, or NULL.
12968 : @param pProgressData application data to pass to the progress function.
12969 :
12970 : @return a vector of nBandCount * nBandCount values if successful,
12971 : in row-major order, or an empty vector in case of failure
12972 :
12973 : @since 3.13
12974 :
12975 : @see GetInterBandCovarianceMatrix()
12976 : */
12977 0 : std::vector<double> GDALDataset::ComputeInterBandCovarianceMatrix(
12978 : int nBandCount, const int *panBandList, bool bApproxOK,
12979 : bool bWriteIntoMetadata, int nDeltaDegreeOfFreedom,
12980 : GDALProgressFunc pfnProgress, void *pProgressData)
12981 : {
12982 0 : std::vector<double> res;
12983 0 : const int nBandCountToUse = nBandCount == 0 ? nBands : nBandCount;
12984 0 : if (nBandCountToUse == 0)
12985 0 : return res;
12986 : if constexpr (sizeof(size_t) < sizeof(uint64_t))
12987 : {
12988 : // Check that nBandCountToUse * nBandCountToUse will not overflow size_t
12989 : if (static_cast<uint32_t>(nBandCountToUse) >
12990 : std::numeric_limits<uint16_t>::max())
12991 : {
12992 : CPLError(CE_Failure, CPLE_OutOfMemory,
12993 : "Not enough memory to store result");
12994 : return res;
12995 : }
12996 : }
12997 : try
12998 : {
12999 0 : res.resize(static_cast<size_t>(nBandCountToUse) * nBandCountToUse);
13000 : }
13001 0 : catch (const std::exception &)
13002 : {
13003 0 : CPLError(CE_Failure, CPLE_OutOfMemory,
13004 : "Not enough memory to store result");
13005 0 : return res;
13006 : }
13007 :
13008 0 : if (ComputeInterBandCovarianceMatrix(
13009 : res.data(), res.size(), nBandCount, panBandList, bApproxOK,
13010 : bWriteIntoMetadata, nDeltaDegreeOfFreedom, pfnProgress,
13011 0 : pProgressData) != CE_None)
13012 0 : res.clear();
13013 0 : return res;
13014 : }
13015 :
13016 : /************************************************************************/
13017 : /* ComputeInterBandCovarianceMatrixInternal() */
13018 : /************************************************************************/
13019 :
13020 : template <class T>
13021 : // CPL_NOSANITIZE_UNSIGNED_INT_OVERFLOW because it seems the uses of openmp-simd
13022 : // causes that to happen
13023 : CPL_NOSANITIZE_UNSIGNED_INT_OVERFLOW static CPLErr
13024 15 : ComputeInterBandCovarianceMatrixInternal(GDALDataset *poDS,
13025 : double *padfCovMatrix, int nBandCount,
13026 : const int *panBandList,
13027 : GDALRasterBand *const *papoBands,
13028 : int nDeltaDegreeOfFreedom,
13029 : GDALProgressFunc pfnProgress,
13030 : void *pProgressData)
13031 : {
13032 : // We use the padfCovMatrix to accumulate co-moments
13033 : // Dimension = nBandCount * nBandCount
13034 15 : double *const padfComomentMatrix = padfCovMatrix;
13035 :
13036 : // Matrix of nBandCount * nBandCount storing co-moments, in optimized
13037 : // case when the block has no nodata value
13038 : // Only used if T != double
13039 30 : [[maybe_unused]] std::vector<T> aCurBlockComomentMatrix;
13040 :
13041 : // Count number of valid values in padfComomentMatrix for each (i,j) tuple
13042 : // Updated while iterating over blocks
13043 : // Dimension = nBandCount * nBandCount
13044 30 : std::vector<uint64_t> anCount;
13045 :
13046 : // Mean of bands, for each (i,j) tuple.
13047 : // Updated while iterating over blocks.
13048 : // This is a matrix rather than a vector due to the fact when need to update
13049 : // it in sync with padfComomentMatrix
13050 : // Dimension = nBandCount * nBandCount
13051 30 : std::vector<T> adfMean;
13052 :
13053 : // Number of valid values when computing adfMean, for each (i,j) tuple.
13054 : // Updated while iterating over blocks.
13055 : // This is a matrix rather than a vector due to the fact when need to update
13056 : // it in sync with padfComomentMatrix
13057 : // Dimension = nBandCount * nBandCount
13058 30 : std::vector<uint64_t> anCountMean;
13059 :
13060 : // Mean of values for each band i. Refreshed for each block.
13061 : // Dimension = nBandCount
13062 30 : std::vector<T> adfCurBlockMean;
13063 :
13064 : // Number of values participating to the mean for each band i.
13065 : // Refreshed for each block. Dimension = nBandCount
13066 30 : std::vector<size_t> anCurBlockCount;
13067 :
13068 : // Pixel values for all selected values for the current block
13069 : // Dimension = nBlockXSize * nBlockYSize * nBandCount
13070 30 : std::vector<T> adfCurBlockPixelsAllBands;
13071 :
13072 : // Vector of nodata values for all bands. Dimension = nBandCount
13073 30 : std::vector<T> adfNoData;
13074 :
13075 : // Vector of mask bands for all bands. Dimension = nBandCount
13076 30 : std::vector<GDALRasterBand *> apoMaskBands;
13077 :
13078 : // Vector of vector of mask values. Dimension = nBandCount
13079 30 : std::vector<std::vector<GByte>> aabyCurBlockMask;
13080 :
13081 : // Vector of pointer to vector of mask values. Dimension = nBandCount
13082 30 : std::vector<std::vector<GByte> *> pabyCurBlockMask;
13083 :
13084 15 : int nBlockXSize = 0;
13085 15 : int nBlockYSize = 0;
13086 15 : papoBands[panBandList[0] - 1]->GetBlockSize(&nBlockXSize, &nBlockYSize);
13087 :
13088 30 : if (static_cast<uint64_t>(nBlockXSize) * nBlockYSize >
13089 15 : std::numeric_limits<size_t>::max() / nBandCount)
13090 : {
13091 0 : poDS->ReportError(CE_Failure, CPLE_OutOfMemory,
13092 : "Not enough memory for intermediate computations");
13093 0 : return CE_Failure;
13094 : }
13095 15 : const size_t nPixelsInBlock =
13096 15 : static_cast<size_t>(nBlockXSize) * nBlockYSize;
13097 :
13098 : // Allocate temporary matrices and vectors
13099 15 : const auto nMatrixSize = static_cast<size_t>(nBandCount) * nBandCount;
13100 :
13101 : using MySignedSize_t = std::make_signed_t<size_t>;
13102 15 : const auto kMax =
13103 15 : static_cast<MySignedSize_t>(nBandCount) * (nBandCount + 1) / 2;
13104 30 : std::vector<std::pair<int, int>> anMapLinearIdxToIJ;
13105 : try
13106 : {
13107 15 : anCount.resize(nMatrixSize);
13108 15 : adfMean.resize(nMatrixSize);
13109 15 : anCountMean.resize(nMatrixSize);
13110 :
13111 : if constexpr (!std::is_same_v<T, double>)
13112 : {
13113 : aCurBlockComomentMatrix.resize(nMatrixSize);
13114 : }
13115 :
13116 15 : anMapLinearIdxToIJ.resize(kMax);
13117 :
13118 15 : adfCurBlockPixelsAllBands.resize(nPixelsInBlock * nBandCount);
13119 :
13120 15 : adfCurBlockMean.resize(nBandCount);
13121 15 : anCurBlockCount.resize(nBandCount);
13122 15 : adfNoData.resize(nBandCount);
13123 15 : apoMaskBands.resize(nBandCount);
13124 15 : aabyCurBlockMask.resize(nBandCount);
13125 15 : pabyCurBlockMask.resize(nBandCount);
13126 : }
13127 0 : catch (const std::exception &)
13128 : {
13129 0 : poDS->ReportError(CE_Failure, CPLE_OutOfMemory,
13130 : "Not enough memory for intermediate computations");
13131 0 : return CE_Failure;
13132 : }
13133 :
13134 15 : constexpr T ZERO{0};
13135 15 : std::fill(padfComomentMatrix,
13136 15 : padfComomentMatrix + static_cast<size_t>(nBandCount) * nBandCount,
13137 15 : 0);
13138 :
13139 : {
13140 15 : MySignedSize_t nLinearIdx = 0;
13141 1045 : for (int i = 0; i < nBandCount; ++i)
13142 : {
13143 501581 : for (int j = i; j < nBandCount; ++j)
13144 : {
13145 500551 : anMapLinearIdxToIJ[nLinearIdx] = {i, j};
13146 500551 : ++nLinearIdx;
13147 : }
13148 : }
13149 : }
13150 :
13151 : // Fetch nodata values and mask bands
13152 15 : bool bAllBandsSameMask = false;
13153 15 : bool bIsAllInteger = false;
13154 15 : bool bNoneHasMaskOrNodata = false;
13155 1045 : for (int i = 0; i < nBandCount; ++i)
13156 : {
13157 1030 : const auto poBand = papoBands[panBandList[i] - 1];
13158 2057 : bIsAllInteger = (i == 0 || bIsAllInteger) &&
13159 1027 : GDALDataTypeIsInteger(poBand->GetRasterDataType());
13160 1030 : int bHasNoData = FALSE;
13161 1030 : double dfNoData = poBand->GetNoDataValue(&bHasNoData);
13162 1030 : if (!bHasNoData)
13163 : {
13164 1028 : dfNoData = std::numeric_limits<double>::quiet_NaN();
13165 :
13166 1032 : if (poBand->GetMaskFlags() != GMF_ALL_VALID &&
13167 4 : poBand->GetColorInterpretation() != GCI_AlphaBand)
13168 : {
13169 4 : apoMaskBands[i] = poBand->GetMaskBand();
13170 : try
13171 : {
13172 4 : aabyCurBlockMask[i].resize(nPixelsInBlock);
13173 : }
13174 0 : catch (const std::exception &)
13175 : {
13176 0 : poDS->ReportError(
13177 : CE_Failure, CPLE_OutOfMemory,
13178 : "Not enough memory for intermediate computations");
13179 0 : return CE_Failure;
13180 : }
13181 : #ifndef __COVERITY__
13182 : // coverity[escape]
13183 4 : pabyCurBlockMask[i] = &aabyCurBlockMask[i];
13184 : #endif
13185 : }
13186 : }
13187 1030 : adfNoData[i] = static_cast<T>(dfNoData);
13188 1030 : if (i == 0)
13189 15 : bAllBandsSameMask = (apoMaskBands[0] != nullptr);
13190 1015 : else if (bAllBandsSameMask)
13191 2 : bAllBandsSameMask = (apoMaskBands[i] == apoMaskBands[0]);
13192 :
13193 3072 : bNoneHasMaskOrNodata = (i == 0 || bNoneHasMaskOrNodata) &&
13194 3072 : std::isnan(dfNoData) &&
13195 1026 : apoMaskBands[i] == nullptr;
13196 : }
13197 15 : if (bAllBandsSameMask)
13198 : {
13199 2 : for (int i = 1; i < nBandCount; ++i)
13200 : {
13201 1 : apoMaskBands[i] = nullptr;
13202 1 : aabyCurBlockMask[i].clear();
13203 1 : pabyCurBlockMask[i] = pabyCurBlockMask[0];
13204 : }
13205 : }
13206 :
13207 15 : const auto nIterCount =
13208 : static_cast<uint64_t>(
13209 15 : cpl::div_round_up(poDS->GetRasterXSize(), nBlockXSize)) *
13210 15 : cpl::div_round_up(poDS->GetRasterYSize(), nBlockYSize);
13211 15 : uint64_t nCurIter = 0;
13212 :
13213 15 : int nNumThreads = 1;
13214 : #ifdef HAVE_OPENMP
13215 15 : if (nBandCount >= 100)
13216 : {
13217 1 : const int nMaxNumThreads = std::max(1, CPLGetNumCPUs() / 2);
13218 : nNumThreads =
13219 1 : GDALGetNumThreads(nMaxNumThreads, /* bDefaultToAllCPUs= */ false);
13220 : }
13221 : #endif
13222 :
13223 : #ifdef CAN_DETECT_AVX2_FMA_AT_RUNTIME
13224 30 : const bool bHasAVX2_FMA = CPLHaveRuntimeAVX() &&
13225 30 : __builtin_cpu_supports("avx2") &&
13226 : __builtin_cpu_supports("fma");
13227 : #endif
13228 :
13229 : // Iterate over all blocks
13230 77 : for (const auto &window : papoBands[panBandList[0] - 1]->IterateWindows())
13231 : {
13232 32 : const auto nThisBlockPixelCount =
13233 32 : static_cast<size_t>(window.nXSize) * window.nYSize;
13234 :
13235 : // Extract pixel values and masks
13236 96 : CPLErr eErr = poDS->RasterIO(
13237 32 : GF_Read, window.nXOff, window.nYOff, window.nXSize, window.nYSize,
13238 32 : adfCurBlockPixelsAllBands.data(), window.nXSize, window.nYSize,
13239 : gdal::CXXTypeTraits<T>::gdal_type, nBandCount, panBandList, 0, 0, 0,
13240 : nullptr);
13241 32 : if (eErr == CE_None && bAllBandsSameMask)
13242 : {
13243 2 : eErr = apoMaskBands[0]->RasterIO(
13244 1 : GF_Read, window.nXOff, window.nYOff, window.nXSize,
13245 1 : window.nYSize, aabyCurBlockMask[0].data(), window.nXSize,
13246 1 : window.nYSize, GDT_Byte, 0, 0, nullptr);
13247 : }
13248 : else
13249 : {
13250 1108 : for (int i = 0; eErr == CE_None && i < nBandCount; ++i)
13251 : {
13252 1077 : if (apoMaskBands[i])
13253 : {
13254 4 : eErr = apoMaskBands[i]->RasterIO(
13255 2 : GF_Read, window.nXOff, window.nYOff, window.nXSize,
13256 2 : window.nYSize, aabyCurBlockMask[i].data(),
13257 2 : window.nXSize, window.nYSize, GDT_Byte, 0, 0, nullptr);
13258 : }
13259 : }
13260 : }
13261 32 : if (eErr != CE_None)
13262 1 : return eErr;
13263 :
13264 : // Compute the mean of all bands for this block
13265 32 : bool bAllBandsAreAllNodata = false;
13266 32 : bool bNoBandHasNodata = false;
13267 1111 : for (int i = 0; i < nBandCount; ++i)
13268 : {
13269 1079 : T dfSum = 0;
13270 1079 : size_t nCount = 0;
13271 1079 : const T dfNoDataI = adfNoData[i];
13272 1079 : const T *padfI =
13273 1079 : adfCurBlockPixelsAllBands.data() + i * nThisBlockPixelCount;
13274 : #ifdef HAVE_OPENMP_SIMD
13275 1079 : #pragma omp simd reduction(+ : dfSum)
13276 : #endif
13277 : for (size_t iPixel = 0; iPixel < nThisBlockPixelCount; ++iPixel)
13278 : {
13279 822482 : const T dfI = padfI[iPixel];
13280 822482 : const bool bIsValid =
13281 1644950 : !std::isnan(dfI) && dfI != dfNoDataI &&
13282 822466 : (!pabyCurBlockMask[i] || (*pabyCurBlockMask[i])[iPixel]);
13283 822482 : nCount += bIsValid;
13284 822482 : dfSum += bIsValid ? dfI : ZERO;
13285 : }
13286 1079 : adfCurBlockMean[i] = nCount > 0 ? dfSum / nCount : ZERO;
13287 1079 : anCurBlockCount[i] = nCount;
13288 1079 : bAllBandsAreAllNodata =
13289 1079 : (i == 0 || bAllBandsAreAllNodata) && (nCount == 0);
13290 1079 : bNoBandHasNodata = (i == 0 || bNoBandHasNodata) &&
13291 : (nCount == nThisBlockPixelCount);
13292 : }
13293 :
13294 : // Modify the pixel values to shift them by minus the mean
13295 32 : if (!bAllBandsAreAllNodata)
13296 : {
13297 1103 : for (int i = 0; i < nBandCount; ++i)
13298 : {
13299 1074 : T *padfI =
13300 1074 : adfCurBlockPixelsAllBands.data() + i * nThisBlockPixelCount;
13301 1074 : const T dfMeanI = adfCurBlockMean[i];
13302 823546 : for (size_t iPixel = 0; iPixel < nThisBlockPixelCount; ++iPixel)
13303 : {
13304 822472 : padfI[iPixel] -= dfMeanI;
13305 : }
13306 : }
13307 : }
13308 :
13309 : // Update padfComomentMatrix, anCount, adfMean, anCountMean
13310 : // from dfComoment, nCount, adfCurBlockMean, anCurBlockCount
13311 32 : const auto UpdateGlobalValues =
13312 13507600 : [&anCount, &adfMean, &anCountMean, &adfCurBlockMean,
13313 : &anCurBlockCount, padfComomentMatrix,
13314 : nBandCount](int i, int j, size_t nCount, T dfComoment)
13315 : {
13316 500647 : const auto idxInMatrixI = static_cast<size_t>(i) * nBandCount + j;
13317 500647 : const auto idxInMatrixJ = static_cast<size_t>(j) * nBandCount + i;
13318 :
13319 : // Update the total comoment using last formula of paragraph
13320 : // https://en.wikipedia.org/wiki/Algorithms_for_calculating_variance#Online :
13321 : // CoMoment(A+B) = CoMoment(A) + CoMoment(B) +
13322 : // (mean_I(A) - mean_I(B)) *
13323 : // (mean_J(A) - mean_J(B)) *
13324 : // (count(A) * count(B)) / (count(A) + count(B))
13325 : //
13326 : // There might be a small gotcha in the fact that the set of
13327 : // pixels on which the means are computed is not always the
13328 : // same as the the one on which the comoment is computed, if
13329 : // pixels are not valid/invalid at the same indices among bands
13330 : // It is not obvious (to me) what should be the correct behavior.
13331 : // The current approach has the benefit to avoid recomputing
13332 : // the mean for each (i,j) tuple, but only for all i.
13333 500647 : if (nCount > 0)
13334 : {
13335 500639 : padfComomentMatrix[idxInMatrixI] +=
13336 : static_cast<double>(dfComoment);
13337 500639 : padfComomentMatrix[idxInMatrixI] +=
13338 500639 : static_cast<double>(adfMean[idxInMatrixI] -
13339 500639 : adfCurBlockMean[i]) *
13340 500639 : static_cast<double>(adfMean[idxInMatrixJ] -
13341 500639 : adfCurBlockMean[j]) *
13342 500639 : (static_cast<double>(anCount[idxInMatrixI]) *
13343 500639 : static_cast<double>(nCount) /
13344 500639 : static_cast<double>(anCount[idxInMatrixI] + nCount));
13345 :
13346 500639 : anCount[idxInMatrixI] += nCount;
13347 : }
13348 :
13349 : // Update means
13350 500647 : if (anCurBlockCount[i] > 0)
13351 : {
13352 1001280 : adfMean[idxInMatrixI] +=
13353 500640 : (adfCurBlockMean[i] - adfMean[idxInMatrixI]) *
13354 : static_cast<T>(
13355 500640 : static_cast<double>(anCurBlockCount[i]) /
13356 500640 : static_cast<double>(anCountMean[idxInMatrixI] +
13357 : anCurBlockCount[i]));
13358 :
13359 500640 : anCountMean[idxInMatrixI] += anCurBlockCount[i];
13360 : }
13361 :
13362 500647 : if (idxInMatrixI != idxInMatrixJ && anCurBlockCount[j] > 0)
13363 : {
13364 999132 : adfMean[idxInMatrixJ] +=
13365 499566 : (adfCurBlockMean[j] - adfMean[idxInMatrixJ]) *
13366 : static_cast<T>(
13367 499566 : static_cast<double>(anCurBlockCount[j]) /
13368 499566 : static_cast<double>(anCountMean[idxInMatrixJ] +
13369 : anCurBlockCount[j]));
13370 :
13371 499566 : anCountMean[idxInMatrixJ] += anCurBlockCount[j];
13372 : }
13373 : };
13374 :
13375 32 : if (bAllBandsAreAllNodata)
13376 : {
13377 : // Optimized code path where all values in the current block
13378 : // are invalid
13379 :
13380 8 : for (int i = 0; i < nBandCount; ++i)
13381 : {
13382 12 : for (int j = i; j < nBandCount; ++j)
13383 : {
13384 7 : UpdateGlobalValues(i, j, 0, ZERO);
13385 : }
13386 : }
13387 : }
13388 29 : else if (bNoBandHasNodata)
13389 : {
13390 : // Optimized code path where there are no invalid value in the
13391 : // current block
13392 :
13393 : if constexpr (!std::is_same_v<T, double>)
13394 : {
13395 : std::fill(aCurBlockComomentMatrix.begin(),
13396 : aCurBlockComomentMatrix.end(), ZERO);
13397 :
13398 : GDALMatrixMultiplyAByTransposeAUpperTriangle(
13399 : nNumThreads, adfCurBlockPixelsAllBands.data(),
13400 : aCurBlockComomentMatrix.data(), nBandCount,
13401 : nThisBlockPixelCount);
13402 : }
13403 : #ifdef CAN_DETECT_AVX2_FMA_AT_RUNTIME
13404 24 : else if (bHasAVX2_FMA)
13405 : {
13406 24 : GDALMatrixMultiplyAByTransposeAUpperTriangle_AVX2_FMA(
13407 : nNumThreads, adfCurBlockPixelsAllBands.data(),
13408 : padfComomentMatrix, nBandCount, nThisBlockPixelCount);
13409 : }
13410 : #endif
13411 : else
13412 : {
13413 0 : GDALMatrixMultiplyAByTransposeAUpperTriangle(
13414 : nNumThreads, adfCurBlockPixelsAllBands.data(),
13415 : padfComomentMatrix, nBandCount, nThisBlockPixelCount);
13416 : }
13417 :
13418 1088 : for (int i = 0; i < nBandCount; ++i)
13419 : {
13420 501689 : for (int j = i; j < nBandCount; ++j)
13421 : {
13422 : if constexpr (!std::is_same_v<T, double>)
13423 : {
13424 : const auto idxInMatrixI =
13425 : static_cast<size_t>(i) * nBandCount + j;
13426 : UpdateGlobalValues(
13427 : i, j, nThisBlockPixelCount,
13428 : aCurBlockComomentMatrix[idxInMatrixI]);
13429 : }
13430 : else
13431 : {
13432 500625 : UpdateGlobalValues(i, j, nThisBlockPixelCount, ZERO);
13433 : }
13434 : }
13435 : }
13436 : }
13437 : else
13438 : {
13439 : #ifdef HAVE_OPENMP
13440 5 : #pragma omp parallel for schedule(static) num_threads(nNumThreads)
13441 : #endif
13442 : for (MySignedSize_t k = 0; k < kMax; ++k)
13443 : {
13444 : int i, j;
13445 : std::tie(i, j) = anMapLinearIdxToIJ[k];
13446 :
13447 : // Now compute the moment of (i, j), but just for this block
13448 : size_t nCount = 0;
13449 : T dfComoment = 0;
13450 : const T *padfI =
13451 : adfCurBlockPixelsAllBands.data() + i * nThisBlockPixelCount;
13452 : const T *padfJ =
13453 : adfCurBlockPixelsAllBands.data() + j * nThisBlockPixelCount;
13454 :
13455 : // Use https://en.wikipedia.org/wiki/Algorithms_for_calculating_variance#Two-pass
13456 : // for the current block
13457 : if ((anCurBlockCount[i] == nThisBlockPixelCount &&
13458 : anCurBlockCount[j] == nThisBlockPixelCount) ||
13459 : (bNoneHasMaskOrNodata && bIsAllInteger))
13460 : {
13461 : // Most optimized code path: integer, no nodata, no mask
13462 : #ifdef HAVE_OPENMP_SIMD
13463 : #pragma omp simd reduction(+ : dfComoment)
13464 : #endif
13465 : for (size_t iPixel = 0; iPixel < nThisBlockPixelCount;
13466 : ++iPixel)
13467 : {
13468 : dfComoment += padfI[iPixel] * padfJ[iPixel];
13469 : }
13470 : nCount = nThisBlockPixelCount;
13471 : }
13472 : else if (bNoneHasMaskOrNodata)
13473 : {
13474 : // Floating-point code path with no nodata and no mask
13475 : #ifdef HAVE_OPENMP_SIMD
13476 : #pragma omp simd reduction(+ : dfComoment)
13477 : #endif
13478 : for (size_t iPixel = 0; iPixel < nThisBlockPixelCount;
13479 : ++iPixel)
13480 : {
13481 : const T dfAcc = padfI[iPixel] * padfJ[iPixel];
13482 : const bool bIsValid = !std::isnan(dfAcc);
13483 : nCount += bIsValid;
13484 : dfComoment += bIsValid ? dfAcc : ZERO;
13485 : }
13486 : }
13487 : else if (!std::isnan(adfNoData[i]) && !std::isnan(adfNoData[j]))
13488 : {
13489 : // Code path when there are both nodata values
13490 : const T shiftedNoDataI = adfNoData[i] - adfCurBlockMean[i];
13491 : const T shiftedNoDataJ = adfNoData[j] - adfCurBlockMean[j];
13492 :
13493 : #ifdef HAVE_OPENMP_SIMD
13494 : #pragma omp simd reduction(+ : dfComoment)
13495 : #endif
13496 : for (size_t iPixel = 0; iPixel < nThisBlockPixelCount;
13497 : ++iPixel)
13498 : {
13499 : const T dfI = padfI[iPixel];
13500 : const T dfJ = padfJ[iPixel];
13501 : const T dfAcc = dfI * dfJ;
13502 : const bool bIsValid = !std::isnan(dfAcc) &&
13503 : dfI != shiftedNoDataI &&
13504 : dfJ != shiftedNoDataJ;
13505 : nCount += bIsValid;
13506 : dfComoment += bIsValid ? dfAcc : ZERO;
13507 : }
13508 : }
13509 : else
13510 : {
13511 : // Generic code path
13512 : const T shiftedNoDataI = adfNoData[i] - adfCurBlockMean[i];
13513 : const T shiftedNoDataJ = adfNoData[j] - adfCurBlockMean[j];
13514 :
13515 : #ifdef HAVE_OPENMP_SIMD
13516 : #pragma omp simd reduction(+ : dfComoment)
13517 : #endif
13518 : for (size_t iPixel = 0; iPixel < nThisBlockPixelCount;
13519 : ++iPixel)
13520 : {
13521 : const T dfI = padfI[iPixel];
13522 : const T dfJ = padfJ[iPixel];
13523 : const T dfAcc = dfI * dfJ;
13524 : const bool bIsValid =
13525 : !std::isnan(dfAcc) && dfI != shiftedNoDataI &&
13526 : dfJ != shiftedNoDataJ &&
13527 : (!pabyCurBlockMask[i] ||
13528 : (*pabyCurBlockMask[i])[iPixel]) &&
13529 : (!pabyCurBlockMask[j] ||
13530 : (*pabyCurBlockMask[j])[iPixel]);
13531 : nCount += bIsValid;
13532 : dfComoment += bIsValid ? dfAcc : ZERO;
13533 : }
13534 : }
13535 :
13536 : UpdateGlobalValues(i, j, nCount, dfComoment);
13537 : }
13538 : }
13539 :
13540 32 : ++nCurIter;
13541 35 : if (pfnProgress &&
13542 3 : !pfnProgress(static_cast<double>(nCurIter) / nIterCount, "",
13543 : pProgressData))
13544 : {
13545 1 : poDS->ReportError(CE_Failure, CPLE_UserInterrupt,
13546 : "User terminated");
13547 1 : return CE_Failure;
13548 : }
13549 : }
13550 :
13551 : // Finalize by dividing co-moments by the number of contributing values
13552 : // (minus nDeltaDegreeOfFreedom) to compute final covariances.
13553 44 : for (int i = 0; i < nBandCount; ++i)
13554 : {
13555 : // The covariance matrix is symmetric. So start at i
13556 81 : for (int j = i; j < nBandCount; ++j)
13557 : {
13558 51 : const auto idxInMatrixI = static_cast<size_t>(i) * nBandCount + j;
13559 51 : const double dfCovariance =
13560 51 : (nDeltaDegreeOfFreedom < 0 ||
13561 51 : anCount[idxInMatrixI] <=
13562 51 : static_cast<uint64_t>(nDeltaDegreeOfFreedom))
13563 4 : ? std::numeric_limits<double>::quiet_NaN()
13564 94 : : padfComomentMatrix[idxInMatrixI] /
13565 47 : static_cast<double>(anCount[idxInMatrixI] -
13566 47 : nDeltaDegreeOfFreedom);
13567 :
13568 51 : padfCovMatrix[idxInMatrixI] = dfCovariance;
13569 : // Fill lower triangle
13570 51 : padfCovMatrix[static_cast<size_t>(j) * nBandCount + i] =
13571 : dfCovariance;
13572 : }
13573 : }
13574 :
13575 14 : return CE_None;
13576 : }
13577 :
13578 : /************************************************************************/
13579 : /* GDALDataset::ComputeInterBandCovarianceMatrix() */
13580 : /************************************************************************/
13581 :
13582 : /**
13583 : \brief Compute the covariance matrix between bands of this dataset.
13584 :
13585 : The covariance indicates the level to which two bands vary together.
13586 :
13587 : If we call \f$ v_i[y,x] \f$ the value of pixel at row=y and column=x for band i,
13588 : and \f$ mean_i \f$ the mean value of all pixels of band i, then
13589 :
13590 : \f[
13591 : \mathrm{cov}[i,j] =
13592 : \frac{
13593 : \sum_{y,x} \left( v_i[y,x] - \mathrm{mean}_i \right)
13594 : \left( v_j[y,x] - \mathrm{mean}_j \right)
13595 : }{
13596 : \mathrm{pixel\_count} - \mathrm{nDeltaDegreeOfFreedom}
13597 : }
13598 : \f]
13599 :
13600 : When there are no nodata values, \f$ pixel\_count = GetRasterXSize() * GetRasterYSize() \f$.
13601 : We can see that \f$ cov[i,j] = cov[j,i] \f$, and consequently the returned matrix
13602 : is symmetric.
13603 :
13604 : A value of nDeltaDegreeOfFreedom=1 (the default) will return a unbiased estimate
13605 : if the pixels in bands are considered to be a sample of the whole population.
13606 : This is consistent with the default of
13607 : https://numpy.org/doc/stable/reference/generated/numpy.cov.html and the returned
13608 : matrix is consistent with what can be obtained with
13609 :
13610 : \verbatim embed:rst
13611 : .. code-block:: python
13612 :
13613 : numpy.cov(
13614 : [ds.GetRasterBand(n + 1).ReadAsArray().ravel() for n in range(ds.RasterCount)]
13615 : )
13616 : \endverbatim
13617 :
13618 : Otherwise a value of nDeltaDegreeOfFreedom=0 can be used if they are considered
13619 : to be the whole population.
13620 :
13621 : The caller must provide an already allocated array in padfCovMatrix of size
13622 : at least nBandCount * nBandCount.
13623 :
13624 : This method recomputes the covariance matrix, even if STATISTICS_COVARIANCES
13625 : metadata items are available in bands. See GetInterBandCovarianceMatrix()
13626 : to use them.
13627 :
13628 : The implementation is optimized to minimize the amount of pixel reading.
13629 :
13630 : This method is the same as the C function GDALDatasetComputeInterBandCovarianceMatrix()
13631 :
13632 : @param[out] padfCovMatrix Pointer to an already allocated output array, of size at least
13633 : nBandCount * nBandCount.
13634 : @param nSize Number of elements in output array.
13635 : @param nBandCount Zero for all bands, or number of values in panBandList.
13636 : Defaults to 0.
13637 : @param panBandList nullptr for all bands if nBandCount == 0, or array of
13638 : nBandCount values such as panBandList[i] is the index
13639 : between 1 and GetRasterCount() of a band that must be used
13640 : in the covariance computation. Defaults to nullptr.
13641 : @param bApproxOK Whether it is acceptable to use a subsample of values.
13642 : Defaults to false.
13643 : @param bWriteIntoMetadata Whether this method must write
13644 : STATISTICS_COVARIANCES band metadata items.
13645 : Defaults to true.
13646 : @param nDeltaDegreeOfFreedom Correction term to subtract in the final
13647 : averaging phase of the covariance computation.
13648 : Defaults to 1.
13649 : @param pfnProgress a function to call to report progress, or NULL.
13650 : @param pProgressData application data to pass to the progress function.
13651 :
13652 : @return CE_None if successful, or CE_Failure in case of failure
13653 :
13654 : @since 3.13
13655 :
13656 : @see GetInterBandCovarianceMatrix()
13657 : */
13658 22 : CPLErr GDALDataset::ComputeInterBandCovarianceMatrix(
13659 : double *padfCovMatrix, size_t nSize, int nBandCount, const int *panBandList,
13660 : bool bApproxOK, bool bWriteIntoMetadata, int nDeltaDegreeOfFreedom,
13661 : GDALProgressFunc pfnProgress, void *pProgressData)
13662 : {
13663 44 : std::vector<int> anBandListTmp; // keep in this scope
13664 22 : if (nBandCount == 0)
13665 : {
13666 0 : if (nBands == 0)
13667 0 : return CE_None;
13668 0 : for (int i = 0; i < nBands; ++i)
13669 0 : anBandListTmp.push_back(i + 1);
13670 0 : nBandCount = nBands;
13671 0 : panBandList = anBandListTmp.data();
13672 : }
13673 : else
13674 : {
13675 22 : if (nBandCount > nBands)
13676 : {
13677 1 : CPLError(CE_Failure, CPLE_AppDefined,
13678 : "ComputeInterBandCovarianceMatrix(): nBandCount > nBands");
13679 1 : return CE_Failure;
13680 : }
13681 1057 : for (int i = 0; i < nBandCount; ++i)
13682 : {
13683 1038 : if (panBandList[i] <= 0 || panBandList[i] > nBands)
13684 : {
13685 2 : CPLError(CE_Failure, CPLE_AppDefined,
13686 : "ComputeInterBandCovarianceMatrix(): invalid value "
13687 : "panBandList[%d] = %d",
13688 2 : i, panBandList[i]);
13689 2 : return CE_Failure;
13690 : }
13691 : }
13692 :
13693 19 : if (bWriteIntoMetadata)
13694 : {
13695 14 : bool bOK = nBandCount == nBands;
13696 38 : for (int i = 0; bOK && i < nBandCount; ++i)
13697 : {
13698 24 : bOK = (panBandList[i] == i + 1);
13699 : }
13700 14 : if (!bOK)
13701 : {
13702 4 : CPLError(CE_Failure, CPLE_AppDefined,
13703 : "ComputeInterBandCovarianceMatrix(): cannot write "
13704 : "STATISTICS_COVARIANCES metadata since the input band "
13705 : "list is not [1, 2, ... GetRasterCount()]");
13706 4 : return CE_Failure;
13707 : }
13708 : }
13709 : }
13710 :
13711 15 : const auto nMatrixSize = static_cast<size_t>(nBandCount) * nBandCount;
13712 15 : if (nSize < nMatrixSize)
13713 : {
13714 0 : CPLError(CE_Failure, CPLE_AppDefined,
13715 : "ComputeInterBandCovarianceMatrix(): too small result matrix "
13716 : "provided");
13717 0 : return CE_Failure;
13718 : }
13719 :
13720 : // Find appropriate overview dataset
13721 15 : GDALDataset *poActiveDS = this;
13722 15 : if (bApproxOK && papoBands[panBandList[0] - 1]->GetOverviewCount() > 0)
13723 : {
13724 1 : GDALDataset *poOvrDS = nullptr;
13725 4 : for (int i = 0; i < nBandCount; ++i)
13726 : {
13727 3 : const int nIdxBand = panBandList[i] - 1;
13728 6 : auto poOvrBand = papoBands[nIdxBand]->GetRasterSampleOverview(
13729 3 : GDALSTAT_APPROX_NUMSAMPLES);
13730 :
13731 6 : if (poOvrBand == papoBands[i] ||
13732 3 : poOvrBand->GetBand() != panBandList[i])
13733 : {
13734 0 : poOvrDS = nullptr;
13735 0 : break;
13736 : }
13737 3 : else if (i == 0)
13738 : {
13739 1 : if (poOvrBand->GetDataset() == this)
13740 : {
13741 0 : break;
13742 : }
13743 1 : poOvrDS = poOvrBand->GetDataset();
13744 : }
13745 2 : else if (poOvrBand->GetDataset() != poOvrDS)
13746 : {
13747 0 : poOvrDS = nullptr;
13748 0 : break;
13749 : }
13750 : }
13751 1 : if (poOvrDS)
13752 : {
13753 1 : poActiveDS = poOvrDS;
13754 : }
13755 : }
13756 :
13757 : #ifdef GDAL_COVARIANCE_CAN_USE_FLOAT32
13758 : const auto UseFloat32 = [](GDALDataType eDT)
13759 : {
13760 : return eDT == GDT_UInt8 || eDT == GDT_Int8 || eDT == GDT_UInt16 ||
13761 : eDT == GDT_Int16 || eDT == GDT_Float32;
13762 : };
13763 :
13764 : bool bUseFloat32 = UseFloat32(
13765 : poActiveDS->GetRasterBand(panBandList[0])->GetRasterDataType());
13766 : for (int i = 1; bUseFloat32 && i < nBandCount; ++i)
13767 : {
13768 : bUseFloat32 = UseFloat32(
13769 : poActiveDS->GetRasterBand(panBandList[i])->GetRasterDataType());
13770 : }
13771 : #endif
13772 :
13773 : CPLErr eErr =
13774 : #ifdef GDAL_COVARIANCE_CAN_USE_FLOAT32
13775 : bUseFloat32 ? ComputeInterBandCovarianceMatrixInternal<float>(
13776 : poActiveDS, padfCovMatrix, nBandCount, panBandList,
13777 : poActiveDS->papoBands, nDeltaDegreeOfFreedom,
13778 : pfnProgress, pProgressData)
13779 : :
13780 : #endif
13781 30 : ComputeInterBandCovarianceMatrixInternal<double>(
13782 : poActiveDS, padfCovMatrix, nBandCount, panBandList,
13783 15 : poActiveDS->papoBands, nDeltaDegreeOfFreedom,
13784 : pfnProgress, pProgressData);
13785 :
13786 15 : if (bWriteIntoMetadata && eErr == CE_None)
13787 : {
13788 10 : CPLAssert(nBands == nBandCount);
13789 20 : std::string osStr;
13790 10 : size_t idx = 0;
13791 32 : for (int i = 0; i < nBands; ++i)
13792 : {
13793 22 : osStr.clear();
13794 74 : for (int j = 0; j < nBands; ++j, ++idx)
13795 : {
13796 52 : if (j > 0)
13797 30 : osStr += ',';
13798 52 : osStr += CPLSPrintf("%.17g", padfCovMatrix[idx]);
13799 : }
13800 22 : papoBands[i]->SetMetadataItem("STATISTICS_COVARIANCES",
13801 22 : osStr.c_str());
13802 : }
13803 : }
13804 :
13805 15 : return eErr;
13806 : }
13807 :
13808 : /************************************************************************/
13809 : /* GDALDatasetComputeInterBandCovarianceMatrix() */
13810 : /************************************************************************/
13811 :
13812 : /**
13813 : \brief Compute the covariance matrix between bands of this dataset.
13814 :
13815 : The covariance indicates the level to which two bands vary together.
13816 :
13817 : If we call \f$ v_i[y,x] \f$ the value of pixel at row=y and column=x for band i,
13818 : and \f$ mean_i \f$ the mean value of all pixels of band i, then
13819 :
13820 : \f[
13821 : \mathrm{cov}[i,j] =
13822 : \frac{
13823 : \sum_{y,x} \left( v_i[y,x] - \mathrm{mean}_i \right)
13824 : \left( v_j[y,x] - \mathrm{mean}_j \right)
13825 : }{
13826 : \mathrm{pixel\_count} - \mathrm{nDeltaDegreeOfFreedom}
13827 : }
13828 : \f]
13829 :
13830 : When there are no nodata values, \f$ pixel\_count = GetRasterXSize() * GetRasterYSize() \f$.
13831 : We can see that \f$ cov[i,j] = cov[j,i] \f$, and consequently the returned matrix
13832 : is symmetric.
13833 :
13834 : A value of nDeltaDegreeOfFreedom=1 (the default) will return a unbiased estimate
13835 : if the pixels in bands are considered to be a sample of the whole population.
13836 : This is consistent with the default of
13837 : https://numpy.org/doc/stable/reference/generated/numpy.cov.html and the returned
13838 : matrix is consistent with what can be obtained with
13839 :
13840 : \verbatim embed:rst
13841 : .. code-block:: python
13842 :
13843 : numpy.cov(
13844 : [ds.GetRasterBand(n + 1).ReadAsArray().ravel() for n in range(ds.RasterCount)]
13845 : )
13846 : \endverbatim
13847 :
13848 : Otherwise a value of nDeltaDegreeOfFreedom=0 can be used if they are considered
13849 : to be the whole population.
13850 :
13851 : The caller must provide an already allocated array in padfCovMatrix of size
13852 : at least GDALGetRasterCount() * GDALGetRasterCount().
13853 :
13854 : This method recomputes the covariance matrix, even if STATISTICS_COVARIANCES
13855 : metadata items are available in bands. See GDALDatasetGetInterBandCovarianceMatrix()
13856 : to use them.
13857 :
13858 : This function is the same as the C++ method GDALDataset::ComputeInterBandCovarianceMatrix()
13859 :
13860 : @param hDS Dataset handle.
13861 : @param[out] padfCovMatrix Pointer to an already allocated output array, of size at least
13862 : nBandCount * nBandCount.
13863 : @param nSize Number of elements in output array.
13864 : @param nBandCount Zero for all bands, or number of values in panBandList.
13865 : Defaults to 0.
13866 : @param panBandList nullptr for all bands if nBandCount == 0, or array of
13867 : nBandCount values such as panBandList[i] is the index
13868 : between 1 and GetRasterCount() of a band that must be used
13869 : in the covariance computation. Defaults to nullptr.
13870 : @param bApproxOK Whether it is acceptable to use a subsample of values.
13871 : Defaults to false.
13872 : @param bWriteIntoMetadata Whether this method must write
13873 : STATISTICS_COVARIANCES band metadata items.
13874 : Defaults to true.
13875 : @param nDeltaDegreeOfFreedom Correction term to subtract in the final
13876 : averaging phase of the covariance computation.
13877 : Defaults to 1.
13878 : @param pfnProgress a function to call to report progress, or NULL.
13879 : @param pProgressData application data to pass to the progress function.
13880 :
13881 : @return CE_None if successful, or CE_Failure in case of failure
13882 :
13883 : @since 3.13
13884 :
13885 : @see GDALDatasetGetInterBandCovarianceMatrix()
13886 : */
13887 17 : CPLErr GDALDatasetComputeInterBandCovarianceMatrix(
13888 : GDALDatasetH hDS, double *padfCovMatrix, size_t nSize, int nBandCount,
13889 : const int *panBandList, bool bApproxOK, bool bWriteIntoMetadata,
13890 : int nDeltaDegreeOfFreedom, GDALProgressFunc pfnProgress,
13891 : void *pProgressData)
13892 : {
13893 17 : VALIDATE_POINTER1(hDS, __func__, CE_Failure);
13894 17 : VALIDATE_POINTER1(padfCovMatrix, __func__, CE_Failure);
13895 17 : return GDALDataset::FromHandle(hDS)->ComputeInterBandCovarianceMatrix(
13896 : padfCovMatrix, nSize, nBandCount, panBandList, bApproxOK,
13897 17 : bWriteIntoMetadata, nDeltaDegreeOfFreedom, pfnProgress, pProgressData);
13898 : }
|